@open-mercato/ui 0.5.1-develop.2856.35de414092 → 0.5.1-develop.2874.77704bccbd
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/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +204 -121
- package/dist/backend/AppShell.js +25 -28
- package/dist/backend/AppShell.js.map +2 -2
- package/dist/backend/ContextHelp.js +1 -1
- package/dist/backend/ContextHelp.js.map +1 -1
- package/dist/backend/CrudForm.js +12 -15
- package/dist/backend/CrudForm.js.map +2 -2
- package/dist/backend/DataTable.js +9 -10
- package/dist/backend/DataTable.js.map +2 -2
- package/dist/backend/FilterBar.js +6 -8
- package/dist/backend/FilterBar.js.map +2 -2
- package/dist/backend/FilterOverlay.js +10 -10
- package/dist/backend/FilterOverlay.js.map +2 -2
- package/dist/backend/FlashMessages.js +1 -1
- package/dist/backend/FlashMessages.js.map +2 -2
- package/dist/backend/JsonBuilder.js +6 -6
- package/dist/backend/JsonBuilder.js.map +1 -1
- package/dist/backend/NextStepCallout.js +1 -1
- package/dist/backend/NextStepCallout.js.map +1 -1
- package/dist/backend/PerspectiveSidebar.js +2 -2
- package/dist/backend/PerspectiveSidebar.js.map +2 -2
- package/dist/backend/ProfileDropdown.js +1 -1
- package/dist/backend/ProfileDropdown.js.map +1 -1
- package/dist/backend/RowActions.js +1 -1
- package/dist/backend/RowActions.js.map +1 -1
- package/dist/backend/UserMenu.js +2 -2
- package/dist/backend/UserMenu.js.map +1 -1
- package/dist/backend/WebhookSetupGuide.js +11 -11
- package/dist/backend/WebhookSetupGuide.js.map +2 -2
- package/dist/backend/charts/KpiCard.js +3 -3
- package/dist/backend/charts/KpiCard.js.map +1 -1
- package/dist/backend/columns/ColumnChooserPanel.js +1 -1
- package/dist/backend/columns/ColumnChooserPanel.js.map +2 -2
- package/dist/backend/custom-fields/FieldDefinitionsEditor.js +3 -3
- package/dist/backend/custom-fields/FieldDefinitionsEditor.js.map +2 -2
- package/dist/backend/dashboard/DashboardScreen.js +1 -1
- package/dist/backend/dashboard/DashboardScreen.js.map +1 -1
- package/dist/backend/date-range/DateRangeSelect.js +1 -1
- package/dist/backend/date-range/DateRangeSelect.js.map +1 -1
- package/dist/backend/date-range/InlineDateRangeSelect.js +1 -1
- package/dist/backend/date-range/InlineDateRangeSelect.js.map +1 -1
- package/dist/backend/detail/AccessDeniedMessage.js +1 -1
- package/dist/backend/detail/AccessDeniedMessage.js.map +1 -1
- package/dist/backend/detail/ActivitiesSection.js +5 -5
- package/dist/backend/detail/ActivitiesSection.js.map +1 -1
- package/dist/backend/detail/AddressEditor.js +3 -3
- package/dist/backend/detail/AddressEditor.js.map +2 -2
- package/dist/backend/detail/AddressTiles.js +3 -3
- package/dist/backend/detail/AddressTiles.js.map +2 -2
- package/dist/backend/detail/AttachmentMetadataDialog.js +1 -1
- package/dist/backend/detail/AttachmentMetadataDialog.js.map +1 -1
- package/dist/backend/detail/CustomDataSection.js +1 -1
- package/dist/backend/detail/CustomDataSection.js.map +1 -1
- package/dist/backend/detail/InlineEditors.js +5 -5
- package/dist/backend/detail/InlineEditors.js.map +1 -1
- package/dist/backend/detail/NotesSection.js +6 -6
- package/dist/backend/detail/NotesSection.js.map +1 -1
- package/dist/backend/detail/TagsSection.js +1 -1
- package/dist/backend/detail/TagsSection.js.map +1 -1
- package/dist/backend/devtools/UmesDevToolsPanel.js +6 -6
- package/dist/backend/devtools/UmesDevToolsPanel.js.map +2 -2
- package/dist/backend/devtools/components/ConflictWarnings.js +3 -3
- package/dist/backend/devtools/components/ConflictWarnings.js.map +2 -2
- package/dist/backend/devtools/components/EnricherTiming.js +2 -2
- package/dist/backend/devtools/components/EnricherTiming.js.map +2 -2
- package/dist/backend/devtools/components/EventFlow.js +5 -5
- package/dist/backend/devtools/components/EventFlow.js.map +2 -2
- package/dist/backend/devtools/components/ExtensionPointList.js +3 -3
- package/dist/backend/devtools/components/ExtensionPointList.js.map +2 -2
- package/dist/backend/devtools/components/InterceptorActivity.js +6 -6
- package/dist/backend/devtools/components/InterceptorActivity.js.map +2 -2
- package/dist/backend/forms/ActionsDropdown.js +1 -1
- package/dist/backend/forms/ActionsDropdown.js.map +1 -1
- package/dist/backend/forms/FormActionButtons.js +2 -3
- package/dist/backend/forms/FormActionButtons.js.map +2 -2
- package/dist/backend/indexes/PartialIndexBanner.js +8 -8
- package/dist/backend/indexes/PartialIndexBanner.js.map +2 -2
- package/dist/backend/inputs/ComboboxInput.js +1 -1
- package/dist/backend/inputs/ComboboxInput.js.map +2 -2
- package/dist/backend/inputs/DatePicker.js +3 -3
- package/dist/backend/inputs/DatePicker.js.map +1 -1
- package/dist/backend/inputs/DateTimePicker.js +3 -3
- package/dist/backend/inputs/DateTimePicker.js.map +1 -1
- package/dist/backend/inputs/EventSelect.js +1 -1
- package/dist/backend/inputs/EventSelect.js.map +2 -2
- package/dist/backend/inputs/LookupSelect.js +1 -1
- package/dist/backend/inputs/LookupSelect.js.map +1 -1
- package/dist/backend/inputs/SwitchableMarkdownInput.js +1 -1
- package/dist/backend/inputs/SwitchableMarkdownInput.js.map +1 -1
- package/dist/backend/inputs/TagsInput.js +2 -2
- package/dist/backend/inputs/TagsInput.js.map +2 -2
- package/dist/backend/inputs/TimeInput.js +1 -1
- package/dist/backend/inputs/TimeInput.js.map +1 -1
- package/dist/backend/inputs/TimePicker.js +3 -3
- package/dist/backend/inputs/TimePicker.js.map +1 -1
- package/dist/backend/messages/MessageObjectDetail.js +1 -1
- package/dist/backend/messages/MessageObjectDetail.js.map +1 -1
- package/dist/backend/messages/MessageObjectPreview.js +1 -1
- package/dist/backend/messages/MessageObjectPreview.js.map +1 -1
- package/dist/backend/messages/message-compose-form-groups.js +3 -3
- package/dist/backend/messages/message-compose-form-groups.js.map +1 -1
- package/dist/backend/notifications/NotificationCountBadge.js +1 -1
- package/dist/backend/notifications/NotificationCountBadge.js.map +2 -2
- package/dist/backend/notifications/NotificationPanel.js +3 -3
- package/dist/backend/notifications/NotificationPanel.js.map +1 -1
- package/dist/backend/progress/ProgressTopBar.js +4 -4
- package/dist/backend/progress/ProgressTopBar.js.map +2 -2
- package/dist/backend/schedule/ScheduleAgenda.js +1 -1
- package/dist/backend/schedule/ScheduleAgenda.js.map +2 -2
- package/dist/backend/schedule/ScheduleCalendar.js +1 -1
- package/dist/backend/schedule/ScheduleCalendar.js.map +1 -1
- package/dist/backend/schedule/ScheduleGrid.js +1 -1
- package/dist/backend/schedule/ScheduleGrid.js.map +2 -2
- package/dist/backend/version-history/VersionHistoryPanel.js +4 -4
- package/dist/backend/version-history/VersionHistoryPanel.js.map +2 -2
- package/dist/frontend/AuthFooter.js +1 -1
- package/dist/frontend/AuthFooter.js.map +1 -1
- package/dist/frontend/LanguageSwitcher.js +1 -1
- package/dist/frontend/LanguageSwitcher.js.map +1 -1
- package/dist/frontend/Layout.js +2 -2
- package/dist/frontend/Layout.js.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +2 -2
- package/dist/portal/PortalShell.js +15 -15
- package/dist/portal/PortalShell.js.map +2 -2
- package/dist/portal/components/PortalCard.js +2 -2
- package/dist/portal/components/PortalCard.js.map +2 -2
- package/dist/portal/components/PortalNotificationPanel.js +18 -18
- package/dist/portal/components/PortalNotificationPanel.js.map +2 -2
- package/dist/portal/components/PortalPageHeader.js +1 -1
- package/dist/portal/components/PortalPageHeader.js.map +2 -2
- package/dist/primitives/avatar.js +11 -1
- package/dist/primitives/avatar.js.map +2 -2
- package/dist/primitives/badge.js +1 -1
- package/dist/primitives/badge.js.map +1 -1
- package/dist/primitives/button.js +9 -5
- package/dist/primitives/button.js.map +2 -2
- package/dist/primitives/calendar.js +1 -1
- package/dist/primitives/calendar.js.map +1 -1
- package/dist/primitives/checkbox-field.js +63 -0
- package/dist/primitives/checkbox-field.js.map +7 -0
- package/dist/primitives/checkbox.js +31 -17
- package/dist/primitives/checkbox.js.map +2 -2
- package/dist/primitives/dialog.js +4 -4
- package/dist/primitives/dialog.js.map +1 -1
- package/dist/primitives/fancy-button.js +72 -0
- package/dist/primitives/fancy-button.js.map +7 -0
- package/dist/primitives/icon-button.js +20 -4
- package/dist/primitives/icon-button.js.map +2 -2
- package/dist/primitives/kbd.js +27 -0
- package/dist/primitives/kbd.js.map +7 -0
- package/dist/primitives/link-button.js +56 -0
- package/dist/primitives/link-button.js.map +7 -0
- package/dist/primitives/popover.js +1 -1
- package/dist/primitives/popover.js.map +1 -1
- package/dist/primitives/social-button.js +61 -0
- package/dist/primitives/social-button.js.map +7 -0
- package/dist/primitives/tabs.js +1 -1
- package/dist/primitives/tabs.js.map +1 -1
- package/dist/primitives/tag.js +45 -0
- package/dist/primitives/tag.js.map +7 -0
- package/dist/primitives/tooltip.js +1 -1
- package/dist/primitives/tooltip.js.map +1 -1
- package/package.json +3 -3
- package/src/backend/AppShell.tsx +25 -28
- package/src/backend/ContextHelp.tsx +1 -1
- package/src/backend/CrudForm.tsx +12 -15
- package/src/backend/DataTable.tsx +9 -10
- package/src/backend/FilterBar.tsx +6 -5
- package/src/backend/FilterOverlay.tsx +10 -10
- package/src/backend/FlashMessages.tsx +1 -1
- package/src/backend/JsonBuilder.tsx +6 -6
- package/src/backend/NextStepCallout.tsx +1 -1
- package/src/backend/PerspectiveSidebar.tsx +2 -2
- package/src/backend/ProfileDropdown.tsx +1 -1
- package/src/backend/RowActions.tsx +1 -1
- package/src/backend/UserMenu.tsx +2 -2
- package/src/backend/WebhookSetupGuide.tsx +11 -11
- package/src/backend/charts/KpiCard.tsx +3 -3
- package/src/backend/columns/ColumnChooserPanel.tsx +1 -1
- package/src/backend/custom-fields/FieldDefinitionsEditor.tsx +3 -3
- package/src/backend/dashboard/DashboardScreen.tsx +1 -1
- package/src/backend/date-range/DateRangeSelect.tsx +1 -1
- package/src/backend/date-range/InlineDateRangeSelect.tsx +1 -1
- package/src/backend/detail/AccessDeniedMessage.tsx +1 -1
- package/src/backend/detail/ActivitiesSection.tsx +5 -5
- package/src/backend/detail/AddressEditor.tsx +3 -3
- package/src/backend/detail/AddressTiles.tsx +3 -3
- package/src/backend/detail/AttachmentMetadataDialog.tsx +1 -1
- package/src/backend/detail/CustomDataSection.tsx +1 -1
- package/src/backend/detail/InlineEditors.tsx +5 -5
- package/src/backend/detail/NotesSection.tsx +6 -6
- package/src/backend/detail/TagsSection.tsx +1 -1
- package/src/backend/devtools/UmesDevToolsPanel.tsx +6 -6
- package/src/backend/devtools/components/ConflictWarnings.tsx +4 -4
- package/src/backend/devtools/components/EnricherTiming.tsx +2 -2
- package/src/backend/devtools/components/EventFlow.tsx +5 -5
- package/src/backend/devtools/components/ExtensionPointList.tsx +3 -3
- package/src/backend/devtools/components/InterceptorActivity.tsx +6 -6
- package/src/backend/forms/ActionsDropdown.tsx +1 -1
- package/src/backend/forms/FormActionButtons.tsx +4 -5
- package/src/backend/indexes/PartialIndexBanner.tsx +8 -8
- package/src/backend/inputs/ComboboxInput.tsx +1 -1
- package/src/backend/inputs/DatePicker.tsx +3 -3
- package/src/backend/inputs/DateTimePicker.tsx +3 -3
- package/src/backend/inputs/EventSelect.tsx +1 -1
- package/src/backend/inputs/LookupSelect.tsx +1 -1
- package/src/backend/inputs/SwitchableMarkdownInput.tsx +1 -1
- package/src/backend/inputs/TagsInput.tsx +2 -2
- package/src/backend/inputs/TimeInput.tsx +1 -1
- package/src/backend/inputs/TimePicker.tsx +3 -3
- package/src/backend/messages/MessageObjectDetail.tsx +1 -1
- package/src/backend/messages/MessageObjectPreview.tsx +1 -1
- package/src/backend/messages/message-compose-form-groups.tsx +3 -3
- package/src/backend/notifications/NotificationCountBadge.tsx +1 -1
- package/src/backend/notifications/NotificationPanel.tsx +3 -3
- package/src/backend/progress/ProgressTopBar.tsx +4 -4
- package/src/backend/schedule/ScheduleAgenda.tsx +1 -1
- package/src/backend/schedule/ScheduleCalendar.tsx +1 -1
- package/src/backend/schedule/ScheduleGrid.tsx +1 -1
- package/src/backend/version-history/VersionHistoryPanel.tsx +4 -4
- package/src/frontend/AuthFooter.tsx +1 -1
- package/src/frontend/LanguageSwitcher.tsx +1 -1
- package/src/frontend/Layout.tsx +2 -2
- package/src/index.ts +6 -1
- package/src/portal/PortalShell.tsx +15 -15
- package/src/portal/components/PortalCard.tsx +2 -2
- package/src/portal/components/PortalNotificationPanel.tsx +18 -18
- package/src/portal/components/PortalPageHeader.tsx +1 -1
- package/src/primitives/avatar.tsx +22 -0
- package/src/primitives/badge.tsx +1 -1
- package/src/primitives/button.tsx +12 -5
- package/src/primitives/calendar.tsx +1 -1
- package/src/primitives/checkbox-field.tsx +85 -0
- package/src/primitives/checkbox.tsx +44 -18
- package/src/primitives/dialog.tsx +4 -4
- package/src/primitives/fancy-button.tsx +89 -0
- package/src/primitives/icon-button.tsx +19 -2
- package/src/primitives/kbd.tsx +38 -0
- package/src/primitives/link-button.tsx +55 -0
- package/src/primitives/popover.tsx +1 -1
- package/src/primitives/social-button.tsx +80 -0
- package/src/primitives/tabs.tsx +1 -1
- package/src/primitives/tag.tsx +66 -0
- package/src/primitives/tooltip.tsx +1 -1
package/src/backend/AppShell.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import Image from 'next/image'
|
|
|
6
6
|
import { ChevronUp, ChevronDown } from 'lucide-react'
|
|
7
7
|
import { Button } from '../primitives/button'
|
|
8
8
|
import { IconButton } from '../primitives/icon-button'
|
|
9
|
+
import { Checkbox } from '../primitives/checkbox'
|
|
9
10
|
import { Separator } from '../primitives/separator'
|
|
10
11
|
import { FlashMessages } from './FlashMessages'
|
|
11
12
|
import { QueryProvider } from '../theme/QueryProvider'
|
|
@@ -753,7 +754,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
753
754
|
|
|
754
755
|
const asideWidth = effectiveCollapsed ? '72px' : expandedSidebarWidth
|
|
755
756
|
// Use min-h-svh so the border extends with tall content; no overflow so sticky bottom works
|
|
756
|
-
const asideClassesBase = `border-r bg-background/
|
|
757
|
+
const asideClassesBase = `border-r bg-background/80 py-4 min-h-svh`;
|
|
757
758
|
|
|
758
759
|
// Persist collapse state to localStorage and cookie
|
|
759
760
|
React.useEffect(() => {
|
|
@@ -932,18 +933,18 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
932
933
|
) : null}
|
|
933
934
|
<div className="flex flex-1 flex-col gap-3 pr-1">
|
|
934
935
|
<div className="space-y-3">
|
|
935
|
-
<div className="h-8 rounded bg-muted/
|
|
936
|
+
<div className="h-8 rounded bg-muted/50" />
|
|
936
937
|
<div className="space-y-2 pl-1">
|
|
937
938
|
<div className="h-8 rounded bg-muted/50" />
|
|
938
|
-
<div className="h-8 rounded bg-muted/
|
|
939
|
-
<div className="h-8 rounded bg-muted/
|
|
939
|
+
<div className="h-8 rounded bg-muted/50" />
|
|
940
|
+
<div className="h-8 rounded bg-muted/50" />
|
|
940
941
|
</div>
|
|
941
942
|
</div>
|
|
942
943
|
<div className="space-y-3">
|
|
943
|
-
<div className="h-8 rounded bg-muted/
|
|
944
|
+
<div className="h-8 rounded bg-muted/50" />
|
|
944
945
|
<div className="space-y-2 pl-1">
|
|
945
|
-
<div className="h-8 rounded bg-muted/
|
|
946
|
-
<div className="h-8 rounded bg-muted/
|
|
946
|
+
<div className="h-8 rounded bg-muted/50" />
|
|
947
|
+
<div className="h-8 rounded bg-muted/50" />
|
|
947
948
|
</div>
|
|
948
949
|
</div>
|
|
949
950
|
</div>
|
|
@@ -1015,11 +1016,9 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
1015
1016
|
>
|
|
1016
1017
|
<span className="text-xs font-medium text-muted-foreground">{placeholder}</span>
|
|
1017
1018
|
<div className="flex items-center gap-2">
|
|
1018
|
-
<
|
|
1019
|
-
type="checkbox"
|
|
1020
|
-
className="h-4 w-4 accent-foreground"
|
|
1019
|
+
<Checkbox
|
|
1021
1020
|
checked={!hidden}
|
|
1022
|
-
|
|
1021
|
+
onCheckedChange={(next) => setItemHidden(itemKey, next !== true)}
|
|
1023
1022
|
disabled={savingPreferences}
|
|
1024
1023
|
aria-label={t('appShell.sidebarCustomizationShowItem')}
|
|
1025
1024
|
title={t('appShell.sidebarCustomizationShowItem')}
|
|
@@ -1029,7 +1028,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
1029
1028
|
onChange={(event) => setItemLabel(itemKey, event.target.value)}
|
|
1030
1029
|
placeholder={placeholder}
|
|
1031
1030
|
disabled={savingPreferences}
|
|
1032
|
-
className="h-8 flex-1 rounded border bg-background px-2 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-
|
|
1031
|
+
className="h-8 flex-1 rounded border bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50"
|
|
1033
1032
|
/>
|
|
1034
1033
|
</div>
|
|
1035
1034
|
{baseItem.children && baseItem.children.length > 0 ? (
|
|
@@ -1044,7 +1043,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
1044
1043
|
|
|
1045
1044
|
const customizationEditor = customizing ? (
|
|
1046
1045
|
customDraft ? (
|
|
1047
|
-
<div className="flex flex-col gap-3 rounded border border-dashed bg-muted/
|
|
1046
|
+
<div className="flex flex-col gap-3 rounded border border-dashed bg-muted/30 p-3">
|
|
1048
1047
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
|
1049
1048
|
<div className="text-sm font-semibold">{t('appShell.sidebarCustomizationHeading')}</div>
|
|
1050
1049
|
<div className="flex items-center gap-2">
|
|
@@ -1076,7 +1075,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
1076
1075
|
</div>
|
|
1077
1076
|
<p className="text-xs text-muted-foreground">{t('appShell.sidebarCustomizationHint', { locale: localeLabel })}</p>
|
|
1078
1077
|
{canApplyToRoles ? (
|
|
1079
|
-
<div className="flex flex-col gap-2 rounded border bg-background/
|
|
1078
|
+
<div className="flex flex-col gap-2 rounded border bg-background/80 p-3 shadow-sm">
|
|
1080
1079
|
<div>
|
|
1081
1080
|
<div className="text-sm font-semibold">{t('appShell.sidebarApplyToRolesTitle')}</div>
|
|
1082
1081
|
<p className="text-xs text-muted-foreground">{t('appShell.sidebarApplyToRolesDescription')}</p>
|
|
@@ -1087,12 +1086,10 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
1087
1086
|
const checked = selectedRoleIds.includes(role.id)
|
|
1088
1087
|
const willClear = role.hasPreference && !checked
|
|
1089
1088
|
return (
|
|
1090
|
-
<label key={role.id} className="flex items-center gap-2 rounded border bg-background px-2 py-1 text-sm shadow-sm">
|
|
1091
|
-
<
|
|
1092
|
-
type="checkbox"
|
|
1093
|
-
className="h-4 w-4 accent-foreground"
|
|
1089
|
+
<label key={role.id} className="flex items-center gap-2 rounded-md border bg-background px-2 py-1 text-sm shadow-sm cursor-pointer">
|
|
1090
|
+
<Checkbox
|
|
1094
1091
|
checked={checked}
|
|
1095
|
-
|
|
1092
|
+
onCheckedChange={() => toggleRoleSelection(role.id)}
|
|
1096
1093
|
disabled={savingPreferences}
|
|
1097
1094
|
/>
|
|
1098
1095
|
<span className="flex-1 truncate">{role.name}</span>
|
|
@@ -1128,7 +1125,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
1128
1125
|
onChange={(event) => setGroupLabel(groupId, event.target.value)}
|
|
1129
1126
|
placeholder={placeholder}
|
|
1130
1127
|
disabled={savingPreferences}
|
|
1131
|
-
className="mt-1 h-8 w-full rounded border bg-background px-2 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-
|
|
1128
|
+
className="mt-1 h-8 w-full rounded border bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50"
|
|
1132
1129
|
/>
|
|
1133
1130
|
</div>
|
|
1134
1131
|
<div className="flex items-center gap-1 self-start">
|
|
@@ -1163,7 +1160,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
1163
1160
|
</div>
|
|
1164
1161
|
</div>
|
|
1165
1162
|
) : (
|
|
1166
|
-
<div className="rounded border border-dashed bg-muted/
|
|
1163
|
+
<div className="rounded border border-dashed bg-muted/30 p-3 text-sm text-muted-foreground">
|
|
1167
1164
|
{t('appShell.sidebarCustomizationLoading')}
|
|
1168
1165
|
</div>
|
|
1169
1166
|
)
|
|
@@ -1320,7 +1317,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
1320
1317
|
})()
|
|
1321
1318
|
)}
|
|
1322
1319
|
</div>
|
|
1323
|
-
<div className="sticky bottom-0 pt-4 border-t bg-background/
|
|
1320
|
+
<div className="sticky bottom-0 pt-4 border-t bg-background/80 backdrop-blur-sm pb-1">
|
|
1324
1321
|
{shouldRenderSidebarInjectionSpots ? (
|
|
1325
1322
|
<InjectionSpot
|
|
1326
1323
|
spotId={BACKEND_SIDEBAR_NAV_FOOTER_INJECTION_SPOT_ID}
|
|
@@ -1440,7 +1437,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
1440
1437
|
<aside className={`${asideClassesBase} ${effectiveCollapsed ? 'px-2' : 'px-3'} hidden lg:block`} style={{ width: asideWidth }}>{renderSidebar(effectiveCollapsed)}</aside>
|
|
1441
1438
|
|
|
1442
1439
|
<div className="flex min-h-svh flex-col min-w-0">
|
|
1443
|
-
<header className="border-b bg-background/
|
|
1440
|
+
<header className="border-b bg-background/80 px-3 lg:px-4 py-2 lg:py-3 flex items-center justify-between gap-2">
|
|
1444
1441
|
<div
|
|
1445
1442
|
data-testid="backend-chrome-ready"
|
|
1446
1443
|
data-ready={isChromeReady ? 'true' : 'false'}
|
|
@@ -1518,8 +1515,8 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
1518
1515
|
)}
|
|
1519
1516
|
</div>
|
|
1520
1517
|
</header>
|
|
1521
|
-
<ProgressTopBar t={t} className="sticky top-0 z-
|
|
1522
|
-
<main className="flex-1 p-4 lg:p-6">
|
|
1518
|
+
<ProgressTopBar t={t} className="sticky top-0 z-sticky" />
|
|
1519
|
+
<main className="flex-1 p-4 lg:p-6 mx-auto w-full max-w-screen-2xl">
|
|
1523
1520
|
<InjectionSpot spotId={BACKEND_LAYOUT_TOP_INJECTION_SPOT_ID} context={injectionContext} />
|
|
1524
1521
|
<FlashMessages />
|
|
1525
1522
|
<PartialIndexBanner />
|
|
@@ -1534,7 +1531,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
1534
1531
|
{children}
|
|
1535
1532
|
<InjectionSpot spotId={BACKEND_LAYOUT_FOOTER_INJECTION_SPOT_ID} context={injectionContext} />
|
|
1536
1533
|
</main>
|
|
1537
|
-
<footer className="border-t bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/
|
|
1534
|
+
<footer className="border-t bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/80 px-4 py-3 flex flex-wrap items-center justify-end gap-4">
|
|
1538
1535
|
{version ? (
|
|
1539
1536
|
<span className="text-xs text-muted-foreground">
|
|
1540
1537
|
{t('appShell.version', { version })}
|
|
@@ -1553,8 +1550,8 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
|
|
|
1553
1550
|
|
|
1554
1551
|
{/* Mobile drawer */}
|
|
1555
1552
|
{mobileOpen && (
|
|
1556
|
-
<div className="lg:hidden fixed inset-0 z-
|
|
1557
|
-
<div className="absolute inset-0 bg-black/
|
|
1553
|
+
<div className="lg:hidden fixed inset-0 z-modal">
|
|
1554
|
+
<div className="absolute inset-0 bg-black/20" onClick={() => setMobileOpen(false)} aria-hidden="true" />
|
|
1558
1555
|
<aside className="absolute left-0 top-0 flex h-full w-[260px] flex-col bg-background border-r overflow-hidden">
|
|
1559
1556
|
<div className="shrink-0 p-3 pb-2 flex items-center justify-between border-b">
|
|
1560
1557
|
<Link href="/backend" className="flex items-center gap-2 text-sm font-semibold" onClick={() => setMobileOpen(false)} aria-label={t('appShell.goToDashboard')}>
|
|
@@ -21,7 +21,7 @@ export function ContextHelp({ title, children, defaultOpen = false, bulb = true,
|
|
|
21
21
|
<Button
|
|
22
22
|
type="button"
|
|
23
23
|
variant="ghost"
|
|
24
|
-
className="w-full justify-start gap-2 px-4 py-3 text-left hover:bg-accent/
|
|
24
|
+
className="w-full justify-start gap-2 px-4 py-3 text-left hover:bg-accent/50"
|
|
25
25
|
aria-expanded={open}
|
|
26
26
|
onClick={() => setOpen(v => !v)}
|
|
27
27
|
>
|
package/src/backend/CrudForm.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import { DndContext, closestCenter, PointerSensor, KeyboardSensor, useSensor, us
|
|
|
7
7
|
import { SortableContext, verticalListSortingStrategy, useSortable, arrayMove } from '@dnd-kit/sortable'
|
|
8
8
|
import { CSS } from '@dnd-kit/utilities'
|
|
9
9
|
import { DataLoader } from '../primitives/DataLoader'
|
|
10
|
+
import { Checkbox } from '../primitives/checkbox'
|
|
10
11
|
import { flash } from './FlashMessages'
|
|
11
12
|
import dynamic from 'next/dynamic'
|
|
12
13
|
import { FormHeader } from './forms/FormHeader'
|
|
@@ -1733,7 +1734,7 @@ export function CrudForm<TValues extends Record<string, unknown>>({
|
|
|
1733
1734
|
const text = t('entities.customFields.empty')
|
|
1734
1735
|
const action = t('entities.customFields.addFirst')
|
|
1735
1736
|
return (
|
|
1736
|
-
<div className="rounded-md border border-dashed border-muted-foreground/50 bg-muted/
|
|
1737
|
+
<div className="rounded-md border border-dashed border-muted-foreground/50 bg-muted/30 px-3 py-4 text-sm text-muted-foreground">
|
|
1737
1738
|
<span>{text} </span>
|
|
1738
1739
|
{customFieldsManageHref ? (
|
|
1739
1740
|
<Link href={customFieldsManageHref} className="font-medium text-primary hover:underline">
|
|
@@ -2773,7 +2774,7 @@ export function CrudForm<TValues extends Record<string, unknown>>({
|
|
|
2773
2774
|
<div className="pointer-events-none select-none opacity-70">
|
|
2774
2775
|
{children}
|
|
2775
2776
|
</div>
|
|
2776
|
-
<div className="absolute inset-0 z-10 flex items-start justify-center rounded-lg bg-background/
|
|
2777
|
+
<div className="absolute inset-0 z-10 flex items-start justify-center rounded-lg bg-background/80 p-4 backdrop-blur-[1px] sm:p-6">
|
|
2777
2778
|
{readOnlyOverlay ?? <div className="rounded-xl border border-border/70 bg-background/95 px-4 py-3 shadow-sm" />}
|
|
2778
2779
|
</div>
|
|
2779
2780
|
</div>
|
|
@@ -3558,7 +3559,7 @@ const HtmlRichTextEditor = React.memo(function HtmlRichTextEditor({ value = '',
|
|
|
3558
3559
|
</div>
|
|
3559
3560
|
<div
|
|
3560
3561
|
ref={ref}
|
|
3561
|
-
className="w-full px-2 py-2 min-h-[100px] sm:min-h-[160px] focus:outline-none prose prose-sm max-w-none"
|
|
3562
|
+
className="w-full px-2 py-2 min-h-[100px] sm:min-h-[160px] focus-visible:outline-none prose prose-sm max-w-none"
|
|
3562
3563
|
contentEditable
|
|
3563
3564
|
suppressContentEditableWarning
|
|
3564
3565
|
onKeyDown={onKeyDown}
|
|
@@ -3725,7 +3726,7 @@ const ListboxMultiSelect = React.memo(function ListboxMultiSelect({
|
|
|
3725
3726
|
className={`w-full justify-start rounded-none font-normal px-3 py-2 ${isSel ? 'bg-muted' : ''}`}
|
|
3726
3727
|
>
|
|
3727
3728
|
<span className="inline-flex items-center gap-2">
|
|
3728
|
-
<
|
|
3729
|
+
<Checkbox checked={isSel} disabled tabIndex={-1} className="pointer-events-none" />
|
|
3729
3730
|
<span>{opt.label}</span>
|
|
3730
3731
|
</span>
|
|
3731
3732
|
</Button>
|
|
@@ -3945,12 +3946,10 @@ const FieldControl = React.memo(function FieldControlImpl({
|
|
|
3945
3946
|
/>
|
|
3946
3947
|
)}
|
|
3947
3948
|
{field.type === 'checkbox' && (
|
|
3948
|
-
<label className="inline-flex items-center gap-2">
|
|
3949
|
-
<
|
|
3950
|
-
type="checkbox"
|
|
3951
|
-
className="size-4"
|
|
3949
|
+
<label className="inline-flex items-center gap-2 cursor-pointer">
|
|
3950
|
+
<Checkbox
|
|
3952
3951
|
checked={value === true}
|
|
3953
|
-
|
|
3952
|
+
onCheckedChange={(next) => setValue(field.id, next === true)}
|
|
3954
3953
|
data-crud-focus-target=""
|
|
3955
3954
|
disabled={disabled}
|
|
3956
3955
|
/>
|
|
@@ -3996,14 +3995,12 @@ const FieldControl = React.memo(function FieldControlImpl({
|
|
|
3996
3995
|
: []
|
|
3997
3996
|
const checked = arr.includes(opt.value)
|
|
3998
3997
|
return (
|
|
3999
|
-
<label key={opt.value} className="inline-flex items-center gap-2">
|
|
4000
|
-
<
|
|
4001
|
-
type="checkbox"
|
|
4002
|
-
className="size-4"
|
|
3998
|
+
<label key={opt.value} className="inline-flex items-center gap-2 cursor-pointer">
|
|
3999
|
+
<Checkbox
|
|
4003
4000
|
checked={checked}
|
|
4004
|
-
|
|
4001
|
+
onCheckedChange={(state) => {
|
|
4005
4002
|
const next = new Set(arr)
|
|
4006
|
-
if (
|
|
4003
|
+
if (state === true) {
|
|
4007
4004
|
next.add(opt.value)
|
|
4008
4005
|
} else {
|
|
4009
4006
|
next.delete(opt.value)
|
|
@@ -3,7 +3,7 @@ import * as React from 'react'
|
|
|
3
3
|
import { useRouter } from 'next/navigation'
|
|
4
4
|
import { useReactTable, getCoreRowModel, getSortedRowModel, flexRender, type ColumnDef, type SortingState, type Column as TableColumn, type VisibilityState, type RowSelectionState } from '@tanstack/react-table'
|
|
5
5
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|
6
|
-
import { RefreshCw, Loader2, SlidersHorizontal, MoreHorizontal, Circle, Filter, ChevronDown, Check } from 'lucide-react'
|
|
6
|
+
import { RefreshCw, Loader2, SlidersHorizontal, MoreHorizontal, Circle, Filter, Columns3, ChevronUp, ChevronDown, ChevronsUpDown, Check } from 'lucide-react'
|
|
7
7
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../primitives/table'
|
|
8
8
|
import { Button } from '../primitives/button'
|
|
9
9
|
import { Checkbox } from '../primitives/checkbox'
|
|
@@ -628,7 +628,6 @@ function ExportMenu({ config, sections }: { config: DataTableExportConfig; secti
|
|
|
628
628
|
<Button
|
|
629
629
|
ref={buttonRef}
|
|
630
630
|
variant="outline"
|
|
631
|
-
size="sm"
|
|
632
631
|
type="button"
|
|
633
632
|
onClick={() => {
|
|
634
633
|
if (disabled) return
|
|
@@ -644,7 +643,7 @@ function ExportMenu({ config, sections }: { config: DataTableExportConfig; secti
|
|
|
644
643
|
<div
|
|
645
644
|
ref={menuRef}
|
|
646
645
|
role="menu"
|
|
647
|
-
className="absolute right-0 mt-2 w-60 rounded-md border bg-background py-2 shadow z-
|
|
646
|
+
className="absolute right-0 mt-2 w-60 rounded-md border bg-background py-2 shadow z-dropdown"
|
|
648
647
|
>
|
|
649
648
|
{sections.map((section, idx) => (
|
|
650
649
|
<div key={section.key} className={idx > 0 ? 'mt-2 border-t pt-3' : ''}>
|
|
@@ -2135,7 +2134,6 @@ export function DataTable<T>({
|
|
|
2135
2134
|
<Button
|
|
2136
2135
|
key={action.id}
|
|
2137
2136
|
type="button"
|
|
2138
|
-
size="sm"
|
|
2139
2137
|
variant="outline"
|
|
2140
2138
|
title={label}
|
|
2141
2139
|
aria-label={label}
|
|
@@ -2154,7 +2152,6 @@ export function DataTable<T>({
|
|
|
2154
2152
|
<Button
|
|
2155
2153
|
key={action.id}
|
|
2156
2154
|
type="button"
|
|
2157
|
-
size="sm"
|
|
2158
2155
|
variant={action.destructive ? 'destructive' : 'outline'}
|
|
2159
2156
|
onClick={() => void runPropBulkAction(action)}
|
|
2160
2157
|
>
|
|
@@ -2308,7 +2305,7 @@ export function DataTable<T>({
|
|
|
2308
2305
|
>
|
|
2309
2306
|
<Filter className="h-4 w-4" />
|
|
2310
2307
|
{advancedFilter.value.conditions.length > 0 ? (
|
|
2311
|
-
<span className="absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-
|
|
2308
|
+
<span className="absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-overline text-primary-foreground">
|
|
2312
2309
|
{advancedFilter.value.conditions.length}
|
|
2313
2310
|
</span>
|
|
2314
2311
|
) : null}
|
|
@@ -2405,10 +2402,12 @@ export function DataTable<T>({
|
|
|
2405
2402
|
>
|
|
2406
2403
|
{flexRender(header.column.columnDef.header, header.getContext())}
|
|
2407
2404
|
{sortable && header.column.getCanSort?.() ? (
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2405
|
+
(() => {
|
|
2406
|
+
const sortState = header.column.getIsSorted()
|
|
2407
|
+
if (sortState === 'asc') return <ChevronUp className="ml-1 size-3.5 shrink-0 text-foreground" aria-hidden="true" />
|
|
2408
|
+
if (sortState === 'desc') return <ChevronDown className="ml-1 size-3.5 shrink-0 text-foreground" aria-hidden="true" />
|
|
2409
|
+
return <ChevronsUpDown className="ml-1 size-3.5 shrink-0 text-muted-foreground/50" aria-hidden="true" />
|
|
2410
|
+
})()
|
|
2412
2411
|
) : null}
|
|
2413
2412
|
</Button>
|
|
2414
2413
|
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
import * as React from 'react'
|
|
3
|
+
import { ListFilter, Search } from 'lucide-react'
|
|
3
4
|
import { Button } from '../primitives/button'
|
|
4
5
|
import { FilterDef, FilterOverlay, FilterValues } from './FilterOverlay'
|
|
5
6
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
@@ -72,22 +73,22 @@ export function FilterBar({
|
|
|
72
73
|
|
|
73
74
|
const containerClass = `flex flex-col ${layout === 'inline' ? 'gap-1 sm:gap-2' : 'gap-2'} w-full`
|
|
74
75
|
const searchInput = onSearchChange ? (
|
|
75
|
-
<div className={`relative w-full sm:w-
|
|
76
|
+
<div className={`relative w-full sm:w-72 lg:w-80 ${searchAlign === 'right' ? 'sm:ml-auto' : ''}`}>
|
|
76
77
|
<input
|
|
77
78
|
value={searchDraft}
|
|
78
79
|
onChange={(e) => setSearchDraft(e.target.value)}
|
|
79
80
|
placeholder={resolvedSearchPlaceholder}
|
|
80
|
-
className="h-9 w-full rounded border pl-8 pr-2 text-sm"
|
|
81
|
+
className="h-9 w-full rounded-md border border-input bg-background pl-8 pr-2 text-sm shadow-xs outline-none transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/50"
|
|
81
82
|
suppressHydrationWarning
|
|
82
83
|
/>
|
|
83
|
-
<
|
|
84
|
+
<Search aria-hidden="true" className="absolute left-2 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
|
|
84
85
|
</div>
|
|
85
86
|
) : null
|
|
86
87
|
const controls = (
|
|
87
88
|
<div className={`flex flex-wrap items-center gap-2 ${searchAlign === 'left' && searchInput ? 'sm:ml-auto' : ''}`}>
|
|
88
89
|
{filters.length > 0 && (
|
|
89
|
-
<Button variant="outline"
|
|
90
|
-
<
|
|
90
|
+
<Button variant="outline" onClick={() => setOpen(true)}>
|
|
91
|
+
<ListFilter aria-hidden="true" className="size-4 opacity-80" />
|
|
91
92
|
{activeCount
|
|
92
93
|
? t('ui.filterBar.filtersWithCount', 'Filters {count}', { count: activeCount })
|
|
93
94
|
: t('ui.filterBar.filters', 'Filters')
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
import * as React from 'react'
|
|
3
3
|
import { Button } from '../primitives/button'
|
|
4
|
+
import { Checkbox } from '../primitives/checkbox'
|
|
4
5
|
import { ComboboxInput } from './inputs/ComboboxInput'
|
|
5
6
|
import { TagsInput, type TagsInputOption } from './inputs/TagsInput'
|
|
6
7
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
@@ -190,8 +191,8 @@ export function FilterOverlay({
|
|
|
190
191
|
return (
|
|
191
192
|
<>
|
|
192
193
|
{open && (
|
|
193
|
-
<div className="fixed inset-0 z-
|
|
194
|
-
<div className="absolute inset-0 bg-black/
|
|
194
|
+
<div className="fixed inset-0 z-modal">
|
|
195
|
+
<div className="absolute inset-0 bg-black/20" onClick={() => onOpenChange(false)} role="presentation" />
|
|
195
196
|
<div className="absolute left-0 top-0 h-full w-full sm:w-[380px] bg-background shadow-xl border-r flex flex-col">
|
|
196
197
|
<div className="flex items-center justify-between p-4 border-b">
|
|
197
198
|
<h2 className="text-base font-semibold">{defaultTitle}</h2>
|
|
@@ -249,15 +250,14 @@ export function FilterOverlay({
|
|
|
249
250
|
const arr: string[] = Array.isArray(values[f.id]) ? values[f.id] : []
|
|
250
251
|
const checked = arr.includes(opt.value)
|
|
251
252
|
return (
|
|
252
|
-
<label key={opt.value} className="inline-flex items-center gap-2">
|
|
253
|
-
<
|
|
254
|
-
type="checkbox"
|
|
253
|
+
<label key={opt.value} className="inline-flex items-center gap-2 cursor-pointer">
|
|
254
|
+
<Checkbox
|
|
255
255
|
checked={checked}
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
if (
|
|
259
|
-
else
|
|
260
|
-
setValue(f.id, Array.from(
|
|
256
|
+
onCheckedChange={(next) => {
|
|
257
|
+
const set = new Set(arr)
|
|
258
|
+
if (next === true) set.add(opt.value)
|
|
259
|
+
else set.delete(opt.value)
|
|
260
|
+
setValue(f.id, Array.from(set))
|
|
261
261
|
}}
|
|
262
262
|
/>
|
|
263
263
|
<span className="text-sm">{opt.label}</span>
|
|
@@ -152,7 +152,7 @@ function FlashMessagesInner() {
|
|
|
152
152
|
const color = colorMap[kind]
|
|
153
153
|
|
|
154
154
|
return (
|
|
155
|
-
<div className="pointer-events-none fixed left-3 right-3 top-3 z-
|
|
155
|
+
<div className="pointer-events-none fixed left-3 right-3 top-3 z-toast sm:left-auto sm:right-4 sm:w-[380px]">
|
|
156
156
|
<div className={`pointer-events-auto rounded px-3 py-2 text-white shadow-md ${color}`}>
|
|
157
157
|
<div className="flex items-center justify-between gap-2">
|
|
158
158
|
<div className="text-sm">{msg}</div>
|
|
@@ -117,7 +117,7 @@ export function JsonBuilder({
|
|
|
117
117
|
} catch { }
|
|
118
118
|
}}
|
|
119
119
|
placeholder='{"key": "value"}'
|
|
120
|
-
className="w-full rounded border px-3 py-2 min-h-[300px] text-sm font-mono focus:outline-none focus:ring-2 focus:ring-
|
|
120
|
+
className="w-full rounded border px-3 py-2 min-h-[300px] text-sm font-mono focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
121
121
|
disabled={disabled}
|
|
122
122
|
/>
|
|
123
123
|
{parseError && (
|
|
@@ -242,7 +242,7 @@ function JsonNode({ data, onChange, onDelete, readOnly, label, isRoot }: JsonNod
|
|
|
242
242
|
<select
|
|
243
243
|
value={type}
|
|
244
244
|
onChange={(e) => handleTypeChange(e.target.value as JsonNodeType)}
|
|
245
|
-
className="text-xs border rounded px-1 py-0.5 bg-muted text-foreground focus:ring-1 focus:ring-
|
|
245
|
+
className="text-xs border rounded px-1 py-0.5 bg-muted text-foreground focus-visible:ring-1 focus-visible:ring-ring"
|
|
246
246
|
>
|
|
247
247
|
<option value="string">String</option>
|
|
248
248
|
<option value="number">Number</option>
|
|
@@ -255,7 +255,7 @@ function JsonNode({ data, onChange, onDelete, readOnly, label, isRoot }: JsonNod
|
|
|
255
255
|
|
|
256
256
|
{type === 'string' && (
|
|
257
257
|
<input
|
|
258
|
-
className="flex-1 min-w-0 sm:min-w-[120px] text-sm border rounded px-2 py-0.5 focus:outline-none focus:border-
|
|
258
|
+
className="flex-1 min-w-0 sm:min-w-[120px] text-sm border rounded px-2 py-0.5 focus-visible:outline-none focus-visible:border-ring"
|
|
259
259
|
value={data}
|
|
260
260
|
onChange={e => onChange(e.target.value)}
|
|
261
261
|
disabled={readOnly}
|
|
@@ -264,7 +264,7 @@ function JsonNode({ data, onChange, onDelete, readOnly, label, isRoot }: JsonNod
|
|
|
264
264
|
{type === 'number' && (
|
|
265
265
|
<input
|
|
266
266
|
type="number"
|
|
267
|
-
className="flex-1 w-full sm:w-[100px] text-sm border rounded px-2 py-0.5 focus:outline-none focus:border-
|
|
267
|
+
className="flex-1 w-full sm:w-[100px] text-sm border rounded px-2 py-0.5 focus-visible:outline-none focus-visible:border-ring"
|
|
268
268
|
value={data}
|
|
269
269
|
onChange={e => onChange(parseFloat(e.target.value) || 0)}
|
|
270
270
|
disabled={readOnly}
|
|
@@ -272,7 +272,7 @@ function JsonNode({ data, onChange, onDelete, readOnly, label, isRoot }: JsonNod
|
|
|
272
272
|
)}
|
|
273
273
|
{type === 'boolean' && (
|
|
274
274
|
<select
|
|
275
|
-
className="flex-1 w-full sm:w-[100px] text-sm border rounded px-2 py-0.5 focus:outline-none focus:border-
|
|
275
|
+
className="flex-1 w-full sm:w-[100px] text-sm border rounded px-2 py-0.5 focus-visible:outline-none focus-visible:border-ring"
|
|
276
276
|
value={String(data)}
|
|
277
277
|
onChange={e => onChange(e.target.value === 'true')}
|
|
278
278
|
disabled={readOnly}
|
|
@@ -310,7 +310,7 @@ function JsonNode({ data, onChange, onDelete, readOnly, label, isRoot }: JsonNod
|
|
|
310
310
|
<div className="pt-2">
|
|
311
311
|
{/* Key Renamer */}
|
|
312
312
|
<input
|
|
313
|
-
className="w-full sm:w-[100px] text-xs font-mono border-b border-transparent hover:border-gray-300 focus:border-
|
|
313
|
+
className="w-full sm:w-[100px] text-xs font-mono border-b border-transparent hover:border-gray-300 focus-visible:border-ring bg-transparent focus-visible:outline-none text-right pr-1"
|
|
314
314
|
value={key}
|
|
315
315
|
onChange={(e) => handleKeyRename(key, e.target.value)}
|
|
316
316
|
disabled={readOnly}
|
|
@@ -46,7 +46,7 @@ const STEP_STYLES: Record<NonNullable<NextStepCalloutStep['state']>, string> = {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
const STATUS_STYLES: Record<NextStepCalloutStatusTone, string> = {
|
|
49
|
-
default: 'border-border bg-background/
|
|
49
|
+
default: 'border-border bg-background/80 text-foreground',
|
|
50
50
|
info: 'border-primary/20 bg-primary/5 text-primary',
|
|
51
51
|
success: 'border-emerald-500/20 bg-emerald-500/5 text-emerald-200',
|
|
52
52
|
warning: 'border-amber-500/20 bg-amber-500/5 text-amber-200',
|
|
@@ -352,8 +352,8 @@ export function PerspectiveSidebar({
|
|
|
352
352
|
const isShare = mode.type === 'share'
|
|
353
353
|
|
|
354
354
|
return (
|
|
355
|
-
<div className="fixed inset-0 z-
|
|
356
|
-
<div className="absolute inset-0 bg-black/
|
|
355
|
+
<div className="fixed inset-0 z-modal">
|
|
356
|
+
<div className="absolute inset-0 bg-black/20" onClick={() => onOpenChange(false)} role="presentation" />
|
|
357
357
|
<div className="fixed right-0 top-0 h-full w-full sm:w-80 bg-background shadow-xl border-l flex flex-col">
|
|
358
358
|
<div className="flex items-center p-4 border-b">
|
|
359
359
|
<Button
|
|
@@ -321,7 +321,7 @@ export function ProfileDropdown({
|
|
|
321
321
|
{open && (
|
|
322
322
|
<div
|
|
323
323
|
ref={menuRef}
|
|
324
|
-
className="absolute right-0 top-full mt-1 w-56 rounded-md border bg-background p-1 shadow-lg z-
|
|
324
|
+
className="absolute right-0 top-full mt-1 w-56 rounded-md border bg-background p-1 shadow-lg z-dropdown"
|
|
325
325
|
role="menu"
|
|
326
326
|
data-testid="profile-dropdown"
|
|
327
327
|
>
|
|
@@ -109,7 +109,7 @@ export function RowActions({ items = [] }: { items?: RowActionItem[] }) {
|
|
|
109
109
|
<div
|
|
110
110
|
ref={menuRef}
|
|
111
111
|
role="menu"
|
|
112
|
-
className="fixed w-44 max-w-[calc(100vw-1rem)] rounded-md border bg-background p-1 shadow focus:outline-none z-
|
|
112
|
+
className="fixed w-44 max-w-[calc(100vw-1rem)] rounded-md border bg-background p-1 shadow focus-visible:outline-none z-dropdown"
|
|
113
113
|
style={{
|
|
114
114
|
top: direction === 'down' ? anchorRect.bottom + 8 : anchorRect.top - 8,
|
|
115
115
|
left: Math.min(anchorRect.right, window.innerWidth - 8),
|
package/src/backend/UserMenu.tsx
CHANGED
|
@@ -88,7 +88,7 @@ export function UserMenu({ email }: { email?: string }) {
|
|
|
88
88
|
<div
|
|
89
89
|
ref={menuRef}
|
|
90
90
|
id="user-menu-dropdown"
|
|
91
|
-
className="absolute right-0 top-full mt-0 w-56 rounded-md border bg-background p-1 shadow z-
|
|
91
|
+
className="absolute right-0 top-full mt-0 w-56 rounded-md border bg-background p-1 shadow z-dropdown"
|
|
92
92
|
role="menu"
|
|
93
93
|
aria-labelledby="user-menu-button"
|
|
94
94
|
tabIndex={-1}
|
|
@@ -102,7 +102,7 @@ export function UserMenu({ email }: { email?: string }) {
|
|
|
102
102
|
<Link
|
|
103
103
|
ref={profileButtonRef}
|
|
104
104
|
href="/backend/profile/change-password"
|
|
105
|
-
className="w-full text-left text-sm px-2 py-1 rounded hover:bg-accent inline-flex items-center gap-2 outline-none focus:outline-none focus-visible:outline-none ring-0 focus:ring-0 focus-visible:ring-0"
|
|
105
|
+
className="w-full text-left text-sm px-2 py-1 rounded hover:bg-accent inline-flex items-center gap-2 outline-none focus-visible:outline-none focus-visible:outline-none ring-0 focus-visible:ring-0 focus-visible:ring-0"
|
|
106
106
|
role="menuitem"
|
|
107
107
|
tabIndex={0}
|
|
108
108
|
onClick={() => setOpen(false)}
|
|
@@ -46,7 +46,7 @@ export function WebhookSetupGuide({
|
|
|
46
46
|
</Button>
|
|
47
47
|
|
|
48
48
|
{isOpen ? (
|
|
49
|
-
<div className="space-y-4 rounded-lg border bg-muted/
|
|
49
|
+
<div className="space-y-4 rounded-lg border bg-muted/30 p-4">
|
|
50
50
|
<div className="space-y-1">
|
|
51
51
|
<div className="flex items-center gap-2">
|
|
52
52
|
<Webhook className="h-4 w-4 text-muted-foreground" />
|
|
@@ -56,16 +56,16 @@ export function WebhookSetupGuide({
|
|
|
56
56
|
</div>
|
|
57
57
|
|
|
58
58
|
<div className="space-y-2">
|
|
59
|
-
<p className="text-
|
|
59
|
+
<p className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
|
|
60
60
|
{t('ui.webhookGuide.dashboardPath', 'Dashboard path')}
|
|
61
61
|
</p>
|
|
62
|
-
<div className="rounded-md border bg-background/
|
|
62
|
+
<div className="rounded-md border bg-background/80 px-3 py-2 text-sm">
|
|
63
63
|
{guide.dashboardPathLabel}
|
|
64
64
|
</div>
|
|
65
65
|
</div>
|
|
66
66
|
|
|
67
67
|
<div className="space-y-2">
|
|
68
|
-
<p className="text-
|
|
68
|
+
<p className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
|
|
69
69
|
{t('ui.webhookGuide.steps', 'Setup steps')}
|
|
70
70
|
</p>
|
|
71
71
|
<ol className="list-decimal space-y-2 pl-5 text-sm text-muted-foreground">
|
|
@@ -76,22 +76,22 @@ export function WebhookSetupGuide({
|
|
|
76
76
|
</div>
|
|
77
77
|
|
|
78
78
|
<div className="space-y-2">
|
|
79
|
-
<p className="text-
|
|
79
|
+
<p className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
|
|
80
80
|
{t('ui.webhookGuide.endpointUrl', 'Webhook endpoint URL')}
|
|
81
81
|
</p>
|
|
82
|
-
<div className="rounded-md border bg-background/
|
|
82
|
+
<div className="rounded-md border bg-background/80 px-3 py-2 font-mono text-xs break-all">
|
|
83
83
|
{endpointUrl}
|
|
84
84
|
</div>
|
|
85
85
|
</div>
|
|
86
86
|
|
|
87
87
|
{guide.events && guide.events.length > 0 ? (
|
|
88
88
|
<div className="space-y-2">
|
|
89
|
-
<p className="text-
|
|
89
|
+
<p className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
|
|
90
90
|
{t('ui.webhookGuide.recommendedEvents', 'Recommended events')}
|
|
91
91
|
</p>
|
|
92
92
|
<div className="flex flex-wrap gap-2">
|
|
93
93
|
{guide.events.map((eventName) => (
|
|
94
|
-
<Badge key={eventName} variant="outline" className="font-mono text-
|
|
94
|
+
<Badge key={eventName} variant="outline" className="font-mono text-overline">
|
|
95
95
|
{eventName}
|
|
96
96
|
</Badge>
|
|
97
97
|
))}
|
|
@@ -101,16 +101,16 @@ export function WebhookSetupGuide({
|
|
|
101
101
|
|
|
102
102
|
{guide.localDevelopment ? (
|
|
103
103
|
<div className="space-y-3">
|
|
104
|
-
<p className="text-
|
|
104
|
+
<p className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
|
|
105
105
|
{t('ui.webhookGuide.localDevelopment', 'Local development')}
|
|
106
106
|
</p>
|
|
107
107
|
{guide.localDevelopment.note ? (
|
|
108
108
|
<p className="text-sm text-muted-foreground">{guide.localDevelopment.note}</p>
|
|
109
109
|
) : null}
|
|
110
|
-
<div className="rounded-md border bg-background/
|
|
110
|
+
<div className="rounded-md border bg-background/80 px-3 py-2 font-mono text-xs">
|
|
111
111
|
{guide.localDevelopment.tunnelCommand}
|
|
112
112
|
</div>
|
|
113
|
-
<div className="rounded-md border bg-background/
|
|
113
|
+
<div className="rounded-md border bg-background/80 px-3 py-2 font-mono text-xs break-all">
|
|
114
114
|
{guide.localDevelopment.publicUrlExample}
|
|
115
115
|
</div>
|
|
116
116
|
</div>
|
|
@@ -46,9 +46,9 @@ function BadgeDelta({ direction, value }: BadgeDeltaProps) {
|
|
|
46
46
|
const baseClasses = 'inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-medium'
|
|
47
47
|
|
|
48
48
|
const directionClasses = {
|
|
49
|
-
up: 'bg-
|
|
50
|
-
down: 'bg-
|
|
51
|
-
unchanged: 'bg-
|
|
49
|
+
up: 'bg-status-success-bg text-status-success-text',
|
|
50
|
+
down: 'bg-status-error-bg text-status-error-text',
|
|
51
|
+
unchanged: 'bg-status-neutral-bg text-status-neutral-text',
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
const icons = {
|
|
@@ -276,7 +276,7 @@ export function ColumnChooserPanel({
|
|
|
276
276
|
}, [open])
|
|
277
277
|
if (!open) return null
|
|
278
278
|
return (
|
|
279
|
-
<div className="fixed inset-y-0 right-0 z-
|
|
279
|
+
<div className="fixed inset-y-0 right-0 z-modal w-80 border-l bg-background shadow-lg flex flex-col">
|
|
280
280
|
<div className="flex items-center justify-between border-b px-4 py-3">
|
|
281
281
|
<h3 className="font-semibold text-sm">
|
|
282
282
|
{t('ui.columnChooser.title', 'Columns')}
|