From 1aa2187944dde4419e523f0087139f5a21efd826 Mon Sep 17 00:00:00 2001
From: Chris Swithinbank
Date: Thu, 22 Jun 2023 18:22:54 +0200
Subject: Support custom 404 pages (#226)
Co-authored-by: Josh Pollara <75546+joshpollara@users.noreply.github.com>
---
.changeset/tiny-sheep-raise.md | 5 ++
docs/src/content/docs/404.md | 13 +++
docs/src/content/docs/guides/customization.mdx | 29 +++++++
packages/starlight/404.astro | 83 +++++++-----------
packages/starlight/components/EmptyMarkdown.md | 0
packages/starlight/index.astro | 113 +-----------------------
packages/starlight/layout/Page.astro | 116 +++++++++++++++++++++++++
packages/starlight/schemas/i18n.ts | 4 +
packages/starlight/translations/de.json | 3 +-
packages/starlight/translations/en.json | 3 +-
packages/starlight/translations/es.json | 3 +-
packages/starlight/translations/fr.json | 3 +-
packages/starlight/translations/it.json | 3 +-
packages/starlight/translations/ja.json | 3 +-
packages/starlight/translations/pt.json | 3 +-
15 files changed, 216 insertions(+), 168 deletions(-)
create mode 100644 .changeset/tiny-sheep-raise.md
create mode 100644 docs/src/content/docs/404.md
create mode 100644 packages/starlight/components/EmptyMarkdown.md
create mode 100644 packages/starlight/layout/Page.astro
diff --git a/.changeset/tiny-sheep-raise.md b/.changeset/tiny-sheep-raise.md
new file mode 100644
index 00000000..07dfedd6
--- /dev/null
+++ b/.changeset/tiny-sheep-raise.md
@@ -0,0 +1,5 @@
+---
+"@astrojs/starlight": minor
+---
+
+Add support for custom 404 pages.
diff --git a/docs/src/content/docs/404.md b/docs/src/content/docs/404.md
new file mode 100644
index 00000000..6772acfb
--- /dev/null
+++ b/docs/src/content/docs/404.md
@@ -0,0 +1,13 @@
+---
+title: Not found
+template: splash
+editUrl: false
+hero:
+ title: '404'
+ tagline: Houston, we have a problem. We couldn’t find that page.
Check the URL or try using the search bar.
+ actions:
+ - text: Go home
+ icon: right-arrow
+ link: /
+ variant: primary
+---
diff --git a/docs/src/content/docs/guides/customization.mdx b/docs/src/content/docs/guides/customization.mdx
index d7d3e5bd..b39c6815 100644
--- a/docs/src/content/docs/guides/customization.mdx
+++ b/docs/src/content/docs/guides/customization.mdx
@@ -236,6 +236,35 @@ export default defineConfig({
});
```
+## Custom 404 page
+
+Starlight sites display a simple 404 page by default.
+You can customize this by adding a `404.md` (or `404.mdx`) file to your `src/content/docs/` directory:
+
+
+
+- src/
+ - content/
+ - docs/
+ - **404.md**
+ - index.md
+- astro.config.mjs
+
+
+
+You can use all of Starlight’s page layout and customization techniques in your 404 page. For example, the default 404 page uses the [`splash` template](#page-layout) and [`hero`](/reference/frontmatter/#hero) component in frontmatter:
+
+```md
+---
+title: '404'
+template: splash
+editUrl: false
+hero:
+ title: '404'
+ tagline: Page not found. Check the URL or try using the search bar.
+---
+```
+
## Custom CSS styles
Customize the styles applied to your Starlight site by providing additional CSS files to modify or extend Starlight’s default styles.
diff --git a/packages/starlight/404.astro b/packages/starlight/404.astro
index 46cf5189..ecd95447 100644
--- a/packages/starlight/404.astro
+++ b/packages/starlight/404.astro
@@ -1,58 +1,39 @@
---
+import { getEntry } from 'astro:content';
import config from 'virtual:starlight/user-config';
-import { pathWithBase } from './utils/base';
+import EmptyContent from './components/EmptyMarkdown.md';
+import Page from './layout/Page.astro';
+import type { StarlightDocsEntry } from './utils/routing';
+import { useTranslations } from './utils/translations';
-// Built-in CSS styles.
-import './style/props.css';
-import './style/reset.css';
-import './style/shiki.css';
-import './style/util.css';
-
-// Layout
-import PageFrame from './layout/PageFrame.astro';
-
-// Components
-import Header from './components/Header.astro';
-import MarkdownContent from './components/MarkdownContent.astro';
-import ThemeProvider from './components/ThemeProvider.astro';
-import SkipLink from './components/SkipLink.astro';
+const { lang = 'en', dir = 'ltr', locale } = config.defaultLocale || {};
+const entryMeta = { dir, lang, locale };
+const t = useTranslations(locale);
-// Important that this is the last import so it can override built-in styles.
-import 'virtual:starlight/user-css';
+const fallbackEntry: StarlightDocsEntry = {
+ slug: '404',
+ id: '404.md' as StarlightDocsEntry['id'],
+ body: '',
+ collection: 'docs',
+ data: {
+ title: '404',
+ template: 'splash',
+ editUrl: false,
+ head: [],
+ hero: { tagline: t('404.text'), actions: [] },
+ },
+ render: async () => ({
+ Content: EmptyContent,
+ headings: [],
+ remarkPluginFrontmatter: {},
+ }),
+};
-const { lang = 'en', dir = 'ltr', locale } = config.defaultLocale || {};
+const userEntry = await getEntry('docs', '404');
+const entry = userEntry || fallbackEntry;
+const { Content, headings } = await entry.render();
---
-
-
-
-
- Not found
-
-
-
-
-
-
-
-
- 404
- Houston, we have a problem.
-
- We couldn’t find that link. Check the address or
- head back home.
-
-
-
-
-
-
-
-
+
+
+
diff --git a/packages/starlight/components/EmptyMarkdown.md b/packages/starlight/components/EmptyMarkdown.md
new file mode 100644
index 00000000..e69de29b
diff --git a/packages/starlight/index.astro b/packages/starlight/index.astro
index 6b5193aa..65c19d85 100644
--- a/packages/starlight/index.astro
+++ b/packages/starlight/index.astro
@@ -1,122 +1,15 @@
---
import type { InferGetStaticPropsType } from 'astro';
-import config from 'virtual:starlight/user-config';
-
-import { getSidebar } from './utils/navigation';
import { paths } from './utils/routing';
-// Built-in CSS styles.
-import './style/props.css';
-import './style/reset.css';
-import './style/shiki.css';
-import './style/util.css';
-
-// Components — can override built-in CSS, but not user CSS.
-import ContentPanel from './components/ContentPanel.astro';
-import FallbackContentNotice from './components/FallbackContentNotice.astro';
-import HeadSEO from './components/HeadSEO.astro';
-import Header from './components/Header.astro';
-import Footer from './components/Footer.astro';
-import MarkdownContent from './components/MarkdownContent.astro';
-import RightSidebar from './components/RightSidebar.astro';
-import Sidebar from './components/Sidebar.astro';
-import SkipLink from './components/SkipLink.astro';
-import ThemeProvider from './components/ThemeProvider.astro';
-import PageFrame from './layout/PageFrame.astro';
-import TwoColumnContent from './layout/TwoColumnContent.astro';
-import Hero from './components/Hero.astro';
-
-// Remark component CSS (needs to override `MarkdownContent.astro`)
-import './style/asides.css';
-
-// Important that this is the last import so it can override built-in styles.
-import 'virtual:starlight/user-css';
+import Page from './layout/Page.astro';
export async function getStaticPaths() {
return paths;
}
type Props = InferGetStaticPropsType;
-
-const { dir, entry, entryMeta, isFallback, lang, locale } = Astro.props;
-const { Content, headings } = await entry.render();
-const sidebar = getSidebar(Astro.url.pathname, locale);
-
-const hasSidebar = entry.data.template !== 'splash';
-const tocConfig = !hasSidebar
- ? false
- : entry.data.tableOfContents !== undefined
- ? entry.data.tableOfContents
- : config.tableOfContents;
-const hasToC = Boolean(tocConfig);
-const hasHero = Boolean(entry.data.hero);
+const { Content, headings } = await Astro.props.entry.render();
---
-
-
-
-
-
-
-
-
-
-
- {hasSidebar && }
-
-
-
- {/* TODO: Revisit how this logic flows. */}
- {entry.data.hero ? (
-
-
-
-
- ) : (
-
-
- {entry.data.title}
-
- {isFallback && }
-
-
-
-
-
- )}
-
-
-
-
-
+
diff --git a/packages/starlight/layout/Page.astro b/packages/starlight/layout/Page.astro
new file mode 100644
index 00000000..b09abe8c
--- /dev/null
+++ b/packages/starlight/layout/Page.astro
@@ -0,0 +1,116 @@
+---
+import config from 'virtual:starlight/user-config';
+import type { MarkdownHeading } from 'astro';
+import { getSidebar } from '../utils/navigation';
+import type { Route } from '../utils/routing';
+
+// Built-in CSS styles.
+import '../style/props.css';
+import '../style/reset.css';
+import '../style/shiki.css';
+import '../style/util.css';
+
+// Components — can override built-in CSS, but not user CSS.
+import ContentPanel from '../components/ContentPanel.astro';
+import FallbackContentNotice from '../components/FallbackContentNotice.astro';
+import Footer from '../components/Footer.astro';
+import HeadSEO from '../components/HeadSEO.astro';
+import Header from '../components/Header.astro';
+import Hero from '../components/Hero.astro';
+import MarkdownContent from '../components/MarkdownContent.astro';
+import RightSidebar from '../components/RightSidebar.astro';
+import Sidebar from '../components/Sidebar.astro';
+import SkipLink from '../components/SkipLink.astro';
+import ThemeProvider from '../components/ThemeProvider.astro';
+import PageFrame from '../layout/PageFrame.astro';
+import TwoColumnContent from '../layout/TwoColumnContent.astro';
+
+// Remark component CSS (needs to override `MarkdownContent.astro`)
+import '../style/asides.css';
+
+// Important that this is the last import so it can override built-in styles.
+import 'virtual:starlight/user-css';
+
+type Props = Route & { headings: MarkdownHeading[] };
+
+const { dir, entry, entryMeta, headings, isFallback, lang, locale } = Astro.props;
+const sidebar = getSidebar(Astro.url.pathname, locale);
+
+const hasSidebar = entry.data.template !== 'splash';
+const tocConfig = !hasSidebar
+ ? false
+ : entry.data.tableOfContents !== undefined
+ ? entry.data.tableOfContents
+ : config.tableOfContents;
+const hasToC = Boolean(tocConfig);
+const hasHero = Boolean(entry.data.hero);
+---
+
+
+
+
+
+
+
+
+
+
+
+ {hasSidebar && }
+
+
+
+ {/* TODO: Revisit how this logic flows. */}
+ {entry.data.hero ? (
+
+
+
+
+ ) : (
+
+
+ {entry.data.title}
+
+ {isFallback && }
+
+
+
+
+
+ )}
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/starlight/schemas/i18n.ts b/packages/starlight/schemas/i18n.ts
index be0aea70..4bac4bec 100644
--- a/packages/starlight/schemas/i18n.ts
+++ b/packages/starlight/schemas/i18n.ts
@@ -98,6 +98,10 @@ function starlightI18nSchema() {
.describe(
'Label shown on the “next page” pagination arrow in the page footer.'
),
+
+ '404.text': z
+ .string()
+ .describe('Text shown on Starlight’s default 404 page'),
})
.partial();
}
diff --git a/packages/starlight/translations/de.json b/packages/starlight/translations/de.json
index fee8b961..da82f791 100644
--- a/packages/starlight/translations/de.json
+++ b/packages/starlight/translations/de.json
@@ -17,5 +17,6 @@
"page.editLink": "Seite bearbeiten",
"page.lastUpdated": "Zuletzt bearbeitet:",
"page.previousLink": "Vorherige Seite",
- "page.nextLink": "Nächste Seite"
+ "page.nextLink": "Nächste Seite",
+ "404.text": "Seite nicht gefunden. Überprüfe die URL oder nutze die Suchleiste."
}
diff --git a/packages/starlight/translations/en.json b/packages/starlight/translations/en.json
index 4bf800a5..5bc396b2 100644
--- a/packages/starlight/translations/en.json
+++ b/packages/starlight/translations/en.json
@@ -17,5 +17,6 @@
"page.editLink": "Edit page",
"page.lastUpdated": "Last updated:",
"page.previousLink": "Previous",
- "page.nextLink": "Next"
+ "page.nextLink": "Next",
+ "404.text": "Page not found. Check the URL or try using the search bar."
}
diff --git a/packages/starlight/translations/es.json b/packages/starlight/translations/es.json
index e03ae58d..8adbe302 100644
--- a/packages/starlight/translations/es.json
+++ b/packages/starlight/translations/es.json
@@ -17,5 +17,6 @@
"page.editLink": "Edita esta página",
"page.lastUpdated": "Última actualización:",
"page.previousLink": "Página anterior",
- "page.nextLink": "Siguiente página"
+ "page.nextLink": "Siguiente página",
+ "404.text": "Página no encontrada. Verifique la URL o intente usar la barra de búsqueda."
}
diff --git a/packages/starlight/translations/fr.json b/packages/starlight/translations/fr.json
index a1c437b7..345cb05c 100644
--- a/packages/starlight/translations/fr.json
+++ b/packages/starlight/translations/fr.json
@@ -17,5 +17,6 @@
"page.editLink": "Editer la page",
"page.lastUpdated": "Dernière mise à jour :",
"page.previousLink": "Précédent",
- "page.nextLink": "Suivant"
+ "page.nextLink": "Suivant",
+ "404.text": "Page non trouvée. Vérifiez l'URL ou essayez d'utiliser la barre de recherche."
}
diff --git a/packages/starlight/translations/it.json b/packages/starlight/translations/it.json
index b9991267..0560fb90 100644
--- a/packages/starlight/translations/it.json
+++ b/packages/starlight/translations/it.json
@@ -17,5 +17,6 @@
"page.editLink": "Modifica pagina",
"page.lastUpdated": "Ultimo aggiornamento:",
"page.previousLink": "Indietro",
- "page.nextLink": "Avanti"
+ "page.nextLink": "Avanti",
+ "404.text": "Pagina non trovata. Verifica l'URL o prova a utilizzare la barra di ricerca."
}
diff --git a/packages/starlight/translations/ja.json b/packages/starlight/translations/ja.json
index 75e2b06e..1f199b48 100644
--- a/packages/starlight/translations/ja.json
+++ b/packages/starlight/translations/ja.json
@@ -17,5 +17,6 @@
"page.editLink": "ページを編集",
"page.lastUpdated": "最終更新日:",
"page.previousLink": "前へ",
- "page.nextLink": "次へ"
+ "page.nextLink": "次へ",
+ "404.text": "ページが見つかりません。 URL を確認するか、検索バーを使用してみてください。"
}
diff --git a/packages/starlight/translations/pt.json b/packages/starlight/translations/pt.json
index 17908cd1..2b379035 100644
--- a/packages/starlight/translations/pt.json
+++ b/packages/starlight/translations/pt.json
@@ -17,5 +17,6 @@
"page.editLink": "Editar página",
"page.lastUpdated": "Última atualização:",
"page.previousLink": "Anterior",
- "page.nextLink": "Próximo"
+ "page.nextLink": "Próximo",
+ "404.text": "Página não encontrada. Verifique o URL ou tente usar a barra de pesquisa."
}
--
cgit