feat: improve mobile responsiveness across UI

Sidenav becomes a full-screen overlay on mobile with slide-in animation.
Dialog goes full-screen on small screens. Settings dialog gets a mobile
nav with hamburger menu. Touch targets and text sizes scaled up for
mobile. Slider gets visual checked/unchecked colors. Sidebar auto-closes
on mobile route navigation. Resize handle hidden on mobile.
This commit is contained in:
Zoe
2026-04-27 12:06:15 -05:00
parent 8c2cefea49
commit 61c73f394d
13 changed files with 163 additions and 81 deletions
+45 -10
View File
@@ -39,6 +39,21 @@ const props = defineProps<{
const { close, setOptions } = useDialog();
const mobileNavOpen = ref(false);
onMounted(() => {
window.addEventListener('resize', () => {
if (window.innerWidth >= 768) {
mobileNavOpen.value = false;
}
})
});
const handleNavigate = (page: string, params?: string) => {
setOptions({ page: page as keyof typeof PAGES_CONFIG, params });
mobileNavOpen.value = false;
};
const runtimePage = computed(() => {
// 1. Get the base config (e.g., 'providers' or 'general')
const config = PAGES_CONFIG[props.page as keyof typeof PAGES_CONFIG] || PAGES_CONFIG.general;
@@ -70,13 +85,26 @@ const runtimePage = computed(() => {
</script>
<template>
<div class="p-2 flex h-[70vh] h-[70dvh] w-[85vw]">
<nav class="w-64 flex flex-col gap-1 mr-2 overflow-y-auto">
<!-- If the page has a custom sidebar (for nested lists), show it; otherwise show default nav -->
<component v-if="runtimePage?.sidebar" :is="runtimePage.sidebar"
@navigate="(p: string, params?: string) => setOptions({ page: p, params })" :params="props.params" />
<div class="p-2 flex flex-col md:flex-row h-screen md:h-[70vh] md:h-[70dvh] w-screen md:w-[85vw]">
<nav :class="[
'w-full md:w-64 flex-col gap-1 mr-2 overflow-y-auto text-xl md:text-base',
// Mobile: hidden by default, shown as fixed overlay
'hidden md:flex',
mobileNavOpen ? '!flex fixed inset-y-0 left-0 z-15 bg-[var(--bg-base)] p-2 shadow-xl' : ''
]">
<!-- Mobile close button -->
<button
class="md:hidden flex items-center justify-center h-9 w-full rounded-lg @hover:bg-[var(--color-hover)] text-[var(--text-secondary)]"
@click="mobileNavOpen = false">
<span class="i-mynaui-x-solid mr-2"></span>
Close
</button>
<button v-else v-for="(config, id) in PAGES_CONFIG" :key="id" @click="setOptions({ page: id })"
<!-- If the page has a custom sidebar (for nested lists), show it; otherwise show default nav -->
<component v-if="runtimePage?.sidebar" :is="runtimePage.sidebar" @navigate="handleNavigate"
:params="props.params" />
<button v-else v-for="(config, id) in PAGES_CONFIG" :key="id" @click="handleNavigate(id)"
:class="[page === id ? 'bg-[var(--color-hover)]' : '@hover:bg-[var(--color-hover)]', 'flex justify-between items-center shrink-0 px-1 rounded-lg transition-colors cursor-pointer h-9']">
<div class="flex items-center gap-2 max-w-full flex-1">
<span :class="['w-5 h-5 text-5', config.icon]"></span>
@@ -87,17 +115,24 @@ const runtimePage = computed(() => {
<!-- DYNAMIC CONTENT -->
<main
class="flex-1 flex flex-col overflow-y-hidden max-h-full h-full px-3 bg-[var(--bg-surface)] border rounded-lg border-[var(--color-border)]">
class="flex-1 flex flex-col overflow-y-hidden max-h-full h-full px-3 bg-[var(--bg-surface)] border rounded-none md:rounded-lg border-[var(--color-border)]">
<header class="flex items-center justify-between pl-2 pb-2 pt-2 ">
<h2 class="text-lg font-semibold m-0 case-capital">{{ runtimePage.label }}</h2>
<div class="flex items-center gap-2">
<!-- Mobile menu button -->
<button
class="md:hidden flex items-center justify-center h-8 w-8 rounded-lg @hover:bg-[var(--color-hover)]"
@click="mobileNavOpen = true">
<span class="i-mynaui-menu text-5"></span>
</button>
<h2 class="text-lg font-semibold m-0 case-capital">{{ runtimePage.label }}</h2>
</div>
<button
class="@hover:bg-[var(--color-hover)] p-1.5 rounded-md transition-colors duration-200 ease-[cubic-bezier(0,0.55,0.45,1)]"
@click="close">
<span class="i-mynaui-x-solid"></span>
</button>
</header>
<component @navigate="(p: string, params?: string) => setOptions({ page: p, params })"
:is="runtimePage.component" :params="props.params" />
<component @navigate="handleNavigate" :is="runtimePage.component" :params="props.params" />
</main>
</div>
</template>