diff --git a/astro.config.mjs b/astro.config.mjs index b1e78c4..36fb09f 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -12,8 +12,20 @@ export default defineConfig({ integrations: [ starlight({ title: 'Coral Docs', - description: 'Documentation for the Coral ecosystem of Jellyfin modules', + description: + "Install, configure and operate Coral's open-source Jellyfin modules. Each one runs as a Docker container and does one thing well.", customCss: ['./src/styles.css'], + // Adds the JSON-LD graph, the social card and non-blocking fonts that + // Starlight does not ship. See src/components/Head.astro. + components: { + Head: './src/components/Head.astro', + }, + // Freshness signal. The docs drifted a long way from the code once + // already; showing the date makes the next drift visible. + lastUpdated: true, + editLink: { + baseUrl: 'https://github.com/Get-Coral/docs/edit/main/', + }, expressiveCode: { themes: ['github-dark'], useStarlightDarkModeSwitch: false, diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000..d40ecfa Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/public/favicon.svg b/public/favicon.svg index cba5ac1..b1dbcb8 100644 --- a/public/favicon.svg +++ b/public/favicon.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/public/icon-192.png b/public/icon-192.png new file mode 100644 index 0000000..ea6b519 Binary files /dev/null and b/public/icon-192.png differ diff --git a/public/icon-512.png b/public/icon-512.png new file mode 100644 index 0000000..f9648e8 Binary files /dev/null and b/public/icon-512.png differ diff --git a/public/site.webmanifest b/public/site.webmanifest new file mode 100644 index 0000000..52a2fcb --- /dev/null +++ b/public/site.webmanifest @@ -0,0 +1,14 @@ +{ + "name": "Coral Docs", + "short_name": "Coral Docs", + "description": "Install, configure and operate Coral's open-source Jellyfin modules.", + "start_url": "/", + "display": "standalone", + "background_color": "#090f22", + "theme_color": "#090f22", + "icons": [ + { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" }, + { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }, + { "src": "/favicon.svg", "sizes": "any", "type": "image/svg+xml" } + ] +} diff --git a/src/assets/houston.webp b/src/assets/houston.webp deleted file mode 100644 index 930c164..0000000 Binary files a/src/assets/houston.webp and /dev/null differ diff --git a/src/components/Head.astro b/src/components/Head.astro new file mode 100644 index 0000000..495c0ca --- /dev/null +++ b/src/components/Head.astro @@ -0,0 +1,101 @@ +--- +/** + * Starlight's own Head, plus the things it does not ship: a social card, a + * JSON-LD graph, and non-render-blocking fonts. + * + * Before this existed the site emitted `twitter:card=summary_large_image` with + * no image behind it, so every share rendered blank, and no structured data at + * all while the marketing site next door published a full graph. + */ +import Default from "@astrojs/starlight/components/Head.astro"; +import { moduleForDocId } from "../lib/modules"; +import { + breadcrumbNode, + graph, + organizationNode, + softwareApplicationNode, + techArticleNode, + webSiteNode, +} from "../lib/schema"; +import { absoluteUrl, SITE_NAME, SITE_URL } from "../lib/site"; + +const route = Astro.locals.starlightRoute; +const { entry, id, lastUpdated } = route; + +const pageUrl = new URL(Astro.url.pathname, SITE_URL).toString(); +const ogImage = absoluteUrl(`${id ? `/${id}` : ""}/og.png`); + +const module = moduleForDocId(id); +const title = entry.data.title; +const description = entry.data.description ?? ""; + +/** "modules/aurora" -> Docs -> Modules -> Aurora. */ +const SECTIONS: Record = { + "getting-started": "Getting started", + modules: "Modules", + libraries: "Libraries", + contributing: "Contributing", +}; + +// Starlight serves a 404 at a real URL. It should not be indexed, and it +// should not claim to be an article about anything. +const is404 = id === "404"; + +// The splash page's collection id is "index", not "". +const isHome = id === "" || id === "index"; +const section = isHome ? "" : id.split("/")[0]; +const trail = [{ name: SITE_NAME, url: `${SITE_URL}/` }]; +if (section && SECTIONS[section]) { + // There are no section landing pages, so this crumb points at the current + // page rather than at a URL that would 404. + trail.push({ name: SECTIONS[section], url: pageUrl }); +} +if (!isHome) trail.push({ name: title, url: pageUrl }); + +const breadcrumb = trail.length > 1 ? breadcrumbNode(pageUrl, trail) : undefined; + +const nodes = [ + organizationNode(), + webSiteNode(), + techArticleNode({ + url: pageUrl, + name: title, + description, + image: ogImage, + breadcrumbId: breadcrumb ? `${pageUrl}#breadcrumb` : undefined, + dateModified: lastUpdated?.toISOString(), + about: module ? `${pageUrl}#software` : undefined, + }), +]; +if (breadcrumb) nodes.push(breadcrumb); +if (module) nodes.push(softwareApplicationNode(module)); + +const jsonLd = JSON.stringify(graph(nodes)); +--- + +{is404 && } + + + +{/* Fonts. These used to be an @import at the top of styles.css, which blocks + render until the remote stylesheet is fetched and parsed. */} + + + + + + + + + + + + + + + + +{!is404 &&