From 4dc557a25575ccac1328d578beb84f75bdaaf91d Mon Sep 17 00:00:00 2001 From: LucasDLTG Date: Wed, 22 Jul 2026 22:33:14 +0200 Subject: [PATCH] feat: add gain responsive --- package.json | 4 +- src-tauri/src/commands.rs | 32 +++ src-tauri/src/lib.rs | 2 + src/{components/app => }/App.tsx | 26 +- src/components/Button/Button.css | 80 ++++++ src/components/Button/Button.tsx | 32 +++ .../Notifications/Notifications.css | 103 +++++++ .../{ => Notifications}/Notifications.tsx | 9 +- .../{dsp408 => }/Sidebar/Sidebar.css | 35 +-- .../{dsp408 => }/Sidebar/Sidebar.tsx | 10 +- src/components/Slider/VerticalSlider.css | 186 ++++++++++++ src/components/Slider/VerticalSlider.tsx | 267 ++++++++++++++++++ .../VerticalStack/VerticalStack.css | 82 ++++++ .../VerticalStack/VerticalStack.tsx | 27 ++ src/components/dsp408/GainPanel.tsx | 56 ---- .../dsp408/GainSection/GainSection.css | 67 +++++ .../dsp408/GainSection/GainSection.tsx | 155 ++++++++++ .../dsp408/Slider.tsx/VerticalSlider.css | 164 ----------- .../dsp408/Slider.tsx/VerticalSlider.tsx | 264 ----------------- .../dsp408/VerticalStack/VerticalStack.css | 91 ------ .../dsp408/VerticalStack/VerticalStack.tsx | 85 ------ src/hooks/useNotifications.tsx | 4 +- src/main.tsx | 2 +- src/{components/app => pages}/AddDspPage.tsx | 12 +- src/{components/app => pages}/CreditsPage.tsx | 0 src/{components/dsp408 => pages}/DspPage.tsx | 23 +- src/{components/app => pages}/HomePage.tsx | 6 +- src/styles/App.css | 204 ++----------- src/styles/variables.css | 8 +- 29 files changed, 1128 insertions(+), 908 deletions(-) rename src/{components/app => }/App.tsx (86%) create mode 100644 src/components/Button/Button.css create mode 100644 src/components/Button/Button.tsx create mode 100644 src/components/Notifications/Notifications.css rename src/components/{ => Notifications}/Notifications.tsx (82%) rename src/components/{dsp408 => }/Sidebar/Sidebar.css (92%) rename src/components/{dsp408 => }/Sidebar/Sidebar.tsx (88%) create mode 100644 src/components/Slider/VerticalSlider.css create mode 100644 src/components/Slider/VerticalSlider.tsx create mode 100644 src/components/VerticalStack/VerticalStack.css create mode 100644 src/components/VerticalStack/VerticalStack.tsx delete mode 100644 src/components/dsp408/GainPanel.tsx create mode 100644 src/components/dsp408/GainSection/GainSection.css create mode 100644 src/components/dsp408/GainSection/GainSection.tsx delete mode 100644 src/components/dsp408/Slider.tsx/VerticalSlider.css delete mode 100644 src/components/dsp408/Slider.tsx/VerticalSlider.tsx delete mode 100644 src/components/dsp408/VerticalStack/VerticalStack.css delete mode 100644 src/components/dsp408/VerticalStack/VerticalStack.tsx rename src/{components/app => pages}/AddDspPage.tsx (91%) rename src/{components/app => pages}/CreditsPage.tsx (100%) rename src/{components/dsp408 => pages}/DspPage.tsx (59%) rename src/{components/app => pages}/HomePage.tsx (84%) diff --git a/package.json b/package.json index fc3f9ca..a4a7258 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "build": "tsc && vite build", "preview": "vite preview", "tauri": "tauri", - "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx}\"", - "format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx}\"" + "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,css}\"", + "format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,css}\"" }, "dependencies": { "@tauri-apps/api": "^2", diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index d9cf37f..f35df15 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -172,3 +172,35 @@ pub async fn set_channel_gain( Ok(r) }) } + +#[tauri::command] +pub async fn set_mute( + state: State<'_, AppState>, + id: u64, + channel: dsp_thomann::dsp408::types::Channel, + muted: bool, +) -> Result { + state.with_device_mut(id, |device| { + let r = device.dsp + .set_mute(channel, muted) + .map_err(|e| e.to_string())?; + + Ok(r) + }) +} + +#[tauri::command] +pub async fn set_channel_inverse_gain( + state: State<'_, AppState>, + id: u64, + channel: dsp_thomann::dsp408::types::Channel, + inverted: bool, +) -> Result { + state.with_device_mut(id, |device| { + let r = device.dsp + .set_channel_inverse_gain(channel, inverted) + .map_err(|e| e.to_string())?; + + Ok(r) + }) +} \ No newline at end of file diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 44a4fb8..36da333 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -15,6 +15,8 @@ pub fn run() { commands::disconnect_dsp408, commands::get_dsp_state, commands::set_channel_gain, + commands::set_mute, + commands::set_channel_inverse_gain ] ) .run(tauri::generate_context!()) diff --git a/src/components/app/App.tsx b/src/App.tsx similarity index 86% rename from src/components/app/App.tsx rename to src/App.tsx index e9ff995..4bbbab7 100644 --- a/src/components/app/App.tsx +++ b/src/App.tsx @@ -1,16 +1,16 @@ import { invoke } from '@tauri-apps/api/core'; import { useState } from 'react'; -import '../../styles/App.css'; -import { DSP, DSPStatus, AppPage } from '../../types/types'; -import TopBar from '../topbar/Topbar'; -import DSPPage from '../dsp408/DspPage'; -import AddDSPForm from './AddDspPage'; -import { useNotifications } from '../../hooks/useNotifications'; -import Notifications from '../Notifications'; -import { DSPState } from '../../types/dsp408State'; -import CreditsPage from './CreditsPage'; -import HomePage from './HomePage'; +import './styles/App.css'; +import { DSP, DSPStatus, AppPage } from './types/types'; +import TopBar from './components/topbar/Topbar'; +import DSPPage from './pages/DspPage'; +import AddDSPForm from './pages/AddDspPage'; +import { useNotifications } from './hooks/useNotifications'; +import Notifications from './components/Notifications/Notifications'; +import { DSPState } from './types/dsp408State'; +import CreditsPage from './pages/CreditsPage'; +import HomePage from './pages/HomePage'; function App() { const [dsps, setDsps] = useState([]); @@ -126,7 +126,11 @@ function App() { return (
- + { + variant?: ButtonVariant; + children: ReactNode; + className?: string; +} + +export default function Button({ + variant = 'primary', + children, + className = '', + disabled, + onClick, + type = 'button', + ...props +}: ButtonProps) { + return ( + + ); +} diff --git a/src/components/Notifications/Notifications.css b/src/components/Notifications/Notifications.css new file mode 100644 index 0000000..ee12b27 --- /dev/null +++ b/src/components/Notifications/Notifications.css @@ -0,0 +1,103 @@ +.notifications { + position: fixed; + right: var(--space-5); + bottom: var(--space-5); + z-index: 9999; + + display: flex; + flex-direction: column; + gap: var(--space-3); + + width: 320px; + pointer-events: none; +} + +.notification { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-3); + + padding: 10px var(--space-3); + border-radius: var(--radius-md); + + font-size: 14px; + + box-shadow: var(--shadow-md); + + animation: notification-in var(--dur-slow) var(--ease-out) forwards; + + pointer-events: auto; +} + +.notification-out { + animation: notification-out var(--dur-slow) var(--ease-in) forwards; +} + +.notification-close { + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 auto; + width: 20px; + height: 20px; + padding: 0; + border: none; + background: transparent; + border-radius: 4px; + font-size: 15px; + line-height: 1; + color: inherit; + cursor: pointer; + transition: background var(--dur-fast) var(--ease-standard); +} + +.notification-close:hover { + background: rgba(255, 255, 255, 0.15); +} + +.notification.error { + background: #b42318; + color: white; +} + +.notification.success { + background: #15803d; + color: white; +} + +.notification.warning { + background: #ca8a04; + color: white; +} + +.notification-message { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +@keyframes notification-in { + from { + transform: translateX(50px); + opacity: 0; + } + + to { + transform: translateX(0); + opacity: 1; + } +} + +@keyframes notification-out { + from { + transform: translateX(0); + opacity: 1; + } + + to { + transform: translateX(50px); + opacity: 0; + } +} diff --git a/src/components/Notifications.tsx b/src/components/Notifications/Notifications.tsx similarity index 82% rename from src/components/Notifications.tsx rename to src/components/Notifications/Notifications.tsx index c82ee4f..dbd2e7b 100644 --- a/src/components/Notifications.tsx +++ b/src/components/Notifications/Notifications.tsx @@ -1,4 +1,5 @@ -import type { Notification } from '../types/types'; +import type { Notification } from '../../types/types'; +import './Notifications.css'; type Props = { notifications: Notification[]; @@ -6,11 +7,7 @@ type Props = { onHover: (id: number, hovering: boolean) => void; }; -export default function Notifications({ - notifications, - onRemove, - onHover, -}: Props) { +export default function Notifications({ notifications, onRemove, onHover }: Props) { return (
{notifications.map((n) => ( diff --git a/src/components/dsp408/Sidebar/Sidebar.css b/src/components/Sidebar/Sidebar.css similarity index 92% rename from src/components/dsp408/Sidebar/Sidebar.css rename to src/components/Sidebar/Sidebar.css index 604d894..1768fdc 100644 --- a/src/components/dsp408/Sidebar/Sidebar.css +++ b/src/components/Sidebar/Sidebar.css @@ -17,7 +17,6 @@ max-width: 200px; } - /* ---------- Icon ---------- */ .sidebar-icon { @@ -43,7 +42,6 @@ fill: none; } - /* ---------- Item ---------- */ .sidebar-item { @@ -71,7 +69,6 @@ border-color var(--dur-base) var(--ease-standard); } - .sidebar-rail--expanded .sidebar-item { width: calc(100% - var(--space-4)); gap: var(--sidebar-item-gap); @@ -81,7 +78,6 @@ padding-left: var(--sidebar-item-padding); } - /* ---------- Item States ---------- */ .sidebar-item:hover { @@ -89,13 +85,11 @@ color: var(--text-primary); } - .sidebar-item--active { border-color: var(--accent-brand); color: var(--text-primary); } - /* ---------- Sidebar ---------- */ .sidebar-rail { @@ -118,16 +112,13 @@ overflow: visible; - transition: - width var(--dur-base) var(--ease-standard); + transition: width var(--dur-base) var(--ease-standard); } - .sidebar-rail--expanded { width: var(--sidebar-width-expanded); } - /* ---------- App name ---------- */ .sidebar-app-name { @@ -162,7 +153,6 @@ transition-delay: var(--dur-fast); } - /* ---------- Scroll ---------- */ .sidebar-scroll { @@ -179,12 +169,10 @@ overflow-y: auto; } - .sidebar-rail--expanded .sidebar-scroll { align-items: stretch; } - /* ---------- Toggle ---------- */ .sidebar-toggle { @@ -220,12 +208,10 @@ z-index: 32; } - .sidebar-rail--expanded .sidebar-toggle { left: calc(var(--sidebar-width-expanded) - var(--sidebar-toggle-size) - var(--space-3)); } - .sidebar-toggle:hover { background: var(--bg-raised); @@ -234,35 +220,32 @@ border-color: var(--accent-brand); } - .sidebar-toggle:active { - transform: scale(.92); + transform: scale(0.92); } .sidebar-rail--expanded .sidebar-toggle:active { - transform: scale(.92); + transform: scale(0.92); } - .sidebar-toggle-icon { width: 14px; height: 14px; - - transition: - transform var(--dur-base) var(--ease-standard); -} + transition: transform var(--dur-base) var(--ease-standard); +} .sidebar-rail--expanded .sidebar-toggle-icon { transform: rotate(180deg); } - /* ---------- Content ---------- */ .stage--with-sidebar { margin-left: var(--sidebar-width-collapsed); + transition: margin-left var(--dur-base) var(--ease-standard); +} - transition: - margin-left var(--dur-base) var(--ease-standard); +.app-root--sidebar-expanded .stage--with-sidebar { + margin-left: var(--sidebar-width-expanded); } \ No newline at end of file diff --git a/src/components/dsp408/Sidebar/Sidebar.tsx b/src/components/Sidebar/Sidebar.tsx similarity index 88% rename from src/components/dsp408/Sidebar/Sidebar.tsx rename to src/components/Sidebar/Sidebar.tsx index 138553b..66d0e15 100644 --- a/src/components/dsp408/Sidebar/Sidebar.tsx +++ b/src/components/Sidebar/Sidebar.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; import './Sidebar.css'; -import { ChevronLeftIcon } from '../../../assets/icons/ChevronLeftIcon'; +import { ChevronLeftIcon } from '../../assets/icons/ChevronLeftIcon'; export type SidebarItem = { id: string; @@ -13,21 +13,23 @@ export default function Sidebar({ activeId, onSelect, appName, + expanded, + onToggle, }: { items: SidebarItem[]; activeId: string | null; onSelect: (id: string) => void; appName: string; + expanded: boolean; + onToggle: () => void; }) { - const [expanded, setExpanded] = useState(false); - return (