ds-one 0.2.5-alpha.8 → 0.3.0-alpha.1

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 (213) hide show
  1. package/DS1/0-face/device.ts +138 -0
  2. package/DS1/0-face/i18n.ts +36 -89
  3. package/DS1/0-face/scaling.ts +152 -0
  4. package/DS1/1-root/fonts/Iosevka-Regular.woff2 +0 -0
  5. package/DS1/1-root/one.css +124 -77
  6. package/DS1/2-core/ds-banner.ts +120 -1
  7. package/DS1/2-core/ds-button.ts +16 -96
  8. package/DS1/2-core/ds-card.ts +137 -0
  9. package/DS1/2-core/ds-cycle.ts +82 -184
  10. package/DS1/2-core/ds-date.ts +3 -10
  11. package/DS1/2-core/ds-gap.ts +38 -0
  12. package/DS1/2-core/ds-icon.ts +6 -35
  13. package/DS1/2-core/ds-input.ts +306 -1
  14. package/DS1/2-core/ds-pagedots.ts +52 -0
  15. package/DS1/2-core/ds-text.ts +55 -28
  16. package/DS1/2-core/ds-tooltip.ts +14 -66
  17. package/DS1/2-core/styles/ds-banner.css +77 -0
  18. package/DS1/2-core/styles/ds-button.css +67 -0
  19. package/DS1/2-core/styles/ds-cycle.css +21 -0
  20. package/DS1/2-core/styles/ds-date.css +9 -0
  21. package/DS1/2-core/styles/ds-gap.css +93 -0
  22. package/DS1/2-core/styles/ds-icon.css +30 -0
  23. package/DS1/2-core/styles/ds-input.css +46 -0
  24. package/DS1/2-core/styles/ds-pagedots.css +31 -0
  25. package/DS1/2-core/styles/ds-text.css +29 -0
  26. package/DS1/2-core/styles/ds-tooltip.css +49 -0
  27. package/DS1/3-unit/ds-accordion.ts +95 -0
  28. package/DS1/3-unit/ds-form.ts +304 -0
  29. package/DS1/3-unit/ds-list.ts +5 -14
  30. package/DS1/3-unit/ds-row.ts +3 -19
  31. package/DS1/3-unit/ds-table.ts +3 -86
  32. package/DS1/3-unit/styles/ds-accordion.css +46 -0
  33. package/DS1/3-unit/styles/ds-list.css +9 -0
  34. package/DS1/3-unit/styles/ds-row.css +19 -0
  35. package/DS1/3-unit/styles/ds-table.css +80 -0
  36. package/DS1/4-page/ds-container.ts +28 -0
  37. package/DS1/4-page/ds-grid.ts +37 -50
  38. package/DS1/4-page/ds-layout.ts +652 -163
  39. package/DS1/4-page/styles/ds-container.css +35 -0
  40. package/DS1/4-page/styles/ds-grid.css +56 -0
  41. package/DS1/4-page/styles/ds-layout.css +246 -0
  42. package/DS1/index.ts +9 -1
  43. package/DS1/vite-env.d.ts +13 -0
  44. package/DS1/x-icon/2x.svg +4 -0
  45. package/DS1/x-icon/2xdots.svg +18 -0
  46. package/DS1/x-icon/2xgrid.svg +6 -0
  47. package/DS1/x-icon/2xlines.svg +6 -0
  48. package/DS1/x-icon/4x4.svg +18 -0
  49. package/DS1/x-icon/apple.svg +4 -0
  50. package/DS1/x-icon/avatar.svg +4 -0
  51. package/DS1/x-icon/big.svg +4 -0
  52. package/DS1/x-icon/blank.svg +3 -0
  53. package/DS1/x-icon/check.svg +3 -0
  54. package/DS1/x-icon/close.svg +3 -0
  55. package/DS1/x-icon/collapse.svg +3 -0
  56. package/DS1/x-icon/color.svg +4 -0
  57. package/DS1/x-icon/column.svg +5 -0
  58. package/DS1/x-icon/default.svg +3 -0
  59. package/DS1/x-icon/delete.svg +5 -0
  60. package/DS1/x-icon/dictate.svg +6 -0
  61. package/DS1/x-icon/do.svg +3 -0
  62. package/DS1/x-icon/down.svg +3 -0
  63. package/DS1/x-icon/duplicate.svg +4 -0
  64. package/DS1/x-icon/gallery.svg +5 -0
  65. package/DS1/x-icon/google.svg +6 -0
  66. package/DS1/x-icon/head.svg +5 -0
  67. package/DS1/x-icon/home.svg +3 -0
  68. package/DS1/x-icon/icon.svg +4 -0
  69. package/DS1/x-icon/in.svg +4 -0
  70. package/DS1/x-icon/lock.svg +5 -0
  71. package/DS1/x-icon/loop.svg +5 -0
  72. package/DS1/x-icon/mic.svg +5 -0
  73. package/DS1/x-icon/minimize.svg +3 -0
  74. package/DS1/x-icon/more.svg +5 -0
  75. package/DS1/x-icon/neutral.svg +6 -0
  76. package/DS1/x-icon/note.svg +6 -0
  77. package/DS1/x-icon/page.svg +4 -0
  78. package/DS1/x-icon/plus.svg +3 -0
  79. package/DS1/x-icon/rewind.svg +4 -0
  80. package/DS1/x-icon/row.svg +5 -0
  81. package/DS1/x-icon/sdown.svg +3 -0
  82. package/DS1/x-icon/search.svg +4 -0
  83. package/DS1/x-icon/see.svg +4 -0
  84. package/DS1/x-icon/ship.svg +5 -0
  85. package/DS1/x-icon/star.svg +3 -0
  86. package/DS1/x-icon/status.svg +4 -0
  87. package/DS1/x-icon/sup.svg +3 -0
  88. package/DS1/x-icon/title.svg +3 -0
  89. package/DS1/x-icon/undo.svg +3 -0
  90. package/DS1/x-icon/ungroup.svg +4 -0
  91. package/DS1/x-icon/unhead.svg +3 -0
  92. package/DS1/x-icon/unicon.svg +3 -0
  93. package/DS1/x-icon/unlock.svg +5 -0
  94. package/DS1/x-icon/unmic.svg +6 -0
  95. package/DS1/x-icon/unsee.svg +5 -0
  96. package/DS1/x-icon/unstar.svg +3 -0
  97. package/DS1/x-icon/untitle.svg +3 -0
  98. package/DS1/x-icon/up.svg +3 -0
  99. package/LICENSE +1 -1
  100. package/README.md +4 -4
  101. package/dist/0-face/device.d.ts +5 -0
  102. package/dist/0-face/device.d.ts.map +1 -1
  103. package/dist/0-face/device.js +111 -0
  104. package/dist/0-face/i18n.d.ts +0 -2
  105. package/dist/0-face/i18n.d.ts.map +1 -1
  106. package/dist/0-face/i18n.js +36 -73
  107. package/dist/0-face/scaling.d.ts +48 -0
  108. package/dist/0-face/scaling.d.ts.map +1 -0
  109. package/dist/0-face/scaling.js +114 -0
  110. package/dist/2-core/ds-banner.d.ts +67 -0
  111. package/dist/2-core/ds-banner.d.ts.map +1 -1
  112. package/dist/2-core/ds-banner.js +97 -1
  113. package/dist/2-core/ds-button.d.ts +4 -20
  114. package/dist/2-core/ds-button.d.ts.map +1 -1
  115. package/dist/2-core/ds-button.js +14 -88
  116. package/dist/2-core/ds-card.d.ts +39 -0
  117. package/dist/2-core/ds-card.d.ts.map +1 -0
  118. package/dist/2-core/ds-card.js +119 -0
  119. package/dist/2-core/ds-cycle.d.ts +1 -5
  120. package/dist/2-core/ds-cycle.d.ts.map +1 -1
  121. package/dist/2-core/ds-cycle.js +79 -166
  122. package/dist/2-core/ds-date.d.ts.map +1 -1
  123. package/dist/2-core/ds-date.js +3 -9
  124. package/dist/2-core/ds-gap.d.ts +28 -0
  125. package/dist/2-core/ds-gap.d.ts.map +1 -0
  126. package/dist/2-core/ds-gap.js +25 -0
  127. package/dist/2-core/ds-icon.d.ts.map +1 -1
  128. package/dist/2-core/ds-icon.js +6 -35
  129. package/dist/2-core/ds-input.d.ts +127 -0
  130. package/dist/2-core/ds-input.d.ts.map +1 -1
  131. package/dist/2-core/ds-input.js +252 -1
  132. package/dist/2-core/ds-pagedots.d.ts +32 -0
  133. package/dist/2-core/ds-pagedots.d.ts.map +1 -0
  134. package/dist/2-core/ds-pagedots.js +36 -0
  135. package/dist/2-core/ds-text.d.ts +5 -3
  136. package/dist/2-core/ds-text.d.ts.map +1 -1
  137. package/dist/2-core/ds-text.js +49 -27
  138. package/dist/2-core/ds-tooltip.d.ts +3 -3
  139. package/dist/2-core/ds-tooltip.d.ts.map +1 -1
  140. package/dist/2-core/ds-tooltip.js +13 -65
  141. package/dist/2-core/styles/ds-banner.css +77 -0
  142. package/dist/2-core/styles/ds-button.css +67 -0
  143. package/dist/2-core/styles/ds-cycle.css +21 -0
  144. package/dist/2-core/styles/ds-date.css +9 -0
  145. package/dist/2-core/styles/ds-gap.css +93 -0
  146. package/dist/2-core/styles/ds-icon.css +30 -0
  147. package/dist/2-core/styles/ds-input.css +46 -0
  148. package/dist/2-core/styles/ds-pagedots.css +26 -0
  149. package/dist/2-core/styles/ds-text.css +29 -0
  150. package/dist/2-core/styles/ds-tooltip.css +49 -0
  151. package/dist/3-unit/ds-accordion.d.ts +47 -0
  152. package/dist/3-unit/ds-accordion.d.ts.map +1 -0
  153. package/dist/3-unit/ds-accordion.js +75 -0
  154. package/dist/3-unit/ds-form.d.ts +70 -0
  155. package/dist/3-unit/ds-form.d.ts.map +1 -0
  156. package/dist/3-unit/ds-form.js +232 -0
  157. package/dist/3-unit/ds-list.d.ts.map +1 -1
  158. package/dist/3-unit/ds-list.js +5 -11
  159. package/dist/3-unit/ds-row.d.ts.map +1 -1
  160. package/dist/3-unit/ds-row.js +3 -19
  161. package/dist/3-unit/ds-table.d.ts.map +1 -1
  162. package/dist/3-unit/ds-table.js +3 -86
  163. package/dist/3-unit/styles/ds-accordion.css +46 -0
  164. package/dist/3-unit/styles/ds-list.css +9 -0
  165. package/dist/3-unit/styles/ds-row.css +19 -0
  166. package/dist/3-unit/styles/ds-table.css +80 -0
  167. package/dist/{3-unit/row-v1.d.ts → 4-page/ds-container.d.ts} +3 -11
  168. package/dist/4-page/ds-container.d.ts.map +1 -0
  169. package/dist/4-page/ds-container.js +11 -0
  170. package/dist/4-page/ds-grid.d.ts +5 -0
  171. package/dist/4-page/ds-grid.d.ts.map +1 -1
  172. package/dist/4-page/ds-grid.js +38 -56
  173. package/dist/4-page/ds-layout.d.ts +3 -3
  174. package/dist/4-page/ds-layout.d.ts.map +1 -1
  175. package/dist/4-page/ds-layout.js +651 -162
  176. package/dist/4-page/styles/ds-container.css +35 -0
  177. package/dist/4-page/styles/ds-grid.css +56 -0
  178. package/dist/4-page/styles/ds-layout.css +251 -0
  179. package/dist/ds-one.bundle.css +700 -0
  180. package/dist/ds-one.bundle.css.map +7 -0
  181. package/dist/ds-one.bundle.js +2728 -1597
  182. package/dist/ds-one.bundle.js.map +1 -7
  183. package/dist/ds-one.bundle.min.css +2 -0
  184. package/dist/ds-one.bundle.min.css.map +7 -0
  185. package/dist/ds-one.bundle.min.js +3850 -546
  186. package/dist/ds-one.bundle.min.js.map +1 -7
  187. package/dist/index.d.ts +9 -1
  188. package/dist/index.d.ts.map +1 -1
  189. package/dist/index.js +9 -1
  190. package/package.json +4 -3
  191. package/dist/3-unit/doublenav-v1.d.ts +0 -51
  192. package/dist/3-unit/doublenav-v1.d.ts.map +0 -1
  193. package/dist/3-unit/doublenav-v1.js +0 -88
  194. package/dist/3-unit/ds-portfolio-doublenav.d.ts +0 -51
  195. package/dist/3-unit/ds-portfolio-doublenav.d.ts.map +0 -1
  196. package/dist/3-unit/ds-portfolio-doublenav.js +0 -88
  197. package/dist/3-unit/ds-portfolio-panel.d.ts +0 -11
  198. package/dist/3-unit/ds-portfolio-panel.d.ts.map +0 -1
  199. package/dist/3-unit/ds-portfolio-panel.js +0 -16
  200. package/dist/3-unit/ds-portfolio-singlenav.d.ts +0 -32
  201. package/dist/3-unit/ds-portfolio-singlenav.d.ts.map +0 -1
  202. package/dist/3-unit/ds-portfolio-singlenav.js +0 -62
  203. package/dist/3-unit/list-v1.d.ts +0 -11
  204. package/dist/3-unit/list-v1.d.ts.map +0 -1
  205. package/dist/3-unit/list-v1.js +0 -15
  206. package/dist/3-unit/panel-v1.d.ts +0 -11
  207. package/dist/3-unit/panel-v1.d.ts.map +0 -1
  208. package/dist/3-unit/panel-v1.js +0 -16
  209. package/dist/3-unit/row-v1.d.ts.map +0 -1
  210. package/dist/3-unit/row-v1.js +0 -32
  211. package/dist/3-unit/singlenav-v1.d.ts +0 -32
  212. package/dist/3-unit/singlenav-v1.d.ts.map +0 -1
  213. package/dist/3-unit/singlenav-v1.js +0 -62
@@ -104,6 +104,10 @@ export function initDeviceDetection(): DeviceInfo {
104
104
  scalingFactor.toFixed(3)
105
105
  );
106
106
 
107
+ // Add .mobile class to html element for CSS targeting
108
+ document.documentElement.classList.add("mobile");
109
+ document.documentElement.classList.remove("desktop");
110
+
107
111
  console.log(
108
112
  `[DS one] Mobile device detected - ${deviceInfo.deviceType} (${deviceInfo.screenWidth}x${deviceInfo.screenHeight}), scaling factor: ${scalingFactor.toFixed(2)}`
109
113
  );
@@ -113,6 +117,10 @@ export function initDeviceDetection(): DeviceInfo {
113
117
  document.documentElement.style.setProperty("--sf", "1");
114
118
  // Also set --sf for backwards compatibility
115
119
  document.documentElement.style.setProperty("--sf", "1");
120
+
121
+ // Add .desktop class and remove .mobile class
122
+ document.documentElement.classList.add("desktop");
123
+ document.documentElement.classList.remove("mobile");
116
124
  }
117
125
  console.log(
118
126
  `[DS one] Desktop device detected (${deviceInfo.screenWidth}x${deviceInfo.screenHeight})`
@@ -156,3 +164,133 @@ if (typeof window !== "undefined") {
156
164
  }, 100);
157
165
  });
158
166
  }
167
+
168
+ /**
169
+ * Disable double-tap to zoom in the browser (app-like behavior)
170
+ * Prevents all zoom gestures including double-tap and pinch-to-zoom
171
+ */
172
+ export function applike(): void {
173
+ if (typeof document === "undefined" || typeof window === "undefined") {
174
+ return;
175
+ }
176
+
177
+ // Set viewport meta tag to prevent zoom - this is the most important step
178
+ let viewport = document.querySelector('meta[name="viewport"]');
179
+ if (!viewport) {
180
+ viewport = document.createElement("meta");
181
+ viewport.setAttribute("name", "viewport");
182
+ document.head.appendChild(viewport);
183
+ }
184
+ viewport.setAttribute(
185
+ "content",
186
+ "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
187
+ );
188
+
189
+ // Apply touch-action: pan-x pan-y globally to prevent zoom but allow panning
190
+ const style = document.createElement("style");
191
+ style.id = "ds-one-applike-style";
192
+ style.textContent = `
193
+ * {
194
+ touch-action: pan-x pan-y !important;
195
+ -ms-touch-action: pan-x pan-y !important;
196
+ }
197
+ html, body {
198
+ touch-action: pan-x pan-y !important;
199
+ -ms-touch-action: pan-x pan-y !important;
200
+ }
201
+ `;
202
+ // Remove existing style if present
203
+ const existingStyle = document.getElementById("ds-one-applike-style");
204
+ if (existingStyle) {
205
+ existingStyle.remove();
206
+ }
207
+ document.head.appendChild(style);
208
+
209
+ // Track touch events to prevent double-tap zoom
210
+ let lastTouchEnd = 0;
211
+ let touchStartTime = 0;
212
+
213
+ const preventZoom = (event: TouchEvent | WheelEvent | Event) => {
214
+ // Prevent pinch zoom (two fingers)
215
+ if (event instanceof TouchEvent) {
216
+ if (event.touches.length > 1) {
217
+ event.preventDefault();
218
+ event.stopPropagation();
219
+ return;
220
+ }
221
+
222
+ const now = Date.now();
223
+
224
+ if (event.type === "touchstart") {
225
+ // If touchstart happens within 300ms of last touchend, it's likely a double-tap
226
+ if (now - lastTouchEnd < 300) {
227
+ event.preventDefault();
228
+ event.stopPropagation();
229
+ return;
230
+ }
231
+ touchStartTime = now;
232
+ } else if (event.type === "touchend") {
233
+ const touchDuration = now - touchStartTime;
234
+ // If this is a quick tap (< 300ms) and happened soon after previous touchend, prevent it
235
+ if (touchDuration < 300 && now - lastTouchEnd < 300) {
236
+ event.preventDefault();
237
+ event.stopPropagation();
238
+ return;
239
+ }
240
+ lastTouchEnd = now;
241
+ } else if (event.type === "touchmove") {
242
+ // Prevent any touchmove that might trigger zoom
243
+ if (event.touches.length > 1) {
244
+ event.preventDefault();
245
+ event.stopPropagation();
246
+ return;
247
+ }
248
+ }
249
+ }
250
+
251
+ // Prevent wheel zoom with ctrl/cmd key (common on trackpads)
252
+ if (event instanceof WheelEvent && (event.ctrlKey || event.metaKey)) {
253
+ event.preventDefault();
254
+ event.stopPropagation();
255
+ return;
256
+ }
257
+ };
258
+
259
+ // Use capture phase to catch events earlier
260
+ const options = { passive: false, capture: true };
261
+
262
+ // Prevent all zoom gestures - use capture phase
263
+ document.addEventListener("touchstart", preventZoom, options);
264
+ document.addEventListener("touchmove", preventZoom, options);
265
+ document.addEventListener("touchend", preventZoom, options);
266
+ document.addEventListener("touchcancel", preventZoom, options);
267
+
268
+ // Prevent wheel zoom
269
+ document.addEventListener("wheel", preventZoom, options);
270
+
271
+ // Prevent gesture events (iOS Safari) - use capture phase
272
+ document.addEventListener(
273
+ "gesturestart",
274
+ (e) => {
275
+ e.preventDefault();
276
+ e.stopPropagation();
277
+ },
278
+ options
279
+ );
280
+ document.addEventListener(
281
+ "gesturechange",
282
+ (e) => {
283
+ e.preventDefault();
284
+ e.stopPropagation();
285
+ },
286
+ options
287
+ );
288
+ document.addEventListener(
289
+ "gestureend",
290
+ (e) => {
291
+ e.preventDefault();
292
+ e.stopPropagation();
293
+ },
294
+ options
295
+ );
296
+ }
@@ -15,15 +15,15 @@ let translationKeys: TranslationMap = {};
15
15
  // Primary language list – prioritise the 10 requested languages when cycling
16
16
  const LANGUAGE_PRIORITY_ORDER = [
17
17
  "da",
18
- "nb",
19
- "sv",
20
- "pt",
18
+ "de",
19
+ "en",
21
20
  "es",
22
- "zh",
23
- "ko",
21
+ "fr",
22
+ "it",
24
23
  "ja",
25
- "en",
26
- "de",
24
+ "pt",
25
+ "sv",
26
+ "zh",
27
27
  ] as const;
28
28
 
29
29
  const LANGUAGE_PRIORITY_LOOKUP = new Map<string, number>(
@@ -34,27 +34,27 @@ const LANGUAGE_PRIORITY_LOOKUP = new Map<string, number>(
34
34
  const FALLBACK_LANGUAGE_NAMES: Record<string, string> = {
35
35
  da: "Danish",
36
36
  "da-dk": "Danish",
37
- nb: "Norwegian",
38
- "nb-no": "Norwegian",
39
- sv: "Swedish",
40
- "sv-se": "Swedish",
41
37
  de: "German",
42
38
  "de-de": "German",
43
39
  en: "English",
44
40
  "en-us": "English",
45
- pt: "Portuguese",
46
- "pt-pt": "Portuguese",
47
- "pt-br": "Portuguese (Brazil)",
48
41
  es: "Spanish",
49
42
  "es-es": "Spanish",
50
- "es-mx": "Spanish (Mexico)",
51
- zh: "Chinese",
52
- "zh-hans": "Chinese (Simplified)",
53
- "zh-hant": "Chinese (Traditional)",
43
+ fr: "French",
44
+ "fr-fr": "French",
45
+ it: "Italian",
46
+ "it-it": "Italian",
54
47
  ja: "Japanese",
55
48
  "ja-jp": "Japanese",
56
- ko: "Korean",
57
- "ko-kr": "Korean",
49
+ pt: "Portuguese",
50
+ "pt-pt": "Portuguese",
51
+ sv: "Swedish",
52
+ "sv-se": "Swedish",
53
+ zh: "Chinese",
54
+ "zh-cn": "Chinese",
55
+ "zh-tw": "Chinese",
56
+ "zh-hans": "Chinese",
57
+ "zh-hant": "Chinese",
58
58
  };
59
59
 
60
60
  const DISPLAY_NAME_CACHE = new Map<string, Intl.DisplayNames>();
@@ -263,9 +263,6 @@ function getTranslationData(): TranslationMap {
263
263
  // Cached translation data - use getter to always get fresh data
264
264
  let translationData = getTranslationData();
265
265
 
266
- type NotionCache = Map<string, string>;
267
-
268
- const notionStore = new Map<LanguageCode, NotionCache>();
269
266
  const defaultLanguage: LanguageCode = "en";
270
267
 
271
268
  function extractPrimarySubtag(code: LanguageCode): string {
@@ -409,33 +406,30 @@ export function getLanguageDisplayName(
409
406
  const BROWSER_LANGUAGE_PREFERENCES: Record<string, LanguageCode> = {
410
407
  da: "da",
411
408
  "da-dk": "da",
412
- no: "nb",
413
- nb: "nb",
414
- "nb-no": "nb",
415
- nn: "nn",
416
- "nn-no": "nn",
417
- sv: "sv",
418
- "sv-se": "sv",
419
- pt: "pt",
420
- "pt-pt": "pt",
421
- "pt-br": "pt",
409
+ de: "de",
410
+ "de-de": "de",
411
+ en: "en",
412
+ "en-us": "en",
413
+ "en-gb": "en",
422
414
  es: "es",
423
415
  "es-es": "es",
424
416
  "es-mx": "es",
417
+ fr: "fr",
418
+ "fr-fr": "fr",
419
+ it: "it",
420
+ "it-it": "it",
421
+ ja: "ja",
422
+ "ja-jp": "ja",
423
+ pt: "pt",
424
+ "pt-pt": "pt",
425
+ "pt-br": "pt",
426
+ sv: "sv",
427
+ "sv-se": "sv",
425
428
  zh: "zh",
426
429
  "zh-cn": "zh",
427
430
  "zh-hans": "zh",
428
431
  "zh-tw": "zh",
429
432
  "zh-hant": "zh",
430
- ko: "ko",
431
- "ko-kr": "ko",
432
- ja: "ja",
433
- "ja-jp": "ja",
434
- en: "en",
435
- "en-us": "en",
436
- "en-gb": "en",
437
- de: "de",
438
- "de-de": "de",
439
433
  };
440
434
 
441
435
  function resolvePreferredLanguage(languageTag: string): LanguageCode | null {
@@ -532,7 +526,6 @@ if (typeof window !== "undefined") {
532
526
 
533
527
  // Dispatch that translations are loaded
534
528
  window.dispatchEvent(new CustomEvent("translations-loaded"));
535
- (window as any).notionDataLoaded = true;
536
529
 
537
530
  // Dispatch language-changed to update all components
538
531
  const currentLang = currentLanguage.value;
@@ -551,7 +544,6 @@ if (typeof window !== "undefined") {
551
544
  setTimeout(() => {
552
545
  // Since we directly imported the data, just dispatch the events
553
546
  window.dispatchEvent(new CustomEvent("translations-loaded"));
554
- (window as any).notionDataLoaded = true;
555
547
 
556
548
  // Also dispatch language-changed with the current language
557
549
  const currentLang = currentLanguage.value;
@@ -614,51 +606,6 @@ export function getText(key: string): string {
614
606
  return translate(key);
615
607
  }
616
608
 
617
- // Get text from translation data (async for compatibility)
618
- export async function getNotionText(
619
- key: string,
620
- language: LanguageCode = currentLanguage.value
621
- ): Promise<string | null> {
622
- if (!key) {
623
- return null;
624
- }
625
-
626
- if (!translationData || !translationData[language]) {
627
- return null;
628
- }
629
-
630
- const text = translationData[language][key];
631
- if (text) {
632
- return text;
633
- }
634
-
635
- // Fallback to English
636
- if (language !== defaultLanguage && translationData[defaultLanguage]?.[key]) {
637
- return translationData[defaultLanguage][key];
638
- }
639
-
640
- return null;
641
- }
642
-
643
- // Store Notion text (for dynamic updates)
644
- export function setNotionText(
645
- key: string,
646
- value: string,
647
- language: LanguageCode = currentLanguage.value
648
- ): void {
649
- if (!key) return;
650
-
651
- const bucket = getLanguageBucket(language);
652
- bucket.set(key, value);
653
- }
654
-
655
- function getLanguageBucket(language: LanguageCode): NotionCache {
656
- if (!notionStore.has(language)) {
657
- notionStore.set(language, new Map());
658
- }
659
- return notionStore.get(language)!;
660
- }
661
-
662
609
  // Get available languages - dynamically detect from loaded data
663
610
  export function getAvailableLanguages(): Promise<LanguageCode[]> {
664
611
  // Always get fresh translation data
@@ -0,0 +1,152 @@
1
+ // scaling.ts
2
+ // Responsive scaling utilities for the design system
3
+
4
+ import { signal } from "@lit-labs/signals";
5
+
6
+ export type ScalingMode = "auto" | "fixed" | "fluid";
7
+
8
+ export interface ScalingConfig {
9
+ mode: ScalingMode;
10
+ baseWidth: number;
11
+ minScale: number;
12
+ maxScale: number;
13
+ }
14
+
15
+ const defaultConfig: ScalingConfig = {
16
+ mode: "auto",
17
+ baseWidth: 280,
18
+ minScale: 0.75,
19
+ maxScale: 2.0,
20
+ };
21
+
22
+ // Reactive scaling factor signal
23
+ export const scalingFactor = signal<number>(1);
24
+
25
+ // Current scaling configuration
26
+ export const scalingConfig = signal<ScalingConfig>(defaultConfig);
27
+
28
+ /**
29
+ * Calculate the scaling factor based on viewport width
30
+ * @param viewportWidth - Current viewport width in pixels
31
+ * @param config - Scaling configuration
32
+ * @returns The calculated scaling factor
33
+ */
34
+ export function calculateScalingFactor(
35
+ viewportWidth: number,
36
+ config: ScalingConfig = scalingConfig.get()
37
+ ): number {
38
+ if (config.mode === "fixed") {
39
+ return 1;
40
+ }
41
+
42
+ const rawScale = viewportWidth / config.baseWidth;
43
+ const clampedScale = Math.max(
44
+ config.minScale,
45
+ Math.min(config.maxScale, rawScale)
46
+ );
47
+
48
+ return Number(clampedScale.toFixed(3));
49
+ }
50
+
51
+ /**
52
+ * Set the scaling configuration
53
+ * @param config - Partial scaling configuration to apply
54
+ */
55
+ export function setScalingConfig(config: Partial<ScalingConfig>): void {
56
+ const currentConfig = scalingConfig.get();
57
+ const newConfig = { ...currentConfig, ...config };
58
+ scalingConfig.set(newConfig);
59
+
60
+ // Recalculate scaling factor if in browser
61
+ if (typeof window !== "undefined") {
62
+ updateScalingFactor();
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Update the scaling factor based on current viewport
68
+ */
69
+ export function updateScalingFactor(): void {
70
+ if (typeof window === "undefined" || typeof document === "undefined") {
71
+ return;
72
+ }
73
+
74
+ const viewportWidth = document.documentElement.clientWidth;
75
+ const config = scalingConfig.get();
76
+ const newFactor = calculateScalingFactor(viewportWidth, config);
77
+
78
+ scalingFactor.set(newFactor);
79
+
80
+ // Update CSS custom property
81
+ document.documentElement.style.setProperty("--sf", newFactor.toString());
82
+
83
+ // Dispatch event for components that need to react
84
+ window.dispatchEvent(
85
+ new CustomEvent("scaling-changed", {
86
+ detail: { scalingFactor: newFactor, config },
87
+ })
88
+ );
89
+ }
90
+
91
+ /**
92
+ * Get the current scaling factor
93
+ * @returns The current scaling factor
94
+ */
95
+ export function getScalingFactor(): number {
96
+ return scalingFactor.get();
97
+ }
98
+
99
+ /**
100
+ * Convert a design pixel value to scaled pixels
101
+ * @param designPx - The design pixel value (based on 280px width)
102
+ * @returns The scaled pixel value
103
+ */
104
+ export function scale(designPx: number): number {
105
+ return designPx * scalingFactor.get();
106
+ }
107
+
108
+ /**
109
+ * Convert a scaled pixel value back to design pixels
110
+ * @param scaledPx - The scaled pixel value
111
+ * @returns The design pixel value
112
+ */
113
+ export function unscale(scaledPx: number): number {
114
+ const factor = scalingFactor.get();
115
+ return factor === 0 ? scaledPx : scaledPx / factor;
116
+ }
117
+
118
+ /**
119
+ * Initialize scaling system
120
+ * This is typically called automatically when the module loads
121
+ */
122
+ export function initScaling(): void {
123
+ if (typeof window === "undefined") {
124
+ return;
125
+ }
126
+
127
+ // Initial calculation
128
+ updateScalingFactor();
129
+
130
+ // Update on resize (debounced)
131
+ let resizeTimeout: ReturnType<typeof setTimeout>;
132
+ window.addEventListener("resize", () => {
133
+ clearTimeout(resizeTimeout);
134
+ resizeTimeout = setTimeout(() => {
135
+ updateScalingFactor();
136
+ }, 100);
137
+ });
138
+
139
+ // Update on orientation change
140
+ window.addEventListener("orientationchange", () => {
141
+ setTimeout(updateScalingFactor, 100);
142
+ });
143
+ }
144
+
145
+ // Auto-initialize when module loads in browser
146
+ if (typeof window !== "undefined") {
147
+ if (document.readyState === "loading") {
148
+ document.addEventListener("DOMContentLoaded", initScaling);
149
+ } else {
150
+ initScaling();
151
+ }
152
+ }