astryx-dracula 0.6.2 → 0.7.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 (59) hide show
  1. package/BRAND.md +54 -3
  2. package/README.md +11 -4
  3. package/USAGE.md +1 -1
  4. package/astryx-dracula.d.ts +2 -2
  5. package/astryx-dracula.js +26 -4
  6. package/astryx-dracula.variants.d.ts +2 -2
  7. package/package.json +11 -11
  8. package/shared/auth-chrome-config.ts +0 -4
  9. package/shared/auth-chrome.tsx +2 -3
  10. package/shared/chaptered-doc-config.ts +3 -2
  11. package/shared/order-desk.tsx +52 -54
  12. package/shared/revenue-chart.tsx +1 -1
  13. package/shared/scene-castle.tsx +21 -13
  14. package/templates/ai-chat-landing.tsx +6 -9
  15. package/templates/ai-chat.tsx +5 -1
  16. package/templates/centered-hero.tsx +2 -2
  17. package/templates/classic-gallery.tsx +5 -0
  18. package/templates/contact-form.tsx +9 -0
  19. package/templates/dashboard-portfolio.tsx +17 -4
  20. package/templates/dashboard.tsx +5 -5
  21. package/templates/detail-page.tsx +20 -28
  22. package/templates/documentation-design.tsx +3 -0
  23. package/templates/documentation-technical.tsx +8 -5
  24. package/templates/documentation.tsx +13 -6
  25. package/templates/form-two-column.tsx +11 -2
  26. package/templates/form-wizard.template.mjs +15 -0
  27. package/templates/form-wizard.tsx +878 -0
  28. package/templates/gallery-hero.tsx +10 -4
  29. package/templates/ide.tsx +177 -96
  30. package/templates/incident-console.tsx +15 -5
  31. package/templates/kanban-board.tsx +46 -4
  32. package/templates/library.tsx +12 -3
  33. package/templates/login-split.tsx +3 -3
  34. package/templates/login-sso.tsx +9 -17
  35. package/templates/messaging-shell.tsx +109 -46
  36. package/templates/mixed-gallery.tsx +6 -0
  37. package/templates/payment-form.tsx +29 -28
  38. package/templates/product-detail.tsx +12 -3
  39. package/templates/product-gallery.tsx +8 -3
  40. package/templates/product-tour.tsx +11 -7
  41. package/templates/settings-dialog.tsx +5 -0
  42. package/templates/settings-sidebar.tsx +603 -584
  43. package/templates/settings.tsx +5 -2
  44. package/templates/shell-nav.tsx +23 -3
  45. package/templates/shell-side-nav.tsx +94 -81
  46. package/templates/shell-top-nav.tsx +98 -86
  47. package/templates/table-grouped.tsx +146 -132
  48. package/templates/{table-page-shoe-store-heatmap.template.mjs → table-page-shoe-store.template.mjs} +1 -1
  49. package/templates/{table-page-shoe-store-heatmap.tsx → table-page-shoe-store.tsx} +1 -1
  50. package/templates/table-page.tsx +8 -0
  51. package/templates/table-tree.template.mjs +16 -0
  52. package/templates/table-tree.tsx +707 -0
  53. package/templates/tech-report.tsx +8 -5
  54. package/templates/theme-showcase.tsx +18 -11
  55. package/templates/work-item-detail.template.mjs +8 -0
  56. package/templates/work-item-detail.tsx +1049 -0
  57. package/theme.css +38 -3
  58. package/theme.css.d.ts +2 -2
  59. package/tokens.css +41 -4
@@ -2,7 +2,7 @@
2
2
  // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
3
  // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
4
  // human drift check — update it with the file, never alone):
5
- // L[h=fill] > (LH[divider p=6] > V[g=4] > (H[g=3 a=center wrap] > (SI[fill] > Hd"Night-shift issues"[level=1 t=display-2]) + B.primary"Raise issue"[opens=#raise-issue]) + (H[g=2 a=center] > (SI[fill] > PS"Filter issues…") + (Po > (B.secondary"View options" + (V[g=4] > RL"Group by" > RLI*5))))) + (LC[p=0] > T[hover density=balanced dv=rows] > (TR > THC*7) + ((TR > TC[colSpan=7] > (H[g=2 a=center] > Ic + Tx"In Progress"[t=body] + Bd.neutral"3")) + (TR > TC*7))*4)) + (LP[divider p=4] > V[g=4] > (H[g=2 a=center] > (SI[fill] > Tx[t=supporting]) + B.ghost"Close panel") + (V[g=1] > Hd[level=2] + Tx[t=body]) + (ML > MLI*6) + (D + (V[g=2] > Tx"Labels"[t=label] + (H[g=2] > Tk*2)))) ;; Dlg#raise-issue > L[h=auto] > (DH"Raise issue" + (LC[p=4] > V[g=4] > TI"Title" + SE{Selector}"Status" + SE{Selector}"Priority" + TI"Project") + (LF[divider] > H[g=2 j=end] > B.secondary"Cancel" + B.primary"Raise issue"))
5
+ // L[h=fill] > (LH[divider p=6] > V[g=4] > (H[g=3 a=center wrap] > (SI[fill] > Hd"Night-shift issues"[level=1 t=display-2]) + B.primary"Raise issue"[opens=#raise-issue]) + (H[g=2 a=center] > (SI[fill] > PS"Filter issues…") + (Po > (B.secondary"View options" + (V[g=4] > RL"Group by" > RLI*5))))) + (LC[p=0] > T[hover density=balanced dv=rows] > (TR > THC*7) + ((TR > TC[colSpan=7] > (H[g=2 a=center] > Ic + Tx"In Progress"[t=body] + Bd.neutral"6")) + (TR > TC*7))*4)) + (LP[divider p=4] > V[g=4] > (H[g=2 a=center] > (SI[fill] > Tx[t=supporting]) + B.ghost"Close panel") + (V[g=1] > Hd[level=2] + Tx[t=body]) + (ML > MLI*6) + (D + (V[g=2] > Tx"Labels"[t=label] + (H[g=2] > Tk*2)))) ;; Dlg#raise-issue > L[h=auto] > (DH"Raise issue" + (LC[p=4] > V[g=4] > TI"Title" + SE{Selector}"Status" + SE{Selector}"Priority" + TI"Project") + (LF[divider] > H[g=2 j=end] > B.secondary"Cancel" + B.primary"Raise issue"))
6
6
 
7
7
  /**
8
8
  * Table Grouped — the night-shift issue tracker: a grouped, collapsible issue table with a PowerSearch bar and a resizable detail inspector. (Frame/responsive/container: see XLE header above.)
@@ -41,7 +41,9 @@ import {
41
41
  proportional,
42
42
  resolveColumnWidths,
43
43
  Table,
44
+ TableBody,
44
45
  TableCell,
46
+ TableHeader,
45
47
  TableHeaderCell,
46
48
  TableRow,
47
49
  } from "@astryxdesign/core/Table";
@@ -73,6 +75,12 @@ const groupHeaderCell: React.CSSProperties = {
73
75
  padding: "var(--spacing-3) var(--spacing-4)",
74
76
  };
75
77
 
78
+ // A definite ancestor for the page's `Layout height="fill"`. 100dvh, not
79
+ // minHeight: '100%': a percentage min-height against an indefinite containing
80
+ // block computes to 0 (CSS 2.1 10.5), so the document would keep the scroll
81
+ // instead of the content pane. Same shape as dashboard.tsx.
82
+ const pageStyle: React.CSSProperties = { height: "100dvh" };
83
+
76
84
  // Types
77
85
  type TaskStatus = "in_progress" | "todo" | "backlog" | "done";
78
86
  type TaskPriority = "urgent" | "high" | "medium" | "low" | "none";
@@ -810,6 +818,7 @@ export default function TableGrouped() {
810
818
  return (
811
819
  <>
812
820
  <Layout
821
+ style={pageStyle}
813
822
  height="fill"
814
823
  header={
815
824
  <LayoutHeader hasDivider padding={6}>
@@ -884,149 +893,154 @@ export default function TableGrouped() {
884
893
  `columns` so the labels and the widths cannot drift, and as
885
894
  real <th scope="col"> cells so the association reaches
886
895
  assistive tech. */}
887
- <TableRow>
888
- {columns.map((col) => (
889
- <TableHeaderCell key={col.key} scope="col">
890
- {col.header}
891
- </TableHeaderCell>
892
- ))}
893
- </TableRow>
894
- {groupKeys.map((key) => {
895
- const tasks = grouped.get(key);
896
- if (!tasks || tasks.length === 0) {
897
- return null;
898
- }
899
- const isExpanded = expandedGroups.has(key);
896
+ <TableHeader>
897
+ <TableRow>
898
+ {columns.map((col) => (
899
+ <TableHeaderCell key={col.key} scope="col">
900
+ {col.header}
901
+ </TableHeaderCell>
902
+ ))}
903
+ </TableRow>
904
+ </TableHeader>
905
+ <TableBody>
906
+ {groupKeys.map((key) => {
907
+ const tasks = grouped.get(key);
908
+ if (!tasks || tasks.length === 0) {
909
+ return null;
910
+ }
911
+ const isExpanded = expandedGroups.has(key);
900
912
 
901
- return (
902
- <React.Fragment key={key}>
903
- {groupBy !== "none" && (
904
- <TableRow
905
- role="button"
906
- tabIndex={0}
907
- onClick={() => toggleGroup(key)}
908
- onKeyDown={(e) => {
909
- if (e.key === "Enter" || e.key === " ") {
910
- e.preventDefault();
911
- toggleGroup(key);
912
- }
913
- }}
914
- >
915
- <TableCell colSpan={columns.length} style={groupHeaderCell}>
916
- <HStack gap={2} vAlign="center">
917
- <Icon
918
- icon={isExpanded ? ChevronDown : ChevronRight}
919
- size="sm"
920
- color="secondary"
921
- />
922
- <Text type="body" weight="semibold">
923
- {getGroupLabel(groupBy, key)}
924
- </Text>
925
- <Badge variant="neutral" label={String(tasks.length)} />
926
- </HStack>
927
- </TableCell>
928
- </TableRow>
929
- )}
930
- {(groupBy === "none" || isExpanded) &&
931
- tasks.map((task) => (
932
- <TableRow key={task.id} onClick={() => setSelectedTask(task)}>
933
- <TableCell>
934
- {/* StatusDot paints nothing but an 8px dot — its
935
- label is aria-label on a role="img" span — so
936
- four states here read as hue alone. Same
937
- dot-plus-word pairing as the Status entry in
938
- TaskDetailPanel's MetadataList. */}
939
- <HStack gap={1} vAlign="center">
940
- <StatusDot
941
- variant={STATUS_DOT_VARIANT[task.status]}
942
- label={STATUS_LABEL[task.status]}
943
- isPulsing={task.status === "in_progress"}
944
- />
945
- <Text type="supporting" color="secondary">
946
- {STATUS_LABEL[task.status]}
947
- </Text>
948
- </HStack>
949
- </TableCell>
950
- <TableCell>
951
- <HStack gap={3} vAlign="center" wrap="wrap">
913
+ return (
914
+ <React.Fragment key={key}>
915
+ {groupBy !== "none" && (
916
+ <TableRow
917
+ role="button"
918
+ tabIndex={0}
919
+ aria-expanded={isExpanded}
920
+ onClick={() => toggleGroup(key)}
921
+ onKeyDown={(e) => {
922
+ if (e.key === "Enter" || e.key === " ") {
923
+ e.preventDefault();
924
+ toggleGroup(key);
925
+ }
926
+ }}
927
+ >
928
+ <TableCell colSpan={columns.length} style={groupHeaderCell}>
929
+ <HStack gap={2} vAlign="center">
952
930
  <Icon
953
- icon={ChartBar}
931
+ icon={isExpanded ? ChevronDown : ChevronRight}
954
932
  size="sm"
955
- color={PRIORITY_COLOR[task.priority]}
933
+ color="secondary"
956
934
  />
957
- <Text type="supporting" color="secondary">
958
- {task.taskId}
935
+ <Text type="body" weight="semibold">
936
+ {getGroupLabel(groupBy, key)}
959
937
  </Text>
960
- <StackItem size="fill">
961
- <Text type="body">
962
- {task.title}
963
- {task.subtitle && (
964
- <Text type="inherit" color="secondary">
965
- {" › "}
966
- {task.subtitle}
967
- </Text>
968
- )}
969
- </Text>
970
- </StackItem>
938
+ <Badge variant="neutral" label={String(tasks.length)} />
971
939
  </HStack>
972
940
  </TableCell>
973
- <TableCell>
974
- {task.project ? (
975
- <Text type="body">{task.project}</Text>
976
- ) : (
941
+ </TableRow>
942
+ )}
943
+ {(groupBy === "none" || isExpanded) &&
944
+ tasks.map((task) => (
945
+ <TableRow key={task.id} onClick={() => setSelectedTask(task)}>
946
+ <TableCell>
947
+ {/* StatusDot paints nothing but an 8px dot — its
948
+ label is aria-label on a role="img" span — so
949
+ four states here read as hue alone. Same
950
+ dot-plus-word pairing as the Status entry in
951
+ TaskDetailPanel's MetadataList. */}
952
+ <HStack gap={1} vAlign="center">
953
+ <StatusDot
954
+ variant={STATUS_DOT_VARIANT[task.status]}
955
+ label={STATUS_LABEL[task.status]}
956
+ isPulsing={task.status === "in_progress"}
957
+ />
958
+ <Text type="supporting" color="secondary">
959
+ {STATUS_LABEL[task.status]}
960
+ </Text>
961
+ </HStack>
962
+ </TableCell>
963
+ <TableCell>
964
+ <HStack gap={3} vAlign="center" wrap="wrap">
965
+ <Icon
966
+ icon={ChartBar}
967
+ size="sm"
968
+ color={PRIORITY_COLOR[task.priority]}
969
+ />
970
+ <Text type="supporting" color="secondary">
971
+ {task.taskId}
972
+ </Text>
973
+ <StackItem size="fill">
974
+ <Text type="body">
975
+ {task.title}
976
+ {task.subtitle && (
977
+ <Text type="inherit" color="secondary">
978
+ {" › "}
979
+ {task.subtitle}
980
+ </Text>
981
+ )}
982
+ </Text>
983
+ </StackItem>
984
+ </HStack>
985
+ </TableCell>
986
+ <TableCell>
987
+ {task.project ? (
988
+ <Text type="body">{task.project}</Text>
989
+ ) : (
990
+ <Text type="supporting" color="secondary">
991
+ None
992
+ </Text>
993
+ )}
994
+ </TableCell>
995
+ <TableCell>
977
996
  <Text type="supporting" color="secondary">
978
- None
997
+ {task.created}
979
998
  </Text>
980
- )}
981
- </TableCell>
982
- <TableCell>
983
- <Text type="supporting" color="secondary">
984
- {task.created}
985
- </Text>
986
- </TableCell>
987
- <TableCell>
988
- <Text type="supporting" color="secondary">
989
- {task.updated}
990
- </Text>
991
- </TableCell>
992
- <TableCell>
993
- {/* Name beside the avatar: below 1024 the
999
+ </TableCell>
1000
+ <TableCell>
1001
+ <Text type="supporting" color="secondary">
1002
+ {task.updated}
1003
+ </Text>
1004
+ </TableCell>
1005
+ <TableCell>
1006
+ {/* Name beside the avatar: below 1024 the
994
1007
  inspector is gone, so the avatar alone would
995
1008
  leave the assignee readable by screen reader
996
1009
  but not by eye. */}
997
- <HStack gap={2} vAlign="center">
998
- <Avatar name={task.assignee} size="sm" />
999
- <Text type="supporting" color="secondary">
1000
- {task.assignee}
1001
- </Text>
1002
- </HStack>
1003
- </TableCell>
1004
- <TableCell>
1005
- <DropdownMenu
1006
- button={{
1007
- label: "Actions",
1008
- variant: "ghost",
1009
- size: "sm",
1010
- icon: <Icon icon={Ellipsis} size="sm" />,
1011
- isIconOnly: true,
1012
- }}
1013
- hasChevron={false}
1014
- items={[
1015
- { label: "Edit issue", icon: Pencil },
1016
- { label: "Assign to...", icon: User },
1017
- { label: "Add label", icon: Tag },
1018
- { label: "Duplicate", icon: Copy },
1019
- { label: "Move to project", icon: ArrowRight },
1020
- { type: "divider" as const },
1021
- { label: "Delete issue", icon: Trash },
1022
- ]}
1023
- />
1024
- </TableCell>
1025
- </TableRow>
1026
- ))}
1027
- </React.Fragment>
1028
- );
1029
- })}
1010
+ <HStack gap={2} vAlign="center">
1011
+ <Avatar name={task.assignee} size="sm" />
1012
+ <Text type="supporting" color="secondary">
1013
+ {task.assignee}
1014
+ </Text>
1015
+ </HStack>
1016
+ </TableCell>
1017
+ <TableCell>
1018
+ <DropdownMenu
1019
+ button={{
1020
+ label: "Actions",
1021
+ variant: "ghost",
1022
+ size: "sm",
1023
+ icon: <Icon icon={Ellipsis} size="sm" />,
1024
+ isIconOnly: true,
1025
+ }}
1026
+ hasChevron={false}
1027
+ items={[
1028
+ { label: "Edit issue", icon: Pencil },
1029
+ { label: "Assign to...", icon: User },
1030
+ { label: "Add label", icon: Tag },
1031
+ { label: "Duplicate", icon: Copy },
1032
+ { label: "Move to project", icon: ArrowRight },
1033
+ { type: "divider" as const },
1034
+ { label: "Delete issue", icon: Trash },
1035
+ ]}
1036
+ />
1037
+ </TableCell>
1038
+ </TableRow>
1039
+ ))}
1040
+ </React.Fragment>
1041
+ );
1042
+ })}
1043
+ </TableBody>
1030
1044
  </Table>
1031
1045
  </LayoutContent>
1032
1046
  }
@@ -2,6 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Shoe Store Sales",
4
4
  description: "Revenue chart over shoe order history",
5
- keywords: ["table", "heatmap", "store", "retail", "region", "data"],
5
+ keywords: ["table", "sales", "store", "retail", "revenue", "data"],
6
6
  category: "data",
7
7
  };
@@ -760,7 +760,7 @@ export default function ShoeStoreTable() {
760
760
  return (
761
761
  <OrderDesk
762
762
  title="Midnight Kicks"
763
- selfHash="#/templates/table-page-shoe-store-heatmap"
763
+ selfHash="#/templates/table-page-shoe-store"
764
764
  products={PRODUCTS}
765
765
  orders={orders}
766
766
  revenueData={revenueData}
@@ -26,6 +26,7 @@ import type { TableColumn } from "@astryxdesign/core/Table";
26
26
  import { pixel, proportional, Table } from "@astryxdesign/core/Table";
27
27
  import { Heading, Text } from "@astryxdesign/core/Text";
28
28
  import { Download, Filter, Plus } from "lucide-react";
29
+ import type { CSSProperties } from "react";
29
30
  import { useMemo, useState } from "react";
30
31
 
31
32
  interface FamiliarRow extends Record<string, unknown> {
@@ -358,6 +359,12 @@ const columns: TableColumn<FamiliarRow>[] = [
358
359
  },
359
360
  ];
360
361
 
362
+ // A definite ancestor for `Layout height="fill"`. 100dvh, not minHeight: '100%':
363
+ // a percentage min-height against an indefinite containing block computes to 0
364
+ // (CSS 2.1 10.5), so the document would keep the scroll instead of the content
365
+ // pane. Same shape as dashboard.tsx and table-page-heatmap-status.tsx.
366
+ const pageStyle: CSSProperties = { height: "100dvh" };
367
+
361
368
  export default function TablePage() {
362
369
  const [filters, setFilters] = useState<PowerSearchFilter[]>([]);
363
370
  const { config, applyFilters } = usePowerSearchConfig(fieldDefs, "Familiars");
@@ -368,6 +375,7 @@ export default function TablePage() {
368
375
 
369
376
  return (
370
377
  <Layout
378
+ style={pageStyle}
371
379
  height="fill"
372
380
  header={
373
381
  <LayoutHeader hasDivider padding={6}>
@@ -0,0 +1,16 @@
1
+ export default {
2
+ type: "page",
3
+ name: "Tree Table",
4
+ description: "Expandable collection tree with sibling-scoped sorting and resizable columns",
5
+ keywords: [
6
+ "table",
7
+ "tree",
8
+ "hierarchy",
9
+ "expandable",
10
+ "resizable",
11
+ "sortable",
12
+ "data",
13
+ "inventory",
14
+ ],
15
+ category: "data",
16
+ };