@grove-dev/astro 0.7.0 → 0.9.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.
Files changed (110) hide show
  1. package/dist/index.d.ts +3 -3
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +22 -33
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/display.d.ts +1 -1
  6. package/dist/lib/display.js +1 -1
  7. package/dist/lib/format.d.ts +1 -1
  8. package/dist/lib/format.js +1 -1
  9. package/dist/lib/icon-kinds.d.ts +1 -1
  10. package/dist/lib/icon-kinds.js +43 -43
  11. package/dist/lib/icon-registry.d.ts +2 -2
  12. package/dist/lib/icon-registry.js +23 -23
  13. package/dist/lib/index.d.ts +9 -9
  14. package/dist/lib/index.d.ts.map +1 -1
  15. package/dist/lib/index.js +9 -9
  16. package/dist/lib/index.js.map +1 -1
  17. package/dist/lib/lenses.d.ts +1 -1
  18. package/dist/lib/lenses.js +1 -1
  19. package/dist/lib/packaged-icons.d.ts +1 -1
  20. package/dist/lib/packaged-icons.js +4 -4
  21. package/dist/lib/repo.d.ts +1 -1
  22. package/dist/lib/repo.js +1 -1
  23. package/dist/lib/search.d.ts +1 -1
  24. package/dist/lib/search.js +1 -1
  25. package/dist/lib/taxonomy-counts.d.ts +1 -1
  26. package/dist/lib/taxonomy-counts.js +1 -1
  27. package/package.json +7 -17
  28. package/src/index.ts +23 -38
  29. package/src/lib/display.ts +1 -1
  30. package/src/lib/format.ts +1 -1
  31. package/src/lib/icon-kinds.ts +44 -44
  32. package/src/lib/icon-registry.ts +25 -25
  33. package/src/lib/index.ts +9 -9
  34. package/src/lib/lenses.ts +1 -1
  35. package/src/lib/packaged-icons.ts +8 -8
  36. package/src/lib/repo.ts +1 -1
  37. package/src/lib/search.ts +1 -1
  38. package/src/lib/taxonomy-counts.ts +1 -1
  39. package/src/server/collections.ts +53 -42
  40. package/src/server/contrast.ts +14 -9
  41. package/src/server/directory.ts +22 -17
  42. package/src/server/index.ts +3 -2
  43. package/src/server/models.ts +425 -218
  44. package/src/server/seo.ts +34 -31
  45. package/src/styles.css +235 -91
  46. package/dist/layouts/index.d.ts +0 -25
  47. package/dist/layouts/index.d.ts.map +0 -1
  48. package/dist/layouts/index.js +0 -25
  49. package/dist/layouts/index.js.map +0 -1
  50. package/dist/ui/button.d.ts +0 -53
  51. package/dist/ui/button.d.ts.map +0 -1
  52. package/dist/ui/button.js +0 -90
  53. package/dist/ui/button.js.map +0 -1
  54. package/src/components/CardGrid.astro +0 -41
  55. package/src/components/CardIcon.astro +0 -67
  56. package/src/components/CategoryGrid.astro +0 -114
  57. package/src/components/CollectionCard.astro +0 -56
  58. package/src/components/CollectionIndex.astro +0 -102
  59. package/src/components/CollectionPage.astro +0 -128
  60. package/src/components/CollectionRow.astro +0 -81
  61. package/src/components/CollectionTeaser.astro +0 -47
  62. package/src/components/ContributorsGrid.astro +0 -143
  63. package/src/components/DirectoryIndexClient.astro +0 -510
  64. package/src/components/EditorialSummary.astro +0 -58
  65. package/src/components/FilterGroupMenu.astro +0 -69
  66. package/src/components/FilterOptions.astro +0 -49
  67. package/src/components/FinalCta.astro +0 -43
  68. package/src/components/Hero.astro +0 -243
  69. package/src/components/Icon.astro +0 -191
  70. package/src/components/IndexRow.astro +0 -37
  71. package/src/components/LanguageBreakdown.astro +0 -67
  72. package/src/components/MarkdownBody.astro +0 -37
  73. package/src/components/OriginalCollection.astro +0 -117
  74. package/src/components/Pagination.astro +0 -50
  75. package/src/components/PoweredBy.astro +0 -60
  76. package/src/components/ProjectCard.astro +0 -321
  77. package/src/components/RecordHeader.astro +0 -221
  78. package/src/components/RecordSection.astro +0 -128
  79. package/src/components/RecordSidebar.astro +0 -387
  80. package/src/components/RefinePanel.astro +0 -168
  81. package/src/components/SmartLensTabs.astro +0 -81
  82. package/src/components/StackGrid.astro +0 -151
  83. package/src/components/StackPlatformChips.astro +0 -73
  84. package/src/components/SubmissionClient.astro +0 -254
  85. package/src/components/TableOfContents.astro +0 -140
  86. package/src/components/WhyThisExists.astro +0 -116
  87. package/src/layouts/BaseLayout.astro +0 -415
  88. package/src/layouts/Container.astro +0 -18
  89. package/src/layouts/Footer.astro +0 -231
  90. package/src/layouts/Header.astro +0 -214
  91. package/src/layouts/SectionHeader.astro +0 -43
  92. package/src/layouts/Seo.astro +0 -171
  93. package/src/layouts/ThemeToggle.astro +0 -118
  94. package/src/layouts/astro-shim.d.ts +0 -29
  95. package/src/layouts/index.ts +0 -24
  96. package/src/server/collections.test.ts +0 -212
  97. package/src/server/contrast.test.ts +0 -82
  98. package/src/server/directory.test.ts +0 -177
  99. package/src/server/github-repo.test.ts +0 -88
  100. package/src/server/models-home.test.ts +0 -101
  101. package/src/server/models.test.ts +0 -135
  102. package/src/server/seo.test.ts +0 -123
  103. package/src/ui/Badge.astro +0 -38
  104. package/src/ui/Button.astro +0 -42
  105. package/src/ui/EmptyState.astro +0 -38
  106. package/src/ui/FilterDrawer.astro +0 -124
  107. package/src/ui/PageHeader.astro +0 -39
  108. package/src/ui/SearchField.astro +0 -106
  109. package/src/ui/button.test.ts +0 -54
  110. package/src/ui/button.ts +0 -107
package/src/server/seo.ts CHANGED
@@ -8,9 +8,9 @@
8
8
  * between pages. The pure helpers take every input as an argument —
9
9
  * no generated-data imports — so they are unit-testable in isolation.
10
10
  */
11
- import { existsSync } from "node:fs";
12
- import { resolve } from "node:path";
13
- import { breadcrumbSchema, type JsonLdNode } from "@grove-dev/core";
11
+ import { existsSync } from 'node:fs';
12
+ import { resolve } from 'node:path';
13
+ import { breadcrumbSchema, type JsonLdNode } from '@grove-dev/core';
14
14
 
15
15
  /** Everything a page passes to BaseLayout for its `<head>`. */
16
16
  export interface PageSeo {
@@ -48,11 +48,11 @@ export function seoTitle(main: string, siteName: string): string {
48
48
  * whitespace, and truncate on a word boundary near 160 chars.
49
49
  */
50
50
  export function seoDescription(raw: string | undefined, fallback: string): string {
51
- const source = (raw ?? "").replace(/\s+/g, " ").trim() || fallback.replace(/\s+/g, " ").trim();
51
+ const source = (raw ?? '').replace(/\s+/g, ' ').trim() || fallback.replace(/\s+/g, ' ').trim();
52
52
  if (source.length <= DESCRIPTION_MAX) return source;
53
53
  const cut = source.slice(0, DESCRIPTION_MAX - 1);
54
- const lastSpace = cut.lastIndexOf(" ");
55
- return `${(lastSpace > 80 ? cut.slice(0, lastSpace) : cut).replace(/[,;:\s]+$/, "")}…`;
54
+ const lastSpace = cut.lastIndexOf(' ');
55
+ return `${(lastSpace > 80 ? cut.slice(0, lastSpace) : cut).replace(/[,;:\s]+$/, '')}…`;
56
56
  }
57
57
 
58
58
  /** Capitalize the first character (for titles like "Browse Projects"). */
@@ -71,34 +71,34 @@ export function recordSeoDescriptor(input: {
71
71
  categoryLabel?: string;
72
72
  singular: string;
73
73
  }): string {
74
- const clause = (input.summary ?? "")
74
+ const clause = (input.summary ?? '')
75
75
  .split(/[.!?\n]|\s[—–]\s/)[0]
76
- ?.replace(/\s+/g, " ")
76
+ ?.replace(/\s+/g, ' ')
77
77
  .trim();
78
78
  if (clause && clause.length > 0 && clause.length <= 45) return clause;
79
79
  const category = input.categoryLabel?.trim();
80
- return category && category.toLowerCase() !== "uncategorized"
80
+ return category && category.toLowerCase() !== 'uncategorized'
81
81
  ? `Open-source ${category} ${input.singular}`
82
82
  : `Open-source ${input.singular}`;
83
83
  }
84
84
 
85
85
  export type OgKind =
86
- | "home"
87
- | "default"
88
- | "record"
89
- | "collection"
90
- | "category"
91
- | "stack"
92
- | "license";
86
+ | 'home'
87
+ | 'default'
88
+ | 'record'
89
+ | 'collection'
90
+ | 'category'
91
+ | 'stack'
92
+ | 'license';
93
93
 
94
94
  const OG_DIR: Record<OgKind, string> = {
95
- home: "home.png",
96
- default: "default.png",
97
- record: "records",
98
- collection: "collections",
99
- category: "categories",
100
- stack: "stacks",
101
- license: "licenses",
95
+ home: 'home.png',
96
+ default: 'default.png',
97
+ record: 'records',
98
+ collection: 'collections',
99
+ category: 'categories',
100
+ stack: 'stacks',
101
+ license: 'licenses',
102
102
  };
103
103
 
104
104
  /**
@@ -109,22 +109,22 @@ const OG_DIR: Record<OgKind, string> = {
109
109
  */
110
110
  export function ogPath(kind: OgKind, slug?: string, cwd = process.cwd()): string {
111
111
  const rel =
112
- kind === "home" || kind === "default"
112
+ kind === 'home' || kind === 'default'
113
113
  ? `og/${OG_DIR[kind]}`
114
114
  : slug
115
115
  ? `og/${OG_DIR[kind]}/${slug}.png`
116
- : "og/default.png";
117
- if (existsSync(resolve(cwd, "public", rel))) return `/${rel}`;
116
+ : 'og/default.png';
117
+ if (existsSync(resolve(cwd, 'public', rel))) return `/${rel}`;
118
118
  // Per-page image missing — try the generated default before the SVG.
119
- if (rel !== "og/default.png" && existsSync(resolve(cwd, "public", "og/default.png"))) {
120
- return "/og/default.png";
119
+ if (rel !== 'og/default.png' && existsSync(resolve(cwd, 'public', 'og/default.png'))) {
120
+ return '/og/default.png';
121
121
  }
122
- return "/og-image.svg";
122
+ return '/og-image.svg';
123
123
  }
124
124
 
125
125
  /** Join a site-relative path onto the site URL (trailing-slash safe). */
126
126
  export function absoluteUrl(siteUrl: string, path: string): string {
127
- return `${siteUrl.replace(/\/$/, "")}/${path.replace(/^\//, "")}`;
127
+ return `${siteUrl.replace(/\/$/, '')}/${path.replace(/^\//, '')}`;
128
128
  }
129
129
 
130
130
  /**
@@ -136,6 +136,9 @@ export function breadcrumbs(
136
136
  crumbs: Array<{ path: string; name: string }>,
137
137
  ): JsonLdNode {
138
138
  return breadcrumbSchema(
139
- crumbs.map((c) => ({ url: absoluteUrl(siteUrl, c.path.endsWith("/") || c.path === "" ? c.path : `${c.path}/`), name: c.name })),
139
+ crumbs.map((c) => ({
140
+ url: absoluteUrl(siteUrl, c.path.endsWith('/') || c.path === '' ? c.path : `${c.path}/`),
141
+ name: c.name,
142
+ })),
140
143
  );
141
144
  }
package/src/styles.css CHANGED
@@ -128,11 +128,12 @@
128
128
  --color-amber-950: oklch(40.8% 0.123 38.172);
129
129
 
130
130
  /* ── Font stacks ─────────────────────────────────────────────── */
131
- --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
132
- "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji",
133
- "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
134
- --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
135
- "Liberation Mono", "Courier New", monospace;
131
+ --font-sans:
132
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial,
133
+ sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
134
+ --font-mono:
135
+ ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
136
+ monospace;
136
137
 
137
138
  /* ── Starlight typography weight/rhythm ──────────────────────── */
138
139
  --font-weight-semibold: 500;
@@ -499,9 +500,15 @@
499
500
  overflow-wrap: break-word;
500
501
  word-wrap: break-word;
501
502
  }
502
- .dark .grove-prose { color: var(--color-ink-200, #d4d4d4); }
503
- .grove-prose > :first-child { margin-top: 0; }
504
- .grove-prose > :last-child { margin-bottom: 0; }
503
+ .dark .grove-prose {
504
+ color: var(--color-ink-200, #d4d4d4);
505
+ }
506
+ .grove-prose > :first-child {
507
+ margin-top: 0;
508
+ }
509
+ .grove-prose > :last-child {
510
+ margin-bottom: 0;
511
+ }
505
512
 
506
513
  /* Headings — full depth. */
507
514
  .grove-prose :where(h1, h2, h3, h4, h5, h6) {
@@ -517,74 +524,113 @@
517
524
  /* Page bodies open with a `# <Page name>` heading that duplicates
518
525
  the page title. Hide the first heading so the body flows from a
519
526
  top-level paragraph into sections. */
520
- .grove-prose > h1:first-child { display: none; }
527
+ .grove-prose > h1:first-child {
528
+ display: none;
529
+ }
521
530
  .grove-prose h1:not(:first-child) {
522
- font-size: 2.5rem; /* 40px */
523
- margin-top: 2.5rem; margin-bottom: 1rem;
531
+ font-size: 2.5rem; /* 40px */
532
+ margin-top: 2.5rem;
533
+ margin-bottom: 1rem;
524
534
  }
525
535
  .grove-prose h2 {
526
- font-size: 1.75rem; /* 28px */
527
- margin-top: 2.5rem; margin-bottom: 0.75rem;
536
+ font-size: 1.75rem; /* 28px */
537
+ margin-top: 2.5rem;
538
+ margin-bottom: 0.75rem;
528
539
  padding-bottom: 0.5rem;
529
540
  border-bottom: 1px solid var(--color-ink-200, #e5e5e5);
530
541
  }
531
- .dark .grove-prose h2 { border-bottom-color: var(--color-ink-800, #2a2a2a); }
542
+ .dark .grove-prose h2 {
543
+ border-bottom-color: var(--color-ink-800, #2a2a2a);
544
+ }
532
545
  .grove-prose h3 {
533
- font-size: 1.3125rem; /* 21px */
534
- margin-top: 2rem; margin-bottom: 0.5rem;
546
+ font-size: 1.3125rem; /* 21px */
547
+ margin-top: 2rem;
548
+ margin-bottom: 0.5rem;
535
549
  }
536
550
  .grove-prose h4 {
537
- font-size: 1.0625rem; /* 17px */
538
- margin-top: 1.5rem; margin-bottom: 0.4rem;
551
+ font-size: 1.0625rem; /* 17px */
552
+ margin-top: 1.5rem;
553
+ margin-bottom: 0.4rem;
539
554
  }
540
555
  .grove-prose h5 {
541
- font-size: 0.9375rem; /* 15px */
542
- margin-top: 1.25rem; margin-bottom: 0.4rem;
556
+ font-size: 0.9375rem; /* 15px */
557
+ margin-top: 1.25rem;
558
+ margin-bottom: 0.4rem;
543
559
  text-transform: uppercase;
544
560
  letter-spacing: 0.04em;
545
561
  color: var(--color-ink-600, #555555);
546
562
  }
547
563
  .grove-prose h6 {
548
- font-size: 0.875rem; /* 14px */
549
- margin-top: 1rem; margin-bottom: 0.35rem;
564
+ font-size: 0.875rem; /* 14px */
565
+ margin-top: 1rem;
566
+ margin-bottom: 0.35rem;
550
567
  text-transform: uppercase;
551
568
  letter-spacing: 0.06em;
552
569
  color: var(--color-ink-500, #6a6a6a);
553
570
  }
554
- .dark .grove-prose h5 { color: var(--color-ink-400, #8a8a8a); }
555
- .dark .grove-prose h6 { color: var(--color-ink-500, #6a6a6a); }
571
+ .dark .grove-prose h5 {
572
+ color: var(--color-ink-400, #8a8a8a);
573
+ }
574
+ .dark .grove-prose h6 {
575
+ color: var(--color-ink-500, #6a6a6a);
576
+ }
556
577
 
557
578
  /* Paragraphs + lists. */
558
- .grove-prose p { margin: 0 0 1rem 0; }
579
+ .grove-prose p {
580
+ margin: 0 0 1rem 0;
581
+ }
559
582
  .grove-prose :where(ul, ol) {
560
583
  margin: 0 0 1rem 0;
561
584
  padding-left: 1.5rem;
562
585
  }
563
- .grove-prose ul { list-style: disc; }
564
- .grove-prose ol { list-style: decimal; }
565
- .grove-prose li { margin-bottom: 0.35rem; padding-left: 0.25rem; }
586
+ .grove-prose ul {
587
+ list-style: disc;
588
+ }
589
+ .grove-prose ol {
590
+ list-style: decimal;
591
+ }
592
+ .grove-prose li {
593
+ margin-bottom: 0.35rem;
594
+ padding-left: 0.25rem;
595
+ }
566
596
  .grove-prose li > :where(ul, ol) {
567
- margin-top: 0.35rem; margin-bottom: 0;
597
+ margin-top: 0.35rem;
598
+ margin-bottom: 0;
568
599
  }
569
600
 
570
601
  /* Definition lists. */
571
- .grove-prose dl { margin: 0 0 1rem 0; }
602
+ .grove-prose dl {
603
+ margin: 0 0 1rem 0;
604
+ }
572
605
  .grove-prose dt {
573
606
  font-weight: 600;
574
607
  color: var(--color-ink-900, #1a1a1a);
575
608
  margin-top: 0.5rem;
576
609
  }
577
610
  .grove-prose dd {
578
- margin-left: 1.5rem; margin-bottom: 0.5rem;
611
+ margin-left: 1.5rem;
612
+ margin-bottom: 0.5rem;
579
613
  color: var(--color-ink-700, #3a3a3a);
580
614
  }
581
- .dark .grove-prose dt { color: var(--color-ink-100, #f0f0f0); }
582
- .dark .grove-prose dd { color: var(--color-ink-200, #d4d4d4); }
615
+ .dark .grove-prose dt {
616
+ color: var(--color-ink-100, #f0f0f0);
617
+ }
618
+ .dark .grove-prose dd {
619
+ color: var(--color-ink-200, #d4d4d4);
620
+ }
583
621
 
584
622
  /* Inline emphasis. */
585
- .grove-prose strong { font-weight: 600; color: var(--color-ink-900, #1a1a1a); }
586
- .grove-prose em { font-style: italic; }
587
- .grove-prose u { text-decoration: underline; text-underline-offset: 2px; }
623
+ .grove-prose strong {
624
+ font-weight: 600;
625
+ color: var(--color-ink-900, #1a1a1a);
626
+ }
627
+ .grove-prose em {
628
+ font-style: italic;
629
+ }
630
+ .grove-prose u {
631
+ text-decoration: underline;
632
+ text-underline-offset: 2px;
633
+ }
588
634
  .grove-prose :where(s, del) {
589
635
  text-decoration: line-through;
590
636
  color: var(--color-ink-500, #6a6a6a);
@@ -598,8 +644,12 @@
598
644
  font-size: 0.85em;
599
645
  color: var(--color-ink-500, #6a6a6a);
600
646
  }
601
- .dark .grove-prose strong { color: var(--color-ink-100, #f0f0f0); }
602
- .dark .grove-prose small { color: var(--color-ink-400, #8a8a8a); }
647
+ .dark .grove-prose strong {
648
+ color: var(--color-ink-100, #f0f0f0);
649
+ }
650
+ .dark .grove-prose small {
651
+ color: var(--color-ink-400, #8a8a8a);
652
+ }
603
653
 
604
654
  /* Inline marks / keys / abbreviations. */
605
655
  .grove-prose mark {
@@ -638,12 +688,20 @@
638
688
  cursor: help;
639
689
  }
640
690
  .grove-prose :where(sub, sup) {
641
- font-size: 0.75em; line-height: 1;
642
- position: relative; vertical-align: baseline;
691
+ font-size: 0.75em;
692
+ line-height: 1;
693
+ position: relative;
694
+ vertical-align: baseline;
695
+ }
696
+ .grove-prose sub {
697
+ bottom: -0.25em;
698
+ }
699
+ .grove-prose sup {
700
+ top: -0.5em;
701
+ }
702
+ .grove-prose time {
703
+ font-variant-numeric: tabular-nums;
643
704
  }
644
- .grove-prose sub { bottom: -0.25em; }
645
- .grove-prose sup { top: -0.5em; }
646
- .grove-prose time { font-variant-numeric: tabular-nums; }
647
705
 
648
706
  /* Links. */
649
707
  .grove-prose a {
@@ -724,9 +782,15 @@
724
782
  color: var(--shiki-dark, var(--color-ink-100, #f0f0f0));
725
783
  border-color: var(--color-ink-800, #2a2a2a);
726
784
  }
727
- .grove-prose pre.shiki code { color: inherit; }
728
- .grove-prose pre.shiki span { color: var(--shiki-light); }
729
- .dark .grove-prose pre.shiki span { color: var(--shiki-dark); }
785
+ .grove-prose pre.shiki code {
786
+ color: inherit;
787
+ }
788
+ .grove-prose pre.shiki span {
789
+ color: var(--shiki-light);
790
+ }
791
+ .dark .grove-prose pre.shiki span {
792
+ color: var(--shiki-dark);
793
+ }
730
794
 
731
795
  /* Blockquotes — italic + left border + background tint. */
732
796
  .grove-prose blockquote {
@@ -738,9 +802,15 @@
738
802
  background-color: var(--color-ink-50, #fafafa);
739
803
  border-radius: 0 0.4rem 0.4rem 0;
740
804
  }
741
- .grove-prose blockquote > :first-child { margin-top: 0; }
742
- .grove-prose blockquote > :last-child { margin-bottom: 0; }
743
- .grove-prose blockquote p { margin: 0 0 0.5rem 0; }
805
+ .grove-prose blockquote > :first-child {
806
+ margin-top: 0;
807
+ }
808
+ .grove-prose blockquote > :last-child {
809
+ margin-bottom: 0;
810
+ }
811
+ .grove-prose blockquote p {
812
+ margin: 0 0 0.5rem 0;
813
+ }
744
814
  .grove-prose blockquote blockquote {
745
815
  margin: 0.5rem 0;
746
816
  border-left-width: 2px;
@@ -757,7 +827,9 @@
757
827
  border-top: 1px solid var(--color-ink-200, #e5e5e5);
758
828
  margin: 2.25rem 0;
759
829
  }
760
- .dark .grove-prose hr { border-top-color: var(--color-ink-800, #2a2a2a); }
830
+ .dark .grove-prose hr {
831
+ border-top-color: var(--color-ink-800, #2a2a2a);
832
+ }
761
833
 
762
834
  /* Images — rounded border, full column width. */
763
835
  .grove-prose img {
@@ -768,18 +840,27 @@
768
840
  display: block;
769
841
  margin: 1.25rem 0;
770
842
  }
771
- .dark .grove-prose img { border-color: var(--color-ink-800, #2a2a2a); }
843
+ .dark .grove-prose img {
844
+ border-color: var(--color-ink-800, #2a2a2a);
845
+ }
772
846
 
773
847
  /* Figures + captions. */
774
- .grove-prose figure { margin: 1.25rem 0; padding: 0; }
775
- .grove-prose figure > img { margin: 0 0 0.5rem 0; }
848
+ .grove-prose figure {
849
+ margin: 1.25rem 0;
850
+ padding: 0;
851
+ }
852
+ .grove-prose figure > img {
853
+ margin: 0 0 0.5rem 0;
854
+ }
776
855
  .grove-prose figcaption {
777
856
  font-size: 0.85rem;
778
857
  color: var(--color-ink-500, #6a6a6a);
779
858
  text-align: center;
780
859
  margin-top: 0.4rem;
781
860
  }
782
- .dark .grove-prose figcaption { color: var(--color-ink-400, #8a8a8a); }
861
+ .dark .grove-prose figcaption {
862
+ color: var(--color-ink-400, #8a8a8a);
863
+ }
783
864
 
784
865
  /* GFM tables — the renderer wraps them in `.grove-prose-table-wrap`
785
866
  so the column-width overflow is contained. */
@@ -790,7 +871,9 @@
790
871
  border: 1px solid var(--color-ink-200, #e5e5e5);
791
872
  background-color: var(--grove-background, #ffffff);
792
873
  }
793
- .dark .grove-prose-table-wrap { border-color: var(--color-ink-800, #2a2a2a); }
874
+ .dark .grove-prose-table-wrap {
875
+ border-color: var(--color-ink-800, #2a2a2a);
876
+ }
794
877
  .grove-prose table {
795
878
  width: 100%;
796
879
  border-collapse: collapse;
@@ -825,25 +908,45 @@
825
908
  color: var(--color-ink-700, #3a3a3a);
826
909
  vertical-align: top;
827
910
  }
828
- .grove-prose th[align="center"], .grove-prose td[align="center"] { text-align: center; }
829
- .grove-prose th[align="right"], .grove-prose td[align="right"] { text-align: right; }
830
- .grove-prose tbody tr:last-child td { border-bottom: 0; }
831
- .grove-prose tbody tr:hover { background-color: var(--color-ink-50, #fafafa); }
832
- .dark .grove-prose th { color: var(--color-ink-100, #f0f0f0); border-bottom-color: var(--color-ink-700, #4a4a4a); }
833
- .dark .grove-prose td { color: var(--color-ink-200, #d4d4d4); border-bottom-color: var(--color-ink-800, #2a2a2a); }
834
- .dark .grove-prose tbody tr:hover { background-color: var(--color-ink-900, #1a1a1a); }
911
+ .grove-prose th[align="center"],
912
+ .grove-prose td[align="center"] {
913
+ text-align: center;
914
+ }
915
+ .grove-prose th[align="right"],
916
+ .grove-prose td[align="right"] {
917
+ text-align: right;
918
+ }
919
+ .grove-prose tbody tr:last-child td {
920
+ border-bottom: 0;
921
+ }
922
+ .grove-prose tbody tr:hover {
923
+ background-color: var(--color-ink-50, #fafafa);
924
+ }
925
+ .dark .grove-prose th {
926
+ color: var(--color-ink-100, #f0f0f0);
927
+ border-bottom-color: var(--color-ink-700, #4a4a4a);
928
+ }
929
+ .dark .grove-prose td {
930
+ color: var(--color-ink-200, #d4d4d4);
931
+ border-bottom-color: var(--color-ink-800, #2a2a2a);
932
+ }
933
+ .dark .grove-prose tbody tr:hover {
934
+ background-color: var(--color-ink-900, #1a1a1a);
935
+ }
835
936
 
836
937
  /* GFM task-list checkboxes — read-only at runtime. */
837
938
  .grove-prose input[type="checkbox"] {
838
939
  appearance: none;
839
940
  -webkit-appearance: none;
840
- width: 1em; height: 1em;
941
+ width: 1em;
942
+ height: 1em;
841
943
  border: 1.5px solid var(--color-ink-400, #999999);
842
944
  border-radius: 0.25rem;
843
945
  margin-right: 0.45rem;
844
946
  margin-top: 0.15rem;
845
947
  vertical-align: middle;
846
- position: relative; top: -0.05em;
948
+ position: relative;
949
+ top: -0.05em;
847
950
  background-color: var(--grove-background, #ffffff);
848
951
  cursor: default;
849
952
  flex-shrink: 0;
@@ -855,13 +958,17 @@
855
958
  .grove-prose input[type="checkbox"]:checked::after {
856
959
  content: "";
857
960
  position: absolute;
858
- left: 4px; top: 1px;
859
- width: 4px; height: 8px;
961
+ left: 4px;
962
+ top: 1px;
963
+ width: 4px;
964
+ height: 8px;
860
965
  border: solid var(--grove-background, #ffffff);
861
966
  border-width: 0 2px 2px 0;
862
967
  transform: rotate(45deg);
863
968
  }
864
- .grove-prose input[type="checkbox"]:disabled { opacity: 0.7; }
969
+ .grove-prose input[type="checkbox"]:disabled {
970
+ opacity: 0.7;
971
+ }
865
972
  .dark .grove-prose input[type="checkbox"] {
866
973
  border-color: var(--color-ink-600, #555555);
867
974
  background-color: var(--grove-background, #1a1a1a);
@@ -876,11 +983,13 @@
876
983
  .grove-prose li:has(> input[type="checkbox"]) {
877
984
  list-style: none;
878
985
  margin-left: -1.25rem;
879
- display: flex; align-items: flex-start;
986
+ display: flex;
987
+ align-items: flex-start;
880
988
  gap: 0.15rem;
881
989
  }
882
990
  .grove-prose li:has(> input[type="checkbox"]) > input[type="checkbox"] {
883
- margin-right: 0.55rem; margin-left: 0.15rem;
991
+ margin-right: 0.55rem;
992
+ margin-left: 0.15rem;
884
993
  }
885
994
 
886
995
  /* Collapsibles (details / summary). */
@@ -891,13 +1000,19 @@
891
1000
  background-color: var(--color-ink-50, #fafafa);
892
1001
  overflow: hidden;
893
1002
  }
894
- .grove-prose details[open] { background-color: var(--grove-background, #ffffff); }
895
- .grove-prose details + details { margin-top: -0.5rem; }
1003
+ .grove-prose details[open] {
1004
+ background-color: var(--grove-background, #ffffff);
1005
+ }
1006
+ .grove-prose details + details {
1007
+ margin-top: -0.5rem;
1008
+ }
896
1009
  .dark .grove-prose details {
897
1010
  border-color: var(--color-ink-800, #2a2a2a);
898
1011
  background-color: var(--color-ink-900, #1a1a1a);
899
1012
  }
900
- .dark .grove-prose details[open] { background-color: var(--grove-background, #1a1a1a); }
1013
+ .dark .grove-prose details[open] {
1014
+ background-color: var(--grove-background, #1a1a1a);
1015
+ }
901
1016
  .grove-prose summary {
902
1017
  cursor: pointer;
903
1018
  padding: 0.75rem 1rem;
@@ -905,26 +1020,45 @@
905
1020
  color: var(--color-ink-900, #1a1a1a);
906
1021
  list-style: none;
907
1022
  user-select: none;
908
- display: flex; align-items: center; gap: 0.5rem;
1023
+ display: flex;
1024
+ align-items: center;
1025
+ gap: 0.5rem;
909
1026
  transition: background-color 120ms ease;
910
1027
  }
911
- .grove-prose summary::-webkit-details-marker { display: none; }
1028
+ .grove-prose summary::-webkit-details-marker {
1029
+ display: none;
1030
+ }
912
1031
  .grove-prose summary::before {
913
1032
  content: "";
914
- width: 0; height: 0;
1033
+ width: 0;
1034
+ height: 0;
915
1035
  border-style: solid;
916
1036
  border-width: 0.35rem 0 0.35rem 0.55rem;
917
1037
  border-color: transparent transparent transparent var(--color-ink-500, #6a6a6a);
918
1038
  transition: transform 120ms ease;
919
1039
  flex-shrink: 0;
920
1040
  }
921
- .grove-prose details[open] > summary::before { transform: rotate(90deg); }
922
- .grove-prose summary:hover { background-color: var(--color-ink-100, #f0f0f0); }
923
- .grove-prose summary strong { font-weight: inherit; }
924
- .dark .grove-prose summary { color: var(--color-ink-100, #f0f0f0); }
925
- .dark .grove-prose summary:hover { background-color: var(--color-ink-800, #2a2a2a); }
926
- .grove-prose details > :not(summary) { padding: 0 1rem 1rem 1rem; }
927
- .grove-prose details > :not(summary):first-of-type { padding-top: 0; }
1041
+ .grove-prose details[open] > summary::before {
1042
+ transform: rotate(90deg);
1043
+ }
1044
+ .grove-prose summary:hover {
1045
+ background-color: var(--color-ink-100, #f0f0f0);
1046
+ }
1047
+ .grove-prose summary strong {
1048
+ font-weight: inherit;
1049
+ }
1050
+ .dark .grove-prose summary {
1051
+ color: var(--color-ink-100, #f0f0f0);
1052
+ }
1053
+ .dark .grove-prose summary:hover {
1054
+ background-color: var(--color-ink-800, #2a2a2a);
1055
+ }
1056
+ .grove-prose details > :not(summary) {
1057
+ padding: 0 1rem 1rem 1rem;
1058
+ }
1059
+ .grove-prose details > :not(summary):first-of-type {
1060
+ padding-top: 0;
1061
+ }
928
1062
 
929
1063
  /* ──────────────────────────────────────────────────────────────────
930
1064
  * On-page TOC component (`.grove-toc-*`)
@@ -932,9 +1066,13 @@
932
1066
  * is set imperatively by the TableOfContents script via
933
1067
  * `[data-toc-active]` on the matching anchor.
934
1068
  * ────────────────────────────────────────────────────────────────── */
935
- .grove-toc summary { color: inherit; }
1069
+ .grove-toc summary {
1070
+ color: inherit;
1071
+ }
936
1072
  .grove-toc[open] .grove-toc-chevron,
937
- .grove-toc > summary:hover .grove-toc-chevron { transform: rotate(90deg); }
1073
+ .grove-toc > summary:hover .grove-toc-chevron {
1074
+ transform: rotate(90deg);
1075
+ }
938
1076
  /* Desktop (lg+): keep the TOC contents visible even before the
939
1077
  * component script sets the `open` attribute (and with JS disabled).
940
1078
  * Closed `<details>` content lives in a hidden UA shadow slot, so
@@ -1006,22 +1144,22 @@
1006
1144
  color: oklch(40% 0.13 40);
1007
1145
  }
1008
1146
  .dark [data-activity-tone="fresh"] {
1009
- border-color: oklch(35% 0.10 154);
1147
+ border-color: oklch(35% 0.1 154);
1010
1148
  background-color: oklch(20% 0.05 156);
1011
1149
  color: oklch(85% 0.15 154);
1012
1150
  }
1013
1151
  .dark [data-activity-tone="ok"] {
1014
- border-color: oklch(30% 0.10 230);
1152
+ border-color: oklch(30% 0.1 230);
1015
1153
  background-color: oklch(20% 0.05 255);
1016
1154
  color: oklch(80% 0.13 230);
1017
1155
  }
1018
1156
  .dark [data-activity-tone="low"] {
1019
- border-color: oklch(35% 0.10 60);
1157
+ border-color: oklch(35% 0.1 60);
1020
1158
  background-color: oklch(20% 0.05 74);
1021
1159
  color: oklch(85% 0.13 70);
1022
1160
  }
1023
1161
  .dark [data-activity-tone="dead"] {
1024
- border-color: oklch(35% 0.10 40);
1162
+ border-color: oklch(35% 0.1 40);
1025
1163
  background-color: oklch(20% 0.05 40);
1026
1164
  color: oklch(85% 0.13 40);
1027
1165
  }
@@ -1031,6 +1169,12 @@
1031
1169
  * Static selector (no dynamic class concatenation) — Tailwind ships
1032
1170
  * the CSS because the class string appears literally here.
1033
1171
  * ────────────────────────────────────────────────────────────────── */
1034
- .grove-kv div { line-height: 1.4; }
1035
- .grove-card-title { letter-spacing: 0.04em; }
1036
- .grove-card--muted { background-color: color-mix(in oklab, var(--grove-background) 60%, transparent); }
1172
+ .grove-kv div {
1173
+ line-height: 1.4;
1174
+ }
1175
+ .grove-card-title {
1176
+ letter-spacing: 0.04em;
1177
+ }
1178
+ .grove-card--muted {
1179
+ background-color: color-mix(in oklab, var(--grove-background) 60%, transparent);
1180
+ }
@@ -1,25 +0,0 @@
1
- /**
2
- * @grove-dev/astro — generic layout components.
3
- *
4
- * These layouts are the public, framework-agnostic shell used by
5
- * every consumer page. They:
6
- *
7
- * - take a `site` prop (name, tagline, nav, repoUrl) instead of
8
- * importing a `siteConfig` from a project-local path;
9
- * - compose the standard Header / Footer / Seo / Container /
10
- * SectionHeader / ThemeToggle components;
11
- * - share the `grove-theme` localStorage key for theme state.
12
- *
13
- * Re-exported as ESM module names. Astro resolves the
14
- * `@grove-dev/astro/layouts/*` subpath import from `src/layouts/`
15
- * (the package's `dist/` only contains TypeScript helpers, not the
16
- * `.astro` files themselves).
17
- */
18
- export { default as BaseLayout } from "./BaseLayout.astro";
19
- export { default as Container } from "./Container.astro";
20
- export { default as Footer } from "./Footer.astro";
21
- export { default as Header } from "./Header.astro";
22
- export { default as SectionHeader } from "./SectionHeader.astro";
23
- export { default as Seo } from "./Seo.astro";
24
- export { default as ThemeToggle } from "./ThemeToggle.astro";
25
- //# sourceMappingURL=index.d.ts.map