Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 97 additions & 66 deletions src/components/DcaSchedulesPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,37 +61,53 @@ export const DcaSchedulesPanel: FC = () => {
return (
<section style={styles.root} aria-label="DCA schedules">
<header style={styles.header}>
<span style={styles.headerIcon} aria-hidden="true">
</span>
<span>DCA schedules</span>
<span style={styles.headerLabel}>Schedules</span>
<span style={styles.headerCount}>{list.length}</span>
</header>
<ul style={styles.list}>
{list.map((s) => (
<li key={s.id} style={styles.row}>
<span
style={{
...styles.statusDot,
background: s.paused
? "var(--color-text-muted)"
: "var(--color-5)",
boxShadow: s.paused
? "none"
: "0 0 6px var(--color-5)",
}}
aria-hidden="true"
/>
<div style={styles.rowMain}>
<div style={styles.rowTitle}>
{s.plan.inputSymbol} → {s.plan.outputSymbol}
<span style={styles.rowCadence}>
· every {humanInterval(s.cadence.intervalMs)}
<span style={styles.pair}>
{s.plan.inputSymbol} → {s.plan.outputSymbol}
</span>
<span style={styles.dot} aria-hidden="true">·</span>
<span style={styles.cadence}>
every {humanInterval(s.cadence.intervalMs)}
</span>
</div>
<div style={styles.rowMeta}>
{s.plan.amountPerCycle.toLocaleString("en-US", {
maximumFractionDigits: 4,
})}{" "}
{s.plan.inputSymbol} per cycle ·{" "}
{s.cyclesDone} / {s.cadence.totalCycles > 0 ? s.cadence.totalCycles : "∞"}
{" · next "}
{s.paused ? "paused" : formatCountdown(new Date(s.nextFireAt), now)}
{s.plan.inputSymbol}
<span style={styles.metaDivider} aria-hidden="true">·</span>
{s.cyclesDone}/
{s.cadence.totalCycles > 0 ? s.cadence.totalCycles : "∞"}
<span style={styles.metaDivider} aria-hidden="true">·</span>
{s.paused
? "paused"
: formatCountdown(new Date(s.nextFireAt), now)}
</div>
</div>
<div style={styles.rowActions}>
<button
type="button"
onClick={() => pauseSchedule(s.id, !s.paused)}
style={styles.pauseButton}
style={styles.ghostButton}
className="liminal-press"
aria-label={s.paused ? "Resume schedule" : "Pause schedule"}
>
Expand All @@ -100,7 +116,7 @@ export const DcaSchedulesPanel: FC = () => {
<button
type="button"
onClick={() => cancelSchedule(s.id)}
style={styles.cancelButton}
style={styles.ghostButton}
className="liminal-press"
aria-label="Cancel schedule"
>
Expand All @@ -111,8 +127,7 @@ export const DcaSchedulesPanel: FC = () => {
))}
</ul>
<div style={styles.footnote}>
DCA is local-first: this tab must stay open for cycles to fire.
Closing the tab pauses the schedule until you return.
Local-first — keep this tab open for cycles to fire.
</div>
</section>
);
Expand All @@ -121,115 +136,131 @@ export const DcaSchedulesPanel: FC = () => {
const styles: Record<string, CSSProperties> = {
root: {
margin: "10px 16px",
padding: "14px 16px",
padding: "12px 14px",
background: "var(--surface-card)",
border: "1px solid var(--color-stroke)",
borderRadius: 12,
display: "flex",
flexDirection: "column",
gap: 10,
backdropFilter: "blur(12px) saturate(130%)",
WebkitBackdropFilter: "blur(12px) saturate(130%)",
gap: 8,
},
header: {
display: "flex",
alignItems: "center",
gap: 8,
paddingBottom: 2,
},
headerLabel: {
fontFamily: MONO,
fontSize: 13,
fontWeight: 700,
fontSize: 10,
fontWeight: 600,
color: "var(--color-text-muted)",
textTransform: "uppercase",
letterSpacing: "0.06em",
},
headerIcon: {
fontSize: 14,
letterSpacing: "0.14em",
},
headerCount: {
marginLeft: "auto",
fontFamily: MONO,
fontSize: 11,
fontWeight: 700,
background: "var(--color-accent-bg-soft)",
color: "var(--color-5-strong)",
border: "1px solid var(--color-accent-border)",
borderRadius: 999,
padding: "1px 7px",
fontSize: 10,
fontWeight: 600,
color: "var(--color-text-muted)",
fontVariantNumeric: "tabular-nums",
letterSpacing: "0.06em",
marginLeft: "auto",
},
list: {
listStyle: "none",
margin: 0,
padding: 0,
display: "flex",
flexDirection: "column",
gap: 8,
gap: 4,
},
row: {
display: "flex",
gap: 10,
padding: "10px 12px",
background: "var(--surface-raised)",
border: "1px solid var(--color-stroke)",
padding: "8px 10px",
background: "transparent",
border: "1px solid transparent",
borderRadius: 8,
alignItems: "center",
transition:
"background var(--motion-base) var(--ease-out), border-color var(--motion-base) var(--ease-out)",
},
statusDot: {
width: 6,
height: 6,
borderRadius: "50%",
flexShrink: 0,
transition: "background var(--motion-base) var(--ease-out)",
},
rowMain: {
flex: 1,
display: "flex",
flexDirection: "column",
gap: 4,
gap: 2,
minWidth: 0,
},
rowTitle: {
fontFamily: SANS,
fontWeight: 700,
fontSize: 14,
display: "flex",
alignItems: "baseline",
gap: 6,
fontFamily: MONO,
fontSize: 13,
color: "var(--color-text)",
fontVariantNumeric: "tabular-nums",
},
pair: {
fontWeight: 600,
letterSpacing: "0.01em",
},
rowCadence: {
cadence: {
fontWeight: 400,
color: "var(--color-text-muted)",
marginLeft: 6,
},
dot: {
color: "var(--color-text-muted)",
opacity: 0.5,
},
rowMeta: {
display: "flex",
flexWrap: "wrap",
gap: 6,
fontFamily: MONO,
fontSize: 12,
fontSize: 11,
color: "var(--color-text-muted)",
fontVariantNumeric: "tabular-nums",
},
metaDivider: {
opacity: 0.4,
},
rowActions: {
display: "inline-flex",
gap: 6,
gap: 4,
flexShrink: 0,
},
pauseButton: {
padding: "5px 10px",
ghostButton: {
padding: "4px 10px",
fontFamily: MONO,
fontSize: 12,
fontWeight: 600,
color: "var(--color-text)",
background: "var(--surface-card)",
border: "1px solid var(--color-stroke)",
borderRadius: 6,
cursor: "pointer",
},
cancelButton: {
padding: "5px 10px",
fontFamily: MONO,
fontSize: 12,
fontWeight: 600,
color: "var(--color-warn)",
fontSize: 11,
fontWeight: 500,
color: "var(--color-text-muted)",
background: "transparent",
border: "1px solid var(--color-stroke)",
border: "1px solid transparent",
borderRadius: 6,
cursor: "pointer",
letterSpacing: "0.04em",
transition:
"color var(--motion-base) var(--ease-out), background var(--motion-base) var(--ease-out), border-color var(--motion-base) var(--ease-out)",
},
footnote: {
fontFamily: SANS,
fontSize: 12,
fontFamily: MONO,
fontSize: 10,
color: "var(--color-text-muted)",
fontStyle: "italic",
lineHeight: 1.4,
letterSpacing: "0.04em",
paddingTop: 2,
borderTop: "1px dashed var(--color-stroke)",
marginTop: 2,
paddingLeft: 2,
},
};

Expand Down
80 changes: 43 additions & 37 deletions src/components/ExecutionPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2201,77 +2201,83 @@ const styles: Record<string, CSSProperties> = {
textTransform: "none",
opacity: 0.75,
},
// ----- Grouped form cards (PR #5b form-flow refactor) -----------------
// ----- Grouped form cards — refined hierarchy --------------------------
// Step pill becomes a thin 24px circle (mono digit, no background fill)
// so the eye lands on the title first. Card surface gains a faint
// glass tint for depth without colour wash. Body padding tightened
// for denser, more terminal-like reading rhythm.
formCard: {
margin: "10px 16px",
padding: "16px 18px",
// Fully transparent surface — only the border + chapter pill +
// content sits between the user and the panel's frosted glass +
// the Unicorn Studio scene behind it. We keep a tiny backdrop
// blur so any text directly under the card body still stays
// legible, but no coloured wash. Border carries the visual
// structure of the card on its own.
background: "transparent",
backdropFilter: "blur(6px)",
WebkitBackdropFilter: "blur(6px)",
border: `1px solid var(--color-stroke)`,
borderRadius: 12,
boxShadow: "var(--shadow-component-soft, none)",
padding: "18px 20px 16px",
background: "var(--surface-card)",
backdropFilter: "blur(10px) saturate(120%)",
WebkitBackdropFilter: "blur(10px) saturate(120%)",
border: "1px solid var(--color-stroke)",
borderRadius: 14,
boxShadow:
"0 1px 0 0 rgba(255, 255, 255, 0.04) inset, 0 6px 24px -8px rgba(0, 0, 0, 0.06)",
display: "flex",
flexDirection: "column",
gap: 12,
gap: 14,
},
formCardHeader: {
display: "flex",
alignItems: "baseline",
gap: 10,
flexWrap: "wrap",
paddingBottom: 4,
alignItems: "center",
gap: 12,
paddingBottom: 6,
borderBottom: "1px dashed var(--color-stroke)",
},
formCardStep: {
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
width: 22,
height: 22,
fontFamily: MONO,
fontSize: 13,
fontWeight: 700,
color: "var(--color-5-strong, var(--color-5))",
letterSpacing: 0,
background: "var(--color-accent-bg-soft)",
border: "1px solid var(--color-accent-border)",
padding: "2px 7px",
borderRadius: 999,
fontSize: 11,
fontWeight: 600,
color: "var(--color-text-muted)",
background: "transparent",
border: "1px solid var(--color-stroke)",
borderRadius: "50%",
fontVariantNumeric: "tabular-nums",
flexShrink: 0,
letterSpacing: 0,
},
formCardTitle: {
fontFamily: SANS,
fontSize: 18,
fontWeight: 700,
fontSize: 16,
fontWeight: 600,
color: THEME.text,
letterSpacing: 0,
letterSpacing: "-0.005em",
},
formCardSubtitle: {
fontFamily: MONO,
fontSize: 14,
fontSize: 11,
color: THEME.textMuted,
fontVariantNumeric: "tabular-nums",
marginLeft: "auto",
letterSpacing: "0.04em",
textTransform: "uppercase",
},
formCardBody: {
display: "flex",
flexDirection: "column",
gap: 10,
gap: 12,
},
formCardSubLabel: {
fontFamily: MONO,
fontSize: 14,
fontSize: 11,
fontWeight: 600,
color: THEME.textMuted,
letterSpacing: 0,
marginTop: 2,
letterSpacing: "0.08em",
textTransform: "uppercase",
marginTop: 4,
},
formCardFootnote: {
marginTop: 4,
marginTop: 6,
fontFamily: MONO,
fontSize: 14,
fontSize: 12,
color: THEME.textMuted,
lineHeight: 1.5,
},
Expand Down
Loading
Loading