添加部分页面
This commit is contained in:
@@ -1,44 +0,0 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
msg: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="greetings">
|
||||
<h1 class="green">{{ msg }}</h1>
|
||||
<h3>
|
||||
You’ve successfully created a project with
|
||||
<a href="https://vite.dev/" target="_blank" rel="noopener">Vite</a> +
|
||||
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>.
|
||||
</h3>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h1 {
|
||||
font-weight: 500;
|
||||
font-size: 2.6rem;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.greetings h1,
|
||||
.greetings h3 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.greetings h1,
|
||||
.greetings h3 {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,87 +0,0 @@
|
||||
<script setup>
|
||||
import WelcomeItem from './WelcomeItem.vue'
|
||||
|
||||
const openReadmeInEditor = () => fetch('/__open-in-editor?file=README.md')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<DocumentationIcon />
|
||||
</template>
|
||||
<template #heading>Documentation</template>
|
||||
|
||||
Vue’s
|
||||
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
|
||||
provides you with all information you need to get started.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #heading>Tooling</template>
|
||||
|
||||
This project is served and bundled with
|
||||
<a href="https://vite.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
|
||||
recommended IDE setup is
|
||||
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a>
|
||||
+
|
||||
<a href="https://github.com/vuejs/language-tools" target="_blank" rel="noopener"
|
||||
>Vue - Official</a
|
||||
>. If you need to test your components and web pages, check out
|
||||
<a href="https://vitest.dev/" target="_blank" rel="noopener">Vitest</a>
|
||||
and
|
||||
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a>
|
||||
/
|
||||
<a href="https://playwright.dev/" target="_blank" rel="noopener">Playwright</a>.
|
||||
|
||||
<br />
|
||||
|
||||
More instructions are available in
|
||||
<a href="javascript:void(0)" @click="openReadmeInEditor"><code>README.md</code></a
|
||||
>.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<EcosystemIcon />
|
||||
</template>
|
||||
<template #heading>Ecosystem</template>
|
||||
|
||||
Get official tools and libraries for your project:
|
||||
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
|
||||
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
|
||||
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
|
||||
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
|
||||
you need more resources, we suggest paying
|
||||
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
|
||||
a visit.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<CommunityIcon />
|
||||
</template>
|
||||
<template #heading>Community</template>
|
||||
|
||||
Got stuck? Ask your question on
|
||||
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>
|
||||
(our official Discord server), or
|
||||
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
|
||||
>StackOverflow</a
|
||||
>. You should also follow the official
|
||||
<a href="https://bsky.app/profile/vuejs.org" target="_blank" rel="noopener">@vuejs.org</a>
|
||||
Bluesky account or the
|
||||
<a href="https://x.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
|
||||
X account for latest news in the Vue world.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<SupportIcon />
|
||||
</template>
|
||||
<template #heading>Support Vue</template>
|
||||
|
||||
As an independent project, Vue relies on community backing for its sustainability. You can help
|
||||
us by
|
||||
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
|
||||
</WelcomeItem>
|
||||
</template>
|
||||
@@ -1,86 +0,0 @@
|
||||
<template>
|
||||
<div class="item">
|
||||
<i>
|
||||
<slot name="icon"></slot>
|
||||
</i>
|
||||
<div class="details">
|
||||
<h3>
|
||||
<slot name="heading"></slot>
|
||||
</h3>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.item {
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.details {
|
||||
flex: 1;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
place-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.4rem;
|
||||
color: var(--color-heading);
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.item {
|
||||
margin-top: 0;
|
||||
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
|
||||
}
|
||||
|
||||
i {
|
||||
top: calc(50% - 25px);
|
||||
left: -26px;
|
||||
position: absolute;
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--color-background);
|
||||
border-radius: 8px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.item:before {
|
||||
content: ' ';
|
||||
border-left: 1px solid var(--color-border);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: calc(50% + 25px);
|
||||
height: calc(50% - 25px);
|
||||
}
|
||||
|
||||
.item:after {
|
||||
content: ' ';
|
||||
border-left: 1px solid var(--color-border);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: calc(50% + 25px);
|
||||
height: calc(50% - 25px);
|
||||
}
|
||||
|
||||
.item:first-of-type:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.item:last-of-type:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1
src/components/index/Leftbar.vue
Normal file
1
src/components/index/Leftbar.vue
Normal file
@@ -0,0 +1 @@
|
||||
<template></template>
|
||||
59
src/components/index/Loading.vue
Normal file
59
src/components/index/Loading.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
onMounted(() => {
|
||||
document.title = 'Loading...'
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div class="loading">
|
||||
<div class="title">DataBuddy</div>
|
||||
<div class="loading-bar">
|
||||
<div class="loading-line"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.loading {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
background-color: #fff;
|
||||
}
|
||||
.title {
|
||||
position: fixed;
|
||||
top: 45%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 48px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.loading-bar {
|
||||
position: fixed;
|
||||
top: 55%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 200px;
|
||||
height: 4px;
|
||||
background-color: #e0e0e0;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.loading-line {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: linear-gradient(90deg, transparent, #f472b6, transparent);
|
||||
background-size: 200% 100%;
|
||||
animation: loading 1.5s infinite linear;
|
||||
}
|
||||
@keyframes loading {
|
||||
0% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -100% 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
32
src/components/index/Topbar.vue
Normal file
32
src/components/index/Topbar.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<script setup>
|
||||
import getConfig from '@/utils/config'
|
||||
|
||||
const config = getConfig()
|
||||
</script>
|
||||
<template>
|
||||
<div class="topbar">
|
||||
<div class="logo" @click="router.push('/')">
|
||||
<img src="@/assets/logo.svg" alt="logo" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.topbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
background-color: rgba(255,255,255,0.2);
|
||||
backdrop-filter: blur(3px);
|
||||
}
|
||||
.logo {
|
||||
position: fixed;
|
||||
top: 6px;
|
||||
left: 10px;
|
||||
}
|
||||
.logo img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createApp, h } from 'vue'
|
||||
import NProgress from 'nprogress'
|
||||
import 'nprogress/nprogress.css'
|
||||
|
||||
@@ -14,26 +15,27 @@ const style = document.createElement('style')
|
||||
style.innerHTML = `
|
||||
#nprogress .bar {
|
||||
background: #f472b6 !important;
|
||||
height: 2px !important;
|
||||
height: 3px !important;
|
||||
box-shadow: 0 0 5px rgba(244, 114, 182, 0.7) !important;
|
||||
}
|
||||
#nprogress .peg {
|
||||
box-shadow: 0 0 15px #f472b6, 0 0 10px #f472b6 !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
#nprogress .spinner {
|
||||
display: none !important;
|
||||
}
|
||||
`
|
||||
document.head.appendChild(style)
|
||||
|
||||
let loadingApp = null;
|
||||
let loadingNode = null;
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
path: '/' || '/index.html',
|
||||
name: 'index',
|
||||
component: () => import('./views/Index.vue'),
|
||||
meta: { requiresIndexLoading: true },
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
@@ -43,13 +45,55 @@ const router = createRouter({
|
||||
],
|
||||
})
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
NProgress.start()
|
||||
next()
|
||||
})
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
if (!to.meta.requiresIndexLoading) {
|
||||
NProgress.start()
|
||||
}
|
||||
|
||||
router.afterEach(() => {
|
||||
NProgress.done()
|
||||
})
|
||||
if (to.meta.requiresIndexLoading) {
|
||||
NProgress.done()
|
||||
NProgress.remove()
|
||||
loadingNode = document.createElement('div');
|
||||
loadingNode.id = 'custom-loading';
|
||||
document.body.appendChild(loadingNode);
|
||||
|
||||
try {
|
||||
const LoadingComponent = (await import('@/components/index/Loading.vue')).default;
|
||||
|
||||
loadingApp = createApp({
|
||||
render: () => h(LoadingComponent)
|
||||
});
|
||||
|
||||
loadingApp.mount(loadingNode);
|
||||
} catch (error) {
|
||||
console.error('Failed to load custom loading component:', error);
|
||||
NProgress.start();
|
||||
document.body.removeChild(loadingNode);
|
||||
loadingNode = null;
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
router.afterEach((to) => {
|
||||
if (to.meta.requiresIndexLoading && loadingApp) {
|
||||
setTimeout(() => {
|
||||
if (loadingApp) {
|
||||
loadingApp.unmount();
|
||||
loadingApp = null;
|
||||
}
|
||||
|
||||
if (loadingNode && document.body.contains(loadingNode)) {
|
||||
document.body.removeChild(loadingNode);
|
||||
loadingNode = null;
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
if (!to.meta.requiresIndexLoading && NProgress.isStarted()) {
|
||||
NProgress.done();
|
||||
}
|
||||
});
|
||||
|
||||
export default router
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import HomeView from '../views/HomeView.vue'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: HomeView,
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
name: 'about',
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (About.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () => import('../views/AboutView.vue'),
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -1,5 +1,22 @@
|
||||
<script setup>
|
||||
import { onMounted, defineAsyncComponent } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import getConfig from '@/utils/config'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const config = getConfig()
|
||||
|
||||
const Topbar = defineAsyncComponent(() => import('@/components/index/Topbar.vue'))
|
||||
const Leftbar = defineAsyncComponent(() => import('@/components/index/Leftbar.vue'))
|
||||
|
||||
onMounted(() => {
|
||||
document.title = config.title
|
||||
document.body.style.background = "url('"+config.backgroundImg+"') no-repeat center center fixed"
|
||||
document.body.style.backgroundSize = "cover"
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<main>
|
||||
<h1>Welcome to DataBuddy</h1>
|
||||
</main>
|
||||
</template>
|
||||
<Topbar />
|
||||
<Leftbar />
|
||||
</template>
|
||||
@@ -1,15 +1,27 @@
|
||||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import getConfig from '@/utils/config'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const config = getConfig()
|
||||
|
||||
onMounted(() => {
|
||||
document.title = '页面未找到 - ' + config.title
|
||||
document.body.style.backgroundColor = '#000'
|
||||
document.body.style.color = '#fff'
|
||||
document.body.style.background = "url('"+config.backgroundImg+"') no-repeat center center fixed"
|
||||
document.body.style.backgroundSize = "cover"
|
||||
|
||||
const linkElement = document.createElement('link');
|
||||
linkElement.rel = 'stylesheet';
|
||||
|
||||
if (config.cdnUrl && config.cdnUrl !== "") {
|
||||
linkElement.href = `${config.cdnUrl}/assets/font-awesome/css/all.min.css`;
|
||||
} else {
|
||||
linkElement.href = '@/assets/font-awesome/css/all.min.css';
|
||||
}
|
||||
|
||||
document.head.appendChild(linkElement);
|
||||
|
||||
if (window.gtag) {
|
||||
window.gtag('event', 'page_view', {
|
||||
@@ -20,5 +32,106 @@ onMounted(() => {
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<h1>404 - Page Not Found</h1>
|
||||
</template>
|
||||
<div class="container">
|
||||
<i class="fa-solid fa-ban"></i>
|
||||
<div class="right-container">
|
||||
<h1>页面未找到</h1>
|
||||
<p>抱歉,您正在寻找的页面不存在。</p>
|
||||
<button class="go-home-button" @click="router.push('/')">
|
||||
<i class="fa-solid fa-arrow-left"></i>
|
||||
<span class="go-home-button-text">返回首页</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.container {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
border-radius: 20px;
|
||||
backdrop-filter: blur(3px);
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.2);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.container i {
|
||||
position: absolute;
|
||||
font-size: 256px;
|
||||
color: #000;
|
||||
left: 32px;
|
||||
}
|
||||
.right-container {
|
||||
position: absolute;
|
||||
width: calc(100% - 416px);
|
||||
right: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
.right-container h1,
|
||||
.right-container p {
|
||||
padding: 8px;
|
||||
}
|
||||
.go-home-button {
|
||||
height: 48px;
|
||||
width: 210px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
border: 0.1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 16px;
|
||||
backdrop-filter: blur(3px);
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
cursor: pointer;
|
||||
}
|
||||
.go-home-button i {
|
||||
position: absolute;
|
||||
font-size: 18px;
|
||||
left: 12px;
|
||||
bottom: 14px;
|
||||
}
|
||||
.go-home-button .go-home-button-text {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
bottom: 11px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.go-home-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
.go-home-button:active {
|
||||
background-color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
width: 90%;
|
||||
height: 95%;
|
||||
}
|
||||
.container i {
|
||||
font-size: 128px;
|
||||
left: auto;
|
||||
top: 64px;
|
||||
}
|
||||
.right-container {
|
||||
width: 100%;
|
||||
height: calc(100% - 256px);
|
||||
right: 0;
|
||||
bottom: 32px;
|
||||
}
|
||||
.go-home-button i {
|
||||
font-size: 18px;
|
||||
left: 12px;
|
||||
top: 14px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.container-404 {
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user