Skip to content

Commit 5c1af35

Browse files
committed
perf: perf some styles
1 parent 90038e5 commit 5c1af35

4 files changed

Lines changed: 144 additions & 68 deletions

File tree

‎ui/components/Settings/settingsPanel.vue‎

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -178,22 +178,24 @@ watch(
178178
class="min-w-0 flex-1 overflow-y-auto bg-(--app-surface-canvas) font-sans"
179179
:class="hasNativeTitlebarInset ? 'pt-10' : ''"
180180
>
181-
<div class="mx-auto w-full max-w-3xl px-5 pt-3 pb-6 sm:px-8 md:px-10 md:pb-8">
182-
<Transition name="settings-section" mode="out-in">
183-
<UPageHeader
184-
:key="activeSection?.key"
185-
:title="activeSection?.label"
186-
:description="activeSection?.description"
187-
:ui="{
188-
root: 'relative mb-8 border-0 py-0',
189-
wrapper: 'flex flex-col gap-0',
190-
title: 'text-2xl font-semibold tracking-tight text-highlighted',
191-
description: 'mt-1.5 text-sm text-muted'
192-
}"
193-
/>
194-
</Transition>
195-
196-
<slot />
181+
<div class="px-5 pt-3 pb-6 sm:px-8 md:px-10 md:pb-8">
182+
<div class="mx-auto w-full max-w-3xl">
183+
<Transition name="settings-section" mode="out-in">
184+
<UPageHeader
185+
:key="activeSection?.key"
186+
:title="activeSection?.label"
187+
:description="activeSection?.description"
188+
:ui="{
189+
root: 'relative mb-8 border-0 py-0',
190+
wrapper: 'flex flex-col gap-0',
191+
title: 'text-2xl font-semibold tracking-tight text-highlighted',
192+
description: 'mt-1.5 text-sm text-muted'
193+
}"
194+
/>
195+
</Transition>
196+
197+
<slot />
198+
</div>
197199
</div>
198200
</main>
199201
</div>

‎ui/components/Settings/settingsRow.vue‎

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
11
<script setup lang="ts">
2-
defineProps<{
3-
title: string;
4-
description?: string;
5-
}>();
2+
withDefaults(
3+
defineProps<{
4+
title: string;
5+
description?: string;
6+
fluid?: boolean;
7+
}>(),
8+
{
9+
fluid: false
10+
}
11+
);
612
</script>
713

814
<template>
9-
<div class="flex items-center justify-between gap-6 px-4 py-3 max-sm:flex-col max-sm:items-stretch max-sm:gap-2.5">
10-
<div class="min-w-0">
15+
<div
16+
class="flex justify-between px-4 py-3 max-sm:flex-col max-sm:items-stretch max-sm:gap-2.5"
17+
:class="fluid ? 'flex-wrap items-start gap-x-6 gap-y-2.5' : 'items-center gap-6'"
18+
>
19+
<div :class="fluid ? 'min-w-48 flex-1 basis-48' : 'min-w-0'">
1120
<p class="text-sm font-medium text-highlighted">{{ title }}</p>
1221
<p v-if="description" class="mt-0.5 text-xs leading-5 text-muted">{{ description }}</p>
1322
</div>
14-
<div class="flex shrink-0 items-center max-sm:w-full">
23+
<div class="flex items-center max-sm:w-full" :class="fluid ? 'min-w-56 flex-1 basis-56 justify-end' : 'shrink-0'">
1524
<slot />
1625
</div>
1726
</div>

‎ui/components/SideBar/profile.vue‎

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ const menuShortcutButtonUi = {
206206
const currentThemeAccent = computed(() => getThemePreset(currentThemePresetId.value)?.accent || "var(--theme-accent)");
207207
const themePaletteOpen = ref(false);
208208
const previewedThemePresetId = ref<ThemePresetId | null>(null);
209+
const palettePreviewArmed = ref(false);
210+
const PALETTE_PREVIEW_DELAY_MS = 300;
211+
let palettePreviewArmFrame = 0;
212+
let palettePreviewTimer: ReturnType<typeof setTimeout> | null = null;
209213
210214
const resolvedPaletteMode = computed<"light" | "dark">(() => {
211215
if (currentAppearanceMode.value === "light") return "light";
@@ -217,6 +221,38 @@ const visibleThemePresets = computed(() =>
217221
resolvedPaletteMode.value === "dark" ? DARK_THEME_PRESETS : LIGHT_THEME_PRESETS
218222
);
219223
224+
const handleProfileOpenAutoFocus = (event: Event) => {
225+
if (profileOpenedByPointer.value) event.preventDefault();
226+
profileOpenedByPointer.value = false;
227+
};
228+
229+
const handlePaletteOpenAutoFocus = (event: Event) => {
230+
event.preventDefault();
231+
};
232+
233+
const cancelPalettePreviewArm = () => {
234+
if (!palettePreviewArmFrame) return;
235+
cancelAnimationFrame(palettePreviewArmFrame);
236+
palettePreviewArmFrame = 0;
237+
};
238+
239+
const cancelPalettePreviewTimer = () => {
240+
if (!palettePreviewTimer) return;
241+
clearTimeout(palettePreviewTimer);
242+
palettePreviewTimer = null;
243+
};
244+
245+
const disarmPalettePreview = () => {
246+
cancelPalettePreviewArm();
247+
cancelPalettePreviewTimer();
248+
palettePreviewArmed.value = false;
249+
};
250+
251+
const armPalettePreview = () => {
252+
cancelPalettePreviewArm();
253+
palettePreviewArmed.value = true;
254+
};
255+
220256
watch(profileOpen, (open) => {
221257
if (!open) {
222258
themePaletteOpen.value = false;
@@ -225,24 +261,44 @@ watch(profileOpen, (open) => {
225261
});
226262
227263
watch(themePaletteOpen, (open) => {
228-
if (!open) restorePalettePreview();
229-
});
264+
if (!open) {
265+
disarmPalettePreview();
266+
restorePalettePreview();
267+
return;
268+
}
230269
231-
const handleProfileOpenAutoFocus = (event: Event) => {
232-
if (profileOpenedByPointer.value) event.preventDefault();
233-
profileOpenedByPointer.value = false;
234-
};
270+
disarmPalettePreview();
271+
palettePreviewArmFrame = requestAnimationFrame(() => {
272+
palettePreviewArmFrame = requestAnimationFrame(() => {
273+
palettePreviewArmFrame = 0;
274+
if (themePaletteOpen.value) palettePreviewArmed.value = true;
275+
});
276+
});
277+
});
235278
236279
const previewPalettePreset = (id: ThemePresetId) => {
237-
const preset = getThemePreset(id);
238-
if (!preset || !import.meta.client) return;
280+
if (!palettePreviewArmed.value) return;
281+
if (previewedThemePresetId.value === id) {
282+
cancelPalettePreviewTimer();
283+
return;
284+
}
239285
240-
previewedThemePresetId.value = id;
241-
document.documentElement.dataset.themePreset = id;
242-
applyPrimaryColor(preset.accent);
286+
cancelPalettePreviewTimer();
287+
palettePreviewTimer = setTimeout(() => {
288+
palettePreviewTimer = null;
289+
if (!palettePreviewArmed.value || !themePaletteOpen.value) return;
290+
291+
const preset = getThemePreset(id);
292+
if (!preset || !import.meta.client) return;
293+
294+
previewedThemePresetId.value = id;
295+
document.documentElement.dataset.themePreset = id;
296+
applyPrimaryColor(preset.accent);
297+
}, PALETTE_PREVIEW_DELAY_MS);
243298
};
244299
245300
function restorePalettePreview() {
301+
cancelPalettePreviewTimer();
246302
if (!previewedThemePresetId.value || !import.meta.client) return;
247303
248304
previewedThemePresetId.value = null;
@@ -830,6 +886,7 @@ onMounted(async () => {
830886
});
831887
832888
onBeforeUnmount(() => {
889+
disarmPalettePreview();
833890
restorePalettePreview();
834891
if (unlistenAuthUrlRef.value) unlistenAuthUrlRef.value();
835892
if (unlistenErrorPageRef.value) unlistenErrorPageRef.value();
@@ -1011,7 +1068,12 @@ onBeforeUnmount(() => {
10111068
</div>
10121069
<UPopover
10131070
v-model:open="themePaletteOpen"
1014-
:content="{ align: 'start', side: 'left', sideOffset: 8 }"
1071+
:content="{
1072+
align: 'start',
1073+
side: 'left',
1074+
sideOffset: 8,
1075+
onOpenAutoFocus: handlePaletteOpenAutoFocus
1076+
}"
10151077
:ui="{
10161078
content:
10171079
'w-56 max-h-80 overflow-y-auto rounded-xl bg-[var(--app-surface-overlay)] p-1.5 shadow-[var(--theme-shadow-soft)] ring-1 ring-[var(--app-border)] backdrop-blur-md'
@@ -1028,7 +1090,12 @@ onBeforeUnmount(() => {
10281090
</UButton>
10291091

10301092
<template #content>
1031-
<div class="space-y-0.5" @pointerleave="restorePalettePreview" @focusout="restorePalettePreview">
1093+
<div
1094+
class="space-y-0.5"
1095+
@pointermove="armPalettePreview"
1096+
@pointerleave="restorePalettePreview"
1097+
@focusout="restorePalettePreview"
1098+
>
10321099
<UButton
10331100
v-for="item in visibleThemePresets"
10341101
:key="item.id"

‎ui/pages/setting/appearance.vue‎

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,7 @@ const LIGHT_ACCENT_COLORS = [
3030
"#06b6d4",
3131
"#64748b",
3232
"#f43f5e",
33-
"#84cc16",
34-
"#6366f1",
35-
"#fbbf24",
36-
"#14b8a6"
33+
"#84cc16"
3734
];
3835
const DARK_ACCENT_COLORS = [
3936
"#34d399",
@@ -44,10 +41,7 @@ const DARK_ACCENT_COLORS = [
4441
"#67e8f9",
4542
"#94a3b8",
4643
"#fb7185",
47-
"#a3e635",
48-
"#818cf8",
49-
"#fcd34d",
50-
"#2dd4bf"
44+
"#a3e635"
5145
];
5246
5347
const { t } = useI18n();
@@ -360,14 +354,14 @@ watch(
360354
class="w-full sm:w-64"
361355
/>
362356
</SettingsRow>
363-
<SettingsRow :title="t('Common.PrimaryColor')" :description="t('Setting.PrimaryColorDescription')">
364-
<div class="flex flex-wrap items-center gap-2">
365-
<div class="flex flex-wrap items-center gap-1.5">
357+
<SettingsRow :title="t('Common.PrimaryColor')" :description="t('Setting.PrimaryColorDescription')" fluid>
358+
<div class="flex items-center justify-end gap-2">
359+
<div class="flex flex-wrap justify-end gap-1.5">
366360
<button
367361
v-for="color in LIGHT_ACCENT_COLORS"
368362
:key="color"
369363
type="button"
370-
class="size-4.5 rounded-full"
364+
class="size-4.5 shrink-0 rounded-full"
371365
:class="
372366
sameHex(lightAccentColor, color)
373367
? 'ring-2 ring-(--theme-accent) ring-offset-2 ring-offset-(--app-surface-card)'
@@ -379,14 +373,16 @@ watch(
379373
@click="lightAccentColor = color"
380374
/>
381375
</div>
382-
<ColorPicker v-model="lightAccentColor" compact />
383-
<UButton
384-
color="neutral"
385-
variant="ghost"
386-
size="xs"
387-
:label="t('Setting.ResetAccent')"
388-
@click="resetAccent('light')"
389-
/>
376+
<div class="flex shrink-0 items-center gap-1.5">
377+
<ColorPicker v-model="lightAccentColor" compact />
378+
<UButton
379+
color="neutral"
380+
variant="ghost"
381+
size="xs"
382+
:label="t('Setting.ResetAccent')"
383+
@click="resetAccent('light')"
384+
/>
385+
</div>
390386
</div>
391387
</SettingsRow>
392388
</SettingsGroup>
@@ -402,14 +398,14 @@ watch(
402398
class="w-full sm:w-64"
403399
/>
404400
</SettingsRow>
405-
<SettingsRow :title="t('Common.PrimaryColor')" :description="t('Setting.PrimaryColorDescription')">
406-
<div class="flex flex-wrap items-center gap-2">
407-
<div class="flex flex-wrap items-center gap-1.5">
401+
<SettingsRow :title="t('Common.PrimaryColor')" :description="t('Setting.PrimaryColorDescription')" fluid>
402+
<div class="flex items-center justify-end gap-2">
403+
<div class="flex flex-wrap justify-end gap-1.5">
408404
<button
409405
v-for="color in DARK_ACCENT_COLORS"
410406
:key="color"
411407
type="button"
412-
class="size-4.5 rounded-full"
408+
class="size-4.5 shrink-0 rounded-full"
413409
:class="
414410
sameHex(darkAccentColor, color)
415411
? 'ring-2 ring-(--theme-accent) ring-offset-2 ring-offset-(--app-surface-card)'
@@ -421,14 +417,16 @@ watch(
421417
@click="darkAccentColor = color"
422418
/>
423419
</div>
424-
<ColorPicker v-model="darkAccentColor" compact />
425-
<UButton
426-
color="neutral"
427-
variant="ghost"
428-
size="xs"
429-
:label="t('Setting.ResetAccent')"
430-
@click="resetAccent('dark')"
431-
/>
420+
<div class="flex shrink-0 items-center gap-1.5">
421+
<ColorPicker v-model="darkAccentColor" compact />
422+
<UButton
423+
color="neutral"
424+
variant="ghost"
425+
size="xs"
426+
:label="t('Setting.ResetAccent')"
427+
@click="resetAccent('dark')"
428+
/>
429+
</div>
432430
</div>
433431
</SettingsRow>
434432
</SettingsGroup>

0 commit comments

Comments
 (0)