@parallelworks/ui 0.17.0 → 0.19.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 (169) hide show
  1. package/README.md +86 -6
  2. package/dist/ai/adapter/memoryStore.d.ts +8 -0
  3. package/dist/ai/adapter/mock/index.d.ts +2 -0
  4. package/dist/ai/adapter/mock/index.js +81 -0
  5. package/dist/ai/adapter/mock/mockAdapter.d.ts +4 -0
  6. package/dist/ai/adapter/openai/createOpenAIStream.d.ts +9 -0
  7. package/dist/ai/adapter/openai/errors.d.ts +3 -0
  8. package/dist/ai/adapter/openai/index.d.ts +6 -0
  9. package/dist/ai/adapter/openai/index.js +334 -0
  10. package/dist/ai/adapter/openai/openaiAdapter.d.ts +9 -0
  11. package/dist/ai/adapter/openai/responses.d.ts +4 -0
  12. package/dist/ai/adapter/openai/sse.d.ts +24 -0
  13. package/dist/ai/adapter/openai/wire.d.ts +40 -0
  14. package/dist/ai/adapter/types.d.ts +131 -0
  15. package/dist/ai/agent/classifier.d.ts +2 -0
  16. package/dist/ai/agent/diff.d.ts +35 -0
  17. package/dist/ai/agent/diffHighlight.d.ts +6 -0
  18. package/dist/ai/agent/index.d.ts +6 -0
  19. package/dist/ai/agent/permissions.d.ts +11 -0
  20. package/dist/ai/agent/toolfmt.d.ts +18 -0
  21. package/dist/ai/agent/transcript.d.ts +38 -0
  22. package/dist/ai/ai.css +325 -0
  23. package/dist/ai/components/AllocationSelector.d.ts +4 -0
  24. package/dist/ai/components/AttachmentManager.d.ts +1 -0
  25. package/dist/ai/components/AttachmentUpload.d.ts +24 -0
  26. package/dist/ai/components/BlockedGroupBanner.d.ts +1 -0
  27. package/dist/ai/components/BranchNavigator.d.ts +8 -0
  28. package/dist/ai/components/ChatEmptyState.d.ts +3 -0
  29. package/dist/ai/components/ChatInput.d.ts +45 -0
  30. package/dist/ai/components/ChatLayout.d.ts +5 -0
  31. package/dist/ai/components/ChatMessage.d.ts +24 -0
  32. package/dist/ai/components/ChatMessageList.d.ts +35 -0
  33. package/dist/ai/components/ChatSidebar.d.ts +5 -0
  34. package/dist/ai/components/ChatThread.d.ts +3 -0
  35. package/dist/ai/components/ComposerChrome.d.ts +18 -0
  36. package/dist/ai/components/ComposerFrame.d.ts +16 -0
  37. package/dist/ai/components/DragOverlay.d.ts +5 -0
  38. package/dist/ai/components/ModelSelector.d.ts +6 -0
  39. package/dist/ai/components/ShareDialog.d.ts +11 -0
  40. package/dist/ai/components/SlashMenu.d.ts +28 -0
  41. package/dist/ai/components/agent/ActivityLine.d.ts +21 -0
  42. package/dist/ai/components/agent/AgentMessageParts.d.ts +54 -0
  43. package/dist/ai/components/agent/PermissionPicker.d.ts +11 -0
  44. package/dist/ai/components/attachmentKeys.d.ts +4 -0
  45. package/dist/ai/core/ChatProvider.d.ts +66 -0
  46. package/dist/ai/core/KeyboardShortcutsProvider.d.ts +5 -0
  47. package/dist/ai/core/chatReducer.d.ts +114 -0
  48. package/dist/ai/core/config.d.ts +47 -0
  49. package/dist/ai/core/events.d.ts +1 -0
  50. package/dist/ai/core/exportConversation.d.ts +4 -0
  51. package/dist/ai/core/greeting.d.ts +3 -0
  52. package/dist/ai/core/parts.d.ts +11 -0
  53. package/dist/ai/core/useDragDrop.d.ts +14 -0
  54. package/dist/ai/core/useKeyboardShortcuts.d.ts +12 -0
  55. package/dist/ai/core/useSSEStream.d.ts +34 -0
  56. package/dist/ai/index.d.ts +40 -0
  57. package/dist/ai/index.js +6645 -0
  58. package/dist/ai/strings.d.ts +167 -0
  59. package/dist/ai/types.d.ts +236 -0
  60. package/dist/ai/ui/Avatar.d.ts +8 -0
  61. package/dist/ai/ui/Dropdown.d.ts +31 -0
  62. package/dist/ai/ui/Markdown.d.ts +8 -0
  63. package/dist/ai/ui/Notice.d.ts +21 -0
  64. package/dist/ai/ui/buttons.d.ts +1 -0
  65. package/dist/ai/ui/codeBreaks.d.ts +16 -0
  66. package/dist/ai/ui/prose.d.ts +1 -0
  67. package/dist/ai/ui/sidebar.d.ts +81 -0
  68. package/dist/ai/utils.d.ts +4 -0
  69. package/dist/assets/{editor.worker-CuBRIwi-.js → editor.worker-BmHUIVG4.js} +194 -163
  70. package/dist/assets/{json.worker-8ytS02vz.js → json.worker-D8bJ92nw.js} +384 -338
  71. package/dist/assets/{yaml.worker-DJC-VUcv.js → yaml.worker-C4gyGAko.js} +15657 -13823
  72. package/dist/chunks/{CodePreviewEditor-UAtnpmOV.js → CodePreviewEditor-YqQBz1YL.js} +2 -2
  73. package/dist/chunks/ConfirmModal-aOR4O1QE.js +79 -0
  74. package/dist/chunks/{lib-CUTRDpa6.js → FieldWrapper-Cszwg-4B.js} +52 -55
  75. package/dist/chunks/{CreateModal-BbV5cTj7.js → Markdown-CM-FenNE.js} +25 -97
  76. package/dist/chunks/Monaco-DJ8MW-Dq.js +110 -0
  77. package/dist/chunks/{PageHeader-MxuOs9cH.js → PageHeader-0kG_iypP.js} +170 -105
  78. package/dist/chunks/{Provider-DHmZ3v9i.js → Provider-CDYurraE.js} +60 -24
  79. package/dist/chunks/{SwitchToggle-BRQoEwLZ.js → SwitchToggle-DShNdcao.js} +143 -140
  80. package/dist/chunks/{Table-C6JdFFiJ.js → Table-DU2MW8xz.js} +6 -4
  81. package/dist/chunks/{Tooltip-n9w7Tkt1.js → Tooltip-K5HJr4_p.js} +32 -5
  82. package/dist/chunks/duration-BOv8Phl8.js +17 -0
  83. package/dist/chunks/{editor-mNznodJN.js → editor-Dk1rbV75.js} +33 -19
  84. package/dist/chunks/focus-D_iZJTW1.js +7 -0
  85. package/dist/chunks/{list-7k0eaI5N.js → list-CJm875m7.js} +497 -379
  86. package/dist/chunks/logviewer-BTKuQWzw.js +828 -0
  87. package/dist/chunks/memoryStore-CC91S5LP.js +152 -0
  88. package/dist/chunks/types-Yy0NrerF.js +11 -0
  89. package/dist/components/AddMenu.d.ts +1 -0
  90. package/dist/components/Avatar.d.ts +13 -0
  91. package/dist/components/Breadcrumbs.d.ts +1 -1
  92. package/dist/components/Dropdown.d.ts +3 -1
  93. package/dist/components/EmptyState.d.ts +1 -1
  94. package/dist/components/Indicator.d.ts +2 -2
  95. package/dist/components/Input.d.ts +1 -1
  96. package/dist/components/LetterBadge.d.ts +1 -1
  97. package/dist/components/MarkdownImpl.d.ts +1 -1
  98. package/dist/components/Provider.d.ts +18 -65
  99. package/dist/components/SettingRow.d.ts +1 -1
  100. package/dist/components/SettingsGroup.d.ts +1 -1
  101. package/dist/components/focus.d.ts +2 -0
  102. package/dist/components/keys.d.ts +12 -0
  103. package/dist/duration.d.ts +3 -0
  104. package/dist/editor/Monaco.d.ts +1 -20
  105. package/dist/editor/index.d.ts +2 -1
  106. package/dist/editor/index.js +2 -2
  107. package/dist/editor/yaml.d.ts +5 -0
  108. package/dist/engine.d.ts +98 -0
  109. package/dist/file-explorer/FileExplorer.d.ts +11 -2
  110. package/dist/file-explorer/FileExplorerContext.d.ts +1 -1
  111. package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +1 -1
  112. package/dist/file-explorer/FilePreview/previewType.d.ts +1 -1
  113. package/dist/file-explorer/FileRow.d.ts +1 -1
  114. package/dist/file-explorer/helpers.d.ts +4 -4
  115. package/dist/file-explorer/index.d.ts +3 -3
  116. package/dist/file-explorer/index.js +632 -665
  117. package/dist/file-explorer/lib/types.d.ts +6 -1
  118. package/dist/file-explorer/lib/utils.d.ts +1 -3
  119. package/dist/file-explorer/useNearEnd.d.ts +1 -1
  120. package/dist/form/FieldWrapper.d.ts +2 -1
  121. package/dist/form/Fields/ResourceOptionIcon.d.ts +1 -1
  122. package/dist/form/Form.d.ts +7 -22
  123. package/dist/form/index.d.ts +11 -12
  124. package/dist/form/index.js +1333 -1454
  125. package/dist/form/lib.d.ts +6 -1
  126. package/dist/form/types/fieldComponentTypes.d.ts +4 -2
  127. package/dist/form/types/fieldTypes.d.ts +6 -20
  128. package/dist/form/useParsedOpts.d.ts +2 -2
  129. package/dist/form/utils/{slurmDuration.d.ts → duration.d.ts} +2 -2
  130. package/dist/{workflow → graph}/MatrixGroup.d.ts +2 -2
  131. package/dist/{workflow → graph}/index.d.ts +1 -1
  132. package/dist/{workflow → graph}/index.js +220 -185
  133. package/dist/{workflow → graph}/types.d.ts +3 -3
  134. package/dist/icons.d.ts +20 -21
  135. package/dist/icons.js +3 -3
  136. package/dist/index.d.ts +38 -39
  137. package/dist/index.js +355 -354
  138. package/dist/list/ListTable.d.ts +1 -1
  139. package/dist/list/ListViewControls.d.ts +2 -2
  140. package/dist/list/RowContextMenu.d.ts +9 -9
  141. package/dist/list/UserHoverCard.d.ts +45 -0
  142. package/dist/list/index.d.ts +9 -8
  143. package/dist/list/index.js +3 -3
  144. package/dist/logviewer/LogViewer.d.ts +1 -1
  145. package/dist/logviewer/index.d.ts +1 -0
  146. package/dist/logviewer/index.js +2 -742
  147. package/dist/logviewer/segments.d.ts +9 -0
  148. package/dist/styles/Geist-Variable.woff2 +0 -0
  149. package/dist/styles/GeistMono-Variable.woff2 +0 -0
  150. package/dist/styles/base.css +57 -0
  151. package/dist/styles/fonts.css +15 -0
  152. package/dist/styles/theme.css +9 -41
  153. package/dist/styles.css +1 -1
  154. package/dist/theme/index.js +2 -2
  155. package/package.json +45 -20
  156. package/LICENSE +0 -21
  157. package/dist/chunks/Monaco-DVyIpyv4.js +0 -1046
  158. package/dist/editor/usesGitlab.d.ts +0 -97
  159. package/dist/form/Fields/BucketReadOnlyField.d.ts +0 -7
  160. package/dist/form/types/workflow-schema.d.ts +0 -1145
  161. package/dist/form/utils/pwResolver.d.ts +0 -18
  162. package/dist/chunks/{BareModal-BqroLbZ5.js → BareModal-BtRiQezg.js} +1 -1
  163. package/dist/chunks/{MarkdownImpl-Bq4QhrtA.js → MarkdownImpl-CyeTVvSt.js} +1 -1
  164. /package/dist/{workflow → graph}/AnnotationBanner.d.ts +0 -0
  165. /package/dist/{workflow → graph}/Collapse.d.ts +0 -0
  166. /package/dist/{workflow → graph}/DependencyGraph.d.ts +0 -0
  167. /package/dist/{workflow → graph}/JobSummary.d.ts +0 -0
  168. /package/dist/{workflow → graph}/Reveal.d.ts +0 -0
  169. /package/dist/{workflow → graph}/TreeView.d.ts +0 -0
package/dist/index.js CHANGED
@@ -1,148 +1,24 @@
1
- import { DEFAULT_PRESET, THEME_PRESETS, THEME_TOKENS, applyTheme, contrastRatio, deriveTheme, isDarkColor } from "./theme/index.js";
1
+ import { a as useOptionalWorkflowEngine, c as useRunFile, d as useWorkflowEngine, f as useWorkflowEngineLoader, i as useNotify, l as useSlots, n as useLink, o as usePersistedState, r as useNavigation, s as useProvisionCorsRules, t as UIProvider, u as useStrings } from "./chunks/Provider-CDYurraE.js";
2
2
  import { AlertIcon, AngleRightIcon, EyeIcon, EyeOffIcon, FilterIcon, LoaderIcon, SortDownIcon, SortUnsortedIcon, SortUpIcon } from "./icons.js";
3
- import { a as CreateModalSelect, c as ConfirmModal, d as primaryButtonClasses, f as Markdown, h as Callout, i as CreateModalField, l as dangerButtonClasses, m as CopyToClipboard, n as CreateModal, o as CreateModalSwitch, p as CopyCodeBlock, r as CreateModalAutocompleteField, s as CreateModalTextarea, t as CREATE_MODAL_SELECT_FILTER_THRESHOLD, u as ghostButtonClasses } from "./chunks/CreateModal-BbV5cTj7.js";
4
- import { a as usePersistedState, c as useRunFile, d as useWorkflowJsonResolver, i as useNotify, l as useSlots, n as useLink, o as useProvisionCorsRules, r as useNavigation, s as useRepoSuggestions, t as UIProvider, u as useStrings } from "./chunks/Provider-DHmZ3v9i.js";
5
- import { a as truncationTooltipProps, i as formatTooltipContent, n as TOOLTIP_ID, r as TooltipInfo, t as GlobalTooltip } from "./chunks/Tooltip-n9w7Tkt1.js";
3
+ import { a as truncationTooltipProps, i as formatTooltipContent, n as TOOLTIP_ID, r as TooltipInfo, t as GlobalTooltip } from "./chunks/Tooltip-K5HJr4_p.js";
4
+ import { C as useSetDefaultBreadcrumbs, E as AddMenu, S as useSetBreadcrumbs, T as avatarInitials, a as HeaderAddButton, b as useClearBreadcrumbs, c as PageHeader, i as HeaderActionMenu, l as headerActionButtonClasses, n as BreadcrumbsRightAction, o as HeaderEditButton, r as BreadcrumbsTitleAction, s as HeaderRowMenu, t as BreadcrumbsActionButton, v as BreadcrumbProvider, w as Avatar, x as useHideBreadcrumbs, y as useBreadcrumb } from "./chunks/PageHeader-0kG_iypP.js";
5
+ import { n as modalPanelClasses, t as BareModal } from "./chunks/BareModal-BtRiQezg.js";
6
+ import { a as CreateModalField, c as CreateModalTextarea, d as Callout, i as CreateModalAutocompleteField, l as CopyCodeBlock, n as CREATE_MODAL_SELECT_FILTER_THRESHOLD, o as CreateModalSelect, r as CreateModal, s as CreateModalSwitch, t as Markdown, u as CopyToClipboard } from "./chunks/Markdown-CM-FenNE.js";
7
+ import { a as Dropdown, c as UncontrolledCollapsiblePanel, i as CustomListbox, n as SectionHeader, o as ControlledCollapsiblePanel, r as MultiSelectDropdown, s as MaybeCollapsible, t as SwitchToggle } from "./chunks/SwitchToggle-DShNdcao.js";
8
+ import { i as primaryButtonClasses, n as dangerButtonClasses, r as ghostButtonClasses, t as ConfirmModal } from "./chunks/ConfirmModal-aOR4O1QE.js";
6
9
  import { a as filterOption, c as isCategory, i as DropdownCaret, l as isOption, n as StatusDot, r as statusTextClass, s as flattenOptions, t as StatusBadge, u as toggleSetMember } from "./chunks/StatusBadge-C1Blx_cW.js";
7
- import { a as UncontrolledCollapsiblePanel, c as Dropdown, i as MaybeCollapsible, n as SectionHeader, o as MultiSelectDropdown, r as ControlledCollapsiblePanel, s as CustomListbox, t as SwitchToggle } from "./chunks/SwitchToggle-BRQoEwLZ.js";
8
- import { t as Loader } from "./chunks/Loader-BXoXTZGc.js";
9
- import { n as modalPanelClasses, t as BareModal } from "./chunks/BareModal-BqroLbZ5.js";
10
- import { C as useSetDefaultBreadcrumbs, S as useSetBreadcrumbs, a as HeaderAddButton, b as useClearBreadcrumbs, c as PageHeader, i as HeaderActionMenu, l as headerActionButtonClasses, n as BreadcrumbsRightAction, o as HeaderEditButton, r as BreadcrumbsTitleAction, s as HeaderRowMenu, t as BreadcrumbsActionButton, v as BreadcrumbProvider, w as AddMenu, x as useHideBreadcrumbs, y as useBreadcrumb } from "./chunks/PageHeader-MxuOs9cH.js";
11
- import { t as useCssIsDark } from "./chunks/useCssIsDark-DHr05dG2.js";
12
10
  import { t as Indicator } from "./chunks/Indicator-hBSIxOPK.js";
13
- import { t as SwitchToggleSmall } from "./chunks/SwitchToggleSmall-FcsaYSTs.js";
14
- import { n as Table, t as CompactTable } from "./chunks/Table-C6JdFFiJ.js";
15
11
  import { t as RequiredMark } from "./chunks/RequiredMark-DfLdYbYZ.js";
12
+ import { t as Loader } from "./chunks/Loader-BXoXTZGc.js";
13
+ import { t as SwitchToggleSmall } from "./chunks/SwitchToggleSmall-FcsaYSTs.js";
14
+ import { n as Table, t as CompactTable } from "./chunks/Table-DU2MW8xz.js";
15
+ import { t as useCssIsDark } from "./chunks/useCssIsDark-DHr05dG2.js";
16
+ import { DEFAULT_PRESET, THEME_PRESETS, THEME_TOKENS, applyTheme, contrastRatio, deriveTheme, isDarkColor } from "./theme/index.js";
16
17
  import cx from "classnames";
17
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
18
18
  import React, { forwardRef, useEffect, useId, useState } from "react";
19
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
19
20
  import Skeleton from "react-loading-skeleton";
20
21
  import { DateTime } from "luxon";
21
- //#region src/components/DescriptionList.tsx
22
- function DescriptionListItem({ label, children, tooltip, className, ...props }) {
23
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("dt", {
24
- className: cx("text-[13px] leading-6 col-span-1 font-normal flex gap-1", className),
25
- children: [/* @__PURE__ */ jsx("span", {
26
- className: "min-w-0 truncate",
27
- children: label
28
- }), tooltip && /* @__PURE__ */ jsx(TooltipInfo, {
29
- className: "pr-2",
30
- text: tooltip
31
- })]
32
- }), /* @__PURE__ */ jsx("dd", {
33
- ...props,
34
- className: "flex text-[13px] leading-6 col-span-4 font-light items-center overflow-auto",
35
- children
36
- })] });
37
- }
38
- function DescriptionList({ children, title, separators = true, subtitle, className, wrapperClassName, vertical = false }) {
39
- return /* @__PURE__ */ jsxs("div", {
40
- className: cx("w-full", wrapperClassName),
41
- children: [
42
- title && /* @__PURE__ */ jsx("h2", {
43
- className: "text-sm font-semibold w-full mb-1",
44
- children: title
45
- }),
46
- subtitle && /* @__PURE__ */ jsx("div", {
47
- className: "max-w-2xl text-sm/6 w-full",
48
- children: subtitle
49
- }),
50
- /* @__PURE__ */ jsx("dl", {
51
- className: cx("grid", separators && "*:not-last-of-type:border-b-1", vertical ? "grid-cols-1" : "grid-cols-5 gap-x-4 gap-y-0.5 *:pb-0.5", className),
52
- children: Array.isArray(children) ? children.map((child, index) => /* @__PURE__ */ jsx(React.Fragment, { children: child }, index)) : children
53
- })
54
- ]
55
- });
56
- }
57
- //#endregion
58
- //#region src/components/EmptyState.tsx
59
- function EmptyState({ title, description, action, icon: Icon }) {
60
- return /* @__PURE__ */ jsxs("div", {
61
- className: "border-solid rounded-2xl border border-(--theme-border) theme-panel flex flex-col items-center justify-center py-12 px-6",
62
- children: [
63
- Icon && /* @__PURE__ */ jsx("div", {
64
- className: "w-10 h-10 rounded-full bg-(--theme-muted-panel-bg) flex items-center justify-center mb-3",
65
- children: /* @__PURE__ */ jsx(Icon, { className: "w-5 h-5 theme-muted-text" })
66
- }),
67
- /* @__PURE__ */ jsx("p", {
68
- className: "text-sm font-medium mb-1",
69
- children: title
70
- }),
71
- description && /* @__PURE__ */ jsx("p", {
72
- className: "text-xs theme-muted-text text-center max-w-xs",
73
- children: description
74
- }),
75
- action && /* @__PURE__ */ jsx("div", {
76
- className: "mt-4",
77
- children: action
78
- })
79
- ]
80
- });
81
- }
82
- //#endregion
83
- //#region src/components/Overview.tsx
84
- function Overview({ Icon, name, type, children, right, className, loading, iconSize = 75 }) {
85
- return /* @__PURE__ */ jsxs("div", {
86
- className: cx("flex items-center w-full", className),
87
- children: [
88
- loading ? /* @__PURE__ */ jsx(Skeleton, {
89
- width: iconSize,
90
- height: iconSize,
91
- circle: true
92
- }) : Icon,
93
- /* @__PURE__ */ jsx("div", {
94
- className: "flex flex-col min-w-0 flex-1",
95
- children: loading ? /* @__PURE__ */ jsx(Skeleton, {
96
- count: 2,
97
- height: 12
98
- }) : /* @__PURE__ */ jsxs(Fragment, { children: [
99
- /* @__PURE__ */ jsx("div", {
100
- className: "font-semibold text-xl tracking-tight",
101
- children: name
102
- }),
103
- type && /* @__PURE__ */ jsx("p", { children: type }),
104
- /* @__PURE__ */ jsx("div", {
105
- className: "flex flex-row gap-x-2",
106
- children
107
- })
108
- ] })
109
- }),
110
- right && /* @__PURE__ */ jsx("div", {
111
- className: "shrink-0 self-center",
112
- children: right
113
- })
114
- ]
115
- });
116
- }
117
- //#endregion
118
- //#region src/components/relativeTime.ts
119
- var TICK_MS = 3e4;
120
- function compactRelativeMinutes(minutes, t) {
121
- if (!Number.isFinite(minutes) || minutes < 1) return t.now;
122
- if (minutes < 60) return t.minutes(minutes);
123
- const hours = Math.floor(minutes / 60);
124
- if (hours < 24) return t.hours(hours);
125
- const days = Math.floor(hours / 24);
126
- if (days < 365) return t.days(days);
127
- return t.years(Math.floor(days / 365));
128
- }
129
- /** A clock that re-reads itself, so "5m" ages while the page sits open, with
130
- * the abbreviated form a row has room for. */
131
- function useRelativeTime() {
132
- const t = useStrings().time;
133
- const [now, setNow] = useState(() => DateTime.now());
134
- useEffect(() => {
135
- const id = setInterval(() => setNow(DateTime.now()), TICK_MS);
136
- return () => clearInterval(id);
137
- }, []);
138
- const compactMinutes = (minutes) => compactRelativeMinutes(minutes, t);
139
- return {
140
- now,
141
- compactMinutes,
142
- compact: (iso) => iso ? compactMinutes(Math.floor(now.diff(DateTime.fromISO(iso)).as("minutes"))) : ""
143
- };
144
- }
145
- //#endregion
146
22
  //#region src/components/Button.tsx
147
23
  var Button = forwardRef(({ children, variant = "primary", size = "default", loading, icon, iconPosition = "right", fullWidth = true, className = "", disabled, ...props }, ref) => {
148
24
  const baseClasses = "inline-flex items-center justify-center gap-2 font-semibold rounded-lg transition-all duration-200 cursor-pointer border-none mt-2 disabled:opacity-50 disabled:cursor-not-allowed";
@@ -164,7 +40,7 @@ var Button = forwardRef(({ children, variant = "primary", size = "default", load
164
40
  disabled: disabled || loading,
165
41
  className: cx(baseClasses, variantClasses[variant], sizeClasses[size], widthClass, className),
166
42
  ...props,
167
- children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(LoaderIcon, { className: "size-[18px]" }), children] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
43
+ children: loading ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(LoaderIcon, { className: "size-[18px]" }), children] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
168
44
  icon && iconPosition === "left" && /* @__PURE__ */ jsx("span", {
169
45
  className: "flex items-center",
170
46
  children: icon
@@ -182,7 +58,7 @@ function MethodButton({ icon, label, description, href, loading, disabled, class
182
58
  const Link = useLink();
183
59
  const baseClasses = "flex items-center w-full p-4 bg-[var(--theme-muted-panel-bg)] border border-[var(--theme-border)] rounded-xl text-[var(--theme-app)] text-[0.9375rem] font-medium cursor-pointer transition-all duration-200 no-underline mb-3 last:mb-0 hover:bg-[var(--theme-border)] hover:border-[var(--theme-muted-text-color)] hover:-translate-y-0.5 active:translate-y-0";
184
60
  const disabledClasses = "disabled:opacity-60 disabled:cursor-not-allowed disabled:hover:bg-[var(--ds-muted)] disabled:hover:border-[var(--ds-border)] disabled:hover:translate-y-0";
185
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
61
+ const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [
186
62
  icon && /* @__PURE__ */ jsx("span", {
187
63
  className: "size-10 rounded-lg bg-gradient-to-br from-[var(--gradient-start,var(--theme-element))] to-[var(--gradient-mid,var(--theme-link))] flex items-center justify-center shrink-0 mr-4 [&_svg]:size-5 [&_svg]:text-white",
188
64
  children: icon
@@ -248,102 +124,117 @@ function CardHeader({ badge, title, description, className = "", align = "center
248
124
  });
249
125
  }
250
126
  //#endregion
251
- //#region src/components/Input.tsx
252
- var Input = forwardRef(({ label, error, className = "", mono, type, required, ...props }, ref) => {
253
- const [showPassword, setShowPassword] = useState(false);
254
- const isPassword = type === "password";
255
- const inputType = isPassword && showPassword ? "text" : type;
256
- const generatedId = useId();
257
- const id = props.id ?? generatedId;
258
- const errorId = `${id}-error`;
259
- const describedBy = [props["aria-describedby"], error ? errorId : void 0].filter(Boolean).join(" ") || void 0;
260
- const inputClasses = cx("w-full py-3 px-4 bg-[var(--theme-muted-panel-bg)] border border-[var(--theme-border)] rounded-lg text-[var(--theme-app)] text-sm transition-all duration-200 box-border", "focus:outline-none focus:border-[var(--theme-element)] focus:shadow-[0_0_0_3px_color-mix(in_srgb,var(--theme-element)_25%,transparent)]", "placeholder:text-[var(--theme-muted-text-color)]", "disabled:bg-[var(--theme-muted-panel-bg)] disabled:text-[var(--theme-muted-text-color)] disabled:cursor-not-allowed disabled:opacity-70", mono && "font-mono text-[0.8125rem]", error && "border-[#ef4444]", isPassword && "pr-11", className);
127
+ //#region src/components/DescriptionList.tsx
128
+ function DescriptionListItem({ label, children, tooltip, className, ...props }) {
129
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("dt", {
130
+ className: cx("text-[13px] leading-6 col-span-1 font-normal flex gap-1", className),
131
+ children: [/* @__PURE__ */ jsx("span", {
132
+ className: "min-w-0 truncate",
133
+ children: label
134
+ }), tooltip && /* @__PURE__ */ jsx(TooltipInfo, {
135
+ className: "pr-2",
136
+ text: tooltip
137
+ })]
138
+ }), /* @__PURE__ */ jsx("dd", {
139
+ ...props,
140
+ className: "flex text-[13px] leading-6 col-span-4 font-light items-center overflow-auto",
141
+ children
142
+ })] });
143
+ }
144
+ function DescriptionList({ children, title, separators = true, subtitle, className, wrapperClassName, vertical = false }) {
261
145
  return /* @__PURE__ */ jsxs("div", {
262
- className: "flex flex-col gap-1.5",
146
+ className: cx("w-full", wrapperClassName),
263
147
  children: [
264
- label && /* @__PURE__ */ jsxs("label", {
265
- className: "text-[0.8125rem] font-medium text-[var(--theme-app)]",
266
- htmlFor: id,
267
- children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
148
+ title && /* @__PURE__ */ jsx("h2", {
149
+ className: "text-sm font-semibold w-full mb-1",
150
+ children: title
268
151
  }),
269
- /* @__PURE__ */ jsxs("div", {
270
- className: isPassword ? "relative w-full" : "",
271
- children: [/* @__PURE__ */ jsx("input", {
272
- ref,
273
- type: inputType,
274
- className: inputClasses,
275
- ...props,
276
- id,
277
- required,
278
- "aria-invalid": error ? true : props["aria-invalid"],
279
- "aria-describedby": describedBy
280
- }), isPassword && /* @__PURE__ */ jsx("button", {
281
- type: "button",
282
- className: "absolute right-3 top-1/2 -translate-y-1/2 bg-transparent border-none text-[var(--theme-muted-text-color)] cursor-pointer p-1 transition-colors duration-200 flex items-center justify-center hover:text-[var(--theme-app)]",
283
- onClick: () => setShowPassword(!showPassword),
284
- tabIndex: -1,
285
- "aria-label": showPassword ? "Hide password" : "Show password",
286
- children: showPassword ? /* @__PURE__ */ jsx(EyeOffIcon, { className: "w-5 h-5" }) : /* @__PURE__ */ jsx(EyeIcon, { className: "w-5 h-5" })
287
- })]
152
+ subtitle && /* @__PURE__ */ jsx("div", {
153
+ className: "max-w-2xl text-sm/6 w-full",
154
+ children: subtitle
288
155
  }),
289
- error && /* @__PURE__ */ jsxs("span", {
290
- id: errorId,
291
- role: "alert",
292
- className: "text-[0.8125rem] text-[#ef4444] flex items-center gap-1.5",
293
- children: [/* @__PURE__ */ jsx(AlertIcon, { className: "w-4 h-4" }), error]
156
+ /* @__PURE__ */ jsx("dl", {
157
+ className: cx("grid", separators && "*:not-last-of-type:border-b-1", vertical ? "grid-cols-1" : "grid-cols-5 gap-x-4 gap-y-0.5 *:pb-0.5", className),
158
+ children: Array.isArray(children) ? React.Children.toArray(children) : children
294
159
  })
295
160
  ]
296
161
  });
297
- });
298
- Input.displayName = "Input";
299
- var Textarea = forwardRef(({ label, error, className = "", mono, required, ...props }, ref) => {
300
- const generatedId = useId();
301
- const id = props.id ?? generatedId;
302
- const errorId = `${id}-error`;
303
- const describedBy = [props["aria-describedby"], error ? errorId : void 0].filter(Boolean).join(" ") || void 0;
304
- const textareaClasses = cx("w-full py-3 px-4 bg-[var(--theme-muted-panel-bg)] border border-[var(--theme-border)] rounded-lg text-[var(--theme-app)] text-sm transition-all duration-200 box-border min-h-[140px] resize-y", "focus:outline-none focus:border-[var(--theme-element)] focus:shadow-[0_0_0_3px_color-mix(in_srgb,var(--theme-element)_25%,transparent)]", "placeholder:text-[var(--theme-muted-text-color)]", mono && "font-mono text-[0.8125rem]", error && "border-[#ef4444]", className);
162
+ }
163
+ //#endregion
164
+ //#region src/components/EmptyState.tsx
165
+ function EmptyState({ title, description, action, icon: Icon }) {
305
166
  return /* @__PURE__ */ jsxs("div", {
306
- className: "flex flex-col gap-1.5",
167
+ className: "border-solid rounded-2xl border border-(--theme-border) theme-panel flex flex-col items-center justify-center py-12 px-6",
307
168
  children: [
308
- label && /* @__PURE__ */ jsxs("label", {
309
- className: "text-[0.8125rem] font-medium text-[var(--theme-app)]",
310
- htmlFor: id,
311
- children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
169
+ Icon && /* @__PURE__ */ jsx("div", {
170
+ className: "w-10 h-10 rounded-full bg-(--theme-muted-panel-bg) flex items-center justify-center mb-3",
171
+ children: /* @__PURE__ */ jsx(Icon, { className: "w-5 h-5 theme-muted-text" })
312
172
  }),
313
- /* @__PURE__ */ jsx("textarea", {
314
- ref,
315
- className: textareaClasses,
316
- ...props,
317
- id,
318
- required,
319
- "aria-invalid": error ? true : props["aria-invalid"],
320
- "aria-describedby": describedBy
173
+ /* @__PURE__ */ jsx("p", {
174
+ className: "text-sm font-medium mb-1",
175
+ children: title
321
176
  }),
322
- error && /* @__PURE__ */ jsxs("span", {
323
- id: errorId,
324
- role: "alert",
325
- className: "text-[0.8125rem] text-[#ef4444] flex items-center gap-1.5",
326
- children: [/* @__PURE__ */ jsx(AlertIcon, { className: "w-4 h-4" }), error]
177
+ description && /* @__PURE__ */ jsx("p", {
178
+ className: "text-xs theme-muted-text text-center max-w-xs",
179
+ children: description
180
+ }),
181
+ action && /* @__PURE__ */ jsx("div", {
182
+ className: "mt-4",
183
+ children: action
327
184
  })
328
185
  ]
329
186
  });
330
- });
331
- Textarea.displayName = "Textarea";
332
- //#endregion
333
- //#region src/components/inputClasses.ts
334
- var inputClasses = "w-full rounded-md border theme-border bg-(--theme-input-bg) px-3 py-2 text-sm text-(--theme-panel) outline-none focus:ring-2 focus:ring-(--theme-element)";
187
+ }
335
188
  //#endregion
336
- //#region src/components/IconButton.tsx
337
- var IconButton = forwardRef(({ icon, label, variant = "default", size = "md", active = false, showTooltip = true, className, disabled, ...props }, ref) => {
338
- const sizeClasses = {
339
- sm: "w-7 h-7 [&_svg]:w-3.5 [&_svg]:h-3.5",
340
- md: "w-9 h-9 [&_svg]:w-4 [&_svg]:h-4",
341
- lg: "w-11 h-11 [&_svg]:w-5 [&_svg]:h-5"
342
- };
343
- const variantClasses = {
344
- default: cx("bg-[var(--theme-muted-panel-bg)] text-[var(--theme-muted-text-color)]", "hover:bg-[var(--theme-border)] hover:text-[var(--theme-app)]", active && "bg-[var(--theme-element)]/10 text-[var(--theme-element)]"),
345
- ghost: cx("bg-transparent text-[var(--theme-muted-text-color)]", "hover:bg-[var(--theme-muted-panel-bg)] hover:text-[var(--theme-app)]", active && "text-[var(--theme-element)]"),
346
- primary: cx("bg-[var(--theme-element)] text-white", "hover:bg-[var(--theme-element)]/90", active && "ring-2 ring-[var(--theme-element)]/50"),
189
+ //#region src/components/Filter.tsx
190
+ function Filter({ filter, setFilter, placeholder = "Filter...", pills, activePill, onPillChange }) {
191
+ return /* @__PURE__ */ jsxs("div", {
192
+ className: "flex items-center gap-2",
193
+ children: [/* @__PURE__ */ jsxs("div", {
194
+ className: "relative flex items-center",
195
+ children: [/* @__PURE__ */ jsx("input", {
196
+ placeholder,
197
+ type: "text",
198
+ value: filter,
199
+ onChange: (e) => setFilter(e.target.value.toLowerCase()),
200
+ className: "shadow-sm focus:ring-1 block w-full pr-3 sm:text-sm theme-border rounded-md py-1.5 pl-8"
201
+ }), /* @__PURE__ */ jsx("div", {
202
+ className: "absolute inset-y-0 left-0 flex py-2.5 pl-2",
203
+ children: /* @__PURE__ */ jsx(FilterIcon, {})
204
+ })]
205
+ }), pills && onPillChange && /* @__PURE__ */ jsx("div", {
206
+ className: "flex gap-1",
207
+ children: pills.map((pill) => /* @__PURE__ */ jsx("button", {
208
+ type: "button",
209
+ onClick: () => onPillChange(pill.value),
210
+ className: cx("px-2.5 py-1 text-xs rounded-full transition-colors border", activePill === pill.value ? "bg-(--theme-element) text-(--theme-element-text) border-transparent" : "theme-border theme-text hover:theme-hover"),
211
+ children: pill.label
212
+ }, pill.value))
213
+ })]
214
+ });
215
+ }
216
+ //#endregion
217
+ //#region src/components/FilterPill.tsx
218
+ function FilterPill({ active, onClick, children }) {
219
+ return /* @__PURE__ */ jsx("button", {
220
+ type: "button",
221
+ onClick,
222
+ className: cx("px-3 py-1.5 text-xs font-medium rounded-full border transition-all duration-200", active ? "bg-[var(--theme-panel-bg)] border-[var(--theme-border)] text-[var(--theme-panel)] shadow-sm" : "bg-transparent border-transparent text-[var(--theme-muted-text-color)] hover:text-[var(--theme-panel)] hover:bg-[var(--theme-hover)]"),
223
+ children
224
+ });
225
+ }
226
+ //#endregion
227
+ //#region src/components/IconButton.tsx
228
+ var IconButton = forwardRef(({ icon, label, variant = "default", size = "md", active = false, showTooltip = true, className, disabled, ...props }, ref) => {
229
+ const sizeClasses = {
230
+ sm: "w-7 h-7 [&_svg]:w-3.5 [&_svg]:h-3.5",
231
+ md: "w-9 h-9 [&_svg]:w-4 [&_svg]:h-4",
232
+ lg: "w-11 h-11 [&_svg]:w-5 [&_svg]:h-5"
233
+ };
234
+ const variantClasses = {
235
+ default: cx("bg-[var(--theme-muted-panel-bg)] text-[var(--theme-muted-text-color)]", "hover:bg-[var(--theme-border)] hover:text-[var(--theme-app)]", active && "bg-[var(--theme-element)]/10 text-[var(--theme-element)]"),
236
+ ghost: cx("bg-transparent text-[var(--theme-muted-text-color)]", "hover:bg-[var(--theme-muted-panel-bg)] hover:text-[var(--theme-app)]", active && "text-[var(--theme-element)]"),
237
+ primary: cx("bg-[var(--theme-element)] text-white", "hover:bg-[var(--theme-element)]/90", active && "ring-2 ring-[var(--theme-element)]/50"),
347
238
  success: cx("bg-[#22c55e] text-white", "hover:bg-[#22c55e]/90", active && "ring-2 ring-[#22c55e]/50")
348
239
  };
349
240
  return /* @__PURE__ */ jsx("button", {
@@ -362,22 +253,90 @@ var IconButton = forwardRef(({ icon, label, variant = "default", size = "md", ac
362
253
  });
363
254
  IconButton.displayName = "IconButton";
364
255
  //#endregion
365
- //#region src/components/Toggle.tsx
366
- function Toggle({ checked, onChange, disabled, label }) {
367
- return /* @__PURE__ */ jsxs("label", {
368
- role: "none",
369
- onClick: (e) => e.stopPropagation(),
370
- className: cx("relative inline-flex items-center", disabled ? "cursor-not-allowed opacity-60" : "cursor-pointer"),
371
- children: [/* @__PURE__ */ jsx("input", {
372
- type: "checkbox",
373
- className: "peer sr-only",
374
- checked,
375
- onChange: (e) => onChange(e.target.checked),
376
- disabled,
377
- "aria-label": label
378
- }), /* @__PURE__ */ jsx("div", { className: "h-6 w-11 rounded-full bg-(--theme-muted-panel-bg) transition-colors peer-checked:bg-(--theme-element) peer-focus-visible:ring-2 peer-focus-visible:ring-[color-mix(in_srgb,var(--theme-element)_25%,transparent)] after:absolute after:start-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:bg-white after:shadow-sm after:transition-transform after:content-[\"\"] motion-reduce:after:transition-none peer-checked:after:translate-x-5" })]
256
+ //#region src/components/Input.tsx
257
+ var Input = forwardRef(({ label, error, className = "", mono, type, required, ...props }, ref) => {
258
+ const [showPassword, setShowPassword] = useState(false);
259
+ const isPassword = type === "password";
260
+ const inputType = isPassword && showPassword ? "text" : type;
261
+ const generatedId = useId();
262
+ const id = props.id ?? generatedId;
263
+ const errorId = `${id}-error`;
264
+ const describedBy = [props["aria-describedby"], error ? errorId : void 0].filter(Boolean).join(" ") || void 0;
265
+ const inputClasses = cx("w-full py-3 px-4 bg-[var(--theme-muted-panel-bg)] border border-[var(--theme-border)] rounded-lg text-[var(--theme-app)] text-sm transition-all duration-200 box-border", "focus:outline-none focus:border-[var(--theme-element)] focus:shadow-[0_0_0_3px_color-mix(in_srgb,var(--theme-element)_25%,transparent)]", "placeholder:text-[var(--theme-muted-text-color)]", "disabled:bg-[var(--theme-muted-panel-bg)] disabled:text-[var(--theme-muted-text-color)] disabled:cursor-not-allowed disabled:opacity-70", mono && "font-mono text-[0.8125rem]", error && "border-[#ef4444]", isPassword && "pr-11", className);
266
+ return /* @__PURE__ */ jsxs("div", {
267
+ className: "flex flex-col gap-1.5",
268
+ children: [
269
+ label && /* @__PURE__ */ jsxs("label", {
270
+ className: "text-[0.8125rem] font-medium text-[var(--theme-app)]",
271
+ htmlFor: id,
272
+ children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
273
+ }),
274
+ /* @__PURE__ */ jsxs("div", {
275
+ className: isPassword ? "relative w-full" : "",
276
+ children: [/* @__PURE__ */ jsx("input", {
277
+ ref,
278
+ type: inputType,
279
+ className: inputClasses,
280
+ ...props,
281
+ id,
282
+ required,
283
+ "aria-invalid": error ? true : props["aria-invalid"],
284
+ "aria-describedby": describedBy
285
+ }), isPassword && /* @__PURE__ */ jsx("button", {
286
+ type: "button",
287
+ className: "absolute right-3 top-1/2 -translate-y-1/2 bg-transparent border-none text-[var(--theme-muted-text-color)] cursor-pointer p-1 transition-colors duration-200 flex items-center justify-center hover:text-[var(--theme-app)]",
288
+ onClick: () => setShowPassword(!showPassword),
289
+ tabIndex: -1,
290
+ "aria-label": showPassword ? "Hide password" : "Show password",
291
+ children: showPassword ? /* @__PURE__ */ jsx(EyeOffIcon, { className: "w-5 h-5" }) : /* @__PURE__ */ jsx(EyeIcon, { className: "w-5 h-5" })
292
+ })]
293
+ }),
294
+ error && /* @__PURE__ */ jsxs("span", {
295
+ id: errorId,
296
+ role: "alert",
297
+ className: "text-[0.8125rem] text-[#ef4444] flex items-center gap-1.5",
298
+ children: [/* @__PURE__ */ jsx(AlertIcon, { className: "w-4 h-4" }), error]
299
+ })
300
+ ]
379
301
  });
380
- }
302
+ });
303
+ Input.displayName = "Input";
304
+ var Textarea = forwardRef(({ label, error, className = "", mono, required, ...props }, ref) => {
305
+ const generatedId = useId();
306
+ const id = props.id ?? generatedId;
307
+ const errorId = `${id}-error`;
308
+ const describedBy = [props["aria-describedby"], error ? errorId : void 0].filter(Boolean).join(" ") || void 0;
309
+ const textareaClasses = cx("w-full py-3 px-4 bg-[var(--theme-muted-panel-bg)] border border-[var(--theme-border)] rounded-lg text-[var(--theme-app)] text-sm transition-all duration-200 box-border min-h-[140px] resize-y", "focus:outline-none focus:border-[var(--theme-element)] focus:shadow-[0_0_0_3px_color-mix(in_srgb,var(--theme-element)_25%,transparent)]", "placeholder:text-[var(--theme-muted-text-color)]", mono && "font-mono text-[0.8125rem]", error && "border-[#ef4444]", className);
310
+ return /* @__PURE__ */ jsxs("div", {
311
+ className: "flex flex-col gap-1.5",
312
+ children: [
313
+ label && /* @__PURE__ */ jsxs("label", {
314
+ className: "text-[0.8125rem] font-medium text-[var(--theme-app)]",
315
+ htmlFor: id,
316
+ children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
317
+ }),
318
+ /* @__PURE__ */ jsx("textarea", {
319
+ ref,
320
+ className: textareaClasses,
321
+ ...props,
322
+ id,
323
+ required,
324
+ "aria-invalid": error ? true : props["aria-invalid"],
325
+ "aria-describedby": describedBy
326
+ }),
327
+ error && /* @__PURE__ */ jsxs("span", {
328
+ id: errorId,
329
+ role: "alert",
330
+ className: "text-[0.8125rem] text-[#ef4444] flex items-center gap-1.5",
331
+ children: [/* @__PURE__ */ jsx(AlertIcon, { className: "w-4 h-4" }), error]
332
+ })
333
+ ]
334
+ });
335
+ });
336
+ Textarea.displayName = "Textarea";
337
+ //#endregion
338
+ //#region src/components/inputClasses.ts
339
+ var inputClasses = "w-full rounded-md border theme-border bg-(--theme-input-bg) px-3 py-2 text-sm text-(--theme-panel) outline-none focus:ring-2 focus:ring-(--theme-element)";
381
340
  //#endregion
382
341
  //#region src/components/LetterBadge.tsx
383
342
  /** A compact letter badge ("AI", "PUB", "SSH") used as a type mark in place of
@@ -389,79 +348,38 @@ function LetterBadge({ text, className }) {
389
348
  });
390
349
  }
391
350
  //#endregion
392
- //#region src/components/FilterPill.tsx
393
- function FilterPill({ active, onClick, children }) {
394
- return /* @__PURE__ */ jsx("button", {
395
- type: "button",
396
- onClick,
397
- className: cx("px-3 py-1.5 text-xs font-medium rounded-full border transition-all duration-200", active ? "bg-[var(--theme-panel-bg)] border-[var(--theme-border)] text-[var(--theme-panel)] shadow-sm" : "bg-transparent border-transparent text-[var(--theme-muted-text-color)] hover:text-[var(--theme-panel)] hover:bg-[var(--theme-hover)]"),
398
- children
399
- });
400
- }
401
- //#endregion
402
- //#region src/components/Filter.tsx
403
- function Filter({ filter, setFilter, placeholder = "Filter...", pills, activePill, onPillChange }) {
351
+ //#region src/components/Overview.tsx
352
+ function Overview({ Icon, name, type, children, right, className, loading, iconSize = 75 }) {
404
353
  return /* @__PURE__ */ jsxs("div", {
405
- className: "flex items-center gap-2",
406
- children: [/* @__PURE__ */ jsxs("div", {
407
- className: "relative flex items-center",
408
- children: [/* @__PURE__ */ jsx("input", {
409
- placeholder,
410
- type: "text",
411
- value: filter,
412
- onChange: (e) => setFilter(e.target.value.toLowerCase()),
413
- className: "shadow-sm focus:ring-1 block w-full pr-3 sm:text-sm theme-border rounded-md py-1.5 pl-8"
414
- }), /* @__PURE__ */ jsx("div", {
415
- className: "absolute inset-y-0 left-0 flex py-2.5 pl-2",
416
- children: /* @__PURE__ */ jsx(FilterIcon, {})
417
- })]
418
- }), pills && onPillChange && /* @__PURE__ */ jsx("div", {
419
- className: "flex gap-1",
420
- children: pills.map((pill) => /* @__PURE__ */ jsx("button", {
421
- type: "button",
422
- onClick: () => onPillChange(pill.value),
423
- className: cx("px-2.5 py-1 text-xs rounded-full transition-colors border", activePill === pill.value ? "bg-(--theme-element) text-(--theme-element-text) border-transparent" : "theme-border theme-text hover:theme-hover"),
424
- children: pill.label
425
- }, pill.value))
426
- })]
427
- });
428
- }
429
- //#endregion
430
- //#region src/components/Sort.tsx
431
- var SortIcon = ({ currentlySorted, currentDirection, name }) => {
432
- const style = { transform: "translateY(2px)" };
433
- if (currentlySorted === name) {
434
- if (currentDirection === "ascending") return /* @__PURE__ */ jsx(SortDownIcon, { style });
435
- else if (currentDirection === "descending") return /* @__PURE__ */ jsx(SortUpIcon, { style });
436
- } else return /* @__PURE__ */ jsx(SortUnsortedIcon, { style });
437
- return null;
438
- };
439
- function Sort({ currentlySorted, name, setCurrentDirection, setCurrentlySorted, currentDirection }) {
440
- const t = useStrings().common;
441
- const sort = (sorted, direction) => {
442
- if (sorted === name) {
443
- if (direction === "ascending") setCurrentDirection("descending");
444
- else if (direction === "descending") {
445
- setCurrentDirection("unsorted");
446
- setCurrentlySorted("");
447
- }
448
- } else {
449
- setCurrentDirection("ascending");
450
- setCurrentlySorted(name);
451
- }
452
- };
453
- return /* @__PURE__ */ jsx("div", {
454
- className: "inline",
455
- children: /* @__PURE__ */ jsx("button", {
456
- type: "button",
457
- "aria-label": t.sort,
458
- onClick: () => sort(currentlySorted, currentDirection),
459
- children: /* @__PURE__ */ jsx(SortIcon, {
460
- currentDirection,
461
- currentlySorted,
462
- name
354
+ className: cx("flex items-center w-full", className),
355
+ children: [
356
+ loading ? /* @__PURE__ */ jsx(Skeleton, {
357
+ width: iconSize,
358
+ height: iconSize,
359
+ circle: true
360
+ }) : Icon,
361
+ /* @__PURE__ */ jsx("div", {
362
+ className: "flex flex-col min-w-0 flex-1",
363
+ children: loading ? /* @__PURE__ */ jsx(Skeleton, {
364
+ count: 2,
365
+ height: 12
366
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
367
+ /* @__PURE__ */ jsx("div", {
368
+ className: "font-semibold text-xl tracking-tight",
369
+ children: name
370
+ }),
371
+ type && /* @__PURE__ */ jsx("p", { children: type }),
372
+ /* @__PURE__ */ jsx("div", {
373
+ className: "flex flex-row gap-x-2",
374
+ children
375
+ })
376
+ ] })
377
+ }),
378
+ right && /* @__PURE__ */ jsx("div", {
379
+ className: "shrink-0 self-center",
380
+ children: right
463
381
  })
464
- })
382
+ ]
465
383
  });
466
384
  }
467
385
  //#endregion
@@ -496,6 +414,93 @@ function Pagination({ endingNumber, endingTime, nextCallback, prevCallback, roun
496
414
  });
497
415
  }
498
416
  //#endregion
417
+ //#region src/components/relativeTime.ts
418
+ var TICK_MS = 3e4;
419
+ function compactRelativeMinutes(minutes, t) {
420
+ if (!Number.isFinite(minutes) || minutes < 1) return t.now;
421
+ if (minutes < 60) return t.minutes(minutes);
422
+ const hours = Math.floor(minutes / 60);
423
+ if (hours < 24) return t.hours(hours);
424
+ const days = Math.floor(hours / 24);
425
+ if (days < 365) return t.days(days);
426
+ return t.years(Math.floor(days / 365));
427
+ }
428
+ /** A clock that re-reads itself, so "5m" ages while the page sits open, with
429
+ * the abbreviated form a row has room for. */
430
+ function useRelativeTime() {
431
+ const t = useStrings().time;
432
+ const [now, setNow] = useState(() => DateTime.now());
433
+ useEffect(() => {
434
+ const id = setInterval(() => setNow(DateTime.now()), TICK_MS);
435
+ return () => clearInterval(id);
436
+ }, []);
437
+ const compactMinutes = (minutes) => compactRelativeMinutes(minutes, t);
438
+ return {
439
+ now,
440
+ compactMinutes,
441
+ compact: (iso) => iso ? compactMinutes(Math.floor(now.diff(DateTime.fromISO(iso)).as("minutes"))) : ""
442
+ };
443
+ }
444
+ //#endregion
445
+ //#region src/components/SettingModeOption.tsx
446
+ /** A labeled + described radio option row, used inside a SettingsCard to pick
447
+ * between modes (e.g. default vs custom). Stacked rows share the card's
448
+ * dividers via `isFirst`. */
449
+ function SettingModeOption({ name, checked, onSelect, label, description, isFirst, disabled }) {
450
+ return /* @__PURE__ */ jsxs("label", {
451
+ className: cx("flex items-start gap-3 px-5 py-4", disabled ? "cursor-default opacity-60" : "cursor-pointer", !isFirst && "border-t theme-border"),
452
+ children: [/* @__PURE__ */ jsx("input", {
453
+ type: "radio",
454
+ name,
455
+ checked,
456
+ onChange: onSelect,
457
+ disabled,
458
+ className: "mt-0.5 w-4 h-4 theme-input shrink-0"
459
+ }), /* @__PURE__ */ jsxs("div", {
460
+ className: "min-w-0",
461
+ children: [/* @__PURE__ */ jsx("div", {
462
+ className: "font-semibold theme-text leading-tight",
463
+ children: label
464
+ }), /* @__PURE__ */ jsx("div", {
465
+ className: "theme-muted-text text-xs leading-snug mt-0.5",
466
+ children: description
467
+ })]
468
+ })]
469
+ });
470
+ }
471
+ //#endregion
472
+ //#region src/components/SettingRow.tsx
473
+ function SettingRow({ label, htmlFor, helpText, children, isFirst, fill, onClick }) {
474
+ return /* @__PURE__ */ jsxs("div", {
475
+ role: "none",
476
+ onClick,
477
+ className: cx("px-5 py-5 grid grid-cols-1 gap-x-8 gap-y-2", fill ? "md:grid-cols-[200px_1fr]" : "md:grid-cols-[1fr_auto]", !isFirst && "border-t theme-border", onClick && "cursor-pointer select-none hover:theme-hover transition-colors"),
478
+ children: [/* @__PURE__ */ jsxs("div", {
479
+ className: "flex flex-col gap-y-1",
480
+ children: [/* @__PURE__ */ jsx("label", {
481
+ htmlFor,
482
+ className: "font-semibold theme-text leading-tight",
483
+ children: label
484
+ }), helpText && /* @__PURE__ */ jsx("div", {
485
+ className: "theme-muted-text text-xs leading-snug",
486
+ children: helpText
487
+ })]
488
+ }), /* @__PURE__ */ jsx("div", {
489
+ className: cx("min-w-0", !fill && "flex items-center justify-end"),
490
+ children
491
+ })]
492
+ });
493
+ }
494
+ function SettingSection({ title, isFirst }) {
495
+ return /* @__PURE__ */ jsx("div", {
496
+ className: cx("px-5 py-3 theme-muted-panel", !isFirst && "border-t theme-border"),
497
+ children: /* @__PURE__ */ jsx("h2", {
498
+ className: "font-semibold text-sm uppercase tracking-wider theme-muted-text",
499
+ children: title
500
+ })
501
+ });
502
+ }
503
+ //#endregion
499
504
  //#region src/components/SettingsCard.tsx
500
505
  /**
501
506
  * A settings card: an optional sentence-case section label sits above a
@@ -538,63 +543,59 @@ function SettingsGroup({ title, children, className }) {
538
543
  });
539
544
  }
540
545
  //#endregion
541
- //#region src/components/SettingRow.tsx
542
- function SettingRow({ label, htmlFor, helpText, children, isFirst, fill, onClick }) {
543
- return /* @__PURE__ */ jsxs("div", {
544
- role: "none",
545
- onClick,
546
- className: cx("px-5 py-5 grid grid-cols-1 gap-x-8 gap-y-2", fill ? "md:grid-cols-[200px_1fr]" : "md:grid-cols-[1fr_auto]", !isFirst && "border-t theme-border", onClick && "cursor-pointer select-none hover:theme-hover transition-colors"),
547
- children: [/* @__PURE__ */ jsxs("div", {
548
- className: "flex flex-col gap-y-1",
549
- children: [/* @__PURE__ */ jsx("label", {
550
- htmlFor,
551
- className: "font-semibold theme-text leading-tight",
552
- children: label
553
- }), helpText && /* @__PURE__ */ jsx("div", {
554
- className: "theme-muted-text text-xs leading-snug",
555
- children: helpText
556
- })]
557
- }), /* @__PURE__ */ jsx("div", {
558
- className: cx("min-w-0", !fill && "flex items-center justify-end"),
559
- children
560
- })]
561
- });
562
- }
563
- function SettingSection({ title, isFirst }) {
546
+ //#region src/components/Sort.tsx
547
+ var SortIcon = ({ currentlySorted, currentDirection, name }) => {
548
+ const style = { transform: "translateY(2px)" };
549
+ if (currentlySorted === name) {
550
+ if (currentDirection === "ascending") return /* @__PURE__ */ jsx(SortDownIcon, { style });
551
+ else if (currentDirection === "descending") return /* @__PURE__ */ jsx(SortUpIcon, { style });
552
+ } else return /* @__PURE__ */ jsx(SortUnsortedIcon, { style });
553
+ return null;
554
+ };
555
+ function Sort({ currentlySorted, name, setCurrentDirection, setCurrentlySorted, currentDirection }) {
556
+ const t = useStrings().common;
557
+ const sort = (sorted, direction) => {
558
+ if (sorted === name) {
559
+ if (direction === "ascending") setCurrentDirection("descending");
560
+ else if (direction === "descending") {
561
+ setCurrentDirection("unsorted");
562
+ setCurrentlySorted("");
563
+ }
564
+ } else {
565
+ setCurrentDirection("ascending");
566
+ setCurrentlySorted(name);
567
+ }
568
+ };
564
569
  return /* @__PURE__ */ jsx("div", {
565
- className: cx("px-5 py-3 theme-muted-panel", !isFirst && "border-t theme-border"),
566
- children: /* @__PURE__ */ jsx("h2", {
567
- className: "font-semibold text-sm uppercase tracking-wider theme-muted-text",
568
- children: title
570
+ className: "inline",
571
+ children: /* @__PURE__ */ jsx("button", {
572
+ type: "button",
573
+ "aria-label": t.sort,
574
+ onClick: () => sort(currentlySorted, currentDirection),
575
+ children: /* @__PURE__ */ jsx(SortIcon, {
576
+ currentDirection,
577
+ currentlySorted,
578
+ name
579
+ })
569
580
  })
570
581
  });
571
582
  }
572
583
  //#endregion
573
- //#region src/components/SettingModeOption.tsx
574
- /** A labeled + described radio option row, used inside a SettingsCard to pick
575
- * between modes (e.g. default vs custom). Stacked rows share the card's
576
- * dividers via `isFirst`. */
577
- function SettingModeOption({ name, checked, onSelect, label, description, isFirst, disabled }) {
584
+ //#region src/components/Toggle.tsx
585
+ function Toggle({ checked, onChange, disabled, label }) {
578
586
  return /* @__PURE__ */ jsxs("label", {
579
- className: cx("flex items-start gap-3 px-5 py-4", disabled ? "cursor-default opacity-60" : "cursor-pointer", !isFirst && "border-t theme-border"),
587
+ role: "none",
588
+ onClick: (e) => e.stopPropagation(),
589
+ className: cx("relative inline-flex items-center", disabled ? "cursor-not-allowed opacity-60" : "cursor-pointer"),
580
590
  children: [/* @__PURE__ */ jsx("input", {
581
- type: "radio",
582
- name,
591
+ type: "checkbox",
592
+ className: "peer sr-only",
583
593
  checked,
584
- onChange: onSelect,
594
+ onChange: (e) => onChange(e.target.checked),
585
595
  disabled,
586
- className: "mt-0.5 w-4 h-4 theme-input shrink-0"
587
- }), /* @__PURE__ */ jsxs("div", {
588
- className: "min-w-0",
589
- children: [/* @__PURE__ */ jsx("div", {
590
- className: "font-semibold theme-text leading-tight",
591
- children: label
592
- }), /* @__PURE__ */ jsx("div", {
593
- className: "theme-muted-text text-xs leading-snug mt-0.5",
594
- children: description
595
- })]
596
- })]
596
+ "aria-label": label
597
+ }), /* @__PURE__ */ jsx("div", { className: "h-6 w-11 rounded-full bg-(--theme-muted-panel-bg) transition-colors peer-checked:bg-(--theme-element) peer-focus-visible:ring-2 peer-focus-visible:ring-[color-mix(in_srgb,var(--theme-element)_25%,transparent)] after:absolute after:start-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:bg-white after:shadow-sm after:transition-transform after:content-[\"\"] motion-reduce:after:transition-none peer-checked:after:translate-x-5" })]
597
598
  });
598
599
  }
599
600
  //#endregion
600
- export { AddMenu, BareModal, BreadcrumbProvider, BreadcrumbsActionButton, BreadcrumbsRightAction, BreadcrumbsTitleAction, Button, CREATE_MODAL_SELECT_FILTER_THRESHOLD, Callout, Card, CardHeader, CompactTable, ConfirmModal, ControlledCollapsiblePanel, CopyCodeBlock, CopyToClipboard, CreateModal, CreateModalAutocompleteField, CreateModalField, CreateModalSelect, CreateModalSwitch, CreateModalTextarea, CustomListbox, DEFAULT_PRESET, DescriptionList, DescriptionListItem, Dropdown, DropdownCaret, EmptyState, Filter, FilterPill, GlobalTooltip, HeaderActionMenu, HeaderAddButton, HeaderEditButton, HeaderRowMenu, IconButton, Indicator, Input, LetterBadge, Loader, Markdown, MaybeCollapsible, MethodButton, MultiSelectDropdown, Overview, PageHeader, Pagination, RequiredMark, SectionHeader, SettingModeOption, SettingRow, SettingSection, SettingsCard, SettingsGroup, Sort, StatusBadge, StatusDot, SwitchToggle, SwitchToggleSmall, THEME_PRESETS, THEME_TOKENS, TOOLTIP_ID, Table, Textarea, Toggle, TooltipInfo, UIProvider, UncontrolledCollapsiblePanel, applyTheme, contrastRatio, dangerButtonClasses, deriveTheme, filterOption, flattenOptions, formatTooltipContent, ghostButtonClasses, headerActionButtonClasses, inputClasses, isCategory, isDarkColor, isOption, modalPanelClasses, primaryButtonClasses, statusTextClass, toggleSetMember, truncationTooltipProps, useBreadcrumb, useClearBreadcrumbs, useCssIsDark, useHideBreadcrumbs, useNavigation, useNotify, usePersistedState, useProvisionCorsRules, useRelativeTime, useRepoSuggestions, useRunFile, useSetBreadcrumbs, useSetDefaultBreadcrumbs, useSlots, useStrings, useWorkflowJsonResolver };
601
+ export { AddMenu, Avatar, BareModal, BreadcrumbProvider, BreadcrumbsActionButton, BreadcrumbsRightAction, BreadcrumbsTitleAction, Button, CREATE_MODAL_SELECT_FILTER_THRESHOLD, Callout, Card, CardHeader, CompactTable, ConfirmModal, ControlledCollapsiblePanel, CopyCodeBlock, CopyToClipboard, CreateModal, CreateModalAutocompleteField, CreateModalField, CreateModalSelect, CreateModalSwitch, CreateModalTextarea, CustomListbox, DEFAULT_PRESET, DescriptionList, DescriptionListItem, Dropdown, DropdownCaret, EmptyState, Filter, FilterPill, GlobalTooltip, HeaderActionMenu, HeaderAddButton, HeaderEditButton, HeaderRowMenu, IconButton, Indicator, Input, LetterBadge, Loader, Markdown, MaybeCollapsible, MethodButton, MultiSelectDropdown, Overview, PageHeader, Pagination, RequiredMark, SectionHeader, SettingModeOption, SettingRow, SettingSection, SettingsCard, SettingsGroup, Sort, StatusBadge, StatusDot, SwitchToggle, SwitchToggleSmall, THEME_PRESETS, THEME_TOKENS, TOOLTIP_ID, Table, Textarea, Toggle, TooltipInfo, UIProvider, UncontrolledCollapsiblePanel, applyTheme, avatarInitials, contrastRatio, dangerButtonClasses, deriveTheme, filterOption, flattenOptions, formatTooltipContent, ghostButtonClasses, headerActionButtonClasses, inputClasses, isCategory, isDarkColor, isOption, modalPanelClasses, primaryButtonClasses, statusTextClass, toggleSetMember, truncationTooltipProps, useBreadcrumb, useClearBreadcrumbs, useCssIsDark, useHideBreadcrumbs, useNavigation, useNotify, useOptionalWorkflowEngine, usePersistedState, useProvisionCorsRules, useRelativeTime, useRunFile, useSetBreadcrumbs, useSetDefaultBreadcrumbs, useSlots, useStrings, useWorkflowEngine, useWorkflowEngineLoader };