This commit is contained in:
2025-11-10 12:50:28 +01:00
parent 9757fd0c10
commit bf1e5cd107
2 changed files with 128 additions and 73 deletions
+49 -49
View File
@@ -189,7 +189,6 @@ const Sidebar = ({
onSelectTenant,
onOpenSettings,
onUploadFiles,
loading = false,
}) => {
const {
setCollapsed,
@@ -318,6 +317,50 @@ const Sidebar = ({
cycleThemeMode();
}, [cycleThemeMode]);
const themeMenuSection =
typeof neutralHue === 'number' || typeof neutralHue === 'string'
? (
<div className="menu__section">
<div className="menu__heading menu__heading--with-actions">
<span>Theme</span>
<div className="menu__heading-actions">
<button
type="button"
className="icon-button"
onClick={handleThemeModeToggle}
aria-label={`Switch theme (next: ${nextThemeLabel})`}
title={`Theme: ${themeModeLabel} (next: ${nextThemeLabel})`}
>
{themeModeIcon}
</button>
<button
type="button"
className="icon-button"
onClick={handleNeutralHueReset}
aria-label="Reset neutral hue"
title="Reset neutral hue"
>
<RestoreIcon size={16} />
</button>
</div>
</div>
<label className="menu__slider" htmlFor={neutralHueInputId}>
<span className="menu__slider-label">Hue</span>
<input
id={neutralHueInputId}
type="range"
min="0"
max="360"
step="1"
value={neutralHue}
onChange={(event) => handleNeutralHueChange(event.target.value)}
/>
<span className="menu__slider-value">{neutralHue}°</span>
</label>
</div>
)
: null;
const handleSearchInputChange = useCallback(
(event) => {
onSearchChange?.(event.target.value);
@@ -348,6 +391,7 @@ const Sidebar = ({
offset: 6,
});
const showTenantList = tenants.length > 1;
const menuClassName = `menu${!showTenantList && !themeMenuSection ? ' menu--simple' : ''}`;
const toggleTenantMenu = useCallback(() => {
if (!tenantMenuOpen && tenants.length === 0 && onSelectTenant) {
@@ -426,50 +470,6 @@ const Sidebar = ({
);
const rootNode = folderNodes.get('root');
const themeControls =
typeof neutralHue === 'number' || typeof neutralHue === 'string'
? (
<div className="sidebar-section sidebar-theme">
<div className="sidebar-section__header">
<h3>Theme</h3>
<div className="sidebar-section__actions">
<button
type="button"
className="icon-button"
onClick={handleThemeModeToggle}
aria-label={`Switch theme (next: ${nextThemeLabel})`}
title={`Theme: ${themeModeLabel} (next: ${nextThemeLabel})`}
>
{themeModeIcon}
</button>
<button
type="button"
className="icon-button"
onClick={handleNeutralHueReset}
aria-label="Reset neutral hue"
title="Reset neutral hue"
>
<RestoreIcon size={16} />
</button>
</div>
</div>
<label className="sidebar-slider" htmlFor={neutralHueInputId}>
<span className="sidebar-slider__label">Hue</span>
<input
id={neutralHueInputId}
type="range"
min="0"
max="360"
step="1"
value={neutralHue}
onChange={(event) => handleNeutralHueChange(event.target.value)}
/>
<span className="sidebar-slider__value">{neutralHue}°</span>
</label>
</div>
)
: null;
return (
<aside className="sidebar">
<input
@@ -505,7 +505,7 @@ const Sidebar = ({
&& typeof document !== 'undefined'
? createPortal(
<div
className={`menu${showTenantList ? '' : ' menu--simple'}`}
className={menuClassName}
ref={tenantMenuRef}
role="menu"
aria-label="Account menu"
@@ -540,7 +540,7 @@ const Sidebar = ({
<div className="menu__footer">
<button
type="button"
className="menu__settings"
className="menu__button"
onClick={handleSettingsFromMenu}
>
<SettingsIcon size={16} />
@@ -548,13 +548,14 @@ const Sidebar = ({
</button>
<button
type="button"
className="menu__logout"
className="menu__button menu__button--danger"
onClick={handleLogoutFromMenu}
>
<LogoutIcon size={16} />
Log out
</button>
</div>
{themeMenuSection}
</div>,
document.body,
)
@@ -760,7 +761,6 @@ const Sidebar = ({
</ul>
</div>
</div>
{themeControls ? <div className="sidebar__footer">{themeControls}</div> : null}
</aside>
);
};
+79 -24
View File
@@ -200,12 +200,23 @@
color: var(--muted);
}
.sidebar__title-chevron {
transition: transform 0.2s ease;
.sidebar__title-button .sidebar__title-chevron {
opacity: 0;
transform: translateY(-1px);
transition:
opacity 0.12s ease,
transform 0.2s ease;
}
.sidebar__title-button:hover .sidebar__title-chevron,
.sidebar__title-button:focus-visible .sidebar__title-chevron,
.sidebar__title-chevron.is-open {
opacity: 1;
}
.sidebar__title-chevron.is-open {
transform: rotate(180deg);
transform: rotate(180deg) translateY(-1px);
}
.menu {
@@ -225,10 +236,10 @@
.menu__list {
max-height: 260px;
overflow-y: auto;
padding: 0.35rem 0;
padding: 0.35rem 0.5rem;
display: flex;
flex-direction: column;
gap: 0.15rem;
gap: 0.25rem;
}
.menu__heading {
@@ -238,17 +249,25 @@
color: var(--muted);
}
.menu__heading--with-actions {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
}
.menu button.menu__item,
.menu .menu__item {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 0.6rem;
gap: 0.5rem;
width: 100%;
padding: 0.55rem 1rem;
padding: 0.45rem 0.75rem;
border: none;
border-radius: 0.4rem;
background: none;
color: inherit;
color: var(--sidebar-fg);
font: inherit;
text-align: left;
cursor: pointer;
@@ -267,6 +286,7 @@
.menu .menu__item.active {
font-weight: 600;
color: var(--accent);
background: var(--accent-soft);
}
.menu button.menu__item:focus-visible,
@@ -313,7 +333,50 @@
border-top: none;
}
.menu__settings {
.menu__section {
border-top: 1px solid var(--border);
padding: 0.35rem 0;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.menu__heading-actions {
display: inline-flex;
gap: 0.35rem;
}
.menu__slider {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.8rem;
color: var(--muted);
padding: 0 1rem 0.25rem;
}
.menu__section > .menu__slider {
margin-top: -0.25rem;
}
.menu__slider input[type='range'] {
flex: 1;
accent-color: var(--accent);
}
.menu__slider-label {
min-width: 2.5rem;
}
.menu__slider-value {
font-variant-numeric: tabular-nums;
color: var(--fg);
min-width: 3rem;
text-align: right;
}
.menu__button {
width: 100%;
display: inline-flex;
align-items: center;
@@ -325,30 +388,22 @@
cursor: pointer;
padding: 0.4rem 0.5rem;
border-radius: 0.35rem;
transition: background 0.15s ease, color 0.15s ease;
}
.menu__settings:hover,
.menu__settings:focus-visible {
.menu__button:hover,
.menu__button:focus-visible {
background: var(--sidebar-hover-bg);
}
.menu__logout {
width: 100%;
display: inline-flex;
align-items: center;
gap: 0.4rem;
border: none;
background: none;
.menu__button--danger {
color: var(--danger);
font: inherit;
cursor: pointer;
padding: 0.4rem 0.5rem;
border-radius: 0.35rem;
}
.menu__logout:hover,
.menu__logout:focus-visible {
.menu__button--danger:hover,
.menu__button--danger:focus-visible {
background: var(--surface-danger-subtle);
color: var(--danger);
}
.sidebar__search {