@carlonicora/nextjs-jsonapi 3.3.9 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BlockNoteEditor-BYMRWUVG.mjs → BlockNoteEditor-3D5D7YL7.mjs} +2 -2
- package/dist/{BlockNoteEditor-USRMFZGP.js → BlockNoteEditor-F6TGKMTW.js} +9 -9
- package/dist/{BlockNoteEditor-USRMFZGP.js.map → BlockNoteEditor-F6TGKMTW.js.map} +1 -1
- package/dist/billing/index.js +347 -347
- package/dist/billing/index.js.map +1 -1
- package/dist/billing/index.mjs +27 -27
- package/dist/billing/index.mjs.map +1 -1
- package/dist/{chunk-CFZW6GU4.mjs → chunk-G5LSXG5K.mjs} +2572 -2482
- package/dist/chunk-G5LSXG5K.mjs.map +1 -0
- package/dist/{chunk-5WFYQE22.js → chunk-KT4CTWCV.js} +825 -735
- package/dist/chunk-KT4CTWCV.js.map +1 -0
- package/dist/client/index.d.mts +5 -0
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.js +2 -2
- package/dist/client/index.mjs +1 -1
- package/dist/components/index.d.mts +13 -7
- package/dist/components/index.d.ts +13 -7
- package/dist/components/index.js +2 -2
- package/dist/components/index.mjs +1 -1
- package/dist/contexts/index.d.mts +13 -1
- package/dist/contexts/index.d.ts +13 -1
- package/dist/contexts/index.js +6 -2
- package/dist/contexts/index.js.map +1 -1
- package/dist/contexts/index.mjs +5 -1
- package/dist/features/help/index.js +35 -35
- package/dist/features/help/index.js.map +1 -1
- package/dist/features/help/index.mjs +6 -6
- package/dist/features/help/index.mjs.map +1 -1
- package/dist/features/tokenusage/index.js +135 -129
- package/dist/features/tokenusage/index.js.map +1 -1
- package/dist/features/tokenusage/index.mjs +74 -68
- package/dist/features/tokenusage/index.mjs.map +1 -1
- package/package.json +35 -35
- package/scripts/check-rtl-classes.mjs +60 -0
- package/scripts/check-rtl-classes.test.ts +25 -0
- package/src/components/TableCellAvatar.tsx +1 -1
- package/src/components/containers/PageContainer.tsx +1 -1
- package/src/components/containers/ReactMarkdownContainer.tsx +20 -4
- package/src/components/containers/RoundPageContainer.tsx +7 -7
- package/src/components/contents/AttributeElement.tsx +1 -1
- package/src/components/editors/BlockNoteDiffInlineContent.tsx +2 -2
- package/src/components/editors/BlockNoteEditorMentionHoverCard.tsx +1 -0
- package/src/components/forms/CommonDeleter.tsx +1 -1
- package/src/components/forms/CommonEditorButtons.tsx +1 -1
- package/src/components/forms/DatePickerPopover.tsx +2 -2
- package/src/components/forms/DateRangeSelector.tsx +2 -2
- package/src/components/forms/EditorSheet.tsx +18 -9
- package/src/components/forms/EntityMultiSelector.tsx +7 -7
- package/src/components/forms/EntitySelector.tsx +8 -8
- package/src/components/forms/FileUploader.tsx +1 -0
- package/src/components/forms/FormCheckbox.tsx +3 -3
- package/src/components/forms/FormDateTime.tsx +3 -3
- package/src/components/forms/FormFieldWrapper.tsx +1 -1
- package/src/components/forms/FormPlaceAutocomplete.tsx +2 -2
- package/src/components/forms/GdprConsentCheckbox.tsx +1 -1
- package/src/components/forms/MultiFileUploader.tsx +1 -1
- package/src/components/forms/PasswordInput.tsx +1 -1
- package/src/components/forms/__tests__/FormCheckbox.test.tsx +4 -4
- package/src/components/navigations/Header.tsx +2 -2
- package/src/components/navigations/PageSection.tsx +1 -1
- package/src/components/pages/PageContainerContentDetails.tsx +1 -1
- package/src/components/pages/PageContentContainer.tsx +5 -2
- package/src/components/tables/ContentListTable.tsx +4 -4
- package/src/components/tables/ContentTableSearch.tsx +5 -5
- package/src/contexts/DirectionContext.tsx +25 -0
- package/src/contexts/__tests__/DirectionContext.test.tsx +22 -0
- package/src/contexts/index.ts +1 -0
- package/src/features/ai-connection/components/lists/AiConnectionTypeCard.tsx +1 -1
- package/src/features/assistant/components/containers/AssistantPageContainer.tsx +1 -1
- package/src/features/assistant/components/parts/AssistantBlockNoteComposer.tsx +2 -2
- package/src/features/assistant/components/parts/AssistantComposer.tsx +2 -2
- package/src/features/assistant/components/parts/AssistantEmptyState.tsx +1 -1
- package/src/features/assistant/components/parts/AssistantSidebar.tsx +3 -3
- package/src/features/assistant-action/components/ApprovalActionCard.tsx +1 -1
- package/src/features/assistant-action/components/AssistantContainerWithApprovals.tsx +1 -1
- package/src/features/assistant-message/components/MessageItem.tsx +3 -3
- package/src/features/assistant-message/components/__tests__/MessageItem.spec.tsx +1 -0
- package/src/features/assistant-message/components/parts/MessageSourcesPanel.tsx +2 -2
- package/src/features/assistant-message/components/parts/RelevanceMeter.tsx +1 -1
- package/src/features/assistant-message/components/parts/tabs/SuggestedQuestionsTab.tsx +1 -1
- package/src/features/auth/components/buttons/GoogleSignInButton.tsx +1 -1
- package/src/features/auth/components/forms/Register.tsx +2 -2
- package/src/features/auth/components/two-factor/BackupCodesDialog.tsx +3 -3
- package/src/features/auth/utils/__tests__/clearClientStorage.spec.ts +4 -4
- package/src/features/billing/components/cards/BillingUsageSummaryCard.tsx +1 -1
- package/src/features/billing/components/cards/CustomerInfoCard.tsx +1 -1
- package/src/features/billing/components/cards/InvoicesSummaryCard.tsx +1 -1
- package/src/features/billing/components/cards/PaymentMethodSummaryCard.tsx +1 -1
- package/src/features/billing/components/cards/SubscriptionSummaryCard.tsx +1 -1
- package/src/features/billing/components/containers/BillingDashboardContainer.tsx +1 -1
- package/src/features/billing/stripe-customer/components/details/PaymentMethodCard.tsx +1 -1
- package/src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx +6 -6
- package/src/features/billing/stripe-invoice/components/lists/InvoicesList.tsx +2 -2
- package/src/features/billing/stripe-price/hooks/useStripePriceTableStructure.tsx +3 -3
- package/src/features/billing/stripe-product/hooks/useStripeProductTableStructure.tsx +2 -2
- package/src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx +4 -4
- package/src/features/billing/stripe-subscription/components/widgets/PricingCard.tsx +2 -2
- package/src/features/billing/stripe-subscription/components/widgets/SubscriptionConfirmation.tsx +1 -1
- package/src/features/billing/stripe-subscription/components/wizards/WizardStepReview.tsx +2 -2
- package/src/features/billing/stripe-usage/components/lists/UsageHistoryTable.tsx +2 -2
- package/src/features/company/components/forms/CompanyDeleter.tsx +4 -4
- package/src/features/content/hooks/useContentTableStructure.tsx +1 -1
- package/src/features/feature/components/forms/FormFeatures.tsx +2 -2
- package/src/features/help/components/HelpAssistantSheet.tsx +3 -2
- package/src/features/help/components/HelpHint.tsx +2 -2
- package/src/features/help/components/HelpTOC.tsx +1 -1
- package/src/features/how-to/components/containers/HowToCommand.tsx +2 -2
- package/src/features/how-to/components/containers/HowToCommandViewer.tsx +5 -5
- package/src/features/how-to/components/forms/HowToEditor.tsx +3 -3
- package/src/features/how-to/components/forms/HowToSelector.tsx +5 -5
- package/src/features/notification/components/lists/NotificationsList.tsx +2 -2
- package/src/features/notification/components/modals/NotificationModal.tsx +1 -1
- package/src/features/oauth/components/OAuthClientCard.tsx +2 -2
- package/src/features/oauth/components/OAuthClientDetail.tsx +2 -2
- package/src/features/oauth/components/OAuthClientList.tsx +3 -3
- package/src/features/oauth/components/OAuthRedirectUriInput.tsx +1 -1
- package/src/features/oauth/components/OAuthScopeSelector.tsx +2 -2
- package/src/features/onboarding/components/OnboardingCard.tsx +1 -7
- package/src/features/rbac/components/RbacByRoleContainer.tsx +3 -3
- package/src/features/rbac/components/RbacContainer.tsx +3 -3
- package/src/features/referral/components/ReferralWidget.tsx +1 -0
- package/src/features/role/components/forms/FormRoles.tsx +1 -1
- package/src/features/role/components/forms/RemoveUserFromRole.tsx +1 -1
- package/src/features/role/components/forms/UserRoleAdd.tsx +1 -1
- package/src/features/tokenusage/components/TokenUsageBreakdownTable.tsx +9 -9
- package/src/features/tokenusage/components/TokenUsageRankedBar.tsx +8 -3
- package/src/features/tokenusage/components/TokenUsageTimelineChart.tsx +5 -1
- package/src/features/user/components/details/UserStandaloneDetails.tsx +1 -1
- package/src/features/user/components/forms/UserReactivator.tsx +2 -2
- package/src/features/user/components/forms/UserResentInvitationEmail.tsx +1 -1
- package/src/features/user/components/forms/UserSelector.tsx +7 -7
- package/src/features/user/components/lists/ContributorsList.tsx +1 -1
- package/src/features/user/components/lists/UserListInAdd.tsx +1 -1
- package/src/features/user/components/widgets/UserSearchPopover.tsx +5 -5
- package/src/features/user/hooks/useUserTableStructure.tsx +1 -1
- package/src/features/waitlist/components/forms/WaitlistQuestionnaireRenderer.tsx +1 -1
- package/src/features/waitlist/hooks/useWaitlistTableStructure.tsx +1 -1
- package/src/hooks/useCustomD3Graph.tsx +16 -0
- package/src/lib/__tests__/direction.test.ts +18 -0
- package/src/lib/direction.ts +8 -0
- package/src/shadcnui/custom/multi-select.tsx +6 -6
- package/src/shadcnui/custom/multiple-selector.tsx +6 -2
- package/src/shadcnui/ui/accordion.tsx +1 -1
- package/src/shadcnui/ui/alert-dialog.tsx +2 -1
- package/src/shadcnui/ui/alert.tsx +2 -2
- package/src/shadcnui/ui/avatar.tsx +1 -1
- package/src/shadcnui/ui/badge.tsx +1 -1
- package/src/shadcnui/ui/breadcrumb.tsx +1 -1
- package/src/shadcnui/ui/button.tsx +4 -4
- package/src/shadcnui/ui/calendar.tsx +9 -8
- package/src/shadcnui/ui/carousel.tsx +18 -11
- package/src/shadcnui/ui/combobox.tsx +3 -3
- package/src/shadcnui/ui/command.tsx +2 -2
- package/src/shadcnui/ui/context-menu.tsx +15 -11
- package/src/shadcnui/ui/dialog.tsx +2 -1
- package/src/shadcnui/ui/drawer.tsx +19 -3
- package/src/shadcnui/ui/dropdown-menu.tsx +12 -10
- package/src/shadcnui/ui/field.tsx +2 -2
- package/src/shadcnui/ui/input-group.tsx +3 -3
- package/src/shadcnui/ui/input-otp.tsx +2 -0
- package/src/shadcnui/ui/navigation-menu.tsx +2 -2
- package/src/shadcnui/ui/progress.tsx +1 -1
- package/src/shadcnui/ui/radio-group.tsx +1 -0
- package/src/shadcnui/ui/resizable.tsx +1 -0
- package/src/shadcnui/ui/scroll-area.tsx +1 -1
- package/src/shadcnui/ui/select.tsx +2 -2
- package/src/shadcnui/ui/sheet.tsx +11 -4
- package/src/shadcnui/ui/sidebar.tsx +37 -20
- package/src/shadcnui/ui/sonner.tsx +6 -1
- package/src/shadcnui/ui/switch.tsx +1 -1
- package/src/shadcnui/ui/table.tsx +2 -2
- package/src/shadcnui/ui/tabs.tsx +1 -1
- package/dist/chunk-5WFYQE22.js.map +0 -1
- package/dist/chunk-CFZW6GU4.mjs.map +0 -1
- /package/dist/{BlockNoteEditor-BYMRWUVG.mjs.map → BlockNoteEditor-3D5D7YL7.mjs.map} +0 -0
|
@@ -103,7 +103,7 @@ export function CustomerInfoCard({ customer, loading, error }: CustomerInfoCardP
|
|
|
103
103
|
)}
|
|
104
104
|
<Button variant="outline" size="sm" className="mt-2" onClick={handlePortalClick} disabled={portalLoading}>
|
|
105
105
|
{portalLoading ? "Loading..." : "Manage in Stripe Portal"}
|
|
106
|
-
<ExternalLink className="h-4 w-4
|
|
106
|
+
<ExternalLink className="h-4 w-4 ms-1" />
|
|
107
107
|
</Button>
|
|
108
108
|
</div>
|
|
109
109
|
</CardContent>
|
|
@@ -103,7 +103,7 @@ export function InvoicesSummaryCard({ invoices, loading, error, onViewAllClick }
|
|
|
103
103
|
{openInvoices.length > 0 && <span className="text-warning">{openInvoices.length} open</span>}
|
|
104
104
|
<span className="flex items-center">
|
|
105
105
|
View all
|
|
106
|
-
<ChevronRight className="h-3 w-3
|
|
106
|
+
<ChevronRight className="h-3 w-3 ms-1 rtl:rotate-180" />
|
|
107
107
|
</span>
|
|
108
108
|
</div>
|
|
109
109
|
</div>
|
|
@@ -360,7 +360,7 @@ export function BillingDashboardContainer() {
|
|
|
360
360
|
<Button onClick={handleCreateCustomer} disabled={creatingCustomer} size="lg">
|
|
361
361
|
{creatingCustomer ? (
|
|
362
362
|
<>
|
|
363
|
-
<Loader2 className="
|
|
363
|
+
<Loader2 className="me-2 h-4 w-4 animate-spin" />
|
|
364
364
|
Setting up...
|
|
365
365
|
</>
|
|
366
366
|
) : (
|
|
@@ -91,7 +91,7 @@ export function PaymentMethodCard({ paymentMethod, onUpdate }: PaymentMethodCard
|
|
|
91
91
|
<Card className="relative">
|
|
92
92
|
{/* Default Badge */}
|
|
93
93
|
{isDefault && (
|
|
94
|
-
<Badge variant="softGreen" className="absolute
|
|
94
|
+
<Badge variant="softGreen" className="absolute end-2 top-2">
|
|
95
95
|
Default
|
|
96
96
|
</Badge>
|
|
97
97
|
)}
|
|
@@ -95,14 +95,14 @@ export function InvoiceDetails({
|
|
|
95
95
|
<table className="w-full">
|
|
96
96
|
<thead className="bg-muted">
|
|
97
97
|
<tr>
|
|
98
|
-
<th className="text-
|
|
99
|
-
<th className="text-
|
|
98
|
+
<th className="text-start p-3 text-sm font-medium">Description</th>
|
|
99
|
+
<th className="text-end p-3 text-sm font-medium">Amount</th>
|
|
100
100
|
</tr>
|
|
101
101
|
</thead>
|
|
102
102
|
<tbody>
|
|
103
103
|
<tr className="border-t">
|
|
104
104
|
<td className="p-3">{productName}</td>
|
|
105
|
-
<td className="p-3 text-
|
|
105
|
+
<td className="p-3 text-end">{formatCurrency(invoice.subtotal, invoice.currency)}</td>
|
|
106
106
|
</tr>
|
|
107
107
|
</tbody>
|
|
108
108
|
</table>
|
|
@@ -149,21 +149,21 @@ export function InvoiceDetails({
|
|
|
149
149
|
<div className="flex flex-wrap gap-2 pt-4 border-t">
|
|
150
150
|
{invoice.stripePdfUrl && (
|
|
151
151
|
<Button variant="outline" onClick={handleDownloadPDF}>
|
|
152
|
-
<Download className="
|
|
152
|
+
<Download className="me-2 h-4 w-4" />
|
|
153
153
|
Download PDF
|
|
154
154
|
</Button>
|
|
155
155
|
)}
|
|
156
156
|
|
|
157
157
|
{invoice.status === InvoiceStatus.OPEN && invoice.attempted && (
|
|
158
158
|
<Button variant="default" onClick={handleRetryPayment}>
|
|
159
|
-
<RefreshCw className="
|
|
159
|
+
<RefreshCw className="me-2 h-4 w-4" />
|
|
160
160
|
Retry Payment
|
|
161
161
|
</Button>
|
|
162
162
|
)}
|
|
163
163
|
|
|
164
164
|
{invoice.stripeHostedInvoiceUrl && (
|
|
165
165
|
<Button variant="outline" onClick={handleViewInStripe}>
|
|
166
|
-
<ExternalLink className="
|
|
166
|
+
<ExternalLink className="me-2 h-4 w-4" />
|
|
167
167
|
View in Stripe
|
|
168
168
|
</Button>
|
|
169
169
|
)}
|
|
@@ -36,7 +36,7 @@ export function InvoicesList({ invoices, onInvoicesChange }: InvoicesListProps)
|
|
|
36
36
|
<TableHead>Invoice #</TableHead>
|
|
37
37
|
<TableHead>Date</TableHead>
|
|
38
38
|
<TableHead>Status</TableHead>
|
|
39
|
-
<TableHead className="text-
|
|
39
|
+
<TableHead className="text-end">Amount</TableHead>
|
|
40
40
|
<TableHead>Period</TableHead>
|
|
41
41
|
</TableRow>
|
|
42
42
|
</TableHeader>
|
|
@@ -58,7 +58,7 @@ export function InvoicesList({ invoices, onInvoicesChange }: InvoicesListProps)
|
|
|
58
58
|
<TableCell>
|
|
59
59
|
<InvoiceStatusBadge status={invoice.status} />
|
|
60
60
|
</TableCell>
|
|
61
|
-
<TableCell className="text-
|
|
61
|
+
<TableCell className="text-end font-medium">{amount}</TableCell>
|
|
62
62
|
<TableCell className="text-muted-foreground text-xs">{period}</TableCell>
|
|
63
63
|
</TableRow>
|
|
64
64
|
);
|
|
@@ -49,9 +49,9 @@ export const useStripePriceTableStructure: UseTableStructureHook<StripePriceInte
|
|
|
49
49
|
header: t("billing.admin.prices.fields.amount"),
|
|
50
50
|
cell: ({ row }: { row: TableContent<StripePriceInterface> }) => {
|
|
51
51
|
const price: StripePriceInterface = row.original.jsonApiData;
|
|
52
|
-
// Typography role 15 (numeric): tabular-nums,
|
|
52
|
+
// Typography role 15 (numeric): tabular-nums, end-aligned. NEVER font-mono.
|
|
53
53
|
return (
|
|
54
|
-
<span className="block text-xs tabular-nums text-
|
|
54
|
+
<span className="block text-xs tabular-nums text-end">
|
|
55
55
|
{formatCurrency(price.unitAmount, price.currency)}
|
|
56
56
|
</span>
|
|
57
57
|
);
|
|
@@ -77,7 +77,7 @@ export const useStripePriceTableStructure: UseTableStructureHook<StripePriceInte
|
|
|
77
77
|
header: t("billing.admin.prices.fields.token"),
|
|
78
78
|
cell: ({ row }: { row: TableContent<StripePriceInterface> }) => {
|
|
79
79
|
const price: StripePriceInterface = row.original.jsonApiData;
|
|
80
|
-
return <span className="block text-xs tabular-nums text-
|
|
80
|
+
return <span className="block text-xs tabular-nums text-end">{price.token ?? ""}</span>;
|
|
81
81
|
},
|
|
82
82
|
enableSorting: false,
|
|
83
83
|
enableHiding: false,
|
|
@@ -59,9 +59,9 @@ export const useStripeProductTableStructure: UseTableStructureHook<StripeProduct
|
|
|
59
59
|
header: t("billing.admin.products.fields.prices"),
|
|
60
60
|
cell: ({ row }: { row: TableContent<StripeProductInterface> }) => {
|
|
61
61
|
const product: StripeProductInterface = row.original.jsonApiData;
|
|
62
|
-
// Typography role 15 (numeric): tabular-nums,
|
|
62
|
+
// Typography role 15 (numeric): tabular-nums, end-aligned. NEVER
|
|
63
63
|
// font-mono — no monospace font is loaded in these apps.
|
|
64
|
-
return <span className="block text-xs tabular-nums text-
|
|
64
|
+
return <span className="block text-xs tabular-nums text-end">{product.stripePrices.length}</span>;
|
|
65
65
|
},
|
|
66
66
|
enableSorting: false,
|
|
67
67
|
enableHiding: false,
|
|
@@ -60,8 +60,8 @@ export function SubscriptionsList({ subscriptions, onSubscriptionsChange, onChan
|
|
|
60
60
|
<TableHead>Status</TableHead>
|
|
61
61
|
<TableHead>Plan</TableHead>
|
|
62
62
|
<TableHead>Period</TableHead>
|
|
63
|
-
<TableHead className="text-
|
|
64
|
-
<TableHead className="text-
|
|
63
|
+
<TableHead className="text-end">Amount</TableHead>
|
|
64
|
+
<TableHead className="text-end">Actions</TableHead>
|
|
65
65
|
</TableRow>
|
|
66
66
|
</TableHeader>
|
|
67
67
|
<TableBody>
|
|
@@ -84,8 +84,8 @@ export function SubscriptionsList({ subscriptions, onSubscriptionsChange, onChan
|
|
|
84
84
|
</TableCell>
|
|
85
85
|
<TableCell className="font-medium">{formatPlanName(price)}</TableCell>
|
|
86
86
|
<TableCell className="text-muted-foreground text-sm">{period}</TableCell>
|
|
87
|
-
<TableCell className="text-
|
|
88
|
-
<TableCell className="text-
|
|
87
|
+
<TableCell className="text-end font-medium">{amount}</TableCell>
|
|
88
|
+
<TableCell className="text-end">
|
|
89
89
|
{(subscription.status === SubscriptionStatus.ACTIVE ||
|
|
90
90
|
subscription.status === SubscriptionStatus.TRIALING) &&
|
|
91
91
|
onChangePlan && (
|
|
@@ -61,7 +61,7 @@ export function PricingCard({
|
|
|
61
61
|
)}
|
|
62
62
|
>
|
|
63
63
|
{isCurrentPlan && (
|
|
64
|
-
<Badge variant="secondary" className="absolute top-2
|
|
64
|
+
<Badge variant="secondary" className="absolute top-2 end-2">
|
|
65
65
|
Current
|
|
66
66
|
</Badge>
|
|
67
67
|
)}
|
|
@@ -73,7 +73,7 @@ export function PricingCard({
|
|
|
73
73
|
<CardContent className="pb-4 grow">
|
|
74
74
|
<div className="mb-4">
|
|
75
75
|
<span className="text-3xl font-bold">{formattedPrice}</span>
|
|
76
|
-
<span className="text-muted-foreground
|
|
76
|
+
<span className="text-muted-foreground ms-1">{interval}</span>
|
|
77
77
|
</div>
|
|
78
78
|
|
|
79
79
|
{features.length > 0 && (
|
package/src/features/billing/stripe-subscription/components/widgets/SubscriptionConfirmation.tsx
CHANGED
|
@@ -54,7 +54,7 @@ export function SubscriptionConfirmation({ price, isLoading, onConfirm, onCancel
|
|
|
54
54
|
<Button onClick={onConfirm} disabled={isLoading}>
|
|
55
55
|
{isLoading ? (
|
|
56
56
|
<>
|
|
57
|
-
<Loader2 className="h-4 w-4 animate-spin
|
|
57
|
+
<Loader2 className="h-4 w-4 animate-spin me-2" />
|
|
58
58
|
Processing...
|
|
59
59
|
</>
|
|
60
60
|
) : (
|
|
@@ -127,7 +127,7 @@ export function WizardStepReview({
|
|
|
127
127
|
<p className="font-medium">{selectedPrice.product?.name}</p>
|
|
128
128
|
{selectedPrice.nickname && <p className="text-sm text-muted-foreground">{selectedPrice.nickname}</p>}
|
|
129
129
|
</div>
|
|
130
|
-
<div className="text-
|
|
130
|
+
<div className="text-end">
|
|
131
131
|
{discountedPrice !== null ? (
|
|
132
132
|
<>
|
|
133
133
|
<p className="text-sm text-muted-foreground line-through">
|
|
@@ -168,7 +168,7 @@ export function WizardStepReview({
|
|
|
168
168
|
<span className={`font-medium ${isTrialUpgrade ? "text-warning" : "text-foreground"}`}>
|
|
169
169
|
{discountedImmediateCharge !== null ? (
|
|
170
170
|
<>
|
|
171
|
-
<span className="line-through text-muted-foreground
|
|
171
|
+
<span className="line-through text-muted-foreground me-2">
|
|
172
172
|
{formatCurrency(prorationPreview.immediateCharge, prorationPreview.currency)}
|
|
173
173
|
</span>
|
|
174
174
|
<span className="text-success">
|
|
@@ -47,7 +47,7 @@ export function UsageHistoryTable({ usageRecords }: UsageHistoryTableProps) {
|
|
|
47
47
|
<TableRow>
|
|
48
48
|
<TableHead>Date & Time</TableHead>
|
|
49
49
|
<TableHead>Meter Event</TableHead>
|
|
50
|
-
<TableHead className="text-
|
|
50
|
+
<TableHead className="text-end">Quantity</TableHead>
|
|
51
51
|
<TableHead>Event ID</TableHead>
|
|
52
52
|
</TableRow>
|
|
53
53
|
</TableHeader>
|
|
@@ -60,7 +60,7 @@ export function UsageHistoryTable({ usageRecords }: UsageHistoryTableProps) {
|
|
|
60
60
|
<TableRow key={record.id}>
|
|
61
61
|
<TableCell className="font-medium">{dateTime}</TableCell>
|
|
62
62
|
<TableCell className="text-muted-foreground">{record.meterEventName}</TableCell>
|
|
63
|
-
<TableCell className="text-
|
|
63
|
+
<TableCell className="text-end font-medium">{quantity}</TableCell>
|
|
64
64
|
<TableCell className="text-muted-foreground text-sm tabular-nums">{record.stripeEventId}</TableCell>
|
|
65
65
|
</TableRow>
|
|
66
66
|
);
|
|
@@ -99,7 +99,7 @@ function CompanyDeleterInternal({ company, isAdministrator }: CompanyDeleterInte
|
|
|
99
99
|
<div className="flex w-full flex-col">
|
|
100
100
|
<Label className="flex items-center">
|
|
101
101
|
{t(`company.fields.name.label`)}
|
|
102
|
-
<span className="
|
|
102
|
+
<span className="ms-1 text-destructive">*</span>
|
|
103
103
|
</Label>
|
|
104
104
|
<Input
|
|
105
105
|
className={`w-full`}
|
|
@@ -109,7 +109,7 @@ function CompanyDeleterInternal({ company, isAdministrator }: CompanyDeleterInte
|
|
|
109
109
|
</div>
|
|
110
110
|
</div>
|
|
111
111
|
<div className="flex justify-end">
|
|
112
|
-
<Button className="
|
|
112
|
+
<Button className="me-2" variant={"outline"} type={`button`} onClick={() => setOpen(false)}>
|
|
113
113
|
{t(`ui.buttons.cancel`)}
|
|
114
114
|
</Button>
|
|
115
115
|
<Button
|
|
@@ -136,7 +136,7 @@ function CompanyDeleterInternal({ company, isAdministrator }: CompanyDeleterInte
|
|
|
136
136
|
</AlertDialogHeader>
|
|
137
137
|
<div className="bg-destructive/10 border-destructive text-destructive rounded-md border p-4 text-sm">
|
|
138
138
|
<p className="mb-3 font-semibold">{t(`common.delete.finalWarning.description`)}</p>
|
|
139
|
-
<ul className="list-disc space-y-1
|
|
139
|
+
<ul className="list-disc space-y-1 ps-5">
|
|
140
140
|
<li>{t(`common.delete.finalWarning.bullet1`)}</li>
|
|
141
141
|
<li>{t(`common.delete.finalWarning.bullet2`)}</li>
|
|
142
142
|
<li>{t(`common.delete.finalWarning.bullet3`)}</li>
|
|
@@ -145,7 +145,7 @@ function CompanyDeleterInternal({ company, isAdministrator }: CompanyDeleterInte
|
|
|
145
145
|
</ul>
|
|
146
146
|
</div>
|
|
147
147
|
<div className="flex justify-end">
|
|
148
|
-
<Button className="
|
|
148
|
+
<Button className="me-2" variant={"outline"} type={`button`} onClick={handleGoBack} disabled={isDeleting}>
|
|
149
149
|
{t(`ui.buttons.go_back`)}
|
|
150
150
|
</Button>
|
|
151
151
|
<Button
|
|
@@ -75,7 +75,7 @@ export const useContentTableStructure = <U extends string = ContentFields>(
|
|
|
75
75
|
return (
|
|
76
76
|
<div className="relative flex h-5 w-20 items-center justify-center overflow-clip rounded border text-center">
|
|
77
77
|
<div
|
|
78
|
-
className={`bg-accent absolute top-0
|
|
78
|
+
className={`bg-accent absolute top-0 start-0 h-full opacity-${Math.round(content.relevance)}`}
|
|
79
79
|
style={{ width: `${content.relevance}%` }}
|
|
80
80
|
></div>
|
|
81
81
|
<span
|
|
@@ -37,7 +37,7 @@ export function FormFeatures({ form, name, features, featureField = "featureIds"
|
|
|
37
37
|
</SectionHeader>
|
|
38
38
|
)}
|
|
39
39
|
<ScrollArea className="h-[40vh]">
|
|
40
|
-
<div className="flex flex-col gap-y-2
|
|
40
|
+
<div className="flex flex-col gap-y-2 pe-4">
|
|
41
41
|
{features
|
|
42
42
|
.filter((feature) => !feature.isCore)
|
|
43
43
|
.map((feature) => (
|
|
@@ -49,7 +49,7 @@ export function FormFeatures({ form, name, features, featureField = "featureIds"
|
|
|
49
49
|
toggleFeature(feature, val === true);
|
|
50
50
|
}}
|
|
51
51
|
/>
|
|
52
|
-
<Label htmlFor={feature.id} className="
|
|
52
|
+
<Label htmlFor={feature.id} className="ms-3 cursor-pointer font-normal">
|
|
53
53
|
{feature.name}
|
|
54
54
|
</Label>
|
|
55
55
|
</div>
|
|
@@ -10,8 +10,9 @@ export function HelpAssistantSheet({ open, onOpenChange }: { open: boolean; onOp
|
|
|
10
10
|
return (
|
|
11
11
|
<Sheet open={open} onOpenChange={onOpenChange}>
|
|
12
12
|
<SheetContent
|
|
13
|
-
side="
|
|
14
|
-
|
|
13
|
+
side="end"
|
|
14
|
+
/* rtl-ok: keyed to the resolved physical side ("right" in LTR, "left" in RTL) */
|
|
15
|
+
className="flex w-full flex-col data-[side=right]:sm:max-w-2xl data-[side=right]:lg:max-w-3xl data-[side=left]:sm:max-w-2xl data-[side=left]:lg:max-w-3xl"
|
|
15
16
|
>
|
|
16
17
|
<AssistantProvider manageUrl={false}>
|
|
17
18
|
<HelpAssistantSheetBody />
|
|
@@ -52,7 +52,7 @@ export function HelpHint({ contextKey }: { contextKey: string }) {
|
|
|
52
52
|
<SheetTrigger render={<Button variant="ghost" size="icon-sm" aria-label={t("help.hint.trigger")} />}>
|
|
53
53
|
<HelpCircleIcon className="h-4 w-4" />
|
|
54
54
|
</SheetTrigger>
|
|
55
|
-
<SheetContent side="
|
|
55
|
+
<SheetContent side="end" className="w-full max-w-md sm:max-w-lg">
|
|
56
56
|
<SheetHeader>
|
|
57
57
|
<SheetTitle>{active ? active.name : t("help.hint.pickArticle")}</SheetTitle>
|
|
58
58
|
<SheetDescription>{active?.summary ?? ""}</SheetDescription>
|
|
@@ -71,7 +71,7 @@ export function HelpHint({ contextKey }: { contextKey: string }) {
|
|
|
71
71
|
<button
|
|
72
72
|
type="button"
|
|
73
73
|
onClick={() => setPicked(a)}
|
|
74
|
-
className="hover:bg-muted block w-full rounded px-2 py-1 text-
|
|
74
|
+
className="hover:bg-muted block w-full rounded px-2 py-1 text-start text-sm"
|
|
75
75
|
>
|
|
76
76
|
<div className="font-medium">{a.name}</div>
|
|
77
77
|
<div className="text-muted-foreground text-xs">{a.summary}</div>
|
|
@@ -30,7 +30,7 @@ export function HelpTOC({ headings }: { headings: readonly HelpHeading[] }) {
|
|
|
30
30
|
<MicroLabel className="mb-2">{t("help.toc.title")}</MicroLabel>
|
|
31
31
|
<ul className="space-y-1 text-sm">
|
|
32
32
|
{headings.map((h) => (
|
|
33
|
-
<li key={h.slug} style={{
|
|
33
|
+
<li key={h.slug} style={{ paddingInlineStart: `${(h.depth - 2) * 0.75}rem` }}>
|
|
34
34
|
<a
|
|
35
35
|
href={`#${h.slug}`}
|
|
36
36
|
className={
|
|
@@ -184,7 +184,7 @@ export default function HowToCommand({ pathname, extraGroups, onStartChat }: How
|
|
|
184
184
|
<CommandGroup heading={t(`howto.command.relevant`)}>
|
|
185
185
|
{relevantHowTos.map((howTo: HowToInterface) => (
|
|
186
186
|
<CommandItem key={howTo.id} onSelect={() => setSelectedHowTo(howTo)} className="cursor-pointer">
|
|
187
|
-
<ArrowRight className="h-4 w-4" />
|
|
187
|
+
<ArrowRight className="h-4 w-4 rtl:rotate-180" />
|
|
188
188
|
<span>{howTo.name}</span>
|
|
189
189
|
</CommandItem>
|
|
190
190
|
))}
|
|
@@ -196,7 +196,7 @@ export default function HowToCommand({ pathname, extraGroups, onStartChat }: How
|
|
|
196
196
|
<CommandGroup heading={searchTerm ? undefined : t(`howto.command.all`)}>
|
|
197
197
|
{otherHowTos.map((howTo: HowToInterface) => (
|
|
198
198
|
<CommandItem key={howTo.id} onSelect={() => setSelectedHowTo(howTo)} className="cursor-pointer">
|
|
199
|
-
<ArrowRight className="h-4 w-4" />
|
|
199
|
+
<ArrowRight className="h-4 w-4 rtl:rotate-180" />
|
|
200
200
|
<span>{howTo.name}</span>
|
|
201
201
|
</CommandItem>
|
|
202
202
|
))}
|
|
@@ -27,8 +27,8 @@ export default function HowToCommandViewer({ howTo, onBack, onStartChat }: HowTo
|
|
|
27
27
|
{/* Header with back button, title, and reading time */}
|
|
28
28
|
<div className="flex items-center gap-3 border-b px-4 py-3">
|
|
29
29
|
<Button variant="ghost" size="sm" onClick={onBack} className="h-8 px-2">
|
|
30
|
-
<ArrowLeft className="h-4 w-4" />
|
|
31
|
-
<span className="
|
|
30
|
+
<ArrowLeft className="h-4 w-4 rtl:rotate-180" />
|
|
31
|
+
<span className="ms-1">{t("howto.command.back")}</span>
|
|
32
32
|
</Button>
|
|
33
33
|
<SectionHeader level={2} className="flex-1 truncate">
|
|
34
34
|
{howTo.name}
|
|
@@ -43,14 +43,14 @@ export default function HowToCommandViewer({ howTo, onBack, onStartChat }: HowTo
|
|
|
43
43
|
<div className="flex min-h-0 flex-1">
|
|
44
44
|
{/* Left sidebar - table of contents */}
|
|
45
45
|
{headings.length > 0 && (
|
|
46
|
-
<div className="w-50 shrink-0 overflow-y-auto border-
|
|
46
|
+
<div className="w-50 shrink-0 overflow-y-auto border-e p-4">
|
|
47
47
|
<nav className="space-y-1">
|
|
48
48
|
{headings.map((heading) => (
|
|
49
49
|
<a
|
|
50
50
|
key={heading.id}
|
|
51
51
|
href={`#${heading.id}`}
|
|
52
52
|
className="text-muted-foreground hover:text-foreground block truncate text-sm"
|
|
53
|
-
style={{
|
|
53
|
+
style={{ paddingInlineStart: `${(heading.level - 1) * 0.75}rem` }}
|
|
54
54
|
>
|
|
55
55
|
{heading.text}
|
|
56
56
|
</a>
|
|
@@ -69,7 +69,7 @@ export default function HowToCommandViewer({ howTo, onBack, onStartChat }: HowTo
|
|
|
69
69
|
{onStartChat && (
|
|
70
70
|
<div className="flex items-center justify-end gap-2 border-t px-4 py-3">
|
|
71
71
|
<Button onClick={onStartChat} variant="default" size="sm">
|
|
72
|
-
<MessageSquare className="
|
|
72
|
+
<MessageSquare className="me-2 h-4 w-4" />
|
|
73
73
|
{t("howto.command.chat_button")}
|
|
74
74
|
</Button>
|
|
75
75
|
</div>
|
|
@@ -77,11 +77,11 @@ function PageSelector({
|
|
|
77
77
|
<PopoverContent align="start" className="w-(--anchor-width) p-0">
|
|
78
78
|
<Command shouldFilter={false}>
|
|
79
79
|
<div className="relative w-full border-b">
|
|
80
|
-
<SearchIcon className="text-muted-foreground absolute top-2.5
|
|
80
|
+
<SearchIcon className="text-muted-foreground absolute top-2.5 start-2.5 h-4 w-4" />
|
|
81
81
|
<Input
|
|
82
82
|
placeholder={placeholder}
|
|
83
83
|
type="text"
|
|
84
|
-
className="rounded-none border-0
|
|
84
|
+
className="rounded-none border-0 ps-8 focus-visible:ring-0"
|
|
85
85
|
onChange={(e) => setSearch(e.target.value)}
|
|
86
86
|
value={search}
|
|
87
87
|
/>
|
|
@@ -339,7 +339,7 @@ function HowToEditorInternal({
|
|
|
339
339
|
/>
|
|
340
340
|
))}
|
|
341
341
|
<Button type="button" variant="outline" size="sm" onClick={addPage}>
|
|
342
|
-
<PlusIcon className="
|
|
342
|
+
<PlusIcon className="me-2 h-4 w-4" />
|
|
343
343
|
{t(`howto.fields.pages.add`)}
|
|
344
344
|
</Button>
|
|
345
345
|
</div>
|
|
@@ -111,7 +111,7 @@ export default function HowToSelector({
|
|
|
111
111
|
</PopoverTrigger>
|
|
112
112
|
{field.value && (
|
|
113
113
|
<CircleX
|
|
114
|
-
className="text-muted hover:text-destructive
|
|
114
|
+
className="text-muted hover:text-destructive ms-2 h-4 w-4 shrink-0 cursor-pointer"
|
|
115
115
|
onClick={() => setHowTo()}
|
|
116
116
|
/>
|
|
117
117
|
)}
|
|
@@ -119,19 +119,19 @@ export default function HowToSelector({
|
|
|
119
119
|
<PopoverContent align="start" className="w-(--anchor-width)">
|
|
120
120
|
<Command shouldFilter={false}>
|
|
121
121
|
<div className="relative mb-2 w-full">
|
|
122
|
-
<SearchIcon className="text-muted-foreground absolute top-2.5
|
|
122
|
+
<SearchIcon className="text-muted-foreground absolute top-2.5 start-2.5 h-4 w-4" />
|
|
123
123
|
<Input
|
|
124
124
|
placeholder={t(`generic.search.placeholder`, { type: t(`entities.howtos`, { count: 1 }) })}
|
|
125
125
|
type="text"
|
|
126
|
-
className="w-full
|
|
126
|
+
className="w-full pe-8 ps-8"
|
|
127
127
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSearchTerm(e.target.value)}
|
|
128
128
|
value={searchTerm}
|
|
129
129
|
/>
|
|
130
130
|
{isSearching ? (
|
|
131
|
-
<RefreshCwIcon className="text-muted-foreground absolute top-2.5
|
|
131
|
+
<RefreshCwIcon className="text-muted-foreground absolute top-2.5 end-2.5 h-4 w-4 animate-spin" />
|
|
132
132
|
) : searchTermRef.current ? (
|
|
133
133
|
<XIcon
|
|
134
|
-
className={`absolute top-2.5
|
|
134
|
+
className={`absolute top-2.5 end-2.5 h-4 w-4 ${searchTermRef.current ? "cursor-pointer" : "text-muted-foreground"}`}
|
|
135
135
|
onClick={() => {
|
|
136
136
|
setSearchTerm("");
|
|
137
137
|
search("");
|
|
@@ -44,7 +44,7 @@ export function NotificationsList({ archived }: NotificationsListProps) {
|
|
|
44
44
|
<Card key={i}>
|
|
45
45
|
<CardContent className="p-2">
|
|
46
46
|
<div className="flex w-full flex-row items-center">
|
|
47
|
-
<Skeleton className="
|
|
47
|
+
<Skeleton className="me-4 h-8 w-8 rounded-full" />
|
|
48
48
|
<div className="flex-1 space-y-2">
|
|
49
49
|
<Skeleton className="h-4 w-3/4" />
|
|
50
50
|
<Skeleton className="h-3 w-1/2" />
|
|
@@ -108,7 +108,7 @@ export function NotificationsList({ archived }: NotificationsListProps) {
|
|
|
108
108
|
e.stopPropagation();
|
|
109
109
|
archiveNotification(notification);
|
|
110
110
|
}}
|
|
111
|
-
className="text-muted-foreground hover:text-destructive
|
|
111
|
+
className="text-muted-foreground hover:text-destructive ms-2"
|
|
112
112
|
>
|
|
113
113
|
<ArchiveIcon className="h-4 w-4 cursor-pointer" />
|
|
114
114
|
</Button>
|
|
@@ -200,7 +200,7 @@ function NotificationModalContent({ isOpen, setIsOpen }: NotificationModalProps)
|
|
|
200
200
|
{t(`entities.notifications`, { count: 2 })}
|
|
201
201
|
</SidebarMenuButton>
|
|
202
202
|
</PopoverTrigger>
|
|
203
|
-
<PopoverContent className="relative
|
|
203
|
+
<PopoverContent className="relative start-10 w-80 border-0 p-0 shadow-none">
|
|
204
204
|
<Card>
|
|
205
205
|
<CardHeader className="p-4">
|
|
206
206
|
<CardTitle>{t(`entities.notifications`, { count: 2 })}</CardTitle>
|
|
@@ -68,7 +68,7 @@ export function OAuthClientCard({ client, onClick, onEdit, onDelete }: OAuthClie
|
|
|
68
68
|
onEdit();
|
|
69
69
|
}}
|
|
70
70
|
>
|
|
71
|
-
<Pencil className="h-4 w-4
|
|
71
|
+
<Pencil className="h-4 w-4 me-2" />
|
|
72
72
|
Edit
|
|
73
73
|
</DropdownMenuItem>
|
|
74
74
|
)}
|
|
@@ -80,7 +80,7 @@ export function OAuthClientCard({ client, onClick, onEdit, onDelete }: OAuthClie
|
|
|
80
80
|
}}
|
|
81
81
|
className="text-destructive"
|
|
82
82
|
>
|
|
83
|
-
<Trash2 className="h-4 w-4
|
|
83
|
+
<Trash2 className="h-4 w-4 me-2" />
|
|
84
84
|
Delete
|
|
85
85
|
</DropdownMenuItem>
|
|
86
86
|
)}
|
|
@@ -194,13 +194,13 @@ export function OAuthClientDetail({
|
|
|
194
194
|
<div className="flex gap-3 pt-4">
|
|
195
195
|
{onEdit && (
|
|
196
196
|
<Button variant="outline" onClick={onEdit} disabled={isLoading}>
|
|
197
|
-
<Pencil className="h-4 w-4
|
|
197
|
+
<Pencil className="h-4 w-4 me-2" />
|
|
198
198
|
Edit
|
|
199
199
|
</Button>
|
|
200
200
|
)}
|
|
201
201
|
{onDelete && (
|
|
202
202
|
<Button variant="destructive" onClick={() => setShowDeleteConfirm(true)} disabled={isLoading}>
|
|
203
|
-
<Trash2 className="h-4 w-4
|
|
203
|
+
<Trash2 className="h-4 w-4 me-2" />
|
|
204
204
|
Delete
|
|
205
205
|
</Button>
|
|
206
206
|
)}
|
|
@@ -80,7 +80,7 @@ export function OAuthClientList({
|
|
|
80
80
|
<SectionHeader level={2}>{title}</SectionHeader>
|
|
81
81
|
{onCreateClick && (
|
|
82
82
|
<Button onClick={onCreateClick}>
|
|
83
|
-
<Plus className="h-4 w-4
|
|
83
|
+
<Plus className="h-4 w-4 me-2" />
|
|
84
84
|
New App
|
|
85
85
|
</Button>
|
|
86
86
|
)}
|
|
@@ -91,7 +91,7 @@ export function OAuthClientList({
|
|
|
91
91
|
<p className="text-muted-foreground mb-4">{emptyStateMessage}</p>
|
|
92
92
|
{onCreateClick && (
|
|
93
93
|
<Button onClick={onCreateClick}>
|
|
94
|
-
<Plus className="h-4 w-4
|
|
94
|
+
<Plus className="h-4 w-4 me-2" />
|
|
95
95
|
Create Application
|
|
96
96
|
</Button>
|
|
97
97
|
)}
|
|
@@ -107,7 +107,7 @@ export function OAuthClientList({
|
|
|
107
107
|
<SectionHeader level={2}>{title}</SectionHeader>
|
|
108
108
|
{onCreateClick && (
|
|
109
109
|
<Button onClick={onCreateClick}>
|
|
110
|
-
<Plus className="h-4 w-4
|
|
110
|
+
<Plus className="h-4 w-4 me-2" />
|
|
111
111
|
New App
|
|
112
112
|
</Button>
|
|
113
113
|
)}
|
|
@@ -135,7 +135,7 @@ export function OAuthRedirectUriInput({
|
|
|
135
135
|
</div>
|
|
136
136
|
|
|
137
137
|
<Button type="button" variant="outline" size="sm" onClick={handleAdd} disabled={disabled} className="mt-2">
|
|
138
|
-
<Plus className="h-4 w-4
|
|
138
|
+
<Plus className="h-4 w-4 me-2" />
|
|
139
139
|
Add Redirect URI
|
|
140
140
|
</Button>
|
|
141
141
|
|
|
@@ -78,7 +78,7 @@ export function OAuthScopeSelector({
|
|
|
78
78
|
{Object.entries(groupedScopes).map(([groupName, scopes]) => (
|
|
79
79
|
<div key={groupName} className="space-y-2">
|
|
80
80
|
<h4 className="text-sm font-medium capitalize">{groupName}</h4>
|
|
81
|
-
<div className="grid grid-cols-1 md:grid-cols-2 gap-2
|
|
81
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 ps-2">
|
|
82
82
|
{scopes.map((scopeInfo) => {
|
|
83
83
|
const isChecked = value.includes(scopeInfo.scope);
|
|
84
84
|
const isAdmin = scopeInfo.scope === "admin";
|
|
@@ -99,7 +99,7 @@ export function OAuthScopeSelector({
|
|
|
99
99
|
<div className="flex-1">
|
|
100
100
|
<Label htmlFor={`scope-${scopeInfo.scope}`} className="cursor-pointer">
|
|
101
101
|
{scopeInfo.name}
|
|
102
|
-
{isAdmin && <span className="
|
|
102
|
+
{isAdmin && <span className="ms-2 text-xs text-destructive">(Dangerous)</span>}
|
|
103
103
|
</Label>
|
|
104
104
|
<p className="text-xs text-muted-foreground">{scopeInfo.description}</p>
|
|
105
105
|
</div>
|
|
@@ -18,13 +18,7 @@ export function OnboardingCard({
|
|
|
18
18
|
}: OnboardingCardRenderProps) {
|
|
19
19
|
return (
|
|
20
20
|
<Card className="w-[320px] relative" data-shepherd-card>
|
|
21
|
-
<Button
|
|
22
|
-
variant="ghost"
|
|
23
|
-
size="icon"
|
|
24
|
-
className="absolute right-2 top-2"
|
|
25
|
-
onClick={onClose}
|
|
26
|
-
aria-label={labels.close}
|
|
27
|
-
>
|
|
21
|
+
<Button variant="ghost" size="icon" className="absolute end-2 top-2" onClick={onClose} aria-label={labels.close}>
|
|
28
22
|
<X className="h-4 w-4" />
|
|
29
23
|
</Button>
|
|
30
24
|
<CardHeader>
|