astryx-dracula 0.5.0 → 0.6.2

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 (129) hide show
  1. package/BRAND.md +3 -3
  2. package/README.md +7 -4
  3. package/USAGE.md +49 -49
  4. package/astryx-dracula.d.ts +2 -2
  5. package/astryx-dracula.js +25 -9
  6. package/astryx-dracula.variants.d.ts +2 -2
  7. package/astryx.integration.mjs +1 -1
  8. package/icons.mjs +21 -17
  9. package/icons.tsx +69 -62
  10. package/package.json +125 -120
  11. package/shared/auth-chrome-config.ts +6 -6
  12. package/shared/auth-chrome.tsx +143 -144
  13. package/shared/auth-copy.ts +14 -14
  14. package/shared/chaptered-doc-config.ts +48 -51
  15. package/shared/chaptered-doc.tsx +267 -289
  16. package/shared/chart-hues.ts +25 -10
  17. package/shared/chart-labels.tsx +31 -30
  18. package/shared/chart-legend.tsx +55 -56
  19. package/shared/chart-panel-style.ts +3 -3
  20. package/shared/data-bar.tsx +97 -102
  21. package/shared/format-money.ts +1 -1
  22. package/shared/gallery-image.ts +6 -6
  23. package/shared/login-demo.ts +1 -1
  24. package/shared/metric-card.tsx +101 -105
  25. package/shared/metric-delta.tsx +28 -27
  26. package/shared/order-desk.tsx +205 -216
  27. package/shared/revenue-chart.tsx +145 -165
  28. package/shared/scene-castle.tsx +206 -291
  29. package/shared/scene-frame.tsx +33 -32
  30. package/shared/scene-hues.ts +17 -17
  31. package/shared/scene-tile.tsx +88 -92
  32. package/shared/settings-data.ts +119 -125
  33. package/shared/settings-rows.tsx +122 -159
  34. package/shared/sparkline.tsx +75 -88
  35. package/shared/sso-icons.tsx +10 -22
  36. package/shared/stars.tsx +16 -25
  37. package/templates/ai-chat-landing.template.mjs +5 -4
  38. package/templates/ai-chat-landing.tsx +473 -460
  39. package/templates/ai-chat.template.mjs +5 -4
  40. package/templates/ai-chat.tsx +543 -612
  41. package/templates/blank.template.mjs +5 -4
  42. package/templates/blank.tsx +18 -14
  43. package/templates/centered-hero.template.mjs +5 -4
  44. package/templates/centered-hero.tsx +55 -68
  45. package/templates/classic-gallery.template.mjs +5 -4
  46. package/templates/classic-gallery.tsx +97 -104
  47. package/templates/contact-form.template.mjs +5 -4
  48. package/templates/contact-form.tsx +247 -282
  49. package/templates/dashboard-portfolio.template.mjs +5 -4
  50. package/templates/dashboard-portfolio.tsx +717 -548
  51. package/templates/dashboard.template.mjs +5 -4
  52. package/templates/dashboard.tsx +596 -567
  53. package/templates/detail-page.template.mjs +5 -4
  54. package/templates/detail-page.tsx +546 -603
  55. package/templates/documentation-design.template.mjs +5 -4
  56. package/templates/documentation-design.tsx +231 -243
  57. package/templates/documentation-technical.template.mjs +5 -4
  58. package/templates/documentation-technical.tsx +236 -239
  59. package/templates/documentation.template.mjs +5 -4
  60. package/templates/documentation.tsx +267 -279
  61. package/templates/editor.template.mjs +5 -4
  62. package/templates/editor.tsx +844 -877
  63. package/templates/file-explorer.template.mjs +5 -4
  64. package/templates/file-explorer.tsx +566 -590
  65. package/templates/form-two-column.template.mjs +5 -4
  66. package/templates/form-two-column.tsx +195 -210
  67. package/templates/gallery-hero.template.mjs +5 -4
  68. package/templates/gallery-hero.tsx +93 -114
  69. package/templates/ide.template.mjs +5 -4
  70. package/templates/ide.tsx +407 -453
  71. package/templates/incident-console.template.mjs +5 -4
  72. package/templates/incident-console.tsx +593 -575
  73. package/templates/kanban-board.template.mjs +5 -4
  74. package/templates/kanban-board.tsx +665 -683
  75. package/templates/library.template.mjs +5 -4
  76. package/templates/library.tsx +409 -430
  77. package/templates/login-card.template.mjs +5 -4
  78. package/templates/login-card.tsx +63 -72
  79. package/templates/login-split.template.mjs +5 -4
  80. package/templates/login-split.tsx +192 -193
  81. package/templates/login-sso.template.mjs +5 -4
  82. package/templates/login-sso.tsx +257 -258
  83. package/templates/login.template.mjs +5 -4
  84. package/templates/login.tsx +53 -49
  85. package/templates/messaging-shell.template.mjs +5 -4
  86. package/templates/messaging-shell.tsx +556 -574
  87. package/templates/mixed-gallery.template.mjs +5 -4
  88. package/templates/mixed-gallery.tsx +60 -58
  89. package/templates/payment-form.template.mjs +5 -4
  90. package/templates/payment-form.tsx +882 -991
  91. package/templates/product-detail.template.mjs +5 -4
  92. package/templates/product-detail.tsx +261 -272
  93. package/templates/product-gallery.template.mjs +5 -4
  94. package/templates/product-gallery.tsx +126 -137
  95. package/templates/product-tour.template.mjs +5 -4
  96. package/templates/product-tour.tsx +741 -773
  97. package/templates/settings-dialog.template.mjs +5 -4
  98. package/templates/settings-dialog.tsx +688 -717
  99. package/templates/settings-sidebar.template.mjs +5 -4
  100. package/templates/settings-sidebar.tsx +762 -807
  101. package/templates/settings.template.mjs +5 -4
  102. package/templates/settings.tsx +289 -304
  103. package/templates/shell-nav.template.mjs +5 -4
  104. package/templates/shell-nav.tsx +212 -219
  105. package/templates/shell-side-nav.template.mjs +5 -4
  106. package/templates/shell-side-nav.tsx +135 -157
  107. package/templates/shell-top-nav.template.mjs +5 -4
  108. package/templates/shell-top-nav.tsx +182 -203
  109. package/templates/side-gallery.template.mjs +5 -4
  110. package/templates/side-gallery.tsx +85 -90
  111. package/templates/table-grouped.template.mjs +5 -4
  112. package/templates/table-grouped.tsx +1000 -1053
  113. package/templates/table-page-chart.template.mjs +5 -4
  114. package/templates/table-page-chart.tsx +400 -398
  115. package/templates/table-page-heatmap-status.template.mjs +5 -4
  116. package/templates/table-page-heatmap-status.tsx +483 -512
  117. package/templates/table-page-shoe-store-heatmap.template.mjs +5 -4
  118. package/templates/table-page-shoe-store-heatmap.tsx +748 -746
  119. package/templates/table-page.template.mjs +5 -4
  120. package/templates/table-page.tsx +396 -405
  121. package/templates/table.template.mjs +5 -4
  122. package/templates/table.tsx +92 -93
  123. package/templates/tech-report.template.mjs +5 -4
  124. package/templates/tech-report.tsx +1316 -1304
  125. package/templates/theme-showcase.template.mjs +5 -4
  126. package/templates/theme-showcase.tsx +871 -951
  127. package/theme.css +35 -77
  128. package/theme.css.d.ts +9 -0
  129. package/tokens.css +373 -380
@@ -1,436 +1,427 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > (LH[divider] > H[g=2 a=center] > (SI[fill] > Hd"Familiars"[level=1]) + IB"Filter"[variant=ghost] + IB"Download"[variant=ghost] + B.primary"Add") + (LC[p=3] > V[g=4] > PS + (T[hover] > (TR > THC*3) + (TR > TC*3)*3))
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=fill] > (LH[divider p=6] > H[g=2 a=center] > (SI[fill] > Hd"Familiars"[level=1 t=display-2]) + IB"Filter"[variant=ghost] + IB"Download"[variant=ghost] + B.primary"Add") + (LC[p=3] > V[g=4] > PS"Search familiars…" + (T[hover density=balanced dv=rows] > (TR > THC"Name" + THC"Biography" + THC"Age") + (TR > TC*3)*38))
4
6
 
5
7
  /**
6
8
  * Familiars — the full roster of the crypt's companions, with a PowerSearch field filter bar above one dense table. (Frame/responsive/container: see XLE header above.)
7
9
  */
8
10
 
9
- import {useState, useMemo} from 'react';
11
+ import { Avatar } from "@astryxdesign/core/Avatar";
12
+ import { Button } from "@astryxdesign/core/Button";
13
+ import { Icon } from "@astryxdesign/core/Icon";
14
+ import { IconButton } from "@astryxdesign/core/IconButton";
10
15
  import {
11
- VStack,
12
- HStack,
13
- StackItem,
14
- Layout,
15
- LayoutContent,
16
- LayoutHeader,
17
- } from '@astryxdesign/core/Layout';
18
- import {Text, Heading} from '@astryxdesign/core/Text';
19
- import {Button} from '@astryxdesign/core/Button';
20
- import {IconButton} from '@astryxdesign/core/IconButton';
21
- import {Icon} from '@astryxdesign/core/Icon';
22
- import {Avatar} from '@astryxdesign/core/Avatar';
23
- import {
24
- PowerSearch,
25
- usePowerSearchConfig,
26
- } from '@astryxdesign/core/PowerSearch';
27
- import type {PowerSearchFilter} from '@astryxdesign/core/PowerSearch';
28
- import {Table, proportional, pixel} from '@astryxdesign/core/Table';
29
- import type {TableColumn} from '@astryxdesign/core/Table';
30
- import {
31
- Filter,
32
- Download,
33
- Plus,
34
- } from 'lucide-react';
16
+ HStack,
17
+ Layout,
18
+ LayoutContent,
19
+ LayoutHeader,
20
+ StackItem,
21
+ VStack,
22
+ } from "@astryxdesign/core/Layout";
23
+ import type { PowerSearchFilter } from "@astryxdesign/core/PowerSearch";
24
+ import { PowerSearch, usePowerSearchConfig } from "@astryxdesign/core/PowerSearch";
25
+ import type { TableColumn } from "@astryxdesign/core/Table";
26
+ import { pixel, proportional, Table } from "@astryxdesign/core/Table";
27
+ import { Heading, Text } from "@astryxdesign/core/Text";
28
+ import { Download, Filter, Plus } from "lucide-react";
29
+ import { useMemo, useState } from "react";
35
30
 
36
31
  interface FamiliarRow extends Record<string, unknown> {
37
- id: string;
38
- name: string;
39
- kind: string;
40
- biography: string;
41
- age: number;
32
+ id: string;
33
+ name: string;
34
+ kind: string;
35
+ biography: string;
36
+ age: number;
42
37
  }
43
38
 
44
39
  const allFamiliars: FamiliarRow[] = [
45
- {
46
- id: '1',
47
- name: 'Vlad',
48
- kind: 'Vampire Bat',
49
- biography:
50
- 'I love brooding in the belfry and hate garlic bread, and you might wonder how well those things mix. The answer is "not that well."',
51
- age: 17,
52
- },
53
- {
54
- id: '2',
55
- name: 'Alucard',
56
- kind: 'Black Cat',
57
- biography: 'This is a black cat summoned by crossing the lobby at midnight',
58
- age: 2,
59
- },
60
- {
61
- id: '3',
62
- name: 'Archer',
63
- kind: 'Hellhound',
64
- biography:
65
- "I'm an 8 year old direwolf and I haunt the moors with my mom and dad.",
66
- age: 9,
67
- },
68
- {
69
- id: '4',
70
- name: 'Archie',
71
- kind: 'Raven',
72
- biography: 'Carrion crow at heart, raven by trade.',
73
- age: 5,
74
- },
75
- {
76
- id: '5',
77
- name: 'Argos',
78
- kind: 'Bloodhound',
79
- biography: 'Faithful hellhound who never gives up the scent.',
80
- age: 23,
81
- },
82
- {
83
- id: '6',
84
- name: 'Banjo',
85
- kind: 'Imp',
86
- biography:
87
- "Banjo was rescued from a cursed carnival in Concord, CA. He's a mischievous imp that loves to juggle skulls on the beach.",
88
- age: 9,
89
- },
90
- {
91
- id: '7',
92
- name: 'Barley',
93
- kind: 'Wisp',
94
- biography: 'Teacup-sized wisp with a full-sized haunting.',
95
- age: 4,
96
- },
97
- {
98
- id: '8',
99
- name: 'Beast',
100
- kind: 'Iron Boar',
101
- biography: 'Summers in Transylvania, winters in the crypt.',
102
- age: 14,
103
- },
104
- {
105
- id: '9',
106
- name: 'Belki',
107
- kind: 'Mist Ferret',
108
- biography: 'Belki is actually three bats in an overcoat.',
109
- age: 6,
110
- },
111
- {
112
- id: '10',
113
- name: 'Bella',
114
- kind: 'Obsidian Panther',
115
- biography: 'Shadow panther by day, lap cat by night.',
116
- age: 10,
117
- },
118
- {
119
- id: '11',
120
- name: 'Brienne',
121
- kind: 'Thorn Hedgehog',
122
- biography: 'Brienne of Bark, the cream mini hedgehog.',
123
- age: 7,
124
- },
125
- {
126
- id: '12',
127
- name: 'Bruno',
128
- kind: 'Gargoyle',
129
- biography:
130
- "Bruno is a gargoyle. He's a stony fellow. I never needed more than a day to teach him to scowl.",
131
- age: 5,
132
- },
133
- {
134
- id: '13',
135
- name: 'Cabo',
136
- kind: 'Swamp Rat',
137
- biography:
138
- 'Cabo is a mix of swamp rat, imp, and unknown. Fat and grumpy but lovable.',
139
- age: 9,
140
- },
141
- {
142
- id: '14',
143
- name: 'Chai',
144
- kind: 'Moon Moth',
145
- biography: 'Moonlight and graveyards are the only two things that matter.',
146
- age: 1,
147
- },
148
- {
149
- id: '15',
150
- name: 'Charlie',
151
- kind: 'Direwolf',
152
- biography: 'The goodest boy in the whole haunted wood.',
153
- age: 3,
154
- },
155
- {
156
- id: '16',
157
- name: 'Coco',
158
- kind: 'Coffin Beetle',
159
- biography: 'Loves coffins and crumbs more than anything.',
160
- age: 6,
161
- },
162
- {
163
- id: '17',
164
- name: 'Daisy',
165
- kind: 'Bloodhound',
166
- biography: 'Will follow any blood trail anywhere, anytime.',
167
- age: 8,
168
- },
169
- {
170
- id: '18',
171
- name: 'Duke',
172
- kind: 'Hellhound',
173
- biography: 'Guard hound by day, couch potato by night.',
174
- age: 11,
175
- },
176
- {
177
- id: '19',
178
- name: 'Ella',
179
- kind: 'Nightmare Mare',
180
- biography: 'Short legs, big nightmares, endless midnight gallops.',
181
- age: 4,
182
- },
183
- {
184
- id: '20',
185
- name: 'Finn',
186
- kind: 'Frost Lynx',
187
- biography: 'Loves snowstorms and howling at the blood moon.',
188
- age: 7,
189
- },
190
- {
191
- id: '21',
192
- name: 'Ginger',
193
- kind: 'Ember Salamander',
194
- biography: 'Red and rambunctious with boundless hellfire.',
195
- age: 5,
196
- },
197
- {
198
- id: '22',
199
- name: 'Hank',
200
- kind: 'Grave Toad',
201
- biography: 'Warts for days and a croak that never quits.',
202
- age: 9,
203
- },
204
- {
205
- id: '23',
206
- name: 'Izzy',
207
- kind: 'Shadow Fox',
208
- biography: 'Smarter than most necromancers I know.',
209
- age: 3,
210
- },
211
- {
212
- id: '24',
213
- name: 'Jax',
214
- kind: 'Iron Boar',
215
- biography: 'Gentle giant who loves kids and belly scratches.',
216
- age: 6,
217
- },
218
- {
219
- id: '25',
220
- name: 'Koda',
221
- kind: 'Obsidian Panther',
222
- biography: 'Loyal, fluffy, and fiercely protective of the crypt.',
223
- age: 8,
224
- },
225
- {
226
- id: '26',
227
- name: 'Luna',
228
- kind: 'Night Owl',
229
- biography: 'A cloud on silent wings with a permanent stare.',
230
- age: 2,
231
- },
232
- {
233
- id: '27',
234
- name: 'Max',
235
- kind: 'Gargoyle',
236
- biography: 'Looks tough, but melts for ear scratches.',
237
- age: 10,
238
- },
239
- {
240
- id: '28',
241
- name: 'Nala',
242
- kind: 'Sable Marten',
243
- biography: 'Hypoallergenic and proud of it.',
244
- age: 4,
245
- },
246
- {
247
- id: '29',
248
- name: 'Oscar',
249
- kind: 'Cave Eel',
250
- biography: 'Long boy of the underground rivers with big dreams.',
251
- age: 12,
252
- },
253
- {
254
- id: '30',
255
- name: 'Penny',
256
- kind: 'Moon Moth',
257
- biography: 'Lap moth extraordinaire and candle connoisseur.',
258
- age: 7,
259
- },
260
- {
261
- id: '31',
262
- name: 'Rex',
263
- kind: 'Hellhound',
264
- biography: 'Fast, fearless, and first to the blood bowl.',
265
- age: 5,
266
- },
267
- {
268
- id: '32',
269
- name: 'Sadie',
270
- kind: 'Direwolf',
271
- biography: 'Herds everything, including the ghosts.',
272
- age: 3,
273
- },
274
- {
275
- id: '33',
276
- name: 'Tucker',
277
- kind: 'Bloodhound',
278
- biography: 'Tennis ball enthusiast and professional fetcher of bones.',
279
- age: 6,
280
- },
281
- {
282
- id: '34',
283
- name: 'Willow',
284
- kind: 'Nightmare Mare',
285
- biography: 'Retired racer, full-time lounger in the mist.',
286
- age: 8,
287
- },
288
- {
289
- id: '35',
290
- name: 'Zeus',
291
- kind: 'Gargoyle',
292
- biography: 'Thinks he is a lap gargoyle despite weighing 150 lbs.',
293
- age: 4,
294
- },
295
- {
296
- id: '36',
297
- name: 'Rosie',
298
- kind: 'Imp',
299
- biography: 'Tiny but mighty with a cackle bigger than her bite.',
300
- age: 2,
301
- },
302
- {
303
- id: '37',
304
- name: 'Scout',
305
- kind: 'Raven',
306
- biography: 'Adventure buddy who never says no to a midnight flight.',
307
- age: 5,
308
- },
309
- {
310
- id: '38',
311
- name: 'Teddy',
312
- kind: 'Albino Crocodile',
313
- biography: 'Gentle giant of the castle moat.',
314
- age: 7,
315
- },
40
+ {
41
+ id: "1",
42
+ name: "Vlad",
43
+ kind: "Vampire Bat",
44
+ biography:
45
+ 'I love brooding in the belfry and hate garlic bread, and you might wonder how well those things mix. The answer is "not that well."',
46
+ age: 17,
47
+ },
48
+ {
49
+ id: "2",
50
+ name: "Alucard",
51
+ kind: "Black Cat",
52
+ biography: "This is a black cat summoned by crossing the lobby at midnight",
53
+ age: 2,
54
+ },
55
+ {
56
+ id: "3",
57
+ name: "Archer",
58
+ kind: "Hellhound",
59
+ biography: "I'm an 8 year old direwolf and I haunt the moors with my mom and dad.",
60
+ age: 9,
61
+ },
62
+ {
63
+ id: "4",
64
+ name: "Archie",
65
+ kind: "Raven",
66
+ biography: "Carrion crow at heart, raven by trade.",
67
+ age: 5,
68
+ },
69
+ {
70
+ id: "5",
71
+ name: "Argos",
72
+ kind: "Bloodhound",
73
+ biography: "Faithful hellhound who never gives up the scent.",
74
+ age: 23,
75
+ },
76
+ {
77
+ id: "6",
78
+ name: "Banjo",
79
+ kind: "Imp",
80
+ biography:
81
+ "Banjo was rescued from a cursed carnival in Concord, CA. He's a mischievous imp that loves to juggle skulls on the beach.",
82
+ age: 9,
83
+ },
84
+ {
85
+ id: "7",
86
+ name: "Barley",
87
+ kind: "Wisp",
88
+ biography: "Teacup-sized wisp with a full-sized haunting.",
89
+ age: 4,
90
+ },
91
+ {
92
+ id: "8",
93
+ name: "Beast",
94
+ kind: "Iron Boar",
95
+ biography: "Summers in Transylvania, winters in the crypt.",
96
+ age: 14,
97
+ },
98
+ {
99
+ id: "9",
100
+ name: "Belki",
101
+ kind: "Mist Ferret",
102
+ biography: "Belki is actually three bats in an overcoat.",
103
+ age: 6,
104
+ },
105
+ {
106
+ id: "10",
107
+ name: "Bella",
108
+ kind: "Obsidian Panther",
109
+ biography: "Shadow panther by day, lap cat by night.",
110
+ age: 10,
111
+ },
112
+ {
113
+ id: "11",
114
+ name: "Brienne",
115
+ kind: "Thorn Hedgehog",
116
+ biography: "Brienne of Bark, the cream mini hedgehog.",
117
+ age: 7,
118
+ },
119
+ {
120
+ id: "12",
121
+ name: "Bruno",
122
+ kind: "Gargoyle",
123
+ biography:
124
+ "Bruno is a gargoyle. He's a stony fellow. I never needed more than a day to teach him to scowl.",
125
+ age: 5,
126
+ },
127
+ {
128
+ id: "13",
129
+ name: "Cabo",
130
+ kind: "Swamp Rat",
131
+ biography: "Cabo is a mix of swamp rat, imp, and unknown. Fat and grumpy but lovable.",
132
+ age: 9,
133
+ },
134
+ {
135
+ id: "14",
136
+ name: "Chai",
137
+ kind: "Moon Moth",
138
+ biography: "Moonlight and graveyards are the only two things that matter.",
139
+ age: 1,
140
+ },
141
+ {
142
+ id: "15",
143
+ name: "Charlie",
144
+ kind: "Direwolf",
145
+ biography: "The goodest boy in the whole haunted wood.",
146
+ age: 3,
147
+ },
148
+ {
149
+ id: "16",
150
+ name: "Coco",
151
+ kind: "Coffin Beetle",
152
+ biography: "Loves coffins and crumbs more than anything.",
153
+ age: 6,
154
+ },
155
+ {
156
+ id: "17",
157
+ name: "Daisy",
158
+ kind: "Bloodhound",
159
+ biography: "Will follow any blood trail anywhere, anytime.",
160
+ age: 8,
161
+ },
162
+ {
163
+ id: "18",
164
+ name: "Duke",
165
+ kind: "Hellhound",
166
+ biography: "Guard hound by day, couch potato by night.",
167
+ age: 11,
168
+ },
169
+ {
170
+ id: "19",
171
+ name: "Ella",
172
+ kind: "Nightmare Mare",
173
+ biography: "Short legs, big nightmares, endless midnight gallops.",
174
+ age: 4,
175
+ },
176
+ {
177
+ id: "20",
178
+ name: "Finn",
179
+ kind: "Frost Lynx",
180
+ biography: "Loves snowstorms and howling at the blood moon.",
181
+ age: 7,
182
+ },
183
+ {
184
+ id: "21",
185
+ name: "Ginger",
186
+ kind: "Ember Salamander",
187
+ biography: "Red and rambunctious with boundless hellfire.",
188
+ age: 5,
189
+ },
190
+ {
191
+ id: "22",
192
+ name: "Hank",
193
+ kind: "Grave Toad",
194
+ biography: "Warts for days and a croak that never quits.",
195
+ age: 9,
196
+ },
197
+ {
198
+ id: "23",
199
+ name: "Izzy",
200
+ kind: "Shadow Fox",
201
+ biography: "Smarter than most necromancers I know.",
202
+ age: 3,
203
+ },
204
+ {
205
+ id: "24",
206
+ name: "Jax",
207
+ kind: "Iron Boar",
208
+ biography: "Gentle giant who loves kids and belly scratches.",
209
+ age: 6,
210
+ },
211
+ {
212
+ id: "25",
213
+ name: "Koda",
214
+ kind: "Obsidian Panther",
215
+ biography: "Loyal, fluffy, and fiercely protective of the crypt.",
216
+ age: 8,
217
+ },
218
+ {
219
+ id: "26",
220
+ name: "Luna",
221
+ kind: "Night Owl",
222
+ biography: "A cloud on silent wings with a permanent stare.",
223
+ age: 2,
224
+ },
225
+ {
226
+ id: "27",
227
+ name: "Max",
228
+ kind: "Gargoyle",
229
+ biography: "Looks tough, but melts for ear scratches.",
230
+ age: 10,
231
+ },
232
+ {
233
+ id: "28",
234
+ name: "Nala",
235
+ kind: "Sable Marten",
236
+ biography: "Hypoallergenic and proud of it.",
237
+ age: 4,
238
+ },
239
+ {
240
+ id: "29",
241
+ name: "Oscar",
242
+ kind: "Cave Eel",
243
+ biography: "Long boy of the underground rivers with big dreams.",
244
+ age: 12,
245
+ },
246
+ {
247
+ id: "30",
248
+ name: "Penny",
249
+ kind: "Moon Moth",
250
+ biography: "Lap moth extraordinaire and candle connoisseur.",
251
+ age: 7,
252
+ },
253
+ {
254
+ id: "31",
255
+ name: "Rex",
256
+ kind: "Hellhound",
257
+ biography: "Fast, fearless, and first to the blood bowl.",
258
+ age: 5,
259
+ },
260
+ {
261
+ id: "32",
262
+ name: "Sadie",
263
+ kind: "Direwolf",
264
+ biography: "Herds everything, including the ghosts.",
265
+ age: 3,
266
+ },
267
+ {
268
+ id: "33",
269
+ name: "Tucker",
270
+ kind: "Bloodhound",
271
+ biography: "Tennis ball enthusiast and professional fetcher of bones.",
272
+ age: 6,
273
+ },
274
+ {
275
+ id: "34",
276
+ name: "Willow",
277
+ kind: "Nightmare Mare",
278
+ biography: "Retired racer, full-time lounger in the mist.",
279
+ age: 8,
280
+ },
281
+ {
282
+ id: "35",
283
+ name: "Zeus",
284
+ kind: "Gargoyle",
285
+ biography: "Thinks he is a lap gargoyle despite weighing 150 lbs.",
286
+ age: 4,
287
+ },
288
+ {
289
+ id: "36",
290
+ name: "Rosie",
291
+ kind: "Imp",
292
+ biography: "Tiny but mighty with a cackle bigger than her bite.",
293
+ age: 2,
294
+ },
295
+ {
296
+ id: "37",
297
+ name: "Scout",
298
+ kind: "Raven",
299
+ biography: "Adventure buddy who never says no to a midnight flight.",
300
+ age: 5,
301
+ },
302
+ {
303
+ id: "38",
304
+ name: "Teddy",
305
+ kind: "Albino Crocodile",
306
+ biography: "Gentle giant of the castle moat.",
307
+ age: 7,
308
+ },
316
309
  ];
317
310
 
318
- const kindValues = Array.from(new Set(allFamiliars.map(f => f.kind)), kind => ({
319
- value: kind,
320
- label: kind,
311
+ const kindValues = Array.from(new Set(allFamiliars.map((f) => f.kind)), (kind) => ({
312
+ value: kind,
313
+ label: kind,
321
314
  }));
322
315
 
323
316
  const fieldDefs = [
324
- {key: 'name', type: 'string', label: 'Name'},
325
- {key: 'kind', type: 'enum', label: 'Kind', enumValues: kindValues},
326
- {key: 'biography', type: 'string', label: 'Biography'},
317
+ { key: "name", type: "string", label: "Name" },
318
+ { key: "kind", type: "enum", label: "Kind", enumValues: kindValues },
319
+ { key: "biography", type: "string", label: "Biography" },
327
320
  ] as const;
328
321
 
329
322
  const columns: TableColumn<FamiliarRow>[] = [
330
- {
331
- key: 'name',
332
- header: 'Name',
333
- width: proportional(2),
334
- renderCell: (item: FamiliarRow) => (
335
- <HStack gap={3} vAlign="center">
336
- <Avatar name={item.name} size="md" />
337
- <StackItem size="fill">
338
- <VStack gap={0}>
339
- <Text type="body" maxLines={1}>
340
- {item.name}
341
- </Text>
342
- <Text type="supporting" color="secondary" maxLines={1}>
343
- {item.kind}
344
- </Text>
345
- </VStack>
346
- </StackItem>
347
- </HStack>
348
- ),
349
- },
350
- {
351
- key: 'biography',
352
- header: 'Biography',
353
- width: proportional(5),
354
- renderCell: (item: FamiliarRow) => <Text type="body">{item.biography}</Text>,
355
- },
356
- {
357
- key: 'age',
358
- header: 'Age',
359
- width: pixel(80),
360
- renderCell: (item: FamiliarRow) => (
361
- <Text type="body" hasTabularNumbers>
362
- {item.age}
363
- </Text>
364
- ),
365
- },
323
+ {
324
+ key: "name",
325
+ header: "Name",
326
+ width: proportional(2),
327
+ renderCell: (item: FamiliarRow) => (
328
+ <HStack gap={3} vAlign="center">
329
+ <Avatar name={item.name} size="md" />
330
+ <StackItem size="fill">
331
+ <VStack gap={0}>
332
+ <Text type="body" maxLines={1}>
333
+ {item.name}
334
+ </Text>
335
+ <Text type="supporting" color="secondary" maxLines={1}>
336
+ {item.kind}
337
+ </Text>
338
+ </VStack>
339
+ </StackItem>
340
+ </HStack>
341
+ ),
342
+ },
343
+ {
344
+ key: "biography",
345
+ header: "Biography",
346
+ width: proportional(5),
347
+ renderCell: (item: FamiliarRow) => <Text type="body">{item.biography}</Text>,
348
+ },
349
+ {
350
+ key: "age",
351
+ header: "Age",
352
+ width: pixel(80),
353
+ renderCell: (item: FamiliarRow) => (
354
+ <Text type="body" hasTabularNumbers>
355
+ {item.age}
356
+ </Text>
357
+ ),
358
+ },
366
359
  ];
367
360
 
368
361
  export default function TablePage() {
369
- const [filters, setFilters] = useState<PowerSearchFilter[]>([]);
370
- const {config, applyFilters} = usePowerSearchConfig(fieldDefs, 'Familiars');
362
+ const [filters, setFilters] = useState<PowerSearchFilter[]>([]);
363
+ const { config, applyFilters } = usePowerSearchConfig(fieldDefs, "Familiars");
371
364
 
372
- const filtered = useMemo(() => {
373
- return applyFilters(filters, allFamiliars);
374
- }, [filters, applyFilters]);
365
+ const filtered = useMemo(() => {
366
+ return applyFilters(filters, allFamiliars);
367
+ }, [filters, applyFilters]);
375
368
 
376
- return (
377
- <Layout
378
- height="fill"
379
- header={
380
- <LayoutHeader hasDivider padding={6}>
381
- <HStack gap={2} vAlign="center">
382
- <StackItem size="fill">
383
- {/* maxLines={1} for symmetry with the other order-desk headers.
369
+ return (
370
+ <Layout
371
+ height="fill"
372
+ header={
373
+ <LayoutHeader hasDivider padding={6}>
374
+ <HStack gap={2} vAlign="center">
375
+ <StackItem size="fill">
376
+ {/* maxLines={1} for symmetry with the other order-desk headers.
384
377
  "Familiars" measures 189px at 35px and fits on one line today,
385
378
  so this is a floor against a longer title rather than a fix
386
379
  for a visible break — but the row has 129.2px of controls and
387
380
  24px of gaps against a 342px content box, so it has ~0px of
388
381
  slack. Tooltip keeps the full value reachable (SC 1.4.10). */}
389
- <Heading level={1} type="display-2" maxLines={1}>Familiars</Heading>
390
- </StackItem>
391
- <IconButton
392
- label="Filter"
393
- icon={<Icon icon={Filter} size="sm" />}
394
- variant="ghost"
395
- tooltip="Filter"
396
- />
397
- <IconButton
398
- label="Download"
399
- icon={<Icon icon={Download} size="sm" />}
400
- variant="ghost"
401
- tooltip="Export"
402
- />
403
- <Button
404
- label="Add"
405
- variant="primary"
406
- icon={<Icon icon={Plus} size="sm" />}
407
- />
408
- </HStack>
409
- </LayoutHeader>
410
- }
411
- content={
412
- <LayoutContent padding={3}>
413
- <VStack gap={4}>
414
- <PowerSearch
415
- config={config}
416
- filters={filters}
417
- onChange={newFilters => {
418
- setFilters([...newFilters]);
419
- }}
420
- placeholder="Search familiars…"
421
- resultCount={filtered.length}
422
- />
423
- <Table<FamiliarRow>
424
- data={filtered}
425
- columns={columns}
426
- idKey="id"
427
- density="balanced"
428
- dividers="rows"
429
- hasHover
430
- />
431
- </VStack>
432
- </LayoutContent>
433
- }
434
- />
435
- );
382
+ <Heading level={1} type="display-2" maxLines={1}>
383
+ Familiars
384
+ </Heading>
385
+ </StackItem>
386
+ <IconButton
387
+ label="Filter"
388
+ icon={<Icon icon={Filter} size="sm" />}
389
+ variant="ghost"
390
+ tooltip="Filter"
391
+ />
392
+ <IconButton
393
+ label="Download"
394
+ icon={<Icon icon={Download} size="sm" />}
395
+ variant="ghost"
396
+ tooltip="Export"
397
+ />
398
+ <Button label="Add" variant="primary" icon={<Icon icon={Plus} size="sm" />} />
399
+ </HStack>
400
+ </LayoutHeader>
401
+ }
402
+ content={
403
+ <LayoutContent padding={3}>
404
+ <VStack gap={4}>
405
+ <PowerSearch
406
+ config={config}
407
+ filters={filters}
408
+ onChange={(newFilters) => {
409
+ setFilters([...newFilters]);
410
+ }}
411
+ placeholder="Search familiars…"
412
+ resultCount={filtered.length}
413
+ />
414
+ <Table<FamiliarRow>
415
+ data={filtered}
416
+ columns={columns}
417
+ idKey="id"
418
+ density="balanced"
419
+ dividers="rows"
420
+ hasHover
421
+ />
422
+ </VStack>
423
+ </LayoutContent>
424
+ }
425
+ />
426
+ );
436
427
  }