Simplify settings preferences layout
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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) => (
|
||||||
|
|||||||
24
src/app.css
24
src/app.css
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user