From ebe57ef273e31268fd326beab7861861230db639 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Fri, 8 May 2026 11:52:52 +0200 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20Phase=205b=20=E2=80=94=20port?= =?UTF-8?q?=20four=20shared=20components=20to=20Vue=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CustomStatistic.vue and SettingListItem.vue are mechanical Vue.component → SFC ports. AppSidebar.vue: AD-Vue 4 dropped , so the five sidebar icons (dashboard/user/setting/tool/logout) live in a name→component map and render via . The legacy hack is replaced with a sibling fixed- position toggle button. Tab paths take basePath/requestUri as props instead of pulling them from Go template scope. TableSortable.vue: the biggest Vue 3 rewrite of this phase. - $listeners is gone — replaced by inheritAttrs: false + explicit attrs forwarding - scopedSlots: this.$scopedSlots collapsed into Vue 3's unified slots object — just iterate Object.keys(this.slots) and forward - Vue 2 h(tag, { props, on, scopedSlots }, children) → Vue 3 h(tag, { ...props, ...on }, slotsObject) - 'a-table' string → resolveComponent('a-table') so app.use(Antd) registration is honored - inject: ['sortable'] (Options API) → inject('sortable', null) (Composition API) inside the trigger child - beforeDestroy → beforeUnmount - customRow's return shape flattened (no nested props/on/class) Two intentional skips, documented in the migration doc: - aClientTable.html — slot fragments, not a component. Migrates inline with inbounds.html (new Phase 5f). - aPersianDatepicker.html — wraps a Persian-only third-party lib; defer until settings.html lands. Build verified with vite 8.0.11. Co-Authored-By: Claude Opus 4.7 --- docs/migrations/vue3-phase1-inventory.md | 27 +- frontend/src/components/AppSidebar.vue | 156 ++++++++++ frontend/src/components/CustomStatistic.vue | 27 ++ frontend/src/components/SettingListItem.vue | 31 ++ frontend/src/components/TableSortable.vue | 300 ++++++++++++++++++++ 5 files changed, 540 insertions(+), 1 deletion(-) create mode 100644 frontend/src/components/AppSidebar.vue create mode 100644 frontend/src/components/CustomStatistic.vue create mode 100644 frontend/src/components/SettingListItem.vue create mode 100644 frontend/src/components/TableSortable.vue diff --git a/docs/migrations/vue3-phase1-inventory.md b/docs/migrations/vue3-phase1-inventory.md index 7b9d4087..7aa96b18 100644 --- a/docs/migrations/vue3-phase1-inventory.md +++ b/docs/migrations/vue3-phase1-inventory.md @@ -108,7 +108,8 @@ Order chosen so that breakage is contained and we always have a working panel: - ✅ Phase 4 — first real page (login.html) ported - ⏳ Phase 5 — medium pages + modals - ✅ 5a — theme system (composable + ThemeSwitch / ThemeSwitchLogin); wired into login - - ⏳ 5b — remaining custom components + - ✅ 5b — CustomStatistic, SettingListItem, AppSidebar, TableSortable + - ⏳ 5c — index.html dashboard ### Phase 5a notes @@ -124,6 +125,30 @@ Order chosen so that breakage is contained and we always have a working panel: **Known gap:** the legacy `web/assets/css/custom.min.css` styles `body.dark` / `body.light` / `[data-theme="ultra-dark"]`. The new login page doesn't import that CSS, so toggling theme switches AD-Vue's own components but not the panel chrome (e.g. card backgrounds). The composable still toggles the body class so behavior is correct — visual fidelity is restored when we either port custom.css to the new build or import it directly. +### Phase 5b notes + +Migrated four components into `frontend/src/components/`: + +- **`CustomStatistic.vue`** — wraps `` with prefix/suffix slots. Trivial port; only change is `Vue.component(...)` → SFC. +- **`SettingListItem.vue`** — wraps `` with title/description/control slots and a `paddings` prop. Trivial port. +- **`AppSidebar.vue`** — main panel sidebar. Surfaces tabs (Dashboard / Inbounds / Settings / Xray / Logout) with icons and the theme switcher. Two key changes from the legacy: + - AD-Vue 4 dropped ``. Replaced with a name→component map (`{ dashboard: DashboardOutlined, ... }`) rendered via ``. + - `` `slot="handle"` (a non-standard prop in legacy AD-Vue 1) was replaced with a fixed-position toggle button rendered as a sibling. The drawer's `:visible` was renamed to `:open` per AD-Vue 4 conventions. + - Tab `key` paths and `requestUri` are passed in as props (parent page knows the basePath); the legacy embedded `{{ .base_path }}` directly via Go templating. +- **`TableSortable.vue`** — drag-to-reorder a-table wrapper. The biggest single Vue 3 / AD-Vue 4 rewrite in this phase: + - `$listeners` (Vue 2) is gone — replaced by `inheritAttrs: false` + `v-bind="$attrs"` style forwarding via the `attrs` setup return. + - `scopedSlots: this.$scopedSlots` → Vue 3 unifies all slots; just iterate `Object.keys(this.slots)` and forward. + - Render-function shape changed: Vue 2's `h(tag, { props, on, scopedSlots }, children)` → Vue 3's `h(tag, { ...props, ...on }, slotsObject)` where slot fns are passed as the third arg. + - `'a-table'` as a plain string → `resolveComponent('a-table')` so `app.use(Antd)` registration is honored. + - `inject: ['sortable']` (Options API) inside child component swapped for `inject('sortable', null)` (Composition API) since the trigger now uses `setup()`. + - `beforeDestroy` → `beforeUnmount` (Vue 3 lifecycle rename). + - `customRow`'s return shape flattened: Vue 2 nested `attrs/on/class` is now a flat object of attrs + listeners + class. + +**Skipped in 5b:** + +- **`aClientTable.html`** — *not actually a component*. It's a fragment of `