@autumnsgrove/groveengine 0.7.0 → 0.8.5
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/dist/components/OnboardingChecklist.svelte +2 -2
- package/dist/components/WispButton.svelte +83 -0
- package/dist/components/WispButton.svelte.d.ts +49 -0
- package/dist/components/WispPanel.svelte +1093 -0
- package/dist/components/WispPanel.svelte.d.ts +49 -0
- package/dist/components/custom/TableOfContents.svelte +12 -1
- package/dist/components/quota/UpgradePrompt.svelte +1 -0
- package/dist/config/wisp.d.ts +145 -0
- package/dist/config/wisp.js +175 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/server/inference-client.d.ts +139 -0
- package/dist/server/inference-client.js +294 -0
- package/dist/ui/components/content/RoadmapPreview.svelte +91 -0
- package/dist/ui/components/content/RoadmapPreview.svelte.d.ts +36 -0
- package/dist/ui/components/content/index.d.ts +1 -0
- package/dist/ui/components/content/index.js +1 -0
- package/dist/ui/components/nature/Logo.svelte +260 -0
- package/dist/ui/components/nature/Logo.svelte.d.ts +14 -0
- package/dist/ui/components/nature/botanical/Acorn.svelte +48 -0
- package/dist/ui/components/nature/botanical/Acorn.svelte.d.ts +8 -0
- package/dist/ui/components/nature/botanical/Berry.svelte +67 -0
- package/dist/ui/components/nature/botanical/Berry.svelte.d.ts +8 -0
- package/dist/ui/components/nature/botanical/DandelionPuff.svelte +98 -0
- package/dist/ui/components/nature/botanical/DandelionPuff.svelte.d.ts +8 -0
- package/dist/ui/components/nature/botanical/FallingLeavesLayer.svelte +170 -0
- package/dist/ui/components/nature/botanical/FallingLeavesLayer.svelte.d.ts +35 -0
- package/dist/ui/components/nature/botanical/FallingPetalsLayer.svelte +174 -0
- package/dist/ui/components/nature/botanical/FallingPetalsLayer.svelte.d.ts +25 -0
- package/dist/ui/components/nature/botanical/Leaf.svelte +77 -0
- package/dist/ui/components/nature/botanical/Leaf.svelte.d.ts +10 -0
- package/dist/ui/components/nature/botanical/LeafFalling.svelte +186 -0
- package/dist/ui/components/nature/botanical/LeafFalling.svelte.d.ts +22 -0
- package/dist/ui/components/nature/botanical/PetalFalling.svelte +266 -0
- package/dist/ui/components/nature/botanical/PetalFalling.svelte.d.ts +25 -0
- package/dist/ui/components/nature/botanical/PineCone.svelte +61 -0
- package/dist/ui/components/nature/botanical/PineCone.svelte.d.ts +7 -0
- package/dist/ui/components/nature/botanical/Vine.svelte +102 -0
- package/dist/ui/components/nature/botanical/Vine.svelte.d.ts +11 -0
- package/dist/ui/components/nature/botanical/index.d.ts +10 -0
- package/dist/ui/components/nature/botanical/index.js +11 -0
- package/dist/ui/components/nature/creatures/Bee.svelte +78 -0
- package/dist/ui/components/nature/creatures/Bee.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/Bird.svelte +94 -0
- package/dist/ui/components/nature/creatures/Bird.svelte.d.ts +11 -0
- package/dist/ui/components/nature/creatures/BirdFlying.svelte +83 -0
- package/dist/ui/components/nature/creatures/BirdFlying.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/Bluebird.svelte +95 -0
- package/dist/ui/components/nature/creatures/Bluebird.svelte.d.ts +12 -0
- package/dist/ui/components/nature/creatures/Butterfly.svelte +87 -0
- package/dist/ui/components/nature/creatures/Butterfly.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/Cardinal.svelte +95 -0
- package/dist/ui/components/nature/creatures/Cardinal.svelte.d.ts +12 -0
- package/dist/ui/components/nature/creatures/Chickadee.svelte +97 -0
- package/dist/ui/components/nature/creatures/Chickadee.svelte.d.ts +12 -0
- package/dist/ui/components/nature/creatures/Deer.svelte +95 -0
- package/dist/ui/components/nature/creatures/Deer.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/Firefly.svelte +111 -0
- package/dist/ui/components/nature/creatures/Firefly.svelte.d.ts +10 -0
- package/dist/ui/components/nature/creatures/Owl.svelte +91 -0
- package/dist/ui/components/nature/creatures/Owl.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/Rabbit.svelte +90 -0
- package/dist/ui/components/nature/creatures/Rabbit.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/Robin.svelte +98 -0
- package/dist/ui/components/nature/creatures/Robin.svelte.d.ts +12 -0
- package/dist/ui/components/nature/creatures/Squirrel.svelte +97 -0
- package/dist/ui/components/nature/creatures/Squirrel.svelte.d.ts +9 -0
- package/dist/ui/components/nature/creatures/index.d.ts +13 -0
- package/dist/ui/components/nature/creatures/index.js +14 -0
- package/dist/ui/components/nature/ground/Bush.svelte +57 -0
- package/dist/ui/components/nature/ground/Bush.svelte.d.ts +10 -0
- package/dist/ui/components/nature/ground/Crocus.svelte +83 -0
- package/dist/ui/components/nature/ground/Crocus.svelte.d.ts +12 -0
- package/dist/ui/components/nature/ground/Daffodil.svelte +75 -0
- package/dist/ui/components/nature/ground/Daffodil.svelte.d.ts +11 -0
- package/dist/ui/components/nature/ground/Fern.svelte +72 -0
- package/dist/ui/components/nature/ground/Fern.svelte.d.ts +10 -0
- package/dist/ui/components/nature/ground/FlowerWild.svelte +60 -0
- package/dist/ui/components/nature/ground/FlowerWild.svelte.d.ts +10 -0
- package/dist/ui/components/nature/ground/GrassTuft.svelte +49 -0
- package/dist/ui/components/nature/ground/GrassTuft.svelte.d.ts +10 -0
- package/dist/ui/components/nature/ground/Log.svelte +42 -0
- package/dist/ui/components/nature/ground/Log.svelte.d.ts +7 -0
- package/dist/ui/components/nature/ground/Mushroom.svelte +48 -0
- package/dist/ui/components/nature/ground/Mushroom.svelte.d.ts +9 -0
- package/dist/ui/components/nature/ground/MushroomCluster.svelte +41 -0
- package/dist/ui/components/nature/ground/MushroomCluster.svelte.d.ts +8 -0
- package/dist/ui/components/nature/ground/Rock.svelte +59 -0
- package/dist/ui/components/nature/ground/Rock.svelte.d.ts +8 -0
- package/dist/ui/components/nature/ground/Stump.svelte +44 -0
- package/dist/ui/components/nature/ground/Stump.svelte.d.ts +8 -0
- package/dist/ui/components/nature/ground/Tulip.svelte +79 -0
- package/dist/ui/components/nature/ground/Tulip.svelte.d.ts +11 -0
- package/dist/ui/components/nature/ground/index.d.ts +12 -0
- package/dist/ui/components/nature/ground/index.js +13 -0
- package/dist/ui/components/nature/index.d.ts +28 -0
- package/dist/ui/components/nature/index.js +38 -0
- package/dist/ui/components/nature/palette.d.ts +602 -0
- package/dist/ui/components/nature/palette.js +472 -0
- package/dist/ui/components/nature/sky/Cloud.svelte +122 -0
- package/dist/ui/components/nature/sky/Cloud.svelte.d.ts +11 -0
- package/dist/ui/components/nature/sky/CloudWispy.svelte +79 -0
- package/dist/ui/components/nature/sky/CloudWispy.svelte.d.ts +9 -0
- package/dist/ui/components/nature/sky/Moon.svelte +60 -0
- package/dist/ui/components/nature/sky/Moon.svelte.d.ts +9 -0
- package/dist/ui/components/nature/sky/Rainbow.svelte +101 -0
- package/dist/ui/components/nature/sky/Rainbow.svelte.d.ts +8 -0
- package/dist/ui/components/nature/sky/Star.svelte +84 -0
- package/dist/ui/components/nature/sky/Star.svelte.d.ts +10 -0
- package/dist/ui/components/nature/sky/StarCluster.svelte +85 -0
- package/dist/ui/components/nature/sky/StarCluster.svelte.d.ts +9 -0
- package/dist/ui/components/nature/sky/StarShooting.svelte +90 -0
- package/dist/ui/components/nature/sky/StarShooting.svelte.d.ts +9 -0
- package/dist/ui/components/nature/sky/Sun.svelte +70 -0
- package/dist/ui/components/nature/sky/Sun.svelte.d.ts +9 -0
- package/dist/ui/components/nature/sky/index.d.ts +8 -0
- package/dist/ui/components/nature/sky/index.js +9 -0
- package/dist/ui/components/nature/structural/Birdhouse.svelte +53 -0
- package/dist/ui/components/nature/structural/Birdhouse.svelte.d.ts +8 -0
- package/dist/ui/components/nature/structural/Bridge.svelte +65 -0
- package/dist/ui/components/nature/structural/Bridge.svelte.d.ts +7 -0
- package/dist/ui/components/nature/structural/FencePost.svelte +54 -0
- package/dist/ui/components/nature/structural/FencePost.svelte.d.ts +8 -0
- package/dist/ui/components/nature/structural/GardenGate.svelte +70 -0
- package/dist/ui/components/nature/structural/GardenGate.svelte.d.ts +8 -0
- package/dist/ui/components/nature/structural/Lantern.svelte +113 -0
- package/dist/ui/components/nature/structural/Lantern.svelte.d.ts +10 -0
- package/dist/ui/components/nature/structural/Lattice.svelte +89 -0
- package/dist/ui/components/nature/structural/Lattice.svelte.d.ts +8 -0
- package/dist/ui/components/nature/structural/LatticeWithVine.svelte +89 -0
- package/dist/ui/components/nature/structural/LatticeWithVine.svelte.d.ts +11 -0
- package/dist/ui/components/nature/structural/StonePath.svelte +48 -0
- package/dist/ui/components/nature/structural/StonePath.svelte.d.ts +7 -0
- package/dist/ui/components/nature/structural/index.d.ts +8 -0
- package/dist/ui/components/nature/structural/index.js +9 -0
- package/dist/ui/components/nature/trees/TreeAspen.svelte +163 -0
- package/dist/ui/components/nature/trees/TreeAspen.svelte.d.ts +11 -0
- package/dist/ui/components/nature/trees/TreeBirch.svelte +186 -0
- package/dist/ui/components/nature/trees/TreeBirch.svelte.d.ts +11 -0
- package/dist/ui/components/nature/trees/TreeCherry.svelte +108 -0
- package/dist/ui/components/nature/trees/TreeCherry.svelte.d.ts +11 -0
- package/dist/ui/components/nature/trees/TreePine.svelte +79 -0
- package/dist/ui/components/nature/trees/TreePine.svelte.d.ts +11 -0
- package/dist/ui/components/nature/trees/index.d.ts +4 -0
- package/dist/ui/components/nature/trees/index.js +5 -0
- package/dist/ui/components/nature/water/LilyPad.svelte +99 -0
- package/dist/ui/components/nature/water/LilyPad.svelte.d.ts +10 -0
- package/dist/ui/components/nature/water/Pond.svelte +104 -0
- package/dist/ui/components/nature/water/Pond.svelte.d.ts +8 -0
- package/dist/ui/components/nature/water/Reeds.svelte +85 -0
- package/dist/ui/components/nature/water/Reeds.svelte.d.ts +11 -0
- package/dist/ui/components/nature/water/Stream.svelte +98 -0
- package/dist/ui/components/nature/water/Stream.svelte.d.ts +8 -0
- package/dist/ui/components/nature/water/index.d.ts +4 -0
- package/dist/ui/components/nature/water/index.js +5 -0
- package/dist/ui/components/nature/weather/SnowfallLayer.svelte +175 -0
- package/dist/ui/components/nature/weather/SnowfallLayer.svelte.d.ts +25 -0
- package/dist/ui/components/nature/weather/Snowflake.svelte +99 -0
- package/dist/ui/components/nature/weather/Snowflake.svelte.d.ts +11 -0
- package/dist/ui/components/nature/weather/SnowflakeFalling.svelte +162 -0
- package/dist/ui/components/nature/weather/SnowflakeFalling.svelte.d.ts +23 -0
- package/dist/ui/components/nature/weather/index.d.ts +3 -0
- package/dist/ui/components/nature/weather/index.js +4 -0
- package/dist/ui/components/primitives/textarea/textarea.svelte +1 -1
- package/dist/ui/components/typography/Alagard.svelte +17 -0
- package/dist/ui/components/typography/Alagard.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Atkinson.svelte +17 -0
- package/dist/ui/components/typography/Atkinson.svelte.d.ts +10 -0
- package/dist/ui/components/typography/BodoniModa.svelte +17 -0
- package/dist/ui/components/typography/BodoniModa.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Calistoga.svelte +17 -0
- package/dist/ui/components/typography/Calistoga.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Caveat.svelte +17 -0
- package/dist/ui/components/typography/Caveat.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Cormorant.svelte +17 -0
- package/dist/ui/components/typography/Cormorant.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Cozette.svelte +17 -0
- package/dist/ui/components/typography/Cozette.svelte.d.ts +10 -0
- package/dist/ui/components/typography/EBGaramond.svelte +17 -0
- package/dist/ui/components/typography/EBGaramond.svelte.d.ts +10 -0
- package/dist/ui/components/typography/FontProvider.svelte +98 -0
- package/dist/ui/components/typography/FontProvider.svelte.d.ts +17 -0
- package/dist/ui/components/typography/Fraunces.svelte +17 -0
- package/dist/ui/components/typography/Fraunces.svelte.d.ts +10 -0
- package/dist/ui/components/typography/IBMPlexMono.svelte +17 -0
- package/dist/ui/components/typography/IBMPlexMono.svelte.d.ts +10 -0
- package/dist/ui/components/typography/InstrumentSans.svelte +17 -0
- package/dist/ui/components/typography/InstrumentSans.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Lexend.svelte +17 -0
- package/dist/ui/components/typography/Lexend.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Lora.svelte +17 -0
- package/dist/ui/components/typography/Lora.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Luciole.svelte +17 -0
- package/dist/ui/components/typography/Luciole.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Manrope.svelte +17 -0
- package/dist/ui/components/typography/Manrope.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Merriweather.svelte +17 -0
- package/dist/ui/components/typography/Merriweather.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Nunito.svelte +17 -0
- package/dist/ui/components/typography/Nunito.svelte.d.ts +10 -0
- package/dist/ui/components/typography/OpenDyslexic.svelte +17 -0
- package/dist/ui/components/typography/OpenDyslexic.svelte.d.ts +10 -0
- package/dist/ui/components/typography/PlusJakartaSans.svelte +17 -0
- package/dist/ui/components/typography/PlusJakartaSans.svelte.d.ts +10 -0
- package/dist/ui/components/typography/Quicksand.svelte +17 -0
- package/dist/ui/components/typography/Quicksand.svelte.d.ts +10 -0
- package/dist/ui/components/typography/README.md +153 -0
- package/dist/ui/components/typography/index.d.ts +23 -0
- package/dist/ui/components/typography/index.js +42 -0
- package/dist/ui/components/ui/GlassCarousel.svelte +446 -0
- package/dist/ui/components/ui/GlassCarousel.svelte.d.ts +57 -0
- package/dist/ui/components/ui/GlassConfirmDialog.svelte +2 -1
- package/dist/ui/components/ui/GlassLogo.svelte +423 -0
- package/dist/ui/components/ui/GlassLogo.svelte.d.ts +23 -0
- package/dist/ui/components/ui/GlassNavbar.svelte +120 -0
- package/dist/ui/components/ui/GlassNavbar.svelte.d.ts +42 -0
- package/dist/ui/components/ui/GlassOverlay.svelte +1 -1
- package/dist/ui/components/ui/Logo.svelte +47 -52
- package/dist/ui/components/ui/Logo.svelte.d.ts +4 -3
- package/dist/ui/components/ui/index.d.ts +3 -0
- package/dist/ui/components/ui/index.js +3 -0
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +2 -0
- package/dist/ui/styles/grove.css +15 -1
- package/dist/ui/vineyard/index.d.ts +9 -0
- package/dist/ui/vineyard/index.js +8 -0
- package/dist/utils/csrf.js +5 -2
- package/dist/utils/readability.d.ts +89 -0
- package/dist/utils/readability.js +204 -0
- package/package.json +27 -1
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* GlassLogo - Grove Logo with glassmorphism styling
|
|
4
|
+
*
|
|
5
|
+
* A beautiful translucent logo with frosted glass effects,
|
|
6
|
+
* subtle highlights, and soft glows. Perfect for hero sections,
|
|
7
|
+
* glass cards, and modern UI designs.
|
|
8
|
+
*
|
|
9
|
+
* @example Basic glass logo
|
|
10
|
+
* ```svelte
|
|
11
|
+
* <GlassLogo class="w-16 h-20" />
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @example Seasonal glass logo
|
|
15
|
+
* ```svelte
|
|
16
|
+
* <GlassLogo season="winter" class="w-16 h-20" />
|
|
17
|
+
* <GlassLogo season="spring" breathing />
|
|
18
|
+
* <GlassLogo season="autumn" variant="frosted" />
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example Accent variant with breathing
|
|
22
|
+
* ```svelte
|
|
23
|
+
* <GlassLogo variant="accent" breathing />
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { tweened } from 'svelte/motion';
|
|
28
|
+
import { cubicInOut } from 'svelte/easing';
|
|
29
|
+
import { browser } from '$app/environment';
|
|
30
|
+
|
|
31
|
+
type GlassVariant =
|
|
32
|
+
| "default" // Light translucent - uses seasonal color or white/emerald
|
|
33
|
+
| "accent" // Accent-colored glass
|
|
34
|
+
| "frosted" // Strong frosted effect, more opaque
|
|
35
|
+
| "dark" // Dark translucent for light backgrounds
|
|
36
|
+
| "ethereal"; // Dreamy, highly transparent with glow
|
|
37
|
+
|
|
38
|
+
type Season = 'spring' | 'summer' | 'autumn' | 'winter';
|
|
39
|
+
|
|
40
|
+
type BreathingSpeed = 'slow' | 'normal' | 'fast';
|
|
41
|
+
|
|
42
|
+
interface Props {
|
|
43
|
+
class?: string;
|
|
44
|
+
/** Glass style variant */
|
|
45
|
+
variant?: GlassVariant;
|
|
46
|
+
/** Seasonal color theme - defaults to summer */
|
|
47
|
+
season?: Season;
|
|
48
|
+
/** Add breathing animation (for loading states) */
|
|
49
|
+
breathing?: boolean;
|
|
50
|
+
/** Breathing animation speed */
|
|
51
|
+
breathingSpeed?: BreathingSpeed;
|
|
52
|
+
/** Whether trunk should match foliage color */
|
|
53
|
+
monochrome?: boolean;
|
|
54
|
+
/** Custom accent color (CSS color value) - only applies when season is not set */
|
|
55
|
+
accentColor?: string;
|
|
56
|
+
/** Unique ID for SVG filters (auto-generated if not provided) */
|
|
57
|
+
filterId?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let {
|
|
61
|
+
class: className = 'w-6 h-6',
|
|
62
|
+
variant = "default",
|
|
63
|
+
season = 'summer',
|
|
64
|
+
breathing = false,
|
|
65
|
+
breathingSpeed = 'normal',
|
|
66
|
+
monochrome = false,
|
|
67
|
+
accentColor,
|
|
68
|
+
filterId
|
|
69
|
+
}: Props = $props();
|
|
70
|
+
|
|
71
|
+
// Check if winter for snow accents
|
|
72
|
+
const isWinter = $derived(season === 'winter');
|
|
73
|
+
|
|
74
|
+
// Generate unique ID for SVG filters to avoid conflicts when multiple logos exist
|
|
75
|
+
const randomId = `glass-logo-${Math.random().toString(36).slice(2, 9)}`;
|
|
76
|
+
const uniqueId = $derived(filterId ?? randomId);
|
|
77
|
+
|
|
78
|
+
// Breathing speed presets
|
|
79
|
+
const BREATHING_SPEEDS = {
|
|
80
|
+
slow: 1500,
|
|
81
|
+
normal: 800,
|
|
82
|
+
fast: 400
|
|
83
|
+
} as const;
|
|
84
|
+
|
|
85
|
+
// Reduced motion preference
|
|
86
|
+
const reducedMotionQuery = browser ? window.matchMedia('(prefers-reduced-motion: reduce)') : null;
|
|
87
|
+
let prefersReducedMotion = $state(reducedMotionQuery?.matches ?? false);
|
|
88
|
+
|
|
89
|
+
$effect(() => {
|
|
90
|
+
if (!reducedMotionQuery) return;
|
|
91
|
+
const handler = (e: MediaQueryListEvent) => { prefersReducedMotion = e.matches; };
|
|
92
|
+
reducedMotionQuery.addEventListener('change', handler);
|
|
93
|
+
return () => reducedMotionQuery.removeEventListener('change', handler);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Seasonal color palettes (glass-tinted versions)
|
|
97
|
+
// These define the base hues for each season
|
|
98
|
+
const seasonalPalettes = {
|
|
99
|
+
spring: {
|
|
100
|
+
// Cherry blossom pink - soft, hopeful
|
|
101
|
+
primary: 'rgba(244, 114, 182, 0.75)', // pink-400
|
|
102
|
+
secondary: 'rgba(251, 207, 232, 0.5)', // pink-200
|
|
103
|
+
glow: 'rgba(236, 72, 153, 0.35)', // pink-500
|
|
104
|
+
shadow: 'rgba(219, 39, 119, 0.2)' // pink-600
|
|
105
|
+
},
|
|
106
|
+
summer: {
|
|
107
|
+
// Grove brand green - growth, warmth
|
|
108
|
+
primary: 'rgba(16, 185, 129, 0.75)', // emerald-500
|
|
109
|
+
secondary: 'rgba(167, 243, 208, 0.5)', // emerald-200
|
|
110
|
+
glow: 'rgba(5, 150, 105, 0.35)', // emerald-600
|
|
111
|
+
shadow: 'rgba(4, 120, 87, 0.2)' // emerald-700
|
|
112
|
+
},
|
|
113
|
+
autumn: {
|
|
114
|
+
// Warm amber/orange - harvest, reflection
|
|
115
|
+
primary: 'rgba(251, 146, 60, 0.75)', // orange-400
|
|
116
|
+
secondary: 'rgba(254, 215, 170, 0.5)', // orange-200
|
|
117
|
+
glow: 'rgba(234, 88, 12, 0.35)', // orange-600
|
|
118
|
+
shadow: 'rgba(194, 65, 12, 0.2)' // orange-700
|
|
119
|
+
},
|
|
120
|
+
winter: {
|
|
121
|
+
// Frosted evergreen - stillness, rest
|
|
122
|
+
primary: 'rgba(134, 239, 172, 0.6)', // green-300 (muted)
|
|
123
|
+
secondary: 'rgba(220, 252, 231, 0.4)', // green-100
|
|
124
|
+
glow: 'rgba(74, 222, 128, 0.3)', // green-400
|
|
125
|
+
shadow: 'rgba(34, 197, 94, 0.15)' // green-500
|
|
126
|
+
}
|
|
127
|
+
} as const;
|
|
128
|
+
|
|
129
|
+
// Snow color for winter accents
|
|
130
|
+
const snowColor = 'rgba(248, 250, 252, 0.9)'; // slate-50
|
|
131
|
+
|
|
132
|
+
// Get seasonal colors or null if no season specified
|
|
133
|
+
const seasonColors = $derived(season ? seasonalPalettes[season] : null);
|
|
134
|
+
|
|
135
|
+
// Glass color schemes per variant, using seasonal colors
|
|
136
|
+
const variantColors = $derived.by(() => {
|
|
137
|
+
// Base colors from variant (all variants use seasonal colors now)
|
|
138
|
+
const baseColors = {
|
|
139
|
+
default: {
|
|
140
|
+
gradientStart: seasonColors?.primary ?? 'rgba(255, 255, 255, 0.7)',
|
|
141
|
+
gradientEnd: seasonColors?.secondary ?? 'rgba(236, 253, 245, 0.5)',
|
|
142
|
+
highlight: 'rgba(255, 255, 255, 0.9)',
|
|
143
|
+
shadow: seasonColors?.shadow ?? 'rgba(16, 185, 129, 0.2)',
|
|
144
|
+
trunk: monochrome
|
|
145
|
+
? (seasonColors?.primary ?? 'rgba(255, 255, 255, 0.5)')
|
|
146
|
+
: 'rgba(93, 64, 55, 0.7)',
|
|
147
|
+
glowColor: seasonColors?.glow ?? 'rgba(16, 185, 129, 0.3)'
|
|
148
|
+
},
|
|
149
|
+
accent: {
|
|
150
|
+
// Accent uses custom accentColor if provided, otherwise seasonal colors
|
|
151
|
+
gradientStart: accentColor ? `${accentColor}cc` : (seasonColors?.primary ?? 'rgba(var(--accent-rgb, 16, 185, 129), 0.8)'),
|
|
152
|
+
gradientEnd: accentColor ? `${accentColor}99` : (seasonColors?.secondary ?? 'rgba(var(--accent-rgb, 16, 185, 129), 0.6)'),
|
|
153
|
+
highlight: 'rgba(255, 255, 255, 0.6)',
|
|
154
|
+
shadow: accentColor ? `${accentColor}40` : (seasonColors?.shadow ?? 'rgba(var(--accent-rgb, 16, 185, 129), 0.25)'),
|
|
155
|
+
trunk: monochrome
|
|
156
|
+
? (accentColor ? `${accentColor}99` : (seasonColors?.primary ?? 'rgba(var(--accent-rgb, 16, 185, 129), 0.6)'))
|
|
157
|
+
: 'rgba(93, 64, 55, 0.8)',
|
|
158
|
+
glowColor: accentColor ? `${accentColor}50` : (seasonColors?.glow ?? 'rgba(var(--accent-rgb, 16, 185, 129), 0.3)')
|
|
159
|
+
},
|
|
160
|
+
frosted: {
|
|
161
|
+
// Frosted: more opaque, tinted with season
|
|
162
|
+
gradientStart: seasonColors
|
|
163
|
+
? seasonColors.primary.replace('0.75)', '0.85)').replace('0.6)', '0.8)')
|
|
164
|
+
: 'rgba(255, 255, 255, 0.85)',
|
|
165
|
+
gradientEnd: seasonColors
|
|
166
|
+
? seasonColors.secondary.replace('0.5)', '0.7)').replace('0.4)', '0.6)')
|
|
167
|
+
: 'rgba(248, 250, 252, 0.75)',
|
|
168
|
+
highlight: 'rgba(255, 255, 255, 0.95)',
|
|
169
|
+
shadow: seasonColors?.shadow ?? 'rgba(100, 116, 139, 0.15)',
|
|
170
|
+
trunk: monochrome
|
|
171
|
+
? (seasonColors?.primary ?? 'rgba(255, 255, 255, 0.7)')
|
|
172
|
+
: 'rgba(93, 64, 55, 0.85)',
|
|
173
|
+
glowColor: seasonColors?.glow ?? 'rgba(148, 163, 184, 0.2)'
|
|
174
|
+
},
|
|
175
|
+
dark: {
|
|
176
|
+
// Dark: subtle seasonal tint in shadow/glow only
|
|
177
|
+
gradientStart: 'rgba(30, 41, 59, 0.7)',
|
|
178
|
+
gradientEnd: 'rgba(15, 23, 42, 0.6)',
|
|
179
|
+
highlight: 'rgba(148, 163, 184, 0.4)',
|
|
180
|
+
shadow: 'rgba(0, 0, 0, 0.3)',
|
|
181
|
+
trunk: monochrome ? 'rgba(30, 41, 59, 0.6)' : 'rgba(60, 45, 38, 0.8)',
|
|
182
|
+
glowColor: seasonColors?.glow ?? 'rgba(100, 116, 139, 0.2)'
|
|
183
|
+
},
|
|
184
|
+
ethereal: {
|
|
185
|
+
// Ethereal: dreamy seasonal colors with strong glow
|
|
186
|
+
gradientStart: seasonColors
|
|
187
|
+
? seasonColors.primary.replace(/0\.\d+\)$/, '0.4)')
|
|
188
|
+
: 'rgba(255, 255, 255, 0.4)',
|
|
189
|
+
gradientEnd: seasonColors
|
|
190
|
+
? seasonColors.secondary.replace(/0\.\d+\)$/, '0.25)')
|
|
191
|
+
: 'rgba(236, 254, 255, 0.25)',
|
|
192
|
+
highlight: 'rgba(255, 255, 255, 0.7)',
|
|
193
|
+
shadow: seasonColors?.shadow ?? 'rgba(34, 211, 238, 0.2)',
|
|
194
|
+
trunk: monochrome
|
|
195
|
+
? (seasonColors?.primary?.replace(/0\.\d+\)$/, '0.3)') ?? 'rgba(255, 255, 255, 0.3)')
|
|
196
|
+
: 'rgba(93, 64, 55, 0.5)',
|
|
197
|
+
glowColor: seasonColors
|
|
198
|
+
? seasonColors.glow.replace(/0\.\d+\)$/, '0.4)')
|
|
199
|
+
: 'rgba(34, 211, 238, 0.4)'
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
return baseColors[variant];
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Breathing animation
|
|
207
|
+
const breathValue = tweened(0, { easing: cubicInOut });
|
|
208
|
+
|
|
209
|
+
$effect(() => {
|
|
210
|
+
const duration = BREATHING_SPEEDS[breathingSpeed];
|
|
211
|
+
|
|
212
|
+
if (!breathing || prefersReducedMotion) {
|
|
213
|
+
breathValue.set(0, { duration: Math.min(duration / 2, 300) });
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
let cancelled = false;
|
|
218
|
+
|
|
219
|
+
async function pulse() {
|
|
220
|
+
while (!cancelled) {
|
|
221
|
+
await breathValue.set(1, { duration });
|
|
222
|
+
if (cancelled) break;
|
|
223
|
+
await breathValue.set(0, { duration });
|
|
224
|
+
if (cancelled) break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
pulse();
|
|
229
|
+
|
|
230
|
+
return () => { cancelled = true; };
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Breathing expansion values
|
|
234
|
+
const expansion = $derived($breathValue * 22);
|
|
235
|
+
const diagExpansion = $derived($breathValue * 16);
|
|
236
|
+
|
|
237
|
+
// Individual branch transforms for breathing
|
|
238
|
+
const leftTransform = $derived(`translate(${-expansion}, 0)`);
|
|
239
|
+
const rightTransform = $derived(`translate(${expansion}, 0)`);
|
|
240
|
+
const topTransform = $derived(`translate(0, ${-expansion})`);
|
|
241
|
+
const topLeftTransform = $derived(`translate(${-diagExpansion}, ${-diagExpansion})`);
|
|
242
|
+
const topRightTransform = $derived(`translate(${diagExpansion}, ${-diagExpansion})`);
|
|
243
|
+
const bottomLeftTransform = $derived(`translate(${-diagExpansion}, ${diagExpansion})`);
|
|
244
|
+
const bottomRightTransform = $derived(`translate(${diagExpansion}, ${diagExpansion})`);
|
|
245
|
+
|
|
246
|
+
// Glow intensity for breathing (pulses with breath)
|
|
247
|
+
const glowIntensity = $derived(4 + $breathValue * 4);
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
// Decomposed foliage paths for breathing animation
|
|
251
|
+
// Each bar extends toward the center so they overlap at rest, forming the complete logo
|
|
252
|
+
// When expanded, the overlapping regions separate creating the burst effect
|
|
253
|
+
|
|
254
|
+
// Left horizontal bar - extends right to center, includes connection wedge
|
|
255
|
+
const leftBarPath = "M0 173.468 L171.476 173.468 L171.476 243.97 L0 243.97 Z";
|
|
256
|
+
|
|
257
|
+
// Right horizontal bar - extends left to center, includes connection wedge
|
|
258
|
+
const rightBarPath = "M245.562 173.268 L417 173.268 L417 243.77 L245.562 243.77 Z";
|
|
259
|
+
|
|
260
|
+
// Top vertical bar - extends down to center, includes connection wedge
|
|
261
|
+
const topBarPath = "M171.476 0 L245.562 0 L245.562 173.468 L171.476 173.468 Z";
|
|
262
|
+
|
|
263
|
+
// Top-left diagonal - arrow with extended inner edge
|
|
264
|
+
const topLeftDiagPath = "M171.476 173.468 L171.476 124.872 L86.037 37.043 L36.446 88.028 L126 173.468 Z";
|
|
265
|
+
|
|
266
|
+
// Top-right diagonal - arrow with extended inner edge
|
|
267
|
+
const topRightDiagPath = "M245.562 173.268 L245.562 124.872 L331 37.243 L380.552 88.028 L290.972 173.268 Z";
|
|
268
|
+
|
|
269
|
+
// Bottom-left diagonal - arrow with extended inner edge to center point
|
|
270
|
+
const bottomLeftDiagPath = "M171.476 243.97 L208.519 258.11 L86.037 381.192 L36.446 331.601 L126.664 243.97 Z";
|
|
271
|
+
|
|
272
|
+
// Bottom-right diagonal - arrow with extended inner edge to center point
|
|
273
|
+
const bottomRightDiagPath = "M245.562 243.77 L208.519 258.11 L331 381.192 L380.435 331.399 L290.252 243.77 Z";
|
|
274
|
+
|
|
275
|
+
// Full foliage path for non-breathing state
|
|
276
|
+
const fullFoliagePath = "M0 173.468h126.068l-89.622-85.44 49.591-50.985 85.439 87.829V0h74.086v124.872L331 37.243l49.552 50.785-89.58 85.24H417v70.502H290.252l90.183 87.629L331 381.192 208.519 258.11 86.037 381.192l-49.591-49.591 90.218-87.631H0v-70.502z";
|
|
277
|
+
</script>
|
|
278
|
+
|
|
279
|
+
<svg
|
|
280
|
+
class={className}
|
|
281
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
282
|
+
viewBox="0 -30 417 542.238"
|
|
283
|
+
aria-label="Grove logo"
|
|
284
|
+
>
|
|
285
|
+
<defs>
|
|
286
|
+
<!-- Main glass gradient for foliage -->
|
|
287
|
+
<linearGradient id="{uniqueId}-foliage-grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
288
|
+
<stop offset="0%" stop-color={variantColors.gradientStart} />
|
|
289
|
+
<stop offset="50%" stop-color={variantColors.gradientEnd} />
|
|
290
|
+
<stop offset="100%" stop-color={variantColors.gradientStart} />
|
|
291
|
+
</linearGradient>
|
|
292
|
+
|
|
293
|
+
<!-- Highlight gradient (top-left shine) -->
|
|
294
|
+
<linearGradient id="{uniqueId}-highlight" x1="0%" y1="0%" x2="50%" y2="50%">
|
|
295
|
+
<stop offset="0%" stop-color={variantColors.highlight} />
|
|
296
|
+
<stop offset="100%" stop-color="transparent" />
|
|
297
|
+
</linearGradient>
|
|
298
|
+
|
|
299
|
+
<!-- Trunk gradient -->
|
|
300
|
+
<linearGradient id="{uniqueId}-trunk-grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
301
|
+
<stop offset="0%" stop-color={variantColors.trunk} />
|
|
302
|
+
<stop offset="100%" stop-color={variantColors.trunk} stop-opacity="0.8" />
|
|
303
|
+
</linearGradient>
|
|
304
|
+
|
|
305
|
+
<!-- Soft glow filter -->
|
|
306
|
+
<filter id="{uniqueId}-glow" x="-30%" y="-30%" width="160%" height="160%">
|
|
307
|
+
<feGaussianBlur in="SourceGraphic" stdDeviation={glowIntensity} result="blur" />
|
|
308
|
+
<feFlood flood-color={variantColors.glowColor} />
|
|
309
|
+
<feComposite in2="blur" operator="in" />
|
|
310
|
+
<feMerge>
|
|
311
|
+
<feMergeNode />
|
|
312
|
+
<feMergeNode in="SourceGraphic" />
|
|
313
|
+
</feMerge>
|
|
314
|
+
</filter>
|
|
315
|
+
|
|
316
|
+
<!-- Inner shadow/depth filter -->
|
|
317
|
+
<filter id="{uniqueId}-inner-shadow" x="-10%" y="-10%" width="120%" height="120%">
|
|
318
|
+
<feOffset dx="2" dy="2" />
|
|
319
|
+
<feGaussianBlur stdDeviation="3" result="shadow" />
|
|
320
|
+
<feFlood flood-color={variantColors.shadow} />
|
|
321
|
+
<feComposite in2="shadow" operator="in" />
|
|
322
|
+
<feComposite in2="SourceGraphic" operator="over" />
|
|
323
|
+
</filter>
|
|
324
|
+
|
|
325
|
+
<!-- Glass edge highlight mask -->
|
|
326
|
+
<mask id="{uniqueId}-edge-mask">
|
|
327
|
+
<path d={fullFoliagePath} fill="white" />
|
|
328
|
+
</mask>
|
|
329
|
+
</defs>
|
|
330
|
+
|
|
331
|
+
<!-- Trunk with glass effect -->
|
|
332
|
+
<path
|
|
333
|
+
fill="url(#{uniqueId}-trunk-grad)"
|
|
334
|
+
d="M171.274 344.942h74.09v167.296h-74.09V344.942z"
|
|
335
|
+
filter="url(#{uniqueId}-inner-shadow)"
|
|
336
|
+
/>
|
|
337
|
+
|
|
338
|
+
{#if breathing}
|
|
339
|
+
<!-- Decomposed foliage with breathing animation - bars expand outward from center -->
|
|
340
|
+
<g filter="url(#{uniqueId}-glow)">
|
|
341
|
+
<!-- Left horizontal bar -->
|
|
342
|
+
<g transform={leftTransform}>
|
|
343
|
+
<path fill="url(#{uniqueId}-foliage-grad)" d={leftBarPath} />
|
|
344
|
+
</g>
|
|
345
|
+
|
|
346
|
+
<!-- Right horizontal bar -->
|
|
347
|
+
<g transform={rightTransform}>
|
|
348
|
+
<path fill="url(#{uniqueId}-foliage-grad)" d={rightBarPath} />
|
|
349
|
+
</g>
|
|
350
|
+
|
|
351
|
+
<!-- Top vertical bar -->
|
|
352
|
+
<g transform={topTransform}>
|
|
353
|
+
<path fill="url(#{uniqueId}-foliage-grad)" d={topBarPath} />
|
|
354
|
+
</g>
|
|
355
|
+
|
|
356
|
+
<!-- Top-left diagonal -->
|
|
357
|
+
<g transform={topLeftTransform}>
|
|
358
|
+
<path fill="url(#{uniqueId}-foliage-grad)" d={topLeftDiagPath} />
|
|
359
|
+
</g>
|
|
360
|
+
|
|
361
|
+
<!-- Top-right diagonal -->
|
|
362
|
+
<g transform={topRightTransform}>
|
|
363
|
+
<path fill="url(#{uniqueId}-foliage-grad)" d={topRightDiagPath} />
|
|
364
|
+
</g>
|
|
365
|
+
|
|
366
|
+
<!-- Bottom-left diagonal -->
|
|
367
|
+
<g transform={bottomLeftTransform}>
|
|
368
|
+
<path fill="url(#{uniqueId}-foliage-grad)" d={bottomLeftDiagPath} />
|
|
369
|
+
</g>
|
|
370
|
+
|
|
371
|
+
<!-- Bottom-right diagonal -->
|
|
372
|
+
<g transform={bottomRightTransform}>
|
|
373
|
+
<path fill="url(#{uniqueId}-foliage-grad)" d={bottomRightDiagPath} />
|
|
374
|
+
</g>
|
|
375
|
+
</g>
|
|
376
|
+
{:else}
|
|
377
|
+
<!-- Static foliage with glass effect -->
|
|
378
|
+
<g filter="url(#{uniqueId}-glow)">
|
|
379
|
+
<path
|
|
380
|
+
fill="url(#{uniqueId}-foliage-grad)"
|
|
381
|
+
d={fullFoliagePath}
|
|
382
|
+
/>
|
|
383
|
+
</g>
|
|
384
|
+
|
|
385
|
+
<!-- Top-left highlight/shine overlay -->
|
|
386
|
+
<path
|
|
387
|
+
d={fullFoliagePath}
|
|
388
|
+
fill="url(#{uniqueId}-highlight)"
|
|
389
|
+
opacity="0.5"
|
|
390
|
+
/>
|
|
391
|
+
|
|
392
|
+
<!-- Subtle edge highlight (inner stroke effect) -->
|
|
393
|
+
<path
|
|
394
|
+
d={fullFoliagePath}
|
|
395
|
+
fill="none"
|
|
396
|
+
stroke={variantColors.highlight}
|
|
397
|
+
stroke-width="2"
|
|
398
|
+
stroke-opacity="0.3"
|
|
399
|
+
/>
|
|
400
|
+
{/if}
|
|
401
|
+
|
|
402
|
+
<!-- Winter snow accents -->
|
|
403
|
+
{#if isWinter}
|
|
404
|
+
<!-- Top point snow cap -->
|
|
405
|
+
<ellipse fill={snowColor} cx="208" cy="8" rx="32" ry="10" opacity="0.85" />
|
|
406
|
+
|
|
407
|
+
<!-- Upper diagonal arm tips (the angled parts pointing up-left and up-right) -->
|
|
408
|
+
<ellipse fill={snowColor} cx="52" cy="60" rx="18" ry="6" opacity="0.7" transform="rotate(-25 52 60)" />
|
|
409
|
+
<ellipse fill={snowColor} cx="365" cy="60" rx="18" ry="6" opacity="0.7" transform="rotate(25 365 60)" />
|
|
410
|
+
|
|
411
|
+
<!-- Horizontal arm snow (left and right extending arms) -->
|
|
412
|
+
<ellipse fill={snowColor} cx="45" cy="175" rx="28" ry="7" opacity="0.75" />
|
|
413
|
+
<ellipse fill={snowColor} cx="372" cy="175" rx="28" ry="7" opacity="0.75" />
|
|
414
|
+
|
|
415
|
+
<!-- Center intersection snow pile -->
|
|
416
|
+
<ellipse fill={snowColor} cx="208" cy="175" rx="25" ry="8" opacity="0.6" />
|
|
417
|
+
|
|
418
|
+
<!-- Lower diagonal arm tips -->
|
|
419
|
+
<ellipse fill={snowColor} cx="95" cy="320" rx="16" ry="5" opacity="0.55" transform="rotate(25 95 320)" />
|
|
420
|
+
<ellipse fill={snowColor} cx="322" cy="320" rx="16" ry="5" opacity="0.55" transform="rotate(-25 322 320)" />
|
|
421
|
+
{/if}
|
|
422
|
+
</svg>
|
|
423
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type GlassVariant = "default" | "accent" | "frosted" | "dark" | "ethereal";
|
|
2
|
+
type Season = 'spring' | 'summer' | 'autumn' | 'winter';
|
|
3
|
+
type BreathingSpeed = 'slow' | 'normal' | 'fast';
|
|
4
|
+
interface Props {
|
|
5
|
+
class?: string;
|
|
6
|
+
/** Glass style variant */
|
|
7
|
+
variant?: GlassVariant;
|
|
8
|
+
/** Seasonal color theme - defaults to summer */
|
|
9
|
+
season?: Season;
|
|
10
|
+
/** Add breathing animation (for loading states) */
|
|
11
|
+
breathing?: boolean;
|
|
12
|
+
/** Breathing animation speed */
|
|
13
|
+
breathingSpeed?: BreathingSpeed;
|
|
14
|
+
/** Whether trunk should match foliage color */
|
|
15
|
+
monochrome?: boolean;
|
|
16
|
+
/** Custom accent color (CSS color value) - only applies when season is not set */
|
|
17
|
+
accentColor?: string;
|
|
18
|
+
/** Unique ID for SVG filters (auto-generated if not provided) */
|
|
19
|
+
filterId?: string;
|
|
20
|
+
}
|
|
21
|
+
declare const GlassLogo: import("svelte").Component<Props, {}, "">;
|
|
22
|
+
type GlassLogo = ReturnType<typeof GlassLogo>;
|
|
23
|
+
export default GlassLogo;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import { cn } from "../../utils";
|
|
4
|
+
import Logo from "./Logo.svelte";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* GlassNavbar - A sticky glassmorphism navigation bar
|
|
8
|
+
*
|
|
9
|
+
* A reusable navigation component with glass styling that can be used
|
|
10
|
+
* across Grove properties (landing, plant, etc.)
|
|
11
|
+
*
|
|
12
|
+
* @example Basic usage
|
|
13
|
+
* ```svelte
|
|
14
|
+
* <GlassNavbar logoHref="https://grove.place" title="Grove" />
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @example With custom content
|
|
18
|
+
* ```svelte
|
|
19
|
+
* <GlassNavbar logoHref="/" title="Grove">
|
|
20
|
+
* {#snippet actions()}
|
|
21
|
+
* <ThemeToggle />
|
|
22
|
+
* {/snippet}
|
|
23
|
+
* </GlassNavbar>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
interface Props {
|
|
28
|
+
/** URL the logo links to */
|
|
29
|
+
logoHref?: string;
|
|
30
|
+
/** Title text next to logo */
|
|
31
|
+
title?: string;
|
|
32
|
+
/** Whether to show the title text */
|
|
33
|
+
showTitle?: boolean;
|
|
34
|
+
/** Max width constraint */
|
|
35
|
+
maxWidth?: 'narrow' | 'default' | 'wide';
|
|
36
|
+
/** Additional CSS classes */
|
|
37
|
+
class?: string;
|
|
38
|
+
/** Slot for navigation items */
|
|
39
|
+
navigation?: Snippet;
|
|
40
|
+
/** Slot for action items (right side) */
|
|
41
|
+
actions?: Snippet;
|
|
42
|
+
/** Callback when logo is clicked */
|
|
43
|
+
onLogoClick?: () => void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let {
|
|
47
|
+
logoHref = "/",
|
|
48
|
+
title = "Grove",
|
|
49
|
+
showTitle = true,
|
|
50
|
+
maxWidth = 'default',
|
|
51
|
+
class: className,
|
|
52
|
+
navigation,
|
|
53
|
+
actions,
|
|
54
|
+
onLogoClick
|
|
55
|
+
}: Props = $props();
|
|
56
|
+
|
|
57
|
+
const maxWidthClass = {
|
|
58
|
+
narrow: 'max-w-2xl',
|
|
59
|
+
default: 'max-w-4xl',
|
|
60
|
+
wide: 'max-w-5xl'
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
function handleLogoClick(e: MouseEvent) {
|
|
64
|
+
if (onLogoClick) {
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
onLogoClick();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<header
|
|
72
|
+
class={cn(
|
|
73
|
+
"sticky top-0 z-40 py-4 px-6",
|
|
74
|
+
"bg-white/60 dark:bg-emerald-950/25 backdrop-blur-md",
|
|
75
|
+
"border-b border-white/40 dark:border-emerald-800/25",
|
|
76
|
+
className
|
|
77
|
+
)}
|
|
78
|
+
>
|
|
79
|
+
<div class="{maxWidthClass[maxWidth]} mx-auto flex items-center justify-between">
|
|
80
|
+
<!-- Logo area -->
|
|
81
|
+
<div class="flex items-center gap-2">
|
|
82
|
+
{#if onLogoClick}
|
|
83
|
+
<button
|
|
84
|
+
onclick={handleLogoClick}
|
|
85
|
+
class="flex-shrink-0 transition-transform hover:scale-110 active:scale-95"
|
|
86
|
+
aria-label="Go to homepage"
|
|
87
|
+
>
|
|
88
|
+
<Logo class="w-7 h-7" />
|
|
89
|
+
</button>
|
|
90
|
+
{:else}
|
|
91
|
+
<a href={logoHref} class="flex-shrink-0 transition-transform hover:scale-105">
|
|
92
|
+
<Logo class="w-7 h-7" />
|
|
93
|
+
</a>
|
|
94
|
+
{/if}
|
|
95
|
+
|
|
96
|
+
{#if showTitle}
|
|
97
|
+
<a
|
|
98
|
+
href={logoHref}
|
|
99
|
+
class="text-lg font-medium text-foreground hover:text-primary transition-colors"
|
|
100
|
+
>
|
|
101
|
+
{title}
|
|
102
|
+
</a>
|
|
103
|
+
{/if}
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<!-- Navigation (center or left of actions) -->
|
|
107
|
+
{#if navigation}
|
|
108
|
+
<nav class="hidden md:flex items-center gap-4 lg:gap-6 text-sm">
|
|
109
|
+
{@render navigation()}
|
|
110
|
+
</nav>
|
|
111
|
+
{/if}
|
|
112
|
+
|
|
113
|
+
<!-- Actions (right side) -->
|
|
114
|
+
{#if actions}
|
|
115
|
+
<div class="flex items-center gap-2">
|
|
116
|
+
{@render actions()}
|
|
117
|
+
</div>
|
|
118
|
+
{/if}
|
|
119
|
+
</div>
|
|
120
|
+
</header>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
/**
|
|
3
|
+
* GlassNavbar - A sticky glassmorphism navigation bar
|
|
4
|
+
*
|
|
5
|
+
* A reusable navigation component with glass styling that can be used
|
|
6
|
+
* across Grove properties (landing, plant, etc.)
|
|
7
|
+
*
|
|
8
|
+
* @example Basic usage
|
|
9
|
+
* ```svelte
|
|
10
|
+
* <GlassNavbar logoHref="https://grove.place" title="Grove" />
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* @example With custom content
|
|
14
|
+
* ```svelte
|
|
15
|
+
* <GlassNavbar logoHref="/" title="Grove">
|
|
16
|
+
* {#snippet actions()}
|
|
17
|
+
* <ThemeToggle />
|
|
18
|
+
* {/snippet}
|
|
19
|
+
* </GlassNavbar>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
interface Props {
|
|
23
|
+
/** URL the logo links to */
|
|
24
|
+
logoHref?: string;
|
|
25
|
+
/** Title text next to logo */
|
|
26
|
+
title?: string;
|
|
27
|
+
/** Whether to show the title text */
|
|
28
|
+
showTitle?: boolean;
|
|
29
|
+
/** Max width constraint */
|
|
30
|
+
maxWidth?: 'narrow' | 'default' | 'wide';
|
|
31
|
+
/** Additional CSS classes */
|
|
32
|
+
class?: string;
|
|
33
|
+
/** Slot for navigation items */
|
|
34
|
+
navigation?: Snippet;
|
|
35
|
+
/** Slot for action items (right side) */
|
|
36
|
+
actions?: Snippet;
|
|
37
|
+
/** Callback when logo is clicked */
|
|
38
|
+
onLogoClick?: () => void;
|
|
39
|
+
}
|
|
40
|
+
declare const GlassNavbar: import("svelte").Component<Props, {}, "">;
|
|
41
|
+
type GlassNavbar = ReturnType<typeof GlassNavbar>;
|
|
42
|
+
export default GlassNavbar;
|