@sensorario/sg-components 0.0.98 → 0.0.100

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.
@@ -0,0 +1,14 @@
1
+ import './AppLauncher.css';
2
+ export declare const DEFAULT_APPS_URL = "https://api.simonegentili.com/heimdall/launcher";
3
+ export type LauncherApp = {
4
+ name: string;
5
+ url: string;
6
+ };
7
+ interface AppLauncherProps {
8
+ /** Endpoint returning `{ apps: LauncherApp[] }` - the enabled apps, managed from Heimdall. */
9
+ appsUrl?: string;
10
+ /** Accessible name of the grid button - this library has no i18n of its own. */
11
+ label?: string;
12
+ }
13
+ export declare const AppLauncher: ({ appsUrl, label }: AppLauncherProps) => import("react/jsx-runtime").JSX.Element;
14
+ export default AppLauncher;
@@ -0,0 +1,7 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import AppLauncher from './AppLauncher';
3
+ declare const meta: Meta<typeof AppLauncher>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof AppLauncher>;
6
+ export declare const Default: Story;
7
+ export declare const Live: Story;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import './Icon.css';
3
- export type IconName = 'menu' | 'layout' | 'edit' | 'help-circle' | 'check' | 'x' | 'file-plus' | 'link' | 'share-2' | 'download' | 'book' | 'printer' | 'eye' | 'columns' | 'sidebar-left' | 'sidebar-right' | 'play' | 'pause' | 'volume-2' | 'tech-node' | 'tech-go' | 'tech-php';
3
+ export type IconName = 'menu' | 'layout' | 'edit' | 'help-circle' | 'check' | 'x' | 'file-plus' | 'link' | 'share-2' | 'download' | 'book' | 'printer' | 'eye' | 'columns' | 'sidebar-left' | 'sidebar-right' | 'play' | 'pause' | 'volume-2' | 'tech-node' | 'tech-go' | 'tech-php' | 'grid';
4
4
  export interface IconProps extends React.SVGAttributes<SVGSVGElement> {
5
5
  name: IconName;
6
6
  size?: number;
@@ -15,6 +15,8 @@ interface QuadratoHeaderProps {
15
15
  onLogout?: () => void;
16
16
  /** Notified on mount and after every login/logout with the current auth state. */
17
17
  onUserAuthenticated?: (isAuthenticated: boolean, username: string | null) => void;
18
+ /** Endpoint of the app launcher menu. Default: the Heimdall-managed list on api.simonegentili.com. */
19
+ appsUrl?: string;
18
20
  }
19
21
  export interface QuadratoHeaderHandle {
20
22
  /** Forces the login modal open, e.g. when a consumer action requires auth first. */
package/dist/index.d.ts CHANGED
@@ -15,3 +15,4 @@ export * from './components/PasswordInput/PasswordInput';
15
15
  export * from './components/ColorPicker/ColorPicker';
16
16
  export * from './components/FontPicker/FontPicker';
17
17
  export * from './components/Toggle/Toggle';
18
+ export * from './components/AppLauncher/AppLauncher';
package/dist/index.es.js CHANGED
@@ -211,7 +211,24 @@ var u = {
211
211
  ] }),
212
212
  "tech-node": /* @__PURE__ */ c("polygon", { points: "12,3 19.8,7.5 19.8,16.5 12,21 4.2,16.5 4.2,7.5" }),
213
213
  "tech-go": /* @__PURE__ */ c("polygon", { points: "12,3 21,12 12,21 3,12" }),
214
- "tech-php": /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c("path", { d: "M9 4c-1.5 0-2.5 1-2.5 2.5v3c0 1-.5 1.5-1.5 2.5 1 1 1.5 1.5 1.5 2.5v3c0 1.5 1 2.5 2.5 2.5" }), /* @__PURE__ */ c("path", { d: "M15 4c1.5 0 2.5 1 2.5 2.5v3c0 1 .5 1.5 1.5 2.5-1 1-1.5 1.5-1.5 2.5v3c0 1.5-1 2.5-2.5 2.5" })] })
214
+ "tech-php": /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c("path", { d: "M9 4c-1.5 0-2.5 1-2.5 2.5v3c0 1-.5 1.5-1.5 2.5 1 1 1.5 1.5 1.5 2.5v3c0 1.5 1 2.5 2.5 2.5" }), /* @__PURE__ */ c("path", { d: "M15 4c1.5 0 2.5 1 2.5 2.5v3c0 1 .5 1.5 1.5 2.5-1 1-1.5 1.5-1.5 2.5v3c0 1.5-1 2.5-2.5 2.5" })] }),
215
+ grid: /* @__PURE__ */ c("g", {
216
+ fill: "currentColor",
217
+ stroke: "none",
218
+ children: [
219
+ 5,
220
+ 12,
221
+ 19
222
+ ].flatMap((e) => [
223
+ 5,
224
+ 12,
225
+ 19
226
+ ].map((t) => /* @__PURE__ */ c("circle", {
227
+ cx: t,
228
+ cy: e,
229
+ r: "2"
230
+ }, `${t}-${e}`)))
231
+ })
215
232
  }, d = ({ name: e, size: t = 18, ...n }) => /* @__PURE__ */ c("svg", {
216
233
  className: "sg-icon",
217
234
  width: t,
@@ -330,7 +347,66 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
330
347
  onNavigate: e,
331
348
  title: "Simone Gentili - senior web developer, tech author and chess enthusiast",
332
349
  homePageKey: "home"
333
- }), C = ({ isLoggedIn: e, handleLogin: t, handleLogout: n }) => /* @__PURE__ */ c(s, { children: e ? /* @__PURE__ */ c("button", {
350
+ }), C = "https://api.simonegentili.com/heimdall/launcher", w = ({ appsUrl: e = C, label: t = "App" }) => {
351
+ let [r, i] = o(!1), [s, u] = o(null), [f, p] = o(!1), m = a(null);
352
+ return n(() => {
353
+ !r || s !== null || fetch(e).then((e) => e.ok ? e.json() : Promise.reject(e.status)).then((e) => u(e.apps)).catch(() => p(!0));
354
+ }, [
355
+ r,
356
+ s,
357
+ e
358
+ ]), n(() => {
359
+ if (!r) return;
360
+ let e = (e) => {
361
+ m.current?.contains(e.target) || i(!1);
362
+ }, t = (e) => {
363
+ e.key === "Escape" && i(!1);
364
+ };
365
+ return document.addEventListener("pointerdown", e), document.addEventListener("keydown", t), () => {
366
+ document.removeEventListener("pointerdown", e), document.removeEventListener("keydown", t);
367
+ };
368
+ }, [r]), /* @__PURE__ */ l("div", {
369
+ className: "sg-app-launcher",
370
+ ref: m,
371
+ children: [/* @__PURE__ */ c("button", {
372
+ type: "button",
373
+ className: "sg-app-launcher-toggle",
374
+ "aria-label": t,
375
+ title: t,
376
+ "aria-expanded": r,
377
+ onClick: () => {
378
+ r || p(!1), i(!r);
379
+ },
380
+ children: /* @__PURE__ */ c(d, {
381
+ name: "grid",
382
+ size: 22
383
+ })
384
+ }), r && /* @__PURE__ */ c("div", {
385
+ className: "sg-app-launcher-panel",
386
+ children: f ? /* @__PURE__ */ c("p", {
387
+ className: "sg-app-launcher-message",
388
+ children: "Impossibile caricare le app."
389
+ }) : s === null ? /* @__PURE__ */ c("p", {
390
+ className: "sg-app-launcher-message",
391
+ children: "Caricamento…"
392
+ }) : /* @__PURE__ */ c("ul", {
393
+ className: "sg-app-launcher-grid",
394
+ children: s.map((e) => /* @__PURE__ */ c("li", { children: /* @__PURE__ */ l("a", {
395
+ href: e.url,
396
+ className: new URL(e.url).origin === window.location.origin ? "sg-app-launcher-app current" : "sg-app-launcher-app",
397
+ children: [/* @__PURE__ */ c("span", {
398
+ className: "sg-app-launcher-tile",
399
+ "aria-hidden": "true",
400
+ children: e.name.charAt(0).toUpperCase()
401
+ }), /* @__PURE__ */ c("span", {
402
+ className: "sg-app-launcher-name",
403
+ children: e.name
404
+ })]
405
+ }) }, e.url))
406
+ })
407
+ })]
408
+ });
409
+ }, T = ({ isLoggedIn: e, handleLogin: t, handleLogout: n }) => /* @__PURE__ */ c(s, { children: e ? /* @__PURE__ */ c("button", {
334
410
  onClick: n,
335
411
  style: {
336
412
  fontSize: "0.9rem",
@@ -344,14 +420,14 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
344
420
  padding: "0.4rem 1rem"
345
421
  },
346
422
  children: "Login"
347
- }) }), w = 220, T = ({ open: t, onClose: r, title: i, icon: a, children: s, buttons: u, footer: d, closeLabel: p = "Close", className: m }) => {
423
+ }) }), E = 220, D = ({ open: t, onClose: r, title: i, icon: a, children: s, buttons: u, footer: d, closeLabel: p = "Close", className: m }) => {
348
424
  let [h, g] = o(!1), [_, v] = o({
349
425
  x: 0,
350
426
  y: 0
351
427
  }), y = e.useRef(null), [b, x] = o(!1), S = (e) => {
352
428
  h || (g(!0), setTimeout(() => {
353
429
  g(!1), e();
354
- }, w));
430
+ }, E));
355
431
  };
356
432
  n(() => {
357
433
  if (!t) return;
@@ -360,12 +436,12 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
360
436
  };
361
437
  return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
362
438
  }, [t, r]);
363
- let [C, T] = o(t);
364
- if (t !== C && (T(t), t && v({
439
+ let [C, w] = o(t);
440
+ if (t !== C && (w(t), t && v({
365
441
  x: 0,
366
442
  y: 0
367
443
  })), !t) return null;
368
- function E(e) {
444
+ function T(e) {
369
445
  e.target.closest(".modal-close") || (y.current = {
370
446
  pointerX: e.clientX,
371
447
  pointerY: e.clientY,
@@ -397,7 +473,7 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
397
473
  children: [
398
474
  /* @__PURE__ */ l("div", {
399
475
  className: `modal-header${b ? " modal-header-dragging" : ""}`,
400
- onPointerDown: E,
476
+ onPointerDown: T,
401
477
  onPointerMove: D,
402
478
  onPointerUp: O,
403
479
  onPointerCancel: O,
@@ -439,7 +515,7 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
439
515
  ]
440
516
  })
441
517
  });
442
- }, E = ({ label: e, invalid: t, className: n, id: i, ...a }) => {
518
+ }, O = ({ label: e, invalid: t, className: n, id: i, ...a }) => {
443
519
  let o = r(), s = i ?? o;
444
520
  return /* @__PURE__ */ l("div", {
445
521
  className: "input-wrapper",
@@ -457,7 +533,7 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
457
533
  ...a
458
534
  })]
459
535
  });
460
- }, D = ({ label: e, className: t, id: n, ...i }) => {
536
+ }, k = ({ label: e, className: t, id: n, ...i }) => {
461
537
  let a = r(), o = n ?? a;
462
538
  return /* @__PURE__ */ l("div", {
463
539
  className: "input-wrapper",
@@ -472,9 +548,9 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
472
548
  ...i
473
549
  })]
474
550
  });
475
- }, O = ({ open: e, onClose: t, onLogin: n }) => {
551
+ }, A = ({ open: e, onClose: t, onLogin: n }) => {
476
552
  let [r, i] = o(""), [a, s] = o("");
477
- return /* @__PURE__ */ c(T, {
553
+ return /* @__PURE__ */ c(D, {
478
554
  open: e,
479
555
  onClose: t,
480
556
  title: "Login",
@@ -483,13 +559,13 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
483
559
  e.preventDefault(), n(r, a);
484
560
  },
485
561
  children: [
486
- /* @__PURE__ */ c(E, {
562
+ /* @__PURE__ */ c(O, {
487
563
  label: "Username",
488
564
  value: r,
489
565
  onChange: (e) => i(e.target.value),
490
566
  autoFocus: !0
491
567
  }),
492
- /* @__PURE__ */ c(D, {
568
+ /* @__PURE__ */ c(k, {
493
569
  label: "Password",
494
570
  value: a,
495
571
  onChange: (e) => s(e.target.value)
@@ -502,57 +578,57 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
502
578
  ]
503
579
  })
504
580
  });
505
- }, k = "simonegentili.com-access-token", A = (e) => document.cookie.split("; ").some((t) => t.startsWith(`${e}=`) && t.slice(e.length + 1).length > 0), j = (e) => {
581
+ }, j = "simonegentili.com-access-token", M = (e) => document.cookie.split("; ").some((t) => t.startsWith(`${e}=`) && t.slice(e.length + 1).length > 0), N = (e) => {
506
582
  let t = document.cookie.split("; ").find((t) => t.startsWith(`${e}=`));
507
583
  return t ? t.slice(e.length + 1) : null;
508
- }, M = (e, t) => {
584
+ }, P = (e, t) => {
509
585
  try {
510
586
  return JSON.parse(atob(e.split(".")[1].replace(/-/g, "+").replace(/_/g, "/")))[t] ?? null;
511
587
  } catch {
512
588
  return null;
513
589
  }
514
- }, N = t(({ title: e = "Quadrato", homePageKey: t = "home", onNavigate: r, cookieName: a = k, username: u = null, usernameJwtField: d = "sub", onLogin: f, onLogout: p, onUserAuthenticated: m }, h) => {
515
- let [g, _] = o(() => A(a)), [v, y] = o(!1);
516
- i(h, () => ({ openLoginModal: () => y(!0) }));
517
- let b = u ?? (g ? M(j(a) ?? "", d) : null);
590
+ }, F = t(({ title: e = "Quadrato", homePageKey: t = "home", onNavigate: r, cookieName: a = j, username: u = null, usernameJwtField: d = "sub", onLogin: f, onLogout: p, onUserAuthenticated: m, appsUrl: h }, g) => {
591
+ let [_, v] = o(() => M(a)), [y, b] = o(!1);
592
+ i(g, () => ({ openLoginModal: () => b(!0) }));
593
+ let S = u ?? (_ ? P(N(a) ?? "", d) : null);
518
594
  return n(() => {
519
- m?.(g, g ? b : null);
520
- }, []), /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c(x, {
595
+ m?.(_, _ ? S : null);
596
+ }, []), /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ l(x, {
521
597
  onNavigate: r,
522
598
  title: e,
523
599
  homePageKey: t,
524
600
  className: "quadrato-header",
525
- children: /* @__PURE__ */ l("div", {
601
+ children: [/* @__PURE__ */ c(w, { appsUrl: h }), /* @__PURE__ */ l("div", {
526
602
  className: "quadrato-header-auth",
527
- children: [g && b && /* @__PURE__ */ c("span", {
603
+ children: [_ && S && /* @__PURE__ */ c("span", {
528
604
  className: "quadrato-header-username",
529
- children: b
530
- }), /* @__PURE__ */ c(C, {
531
- isLoggedIn: g,
532
- handleLogin: () => y(!0),
605
+ children: S
606
+ }), /* @__PURE__ */ c(T, {
607
+ isLoggedIn: _,
608
+ handleLogin: () => b(!0),
533
609
  handleLogout: () => {
534
610
  p?.();
535
- let e = A(a);
536
- _(e), m?.(e, null);
611
+ let e = M(a);
612
+ v(e), m?.(e, null);
537
613
  }
538
614
  })]
539
- })
540
- }), /* @__PURE__ */ c(O, {
541
- open: v,
542
- onClose: () => y(!1),
615
+ })]
616
+ }), /* @__PURE__ */ c(A, {
617
+ open: y,
618
+ onClose: () => b(!1),
543
619
  onLogin: async (e, t) => {
544
620
  await f(e, t);
545
- let n = A(a);
546
- _(n), y(!1), m?.(n, n ? u ?? e : null);
621
+ let n = M(a);
622
+ v(n), b(!1), m?.(n, n ? u ?? e : null);
547
623
  }
548
624
  })] });
549
625
  });
550
- N.displayName = "QuadratoHeader";
626
+ F.displayName = "QuadratoHeader";
551
627
  //#endregion
552
628
  //#region src/components/SetPasswordModal/SetPasswordModal.tsx
553
- var P = ({ open: e, onClose: t, onSubmit: n }) => {
629
+ var I = ({ open: e, onClose: t, onSubmit: n }) => {
554
630
  let [r, i] = o(""), [a, s] = o(""), [u, d] = o("");
555
- return /* @__PURE__ */ c(T, {
631
+ return /* @__PURE__ */ c(D, {
556
632
  open: e,
557
633
  onClose: t,
558
634
  title: "Imposta una nuova password",
@@ -570,13 +646,13 @@ var P = ({ open: e, onClose: t, onSubmit: n }) => {
570
646
  d(""), n(r);
571
647
  },
572
648
  children: [
573
- /* @__PURE__ */ c(D, {
649
+ /* @__PURE__ */ c(k, {
574
650
  label: "Nuova password",
575
651
  value: r,
576
652
  onChange: (e) => i(e.target.value),
577
653
  autoFocus: !0
578
654
  }),
579
- /* @__PURE__ */ c(D, {
655
+ /* @__PURE__ */ c(k, {
580
656
  label: "Conferma password",
581
657
  value: a,
582
658
  onChange: (e) => s(e.target.value)
@@ -593,7 +669,7 @@ var P = ({ open: e, onClose: t, onSubmit: n }) => {
593
669
  ]
594
670
  })
595
671
  });
596
- }, F = ({ value: e, onChange: t, swatches: r }) => {
672
+ }, L = ({ value: e, onChange: t, swatches: r }) => {
597
673
  let [i, s] = o(!1), u = a(null);
598
674
  return n(() => {
599
675
  if (!i) return;
@@ -642,7 +718,7 @@ var P = ({ open: e, onClose: t, onSubmit: n }) => {
642
718
  })]
643
719
  })]
644
720
  });
645
- }, I = (e) => e.split(",")[0].replace(/'/g, ""), L = ({ value: e, onChange: t, options: r }) => {
721
+ }, R = (e) => e.split(",")[0].replace(/'/g, ""), z = ({ value: e, onChange: t, options: r }) => {
646
722
  let [i, s] = o(!1), u = a(null);
647
723
  return n(() => {
648
724
  if (!i) return;
@@ -664,7 +740,7 @@ var P = ({ open: e, onClose: t, onSubmit: n }) => {
664
740
  style: { fontFamily: e },
665
741
  children: [/* @__PURE__ */ c("span", {
666
742
  className: "sg-font-picker-toggle-label",
667
- children: I(e)
743
+ children: R(e)
668
744
  }), /* @__PURE__ */ c("span", {
669
745
  className: "sg-font-picker-toggle-caret",
670
746
  children: i ? "▲" : "▼"
@@ -678,11 +754,11 @@ var P = ({ open: e, onClose: t, onSubmit: n }) => {
678
754
  t(n), s(!1);
679
755
  },
680
756
  style: { fontFamily: n },
681
- children: I(n)
757
+ children: R(n)
682
758
  }) }, n))
683
759
  })]
684
760
  });
685
- }, R = ({ checked: e, onChange: t, label: n }) => /* @__PURE__ */ l("label", {
761
+ }, B = ({ checked: e, onChange: t, label: n }) => /* @__PURE__ */ l("label", {
686
762
  className: "sg-toggle",
687
763
  children: [
688
764
  /* @__PURE__ */ c("input", {
@@ -702,4 +778,4 @@ var P = ({ open: e, onClose: t, onSubmit: n }) => {
702
778
  ]
703
779
  });
704
780
  //#endregion
705
- export { C as Authenticator, f as Button, F as ColorPicker, v as CookieConsent, L as FontPicker, p as Footer, x as Header, d as Icon, E as Input, T as Modal, D as PasswordInput, N as QuadratoHeader, b as SGFooter, S as SGHeader, P as SetPasswordModal, R as Toggle };
781
+ export { w as AppLauncher, T as Authenticator, f as Button, L as ColorPicker, v as CookieConsent, C as DEFAULT_APPS_URL, z as FontPicker, p as Footer, x as Header, d as Icon, O as Input, D as Modal, k as PasswordInput, F as QuadratoHeader, b as SGFooter, S as SGHeader, I as SetPasswordModal, B as Toggle };
@@ -1,2 +1,2 @@
1
- .custom-button{border-radius:var(--button-radius);background:var(--button-bg);color:var(--button-color);cursor:pointer;font-size:var(--primary-font);font-weight:600;font-family:var(--font-family);box-shadow:var(--button-shadow);transition:background .15s var(--button-ease-standard), transform var(--button-ease-bounce) .2s;border:none;padding:8px 20px}.custom-button:hover:not(:disabled){background:var(--button-bg-hover);transform:translateY(-1px)}.custom-button:active:not(:disabled){transform:scale(.97)}.custom-button:disabled{opacity:.6;cursor:default}.custom-button-with-icon{align-items:center;gap:8px;display:inline-flex}.custom-button-label-visually-hidden{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.sg-icon{vertical-align:middle;flex-shrink:0;display:inline-block}.footer{background-color:var(--primary-bg);border-top:1px solid var(--primary-border);font-family:var(--font-family);color:#555;justify-content:space-between;align-items:center;width:100%;padding:16px 32px;font-size:14px;display:flex;position:fixed;bottom:0;left:0}.footer a{color:#1ea7fd;text-decoration:none}.footer a:hover{text-decoration:underline}.cookie-consent{background-color:var(--primary-bg);border-top:1px solid var(--primary-border);font-family:var(--font-family);color:#555;z-index:1000;box-sizing:border-box;flex-wrap:wrap;justify-content:center;align-items:center;gap:16px;width:100%;padding:16px 32px;font-size:14px;display:flex;position:fixed;bottom:0;left:0}.cookie-consent-text{flex:320px;margin:0}.cookie-consent a{color:#1ea7fd;text-decoration:none}.cookie-consent a:hover{text-decoration:underline}.cookie-consent-accept{flex:none}.logo-text{font-size:var(--font-size-h1);font-family:var(--font-family);margin:0;font-weight:400}.header{z-index:100;width:100%;font-size:var(--font-size);background-color:#fff;border-bottom:1px solid #e1e5e9;position:sticky;top:0;box-shadow:0 2px 4px #0000001a}.header-container{justify-content:flex-start;align-items:center;max-width:1200px;margin:0 auto;padding:16px;display:flex}.header-actions{align-items:center;gap:12px;margin-left:auto;display:flex}.logo{cursor:pointer;color:#333;font-size:24px;font-weight:700;transition:color .2s}.logo:hover{color:#007acc}.logo-full{display:inline}.logo-short{display:none}@media (width<=768px){.header-container{padding:12px 16px}.logo{font-size:var(--font-size)}.logo-full{display:none}.logo-short{display:inline}}@media (width<=480px){.header-container{padding:8px 12px}.logo{font-size:var(--font-size)}}.modal-overlay{background:var(--modal-overlay);z-index:1000;justify-content:center;align-items:center;width:100vw;height:100vh;animation:.25s ease-out sg-modal-overlay-fade-in;display:flex;position:fixed;top:0;left:0}.modal-overlay.modal-overlay-closing{animation:.22s ease-in forwards sg-modal-overlay-fade-out}.modal-content{--drag-x:0px;--drag-y:0px;background:var(--modal-bg);border-radius:var(--primary-radius);font-size:var(--primary-font);min-width:320px;max-width:calc(100vw - 40px);max-height:90vh;transform:translate(var(--drag-x), var(--drag-y));flex-direction:column;animation:.3s ease-out sg-modal-slide-in;display:flex;overflow:hidden;box-shadow:0 2px 16px #00000026}.modal-content.modal-content-closing{animation:.22s ease-in forwards sg-modal-slide-out}@keyframes sg-modal-overlay-fade-in{0%{opacity:0}to{opacity:1}}@keyframes sg-modal-overlay-fade-out{0%{opacity:1}to{opacity:0}}@keyframes sg-modal-slide-in{0%{transform:translate(var(--drag-x), calc(var(--drag-y) - 24px)) scale(.97);opacity:0}to{transform:translate(var(--drag-x), var(--drag-y)) scale(1);opacity:1}}@keyframes sg-modal-slide-out{0%{transform:translate(var(--drag-x), var(--drag-y)) scale(1);opacity:1}to{transform:translate(var(--drag-x), calc(var(--drag-y) - 24px)) scale(.97);opacity:0}}.modal-header{background:var(--primary-bg);border-top-left-radius:var(--primary-radius);border-top-right-radius:var(--primary-radius);cursor:grab;touch-action:none;flex:none;align-items:center;gap:8px;padding:16px;display:flex}.modal-header-dragging{cursor:grabbing;-webkit-user-select:none;user-select:none}.modal-icon{color:var(--modal-title-color);display:inline-flex}.modal-title{color:var(--modal-title-color);font-family:var(--font-family);font-size:var(--primary-font);flex:1;margin:0}.modal-close{cursor:pointer;color:var(--modal-title-color);background:0 0;border:none;padding:4px 8px;font-size:20px;line-height:1}.modal-close:disabled{cursor:default;opacity:.6}.modal-children{font-family:var(--font-family);padding:16px;overflow-y:auto}.modal-footer{border-top:1px solid var(--primary-border);flex-wrap:wrap;flex:none;justify-content:flex-end;gap:8px;padding:12px 16px;display:flex}.input-label{font-weight:500;font-family:var(--font-family);font-size:var(--primary-font);margin-bottom:4px;display:block}.input-field--invalid{background-color:#ffe5e5;border-color:#c00}.input-wrapper{margin-bottom:16px}.input-label{font-weight:500;font-size:var(--primary-font);margin-bottom:4px;display:block}.input-field{box-sizing:border-box;border-radius:var(--radius);width:100%;font-size:var(--primary-font);border-style:solid;border-width:1px;padding:8px}.login-modal-form{font-family:var(--font-family);font-size:var(--primary-font);flex-direction:column;gap:16px;display:flex}.header.quadrato-header{z-index:999}.quadrato-header-auth{align-items:center;gap:12px;display:flex}.quadrato-header-username{font-size:var(--font-size);color:#333}form{font-family:var(--font-family)}.set-password-modal-form{font-family:var(--font-family);font-size:var(--primary-font);flex-direction:column;gap:16px;display:flex}.set-password-modal-error{color:#d32f2f;font-size:var(--primary-font);margin:0}.sg-color-picker{font-family:var(--font-family);position:relative}.sg-color-picker-toggle{border-radius:var(--input-radius);border:1px solid var(--input-border);background:var(--input-bg);width:100%;color:inherit;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;font-family:inherit;font-size:13px;display:flex}.sg-color-picker-toggle-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.sg-color-picker-swatch{border:1px solid #00000026;border-radius:4px;flex:none;width:18px;height:18px}.sg-color-picker-popover{z-index:30;background:var(--input-bg);border:1px solid var(--input-border);border-radius:var(--input-radius);box-shadow:var(--shadow-1);width:170px;padding:10px;position:absolute;top:calc(100% + 4px);left:0}.sg-color-picker-grid{grid-template-columns:repeat(6,1fr);gap:6px;display:grid}.sg-color-picker-swatch-button{cursor:pointer;border:1px solid #00000026;border-radius:4px;width:20px;height:20px;padding:0}.sg-color-picker-swatch-button.active{border:2px solid var(--accent)}.sg-color-picker-custom{border-top:1px solid var(--input-border);color:var(--ink-muted);cursor:pointer;justify-content:space-between;align-items:center;gap:8px;margin-top:8px;padding-top:8px;font-size:11px;display:flex}.sg-color-picker-custom input[type=color]{cursor:pointer;border:none;width:26px;height:20px;padding:0}.sg-font-picker{font-family:var(--font-family);position:relative}.sg-font-picker-toggle{border-radius:var(--input-radius);border:1px solid var(--input-border);background:var(--input-bg);width:100%;color:inherit;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;font-size:13px;display:flex}.sg-font-picker-toggle-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.sg-font-picker-toggle-caret{opacity:.5;flex:none;font-size:10px}.sg-font-picker-list{background:var(--input-bg);border:1px solid var(--input-border);border-radius:var(--input-radius);max-height:260px;box-shadow:var(--shadow-1);z-index:30;margin:0;padding:4px 0;list-style:none;position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto}.sg-font-picker-option{text-align:left;width:100%;color:inherit;cursor:pointer;background:0 0;border:none;padding:8px 10px;font-size:15px;display:block}.sg-font-picker-option.active{background:var(--accent-soft)}:root{--unit:3px;--primary-bg:#f5f5f5;--primary-border:#ccc;--radius:calc(var(--unit) * 2);--primary-radius:var(--radius);--primary-font:var(--font-size);--primary-hover-bg:#e0e0e0;--modal-bg:#fff;--modal-overlay:#0000004d;--modal-title-color:#222;--input-bg:#fff;--input-border:#ccc;--input-radius:var(--radius);--input-font:1rem;--font-size:14px;--font-family:Arial, sans-serif;--font-size-h1:calc(var(--font-size) * 1.5);--button-bg:#6f9cf7;--button-bg-hover:#5480e6;--button-color:#fff;--button-radius:999px;--button-shadow:0 1px 2px #5480e61f, 0 1px 3px #5480e61a;--button-ease-standard:cubic-bezier(.4, 0, .2, 1);--button-ease-bounce:cubic-bezier(.34, 1.56, .64, 1);--accent:#3d5fc4;--accent-strong:#2e4aa0;--accent-soft:#e2e7f8;--ink-muted:#647089;--shadow-1:0 1px 2px #0f172a14, 0 1px 3px #0f172a0f;--shadow-2:0 4px 12px #0f172a1f}.theme-dark{--primary-bg:#222;--primary-border:#444;--primary-font:1rem;--font-family:"Inter", Arial, sans-serif;--primary-hover-bg:#333;--modal-bg:#222;--modal-title-color:#fff;--input-bg:#333;--input-border:#555;--input-font:1rem;--button-bg:#6f9cf7;--button-bg-hover:#86aefc;--button-color:#fff;--accent:#6f9cf7;--accent-strong:#86aefc;--accent-soft:#6f9cf72e;--ink-muted:#9aa3b5;--shadow-1:0 1px 2px #0000004d, 0 1px 3px #0000003d;--shadow-2:0 4px 12px #0006}.sg-toggle{cursor:pointer;-webkit-user-select:none;user-select:none;font-family:var(--font-family);align-items:center;gap:6px;display:flex}.sg-toggle-input{opacity:0;width:1px;height:1px;position:absolute}.sg-toggle-track{background:var(--input-border);border-radius:999px;flex:none;width:34px;height:20px;transition:background .15s cubic-bezier(.4,0,.2,1);position:relative}.sg-toggle-input:checked+.sg-toggle-track{background:var(--accent)}.sg-toggle-thumb{background:var(--input-bg);width:16px;height:16px;box-shadow:var(--shadow-1);border-radius:50%;transition:left .15s cubic-bezier(.4,0,.2,1);position:absolute;top:2px;left:2px}.sg-toggle-input:checked+.sg-toggle-track .sg-toggle-thumb{left:16px}.sg-toggle-input:focus-visible+.sg-toggle-track{outline:2px solid var(--accent-strong);outline-offset:2px}.sg-toggle-label{color:var(--ink-muted);white-space:nowrap;font-size:13px}
1
+ .custom-button{border-radius:var(--button-radius);background:var(--button-bg);color:var(--button-color);cursor:pointer;font-size:var(--primary-font);font-weight:600;font-family:var(--font-family);box-shadow:var(--button-shadow);transition:background .15s var(--button-ease-standard), transform var(--button-ease-bounce) .2s;border:none;padding:8px 20px}.custom-button:hover:not(:disabled){background:var(--button-bg-hover);transform:translateY(-1px)}.custom-button:active:not(:disabled){transform:scale(.97)}.custom-button:disabled{opacity:.6;cursor:default}.custom-button-with-icon{align-items:center;gap:8px;display:inline-flex}.custom-button-label-visually-hidden{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.sg-icon{vertical-align:middle;flex-shrink:0;display:inline-block}.footer{background-color:var(--primary-bg);border-top:1px solid var(--primary-border);font-family:var(--font-family);color:#555;justify-content:space-between;align-items:center;width:100%;padding:16px 32px;font-size:14px;display:flex;position:fixed;bottom:0;left:0}.footer a{color:#1ea7fd;text-decoration:none}.footer a:hover{text-decoration:underline}.cookie-consent{background-color:var(--primary-bg);border-top:1px solid var(--primary-border);font-family:var(--font-family);color:#555;z-index:1000;box-sizing:border-box;flex-wrap:wrap;justify-content:center;align-items:center;gap:16px;width:100%;padding:16px 32px;font-size:14px;display:flex;position:fixed;bottom:0;left:0}.cookie-consent-text{flex:320px;margin:0}.cookie-consent a{color:#1ea7fd;text-decoration:none}.cookie-consent a:hover{text-decoration:underline}.cookie-consent-accept{flex:none}.logo-text{font-size:var(--font-size-h1);font-family:var(--font-family);margin:0;font-weight:400}.header{z-index:100;width:100%;font-size:var(--font-size);background-color:#fff;border-bottom:1px solid #e1e5e9;position:sticky;top:0;box-shadow:0 2px 4px #0000001a}.header-container{justify-content:flex-start;align-items:center;max-width:1200px;margin:0 auto;padding:16px;display:flex}.header-actions{align-items:center;gap:12px;margin-left:auto;display:flex}.logo{cursor:pointer;color:#333;font-size:24px;font-weight:700;transition:color .2s}.logo:hover{color:#007acc}.logo-full{display:inline}.logo-short{display:none}@media (width<=768px){.header-container{padding:12px 16px}.logo{font-size:var(--font-size)}.logo-full{display:none}.logo-short{display:inline}}@media (width<=480px){.header-container{padding:8px 12px}.logo{font-size:var(--font-size)}}.sg-app-launcher{font-family:var(--font-family);position:relative}.sg-app-launcher-toggle{width:40px;height:40px;color:var(--ink-muted);cursor:pointer;background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;padding:0;display:inline-flex}.sg-app-launcher-toggle:hover,.sg-app-launcher-toggle[aria-expanded=true]{background:var(--primary-hover-bg)}.sg-app-launcher-panel{z-index:1000;box-sizing:border-box;border:1px solid var(--primary-border);border-radius:calc(var(--radius) * 3);background:var(--modal-bg);width:320px;max-width:calc(100vw - 24px);max-height:70vh;box-shadow:var(--shadow-2);padding:12px;position:absolute;top:calc(100% + 8px);right:0;overflow-y:auto}.sg-app-launcher-grid{grid-template-columns:repeat(3,minmax(0,1fr));gap:4px;margin:0;padding:0;list-style:none;display:grid}.sg-app-launcher-app{border-radius:var(--radius);color:inherit;flex-direction:column;align-items:center;gap:6px;padding:12px 4px;text-decoration:none;display:flex}.sg-app-launcher-app:hover,.sg-app-launcher-app:focus-visible{background:var(--primary-hover-bg)}.sg-app-launcher-app.current{background:var(--accent-soft)}.sg-app-launcher-tile{border-radius:var(--radius);background:var(--accent);color:#fff;justify-content:center;align-items:center;width:40px;height:40px;font-size:18px;font-weight:600;display:flex}.sg-app-launcher-name{text-overflow:ellipsis;white-space:nowrap;max-width:100%;font-size:13px;overflow:hidden}.sg-app-launcher-message{color:var(--ink-muted);margin:0;padding:8px;font-size:13px}.modal-overlay{background:var(--modal-overlay);z-index:1000;justify-content:center;align-items:center;width:100vw;height:100vh;animation:.25s ease-out sg-modal-overlay-fade-in;display:flex;position:fixed;top:0;left:0}.modal-overlay.modal-overlay-closing{animation:.22s ease-in forwards sg-modal-overlay-fade-out}.modal-content{--drag-x:0px;--drag-y:0px;background:var(--modal-bg);border-radius:var(--primary-radius);font-size:var(--primary-font);min-width:320px;max-width:calc(100vw - 40px);max-height:90vh;transform:translate(var(--drag-x), var(--drag-y));flex-direction:column;animation:.3s ease-out sg-modal-slide-in;display:flex;overflow:hidden;box-shadow:0 2px 16px #00000026}.modal-content.modal-content-closing{animation:.22s ease-in forwards sg-modal-slide-out}@keyframes sg-modal-overlay-fade-in{0%{opacity:0}to{opacity:1}}@keyframes sg-modal-overlay-fade-out{0%{opacity:1}to{opacity:0}}@keyframes sg-modal-slide-in{0%{transform:translate(var(--drag-x), calc(var(--drag-y) - 24px)) scale(.97);opacity:0}to{transform:translate(var(--drag-x), var(--drag-y)) scale(1);opacity:1}}@keyframes sg-modal-slide-out{0%{transform:translate(var(--drag-x), var(--drag-y)) scale(1);opacity:1}to{transform:translate(var(--drag-x), calc(var(--drag-y) - 24px)) scale(.97);opacity:0}}.modal-header{background:var(--primary-bg);border-top-left-radius:var(--primary-radius);border-top-right-radius:var(--primary-radius);cursor:grab;touch-action:none;flex:none;align-items:center;gap:8px;padding:16px;display:flex}.modal-header-dragging{cursor:grabbing;-webkit-user-select:none;user-select:none}.modal-icon{color:var(--modal-title-color);display:inline-flex}.modal-title{color:var(--modal-title-color);font-family:var(--font-family);font-size:var(--primary-font);flex:1;margin:0}.modal-close{cursor:pointer;color:var(--modal-title-color);background:0 0;border:none;padding:4px 8px;font-size:20px;line-height:1}.modal-close:disabled{cursor:default;opacity:.6}.modal-children{font-family:var(--font-family);padding:16px;overflow-y:auto}.modal-footer{border-top:1px solid var(--primary-border);flex-wrap:wrap;flex:none;justify-content:flex-end;gap:8px;padding:12px 16px;display:flex}.input-label{font-weight:500;font-family:var(--font-family);font-size:var(--primary-font);margin-bottom:4px;display:block}.input-field--invalid{background-color:#ffe5e5;border-color:#c00}.input-wrapper{margin-bottom:16px}.input-label{font-weight:500;font-size:var(--primary-font);margin-bottom:4px;display:block}.input-field{box-sizing:border-box;border-radius:var(--radius);width:100%;font-size:var(--primary-font);border-style:solid;border-width:1px;padding:8px}.login-modal-form{font-family:var(--font-family);font-size:var(--primary-font);flex-direction:column;gap:16px;display:flex}.header.quadrato-header{z-index:999}.quadrato-header-auth{align-items:center;gap:12px;display:flex}.quadrato-header-username{font-size:var(--font-size);color:#333}form{font-family:var(--font-family)}.set-password-modal-form{font-family:var(--font-family);font-size:var(--primary-font);flex-direction:column;gap:16px;display:flex}.set-password-modal-error{color:#d32f2f;font-size:var(--primary-font);margin:0}.sg-color-picker{font-family:var(--font-family);position:relative}.sg-color-picker-toggle{border-radius:var(--input-radius);border:1px solid var(--input-border);background:var(--input-bg);width:100%;color:inherit;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;font-family:inherit;font-size:13px;display:flex}.sg-color-picker-toggle-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.sg-color-picker-swatch{border:1px solid #00000026;border-radius:4px;flex:none;width:18px;height:18px}.sg-color-picker-popover{z-index:30;background:var(--input-bg);border:1px solid var(--input-border);border-radius:var(--input-radius);box-shadow:var(--shadow-1);width:170px;padding:10px;position:absolute;top:calc(100% + 4px);left:0}.sg-color-picker-grid{grid-template-columns:repeat(6,1fr);gap:6px;display:grid}.sg-color-picker-swatch-button{cursor:pointer;border:1px solid #00000026;border-radius:4px;width:20px;height:20px;padding:0}.sg-color-picker-swatch-button.active{border:2px solid var(--accent)}.sg-color-picker-custom{border-top:1px solid var(--input-border);color:var(--ink-muted);cursor:pointer;justify-content:space-between;align-items:center;gap:8px;margin-top:8px;padding-top:8px;font-size:11px;display:flex}.sg-color-picker-custom input[type=color]{cursor:pointer;border:none;width:26px;height:20px;padding:0}.sg-font-picker{font-family:var(--font-family);position:relative}.sg-font-picker-toggle{border-radius:var(--input-radius);border:1px solid var(--input-border);background:var(--input-bg);width:100%;color:inherit;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;font-size:13px;display:flex}.sg-font-picker-toggle-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.sg-font-picker-toggle-caret{opacity:.5;flex:none;font-size:10px}.sg-font-picker-list{background:var(--input-bg);border:1px solid var(--input-border);border-radius:var(--input-radius);max-height:260px;box-shadow:var(--shadow-1);z-index:30;margin:0;padding:4px 0;list-style:none;position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto}.sg-font-picker-option{text-align:left;width:100%;color:inherit;cursor:pointer;background:0 0;border:none;padding:8px 10px;font-size:15px;display:block}.sg-font-picker-option.active{background:var(--accent-soft)}:root{--unit:3px;--primary-bg:#f5f5f5;--primary-border:#ccc;--radius:calc(var(--unit) * 2);--primary-radius:var(--radius);--primary-font:var(--font-size);--primary-hover-bg:#e0e0e0;--modal-bg:#fff;--modal-overlay:#0000004d;--modal-title-color:#222;--input-bg:#fff;--input-border:#ccc;--input-radius:var(--radius);--input-font:1rem;--font-size:14px;--font-family:Arial, sans-serif;--font-size-h1:calc(var(--font-size) * 1.5);--button-bg:#6f9cf7;--button-bg-hover:#5480e6;--button-color:#fff;--button-radius:999px;--button-shadow:0 1px 2px #5480e61f, 0 1px 3px #5480e61a;--button-ease-standard:cubic-bezier(.4, 0, .2, 1);--button-ease-bounce:cubic-bezier(.34, 1.56, .64, 1);--accent:#3d5fc4;--accent-strong:#2e4aa0;--accent-soft:#e2e7f8;--ink-muted:#647089;--shadow-1:0 1px 2px #0f172a14, 0 1px 3px #0f172a0f;--shadow-2:0 4px 12px #0f172a1f}.theme-dark{--primary-bg:#222;--primary-border:#444;--primary-font:1rem;--font-family:"Inter", Arial, sans-serif;--primary-hover-bg:#333;--modal-bg:#222;--modal-title-color:#fff;--input-bg:#333;--input-border:#555;--input-font:1rem;--button-bg:#6f9cf7;--button-bg-hover:#86aefc;--button-color:#fff;--accent:#6f9cf7;--accent-strong:#86aefc;--accent-soft:#6f9cf72e;--ink-muted:#9aa3b5;--shadow-1:0 1px 2px #0000004d, 0 1px 3px #0000003d;--shadow-2:0 4px 12px #0006}.sg-toggle{cursor:pointer;-webkit-user-select:none;user-select:none;font-family:var(--font-family);align-items:center;gap:6px;display:flex}.sg-toggle-input{opacity:0;width:1px;height:1px;position:absolute}.sg-toggle-track{background:var(--input-border);border-radius:999px;flex:none;width:34px;height:20px;transition:background .15s cubic-bezier(.4,0,.2,1);position:relative}.sg-toggle-input:checked+.sg-toggle-track{background:var(--accent)}.sg-toggle-thumb{background:var(--input-bg);width:16px;height:16px;box-shadow:var(--shadow-1);border-radius:50%;transition:left .15s cubic-bezier(.4,0,.2,1);position:absolute;top:2px;left:2px}.sg-toggle-input:checked+.sg-toggle-track .sg-toggle-thumb{left:16px}.sg-toggle-input:focus-visible+.sg-toggle-track{outline:2px solid var(--accent-strong);outline-offset:2px}.sg-toggle-label{color:var(--ink-muted);white-space:nowrap;font-size:13px}
2
2
  /*$vite$:1*/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sensorario/sg-components",
3
- "version": "0.0.98",
3
+ "version": "0.0.100",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "scripts": {