A:增加初始页面和基础路由配置
This commit is contained in:
1 parent
f345fa3a80
commit
da2222f2d9
15 files changed
+965
-187
No files matched your search
@@ -1,85 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterLink, RouterView } from 'vue-router'
|
||||
import HelloWorld from './components/HelloWorld.vue'
|
||||
import { ref } from 'vue'
|
||||
import { NConfigProvider, NMessageProvider, NGlobalStyle, lightTheme } from 'naive-ui'
|
||||
import AppLayout from '@/components/Layout/AppLayout.vue'
|
||||
|
||||
const theme = ref(lightTheme)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
|
||||
|
||||
<div class="wrapper">
|
||||
<HelloWorld msg="You did it!" />
|
||||
|
||||
<nav>
|
||||
<RouterLink to="/">Home</RouterLink>
|
||||
<RouterLink to="/about">About</RouterLink>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<RouterView />
|
||||
<n-config-provider :theme="theme">
|
||||
<n-global-style />
|
||||
<n-message-provider>
|
||||
<AppLayout />
|
||||
</n-message-provider>
|
||||
</n-config-provider>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
header {
|
||||
line-height: 1.5;
|
||||
max-height: 100vh;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: block;
|
||||
margin: 0 auto 2rem;
|
||||
}
|
||||
|
||||
nav {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
nav a.router-link-exact-active {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
nav a.router-link-exact-active:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
nav a {
|
||||
display: inline-block;
|
||||
padding: 0 1rem;
|
||||
border-left: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
nav a:first-of-type {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
header {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
padding-right: calc(var(--section-gap) / 2);
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin: 0 2rem 0 0;
|
||||
}
|
||||
|
||||
header .wrapper {
|
||||
display: flex;
|
||||
place-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
nav {
|
||||
text-align: left;
|
||||
margin-left: -1rem;
|
||||
font-size: 1rem;
|
||||
|
||||
padding: 1rem 0;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,35 +1,5 @@
|
||||
@import './base.css';
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a,
|
||||
.green {
|
||||
text-decoration: none;
|
||||
color: hsla(160, 100%, 37%, 1);
|
||||
transition: 0.4s;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
a:hover {
|
||||
background-color: hsla(160, 100%, 37%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
*{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
<template>
|
||||
<n-layout class="layout-container">
|
||||
<!-- 头部 -->
|
||||
<n-layout-header bordered class="layout-header">
|
||||
<div class="header-content">
|
||||
<!-- 左侧 Logo 和标题 -->
|
||||
<div class="header-left">
|
||||
<n-icon size="32" class="logo-icon">
|
||||
<img src="@/assets/logo.svg" alt="logo" />
|
||||
</n-icon>
|
||||
<span class="site-title">标题</span>
|
||||
</div>
|
||||
|
||||
<!-- 中间搜索框 -->
|
||||
<div class="header-center">
|
||||
<n-input placeholder="搜索..." class="search-input" clearable>
|
||||
<template #prefix>
|
||||
<n-icon>
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"
|
||||
/>
|
||||
</svg>
|
||||
</n-icon>
|
||||
</template>
|
||||
</n-input>
|
||||
</div>
|
||||
|
||||
<!-- 右侧预留空间(可放用户信息等) -->
|
||||
<div class="header-right">
|
||||
<!-- 可以添加用户头像、设置按钮等 -->
|
||||
</div>
|
||||
</div>
|
||||
</n-layout-header>
|
||||
|
||||
<!-- 主体布局 -->
|
||||
<n-layout has-sider class="layout-body">
|
||||
<!-- 左侧导航栏 -->
|
||||
<n-layout-sider
|
||||
bordered
|
||||
show-trigger
|
||||
collapse-mode="width"
|
||||
:collapsed-width="64"
|
||||
:width="240"
|
||||
:native-scrollbar="false"
|
||||
class="layout-sider"
|
||||
>
|
||||
<n-menu
|
||||
v-model:value="activeKey"
|
||||
:collapsed-width="64"
|
||||
:collapsed-icon-size="22"
|
||||
:options="menuOptionsWithIcons"
|
||||
:root-indent="24"
|
||||
:indent="24"
|
||||
@update:value="handleMenuSelect"
|
||||
/>
|
||||
</n-layout-sider>
|
||||
|
||||
<!-- 主内容区域 -->
|
||||
<n-layout-content class="layout-content">
|
||||
<div class="content-wrapper">
|
||||
<router-view />
|
||||
</div>
|
||||
</n-layout-content>
|
||||
</n-layout>
|
||||
|
||||
<!-- 底部(暂时隐藏) -->
|
||||
<n-layout-footer v-if="false" bordered> Footer Footer Footer</n-layout-footer>
|
||||
</n-layout>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, h } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { NMenu, NIcon } from 'naive-ui'
|
||||
import {
|
||||
ImageOutline,
|
||||
SearchOutline,
|
||||
PeopleOutline,
|
||||
HeartOutline,
|
||||
LocationOutline,
|
||||
CalendarOutline,
|
||||
PricetagOutline,
|
||||
LibraryOutline,
|
||||
SettingsOutline,
|
||||
} from '@vicons/ionicons5'
|
||||
import { menuOptions, type MenuOption, type MenuItem, type MenuGroup } from '@/types/menu'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
// 图标映射
|
||||
const iconMap = {
|
||||
'image-outline': ImageOutline,
|
||||
'search-outline': SearchOutline,
|
||||
'people-outline': PeopleOutline,
|
||||
'heart-outline': HeartOutline,
|
||||
'location-outline': LocationOutline,
|
||||
'calendar-outline': CalendarOutline,
|
||||
'pricetag-outline': PricetagOutline,
|
||||
'library-outline': LibraryOutline,
|
||||
'settings-outline': SettingsOutline,
|
||||
}
|
||||
|
||||
// 渲染图标
|
||||
const renderIcon = (iconName: string) => {
|
||||
const IconComponent = iconMap[iconName as keyof typeof iconMap]
|
||||
return IconComponent ? () => h(NIcon, null, { default: () => h(IconComponent) }) : undefined
|
||||
}
|
||||
|
||||
// 转换菜单选项,添加图标渲染函数
|
||||
const menuOptionsWithIcons = computed(() => {
|
||||
return menuOptions.map((option: MenuOption) => {
|
||||
if ('children' in option) {
|
||||
// 分组菜单
|
||||
const group: MenuGroup = option
|
||||
return {
|
||||
key: group.key,
|
||||
label: group.label,
|
||||
type: 'group',
|
||||
children: group.children.map((child: MenuItem) => ({
|
||||
key: child.key,
|
||||
label: child.label,
|
||||
icon: child.icon ? renderIcon(child.icon) : undefined,
|
||||
})),
|
||||
}
|
||||
} else {
|
||||
// 普通菜单项
|
||||
const item: MenuItem = option
|
||||
return {
|
||||
key: item.key,
|
||||
label: item.label,
|
||||
icon: item.icon ? renderIcon(item.icon) : undefined,
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 当前激活的菜单项
|
||||
const activeKey = computed(() => {
|
||||
const currentPath = route.path
|
||||
// 从菜单选项中找到匹配当前路径的key
|
||||
for (const option of menuOptions) {
|
||||
if ('children' in option) {
|
||||
for (const child of option.children) {
|
||||
if (child.path === currentPath) {
|
||||
return child.key
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (option.path === currentPath) {
|
||||
return option.key
|
||||
}
|
||||
}
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
// 处理菜单选择
|
||||
const handleMenuSelect = (key: string) => {
|
||||
// 根据key找到对应的路径
|
||||
let targetPath = ''
|
||||
|
||||
for (const option of menuOptions) {
|
||||
if ('children' in option) {
|
||||
for (const child of option.children) {
|
||||
if (child.key === key) {
|
||||
targetPath = child.path
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (option.key === key) {
|
||||
targetPath = option.path
|
||||
break
|
||||
}
|
||||
}
|
||||
if (targetPath) break
|
||||
}
|
||||
|
||||
if (targetPath && targetPath !== route.path) {
|
||||
router.push(targetPath)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
:root {
|
||||
--header-height: 64px;
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
.layout-container {
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.layout-header {
|
||||
height: var(--header-height);
|
||||
padding: 0;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 24px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.logo-icon img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.site-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.header-center {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0 24px;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
flex-shrink: 0;
|
||||
min-width: 120px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.layout-body {
|
||||
height: calc(100vh - var(--header-height));
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.layout-sider {
|
||||
height: 100%;
|
||||
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.sidebar-menu {
|
||||
height: 100%;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.layout-content {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
padding: 24px;
|
||||
height: 100%;
|
||||
min-height: calc(100vh - 64px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.content-wrapper h1 {
|
||||
margin: 0 0 16px 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.content-wrapper p {
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.header-content {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.header-center {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.site-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
min-width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.search-input {
|
||||
max-width: 200px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,64 @@
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
|
||||
export function useLayout() {
|
||||
// 侧边栏是否展开
|
||||
const sidebarCollapsed = ref(false)
|
||||
|
||||
// 移动端断点
|
||||
const MOBILE_BREAKPOINT = 768
|
||||
|
||||
// 当前屏幕宽度
|
||||
const screenWidth = ref(window.innerWidth)
|
||||
|
||||
// 是否是移动端
|
||||
const isMobile = computed(() => screenWidth.value < MOBILE_BREAKPOINT)
|
||||
|
||||
// 移动端菜单抽屉是否显示
|
||||
const showMobileMenu = ref(false)
|
||||
|
||||
// 侧边栏宽度
|
||||
const sidebarWidth = computed(() => {
|
||||
if (isMobile.value) return 0
|
||||
return sidebarCollapsed.value ? 64 : 240
|
||||
})
|
||||
|
||||
// 监听窗口大小变化
|
||||
const handleResize = () => {
|
||||
screenWidth.value = window.innerWidth
|
||||
// 如果从移动端切换到桌面端,关闭移动端菜单
|
||||
if (!isMobile.value) {
|
||||
showMobileMenu.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 切换侧边栏展开/折叠
|
||||
const toggleSidebar = () => {
|
||||
if (isMobile.value) {
|
||||
showMobileMenu.value = !showMobileMenu.value
|
||||
} else {
|
||||
sidebarCollapsed.value = !sidebarCollapsed.value
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭移动端菜单
|
||||
const closeMobileMenu = () => {
|
||||
showMobileMenu.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
return {
|
||||
sidebarCollapsed,
|
||||
isMobile,
|
||||
showMobileMenu,
|
||||
sidebarWidth,
|
||||
toggleSidebar,
|
||||
closeMobileMenu
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,65 @@
|
||||
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'),
|
||||
// },
|
||||
// ],
|
||||
// })
|
||||
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: HomeView,
|
||||
redirect: '/photo'
|
||||
},
|
||||
{
|
||||
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'),
|
||||
path: '/photos',
|
||||
name: 'photos',
|
||||
component: () => import('@/views/PhotosView.vue'),
|
||||
meta: { title: '照片' }
|
||||
},
|
||||
],
|
||||
{
|
||||
path: '/search',
|
||||
name: 'search',
|
||||
component: () => import('@/views/SearchView.vue'),
|
||||
meta: { title: '搜索' }
|
||||
},
|
||||
{
|
||||
path: '/people',
|
||||
name: 'people',
|
||||
component: () => import('@/views/PeopleView.vue'),
|
||||
meta: { title: '人物' }
|
||||
},
|
||||
|
||||
{
|
||||
path: '/library',
|
||||
name: 'library',
|
||||
component: () => import('@/views/LibraryView.vue'),
|
||||
meta: { title: '资料库' }
|
||||
},
|
||||
{
|
||||
path: '/settings',
|
||||
name: 'settings',
|
||||
component: () => import('@/views/SettingsView.vue'),
|
||||
meta: { title: '设置' }
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
|
||||
export default router
|
||||
@@ -0,0 +1,88 @@
|
||||
// # 菜单类型定义
|
||||
export interface MenuItem {
|
||||
key: string
|
||||
label: string
|
||||
icon?: string
|
||||
path: string
|
||||
}
|
||||
|
||||
export interface MenuGroup {
|
||||
key: string
|
||||
label: string
|
||||
children: MenuItem[]
|
||||
}
|
||||
|
||||
export type MenuOption = MenuItem | MenuGroup
|
||||
|
||||
export const menuOptions: MenuOption[] = [
|
||||
// 默认分组菜单
|
||||
{
|
||||
key: 'photos',
|
||||
label: '照片',
|
||||
icon: 'image-outline',
|
||||
path: '/photos',
|
||||
},
|
||||
{
|
||||
key: 'search',
|
||||
label: '搜索',
|
||||
icon: 'search-outline',
|
||||
path: '/search',
|
||||
},
|
||||
{
|
||||
key: 'people',
|
||||
label: '人物',
|
||||
icon: 'people-outline',
|
||||
path: '/people',
|
||||
},
|
||||
// 媒体分组
|
||||
{
|
||||
key: 'media',
|
||||
label: '媒体',
|
||||
children: [],
|
||||
},
|
||||
|
||||
{
|
||||
key: 'favorites',
|
||||
label: '收藏',
|
||||
icon: 'heart-outline',
|
||||
path: '/favorites',
|
||||
},
|
||||
{
|
||||
key: 'places',
|
||||
label: '地点',
|
||||
icon: 'location-outline',
|
||||
path: '/places',
|
||||
},
|
||||
{
|
||||
key: 'calendar',
|
||||
label: '日历',
|
||||
icon: 'calendar-outline',
|
||||
path: '/calendar',
|
||||
},
|
||||
{
|
||||
key: 'tags',
|
||||
label: '标签',
|
||||
icon: 'pricetag-outline',
|
||||
path: '/tags',
|
||||
},
|
||||
|
||||
// 管理分组
|
||||
{
|
||||
key: 'management',
|
||||
label: '管理',
|
||||
children: [],
|
||||
},
|
||||
|
||||
{
|
||||
key: 'library',
|
||||
label: '资料库',
|
||||
icon: 'library-outline',
|
||||
path: '/library',
|
||||
},
|
||||
{
|
||||
key: 'settings',
|
||||
label: '设置',
|
||||
icon: 'settings-outline',
|
||||
path: '/settings',
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<h1>照片!!!!!11</h1>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style scoped>
|
||||
.page-container {
|
||||
padding: 24px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.page-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.page-content {
|
||||
/* 页面内容样式 */
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media (max-width: 767px) {
|
||||
.page-container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.page-actions {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>搜索!!</h1>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
Reference in new issue
Block a user