@eifi1/ui-kit 0.43.0 → 0.45.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.
- package/README.md +11 -7
- package/dist/admin/admin-action-log-labels.js +9 -0
- package/dist/admin/admin-action-log-labels.js.map +1 -1
- package/dist/admin/admin-action-log.d.ts +18 -1
- package/dist/admin/admin-action-log.js +25 -16
- package/dist/admin/admin-action-log.js.map +1 -1
- package/dist/admin/admin-area-labels.d.ts +6 -0
- package/dist/admin/admin-area-labels.js +1 -0
- package/dist/admin/admin-area-labels.js.map +1 -1
- package/dist/admin/mail-test-card-labels.d.ts +3 -0
- package/dist/admin/mail-test-card-labels.js +17 -0
- package/dist/admin/mail-test-card-labels.js.map +1 -0
- package/dist/admin/mail-test-card.d.ts +74 -0
- package/dist/admin/mail-test-card.js +80 -0
- package/dist/admin/mail-test-card.js.map +1 -0
- package/dist/billing/provider-page.d.ts +9 -0
- package/dist/billing/provider-page.js.map +1 -1
- package/dist/components/data-table-mobile.js +17 -2
- package/dist/components/data-table-mobile.js.map +1 -1
- package/dist/components/data-table-shared.d.ts +2 -0
- package/dist/components/data-table-shared.js +8 -0
- package/dist/components/data-table-shared.js.map +1 -1
- package/dist/components/data-table.js +1 -6
- package/dist/components/data-table.js.map +1 -1
- package/dist/eslint/index.js +1 -1
- package/dist/i18n/defaults.js +9 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.js +42 -2
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +13 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +60 -4
- package/dist/i18n/locales/en.js.map +3 -3
- package/dist/i18n/locales/es.js +40 -0
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +42 -2
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +40 -0
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +41 -1
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +40 -0
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +13 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/format.d.ts +2 -1
- package/dist/lib/format.js +6 -1
- package/dist/lib/format.js.map +1 -1
- package/dist/offline/pwa-update-prompt-labels.d.ts +2 -0
- package/dist/offline/pwa-update-prompt-labels.js +9 -0
- package/dist/offline/pwa-update-prompt-labels.js.map +1 -0
- package/dist/offline/pwa-update-prompt.d.ts +32 -0
- package/dist/offline/pwa-update-prompt.js +36 -0
- package/dist/offline/pwa-update-prompt.js.map +1 -0
- package/dist/offline/query-persistence.d.ts +100 -0
- package/dist/offline/query-persistence.js +179 -0
- package/dist/offline/query-persistence.js.map +1 -0
- package/dist/offline/shared-computer-labels.d.ts +2 -0
- package/dist/offline/shared-computer-labels.js +9 -0
- package/dist/offline/shared-computer-labels.js.map +1 -0
- package/dist/offline/shared-computer.d.ts +44 -0
- package/dist/offline/shared-computer.js +51 -0
- package/dist/offline/shared-computer.js.map +1 -0
- package/dist/offline/sign-out-pending-dialog-labels.d.ts +2 -0
- package/dist/offline/sign-out-pending-dialog-labels.js +14 -0
- package/dist/offline/sign-out-pending-dialog-labels.js.map +1 -0
- package/dist/offline/sign-out-pending-dialog.d.ts +58 -0
- package/dist/offline/sign-out-pending-dialog.js +66 -0
- package/dist/offline/sign-out-pending-dialog.js.map +1 -0
- package/dist/offline.d.ts +8 -0
- package/dist/offline.js +24 -0
- package/dist/offline.js.map +1 -0
- package/dist/shell/admin-menu.d.ts +24 -0
- package/dist/shell/admin-menu.js +12 -3
- package/dist/shell/admin-menu.js.map +1 -1
- package/dist/shell.d.ts +2 -0
- package/dist/shell.js +2 -0
- package/dist/shell.js.map +1 -1
- package/dist/tour/tour-catalogue-labels.js +2 -2
- package/dist/tour/tour-catalogue-labels.js.map +1 -1
- package/dist/tour/tour-catalogue.d.ts +7 -1
- package/dist/tour/tour-catalogue.js.map +1 -1
- package/dist/tour/tour-info.d.ts +2 -2
- package/dist/tour/tour-info.js.map +1 -1
- package/dist/tour/tour.d.ts +38 -2
- package/dist/tour/tour.js +42 -3
- package/dist/tour/tour.js.map +1 -1
- package/dist/tour/use-tour-progress.d.ts +165 -12
- package/dist/tour/use-tour-progress.js +271 -25
- package/dist/tour/use-tour-progress.js.map +1 -1
- package/dist/tour.d.ts +3 -1
- package/dist/tour.js +4 -1
- package/dist/tour.js.map +1 -1
- package/package.json +25 -1
- package/src/admin/admin-action-log-labels.ts +9 -0
- package/src/admin/admin-action-log.tsx +41 -5
- package/src/admin/admin-area-labels.ts +7 -0
- package/src/admin/mail-test-card-labels.ts +19 -0
- package/src/admin/mail-test-card.tsx +186 -0
- package/src/billing/provider-page.ts +9 -0
- package/src/components/data-table-mobile.tsx +26 -3
- package/src/components/data-table-shared.tsx +18 -1
- package/src/components/data-table.tsx +1 -15
- package/src/i18n/defaults.ts +8 -0
- package/src/i18n/german.ts +48 -2
- package/src/i18n/kit-labels.tsx +13 -0
- package/src/i18n/locales/en.ts +13 -1
- package/src/i18n/locales/es.ts +46 -0
- package/src/i18n/locales/fr.ts +48 -2
- package/src/i18n/locales/hu.ts +42 -0
- package/src/i18n/locales/it.ts +47 -1
- package/src/i18n/locales/zh.ts +40 -0
- package/src/i18n/review.ts +12 -0
- package/src/index.ts +3 -0
- package/src/lib/format.ts +13 -2
- package/src/offline/pwa-update-prompt-labels.ts +9 -0
- package/src/offline/pwa-update-prompt.tsx +72 -0
- package/src/offline/query-persistence.ts +323 -0
- package/src/offline/shared-computer-labels.ts +8 -0
- package/src/offline/shared-computer.tsx +87 -0
- package/src/offline/sign-out-pending-dialog-labels.ts +21 -0
- package/src/offline/sign-out-pending-dialog.tsx +135 -0
- package/src/offline.ts +26 -0
- package/src/shell/admin-menu.tsx +40 -3
- package/src/shell.ts +4 -0
- package/src/tour/tour-catalogue-labels.ts +2 -2
- package/src/tour/tour-catalogue.tsx +7 -1
- package/src/tour/tour-info.ts +2 -2
- package/src/tour/tour.tsx +87 -3
- package/src/tour/use-tour-progress.ts +501 -34
- package/src/tour.ts +5 -1
package/src/i18n/locales/it.ts
CHANGED
|
@@ -626,7 +626,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
626
626
|
stateDone: (count) => `Completati (${n(count)})`,
|
|
627
627
|
showing: (shown, total) => `${n(shown)} di ${n(total)} tour`,
|
|
628
628
|
noMatches: "Nessun tour corrisponde",
|
|
629
|
-
noMatchesHint: "Provi un’altra parola o cancelli
|
|
629
|
+
noMatchesHint: "Provi un’altra parola o cancelli il filtro.",
|
|
630
630
|
clearFilters: "Cancella filtri",
|
|
631
631
|
badgeNew: "Nuovo",
|
|
632
632
|
badgeUpdated: "Aggiornato",
|
|
@@ -1385,11 +1385,14 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
1385
1385
|
// ("Azienda creata"; Kurvenschmiede's "il team" is masculine, never "squadra"), a
|
|
1386
1386
|
// member's with "account", as `actions` do. `budget` is keksdose's; `company` keeps
|
|
1387
1387
|
// `actions.membership_remove`'s string.
|
|
1388
|
+
renamedFromTo: (from, to) => `da ${from} a ${to}`,
|
|
1388
1389
|
groupActions: {
|
|
1389
1390
|
group: {
|
|
1390
1391
|
group_create: "Gruppo creato",
|
|
1391
1392
|
group_rename: "Gruppo rinominato",
|
|
1392
1393
|
group_delete: "Gruppo eliminato",
|
|
1394
|
+
group_deactivate: "Gruppo disattivato",
|
|
1395
|
+
group_reactivate: "Gruppo riattivato",
|
|
1393
1396
|
membership_add: "Aggiunto al gruppo",
|
|
1394
1397
|
membership_role: "Ruolo nel gruppo cambiato",
|
|
1395
1398
|
membership_remove: "Rimosso dal gruppo",
|
|
@@ -1399,6 +1402,8 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
1399
1402
|
group_create: "Team creato",
|
|
1400
1403
|
group_rename: "Team rinominato",
|
|
1401
1404
|
group_delete: "Team eliminato",
|
|
1405
|
+
group_deactivate: "Team disattivato",
|
|
1406
|
+
group_reactivate: "Team riattivato",
|
|
1402
1407
|
membership_add: "Aggiunto al team",
|
|
1403
1408
|
membership_role: "Ruolo nel team cambiato",
|
|
1404
1409
|
membership_remove: "Rimosso dal team",
|
|
@@ -1408,6 +1413,8 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
1408
1413
|
group_create: "Azienda creata",
|
|
1409
1414
|
group_rename: "Azienda rinominata",
|
|
1410
1415
|
group_delete: "Azienda eliminata",
|
|
1416
|
+
group_deactivate: "Azienda disattivata",
|
|
1417
|
+
group_reactivate: "Azienda riattivata",
|
|
1411
1418
|
membership_add: "Aggiunto all’azienda",
|
|
1412
1419
|
membership_role: "Ruolo nell’azienda cambiato",
|
|
1413
1420
|
membership_remove: "Rimosso dall’azienda",
|
|
@@ -1417,6 +1424,8 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
1417
1424
|
group_create: "Budget creato",
|
|
1418
1425
|
group_rename: "Budget rinominato",
|
|
1419
1426
|
group_delete: "Budget eliminato",
|
|
1427
|
+
group_deactivate: "Budget disattivato",
|
|
1428
|
+
group_reactivate: "Budget riattivato",
|
|
1420
1429
|
membership_add: "Aggiunto al budget",
|
|
1421
1430
|
membership_role: "Ruolo nel budget cambiato",
|
|
1422
1431
|
membership_remove: "Rimosso dal budget",
|
|
@@ -1850,9 +1859,21 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
1850
1859
|
},
|
|
1851
1860
|
// 0.42.0 — docs/admin-harmonization.md §3.1: the admin area's shared words. "Lei", as
|
|
1852
1861
|
// the rest of the catalogue.
|
|
1862
|
+
mailTestCard: {
|
|
1863
|
+
title: "Email di prova",
|
|
1864
|
+
description: "Invia un’email al Suo indirizzo, tramite il trasporto con cui questa installazione invia tutte le sue email.",
|
|
1865
|
+
transport: (backend) => `Trasporto: ${backend}`,
|
|
1866
|
+
action: "Inviami un’email di prova",
|
|
1867
|
+
sent: (address) => `Inviata a ${address}. Controlli la posta in arrivo.`,
|
|
1868
|
+
console: "Il trasporto console registra solo le email; non è stato inviato nulla.",
|
|
1869
|
+
failed: "Invio non riuscito. Il log del server contiene la risposta del provider.",
|
|
1870
|
+
rateLimited,
|
|
1871
|
+
keywords: "email prova test posta trasporto smtp resend console inviare consegna",
|
|
1872
|
+
},
|
|
1853
1873
|
adminArea: {
|
|
1854
1874
|
title: "Amministrazione",
|
|
1855
1875
|
waiting: (count) => `${n(count)} in attesa`,
|
|
1876
|
+
waitingLabel: (label, count) => `${label}, ${n(count)} in attesa`,
|
|
1856
1877
|
forbiddenTitle: "Solo per gli amministratori",
|
|
1857
1878
|
forbiddenBody: (appName) =>
|
|
1858
1879
|
`Qui gli amministratori gestiscono ${appName}. Il Suo account non può aprire questa pagina.`,
|
|
@@ -1921,6 +1942,31 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
1921
1942
|
billingOff: "La fatturazione è disattivata in locale: i piani non cambiano nulla",
|
|
1922
1943
|
},
|
|
1923
1944
|
},
|
|
1945
|
+
// 0.45.0 — docs/local-first-harmonization.md §1.6 (`@eifi1/ui-kit/offline`): keksdose's
|
|
1946
|
+
// reviewed words (nav.logout_queued_*, pwa.*) where it has the language.
|
|
1947
|
+
signOutPending: {
|
|
1948
|
+
title: "Alcune modifiche non sono ancora state salvate sul server",
|
|
1949
|
+
lost: (count) =>
|
|
1950
|
+
count === 1
|
|
1951
|
+
? `${n(count)} modifica è ancora in attesa di sincronizzazione. Uscendo, la copia su questo dispositivo viene cancellata, ed è l’unica.`
|
|
1952
|
+
: `${n(count)} modifiche sono ancora in attesa di sincronizzazione. Uscendo, la copia su questo dispositivo viene cancellata, ed è l’unica.`,
|
|
1953
|
+
kept: (count) =>
|
|
1954
|
+
count === 1
|
|
1955
|
+
? `${n(count)} modifica è ancora in attesa di sincronizzazione. Resta per Lei su questo dispositivo e verrà sincronizzata al Suo prossimo accesso qui.`
|
|
1956
|
+
: `${n(count)} modifiche sono ancora in attesa di sincronizzazione. Restano per Lei su questo dispositivo e verranno sincronizzate al Suo prossimo accesso qui.`,
|
|
1957
|
+
syncNow: "Sincronizza ora",
|
|
1958
|
+
signOutAnyway: "Esci comunque",
|
|
1959
|
+
discardWaiting: "Scarta le modifiche in attesa",
|
|
1960
|
+
cancel: "Annulla",
|
|
1961
|
+
},
|
|
1962
|
+
pwaUpdate: {
|
|
1963
|
+
updateAvailable: "È disponibile una nuova versione.",
|
|
1964
|
+
reload: "Ricarica",
|
|
1965
|
+
},
|
|
1966
|
+
sharedComputer: {
|
|
1967
|
+
label: "Questo è un computer condiviso",
|
|
1968
|
+
hint: "Su questo dispositivo non resta alcuna copia dei Suoi dati. Le pagine si aprono quindi solo con una connessione.",
|
|
1969
|
+
},
|
|
1924
1970
|
};
|
|
1925
1971
|
}
|
|
1926
1972
|
|
package/src/i18n/locales/zh.ts
CHANGED
|
@@ -1321,11 +1321,14 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1321
1321
|
},
|
|
1322
1322
|
// 0.34 (§11.5): whole phrases per noun. `team` is Kurvenschmiede's "团队"; `company`
|
|
1323
1323
|
// keeps `actions.membership_remove`'s string.
|
|
1324
|
+
renamedFromTo: (from, to) => `从 ${from} 改为 ${to}`,
|
|
1324
1325
|
groupActions: {
|
|
1325
1326
|
group: {
|
|
1326
1327
|
group_create: "群组已创建",
|
|
1327
1328
|
group_rename: "群组已重命名",
|
|
1328
1329
|
group_delete: "群组已删除",
|
|
1330
|
+
group_deactivate: "群组已停用",
|
|
1331
|
+
group_reactivate: "群组已重新激活",
|
|
1329
1332
|
membership_add: "已添加到群组",
|
|
1330
1333
|
membership_role: "群组中的角色已更改",
|
|
1331
1334
|
membership_remove: "已从群组移除",
|
|
@@ -1335,6 +1338,8 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1335
1338
|
group_create: "团队已创建",
|
|
1336
1339
|
group_rename: "团队已重命名",
|
|
1337
1340
|
group_delete: "团队已删除",
|
|
1341
|
+
group_deactivate: "团队已停用",
|
|
1342
|
+
group_reactivate: "团队已重新激活",
|
|
1338
1343
|
membership_add: "已添加到团队",
|
|
1339
1344
|
membership_role: "团队中的角色已更改",
|
|
1340
1345
|
membership_remove: "已从团队移除",
|
|
@@ -1344,6 +1349,8 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1344
1349
|
group_create: "公司已创建",
|
|
1345
1350
|
group_rename: "公司已重命名",
|
|
1346
1351
|
group_delete: "公司已删除",
|
|
1352
|
+
group_deactivate: "公司已停用",
|
|
1353
|
+
group_reactivate: "公司已重新激活",
|
|
1347
1354
|
membership_add: "已添加到公司",
|
|
1348
1355
|
membership_role: "公司中的角色已更改",
|
|
1349
1356
|
membership_remove: "已从公司移除",
|
|
@@ -1353,6 +1360,8 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1353
1360
|
group_create: "预算已创建",
|
|
1354
1361
|
group_rename: "预算已重命名",
|
|
1355
1362
|
group_delete: "预算已删除",
|
|
1363
|
+
group_deactivate: "预算已停用",
|
|
1364
|
+
group_reactivate: "预算已重新激活",
|
|
1356
1365
|
membership_add: "已添加到预算",
|
|
1357
1366
|
membership_role: "预算中的角色已更改",
|
|
1358
1367
|
membership_remove: "已从预算移除",
|
|
@@ -1754,9 +1763,21 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1754
1763
|
moreTitle: "更多页面",
|
|
1755
1764
|
},
|
|
1756
1765
|
// 0.42.0 — docs/admin-harmonization.md §3.1: the admin area's shared words.
|
|
1766
|
+
mailTestCard: {
|
|
1767
|
+
title: "测试邮件",
|
|
1768
|
+
description: "通过本安装发送所有邮件所用的传输方式,向您自己的地址发送一封邮件。",
|
|
1769
|
+
transport: (backend) => `传输方式:${backend}`,
|
|
1770
|
+
action: "给我发送测试邮件",
|
|
1771
|
+
sent: (address) => `已发送至 ${address}。请查看收件箱。`,
|
|
1772
|
+
console: "控制台传输只记录邮件,未发送任何邮件。",
|
|
1773
|
+
failed: "无法发送。服务器日志中有服务商的回复。",
|
|
1774
|
+
rateLimited,
|
|
1775
|
+
keywords: "测试邮件 邮件 电子邮件 传输 smtp resend 控制台 发送 投递",
|
|
1776
|
+
},
|
|
1757
1777
|
adminArea: {
|
|
1758
1778
|
title: "管理",
|
|
1759
1779
|
waiting: (count) => `${n(count)} 项待处理`,
|
|
1780
|
+
waitingLabel: (label, count) => `${label},${n(count)} 项待处理`,
|
|
1760
1781
|
forbiddenTitle: "仅限管理员",
|
|
1761
1782
|
forbiddenBody: (appName) => `管理员在这里管理 ${appName}。您的账户无法打开此页面。`,
|
|
1762
1783
|
forbiddenHome: "前往首页",
|
|
@@ -1822,6 +1843,25 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1822
1843
|
billingOff: "本地已关闭计费:切换套餐不会改变任何内容",
|
|
1823
1844
|
},
|
|
1824
1845
|
},
|
|
1846
|
+
// 0.45.0 — docs/local-first-harmonization.md §1.6 (`@eifi1/ui-kit/offline`): keksdose's
|
|
1847
|
+
// reviewed words (nav.logout_queued_*, pwa.*) where it has the language.
|
|
1848
|
+
signOutPending: {
|
|
1849
|
+
title: "部分修改尚未保存到服务器",
|
|
1850
|
+
lost: (count) => `${n(count)} 项修改仍在等待同步。退出登录会清除此设备上的副本,而这是唯一的副本。`,
|
|
1851
|
+
kept: (count) => `${n(count)} 项修改仍在等待同步。它们会为您保留在此设备上,并在您下次在此登录时同步。`,
|
|
1852
|
+
syncNow: "立即同步",
|
|
1853
|
+
signOutAnyway: "仍然退出登录",
|
|
1854
|
+
discardWaiting: "放弃等待中的修改",
|
|
1855
|
+
cancel: "取消",
|
|
1856
|
+
},
|
|
1857
|
+
pwaUpdate: {
|
|
1858
|
+
updateAvailable: "有新版本可用。",
|
|
1859
|
+
reload: "重新加载",
|
|
1860
|
+
},
|
|
1861
|
+
sharedComputer: {
|
|
1862
|
+
label: "这是一台共用电脑",
|
|
1863
|
+
hint: "此设备上不会保留您的数据副本。页面将只能在联网时打开。",
|
|
1864
|
+
},
|
|
1825
1865
|
};
|
|
1826
1866
|
}
|
|
1827
1867
|
|
package/src/i18n/review.ts
CHANGED
|
@@ -353,6 +353,8 @@ export const KIT_LABEL_SAMPLES: Readonly<Record<string, readonly (readonly unkno
|
|
|
353
353
|
"adminActionLog.by": [["{{actor}}"]],
|
|
354
354
|
"adminActionLog.filteredTo": [["{{target}}"]],
|
|
355
355
|
"adminActionLog.filterBy": [["{{target}}"]],
|
|
356
|
+
// 0.45.0 (admin §9.4): a company rename that logged both names.
|
|
357
|
+
"adminActionLog.renamedFromTo": [["{{from}}", "{{to}}"]],
|
|
356
358
|
"transferOwnership.title": [["{{name}}"]],
|
|
357
359
|
"transferOwnership.unavailable": [["{{account}}", "{{reason}}"]],
|
|
358
360
|
"invitations.sent": [["{{date}}"]],
|
|
@@ -406,6 +408,12 @@ export const KIT_LABEL_SAMPLES: Readonly<Record<string, readonly (readonly unkno
|
|
|
406
408
|
// 0.42.0 (docs/admin-harmonization.md §3.1): the menu row's count, the 403 page's app,
|
|
407
409
|
// the users tile's new accounts.
|
|
408
410
|
"adminArea.waiting": one,
|
|
411
|
+
// 0.45.0 (admin §9.3.4): an IconButton's name with its waiting count.
|
|
412
|
+
"adminArea.waitingLabel": [["{{label}}", 1], ["{{label}}", 3]],
|
|
413
|
+
// 0.45.0 (admin §9.2.4): the test mail's transport, masked address and limiter.
|
|
414
|
+
"mailTestCard.transport": [["{{backend}}"]],
|
|
415
|
+
"mailTestCard.sent": [["{{address}}"]],
|
|
416
|
+
"mailTestCard.rateLimited": [[], [30], [300]],
|
|
409
417
|
"adminArea.forbiddenBody": [["{{app}}"]],
|
|
410
418
|
"adminArea.tiles.usersNew": one,
|
|
411
419
|
// 0.42.0 (docs/top-bar-harmonization.md §3.1): the sync indicator's counts, its time, the
|
|
@@ -431,4 +439,8 @@ export const KIT_LABEL_SAMPLES: Readonly<Record<string, readonly (readonly unkno
|
|
|
431
439
|
"tourCatalogue.steps": one,
|
|
432
440
|
"tourCatalogue.duration": one,
|
|
433
441
|
"tourCatalogue.completedOn": [["{{date}}"]],
|
|
442
|
+
// 0.45.0 (docs/local-first-harmonization.md §1.6): the sign-out question's count, in
|
|
443
|
+
// both word sets.
|
|
444
|
+
"signOutPending.lost": one,
|
|
445
|
+
"signOutPending.kept": one,
|
|
434
446
|
};
|
package/src/index.ts
CHANGED
|
@@ -811,6 +811,9 @@ export type {
|
|
|
811
811
|
} from "./admin/admin-overview";
|
|
812
812
|
export { AdminToolLinks } from "./admin/admin-tool-links";
|
|
813
813
|
export type { AdminToolLink, AdminToolLinksProps } from "./admin/admin-tool-links";
|
|
814
|
+
// 0.45.0 (docs/admin-harmonization.md §9.2.4): "Send a test mail to me".
|
|
815
|
+
export { MailTestCard, DEFAULT_MAIL_TEST_CARD_LABELS, MAIL_TEST_ANCHOR, maskMailAddress } from "./admin/mail-test-card";
|
|
816
|
+
export type { MailTestCardProps, MailTestCardLabels, MailTestAnswer } from "./admin/mail-test-card";
|
|
814
817
|
// 0.33.0: the operator's plan parts (docs/billing-harmonization.md §14.12).
|
|
815
818
|
export {
|
|
816
819
|
planColumn,
|
package/src/lib/format.ts
CHANGED
|
@@ -182,10 +182,14 @@ const DATE_STYLES: Record<FormatDateStyle, Intl.DateTimeFormatOptions> = {
|
|
|
182
182
|
};
|
|
183
183
|
|
|
184
184
|
export interface FormatDateOptions extends BaseOptions {
|
|
185
|
-
/** An IANA zone ("Europe/Zurich") for a timestamp. Left out: the device's.
|
|
185
|
+
/** An IANA zone ("Europe/Zurich") for a timestamp. Left out: the device's. A bare
|
|
186
|
+
* "YYYY-MM-DD" ignores it: a calendar day is the day it names in every zone. */
|
|
186
187
|
timeZone?: string;
|
|
187
188
|
}
|
|
188
189
|
|
|
190
|
+
/** A bare ISO calendar day, `"YYYY-MM-DD"`. */
|
|
191
|
+
const BARE_ISO_DAY = /^\d{4}-\d{2}-\d{2}$/;
|
|
192
|
+
|
|
189
193
|
/** What {@link formatDate} and {@link formatRelativeTime} accept. */
|
|
190
194
|
export type DateInput = string | number | Date | null | undefined;
|
|
191
195
|
|
|
@@ -197,7 +201,7 @@ export type DateInput = string | number | Date | null | undefined;
|
|
|
197
201
|
*/
|
|
198
202
|
export function toDate(value: DateInput): Date | null {
|
|
199
203
|
if (value === null || value === undefined || value === "") return null;
|
|
200
|
-
if (typeof value === "string" &&
|
|
204
|
+
if (typeof value === "string" && BARE_ISO_DAY.test(value)) return parseIsoDate(value);
|
|
201
205
|
const d = value instanceof Date ? value : new Date(value);
|
|
202
206
|
return Number.isNaN(d.getTime()) ? null : d;
|
|
203
207
|
}
|
|
@@ -229,6 +233,13 @@ export function formatDate(
|
|
|
229
233
|
const d = toDate(value);
|
|
230
234
|
if (!d) return options.empty ?? EMPTY_FORMATTED_VALUE;
|
|
231
235
|
const base = typeof style === "string" ? DATE_STYLES[style] : style;
|
|
236
|
+
// A bare "YYYY-MM-DD" is a calendar day, which has no zone: it is the day it names
|
|
237
|
+
// wherever it is read, so a `timeZone` (in `options` or the style) never moves it — the
|
|
238
|
+
// device's local midnight shown in a zone west of it was the day before (round 0.45, N9).
|
|
239
|
+
if (typeof value === "string" && BARE_ISO_DAY.test(value)) {
|
|
240
|
+
const day = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
|
|
241
|
+
return dateFormatter(options.locale, { ...base, timeZone: "UTC" }).format(day);
|
|
242
|
+
}
|
|
232
243
|
return dateFormatter(options.locale, options.timeZone ? { ...base, timeZone: options.timeZone } : base).format(d);
|
|
233
244
|
}
|
|
234
245
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// The English words of ./pwa-update-prompt, in a module with no component code (0.34, KS U8).
|
|
2
|
+
// keksdose's reviewed words (pwa.updateAvailable, pwa.reload) are the canon.
|
|
3
|
+
|
|
4
|
+
import type { PwaUpdatePromptLabels } from "./pwa-update-prompt";
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_PWA_UPDATE_PROMPT_LABELS: PwaUpdatePromptLabels = {
|
|
7
|
+
updateAvailable: "A new version is available.",
|
|
8
|
+
reload: "Reload",
|
|
9
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import { useKitLabels, type LabelOverride } from "../i18n/kit-labels";
|
|
3
|
+
import { toast } from "../components/toast";
|
|
4
|
+
import { DEFAULT_PWA_UPDATE_PROMPT_LABELS } from "./pwa-update-prompt-labels";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* "A new version is available. — Reload": keksdose's service-worker toast
|
|
8
|
+
* (app/pwa-update-prompt.tsx) as a kit component (docs/local-first-harmonization.md §1.5
|
|
9
|
+
* D8). The app keeps `useRegisterSW` (vite-plugin-pwa, `registerType: "prompt"`) and hands
|
|
10
|
+
* its state in: `needRefresh` from it, `onReload` = `updateServiceWorker(true)`,
|
|
11
|
+
* `onDismiss` = `setNeedRefresh(false)`.
|
|
12
|
+
*
|
|
13
|
+
* `hold` defers the prompt while a reload would hurt — a handover being signed, a tour
|
|
14
|
+
* running. Nothing shows while it holds; the toast appears once it drops. A hold that
|
|
15
|
+
* starts while the toast is up takes it down again until it drops.
|
|
16
|
+
*
|
|
17
|
+
* Renders nothing itself: the toast needs a mounted `<Toaster>`.
|
|
18
|
+
*/
|
|
19
|
+
export interface PwaUpdatePromptLabels {
|
|
20
|
+
updateAvailable: string;
|
|
21
|
+
reload: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Defined in ./pwa-update-prompt-labels, which holds no component code (0.34, KS U8).
|
|
25
|
+
export { DEFAULT_PWA_UPDATE_PROMPT_LABELS };
|
|
26
|
+
|
|
27
|
+
export interface PwaUpdatePromptProps {
|
|
28
|
+
/** A new service worker is waiting. */
|
|
29
|
+
needRefresh: boolean;
|
|
30
|
+
/** Activates it and reloads — `updateServiceWorker(true)`. */
|
|
31
|
+
onReload: () => void;
|
|
32
|
+
/** The toast was closed without reloading. */
|
|
33
|
+
onDismiss?: () => void;
|
|
34
|
+
/** Wait: a handover is open, a tour runs. */
|
|
35
|
+
hold?: boolean;
|
|
36
|
+
labels?: LabelOverride<PwaUpdatePromptLabels>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The toast's id: one prompt at a time, replaced in place. */
|
|
40
|
+
const PWA_UPDATE_TOAST_ID = "pwa-update";
|
|
41
|
+
|
|
42
|
+
export function PwaUpdatePrompt({ needRefresh, onReload, onDismiss, hold = false, labels: labelsProp }: PwaUpdatePromptProps) {
|
|
43
|
+
const labels = useKitLabels("pwaUpdate", DEFAULT_PWA_UPDATE_PROMPT_LABELS, labelsProp);
|
|
44
|
+
// The callbacks are read at click time, so a new function each render does not
|
|
45
|
+
// re-raise the toast.
|
|
46
|
+
const handlers = useRef({ onReload, onDismiss });
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
handlers.current = { onReload, onDismiss };
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const show = needRefresh && !hold;
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (!show) return;
|
|
54
|
+
// sonner calls `onDismiss` for a programmatic dismiss too: the one this effect makes
|
|
55
|
+
// when a hold starts must not tell the app the person waved the update away.
|
|
56
|
+
let ours = false;
|
|
57
|
+
toast(labels.updateAvailable, {
|
|
58
|
+
id: PWA_UPDATE_TOAST_ID,
|
|
59
|
+
duration: Infinity,
|
|
60
|
+
action: { label: labels.reload, onClick: () => handlers.current.onReload() },
|
|
61
|
+
onDismiss: () => {
|
|
62
|
+
if (!ours) handlers.current.onDismiss?.();
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
return () => {
|
|
66
|
+
ours = true;
|
|
67
|
+
toast.dismiss(PWA_UPDATE_TOAST_ID);
|
|
68
|
+
};
|
|
69
|
+
}, [show, labels.updateAvailable, labels.reload]);
|
|
70
|
+
|
|
71
|
+
return null;
|
|
72
|
+
}
|