@atmo-dev/events-ui 0.1.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/dist/DatePicker.svelte +231 -0
- package/dist/DatePicker.svelte.d.ts +11 -0
- package/dist/DateTimePicker.svelte +101 -0
- package/dist/DateTimePicker.svelte.d.ts +9 -0
- package/dist/EventAttendees.svelte +203 -0
- package/dist/EventAttendees.svelte.d.ts +13 -0
- package/dist/EventCard.svelte +131 -0
- package/dist/EventCard.svelte.d.ts +8 -0
- package/dist/EventComments.svelte +99 -0
- package/dist/EventComments.svelte.d.ts +6 -0
- package/dist/EventEditor.svelte +589 -0
- package/dist/EventEditor.svelte.d.ts +20 -0
- package/dist/EventRsvp.svelte +237 -0
- package/dist/EventRsvp.svelte.d.ts +17 -0
- package/dist/EventView.svelte +433 -0
- package/dist/EventView.svelte.d.ts +16 -0
- package/dist/ImageDropper.svelte +66 -0
- package/dist/ImageDropper.svelte.d.ts +7 -0
- package/dist/Map.svelte +27 -0
- package/dist/Map.svelte.d.ts +8 -0
- package/dist/PostToBlueskyModal.svelte +244 -0
- package/dist/PostToBlueskyModal.svelte.d.ts +22 -0
- package/dist/ShareModal.svelte +160 -0
- package/dist/ShareModal.svelte.d.ts +23 -0
- package/dist/ThemeApply.svelte +50 -0
- package/dist/ThemeApply.svelte.d.ts +7 -0
- package/dist/ThemeBackground.svelte +33 -0
- package/dist/ThemeBackground.svelte.d.ts +7 -0
- package/dist/ThemePicker.svelte +102 -0
- package/dist/ThemePicker.svelte.d.ts +7 -0
- package/dist/ThumbnailPresets.svelte +68 -0
- package/dist/ThumbnailPresets.svelte.d.ts +11 -0
- package/dist/TimePicker.svelte +188 -0
- package/dist/TimePicker.svelte.d.ts +9 -0
- package/dist/TimezonePicker.svelte +132 -0
- package/dist/TimezonePicker.svelte.d.ts +6 -0
- package/dist/VodPlayer.svelte +137 -0
- package/dist/VodPlayer.svelte.d.ts +14 -0
- package/dist/VodTranscript.svelte +72 -0
- package/dist/VodTranscript.svelte.d.ts +8 -0
- package/dist/atproto-helpers.d.ts +21 -0
- package/dist/atproto-helpers.js +61 -0
- package/dist/cal/helper.d.ts +1 -0
- package/dist/cal/helper.js +20 -0
- package/dist/cal/ical.d.ts +22 -0
- package/dist/cal/ical.js +188 -0
- package/dist/cal/sanitize.d.ts +3 -0
- package/dist/cal/sanitize.js +25 -0
- package/dist/contrail.d.ts +54 -0
- package/dist/contrail.js +22 -0
- package/dist/date-format.d.ts +22 -0
- package/dist/date-format.js +43 -0
- package/dist/editor/LinksSection.svelte +144 -0
- package/dist/editor/LinksSection.svelte.d.ts +10 -0
- package/dist/editor/LocationSection.svelte +215 -0
- package/dist/editor/LocationSection.svelte.d.ts +8 -0
- package/dist/editor/RecurringModal.svelte +270 -0
- package/dist/editor/RecurringModal.svelte.d.ts +30 -0
- package/dist/editor/ThemeSection.svelte +39 -0
- package/dist/editor/ThemeSection.svelte.d.ts +7 -0
- package/dist/editor/ThumbnailSection.svelte +219 -0
- package/dist/editor/ThumbnailSection.svelte.d.ts +13 -0
- package/dist/editor/adapter.d.ts +98 -0
- package/dist/editor/adapter.js +9 -0
- package/dist/editor/save.d.ts +42 -0
- package/dist/editor/save.js +154 -0
- package/dist/editor/types.d.ts +39 -0
- package/dist/editor/types.js +9 -0
- package/dist/event-types.d.ts +70 -0
- package/dist/event-types.js +11 -0
- package/dist/event-view/AddToCalendarButton.svelte +42 -0
- package/dist/event-view/AddToCalendarButton.svelte.d.ts +9 -0
- package/dist/event-view/EventBadges.svelte +20 -0
- package/dist/event-view/EventBadges.svelte.d.ts +7 -0
- package/dist/event-view/EventDateBlock.svelte +43 -0
- package/dist/event-view/EventDateBlock.svelte.d.ts +7 -0
- package/dist/event-view/EventHostedBy.svelte +63 -0
- package/dist/event-view/EventHostedBy.svelte.d.ts +16 -0
- package/dist/event-view/EventLinksList.svelte +37 -0
- package/dist/event-view/EventLinksList.svelte.d.ts +9 -0
- package/dist/event-view/EventLocationBlock.svelte +48 -0
- package/dist/event-view/EventLocationBlock.svelte.d.ts +7 -0
- package/dist/event-view/EventLocationMap.svelte +72 -0
- package/dist/event-view/EventLocationMap.svelte.d.ts +8 -0
- package/dist/event-view/ExternalRsvpNotice.svelte +44 -0
- package/dist/event-view/ExternalRsvpNotice.svelte.d.ts +6 -0
- package/dist/event-view/InviteShareFlow.svelte +177 -0
- package/dist/event-view/InviteShareFlow.svelte.d.ts +15 -0
- package/dist/event-view/StreamPlacePlayer.svelte +222 -0
- package/dist/event-view/StreamPlacePlayer.svelte.d.ts +8 -0
- package/dist/event-view/format.d.ts +26 -0
- package/dist/event-view/format.js +145 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +18 -0
- package/dist/profile-url.d.ts +1 -0
- package/dist/profile-url.js +7 -0
- package/dist/theme.d.ts +9 -0
- package/dist/theme.js +22 -0
- package/dist/themes/Blobs.svelte +35 -0
- package/dist/themes/Blobs.svelte.d.ts +26 -0
- package/dist/themes/Butterflies.svelte +185 -0
- package/dist/themes/Butterflies.svelte.d.ts +3 -0
- package/dist/themes/Fireflies.svelte +134 -0
- package/dist/themes/Fireflies.svelte.d.ts +3 -0
- package/dist/themes/Kaleidoscope.svelte +177 -0
- package/dist/themes/Kaleidoscope.svelte.d.ts +3 -0
- package/dist/themes/Matrix.svelte +150 -0
- package/dist/themes/Matrix.svelte.d.ts +3 -0
- package/dist/themes/Stars.svelte +98 -0
- package/dist/themes/Stars.svelte.d.ts +3 -0
- package/dist/thumbnails/designs.d.ts +18 -0
- package/dist/thumbnails/designs.js +316 -0
- package/package.json +95 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { BROWSER as browser } from 'esm-env';
|
|
3
|
+
|
|
4
|
+
let canvas: HTMLCanvasElement | undefined = $state(undefined);
|
|
5
|
+
|
|
6
|
+
$effect(() => {
|
|
7
|
+
if (!canvas || !browser) return;
|
|
8
|
+
|
|
9
|
+
const ctx = canvas.getContext('2d')!;
|
|
10
|
+
let animId: number;
|
|
11
|
+
|
|
12
|
+
const fontSize = 14;
|
|
13
|
+
const chars = 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン0123456789ABCDEF';
|
|
14
|
+
|
|
15
|
+
// Speeds in units per second
|
|
16
|
+
const DROP_SPEED = 8; // rows per second
|
|
17
|
+
const FADE_RATE = 2; // alpha per second for trail fade
|
|
18
|
+
const MUTATE_CHANCE = 0.8; // chance per column per second
|
|
19
|
+
|
|
20
|
+
let lastWidth = 0;
|
|
21
|
+
function resize() {
|
|
22
|
+
const w = window.innerWidth;
|
|
23
|
+
if (w === lastWidth) return;
|
|
24
|
+
lastWidth = w;
|
|
25
|
+
canvas!.width = w;
|
|
26
|
+
canvas!.height = window.screen.height;
|
|
27
|
+
}
|
|
28
|
+
resize();
|
|
29
|
+
window.addEventListener('resize', resize);
|
|
30
|
+
|
|
31
|
+
let columns = Math.floor(canvas.width / fontSize);
|
|
32
|
+
let rows = Math.ceil(canvas.height / fontSize) + 1;
|
|
33
|
+
let drops = new Array(columns).fill(0).map(() => Math.random() * -100);
|
|
34
|
+
let grid: string[][] = Array.from({ length: columns }, () =>
|
|
35
|
+
Array.from({ length: rows }, () => chars[Math.floor(Math.random() * chars.length)])
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const accentColor = getComputedStyle(document.documentElement)
|
|
39
|
+
.getPropertyValue('--color-accent-500')
|
|
40
|
+
.trim();
|
|
41
|
+
|
|
42
|
+
let bgColor = '';
|
|
43
|
+
function readBgColor() {
|
|
44
|
+
const isDark = document.documentElement.classList.contains('dark');
|
|
45
|
+
bgColor = getComputedStyle(document.documentElement)
|
|
46
|
+
.getPropertyValue(isDark ? '--color-base-900' : '--color-base-50')
|
|
47
|
+
.trim();
|
|
48
|
+
}
|
|
49
|
+
readBgColor();
|
|
50
|
+
|
|
51
|
+
const themeObserver = new MutationObserver(readBgColor);
|
|
52
|
+
themeObserver.observe(document.documentElement, {
|
|
53
|
+
attributes: true,
|
|
54
|
+
attributeFilter: ['class']
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
let lastResize = canvas.width;
|
|
58
|
+
let lastTime = performance.now();
|
|
59
|
+
|
|
60
|
+
function draw(now: number) {
|
|
61
|
+
const dt = Math.min((now - lastTime) / 1000, 0.1); // delta in seconds, capped
|
|
62
|
+
lastTime = now;
|
|
63
|
+
|
|
64
|
+
const w = canvas!.width;
|
|
65
|
+
const h = canvas!.height;
|
|
66
|
+
|
|
67
|
+
if (w !== lastResize) {
|
|
68
|
+
lastResize = w;
|
|
69
|
+
columns = Math.floor(w / fontSize);
|
|
70
|
+
rows = Math.ceil(h / fontSize) + 1;
|
|
71
|
+
drops = new Array(columns).fill(0).map(() => Math.random() * -100);
|
|
72
|
+
grid = Array.from({ length: columns }, () =>
|
|
73
|
+
Array.from({ length: rows }, () => chars[Math.floor(Math.random() * chars.length)])
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Randomly mutate characters — framerate independent
|
|
78
|
+
const mutatePerFrame = MUTATE_CHANCE * dt;
|
|
79
|
+
for (let m = 0; m < columns; m++) {
|
|
80
|
+
if (Math.random() < mutatePerFrame) {
|
|
81
|
+
const row = Math.floor(Math.random() * rows);
|
|
82
|
+
grid[m][row] = chars[Math.floor(Math.random() * chars.length)];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Fade trail — framerate independent
|
|
87
|
+
const fadeAlpha = Math.min(1, FADE_RATE * dt);
|
|
88
|
+
ctx.fillStyle = bgColor ? `oklch(from ${bgColor} l c h / ${fadeAlpha})` : `rgba(0, 0, 0, ${fadeAlpha})`;
|
|
89
|
+
ctx.fillRect(0, 0, w, h);
|
|
90
|
+
|
|
91
|
+
ctx.font = `${fontSize}px monospace`;
|
|
92
|
+
|
|
93
|
+
const dropStep = DROP_SPEED * dt;
|
|
94
|
+
|
|
95
|
+
for (let i = 0; i < columns; i++) {
|
|
96
|
+
if (drops[i] * fontSize > h && Math.random() < 0.5 * dt) {
|
|
97
|
+
drops[i] = 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (drops[i] < 0) {
|
|
101
|
+
drops[i] += dropStep;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const row = Math.floor(drops[i]);
|
|
106
|
+
const y = row * fontSize;
|
|
107
|
+
const gridRow = ((row % rows) + rows) % rows;
|
|
108
|
+
const char = grid[i]?.[gridRow] ?? '0';
|
|
109
|
+
|
|
110
|
+
// Bright head
|
|
111
|
+
ctx.fillStyle = accentColor
|
|
112
|
+
? `oklch(from ${accentColor} calc(l * 1.3) c h / 0.9)`
|
|
113
|
+
: `rgba(150, 255, 150, 0.9)`;
|
|
114
|
+
ctx.fillText(char, i * fontSize, y);
|
|
115
|
+
|
|
116
|
+
// Dimmer trail chars
|
|
117
|
+
for (let t = 1; t < 3; t++) {
|
|
118
|
+
const trailRow = ((gridRow - t) % rows + rows) % rows;
|
|
119
|
+
const trailY = y - t * fontSize;
|
|
120
|
+
if (trailY < 0) break;
|
|
121
|
+
const trailAlpha = 0.4 - t * 0.12;
|
|
122
|
+
ctx.fillStyle = accentColor
|
|
123
|
+
? `oklch(from ${accentColor} l c h / ${trailAlpha})`
|
|
124
|
+
: `rgba(100, 200, 100, ${trailAlpha})`;
|
|
125
|
+
ctx.fillText(grid[i]?.[trailRow] ?? '0', i * fontSize, trailY);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
drops[i] += dropStep;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
animId = requestAnimationFrame(draw);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Fill initial background
|
|
135
|
+
ctx.fillStyle = bgColor ? `oklch(from ${bgColor} l c h)` : '#000';
|
|
136
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
137
|
+
|
|
138
|
+
animId = requestAnimationFrame(draw);
|
|
139
|
+
|
|
140
|
+
return () => {
|
|
141
|
+
cancelAnimationFrame(animId);
|
|
142
|
+
window.removeEventListener('resize', resize);
|
|
143
|
+
themeObserver.disconnect();
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
</script>
|
|
147
|
+
|
|
148
|
+
<div class="pointer-events-none fixed inset-0 -z-10 bg-base-50 dark:bg-base-900">
|
|
149
|
+
<canvas bind:this={canvas} class="absolute inset-0 h-full w-full opacity-40"></canvas>
|
|
150
|
+
</div>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { BROWSER as browser } from 'esm-env';
|
|
3
|
+
|
|
4
|
+
let canvas: HTMLCanvasElement | undefined = $state(undefined);
|
|
5
|
+
|
|
6
|
+
$effect(() => {
|
|
7
|
+
if (!canvas || !browser) return;
|
|
8
|
+
|
|
9
|
+
const ctx = canvas.getContext('2d')!;
|
|
10
|
+
let animId: number;
|
|
11
|
+
|
|
12
|
+
const stars: { x: number; y: number; z: number; pz: number }[] = [];
|
|
13
|
+
const COUNT = 600;
|
|
14
|
+
const SPEED = 300; // pixels per second
|
|
15
|
+
|
|
16
|
+
let lastWidth = 0;
|
|
17
|
+
function resize() {
|
|
18
|
+
const w = window.innerWidth;
|
|
19
|
+
if (w === lastWidth) return;
|
|
20
|
+
lastWidth = w;
|
|
21
|
+
canvas!.width = w;
|
|
22
|
+
canvas!.height = window.screen.height;
|
|
23
|
+
}
|
|
24
|
+
resize();
|
|
25
|
+
window.addEventListener('resize', resize);
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < COUNT; i++) {
|
|
28
|
+
stars.push({
|
|
29
|
+
x: (Math.random() - 0.5) * canvas.width,
|
|
30
|
+
y: (Math.random() - 0.5) * canvas.height,
|
|
31
|
+
z: Math.random() * canvas.width,
|
|
32
|
+
pz: 0
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
stars.forEach((s) => (s.pz = s.z));
|
|
36
|
+
|
|
37
|
+
const accentColor = getComputedStyle(document.documentElement)
|
|
38
|
+
.getPropertyValue('--color-accent-500')
|
|
39
|
+
.trim();
|
|
40
|
+
|
|
41
|
+
let lastTime = performance.now();
|
|
42
|
+
|
|
43
|
+
function draw(now: number) {
|
|
44
|
+
const dt = Math.min((now - lastTime) / 1000, 0.1);
|
|
45
|
+
lastTime = now;
|
|
46
|
+
|
|
47
|
+
const w = canvas!.width;
|
|
48
|
+
const h = canvas!.height;
|
|
49
|
+
const cx = w / 2;
|
|
50
|
+
const cy = h / 2;
|
|
51
|
+
const speed = SPEED * dt;
|
|
52
|
+
|
|
53
|
+
ctx.clearRect(0, 0, w, h);
|
|
54
|
+
|
|
55
|
+
for (const star of stars) {
|
|
56
|
+
star.pz = star.z;
|
|
57
|
+
star.z -= speed;
|
|
58
|
+
|
|
59
|
+
if (star.z <= 0) {
|
|
60
|
+
star.x = (Math.random() - 0.5) * w;
|
|
61
|
+
star.y = (Math.random() - 0.5) * h;
|
|
62
|
+
star.z = w;
|
|
63
|
+
star.pz = w;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const sx = (star.x / star.z) * w + cx;
|
|
67
|
+
const sy = (star.y / star.z) * h + cy;
|
|
68
|
+
const px = (star.x / star.pz) * w + cx;
|
|
69
|
+
const py = (star.y / star.pz) * h + cy;
|
|
70
|
+
|
|
71
|
+
const size = Math.max(0, (1 - star.z / w) * 4);
|
|
72
|
+
const alpha = Math.max(0, (1 - star.z / w) * 0.9);
|
|
73
|
+
|
|
74
|
+
ctx.beginPath();
|
|
75
|
+
ctx.moveTo(px, py);
|
|
76
|
+
ctx.lineTo(sx, sy);
|
|
77
|
+
ctx.strokeStyle = accentColor
|
|
78
|
+
? `oklch(from ${accentColor} l c h / ${alpha})`
|
|
79
|
+
: `rgba(255,255,255,${alpha})`;
|
|
80
|
+
ctx.lineWidth = size;
|
|
81
|
+
ctx.stroke();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
animId = requestAnimationFrame(draw);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
animId = requestAnimationFrame(draw);
|
|
88
|
+
|
|
89
|
+
return () => {
|
|
90
|
+
cancelAnimationFrame(animId);
|
|
91
|
+
window.removeEventListener('resize', resize);
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<div class="pointer-events-none fixed inset-0 -z-10 bg-base-50 dark:bg-base-900">
|
|
97
|
+
<canvas bind:this={canvas} class="absolute inset-0 h-full w-full opacity-80"></canvas>
|
|
98
|
+
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type ThumbnailRenderer = (ctx: CanvasRenderingContext2D, w: number, h: number, name: string, dateStr: string, seed: number, accent: string) => void;
|
|
2
|
+
export declare const gradientMesh: ThumbnailRenderer;
|
|
3
|
+
export declare const boldType: ThumbnailRenderer;
|
|
4
|
+
export declare const minimal: ThumbnailRenderer;
|
|
5
|
+
export declare const geometric: ThumbnailRenderer;
|
|
6
|
+
export declare const darkGradient: ThumbnailRenderer;
|
|
7
|
+
export declare const waves: ThumbnailRenderer;
|
|
8
|
+
/** Textless gradient-mesh preset — built from 6 overlapping radial hotspots
|
|
9
|
+
* placed around a loose 3×2 grid with seeded jitter. Used as the default
|
|
10
|
+
* thumbnail for new events. */
|
|
11
|
+
export declare const plainMesh: ThumbnailRenderer;
|
|
12
|
+
export declare const DEFAULT_PRESET = "plain";
|
|
13
|
+
export declare const designs: Record<string, ThumbnailRenderer>;
|
|
14
|
+
export declare function resolveAccentColor(name?: string): string;
|
|
15
|
+
/** Stable non-zero integer seed derived from a string (e.g. an event rkey).
|
|
16
|
+
* Same input always produces the same seed, so the picker preview matches
|
|
17
|
+
* the uploaded PNG for a given event. */
|
|
18
|
+
export declare function hashSeed(s: string): number;
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
function lch(accent, l, c = 'c', hShift = 0, a = 1) {
|
|
2
|
+
const lStr = typeof l === 'number' ? l.toFixed(3) : l;
|
|
3
|
+
const cStr = typeof c === 'number' ? c.toFixed(3) : c;
|
|
4
|
+
const hStr = hShift === 0 ? 'h' : `calc(h + ${hShift})`;
|
|
5
|
+
return `oklch(from ${accent} ${lStr} ${cStr} ${hStr} / ${a})`;
|
|
6
|
+
}
|
|
7
|
+
/** Monochrome film-grain overlay. Reads back pixels and perturbs each RGB
|
|
8
|
+
* channel by ±intensity/255 using a seeded LCG — deterministic, so picker
|
|
9
|
+
* previews and the uploaded PNG match. Call as the final step of a design. */
|
|
10
|
+
function addNoise(ctx, w, h, seed, intensity = 7) {
|
|
11
|
+
const img = ctx.getImageData(0, 0, w, h);
|
|
12
|
+
const data = img.data;
|
|
13
|
+
let s = seed | 0 || 1;
|
|
14
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
15
|
+
s = (Math.imul(s, 1664525) + 1013904223) | 0;
|
|
16
|
+
const n = ((s >>> 16) & 0xff) / 255 - 0.5;
|
|
17
|
+
const d = n * 2 * intensity;
|
|
18
|
+
data[i] = Math.max(0, Math.min(255, data[i] + d));
|
|
19
|
+
data[i + 1] = Math.max(0, Math.min(255, data[i + 1] + d));
|
|
20
|
+
data[i + 2] = Math.max(0, Math.min(255, data[i + 2] + d));
|
|
21
|
+
}
|
|
22
|
+
ctx.putImageData(img, 0, 0);
|
|
23
|
+
}
|
|
24
|
+
function drawText(ctx, text, x, y, maxWidth, fontSize, fontWeight, color, align = 'center') {
|
|
25
|
+
ctx.fillStyle = color;
|
|
26
|
+
ctx.font = `${fontWeight} ${fontSize}px system-ui, -apple-system, sans-serif`;
|
|
27
|
+
ctx.textAlign = align;
|
|
28
|
+
ctx.textBaseline = 'middle';
|
|
29
|
+
const words = text.split(' ');
|
|
30
|
+
const lines = [];
|
|
31
|
+
let line = '';
|
|
32
|
+
for (const word of words) {
|
|
33
|
+
const test = line ? `${line} ${word}` : word;
|
|
34
|
+
if (ctx.measureText(test).width > maxWidth && line) {
|
|
35
|
+
lines.push(line);
|
|
36
|
+
line = word;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
line = test;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (line)
|
|
43
|
+
lines.push(line);
|
|
44
|
+
const lineHeight = fontSize * 1.2;
|
|
45
|
+
const totalHeight = lines.length * lineHeight;
|
|
46
|
+
const startY = y - totalHeight / 2 + lineHeight / 2;
|
|
47
|
+
for (let i = 0; i < lines.length; i++) {
|
|
48
|
+
ctx.fillText(lines[i], x, startY + i * lineHeight, maxWidth);
|
|
49
|
+
}
|
|
50
|
+
return totalHeight;
|
|
51
|
+
}
|
|
52
|
+
export const gradientMesh = (ctx, w, h, name, dateStr, seed, accent) => {
|
|
53
|
+
const angle = (seed * 47) % 360;
|
|
54
|
+
const rad = (angle * Math.PI) / 180;
|
|
55
|
+
const cx = w / 2 + (Math.cos(rad) * w) / 2;
|
|
56
|
+
const cy = h / 2 + (Math.sin(rad) * h) / 2;
|
|
57
|
+
const shiftA = ((seed * 37) % 60) - 30;
|
|
58
|
+
const shiftB = ((seed * 71) % 70) + 20;
|
|
59
|
+
const bg = ctx.createLinearGradient(w - cx, h - cy, cx, cy);
|
|
60
|
+
bg.addColorStop(0, lch(accent, 0.55, 'c', shiftA));
|
|
61
|
+
bg.addColorStop(0.5, lch(accent, 0.45, 'c', 0));
|
|
62
|
+
bg.addColorStop(1, lch(accent, 0.35, 'c', -shiftB));
|
|
63
|
+
ctx.fillStyle = bg;
|
|
64
|
+
ctx.fillRect(0, 0, w, h);
|
|
65
|
+
function blob(x, y, r, hShift, alpha) {
|
|
66
|
+
const g = ctx.createRadialGradient(x, y, 0, x, y, r);
|
|
67
|
+
g.addColorStop(0, lch(accent, 0.75, 'c', hShift, alpha));
|
|
68
|
+
g.addColorStop(1, lch(accent, 0.75, 'c', hShift, 0));
|
|
69
|
+
ctx.fillStyle = g;
|
|
70
|
+
ctx.fillRect(x - r, y - r, r * 2, r * 2);
|
|
71
|
+
}
|
|
72
|
+
const p = (i, m) => ((seed * i) % m) / m;
|
|
73
|
+
blob(w * (-0.1 + p(17, 30) * 0.3), h * (-0.1 + p(23, 30) * 0.3), w * 0.4, shiftA * 1.5, 0.45);
|
|
74
|
+
blob(w * (1.1 - p(13, 30) * 0.3), h * (1.1 - p(19, 30) * 0.3), w * 0.35, shiftB, 0.35);
|
|
75
|
+
blob(w * (0.3 + p(29, 40) * 0.4), h * (0.3 + p(31, 40) * 0.4), w * 0.3, -shiftA, 0.3);
|
|
76
|
+
if (name) {
|
|
77
|
+
const th = drawText(ctx, name, w / 2, h / 2 - 10, w * 0.75, w * 0.09, 'bold', 'white');
|
|
78
|
+
if (dateStr) {
|
|
79
|
+
drawText(ctx, dateStr, w / 2, h / 2 + th / 2 + w * 0.03, w * 0.7, w * 0.04, '500', 'rgba(255,255,255,0.85)');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
addNoise(ctx, w, h, seed);
|
|
83
|
+
};
|
|
84
|
+
export const boldType = (ctx, w, h, name, dateStr, seed, accent) => {
|
|
85
|
+
ctx.fillStyle = lch(accent, 0.12, 0.025);
|
|
86
|
+
ctx.fillRect(0, 0, w, h);
|
|
87
|
+
const angle = (seed * 53) % 360;
|
|
88
|
+
const rad = (angle * Math.PI) / 180;
|
|
89
|
+
const hl = ctx.createLinearGradient(w / 2 - (Math.cos(rad) * w) / 2, h / 2 - (Math.sin(rad) * h) / 2, w / 2 + (Math.cos(rad) * w) / 2, h / 2 + (Math.sin(rad) * h) / 2);
|
|
90
|
+
hl.addColorStop(0, lch(accent, 0.22, 'c', 0, 0.4));
|
|
91
|
+
hl.addColorStop(1, lch(accent, 0.1, 0.02, 0, 0));
|
|
92
|
+
ctx.fillStyle = hl;
|
|
93
|
+
ctx.fillRect(0, 0, w, h);
|
|
94
|
+
if (name) {
|
|
95
|
+
drawText(ctx, name, w * 0.07, h * 0.72, w * 0.86, w * 0.11, '900', lch(accent, 0.75, 'c'), 'left');
|
|
96
|
+
}
|
|
97
|
+
if (dateStr) {
|
|
98
|
+
ctx.fillStyle = lch(accent, 0.55, 0.03, 0, 0.9);
|
|
99
|
+
ctx.font = `500 ${w * 0.04}px system-ui, -apple-system, sans-serif`;
|
|
100
|
+
ctx.textAlign = 'left';
|
|
101
|
+
ctx.textBaseline = 'top';
|
|
102
|
+
ctx.fillText(dateStr, w * 0.07, h * 0.88);
|
|
103
|
+
}
|
|
104
|
+
addNoise(ctx, w, h, seed);
|
|
105
|
+
};
|
|
106
|
+
export const minimal = (ctx, w, h, name, dateStr, seed, accent) => {
|
|
107
|
+
ctx.fillStyle = lch(accent, 0.97, 0.02);
|
|
108
|
+
ctx.fillRect(0, 0, w, h);
|
|
109
|
+
const edge = seed % 4;
|
|
110
|
+
ctx.fillStyle = lch(accent, 0.55, 'c');
|
|
111
|
+
if (edge === 0)
|
|
112
|
+
ctx.fillRect(0, h * 0.5 - 1.5, w * 0.12, 3);
|
|
113
|
+
else if (edge === 1)
|
|
114
|
+
ctx.fillRect(w * 0.88, h * 0.5 - 1.5, w * 0.12, 3);
|
|
115
|
+
else if (edge === 2)
|
|
116
|
+
ctx.fillRect(w * 0.44, 0, 3, h * 0.12);
|
|
117
|
+
else
|
|
118
|
+
ctx.fillRect(w * 0.44, h * 0.88, 3, h * 0.12);
|
|
119
|
+
if (name) {
|
|
120
|
+
const th = drawText(ctx, name, w / 2, h / 2 - 10, w * 0.75, w * 0.09, '600', lch(accent, 0.25, 'c'));
|
|
121
|
+
if (dateStr) {
|
|
122
|
+
drawText(ctx, dateStr, w / 2, h / 2 + th / 2 + w * 0.03, w * 0.7, w * 0.04, 'normal', lch(accent, 0.5, 'c'));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
addNoise(ctx, w, h, seed);
|
|
126
|
+
};
|
|
127
|
+
export const geometric = (ctx, w, h, name, dateStr, seed, accent) => {
|
|
128
|
+
ctx.fillStyle = lch(accent, 0.55, 'c');
|
|
129
|
+
ctx.fillRect(0, 0, w, h);
|
|
130
|
+
ctx.globalAlpha = 0.18;
|
|
131
|
+
for (let i = 0; i < 6; i++) {
|
|
132
|
+
const x = (((seed * 31 + i * 73) % 100) / 100) * w;
|
|
133
|
+
const y = (((seed * 47 + i * 59) % 100) / 100) * h;
|
|
134
|
+
const size = ((15 + ((seed * 13 + i * 41) % 25)) / 100) * w;
|
|
135
|
+
const type = i % 3;
|
|
136
|
+
const hShift = (((seed * 19 + i * 53) % 90) - 45) * 0.6;
|
|
137
|
+
ctx.fillStyle = lch(accent, 0.85, 'c', hShift);
|
|
138
|
+
ctx.save();
|
|
139
|
+
ctx.translate(x, y);
|
|
140
|
+
ctx.rotate((((seed * 23 + i * 67) % 360) * Math.PI) / 180);
|
|
141
|
+
if (type === 0) {
|
|
142
|
+
ctx.beginPath();
|
|
143
|
+
ctx.arc(0, 0, size / 2, 0, Math.PI * 2);
|
|
144
|
+
ctx.fill();
|
|
145
|
+
}
|
|
146
|
+
else if (type === 1) {
|
|
147
|
+
ctx.fillRect(-size / 2, -size / 2, size, size);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
ctx.beginPath();
|
|
151
|
+
ctx.moveTo(0, -size / 2);
|
|
152
|
+
ctx.lineTo(-size / 2, size / 2);
|
|
153
|
+
ctx.lineTo(size / 2, size / 2);
|
|
154
|
+
ctx.closePath();
|
|
155
|
+
ctx.fill();
|
|
156
|
+
}
|
|
157
|
+
ctx.restore();
|
|
158
|
+
}
|
|
159
|
+
ctx.globalAlpha = 1;
|
|
160
|
+
if (name) {
|
|
161
|
+
const th = drawText(ctx, name, w / 2, h / 2 - 10, w * 0.75, w * 0.09, 'bold', 'white');
|
|
162
|
+
if (dateStr) {
|
|
163
|
+
drawText(ctx, dateStr, w / 2, h / 2 + th / 2 + w * 0.03, w * 0.7, w * 0.04, '500', 'rgba(255,255,255,0.8)');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
addNoise(ctx, w, h, seed);
|
|
167
|
+
};
|
|
168
|
+
export const darkGradient = (ctx, w, h, name, dateStr, seed, accent) => {
|
|
169
|
+
const angle = (seed * 67) % 360;
|
|
170
|
+
const rad = (angle * Math.PI) / 180;
|
|
171
|
+
const bg = ctx.createLinearGradient(w / 2 - (Math.cos(rad) * w) / 2, h / 2 - (Math.sin(rad) * h) / 2, w / 2 + (Math.cos(rad) * w) / 2, h / 2 + (Math.sin(rad) * h) / 2);
|
|
172
|
+
bg.addColorStop(0, lch(accent, 0.18, 'c'));
|
|
173
|
+
bg.addColorStop(1, lch(accent, 0.06, 0.03));
|
|
174
|
+
ctx.fillStyle = bg;
|
|
175
|
+
ctx.fillRect(0, 0, w, h);
|
|
176
|
+
const edge = seed % 4;
|
|
177
|
+
const shift = ((seed * 43) % 120) - 60;
|
|
178
|
+
const line = ctx.createLinearGradient(0, 0, w, 0);
|
|
179
|
+
line.addColorStop(0, lch(accent, 0.65, 'c', shift));
|
|
180
|
+
line.addColorStop(1, lch(accent, 0.7, 'c', -shift));
|
|
181
|
+
ctx.fillStyle = line;
|
|
182
|
+
if (edge === 0)
|
|
183
|
+
ctx.fillRect(0, 0, w, h * 0.012);
|
|
184
|
+
else if (edge === 1)
|
|
185
|
+
ctx.fillRect(0, h * 0.988, w, h * 0.012);
|
|
186
|
+
else if (edge === 2)
|
|
187
|
+
ctx.fillRect(0, 0, w * 0.012, h);
|
|
188
|
+
else
|
|
189
|
+
ctx.fillRect(w * 0.988, 0, w * 0.012, h);
|
|
190
|
+
if (name) {
|
|
191
|
+
drawText(ctx, name, w * 0.07, h * 0.72, w * 0.86, w * 0.09, 'bold', 'white', 'left');
|
|
192
|
+
}
|
|
193
|
+
if (dateStr) {
|
|
194
|
+
ctx.fillStyle = lch(accent, 0.65, 'c');
|
|
195
|
+
ctx.font = `normal ${w * 0.04}px system-ui, -apple-system, sans-serif`;
|
|
196
|
+
ctx.textAlign = 'left';
|
|
197
|
+
ctx.textBaseline = 'top';
|
|
198
|
+
ctx.fillText(dateStr, w * 0.07, h * 0.88);
|
|
199
|
+
}
|
|
200
|
+
addNoise(ctx, w, h, seed);
|
|
201
|
+
};
|
|
202
|
+
export const waves = (ctx, w, h, name, dateStr, seed, accent) => {
|
|
203
|
+
ctx.fillStyle = lch(accent, 0.95, 0.04);
|
|
204
|
+
ctx.fillRect(0, 0, w, h);
|
|
205
|
+
function wave(yBase, amplitude, frequency, phase, color, alpha) {
|
|
206
|
+
ctx.globalAlpha = alpha;
|
|
207
|
+
ctx.fillStyle = color;
|
|
208
|
+
ctx.beginPath();
|
|
209
|
+
ctx.moveTo(0, yBase);
|
|
210
|
+
for (let x = 0; x <= w; x += 2) {
|
|
211
|
+
const y = yBase + Math.sin((x / w) * Math.PI * frequency + phase) * amplitude;
|
|
212
|
+
ctx.lineTo(x, y);
|
|
213
|
+
}
|
|
214
|
+
ctx.lineTo(w, h);
|
|
215
|
+
ctx.lineTo(0, h);
|
|
216
|
+
ctx.closePath();
|
|
217
|
+
ctx.fill();
|
|
218
|
+
}
|
|
219
|
+
const freq = 2 + (seed % 3);
|
|
220
|
+
const phase = seed;
|
|
221
|
+
wave(h * 0.7, h * 0.05, freq, phase, lch(accent, 0.78, 'c', 20), 0.55);
|
|
222
|
+
wave(h * 0.78, h * 0.04, freq + 1, phase + 1, lch(accent, 0.65, 'c', 0), 0.5);
|
|
223
|
+
wave(h * 0.85, h * 0.03, freq + 2, phase + 2, lch(accent, 0.5, 'c', -20), 0.55);
|
|
224
|
+
ctx.globalAlpha = 1;
|
|
225
|
+
if (name) {
|
|
226
|
+
const th = drawText(ctx, name, w / 2, h * 0.4, w * 0.75, w * 0.09, 'bold', lch(accent, 0.25, 'c'));
|
|
227
|
+
if (dateStr) {
|
|
228
|
+
drawText(ctx, dateStr, w / 2, h * 0.4 + th / 2 + w * 0.03, w * 0.7, w * 0.04, '500', lch(accent, 0.45, 'c'));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
addNoise(ctx, w, h, seed);
|
|
232
|
+
};
|
|
233
|
+
/** Textless gradient-mesh preset — built from 6 overlapping radial hotspots
|
|
234
|
+
* placed around a loose 3×2 grid with seeded jitter. Used as the default
|
|
235
|
+
* thumbnail for new events. */
|
|
236
|
+
export const plainMesh = (ctx, w, h, _name, _dateStr, seed, accent) => {
|
|
237
|
+
const p = (i, m) => ((seed * i) % m) / m;
|
|
238
|
+
const jitter = (i, amt) => (p(i, 100) - 0.5) * amt;
|
|
239
|
+
// Mid-tone accent base so the hotspots read as both lighter and darker pools
|
|
240
|
+
ctx.fillStyle = lch(accent, 0.5, 'c');
|
|
241
|
+
ctx.fillRect(0, 0, w, h);
|
|
242
|
+
// Six hotspots anchored to a 3x2 grid, each jittered and hue-shifted
|
|
243
|
+
// independently so no two thumbnails look the same.
|
|
244
|
+
const anchors = [
|
|
245
|
+
{ x: 0.18, y: 0.22 },
|
|
246
|
+
{ x: 0.55, y: 0.15 },
|
|
247
|
+
{ x: 0.85, y: 0.35 },
|
|
248
|
+
{ x: 0.2, y: 0.72 },
|
|
249
|
+
{ x: 0.55, y: 0.85 },
|
|
250
|
+
{ x: 0.88, y: 0.78 }
|
|
251
|
+
];
|
|
252
|
+
// Alternating light/dark levels and hue shifts spread across the spectrum
|
|
253
|
+
const levels = [0.8, 0.62, 0.78, 0.38, 0.72, 0.48];
|
|
254
|
+
const shifts = [-55, 25, 55, -25, 40, -40];
|
|
255
|
+
for (let i = 0; i < anchors.length; i++) {
|
|
256
|
+
const a = anchors[i];
|
|
257
|
+
const x = (a.x + jitter(11 + i * 7, 0.18)) * w;
|
|
258
|
+
const y = (a.y + jitter(17 + i * 11, 0.18)) * h;
|
|
259
|
+
const r = w * (0.45 + p(23 + i * 5, 40) * 0.25);
|
|
260
|
+
const hShift = shifts[i] + jitter(29 + i * 13, 20);
|
|
261
|
+
const l = levels[i] + jitter(31 + i * 3, 0.08);
|
|
262
|
+
const alpha = 0.55 + p(37 + i * 3, 20) * 0.1;
|
|
263
|
+
const g = ctx.createRadialGradient(x, y, 0, x, y, r);
|
|
264
|
+
g.addColorStop(0, lch(accent, l, 'c', hShift, alpha));
|
|
265
|
+
g.addColorStop(1, lch(accent, l, 'c', hShift, 0));
|
|
266
|
+
ctx.fillStyle = g;
|
|
267
|
+
ctx.fillRect(0, 0, w, h);
|
|
268
|
+
}
|
|
269
|
+
addNoise(ctx, w, h, seed);
|
|
270
|
+
};
|
|
271
|
+
export const DEFAULT_PRESET = 'plain';
|
|
272
|
+
export const designs = {
|
|
273
|
+
plain: plainMesh,
|
|
274
|
+
gradient: gradientMesh,
|
|
275
|
+
bold: boldType,
|
|
276
|
+
minimal,
|
|
277
|
+
geometric,
|
|
278
|
+
dark: darkGradient,
|
|
279
|
+
waves
|
|
280
|
+
};
|
|
281
|
+
/** Concrete oklch() values for each Tailwind accent-500, so canvas rendering
|
|
282
|
+
* stays in sync with the theme without depending on CSS-var resolution timing
|
|
283
|
+
* (also works during SSR and before the theme class is applied). */
|
|
284
|
+
const ACCENT_OKLCH = {
|
|
285
|
+
red: 'oklch(0.637 0.237 25.331)',
|
|
286
|
+
orange: 'oklch(0.705 0.213 47.604)',
|
|
287
|
+
amber: 'oklch(0.769 0.188 70.08)',
|
|
288
|
+
yellow: 'oklch(0.795 0.184 86.047)',
|
|
289
|
+
lime: 'oklch(0.768 0.233 130.85)',
|
|
290
|
+
green: 'oklch(0.723 0.219 149.579)',
|
|
291
|
+
emerald: 'oklch(0.696 0.17 162.48)',
|
|
292
|
+
teal: 'oklch(0.704 0.14 182.503)',
|
|
293
|
+
cyan: 'oklch(0.715 0.143 215.221)',
|
|
294
|
+
sky: 'oklch(0.685 0.169 237.323)',
|
|
295
|
+
blue: 'oklch(0.623 0.214 259.815)',
|
|
296
|
+
indigo: 'oklch(0.585 0.233 277.117)',
|
|
297
|
+
violet: 'oklch(0.606 0.25 292.717)',
|
|
298
|
+
purple: 'oklch(0.627 0.265 303.9)',
|
|
299
|
+
fuchsia: 'oklch(0.667 0.295 322.15)',
|
|
300
|
+
pink: 'oklch(0.656 0.241 354.308)',
|
|
301
|
+
rose: 'oklch(0.645 0.246 16.439)'
|
|
302
|
+
};
|
|
303
|
+
export function resolveAccentColor(name) {
|
|
304
|
+
return (name && ACCENT_OKLCH[name]) || ACCENT_OKLCH.cyan;
|
|
305
|
+
}
|
|
306
|
+
/** Stable non-zero integer seed derived from a string (e.g. an event rkey).
|
|
307
|
+
* Same input always produces the same seed, so the picker preview matches
|
|
308
|
+
* the uploaded PNG for a given event. */
|
|
309
|
+
export function hashSeed(s) {
|
|
310
|
+
let h = 2166136261;
|
|
311
|
+
for (let i = 0; i < s.length; i++) {
|
|
312
|
+
h ^= s.charCodeAt(i);
|
|
313
|
+
h = Math.imul(h, 16777619);
|
|
314
|
+
}
|
|
315
|
+
return Math.abs(h) || 1;
|
|
316
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atmo-dev/events-ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Svelte components for atmo events (EventView, EventEditor, EventCard).",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/flo-bit/atmo-events.git",
|
|
10
|
+
"directory": "packages/ui"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/flo-bit/atmo-events/tree/main/packages/ui#readme",
|
|
13
|
+
"bugs": "https://github.com/flo-bit/atmo-events/issues",
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"package": "svelte-kit sync && svelte-package -i src -o dist && publint",
|
|
19
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
20
|
+
"prepublishOnly": "pnpm package"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"!dist/**/*.test.*",
|
|
25
|
+
"!dist/**/*.spec.*"
|
|
26
|
+
],
|
|
27
|
+
"sideEffects": [
|
|
28
|
+
"**/*.css"
|
|
29
|
+
],
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"svelte": "./dist/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"svelte": "./dist/index.js",
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@foxui/core": "^0.9.0",
|
|
39
|
+
"@foxui/social": "^0.8.0",
|
|
40
|
+
"@foxui/text": "^0.8.0",
|
|
41
|
+
"@foxui/time": "^0.8.0",
|
|
42
|
+
"@foxui/visual": "^0.8.0",
|
|
43
|
+
"bits-ui": "^2.16.0",
|
|
44
|
+
"svelte": "^5.0.0",
|
|
45
|
+
"tailwindcss": "^4.0.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"maplibre-gl": {
|
|
49
|
+
"optional": true
|
|
50
|
+
},
|
|
51
|
+
"svelte-maplibre-gl": {
|
|
52
|
+
"optional": true
|
|
53
|
+
},
|
|
54
|
+
"hls.js": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"plyr": {
|
|
58
|
+
"optional": true
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"@atcute/bluesky-richtext-parser": "^2.1.1",
|
|
63
|
+
"@atcute/tid": "^1.1.2",
|
|
64
|
+
"@atmo-dev/contrail-lexicons": "^0.4.4",
|
|
65
|
+
"@internationalized/date": "^3.12.0",
|
|
66
|
+
"@number-flow/svelte": "^0.4.0",
|
|
67
|
+
"dompurify": "^3.3.3",
|
|
68
|
+
"esm-env": "^1.2.2",
|
|
69
|
+
"marked": "^17.0.5",
|
|
70
|
+
"svelte-boring-avatars": "^1.2.6",
|
|
71
|
+
"svelte-tiptap": "^3.0.1",
|
|
72
|
+
"valibot": "^1.3.1"
|
|
73
|
+
},
|
|
74
|
+
"devDependencies": {
|
|
75
|
+
"@foxui/core": "^0.9.1",
|
|
76
|
+
"@foxui/social": "^0.8.10",
|
|
77
|
+
"@foxui/text": "^0.8.5",
|
|
78
|
+
"@foxui/time": "^0.8.5",
|
|
79
|
+
"@foxui/visual": "^0.8.7",
|
|
80
|
+
"@sveltejs/kit": "^2.55.0",
|
|
81
|
+
"@sveltejs/package": "^2.5.5",
|
|
82
|
+
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
|
83
|
+
"bits-ui": "^2.16.3",
|
|
84
|
+
"hls.js": "^1.6.15",
|
|
85
|
+
"maplibre-gl": "^5.21.1",
|
|
86
|
+
"plyr": "^3.8.4",
|
|
87
|
+
"publint": "^0.3.16",
|
|
88
|
+
"svelte": "^5.55.0",
|
|
89
|
+
"svelte-check": "^4.4.8",
|
|
90
|
+
"svelte-maplibre-gl": "^1.0.3",
|
|
91
|
+
"tailwindcss": "^4.2.2",
|
|
92
|
+
"typescript": "^6.0.2",
|
|
93
|
+
"vite": "^8.0.3"
|
|
94
|
+
}
|
|
95
|
+
}
|