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.
- package/lib/aside.css +13 -0
- package/lib/badge.css +23 -0
- package/lib/card.css +42 -0
- package/lib/fonts.css +4 -0
- package/lib/layer.css +31 -0
- package/lib/markdown.css +71 -0
- package/lib/shiki.css +79 -0
- package/lib/styles.css +6 -0
- package/lib/tailwind.build.css +2 -0
- package/lib/tailwind.css +29 -0
- package/lib/tailwind.gen.css +1197 -0
- package/lib/theme.css +94 -0
- package/package.json +56 -0
- package/src/astro.d.ts +6 -0
- package/src/components/Code.astro +12 -0
- package/src/components/CodeCopy.astro +39 -0
- package/src/components/CodeFile.astro +64 -0
- package/src/components/CodePackageManagers.astro +55 -0
- package/src/components/CodeTabItem.astro +13 -0
- package/src/components/CodeTabs.astro +67 -0
- package/src/components/Head.astro +7 -0
- package/src/components/Header.astro +91 -0
- package/src/components/Hero.astro +169 -0
- package/src/components/LanguageSelect.astro +5 -0
- package/src/components/LinkButton.astro +47 -0
- package/src/components/LinkButtonIcon.astro +22 -0
- package/src/components/LinkCard.astro +32 -0
- package/src/components/MarkdownContent.astro +22 -0
- package/src/components/MobileMenuFooter.astro +11 -0
- package/src/components/MobileMenuToggle.astro +23 -0
- package/src/components/MobileTableOfContents.astro +26 -0
- package/src/components/PageFrame.astro +50 -0
- package/src/components/Pagination.astro +34 -0
- package/src/components/PaginationLink.astro +30 -0
- package/src/components/Search.astro +645 -0
- package/src/components/SiteTitle.astro +47 -0
- package/src/components/SiteTitleVersioned.astro +62 -0
- package/src/components/SocialIcons.astro +31 -0
- package/src/components/ThemeProvider.astro +102 -0
- package/src/components/ThemeSelect.astro +188 -0
- package/src/components/TwoColumnContent.astro +44 -0
- package/src/components/VersionSelect.astro +261 -0
- package/src/components/get-i18n-text.ts +39 -0
- package/src/components/index.ts +7 -0
- package/src/components/mobile-menu-toggle.ts +49 -0
- package/src/components/rehype-code-tabs.ts +52 -0
- package/src/constants.ts +7 -0
- package/src/content.config.ts +16 -0
- package/src/content.d.ts +22 -0
- package/src/icons/lucide-arrow-left.svg +1 -0
- package/src/icons/lucide-arrow-right.svg +1 -0
- package/src/icons/lucide-check.svg +1 -0
- package/src/icons/lucide-chevron-left.svg +1 -0
- package/src/icons/lucide-chevron-right.svg +1 -0
- package/src/icons/lucide-clipboard.svg +1 -0
- package/src/icons/lucide-menu.svg +1 -0
- package/src/icons/lucide-search.svg +1 -0
- package/src/icons/lucide-x.svg +1 -0
- package/src/icons/tabler-moon-filled.svg +1 -0
- package/src/icons/tabler-sun-high-filled.svg +1 -0
- package/src/index.ts +112 -0
- package/src/shiki-config.ts +49 -0
- package/src/shiki-meta-title.ts +6 -0
- package/src/shiki-transformer-container.ts +85 -0
- package/src/types.d.ts +2 -0
- package/src/user-options.ts +37 -0
- package/src/virtual-internal.d.ts +44 -0
- 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,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,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>
|