@carlonicora/nextjs-jsonapi 1.129.1 → 1.130.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.
Files changed (115) hide show
  1. package/dist/{BlockNoteEditor-RG2YQDMQ.js → BlockNoteEditor-AI5C4PBZ.js} +11 -11
  2. package/dist/BlockNoteEditor-AI5C4PBZ.js.map +1 -0
  3. package/dist/{BlockNoteEditor-WIAQJ5HM.mjs → BlockNoteEditor-KARBUMFE.mjs} +4 -4
  4. package/dist/BlockNoteEditor-KARBUMFE.mjs.map +1 -0
  5. package/dist/billing/index.js +398 -389
  6. package/dist/billing/index.js.map +1 -1
  7. package/dist/billing/index.mjs +131 -122
  8. package/dist/billing/index.mjs.map +1 -1
  9. package/dist/{chunk-YQTMNZQB.js → chunk-BHZVFSDR.js} +158 -89
  10. package/dist/chunk-BHZVFSDR.js.map +1 -0
  11. package/dist/{chunk-F54XZKPY.mjs → chunk-NXHNJCY2.mjs} +2119 -2050
  12. package/dist/chunk-NXHNJCY2.mjs.map +1 -0
  13. package/dist/client/index.js +2 -2
  14. package/dist/client/index.mjs +1 -1
  15. package/dist/components/index.d.mts +20 -2
  16. package/dist/components/index.d.ts +20 -2
  17. package/dist/components/index.js +8 -2
  18. package/dist/components/index.js.map +1 -1
  19. package/dist/components/index.mjs +7 -1
  20. package/dist/contexts/index.js +2 -2
  21. package/dist/contexts/index.mjs +1 -1
  22. package/dist/features/help/index.js +32 -31
  23. package/dist/features/help/index.js.map +1 -1
  24. package/dist/features/help/index.mjs +3 -2
  25. package/dist/features/help/index.mjs.map +1 -1
  26. package/package.json +1 -1
  27. package/src/components/containers/ReactMarkdownContainer.tsx +2 -2
  28. package/src/components/editors/BlockNoteDiffInlineContent.tsx +10 -10
  29. package/src/components/editors/BlockNoteEditor.tsx +2 -2
  30. package/src/components/forms/FormCheckbox.tsx +2 -2
  31. package/src/components/forms/FormFieldWrapper.tsx +1 -1
  32. package/src/components/forms/FormSlider.tsx +1 -1
  33. package/src/components/forms/GdprConsentCheckbox.tsx +1 -1
  34. package/src/components/hero/EntitySection.tsx +2 -1
  35. package/src/components/index.ts +1 -0
  36. package/src/components/typography/DetailField.tsx +35 -0
  37. package/src/components/typography/MicroLabel.tsx +21 -0
  38. package/src/components/typography/SectionHeader.tsx +18 -0
  39. package/src/components/typography/index.ts +6 -0
  40. package/src/features/assistant/components/parts/AssistantEmptyState.tsx +2 -1
  41. package/src/features/assistant/components/parts/AssistantSidebar.tsx +2 -1
  42. package/src/features/auth/components/buttons/GoogleSignInButton.tsx +1 -1
  43. package/src/features/auth/components/forms/Register.tsx +1 -1
  44. package/src/features/auth/components/forms/TwoFactorChallenge.tsx +3 -3
  45. package/src/features/auth/components/two-factor/BackupCodesDialog.tsx +1 -1
  46. package/src/features/auth/components/two-factor/TotpInput.tsx +2 -2
  47. package/src/features/auth/components/two-factor/TwoFactorSettings.tsx +3 -3
  48. package/src/features/billing/components/cards/BillingUsageSummaryCard.tsx +4 -4
  49. package/src/features/billing/components/cards/CustomerInfoCard.tsx +6 -6
  50. package/src/features/billing/components/cards/InvoicesSummaryCard.tsx +5 -5
  51. package/src/features/billing/components/cards/PaymentMethodSummaryCard.tsx +4 -4
  52. package/src/features/billing/components/cards/SubscriptionSummaryCard.tsx +4 -4
  53. package/src/features/billing/components/containers/BillingDashboardContainer.tsx +2 -2
  54. package/src/features/billing/components/widgets/BillingAlertBanner.tsx +8 -8
  55. package/src/features/billing/stripe-customer/components/containers/PaymentMethodsContainer.tsx +2 -2
  56. package/src/features/billing/stripe-customer/components/details/PaymentMethodCard.tsx +8 -2
  57. package/src/features/billing/stripe-customer/components/forms/PaymentMethodForm.tsx +1 -1
  58. package/src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx +16 -18
  59. package/src/features/billing/stripe-invoice/components/lists/InvoicesList.tsx +2 -2
  60. package/src/features/billing/stripe-invoice/components/widgets/InvoiceStatusBadge.tsx +8 -7
  61. package/src/features/billing/stripe-price/components/lists/PricesList.tsx +6 -13
  62. package/src/features/billing/stripe-product/components/containers/ProductsAdminContainer.tsx +3 -3
  63. package/src/features/billing/stripe-product/components/lists/ProductsList.tsx +4 -7
  64. package/src/features/billing/stripe-promotion-code/components/PromoCodeInput.tsx +6 -6
  65. package/src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx +2 -2
  66. package/src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx +10 -10
  67. package/src/features/billing/stripe-subscription/components/widgets/PricingCard.tsx +2 -2
  68. package/src/features/billing/stripe-subscription/components/widgets/ProductPricingRow.tsx +2 -1
  69. package/src/features/billing/stripe-subscription/components/widgets/ProrationPreview.tsx +1 -1
  70. package/src/features/billing/stripe-subscription/components/widgets/SubscriptionStatusBadge.tsx +12 -11
  71. package/src/features/billing/stripe-subscription/components/wizards/WizardStepPaymentMethod.tsx +2 -1
  72. package/src/features/billing/stripe-subscription/components/wizards/WizardStepReview.tsx +10 -13
  73. package/src/features/billing/stripe-usage/components/containers/UsageContainer.tsx +2 -2
  74. package/src/features/billing/stripe-usage/components/details/UsageSummaryCard.tsx +6 -6
  75. package/src/features/billing/stripe-usage/components/lists/UsageHistoryTable.tsx +3 -2
  76. package/src/features/company/components/details/CompanyContent.tsx +4 -7
  77. package/src/features/company/components/details/TokenStatusIndicator.tsx +5 -5
  78. package/src/features/company/components/forms/CompanyDeleter.tsx +1 -1
  79. package/src/features/company/components/forms/CompanyEditor.tsx +3 -2
  80. package/src/features/content/components/lists/ContentsList.tsx +2 -1
  81. package/src/features/feature/components/forms/FormFeatures.tsx +6 -1
  82. package/src/features/help/components/HelpTOC.tsx +2 -3
  83. package/src/features/how-to/components/containers/HowToCommand.tsx +3 -3
  84. package/src/features/how-to/components/containers/HowToCommandViewer.tsx +4 -1
  85. package/src/features/notification/components/containers/NotificationsListContainer.tsx +1 -1
  86. package/src/features/notification/components/modals/NotificationModal.tsx +2 -2
  87. package/src/features/oauth/components/OAuthClientCard.tsx +1 -1
  88. package/src/features/oauth/components/OAuthClientDetail.tsx +5 -9
  89. package/src/features/oauth/components/OAuthClientForm.tsx +3 -3
  90. package/src/features/oauth/components/OAuthClientList.tsx +5 -4
  91. package/src/features/oauth/components/OAuthClientSecretDisplay.tsx +3 -3
  92. package/src/features/oauth/components/OAuthRedirectUriInput.tsx +1 -1
  93. package/src/features/oauth/components/OAuthScopeSelector.tsx +2 -2
  94. package/src/features/oauth/components/consent/OAuthConsentHeader.tsx +1 -1
  95. package/src/features/oauth/components/consent/OAuthConsentScreen.tsx +1 -1
  96. package/src/features/oauth/components/consent/OAuthScopeList.tsx +2 -3
  97. package/src/features/rbac/components/RbacContainer.tsx +1 -1
  98. package/src/features/rbac/components/RbacPermissionCell.tsx +2 -2
  99. package/src/features/rbac/components/RbacPermissionPicker.tsx +3 -3
  100. package/src/features/referral/components/ReferralWidget.tsx +7 -6
  101. package/src/features/waitlist/components/forms/WaitlistForm.tsx +3 -2
  102. package/src/features/waitlist/components/forms/WaitlistQuestionnaireRenderer.tsx +1 -1
  103. package/src/features/waitlist/components/lists/WaitlistList.tsx +2 -1
  104. package/src/features/waitlist/components/sections/WaitlistConfirmation.tsx +3 -2
  105. package/src/features/waitlist/components/sections/WaitlistSuccessState.tsx +2 -1
  106. package/src/features/waitlist/hooks/useWaitlistTableStructure.tsx +1 -1
  107. package/src/shadcnui/custom/link.tsx +7 -1
  108. package/src/shadcnui/ui/alert.tsx +1 -1
  109. package/src/shadcnui/ui/badge.tsx +7 -0
  110. package/src/shadcnui/ui/button.tsx +1 -1
  111. package/src/shadcnui/ui/chart.tsx +1 -3
  112. package/dist/BlockNoteEditor-RG2YQDMQ.js.map +0 -1
  113. package/dist/BlockNoteEditor-WIAQJ5HM.mjs.map +0 -1
  114. package/dist/chunk-F54XZKPY.mjs.map +0 -1
  115. package/dist/chunk-YQTMNZQB.js.map +0 -1
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
 
3
3
  import { AlertCircle } from "lucide-react";
4
- import { Alert, AlertDescription, Button } from "../../../../../shadcnui";
4
+ import { Alert, AlertDescription, Badge, Button } from "../../../../../shadcnui";
5
+ import { SectionHeader } from "../../../../../components/typography";
5
6
  import { formatCurrency } from "../../../components/utils/currency";
6
7
  import { StripePriceInterface } from "../../../stripe-price/data/stripe-price.interface";
7
8
  import { ProrationPreviewInterface } from "../../../stripe-invoice/data/stripe-invoice.interface";
@@ -120,7 +121,7 @@ export function WizardStepReview({
120
121
  <div className="space-y-6">
121
122
  {/* Selected Plan Summary */}
122
123
  <div className="bg-muted/50 rounded-lg p-4 space-y-3">
123
- <h3 className="font-semibold text-lg">Selected Plan</h3>
124
+ <SectionHeader>Selected Plan</SectionHeader>
124
125
  <div className="flex justify-between items-center">
125
126
  <div>
126
127
  <p className="font-medium">{selectedPrice.product?.name}</p>
@@ -132,14 +133,10 @@ export function WizardStepReview({
132
133
  <p className="text-sm text-muted-foreground line-through">
133
134
  {formatCurrency(selectedPrice.unitAmount || 0, selectedPrice.currency)}
134
135
  </p>
135
- <p className="font-semibold text-lg text-green-600">
136
+ <p className="text-success text-lg font-semibold">
136
137
  {formatCurrency(discountedPrice, selectedPrice.currency)}
137
138
  </p>
138
- {discountDescription && (
139
- <span className="inline-block text-xs bg-green-100 text-green-700 px-2 py-0.5 rounded-full">
140
- {discountDescription}
141
- </span>
142
- )}
139
+ {discountDescription && <Badge variant="softGreen">{discountDescription}</Badge>}
143
140
  </>
144
141
  ) : (
145
142
  <p className="font-semibold text-lg">
@@ -156,25 +153,25 @@ export function WizardStepReview({
156
153
  <div
157
154
  className={`${isTrialUpgrade ? "bg-amber-50 border-amber-200" : "bg-blue-50 border-blue-200"} border rounded-lg p-4 space-y-2`}
158
155
  >
159
- <h4 className={`font-medium ${isTrialUpgrade ? "text-amber-800" : "text-blue-800"}`}>
156
+ <h4 className={`font-medium ${isTrialUpgrade ? "text-warning" : "text-blue-800"}`}>
160
157
  {isTrialUpgrade ? "Trial Upgrade" : "Proration Summary"}
161
158
  </h4>
162
- <p className={`text-sm ${isTrialUpgrade ? "text-amber-700" : "text-blue-700"}`}>
159
+ <p className={`text-sm ${isTrialUpgrade ? "text-warning" : "text-blue-700"}`}>
163
160
  {isTrialUpgrade
164
161
  ? "Your trial will end immediately and you will be charged the full price."
165
162
  : "Your next charge will be adjusted to account for the plan change."}
166
163
  </p>
167
164
  <div className="flex justify-between text-sm">
168
- <span className={`${isTrialUpgrade ? "text-amber-600" : "text-blue-600"}`}>
165
+ <span className={`${isTrialUpgrade ? "text-warning" : "text-blue-600"}`}>
169
166
  {isTrialUpgrade ? "Amount to charge now:" : "Amount due now:"}
170
167
  </span>
171
- <span className={`font-medium ${isTrialUpgrade ? "text-amber-800" : "text-blue-800"}`}>
168
+ <span className={`font-medium ${isTrialUpgrade ? "text-warning" : "text-blue-800"}`}>
172
169
  {discountedImmediateCharge !== null ? (
173
170
  <>
174
171
  <span className="line-through text-muted-foreground mr-2">
175
172
  {formatCurrency(prorationPreview.immediateCharge, prorationPreview.currency)}
176
173
  </span>
177
- <span className="text-green-600">
174
+ <span className="text-success">
178
175
  {formatCurrency(discountedImmediateCharge, prorationPreview.currency)}
179
176
  </span>
180
177
  </>
@@ -86,7 +86,7 @@ export function UsageContainer() {
86
86
  {/* Header */}
87
87
  <div className="flex items-center gap-x-3">
88
88
  <Activity className="h-8 w-8" />
89
- <h1 className="text-3xl font-bold">Usage Tracking</h1>
89
+ <h1 className="text-primary text-3xl font-semibold">Usage Tracking</h1>
90
90
  </div>
91
91
 
92
92
  {/* Empty State */}
@@ -94,7 +94,7 @@ export function UsageContainer() {
94
94
  <div className="bg-muted/50 flex flex-col items-center justify-center gap-y-4 rounded-lg border-2 border-dashed border-gray-300 p-12">
95
95
  <Activity className="text-muted-foreground h-16 w-16" />
96
96
  <div className="text-center">
97
- <h3 className="mb-2 text-xl font-semibold">No usage meters configured</h3>
97
+ <h3 className="mb-2 text-sm font-medium">No usage meters configured</h3>
98
98
  <p className="text-muted-foreground">
99
99
  Usage tracking will appear here when you have metered subscriptions with configured meters.
100
100
  </p>
@@ -52,8 +52,8 @@ export function UsageSummaryCard({ meter, summary }: UsageSummaryCardProps) {
52
52
  <Activity className="h-5 w-5" />
53
53
  </div>
54
54
  <div className="flex flex-col">
55
- <h3 className="font-semibold">{displayName}</h3>
56
- <p className="text-xs text-gray-500">{meter.id}</p>
55
+ <h3 className="text-sm font-medium">{displayName}</h3>
56
+ <p className="text-muted-foreground text-xs">{meter.id}</p>
57
57
  </div>
58
58
  </CardHeader>
59
59
 
@@ -61,7 +61,7 @@ export function UsageSummaryCard({ meter, summary }: UsageSummaryCardProps) {
61
61
  {/* Current Usage */}
62
62
  <div>
63
63
  <p className="text-3xl font-bold">{currentUsage.toLocaleString()}</p>
64
- {hasLimit && <p className="text-sm text-gray-500">of {limit.toLocaleString()} used</p>}
64
+ {hasLimit && <p className="text-muted-foreground text-sm">of {limit.toLocaleString()} used</p>}
65
65
  </div>
66
66
 
67
67
  {/* Progress Bar */}
@@ -70,16 +70,16 @@ export function UsageSummaryCard({ meter, summary }: UsageSummaryCardProps) {
70
70
  <div className="h-2 w-full overflow-hidden rounded-full bg-gray-200">
71
71
  <div className={`h-full transition-all ${progressColor}`} style={{ width: `${progressWidth}%` }} />
72
72
  </div>
73
- <p className="text-sm text-gray-500">{percentage?.toFixed(1)}% used</p>
73
+ <p className="text-muted-foreground text-sm">{percentage?.toFixed(1)}% used</p>
74
74
  </div>
75
75
  ) : (
76
- <p className="text-sm text-gray-500">No limit set</p>
76
+ <p className="text-muted-foreground text-sm">No limit set</p>
77
77
  )}
78
78
 
79
79
  {/* Period Information */}
80
80
  {summary && summary.start && summary.end && (
81
81
  <div className="border-t pt-3">
82
- <p className="text-xs text-gray-500">
82
+ <p className="text-muted-foreground text-xs">
83
83
  Period: {formatDate(summary.start)} - {formatDate(summary.end)}
84
84
  </p>
85
85
  </div>
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../../../../../shadcnui";
4
+ import { SectionHeader } from "../../../../../components/typography";
4
5
  import { StripeUsageInterface } from "../../data/stripe-usage.interface";
5
6
 
6
7
  type UsageHistoryTableProps = {
@@ -39,7 +40,7 @@ export function UsageHistoryTable({ usageRecords }: UsageHistoryTableProps) {
39
40
 
40
41
  return (
41
42
  <div className="flex w-full flex-col gap-y-4">
42
- <h2 className="text-xl font-semibold">Usage History</h2>
43
+ <SectionHeader level={2}>Usage History</SectionHeader>
43
44
  <div className="overflow-clip rounded-lg border">
44
45
  <Table>
45
46
  <TableHeader className="bg-muted">
@@ -60,7 +61,7 @@ export function UsageHistoryTable({ usageRecords }: UsageHistoryTableProps) {
60
61
  <TableCell className="font-medium">{dateTime}</TableCell>
61
62
  <TableCell className="text-muted-foreground">{record.meterEventName}</TableCell>
62
63
  <TableCell className="text-right font-medium">{quantity}</TableCell>
63
- <TableCell className="text-muted-foreground text-sm font-mono">{record.stripeEventId}</TableCell>
64
+ <TableCell className="text-muted-foreground text-sm tabular-nums">{record.stripeEventId}</TableCell>
64
65
  </TableRow>
65
66
  );
66
67
  })}
@@ -5,6 +5,7 @@ import { useTranslations } from "next-intl";
5
5
  import Image from "next/image";
6
6
  import { ReactNode } from "react";
7
7
  import { AttributeElement } from "../../../../components";
8
+ import { SectionHeader, MicroLabel } from "../../../../components/typography";
8
9
  import { FiscalDataDisplay } from "../../../../components/fiscal/FiscalDataDisplay";
9
10
  import { CompanyInterface } from "../../data";
10
11
 
@@ -34,7 +35,7 @@ export function CompanyContent({ company, actions }: CompanyContentProps) {
34
35
  <div className="flex flex-col gap-y-8">
35
36
  {/* Title Row */}
36
37
  <div className="flex w-full items-center justify-between">
37
- <h2 className="text-lg font-semibold">{company.name}</h2>
38
+ <SectionHeader level={2}>{company.name}</SectionHeader>
38
39
  {actions && <div className="flex items-center gap-x-2">{actions}</div>}
39
40
  </div>
40
41
 
@@ -70,9 +71,7 @@ export function CompanyContent({ company, actions }: CompanyContentProps) {
70
71
  {/* Fiscal Data Section */}
71
72
  {company.fiscal_data && (
72
73
  <div className="flex flex-col gap-y-3">
73
- <h3 className="text-muted-foreground text-xs font-semibold tracking-wider uppercase">
74
- {t("company.sections.fiscal_data")}
75
- </h3>
74
+ <MicroLabel>{t("company.sections.fiscal_data")}</MicroLabel>
76
75
  <FiscalDataDisplay fiscalData={company.fiscal_data} />
77
76
  </div>
78
77
  )}
@@ -80,9 +79,7 @@ export function CompanyContent({ company, actions }: CompanyContentProps) {
80
79
  {/* Address Details Section */}
81
80
  {hasAddressDetails(company) && (
82
81
  <div className="flex flex-col gap-y-3">
83
- <h3 className="text-muted-foreground text-xs font-semibold tracking-wider uppercase">
84
- {t("company.sections.address_details")}
85
- </h3>
82
+ <MicroLabel>{t("company.sections.address_details")}</MicroLabel>
86
83
  <div className="grid grid-cols-1 gap-4 md:grid-cols-3">
87
84
  {company.street && <AttributeElement title={t("company.fields.street.label")} value={company.street} />}
88
85
  {company.street_number && (
@@ -62,11 +62,11 @@ export function TokenStatusIndicator({ className, size = "md", showExtraPages =
62
62
 
63
63
  const getBatteryIcon = () => {
64
64
  if (percentage > 75) {
65
- return <BatteryFull className={cn(iconSize, "text-green-500")} />;
65
+ return <BatteryFull className={cn(iconSize, "text-success")} />;
66
66
  } else if (percentage > 50) {
67
- return <BatteryMedium className={cn(iconSize, "text-green-500")} />;
67
+ return <BatteryMedium className={cn(iconSize, "text-success")} />;
68
68
  } else if (percentage >= 25) {
69
- return <BatteryLow className={cn(iconSize, "text-yellow-500")} />;
69
+ return <BatteryLow className={cn(iconSize, "text-warning")} />;
70
70
  } else {
71
71
  return <Battery className={cn(iconSize, "text-destructive")} />;
72
72
  }
@@ -74,9 +74,9 @@ export function TokenStatusIndicator({ className, size = "md", showExtraPages =
74
74
 
75
75
  const getStatusColor = () => {
76
76
  if (percentage > 50) {
77
- return "text-green-500";
77
+ return "text-success";
78
78
  } else if (percentage >= 25) {
79
- return "text-yellow-500";
79
+ return "text-warning";
80
80
  } else {
81
81
  return "text-destructive";
82
82
  }
@@ -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="text-destructive ml-2 font-semibold">*</span>
102
+ <span className="ml-1 text-destructive">*</span>
103
103
  </Label>
104
104
  <Input
105
105
  className={`w-full`}
@@ -20,6 +20,7 @@ import {
20
20
  parseFiscalData,
21
21
  } from "../../../../components";
22
22
  import type { FiscalDataHandle } from "../../../../components";
23
+ import { SectionHeader } from "../../../../components/typography";
23
24
  import { Modules } from "../../../../core";
24
25
  import { useI18nRouter } from "../../../../i18n";
25
26
  import { getRoleId } from "../../../../roles";
@@ -223,7 +224,7 @@ function CompanyEditorInternal({
223
224
  <div className="flex w-full items-start justify-between gap-x-4">
224
225
  <div className="flex w-96 flex-col justify-start gap-y-4">
225
226
  <FileUploader value={files} onValueChange={setFiles} dropzoneOptions={dropzone} className="w-full p-4">
226
- <FileInput className="text-neutral-300 outline-dashed">
227
+ <FileInput className="text-muted-foreground/50 outline-dashed">
227
228
  <div className="flex w-full flex-col items-center justify-center pt-3 pb-4">
228
229
  <div className="flex w-full flex-col items-center justify-center pt-3 pb-4">
229
230
  {file || company?.logo ? (
@@ -262,7 +263,7 @@ function CompanyEditorInternal({
262
263
  }
263
264
  }}
264
265
  />
265
- <h3 className="mt-2 text-sm font-semibold">{t(`company.sections.fiscal_data`)}</h3>
266
+ <SectionHeader className="mt-2">{t(`company.sections.fiscal_data`)}</SectionHeader>
266
267
  <ItalianFiscalData ref={fiscalRef} initialData={parseFiscalData(company?.fiscal_data)} />
267
268
  </div>
268
269
  {canAccessFeatures && (
@@ -5,6 +5,7 @@ import { Modules } from "../../../../core";
5
5
  import { usePageUrlGenerator } from "../../../../hooks";
6
6
  import { HoverCard, HoverCardContent, HoverCardTrigger, Link } from "../../../../shadcnui";
7
7
  import { getIconByModule } from "../../../../utils";
8
+ import { SectionHeader } from "../../../../components/typography";
8
9
  import { ContributorsList } from "../../../user/components";
9
10
  import { ContentInterface } from "../../data";
10
11
 
@@ -17,7 +18,7 @@ export function ContentsList({ contentList }: ContentsListProps) {
17
18
 
18
19
  return (
19
20
  <div className="flex min-h-0 w-full flex-col overflow-y-auto">
20
- <h2 className="text-xl font-semibold">{t(`content.news`)}</h2>
21
+ <SectionHeader level={2}>{t(`content.news`)}</SectionHeader>
21
22
  <div className="flex flex-col">
22
23
  {contentList.map((content) => (
23
24
  <ContentsListElement content={content} key={content.id} />
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { Checkbox, Label, ScrollArea } from "../../../../shadcnui";
4
+ import { SectionHeader } from "../../../../components/typography";
4
5
  import { FeatureInterface } from "../../data";
5
6
 
6
7
  type FormFeaturesProps = {
@@ -30,7 +31,11 @@ export function FormFeatures({ form, name, features, featureField = "featureIds"
30
31
 
31
32
  return (
32
33
  <div className="flex w-full flex-col">
33
- {name && <h2 className="mb-4 border-b text-lg font-semibold">{name}</h2>}
34
+ {name && (
35
+ <SectionHeader level={2} className="mb-4 border-b">
36
+ {name}
37
+ </SectionHeader>
38
+ )}
34
39
  <ScrollArea className="h-[40vh]">
35
40
  <div className="flex flex-col gap-y-2 pr-4">
36
41
  {features
@@ -2,6 +2,7 @@
2
2
  import { useEffect, useState } from "react";
3
3
  import { useTranslations } from "next-intl";
4
4
  import type { HelpHeading } from "../types/help-article.types";
5
+ import { MicroLabel } from "../../../components/typography";
5
6
 
6
7
  export function HelpTOC({ headings }: { headings: readonly HelpHeading[] }) {
7
8
  const t = useTranslations();
@@ -26,9 +27,7 @@ export function HelpTOC({ headings }: { headings: readonly HelpHeading[] }) {
26
27
  if (headings.length === 0) return null;
27
28
  return (
28
29
  <nav aria-label={t("help.toc.title")} className="hidden lg:block">
29
- <div className="text-muted-foreground mb-2 text-xs font-semibold tracking-wider uppercase">
30
- {t("help.toc.title")}
31
- </div>
30
+ <MicroLabel className="mb-2">{t("help.toc.title")}</MicroLabel>
32
31
  <ul className="space-y-1 text-sm">
33
32
  {headings.map((h) => (
34
33
  <li key={h.slug} style={{ paddingLeft: `${(h.depth - 2) * 0.75}rem` }}>
@@ -207,15 +207,15 @@ export default function HowToCommand({ pathname, extraGroups, onStartChat }: How
207
207
  {/* Keyboard hints footer */}
208
208
  <div className="text-muted-foreground flex items-center justify-center gap-4 border-t px-3 py-2 text-xs">
209
209
  <span className="flex items-center gap-1">
210
- <kbd className="bg-muted rounded border px-1.5 py-0.5 font-mono text-xs">&#9166;</kbd>
210
+ <kbd className="bg-muted rounded border px-1.5 py-0.5 tabular-nums text-xs">&#9166;</kbd>
211
211
  {t(`howto.command.keyboard.select`)}
212
212
  </span>
213
213
  <span className="flex items-center gap-1">
214
- <kbd className="bg-muted rounded border px-1.5 py-0.5 font-mono text-xs">&#8593;&#8595;</kbd>
214
+ <kbd className="bg-muted rounded border px-1.5 py-0.5 tabular-nums text-xs">&#8593;&#8595;</kbd>
215
215
  {t(`howto.command.keyboard.navigate`)}
216
216
  </span>
217
217
  <span className="flex items-center gap-1">
218
- <kbd className="bg-muted rounded border px-1.5 py-0.5 font-mono text-xs">
218
+ <kbd className="bg-muted rounded border px-1.5 py-0.5 tabular-nums text-xs">
219
219
  {t(`howto.keyboard.esc`)}
220
220
  </kbd>
221
221
  {t(`howto.command.keyboard.close`)}
@@ -6,6 +6,7 @@ import { useMemo } from "react";
6
6
 
7
7
  import { BlockNoteEditorContainer } from "../../../../components";
8
8
  import { Button } from "../../../../shadcnui";
9
+ import { SectionHeader } from "../../../../components/typography";
9
10
  import { HowToInterface } from "../../data/HowToInterface";
10
11
  import { calculateReadingTime, extractHeadings } from "../../utils/blocknote";
11
12
 
@@ -29,7 +30,9 @@ export default function HowToCommandViewer({ howTo, onBack, onStartChat }: HowTo
29
30
  <ArrowLeft className="h-4 w-4" />
30
31
  <span className="ml-1">{t("howto.command.back")}</span>
31
32
  </Button>
32
- <h2 className="flex-1 truncate text-lg font-semibold">{howTo.name}</h2>
33
+ <SectionHeader level={2} className="flex-1 truncate">
34
+ {howTo.name}
35
+ </SectionHeader>
33
36
  <div className="text-muted-foreground flex items-center gap-1.5 text-sm">
34
37
  <BookOpen className="h-4 w-4" />
35
38
  <span>{t("howto.reading_time.label", { minutes: readingTime })}</span>
@@ -13,7 +13,7 @@ function NotificationsListContainerContent() {
13
13
  if (error) {
14
14
  return (
15
15
  <div className="flex items-center justify-center p-8 text-center">
16
- <div className="text-destructive text-sm">
16
+ <div className="text-destructive text-xs/relaxed">
17
17
  <p>Error loading notifications: {error}</p>
18
18
  <p className="text-muted-foreground mt-2">Please try refreshing the page.</p>
19
19
  </div>
@@ -205,7 +205,7 @@ function NotificationModalContent({ isOpen, setIsOpen }: NotificationModalProps)
205
205
  <CardHeader className="p-4">
206
206
  <CardTitle>{t(`entities.notifications`, { count: 2 })}</CardTitle>
207
207
  {isLoading && <div className="text-muted-foreground text-xs">Loading...</div>}
208
- {error && <div className="text-destructive text-xs">Error: {error}</div>}
208
+ {error && <div className="text-destructive text-xs/relaxed">Error: {error}</div>}
209
209
  </CardHeader>
210
210
  <Separator />
211
211
  <ScrollArea className="h-96">
@@ -214,7 +214,7 @@ function NotificationModalContent({ isOpen, setIsOpen }: NotificationModalProps)
214
214
  <Fragment key={notification.id}>{generateNotification(notification, () => setIsOpen(false))}</Fragment>
215
215
  ))
216
216
  ) : (
217
- <div className="p-4 text-center text-sm text-gray-500">{t(`notification.empty`)}</div>
217
+ <div className="text-muted-foreground p-4 text-center text-sm">{t(`notification.empty`)}</div>
218
218
  )}
219
219
  </ScrollArea>
220
220
  </Card>
@@ -93,7 +93,7 @@ export function OAuthClientCard({ client, onClick, onEdit, onDelete }: OAuthClie
93
93
  </CardHeader>
94
94
  <CardContent>
95
95
  <div className="flex flex-wrap gap-x-4 gap-y-1 text-sm text-muted-foreground">
96
- <span className="font-mono">{truncatedId}</span>
96
+ <span className="tabular-nums">{truncatedId}</span>
97
97
  <span>Created {createdAgo}</span>
98
98
  <span>{client.isConfidential ? "Confidential" : "Public"}</span>
99
99
  </div>
@@ -94,7 +94,7 @@ export function OAuthClientDetail({
94
94
  <CardHeader>
95
95
  <div className="flex items-start justify-between">
96
96
  <div>
97
- <CardTitle className="text-2xl">{client.name}</CardTitle>
97
+ <CardTitle>{client.name}</CardTitle>
98
98
  {client.description && <CardDescription className="mt-1">{client.description}</CardDescription>}
99
99
  </div>
100
100
  <div className="flex items-center gap-2">
@@ -110,18 +110,14 @@ export function OAuthClientDetail({
110
110
  <div className="space-y-2">
111
111
  <Label>Client ID</Label>
112
112
  <div className="flex gap-2">
113
- <Input value={client.clientId} readOnly className="font-mono" />
113
+ <Input value={client.clientId} readOnly className="tabular-nums" />
114
114
  <Button
115
115
  variant="outline"
116
116
  size="icon"
117
117
  onClick={() => copyToClipboard(client.clientId, "clientId")}
118
118
  title="Copy Client ID"
119
119
  >
120
- {copiedField === "clientId" ? (
121
- <Check className="h-4 w-4 text-green-600" />
122
- ) : (
123
- <Copy className="h-4 w-4" />
124
- )}
120
+ {copiedField === "clientId" ? <Check className="text-success h-4 w-4" /> : <Copy className="h-4 w-4" />}
125
121
  </Button>
126
122
  </div>
127
123
  </div>
@@ -130,7 +126,7 @@ export function OAuthClientDetail({
130
126
  <div className="space-y-2">
131
127
  <Label>Client Secret</Label>
132
128
  <div className="flex gap-2">
133
- <Input value="••••••••••••••••••••••••••••••••" readOnly className="font-mono" />
129
+ <Input value="••••••••••••••••••••••••••••••••" readOnly className="tabular-nums" />
134
130
  {onRegenerateSecret && (
135
131
  <Button
136
132
  variant="outline"
@@ -155,7 +151,7 @@ export function OAuthClientDetail({
155
151
  <Label>Redirect URIs</Label>
156
152
  <ul className="space-y-1">
157
153
  {client.redirectUris.map((uri, index) => (
158
- <li key={index} className="flex items-center gap-2 text-sm font-mono">
154
+ <li key={index} className="flex items-center gap-2 text-sm tabular-nums">
159
155
  <ExternalLink className="h-3 w-3 text-muted-foreground" />
160
156
  {uri}
161
157
  </li>
@@ -121,7 +121,7 @@ export function OAuthClientForm({ client, onSubmit, onCancel, isLoading = false
121
121
  disabled={isLoading}
122
122
  className={errors.name ? "border-destructive" : ""}
123
123
  />
124
- {errors.name && <p className="text-sm text-destructive">{errors.name}</p>}
124
+ {errors.name && <p className="text-destructive text-xs/relaxed">{errors.name}</p>}
125
125
  </div>
126
126
 
127
127
  {/* Description */}
@@ -164,7 +164,7 @@ export function OAuthClientForm({ client, onSubmit, onCancel, isLoading = false
164
164
  <div className="flex items-start space-x-3 p-3 rounded-md border">
165
165
  <RadioGroupItem value="confidential" id="confidential" className="mt-1" />
166
166
  <div>
167
- <Label htmlFor="confidential" className="font-medium cursor-pointer">
167
+ <Label htmlFor="confidential" className="cursor-pointer">
168
168
  Confidential
169
169
  </Label>
170
170
  <p className="text-sm text-muted-foreground">
@@ -175,7 +175,7 @@ export function OAuthClientForm({ client, onSubmit, onCancel, isLoading = false
175
175
  <div className="flex items-start space-x-3 p-3 rounded-md border">
176
176
  <RadioGroupItem value="public" id="public" className="mt-1" />
177
177
  <div>
178
- <Label htmlFor="public" className="font-medium cursor-pointer">
178
+ <Label htmlFor="public" className="cursor-pointer">
179
179
  Public
180
180
  </Label>
181
181
  <p className="text-sm text-muted-foreground">
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { Plus, Key } from "lucide-react";
4
4
  import { Button, Skeleton } from "../../../shadcnui";
5
+ import { SectionHeader } from "../../../components/typography";
5
6
  import { OAuthClientCard } from "./OAuthClientCard";
6
7
  import { OAuthClientInterface } from "../interfaces/oauth.interface";
7
8
 
@@ -45,7 +46,7 @@ export function OAuthClientList({
45
46
  return (
46
47
  <div className="space-y-4">
47
48
  <div className="flex items-center justify-between">
48
- <h2 className="text-2xl font-bold">{title}</h2>
49
+ <SectionHeader level={2}>{title}</SectionHeader>
49
50
  <Skeleton className="h-10 w-32" />
50
51
  </div>
51
52
  <div className="space-y-3">
@@ -62,7 +63,7 @@ export function OAuthClientList({
62
63
  return (
63
64
  <div className="space-y-4">
64
65
  <div className="flex items-center justify-between">
65
- <h2 className="text-2xl font-bold">{title}</h2>
66
+ <SectionHeader level={2}>{title}</SectionHeader>
66
67
  </div>
67
68
  <div className="rounded-lg border border-destructive/50 bg-destructive/10 p-6 text-center">
68
69
  <p className="text-destructive">{error.message}</p>
@@ -76,7 +77,7 @@ export function OAuthClientList({
76
77
  return (
77
78
  <div className="space-y-4">
78
79
  <div className="flex items-center justify-between">
79
- <h2 className="text-2xl font-bold">{title}</h2>
80
+ <SectionHeader level={2}>{title}</SectionHeader>
80
81
  {onCreateClick && (
81
82
  <Button onClick={onCreateClick}>
82
83
  <Plus className="h-4 w-4 mr-2" />
@@ -103,7 +104,7 @@ export function OAuthClientList({
103
104
  return (
104
105
  <div className="space-y-4">
105
106
  <div className="flex items-center justify-between">
106
- <h2 className="text-2xl font-bold">{title}</h2>
107
+ <SectionHeader level={2}>{title}</SectionHeader>
107
108
  {onCreateClick && (
108
109
  <Button onClick={onCreateClick}>
109
110
  <Plus className="h-4 w-4 mr-2" />
@@ -85,7 +85,7 @@ export function OAuthClientSecretDisplay({ secret, onDismiss, open, clientName }
85
85
 
86
86
  <div className="flex items-center space-x-2">
87
87
  <div className="flex-1">
88
- <Input value={secret} readOnly className="font-mono text-sm" onClick={(e) => e.currentTarget.select()} />
88
+ <Input value={secret} readOnly className="tabular-nums text-sm" onClick={(e) => e.currentTarget.select()} />
89
89
  </div>
90
90
  <Button
91
91
  type="button"
@@ -94,11 +94,11 @@ export function OAuthClientSecretDisplay({ secret, onDismiss, open, clientName }
94
94
  onClick={handleCopy}
95
95
  title={copied ? "Copied!" : "Copy to clipboard"}
96
96
  >
97
- {copied ? <Check className="h-4 w-4 text-green-600" /> : <Copy className="h-4 w-4" />}
97
+ {copied ? <Check className="text-success h-4 w-4" /> : <Copy className="h-4 w-4" />}
98
98
  </Button>
99
99
  </div>
100
100
 
101
- {copied && <p className="text-sm text-green-600 text-center">Copied to clipboard!</p>}
101
+ {copied && <p className="text-success text-center text-sm">Copied to clipboard!</p>}
102
102
 
103
103
  <DialogFooter className="mt-4">
104
104
  <Button onClick={handleDismiss} className="w-full">
@@ -139,7 +139,7 @@ export function OAuthRedirectUriInput({
139
139
  Add Redirect URI
140
140
  </Button>
141
141
 
142
- {error && <p className="text-sm text-destructive">{error}</p>}
142
+ {error && <p className="text-destructive text-xs/relaxed">{error}</p>}
143
143
  </div>
144
144
  );
145
145
  }
@@ -97,7 +97,7 @@ export function OAuthScopeSelector({
97
97
  disabled={disabled}
98
98
  />
99
99
  <div className="flex-1">
100
- <Label htmlFor={`scope-${scopeInfo.scope}`} className="text-sm font-medium cursor-pointer">
100
+ <Label htmlFor={`scope-${scopeInfo.scope}`} className="cursor-pointer">
101
101
  {scopeInfo.name}
102
102
  {isAdmin && <span className="ml-2 text-xs text-destructive">(Dangerous)</span>}
103
103
  </Label>
@@ -111,7 +111,7 @@ export function OAuthScopeSelector({
111
111
  ))}
112
112
  </div>
113
113
 
114
- {error && <p className="text-sm text-destructive">{error}</p>}
114
+ {error && <p className="text-destructive text-xs/relaxed">{error}</p>}
115
115
  </div>
116
116
  );
117
117
  }
@@ -32,7 +32,7 @@ export function OAuthConsentHeader({ client, logoUrl, appName = "Only35" }: OAut
32
32
 
33
33
  {/* Authorization Request */}
34
34
  <div className="space-y-2">
35
- <h1 className="text-2xl font-bold">Authorize {client.name}</h1>
35
+ <h1 className="text-primary text-3xl font-semibold">Authorize {client.name}</h1>
36
36
  <p className="text-muted-foreground">
37
37
  <span className="font-medium text-foreground">{client.name}</span> wants to access your {appName} account
38
38
  </p>
@@ -99,7 +99,7 @@ export function OAuthConsentScreen({
99
99
  <ExternalLink className="h-4 w-4 mt-0.5 flex-shrink-0" />
100
100
  <div>
101
101
  <span>Authorizing will redirect you to:</span>
102
- <p className="font-mono text-xs mt-1 break-all">{params.redirectUri}</p>
102
+ <p className="tabular-nums text-xs mt-1 break-all">{params.redirectUri}</p>
103
103
  </div>
104
104
  </div>
105
105
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { Eye, Pencil, Image, Upload, Film, FolderPlus, User, Shield, LucideIcon } from "lucide-react";
4
4
  import { OAuthScopeInfo } from "../../interfaces/oauth.interface";
5
+ import { MicroLabel } from "../../../../components/typography";
5
6
 
6
7
  export interface OAuthScopeListProps {
7
8
  /** List of requested scopes */
@@ -30,9 +31,7 @@ export function OAuthScopeList({ scopes }: OAuthScopeListProps) {
30
31
 
31
32
  return (
32
33
  <div className="space-y-3">
33
- <h2 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
34
- This will allow the application to:
35
- </h2>
34
+ <MicroLabel as="h3">This will allow the application to:</MicroLabel>
36
35
  <ul className="space-y-3">
37
36
  {scopes.map((scope) => {
38
37
  const IconComponent = scope.icon ? SCOPE_ICONS[scope.icon] : Eye;
@@ -112,7 +112,7 @@ const ModuleEditor = memo(function ModuleEditor({
112
112
  <div className="rounded-lg border border-accent bg-card">
113
113
  <div className="flex items-center justify-between border-b px-4 py-2">
114
114
  <h4 className="text-sm font-medium">{moduleLabel}</h4>
115
- <span className="font-mono text-xs text-muted-foreground">{moduleId}</span>
115
+ <span className="text-muted-foreground tabular-nums text-xs">{moduleId}</span>
116
116
  </div>
117
117
  <div className="overflow-x-auto">
118
118
  <table className="w-full text-sm">