mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
feat(UX): update theme selector in preferences modal
This commit is contained in:
@@ -2,28 +2,30 @@ import styled from 'styled-components';
|
||||
import { rgba } from 'polished';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
.theme-mode-selector {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
padding: 8px 0;
|
||||
|
||||
.theme-mode-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
border: 1px solid ${(props) => props.theme.input.border};
|
||||
border-radius: ${(props) => props.theme.border.radius.md};
|
||||
box-shadow: none;
|
||||
padding: 6px 8px;
|
||||
width: auto;
|
||||
|
||||
.theme-variant-section {
|
||||
margin-top: 20px;
|
||||
&.selected {
|
||||
border: 1px solid ${(props) => props.theme.accents.primary};
|
||||
background: ${(props) => rgba(props.theme.accents.primary, 0.07)};
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 1px solid ${(props) => props.theme.accents.primary};
|
||||
}
|
||||
}
|
||||
|
||||
.theme-variant-label {
|
||||
font-size: ${(props) => props.theme.font.size.sm};
|
||||
color: ${(props) => props.theme.colors.text.muted};
|
||||
margin-bottom: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.theme-variants {
|
||||
@@ -41,7 +43,7 @@ const StyledWrapper = styled.div`
|
||||
border-radius: ${(props) => props.theme.border.radius.md};
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
min-width: 120px;
|
||||
min-width: 165px;
|
||||
|
||||
&:hover {
|
||||
border-color: ${(props) => props.theme.input.focusBorder};
|
||||
@@ -50,6 +52,7 @@ const StyledWrapper = styled.div`
|
||||
&.selected {
|
||||
border-color: ${(props) => props.theme.accents.primary};
|
||||
background: ${(props) => rgba(props.theme.accents.primary, 0.07)};
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +93,7 @@ const StyledWrapper = styled.div`
|
||||
.section-divider {
|
||||
height: 1px;
|
||||
background: ${(props) => props.theme.input.border};
|
||||
margin: 24px 0;
|
||||
margin: 15px 0;
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import React from 'react';
|
||||
import { rgba } from 'polished';
|
||||
import { useTheme } from 'providers/Theme';
|
||||
import { getLightThemes, getDarkThemes } from 'themes/index';
|
||||
import themes, { getLightThemes, getDarkThemes } from 'themes/index';
|
||||
import { IconBrightnessUp, IconMoon, IconDeviceDesktop } from '@tabler/icons';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const ThemePreview = ({ themeId, isDark }) => {
|
||||
const bgColor = isDark ? '#1e1e1e' : '#ffffff';
|
||||
const sidebarColor = isDark ? '#252526' : '#f8f8f8';
|
||||
const lineColor = isDark ? '#3d3d3d' : '#e5e5e5';
|
||||
const theme = themes[themeId] || themes[isDark ? 'dark' : 'light'];
|
||||
|
||||
const bgColor = theme.background.base;
|
||||
const sidebarColor = theme.sidebar.bg;
|
||||
const lineColor = rgba(theme.brand, 0.5);
|
||||
|
||||
return (
|
||||
<div className="theme-preview" style={{ background: bgColor, border: `1px solid ${lineColor}` }}>
|
||||
@@ -44,6 +48,12 @@ const Themes = () => {
|
||||
const lightThemes = getLightThemes();
|
||||
const darkThemes = getDarkThemes();
|
||||
|
||||
const themeModes = [
|
||||
{ key: 'light', label: 'Light', icon: IconBrightnessUp },
|
||||
{ key: 'dark', label: 'Dark', icon: IconMoon },
|
||||
{ key: 'system', label: 'System', icon: IconDeviceDesktop }
|
||||
];
|
||||
|
||||
const handleModeChange = (mode) => {
|
||||
setStoredTheme(mode);
|
||||
};
|
||||
@@ -69,40 +79,30 @@ const Themes = () => {
|
||||
<div className="flex flex-col gap-4 w-full">
|
||||
<div>
|
||||
<div className="section-header">Appearance</div>
|
||||
<div className="theme-mode-selector">
|
||||
<label className="theme-mode-option">
|
||||
<input
|
||||
type="radio"
|
||||
name="theme-mode"
|
||||
value="light"
|
||||
checked={storedTheme === 'light'}
|
||||
onChange={() => handleModeChange('light')}
|
||||
/>
|
||||
<span>Light</span>
|
||||
</label>
|
||||
<label className="theme-mode-option">
|
||||
<input
|
||||
type="radio"
|
||||
name="theme-mode"
|
||||
value="dark"
|
||||
checked={storedTheme === 'dark'}
|
||||
onChange={() => handleModeChange('dark')}
|
||||
/>
|
||||
<span>Dark</span>
|
||||
</label>
|
||||
<label className="theme-mode-option">
|
||||
<input
|
||||
type="radio"
|
||||
name="theme-mode"
|
||||
value="system"
|
||||
checked={storedTheme === 'system'}
|
||||
onChange={() => handleModeChange('system')}
|
||||
/>
|
||||
<span>System</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3 theme-mode-selector justify-start">
|
||||
{themeModes.map((mode) => {
|
||||
const Icon = mode.icon;
|
||||
const isSelected = storedTheme === mode.key;
|
||||
|
||||
return (
|
||||
<button
|
||||
key={mode.key}
|
||||
onClick={() => handleModeChange(mode.key)}
|
||||
className={`theme-mode-option relative ${isSelected ? 'selected' : ''}`}
|
||||
>
|
||||
<div className="flex items-center justify-start gap-2">
|
||||
<Icon size={16} strokeWidth={1.5} />
|
||||
<span>{mode.label}</span>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="section-divider" />
|
||||
|
||||
{storedTheme === 'light' && (
|
||||
<>
|
||||
{renderThemeVariants(lightThemes, themeVariantLight, setThemeVariantLight, 'Light Theme')}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Modal from 'components/Modal/index';
|
||||
import classnames from 'classnames';
|
||||
import React, { useState } from 'react';
|
||||
import { IconSettings, IconPalette, IconBrowser, IconUserCircle, IconKeyboard, IconZoomQuestion, IconSquareLetterB } from '@tabler/icons';
|
||||
|
||||
import Support from './Support';
|
||||
import General from './General';
|
||||
@@ -59,24 +60,31 @@ const Preferences = ({ onClose }) => {
|
||||
<div className="flex flex-row gap-2 mx-[-1rem] !my-[-1.5rem] py-2">
|
||||
<div className="flex flex-col items-center tabs" role="tablist">
|
||||
<div className={getTabClassname('general')} role="tab" onClick={() => setTab('general')}>
|
||||
<IconSettings size={16} strokeWidth={1.5} />
|
||||
General
|
||||
</div>
|
||||
<div className={getTabClassname('themes')} role="tab" onClick={() => setTab('themes')}>
|
||||
<IconPalette size={16} strokeWidth={1.5} />
|
||||
Themes
|
||||
</div>
|
||||
<div className={getTabClassname('display')} role="tab" onClick={() => setTab('display')}>
|
||||
<IconBrowser size={16} strokeWidth={1.5} />
|
||||
Display
|
||||
</div>
|
||||
<div className={getTabClassname('proxy')} role="tab" onClick={() => setTab('proxy')}>
|
||||
<IconUserCircle size={16} strokeWidth={1.5} />
|
||||
Proxy
|
||||
</div>
|
||||
<div className={getTabClassname('keybindings')} role="tab" onClick={() => setTab('keybindings')}>
|
||||
<IconKeyboard size={16} strokeWidth={1.5} />
|
||||
Keybindings
|
||||
</div>
|
||||
<div className={getTabClassname('support')} role="tab" onClick={() => setTab('support')}>
|
||||
<IconZoomQuestion size={16} strokeWidth={1.5} />
|
||||
Support
|
||||
</div>
|
||||
<div className={getTabClassname('beta')} role="tab" onClick={() => setTab('beta')}>
|
||||
<IconSquareLetterB size={16} strokeWidth={1.5} />
|
||||
Beta
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -32,7 +32,7 @@ const themes = {
|
||||
export const themeRegistry = {
|
||||
'light': {
|
||||
id: 'light',
|
||||
name: 'Bruno Light',
|
||||
name: 'Light',
|
||||
mode: 'light'
|
||||
},
|
||||
'light-monochrome': {
|
||||
@@ -42,7 +42,7 @@ export const themeRegistry = {
|
||||
},
|
||||
'light-pastel': {
|
||||
id: 'light-pastel',
|
||||
name: 'Bruno Light Pastel',
|
||||
name: 'Light Pastel',
|
||||
mode: 'light'
|
||||
},
|
||||
'catppuccin-latte': {
|
||||
@@ -52,17 +52,17 @@ export const themeRegistry = {
|
||||
},
|
||||
'dark': {
|
||||
id: 'dark',
|
||||
name: 'Bruno Dark',
|
||||
name: 'Dark',
|
||||
mode: 'dark'
|
||||
},
|
||||
'dark-monochrome': {
|
||||
id: 'dark-monochrome',
|
||||
name: 'Bruno Dark Monochrome',
|
||||
name: 'Dark Monochrome',
|
||||
mode: 'dark'
|
||||
},
|
||||
'dark-pastel': {
|
||||
id: 'dark-pastel',
|
||||
name: 'Bruno Dark Pastel',
|
||||
name: 'Dark Pastel',
|
||||
mode: 'dark'
|
||||
},
|
||||
'catppuccin-frappe': {
|
||||
|
||||
Reference in New Issue
Block a user