@jaamd/jaad 0.11.0 → 1.0.0-rc.1
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/README.md +8 -2
- package/dist/jaad.css +232 -347
- package/docs/00-overview.md +25 -0
- package/docs/01-getting-started/01-installation.md +216 -0
- package/docs/01-getting-started/02-pages.md +109 -0
- package/docs/01-getting-started/03-deployment.md +100 -0
- package/docs/02-configurations/01-reference.md +215 -0
- package/docs/02-configurations/02-frontmatter.md +105 -0
- package/docs/02-configurations/03-i18n.md +210 -0
- package/docs/02-configurations/04-search.md +58 -0
- package/docs/02-configurations/05-themes.md +104 -0
- package/docs/02-configurations/06-styles.md +156 -0
- package/docs/02-configurations/07-custom-pages.md +119 -0
- package/docs/02-configurations/08-advanced-layout.md +139 -0
- package/docs/03-upgrading.md +208 -0
- package/index.ts +8 -22
- package/package.json +10 -9
- package/site.ts +18 -1
- package/src/config.ts +25 -176
- package/src/{advanced.ts → docs/advanced.ts} +6 -4
- package/src/docs/collection.ts +109 -0
- package/src/docs/components/Breadcrumbs.astro +29 -0
- package/src/docs/components/DocsMobileNav.astro +90 -0
- package/src/docs/components/DocsNavTree.astro +57 -0
- package/src/docs/components/DocsPage.astro +66 -0
- package/src/{components/docs → docs/components}/DocsPageNav.astro +4 -4
- package/src/docs/components/DocsSidebarLeft.astro +53 -0
- package/src/{components/docs → docs/components}/PageActions.astro +10 -8
- package/src/{components/docs → docs/components}/StructuredData.astro +3 -3
- package/src/{components/docs → docs/components}/TableOfContents.astro +20 -22
- package/src/docs/config.ts +167 -0
- package/src/docs/content.ts +36 -0
- package/src/docs/endpoints.ts +89 -0
- package/src/docs/integration.ts +249 -0
- package/src/{layouts → docs/layouts}/DefaultDocsFrame.astro +7 -5
- package/src/{layouts → docs/layouts}/Docs.astro +44 -43
- package/src/docs/layouts/Page.astro +18 -0
- package/src/docs/link-plugins.ts +52 -0
- package/src/docs/links.ts +42 -0
- package/src/{locale-tree.ts → docs/locale-tree.ts} +1 -1
- package/src/docs/model/ids.ts +87 -0
- package/src/docs/model/rendered.ts +185 -0
- package/src/docs/model/tree.ts +124 -0
- package/src/docs/model/validate.ts +75 -0
- package/src/docs/navigation.ts +75 -0
- package/src/{routes → docs/routes}/404.astro +1 -1
- package/src/docs/routes/docs-index.astro +19 -0
- package/src/docs/routes/docs-slug.astro +54 -0
- package/src/{routes → docs/routes}/docs-slug.md.ts +8 -10
- package/src/{routes → docs/routes}/llms-locale.txt.ts +1 -1
- package/src/{routes → docs/routes}/llms.txt.ts +1 -1
- package/src/{routes → docs/routes}/search-index-locale.json.ts +1 -1
- package/src/{routes → docs/routes}/search-index.json.ts +1 -1
- package/src/docs/runtime.ts +17 -0
- package/src/docs/search-index.ts +39 -0
- package/src/docs/styles/components/breadcrumbs.css +26 -0
- package/src/docs/styles/components/docs-mobile-nav.css +47 -0
- package/src/docs/styles/components/docs-page-nav.css +41 -0
- package/src/docs/styles/components/docs-sidebar.css +59 -0
- package/src/docs/styles/components/page-actions.css +51 -0
- package/src/docs/styles/components/toc.css +38 -0
- package/src/docs/styles/components.css +7 -0
- package/src/docs/styles/docs.css +81 -0
- package/src/{@types/docs.ts → docs/types.ts} +8 -16
- package/src/{urls.ts → docs/urls.ts} +2 -16
- package/src/env.d.ts +1 -1
- package/src/integration.ts +15 -249
- package/src/{components → site/components}/Footer.astro +1 -1
- package/src/{components → site/components}/Header.astro +14 -11
- package/src/{components → site/components}/LocaleSwitcher.astro +2 -2
- package/src/{components → site/components}/NavMobile.astro +1 -1
- package/src/{components → site/components}/SearchPalette.astro +160 -79
- package/src/{components → site/components}/ThemeSwitcher.astro +1 -1
- package/src/site/config.ts +149 -0
- package/src/{infer.ts → site/infer.ts} +3 -3
- package/src/site/integration.ts +59 -0
- package/src/{layouts/Page.astro → site/layouts/Shell.astro} +6 -3
- package/src/{locales.ts → site/locales.ts} +9 -1
- package/src/{docs-config.ts → site/runtime.ts} +1 -12
- package/src/site/search.ts +227 -0
- package/src/{social.ts → site/social.ts} +2 -2
- package/src/site/styles/components/header.css +31 -0
- package/src/{styles → site/styles}/components/search.css +21 -1
- package/src/{styles → site/styles}/components/shell.css +4 -0
- package/src/site/styles/components.css +10 -0
- package/src/{styles → site/styles}/global.css +4 -26
- package/src/{themes/index.ts → site/themes.ts} +1 -1
- package/src/{ui → site/ui}/en.ts +3 -5
- package/src/{ui → site/ui}/it.ts +2 -4
- package/src/site/urls.ts +14 -0
- package/src/{virtual.ts → site/virtual.ts} +12 -18
- package/src/styles.css +5 -0
- package/src/collection.ts +0 -97
- package/src/components/ScrollToTop.astro +0 -43
- package/src/components/docs/Breadcrumbs.astro +0 -36
- package/src/components/docs/DocsMobileNav.astro +0 -93
- package/src/components/docs/DocsPage.astro +0 -68
- package/src/components/docs/DocsSidebarLeft.astro +0 -82
- package/src/content.ts +0 -42
- package/src/navigation.ts +0 -97
- package/src/routes/docs-index.astro +0 -19
- package/src/routes/docs-slug.astro +0 -58
- package/src/styles/components/breadcrumbs.css +0 -13
- package/src/styles/components/docs-mobile-nav.css +0 -9
- package/src/styles/components/docs-page-nav.css +0 -31
- package/src/styles/components/docs-sidebar.css +0 -42
- package/src/styles/components/header.css +0 -20
- package/src/styles/components/page-actions.css +0 -13
- package/src/styles/components/scroll-to-top.css +0 -11
- package/src/styles/components/toc.css +0 -21
- package/src/styles/docs.css +0 -112
- package/src/utils/docs.ts +0 -300
- package/src/utils/endpoints.ts +0 -80
- package/src/utils/search.ts +0 -83
- /package/src/{styles → docs/styles}/components/docs-page.css +0 -0
- /package/src/{styles → docs/styles}/jaamd.css +0 -0
- /package/src/{components → site/components}/Head.astro +0 -0
- /package/src/{components → site/components}/Nav.astro +0 -0
- /package/src/{components → site/components}/SocialLinks.astro +0 -0
- /package/src/{components → site/components}/locale-switcher.ts +0 -0
- /package/src/{fonts → site/fonts}/OFL.txt +0 -0
- /package/src/{fonts → site/fonts}/inter.woff2 +0 -0
- /package/src/{fonts → site/fonts}/merriweather-italic.woff2 +0 -0
- /package/src/{fonts → site/fonts}/merriweather.woff2 +0 -0
- /package/src/{fonts.ts → site/fonts.ts} +0 -0
- /package/src/{forges.ts → site/forges.ts} +0 -0
- /package/src/{utils → site}/helpers.ts +0 -0
- /package/src/{styles → site/styles}/components/footer.css +0 -0
- /package/src/{styles → site/styles}/components/locale-switcher.css +0 -0
- /package/src/{styles → site/styles}/components/nav-mobile.css +0 -0
- /package/src/{styles → site/styles}/components/nav.css +0 -0
- /package/src/{styles → site/styles}/components/not-found.css +0 -0
- /package/src/{styles → site/styles}/components/social-links.css +0 -0
- /package/src/{styles → site/styles}/components/theme-switcher.css +0 -0
- /package/src/{styles → site/styles}/jaamd-forward.css +0 -0
- /package/src/{styles → site/styles}/jaamd-reverse.css +0 -0
- /package/src/{styles → site/styles}/tailwind.css +0 -0
- /package/src/{ui.ts → site/ui.ts} +0 -0
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { ui } from '../docs-config.ts'
|
|
3
|
-
|
|
4
|
-
const t = ui(Astro.props.locale)
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
<jaad-scroll-top>
|
|
8
|
-
<button class="jaad-scroll-top-button" aria-label={t('scrollTop')}>
|
|
9
|
-
<svg class="jaad-scroll-top-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
10
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18"></path>
|
|
11
|
-
</svg>
|
|
12
|
-
</button>
|
|
13
|
-
</jaad-scroll-top>
|
|
14
|
-
|
|
15
|
-
<script>
|
|
16
|
-
const SHOW_AFTER = 300
|
|
17
|
-
|
|
18
|
-
class JaadScrollTop extends HTMLElement {
|
|
19
|
-
#button: HTMLButtonElement | null = null
|
|
20
|
-
#onScroll = () => {
|
|
21
|
-
const shown = window.scrollY > SHOW_AFTER
|
|
22
|
-
this.#button?.toggleAttribute('data-visible', shown)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
connectedCallback() {
|
|
26
|
-
this.#button = this.querySelector('button')
|
|
27
|
-
this.#button?.addEventListener('click', () => {
|
|
28
|
-
const reduced = matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
29
|
-
window.scrollTo({ top: 0, behavior: reduced ? 'auto' : 'smooth' })
|
|
30
|
-
})
|
|
31
|
-
window.addEventListener('scroll', this.#onScroll, { passive: true })
|
|
32
|
-
this.#onScroll()
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
disconnectedCallback() {
|
|
36
|
-
window.removeEventListener('scroll', this.#onScroll)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (!customElements.get('jaad-scroll-top')) {
|
|
41
|
-
customElements.define('jaad-scroll-top', JaadScrollTop)
|
|
42
|
-
}
|
|
43
|
-
</script>
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import config from 'virtual:jaad/config'
|
|
3
|
-
import { docsUrls, ui } from '../../docs-config.ts'
|
|
4
|
-
import { docsPageHref } from '../../urls.ts'
|
|
5
|
-
import { formatChapterTitle } from '../../utils/docs.ts'
|
|
6
|
-
|
|
7
|
-
interface Props {
|
|
8
|
-
chapter?: string
|
|
9
|
-
title: string
|
|
10
|
-
locale?: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const { chapter, title, locale } = Astro.props
|
|
14
|
-
const t = ui(locale)
|
|
15
|
-
const chapterTitle = formatChapterTitle(chapter)
|
|
16
|
-
|
|
17
|
-
const rootSegment = config.docsBase.split('/').filter(Boolean).at(-1)
|
|
18
|
-
const rootLabel = formatChapterTitle(rootSegment) ?? t('breadcrumb.root')
|
|
19
|
-
const rootHref = docsPageHref('', docsUrls(locale))
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
<nav aria-label={t('breadcrumb.label')} class="docs-breadcrumbs">
|
|
23
|
-
<a href={rootHref} class="docs-breadcrumbs-link">
|
|
24
|
-
{rootLabel}
|
|
25
|
-
</a>
|
|
26
|
-
{chapterTitle && (
|
|
27
|
-
<>
|
|
28
|
-
<span aria-hidden="true">/</span>
|
|
29
|
-
<span>{chapterTitle}</span>
|
|
30
|
-
</>
|
|
31
|
-
)}
|
|
32
|
-
<span aria-hidden="true">/</span>
|
|
33
|
-
<span class="docs-breadcrumbs-current" aria-current="page">
|
|
34
|
-
{title}
|
|
35
|
-
</span>
|
|
36
|
-
</nav>
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { DocsHeadings } from '../../@types/docs.ts'
|
|
3
|
-
import type { NavSection } from '../../navigation.ts'
|
|
4
|
-
import { ui } from '../../docs-config.ts'
|
|
5
|
-
import { formatChapterTitle } from '../../utils/docs.ts'
|
|
6
|
-
import ScrollToTop from '../ScrollToTop.astro'
|
|
7
|
-
|
|
8
|
-
interface Props {
|
|
9
|
-
locale?: string
|
|
10
|
-
sections: NavSection[]
|
|
11
|
-
headings: DocsHeadings[]
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const { sections, headings, locale } = Astro.props
|
|
15
|
-
const t = ui(locale)
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
<div class="docs-mobile-nav">
|
|
19
|
-
<div class="docs-select">
|
|
20
|
-
<label for="page-select" class="jaad-sr-only">
|
|
21
|
-
{t('nav.selectPage')}
|
|
22
|
-
</label>
|
|
23
|
-
<select id="page-select" class="docs-select-field">
|
|
24
|
-
{sections.map((section) =>
|
|
25
|
-
section.type === 'page' ? (
|
|
26
|
-
<option value={section.item.href} selected={section.item.isActive}>
|
|
27
|
-
{section.item.title}
|
|
28
|
-
</option>
|
|
29
|
-
) : (
|
|
30
|
-
<optgroup label={formatChapterTitle(section.chapter) || section.chapter}>
|
|
31
|
-
{section.items.map((page) => (
|
|
32
|
-
<option value={page.href} selected={page.isActive}>
|
|
33
|
-
{page.title}
|
|
34
|
-
</option>
|
|
35
|
-
))}
|
|
36
|
-
</optgroup>
|
|
37
|
-
),
|
|
38
|
-
)}
|
|
39
|
-
</select>
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
{headings.length > 0 && (
|
|
43
|
-
<div id="section-select-wrapper" class="docs-select">
|
|
44
|
-
<label for="section-select" class="jaad-sr-only">
|
|
45
|
-
Jump to section
|
|
46
|
-
</label>
|
|
47
|
-
<select id="section-select" class="docs-select-field">
|
|
48
|
-
<option value="">{t('nav.jumpToSection')}</option>
|
|
49
|
-
{headings.map((heading) => {
|
|
50
|
-
const prefix = heading.depth === 3 ? '\u00A0\u00A0\u00A0\u00A0' : ''
|
|
51
|
-
return (
|
|
52
|
-
<option value={`#${heading.slug}`}>
|
|
53
|
-
{prefix}
|
|
54
|
-
{heading.text}
|
|
55
|
-
</option>
|
|
56
|
-
)
|
|
57
|
-
})}
|
|
58
|
-
</select>
|
|
59
|
-
</div>
|
|
60
|
-
)}
|
|
61
|
-
</div>
|
|
62
|
-
|
|
63
|
-
<ScrollToTop {locale} />
|
|
64
|
-
|
|
65
|
-
<script>
|
|
66
|
-
import { navigate } from 'astro:transitions/client'
|
|
67
|
-
|
|
68
|
-
function initMobileNav(): void {
|
|
69
|
-
const pageSelect = document.querySelector<HTMLSelectElement>('#page-select')
|
|
70
|
-
const sectionSelect = document.querySelector<HTMLSelectElement>('#section-select')
|
|
71
|
-
|
|
72
|
-
if (pageSelect && !pageSelect.dataset.navInit) {
|
|
73
|
-
pageSelect.dataset.navInit = '1'
|
|
74
|
-
pageSelect.addEventListener('change', () => {
|
|
75
|
-
if (pageSelect.value) navigate(pageSelect.value)
|
|
76
|
-
})
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (sectionSelect && !sectionSelect.dataset.navInit) {
|
|
80
|
-
sectionSelect.dataset.navInit = '1'
|
|
81
|
-
sectionSelect.addEventListener('change', () => {
|
|
82
|
-
const target = sectionSelect.value
|
|
83
|
-
if (!target) return
|
|
84
|
-
document.querySelector(target)?.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
|
85
|
-
// Reset so picking the same section twice in a row fires again.
|
|
86
|
-
setTimeout(() => (sectionSelect.value = ''), 500)
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
initMobileNav()
|
|
92
|
-
document.addEventListener('astro:page-load', initMobileNav)
|
|
93
|
-
</script>
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { DocsEntry } from '../../@types/docs.ts'
|
|
3
|
-
import MarkdownContent from '@jaamd/jaamd/components'
|
|
4
|
-
import config from 'virtual:jaad/config'
|
|
5
|
-
import { DEFAULT_LOCALE, LOCALES, docsUrls, ui } from '../../docs-config.ts'
|
|
6
|
-
import DocsLayout from '../../layouts/Docs.astro'
|
|
7
|
-
import { buildDocsNavigation } from '../../navigation.ts'
|
|
8
|
-
import {
|
|
9
|
-
getCleanSlug,
|
|
10
|
-
parseDocCollectionId,
|
|
11
|
-
docTitle,
|
|
12
|
-
extractHeadingsFromMarkdown,
|
|
13
|
-
routedId,
|
|
14
|
-
} from '../../utils/docs.ts'
|
|
15
|
-
import Breadcrumbs from './Breadcrumbs.astro'
|
|
16
|
-
import DocsMobileNav from './DocsMobileNav.astro'
|
|
17
|
-
import DocsPageNav from './DocsPageNav.astro'
|
|
18
|
-
import PageActions from './PageActions.astro'
|
|
19
|
-
|
|
20
|
-
interface Props {
|
|
21
|
-
entry: DocsEntry
|
|
22
|
-
sortedPages: DocsEntry[]
|
|
23
|
-
/** Left out on the opening page, whose title is the site name alone. */
|
|
24
|
-
headTitle?: string
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const { entry, sortedPages, headTitle } = Astro.props
|
|
28
|
-
|
|
29
|
-
const cleanSlug = getCleanSlug(routedId(entry))
|
|
30
|
-
const { chapter } = parseDocCollectionId(routedId(entry))
|
|
31
|
-
const title = docTitle(entry)
|
|
32
|
-
const headings = extractHeadingsFromMarkdown(entry.body || '')
|
|
33
|
-
const urls = docsUrls(entry.locale)
|
|
34
|
-
const t = ui(entry.locale)
|
|
35
|
-
const language = LOCALES.find((known) => known.code === (entry.locale ?? DEFAULT_LOCALE))?.tag ?? config.lang
|
|
36
|
-
const updated = entry.data.lastUpdated
|
|
37
|
-
const navigation = buildDocsNavigation(sortedPages, entry.id, urls)
|
|
38
|
-
const contentAttrs = { id: 'content' }
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
<DocsLayout title={headTitle} chapter={chapter} entry={entry} headings={headings} {navigation}>
|
|
42
|
-
<DocsMobileNav slot="mobile-navigation" sections={navigation.sections} headings={headings} locale={entry.locale} />
|
|
43
|
-
|
|
44
|
-
<Breadcrumbs slot="breadcrumbs" chapter={chapter} title={title} locale={entry.locale} />
|
|
45
|
-
<PageActions slot="page-actions" id={entry.id} cleanSlug={cleanSlug} locale={entry.locale} />
|
|
46
|
-
|
|
47
|
-
<Fragment slot="content">
|
|
48
|
-
<MarkdownContent {...contentAttrs} class="docs-content">
|
|
49
|
-
<slot />
|
|
50
|
-
</MarkdownContent>
|
|
51
|
-
|
|
52
|
-
{updated && (
|
|
53
|
-
<p class="docs-updated">
|
|
54
|
-
{t('page.lastUpdated')}{' '}
|
|
55
|
-
<time datetime={updated.toISOString()}>
|
|
56
|
-
{new Intl.DateTimeFormat(language, { dateStyle: 'long' }).format(updated)}
|
|
57
|
-
</time>
|
|
58
|
-
</p>
|
|
59
|
-
)}
|
|
60
|
-
</Fragment>
|
|
61
|
-
|
|
62
|
-
<DocsPageNav
|
|
63
|
-
slot="page-navigation"
|
|
64
|
-
previousPage={navigation.previousPage}
|
|
65
|
-
nextPage={navigation.nextPage}
|
|
66
|
-
locale={entry.locale}
|
|
67
|
-
/>
|
|
68
|
-
</DocsLayout>
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { NavSection } from '../../navigation.ts'
|
|
3
|
-
import { ui } from '../../docs-config.ts'
|
|
4
|
-
import { formatChapterTitle } from '../../utils/docs.ts'
|
|
5
|
-
|
|
6
|
-
interface Props {
|
|
7
|
-
sections: NavSection[]
|
|
8
|
-
locale?: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const { sections, locale } = Astro.props
|
|
12
|
-
const t = ui(locale)
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
<aside class="docs-sidebar-left jaad-sidebar">
|
|
16
|
-
<nav aria-label={t('nav.documentation')}>
|
|
17
|
-
{sections.map((section) =>
|
|
18
|
-
section.type === 'page' ? (
|
|
19
|
-
<div class="docs-sidebar-page">
|
|
20
|
-
<a
|
|
21
|
-
href={section.item.href}
|
|
22
|
-
class="docs-sidebar-link"
|
|
23
|
-
aria-current={section.item.isActive ? 'page' : undefined}
|
|
24
|
-
>
|
|
25
|
-
{section.item.title}
|
|
26
|
-
</a>
|
|
27
|
-
</div>
|
|
28
|
-
) : (
|
|
29
|
-
<div class="docs-sidebar-chapter">
|
|
30
|
-
<h3 class="docs-sidebar-chapter-title">{formatChapterTitle(section.chapter)}</h3>
|
|
31
|
-
<ul class="docs-sidebar-chapter-list">
|
|
32
|
-
{section.items.map((item) => (
|
|
33
|
-
<li>
|
|
34
|
-
<a
|
|
35
|
-
href={item.href}
|
|
36
|
-
class="docs-sidebar-sublink"
|
|
37
|
-
aria-current={item.isActive ? 'page' : undefined}
|
|
38
|
-
>
|
|
39
|
-
{item.title}
|
|
40
|
-
</a>
|
|
41
|
-
</li>
|
|
42
|
-
))}
|
|
43
|
-
</ul>
|
|
44
|
-
</div>
|
|
45
|
-
),
|
|
46
|
-
)}
|
|
47
|
-
</nav>
|
|
48
|
-
</aside>
|
|
49
|
-
|
|
50
|
-
<script>
|
|
51
|
-
const SELECTOR = '.docs-sidebar-left'
|
|
52
|
-
let scrollTop = 0
|
|
53
|
-
|
|
54
|
-
const sidebar = () => document.querySelector<HTMLElement>(SELECTOR)
|
|
55
|
-
|
|
56
|
-
/** Scrolls the sidebar only, never the document, and only when needed. */
|
|
57
|
-
function revealCurrent() {
|
|
58
|
-
const el = sidebar()
|
|
59
|
-
const current = el?.querySelector('[aria-current="page"]')
|
|
60
|
-
if (!el || !current) return
|
|
61
|
-
|
|
62
|
-
const box = el.getBoundingClientRect()
|
|
63
|
-
const item = current.getBoundingClientRect()
|
|
64
|
-
if (item.top >= box.top && item.bottom <= box.bottom) return
|
|
65
|
-
|
|
66
|
-
el.scrollTop += item.top - box.top - (box.height - item.height) / 2
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
document.addEventListener('astro:before-swap', () => {
|
|
70
|
-
scrollTop = sidebar()?.scrollTop ?? 0
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
document.addEventListener('astro:after-swap', () => {
|
|
74
|
-
const el = sidebar()
|
|
75
|
-
if (!el) return
|
|
76
|
-
el.scrollTop = scrollTop
|
|
77
|
-
// A deep link, or a page whose entry sits outside the restored window.
|
|
78
|
-
revealCurrent()
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
revealCurrent()
|
|
82
|
-
</script>
|
package/src/content.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { glob } from 'astro/loaders'
|
|
2
|
-
import { z } from 'astro/zod'
|
|
3
|
-
import { defineCollection } from 'astro:content'
|
|
4
|
-
import config from 'virtual:jaad/config'
|
|
5
|
-
import { getDocCollectionId } from './utils/docs.ts'
|
|
6
|
-
|
|
7
|
-
const docsPages = defineCollection({
|
|
8
|
-
loader: glob({
|
|
9
|
-
pattern: '**/*.md',
|
|
10
|
-
base: config.docsDir,
|
|
11
|
-
// Keep URLs file-driven even if markdown contains an unrelated slug field.
|
|
12
|
-
generateId: ({ entry }) => getDocCollectionId(entry),
|
|
13
|
-
}),
|
|
14
|
-
// Every field is optional: markdown without frontmatter works as-is.
|
|
15
|
-
schema: z.object({
|
|
16
|
-
title: z.string().optional(),
|
|
17
|
-
description: z.string().optional(),
|
|
18
|
-
/** Shorter label, in navigation only. */
|
|
19
|
-
label: z.string().optional(),
|
|
20
|
-
/** Pairs this page with its translations when the slugs differ. */
|
|
21
|
-
translationKey: z.string().optional(),
|
|
22
|
-
/** Replaces the filename prefix number. */
|
|
23
|
-
order: z.number().int().optional(),
|
|
24
|
-
/** Left out of production builds. */
|
|
25
|
-
draft: z.boolean().default(false),
|
|
26
|
-
/** Metadata and search weight; never rendered. */
|
|
27
|
-
keywords: z.array(z.string()).default([]),
|
|
28
|
-
author: z.string().optional(),
|
|
29
|
-
/** Public path or URL; false drops the site's. */
|
|
30
|
-
ogImage: z
|
|
31
|
-
.union([
|
|
32
|
-
z.string().refine((v) => v.startsWith('/') || /^https?:\/\//.test(v), {
|
|
33
|
-
message: 'ogImage must be a public url, such as "/og/page.png"',
|
|
34
|
-
}),
|
|
35
|
-
z.literal(false),
|
|
36
|
-
])
|
|
37
|
-
.optional(),
|
|
38
|
-
lastUpdated: z.coerce.date().optional(),
|
|
39
|
-
}),
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
export const collections = { docsPages }
|
package/src/navigation.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import type { DocsNavItem } from './@types/docs.ts'
|
|
2
|
-
import { docsPageHref, type DocsUrlOptions } from './urls.ts'
|
|
3
|
-
import { docLabel, getCanonicalDocSlug, parseDocCollectionId, routedId, type DocsPageLike } from './utils/docs.ts'
|
|
4
|
-
|
|
5
|
-
export type NavSection =
|
|
6
|
-
| { type: 'page'; order: number; item: DocsNavItem }
|
|
7
|
-
| { type: 'chapter'; order: number; chapter: string; items: DocsNavItem[] }
|
|
8
|
-
|
|
9
|
-
export interface DocsNavigation {
|
|
10
|
-
sections: NavSection[]
|
|
11
|
-
previousPage: DocsNavItem | null
|
|
12
|
-
nextPage: DocsNavItem | null
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function groupByChapter(items: DocsNavItem[]): NavSection[] {
|
|
16
|
-
const chapters = new Map<string, Extract<NavSection, { type: 'chapter' }>>()
|
|
17
|
-
const sections: NavSection[] = []
|
|
18
|
-
|
|
19
|
-
for (const item of items) {
|
|
20
|
-
if (!item.chapter) {
|
|
21
|
-
sections.push({ type: 'page', order: item.primaryOrder, item })
|
|
22
|
-
continue
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
let chapter = chapters.get(item.chapter)
|
|
26
|
-
if (!chapter) {
|
|
27
|
-
chapter = {
|
|
28
|
-
type: 'chapter',
|
|
29
|
-
order: item.primaryOrder,
|
|
30
|
-
chapter: item.chapter,
|
|
31
|
-
items: [],
|
|
32
|
-
}
|
|
33
|
-
chapters.set(item.chapter, chapter)
|
|
34
|
-
sections.push(chapter)
|
|
35
|
-
}
|
|
36
|
-
chapter.items.push(item)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return sections.toSorted((a, b) => a.order - b.order)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Build every navigation view from one ordered collection traversal. */
|
|
43
|
-
interface Model {
|
|
44
|
-
items: DocsNavItem[]
|
|
45
|
-
positions: Map<string, number>
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Only isActive and the neighbours vary between the pages of one locale. The
|
|
49
|
-
// hrefs do not, as long as the url options are the same ones.
|
|
50
|
-
const models = new WeakMap<object, Map<string, Model>>()
|
|
51
|
-
|
|
52
|
-
function modelFor(sortedPages: DocsPageLike[], urls: DocsUrlOptions): Model {
|
|
53
|
-
const key = `${urls.docsBase}\u0000${urls.deploymentBase ?? ''}\u0000${urls.locale ?? ''}\u0000${urls.defaultLocale ?? ''}`
|
|
54
|
-
let byUrls = models.get(sortedPages)
|
|
55
|
-
if (!byUrls) {
|
|
56
|
-
byUrls = new Map()
|
|
57
|
-
models.set(sortedPages, byUrls)
|
|
58
|
-
}
|
|
59
|
-
const cached = byUrls.get(key)
|
|
60
|
-
if (cached) return cached
|
|
61
|
-
|
|
62
|
-
const model: Model = {
|
|
63
|
-
items: sortedPages.map((page, index): DocsNavItem => {
|
|
64
|
-
const parsed = parseDocCollectionId(routedId(page))
|
|
65
|
-
return {
|
|
66
|
-
title: docLabel(page),
|
|
67
|
-
chapter: parsed.chapter,
|
|
68
|
-
primaryOrder: parsed.orderChapter ?? page.data?.order ?? parsed.order,
|
|
69
|
-
href: docsPageHref(getCanonicalDocSlug(page, index), urls),
|
|
70
|
-
isActive: false,
|
|
71
|
-
}
|
|
72
|
-
}),
|
|
73
|
-
positions: new Map(sortedPages.map((page, index) => [page.id, index])),
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
byUrls.set(key, model)
|
|
77
|
-
return model
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function buildDocsNavigation(
|
|
81
|
-
sortedPages: DocsPageLike[],
|
|
82
|
-
currentId: string,
|
|
83
|
-
urls: DocsUrlOptions,
|
|
84
|
-
): DocsNavigation {
|
|
85
|
-
const { items, positions } = modelFor(sortedPages, urls)
|
|
86
|
-
const currentIndex = positions.get(currentId) ?? -1
|
|
87
|
-
const marked = items.map((item, index) => ({
|
|
88
|
-
...item,
|
|
89
|
-
isActive: index === currentIndex,
|
|
90
|
-
}))
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
sections: groupByChapter(marked),
|
|
94
|
-
previousPage: currentIndex > 0 ? marked[currentIndex - 1] : null,
|
|
95
|
-
nextPage: currentIndex >= 0 && currentIndex < marked.length - 1 ? marked[currentIndex + 1] : null,
|
|
96
|
-
}
|
|
97
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { render } from 'astro:content'
|
|
3
|
-
import { getSortedDocsPages } from '../collection.ts'
|
|
4
|
-
import DocsPage from '../components/docs/DocsPage.astro'
|
|
5
|
-
import { withDeploymentBase } from '../urls.ts'
|
|
6
|
-
|
|
7
|
-
const sortedPages = await getSortedDocsPages()
|
|
8
|
-
|
|
9
|
-
const firstPage = sortedPages[0]
|
|
10
|
-
if (!firstPage) {
|
|
11
|
-
return Astro.redirect(withDeploymentBase('/404', import.meta.env.BASE_URL))
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const { Content } = await render(firstPage)
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
<DocsPage entry={firstPage} {sortedPages}>
|
|
18
|
-
<Content />
|
|
19
|
-
</DocsPage>
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { render } from 'astro:content'
|
|
3
|
-
import { getSortedDocsPages } from '../collection.ts'
|
|
4
|
-
import DocsPage from '../components/docs/DocsPage.astro'
|
|
5
|
-
import { buildLocales, docsUrls, localePrefix } from '../docs-config.ts'
|
|
6
|
-
import { docsPageHref, withDeploymentBase } from '../urls.ts'
|
|
7
|
-
import { getCanonicalDocSlug, getCleanSlug, docTitle, routedId } from '../utils/docs.ts'
|
|
8
|
-
|
|
9
|
-
interface DocsPath {
|
|
10
|
-
params: { slug: string }
|
|
11
|
-
props: { id: string; locale?: string; isOpening: boolean }
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export async function getStaticPaths() {
|
|
15
|
-
const paths: DocsPath[] = []
|
|
16
|
-
|
|
17
|
-
for (const locale of buildLocales()) {
|
|
18
|
-
const sortedPages = await getSortedDocsPages(locale)
|
|
19
|
-
const prefix = localePrefix(locale)
|
|
20
|
-
|
|
21
|
-
sortedPages.forEach((page, index) => {
|
|
22
|
-
const isOpening = getCanonicalDocSlug(page, index) === ''
|
|
23
|
-
paths.push({
|
|
24
|
-
params: { slug: `${prefix}${getCleanSlug(routedId(page))}` },
|
|
25
|
-
props: { id: page.id, locale, isOpening },
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
// A prefixed locale has no index route of its own: /it is this page.
|
|
29
|
-
if (isOpening && prefix) {
|
|
30
|
-
paths.push({
|
|
31
|
-
params: { slug: locale! },
|
|
32
|
-
props: { id: page.id, locale, isOpening: false },
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return paths
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const { id, locale, isOpening } = Astro.props
|
|
42
|
-
|
|
43
|
-
if (isOpening) {
|
|
44
|
-
return Astro.redirect(docsPageHref('', docsUrls(locale)), 301)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const sortedPages = await getSortedDocsPages(locale)
|
|
48
|
-
const docPage = sortedPages.find((page) => page.id === id)
|
|
49
|
-
if (!docPage) {
|
|
50
|
-
return Astro.redirect(withDeploymentBase('/404', import.meta.env.BASE_URL))
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const { Content } = await render(docPage)
|
|
54
|
-
---
|
|
55
|
-
|
|
56
|
-
<DocsPage entry={docPage} {sortedPages} headTitle={docTitle(docPage)}>
|
|
57
|
-
<Content />
|
|
58
|
-
</DocsPage>
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
@layer components {
|
|
2
|
-
.docs-breadcrumbs {
|
|
3
|
-
@apply text-foreground-muted mb-4 flex items-center gap-1.5 text-xs;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
.docs-breadcrumbs-link {
|
|
7
|
-
@apply hover:text-foreground-bright no-underline;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.docs-breadcrumbs-current {
|
|
11
|
-
@apply text-foreground-bright font-medium;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
@layer components {
|
|
2
|
-
.docs-mobile-nav {
|
|
3
|
-
@apply mb-8 space-y-4 lg:hidden;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
.docs-select-field {
|
|
7
|
-
@apply border-primary/20 bg-surface text-foreground focus:border-primary w-full appearance-none rounded-lg border py-3 pr-10 pl-4 transition-colors focus:outline-none;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
@layer components {
|
|
2
|
-
.docs-page-nav {
|
|
3
|
-
@apply py-8;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
.docs-page-nav-row {
|
|
7
|
-
@apply flex items-center justify-between gap-4;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.docs-page-nav-link {
|
|
11
|
-
@apply border-border-dark bg-background-tertiary text-foreground-bright hover:border-primary hover:bg-border-dark hover:text-primary flex max-w-[calc(45%-1rem)] min-w-0 items-center gap-2 rounded-lg border px-4 py-3 no-underline transition-all duration-300;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.docs-page-nav-icon {
|
|
15
|
-
@apply h-4 w-4 shrink-0 transition-transform;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
@media (hover: hover) {
|
|
19
|
-
.docs-page-nav-link:hover .docs-page-nav-icon-prev {
|
|
20
|
-
@apply -translate-x-1;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.docs-page-nav-link:hover .docs-page-nav-icon-next {
|
|
24
|
-
@apply translate-x-1;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.docs-page-nav-label {
|
|
29
|
-
@apply overflow-hidden font-medium text-ellipsis whitespace-nowrap;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
@layer components {
|
|
2
|
-
.docs-sidebar-page {
|
|
3
|
-
@apply mb-0.5;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
.docs-sidebar-page:not(:first-child) {
|
|
7
|
-
@apply mt-0.5;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.docs-sidebar-link,
|
|
11
|
-
.docs-sidebar-sublink {
|
|
12
|
-
@apply text-foreground hover:bg-primary/10 hover:text-primary block px-3 py-1.5 text-sm no-underline transition-colors;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.docs-sidebar-link {
|
|
16
|
-
@apply rounded;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.docs-sidebar-sublink {
|
|
20
|
-
@apply rounded-r;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.docs-sidebar-link[aria-current='page'] {
|
|
24
|
-
@apply bg-primary/10 text-primary font-semibold;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.docs-sidebar-sublink[aria-current='page'] {
|
|
28
|
-
@apply border-primary bg-primary/10 text-primary -ml-px border-l-2 pl-2.75 font-semibold;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.docs-sidebar-chapter {
|
|
32
|
-
@apply mt-5 mb-5;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.docs-sidebar-chapter-title {
|
|
36
|
-
@apply text-primary/50 mb-1 px-3 text-[0.825rem] font-semibold tracking-widest uppercase;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.docs-sidebar-chapter-list {
|
|
40
|
-
@apply border-border/40 ml-3 space-y-0.5 border-l pl-0;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
@layer components {
|
|
2
|
-
.jaad-header-inner {
|
|
3
|
-
@apply container mx-auto p-4;
|
|
4
|
-
}
|
|
5
|
-
.jaad-header-row {
|
|
6
|
-
@apply flex items-center gap-4;
|
|
7
|
-
}
|
|
8
|
-
.jaad-brand {
|
|
9
|
-
@apply text-foreground-bright text-xl;
|
|
10
|
-
}
|
|
11
|
-
.jaad-brand-link {
|
|
12
|
-
@apply text-primary no-underline;
|
|
13
|
-
}
|
|
14
|
-
.jaad-logo {
|
|
15
|
-
@apply h-7;
|
|
16
|
-
}
|
|
17
|
-
.jaad-header-actions {
|
|
18
|
-
@apply ml-auto flex items-center gap-2;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
@layer components {
|
|
2
|
-
.docs-page-actions {
|
|
3
|
-
@apply mb-4 flex items-center gap-2 text-xs;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
.docs-page-action {
|
|
7
|
-
@apply border-border bg-surface hover:bg-surface-hover text-foreground-secondary hover:text-foreground-bright flex cursor-pointer items-center gap-1.5 rounded-lg border px-3 py-1.5 no-underline transition-colors;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.docs-page-action-icon {
|
|
11
|
-
@apply h-3.5 w-3.5 shrink-0;
|
|
12
|
-
}
|
|
13
|
-
}
|