akanjs 2.4.2-rc.2 → 3.0.0-alpha.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 (170) hide show
  1. package/base/baseEnv.ts +0 -6
  2. package/client/cn.ts +52 -0
  3. package/client/csrTypes.ts +2 -2
  4. package/client/frameConfig.ts +2 -2
  5. package/client/index.ts +1 -0
  6. package/client/types.ts +0 -4
  7. package/common/fileUpload.ts +1 -1
  8. package/common/index.ts +1 -0
  9. package/common/isThenable.ts +12 -0
  10. package/constant/purify.ts +9 -10
  11. package/fetch/client/fetchClient.ts +1 -1
  12. package/fetch/client/httpClient.ts +9 -5
  13. package/fetch/fetchType/sliceFetch.type.ts +1 -1
  14. package/package.json +4 -7
  15. package/server/akanApp.ts +2 -0
  16. package/server/systemPageDocument.tsx +12 -12
  17. package/signal/endpointInfo.ts +2 -1
  18. package/signal/slice.ts +1 -1
  19. package/signal/sliceInfo.ts +2 -1
  20. package/store/action.ts +18 -2
  21. package/store/baseSt.ts +2 -2
  22. package/store/state.ts +9 -1
  23. package/store/storeInstance.ts +2 -0
  24. package/test/sampleOf.ts +3 -3
  25. package/test/signalTestRuntime.ts +0 -2
  26. package/types/base/baseEnv.d.ts +0 -2
  27. package/types/client/cn.d.ts +12 -0
  28. package/types/client/index.d.ts +1 -0
  29. package/types/client/types.d.ts +0 -3
  30. package/types/common/fileUpload.d.ts +1 -1
  31. package/types/common/index.d.ts +1 -0
  32. package/types/common/isThenable.d.ts +9 -0
  33. package/types/constant/purify.d.ts +3 -2
  34. package/types/fetch/fetchType/sliceFetch.type.d.ts +1 -1
  35. package/types/signal/endpointInfo.d.ts +2 -2
  36. package/types/signal/slice.d.ts +1 -1
  37. package/types/signal/sliceInfo.d.ts +2 -2
  38. package/types/store/action.d.ts +1 -1
  39. package/types/store/state.d.ts +4 -2
  40. package/types/test/sampleOf.d.ts +2 -2
  41. package/types/ui/Badge.d.ts +6 -0
  42. package/types/ui/Button.d.ts +26 -6
  43. package/types/ui/Load/Units.d.ts +3 -1
  44. package/types/ui/RecentTime.d.ts +1 -1
  45. package/types/ui/Signal/Collapse.d.ts +12 -0
  46. package/types/ui/Signal/style.d.ts +5 -6
  47. package/types/ui/Switch.d.ts +14 -0
  48. package/types/ui/Tooltip.d.ts +11 -0
  49. package/types/ui/UiOverride/Provider.d.ts +6 -5
  50. package/types/ui/UiOverride/context.d.ts +22 -1
  51. package/types/ui/UiOverride/index.d.ts +2 -1
  52. package/types/ui/UiOverride/override.d.ts +7 -6
  53. package/types/ui/UiOverride/useUiRecipe.d.ts +8 -0
  54. package/types/ui/index.d.ts +5 -1
  55. package/types/ui/recipe/badgeRecipe.d.ts +13 -0
  56. package/types/ui/recipe/buttonRecipe.d.ts +15 -0
  57. package/types/ui/recipe/factory.d.ts +24 -0
  58. package/types/ui/recipe/index.d.ts +18 -0
  59. package/types/ui/recipe/inputRecipe.d.ts +13 -0
  60. package/types/ui/recipe.d.ts +1 -0
  61. package/ui/Badge.tsx +17 -0
  62. package/ui/BottomSheet.tsx +8 -10
  63. package/ui/Button.tsx +158 -48
  64. package/ui/Clipboard.tsx +3 -3
  65. package/ui/Constant/Doc.tsx +108 -65
  66. package/ui/Constant/Mermaid.tsx +9 -9
  67. package/ui/Data/CardList.tsx +3 -3
  68. package/ui/Data/Dashboard.tsx +22 -13
  69. package/ui/Data/Insight.tsx +6 -6
  70. package/ui/Data/Item.tsx +49 -34
  71. package/ui/Data/ListContainer.tsx +11 -7
  72. package/ui/Data/Pagination.tsx +2 -2
  73. package/ui/DatePicker.tsx +5 -5
  74. package/ui/Dialog/Content.tsx +2 -2
  75. package/ui/Dialog/Modal.tsx +12 -8
  76. package/ui/Dialog/Provider.tsx +2 -2
  77. package/ui/DragAction.tsx +2 -2
  78. package/ui/DraggableList.tsx +10 -5
  79. package/ui/Dropdown.tsx +33 -26
  80. package/ui/Empty.tsx +5 -5
  81. package/ui/Field.tsx +82 -70
  82. package/ui/Image.tsx +2 -2
  83. package/ui/Input.tsx +62 -60
  84. package/ui/Layout/BottomInset.tsx +2 -2
  85. package/ui/Layout/BottomTab.tsx +5 -5
  86. package/ui/Layout/Header.tsx +3 -3
  87. package/ui/Layout/LeftSider.tsx +6 -5
  88. package/ui/Layout/Navbar.tsx +2 -12
  89. package/ui/Layout/RightSider.tsx +10 -8
  90. package/ui/Layout/Sider.tsx +5 -4
  91. package/ui/Layout/Template.tsx +2 -2
  92. package/ui/Layout/TopInset.tsx +2 -2
  93. package/ui/Layout/Unit.tsx +2 -2
  94. package/ui/Layout/View.tsx +2 -2
  95. package/ui/Layout/Zone.tsx +2 -2
  96. package/ui/Link/Back.tsx +2 -2
  97. package/ui/Link/Close.tsx +2 -2
  98. package/ui/Link/CsrLink.tsx +6 -4
  99. package/ui/Link/Lang.tsx +2 -2
  100. package/ui/Link/SsrLink.tsx +6 -5
  101. package/ui/Load/Page.tsx +1 -1
  102. package/ui/Load/Pagination.tsx +2 -2
  103. package/ui/Load/Units.tsx +19 -4
  104. package/ui/Load/View.tsx +2 -2
  105. package/ui/Loading/Area.tsx +4 -2
  106. package/ui/Loading/Button.tsx +2 -2
  107. package/ui/Loading/Input.tsx +2 -2
  108. package/ui/Loading/ProgressBar.tsx +2 -2
  109. package/ui/Loading/Skeleton.tsx +6 -6
  110. package/ui/Loading/Spin.tsx +2 -2
  111. package/ui/Menu.tsx +29 -27
  112. package/ui/Model/Edit.tsx +3 -3
  113. package/ui/Model/EditModal.tsx +5 -5
  114. package/ui/Model/EditWrapper.tsx +2 -2
  115. package/ui/Model/New.tsx +3 -3
  116. package/ui/Model/NewWrapper_Client.tsx +2 -2
  117. package/ui/Model/Remove.tsx +5 -4
  118. package/ui/Model/RemoveWrapper.tsx +2 -2
  119. package/ui/Model/SureToRemove.tsx +7 -6
  120. package/ui/Model/View.tsx +2 -2
  121. package/ui/Model/ViewEditModal.tsx +20 -21
  122. package/ui/Model/ViewWrapper.tsx +2 -2
  123. package/ui/More.tsx +2 -2
  124. package/ui/ObjectId.tsx +9 -3
  125. package/ui/Pagination.tsx +14 -11
  126. package/ui/Popconfirm.tsx +20 -11
  127. package/ui/Radio.tsx +4 -4
  128. package/ui/RecentTime.tsx +30 -83
  129. package/ui/Refresh.tsx +1 -1
  130. package/ui/ScreenNavigator.tsx +2 -2
  131. package/ui/Select.tsx +21 -23
  132. package/ui/Signal/Arg.tsx +21 -18
  133. package/ui/Signal/Collapse.tsx +29 -0
  134. package/ui/Signal/Doc.tsx +27 -22
  135. package/ui/Signal/Listener.tsx +3 -3
  136. package/ui/Signal/Message.tsx +31 -17
  137. package/ui/Signal/Object.tsx +13 -8
  138. package/ui/Signal/PubSub.tsx +26 -16
  139. package/ui/Signal/Request.tsx +3 -2
  140. package/ui/Signal/Response.tsx +5 -4
  141. package/ui/Signal/RestApi.tsx +27 -17
  142. package/ui/Signal/style.ts +16 -16
  143. package/ui/Switch.tsx +62 -0
  144. package/ui/System/CSR.tsx +40 -35
  145. package/ui/System/Client.tsx +2 -2
  146. package/ui/System/DevModeToggle.tsx +10 -12
  147. package/ui/System/Messages.tsx +14 -16
  148. package/ui/System/Reconnect.tsx +7 -7
  149. package/ui/System/SSR.tsx +25 -21
  150. package/ui/System/SelectLanguage.tsx +24 -28
  151. package/ui/System/ThemeToggle.tsx +38 -45
  152. package/ui/Tab/Menu.tsx +20 -18
  153. package/ui/Tab/Panel.tsx +3 -3
  154. package/ui/Tab/Provider.tsx +2 -2
  155. package/ui/Table.tsx +11 -8
  156. package/ui/ToggleSelect.tsx +14 -18
  157. package/ui/Tooltip.tsx +55 -0
  158. package/ui/UiOverride/Provider.tsx +10 -6
  159. package/ui/UiOverride/context.ts +22 -2
  160. package/ui/UiOverride/index.ts +8 -1
  161. package/ui/UiOverride/override.ts +7 -6
  162. package/ui/UiOverride/useUiRecipe.ts +15 -0
  163. package/ui/Unauthorized.tsx +5 -5
  164. package/ui/index.ts +16 -0
  165. package/ui/recipe/badgeRecipe.ts +23 -0
  166. package/ui/recipe/buttonRecipe.ts +32 -0
  167. package/ui/recipe/factory.ts +32 -0
  168. package/ui/recipe/index.ts +18 -0
  169. package/ui/recipe/inputRecipe.ts +13 -0
  170. package/ui/styles.css +150 -21
@@ -1,11 +1,13 @@
1
1
  "use client";
2
2
 
3
- import { usePage } from "akanjs/client";
3
+ import { cn, usePage } from "akanjs/client";
4
4
  import { capitalize } from "akanjs/common";
5
5
  import { useMemo, useState } from "react";
6
6
  import { AiOutlineInfoCircle, AiOutlineSearch } from "react-icons/ai";
7
7
  import { BiNetworkChart, BiTable } from "react-icons/bi";
8
8
 
9
+ import { badgeRecipe } from "../Badge";
10
+ import { buttonRecipe } from "../Button";
9
11
  import { Input } from "../Input";
10
12
  import { Modal } from "../Modal";
11
13
  import { Mermaid } from "./Mermaid";
@@ -20,6 +22,9 @@ import {
20
22
  type ScalarSchema,
21
23
  } from "./schemaDoc";
22
24
 
25
+ const tableClass =
26
+ "w-full text-left text-sm [&_th]:px-3 [&_th]:py-2 [&_th]:font-medium [&_th]:text-foreground/60 [&_td]:px-3 [&_td]:py-2 [&_tbody_tr]:border-border [&_tbody_tr]:border-t";
27
+
23
28
  export default function Doc() {
24
29
  return <div />;
25
30
  }
@@ -54,7 +59,7 @@ const Zone = ({ models, scalars, enums, openAll }: ZoneProps) => {
54
59
  <div className="flex break-after-page flex-col gap-4">
55
60
  <div>
56
61
  <div className="font-bold text-3xl">Constant Schema Docs</div>
57
- <div className="text-base-content/70">
62
+ <div className="text-foreground/70">
58
63
  Database models, scalar models, enums, and relations from ConstantRegistry.
59
64
  </div>
60
65
  </div>
@@ -64,7 +69,7 @@ const Zone = ({ models, scalars, enums, openAll }: ZoneProps) => {
64
69
  <SummaryCard title="Enums" value={filteredEnums.length} />
65
70
  <SummaryCard title="Relations" value={schemaDoc.relations.length} />
66
71
  </div>
67
- <div className="flex flex-wrap items-center justify-between gap-2 rounded-xl bg-base-200 p-3">
72
+ <div className="flex flex-wrap items-center justify-between gap-2 rounded-xl bg-muted p-3">
68
73
  <Input
69
74
  nullable
70
75
  value={query}
@@ -73,15 +78,21 @@ const Zone = ({ models, scalars, enums, openAll }: ZoneProps) => {
73
78
  icon={<AiOutlineSearch />}
74
79
  placeholder="Search models or enums"
75
80
  />
76
- <div className="join">
81
+ <div className="inline-flex w-fit overflow-hidden rounded-field">
77
82
  <button
78
- className={`btn join-item btn-sm ${viewMode === "table" ? "btn-primary" : "btn-outline"}`}
83
+ className={buttonRecipe(
84
+ { variant: viewMode === "table" ? "primary" : "outline", size: "sm" },
85
+ "rounded-none",
86
+ )}
79
87
  onClick={() => setViewMode("table")}
80
88
  >
81
89
  <BiTable /> Table
82
90
  </button>
83
91
  <button
84
- className={`btn join-item btn-sm ${viewMode === "diagram" ? "btn-primary" : "btn-outline"}`}
92
+ className={buttonRecipe(
93
+ { variant: viewMode === "diagram" ? "primary" : "outline", size: "sm" },
94
+ "rounded-none",
95
+ )}
85
96
  onClick={() => setViewMode("diagram")}
86
97
  >
87
98
  <BiNetworkChart /> Diagram
@@ -119,10 +130,10 @@ Doc.Zone = Zone;
119
130
  const Print = ({ models, scalars, enums }: ZoneProps) => {
120
131
  const schemaDoc = useMemo(() => getConstantSchemaDoc({ models, scalars, enums }), [models, scalars, enums]);
121
132
  return (
122
- <div className="flex flex-col gap-10 bg-base-100 text-base-content print:bg-white print:text-black">
133
+ <div className="flex flex-col gap-10 bg-background text-foreground print:bg-white print:text-black">
123
134
  <div className="break-after-page">
124
135
  <div className="font-bold text-4xl">Constant Schema Definition</div>
125
- <div className="mt-2 text-base-content/70 print:text-black">
136
+ <div className="mt-2 text-foreground/70 print:text-black">
126
137
  Database models, scalar models, enums, and relations from ConstantRegistry.
127
138
  </div>
128
139
  <div className="mt-6 grid grid-cols-2 gap-2 md:grid-cols-4">
@@ -170,20 +181,20 @@ const Model = ({ refName, database: databaseProp, openAll }: ModelProps) => {
170
181
  if (!database) return null;
171
182
  const activeVariant = database.variants[variant] ?? getDefaultVariant(database);
172
183
  return (
173
- <div className="collapse-arrow collapse bg-base-200">
174
- <input type="checkbox" defaultChecked={openAll} />
175
- <div className="collapse-title">
184
+ <details className="group rounded-box bg-muted" open={openAll}>
185
+ <summary className="flex cursor-pointer list-none items-center justify-between gap-2 p-4">
176
186
  <div className="flex flex-wrap items-center gap-2">
177
187
  <div className="font-bold text-xl">{database.modelName}</div>
178
- <div className="badge badge-primary">{database.refName}</div>
179
- <div className="text-base-content/70 text-sm">{l._(`${database.refName}.modelDesc`)}</div>
188
+ <div className={badgeRecipe({ variant: "primary" })}>{database.refName}</div>
189
+ <div className="text-foreground/70 text-sm">{l._(`${database.refName}.modelDesc`)}</div>
180
190
  </div>
181
- </div>
182
- <div className="collapse-content flex flex-col gap-3">
191
+ <span className="text-foreground/50 transition-transform group-open:rotate-180">▾</span>
192
+ </summary>
193
+ <div className="flex flex-col gap-3 p-4 pt-0">
183
194
  <VariantTabs variant={variant} onChange={setVariant} />
184
195
  <ModelVariantTable variant={activeVariant} />
185
196
  </div>
186
- </div>
197
+ </details>
187
198
  );
188
199
  };
189
200
  Doc.Model = Model;
@@ -202,19 +213,19 @@ const Scalar = ({ refName, scalar: scalarProp, openAll }: ScalarProps) => {
202
213
  const { l } = usePage();
203
214
  if (!scalar) return null;
204
215
  return (
205
- <div className="collapse-arrow collapse bg-base-200">
206
- <input type="checkbox" defaultChecked={openAll} />
207
- <div className="collapse-title">
216
+ <details className="group rounded-box bg-muted" open={openAll}>
217
+ <summary className="flex cursor-pointer list-none items-center justify-between gap-2 p-4">
208
218
  <div className="flex flex-wrap items-center gap-2">
209
219
  <div className="font-bold text-xl">{scalar.modelName}</div>
210
- <div className="badge badge-secondary">{scalar.refName}</div>
211
- <div className="text-base-content/70 text-sm">{l._(`${scalar.refName}.modelDesc`)}</div>
220
+ <div className={badgeRecipe({ variant: "secondary" })}>{scalar.refName}</div>
221
+ <div className="text-foreground/70 text-sm">{l._(`${scalar.refName}.modelDesc`)}</div>
212
222
  </div>
213
- </div>
214
- <div className="collapse-content">
223
+ <span className="text-foreground/50 transition-transform group-open:rotate-180">▾</span>
224
+ </summary>
225
+ <div className="p-4 pt-0">
215
226
  <FieldTable refName={scalar.refName} fields={scalar.fields} />
216
227
  </div>
217
- </div>
228
+ </details>
218
229
  );
219
230
  };
220
231
  Doc.Scalar = Scalar;
@@ -226,7 +237,7 @@ interface EnumProps {
226
237
  const EnumList = ({ enums = getConstantSchemaDoc().enums }: EnumProps) => {
227
238
  const { l } = usePage();
228
239
  return (
229
- <div className="overflow-x-auto rounded-xl bg-base-200 p-3">
240
+ <div className="overflow-x-auto rounded-xl bg-muted p-3">
230
241
  <table className="table">
231
242
  <thead>
232
243
  <tr>
@@ -246,13 +257,13 @@ const EnumList = ({ enums = getConstantSchemaDoc().enums }: EnumProps) => {
246
257
  <td>
247
258
  <div className="flex flex-wrap gap-1">
248
259
  {enumSchema.values.map((value) => (
249
- <div
260
+ <button
250
261
  key={String(value)}
251
- className="tooltip tooltip-primary"
252
- data-tip={l._(`${enumSchema.refName}.${value}`)}
262
+ className={buttonRecipe({ variant: "outline", size: "xs" })}
263
+ title={l._(`${enumSchema.refName}.${value}`)}
253
264
  >
254
- <button className="btn btn-xs">{String(value)}</button>
255
- </div>
265
+ {String(value)}
266
+ </button>
256
267
  ))}
257
268
  </div>
258
269
  </td>
@@ -262,7 +273,7 @@ const EnumList = ({ enums = getConstantSchemaDoc().enums }: EnumProps) => {
262
273
  ? enumSchema.usedBy.map((usage) => (
263
274
  <span
264
275
  key={`${usage.refName}-${usage.variant}-${usage.fieldKey}`}
265
- className="badge badge-outline"
276
+ className={badgeRecipe({ variant: "outline" })}
266
277
  >
267
278
  {usage.refName}.{usage.fieldKey}
268
279
  </span>
@@ -286,9 +297,16 @@ const VariantTabs = ({
286
297
  variant: DatabaseModelVariant;
287
298
  onChange: (variant: DatabaseModelVariant) => void;
288
299
  }) => (
289
- <div className="tabs tabs-box w-fit">
300
+ <div className="inline-flex w-fit gap-1 rounded-field bg-muted p-1">
290
301
  {databaseModelVariants.map((item) => (
291
- <button key={item} className={`tab ${variant === item ? "tab-active" : ""}`} onClick={() => onChange(item)}>
302
+ <button
303
+ key={item}
304
+ className={cn(
305
+ "rounded-[calc(var(--radius-field)-0.25rem)] px-3 py-1 font-medium text-sm transition-colors",
306
+ variant === item ? "bg-background text-foreground shadow-sm" : "text-foreground/60 hover:text-foreground",
307
+ )}
308
+ onClick={() => onChange(item)}
309
+ >
292
310
  {getVariantTitle(item)}
293
311
  </button>
294
312
  ))}
@@ -299,8 +317,8 @@ const ModelVariantTable = ({ variant }: { variant: ReturnType<typeof getDefaultV
299
317
  <div className="flex flex-col gap-2">
300
318
  <div className="flex flex-wrap items-center gap-2">
301
319
  <div className="font-extrabold text-lg">{variant.modelName}</div>
302
- <div className="badge badge-outline">{getVariantTitle(variant.variant)}</div>
303
- <div className="text-base-content/60 text-sm">{variant.fields.length} fields</div>
320
+ <div className={badgeRecipe({ variant: "outline" })}>{getVariantTitle(variant.variant)}</div>
321
+ <div className="text-foreground/60 text-sm">{variant.fields.length} fields</div>
304
322
  </div>
305
323
  <FieldTable refName={variant.refName} fields={variant.fields} />
306
324
  </div>
@@ -313,11 +331,16 @@ const PrintDatabase = ({ database }: { database: DatabaseSchema }) => {
313
331
  <div>
314
332
  <div className="flex flex-wrap items-center gap-2">
315
333
  <div className="font-bold text-3xl">{database.modelName}</div>
316
- <div className="badge badge-primary print:border print:border-black print:bg-white print:text-black">
334
+ <div
335
+ className={badgeRecipe(
336
+ { variant: "primary" },
337
+ "print:border print:border-black print:bg-white print:text-black",
338
+ )}
339
+ >
317
340
  {database.refName}
318
341
  </div>
319
342
  </div>
320
- <div className="mt-2 text-base-content/70 print:text-black">{l._(`${database.refName}.modelDesc`)}</div>
343
+ <div className="mt-2 text-foreground/70 print:text-black">{l._(`${database.refName}.modelDesc`)}</div>
321
344
  </div>
322
345
  {databaseModelVariants.map((variantKey) => {
323
346
  const variant = database.variants[variantKey];
@@ -343,11 +366,16 @@ const PrintScalar = ({ scalar }: { scalar: ScalarSchema }) => {
343
366
  <div>
344
367
  <div className="flex flex-wrap items-center gap-2">
345
368
  <div className="font-bold text-2xl">{scalar.modelName}</div>
346
- <div className="badge badge-secondary print:border print:border-black print:bg-white print:text-black">
369
+ <div
370
+ className={badgeRecipe(
371
+ { variant: "secondary" },
372
+ "print:border print:border-black print:bg-white print:text-black",
373
+ )}
374
+ >
347
375
  {scalar.refName}
348
376
  </div>
349
377
  </div>
350
- <div className="mt-1 text-base-content/70 print:text-black">{l._(`${scalar.refName}.modelDesc`)}</div>
378
+ <div className="mt-1 text-foreground/70 print:text-black">{l._(`${scalar.refName}.modelDesc`)}</div>
351
379
  </div>
352
380
  <PrintFieldTable refName={scalar.refName} fields={scalar.fields} />
353
381
  </section>
@@ -359,8 +387,8 @@ const PrintSectionTitle = ({ title }: { title: string }) => <div className="font
359
387
  const PrintVariantHeader = ({ title, badge, fields }: { title: string; badge: string; fields: number }) => (
360
388
  <div className="flex flex-wrap items-center gap-2">
361
389
  <div className="font-extrabold text-xl">{title}</div>
362
- <div className="badge badge-outline print:border print:border-black">{badge}</div>
363
- <div className="text-base-content/60 text-sm print:text-black">{fields} fields</div>
390
+ <div className={badgeRecipe({ variant: "outline" }, "print:border print:border-black")}>{badge}</div>
391
+ <div className="text-foreground/60 text-sm print:text-black">{fields} fields</div>
364
392
  </div>
365
393
  );
366
394
 
@@ -369,8 +397,8 @@ const FieldTable = ({ refName, fields }: { refName: string; fields: FieldSchema[
369
397
  const [selectedField, setSelectedField] = useState<FieldSchema | null>(null);
370
398
  return (
371
399
  <>
372
- <div className="overflow-x-auto rounded-xl bg-base-100 p-3">
373
- <table className="table">
400
+ <div className="overflow-x-auto rounded-xl bg-background p-3">
401
+ <table className={tableClass}>
374
402
  <thead>
375
403
  <tr>
376
404
  <th>Key</th>
@@ -390,33 +418,45 @@ const FieldTable = ({ refName, fields }: { refName: string; fields: FieldSchema[
390
418
  <tr key={field.key}>
391
419
  <td>
392
420
  <div className="font-bold">{field.key}</div>
393
- <div className="text-base-content/60 text-xs">{l._(`${refName}.${field.key}`)}</div>
421
+ <div className="text-foreground/60 text-xs">{l._(`${refName}.${field.key}`)}</div>
394
422
  </td>
395
423
  <td>
396
- <span className={field.typeKind === "primitive" ? "" : "badge badge-primary badge-outline"}>
424
+ <span
425
+ className={
426
+ field.typeKind === "primitive"
427
+ ? ""
428
+ : badgeRecipe({ variant: "outline" }, "border-primary text-primary")
429
+ }
430
+ >
397
431
  {field.typeLabel}
398
432
  </span>
399
433
  </td>
400
434
  <td>
401
435
  {field.required ? (
402
- <span className="badge badge-error">Required</span>
436
+ <span className={badgeRecipe({ variant: "error" })}>Required</span>
403
437
  ) : (
404
- <span className="badge">Optional</span>
438
+ <span className={badgeRecipe()}>Optional</span>
405
439
  )}
406
440
  </td>
407
441
  <td>
408
- <span className="badge badge-outline">{field.fieldType}</span>
409
- {!field.select ? <span className="badge badge-warning ml-1">select:false</span> : null}
442
+ <span className={badgeRecipe({ variant: "outline" })}>{field.fieldType}</span>
443
+ {!field.select ? (
444
+ <span className={badgeRecipe({ variant: "warning" }, "ml-1")}>select:false</span>
445
+ ) : null}
410
446
  </td>
411
447
  <td>
412
- {field.relationLabel ? <span className="badge badge-secondary">{field.relationLabel}</span> : "-"}
448
+ {field.relationLabel ? (
449
+ <span className={badgeRecipe({ variant: "secondary" })}>{field.relationLabel}</span>
450
+ ) : (
451
+ "-"
452
+ )}
413
453
  </td>
414
454
  <td className="max-w-48 truncate">{field.defaultLabel ?? "-"}</td>
415
455
  <td>
416
456
  <div className="flex flex-wrap gap-1">
417
457
  {field.constraints.length
418
458
  ? field.constraints.map((constraint) => (
419
- <span key={constraint} className="badge badge-outline">
459
+ <span key={constraint} className={badgeRecipe({ variant: "outline" })}>
420
460
  {constraint}
421
461
  </span>
422
462
  ))
@@ -427,7 +467,7 @@ const FieldTable = ({ refName, fields }: { refName: string; fields: FieldSchema[
427
467
  {field.enumValues ? (
428
468
  <div className="flex flex-wrap gap-1">
429
469
  {field.enumValues.map((value) => (
430
- <span key={String(value)} className="badge">
470
+ <span key={String(value)} className={badgeRecipe()}>
431
471
  {String(value)}
432
472
  </span>
433
473
  ))}
@@ -438,7 +478,10 @@ const FieldTable = ({ refName, fields }: { refName: string; fields: FieldSchema[
438
478
  </td>
439
479
  <td className="min-w-52">{l._(`${refName}.${field.key}.desc`)}</td>
440
480
  <td>
441
- <button className="btn btn-ghost btn-xs" onClick={() => setSelectedField(field)}>
481
+ <button
482
+ className={buttonRecipe({ variant: "ghost", size: "xs" })}
483
+ onClick={() => setSelectedField(field)}
484
+ >
442
485
  <AiOutlineInfoCircle /> Detail
443
486
  </button>
444
487
  </td>
@@ -455,8 +498,8 @@ const FieldTable = ({ refName, fields }: { refName: string; fields: FieldSchema[
455
498
  const PrintFieldTable = ({ refName, fields }: { refName: string; fields: FieldSchema[] }) => {
456
499
  const { l } = usePage();
457
500
  return (
458
- <div className="overflow-x-auto rounded-xl bg-base-100 p-3 print:overflow-visible print:rounded-none print:p-0">
459
- <table className="table-sm table">
501
+ <div className="overflow-x-auto rounded-xl bg-background p-3 print:overflow-visible print:rounded-none print:p-0">
502
+ <table className={tableClass}>
460
503
  <thead>
461
504
  <tr>
462
505
  <th>Key</th>
@@ -476,7 +519,7 @@ const PrintFieldTable = ({ refName, fields }: { refName: string; fields: FieldSc
476
519
  <tr key={field.key} className="break-inside-avoid">
477
520
  <td>
478
521
  <div className="font-bold">{field.key}</div>
479
- <div className="text-base-content/60 text-xs print:text-black">{l._(`${refName}.${field.key}`)}</div>
522
+ <div className="text-foreground/60 text-xs print:text-black">{l._(`${refName}.${field.key}`)}</div>
480
523
  </td>
481
524
  <td>{field.typeLabel}</td>
482
525
  <td>{field.required ? "Required" : "Optional"}</td>
@@ -515,8 +558,8 @@ const PrintFieldDetail = ({ field }: { field: FieldSchema }) => {
515
558
  const PrintEnumTable = ({ enums }: { enums: ReturnType<typeof getConstantSchemaDoc>["enums"] }) => {
516
559
  const { l } = usePage();
517
560
  return (
518
- <div className="overflow-x-auto rounded-xl bg-base-100 p-3 print:overflow-visible print:rounded-none print:p-0">
519
- <table className="table-sm table">
561
+ <div className="overflow-x-auto rounded-xl bg-background p-3 print:overflow-visible print:rounded-none print:p-0">
562
+ <table className={tableClass}>
520
563
  <thead>
521
564
  <tr>
522
565
  <th>Key</th>
@@ -593,9 +636,9 @@ const FieldDetailModal = ({
593
636
  >
594
637
  <div>
595
638
  <div className="font-bold text-lg">{l._(`${refName}.${field.key}`)}</div>
596
- <div className="text-base-content/70">{l._(`${refName}.${field.key}.desc`)}</div>
639
+ <div className="text-foreground/70">{l._(`${refName}.${field.key}.desc`)}</div>
597
640
  </div>
598
- <pre className="max-h-[60vh] overflow-auto rounded-xl bg-base-200 p-4 text-sm">
641
+ <pre className="max-h-[60vh] overflow-auto rounded-xl bg-muted p-4 text-sm">
599
642
  {JSON.stringify(detail, null, 2)}
600
643
  </pre>
601
644
  </Modal>
@@ -613,8 +656,8 @@ const getPrintRelation = (field: FieldSchema) => {
613
656
  };
614
657
 
615
658
  const SummaryCard = ({ title, value }: { title: string; value: number }) => (
616
- <div className="rounded-xl bg-base-200 p-4">
617
- <div className="text-base-content/60 text-sm">{title}</div>
659
+ <div className="rounded-xl bg-muted p-4">
660
+ <div className="text-foreground/60 text-sm">{title}</div>
618
661
  <div className="font-bold text-2xl">{value}</div>
619
662
  </div>
620
663
  );
@@ -637,7 +680,7 @@ const Diagram = ({ databases, scalars }: { databases: DatabaseSchema[]; scalars:
637
680
  highlightNodes={selectedNode ? [selectedNode] : []}
638
681
  onSelectNode={setSelectedNode}
639
682
  />
640
- <div className="rounded-xl bg-base-200 p-4">
683
+ <div className="rounded-xl bg-muted p-4">
641
684
  <div className="font-bold text-xl">Selected Model</div>
642
685
  {selectedDatabase ? (
643
686
  <Model database={selectedDatabase} openAll />
@@ -645,11 +688,11 @@ const Diagram = ({ databases, scalars }: { databases: DatabaseSchema[]; scalars:
645
688
  <Scalar scalar={selectedScalar} openAll />
646
689
  ) : selectedRefName ? (
647
690
  <div className="mt-4">
648
- <div className="badge badge-outline">External</div>
691
+ <div className={badgeRecipe({ variant: "outline" })}>External</div>
649
692
  <div className="mt-2 font-bold">{selectedRefName}</div>
650
693
  </div>
651
694
  ) : (
652
- <div className="mt-4 text-base-content/60">Select a node in the diagram.</div>
695
+ <div className="mt-4 text-foreground/60">Select a node in the diagram.</div>
653
696
  )}
654
697
  </div>
655
698
  </div>
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { clsx } from "akanjs/client";
3
+ import { cn } from "akanjs/client";
4
4
  import { useEffect, useId, useRef, useState } from "react";
5
5
 
6
6
  export interface MermaidProps {
@@ -80,15 +80,15 @@ export const Mermaid = ({ chart, title, className, highlightNodes = [], onSelect
80
80
  }, [chart, highlightNodes, onSelectNode, reactId]);
81
81
 
82
82
  return (
83
- <div className={clsx("my-4 overflow-hidden rounded-xl border border-base-300 bg-base-200/40", className)}>
83
+ <div className={cn("my-4 overflow-hidden rounded-xl border border-border bg-muted/40", className)}>
84
84
  {title ? (
85
- <div className="border-base-300 border-b px-4 py-2 font-bold text-base-content/70 text-sm">{title}</div>
85
+ <div className="border-border border-b px-4 py-2 font-bold text-foreground/70 text-sm">{title}</div>
86
86
  ) : null}
87
87
  <div className="overflow-x-auto p-4">
88
88
  {error ? (
89
- <pre className="whitespace-pre-wrap text-error text-sm">{error}</pre>
89
+ <pre className="whitespace-pre-wrap text-destructive text-sm">{error}</pre>
90
90
  ) : (
91
- <div ref={containerRef} className="min-w-fit text-base-content" />
91
+ <div ref={containerRef} className="min-w-fit text-foreground" />
92
92
  )}
93
93
  </div>
94
94
  </div>
@@ -101,10 +101,10 @@ function getThemeColors() {
101
101
  const fallback = isDarkTheme(root) ? darkThemeFallback : lightThemeFallback;
102
102
 
103
103
  return {
104
- base100: getMermaidColor(style, "--color-base-100", fallback.base100),
105
- base200: getMermaidColor(style, "--color-base-200", fallback.base200),
106
- base300: getMermaidColor(style, "--color-base-300", fallback.base300),
107
- baseContent: getMermaidColor(style, "--color-base-content", fallback.baseContent),
104
+ base100: getMermaidColor(style, "--color-background", fallback.base100),
105
+ base200: getMermaidColor(style, "--color-muted", fallback.base200),
106
+ base300: getMermaidColor(style, "--color-border", fallback.base300),
107
+ baseContent: getMermaidColor(style, "--color-foreground", fallback.baseContent),
108
108
  primary: getMermaidColor(style, "--color-primary", fallback.primary),
109
109
  };
110
110
  }
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import type { DataList } from "akanjs/base";
3
- import { clsx, type DataAction, type DataColumn } from "akanjs/client";
3
+ import { cn, type DataAction, type DataColumn } from "akanjs/client";
4
4
  import { capitalize } from "akanjs/common";
5
5
  import type { FilterInstance } from "akanjs/document";
6
6
  import type { FetchInitForm, SliceMeta } from "akanjs/fetch";
@@ -86,14 +86,14 @@ export default function CardList<
86
86
  return (
87
87
  <div className={className}>
88
88
  {modelListLoading ? (
89
- <div className={clsx("grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5", cardListClassName)}>
89
+ <div className={cn("grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5", cardListClassName)}>
90
90
  {new Array(limitOfModel || 20)
91
91
  .fill(0)
92
92
  .map((_, idx) => `skeleton-${idx}`)
93
93
  .map((key) => (renderLoading ? renderLoading() : <Loading.Skeleton key={key} active />))}
94
94
  </div>
95
95
  ) : (
96
- <div className={clsx("grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5", cardListClassName)}>
96
+ <div className={cn("grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5", cardListClassName)}>
97
97
  {modelList.map((model, idx) => {
98
98
  return (
99
99
  <DataItem
@@ -1,9 +1,10 @@
1
1
  "use client";
2
- import { clsx, usePage } from "akanjs/client";
2
+ import { cn, usePage } from "akanjs/client";
3
3
  import { capitalize } from "akanjs/common";
4
4
  import type { SliceMeta } from "akanjs/fetch";
5
5
  import { st } from "akanjs/store";
6
6
 
7
+ import { buttonRecipe } from "../Button";
7
8
  import { Link } from "../Link";
8
9
 
9
10
  export interface DashboardProps<T extends string, State> {
@@ -33,21 +34,26 @@ export default function Dashboard<T extends string, State>({
33
34
  const formatSummaryValue = (value: unknown) =>
34
35
  typeof value === "number" || typeof value === "string" ? value.toLocaleString() : "";
35
36
  return (
36
- <div className={clsx("stats my-2 flex w-full flex-wrap justify-center py-0 shadow-sm", className)}>
37
- <div className="stats">
37
+ <div className={cn("my-2 flex w-full flex-wrap justify-center py-0 shadow-sm", className)}>
38
+ <div className="flex flex-wrap">
38
39
  {columns?.map(
39
40
  (column) =>
40
41
  summary[column] !== undefined &&
41
42
  queryMap[column] !== undefined && (
42
43
  <button
43
44
  key={column}
44
- className={`btn btn-ghost mx-1 h-32 w-48 rounded-none pt-3 hover:border ${
45
- filter === column ? "border" : "border-0"
46
- }`}
45
+ className={buttonRecipe({ variant: "ghost" }, [
46
+ "mx-1 h-32 w-48 rounded-none pt-3 hover:border",
47
+ filter === column ? "border" : "border-0",
48
+ ])}
47
49
  >
48
- <Link key={column} className="stat" href={`/admin?topMenu=data&subMenu=${modelName}&filter=${column}`}>
49
- <div className="stat-title">{l(`summary.${column}` as "base.new")}</div>
50
- <div className="stat-value text-primary">{formatSummaryValue(summary[column])}</div>
50
+ <Link
51
+ key={column}
52
+ className="flex flex-col gap-1"
53
+ href={`/admin?topMenu=data&subMenu=${modelName}&filter=${column}`}
54
+ >
55
+ <div className="text-foreground/60 text-xs">{l(`summary.${column}` as "base.new")}</div>
56
+ <div className="font-semibold text-2xl text-primary">{formatSummaryValue(summary[column])}</div>
51
57
  </Link>
52
58
  </button>
53
59
  ),
@@ -57,10 +63,13 @@ export default function Dashboard<T extends string, State>({
57
63
  (column) =>
58
64
  summary[column] !== undefined &&
59
65
  queryMap[column] !== undefined && (
60
- <button key={column} className={`btn btn-ghost mx-1 h-32 w-48 rounded-none border-none pt-3`}>
61
- <div className="stat">
62
- <div className="stat-title">{l(`summary.${column}` as "base.new")}</div>
63
- <div className="stat-value text-primary">{formatSummaryValue(summary[column])}</div>
66
+ <button
67
+ key={column}
68
+ className={buttonRecipe({ variant: "ghost" }, "mx-1 h-32 w-48 rounded-none border-none pt-3")}
69
+ >
70
+ <div className="flex flex-col gap-1">
71
+ <div className="text-foreground/60 text-xs">{l(`summary.${column}` as "base.new")}</div>
72
+ <div className="font-semibold text-2xl text-primary">{formatSummaryValue(summary[column])}</div>
64
73
  </div>
65
74
  </button>
66
75
  ),
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { clsx, usePage } from "akanjs/client";
2
+ import { cn, usePage } from "akanjs/client";
3
3
  import type { SliceMeta } from "akanjs/fetch";
4
4
 
5
5
  interface InsightProps<T extends string, Insight> {
@@ -18,14 +18,14 @@ export default function Insight<T extends string, Insight>({
18
18
  const { l } = usePage();
19
19
  const { refName } = slice;
20
20
  return (
21
- <div className={clsx("stats my-2 flex w-full flex-wrap justify-center py-2 shadow-sm", className)}>
22
- <div className="stats">
21
+ <div className={cn("my-2 flex w-full flex-wrap justify-center py-2 shadow-sm", className)}>
22
+ <div className="flex flex-wrap">
23
23
  {columns?.map(
24
24
  (column: keyof Insight, idx) =>
25
25
  insight[column] !== undefined && (
26
- <div key={column.toString()} className="stat mx-1 flex items-center rounded-none">
27
- <div className="stat-title">{l._(`${refName}.insight.${column as string}`)}</div>
28
- <div className="stat-value text-xl">{(insight[column] as string).toLocaleString()}</div>
26
+ <div key={column.toString()} className="mx-1 flex items-center gap-2 rounded-none px-6 py-4">
27
+ <div className="text-foreground/60 text-xs">{l._(`${refName}.insight.${column as string}`)}</div>
28
+ <div className="font-semibold text-xl">{(insight[column] as string).toLocaleString()}</div>
29
29
  </div>
30
30
  ),
31
31
  )}