@refrakt-md/lumina 0.5.1 → 0.6.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/index.css +1 -0
- package/manifest.json +12 -0
- package/package.json +5 -5
- package/styles/layouts/docs.css +46 -0
- package/styles/layouts/mobile.css +5 -3
- package/styles/layouts/on-this-page.css +48 -0
- package/styles/runes/symbol.css +9 -11
- package/svelte/components/OnThisPage.svelte +76 -0
- package/svelte/index.ts +24 -7
- package/svelte/layouts/DocsLayout.svelte +17 -3
- package/svelte/manifest.json +3 -20
package/index.css
CHANGED
package/manifest.json
CHANGED
|
@@ -9,5 +9,17 @@
|
|
|
9
9
|
"attribute": "data-theme",
|
|
10
10
|
"values": { "dark": "dark", "light": "light" },
|
|
11
11
|
"systemPreference": true
|
|
12
|
+
},
|
|
13
|
+
"layouts": {
|
|
14
|
+
"default": {
|
|
15
|
+
"regions": ["header", "footer"]
|
|
16
|
+
},
|
|
17
|
+
"docs": {
|
|
18
|
+
"regions": ["header", "nav", "sidebar", "footer"],
|
|
19
|
+
"requiredRegions": ["nav"]
|
|
20
|
+
},
|
|
21
|
+
"blog": {
|
|
22
|
+
"regions": ["header", "sidebar", "footer"]
|
|
23
|
+
}
|
|
12
24
|
}
|
|
13
25
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@refrakt-md/lumina",
|
|
3
3
|
"description": "Lumina theme for refrakt.md — design tokens, CSS, identity transform, and framework adapters",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"build": "tsc"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@refrakt-md/theme-base": "0.
|
|
50
|
-
"@refrakt-md/transform": "0.
|
|
51
|
-
"@refrakt-md/types": "0.
|
|
52
|
-
"@refrakt-md/svelte": "0.
|
|
49
|
+
"@refrakt-md/theme-base": "0.6.0",
|
|
50
|
+
"@refrakt-md/transform": "0.6.0",
|
|
51
|
+
"@refrakt-md/types": "0.6.0",
|
|
52
|
+
"@refrakt-md/svelte": "0.6.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"svelte": "^5.0.0",
|
package/styles/layouts/docs.css
CHANGED
|
@@ -88,6 +88,41 @@
|
|
|
88
88
|
padding: 0 2.5rem;
|
|
89
89
|
--rf-content-padding: 2.5rem;
|
|
90
90
|
}
|
|
91
|
+
.rf-docs-content__inner--has-toc {
|
|
92
|
+
display: flex;
|
|
93
|
+
gap: 0;
|
|
94
|
+
max-width: calc(60rem + 220px);
|
|
95
|
+
}
|
|
96
|
+
.rf-docs-content__inner--has-toc .rf-docs-content__body {
|
|
97
|
+
flex: 1;
|
|
98
|
+
min-width: 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* ---- "On this page" sidebar ---- */
|
|
102
|
+
.rf-docs-toc {
|
|
103
|
+
width: 220px;
|
|
104
|
+
flex-shrink: 0;
|
|
105
|
+
position: sticky;
|
|
106
|
+
top: 5.75rem;
|
|
107
|
+
align-self: flex-start;
|
|
108
|
+
max-height: calc(100vh - 5.75rem);
|
|
109
|
+
overflow-y: auto;
|
|
110
|
+
padding: 0 1.25rem;
|
|
111
|
+
}
|
|
112
|
+
.rf-docs-toc::-webkit-scrollbar {
|
|
113
|
+
width: 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* ---- Smooth scroll with fixed-header offset ---- */
|
|
117
|
+
html:has(.rf-docs-header) {
|
|
118
|
+
scroll-behavior: smooth;
|
|
119
|
+
scroll-padding-top: 5rem;
|
|
120
|
+
}
|
|
121
|
+
@media (prefers-reduced-motion: reduce) {
|
|
122
|
+
html:has(.rf-docs-header) {
|
|
123
|
+
scroll-behavior: auto;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
91
126
|
|
|
92
127
|
/* ---- Mobile toolbar (hidden on desktop) ---- */
|
|
93
128
|
.rf-docs-toolbar {
|
|
@@ -130,6 +165,17 @@
|
|
|
130
165
|
font-weight: 500;
|
|
131
166
|
}
|
|
132
167
|
|
|
168
|
+
/* ---- Hide TOC on medium screens ---- */
|
|
169
|
+
@media (max-width: 1100px) {
|
|
170
|
+
.rf-docs-toc {
|
|
171
|
+
display: none;
|
|
172
|
+
}
|
|
173
|
+
.rf-docs-content__inner--has-toc {
|
|
174
|
+
display: block;
|
|
175
|
+
max-width: 60rem;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
133
179
|
/* ---- Mobile overrides ---- */
|
|
134
180
|
@media (max-width: 768px) {
|
|
135
181
|
.rf-docs-header {
|
|
@@ -74,11 +74,13 @@
|
|
|
74
74
|
padding: 1rem 1.5rem;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/* Panel opens via data-open attribute (set by mobile-menu behavior) */
|
|
78
|
+
.rf-mobile-panel[data-open] {
|
|
79
|
+
display: block;
|
|
80
|
+
}
|
|
81
|
+
|
|
77
82
|
@media (max-width: 768px) {
|
|
78
83
|
.rf-mobile-menu-btn {
|
|
79
84
|
display: block;
|
|
80
85
|
}
|
|
81
|
-
.rf-mobile-panel {
|
|
82
|
-
display: block;
|
|
83
|
-
}
|
|
84
86
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/* On This Page — TOC sidebar navigation */
|
|
2
|
+
|
|
3
|
+
.rf-on-this-page {
|
|
4
|
+
font-size: 0.8rem;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.rf-on-this-page__title {
|
|
8
|
+
font-size: 0.7rem;
|
|
9
|
+
font-weight: 600;
|
|
10
|
+
text-transform: uppercase;
|
|
11
|
+
letter-spacing: 0.05em;
|
|
12
|
+
color: var(--rf-color-muted, #64748b);
|
|
13
|
+
margin: 0 0 0.75rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.rf-on-this-page__list {
|
|
17
|
+
list-style: none;
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.rf-on-this-page__item {
|
|
23
|
+
border-left: 2px solid transparent;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.rf-on-this-page__item[data-level="3"] {
|
|
27
|
+
padding-left: 0.75rem;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.rf-on-this-page__item a {
|
|
31
|
+
display: block;
|
|
32
|
+
padding: 0.25rem 0.75rem;
|
|
33
|
+
color: var(--rf-color-muted, #64748b);
|
|
34
|
+
text-decoration: none;
|
|
35
|
+
line-height: 1.4;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.rf-on-this-page__item a:hover {
|
|
39
|
+
color: var(--rf-color-text, #1a1a2e);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.rf-on-this-page__item[data-active] {
|
|
43
|
+
border-left-color: var(--rf-color-primary, #0ea5e9);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.rf-on-this-page__item[data-active] a {
|
|
47
|
+
color: var(--rf-color-primary, #0ea5e9);
|
|
48
|
+
}
|
package/styles/runes/symbol.css
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
/* Symbol */
|
|
2
2
|
.rf-symbol {
|
|
3
|
-
border: 1px solid var(--rf-color-border);
|
|
4
|
-
border-radius: var(--rf-radius-lg);
|
|
5
3
|
margin: 1.5rem 0;
|
|
6
|
-
overflow: hidden;
|
|
7
4
|
}
|
|
8
5
|
.rf-symbol__header {
|
|
9
6
|
display: flex;
|
|
10
7
|
align-items: center;
|
|
11
8
|
gap: 0.5rem;
|
|
12
|
-
padding: 0.
|
|
13
|
-
background: var(--rf-color-surface-hover);
|
|
14
|
-
border-bottom: 1px solid var(--rf-color-border);
|
|
9
|
+
padding: 0.5rem 0;
|
|
15
10
|
flex-wrap: wrap;
|
|
16
11
|
}
|
|
17
12
|
.rf-symbol__kind-badge {
|
|
@@ -56,7 +51,7 @@
|
|
|
56
51
|
color: var(--rf-color-primary);
|
|
57
52
|
}
|
|
58
53
|
.rf-symbol__body {
|
|
59
|
-
padding:
|
|
54
|
+
padding: 0;
|
|
60
55
|
}
|
|
61
56
|
.rf-symbol__body > header {
|
|
62
57
|
margin-bottom: 1rem;
|
|
@@ -100,6 +95,9 @@
|
|
|
100
95
|
border-radius: 0 var(--rf-radius-sm) var(--rf-radius-sm) 0;
|
|
101
96
|
font-size: 0.9375rem;
|
|
102
97
|
}
|
|
98
|
+
.rf-symbol__body blockquote::before {
|
|
99
|
+
content: none;
|
|
100
|
+
}
|
|
103
101
|
|
|
104
102
|
/* Deprecated symbol */
|
|
105
103
|
[data-deprecated] .rf-symbol__body > header h2,
|
|
@@ -132,10 +130,7 @@
|
|
|
132
130
|
/* SymbolMember */
|
|
133
131
|
.rf-symbol-member {
|
|
134
132
|
margin: 1.25rem 0;
|
|
135
|
-
padding:
|
|
136
|
-
border: 1px solid var(--rf-color-border);
|
|
137
|
-
border-radius: var(--rf-radius-md);
|
|
138
|
-
background: var(--rf-color-surface);
|
|
133
|
+
padding: 0;
|
|
139
134
|
}
|
|
140
135
|
.rf-symbol-member h4 {
|
|
141
136
|
margin: 0 0 0.5rem;
|
|
@@ -162,3 +157,6 @@
|
|
|
162
157
|
border-radius: 0 var(--rf-radius-sm) var(--rf-radius-sm) 0;
|
|
163
158
|
font-size: 0.875rem;
|
|
164
159
|
}
|
|
160
|
+
.rf-symbol-member blockquote::before {
|
|
161
|
+
content: none;
|
|
162
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Heading {
|
|
3
|
+
level: number;
|
|
4
|
+
text: string;
|
|
5
|
+
id: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
headings: Heading[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let { headings }: Props = $props();
|
|
13
|
+
|
|
14
|
+
// Filter to h2 and h3 only
|
|
15
|
+
const filtered = $derived(headings.filter(h => h.level >= 2 && h.level <= 3));
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<nav class="rf-on-this-page" data-scrollspy>
|
|
19
|
+
<p class="rf-on-this-page__title">On this page</p>
|
|
20
|
+
<ul class="rf-on-this-page__list">
|
|
21
|
+
{#each filtered as heading}
|
|
22
|
+
<li class="rf-on-this-page__item" data-level={heading.level}>
|
|
23
|
+
<a href="#{heading.id}">{heading.text}</a>
|
|
24
|
+
</li>
|
|
25
|
+
{/each}
|
|
26
|
+
</ul>
|
|
27
|
+
</nav>
|
|
28
|
+
|
|
29
|
+
<style>
|
|
30
|
+
.rf-on-this-page {
|
|
31
|
+
font-size: 0.8rem;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.rf-on-this-page__title {
|
|
35
|
+
font-size: 0.7rem;
|
|
36
|
+
font-weight: 600;
|
|
37
|
+
text-transform: uppercase;
|
|
38
|
+
letter-spacing: 0.05em;
|
|
39
|
+
color: var(--rf-color-muted, #64748b);
|
|
40
|
+
margin: 0 0 0.75rem;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.rf-on-this-page__list {
|
|
44
|
+
list-style: none;
|
|
45
|
+
margin: 0;
|
|
46
|
+
padding: 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.rf-on-this-page__item {
|
|
50
|
+
border-left: 2px solid transparent;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.rf-on-this-page__item[data-level="3"] {
|
|
54
|
+
padding-left: 0.75rem;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.rf-on-this-page__item a {
|
|
58
|
+
display: block;
|
|
59
|
+
padding: 0.25rem 0.75rem;
|
|
60
|
+
color: var(--rf-color-muted, #64748b);
|
|
61
|
+
text-decoration: none;
|
|
62
|
+
line-height: 1.4;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.rf-on-this-page__item a:hover {
|
|
66
|
+
color: var(--rf-color-text, #1a1a2e);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.rf-on-this-page__item[data-active] {
|
|
70
|
+
border-left-color: var(--rf-color-primary, #0ea5e9);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.rf-on-this-page__item[data-active] a {
|
|
74
|
+
color: var(--rf-color-primary, #0ea5e9);
|
|
75
|
+
}
|
|
76
|
+
</style>
|
package/svelte/index.ts
CHANGED
|
@@ -1,18 +1,35 @@
|
|
|
1
1
|
import type { SvelteTheme } from '@refrakt-md/svelte';
|
|
2
|
-
import
|
|
2
|
+
import adapterManifest from './manifest.json';
|
|
3
3
|
import { registry } from './registry.js';
|
|
4
4
|
import { elements } from './elements.js';
|
|
5
|
-
import
|
|
6
|
-
import DefaultLayout from './layouts/DefaultLayout.svelte';
|
|
7
|
-
import BlogLayout from './layouts/BlogLayout.svelte';
|
|
5
|
+
import { defaultLayout, docsLayout, blogArticleLayout } from '@refrakt-md/theme-base';
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
// Layout region metadata from the base theme manifest (packages/lumina/manifest.json).
|
|
8
|
+
// Merged with adapter manifest component paths to produce full LayoutDefinitions.
|
|
9
|
+
const layoutRegions: Record<string, { regions: string[]; requiredRegions?: string[] }> = {
|
|
10
|
+
default: { regions: ['header', 'footer'] },
|
|
11
|
+
docs: { regions: ['header', 'nav', 'sidebar', 'footer'], requiredRegions: ['nav'] },
|
|
12
|
+
'blog-article': { regions: ['header', 'sidebar', 'footer'] },
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const layouts: Record<string, any> = {};
|
|
16
|
+
for (const [name, adapter] of Object.entries(adapterManifest.layouts)) {
|
|
17
|
+
layouts[name] = { ...layoutRegions[name], ...adapter };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const manifest = { ...adapterManifest, layouts };
|
|
21
|
+
|
|
22
|
+
/** Re-export the merged manifest for server-side use (no Svelte imports) */
|
|
23
|
+
export { manifest };
|
|
11
24
|
|
|
12
25
|
/** The structured theme object consumed by ThemeShell */
|
|
13
26
|
export const theme: SvelteTheme = {
|
|
14
27
|
manifest: manifest as any,
|
|
15
|
-
layouts: {
|
|
28
|
+
layouts: {
|
|
29
|
+
default: defaultLayout,
|
|
30
|
+
docs: docsLayout,
|
|
31
|
+
'blog-article': blogArticleLayout,
|
|
32
|
+
},
|
|
16
33
|
components: registry,
|
|
17
34
|
elements,
|
|
18
35
|
};
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Renderer } from '@refrakt-md/svelte';
|
|
3
|
+
import OnThisPage from '../components/OnThisPage.svelte';
|
|
3
4
|
|
|
4
|
-
let { title, regions, renderable, url, pages }: {
|
|
5
|
+
let { title, regions, renderable, url, pages, headings, frontmatter }: {
|
|
5
6
|
title: string;
|
|
6
7
|
description: string;
|
|
7
8
|
regions: Record<string, { name: string; mode: string; content: any[] }>;
|
|
8
9
|
renderable: any;
|
|
9
10
|
url: string;
|
|
10
11
|
pages: Array<{ url: string; title: string; draft: boolean }>;
|
|
12
|
+
headings?: Array<{ level: number; text: string; id: string }>;
|
|
13
|
+
frontmatter?: Record<string, unknown>;
|
|
11
14
|
} = $props();
|
|
12
15
|
|
|
13
16
|
const hasNav = $derived(!!regions.nav);
|
|
14
17
|
|
|
18
|
+
// Show TOC when 2+ qualifying headings (h2/h3) and not opted out via frontmatter
|
|
19
|
+
const tocHeadings = $derived((headings ?? []).filter(h => h.level >= 2 && h.level <= 3));
|
|
20
|
+
const showToc = $derived(tocHeadings.length >= 2 && frontmatter?.toc !== false);
|
|
21
|
+
|
|
15
22
|
// Mobile panel state
|
|
16
23
|
let menuOpen = $state(false);
|
|
17
24
|
let navOpen = $state(false);
|
|
@@ -149,7 +156,14 @@
|
|
|
149
156
|
{/if}
|
|
150
157
|
|
|
151
158
|
<main class="rf-docs-content" class:rf-docs-content--has-nav={hasNav}>
|
|
152
|
-
<div class="rf-docs-content__inner">
|
|
153
|
-
<
|
|
159
|
+
<div class="rf-docs-content__inner" class:rf-docs-content__inner--has-toc={showToc}>
|
|
160
|
+
<div class="rf-docs-content__body">
|
|
161
|
+
<Renderer node={renderable} />
|
|
162
|
+
</div>
|
|
163
|
+
{#if showToc}
|
|
164
|
+
<aside class="rf-docs-toc">
|
|
165
|
+
<OnThisPage headings={tocHeadings} />
|
|
166
|
+
</aside>
|
|
167
|
+
{/if}
|
|
154
168
|
</div>
|
|
155
169
|
</main>
|
package/svelte/manifest.json
CHANGED
|
@@ -6,28 +6,11 @@
|
|
|
6
6
|
"designTokens": "tokens.css",
|
|
7
7
|
|
|
8
8
|
"layouts": {
|
|
9
|
-
"default": {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
},
|
|
13
|
-
"docs": {
|
|
14
|
-
"component": "layouts/DocsLayout.svelte",
|
|
15
|
-
"regions": ["header", "nav", "sidebar", "footer"],
|
|
16
|
-
"requiredRegions": ["nav"]
|
|
17
|
-
},
|
|
18
|
-
"blog": {
|
|
19
|
-
"component": "layouts/BlogLayout.svelte",
|
|
20
|
-
"regions": ["header", "sidebar", "footer"]
|
|
21
|
-
}
|
|
9
|
+
"default": { "component": "layouts/DefaultLayout.svelte" },
|
|
10
|
+
"docs": { "component": "layouts/DocsLayout.svelte" },
|
|
11
|
+
"blog": { "component": "layouts/BlogLayout.svelte" }
|
|
22
12
|
},
|
|
23
13
|
|
|
24
|
-
"routeRules": [
|
|
25
|
-
{ "pattern": "docs/**", "layout": "docs" },
|
|
26
|
-
{ "pattern": "blog", "layout": "blog" },
|
|
27
|
-
{ "pattern": "blog/**", "layout": "blog" },
|
|
28
|
-
{ "pattern": "**", "layout": "default" }
|
|
29
|
-
],
|
|
30
|
-
|
|
31
14
|
"components": {
|
|
32
15
|
"Hint": { "component": "components/Hint.svelte" },
|
|
33
16
|
"CallToAction": { "component": "components/CallToAction.svelte" },
|