@refrakt-md/lumina 0.4.0 → 0.5.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/base.css +16 -0
- package/contracts/structures.json +1317 -3
- package/dist/config.d.ts +2 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -229
- package/dist/config.js.map +1 -1
- package/dist/transform.d.ts +2 -0
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +2 -0
- package/dist/transform.js.map +1 -1
- package/index.css +11 -0
- package/package.json +18 -11
- package/styles/elements/blockquote.css +8 -4
- package/styles/global.css +0 -7
- package/styles/layouts/blog.css +255 -0
- package/styles/layouts/default.css +11 -3
- package/styles/layouts/docs.css +67 -13
- package/styles/layouts/mobile.css +84 -0
- package/styles/runes/bento.css +2 -0
- package/styles/runes/codegroup.css +7 -2
- package/styles/runes/design-context.css +25 -0
- package/styles/runes/feature.css +20 -14
- package/styles/runes/form.css +1 -2
- package/styles/runes/grid.css +25 -7
- package/styles/runes/hero.css +15 -0
- package/styles/runes/map.css +113 -0
- package/styles/runes/palette.css +86 -0
- package/styles/runes/preview.css +187 -0
- package/styles/runes/sandbox.css +23 -0
- package/styles/runes/spacing.css +105 -0
- package/styles/runes/steps.css +7 -1
- package/styles/runes/swatch.css +28 -0
- package/styles/runes/symbol.css +164 -0
- package/styles/runes/tabs.css +6 -0
- package/styles/runes/testimonial.css +2 -3
- package/styles/runes/timeline.css +43 -24
- package/styles/runes/typography.css +91 -0
- package/svelte/elements.ts +1 -0
- package/{sveltekit → svelte}/index.ts +0 -8
- package/svelte/layouts/BlogLayout.svelte +173 -0
- package/svelte/layouts/DefaultLayout.svelte +67 -0
- package/svelte/layouts/DocsLayout.svelte +155 -0
- package/{sveltekit → svelte}/manifest.json +1 -1
- package/svelte/registry.ts +2 -0
- package/svelte/tokens.css +6 -0
- package/sveltekit/components/Accordion.svelte +0 -26
- package/sveltekit/components/Bento.svelte +0 -50
- package/sveltekit/components/Chart.svelte +0 -121
- package/sveltekit/components/CodeGroup.svelte +0 -88
- package/sveltekit/components/Comparison.svelte +0 -209
- package/sveltekit/components/DataTable.svelte +0 -154
- package/sveltekit/components/Details.svelte +0 -23
- package/sveltekit/components/Diagram.svelte +0 -45
- package/sveltekit/components/Embed.svelte +0 -36
- package/sveltekit/components/Form.svelte +0 -194
- package/sveltekit/components/Grid.svelte +0 -42
- package/sveltekit/components/Nav.svelte +0 -62
- package/sveltekit/components/Pricing.svelte +0 -20
- package/sveltekit/components/Reveal.svelte +0 -62
- package/sveltekit/components/Storyboard.svelte +0 -41
- package/sveltekit/components/Tabs.svelte +0 -75
- package/sveltekit/components/Testimonial.svelte +0 -26
- package/sveltekit/elements/Blockquote.svelte +0 -37
- package/sveltekit/elements/Pre.svelte +0 -77
- package/sveltekit/elements/Table.svelte +0 -40
- package/sveltekit/elements.ts +0 -11
- package/sveltekit/layouts/BlogLayout.svelte +0 -382
- package/sveltekit/layouts/DefaultLayout.svelte +0 -70
- package/sveltekit/layouts/DocsLayout.svelte +0 -133
- package/sveltekit/registry.ts +0 -59
- package/sveltekit/tokens.css +0 -71
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { onMount } from 'svelte';
|
|
3
|
-
import type { Snippet } from 'svelte';
|
|
4
|
-
import type { SerializedTag } from '@refrakt-md/svelte';
|
|
5
|
-
|
|
6
|
-
let { tag, children }: { tag: SerializedTag; children: Snippet } = $props();
|
|
7
|
-
|
|
8
|
-
const sortable = (tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'sortable')?.attributes?.content || '').split(',').map((s: string) => s.trim()).filter(Boolean);
|
|
9
|
-
const searchable = tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'searchable')?.attributes?.content === 'true';
|
|
10
|
-
const pageSize = parseInt(tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'pageSize')?.attributes?.content || '0', 10);
|
|
11
|
-
const defaultSort = tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'defaultSort')?.attributes?.content || '';
|
|
12
|
-
|
|
13
|
-
let searchQuery = $state('');
|
|
14
|
-
let sortColumn = $state(defaultSort);
|
|
15
|
-
let sortDirection = $state<'asc' | 'desc'>('asc');
|
|
16
|
-
let currentPage = $state(0);
|
|
17
|
-
|
|
18
|
-
let contentEl: HTMLDivElement;
|
|
19
|
-
let headers: string[] = [];
|
|
20
|
-
let allRows: { el: HTMLTableRowElement; cells: string[] }[] = [];
|
|
21
|
-
let totalFiltered = $state(0);
|
|
22
|
-
|
|
23
|
-
function toggleSort(column: string) {
|
|
24
|
-
if (!sortable.includes(column)) return;
|
|
25
|
-
if (sortColumn === column) {
|
|
26
|
-
sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
|
|
27
|
-
} else {
|
|
28
|
-
sortColumn = column;
|
|
29
|
-
sortDirection = 'asc';
|
|
30
|
-
}
|
|
31
|
-
currentPage = 0;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
onMount(() => {
|
|
35
|
-
const table = contentEl?.querySelector('table');
|
|
36
|
-
if (!table) return;
|
|
37
|
-
|
|
38
|
-
const thEls = table.querySelectorAll('th');
|
|
39
|
-
headers = Array.from(thEls).map(th => th.textContent?.trim() || '');
|
|
40
|
-
|
|
41
|
-
thEls.forEach((th) => {
|
|
42
|
-
const name = th.textContent?.trim() || '';
|
|
43
|
-
if (sortable.includes(name)) {
|
|
44
|
-
th.style.cursor = 'pointer';
|
|
45
|
-
th.style.userSelect = 'none';
|
|
46
|
-
th.addEventListener('click', () => toggleSort(name));
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
const bodyRows = table.querySelectorAll('tbody tr');
|
|
51
|
-
const rows = bodyRows.length > 0 ? bodyRows : table.querySelectorAll('tr:not(:first-child)');
|
|
52
|
-
allRows = Array.from(rows).map(tr => ({
|
|
53
|
-
el: tr as HTMLTableRowElement,
|
|
54
|
-
cells: Array.from(tr.querySelectorAll('td')).map(td => td.textContent?.trim() || ''),
|
|
55
|
-
}));
|
|
56
|
-
|
|
57
|
-
totalFiltered = allRows.length;
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
$effect(() => {
|
|
61
|
-
if (!allRows.length) return;
|
|
62
|
-
|
|
63
|
-
let filtered = [...allRows];
|
|
64
|
-
|
|
65
|
-
if (searchQuery) {
|
|
66
|
-
const q = searchQuery.toLowerCase();
|
|
67
|
-
filtered = filtered.filter(r => r.cells.some(c => c.toLowerCase().includes(q)));
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (sortColumn) {
|
|
71
|
-
const idx = headers.indexOf(sortColumn);
|
|
72
|
-
if (idx >= 0) {
|
|
73
|
-
filtered.sort((a, b) => {
|
|
74
|
-
const cmp = a.cells[idx].localeCompare(b.cells[idx], undefined, { numeric: true });
|
|
75
|
-
return sortDirection === 'asc' ? cmp : -cmp;
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
totalFiltered = filtered.length;
|
|
81
|
-
|
|
82
|
-
const visible = pageSize > 0
|
|
83
|
-
? filtered.slice(currentPage * pageSize, (currentPage + 1) * pageSize)
|
|
84
|
-
: filtered;
|
|
85
|
-
|
|
86
|
-
const tbody = contentEl?.querySelector('tbody') || contentEl?.querySelector('table');
|
|
87
|
-
if (!tbody) return;
|
|
88
|
-
|
|
89
|
-
allRows.forEach(r => r.el.style.display = 'none');
|
|
90
|
-
visible.forEach(r => {
|
|
91
|
-
r.el.style.display = '';
|
|
92
|
-
tbody.appendChild(r.el);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const thEls = contentEl?.querySelectorAll('th');
|
|
96
|
-
thEls?.forEach(th => {
|
|
97
|
-
const name = th.textContent?.replace(/[▲▼]/g, '').trim() || '';
|
|
98
|
-
const indicator = th.querySelector('.sort-indicator');
|
|
99
|
-
if (sortable.includes(name)) {
|
|
100
|
-
if (sortColumn === name) {
|
|
101
|
-
if (indicator) {
|
|
102
|
-
indicator.textContent = sortDirection === 'asc' ? ' ▲' : ' ▼';
|
|
103
|
-
} else {
|
|
104
|
-
const span = document.createElement('span');
|
|
105
|
-
span.className = 'sort-indicator';
|
|
106
|
-
span.textContent = sortDirection === 'asc' ? ' ▲' : ' ▼';
|
|
107
|
-
th.appendChild(span);
|
|
108
|
-
}
|
|
109
|
-
} else {
|
|
110
|
-
if (indicator) indicator.remove();
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
const totalPages = $derived(pageSize > 0 ? Math.ceil(totalFiltered / pageSize) : 1);
|
|
117
|
-
</script>
|
|
118
|
-
|
|
119
|
-
<div class="rf-datatable" typeof="DataTable">
|
|
120
|
-
{#if searchable}
|
|
121
|
-
<div class="rf-datatable__toolbar">
|
|
122
|
-
<input
|
|
123
|
-
type="search"
|
|
124
|
-
placeholder="Filter rows..."
|
|
125
|
-
bind:value={searchQuery}
|
|
126
|
-
class="rf-datatable__input"
|
|
127
|
-
/>
|
|
128
|
-
</div>
|
|
129
|
-
{/if}
|
|
130
|
-
<div class="rf-datatable__content" bind:this={contentEl}>
|
|
131
|
-
{@render children()}
|
|
132
|
-
</div>
|
|
133
|
-
{#if pageSize > 0 && totalPages > 1}
|
|
134
|
-
<div class="rf-datatable__pagination">
|
|
135
|
-
<button
|
|
136
|
-
class="rf-datatable__page-btn"
|
|
137
|
-
disabled={currentPage === 0}
|
|
138
|
-
onclick={() => currentPage--}
|
|
139
|
-
>
|
|
140
|
-
← Prev
|
|
141
|
-
</button>
|
|
142
|
-
<span class="rf-datatable__page-info">
|
|
143
|
-
{currentPage + 1} / {totalPages}
|
|
144
|
-
</span>
|
|
145
|
-
<button
|
|
146
|
-
class="rf-datatable__page-btn"
|
|
147
|
-
disabled={currentPage >= totalPages - 1}
|
|
148
|
-
onclick={() => currentPage++}
|
|
149
|
-
>
|
|
150
|
-
Next →
|
|
151
|
-
</button>
|
|
152
|
-
</div>
|
|
153
|
-
{/if}
|
|
154
|
-
</div>
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { SerializedTag } from '@refrakt-md/svelte';
|
|
3
|
-
import type { Snippet } from 'svelte';
|
|
4
|
-
|
|
5
|
-
let { tag, children }: { tag: SerializedTag; children: Snippet } = $props();
|
|
6
|
-
|
|
7
|
-
const summary = $derived(tag.children
|
|
8
|
-
.find((c: any) => c?.name === 'span' && c?.attributes?.property === 'summary')
|
|
9
|
-
?.children?.[0] ?? 'Details');
|
|
10
|
-
|
|
11
|
-
const isOpen = $derived(tag.children
|
|
12
|
-
.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'open')
|
|
13
|
-
?.attributes?.content ?? false);
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<details class="rf-details" open={isOpen || undefined}>
|
|
17
|
-
<summary class="rf-details__summary">
|
|
18
|
-
<span>{summary}</span>
|
|
19
|
-
</summary>
|
|
20
|
-
<div class="rf-details__body">
|
|
21
|
-
{@render children()}
|
|
22
|
-
</div>
|
|
23
|
-
</details>
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { onMount } from 'svelte';
|
|
3
|
-
import type { Snippet } from 'svelte';
|
|
4
|
-
import type { SerializedTag } from '@refrakt-md/svelte';
|
|
5
|
-
|
|
6
|
-
let { tag, children }: { tag: SerializedTag; children: Snippet } = $props();
|
|
7
|
-
|
|
8
|
-
const language = tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'language')?.attributes?.content || 'mermaid';
|
|
9
|
-
const title = tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'title')?.attributes?.content || '';
|
|
10
|
-
const source = tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.['data-name'] === 'source')?.attributes?.content || '';
|
|
11
|
-
|
|
12
|
-
let container: HTMLDivElement;
|
|
13
|
-
let rendered = $state(false);
|
|
14
|
-
|
|
15
|
-
onMount(async () => {
|
|
16
|
-
if (language === 'mermaid' && source) {
|
|
17
|
-
try {
|
|
18
|
-
const cdn = 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
|
19
|
-
const mermaid = (await import(/* @vite-ignore */ cdn)).default;
|
|
20
|
-
mermaid.initialize({ startOnLoad: false, theme: 'default' });
|
|
21
|
-
const { svg } = await mermaid.render('mermaid-' + Math.random().toString(36).slice(2), source);
|
|
22
|
-
container.innerHTML = svg;
|
|
23
|
-
rendered = true;
|
|
24
|
-
} catch (e) {
|
|
25
|
-
container.textContent = source;
|
|
26
|
-
}
|
|
27
|
-
} else if (language === 'ascii' && source) {
|
|
28
|
-
container.textContent = source;
|
|
29
|
-
container.style.fontFamily = 'var(--rf-font-mono)';
|
|
30
|
-
container.style.whiteSpace = 'pre';
|
|
31
|
-
rendered = true;
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
</script>
|
|
35
|
-
|
|
36
|
-
<figure class="rf-diagram" typeof="Diagram">
|
|
37
|
-
{#if title}
|
|
38
|
-
<figcaption class="rf-diagram__title">{title}</figcaption>
|
|
39
|
-
{/if}
|
|
40
|
-
<div class="rf-diagram__container" bind:this={container}>
|
|
41
|
-
{#if !rendered}
|
|
42
|
-
<pre class="rf-diagram__source"><code>{source}</code></pre>
|
|
43
|
-
{/if}
|
|
44
|
-
</div>
|
|
45
|
-
</figure>
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { SerializedTag } from '@refrakt-md/svelte';
|
|
3
|
-
import type { Snippet } from 'svelte';
|
|
4
|
-
|
|
5
|
-
let { tag, children }: { tag: SerializedTag; children: Snippet } = $props();
|
|
6
|
-
|
|
7
|
-
const getMeta = (prop: string) => tag.children
|
|
8
|
-
.find((c: any) => c?.name === 'meta' && c?.attributes?.property === prop)
|
|
9
|
-
?.attributes?.content;
|
|
10
|
-
|
|
11
|
-
const embedUrl = getMeta('embedUrl') || getMeta('url') || '';
|
|
12
|
-
const title = getMeta('title') || 'Embedded content';
|
|
13
|
-
const aspect = getMeta('aspect') || '16:9';
|
|
14
|
-
const provider = getMeta('provider') || '';
|
|
15
|
-
|
|
16
|
-
const [w, h] = aspect.split(':').map(Number);
|
|
17
|
-
const paddingPercent = h && w ? (h / w) * 100 : 56.25;
|
|
18
|
-
</script>
|
|
19
|
-
|
|
20
|
-
<figure class="rf-embed" data-provider={provider || undefined}>
|
|
21
|
-
{#if embedUrl}
|
|
22
|
-
<div class="rf-embed__wrapper" style="padding-bottom: {paddingPercent}%">
|
|
23
|
-
<iframe
|
|
24
|
-
src={embedUrl}
|
|
25
|
-
{title}
|
|
26
|
-
frameborder="0"
|
|
27
|
-
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
28
|
-
allowfullscreen
|
|
29
|
-
loading="lazy"
|
|
30
|
-
></iframe>
|
|
31
|
-
</div>
|
|
32
|
-
{/if}
|
|
33
|
-
<div class="rf-embed__fallback">
|
|
34
|
-
{@render children()}
|
|
35
|
-
</div>
|
|
36
|
-
</figure>
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
|
-
import type { SerializedTag } from '@refrakt-md/svelte';
|
|
4
|
-
|
|
5
|
-
let { tag, children }: { tag: SerializedTag; children: Snippet } = $props();
|
|
6
|
-
|
|
7
|
-
const isForm = tag.attributes.typeof === 'Form';
|
|
8
|
-
|
|
9
|
-
// Form-level properties
|
|
10
|
-
const action = isForm
|
|
11
|
-
? tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'action')?.attributes?.content || ''
|
|
12
|
-
: '';
|
|
13
|
-
const method = isForm
|
|
14
|
-
? tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'method')?.attributes?.content || 'POST'
|
|
15
|
-
: 'POST';
|
|
16
|
-
const success = isForm
|
|
17
|
-
? tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'success')?.attributes?.content || ''
|
|
18
|
-
: '';
|
|
19
|
-
const errorMsg = isForm
|
|
20
|
-
? tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'error')?.attributes?.content || ''
|
|
21
|
-
: '';
|
|
22
|
-
const formStyle = isForm
|
|
23
|
-
? tag.attributes['data-style'] || 'stacked'
|
|
24
|
-
: 'stacked';
|
|
25
|
-
const honeypot = isForm
|
|
26
|
-
? tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'honeypot')?.attributes?.content !== 'false'
|
|
27
|
-
: true;
|
|
28
|
-
|
|
29
|
-
// FormField properties
|
|
30
|
-
const fieldName = !isForm
|
|
31
|
-
? tag.children.find((c: any) => c?.name === 'span' && c?.attributes?.property === 'name')?.children?.[0] || ''
|
|
32
|
-
: '';
|
|
33
|
-
const fieldType = !isForm
|
|
34
|
-
? tag.attributes['data-field-type'] || 'text'
|
|
35
|
-
: '';
|
|
36
|
-
const required = !isForm
|
|
37
|
-
? tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'required')?.attributes?.content === 'true'
|
|
38
|
-
: false;
|
|
39
|
-
const placeholder = !isForm
|
|
40
|
-
? tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'placeholder')?.attributes?.content || ''
|
|
41
|
-
: '';
|
|
42
|
-
const options = !isForm
|
|
43
|
-
? (tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'options')?.attributes?.content || '')
|
|
44
|
-
.split(',')
|
|
45
|
-
.map((o: string) => o.trim())
|
|
46
|
-
.filter(Boolean)
|
|
47
|
-
: [];
|
|
48
|
-
|
|
49
|
-
const fieldId = !isForm ? `field-${fieldName.toLowerCase().replace(/\s+/g, '-')}` : '';
|
|
50
|
-
|
|
51
|
-
// Form submission state
|
|
52
|
-
let status = $state<'idle' | 'submitting' | 'success' | 'error'>('idle');
|
|
53
|
-
let statusMessage = $state('');
|
|
54
|
-
|
|
55
|
-
async function handleSubmit(e: SubmitEvent) {
|
|
56
|
-
e.preventDefault();
|
|
57
|
-
if (!action) return;
|
|
58
|
-
|
|
59
|
-
status = 'submitting';
|
|
60
|
-
const formData = new FormData(e.target as HTMLFormElement);
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
const response = await fetch(action, {
|
|
64
|
-
method: method,
|
|
65
|
-
body: formData,
|
|
66
|
-
headers: { 'Accept': 'application/json' },
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
if (response.ok) {
|
|
70
|
-
status = 'success';
|
|
71
|
-
statusMessage = success || 'Form submitted successfully.';
|
|
72
|
-
(e.target as HTMLFormElement).reset();
|
|
73
|
-
} else {
|
|
74
|
-
status = 'error';
|
|
75
|
-
statusMessage = errorMsg || 'Something went wrong. Please try again.';
|
|
76
|
-
}
|
|
77
|
-
} catch {
|
|
78
|
-
status = 'error';
|
|
79
|
-
statusMessage = errorMsg || 'Something went wrong. Please try again.';
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
</script>
|
|
83
|
-
|
|
84
|
-
{#if isForm}
|
|
85
|
-
<form
|
|
86
|
-
class="rf-form {formStyle !== 'stacked' ? `rf-form--${formStyle}` : ''}"
|
|
87
|
-
action={action}
|
|
88
|
-
method={method}
|
|
89
|
-
onsubmit={handleSubmit}
|
|
90
|
-
>
|
|
91
|
-
{#if honeypot}
|
|
92
|
-
<div class="rf-form__hp" aria-hidden="true">
|
|
93
|
-
<input type="text" name="_gotcha" autocomplete="off" tabindex={-1} />
|
|
94
|
-
</div>
|
|
95
|
-
{/if}
|
|
96
|
-
{@render children()}
|
|
97
|
-
{#if status === 'submitting'}
|
|
98
|
-
<div class="rf-form__status rf-form__status--submitting" role="status">Submitting...</div>
|
|
99
|
-
{:else if status === 'success'}
|
|
100
|
-
<div class="rf-form__status rf-form__status--success" role="alert">{statusMessage}</div>
|
|
101
|
-
{:else if status === 'error'}
|
|
102
|
-
<div class="rf-form__status rf-form__status--error" role="alert">{statusMessage}</div>
|
|
103
|
-
{/if}
|
|
104
|
-
</form>
|
|
105
|
-
{:else if fieldType === 'group'}
|
|
106
|
-
<fieldset class="rf-form-fieldset">
|
|
107
|
-
<legend>{fieldName}</legend>
|
|
108
|
-
{@render children()}
|
|
109
|
-
</fieldset>
|
|
110
|
-
{:else if fieldType === 'submit'}
|
|
111
|
-
<button type="submit" class="rf-form__submit">{fieldName}</button>
|
|
112
|
-
{:else if fieldType === 'separator'}
|
|
113
|
-
<hr class="rf-form__separator" />
|
|
114
|
-
{:else if fieldType === 'help'}
|
|
115
|
-
<p class="rf-form__help">{fieldName}</p>
|
|
116
|
-
{:else if fieldType === 'description'}
|
|
117
|
-
<p class="rf-form__text">{fieldName}</p>
|
|
118
|
-
{:else if fieldType === 'textarea'}
|
|
119
|
-
<div class="rf-form-field">
|
|
120
|
-
<label for={fieldId}>
|
|
121
|
-
{fieldName}
|
|
122
|
-
{#if required}<span class="rf-form-field__required" aria-hidden="true">*</span>{/if}
|
|
123
|
-
</label>
|
|
124
|
-
<textarea
|
|
125
|
-
id={fieldId}
|
|
126
|
-
name={fieldId}
|
|
127
|
-
placeholder={placeholder}
|
|
128
|
-
required={required}
|
|
129
|
-
rows={4}
|
|
130
|
-
></textarea>
|
|
131
|
-
</div>
|
|
132
|
-
{:else if fieldType === 'select'}
|
|
133
|
-
<div class="rf-form-field">
|
|
134
|
-
<label for={fieldId}>
|
|
135
|
-
{fieldName}
|
|
136
|
-
{#if required}<span class="rf-form-field__required" aria-hidden="true">*</span>{/if}
|
|
137
|
-
</label>
|
|
138
|
-
<select id={fieldId} name={fieldId} required={required}>
|
|
139
|
-
<option value="" disabled selected>Select an option</option>
|
|
140
|
-
{#each options as option}
|
|
141
|
-
<option value={option}>{option}</option>
|
|
142
|
-
{/each}
|
|
143
|
-
</select>
|
|
144
|
-
</div>
|
|
145
|
-
{:else if fieldType === 'radio'}
|
|
146
|
-
<fieldset class="rf-form-field rf-form-choice-group">
|
|
147
|
-
<legend>
|
|
148
|
-
{fieldName}
|
|
149
|
-
{#if required}<span class="rf-form-field__required" aria-hidden="true">*</span>{/if}
|
|
150
|
-
</legend>
|
|
151
|
-
{#each options as option, i}
|
|
152
|
-
<label class="rf-form-choice">
|
|
153
|
-
<input
|
|
154
|
-
type="radio"
|
|
155
|
-
name={fieldId}
|
|
156
|
-
value={option}
|
|
157
|
-
required={required && i === 0}
|
|
158
|
-
/>
|
|
159
|
-
<span>{option}</span>
|
|
160
|
-
</label>
|
|
161
|
-
{/each}
|
|
162
|
-
</fieldset>
|
|
163
|
-
{:else if fieldType === 'checkbox'}
|
|
164
|
-
<fieldset class="rf-form-field rf-form-choice-group">
|
|
165
|
-
<legend>
|
|
166
|
-
{fieldName}
|
|
167
|
-
{#if required}<span class="rf-form-field__required" aria-hidden="true">*</span>{/if}
|
|
168
|
-
</legend>
|
|
169
|
-
{#each options as option}
|
|
170
|
-
<label class="rf-form-choice">
|
|
171
|
-
<input
|
|
172
|
-
type="checkbox"
|
|
173
|
-
name={fieldId}
|
|
174
|
-
value={option}
|
|
175
|
-
/>
|
|
176
|
-
<span>{option}</span>
|
|
177
|
-
</label>
|
|
178
|
-
{/each}
|
|
179
|
-
</fieldset>
|
|
180
|
-
{:else}
|
|
181
|
-
<div class="rf-form-field">
|
|
182
|
-
<label for={fieldId}>
|
|
183
|
-
{fieldName}
|
|
184
|
-
{#if required}<span class="rf-form-field__required" aria-hidden="true">*</span>{/if}
|
|
185
|
-
</label>
|
|
186
|
-
<input
|
|
187
|
-
type={fieldType}
|
|
188
|
-
id={fieldId}
|
|
189
|
-
name={fieldId}
|
|
190
|
-
placeholder={placeholder}
|
|
191
|
-
required={required}
|
|
192
|
-
/>
|
|
193
|
-
</div>
|
|
194
|
-
{/if}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { SerializedTag, RendererNode } from '@refrakt-md/svelte';
|
|
3
|
-
import { Renderer } from '@refrakt-md/svelte';
|
|
4
|
-
import type { Snippet } from 'svelte';
|
|
5
|
-
|
|
6
|
-
let { tag, children }: { tag: SerializedTag; children: Snippet } = $props();
|
|
7
|
-
|
|
8
|
-
function isTag(n: RendererNode): n is SerializedTag {
|
|
9
|
-
return n !== null && typeof n === 'object' && !Array.isArray(n) && (n as any).$$mdtype === 'Tag';
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const layoutDiv = $derived(tag.children.find(
|
|
13
|
-
(c): c is SerializedTag => isTag(c) && c.attributes?.['data-layout'] === 'grid'
|
|
14
|
-
));
|
|
15
|
-
const columns = $derived(layoutDiv?.attributes?.['data-columns']);
|
|
16
|
-
const flow = $derived(layoutDiv?.attributes?.['data-flow']);
|
|
17
|
-
const gridItems = $derived(layoutDiv?.children?.filter((c): c is SerializedTag => isTag(c)) ?? []);
|
|
18
|
-
</script>
|
|
19
|
-
|
|
20
|
-
{#if gridItems.length > 0}
|
|
21
|
-
<div
|
|
22
|
-
class="rf-grid"
|
|
23
|
-
style:grid-template-columns={columns ? `repeat(${columns}, 1fr)` : undefined}
|
|
24
|
-
style:grid-auto-flow={flow || undefined}
|
|
25
|
-
>
|
|
26
|
-
{#each gridItems as item}
|
|
27
|
-
{@const colspan = Number(item.attributes?.['data-colspan']) || 1}
|
|
28
|
-
{@const rowspan = Number(item.attributes?.['data-rowspan']) || 1}
|
|
29
|
-
<div
|
|
30
|
-
class="rf-grid__item"
|
|
31
|
-
style:grid-column={colspan > 1 ? `span ${colspan}` : undefined}
|
|
32
|
-
style:grid-row={rowspan > 1 ? `span ${rowspan}` : undefined}
|
|
33
|
-
>
|
|
34
|
-
<Renderer node={item.children} />
|
|
35
|
-
</div>
|
|
36
|
-
{/each}
|
|
37
|
-
</div>
|
|
38
|
-
{:else}
|
|
39
|
-
<div class="rf-grid">
|
|
40
|
-
{@render children()}
|
|
41
|
-
</div>
|
|
42
|
-
{/if}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { SerializedTag, RendererNode } from '@refrakt-md/svelte';
|
|
3
|
-
import type { Snippet } from 'svelte';
|
|
4
|
-
import { getContext } from 'svelte';
|
|
5
|
-
import { page } from '$app/state';
|
|
6
|
-
|
|
7
|
-
interface PageEntry {
|
|
8
|
-
url: string;
|
|
9
|
-
title: string;
|
|
10
|
-
draft: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
let { tag, children }: { tag: SerializedTag; children: Snippet } = $props();
|
|
14
|
-
const typeName = $derived(tag.attributes.typeof);
|
|
15
|
-
const pages = getContext<PageEntry[]>('pages');
|
|
16
|
-
|
|
17
|
-
function getSlug(tag: SerializedTag): string | null {
|
|
18
|
-
for (const child of tag.children) {
|
|
19
|
-
if (isTag(child) && child.name === 'span' && child.attributes.property === 'slug') {
|
|
20
|
-
return getTextContent(child);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function isTag(node: RendererNode): node is SerializedTag {
|
|
27
|
-
return node !== null && typeof node === 'object' && !Array.isArray(node) && (node as any).$$mdtype === 'Tag';
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function getTextContent(node: RendererNode): string {
|
|
31
|
-
if (typeof node === 'string') return node;
|
|
32
|
-
if (typeof node === 'number') return String(node);
|
|
33
|
-
if (isTag(node)) return node.children.map(getTextContent).join('');
|
|
34
|
-
if (Array.isArray(node)) return node.map(getTextContent).join('');
|
|
35
|
-
return '';
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function resolvePage(slug: string): PageEntry | undefined {
|
|
39
|
-
return pages?.find(p => p.url.endsWith('/' + slug) || p.url === '/' + slug);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const slug = $derived(typeName === 'NavItem' ? getSlug(tag) : null);
|
|
43
|
-
const linkedPage = $derived(slug ? resolvePage(slug) : null);
|
|
44
|
-
</script>
|
|
45
|
-
|
|
46
|
-
{#if typeName === 'Nav'}
|
|
47
|
-
<nav class="rf-nav">
|
|
48
|
-
{@render children()}
|
|
49
|
-
</nav>
|
|
50
|
-
{:else if typeName === 'NavGroup'}
|
|
51
|
-
<div class="rf-nav-group">
|
|
52
|
-
{@render children()}
|
|
53
|
-
</div>
|
|
54
|
-
{:else if typeName === 'NavItem' && linkedPage}
|
|
55
|
-
<a href={linkedPage.url} class="rf-nav-item__link" class:rf-nav-item__link--active={page.url.pathname === linkedPage.url}>
|
|
56
|
-
{linkedPage.title}
|
|
57
|
-
</a>
|
|
58
|
-
{:else}
|
|
59
|
-
<div class="rf-nav-item">
|
|
60
|
-
{@render children()}
|
|
61
|
-
</div>
|
|
62
|
-
{/if}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { SerializedTag } from '@refrakt-md/svelte';
|
|
3
|
-
import type { Snippet } from 'svelte';
|
|
4
|
-
|
|
5
|
-
let { tag, children }: { tag: SerializedTag; children: Snippet } = $props();
|
|
6
|
-
|
|
7
|
-
const typeName = tag.attributes.typeof;
|
|
8
|
-
const isTier = typeName === 'Tier' || typeName === 'FeaturedTier';
|
|
9
|
-
const isFeatured = typeName === 'FeaturedTier';
|
|
10
|
-
</script>
|
|
11
|
-
|
|
12
|
-
{#if typeName === 'Pricing'}
|
|
13
|
-
<section class="rf-pricing">
|
|
14
|
-
{@render children()}
|
|
15
|
-
</section>
|
|
16
|
-
{:else if isTier}
|
|
17
|
-
<li class="rf-tier {isFeatured ? 'rf-tier--featured' : ''}">
|
|
18
|
-
{@render children()}
|
|
19
|
-
</li>
|
|
20
|
-
{/if}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
|
-
import type { SerializedTag } from '@refrakt-md/svelte';
|
|
4
|
-
import { Renderer } from '@refrakt-md/svelte';
|
|
5
|
-
|
|
6
|
-
let { tag, children }: { tag: SerializedTag; children: Snippet } = $props();
|
|
7
|
-
|
|
8
|
-
const isGroup = tag.attributes.typeof === 'Reveal';
|
|
9
|
-
|
|
10
|
-
const stepName = !isGroup
|
|
11
|
-
? tag.children.find((c: any) => c?.name === 'span' && c?.attributes?.property === 'name')?.children?.[0] || ''
|
|
12
|
-
: '';
|
|
13
|
-
|
|
14
|
-
const mode = isGroup
|
|
15
|
-
? tag.children.find((c: any) => c?.name === 'meta')?.attributes?.content || 'click'
|
|
16
|
-
: 'click';
|
|
17
|
-
|
|
18
|
-
const stepsDiv = isGroup
|
|
19
|
-
? tag.children.find((c: any) => c?.name === 'div' && c?.attributes?.['data-name'] === 'steps')
|
|
20
|
-
: null;
|
|
21
|
-
|
|
22
|
-
const totalSteps = isGroup && stepsDiv
|
|
23
|
-
? (stepsDiv as any).children?.filter((c: any) => c?.attributes?.typeof === 'RevealStep')?.length ?? 0
|
|
24
|
-
: 0;
|
|
25
|
-
|
|
26
|
-
let visibleCount = $state(1);
|
|
27
|
-
</script>
|
|
28
|
-
|
|
29
|
-
{#if isGroup}
|
|
30
|
-
<section class="rf-reveal">
|
|
31
|
-
{#if stepsDiv}
|
|
32
|
-
<div class="rf-reveal__steps">
|
|
33
|
-
{#each (stepsDiv as any).children?.filter((c: any) => c?.attributes?.typeof === 'RevealStep') ?? [] as step, i}
|
|
34
|
-
<div class="rf-reveal-step {i < visibleCount ? 'rf-reveal-step--visible' : 'rf-reveal-step--hidden'}">
|
|
35
|
-
<Renderer node={step} />
|
|
36
|
-
</div>
|
|
37
|
-
{/each}
|
|
38
|
-
</div>
|
|
39
|
-
{:else}
|
|
40
|
-
{@render children()}
|
|
41
|
-
{/if}
|
|
42
|
-
{#if mode === 'click' && visibleCount < totalSteps}
|
|
43
|
-
<button class="rf-reveal__next" onclick={() => visibleCount++}>
|
|
44
|
-
Continue
|
|
45
|
-
</button>
|
|
46
|
-
{/if}
|
|
47
|
-
{#if mode === 'click' && visibleCount >= totalSteps && totalSteps > 1}
|
|
48
|
-
<button class="rf-reveal__reset" onclick={() => visibleCount = 1}>
|
|
49
|
-
Start over
|
|
50
|
-
</button>
|
|
51
|
-
{/if}
|
|
52
|
-
</section>
|
|
53
|
-
{:else}
|
|
54
|
-
<div class="rf-reveal-step__content">
|
|
55
|
-
{#if stepName}
|
|
56
|
-
<h3 class="rf-reveal-step__title">{stepName}</h3>
|
|
57
|
-
{/if}
|
|
58
|
-
<div class="rf-reveal-step__body">
|
|
59
|
-
{@render children()}
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
{/if}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
|
-
import type { SerializedTag, RendererNode } from '@refrakt-md/svelte';
|
|
4
|
-
import { Renderer } from '@refrakt-md/svelte';
|
|
5
|
-
|
|
6
|
-
let { tag, children }: { tag: SerializedTag; children: Snippet } = $props();
|
|
7
|
-
|
|
8
|
-
function isTag(n: RendererNode): n is SerializedTag {
|
|
9
|
-
return n !== null && typeof n === 'object' && !Array.isArray(n) && (n as any).$$mdtype === 'Tag';
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const isGroup = $derived(tag.attributes.typeof === 'Storyboard');
|
|
13
|
-
|
|
14
|
-
// Style modifier is consumed by engine; read from data attribute
|
|
15
|
-
const styleName = $derived(isGroup
|
|
16
|
-
? tag.attributes['data-style'] || 'clean'
|
|
17
|
-
: 'clean');
|
|
18
|
-
const columns = $derived(isGroup
|
|
19
|
-
? parseInt(tag.children.find((c: any) => c?.name === 'meta' && c?.attributes?.property === 'columns')?.attributes?.content || '3', 10)
|
|
20
|
-
: 3);
|
|
21
|
-
|
|
22
|
-
const panelsEl = $derived(isGroup
|
|
23
|
-
? tag.children.find((c): c is SerializedTag => isTag(c) && c.attributes?.['data-name'] === 'panels')
|
|
24
|
-
: undefined);
|
|
25
|
-
</script>
|
|
26
|
-
|
|
27
|
-
{#if isGroup}
|
|
28
|
-
<div class="rf-storyboard rf-storyboard--{styleName}" style="--sb-columns: {columns};">
|
|
29
|
-
<div class="rf-storyboard__panels">
|
|
30
|
-
{#if panelsEl}
|
|
31
|
-
<Renderer node={panelsEl.children} />
|
|
32
|
-
{/if}
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
{:else}
|
|
36
|
-
<div class="rf-storyboard-panel">
|
|
37
|
-
<div class="rf-storyboard-panel__body">
|
|
38
|
-
{@render children()}
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
{/if}
|