refactor: remove React dependencies and streamline Vite configuration for Vue application
parent
c49a9aa6c3
commit
312f82a5b6
|
@ -20,8 +20,6 @@
|
|||
"@wdns/vue-code-block": "^2.3.3",
|
||||
"clsx": "^2.1.1",
|
||||
"cookies": "^0.9.1",
|
||||
"react": "18",
|
||||
"react-dom": "18",
|
||||
"uuid": "^10.0.0",
|
||||
"vue": "^3.4.34",
|
||||
"vue-router": "^4.4.0"
|
||||
|
@ -35,9 +33,6 @@
|
|||
"@tailwindcss/vite": "^4.1.3",
|
||||
"@types/cookies": "^0.9.0",
|
||||
"@types/node": "^20.0.0",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"@vitejs/plugin-vue": "^5.1.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"tailwindcss": "^4.1.3",
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<div class="flex h-screen" :class="pageClass">
|
||||
<TheNavbar v-if="!hideNavbar" :items="navs"></TheNavbar>
|
||||
<div class="flex-1 justify-center px-4 py-16" :class="contentClass">
|
||||
<RouterView></RouterView>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { provideLayoutOptions } from '@/composables/layout'
|
||||
import { computed, ref } from 'vue'
|
||||
import TheNavbar from './TheNavbar.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
navs: { name: string; path: string }[]
|
||||
hideNavbar?: boolean
|
||||
hideBreadcrumbs?: boolean
|
||||
}>()
|
||||
|
||||
const pageClass = ref<string>()
|
||||
const contentClass = ref<string>()
|
||||
|
||||
provideLayoutOptions({
|
||||
pageClass,
|
||||
contentClass,
|
||||
hideNavbar: computed(() => props.hideNavbar),
|
||||
hideBreadcrumbs: computed(() => props.hideBreadcrumbs),
|
||||
})
|
||||
</script>
|
|
@ -0,0 +1,25 @@
|
|||
<template>
|
||||
<div class="flex flex-wrap gap-8 px-8">
|
||||
<RouterLink v-for="item in items" :key="item.path" :to="item.path">
|
||||
<div
|
||||
class="shadow-xs relative flex w-72 flex-col rounded-lg bg-primary capitalize text-primary-content transition-all hover:scale-105 hover:shadow-xl"
|
||||
>
|
||||
<div className="flex-col gap-2 flex flex-auto p-4 text-sm items-center text-center">
|
||||
<h2 className="font-semibold flex items-center gap-2 text-xl mb-1">
|
||||
{{ item.name }}
|
||||
</h2>
|
||||
<div className="flex flex-wrap items-start gap-2 justify-end">
|
||||
<ArrowRightIcon class="size-5" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ArrowRightIcon } from '@heroicons/vue/20/solid'
|
||||
|
||||
defineProps<{
|
||||
items: { name: string; path: string }[]
|
||||
}>()
|
||||
</script>
|
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<div class="max-w-full select-none overflow-x-auto px-4 py-2 text-sm">
|
||||
<ul class="flex min-h-min items-center whitespace-nowrap capitalize">
|
||||
<template v-for="(item, i) in items" :key="item.path">
|
||||
<li class="flex items-center">
|
||||
<template v-if="i > 0">
|
||||
<span
|
||||
class="ml-2 mr-3 block size-1.5 rotate-45 transform border-r-[1px] border-t-[1px] border-base-content/70 bg-transparent"
|
||||
></span>
|
||||
</template>
|
||||
<template v-if="item.path !== route.path">
|
||||
<RouterLink class="flex items-center hover:underline" :to="item.path">
|
||||
{{ item.name }}
|
||||
</RouterLink>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="text-base-content/70">{{ item.name }}</span>
|
||||
</template>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
defineProps<{ items: { name: string; path: string }[] }>()
|
||||
const route = useRoute()
|
||||
</script>
|
|
@ -0,0 +1,44 @@
|
|||
<template>
|
||||
<div class="bg-base-100/90 text-base-content border-base-content/10 border-r">
|
||||
<div class="flex min-h-16 w-full items-center p-2">
|
||||
<div class="justify-start">
|
||||
<div class="group relative inline-block">
|
||||
<ul
|
||||
tabindex="0"
|
||||
class="bg-base-100 z-[1] mt-3 flex w-52 origin-top scale-95 flex-col flex-wrap rounded-lg p-2 text-sm capitalize"
|
||||
>
|
||||
<li v-for="item in items" :key="item.name">
|
||||
<RouterLink
|
||||
:aria-disabled="item.path === route.path"
|
||||
:to="item.path"
|
||||
@click.stop="$event.currentTarget.blur()"
|
||||
class="hover:bg-base-content/10 flex cursor-pointer flex-col rounded-lg px-3 py-2 transition duration-200"
|
||||
>
|
||||
{{ item.name }}
|
||||
</RouterLink>
|
||||
<ul v-if="item.children">
|
||||
<li v-for="child in item.children" :key="child.name">
|
||||
<RouterLink
|
||||
:to="child.path"
|
||||
@click.stop="$event.currentTarget.blur()"
|
||||
class="hover:bg-base-content/10 flex cursor-pointer flex-col rounded-lg px-3 py-2 text-xs opacity-80 transition duration-200"
|
||||
>
|
||||
{{ child.name }}
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
defineProps<{
|
||||
items: { name: string; path: string; children?: { name: string; path: string }[] }[]
|
||||
}>()
|
||||
const route = useRoute()
|
||||
</script>
|
|
@ -0,0 +1,22 @@
|
|||
import { inject, InjectionKey, provide, Ref } from 'vue'
|
||||
|
||||
export interface LayoutOptions {
|
||||
pageClass: Ref<string | undefined>
|
||||
contentClass: Ref<string | undefined>
|
||||
hideNavbar: Ref<boolean>
|
||||
hideBreadcrumbs: Ref<boolean>
|
||||
}
|
||||
|
||||
const LayoutOptionsToken: InjectionKey<LayoutOptions> = Symbol()
|
||||
|
||||
export function provideLayoutOptions(options: LayoutOptions) {
|
||||
provide(LayoutOptionsToken, options)
|
||||
}
|
||||
|
||||
export function injectLayoutOptions() {
|
||||
const options = inject(LayoutOptionsToken)
|
||||
if (!options) {
|
||||
throw new Error('"injectLayoutOptions" must be called inside pages')
|
||||
}
|
||||
return options
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<button class="btn btn-primary">Primary Button</button>
|
||||
<button class="btn btn-secondary">Default Button</button>
|
||||
<button class="btn btn-error">Dashed Button</button>
|
||||
<button class="btn btn-link">Text Button</button>
|
||||
<button class="btn btn-link">Link Button</button>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,12 @@
|
|||
<template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<button class="btn btn-primary">Primary</button>
|
||||
<button class="btn btn-secondary">Default</button>
|
||||
<button class="btn btn-error">Danger</button>
|
||||
<button class="btn btn-link">Link</button>
|
||||
<button class="btn btn-ghost">Ghost</button>
|
||||
<button class="btn btn-link">Link</button>
|
||||
<button class="btn btn-link">Link</button>
|
||||
<button class="btn btn-link">Link</button>
|
||||
</div>
|
||||
</template>
|
|
@ -1,4 +1,65 @@
|
|||
import { RouteRecordRaw } from 'vue-router'
|
||||
import { RouteRecordRaw, RouterView } from 'vue-router'
|
||||
import BasicLayout from './components/BasicLayout.vue'
|
||||
import { Fragment, h } from 'vue'
|
||||
|
||||
const items = import.meta.glob('./pages/*/index.ts', { import: 'default', eager: true })
|
||||
export default Object.values(items) as RouteRecordRaw[]
|
||||
// /pages/button/basic.vue
|
||||
const items = import.meta.glob('./pages/*/*.vue', { import: 'default', eager: true })
|
||||
|
||||
const categoryRoutes: Record<string, RouteRecordRaw[]> = {}
|
||||
|
||||
Object.keys(items).forEach(path => {
|
||||
const route = path.replace('./pages/', '').replace('.vue', '')
|
||||
const [category, demo] = route.split('/')
|
||||
|
||||
if (!categoryRoutes[category]) {
|
||||
categoryRoutes[category] = []
|
||||
}
|
||||
|
||||
categoryRoutes[category].push({
|
||||
path: demo,
|
||||
component: items[path],
|
||||
})
|
||||
})
|
||||
|
||||
const routes: RouteRecordRaw[] = Object.entries(categoryRoutes).map(([category, children]) => {
|
||||
const renderComponents = () =>
|
||||
h(
|
||||
'div',
|
||||
children.map(child => h(child.component)),
|
||||
)
|
||||
renderComponents.displayName = 'renderComponents'
|
||||
return {
|
||||
path: `/${category}`,
|
||||
component: RouterView,
|
||||
children: [
|
||||
...children,
|
||||
{
|
||||
path: ':demo*',
|
||||
component: renderComponents,
|
||||
},
|
||||
],
|
||||
}
|
||||
})
|
||||
|
||||
const navs = Object.keys(categoryRoutes).map(category => ({
|
||||
name: category,
|
||||
path: `/${category}`,
|
||||
children: categoryRoutes[category].map(child => ({
|
||||
name: child.path,
|
||||
path: `/${category}/${child.path}`,
|
||||
})),
|
||||
}))
|
||||
routes.push({
|
||||
path: '/:pathMatch(.*)*',
|
||||
component: h('div', 'demo not found'),
|
||||
})
|
||||
export default [
|
||||
{
|
||||
path: '/',
|
||||
component: BasicLayout,
|
||||
children: routes,
|
||||
props: {
|
||||
navs,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"extends": "@ant-design-vue/typescript-config/tsconfig.vue.json",
|
||||
"include": ["src/**/*.ts", "src/**/*.vue"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }],
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"~/*": ["./assets/*"]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"extends": "@ant-design-vue/typescript-config/tsconfig.node.json",
|
||||
"include": ["vite.config.*"]
|
||||
}
|
|
@ -1,24 +1,11 @@
|
|||
import tailwindcss from '@tailwindcss/vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { resolve } from 'node:path'
|
||||
import { defineConfig, Plugin } from 'vite'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
appType: 'mpa',
|
||||
plugins: [
|
||||
vue(),
|
||||
react(),
|
||||
tailwindcss(),
|
||||
],
|
||||
build: {
|
||||
rollupOptions: {
|
||||
input: {
|
||||
main: resolve(__dirname, './index.html'),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [vue(), tailwindcss()],
|
||||
server: {
|
||||
watch: {
|
||||
ignored: ['!**/node_modules/@ant-design-vue/**'],
|
||||
|
@ -31,40 +18,3 @@ export default defineConfig({
|
|||
},
|
||||
},
|
||||
})
|
||||
|
||||
interface ImportmapOptions {
|
||||
imports: Record<string, string>
|
||||
}
|
||||
function importmapPlugin(options: ImportmapOptions): Plugin {
|
||||
return {
|
||||
name: 'vite-plugin-importmap',
|
||||
apply: 'build',
|
||||
config() {
|
||||
return {
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: Object.keys(options.imports),
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
transformIndexHtml: {
|
||||
order: 'pre',
|
||||
handler(html) {
|
||||
return {
|
||||
html,
|
||||
tags: [
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: {
|
||||
type: 'importmap',
|
||||
},
|
||||
children: JSON.stringify(options),
|
||||
injectTo: 'head-prepend',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue