mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-14 01:56:03 +00:00
feat(frontend): Phase 5c-i — index.html dashboard shell
Replaces the smoke-test App.vue with a real IndexPage shell so the /index.html route now boots the actual dashboard layout in Vue 3: - a-config-provider drives AD-Vue 4's dark algorithm from useTheme (same pattern as LoginPage) - AppSidebar (Phase 5b component) is wired in with basePath + requestUri props - a-spin loading state with placeholder card while we build out the rest of the page - Page palette mirrors the legacy: light #f0f2f5, dark #0a1222 (--dark-color-background), ultra-dark #21242a The 1,805-line legacy index.html is too big for one commit. Split into five sub-phases on the todo list: ii) status cards + /server/status polling, iii) xray status card, iv) logs/backup/panel-update modals, v) custom-geo section. frontend/src/App.vue and frontend/src/main.js (smoke-test scaffold) are removed — both purposes now served by IndexPage and index.js. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
4a98280519
commit
e24e70dde2
5 changed files with 115 additions and 80 deletions
|
|
@ -6,7 +6,8 @@
|
|||
<title>3x-ui</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="message"></div>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
<script type="module" src="/src/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { SizeFormatter, RandomUtil, Wireguard } from '@/utils';
|
||||
import { useMediaQuery } from '@/composables/useMediaQuery.js';
|
||||
|
||||
const message = ref('Vue 3 + Ant Design Vue 4 scaffold is alive');
|
||||
const count = ref(0);
|
||||
|
||||
const { isMobile } = useMediaQuery();
|
||||
|
||||
const fakeBytes = ref(1234567890);
|
||||
const formatted = computed(() => SizeFormatter.sizeFormat(fakeBytes.value));
|
||||
const uuid = ref(RandomUtil.randomUUID());
|
||||
const keypair = ref(Wireguard.generateKeypair());
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a-layout class="layout">
|
||||
<a-layout-header class="header">
|
||||
<h1>3x-ui (vue3-migration scaffold)</h1>
|
||||
<a-tag color="blue">isMobile: {{ isMobile }}</a-tag>
|
||||
</a-layout-header>
|
||||
<a-layout-content class="content">
|
||||
<a-space direction="vertical" :size="16" style="width: 100%">
|
||||
<a-alert :message="message" type="success" show-icon />
|
||||
<a-card title="Smoke test — toolchain">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="count++">Clicked {{ count }} times</a-button>
|
||||
<a-button @click="count = 0">Reset</a-button>
|
||||
</a-space>
|
||||
</a-card>
|
||||
<a-card title="Smoke test — utility imports">
|
||||
<p><strong>SizeFormatter:</strong> {{ formatted }}</p>
|
||||
<p><strong>RandomUtil.randomUUID:</strong> <code>{{ uuid }}</code></p>
|
||||
<p><strong>Wireguard public key:</strong> <code>{{ keypair.publicKey }}</code></p>
|
||||
<a-button @click="uuid = RandomUtil.randomUUID()">Regenerate UUID</a-button>
|
||||
</a-card>
|
||||
</a-space>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.layout {
|
||||
min-height: 100vh;
|
||||
}
|
||||
.header {
|
||||
background: #001529;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
.header h1 {
|
||||
color: #fff;
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
.content {
|
||||
padding: 24px;
|
||||
background: #f0f2f5;
|
||||
}
|
||||
code {
|
||||
background: rgba(0, 0, 0, 0.06);
|
||||
padding: 1px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
18
frontend/src/index.js
Normal file
18
frontend/src/index.js
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { createApp } from 'vue';
|
||||
import Antd, { message } from 'ant-design-vue';
|
||||
import 'ant-design-vue/dist/reset.css';
|
||||
|
||||
import { setupAxios } from '@/api/axios-init.js';
|
||||
// Importing useTheme triggers the boot side-effect that applies the
|
||||
// stored theme to <body>/<html> before Vue mounts.
|
||||
import '@/composables/useTheme.js';
|
||||
import IndexPage from '@/pages/index/IndexPage.vue';
|
||||
|
||||
setupAxios();
|
||||
|
||||
const messageContainer = document.getElementById('message');
|
||||
if (messageContainer) {
|
||||
message.config({ getContainer: () => messageContainer });
|
||||
}
|
||||
|
||||
createApp(IndexPage).use(Antd).mount('#app');
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { createApp } from 'vue';
|
||||
import Antd from 'ant-design-vue';
|
||||
import 'ant-design-vue/dist/reset.css';
|
||||
|
||||
import App from './App.vue';
|
||||
|
||||
const app = createApp(App);
|
||||
app.use(Antd);
|
||||
app.mount('#app');
|
||||
95
frontend/src/pages/index/IndexPage.vue
Normal file
95
frontend/src/pages/index/IndexPage.vue
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { theme as antdTheme } from 'ant-design-vue';
|
||||
|
||||
import { theme as themeState } from '@/composables/useTheme.js';
|
||||
import AppSidebar from '@/components/AppSidebar.vue';
|
||||
|
||||
// Drive AD-Vue 4's built-in dark algorithm from our reactive theme.
|
||||
const antdThemeConfig = computed(() => ({
|
||||
algorithm: themeState.isDark ? antdTheme.darkAlgorithm : antdTheme.defaultAlgorithm,
|
||||
}));
|
||||
|
||||
// Phase 5c-i ships the page shell only — sidebar, layout, theme.
|
||||
// Real content (CPU/mem/swap/disk cards, Xray status card, panel
|
||||
// update modal, logs, custom-geo section) follows in 5c-ii through
|
||||
// 5c-iv. Loading state is currently a placeholder true so the shell
|
||||
// renders; it will be wired to the real /server/status fetch later.
|
||||
const fetched = ref(true);
|
||||
|
||||
// In production the Go panel injects basePath + requestUri into the
|
||||
// served HTML; during `npm run dev` we infer them from window.location.
|
||||
const basePath = window.__X_UI_BASE_PATH__ || '';
|
||||
const requestUri = window.location.pathname;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a-config-provider :theme="antdThemeConfig">
|
||||
<a-layout class="index-page" :class="{ 'is-dark': themeState.isDark, 'is-ultra': themeState.isUltra }">
|
||||
<AppSidebar :base-path="basePath" :request-uri="requestUri" />
|
||||
|
||||
<a-layout class="content-shell">
|
||||
<a-layout-content class="content-area">
|
||||
<a-spin :spinning="!fetched" :delay="200" size="large">
|
||||
<div v-if="!fetched" class="loading-spacer" />
|
||||
|
||||
<div v-else class="page-body">
|
||||
<a-card hoverable>
|
||||
<a-space direction="vertical" :size="12" style="width: 100%">
|
||||
<h2 style="margin: 0">Dashboard (vue3-migration shell)</h2>
|
||||
<p style="margin: 0; opacity: 0.7">
|
||||
Phase 5c-i: layout, sidebar, and theme switching wired up.
|
||||
Status cards, xray controls, and custom-geo arrive in
|
||||
follow-up commits.
|
||||
</p>
|
||||
</a-space>
|
||||
</a-card>
|
||||
</div>
|
||||
</a-spin>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
</a-config-provider>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.index-page {
|
||||
/* Same legacy palette source as the login page. */
|
||||
--bg-page: #f0f2f5;
|
||||
--bg-card: #ffffff;
|
||||
|
||||
min-height: 100vh;
|
||||
background: var(--bg-page);
|
||||
}
|
||||
|
||||
.index-page.is-dark {
|
||||
--bg-page: #0a1222; /* legacy --dark-color-background */
|
||||
--bg-card: #151f31; /* legacy --dark-color-surface-100 */
|
||||
}
|
||||
|
||||
.index-page.is-dark.is-ultra {
|
||||
--bg-page: #21242a; /* legacy ultra --dark-color-background */
|
||||
--bg-card: #0c0e12; /* legacy ultra surface-100 */
|
||||
}
|
||||
|
||||
.index-page :deep(.ant-layout),
|
||||
.index-page :deep(.ant-layout-content) {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.content-shell {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.content-area {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.loading-spacer {
|
||||
min-height: calc(100vh - 120px);
|
||||
}
|
||||
|
||||
.page-body :deep(.ant-card) {
|
||||
background: var(--bg-card);
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in a new issue