@protobase/ui 0.25.2 → 0.25.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 (271) hide show
  1. package/dist/account/account-pages.js +3 -2
  2. package/dist/account/account-section.js +1 -1
  3. package/dist/account/account-security-page.js +9 -4
  4. package/dist/account/backup-codes.js +7 -6
  5. package/dist/account/messages.js +214 -0
  6. package/dist/account/passkeys-section.js +23 -22
  7. package/dist/account/password-dialog.js +4 -3
  8. package/dist/account/sign-in-policy-form.js +14 -13
  9. package/dist/account/sign-in-policy-labels.js +30 -29
  10. package/dist/account/sign-in-policy-page.js +11 -6
  11. package/dist/account/sign-in-providers-section.js +6 -5
  12. package/dist/account/staff-sign-in-log.js +11 -10
  13. package/dist/account/totp-qr.js +2 -1
  14. package/dist/account/two-factor-section.js +24 -23
  15. package/dist/account/two-factor-setup.js +19 -18
  16. package/dist/action-card/action-card.js +2 -1
  17. package/dist/action-card/field-list.js +1 -1
  18. package/dist/action-card/messages.js +8 -0
  19. package/dist/activity-chart/activity-chart.js +3 -2
  20. package/dist/activity-chart/messages.js +14 -0
  21. package/dist/app/app.d.ts +1 -1
  22. package/dist/app/app.js +20 -21
  23. package/dist/app/assistant-shell.js +2 -1
  24. package/dist/app/batch-failure.js +2 -1
  25. package/dist/app/breadcrumb-for.js +4 -3
  26. package/dist/app/charts/chart-groups.js +3 -2
  27. package/dist/app/charts/chart-view.js +3 -2
  28. package/dist/app/charts/group-bars.js +2 -1
  29. package/dist/app/charts/messages.js +26 -0
  30. package/dist/app/charts/period-chart.js +3 -2
  31. package/dist/app/charts/split-points.js +2 -1
  32. package/dist/app/comments/comment-composer.js +19 -18
  33. package/dist/app/comments/comments-section.js +4 -3
  34. package/dist/app/comments/messages.js +26 -0
  35. package/dist/app/create/create-page.js +11 -18
  36. package/dist/app/custom-section.js +4 -6
  37. package/dist/app/displays/board-column.js +7 -6
  38. package/dist/app/displays/board-columns.js +3 -2
  39. package/dist/app/displays/board-display.js +13 -15
  40. package/dist/app/displays/calendar-controls.js +3 -2
  41. package/dist/app/displays/calendar-display.js +12 -17
  42. package/dist/app/displays/card-carousel.js +4 -3
  43. package/dist/app/displays/cards-display.js +2 -1
  44. package/dist/app/displays/custom-display.js +4 -6
  45. package/dist/app/displays/display-frame.js +3 -2
  46. package/dist/app/displays/list-cards.js +5 -8
  47. package/dist/app/displays/list-displays.js +3 -3
  48. package/dist/app/displays/map-display.js +15 -14
  49. package/dist/app/displays/messages.js +128 -2
  50. package/dist/app/displays/period-controls.js +4 -3
  51. package/dist/app/displays/record-card.js +7 -6
  52. package/dist/app/displays/timeline-display.js +17 -26
  53. package/dist/app/displays/timeline-range.js +2 -1
  54. package/dist/app/displays/timeline-row.js +1 -1
  55. package/dist/app/displays/use-board-move.js +2 -2
  56. package/dist/app/displays/use-calendar-move.js +2 -1
  57. package/dist/app/document-title.js +2 -1
  58. package/dist/app/error-banner.js +1 -1
  59. package/dist/app/export/builder-port.js +2 -1
  60. package/dist/app/export/export-dialog.js +39 -43
  61. package/dist/app/export/export-worker.js +2 -0
  62. package/dist/app/export/messages.js +78 -0
  63. package/dist/app/export/run-export.js +5 -2
  64. package/dist/app/export/sink.js +4 -3
  65. package/dist/app/export/use-export-flow.js +4 -3
  66. package/dist/app/field-editor.js +4 -3
  67. package/dist/app/field-types/messages.js +8 -0
  68. package/dist/app/field-types/widget-part.js +2 -1
  69. package/dist/app/file-field.js +11 -14
  70. package/dist/app/gallery/gallery-section.js +4 -3
  71. package/dist/app/gallery/lightbox.js +5 -4
  72. package/dist/app/gallery/messages.js +30 -0
  73. package/dist/app/gallery/photo-details.js +3 -2
  74. package/dist/app/hand-order/hand-sorted-list.js +3 -6
  75. package/dist/app/hand-order/messages.js +4 -2
  76. package/dist/app/history/describe-change.js +3 -8
  77. package/dist/app/history/messages.js +32 -0
  78. package/dist/app/import/convert.js +20 -19
  79. package/dist/app/import/failed-rows.js +3 -2
  80. package/dist/app/import/import-button.js +2 -1
  81. package/dist/app/import/import-check-step.js +21 -37
  82. package/dist/app/import/import-dialog.js +13 -17
  83. package/dist/app/import/import-file-step.js +5 -9
  84. package/dist/app/import/import-mapping-step.js +32 -35
  85. package/dist/app/import/import-result-step.js +13 -12
  86. package/dist/app/import/messages.js +200 -0
  87. package/dist/app/import/parse-worker.js +2 -0
  88. package/dist/app/import/prepare-rows.js +5 -4
  89. package/dist/app/import/sheet-cell.js +2 -1
  90. package/dist/app/import/sheet-file.js +3 -2
  91. package/dist/app/import/sheet-source.js +7 -3
  92. package/dist/app/import/xlsx-reader.js +4 -3
  93. package/dist/app/import/xlsx-xml.js +2 -1
  94. package/dist/app/import/zip-reader.js +4 -3
  95. package/dist/app/list-edit/use-list-edits.js +1 -1
  96. package/dist/app/list-group-chart.js +2 -1
  97. package/dist/app/list-page.js +1 -1
  98. package/dist/app/map/map-layer-switch.js +3 -2
  99. package/dist/app/map/messages.js +14 -0
  100. package/dist/app/messages.js +116 -2
  101. package/dist/app/meta-gate.js +1 -1
  102. package/dist/app/nav-from-meta.js +11 -10
  103. package/dist/app/pages/action-inputs/action-inputs-dialog.js +3 -2
  104. package/dist/app/pages/action-inputs/input-answers.js +6 -5
  105. package/dist/app/pages/blocks/card-row.js +3 -2
  106. package/dist/app/pages/blocks/field.js +1 -1
  107. package/dist/app/pages/blocks/modal-form.js +5 -4
  108. package/dist/app/pages/blocks/progress.js +1 -1
  109. package/dist/app/pages/blocks/record-card.js +3 -2
  110. package/dist/app/pages/blocks/stat.js +2 -1
  111. package/dist/app/pages/composed-page.js +6 -8
  112. package/dist/app/pages/confirm-action.js +2 -1
  113. package/dist/app/pages/custom-boundary.js +4 -2
  114. package/dist/app/pages/messages.js +64 -0
  115. package/dist/app/pages/render-node.js +5 -7
  116. package/dist/app/pages/use-run-action.js +11 -10
  117. package/dist/app/record-page.js +1 -1
  118. package/dist/app/record-row/messages.js +26 -0
  119. package/dist/app/record-row/record-row-body.js +12 -7
  120. package/dist/app/record-row/record-row.js +4 -3
  121. package/dist/app/record-row/saved-record-row.js +3 -2
  122. package/dist/app/related-dots/dots-summary.js +2 -1
  123. package/dist/app/related-dots/messages.js +8 -0
  124. package/dist/app/relation-picker.js +9 -8
  125. package/dist/app/router.js +5 -4
  126. package/dist/app/runtime/messages.js +58 -0
  127. package/dist/app/runtime/runtime-status.js +10 -23
  128. package/dist/app/runtime/runtime-update-dialog.js +7 -6
  129. package/dist/app/runtime/runtime-update.js +4 -3
  130. package/dist/app/saved/favorite-button.js +2 -1
  131. package/dist/app/saved/messages.js +22 -0
  132. package/dist/app/saved/saved-list.js +4 -7
  133. package/dist/app/saved/use-favorite.js +3 -2
  134. package/dist/app/search/messages.js +6 -2
  135. package/dist/app/search/navigation-hits.js +9 -7
  136. package/dist/app/searches/filter-chip-list.js +2 -1
  137. package/dist/app/searches/messages.js +96 -0
  138. package/dist/app/searches/save-search-button.js +5 -4
  139. package/dist/app/searches/saved-search-rows.js +3 -2
  140. package/dist/app/searches/saved-search-section.js +6 -5
  141. package/dist/app/searches/saved-search.js +4 -3
  142. package/dist/app/searches/saved-searches.js +15 -25
  143. package/dist/app/searches/search-controls.js +5 -4
  144. package/dist/app/searches/search-diff.js +4 -2
  145. package/dist/app/searches/search-name-dialog.js +4 -3
  146. package/dist/app/searches/update-search-dialog.js +15 -30
  147. package/dist/app/searches/use-save-search.js +8 -7
  148. package/dist/app/searches/use-search-row.js +4 -3
  149. package/dist/app/sensitive-field.js +5 -4
  150. package/dist/app/source-notice.js +13 -8
  151. package/dist/app/staff-banner.js +13 -20
  152. package/dist/app-shell/global-search.js +2 -2
  153. package/dist/app-shell/messages.js +4 -2
  154. package/dist/app-shell/sidebar-group.js +1 -1
  155. package/dist/app-shell/sidebar-item.js +1 -1
  156. package/dist/app-shell/sidebar.js +1 -1
  157. package/dist/assistant-dock/assistant-dock.js +6 -6
  158. package/dist/assistant-dock/messages.js +26 -0
  159. package/dist/assistant-dock/use-assistant.js +2 -1
  160. package/dist/assistant-dock/use-backend-data.js +2 -1
  161. package/dist/assistant-dock/widget-view.js +3 -2
  162. package/dist/auth/auth-gate.js +10 -5
  163. package/dist/auth/auth-locale.js +14 -0
  164. package/dist/auth/auth-messages.js +122 -43
  165. package/dist/auth/auth-provider.js +6 -1
  166. package/dist/auth/code-form.js +4 -3
  167. package/dist/auth/email-code-form.js +11 -13
  168. package/dist/auth/email-code-page.js +2 -1
  169. package/dist/auth/first-run-page.js +6 -5
  170. package/dist/auth/forgot-password-form.js +15 -17
  171. package/dist/auth/forgot-password-page.js +2 -1
  172. package/dist/auth/messages.js +200 -0
  173. package/dist/auth/provider-sign-in-page.js +5 -5
  174. package/dist/auth/resend-code-button.js +2 -1
  175. package/dist/auth/reset-password-form.js +12 -11
  176. package/dist/auth/reset-password-page.js +4 -3
  177. package/dist/auth/setup-required-form.js +8 -10
  178. package/dist/auth/setup-required-page.js +7 -2
  179. package/dist/auth/sign-in-form.js +18 -21
  180. package/dist/auth/sign-in-prompt.js +4 -3
  181. package/dist/auth/sign-up-code-form.js +11 -13
  182. package/dist/auth/sign-up-details-form.js +15 -22
  183. package/dist/auth/sign-up-email-form.js +9 -8
  184. package/dist/auth/sign-up-page.js +2 -1
  185. package/dist/auth/staff-sign-in-form.js +16 -19
  186. package/dist/auth/two-factor-form.js +19 -18
  187. package/dist/auth/user-to-shell.js +2 -1
  188. package/dist/chat/composer.js +8 -7
  189. package/dist/chat/messages.js +14 -0
  190. package/dist/compact-table/compact-table.js +4 -8
  191. package/dist/compact-table/messages.js +18 -0
  192. package/dist/data/meta-data.d.ts +1 -1
  193. package/dist/data/use-update-record.js +1 -1
  194. package/dist/data-grid/grid-header.js +1 -1
  195. package/dist/filter-panel/date-presets.js +1 -1
  196. package/dist/forms/public-form-page.js +1 -1
  197. package/dist/inline-child-table/inline-child-table.js +12 -12
  198. package/dist/inline-child-table/line-row.js +10 -9
  199. package/dist/inline-child-table/messages.js +52 -0
  200. package/dist/inline-child-table/totals-footer.js +5 -8
  201. package/dist/invitations/invite-form.js +3 -2
  202. package/dist/invitations/link-notice.js +6 -4
  203. package/dist/invitations/messages.js +24 -0
  204. package/dist/invitations/pending-invitation-row.js +4 -3
  205. package/dist/lists/messages.js +8 -0
  206. package/dist/lists/paged-search-list.js +2 -1
  207. package/dist/locale/slotted.js +14 -0
  208. package/dist/markdown/markdown-editor.js +6 -5
  209. package/dist/markdown/messages.js +16 -0
  210. package/dist/organizations/all-organizations.js +6 -5
  211. package/dist/organizations/app-roles-picker.js +2 -1
  212. package/dist/organizations/invitation-page.js +41 -51
  213. package/dist/organizations/invitations-page.js +11 -10
  214. package/dist/organizations/members-page.js +16 -11
  215. package/dist/organizations/messages.js +180 -0
  216. package/dist/organizations/organization-page.js +27 -26
  217. package/dist/organizations/organization-paths.js +16 -13
  218. package/dist/organizations/organization-row.js +3 -2
  219. package/dist/organizations/organizations-page.js +17 -16
  220. package/dist/organizations/use-organizations.js +2 -1
  221. package/dist/package.js +1 -1
  222. package/dist/plugins/before-sign-in.js +6 -1
  223. package/dist/plugins/load-plugin.d.ts +1 -1
  224. package/dist/plugins/load-plugin.js +3 -2
  225. package/dist/plugins/messages.js +36 -0
  226. package/dist/plugins/plugin-gate.js +6 -1
  227. package/dist/plugins/plugin-manifest.js +8 -7
  228. package/dist/plugins/plugin-notice.js +8 -12
  229. package/dist/primitives/button.js +1 -1
  230. package/dist/primitives/messages.js +16 -0
  231. package/dist/primitives/segmented.js +1 -1
  232. package/dist/primitives/sheet.js +2 -1
  233. package/dist/primitives/spinner.js +2 -1
  234. package/dist/primitives/token.js +2 -1
  235. package/dist/record-view/field.js +2 -2
  236. package/dist/record-view/messages.js +4 -2
  237. package/dist/record-view/record-tabs.js +2 -1
  238. package/dist/roles/messages.js +14 -0
  239. package/dist/roles/use-active-role.js +3 -2
  240. package/dist/shell/assets/app-yCMYvqMX.js +69 -0
  241. package/dist/shell/assets/cn-Bi0ZEjD9.js +1 -0
  242. package/dist/shell/assets/export-worker-ClACk00b.js +2 -0
  243. package/dist/shell/assets/{index-BRkDA5KD.css → index-Bkc7w8I4.css} +1 -1
  244. package/dist/shell/assets/{index-xY0Mvv6V.js → index-HkjqX_O-.js} +2 -2
  245. package/dist/shell/assets/maplibre-DUTS_eJM.js +814 -0
  246. package/dist/shell/assets/{markdown-content-ukDTCu6u.js → markdown-content-CtGUP4W6.js} +1 -1
  247. package/dist/shell/assets/parse-worker-UhbwEjS0.js +5 -0
  248. package/dist/shell/assets/preload-helper-BZ3hrQDD.js +1 -0
  249. package/dist/shell/assets/{record-map-BJmYZ7kQ.js → record-map-DFy7sJEU.js} +1 -1
  250. package/dist/shell/assets/records-map-MfQEuiFB.js +1 -0
  251. package/dist/shell/assets/shared-protobase-ui-Bfa59vx6.js +1 -0
  252. package/dist/shell/index.html +6 -4
  253. package/dist/shell/protobase.shell.json +1 -1
  254. package/dist/shell/protobase.sw.js +2 -2
  255. package/dist/side-panel/messages.js +8 -0
  256. package/dist/side-panel/side-panel.js +2 -1
  257. package/dist/toasts/messages.js +8 -0
  258. package/dist/toasts/toast.js +2 -1
  259. package/dist/users/app-invitations.js +5 -4
  260. package/dist/users/create-user-form.js +9 -8
  261. package/dist/users/messages.js +52 -0
  262. package/dist/users/use-user-roles.js +2 -1
  263. package/dist/users/user-list.js +6 -5
  264. package/dist/users/user-row.js +5 -4
  265. package/package.json +4 -4
  266. package/dist/shell/assets/app-C-OLrsRR.js +0 -69
  267. package/dist/shell/assets/export-worker-Bz57Pf5g.js +0 -2
  268. package/dist/shell/assets/maplibre-Dov6nhPX.js +0 -814
  269. package/dist/shell/assets/parse-worker-BtcY0dQw.js +0 -5
  270. package/dist/shell/assets/records-map-C1_gDKHR.js +0 -1
  271. package/dist/shell/assets/shared-protobase-ui-CFYJAbMR.js +0 -1
@@ -1,3 +1,4 @@
1
+ import { text } from "./messages.js";
1
2
  import { KeyRound, ShieldCheck } from "lucide-react";
2
3
  //#region src/account/account-pages.ts
3
4
  const accountSecurityPath = "/-/account";
@@ -5,13 +6,13 @@ const signInPolicyPath = "/-/sign-in-policy";
5
6
  /** The app's own pages for the signed-in person, at the end of the profile menu: their sign-in, and for admins the policy. */
6
7
  const accountMenuItems = (basePath, path, admin) => [{
7
8
  id: "account-security",
8
- label: "Sign-in & security",
9
+ label: text("signInSecurity"),
9
10
  icon: KeyRound,
10
11
  href: `${basePath}${accountSecurityPath}`,
11
12
  active: path === accountSecurityPath
12
13
  }, ...admin ? [{
13
14
  id: "sign-in-policy",
14
- label: "Sign-in policy",
15
+ label: text("signInPolicy"),
15
16
  icon: ShieldCheck,
16
17
  href: `${basePath}${signInPolicyPath}`,
17
18
  active: path === signInPolicyPath
@@ -24,7 +24,7 @@ const AccountSection = ({ title, status, description, children }) => /* @__PURE_
24
24
  });
25
25
  const SectionError = ({ message }) => message ? /* @__PURE__ */ jsx("p", {
26
26
  role: "alert",
27
- className: "mb-3 text-xs font-medium text-danger-text",
27
+ className: "mb-3 text-body font-medium text-danger-text",
28
28
  children: message
29
29
  }) : null;
30
30
  //#endregion
@@ -1,3 +1,4 @@
1
+ import { text } from "./messages.js";
1
2
  import { Spinner } from "../primitives/spinner.js";
2
3
  import { PageHeader } from "../app-shell/page-header.js";
3
4
  import { authMessage, providerMessage } from "../auth/auth-messages.js";
@@ -32,14 +33,14 @@ const AccountSecurityPage = ({ email }) => {
32
33
  methods,
33
34
  passkeys,
34
35
  linked
35
- }), (failure) => setError(failure instanceof AuthError ? authMessage(failure) : "Could not read your sign-in methods"));
36
+ }), (failure) => setError(failure instanceof AuthError ? authMessage(failure) : text("couldNotReadMethods")));
36
37
  }, [account]);
37
38
  useEffect(reload, [reload]);
38
39
  const thenReload = (change) => change.then((result) => (reload(), result));
39
40
  return /* @__PURE__ */ jsxs("div", {
40
41
  className: "mx-auto flex w-full max-w-3xl flex-col gap-4 px-4 py-6 md:px-6",
41
42
  children: [/* @__PURE__ */ jsx(PageHeader, {
42
- title: "Sign-in & security",
43
+ title: text("signInSecurity"),
43
44
  subtitle: email
44
45
  }), loaded ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
45
46
  /* @__PURE__ */ jsx(PasskeysSection, {
@@ -66,7 +67,7 @@ const AccountSecurityPage = ({ email }) => {
66
67
  providers: linkable,
67
68
  linked: loaded.linked,
68
69
  onConnect: linkProvider,
69
- error: linkError && providerMessage(linkError, linkable.length === 1 ? linkable[0].name : "the provider")
70
+ error: linkError && providerMessage(linkError, linkable.length === 1 ? linkable[0].name : text("theProvider"))
70
71
  })
71
72
  ] }) : error ? /* @__PURE__ */ jsx("p", {
72
73
  role: "alert",
@@ -74,7 +75,11 @@ const AccountSecurityPage = ({ email }) => {
74
75
  children: error
75
76
  }) : /* @__PURE__ */ jsxs("div", {
76
77
  className: "flex items-center gap-2 text-muted-foreground",
77
- children: [/* @__PURE__ */ jsx(Spinner, {}), " Loading"]
78
+ children: [
79
+ /* @__PURE__ */ jsx(Spinner, {}),
80
+ " ",
81
+ text("loading")
82
+ ]
78
83
  })]
79
84
  });
80
85
  };
@@ -1,3 +1,4 @@
1
+ import { text } from "./messages.js";
1
2
  import { Button } from "../primitives/button.js";
2
3
  import { saveFile } from "../lib/save-file.js";
3
4
  import { useState } from "react";
@@ -7,11 +8,11 @@ import { jsx, jsxs } from "react/jsx-runtime";
7
8
  /** The backup codes, shown once, with ways to keep them: each works once instead of a code from the app. */
8
9
  const BackupCodes = ({ codes }) => {
9
10
  const [copied, setCopied] = useState(false);
10
- const text = `${codes.join("\n")}\n`;
11
+ const lines = `${codes.join("\n")}\n`;
11
12
  return /* @__PURE__ */ jsxs("div", {
12
13
  className: "flex flex-col gap-3",
13
14
  children: [/* @__PURE__ */ jsx("ul", {
14
- "aria-label": "Backup codes",
15
+ "aria-label": text("backupCodes"),
15
16
  className: "grid grid-cols-2 gap-x-4 gap-y-1 rounded-md border bg-surface p-3 font-mono",
16
17
  children: codes.map((code) => /* @__PURE__ */ jsx("li", { children: code }, code))
17
18
  }), /* @__PURE__ */ jsxs("div", {
@@ -19,16 +20,16 @@ const BackupCodes = ({ codes }) => {
19
20
  children: [/* @__PURE__ */ jsxs(Button, {
20
21
  size: "sm",
21
22
  onClick: () => {
22
- navigator.clipboard.writeText(text).then(() => {
23
+ navigator.clipboard.writeText(lines).then(() => {
23
24
  setCopied(true);
24
25
  setTimeout(() => setCopied(false), 2e3);
25
26
  });
26
27
  },
27
- children: [copied ? /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-success" }) : /* @__PURE__ */ jsx(Copy, { className: "size-3.5" }), copied ? "Copied" : "Copy"]
28
+ children: [copied ? /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-success" }) : /* @__PURE__ */ jsx(Copy, { className: "size-3.5" }), copied ? text("copied") : text("copy")]
28
29
  }), /* @__PURE__ */ jsxs(Button, {
29
30
  size: "sm",
30
- onClick: () => saveFile(text, "backup-codes.txt"),
31
- children: [/* @__PURE__ */ jsx(Download, { className: "size-3.5" }), "Download"]
31
+ onClick: () => saveFile(lines, "backup-codes.txt"),
32
+ children: [/* @__PURE__ */ jsx(Download, { className: "size-3.5" }), text("download")]
32
33
  })]
33
34
  })]
34
35
  });
@@ -0,0 +1,214 @@
1
+ import { defineMessages } from "../locale/messages.js";
2
+ //#region src/account/messages.ts
3
+ const text = defineMessages({
4
+ en: {
5
+ signInSecurity: "Sign-in & security",
6
+ signInPolicy: "Sign-in policy",
7
+ couldNotReadMethods: "Could not read your sign-in methods",
8
+ theProvider: "the provider",
9
+ loading: "Loading",
10
+ backupCodes: "Backup codes",
11
+ copied: "Copied",
12
+ copy: "Copy",
13
+ download: "Download",
14
+ cancel: "Cancel",
15
+ save: "Save",
16
+ name: "Name",
17
+ yourPassword: "Your password",
18
+ continue: "Continue",
19
+ on: "On",
20
+ off: "Off",
21
+ optional: "Optional",
22
+ required: "Required",
23
+ passkeys: "Passkeys",
24
+ passkey: "Passkey",
25
+ passkeysAllowed: "Sign in with Face ID, Touch ID, Windows Hello, your phone or a security key instead of a password.",
26
+ passkeysRequired: "This app requires a passkey for every account. Sign in with Face ID, Touch ID, Windows Hello, your phone or a security key.",
27
+ passkeysForbidden: "Your admin turned passkeys off for this app, so they cannot be used to sign in.",
28
+ addedOn: (date) => `Added ${date}`,
29
+ addedEarlier: "Added earlier",
30
+ synced: "Synced across your devices",
31
+ oneDevice: "On one device",
32
+ rename: "Rename",
33
+ remove: "Remove",
34
+ keepLastPasskey: "Passkeys are required: add another one before removing this one.",
35
+ addPasskey: "Add a passkey",
36
+ renamePasskey: "Rename passkey",
37
+ renamePasskeyDescription: "A name that tells you where this passkey lives, such as the device or password manager.",
38
+ removePasskey: "Remove passkey?",
39
+ removePasskeyDescription: (name) => `${name} will no longer sign you in here. It stays on the device until you delete it there.`,
40
+ thisPasskey: "This passkey",
41
+ connectedAccounts: "Connected accounts",
42
+ connectedAccountsDescription: "Sign in with these instead of your password. Connecting one asks you to sign in there; its address may differ from yours here.",
43
+ connected: "Connected",
44
+ connect: (name) => `Connect ${name}`,
45
+ stopped: (time) => `Stopped ${time}`,
46
+ ended: (time) => `Ended ${time}`,
47
+ signedInUntil: (time) => `Signed in until ${time}`,
48
+ staffSignIns: "Staff sign-ins",
49
+ staffSignInsDescription: (operator) => `Each time staff of ${operator} signed in as someone here, newest first.`,
50
+ noStaffSignIns: "No staff has signed in as anyone yet.",
51
+ as: "as",
52
+ qrCode: "QR code for your authenticator app",
53
+ twoFactor: "Two-factor authentication",
54
+ twoFactorAllowed: "Ask for a second step after your password or an emailed sign-in code: a code from an authenticator app, or one emailed to you. A passkey needs no second step.",
55
+ twoFactorRequired: "This app requires two-factor authentication for every account. Turn it on to keep using the app.",
56
+ twoFactorForbidden: "Your admin turned two-factor authentication off for this app.",
57
+ twoFactorOnWithApp: "Signing in with a password or an emailed sign-in code also asks for a code from your authenticator app. Backup codes work when you do not have the app.",
58
+ twoFactorOnWithAppOrMail: "Signing in with a password or an emailed sign-in code also asks for a code from your authenticator app, or one emailed to you. Backup codes work when you do not have the app.",
59
+ twoFactorOnWithMail: "Signing in with a password or an emailed sign-in code also asks for a code emailed to you.",
60
+ turnOn: "Turn on",
61
+ turnOff: "Turn off",
62
+ addAuthenticator: "Add an authenticator app",
63
+ newBackupCodes: "New backup codes",
64
+ twoFactorIsRequired: "This app requires two-factor authentication.",
65
+ turnOffTitle: "Turn off two-factor authentication?",
66
+ turnOffDescription: "Signing in then needs only your password or an emailed code. Your backup codes stop working.",
67
+ newCodesTitle: "Make new backup codes?",
68
+ newCodesDescription: "Your current backup codes stop working, and you get ten new ones.",
69
+ makeNewCodes: "Make new codes",
70
+ yourNewCodes: "Your new backup codes",
71
+ keepCodesSafe: "Keep them somewhere safe: each one signs you in once if you lose your phone. They are not shown again.",
72
+ savedCodes: "I saved my backup codes",
73
+ authenticatorApp: "Authenticator app",
74
+ authenticatorAppDescription: "A code from an app such as Google Authenticator, Microsoft Authenticator or 1Password. Comes with backup codes.",
75
+ emailedCode: "Emailed code",
76
+ emailedCodeDescription: "A code mailed to your address each time you sign in with a password or an emailed sign-in code.",
77
+ twoFactorIsOn: "Two-factor authentication is on. Keep these backup codes somewhere safe: each one signs you in once if you lose your phone. They are not shown again.",
78
+ scanCode: "Scan this code with your authenticator app, then enter the 6-digit code it shows.",
79
+ cannotScan: "Can't scan it? Enter this key in the app:",
80
+ codeFromApp: "Code from the app",
81
+ secondStep: "Second step",
82
+ password: "Password",
83
+ passwordDescription: "Sign in with the email address and a password.",
84
+ emailedSignInCode: "Emailed sign-in code",
85
+ emailedSignInCodeDescription: "Sign in with a one-time code mailed to the account's address.",
86
+ passkeysPolicyDescription: "Sign in with Face ID, Touch ID, Windows Hello, a phone or a security key. Required: everyone adds one after signing in.",
87
+ twoFactorPolicyDescription: "A code from an authenticator app, or an emailed one, after a password or an emailed sign-in code. Required: everyone turns it on after signing in.",
88
+ staffAccess: "Staff sign-in as a person",
89
+ staffAccessDescription: "The team that runs this app signs in as someone to help them, with a reason, for a short session. Each time is in the log below; with \"Email the person\" they are told too.",
90
+ emailThePerson: "Email the person",
91
+ platformSignIn: "Sign-in through the platform",
92
+ platformSignInDescription: "The sign-in provider the platform that runs this app adds, for people who have an account here already. It never creates accounts.",
93
+ platformSignInWith: (provider) => `Sign in with ${provider} through the platform`,
94
+ codeNeedsMail: "Needs mail settings (PROTOBASE_SMTP_URL and PROTOBASE_MAIL_FROM): off until they are set.",
95
+ passwordStaysOn: "Without mail settings, password sign-in stays on so nobody is locked out.",
96
+ staffNeedsMail: "Needs mail settings (PROTOBASE_SMTP_URL and PROTOBASE_MAIL_FROM): staff cannot sign in until they are set.",
97
+ platformOff: "Off while passkeys or two-factor authentication are required: it skips the second step.",
98
+ appliesAs: (rule) => `Applies as ${rule} for now.`,
99
+ lastSaved: (time) => `Last saved on ${time}.`,
100
+ lastSavedBy: (name, time) => `Last saved by ${name} on ${time}.`,
101
+ neverChanged: "Never changed: everything is on, nothing is required.",
102
+ reset: "Reset",
103
+ couldNotReadStaffSignIns: "Could not read the staff sign-ins",
104
+ couldNotReadPolicy: "Could not read the sign-in policy",
105
+ policySaved: "Saved. It applies to every sign-in from now on.",
106
+ policySubtitle: "How people sign in to this app. Signed-in people keep their session, and are asked for what is newly required within 15 minutes."
107
+ },
108
+ nl: {
109
+ signInSecurity: "Inloggen en beveiliging",
110
+ signInPolicy: "Inlogbeleid",
111
+ couldNotReadMethods: "Kon je inlogmethoden niet lezen",
112
+ theProvider: "de provider",
113
+ loading: "Laden",
114
+ backupCodes: "Back-upcodes",
115
+ copied: "Gekopieerd",
116
+ copy: "Kopiëren",
117
+ download: "Downloaden",
118
+ cancel: "Annuleren",
119
+ save: "Bewaren",
120
+ name: "Naam",
121
+ yourPassword: "Je wachtwoord",
122
+ continue: "Doorgaan",
123
+ on: "Aan",
124
+ off: "Uit",
125
+ optional: "Optioneel",
126
+ required: "Verplicht",
127
+ passkeys: "Passkeys",
128
+ passkey: "Passkey",
129
+ passkeysAllowed: "Log in met Face ID, Touch ID, Windows Hello, je telefoon of een beveiligingssleutel in plaats van een wachtwoord.",
130
+ passkeysRequired: "Deze app vraagt een passkey voor elk account. Log in met Face ID, Touch ID, Windows Hello, je telefoon of een beveiligingssleutel.",
131
+ passkeysForbidden: "Je beheerder heeft passkeys uitgezet voor deze app, dus je kunt er niet mee inloggen.",
132
+ addedOn: (date) => `Toegevoegd ${date}`,
133
+ addedEarlier: "Eerder toegevoegd",
134
+ synced: "Gesynchroniseerd op je apparaten",
135
+ oneDevice: "Op één apparaat",
136
+ rename: "Naam wijzigen",
137
+ remove: "Verwijderen",
138
+ keepLastPasskey: "Passkeys zijn verplicht: voeg er nog een toe voordat je deze verwijdert.",
139
+ addPasskey: "Passkey toevoegen",
140
+ renamePasskey: "Naam van passkey wijzigen",
141
+ renamePasskeyDescription: "Een naam die zegt waar deze passkey staat, zoals het apparaat of de wachtwoordbeheerder.",
142
+ removePasskey: "Passkey verwijderen?",
143
+ removePasskeyDescription: (name) => `Met ${name} log je hier niet meer in. Die blijft op het apparaat tot je die daar verwijdert.`,
144
+ thisPasskey: "deze passkey",
145
+ connectedAccounts: "Gekoppelde accounts",
146
+ connectedAccountsDescription: "Log hiermee in in plaats van met je wachtwoord. Koppelen vraagt je daar in te loggen; het adres daar kan anders zijn dan hier.",
147
+ connected: "Gekoppeld",
148
+ connect: (name) => `${name} koppelen`,
149
+ stopped: (time) => `Gestopt ${time}`,
150
+ ended: (time) => `Afgelopen ${time}`,
151
+ signedInUntil: (time) => `Ingelogd tot ${time}`,
152
+ staffSignIns: "Inlogs van medewerkers",
153
+ staffSignInsDescription: (operator) => `Elke keer dat een medewerker van ${operator} hier als iemand anders inlogde, nieuwste eerst.`,
154
+ noStaffSignIns: "Nog geen medewerker heeft als iemand anders ingelogd.",
155
+ as: "als",
156
+ qrCode: "QR-code voor je authenticator-app",
157
+ twoFactor: "Tweestapsverificatie",
158
+ twoFactorAllowed: "Vraag een tweede stap na je wachtwoord of een gemailde inlogcode: een code uit een authenticator-app, of een die je gemaild krijgt. Een passkey heeft geen tweede stap nodig.",
159
+ twoFactorRequired: "Deze app vraagt tweestapsverificatie voor elk account. Zet het aan om de app te blijven gebruiken.",
160
+ twoFactorForbidden: "Je beheerder heeft tweestapsverificatie uitgezet voor deze app.",
161
+ twoFactorOnWithApp: "Inloggen met een wachtwoord of een gemailde inlogcode vraagt ook een code uit je authenticator-app. Back-upcodes werken als je de app niet bij de hand hebt.",
162
+ twoFactorOnWithAppOrMail: "Inloggen met een wachtwoord of een gemailde inlogcode vraagt ook een code uit je authenticator-app, of een die je gemaild krijgt. Back-upcodes werken als je de app niet bij de hand hebt.",
163
+ twoFactorOnWithMail: "Inloggen met een wachtwoord of een gemailde inlogcode vraagt ook een code die je gemaild krijgt.",
164
+ turnOn: "Aanzetten",
165
+ turnOff: "Uitzetten",
166
+ addAuthenticator: "Authenticator-app toevoegen",
167
+ newBackupCodes: "Nieuwe back-upcodes",
168
+ twoFactorIsRequired: "Deze app vraagt tweestapsverificatie.",
169
+ turnOffTitle: "Tweestapsverificatie uitzetten?",
170
+ turnOffDescription: "Inloggen vraagt dan alleen je wachtwoord of een gemailde code. Je back-upcodes werken niet meer.",
171
+ newCodesTitle: "Nieuwe back-upcodes maken?",
172
+ newCodesDescription: "Je huidige back-upcodes werken niet meer, en je krijgt tien nieuwe.",
173
+ makeNewCodes: "Nieuwe codes maken",
174
+ yourNewCodes: "Je nieuwe back-upcodes",
175
+ keepCodesSafe: "Bewaar ze op een veilige plek: met elke code log je één keer in als je je telefoon kwijt bent. Ze worden niet opnieuw getoond.",
176
+ savedCodes: "Ik heb mijn back-upcodes bewaard",
177
+ authenticatorApp: "Authenticator-app",
178
+ authenticatorAppDescription: "Een code uit een app zoals Google Authenticator, Microsoft Authenticator of 1Password. Met back-upcodes.",
179
+ emailedCode: "Gemailde code",
180
+ emailedCodeDescription: "Een code naar je adres, elke keer dat je inlogt met een wachtwoord of een gemailde inlogcode.",
181
+ twoFactorIsOn: "Tweestapsverificatie staat aan. Bewaar deze back-upcodes op een veilige plek: met elke code log je één keer in als je je telefoon kwijt bent. Ze worden niet opnieuw getoond.",
182
+ scanCode: "Scan deze code met je authenticator-app en vul daarna de code van 6 cijfers in die de app toont.",
183
+ cannotScan: "Lukt scannen niet? Vul deze sleutel in de app in:",
184
+ codeFromApp: "Code uit de app",
185
+ secondStep: "Tweede stap",
186
+ password: "Wachtwoord",
187
+ passwordDescription: "Inloggen met het e-mailadres en een wachtwoord.",
188
+ emailedSignInCode: "Gemailde inlogcode",
189
+ emailedSignInCodeDescription: "Inloggen met een eenmalige code naar het adres van het account.",
190
+ passkeysPolicyDescription: "Inloggen met Face ID, Touch ID, Windows Hello, een telefoon of een beveiligingssleutel. Verplicht: iedereen voegt er een toe na het inloggen.",
191
+ twoFactorPolicyDescription: "Een code uit een authenticator-app, of een gemailde, na een wachtwoord of een gemailde inlogcode. Verplicht: iedereen zet het aan na het inloggen.",
192
+ staffAccess: "Medewerker logt in als iemand anders",
193
+ staffAccessDescription: "Het team dat deze app beheert, logt in als iemand om die te helpen, met een reden, voor een korte sessie. Elke keer staat in het logboek hieronder; met \"De persoon mailen\" krijgt die het ook te horen.",
194
+ emailThePerson: "De persoon mailen",
195
+ platformSignIn: "Inloggen via het platform",
196
+ platformSignInDescription: "De inlogprovider die het platform van deze app toevoegt, voor mensen die hier al een account hebben. Die maakt nooit accounts.",
197
+ platformSignInWith: (provider) => `Inloggen met ${provider} via het platform`,
198
+ codeNeedsMail: "Vraagt mailinstellingen (PROTOBASE_SMTP_URL en PROTOBASE_MAIL_FROM): uit tot die zijn ingesteld.",
199
+ passwordStaysOn: "Zonder mailinstellingen blijft inloggen met een wachtwoord aan, zodat niemand wordt buitengesloten.",
200
+ staffNeedsMail: "Vraagt mailinstellingen (PROTOBASE_SMTP_URL en PROTOBASE_MAIL_FROM): medewerkers kunnen niet inloggen tot die zijn ingesteld.",
201
+ platformOff: "Uit zolang passkeys of tweestapsverificatie verplicht zijn: het slaat de tweede stap over.",
202
+ appliesAs: (rule) => `Geldt voorlopig als ${rule}.`,
203
+ lastSaved: (time) => `Laatst bewaard op ${time}.`,
204
+ lastSavedBy: (name, time) => `Laatst bewaard door ${name} op ${time}.`,
205
+ neverChanged: "Nooit gewijzigd: alles staat aan, niets is verplicht.",
206
+ reset: "Terugzetten",
207
+ couldNotReadStaffSignIns: "Kon de inlogs van medewerkers niet lezen",
208
+ couldNotReadPolicy: "Kon het inlogbeleid niet lezen",
209
+ policySaved: "Bewaard. Het geldt vanaf nu voor elke inlog.",
210
+ policySubtitle: "Hoe mensen inloggen bij deze app. Wie is ingelogd, houdt de sessie en krijgt binnen 15 minuten de vraag naar wat nieuw verplicht is."
211
+ }
212
+ });
213
+ //#endregion
214
+ export { text };
@@ -1,3 +1,4 @@
1
+ import { text } from "./messages.js";
1
2
  import { Badge } from "../primitives/badge.js";
2
3
  import { Input } from "../primitives/input.js";
3
4
  import { authMessage } from "../auth/auth-messages.js";
@@ -11,9 +12,9 @@ import { AuthError } from "@protobase/client";
11
12
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
13
  //#region src/account/passkeys-section.tsx
13
14
  const descriptions = {
14
- allowed: "Sign in with Face ID, Touch ID, Windows Hello, your phone or a security key instead of a password.",
15
- required: "This app requires a passkey for every account. Sign in with Face ID, Touch ID, Windows Hello, your phone or a security key.",
16
- forbidden: "Your admin turned passkeys off for this app, so they cannot be used to sign in."
15
+ allowed: "passkeysAllowed",
16
+ required: "passkeysRequired",
17
+ forbidden: "passkeysForbidden"
17
18
  };
18
19
  const PasskeysSection = ({ rule, passkeys, onAdd, onRename, onRemove }) => {
19
20
  const [busy, setBusy] = useState(false);
@@ -34,12 +35,12 @@ const PasskeysSection = ({ rule, passkeys, onAdd, onRename, onRemove }) => {
34
35
  setBusy(false);
35
36
  };
36
37
  return /* @__PURE__ */ jsxs(AccountSection, {
37
- title: "Passkeys",
38
+ title: text("passkeys"),
38
39
  status: rule === "required" && /* @__PURE__ */ jsx(Badge, {
39
40
  tone: "blue",
40
- children: "Required"
41
+ children: text("required")
41
42
  }),
42
- description: descriptions[rule],
43
+ description: text(descriptions[rule]),
43
44
  children: [
44
45
  /* @__PURE__ */ jsx(SectionError, { message: editing ? void 0 : error }),
45
46
  passkeys.length > 0 && /* @__PURE__ */ jsx("ul", {
@@ -52,13 +53,13 @@ const PasskeysSection = ({ rule, passkeys, onAdd, onRename, onRemove }) => {
52
53
  className: "min-w-0 flex-1",
53
54
  children: [/* @__PURE__ */ jsx("span", {
54
55
  className: "block truncate font-medium",
55
- children: passkey.name ?? "Passkey"
56
+ children: passkey.name ?? text("passkey")
56
57
  }), /* @__PURE__ */ jsxs("span", {
57
58
  className: "block text-xs text-muted-foreground",
58
59
  children: [
59
- passkey.createdAt ? `Added ${formatDate(Date.parse(passkey.createdAt))}` : "Added earlier",
60
+ passkey.createdAt ? text("addedOn", formatDate(Date.parse(passkey.createdAt))) : text("addedEarlier"),
60
61
  " · ",
61
- passkey.backedUp ? "Synced across your devices" : "On one device"
62
+ passkey.backedUp ? text("synced") : text("oneDevice")
62
63
  ]
63
64
  })]
64
65
  }),
@@ -74,17 +75,17 @@ const PasskeysSection = ({ rule, passkeys, onAdd, onRename, onRemove }) => {
74
75
  passkey
75
76
  });
76
77
  },
77
- children: "Rename"
78
+ children: text("rename")
78
79
  }), /* @__PURE__ */ jsx(Button, {
79
80
  size: "sm",
80
81
  variant: "ghost",
81
82
  disabled: keepLast,
82
- title: keepLast ? "Passkeys are required: add another one before removing this one." : void 0,
83
+ title: keepLast ? text("keepLastPasskey") : void 0,
83
84
  onClick: () => setEditing({
84
85
  kind: "remove",
85
86
  passkey
86
87
  }),
87
- children: "Remove"
88
+ children: text("remove")
88
89
  })]
89
90
  })
90
91
  ]
@@ -93,25 +94,25 @@ const PasskeysSection = ({ rule, passkeys, onAdd, onRename, onRemove }) => {
93
94
  rule !== "forbidden" && /* @__PURE__ */ jsxs(Button, {
94
95
  loading: busy && !editing,
95
96
  onClick: () => void attempt(onAdd),
96
- children: [/* @__PURE__ */ jsx(Plus, { className: "size-3.5" }), "Add a passkey"]
97
+ children: [/* @__PURE__ */ jsx(Plus, { className: "size-3.5" }), text("addPasskey")]
97
98
  }),
98
99
  editing?.kind === "rename" && /* @__PURE__ */ jsxs(Dialog, {
99
- title: "Rename passkey",
100
- description: "A name that tells you where this passkey lives, such as the device or password manager.",
100
+ title: text("renamePasskey"),
101
+ description: text("renamePasskeyDescription"),
101
102
  onClose: () => setEditing(void 0),
102
103
  actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
103
104
  onClick: () => setEditing(void 0),
104
- children: "Cancel"
105
+ children: text("cancel")
105
106
  }), /* @__PURE__ */ jsx(Button, {
106
107
  variant: "primary",
107
108
  loading: busy,
108
109
  disabled: !name.trim(),
109
110
  onClick: () => void attempt(() => onRename(editing.passkey.id, name.trim())),
110
- children: "Save"
111
+ children: text("save")
111
112
  })] }),
112
113
  children: [/* @__PURE__ */ jsxs("label", {
113
114
  className: "flex flex-col gap-1.5 font-medium",
114
- children: ["Name", /* @__PURE__ */ jsx(Input, {
115
+ children: [text("name"), /* @__PURE__ */ jsx(Input, {
115
116
  autoFocus: true,
116
117
  value: name,
117
118
  maxLength: 60,
@@ -120,17 +121,17 @@ const PasskeysSection = ({ rule, passkeys, onAdd, onRename, onRemove }) => {
120
121
  }), /* @__PURE__ */ jsx(SectionError, { message: error })]
121
122
  }),
122
123
  editing?.kind === "remove" && /* @__PURE__ */ jsx(Dialog, {
123
- title: "Remove passkey?",
124
- description: `${editing.passkey.name ?? "This passkey"} will no longer sign you in here. It stays on the device until you delete it there.`,
124
+ title: text("removePasskey"),
125
+ description: text("removePasskeyDescription", editing.passkey.name ?? text("thisPasskey")),
125
126
  onClose: () => setEditing(void 0),
126
127
  actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
127
128
  onClick: () => setEditing(void 0),
128
- children: "Cancel"
129
+ children: text("cancel")
129
130
  }), /* @__PURE__ */ jsx(Button, {
130
131
  variant: "danger",
131
132
  loading: busy,
132
133
  onClick: () => void attempt(() => onRemove(editing.passkey.id)),
133
- children: "Remove"
134
+ children: text("remove")
134
135
  })] }),
135
136
  children: error && /* @__PURE__ */ jsx(SectionError, { message: error })
136
137
  })
@@ -1,3 +1,4 @@
1
+ import { text } from "./messages.js";
1
2
  import { Input } from "../primitives/input.js";
2
3
  import { authMessage } from "../auth/auth-messages.js";
3
4
  import { Button } from "../primitives/button.js";
@@ -28,7 +29,7 @@ const PasswordDialog = ({ title, description, confirmLabel, danger, needsPasswor
28
29
  onClose,
29
30
  actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
30
31
  onClick: onClose,
31
- children: "Cancel"
32
+ children: text("cancel")
32
33
  }), /* @__PURE__ */ jsx(Button, {
33
34
  variant: danger ? "danger" : "primary",
34
35
  loading: busy,
@@ -38,7 +39,7 @@ const PasswordDialog = ({ title, description, confirmLabel, danger, needsPasswor
38
39
  })] }),
39
40
  children: [needsPassword && /* @__PURE__ */ jsxs("label", {
40
41
  className: "flex flex-col gap-1.5 font-medium",
41
- children: ["Your password", /* @__PURE__ */ jsx(Input, {
42
+ children: [text("yourPassword"), /* @__PURE__ */ jsx(Input, {
42
43
  type: "password",
43
44
  autoComplete: "current-password",
44
45
  autoFocus: true,
@@ -49,7 +50,7 @@ const PasswordDialog = ({ title, description, confirmLabel, danger, needsPasswor
49
50
  })]
50
51
  }), error && /* @__PURE__ */ jsx("p", {
51
52
  role: "alert",
52
- className: "mt-2 text-xs font-medium text-danger-text",
53
+ className: "mt-2 text-body font-medium text-danger-text",
53
54
  children: error
54
55
  })]
55
56
  });
@@ -1,3 +1,4 @@
1
+ import { text } from "./messages.js";
1
2
  import { cn } from "../lib/cn.js";
2
3
  import { formatDateTime } from "../format/date.js";
3
4
  import { Button } from "../primitives/button.js";
@@ -14,22 +15,22 @@ const RuleChoice = ({ row, value, onChange }) => /* @__PURE__ */ jsx("span", {
14
15
  role: "radio",
15
16
  "aria-checked": option.value === value,
16
17
  onClick: () => onChange(option.value),
17
- className: cn("rounded px-3 text-xs font-medium transition-colors", option.value === value ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"),
18
+ className: cn("rounded px-3 text-body font-medium transition-colors", option.value === value ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"),
18
19
  children: option.label
19
20
  }, option.value))
20
21
  });
21
22
  const rowNote = ({ method }, draft, { mail, effective, policy }) => {
22
- if (method === "emailCode" && !mail) return "Needs mail settings (PROTOBASE_SMTP_URL and PROTOBASE_MAIL_FROM): off until they are set.";
23
- if (method === "password" && !mail && draft.password === "forbidden") return "Without mail settings, password sign-in stays on so nobody is locked out.";
24
- if (method === "staffAccess" && !mail && draft.staffAccess === "notify") return "Needs mail settings (PROTOBASE_SMTP_URL and PROTOBASE_MAIL_FROM): staff cannot sign in until they are set.";
25
- if (method === "platformSignIn" && draft.platformSignIn === "allowed" && (draft.passkey === "required" || draft.twoFactor === "required")) return "Off while passkeys or two-factor authentication are required: it skips the second step.";
26
- if (draft[method] === policy[method] && effective[method] !== policy[method]) return `Applies as ${ruleLabel(method, effective[method])} for now.`;
23
+ if (method === "emailCode" && !mail) return text("codeNeedsMail");
24
+ if (method === "password" && !mail && draft.password === "forbidden") return text("passwordStaysOn");
25
+ if (method === "staffAccess" && !mail && draft.staffAccess === "notify") return text("staffNeedsMail");
26
+ if (method === "platformSignIn" && draft.platformSignIn === "allowed" && (draft.passkey === "required" || draft.twoFactor === "required")) return text("platformOff");
27
+ if (draft[method] === policy[method] && effective[method] !== policy[method]) return text("appliesAs", ruleLabel(method, effective[method]));
27
28
  };
28
- const rowsFor = ({ operator, platformSignIn }) => policyRows.flatMap((row) => {
29
+ const rowsFor = ({ operator, platformSignIn }) => policyRows().flatMap((row) => {
29
30
  if (row.method === "staffAccess" && !operator) return [];
30
31
  if (row.method === "platformSignIn") return platformSignIn ? [{
31
32
  ...row,
32
- label: `Sign in with ${platformSignIn} through the platform`
33
+ label: text("platformSignInWith", platformSignIn)
33
34
  }] : [];
34
35
  return [row];
35
36
  });
@@ -84,30 +85,30 @@ const SignInPolicyForm = ({ state, onSave, busy, error, notice }) => {
84
85
  }),
85
86
  error && /* @__PURE__ */ jsx("p", {
86
87
  role: "alert",
87
- className: "rounded-md bg-danger-soft px-3 py-2 text-xs font-medium text-danger-text",
88
+ className: "rounded-md bg-danger-soft px-3 py-2 text-body font-medium text-danger-text",
88
89
  children: error
89
90
  }),
90
91
  notice && !changed && /* @__PURE__ */ jsx("p", {
91
92
  role: "status",
92
- className: "rounded-md bg-success-soft px-3 py-2 text-xs font-medium text-success-text",
93
+ className: "rounded-md bg-success-soft px-3 py-2 text-body font-medium text-success-text",
93
94
  children: notice
94
95
  }),
95
96
  /* @__PURE__ */ jsxs("div", {
96
97
  className: "flex flex-wrap items-center justify-between gap-3",
97
98
  children: [/* @__PURE__ */ jsx("p", {
98
99
  className: "text-xs text-muted-foreground",
99
- children: state.savedAt ? `Last saved${state.savedBy ? ` by ${state.savedBy}` : ""} on ${formatDateTime(Date.parse(state.savedAt))}.` : "Never changed: everything is on, nothing is required."
100
+ children: state.savedAt ? state.savedBy ? text("lastSavedBy", state.savedBy, formatDateTime(Date.parse(state.savedAt))) : text("lastSaved", formatDateTime(Date.parse(state.savedAt))) : text("neverChanged")
100
101
  }), /* @__PURE__ */ jsxs("div", {
101
102
  className: "flex gap-2",
102
103
  children: [changed && /* @__PURE__ */ jsx(Button, {
103
104
  onClick: () => setDraft(state.policy),
104
- children: "Reset"
105
+ children: text("reset")
105
106
  }), /* @__PURE__ */ jsx(Button, {
106
107
  variant: "primary",
107
108
  type: "submit",
108
109
  loading: busy,
109
110
  disabled: !changed,
110
- children: "Save"
111
+ children: text("save")
111
112
  })]
112
113
  })]
113
114
  })