starlight-theme-celestia 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/lib/aside.css +13 -0
  2. package/lib/badge.css +23 -0
  3. package/lib/card.css +42 -0
  4. package/lib/fonts.css +4 -0
  5. package/lib/layer.css +31 -0
  6. package/lib/markdown.css +71 -0
  7. package/lib/shiki.css +79 -0
  8. package/lib/styles.css +6 -0
  9. package/lib/tailwind.build.css +2 -0
  10. package/lib/tailwind.css +29 -0
  11. package/lib/tailwind.gen.css +1197 -0
  12. package/lib/theme.css +94 -0
  13. package/package.json +56 -0
  14. package/src/astro.d.ts +6 -0
  15. package/src/components/Code.astro +12 -0
  16. package/src/components/CodeCopy.astro +39 -0
  17. package/src/components/CodeFile.astro +64 -0
  18. package/src/components/CodePackageManagers.astro +55 -0
  19. package/src/components/CodeTabItem.astro +13 -0
  20. package/src/components/CodeTabs.astro +67 -0
  21. package/src/components/Head.astro +7 -0
  22. package/src/components/Header.astro +91 -0
  23. package/src/components/Hero.astro +169 -0
  24. package/src/components/LanguageSelect.astro +5 -0
  25. package/src/components/LinkButton.astro +47 -0
  26. package/src/components/LinkButtonIcon.astro +22 -0
  27. package/src/components/LinkCard.astro +32 -0
  28. package/src/components/MarkdownContent.astro +22 -0
  29. package/src/components/MobileMenuFooter.astro +11 -0
  30. package/src/components/MobileMenuToggle.astro +23 -0
  31. package/src/components/MobileTableOfContents.astro +26 -0
  32. package/src/components/PageFrame.astro +50 -0
  33. package/src/components/Pagination.astro +34 -0
  34. package/src/components/PaginationLink.astro +30 -0
  35. package/src/components/Search.astro +645 -0
  36. package/src/components/SiteTitle.astro +47 -0
  37. package/src/components/SiteTitleVersioned.astro +62 -0
  38. package/src/components/SocialIcons.astro +31 -0
  39. package/src/components/ThemeProvider.astro +102 -0
  40. package/src/components/ThemeSelect.astro +188 -0
  41. package/src/components/TwoColumnContent.astro +44 -0
  42. package/src/components/VersionSelect.astro +261 -0
  43. package/src/components/get-i18n-text.ts +39 -0
  44. package/src/components/index.ts +7 -0
  45. package/src/components/mobile-menu-toggle.ts +49 -0
  46. package/src/components/rehype-code-tabs.ts +52 -0
  47. package/src/constants.ts +7 -0
  48. package/src/content.config.ts +16 -0
  49. package/src/content.d.ts +22 -0
  50. package/src/icons/lucide-arrow-left.svg +1 -0
  51. package/src/icons/lucide-arrow-right.svg +1 -0
  52. package/src/icons/lucide-check.svg +1 -0
  53. package/src/icons/lucide-chevron-left.svg +1 -0
  54. package/src/icons/lucide-chevron-right.svg +1 -0
  55. package/src/icons/lucide-clipboard.svg +1 -0
  56. package/src/icons/lucide-menu.svg +1 -0
  57. package/src/icons/lucide-search.svg +1 -0
  58. package/src/icons/lucide-x.svg +1 -0
  59. package/src/icons/tabler-moon-filled.svg +1 -0
  60. package/src/icons/tabler-sun-high-filled.svg +1 -0
  61. package/src/index.ts +112 -0
  62. package/src/shiki-config.ts +49 -0
  63. package/src/shiki-meta-title.ts +6 -0
  64. package/src/shiki-transformer-container.ts +85 -0
  65. package/src/types.d.ts +2 -0
  66. package/src/user-options.ts +37 -0
  67. package/src/virtual-internal.d.ts +44 -0
  68. package/src/virtual-user-config.ts +44 -0
package/lib/theme.css ADDED
@@ -0,0 +1,94 @@
1
+ :root,
2
+ ::backdrop {
3
+ --sl-content-width: 55rem;
4
+ --sl-sidebar-width: 17rem;
5
+ --sl-font: "Inter", system-ui, sans-serif;
6
+
7
+ /* Prevent adjustments of font size after orientation changes in iOS. */
8
+ -webkit-text-size-adjust: 100%;
9
+ }
10
+
11
+ /* Dark mode Starlight theme variables (default). */
12
+ :root {
13
+ --sl-color-white: white;
14
+ --sl-color-gray-1: var(--color-gray-200);
15
+ --sl-color-gray-2: var(--color-gray-300);
16
+ --sl-color-gray-3: var(--color-gray-400);
17
+ --sl-color-gray-4: var(--color-gray-600);
18
+ --sl-color-gray-5: var(--color-gray-700);
19
+ --sl-color-gray-6: var(--color-gray-800);
20
+ --sl-color-black: var(--color-gray-950);
21
+
22
+ --sl-color-bg-inline-code: var(--color-gray-800);
23
+ --sl-color-border-inline-code: var(--color-gray-700);
24
+ --sl-color-bg-nav: color-mix(in oklch, var(--color-gray-950) 50%, transparent);
25
+
26
+ --sl-color-orange-low: var(--color-amber-950);
27
+ --sl-color-orange: var(--color-amber-900);
28
+ --sl-color-orange-high: var(--color-amber-200);
29
+
30
+ --sl-color-green-low: var(--color-green-950);
31
+ --sl-color-green: var(--color-green-900);
32
+ --sl-color-green-high: var(--color-green-200);
33
+
34
+ --sl-color-blue-low: var(--color-blue-950);
35
+ --sl-color-blue: var(--color-blue-900);
36
+ --sl-color-blue-high: var(--color-blue-200);
37
+
38
+ --sl-color-purple-low: var(--color-purple-950);
39
+ --sl-color-purple: var(--color-purple-900);
40
+ --sl-color-purple-high: var(--color-purple-200);
41
+
42
+ --sl-color-red-low: var(--color-red-950);
43
+ --sl-color-red: var(--color-red-900);
44
+ --sl-color-red-high: var(--color-red-200);
45
+
46
+ --nano-color-highlight: var(--sl-color-gray-5);
47
+ }
48
+
49
+ /* Light mode Starlight theme variables */
50
+ :root[data-theme="light"] {
51
+ --sl-color-white: var(--color-gray-900);
52
+ --sl-color-gray-1: var(--color-gray-800);
53
+ --sl-color-gray-2: var(--color-gray-700);
54
+ --sl-color-gray-3: var(--color-gray-500);
55
+ --sl-color-gray-4: var(--color-gray-400);
56
+ --sl-color-gray-5: var(--color-gray-300);
57
+ --sl-color-gray-6: var(--color-gray-200);
58
+ --sl-color-gray-7: var(--color-gray-100);
59
+ --sl-color-black: white;
60
+
61
+ --sl-color-bg-inline-code: var(--color-gray-100);
62
+ --sl-color-border-inline-code: var(--color-gray-300);
63
+ --sl-color-bg-nav: color-mix(in oklch, var(--color-white) 80%, transparent);
64
+
65
+ --sl-color-orange-low: var(--color-amber-100);
66
+ --sl-color-orange: var(--color-amber-400);
67
+ --sl-color-orange-high: var(--color-amber-800);
68
+
69
+ --sl-color-green-low: var(--color-green-100);
70
+ --sl-color-green: var(--color-green-400);
71
+ --sl-color-green-high: var(--color-green-800);
72
+
73
+ --sl-color-blue-low: var(--color-blue-100);
74
+ --sl-color-blue: var(--color-blue-400);
75
+ --sl-color-blue-high: var(--color-blue-800);
76
+
77
+ --sl-color-purple-low: var(--color-purple-100);
78
+ --sl-color-purple: var(--color-purple-400);
79
+ --sl-color-purple-high: var(--color-purple-800);
80
+
81
+ --sl-color-red-low: var(--color-red-100);
82
+ --sl-color-red: var(--color-red-400);
83
+ --sl-color-red-high: var(--color-red-800);
84
+
85
+ --nano-color-highlight: var(--sl-color-gray-6);
86
+ }
87
+
88
+ .sl-markdown-content [data-celestia-code-container] pre.astro-code,
89
+ .sl-markdown-content [data-celestia-code-container] pre.astro-code code {
90
+ border-width: 0;
91
+ border-style: solid;
92
+ border-color: transparent;
93
+ border-radius: 0;
94
+ }
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "starlight-theme-celestia",
3
+ "type": "module",
4
+ "version": "0.2.0",
5
+ "description": "A clean, modern theme for Astro Starlight",
6
+ "license": "MIT",
7
+ "sideEffects": false,
8
+ "main": "./src/index.ts",
9
+ "exports": {
10
+ ".": "./src/index.ts",
11
+ "./*.css": "./lib/*.css",
12
+ "./components": "./src/components/index.ts",
13
+ "./components/*.astro": "./src/components/*.astro"
14
+ },
15
+ "files": [
16
+ "lib",
17
+ "src"
18
+ ],
19
+ "scripts": {
20
+ "build": "bun run build:tailwindcss",
21
+ "build:tailwindcss": "tailwindcss -i ./lib/tailwind.build.css -o ./lib/tailwind.gen.css"
22
+ },
23
+ "dependencies": {
24
+ "@aria-ui/core": "^0.2.0",
25
+ "@aria-ui/utils": "^0.1.5",
26
+ "@fontsource/inter": "^5.0.0",
27
+ "@lorenzo_lewis/starlight-utils": "^0.3.0",
28
+ "@pagefind/default-ui": "^1.5.2",
29
+ "@shikijs/transformers": "^4.0.2",
30
+ "@shikijs/twoslash": "^4.0.2",
31
+ "@shikijs/types": "^4.0.2",
32
+ "@types/hast": "^3.0.4",
33
+ "hast-util-is-element": "^3.0.0",
34
+ "rehype": "^13.0.2",
35
+ "remark-custom-header-id": "^1.0.0",
36
+ "shiki-twoslash-renderer": "^0.3.3",
37
+ "starlight-versions": "^0.8.0"
38
+ },
39
+ "peerDependencies": {
40
+ "@astrojs/starlight": "*"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "@astrojs/starlight": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "devDependencies": {
48
+ "@astrojs/starlight": "^0.38.3",
49
+ "@tailwindcss/cli": "^4.2.2",
50
+ "@tailwindcss/vite": "^4.2.2",
51
+ "@types/node": "^20.17.30",
52
+ "astro": "^6.1.6",
53
+ "tailwindcss": "^4.2.2",
54
+ "typescript": "^5.9.3"
55
+ }
56
+ }
package/src/astro.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ declare module "*.astro" {
2
+ import type { AstroComponentFactory } from "astro/runtime/server/index.js";
3
+
4
+ const content: AstroComponentFactory;
5
+ export default content;
6
+ }
@@ -0,0 +1,12 @@
1
+ ---
2
+ import type { ComponentProps } from 'astro/types'
3
+ import { Code as CodeComponent } from 'astro:components'
4
+ import { createShikiConfig } from '../shiki-config'
5
+
6
+ type Props = ComponentProps<typeof CodeComponent>
7
+
8
+ // For unknown reasons, enabling twoslash breaks the build, thus twoslash is disabled here.
9
+ const shikiConfig = createShikiConfig({ twoslash: false })
10
+ ---
11
+
12
+ <CodeComponent {...shikiConfig} {...Astro.props} />
@@ -0,0 +1,39 @@
1
+ <script>
2
+ import ClipboardIcon from '../icons/lucide-clipboard.svg?raw'
3
+ import CheckIcon from '../icons/lucide-check.svg?raw'
4
+
5
+ class CodeCopyButton extends HTMLElement {
6
+ constructor() {
7
+ super()
8
+ }
9
+
10
+ connectedCallback() {
11
+ const update = () => {
12
+ const iconHtml = state === 'ready' ? ClipboardIcon : CheckIcon
13
+ this.innerHTML =
14
+ '<span class="w-full h-full block [&_svg]:w-full [&_svg]:h-full">' +
15
+ iconHtml +
16
+ '</span>'
17
+ }
18
+
19
+ let state: 'ready' | 'success' = 'ready'
20
+ update()
21
+
22
+ this.addEventListener('click', () => {
23
+ if (state === 'ready') {
24
+ state = 'success'
25
+ update()
26
+
27
+ const code = this.dataset.code || ''
28
+ void navigator.clipboard.writeText(code)
29
+ setTimeout(() => {
30
+ state = 'ready'
31
+ update()
32
+ }, 1500)
33
+ }
34
+ })
35
+ }
36
+ }
37
+
38
+ customElements.define('celestia-code-copy-button', CodeCopyButton)
39
+ </script>
@@ -0,0 +1,64 @@
1
+ ---
2
+ import type { ComponentProps } from 'astro/types'
3
+ import { existsSync } from 'node:fs'
4
+ import fs from 'node:fs/promises'
5
+ import { basename } from 'node:path'
6
+ import Code from './Code.astro'
7
+ import config from 'virtual:starlight-theme-celestia/user-config'
8
+ import { fileURLToPath } from 'node:url'
9
+
10
+ type CodeProps = ComponentProps<typeof Code>
11
+
12
+ interface Props extends Omit<CodeProps, 'code' | 'lang'> {
13
+ /**
14
+ * The file path relative to the project root.
15
+ */
16
+ path: string
17
+
18
+ /**
19
+ * The title of the file. If not provided, the file name will be used.
20
+ */
21
+ title?: string
22
+
23
+ /**
24
+ * The language of the file. If not provided, the file extension will be used.
25
+ */
26
+ lang?: CodeProps['lang']
27
+ }
28
+
29
+ const { path, title, lang, meta, ...rest } = Astro.props
30
+
31
+ if (!path) {
32
+ throw new Error('path is required for <CodeFile> component')
33
+ }
34
+
35
+ const root = new URL(config.rootHref)
36
+ const url = new URL(path, root)
37
+ const absolutePath = fileURLToPath(url)
38
+ if (!existsSync(absolutePath)) {
39
+ throw new Error(`Unable to find file ${absolutePath}`)
40
+ }
41
+
42
+ let code: string
43
+ try {
44
+ code = await fs.readFile(absolutePath, 'utf-8')
45
+ } catch (error) {
46
+ throw new Error(`Unable to read file ${absolutePath}: ${error}`, {
47
+ cause: error,
48
+ })
49
+ }
50
+
51
+ let fileName = basename(path)
52
+ let defaultLang = (fileName.split('.').pop() || 'plaintext') as 'plaintext'
53
+ let defaultTitle = fileName
54
+ let titleMeta = `title="${title || defaultTitle}"`
55
+
56
+ const codeProps: CodeProps = {
57
+ ...rest,
58
+ lang: lang ?? defaultLang,
59
+ meta: meta ? `${meta} ${titleMeta}` : titleMeta,
60
+ code,
61
+ }
62
+ ---
63
+
64
+ <Code {...codeProps} />
@@ -0,0 +1,55 @@
1
+ ---
2
+ import { CodeTabItem, CodeTabs } from 'starlight-theme-celestia/components'
3
+
4
+ type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun'
5
+
6
+ interface Props {
7
+ /**
8
+ * The package managers to use.
9
+ *
10
+ * @default ['pnpm', 'npm', 'yarn', 'bun']
11
+ */
12
+ packageManagers?: PackageManager[]
13
+
14
+ /**
15
+ * The packages to install. If you want to install multiple packages, you can pass a space-separated string.
16
+ */
17
+ packages: string
18
+
19
+ /**
20
+ * Whether to install the packages as dev dependencies.
21
+ *
22
+ * @default false
23
+ */
24
+ dev?: boolean
25
+ }
26
+
27
+ const props: Props = Astro.props
28
+
29
+ const packageManagers = props.packageManagers ?? ['pnpm', 'npm', 'yarn', 'bun']
30
+
31
+ function getCode(packageManager: PackageManager) {
32
+ const parts: string[] = [
33
+ {
34
+ pnpm: 'pnpm add',
35
+ npm: 'npm install',
36
+ yarn: 'yarn add',
37
+ bun: 'bun add',
38
+ }[packageManager],
39
+
40
+ props.dev ? '-D' : '',
41
+
42
+ props.packages,
43
+ ]
44
+
45
+ return parts.filter(Boolean).join(' ')
46
+ }
47
+ ---
48
+
49
+ <CodeTabs syncKey="code-group-installation">
50
+ {
51
+ packageManagers.map((pkg) => (
52
+ <CodeTabItem label={pkg} lang="shell" code={getCode(pkg)} />
53
+ ))
54
+ }
55
+ </CodeTabs>
@@ -0,0 +1,13 @@
1
+ ---
2
+ import { TabItem } from '@astrojs/starlight/components'
3
+ import Code from './Code.astro'
4
+ import type { ComponentProps } from 'astro/types'
5
+
6
+ type Props = { label: string } & ComponentProps<typeof Code>
7
+
8
+ const { label, ...codeProps } = Astro.props
9
+ ---
10
+
11
+ <TabItem label={label}>
12
+ <Code {...codeProps} />
13
+ </TabItem>
@@ -0,0 +1,67 @@
1
+ ---
2
+ import { Tabs } from '@astrojs/starlight/components'
3
+ import { processCodeTabs } from './rehype-code-tabs'
4
+
5
+ interface Props {
6
+ border?: boolean
7
+ syncKey?: string
8
+ }
9
+
10
+ const { border = true, syncKey } = Astro.props
11
+
12
+ const originalHtml = await Astro.slots.render('default')
13
+ const processedHtml = processCodeTabs(originalHtml)
14
+ ---
15
+
16
+ <div class:list={['code-tabs', border ? 'code-tabs-border' : undefined]}>
17
+ <Tabs syncKey={syncKey}>
18
+ <Fragment set:html={processedHtml} />
19
+ </Tabs>
20
+ </div>
21
+
22
+ <style is:global>
23
+ @layer utilities {
24
+ .sl-markdown-content .code-tabs {
25
+ &.code-tabs-border {
26
+ border-color: var(--sl-color-gray-5);
27
+ border-width: 1px;
28
+ border-style: solid;
29
+ border-radius: 0.5rem;
30
+ }
31
+
32
+ [role='tablist'] {
33
+ border-bottom-width: 1px;
34
+ }
35
+
36
+ .tablist-wrapper {
37
+ [role='tab'] {
38
+ font-family: var(--sl-font-system-mono);
39
+ padding-top: 0.6rem;
40
+ padding-bottom: 0.6rem;
41
+ padding-left: 0.75rem;
42
+ padding-right: 0.75rem;
43
+ font-size: 0.875rem;
44
+ white-space: nowrap;
45
+ }
46
+ }
47
+
48
+ starlight-tabs {
49
+ margin-top: 0rem;
50
+ }
51
+
52
+ div[role='tabpanel'] {
53
+ margin: 0;
54
+ }
55
+
56
+ .astro-code {
57
+ border-radius: 0;
58
+ }
59
+
60
+ [data-celestia-code-container] {
61
+ border-radius: 0;
62
+ border-width: 0;
63
+ border-color: transparent;
64
+ }
65
+ }
66
+ }
67
+ </style>
@@ -0,0 +1,7 @@
1
+ ---
2
+ import Default from "@astrojs/starlight/components/Head.astro";
3
+ import { ClientRouter } from "astro:transitions";
4
+ ---
5
+
6
+ <Default />
7
+ <ClientRouter />
@@ -0,0 +1,91 @@
1
+ ---
2
+ const { hasSidebar } = Astro.locals.starlightRoute
3
+
4
+ import LanguageSelect from 'virtual:starlight/components/LanguageSelect'
5
+ import Search from 'virtual:starlight/components/Search'
6
+ import SiteTitle from 'virtual:starlight/components/SiteTitle'
7
+ import SocialIcons from 'virtual:starlight/components/SocialIcons'
8
+ import ThemeSelect from 'virtual:starlight/components/ThemeSelect'
9
+
10
+ import options from 'virtual:starlight-theme-celestia/user-config'
11
+ import MobileMenuToggle from './MobileMenuToggle.astro'
12
+ import { getI18nText } from './get-i18n-text'
13
+
14
+ const nav = options.nav ?? []
15
+
16
+ const route = Astro.locals.starlightRoute
17
+ ---
18
+
19
+ <div class="header-bar">
20
+ <div class="header-start">
21
+ <div
22
+ class:list={[
23
+ '-m-3 overflow-clip p-3',
24
+ 'flex min-w-0',
25
+ ]}
26
+ >
27
+ <SiteTitle />
28
+ </div>
29
+ <nav
30
+ class="flex flex-row gap-4 overflow-x-auto py-3 pr-4 pl-4 text-sm font-medium max-md:**:hidden xl:gap-6 xl:pl-6"
31
+ >
32
+ {
33
+ nav.map((item) => (
34
+ <a
35
+ class="-m-1.5 rounded-md p-1.5 text-(--sl-color-gray-3) no-underline hover:text-(--sl-color-white) focus-visible:outline-offset-0"
36
+ href={getI18nText(item.href, route)}
37
+ >
38
+ {getI18nText(item.label, route)}
39
+ </a>
40
+ ))
41
+ }
42
+ </nav>
43
+ </div>
44
+ <div class="header-center print:hidden">
45
+ <Search />
46
+ </div>
47
+ <div class="header-end">
48
+ <div class="hidden items-center gap-4 md:flex print:hidden">
49
+ <SocialIcons />
50
+ <LanguageSelect />
51
+ <ThemeSelect />
52
+ </div>
53
+ {
54
+ hasSidebar && (
55
+ <div class="flex items-center gap-2 md:hidden print:hidden">
56
+ <MobileMenuToggle />
57
+ </div>
58
+ )
59
+ }
60
+ </div>
61
+ </div>
62
+
63
+ <style>
64
+ .header-bar {
65
+ display: flex;
66
+ align-items: center;
67
+ height: 100%;
68
+ box-sizing: border-box;
69
+ }
70
+
71
+ .header-start {
72
+ display: flex;
73
+ align-items: center;
74
+ min-width: 0;
75
+ flex-shrink: 0;
76
+ }
77
+
78
+ .header-center {
79
+ flex: 1;
80
+ display: flex;
81
+ justify-content: center;
82
+ max-width: 24rem;
83
+ margin: 0 auto;
84
+ }
85
+
86
+ .header-end {
87
+ display: flex;
88
+ align-items: center;
89
+ flex-shrink: 0;
90
+ }
91
+ </style>
@@ -0,0 +1,169 @@
1
+ ---
2
+ import { Image } from 'astro:assets'
3
+ import { PAGE_TITLE_ID } from '../constants'
4
+ import LinkButton from './LinkButton.astro'
5
+ import type { StarlightRouteEntryData } from '../content'
6
+
7
+ const data = Astro.locals.starlightRoute.entry.data as StarlightRouteEntryData
8
+
9
+ const { title = data.title, tagline, image, actions = [] } = data.hero || {}
10
+
11
+ const imageAttrs = {
12
+ loading: 'eager' as const,
13
+ decoding: 'async' as const,
14
+ width: 400,
15
+ height: 400,
16
+ alt: image?.alt || '',
17
+ }
18
+
19
+ let darkImage: ImageMetadata | undefined
20
+ let lightImage: ImageMetadata | undefined
21
+ let rawHtml: string | undefined
22
+ if (image) {
23
+ if ('file' in image) {
24
+ darkImage = image.file
25
+ } else if ('dark' in image) {
26
+ darkImage = image.dark
27
+ lightImage = image.light
28
+ } else {
29
+ rawHtml = image.html
30
+ }
31
+ }
32
+ ---
33
+
34
+ <div class="hero">
35
+ {
36
+ darkImage && (
37
+ <Image
38
+ src={darkImage}
39
+ {...imageAttrs}
40
+ class:list={{ 'light:sl-hidden': Boolean(lightImage) }}
41
+ />
42
+ )
43
+ }
44
+ {
45
+ lightImage && (
46
+ <Image src={lightImage} {...imageAttrs} class="dark:sl-hidden" />
47
+ )
48
+ }
49
+ {rawHtml && <div class="hero-html sl-flex" set:html={rawHtml} />}
50
+ <div class="sl-flex stack">
51
+ <div class="sl-flex copy">
52
+ <h1 id={PAGE_TITLE_ID} data-page-title set:html={title} />
53
+ {tagline && <div class="tagline" set:html={tagline} />}
54
+ </div>
55
+ {
56
+ actions.length > 0 && (
57
+ <div class="sl-flex actions">
58
+ {actions.map(
59
+ ({
60
+ attrs: { class: className, ...attrs } = {},
61
+ icon,
62
+ link: href,
63
+ text,
64
+ variant,
65
+ }) => (
66
+ <LinkButton
67
+ {href}
68
+ {variant}
69
+ icon={icon?.name}
70
+ class:list={[className]}
71
+ {...attrs}
72
+ >
73
+ {text}
74
+ {icon?.html && <Fragment set:html={icon.html} />}
75
+ </LinkButton>
76
+ ),
77
+ )}
78
+ </div>
79
+ )
80
+ }
81
+ </div>
82
+ </div>
83
+
84
+ <style>
85
+ @layer celestia {
86
+ .hero {
87
+ display: grid;
88
+ align-items: center;
89
+ gap: 1rem;
90
+ padding-bottom: 1rem;
91
+ }
92
+
93
+ .hero > img,
94
+ .hero > .hero-html {
95
+ object-fit: contain;
96
+ width: min(70%, 20rem);
97
+ height: auto;
98
+ margin-inline: auto;
99
+ }
100
+
101
+ .stack {
102
+ flex-direction: column;
103
+ gap: clamp(1.5rem, calc(1.5rem + 1vw), 2rem);
104
+ text-align: center;
105
+ }
106
+
107
+ .copy {
108
+ flex-direction: column;
109
+ gap: 1rem;
110
+ align-items: center;
111
+ }
112
+
113
+ .copy > * {
114
+ max-width: 50ch;
115
+ }
116
+
117
+ h1 {
118
+ font-size: clamp(
119
+ var(--sl-text-3xl),
120
+ calc(0.25rem + 5vw),
121
+ var(--sl-text-6xl)
122
+ );
123
+ line-height: var(--sl-line-height-headings);
124
+ font-weight: 600;
125
+ color: var(--sl-color-white);
126
+ }
127
+
128
+ .tagline {
129
+ font-size: clamp(
130
+ var(--sl-text-base),
131
+ calc(0.0625rem + 2vw),
132
+ var(--sl-text-xl)
133
+ );
134
+ color: var(--sl-color-gray-2);
135
+ }
136
+
137
+ .actions {
138
+ gap: 1rem 2rem;
139
+ flex-wrap: wrap;
140
+ justify-content: center;
141
+ }
142
+
143
+ @media (min-width: 50rem) {
144
+ .hero {
145
+ grid-template-columns: 7fr 4fr;
146
+ gap: 3%;
147
+ padding-block: clamp(2.5rem, calc(1rem + 10vmin), 10rem);
148
+ }
149
+
150
+ .hero > img,
151
+ .hero > .hero-html {
152
+ order: 2;
153
+ width: min(100%, 25rem);
154
+ }
155
+
156
+ .stack {
157
+ text-align: start;
158
+ }
159
+
160
+ .copy {
161
+ align-items: flex-start;
162
+ }
163
+
164
+ .actions {
165
+ justify-content: flex-start;
166
+ }
167
+ }
168
+ }
169
+ </style>
@@ -0,0 +1,5 @@
1
+ ---
2
+ import Default from '@astrojs/starlight/components/LanguageSelect.astro'
3
+ ---
4
+
5
+ <Default />