@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/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
- border-bottom: 2px solid var(--color-border);
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-site);
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
- height: 3.25rem;
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-text);
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: var(--color-link);
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: var(--color-muted);
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.1s;
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-text);
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
- border-top: 1px solid var(--color-border);
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: var(--spacing-lg) var(--spacing-md);
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
- margin-left: auto;
266
+ flex-shrink: 0;
215
267
  }
216
268
 
217
269
  footer a {
218
- color: var(--color-muted);
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-link);
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-inner {
382
- flex-direction: column;
383
- align-items: flex-start;
384
- gap: var(--spacing-sm);
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-attr {
388
- margin-left: 0;
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>