@eifi1/ui-kit 0.30.0 → 0.31.0

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 (254) hide show
  1. package/README.md +42 -5
  2. package/dist/account/data-export-setting.js +3 -2
  3. package/dist/account/data-export-setting.js.map +1 -1
  4. package/dist/account/delete-account-setting.d.ts +5 -1
  5. package/dist/account/delete-account-setting.js +3 -2
  6. package/dist/account/delete-account-setting.js.map +1 -1
  7. package/dist/account/email-change-setting.js +4 -3
  8. package/dist/account/email-change-setting.js.map +1 -1
  9. package/dist/account/sessions-setting.js +3 -2
  10. package/dist/account/sessions-setting.js.map +1 -1
  11. package/dist/admin/admin-action-confirm.d.ts +5 -1
  12. package/dist/admin/invitations-panel.d.ts +5 -1
  13. package/dist/admin/invitations-panel.js +3 -2
  14. package/dist/admin/invitations-panel.js.map +1 -1
  15. package/dist/admin/reviewer-scope-editor.d.ts +5 -1
  16. package/dist/admin/role-select.d.ts +5 -1
  17. package/dist/admin/transfer-ownership-dialog.d.ts +5 -1
  18. package/dist/admin/user-roster.d.ts +5 -1
  19. package/dist/auth/auth-errors.d.ts +24 -6
  20. package/dist/auth/auth-errors.js +7 -1
  21. package/dist/auth/auth-errors.js.map +1 -1
  22. package/dist/auth/register-form.d.ts +5 -1
  23. package/dist/auth/sign-in-form.d.ts +15 -1
  24. package/dist/auth/sign-in-form.js +12 -3
  25. package/dist/auth/sign-in-form.js.map +1 -1
  26. package/dist/chart.d.ts +5 -1
  27. package/dist/components/account-settings-labels.d.ts +12 -0
  28. package/dist/components/account-settings-labels.js +2 -1
  29. package/dist/components/account-settings-labels.js.map +1 -1
  30. package/dist/components/account-settings.d.ts +8 -2
  31. package/dist/components/account-settings.js +19 -11
  32. package/dist/components/account-settings.js.map +1 -1
  33. package/dist/components/amount-input.d.ts +5 -1
  34. package/dist/components/button-group.d.ts +5 -1
  35. package/dist/components/calculator.d.ts +5 -1
  36. package/dist/components/confirm-dialog.d.ts +5 -1
  37. package/dist/components/copy-button.d.ts +5 -1
  38. package/dist/components/danger-confirm.d.ts +5 -1
  39. package/dist/components/data-table.js +8 -1
  40. package/dist/components/data-table.js.map +1 -1
  41. package/dist/components/date-picker.js +9 -4
  42. package/dist/components/date-picker.js.map +1 -1
  43. package/dist/components/facing-pair.d.ts +5 -1
  44. package/dist/components/file-button.d.ts +5 -1
  45. package/dist/components/file-dropzone.d.ts +5 -1
  46. package/dist/components/form-actions.d.ts +5 -1
  47. package/dist/components/iban-input.d.ts +5 -1
  48. package/dist/components/language-select.d.ts +5 -1
  49. package/dist/components/legal-page.d.ts +5 -1
  50. package/dist/components/legal.d.ts +5 -1
  51. package/dist/components/money-field.d.ts +5 -1
  52. package/dist/components/number-field.d.ts +5 -1
  53. package/dist/components/number-input.d.ts +5 -1
  54. package/dist/components/numpad-sheet.d.ts +5 -1
  55. package/dist/components/passkeys-setting.js +2 -1
  56. package/dist/components/passkeys-setting.js.map +1 -1
  57. package/dist/components/phone-input.d.ts +5 -1
  58. package/dist/components/series-chart.d.ts +5 -1
  59. package/dist/components/settings-fields.d.ts +40 -3
  60. package/dist/components/settings-fields.js +20 -1
  61. package/dist/components/settings-fields.js.map +1 -1
  62. package/dist/components/share-card.d.ts +5 -1
  63. package/dist/components/text-link.d.ts +5 -1
  64. package/dist/components/time-input.d.ts +5 -1
  65. package/dist/components/ui.d.ts +5 -1
  66. package/dist/{delete-account-setting-CGVMckMw.d.ts → delete-account-setting-DCFS5Vof.d.ts} +52 -23
  67. package/dist/demo/demo-banner.d.ts +51 -0
  68. package/dist/demo/demo-banner.js +97 -0
  69. package/dist/demo/demo-banner.js.map +1 -0
  70. package/dist/demo/demo-countdown.d.ts +58 -0
  71. package/dist/demo/demo-countdown.js +79 -0
  72. package/dist/demo/demo-countdown.js.map +1 -0
  73. package/dist/demo/demo-ended.d.ts +45 -0
  74. package/dist/demo/demo-ended.js +42 -0
  75. package/dist/demo/demo-ended.js.map +1 -0
  76. package/dist/demo/demo-labels.d.ts +53 -0
  77. package/dist/demo/demo-labels.js +29 -0
  78. package/dist/demo/demo-labels.js.map +1 -0
  79. package/dist/demo/demo-session.d.ts +30 -0
  80. package/dist/demo/demo-session.js +8 -0
  81. package/dist/demo/demo-session.js.map +1 -0
  82. package/dist/demo/demo-start.d.ts +54 -0
  83. package/dist/demo/demo-start.js +68 -0
  84. package/dist/demo/demo-start.js.map +1 -0
  85. package/dist/feedback/feedback-attachment.d.ts +5 -1
  86. package/dist/feedback/feedback-context.d.ts +5 -1
  87. package/dist/feedback/feedback-crash.d.ts +5 -1
  88. package/dist/feedback/feedback-dialog.d.ts +5 -1
  89. package/dist/feedback/feedback-inbox.d.ts +5 -1
  90. package/dist/feedback/feedback-inbox.js +12 -2
  91. package/dist/feedback/feedback-inbox.js.map +1 -1
  92. package/dist/feedback/feedback-labels.d.ts +5 -1
  93. package/dist/feedback/feedback-labels.js +1 -0
  94. package/dist/feedback/feedback-labels.js.map +1 -1
  95. package/dist/feedback/feedback-menu.d.ts +5 -1
  96. package/dist/feedback/feedback-record.d.ts +5 -1
  97. package/dist/feedback/feedback-record.js +2 -0
  98. package/dist/feedback/feedback-record.js.map +1 -1
  99. package/dist/feedback/feedback-row-detail.d.ts +5 -1
  100. package/dist/feedback/feedback-row-detail.js +7 -0
  101. package/dist/feedback/feedback-row-detail.js.map +1 -1
  102. package/dist/feedback/feedback-status-undo.d.ts +5 -1
  103. package/dist/feedback/feedback-submit.d.ts +5 -1
  104. package/dist/feedback/feedback-swipe.d.ts +6 -2
  105. package/dist/feedback/feedback-swipe.js.map +1 -1
  106. package/dist/feedback/feedback-table.d.ts +5 -1
  107. package/dist/feedback/feedback-thread.d.ts +5 -1
  108. package/dist/feedback.d.ts +5 -1
  109. package/dist/hooks/use-file-drop.d.ts +5 -1
  110. package/dist/i18n/defaults.d.ts +5 -1
  111. package/dist/i18n/defaults.js +6 -0
  112. package/dist/i18n/defaults.js.map +1 -1
  113. package/dist/i18n/german.d.ts +5 -1
  114. package/dist/i18n/german.js +84 -2
  115. package/dist/i18n/german.js.map +1 -1
  116. package/dist/i18n/kit-labels.d.ts +5 -1
  117. package/dist/i18n/kit-labels.js.map +1 -1
  118. package/dist/i18n/languages.d.ts +5 -1
  119. package/dist/i18n/locales/de-CH.d.ts +5 -1
  120. package/dist/i18n/locales/en.d.ts +5 -1
  121. package/dist/i18n/locales/es.d.ts +5 -1
  122. package/dist/i18n/locales/es.js +81 -2
  123. package/dist/i18n/locales/es.js.map +1 -1
  124. package/dist/i18n/locales/fr.d.ts +5 -1
  125. package/dist/i18n/locales/fr.js +82 -2
  126. package/dist/i18n/locales/fr.js.map +1 -1
  127. package/dist/i18n/locales/hu.d.ts +5 -1
  128. package/dist/i18n/locales/hu.js +82 -2
  129. package/dist/i18n/locales/hu.js.map +1 -1
  130. package/dist/i18n/locales/it.d.ts +5 -1
  131. package/dist/i18n/locales/it.js +81 -2
  132. package/dist/i18n/locales/it.js.map +1 -1
  133. package/dist/i18n/locales/zh.d.ts +5 -1
  134. package/dist/i18n/locales/zh.js +80 -2
  135. package/dist/i18n/locales/zh.js.map +1 -1
  136. package/dist/i18n/review.d.ts +5 -1
  137. package/dist/i18n/review.js +14 -1
  138. package/dist/i18n/review.js.map +1 -1
  139. package/dist/index.d.ts +25 -3
  140. package/dist/index.js +95 -0
  141. package/dist/index.js.map +1 -1
  142. package/dist/landing/access.d.ts +48 -0
  143. package/dist/landing/access.js +38 -0
  144. package/dist/landing/access.js.map +1 -0
  145. package/dist/landing/landing-actions.d.ts +138 -0
  146. package/dist/landing/landing-actions.js +39 -0
  147. package/dist/landing/landing-actions.js.map +1 -0
  148. package/dist/landing/landing-labels.d.ts +43 -0
  149. package/dist/landing/landing-labels.js +23 -0
  150. package/dist/landing/landing-labels.js.map +1 -0
  151. package/dist/landing/landing-sections.d.ts +218 -0
  152. package/dist/landing/landing-sections.js +167 -0
  153. package/dist/landing/landing-sections.js.map +1 -0
  154. package/dist/landing/page-seo.d.ts +99 -0
  155. package/dist/landing/page-seo.js +121 -0
  156. package/dist/landing/page-seo.js.map +1 -0
  157. package/dist/landing/public-header.d.ts +148 -0
  158. package/dist/landing/public-header.js +49 -0
  159. package/dist/landing/public-header.js.map +1 -0
  160. package/dist/landing/routing.d.ts +218 -0
  161. package/dist/landing/routing.js +81 -0
  162. package/dist/landing/routing.js.map +1 -0
  163. package/dist/rhf/fields.d.ts +5 -1
  164. package/dist/rhf/form.d.ts +5 -1
  165. package/dist/rhf.d.ts +5 -1
  166. package/dist/settings/settings-catalogue.d.ts +84 -0
  167. package/dist/settings/settings-catalogue.js +47 -0
  168. package/dist/settings/settings-catalogue.js.map +1 -0
  169. package/dist/settings/settings-context.d.ts +31 -0
  170. package/dist/settings/settings-context.js +11 -0
  171. package/dist/settings/settings-context.js.map +1 -0
  172. package/dist/settings/settings-heading.d.ts +50 -0
  173. package/dist/settings/settings-heading.js +27 -0
  174. package/dist/settings/settings-heading.js.map +1 -0
  175. package/dist/settings/settings-labels.d.ts +41 -0
  176. package/dist/settings/settings-labels.js +38 -0
  177. package/dist/settings/settings-labels.js.map +1 -0
  178. package/dist/settings/settings-layout.d.ts +77 -0
  179. package/dist/settings/settings-layout.js +242 -0
  180. package/dist/settings/settings-layout.js.map +1 -0
  181. package/dist/settings/settings-section.d.ts +133 -0
  182. package/dist/settings/settings-section.js +63 -0
  183. package/dist/settings/settings-section.js.map +1 -0
  184. package/dist/settings/use-account-language.d.ts +83 -0
  185. package/dist/settings/use-account-language.js +62 -0
  186. package/dist/settings/use-account-language.js.map +1 -0
  187. package/dist/settings/use-settings-focus.d.ts +34 -0
  188. package/dist/settings/use-settings-focus.js +77 -0
  189. package/dist/settings/use-settings-focus.js.map +1 -0
  190. package/dist/settings/use-settings-route.d.ts +118 -0
  191. package/dist/settings/use-settings-route.js +120 -0
  192. package/dist/settings/use-settings-route.js.map +1 -0
  193. package/dist/shell/app-shell.d.ts +11 -1
  194. package/dist/shell/app-shell.js +3 -2
  195. package/dist/shell/app-shell.js.map +1 -1
  196. package/dist/shell/top-bar-brand.d.ts +5 -1
  197. package/dist/shell.d.ts +15 -1
  198. package/dist/shell.js +56 -0
  199. package/dist/shell.js.map +1 -1
  200. package/dist/wizard/stepper-nav.d.ts +5 -1
  201. package/dist/wizard.d.ts +5 -1
  202. package/package.json +2 -1
  203. package/src/account/data-export-setting.tsx +3 -2
  204. package/src/account/delete-account-setting.tsx +3 -2
  205. package/src/account/email-change-setting.tsx +4 -7
  206. package/src/account/sessions-setting.tsx +3 -2
  207. package/src/admin/invitations-panel.tsx +11 -4
  208. package/src/auth/auth-errors.ts +36 -5
  209. package/src/auth/sign-in-form.tsx +34 -3
  210. package/src/components/account-settings-labels.ts +13 -0
  211. package/src/components/account-settings.tsx +33 -12
  212. package/src/components/data-table.tsx +8 -0
  213. package/src/components/date-picker.tsx +9 -4
  214. package/src/components/passkeys-setting.tsx +2 -1
  215. package/src/components/settings-fields.tsx +50 -1
  216. package/src/demo/demo-banner.tsx +159 -0
  217. package/src/demo/demo-countdown.ts +141 -0
  218. package/src/demo/demo-ended.tsx +89 -0
  219. package/src/demo/demo-labels.ts +78 -0
  220. package/src/demo/demo-session.ts +32 -0
  221. package/src/demo/demo-start.tsx +150 -0
  222. package/src/feedback/feedback-inbox.tsx +21 -8
  223. package/src/feedback/feedback-labels.ts +2 -1
  224. package/src/feedback/feedback-record.ts +10 -7
  225. package/src/feedback/feedback-row-detail.tsx +28 -4
  226. package/src/feedback/feedback-swipe.tsx +1 -1
  227. package/src/i18n/defaults.ts +6 -0
  228. package/src/i18n/german.ts +86 -0
  229. package/src/i18n/kit-labels.tsx +9 -0
  230. package/src/i18n/locales/es.ts +83 -0
  231. package/src/i18n/locales/fr.ts +84 -0
  232. package/src/i18n/locales/hu.ts +84 -0
  233. package/src/i18n/locales/it.ts +83 -0
  234. package/src/i18n/locales/zh.ts +81 -0
  235. package/src/i18n/review.ts +13 -0
  236. package/src/index.ts +92 -1
  237. package/src/landing/access.ts +97 -0
  238. package/src/landing/landing-actions.tsx +92 -0
  239. package/src/landing/landing-labels.ts +59 -0
  240. package/src/landing/landing-sections.tsx +337 -0
  241. package/src/landing/page-seo.ts +251 -0
  242. package/src/landing/public-header.tsx +120 -0
  243. package/src/landing/routing.tsx +209 -0
  244. package/src/settings/settings-catalogue.ts +132 -0
  245. package/src/settings/settings-context.ts +33 -0
  246. package/src/settings/settings-heading.tsx +65 -0
  247. package/src/settings/settings-labels.ts +75 -0
  248. package/src/settings/settings-layout.tsx +379 -0
  249. package/src/settings/settings-section.tsx +108 -0
  250. package/src/settings/use-account-language.ts +146 -0
  251. package/src/settings/use-settings-focus.ts +120 -0
  252. package/src/settings/use-settings-route.ts +258 -0
  253. package/src/shell/app-shell.tsx +10 -2
  254. package/src/shell.ts +45 -0
@@ -4,6 +4,7 @@ import {
4
4
  Ban,
5
5
  Bug,
6
6
  CheckCircle2,
7
+ ClipboardCheck,
7
8
  CloudUpload,
8
9
  Eye,
9
10
  HelpCircle,
@@ -55,13 +56,16 @@ import { useFeedbackCategoryLabels, useFeedbackStatusLabels } from "./feedback-l
55
56
  * a `label` the caller passes still wins.
56
57
  */
57
58
 
58
- /** The seven states a report can be in.
59
+ /** The eight states a report can be in.
59
60
  *
60
- * Shared value for value across both apps on purpose: it is what lets one habit,
61
- * and one agent prompt, work on either repo. Four are a chain and three sit off
62
- * it — see {@link visibleFeedbackStatuses} for what that buys. */
61
+ * Shared value for value across the apps on purpose: it is what lets one habit,
62
+ * and one agent prompt, work on any repo. Five are a chain and three sit off
63
+ * it — see {@link visibleFeedbackStatuses} for what that buys. `READY` joined in 0.31
64
+ * (feedback contract §8.2): OPEN is "filed, not yet triaged", READY "released for
65
+ * implementation", and nobody works an OPEN row. */
63
66
  export type FeedbackStatus =
64
67
  | "OPEN"
68
+ | "READY"
65
69
  | "IN_PROGRESS"
66
70
  | "IN_EVALUATION"
67
71
  | "NEEDS_LIVE_TEST"
@@ -81,7 +85,7 @@ export type FeedbackCategory = "CRASH" | "BUG" | "IDEA" | "QUESTION" | "OTHER";
81
85
  * its own shape as well. Declaration order is chain order, and
82
86
  * {@link FEEDBACK_STATUS_ORDER} is derived from it rather than restated, because
83
87
  * a restated list cannot be checked for exhaustiveness: an eighth status would
84
- * break the build here and leave a literal seven long.
88
+ * break the build here and leave a literal eight long (as READY did in 0.31).
85
89
  */
86
90
  export const FEEDBACK_STATUS_META: Record<
87
91
  FeedbackStatus,
@@ -92,6 +96,15 @@ export const FEEDBACK_STATUS_META: Record<
92
96
  activeBg: "bg-[var(--bg-active)]",
93
97
  activeText: "text-[var(--text-primary)]",
94
98
  },
99
+ // Triaged and released for implementation (feedback contract §8.2, keksdose live
100
+ // #396): OPEN is "filed, nobody has looked yet", READY is "go". The brand tint at full
101
+ // strength, so it reads as the go-ahead beside OPEN's neutral fill and
102
+ // NEEDS_LIVE_TEST's muted brand.
103
+ READY: {
104
+ icon: ClipboardCheck,
105
+ activeBg: "bg-[var(--brand-bg)]",
106
+ activeText: "text-[var(--brand)]",
107
+ },
95
108
  IN_PROGRESS: {
96
109
  icon: Wrench,
97
110
  activeBg: "bg-[var(--warning-bg)]",
@@ -155,7 +168,7 @@ export const FEEDBACK_STATUS_ORDER = Object.keys(FEEDBACK_STATUS_META) as Feedba
155
168
  * through them to reach `DONE`. */
156
169
  const OFF_CHAIN: FeedbackStatus[] = ["NEEDS_LIVE_TEST", "POSTPONED", "WONT_DO"];
157
170
 
158
- const FORWARD_CHAIN: FeedbackStatus[] = ["OPEN", "IN_PROGRESS", "IN_EVALUATION", "DONE"];
171
+ const FORWARD_CHAIN: FeedbackStatus[] = ["OPEN", "READY", "IN_PROGRESS", "IN_EVALUATION", "DONE"];
159
172
 
160
173
  /** The next status along the chain, or null at the end (or off it, as `WONT_DO`
161
174
  * is). What a swipe-to-advance gesture commits. */
@@ -168,7 +181,7 @@ export function nextFeedbackStatus(current: FeedbackStatus): FeedbackStatus | nu
168
181
  * The steps that make sense from where a row currently stands.
169
182
  *
170
183
  * For the compact control in a table cell: it is a glanceable triage affordance,
171
- * and a row of seven icons in a cell is noise. One step forward, one step back
184
+ * and a row of eight icons in a cell is noise. One step forward, one step back
172
185
  * (so an item can be sent back for rework), and any of the three off-chain
173
186
  * verdicts — which is what makes those usable as verdicts at all.
174
187
  *
@@ -452,7 +465,7 @@ export function FeedbackStatusTransitions({
452
465
  ),
453
466
  // Both stay unclickable, but only the read-only case is DIMMED: the
454
467
  // current status is the one thing in the row that has to be legible
455
- // at a glance, and among seven pills a faded active one reads as
468
+ // at a glance, and among eight pills a faded active one reads as
456
469
  // "unavailable" rather than as "this is where the row stands".
457
470
  (!canEdit || active) && "cursor-default",
458
471
  !canEdit && "opacity-60",
@@ -24,7 +24,7 @@ import type { FeedbackCategory, FeedbackStatus } from "./feedback-inbox";
24
24
  * `feedbackStatus` — one word per status, keyed by the enum value so
25
25
  * `labels[row.status]` is the whole lookup.
26
26
  *
27
- * de-CH canon: OPEN "Offen" · IN_PROGRESS "In Bearbeitung" · IN_EVALUATION "Zur Prüfung"
27
+ * de-CH canon: OPEN "Offen" · READY "Bereit zur Umsetzung" · IN_PROGRESS "In Bearbeitung" · IN_EVALUATION "Zur Prüfung"
28
28
  * · NEEDS_LIVE_TEST "Live testen" · POSTPONED "Zurückgestellt" · DONE "Erledigt" ·
29
29
  * WONT_DO "Wird nicht umgesetzt".
30
30
  */
@@ -32,6 +32,7 @@ export type FeedbackStatusLabels = Record<FeedbackStatus, string>;
32
32
 
33
33
  export const DEFAULT_FEEDBACK_STATUS_LABELS: FeedbackStatusLabels = {
34
34
  OPEN: "Open",
35
+ READY: "Ready to implement",
35
36
  IN_PROGRESS: "In progress",
36
37
  IN_EVALUATION: "In evaluation",
37
38
  NEEDS_LIVE_TEST: "Test when live",
@@ -158,22 +158,25 @@ export const FEEDBACK_REWORKABLE_STATUSES: readonly FeedbackStatus[] = Object.fr
158
158
 
159
159
  /**
160
160
  * The statuses in which the AUTHOR may still edit title, body and category (§3.4,
161
- * keksdose `canAuthorEdit`, `feedback-page.tsx:398`): `OPEN` and `IN_PROGRESS`. Once the
162
- * team has answered, the description is what they answered and stays as it was; a
163
- * correction goes in as a rework.
161
+ * keksdose `canAuthorEdit`, `feedback-page.tsx:398`): `OPEN`, `READY` and `IN_PROGRESS`.
162
+ * Once the team has answered, the description is what they answered and stays as it
163
+ * was; a correction goes in as a rework.
164
164
  */
165
165
  export const FEEDBACK_AUTHOR_EDITABLE_STATUSES: readonly FeedbackStatus[] = Object.freeze([
166
166
  "OPEN",
167
+ "READY",
167
168
  "IN_PROGRESS",
168
169
  ] as const);
169
170
 
170
171
  /**
171
- * The two statuses that wait on the person triaging: answered and handed back for a
172
- * verdict, or answered and only checkable on a deployed build (keksdose
173
- * `AWAITING_VERDICT`, live #330). The phone's "Only what is waiting for you" toggle
174
- * narrows the inbox to exactly these (§4.3).
172
+ * The statuses that wait on the person triaging: filed and not yet triaged (`OPEN`,
173
+ * since READY took over "released for implementation" in 0.31, feedback contract §8.2),
174
+ * answered and handed back for a verdict, or answered and only checkable on a deployed
175
+ * build (keksdose `AWAITING_VERDICT`, live #330). The phone's "Only what is waiting for
176
+ * you" toggle narrows the inbox to exactly these (§4.3).
175
177
  */
176
178
  export const FEEDBACK_AWAITING_STATUSES: readonly FeedbackStatus[] = Object.freeze([
179
+ "OPEN",
177
180
  "IN_EVALUATION",
178
181
  "NEEDS_LIVE_TEST",
179
182
  ] as const);
@@ -12,6 +12,7 @@ import { formatDate } from "../lib/format";
12
12
  import { DEFAULT_MAX_ATTACHMENT_BYTES } from "./feedback-attachment";
13
13
  import { DEFAULT_FEEDBACK_DIALOG_LABELS } from "./feedback-dialog";
14
14
  import {
15
+ FeedbackCategoryBadge,
15
16
  FeedbackDetail,
16
17
  FeedbackDetailSection,
17
18
  FeedbackNoteEditor,
@@ -63,8 +64,9 @@ import type { FeedbackStatusChange } from "./feedback-status-undo";
63
64
  * path (`/accounts?p=2`): keksdose's `new URL(…)` throws on one and the section
64
65
  * vanished. kastlan already fell back to `context.route` (`feedbackRaw`, `:97`).
65
66
  *
66
- * The sections, in the contract's order: **Description** (the body; the author's
67
- * Edit while OPEN / IN_PROGRESS), **URL**, **Attachment**, **Outcome** (the admin's
67
+ * The sections, in the contract's order: **Subject** (the category and the title, §8.1;
68
+ * `showSubject={false}` leaves it out), **Description** (the body; the author's
69
+ * Edit while OPEN / READY / IN_PROGRESS), **URL**, **Attachment**, **Outcome** (the admin's
68
70
  * outcome editor, Rework, Open page), **Send for rework** (only while reworking) and
69
71
  * **Status**. No comment thread (§2.2: kastlan's comments fold into the body, §7.7).
70
72
  *
@@ -81,7 +83,11 @@ import type { FeedbackStatusChange } from "./feedback-status-undo";
81
83
  * canon (keksdose `de-CH.json`, ss never ß, "Nacharbeit" throughout — §7.14) on each key.
82
84
  */
83
85
  export interface FeedbackDetailLabels {
84
- /** Section 1's heading — keksdose's `feedback.body` (§7.3). The dialog's field asks
86
+ /** The first section's heading: what the report is called (feedback contract §8.1,
87
+ * keksdose live #395 — with the row expanded and the table scrolled, nothing said
88
+ * which entry was being answered). de-CH: "Betreff" */
89
+ subject: string;
90
+ /** The description section's heading — keksdose's `feedback.body` (§7.3). The dialog's field asks
85
91
  * "What happened? (optional)"; the description, once filed, is headed as what it is
86
92
  * — and as the author's "Edit description" calls it. de-CH: "Beschreibung" */
87
93
  body: string;
@@ -140,6 +146,7 @@ export interface FeedbackDetailLabels {
140
146
  }
141
147
 
142
148
  export const DEFAULT_FEEDBACK_DETAIL_LABELS: FeedbackDetailLabels = {
149
+ subject: "Subject",
143
150
  body: "Description",
144
151
  edit: "Edit",
145
152
  editDescription: "Edit description",
@@ -316,7 +323,7 @@ function AttachmentDownload({
316
323
  export interface FeedbackRowAccess {
317
324
  /** The viewer filed it (`viewerId === row.user_id`; never for an erased author). */
318
325
  isAuthor: boolean;
319
- /** "Edit description": the author, while the row is OPEN or IN_PROGRESS — on either
326
+ /** "Edit description": the author, while the row is OPEN, READY or IN_PROGRESS — on either
320
327
  * page (keksdose `canAuthorEdit`, `feedback-page.tsx:398`, is not gated on `mine`). */
321
328
  canEditDescription: boolean;
322
329
  /** The outcome editor: the admin on the inbox (`canEdit`). */
@@ -563,6 +570,12 @@ export interface FeedbackRowDetailProps {
563
570
  * BUDGET, and a person viewing one still owns their own reports.
564
571
  */
565
572
  commit?: boolean;
573
+ /**
574
+ * Open with the subject: the category badge and the title (feedback contract §8.1,
575
+ * keksdose live #395). On by default; `false` for a page that already shows the title
576
+ * beside the detail.
577
+ */
578
+ showSubject?: boolean;
566
579
  labels?: Partial<FeedbackDetailLabels>;
567
580
  className?: string;
568
581
  }
@@ -603,6 +616,7 @@ export function FeedbackRowDetail({
603
616
  reworkAttachment,
604
617
  renderDate,
605
618
  commit,
619
+ showSubject = true,
606
620
  labels: labelsProp,
607
621
  className,
608
622
  }: FeedbackRowDetailProps) {
@@ -653,6 +667,16 @@ export function FeedbackRowDetail({
653
667
 
654
668
  return (
655
669
  <FeedbackDetail className={className}>
670
+ {showSubject && (
671
+ <FeedbackDetailSection title={labels.subject}>
672
+ <p className="flex flex-wrap items-center gap-x-2 gap-y-1 text-sm" data-feedback-subject="">
673
+ <FeedbackCategoryBadge category={row.category} />
674
+ <span className="min-w-0 font-medium text-[var(--text-primary)] [overflow-wrap:anywhere]">
675
+ {row.title}
676
+ </span>
677
+ </p>
678
+ </FeedbackDetailSection>
679
+ )}
656
680
  <FeedbackDetailSection
657
681
  title={labels.body}
658
682
  action={
@@ -10,7 +10,7 @@ import type { FeedbackStatusChange, FeedbackStatusRow } from "./feedback-status-
10
10
  * (`feedback-page.tsx:990`, feedback #144 rework item 4: *"it is a queue, and triaging it
11
11
  * one tap-into-the-row at a time is the slow way"*), for every app.
12
12
  *
13
- * - `advance` — one step along the chain (`nextFeedbackStatus`: OPEN → IN_PROGRESS →
13
+ * - `advance` — one step along the chain (`nextFeedbackStatus`: OPEN → READY → IN_PROGRESS →
14
14
  * IN_EVALUATION → DONE), labelled with the status it goes to;
15
15
  * - `done` — straight to DONE, for a row that plainly needs no stop on the way;
16
16
  * - `wont_do` — dismiss as WONT_DO.
@@ -81,6 +81,9 @@ import { DEFAULT_ADMIN_ACTION_LABELS } from "../admin/admin-action-confirm";
81
81
  import { DEFAULT_ADMIN_ACTION_LOG_LABELS } from "../admin/admin-action-log";
82
82
  import { DEFAULT_TRANSFER_OWNERSHIP_LABELS } from "../admin/transfer-ownership-dialog";
83
83
  import { DEFAULT_INVITATIONS_LABELS } from "../admin/invitations-panel";
84
+ import { DEFAULT_SETTINGS_LABELS } from "../settings/settings-labels";
85
+ import { DEFAULT_LANDING_LABELS } from "../landing/landing-labels";
86
+ import { DEFAULT_DEMO_LABELS } from "../demo/demo-labels";
84
87
  import { DEFAULT_ACCOUNT_STATE_LABELS } from "../components/account-chips";
85
88
  import { DEFAULT_SHARE_CARD_LABELS } from "../components/share-card";
86
89
  import { DEFAULT_REAUTH_DIALOG_LABELS } from "../components/reauth-dialog";
@@ -208,6 +211,9 @@ export const DEFAULT_UI_KIT_LABELS: UiKitLabels = {
208
211
  adminActionLog: DEFAULT_ADMIN_ACTION_LOG_LABELS,
209
212
  transferOwnership: DEFAULT_TRANSFER_OWNERSHIP_LABELS,
210
213
  invitations: DEFAULT_INVITATIONS_LABELS,
214
+ settings: DEFAULT_SETTINGS_LABELS,
215
+ landing: DEFAULT_LANDING_LABELS,
216
+ demo: DEFAULT_DEMO_LABELS,
211
217
  characterCount: DEFAULT_CHARACTER_COUNT_LABELS,
212
218
  countrySelect: DEFAULT_COUNTRY_SELECT_LABELS,
213
219
  inlineEdit: DEFAULT_INLINE_EDIT_LABELS,
@@ -79,6 +79,7 @@ export function germanLabels(numberLocale: string): UiKitLabels {
79
79
  // written here with "ß" like the rest of this source; `swiss()` makes it "grösser".
80
80
  feedbackStatus: {
81
81
  OPEN: "Offen",
82
+ READY: "Bereit zur Umsetzung",
82
83
  IN_PROGRESS: "In Bearbeitung",
83
84
  IN_EVALUATION: "Zur Prüfung",
84
85
  NEEDS_LIVE_TEST: "Live testen",
@@ -140,6 +141,7 @@ export function germanLabels(numberLocale: string): UiKitLabels {
140
141
  phoneActions: "Feedback-Aktionen",
141
142
  },
142
143
  feedbackDetail: {
144
+ subject: "Betreff",
143
145
  body: "Beschreibung",
144
146
  edit: "Bearbeiten",
145
147
  editDescription: "Beschreibung bearbeiten",
@@ -198,6 +200,8 @@ export function germanLabels(numberLocale: string): UiKitLabels {
198
200
  qrAlt: "QR-Code für die Authenticator-App",
199
201
  secretHint: "Scannen nicht möglich? Stattdessen diesen Schlüssel in der App eingeben:",
200
202
  copySecret: "Schlüssel kopieren",
203
+ // 0.31.0: the card's title; the state ("Aktiv") stands beside it.
204
+ title: "Zwei-Faktor-Authentifizierung",
201
205
  },
202
206
  passkeys: {
203
207
  title: "Passkeys",
@@ -908,6 +912,8 @@ export function germanLabels(numberLocale: string): UiKitLabels {
908
912
  `${n(length)} Buchstaben und Ziffern. Bindestriche und Leerzeichen spielen keine Rolle.`,
909
913
  recoveryCodeInvalid: "Dieser Backup-Code ist ungültig oder wurde schon verwendet.",
910
914
  rateLimited,
915
+ // 0.31.0: the same words as `landing.requestAccess`.
916
+ requestAccess: "Zugang anfragen",
911
917
  },
912
918
  register: {
913
919
  firstName: "Vorname",
@@ -1363,5 +1369,85 @@ export function germanLabels(numberLocale: string): UiKitLabels {
1363
1369
  ? `Den ungeprüften Text in „${group}“ bestätigen?`
1364
1370
  : `Alle ${n(count)} ungeprüften Texte in „${group}“ bestätigen – auch die nicht angezeigten?`,
1365
1371
  },
1372
+ // 0.31.0 — docs/settings-harmonization.md §4.3 and docs/landing-demo-harmonization.md
1373
+ // §4–§5: the settings shell, the landing page's generic words and the demo. The group
1374
+ // names are the contracts' ("Darstellung", "Konto", "Sicherheit", "Benachrichtigungen",
1375
+ // "Daten"); the help lines name things as `accountSettings`, `sessions` and
1376
+ // `dataExport` do. Formal "Sie".
1377
+ settings: {
1378
+ title: "Einstellungen",
1379
+ search: "Einstellungen durchsuchen",
1380
+ searchPlaceholder: "Einstellungen durchsuchen…",
1381
+ results: "Passende Einstellungen",
1382
+ noMatches: (query) => `Keine Einstellung passt zu „${query}“.`,
1383
+ // As `commandPalette.clear`.
1384
+ clearSearch: "Suche löschen",
1385
+ back: "Zurück zu den Einstellungen",
1386
+ sections: "Einstellungsbereiche",
1387
+ // "Treffer" is the same in singular and plural.
1388
+ matchCount: (count) => `${n(count)} Treffer`,
1389
+ groups: {
1390
+ appearance: {
1391
+ title: "Darstellung",
1392
+ // "Theme", as `topBar.theme`.
1393
+ help: "Sprache, Theme und wie die App auf diesem Gerät aussieht.",
1394
+ },
1395
+ account: {
1396
+ title: "Konto",
1397
+ help: "Ihr Profil und Ihre E-Mail-Adresse.",
1398
+ },
1399
+ security: {
1400
+ title: "Sicherheit",
1401
+ help: "Wie Sie sich anmelden: Passwort, Zwei-Faktor-Codes, Passkeys und Sitzungen.",
1402
+ },
1403
+ notifications: {
1404
+ title: "Benachrichtigungen",
1405
+ help: "Worüber Sie informiert werden, wann und auf welchen Geräten.",
1406
+ },
1407
+ data: {
1408
+ title: "Daten",
1409
+ help: "Ihre Daten exportieren oder zusammen mit Ihrem Konto löschen.",
1410
+ },
1411
+ },
1412
+ },
1413
+ landing: {
1414
+ signIn: "Anmelden",
1415
+ requestAccess: "Zugang anfragen",
1416
+ getStarted: "Jetzt starten",
1417
+ tryDemo: "Demo ausprobieren",
1418
+ openApp: "App öffnen",
1419
+ continueDemo: "Demo fortsetzen",
1420
+ beta: "Beta",
1421
+ // Plain text: a mail's subject and body lines, never HTML.
1422
+ accessSubject: (app) => (app ? `Zugang zu ${app}` : "Zugangsanfrage"),
1423
+ accessName: "Name:",
1424
+ // "Unternehmen", as `companySwitcher`.
1425
+ accessCompany: "Unternehmen:",
1426
+ accessUse: "Wofür Sie die App nutzen möchten:",
1427
+ },
1428
+ demo: {
1429
+ starting: "Demo wird gestartet…",
1430
+ rateLimited: (minutes) =>
1431
+ minutes
1432
+ ? `Zu viele Demos aus diesem Netzwerk. Versuchen Sie es in ${n(minutes)} min erneut.`
1433
+ : "Zu viele Demos aus diesem Netzwerk. Versuchen Sie es später erneut.",
1434
+ capacity: "Die Demo ist gerade ausgelastet. Versuchen Sie es später erneut.",
1435
+ unavailable: "Die Demo ist gerade nicht verfügbar.",
1436
+ failed: "Die Demo konnte nicht gestartet werden. Bitte versuchen Sie es erneut.",
1437
+ // As `legal.backHome`.
1438
+ backToStart: "Zurück zur Startseite",
1439
+ hoursLeft: (hours, minutes) => `Demo · noch ${n(hours)} h ${n(minutes)} min`,
1440
+ minutesLeft: (minutes) => `Demo · noch ${n(minutes)} min`,
1441
+ badge: "Demo",
1442
+ readOnly: "Sie sehen Beispieldaten. Änderungen sind nicht möglich.",
1443
+ sandbox: "Was Sie selbst anlegen, wird gelöscht, wenn die Demo endet.",
1444
+ details: "Demo-Details",
1445
+ writeLocked: "In der Demo nicht möglich.",
1446
+ endedTitle: "Die Demo ist beendet",
1447
+ endedReadOnly: "Die Beispieldaten werden regelmäßig zurückgesetzt.",
1448
+ endedSandbox:
1449
+ "Die Beispieldaten werden regelmäßig zurückgesetzt; was Sie in der Demo selbst angelegt haben, wird gelöscht.",
1450
+ restart: "Neue Demo starten",
1451
+ },
1366
1452
  };
1367
1453
  }
@@ -77,6 +77,9 @@ import type { AdminActionLabels } from "../admin/admin-action-confirm";
77
77
  import type { AdminActionLogLabels } from "../admin/admin-action-log";
78
78
  import type { TransferOwnershipLabels } from "../admin/transfer-ownership-dialog";
79
79
  import type { InvitationsLabels } from "../admin/invitations-panel";
80
+ import type { SettingsLabels } from "../settings/settings-labels";
81
+ import type { LandingLabels } from "../landing/landing-labels";
82
+ import type { DemoLabels } from "../demo/demo-labels";
80
83
  import type { AccountStateLabels } from "../components/account-chips";
81
84
  import type { ShareCardLabels } from "../components/share-card";
82
85
  import type { ReauthDialogLabels } from "../components/reauth-dialog";
@@ -383,6 +386,12 @@ export interface UiKitLabels {
383
386
  transferOwnership: TransferOwnershipLabels;
384
387
  /** 0.30.0: the invitations panel (§5). */
385
388
  invitations: InvitationsLabels;
389
+ /** 0.31.0: the settings and admin pages' shell (docs/settings-harmonization.md §4.3). */
390
+ settings: SettingsLabels;
391
+ /** 0.31.0: the public landing page's kit words (docs/landing-demo-harmonization.md §4). */
392
+ landing: LandingLabels;
393
+ /** 0.31.0: the demo's start, banner and end (§5). */
394
+ demo: DemoLabels;
386
395
  /** 0.22.0: the screen-reader words of `Input` / `Textarea`'s `showCount` counter. */
387
396
  characterCount: CharacterCountLabels;
388
397
  /** 0.22.0: `CountrySelect`. Its list's "no results" and counts are `combobox`'s. */
@@ -70,6 +70,7 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
70
70
  // 0.27.0. "Comentarios" for feedback, as `feedbackDialog`; "corrección" for rework.
71
71
  feedbackStatus: {
72
72
  OPEN: "Abierto",
73
+ READY: "Listo para implementar",
73
74
  IN_PROGRESS: "En curso",
74
75
  IN_EVALUATION: "En evaluación",
75
76
  NEEDS_LIVE_TEST: "Probar en producción",
@@ -131,6 +132,7 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
131
132
  phoneActions: "Acciones de comentarios",
132
133
  },
133
134
  feedbackDetail: {
135
+ subject: "Asunto",
134
136
  body: "Descripción",
135
137
  edit: "Editar",
136
138
  editDescription: "Editar descripción",
@@ -189,6 +191,8 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
189
191
  qrAlt: "Código QR para su app de autenticación",
190
192
  secretHint: "¿No puede escanearlo? Introduzca esta clave en la app:",
191
193
  copySecret: "Copiar clave",
194
+ // 0.31.0: the card's title; the state ("Activada") stands beside it.
195
+ title: "Verificación en dos pasos",
192
196
  },
193
197
  passkeys: {
194
198
  title: "Llaves de acceso",
@@ -887,6 +891,8 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
887
891
  `${n(length)} letras y dígitos. Los guiones y los espacios no importan.`,
888
892
  recoveryCodeInvalid: "Este código de respaldo no es válido o ya se ha usado.",
889
893
  rateLimited,
894
+ // 0.31.0: the same words as `landing.requestAccess`.
895
+ requestAccess: "Solicitar acceso",
890
896
  },
891
897
  register: {
892
898
  firstName: "Nombre",
@@ -1331,6 +1337,83 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
1331
1337
  ? `¿Aprobar el texto sin revisar de «${group}»?`
1332
1338
  : `¿Aprobar los ${n(count)} textos sin revisar de «${group}», incluidos los que no están en pantalla?`,
1333
1339
  },
1340
+ // 0.31.0 — docs/settings-harmonization.md §4.3 and docs/landing-demo-harmonization.md
1341
+ // §4–§5: the settings shell, the landing page's generic words and the demo. The help
1342
+ // lines name things as `accountSettings`, `sessions` and `dataExport` do. "Usted".
1343
+ // "Ajustes" (es-ES), a countable noun: "Ningún ajuste coincide…".
1344
+ settings: {
1345
+ title: "Ajustes",
1346
+ search: "Buscar en los ajustes",
1347
+ searchPlaceholder: "Buscar en los ajustes…",
1348
+ results: "Ajustes coincidentes",
1349
+ noMatches: (query) => `Ningún ajuste coincide con «${query}».`,
1350
+ // As `commandPalette.clear`.
1351
+ clearSearch: "Borrar búsqueda",
1352
+ back: "Volver a los ajustes",
1353
+ sections: "Secciones de los ajustes",
1354
+ matchCount: (count) => `${n(count)} ${plural(count, "resultado", "resultados")}`,
1355
+ groups: {
1356
+ appearance: {
1357
+ title: "Apariencia",
1358
+ help: "Idioma, tema y aspecto de la aplicación en este dispositivo.",
1359
+ },
1360
+ account: {
1361
+ title: "Cuenta",
1362
+ help: "Su perfil y su dirección de correo electrónico.",
1363
+ },
1364
+ security: {
1365
+ title: "Seguridad",
1366
+ help: "Cómo inicia sesión: contraseña, verificación en dos pasos, llaves de acceso y sesiones.",
1367
+ },
1368
+ notifications: {
1369
+ title: "Notificaciones",
1370
+ help: "Qué notificaciones recibe, cuándo y en qué dispositivos.",
1371
+ },
1372
+ data: {
1373
+ title: "Datos",
1374
+ help: "Exporte lo que es suyo o elimínelo junto con su cuenta.",
1375
+ },
1376
+ },
1377
+ },
1378
+ landing: {
1379
+ signIn: "Iniciar sesión",
1380
+ requestAccess: "Solicitar acceso",
1381
+ getStarted: "Empezar",
1382
+ tryDemo: "Probar la demo",
1383
+ openApp: "Abrir la aplicación",
1384
+ continueDemo: "Continuar la demo",
1385
+ beta: "Beta",
1386
+ // Plain text: a mail's subject and body lines, never HTML.
1387
+ accessSubject: (app) => (app ? `Acceso a ${app}` : "Solicitud de acceso"),
1388
+ accessName: "Nombre:",
1389
+ accessCompany: "Empresa:",
1390
+ accessUse: "Uso previsto:",
1391
+ },
1392
+ demo: {
1393
+ starting: "Iniciando la demo…",
1394
+ rateLimited: (minutes) =>
1395
+ minutes
1396
+ ? `Demasiadas demos desde esta red. Inténtelo de nuevo en ${n(minutes)} min.`
1397
+ : "Demasiadas demos desde esta red. Inténtelo de nuevo más tarde.",
1398
+ capacity: "La demo está completa en este momento. Inténtelo de nuevo más tarde.",
1399
+ unavailable: "La demo no está disponible en este momento.",
1400
+ failed: "No se pudo iniciar la demo. Inténtelo de nuevo.",
1401
+ // As `legal.backHome`.
1402
+ backToStart: "Volver al inicio",
1403
+ // Hours and minutes together are plural; minutes alone agree with the count.
1404
+ hoursLeft: (hours, minutes) => `Demo · quedan ${n(hours)} h ${n(minutes)} min`,
1405
+ minutesLeft: (minutes) => `Demo · ${plural(minutes, "queda", "quedan")} ${n(minutes)} min`,
1406
+ badge: "Demo",
1407
+ readOnly: "Está viendo datos de ejemplo. No es posible hacer cambios.",
1408
+ sandbox: "Su propio trabajo se elimina cuando termina la demo.",
1409
+ details: "Detalles de la demo",
1410
+ writeLocked: "No es posible en la demo.",
1411
+ endedTitle: "La demo ha terminado",
1412
+ endedReadOnly: "Los datos de ejemplo se restablecen con regularidad.",
1413
+ endedSandbox:
1414
+ "Los datos de ejemplo se restablecen con regularidad; su propio trabajo en la demo se elimina.",
1415
+ restart: "Iniciar una nueva demo",
1416
+ },
1334
1417
  };
1335
1418
  }
1336
1419
 
@@ -70,6 +70,7 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
70
70
  // 0.27.0. "Retour" for feedback, as `feedbackDialog`; "reprise" for rework.
71
71
  feedbackStatus: {
72
72
  OPEN: "Ouvert",
73
+ READY: "Prêt à implémenter",
73
74
  IN_PROGRESS: "En cours",
74
75
  IN_EVALUATION: "En évaluation",
75
76
  NEEDS_LIVE_TEST: "À tester en production",
@@ -129,6 +130,7 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
129
130
  phoneActions: "Actions sur les retours",
130
131
  },
131
132
  feedbackDetail: {
133
+ subject: "Objet",
132
134
  body: "Description",
133
135
  edit: "Modifier",
134
136
  editDescription: "Modifier la description",
@@ -189,6 +191,8 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
189
191
  qrAlt: "Code QR pour votre application d’authentification",
190
192
  secretHint: "Impossible de le scanner\u202f? Saisissez plutôt cette clé dans l’application\u00a0:",
191
193
  copySecret: "Copier la clé",
194
+ // 0.31.0: the card's title; the state ("Activée") stands beside it.
195
+ title: "Authentification à deux facteurs",
192
196
  },
193
197
  passkeys: {
194
198
  title: "Clés d’accès",
@@ -909,6 +913,8 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
909
913
  `${n(length)} lettres et chiffres. Les tirets et les espaces ne comptent pas.`,
910
914
  recoveryCodeInvalid: "Ce code de secours n’est pas valable ou a déjà été utilisé.",
911
915
  rateLimited,
916
+ // 0.31.0: the same words as `landing.requestAccess`.
917
+ requestAccess: "Demander l’accès",
912
918
  },
913
919
  register: {
914
920
  firstName: "Prénom",
@@ -1358,6 +1364,84 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
1358
1364
  ? `Approuver le texte non relu de «\u202f${group}\u202f»\u202f?`
1359
1365
  : `Approuver les ${n(count)} textes non relus de «\u202f${group}\u202f», y compris ceux qui ne sont pas à l’écran\u202f?`,
1360
1366
  },
1367
+ // 0.31.0 — docs/settings-harmonization.md §4.3 and docs/landing-demo-harmonization.md
1368
+ // §4–§5: the settings shell, the landing page's generic words and the demo. The help
1369
+ // lines name things as `accountSettings`, `sessions` and `dataExport` do, and no
1370
+ // sentence about the reader needs a gender ("informé·e").
1371
+ settings: {
1372
+ title: "Paramètres",
1373
+ search: "Rechercher dans les paramètres",
1374
+ searchPlaceholder: "Rechercher dans les paramètres…",
1375
+ results: "Paramètres correspondants",
1376
+ noMatches: (query) => `Aucun paramètre ne correspond à «\u202f${query}\u202f».`,
1377
+ // As `commandPalette.clear`.
1378
+ clearSearch: "Effacer la recherche",
1379
+ back: "Retour aux paramètres",
1380
+ sections: "Sections des paramètres",
1381
+ matchCount: (count) => `${n(count)} ${plural(count, "résultat", "résultats")}`,
1382
+ groups: {
1383
+ appearance: {
1384
+ title: "Apparence",
1385
+ help: "Langue, thème et apparence de l’application sur cet appareil.",
1386
+ },
1387
+ account: {
1388
+ title: "Compte",
1389
+ help: "Votre profil et votre adresse e-mail.",
1390
+ },
1391
+ security: {
1392
+ title: "Sécurité",
1393
+ help: "Comment vous vous connectez\u00a0: mot de passe, codes 2FA, clés d’accès et sessions.",
1394
+ },
1395
+ notifications: {
1396
+ title: "Notifications",
1397
+ help: "Quelles notifications vous recevez, quand et sur quels appareils.",
1398
+ },
1399
+ data: {
1400
+ title: "Données",
1401
+ help: "Exportez ce qui vous appartient, ou supprimez-le avec votre compte.",
1402
+ },
1403
+ },
1404
+ },
1405
+ landing: {
1406
+ signIn: "Se connecter",
1407
+ requestAccess: "Demander l’accès",
1408
+ getStarted: "Commencer",
1409
+ tryDemo: "Essayer la démo",
1410
+ openApp: "Ouvrir l’application",
1411
+ continueDemo: "Continuer la démo",
1412
+ // As `legal.notice` ("Bêta fermée").
1413
+ beta: "Bêta",
1414
+ // Plain text: a mail's subject and body lines, never HTML. The no-break space
1415
+ // before the colon, as everywhere in this catalogue.
1416
+ accessSubject: (app) => (app ? `Accès à ${app}` : "Demande d’accès"),
1417
+ accessName: "Nom\u00a0:",
1418
+ accessCompany: "Entreprise\u00a0:",
1419
+ accessUse: "Utilisation prévue\u00a0:",
1420
+ },
1421
+ demo: {
1422
+ starting: "Démarrage de la démo…",
1423
+ rateLimited: (minutes) =>
1424
+ minutes
1425
+ ? `Trop de démos depuis ce réseau. Réessayez dans ${n(minutes)}\u00a0min.`
1426
+ : "Trop de démos depuis ce réseau. Réessayez plus tard.",
1427
+ capacity: "La démo est complète pour le moment. Réessayez plus tard.",
1428
+ unavailable: "La démo n’est pas disponible pour le moment.",
1429
+ failed: "La démo n’a pas pu être lancée. Veuillez réessayer.",
1430
+ // As `legal.backHome`.
1431
+ backToStart: "Retour à l’accueil",
1432
+ hoursLeft: (hours, minutes) => `Démo · il reste ${n(hours)}\u00a0h ${n(minutes)}\u00a0min`,
1433
+ minutesLeft: (minutes) => `Démo · il reste ${n(minutes)}\u00a0min`,
1434
+ badge: "Démo",
1435
+ readOnly: "Vous consultez des données d’exemple. Aucune modification n’est possible.",
1436
+ sandbox: "Ce que vous créez vous-même est supprimé à la fin de la démo.",
1437
+ details: "Détails de la démo",
1438
+ writeLocked: "Impossible dans la démo.",
1439
+ endedTitle: "La démo est terminée",
1440
+ endedReadOnly: "Les données d’exemple sont réinitialisées régulièrement.",
1441
+ endedSandbox:
1442
+ "Les données d’exemple sont réinitialisées régulièrement\u202f; ce que vous avez créé dans la démo est supprimé.",
1443
+ restart: "Lancer une nouvelle démo",
1444
+ },
1361
1445
  };
1362
1446
  }
1363
1447