@data-club/ai-hub 0.0.2 → 0.0.4

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 (169) hide show
  1. package/dist/auth/locales/cs.d.ts +16 -0
  2. package/dist/auth/locales/cs.d.ts.map +1 -0
  3. package/dist/auth/locales/cs.js +404 -0
  4. package/dist/auth/locales/cs.js.map +1 -0
  5. package/dist/auth/locales/index.d.ts +24 -0
  6. package/dist/auth/locales/index.d.ts.map +1 -0
  7. package/dist/auth/locales/index.js +31 -0
  8. package/dist/auth/locales/index.js.map +1 -0
  9. package/dist/auth/locales/sk.d.ts +16 -0
  10. package/dist/auth/locales/sk.d.ts.map +1 -0
  11. package/dist/auth/locales/sk.js +404 -0
  12. package/dist/auth/locales/sk.js.map +1 -0
  13. package/dist/auth/texts.d.ts +42 -2
  14. package/dist/auth/texts.d.ts.map +1 -1
  15. package/dist/auth/texts.js +30 -7
  16. package/dist/auth/texts.js.map +1 -1
  17. package/dist/client/AIHubClient.d.ts +11 -0
  18. package/dist/client/AIHubClient.d.ts.map +1 -1
  19. package/dist/client/AIHubClient.js +10 -0
  20. package/dist/client/AIHubClient.js.map +1 -1
  21. package/dist/components/AgentsPicker/index.d.ts.map +1 -1
  22. package/dist/components/AgentsPicker/index.js +3 -2
  23. package/dist/components/AgentsPicker/index.js.map +1 -1
  24. package/dist/components/ChangePassword/index.d.ts.map +1 -1
  25. package/dist/components/ChangePassword/index.js +3 -2
  26. package/dist/components/ChangePassword/index.js.map +1 -1
  27. package/dist/components/ChatShell/ShellHeader.d.ts.map +1 -1
  28. package/dist/components/ChatShell/ShellHeader.js +4 -3
  29. package/dist/components/ChatShell/ShellHeader.js.map +1 -1
  30. package/dist/components/ChatShell/index.d.ts.map +1 -1
  31. package/dist/components/ChatShell/index.js +3 -2
  32. package/dist/components/ChatShell/index.js.map +1 -1
  33. package/dist/components/DataClubAIHub/index.d.ts +7 -1
  34. package/dist/components/DataClubAIHub/index.d.ts.map +1 -1
  35. package/dist/components/DataClubAIHub/index.js +3 -1
  36. package/dist/components/DataClubAIHub/index.js.map +1 -1
  37. package/dist/components/DataClubAIHubAdmin/SessionsOverviewPage.d.ts.map +1 -1
  38. package/dist/components/DataClubAIHubAdmin/SessionsOverviewPage.js +5 -23
  39. package/dist/components/DataClubAIHubAdmin/SessionsOverviewPage.js.map +1 -1
  40. package/dist/components/DataClubAIHubAdmin/SettingsPage.d.ts.map +1 -1
  41. package/dist/components/DataClubAIHubAdmin/SettingsPage.js +45 -16
  42. package/dist/components/DataClubAIHubAdmin/SettingsPage.js.map +1 -1
  43. package/dist/components/DataClubAIHubAdmin/index.d.ts.map +1 -1
  44. package/dist/components/DataClubAIHubAdmin/index.js +3 -2
  45. package/dist/components/DataClubAIHubAdmin/index.js.map +1 -1
  46. package/dist/components/DataClubAIHubLogin/index.d.ts.map +1 -1
  47. package/dist/components/DataClubAIHubLogin/index.js +3 -2
  48. package/dist/components/DataClubAIHubLogin/index.js.map +1 -1
  49. package/dist/components/EffortControl/index.d.ts.map +1 -1
  50. package/dist/components/EffortControl/index.js +3 -2
  51. package/dist/components/EffortControl/index.js.map +1 -1
  52. package/dist/components/LanguageSwitcher/index.d.ts +25 -0
  53. package/dist/components/LanguageSwitcher/index.d.ts.map +1 -0
  54. package/dist/components/LanguageSwitcher/index.js +73 -0
  55. package/dist/components/LanguageSwitcher/index.js.map +1 -0
  56. package/dist/components/MainColumn/index.d.ts.map +1 -1
  57. package/dist/components/MainColumn/index.js +3 -2
  58. package/dist/components/MainColumn/index.js.map +1 -1
  59. package/dist/components/MessageInput/index.d.ts.map +1 -1
  60. package/dist/components/MessageInput/index.js +3 -2
  61. package/dist/components/MessageInput/index.js.map +1 -1
  62. package/dist/components/MessageList/index.d.ts.map +1 -1
  63. package/dist/components/MessageList/index.js +3 -2
  64. package/dist/components/MessageList/index.js.map +1 -1
  65. package/dist/components/ReasoningView/index.d.ts.map +1 -1
  66. package/dist/components/ReasoningView/index.js +3 -2
  67. package/dist/components/ReasoningView/index.js.map +1 -1
  68. package/dist/components/ScrollToPresentButton/index.d.ts.map +1 -1
  69. package/dist/components/ScrollToPresentButton/index.js +3 -2
  70. package/dist/components/ScrollToPresentButton/index.js.map +1 -1
  71. package/dist/components/SessionsPanel/index.d.ts.map +1 -1
  72. package/dist/components/SessionsPanel/index.js +6 -34
  73. package/dist/components/SessionsPanel/index.js.map +1 -1
  74. package/dist/components/ThemeSwitcher/index.d.ts.map +1 -1
  75. package/dist/components/ThemeSwitcher/index.js +3 -2
  76. package/dist/components/ThemeSwitcher/index.js.map +1 -1
  77. package/dist/components/ToolCallView/index.d.ts.map +1 -1
  78. package/dist/components/ToolCallView/index.js +3 -2
  79. package/dist/components/ToolCallView/index.js.map +1 -1
  80. package/dist/components/TpmBanner/index.d.ts.map +1 -1
  81. package/dist/components/TpmBanner/index.js +3 -2
  82. package/dist/components/TpmBanner/index.js.map +1 -1
  83. package/dist/components/TurnStatusIndicator/index.d.ts.map +1 -1
  84. package/dist/components/TurnStatusIndicator/index.js +2 -1
  85. package/dist/components/TurnStatusIndicator/index.js.map +1 -1
  86. package/dist/context/AIHubContext.d.ts +23 -0
  87. package/dist/context/AIHubContext.d.ts.map +1 -1
  88. package/dist/context/AIHubContext.js.map +1 -1
  89. package/dist/context/AIHubProvider.d.ts +13 -0
  90. package/dist/context/AIHubProvider.d.ts.map +1 -1
  91. package/dist/context/AIHubProvider.js +39 -2
  92. package/dist/context/AIHubProvider.js.map +1 -1
  93. package/dist/context/index.d.ts +1 -0
  94. package/dist/context/index.d.ts.map +1 -1
  95. package/dist/context/index.js +1 -0
  96. package/dist/context/index.js.map +1 -1
  97. package/dist/context/language.d.ts +44 -0
  98. package/dist/context/language.d.ts.map +1 -0
  99. package/dist/context/language.js +74 -0
  100. package/dist/context/language.js.map +1 -0
  101. package/dist/context/useAIHub.d.ts +8 -0
  102. package/dist/context/useAIHub.d.ts.map +1 -1
  103. package/dist/context/useAIHub.js +4 -0
  104. package/dist/context/useAIHub.js.map +1 -1
  105. package/dist/context/useAIHubTexts.d.ts +40 -0
  106. package/dist/context/useAIHubTexts.d.ts.map +1 -0
  107. package/dist/context/useAIHubTexts.js +52 -0
  108. package/dist/context/useAIHubTexts.js.map +1 -0
  109. package/dist/index.d.ts +4 -2
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js +4 -1
  112. package/dist/index.js.map +1 -1
  113. package/dist/primitives/index.d.ts +3 -0
  114. package/dist/primitives/index.d.ts.map +1 -1
  115. package/dist/primitives/index.js +3 -0
  116. package/dist/primitives/index.js.map +1 -1
  117. package/dist/state/affordances.d.ts +13 -1
  118. package/dist/state/affordances.d.ts.map +1 -1
  119. package/dist/state/affordances.js +11 -9
  120. package/dist/state/affordances.js.map +1 -1
  121. package/dist/stories/_mockProvider.d.ts.map +1 -1
  122. package/dist/stories/_mockProvider.js +5 -0
  123. package/dist/stories/_mockProvider.js.map +1 -1
  124. package/dist/types.d.ts +13 -0
  125. package/dist/types.d.ts.map +1 -1
  126. package/dist/util/relativeTime.d.ts +49 -0
  127. package/dist/util/relativeTime.d.ts.map +1 -0
  128. package/dist/util/relativeTime.js +78 -0
  129. package/dist/util/relativeTime.js.map +1 -0
  130. package/package.json +1 -1
  131. package/src/auth/locales/cs.ts +462 -0
  132. package/src/auth/locales/index.ts +38 -0
  133. package/src/auth/locales/sk.ts +462 -0
  134. package/src/auth/texts.ts +75 -6
  135. package/src/client/AIHubClient.ts +22 -0
  136. package/src/components/AgentsPicker/index.tsx +3 -2
  137. package/src/components/ChangePassword/index.tsx +2 -2
  138. package/src/components/ChatShell/ShellHeader.tsx +2 -0
  139. package/src/components/ChatShell/index.tsx +2 -2
  140. package/src/components/DataClubAIHub/index.tsx +11 -1
  141. package/src/components/DataClubAIHubAdmin/SessionsOverviewPage.tsx +5 -19
  142. package/src/components/DataClubAIHubAdmin/SettingsPage.tsx +138 -13
  143. package/src/components/DataClubAIHubAdmin/index.tsx +2 -2
  144. package/src/components/DataClubAIHubLogin/index.tsx +3 -2
  145. package/src/components/EffortControl/index.tsx +2 -2
  146. package/src/components/LanguageSwitcher/index.tsx +127 -0
  147. package/src/components/MainColumn/index.tsx +2 -2
  148. package/src/components/MessageInput/index.tsx +2 -2
  149. package/src/components/MessageList/index.tsx +2 -2
  150. package/src/components/ReasoningView/index.tsx +2 -2
  151. package/src/components/ScrollToPresentButton/index.tsx +2 -2
  152. package/src/components/SessionsPanel/index.tsx +5 -27
  153. package/src/components/ThemeSwitcher/index.tsx +3 -2
  154. package/src/components/ToolCallView/index.tsx +2 -2
  155. package/src/components/TpmBanner/index.tsx +2 -2
  156. package/src/components/TurnStatusIndicator/index.tsx +2 -1
  157. package/src/context/AIHubContext.ts +25 -0
  158. package/src/context/AIHubProvider.tsx +68 -1
  159. package/src/context/index.ts +1 -0
  160. package/src/context/language.ts +81 -0
  161. package/src/context/useAIHub.ts +12 -0
  162. package/src/context/useAIHubTexts.ts +64 -0
  163. package/src/index.ts +13 -0
  164. package/src/primitives/index.ts +3 -0
  165. package/src/state/affordances.ts +34 -10
  166. package/src/stories/_mockProvider.tsx +5 -0
  167. package/src/styles/default.css +79 -0
  168. package/src/types.ts +14 -0
  169. package/src/util/relativeTime.ts +90 -0
@@ -664,6 +664,85 @@
664
664
  text-decoration: none;
665
665
  }
666
666
 
667
+ /* ── Language switcher (left of the user menu in the shell header) ────── */
668
+
669
+ .data-club-ai-hub__language-switcher {
670
+ position: relative;
671
+ }
672
+
673
+ .data-club-ai-hub__language-switcher__button {
674
+ display: inline-flex;
675
+ align-items: center;
676
+ gap: var(--dc-aih-space-xs);
677
+ padding: var(--dc-aih-space-xs) var(--dc-aih-space-sm);
678
+ font: inherit;
679
+ color: var(--dc-aih-fg);
680
+ background: transparent;
681
+ border: 1px solid transparent;
682
+ border-radius: var(--dc-aih-radius-md);
683
+ transition: background-color var(--dc-aih-transition),
684
+ border-color var(--dc-aih-transition);
685
+ }
686
+
687
+ .data-club-ai-hub__language-switcher__button:hover {
688
+ background-color: color-mix(in srgb, var(--dc-aih-fg) 6%, transparent);
689
+ }
690
+
691
+ .data-club-ai-hub__language-switcher__button:focus-visible {
692
+ outline: none;
693
+ border-color: var(--dc-aih-accent);
694
+ box-shadow: 0 0 0 3px var(--dc-aih-focus-ring);
695
+ }
696
+
697
+ .data-club-ai-hub__language-switcher__icon {
698
+ font-size: var(--dc-aih-font-size-md);
699
+ line-height: 1;
700
+ }
701
+
702
+ .data-club-ai-hub__language-switcher__code {
703
+ font-size: var(--dc-aih-font-size-sm);
704
+ font-weight: 600;
705
+ letter-spacing: 0.03em;
706
+ }
707
+
708
+ .data-club-ai-hub__language-switcher__dropdown {
709
+ position: absolute;
710
+ right: 0;
711
+ top: calc(100% + var(--dc-aih-space-xs));
712
+ min-width: 160px;
713
+ padding: var(--dc-aih-space-sm) 0;
714
+ background-color: var(--dc-aih-bg-elevated);
715
+ border: 1px solid var(--dc-aih-border);
716
+ border-radius: var(--dc-aih-radius-md);
717
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
718
+ z-index: 30;
719
+ }
720
+
721
+ .data-club-ai-hub__language-switcher__item {
722
+ display: block;
723
+ width: 100%;
724
+ padding: var(--dc-aih-space-sm) var(--dc-aih-space-md);
725
+ font: inherit;
726
+ text-align: left;
727
+ color: var(--dc-aih-fg);
728
+ background: transparent;
729
+ border: none;
730
+ }
731
+
732
+ .data-club-ai-hub__language-switcher__item:hover {
733
+ background-color: color-mix(in srgb, var(--dc-aih-fg) 6%, transparent);
734
+ }
735
+
736
+ .data-club-ai-hub__language-switcher__item:focus-visible {
737
+ outline: none;
738
+ background-color: color-mix(in srgb, var(--dc-aih-accent) 12%, transparent);
739
+ }
740
+
741
+ .data-club-ai-hub__language-switcher__item--active {
742
+ font-weight: 600;
743
+ color: var(--dc-aih-accent);
744
+ }
745
+
667
746
  /* ────────────────────────────────────────────────────────────────────── */
668
747
  /* Admin shell + Users sub-page — Step 11 */
669
748
  /* ui-sketches/04-admin-overview.md, ui-sketches/05-admin-users.md */
package/src/types.ts CHANGED
@@ -16,6 +16,8 @@
16
16
  * @see SPECIFICATIONS.md §11 — data model
17
17
  */
18
18
 
19
+ import type { AIHubLanguage } from "./auth/texts.js";
20
+
19
21
  /* ────────────────────────────────────────────────────────────────────────── */
20
22
  /* Roles + users */
21
23
  /* ────────────────────────────────────────────────────────────────────────── */
@@ -98,6 +100,18 @@ export interface AIHubDeployment {
98
100
  * `user.theme_preference`.
99
101
  */
100
102
  theme_switcher_enabled: boolean;
103
+ /**
104
+ * Default UI language for the deployment (`en` | `cs` | `sk`). Seeds a
105
+ * user's language when they have no per-device choice cached, and is the
106
+ * only language used when `user_language_locked` is true.
107
+ */
108
+ language_default: AIHubLanguage;
109
+ /**
110
+ * When `true`, the deployment is single-language — `AIHub.LanguageSwitcher`
111
+ * is hidden and every user sees `language_default` regardless of any cached
112
+ * per-device choice.
113
+ */
114
+ user_language_locked: boolean;
101
115
  /**
102
116
  * Browser-facing URL of the self-hosted Letta ADE — only present when the
103
117
  * caller's role is `power_user` or higher. Absent for `user`-role callers.
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Locale-aware relative-time / date helpers.
3
+ *
4
+ * These replace the three hand-rolled English `"N min ago"` / `"yesterday"`
5
+ * formatters (sessions panel, admin sessions overview, admin settings). They
6
+ * delegate to the platform `Intl.RelativeTimeFormat` / `Intl.DateTimeFormat`,
7
+ * which know each language's CLDR plural rules for free — important for
8
+ * Czech / Slovak where the count word changes between 1, 2–4 and 5+ ("1
9
+ * minúta" / "2 minúty" / "5 minút"), something a flat `"{n} min ago"`
10
+ * template can't express.
11
+ *
12
+ * @see ../auth/texts.ts — `AIHubLanguage`
13
+ */
14
+
15
+ import type { AIHubLanguage } from "../auth/texts.js";
16
+
17
+ /**
18
+ * Formats an ISO-8601 timestamp as a short relative string in `language`,
19
+ * e.g. `"now"` / `"5 minutes ago"` / `"yesterday"` / `"3 days ago"` (and the
20
+ * Czech / Slovak equivalents).
21
+ *
22
+ * @param iso - ISO timestamp. Returns `""` for an unparseable value.
23
+ * @param language - the active UI language.
24
+ * @param opts.absoluteAfterDays - when set and the timestamp is at least this
25
+ * many days old, returns a short absolute date instead (used by the admin
26
+ * sessions overview, which falls back to a date after a week).
27
+ * @returns the localized relative-time string.
28
+ */
29
+ export function formatRelativeTime(
30
+ iso: string,
31
+ language: AIHubLanguage,
32
+ opts: { absoluteAfterDays?: number } = {},
33
+ ): string {
34
+ const then = Date.parse(iso);
35
+ if (Number.isNaN(then)) return "";
36
+ const diffMs = Date.now() - then;
37
+ const rtf = new Intl.RelativeTimeFormat(language, { numeric: "auto" });
38
+ const minutes = Math.round(diffMs / 60_000);
39
+ if (minutes < 1) return rtf.format(0, "second"); // locale "now"
40
+ if (minutes < 60) return rtf.format(-minutes, "minute");
41
+ const hours = Math.round(minutes / 60);
42
+ if (hours < 24) return rtf.format(-hours, "hour");
43
+ const days = Math.round(hours / 24);
44
+ if (
45
+ opts.absoluteAfterDays !== undefined &&
46
+ days >= opts.absoluteAfterDays
47
+ ) {
48
+ return formatAbsoluteDate(iso, language);
49
+ }
50
+ return rtf.format(-days, "day");
51
+ }
52
+
53
+ /**
54
+ * Formats an ISO timestamp as a short, locale-formatted absolute date
55
+ * (e.g. `2026-06-08` → `08/06/2026` in en-GB style, `8. 6. 2026` in cs).
56
+ *
57
+ * @param iso - ISO timestamp. Returns the raw input for an unparseable value.
58
+ * @param language - the active UI language.
59
+ * @returns the localized date string.
60
+ */
61
+ export function formatAbsoluteDate(
62
+ iso: string,
63
+ language: AIHubLanguage,
64
+ ): string {
65
+ const ts = Date.parse(iso);
66
+ if (Number.isNaN(ts)) return iso;
67
+ return new Intl.DateTimeFormat(language, { dateStyle: "short" }).format(
68
+ new Date(ts),
69
+ );
70
+ }
71
+
72
+ /**
73
+ * Day-granular relative label — `"today"` / `"yesterday"` / `"N days ago"`
74
+ * (localized). Used for the admin settings rotation stamp, which pairs an
75
+ * absolute date with this parenthetical.
76
+ *
77
+ * @param iso - ISO timestamp.
78
+ * @param language - the active UI language.
79
+ * @returns the localized day-relative label, or `""` when unparseable.
80
+ */
81
+ export function formatRelativeDay(
82
+ iso: string,
83
+ language: AIHubLanguage,
84
+ ): string {
85
+ const ts = Date.parse(iso);
86
+ if (Number.isNaN(ts)) return "";
87
+ const diffDays = Math.floor((Date.now() - ts) / (24 * 60 * 60 * 1000));
88
+ const rtf = new Intl.RelativeTimeFormat(language, { numeric: "auto" });
89
+ return rtf.format(-Math.max(0, diffDays), "day");
90
+ }