@eifi1/ui-kit 0.41.0 → 0.43.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 +26 -7
- package/dist/admin/admin-area-labels.d.ts +59 -0
- package/dist/admin/admin-area-labels.js +35 -0
- package/dist/admin/admin-area-labels.js.map +1 -0
- package/dist/admin/admin-forbidden.d.ts +35 -0
- package/dist/admin/admin-forbidden.js +36 -0
- package/dist/admin/admin-forbidden.js.map +1 -0
- package/dist/admin/admin-overview.d.ts +110 -0
- package/dist/admin/admin-overview.js +92 -0
- package/dist/admin/admin-overview.js.map +1 -0
- package/dist/admin/admin-sections.d.ts +94 -0
- package/dist/admin/admin-sections.js +81 -0
- package/dist/admin/admin-sections.js.map +1 -0
- package/dist/admin/admin-tool-links.d.ts +48 -0
- package/dist/admin/admin-tool-links.js +31 -0
- package/dist/admin/admin-tool-links.js.map +1 -0
- package/dist/billing/billing-banner.d.ts +33 -2
- package/dist/billing/billing-banner.js +29 -3
- package/dist/billing/billing-banner.js.map +1 -1
- package/dist/billing/billing-labels.d.ts +36 -0
- package/dist/billing/billing-labels.js +10 -0
- package/dist/billing/billing-labels.js.map +1 -1
- package/dist/billing/billing-overview.d.ts +33 -0
- package/dist/billing/billing-overview.js +6 -0
- package/dist/billing/billing-overview.js.map +1 -1
- package/dist/billing/billing-standing.d.ts +8 -0
- package/dist/billing/billing-standing.js.map +1 -1
- package/dist/billing/cancel-request.d.ts +53 -0
- package/dist/billing/cancel-request.js +21 -0
- package/dist/billing/cancel-request.js.map +1 -0
- package/dist/billing/cancel-subscription.d.ts +46 -0
- package/dist/billing/cancel-subscription.js +57 -0
- package/dist/billing/cancel-subscription.js.map +1 -0
- package/dist/billing/plan-card.d.ts +45 -1
- package/dist/billing/plan-card.js +53 -2
- package/dist/billing/plan-card.js.map +1 -1
- package/dist/billing/plan-switch.d.ts +10 -1
- package/dist/billing/plan-switch.js +22 -13
- package/dist/billing/plan-switch.js.map +1 -1
- package/dist/billing/provider-page.d.ts +40 -0
- package/dist/billing/provider-page.js +33 -0
- package/dist/billing/provider-page.js.map +1 -0
- package/dist/billing/subscription-actions.d.ts +68 -4
- package/dist/billing/subscription-actions.js +65 -5
- package/dist/billing/subscription-actions.js.map +1 -1
- package/dist/components/account-chips.d.ts +50 -2
- package/dist/components/account-chips.js +33 -0
- package/dist/components/account-chips.js.map +1 -1
- package/dist/components/empty-state.d.ts +2 -1
- package/dist/components/empty-state.js.map +1 -1
- package/dist/eslint/index.js +1 -1
- package/dist/feedback/feedback-menu.d.ts +7 -4
- package/dist/feedback/feedback-menu.js +4 -2
- package/dist/feedback/feedback-menu.js.map +1 -1
- package/dist/hooks/use-search-param-state.js +4 -1
- package/dist/hooks/use-search-param-state.js.map +1 -1
- package/dist/i18n/defaults.js +7 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.js +113 -0
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +12 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +142 -1
- package/dist/i18n/locales/en.js.map +3 -3
- package/dist/i18n/locales/es.js +110 -0
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +109 -0
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +110 -0
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +110 -0
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +109 -0
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +34 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +24 -2
- package/dist/index.js +29 -1
- package/dist/index.js.map +1 -1
- package/dist/search/global-search.d.ts +3 -0
- package/dist/search/global-search.js +3 -1
- package/dist/search/global-search.js.map +1 -1
- package/dist/settings/settings-catalogue.d.ts +9 -1
- package/dist/settings/settings-catalogue.js +1 -1
- package/dist/settings/settings-catalogue.js.map +1 -1
- package/dist/settings/settings-layout.d.ts +7 -1
- package/dist/settings/settings-layout.js +35 -27
- package/dist/settings/settings-layout.js.map +1 -1
- package/dist/shell/account-menu-language.d.ts +46 -0
- package/dist/shell/account-menu-language.js +64 -0
- package/dist/shell/account-menu-language.js.map +1 -0
- package/dist/shell/admin-menu.d.ts +69 -0
- package/dist/shell/admin-menu.js +64 -0
- package/dist/shell/admin-menu.js.map +1 -0
- package/dist/shell/app-shell.d.ts +10 -0
- package/dist/shell/app-shell.js +22 -4
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/dev-switchers.d.ts +53 -0
- package/dist/shell/dev-switchers.js +107 -0
- package/dist/shell/dev-switchers.js.map +1 -0
- package/dist/shell/sync-status-indicator.d.ts +86 -0
- package/dist/shell/sync-status-indicator.js +170 -0
- package/dist/shell/sync-status-indicator.js.map +1 -0
- package/dist/shell/top-bar-actions.d.ts +49 -0
- package/dist/shell/top-bar-actions.js +31 -0
- package/dist/shell/top-bar-actions.js.map +1 -0
- package/dist/shell/top-bar-parts-labels.d.ts +90 -0
- package/dist/shell/top-bar-parts-labels.js +51 -0
- package/dist/shell/top-bar-parts-labels.js.map +1 -0
- package/dist/shell/topbar-action-menu.d.ts +13 -1
- package/dist/shell/topbar-action-menu.js +5 -2
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell/topbar-controls.d.ts +16 -3
- package/dist/shell/topbar-controls.js +5 -1
- package/dist/shell/topbar-controls.js.map +1 -1
- package/dist/shell/tour-menu.d.ts +67 -0
- package/dist/shell/tour-menu.js +87 -0
- package/dist/shell/tour-menu.js.map +1 -0
- package/dist/shell.d.ts +16 -0
- package/dist/shell.js +21 -0
- package/dist/shell.js.map +1 -1
- package/dist/tour/tour-catalogue-labels.d.ts +44 -0
- package/dist/tour/tour-catalogue-labels.js +32 -0
- package/dist/tour/tour-catalogue-labels.js.map +1 -0
- package/dist/tour/tour-catalogue.d.ts +68 -0
- package/dist/tour/tour-catalogue.js +189 -0
- package/dist/tour/tour-catalogue.js.map +1 -0
- package/dist/tour/tour-info.d.ts +112 -0
- package/dist/tour/tour-info.js +36 -0
- package/dist/tour/tour-info.js.map +1 -0
- package/dist/tour/use-tour-progress.d.ts +61 -0
- package/dist/tour/use-tour-progress.js +116 -0
- package/dist/tour/use-tour-progress.js.map +1 -0
- package/dist/tour/use-tour-url-sync.d.ts +58 -0
- package/dist/tour/use-tour-url-sync.js +110 -0
- package/dist/tour/use-tour-url-sync.js.map +1 -0
- package/dist/tour.d.ts +8 -0
- package/dist/tour.js +18 -0
- package/dist/tour.js.map +1 -1
- package/package.json +1 -1
- package/src/admin/admin-area-labels.ts +91 -0
- package/src/admin/admin-forbidden.tsx +75 -0
- package/src/admin/admin-overview.tsx +217 -0
- package/src/admin/admin-sections.tsx +198 -0
- package/src/admin/admin-tool-links.tsx +84 -0
- package/src/billing/billing-banner.tsx +57 -6
- package/src/billing/billing-labels.ts +59 -0
- package/src/billing/billing-overview.ts +37 -0
- package/src/billing/billing-standing.ts +8 -0
- package/src/billing/cancel-request.ts +75 -0
- package/src/billing/cancel-subscription.tsx +102 -0
- package/src/billing/plan-card.tsx +97 -1
- package/src/billing/plan-switch.tsx +16 -0
- package/src/billing/provider-page.ts +75 -0
- package/src/billing/subscription-actions.tsx +155 -20
- package/src/components/account-chips.tsx +89 -2
- package/src/components/empty-state.tsx +2 -1
- package/src/feedback/feedback-menu.tsx +8 -3
- package/src/hooks/use-search-param-state.ts +6 -1
- package/src/i18n/defaults.ts +6 -0
- package/src/i18n/german.ts +127 -0
- package/src/i18n/kit-labels.tsx +12 -0
- package/src/i18n/locales/en.ts +32 -0
- package/src/i18n/locales/es.ts +121 -0
- package/src/i18n/locales/fr.ts +121 -0
- package/src/i18n/locales/hu.ts +119 -0
- package/src/i18n/locales/it.ts +122 -0
- package/src/i18n/locales/zh.ts +114 -0
- package/src/i18n/review.ts +33 -0
- package/src/index.ts +38 -2
- package/src/search/global-search.tsx +5 -0
- package/src/settings/settings-catalogue.ts +10 -2
- package/src/settings/settings-layout.tsx +58 -34
- package/src/shell/account-menu-language.tsx +116 -0
- package/src/shell/admin-menu.tsx +146 -0
- package/src/shell/app-shell.tsx +44 -3
- package/src/shell/dev-switchers.tsx +179 -0
- package/src/shell/sync-status-indicator.tsx +301 -0
- package/src/shell/top-bar-actions.tsx +79 -0
- package/src/shell/top-bar-parts-labels.ts +142 -0
- package/src/shell/topbar-action-menu.tsx +15 -2
- package/src/shell/topbar-controls.tsx +20 -3
- package/src/shell/tour-menu.tsx +179 -0
- package/src/shell.ts +27 -0
- package/src/tour/tour-catalogue-labels.ts +75 -0
- package/src/tour/tour-catalogue.tsx +316 -0
- package/src/tour/tour-info.ts +144 -0
- package/src/tour/use-tour-progress.ts +198 -0
- package/src/tour/use-tour-url-sync.ts +221 -0
- package/src/tour.ts +11 -0
package/src/i18n/locales/zh.ts
CHANGED
|
@@ -592,6 +592,34 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
592
592
|
awaitClickHint: "点击高亮的元素以继续",
|
|
593
593
|
step: (current, total) => `${n(current)} / ${n(total)}`,
|
|
594
594
|
},
|
|
595
|
+
// 0.43.0 — docs/tours-harmonization.md §3, §8: the tours page.
|
|
596
|
+
tourCatalogue: {
|
|
597
|
+
searchLabel: "搜索导览",
|
|
598
|
+
searchPlaceholder: "搜索导览…",
|
|
599
|
+
groupLabel: "主题",
|
|
600
|
+
groupAll: (count) => `全部主题(${n(count)})`,
|
|
601
|
+
groupOption: (group, count) => `${group}(${n(count)})`,
|
|
602
|
+
stateLabel: "筛选导览",
|
|
603
|
+
stateAll: (count) => `全部(${n(count)})`,
|
|
604
|
+
stateTodo: (count) => `待完成(${n(count)})`,
|
|
605
|
+
stateDone: (count) => `已完成(${n(count)})`,
|
|
606
|
+
showing: (shown, total) => `显示 ${n(shown)} / ${n(total)} 个导览`,
|
|
607
|
+
noMatches: "没有匹配的导览",
|
|
608
|
+
noMatchesHint: "请换个关键词,或清除筛选条件。",
|
|
609
|
+
clearFilters: "清除筛选",
|
|
610
|
+
badgeNew: "新",
|
|
611
|
+
badgeUpdated: "已更新",
|
|
612
|
+
resetOn: (date, reason) => (reason ? `已于 ${date} 重置:${reason}` : `已于 ${date} 重置`),
|
|
613
|
+
points: (count) => `+${n(count)} 分`,
|
|
614
|
+
steps: (count) => `${n(count)} 步`,
|
|
615
|
+
duration: (minutes) => `约 ${n(minutes)} 分钟`,
|
|
616
|
+
completedOn: (date) => `完成于 ${date}`,
|
|
617
|
+
completed: "已完成",
|
|
618
|
+
notCompleted: "未完成",
|
|
619
|
+
markUndone: "标记为未完成",
|
|
620
|
+
start: "开始",
|
|
621
|
+
replay: "再来一次",
|
|
622
|
+
},
|
|
595
623
|
commandPalette: {
|
|
596
624
|
clear: "清除搜索",
|
|
597
625
|
submit: "搜索",
|
|
@@ -1613,6 +1641,9 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1613
1641
|
processing: "您的付款正在处理中。确认后您的套餐即会生效;此页面会自动更新。",
|
|
1614
1642
|
choosePlan: "选择套餐",
|
|
1615
1643
|
updatePayment: "更新付款方式",
|
|
1644
|
+
// 0.42 (§16.7 A): for an admin who isn't the buyer.
|
|
1645
|
+
paymentFailedAskBuyer: (buyer) =>
|
|
1646
|
+
buyer ? `付款未成功。${buyer} 可以更新付款方式。` : "付款未成功。购买该订阅的管理员可以更新付款方式。",
|
|
1616
1647
|
checkAgain: "再次检查",
|
|
1617
1648
|
lockReason: "您的套餐已结束。选择套餐后即可再次进行修改。",
|
|
1618
1649
|
// As `characterCount.limitReached` ("已达到字符数上限").
|
|
@@ -1643,6 +1674,20 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1643
1674
|
switchCredited: "抵扣后续扣款",
|
|
1644
1675
|
switchNextCharge: (date) => `下次扣款日期:${date}`,
|
|
1645
1676
|
switchConfirm: "更改套餐",
|
|
1677
|
+
// 0.42 (§16): the portal for the buyer only, the in-app cancel, the grant warning.
|
|
1678
|
+
buyerHolds: (buyer) =>
|
|
1679
|
+
buyer
|
|
1680
|
+
? `付款方式和发票由购买该订阅的 ${buyer} 管理。`
|
|
1681
|
+
: "付款方式和发票由购买该订阅的管理员管理。",
|
|
1682
|
+
cancelConfirmTitle: "取消订阅",
|
|
1683
|
+
cancelConfirmBody: (date) => `您的订阅将于 ${date} 结束。在此之前,一切照常使用。`,
|
|
1684
|
+
cancelConfirmAction: "立即取消订阅",
|
|
1685
|
+
keepSubscription: "保留订阅",
|
|
1686
|
+
portalOpensNewTab: (provider, app) =>
|
|
1687
|
+
`付款和发票将在新标签页中于 ${provider} 打开;${app ? `${app} 仍在此保持打开` : "本页面仍保持打开"}。`,
|
|
1688
|
+
grantWarningTitle: "您的免费使用权仍然有效",
|
|
1689
|
+
grantWarningBody: "您的免费使用权没有结束日期。在此期间,购买不会改变您的套餐:您将为一个不生效的套餐付费。",
|
|
1690
|
+
grantWarningAction: "仍然购买",
|
|
1646
1691
|
waitingChanges: (count) => `${n(count)} 项修改正在等待套餐`,
|
|
1647
1692
|
// "放弃", as `wizard.cancelConfirmLabel`.
|
|
1648
1693
|
discardWaiting: "放弃等待中的修改",
|
|
@@ -1708,6 +1753,75 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1708
1753
|
more: "更多",
|
|
1709
1754
|
moreTitle: "更多页面",
|
|
1710
1755
|
},
|
|
1756
|
+
// 0.42.0 — docs/admin-harmonization.md §3.1: the admin area's shared words.
|
|
1757
|
+
adminArea: {
|
|
1758
|
+
title: "管理",
|
|
1759
|
+
waiting: (count) => `${n(count)} 项待处理`,
|
|
1760
|
+
forbiddenTitle: "仅限管理员",
|
|
1761
|
+
forbiddenBody: (appName) => `管理员在这里管理 ${appName}。您的账户无法打开此页面。`,
|
|
1762
|
+
forbiddenHome: "前往首页",
|
|
1763
|
+
forbiddenReviewer: "审校翻译",
|
|
1764
|
+
sections: {
|
|
1765
|
+
overview: { title: "概览", help: "一眼看清待处理的事项。" },
|
|
1766
|
+
users: { title: "用户", help: "谁拥有账户,以及每个人可以做什么。" },
|
|
1767
|
+
invitations: { title: "邀请", help: "通过电子邮件以对方的语言邀请他人;可重新发送或撤销尚未处理的邀请。" },
|
|
1768
|
+
billing: { title: "账单", help: "套餐、付款和发票。" },
|
|
1769
|
+
activity: { title: "活动", help: "管理员的操作记录,最新的在前。" },
|
|
1770
|
+
},
|
|
1771
|
+
tiles: {
|
|
1772
|
+
feedbackWaiting: "待分类",
|
|
1773
|
+
deletionRequests: "删除请求",
|
|
1774
|
+
invitationsPending: "待接受的邀请",
|
|
1775
|
+
users: "用户",
|
|
1776
|
+
usersNew: (count) => `近 7 天新增 ${n(count)} 人`,
|
|
1777
|
+
},
|
|
1778
|
+
overviewError: "无法加载概览。",
|
|
1779
|
+
retry: "重试",
|
|
1780
|
+
tools: "工具",
|
|
1781
|
+
},
|
|
1782
|
+
// 0.42.0 — docs/top-bar-harmonization.md §3.1: the top bar's shared parts; "套餐" as
|
|
1783
|
+
// `billing`.
|
|
1784
|
+
topBarParts: {
|
|
1785
|
+
tours: {
|
|
1786
|
+
menu: "导览",
|
|
1787
|
+
newDot: "有新导览",
|
|
1788
|
+
thisPage: "本页",
|
|
1789
|
+
newTours: "新导览",
|
|
1790
|
+
allTours: "全部导览…",
|
|
1791
|
+
badgeNew: "新",
|
|
1792
|
+
completed: "已完成",
|
|
1793
|
+
badgeUpdated: "已更新",
|
|
1794
|
+
updatedDot: "有更新的导览",
|
|
1795
|
+
newAndUpdated: "新增和更新",
|
|
1796
|
+
},
|
|
1797
|
+
sync: {
|
|
1798
|
+
blocked: (count) => `${n(count)} 项修改无法从此设备发送`,
|
|
1799
|
+
offline: "离线——修改已保存在此设备上,重新连接后会同步",
|
|
1800
|
+
refused: "服务器拒绝了上一次同步",
|
|
1801
|
+
syncing: "正在同步…",
|
|
1802
|
+
pending: (count) => `${n(count)} 项修改等待同步`,
|
|
1803
|
+
syncedAt: (time) => `已于 ${time} 同步`,
|
|
1804
|
+
idle: "已是最新",
|
|
1805
|
+
syncHint: "点按立即同步",
|
|
1806
|
+
offlineHint: "离线时无可同步内容",
|
|
1807
|
+
withHint: (state, hint) => `${state}——${hint}`,
|
|
1808
|
+
scoped: (scope, state) => `${scope}:${state}`,
|
|
1809
|
+
offlineShort: "离线",
|
|
1810
|
+
syncingShort: "正在同步…",
|
|
1811
|
+
waitingShort: (count) => `${n(count)} 项等待中`,
|
|
1812
|
+
refusedShort: "未同步",
|
|
1813
|
+
offlineUnsaved: "离线——重新连接前无法保存修改",
|
|
1814
|
+
saving: "正在保存…",
|
|
1815
|
+
},
|
|
1816
|
+
dev: {
|
|
1817
|
+
roleHeading: "开发 · 角色",
|
|
1818
|
+
switchPlan: "切换套餐",
|
|
1819
|
+
plan: (value) => `套餐:${value}`,
|
|
1820
|
+
planHeading: "开发 · 套餐",
|
|
1821
|
+
backTo: (role) => `返回 ${role}`,
|
|
1822
|
+
billingOff: "本地已关闭计费:切换套餐不会改变任何内容",
|
|
1823
|
+
},
|
|
1824
|
+
},
|
|
1711
1825
|
};
|
|
1712
1826
|
}
|
|
1713
1827
|
|
package/src/i18n/review.ts
CHANGED
|
@@ -393,9 +393,42 @@ export const KIT_LABEL_SAMPLES: Readonly<Record<string, readonly (readonly unkno
|
|
|
393
393
|
// 0.39: PlanSwitchConfirm's two lines with figures (§15.2.10).
|
|
394
394
|
"billing.switchFromTo": [["{{from}}", "{{to}}"]],
|
|
395
395
|
"billing.switchNextCharge": [["{{date}}"]],
|
|
396
|
+
// 0.42 (§16): the buyer's name, or none once they are gone; the cancel's period end.
|
|
397
|
+
"billing.buyerHolds": [["{{buyer}}"], [undefined]],
|
|
398
|
+
"billing.paymentFailedAskBuyer": [["{{buyer}}"], [undefined]],
|
|
399
|
+
"billing.cancelConfirmBody": [["{{date}}"]],
|
|
400
|
+
"billing.portalOpensNewTab": [["{{provider}}", "{{app}}"], ["{{provider}}", undefined]],
|
|
396
401
|
"planChange.current": [["{{plan}}"]],
|
|
397
402
|
"planChange.changed": [["{{from}}", "{{to}}"]],
|
|
398
403
|
"planChange.set": [["{{to}}"]],
|
|
399
404
|
"planChange.untilDone": [["{{date}}"]],
|
|
400
405
|
"planChange.usageOf": [["{{used}}", "{{limit}}", "{{dimension}}"]],
|
|
406
|
+
// 0.42.0 (docs/admin-harmonization.md §3.1): the menu row's count, the 403 page's app,
|
|
407
|
+
// the users tile's new accounts.
|
|
408
|
+
"adminArea.waiting": one,
|
|
409
|
+
"adminArea.forbiddenBody": [["{{app}}"]],
|
|
410
|
+
"adminArea.tiles.usersNew": one,
|
|
411
|
+
// 0.42.0 (docs/top-bar-harmonization.md §3.1): the sync indicator's counts, its time, the
|
|
412
|
+
// state joined to its hint or to the app's scope; the dev plan and the role to go back to.
|
|
413
|
+
"topBarParts.sync.blocked": one,
|
|
414
|
+
"topBarParts.sync.pending": one,
|
|
415
|
+
"topBarParts.sync.syncedAt": [["{{time}}"]],
|
|
416
|
+
"topBarParts.sync.withHint": [["{{state}}", "{{hint}}"]],
|
|
417
|
+
"topBarParts.sync.scoped": [["{{scope}}", "{{state}}"]],
|
|
418
|
+
"topBarParts.sync.waitingShort": one,
|
|
419
|
+
"topBarParts.dev.plan": [["{{plan}}"]],
|
|
420
|
+
"topBarParts.dev.backTo": [["{{role}}"]],
|
|
421
|
+
// 0.43.0 (docs/tours-harmonization.md §3, §8): the tours page's counts, its group
|
|
422
|
+
// option, the completion day and a reset's day and reason.
|
|
423
|
+
"tourCatalogue.groupAll": one,
|
|
424
|
+
"tourCatalogue.groupOption": [["{{group}}", 1], ["{{group}}", 3]],
|
|
425
|
+
"tourCatalogue.stateAll": one,
|
|
426
|
+
"tourCatalogue.stateTodo": one,
|
|
427
|
+
"tourCatalogue.stateDone": one,
|
|
428
|
+
"tourCatalogue.showing": [[3, 16]],
|
|
429
|
+
"tourCatalogue.resetOn": [["{{date}}", "{{reason}}"]],
|
|
430
|
+
"tourCatalogue.points": one,
|
|
431
|
+
"tourCatalogue.steps": one,
|
|
432
|
+
"tourCatalogue.duration": one,
|
|
433
|
+
"tourCatalogue.completedOn": [["{{date}}"]],
|
|
401
434
|
};
|
package/src/index.ts
CHANGED
|
@@ -412,6 +412,10 @@ export type { WriteLock, WriteLockLabels, WriteLockProviderProps, WriteLockKind,
|
|
|
412
412
|
// 0.18: the parts both apps' admin rosters repeat (Kurvenschmiede 6).
|
|
413
413
|
export { RoleChip, AccountStateChip, DateMark, dateColumn, DEFAULT_ACCOUNT_STATE_LABELS, ACCOUNT_STATE_TONES } from "./components/account-chips";
|
|
414
414
|
export type { RoleChipProps, RoleDefinition, RoleVocabulary, AccountState, AccountStateLabels, AccountStateChipProps, DateMarkProps, DateColumnOptions } from "./components/account-chips";
|
|
415
|
+
// 0.42 (docs/admin-harmonization.md §2.1): the role in the account menu's header, a link
|
|
416
|
+
// to the role's tool (`RoleDefinition.href`).
|
|
417
|
+
export { AccountRoleChip } from "./components/account-chips";
|
|
418
|
+
export type { AccountRoleChipProps } from "./components/account-chips";
|
|
415
419
|
// 0.18: the cold-start notice keksdose built (#199), for every app: the corner notice
|
|
416
420
|
// that explains the wait (its framework-free watchdog is lib/server-wake).
|
|
417
421
|
export { ServerWakeNotice, useServerWakeStage, DEFAULT_SERVER_WAKE_LABELS } from "./components/server-wake";
|
|
@@ -785,6 +789,28 @@ export type {
|
|
|
785
789
|
InvitationsPanelProps,
|
|
786
790
|
} from "./admin/invitations-panel";
|
|
787
791
|
export type { AdminPerson } from "./admin/admin-parts";
|
|
792
|
+
// 0.42.0 (docs/admin-harmonization.md §3.1): the admin area's template — its words, the
|
|
793
|
+
// shared sections and the catalogue helper, the 403 page, the overview and its tiles fed
|
|
794
|
+
// by `GET /admin/attention`, and the Tools list. The menu row is `./shell`'s.
|
|
795
|
+
export { DEFAULT_ADMIN_AREA_LABELS, useAdminAreaLabels } from "./admin/admin-area-labels";
|
|
796
|
+
export type { AdminAreaLabels, AdminTileLabels, AdminSharedSection } from "./admin/admin-area-labels";
|
|
797
|
+
export { ADMIN_SECTIONS, adminSections } from "./admin/admin-sections";
|
|
798
|
+
export type { AdminSectionDefinition, AdminOwnSection, AdminSectionsOptions } from "./admin/admin-sections";
|
|
799
|
+
// 0.43.0 (keksdose): the section order as ids, and the narrowed `leaveOut`.
|
|
800
|
+
export { adminSectionOrder } from "./admin/admin-sections";
|
|
801
|
+
export type { AdminSectionPlace, AdminSectionOrderOptions, AdminKeptSection } from "./admin/admin-sections";
|
|
802
|
+
export { AdminForbidden } from "./admin/admin-forbidden";
|
|
803
|
+
export type { AdminForbiddenProps } from "./admin/admin-forbidden";
|
|
804
|
+
export { AdminOverview, AttentionTile, adminWaitingCount, DEFAULT_ADMIN_ATTENTION_HREFS } from "./admin/admin-overview";
|
|
805
|
+
export type {
|
|
806
|
+
AdminAttention,
|
|
807
|
+
AdminAttentionTile,
|
|
808
|
+
AdminExtraTile,
|
|
809
|
+
AdminOverviewProps,
|
|
810
|
+
AttentionTileProps,
|
|
811
|
+
} from "./admin/admin-overview";
|
|
812
|
+
export { AdminToolLinks } from "./admin/admin-tool-links";
|
|
813
|
+
export type { AdminToolLink, AdminToolLinksProps } from "./admin/admin-tool-links";
|
|
788
814
|
// 0.33.0: the operator's plan parts (docs/billing-harmonization.md §14.12).
|
|
789
815
|
export {
|
|
790
816
|
planColumn,
|
|
@@ -811,8 +837,8 @@ export { DEFAULT_BILLING_LABELS, useBillingLabels, SUBSCRIPTION_STATUSES } from
|
|
|
811
837
|
export type { BillingLabels, SubscriptionStatus } from "./billing/billing-labels";
|
|
812
838
|
export { BILLING_INTERVALS, planPrice, minorToMajor, formatPlanPrice, billingCurrencyFor } from "./billing/plan-price";
|
|
813
839
|
export type { BillingInterval, BillingCurrency, PlanIntervalPrices, PlanPrices, PlanPriceAnswer } from "./billing/plan-price";
|
|
814
|
-
export { PlanCard, PlanPicker, planRelation } from "./billing/plan-card";
|
|
815
|
-
export type { BillingPlan, PlanRelation, PlanCardProps, PlanPickerProps, PlanChoice } from "./billing/plan-card";
|
|
840
|
+
export { PlanCard, PlanPicker, GrantWarningConfirm, planRelation } from "./billing/plan-card";
|
|
841
|
+
export type { BillingPlan, PlanRelation, PlanCardProps, PlanPickerProps, PlanChoice, GrantWarningConfirmProps } from "./billing/plan-card";
|
|
816
842
|
export { SubscriptionStatusChip, SUBSCRIPTION_STATUS_TONES } from "./billing/subscription-status-chip";
|
|
817
843
|
export type { SubscriptionStatusChipProps } from "./billing/subscription-status-chip";
|
|
818
844
|
export { BillingBanner } from "./billing/billing-banner";
|
|
@@ -855,6 +881,16 @@ export type { PlanLimitToastOptions } from "./billing/plan-limit-toast";
|
|
|
855
881
|
export { PlanSwitchConfirm } from "./billing/plan-switch";
|
|
856
882
|
export type { PlanSwitchConfirmProps, PlanSwitchSide } from "./billing/plan-switch";
|
|
857
883
|
export type { PaidPrice, PlanSwitchRequest, PlanSwitchPreview } from "./billing/billing-overview";
|
|
884
|
+
// 0.42 (§16): the portal for the buyer only, the in-app cancel, the permanent-grant warning.
|
|
885
|
+
export { isPermanentGrant } from "./billing/billing-overview";
|
|
886
|
+
export type { BillingPortalAccess } from "./billing/billing-overview";
|
|
887
|
+
export { CancelSubscriptionConfirm } from "./billing/cancel-subscription";
|
|
888
|
+
export type { CancelSubscriptionConfirmProps } from "./billing/cancel-subscription";
|
|
889
|
+
// 0.43 (§17): the provider's portal in a new tab; the in-app cancel's follow-up.
|
|
890
|
+
export { openProviderPage } from "./billing/provider-page";
|
|
891
|
+
export type { OpenProviderPageOptions, ProviderPageWay } from "./billing/provider-page";
|
|
892
|
+
export { useCancelRequest } from "./billing/cancel-request";
|
|
893
|
+
export type { CancelRequest, CancelRequested, CancelRequestView } from "./billing/cancel-request";
|
|
858
894
|
// The operator's plan parts (§14.12) are admin/plan-change, in the admin section.
|
|
859
895
|
|
|
860
896
|
// ── settings ─────────────────────────────────────────────────────────────────
|
|
@@ -188,6 +188,9 @@ export interface GlobalSearchProps {
|
|
|
188
188
|
labels?: LabelOverride<GlobalSearchLabels>;
|
|
189
189
|
/** Passed through to the palette (`empty`, `loading`, `error`, `hint`, …). */
|
|
190
190
|
paletteLabels?: Partial<CommandPaletteLabels>;
|
|
191
|
+
/** 0.43: `data-*` attributes go on the kit's trigger button (`trigger="button"`) — a
|
|
192
|
+
* tour's anchor (`data-tour="search"`), a test hook. A function trigger is the app's. */
|
|
193
|
+
[key: `data-${string}`]: string | number | boolean | undefined;
|
|
191
194
|
}
|
|
192
195
|
|
|
193
196
|
function isApplePlatform(): boolean {
|
|
@@ -290,6 +293,7 @@ function GlobalSearchImpl({
|
|
|
290
293
|
density,
|
|
291
294
|
labels,
|
|
292
295
|
paletteLabels,
|
|
296
|
+
...attributes
|
|
293
297
|
}: GlobalSearchProps & { navigate: (href: string) => void; hrefFor: (href: string) => string }) {
|
|
294
298
|
const l = useKitLabels("globalSearch", DEFAULT_GLOBAL_SEARCH_LABELS, labels);
|
|
295
299
|
const pl = useKitLabels("commandPalette", DEFAULT_COMMAND_PALETTE_LABELS, paletteLabels);
|
|
@@ -563,6 +567,7 @@ function GlobalSearchImpl({
|
|
|
563
567
|
className={hideTriggerOnPhone ? "hidden sm:block" : undefined}
|
|
564
568
|
>
|
|
565
569
|
<button
|
|
570
|
+
{...Object.fromEntries(Object.entries(attributes).filter(([k]) => k.startsWith("data-")))}
|
|
566
571
|
type="button"
|
|
567
572
|
onClick={openSearch}
|
|
568
573
|
aria-label={triggerLabel}
|
|
@@ -29,6 +29,13 @@ export interface SettingsGroup<G extends string = string> {
|
|
|
29
29
|
* kastlan's `/admin/billing` while billing is off. Default: visible.
|
|
30
30
|
*/
|
|
31
31
|
visible?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* 0.43: the group shows with no visible entry — a page of its own rather than of setting
|
|
34
|
+
* cards (the admin area's Overview, whose tiles are no settings; `adminSections` sets
|
|
35
|
+
* it). `visible: false` still hides it. Default: a group shows only with an entry once
|
|
36
|
+
* `entries` are given (§4.1).
|
|
37
|
+
*/
|
|
38
|
+
standalone?: boolean;
|
|
32
39
|
}
|
|
33
40
|
|
|
34
41
|
/** One setting, and the card that holds it (§4.1). */
|
|
@@ -57,7 +64,8 @@ export interface SettingsEntry<G extends string = string> {
|
|
|
57
64
|
/**
|
|
58
65
|
* The groups that show, in their order: not `visible: false`, and — when `entries` is
|
|
59
66
|
* given — holding at least one visible entry (§4.1: Kurvenschmiede's notifications group
|
|
60
|
-
* stays hidden until it has a card). Without `entries` only the
|
|
67
|
+
* stays hidden until it has a card) or `standalone` (0.43). Without `entries` only the
|
|
68
|
+
* groups' own flag counts.
|
|
61
69
|
*/
|
|
62
70
|
export function visibleSettingsGroups<G extends string>(
|
|
63
71
|
groups: readonly SettingsGroup<G>[],
|
|
@@ -66,7 +74,7 @@ export function visibleSettingsGroups<G extends string>(
|
|
|
66
74
|
if (!entries) return groups.filter((g) => g.visible !== false);
|
|
67
75
|
const filled = new Set<G>();
|
|
68
76
|
for (const e of entries) if (e.visible !== false) filled.add(e.group);
|
|
69
|
-
return groups.filter((g) => g.visible !== false && filled.has(g.id));
|
|
77
|
+
return groups.filter((g) => g.visible !== false && (g.standalone === true || filled.has(g.id)));
|
|
70
78
|
}
|
|
71
79
|
|
|
72
80
|
/** The visible entries of the visible groups — what search may find. */
|
|
@@ -40,6 +40,9 @@ export type SettingsLayoutWidth = "6xl" | "7xl";
|
|
|
40
40
|
* about twelve, keksdose 26; a page of six needs none. */
|
|
41
41
|
export const SETTINGS_SEARCH_THRESHOLD = 8;
|
|
42
42
|
|
|
43
|
+
/** The desktop sidebar's column: sticky beside a long group (§3.2). */
|
|
44
|
+
const SIDEBAR_COLUMN = "mb-4 md:sticky md:top-6 md:mb-0 md:self-start";
|
|
45
|
+
|
|
43
46
|
export interface SettingsLayoutProps<G extends string> {
|
|
44
47
|
/** The page's `h1`: "Settings", "Administration". Default: `labels.title`. */
|
|
45
48
|
title?: ReactNode;
|
|
@@ -72,6 +75,12 @@ export interface SettingsLayoutProps<G extends string> {
|
|
|
72
75
|
* own navigation carries them.
|
|
73
76
|
*/
|
|
74
77
|
phoneFooter?: ReactNode;
|
|
78
|
+
/**
|
|
79
|
+
* 0.42.0 (docs/admin-harmonization.md §2.5 decision 16): content under the section
|
|
80
|
+
* list on a desktop, in the same sticky column — the admin area's Tools list
|
|
81
|
+
* (`AdminToolLinks`). Not shown on a phone, where `phoneFooter` carries the same links.
|
|
82
|
+
*/
|
|
83
|
+
sidebarFooter?: ReactNode;
|
|
75
84
|
/** Prop > `<UiKitProvider labels={{ settings }}>` > English. */
|
|
76
85
|
labels?: LabelOverride<SettingsLabels>;
|
|
77
86
|
/** See {@link SettingsLayoutMode}. Default `"auto"`: the screen decides. */
|
|
@@ -151,6 +160,7 @@ export function SettingsLayout<G extends string>({
|
|
|
151
160
|
width = "6xl",
|
|
152
161
|
renderGroup,
|
|
153
162
|
phoneFooter,
|
|
163
|
+
sidebarFooter,
|
|
154
164
|
labels: labelsProp,
|
|
155
165
|
layout = "auto",
|
|
156
166
|
appName,
|
|
@@ -376,45 +386,59 @@ export function SettingsLayout<G extends string>({
|
|
|
376
386
|
);
|
|
377
387
|
} else {
|
|
378
388
|
const open = group === null ? undefined : groupById.get(group);
|
|
389
|
+
// The section list alone, or (0.42) with the app's `sidebarFooter` under it in one
|
|
390
|
+
// sticky column.
|
|
391
|
+
const withSidebarFooter = (tabs: ReactNode) =>
|
|
392
|
+
sidebarFooter == null ? (
|
|
393
|
+
tabs
|
|
394
|
+
) : (
|
|
395
|
+
<div className={cn(SIDEBAR_COLUMN, "space-y-6")}>
|
|
396
|
+
{tabs}
|
|
397
|
+
<div data-slot="settings-sidebar-footer">{sidebarFooter}</div>
|
|
398
|
+
</div>
|
|
399
|
+
);
|
|
379
400
|
body = (
|
|
380
401
|
<div className={pageClass} data-settings-view="desktop">
|
|
381
402
|
<PageHeader size="compact" title={pageTitle} />
|
|
382
403
|
{searchField}
|
|
383
404
|
<div className="md:grid md:grid-cols-[14rem_minmax(0,1fr)] md:gap-6">
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
<
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
405
|
+
{withSidebarFooter(
|
|
406
|
+
<Tabs<G>
|
|
407
|
+
orientation="vertical"
|
|
408
|
+
aria-label={labels.sections}
|
|
409
|
+
// Sticky (new in the harmonisation, §3.2): keksdose's notifications group
|
|
410
|
+
// scrolls for screens, and the list should stay in view beside it. With a
|
|
411
|
+
// `sidebarFooter` the column round both is the sticky one.
|
|
412
|
+
className={sidebarFooter == null ? SIDEBAR_COLUMN : undefined}
|
|
413
|
+
panelId={open && !searching ? panelId : undefined}
|
|
414
|
+
tabs={route.groups.map((g) => {
|
|
415
|
+
const count = hitsByGroup.get(g.id) ?? 0;
|
|
416
|
+
// While searching, the groups with nothing to show step back (keksdose).
|
|
417
|
+
const dim = searching && count === 0;
|
|
418
|
+
return {
|
|
419
|
+
id: g.id,
|
|
420
|
+
href: `${root}${settingsHref(base, g.id)}`,
|
|
421
|
+
name: g.title,
|
|
422
|
+
label: <span className={cn(dim && "opacity-40")}>{g.title}</span>,
|
|
423
|
+
icon: <span className={cn("inline-flex [&_svg]:size-4", dim && "opacity-40")}>{g.icon}</span>,
|
|
424
|
+
badge:
|
|
425
|
+
searching && count > 0 ? (
|
|
426
|
+
<Chip size="sm" tone="brand">
|
|
427
|
+
<span aria-hidden>{count}</span>
|
|
428
|
+
<span className="sr-only-fixed">{labels.matchCount(count)}</span>
|
|
429
|
+
</Chip>
|
|
430
|
+
) : undefined,
|
|
431
|
+
};
|
|
432
|
+
})}
|
|
433
|
+
active={(open?.id ?? route.groups[0]?.id) as G}
|
|
434
|
+
onChange={(id) => {
|
|
435
|
+
// While searching the hits stand where the group would; a click on a group
|
|
436
|
+
// means "go there", so the search makes way (keksdose).
|
|
437
|
+
setQuery("");
|
|
438
|
+
select(id);
|
|
439
|
+
}}
|
|
440
|
+
/>,
|
|
441
|
+
)}
|
|
418
442
|
<div className="min-w-0 space-y-4">
|
|
419
443
|
{searching ? (
|
|
420
444
|
results
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import { Globe } from "lucide-react";
|
|
4
|
+
import { Disclosure } from "../components/disclosure";
|
|
5
|
+
import { MenuItem } from "../components/menu-item";
|
|
6
|
+
import { DEFAULT_TOP_BAR_LABELS, useKitLabels } from "../i18n/kit-labels";
|
|
7
|
+
|
|
8
|
+
/** One offered language in the account menu's sub-list. */
|
|
9
|
+
export interface AccountMenuLanguageOption {
|
|
10
|
+
code: string;
|
|
11
|
+
/** Its name, in its own language ("Deutsch", "Français"). */
|
|
12
|
+
label: ReactNode;
|
|
13
|
+
/**
|
|
14
|
+
* A flag before the name, as the app draws it — keksdose's flag-icons span
|
|
15
|
+
* (`<span aria-hidden className="fi fi-ch …" />`). A node rather than a country code, so
|
|
16
|
+
* the kit ships no flag set; decorative, so give it `aria-hidden`.
|
|
17
|
+
*/
|
|
18
|
+
flag?: ReactNode;
|
|
19
|
+
/**
|
|
20
|
+
* Or the ISO 3166-1 alpha-2 country (lowercase) whose flag-icons flag to draw, as
|
|
21
|
+
* `LanguageMenu`'s `LanguageOption` takes it — so one language list feeds both
|
|
22
|
+
* (Kurvenschmiede's `LANGUAGES`). Needs the app's flag-icons CSS, as `LanguageMenu`
|
|
23
|
+
* does. `flag` wins when both are given.
|
|
24
|
+
*/
|
|
25
|
+
country?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The option's flag: its own node, else the flag-icons flag of its country. */
|
|
29
|
+
function flagOf(lang: AccountMenuLanguageOption): ReactNode {
|
|
30
|
+
if (lang.flag !== undefined) return lang.flag;
|
|
31
|
+
if (!lang.country) return undefined;
|
|
32
|
+
return (
|
|
33
|
+
<span
|
|
34
|
+
aria-hidden
|
|
35
|
+
data-country={lang.country}
|
|
36
|
+
className={`fi fi-${lang.country} inline-block h-[0.9375rem] w-5 shrink-0 rounded-sm shadow-[0_0_0_1px_rgba(0,0,0,0.08)]`}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface AccountMenuLanguageProps {
|
|
42
|
+
languages: readonly AccountMenuLanguageOption[];
|
|
43
|
+
/** The active language's code. */
|
|
44
|
+
value: string | undefined;
|
|
45
|
+
/** A pick: the app sets the device's language and, signed in, the account's
|
|
46
|
+
* (settings §6.2). */
|
|
47
|
+
onPick: (code: string) => void;
|
|
48
|
+
/** The account menu's `close` (from `TopBarActionMenu`'s `children`): a pick shuts it. */
|
|
49
|
+
close?: () => void;
|
|
50
|
+
/** The row's name. Default: `topBar.language` ("Language"). */
|
|
51
|
+
label?: string;
|
|
52
|
+
/** Open the sub-list at first. Default `false`. */
|
|
53
|
+
defaultOpen?: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The language choice INSIDE the account menu (docs/top-bar-harmonization.md §2.3),
|
|
58
|
+
* keksdose's sub-list: a `Disclosure variant="menu"` row — the globe, "Language", the
|
|
59
|
+
* active language's flag and the chevron — that opens in place onto one checked
|
|
60
|
+
* `MenuItem` per language. Inline rather than a nested popover: a popover inside a
|
|
61
|
+
* popover fights the outside click and has nowhere to go on a phone (keksdose #140).
|
|
62
|
+
*
|
|
63
|
+
* It renders its own `<li>`: drop it into `TopBarActionMenu`'s `children` first after the
|
|
64
|
+
* app's context rows (§6.5). Signed out there is no account menu; `LanguageMenu` stays
|
|
65
|
+
* the bar's button (§2.3).
|
|
66
|
+
*/
|
|
67
|
+
export function AccountMenuLanguage({
|
|
68
|
+
languages,
|
|
69
|
+
value,
|
|
70
|
+
onPick,
|
|
71
|
+
close,
|
|
72
|
+
label,
|
|
73
|
+
defaultOpen = false,
|
|
74
|
+
}: AccountMenuLanguageProps) {
|
|
75
|
+
const words = useKitLabels("topBar", DEFAULT_TOP_BAR_LABELS);
|
|
76
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
77
|
+
const active = languages.find((l) => l.code === value);
|
|
78
|
+
return (
|
|
79
|
+
<li>
|
|
80
|
+
<Disclosure
|
|
81
|
+
variant="menu"
|
|
82
|
+
open={open}
|
|
83
|
+
onOpenChange={setOpen}
|
|
84
|
+
title={
|
|
85
|
+
<span className="flex items-center justify-between gap-3">
|
|
86
|
+
<span className="flex items-center gap-2">
|
|
87
|
+
<Globe aria-hidden className="size-4" />
|
|
88
|
+
{label ?? words.language}
|
|
89
|
+
</span>
|
|
90
|
+
{active && flagOf(active)}
|
|
91
|
+
</span>
|
|
92
|
+
}
|
|
93
|
+
>
|
|
94
|
+
<ul>
|
|
95
|
+
{languages.map((lang) => (
|
|
96
|
+
<li key={lang.code}>
|
|
97
|
+
<MenuItem
|
|
98
|
+
checked={lang.code === value}
|
|
99
|
+
onClick={() => {
|
|
100
|
+
onPick(lang.code);
|
|
101
|
+
setOpen(false);
|
|
102
|
+
close?.();
|
|
103
|
+
}}
|
|
104
|
+
leading={flagOf(lang)}
|
|
105
|
+
// Under the row's own text, past the globe.
|
|
106
|
+
className="ps-9"
|
|
107
|
+
>
|
|
108
|
+
{lang.label}
|
|
109
|
+
</MenuItem>
|
|
110
|
+
</li>
|
|
111
|
+
))}
|
|
112
|
+
</ul>
|
|
113
|
+
</Disclosure>
|
|
114
|
+
</li>
|
|
115
|
+
);
|
|
116
|
+
}
|