Add a square corners toggle for a border-radius-free interface
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import * as LucideIcons from 'lucide-react';
|
||||
const { Sun, Moon, User, LogOut, Check, Menu, Sparkles, Search } = LucideIcons;
|
||||
const { Sun, Moon, User, LogOut, Check, Menu, Sparkles, Search, Radius } = LucideIcons;
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { CommandPalette } from '@/components/common/CommandPalette';
|
||||
import {
|
||||
@@ -43,6 +43,8 @@ export function TopBar() {
|
||||
const navigate = useNavigate();
|
||||
const theme = useUIStore((s) => s.theme);
|
||||
const toggleTheme = useUIStore((s) => s.toggleTheme);
|
||||
const radius = useUIStore((s) => s.radius);
|
||||
const toggleRadius = useUIStore((s) => s.toggleRadius);
|
||||
const toggleSidebar = useUIStore((s) => s.toggleSidebar);
|
||||
const setActiveSection = useUIStore((s) => s.setActiveSection);
|
||||
const accounts = useAuthStore((s) => s.accounts);
|
||||
@@ -189,6 +191,13 @@ export function TopBar() {
|
||||
</>
|
||||
)}
|
||||
|
||||
<DropdownMenuItem onClick={toggleRadius}>
|
||||
<Radius className="mr-2 h-4 w-4" />
|
||||
{t('squareCorners', 'Square corners')}
|
||||
{radius === 'square' && <Check className="ml-auto h-4 w-4" />}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
const endSessionEndpoint = useAuthStore.getState().endSessionEndpoint;
|
||||
|
||||
@@ -337,6 +337,7 @@
|
||||
"periodValue": "Period value"
|
||||
},
|
||||
"sections": "Sections",
|
||||
"squareCorners": "Square corners",
|
||||
"toggleTheme": "Toggle theme",
|
||||
"tracing": {
|
||||
"addFilter": "Add filter",
|
||||
|
||||
+9
-3
@@ -90,6 +90,12 @@
|
||||
--chart-5: 340 75% 60%;
|
||||
}
|
||||
|
||||
/* Square mode: every radius token derives multiplicatively from --radius,
|
||||
so zeroing it here flattens all corners (rounded-full stays untouched). */
|
||||
:root[data-radius='square'] {
|
||||
--radius: 0px;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
@@ -127,10 +133,10 @@
|
||||
--color-chart-4: hsl(var(--chart-4));
|
||||
--color-chart-5: hsl(var(--chart-5));
|
||||
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-sm: calc(var(--radius) * 0.5);
|
||||
--radius-md: calc(var(--radius) * 0.75);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--radius-xl: calc(var(--radius) * 1.5);
|
||||
|
||||
--animate-collapsible-down: collapsible-down 0.2s ease-out;
|
||||
--animate-collapsible-up: collapsible-up 0.2s ease-out;
|
||||
|
||||
@@ -8,14 +8,18 @@ import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
type Theme = 'light' | 'dark';
|
||||
type Radius = 'rounded' | 'square';
|
||||
|
||||
interface UIState {
|
||||
theme: Theme;
|
||||
radius: Radius;
|
||||
sidebarOpen: boolean;
|
||||
activeSection: string;
|
||||
|
||||
toggleTheme: () => void;
|
||||
setTheme: (theme: Theme) => void;
|
||||
toggleRadius: () => void;
|
||||
setRadius: (radius: Radius) => void;
|
||||
toggleSidebar: () => void;
|
||||
setSidebarOpen: (open: boolean) => void;
|
||||
setActiveSection: (section: string) => void;
|
||||
@@ -29,11 +33,16 @@ function applyThemeClass(theme: Theme) {
|
||||
}
|
||||
}
|
||||
|
||||
function applyRadiusAttribute(radius: Radius) {
|
||||
document.documentElement.dataset.radius = radius;
|
||||
}
|
||||
|
||||
export const useUIStore = create<UIState>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
theme:
|
||||
typeof window !== 'undefined' && window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light',
|
||||
radius: 'rounded',
|
||||
sidebarOpen: typeof window !== 'undefined' ? (window.matchMedia?.('(min-width: 768px)').matches ?? true) : true,
|
||||
activeSection: '',
|
||||
|
||||
@@ -48,6 +57,17 @@ export const useUIStore = create<UIState>()(
|
||||
set({ theme });
|
||||
},
|
||||
|
||||
toggleRadius: () => {
|
||||
const next = get().radius === 'rounded' ? 'square' : 'rounded';
|
||||
applyRadiusAttribute(next);
|
||||
set({ radius: next });
|
||||
},
|
||||
|
||||
setRadius: (radius) => {
|
||||
applyRadiusAttribute(radius);
|
||||
set({ radius });
|
||||
},
|
||||
|
||||
toggleSidebar: () => {
|
||||
set({ sidebarOpen: !get().sidebarOpen });
|
||||
},
|
||||
@@ -64,11 +84,13 @@ export const useUIStore = create<UIState>()(
|
||||
name: 'stalwart-ui',
|
||||
partialize: (state) => ({
|
||||
theme: state.theme,
|
||||
radius: state.radius,
|
||||
}),
|
||||
onRehydrateStorage: () => {
|
||||
return (state) => {
|
||||
if (state) {
|
||||
applyThemeClass(state.theme);
|
||||
applyRadiusAttribute(state.radius ?? 'rounded');
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user