@ghxstship/xos-ui 0.0.0-stage → 4.16.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/LICENSE +21 -0
- package/README.md +32 -2
- package/package.json +76 -4
- package/scripts/generate-stories.mjs +85 -0
- package/src/AIDisclosureBadge/README.md +7 -0
- package/src/AccessGridMatrix/README.md +3 -0
- package/src/Accordion/README.md +7 -0
- package/src/ActivityFeedItem/README.md +3 -0
- package/src/AgencySlate/README.md +3 -0
- package/src/AppShell/README.md +5 -0
- package/src/ApplicationForm/README.md +3 -0
- package/src/AssertionRankBadge/README.md +5 -0
- package/src/AvailabilityCalendar/README.md +3 -0
- package/src/Avatar/Avatar.tsx +56 -0
- package/src/Avatar/README.md +3 -0
- package/src/Avatar/avatar-class.ts +19 -0
- package/src/AvatarStack/README.md +3 -0
- package/src/Badge/README.md +3 -0
- package/src/Banner/README.md +3 -0
- package/src/BidSheet/README.md +3 -0
- package/src/Board/README.md +6 -0
- package/src/BrandMark/BrandMark.tsx +95 -0
- package/src/BrandMark/README.md +7 -0
- package/src/BrandSlot/README.md +6 -0
- package/src/Breadcrumbs/README.md +3 -0
- package/src/BudgetGrid/README.md +10 -0
- package/src/BulkActionBar/README.md +3 -0
- package/src/Button/Button.tsx +100 -0
- package/src/Button/README.md +10 -0
- package/src/Button/button-class.ts +54 -0
- package/src/ButtonLink/README.md +7 -0
- package/src/Calendar/README.md +3 -0
- package/src/Card/README.md +3 -0
- package/src/Chart/README.md +9 -0
- package/src/Charts/Calendar.tsx +228 -0
- package/src/Charts/Chart.tsx +547 -0
- package/src/Charts/Charts.tsx +20 -0
- package/src/Charts/Charts.types.ts +40 -0
- package/src/Charts/Gallery.tsx +25 -0
- package/src/Charts/Heatmap.tsx +116 -0
- package/src/Charts/OrgChart.tsx +53 -0
- package/src/Charts/ResourceSchedule.tsx +91 -0
- package/src/Charts/Sparkline.tsx +59 -0
- package/src/Charts/Timeline.tsx +777 -0
- package/src/Charts/categories.ts +21 -0
- package/src/Charts/timeline-plan.ts +191 -0
- package/src/Checkbox/README.md +6 -0
- package/src/ChecklistRunner/README.md +3 -0
- package/src/Chips/Badge.tsx +27 -0
- package/src/Chips/Chips.shared.tsx +34 -0
- package/src/Chips/Chips.tsx +21 -0
- package/src/Chips/Chips.types.ts +35 -0
- package/src/Chips/DepartmentChip.tsx +16 -0
- package/src/Chips/PhaseChip.tsx +16 -0
- package/src/Chips/PropertyChip.tsx +15 -0
- package/src/Chips/RecordKindChip.tsx +14 -0
- package/src/Chips/StateChip.tsx +19 -0
- package/src/Chips/Tag.tsx +47 -0
- package/src/Chips/URIDChip.tsx +14 -0
- package/src/Chips/chipClass.tsx +8 -0
- package/src/Chips/codeClass.tsx +6 -0
- package/src/ClockButton/README.md +6 -0
- package/src/CodeSample/README.md +7 -0
- package/src/ColorPicker/README.md +5 -0
- package/src/Combobox/README.md +7 -0
- package/src/CommandMenu/CommandMenu.tsx +179 -0
- package/src/CommandMenu/README.md +5 -0
- package/src/ComparisonTable/README.md +9 -0
- package/src/Compass/ChecklistRunner.tsx +128 -0
- package/src/Compass/ClockButton.tsx +57 -0
- package/src/Compass/Compass.shared.tsx +58 -0
- package/src/Compass/Compass.tsx +26 -0
- package/src/Compass/Compass.types.ts +79 -0
- package/src/Compass/DaySheetView.tsx +104 -0
- package/src/Compass/ForceUpdateScreen.tsx +29 -0
- package/src/Compass/LiveActivity.tsx +60 -0
- package/src/Compass/OfflineBanner.tsx +31 -0
- package/src/Compass/PhotoCapture.tsx +69 -0
- package/src/Compass/QuickIncidentSheet.tsx +46 -0
- package/src/Compass/ScanSheet.tsx +83 -0
- package/src/Compass/ShiftCard.tsx +55 -0
- package/src/Compass/SignaturePad.tsx +71 -0
- package/src/Compass/SyncConflictSheet.tsx +60 -0
- package/src/ConsentBanner/ConsentBanner.tsx +210 -0
- package/src/ConsentBanner/ConsentBannerStatic.tsx +163 -0
- package/src/ConsentBanner/ConsentSettings.tsx +213 -0
- package/src/ConsentBanner/README.md +101 -0
- package/src/ConsentBanner/consent.ts +238 -0
- package/src/ConsentBanner/index.ts +40 -0
- package/src/ConsentBanner/static.ts +11 -0
- package/src/ConsentBanner/useConsent.ts +160 -0
- package/src/ContextMenu/README.md +3 -0
- package/src/CoordinateMatrix/README.md +6 -0
- package/src/CredentialBadge/README.md +7 -0
- package/src/CurrencyInput/README.md +7 -0
- package/src/DataTable/DataTable.tsx +1034 -0
- package/src/DataTable/DataTableResizer.tsx +72 -0
- package/src/DataTable/DataTableVirtualizer.tsx +58 -0
- package/src/DataTable/README.md +9 -0
- package/src/DatePicker/README.md +5 -0
- package/src/DateRangePicker/README.md +3 -0
- package/src/DaySheetView/README.md +3 -0
- package/src/DepartmentChip/README.md +3 -0
- package/src/DepartmentGlyph/README.md +18 -0
- package/src/Dialog/README.md +3 -0
- package/src/DiffViewer/README.md +3 -0
- package/src/Divider/README.md +3 -0
- package/src/Drawer/README.md +3 -0
- package/src/DropdownMenu/README.md +3 -0
- package/src/EPKViewer/README.md +3 -0
- package/src/Editing/ColorPicker.tsx +125 -0
- package/src/Editing/DiffViewer.tsx +49 -0
- package/src/Editing/Editing.tsx +29 -0
- package/src/Editing/Editing.types.ts +71 -0
- package/src/Editing/FilterBuilder.tsx +72 -0
- package/src/Editing/QuickAdd.tsx +102 -0
- package/src/Editing/QuickAddChips.tsx +180 -0
- package/src/Editing/contrastRatio.tsx +11 -0
- package/src/Editing/parseQuickAdd.tsx +187 -0
- package/src/Editing/quickAddCore.ts +204 -0
- package/src/Editing/timeShorthand.ts +157 -0
- package/src/Editing/useQuickAdd.ts +201 -0
- package/src/EmergencyCodeCard/README.md +10 -0
- package/src/EmptyState/README.md +5 -0
- package/src/EngagementTimeline/README.md +3 -0
- package/src/ErrorState/README.md +3 -0
- package/src/FAQ/README.md +7 -0
- package/src/FeatureGrid/README.md +7 -0
- package/src/Feedback/Banner.tsx +40 -0
- package/src/Feedback/EmptyState.tsx +32 -0
- package/src/Feedback/ErrorState.tsx +32 -0
- package/src/Feedback/Feedback.shared.tsx +38 -0
- package/src/Feedback/Feedback.tsx +18 -0
- package/src/Feedback/Feedback.types.ts +40 -0
- package/src/Feedback/InlineAlert.tsx +19 -0
- package/src/Feedback/RefusalNotice.tsx +46 -0
- package/src/Feedback/RegionBoundary.tsx +102 -0
- package/src/Feedback/Toast.tsx +31 -0
- package/src/Feedback/ToastRegion.tsx +26 -0
- package/src/Feedback/UndoToast.tsx +97 -0
- package/src/FeedbackWidget/README.md +3 -0
- package/src/Field/Field.tsx +81 -0
- package/src/FileDrop/README.md +3 -0
- package/src/FilePreviewer/README.md +3 -0
- package/src/FilterBuilder/README.md +3 -0
- package/src/ForceUpdateScreen/README.md +3 -0
- package/src/Forms/Checkbox.tsx +14 -0
- package/src/Forms/CurrencyInput.tsx +40 -0
- package/src/Forms/Forms.shared.tsx +5 -0
- package/src/Forms/Forms.tsx +20 -0
- package/src/Forms/Forms.types.ts +33 -0
- package/src/Forms/Input.tsx +28 -0
- package/src/Forms/Money.tsx +15 -0
- package/src/Forms/NumberInput.tsx +85 -0
- package/src/Forms/Radio.tsx +31 -0
- package/src/Forms/Select.tsx +54 -0
- package/src/Forms/Switch.tsx +14 -0
- package/src/Forms/Textarea.tsx +30 -0
- package/src/Gallery/README.md +5 -0
- package/src/GateLifecycleRail/README.md +7 -0
- package/src/GateReadinessPanel/README.md +8 -0
- package/src/Gateway/AgencySlate.tsx +76 -0
- package/src/Gateway/ApplicationForm.tsx +48 -0
- package/src/Gateway/AvailabilityCalendar.tsx +82 -0
- package/src/Gateway/EPKViewer.tsx +77 -0
- package/src/Gateway/EngagementTimeline.tsx +43 -0
- package/src/Gateway/Gateway.shared.tsx +5 -0
- package/src/Gateway/Gateway.tsx +30 -0
- package/src/Gateway/Gateway.types.ts +69 -0
- package/src/Gateway/OnboardingPacket.tsx +61 -0
- package/src/Gateway/OpportunityCard.tsx +73 -0
- package/src/Gateway/OpportunityFilters.tsx +64 -0
- package/src/Gateway/PaymentTracker.tsx +71 -0
- package/src/Gateway/PayoutDetailsForm.tsx +62 -0
- package/src/Gateway/ProfileEditor.tsx +45 -0
- package/src/Gateway/ProgressBar.tsx +30 -0
- package/src/Gateway/RatingDialog.tsx +83 -0
- package/src/Gateway/UpNextCard.tsx +76 -0
- package/src/Glyphs/Glyphs.tsx +66 -0
- package/src/Grids/BidSheet.tsx +63 -0
- package/src/Grids/BudgetGrid.tsx +164 -0
- package/src/Grids/Grids.shared.tsx +5 -0
- package/src/Grids/Grids.tsx +11 -0
- package/src/Grids/Grids.types.ts +38 -0
- package/src/Grids/SpreadsheetGrid.tsx +445 -0
- package/src/Grids/columnTotal.tsx +14 -0
- package/src/Grids/glForCode.tsx +11 -0
- package/src/Grids/parseCell.tsx +16 -0
- package/src/Help/FeedbackWidget.tsx +89 -0
- package/src/Help/Help.tsx +14 -0
- package/src/Help/Help.types.ts +51 -0
- package/src/Help/HelpPanel.tsx +116 -0
- package/src/Help/NotificationCenter.tsx +100 -0
- package/src/Help/OnboardingChecklist.tsx +57 -0
- package/src/Help/ShortcutEditor.tsx +81 -0
- package/src/Help/WhatsNew.tsx +33 -0
- package/src/HelpPanel/README.md +5 -0
- package/src/HoverCard/README.md +3 -0
- package/src/Icon/Icon.tsx +47 -0
- package/src/Icon/README.md +9 -0
- package/src/IconButton/README.md +6 -0
- package/src/Identity/BrandSlot.tsx +20 -0
- package/src/Identity/BrandSlotFrame.tsx +38 -0
- package/src/Identity/CredentialBadge.tsx +92 -0
- package/src/Identity/Identity.tsx +14 -0
- package/src/Identity/Identity.types.ts +25 -0
- package/src/Identity/PresenceIndicator.tsx +37 -0
- package/src/Identity/QRCode.tsx +22 -0
- package/src/Identity/WhiteLabelPreview.tsx +33 -0
- package/src/Identity/qrPath.tsx +16 -0
- package/src/Identity/tokenVariable.tsx +9 -0
- package/src/InlineAlert/README.md +3 -0
- package/src/Input/README.md +8 -0
- package/src/Kbd/Kbd.tsx +30 -0
- package/src/Kbd/README.md +6 -0
- package/src/Layout/AppShell.tsx +151 -0
- package/src/Layout/Layout.tsx +14 -0
- package/src/Layout/Layout.types.ts +43 -0
- package/src/Layout/PageHeader.tsx +22 -0
- package/src/Layout/ResizablePanel.tsx +81 -0
- package/src/Layout/ScrollRegion.tsx +107 -0
- package/src/Layout/SplitView.tsx +78 -0
- package/src/Layout/Stepper.tsx +39 -0
- package/src/LegalText/LegalText.tsx +289 -0
- package/src/LegalText/README.md +10 -0
- package/src/LegalText/index.ts +29 -0
- package/src/LegalText/legal-markdown.ts +581 -0
- package/src/Link/Link.tsx +25 -0
- package/src/Link/README.md +5 -0
- package/src/Link/link-class.ts +10 -0
- package/src/LiveActivity/README.md +3 -0
- package/src/LogoSlotWall/README.md +7 -0
- package/src/MapView/README.md +5 -0
- package/src/Marketing/AIDisclosureBadge.tsx +31 -0
- package/src/Marketing/ButtonLink.tsx +32 -0
- package/src/Marketing/CodeSample.tsx +47 -0
- package/src/Marketing/ComparisonScroll.tsx +7 -0
- package/src/Marketing/ComparisonTable.tsx +104 -0
- package/src/Marketing/FAQ.tsx +26 -0
- package/src/Marketing/FeatureGrid.tsx +65 -0
- package/src/Marketing/GateLifecycleRail.tsx +52 -0
- package/src/Marketing/LogoSlotWall.tsx +53 -0
- package/src/Marketing/Marketing.tsx +49 -0
- package/src/Marketing/Marketing.types.ts +64 -0
- package/src/Marketing/MarketingFooter.tsx +88 -0
- package/src/Marketing/MarketingHero.tsx +45 -0
- package/src/Marketing/MarketingNav.tsx +76 -0
- package/src/Marketing/MarketingPoints.tsx +16 -0
- package/src/Marketing/MarketingSection.tsx +52 -0
- package/src/Marketing/PersonaSwitcher.tsx +137 -0
- package/src/Marketing/PriceDisplay.tsx +56 -0
- package/src/Marketing/PricingTable.tsx +122 -0
- package/src/Marketing/ProofStatStrip.tsx +35 -0
- package/src/Marketing/ScreenshotFrame.tsx +56 -0
- package/src/Marketing/SurfaceTriptych.tsx +43 -0
- package/src/Marketing/Testimonial.tsx +45 -0
- package/src/Marketing/marketing-copy.ts +25 -0
- package/src/Marketing/provided.tsx +36 -0
- package/src/MarketingFooter/README.md +7 -0
- package/src/MarketingHero/README.md +7 -0
- package/src/MarketingNav/README.md +7 -0
- package/src/MarketingSection/README.md +7 -0
- package/src/Media/FilePreviewer.tsx +86 -0
- package/src/Media/MapView.tsx +200 -0
- package/src/Media/Media.tsx +11 -0
- package/src/Media/Media.types.ts +47 -0
- package/src/Media/RichTextEditor.tsx +198 -0
- package/src/Media/toLngLat.tsx +13 -0
- package/src/Menus/ContextMenu.tsx +106 -0
- package/src/Menus/DropdownMenu.tsx +51 -0
- package/src/Menus/Menus.shared.tsx +67 -0
- package/src/Menus/Menus.tsx +13 -0
- package/src/Menus/Menus.types.ts +49 -0
- package/src/Menus/OrgSwitcher.tsx +69 -0
- package/src/Menus/compactTriggerClass.tsx +7 -0
- package/src/Menus/menuClass.tsx +4 -0
- package/src/Menus/menuItemClass.tsx +7 -0
- package/src/Menus/orgSwitcherTriggerClass.tsx +7 -0
- package/src/Money/README.md +6 -0
- package/src/MultiSelect/README.md +3 -0
- package/src/Navigation/Accordion.tsx +59 -0
- package/src/Navigation/Breadcrumbs.tsx +59 -0
- package/src/Navigation/MoreFields.tsx +42 -0
- package/src/Navigation/Navigation.shared.tsx +32 -0
- package/src/Navigation/Navigation.tsx +21 -0
- package/src/Navigation/Navigation.types.ts +63 -0
- package/src/Navigation/Pagination.tsx +30 -0
- package/src/Navigation/SegmentedControl.tsx +87 -0
- package/src/Navigation/Sidebar.tsx +106 -0
- package/src/Navigation/TabBar.tsx +61 -0
- package/src/Navigation/Tabs.tsx +79 -0
- package/src/Navigation/TopNav.tsx +86 -0
- package/src/Navigation/sidebar-classes.ts +18 -0
- package/src/NotificationCenter/README.md +3 -0
- package/src/NumberInput/README.md +3 -0
- package/src/OfflineBanner/README.md +3 -0
- package/src/OnboardingChecklist/README.md +3 -0
- package/src/OnboardingPacket/README.md +3 -0
- package/src/OpportunityCard/README.md +5 -0
- package/src/OpportunityFilters/README.md +3 -0
- package/src/OrgChart/README.md +5 -0
- package/src/OrgSwitcher/README.md +3 -0
- package/src/Overlays/Dialog.tsx +54 -0
- package/src/Overlays/Drawer.tsx +62 -0
- package/src/Overlays/HoverCard.tsx +59 -0
- package/src/Overlays/Overlays.shared.tsx +12 -0
- package/src/Overlays/Overlays.tsx +20 -0
- package/src/Overlays/Overlays.types.ts +66 -0
- package/src/Overlays/Popover.tsx +70 -0
- package/src/Overlays/PropertyList.tsx +19 -0
- package/src/Overlays/ShortcutSheet.tsx +62 -0
- package/src/Overlays/SidePeek.tsx +117 -0
- package/src/Overlays/Tooltip.tsx +73 -0
- package/src/Overlays/panelClass.tsx +6 -0
- package/src/Overlays/popoverPanelClass.tsx +6 -0
- package/src/PageHeader/README.md +3 -0
- package/src/Pagination/README.md +3 -0
- package/src/PaymentTracker/README.md +3 -0
- package/src/PayoutDetailsForm/README.md +3 -0
- package/src/PersonaSwitcher/README.md +7 -0
- package/src/PhaseChip/README.md +5 -0
- package/src/PhaseGlyph/README.md +17 -0
- package/src/PhotoCapture/README.md +3 -0
- package/src/Pickers/Combobox.tsx +91 -0
- package/src/Pickers/DatePicker.tsx +60 -0
- package/src/Pickers/DateRangePicker.tsx +78 -0
- package/src/Pickers/FileDrop.tsx +84 -0
- package/src/Pickers/MultiSelect.tsx +118 -0
- package/src/Pickers/Pickers.shared.tsx +337 -0
- package/src/Pickers/Pickers.tsx +17 -0
- package/src/Pickers/Pickers.types.ts +47 -0
- package/src/Pickers/Slider.tsx +59 -0
- package/src/Pickers/TimePicker.tsx +68 -0
- package/src/Pickers/rankOptions.tsx +12 -0
- package/src/Popover/README.md +3 -0
- package/src/PresenceIndicator/README.md +3 -0
- package/src/PriceDisplay/README.md +7 -0
- package/src/PricingTable/README.md +9 -0
- package/src/ProfileEditor/README.md +3 -0
- package/src/ProgressBar/README.md +3 -0
- package/src/ProofStatStrip/README.md +7 -0
- package/src/PropertyChip/README.md +3 -0
- package/src/ProvenanceBadge/README.md +3 -0
- package/src/QRCode/README.md +6 -0
- package/src/QuickAdd/README.md +5 -0
- package/src/QuickIncidentSheet/README.md +3 -0
- package/src/Radio/README.md +3 -0
- package/src/RadioChannelTable/README.md +7 -0
- package/src/RatingDialog/README.md +3 -0
- package/src/ReconciliationTable/README.md +3 -0
- package/src/RecordKindChip/README.md +3 -0
- package/src/RecordKindGlyph/README.md +34 -0
- package/src/RecordRow/README.md +7 -0
- package/src/RefusalNotice/README.md +5 -0
- package/src/ResizablePanel/README.md +3 -0
- package/src/ResourceSchedule/README.md +6 -0
- package/src/RichTextEditor/README.md +3 -0
- package/src/RichTextEditor/extensions.ts +217 -0
- package/src/RunOfShowLive/README.md +5 -0
- package/src/ScanSheet/README.md +3 -0
- package/src/ScreenshotFrame/README.md +7 -0
- package/src/ScrollRegion/README.md +9 -0
- package/src/SegmentedControl/README.md +5 -0
- package/src/Select/README.md +5 -0
- package/src/ShiftCard/README.md +3 -0
- package/src/ShortcutEditor/README.md +3 -0
- package/src/ShortcutSheet/README.md +3 -0
- package/src/SidePeek/README.md +6 -0
- package/src/Sidebar/README.md +5 -0
- package/src/SignaturePad/README.md +3 -0
- package/src/Skeleton/README.md +3 -0
- package/src/Slider/README.md +3 -0
- package/src/SplitView/README.md +3 -0
- package/src/SpreadsheetGrid/README.md +9 -0
- package/src/StalenessIndicator/README.md +3 -0
- package/src/StatTile/README.md +6 -0
- package/src/StateChip/README.md +6 -0
- package/src/StateIcon/README.md +6 -0
- package/src/StateIcon/StateIcon.tsx +127 -0
- package/src/StatusHeatmap/README.md +15 -0
- package/src/Stepper/README.md +3 -0
- package/src/Surface/Skeleton.tsx +21 -0
- package/src/Surface/Surface.tsx +63 -0
- package/src/SurfaceTriptych/README.md +7 -0
- package/src/Switch/README.md +5 -0
- package/src/SyncConflictSheet/README.md +3 -0
- package/src/TabBar/README.md +7 -0
- package/src/Tabs/README.md +6 -0
- package/src/Tag/README.md +3 -0
- package/src/TemplateAuth/README.md +6 -0
- package/src/TemplateCollection/README.md +6 -0
- package/src/TemplateDashboard/README.md +8 -0
- package/src/TemplateDocument/README.md +5 -0
- package/src/TemplateGatewayShell/README.md +5 -0
- package/src/TemplateGridEditor/README.md +3 -0
- package/src/TemplateRecord/README.md +3 -0
- package/src/TemplateSettings/README.md +5 -0
- package/src/TemplateSplitView/README.md +3 -0
- package/src/TemplateSystem/README.md +5 -0
- package/src/TemplateWizard/README.md +3 -0
- package/src/Templates/TemplateAuth.tsx +16 -0
- package/src/Templates/TemplateCollection.tsx +35 -0
- package/src/Templates/TemplateDashboard.tsx +200 -0
- package/src/Templates/TemplateDocument.tsx +24 -0
- package/src/Templates/TemplateGatewayShell.tsx +36 -0
- package/src/Templates/TemplateGridEditor.tsx +17 -0
- package/src/Templates/TemplateRecord.tsx +31 -0
- package/src/Templates/TemplateSettings.tsx +26 -0
- package/src/Templates/TemplateSplitView.tsx +27 -0
- package/src/Templates/TemplateSystem.tsx +19 -0
- package/src/Templates/TemplateSystemLink.tsx +55 -0
- package/src/Templates/TemplateWizard.tsx +43 -0
- package/src/Templates/Templates.tsx +29 -0
- package/src/Templates/Templates.types.ts +153 -0
- package/src/Testimonial/README.md +7 -0
- package/src/Textarea/README.md +3 -0
- package/src/TimePicker/README.md +5 -0
- package/src/Timeline/README.md +6 -0
- package/src/Toast/README.md +3 -0
- package/src/Tooltip/README.md +3 -0
- package/src/TopNav/README.md +5 -0
- package/src/TreeView/README.md +3 -0
- package/src/URIDChip/README.md +5 -0
- package/src/UndoToast/README.md +3 -0
- package/src/UpNextCard/README.md +6 -0
- package/src/Views/ActivityFeedItem.tsx +52 -0
- package/src/Views/Board.tsx +229 -0
- package/src/Views/BulkActionBar.tsx +76 -0
- package/src/Views/RecordList.tsx +146 -0
- package/src/Views/RecordRow.tsx +132 -0
- package/src/Views/StatTile.tsx +88 -0
- package/src/Views/TreeView.tsx +161 -0
- package/src/Views/Views.tsx +18 -0
- package/src/Views/Views.types.ts +99 -0
- package/src/WhatsNew/README.md +3 -0
- package/src/WhiteLabelPreview/README.md +8 -0
- package/src/XOS/AccessGridMatrix.tsx +111 -0
- package/src/XOS/AssertionRankBadge.tsx +27 -0
- package/src/XOS/CoordinateMatrix.tsx +123 -0
- package/src/XOS/EmergencyCodeCard.tsx +109 -0
- package/src/XOS/GateReadinessPanel.tsx +100 -0
- package/src/XOS/ProvenanceBadge.tsx +19 -0
- package/src/XOS/RadioChannelTable.tsx +50 -0
- package/src/XOS/ReconciliationTable.tsx +64 -0
- package/src/XOS/RunOfShowLive.tsx +97 -0
- package/src/XOS/StalenessIndicator.tsx +31 -0
- package/src/XOS/StatusHeatmap.tsx +200 -0
- package/src/XOS/XOS.shared.tsx +90 -0
- package/src/XOS/XOS.tsx +29 -0
- package/src/XOS/XOS.types.ts +99 -0
- package/src/XOS/resolveStep.tsx +16 -0
- package/src/brand/defaults/README.md +13 -0
- package/src/brand/defaults/app-icon.svg +6 -0
- package/src/brand/defaults/favicon.svg +6 -0
- package/src/brand/defaults/logo-dark.svg +6 -0
- package/src/brand/defaults/logo-light.svg +6 -0
- package/src/brand/defaults/splash.svg +6 -0
- package/src/index.ts +606 -0
- package/src/lib/context.tsx +156 -0
- package/src/lib/cx.ts +4 -0
- package/src/lib/format.ts +200 -0
- package/src/lib/hooks.ts +187 -0
- package/src/lib/i18n.ts +97 -0
- package/src/lib/icons.ts +45 -0
- package/src/lib/live.ts +92 -0
- package/src/lib/preferences.ts +242 -0
- package/src/lib/route-transition.tsx +22 -0
- package/src/lib/selection.ts +92 -0
- package/src/lib/shortcut-targets.ts +125 -0
- package/src/lib/theme.ts +50 -0
- package/src/lib/undo-stack.ts +125 -0
- package/src/marketing.ts +33 -0
- package/src/pwa/action-outcome.tsx +81 -0
- package/src/pwa/analytics.ts +236 -0
- package/src/pwa/browser-push.tsx +132 -0
- package/src/pwa/client.ts +126 -0
- package/src/pwa/index.ts +40 -0
- package/src/pwa/offline-key.ts +18 -0
- package/src/pwa/service-worker.ts +229 -0
- package/src/static.ts +10 -0
- package/src/styles/base.css +208 -0
- package/src/styles/components.css +453 -0
- package/src/styles/index.css +16 -0
- package/src/styles/marketing.css +1260 -0
- package/src/styles/reference.css +5792 -0
- package/src/types/reference.d.ts +1608 -0
- package/tailwind.config.cjs +3 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useFormat, useT } from "../lib/context.tsx";
|
|
4
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
5
|
+
import { Button, IconButton } from "../Button/Button.tsx";
|
|
6
|
+
import { BrandMark } from "../BrandMark/BrandMark.tsx";
|
|
7
|
+
import { panelClass } from "./Gateway.shared.tsx";
|
|
8
|
+
import { type OpportunityCardProps } from "./Gateway.types.ts";
|
|
9
|
+
|
|
10
|
+
/** Role, pay, date and place, then a requirements check that shows exactly what is missing. No posted pay reads Rate on Request. */
|
|
11
|
+
export function OpportunityCard({
|
|
12
|
+
org,
|
|
13
|
+
verified,
|
|
14
|
+
role,
|
|
15
|
+
pay,
|
|
16
|
+
date,
|
|
17
|
+
place,
|
|
18
|
+
requirements,
|
|
19
|
+
missingAction,
|
|
20
|
+
deadline,
|
|
21
|
+
saved,
|
|
22
|
+
onApply,
|
|
23
|
+
onSave,
|
|
24
|
+
}: OpportunityCardProps): ReactElement {
|
|
25
|
+
const t = useT();
|
|
26
|
+
const fmt = useFormat();
|
|
27
|
+
const missing = requirements.missing.length > 0;
|
|
28
|
+
return (
|
|
29
|
+
<article className={cx(panelClass, "gap-8 w-(--ui-gateway-aside) p-16 text-text-14")}>
|
|
30
|
+
<header className="flex items-center justify-between gap-8">
|
|
31
|
+
<span className="flex items-center gap-6 min-w-0">
|
|
32
|
+
<BrandMark name={org} size="sm" iconOnly />
|
|
33
|
+
<span className="truncate">{org}</span>
|
|
34
|
+
{verified ? (
|
|
35
|
+
<span className="text-state-scheduled">
|
|
36
|
+
<Icon name="BadgeCheck" size={14} label={t("org.verified")} />
|
|
37
|
+
</span>
|
|
38
|
+
) : null}
|
|
39
|
+
</span>
|
|
40
|
+
<IconButton
|
|
41
|
+
icon="Bookmark"
|
|
42
|
+
label={saved ? t("action.saved") : t("action.save")}
|
|
43
|
+
aria-pressed={saved ?? false}
|
|
44
|
+
onClick={onSave}
|
|
45
|
+
/>
|
|
46
|
+
</header>
|
|
47
|
+
<h3 className="m-0 text-heading-16 font-semibold">{role}</h3>
|
|
48
|
+
<div className="flex flex-wrap gap-x-12 gap-y-4 text-text-secondary">
|
|
49
|
+
<strong className="text-text-primary tabular-nums">
|
|
50
|
+
{pay ?? t("money.rateOnRequest")}
|
|
51
|
+
</strong>
|
|
52
|
+
<span>{date}</span>
|
|
53
|
+
<span>{place}</span>
|
|
54
|
+
</div>
|
|
55
|
+
<div className="flex items-center gap-6 px-8 py-6 rounded-control bg-bg-surface text-text-13">
|
|
56
|
+
<span className={missing ? "text-warning" : "text-success"}>
|
|
57
|
+
<Icon name={missing ? "CircleAlert" : "CircleCheck"} size={14} />
|
|
58
|
+
</span>
|
|
59
|
+
<span>
|
|
60
|
+
{missing
|
|
61
|
+
? t("opp.missing", { list: fmt.list(requirements.missing) })
|
|
62
|
+
: t("opp.qualified")}
|
|
63
|
+
</span>
|
|
64
|
+
</div>
|
|
65
|
+
<footer className="flex items-center justify-between gap-8">
|
|
66
|
+
<span className="text-text-secondary">{deadline}</span>
|
|
67
|
+
<Button variant="primary" onClick={onApply}>
|
|
68
|
+
{missingAction && missing ? missingAction : t("opp.apply")}
|
|
69
|
+
</Button>
|
|
70
|
+
</footer>
|
|
71
|
+
</article>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useState, type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
5
|
+
import { SegmentedControl } from "../Navigation/Navigation.tsx";
|
|
6
|
+
import { type OpportunityFiltersProps } from "./Gateway.types.ts";
|
|
7
|
+
|
|
8
|
+
/** Search, filter chips and the cards or map view. */
|
|
9
|
+
export function OpportunityFilters({
|
|
10
|
+
placeholder: hint,
|
|
11
|
+
chips,
|
|
12
|
+
active = [],
|
|
13
|
+
onSearch,
|
|
14
|
+
onChipsChange,
|
|
15
|
+
onViewChange,
|
|
16
|
+
}: OpportunityFiltersProps): ReactElement {
|
|
17
|
+
const t = useT();
|
|
18
|
+
const [on, setOn] = useState(active);
|
|
19
|
+
return (
|
|
20
|
+
<div role="group" aria-label={t("filter.label")} className="flex flex-wrap items-center gap-8">
|
|
21
|
+
<label className="flex items-center gap-8 w-(--ui-skeleton-inline) min-w-0 grow h-row-default ps-12 pe-8 rounded-control border border-border-control bg-bg-surface focus-within:outline-solid focus-within:outline-stroke-focus focus-within:outline-focus-ring">
|
|
22
|
+
<Icon name="Search" color="var(--color-text-secondary)" />
|
|
23
|
+
<input
|
|
24
|
+
aria-label={t("opp.search")}
|
|
25
|
+
placeholder={hint}
|
|
26
|
+
onChange={(e) => onSearch?.(e.target.value)}
|
|
27
|
+
className="flex-1 min-w-0 bg-transparent border-0 outline-none text-text-primary placeholder:text-text-tertiary pointer-coarse:min-h-target-coarse"
|
|
28
|
+
/>
|
|
29
|
+
</label>
|
|
30
|
+
{chips.map((chip) => {
|
|
31
|
+
const pressed = on.includes(chip);
|
|
32
|
+
return (
|
|
33
|
+
<button
|
|
34
|
+
key={chip}
|
|
35
|
+
type="button"
|
|
36
|
+
aria-pressed={pressed}
|
|
37
|
+
onClick={() => {
|
|
38
|
+
const next = pressed ? on.filter((c) => c !== chip) : [...on, chip];
|
|
39
|
+
setOn(next);
|
|
40
|
+
onChipsChange?.(next);
|
|
41
|
+
}}
|
|
42
|
+
className={cx(
|
|
43
|
+
"inline-flex items-center gap-4 h-control-md px-12 rounded-pill border border-border-control bg-transparent cursor-pointer",
|
|
44
|
+
"font-medium text-text-13 text-text-secondary pointer-coarse:min-h-target-coarse",
|
|
45
|
+
"aria-pressed:bg-text-primary aria-pressed:text-bg-canvas aria-pressed:border-text-primary",
|
|
46
|
+
)}
|
|
47
|
+
>
|
|
48
|
+
{pressed ? <Icon name="Check" size={12} /> : null}
|
|
49
|
+
{chip}
|
|
50
|
+
</button>
|
|
51
|
+
);
|
|
52
|
+
})}
|
|
53
|
+
<SegmentedControl
|
|
54
|
+
label={t("view.label")}
|
|
55
|
+
value="cards"
|
|
56
|
+
onChange={(v) => onViewChange?.(v === "map" ? "map" : "cards")}
|
|
57
|
+
options={[
|
|
58
|
+
{ value: "cards", label: t("view.cards"), icon: "LayoutGrid" },
|
|
59
|
+
{ value: "map", label: t("view.map"), icon: "Map" },
|
|
60
|
+
]}
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
5
|
+
import { Money } from "../Forms/Forms.tsx";
|
|
6
|
+
import { type PaymentTrackerProps } from "./Gateway.types.ts";
|
|
7
|
+
|
|
8
|
+
/** A payment followed like a package: Submitted, Approved, Scheduled, Paid. */
|
|
9
|
+
export function PaymentTracker({
|
|
10
|
+
invoiceKey,
|
|
11
|
+
title,
|
|
12
|
+
amount,
|
|
13
|
+
current,
|
|
14
|
+
dates,
|
|
15
|
+
expected,
|
|
16
|
+
}: PaymentTrackerProps): ReactElement {
|
|
17
|
+
const t = useT();
|
|
18
|
+
const steps = [t("pay.submitted"), t("pay.approved"), t("pay.scheduled"), t("pay.paid")];
|
|
19
|
+
return (
|
|
20
|
+
<section
|
|
21
|
+
aria-label={t("pay.label", { key: invoiceKey })}
|
|
22
|
+
className="flex flex-col gap-16 w-(--ui-alert) max-w-full p-16 box-border rounded-card border border-border-subtle bg-bg-raised"
|
|
23
|
+
>
|
|
24
|
+
<div className="flex items-start justify-between gap-8">
|
|
25
|
+
<div className="flex flex-col">
|
|
26
|
+
<span className="font-mono text-text-12 text-text-secondary">{invoiceKey}</span>
|
|
27
|
+
<strong className="font-semibold">{title}</strong>
|
|
28
|
+
</div>
|
|
29
|
+
<strong className="text-heading-20 font-semibold tabular-nums">
|
|
30
|
+
<Money amount={amount} />
|
|
31
|
+
</strong>
|
|
32
|
+
</div>
|
|
33
|
+
<ol className="grid grid-cols-4 gap-8 m-0 p-0 list-none">
|
|
34
|
+
{steps.map((s, i) => {
|
|
35
|
+
const state = i < current ? "done" : i === current ? "current" : "todo";
|
|
36
|
+
const note =
|
|
37
|
+
dates[i] ??
|
|
38
|
+
(state === "todo" && expected && i === current + 1
|
|
39
|
+
? t("pay.expected", { date: expected })
|
|
40
|
+
: "");
|
|
41
|
+
return (
|
|
42
|
+
<li
|
|
43
|
+
key={s}
|
|
44
|
+
aria-current={state === "current" ? "step" : undefined}
|
|
45
|
+
className={cx(
|
|
46
|
+
"flex flex-col gap-6 pt-4 text-text-12 border-t-stroke-accent",
|
|
47
|
+
state === "done" && "border-t-success",
|
|
48
|
+
state === "current" && "border-t-accent font-medium",
|
|
49
|
+
state === "todo" && "border-t-border-subtle text-text-secondary",
|
|
50
|
+
)}
|
|
51
|
+
>
|
|
52
|
+
<span
|
|
53
|
+
className={cx(
|
|
54
|
+
"inline-grid place-items-center size-icon-20 rounded-full text-text-11 font-semibold tabular-nums",
|
|
55
|
+
state === "todo" &&
|
|
56
|
+
"ring-(length:--stroke-width-hairline) ring-inset ring-border-strong",
|
|
57
|
+
state === "current" && "bg-accent text-accent-text-on",
|
|
58
|
+
state === "done" && "bg-bg-hover text-success",
|
|
59
|
+
)}
|
|
60
|
+
>
|
|
61
|
+
{state === "done" ? <Icon name="Check" size={12} /> : i + 1}
|
|
62
|
+
</span>
|
|
63
|
+
<span>{s}</span>
|
|
64
|
+
<span className="text-text-secondary tabular-nums">{note}</span>
|
|
65
|
+
</li>
|
|
66
|
+
);
|
|
67
|
+
})}
|
|
68
|
+
</ol>
|
|
69
|
+
</section>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useState, type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
5
|
+
import { Button } from "../Button/Button.tsx";
|
|
6
|
+
import { chipClass } from "../Chips/Chips.tsx";
|
|
7
|
+
import { Card } from "../Surface/Surface.tsx";
|
|
8
|
+
import { Input, Select } from "../Forms/Forms.tsx";
|
|
9
|
+
import { type PayoutDetailsFormProps } from "./Gateway.types.ts";
|
|
10
|
+
|
|
11
|
+
/** Bank details in a secure form; after saving only the last four digits are shown. */
|
|
12
|
+
export function PayoutDetailsForm({ rail, onFile, onSave }: PayoutDetailsFormProps): ReactElement {
|
|
13
|
+
const t = useT();
|
|
14
|
+
const [routing, setRouting] = useState("");
|
|
15
|
+
const [account, setAccount] = useState("");
|
|
16
|
+
const [type, setType] = useState("checking");
|
|
17
|
+
return (
|
|
18
|
+
<Card
|
|
19
|
+
title={t("payout.title")}
|
|
20
|
+
meta={rail}
|
|
21
|
+
footer={
|
|
22
|
+
<Button variant="primary" icon="Lock" onClick={() => onSave?.({ routing, account, type })}>
|
|
23
|
+
{t("payout.save")}
|
|
24
|
+
</Button>
|
|
25
|
+
}
|
|
26
|
+
>
|
|
27
|
+
{onFile ? (
|
|
28
|
+
<div className={cx(chipClass, "h-control-lg self-start")}>
|
|
29
|
+
<Icon name="Landmark" size={14} />
|
|
30
|
+
<span>{onFile.bank}</span>
|
|
31
|
+
<span className="font-mono">{t("payout.masked", { last4: onFile.last4 })}</span>
|
|
32
|
+
</div>
|
|
33
|
+
) : null}
|
|
34
|
+
<Input
|
|
35
|
+
label={t("payout.routing")}
|
|
36
|
+
inputMode="numeric"
|
|
37
|
+
autoComplete="off"
|
|
38
|
+
placeholder={t("payout.routingHint")}
|
|
39
|
+
value={routing}
|
|
40
|
+
onChange={(e) => setRouting(e.target.value)}
|
|
41
|
+
/>
|
|
42
|
+
<Input
|
|
43
|
+
label={t("payout.account")}
|
|
44
|
+
inputMode="numeric"
|
|
45
|
+
autoComplete="off"
|
|
46
|
+
type="password"
|
|
47
|
+
help={t("payout.accountHelp")}
|
|
48
|
+
value={account}
|
|
49
|
+
onChange={(e) => setAccount(e.target.value)}
|
|
50
|
+
/>
|
|
51
|
+
<Select
|
|
52
|
+
label={t("payout.type")}
|
|
53
|
+
value="checking"
|
|
54
|
+
options={[
|
|
55
|
+
{ value: "checking", label: t("payout.checking") },
|
|
56
|
+
{ value: "savings", label: t("payout.savings") },
|
|
57
|
+
]}
|
|
58
|
+
onChange={(e) => setType(e.target.value)}
|
|
59
|
+
/>
|
|
60
|
+
</Card>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { useT } from "../lib/context.tsx";
|
|
3
|
+
import { Card } from "../Surface/Surface.tsx";
|
|
4
|
+
import { SegmentedControl } from "../Navigation/Navigation.tsx";
|
|
5
|
+
import { type ProfileEditorProps } from "./Gateway.types.ts";
|
|
6
|
+
import { ProgressBar } from "./ProgressBar.tsx";
|
|
7
|
+
|
|
8
|
+
/** Each field's visibility (Private, On Apply, Public) with a strength meter naming the next step. */
|
|
9
|
+
export function ProfileEditor({
|
|
10
|
+
strength,
|
|
11
|
+
nextStep,
|
|
12
|
+
fields,
|
|
13
|
+
onVisibilityChange,
|
|
14
|
+
}: ProfileEditorProps): ReactElement {
|
|
15
|
+
const t = useT();
|
|
16
|
+
const options = [
|
|
17
|
+
{ value: "private", label: t("visibility.private") },
|
|
18
|
+
{ value: "application", label: t("visibility.application") },
|
|
19
|
+
{ value: "public", label: t("visibility.public") },
|
|
20
|
+
];
|
|
21
|
+
return (
|
|
22
|
+
<Card title={t("profile.title")} meta={t("profile.complete", { n: strength })}>
|
|
23
|
+
<ProgressBar label={nextStep} value={strength} />
|
|
24
|
+
{fields.map((f) => (
|
|
25
|
+
<div
|
|
26
|
+
key={f.label}
|
|
27
|
+
className="flex flex-wrap items-center gap-12 py-8 border-b border-border-subtle last:border-b-0"
|
|
28
|
+
>
|
|
29
|
+
<div className="flex flex-1 flex-col min-w-0">
|
|
30
|
+
<span className="text-text-12 font-medium text-text-secondary">{f.label}</span>
|
|
31
|
+
<span>{f.value}</span>
|
|
32
|
+
</div>
|
|
33
|
+
<SegmentedControl
|
|
34
|
+
label={f.label}
|
|
35
|
+
value={f.visibility}
|
|
36
|
+
options={options}
|
|
37
|
+
onChange={(v) =>
|
|
38
|
+
onVisibilityChange?.(f.label, v as "private" | "application" | "public")
|
|
39
|
+
}
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
))}
|
|
43
|
+
</Card>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { useT } from "../lib/context.tsx";
|
|
3
|
+
import { type ProgressBarProps } from "./Gateway.types.ts";
|
|
4
|
+
|
|
5
|
+
/** Determinate progress with its percentage. */
|
|
6
|
+
export function ProgressBar({ label, value }: ProgressBarProps): ReactElement {
|
|
7
|
+
const t = useT();
|
|
8
|
+
const pct = Math.max(0, Math.min(100, Math.round(value)));
|
|
9
|
+
return (
|
|
10
|
+
<div className="flex flex-col gap-6 w-(--ui-field) max-w-full">
|
|
11
|
+
<div className="flex justify-between text-text-12 text-text-secondary">
|
|
12
|
+
<span>{label}</span>
|
|
13
|
+
<span className="tabular-nums">{t("progress.percent", { n: pct })}</span>
|
|
14
|
+
</div>
|
|
15
|
+
<div
|
|
16
|
+
role="progressbar"
|
|
17
|
+
aria-label={label}
|
|
18
|
+
aria-valuenow={pct}
|
|
19
|
+
aria-valuemin={0}
|
|
20
|
+
aria-valuemax={100}
|
|
21
|
+
className="h-(--space-4) rounded-pill bg-bg-hover overflow-hidden"
|
|
22
|
+
>
|
|
23
|
+
<div
|
|
24
|
+
className="h-full rounded-pill bg-accent forced-colors:bg-[Highlight]"
|
|
25
|
+
style={{ inlineSize: `${pct}%` }}
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { useState, type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
5
|
+
import { Button } from "../Button/Button.tsx";
|
|
6
|
+
import { Textarea } from "../Forms/Forms.tsx";
|
|
7
|
+
import { Dialog } from "../Overlays/Overlays.tsx";
|
|
8
|
+
import { type RatingDialogProps } from "./Gateway.types.ts";
|
|
9
|
+
|
|
10
|
+
/** A two-sided rating after close-out; stars are a radio group, both ratings release together. */
|
|
11
|
+
export function RatingDialog({
|
|
12
|
+
counterpart,
|
|
13
|
+
value = 0,
|
|
14
|
+
onSubmit,
|
|
15
|
+
onLater,
|
|
16
|
+
open,
|
|
17
|
+
onOpenChange,
|
|
18
|
+
}: RatingDialogProps): ReactElement {
|
|
19
|
+
const t = useT();
|
|
20
|
+
const [rating, setRating] = useState(value);
|
|
21
|
+
const [comment, setComment] = useState("");
|
|
22
|
+
return (
|
|
23
|
+
<Dialog
|
|
24
|
+
title={t("rating.title", { name: counterpart })}
|
|
25
|
+
{...(open === undefined ? {} : { open })}
|
|
26
|
+
{...(onOpenChange ? { onOpenChange } : {})}
|
|
27
|
+
actions={
|
|
28
|
+
<>
|
|
29
|
+
<Button variant="ghost" onClick={onLater}>
|
|
30
|
+
{t("action.later")}
|
|
31
|
+
</Button>
|
|
32
|
+
<Button variant="primary" disabled={!rating} onClick={() => onSubmit?.(rating, comment)}>
|
|
33
|
+
{t("rating.submit")}
|
|
34
|
+
</Button>
|
|
35
|
+
</>
|
|
36
|
+
}
|
|
37
|
+
>
|
|
38
|
+
<div className="flex flex-col gap-12">
|
|
39
|
+
<div role="radiogroup" aria-label={t("rating.label")} className="flex gap-4">
|
|
40
|
+
{[1, 2, 3, 4, 5].map((n) => (
|
|
41
|
+
<button
|
|
42
|
+
key={n}
|
|
43
|
+
type="button"
|
|
44
|
+
role="radio"
|
|
45
|
+
aria-checked={rating === n}
|
|
46
|
+
tabIndex={rating === n || (rating === 0 && n === 1) ? 0 : -1}
|
|
47
|
+
aria-label={t(n === 1 ? "rating.star" : "rating.stars", { n })}
|
|
48
|
+
onClick={() => setRating(n)}
|
|
49
|
+
onKeyDown={(e) => {
|
|
50
|
+
const next =
|
|
51
|
+
e.key === "ArrowRight" || e.key === "ArrowUp"
|
|
52
|
+
? Math.min(5, n + 1)
|
|
53
|
+
: e.key === "ArrowLeft" || e.key === "ArrowDown"
|
|
54
|
+
? Math.max(1, n - 1)
|
|
55
|
+
: null;
|
|
56
|
+
if (next === null) return;
|
|
57
|
+
e.preventDefault();
|
|
58
|
+
setRating(next);
|
|
59
|
+
(
|
|
60
|
+
e.currentTarget.parentElement?.children[next - 1] as HTMLElement | undefined
|
|
61
|
+
)?.focus();
|
|
62
|
+
}}
|
|
63
|
+
className={cx(
|
|
64
|
+
"grid place-items-center size-(--density-target-coarse) rounded-control border-0 bg-transparent cursor-pointer text-text-tertiary",
|
|
65
|
+
n <= rating && "text-warning [&_svg]:fill-current",
|
|
66
|
+
)}
|
|
67
|
+
>
|
|
68
|
+
<Icon name="Star" size={24} />
|
|
69
|
+
</button>
|
|
70
|
+
))}
|
|
71
|
+
</div>
|
|
72
|
+
<Textarea
|
|
73
|
+
label={t("rating.comment")}
|
|
74
|
+
width="100%"
|
|
75
|
+
rows={2}
|
|
76
|
+
value={comment}
|
|
77
|
+
onChange={(e) => setComment(e.target.value)}
|
|
78
|
+
/>
|
|
79
|
+
<span className="text-text-12 text-text-secondary">{t("rating.release")}</span>
|
|
80
|
+
</div>
|
|
81
|
+
</Dialog>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { cx } from "../lib/cx.ts";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
5
|
+
import { Button } from "../Button/Button.tsx";
|
|
6
|
+
import { BrandMark } from "../BrandMark/BrandMark.tsx";
|
|
7
|
+
import { PropertyList } from "../Overlays/Overlays.tsx";
|
|
8
|
+
import { panelClass } from "./Gateway.shared.tsx";
|
|
9
|
+
import { type UpNextCardProps } from "./Gateway.types.ts";
|
|
10
|
+
|
|
11
|
+
/** Leads Gateway Home with the next shift: countdown, call time, address and what to bring. */
|
|
12
|
+
export function UpNextCard({
|
|
13
|
+
org,
|
|
14
|
+
countdown,
|
|
15
|
+
title,
|
|
16
|
+
when,
|
|
17
|
+
callTime,
|
|
18
|
+
address,
|
|
19
|
+
parking,
|
|
20
|
+
contact,
|
|
21
|
+
bring,
|
|
22
|
+
onDirections,
|
|
23
|
+
onCalendar,
|
|
24
|
+
onWallet,
|
|
25
|
+
}: UpNextCardProps): ReactElement {
|
|
26
|
+
const t = useT();
|
|
27
|
+
const properties = [
|
|
28
|
+
{ label: t("upnext.when"), value: <span className="tabular-nums">{when}</span> },
|
|
29
|
+
{ label: t("upnext.call"), value: <span className="tabular-nums">{callTime}</span> },
|
|
30
|
+
{ label: t("upnext.where"), value: address },
|
|
31
|
+
...(parking ? [{ label: t("upnext.parking"), value: parking }] : []),
|
|
32
|
+
...(contact ? [{ label: t("upnext.contact"), value: contact }] : []),
|
|
33
|
+
];
|
|
34
|
+
return (
|
|
35
|
+
<article
|
|
36
|
+
aria-label={t("upnext.label")}
|
|
37
|
+
className={cx(panelClass, "gap-12 w-(--ui-gateway-aside) p-16 text-text-14")}
|
|
38
|
+
>
|
|
39
|
+
<header className="flex items-center justify-between gap-8">
|
|
40
|
+
<span className="flex items-center gap-6">
|
|
41
|
+
<BrandMark name={org} size="sm" iconOnly />
|
|
42
|
+
<span className="text-text-12 font-medium text-text-secondary">{t("upnext.label")}</span>
|
|
43
|
+
</span>
|
|
44
|
+
<span className="font-semibold text-accent-text tabular-nums">{countdown}</span>
|
|
45
|
+
</header>
|
|
46
|
+
<h3 className="m-0 text-heading-20 font-semibold">{title}</h3>
|
|
47
|
+
<PropertyList items={properties} />
|
|
48
|
+
{bring && bring.length ? (
|
|
49
|
+
<div className="flex flex-col gap-4">
|
|
50
|
+
<span className="text-text-12 font-medium text-text-secondary">{t("upnext.bring")}</span>
|
|
51
|
+
<ul className="flex flex-col gap-4 m-0 p-0 list-none">
|
|
52
|
+
{bring.map((b) => (
|
|
53
|
+
<li key={b} className="flex items-center gap-6">
|
|
54
|
+
<span className="text-success">
|
|
55
|
+
<Icon name="Check" size={14} />
|
|
56
|
+
</span>
|
|
57
|
+
{b}
|
|
58
|
+
</li>
|
|
59
|
+
))}
|
|
60
|
+
</ul>
|
|
61
|
+
</div>
|
|
62
|
+
) : null}
|
|
63
|
+
<footer className="flex flex-wrap items-center gap-8">
|
|
64
|
+
<Button variant="primary" icon="Navigation" onClick={onDirections}>
|
|
65
|
+
{t("upnext.directions")}
|
|
66
|
+
</Button>
|
|
67
|
+
<Button icon="CalendarPlus" onClick={onCalendar}>
|
|
68
|
+
{t("upnext.calendar")}
|
|
69
|
+
</Button>
|
|
70
|
+
<Button icon="Wallet" onClick={onWallet}>
|
|
71
|
+
{t("badge.wallet")}
|
|
72
|
+
</Button>
|
|
73
|
+
</footer>
|
|
74
|
+
</article>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import {
|
|
3
|
+
departmentCodes,
|
|
4
|
+
departmentIcon,
|
|
5
|
+
phaseCodes,
|
|
6
|
+
phaseIcon,
|
|
7
|
+
recordKindIcon,
|
|
8
|
+
recordKinds,
|
|
9
|
+
} from "@xos/icons/glyphs";
|
|
10
|
+
import type {
|
|
11
|
+
DepartmentCode,
|
|
12
|
+
DepartmentGlyphProps as ReferenceDepartmentGlyphProps,
|
|
13
|
+
PhaseCode,
|
|
14
|
+
PhaseGlyphProps as ReferencePhaseGlyphProps,
|
|
15
|
+
RecordKind,
|
|
16
|
+
RecordKindGlyphProps as ReferenceRecordKindGlyphProps,
|
|
17
|
+
} from "../types/reference";
|
|
18
|
+
import { Icon } from "../Icon/Icon.tsx";
|
|
19
|
+
|
|
20
|
+
export type DepartmentGlyphProps = ReferenceDepartmentGlyphProps;
|
|
21
|
+
export type PhaseGlyphProps = ReferencePhaseGlyphProps;
|
|
22
|
+
export type RecordKindGlyphProps = ReferenceRecordKindGlyphProps;
|
|
23
|
+
|
|
24
|
+
/** The XOS glyph map (canon code to Lucide name), from @xos/icons so the assignment lives in one place. */
|
|
25
|
+
export const glyphs: {
|
|
26
|
+
departments: Record<DepartmentCode, string>;
|
|
27
|
+
phases: Record<PhaseCode, string>;
|
|
28
|
+
recordKinds: Record<RecordKind, string>;
|
|
29
|
+
} = {
|
|
30
|
+
departments: Object.fromEntries(departmentCodes.map((c) => [c, departmentIcon(c)])) as Record<
|
|
31
|
+
DepartmentCode,
|
|
32
|
+
string
|
|
33
|
+
>,
|
|
34
|
+
phases: Object.fromEntries(phaseCodes.map((c) => [c, phaseIcon(c)])) as Record<PhaseCode, string>,
|
|
35
|
+
recordKinds: Object.fromEntries(recordKinds.map((k) => [k, recordKindIcon(k)])) as Record<
|
|
36
|
+
RecordKind,
|
|
37
|
+
string
|
|
38
|
+
>,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
function glyphProps(
|
|
42
|
+
size: number | undefined,
|
|
43
|
+
label: string | undefined,
|
|
44
|
+
color: string | undefined,
|
|
45
|
+
) {
|
|
46
|
+
return {
|
|
47
|
+
...(size === undefined ? {} : { size }),
|
|
48
|
+
...(label === undefined ? {} : { label }),
|
|
49
|
+
...(color === undefined ? {} : { color }),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Department glyph (`4000` Environment is Tent). Sits beside the plain name; never alone. */
|
|
54
|
+
export function DepartmentGlyph({ code, size, label, color }: DepartmentGlyphProps): ReactElement {
|
|
55
|
+
return <Icon name={glyphs.departments[code] ?? "Circle"} {...glyphProps(size, label, color)} />;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Phase glyph (`BLD` Build is Hammer). */
|
|
59
|
+
export function PhaseGlyph({ code, size, label, color }: PhaseGlyphProps): ReactElement {
|
|
60
|
+
return <Icon name={glyphs.phases[code] ?? "Circle"} {...glyphProps(size, label, color)} />;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Record kind glyph (`Task` is SquareCheck). */
|
|
64
|
+
export function RecordKindGlyph({ kind, size, label, color }: RecordKindGlyphProps): ReactElement {
|
|
65
|
+
return <Icon name={glyphs.recordKinds[kind] ?? "Circle"} {...glyphProps(size, label, color)} />;
|
|
66
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import type { GridColumn } from "../types/reference";
|
|
3
|
+
import { useT } from "../lib/context.tsx";
|
|
4
|
+
import { InlineAlert } from "../Feedback/Feedback.tsx";
|
|
5
|
+
import { type BidSheetProps } from "./Grids.types.ts";
|
|
6
|
+
import { SpreadsheetGrid } from "./SpreadsheetGrid.tsx";
|
|
7
|
+
|
|
8
|
+
/** A sealed line-item bid: unit prices are the only editable cells; extended amounts and the total are derived and stay Unpriced while any line is blank. */
|
|
9
|
+
export function BidSheet({ deadline, lines, onChange }: BidSheetProps): ReactElement {
|
|
10
|
+
const t = useT();
|
|
11
|
+
const columns: GridColumn[] = [
|
|
12
|
+
{ key: "line", label: t("bid.line"), type: "code", width: 64 },
|
|
13
|
+
{ key: "item", label: t("bid.item") },
|
|
14
|
+
{ key: "unit", label: t("bid.unit"), width: 72 },
|
|
15
|
+
{ key: "qty", label: t("bid.qty"), type: "number", width: 64 },
|
|
16
|
+
{ key: "price", label: t("bid.unitPrice"), type: "money", editable: true },
|
|
17
|
+
{
|
|
18
|
+
key: "ext",
|
|
19
|
+
label: t("bid.extended"),
|
|
20
|
+
type: "money",
|
|
21
|
+
total: true,
|
|
22
|
+
derive: (row) =>
|
|
23
|
+
typeof row["qty"] === "number" && typeof row["price"] === "number"
|
|
24
|
+
? row["qty"] * row["price"]
|
|
25
|
+
: null,
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
return (
|
|
29
|
+
<div className="flex flex-col gap-12">
|
|
30
|
+
<InlineAlert tone="info" title={t("bid.sealed")}>
|
|
31
|
+
{t("bid.sealedBody", { deadline })}
|
|
32
|
+
</InlineAlert>
|
|
33
|
+
<SpreadsheetGrid
|
|
34
|
+
label={t("bid.lines")}
|
|
35
|
+
columns={columns}
|
|
36
|
+
rows={lines.map((l) => ({
|
|
37
|
+
line: l.line,
|
|
38
|
+
item: l.item,
|
|
39
|
+
unit: l.unit,
|
|
40
|
+
qty: l.qty,
|
|
41
|
+
price: l.price,
|
|
42
|
+
ext: l.ext,
|
|
43
|
+
}))}
|
|
44
|
+
totalsLabel={t("bid.total")}
|
|
45
|
+
onChange={(rows) =>
|
|
46
|
+
onChange?.(
|
|
47
|
+
rows.map((r) => ({
|
|
48
|
+
line: String(r["line"] ?? ""),
|
|
49
|
+
item: String(r["item"] ?? ""),
|
|
50
|
+
unit: String(r["unit"] ?? ""),
|
|
51
|
+
qty: Number(r["qty"] ?? 0),
|
|
52
|
+
price: typeof r["price"] === "number" ? r["price"] : null,
|
|
53
|
+
ext:
|
|
54
|
+
typeof r["qty"] === "number" && typeof r["price"] === "number"
|
|
55
|
+
? r["qty"] * r["price"]
|
|
56
|
+
: null,
|
|
57
|
+
})),
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
/>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|