Simplify settings preferences layout

This commit is contained in:
2026-04-02 01:04:12 +03:00
parent 760ab62c10
commit b3b097d265
4 changed files with 67 additions and 59 deletions

View File

@@ -31,4 +31,4 @@ Updated: 2026-04-02
15. Added editable System settings with shared validation, a system update API, service/port conflict protection, and UI coverage for local save flows. 15. Added editable System settings with shared validation, a system update API, service/port conflict protection, and UI coverage for local save flows.
16. Simplified the System tab layout by removing the redundant Runtime card and collapsing those fields into a compact settings section. 16. Simplified the System tab layout by removing the redundant Runtime card and collapsing those fields into a compact settings section.
17. Moved panel auth to server-issued expiring tokens with `sessionStorage` persistence and Compose-configurable credentials/TTL. 17. Moved panel auth to server-issued expiring tokens with `sessionStorage` persistence and Compose-configurable credentials/TTL.
18. Reworked Settings to store panel language/theme in `localStorage`, added RU/EN UI switching, and made service deletion warn before cascading linked-user removal. 18. Reworked Settings to store panel language/theme in `localStorage`, added RU/EN UI switching, made service deletion warn before cascading linked-user removal, and then simplified the preferences UI back into a compact inline strip with a light default theme.

View File

@@ -71,60 +71,54 @@ export default function SystemTab({
<> <>
<form className="system-editor" onSubmit={handleSubmit}> <form className="system-editor" onSubmit={handleSubmit}>
<section className="page-grid single-column system-grid"> <section className="page-grid single-column system-grid">
<article className="panel-card">
<div className="card-header">
<h2>{text.common.panelPreferences}</h2>
</div>
<div className="system-fields">
<label className="field-group">
{text.common.language}
<select
value={preferences.language}
onChange={(event) =>
onPreferencesChange({
...preferences,
language: event.target.value as PanelLanguage,
})
}
>
<option value="en">{text.common.english}</option>
<option value="ru">{text.common.russian}</option>
</select>
</label>
<label className="field-group">
{text.common.theme}
<select
value={preferences.theme}
onChange={(event) =>
onPreferencesChange({
...preferences,
theme: event.target.value as PanelTheme,
})
}
>
<option value="light">{getThemeLabel(preferences.language, 'light')}</option>
<option value="dark">{getThemeLabel(preferences.language, 'dark')}</option>
<option value="system">{getThemeLabel(preferences.language, 'system')}</option>
</select>
</label>
</div>
</article>
<article className="panel-card"> <article className="panel-card">
<div className="card-header"> <div className="card-header">
<h2>{text.settings.title}</h2> <h2>{text.settings.title}</h2>
<button <div className="settings-toolbar">
type="button" <label className="field-group compact-field">
className="button-secondary" <span>{text.common.language}</span>
onClick={() => <select
setDraft((current) => ({ value={preferences.language}
...current, onChange={(event) =>
services: [...current.services, createServiceDraft(current.services)], onPreferencesChange({
})) ...preferences,
} language: event.target.value as PanelLanguage,
> })
{text.common.addService} }
</button> >
<option value="en">{text.common.english}</option>
<option value="ru">{text.common.russian}</option>
</select>
</label>
<label className="field-group compact-field">
<span>{text.common.theme}</span>
<select
value={preferences.theme}
onChange={(event) =>
onPreferencesChange({
...preferences,
theme: event.target.value as PanelTheme,
})
}
>
<option value="light">{getThemeLabel(preferences.language, 'light')}</option>
<option value="dark">{getThemeLabel(preferences.language, 'dark')}</option>
<option value="system">{getThemeLabel(preferences.language, 'system')}</option>
</select>
</label>
<button
type="button"
className="button-secondary"
onClick={() =>
setDraft((current) => ({
...current,
services: [...current.services, createServiceDraft(current.services)],
}))
}
>
{text.common.addService}
</button>
</div>
</div> </div>
<div className="service-editor-list"> <div className="service-editor-list">
{draft.services.map((service, index) => ( {draft.services.map((service, index) => (

View File

@@ -450,6 +450,23 @@ button,
color: var(--muted); color: var(--muted);
} }
.settings-toolbar {
display: flex;
align-items: end;
gap: 12px;
flex-wrap: wrap;
}
.compact-field {
min-width: 220px;
flex: 0 1 240px;
}
.compact-field span {
color: var(--muted);
font-size: 12px;
}
.toolbar-actions { .toolbar-actions {
flex-wrap: wrap; flex-wrap: wrap;
} }
@@ -563,10 +580,6 @@ tbody tr:last-child td {
display: block; display: block;
} }
.system-settings-card {
gap: 12px;
}
.system-fields, .system-fields,
.service-editor-grid { .service-editor-grid {
display: grid; display: grid;
@@ -694,7 +707,8 @@ pre {
} }
.shell-header, .shell-header,
.table-toolbar { .table-toolbar,
.settings-toolbar {
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
} }

View File

@@ -6,11 +6,11 @@ export interface PanelPreferences {
theme: PanelTheme; theme: PanelTheme;
} }
const PREFERENCES_KEY = '3proxy-ui-panel-preferences'; const PREFERENCES_KEY = '3proxy-ui-panel-preferences-v2';
export const defaultPanelPreferences: PanelPreferences = { export const defaultPanelPreferences: PanelPreferences = {
language: 'en', language: 'en',
theme: 'system', theme: 'light',
}; };
export function loadPanelPreferences(): PanelPreferences { export function loadPanelPreferences(): PanelPreferences {