@sensorario/sg-components 0.0.103 → 0.0.104

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.
@@ -9,7 +9,7 @@ export type LauncherApp = {
9
9
  interface AppLauncherProps {
10
10
  /** Endpoint returning `{ apps: LauncherApp[] }` - the enabled apps, managed from Heimdall. */
11
11
  appsUrl?: string;
12
- /** Accessible name of the grid button - this library has no i18n of its own. */
12
+ /** Accessible name of the grid button. Default: the translated "App". */
13
13
  label?: string;
14
14
  /** Logged-in user's JWT: the API then lists only the apps this user may use. */
15
15
  token?: string | null;
@@ -0,0 +1,6 @@
1
+ import './LanguageSwitcher.css';
2
+ interface LanguageSwitcherProps {
3
+ className?: string;
4
+ }
5
+ export declare const LanguageSwitcher: ({ className }: LanguageSwitcherProps) => import("react/jsx-runtime").JSX.Element;
6
+ export default LanguageSwitcher;
@@ -0,0 +1,5 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { LanguageSwitcher } from './LanguageSwitcher';
3
+ declare const meta: Meta<typeof LanguageSwitcher>;
4
+ export default meta;
5
+ export declare const Default: StoryObj<typeof LanguageSwitcher>;
@@ -12,6 +12,7 @@ interface ModalProps {
12
12
  children: React.ReactNode;
13
13
  buttons?: ModalButton[];
14
14
  footer?: React.ReactNode;
15
+ /** Accessible name of the dismiss button. Default: the translated "Close". */
15
16
  closeLabel?: string;
16
17
  className?: string;
17
18
  }
@@ -1,4 +1,6 @@
1
1
  import './QuadratoHeader.css';
2
+ /** Dispatch on `window` with the new avatar (data URL or null) as `detail` after changing it, so the header updates without a reload. */
3
+ export declare const AVATAR_CHANGE_EVENT = "sg-avatar-change";
2
4
  interface QuadratoHeaderProps {
3
5
  title?: string;
4
6
  homePageKey?: string;
@@ -0,0 +1,13 @@
1
+ import { type i18n } from 'i18next';
2
+ export declare const SUPPORTED_LANGUAGES: readonly ["it", "en", "fr", "de", "es", "ja"];
3
+ export type SupportedLanguage = typeof SUPPORTED_LANGUAGES[number];
4
+ export declare const LANGUAGE_NAMES: Record<SupportedLanguage, string>;
5
+ export declare const LANGUAGE_COOKIE = "sg-language";
6
+ export declare const readLanguageCookie: () => SupportedLanguage | null;
7
+ export declare const sgI18n: i18n;
8
+ type AppResources = Partial<Record<SupportedLanguage, Record<string, unknown>>>;
9
+ /** Adds the app's own texts (default namespace) to the shared instance and makes it the one react-i18next hooks use. */
10
+ export declare const createI18n: ({ resources }: {
11
+ resources: AppResources;
12
+ }) => i18n;
13
+ export {};
package/dist/index.d.ts CHANGED
@@ -17,3 +17,6 @@ export * from './components/FontPicker/FontPicker';
17
17
  export * from './components/Toggle/Toggle';
18
18
  export * from './components/AppLauncher/AppLauncher';
19
19
  export * from './components/AppAccessGate/AppAccessGate';
20
+ export * from './components/LanguageSwitcher/LanguageSwitcher';
21
+ export { createI18n, sgI18n, SUPPORTED_LANGUAGES, LANGUAGE_NAMES, LANGUAGE_COOKIE, readLanguageCookie } from './i18n';
22
+ export type { SupportedLanguage } from './i18n';
package/dist/index.es.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import e, { forwardRef as t, useEffect as n, useId as r, useImperativeHandle as i, useRef as a, useState as o } from "react";
2
2
  import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
3
+ import { setI18n as u, useTranslation as d } from "react-i18next";
4
+ import f from "i18next";
3
5
  //#region src/components/Icon/Icon.tsx
4
- var u = {
6
+ var p = {
5
7
  menu: /* @__PURE__ */ l(s, { children: [
6
8
  /* @__PURE__ */ c("line", {
7
9
  x1: "3",
@@ -236,7 +238,7 @@ var u = {
236
238
  height: "10",
237
239
  rx: "2"
238
240
  }), /* @__PURE__ */ c("path", { d: "M8 11V7a4 4 0 0 1 8 0v4" })] })
239
- }, d = ({ name: e, size: t = 18, ...n }) => /* @__PURE__ */ c("svg", {
241
+ }, m = ({ name: e, size: t = 18, ...n }) => /* @__PURE__ */ c("svg", {
240
242
  className: "sg-icon",
241
243
  width: t,
242
244
  height: t,
@@ -248,8 +250,8 @@ var u = {
248
250
  strokeLinejoin: "round",
249
251
  "aria-hidden": "true",
250
252
  ...n,
251
- children: u[e]
252
- }), f = ({ label: e, icon: t, iconOnly: n, className: r, title: i, ...a }) => /* @__PURE__ */ l("button", {
253
+ children: p[e]
254
+ }), h = ({ label: e, icon: t, iconOnly: n, className: r, title: i, ...a }) => /* @__PURE__ */ l("button", {
253
255
  className: [
254
256
  "custom-button",
255
257
  t ? "custom-button-with-icon" : "",
@@ -257,11 +259,11 @@ var u = {
257
259
  ].filter(Boolean).join(" "),
258
260
  title: i ?? (n ? e : void 0),
259
261
  ...a,
260
- children: [t && /* @__PURE__ */ c(d, { name: t }), /* @__PURE__ */ c("span", {
262
+ children: [t && /* @__PURE__ */ c(m, { name: t }), /* @__PURE__ */ c("span", {
261
263
  className: n ? "custom-button-label-visually-hidden" : void 0,
262
264
  children: e
263
265
  })]
264
- }), p = ({ copyright: e = "© 2026 My Company", href: t = "#", links: n = [] }) => /* @__PURE__ */ l("footer", {
266
+ }), g = ({ copyright: e = "© 2026 My Company", href: t = "#", links: n = [] }) => /* @__PURE__ */ l("footer", {
265
267
  className: "footer",
266
268
  children: [/* @__PURE__ */ c("span", { children: /* @__PURE__ */ c("a", {
267
269
  href: t,
@@ -271,17 +273,17 @@ var u = {
271
273
  style: { marginLeft: "16px" },
272
274
  children: e
273
275
  }, t)) })]
274
- }), m = "simonegentili.com-cookie-consent", h = 3600 * 24 * 365;
275
- function g() {
276
- return document.cookie.split("; ").some((e) => e.startsWith(`${m}=`));
276
+ }), _ = "simonegentili.com-cookie-consent", v = 3600 * 24 * 365;
277
+ function y() {
278
+ return document.cookie.split("; ").some((e) => e.startsWith(`${_}=`));
277
279
  }
278
- function _() {
279
- document.cookie = `${m}=accepted; path=/; domain=.simonegentili.com; max-age=${h}; secure; samesite=strict`;
280
+ function b() {
281
+ document.cookie = `${_}=accepted; path=/; domain=.simonegentili.com; max-age=${v}; secure; samesite=strict`;
280
282
  }
281
- var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
283
+ var x = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
282
284
  let [t, r] = o(!1);
283
285
  return n(() => {
284
- r(!g());
286
+ r(!y());
285
287
  }, []), t ? /* @__PURE__ */ l("div", {
286
288
  className: "cookie-consent",
287
289
  role: "region",
@@ -299,15 +301,15 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
299
301
  }),
300
302
  "."
301
303
  ]
302
- }), /* @__PURE__ */ c(f, {
304
+ }), /* @__PURE__ */ c(h, {
303
305
  label: "Accetta",
304
306
  onClick: () => {
305
- _(), r(!1);
307
+ b(), r(!1);
306
308
  },
307
309
  className: "cookie-consent-accept"
308
310
  })]
309
311
  }) : null;
310
- }, y = [
312
+ }, S = [
311
313
  {
312
314
  label: "guitar",
313
315
  href: "https://guitar.simonegentili.com"
@@ -328,11 +330,11 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
328
330
  label: "code2image",
329
331
  href: "https://code2image.simonegentili.com"
330
332
  }
331
- ], b = () => /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c(p, {
333
+ ], C = () => /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c(g, {
332
334
  href: "https://simonegentili.com",
333
335
  copyright: "© 2026 simonegentili.com",
334
- links: y
335
- }), /* @__PURE__ */ c(v, {})] }), x = ({ onNavigate: e, title: t = "Simone Gentili - senior web developer, tech author and chess enthusiast", homePageKey: n = "home", children: r, className: i }) => /* @__PURE__ */ c("header", {
336
+ links: S
337
+ }), /* @__PURE__ */ c(x, {})] }), w = ({ onNavigate: e, title: t = "Simone Gentili - senior web developer, tech author and chess enthusiast", homePageKey: n = "home", children: r, className: i }) => /* @__PURE__ */ c("header", {
336
338
  className: i ? `header ${i}` : "header",
337
339
  children: /* @__PURE__ */ l("div", {
338
340
  className: "header-container",
@@ -350,46 +352,279 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
350
352
  children: r
351
353
  })]
352
354
  })
353
- }), S = ({ onNavigate: e }) => /* @__PURE__ */ c(x, {
355
+ }), T = ({ onNavigate: e }) => /* @__PURE__ */ c(w, {
354
356
  onNavigate: e,
355
357
  title: "Simone Gentili - senior web developer, tech author and chess enthusiast",
356
358
  homePageKey: "home"
357
- }), C = "https://api.simonegentili.com/heimdall", w = (e) => e.endsWith("/") ? e : `${e}/`, T = (e) => {
358
- let t = w(window.location.origin + window.location.pathname);
359
- return e.filter((e) => t.startsWith(w(e.url))).sort((e, t) => t.url.length - e.url.length)[0] ?? null;
360
- }, E = ({ token: e, heimdallUrl: t = C }) => {
361
- let [r, i] = o(null), [a, u] = o(!1), [d, p] = o(!1);
359
+ }), E = {
360
+ auth: {
361
+ login: "Accedi",
362
+ logout: "Esci",
363
+ username: "Username",
364
+ password: "Password"
365
+ },
366
+ modal: { close: "Chiudi" },
367
+ accessGate: {
368
+ title: "Non hai accesso a {{app}}",
369
+ pending: "La tua richiesta è in attesa di approvazione.",
370
+ rejected: "La tua richiesta di accesso è stata rifiutata. Puoi inviarne una nuova.",
371
+ none: "Per usare questa app devi chiedere l’accesso a un amministratore.",
372
+ failed: "Invio non riuscito, riprova.",
373
+ sending: "Invio…",
374
+ request: "Richiedi accesso"
375
+ },
376
+ launcher: {
377
+ label: "App",
378
+ loading: "Caricamento…",
379
+ loadFailed: "Impossibile caricare le app.",
380
+ locked: "accesso su richiesta"
381
+ },
382
+ setPassword: {
383
+ title: "Imposta una nuova password",
384
+ newPassword: "Nuova password",
385
+ confirmPassword: "Conferma password",
386
+ submit: "Salva password",
387
+ errorEmpty: "Inserisci e conferma la nuova password.",
388
+ errorMismatch: "Le password non coincidono."
389
+ },
390
+ languageSwitcher: { label: "Lingua" }
391
+ }, D = {
392
+ auth: {
393
+ login: "Log in",
394
+ logout: "Log out",
395
+ username: "Username",
396
+ password: "Password"
397
+ },
398
+ modal: { close: "Close" },
399
+ accessGate: {
400
+ title: "You don't have access to {{app}}",
401
+ pending: "Your request is awaiting approval.",
402
+ rejected: "Your access request was rejected. You can send a new one.",
403
+ none: "To use this app you need to ask an administrator for access.",
404
+ failed: "Sending failed, please try again.",
405
+ sending: "Sending…",
406
+ request: "Request access"
407
+ },
408
+ launcher: {
409
+ label: "Apps",
410
+ loading: "Loading…",
411
+ loadFailed: "Unable to load the apps.",
412
+ locked: "access on request"
413
+ },
414
+ setPassword: {
415
+ title: "Set a new password",
416
+ newPassword: "New password",
417
+ confirmPassword: "Confirm password",
418
+ submit: "Save password",
419
+ errorEmpty: "Enter and confirm the new password.",
420
+ errorMismatch: "The passwords don't match."
421
+ },
422
+ languageSwitcher: { label: "Language" }
423
+ }, O = {
424
+ auth: {
425
+ login: "Se connecter",
426
+ logout: "Se déconnecter",
427
+ username: "Nom d’utilisateur",
428
+ password: "Mot de passe"
429
+ },
430
+ modal: { close: "Fermer" },
431
+ accessGate: {
432
+ title: "Vous n’avez pas accès à {{app}}",
433
+ pending: "Votre demande est en attente d’approbation.",
434
+ rejected: "Votre demande d’accès a été refusée. Vous pouvez en envoyer une nouvelle.",
435
+ none: "Pour utiliser cette application, vous devez demander l’accès à un administrateur.",
436
+ failed: "Échec de l’envoi, veuillez réessayer.",
437
+ sending: "Envoi…",
438
+ request: "Demander l’accès"
439
+ },
440
+ launcher: {
441
+ label: "Applications",
442
+ loading: "Chargement…",
443
+ loadFailed: "Impossible de charger les applications.",
444
+ locked: "accès sur demande"
445
+ },
446
+ setPassword: {
447
+ title: "Définir un nouveau mot de passe",
448
+ newPassword: "Nouveau mot de passe",
449
+ confirmPassword: "Confirmer le mot de passe",
450
+ submit: "Enregistrer le mot de passe",
451
+ errorEmpty: "Saisissez et confirmez le nouveau mot de passe.",
452
+ errorMismatch: "Les mots de passe ne correspondent pas."
453
+ },
454
+ languageSwitcher: { label: "Langue" }
455
+ }, k = {
456
+ auth: {
457
+ login: "Anmelden",
458
+ logout: "Abmelden",
459
+ username: "Benutzername",
460
+ password: "Passwort"
461
+ },
462
+ modal: { close: "Schließen" },
463
+ accessGate: {
464
+ title: "Du hast keinen Zugriff auf {{app}}",
465
+ pending: "Deine Anfrage wartet auf Freigabe.",
466
+ rejected: "Deine Zugriffsanfrage wurde abgelehnt. Du kannst eine neue senden.",
467
+ none: "Um diese App zu nutzen, musst du einen Administrator um Zugriff bitten.",
468
+ failed: "Senden fehlgeschlagen, bitte versuche es erneut.",
469
+ sending: "Wird gesendet…",
470
+ request: "Zugriff anfragen"
471
+ },
472
+ launcher: {
473
+ label: "Apps",
474
+ loading: "Wird geladen…",
475
+ loadFailed: "Die Apps konnten nicht geladen werden.",
476
+ locked: "Zugriff auf Anfrage"
477
+ },
478
+ setPassword: {
479
+ title: "Neues Passwort festlegen",
480
+ newPassword: "Neues Passwort",
481
+ confirmPassword: "Passwort bestätigen",
482
+ submit: "Passwort speichern",
483
+ errorEmpty: "Gib das neue Passwort ein und bestätige es.",
484
+ errorMismatch: "Die Passwörter stimmen nicht überein."
485
+ },
486
+ languageSwitcher: { label: "Sprache" }
487
+ }, A = {
488
+ auth: {
489
+ login: "Iniciar sesión",
490
+ logout: "Cerrar sesión",
491
+ username: "Usuario",
492
+ password: "Contraseña"
493
+ },
494
+ modal: { close: "Cerrar" },
495
+ accessGate: {
496
+ title: "No tienes acceso a {{app}}",
497
+ pending: "Tu solicitud está pendiente de aprobación.",
498
+ rejected: "Tu solicitud de acceso ha sido rechazada. Puedes enviar una nueva.",
499
+ none: "Para usar esta aplicación debes pedir acceso a un administrador.",
500
+ failed: "No se pudo enviar, inténtalo de nuevo.",
501
+ sending: "Enviando…",
502
+ request: "Solicitar acceso"
503
+ },
504
+ launcher: {
505
+ label: "Aplicaciones",
506
+ loading: "Cargando…",
507
+ loadFailed: "No se pudieron cargar las aplicaciones.",
508
+ locked: "acceso bajo solicitud"
509
+ },
510
+ setPassword: {
511
+ title: "Establecer una nueva contraseña",
512
+ newPassword: "Nueva contraseña",
513
+ confirmPassword: "Confirmar contraseña",
514
+ submit: "Guardar contraseña",
515
+ errorEmpty: "Introduce y confirma la nueva contraseña.",
516
+ errorMismatch: "Las contraseñas no coinciden."
517
+ },
518
+ languageSwitcher: { label: "Idioma" }
519
+ }, ee = {
520
+ auth: {
521
+ login: "ログイン",
522
+ logout: "ログアウト",
523
+ username: "ユーザー名",
524
+ password: "パスワード"
525
+ },
526
+ modal: { close: "閉じる" },
527
+ accessGate: {
528
+ title: "{{app}} へのアクセス権がありません",
529
+ pending: "リクエストは承認待ちです。",
530
+ rejected: "アクセスリクエストは却下されました。新しいリクエストを送信できます。",
531
+ none: "このアプリを使うには、管理者にアクセスを申請してください。",
532
+ failed: "送信に失敗しました。もう一度お試しください。",
533
+ sending: "送信中…",
534
+ request: "アクセスを申請"
535
+ },
536
+ launcher: {
537
+ label: "アプリ",
538
+ loading: "読み込み中…",
539
+ loadFailed: "アプリを読み込めませんでした。",
540
+ locked: "申請によりアクセス可能"
541
+ },
542
+ setPassword: {
543
+ title: "新しいパスワードを設定",
544
+ newPassword: "新しいパスワード",
545
+ confirmPassword: "パスワードの確認",
546
+ submit: "パスワードを保存",
547
+ errorEmpty: "新しいパスワードを入力して確認してください。",
548
+ errorMismatch: "パスワードが一致しません。"
549
+ },
550
+ languageSwitcher: { label: "言語" }
551
+ }, j = [
552
+ "it",
553
+ "en",
554
+ "fr",
555
+ "de",
556
+ "es",
557
+ "ja"
558
+ ], M = {
559
+ it: "Italiano",
560
+ en: "English",
561
+ fr: "Français",
562
+ de: "Deutsch",
563
+ es: "Español",
564
+ ja: "日本語"
565
+ }, N = "sg-language", P = "it", te = (e) => !!e && j.includes(e), F = () => {
566
+ let e = document.cookie.split("; ").find((e) => e.startsWith(`${N}=`))?.slice(12);
567
+ return te(e) ? e : null;
568
+ }, I = (e) => {
569
+ let t = window.location.hostname.endsWith("simonegentili.com") ? "; domain=.simonegentili.com; secure" : "";
570
+ document.cookie = `${N}=${e}; path=/; max-age=31536000; samesite=lax${t}`;
571
+ }, L = f.createInstance();
572
+ L.init({
573
+ resources: {
574
+ it: { sg: E },
575
+ en: { sg: D },
576
+ fr: { sg: O },
577
+ de: { sg: k },
578
+ es: { sg: A },
579
+ ja: { sg: ee }
580
+ },
581
+ lng: F() ?? P,
582
+ fallbackLng: P,
583
+ supportedLngs: [...j],
584
+ ns: ["sg", "translation"],
585
+ defaultNS: "translation",
586
+ initAsync: !1,
587
+ interpolation: { escapeValue: !1 }
588
+ }), L.on("languageChanged", I);
589
+ var ne = ({ resources: e }) => {
590
+ for (let [t, n] of Object.entries(e)) L.addResourceBundle(t, "translation", n, !0, !0);
591
+ return u(L), L;
592
+ }, R = "https://api.simonegentili.com/heimdall", z = (e) => e.endsWith("/") ? e : `${e}/`, re = (e) => {
593
+ let t = z(window.location.origin + window.location.pathname);
594
+ return e.filter((e) => t.startsWith(z(e.url))).sort((e, t) => t.url.length - e.url.length)[0] ?? null;
595
+ }, B = ({ token: e, heimdallUrl: t = R }) => {
596
+ let { t: r } = d("sg", { i18n: L }), [i, a] = o(null), [u, f] = o(!1), [p, m] = o(!1);
362
597
  n(() => {
363
- e && fetch(`${t}/access`, { headers: { Authorization: `Bearer ${e}` } }).then((e) => e.ok ? e.json() : Promise.reject(e.status)).then((t) => i({
598
+ e && fetch(`${t}/access`, { headers: { Authorization: `Bearer ${e}` } }).then((e) => e.ok ? e.json() : Promise.reject(e.status)).then((t) => a({
364
599
  token: e,
365
- app: T(t.apps)
366
- })).catch(() => i({
600
+ app: re(t.apps)
601
+ })).catch(() => a({
367
602
  token: e,
368
603
  app: null
369
604
  }));
370
605
  }, [e, t]);
371
- let m = r?.token === e ? r.app : null;
372
- return !e || m === null || m.access === "open" || m.access === "approved" ? null : /* @__PURE__ */ c("div", {
606
+ let g = i?.token === e ? i.app : null;
607
+ return !e || g === null || g.access === "open" || g.access === "approved" ? null : /* @__PURE__ */ c("div", {
373
608
  className: "sg-access-gate",
374
609
  role: "dialog",
375
610
  "aria-modal": "true",
376
611
  "aria-labelledby": "sg-access-gate-title",
377
612
  children: /* @__PURE__ */ l("div", {
378
613
  className: "sg-access-gate-card",
379
- children: [/* @__PURE__ */ l("h2", {
614
+ children: [/* @__PURE__ */ c("h2", {
380
615
  id: "sg-access-gate-title",
381
- children: ["Non hai accesso a ", m.name]
382
- }), m.access === "pending" ? /* @__PURE__ */ c("p", { children: "La tua richiesta è in attesa di approvazione." }) : /* @__PURE__ */ l(s, { children: [
383
- /* @__PURE__ */ c("p", { children: m.access === "rejected" ? "La tua richiesta di accesso è stata rifiutata. Puoi inviarne una nuova." : "Per usare questa app devi chiedere l’accesso a un amministratore." }),
384
- d && /* @__PURE__ */ c("p", {
616
+ children: r("accessGate.title", { app: g.name })
617
+ }), g.access === "pending" ? /* @__PURE__ */ c("p", { children: r("accessGate.pending") }) : /* @__PURE__ */ l(s, { children: [
618
+ /* @__PURE__ */ c("p", { children: g.access === "rejected" ? r("accessGate.rejected") : r("accessGate.none") }),
619
+ p && /* @__PURE__ */ c("p", {
385
620
  className: "sg-access-gate-error",
386
- children: "Invio non riuscito, riprova."
621
+ children: r("accessGate.failed")
387
622
  }),
388
- /* @__PURE__ */ c(f, {
389
- label: a ? "Invio…" : "Richiedi accesso",
390
- disabled: a,
623
+ /* @__PURE__ */ c(h, {
624
+ label: r(u ? "accessGate.sending" : "accessGate.request"),
625
+ disabled: u,
391
626
  onClick: async () => {
392
- u(!0), p(!1);
627
+ f(!0), m(!1);
393
628
  try {
394
629
  let n = await fetch(`${t}/access-requests`, {
395
630
  method: "POST",
@@ -397,167 +632,174 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
397
632
  Authorization: `Bearer ${e}`,
398
633
  "Content-Type": "application/json"
399
634
  },
400
- body: JSON.stringify({ app: m.slug })
635
+ body: JSON.stringify({ app: g.slug })
401
636
  });
402
- n.ok || n.status === 409 ? i({
637
+ n.ok || n.status === 409 ? a({
403
638
  token: e,
404
639
  app: {
405
- ...m,
640
+ ...g,
406
641
  access: "pending"
407
642
  }
408
- }) : p(!0);
643
+ }) : m(!0);
409
644
  } catch {
410
- p(!0);
645
+ m(!0);
411
646
  } finally {
412
- u(!1);
647
+ f(!1);
413
648
  }
414
649
  }
415
650
  })
416
651
  ] })]
417
652
  })
418
653
  });
419
- }, D = "https://api.simonegentili.com/heimdall/launcher", O = ({ appsUrl: e = D, label: t = "App", token: r = null }) => {
420
- let [i, s] = o(!1), [u, f] = o(null), p = u?.token === r ? u.apps : null, [m, h] = o(!1), g = a(null);
654
+ }, V = "https://api.simonegentili.com/heimdall/launcher", H = ({ appsUrl: e = V, label: t, token: r = null }) => {
655
+ let { t: i } = d("sg", { i18n: L }), s = t ?? i("launcher.label"), [u, f] = o(!1), [p, h] = o(null), g = p?.token === r ? p.apps : null, [_, v] = o(!1), y = a(null);
421
656
  return n(() => {
422
- !i || p !== null || fetch(e, r ? { headers: { Authorization: `Bearer ${r}` } } : void 0).then((e) => e.ok ? e.json() : Promise.reject(e.status)).then((e) => f({
657
+ !u || g !== null || fetch(e, r ? { headers: { Authorization: `Bearer ${r}` } } : void 0).then((e) => e.ok ? e.json() : Promise.reject(e.status)).then((e) => h({
423
658
  token: r,
424
659
  apps: e.apps
425
- })).catch(() => h(!0));
660
+ })).catch(() => v(!0));
426
661
  }, [
427
- i,
428
- p,
662
+ u,
663
+ g,
429
664
  e,
430
665
  r
431
666
  ]), n(() => {
432
- if (!i) return;
667
+ if (!u) return;
433
668
  let e = (e) => {
434
- g.current?.contains(e.target) || s(!1);
669
+ y.current?.contains(e.target) || f(!1);
435
670
  }, t = (e) => {
436
- e.key === "Escape" && s(!1);
671
+ e.key === "Escape" && f(!1);
437
672
  };
438
673
  return document.addEventListener("pointerdown", e), document.addEventListener("keydown", t), () => {
439
674
  document.removeEventListener("pointerdown", e), document.removeEventListener("keydown", t);
440
675
  };
441
- }, [i]), /* @__PURE__ */ l("div", {
676
+ }, [u]), /* @__PURE__ */ l("div", {
442
677
  className: "sg-app-launcher",
443
- ref: g,
678
+ ref: y,
444
679
  children: [/* @__PURE__ */ c("button", {
445
680
  type: "button",
446
681
  className: "sg-app-launcher-toggle",
447
- "aria-label": t,
448
- title: t,
449
- "aria-expanded": i,
682
+ "aria-label": s,
683
+ title: s,
684
+ "aria-expanded": u,
450
685
  onClick: () => {
451
- i || h(!1), s(!i);
686
+ u || v(!1), f(!u);
452
687
  },
453
- children: /* @__PURE__ */ c(d, {
688
+ children: /* @__PURE__ */ c(m, {
454
689
  name: "grid",
455
690
  size: 22
456
691
  })
457
- }), i && /* @__PURE__ */ c("div", {
692
+ }), u && /* @__PURE__ */ c("div", {
458
693
  className: "sg-app-launcher-panel",
459
- children: m ? /* @__PURE__ */ c("p", {
694
+ children: _ ? /* @__PURE__ */ c("p", {
460
695
  className: "sg-app-launcher-message",
461
- children: "Impossibile caricare le app."
462
- }) : p === null ? /* @__PURE__ */ c("p", {
696
+ children: i("launcher.loadFailed")
697
+ }) : g === null ? /* @__PURE__ */ c("p", {
463
698
  className: "sg-app-launcher-message",
464
- children: "Caricamento…"
699
+ children: i("launcher.loading")
465
700
  }) : /* @__PURE__ */ c("ul", {
466
701
  className: "sg-app-launcher-grid",
467
- children: p.map((e) => /* @__PURE__ */ c("li", { children: /* @__PURE__ */ l("a", {
702
+ children: g.map((e) => /* @__PURE__ */ c("li", { children: /* @__PURE__ */ l("a", {
468
703
  href: e.url,
469
704
  className: [
470
705
  "sg-app-launcher-app",
471
706
  new URL(e.url).origin === window.location.origin ? "current" : "",
472
707
  e.locked ? "locked" : ""
473
708
  ].filter(Boolean).join(" "),
474
- title: e.locked ? `${e.name}: accesso su richiesta` : void 0,
709
+ title: e.locked ? `${e.name}: ${i("launcher.locked")}` : void 0,
475
710
  children: [/* @__PURE__ */ l("span", {
476
711
  className: "sg-app-launcher-tile",
477
712
  "aria-hidden": "true",
478
713
  children: [e.name.charAt(0).toUpperCase(), e.locked && /* @__PURE__ */ c("span", {
479
714
  className: "sg-app-launcher-lock",
480
- children: /* @__PURE__ */ c(d, {
715
+ children: /* @__PURE__ */ c(m, {
481
716
  name: "lock",
482
717
  size: 12
483
718
  })
484
719
  })]
485
720
  }), /* @__PURE__ */ l("span", {
486
721
  className: "sg-app-launcher-name",
487
- children: [e.name, e.locked && /* @__PURE__ */ c("span", {
722
+ children: [e.name, e.locked && /* @__PURE__ */ l("span", {
488
723
  className: "sg-visually-hidden",
489
- children: " (accesso su richiesta)"
724
+ children: [
725
+ " (",
726
+ i("launcher.locked"),
727
+ ")"
728
+ ]
490
729
  })]
491
730
  })]
492
731
  }) }, e.url))
493
732
  })
494
733
  })]
495
734
  });
496
- }, k = ({ isLoggedIn: e, handleLogin: t, handleLogout: n }) => /* @__PURE__ */ c(s, { children: e ? /* @__PURE__ */ c("button", {
497
- onClick: n,
498
- className: "sg-authenticator-button",
499
- children: "logout"
500
- }) : /* @__PURE__ */ c("button", {
501
- onClick: t,
502
- className: "sg-authenticator-button",
503
- children: "Login"
504
- }) }), A = 220, j = ({ open: t, onClose: r, title: i, icon: a, children: s, buttons: u, footer: d, closeLabel: p = "Close", className: m }) => {
505
- let [h, g] = o(!1), [_, v] = o({
735
+ }, U = ({ isLoggedIn: e, handleLogin: t, handleLogout: n }) => {
736
+ let { t: r } = d("sg", { i18n: L });
737
+ return /* @__PURE__ */ c(s, { children: e ? /* @__PURE__ */ c("button", {
738
+ onClick: n,
739
+ className: "sg-authenticator-button",
740
+ children: r("auth.logout")
741
+ }) : /* @__PURE__ */ c("button", {
742
+ onClick: t,
743
+ className: "sg-authenticator-button",
744
+ children: r("auth.login")
745
+ }) });
746
+ }, ie = 220, W = ({ open: t, onClose: r, title: i, icon: a, children: s, buttons: u, footer: f, closeLabel: p, className: m }) => {
747
+ let { t: g } = d("sg", { i18n: L }), [_, v] = o(!1), [y, b] = o({
506
748
  x: 0,
507
749
  y: 0
508
- }), y = e.useRef(null), [b, x] = o(!1), S = (e) => {
509
- h || (g(!0), setTimeout(() => {
510
- g(!1), e();
511
- }, A));
750
+ }), x = e.useRef(null), [S, C] = o(!1), w = (e) => {
751
+ _ || (v(!0), setTimeout(() => {
752
+ v(!1), e();
753
+ }, ie));
512
754
  };
513
755
  n(() => {
514
756
  if (!t) return;
515
757
  let e = (e) => {
516
- e.key === "Escape" && S(r);
758
+ e.key === "Escape" && w(r);
517
759
  };
518
760
  return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
519
761
  }, [t, r]);
520
- let [C, w] = o(t);
521
- if (t !== C && (w(t), t && v({
762
+ let [T, E] = o(t);
763
+ if (t !== T && (E(t), t && b({
522
764
  x: 0,
523
765
  y: 0
524
766
  })), !t) return null;
525
- function T(e) {
526
- e.target.closest(".modal-close") || (y.current = {
767
+ function D(e) {
768
+ e.target.closest(".modal-close") || (x.current = {
527
769
  pointerX: e.clientX,
528
770
  pointerY: e.clientY,
529
- offsetX: _.x,
530
- offsetY: _.y
531
- }, x(!0), e.currentTarget.setPointerCapture(e.pointerId));
771
+ offsetX: y.x,
772
+ offsetY: y.y
773
+ }, C(!0), e.currentTarget.setPointerCapture(e.pointerId));
532
774
  }
533
- function E(e) {
534
- if (!y.current) return;
535
- let { pointerX: t, pointerY: n, offsetX: r, offsetY: i } = y.current;
536
- v({
775
+ function O(e) {
776
+ if (!x.current) return;
777
+ let { pointerX: t, pointerY: n, offsetX: r, offsetY: i } = x.current;
778
+ b({
537
779
  x: r + (e.clientX - t),
538
780
  y: i + (e.clientY - n)
539
781
  });
540
782
  }
541
- function D() {
542
- y.current = null, x(!1);
783
+ function k() {
784
+ x.current = null, C(!1);
543
785
  }
544
786
  return /* @__PURE__ */ c("div", {
545
- className: `modal-overlay${h ? " modal-overlay-closing" : ""}`,
546
- onClick: () => S(r),
787
+ className: `modal-overlay${_ ? " modal-overlay-closing" : ""}`,
788
+ onClick: () => w(r),
547
789
  children: /* @__PURE__ */ l("div", {
548
- className: `modal-content${m ? ` ${m}` : ""}${h ? " modal-content-closing" : ""}`,
790
+ className: `modal-content${m ? ` ${m}` : ""}${_ ? " modal-content-closing" : ""}`,
549
791
  style: {
550
- "--drag-x": `${_.x}px`,
551
- "--drag-y": `${_.y}px`
792
+ "--drag-x": `${y.x}px`,
793
+ "--drag-y": `${y.y}px`
552
794
  },
553
795
  onClick: (e) => e.stopPropagation(),
554
796
  children: [
555
797
  /* @__PURE__ */ l("div", {
556
- className: `modal-header${b ? " modal-header-dragging" : ""}`,
557
- onPointerDown: T,
558
- onPointerMove: E,
559
- onPointerUp: D,
560
- onPointerCancel: D,
798
+ className: `modal-header${S ? " modal-header-dragging" : ""}`,
799
+ onPointerDown: D,
800
+ onPointerMove: O,
801
+ onPointerUp: k,
802
+ onPointerCancel: k,
561
803
  children: [
562
804
  a && /* @__PURE__ */ c("span", {
563
805
  className: "modal-icon",
@@ -570,9 +812,9 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
570
812
  /* @__PURE__ */ c("button", {
571
813
  type: "button",
572
814
  className: "modal-close",
573
- "aria-label": p,
574
- onClick: () => S(r),
575
- disabled: h,
815
+ "aria-label": p ?? g("modal.close"),
816
+ onClick: () => w(r),
817
+ disabled: _,
576
818
  children: "×"
577
819
  })
578
820
  ]
@@ -583,20 +825,20 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
583
825
  }),
584
826
  u && /* @__PURE__ */ c("div", {
585
827
  className: "modal-footer",
586
- children: u.map((e, t) => /* @__PURE__ */ c(f, {
828
+ children: u.map((e, t) => /* @__PURE__ */ c(h, {
587
829
  label: e.label,
588
- onClick: () => S(e.onClick),
589
- disabled: h
830
+ onClick: () => w(e.onClick),
831
+ disabled: _
590
832
  }, t))
591
833
  }),
592
- d && /* @__PURE__ */ c("div", {
834
+ f && /* @__PURE__ */ c("div", {
593
835
  className: "modal-footer",
594
- children: d
836
+ children: f
595
837
  })
596
838
  ]
597
839
  })
598
840
  });
599
- }, M = ({ label: e, invalid: t, className: n, id: i, ...a }) => {
841
+ }, G = ({ label: e, invalid: t, className: n, id: i, ...a }) => {
600
842
  let o = r(), s = i ?? o;
601
843
  return /* @__PURE__ */ l("div", {
602
844
  className: "input-wrapper",
@@ -614,7 +856,7 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
614
856
  ...a
615
857
  })]
616
858
  });
617
- }, N = ({ label: e, className: t, id: n, ...i }) => {
859
+ }, K = ({ label: e, className: t, id: n, ...i }) => {
618
860
  let a = r(), o = n ?? a;
619
861
  return /* @__PURE__ */ l("div", {
620
862
  className: "input-wrapper",
@@ -629,138 +871,164 @@ var v = ({ privacyPolicyHref: e = "https://simonegentili.com/privacy" }) => {
629
871
  ...i
630
872
  })]
631
873
  });
632
- }, P = ({ open: e, onClose: t, onLogin: n }) => {
633
- let [r, i] = o(""), [a, s] = o("");
634
- return /* @__PURE__ */ c(j, {
874
+ }, q = ({ open: e, onClose: t, onLogin: n }) => {
875
+ let { t: r } = d("sg", { i18n: L }), [i, a] = o(""), [s, u] = o("");
876
+ return /* @__PURE__ */ c(W, {
635
877
  open: e,
636
878
  onClose: t,
637
- title: "Login",
879
+ title: r("auth.login"),
638
880
  children: /* @__PURE__ */ l("form", {
639
881
  onSubmit: (e) => {
640
- e.preventDefault(), n(r, a);
882
+ e.preventDefault(), n(i, s);
641
883
  },
642
884
  children: [
643
- /* @__PURE__ */ c(M, {
644
- label: "Username",
645
- value: r,
646
- onChange: (e) => i(e.target.value),
885
+ /* @__PURE__ */ c(G, {
886
+ label: r("auth.username"),
887
+ value: i,
888
+ onChange: (e) => a(e.target.value),
647
889
  autoFocus: !0
648
890
  }),
649
- /* @__PURE__ */ c(N, {
650
- label: "Password",
651
- value: a,
652
- onChange: (e) => s(e.target.value)
891
+ /* @__PURE__ */ c(K, {
892
+ label: r("auth.password"),
893
+ value: s,
894
+ onChange: (e) => u(e.target.value)
653
895
  }),
654
- /* @__PURE__ */ c(f, {
655
- label: "Login",
896
+ /* @__PURE__ */ c(h, {
897
+ label: r("auth.login"),
656
898
  type: "submit",
657
899
  style: { width: "100%" }
658
900
  })
659
901
  ]
660
902
  })
661
903
  });
662
- }, F = "simonegentili.com-access-token", I = (e) => document.cookie.split("; ").some((t) => t.startsWith(`${e}=`) && t.slice(e.length + 1).length > 0), L = (e) => {
904
+ }, J = "simonegentili.com-access-token", Y = "sg-avatar-change", X = (e) => document.cookie.split("; ").some((t) => t.startsWith(`${e}=`) && t.slice(e.length + 1).length > 0), ae = (e) => {
663
905
  let t = document.cookie.split("; ").find((t) => t.startsWith(`${e}=`));
664
906
  return t ? t.slice(e.length + 1) : null;
665
- }, R = (e, t) => {
907
+ }, oe = (e, t) => {
666
908
  try {
667
909
  return JSON.parse(atob(e.split(".")[1].replace(/-/g, "+").replace(/_/g, "/")))[t] ?? null;
668
910
  } catch {
669
911
  return null;
670
912
  }
671
- }, z = t(({ title: e = "Quadrato", homePageKey: t = "home", onNavigate: r, cookieName: a = F, username: u = null, usernameJwtField: d = "sub", onLogin: f, onLogout: p, onUserAuthenticated: m, appsUrl: h, heimdallUrl: g }, _) => {
672
- let [v, y] = o(() => I(a)), [b, S] = o(!1);
673
- i(_, () => ({ openLoginModal: () => S(!0) }));
674
- let C = v ? L(a) : null, w = u ?? (C ? R(C, d) : null);
913
+ }, Z = 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, heimdallUrl: g = R }, _) => {
914
+ let [v, y] = o(() => X(a)), [b, x] = o(!1);
915
+ i(_, () => ({ openLoginModal: () => x(!0) }));
916
+ let S = v ? ae(a) : null, C = u ?? (S ? oe(S, d) : null), [T, E] = o(null), D = S && T?.token === S ? T.src : null;
675
917
  return n(() => {
676
- m?.(v, v ? w : null);
918
+ if (!S) return;
919
+ let e = !1;
920
+ return fetch(`${g}/me/avatar`, { headers: { Authorization: `Bearer ${S}` } }).then((e) => e.ok ? e.json() : null).then((t) => {
921
+ e || E({
922
+ token: S,
923
+ src: t?.avatar ?? null
924
+ });
925
+ }).catch(() => {}), () => {
926
+ e = !0;
927
+ };
928
+ }, [S, g]), n(() => {
929
+ if (!S) return;
930
+ let e = (e) => E({
931
+ token: S,
932
+ src: e.detail
933
+ });
934
+ return window.addEventListener(Y, e), () => window.removeEventListener(Y, e);
935
+ }, [S]), n(() => {
936
+ m?.(v, v ? C : null);
677
937
  }, []), /* @__PURE__ */ l(s, { children: [
678
- /* @__PURE__ */ l(x, {
938
+ /* @__PURE__ */ l(w, {
679
939
  onNavigate: r,
680
940
  title: e,
681
941
  homePageKey: t,
682
942
  className: "quadrato-header",
683
- children: [/* @__PURE__ */ c(O, {
943
+ children: [/* @__PURE__ */ c(H, {
684
944
  appsUrl: h,
685
- token: C
945
+ token: S
686
946
  }), /* @__PURE__ */ l("div", {
687
947
  className: "quadrato-header-auth",
688
- children: [v && w && /* @__PURE__ */ c("span", {
689
- className: "quadrato-header-username",
690
- children: w
691
- }), /* @__PURE__ */ c(k, {
692
- isLoggedIn: v,
693
- handleLogin: () => S(!0),
694
- handleLogout: () => {
695
- p?.();
696
- let e = I(a);
697
- y(e), m?.(e, null);
698
- }
699
- })]
948
+ children: [
949
+ v && D && /* @__PURE__ */ c("img", {
950
+ className: "quadrato-header-avatar",
951
+ src: D,
952
+ alt: ""
953
+ }),
954
+ v && C && /* @__PURE__ */ c("span", {
955
+ className: "quadrato-header-username",
956
+ children: C
957
+ }),
958
+ /* @__PURE__ */ c(U, {
959
+ isLoggedIn: v,
960
+ handleLogin: () => x(!0),
961
+ handleLogout: () => {
962
+ p?.();
963
+ let e = X(a);
964
+ y(e), m?.(e, null);
965
+ }
966
+ })
967
+ ]
700
968
  })]
701
969
  }),
702
- /* @__PURE__ */ c(E, {
703
- token: C,
970
+ /* @__PURE__ */ c(B, {
971
+ token: S,
704
972
  heimdallUrl: g
705
973
  }),
706
- /* @__PURE__ */ c(P, {
974
+ /* @__PURE__ */ c(q, {
707
975
  open: b,
708
- onClose: () => S(!1),
976
+ onClose: () => x(!1),
709
977
  onLogin: async (e, t) => {
710
978
  await f(e, t);
711
- let n = I(a);
712
- y(n), S(!1), m?.(n, n ? u ?? e : null);
979
+ let n = X(a);
980
+ y(n), x(!1), m?.(n, n ? u ?? e : null);
713
981
  }
714
982
  })
715
983
  ] });
716
984
  });
717
- z.displayName = "QuadratoHeader";
985
+ Z.displayName = "QuadratoHeader";
718
986
  //#endregion
719
987
  //#region src/components/SetPasswordModal/SetPasswordModal.tsx
720
- var B = ({ open: e, onClose: t, onSubmit: n }) => {
721
- let [r, i] = o(""), [a, s] = o(""), [u, d] = o("");
722
- return /* @__PURE__ */ c(j, {
988
+ var se = ({ open: e, onClose: t, onSubmit: n }) => {
989
+ let { t: r } = d("sg", { i18n: L }), [i, a] = o(""), [s, u] = o(""), [f, p] = o("");
990
+ return /* @__PURE__ */ c(W, {
723
991
  open: e,
724
992
  onClose: t,
725
- title: "Imposta una nuova password",
993
+ title: r("setPassword.title"),
726
994
  children: /* @__PURE__ */ l("form", {
727
995
  className: "set-password-modal-form",
728
996
  onSubmit: (e) => {
729
- if (e.preventDefault(), r === "" || a === "") {
730
- d("Inserisci ed conferma la nuova password.");
997
+ if (e.preventDefault(), i === "" || s === "") {
998
+ p(r("setPassword.errorEmpty"));
731
999
  return;
732
1000
  }
733
- if (r !== a) {
734
- d("Le password non coincidono.");
1001
+ if (i !== s) {
1002
+ p(r("setPassword.errorMismatch"));
735
1003
  return;
736
1004
  }
737
- d(""), n(r);
1005
+ p(""), n(i);
738
1006
  },
739
1007
  children: [
740
- /* @__PURE__ */ c(N, {
741
- label: "Nuova password",
742
- value: r,
743
- onChange: (e) => i(e.target.value),
1008
+ /* @__PURE__ */ c(K, {
1009
+ label: r("setPassword.newPassword"),
1010
+ value: i,
1011
+ onChange: (e) => a(e.target.value),
744
1012
  autoFocus: !0
745
1013
  }),
746
- /* @__PURE__ */ c(N, {
747
- label: "Conferma password",
748
- value: a,
749
- onChange: (e) => s(e.target.value)
1014
+ /* @__PURE__ */ c(K, {
1015
+ label: r("setPassword.confirmPassword"),
1016
+ value: s,
1017
+ onChange: (e) => u(e.target.value)
750
1018
  }),
751
- u && /* @__PURE__ */ c("p", {
1019
+ f && /* @__PURE__ */ c("p", {
752
1020
  className: "set-password-modal-error",
753
- children: u
1021
+ children: f
754
1022
  }),
755
- /* @__PURE__ */ c(f, {
756
- label: "Salva password",
1023
+ /* @__PURE__ */ c(h, {
1024
+ label: r("setPassword.submit"),
757
1025
  type: "submit",
758
1026
  style: { width: "100%" }
759
1027
  })
760
1028
  ]
761
1029
  })
762
1030
  });
763
- }, V = ({ value: e, onChange: t, swatches: r }) => {
1031
+ }, Q = ({ value: e, onChange: t, swatches: r }) => {
764
1032
  let [i, s] = o(!1), u = a(null);
765
1033
  return n(() => {
766
1034
  if (!i) return;
@@ -809,7 +1077,7 @@ var B = ({ open: e, onClose: t, onSubmit: n }) => {
809
1077
  })]
810
1078
  })]
811
1079
  });
812
- }, H = (e) => e.split(",")[0].replace(/'/g, ""), U = ({ value: e, onChange: t, options: r }) => {
1080
+ }, $ = (e) => e.split(",")[0].replace(/'/g, ""), ce = ({ value: e, onChange: t, options: r }) => {
813
1081
  let [i, s] = o(!1), u = a(null);
814
1082
  return n(() => {
815
1083
  if (!i) return;
@@ -831,7 +1099,7 @@ var B = ({ open: e, onClose: t, onSubmit: n }) => {
831
1099
  style: { fontFamily: e },
832
1100
  children: [/* @__PURE__ */ c("span", {
833
1101
  className: "sg-font-picker-toggle-label",
834
- children: H(e)
1102
+ children: $(e)
835
1103
  }), /* @__PURE__ */ c("span", {
836
1104
  className: "sg-font-picker-toggle-caret",
837
1105
  children: i ? "▲" : "▼"
@@ -845,11 +1113,11 @@ var B = ({ open: e, onClose: t, onSubmit: n }) => {
845
1113
  t(n), s(!1);
846
1114
  },
847
1115
  style: { fontFamily: n },
848
- children: H(n)
1116
+ children: $(n)
849
1117
  }) }, n))
850
1118
  })]
851
1119
  });
852
- }, W = ({ checked: e, onChange: t, label: n }) => /* @__PURE__ */ l("label", {
1120
+ }, le = ({ checked: e, onChange: t, label: n }) => /* @__PURE__ */ l("label", {
853
1121
  className: "sg-toggle",
854
1122
  children: [
855
1123
  /* @__PURE__ */ c("input", {
@@ -867,6 +1135,18 @@ var B = ({ open: e, onClose: t, onSubmit: n }) => {
867
1135
  children: n
868
1136
  })
869
1137
  ]
870
- });
1138
+ }), ue = ({ className: e }) => {
1139
+ let { t, i18n: n } = d("sg", { i18n: L });
1140
+ return /* @__PURE__ */ c("select", {
1141
+ className: ["sg-language-switcher", e].filter(Boolean).join(" "),
1142
+ value: n.resolvedLanguage,
1143
+ onChange: (e) => n.changeLanguage(e.target.value),
1144
+ "aria-label": t("languageSwitcher.label"),
1145
+ children: j.map((e) => /* @__PURE__ */ c("option", {
1146
+ value: e,
1147
+ children: M[e]
1148
+ }, e))
1149
+ });
1150
+ };
871
1151
  //#endregion
872
- export { E as AppAccessGate, O as AppLauncher, k as Authenticator, f as Button, V as ColorPicker, v as CookieConsent, D as DEFAULT_APPS_URL, C as DEFAULT_HEIMDALL_URL, U as FontPicker, p as Footer, x as Header, d as Icon, M as Input, j as Modal, N as PasswordInput, z as QuadratoHeader, b as SGFooter, S as SGHeader, B as SetPasswordModal, W as Toggle };
1152
+ export { Y as AVATAR_CHANGE_EVENT, B as AppAccessGate, H as AppLauncher, U as Authenticator, h as Button, Q as ColorPicker, x as CookieConsent, V as DEFAULT_APPS_URL, R as DEFAULT_HEIMDALL_URL, ce as FontPicker, g as Footer, w as Header, m as Icon, G as Input, N as LANGUAGE_COOKIE, M as LANGUAGE_NAMES, ue as LanguageSwitcher, W as Modal, K as PasswordInput, Z as QuadratoHeader, C as SGFooter, T as SGHeader, j as SUPPORTED_LANGUAGES, se as SetPasswordModal, le as Toggle, ne as createI18n, F as readLanguageCookie, L as sgI18n };
@@ -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)}}.sg-access-gate{z-index:998;box-sizing:border-box;background:var(--primary-bg);font-family:var(--font-family);justify-content:center;align-items:center;padding:16px;display:flex;position:fixed;inset:0}.sg-access-gate-card{border:1px solid var(--primary-border);border-radius:calc(var(--radius) * 3);background:var(--modal-bg);max-width:420px;box-shadow:var(--shadow-2);text-align:center;padding:24px}.sg-access-gate-card h2{font-size:var(--font-size-h1);color:var(--modal-title-color);margin:0 0 12px}.sg-access-gate-card p{color:var(--ink-muted);margin:0 0 16px}.sg-access-gate-card .sg-access-gate-error{color:#c0392b}.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}.sg-app-launcher-tile{position:relative}.sg-app-launcher-app.locked .sg-app-launcher-tile{background:var(--ink-muted)}.sg-app-launcher-app.locked .sg-app-launcher-name{color:var(--ink-muted)}.sg-app-launcher-lock{border:2px solid var(--modal-bg);background:var(--modal-title-color);width:20px;height:20px;color:var(--modal-bg);border-radius:50%;justify-content:center;align-items:center;display:flex;position:absolute;bottom:-6px;right:-6px}.sg-visually-hidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.sg-authenticator-button{font-size:.9rem;font-family:var(--font-family);border:1px solid var(--primary-border);border-radius:var(--radius);background:var(--primary-bg);color:#333;cursor:pointer;padding:.4rem 1rem;transition:background .15s,border-color .15s}.sg-authenticator-button:hover{background:var(--primary-hover-bg);border-color:var(--ink-muted)}.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;transition:color .2s}.quadrato-header-username:hover{color:var(--accent)}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:var(--sg-text-secondary);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:var(--sg-link);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:var(--sg-text-secondary);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:var(--sg-link);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{background-color:var(--sg-surface);width:100%;color:var(--sg-text);border-bottom:1px solid var(--sg-border-subtle);box-shadow:var(--sg-shadow-1);z-index:100;font-size:var(--font-size);position:sticky;top:0}.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:var(--sg-text);font-size:24px;font-weight:700;transition:color .2s}.logo:hover{color:var(--accent)}.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-access-gate{z-index:998;box-sizing:border-box;background:var(--primary-bg);font-family:var(--font-family);justify-content:center;align-items:center;padding:16px;display:flex;position:fixed;inset:0}.sg-access-gate-card{border:1px solid var(--primary-border);border-radius:calc(var(--radius) * 3);background:var(--modal-bg);max-width:420px;box-shadow:var(--shadow-2);color:var(--sg-text);text-align:center;padding:24px}.sg-access-gate-card h2{font-size:var(--font-size-h1);color:var(--modal-title-color);margin:0 0 12px}.sg-access-gate-card p{color:var(--ink-muted);margin:0 0 16px}.sg-access-gate-card .sg-access-gate-error{color:var(--sg-danger)}.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;color:var(--sg-text);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);width:40px;height:40px;color:var(--sg-on-accent);justify-content:center;align-items:center;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}.sg-app-launcher-tile{position:relative}.sg-app-launcher-app.locked .sg-app-launcher-tile{background:var(--ink-muted)}.sg-app-launcher-app.locked .sg-app-launcher-name{color:var(--ink-muted)}.sg-app-launcher-lock{border:2px solid var(--modal-bg);background:var(--modal-title-color);width:20px;height:20px;color:var(--modal-bg);border-radius:50%;justify-content:center;align-items:center;display:flex;position:absolute;bottom:-6px;right:-6px}.sg-visually-hidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.sg-authenticator-button{font-size:.9rem;font-family:var(--font-family);border:1px solid var(--primary-border);border-radius:var(--radius);background:var(--primary-bg);color:var(--sg-text);cursor:pointer;padding:.4rem 1rem;transition:background .15s,border-color .15s}.sg-authenticator-button:hover{background:var(--primary-hover-bg);border-color:var(--ink-muted)}.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;color:var(--sg-text);box-shadow:var(--sg-shadow-3);transform:translate(var(--drag-x), var(--drag-y));flex-direction:column;animation:.3s ease-out sg-modal-slide-in;display:flex;overflow:hidden}.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:var(--sg-danger-soft);border-color:var(--sg-danger)}.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);border-style:solid;border-width:1px;border-color:var(--input-border);background-color:var(--input-bg);width:100%;color:var(--sg-text);font-size:var(--primary-font);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-avatar{object-fit:cover;width:32px;height:32px;box-shadow:var(--sg-shadow-1);border-radius:50%}.quadrato-header-username{font-size:var(--font-size);color:var(--sg-text);transition:color .2s}.quadrato-header-username:hover{color:var(--accent)}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:var(--sg-danger);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 var(--sg-border-subtle);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{border:1px solid var(--sg-border-subtle);cursor:pointer;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)}.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}:root{--sg-color-white:#fff;--sg-color-black:#000;--sg-color-gray-50:#f5f5f5;--sg-color-gray-100:#e1e5e9;--sg-color-gray-150:#e0e0e0;--sg-color-gray-200:#e6e6e6;--sg-color-gray-300:#ccc;--sg-color-gray-350:#bdbdbd;--sg-color-gray-400:#9aa3b5;--sg-color-gray-500:#647089;--sg-color-gray-600:#555;--sg-color-gray-650:#444;--sg-color-gray-700:#333;--sg-color-gray-750:#2a2a2a;--sg-color-gray-800:#222;--sg-color-gray-900:#1a1a1a;--sg-color-blue-50:#e2e7f8;--sg-color-blue-300:#86aefc;--sg-color-blue-400:#6f9cf7;--sg-color-blue-500:#5480e6;--sg-color-blue-600:#3d5fc4;--sg-color-blue-700:#2e4aa0;--sg-color-sky-500:#1ea7fd;--sg-color-red-50:#ffe5e5;--sg-color-red-400:#e57373;--sg-color-red-600:#c0392b;--sg-bg:var(--sg-color-white);--sg-surface:var(--sg-color-white);--sg-surface-muted:var(--sg-color-gray-50);--sg-surface-hover:var(--sg-color-gray-150);--sg-border:var(--sg-color-gray-300);--sg-border-subtle:var(--sg-color-gray-100);--sg-text:var(--sg-color-gray-700);--sg-text-heading:var(--sg-color-gray-800);--sg-text-secondary:var(--sg-color-gray-600);--sg-text-muted:var(--sg-color-gray-500);--sg-accent:var(--sg-color-blue-600);--sg-accent-strong:var(--sg-color-blue-700);--sg-accent-soft:var(--sg-color-blue-50);--sg-on-accent:var(--sg-color-white);--sg-action:var(--sg-color-blue-400);--sg-action-hover:var(--sg-color-blue-500);--sg-link:var(--sg-color-sky-500);--sg-danger:var(--sg-color-red-600);--sg-danger-soft:var(--sg-color-red-50);--sg-overlay:#0000004d;--sg-shadow-1:0 1px 2px #0f172a14, 0 1px 3px #0f172a0f;--sg-shadow-2:0 4px 12px #0f172a1f;--sg-shadow-3:0 2px 16px #00000026;--sg-action-shadow:0 1px 2px #5480e61f, 0 1px 3px #5480e61a;--unit:3px;--radius:calc(var(--unit) * 2);--font-size:14px;--font-family:Arial, sans-serif;--font-size-h1:calc(var(--font-size) * 1.5);--primary-bg:var(--sg-surface-muted);--primary-border:var(--sg-border);--primary-radius:var(--radius);--primary-font:var(--font-size);--primary-hover-bg:var(--sg-surface-hover);--modal-bg:var(--sg-surface);--modal-overlay:var(--sg-overlay);--modal-title-color:var(--sg-text-heading);--input-bg:var(--sg-surface);--input-border:var(--sg-border);--input-radius:var(--radius);--input-font:1rem;--button-bg:var(--sg-action);--button-bg-hover:var(--sg-action-hover);--button-color:var(--sg-on-accent);--button-radius:999px;--button-shadow:var(--sg-action-shadow);--button-ease-standard:cubic-bezier(.4, 0, .2, 1);--button-ease-bounce:cubic-bezier(.34, 1.56, .64, 1);--accent:var(--sg-accent);--accent-strong:var(--sg-accent-strong);--accent-soft:var(--sg-accent-soft);--ink-muted:var(--sg-text-muted);--shadow-1:var(--sg-shadow-1);--shadow-2:var(--sg-shadow-2)}:root[data-theme=dark]{--sg-bg:var(--sg-color-gray-900);--sg-surface:var(--sg-color-gray-800);--sg-surface-muted:var(--sg-color-gray-750);--sg-surface-hover:var(--sg-color-gray-700);--sg-border:var(--sg-color-gray-600);--sg-border-subtle:var(--sg-color-gray-650);--sg-text:var(--sg-color-gray-200);--sg-text-heading:var(--sg-color-white);--sg-text-secondary:var(--sg-color-gray-350);--sg-text-muted:var(--sg-color-gray-400);--sg-accent:var(--sg-color-blue-400);--sg-accent-strong:var(--sg-color-blue-300);--sg-accent-soft:#6f9cf72e;--sg-action-hover:var(--sg-color-blue-300);--sg-link:var(--sg-color-blue-300);--sg-danger:var(--sg-color-red-400);--sg-danger-soft:#e5737326;--sg-overlay:#0009;--sg-shadow-1:0 1px 2px #0000004d, 0 1px 3px #0000003d;--sg-shadow-2:0 4px 12px #0006;--sg-shadow-3:0 2px 16px #00000080}.sg-language-switcher{border:1px solid var(--input-border);border-radius:var(--input-radius);background:var(--input-bg);color:var(--sg-text);font-family:var(--font-family);font-size:var(--primary-font);cursor:pointer;padding:4px 8px}
2
2
  /*$vite$:1*/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sensorario/sg-components",
3
- "version": "0.0.103",
3
+ "version": "0.0.104",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "scripts": {
@@ -25,12 +25,21 @@
25
25
  "types": "./dist/index.d.ts",
26
26
  "import": "./dist/index.es.js",
27
27
  "style": "./dist/sg-components.css"
28
- }
28
+ },
29
+ "./style.css": "./dist/sg-components.css",
30
+ "./dist/sg-components.css": "./dist/sg-components.css"
29
31
  },
32
+ "sideEffects": [
33
+ "*.css"
34
+ ],
30
35
  "dependencies": {
31
36
  "react": "^19.2.6",
32
37
  "react-dom": "^19.2.6"
33
38
  },
39
+ "peerDependencies": {
40
+ "i18next": ">=26",
41
+ "react-i18next": ">=17"
42
+ },
34
43
  "devDependencies": {
35
44
  "@chromatic-com/storybook": "^5.3.0",
36
45
  "@eslint/js": "^10.0.1",
@@ -54,7 +63,9 @@
54
63
  "eslint-plugin-react-refresh": "^0.5.2",
55
64
  "eslint-plugin-storybook": "^10.5.10",
56
65
  "globals": "^17.6.0",
66
+ "i18next": "^26.4.2",
57
67
  "playwright": "^1.60.0",
68
+ "react-i18next": "^17.0.15",
58
69
  "rollup": "^4.60.4",
59
70
  "rollup-plugin-dts": "^6.4.1",
60
71
  "rollup-plugin-peer-deps-external": "^2.2.4",