diff --git a/.cursor/rules/minimalist-ui-styling.mdc b/.cursor/rules/minimalist-ui-styling.mdc new file mode 100644 index 0000000..eae2d35 --- /dev/null +++ b/.cursor/rules/minimalist-ui-styling.mdc @@ -0,0 +1,58 @@ +--- +description: UI styling conventions for a minimalistic, flat, and rounded aesthetic +globs: src/renderer/src/**/*.{css,tsx} +alwaysApply: false +--- + +# Minimalistic UI Styling + +When styling UI components in this application, adhere to a flat, clean, and rounded aesthetic. Avoid sharp edges, heavy borders, and prominent solid backgrounds for secondary elements. + +## 1. Rounded Edges over Sharp Cuts +Do not use `clip-path` polygons to create sharp, angled cuts (e.g., "blades" or "notches"). Instead, use smooth `border-radius` values (e.g., `10px`, `12px`, `18px`, or fully rounded). + +```css +/* ❌ BAD */ +.button { + clip-path: polygon(12px 0, calc(100% - 12px) 0, 100% 50%, calc(100% - 12px) 100%, 12px 100%, 0 50%); +} + +/* ✅ GOOD */ +.button { + border-radius: 10px; /* or 12px, 18px, etc. */ +} +``` + +## 2. Flat Controls with Hover Highlights +Secondary buttons, pills, and toggle controls should sit flat against their container's background. Remove static borders and solid backgrounds. Instead, use transparent backgrounds that reveal a subtle highlight only on hover. + +```tsx +// ❌ BAD + + +// ✅ GOOD + +``` + +## 3. Active States +When indicating an active state (like a selected workspace pill), avoid full borders or heavy background fills. Use minimalistic indicators, such as a single colored line or a subtle text color change. + +```css +/* ❌ BAD */ +.item-active { + border: 1px solid var(--active-border); + background-color: var(--active-bg); +} + +/* ✅ GOOD */ +.item-active { + border-color: transparent; + background-color: transparent; + color: var(--color-fg); + /* Rely on a pseudo-element or separate indicator line for the active state */ +} +``` \ No newline at end of file diff --git a/src/renderer/src/components/Canvas.tsx b/src/renderer/src/components/Canvas.tsx index 0964bd0..1d40edd 100644 --- a/src/renderer/src/components/Canvas.tsx +++ b/src/renderer/src/components/Canvas.tsx @@ -183,7 +183,7 @@ export function Canvas(props: CanvasProps) { : "bg-muted"; const segmentBtn = - "min-w-[44px] min-h-9 px-3.5 border-0 border-r border-panel-border bg-transparent cursor-pointer text-fg hover:bg-[var(--surface-item-hover-bg)] last:border-r-0 font-medium tracking-wide max-md:min-h-10"; + "min-w-[44px] min-h-9 px-3.5 border-0 bg-transparent cursor-pointer text-muted hover:text-fg hover:bg-[var(--surface-item-hover-bg)] font-medium tracking-wide max-md:min-h-10 rounded-[10px] transition-colors"; return (
@@ -191,15 +191,23 @@ export function Canvas(props: CanvasProps) { className="absolute top-4 left-4 z-20 flex items-center flex-wrap gap-2.5 pointer-events-auto max-md:left-[70px] max-md:right-2.5 max-md:top-2.5 max-md:gap-2" aria-label="Canvas controls" > +
+ + Baton + + + Orchestrate terminals + +
@@ -228,7 +236,7 @@ export function Canvas(props: CanvasProps) {
{props.terminalMode === "electron" @@ -288,7 +296,7 @@ export function Canvas(props: CanvasProps) { )} -
+
Drag to pan · scroll to pan · ⌘/ctrl/alt + scroll to zoom · double-click workspace to rename
diff --git a/src/renderer/src/components/TerminalPane.tsx b/src/renderer/src/components/TerminalPane.tsx index 9b89429..d454798 100644 --- a/src/renderer/src/components/TerminalPane.tsx +++ b/src/renderer/src/components/TerminalPane.tsx @@ -77,7 +77,7 @@ export function TerminalPane({ terminalId }: TerminalPaneProps) { cursorStyle: "block", convertEol: false, fontFamily: - '"Terminess Nerd Font Mono", "JetBrainsMono Nerd Font Mono", "FiraCode Nerd Font Mono", SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace', + '"FiraCode Nerd Font Mono", "JetBrainsMono Nerd Font Mono", SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace', fontSize: 14, lineHeight: 1.2, scrollback: 10000, diff --git a/src/renderer/src/components/WorkspaceSidebar.tsx b/src/renderer/src/components/WorkspaceSidebar.tsx index e723ca4..e5ac5a5 100644 --- a/src/renderer/src/components/WorkspaceSidebar.tsx +++ b/src/renderer/src/components/WorkspaceSidebar.tsx @@ -17,23 +17,20 @@ interface WorkspaceSidebarProps { } const SIDEBAR_BASE = - "surface-sidebar flex flex-col h-full grow-0 shrink-0 z-30 border-r border-panel-border backdrop-blur-2xl transition-[width,flex-basis] duration-150 ease-out max-md:absolute max-md:inset-y-0 max-md:left-0 max-md:basis-auto max-md:shadow-[24px_0_80px_rgba(0,0,0,0.25)]"; + "relative surface-sidebar flex flex-col h-full grow-0 shrink-0 z-30 border-r border-panel-border backdrop-blur-2xl transition-[width,flex-basis] duration-150 ease-out max-md:absolute max-md:inset-y-0 max-md:left-0 max-md:basis-auto max-md:shadow-[24px_0_80px_rgba(0,0,0,0.25)]"; const SIDEBAR_COLLAPSED = "w-[66px] basis-[66px] max-md:w-[58px]"; const SIDEBAR_COLLAPSED_MAC = "w-[96px] basis-[96px] max-md:w-[88px]"; const SIDEBAR_EXPANDED = "w-[286px] basis-[286px] max-md:w-[min(82vw,286px)]"; -const ICON_BUTTON = - "app-region-no-drag chamfer surface-btn-secondary inline-flex items-center justify-center w-9 h-9 min-h-9 px-0 cursor-pointer"; - const SECONDARY_BUTTON = - "app-region-no-drag chamfer surface-btn-secondary min-h-9 min-w-0 px-1.5 text-[10px] font-medium tracking-[0.01em] text-center cursor-pointer overflow-hidden whitespace-nowrap text-ellipsis"; + "app-region-no-drag rounded-[10px] min-h-9 min-w-0 px-1.5 text-[10px] font-medium tracking-[0.01em] text-center cursor-pointer overflow-hidden whitespace-nowrap text-ellipsis text-muted hover:text-fg hover:bg-[var(--surface-item-hover-bg)] transition-colors"; const ITEM_BASE = - "app-region-no-drag pill-rounded w-full flex items-center gap-3 p-2.5 mb-2 text-left border relative"; + "app-region-no-drag pill-rounded w-full flex items-center gap-3 p-2.5 mb-2 text-left relative"; const ITEM_COLLAPSED = - "app-region-no-drag pill-rounded flex items-center justify-center w-11 h-11 mx-auto mb-2 border"; + "app-region-no-drag pill-rounded flex items-center justify-center w-11 h-11 mx-auto mb-2 relative"; const ITEM_INACTIVE = "surface-item-inactive"; const ITEM_ACTIVE = "surface-item-active"; @@ -76,41 +73,12 @@ export function WorkspaceSidebar(props: WorkspaceSidebarProps) { props.collapsed ? collapsedSidebarClass : SIDEBAR_EXPANDED }`} > +
- - {!props.collapsed && ( -
- - Baton - - - Orchestrate terminals - -
- )}
props.onRenameWorkspace(workspace.id)} title={workspace.name} > - {selected && !props.collapsed && ( + {selected && ( {!props.collapsed && activeWorkspace && (
diff --git a/src/renderer/src/styles.css b/src/renderer/src/styles.css index e2fdd6d..535fb66 100644 --- a/src/renderer/src/styles.css +++ b/src/renderer/src/styles.css @@ -4,23 +4,23 @@ /* * Typography * UI: Bricolage Grotesque (Google Fonts) - * Terminal: Terminess Nerd Font Mono (Nerd Fonts CDN via jsDelivr) + * Terminal: FiraCode Nerd Font Mono (Nerd Fonts CDN via jsDelivr) */ @font-face { - font-family: "Terminess Nerd Font Mono"; + font-family: "FiraCode Nerd Font Mono"; font-style: normal; font-weight: 400; font-display: swap; - src: url("https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@master/patched-fonts/Terminus/Regular/TerminessNerdFontMono-Regular.ttf") format("truetype"); + src: url("https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@master/patched-fonts/FiraCode/Regular/FiraCodeNerdFontMono-Regular.ttf") format("truetype"); } @font-face { - font-family: "Terminess Nerd Font Mono"; + font-family: "FiraCode Nerd Font Mono"; font-style: normal; font-weight: 700; font-display: swap; - src: url("https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@master/patched-fonts/Terminus/Bold/TerminessNerdFontMono-Bold.ttf") format("truetype"); + src: url("https://cdn.jsdelivr.net/gh/ryanoasis/nerd-fonts@master/patched-fonts/FiraCode/Bold/FiraCodeNerdFontMono-Bold.ttf") format("truetype"); } @theme { @@ -41,7 +41,7 @@ --color-warning: #e7e5e4; --color-danger: #fafafa; - --surface-sidebar: rgba(10, 10, 10, 0.90); + --surface-sidebar: linear-gradient(180deg, rgba(10, 10, 10, 0.90), rgba(18, 18, 17, 0.92)); --surface-window: rgba(10, 10, 10, 0.95); --surface-window-border: rgba(231, 229, 228, 0.15); --surface-window-shadow: 0 24px 80px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(245, 245, 244, 0.04); @@ -86,7 +86,7 @@ --terminal-selection: #404040; --font-sans: "Bricolage Grotesque", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; - --font-mono: "Terminess Nerd Font Mono", "JetBrainsMono Nerd Font Mono", "FiraCode Nerd Font Mono", SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; + --font-mono: "FiraCode Nerd Font Mono", "JetBrainsMono Nerd Font Mono", SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; } /* @@ -106,7 +106,7 @@ --color-warning: #b45309; --color-danger: #b91c1c; - --surface-sidebar: rgba(250, 249, 246, 0.92); + --surface-sidebar: linear-gradient(180deg, rgba(250, 249, 246, 0.92), rgba(245, 245, 244, 0.94)); --surface-window: rgba(255, 254, 251, 0.96); --surface-window-border: rgba(28, 25, 23, 0.14); --surface-window-shadow: 0 18px 60px rgba(28, 25, 23, 0.14), inset 0 1px 0 rgba(255, 255, 255, 0.8); @@ -207,6 +207,7 @@ input { .terminal-header-grad { background: var(--surface-header-grad); + backdrop-filter: blur(12px); } /* @@ -220,6 +221,7 @@ input { .surface-window { border: 1px solid var(--surface-window-border); + border-radius: 12px; background: var(--surface-window); box-shadow: var(--surface-window-shadow); } @@ -280,8 +282,8 @@ input { .surface-item-active { color: var(--color-fg); - border-color: var(--surface-item-active-border); - background-color: var(--surface-item-active-bg); + border-color: transparent; + background-color: transparent; } .surface-item-avatar { @@ -309,14 +311,7 @@ input { * cannot collide with the angled notches when the element is narrow. */ .blade { - clip-path: polygon( - 12px 0, - calc(100% - 12px) 0, - 100% 50%, - calc(100% - 12px) 100%, - 12px 100%, - 0 50% - ); + border-radius: 18px; padding-left: max(1.125rem, 18px); padding-right: max(1.125rem, 18px); } @@ -324,27 +319,13 @@ input { /* When a blade wraps a single icon/glyph we still need the point cuts * but can collapse the textual side padding to stay compact. */ .blade-compact { - clip-path: polygon( - 10px 0, - calc(100% - 10px) 0, - 100% 50%, - calc(100% - 10px) 100%, - 10px 100%, - 0 50% - ); + border-radius: 18px; padding-left: 14px; padding-right: 14px; } .notch { - clip-path: polygon( - 0 0, - calc(100% - 14px) 0, - 100% 14px, - 100% 100%, - 14px 100%, - 0 calc(100% - 14px) - ); + border-radius: 12px; } /* @@ -497,8 +478,8 @@ input { gap: 0; padding: 2px; border-radius: 7px; - border: 1px solid var(--surface-btn-secondary-border); - background: var(--surface-btn-secondary-bg); + border: 1px solid transparent; + background: transparent; } .theme-toggle[data-compact='true'] { @@ -515,8 +496,8 @@ input { left: 2px; width: calc((100% - 4px) / var(--theme-toggle-count)); border-radius: 5px; - background: var(--surface-item-active-bg); - box-shadow: inset 0 0 0 1px var(--surface-item-active-border); + background: var(--surface-item-hover-bg); + box-shadow: none; transform: translateX(calc(var(--theme-toggle-index) * 100%)); transition: transform 220ms cubic-bezier(0.4, 0.0, 0.2, 1); pointer-events: none;