@eifi1/ui-kit 0.30.0 → 0.31.1
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 +42 -5
- package/dist/account/data-export-setting.js +3 -2
- package/dist/account/data-export-setting.js.map +1 -1
- package/dist/account/delete-account-setting.d.ts +5 -1
- package/dist/account/delete-account-setting.js +3 -2
- package/dist/account/delete-account-setting.js.map +1 -1
- package/dist/account/email-change-setting.js +4 -3
- package/dist/account/email-change-setting.js.map +1 -1
- package/dist/account/sessions-setting.js +3 -2
- package/dist/account/sessions-setting.js.map +1 -1
- package/dist/admin/admin-action-confirm.d.ts +5 -1
- package/dist/admin/admin-parts.d.ts +8 -1
- package/dist/admin/admin-parts.js +1 -1
- package/dist/admin/admin-parts.js.map +1 -1
- package/dist/admin/invitations-panel.d.ts +5 -1
- package/dist/admin/invitations-panel.js +3 -2
- package/dist/admin/invitations-panel.js.map +1 -1
- package/dist/admin/reviewer-scope-editor.d.ts +5 -1
- package/dist/admin/role-select.d.ts +5 -1
- package/dist/admin/transfer-ownership-dialog.d.ts +5 -1
- package/dist/admin/user-roster.d.ts +5 -1
- package/dist/auth/auth-errors.d.ts +24 -6
- package/dist/auth/auth-errors.js +7 -1
- package/dist/auth/auth-errors.js.map +1 -1
- package/dist/auth/register-form.d.ts +5 -1
- package/dist/auth/reset-password-form.d.ts +1 -1
- package/dist/auth/reset-password-form.js +2 -1
- package/dist/auth/reset-password-form.js.map +1 -1
- package/dist/auth/sign-in-form.d.ts +15 -1
- package/dist/auth/sign-in-form.js +12 -3
- package/dist/auth/sign-in-form.js.map +1 -1
- package/dist/auth/verify-email.d.ts +4 -0
- package/dist/auth/verify-email.js +3 -2
- package/dist/auth/verify-email.js.map +1 -1
- package/dist/chart.d.ts +5 -1
- package/dist/components/account-settings-labels.d.ts +12 -0
- package/dist/components/account-settings-labels.js +2 -1
- package/dist/components/account-settings-labels.js.map +1 -1
- package/dist/components/account-settings.d.ts +8 -2
- package/dist/components/account-settings.js +19 -11
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/amount-input.d.ts +5 -1
- package/dist/components/button-group.d.ts +5 -1
- package/dist/components/calculator.d.ts +5 -1
- package/dist/components/confirm-dialog.d.ts +5 -1
- package/dist/components/confirm-dialog.js +7 -1
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/copy-button.d.ts +5 -1
- package/dist/components/danger-confirm.d.ts +5 -1
- package/dist/components/data-table.js +8 -1
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.js +9 -4
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/facing-pair.d.ts +5 -1
- package/dist/components/file-button.d.ts +5 -1
- package/dist/components/file-dropzone.d.ts +5 -1
- package/dist/components/form-actions.d.ts +5 -1
- package/dist/components/iban-input.d.ts +5 -1
- package/dist/components/language-select.d.ts +5 -1
- package/dist/components/legal-page.d.ts +5 -1
- package/dist/components/legal.d.ts +5 -1
- package/dist/components/money-field.d.ts +5 -1
- package/dist/components/number-field.d.ts +5 -1
- package/dist/components/number-input.d.ts +5 -1
- package/dist/components/numpad-sheet.d.ts +5 -1
- package/dist/components/passkeys-setting.js +2 -1
- package/dist/components/passkeys-setting.js.map +1 -1
- package/dist/components/phone-input.d.ts +5 -1
- package/dist/components/series-chart.d.ts +5 -1
- package/dist/components/settings-fields.d.ts +40 -3
- package/dist/components/settings-fields.js +20 -1
- package/dist/components/settings-fields.js.map +1 -1
- package/dist/components/share-card.d.ts +5 -1
- package/dist/components/text-link.d.ts +5 -1
- package/dist/components/time-input.d.ts +5 -1
- package/dist/components/ui.d.ts +5 -1
- package/dist/{delete-account-setting-CGVMckMw.d.ts → delete-account-setting-CpIhzxxZ.d.ts} +60 -23
- package/dist/demo/demo-banner.d.ts +51 -0
- package/dist/demo/demo-banner.js +97 -0
- package/dist/demo/demo-banner.js.map +1 -0
- package/dist/demo/demo-countdown.d.ts +58 -0
- package/dist/demo/demo-countdown.js +79 -0
- package/dist/demo/demo-countdown.js.map +1 -0
- package/dist/demo/demo-ended.d.ts +45 -0
- package/dist/demo/demo-ended.js +42 -0
- package/dist/demo/demo-ended.js.map +1 -0
- package/dist/demo/demo-labels.d.ts +53 -0
- package/dist/demo/demo-labels.js +29 -0
- package/dist/demo/demo-labels.js.map +1 -0
- package/dist/demo/demo-session.d.ts +30 -0
- package/dist/demo/demo-session.js +8 -0
- package/dist/demo/demo-session.js.map +1 -0
- package/dist/demo/demo-start.d.ts +54 -0
- package/dist/demo/demo-start.js +68 -0
- package/dist/demo/demo-start.js.map +1 -0
- package/dist/feedback/feedback-attachment.d.ts +5 -1
- package/dist/feedback/feedback-context.d.ts +5 -1
- package/dist/feedback/feedback-crash.d.ts +5 -1
- package/dist/feedback/feedback-dialog.d.ts +5 -1
- package/dist/feedback/feedback-inbox.d.ts +5 -1
- package/dist/feedback/feedback-inbox.js +12 -2
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/feedback/feedback-labels.d.ts +5 -1
- package/dist/feedback/feedback-labels.js +1 -0
- package/dist/feedback/feedback-labels.js.map +1 -1
- package/dist/feedback/feedback-menu.d.ts +5 -1
- package/dist/feedback/feedback-record.d.ts +5 -1
- package/dist/feedback/feedback-record.js +2 -0
- package/dist/feedback/feedback-record.js.map +1 -1
- package/dist/feedback/feedback-row-detail.d.ts +5 -1
- package/dist/feedback/feedback-row-detail.js +7 -0
- package/dist/feedback/feedback-row-detail.js.map +1 -1
- package/dist/feedback/feedback-status-undo.d.ts +5 -1
- package/dist/feedback/feedback-submit.d.ts +5 -1
- package/dist/feedback/feedback-swipe.d.ts +6 -2
- package/dist/feedback/feedback-swipe.js.map +1 -1
- package/dist/feedback/feedback-table.d.ts +5 -1
- package/dist/feedback/feedback-thread.d.ts +5 -1
- package/dist/feedback.d.ts +5 -1
- package/dist/hooks/use-file-drop.d.ts +5 -1
- package/dist/i18n/defaults.d.ts +5 -1
- package/dist/i18n/defaults.js +6 -0
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.d.ts +5 -1
- package/dist/i18n/german.js +85 -2
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +5 -1
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/languages.d.ts +5 -1
- package/dist/i18n/locales/de-CH.d.ts +5 -1
- package/dist/i18n/locales/en.d.ts +5 -1
- package/dist/i18n/locales/es.d.ts +5 -1
- package/dist/i18n/locales/es.js +82 -2
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +5 -1
- package/dist/i18n/locales/fr.js +83 -2
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +5 -1
- package/dist/i18n/locales/hu.js +83 -2
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +5 -1
- package/dist/i18n/locales/it.js +82 -2
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +5 -1
- package/dist/i18n/locales/zh.js +81 -2
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.d.ts +5 -1
- package/dist/i18n/review.js +15 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +25 -3
- package/dist/index.js +96 -0
- package/dist/index.js.map +1 -1
- package/dist/landing/access.d.ts +48 -0
- package/dist/landing/access.js +38 -0
- package/dist/landing/access.js.map +1 -0
- package/dist/landing/landing-actions.d.ts +140 -0
- package/dist/landing/landing-actions.js +39 -0
- package/dist/landing/landing-actions.js.map +1 -0
- package/dist/landing/landing-labels.d.ts +43 -0
- package/dist/landing/landing-labels.js +23 -0
- package/dist/landing/landing-labels.js.map +1 -0
- package/dist/landing/landing-sections.d.ts +218 -0
- package/dist/landing/landing-sections.js +167 -0
- package/dist/landing/landing-sections.js.map +1 -0
- package/dist/landing/page-seo.d.ts +99 -0
- package/dist/landing/page-seo.js +121 -0
- package/dist/landing/page-seo.js.map +1 -0
- package/dist/landing/public-header.d.ts +148 -0
- package/dist/landing/public-header.js +49 -0
- package/dist/landing/public-header.js.map +1 -0
- package/dist/landing/routing.d.ts +231 -0
- package/dist/landing/routing.js +84 -0
- package/dist/landing/routing.js.map +1 -0
- package/dist/rhf/fields.d.ts +5 -1
- package/dist/rhf/form.d.ts +5 -1
- package/dist/rhf.d.ts +5 -1
- package/dist/settings/settings-catalogue.d.ts +84 -0
- package/dist/settings/settings-catalogue.js +47 -0
- package/dist/settings/settings-catalogue.js.map +1 -0
- package/dist/settings/settings-context.d.ts +31 -0
- package/dist/settings/settings-context.js +11 -0
- package/dist/settings/settings-context.js.map +1 -0
- package/dist/settings/settings-heading.d.ts +50 -0
- package/dist/settings/settings-heading.js +27 -0
- package/dist/settings/settings-heading.js.map +1 -0
- package/dist/settings/settings-labels.d.ts +48 -0
- package/dist/settings/settings-labels.js +43 -0
- package/dist/settings/settings-labels.js.map +1 -0
- package/dist/settings/settings-layout.d.ts +77 -0
- package/dist/settings/settings-layout.js +242 -0
- package/dist/settings/settings-layout.js.map +1 -0
- package/dist/settings/settings-section.d.ts +133 -0
- package/dist/settings/settings-section.js +63 -0
- package/dist/settings/settings-section.js.map +1 -0
- package/dist/settings/use-account-language.d.ts +83 -0
- package/dist/settings/use-account-language.js +62 -0
- package/dist/settings/use-account-language.js.map +1 -0
- package/dist/settings/use-settings-focus.d.ts +34 -0
- package/dist/settings/use-settings-focus.js +77 -0
- package/dist/settings/use-settings-focus.js.map +1 -0
- package/dist/settings/use-settings-route.d.ts +118 -0
- package/dist/settings/use-settings-route.js +120 -0
- package/dist/settings/use-settings-route.js.map +1 -0
- package/dist/shell/app-shell.d.ts +11 -1
- package/dist/shell/app-shell.js +3 -2
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/top-bar-brand.d.ts +5 -1
- package/dist/shell.d.ts +15 -1
- package/dist/shell.js +56 -0
- package/dist/shell.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +5 -1
- package/dist/wizard.d.ts +5 -1
- package/package.json +2 -1
- package/src/account/data-export-setting.tsx +3 -2
- package/src/account/delete-account-setting.tsx +3 -2
- package/src/account/email-change-setting.tsx +4 -7
- package/src/account/sessions-setting.tsx +3 -2
- package/src/admin/admin-parts.ts +9 -2
- package/src/admin/invitations-panel.tsx +11 -4
- package/src/auth/auth-errors.ts +36 -5
- package/src/auth/reset-password-form.tsx +6 -2
- package/src/auth/sign-in-form.tsx +34 -3
- package/src/auth/verify-email.tsx +14 -2
- package/src/components/account-settings-labels.ts +13 -0
- package/src/components/account-settings.tsx +33 -12
- package/src/components/confirm-dialog.tsx +20 -1
- package/src/components/data-table.tsx +8 -0
- package/src/components/date-picker.tsx +9 -4
- package/src/components/passkeys-setting.tsx +2 -1
- package/src/components/settings-fields.tsx +50 -1
- package/src/demo/demo-banner.tsx +159 -0
- package/src/demo/demo-countdown.ts +141 -0
- package/src/demo/demo-ended.tsx +89 -0
- package/src/demo/demo-labels.ts +78 -0
- package/src/demo/demo-session.ts +32 -0
- package/src/demo/demo-start.tsx +150 -0
- package/src/feedback/feedback-inbox.tsx +21 -8
- package/src/feedback/feedback-labels.ts +2 -1
- package/src/feedback/feedback-record.ts +10 -7
- package/src/feedback/feedback-row-detail.tsx +28 -4
- package/src/feedback/feedback-swipe.tsx +1 -1
- package/src/i18n/defaults.ts +6 -0
- package/src/i18n/german.ts +87 -0
- package/src/i18n/kit-labels.tsx +9 -0
- package/src/i18n/locales/es.ts +84 -0
- package/src/i18n/locales/fr.ts +85 -0
- package/src/i18n/locales/hu.ts +85 -0
- package/src/i18n/locales/it.ts +84 -0
- package/src/i18n/locales/zh.ts +82 -0
- package/src/i18n/review.ts +14 -0
- package/src/index.ts +98 -1
- package/src/landing/access.ts +97 -0
- package/src/landing/landing-actions.tsx +96 -0
- package/src/landing/landing-labels.ts +59 -0
- package/src/landing/landing-sections.tsx +337 -0
- package/src/landing/page-seo.ts +251 -0
- package/src/landing/public-header.tsx +120 -0
- package/src/landing/routing.tsx +226 -0
- package/src/settings/settings-catalogue.ts +132 -0
- package/src/settings/settings-context.ts +33 -0
- package/src/settings/settings-heading.tsx +65 -0
- package/src/settings/settings-labels.ts +87 -0
- package/src/settings/settings-layout.tsx +379 -0
- package/src/settings/settings-section.tsx +108 -0
- package/src/settings/use-account-language.ts +146 -0
- package/src/settings/use-settings-focus.ts +120 -0
- package/src/settings/use-settings-route.ts +258 -0
- package/src/shell/app-shell.tsx +10 -2
- package/src/shell.ts +51 -0
package/src/index.ts
CHANGED
|
@@ -545,7 +545,7 @@ export type { CompanySwitcherProps, CompanySwitcherLabels, CompanySwitcherCompan
|
|
|
545
545
|
// invitations panel, and the account's own settings — email change, sessions, deletion,
|
|
546
546
|
// export. Callbacks only; the confirmation level is the server's.
|
|
547
547
|
export { isRateLimited, retryAfterSeconds } from "./auth/auth-errors";
|
|
548
|
-
export type { AccountErrorCode, KitErrorCode } from "./auth/auth-errors";
|
|
548
|
+
export type { AccountErrorCode, DemoErrorCode, KitErrorCode } from "./auth/auth-errors";
|
|
549
549
|
export { EmailChangeSetting, DEFAULT_EMAIL_CHANGE_LABELS } from "./account/email-change-setting";
|
|
550
550
|
export type {
|
|
551
551
|
EmailChangeSettingProps,
|
|
@@ -633,6 +633,103 @@ export type {
|
|
|
633
633
|
InvitationsPanelProps,
|
|
634
634
|
} from "./admin/invitations-panel";
|
|
635
635
|
export type { AdminPerson } from "./admin/admin-parts";
|
|
636
|
+
|
|
637
|
+
// ── 0.31.0: the settings page and the admin page on one shell (docs/settings-harmonization.md) ──
|
|
638
|
+
// Router-aware: the layout, its route and focus hooks (also in `@eifi1/ui-kit/shell`).
|
|
639
|
+
export { SettingsLayout, SETTINGS_SEARCH_THRESHOLD } from "./settings/settings-layout";
|
|
640
|
+
export type { SettingsLayoutProps, SettingsLayoutWidth } from "./settings/settings-layout";
|
|
641
|
+
export {
|
|
642
|
+
useSettingsRoute,
|
|
643
|
+
resolveSettingsLocation,
|
|
644
|
+
settingsFromListState,
|
|
645
|
+
SETTINGS_FROM_LIST_STATE,
|
|
646
|
+
} from "./settings/use-settings-route";
|
|
647
|
+
export type {
|
|
648
|
+
UseSettingsRouteOptions,
|
|
649
|
+
SettingsRoute,
|
|
650
|
+
SettingsLayoutMode,
|
|
651
|
+
SettingsLocation,
|
|
652
|
+
SettingsLocationRules,
|
|
653
|
+
SettingsLocationResult,
|
|
654
|
+
} from "./settings/use-settings-route";
|
|
655
|
+
export { useSettingsFocus, SETTINGS_FOCUS_RING, SETTINGS_FOCUS_MS } from "./settings/use-settings-focus";
|
|
656
|
+
// The router-free companions: a card, the context, the heading level, the catalogue.
|
|
657
|
+
export { SettingsSection } from "./settings/settings-section";
|
|
658
|
+
export type { SettingsSectionProps } from "./settings/settings-section";
|
|
659
|
+
export { useSettingsLayout } from "./settings/settings-context";
|
|
660
|
+
export type { SettingsLayoutContextValue } from "./settings/settings-context";
|
|
661
|
+
export { SettingsHeadingLevel, useSettingsHeadingLevel } from "./settings/settings-heading";
|
|
662
|
+
export type { SettingsHeadingLevelProps, SettingsHeadingTag } from "./settings/settings-heading";
|
|
663
|
+
export {
|
|
664
|
+
settingsSearchEntries,
|
|
665
|
+
visibleSettingsGroups,
|
|
666
|
+
visibleSettingsEntries,
|
|
667
|
+
settingsHref,
|
|
668
|
+
} from "./settings/settings-catalogue";
|
|
669
|
+
export type { SettingsGroup, SettingsEntry, SettingsSearchEntriesOptions } from "./settings/settings-catalogue";
|
|
670
|
+
export { DEFAULT_SETTINGS_LABELS, useSettingsLabels } from "./settings/settings-labels";
|
|
671
|
+
export type { SettingsLabels, SettingsGroupLabels, SettingsCoreGroup } from "./settings/settings-labels";
|
|
672
|
+
// Only the language follows the account (§6.2).
|
|
673
|
+
export { useAccountLanguage, resolveAccountLanguage, matchOfferedLanguage } from "./settings/use-account-language";
|
|
674
|
+
export type {
|
|
675
|
+
UseAccountLanguageOptions,
|
|
676
|
+
AccountLanguage,
|
|
677
|
+
AccountLanguageSource,
|
|
678
|
+
ResolveAccountLanguageInput,
|
|
679
|
+
ResolvedAccountLanguage,
|
|
680
|
+
} from "./settings/use-account-language";
|
|
681
|
+
|
|
682
|
+
// ── 0.31.0: the public landing page and the demo (docs/landing-demo-harmonization.md) ──
|
|
683
|
+
export { DEFAULT_LANDING_LABELS, useLandingLabels } from "./landing/landing-labels";
|
|
684
|
+
export type { LandingLabels } from "./landing/landing-labels";
|
|
685
|
+
export { accessAction, useAccessAction } from "./landing/access";
|
|
686
|
+
export type { AccessChoice, AccessLink, AccessLabels } from "./landing/access";
|
|
687
|
+
export { LandingActions } from "./landing/landing-actions";
|
|
688
|
+
export type { LandingActionsProps, LandingSession } from "./landing/landing-actions";
|
|
689
|
+
export { Hero, FeatureRows, FeatureRow, TrustStrip, CtaBand, PublicFooter } from "./landing/landing-sections";
|
|
690
|
+
export type {
|
|
691
|
+
HeroProps,
|
|
692
|
+
FeatureRowsProps,
|
|
693
|
+
FeatureRowProps,
|
|
694
|
+
TrustItem,
|
|
695
|
+
TrustStripProps,
|
|
696
|
+
CtaBandProps,
|
|
697
|
+
PublicFooterProps,
|
|
698
|
+
} from "./landing/landing-sections";
|
|
699
|
+
export { usePageSeo, seoCopyProblems, metaContent } from "./landing/page-seo";
|
|
700
|
+
export type { SeoCopy, SeoCopyLimits, SeoCopyProblem, SeoCopyProblemCode } from "./landing/page-seo";
|
|
701
|
+
// Router-aware (also in `@eifi1/ui-kit/shell`): the header and the resume.
|
|
702
|
+
export {
|
|
703
|
+
RootEntry,
|
|
704
|
+
RedirectIfAuthed,
|
|
705
|
+
useLastVisitedPage,
|
|
706
|
+
readLastVisitedPage,
|
|
707
|
+
clearLastVisitedPage,
|
|
708
|
+
safeNextPath,
|
|
709
|
+
NEXT_PARAM,
|
|
710
|
+
DEFAULT_LAST_VISITED_EXCLUDES,
|
|
711
|
+
} from "./landing/routing";
|
|
712
|
+
export type {
|
|
713
|
+
RootEntryProps,
|
|
714
|
+
RedirectIfAuthedProps,
|
|
715
|
+
RoutingSession,
|
|
716
|
+
LastVisitedPageOptions,
|
|
717
|
+
PathPattern,
|
|
718
|
+
} from "./landing/routing";
|
|
719
|
+
export { PublicHeader } from "./landing/public-header";
|
|
720
|
+
export type { PublicHeaderProps, PublicHeaderBrand } from "./landing/public-header";
|
|
721
|
+
export { DEFAULT_DEMO_LABELS, useDemoLabels } from "./demo/demo-labels";
|
|
722
|
+
export type { DemoLabels } from "./demo/demo-labels";
|
|
723
|
+
export { isDemoSession } from "./demo/demo-session";
|
|
724
|
+
export type { DemoModel, DemoSessionUser } from "./demo/demo-session";
|
|
725
|
+
export { useDemoCountdown, demoCountdown, DEMO_WARNING_MINUTES, DEMO_MINUTES_ONLY } from "./demo/demo-countdown";
|
|
726
|
+
export type { DemoCountdown, DemoCountdownOptions, DemoExpiry } from "./demo/demo-countdown";
|
|
727
|
+
export { DemoStart } from "./demo/demo-start";
|
|
728
|
+
export type { DemoStartProps } from "./demo/demo-start";
|
|
729
|
+
export { DemoBanner } from "./demo/demo-banner";
|
|
730
|
+
export type { DemoBannerProps } from "./demo/demo-banner";
|
|
731
|
+
export { DemoEnded } from "./demo/demo-ended";
|
|
732
|
+
export type { DemoEndedProps } from "./demo/demo-ended";
|
|
636
733
|
export type {
|
|
637
734
|
LegalPageProps,
|
|
638
735
|
LegalKitSectionProps,
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
|
|
3
|
+
import { DEFAULT_LANDING_LABELS, useLandingLabels } from "./landing-labels";
|
|
4
|
+
import type { LandingLabels } from "./landing-labels";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* How a visitor gets an account (docs/landing-demo-harmonization.md §2.2, §4.2).
|
|
8
|
+
*
|
|
9
|
+
* - `request` — every app today: registration is invitation-only, so the primary action
|
|
10
|
+
* is a mail to `support@<domain>`, answered with an invitation. There is no request
|
|
11
|
+
* form and no table. `app` names the product in the mail's subject ("Access to
|
|
12
|
+
* Kastlan"); `askCompany` adds kastlan's "Company:" line to the body.
|
|
13
|
+
* - `register` — the day an app opens registration, the SAME slot becomes "Get started"
|
|
14
|
+
* → its `/register`. Nothing else on the page changes.
|
|
15
|
+
*
|
|
16
|
+
* One value per app, passed to every part that offers access — `PublicHeader`, `Hero`,
|
|
17
|
+
* `CtaBand`, `LandingActions`, `SignInForm`, `DemoStart`, `DemoBanner`, `DemoEnded` — so
|
|
18
|
+
* the switch is one line when it comes.
|
|
19
|
+
*/
|
|
20
|
+
export type AccessChoice =
|
|
21
|
+
| { kind: "request"; email: string; app?: string; askCompany?: boolean }
|
|
22
|
+
| { kind: "register"; href: string };
|
|
23
|
+
|
|
24
|
+
/** What {@link accessAction} answers: where the access action goes and what it says. */
|
|
25
|
+
export interface AccessLink {
|
|
26
|
+
kind: AccessChoice["kind"];
|
|
27
|
+
/** A `mailto:` for `request`, the app's register page for `register`. */
|
|
28
|
+
href: string;
|
|
29
|
+
/** "Request access" or "Get started". */
|
|
30
|
+
label: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The words {@link accessAction} reads. */
|
|
34
|
+
export type AccessLabels = Pick<
|
|
35
|
+
LandingLabels,
|
|
36
|
+
"requestAccess" | "getStarted" | "accessSubject" | "accessName" | "accessCompany" | "accessUse"
|
|
37
|
+
>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* RFC 3986 percent-encoding, stricter than `encodeURIComponent`: `!'()*` too. RFC 6068
|
|
41
|
+
* would allow them in a header value, but a mail client that splits on `'` or `(` is
|
|
42
|
+
* the one that breaks a subject like "Access to Ada's Garden Planner", and an encoded
|
|
43
|
+
* one reads the same everywhere.
|
|
44
|
+
*/
|
|
45
|
+
function encodeStrict(value: string): string {
|
|
46
|
+
return encodeURIComponent(value).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The `mailto:` of a request (§4.2): the subject in the visitor's language ("Access to
|
|
51
|
+
* <App>") and a short body to fill in — "Name:", kastlan's "Company:", "What would you
|
|
52
|
+
* use it for:" — one prompt per line.
|
|
53
|
+
*
|
|
54
|
+
* RFC 6068: the lines are separated by CRLF (`%0D%0A`), spaces are `%20` (a `+` would be
|
|
55
|
+
* read as a plus), and the address keeps its `@` but nothing else unencoded.
|
|
56
|
+
*/
|
|
57
|
+
function mailtoHref(access: Extract<AccessChoice, { kind: "request" }>, labels: AccessLabels): string {
|
|
58
|
+
const body = [labels.accessName, ...(access.askCompany ? [labels.accessCompany] : []), labels.accessUse].join("\r\n");
|
|
59
|
+
const to = encodeStrict(access.email).replace(/%40/g, "@");
|
|
60
|
+
return `mailto:${to}?subject=${encodeStrict(labels.accessSubject(access.app))}&body=${encodeStrict(body)}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The access action for `access`, in the language of `labels` (§4.2): "Request access"
|
|
65
|
+
* as a mail to support, or "Get started" → the register page.
|
|
66
|
+
*
|
|
67
|
+
* Pure, so a test or an app's own button can use it; the kit's parts call
|
|
68
|
+
* {@link useAccessAction}, which takes the words from the provider. The labels already
|
|
69
|
+
* carry the language — there is no separate locale argument.
|
|
70
|
+
*/
|
|
71
|
+
export function accessAction(access: AccessChoice, labels: Partial<AccessLabels> = {}): AccessLink {
|
|
72
|
+
// A key given as `undefined` keeps the English, as in every kit namespace.
|
|
73
|
+
const words: AccessLabels = { ...DEFAULT_LANDING_LABELS };
|
|
74
|
+
for (const [key, value] of Object.entries(labels)) {
|
|
75
|
+
if (value !== undefined) (words as unknown as Record<string, unknown>)[key] = value;
|
|
76
|
+
}
|
|
77
|
+
if (access.kind === "register") return { kind: "register", href: access.href, label: words.getStarted };
|
|
78
|
+
return { kind: "request", href: mailtoHref(access, words), label: words.requestAccess };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** {@link accessAction} with the `landing` words of the nearest provider (then `labels`). */
|
|
82
|
+
export function useAccessAction(access: AccessChoice, labels?: Partial<LandingLabels>): AccessLink {
|
|
83
|
+
const words = useLandingLabels(labels);
|
|
84
|
+
// `access` is usually an inline object; its fields are what the link depends on.
|
|
85
|
+
const kind = access.kind;
|
|
86
|
+
const target = access.kind === "register" ? access.href : access.email;
|
|
87
|
+
const app = access.kind === "request" ? access.app : undefined;
|
|
88
|
+
const askCompany = access.kind === "request" ? access.askCompany === true : false;
|
|
89
|
+
return useMemo(
|
|
90
|
+
() =>
|
|
91
|
+
accessAction(
|
|
92
|
+
kind === "register" ? { kind, href: target } : { kind, email: target, app, askCompany },
|
|
93
|
+
words,
|
|
94
|
+
),
|
|
95
|
+
[kind, target, app, askCompany, words],
|
|
96
|
+
);
|
|
97
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef } from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../lib/cn";
|
|
4
|
+
import { Button } from "../components/ui";
|
|
5
|
+
import type { ButtonSize } from "../components/ui";
|
|
6
|
+
import { useAccessAction } from "./access";
|
|
7
|
+
import type { AccessChoice } from "./access";
|
|
8
|
+
import { useLandingLabels } from "./landing-labels";
|
|
9
|
+
import type { LandingLabels } from "./landing-labels";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Who is looking at a public page (docs/landing-demo-harmonization.md §3.1, §4.1):
|
|
13
|
+
* nobody signed in, a demo session, or a real account. The app derives it from its auth
|
|
14
|
+
* state — a demo is `isDemoSession(me)`.
|
|
15
|
+
*/
|
|
16
|
+
export type LandingSession = "none" | "demo" | "user";
|
|
17
|
+
|
|
18
|
+
/** keksdose's hero buttons: wider than the kit's `md` (px-5 py-2.5), the page's
|
|
19
|
+
* largest actions. */
|
|
20
|
+
const LARGE = "px-5 py-2.5";
|
|
21
|
+
|
|
22
|
+
export interface LandingActionsProps extends Omit<ComponentPropsWithoutRef<"div">, "children"> {
|
|
23
|
+
session: LandingSession;
|
|
24
|
+
access: AccessChoice;
|
|
25
|
+
/** "Try the demo" without a session, "Continue the demo" with a demo one. Default
|
|
26
|
+
* `/demo`, which starts a demo — or, for a live one, continues it (§3.1). `null`
|
|
27
|
+
* (0.31.1): the app has no demo yet, and the action is left out — "Request access"
|
|
28
|
+
* stands alone (Kurvenschmiede's 0.31 adoption). */
|
|
29
|
+
demoHref?: string | null;
|
|
30
|
+
/** "Open app" for a real session: the resume target. Default `/`, which resumes
|
|
31
|
+
* through `RootEntry`. */
|
|
32
|
+
openAppHref?: string;
|
|
33
|
+
/** `large` (default): the hero's and the CTA band's size. Or a kit `ButtonSize`. */
|
|
34
|
+
size?: ButtonSize | "large";
|
|
35
|
+
/** `start` (default) under the hero's copy; `center` in the CTA band. */
|
|
36
|
+
align?: "start" | "center";
|
|
37
|
+
labels?: Partial<LandingLabels>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The landing's action pair for the visitor's state (§4.1), shared by {@link Hero} and
|
|
42
|
+
* {@link CtaBand}:
|
|
43
|
+
*
|
|
44
|
+
* | session | actions |
|
|
45
|
+
* |---|---|
|
|
46
|
+
* | none | **Request access** (primary), Try the demo |
|
|
47
|
+
* | demo | **Request access** (primary), Continue the demo |
|
|
48
|
+
* | user | **Open app** (primary), alone |
|
|
49
|
+
*
|
|
50
|
+
* keksdose showed a signed-in visitor (who reached the landing by its brand link,
|
|
51
|
+
* `/welcome`) the register/demo pair, which `RedirectIfAuthed` then silently bounced
|
|
52
|
+
* back into the app; one "Open app" says where it goes. "Request access" is the mail of
|
|
53
|
+
* {@link accessAction}, or "Get started" once the app opens registration.
|
|
54
|
+
*
|
|
55
|
+
* Stacked full-width on a phone, a row from `sm` up — keksdose's layout.
|
|
56
|
+
*/
|
|
57
|
+
export function LandingActions({
|
|
58
|
+
session,
|
|
59
|
+
access,
|
|
60
|
+
demoHref = "/demo",
|
|
61
|
+
openAppHref = "/",
|
|
62
|
+
size = "large",
|
|
63
|
+
align = "start",
|
|
64
|
+
labels: labelsProp,
|
|
65
|
+
className,
|
|
66
|
+
...rest
|
|
67
|
+
}: LandingActionsProps) {
|
|
68
|
+
const labels = useLandingLabels(labelsProp);
|
|
69
|
+
const accessLink = useAccessAction(access, labelsProp);
|
|
70
|
+
const buttonSize: ButtonSize = size === "large" ? "md" : size;
|
|
71
|
+
const extra = size === "large" ? LARGE : undefined;
|
|
72
|
+
return (
|
|
73
|
+
<div
|
|
74
|
+
{...rest}
|
|
75
|
+
data-slot="landing-actions"
|
|
76
|
+
className={cn("flex flex-col gap-3 sm:flex-row", align === "center" && "sm:justify-center", className)}
|
|
77
|
+
>
|
|
78
|
+
{session === "user" ? (
|
|
79
|
+
<Button href={openAppHref} variant="brand" size={buttonSize} className={extra}>
|
|
80
|
+
{labels.openApp}
|
|
81
|
+
</Button>
|
|
82
|
+
) : (
|
|
83
|
+
<>
|
|
84
|
+
<Button href={accessLink.href} variant="brand" size={buttonSize} className={extra}>
|
|
85
|
+
{accessLink.label}
|
|
86
|
+
</Button>
|
|
87
|
+
{demoHref !== null && (
|
|
88
|
+
<Button href={demoHref} variant="secondary" size={buttonSize} className={extra}>
|
|
89
|
+
{session === "demo" ? labels.continueDemo : labels.tryDemo}
|
|
90
|
+
</Button>
|
|
91
|
+
)}
|
|
92
|
+
</>
|
|
93
|
+
)}
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useKitLabels } from "../i18n/kit-labels";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The kit's words on the public landing page (docs/landing-demo-harmonization.md §4.1,
|
|
5
|
+
* §4.2) — the `landing` namespace of `<UiKitProvider labels>`.
|
|
6
|
+
*
|
|
7
|
+
* Only the GENERIC words are the kit's: the actions every app's header, hero and CTA band
|
|
8
|
+
* share, the "Beta" badge, and the template of the request-access mail. The marketing
|
|
9
|
+
* copy (the hero's title, the feature rows, the trust strip, the tagline) is each app's,
|
|
10
|
+
* in every language it ships (§4.1 "Words").
|
|
11
|
+
*
|
|
12
|
+
* The demo parts and `SignInForm` read the access words from here too, so "Request
|
|
13
|
+
* access" and its mail are said the same way on the landing, the sign-in page, the demo
|
|
14
|
+
* start, the banner and the end page.
|
|
15
|
+
*/
|
|
16
|
+
export interface LandingLabels {
|
|
17
|
+
/** The header's secondary action without a session; also the demo banner's and the
|
|
18
|
+
* end page's way to an existing account. */
|
|
19
|
+
signIn: string;
|
|
20
|
+
/** The access action of an invitation-only app: a mail to support (§2.2, §4.2). */
|
|
21
|
+
requestAccess: string;
|
|
22
|
+
/** The access action once an app opens registration (`{kind: "register"}`, §4.2). */
|
|
23
|
+
getStarted: string;
|
|
24
|
+
/** The hero's and the CTA band's second action without a session. */
|
|
25
|
+
tryDemo: string;
|
|
26
|
+
/** The one action for a real session: into the app, at the resume target. */
|
|
27
|
+
openApp: string;
|
|
28
|
+
/** The secondary action for a demo session: back into the live demo. */
|
|
29
|
+
continueDemo: string;
|
|
30
|
+
/** The hero's optional badge. */
|
|
31
|
+
beta: string;
|
|
32
|
+
/** The request mail's subject, given the app's name (`access.app`): "Access to
|
|
33
|
+
* Kastlan". `undefined` when the app named none. */
|
|
34
|
+
accessSubject: (app?: string) => string;
|
|
35
|
+
/** The request mail's body, one prompt per line; the sender writes after each. */
|
|
36
|
+
accessName: string;
|
|
37
|
+
/** Asked only where the app says so (`askCompany`, kastlan). */
|
|
38
|
+
accessCompany: string;
|
|
39
|
+
accessUse: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const DEFAULT_LANDING_LABELS: LandingLabels = {
|
|
43
|
+
signIn: "Sign in",
|
|
44
|
+
requestAccess: "Request access",
|
|
45
|
+
getStarted: "Get started",
|
|
46
|
+
tryDemo: "Try the demo",
|
|
47
|
+
openApp: "Open app",
|
|
48
|
+
continueDemo: "Continue the demo",
|
|
49
|
+
beta: "Beta",
|
|
50
|
+
accessSubject: (app) => (app ? `Access to ${app}` : "Access request"),
|
|
51
|
+
accessName: "Name:",
|
|
52
|
+
accessCompany: "Company:",
|
|
53
|
+
accessUse: "What would you use it for:",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/** The `landing` namespace, resolved: English, then the provider, then `labels`. */
|
|
57
|
+
export function useLandingLabels(labels?: Partial<LandingLabels>): LandingLabels {
|
|
58
|
+
return useKitLabels("landing", DEFAULT_LANDING_LABELS, labels);
|
|
59
|
+
}
|