[aidan] refactor/workflow-cards: use radius and status design tokens, polish card chrome

This commit is contained in:
abccodes
2026-06-19 18:20:21 -07:00
parent 43741e8ccf
commit 90a98739f6
8 changed files with 63 additions and 66 deletions
@@ -213,7 +213,7 @@ export default function EditAgentView({ workflow, steps, isFixMode = false, onEd
title={canSave ? undefined : 'Add at least one step before saving'}
sx={{
fontSize: '0.8rem', fontWeight: 700, color: '#fff', bgcolor: c.accent.primary,
px: 1.2, py: 0.35, borderRadius: 999, cursor: canSave ? 'pointer' : 'not-allowed',
px: 1.2, py: 0.35, borderRadius: c.radius.full, cursor: canSave ? 'pointer' : 'not-allowed',
opacity: canSave ? 1 : 0.45,
'&:hover': { filter: 'brightness(1.05)' },
}}>
@@ -139,7 +139,7 @@ export default function SchedulePopover({
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.12, ease: 'easeOut' }}
transition={{ duration: 0.14, ease: 'easeOut' }}
style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column' }}>
{mode === 'search' && (
<Box sx={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0 }}>
@@ -179,8 +179,8 @@ export default function ScheduleThisPopover({ anchorEl, onClose, sessionId, sess
display: 'flex', flexDirection: 'column', gap: 0.4,
px: 1, py: 0.75, mb: 0.75,
borderRadius: `${c.radius.md}px`,
bgcolor: c.status.warningBg || c.bg.elevated,
border: `1px solid ${(c.status.warning || c.text.muted) + '60'}`,
bgcolor: c.status.warningBg,
border: `1px solid ${c.status.warning + '60'}`,
}}>
<Typography sx={{ fontSize: '0.78rem', fontWeight: 700, color: c.text.primary }}>
This chat is already scheduled.
@@ -472,7 +472,7 @@ const WorkflowCard: React.FC<Props> = ({
? '2px solid #3b82f6'
: isRunning
? `1px solid ${c.accent.primary}80`
: `1px solid ${c.border.subtle}`;
: `1px solid ${c.border.strong}`;
const shadow = isHighlighted
? `0 0 0 3px ${c.accent.primary}50, 0 0 20px ${c.accent.primary}35, 0 0 40px ${c.accent.primary}15`
@@ -480,7 +480,7 @@ const WorkflowCard: React.FC<Props> = ({
? c.shadow.lg
: isSelected
? `0 0 0 1px #3b82f6, ${c.shadow.md}`
: c.shadow.md;
: c.shadow.sm;
return (
<Box
@@ -514,7 +514,7 @@ const WorkflowCard: React.FC<Props> = ({
width: displayW,
height: autoHeight ? 'auto' : displayH,
maxHeight: autoHeight ? 'min(82vh, 760px)' : undefined,
borderRadius: '14px',
borderRadius: 3,
border,
bgcolor: c.bg.surface,
boxShadow: shadow,
@@ -541,7 +541,7 @@ const WorkflowCard: React.FC<Props> = ({
onPointerUp={handleDragPointerUp}
sx={{
display: 'flex', alignItems: 'center', gap: 1,
px: 2, py: 1.4,
px: 2, pt: 2, pb: 1.4,
cursor: isDragging ? 'grabbing' : 'grab',
touchAction: 'none', userSelect: 'none',
flexShrink: 0,
@@ -549,7 +549,7 @@ const WorkflowCard: React.FC<Props> = ({
position: 'relative',
}}
>
<DragIndicatorIcon sx={{ fontSize: 18, color: c.text.muted }} />
<DragIndicatorIcon sx={{ fontSize: 16, color: c.text.ghost, mr: -0.5 }} />
{isDraft ? (
// Draft state: title is inline-editable. Patches the openCard's
// draft.title so PreviewView picks it up on Save. Saved cards
@@ -610,9 +610,9 @@ const WorkflowCard: React.FC<Props> = ({
data-no-drag
onClick={(e) => { e.stopPropagation(); onClose(); }}
onPointerDown={(e) => e.stopPropagation()}
sx={{ p: 0.5, color: c.text.secondary, '&:hover': { color: c.status.error, bgcolor: c.status.errorBg } }}
sx={{ p: 0.5, color: c.text.ghost, '&:hover': { color: c.status.error, bgcolor: c.status.errorBg } }}
>
<CloseIcon sx={{ fontSize: 17 }} />
<CloseIcon sx={{ fontSize: 16 }} />
</IconButton>
</Box>
@@ -633,7 +633,6 @@ const WorkflowCard: React.FC<Props> = ({
workflow={null}
runs={null}
fallbackModel={card?.draft?.model}
fallbackMode={card?.draft?.mode}
fallbackSourceSessionId={card?.draft?.source_session_id}
/>
<Box sx={{ flex: 1 }} />
@@ -842,7 +841,7 @@ const WorkflowCard: React.FC<Props> = ({
<Box sx={{
position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)',
fontSize: '1.4rem', fontWeight: 700, color: c.accent.primary,
bgcolor: c.bg.surface, px: 1.2, py: 0.5, borderRadius: 999,
bgcolor: c.bg.surface, px: 1.2, py: 0.5, borderRadius: c.radius.full,
boxShadow: c.shadow.md,
animation: 'first-success-pop 1.4s ease-out forwards',
'@keyframes first-success-pop': {
@@ -944,11 +943,10 @@ function EditAgentSubtitle({ session }: { session: import('@/shared/state/agents
);
}
function SubtitleRow({ workflow, runs, fallbackModel, fallbackMode, fallbackSourceSessionId }: {
function SubtitleRow({ workflow, runs, fallbackModel, fallbackSourceSessionId }: {
workflow: Workflow | null;
runs: import('@/shared/state/workflowsSlice').WorkflowRun[] | null;
fallbackModel?: string;
fallbackMode?: string;
fallbackSourceSessionId?: string | null;
}) {
const c = useClaudeTokens();
@@ -957,8 +955,8 @@ function SubtitleRow({ workflow, runs, fallbackModel, fallbackMode, fallbackSour
// model/mode and use its work time for the "28s" so the subtitle reads the
// same as the source chat card did.
const sourceSession = useAppSelector((s) => fallbackSourceSessionId ? s.agents.sessions[fallbackSourceSessionId] : undefined);
// Match Image #34/#35/#36/#38/#40: "Claude Opus 4.6 agent 28s".
// Spaces between fields, all in muted text.
// Reads "Claude Opus 4.6 28s": model then work time, spaces between,
// all muted. Mode is omitted to match the chat card's subtitle.
const effModel = workflow?.model || fallbackModel || '';
const modelLabel = React.useMemo(() => {
if (!effModel) return '';
@@ -969,7 +967,6 @@ function SubtitleRow({ workflow, runs, fallbackModel, fallbackMode, fallbackSour
}
return effModel;
}, [effModel, modelsByProvider]);
const modeLabel = workflow?.mode || fallbackMode || '';
const duration = React.useMemo(() => {
const finished = (runs || []).find((r) => r.finished_at);
if (finished && finished.finished_at) {
@@ -989,7 +986,6 @@ function SubtitleRow({ workflow, runs, fallbackModel, fallbackMode, fallbackSour
return (
<Box sx={{ display: 'inline-flex', alignItems: 'center', gap: 1.25, fontSize: '0.82rem', color: c.text.muted, minWidth: 0, overflow: 'hidden' }}>
{modelLabel && <Box component="span" sx={{ whiteSpace: 'nowrap' }}>{modelLabel}</Box>}
{modeLabel && <Box component="span" sx={{ whiteSpace: 'nowrap' }}>{modeLabel}</Box>}
{duration && <Box component="span" sx={{ whiteSpace: 'nowrap' }}>{duration}</Box>}
</Box>
);
@@ -1030,7 +1026,7 @@ function RunningHeader({ workflowId }: { workflowId: string }) {
onClick={controlsDisabled ? undefined : onStop}
role="button"
aria-disabled={controlsDisabled}
sx={{ display: 'inline-flex', alignItems: 'center', gap: 0.35, fontSize: '0.82rem', fontWeight: 600, px: 1, py: 0.4, color: c.text.secondary, cursor: controlsDisabled ? 'default' : 'pointer', borderRadius: 999, opacity: controlsDisabled && !stopPending ? 0.55 : 1, '&:hover': controlsDisabled ? {} : { color: c.text.primary, bgcolor: c.bg.elevated } }}>
sx={{ display: 'inline-flex', alignItems: 'center', gap: 0.35, fontSize: '0.82rem', fontWeight: 600, px: 1, py: 0.4, color: c.text.secondary, cursor: controlsDisabled ? 'default' : 'pointer', borderRadius: c.radius.full, opacity: controlsDisabled && !stopPending ? 0.55 : 1, '&:hover': controlsDisabled ? {} : { color: c.text.primary, bgcolor: c.bg.elevated } }}>
{stopPending ? <CircularProgress size={14} thickness={5} sx={{ color: c.text.secondary }} /> : <StopRounded sx={{ fontSize: 15 }} />}
Stop
</Box>
@@ -1042,7 +1038,7 @@ function RunningHeader({ workflowId }: { workflowId: string }) {
sx={{
display: 'inline-flex', alignItems: 'center', gap: 0.35,
fontSize: '0.82rem', fontWeight: 700,
px: 1.1, py: 0.4, borderRadius: 999,
px: 1.1, py: 0.4, borderRadius: c.radius.full,
bgcolor: c.accent.primary, color: '#fff', cursor: controlsDisabled ? 'default' : 'pointer',
opacity: controlsDisabled && !pausePending ? 0.55 : 1,
'&:hover': controlsDisabled ? {} : { filter: 'brightness(1.05)' },
@@ -85,7 +85,7 @@ export function ActionBtn({ label, tone, disabled, onClick, icon }: { label: str
display: 'inline-flex', alignItems: 'center', gap: 0.4,
fontSize: '0.78rem', fontWeight: 600,
px: 1, py: 0.35,
borderRadius: 999,
borderRadius: c.radius.full,
cursor: disabled ? 'not-allowed' : 'pointer',
color: palette.color,
bgcolor: palette.bg,
@@ -267,7 +267,7 @@ export function PreviewView({ workflowId, steps, sourceSessionId, initialDraft,
sx={{
display: 'inline-flex', alignItems: 'center', gap: 0.5,
fontSize: '0.88rem', fontWeight: 700,
px: 1.75, py: 0.6, borderRadius: 999,
px: 1.75, py: 0.6, borderRadius: c.radius.full,
color: '#fff', bgcolor: c.accent.primary,
cursor: busy ? 'wait' : canSave ? 'pointer' : 'not-allowed',
opacity: busy || !canSave ? 0.6 : 1,
@@ -300,7 +300,7 @@ export function PreviewView({ workflowId, steps, sourceSessionId, initialDraft,
role="button"
onClick={canSave ? onSaveDraft : undefined}
title={canSave ? undefined : 'Add at least one step before saving'}
sx={{ fontSize: '0.84rem', fontWeight: 700, color: '#fff', bgcolor: c.accent.primary, borderRadius: 999, cursor: busy ? 'wait' : canSave ? 'pointer' : 'not-allowed', px: 1.5, py: 0.6, opacity: busy || !canSave ? 0.6 : 1, '&:hover': { filter: 'brightness(1.06)' } }}>
sx={{ fontSize: '0.84rem', fontWeight: 700, color: '#fff', bgcolor: c.accent.primary, borderRadius: c.radius.full, cursor: busy ? 'wait' : canSave ? 'pointer' : 'not-allowed', px: 1.5, py: 0.6, opacity: busy || !canSave ? 0.6 : 1, '&:hover': { filter: 'brightness(1.06)' } }}>
Save
</Box>
</DialogActions>
@@ -466,7 +466,7 @@ export function SavedView({ workflow, steps, runs, activeRunId }: { workflow: Wo
sx={{
display: 'inline-flex', alignItems: 'center', gap: 0.5,
fontSize: '0.88rem', fontWeight: 700,
px: 1.75, py: 0.6, borderRadius: 999,
px: 1.75, py: 0.6, borderRadius: c.radius.full,
color: '#fff', bgcolor: c.accent.primary,
cursor: 'pointer',
'&:hover': { bgcolor: c.accent.primary, filter: 'brightness(1.06)' },
@@ -499,12 +499,12 @@ export function SavedView({ workflow, steps, runs, activeRunId }: { workflow: Wo
display: 'inline-flex', alignItems: 'center', gap: 0.45,
fontSize: '0.82rem', fontWeight: 600,
px: 1.25, py: 0.5,
borderRadius: 999,
borderRadius: c.radius.full,
cursor: 'pointer',
color: c.text.secondary,
bgcolor: 'transparent',
border: `1px solid ${c.border.medium}`,
'&:hover': { bgcolor: c.bg.elevated, borderColor: c.border.strong || c.border.medium, color: c.text.primary },
'&:hover': { bgcolor: c.bg.elevated, borderColor: c.border.strong, color: c.text.primary },
}}>
<EditOutlined sx={{ fontSize: 15 }} />
Edit
@@ -596,7 +596,7 @@ function AuditTraceLink({ workflowId }: { workflowId: string }) {
<Box onClick={open} role="button" sx={{
display: 'inline-flex', alignItems: 'center', gap: 0.3,
fontSize: '0.7rem', color: c.text.muted, cursor: 'pointer',
px: 0.5, py: 0.25, borderRadius: 0.75,
px: 0.5, py: 0.25, borderRadius: c.radius.sm,
'&:hover': { color: c.accent.primary, bgcolor: c.bg.elevated },
}}>
<HistoryIcon sx={{ fontSize: 12 }} />
@@ -712,7 +712,7 @@ export function HistoryList({ runs, onOpen, showWorkflow = false, workflowTitleF
color: filter === k ? c.accent.primary : c.text.muted,
bgcolor: filter === k ? c.accent.primary + '14' : 'transparent',
border: `1px solid ${filter === k ? c.accent.primary + '40' : c.border.subtle}`,
px: 0.7, py: 0.2, borderRadius: 999, cursor: 'pointer',
px: 0.75, py: 0.3, borderRadius: c.radius.full, cursor: 'pointer',
'&:hover': { color: c.accent.primary },
}}>
{k === 'all' ? 'All' : k === 'failure' ? 'Failures only' : 'Ran late only'}
@@ -733,8 +733,8 @@ export function HistoryList({ runs, onOpen, showWorkflow = false, workflowTitleF
<Box key={r.id}>
<Box
onClick={() => setExpandedId(expanded ? null : r.id)}
sx={{ display: 'flex', alignItems: 'center', gap: 1.25, py: 0.6, px: 0.5, cursor: 'pointer', borderRadius: 0.75, '&:hover': { bgcolor: c.bg.elevated } }}>
<Box sx={{ fontSize: '0.72rem', fontWeight: 700, color: statusColor(r.status, c), bgcolor: statusBg(r.status, c), px: 0.8, py: 0.3, borderRadius: 0.75, minWidth: 64, textAlign: 'center' }}>
sx={{ display: 'flex', alignItems: 'center', gap: 1.25, py: 0.6, px: 0.5, cursor: 'pointer', borderRadius: c.radius.sm, '&:hover': { bgcolor: c.bg.elevated } }}>
<Box sx={{ fontSize: '0.72rem', fontWeight: 700, color: statusColor(r.status, c), bgcolor: statusBg(r.status, c), px: 0.8, py: 0.3, borderRadius: c.radius.sm, minWidth: 64, textAlign: 'center' }}>
{labelForStatus(r.status)}
</Box>
{showWorkflow && workflowTitleFor ? (
@@ -753,7 +753,7 @@ export function HistoryList({ runs, onOpen, showWorkflow = false, workflowTitleF
<Box sx={{ fontSize: '0.7rem', color: c.text.ghost, transform: expanded ? 'rotate(180deg)' : 'none', transition: 'transform 0.15s ease' }}></Box>
</Box>
{expanded && (
<Box sx={{ ml: 8, mt: 0.25, mb: 0.75, p: 1, bgcolor: c.bg.elevated, borderRadius: 0.75, border: `1px solid ${c.border.subtle}` }}>
<Box sx={{ ml: 8, mt: 0.25, mb: 0.75, p: 1, bgcolor: c.bg.elevated, borderRadius: c.radius.sm, border: `1px solid ${c.border.subtle}` }}>
{r.error ? (
<Typography sx={{ fontSize: '0.78rem', color: c.status.error, lineHeight: 1.4 }}>{r.error}</Typography>
) : (
@@ -784,11 +784,11 @@ export function HistoryDetail({ run, onBack }: { run: WorkflowRun | null; onBack
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Box onClick={onBack} role="button" sx={{ fontSize: '0.82rem', color: c.text.muted, cursor: 'pointer', '&:hover': { color: c.accent.primary } }}> back</Box>
<Box sx={{ fontSize: '0.72rem', fontWeight: 700, color: statusColor(run.status, c), bgcolor: statusBg(run.status, c), px: 0.8, py: 0.3, borderRadius: 0.75 }}>{labelForStatus(run.status)}</Box>
<Box sx={{ fontSize: '0.72rem', fontWeight: 700, color: statusColor(run.status, c), bgcolor: statusBg(run.status, c), px: 0.8, py: 0.3, borderRadius: c.radius.sm }}>{labelForStatus(run.status)}</Box>
<Typography sx={{ fontSize: '0.88rem', color: c.text.primary, fontWeight: 600 }}>{formatRunDate(run.started_at)}</Typography>
</Box>
{run.error && (
<Typography sx={{ fontSize: '0.85rem', color: c.status.error, bgcolor: c.status.errorBg, p: 1, borderRadius: 0.75 }}>{run.error}</Typography>
<Typography sx={{ fontSize: '0.85rem', color: c.status.error, bgcolor: c.status.errorBg, p: 1, borderRadius: c.radius.sm }}>{run.error}</Typography>
)}
<Typography sx={{ fontSize: '0.85rem', color: c.text.secondary, lineHeight: 1.5 }}>Started {formatRunDate(run.started_at)}, finished {run.finished_at ? formatRunDate(run.finished_at) : 'in progress'}.</Typography>
{run.session_id && (
@@ -3,6 +3,7 @@ import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import IconButton from '@mui/material/IconButton';
import InputBase from '@mui/material/InputBase';
import Fade from '@mui/material/Fade';
import CloseIcon from '@mui/icons-material/Close';
import AddIcon from '@mui/icons-material/Add';
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
@@ -108,14 +109,14 @@ function TimeSavedBadge() {
<Tooltip title={`${count} workflow runs completed for you. Rough estimate of ~3 min saved per run vs. doing it by hand.`}>
<Box sx={{
display: 'inline-flex', alignItems: 'center', gap: 0.5,
ml: 1, px: 0.85, py: 0.2,
ml: 1, px: 0.75, py: 0.3,
fontSize: '0.74rem', fontWeight: 600,
color: c.text.secondary,
bgcolor: 'transparent',
border: `1px solid ${c.border.subtle}`,
borderRadius: 999,
borderRadius: c.radius.full,
}}>
<Box sx={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 14, height: 14, borderRadius: '50%', bgcolor: (c.status.success || c.accent.primary) + '22', color: c.status.success || c.accent.primary, fontSize: 9, fontWeight: 800 }}></Box>
<Box sx={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 14, height: 14, borderRadius: '50%', bgcolor: c.status.success + '22', color: c.status.success, fontSize: 9, fontWeight: 800 }}></Box>
<span style={{ color: c.text.primary }}>{count}</span>
<span style={{ color: c.text.muted }}>·</span>
<span style={{ color: c.text.secondary }}>{timeLabel} back</span>
@@ -344,14 +345,14 @@ const WorkflowsHubCard: React.FC<Props> = ({
? `2px solid ${c.accent.primary}`
: isSelected
? '2px solid #3b82f6'
: `1px solid ${c.border.medium}`;
: `1px solid ${c.border.strong}`;
const shadow = isHighlighted
? `0 0 0 3px ${c.accent.primary}50, 0 0 20px ${c.accent.primary}35, 0 0 40px ${c.accent.primary}15`
: (isDragging || isResizing)
? c.shadow.lg
: isSelected
? `0 0 0 1px #3b82f6, ${c.shadow.md}`
: c.shadow.md;
: c.shadow.sm;
const noTransition = isDragging || isResizing || (isSelected && !!multiDragDelta);
return (
@@ -380,7 +381,7 @@ const WorkflowsHubCard: React.FC<Props> = ({
height: dh,
bgcolor: c.bg.surface,
border,
borderRadius: `${c.radius.lg}px`,
borderRadius: 3,
boxShadow: shadow,
display: 'flex',
flexDirection: 'column',
@@ -408,15 +409,15 @@ const WorkflowsHubCard: React.FC<Props> = ({
points right, matching the Workflows brand mark. */}
<CallSplitRoundedIcon sx={{ fontSize: 16, transform: 'rotate(90deg)' }} />
</Box>
<Typography sx={{ flex: 1, fontWeight: 700, fontSize: '0.88rem', color: c.text.primary }}>Workflows</Typography>
<Typography sx={{ flex: 1, fontWeight: 600, fontSize: '0.95rem', color: c.text.primary }}>Workflows</Typography>
<IconButton
size="small"
data-no-drag
onClick={(e) => { e.stopPropagation(); dispatch(closeWorkflowsHub()); }}
onPointerDown={(e) => e.stopPropagation()}
sx={{ p: 0.35, color: c.text.ghost, '&:hover': { color: c.status.error, bgcolor: c.status.errorBg } }}
sx={{ p: 0.5, color: c.text.ghost, '&:hover': { color: c.status.error, bgcolor: c.status.errorBg } }}
>
<CloseIcon sx={{ fontSize: 15 }} />
<CloseIcon sx={{ fontSize: 16 }} />
</IconButton>
</Box>
@@ -433,9 +434,9 @@ const WorkflowsHubCard: React.FC<Props> = ({
data-no-drag
sx={{
display: 'inline-flex', alignItems: 'center', gap: 0.4,
fontSize: '0.85rem', fontWeight: 600, color: c.text.primary,
fontSize: '0.82rem', fontWeight: 600, color: c.text.primary,
bgcolor: c.bg.elevated, border: `1px solid ${c.border.subtle}`,
px: 1, py: 0.4, borderRadius: `${c.radius.md}px`, cursor: 'pointer',
px: 1, py: 0.35, borderRadius: `${c.radius.md}px`, cursor: 'pointer',
'&:hover': { borderColor: c.accent.primary, color: c.accent.primary },
}}
>
@@ -448,11 +449,11 @@ const WorkflowsHubCard: React.FC<Props> = ({
data-no-drag
sx={{
display: 'inline-flex', alignItems: 'center', gap: 0.4, ml: 0.5,
fontSize: '0.8rem', fontWeight: 600,
color: paused ? c.status.warning || c.accent.primary : c.text.secondary,
bgcolor: paused ? (c.status.warningBg || c.bg.elevated) : 'transparent',
border: `1px solid ${paused ? (c.status.warning || c.accent.primary) + '60' : c.border.subtle}`,
px: 0.85, py: 0.3, borderRadius: `${c.radius.md}px`, cursor: 'pointer',
fontSize: '0.82rem', fontWeight: 600,
color: c.text.secondary,
bgcolor: paused ? c.bg.elevated : 'transparent',
border: `1px solid ${paused ? c.border.medium : c.border.subtle}`,
px: 1, py: 0.35, borderRadius: `${c.radius.md}px`, cursor: 'pointer',
'&:hover': { color: c.text.primary, borderColor: c.border.medium },
}}>
<Switch size="small" checked={paused} sx={{ pointerEvents: 'none', mr: -0.5, ml: -0.5 }} />
@@ -468,7 +469,7 @@ const WorkflowsHubCard: React.FC<Props> = ({
sx={{
fontSize: '0.82rem', fontWeight: 500, color: c.text.secondary,
border: `1px solid ${c.border.subtle}`,
px: 1.1, py: 0.35, borderRadius: `${c.radius.md}px`, cursor: 'pointer',
px: 1, py: 0.35, borderRadius: `${c.radius.md}px`, cursor: 'pointer',
'&:hover': { color: c.text.primary, borderColor: c.border.medium },
}}>Today</Box>
<IconButton size="small" data-no-drag onClick={() => setRefDate(addDays(refDate, view === 'Month' ? -28 : -7))} sx={{ p: 0.3 }}><ChevronLeftIcon sx={{ fontSize: 18 }} /></IconButton>
@@ -495,7 +496,7 @@ const WorkflowsHubCard: React.FC<Props> = ({
{view}
<KeyboardArrowDownIcon sx={{ fontSize: 16 }} />
</Box>
{viewOpen && (
<Fade in={viewOpen} timeout={{ enter: 200, exit: 220 }} unmountOnExit>
<Box sx={{ position: 'absolute', top: '100%', right: 0, mt: 0.5, bgcolor: c.bg.surface, border: `1px solid ${c.border.subtle}`, borderRadius: `${c.radius.md}px`, boxShadow: c.shadow.md, zIndex: 5, minWidth: 110 }}>
{(['List', 'Week', 'Month'] as const).map((v) => (
<Box
@@ -507,7 +508,7 @@ const WorkflowsHubCard: React.FC<Props> = ({
</Box>
))}
</Box>
)}
</Fade>
</Box>
</Box>
@@ -686,7 +687,7 @@ function SidebarSection({ title, items, onPick, scheduled, onContext, onSchedule
<Box
onClick={(e) => toggleEnabled(w, e)}
sx={{
width: 14, height: 14, borderRadius: '3px', flexShrink: 0,
width: 14, height: 14, borderRadius: c.radius.sm, flexShrink: 0,
border: `1.5px solid ${w.schedule.enabled ? c.accent.primary : c.border.medium}`,
bgcolor: w.schedule.enabled ? c.accent.primary : 'transparent',
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
@@ -702,7 +703,7 @@ function SidebarSection({ title, items, onPick, scheduled, onContext, onSchedule
<Box
onClick={(e) => { e.stopPropagation(); onSchedule?.(w, e.currentTarget); }}
sx={{
width: 16, height: 16, borderRadius: '4px', flexShrink: 0,
width: 16, height: 16, borderRadius: c.radius.sm, flexShrink: 0,
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
color: c.text.muted, cursor: 'pointer',
'&:hover': { color: c.accent.primary, bgcolor: c.bg.elevated },
@@ -720,7 +721,7 @@ function SidebarSection({ title, items, onPick, scheduled, onContext, onSchedule
)}
</Typewriter>
{scheduled && (!w.schedule.enabled || allPaused) && (
<Box sx={{ flexShrink: 0, px: 0.6, py: 0.1, borderRadius: '3px', bgcolor: c.bg.elevated, color: c.text.muted, fontSize: '0.62rem', fontWeight: 600, lineHeight: 1.5, letterSpacing: '0.02em' }}>Paused</Box>
<Box sx={{ flexShrink: 0, px: 0.6, py: 0.1, borderRadius: c.radius.sm, bgcolor: c.bg.elevated, color: c.text.muted, fontSize: '0.62rem', fontWeight: 600, lineHeight: 1.5, letterSpacing: '0.02em' }}>Paused</Box>
)}
</Box>
))}
@@ -36,7 +36,7 @@ export function ActionBtn({ label, tone, disabled, onClick, icon }: { label: str
sx={{
display: 'inline-flex', alignItems: 'center', gap: 0.45,
fontSize: LABEL_FS, fontWeight: 600, px: 1.25, py: 0.5,
borderRadius: 999,
borderRadius: c.radius.full,
cursor: disabled ? 'not-allowed' : 'pointer',
color: palette.color,
bgcolor: palette.bg,
@@ -48,7 +48,7 @@ export type LastRunStatus = NonNullable<Workflow['last_run_status']>;
export function statusDotColor(status: LastRunStatus | null | undefined, c: ReturnType<typeof useClaudeTokens>) {
switch (status) {
case 'success': return c.status.success;
case 'ran_late': return c.status.warning || '#f59e0b';
case 'ran_late': return c.status.warning;
case 'failure': return c.status.error;
case 'running': return c.accent.primary;
case 'skipped': return c.text.muted;
@@ -75,7 +75,7 @@ export function StatusDot({ status }: { status: LastRunStatus | null | undefined
<Tooltip title={status ? `Last run: ${word.toLowerCase()}` : 'This workflow has never run.'}>
<Box sx={{
display: 'inline-flex', alignItems: 'center', gap: 0.4,
height: 18, px: 0.6, borderRadius: 999,
height: 18, px: 0.75, borderRadius: c.radius.full,
bgcolor: status === 'failure' ? c.status.errorBg : status === 'ran_late' ? c.status.warningBg : status === 'success' ? c.status.successBg : c.bg.elevated,
border: `1px solid ${dotColor}55`,
flexShrink: 0,
@@ -163,7 +163,7 @@ export function PermissionChip({ workflow }: { workflow: Workflow }) {
color: c.text.secondary,
bgcolor: c.bg.elevated,
border: `1px solid ${c.border.subtle}`,
px: 0.85, py: 0.3, borderRadius: 999,
px: 0.75, py: 0.3, borderRadius: c.radius.full,
}}>
{tiers.map((t, i) => (
<React.Fragment key={i}>
@@ -204,7 +204,7 @@ export function ScheduleChip({ workflow }: { workflow: Workflow }) {
color: enabled ? c.accent.primary : c.text.muted,
bgcolor: enabled ? c.accent.primary + '14' : c.bg.elevated,
border: `1px solid ${enabled ? c.accent.primary + '40' : c.border.subtle}`,
px: 0.85, py: 0.3, borderRadius: 999,
px: 0.75, py: 0.3, borderRadius: c.radius.full,
cursor: enabled ? 'pointer' : 'default',
'&:hover': enabled ? { bgcolor: c.accent.primary + '22' } : undefined,
}}>
@@ -354,7 +354,7 @@ function chipSx(c: ReturnType<typeof useClaudeTokens>) {
color: c.text.secondary,
bgcolor: c.bg.elevated,
border: `1px solid ${c.border.subtle}`,
px: 0.75, py: 0.3, borderRadius: 999,
px: 0.75, py: 0.3, borderRadius: c.radius.full,
} as const;
}
@@ -433,10 +433,10 @@ export function StreakBadge({ runs }: { runs: WorkflowRun[] | undefined }) {
<Box sx={{
display: 'inline-flex', alignItems: 'center', gap: 0.3,
fontSize: '0.72rem', fontWeight: 700,
color: c.status.warning || '#f59e0b',
bgcolor: (c.status.warningBg || c.bg.elevated),
border: `1px solid ${(c.status.warning || '#f59e0b') + '60'}`,
px: 0.7, py: 0.2, borderRadius: 999,
color: c.status.success,
bgcolor: c.status.successBg,
border: `1px solid ${c.status.success + '60'}`,
px: 0.75, py: 0.3, borderRadius: c.radius.full,
}}>
🔥 {n}
</Box>