refactor: UI consistency — shared CSS, design system colors, no inline styles
Phase 1: Extract 6 shared CSS modules (table-section, log-panel, rate-colors, refresh-indicator, chart-card, section-card) eliminating ~135 duplicate class definitions across 11 files. Phase 2: Replace all hardcoded hex colors in CSS modules with design system variables. Strip ~55 hex fallbacks from var() patterns. Fix 4 undefined variable names (--accent, --bg-base, --surface, --bg-surface-raised). Phase 3: Replace ~45 hardcoded hex values in ProcessDiagram SVG components with var() CSS custom properties. Fix Dashboard.tsx color prop. Phase 4: Create CSS modules for AdminLayout, DatabaseAdminPage, OidcCallback (previously 100% inline). Extract shared PageLoader component (replaces 3 copy-pasted spinner patterns). Move AppsTab static inline styles to CSS classes. Extract LayoutShell StarredList styles. 58 files changed, net -219 lines. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,6 @@
|
||||
padding: 0 1.5rem;
|
||||
padding-top: 0.375rem;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
background: var(--bg-surface);
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--border-subtle);
|
||||
background: var(--surface, #1a1a1a);
|
||||
background: var(--bg-surface);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -56,7 +56,7 @@
|
||||
.dot.completed {
|
||||
background: var(--amber);
|
||||
border-color: var(--amber);
|
||||
color: var(--surface, #1a1a1a);
|
||||
color: var(--bg-surface);
|
||||
}
|
||||
|
||||
.dot.active {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
|
||||
.select:focus-visible {
|
||||
outline: 1px solid var(--accent);
|
||||
outline: 1px solid var(--amber);
|
||||
outline-offset: 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
@@ -15,37 +15,37 @@
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 8px 14px;
|
||||
background: var(--bg-surface, #FFFFFF);
|
||||
border-bottom: 1px solid var(--border, #E4DFD8);
|
||||
background: var(--bg-surface);
|
||||
border-bottom: 1px solid var(--border);
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary, #5C5347);
|
||||
color: var(--text-secondary);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.exchangeLabel {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary, #1A1612);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.exchangeId {
|
||||
font-size: 12px;
|
||||
background: var(--bg-hover, #F5F0EA);
|
||||
background: var(--bg-hover);
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
color: var(--text-primary, #1A1612);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.exchangeMeta {
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.jumpToError {
|
||||
margin-left: auto;
|
||||
font-size: 12px;
|
||||
padding: 3px 10px;
|
||||
border: 1px solid var(--error, #C0392B);
|
||||
background: #FDF2F0;
|
||||
color: var(--error, #C0392B);
|
||||
border: 1px solid var(--error);
|
||||
background: var(--error-bg);
|
||||
color: var(--error);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
@@ -53,7 +53,7 @@
|
||||
}
|
||||
|
||||
.jumpToError:hover {
|
||||
background: #F9E0DC;
|
||||
background: color-mix(in srgb, var(--error) 15%, var(--bg-surface));
|
||||
}
|
||||
|
||||
.diagramArea {
|
||||
@@ -67,12 +67,12 @@
|
||||
right: 8px;
|
||||
z-index: 10;
|
||||
font-size: 12px;
|
||||
font-family: var(--font-mono, monospace);
|
||||
font-family: var(--font-mono);
|
||||
padding: 3px 8px;
|
||||
border: 1px solid var(--border, #E4DFD8);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
background: var(--bg-surface, #FFFFFF);
|
||||
color: var(--text-secondary, #5C5347);
|
||||
background: var(--bg-surface);
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.15s, background 0.15s;
|
||||
@@ -80,18 +80,18 @@
|
||||
|
||||
.downloadBtn:hover {
|
||||
opacity: 1;
|
||||
background: var(--bg-hover, #F5F0EA);
|
||||
background: var(--bg-hover);
|
||||
}
|
||||
|
||||
.splitter {
|
||||
height: 4px;
|
||||
background: var(--border, #E4DFD8);
|
||||
background: var(--border);
|
||||
cursor: row-resize;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.splitter:hover {
|
||||
background: var(--amber, #C6820E);
|
||||
background: var(--amber);
|
||||
}
|
||||
|
||||
.detailArea {
|
||||
@@ -106,7 +106,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
@@ -115,13 +115,13 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
color: var(--error, #C0392B);
|
||||
color: var(--error);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.statusRunning {
|
||||
color: var(--amber, #C6820E);
|
||||
background: #FFF8F0;
|
||||
color: var(--amber);
|
||||
background: var(--amber-bg);
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
@@ -131,8 +131,8 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
background: var(--bg-surface, #FFFFFF);
|
||||
border-top: 1px solid var(--border, #E4DFD8);
|
||||
background: var(--bg-surface);
|
||||
border-top: 1px solid var(--border);
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
@@ -143,27 +143,27 @@
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 6px 14px;
|
||||
border-bottom: 1px solid var(--border, #E4DFD8);
|
||||
background: #FAFAF8;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: var(--bg-raised);
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.processorName {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary, #1A1612);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.processorId {
|
||||
font-size: 12px;
|
||||
font-family: var(--font-mono, monospace);
|
||||
color: var(--text-muted, #9C9184);
|
||||
font-family: var(--font-mono);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.processorDuration {
|
||||
font-size: 12px;
|
||||
font-family: var(--font-mono, monospace);
|
||||
color: var(--text-secondary, #5C5347);
|
||||
font-family: var(--font-mono);
|
||||
color: var(--text-secondary);
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@@ -180,13 +180,13 @@
|
||||
}
|
||||
|
||||
.statusCompleted {
|
||||
color: var(--success, #3D7C47);
|
||||
background: #F0F9F1;
|
||||
color: var(--success);
|
||||
background: var(--success-bg);
|
||||
}
|
||||
|
||||
.statusFailed {
|
||||
color: var(--error, #C0392B);
|
||||
background: #FDF2F0;
|
||||
color: var(--error);
|
||||
background: var(--error-bg);
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
@@ -195,18 +195,18 @@
|
||||
.tabBar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-bottom: 1px solid var(--border, #E4DFD8);
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding: 0 14px;
|
||||
background: #FAFAF8;
|
||||
background: var(--bg-raised);
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
font-family: var(--font-body, inherit);
|
||||
font-family: var(--font-body);
|
||||
cursor: pointer;
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
border: none;
|
||||
background: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
@@ -215,12 +215,12 @@
|
||||
}
|
||||
|
||||
.tab:hover {
|
||||
color: var(--text-secondary, #5C5347);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.tabActive {
|
||||
color: var(--amber, #C6820E);
|
||||
border-bottom: 2px solid var(--amber, #C6820E);
|
||||
color: var(--amber);
|
||||
border-bottom: 2px solid var(--amber);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -230,15 +230,15 @@
|
||||
}
|
||||
|
||||
.tabDisabled:hover {
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.tabError {
|
||||
color: var(--error, #C0392B);
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.tabError:hover {
|
||||
color: var(--error, #C0392B);
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
@@ -262,7 +262,7 @@
|
||||
|
||||
.fieldLabel {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
margin-bottom: 2px;
|
||||
@@ -270,14 +270,14 @@
|
||||
|
||||
.fieldValue {
|
||||
font-size: 12px;
|
||||
color: var(--text-primary, #1A1612);
|
||||
color: var(--text-primary);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.fieldValueMono {
|
||||
font-size: 12px;
|
||||
color: var(--text-primary, #1A1612);
|
||||
font-family: var(--font-mono, monospace);
|
||||
color: var(--text-primary);
|
||||
font-family: var(--font-mono);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
@@ -287,12 +287,12 @@
|
||||
.attributesSection {
|
||||
margin-top: 14px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid var(--border, #E4DFD8);
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.attributesLabel {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
margin-bottom: 6px;
|
||||
@@ -307,10 +307,10 @@
|
||||
.attributePill {
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
background: var(--bg-hover, #F5F0EA);
|
||||
background: var(--bg-hover);
|
||||
border-radius: 10px;
|
||||
color: var(--text-secondary, #5C5347);
|
||||
font-family: var(--font-mono, monospace);
|
||||
color: var(--text-secondary);
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
@@ -330,7 +330,7 @@
|
||||
}
|
||||
|
||||
.headersColumn + .headersColumn {
|
||||
border-left: 1px solid var(--border, #E4DFD8);
|
||||
border-left: 1px solid var(--border);
|
||||
padding-left: 14px;
|
||||
margin-left: 14px;
|
||||
}
|
||||
@@ -338,7 +338,7 @@
|
||||
.headersColumnLabel {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
margin-bottom: 6px;
|
||||
@@ -352,7 +352,7 @@
|
||||
|
||||
.headersTable td {
|
||||
padding: 3px 0;
|
||||
border-bottom: 1px solid var(--border, #E4DFD8);
|
||||
border-bottom: 1px solid var(--border);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
@@ -361,9 +361,9 @@
|
||||
}
|
||||
|
||||
.headerKey {
|
||||
font-family: var(--font-mono, monospace);
|
||||
font-family: var(--font-mono);
|
||||
font-weight: 600;
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
white-space: nowrap;
|
||||
padding-right: 12px;
|
||||
width: 140px;
|
||||
@@ -373,8 +373,8 @@
|
||||
}
|
||||
|
||||
.headerVal {
|
||||
font-family: var(--font-mono, monospace);
|
||||
color: var(--text-primary, #1A1612);
|
||||
font-family: var(--font-mono);
|
||||
color: var(--text-primary);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
@@ -391,39 +391,41 @@
|
||||
.codeFormat {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.codeSize {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted, #9C9184);
|
||||
font-family: var(--font-mono, monospace);
|
||||
color: var(--text-muted);
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.codeCopyBtn {
|
||||
margin-left: auto;
|
||||
font-size: 12px;
|
||||
font-family: var(--font-body, inherit);
|
||||
font-family: var(--font-body);
|
||||
padding: 2px 8px;
|
||||
border: 1px solid var(--border, #E4DFD8);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
background: var(--bg-surface, #FFFFFF);
|
||||
color: var(--text-secondary, #5C5347);
|
||||
background: var(--bg-surface);
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.codeCopyBtn:hover {
|
||||
background: var(--bg-hover, #F5F0EA);
|
||||
background: var(--bg-hover);
|
||||
}
|
||||
|
||||
.codeBlock {
|
||||
background: #1A1612;
|
||||
color: #E4DFD8;
|
||||
--code-bg: var(--bg-inset);
|
||||
--code-fg: var(--text-primary);
|
||||
background: var(--code-bg);
|
||||
color: var(--code-fg);
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
font-family: var(--font-mono, monospace);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
overflow-x: auto;
|
||||
@@ -439,15 +441,15 @@
|
||||
.errorType {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--error, #C0392B);
|
||||
color: var(--error);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.errorMessage {
|
||||
font-size: 12px;
|
||||
color: var(--text-primary, #1A1612);
|
||||
background: #FDF2F0;
|
||||
border: 1px solid #F5D5D0;
|
||||
color: var(--text-primary);
|
||||
background: var(--error-bg);
|
||||
border: 1px solid var(--error-border);
|
||||
border-radius: 6px;
|
||||
padding: 10px 12px;
|
||||
margin-bottom: 12px;
|
||||
@@ -456,11 +458,13 @@
|
||||
}
|
||||
|
||||
.errorStackTrace {
|
||||
background: #1A1612;
|
||||
color: #E4DFD8;
|
||||
--code-bg: var(--bg-inset);
|
||||
--code-fg: var(--text-primary);
|
||||
background: var(--code-bg);
|
||||
color: var(--code-fg);
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
font-family: var(--font-mono, monospace);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
overflow-x: auto;
|
||||
@@ -477,7 +481,7 @@
|
||||
.errorStackLabel {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
margin-bottom: 6px;
|
||||
@@ -505,22 +509,22 @@
|
||||
}
|
||||
|
||||
.ganttRow:hover {
|
||||
background: var(--bg-hover, #F5F0EA);
|
||||
background: var(--bg-hover);
|
||||
}
|
||||
|
||||
.ganttSelected {
|
||||
background: #FFF8F0;
|
||||
background: var(--amber-bg);
|
||||
}
|
||||
|
||||
.ganttSelected:hover {
|
||||
background: #FFF8F0;
|
||||
background: var(--amber-bg);
|
||||
}
|
||||
|
||||
.ganttLabel {
|
||||
width: 100px;
|
||||
min-width: 100px;
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary, #5C5347);
|
||||
color: var(--text-secondary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@@ -529,7 +533,7 @@
|
||||
.ganttBar {
|
||||
flex: 1;
|
||||
height: 16px;
|
||||
background: var(--bg-hover, #F5F0EA);
|
||||
background: var(--bg-hover);
|
||||
border-radius: 2px;
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
@@ -543,19 +547,19 @@
|
||||
}
|
||||
|
||||
.ganttFillCompleted {
|
||||
background: var(--success, #3D7C47);
|
||||
background: var(--success);
|
||||
}
|
||||
|
||||
.ganttFillFailed {
|
||||
background: var(--error, #C0392B);
|
||||
background: var(--error);
|
||||
}
|
||||
|
||||
.ganttDuration {
|
||||
width: 50px;
|
||||
min-width: 50px;
|
||||
font-size: 12px;
|
||||
font-family: var(--font-mono, monospace);
|
||||
color: var(--text-muted, #9C9184);
|
||||
font-family: var(--font-mono);
|
||||
color: var(--text-muted);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@@ -564,7 +568,7 @@
|
||||
========================================================================== */
|
||||
.emptyState {
|
||||
text-align: center;
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -14,3 +14,39 @@
|
||||
margin-left: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.starredList {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.starredIconWrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--sidebar-muted);
|
||||
}
|
||||
|
||||
.starredLabel {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.starredRemoveBtn {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 2px;
|
||||
cursor: pointer;
|
||||
color: var(--sidebar-muted);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.mainContent {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ function collectStarredItems(apps: SidebarApp[], starredIds: Set<string>): Starr
|
||||
function StarredList({ items, onNavigate, onRemove }: { items: StarredItem[]; onNavigate: (path: string) => void; onRemove: (key: string) => void }) {
|
||||
if (items.length === 0) return null;
|
||||
return (
|
||||
<div style={{ padding: '4px 0' }}>
|
||||
<div className={css.starredList}>
|
||||
{items.map((item) => (
|
||||
<div
|
||||
key={item.starKey}
|
||||
@@ -242,13 +242,13 @@ function StarredList({ items, onNavigate, onRemove }: { items: StarredItem[]; on
|
||||
tabIndex={0}
|
||||
onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') onNavigate(item.path); }}
|
||||
>
|
||||
{item.icon && <span style={{ display: 'flex', alignItems: 'center', color: 'var(--sidebar-muted)' }}>{item.icon}</span>}
|
||||
<span style={{ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
||||
{item.icon && <span className={css.starredIconWrap}>{item.icon}</span>}
|
||||
<span className={css.starredLabel}>
|
||||
{item.label}
|
||||
{item.parentApp && <span className={css.starredParentApp}>{item.parentApp}</span>}
|
||||
</span>
|
||||
<button
|
||||
style={{ background: 'none', border: 'none', padding: 2, cursor: 'pointer', color: 'var(--sidebar-muted)', display: 'flex', alignItems: 'center', opacity: 0.6 }}
|
||||
className={css.starredRemoveBtn}
|
||||
onClick={(e) => { e.stopPropagation(); onRemove(item.starKey); }}
|
||||
aria-label={`Remove ${item.label} from starred`}
|
||||
>
|
||||
@@ -771,7 +771,7 @@ function LayoutContent() {
|
||||
<ContentTabs active={scope.tab} onChange={setTab} scope={scope} />
|
||||
)}
|
||||
|
||||
<main style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden', minHeight: 0 }}>
|
||||
<main className={css.mainContent}>
|
||||
<Outlet key={selectedEnv ?? '__all__'} />
|
||||
</main>
|
||||
</AppShell>
|
||||
|
||||
5
ui/src/components/PageLoader.module.css
Normal file
5
ui/src/components/PageLoader.module.css
Normal file
@@ -0,0 +1,5 @@
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 4rem;
|
||||
}
|
||||
10
ui/src/components/PageLoader.tsx
Normal file
10
ui/src/components/PageLoader.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Spinner } from '@cameleer/design-system';
|
||||
import styles from './PageLoader.module.css';
|
||||
|
||||
export function PageLoader() {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Spinner size="lg" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -79,8 +79,8 @@ export function CompoundNode({
|
||||
|
||||
// Color: own status first, then infer from descendants (for path containers like when/otherwise)
|
||||
const effectiveColor = isGated ? 'var(--amber)'
|
||||
: isFailed || descendantFailed ? '#C0392B'
|
||||
: isCompleted || executedDescendant ? '#3D7C47'
|
||||
: isFailed || descendantFailed ? 'var(--error)'
|
||||
: isCompleted || executedDescendant ? 'var(--success)'
|
||||
: color;
|
||||
|
||||
// Dim compound when overlay is active but neither the compound nor any
|
||||
@@ -99,7 +99,7 @@ export function CompoundNode({
|
||||
|
||||
// _CB_FALLBACK: section styling with EIP purple
|
||||
if (node.type === '_CB_FALLBACK') {
|
||||
const fallbackColor = '#7C3AED'; // EIP purple
|
||||
const fallbackColor = 'var(--purple)';
|
||||
return (
|
||||
<g data-node-id={node.id} transform={`translate(${x}, ${y})`} opacity={isSkipped ? 0.35 : undefined}>
|
||||
<rect x={0} y={0} width={w} height={h} rx={CORNER_RADIUS}
|
||||
@@ -140,7 +140,7 @@ export function CompoundNode({
|
||||
}
|
||||
|
||||
// Default compound rendering (DO_TRY, EIP_CHOICE, EIP_FILTER, EIP_IDEMPOTENT_CONSUMER, etc.)
|
||||
const containerFill = isGated ? 'var(--amber-bg)' : 'white';
|
||||
const containerFill = isGated ? 'var(--amber-bg)' : 'var(--bg-surface)';
|
||||
return (
|
||||
<g data-node-id={node.id} transform={`translate(${x}, ${y})`} opacity={isSkipped ? 0.35 : undefined}>
|
||||
{/* Container body */}
|
||||
@@ -163,15 +163,15 @@ export function CompoundNode({
|
||||
<g transform={`translate(6, ${HEADER_HEIGHT / 2 - 5}) scale(0.417)`}>
|
||||
{iconForType(node.type).map((el: IconElement, i: number) =>
|
||||
'd' in el
|
||||
? <path key={i} d={el.d} fill="none" stroke="white" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" />
|
||||
: <circle key={i} cx={el.cx} cy={el.cy} r={el.r} fill="none" stroke="white" strokeWidth={2} />
|
||||
? <path key={i} d={el.d} fill="none" stroke="var(--text-inverse)" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" />
|
||||
: <circle key={i} cx={el.cx} cy={el.cy} r={el.r} fill="none" stroke="var(--text-inverse)" strokeWidth={2} />
|
||||
)}
|
||||
</g>
|
||||
{/* Header label (centered) */}
|
||||
<text
|
||||
x={w / 2}
|
||||
y={HEADER_HEIGHT / 2 + 4}
|
||||
fill="white"
|
||||
fill="var(--text-inverse)"
|
||||
fontSize={10}
|
||||
fontWeight={600}
|
||||
textAnchor="middle"
|
||||
|
||||
@@ -3,8 +3,8 @@ import type { NodeConfig } from './types';
|
||||
|
||||
const BADGE_SIZE = 18;
|
||||
const BADGE_GAP = 4;
|
||||
const TRACE_COLOR = '#1A7F8E'; // teal
|
||||
const TAP_COLOR = '#7C3AED'; // purple
|
||||
const TRACE_COLOR = 'var(--running)';
|
||||
const TAP_COLOR = 'var(--purple)';
|
||||
|
||||
interface ConfigBadgeProps {
|
||||
nodeWidth: number;
|
||||
@@ -42,7 +42,7 @@ export function ConfigBadge({ nodeWidth, config, hasTraceData }: ConfigBadgeProp
|
||||
badges.push(
|
||||
<g key="tap" transform={`translate(${xOffset}, ${-BADGE_SIZE - 4})`}>
|
||||
<circle cx={cx} cy={cy} r={BADGE_SIZE / 2} fill={TAP_COLOR} />
|
||||
<g transform="translate(4, 4)" stroke="white" strokeWidth={1.4} fill="none" strokeLinecap="round" strokeLinejoin="round">
|
||||
<g transform="translate(4, 4)" stroke="var(--text-inverse)" strokeWidth={1.4} fill="none" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M5 1 C5 1 2 4.5 2 6.5a3 3 0 006 0C8 4.5 5 1 5 1z" />
|
||||
</g>
|
||||
</g>,
|
||||
@@ -70,7 +70,7 @@ export function ConfigBadge({ nodeWidth, config, hasTraceData }: ConfigBadgeProp
|
||||
</circle>
|
||||
<circle cx={cx} cy={cy} r={r} fill={TRACE_COLOR} />
|
||||
<g transform={`translate(${(BADGE_SIZE - 14) / 2}, ${(BADGE_SIZE - 14) / 2})`}>
|
||||
<FootprintsIcon color="white" size={14} />
|
||||
<FootprintsIcon color="var(--text-inverse)" size={14} />
|
||||
</g>
|
||||
</g>,
|
||||
);
|
||||
|
||||
@@ -23,7 +23,7 @@ export function DiagramEdge({ edge, offsetY = 0, traversed }: DiagramEdgeProps)
|
||||
<path
|
||||
d={d}
|
||||
fill="none"
|
||||
stroke={traversed === true ? '#3D7C47' : '#9CA3AF'}
|
||||
stroke={traversed === true ? 'var(--success)' : 'var(--text-muted)'}
|
||||
strokeWidth={traversed === true ? 1.5 : traversed === false ? 1 : 1.5}
|
||||
strokeDasharray={traversed === false ? '4,3' : undefined}
|
||||
markerEnd={traversed === true ? 'url(#arrowhead-green)' : traversed === false ? undefined : 'url(#arrowhead)'}
|
||||
@@ -32,7 +32,7 @@ export function DiagramEdge({ edge, offsetY = 0, traversed }: DiagramEdgeProps)
|
||||
<text
|
||||
x={(pts[0][0] + pts[pts.length - 1][0]) / 2}
|
||||
y={(pts[0][1] + pts[pts.length - 1][1]) / 2 + offsetY - 6}
|
||||
fill="#9C9184"
|
||||
fill="var(--text-muted)"
|
||||
fontSize={9}
|
||||
textAnchor="middle"
|
||||
>
|
||||
|
||||
@@ -61,23 +61,27 @@ export function DiagramNode({
|
||||
const isSkipped = overlayActive && !executionState;
|
||||
|
||||
// Colors based on execution state (heatmap takes priority when no execution overlay)
|
||||
let cardFill = isHovered ? '#F5F0EA' : 'white';
|
||||
let borderStroke = isHovered || isSelected ? color : '#E4DFD8';
|
||||
let cardFill = isHovered ? 'var(--bg-hover)' : 'var(--bg-surface)';
|
||||
let borderStroke = isHovered || isSelected ? color : 'var(--border-subtle)';
|
||||
let borderWidth = isHovered || isSelected ? 1.5 : 1;
|
||||
let topBarColor = color;
|
||||
let labelColor = '#1A1612';
|
||||
let labelColor = 'var(--text-primary)';
|
||||
|
||||
if (isCompleted) {
|
||||
cardFill = isHovered ? '#E4F5E6' : '#F0F9F1';
|
||||
borderStroke = '#3D7C47';
|
||||
cardFill = isHovered
|
||||
? 'color-mix(in srgb, var(--success) 15%, var(--bg-surface))'
|
||||
: 'color-mix(in srgb, var(--success) 10%, var(--bg-surface))';
|
||||
borderStroke = 'var(--success)';
|
||||
borderWidth = 1.5;
|
||||
topBarColor = '#3D7C47';
|
||||
topBarColor = 'var(--success)';
|
||||
} else if (isFailed) {
|
||||
cardFill = isHovered ? '#F9E4E1' : '#FDF2F0';
|
||||
borderStroke = '#C0392B';
|
||||
cardFill = isHovered
|
||||
? 'color-mix(in srgb, var(--error) 15%, var(--bg-surface))'
|
||||
: 'color-mix(in srgb, var(--error) 10%, var(--bg-surface))';
|
||||
borderStroke = 'var(--error)';
|
||||
borderWidth = 2;
|
||||
topBarColor = '#C0392B';
|
||||
labelColor = '#C0392B';
|
||||
topBarColor = 'var(--error)';
|
||||
labelColor = 'var(--error)';
|
||||
} else if (heatmapEntry && !overlayActive) {
|
||||
cardFill = heatmapColor(heatmapEntry.pctOfRoute);
|
||||
borderStroke = heatmapBorderColor(heatmapEntry.pctOfRoute);
|
||||
@@ -85,7 +89,7 @@ export function DiagramNode({
|
||||
topBarColor = heatmapBorderColor(heatmapEntry.pctOfRoute);
|
||||
}
|
||||
|
||||
const statusColor = isCompleted ? '#3D7C47' : isFailed ? '#C0392B' : undefined;
|
||||
const statusColor = isCompleted ? 'var(--success)' : isFailed ? 'var(--error)' : undefined;
|
||||
|
||||
return (
|
||||
<g
|
||||
@@ -107,7 +111,7 @@ export function DiagramNode({
|
||||
height={h + 4}
|
||||
rx={CORNER_RADIUS + 2}
|
||||
fill="none"
|
||||
stroke="#C6820E"
|
||||
stroke="var(--amber)"
|
||||
strokeWidth={2.5}
|
||||
/>
|
||||
)}
|
||||
@@ -150,11 +154,11 @@ export function DiagramNode({
|
||||
{typeName}
|
||||
</text>
|
||||
{detail && detail !== typeName && (
|
||||
<text x={TEXT_LEFT} y={TOP_BAR_HEIGHT + 24} fill={isFailed ? '#C0392B' : '#5C5347'} fontSize={10}>
|
||||
<text x={TEXT_LEFT} y={TOP_BAR_HEIGHT + 24} fill={isFailed ? 'var(--error)' : 'var(--text-secondary)'} fontSize={10}>
|
||||
{detail}
|
||||
</text>
|
||||
)}
|
||||
<text x={TEXT_LEFT} y={TOP_BAR_HEIGHT + (detail && detail !== typeName ? 35 : 24)} fill="#1A7F8E" fontSize={9} fontStyle="italic">
|
||||
<text x={TEXT_LEFT} y={TOP_BAR_HEIGHT + (detail && detail !== typeName ? 35 : 24)} fill="var(--running)" fontSize={9} fontStyle="italic">
|
||||
→ {resolvedUri.split('?')[0]}
|
||||
</text>
|
||||
</>
|
||||
@@ -164,7 +168,7 @@ export function DiagramNode({
|
||||
{typeName}
|
||||
</text>
|
||||
{detail && detail !== typeName && (
|
||||
<text x={TEXT_LEFT} y={h / 2 + 12} fill={isFailed ? '#C0392B' : '#5C5347'} fontSize={10}>
|
||||
<text x={TEXT_LEFT} y={h / 2 + 12} fill={isFailed ? 'var(--error)' : 'var(--text-secondary)'} fontSize={10}>
|
||||
{detail}
|
||||
</text>
|
||||
)}
|
||||
@@ -189,24 +193,24 @@ export function DiagramNode({
|
||||
if (isCompleted) {
|
||||
badges.push(
|
||||
<g key="status">
|
||||
<circle cx={statusCx} cy={cy} r={BADGE_R} fill="#3D7C47" />
|
||||
<path d={`M${statusCx - 3} ${cy} l2 2 4-4`} fill="none" stroke="white" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" />
|
||||
<circle cx={statusCx} cy={cy} r={BADGE_R} fill="var(--success)" />
|
||||
<path d={`M${statusCx - 3} ${cy} l2 2 4-4`} fill="none" stroke="var(--text-inverse)" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" />
|
||||
</g>
|
||||
);
|
||||
slot++;
|
||||
} else if (isFailed) {
|
||||
badges.push(
|
||||
<g key="status">
|
||||
<circle cx={statusCx} cy={cy} r={BADGE_R} fill="none" stroke="#C0392B" strokeWidth={2} opacity={0.5}>
|
||||
<circle cx={statusCx} cy={cy} r={BADGE_R} fill="none" stroke="var(--error)" strokeWidth={2} opacity={0.5}>
|
||||
<animate attributeName="r" values="6;14" dur="1.5s" repeatCount="indefinite" />
|
||||
<animate attributeName="opacity" values="0.5;0" dur="1.5s" repeatCount="indefinite" />
|
||||
</circle>
|
||||
<circle cx={statusCx} cy={cy} r={BADGE_R} fill="none" stroke="#C0392B" strokeWidth={2} opacity={0.5}>
|
||||
<circle cx={statusCx} cy={cy} r={BADGE_R} fill="none" stroke="var(--error)" strokeWidth={2} opacity={0.5}>
|
||||
<animate attributeName="r" values="6;14" dur="1.5s" begin="0.75s" repeatCount="indefinite" />
|
||||
<animate attributeName="opacity" values="0.5;0" dur="1.5s" begin="0.75s" repeatCount="indefinite" />
|
||||
</circle>
|
||||
<circle cx={statusCx} cy={cy} r={BADGE_R} fill="#C0392B" />
|
||||
<path d={`M${statusCx} ${cy - 3} v4 M${statusCx} ${cy + 2.5} v0.5`} fill="none" stroke="white" strokeWidth={1.5} strokeLinecap="round" />
|
||||
<circle cx={statusCx} cy={cy} r={BADGE_R} fill="var(--error)" />
|
||||
<path d={`M${statusCx} ${cy - 3} v4 M${statusCx} ${cy + 2.5} v0.5`} fill="none" stroke="var(--text-inverse)" strokeWidth={1.5} strokeLinecap="round" />
|
||||
</g>
|
||||
);
|
||||
slot++;
|
||||
@@ -217,8 +221,8 @@ export function DiagramNode({
|
||||
const tapCx = statusCx - slot * (BADGE_D + BADGE_GAP);
|
||||
badges.push(
|
||||
<g key="tap">
|
||||
<circle cx={tapCx} cy={cy} r={BADGE_R} fill="#7C3AED" />
|
||||
<g transform={`translate(${tapCx - 5}, ${cy - 5})`} stroke="white" strokeWidth={1.4} fill="none" strokeLinecap="round" strokeLinejoin="round">
|
||||
<circle cx={tapCx} cy={cy} r={BADGE_R} fill="var(--purple)" />
|
||||
<g transform={`translate(${tapCx - 5}, ${cy - 5})`} stroke="var(--text-inverse)" strokeWidth={1.4} fill="none" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M5 1 C5 1 2 4.5 2 6.5a3 3 0 006 0C8 4.5 5 1 5 1z" />
|
||||
</g>
|
||||
</g>
|
||||
@@ -235,18 +239,18 @@ export function DiagramNode({
|
||||
<g key="trace">
|
||||
{tracePulse && (
|
||||
<>
|
||||
<circle cx={traceCx} cy={cy} r={BADGE_R} fill="none" stroke="#1A7F8E" strokeWidth={2} opacity={0.5}>
|
||||
<circle cx={traceCx} cy={cy} r={BADGE_R} fill="none" stroke="var(--running)" strokeWidth={2} opacity={0.5}>
|
||||
<animate attributeName="r" values={`${BADGE_R};${BADGE_R + 8}`} dur="1.5s" repeatCount="indefinite" />
|
||||
<animate attributeName="opacity" values="0.5;0" dur="1.5s" repeatCount="indefinite" />
|
||||
</circle>
|
||||
<circle cx={traceCx} cy={cy} r={BADGE_R} fill="none" stroke="#1A7F8E" strokeWidth={2} opacity={0.5}>
|
||||
<circle cx={traceCx} cy={cy} r={BADGE_R} fill="none" stroke="var(--running)" strokeWidth={2} opacity={0.5}>
|
||||
<animate attributeName="r" values={`${BADGE_R};${BADGE_R + 8}`} dur="1.5s" begin="0.75s" repeatCount="indefinite" />
|
||||
<animate attributeName="opacity" values="0.5;0" dur="1.5s" begin="0.75s" repeatCount="indefinite" />
|
||||
</circle>
|
||||
</>
|
||||
)}
|
||||
<circle cx={traceCx} cy={cy} r={BADGE_R} fill={traceHasData ? '#1A7F8E' : '#1A7F8E'} opacity={traceHasData ? 1 : 0.2} />
|
||||
<g transform={`translate(${traceCx - 5}, ${cy - 5}) scale(${10/24})`} stroke={traceHasData ? 'white' : '#1A7F8E'} strokeWidth={2.4} fill="none" strokeLinecap="round" strokeLinejoin="round">
|
||||
<circle cx={traceCx} cy={cy} r={BADGE_R} fill="var(--running)" opacity={traceHasData ? 1 : 0.2} />
|
||||
<g transform={`translate(${traceCx - 5}, ${cy - 5}) scale(${10/24})`} stroke={traceHasData ? 'var(--text-inverse)' : 'var(--running)'} strokeWidth={2.4} fill="none" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M4 16v-2.38C4 11.5 2.97 10.5 3 8c.03-2.72 1.49-6 4.5-6C9.37 2 10 3.8 10 5.5c0 3.11-2 5.66-2 8.68V16a2 2 0 1 1-4 0Z" />
|
||||
<path d="M20 20v-2.38c0-2.12 1.03-3.12 1-5.62-.03-2.72-1.49-6-4.5-6C14.63 6 14 7.8 14 9.5c0 3.11 2 5.66 2 8.68V20a2 2 0 1 0 4 0Z" />
|
||||
<path d="M16 17h4" />
|
||||
@@ -292,9 +296,9 @@ export function DiagramNode({
|
||||
<g transform={`translate(4, ${h - 14})`}>
|
||||
<path
|
||||
d="M2 2 v5 a3 3 0 003 3 h5"
|
||||
fill="none" stroke="#C0392B" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round"
|
||||
fill="none" stroke="var(--error)" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round"
|
||||
/>
|
||||
<path d="M8 8 l2 2 -2 2" fill="none" stroke="#C0392B" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path d="M8 8 l2 2 -2 2" fill="none" stroke="var(--error)" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" />
|
||||
</g>
|
||||
)}
|
||||
</g>
|
||||
|
||||
@@ -32,8 +32,8 @@ interface ErrorSectionProps {
|
||||
}
|
||||
|
||||
const VARIANT_COLORS: Record<string, string> = {
|
||||
error: '#C0392B',
|
||||
completion: '#1A7F8E',
|
||||
error: 'var(--error)',
|
||||
completion: 'var(--running)',
|
||||
};
|
||||
|
||||
export function ErrorSection({
|
||||
|
||||
@@ -147,12 +147,12 @@ function nodeColor(
|
||||
): { fill: string; opacity: number } {
|
||||
if (!overlay) return { fill: colorForType(node.type), opacity: 0.7 };
|
||||
const state = node.id ? overlay.get(node.id) : undefined;
|
||||
if (state?.status === 'COMPLETED') return { fill: '#3D7C47', opacity: 0.85 };
|
||||
if (state?.status === 'FAILED') return { fill: '#C0392B', opacity: 0.85 };
|
||||
if (state?.status === 'COMPLETED') return { fill: 'var(--success)', opacity: 0.85 };
|
||||
if (state?.status === 'FAILED') return { fill: 'var(--error)', opacity: 0.85 };
|
||||
// ENDPOINT is always traversed when overlay is active (route entry point)
|
||||
if (node.type === 'ENDPOINT' && overlay.size > 0) return { fill: '#3D7C47', opacity: 0.85 };
|
||||
if (node.type === 'ENDPOINT' && overlay.size > 0) return { fill: 'var(--success)', opacity: 0.85 };
|
||||
// Skipped (overlay active but node not executed)
|
||||
return { fill: '#9CA3AF', opacity: 0.35 };
|
||||
return { fill: 'var(--text-muted)', opacity: 0.35 };
|
||||
}
|
||||
|
||||
function renderMinimapNodes(
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { NodeAction, NodeConfig } from './types';
|
||||
import styles from './ProcessDiagram.module.css';
|
||||
|
||||
const HIDE_DELAY = 150;
|
||||
const TRACE_ACTIVE_COLOR = '#1A7F8E';
|
||||
const TRACE_ACTIVE_COLOR = 'var(--running)';
|
||||
|
||||
interface NodeToolbarProps {
|
||||
nodeId: string;
|
||||
@@ -50,7 +50,7 @@ export function NodeToolbar({
|
||||
className={`${styles.nodeToolbarBtn} ${tapActive ? styles.nodeToolbarBtnActive : ''}`}
|
||||
title={tapActive ? 'Edit tap' : 'Configure tap'}
|
||||
onClick={(e) => { e.stopPropagation(); onAction(nodeId, 'configure-tap'); }}
|
||||
style={tapActive ? { color: '#7C3AED' } : undefined}
|
||||
style={tapActive ? { color: 'var(--purple)' } : undefined}
|
||||
>
|
||||
<Droplets size={14} />
|
||||
</button>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
height: 100%;
|
||||
min-height: 300px;
|
||||
overflow: hidden;
|
||||
background: var(--bg-surface, #FFFFFF);
|
||||
border: 1px solid var(--border, #E4DFD8);
|
||||
border-radius: var(--radius-md, 8px);
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.svg {
|
||||
@@ -25,7 +25,7 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 300px;
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 300px;
|
||||
color: var(--error, #C0392B);
|
||||
color: var(--error);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@@ -47,11 +47,11 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
background: var(--bg-surface, #FFFFFF);
|
||||
border: 1px solid var(--border, #E4DFD8);
|
||||
border-radius: var(--radius-sm, 5px);
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 4px;
|
||||
box-shadow: var(--shadow-md, 0 2px 8px rgba(44, 37, 32, 0.08));
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.zoomBtn {
|
||||
@@ -62,19 +62,19 @@
|
||||
height: 28px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--text-primary, #1A1612);
|
||||
color: var(--text-primary);
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border-radius: var(--radius-sm, 5px);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.zoomBtn:hover {
|
||||
background: var(--bg-hover, #F5F0EA);
|
||||
background: var(--bg-hover);
|
||||
}
|
||||
|
||||
.zoomLevel {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
min-width: 36px;
|
||||
text-align: center;
|
||||
font-variant-numeric: tabular-nums;
|
||||
@@ -87,10 +87,10 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
background: var(--bg-surface, #FFFFFF);
|
||||
border: 1px solid var(--border, #E4DFD8);
|
||||
border-radius: var(--radius-sm, 5px);
|
||||
box-shadow: var(--shadow-sm, 0 1px 2px rgba(44, 37, 32, 0.06));
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
box-shadow: var(--shadow-sm);
|
||||
z-index: 10;
|
||||
font-size: 12px;
|
||||
}
|
||||
@@ -102,13 +102,13 @@
|
||||
|
||||
.breadcrumbSep {
|
||||
margin: 0 6px;
|
||||
color: var(--text-muted, #9C9184);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.breadcrumbLink {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--running, #1A7F8E);
|
||||
color: var(--running);
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
font-size: 12px;
|
||||
@@ -120,7 +120,7 @@
|
||||
}
|
||||
|
||||
.breadcrumbCurrent {
|
||||
color: var(--text-primary, #1A1612);
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -128,9 +128,9 @@
|
||||
position: absolute;
|
||||
bottom: 52px;
|
||||
right: 12px;
|
||||
border: 1px solid var(--border, #E4DFD8);
|
||||
border-radius: var(--radius-sm, 5px);
|
||||
box-shadow: var(--shadow-md, 0 2px 8px rgba(44, 37, 32, 0.08));
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
box-shadow: var(--shadow-md);
|
||||
overflow: hidden;
|
||||
z-index: 5;
|
||||
}
|
||||
@@ -141,10 +141,10 @@
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
padding: 3px 4px;
|
||||
background: var(--bg-surface, #FFFFFF);
|
||||
border: 1px solid var(--border, #E4DFD8);
|
||||
border-radius: var(--radius-sm, 5px);
|
||||
box-shadow: var(--shadow-lg, 0 4px 16px rgba(44, 37, 32, 0.10));
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
box-shadow: var(--shadow-lg);
|
||||
transform: translate(-50%, -100%);
|
||||
margin-top: -6px;
|
||||
z-index: 10;
|
||||
@@ -159,31 +159,31 @@
|
||||
height: 26px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--text-secondary, #5C5347);
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
border-radius: var(--radius-sm, 5px);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nodeToolbarBtn:hover {
|
||||
background: var(--bg-hover, #F5F0EA);
|
||||
color: var(--text-primary, #1A1612);
|
||||
background: var(--bg-hover);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.nodeToolbarBtnActive {
|
||||
background: var(--bg-hover, #F5F0EA);
|
||||
background: var(--bg-hover);
|
||||
}
|
||||
|
||||
.iterationStepper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
background: color-mix(in srgb, var(--bg-surface) 15%, transparent);
|
||||
border-radius: 3px;
|
||||
padding: 1px 3px;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
color: var(--text-primary);
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
@@ -191,8 +191,8 @@
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: none;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: white;
|
||||
background: color-mix(in srgb, var(--bg-surface) 20%, transparent);
|
||||
color: var(--text-primary);
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
|
||||
@@ -294,7 +294,7 @@ export function ProcessDiagram({
|
||||
refY="3"
|
||||
orient="auto"
|
||||
>
|
||||
<polygon points="0 0, 8 3, 0 6" fill="#9CA3AF" />
|
||||
<polygon points="0 0, 8 3, 0 6" fill="var(--text-muted)" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowhead-green"
|
||||
@@ -304,7 +304,7 @@ export function ProcessDiagram({
|
||||
refY="3"
|
||||
orient="auto"
|
||||
>
|
||||
<polygon points="0 0, 8 3, 0 6" fill="#3D7C47" />
|
||||
<polygon points="0 0, 8 3, 0 6" fill="var(--success)" />
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user