diff --git a/src/App.tsx b/src/App.tsx index 33e4110..36bd543 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,11 +5,11 @@ import './styles/App.css'; import { DSP, DSPStatus, AppPage } from './types/types'; import TopBar from './components/Topbar/Topbar'; import DSPPage from './pages/DspPage/DspPage'; -import AddDSPForm from './pages/AddDspPage'; +import AddDSPForm from './pages/AddDspPage/AddDspPage'; import { useNotifications } from './hooks/useNotifications'; import Notifications from './components/Notifications/Notifications'; import { DSPState } from './types/dsp408State'; -import CreditsPage from './pages/CreditsPage'; +import CreditsPage from './pages/CreditsPage/CreditsPage'; import HomePage from './pages/HomePage/HomePage'; function App() { diff --git a/src/components/Button/Button.css b/src/components/Button/Button.css index d9daa3a..c7a59c9 100644 --- a/src/components/Button/Button.css +++ b/src/components/Button/Button.css @@ -1,47 +1,36 @@ .btn { - width: 100%; - height: 100%; - display: flex; align-items: center; justify-content: center; box-sizing: border-box; + min-height: var(--card-control-height); + padding: 0 var(--space-4); + border: var(--border-width) solid transparent; border-radius: var(--radius-sm); font-family: var(--font-ui); - font-size: 13px; - font-weight: 500; + font-size: var(--font-md); + font-weight: var(--font-weight-medium); cursor: pointer; - border: 1px solid transparent; } .btn:disabled { - opacity: 0.45; + opacity: var(--disabled-opacity); cursor: not-allowed; } .btn-primary { background: var(--accent-brand); - color: #0d0f12; -} - -.btn-ghost { - background: transparent; - border-color: var(--border-hairline); - color: var(--text-muted); -} - -.btn-toggle { - background: transparent; - border-color: var(--border-hairline); - color: var(--text-muted); + color: var(--bg-void); } +.btn-ghost, +.btn-toggle, .btn-outline { background: transparent; border-color: var(--border-hairline); diff --git a/src/components/Card/Card.css b/src/components/Card/Card.css index 51ea730..034ba6d 100644 --- a/src/components/Card/Card.css +++ b/src/components/Card/Card.css @@ -1,8 +1,13 @@ .card { + width: min(100%, var(--card-width)); + background: var(--bg-panel); + border: var(--border-width) solid var(--border-hairline); border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); + padding: var(--space-6); color: var(--text-primary); @@ -12,5 +17,6 @@ display: flex; flex-direction: column; - width: clamp(280px, 33.333%, 480px); + min-width: 0; + box-sizing: border-box; } diff --git a/src/components/Sidebar/Sidebar.css b/src/components/Sidebar/Sidebar.css index 3808bd5..975734c 100644 --- a/src/components/Sidebar/Sidebar.css +++ b/src/components/Sidebar/Sidebar.css @@ -132,7 +132,7 @@ align-items: center; font-size: var(--font-size-sm, 13px); - font-weight: 600; + font-weight: var(--font-weight-semibold); color: var(--text-primary); white-space: nowrap; diff --git a/src/components/dsp408/ChannelGroup/ChannelGroup.css b/src/components/dsp408/ChannelGroup/ChannelGroup.css index 2df995f..a12cb6c 100644 --- a/src/components/dsp408/ChannelGroup/ChannelGroup.css +++ b/src/components/dsp408/ChannelGroup/ChannelGroup.css @@ -27,7 +27,7 @@ font-family: var(--font-ui); font-size: var(--tab-close-font); - font-weight: 600; + font-weight: var(--font-weight-semibold); color: var(--text-muted); white-space: nowrap; diff --git a/src/components/dsp408/ConnectionSection/ConnectionSection.css b/src/components/dsp408/ConnectionSection/ConnectionSection.css index 687e444..cde4110 100644 --- a/src/components/dsp408/ConnectionSection/ConnectionSection.css +++ b/src/components/dsp408/ConnectionSection/ConnectionSection.css @@ -1,4 +1,4 @@ -.connection-panel-frame { +/* .connection-panel-frame { width: 33.333%; height: 33.333%; box-sizing: border-box; @@ -27,7 +27,7 @@ align-items: flex-start; justify-content: space-between; gap: 12px; - min-width: 0; /* required so children can actually shrink/ellipsize instead of forcing overflow */ + min-width: 0; } .panel-header-text { @@ -41,7 +41,7 @@ text-overflow: ellipsis; margin: 0; font-size: 18px; - font-weight: 600; + font-weight: var(--font-weight-semibold); } .mono { @@ -54,19 +54,11 @@ flex-shrink: 0; } -.panel-actions { - position: absolute; - right: 16px; - bottom: 16px; - margin: 0; /* drop margin-top: auto, no longer needed */ - padding: 0; /* drop padding-top: 16px, spacing now handled by right/bottom offsets */ -} - .connection-section { - position: absolute; /* was: fixed — relative to .dsp-content now */ - inset: 0; /* replaces top:0; right:0; bottom:0; left:0 */ + position: absolute; + inset: 0; display: flex; justify-content: center; align-items: center; -} +} */ diff --git a/src/components/dsp408/GainSection/GainSection.css b/src/components/dsp408/GainSection/GainSection.css index ef15ee5..b81bb87 100644 --- a/src/components/dsp408/GainSection/GainSection.css +++ b/src/components/dsp408/GainSection/GainSection.css @@ -74,7 +74,7 @@ font-family: var(--font-ui); font-size: 12px; - font-weight: 600; + font-weight: var(--font-weight-semibold); padding-bottom: 6px; diff --git a/src/components/dsp408/GainSection/GainSection.tsx b/src/components/dsp408/GainSection/GainSection.tsx index 378e940..faa10db 100644 --- a/src/components/dsp408/GainSection/GainSection.tsx +++ b/src/components/dsp408/GainSection/GainSection.tsx @@ -92,15 +92,7 @@ function GainPanel({ }; return ( -
+
{title}
diff --git a/src/components/dsp408/GateSection/GateSection.css b/src/components/dsp408/GateSection/GateSection.css new file mode 100644 index 0000000..b880108 --- /dev/null +++ b/src/components/dsp408/GateSection/GateSection.css @@ -0,0 +1,118 @@ +.gate-section { + position: absolute; + left: 0; + right: 0; + bottom: 0; + + height: var(--gain-section-height); + min-height: 0; + + display: flex; + align-items: flex-end; + justify-content: center; + + box-sizing: border-box; + padding: 0 var(--space-4); + + background: var(--bg-panel); + + z-index: 20; + + border-top: 1px solid var(--border-hairline); +} + +.gate-panels { + display: flex; + flex-direction: row; + align-items: stretch; + justify-content: safe center; + gap: var(--space-4); + width: 100%; + height: 100%; + min-width: 0; + min-height: 0; + overflow-x: auto; + overflow-y: hidden; +} + +.gate-panel-frame { + flex: 0 0 auto; + height: calc(100% - 8px); + aspect-ratio: var(--panel-w) / var(--panel-h); + margin: 4px 0; + box-sizing: border-box; +} + +.gate-panels::-webkit-scrollbar { + height: 6px; +} +.gate-panels::-webkit-scrollbar-thumb { + background: var(--border-hairline); + border-radius: var(--radius-pill); +} +.gate-panels::-webkit-scrollbar-track { + background: transparent; +} + +.gate-panel { + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + border: 1px solid var(--border-hairline); + border-radius: var(--radius-md); + box-sizing: border-box; + padding: 8px; + background: var(--bg-void); +} + +.gate-panel__title { + width: 100%; + + text-align: center; + + font-family: var(--font-ui); + font-size: 12px; + font-weight: var(--font-weight-semibold); + + padding-bottom: 6px; + + border-bottom: 1px solid var(--border-hairline); +} + +.gate-panel__sliders { + display: flex; + flex-direction: row; + align-items: stretch; + justify-content: center; + gap: var(--space-2); + width: 100%; + flex: 1; + min-height: 0; +} + +.gate-panel__slider-col { + display: flex; + flex-direction: column; + align-items: center; + flex: 1 1 0; + min-width: 0; +} + +.gate-panel__slider-label { + font-family: var(--font-ui); + font-size: 10px; + font-weight: var(--font-weight-medium); + text-align: center; + padding-top: 4px; + color: var(--text-secondary); +} + +/* GateSection.css */ +.gate-panels .channel-group__items { + display: grid; + grid-template-columns: repeat(2, auto); + grid-template-rows: repeat(2, 1fr); + gap: var(--space-2); + align-items: stretch; +} diff --git a/src/components/topbar/Topbar.css b/src/components/topbar/Topbar.css index 42e05b9..725d353 100644 --- a/src/components/topbar/Topbar.css +++ b/src/components/topbar/Topbar.css @@ -7,7 +7,7 @@ -webkit-app-region: drag; padding-inline: var(--space-3); gap: var(--space-3); - box-sizing: border-box + box-sizing: border-box; } .logo-slot { @@ -37,7 +37,6 @@ -webkit-app-region: no-drag; border-left: 1px solid var(--border-hairline); - scrollbar-width: thin; scrollbar-color: var(--border-hairline) transparent; scroll-behavior: smooth; @@ -114,7 +113,7 @@ color: var(--text-muted); font-family: var(--font-ui); - font-weight: 500; + font-weight: var(--font-weight-medium); flex-shrink: 0; diff --git a/src/pages/AddDspPage/AddDspPage.css b/src/pages/AddDspPage/AddDspPage.css new file mode 100644 index 0000000..9d60079 --- /dev/null +++ b/src/pages/AddDspPage/AddDspPage.css @@ -0,0 +1,69 @@ +.add-dsp-form__header { + margin-bottom: var(--space-5); +} + +.add-dsp-form__title { + margin: 0; + font-size: var(--font-lg); + font-weight: var(--font-weight-semibold); + color: var(--text-primary); +} + +.add-dsp-form__hint { + margin: var(--space-2) 0 0; + font-size: var(--font-sm); + color: var(--text-muted); +} + +.add-dsp-form__field { + display: flex; + flex-direction: column; + gap: var(--space-2); + margin-bottom: var(--space-4); + flex: 1; + min-width: 0; +} + +.add-dsp-form__row { + display: flex; + gap: var(--space-3); +} + +.add-dsp-form__field label { + font-size: var(--font-sm); + color: var(--text-muted); +} + +.add-dsp-form__field input, +.add-dsp-form__field select { + height: var(--card-control-height); + padding: 0 var(--space-3); + + background: var(--bg-panel); + + border: var(--border-width) solid var(--border-hairline); + border-radius: var(--radius-sm); + + color: var(--text-primary); + font-family: var(--font-ui); + font-size: var(--font-sm); + + outline: none; + transition: border-color var(--dur-base) var(--ease-standard); +} + +.add-dsp-form__field input.mono { + font-family: var(--font-mono); +} + +.add-dsp-form__field input:focus, +.add-dsp-form__field select:focus { + border-color: var(--accent-brand); +} + +.add-dsp-form__actions { + display: flex; + justify-content: flex-end; + gap: var(--space-3); + margin-top: var(--space-2); +} diff --git a/src/pages/AddDspPage.tsx b/src/pages/AddDspPage/AddDspPage.tsx similarity index 77% rename from src/pages/AddDspPage.tsx rename to src/pages/AddDspPage/AddDspPage.tsx index 516a37f..afa0cb7 100644 --- a/src/pages/AddDspPage.tsx +++ b/src/pages/AddDspPage/AddDspPage.tsx @@ -1,6 +1,9 @@ import { useState } from 'react'; -import { DSP, DSP_TYPES } from '../types/types'; -import Button from '../components/Button/Button'; +import { DSP, DSP_TYPES } from '../../types/types'; +import Button from '../../components/Button/Button'; +import Card from '../../components/Card/Card'; + +import './AddDspPage.css'; function AddDSPForm({ onCancel, @@ -28,13 +31,13 @@ function AddDSPForm({ } return ( -
-
-

Add DSP

-

Register a new device to control from this app.

+ +
+

Add DSP

+

Register a new device to control from this app.

-
+
-
-
+
+
-
-
+
+
-
+
-
+
@@ -116,7 +119,7 @@ function AddDSPForm({ Add DSP
-
+ ); } diff --git a/src/pages/CreditsPage.tsx b/src/pages/CreditsPage.tsx deleted file mode 100644 index 2ee3ec8..0000000 --- a/src/pages/CreditsPage.tsx +++ /dev/null @@ -1,35 +0,0 @@ -function CreditsPage() { - return ( -
-
-
-

Credits

-
Thank you to everyone supporting the project
-
-
- -
-
-
Developer
-
Your Name
-
- -
-
Design
-
Open Source Community
-
- -
-
Libraries
-
React · Tauri · TypeScript
-
-
- -
- -
-
- ); -} - -export default CreditsPage; diff --git a/src/pages/CreditsPage/CreditsPage.css b/src/pages/CreditsPage/CreditsPage.css new file mode 100644 index 0000000..0b34e92 --- /dev/null +++ b/src/pages/CreditsPage/CreditsPage.css @@ -0,0 +1,26 @@ +.credits-page__header { + margin-bottom: var(--space-5); +} + +.credits-page__title { + margin: 0; + + font-size: var(--font-2xl); + font-weight: var(--font-weight-semibold); + + color: var(--text-primary); +} + +.credits-page__subtitle { + margin: var(--space-2) 0 0; + + font-size: var(--font-sm); + color: var(--text-muted); +} + +.credits-page__actions { + display: flex; + justify-content: flex-end; + + margin-top: var(--space-2); +} diff --git a/src/pages/CreditsPage/CreditsPage.tsx b/src/pages/CreditsPage/CreditsPage.tsx new file mode 100644 index 0000000..a03590d --- /dev/null +++ b/src/pages/CreditsPage/CreditsPage.tsx @@ -0,0 +1,45 @@ +import Card from '../../components/Card/Card'; +import Button from '../../components/Button/Button'; + +import './CreditsPage.css'; + +function CreditsPage() { + return ( + +
+

Credits

+

+ Thanks to the people, projects, and communities that made this application possible. +

+
+ +
+
+
Developer
+
Lucas
+
+ +
+
Framework
+
React + TypeScript
+
+ +
+
Desktop Runtime
+
Tauri
+
+ +
+
Special Thanks
+
+
+
+ +
+ +
+
+ ); +} + +export default CreditsPage; diff --git a/src/pages/HomePage/HomePage.css b/src/pages/HomePage/HomePage.css index bad807d..b40e4c5 100644 --- a/src/pages/HomePage/HomePage.css +++ b/src/pages/HomePage/HomePage.css @@ -1,35 +1,14 @@ .home-page { width: 100%; height: 100%; - position: relative; display: flex; align-items: center; justify-content: center; -} -.status-block { - display: flex; - align-items: center; - gap: var(--space-2); - flex-shrink: 0; -} + padding: var(--space-6); -.status-label { - font-weight: 500; - transition: color var(--dur-base) var(--ease-standard); -} - -.status-label--connected { - color: var(--accent-live); -} - -.status-label--connecting { - color: var(--accent-connecting); -} - -.status-label--disconnected { - color: var(--text-muted); + box-sizing: border-box; } .specs { @@ -50,18 +29,30 @@ display: flex; align-items: center; justify-content: space-between; + + gap: var(--space-4); } .spec dt { color: var(--text-muted); + font-size: var(--font-md); } .spec dd { margin: 0; + color: var(--text-primary); + font-weight: var(--font-weight-medium); + font-size: var(--font-md); } -.panel-actions { +.home-panel-actions { display: flex; justify-content: flex-end; } + +.card-content { + display: flex; + flex-direction: column; + gap: var(--space-6); +} diff --git a/src/pages/HomePage/HomePage.tsx b/src/pages/HomePage/HomePage.tsx index ea01516..22f7db8 100644 --- a/src/pages/HomePage/HomePage.tsx +++ b/src/pages/HomePage/HomePage.tsx @@ -2,39 +2,41 @@ import Button from '../../components/Button/Button'; import Card from '../../components/Card/Card'; import './HomePage.css'; -function HomePage({ - dspCount, - connectedCount, - onAddDSP, -}: { +interface HomePageProps { dspCount: number; connectedCount: number; onAddDSP: () => void; -}) { +} + +function HomePage({ dspCount, connectedCount, onAddDSP }: HomePageProps) { return ( - -
-
-
Connected
-
- {connectedCount} DSP{connectedCount !== 1 ? 's' : ''} -
-
+
+ +
+
+
+
Connected
+
+ {connectedCount} DSP{connectedCount !== 1 ? 's' : ''} +
+
-
-
Devices
-
- {dspCount} DSP{dspCount !== 1 ? 's' : ''} configured -
-
-
+
+
Devices
+
+ {dspCount} DSP{dspCount !== 1 ? 's' : ''} configured +
+
+
-
- -
-
+
+ +
+
+ +
); } diff --git a/src/styles/App.css b/src/styles/App.css index 1f38199..d1dad87 100644 --- a/src/styles/App.css +++ b/src/styles/App.css @@ -58,105 +58,15 @@ button { transform var(--dur-base) var(--ease-standard); } -/* ---------- Stage / main area ---------- */ - .stage { flex: 1; display: flex; align-items: center; justify-content: center; - padding: 40px var(--space-6); background: var(--bg-panel); overflow-y: auto; } -.empty { - display: flex; - flex-direction: column; - align-items: center; - gap: 14px; - color: var(--text-muted); - text-align: center; -} - -.empty-mark { - font-size: 28px; - color: var(--border-hairline); -} - -.empty p { - margin: 0; - font-size: 14px; -} - -/* ---------- Form ---------- */ - -.form-header { - margin-bottom: var(--space-5); -} - -.form-hint { - margin: 6px 0 0; - font-size: 13px; - color: var(--text-muted); -} - -.field { - display: flex; - flex-direction: column; - gap: 6px; - margin-bottom: var(--space-4); - flex: 1; -} - -.field--grow { - flex: 2; -} - -.field--narrow { - flex: 1; -} - -.field-row { - display: flex; - gap: var(--space-3); -} - -.field label { - font-size: 12px; - color: var(--text-muted); -} - -.field input, -.field select { - height: 36px; - padding: 0 10px; - background: var(--bg-panel); - border: 1px solid var(--border-hairline); - border-radius: var(--radius-sm); - color: var(--text-primary); - font-family: var(--font-ui); - font-size: 13px; - outline: none; - transition: border-color var(--dur-base) var(--ease-standard); -} - -.field input.mono { - font-family: var(--font-mono); -} - -.field input:focus, -.field select:focus { - border-color: var(--accent-brand); -} - -.form-actions { - display: flex; - justify-content: flex-end; - gap: 10px; - margin-top: var(--space-2); -} - /* Global scrollbar */ ::-webkit-scrollbar { width: 4px; diff --git a/src/styles/variables.css b/src/styles/variables.css index 657028b..c30487a 100644 --- a/src/styles/variables.css +++ b/src/styles/variables.css @@ -23,6 +23,11 @@ --font-xl: 1.25rem; --font-2xl: 1.5rem; + /* ---------- Typography ---------- */ + --font-weight-normal: 400; + --font-weight-medium: 500; + --font-weight-semibold: 600; + /* ---------- Spacing Scale ---------- */ --space-0: 0; --space-1: 0.25rem; @@ -45,16 +50,21 @@ --radius-lg: 10px; --radius-pill: 999px; - - /* ---------- Header ---------- */ --header-height: 50px; --font-size-header: 1rem; --tab-height: calc(var(--header-height) * 0.75); + /* ---------- Card ---------- */ + --card-width: 500px; + --card-control-height: 36px; + + /* ---------- Button ---------- */ + --disabled-opacity: 0.45; + /* ---------- SideBar ---------- */ - --sidebar-width-collapsed: calc(var(--header-height) * 0.85 + 2 * var(--space-3)); + --sidebar-width-collapsed: calc(var(--header-height) * 0.85 + 2 * var(--space-3)); --gain-section-height: 40vh; @@ -88,14 +98,10 @@ --ease-out: cubic-bezier(0, 0, 0.2, 1); --ease-in: cubic-bezier(0.4, 0, 1, 1); - - /* ---------- Shadow ---------- */ --shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.2); --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.25); - - /* ---------- Animation ---------- */ --transition-fast: 120ms; --transition-base: 180ms;