Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions apps/web/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ const nextConfig: NextConfig = {
unoptimized: true,
},
poweredByHeader: false,
async redirects() {
// The manual's content now lives in the docs as the pseudocode reference.
return ["/manual", "/app/manual"].flatMap((source) => [
{ source, destination: "/docs", permanent: true },
{ source: `/:locale(en|zh)${source}`, destination: "/:locale/docs", permanent: true },
]);
},
async headers() {
const immutableAssetHeaders = [
{
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/app/[locale]/(public)/docs/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ContentArticle } from "@/app/components/docs/ContentArticle";
import { localePath, pageMetadata } from "@/i18n/config";
import { getDictionary } from "@/i18n/messages";
import { resolveLocale } from "@/i18n/server";
import { docs, docPath, getDoc } from "@/lib/docs";
import { docs, docPath, getDoc, isGuide } from "@/lib/docs";

type PageProps = { params: Promise<{ locale: string; slug: string }> };

Expand All @@ -26,6 +26,6 @@ export default async function DocPage({ params }: PageProps) {
const { slug } = await params;
const doc = getDoc(locale, slug);
if (!doc) notFound();
if (doc.unit !== "pseudoeditor") permanentRedirect(localePath(locale, docPath(doc)));
if (!isGuide(doc)) permanentRedirect(localePath(locale, docPath(doc)));
return <ContentArticle locale={locale} doc={doc} />;
}
24 changes: 15 additions & 9 deletions apps/web/src/app/[locale]/(public)/docs/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { PublicListLink, publicListClassName } from "@/app/components/PublicUi";
import { localePath, localeTags, localeUrl, pageMetadata } from "@/i18n/config";
import { getDictionary } from "@/i18n/messages";
import { resolveLocale, type LocaleParams } from "@/i18n/server";
import { docPath, getGuides } from "@/lib/docs";
import { docPath, getGuides, getUnit, guideUnitIds } from "@/lib/docs";

export async function generateMetadata({ params }: LocaleParams): Promise<Metadata> {
const locale = await resolveLocale(params);
Expand Down Expand Up @@ -60,14 +60,20 @@ export default async function DocsIndexPage({ params }: LocaleParams) {
</div>
</section>

<section className="site-wrap pb-16">
<h2 className="site-h2">{t.guidesTitle}</h2>
<div className={`mt-6 ${publicListClassName}`}>
{guides.map((doc) => (
<PublicListLink key={doc.slug} href={href(docPath(doc))} title={doc.title} description={doc.description} />
))}
</div>
</section>
{guideUnitIds.map((id) => {
const unit = getUnit(locale, id);
return (
<section key={id} id={id} className="site-wrap scroll-mt-20 pb-16">
<h2 className="site-h2">{unit.title}</h2>
<p className="mt-3 max-w-2xl text-sm leading-6 text-[var(--text2)]">{unit.summary}</p>
<div className={`mt-6 ${publicListClassName}`}>
{guides.filter((doc) => doc.unit === id).map((doc) => (
<PublicListLink key={doc.slug} href={href(docPath(doc))} title={doc.title} description={doc.description} />
))}
</div>
</section>
);
})}

<section className="site-wrap pb-20">
<div className="border-t border-[var(--separator)] pt-8">
Expand Down
8 changes: 4 additions & 4 deletions apps/web/src/app/[locale]/(public)/lessons/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ import { ContentArticle } from "@/app/components/docs/ContentArticle";
import { pageMetadata } from "@/i18n/config";
import { getDictionary } from "@/i18n/messages";
import { resolveLocale } from "@/i18n/server";
import { docs, docPath, getDoc } from "@/lib/docs";
import { docs, docPath, getDoc, isGuide } from "@/lib/docs";

type PageProps = { params: Promise<{ locale: string; slug: string }> };

export function generateStaticParams() {
return docs.filter((doc) => doc.unit !== "pseudoeditor").map((doc) => ({ slug: doc.slug }));
return docs.filter((doc) => !isGuide(doc)).map((doc) => ({ slug: doc.slug }));
}

export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const locale = await resolveLocale(params);
const { slug } = await params;
const doc = getDoc(locale, slug);
if (!doc || doc.unit === "pseudoeditor") return {};
if (!doc || isGuide(doc)) return {};
const base = pageMetadata(locale, docPath(doc), doc.title, doc.description, getDictionary(locale).meta.ogImageAlt);
return { ...base, openGraph: { ...base.openGraph, type: "article", modifiedTime: doc.updated } };
}
Expand All @@ -25,6 +25,6 @@ export default async function LessonPage({ params }: PageProps) {
const locale = await resolveLocale(params);
const { slug } = await params;
const doc = getDoc(locale, slug);
if (!doc || doc.unit === "pseudoeditor") notFound();
if (!doc || isGuide(doc)) notFound();
return <ContentArticle locale={locale} doc={doc} />;
}
Loading
Loading