@autumnsgrove/groveengine 0.6.5 → 0.8.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.
- package/LICENSE +378 -0
- package/dist/auth/index.d.ts +1 -2
- package/dist/auth/index.js +8 -4
- package/dist/auth/session.d.ts +12 -31
- package/dist/auth/session.js +5 -103
- package/dist/components/custom/ContentWithGutter.svelte +22 -25
- 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 +224 -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 +491 -0
- package/dist/ui/components/nature/palette.js +384 -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/ui/Glass.svelte +158 -0
- package/dist/ui/components/ui/Glass.svelte.d.ts +52 -0
- package/dist/ui/components/ui/GlassButton.svelte +157 -0
- package/dist/ui/components/ui/GlassButton.svelte.d.ts +39 -0
- package/dist/ui/components/ui/GlassCard.svelte +160 -0
- package/dist/ui/components/ui/GlassCard.svelte.d.ts +39 -0
- package/dist/ui/components/ui/GlassConfirmDialog.svelte +208 -0
- package/dist/ui/components/ui/GlassConfirmDialog.svelte.d.ts +52 -0
- package/dist/ui/components/ui/GlassLogo.svelte +422 -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 +93 -0
- package/dist/ui/components/ui/GlassOverlay.svelte.d.ts +33 -0
- 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 +7 -0
- package/dist/ui/components/ui/index.js +8 -0
- package/dist/ui/styles/grove.css +151 -1
- package/dist/utils/gutter.d.ts +2 -8
- package/dist/utils/markdown.d.ts +1 -0
- package/dist/utils/markdown.js +32 -11
- package/package.json +31 -22
- package/static/fonts/alagard.ttf +0 -0
- package/static/robots.txt +34 -1
- package/dist/auth/jwt.d.ts +0 -20
- package/dist/auth/jwt.js +0 -123
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Grove — A place to Be
|
|
3
|
+
Copyright (c) 2025 Autumn Brown
|
|
4
|
+
Licensed under AGPL-3.0
|
|
5
|
+
-->
|
|
6
|
+
<script lang="ts">
|
|
7
|
+
import { winter } from '../palette';
|
|
8
|
+
|
|
9
|
+
type SnowflakeVariant = 'crystal' | 'simple' | 'star' | 'delicate' | 'dot';
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
class?: string;
|
|
13
|
+
color?: string;
|
|
14
|
+
variant?: SnowflakeVariant;
|
|
15
|
+
/** Opacity for depth effect */
|
|
16
|
+
opacity?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
class: className = 'w-4 h-4',
|
|
21
|
+
color = winter.snow,
|
|
22
|
+
variant = 'crystal',
|
|
23
|
+
opacity = 1
|
|
24
|
+
}: Props = $props();
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<!-- Snowflake - various crystalline shapes -->
|
|
28
|
+
<svg
|
|
29
|
+
class={className}
|
|
30
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
31
|
+
viewBox="0 0 40 40"
|
|
32
|
+
style="opacity: {opacity};"
|
|
33
|
+
>
|
|
34
|
+
{#if variant === 'crystal'}
|
|
35
|
+
<!-- Classic 6-pointed crystal snowflake -->
|
|
36
|
+
<g fill="none" stroke={color} stroke-width="1.5" stroke-linecap="round">
|
|
37
|
+
<!-- Main axes -->
|
|
38
|
+
<line x1="20" y1="4" x2="20" y2="36" />
|
|
39
|
+
<line x1="6" y1="12" x2="34" y2="28" />
|
|
40
|
+
<line x1="6" y1="28" x2="34" y2="12" />
|
|
41
|
+
<!-- Branch details on vertical axis -->
|
|
42
|
+
<line x1="20" y1="8" x2="16" y2="12" />
|
|
43
|
+
<line x1="20" y1="8" x2="24" y2="12" />
|
|
44
|
+
<line x1="20" y1="32" x2="16" y2="28" />
|
|
45
|
+
<line x1="20" y1="32" x2="24" y2="28" />
|
|
46
|
+
<!-- Branch details on diagonal axes -->
|
|
47
|
+
<line x1="10" y1="14" x2="12" y2="10" />
|
|
48
|
+
<line x1="10" y1="14" x2="8" y2="18" />
|
|
49
|
+
<line x1="30" y1="26" x2="28" y2="30" />
|
|
50
|
+
<line x1="30" y1="26" x2="32" y2="22" />
|
|
51
|
+
<line x1="10" y1="26" x2="12" y2="30" />
|
|
52
|
+
<line x1="10" y1="26" x2="8" y2="22" />
|
|
53
|
+
<line x1="30" y1="14" x2="28" y2="10" />
|
|
54
|
+
<line x1="30" y1="14" x2="32" y2="18" />
|
|
55
|
+
</g>
|
|
56
|
+
<!-- Center crystal -->
|
|
57
|
+
<circle fill={color} cx="20" cy="20" r="2" />
|
|
58
|
+
{:else if variant === 'simple'}
|
|
59
|
+
<!-- Simple 6-pointed star snowflake -->
|
|
60
|
+
<g fill="none" stroke={color} stroke-width="2" stroke-linecap="round">
|
|
61
|
+
<line x1="20" y1="5" x2="20" y2="35" />
|
|
62
|
+
<line x1="7" y1="12.5" x2="33" y2="27.5" />
|
|
63
|
+
<line x1="7" y1="27.5" x2="33" y2="12.5" />
|
|
64
|
+
</g>
|
|
65
|
+
<circle fill={color} cx="20" cy="20" r="3" />
|
|
66
|
+
{:else if variant === 'star'}
|
|
67
|
+
<!-- Decorative star snowflake with filled points -->
|
|
68
|
+
<polygon
|
|
69
|
+
fill={color}
|
|
70
|
+
points="20,2 22,15 35,12 25,20 35,28 22,25 20,38 18,25 5,28 15,20 5,12 18,15"
|
|
71
|
+
/>
|
|
72
|
+
<circle fill={color} cx="20" cy="20" r="4" opacity="0.8" />
|
|
73
|
+
{:else if variant === 'delicate'}
|
|
74
|
+
<!-- Delicate branching snowflake -->
|
|
75
|
+
<g fill="none" stroke={color} stroke-width="1" stroke-linecap="round">
|
|
76
|
+
<!-- Main spokes -->
|
|
77
|
+
<line x1="20" y1="4" x2="20" y2="36" />
|
|
78
|
+
<line x1="6" y1="12" x2="34" y2="28" />
|
|
79
|
+
<line x1="6" y1="28" x2="34" y2="12" />
|
|
80
|
+
<!-- Delicate inner branches -->
|
|
81
|
+
<line x1="20" y1="10" x2="14" y2="13" />
|
|
82
|
+
<line x1="20" y1="10" x2="26" y2="13" />
|
|
83
|
+
<line x1="20" y1="30" x2="14" y2="27" />
|
|
84
|
+
<line x1="20" y1="30" x2="26" y2="27" />
|
|
85
|
+
<!-- Tiny end crystals -->
|
|
86
|
+
<circle cx="20" cy="4" r="1.5" fill={color} />
|
|
87
|
+
<circle cx="20" cy="36" r="1.5" fill={color} />
|
|
88
|
+
<circle cx="6" cy="12" r="1.5" fill={color} />
|
|
89
|
+
<circle cx="34" cy="28" r="1.5" fill={color} />
|
|
90
|
+
<circle cx="6" cy="28" r="1.5" fill={color} />
|
|
91
|
+
<circle cx="34" cy="12" r="1.5" fill={color} />
|
|
92
|
+
</g>
|
|
93
|
+
<circle fill={color} cx="20" cy="20" r="2.5" />
|
|
94
|
+
{:else if variant === 'dot'}
|
|
95
|
+
<!-- Simple snow dot/orb (for distant flakes) -->
|
|
96
|
+
<circle fill={color} cx="20" cy="20" r="8" />
|
|
97
|
+
<circle fill="white" cx="17" cy="17" r="2" opacity="0.6" />
|
|
98
|
+
{/if}
|
|
99
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type SnowflakeVariant = 'crystal' | 'simple' | 'star' | 'delicate' | 'dot';
|
|
2
|
+
interface Props {
|
|
3
|
+
class?: string;
|
|
4
|
+
color?: string;
|
|
5
|
+
variant?: SnowflakeVariant;
|
|
6
|
+
/** Opacity for depth effect */
|
|
7
|
+
opacity?: number;
|
|
8
|
+
}
|
|
9
|
+
declare const Snowflake: import("svelte").Component<Props, {}, "">;
|
|
10
|
+
type Snowflake = ReturnType<typeof Snowflake>;
|
|
11
|
+
export default Snowflake;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Grove — A place to Be
|
|
3
|
+
Copyright (c) 2025 Autumn Brown
|
|
4
|
+
Licensed under AGPL-3.0
|
|
5
|
+
-->
|
|
6
|
+
<script lang="ts">
|
|
7
|
+
import { winter } from '../palette';
|
|
8
|
+
import Snowflake from './Snowflake.svelte';
|
|
9
|
+
import { browser } from '$app/environment';
|
|
10
|
+
|
|
11
|
+
type SnowflakeVariant = 'crystal' | 'simple' | 'star' | 'delicate' | 'dot';
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
class?: string;
|
|
15
|
+
color?: string;
|
|
16
|
+
variant?: SnowflakeVariant;
|
|
17
|
+
/** Fall animation duration in seconds */
|
|
18
|
+
duration?: number;
|
|
19
|
+
/** Animation delay in seconds */
|
|
20
|
+
delay?: number;
|
|
21
|
+
/** Horizontal drift amount in vw units */
|
|
22
|
+
drift?: number;
|
|
23
|
+
/** Vertical fall distance in vh units */
|
|
24
|
+
fallDistance?: number;
|
|
25
|
+
/** Enable falling animation */
|
|
26
|
+
animate?: boolean;
|
|
27
|
+
/** Random seed for rotation variation */
|
|
28
|
+
seed?: number;
|
|
29
|
+
/** Opacity for depth effect */
|
|
30
|
+
opacity?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let {
|
|
34
|
+
class: className = 'w-4 h-4',
|
|
35
|
+
color = winter.snow,
|
|
36
|
+
variant = 'crystal',
|
|
37
|
+
duration = 12,
|
|
38
|
+
delay = 0,
|
|
39
|
+
drift = 0,
|
|
40
|
+
fallDistance = 100,
|
|
41
|
+
animate = true,
|
|
42
|
+
seed = 0,
|
|
43
|
+
opacity = 1
|
|
44
|
+
}: Props = $props();
|
|
45
|
+
|
|
46
|
+
// Deterministic rotation based on seed - gentle swaying for snow
|
|
47
|
+
const initialRotation = $derived((seed * 37) % 360);
|
|
48
|
+
const rotationDirection = $derived(seed % 2 === 0 ? 1 : -1);
|
|
49
|
+
const rotationAmount = $derived(180 + (seed % 180)); // 180-360 degrees total rotation - gentler than petals
|
|
50
|
+
|
|
51
|
+
// Gentle horizontal sway - snow drifts more subtly than petals
|
|
52
|
+
const swayAmplitude = $derived(40 + (seed % 60)); // 40-100px horizontal sway - lighter than petals
|
|
53
|
+
const swayFrequency = $derived(1 + (seed % 3)); // 1-3 complete waves during fall - fewer than petals
|
|
54
|
+
|
|
55
|
+
// Unique animation name to prevent conflicts
|
|
56
|
+
const animId = $derived(`snow-${seed}`);
|
|
57
|
+
|
|
58
|
+
// Inject dynamic keyframes at runtime
|
|
59
|
+
$effect(() => {
|
|
60
|
+
if (!browser || !animate) return;
|
|
61
|
+
|
|
62
|
+
const styleId = `snow-style-${seed}`;
|
|
63
|
+
// Check if already injected
|
|
64
|
+
if (document.getElementById(styleId)) return;
|
|
65
|
+
|
|
66
|
+
const style = document.createElement('style');
|
|
67
|
+
style.id = styleId;
|
|
68
|
+
// Create gentle drifting motion with sine wave horizontal movement
|
|
69
|
+
// Snowflakes are lighter and more delicate than petals
|
|
70
|
+
style.textContent = `
|
|
71
|
+
@keyframes ${animId}-fall {
|
|
72
|
+
0% {
|
|
73
|
+
transform: translateY(0) translateX(0) rotate(${initialRotation}deg);
|
|
74
|
+
opacity: 0;
|
|
75
|
+
}
|
|
76
|
+
5% {
|
|
77
|
+
opacity: ${opacity};
|
|
78
|
+
}
|
|
79
|
+
12.5% {
|
|
80
|
+
transform: translateY(${fallDistance * 0.125}vh) translateX(${Math.sin(Math.PI * 0.25 * swayFrequency) * swayAmplitude + drift * 0.125}px) rotate(${initialRotation + rotationAmount * rotationDirection * 0.125}deg);
|
|
81
|
+
}
|
|
82
|
+
25% {
|
|
83
|
+
transform: translateY(${fallDistance * 0.25}vh) translateX(${Math.sin(Math.PI * 0.5 * swayFrequency) * swayAmplitude + drift * 0.25}px) rotate(${initialRotation + rotationAmount * rotationDirection * 0.25}deg);
|
|
84
|
+
}
|
|
85
|
+
37.5% {
|
|
86
|
+
transform: translateY(${fallDistance * 0.375}vh) translateX(${Math.sin(Math.PI * 0.75 * swayFrequency) * swayAmplitude + drift * 0.375}px) rotate(${initialRotation + rotationAmount * rotationDirection * 0.375}deg);
|
|
87
|
+
}
|
|
88
|
+
50% {
|
|
89
|
+
transform: translateY(${fallDistance * 0.5}vh) translateX(${Math.sin(Math.PI * swayFrequency) * swayAmplitude + drift * 0.5}px) rotate(${initialRotation + rotationAmount * rotationDirection * 0.5}deg);
|
|
90
|
+
}
|
|
91
|
+
62.5% {
|
|
92
|
+
transform: translateY(${fallDistance * 0.625}vh) translateX(${Math.sin(Math.PI * 1.25 * swayFrequency) * swayAmplitude + drift * 0.625}px) rotate(${initialRotation + rotationAmount * rotationDirection * 0.625}deg);
|
|
93
|
+
}
|
|
94
|
+
75% {
|
|
95
|
+
transform: translateY(${fallDistance * 0.75}vh) translateX(${Math.sin(Math.PI * 1.5 * swayFrequency) * swayAmplitude + drift * 0.75}px) rotate(${initialRotation + rotationAmount * rotationDirection * 0.75}deg);
|
|
96
|
+
}
|
|
97
|
+
87.5% {
|
|
98
|
+
transform: translateY(${fallDistance * 0.875}vh) translateX(${Math.sin(Math.PI * 1.75 * swayFrequency) * swayAmplitude + drift * 0.875}px) rotate(${initialRotation + rotationAmount * rotationDirection * 0.875}deg);
|
|
99
|
+
}
|
|
100
|
+
95% {
|
|
101
|
+
opacity: ${opacity};
|
|
102
|
+
}
|
|
103
|
+
100% {
|
|
104
|
+
transform: translateY(${fallDistance}vh) translateX(${Math.sin(Math.PI * 2 * swayFrequency) * swayAmplitude + drift}px) rotate(${initialRotation + rotationAmount * rotationDirection}deg);
|
|
105
|
+
opacity: 0;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
@keyframes ${animId}-flutter {
|
|
109
|
+
0%, 100% {
|
|
110
|
+
transform: rotateX(0deg) rotateY(0deg) scale(1);
|
|
111
|
+
}
|
|
112
|
+
20% {
|
|
113
|
+
transform: rotateX(20deg) rotateY(25deg) scale(0.95);
|
|
114
|
+
}
|
|
115
|
+
40% {
|
|
116
|
+
transform: rotateX(-15deg) rotateY(-20deg) scale(1.05);
|
|
117
|
+
}
|
|
118
|
+
60% {
|
|
119
|
+
transform: rotateX(25deg) rotateY(20deg) scale(0.92);
|
|
120
|
+
}
|
|
121
|
+
80% {
|
|
122
|
+
transform: rotateX(-20deg) rotateY(-25deg) scale(1.03);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
126
|
+
document.head.appendChild(style);
|
|
127
|
+
|
|
128
|
+
return () => {
|
|
129
|
+
// Cleanup on component destroy
|
|
130
|
+
const el = document.getElementById(styleId);
|
|
131
|
+
if (el) el.remove();
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
</script>
|
|
135
|
+
|
|
136
|
+
<!-- Snowflake - delicate and drifting -->
|
|
137
|
+
<!-- Wrapper div for fall animation (translateY/X/rotate), inner div for flutter (3D rotations) -->
|
|
138
|
+
<div
|
|
139
|
+
class="snowflake-wrapper"
|
|
140
|
+
style="{animate ? `animation: ${animId}-fall ${duration}s linear ${delay}s infinite;` : `opacity: ${opacity};`}"
|
|
141
|
+
>
|
|
142
|
+
<div
|
|
143
|
+
class="snowflake-flutter"
|
|
144
|
+
style="{animate ? `animation: ${animId}-flutter ${duration / 3}s ease-in-out ${delay}s infinite;` : ''}"
|
|
145
|
+
>
|
|
146
|
+
<Snowflake class={className} {color} {variant} opacity={1} />
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<style>
|
|
151
|
+
/* Dynamic keyframes are injected via $effect */
|
|
152
|
+
.snowflake-wrapper {
|
|
153
|
+
display: inline-block;
|
|
154
|
+
will-change: transform, opacity;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.snowflake-flutter {
|
|
158
|
+
display: inline-block;
|
|
159
|
+
transform-style: preserve-3d;
|
|
160
|
+
will-change: transform;
|
|
161
|
+
}
|
|
162
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type SnowflakeVariant = 'crystal' | 'simple' | 'star' | 'delicate' | 'dot';
|
|
2
|
+
interface Props {
|
|
3
|
+
class?: string;
|
|
4
|
+
color?: string;
|
|
5
|
+
variant?: SnowflakeVariant;
|
|
6
|
+
/** Fall animation duration in seconds */
|
|
7
|
+
duration?: number;
|
|
8
|
+
/** Animation delay in seconds */
|
|
9
|
+
delay?: number;
|
|
10
|
+
/** Horizontal drift amount in vw units */
|
|
11
|
+
drift?: number;
|
|
12
|
+
/** Vertical fall distance in vh units */
|
|
13
|
+
fallDistance?: number;
|
|
14
|
+
/** Enable falling animation */
|
|
15
|
+
animate?: boolean;
|
|
16
|
+
/** Random seed for rotation variation */
|
|
17
|
+
seed?: number;
|
|
18
|
+
/** Opacity for depth effect */
|
|
19
|
+
opacity?: number;
|
|
20
|
+
}
|
|
21
|
+
declare const SnowflakeFalling: import("svelte").Component<Props, {}, "">;
|
|
22
|
+
type SnowflakeFalling = ReturnType<typeof SnowflakeFalling>;
|
|
23
|
+
export default SnowflakeFalling;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
4
|
+
import { cn } from "../../utils";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Glass component for creating glassmorphism effects
|
|
8
|
+
*
|
|
9
|
+
* A reusable component that provides translucent, frosted-glass effects
|
|
10
|
+
* perfect for overlays, cards, navbars, and text containers while
|
|
11
|
+
* maintaining visibility of background elements.
|
|
12
|
+
*
|
|
13
|
+
* @example Basic usage
|
|
14
|
+
* ```svelte
|
|
15
|
+
* <Glass variant="card">
|
|
16
|
+
* <p>Content with glass background</p>
|
|
17
|
+
* </Glass>
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @example As a navbar
|
|
21
|
+
* ```svelte
|
|
22
|
+
* <Glass variant="surface" as="header" class="sticky top-0">
|
|
23
|
+
* <nav>...</nav>
|
|
24
|
+
* </Glass>
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @example Accent tint for callouts
|
|
28
|
+
* ```svelte
|
|
29
|
+
* <Glass variant="accent" intensity="light" class="p-6 rounded-xl">
|
|
30
|
+
* <p>Important message here</p>
|
|
31
|
+
* </Glass>
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
type Variant =
|
|
36
|
+
| "surface" // Headers, navbars - high opacity, subtle blur
|
|
37
|
+
| "overlay" // Modal backdrops - dark, medium blur
|
|
38
|
+
| "card" // Content cards - medium opacity, clean look
|
|
39
|
+
| "tint" // Text containers - light background for readability
|
|
40
|
+
| "accent" // Accent-colored glass for callouts/highlights
|
|
41
|
+
| "muted"; // Subtle background, barely visible
|
|
42
|
+
|
|
43
|
+
type Intensity =
|
|
44
|
+
| "none" // No blur (just transparency)
|
|
45
|
+
| "light" // backdrop-blur-sm (4px)
|
|
46
|
+
| "medium" // backdrop-blur (8px)
|
|
47
|
+
| "strong"; // backdrop-blur-md (12px)
|
|
48
|
+
|
|
49
|
+
type Element = "div" | "section" | "article" | "aside" | "header" | "footer" | "nav" | "main";
|
|
50
|
+
|
|
51
|
+
interface Props extends HTMLAttributes<HTMLElement> {
|
|
52
|
+
/** Visual style variant */
|
|
53
|
+
variant?: Variant;
|
|
54
|
+
/** Blur intensity */
|
|
55
|
+
intensity?: Intensity;
|
|
56
|
+
/** HTML element to render */
|
|
57
|
+
as?: Element;
|
|
58
|
+
/** Include subtle border */
|
|
59
|
+
border?: boolean;
|
|
60
|
+
/** Include shadow */
|
|
61
|
+
shadow?: boolean;
|
|
62
|
+
/** Additional CSS classes */
|
|
63
|
+
class?: string;
|
|
64
|
+
/** Content */
|
|
65
|
+
children?: Snippet;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let {
|
|
69
|
+
variant = "card",
|
|
70
|
+
intensity = "light",
|
|
71
|
+
as: element = "div",
|
|
72
|
+
border = true,
|
|
73
|
+
shadow = false,
|
|
74
|
+
class: className,
|
|
75
|
+
children,
|
|
76
|
+
...restProps
|
|
77
|
+
}: Props = $props();
|
|
78
|
+
|
|
79
|
+
// Background colors per variant - warm grove tones, translucent for glass effect
|
|
80
|
+
const variantClasses: Record<Variant, string> = {
|
|
81
|
+
// High opacity for sticky headers/navbars (uses background color)
|
|
82
|
+
surface: "bg-background/90 dark:bg-background/90",
|
|
83
|
+
|
|
84
|
+
// Dark overlay for modals/sheets
|
|
85
|
+
overlay: "bg-black/50 dark:bg-black/60",
|
|
86
|
+
|
|
87
|
+
// Medium opacity for content cards - translucent with grove warmth
|
|
88
|
+
card: "bg-white/60 dark:bg-emerald-950/25",
|
|
89
|
+
|
|
90
|
+
// Light tint for text readability
|
|
91
|
+
tint: "bg-white/50 dark:bg-emerald-950/20",
|
|
92
|
+
|
|
93
|
+
// Accent-colored glass for highlights/callouts
|
|
94
|
+
accent: "bg-accent/25 dark:bg-accent/15",
|
|
95
|
+
|
|
96
|
+
// Barely visible, very subtle
|
|
97
|
+
muted: "bg-white/30 dark:bg-emerald-950/15"
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Blur intensity classes - default to medium blur for true glass effect
|
|
101
|
+
const intensityClasses: Record<Intensity, string> = {
|
|
102
|
+
none: "",
|
|
103
|
+
light: "backdrop-blur", // 8px
|
|
104
|
+
medium: "backdrop-blur-md", // 12px
|
|
105
|
+
strong: "backdrop-blur-lg" // 16px
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Border classes per variant - subtle borders that complement the glass
|
|
109
|
+
const borderClasses: Record<Variant, string> = {
|
|
110
|
+
surface: "border-border",
|
|
111
|
+
overlay: "border-white/10",
|
|
112
|
+
card: "border-white/40 dark:border-emerald-800/25",
|
|
113
|
+
tint: "border-white/30 dark:border-emerald-800/20",
|
|
114
|
+
accent: "border-accent/30 dark:border-accent/20",
|
|
115
|
+
muted: "border-white/20 dark:border-emerald-800/15"
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Shadow classes
|
|
119
|
+
const shadowClasses: Record<Variant, string> = {
|
|
120
|
+
surface: "shadow-sm",
|
|
121
|
+
overlay: "shadow-2xl",
|
|
122
|
+
card: "shadow-sm",
|
|
123
|
+
tint: "shadow-sm",
|
|
124
|
+
accent: "shadow-sm",
|
|
125
|
+
muted: ""
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const computedClass = $derived(
|
|
129
|
+
cn(
|
|
130
|
+
variantClasses[variant],
|
|
131
|
+
intensityClasses[intensity],
|
|
132
|
+
border && `border ${borderClasses[variant]}`,
|
|
133
|
+
shadow && shadowClasses[variant],
|
|
134
|
+
className
|
|
135
|
+
)
|
|
136
|
+
);
|
|
137
|
+
</script>
|
|
138
|
+
|
|
139
|
+
<!--
|
|
140
|
+
Glassmorphism component for Grove
|
|
141
|
+
|
|
142
|
+
CSS Properties used:
|
|
143
|
+
- backdrop-filter: blur() - Creates the frosted glass effect
|
|
144
|
+
- Background with alpha - Semi-transparent backgrounds (e.g., bg-white/80)
|
|
145
|
+
- Border with alpha - Subtle borders that complement the glass effect
|
|
146
|
+
|
|
147
|
+
Browser Support:
|
|
148
|
+
- backdrop-filter is supported in all modern browsers
|
|
149
|
+
- Falls back gracefully to solid backgrounds in older browsers
|
|
150
|
+
-->
|
|
151
|
+
|
|
152
|
+
<svelte:element
|
|
153
|
+
this={element}
|
|
154
|
+
class={computedClass}
|
|
155
|
+
{...restProps}
|
|
156
|
+
>
|
|
157
|
+
{#if children}{@render children()}{/if}
|
|
158
|
+
</svelte:element>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
/**
|
|
4
|
+
* Glass component for creating glassmorphism effects
|
|
5
|
+
*
|
|
6
|
+
* A reusable component that provides translucent, frosted-glass effects
|
|
7
|
+
* perfect for overlays, cards, navbars, and text containers while
|
|
8
|
+
* maintaining visibility of background elements.
|
|
9
|
+
*
|
|
10
|
+
* @example Basic usage
|
|
11
|
+
* ```svelte
|
|
12
|
+
* <Glass variant="card">
|
|
13
|
+
* <p>Content with glass background</p>
|
|
14
|
+
* </Glass>
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @example As a navbar
|
|
18
|
+
* ```svelte
|
|
19
|
+
* <Glass variant="surface" as="header" class="sticky top-0">
|
|
20
|
+
* <nav>...</nav>
|
|
21
|
+
* </Glass>
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example Accent tint for callouts
|
|
25
|
+
* ```svelte
|
|
26
|
+
* <Glass variant="accent" intensity="light" class="p-6 rounded-xl">
|
|
27
|
+
* <p>Important message here</p>
|
|
28
|
+
* </Glass>
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
type Variant = "surface" | "overlay" | "card" | "tint" | "accent" | "muted";
|
|
32
|
+
type Intensity = "none" | "light" | "medium" | "strong";
|
|
33
|
+
type Element = "div" | "section" | "article" | "aside" | "header" | "footer" | "nav" | "main";
|
|
34
|
+
interface Props extends HTMLAttributes<HTMLElement> {
|
|
35
|
+
/** Visual style variant */
|
|
36
|
+
variant?: Variant;
|
|
37
|
+
/** Blur intensity */
|
|
38
|
+
intensity?: Intensity;
|
|
39
|
+
/** HTML element to render */
|
|
40
|
+
as?: Element;
|
|
41
|
+
/** Include subtle border */
|
|
42
|
+
border?: boolean;
|
|
43
|
+
/** Include shadow */
|
|
44
|
+
shadow?: boolean;
|
|
45
|
+
/** Additional CSS classes */
|
|
46
|
+
class?: string;
|
|
47
|
+
/** Content */
|
|
48
|
+
children?: Snippet;
|
|
49
|
+
}
|
|
50
|
+
declare const Glass: import("svelte").Component<Props, {}, "">;
|
|
51
|
+
type Glass = ReturnType<typeof Glass>;
|
|
52
|
+
export default Glass;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import type { HTMLButtonAttributes, HTMLAnchorAttributes } from "svelte/elements";
|
|
4
|
+
import { cn } from "../../utils";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* GlassButton - A button with glassmorphism styling
|
|
8
|
+
*
|
|
9
|
+
* Beautiful translucent buttons with backdrop blur effects.
|
|
10
|
+
* Perfect for floating actions, overlays, and modern UI designs.
|
|
11
|
+
*
|
|
12
|
+
* @example Basic glass button
|
|
13
|
+
* ```svelte
|
|
14
|
+
* <GlassButton>Click me</GlassButton>
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @example Accent glass button
|
|
18
|
+
* ```svelte
|
|
19
|
+
* <GlassButton variant="accent">Subscribe</GlassButton>
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example Ghost glass with icon
|
|
23
|
+
* ```svelte
|
|
24
|
+
* <GlassButton variant="ghost" size="icon">
|
|
25
|
+
* <X class="w-4 h-4" />
|
|
26
|
+
* </GlassButton>
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
type GlassVariant =
|
|
31
|
+
| "default" // Light translucent background
|
|
32
|
+
| "accent" // Accent-colored glass
|
|
33
|
+
| "dark" // Dark translucent background
|
|
34
|
+
| "ghost" // No background until hover
|
|
35
|
+
| "outline"; // Transparent with glass border
|
|
36
|
+
|
|
37
|
+
type ButtonSize = "sm" | "md" | "lg" | "icon";
|
|
38
|
+
|
|
39
|
+
interface Props extends Omit<HTMLButtonAttributes, "class"> {
|
|
40
|
+
variant?: GlassVariant;
|
|
41
|
+
size?: ButtonSize;
|
|
42
|
+
disabled?: boolean;
|
|
43
|
+
href?: string;
|
|
44
|
+
class?: string;
|
|
45
|
+
children?: Snippet;
|
|
46
|
+
ref?: HTMLButtonElement | HTMLAnchorElement | null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let {
|
|
50
|
+
variant = "default",
|
|
51
|
+
size = "md",
|
|
52
|
+
disabled = false,
|
|
53
|
+
href,
|
|
54
|
+
class: className,
|
|
55
|
+
children,
|
|
56
|
+
ref = $bindable(null),
|
|
57
|
+
type = "button",
|
|
58
|
+
...restProps
|
|
59
|
+
}: Props = $props();
|
|
60
|
+
|
|
61
|
+
// Base styles shared by all variants - medium blur for glass effect
|
|
62
|
+
const baseClasses = `
|
|
63
|
+
inline-flex items-center justify-center gap-2
|
|
64
|
+
font-medium rounded-lg
|
|
65
|
+
transition-all duration-200
|
|
66
|
+
backdrop-blur-md
|
|
67
|
+
outline-none
|
|
68
|
+
focus-visible:ring-2 focus-visible:ring-accent/50 focus-visible:ring-offset-2
|
|
69
|
+
disabled:opacity-50 disabled:pointer-events-none
|
|
70
|
+
[&_svg]:w-4 [&_svg]:h-4 [&_svg]:shrink-0
|
|
71
|
+
`.trim().replace(/\s+/g, ' ');
|
|
72
|
+
|
|
73
|
+
// Variant-specific styles - warm grove tones with true glass transparency
|
|
74
|
+
const variantClasses: Record<GlassVariant, string> = {
|
|
75
|
+
default: `
|
|
76
|
+
bg-white/60 dark:bg-emerald-950/25
|
|
77
|
+
border border-white/40 dark:border-emerald-800/25
|
|
78
|
+
text-foreground
|
|
79
|
+
hover:bg-white/75 dark:hover:bg-emerald-950/35
|
|
80
|
+
hover:border-white/50 dark:hover:border-emerald-700/30
|
|
81
|
+
shadow-sm hover:shadow-md
|
|
82
|
+
`.trim().replace(/\s+/g, ' '),
|
|
83
|
+
|
|
84
|
+
accent: `
|
|
85
|
+
bg-accent/70 dark:bg-accent/60
|
|
86
|
+
border border-accent/40 dark:border-accent/30
|
|
87
|
+
text-white
|
|
88
|
+
hover:bg-accent/85 dark:hover:bg-accent/75
|
|
89
|
+
hover:border-accent/60 dark:hover:border-accent/50
|
|
90
|
+
shadow-sm hover:shadow-md shadow-accent/20
|
|
91
|
+
`.trim().replace(/\s+/g, ' '),
|
|
92
|
+
|
|
93
|
+
dark: `
|
|
94
|
+
bg-slate-900/50 dark:bg-slate-950/50
|
|
95
|
+
border border-slate-700/30 dark:border-slate-600/30
|
|
96
|
+
text-white
|
|
97
|
+
hover:bg-slate-900/65 dark:hover:bg-slate-950/65
|
|
98
|
+
hover:border-slate-600/40 dark:hover:border-slate-500/35
|
|
99
|
+
shadow-md hover:shadow-lg
|
|
100
|
+
`.trim().replace(/\s+/g, ' '),
|
|
101
|
+
|
|
102
|
+
ghost: `
|
|
103
|
+
bg-transparent
|
|
104
|
+
border border-transparent
|
|
105
|
+
text-foreground
|
|
106
|
+
hover:bg-white/40 dark:hover:bg-emerald-950/25
|
|
107
|
+
hover:border-white/25 dark:hover:border-emerald-800/20
|
|
108
|
+
`.trim().replace(/\s+/g, ' '),
|
|
109
|
+
|
|
110
|
+
outline: `
|
|
111
|
+
bg-transparent
|
|
112
|
+
border border-white/40 dark:border-emerald-800/30
|
|
113
|
+
text-foreground
|
|
114
|
+
hover:bg-white/25 dark:hover:bg-emerald-950/20
|
|
115
|
+
hover:border-white/55 dark:hover:border-emerald-700/40
|
|
116
|
+
`.trim().replace(/\s+/g, ' ')
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// Size-specific styles
|
|
120
|
+
const sizeClasses: Record<ButtonSize, string> = {
|
|
121
|
+
sm: "h-8 px-3 text-sm",
|
|
122
|
+
md: "h-10 px-4 text-sm",
|
|
123
|
+
lg: "h-12 px-6 text-base",
|
|
124
|
+
icon: "h-10 w-10 p-0"
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const computedClass = $derived(
|
|
128
|
+
cn(
|
|
129
|
+
baseClasses,
|
|
130
|
+
variantClasses[variant],
|
|
131
|
+
sizeClasses[size],
|
|
132
|
+
className
|
|
133
|
+
)
|
|
134
|
+
);
|
|
135
|
+
</script>
|
|
136
|
+
|
|
137
|
+
{#if href && !disabled}
|
|
138
|
+
<a
|
|
139
|
+
bind:this={ref}
|
|
140
|
+
{href}
|
|
141
|
+
class={computedClass}
|
|
142
|
+
aria-disabled={disabled}
|
|
143
|
+
{...restProps}
|
|
144
|
+
>
|
|
145
|
+
{#if children}{@render children()}{/if}
|
|
146
|
+
</a>
|
|
147
|
+
{:else}
|
|
148
|
+
<button
|
|
149
|
+
bind:this={ref}
|
|
150
|
+
{type}
|
|
151
|
+
{disabled}
|
|
152
|
+
class={computedClass}
|
|
153
|
+
{...restProps}
|
|
154
|
+
>
|
|
155
|
+
{#if children}{@render children()}{/if}
|
|
156
|
+
</button>
|
|
157
|
+
{/if}
|