@burdenoff/microfe-technospam 2026.828.1 → 2026.830.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/index.js +4 -3
  2. package/dist/technospam/TechnoSpamRoot.js +4 -4
  3. package/dist/technospam/components/PageLayout.d.ts.map +1 -1
  4. package/dist/technospam/components/PageLayout.js +24 -23
  5. package/dist/technospam/components/PageLayout.js.map +1 -1
  6. package/dist/technospam/components/StateViews.d.ts +1 -1
  7. package/dist/technospam/components/StateViews.d.ts.map +1 -1
  8. package/dist/technospam/components/StateViews.js +28 -26
  9. package/dist/technospam/components/StateViews.js.map +1 -1
  10. package/dist/technospam/components/TagInput.d.ts +1 -1
  11. package/dist/technospam/components/TagInput.d.ts.map +1 -1
  12. package/dist/technospam/components/TagInput.js +39 -34
  13. package/dist/technospam/components/TagInput.js.map +1 -1
  14. package/dist/technospam/hooks/useTr.d.ts +17 -0
  15. package/dist/technospam/hooks/useTr.d.ts.map +1 -0
  16. package/dist/technospam/hooks/useTr.js +12 -0
  17. package/dist/technospam/hooks/useTr.js.map +1 -0
  18. package/dist/technospam/index.d.ts +1 -0
  19. package/dist/technospam/index.d.ts.map +1 -1
  20. package/dist/technospam/index.js +1 -0
  21. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.d.ts.map +1 -1
  22. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js +198 -189
  23. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  24. package/dist/technospam/pages/ApplicationsProblemsPagePage.d.ts.map +1 -1
  25. package/dist/technospam/pages/ApplicationsProblemsPagePage.js +165 -163
  26. package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
  27. package/dist/technospam/pages/CoursesCoursesPagePage.d.ts.map +1 -1
  28. package/dist/technospam/pages/CoursesCoursesPagePage.js +117 -113
  29. package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
  30. package/dist/technospam/pages/DashboardDashboardPagePage.d.ts.map +1 -1
  31. package/dist/technospam/pages/DashboardDashboardPagePage.js +211 -193
  32. package/dist/technospam/pages/DashboardDashboardPagePage.js.map +1 -1
  33. package/dist/technospam/pages/HackathonsHackathonsPagePage.d.ts.map +1 -1
  34. package/dist/technospam/pages/HackathonsHackathonsPagePage.js +110 -110
  35. package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
  36. package/dist/technospam/pages/MentorshipMentorsPagePage.d.ts.map +1 -1
  37. package/dist/technospam/pages/MentorshipMentorsPagePage.js +174 -160
  38. package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
  39. package/dist/technospam/pages/MentorshipSessionsPagePage.d.ts.map +1 -1
  40. package/dist/technospam/pages/MentorshipSessionsPagePage.js +156 -151
  41. package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
  42. package/dist/technospam/utils/i18n.js +1 -1
  43. package/dist/technospam/utils/i18n.js.map +1 -1
  44. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { useTechnoSpam as e, useTechnoSpamNavigate as t } from "./technospam/providers/TechnoSpamProvider.js";
2
2
  import { useTechnoSpamAnalytics as n } from "./technospam/hooks/useTechnoSpamAnalytics.js";
3
- import { TechnoSpamRoot as r } from "./technospam/TechnoSpamRoot.js";
4
- import { useSandboxAssistantTransport as i } from "./technospam/services/createSandboxAssistantTransport.js";
3
+ import { useTr as r } from "./technospam/hooks/useTr.js";
4
+ import { TechnoSpamRoot as i } from "./technospam/TechnoSpamRoot.js";
5
+ import { useSandboxAssistantTransport as a } from "./technospam/services/createSandboxAssistantTransport.js";
5
6
  import "./technospam/index.js";
6
- export { r as TechnoSpamRoot, i as useSandboxAssistantTransport, e as useTechnoSpam, n as useTechnoSpamAnalytics, t as useTechnoSpamNavigate };
7
+ export { i as TechnoSpamRoot, a as useSandboxAssistantTransport, e as useTechnoSpam, n as useTechnoSpamAnalytics, t as useTechnoSpamNavigate, r as useTr };
@@ -1,6 +1,6 @@
1
1
  import { TechnoSpamProvider as e } from "./providers/TechnoSpamProvider.js";
2
- import { TechnoSpamRoutes as t } from "./TechnoSpamRoutes.js";
3
- import { tWithFallback as n } from "./utils/i18n.js";
2
+ import { tWithFallback as t } from "./utils/i18n.js";
3
+ import { TechnoSpamRoutes as n } from "./TechnoSpamRoutes.js";
4
4
  import { joinPath as r } from "./utils/navigation.js";
5
5
  import { useEffect as i } from "react";
6
6
  import { useI18n as a } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
@@ -9,7 +9,7 @@ import { jsx as P } from "react/jsx-runtime";
9
9
  import { FeatureFlagProvider as F } from "@burdenoff/fe-libs/shared/feature-flags";
10
10
  //#region src/technospam/TechnoSpamRoot.tsx
11
11
  var I = (I) => {
12
- let { registerNavItems: L, registerFooterItems: R, basePath: z = "/" } = I, { t: B } = a(), V = (e, t) => n(B, e, t);
12
+ let { registerNavItems: L, registerFooterItems: R, basePath: z = "/" } = I, { t: B } = a(), V = (e, n) => t(B, e, n);
13
13
  return i(() => {
14
14
  if (L) return L({
15
15
  id: "technospam",
@@ -374,7 +374,7 @@ var I = (I) => {
374
374
  defaultEnabled: !0,
375
375
  children: /* @__PURE__ */ P(e, {
376
376
  ...I,
377
- children: /* @__PURE__ */ P(t, {})
377
+ children: /* @__PURE__ */ P(n, {})
378
378
  })
379
379
  });
380
380
  };
@@ -1 +1 @@
1
- {"version":3,"file":"PageLayout.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/PageLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,UAAU,eAAe;IACvB,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,WAAW,EACX,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,IAAY,GACb,EAAE,eAAe,+BAuCjB"}
1
+ {"version":3,"file":"PageLayout.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/PageLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAQvC,UAAU,eAAe;IACvB,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,WAAW,EACX,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,IAAY,GACb,EAAE,eAAe,+BAwCjB"}
@@ -1,51 +1,52 @@
1
1
  import { useTechnoSpamNavigate as e } from "../providers/TechnoSpamProvider.js";
2
2
  import { useNativeControls as t } from "../hooks/useNativeControls.js";
3
- import { cn as n } from "../utils/cn.js";
4
- import { ArrowLeft as r } from "lucide-react";
5
- import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
- import { AuroraBackground as o } from "@burdenoff/fe-libs/ui";
3
+ import { useTr as n } from "../hooks/useTr.js";
4
+ import { cn as r } from "../utils/cn.js";
5
+ import { ArrowLeft as i } from "lucide-react";
6
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
7
+ import { AuroraBackground as s } from "@burdenoff/fe-libs/ui";
7
8
  //#region src/technospam/components/PageLayout.tsx
8
- function s({ title: s, description: c, actions: l, children: u, backPath: d, hero: f = !1 }) {
9
- let p = e(), { impact: m } = t();
10
- return /* @__PURE__ */ a("div", {
9
+ function c({ title: c, description: l, actions: u, children: d, backPath: f, hero: p = !1 }) {
10
+ let m = e(), { impact: h } = t(), g = n();
11
+ return /* @__PURE__ */ o("div", {
11
12
  className: "flex h-full flex-col bg-bg-surface",
12
- children: [/* @__PURE__ */ a("div", {
13
- className: n("relative flex flex-col gap-4 overflow-hidden border-b border-border-seam px-6 py-5 sm:flex-row sm:items-start sm:justify-between", f ? "bg-accent-primary/12" : "bg-bg-surface"),
13
+ children: [/* @__PURE__ */ o("div", {
14
+ className: r("relative flex flex-col gap-4 overflow-hidden border-b border-border-seam px-6 py-5 sm:flex-row sm:items-start sm:justify-between", p ? "bg-accent-primary/12" : "bg-bg-surface"),
14
15
  children: [
15
- f ? /* @__PURE__ */ i(o, { intensity: "subtle" }) : null,
16
- /* @__PURE__ */ a("div", {
16
+ p ? /* @__PURE__ */ a(s, { intensity: "subtle" }) : null,
17
+ /* @__PURE__ */ o("div", {
17
18
  className: "relative flex min-w-0 flex-col gap-1",
18
19
  children: [
19
- d ? /* @__PURE__ */ a("button", {
20
+ f ? /* @__PURE__ */ o("button", {
20
21
  type: "button",
21
22
  onClick: () => {
22
- m("light"), p(d);
23
+ h("light"), m(f);
23
24
  },
24
25
  className: "flex w-fit items-center gap-1 text-sm text-text-secondary transition-colors hover:text-text-primary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]",
25
- children: [/* @__PURE__ */ i(r, { size: 15 }), "Back"]
26
+ children: [/* @__PURE__ */ a(i, { size: 15 }), g("technospam.common.back", "Back")]
26
27
  }) : null,
27
- /* @__PURE__ */ i("h1", {
28
+ /* @__PURE__ */ a("h1", {
28
29
  className: "truncate text-xl font-semibold text-text-primary sm:text-2xl",
29
- children: s
30
+ children: c
30
31
  }),
31
- c ? /* @__PURE__ */ i("p", {
32
+ l ? /* @__PURE__ */ a("p", {
32
33
  className: "max-w-2xl text-sm text-text-secondary",
33
- children: c
34
+ children: l
34
35
  }) : null
35
36
  ]
36
37
  }),
37
- l ? /* @__PURE__ */ i("div", {
38
+ u ? /* @__PURE__ */ a("div", {
38
39
  className: "relative flex flex-wrap items-center gap-2",
39
- children: l
40
+ children: u
40
41
  }) : null
41
42
  ]
42
- }), /* @__PURE__ */ i("div", {
43
+ }), /* @__PURE__ */ a("div", {
43
44
  className: "flex-1 overflow-y-auto p-6",
44
- children: u
45
+ children: d
45
46
  })]
46
47
  });
47
48
  }
48
49
  //#endregion
49
- export { s as PageLayout };
50
+ export { c as PageLayout };
50
51
 
51
52
  //# sourceMappingURL=PageLayout.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PageLayout.js","names":[],"sources":["../../../src/technospam/components/PageLayout.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { ArrowLeft } from 'lucide-react';\nimport { AuroraBackground } from '@burdenoff/fe-libs/ui';\nimport { useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport { useNativeControls } from '../hooks/useNativeControls';\nimport { cn } from '../utils/cn';\n\ninterface PageLayoutProps {\n title: ReactNode;\n description?: ReactNode;\n actions?: ReactNode;\n children: ReactNode;\n backPath?: string;\n /** Render the page header with the living-glass aurora backdrop (module hero). */\n hero?: boolean;\n}\n\n/**\n * Consistent page chrome for every TechnoSpam module page: a header band\n * (optionally with the aurora hero backdrop), an optional back affordance, an\n * actions slot, and a scrollable body. Mirrors the platform page pattern so\n * TechnoSpam feels native to the shell.\n */\nexport function PageLayout({\n title,\n description,\n actions,\n children,\n backPath,\n hero = false,\n}: PageLayoutProps) {\n const navigate = useTechnoSpamNavigate();\n const { impact } = useNativeControls();\n\n return (\n <div className=\"flex h-full flex-col bg-bg-surface\">\n <div\n className={cn(\n 'relative flex flex-col gap-4 overflow-hidden border-b border-border-seam px-6 py-5 sm:flex-row sm:items-start sm:justify-between',\n hero ? 'bg-accent-primary/12' : 'bg-bg-surface'\n )}\n >\n {hero ? <AuroraBackground intensity=\"subtle\" /> : null}\n <div className=\"relative flex min-w-0 flex-col gap-1\">\n {backPath ? (\n <button\n type=\"button\"\n onClick={() => {\n void impact('light');\n navigate(backPath);\n }}\n className=\"flex w-fit items-center gap-1 text-sm text-text-secondary transition-colors hover:text-text-primary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <ArrowLeft size={15} />\n Back\n </button>\n ) : null}\n <h1 className=\"truncate text-xl font-semibold text-text-primary sm:text-2xl\">{title}</h1>\n {description ? (\n <p className=\"max-w-2xl text-sm text-text-secondary\">{description}</p>\n ) : null}\n </div>\n {actions ? (\n <div className=\"relative flex flex-wrap items-center gap-2\">{actions}</div>\n ) : null}\n </div>\n <div className=\"flex-1 overflow-y-auto p-6\">{children}</div>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAuBA,SAAgB,EAAW,EACzB,UACA,gBACA,YACA,aACA,aACA,UAAO,MACW;CAClB,IAAM,IAAW,GAAuB,EAClC,EAAE,cAAW,GAAmB;AAEtC,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GACE,WAAW,EACT,oIACA,IAAO,yBAAyB,gBACjC;aAJH;IAMG,IAAO,kBAAC,GAAD,EAAkB,WAAU,UAAW,CAAA,GAAG;IAClD,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,IACC,kBAAC,UAAD;OACE,MAAK;OACL,eAAe;AAEb,QADK,EAAO,QAAQ,EACpB,EAAS,EAAS;;OAEpB,WAAU;iBANZ,CAQE,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA,EAAA,OAEhB;WACP;MACJ,kBAAC,MAAD;OAAI,WAAU;iBAAgE;OAAW,CAAA;MACxF,IACC,kBAAC,KAAD;OAAG,WAAU;iBAAyC;OAAgB,CAAA,GACpE;MACA;;IACL,IACC,kBAAC,OAAD;KAAK,WAAU;eAA8C;KAAc,CAAA,GACzE;IACA;MACN,kBAAC,OAAD;GAAK,WAAU;GAA8B;GAAe,CAAA,CACxD"}
1
+ {"version":3,"file":"PageLayout.js","names":[],"sources":["../../../src/technospam/components/PageLayout.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { ArrowLeft } from 'lucide-react';\nimport { AuroraBackground } from '@burdenoff/fe-libs/ui';\nimport { useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport { useNativeControls } from '../hooks/useNativeControls';\nimport { useTr } from '../hooks/useTr';\nimport { cn } from '../utils/cn';\n\ninterface PageLayoutProps {\n title: ReactNode;\n description?: ReactNode;\n actions?: ReactNode;\n children: ReactNode;\n backPath?: string;\n /** Render the page header with the living-glass aurora backdrop (module hero). */\n hero?: boolean;\n}\n\n/**\n * Consistent page chrome for every TechnoSpam module page: a header band\n * (optionally with the aurora hero backdrop), an optional back affordance, an\n * actions slot, and a scrollable body. Mirrors the platform page pattern so\n * TechnoSpam feels native to the shell.\n */\nexport function PageLayout({\n title,\n description,\n actions,\n children,\n backPath,\n hero = false,\n}: PageLayoutProps) {\n const navigate = useTechnoSpamNavigate();\n const { impact } = useNativeControls();\n const tr = useTr();\n\n return (\n <div className=\"flex h-full flex-col bg-bg-surface\">\n <div\n className={cn(\n 'relative flex flex-col gap-4 overflow-hidden border-b border-border-seam px-6 py-5 sm:flex-row sm:items-start sm:justify-between',\n hero ? 'bg-accent-primary/12' : 'bg-bg-surface'\n )}\n >\n {hero ? <AuroraBackground intensity=\"subtle\" /> : null}\n <div className=\"relative flex min-w-0 flex-col gap-1\">\n {backPath ? (\n <button\n type=\"button\"\n onClick={() => {\n void impact('light');\n navigate(backPath);\n }}\n className=\"flex w-fit items-center gap-1 text-sm text-text-secondary transition-colors hover:text-text-primary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <ArrowLeft size={15} />\n {tr('technospam.common.back', 'Back')}\n </button>\n ) : null}\n <h1 className=\"truncate text-xl font-semibold text-text-primary sm:text-2xl\">{title}</h1>\n {description ? (\n <p className=\"max-w-2xl text-sm text-text-secondary\">{description}</p>\n ) : null}\n </div>\n {actions ? (\n <div className=\"relative flex flex-wrap items-center gap-2\">{actions}</div>\n ) : null}\n </div>\n <div className=\"flex-1 overflow-y-auto p-6\">{children}</div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAwBA,SAAgB,EAAW,EACzB,UACA,gBACA,YACA,aACA,aACA,UAAO,MACW;CAClB,IAAM,IAAW,GAAuB,EAClC,EAAE,cAAW,GAAmB,EAChC,IAAK,GAAO;AAElB,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GACE,WAAW,EACT,oIACA,IAAO,yBAAyB,gBACjC;aAJH;IAMG,IAAO,kBAAC,GAAD,EAAkB,WAAU,UAAW,CAAA,GAAG;IAClD,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,IACC,kBAAC,UAAD;OACE,MAAK;OACL,eAAe;AAEb,QADK,EAAO,QAAQ,EACpB,EAAS,EAAS;;OAEpB,WAAU;iBANZ,CAQE,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA,EACtB,EAAG,0BAA0B,OAAO,CAC9B;WACP;MACJ,kBAAC,MAAD;OAAI,WAAU;iBAAgE;OAAW,CAAA;MACxF,IACC,kBAAC,KAAD;OAAG,WAAU;iBAAyC;OAAgB,CAAA,GACpE;MACA;;IACL,IACC,kBAAC,OAAD;KAAK,WAAU;eAA8C;KAAc,CAAA,GACzE;IACA;MACN,kBAAC,OAAD;GAAK,WAAU;GAA8B;GAAe,CAAA,CACxD"}
@@ -11,7 +11,7 @@ export declare function EmptyView({ title, description, action, icon, }: {
11
11
  icon?: ReactNode;
12
12
  }): import("react").JSX.Element;
13
13
  /** Consistent error state, surfaced from a GraphQL/network error. */
14
- export declare function ErrorView({ title, error, }: {
14
+ export declare function ErrorView({ title, error }: {
15
15
  title?: string;
16
16
  error?: {
17
17
  message?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"StateViews.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/StateViews.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,WAAW,EACX,MAAM,EACN,IAAI,GACL,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB,+BAWA;AAED,qEAAqE;AACrE,wBAAgB,SAAS,CAAC,EACxB,KAAgC,EAChC,KAAK,GACN,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9B,+BAYA;AAED,oCAAoC;AACpC,wBAAgB,WAAW,CAAC,EAAE,KAAS,EAAE,MAAe,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,+BAQ9F;AAED,uCAAuC;AACvC,wBAAgB,WAAW,CAAC,EAAE,KAAS,EAAE,MAAe,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,+BAQ9F"}
1
+ {"version":3,"file":"StateViews.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/StateViews.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,WAAW,EACX,MAAM,EACN,IAAI,GACL,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB,+BAWA;AAED,qEAAqE;AACrE,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,+BAe3F;AAED,oCAAoC;AACpC,wBAAgB,WAAW,CAAC,EAAE,KAAS,EAAE,MAAe,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,+BAQ9F;AAED,uCAAuC;AACvC,wBAAgB,WAAW,CAAC,EAAE,KAAS,EAAE,MAAe,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,+BAQ9F"}
@@ -1,62 +1,64 @@
1
- import { AlertTriangle as e, Inbox as t } from "lucide-react";
2
- import { jsx as n, jsxs as r } from "react/jsx-runtime";
3
- import { Skeleton as i } from "@burdenoff/fe-libs/ui";
1
+ import { useTr as e } from "../hooks/useTr.js";
2
+ import { AlertTriangle as t, Inbox as n } from "lucide-react";
3
+ import { jsx as r, jsxs as i } from "react/jsx-runtime";
4
+ import { Skeleton as a } from "@burdenoff/fe-libs/ui";
4
5
  //#region src/technospam/components/StateViews.tsx
5
- function a({ title: e, description: i, action: a, icon: o }) {
6
- return /* @__PURE__ */ r("div", {
6
+ function o({ title: e, description: t, action: a, icon: o }) {
7
+ return /* @__PURE__ */ i("div", {
7
8
  className: "flex flex-col items-center justify-center gap-3 rounded-2xl border border-border-seam bg-bg-surface px-6 py-14 text-center",
8
9
  children: [
9
- /* @__PURE__ */ n("span", {
10
+ /* @__PURE__ */ r("span", {
10
11
  className: "flex h-14 w-14 items-center justify-center rounded-2xl bg-bg-sunken text-text-muted",
11
- children: o ?? /* @__PURE__ */ n(t, { size: 26 })
12
+ children: o ?? /* @__PURE__ */ r(n, { size: 26 })
12
13
  }),
13
- /* @__PURE__ */ n("h3", {
14
+ /* @__PURE__ */ r("h3", {
14
15
  className: "text-base font-semibold text-text-primary",
15
16
  children: e
16
17
  }),
17
- i ? /* @__PURE__ */ n("p", {
18
+ t ? /* @__PURE__ */ r("p", {
18
19
  className: "max-w-md text-sm text-text-secondary",
19
- children: i
20
+ children: t
20
21
  }) : null,
21
- a ? /* @__PURE__ */ n("div", {
22
+ a ? /* @__PURE__ */ r("div", {
22
23
  className: "mt-2",
23
24
  children: a
24
25
  }) : null
25
26
  ]
26
27
  });
27
28
  }
28
- function o({ title: t = "Couldn't load this yet", error: i }) {
29
- return /* @__PURE__ */ r("div", {
29
+ function s({ title: n, error: a }) {
30
+ let o = e();
31
+ return /* @__PURE__ */ i("div", {
30
32
  className: "flex flex-col items-center justify-center gap-3 rounded-2xl border border-border-seam bg-bg-surface px-6 py-14 text-center",
31
33
  children: [
32
- /* @__PURE__ */ n("span", {
34
+ /* @__PURE__ */ r("span", {
33
35
  className: "flex h-14 w-14 items-center justify-center rounded-2xl bg-status-error-bg-subtle text-status-error-text",
34
- children: /* @__PURE__ */ n(e, { size: 26 })
36
+ children: /* @__PURE__ */ r(t, { size: 26 })
35
37
  }),
36
- /* @__PURE__ */ n("h3", {
38
+ /* @__PURE__ */ r("h3", {
37
39
  className: "text-base font-semibold text-text-primary",
38
- children: t
40
+ children: n ?? o("technospam.common.errorTitle", "Couldn't load this yet")
39
41
  }),
40
- /* @__PURE__ */ n("p", {
42
+ /* @__PURE__ */ r("p", {
41
43
  className: "max-w-md text-sm text-text-secondary",
42
- children: i?.message ?? "Please try again in a moment."
44
+ children: a?.message ?? o("technospam.common.tryAgain", "Please try again in a moment.")
43
45
  })
44
46
  ]
45
47
  });
46
48
  }
47
- function s({ count: e = 6, height: t = "h-56" }) {
48
- return /* @__PURE__ */ n("div", {
49
+ function c({ count: e = 6, height: t = "h-56" }) {
50
+ return /* @__PURE__ */ r("div", {
49
51
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
50
- children: Array.from({ length: e }).map((e, r) => /* @__PURE__ */ n(i, { className: `${t} w-full rounded-xl` }, r))
52
+ children: Array.from({ length: e }).map((e, n) => /* @__PURE__ */ r(a, { className: `${t} w-full rounded-xl` }, n))
51
53
  });
52
54
  }
53
- function c({ count: e = 4, height: t = "h-20" }) {
54
- return /* @__PURE__ */ n("div", {
55
+ function l({ count: e = 4, height: t = "h-20" }) {
56
+ return /* @__PURE__ */ r("div", {
55
57
  className: "space-y-3",
56
- children: Array.from({ length: e }).map((e, r) => /* @__PURE__ */ n(i, { className: `${t} w-full rounded-xl` }, r))
58
+ children: Array.from({ length: e }).map((e, n) => /* @__PURE__ */ r(a, { className: `${t} w-full rounded-xl` }, n))
57
59
  });
58
60
  }
59
61
  //#endregion
60
- export { a as EmptyView, o as ErrorView, s as LoadingGrid, c as LoadingRows };
62
+ export { o as EmptyView, s as ErrorView, c as LoadingGrid, l as LoadingRows };
61
63
 
62
64
  //# sourceMappingURL=StateViews.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StateViews.js","names":[],"sources":["../../../src/technospam/components/StateViews.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { AlertTriangle, Inbox } from 'lucide-react';\nimport { Skeleton } from '@burdenoff/fe-libs/ui';\n\n/**\n * Self-contained empty state (does not depend on host-shell illustration assets).\n * A soft glass medallion + lucide icon, a title, an optional description and action.\n */\nexport function EmptyView({\n title,\n description,\n action,\n icon,\n}: {\n title: string;\n description?: string;\n action?: ReactNode;\n icon?: ReactNode;\n}) {\n return (\n <div className=\"flex flex-col items-center justify-center gap-3 rounded-2xl border border-border-seam bg-bg-surface px-6 py-14 text-center\">\n <span className=\"flex h-14 w-14 items-center justify-center rounded-2xl bg-bg-sunken text-text-muted\">\n {icon ?? <Inbox size={26} />}\n </span>\n <h3 className=\"text-base font-semibold text-text-primary\">{title}</h3>\n {description ? <p className=\"max-w-md text-sm text-text-secondary\">{description}</p> : null}\n {action ? <div className=\"mt-2\">{action}</div> : null}\n </div>\n );\n}\n\n/** Consistent error state, surfaced from a GraphQL/network error. */\nexport function ErrorView({\n title = \"Couldn't load this yet\",\n error,\n}: {\n title?: string;\n error?: { message?: string };\n}) {\n return (\n <div className=\"flex flex-col items-center justify-center gap-3 rounded-2xl border border-border-seam bg-bg-surface px-6 py-14 text-center\">\n <span className=\"flex h-14 w-14 items-center justify-center rounded-2xl bg-status-error-bg-subtle text-status-error-text\">\n <AlertTriangle size={26} />\n </span>\n <h3 className=\"text-base font-semibold text-text-primary\">{title}</h3>\n <p className=\"max-w-md text-sm text-text-secondary\">\n {error?.message ?? 'Please try again in a moment.'}\n </p>\n </div>\n );\n}\n\n/** Skeleton grid for card lists. */\nexport function LoadingGrid({ count = 6, height = 'h-56' }: { count?: number; height?: string }) {\n return (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {Array.from({ length: count }).map((_, i) => (\n <Skeleton key={i} className={`${height} w-full rounded-xl`} />\n ))}\n </div>\n );\n}\n\n/** Skeleton rows for stacked lists. */\nexport function LoadingRows({ count = 4, height = 'h-20' }: { count?: number; height?: string }) {\n return (\n <div className=\"space-y-3\">\n {Array.from({ length: count }).map((_, i) => (\n <Skeleton key={i} className={`${height} w-full rounded-xl`} />\n ))}\n </div>\n );\n}\n"],"mappings":";;;;AAQA,SAAgB,EAAU,EACxB,UACA,gBACA,WACA,WAMC;AACD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,QAAD;IAAM,WAAU;cACb,KAAQ,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACvB,CAAA;GACP,kBAAC,MAAD;IAAI,WAAU;cAA6C;IAAW,CAAA;GACrE,IAAc,kBAAC,KAAD;IAAG,WAAU;cAAwC;IAAgB,CAAA,GAAG;GACtF,IAAS,kBAAC,OAAD;IAAK,WAAU;cAAQ;IAAa,CAAA,GAAG;GAC7C;;;AAKV,SAAgB,EAAU,EACxB,WAAQ,0BACR,YAIC;AACD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,QAAD;IAAM,WAAU;cACd,kBAAC,GAAD,EAAe,MAAM,IAAM,CAAA;IACtB,CAAA;GACP,kBAAC,MAAD;IAAI,WAAU;cAA6C;IAAW,CAAA;GACtE,kBAAC,KAAD;IAAG,WAAU;cACV,GAAO,WAAW;IACjB,CAAA;GACA;;;AAKV,SAAgB,EAAY,EAAE,WAAQ,GAAG,YAAS,UAA+C;AAC/F,QACE,kBAAC,OAAD;EAAK,WAAU;YACZ,MAAM,KAAK,EAAE,QAAQ,GAAO,CAAC,CAAC,KAAK,GAAG,MACrC,kBAAC,GAAD,EAAkB,WAAW,GAAG,EAAO,qBAAuB,EAA/C,EAA+C,CAC9D;EACE,CAAA;;AAKV,SAAgB,EAAY,EAAE,WAAQ,GAAG,YAAS,UAA+C;AAC/F,QACE,kBAAC,OAAD;EAAK,WAAU;YACZ,MAAM,KAAK,EAAE,QAAQ,GAAO,CAAC,CAAC,KAAK,GAAG,MACrC,kBAAC,GAAD,EAAkB,WAAW,GAAG,EAAO,qBAAuB,EAA/C,EAA+C,CAC9D;EACE,CAAA"}
1
+ {"version":3,"file":"StateViews.js","names":[],"sources":["../../../src/technospam/components/StateViews.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { AlertTriangle, Inbox } from 'lucide-react';\nimport { Skeleton } from '@burdenoff/fe-libs/ui';\nimport { useTr } from '../hooks/useTr';\n\n/**\n * Self-contained empty state (does not depend on host-shell illustration assets).\n * A soft glass medallion + lucide icon, a title, an optional description and action.\n */\nexport function EmptyView({\n title,\n description,\n action,\n icon,\n}: {\n title: string;\n description?: string;\n action?: ReactNode;\n icon?: ReactNode;\n}) {\n return (\n <div className=\"flex flex-col items-center justify-center gap-3 rounded-2xl border border-border-seam bg-bg-surface px-6 py-14 text-center\">\n <span className=\"flex h-14 w-14 items-center justify-center rounded-2xl bg-bg-sunken text-text-muted\">\n {icon ?? <Inbox size={26} />}\n </span>\n <h3 className=\"text-base font-semibold text-text-primary\">{title}</h3>\n {description ? <p className=\"max-w-md text-sm text-text-secondary\">{description}</p> : null}\n {action ? <div className=\"mt-2\">{action}</div> : null}\n </div>\n );\n}\n\n/** Consistent error state, surfaced from a GraphQL/network error. */\nexport function ErrorView({ title, error }: { title?: string; error?: { message?: string } }) {\n const tr = useTr();\n return (\n <div className=\"flex flex-col items-center justify-center gap-3 rounded-2xl border border-border-seam bg-bg-surface px-6 py-14 text-center\">\n <span className=\"flex h-14 w-14 items-center justify-center rounded-2xl bg-status-error-bg-subtle text-status-error-text\">\n <AlertTriangle size={26} />\n </span>\n <h3 className=\"text-base font-semibold text-text-primary\">\n {title ?? tr('technospam.common.errorTitle', \"Couldn't load this yet\")}\n </h3>\n <p className=\"max-w-md text-sm text-text-secondary\">\n {error?.message ?? tr('technospam.common.tryAgain', 'Please try again in a moment.')}\n </p>\n </div>\n );\n}\n\n/** Skeleton grid for card lists. */\nexport function LoadingGrid({ count = 6, height = 'h-56' }: { count?: number; height?: string }) {\n return (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {Array.from({ length: count }).map((_, i) => (\n <Skeleton key={i} className={`${height} w-full rounded-xl`} />\n ))}\n </div>\n );\n}\n\n/** Skeleton rows for stacked lists. */\nexport function LoadingRows({ count = 4, height = 'h-20' }: { count?: number; height?: string }) {\n return (\n <div className=\"space-y-3\">\n {Array.from({ length: count }).map((_, i) => (\n <Skeleton key={i} className={`${height} w-full rounded-xl`} />\n ))}\n </div>\n );\n}\n"],"mappings":";;;;;AASA,SAAgB,EAAU,EACxB,UACA,gBACA,WACA,WAMC;AACD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,QAAD;IAAM,WAAU;cACb,KAAQ,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACvB,CAAA;GACP,kBAAC,MAAD;IAAI,WAAU;cAA6C;IAAW,CAAA;GACrE,IAAc,kBAAC,KAAD;IAAG,WAAU;cAAwC;IAAgB,CAAA,GAAG;GACtF,IAAS,kBAAC,OAAD;IAAK,WAAU;cAAQ;IAAa,CAAA,GAAG;GAC7C;;;AAKV,SAAgB,EAAU,EAAE,UAAO,YAA2D;CAC5F,IAAM,IAAK,GAAO;AAClB,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,QAAD;IAAM,WAAU;cACd,kBAAC,GAAD,EAAe,MAAM,IAAM,CAAA;IACtB,CAAA;GACP,kBAAC,MAAD;IAAI,WAAU;cACX,KAAS,EAAG,gCAAgC,yBAAyB;IACnE,CAAA;GACL,kBAAC,KAAD;IAAG,WAAU;cACV,GAAO,WAAW,EAAG,8BAA8B,gCAAgC;IAClF,CAAA;GACA;;;AAKV,SAAgB,EAAY,EAAE,WAAQ,GAAG,YAAS,UAA+C;AAC/F,QACE,kBAAC,OAAD;EAAK,WAAU;YACZ,MAAM,KAAK,EAAE,QAAQ,GAAO,CAAC,CAAC,KAAK,GAAG,MACrC,kBAAC,GAAD,EAAkB,WAAW,GAAG,EAAO,qBAAuB,EAA/C,EAA+C,CAC9D;EACE,CAAA;;AAKV,SAAgB,EAAY,EAAE,WAAQ,GAAG,YAAS,UAA+C;AAC/F,QACE,kBAAC,OAAD;EAAK,WAAU;YACZ,MAAM,KAAK,EAAE,QAAQ,GAAO,CAAC,CAAC,KAAK,GAAG,MACrC,kBAAC,GAAD,EAAkB,WAAW,GAAG,EAAO,qBAAuB,EAA/C,EAA+C,CAC9D;EACE,CAAA"}
@@ -13,6 +13,6 @@ interface TagInputProps {
13
13
  * arrays stored on Tec* entities while the workspace-wide @burdenoff/microfe-tags
14
14
  * taxonomy is being adopted product-wide.
15
15
  */
16
- export declare function TagInput({ value, onChange, placeholder, className, maxTags, }: TagInputProps): import("react").JSX.Element;
16
+ export declare function TagInput({ value, onChange, placeholder, className, maxTags }: TagInputProps): import("react").JSX.Element;
17
17
  export {};
18
18
  //# sourceMappingURL=TagInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TagInput.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/TagInput.tsx"],"names":[],"mappings":"AAKA,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,WAA0B,EAC1B,SAAS,EACT,OAAO,GACR,EAAE,aAAa,+BA4Df"}
1
+ {"version":3,"file":"TagInput.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/TagInput.tsx"],"names":[],"mappings":"AAMA,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,aAAa,+BA6D3F"}
@@ -1,58 +1,63 @@
1
- import { cn as e } from "../utils/cn.js";
2
- import { useCallback as t, useState as n } from "react";
3
- import { Plus as r, X as i } from "lucide-react";
4
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
5
- import { Button as s, Input as c } from "@burdenoff/fe-libs/ui";
1
+ import { useTr as e } from "../hooks/useTr.js";
2
+ import { cn as t } from "../utils/cn.js";
3
+ import { useCallback as n, useState as r } from "react";
4
+ import { Plus as i, X as a } from "lucide-react";
5
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
6
+ import { Button as c, Input as l } from "@burdenoff/fe-libs/ui";
6
7
  //#region src/technospam/components/TagInput.tsx
7
- function l({ value: l, onChange: u, placeholder: d = "Add a tag…", className: f, maxTags: p }) {
8
- let [m, h] = n(""), g = t(() => {
9
- let e = m.split(",").map((e) => e.trim()).filter(Boolean);
8
+ function u({ value: u, onChange: d, placeholder: f, className: p, maxTags: m }) {
9
+ let h = e(), [g, _] = r(""), v = n(() => {
10
+ let e = g.split(",").map((e) => e.trim()).filter(Boolean);
10
11
  if (e.length === 0) return;
11
- let t = Array.from(new Set([...l, ...e]));
12
- u(p ? t.slice(0, p) : t), h("");
12
+ let t = Array.from(new Set([...u, ...e]));
13
+ d(m ? t.slice(0, m) : t), _("");
13
14
  }, [
14
- m,
15
- l,
15
+ g,
16
16
  u,
17
- p
18
- ]), _ = t((e) => {
19
- u(l.filter((t) => t !== e));
20
- }, [l, u]);
21
- return /* @__PURE__ */ o("div", {
22
- className: e("space-y-2", f),
23
- children: [/* @__PURE__ */ a("div", {
17
+ d,
18
+ m
19
+ ]), y = n((e) => {
20
+ d(u.filter((t) => t !== e));
21
+ }, [u, d]);
22
+ return /* @__PURE__ */ s("div", {
23
+ className: t("space-y-2", p),
24
+ children: [/* @__PURE__ */ o("div", {
24
25
  className: "flex flex-wrap items-center gap-1.5",
25
- children: l.map((e) => /* @__PURE__ */ o("span", {
26
+ children: u.map((e) => /* @__PURE__ */ s("span", {
26
27
  className: "inline-flex items-center gap-1 rounded-full border border-border-seam bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
27
- children: [e, /* @__PURE__ */ a("button", {
28
+ children: [e, /* @__PURE__ */ o("button", {
28
29
  type: "button",
29
- onClick: () => _(e),
30
+ onClick: () => y(e),
30
31
  className: "rounded-full p-0.5 hover:bg-bg-surface hover:text-status-error-text focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]",
31
- "aria-label": `Remove ${e}`,
32
- children: /* @__PURE__ */ a(i, { size: 10 })
32
+ "aria-label": h("technospam.common.removeTagAria", "Remove {{tag}}", { tag: e }),
33
+ children: /* @__PURE__ */ o(a, { size: 10 })
33
34
  })]
34
35
  }, e))
35
- }), /* @__PURE__ */ o("div", {
36
+ }), /* @__PURE__ */ s("div", {
36
37
  className: "flex items-center gap-2",
37
- children: [/* @__PURE__ */ a(c, {
38
- value: m,
39
- onChange: (e) => h(e.target.value),
38
+ children: [/* @__PURE__ */ o(l, {
39
+ value: g,
40
+ onChange: (e) => _(e.target.value),
40
41
  onKeyDown: (e) => {
41
- e.key === "Enter" && (e.preventDefault(), g());
42
+ e.key === "Enter" && (e.preventDefault(), v());
42
43
  },
43
- placeholder: d,
44
+ placeholder: f ?? h("technospam.common.addTag", "Add a tag…"),
44
45
  className: "flex-1"
45
- }), /* @__PURE__ */ o(s, {
46
+ }), /* @__PURE__ */ s(c, {
46
47
  type: "button",
47
48
  variant: "outline",
48
49
  size: "sm",
49
- onClick: g,
50
- children: [/* @__PURE__ */ a(r, { size: 14 }), " Add"]
50
+ onClick: v,
51
+ children: [
52
+ /* @__PURE__ */ o(i, { size: 14 }),
53
+ " ",
54
+ h("technospam.common.add", "Add")
55
+ ]
51
56
  })]
52
57
  })]
53
58
  });
54
59
  }
55
60
  //#endregion
56
- export { l as TagInput };
61
+ export { u as TagInput };
57
62
 
58
63
  //# sourceMappingURL=TagInput.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TagInput.js","names":[],"sources":["../../../src/technospam/components/TagInput.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { X, Plus } from 'lucide-react';\nimport { Input, Button } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\ninterface TagInputProps {\n value: string[];\n onChange: (tags: string[]) => void;\n placeholder?: string;\n className?: string;\n maxTags?: number;\n}\n\n/**\n * Small controlled tag input. Renders existing tags as removable chips and\n * commits a new tag on Enter or when the add button is pressed.\n *\n * This is the TechnoSpam-local tag picker; it works with the legacy string-tag\n * arrays stored on Tec* entities while the workspace-wide @burdenoff/microfe-tags\n * taxonomy is being adopted product-wide.\n */\nexport function TagInput({\n value,\n onChange,\n placeholder = 'Add a tag…',\n className,\n maxTags,\n}: TagInputProps) {\n const [draft, setDraft] = useState('');\n\n const commit = useCallback(() => {\n const next = draft\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n if (next.length === 0) return;\n const merged = Array.from(new Set([...value, ...next]));\n onChange(maxTags ? merged.slice(0, maxTags) : merged);\n setDraft('');\n }, [draft, value, onChange, maxTags]);\n\n const remove = useCallback(\n (tag: string) => {\n onChange(value.filter((t) => t !== tag));\n },\n [value, onChange]\n );\n\n return (\n <div className={cn('space-y-2', className)}>\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {value.map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 rounded-full border border-border-seam bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\"\n >\n {tag}\n <button\n type=\"button\"\n onClick={() => remove(tag)}\n className=\"rounded-full p-0.5 hover:bg-bg-surface hover:text-status-error-text focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n aria-label={`Remove ${tag}`}\n >\n <X size={10} />\n </button>\n </span>\n ))}\n </div>\n <div className=\"flex items-center gap-2\">\n <Input\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n commit();\n }\n }}\n placeholder={placeholder}\n className=\"flex-1\"\n />\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={commit}>\n <Plus size={14} /> Add\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAqBA,SAAgB,EAAS,EACvB,UACA,aACA,iBAAc,cACd,cACA,cACgB;CAChB,IAAM,CAAC,GAAO,KAAY,EAAS,GAAG,EAEhC,IAAS,QAAkB;EAC/B,IAAM,IAAO,EACV,MAAM,IAAI,CACV,KAAK,MAAM,EAAE,MAAM,CAAC,CACpB,OAAO,QAAQ;AAClB,MAAI,EAAK,WAAW,EAAG;EACvB,IAAM,IAAS,MAAM,KAAK,IAAI,IAAI,CAAC,GAAG,GAAO,GAAG,EAAK,CAAC,CAAC;AAEvD,EADA,EAAS,IAAU,EAAO,MAAM,GAAG,EAAQ,GAAG,EAAO,EACrD,EAAS,GAAG;IACX;EAAC;EAAO;EAAO;EAAU;EAAQ,CAAC,EAE/B,IAAS,GACZ,MAAgB;AACf,IAAS,EAAM,QAAQ,MAAM,MAAM,EAAI,CAAC;IAE1C,CAAC,GAAO,EAAS,CAClB;AAED,QACE,kBAAC,OAAD;EAAK,WAAW,EAAG,aAAa,EAAU;YAA1C,CACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAM,KAAK,MACV,kBAAC,QAAD;IAEE,WAAU;cAFZ,CAIG,GACD,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAO,EAAI;KAC1B,WAAU;KACV,cAAY,UAAU;eAEtB,kBAAC,GAAD,EAAG,MAAM,IAAM,CAAA;KACR,CAAA,CACJ;MAZA,EAYA,CACP;GACE,CAAA,EACN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IACE,OAAO;IACP,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;IACzC,YAAY,MAAM;AAChB,KAAI,EAAE,QAAQ,YACZ,EAAE,gBAAgB,EAClB,GAAQ;;IAGC;IACb,WAAU;IACV,CAAA,EACF,kBAAC,GAAD;IAAQ,MAAK;IAAS,SAAQ;IAAU,MAAK;IAAK,SAAS;cAA3D,CACE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EAAA,OACX;MACL;KACF"}
1
+ {"version":3,"file":"TagInput.js","names":[],"sources":["../../../src/technospam/components/TagInput.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { X, Plus } from 'lucide-react';\nimport { Input, Button } from '@burdenoff/fe-libs/ui';\nimport { useTr } from '../hooks/useTr';\nimport { cn } from '../utils/cn';\n\ninterface TagInputProps {\n value: string[];\n onChange: (tags: string[]) => void;\n placeholder?: string;\n className?: string;\n maxTags?: number;\n}\n\n/**\n * Small controlled tag input. Renders existing tags as removable chips and\n * commits a new tag on Enter or when the add button is pressed.\n *\n * This is the TechnoSpam-local tag picker; it works with the legacy string-tag\n * arrays stored on Tec* entities while the workspace-wide @burdenoff/microfe-tags\n * taxonomy is being adopted product-wide.\n */\nexport function TagInput({ value, onChange, placeholder, className, maxTags }: TagInputProps) {\n const tr = useTr();\n const [draft, setDraft] = useState('');\n\n const commit = useCallback(() => {\n const next = draft\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n if (next.length === 0) return;\n const merged = Array.from(new Set([...value, ...next]));\n onChange(maxTags ? merged.slice(0, maxTags) : merged);\n setDraft('');\n }, [draft, value, onChange, maxTags]);\n\n const remove = useCallback(\n (tag: string) => {\n onChange(value.filter((t) => t !== tag));\n },\n [value, onChange]\n );\n\n return (\n <div className={cn('space-y-2', className)}>\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {value.map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 rounded-full border border-border-seam bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\"\n >\n {tag}\n <button\n type=\"button\"\n onClick={() => remove(tag)}\n className=\"rounded-full p-0.5 hover:bg-bg-surface hover:text-status-error-text focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n aria-label={tr('technospam.common.removeTagAria', 'Remove {{tag}}', { tag })}\n >\n <X size={10} />\n </button>\n </span>\n ))}\n </div>\n <div className=\"flex items-center gap-2\">\n <Input\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n commit();\n }\n }}\n placeholder={placeholder ?? tr('technospam.common.addTag', 'Add a tag…')}\n className=\"flex-1\"\n />\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={commit}>\n <Plus size={14} /> {tr('technospam.common.add', 'Add')}\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAsBA,SAAgB,EAAS,EAAE,UAAO,aAAU,gBAAa,cAAW,cAA0B;CAC5F,IAAM,IAAK,GAAO,EACZ,CAAC,GAAO,KAAY,EAAS,GAAG,EAEhC,IAAS,QAAkB;EAC/B,IAAM,IAAO,EACV,MAAM,IAAI,CACV,KAAK,MAAM,EAAE,MAAM,CAAC,CACpB,OAAO,QAAQ;AAClB,MAAI,EAAK,WAAW,EAAG;EACvB,IAAM,IAAS,MAAM,KAAK,IAAI,IAAI,CAAC,GAAG,GAAO,GAAG,EAAK,CAAC,CAAC;AAEvD,EADA,EAAS,IAAU,EAAO,MAAM,GAAG,EAAQ,GAAG,EAAO,EACrD,EAAS,GAAG;IACX;EAAC;EAAO;EAAO;EAAU;EAAQ,CAAC,EAE/B,IAAS,GACZ,MAAgB;AACf,IAAS,EAAM,QAAQ,MAAM,MAAM,EAAI,CAAC;IAE1C,CAAC,GAAO,EAAS,CAClB;AAED,QACE,kBAAC,OAAD;EAAK,WAAW,EAAG,aAAa,EAAU;YAA1C,CACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAM,KAAK,MACV,kBAAC,QAAD;IAEE,WAAU;cAFZ,CAIG,GACD,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAO,EAAI;KAC1B,WAAU;KACV,cAAY,EAAG,mCAAmC,kBAAkB,EAAE,QAAK,CAAC;eAE5E,kBAAC,GAAD,EAAG,MAAM,IAAM,CAAA;KACR,CAAA,CACJ;MAZA,EAYA,CACP;GACE,CAAA,EACN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IACE,OAAO;IACP,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;IACzC,YAAY,MAAM;AAChB,KAAI,EAAE,QAAQ,YACZ,EAAE,gBAAgB,EAClB,GAAQ;;IAGZ,aAAa,KAAe,EAAG,4BAA4B,aAAa;IACxE,WAAU;IACV,CAAA,EACF,kBAAC,GAAD;IAAQ,MAAK;IAAS,SAAQ;IAAU,MAAK;IAAK,SAAS;cAA3D;KACE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;;KAAE,EAAG,yBAAyB,MAAM;KAC/C;MACL;KACF"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * useTr — translation hook with fallback semantics.
3
+ *
4
+ * Wraps `useI18n().t()` so that when a key has no translation (i.e. the
5
+ * provider returns the key itself), the caller's English fallback is used
6
+ * instead. This keeps consumer call sites consistent and avoids leaking
7
+ * untranslated keys into the UI.
8
+ *
9
+ * Supports optional interpolation params using `{{key}}` placeholders.
10
+ *
11
+ * @example
12
+ * const tr = useTr();
13
+ * return <h1>{tr('technospam.dashboard.title', 'Dashboard')}</h1>;
14
+ * return <p>{tr('technospam.delete.confirm', 'Delete {{count}} items?', { count: 5 })}</p>;
15
+ */
16
+ export declare function useTr(): (key: string, fallback: string, params?: Record<string, string | number>) => string;
17
+ //# sourceMappingURL=useTr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTr.d.ts","sourceRoot":"","sources":["../../../src/technospam/hooks/useTr.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,IAAI,CACvB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KACrC,MAAM,CAOV"}
@@ -0,0 +1,12 @@
1
+ import { tWithFallback as e } from "../utils/i18n.js";
2
+ import { useCallback as t } from "react";
3
+ import { useI18n as n } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
4
+ //#region src/technospam/hooks/useTr.ts
5
+ function r() {
6
+ let { t: r } = n();
7
+ return t((t, n, i) => e(r, t, n, i), [r]);
8
+ }
9
+ //#endregion
10
+ export { r as useTr };
11
+
12
+ //# sourceMappingURL=useTr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTr.js","names":[],"sources":["../../../src/technospam/hooks/useTr.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\n\n/**\n * useTr — translation hook with fallback semantics.\n *\n * Wraps `useI18n().t()` so that when a key has no translation (i.e. the\n * provider returns the key itself), the caller's English fallback is used\n * instead. This keeps consumer call sites consistent and avoids leaking\n * untranslated keys into the UI.\n *\n * Supports optional interpolation params using `{{key}}` placeholders.\n *\n * @example\n * const tr = useTr();\n * return <h1>{tr('technospam.dashboard.title', 'Dashboard')}</h1>;\n * return <p>{tr('technospam.delete.confirm', 'Delete {{count}} items?', { count: 5 })}</p>;\n */\nexport function useTr(): (\n key: string,\n fallback: string,\n params?: Record<string, string | number>\n) => string {\n const { t } = useI18n();\n return useCallback(\n (key: string, fallback: string, params?: Record<string, string | number>): string =>\n tWithFallback(t, key, fallback, params),\n [t]\n );\n}\n"],"mappings":";;;;AAmBA,SAAgB,IAIJ;CACV,IAAM,EAAE,SAAM,GAAS;AACvB,QAAO,GACJ,GAAa,GAAkB,MAC9B,EAAc,GAAG,GAAK,GAAU,EAAO,EACzC,CAAC,EAAE,CACJ"}
@@ -2,5 +2,6 @@ export { TechnoSpamRoot } from './TechnoSpamRoot';
2
2
  export type { TechnoSpamRootProps, NavItem, FooterItem } from './types';
3
3
  export { useTechnoSpam, useTechnoSpamNavigate } from './providers/TechnoSpamProvider';
4
4
  export * from './services/createSandboxAssistantTransport';
5
+ export { useTr } from './hooks/useTr';
5
6
  export { useTechnoSpamAnalytics } from './hooks/useTechnoSpamAnalytics';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/technospam/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAOtF,cAAc,4CAA4C,CAAC;AAG3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/technospam/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAOtF,cAAc,4CAA4C,CAAC;AAG3D,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAGtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import "./providers/TechnoSpamProvider.js";
2
2
  import "./hooks/useTechnoSpamAnalytics.js";
3
+ import "./hooks/useTr.js";
3
4
  import "./TechnoSpamRoot.js";
4
5
  import "./services/createSandboxAssistantTransport.js";
@@ -1 +1 @@
1
- {"version":3,"file":"AnalyticsAnalyticsPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/AnalyticsAnalyticsPagePage.tsx"],"names":[],"mappings":"AAmXA,wBAAgB,0BAA0B,gCAkYzC"}
1
+ {"version":3,"file":"AnalyticsAnalyticsPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/AnalyticsAnalyticsPagePage.tsx"],"names":[],"mappings":"AA4XA,wBAAgB,0BAA0B,gCAodzC"}