@karaoke-cms/theme-default 0.9.0 → 0.9.3
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/package.json +8 -5
- package/src/components/AudienceGrid.astro +143 -0
- package/src/components/CtaSection.astro +91 -0
- package/src/components/FeatureGrid.astro +138 -0
- package/src/components/Hero.astro +141 -0
- package/src/components/HowItWorks.astro +117 -0
- package/src/components/InstallBox.astro +71 -0
- package/src/components/MetaphorSection.astro +69 -0
- package/src/components/ScaleSection.astro +146 -0
- package/src/index.ts +53 -6
- package/src/pages/404.astro +3 -3
- package/src/pages/docs/[slug].astro +3 -3
- package/src/pages/docs/index.astro +3 -3
- package/src/pages/index.astro +18 -60
- package/src/pages/tags/[tag].astro +3 -3
- package/src/pages/tags/index.astro +3 -3
- package/src/styles/blog.css +9 -0
- package/src/styles.css +153 -20
- package/src/pages/blog/[slug].astro +0 -66
- package/src/pages/blog/index.astro +0 -31
package/src/styles.css
CHANGED
|
@@ -30,6 +30,20 @@
|
|
|
30
30
|
--spacing-xl: 4rem;
|
|
31
31
|
|
|
32
32
|
--radius-sm: 4px;
|
|
33
|
+
--radius-lg: 12px;
|
|
34
|
+
|
|
35
|
+
/* Landing / marketing palette */
|
|
36
|
+
--color-accent: #6366f1;
|
|
37
|
+
--color-accent-2: #8b5cf6;
|
|
38
|
+
--color-bg-alt: #f8fafc;
|
|
39
|
+
|
|
40
|
+
/* Dark-section backgrounds — intentionally always dark */
|
|
41
|
+
--color-section-dark: #0f172a;
|
|
42
|
+
--color-section-dark-2: #1e293b;
|
|
43
|
+
--color-on-dark: #e2e8f0;
|
|
44
|
+
--color-on-dark-2: #d0dae6;
|
|
45
|
+
|
|
46
|
+
--width-landing: 1100px;
|
|
33
47
|
}
|
|
34
48
|
|
|
35
49
|
@media (prefers-color-scheme: dark) {
|
|
@@ -41,6 +55,7 @@
|
|
|
41
55
|
--color-link: #60a5fa;
|
|
42
56
|
--color-link-hover: #93c5fd;
|
|
43
57
|
--color-link-visited: #a78bfa;
|
|
58
|
+
--color-bg-alt: #1a1a1a;
|
|
44
59
|
}
|
|
45
60
|
}
|
|
46
61
|
|
|
@@ -63,17 +78,23 @@ body {
|
|
|
63
78
|
/* --- Header --- */
|
|
64
79
|
|
|
65
80
|
header {
|
|
66
|
-
|
|
81
|
+
position: sticky;
|
|
82
|
+
top: 0;
|
|
83
|
+
z-index: 100;
|
|
84
|
+
background: rgba(15, 23, 42, 0.92);
|
|
85
|
+
backdrop-filter: blur(12px);
|
|
86
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
|
67
87
|
margin-bottom: var(--spacing-xl);
|
|
68
88
|
}
|
|
69
89
|
|
|
70
90
|
.header-inner {
|
|
71
|
-
max-width: var(--width-
|
|
91
|
+
max-width: var(--width-landing);
|
|
72
92
|
margin: 0 auto;
|
|
73
93
|
padding: 0 var(--spacing-md);
|
|
74
94
|
display: flex;
|
|
75
95
|
align-items: center;
|
|
76
|
-
|
|
96
|
+
justify-content: space-between;
|
|
97
|
+
height: 3.5rem;
|
|
77
98
|
gap: var(--spacing-md);
|
|
78
99
|
}
|
|
79
100
|
|
|
@@ -81,13 +102,13 @@ header {
|
|
|
81
102
|
font-weight: 700;
|
|
82
103
|
font-size: 1rem;
|
|
83
104
|
text-decoration: none;
|
|
84
|
-
color: var(--color-
|
|
105
|
+
color: var(--color-on-dark);
|
|
85
106
|
flex-shrink: 0;
|
|
86
107
|
letter-spacing: -0.01em;
|
|
87
108
|
}
|
|
88
109
|
|
|
89
110
|
.site-name:hover {
|
|
90
|
-
color:
|
|
111
|
+
color: #fff;
|
|
91
112
|
}
|
|
92
113
|
|
|
93
114
|
header nav {
|
|
@@ -104,18 +125,18 @@ header nav ul {
|
|
|
104
125
|
|
|
105
126
|
header nav ul a {
|
|
106
127
|
text-decoration: none;
|
|
107
|
-
color:
|
|
128
|
+
color: #94a3b8;
|
|
108
129
|
font-size: var(--font-size-sm);
|
|
109
130
|
padding: var(--spacing-xs) 0;
|
|
110
131
|
min-height: 44px;
|
|
111
132
|
display: flex;
|
|
112
133
|
align-items: center;
|
|
113
|
-
transition: color 0.
|
|
134
|
+
transition: color 0.15s;
|
|
114
135
|
}
|
|
115
136
|
|
|
116
137
|
header nav ul a:hover,
|
|
117
138
|
header nav ul a[aria-current="page"] {
|
|
118
|
-
color: var(--color-
|
|
139
|
+
color: var(--color-on-dark);
|
|
119
140
|
}
|
|
120
141
|
|
|
121
142
|
/* --- Page body (left + main + right regions) --- */
|
|
@@ -194,33 +215,84 @@ main {
|
|
|
194
215
|
/* --- Footer --- */
|
|
195
216
|
|
|
196
217
|
footer {
|
|
197
|
-
|
|
218
|
+
background: var(--color-section-dark);
|
|
219
|
+
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
|
198
220
|
margin-top: var(--spacing-xl);
|
|
199
221
|
}
|
|
200
222
|
|
|
201
223
|
.footer-inner {
|
|
202
224
|
max-width: var(--width-site);
|
|
203
225
|
margin: 0 auto;
|
|
204
|
-
padding:
|
|
226
|
+
padding: 0 var(--spacing-md);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.footer-grid {
|
|
230
|
+
display: grid;
|
|
231
|
+
grid-template-columns: repeat(4, 1fr);
|
|
232
|
+
gap: var(--spacing-lg);
|
|
233
|
+
padding: var(--spacing-xl) 0 var(--spacing-lg);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.footer-col {
|
|
237
|
+
min-width: 0;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.footer-brand {
|
|
241
|
+
font-weight: 700;
|
|
242
|
+
font-size: var(--font-size-sm);
|
|
243
|
+
color: var(--color-on-dark);
|
|
244
|
+
margin: 0 0 var(--spacing-sm);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.footer-tagline {
|
|
248
|
+
font-size: var(--font-size-sm);
|
|
249
|
+
color: var(--color-on-dark-2);
|
|
250
|
+
margin: 0;
|
|
251
|
+
line-height: var(--line-height-body);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.footer-below {
|
|
255
|
+
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
|
256
|
+
padding: var(--spacing-md) 0;
|
|
205
257
|
display: flex;
|
|
206
258
|
align-items: center;
|
|
207
259
|
justify-content: space-between;
|
|
208
260
|
gap: var(--spacing-md);
|
|
209
|
-
color: var(--color-muted);
|
|
210
261
|
font-size: var(--font-size-sm);
|
|
262
|
+
color: var(--color-on-dark-2);
|
|
211
263
|
}
|
|
212
264
|
|
|
213
265
|
.footer-attr {
|
|
214
|
-
|
|
266
|
+
flex-shrink: 0;
|
|
215
267
|
}
|
|
216
268
|
|
|
217
269
|
footer a {
|
|
218
|
-
color: var(--color-
|
|
270
|
+
color: var(--color-on-dark-2);
|
|
219
271
|
text-decoration: none;
|
|
220
272
|
}
|
|
221
273
|
|
|
222
274
|
footer a:hover {
|
|
223
|
-
color: var(--color-
|
|
275
|
+
color: var(--color-on-dark);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* Footer vertical menu — top-level entry as column heading */
|
|
279
|
+
.footer-col nav.karaoke-menu > ul > li > a {
|
|
280
|
+
font-size: var(--font-size-sm);
|
|
281
|
+
font-weight: 600;
|
|
282
|
+
color: var(--color-on-dark);
|
|
283
|
+
display: block;
|
|
284
|
+
padding-bottom: var(--spacing-xs);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.footer-col nav.karaoke-menu > ul > li > ul a {
|
|
288
|
+
font-size: var(--font-size-sm);
|
|
289
|
+
color: #94a3b8;
|
|
290
|
+
display: block;
|
|
291
|
+
padding: 2px 0;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.footer-col nav.karaoke-menu > ul > li > ul a:hover {
|
|
295
|
+
color: var(--color-on-dark);
|
|
224
296
|
}
|
|
225
297
|
|
|
226
298
|
/* --- Typography --- */
|
|
@@ -378,14 +450,16 @@ pre code {
|
|
|
378
450
|
width: 100%;
|
|
379
451
|
}
|
|
380
452
|
|
|
381
|
-
.footer-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
453
|
+
.footer-grid {
|
|
454
|
+
grid-template-columns: 1fr 1fr;
|
|
455
|
+
gap: var(--spacing-md);
|
|
456
|
+
padding: var(--spacing-lg) 0 var(--spacing-md);
|
|
385
457
|
}
|
|
386
458
|
|
|
387
|
-
.footer-
|
|
388
|
-
|
|
459
|
+
.footer-below {
|
|
460
|
+
flex-direction: column;
|
|
461
|
+
align-items: flex-start;
|
|
462
|
+
gap: var(--spacing-xs);
|
|
389
463
|
}
|
|
390
464
|
}
|
|
391
465
|
|
|
@@ -531,3 +605,62 @@ nav.karaoke-menu[data-orientation="vertical"] > ul {
|
|
|
531
605
|
nav.karaoke-menu[data-orientation="vertical"] li ul {
|
|
532
606
|
padding-left: var(--spacing-md, 1rem);
|
|
533
607
|
}
|
|
608
|
+
|
|
609
|
+
/* ── Site icon ───────────────────────────────────────────────────────── */
|
|
610
|
+
|
|
611
|
+
.site-icon {
|
|
612
|
+
font-size: 1.1em;
|
|
613
|
+
margin-right: 0.3em;
|
|
614
|
+
vertical-align: -0.05em;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/* ── Header CTA button ──────────────────────────────────────────────── */
|
|
618
|
+
|
|
619
|
+
.btn-cta {
|
|
620
|
+
font-size: var(--font-size-sm);
|
|
621
|
+
font-weight: 600;
|
|
622
|
+
color: #fff;
|
|
623
|
+
background: var(--color-accent);
|
|
624
|
+
padding: 5px 14px;
|
|
625
|
+
border-radius: 999px;
|
|
626
|
+
text-decoration: none;
|
|
627
|
+
transition: opacity 0.15s;
|
|
628
|
+
flex-shrink: 0;
|
|
629
|
+
white-space: nowrap;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.btn-cta:hover,
|
|
633
|
+
.btn-cta:visited {
|
|
634
|
+
opacity: 0.85;
|
|
635
|
+
color: #fff;
|
|
636
|
+
text-decoration: none;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/* ── Landing layout ─────────────────────────────────────────────────── */
|
|
640
|
+
|
|
641
|
+
main.landing-main {
|
|
642
|
+
width: 100%;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
.landing-container {
|
|
647
|
+
max-width: var(--width-landing);
|
|
648
|
+
margin: 0 auto;
|
|
649
|
+
padding: 0 24px;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/* ── Section label (uppercase eyebrow) ──────────────────────────────── */
|
|
653
|
+
|
|
654
|
+
.section-label {
|
|
655
|
+
display: inline-block;
|
|
656
|
+
font-size: 0.75rem;
|
|
657
|
+
font-weight: 700;
|
|
658
|
+
letter-spacing: 0.1em;
|
|
659
|
+
text-transform: uppercase;
|
|
660
|
+
color: var(--color-accent);
|
|
661
|
+
margin-bottom: 12px;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.section-label.on-dark {
|
|
665
|
+
color: #818cf8;
|
|
666
|
+
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { getCollection, render } from 'astro:content';
|
|
3
|
-
import Base from '@karaoke-cms/astro/layouts/Base.astro';
|
|
4
|
-
import ModuleLoader from '@karaoke-cms/astro/components/ModuleLoader.astro';
|
|
5
|
-
import { siteTitle } from 'virtual:karaoke-cms/config';
|
|
6
|
-
|
|
7
|
-
export async function getStaticPaths() {
|
|
8
|
-
const posts = await getCollection('blog', ({ data }) => data.publish === true);
|
|
9
|
-
return posts.map(entry => ({
|
|
10
|
-
params: { slug: entry.id },
|
|
11
|
-
props: { entry },
|
|
12
|
-
}));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const { entry } = Astro.props;
|
|
16
|
-
const { Content } = await render(entry);
|
|
17
|
-
|
|
18
|
-
// Resolve related entries by ID across both collections
|
|
19
|
-
const relatedIds = entry.data.related ?? [];
|
|
20
|
-
const related = relatedIds.length > 0
|
|
21
|
-
? (await Promise.all([
|
|
22
|
-
getCollection('blog', ({ data }) => data.publish === true),
|
|
23
|
-
getCollection('docs', ({ data }) => data.publish === true),
|
|
24
|
-
]))
|
|
25
|
-
.flat()
|
|
26
|
-
.filter(e => relatedIds.includes(e.id))
|
|
27
|
-
: [];
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
<Base title={`${entry.data.title} — ${siteTitle}`} description={entry.data.description} type="article">
|
|
31
|
-
<article>
|
|
32
|
-
<div class="post-header">
|
|
33
|
-
<h1>{entry.data.title}</h1>
|
|
34
|
-
<div class="post-meta">
|
|
35
|
-
{entry.data.date && <span>{entry.data.date.toISOString().slice(0, 10)}</span>}
|
|
36
|
-
{entry.data.author && entry.data.date && <span> · </span>}
|
|
37
|
-
{entry.data.author && (
|
|
38
|
-
<span>{Array.isArray(entry.data.author) ? entry.data.author.join(' · ') : entry.data.author}</span>
|
|
39
|
-
)}
|
|
40
|
-
{entry.data.reading_time && <span> · {entry.data.reading_time} min read</span>}
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
<div class="prose">
|
|
44
|
-
<Content />
|
|
45
|
-
</div>
|
|
46
|
-
<div class="post-footer">
|
|
47
|
-
{entry.data.tags && entry.data.tags.length > 0 && (
|
|
48
|
-
<div class="post-tags">
|
|
49
|
-
{entry.data.tags.map(tag => <a href={`/tags/${tag}`} class="tag">#{tag}</a>)}
|
|
50
|
-
</div>
|
|
51
|
-
)}
|
|
52
|
-
{related.length > 0 && (
|
|
53
|
-
<div class="related-posts">
|
|
54
|
-
<p class="related-label">Related</p>
|
|
55
|
-
<ul>
|
|
56
|
-
{related.map(r => (
|
|
57
|
-
<li><a href={`/${r.collection}/${r.id}`}>{r.data.title}</a></li>
|
|
58
|
-
))}
|
|
59
|
-
</ul>
|
|
60
|
-
</div>
|
|
61
|
-
)}
|
|
62
|
-
<a href="/blog">← Blog</a>
|
|
63
|
-
</div>
|
|
64
|
-
</article>
|
|
65
|
-
<ModuleLoader comments={entry.data.comments} />
|
|
66
|
-
</Base>
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { getCollection } from 'astro:content';
|
|
3
|
-
import Base from '@karaoke-cms/astro/layouts/Base.astro';
|
|
4
|
-
import { siteTitle } from 'virtual:karaoke-cms/config';
|
|
5
|
-
|
|
6
|
-
const posts = (await getCollection('blog', ({ data }) => data.publish === true))
|
|
7
|
-
.sort((a, b) => (b.data.date?.valueOf() ?? 0) - (a.data.date?.valueOf() ?? 0));
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
<Base title={`Blog — ${siteTitle}`}>
|
|
11
|
-
<div class="listing-header">
|
|
12
|
-
<h1>Blog</h1>
|
|
13
|
-
</div>
|
|
14
|
-
{posts.length > 0 ? (
|
|
15
|
-
<ul class="post-list">
|
|
16
|
-
{posts.map(post => (
|
|
17
|
-
<li>
|
|
18
|
-
{post.data.date && (
|
|
19
|
-
<span class="post-date">{post.data.date.toISOString().slice(0, 10)}</span>
|
|
20
|
-
)}
|
|
21
|
-
<a href={`/blog/${post.id}`}>{post.data.title}</a>
|
|
22
|
-
</li>
|
|
23
|
-
))}
|
|
24
|
-
</ul>
|
|
25
|
-
) : (
|
|
26
|
-
<div class="empty-state">
|
|
27
|
-
<p>No posts published yet.</p>
|
|
28
|
-
<p>Create a Markdown file in your vault's <code>blog/</code> folder and set <code>publish: true</code> in the frontmatter to make it appear here.</p>
|
|
29
|
-
</div>
|
|
30
|
-
)}
|
|
31
|
-
</Base>
|