@atmo-dev/kit 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/README.md +35 -0
  2. package/dist/events/DatePicker.svelte +222 -0
  3. package/dist/events/DatePicker.svelte.d.ts +12 -0
  4. package/dist/events/DateTimePicker.svelte +112 -0
  5. package/dist/events/DateTimePicker.svelte.d.ts +10 -0
  6. package/dist/events/EventAttendees.svelte +199 -0
  7. package/dist/events/EventAttendees.svelte.d.ts +19 -0
  8. package/dist/events/EventCard.svelte +148 -0
  9. package/dist/events/EventCard.svelte.d.ts +8 -0
  10. package/dist/events/EventComments.svelte +98 -0
  11. package/dist/events/EventComments.svelte.d.ts +8 -0
  12. package/dist/events/EventEditor.svelte +540 -0
  13. package/dist/events/EventEditor.svelte.d.ts +18 -0
  14. package/dist/events/EventRsvp.svelte +178 -0
  15. package/dist/events/EventRsvp.svelte.d.ts +16 -0
  16. package/dist/events/EventView.svelte +488 -0
  17. package/dist/events/EventView.svelte.d.ts +23 -0
  18. package/dist/events/ImageDropper.svelte +66 -0
  19. package/dist/events/ImageDropper.svelte.d.ts +7 -0
  20. package/dist/events/Map.svelte +36 -0
  21. package/dist/events/Map.svelte.d.ts +8 -0
  22. package/dist/events/PostToBlueskyModal.svelte +246 -0
  23. package/dist/events/PostToBlueskyModal.svelte.d.ts +22 -0
  24. package/dist/events/ShareModal.svelte +174 -0
  25. package/dist/events/ShareModal.svelte.d.ts +23 -0
  26. package/dist/events/StarterPackButton.svelte +72 -0
  27. package/dist/events/StarterPackButton.svelte.d.ts +10 -0
  28. package/dist/events/ThemeApply.svelte +30 -0
  29. package/dist/events/ThemeApply.svelte.d.ts +7 -0
  30. package/dist/events/ThemeBackground.svelte +33 -0
  31. package/dist/events/ThemeBackground.svelte.d.ts +7 -0
  32. package/dist/events/ThemePicker.svelte +104 -0
  33. package/dist/events/ThemePicker.svelte.d.ts +7 -0
  34. package/dist/events/ThumbnailPresets.svelte +71 -0
  35. package/dist/events/ThumbnailPresets.svelte.d.ts +11 -0
  36. package/dist/events/TimePicker.svelte +117 -0
  37. package/dist/events/TimePicker.svelte.d.ts +10 -0
  38. package/dist/events/TimezonePicker.svelte +67 -0
  39. package/dist/events/TimezonePicker.svelte.d.ts +6 -0
  40. package/dist/events/VodPlayer.svelte +154 -0
  41. package/dist/events/VodPlayer.svelte.d.ts +14 -0
  42. package/dist/events/VodTranscript.svelte +75 -0
  43. package/dist/events/VodTranscript.svelte.d.ts +8 -0
  44. package/dist/events/atproto-helpers.d.ts +21 -0
  45. package/dist/events/atproto-helpers.js +61 -0
  46. package/dist/events/cal/helper.d.ts +1 -0
  47. package/dist/events/cal/helper.js +20 -0
  48. package/dist/events/cal/ical.d.ts +22 -0
  49. package/dist/events/cal/ical.js +188 -0
  50. package/dist/events/cal/sanitize.d.ts +3 -0
  51. package/dist/events/cal/sanitize.js +25 -0
  52. package/dist/events/conference.d.ts +65 -0
  53. package/dist/events/conference.js +61 -0
  54. package/dist/events/contrail.d.ts +49 -0
  55. package/dist/events/contrail.js +12 -0
  56. package/dist/events/date-format.d.ts +22 -0
  57. package/dist/events/date-format.js +43 -0
  58. package/dist/events/editor/LinkedRecordsPicker.svelte +104 -0
  59. package/dist/events/editor/LinkedRecordsPicker.svelte.d.ts +12 -0
  60. package/dist/events/editor/LinksSection.svelte +154 -0
  61. package/dist/events/editor/LinksSection.svelte.d.ts +13 -0
  62. package/dist/events/editor/LocationSection.svelte +163 -0
  63. package/dist/events/editor/LocationSection.svelte.d.ts +8 -0
  64. package/dist/events/editor/RecurringModal.svelte +313 -0
  65. package/dist/events/editor/RecurringModal.svelte.d.ts +30 -0
  66. package/dist/events/editor/ThemeSection.svelte +24 -0
  67. package/dist/events/editor/ThemeSection.svelte.d.ts +7 -0
  68. package/dist/events/editor/ThumbnailSection.svelte +181 -0
  69. package/dist/events/editor/ThumbnailSection.svelte.d.ts +13 -0
  70. package/dist/events/editor/adapter.d.ts +73 -0
  71. package/dist/events/editor/adapter.js +9 -0
  72. package/dist/events/editor/location.d.ts +16 -0
  73. package/dist/events/editor/location.js +50 -0
  74. package/dist/events/editor/save.d.ts +43 -0
  75. package/dist/events/editor/save.js +168 -0
  76. package/dist/events/editor/types.d.ts +39 -0
  77. package/dist/events/editor/types.js +9 -0
  78. package/dist/events/event-media.d.ts +4 -0
  79. package/dist/events/event-media.js +4 -0
  80. package/dist/events/event-types.d.ts +79 -0
  81. package/dist/events/event-types.js +11 -0
  82. package/dist/events/event-view/AddToCalendarButton.svelte +31 -0
  83. package/dist/events/event-view/AddToCalendarButton.svelte.d.ts +9 -0
  84. package/dist/events/event-view/EventBadges.svelte +20 -0
  85. package/dist/events/event-view/EventBadges.svelte.d.ts +7 -0
  86. package/dist/events/event-view/EventDateBlock.svelte +43 -0
  87. package/dist/events/event-view/EventDateBlock.svelte.d.ts +7 -0
  88. package/dist/events/event-view/EventHostedBy.svelte +61 -0
  89. package/dist/events/event-view/EventHostedBy.svelte.d.ts +16 -0
  90. package/dist/events/event-view/EventLinksList.svelte +24 -0
  91. package/dist/events/event-view/EventLinksList.svelte.d.ts +9 -0
  92. package/dist/events/event-view/EventLocationBlock.svelte +62 -0
  93. package/dist/events/event-view/EventLocationBlock.svelte.d.ts +7 -0
  94. package/dist/events/event-view/EventLocationMap.svelte +66 -0
  95. package/dist/events/event-view/EventLocationMap.svelte.d.ts +7 -0
  96. package/dist/events/event-view/ExternalRsvpNotice.svelte +34 -0
  97. package/dist/events/event-view/ExternalRsvpNotice.svelte.d.ts +6 -0
  98. package/dist/events/event-view/StreamPlacePlayer.svelte +209 -0
  99. package/dist/events/event-view/StreamPlacePlayer.svelte.d.ts +8 -0
  100. package/dist/events/event-view/format.d.ts +10 -0
  101. package/dist/events/event-view/format.js +112 -0
  102. package/dist/events/event-view/locations.d.ts +36 -0
  103. package/dist/events/event-view/locations.js +243 -0
  104. package/dist/events/event-view/plyr-icons.d.ts +3 -0
  105. package/dist/events/event-view/plyr-icons.js +46 -0
  106. package/dist/events/linked-records.d.ts +18 -0
  107. package/dist/events/linked-records.js +11 -0
  108. package/dist/events/profile-url.d.ts +3 -0
  109. package/dist/events/profile-url.js +11 -0
  110. package/dist/events/schedule/ConferenceTimetable.svelte +340 -0
  111. package/dist/events/schedule/ConferenceTimetable.svelte.d.ts +22 -0
  112. package/dist/events/schedule/DaySchedule.svelte +298 -0
  113. package/dist/events/schedule/DaySchedule.svelte.d.ts +26 -0
  114. package/dist/events/schedule/ScheduleEventCell.svelte +166 -0
  115. package/dist/events/schedule/ScheduleEventCell.svelte.d.ts +25 -0
  116. package/dist/events/schedule/schedule-utils.d.ts +44 -0
  117. package/dist/events/schedule/schedule-utils.js +166 -0
  118. package/dist/events/starter-pack-url.d.ts +3 -0
  119. package/dist/events/starter-pack-url.js +16 -0
  120. package/dist/events/theme.d.ts +9 -0
  121. package/dist/events/theme.js +36 -0
  122. package/dist/events/themes/Blobs.svelte +64 -0
  123. package/dist/events/themes/Blobs.svelte.d.ts +18 -0
  124. package/dist/events/themes/Butterflies.svelte +183 -0
  125. package/dist/events/themes/Butterflies.svelte.d.ts +3 -0
  126. package/dist/events/themes/Fireflies.svelte +134 -0
  127. package/dist/events/themes/Fireflies.svelte.d.ts +3 -0
  128. package/dist/events/themes/Kaleidoscope.svelte +183 -0
  129. package/dist/events/themes/Kaleidoscope.svelte.d.ts +3 -0
  130. package/dist/events/themes/Matrix.svelte +153 -0
  131. package/dist/events/themes/Matrix.svelte.d.ts +3 -0
  132. package/dist/events/themes/Stars.svelte +98 -0
  133. package/dist/events/themes/Stars.svelte.d.ts +3 -0
  134. package/dist/events/thumbnails/designs.d.ts +18 -0
  135. package/dist/events/thumbnails/designs.js +316 -0
  136. package/dist/events/view-data.d.ts +38 -0
  137. package/dist/events/view-data.js +1 -0
  138. package/dist/events-data.d.ts +15 -0
  139. package/dist/events-data.js +9 -0
  140. package/dist/events-editor.d.ts +2 -0
  141. package/dist/events-editor.js +2 -0
  142. package/dist/events.d.ts +19 -0
  143. package/dist/events.js +17 -0
  144. package/package.json +46 -4
@@ -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
+ }
@@ -0,0 +1,38 @@
1
+ import type { AttendeeInfo, FlatEventRecord, HostProfile } from './contrail.js';
2
+ /** App-loaded data for EventView; fetching and authorization stay in the host. */
3
+ export interface EventViewData {
4
+ eventData: FlatEventRecord;
5
+ actorDid: string;
6
+ rkey: string;
7
+ hostProfile?: HostProfile | null;
8
+ attendees: {
9
+ going: AttendeeInfo[];
10
+ interested: AttendeeInfo[];
11
+ goingCount?: number;
12
+ interestedCount?: number;
13
+ };
14
+ viewerRsvpStatus?: 'going' | 'interested' | 'notgoing' | null;
15
+ viewerRsvpRkey?: string | null;
16
+ ogImage?: string;
17
+ speakerProfiles?: Array<{
18
+ id?: string;
19
+ handle?: string;
20
+ name: string;
21
+ avatar?: string;
22
+ }>;
23
+ parentEvent?: FlatEventRecord | null;
24
+ parentEventActor?: string | null;
25
+ parentScheduleUrl?: string | null;
26
+ vod?: {
27
+ playlistUrl: string;
28
+ } | null;
29
+ conferenceTalks?: FlatEventRecord[];
30
+ conferenceTimezone?: string;
31
+ conferenceRsvpStatuses?: Record<string, string>;
32
+ conferenceRsvpRkeys?: Record<string, string>;
33
+ conferenceVods?: Record<string, {
34
+ playlistUrl: string;
35
+ subtitlesUrl?: string;
36
+ }>;
37
+ loggedIn?: boolean;
38
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,15 @@
1
+ /** Event types and pure helpers. Safe to import without Svelte, CSS or browser players. */
2
+ export type { EventViewData } from './events/view-data.js';
3
+ export type { EditorAdapter, EditorBlobRef, EditorViewer } from './events/editor/adapter.js';
4
+ export type { EventEditorPrefill } from './events/editor/types.js';
5
+ export type { EventData, EventLexiconMain, EventLocationVariant, EventStatus, EventMode as EventLexiconMode } from './events/event-types.js';
6
+ export type { FlatEventRecord, HostProfile, AttendeeInfo } from './events/contrail.js';
7
+ export { eventUrl, isEventOngoing, RSVP_GOING, RSVP_INTERESTED } from './events/contrail.js';
8
+ export * from './events/conference.js';
9
+ export * from './events/linked-records.js';
10
+ export * from './events/date-format.js';
11
+ export * from './events/theme.js';
12
+ export { getEventThumbnail } from './events/event-media.js';
13
+ export { getCDNImageBlobUrl, compressImage } from './events/atproto-helpers.js';
14
+ export { getProfileUrl, getLocalProfileUrl } from './events/profile-url.js';
15
+ export { normalizeCountryCode, normalizeEventLocations, LocationValidationError } from './events/editor/location.js';
@@ -0,0 +1,9 @@
1
+ export { eventUrl, isEventOngoing, RSVP_GOING, RSVP_INTERESTED } from './events/contrail.js';
2
+ export * from './events/conference.js';
3
+ export * from './events/linked-records.js';
4
+ export * from './events/date-format.js';
5
+ export * from './events/theme.js';
6
+ export { getEventThumbnail } from './events/event-media.js';
7
+ export { getCDNImageBlobUrl, compressImage } from './events/atproto-helpers.js';
8
+ export { getProfileUrl, getLocalProfileUrl } from './events/profile-url.js';
9
+ export { normalizeCountryCode, normalizeEventLocations, LocationValidationError } from './events/editor/location.js';
@@ -0,0 +1,2 @@
1
+ /** Event record construction, kept separate from the pure data and component APIs. */
2
+ export { buildEventRecord, buildThumbnailMedia } from './events/editor/save.js';
@@ -0,0 +1,2 @@
1
+ /** Event record construction, kept separate from the pure data and component APIs. */
2
+ export { buildEventRecord, buildThumbnailMedia } from './events/editor/save.js';
@@ -0,0 +1,19 @@
1
+ /** Shared event UI. Apps own sessions, transport, routes and persistence. */
2
+ export * from './events-data.js';
3
+ export { default as EventView } from './events/EventView.svelte';
4
+ export { default as EventEditor } from './events/EventEditor.svelte';
5
+ export { default as EventCard } from './events/EventCard.svelte';
6
+ export { default as EventRsvp } from './events/EventRsvp.svelte';
7
+ export { default as EventComments } from './events/EventComments.svelte';
8
+ export { default as EventAttendees } from './events/EventAttendees.svelte';
9
+ export type { AttendeeCounts } from './events/EventAttendees.svelte';
10
+ export { default as StarterPackButton } from './events/StarterPackButton.svelte';
11
+ export { default as VodPlayer } from './events/VodPlayer.svelte';
12
+ export type { VodPlayerApi } from './events/VodPlayer.svelte';
13
+ export { default as VodTranscript } from './events/VodTranscript.svelte';
14
+ export { default as ConferenceTimetable } from './events/schedule/ConferenceTimetable.svelte';
15
+ export { default as DatePicker } from './events/DatePicker.svelte';
16
+ export { default as TimePicker } from './events/TimePicker.svelte';
17
+ export { default as DateTimePicker } from './events/DateTimePicker.svelte';
18
+ export { default as TimezonePicker } from './events/TimezonePicker.svelte';
19
+ export { default as ImageDropper } from './events/ImageDropper.svelte';
package/dist/events.js ADDED
@@ -0,0 +1,17 @@
1
+ /** Shared event UI. Apps own sessions, transport, routes and persistence. */
2
+ export * from './events-data.js';
3
+ export { default as EventView } from './events/EventView.svelte';
4
+ export { default as EventEditor } from './events/EventEditor.svelte';
5
+ export { default as EventCard } from './events/EventCard.svelte';
6
+ export { default as EventRsvp } from './events/EventRsvp.svelte';
7
+ export { default as EventComments } from './events/EventComments.svelte';
8
+ export { default as EventAttendees } from './events/EventAttendees.svelte';
9
+ export { default as StarterPackButton } from './events/StarterPackButton.svelte';
10
+ export { default as VodPlayer } from './events/VodPlayer.svelte';
11
+ export { default as VodTranscript } from './events/VodTranscript.svelte';
12
+ export { default as ConferenceTimetable } from './events/schedule/ConferenceTimetable.svelte';
13
+ export { default as DatePicker } from './events/DatePicker.svelte';
14
+ export { default as TimePicker } from './events/TimePicker.svelte';
15
+ export { default as DateTimePicker } from './events/DateTimePicker.svelte';
16
+ export { default as TimezonePicker } from './events/TimezonePicker.svelte';
17
+ export { default as ImageDropper } from './events/ImageDropper.svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atmo-dev/kit",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "The shared UI foundation for Atmo apps.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -27,6 +27,19 @@
27
27
  "svelte": "./dist/index.js",
28
28
  "default": "./dist/index.js"
29
29
  },
30
+ "./events": {
31
+ "types": "./dist/events.d.ts",
32
+ "svelte": "./dist/events.js",
33
+ "default": "./dist/events.js"
34
+ },
35
+ "./events-data": {
36
+ "types": "./dist/events-data.d.ts",
37
+ "default": "./dist/events-data.js"
38
+ },
39
+ "./events/editor": {
40
+ "types": "./dist/events-editor.d.ts",
41
+ "default": "./dist/events-editor.js"
42
+ },
30
43
  "./grain": {
31
44
  "types": "./dist/grain.d.ts",
32
45
  "default": "./dist/grain.js"
@@ -52,10 +65,28 @@
52
65
  },
53
66
  "peerDependencies": {
54
67
  "svelte": ">=5.48.0 <6",
55
- "tailwindcss": "^4.0.0"
68
+ "tailwindcss": "^4.0.0",
69
+ "maplibre-gl": "^6.16.0",
70
+ "svelte-maplibre-gl": "^2.2.1",
71
+ "plyr": "^3.8.5"
72
+ },
73
+ "peerDependenciesMeta": {
74
+ "maplibre-gl": {
75
+ "optional": true
76
+ },
77
+ "svelte-maplibre-gl": {
78
+ "optional": true
79
+ },
80
+ "plyr": {
81
+ "optional": true
82
+ }
56
83
  },
57
84
  "devDependencies": {
58
85
  "@axe-core/playwright": "^4.14.0",
86
+ "axe-core": "^4.14.0",
87
+ "maplibre-gl": "^6.16.0",
88
+ "svelte-maplibre-gl": "^2.2.1",
89
+ "plyr": "^3.8.5",
59
90
  "@changesets/cli": "^2.31.1",
60
91
  "@eslint/js": "^10.0.1",
61
92
  "@playwright/test": "^1.60.0",
@@ -96,6 +127,16 @@
96
127
  },
97
128
  "dependencies": {
98
129
  "@atcute/bluesky-richtext-parser": "^2.1.2",
130
+ "@atcute/tid": "^1.1.4",
131
+ "@internationalized/date": "^3.12.4",
132
+ "@number-flow/svelte": "^0.4.2",
133
+ "dompurify": "^3.4.17",
134
+ "esm-env": "^1.2.2",
135
+ "h3-js": "^4.5.0",
136
+ "i18n-iso-countries": "^7.14.0",
137
+ "marked": "^18.1.2",
138
+ "svelte-boring-avatars": "^1.2.6",
139
+ "valibot": "^1.5.0",
99
140
  "@atcute/lexicons": "^2.1.1",
100
141
  "@fontsource-variable/figtree": "^5.3.0",
101
142
  "@sketchyicons/svelte": "^0.5.0",
@@ -122,9 +163,10 @@
122
163
  "lint": "prettier --check . && eslint .",
123
164
  "format": "prettier --write .",
124
165
  "test:unit": "vitest",
125
- "test": "pnpm test:unit --run && pnpm test:e2e",
126
- "test:ci": "pnpm test:unit --run --no-file-parallelism && pnpm test:e2e",
166
+ "test": "pnpm test:unit --run && pnpm test:e2e && pnpm test:package",
167
+ "test:ci": "pnpm test:unit --run --no-file-parallelism && pnpm test:e2e && pnpm test:package",
127
168
  "test:e2e": "playwright test",
169
+ "test:package": "pnpm prepack && node --test scripts/test-events-package.mjs",
128
170
  "changeset": "changeset",
129
171
  "version-packages": "changeset version && pnpm install --lockfile-only --no-frozen-lockfile --ignore-scripts",
130
172
  "release": "pnpm prepack && changeset publish"