| 1 | import Link from "next/link"; |
| 2 | import { Icon, type IconName } from "@/components/icon"; |
| 3 | import { PageHeader, Section } from "@/components/page-header"; |
| 4 | import { getFacts } from "@/lib/facts"; |
| 5 | import { fill, getCommunity, pickTextLocale } from "@/lib/i18n/dictionaries"; |
| 6 | import { buildPageMetadata } from "@/lib/page-meta"; |
| 7 | import { RELEASE_CONTRIBUTORS, RELEASE_HELPERS } from "@/lib/release-credits"; |
| 8 | |
| 9 | export const revalidate = 300; |
| 10 | |
| 11 | export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) { |
| 12 | const { locale } = await params; |
| 13 | const t = getCommunity(locale); |
| 14 | return buildPageMetadata({ |
| 15 | path: "/community", |
| 16 | locale, |
| 17 | title: t.metaTitle, |
| 18 | description: t.metaDescription, |
| 19 | }); |
| 20 | } |
| 21 | |
| 22 | const pathsEn = [ |
| 23 | { |
| 24 | title: "Report a problem", |
| 25 | description: "File a bug, compatibility problem, or unclear behavior with system details, reproduction steps, and any logs you can share safely.", |
| 26 | cta: "File an issue", |
| 27 | href: "https://github.com/codewhale-hq/CodeWhale/issues/new/choose", |
| 28 | }, |
| 29 | { |
| 30 | title: "Improve code or tests", |
| 31 | description: "Pick one problem with clear edges, write the smallest patch that fixes it, and add a regression test that covers it.", |
| 32 | cta: "Browse open issues", |
| 33 | href: "https://github.com/codewhale-hq/CodeWhale/issues", |
| 34 | }, |
| 35 | { |
| 36 | title: "Improve documentation or translations", |
| 37 | description: "Fix a wrong sentence, add an example, or help finish a language pack.", |
| 38 | cta: "Open the localization guide", |
| 39 | href: "https://github.com/codewhale-hq/CodeWhale/blob/main/docs/LOCALIZATION.md", |
| 40 | }, |
| 41 | { |
| 42 | title: "Reproduce and review existing work", |
| 43 | description: "Try an issue or pull request on your platform and provider. Post the commands you ran, what happened, and what is still wrong.", |
| 44 | cta: "Browse pull requests", |
| 45 | href: "https://github.com/codewhale-hq/CodeWhale/pulls", |
| 46 | }, |
| 47 | ]; |
| 48 | |
| 49 | const pathsZh = [ |
| 50 | { |
| 51 | title: "报告问题", |
| 52 | description: "报告 bug、兼容性问题或不清楚的行为,并附上系统信息、复现步骤和可以安全分享的日志。", |
| 53 | cta: "提交 issue", |
| 54 | href: "https://github.com/codewhale-hq/CodeWhale/issues/new/choose", |
| 55 | }, |
| 56 | { |
| 57 | title: "改进代码或测试", |
| 58 | description: "挑一个范围清楚的问题,写最小的补丁,加一个覆盖改动的回归测试。", |
| 59 | cta: "查看开放 issues", |
| 60 | href: "https://github.com/codewhale-hq/CodeWhale/issues", |
| 61 | }, |
| 62 | { |
| 63 | title: "改进文档或翻译", |
| 64 | description: "改正说错的地方,补一个示例,或者帮忙完成一个语言包。", |
| 65 | cta: "查看本地化指南", |
| 66 | href: "https://github.com/codewhale-hq/CodeWhale/blob/main/docs/LOCALIZATION.md", |
| 67 | }, |
| 68 | { |
| 69 | title: "复现并审查现有工作", |
| 70 | description: "在你的平台和提供商上验证 issue 或 pull request,然后分享你运行的命令、结果和剩余问题。", |
| 71 | cta: "查看 pull requests", |
| 72 | href: "https://github.com/codewhale-hq/CodeWhale/pulls", |
| 73 | }, |
| 74 | ]; |
| 75 | |
| 76 | const activityEn = [ |
| 77 | { title: "Repository activity", description: "Recent issues and pull requests.", path: "/feed" }, |
| 78 | { title: "Community digest", description: "The weekly project record, reviewed by a maintainer.", path: "/digest" }, |
| 79 | { title: "Public roadmap", description: "Shipped, underway, considered, and ruled-out work.", path: "/roadmap" }, |
| 80 | ]; |
| 81 | |
| 82 | const activityZh = [ |
| 83 | { title: "仓库动态", description: "最近的 issues 与 pull requests。", path: "/feed" }, |
| 84 | { title: "社区摘要", description: "经过维护者审核的每周项目记录。", path: "/digest" }, |
| 85 | { title: "公开路线图", description: "已发布、正在进行、考虑中和明确不做的工作。", path: "/roadmap" }, |
| 86 | ]; |
| 87 | |
| 88 | export default async function CommunityPage({ params }: { params: Promise<{ locale: string }> }) { |
| 89 | const { locale } = await params; |
| 90 | const t = getCommunity(locale); |
| 91 | const p = (path: string) => `/${locale}${path}`; |
| 92 | const facts = await getFacts(); |
| 93 | const sourceIsPublished = facts.latestPublishedRelease?.version === facts.version; |
| 94 | const textLocale = pickTextLocale(locale); |
| 95 | const contributionPaths = { en: pathsEn, zh: pathsZh }[textLocale]; |
| 96 | const activityLinks = { en: activityEn, zh: activityZh }[textLocale]; |
| 97 | |
| 98 | |
| 99 | const activityIcons: IconName[] = ["repeat", "book", "tide"]; |
| 100 | |
| 101 | return ( |
| 102 | <> |
| 103 | <PageHeader |
| 104 | kicker={t.kicker} |
| 105 | title={t.title} |
| 106 | lede={t.lede} |
| 107 | pose="talk" |
| 108 | actions={ |
| 109 | <> |
| 110 | <Link href="https://github.com/codewhale-hq/CodeWhale/issues/new/choose" className="btn btn-primary btn-lg"> |
| 111 | {t.fileIssue} |
| 112 | </Link> |
| 113 | <Link href="https://github.com/codewhale-hq/CodeWhale/pulls" className="btn btn-secondary btn-lg"> |
| 114 | {t.browsePulls} |
| 115 | </Link> |
| 116 | <Link href={p("/contribute")} className="btn btn-ghost btn-lg"> |
| 117 | {t.readGuide} |
| 118 | <Icon name="arrow-right" className="icon icon-flip" /> |
| 119 | </Link> |
| 120 | </> |
| 121 | } |
| 122 | /> |
| 123 | |
| 124 | <div className="page-body"> |
| 125 | <Section |
| 126 | id="community-paths" |
| 127 | title={t.pathsTitle} |
| 128 | scope={t.pathsScope} |
| 129 | > |
| 130 | <div className="grid-2"> |
| 131 | {contributionPaths.map((path) => ( |
| 132 | <Link key={path.title} href={path.href} className="tile"> |
| 133 | <h3>{path.title}</h3> |
| 134 | <p>{path.description}</p> |
| 135 | <span className="section-link"> |
| 136 | {path.cta} |
| 137 | <Icon name={path.href.includes("LOCALIZATION") ? "external" : "arrow-right"} className="icon icon-flip" /> |
| 138 | </span> |
| 139 | </Link> |
| 140 | ))} |
| 141 | </div> |
| 142 | </Section> |
| 143 | |
| 144 | <Section |
| 145 | id="community-record" |
| 146 | title={t.recordTitle} |
| 147 | scope={t.recordScope} |
| 148 | > |
| 149 | <ul className="dir-list dir-list-card" role="list"> |
| 150 | {activityLinks.map((item, index) => ( |
| 151 | <li key={item.path}> |
| 152 | <Link href={p(item.path)} className="dir-row"> |
| 153 | <span className="dir-mark" aria-hidden="true"><Icon name={activityIcons[index] ?? "book"} /></span> |
| 154 | <span className="dir-text"> |
| 155 | <span className="dir-title">{item.title}</span> |
| 156 | <span className="dir-purpose">{item.description}</span> |
| 157 | </span> |
| 158 | <span className="dir-action" aria-hidden="true"><Icon name="chevron-right" className="icon icon-flip" /></span> |
| 159 | </Link> |
| 160 | </li> |
| 161 | ))} |
| 162 | </ul> |
| 163 | </Section> |
| 164 | |
| 165 | <Section |
| 166 | id="community-credit" |
| 167 | title={t.creditTitle} |
| 168 | scope={sourceIsPublished ? t.creditScope : t.creditScopeUnreleased} |
| 169 | > |
| 170 | <p className="page-kicker mb-4"> |
| 171 | {fill(sourceIsPublished ? t.creditLabel : t.creditLabelUnreleased, { version: facts.version ?? "—" })} |
| 172 | </p> |
| 173 | <div className="grid-2"> |
| 174 | <div className="tile"> |
| 175 | <h3>{t.mergedTitle}</h3> |
| 176 | <ul className="credit-list" role="list"> |
| 177 | {RELEASE_CONTRIBUTORS.map((handle) => ( |
| 178 | <li key={handle}> |
| 179 | <Link href={`https://github.com/${handle.slice(1)}`}>{handle}</Link> |
| 180 | </li> |
| 181 | ))} |
| 182 | </ul> |
| 183 | </div> |
| 184 | {RELEASE_HELPERS.length > 0 ? ( |
| 185 | <div className="tile"> |
| 186 | <h3>{t.helpersTitle}</h3> |
| 187 | <ul className="credit-list" role="list"> |
| 188 | {RELEASE_HELPERS.map((handle) => ( |
| 189 | <li key={handle}> |
| 190 | <Link href={`https://github.com/${handle.slice(1)}`}>{handle}</Link> |
| 191 | </li> |
| 192 | ))} |
| 193 | </ul> |
| 194 | </div> |
| 195 | ) : null} |
| 196 | </div> |
| 197 | <p className="status-line mt-4"> |
| 198 | <Link href="https://github.com/codewhale-hq/CodeWhale/blob/main/docs/CONTRIBUTORS.md" className="link"> |
| 199 | {t.fullRecord} |
| 200 | </Link> |
| 201 | <Link href="https://github.com/codewhale-hq/CodeWhale/blob/main/CHANGELOG.md" className="link">CHANGELOG</Link> |
| 202 | </p> |
| 203 | </Section> |
| 204 | </div> |
| 205 | </> |
| 206 | ); |
| 207 | } |
| 208 |