@keyfunc/keybricks-ds 1.0.4 → 2.3.1
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.
- package/DEPLOY.md +14 -5
- package/DESIGN.md +245 -59
- package/INTEGRATION.md +243 -49
- package/SKILL.md +13 -11
- package/_adherence.oxlintrc.json +183 -70
- package/_scripts/build-index.mjs +24 -4
- package/_scripts/build-tokens.mjs +5 -2
- package/assets/icons/icon-index.js +1 -1
- package/assets/icons/icon-index.json +1 -1
- package/components/_cards/accordion.card.html +2 -2
- package/components/_cards/action-chip.card.html +11 -9
- package/components/_cards/activity.card.html +3 -3
- package/components/_cards/alert.card.html +3 -3
- package/components/_cards/app-chrome.card.html +4 -4
- package/components/_cards/banner.card.html +1 -1
- package/components/_cards/breadcrumb.card.html +5 -5
- package/components/_cards/button-1-base.card.html +23 -26
- package/components/_cards/button-2-states.card.html +27 -25
- package/components/_cards/button-3-sizes-icons.card.html +20 -19
- package/components/_cards/button-4-group.card.html +14 -31
- package/components/_cards/canvas-zoom-controls.card.html +1 -1
- package/components/_cards/cards-indicators.card.html +2 -2
- package/components/_cards/charts-1-sparkline.card.html +5 -5
- package/components/_cards/charts-10-gauge.card.html +5 -5
- package/components/_cards/charts-11-funnel.card.html +3 -3
- package/components/_cards/charts-12-treemap.card.html +3 -3
- package/components/_cards/charts-14-radar.card.html +3 -3
- package/components/_cards/charts-15-distribution.card.html +2 -2
- package/components/_cards/charts-16-pareto.card.html +3 -3
- package/components/_cards/charts-17-candlestick.card.html +3 -3
- package/components/_cards/charts-18-sankey.card.html +3 -3
- package/components/_cards/charts-19-chord.card.html +3 -3
- package/components/_cards/charts-2-line.card.html +4 -4
- package/components/_cards/charts-20-sunburst.card.html +3 -3
- package/components/_cards/charts-21-worldmap.card.html +4 -4
- package/components/_cards/charts-22-gantt.card.html +3 -3
- package/components/_cards/charts-23-bar3d.card.html +3 -3
- package/components/_cards/charts-24-pie3d.card.html +3 -3
- package/components/_cards/charts-25-surface3d.card.html +3 -3
- package/components/_cards/charts-26-scatter3d.card.html +3 -3
- package/components/_cards/charts-27-ribbon3d.card.html +3 -3
- package/components/_cards/charts-3-bar.card.html +7 -7
- package/components/_cards/charts-4-barlist.card.html +3 -3
- package/components/_cards/charts-5-donut.card.html +4 -4
- package/components/_cards/charts-6-scatter.card.html +3 -3
- package/components/_cards/charts-7-heatmap.card.html +3 -3
- package/components/_cards/charts-8-waterfall.card.html +3 -3
- package/components/_cards/charts-9-bullet.card.html +3 -3
- package/components/_cards/charts-99-fullpage.card.html +5 -5
- package/components/_cards/checkbox.card.html +9 -6
- package/components/_cards/codeblock.card.html +2 -2
- package/components/_cards/combobox.card.html +6 -3
- package/components/_cards/context-menu.card.html +6 -3
- package/components/_cards/date-picker.card.html +10 -4
- package/components/_cards/diffvalue.card.html +3 -3
- package/components/_cards/divider.card.html +4 -4
- package/components/_cards/drawer.card.html +4 -4
- package/components/_cards/dropdown-menu.card.html +7 -7
- package/components/_cards/dropzone.card.html +5 -3
- package/components/_cards/empty-state.card.html +6 -6
- package/components/_cards/filter-bar.card.html +5 -5
- package/components/_cards/icon-button.card.html +14 -14
- package/components/_cards/icons-1-core.card.html +4 -4
- package/components/_cards/icons-2-feather.card.html +4 -4
- package/components/_cards/icons-3-unicons.card.html +4 -4
- package/components/_cards/input.card.html +5 -2
- package/components/_cards/kbd.card.html +2 -2
- package/components/_cards/keyvalue.card.html +2 -2
- package/components/_cards/listrow.card.html +2 -2
- package/components/_cards/loading.card.html +3 -3
- package/components/_cards/log-viewer.card.html +3 -3
- package/components/_cards/modal.card.html +9 -9
- package/components/_cards/multi-select.card.html +6 -3
- package/components/_cards/number-stepper.card.html +9 -5
- package/components/_cards/pagination.card.html +6 -3
- package/components/_cards/people.card.html +4 -4
- package/components/_cards/pipeline-node.card.html +8 -8
- package/components/_cards/pipeline-palette.card.html +5 -5
- package/components/_cards/radio.card.html +12 -7
- package/components/_cards/search.card.html +6 -3
- package/components/_cards/segmented-control.card.html +11 -10
- package/components/_cards/select.card.html +8 -4
- package/components/_cards/slider.card.html +2 -2
- package/components/_cards/smart-table.card.html +3 -3
- package/components/_cards/spreadsheet.card.html +3 -3
- package/components/_cards/stepper.card.html +3 -3
- package/components/_cards/table.card.html +165 -0
- package/components/_cards/tabs.card.html +6 -3
- package/components/_cards/tag.card.html +6 -3
- package/components/_cards/textarea.card.html +2 -2
- package/components/_cards/timeline.card.html +3 -3
- package/components/_cards/toast.card.html +10 -8
- package/components/_cards/toggles.card.html +15 -10
- package/components/_cards/tooltip.card.html +7 -7
- package/components/_cards/tree.card.html +3 -3
- package/components/_shared/card-kit.css +25 -0
- package/components/_shared/card-kit.js +50 -0
- package/components/_shared/src-buttons.js +1 -1
- package/components/_shared/src-charts.js +1 -1
- package/components/_shared/src-data.js +1 -1
- package/components/_shared/src-display.js +1 -1
- package/components/_shared/src-feedback.js +1 -1
- package/components/_shared/src-forms.js +1 -1
- package/components/_shared/src-icons.js +1 -1
- package/components/_shared/src-navigation.js +1 -1
- package/components/_shared/src-pipeline.js +1 -1
- package/components/_shared/src-tabs.js +1 -1
- package/components/_shared/view-source.js +3 -3
- package/components/_vue/index.mjs +16 -5
- package/components/buttons/ActionChip.d.ts +3 -1
- package/components/buttons/ActionChip.jsx +4 -4
- package/components/buttons/ActionChip.vue +4 -4
- package/components/buttons/Button.d.ts +5 -2
- package/components/buttons/Button.jsx +15 -18
- package/components/buttons/Button.vue +17 -18
- package/components/buttons/ButtonGroup.vue +1 -1
- package/components/buttons/IconButton.d.ts +2 -1
- package/components/buttons/IconButton.jsx +13 -9
- package/components/buttons/IconButton.vue +12 -9
- package/components/buttons/buttons.prompt.md +6 -5
- package/components/charts/Bar3D.jsx +2 -2
- package/components/charts/Bar3D.vue +3 -3
- package/components/charts/BarChart.jsx +4 -4
- package/components/charts/BarChart.vue +6 -6
- package/components/charts/BarList.jsx +4 -4
- package/components/charts/BarList.vue +4 -4
- package/components/charts/BoxPlot.jsx +1 -1
- package/components/charts/BoxPlot.vue +3 -3
- package/components/charts/BulletChart.jsx +6 -6
- package/components/charts/BulletChart.vue +6 -6
- package/components/charts/CandlestickChart.jsx +2 -2
- package/components/charts/CandlestickChart.vue +5 -5
- package/components/charts/ChartKit.jsx +8 -7
- package/components/charts/ChartLegend.vue +16 -0
- package/components/charts/ChartTooltip.vue +16 -0
- package/components/charts/ChordChart.jsx +2 -2
- package/components/charts/ChordChart.vue +3 -3
- package/components/charts/DonutChart.jsx +1 -1
- package/components/charts/DonutChart.vue +2 -2
- package/components/charts/FunnelChart.jsx +3 -3
- package/components/charts/FunnelChart.vue +4 -4
- package/components/charts/GanttChart.jsx +2 -2
- package/components/charts/GanttChart.vue +3 -3
- package/components/charts/GaugeChart.jsx +2 -2
- package/components/charts/GaugeChart.vue +2 -2
- package/components/charts/HeatmapChart.jsx +2 -2
- package/components/charts/HeatmapChart.vue +2 -2
- package/components/charts/Histogram.jsx +2 -2
- package/components/charts/Histogram.vue +4 -4
- package/components/charts/LineChart.jsx +1 -1
- package/components/charts/LineChart.vue +4 -4
- package/components/charts/ParetoChart.jsx +3 -3
- package/components/charts/ParetoChart.vue +5 -5
- package/components/charts/Pie3D.jsx +1 -1
- package/components/charts/Pie3D.vue +2 -2
- package/components/charts/PlotGrid.vue +18 -0
- package/components/charts/RadarChart.jsx +1 -1
- package/components/charts/RadarChart.vue +2 -2
- package/components/charts/Ribbon3D.jsx +2 -2
- package/components/charts/Ribbon3D.vue +3 -3
- package/components/charts/SankeyChart.jsx +2 -2
- package/components/charts/SankeyChart.vue +3 -3
- package/components/charts/Scatter3D.jsx +1 -1
- package/components/charts/Scatter3D.vue +2 -2
- package/components/charts/ScatterChart.jsx +3 -3
- package/components/charts/ScatterChart.vue +5 -5
- package/components/charts/Sparkline.jsx +1 -1
- package/components/charts/Sparkline.vue +1 -1
- package/components/charts/SunburstChart.jsx +1 -1
- package/components/charts/SunburstChart.vue +2 -2
- package/components/charts/Surface3D.jsx +2 -2
- package/components/charts/Surface3D.vue +3 -3
- package/components/charts/TreemapChart.jsx +2 -2
- package/components/charts/TreemapChart.vue +3 -3
- package/components/charts/WaterfallChart.jsx +2 -2
- package/components/charts/WaterfallChart.vue +6 -5
- package/components/charts/WorldMap.jsx +4 -4
- package/components/charts/WorldMap.vue +5 -5
- package/components/charts/XLabels.vue +11 -0
- package/components/data/CodeBlock.jsx +1 -1
- package/components/data/CodeBlock.vue +1 -1
- package/components/data/DiffValue.d.ts +1 -0
- package/components/data/DiffValue.jsx +1 -1
- package/components/data/DiffValue.vue +1 -1
- package/components/data/FilterBar.d.ts +2 -0
- package/components/data/FilterBar.jsx +10 -9
- package/components/data/FilterBar.vue +9 -8
- package/components/data/KeyValue.d.ts +1 -1
- package/components/data/KeyValue.jsx +4 -4
- package/components/data/KeyValue.vue +4 -4
- package/components/data/ListRow.jsx +2 -2
- package/components/data/ListRow.vue +2 -2
- package/components/data/Pagination.d.ts +5 -1
- package/components/data/Pagination.jsx +16 -12
- package/components/data/Pagination.vue +14 -9
- package/components/data/SmartTable.d.ts +4 -1
- package/components/data/SmartTable.jsx +16 -14
- package/components/data/SmartTable.vue +26 -23
- package/components/data/Spreadsheet.d.ts +2 -0
- package/components/data/Spreadsheet.jsx +16 -15
- package/components/data/Spreadsheet.vue +19 -18
- package/components/data/Table.d.ts +101 -0
- package/components/data/Table.jsx +223 -0
- package/components/data/Table.vue +153 -0
- package/components/data/data.prompt.md +3 -3
- package/components/display/Avatar.jsx +2 -2
- package/components/display/Avatar.vue +3 -2
- package/components/display/AvatarGroup.vue +3 -2
- package/components/display/Badge.d.ts +4 -1
- package/components/display/Badge.jsx +10 -5
- package/components/display/Badge.vue +1 -1
- package/components/display/Divider.vue +3 -3
- package/components/display/Donut.vue +3 -2
- package/components/display/IconTile.vue +10 -4
- package/components/display/Kbd.d.ts +1 -1
- package/components/display/Kbd.jsx +1 -1
- package/components/display/Kbd.vue +2 -2
- package/components/display/ProgressBar.jsx +1 -1
- package/components/display/ProgressBar.vue +1 -1
- package/components/display/StatCard.vue +1 -1
- package/components/display/Tag.d.ts +3 -1
- package/components/display/Tag.jsx +4 -4
- package/components/display/Tag.vue +4 -4
- package/components/feedback/Accordion.jsx +2 -2
- package/components/feedback/Accordion.vue +2 -2
- package/components/feedback/ActivityItem.d.ts +3 -1
- package/components/feedback/ActivityItem.jsx +6 -6
- package/components/feedback/ActivityItem.vue +5 -4
- package/components/feedback/Alert.jsx +4 -4
- package/components/feedback/Alert.vue +3 -3
- package/components/feedback/Banner.jsx +5 -5
- package/components/feedback/Banner.vue +5 -5
- package/components/feedback/ContextMenu.d.ts +3 -1
- package/components/feedback/ContextMenu.jsx +5 -5
- package/components/feedback/ContextMenu.vue +5 -5
- package/components/feedback/DotActivity.vue +3 -3
- package/components/feedback/Drawer.d.ts +2 -0
- package/components/feedback/Drawer.jsx +6 -6
- package/components/feedback/Drawer.vue +22 -15
- package/components/feedback/EmptyState.vue +2 -2
- package/components/feedback/LogViewer.vue +1 -1
- package/components/feedback/Modal.d.ts +2 -0
- package/components/feedback/Modal.jsx +12 -11
- package/components/feedback/Modal.vue +10 -8
- package/components/feedback/Skeleton.vue +2 -1
- package/components/feedback/Spinner.vue +2 -1
- package/components/feedback/Stepper.vue +1 -1
- package/components/feedback/Timeline.jsx +1 -1
- package/components/feedback/Timeline.vue +3 -3
- package/components/feedback/Toast.vue +4 -4
- package/components/feedback/ToastStack.vue +11 -0
- package/components/feedback/Tooltip.vue +19 -0
- package/components/feedback/feedback.prompt.md +4 -4
- package/components/forms/Checkbox.d.ts +3 -2
- package/components/forms/Checkbox.jsx +7 -7
- package/components/forms/Checkbox.vue +8 -8
- package/components/forms/Combobox.d.ts +2 -0
- package/components/forms/Combobox.jsx +12 -10
- package/components/forms/Combobox.vue +11 -10
- package/components/forms/DatePicker.d.ts +4 -0
- package/components/forms/DatePicker.jsx +16 -12
- package/components/forms/DatePicker.vue +15 -11
- package/components/forms/Dropzone.jsx +2 -2
- package/components/forms/Dropzone.vue +5 -5
- package/components/forms/Field.d.ts +5 -1
- package/components/forms/Field.jsx +4 -4
- package/components/forms/Field.vue +4 -4
- package/components/forms/Input.d.ts +5 -1
- package/components/forms/Input.jsx +8 -8
- package/components/forms/Input.vue +3 -3
- package/components/forms/MultiSelect.d.ts +2 -0
- package/components/forms/MultiSelect.jsx +13 -11
- package/components/forms/MultiSelect.vue +12 -11
- package/components/forms/NumberStepper.d.ts +3 -1
- package/components/forms/NumberStepper.jsx +7 -7
- package/components/forms/NumberStepper.vue +8 -7
- package/components/forms/Radio.d.ts +5 -3
- package/components/forms/Radio.jsx +13 -15
- package/components/forms/Radio.vue +9 -10
- package/components/forms/RadioGroup.vue +5 -5
- package/components/forms/SearchInput.d.ts +3 -1
- package/components/forms/SearchInput.jsx +6 -6
- package/components/forms/SearchInput.vue +7 -6
- package/components/forms/Select.d.ts +3 -2
- package/components/forms/Select.jsx +6 -7
- package/components/forms/Select.vue +6 -6
- package/components/forms/Slider.jsx +3 -3
- package/components/forms/Slider.vue +3 -3
- package/components/forms/Switch.d.ts +2 -2
- package/components/forms/Switch.jsx +20 -22
- package/components/forms/Switch.vue +22 -18
- package/components/forms/Textarea.vue +5 -5
- package/components/forms/forms.prompt.md +1 -1
- package/components/forms/input-base.js +2 -1
- package/components/icons/Icon.jsx +17 -1
- package/components/icons/Icon.prompt.md +2 -0
- package/components/icons/Icon.vue +1 -1
- package/components/icons/icon-paths.js +15 -0
- package/components/index.d.ts +1 -2
- package/components/index.js +4 -5
- package/components/navigation/Breadcrumb.jsx +6 -10
- package/components/navigation/Breadcrumb.vue +6 -12
- package/components/navigation/DocTree.jsx +3 -3
- package/components/navigation/DocTree.vue +3 -3
- package/components/navigation/PageHeading.vue +1 -1
- package/components/navigation/PageToolbar.vue +7 -6
- package/components/navigation/Sidebar.jsx +4 -23
- package/components/navigation/Sidebar.vue +5 -10
- package/components/navigation/ThemeToggle.vue +2 -1
- package/components/navigation/TopBar.d.ts +3 -1
- package/components/navigation/TopBar.jsx +6 -6
- package/components/navigation/Tree.jsx +5 -5
- package/components/navigation/Tree.vue +13 -8
- package/components/navigation/nav-model.js +23 -0
- package/components/navigation/theme-store.js +9 -0
- package/components/pipeline/ConfigPanel.d.ts +2 -0
- package/components/pipeline/ConfigPanel.jsx +9 -9
- package/components/pipeline/ConfigPanel.vue +9 -9
- package/components/pipeline/DataPreview.d.ts +3 -1
- package/components/pipeline/DataPreview.jsx +7 -7
- package/components/pipeline/DataPreview.vue +7 -7
- package/components/pipeline/NodeCard.jsx +3 -3
- package/components/pipeline/NodeCard.vue +3 -3
- package/components/pipeline/PaletteItem.vue +2 -2
- package/components/pipeline/PaletteListItem.vue +1 -1
- package/components/pipeline/PalettePanel.jsx +2 -2
- package/components/pipeline/PalettePanel.vue +1 -1
- package/components/pipeline/Port.vue +15 -0
- package/components/pipeline/PortLabel.vue +15 -0
- package/components/pipeline/ZoomControls.vue +1 -1
- package/components/pipeline/port-skin.js +13 -0
- package/components/px.js +4 -0
- package/components/tabs/PanelTabs.vue +5 -4
- package/components/tabs/PillTabs.vue +5 -4
- package/components/tabs/SegmentedControl.d.ts +2 -2
- package/components/tabs/SegmentedControl.jsx +7 -7
- package/components/tabs/SegmentedControl.vue +7 -7
- package/components/tabs/Tabs.d.ts +5 -3
- package/components/tabs/Tabs.jsx +15 -15
- package/components/tabs/Tabs.vue +5 -5
- package/components/tabs/ViewToggle.d.ts +3 -1
- package/components/tabs/ViewToggle.jsx +5 -5
- package/components/tabs/ViewToggle.vue +5 -5
- package/components/tabs/tabs.prompt.md +1 -1
- package/keybricks.css +4 -0
- package/package.json +6 -3
- package/readme.md +91 -122
- package/readme.zh-CN.md +121 -0
- package/tokens/alpha.css +3 -1
- package/tokens/charts.css +20 -17
- package/tokens/colors.css +3 -3
- package/tokens/dark.css +3 -3
- package/tokens/hover.css +32 -0
- package/tokens/interaction.css +3 -1
- package/tokens/layout.css +31 -7
- package/tokens/tokens.d.ts +58 -0
- package/tokens/tokens.js +179 -92
- package/tokens/tokens.json +327 -114
- package/tokens/typography.css +45 -15
- package/components/_cards/brand-visual.card.html +0 -43
- package/components/_cards/datatable.card.html +0 -48
- package/components/_shared/src-brand.js +0 -1
- package/components/brand/BrandVisual.d.ts +0 -17
- package/components/brand/BrandVisual.jsx +0 -29
- package/components/brand/BrandVisual.vue +0 -34
- package/components/brand/_dir.card.html +0 -13
- package/components/brand/brandMotifs.js +0 -210
- package/components/buttons/_dir.card.html +0 -13
- package/components/charts/ChartKit.vue +0 -47
- package/components/charts/_dir.card.html +0 -7
- package/components/data/DataTable.d.ts +0 -28
- package/components/data/DataTable.jsx +0 -32
- package/components/data/DataTable.vue +0 -25
- package/components/data/_dir.card.html +0 -13
- package/components/display/_dir.card.html +0 -13
- package/components/feedback/_dir.card.html +0 -13
- package/components/forms/_dir.card.html +0 -13
- package/components/icons/_dir.card.html +0 -13
- package/components/navigation/_dir.card.html +0 -13
- package/components/pipeline/_dir.card.html +0 -13
- package/components/tabs/_dir.card.html +0 -13
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Icon } from "../icons/Icon.jsx";
|
|
3
|
+
import { KEYBRICKS_NAV } from "./nav-model.js";
|
|
3
4
|
|
|
4
5
|
function NavItem({ icon, label, active, indent, collapsed, badge, onClick }) {
|
|
5
6
|
const [hover, setHover] = React.useState(false);
|
|
@@ -30,7 +31,7 @@ export function Sidebar({ items = [], footerItems = [{ icon: "circle-help", labe
|
|
|
30
31
|
{onToggleCollapse ? <NavItem icon="panel-left" label="Collapse" collapsed={collapsed} onClick={onToggleCollapse} /> : null}
|
|
31
32
|
{items.map((it) => it.children ? (
|
|
32
33
|
<div key={it.label}>
|
|
33
|
-
<div onClick={() => toggleSection(it.label)} style={{ height: "var(--h-subnav-item)", display: "flex", alignItems: "center", gap: 10, padding: collapsed ? "6px 10px" : "6px 10px", justifyContent: collapsed ? "center" : "flex-start", cursor: "pointer", color: "var(--text-body)", borderRadius: "var(--radius-md)", boxSizing: "border-box" }}>
|
|
34
|
+
<div role="button" tabIndex={0} data-wash="" onClick={() => toggleSection(it.label)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); toggleSection(it.label); } }} style={{ background: "var(--wash, transparent)", transition: "var(--t-hover)", height: "var(--h-subnav-item)", display: "flex", alignItems: "center", gap: 10, padding: collapsed ? "6px 10px" : "6px 10px", justifyContent: collapsed ? "center" : "flex-start", cursor: "pointer", color: "var(--text-body)", borderRadius: "var(--radius-md)", boxSizing: "border-box" }}>
|
|
34
35
|
<Icon name={it.icon} size={16} />
|
|
35
36
|
{!collapsed ? <><span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-base)", letterSpacing: "var(--tracking-base)", flex: 1 }}>{it.label}</span><Icon name={openSections.includes(it.label) ? "chevron-up" : "chevron-down"} size={14} /></> : null}
|
|
36
37
|
</div>
|
|
@@ -51,25 +52,5 @@ export function Sidebar({ items = [], footerItems = [{ icon: "circle-help", labe
|
|
|
51
52
|
);
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
/** Default Keybricks nav model (Home dashboard). */
|
|
55
|
-
export
|
|
56
|
-
{ icon: "house", label: "Home" },
|
|
57
|
-
{ icon: "file-text", label: "Documents" },
|
|
58
|
-
{ icon: "layout-grid", label: "Business Intelligence" },
|
|
59
|
-
{ icon: "database", label: "Data Integration" },
|
|
60
|
-
{ icon: "scale", label: "Reconciliation" },
|
|
61
|
-
{ icon: "network", label: "Consolidation" },
|
|
62
|
-
{
|
|
63
|
-
icon: "folder-cog", label: "Management", children: [
|
|
64
|
-
{ icon: "box", label: "Modeling" },
|
|
65
|
-
{ icon: "workflow", label: "Workflow" },
|
|
66
|
-
{ icon: "shield", label: "Security Management" },
|
|
67
|
-
{ icon: "refresh-cw", label: "System Migration" },
|
|
68
|
-
{ icon: "chart-column", label: "Business Logic" },
|
|
69
|
-
{ icon: "list-todo", label: "Tasks Management" },
|
|
70
|
-
{ icon: "circle-check", label: "Validation Rules" },
|
|
71
|
-
{ icon: "settings-2", label: "Control Center" },
|
|
72
|
-
{ icon: "network", label: "Reconciliation" },
|
|
73
|
-
],
|
|
74
|
-
},
|
|
75
|
-
];
|
|
55
|
+
/** Default Keybricks nav model (Home dashboard) — defined in nav-model.js, shared with the Vue entry. */
|
|
56
|
+
export { KEYBRICKS_NAV };
|
|
@@ -16,11 +16,11 @@ const props = defineProps({
|
|
|
16
16
|
const emit = defineEmits(['select', 'toggleCollapse'])
|
|
17
17
|
const openSections = ref(props.items.filter(i => i.children && (i.open || i.children.some(c => c.label === props.active))).map(i => i.label))
|
|
18
18
|
function toggleSection(l) { openSections.value = openSections.value.includes(l) ? openSections.value.filter(x => x !== l) : [...openSections.value, l] }
|
|
19
|
-
function itemStyle(active, indent) { return { height: indent ? 'var(--h-subnav-item)' : 'var(--h-nav-item)', borderRadius: 'var(--radius-md)', display: 'flex', alignItems: 'center', gap:
|
|
19
|
+
function itemStyle(active, indent) { return { height: indent ? 'var(--h-subnav-item)' : 'var(--h-nav-item)', borderRadius: 'var(--radius-md)', display: 'flex', alignItems: 'center', gap: '10px', padding: indent ? '6px 10px' : '8px 10px', boxSizing: 'border-box', cursor: 'pointer', background: active ? 'var(--bg-active)' : 'transparent', color: active ? 'var(--text-heading)' : 'var(--text-body)', transition: 'var(--t-hover)' } }
|
|
20
20
|
</script>
|
|
21
21
|
<template>
|
|
22
22
|
<aside :style="{ width: collapsed ? 'var(--rail-w)' : 'var(--sidebar-w)', height, background: 'var(--bg-surface)', borderRight: '1px solid var(--border-card)', display: 'flex', flexDirection: 'column', boxSizing: 'border-box', flexShrink: 0, transition: 'width .15s ease', ...style }">
|
|
23
|
-
<div :style="{ height: 'var(--topbar-h)', borderBottom: '1px solid var(--border-card)', display: 'flex', alignItems: 'center', gap:
|
|
23
|
+
<div :style="{ height: 'var(--topbar-h)', borderBottom: '1px solid var(--border-card)', display: 'flex', alignItems: 'center', gap: '10px', padding: '0 16px', boxSizing: 'border-box', justifyContent: collapsed ? 'center' : 'flex-start', flexShrink: 0 }">
|
|
24
24
|
<img :src="logo" alt="" style="width:24px;height:24px;object-fit:contain" />
|
|
25
25
|
<span v-if="!collapsed" style="font-family:var(--font-sans);font-weight:var(--weight-semibold);font-size:var(--text-lg);line-height:var(--leading-lg);letter-spacing:-.609px;color:var(--text-primary)">{{ brand }}</span>
|
|
26
26
|
</div>
|
|
@@ -28,7 +28,7 @@ function itemStyle(active, indent) { return { height: indent ? 'var(--h-subnav-i
|
|
|
28
28
|
<div v-if="canCollapse" role="button" tabindex="0" @click="emit('toggleCollapse')" :style="itemStyle(false, false)"><Icon name="panel-left" :size="16" /><span v-if="!collapsed" style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);white-space:nowrap;flex:1">Collapse</span></div>
|
|
29
29
|
<template v-for="it in items" :key="it.label">
|
|
30
30
|
<div v-if="it.children">
|
|
31
|
-
<div role="button" tabindex="0" @click="toggleSection(it.label)" :style="{ height: 'var(--h-subnav-item)', display: 'flex', alignItems: 'center', gap:
|
|
31
|
+
<div role="button" tabindex="0" data-wash="" @click="toggleSection(it.label)" @keydown.enter.prevent="toggleSection(it.label)" @keydown.space.prevent="toggleSection(it.label)" :style="{ background: 'var(--wash, transparent)', transition: 'var(--t-hover)', height: 'var(--h-subnav-item)', display: 'flex', alignItems: 'center', gap: '10px', padding: '6px 10px', justifyContent: collapsed ? 'center' : 'flex-start', cursor: 'pointer', color: 'var(--text-body)', borderRadius: 'var(--radius-md)', boxSizing: 'border-box' }">
|
|
32
32
|
<Icon :name="it.icon" :size="16" />
|
|
33
33
|
<template v-if="!collapsed"><span style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-base);letter-spacing:var(--tracking-base);flex:1">{{ it.label }}</span><Icon :name="openSections.includes(it.label) ? 'chevron-up' : 'chevron-down'" :size="14" /></template>
|
|
34
34
|
</div>
|
|
@@ -45,10 +45,5 @@ function itemStyle(active, indent) { return { height: indent ? 'var(--h-subnav-i
|
|
|
45
45
|
</aside>
|
|
46
46
|
</template>
|
|
47
47
|
|
|
48
|
-
<!--
|
|
49
|
-
|
|
50
|
-
{ icon: 'house', label: 'Home' }, { icon: 'file-text', label: 'Documents' },
|
|
51
|
-
{ icon: 'layout-grid', label: 'Business Intelligence' }, { icon: 'database', label: 'Data Integration' },
|
|
52
|
-
{ icon: 'scale', label: 'Reconciliation' }, { icon: 'network', label: 'Consolidation' },
|
|
53
|
-
{ icon: 'folder-cog', label: 'Management', children: [ ... ] },
|
|
54
|
-
] -->
|
|
48
|
+
<!-- The product's nav model is KEYBRICKS_NAV in ./nav-model.js — also exported from the Vue entry:
|
|
49
|
+
import { Sidebar, KEYBRICKS_NAV } from '@keyfunc/keybricks-ds/vue' -->
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { px } from '../px.js'
|
|
2
3
|
import { ref, computed, watch, onMounted } from 'vue'
|
|
3
4
|
import Icon from '../icons/Icon.vue'
|
|
4
5
|
const props = defineProps({ size: { type: Number, default: 34 }, dark: { type: Boolean, default: null }, style: Object })
|
|
@@ -12,7 +13,7 @@ function toggle() { if (props.dark != null) emit('update:dark', !dark.value); el
|
|
|
12
13
|
</script>
|
|
13
14
|
<template>
|
|
14
15
|
<button type="button" :aria-label="dark ? 'Switch to light mode' : 'Switch to dark mode'" @click="toggle" @mouseenter="hover = true" @mouseleave="hover = false"
|
|
15
|
-
:style="{ width: size, height: size, borderRadius: 'var(--radius-md)', border: 'none', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', background: hover ? 'var(--bg-hover)' : 'transparent', color: 'var(--text-body)', padding: 0, transition: 'var(--t-hover)', ...style }">
|
|
16
|
+
:style="{ width: px(size), height: px(size), borderRadius: 'var(--radius-md)', border: 'none', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', background: hover ? 'var(--bg-hover)' : 'transparent', color: 'var(--text-body)', padding: 0, transition: 'var(--t-hover)', ...style }">
|
|
16
17
|
<Icon :name="dark ? 'sparkles' : 'moon'" :size="18" />
|
|
17
18
|
</button>
|
|
18
19
|
</template>
|
|
@@ -15,10 +15,12 @@ export interface PageToolbarProps {
|
|
|
15
15
|
status?: string;
|
|
16
16
|
actions?: React.ReactNode;
|
|
17
17
|
onBack?: () => void;
|
|
18
|
+
/** Size tier for the toolbar's controls. Omit to inherit (the default). */
|
|
19
|
+
size?: "sm" | "md" | "lg";
|
|
18
20
|
style?: React.CSSProperties;
|
|
19
21
|
}
|
|
20
22
|
export declare function PageToolbar(props: PageToolbarProps): JSX.Element;
|
|
21
|
-
/**
|
|
23
|
+
/** Page title (--text-lg 20px/500) + muted subtitle. */
|
|
22
24
|
export interface PageHeadingProps {
|
|
23
25
|
title?: string;
|
|
24
26
|
subtitle?: string;
|
|
@@ -20,15 +20,15 @@ export function TopBar({ placeholder = "Search documents, workflows, data...", a
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/** Editor toolbar: back chevron, 14px/600 title, "• Editing" status, right action slot. */
|
|
23
|
-
export function PageToolbar({ title, status = "• Editing", actions, onBack, style }) {
|
|
23
|
+
export function PageToolbar({ title, status = "• Editing", actions, onBack, size, style }) {
|
|
24
24
|
return (
|
|
25
|
-
<div style={{ height: "var(--topbar-h)", background: "var(--bg-surface)", borderBottom: "1px solid var(--border-card)", display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0
|
|
26
|
-
<div style={{ display: "flex", alignItems: "center", gap:
|
|
27
|
-
{onBack ? <IconButton icon="chevron-left"
|
|
25
|
+
<div data-size={size} style={{ height: "var(--topbar-h)", background: "var(--bg-surface)", borderBottom: "1px solid var(--border-card)", display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 var(--edge-pad)", boxSizing: "border-box", flexShrink: 0, ...style }}>
|
|
26
|
+
<div style={{ display: "flex", alignItems: "center", gap: "var(--control-gap)" }}>
|
|
27
|
+
{onBack ? <IconButton icon="chevron-left" onClick={onBack} label="Back" /> : null}
|
|
28
28
|
<span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-semibold)", fontSize: "var(--text-md)", lineHeight: "var(--leading-md)", letterSpacing: "var(--tracking-md)", color: "var(--text-heading)" }}>{title}</span>
|
|
29
|
-
{status ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text
|
|
29
|
+
{status ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", letterSpacing: "var(--control-tracking)", color: "var(--text-muted)", marginLeft: 6 }}>{status}</span> : null}
|
|
30
30
|
</div>
|
|
31
|
-
<div style={{ display: "flex", alignItems: "center", gap:
|
|
31
|
+
<div style={{ display: "flex", alignItems: "center", gap: "var(--control-gap)" }}>{actions}</div>
|
|
32
32
|
</div>
|
|
33
33
|
);
|
|
34
34
|
}
|
|
@@ -153,7 +153,7 @@ function Row({ item, state, cfg, api }) {
|
|
|
153
153
|
{chevron}
|
|
154
154
|
{cfg.checkable && node.checkable !== false ? (
|
|
155
155
|
<span onClick={(e) => e.stopPropagation()} style={{ display: "inline-flex", flexShrink: 0 }}>
|
|
156
|
-
<Checkbox
|
|
156
|
+
<Checkbox checked={checked} indeterminate={half} disabled={disabled || node.disableCheckbox} onChange={() => api.check(key)} />
|
|
157
157
|
</span>
|
|
158
158
|
) : null}
|
|
159
159
|
{cfg.showIcon ? (
|
|
@@ -161,11 +161,11 @@ function Row({ item, state, cfg, api }) {
|
|
|
161
161
|
<Icon name={node.icon || (branch ? (open ? "folder-open" : "folder") : "file-text")} size={15} />
|
|
162
162
|
</span>
|
|
163
163
|
) : null}
|
|
164
|
-
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-
|
|
164
|
+
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", fontWeight: selected ? "var(--weight-medium)" : "var(--weight-regular)", color: disabled ? "var(--text-muted)" : "var(--text-heading)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
|
|
165
165
|
<Highlight text={titleOf(node)} query={cfg.searchValue} />
|
|
166
166
|
</span>
|
|
167
|
-
{node.tag ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-
|
|
168
|
-
{node.count != null ? <span style={{ marginLeft: "auto", fontFamily: "var(--font-
|
|
167
|
+
{node.tag ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", lineHeight: 1, padding: "2px 5px", borderRadius: "var(--radius-sm)", background: "var(--bg-inset)", color: "var(--text-secondary)", flexShrink: 0 }}>{node.tag}</span> : null}
|
|
168
|
+
{node.count != null ? <span style={{ marginLeft: "auto", fontFamily: "var(--font-sans)", fontVariantNumeric: "tabular-nums", fontSize: "var(--text-xs)", color: "var(--text-muted)", paddingLeft: 8 }}>{node.count}</span> : null}
|
|
169
169
|
{cfg.rowActions && !disabled ? <span style={{ marginLeft: node.count != null ? 6 : "auto", display: "flex", gap: 2, opacity: hover ? 1 : 0, transition: "var(--t-hover)" }} onClick={(e) => e.stopPropagation()}>{cfg.rowActions(node)}</span> : null}
|
|
170
170
|
</div>
|
|
171
171
|
{open && loading && !kids.length ? (
|
|
@@ -340,7 +340,7 @@ export function Tree({
|
|
|
340
340
|
<div role="tree" aria-multiselectable={multiple || undefined} style={{ display: "flex", flexDirection: "column", gap: showLine ? 0 : 1, ...style }}>
|
|
341
341
|
<style>{"@keyframes kb-tree-spin{to{transform:rotate(360deg)}}"}</style>
|
|
342
342
|
{rows.length === 0 ? (
|
|
343
|
-
<div style={{ padding: "10px 8px", fontFamily: "var(--font-sans)", fontSize: "var(--text-
|
|
343
|
+
<div style={{ padding: "10px 8px", fontFamily: "var(--font-sans)", fontSize: "var(--text-base)", color: "var(--text-muted)" }}>No matching items</div>
|
|
344
344
|
) : rows.map((r) => <Row key={r.key} item={r} state={state} cfg={cfg} api={api} />)}
|
|
345
345
|
</div>
|
|
346
346
|
);
|
|
@@ -9,6 +9,8 @@ const docHues = { orange: 'var(--cat-transform)', green: 'var(--cat-source)', pu
|
|
|
9
9
|
const INDENT = 18
|
|
10
10
|
const props = defineProps({
|
|
11
11
|
items: { type: Array, default: () => [] },
|
|
12
|
+
treeData: Array, // alias of items (same as Tree.jsx)
|
|
13
|
+
expandedKeys: Array, selectedKeys: Array, checkedKeys: Array, // controlled: the parent's value wins whenever it changes
|
|
12
14
|
defaultExpanded: { type: Array, default: () => [] },
|
|
13
15
|
defaultActive: String,
|
|
14
16
|
defaultSelected: { type: Array, default: () => [] },
|
|
@@ -24,12 +26,15 @@ const props = defineProps({
|
|
|
24
26
|
})
|
|
25
27
|
const emit = defineEmits(['select', 'check', 'expand', 'drop'])
|
|
26
28
|
|
|
27
|
-
const data = ref(JSON.parse(JSON.stringify(props.items)))
|
|
29
|
+
const data = ref(JSON.parse(JSON.stringify(props.treeData || props.items)))
|
|
28
30
|
// Compare by value: re-seeding on identity alone would wipe async-loaded children.
|
|
29
|
-
watch(() => JSON.stringify(props.items), (next, prev) => { if (next !== prev) data.value = JSON.parse(next) })
|
|
31
|
+
watch(() => JSON.stringify(props.treeData || props.items), (next, prev) => { if (next !== prev) data.value = JSON.parse(next) })
|
|
30
32
|
const expanded = ref([...props.defaultExpanded])
|
|
31
33
|
const selected = ref(props.defaultActive ? [props.defaultActive] : [...props.defaultSelected])
|
|
32
34
|
const checked = ref([...props.defaultChecked])
|
|
35
|
+
watch(() => props.expandedKeys, (v) => { if (v) expanded.value = [...v] }, { immediate: true })
|
|
36
|
+
watch(() => props.selectedKeys, (v) => { if (v) selected.value = [...v] }, { immediate: true })
|
|
37
|
+
watch(() => props.checkedKeys, (v) => { if (v) checked.value = [...v] }, { immediate: true })
|
|
33
38
|
const loading = ref([]); const loaded = ref([]); const focus = ref(null)
|
|
34
39
|
const dragKey = ref(null); const drop = ref(null)
|
|
35
40
|
|
|
@@ -235,24 +240,24 @@ const dropAt = k => (drop.value && drop.value.key === k ? drop.value.pos : null)
|
|
|
235
240
|
</span>
|
|
236
241
|
<span v-else :style="{ width: showLine ? 0 : '14px', flexShrink: 0 }" />
|
|
237
242
|
<span v-if="checkable && row.n.checkable !== false" @click.stop style="display:inline-flex;flex-shrink:0">
|
|
238
|
-
<Checkbox
|
|
243
|
+
<Checkbox :checked="view.full.has(row.key)" :indeterminate="view.half.has(row.key)"
|
|
239
244
|
:disabled="row.n.disabled || row.n.disableCheckbox" @change="check(row.key)" />
|
|
240
245
|
</span>
|
|
241
246
|
<span v-if="showIcon" :style="{ color: isBranch(row.n) ? 'var(--text-muted)' : docHues[row.n.hue || 'gray'], display: 'inline-flex', flexShrink: 0 }">
|
|
242
247
|
<Icon :name="row.n.icon || (isBranch(row.n) ? (openKeys.includes(row.key) ? 'folder-open' : 'folder') : 'file-text')" :size="15" />
|
|
243
248
|
</span>
|
|
244
|
-
<span :style="{ fontFamily: 'var(--font-sans)', fontSize: 'var(--text-
|
|
249
|
+
<span :style="{ fontFamily: 'var(--font-sans)', fontSize: 'var(--text-base)', lineHeight: 'var(--leading-base)', fontWeight: selected.includes(row.key) ? 'var(--weight-medium)' : 'var(--weight-regular)', color: row.n.disabled ? 'var(--text-muted)' : 'var(--text-heading)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }">
|
|
245
250
|
<template v-for="(p, i) in parts(titleOf(row.n))" :key="i"><mark v-if="p.hit" style="background:var(--soft-bg);color:var(--info-fg);font-weight:var(--weight-medium);padding:0;border-radius:2px">{{ p.t }}</mark><template v-else>{{ p.t }}</template></template>
|
|
246
251
|
</span>
|
|
247
|
-
<span v-if="row.n.tag" style="font-family:var(--font-sans);font-size:var(--text-
|
|
248
|
-
<span v-if="row.n.count != null" style="margin-left:auto;font-family:var(--font-
|
|
252
|
+
<span v-if="row.n.tag" style="font-family:var(--font-sans);font-size:var(--text-xs);line-height:1;padding:2px 5px;border-radius:var(--radius-sm);background:var(--bg-inset);color:var(--text-secondary);flex-shrink:0">{{ row.n.tag }}</span>
|
|
253
|
+
<span v-if="row.n.count != null" style="margin-left:auto;font-family:var(--font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-xs);color:var(--text-muted);padding-left:8px">{{ row.n.count }}</span>
|
|
249
254
|
</div>
|
|
250
|
-
<div v-if="!rows.length" style="padding:10px 8px;font-family:var(--font-sans);font-size:var(--text-
|
|
255
|
+
<div v-if="!rows.length" style="padding:10px 8px;font-family:var(--font-sans);font-size:var(--text-base);color:var(--text-muted)">No matching items</div>
|
|
251
256
|
</div>
|
|
252
257
|
</template>
|
|
253
258
|
<style scoped>
|
|
254
259
|
.kb-tree-row:not(.is-disabled):hover{background:var(--bg-hover)}
|
|
255
|
-
.kb-tree-row:focus-visible{outline:2px solid var(--focus-
|
|
260
|
+
.kb-tree-row:focus-visible{outline:2px solid var(--focus-border);outline-offset:-2px}
|
|
256
261
|
.kb-tree-spin{animation:kb-tree-spin 900ms linear infinite}
|
|
257
262
|
@keyframes kb-tree-spin{to{transform:rotate(360deg)}}
|
|
258
263
|
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// The product's real nav model (Home dashboard). Framework-neutral: imported by Sidebar.jsx (re-exported
|
|
2
|
+
// as KEYBRICKS_NAV from the React entry) and exported from the Vue entry for <Sidebar :items="KEYBRICKS_NAV">.
|
|
3
|
+
export const KEYBRICKS_NAV = [
|
|
4
|
+
{ icon: 'house', label: 'Home' },
|
|
5
|
+
{ icon: 'file-text', label: 'Documents' },
|
|
6
|
+
{ icon: 'layout-grid', label: 'Business Intelligence' },
|
|
7
|
+
{ icon: 'database', label: 'Data Integration' },
|
|
8
|
+
{ icon: 'reconciliation', label: 'Reconciliation' },
|
|
9
|
+
{ icon: 'consolidation', label: 'Consolidation' },
|
|
10
|
+
{
|
|
11
|
+
icon: 'folder-cog', label: 'Management', children: [
|
|
12
|
+
{ icon: 'box', label: 'Modeling' },
|
|
13
|
+
{ icon: 'workflow', label: 'Workflow' },
|
|
14
|
+
{ icon: 'shield', label: 'Security Management' },
|
|
15
|
+
{ icon: 'refresh-cw', label: 'System Migration' },
|
|
16
|
+
{ icon: 'chart-column', label: 'Business Logic' },
|
|
17
|
+
{ icon: 'list-todo', label: 'Tasks Management' },
|
|
18
|
+
{ icon: 'circle-check', label: 'Validation Rules' },
|
|
19
|
+
{ icon: 'settings-2', label: 'Control Center' },
|
|
20
|
+
{ icon: 'reconciliation', label: 'Reconciliation' },
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Theme persistence shared by ThemeToggle (React and Vue). Framework-neutral.
|
|
2
|
+
// applyStoredTheme(): reads localStorage("kb-theme") and sets <html data-theme> before first paint —
|
|
3
|
+
// call once at app start (main.jsx / main.js).
|
|
4
|
+
export function applyStoredTheme() {
|
|
5
|
+
if (typeof document === 'undefined') return;
|
|
6
|
+
let t = 'light';
|
|
7
|
+
try { t = localStorage.getItem('kb-theme') || 'light'; } catch (e) {}
|
|
8
|
+
document.documentElement.dataset.theme = t;
|
|
9
|
+
}
|
|
@@ -13,6 +13,8 @@ export interface ConfigPanelProps {
|
|
|
13
13
|
onPreview?: () => void;
|
|
14
14
|
children?: React.ReactNode;
|
|
15
15
|
height?: number | string;
|
|
16
|
+
/** Size tier for the panel's controls. Omit to inherit (→ md). */
|
|
17
|
+
size?: "sm" | "md" | "lg";
|
|
16
18
|
style?: React.CSSProperties;
|
|
17
19
|
}
|
|
18
20
|
export declare function ConfigPanel(props: ConfigPanelProps): JSX.Element;
|
|
@@ -3,24 +3,24 @@ import { Button } from "../buttons/Button.jsx";
|
|
|
3
3
|
import { PanelTabs } from "../tabs/Tabs.jsx";
|
|
4
4
|
import { NumberStepper } from "../forms/NumberStepper.jsx";
|
|
5
5
|
|
|
6
|
-
/** Right node-config panel — 400px: title/subtitle + Save Settings, preview-rows row, PanelTabs, body slot. */
|
|
7
|
-
export function ConfigPanel({ title, subtitle, tabs = ["Node Info", "Calc Rules", "Output Fields", "SQL Preview"], activeTab, onTab, previewRows = 100, onPreviewRows, onSave, onPreview, children, height = "100%", style }) {
|
|
6
|
+
/** Right node-config panel — 400px: title/subtitle + Save Settings, preview-rows row, PanelTabs, body slot. A size region (default inherit → md): every control in the header shares one tier. */
|
|
7
|
+
export function ConfigPanel({ title, subtitle, tabs = ["Node Info", "Calc Rules", "Output Fields", "SQL Preview"], activeTab, onTab, previewRows = 100, onPreviewRows, onSave, onPreview, children, height = "100%", size, style }) {
|
|
8
8
|
const [tab, setTab] = React.useState(tabs[0]);
|
|
9
9
|
const cur = activeTab != null ? activeTab : tab;
|
|
10
10
|
return (
|
|
11
|
-
<div style={{ width: "var(--panel-w)", height, background: "var(--bg-surface)", borderLeft: "1px solid var(--border-card)", display: "flex", flexDirection: "column", boxSizing: "border-box", flexShrink: 0, ...style }}>
|
|
11
|
+
<div data-size={size} style={{ width: "var(--panel-w)", height, background: "var(--bg-surface)", borderLeft: "1px solid var(--border-card)", display: "flex", flexDirection: "column", boxSizing: "border-box", flexShrink: 0, ...style }}>
|
|
12
12
|
<div style={{ padding: "12px 16px 0", borderBottom: "1px solid var(--border-card)", flexShrink: 0 }}>
|
|
13
13
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
|
|
14
14
|
<div style={{ display: "flex", flexDirection: "column" }}>
|
|
15
|
-
<span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-semibold)", fontSize: "var(--text-md)", lineHeight: "
|
|
16
|
-
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", lineHeight: "var(--leading-xs)", letterSpacing: "var(--tracking-xs)", color: "var(--text-muted)", paddingTop:
|
|
15
|
+
<span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-semibold)", fontSize: "var(--text-md)", lineHeight: "var(--leading-md)", letterSpacing: "var(--tracking-md)", color: "var(--text-heading)" }}>{title}</span>
|
|
16
|
+
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", lineHeight: "var(--leading-xs)", letterSpacing: "var(--tracking-xs)", color: "var(--text-muted)", paddingTop: 2 }}>{subtitle}</span>
|
|
17
17
|
</div>
|
|
18
|
-
<Button
|
|
18
|
+
<Button onClick={onSave}>Save Settings</Button>
|
|
19
19
|
</div>
|
|
20
|
-
<div style={{ display: "flex", alignItems: "center", gap:
|
|
21
|
-
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text
|
|
20
|
+
<div style={{ display: "flex", alignItems: "center", gap: "var(--control-gap)", padding: "12px 0" }}>
|
|
21
|
+
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", letterSpacing: "var(--control-tracking)", color: "var(--text-secondary)" }}>Preview rows</span>
|
|
22
22
|
<NumberStepper value={previewRows} onChange={onPreviewRows} />
|
|
23
|
-
<Button variant="primary-soft"
|
|
23
|
+
<Button variant="primary-soft" icon="eye" onClick={onPreview}>Data Preview</Button>
|
|
24
24
|
</div>
|
|
25
25
|
<PanelTabs tabs={tabs} active={cur} onChange={(t) => { setTab(t); onTab && onTab(t); }} style={{ margin: "0 -16px", padding: "0 16px", borderBottom: "none" }} />
|
|
26
26
|
</div>
|
|
@@ -3,27 +3,27 @@ import { ref, computed } from 'vue'
|
|
|
3
3
|
import Button from '../buttons/Button.vue'
|
|
4
4
|
import PanelTabs from '../tabs/Tabs.vue'
|
|
5
5
|
import NumberStepper from '../forms/NumberStepper.vue'
|
|
6
|
-
// Right node-config panel — 400px: title/subtitle + Save Settings, preview-rows row, PanelTabs, body slot.
|
|
7
|
-
const props = defineProps({ title: String, subtitle: String, tabs: { type: Array, default: () => ['Node Info', 'Calc Rules', 'Output Fields', 'SQL Preview'] }, activeTab: String, previewRows: { type: Number, default: 100 }, height: { type: [String, Number], default: '100%' }, style: Object })
|
|
6
|
+
// Right node-config panel — 400px: title/subtitle + Save Settings, preview-rows row, PanelTabs, body slot. A size region (default inherit → md): every control in the header shares one tier.
|
|
7
|
+
const props = defineProps({ title: String, subtitle: String, tabs: { type: Array, default: () => ['Node Info', 'Calc Rules', 'Output Fields', 'SQL Preview'] }, activeTab: String, previewRows: { type: Number, default: 100 }, height: { type: [String, Number], default: '100%' }, size: String, style: Object })
|
|
8
8
|
const emit = defineEmits(['tab', 'update:previewRows', 'save', 'preview'])
|
|
9
9
|
const tabState = ref(props.tabs[0])
|
|
10
10
|
const cur = computed(() => props.activeTab != null ? props.activeTab : tabState.value)
|
|
11
11
|
function setTab(t) { tabState.value = t; emit('tab', t) }
|
|
12
12
|
</script>
|
|
13
13
|
<template>
|
|
14
|
-
<div :style="{ width: 'var(--panel-w)', height, background: 'var(--bg-surface)', borderLeft: '1px solid var(--border-card)', display: 'flex', flexDirection: 'column', boxSizing: 'border-box', flexShrink: 0, ...style }">
|
|
14
|
+
<div :data-size="size" :style="{ width: 'var(--panel-w)', height, background: 'var(--bg-surface)', borderLeft: '1px solid var(--border-card)', display: 'flex', flexDirection: 'column', boxSizing: 'border-box', flexShrink: 0, ...style }">
|
|
15
15
|
<div style="padding:12px 16px 0;border-bottom:1px solid var(--border-card);flex-shrink:0">
|
|
16
16
|
<div style="display:flex;justify-content:space-between;align-items:flex-start">
|
|
17
17
|
<div style="display:flex;flex-direction:column">
|
|
18
|
-
<span style="font-family:var(--font-sans);font-weight:var(--weight-semibold);font-size:var(--text-md);line-height:
|
|
19
|
-
<span style="font-family:var(--font-sans);font-size:var(--text-xs);line-height:var(--leading-xs);letter-spacing:var(--tracking-xs);color:var(--text-muted);padding-top:
|
|
18
|
+
<span style="font-family:var(--font-sans);font-weight:var(--weight-semibold);font-size:var(--text-md);line-height:var(--leading-md);letter-spacing:var(--tracking-md);color:var(--text-heading)">{{ title }}</span>
|
|
19
|
+
<span style="font-family:var(--font-sans);font-size:var(--text-xs);line-height:var(--leading-xs);letter-spacing:var(--tracking-xs);color:var(--text-muted);padding-top:2px">{{ subtitle }}</span>
|
|
20
20
|
</div>
|
|
21
|
-
<Button
|
|
21
|
+
<Button @click="emit('save')">Save Settings</Button>
|
|
22
22
|
</div>
|
|
23
|
-
<div style="display:flex;align-items:center;gap:
|
|
24
|
-
<span style="font-family:var(--font-sans);font-size:var(--text
|
|
23
|
+
<div style="display:flex;align-items:center;gap:var(--control-gap);padding:12px 0">
|
|
24
|
+
<span style="font-family:var(--font-sans);font-size:var(--control-text);line-height:var(--control-leading);letter-spacing:var(--control-tracking);color:var(--text-secondary)">Preview rows</span>
|
|
25
25
|
<NumberStepper :model-value="previewRows" @update:modelValue="v => emit('update:previewRows', v)" />
|
|
26
|
-
<Button variant="primary-soft"
|
|
26
|
+
<Button variant="primary-soft" icon="eye" @click="emit('preview')">Data Preview</Button>
|
|
27
27
|
</div>
|
|
28
28
|
<PanelTabs :tabs="tabs" :active="cur" @change="setTab" style="margin:0 -16px;padding:0 16px;border-bottom:none" />
|
|
29
29
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { DataTableColumn } from "../data/
|
|
2
|
+
import { DataTableColumn } from "../data/Table";
|
|
3
3
|
/** Bottom 250px data-preview drawer with Debug Mode checkbox and dense table. */
|
|
4
4
|
export interface DataPreviewProps {
|
|
5
5
|
title?: string;
|
|
@@ -9,6 +9,8 @@ export interface DataPreviewProps {
|
|
|
9
9
|
onDebug?: (v: boolean) => void;
|
|
10
10
|
collapsed?: boolean;
|
|
11
11
|
onCollapse?: () => void;
|
|
12
|
+
/** Size tier of the drawer region. Defaults to "sm": 24px header controls, 32px table rows with 12px text. */
|
|
13
|
+
size?: "sm" | "md" | "lg";
|
|
12
14
|
style?: React.CSSProperties;
|
|
13
15
|
}
|
|
14
16
|
export declare function DataPreview(props: DataPreviewProps): JSX.Element;
|
|
@@ -2,21 +2,21 @@ import React from "react";
|
|
|
2
2
|
import { Icon } from "../icons/Icon.jsx";
|
|
3
3
|
import { IconButton } from "../buttons/IconButton.jsx";
|
|
4
4
|
import { Checkbox } from "../forms/Checkbox.jsx";
|
|
5
|
-
import {
|
|
5
|
+
import { Table } from "../data/Table.jsx";
|
|
6
6
|
|
|
7
|
-
/** Bottom data-preview drawer — 250px: 40px header (title, Debug Mode, collapse) + dense table. */
|
|
8
|
-
export function DataPreview({ title = "Data Preview", columns = [], rows = [], debug = false, onDebug, collapsed, onCollapse, style }) {
|
|
7
|
+
/** Bottom data-preview drawer — 250px: 40px header (title, Debug Mode, collapse) + dense table. An sm size region: the header's controls are 24px and the table has 32px rows with 12px text. */
|
|
8
|
+
export function DataPreview({ title = "Data Preview", columns = [], rows = [], debug = false, onDebug, collapsed, onCollapse, size = "sm", style }) {
|
|
9
9
|
return (
|
|
10
|
-
<div style={{ background: "var(--bg-surface)", borderTop: "1px solid var(--border-card)", display: "flex", flexDirection: "column", height: collapsed ?
|
|
11
|
-
<div style={{ height:
|
|
10
|
+
<div data-size={size} style={{ background: "var(--bg-surface)", borderTop: "1px solid var(--border-card)", display: "flex", flexDirection: "column", height: collapsed ? "var(--bar-card-h)" : "var(--drawer-h)", overflow: "hidden", boxSizing: "border-box", flexShrink: 0, transition: "height .15s ease", ...style }}>
|
|
11
|
+
<div style={{ height: "var(--bar-card-h)", display: "flex", alignItems: "center", gap: "var(--group-gap)", padding: "0 var(--edge-pad)", boxSizing: "border-box", flexShrink: 0 }}>
|
|
12
12
|
<span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-semibold)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", letterSpacing: "var(--tracking-base)", color: "var(--text-heading)" }}>{title}</span>
|
|
13
13
|
<span style={{ flex: 1 }} />
|
|
14
14
|
<Checkbox label="Debug Mode" checked={debug} onChange={onDebug} />
|
|
15
|
-
<IconButton icon={collapsed ? "chevron-up" : "chevron-down"}
|
|
15
|
+
<IconButton icon={collapsed ? "chevron-up" : "chevron-down"} muted onClick={onCollapse} label={collapsed ? "Expand" : "Collapse"} />
|
|
16
16
|
</div>
|
|
17
17
|
{!collapsed ? (
|
|
18
18
|
<div style={{ overflowY: "auto", borderTop: "1px solid var(--border-subtle)" }}>
|
|
19
|
-
<
|
|
19
|
+
<Table resizable columns={columns} rows={rows} headerBorder={false} />
|
|
20
20
|
</div>
|
|
21
21
|
) : null}
|
|
22
22
|
</div>
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import IconButton from '../buttons/IconButton.vue'
|
|
3
3
|
import Checkbox from '../forms/Checkbox.vue'
|
|
4
|
-
import
|
|
5
|
-
// Bottom data-preview drawer — 250px: 40px header (title, Debug Mode, collapse) + dense table.
|
|
6
|
-
defineProps({ title: { type: String, default: 'Data Preview' }, columns: { type: Array, default: () => [] }, rows: { type: Array, default: () => [] }, debug: Boolean, collapsed: Boolean, style: Object })
|
|
4
|
+
import Table from '../data/Table.vue'
|
|
5
|
+
// Bottom data-preview drawer — 250px: 40px header (title, Debug Mode, collapse) + dense table. An sm size region: the header's controls are 24px and the table has 32px rows with 12px text.
|
|
6
|
+
defineProps({ title: { type: String, default: 'Data Preview' }, columns: { type: Array, default: () => [] }, rows: { type: Array, default: () => [] }, debug: Boolean, collapsed: Boolean, size: { type: String, default: 'sm' }, style: Object })
|
|
7
7
|
const emit = defineEmits(['update:debug', 'toggleCollapse'])
|
|
8
8
|
</script>
|
|
9
9
|
<template>
|
|
10
|
-
<div :style="{ background: 'var(--bg-surface)', borderTop: '1px solid var(--border-card)', display: 'flex', flexDirection: 'column', height: collapsed ?
|
|
11
|
-
<div style="height:
|
|
10
|
+
<div :data-size="size" :style="{ background: 'var(--bg-surface)', borderTop: '1px solid var(--border-card)', display: 'flex', flexDirection: 'column', height: collapsed ? 'var(--bar-card-h)' : 'var(--drawer-h)', overflow: 'hidden', boxSizing: 'border-box', flexShrink: 0, transition: 'height .15s ease', ...style }">
|
|
11
|
+
<div style="height:var(--bar-card-h);display:flex;align-items:center;gap:var(--group-gap);padding:0 var(--edge-pad);box-sizing:border-box;flex-shrink:0">
|
|
12
12
|
<span style="font-family:var(--font-sans);font-weight:var(--weight-semibold);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);color:var(--text-heading)">{{ title }}</span>
|
|
13
13
|
<span style="flex:1" />
|
|
14
14
|
<Checkbox label="Debug Mode" :checked="debug" @change="v => emit('update:debug', v)" />
|
|
15
|
-
<IconButton :icon="collapsed ? 'chevron-up' : 'chevron-down'"
|
|
15
|
+
<IconButton :icon="collapsed ? 'chevron-up' : 'chevron-down'" muted :label="collapsed ? 'Expand' : 'Collapse'" @click="emit('toggleCollapse')" />
|
|
16
16
|
</div>
|
|
17
17
|
<div v-if="!collapsed" style="overflow-y:auto;border-top:1px solid var(--border-subtle)">
|
|
18
|
-
<
|
|
18
|
+
<Table resizable :columns="columns" :rows="rows" :header-border="false" />
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
21
|
</template>
|
|
@@ -60,12 +60,12 @@ export function NodeCard({ title, subtitle, icon = "table", subtitleIcon, hue =
|
|
|
60
60
|
{badge === "clock" ? <StatusBadge tone="pending" icon="clock" size={20} style={{ position: "absolute", top: -6, right: -6 }} /> : null}
|
|
61
61
|
</span>
|
|
62
62
|
<div style={{ display: "flex", flexDirection: "column", minWidth: 0, flex: 1, paddingRight: 18 }}>
|
|
63
|
-
<span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-semibold)", fontSize: "var(--text-base)", lineHeight: "
|
|
63
|
+
<span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-semibold)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", letterSpacing: "var(--tracking-base)", color: "var(--text-heading)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{title}</span>
|
|
64
64
|
<span style={{ display: "flex", alignItems: "flex-start", gap: 4, paddingTop: 4, minWidth: 0 }}>
|
|
65
|
-
{subtitleIcon !== false ? <span style={{ color: "var(--text-muted)", display: "inline-flex", flexShrink: 0,
|
|
65
|
+
{subtitleIcon !== false ? <span style={{ color: "var(--text-muted)", display: "inline-flex", alignItems: "center", flexShrink: 0, height: "var(--leading-xs)", transform: "translateY(-0.5px)" }}><Icon name={subtitleIcon || "info"} size={12} /></span> : null}
|
|
66
66
|
{/* Node types run long ("Field Value Calculation"), so the subtitle wraps to a
|
|
67
67
|
second line and only then clamps — the card size never changes. */}
|
|
68
|
-
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", lineHeight: "
|
|
68
|
+
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", lineHeight: "var(--leading-xs)", letterSpacing: "var(--tracking-xs)", color: "var(--text-muted)", minWidth: 0, overflow: "hidden", display: "-webkit-box", WebkitBoxOrient: "vertical", WebkitLineClamp: 2, overflowWrap: "break-word" }}>{subtitle}</span>
|
|
69
69
|
</span>
|
|
70
70
|
</div>
|
|
71
71
|
</div>
|
|
@@ -38,11 +38,11 @@ const tone = i => props.inputTones[i] || 'default'
|
|
|
38
38
|
<StatusBadge v-if="badge === 'clock'" tone="pending" icon="clock" :size="20" style="position:absolute;top:-6px;right:-6px" />
|
|
39
39
|
</span>
|
|
40
40
|
<div style="display:flex;flex-direction:column;min-width:0;flex:1;padding-right:18px">
|
|
41
|
-
<span style="font-family:var(--font-sans);font-weight:var(--weight-semibold);font-size:var(--text-base);line-height:
|
|
41
|
+
<span style="font-family:var(--font-sans);font-weight:var(--weight-semibold);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);color:var(--text-heading);white-space:nowrap;overflow:hidden;text-overflow:ellipsis">{{ title }}</span>
|
|
42
42
|
<span style="display:flex;align-items:flex-start;gap:4px;padding-top:4px;min-width:0">
|
|
43
|
-
<span v-if="subtitleIcon !== false" style="color:var(--text-muted);display:inline-flex;flex-shrink:0;
|
|
43
|
+
<span v-if="subtitleIcon !== false" style="color:var(--text-muted);display:inline-flex;align-items:center;flex-shrink:0;height:var(--leading-xs);transform:translateY(-0.5px)"><Icon :name="subtitleIcon || 'info'" :size="12" /></span>
|
|
44
44
|
<!-- Node types run long ("Field Value Calculation"): wrap to a second line, then clamp. -->
|
|
45
|
-
<span style="font-family:var(--font-sans);font-size:var(--text-xs);line-height:
|
|
45
|
+
<span style="font-family:var(--font-sans);font-size:var(--text-xs);line-height:var(--leading-xs);letter-spacing:var(--tracking-xs);color:var(--text-muted);min-width:0;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow-wrap:break-word">{{ subtitle }}</span>
|
|
46
46
|
</span>
|
|
47
47
|
</div>
|
|
48
48
|
</div>
|
|
@@ -8,8 +8,8 @@ const hover = ref(false)
|
|
|
8
8
|
</script>
|
|
9
9
|
<template>
|
|
10
10
|
<div role="button" tabindex="0" @click="$emit('click')" @mouseenter="hover = true" @mouseleave="hover = false"
|
|
11
|
-
:style="{ width: 67.
|
|
11
|
+
:style="{ width: '67.664px', borderRadius: 'var(--radius-lg)', padding: '8px', display: 'flex', flexDirection: 'column', gap: '6px', alignItems: 'center', cursor: 'grab', boxSizing: 'border-box', background: hover ? 'var(--bg-hover)' : 'transparent', transition: 'background .12s ease', ...style }">
|
|
12
12
|
<IconTile :icon="icon" :hue="hue" kind="palette" />
|
|
13
|
-
<span style="font-family:var(--font-sans);font-size:var(--text-
|
|
13
|
+
<span style="font-family:var(--font-sans);font-size:var(--text-xs);line-height:var(--leading-xs);letter-spacing:var(--tracking-xs);color:var(--text-body);text-align:center">{{ label }}</span>
|
|
14
14
|
</div>
|
|
15
15
|
</template>
|
|
@@ -8,7 +8,7 @@ const hover = ref(false)
|
|
|
8
8
|
</script>
|
|
9
9
|
<template>
|
|
10
10
|
<div role="button" tabindex="0" @click="$emit('click')" @mouseenter="hover = true" @mouseleave="hover = false"
|
|
11
|
-
:style="{ height: 'var(--h-subnav-item)', borderRadius: 'var(--radius-md)', display: 'flex', alignItems: 'center', gap:
|
|
11
|
+
:style="{ height: 'var(--h-subnav-item)', borderRadius: 'var(--radius-md)', display: 'flex', alignItems: 'center', gap: '8px', padding: '6px 8px', boxSizing: 'border-box', cursor: 'grab', background: hover ? 'var(--bg-hover)' : 'transparent', ...style }">
|
|
12
12
|
<span :style="{ color: `var(--cat-${hue})`, display: 'inline-flex' }"><Icon :name="icon" :size="14" /></span>
|
|
13
13
|
<span style="font-family:var(--font-sans);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);color:var(--text-body);white-space:nowrap">{{ label }}</span>
|
|
14
14
|
</div>
|
|
@@ -11,7 +11,7 @@ export function PaletteItem({ icon, hue, label, onClick, style }) {
|
|
|
11
11
|
<div role="button" tabIndex={0} onClick={onClick} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
|
|
12
12
|
style={{ width: 67.664, borderRadius: "var(--radius-lg)", padding: 8, display: "flex", flexDirection: "column", gap: 6, alignItems: "center", cursor: "grab", boxSizing: "border-box", background: hover ? "var(--bg-hover)" : "transparent", transition: "background .12s ease", ...style }}>
|
|
13
13
|
<IconTile icon={icon} hue={hue} kind="palette" />
|
|
14
|
-
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-
|
|
14
|
+
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", lineHeight: "var(--leading-xs)", letterSpacing: "var(--tracking-xs)", color: "var(--text-body)", textAlign: "center" }}>{label}</span>
|
|
15
15
|
</div>
|
|
16
16
|
);
|
|
17
17
|
}
|
|
@@ -44,7 +44,7 @@ export function PalettePanel({ catalog = PIPELINE_CATALOG, height = "100%", onPi
|
|
|
44
44
|
<div style={{ flex: 1, overflowY: "auto", padding: 8 }}>
|
|
45
45
|
{catalog.map((cat) => (
|
|
46
46
|
<div key={cat.label}>
|
|
47
|
-
<div onClick={() => toggle(cat.label)} style={{ height: "var(--h-subnav-item)", borderRadius: "var(--radius-md)", display: "flex", alignItems: "center", gap: 8, padding: "6px 8px", boxSizing: "border-box", cursor: "pointer" }}>
|
|
47
|
+
<div onClick={() => toggle(cat.label)} data-wash="" style={{ height: "var(--h-subnav-item)", borderRadius: "var(--radius-md)", display: "flex", alignItems: "center", gap: 8, padding: "6px 8px", boxSizing: "border-box", cursor: "pointer", background: "var(--wash, transparent)", transition: "var(--t-hover)" }}>
|
|
48
48
|
<span style={{ color: "var(--text-muted)", display: "inline-flex", transform: closed.includes(cat.label) ? "rotate(-90deg)" : "none", transition: "transform .15s ease" }}><Icon name="chevron-down" size={14} /></span>
|
|
49
49
|
<span style={{ color: `var(--cat-${cat.hue})`, display: "inline-flex" }}><Icon name={cat.icon} size={14} /></span>
|
|
50
50
|
<span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", letterSpacing: "var(--tracking-base)", color: "var(--text-strong)" }}>{cat.label}</span>
|
|
@@ -21,7 +21,7 @@ function toggle(l) { closed.value = closed.value.includes(l) ? closed.value.filt
|
|
|
21
21
|
</div>
|
|
22
22
|
<div style="flex:1;overflow-y:auto;padding:8px">
|
|
23
23
|
<div v-for="cat in catalog" :key="cat.label">
|
|
24
|
-
<div @click="toggle(cat.label)" style="height:var(--h-subnav-item);border-radius:var(--radius-md);display:flex;align-items:center;gap:8px;padding:6px 8px;box-sizing:border-box;cursor:pointer">
|
|
24
|
+
<div @click="toggle(cat.label)" data-wash="" style="height:var(--h-subnav-item);border-radius:var(--radius-md);display:flex;align-items:center;gap:8px;padding:6px 8px;box-sizing:border-box;cursor:pointer;background:var(--wash, transparent);transition:var(--t-hover)">
|
|
25
25
|
<span :style="{ color: 'var(--text-muted)', display: 'inline-flex', transform: closed.includes(cat.label) ? 'rotate(-90deg)' : 'none', transition: 'transform .15s ease' }"><Icon name="chevron-down" :size="14" /></span>
|
|
26
26
|
<span :style="{ color: `var(--cat-${cat.hue})`, display: 'inline-flex' }"><Icon :name="cat.icon" :size="14" /></span>
|
|
27
27
|
<span style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);color:var(--text-strong)">{{ cat.label }}</span>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import Icon from '../icons/Icon.vue'
|
|
4
|
+
import { portSkin } from './port-skin.js'
|
|
5
|
+
// Round output/input port — 22px. tone: "default" | "active" (dragging from it) | "target" (drop here).
|
|
6
|
+
// interactive lights it on hover and shows a grab cursor. Native listeners (@mousedown, @mouseup…) fall through to the span.
|
|
7
|
+
defineProps({ tone: { type: String, default: 'default' }, interactive: Boolean, style: Object })
|
|
8
|
+
const hover = ref(false)
|
|
9
|
+
</script>
|
|
10
|
+
<template>
|
|
11
|
+
<span @mouseenter="hover = true" @mouseleave="hover = false"
|
|
12
|
+
:style="{ width: '22px', height: '22px', borderRadius: 'var(--radius-full)', boxSizing: 'border-box', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', ...portSkin(tone, hover, interactive), ...style }">
|
|
13
|
+
<Icon :name="tone === 'target' ? 'plus' : 'arrow-right'" :size="12" :stroke-width="2.2" />
|
|
14
|
+
</span>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import Icon from '../icons/Icon.vue'
|
|
4
|
+
import { portSkin } from './port-skin.js'
|
|
5
|
+
// Labeled input port pill ("A >", "B >") — 28×22, same three tones as Port.
|
|
6
|
+
defineProps({ label: { type: String, default: 'A' }, tone: { type: String, default: 'default' }, interactive: Boolean, style: Object })
|
|
7
|
+
const hover = ref(false)
|
|
8
|
+
</script>
|
|
9
|
+
<template>
|
|
10
|
+
<span @mouseenter="hover = true" @mouseleave="hover = false"
|
|
11
|
+
:style="{ width: '28px', height: '22px', borderRadius: 'var(--radius-full)', boxSizing: 'border-box', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: '2px', fontFamily: 'var(--font-sans)', fontSize: 'var(--text-xs)', letterSpacing: 'var(--tracking-xs)', lineHeight: 1, ...portSkin(tone, hover, interactive), ...style }">
|
|
12
|
+
<Icon v-if="tone === 'target'" name="plus" :size="12" :stroke-width="2.2" />
|
|
13
|
+
<template v-else>{{ label }}<Icon name="chevron-right" :size="9" :stroke-width="2.5" /></template>
|
|
14
|
+
</span>
|
|
15
|
+
</template>
|