From 3ff0a64e89fa51766b55f84fd13a0027fc0143e5 Mon Sep 17 00:00:00 2001 From: Estrella Pan Date: Sat, 24 Jan 2026 07:37:50 +0100 Subject: [PATCH] feat(webui): mobile-first responsive redesign with 3-tier breakpoints Implement a comprehensive mobile-first UI redesign with touch-friendly navigation, responsive data display, and proper device adaptation. Key changes: - Add 3-tier breakpoint system: mobile (<640px), tablet (640-1023px), desktop (1024px+) - Create core mobile components: bottom-sheet, pull-refresh, swipe-container, data-list, adaptive-modal - Redesign navigation: bottom nav with labels on mobile, mini sidebar on tablet - Mobile-first layout with dvh units, safe area insets, and column-reverse flex - Forms stack labels vertically on mobile, inputs go full-width - Popups render as bottom sheets on mobile devices - Bangumi grid uses CSS Grid with responsive minmax columns - RSS page uses card-based data-list on mobile instead of NDataTable - Config actions get safe area padding and full-width buttons on mobile/tablet - Touch targets enforced at 44px minimum throughout - Add sheet/overlay/swipe CSS transitions - Topbar search visible on tablet (previously desktop-only) Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Co-Authored-By: Happy --- webui/index.html | 2 +- webui/src/components/ab-edit-rule.vue | 2 +- webui/src/components/ab-label.vue | 25 +- webui/src/components/ab-popup.vue | 15 +- webui/src/components/ab-setting.vue | 2 +- webui/src/components/ab-status-bar.vue | 34 +-- .../components/basic/ab-adaptive-modal.vue | 45 ++++ .../src/components/basic/ab-bottom-sheet.vue | 193 +++++++++++++++ webui/src/components/basic/ab-data-list.vue | 223 ++++++++++++++++++ .../src/components/basic/ab-pull-refresh.vue | 168 +++++++++++++ .../components/basic/ab-swipe-container.vue | 149 ++++++++++++ webui/src/components/layout/ab-mobile-nav.vue | 134 +++++++++++ webui/src/components/layout/ab-sidebar.vue | 108 ++++----- webui/src/components/layout/ab-topbar.vue | 35 +-- webui/src/components/media-query.vue | 11 +- webui/src/hooks/useBreakpointQuery.ts | 11 +- webui/src/hooks/useSafeArea.ts | 15 ++ webui/src/pages/index.vue | 29 +-- webui/src/pages/index/bangumi.vue | 30 ++- webui/src/pages/index/config.vue | 11 +- webui/src/pages/index/downloader.vue | 21 +- webui/src/pages/index/log.vue | 4 +- webui/src/pages/index/rss.vue | 69 +++++- webui/src/style/mixin.scss | 41 +++- webui/src/style/transition.scss | 66 ++++++ webui/src/style/var.scss | 21 +- webui/types/dts/auto-imports.d.ts | 1 + webui/types/dts/components.d.ts | 6 + webui/unocss.config.ts | 3 +- 29 files changed, 1336 insertions(+), 138 deletions(-) create mode 100644 webui/src/components/basic/ab-adaptive-modal.vue create mode 100644 webui/src/components/basic/ab-bottom-sheet.vue create mode 100644 webui/src/components/basic/ab-data-list.vue create mode 100644 webui/src/components/basic/ab-pull-refresh.vue create mode 100644 webui/src/components/basic/ab-swipe-container.vue create mode 100644 webui/src/components/layout/ab-mobile-nav.vue create mode 100644 webui/src/hooks/useSafeArea.ts diff --git a/webui/index.html b/webui/index.html index 6b8f6f66..58c562d9 100644 --- a/webui/index.html +++ b/webui/index.html @@ -2,7 +2,7 @@ - + diff --git a/webui/src/components/ab-edit-rule.vue b/webui/src/components/ab-edit-rule.vue index 07ed000c..878769f6 100644 --- a/webui/src/components/ab-edit-rule.vue +++ b/webui/src/components/ab-edit-rule.vue @@ -78,7 +78,7 @@ const boxSize = computed(() => {
{{ $t('homepage.rule.enable_hit') }}
diff --git a/webui/src/components/ab-label.vue b/webui/src/components/ab-label.vue index 4b551da8..f07ce032 100644 --- a/webui/src/components/ab-label.vue +++ b/webui/src/components/ab-label.vue @@ -24,14 +24,35 @@ const abLabel = computed(() => { diff --git a/webui/src/components/ab-popup.vue b/webui/src/components/ab-popup.vue index b51c9271..126f4183 100644 --- a/webui/src/components/ab-popup.vue +++ b/webui/src/components/ab-popup.vue @@ -20,6 +20,7 @@ const props = withDefaults( ); const show = defineModel('show', { default: false }); +const { isMobile } = useBreakpointQuery(); function close() { if (props.maskClick) { @@ -29,7 +30,19 @@ function close() {