@refrakt-md/lumina 0.5.1 → 0.7.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.
@@ -0,0 +1,80 @@
1
+ /* Plot */
2
+ .rf-plot {
3
+ border: 1px solid var(--rf-color-border);
4
+ border-radius: var(--rf-radius-lg);
5
+ padding: 2rem;
6
+ margin: 1.5rem 0;
7
+ }
8
+ .rf-plot > span[property="title"] {
9
+ display: block;
10
+ font-size: 1.5rem;
11
+ font-weight: 700;
12
+ margin-bottom: 1rem;
13
+ color: var(--rf-color-heading);
14
+ }
15
+ .rf-plot ol {
16
+ list-style: none;
17
+ padding-left: 0;
18
+ margin: 0;
19
+ position: relative;
20
+ }
21
+ .rf-plot--linear ol {
22
+ border-left: 2px solid var(--rf-color-border);
23
+ padding-left: 1.5rem;
24
+ }
25
+
26
+ /* Beat */
27
+ .rf-beat {
28
+ position: relative;
29
+ padding: 0.75rem 0;
30
+ }
31
+ .rf-beat::before {
32
+ content: '';
33
+ position: absolute;
34
+ left: -1.75rem;
35
+ top: 1rem;
36
+ width: 0.75rem;
37
+ height: 0.75rem;
38
+ border-radius: var(--rf-radius-full);
39
+ background: var(--rf-color-border);
40
+ border: 2px solid var(--rf-color-bg);
41
+ }
42
+ .rf-beat > span[property="label"] {
43
+ font-weight: 600;
44
+ font-size: 1rem;
45
+ color: var(--rf-color-heading);
46
+ }
47
+ .rf-beat__body {
48
+ margin-top: 0.25rem;
49
+ font-size: 0.9375rem;
50
+ color: var(--rf-color-text);
51
+ }
52
+
53
+ /* Beat status variants */
54
+ .rf-beat--complete::before {
55
+ background: var(--rf-color-success);
56
+ }
57
+ .rf-beat--complete > span[property="label"] {
58
+ color: var(--rf-color-muted);
59
+ }
60
+
61
+ .rf-beat--active::before {
62
+ background: var(--rf-color-primary);
63
+ box-shadow: 0 0 0 3px var(--rf-color-primary-bg);
64
+ }
65
+ .rf-beat--active > span[property="label"] {
66
+ color: var(--rf-color-primary);
67
+ }
68
+
69
+ .rf-beat--planned::before {
70
+ background: var(--rf-color-muted-bg);
71
+ border-color: var(--rf-color-border);
72
+ }
73
+
74
+ .rf-beat--abandoned > span[property="label"] {
75
+ text-decoration: line-through;
76
+ color: var(--rf-color-muted);
77
+ }
78
+ .rf-beat--abandoned::before {
79
+ background: var(--rf-color-muted);
80
+ }
@@ -0,0 +1,108 @@
1
+ /* PullQuote */
2
+ .rf-pullquote {
3
+ margin: 2rem 0;
4
+ padding: 1.5rem 2rem;
5
+ border: none;
6
+ font-size: 1.375rem;
7
+ font-style: italic;
8
+ font-weight: 500;
9
+ line-height: 1.5;
10
+ color: var(--rf-color-text);
11
+ background: none;
12
+ position: relative;
13
+ }
14
+ .rf-pullquote::before {
15
+ content: '\201C';
16
+ position: absolute;
17
+ top: -0.25rem;
18
+ left: 0;
19
+ font-size: 4rem;
20
+ font-style: normal;
21
+ font-weight: 700;
22
+ line-height: 1;
23
+ color: var(--rf-color-primary);
24
+ opacity: 0.3;
25
+ }
26
+ .rf-pullquote p {
27
+ margin: 0;
28
+ }
29
+ .rf-pullquote p + p {
30
+ margin-top: 0.75rem;
31
+ }
32
+
33
+ /* Alignment — block modes */
34
+ .rf-pullquote--center {
35
+ text-align: center;
36
+ max-width: 80%;
37
+ margin-left: auto;
38
+ margin-right: auto;
39
+ }
40
+ .rf-pullquote--center::before {
41
+ left: 50%;
42
+ transform: translateX(-50%);
43
+ }
44
+ .rf-pullquote--left {
45
+ text-align: left;
46
+ border-left: 4px solid var(--rf-color-primary);
47
+ padding-left: 1.5rem;
48
+ }
49
+ .rf-pullquote--left::before {
50
+ display: none;
51
+ }
52
+ .rf-pullquote--right {
53
+ text-align: right;
54
+ border-right: 4px solid var(--rf-color-primary);
55
+ padding-right: 1.5rem;
56
+ margin-left: auto;
57
+ }
58
+ .rf-pullquote--right::before {
59
+ display: none;
60
+ }
61
+
62
+ /* Float modes — left/right pull quotes can float for text wrapping */
63
+ .rf-pullquote[data-align="left"] {
64
+ float: left;
65
+ width: 40%;
66
+ margin: 0.5rem 2rem 1rem 0;
67
+ }
68
+ .rf-pullquote[data-align="right"] {
69
+ float: right;
70
+ width: 40%;
71
+ margin: 0.5rem 0 1rem 2rem;
72
+ }
73
+
74
+ /* Style: accent — uses primary color background tint */
75
+ .rf-pullquote--accent {
76
+ background: color-mix(in srgb, var(--rf-color-primary) 8%, transparent);
77
+ border-radius: var(--rf-radius-lg);
78
+ padding: 2rem 2.5rem;
79
+ }
80
+ .rf-pullquote--accent::before {
81
+ color: var(--rf-color-primary);
82
+ opacity: 0.5;
83
+ }
84
+
85
+ /* Style: editorial — decorative top/bottom rules */
86
+ .rf-pullquote--editorial {
87
+ border-top: 3px solid var(--rf-color-text);
88
+ border-bottom: 3px solid var(--rf-color-text);
89
+ padding: 1.5rem 0;
90
+ font-family: Georgia, 'Times New Roman', serif;
91
+ letter-spacing: 0.01em;
92
+ }
93
+ .rf-pullquote--editorial::before {
94
+ display: none;
95
+ }
96
+
97
+ /* Responsive — floated quotes become full-width on mobile */
98
+ @media (max-width: 768px) {
99
+ .rf-pullquote[data-align="left"],
100
+ .rf-pullquote[data-align="right"] {
101
+ float: none;
102
+ width: 100%;
103
+ margin: 1.5rem 0;
104
+ }
105
+ .rf-pullquote--center {
106
+ max-width: 100%;
107
+ }
108
+ }
@@ -0,0 +1,82 @@
1
+ /* Realm */
2
+ .rf-realm {
3
+ border: 1px solid var(--rf-color-border);
4
+ border-radius: var(--rf-radius-lg);
5
+ padding: 2rem;
6
+ margin: 1.5rem 0;
7
+ }
8
+ .rf-realm__badge {
9
+ display: flex;
10
+ flex-wrap: wrap;
11
+ gap: 0.5rem;
12
+ margin-bottom: 1rem;
13
+ }
14
+ .rf-realm__type-badge {
15
+ display: inline-block;
16
+ padding: 0.25rem 0.75rem;
17
+ border-radius: var(--rf-radius-full);
18
+ font-size: 0.75rem;
19
+ font-weight: 600;
20
+ text-transform: uppercase;
21
+ letter-spacing: 0.05em;
22
+ background: var(--rf-color-muted-bg);
23
+ color: var(--rf-color-muted);
24
+ }
25
+ .rf-realm__scale-badge {
26
+ display: inline-block;
27
+ padding: 0.25rem 0.75rem;
28
+ border-radius: var(--rf-radius-full);
29
+ font-size: 0.75rem;
30
+ font-weight: 600;
31
+ text-transform: uppercase;
32
+ letter-spacing: 0.05em;
33
+ background: var(--rf-color-muted-bg);
34
+ color: var(--rf-color-muted);
35
+ }
36
+ .rf-realm__scene {
37
+ width: 100%;
38
+ margin-bottom: 1rem;
39
+ border-radius: var(--rf-radius-md);
40
+ overflow: hidden;
41
+ aspect-ratio: 16 / 9;
42
+ }
43
+ .rf-realm__scene img {
44
+ width: 100%;
45
+ height: 100%;
46
+ object-fit: cover;
47
+ }
48
+ .rf-realm__sections {
49
+ display: flex;
50
+ flex-direction: column;
51
+ gap: 1rem;
52
+ }
53
+ .rf-realm__content {
54
+ /* content wrapper */
55
+ }
56
+ .rf-realm__content ul,
57
+ .rf-realm__content ol {
58
+ padding-left: 1.5rem;
59
+ }
60
+ .rf-realm > span[property="name"] {
61
+ display: block;
62
+ font-size: 1.5rem;
63
+ font-weight: 700;
64
+ margin-bottom: 0.5rem;
65
+ color: var(--rf-color-heading);
66
+ }
67
+
68
+ /* Realm Section */
69
+ .rf-realm-section {
70
+ padding: 0.75rem 0;
71
+ border-top: 1px solid var(--rf-color-border);
72
+ }
73
+ .rf-realm-section__header {
74
+ font-size: 1.125rem;
75
+ font-weight: 600;
76
+ margin-bottom: 0.5rem;
77
+ color: var(--rf-color-heading);
78
+ }
79
+ .rf-realm-section__body ul,
80
+ .rf-realm-section__body ol {
81
+ padding-left: 1.5rem;
82
+ }
@@ -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.75rem 1.25rem;
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: 1.25rem;
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: 1rem;
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,64 @@
1
+ /* TextBlock */
2
+ .rf-textblock {
3
+ margin: 1.5rem 0;
4
+ }
5
+ .rf-textblock__body {
6
+ display: block;
7
+ }
8
+
9
+ /* Drop cap — decorative first letter */
10
+ .rf-textblock--dropcap .rf-textblock__body > p:first-child::first-letter {
11
+ float: left;
12
+ font-size: 3.5em;
13
+ font-weight: 700;
14
+ line-height: 0.8;
15
+ padding-right: 0.1em;
16
+ margin-top: 0.05em;
17
+ color: var(--rf-color-primary);
18
+ font-family: Georgia, 'Times New Roman', serif;
19
+ }
20
+
21
+ /* Lead paragraph — emphasized opening text */
22
+ .rf-textblock--lead .rf-textblock__body > p:first-child {
23
+ font-size: 1.25rem;
24
+ line-height: 1.6;
25
+ font-weight: 400;
26
+ color: var(--rf-color-text);
27
+ }
28
+
29
+ /* Multi-column text flow */
30
+ .rf-textblock[data-columns="2"] .rf-textblock__body {
31
+ column-count: 2;
32
+ column-gap: 2rem;
33
+ column-rule: 1px solid var(--rf-color-border);
34
+ }
35
+ .rf-textblock[data-columns="3"] .rf-textblock__body {
36
+ column-count: 3;
37
+ column-gap: 2rem;
38
+ column-rule: 1px solid var(--rf-color-border);
39
+ }
40
+ .rf-textblock[data-columns="4"] .rf-textblock__body {
41
+ column-count: 4;
42
+ column-gap: 2rem;
43
+ column-rule: 1px solid var(--rf-color-border);
44
+ }
45
+
46
+ /* Text alignment */
47
+ .rf-textblock--center .rf-textblock__body { text-align: center; }
48
+ .rf-textblock--right .rf-textblock__body { text-align: right; }
49
+ .rf-textblock--justify .rf-textblock__body { text-align: justify; }
50
+
51
+ /* Responsive — columns collapse on smaller screens */
52
+ @media (max-width: 768px) {
53
+ .rf-textblock[data-columns="3"] .rf-textblock__body,
54
+ .rf-textblock[data-columns="4"] .rf-textblock__body {
55
+ column-count: 2;
56
+ }
57
+ }
58
+ @media (max-width: 480px) {
59
+ .rf-textblock[data-columns="2"] .rf-textblock__body,
60
+ .rf-textblock[data-columns="3"] .rf-textblock__body,
61
+ .rf-textblock[data-columns="4"] .rf-textblock__body {
62
+ column-count: 1;
63
+ }
64
+ }
@@ -1 +1 @@
1
- export { elements } from '@refrakt-md/theme-base/svelte/elements';
1
+ export { elements } from '@refrakt-md/svelte';
package/svelte/index.ts CHANGED
@@ -1,24 +1,37 @@
1
1
  import type { SvelteTheme } from '@refrakt-md/svelte';
2
- import manifest from './manifest.json';
2
+ import adapterManifest from './manifest.json';
3
3
  import { registry } from './registry.js';
4
4
  import { elements } from './elements.js';
5
- import DocsLayout from './layouts/DocsLayout.svelte';
6
- import DefaultLayout from './layouts/DefaultLayout.svelte';
7
- import BlogLayout from './layouts/BlogLayout.svelte';
5
+ import { defaultLayout, docsLayout, blogArticleLayout } from '@refrakt-md/transform';
8
6
 
9
- /** Re-export the raw manifest for server-side use (no Svelte imports) */
10
- export { default as manifest } from './manifest.json';
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: { default: DefaultLayout, docs: DocsLayout, blog: BlogLayout },
28
+ layouts: {
29
+ default: defaultLayout,
30
+ docs: docsLayout,
31
+ 'blog-article': blogArticleLayout,
32
+ },
16
33
  components: registry,
17
34
  elements,
18
35
  };
19
36
 
20
- // Backward-compatible named exports
21
37
  export { registry };
22
- export { default as DocsLayout } from './layouts/DocsLayout.svelte';
23
- export { default as DefaultLayout } from './layouts/DefaultLayout.svelte';
24
- export { default as BlogLayout } from './layouts/BlogLayout.svelte';
@@ -6,46 +6,12 @@
6
6
  "designTokens": "tokens.css",
7
7
 
8
8
  "layouts": {
9
- "default": {
10
- "component": "layouts/DefaultLayout.svelte",
11
- "regions": ["header", "footer"]
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": {},
10
+ "docs": {},
11
+ "blog": {}
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
- "components": {
32
- "Hint": { "component": "components/Hint.svelte" },
33
- "CallToAction": { "component": "components/CallToAction.svelte" },
34
- "Feature": { "component": "components/Feature.svelte" },
35
- "FeatureDefinition": { "component": "components/Feature.svelte" },
36
- "Grid": { "component": "components/Grid.svelte" },
37
- "Steps": { "component": "components/Steps.svelte" },
38
- "Step": { "component": "components/Steps.svelte" },
39
- "TabGroup": { "component": "components/Tabs.svelte" },
40
- "Tab": { "component": "components/Tabs.svelte" },
41
- "CodeGroup": { "component": "components/CodeGroup.svelte" },
42
- "Pricing": { "component": "components/Pricing.svelte" },
43
- "Tier": { "component": "components/Pricing.svelte" },
44
- "PageSection": { "component": "components/PageSection.svelte" },
45
- "Nav": { "component": "components/Nav.svelte" },
46
- "NavGroup": { "component": "components/Nav.svelte" },
47
- "NavItem": { "component": "components/Nav.svelte" }
48
- },
14
+ "components": {},
49
15
 
50
16
  "unsupportedRuneBehavior": "passthrough"
51
17
  }
@@ -1,2 +1,2 @@
1
1
  // Re-export base registry — lumina uses the same interactive components
2
- export { registry } from '@refrakt-md/theme-base/svelte/registry';
2
+ export { registry } from '@refrakt-md/svelte';
@@ -1,173 +0,0 @@
1
- <script lang="ts">
2
- import { Renderer } from '@refrakt-md/svelte';
3
-
4
- let { title, frontmatter, regions, renderable, pages, url }: {
5
- title: string;
6
- description: string;
7
- frontmatter?: Record<string, unknown>;
8
- regions: Record<string, { name: string; mode: string; content: any[] }>;
9
- renderable: any;
10
- pages: Array<{
11
- url: string;
12
- title: string;
13
- draft: boolean;
14
- description?: string;
15
- date?: string;
16
- author?: string;
17
- tags?: string[];
18
- image?: string;
19
- }>;
20
- url: string;
21
- } = $props();
22
-
23
- const date = $derived(frontmatter?.date as string | undefined);
24
- const author = $derived(frontmatter?.author as string | undefined);
25
- const tags = $derived(frontmatter?.tags as string[] | undefined);
26
-
27
- // Index page has no date; individual posts always have one
28
- const isIndex = $derived(!date);
29
-
30
- const posts = $derived(
31
- isIndex
32
- ? pages
33
- .filter(p => p.url.startsWith('/blog/') && p.url !== '/blog' && !p.draft && p.date)
34
- .sort((a, b) => (b.date ?? '').localeCompare(a.date ?? ''))
35
- : []
36
- );
37
-
38
- const hasSidebar = $derived(!!regions.sidebar);
39
-
40
- let menuOpen = $state(false);
41
-
42
- function onKeydown(e: KeyboardEvent) {
43
- if (e.key === 'Escape') menuOpen = false;
44
- }
45
-
46
- $effect(() => {
47
- url;
48
- menuOpen = false;
49
- });
50
-
51
- // Lock body scroll when panel is open
52
- $effect(() => {
53
- document.body.style.overflow = menuOpen ? 'hidden' : '';
54
- });
55
-
56
- function formatDate(iso: string): string {
57
- const d = new Date(iso + 'T00:00:00');
58
- return d.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
59
- }
60
- </script>
61
-
62
- <svelte:window onkeydown={onKeydown} />
63
-
64
- {#if regions.header}
65
- <header class="rf-blog-header">
66
- <div class="rf-blog-header__inner">
67
- <Renderer node={regions.header.content} />
68
- <button class="rf-mobile-menu-btn" onclick={() => menuOpen = true} aria-label="Open menu">
69
- <svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor">
70
- <circle cx="10" cy="4" r="1.5"/>
71
- <circle cx="10" cy="10" r="1.5"/>
72
- <circle cx="10" cy="16" r="1.5"/>
73
- </svg>
74
- </button>
75
- </div>
76
- </header>
77
- {/if}
78
-
79
- {#if menuOpen}
80
- <div class="rf-mobile-panel" role="dialog" aria-label="Navigation menu">
81
- <div class="rf-mobile-panel__header">
82
- <span class="rf-mobile-panel__title">Menu</span>
83
- <button class="rf-mobile-panel__close" onclick={() => menuOpen = false} aria-label="Close menu">
84
- <svg width="20" height="20" viewBox="0 0 20 20" stroke="currentColor" stroke-width="2" fill="none">
85
- <line x1="4" y1="4" x2="16" y2="16"/><line x1="16" y1="4" x2="4" y2="16"/>
86
- </svg>
87
- </button>
88
- </div>
89
- <nav class="rf-mobile-panel__nav">
90
- {#if regions.header}
91
- <Renderer node={regions.header.content} />
92
- {/if}
93
- </nav>
94
- </div>
95
- {/if}
96
-
97
- <div class="rf-blog" class:rf-blog--has-sidebar={hasSidebar}>
98
- {#if isIndex}
99
- <div class="rf-blog-index">
100
- <h1 class="rf-blog-index__title">{title}</h1>
101
-
102
- <div class="rf-blog-index__body">
103
- <Renderer node={renderable} />
104
- </div>
105
-
106
- <div class="rf-blog-index__posts">
107
- {#each posts as post}
108
- <a href={post.url} class="rf-blog-card">
109
- <h2 class="rf-blog-card__title">{post.title}</h2>
110
- <div class="rf-blog-card__meta">
111
- {#if post.date}
112
- <time datetime={post.date}>{formatDate(post.date)}</time>
113
- {/if}
114
- {#if post.author}
115
- <span class="rf-blog-card__author">{post.author}</span>
116
- {/if}
117
- </div>
118
- {#if post.description}
119
- <p class="rf-blog-card__desc">{post.description}</p>
120
- {/if}
121
- {#if post.tags && post.tags.length > 0}
122
- <div class="rf-blog-card__tags">
123
- {#each post.tags as tag}
124
- <span class="rf-blog-article__tag">{tag}</span>
125
- {/each}
126
- </div>
127
- {/if}
128
- <span class="rf-blog-card__link">Read more &rarr;</span>
129
- </a>
130
- {/each}
131
- </div>
132
- </div>
133
- {:else}
134
- <article class="rf-blog-article">
135
- <header class="rf-blog-article__header">
136
- <h1 class="rf-blog-article__title">{title}</h1>
137
- {#if date || author}
138
- <div class="rf-blog-article__meta">
139
- {#if date}
140
- <time datetime={date}>{formatDate(date)}</time>
141
- {/if}
142
- {#if author}
143
- <span class="rf-blog-article__author">{author}</span>
144
- {/if}
145
- </div>
146
- {/if}
147
- {#if tags && tags.length > 0}
148
- <div class="rf-blog-article__tags">
149
- {#each tags as tag}
150
- <span class="rf-blog-article__tag">{tag}</span>
151
- {/each}
152
- </div>
153
- {/if}
154
- </header>
155
-
156
- <div class="rf-blog-article__body">
157
- <Renderer node={renderable} />
158
- </div>
159
- </article>
160
-
161
- {#if regions.sidebar}
162
- <aside class="rf-blog-sidebar">
163
- <Renderer node={regions.sidebar.content} />
164
- </aside>
165
- {/if}
166
- {/if}
167
- </div>
168
-
169
- {#if regions.footer}
170
- <footer class="rf-blog-footer">
171
- <Renderer node={regions.footer.content} />
172
- </footer>
173
- {/if}