@jaamd/jaad 0.0.0-stage → 0.11.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 (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +52 -2
  3. package/dist/jaad.css +1446 -0
  4. package/index.ts +45 -0
  5. package/package.json +70 -3
  6. package/site.ts +19 -0
  7. package/src/@types/docs.ts +47 -0
  8. package/src/advanced.ts +21 -0
  9. package/src/collection.ts +97 -0
  10. package/src/components/Footer.astro +18 -0
  11. package/src/components/Head.astro +119 -0
  12. package/src/components/Header.astro +47 -0
  13. package/src/components/LocaleSwitcher.astro +111 -0
  14. package/src/components/Nav.astro +22 -0
  15. package/src/components/NavMobile.astro +105 -0
  16. package/src/components/ScrollToTop.astro +43 -0
  17. package/src/components/SearchPalette.astro +328 -0
  18. package/src/components/SocialLinks.astro +27 -0
  19. package/src/components/ThemeSwitcher.astro +55 -0
  20. package/src/components/docs/Breadcrumbs.astro +36 -0
  21. package/src/components/docs/DocsMobileNav.astro +93 -0
  22. package/src/components/docs/DocsPage.astro +68 -0
  23. package/src/components/docs/DocsPageNav.astro +53 -0
  24. package/src/components/docs/DocsSidebarLeft.astro +82 -0
  25. package/src/components/docs/PageActions.astro +81 -0
  26. package/src/components/docs/StructuredData.astro +55 -0
  27. package/src/components/docs/TableOfContents.astro +73 -0
  28. package/src/components/locale-switcher.ts +6 -0
  29. package/src/config.ts +236 -0
  30. package/src/content.ts +42 -0
  31. package/src/docs-config.ts +30 -0
  32. package/src/env.d.ts +13 -0
  33. package/src/fonts/OFL.txt +94 -0
  34. package/src/fonts/inter.woff2 +0 -0
  35. package/src/fonts/merriweather-italic.woff2 +0 -0
  36. package/src/fonts/merriweather.woff2 +0 -0
  37. package/src/fonts.ts +29 -0
  38. package/src/forges.ts +60 -0
  39. package/src/infer.ts +75 -0
  40. package/src/integration.ts +270 -0
  41. package/src/layouts/DefaultDocsFrame.astro +31 -0
  42. package/src/layouts/Docs.astro +168 -0
  43. package/src/layouts/Page.astro +38 -0
  44. package/src/locale-tree.ts +51 -0
  45. package/src/locales.ts +191 -0
  46. package/src/navigation.ts +97 -0
  47. package/src/routes/404.astro +16 -0
  48. package/src/routes/docs-index.astro +19 -0
  49. package/src/routes/docs-slug.astro +58 -0
  50. package/src/routes/docs-slug.md.ts +37 -0
  51. package/src/routes/llms-locale.txt.ts +8 -0
  52. package/src/routes/llms.txt.ts +4 -0
  53. package/src/routes/search-index-locale.json.ts +8 -0
  54. package/src/routes/search-index.json.ts +4 -0
  55. package/src/social.ts +44 -0
  56. package/src/styles/components/breadcrumbs.css +13 -0
  57. package/src/styles/components/docs-mobile-nav.css +9 -0
  58. package/src/styles/components/docs-page-nav.css +31 -0
  59. package/src/styles/components/docs-page.css +9 -0
  60. package/src/styles/components/docs-sidebar.css +42 -0
  61. package/src/styles/components/footer.css +8 -0
  62. package/src/styles/components/header.css +20 -0
  63. package/src/styles/components/locale-switcher.css +20 -0
  64. package/src/styles/components/nav-mobile.css +15 -0
  65. package/src/styles/components/nav.css +11 -0
  66. package/src/styles/components/not-found.css +11 -0
  67. package/src/styles/components/page-actions.css +13 -0
  68. package/src/styles/components/scroll-to-top.css +11 -0
  69. package/src/styles/components/search.css +98 -0
  70. package/src/styles/components/shell.css +73 -0
  71. package/src/styles/components/social-links.css +8 -0
  72. package/src/styles/components/theme-switcher.css +14 -0
  73. package/src/styles/components/toc.css +21 -0
  74. package/src/styles/docs.css +112 -0
  75. package/src/styles/global.css +162 -0
  76. package/src/styles/jaamd-forward.css +16 -0
  77. package/src/styles/jaamd-reverse.css +18 -0
  78. package/src/styles/jaamd.css +11 -0
  79. package/src/styles/tailwind.css +30 -0
  80. package/src/themes/index.ts +26 -0
  81. package/src/ui/en.ts +29 -0
  82. package/src/ui/it.ts +30 -0
  83. package/src/ui.ts +49 -0
  84. package/src/urls.ts +49 -0
  85. package/src/utils/docs.ts +300 -0
  86. package/src/utils/endpoints.ts +80 -0
  87. package/src/utils/helpers.ts +4 -0
  88. package/src/utils/search.ts +83 -0
  89. package/src/virtual.ts +48 -0
@@ -0,0 +1,162 @@
1
+ @import 'tailwindcss' source(none);
2
+ @import './components/shell.css';
3
+ @import './components/header.css';
4
+ @import './components/footer.css';
5
+ @import './components/nav.css';
6
+ @import './components/nav-mobile.css';
7
+ @import './components/social-links.css';
8
+ @import './components/theme-switcher.css';
9
+ @import './components/locale-switcher.css';
10
+ @import './components/scroll-to-top.css';
11
+ @import './components/not-found.css';
12
+ @import './components/search.css';
13
+ @import './components/docs-page.css';
14
+ @import './components/docs-sidebar.css';
15
+ @import './components/toc.css';
16
+ @import './components/docs-mobile-nav.css';
17
+ @import './components/docs-page-nav.css';
18
+ @import './components/page-actions.css';
19
+ @import './components/breadcrumbs.css';
20
+
21
+ @theme static {
22
+ /* Seeds */
23
+
24
+ --color-background: #faf8f5;
25
+ --color-surface: #ffffff;
26
+ --color-foreground: #3a3a3a;
27
+ --color-foreground-bright: #1a1a1a;
28
+ --color-primary: #2d2d2d;
29
+
30
+ --color-error: #c45959;
31
+ --color-warning: #d4a259;
32
+ --color-info: #5988c4;
33
+ --color-success: #5a9c7e;
34
+
35
+ /* Derived */
36
+
37
+ --color-background-secondary: color-mix(in oklab, var(--color-foreground) 2%, var(--color-background));
38
+ --color-background-tertiary: color-mix(in oklab, var(--color-foreground) 6%, var(--color-background));
39
+ --color-surface-hover: color-mix(in oklab, var(--color-foreground) 5%, var(--color-background));
40
+
41
+ --color-border-light: color-mix(in oklab, var(--color-foreground) 11%, var(--color-background));
42
+ --color-border: color-mix(in oklab, var(--color-foreground) 17%, var(--color-background));
43
+ --color-border-dark: color-mix(in oklab, var(--color-foreground) 25%, var(--color-background));
44
+
45
+ --color-foreground-muted: color-mix(in oklab, var(--color-foreground) 55%, var(--color-background));
46
+ --color-foreground-secondary: color-mix(in oklab, var(--color-foreground) 72%, var(--color-background));
47
+
48
+ --color-primary-dark: var(--color-foreground-bright);
49
+ --color-primary-light: color-mix(in oklab, var(--color-primary) 83%, var(--color-background));
50
+
51
+ /* Fonts */
52
+ --font-sans: var(--font-inter), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
53
+ --font-serif: var(--font-merriweather), Georgia, serif;
54
+ --font-mono: 'SF Mono', SF Mono, Consolas, 'Liberation Mono', Menlo, Courier, monospace;
55
+
56
+ /* Layout */
57
+ --jaad-content-width: 56rem;
58
+ --jaad-chrome-width: var(--jaad-content-width);
59
+ --jaad-sidebar-width: 16rem;
60
+ --jaad-page-padding: 2rem;
61
+
62
+ /* Where a sidebar sits beside centred content. Derived, so moving the
63
+ content width moves the sidebars with it. */
64
+ --jaad-sidebar-offset: calc(50% - (var(--jaad-content-width) / 2) - var(--jaad-sidebar-width) - 2rem);
65
+ }
66
+
67
+ @layer base {
68
+ html {
69
+ scroll-padding-top: 8rem;
70
+ background-color: var(--color-background);
71
+ color: var(--color-foreground);
72
+ font-family: var(--font-sans);
73
+ font-size: 16px;
74
+ scroll-behavior: smooth;
75
+ scrollbar-gutter: stable;
76
+ }
77
+
78
+ h1,
79
+ h2,
80
+ h3 {
81
+ color: var(--color-foreground-bright);
82
+ font-family: var(--font-serif);
83
+ }
84
+
85
+ h2 {
86
+ margin-bottom: 1.5rem;
87
+ font-size: 1.5rem;
88
+ font-weight: 600;
89
+ }
90
+
91
+ h3 {
92
+ margin-bottom: 1rem;
93
+ font-size: 1.2rem;
94
+ font-weight: normal;
95
+ }
96
+
97
+ a {
98
+ @apply text-primary hover:text-primary-dark underline decoration-1 underline-offset-2 transition duration-200 ease-in-out;
99
+ }
100
+
101
+ i {
102
+ @apply text-primary italic;
103
+ }
104
+ }
105
+
106
+ /* Utilities layer: wins over .jaad-brand's line-height. */
107
+ @layer utilities {
108
+ .font-brand {
109
+ font-family: var(--font-serif);
110
+ font-weight: 300;
111
+ font-style: italic;
112
+ letter-spacing: -0.01em;
113
+ line-height: 1;
114
+ }
115
+ }
116
+
117
+ /* Dark mode */
118
+
119
+ html.dark {
120
+ color-scheme: dark;
121
+
122
+ --color-background: #0d1117;
123
+ --color-surface: #21262d;
124
+ --color-foreground: #c9d1d9;
125
+ --color-foreground-bright: #e6edf3;
126
+ --color-primary: #c9d1d9;
127
+
128
+ --color-error: #f85149;
129
+ --color-warning: #d29922;
130
+ --color-info: #58a6ff;
131
+ --color-success: #3fb950;
132
+
133
+ --color-background-secondary: color-mix(in oklab, var(--color-foreground) 7%, var(--color-background));
134
+ --color-background-tertiary: color-mix(in oklab, var(--color-foreground) 10%, var(--color-background));
135
+ --color-surface-hover: color-mix(in oklab, var(--color-foreground) 22%, var(--color-background));
136
+
137
+ --color-border-light: color-mix(in oklab, var(--color-foreground) 13%, var(--color-background));
138
+ --color-border: color-mix(in oklab, var(--color-foreground) 22%, var(--color-background));
139
+ --color-border-dark: color-mix(in oklab, var(--color-foreground) 36%, var(--color-background));
140
+
141
+ --color-foreground-muted: color-mix(in oklab, var(--color-foreground) 57%, var(--color-background));
142
+ --color-foreground-secondary: color-mix(in oklab, var(--color-foreground) 71%, var(--color-background));
143
+
144
+ --color-primary-light: color-mix(in oklab, var(--color-primary) 71%, var(--color-background));
145
+ }
146
+
147
+ /* Reduced motion */
148
+
149
+ @media (prefers-reduced-motion: reduce) {
150
+ html {
151
+ scroll-behavior: auto;
152
+ }
153
+
154
+ *,
155
+ *::before,
156
+ *::after {
157
+ animation-duration: 0.01ms !important;
158
+ animation-iteration-count: 1 !important;
159
+ transition-duration: 0.01ms !important;
160
+ scroll-behavior: auto !important;
161
+ }
162
+ }
@@ -0,0 +1,16 @@
1
+ /* JAAD's palette drives JAAMD's. Used when the colours come from JAAD — its own
2
+ identity, or a custom theme written in src/jaad.css. */
3
+
4
+ :root {
5
+ --jaamd-bg: var(--color-background);
6
+ --jaamd-color-fg: var(--color-foreground);
7
+ --jaamd-color-fg-bright: var(--color-foreground-bright);
8
+ --jaamd-color-primary: var(--color-primary);
9
+ --jaamd-color-success: var(--color-success);
10
+
11
+ --jaamd-alert-note-color: var(--color-info);
12
+ --jaamd-alert-tip-color: var(--color-success);
13
+ --jaamd-alert-important-color: var(--color-primary);
14
+ --jaamd-alert-warning-color: var(--color-warning);
15
+ --jaamd-alert-caution-color: var(--color-error);
16
+ }
@@ -0,0 +1,18 @@
1
+ /* JAAMD's palette drives JAAD's, the opposite direction to jaamd-forward.css.
2
+ Never both at once: together they are a cycle, and CSS drops both sides.
3
+
4
+ Only the seeds; global.css derives the rest with color-mix(). */
5
+
6
+ :root,
7
+ html.dark {
8
+ --color-background: var(--jaamd-bg);
9
+ --color-surface: var(--jaamd-surface-1);
10
+ --color-foreground: var(--jaamd-color-fg);
11
+ --color-foreground-bright: var(--jaamd-color-fg-bright);
12
+ --color-primary: var(--jaamd-color-primary);
13
+
14
+ --color-info: var(--jaamd-alert-note-color);
15
+ --color-success: var(--jaamd-alert-tip-color);
16
+ --color-warning: var(--jaamd-alert-warning-color);
17
+ --color-error: var(--jaamd-alert-caution-color);
18
+ }
@@ -0,0 +1,11 @@
1
+ /* Bridge to JAAMD. */
2
+
3
+ :root {
4
+ --jaamd-font-sans: var(--font-sans);
5
+ --jaamd-font-serif: var(--font-serif);
6
+ --jaamd-font-mono: var(--font-mono);
7
+ --jaamd-font-size: 1.125rem;
8
+ --jaamd-line-height: 1.6;
9
+
10
+ --jaamd-scroll-margin-top: 0;
11
+ }
@@ -0,0 +1,30 @@
1
+ /* Opt-in (`tailwind: true`): site utilities read JAAD's tokens. No values, no preflight. */
2
+ @import 'tailwindcss/theme.css' layer(theme) theme(reference);
3
+ @import 'tailwindcss/utilities.css' layer(utilities);
4
+
5
+ @custom-variant dark (&:where(.dark, .dark *));
6
+
7
+ @theme reference {
8
+ --color-background: transparent;
9
+ --color-surface: transparent;
10
+ --color-foreground: transparent;
11
+ --color-foreground-bright: transparent;
12
+ --color-primary: transparent;
13
+ --color-error: transparent;
14
+ --color-warning: transparent;
15
+ --color-info: transparent;
16
+ --color-success: transparent;
17
+ --color-background-secondary: transparent;
18
+ --color-background-tertiary: transparent;
19
+ --color-surface-hover: transparent;
20
+ --color-border-light: transparent;
21
+ --color-border: transparent;
22
+ --color-border-dark: transparent;
23
+ --color-foreground-muted: transparent;
24
+ --color-foreground-secondary: transparent;
25
+ --color-primary-dark: transparent;
26
+ --color-primary-light: transparent;
27
+ --font-sans: transparent;
28
+ --font-serif: transparent;
29
+ --font-mono: transparent;
30
+ }
@@ -0,0 +1,26 @@
1
+ import { themes } from '@jaamd/jaamd/themes'
2
+
3
+ export interface Preset {
4
+ /** Shiki theme, or a light/dark pair, for code blocks. */
5
+ shiki: string | { light: string; dark: string }
6
+ /** JAAMD theme slug, or null when JAAD's own identity already applies. */
7
+ theme: string | null
8
+ /** `dual` carries a light and a dark palette; the others apply in both modes. */
9
+ mode: 'light' | 'dark' | 'dual'
10
+ }
11
+
12
+ /** JAAMD's palettes, plus `default`: JAAD's own, which needs no stylesheet. */
13
+ export const PRESETS: Record<string, Preset> = {
14
+ default: {
15
+ shiki: { light: 'github-light', dark: 'github-dark' },
16
+ theme: null,
17
+ mode: 'dual',
18
+ },
19
+ ...Object.fromEntries(
20
+ themes.map((theme) => [theme.slug, { shiki: theme.shiki, theme: theme.slug, mode: theme.mode }]),
21
+ ),
22
+ }
23
+
24
+ export const PRESET_NAMES = Object.keys(PRESETS)
25
+
26
+ export const isPreset = (value: string): boolean => value in PRESETS
package/src/ui/en.ts ADDED
@@ -0,0 +1,29 @@
1
+ /** The canonical UI catalogue: its keys define every catalogue JAAD accepts. */
2
+ export const ENGLISH_UI = {
3
+ 'breadcrumb.label': 'Breadcrumb',
4
+ 'breadcrumb.root': 'Docs',
5
+ home: 'Home',
6
+ 'locale.change': 'Change language',
7
+ 'nav.documentation': 'Documentation navigation',
8
+ 'nav.jumpToSection': 'Jump to section...',
9
+ 'nav.mobile': 'Toggle mobile menu',
10
+ 'nav.page': 'Page navigation',
11
+ 'nav.selectPage': 'Select page',
12
+ 'page.copied': 'Copied!',
13
+ 'page.copy': 'Copy page',
14
+ 'page.edit': 'Edit this page',
15
+ 'page.lastUpdated': 'Last updated on',
16
+ scrollTop: 'Scroll to top',
17
+ 'search.close': 'close',
18
+ 'search.empty': 'No results for',
19
+ 'search.label': 'Search documentation',
20
+ 'search.loading': 'Loading...',
21
+ 'search.navigate': 'navigate',
22
+ 'search.open': 'open',
23
+ 'search.placeholder': 'Search documentation...',
24
+ 'search.results': 'Search results',
25
+ 'search.trigger': 'Search docs...',
26
+ 'theme.toggle': 'Toggle color theme',
27
+ 'toc.label': 'Table of contents',
28
+ 'toc.title': 'On This Page',
29
+ } as const
package/src/ui/it.ts ADDED
@@ -0,0 +1,30 @@
1
+ import type { UiCatalog } from '../ui.ts'
2
+
3
+ export const ITALIAN_UI = {
4
+ 'breadcrumb.label': 'Percorso di navigazione',
5
+ 'breadcrumb.root': 'Documentazione',
6
+ home: 'Pagina iniziale',
7
+ 'locale.change': 'Cambia lingua',
8
+ 'nav.documentation': 'Navigazione della documentazione',
9
+ 'nav.jumpToSection': 'Vai alla sezione…',
10
+ 'nav.mobile': 'Apri o chiudi il menu',
11
+ 'nav.page': 'Navigazione tra le pagine',
12
+ 'nav.selectPage': 'Seleziona una pagina',
13
+ 'page.copied': 'Copiata!',
14
+ 'page.copy': 'Copia',
15
+ 'page.edit': 'Modifica',
16
+ 'page.lastUpdated': 'Ultimo aggiornamento il',
17
+ scrollTop: 'Torna in cima',
18
+ 'search.close': 'chiudi',
19
+ 'search.empty': 'Nessun risultato per',
20
+ 'search.label': 'Cerca nella documentazione',
21
+ 'search.loading': 'Caricamento…',
22
+ 'search.navigate': 'naviga',
23
+ 'search.open': 'apri',
24
+ 'search.placeholder': 'Cerca nella documentazione…',
25
+ 'search.results': 'Risultati della ricerca',
26
+ 'search.trigger': 'Cerca…',
27
+ 'theme.toggle': 'Cambia modalità',
28
+ 'toc.label': 'Indice dei contenuti',
29
+ 'toc.title': 'In questa pagina',
30
+ } satisfies UiCatalog
package/src/ui.ts ADDED
@@ -0,0 +1,49 @@
1
+ import { ENGLISH_UI } from './ui/en.ts'
2
+ import { ITALIAN_UI } from './ui/it.ts'
3
+
4
+ /** Every string JAAD puts on a page itself. */
5
+ export const UI_DEFAULTS = ENGLISH_UI
6
+
7
+ export type UiKey = keyof typeof UI_DEFAULTS
8
+ export type UiCatalog = Record<UiKey, string>
9
+
10
+ export type UiOverrides = Record<string, Partial<Record<string, string>>>
11
+
12
+ const UI_CATALOGS = {
13
+ en: ENGLISH_UI,
14
+ it: ITALIAN_UI,
15
+ } satisfies Record<string, UiCatalog>
16
+
17
+ function localeCandidates(locale: string): string[] {
18
+ const exact = locale.toLowerCase()
19
+ const base = exact.split('-', 1)[0]
20
+ return exact === base ? [exact] : [exact, base]
21
+ }
22
+
23
+ /** Locale keys in config are BCP-47 and therefore case-insensitive. */
24
+ function localeEntry<T>(entries: Record<string, T>, locale: string) {
25
+ return Object.entries(entries).find(([candidate]) => candidate.toLowerCase() === locale)?.[1]
26
+ }
27
+
28
+ /** User overrides win, from the exact locale to its base language. Bundled
29
+ * catalogues follow the same order; English remains the final fallback. */
30
+ export function uiString(overrides: UiOverrides, locale: string, key: UiKey): string {
31
+ const candidates = localeCandidates(locale)
32
+
33
+ for (const candidate of candidates) {
34
+ const value = localeEntry(overrides, candidate)?.[key]
35
+ if (value !== undefined) return value
36
+ }
37
+
38
+ for (const candidate of candidates) {
39
+ const catalogue = localeEntry<UiCatalog>(UI_CATALOGS, candidate)
40
+ if (catalogue) return catalogue[key]
41
+ }
42
+
43
+ return UI_DEFAULTS[key]
44
+ }
45
+
46
+ export const UI_KEYS = Object.keys(UI_DEFAULTS) as UiKey[]
47
+
48
+ /** Kept internal: consumers customise strings through `ui`. */
49
+ export const UI_SUPPORTED_LOCALES = Object.keys(UI_CATALOGS)
package/src/urls.ts ADDED
@@ -0,0 +1,49 @@
1
+ import { localeSegment } from './locales.ts'
2
+
3
+ /** Empty at the site root, otherwise one leading slash and no trailing slash. */
4
+ export function normaliseBasePath(value: string): string {
5
+ const trimmed = value.replace(/^\/+/, '').replace(/\/+$/, '')
6
+ return trimmed ? `/${trimmed}` : ''
7
+ }
8
+
9
+ /** Apply Astro's deployment base to an application-local, root-relative href. */
10
+ export function withDeploymentBase(href: string, deploymentBase: string): string {
11
+ if (!href.startsWith('/') || href.startsWith('//')) return href
12
+
13
+ const prefix = normaliseBasePath(deploymentBase)
14
+ if (!prefix) return href
15
+ return href === '/' ? `${prefix}/` : `${prefix}${href}`
16
+ }
17
+
18
+ export interface DocsUrlOptions {
19
+ /** routeBase, normalised here: empty at the application root. */
20
+ docsBase: string
21
+ /** Astro's deployment base. */
22
+ deploymentBase?: string
23
+ /** Locale of the page, when the docs are localised. */
24
+ locale?: string
25
+ /** The one locale that owns the unprefixed urls. */
26
+ defaultLocale?: string
27
+ }
28
+
29
+ /** Public href for a documentation page. Empty slug means the opening page. */
30
+ export function docsPageHref(slug: string, urls: DocsUrlOptions): string {
31
+ return docsHref(slug, urls)
32
+ }
33
+
34
+ /** Raw Markdown keeps the page's named slug, including for the opener. */
35
+ export function docsMarkdownHref(slug: string, urls: DocsUrlOptions): string {
36
+ return docsHref(slug, urls, '.md')
37
+ }
38
+
39
+ function docsHref(
40
+ slug: string,
41
+ { docsBase, deploymentBase = '', locale, defaultLocale }: DocsUrlOptions,
42
+ suffix = '',
43
+ ): string {
44
+ const mount = normaliseBasePath(docsBase)
45
+ const path = [localeSegment(locale, defaultLocale), slug].filter(Boolean).join('/')
46
+ // Without a suffix an empty path is the mount itself; with one it is a file.
47
+ const href = path || suffix ? `${mount}/${path}${suffix}` : mount || '/'
48
+ return withDeploymentBase(href, deploymentBase)
49
+ }