@hyvnt/hyvui 0.2.0 → 0.4.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/README.md +294 -253
- package/dist/components/ambient/ArcaneVein.svelte +151 -0
- package/dist/components/ambient/ArcaneVein.svelte.d.ts +31 -0
- package/dist/components/ambient/BrassFiligree.svelte +109 -0
- package/dist/components/ambient/BrassFiligree.svelte.d.ts +20 -0
- package/dist/components/ambient/CornerBrackets.svelte +91 -87
- package/dist/components/ambient/CornerBrackets.svelte.d.ts +8 -0
- package/dist/components/ambient/CrystalShard.svelte +151 -0
- package/dist/components/ambient/CrystalShard.svelte.d.ts +19 -0
- package/dist/components/ambient/DataStream.svelte +117 -94
- package/dist/components/ambient/DataStream.svelte.d.ts +6 -0
- package/dist/components/ambient/EnergyArc.svelte +189 -0
- package/dist/components/ambient/EnergyArc.svelte.d.ts +32 -0
- package/dist/components/ambient/GlyphMark.svelte +75 -69
- package/dist/components/ambient/GlyphMark.svelte.d.ts +6 -0
- package/dist/components/ambient/GridOverlay.svelte +34 -28
- package/dist/components/ambient/GridOverlay.svelte.d.ts +8 -0
- package/dist/components/ambient/HexGrid.svelte +119 -0
- package/dist/components/ambient/HexGrid.svelte.d.ts +21 -0
- package/dist/components/ambient/ParallaxLayer.svelte +45 -41
- package/dist/components/ambient/ParallaxLayer.svelte.d.ts +7 -0
- package/dist/components/ambient/ScanBand.svelte +103 -91
- package/dist/components/ambient/ScanBand.svelte.d.ts +8 -0
- package/dist/components/ambient/ShimmerCloud.svelte +180 -0
- package/dist/components/ambient/ShimmerCloud.svelte.d.ts +21 -0
- package/dist/components/ambient/SignalRing.svelte +106 -100
- package/dist/components/ambient/SignalRing.svelte.d.ts +6 -0
- package/dist/components/ambient/ThreadLine.svelte +78 -78
- package/dist/components/ambient/ThreadLine.svelte.d.ts +7 -0
- package/dist/components/ambient/Vignette.svelte +30 -26
- package/dist/components/ambient/Vignette.svelte.d.ts +6 -0
- package/dist/components/depth/DepthLayer.svelte +30 -27
- package/dist/components/depth/DepthLayer.svelte.d.ts +8 -0
- package/dist/components/depth/DepthStage.svelte +67 -62
- package/dist/components/depth/DepthStage.svelte.d.ts +8 -0
- package/dist/components/depth/FloatCard.svelte +129 -104
- package/dist/components/depth/FloatCard.svelte.d.ts +8 -0
- package/dist/components/depth/HorizonGrid.svelte +241 -160
- package/dist/components/depth/HorizonGrid.svelte.d.ts +9 -0
- package/dist/components/depth/Plinth.svelte +62 -57
- package/dist/components/depth/Plinth.svelte.d.ts +10 -0
- package/dist/components/display/Avatar.svelte +69 -69
- package/dist/components/display/Avatar.svelte.d.ts +5 -0
- package/dist/components/display/Badge.svelte +75 -63
- package/dist/components/display/Badge.svelte.d.ts +6 -0
- package/dist/components/display/Blockquote.svelte +35 -34
- package/dist/components/display/Blockquote.svelte.d.ts +4 -0
- package/dist/components/display/CodeBlock.svelte +76 -76
- package/dist/components/display/CodeBlock.svelte.d.ts +5 -0
- package/dist/components/display/MetricCard.svelte +100 -83
- package/dist/components/display/MetricCard.svelte.d.ts +6 -0
- package/dist/components/display/Table.svelte +106 -104
- package/dist/components/display/Table.svelte.d.ts +7 -0
- package/dist/components/feedback/Alert.svelte +95 -76
- package/dist/components/feedback/Alert.svelte.d.ts +6 -0
- package/dist/components/feedback/EmptyState.svelte +75 -68
- package/dist/components/feedback/EmptyState.svelte.d.ts +7 -0
- package/dist/components/feedback/ErrorState.svelte +78 -73
- package/dist/components/feedback/ErrorState.svelte.d.ts +5 -0
- package/dist/components/feedback/Skeleton.svelte +58 -52
- package/dist/components/feedback/Skeleton.svelte.d.ts +6 -0
- package/dist/components/feedback/StatusDot.svelte +84 -54
- package/dist/components/feedback/StatusDot.svelte.d.ts +6 -0
- package/dist/components/feedback/StatusLine.svelte +128 -122
- package/dist/components/feedback/StatusLine.svelte.d.ts +6 -0
- package/dist/components/feedback/Toast.svelte +144 -136
- package/dist/components/feedback/Toast.svelte.d.ts +10 -0
- package/dist/components/inputs/Button.svelte +310 -237
- package/dist/components/inputs/Button.svelte.d.ts +8 -0
- package/dist/components/inputs/Checkbox.svelte +109 -105
- package/dist/components/inputs/Checkbox.svelte.d.ts +5 -0
- package/dist/components/inputs/FileUpload.svelte +170 -163
- package/dist/components/inputs/FileUpload.svelte.d.ts +5 -0
- package/dist/components/inputs/Input.svelte +153 -147
- package/dist/components/inputs/Input.svelte.d.ts +7 -0
- package/dist/components/inputs/Select.svelte +164 -150
- package/dist/components/inputs/Select.svelte.d.ts +8 -0
- package/dist/components/inputs/Textarea.svelte +160 -154
- package/dist/components/inputs/Textarea.svelte.d.ts +6 -0
- package/dist/components/inputs/Toggle.svelte +125 -120
- package/dist/components/inputs/Toggle.svelte.d.ts +5 -0
- package/dist/components/layout/Card.svelte +81 -76
- package/dist/components/layout/Card.svelte.d.ts +11 -0
- package/dist/components/layout/Drawer.svelte +140 -109
- package/dist/components/layout/Drawer.svelte.d.ts +6 -0
- package/dist/components/layout/Grid.svelte +128 -43
- package/dist/components/layout/Grid.svelte.d.ts +18 -2
- package/dist/components/layout/Modal.svelte +191 -159
- package/dist/components/layout/Modal.svelte.d.ts +10 -0
- package/dist/components/layout/Panel.svelte +58 -54
- package/dist/components/layout/Panel.svelte.d.ts +9 -0
- package/dist/components/layout/Popover.svelte +188 -67
- package/dist/components/layout/Popover.svelte.d.ts +19 -1
- package/dist/components/layout/Stack.svelte +65 -53
- package/dist/components/layout/Stack.svelte.d.ts +12 -0
- package/dist/components/navigation/Breadcrumb.svelte +78 -73
- package/dist/components/navigation/Breadcrumb.svelte.d.ts +8 -0
- package/dist/components/navigation/DropdownMenu.svelte +179 -124
- package/dist/components/navigation/DropdownMenu.svelte.d.ts +24 -2
- package/dist/components/navigation/SidebarNav.svelte +96 -90
- package/dist/components/navigation/SidebarNav.svelte.d.ts +9 -0
- package/dist/components/navigation/Tabs.svelte +106 -86
- package/dist/components/navigation/Tabs.svelte.d.ts +8 -0
- package/dist/components/navigation/Topbar.svelte +94 -85
- package/dist/components/navigation/Topbar.svelte.d.ts +9 -0
- package/dist/components/patterns/ActionBar.svelte +82 -76
- package/dist/components/patterns/ActionBar.svelte.d.ts +10 -0
- package/dist/components/patterns/ChapterMark.svelte +152 -0
- package/dist/components/patterns/ChapterMark.svelte.d.ts +19 -0
- package/dist/components/patterns/ConfirmDialog.svelte +75 -64
- package/dist/components/patterns/ConfirmDialog.svelte.d.ts +12 -0
- package/dist/components/patterns/DepthPortal.svelte +123 -0
- package/dist/components/patterns/DepthPortal.svelte.d.ts +24 -0
- package/dist/components/patterns/Manifesto.svelte +171 -0
- package/dist/components/patterns/Manifesto.svelte.d.ts +25 -0
- package/dist/components/patterns/PageHeader.svelte +117 -114
- package/dist/components/patterns/PageHeader.svelte.d.ts +8 -0
- package/dist/components/patterns/PullQuote.svelte +145 -0
- package/dist/components/patterns/PullQuote.svelte.d.ts +23 -0
- package/dist/components/patterns/RegisterSwitcher.svelte +132 -0
- package/dist/components/patterns/RegisterSwitcher.svelte.d.ts +21 -0
- package/dist/components/patterns/SearchBar.svelte +59 -59
- package/dist/components/patterns/SearchBar.svelte.d.ts +5 -0
- package/dist/components/patterns/ShowcaseFrame.svelte +117 -0
- package/dist/components/patterns/ShowcaseFrame.svelte.d.ts +28 -0
- package/dist/components/patterns/TerminalBoot.svelte +118 -104
- package/dist/components/patterns/TerminalBoot.svelte.d.ts +12 -0
- package/dist/components/primitives/Divider.svelte +56 -29
- package/dist/components/primitives/Divider.svelte.d.ts +5 -0
- package/dist/components/primitives/Icon.svelte +53 -49
- package/dist/components/primitives/Icon.svelte.d.ts +9 -0
- package/dist/components/primitives/Label.svelte +45 -44
- package/dist/components/primitives/Label.svelte.d.ts +6 -0
- package/dist/components/primitives/Surface.svelte +154 -87
- package/dist/components/primitives/Surface.svelte.d.ts +7 -0
- package/dist/components/primitives/Text.svelte +130 -98
- package/dist/components/primitives/Text.svelte.d.ts +7 -0
- package/dist/components/scenes/ArchiveScene.svelte +102 -95
- package/dist/components/scenes/ArchiveScene.svelte.d.ts +17 -1
- package/dist/components/scenes/DepthScene.svelte +128 -0
- package/dist/components/scenes/DepthScene.svelte.d.ts +36 -0
- package/dist/components/scenes/LogScene.svelte +86 -77
- package/dist/components/scenes/LogScene.svelte.d.ts +14 -0
- package/dist/components/scenes/NarrativeScene.svelte +100 -92
- package/dist/components/scenes/NarrativeScene.svelte.d.ts +9 -0
- package/dist/components/scenes/ReadoutScene.svelte +131 -107
- package/dist/components/scenes/ReadoutScene.svelte.d.ts +14 -1
- package/dist/components/scenes/StageScene.svelte +111 -104
- package/dist/components/scenes/StageScene.svelte.d.ts +14 -0
- package/dist/components/system/AppShell.svelte +62 -0
- package/dist/components/system/AppShell.svelte.d.ts +32 -0
- package/dist/examples/ArcaneShard.svelte +364 -0
- package/dist/examples/ArcaneShard.svelte.d.ts +3 -0
- package/dist/examples/FieldReport.svelte +226 -223
- package/dist/examples/HextechForge.svelte +324 -0
- package/dist/examples/HextechForge.svelte.d.ts +3 -0
- package/dist/examples/ObservationDeck.svelte +333 -317
- package/dist/examples/SignalLost.svelte +191 -191
- package/dist/index.d.ts +15 -1
- package/dist/index.js +16 -1
- package/dist/styles.css +115 -0
- package/dist/system/actions/echo.js +21 -12
- package/dist/system/actions/resolve.js +28 -14
- package/dist/system/actions/reveal.js +2 -2
- package/dist/system/actions/surface.js +12 -2
- package/dist/system/depth/depth.css +49 -49
- package/dist/system/depth/depth.js +1 -1
- package/dist/system/expressions.css +80 -80
- package/dist/system/override-template.css +72 -72
- package/dist/system/register.css +74 -74
- package/dist/system/register.d.ts +1 -1
- package/dist/system/register.js +5 -1
- package/dist/system/scroll-lock.d.ts +6 -0
- package/dist/system/scroll-lock.js +23 -0
- package/dist/tokens/arcane.css +96 -0
- package/dist/tokens/hextech.css +96 -0
- package/dist/tokens/tokens.css +102 -86
- package/dist/tokens/tokens.d.ts +41 -0
- package/dist/tokens/tokens.js +44 -3
- package/dist/utils/motion.js +1 -1
- package/package.json +71 -60
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../../utils/cn.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Decorative hex grid overlay. Adapts color and character per active register:
|
|
6
|
+
* hextech → cyan precise etching; arcane → violet cracked. Parent must have
|
|
7
|
+
* `position: relative`. Renders `aria-hidden`.
|
|
8
|
+
* @example
|
|
9
|
+
* <div style="position: relative;">
|
|
10
|
+
* <HexGrid />
|
|
11
|
+
* content here
|
|
12
|
+
* </div>
|
|
13
|
+
*/
|
|
14
|
+
interface Props {
|
|
15
|
+
/** Controls animation playback. */
|
|
16
|
+
animated?: boolean;
|
|
17
|
+
/** Override grid opacity (0–1). Defaults to register's --reg-ornament-opacity. */
|
|
18
|
+
opacity?: number | undefined;
|
|
19
|
+
/** Additional CSS classes. */
|
|
20
|
+
class?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let { animated = true, opacity = undefined, class: className = '' }: Props = $props();
|
|
24
|
+
|
|
25
|
+
const prefersReduced =
|
|
26
|
+
typeof window !== 'undefined'
|
|
27
|
+
? window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
28
|
+
: false;
|
|
29
|
+
|
|
30
|
+
const shouldAnimate = $derived(animated && !prefersReduced);
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<div
|
|
34
|
+
class={cn('hyvui-hex-grid', shouldAnimate && 'hyvui-hex-grid--animated', className)}
|
|
35
|
+
style={opacity !== undefined ? `--hex-opacity-override: ${opacity}` : undefined}
|
|
36
|
+
aria-hidden="true"
|
|
37
|
+
></div>
|
|
38
|
+
|
|
39
|
+
<style>
|
|
40
|
+
.hyvui-hex-grid {
|
|
41
|
+
position: absolute;
|
|
42
|
+
inset: 0;
|
|
43
|
+
pointer-events: none;
|
|
44
|
+
|
|
45
|
+
/* Hex pattern via three-angle stripes (vertical + two diagonals).
|
|
46
|
+
Color and opacity come from register tokens so they shift automatically. */
|
|
47
|
+
background-image:
|
|
48
|
+
linear-gradient(to right, var(--hg-color) 1px, transparent 1px),
|
|
49
|
+
linear-gradient(60deg, var(--hg-color) 1px, transparent 1px),
|
|
50
|
+
linear-gradient(-60deg, var(--hg-color) 1px, transparent 1px);
|
|
51
|
+
background-size: 40px 23px;
|
|
52
|
+
|
|
53
|
+
opacity: var(--hex-opacity-override, var(--reg-ornament-opacity));
|
|
54
|
+
mask-image: linear-gradient(to bottom, transparent, black 12%, black 88%, transparent);
|
|
55
|
+
-webkit-mask-image: linear-gradient(
|
|
56
|
+
to bottom,
|
|
57
|
+
transparent,
|
|
58
|
+
black 12%,
|
|
59
|
+
black 88%,
|
|
60
|
+
transparent
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
/* default color (field-notebook) */
|
|
64
|
+
--hg-color: rgba(199, 156, 87, 0.45);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* ── hextech ─ cyan precision ─────────────────────────────────────── */
|
|
68
|
+
:global([data-register='hextech']) .hyvui-hex-grid {
|
|
69
|
+
--hg-color: rgba(93, 217, 240, 0.55);
|
|
70
|
+
background-size: 48px 28px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* ── arcane ─ violet instability ─────────────────────────────────── */
|
|
74
|
+
:global([data-register='arcane']) .hyvui-hex-grid {
|
|
75
|
+
--hg-color: rgba(184, 69, 201, 0.5);
|
|
76
|
+
background-size: 40px 23px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* ── pulse animation ─────────────────────────────────────────────── */
|
|
80
|
+
.hyvui-hex-grid--animated {
|
|
81
|
+
animation: hg-pulse var(--orn-shimmer-rate, 4s) var(--orn-pulse-rhythm, ease-in-out) infinite;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
:global([data-register='arcane']) .hyvui-hex-grid--animated {
|
|
85
|
+
animation:
|
|
86
|
+
hg-pulse var(--orn-shimmer-rate, 2.4s) var(--orn-pulse-rhythm, ease-in-out) infinite,
|
|
87
|
+
hg-flicker 7s step-end infinite;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@keyframes hg-pulse {
|
|
91
|
+
0%,
|
|
92
|
+
100% {
|
|
93
|
+
opacity: var(--hex-opacity-override, var(--reg-ornament-opacity));
|
|
94
|
+
}
|
|
95
|
+
50% {
|
|
96
|
+
opacity: calc(var(--hex-opacity-override, var(--reg-ornament-opacity)) * 1.8);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@keyframes hg-flicker {
|
|
101
|
+
0%,
|
|
102
|
+
97%,
|
|
103
|
+
100% {
|
|
104
|
+
opacity: var(--hex-opacity-override, var(--reg-ornament-opacity));
|
|
105
|
+
}
|
|
106
|
+
98% {
|
|
107
|
+
opacity: 0.02;
|
|
108
|
+
}
|
|
109
|
+
99% {
|
|
110
|
+
opacity: calc(var(--hex-opacity-override, var(--reg-ornament-opacity)) * 2.2);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@media (prefers-reduced-motion: reduce) {
|
|
115
|
+
.hyvui-hex-grid--animated {
|
|
116
|
+
animation: none;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decorative hex grid overlay. Adapts color and character per active register:
|
|
3
|
+
* hextech → cyan precise etching; arcane → violet cracked. Parent must have
|
|
4
|
+
* `position: relative`. Renders `aria-hidden`.
|
|
5
|
+
* @example
|
|
6
|
+
* <div style="position: relative;">
|
|
7
|
+
* <HexGrid />
|
|
8
|
+
* content here
|
|
9
|
+
* </div>
|
|
10
|
+
*/
|
|
11
|
+
interface Props {
|
|
12
|
+
/** Controls animation playback. */
|
|
13
|
+
animated?: boolean;
|
|
14
|
+
/** Override grid opacity (0–1). Defaults to register's --reg-ornament-opacity. */
|
|
15
|
+
opacity?: number | undefined;
|
|
16
|
+
/** Additional CSS classes. */
|
|
17
|
+
class?: string;
|
|
18
|
+
}
|
|
19
|
+
declare const HexGrid: import("svelte").Component<Props, {}, "">;
|
|
20
|
+
type HexGrid = ReturnType<typeof HexGrid>;
|
|
21
|
+
export default HexGrid;
|
|
@@ -1,41 +1,45 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../../utils/cn.js';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Reads `--px` and `--py` CSS custom properties for pointer-driven parallax. Set these on a parent via JS.
|
|
7
|
+
* @example
|
|
8
|
+
* <div onpointermove={trackPointer} style="position:relative;">
|
|
9
|
+
* <ParallaxLayer strength={12}><GlyphMark /></ParallaxLayer>
|
|
10
|
+
* </div>
|
|
11
|
+
*/
|
|
12
|
+
interface Props {
|
|
13
|
+
/** Motion multiplier applied to --px/--py custom properties. */
|
|
14
|
+
strength?: number;
|
|
15
|
+
/** Additional CSS classes. */
|
|
16
|
+
class?: string;
|
|
17
|
+
/** Content to apply parallax to. */
|
|
18
|
+
children?: Snippet;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let { strength = 18, class: className = '', children }: Props = $props();
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<div
|
|
25
|
+
class={cn('hyvui-parallax', className)}
|
|
26
|
+
style:transform="translate(calc(var(--px, 0) * {strength}px), calc(var(--py, 0) * {strength}px))"
|
|
27
|
+
aria-hidden="true"
|
|
28
|
+
>
|
|
29
|
+
{#if children}{@render children()}{/if}
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<style>
|
|
33
|
+
.hyvui-parallax {
|
|
34
|
+
will-change: transform;
|
|
35
|
+
backface-visibility: hidden;
|
|
36
|
+
transition: transform 0.15s var(--ease-smooth);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@media (prefers-reduced-motion: reduce) {
|
|
40
|
+
.hyvui-parallax {
|
|
41
|
+
transform: none !important;
|
|
42
|
+
transition: none;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
</style>
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
|
+
/**
|
|
3
|
+
* Reads `--px` and `--py` CSS custom properties for pointer-driven parallax. Set these on a parent via JS.
|
|
4
|
+
* @example
|
|
5
|
+
* <div onpointermove={trackPointer} style="position:relative;">
|
|
6
|
+
* <ParallaxLayer strength={12}><GlyphMark /></ParallaxLayer>
|
|
7
|
+
* </div>
|
|
8
|
+
*/
|
|
2
9
|
interface Props {
|
|
3
10
|
/** Motion multiplier applied to --px/--py custom properties. */
|
|
4
11
|
strength?: number;
|
|
@@ -1,91 +1,103 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../../utils/cn.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Decorative. Parent must have `position: relative`. Renders `aria-hidden`.
|
|
6
|
+
* @example
|
|
7
|
+
* <div style="position: relative;">
|
|
8
|
+
* <ScanBand axis="x" duration="6s" />
|
|
9
|
+
* content with scan line
|
|
10
|
+
* </div>
|
|
11
|
+
*/
|
|
12
|
+
interface Props {
|
|
13
|
+
/** Enable the scan animation. */
|
|
14
|
+
active?: boolean;
|
|
15
|
+
/** Animation axis. */
|
|
16
|
+
axis?: 'x' | 'y';
|
|
17
|
+
/** Thickness/width of the band. */
|
|
18
|
+
size?: string;
|
|
19
|
+
/** Animation duration. */
|
|
20
|
+
duration?: string;
|
|
21
|
+
/** Gradient used for the band. */
|
|
22
|
+
gradient?: string;
|
|
23
|
+
/** Additional CSS classes. */
|
|
24
|
+
class?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
active = true,
|
|
29
|
+
axis = 'y',
|
|
30
|
+
size = '1px',
|
|
31
|
+
duration = '8s',
|
|
32
|
+
gradient = 'linear-gradient(90deg, transparent, rgba(199, 156, 87, 0.18), transparent)',
|
|
33
|
+
class: className = ''
|
|
34
|
+
}: Props = $props();
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
{#if active}
|
|
38
|
+
<div
|
|
39
|
+
class={cn(
|
|
40
|
+
'hyvui-scan-band',
|
|
41
|
+
axis === 'x' ? 'hyvui-scan-band-x' : 'hyvui-scan-band-y',
|
|
42
|
+
className
|
|
43
|
+
)}
|
|
44
|
+
style:--scan-size={size}
|
|
45
|
+
style:--scan-duration={duration}
|
|
46
|
+
style:--scan-gradient={gradient}
|
|
47
|
+
aria-hidden="true"
|
|
48
|
+
></div>
|
|
49
|
+
{/if}
|
|
50
|
+
|
|
51
|
+
<style>
|
|
52
|
+
.hyvui-scan-band {
|
|
53
|
+
position: absolute;
|
|
54
|
+
inset: 0;
|
|
55
|
+
pointer-events: none;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.hyvui-scan-band::after {
|
|
60
|
+
content: '';
|
|
61
|
+
position: absolute;
|
|
62
|
+
background: var(--scan-gradient);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.hyvui-scan-band-y::after {
|
|
66
|
+
left: 0;
|
|
67
|
+
right: 0;
|
|
68
|
+
height: var(--scan-size);
|
|
69
|
+
animation: scan-band-y var(--scan-duration) linear infinite;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.hyvui-scan-band-x::after {
|
|
73
|
+
top: 0;
|
|
74
|
+
bottom: 0;
|
|
75
|
+
width: var(--scan-size);
|
|
76
|
+
animation: scan-band-x var(--scan-duration) linear infinite;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@keyframes scan-band-y {
|
|
80
|
+
0% {
|
|
81
|
+
transform: translateY(-100%);
|
|
82
|
+
}
|
|
83
|
+
100% {
|
|
84
|
+
transform: translateY(100%);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@keyframes scan-band-x {
|
|
89
|
+
0% {
|
|
90
|
+
transform: translateX(-120%);
|
|
91
|
+
}
|
|
92
|
+
100% {
|
|
93
|
+
transform: translateX(520%);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@media (prefers-reduced-motion: reduce) {
|
|
98
|
+
.hyvui-scan-band::after {
|
|
99
|
+
animation: none;
|
|
100
|
+
display: none;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
</style>
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decorative. Parent must have `position: relative`. Renders `aria-hidden`.
|
|
3
|
+
* @example
|
|
4
|
+
* <div style="position: relative;">
|
|
5
|
+
* <ScanBand axis="x" duration="6s" />
|
|
6
|
+
* content with scan line
|
|
7
|
+
* </div>
|
|
8
|
+
*/
|
|
1
9
|
interface Props {
|
|
2
10
|
/** Enable the scan animation. */
|
|
3
11
|
active?: boolean;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../../utils/cn.js';
|
|
3
|
+
import { onMount } from 'svelte';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Particle-smoke ambient effect using canvas.
|
|
7
|
+
* Under `hextech`: slow blue-mist dots, precise motion.
|
|
8
|
+
* Under `arcane`: pink/violet shimmer drift, chaotic.
|
|
9
|
+
* Parent must have `position: relative`. Renders `aria-hidden`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* <div style="position: relative;">
|
|
13
|
+
* <ShimmerCloud />
|
|
14
|
+
* content
|
|
15
|
+
* </div>
|
|
16
|
+
*/
|
|
17
|
+
interface Props {
|
|
18
|
+
/** Particle count. */
|
|
19
|
+
count?: number;
|
|
20
|
+
/** Additional CSS classes. */
|
|
21
|
+
class?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let { count = 28, class: className = '' }: Props = $props();
|
|
25
|
+
|
|
26
|
+
const prefersReduced =
|
|
27
|
+
typeof window !== 'undefined'
|
|
28
|
+
? window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
29
|
+
: false;
|
|
30
|
+
|
|
31
|
+
let canvas: HTMLCanvasElement | undefined = $state();
|
|
32
|
+
let rafId: number | undefined;
|
|
33
|
+
|
|
34
|
+
type Particle = {
|
|
35
|
+
x: number;
|
|
36
|
+
y: number;
|
|
37
|
+
r: number;
|
|
38
|
+
vx: number;
|
|
39
|
+
vy: number;
|
|
40
|
+
alpha: number;
|
|
41
|
+
alphaDir: number;
|
|
42
|
+
alphaSpeed: number;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function getRegister(): string {
|
|
46
|
+
if (typeof document === 'undefined') return '';
|
|
47
|
+
return document.body.dataset.register ?? '';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getParticleColor(register: string): string {
|
|
51
|
+
if (register === 'hextech') return '93, 217, 240';
|
|
52
|
+
if (register === 'arcane') return '184, 69, 201';
|
|
53
|
+
return '199, 156, 87';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getParticleColorB(register: string): string {
|
|
57
|
+
// Second color for arcane (two-color particles add richness)
|
|
58
|
+
if (register === 'arcane') return '233, 76, 188';
|
|
59
|
+
return getParticleColor(register);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
onMount(() => {
|
|
63
|
+
if (prefersReduced || !canvas) return;
|
|
64
|
+
|
|
65
|
+
const ctx = canvas.getContext('2d');
|
|
66
|
+
if (!ctx) return;
|
|
67
|
+
|
|
68
|
+
let particles: Particle[] = [];
|
|
69
|
+
|
|
70
|
+
function resize() {
|
|
71
|
+
if (!canvas || !canvas.parentElement) return;
|
|
72
|
+
const { width, height } = canvas.parentElement.getBoundingClientRect();
|
|
73
|
+
canvas.width = width;
|
|
74
|
+
canvas.height = height;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function spawn(): Particle {
|
|
78
|
+
const w = canvas?.width ?? 400;
|
|
79
|
+
const h = canvas?.height ?? 300;
|
|
80
|
+
const register = getRegister();
|
|
81
|
+
const fast = register === 'arcane';
|
|
82
|
+
return {
|
|
83
|
+
x: Math.random() * w,
|
|
84
|
+
y: Math.random() * h,
|
|
85
|
+
r: 1 + Math.random() * (fast ? 3 : 2),
|
|
86
|
+
vx: (Math.random() - 0.5) * (fast ? 0.45 : 0.2),
|
|
87
|
+
vy: -(Math.random() * (fast ? 0.5 : 0.3) + 0.05),
|
|
88
|
+
alpha: Math.random() * 0.3,
|
|
89
|
+
alphaDir: 1,
|
|
90
|
+
alphaSpeed: 0.003 + Math.random() * (fast ? 0.008 : 0.004)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
resize();
|
|
95
|
+
particles = Array.from({ length: count }, spawn);
|
|
96
|
+
|
|
97
|
+
const ro = new ResizeObserver(resize);
|
|
98
|
+
if (canvas.parentElement) ro.observe(canvas.parentElement);
|
|
99
|
+
|
|
100
|
+
let io_visible = true;
|
|
101
|
+
const io = new IntersectionObserver((entries) => {
|
|
102
|
+
io_visible = entries[0]?.isIntersecting ?? true;
|
|
103
|
+
});
|
|
104
|
+
io.observe(canvas);
|
|
105
|
+
|
|
106
|
+
function draw() {
|
|
107
|
+
if (!ctx || !canvas) return;
|
|
108
|
+
const register = getRegister();
|
|
109
|
+
const colorA = getParticleColor(register);
|
|
110
|
+
const colorB = getParticleColorB(register);
|
|
111
|
+
|
|
112
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
113
|
+
|
|
114
|
+
if (io_visible) {
|
|
115
|
+
particles.forEach((p, i) => {
|
|
116
|
+
// breathing alpha
|
|
117
|
+
p.alpha += p.alphaDir * p.alphaSpeed;
|
|
118
|
+
if (p.alpha >= (register === 'arcane' ? 0.38 : 0.22)) p.alphaDir = -1;
|
|
119
|
+
if (p.alpha <= 0.02) p.alphaDir = 1;
|
|
120
|
+
|
|
121
|
+
// drift
|
|
122
|
+
p.x += p.vx;
|
|
123
|
+
p.y += p.vy;
|
|
124
|
+
|
|
125
|
+
// wrap
|
|
126
|
+
if (p.y < -10) p.y = canvas.height + 10;
|
|
127
|
+
if (p.x < -10) p.x = canvas.width + 10;
|
|
128
|
+
if (p.x > canvas.width + 10) p.x = -10;
|
|
129
|
+
|
|
130
|
+
const color = i % 2 === 0 ? colorA : colorB;
|
|
131
|
+
ctx.beginPath();
|
|
132
|
+
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
|
|
133
|
+
ctx.fillStyle = `rgba(${color}, ${p.alpha})`;
|
|
134
|
+
ctx.fill();
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
rafId = requestAnimationFrame(draw);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
rafId = requestAnimationFrame(draw);
|
|
142
|
+
|
|
143
|
+
return () => {
|
|
144
|
+
if (rafId !== undefined) cancelAnimationFrame(rafId);
|
|
145
|
+
ro.disconnect();
|
|
146
|
+
io.disconnect();
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
</script>
|
|
150
|
+
|
|
151
|
+
<canvas
|
|
152
|
+
bind:this={canvas}
|
|
153
|
+
class={cn('hyvui-shimmer-cloud', className)}
|
|
154
|
+
aria-hidden="true"
|
|
155
|
+
></canvas>
|
|
156
|
+
|
|
157
|
+
<style>
|
|
158
|
+
.hyvui-shimmer-cloud {
|
|
159
|
+
position: absolute;
|
|
160
|
+
inset: 0;
|
|
161
|
+
width: 100%;
|
|
162
|
+
height: 100%;
|
|
163
|
+
pointer-events: none;
|
|
164
|
+
opacity: 0.7;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
:global([data-register='hextech']) .hyvui-shimmer-cloud {
|
|
168
|
+
opacity: 0.55;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
:global([data-register='arcane']) .hyvui-shimmer-cloud {
|
|
172
|
+
opacity: 0.85;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@media (prefers-reduced-motion: reduce) {
|
|
176
|
+
.hyvui-shimmer-cloud {
|
|
177
|
+
display: none;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Particle-smoke ambient effect using canvas.
|
|
3
|
+
* Under `hextech`: slow blue-mist dots, precise motion.
|
|
4
|
+
* Under `arcane`: pink/violet shimmer drift, chaotic.
|
|
5
|
+
* Parent must have `position: relative`. Renders `aria-hidden`.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* <div style="position: relative;">
|
|
9
|
+
* <ShimmerCloud />
|
|
10
|
+
* content
|
|
11
|
+
* </div>
|
|
12
|
+
*/
|
|
13
|
+
interface Props {
|
|
14
|
+
/** Particle count. */
|
|
15
|
+
count?: number;
|
|
16
|
+
/** Additional CSS classes. */
|
|
17
|
+
class?: string;
|
|
18
|
+
}
|
|
19
|
+
declare const ShimmerCloud: import("svelte").Component<Props, {}, "">;
|
|
20
|
+
type ShimmerCloud = ReturnType<typeof ShimmerCloud>;
|
|
21
|
+
export default ShimmerCloud;
|