返回 CodeWhale
page.tsx
根目录 / web / app / [locale] / models / page.tsx
1 import Link from "next/link";
2 import { getFacts } from "@/lib/facts";
3 import { buildPageMetadata } from "@/lib/page-meta";
4 import { MODELS_COPY } from "@/lib/content/models";
5 import { Icon } from "@/components/icon";
6 import { ModelsTable } from "@/components/models-table";
7 import { PageHeader, Section } from "@/components/page-header";
8 import type { LocalizedText } from "@/lib/content/vocabulary";
9 import { fill, pickText } from "@/lib/i18n/dictionaries";
10
11 export const revalidate = 300;
12
13 export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
14 const { locale } = await params;
15 return buildPageMetadata({ path: "/models", locale,
16 title: pickText(MODELS_COPY.metaTitle, locale),
17 description: pickText(MODELS_COPY.metaDescription, locale) });
18 }
19
20 /**
21 * /models — connect a provider, then the source's own model and provider
22 * lists (facts layer), never a hand-typed catalogue.
23 */
24 export default async function ModelsPage({ params }: { params: Promise<{ locale: string }> }) {
25 const { locale } = await params;
26 const facts = await getFacts();
27 const t = (copy: LocalizedText) => fill(pickText(copy, locale), {
28 version: facts.version ?? "—", model: facts.defaultModel ?? "—",
29 });
30 const providerDocs = "https://github.com/codewhale-hq/CodeWhale/blob/main/docs/PROVIDERS.md";
31 const docsLink = (
32 <Link href={providerDocs} className="section-link">
33 {t(MODELS_COPY.providerDocs)}
34 <Icon name="external" className="icon" />
35 </Link>
36 );
37
38 return (
39 <>
40 <PageHeader
41 kicker={t(MODELS_COPY.kicker)}
42 title={t(MODELS_COPY.title)}
43 lede={t(MODELS_COPY.lead)}
44 pose="think"
45 actions={
46 <>
47 <Link href={providerDocs} className="btn btn-primary btn-lg">{t(MODELS_COPY.providerDocs)}</Link>
48 <Link href={`/${locale}/install`} className="btn btn-secondary btn-lg">{t(MODELS_COPY.install)}</Link>
49 </>
50 }
51 />
52
53 <div className="page-body">
54 <Section
55 id="models-setup"
56 layout="split"
57 title={t(MODELS_COPY.setupTitle)}
58 scope={t(MODELS_COPY.setupLead)}
59 link={docsLink}
60 >
61 <dl className="ruled-list">
62 {MODELS_COPY.patterns.map((pattern) => (
63 <div key={pattern.reference}>
64 <dt>{pattern.reference}</dt>
65 <dd>
66 <strong>{t(pattern.title)}</strong> · {t(pattern.detail)}
67 </dd>
68 </div>
69 ))}
70 </dl>
71 </Section>
72
73 <Section id="models-title" title={t(MODELS_COPY.modelsTitle)} scope={t(MODELS_COPY.modelsLead)} link={docsLink}>
74 <ModelsTable models={facts.models} locale={locale} />
75 </Section>
76
77 <Section id="providers-title" title={t(MODELS_COPY.listTitle)} scope={t(MODELS_COPY.listLead)} link={docsLink}>
78 <div className="data-table-wrap">
79 <table className="data-table">
80 <caption className="sr-only">{t(MODELS_COPY.listTitle)}</caption>
81 <thead>
82 <tr>
83 <th scope="col">{t(MODELS_COPY.provider)}</th>
84 <th scope="col">{t(MODELS_COPY.id)}</th>
85 <th scope="col">{t(MODELS_COPY.credential)}</th>
86 </tr>
87 </thead>
88 <tbody>
89 {facts.providers.map((provider) => (
90 <tr key={provider.id}>
91 <th scope="row">{provider.label}</th>
92 <td><code>{provider.id}</code></td>
93 <td><code>{provider.env}</code></td>
94 </tr>
95 ))}
96 </tbody>
97 </table>
98 </div>
99 <p className="section-scope mt-5">
100 {t(MODELS_COPY.missing)}{" "}
101 <Link href="https://github.com/codewhale-hq/CodeWhale/issues/new/choose" className="link">{t(MODELS_COPY.request)}</Link>
102 </p>
103 </Section>
104 </div>
105 </>
106 );
107 }
108
108 lines Plain Text