@autumnsgrove/groveengine 0.8.6 → 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 (80) hide show
  1. package/dist/components/admin/GutterManager.svelte +213 -101
  2. package/dist/components/admin/MarkdownEditor.svelte +6 -3
  3. package/dist/components/custom/GutterItem.svelte +8 -2
  4. package/dist/components/quota/UpgradePrompt.svelte +1 -0
  5. package/dist/config/domain-blocklist.d.ts +59 -0
  6. package/dist/config/domain-blocklist.js +731 -0
  7. package/dist/config/index.d.ts +3 -1
  8. package/dist/config/index.js +2 -1
  9. package/dist/config/offensive-blocklist.d.ts +44 -0
  10. package/dist/config/offensive-blocklist.js +751 -0
  11. package/dist/config/terrarium.d.ts +109 -0
  12. package/dist/config/terrarium.js +125 -0
  13. package/dist/styles/tokens.css +90 -0
  14. package/dist/types/dom-to-image-more.d.ts +39 -0
  15. package/dist/ui/components/chrome/Footer.svelte +137 -0
  16. package/dist/ui/components/chrome/Footer.svelte.d.ts +11 -0
  17. package/dist/ui/components/chrome/FooterMinimal.svelte +75 -0
  18. package/dist/ui/components/chrome/FooterMinimal.svelte.d.ts +10 -0
  19. package/dist/ui/components/chrome/Header.svelte +113 -0
  20. package/dist/ui/components/chrome/Header.svelte.d.ts +11 -0
  21. package/dist/ui/components/chrome/HeaderMinimal.svelte +68 -0
  22. package/dist/ui/components/chrome/HeaderMinimal.svelte.d.ts +9 -0
  23. package/dist/ui/components/chrome/MobileMenu.svelte +145 -0
  24. package/dist/ui/components/chrome/MobileMenu.svelte.d.ts +9 -0
  25. package/dist/ui/components/chrome/ThemeToggle.svelte +34 -0
  26. package/dist/ui/components/chrome/ThemeToggle.svelte.d.ts +3 -0
  27. package/dist/ui/components/chrome/defaults.d.ts +6 -0
  28. package/dist/ui/components/chrome/defaults.js +65 -0
  29. package/dist/ui/components/chrome/index.d.ts +13 -0
  30. package/dist/ui/components/chrome/index.js +14 -0
  31. package/dist/ui/components/chrome/types.d.ts +19 -0
  32. package/dist/ui/components/chrome/types.js +8 -0
  33. package/dist/ui/components/content/RoadmapPreview.svelte +2 -1
  34. package/dist/ui/components/forms/ContentSearch.svelte +406 -0
  35. package/dist/ui/components/forms/ContentSearch.svelte.d.ts +71 -0
  36. package/dist/ui/components/forms/filterUtils.d.ts +138 -0
  37. package/dist/ui/components/forms/filterUtils.js +240 -0
  38. package/dist/ui/components/forms/index.d.ts +2 -0
  39. package/dist/ui/components/forms/index.js +5 -1
  40. package/dist/ui/components/gallery/ImageGallery.svelte +3 -0
  41. package/dist/ui/components/gallery/Lightbox.svelte +3 -0
  42. package/dist/ui/components/gallery/ZoomableImage.svelte +1 -0
  43. package/dist/ui/components/icons/index.d.ts +2 -1
  44. package/dist/ui/components/icons/index.js +14 -3
  45. package/dist/ui/components/icons/lucide.d.ts +213 -0
  46. package/dist/ui/components/icons/lucide.js +224 -0
  47. package/dist/ui/components/terrarium/AssetPalette.svelte +207 -0
  48. package/dist/ui/components/terrarium/AssetPalette.svelte.d.ts +7 -0
  49. package/dist/ui/components/terrarium/Canvas.svelte +231 -0
  50. package/dist/ui/components/terrarium/Canvas.svelte.d.ts +14 -0
  51. package/dist/ui/components/terrarium/ExportDialog.svelte +307 -0
  52. package/dist/ui/components/terrarium/ExportDialog.svelte.d.ts +18 -0
  53. package/dist/ui/components/terrarium/PaletteItem.svelte +169 -0
  54. package/dist/ui/components/terrarium/PaletteItem.svelte.d.ts +9 -0
  55. package/dist/ui/components/terrarium/PlacedAsset.svelte +222 -0
  56. package/dist/ui/components/terrarium/PlacedAsset.svelte.d.ts +11 -0
  57. package/dist/ui/components/terrarium/Terrarium.svelte +266 -0
  58. package/dist/ui/components/terrarium/Terrarium.svelte.d.ts +3 -0
  59. package/dist/ui/components/terrarium/Toolbar.svelte +299 -0
  60. package/dist/ui/components/terrarium/Toolbar.svelte.d.ts +24 -0
  61. package/dist/ui/components/terrarium/index.d.ts +31 -0
  62. package/dist/ui/components/terrarium/index.js +33 -0
  63. package/dist/ui/components/terrarium/terrariumState.svelte.d.ts +45 -0
  64. package/dist/ui/components/terrarium/terrariumState.svelte.js +291 -0
  65. package/dist/ui/components/terrarium/types.d.ts +139 -0
  66. package/dist/ui/components/terrarium/types.js +43 -0
  67. package/dist/ui/components/terrarium/utils/export.d.ts +48 -0
  68. package/dist/ui/components/terrarium/utils/export.js +148 -0
  69. package/dist/ui/components/ui/CollapsibleSection.svelte +2 -0
  70. package/dist/ui/components/ui/GlassConfirmDialog.svelte +9 -0
  71. package/dist/ui/components/ui/GlassOverlay.svelte +2 -1
  72. package/dist/ui/components/ui/Input.svelte +9 -1
  73. package/dist/ui/components/ui/Input.svelte.d.ts +2 -0
  74. package/dist/ui/components/ui/Textarea.svelte +9 -1
  75. package/dist/ui/components/ui/Textarea.svelte.d.ts +2 -0
  76. package/dist/ui/stores/index.d.ts +6 -0
  77. package/dist/ui/stores/index.js +6 -0
  78. package/dist/ui/stores/season.d.ts +14 -0
  79. package/dist/ui/stores/season.js +65 -0
  80. package/package.json +27 -4
@@ -0,0 +1,113 @@
1
+ <script lang="ts">
2
+ import { page } from '$app/stores';
3
+ import { Logo } from '../nature';
4
+ import ThemeToggle from './ThemeToggle.svelte';
5
+ import MobileMenu from './MobileMenu.svelte';
6
+ import { seasonStore } from '../../stores/season';
7
+ import { Menu } from 'lucide-svelte';
8
+ import type { NavItem, MaxWidth, Season } from './types';
9
+ import { isActivePath } from './types';
10
+ import { DEFAULT_NAV_ITEMS } from './defaults';
11
+
12
+ // Determine current page for highlighting
13
+ let currentPath = $derived($page.url.pathname);
14
+
15
+ interface Props {
16
+ navItems?: NavItem[];
17
+ maxWidth?: MaxWidth;
18
+ brandTitle?: string;
19
+ season?: Season;
20
+ onSeasonChange?: () => void;
21
+ }
22
+
23
+ let {
24
+ navItems,
25
+ maxWidth = 'default',
26
+ brandTitle,
27
+ season,
28
+ onSeasonChange
29
+ }: Props = $props();
30
+
31
+ const maxWidthClass = {
32
+ narrow: 'max-w-3xl',
33
+ default: 'max-w-4xl',
34
+ wide: 'max-w-5xl'
35
+ };
36
+
37
+ // Mobile menu state
38
+ let mobileMenuOpen = $state(false);
39
+
40
+ // Toggle season on logo click
41
+ function handleLogoClick() {
42
+ if (onSeasonChange) {
43
+ onSeasonChange();
44
+ } else {
45
+ seasonStore.cycle();
46
+ }
47
+ }
48
+
49
+ const items = navItems || DEFAULT_NAV_ITEMS;
50
+ </script>
51
+
52
+ <header class="sticky top-0 z-40 py-6 px-6 border-b border-default bg-surface/95 backdrop-blur-sm">
53
+ <div class="{maxWidthClass[maxWidth]} mx-auto flex items-center justify-between">
54
+ <!-- Logo area -->
55
+ <div class="flex items-center gap-2">
56
+ <!-- Logo icon - clickable to toggle season -->
57
+ <button
58
+ onclick={handleLogoClick}
59
+ class="flex-shrink-0 transition-transform hover:scale-110 active:scale-95"
60
+ aria-label="Toggle season theme"
61
+ title="Click to change season"
62
+ >
63
+ <Logo class="w-6 h-6" season={season || $seasonStore} />
64
+ </button>
65
+
66
+ <!-- Brand title or "Grove" text - home link, hidden on mobile -->
67
+ {#if brandTitle}
68
+ <span class="hidden sm:block text-xl font-serif text-foreground">
69
+ {brandTitle}
70
+ </span>
71
+ {:else}
72
+ <a
73
+ href="/"
74
+ class="hidden sm:block text-xl font-serif text-foreground hover:text-accent-muted transition-colors"
75
+ >
76
+ Grove
77
+ </a>
78
+ {/if}
79
+ </div>
80
+
81
+ <!-- Desktop navigation -->
82
+ <nav class="hidden md:flex items-center gap-4 lg:gap-6 text-sm font-sans">
83
+ {#each items as item}
84
+ <a
85
+ href={item.href}
86
+ target={item.external ? '_blank' : undefined}
87
+ rel={item.external ? 'noopener noreferrer' : undefined}
88
+ class="transition-colors whitespace-nowrap {isActivePath(item.href, currentPath)
89
+ ? 'text-accent-muted'
90
+ : 'text-foreground-subtle hover:text-accent-muted'}"
91
+ >
92
+ <span>{item.label}</span>
93
+ </a>
94
+ {/each}
95
+ <ThemeToggle />
96
+ </nav>
97
+
98
+ <!-- Mobile: Theme toggle + hamburger -->
99
+ <div class="flex md:hidden items-center gap-2">
100
+ <ThemeToggle />
101
+ <button
102
+ onclick={() => (mobileMenuOpen = true)}
103
+ class="p-2 -mr-2 text-foreground-subtle hover:text-foreground transition-colors rounded-lg hover:bg-surface-hover"
104
+ aria-label="Open menu"
105
+ >
106
+ <Menu class="w-5 h-5" />
107
+ </button>
108
+ </div>
109
+ </div>
110
+ </header>
111
+
112
+ <!-- Mobile menu overlay -->
113
+ <MobileMenu bind:open={mobileMenuOpen} onClose={() => (mobileMenuOpen = false)} {navItems} />
@@ -0,0 +1,11 @@
1
+ import type { NavItem, MaxWidth, Season } from './types';
2
+ interface Props {
3
+ navItems?: NavItem[];
4
+ maxWidth?: MaxWidth;
5
+ brandTitle?: string;
6
+ season?: Season;
7
+ onSeasonChange?: () => void;
8
+ }
9
+ declare const Header: import("svelte").Component<Props, {}, "">;
10
+ type Header = ReturnType<typeof Header>;
11
+ export default Header;
@@ -0,0 +1,68 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Header - Status page navigation header
4
+ *
5
+ * Clean, minimal header with Grove branding and theme toggle.
6
+ */
7
+ import { Trees, Sun, Moon, Rss } from 'lucide-svelte';
8
+ import ThemeToggle from './ThemeToggle.svelte';
9
+ import { cn } from '../../../utils/cn';
10
+
11
+ interface Props {
12
+ class?: string;
13
+ brandTitle?: string;
14
+ subtitle?: string;
15
+ maxWidth?: 'narrow' | 'default' | 'wide';
16
+ }
17
+
18
+ let {
19
+ class: className,
20
+ brandTitle = 'Grove',
21
+ subtitle = 'Status',
22
+ maxWidth = 'default'
23
+ }: Props = $props();
24
+
25
+ const maxWidthClass = {
26
+ narrow: 'max-w-2xl',
27
+ default: 'max-w-4xl',
28
+ wide: 'max-w-5xl'
29
+ };
30
+ </script>
31
+
32
+ <header
33
+ class={cn(
34
+ 'sticky top-0 z-40 py-4 px-6',
35
+ 'bg-white/60 dark:bg-slate-900/60 backdrop-blur-md',
36
+ 'border-b border-white/40 dark:border-slate-700/40',
37
+ className
38
+ )}
39
+ >
40
+ <div class="{maxWidthClass[maxWidth]} mx-auto flex items-center justify-between">
41
+ <!-- Logo and title -->
42
+ <a href="/" class="flex items-center gap-2.5 group">
43
+ <div class="p-1.5 rounded-lg bg-grove-500/10 group-hover:bg-grove-500/20 transition-colors">
44
+ <Trees class="w-6 h-6 text-grove-600 dark:text-grove-400" />
45
+ </div>
46
+ <div>
47
+ <span class="font-semibold text-foreground">{brandTitle}</span>
48
+ <span class="text-foreground-muted ml-1">{subtitle}</span>
49
+ </div>
50
+ </a>
51
+
52
+ <!-- Actions -->
53
+ <div class="flex items-center gap-2">
54
+ <!-- RSS Feed link -->
55
+ <a
56
+ href="/feed"
57
+ class="p-2 rounded-lg text-foreground-muted hover:text-foreground hover:bg-white/50 dark:hover:bg-slate-800/50 transition-colors"
58
+ aria-label="RSS Feed"
59
+ title="Subscribe via RSS"
60
+ >
61
+ <Rss class="w-5 h-5" />
62
+ </a>
63
+
64
+ <!-- Theme toggle -->
65
+ <ThemeToggle />
66
+ </div>
67
+ </div>
68
+ </header>
@@ -0,0 +1,9 @@
1
+ interface Props {
2
+ class?: string;
3
+ brandTitle?: string;
4
+ subtitle?: string;
5
+ maxWidth?: 'narrow' | 'default' | 'wide';
6
+ }
7
+ declare const HeaderMinimal: import("svelte").Component<Props, {}, "">;
8
+ type HeaderMinimal = ReturnType<typeof HeaderMinimal>;
9
+ export default HeaderMinimal;
@@ -0,0 +1,145 @@
1
+ <script lang="ts">
2
+ import { page } from '$app/stores';
3
+ import { X } from 'lucide-svelte';
4
+ import type { NavItem } from './types';
5
+ import { isActivePath } from './types';
6
+ import { DEFAULT_MOBILE_NAV_ITEMS } from './defaults';
7
+
8
+ interface Props {
9
+ open: boolean;
10
+ onClose: () => void;
11
+ navItems?: NavItem[];
12
+ }
13
+
14
+ let { open = $bindable(), onClose, navItems }: Props = $props();
15
+
16
+ let currentPath = $derived($page.url.pathname);
17
+
18
+ // References for focus management
19
+ let closeButtonRef: HTMLButtonElement | undefined = $state();
20
+ let menuPanelRef: HTMLDivElement | undefined = $state();
21
+ let previouslyFocusedElement: HTMLElement | null = null;
22
+
23
+ // Handle close action
24
+ function handleClose() {
25
+ open = false;
26
+ onClose();
27
+ }
28
+
29
+ // Close on escape key
30
+ function handleKeydown(event: KeyboardEvent) {
31
+ if (event.key === 'Escape' && open) {
32
+ handleClose();
33
+ }
34
+
35
+ // Focus trap: Tab key cycles within menu
36
+ if (event.key === 'Tab' && open && menuPanelRef) {
37
+ const focusableElements = menuPanelRef.querySelectorAll<HTMLElement>(
38
+ 'button, a, input, select, textarea, [tabindex]:not([tabindex="-1"])'
39
+ );
40
+ const firstElement = focusableElements[0];
41
+ const lastElement = focusableElements[focusableElements.length - 1];
42
+
43
+ if (event.shiftKey && document.activeElement === firstElement) {
44
+ // Shift+Tab on first element: wrap to last
45
+ event.preventDefault();
46
+ lastElement?.focus();
47
+ } else if (!event.shiftKey && document.activeElement === lastElement) {
48
+ // Tab on last element: wrap to first
49
+ event.preventDefault();
50
+ firstElement?.focus();
51
+ }
52
+ }
53
+ }
54
+
55
+ // Focus management and body scroll lock when menu opens/closes
56
+ $effect(() => {
57
+ if (open) {
58
+ // Store the previously focused element to restore later
59
+ previouslyFocusedElement = document.activeElement as HTMLElement;
60
+ // Focus the close button when menu opens
61
+ requestAnimationFrame(() => {
62
+ closeButtonRef?.focus();
63
+ });
64
+ // Prevent body scroll
65
+ document.body.style.overflow = 'hidden';
66
+ } else {
67
+ if (previouslyFocusedElement) {
68
+ // Restore focus when menu closes
69
+ previouslyFocusedElement.focus();
70
+ previouslyFocusedElement = null;
71
+ }
72
+ // Restore body scroll
73
+ document.body.style.overflow = '';
74
+ }
75
+
76
+ // Cleanup on unmount: ensure body scroll is always restored
77
+ return () => {
78
+ document.body.style.overflow = '';
79
+ };
80
+ });
81
+
82
+ const items = navItems || DEFAULT_MOBILE_NAV_ITEMS;
83
+ </script>
84
+
85
+ <svelte:window on:keydown={handleKeydown} />
86
+
87
+ <!-- Backdrop -->
88
+ {#if open}
89
+ <button
90
+ type="button"
91
+ class="fixed inset-0 z-[100] bg-black/50 backdrop-blur-sm transition-opacity"
92
+ onclick={handleClose}
93
+ aria-label="Close menu"
94
+ ></button>
95
+ {/if}
96
+
97
+ <!-- Slide-out panel -->
98
+ <div
99
+ bind:this={menuPanelRef}
100
+ class="fixed top-0 right-0 z-[110] h-full w-64 transform bg-surface border-l border-default shadow-xl transition-transform duration-300 ease-out {open
101
+ ? 'translate-x-0'
102
+ : 'translate-x-full'}"
103
+ role="dialog"
104
+ aria-modal="true"
105
+ aria-label="Navigation menu"
106
+ aria-hidden={!open}
107
+ >
108
+ <!-- Header -->
109
+ <div class="flex items-center justify-between p-4 border-b border-default">
110
+ <span class="text-sm font-medium text-foreground-subtle">Menu</span>
111
+ <button
112
+ bind:this={closeButtonRef}
113
+ type="button"
114
+ onclick={handleClose}
115
+ class="p-2 -mr-2 text-foreground-subtle hover:text-foreground transition-colors rounded-lg hover:bg-surface-hover"
116
+ aria-label="Close menu"
117
+ >
118
+ <X class="w-5 h-5" />
119
+ </button>
120
+ </div>
121
+
122
+ <!-- Navigation -->
123
+ <nav class="p-2">
124
+ {#each items as item}
125
+ {@const Icon = item.icon}
126
+ {@const active = isActivePath(item.href, currentPath)}
127
+ <a
128
+ href={item.href}
129
+ target={item.external ? '_blank' : undefined}
130
+ rel={item.external ? 'noopener noreferrer' : undefined}
131
+ onclick={handleClose}
132
+ class="flex items-center gap-3 px-3 py-3 rounded-lg transition-colors
133
+ {active
134
+ ? 'bg-accent/10 text-accent-muted'
135
+ : 'text-foreground hover:bg-surface-hover hover:text-accent-muted'}"
136
+ >
137
+ <Icon class="w-5 h-5 flex-shrink-0" />
138
+ <span class="text-sm font-medium">{item.label}</span>
139
+ {#if item.external}
140
+ <span class="text-xs text-foreground-subtle ml-auto">External</span>
141
+ {/if}
142
+ </a>
143
+ {/each}
144
+ </nav>
145
+ </div>
@@ -0,0 +1,9 @@
1
+ import type { NavItem } from './types';
2
+ interface Props {
3
+ open: boolean;
4
+ onClose: () => void;
5
+ navItems?: NavItem[];
6
+ }
7
+ declare const MobileMenu: import("svelte").Component<Props, {}, "open">;
8
+ type MobileMenu = ReturnType<typeof MobileMenu>;
9
+ export default MobileMenu;
@@ -0,0 +1,34 @@
1
+ <script lang="ts">
2
+ import { themeStore } from '../../stores/theme';
3
+
4
+ // Extract the resolvedTheme store and toggle function
5
+ const { resolvedTheme, toggle } = themeStore;
6
+ let isDark = $derived($resolvedTheme === 'dark');
7
+ </script>
8
+
9
+ <button
10
+ onclick={() => toggle()}
11
+ class="p-2 rounded-lg text-foreground-subtle hover:text-accent-muted hover:bg-surface transition-colors"
12
+ aria-label={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
13
+ title={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
14
+ >
15
+ {#if isDark}
16
+ <!-- Sun icon - shown in dark mode -->
17
+ <svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
18
+ <circle cx="12" cy="12" r="5" />
19
+ <line x1="12" y1="1" x2="12" y2="3" />
20
+ <line x1="12" y1="21" x2="12" y2="23" />
21
+ <line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
22
+ <line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
23
+ <line x1="1" y1="12" x2="3" y2="12" />
24
+ <line x1="21" y1="12" x2="23" y2="12" />
25
+ <line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
26
+ <line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
27
+ </svg>
28
+ {:else}
29
+ <!-- Moon icon - shown in light mode -->
30
+ <svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
31
+ <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
32
+ </svg>
33
+ {/if}
34
+ </button>
@@ -0,0 +1,3 @@
1
+ declare const ThemeToggle: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type ThemeToggle = ReturnType<typeof ThemeToggle>;
3
+ export default ThemeToggle;
@@ -0,0 +1,6 @@
1
+ import type { NavItem, FooterLink } from "./types";
2
+ export declare const DEFAULT_NAV_ITEMS: NavItem[];
3
+ export declare const DEFAULT_MOBILE_NAV_ITEMS: NavItem[];
4
+ export declare const DEFAULT_RESOURCE_LINKS: FooterLink[];
5
+ export declare const DEFAULT_CONNECT_LINKS: FooterLink[];
6
+ export declare const DEFAULT_LEGAL_LINKS: FooterLink[];
@@ -0,0 +1,65 @@
1
+ import { Scroll, Telescope, MapPin, Tag, BookOpen, Trees, PenLine, Home, CircleDollarSign, Send, Github, ExternalLink, Mail, Hammer, Grape, } from "lucide-svelte";
2
+ // Default navigation items (desktop)
3
+ export const DEFAULT_NAV_ITEMS = [
4
+ { href: "/manifesto", label: "Manifesto", icon: Scroll },
5
+ { href: "/vision", label: "Vision", icon: Telescope },
6
+ { href: "/roadmap", label: "Roadmap", icon: MapPin },
7
+ { href: "/pricing", label: "Pricing", icon: Tag },
8
+ { href: "/knowledge", label: "Knowledge", icon: BookOpen },
9
+ { href: "/forest", label: "Forest", icon: Trees },
10
+ {
11
+ href: "https://autumnsgrove.com/blog",
12
+ label: "Blog",
13
+ icon: PenLine,
14
+ external: true,
15
+ },
16
+ ];
17
+ // Default mobile navigation items (includes Home and Contact)
18
+ export const DEFAULT_MOBILE_NAV_ITEMS = [
19
+ { href: "/", label: "Home", icon: Home },
20
+ { href: "/manifesto", label: "Manifesto", icon: Scroll },
21
+ { href: "/vision", label: "Vision", icon: Telescope },
22
+ { href: "/roadmap", label: "Roadmap", icon: MapPin },
23
+ { href: "/pricing", label: "Pricing", icon: CircleDollarSign },
24
+ { href: "/knowledge", label: "Knowledge", icon: BookOpen },
25
+ { href: "/forest", label: "Forest", icon: Trees },
26
+ { href: "/contact", label: "Contact", icon: Send },
27
+ {
28
+ href: "https://autumnsgrove.com/blog",
29
+ label: "Blog",
30
+ icon: PenLine,
31
+ external: true,
32
+ },
33
+ ];
34
+ // Default resource links (for footer)
35
+ export const DEFAULT_RESOURCE_LINKS = [
36
+ { href: "/knowledge", label: "Knowledge Base", icon: BookOpen },
37
+ { href: "/roadmap", label: "Roadmap", icon: MapPin },
38
+ { href: "/roadmap/workshop", label: "Workshop", icon: Hammer },
39
+ { href: "/forest", label: "Forest", icon: Trees },
40
+ { href: "/vineyard", label: "Vineyard", icon: Grape },
41
+ { href: "/pricing", label: "Pricing", icon: Tag },
42
+ { href: "/manifesto", label: "Manifesto", icon: Scroll },
43
+ { href: "/vision", label: "Our Vision", icon: Telescope },
44
+ ];
45
+ // Default connect links (for footer)
46
+ export const DEFAULT_CONNECT_LINKS = [
47
+ { href: "/contact", label: "Contact", icon: Mail },
48
+ {
49
+ href: "https://autumnsgrove.com/blog",
50
+ label: "Blog",
51
+ icon: PenLine,
52
+ external: true,
53
+ },
54
+ {
55
+ href: "https://github.com/AutumnsGrove/GroveEngine",
56
+ label: "GitHub",
57
+ icon: Github,
58
+ external: true,
59
+ },
60
+ ];
61
+ // Default legal links (for footer)
62
+ export const DEFAULT_LEGAL_LINKS = [
63
+ { href: "/legal/privacy", label: "Privacy" },
64
+ { href: "/legal/terms", label: "Terms" },
65
+ ];
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Chrome Components Index
3
+ * Re-exports all shared chrome/navigation components from the engine package
4
+ */
5
+ export { default as ThemeToggle } from "./ThemeToggle.svelte";
6
+ export { default as MobileMenu } from "./MobileMenu.svelte";
7
+ export { default as Header } from "./Header.svelte";
8
+ export { default as HeaderMinimal } from "./HeaderMinimal.svelte";
9
+ export { default as Footer } from "./Footer.svelte";
10
+ export { default as FooterMinimal } from "./FooterMinimal.svelte";
11
+ export * from "./types";
12
+ export * from "./defaults";
13
+ export { seasonStore, themeStore } from "../../stores";
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Chrome Components Index
3
+ * Re-exports all shared chrome/navigation components from the engine package
4
+ */
5
+ export { default as ThemeToggle } from "./ThemeToggle.svelte";
6
+ export { default as MobileMenu } from "./MobileMenu.svelte";
7
+ export { default as Header } from "./Header.svelte";
8
+ export { default as HeaderMinimal } from "./HeaderMinimal.svelte";
9
+ export { default as Footer } from "./Footer.svelte";
10
+ export { default as FooterMinimal } from "./FooterMinimal.svelte";
11
+ export * from "./types";
12
+ export * from "./defaults";
13
+ // Re-export stores for convenient access
14
+ export { seasonStore, themeStore } from "../../stores";
@@ -0,0 +1,19 @@
1
+ import type { Component } from 'svelte';
2
+ export type { Season } from '../nature/palette';
3
+ export interface NavItem {
4
+ href: string;
5
+ label: string;
6
+ icon?: Component;
7
+ external?: boolean;
8
+ }
9
+ export interface FooterLink {
10
+ href: string;
11
+ label: string;
12
+ icon?: Component;
13
+ external?: boolean;
14
+ }
15
+ export type MaxWidth = "narrow" | "default" | "wide";
16
+ /**
17
+ * Check if a navigation item is active based on the current path
18
+ */
19
+ export declare function isActivePath(href: string, currentPath: string): boolean;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Check if a navigation item is active based on the current path
3
+ */
4
+ export function isActivePath(href, currentPath) {
5
+ if (href === '/')
6
+ return currentPath === '/';
7
+ return currentPath.startsWith(href);
8
+ }
@@ -1,7 +1,8 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from "svelte";
3
3
  import { cn } from "../../utils";
4
- import { MapPin, ArrowRight } from "lucide-svelte";
4
+ // Use centralized icon registry instead of direct lucide-svelte imports
5
+ import { MapPin, ArrowRight } from "../icons";
5
6
 
6
7
  /**
7
8
  * RoadmapPreview - A glass card showing current development phase