chore(front): apply biome formatter
This commit is contained in:
@@ -34,11 +34,11 @@
|
|||||||
/* ── Layout shell ──────────────────────────────────────────── */
|
/* ── Layout shell ──────────────────────────────────────────── */
|
||||||
/* Fluid sidebar: tracks viewport but clamped to a sane band. */
|
/* Fluid sidebar: tracks viewport but clamped to a sane band. */
|
||||||
--sidebar-width: clamp(220px, 18vw, 280px);
|
--sidebar-width: clamp(220px, 18vw, 280px);
|
||||||
--sidebar-width-min: 200px; /* resizable rail floor (Fase 1) */
|
--sidebar-width-min: 200px; /* resizable rail floor (Fase 1) */
|
||||||
--sidebar-width-max: 320px; /* resizable rail ceiling (Fase 1) */
|
--sidebar-width-max: 320px; /* resizable rail ceiling (Fase 1) */
|
||||||
--sidebar-width-collapsed: 72px; /* icon-rail mode (Fase 1) */
|
--sidebar-width-collapsed: 72px; /* icon-rail mode (Fase 1) */
|
||||||
--gutter: var(--space-6); /* shared topbar/content horizontal gutter (drops to 16px on phones) */
|
--gutter: var(--space-6); /* shared topbar/content horizontal gutter (drops to 16px on phones) */
|
||||||
--grid-card-min: 200px; /* min width of a grid card (tightens on phones) */
|
--grid-card-min: 200px; /* min width of a grid card (tightens on phones) */
|
||||||
|
|
||||||
/* ── Spacing — 4px grid ────────────────────────────────────── */
|
/* ── Spacing — 4px grid ────────────────────────────────────── */
|
||||||
/* Direct steps are multiples of 4; half-steps (0-5/1-5/2-5/3-5)
|
/* Direct steps are multiples of 4; half-steps (0-5/1-5/2-5/3-5)
|
||||||
@@ -88,18 +88,18 @@
|
|||||||
|
|
||||||
/* Modular size scale in rem (root = 16px) so it honors user zoom.
|
/* Modular size scale in rem (root = 16px) so it honors user zoom.
|
||||||
* --text-base (14px) is the app body default. */
|
* --text-base (14px) is the app body default. */
|
||||||
--text-2xs: 0.6875rem; /* 11px */
|
--text-2xs: 0.6875rem; /* 11px */
|
||||||
--text-xs: 0.75rem; /* 12px */
|
--text-xs: 0.75rem; /* 12px */
|
||||||
--text-sm: 0.8125rem; /* 13px */
|
--text-sm: 0.8125rem; /* 13px */
|
||||||
--text-base: 0.875rem; /* 14px */
|
--text-base: 0.875rem; /* 14px */
|
||||||
--text-md: 1rem; /* 16px */
|
--text-md: 1rem; /* 16px */
|
||||||
--text-lg: 1.125rem; /* 18px */
|
--text-lg: 1.125rem; /* 18px */
|
||||||
--text-xl: 1.25rem; /* 20px */
|
--text-xl: 1.25rem; /* 20px */
|
||||||
--text-2xl: 1.5rem; /* 24px */
|
--text-2xl: 1.5rem; /* 24px */
|
||||||
--text-3xl: 1.75rem; /* 28px */
|
--text-3xl: 1.75rem; /* 28px */
|
||||||
--text-4xl: 2rem; /* 32px */
|
--text-4xl: 2rem; /* 32px */
|
||||||
--text-5xl: 2.5rem; /* 40px */
|
--text-5xl: 2.5rem; /* 40px */
|
||||||
--text-6xl: 3rem; /* 48px */
|
--text-6xl: 3rem; /* 48px */
|
||||||
|
|
||||||
/* Line-heights (leading) — unitless ratios. */
|
/* Line-heights (leading) — unitless ratios. */
|
||||||
--leading-none: 1;
|
--leading-none: 1;
|
||||||
@@ -189,8 +189,8 @@
|
|||||||
/* ── Density — comfortable (default) vs compact ────────────── */
|
/* ── Density — comfortable (default) vs compact ────────────── */
|
||||||
/* Gated by html[data-density="compact"] below. Consumed by list rows
|
/* Gated by html[data-density="compact"] below. Consumed by list rows
|
||||||
* and controls in Fase 1. */
|
* and controls in Fase 1. */
|
||||||
--density-row-py: var(--space-3); /* 12px */
|
--density-row-py: var(--space-3); /* 12px */
|
||||||
--density-row-px: var(--space-3-5); /* 14px */
|
--density-row-px: var(--space-3-5); /* 14px */
|
||||||
--density-gap: var(--space-3);
|
--density-gap: var(--space-3);
|
||||||
--density-control-h: 40px;
|
--density-control-h: 40px;
|
||||||
|
|
||||||
@@ -218,14 +218,14 @@
|
|||||||
* an alias so no consumer breaks (migration to the canonical names → Fase 1).
|
* an alias so no consumer breaks (migration to the canonical names → Fase 1).
|
||||||
* Each tier clears WCAG AA 4.5:1 on #fff AND the page bg, light and dark. The
|
* Each tier clears WCAG AA 4.5:1 on #fff AND the page bg, light and dark. The
|
||||||
* muted/faint/placeholder tiers used to FAIL (2.3–4.0:1) and are now darkened. */
|
* muted/faint/placeholder tiers used to FAIL (2.3–4.0:1) and are now darkened. */
|
||||||
--color-text: light-dark(#2d3748, #e2e8f0); /* primary body */
|
--color-text: light-dark(#2d3748, #e2e8f0); /* primary body */
|
||||||
--color-text-heading: light-dark(#1e293b, #f1f5f9); /* headings */
|
--color-text-heading: light-dark(#1e293b, #f1f5f9); /* headings */
|
||||||
--color-text-secondary: light-dark(#475569, #cbd5e1); /* strong secondary */
|
--color-text-secondary: light-dark(#475569, #cbd5e1); /* strong secondary */
|
||||||
/* muted/subtle/faint converge: AA 4.5:1 on the grayish page/muted bgs AND
|
/* muted/subtle/faint converge: AA 4.5:1 on the grayish page/muted bgs AND
|
||||||
* on the lighter dark hover bg leaves only a narrow passing window. */
|
* on the lighter dark hover bg leaves only a narrow passing window. */
|
||||||
--color-text-muted: light-dark(#5e6a78, #9fadbe); /* muted */
|
--color-text-muted: light-dark(#5e6a78, #9fadbe); /* muted */
|
||||||
--color-text-subtle: light-dark(#5e6a78, #9fadbe); /* subtle */
|
--color-text-subtle: light-dark(#5e6a78, #9fadbe); /* subtle */
|
||||||
--color-text-faint: light-dark(#5e6a78, #9fadbe); /* faintest still-AA */
|
--color-text-faint: light-dark(#5e6a78, #9fadbe); /* faintest still-AA */
|
||||||
/* legacy aliases → one of the tiers above */
|
/* legacy aliases → one of the tiers above */
|
||||||
--color-text-dark: var(--color-text-secondary);
|
--color-text-dark: var(--color-text-secondary);
|
||||||
--color-text-dim: var(--color-text-secondary);
|
--color-text-dim: var(--color-text-secondary);
|
||||||
@@ -274,8 +274,7 @@
|
|||||||
radial-gradient(55% 55% at 95% 98%, var(--color-accent-glow), transparent 58%),
|
radial-gradient(55% 55% at 95% 98%, var(--color-accent-glow), transparent 58%),
|
||||||
radial-gradient(48% 48% at 88% 12%, var(--color-accent-glow-soft), transparent 55%),
|
radial-gradient(48% 48% at 88% 12%, var(--color-accent-glow-soft), transparent 55%),
|
||||||
radial-gradient(50% 45% at 6% 92%, var(--color-accent-glow-soft), transparent 55%),
|
radial-gradient(50% 45% at 6% 92%, var(--color-accent-glow-soft), transparent 55%),
|
||||||
radial-gradient(78% 64% at 50% 33%, var(--color-bg-surface), transparent 70%),
|
radial-gradient(78% 64% at 50% 33%, var(--color-bg-surface), transparent 70%), var(--color-bg-page);
|
||||||
var(--color-bg-page);
|
|
||||||
/* Desaturated fractal-noise grain — kills gradient banding and adds a
|
/* Desaturated fractal-noise grain — kills gradient banding and adds a
|
||||||
tactile, "expensive" film. No colour inside the data-URI (token-safe);
|
tactile, "expensive" film. No colour inside the data-URI (token-safe);
|
||||||
applied via a low-opacity overlay pseudo-element. */
|
applied via a low-opacity overlay pseudo-element. */
|
||||||
@@ -676,8 +675,8 @@ html[data-color-scheme="dark"] {
|
|||||||
/* Compact density — tighter rows/controls. Toggled by writing
|
/* Compact density — tighter rows/controls. Toggled by writing
|
||||||
* data-density="compact" on <html>; consumed by list/control CSS in Fase 1. */
|
* data-density="compact" on <html>; consumed by list/control CSS in Fase 1. */
|
||||||
html[data-density="compact"] {
|
html[data-density="compact"] {
|
||||||
--density-row-py: var(--space-2); /* 8px */
|
--density-row-py: var(--space-2); /* 8px */
|
||||||
--density-row-px: var(--space-2-5); /* 10px */
|
--density-row-px: var(--space-2-5); /* 10px */
|
||||||
--density-gap: var(--space-2);
|
--density-gap: var(--space-2);
|
||||||
--density-control-h: 32px;
|
--density-control-h: 32px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -389,7 +389,9 @@
|
|||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
color: var(--color-on-accent);
|
color: var(--color-on-accent);
|
||||||
/* Subtle halo lifts the active step off the connector track. */
|
/* Subtle halo lifts the active step off the connector track. */
|
||||||
box-shadow: 0 0 0 4px var(--color-accent-ring), 0 4px 12px var(--color-accent-shadow);
|
box-shadow:
|
||||||
|
0 0 0 4px var(--color-accent-ring),
|
||||||
|
0 4px 12px var(--color-accent-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-title {
|
.step-title {
|
||||||
|
|||||||
@@ -455,9 +455,7 @@ async function loadFiles(options = { insertHistory: true }) {
|
|||||||
? '<div class="skeleton-row"><div class="skeleton skeleton-icon"></div><div class="skeleton skeleton-line skeleton-line--medium"></div><div class="skeleton skeleton-line skeleton-line--short"></div></div>'
|
? '<div class="skeleton-row"><div class="skeleton skeleton-icon"></div><div class="skeleton skeleton-line skeleton-line--medium"></div><div class="skeleton skeleton-line skeleton-line--short"></div></div>'
|
||||||
: '<div class="skeleton-card"><div class="skeleton skeleton-thumb"></div><div class="skeleton skeleton-line skeleton-line--medium"></div><div class="skeleton skeleton-line skeleton-line--short"></div></div>';
|
: '<div class="skeleton-card"><div class="skeleton skeleton-thumb"></div><div class="skeleton skeleton-line skeleton-line--medium"></div><div class="skeleton skeleton-line skeleton-line--short"></div></div>';
|
||||||
const wrapper = isList ? 'files-skeleton' : 'files-grid-view files-skeleton';
|
const wrapper = isList ? 'files-skeleton' : 'files-grid-view files-skeleton';
|
||||||
ui.showError(
|
ui.showError(`<div class="${wrapper}" role="status" aria-busy="true" aria-label="${i18n.t('files.loading')}">${cell.repeat(8)}</div>`);
|
||||||
`<div class="${wrapper}" role="status" aria-busy="true" aria-label="${i18n.t('files.loading')}">${cell.repeat(8)}</div>`
|
|
||||||
);
|
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
// A temporary guard: _loadPage sets _loading itself, but we need to
|
// A temporary guard: _loadPage sets _loading itself, but we need to
|
||||||
|
|||||||
@@ -111,9 +111,7 @@ function initSidebarToggle() {
|
|||||||
// Trap Tab focus inside the open drawer (mobile).
|
// Trap Tab focus inside the open drawer (mobile).
|
||||||
sidebar.addEventListener('keydown', (e) => {
|
sidebar.addEventListener('keydown', (e) => {
|
||||||
if (e.key !== 'Tab' || !sidebar.classList.contains('open')) return;
|
if (e.key !== 'Tab' || !sidebar.classList.contains('open')) return;
|
||||||
const f = /** @type {NodeListOf<HTMLElement>} */ (
|
const f = /** @type {NodeListOf<HTMLElement>} */ (sidebar.querySelectorAll('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])'));
|
||||||
sidebar.querySelectorAll('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])')
|
|
||||||
);
|
|
||||||
if (!f.length) return;
|
if (!f.length) return;
|
||||||
const first = f[0];
|
const first = f[0];
|
||||||
const last = f[f.length - 1];
|
const last = f[f.length - 1];
|
||||||
|
|||||||
+2
-7
@@ -16,7 +16,7 @@ import { wopiEditor } from '../features/files/wopiEditor.js';
|
|||||||
import { recent } from '../features/library/recent.js';
|
import { recent } from '../features/library/recent.js';
|
||||||
import { buildBatchDownloadUrl } from '../utils/download.js';
|
import { buildBatchDownloadUrl } from '../utils/download.js';
|
||||||
import { positionMenu } from '../utils/menuPosition.js';
|
import { positionMenu } from '../utils/menuPosition.js';
|
||||||
import { loadFiles, filesView } from './filesView.js';
|
import { filesView, loadFiles } from './filesView.js';
|
||||||
import { updateHistory } from './main.js';
|
import { updateHistory } from './main.js';
|
||||||
import { activateFilesUI, switchToFilesSection, syncViewContainers } from './navigation.js';
|
import { activateFilesUI, switchToFilesSection, syncViewContainers } from './navigation.js';
|
||||||
import { app } from './state.js';
|
import { app } from './state.js';
|
||||||
@@ -1057,12 +1057,7 @@ const ui = {
|
|||||||
const active = btn.dataset.sortField === field;
|
const active = btn.dataset.sortField === field;
|
||||||
btn.classList.toggle('is-active', active);
|
btn.classList.toggle('is-active', active);
|
||||||
const colName = btn.querySelector('span')?.textContent || '';
|
const colName = btn.querySelector('span')?.textContent || '';
|
||||||
btn.setAttribute(
|
btn.setAttribute('aria-label', active ? `${colName}: ${reversed ? i18n.t('sort.desc', 'descending') : i18n.t('sort.asc', 'ascending')}` : colName);
|
||||||
'aria-label',
|
|
||||||
active
|
|
||||||
? `${colName}: ${reversed ? i18n.t('sort.desc', 'descending') : i18n.t('sort.asc', 'ascending')}`
|
|
||||||
: colName
|
|
||||||
);
|
|
||||||
const arrow = btn.querySelector('.list-header-sort__arrow');
|
const arrow = btn.querySelector('.list-header-sort__arrow');
|
||||||
if (arrow) {
|
if (arrow) {
|
||||||
arrow.classList.toggle('hidden', !active);
|
arrow.classList.toggle('hidden', !active);
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
* Isolates notification rendering policy from ui.js.
|
* Isolates notification rendering policy from ui.js.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { notifications } from '../core/notifications.js';
|
|
||||||
import { announce } from '../core/liveRegion.js';
|
import { announce } from '../core/liveRegion.js';
|
||||||
|
import { notifications } from '../core/notifications.js';
|
||||||
|
|
||||||
const uiNotifications = {
|
const uiNotifications = {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -47,8 +47,7 @@ const JUST_ADDED_KEY = '__oxicloud_just_added__';
|
|||||||
*/
|
*/
|
||||||
function gridMetaDate(value) {
|
function gridMetaDate(value) {
|
||||||
if (!value) return '';
|
if (!value) return '';
|
||||||
const date =
|
const date = value instanceof Date ? value : new Date(typeof value === 'number' && value < 1e12 ? value * 1000 : value);
|
||||||
value instanceof Date ? value : new Date(typeof value === 'number' && value < 1e12 ? value * 1000 : value);
|
|
||||||
if (Number.isNaN(date.getTime())) return '';
|
if (Number.isNaN(date.getTime())) return '';
|
||||||
const ageDays = (Date.now() - date.getTime()) / 86_400_000;
|
const ageDays = (Date.now() - date.getTime()) / 86_400_000;
|
||||||
return ageDays > 30 ? formatDateShort(value) : formatRelativeTime(value);
|
return ageDays > 30 ? formatDateShort(value) : formatRelativeTime(value);
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ function formatFileSize(bytes) {
|
|||||||
const k = 1024;
|
const k = 1024;
|
||||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
const num = new Intl.NumberFormat(i18n.getCurrentLocale(), { maximumFractionDigits: 2 }).format(
|
const num = new Intl.NumberFormat(i18n.getCurrentLocale(), { maximumFractionDigits: 2 }).format(bytes / k ** i);
|
||||||
bytes / k ** i
|
|
||||||
);
|
|
||||||
|
|
||||||
return `${num} ${sizes[i]}`;
|
return `${num} ${sizes[i]}`;
|
||||||
}
|
}
|
||||||
@@ -89,10 +87,7 @@ function formatDateShort(value) {
|
|||||||
*/
|
*/
|
||||||
function formatRelativeTime(value) {
|
function formatRelativeTime(value) {
|
||||||
if (!value) return '';
|
if (!value) return '';
|
||||||
const date =
|
const date = value instanceof Date ? value : new Date(typeof value === 'number' && value < 1e12 ? value * 1000 : value);
|
||||||
value instanceof Date
|
|
||||||
? value
|
|
||||||
: new Date(typeof value === 'number' && value < 1e12 ? value * 1000 : value);
|
|
||||||
if (Number.isNaN(date.getTime())) return String(value);
|
if (Number.isNaN(date.getTime())) return String(value);
|
||||||
const diffSec = Math.round((date.getTime() - Date.now()) / 1000);
|
const diffSec = Math.round((date.getTime() - Date.now()) / 1000);
|
||||||
const abs = Math.abs(diffSec);
|
const abs = Math.abs(diffSec);
|
||||||
|
|||||||
@@ -524,10 +524,7 @@ const OxiIcons = {
|
|||||||
'M384 96c0-35.3 28.7-64 64-64s64 28.7 64 64l0 32c0 17.7 14.3 32 32 32s32-14.3 32-32l0-32c0-70.7-57.3-128-128-128S320 25.3 320 96l0 64-160 0c-35.3 0-64 28.7-64 64l0 224c0 35.3 28.7 64 64 64l256 0c35.3 0 64-28.7 64-64l0-224c0-35.3-28.7-64-64-64l-32 0 0-64z'
|
'M384 96c0-35.3 28.7-64 64-64s64 28.7 64 64l0 32c0 17.7 14.3 32 32 32s32-14.3 32-32l0-32c0-70.7-57.3-128-128-128S320 25.3 320 96l0 64-160 0c-35.3 0-64 28.7-64 64l0 224c0 35.3 28.7 64 64 64l256 0c35.3 0 64-28.7 64-64l0-224c0-35.3-28.7-64-64-64l-32 0 0-64z'
|
||||||
],
|
],
|
||||||
|
|
||||||
'adjust': [
|
adjust: [512, 'M448 256c0-106-86-192-192-192l0 384c106 0 192-86 192-192zM0 256a256 256 0 1 1 512 0 256 256 0 1 1 -512 0z']
|
||||||
512,
|
|
||||||
'M448 256c0-106-86-192-192-192l0 384c106 0 192-86 192-192zM0 256a256 256 0 1 1 512 0 256 256 0 1 1 -512 0z'
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Icon CSS is now in /css/components/icons.css (loaded via main.css).
|
// Icon CSS is now in /css/components/icons.css (loaded via main.css).
|
||||||
|
|||||||
@@ -850,10 +850,7 @@ function initPasswordToggles() {
|
|||||||
const sync = () => {
|
const sync = () => {
|
||||||
const shown = input.type === 'text';
|
const shown = input.type === 'text';
|
||||||
btn.setAttribute('aria-pressed', String(shown));
|
btn.setAttribute('aria-pressed', String(shown));
|
||||||
btn.setAttribute(
|
btn.setAttribute('aria-label', shown ? i18n.t('auth.hidePassword', 'Hide password') : i18n.t('auth.showPassword', 'Show password'));
|
||||||
'aria-label',
|
|
||||||
shown ? i18n.t('auth.hidePassword', 'Hide password') : i18n.t('auth.showPassword', 'Show password')
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
sync();
|
sync();
|
||||||
btn.addEventListener('click', () => {
|
btn.addEventListener('click', () => {
|
||||||
@@ -930,9 +927,7 @@ function initPasswordMatch(passId, confirmId, indicatorId) {
|
|||||||
}
|
}
|
||||||
const ok = pass.value === confirmEl.value;
|
const ok = pass.value === confirmEl.value;
|
||||||
out.className = `auth-match show ${ok ? 'auth-match--ok' : 'auth-match--bad'}`;
|
out.className = `auth-match show ${ok ? 'auth-match--ok' : 'auth-match--bad'}`;
|
||||||
out.textContent = ok
|
out.textContent = ok ? i18n.t('auth.passwordsMatch', 'Passwords match') : i18n.t('auth.passwords_mismatch', "Passwords don't match");
|
||||||
? i18n.t('auth.passwordsMatch', 'Passwords match')
|
|
||||||
: i18n.t('auth.passwords_mismatch', "Passwords don't match");
|
|
||||||
};
|
};
|
||||||
pass.addEventListener('input', update);
|
pass.addEventListener('input', update);
|
||||||
confirmEl.addEventListener('input', update);
|
confirmEl.addEventListener('input', update);
|
||||||
@@ -1107,9 +1102,7 @@ if (isLoginPage && loginForm) {
|
|||||||
const username = inputVal('login-username');
|
const username = inputVal('login-username');
|
||||||
const password = inputVal('login-password');
|
const password = inputVal('login-password');
|
||||||
|
|
||||||
const loginSubmit = /** @type {HTMLButtonElement | null} */ (
|
const loginSubmit = /** @type {HTMLButtonElement | null} */ (document.getElementById('login-submit'));
|
||||||
document.getElementById('login-submit')
|
|
||||||
);
|
|
||||||
loginSubmit?.classList.add('is-loading');
|
loginSubmit?.classList.add('is-loading');
|
||||||
loginSubmit?.setAttribute('aria-busy', 'true');
|
loginSubmit?.setAttribute('aria-busy', 'true');
|
||||||
if (loginSubmit) loginSubmit.disabled = true;
|
if (loginSubmit) loginSubmit.disabled = true;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { getCsrfHeaders } from '../../core/csrf.js';
|
import { getCsrfHeaders } from '../../core/csrf.js';
|
||||||
import { installFetchInterceptor } from '../../core/fetchWrapper.js';
|
import { installFetchInterceptor } from '../../core/fetchWrapper.js';
|
||||||
import { i18n } from '../../core/i18n.js';
|
|
||||||
import { formatRelativeTime } from '../../core/formatters.js';
|
import { formatRelativeTime } from '../../core/formatters.js';
|
||||||
|
import { i18n } from '../../core/i18n.js';
|
||||||
import { oxiIconsInit } from '../../core/icons.js';
|
import { oxiIconsInit } from '../../core/icons.js';
|
||||||
import { resizeImageToDataUrl } from '../../utils/imageResize.js';
|
import { resizeImageToDataUrl } from '../../utils/imageResize.js';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user