| 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 |