Settings in tabs: localization, filters, interface, data
- Tabbed settings dialog (side navigation, 4-column tabs on mobile); the last opened tab is remembered. - Interface: theme System/Light/Dark (System follows the OS preference), log font size (tiny, small, medium, large) and log font: system monospace or 12 free monospace fonts loaded from Bunny Fonts, with a live preview. Ligatures disabled in log rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e583ab4b87
commit
84e71f741c
4 files changed
+276
-14
No files matched your search
@@ -61,14 +61,31 @@ Shortcuts: `/` focuses the search box, `Esc` clears it. Clicking a row shows all
|
||||
|
||||
## Settings
|
||||
|
||||
The gear icon opens the settings panel:
|
||||
The gear icon opens the settings, organized in tabs. Everything except color tags is
|
||||
remembered per browser.
|
||||
|
||||
- **Language**: English or French. The choice is remembered in the browser.
|
||||
- **Date & time**: time zone (browser zone, UTC, or about 80 common zones) and the display
|
||||
- **Localization**
|
||||
- *Language*: English or French.
|
||||
- *Date & time*: time zone (browser zone, UTC, or about 80 common zones) and the display
|
||||
format of the reception time: `DD/MM/YYYY HH:MM:SS` (default, the usual French display),
|
||||
with milliseconds, `YYYY-MM-DD`, 12-hour clock, ISO 8601 or Unix epoch. The time zone
|
||||
applies to every date shown. Remembered in the browser.
|
||||
- **Danger zone**: "Delete all logs" permanently erases every stored log (you must type
|
||||
applies to every date shown.
|
||||
- **Filters**: color tags. Each tag has a keyword, a background color (the text automatically
|
||||
switches to black or white to stay readable) and options: whole word, match case,
|
||||
regular expression, active. Tags are stored on the server in `/data/tags.json`
|
||||
(`logstream-data` volume), so they are shared by every browser. Default tags (pastel):
|
||||
`warning` (orange), `error` (red), `ok` (green). Default tags still using the colors of
|
||||
earlier versions are switched to the pastel ones automatically.
|
||||
- **Interface**
|
||||
- *Theme*: System (follows the computer/phone preference), Light or Dark. The sun/moon
|
||||
button in the header switches between light and dark.
|
||||
- *Log display*: font size (tiny, small, medium, large) and font: the system monospace
|
||||
font, or one of 12 free fonts made for dense text (JetBrains Mono, Fira Code, Source
|
||||
Code Pro, IBM Plex Mono, Cascadia Code, Roboto Mono, Ubuntu Mono, Inconsolata, Red Hat
|
||||
Mono, Noto Sans Mono, Victor Mono, DM Mono). They are loaded by the browser from
|
||||
[Bunny Fonts](https://fonts.bunny.net), a privacy-friendly European font service; without
|
||||
internet access, the system font is used. Ligatures are disabled so `->` or `!=` show as typed.
|
||||
- **Data**: "Delete all logs" permanently erases every stored log (you must type
|
||||
`PURGE` to confirm). Tags and settings are kept. VictoriaLogs needs `-delete.enable`
|
||||
(already set in `docker-compose.yml`); set `ALLOW_PURGE=false` to disable the feature.
|
||||
Anyone who can open the UI can purge: set `AUTH_USER` / `AUTH_PASS` if the UI is reachable
|
||||
|
||||
+133
-4
@@ -66,6 +66,14 @@ const I18N = {
|
||||
msgTimeTitle: 'Timestamp from the message',
|
||||
fHostName: 'host name (DNS)', fHostIp: 'host IP',
|
||||
clickHost: 'Click to filter on this host', clickApp: 'Click to filter on this app',
|
||||
tabLocale: 'Localization', tabFilters: 'Filters', tabInterface: 'Interface', tabData: 'Data',
|
||||
themeTitle: 'Theme', themeSystem: 'System', themeLight: 'Light', themeDark: 'Dark',
|
||||
themeHelp: 'System follows the light/dark preference of your computer or phone.',
|
||||
logDisplay: 'Log display', fontSize: 'Font size',
|
||||
sizeTiny: 'Tiny', sizeSmall: 'Small', sizeMedium: 'Medium', sizeLarge: 'Large',
|
||||
fontLabel: 'Font', fontSystem: 'System monospace (no download)',
|
||||
fontHelp: 'Free fonts (SIL Open Font License) loaded by your browser from Bunny Fonts, a privacy-friendly European font service. Without internet access, the system font is used.',
|
||||
previewMsgs: ['error: link down on eth1, carrier lost', 'warning: disk /dev/sda temperature 58°C', 'backup finished: ok (12.4 GB in 00:14:32)'],
|
||||
dangerZone: 'Danger zone',
|
||||
purgeHelp: 'Permanently delete every stored log to start from scratch. Color tags and settings are kept.',
|
||||
purgeBtn: 'Delete all logs…',
|
||||
@@ -141,6 +149,14 @@ const I18N = {
|
||||
msgTimeTitle: 'Horodatage contenu dans le message',
|
||||
fHostName: 'nom d\'hôte (DNS)', fHostIp: 'IP de l\'hôte',
|
||||
clickHost: 'Cliquer pour filtrer sur cet hôte', clickApp: 'Cliquer pour filtrer sur cette appli',
|
||||
tabLocale: 'Localisation', tabFilters: 'Filtres', tabInterface: 'Interface', tabData: 'Données',
|
||||
themeTitle: 'Thème', themeSystem: 'Système', themeLight: 'Clair', themeDark: 'Sombre',
|
||||
themeHelp: 'Système suit la préférence clair/sombre de votre ordinateur ou de votre téléphone.',
|
||||
logDisplay: 'Affichage des logs', fontSize: 'Taille du texte',
|
||||
sizeTiny: 'Très petite', sizeSmall: 'Petite', sizeMedium: 'Moyenne', sizeLarge: 'Grande',
|
||||
fontLabel: 'Police', fontSystem: 'Monospace du système (aucun téléchargement)',
|
||||
fontHelp: 'Polices libres (licence SIL Open Font) chargées par votre navigateur depuis Bunny Fonts, un service européen respectueux de la vie privée. Sans accès à internet, la police du système est utilisée.',
|
||||
previewMsgs: ['error: link down on eth1, carrier lost', 'warning: disk /dev/sda temperature 58°C', 'backup finished: ok (12.4 GB in 00:14:32)'],
|
||||
dangerZone: 'Zone de danger',
|
||||
purgeHelp: 'Supprime définitivement tous les logs stockés pour repartir de zéro. Les tags de couleur et les réglages sont conservés.',
|
||||
purgeBtn: 'Supprimer tous les logs…',
|
||||
@@ -333,6 +349,7 @@ function setLang(next) {
|
||||
renderTagList();
|
||||
renderTimeSettings();
|
||||
renderPurge();
|
||||
renderInterface();
|
||||
}
|
||||
|
||||
$('#langSwitch').addEventListener('click', (ev) => {
|
||||
@@ -347,10 +364,118 @@ function effectiveTheme() {
|
||||
if (th) return th;
|
||||
return matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
}
|
||||
$('#themeBtn').addEventListener('click', () => {
|
||||
const next = effectiveTheme() === 'dark' ? 'light' : 'dark';
|
||||
document.documentElement.dataset.theme = next;
|
||||
store.set('theme', next);
|
||||
// mode: 'system' (follow the OS), 'light' or 'dark'.
|
||||
function setTheme(mode) {
|
||||
if (mode === 'light' || mode === 'dark') document.documentElement.dataset.theme = mode;
|
||||
else { delete document.documentElement.dataset.theme; mode = 'system'; }
|
||||
store.set('theme', mode);
|
||||
renderThemeSwitch();
|
||||
}
|
||||
|
||||
function renderThemeSwitch() {
|
||||
const mode = document.documentElement.dataset.theme || 'system';
|
||||
for (const b of document.querySelectorAll('#themeSwitch [data-theme-opt]')) {
|
||||
b.setAttribute('aria-checked', String(b.dataset.themeOpt === mode));
|
||||
}
|
||||
}
|
||||
|
||||
// The header button switches between light and dark.
|
||||
$('#themeBtn').addEventListener('click', () => setTheme(effectiveTheme() === 'dark' ? 'light' : 'dark'));
|
||||
$('#themeSwitch').addEventListener('click', (ev) => {
|
||||
const b = ev.target.closest('[data-theme-opt]');
|
||||
if (b) setTheme(b.dataset.themeOpt);
|
||||
});
|
||||
|
||||
/* ================= Log font and size ================= */
|
||||
|
||||
// Free monospace fonts, served by Bunny Fonts (https://fonts.bunny.net).
|
||||
const LOG_FONTS = [
|
||||
{ id: 'system' },
|
||||
{ id: 'jetbrains-mono', family: 'JetBrains Mono' },
|
||||
{ id: 'fira-code', family: 'Fira Code' },
|
||||
{ id: 'source-code-pro', family: 'Source Code Pro' },
|
||||
{ id: 'ibm-plex-mono', family: 'IBM Plex Mono' },
|
||||
{ id: 'cascadia-code', family: 'Cascadia Code' },
|
||||
{ id: 'roboto-mono', family: 'Roboto Mono' },
|
||||
{ id: 'ubuntu-mono', family: 'Ubuntu Mono' },
|
||||
{ id: 'inconsolata', family: 'Inconsolata' },
|
||||
{ id: 'red-hat-mono', family: 'Red Hat Mono' },
|
||||
{ id: 'noto-sans-mono', family: 'Noto Sans Mono' },
|
||||
{ id: 'victor-mono', family: 'Victor Mono' },
|
||||
{ id: 'dm-mono', family: 'DM Mono', weights: '400,500' },
|
||||
];
|
||||
const LOG_SIZES = { tiny: '10.5px', small: '11.5px', medium: '12.5px', large: '14px' };
|
||||
const ui = { font: 'system', size: 'medium' };
|
||||
|
||||
function applyLogFont(id) {
|
||||
const f = LOG_FONTS.find((x) => x.id === id) || LOG_FONTS[0];
|
||||
ui.font = f.id;
|
||||
const root = document.documentElement.style;
|
||||
if (!f.family) {
|
||||
root.removeProperty('--log-font');
|
||||
return;
|
||||
}
|
||||
const href = `https://fonts.bunny.net/css?family=${f.id}:${f.weights || '400,700'}&display=swap`;
|
||||
let link = document.getElementById('logFontCss');
|
||||
if (!link) {
|
||||
link = Object.assign(document.createElement('link'), { id: 'logFontCss', rel: 'stylesheet' });
|
||||
document.head.append(link);
|
||||
}
|
||||
if (link.getAttribute('href') !== href) link.href = href;
|
||||
root.setProperty('--log-font', `'${f.family}', var(--mono)`);
|
||||
}
|
||||
|
||||
function applyLogSize(id) {
|
||||
ui.size = LOG_SIZES[id] ? id : 'medium';
|
||||
document.documentElement.style.setProperty('--log-size', LOG_SIZES[ui.size]);
|
||||
}
|
||||
|
||||
function renderInterface() {
|
||||
renderThemeSwitch();
|
||||
for (const b of document.querySelectorAll('#sizeSwitch [data-size]')) {
|
||||
b.setAttribute('aria-checked', String(b.dataset.size === ui.size));
|
||||
}
|
||||
const sel = $('#fontSelect');
|
||||
sel.innerHTML = LOG_FONTS.map((f) => `<option value="${f.id}">${esc(f.family || t('fontSystem'))}</option>`).join('');
|
||||
sel.value = ui.font;
|
||||
renderFontPreview();
|
||||
}
|
||||
|
||||
function renderFontPreview() {
|
||||
const now = new Date().toISOString();
|
||||
const [m1, m2, m3] = t('previewMsgs');
|
||||
const rows = [
|
||||
{ received: now, msg_time: now, severity: 'err', host: 'fw-edge', app: 'kernel', _msg: m1 },
|
||||
{ received: now, msg_time: now, severity: 'warning', host: 'nas', app: 'smartd', _msg: m2 },
|
||||
{ received: now, msg_time: now, severity: 'info', host: 'web-01', app: 'backup', _msg: m3 },
|
||||
];
|
||||
$('#fontPreview').innerHTML = rows.map((r) => rowHTML(r, false)).join('');
|
||||
}
|
||||
|
||||
$('#sizeSwitch').addEventListener('click', (ev) => {
|
||||
const b = ev.target.closest('[data-size]');
|
||||
if (!b) return;
|
||||
applyLogSize(b.dataset.size);
|
||||
store.set('logSize', ui.size);
|
||||
renderInterface();
|
||||
});
|
||||
$('#fontSelect').addEventListener('change', (ev) => {
|
||||
applyLogFont(ev.target.value);
|
||||
store.set('logFont', ui.font);
|
||||
});
|
||||
|
||||
/* ================= Settings tabs ================= */
|
||||
|
||||
function showSettingsTab(name) {
|
||||
const tabs = [...document.querySelectorAll('#setNav [data-tab]')];
|
||||
if (!tabs.some((b) => b.dataset.tab === name)) name = 'locale';
|
||||
for (const b of tabs) b.setAttribute('aria-selected', String(b.dataset.tab === name));
|
||||
for (const p of document.querySelectorAll('.set-panel')) p.hidden = p.dataset.panel !== name;
|
||||
store.set('settingsTab', name);
|
||||
}
|
||||
$('#setNav').addEventListener('click', (ev) => {
|
||||
const b = ev.target.closest('[data-tab]');
|
||||
if (b) showSettingsTab(b.dataset.tab);
|
||||
});
|
||||
|
||||
/* ================= Filters ================= */
|
||||
@@ -1014,7 +1139,9 @@ $('#resetTags').addEventListener('click', async () => {
|
||||
$('#settingsBtn').addEventListener('click', () => {
|
||||
renderTimeSettings();
|
||||
renderTagList();
|
||||
renderInterface();
|
||||
loadPurgeStatus();
|
||||
showSettingsTab(store.get('settingsTab', 'locale'));
|
||||
$('#settingsDlg').showModal();
|
||||
});
|
||||
$('#closeSettings').addEventListener('click', () => $('#settingsDlg').close());
|
||||
@@ -1028,6 +1155,8 @@ $('#settingsDlg').addEventListener('click', (ev) => { if (ev.target === ev.curre
|
||||
const fmt = store.get('timefmt', DEFAULT_TIME_FMT);
|
||||
timePrefs.fmt = TIME_FORMATS.some((f) => f.id === fmt) ? fmt : DEFAULT_TIME_FMT;
|
||||
}
|
||||
applyLogFont(store.get('logFont', 'system'));
|
||||
applyLogSize(store.get('logSize', 'medium'));
|
||||
applyLang();
|
||||
$('#range').value = store.get('range', '1h');
|
||||
if (!$('#range').value) $('#range').value = '1h';
|
||||
|
||||
+63
-3
@@ -10,7 +10,7 @@
|
||||
// Apply the saved theme and language before first paint to avoid a flash.
|
||||
try {
|
||||
var t = localStorage.getItem('logstream.theme');
|
||||
if (t) document.documentElement.dataset.theme = t;
|
||||
if (t === 'light' || t === 'dark') document.documentElement.dataset.theme = t;
|
||||
var l = localStorage.getItem('logstream.lang');
|
||||
if (l) document.documentElement.lang = l;
|
||||
} catch (e) {}
|
||||
@@ -87,7 +87,7 @@
|
||||
<span id="stats" class="muted"></span>
|
||||
</footer>
|
||||
|
||||
<dialog id="settingsDlg" aria-labelledby="settingsTitle">
|
||||
<dialog id="settingsDlg" class="settings" aria-labelledby="settingsTitle">
|
||||
<div class="dlg">
|
||||
<header>
|
||||
<h2 id="settingsTitle" data-i18n="settings">Settings</h2>
|
||||
@@ -96,6 +96,29 @@
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div class="set-body">
|
||||
<nav id="setNav" class="set-nav" role="tablist" aria-orientation="vertical">
|
||||
<button type="button" role="tab" data-tab="locale">
|
||||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/></svg>
|
||||
<span data-i18n="tabLocale">Localization</span>
|
||||
</button>
|
||||
<button type="button" role="tab" data-tab="filters">
|
||||
<svg viewBox="0 0 24 24"><path d="M3 12V4a1 1 0 0 1 1-1h8l9 9-9 9z"/><circle cx="8" cy="8" r="1.5"/></svg>
|
||||
<span data-i18n="tabFilters">Filters</span>
|
||||
</button>
|
||||
<button type="button" role="tab" data-tab="interface">
|
||||
<svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="12" rx="2"/><path d="M8 20h8M12 16v4"/></svg>
|
||||
<span data-i18n="tabInterface">Interface</span>
|
||||
</button>
|
||||
<button type="button" role="tab" data-tab="data">
|
||||
<svg viewBox="0 0 24 24"><ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v14c0 1.7 3.6 3 8 3s8-1.3 8-3V5M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3"/></svg>
|
||||
<span data-i18n="tabData">Data</span>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div class="set-panels">
|
||||
<!-- Localization -->
|
||||
<div class="set-panel" role="tabpanel" data-panel="locale">
|
||||
<section class="set-section">
|
||||
<h3 data-i18n="language">Language</h3>
|
||||
<div id="langSwitch" class="seg" role="radiogroup" data-i18n-aria="language">
|
||||
@@ -103,7 +126,6 @@
|
||||
<button type="button" role="radio" data-lang="fr">Français</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="set-section">
|
||||
<h3 data-i18n="dateTime">Date & time</h3>
|
||||
<div class="field-grid">
|
||||
@@ -115,7 +137,10 @@
|
||||
<p id="timePreview" class="time-preview"></p>
|
||||
<p class="muted small" data-i18n="timeHelp"></p>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Filters -->
|
||||
<div class="set-panel" role="tabpanel" data-panel="filters" hidden>
|
||||
<section class="set-section">
|
||||
<h3 data-i18n="tagsTitle">Color tags</h3>
|
||||
<p class="muted small" data-i18n="tagsHelp"></p>
|
||||
@@ -125,7 +150,39 @@
|
||||
<button id="resetTags" class="btn ghost" type="button" data-i18n="resetTags">Restore default tags</button>
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Interface -->
|
||||
<div class="set-panel" role="tabpanel" data-panel="interface" hidden>
|
||||
<section class="set-section">
|
||||
<h3 data-i18n="themeTitle">Theme</h3>
|
||||
<div id="themeSwitch" class="seg" role="radiogroup" data-i18n-aria="themeTitle">
|
||||
<button type="button" role="radio" data-theme-opt="system" data-i18n="themeSystem">System</button>
|
||||
<button type="button" role="radio" data-theme-opt="light" data-i18n="themeLight">Light</button>
|
||||
<button type="button" role="radio" data-theme-opt="dark" data-i18n="themeDark">Dark</button>
|
||||
</div>
|
||||
<p class="muted small hint" data-i18n="themeHelp"></p>
|
||||
</section>
|
||||
<section class="set-section">
|
||||
<h3 data-i18n="logDisplay">Log display</h3>
|
||||
<div class="field-grid">
|
||||
<span class="lbl" data-i18n="fontSize">Font size</span>
|
||||
<div id="sizeSwitch" class="seg" role="radiogroup" data-i18n-aria="fontSize">
|
||||
<button type="button" role="radio" data-size="tiny" data-i18n="sizeTiny">Tiny</button>
|
||||
<button type="button" role="radio" data-size="small" data-i18n="sizeSmall">Small</button>
|
||||
<button type="button" role="radio" data-size="medium" data-i18n="sizeMedium">Medium</button>
|
||||
<button type="button" role="radio" data-size="large" data-i18n="sizeLarge">Large</button>
|
||||
</div>
|
||||
<label for="fontSelect" data-i18n="fontLabel">Font</label>
|
||||
<select id="fontSelect" class="field"></select>
|
||||
</div>
|
||||
<div id="fontPreview" class="list preview-list" aria-hidden="true"></div>
|
||||
<p class="muted small" data-i18n="fontHelp"></p>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Data -->
|
||||
<div class="set-panel" role="tabpanel" data-panel="data" hidden>
|
||||
<section class="set-section danger">
|
||||
<h3 data-i18n="dangerZone">Danger zone</h3>
|
||||
<p class="muted small" data-i18n="purgeHelp"></p>
|
||||
@@ -135,6 +192,9 @@
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<div id="toast" class="toast" hidden></div>
|
||||
|
||||
+58
-2
@@ -25,6 +25,8 @@
|
||||
--tag-warning: #fdba74;
|
||||
--tag-warning-text: #111827;
|
||||
|
||||
--log-size: 12.5px; /* Settings > Interface > Font size */
|
||||
/* --log-font is set by Settings > Interface > Font (defaults to --mono) */
|
||||
--mono: ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", Menlo, Consolas, monospace;
|
||||
--sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
--radius: 10px;
|
||||
@@ -221,7 +223,8 @@ body.busy .progress::after {
|
||||
padding: 5px 14px 5px 11px;
|
||||
border-left: 3px solid transparent;
|
||||
border-bottom: 1px solid var(--border);
|
||||
font-family: var(--mono); font-size: 12.5px;
|
||||
font-family: var(--log-font, var(--mono)); font-size: var(--log-size);
|
||||
font-variant-ligatures: none; /* keep -> != etc. as typed */
|
||||
cursor: pointer;
|
||||
}
|
||||
.row:last-child { border-bottom: 0; }
|
||||
@@ -268,7 +271,7 @@ mark.hit { background: var(--hit); color: inherit; border-radius: 3px; padding:
|
||||
grid-column: 1 / -1;
|
||||
margin: 8px 0 4px; padding: 10px 12px;
|
||||
background: var(--panel-2); border-radius: 8px;
|
||||
cursor: auto; font-size: 12px;
|
||||
cursor: auto; font-size: calc(var(--log-size) - .5px);
|
||||
}
|
||||
.details dl { display: grid; grid-template-columns: max-content 1fr; gap: 3px 16px; margin: 0; }
|
||||
.details dt { color: var(--muted); }
|
||||
@@ -316,6 +319,45 @@ mark.hit { background: var(--hit); color: inherit; border-radius: 3px; padding:
|
||||
}
|
||||
|
||||
/* ---------- Settings dialog ---------- */
|
||||
dialog.settings {
|
||||
width: min(900px, calc(100vw - 32px));
|
||||
height: min(660px, calc(100vh - 64px)); max-height: none;
|
||||
}
|
||||
dialog.settings .dlg { display: flex; flex-direction: column; height: 100%; padding: 0; }
|
||||
dialog.settings .dlg > header { padding: 14px 16px 14px 22px; border-bottom: 1px solid var(--border); }
|
||||
.set-body { flex: 1; min-height: 0; display: grid; grid-template-columns: 200px minmax(0, 1fr); }
|
||||
.set-nav {
|
||||
display: flex; flex-direction: column; gap: 2px;
|
||||
padding: 12px 10px; border-right: 1px solid var(--border);
|
||||
background: color-mix(in srgb, var(--panel-2) 50%, transparent);
|
||||
}
|
||||
.set-nav button {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
height: 38px; padding: 0 12px; border: 0; border-radius: 9px;
|
||||
background: transparent; color: var(--muted); font-weight: 560; font-size: 13.5px; text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.set-nav button:hover { background: var(--panel-2); color: var(--text); }
|
||||
.set-nav button[aria-selected="true"] { background: var(--accent-soft); color: var(--accent); }
|
||||
.set-nav svg { width: 18px; height: 18px; flex: none; }
|
||||
.set-panels { overflow-y: auto; padding: 2px 24px 22px; }
|
||||
.set-panel > .set-section:first-child { margin-top: 16px; }
|
||||
.hint { margin-top: 8px !important; }
|
||||
.lbl { font-size: 13px; font-weight: 550; }
|
||||
.set-panel .preview-list { margin: 14px 0 10px; pointer-events: none; }
|
||||
.preview-list .row {
|
||||
cursor: default;
|
||||
grid-template-columns: max-content max-content minmax(0, max-content) minmax(0, 1fr);
|
||||
grid-template-areas: "rcv sev host app" "msg msg msg msg";
|
||||
gap: 3px 10px;
|
||||
}
|
||||
.preview-list .row time.rcv { grid-area: rcv; }
|
||||
.preview-list .row time.mt { display: none; }
|
||||
.preview-list .row .sev { grid-area: sev; }
|
||||
.preview-list .row .host { grid-area: host; }
|
||||
.preview-list .row .app { grid-area: app; display: block; }
|
||||
.preview-list .row .msg { grid-area: msg; }
|
||||
|
||||
dialog {
|
||||
width: min(720px, calc(100vw - 32px)); max-height: calc(100vh - 64px);
|
||||
padding: 0; border: 1px solid var(--border); border-radius: 14px;
|
||||
@@ -419,6 +461,20 @@ select.field:focus { outline: 0; border-color: var(--accent); box-shadow: 0 0 0
|
||||
.details dl { grid-template-columns: 1fr; }
|
||||
.details dt { margin-top: 4px; }
|
||||
.field-grid { grid-template-columns: 1fr; gap: 4px; }
|
||||
dialog.settings { height: calc(100vh - 24px); width: calc(100vw - 16px); }
|
||||
.set-body { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
|
||||
.set-nav {
|
||||
display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); padding: 6px;
|
||||
border-right: 0; border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.set-nav button {
|
||||
flex-direction: column; justify-content: center; height: auto; padding: 6px 2px; gap: 3px;
|
||||
font-size: 11.5px; text-align: center;
|
||||
}
|
||||
.set-nav button span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
|
||||
.set-panels { padding: 0 16px 18px; }
|
||||
#sizeSwitch { display: flex; }
|
||||
#sizeSwitch button { flex: 1; padding: 0 4px; white-space: nowrap; font-size: 12px; }
|
||||
.field-grid select { margin-bottom: 6px; }
|
||||
.status { padding: 6px 16px; }
|
||||
.tag-row { grid-template-columns: 38px 1fr 36px; }
|
||||
|
||||
Reference in new issue
Block a user