feat(projects): 新增主题配置

This commit is contained in:
Soybean
2021-08-18 12:02:59 +08:00
parent 09a28d8e1d
commit ed67b797c2
30 changed files with 528 additions and 47 deletions

View File

@ -1,11 +1,16 @@
<template>
<el-config-provider :locale="locale">
<router-view />
</el-config-provider>
<n-config-provider :locale="zhCN" :date-locale="dateZhCN" :theme-overrides="app.themeOverrids">
<naive-app>
<router-view />
</naive-app>
</n-config-provider>
</template>
<script lang="ts" setup>
import { ElConfigProvider } from 'element-plus';
import locale from 'element-plus/lib/locale/lang/zh-cn';
import { NConfigProvider, zhCN, dateZhCN } from 'naive-ui';
import { NaiveApp } from '@/components';
import { useAppStore } from '@/store';
const app = useAppStore();
</script>
<style></style>

View File

@ -0,0 +1,17 @@
<template>
<div></div>
</template>
<script lang="ts" setup>
import { useLoadingBar, useDialog, useMessage, useNotification } from 'naive-ui';
function registerNaiveTool() {
window.$loadingBar = useLoadingBar();
window.$dialog = useDialog();
window.$message = useMessage();
window.$notification = useNotification();
}
registerNaiveTool();
</script>
<style scoped></style>

View File

@ -0,0 +1,18 @@
<template>
<n-loading-bar-provider>
<n-dialog-provider>
<n-notification-provider>
<n-message-provider>
<slot></slot>
<naive-content />
</n-message-provider>
</n-notification-provider>
</n-dialog-provider>
</n-loading-bar-provider>
</template>
<script lang="ts" setup>
import { NLoadingBarProvider, NDialogProvider, NNotificationProvider, NMessageProvider } from 'naive-ui';
import NaiveContent from './NaiveContent.vue';
</script>
<style scoped></style>

View File

@ -0,0 +1,3 @@
import NaiveApp from './NaiveApp/index.vue';
export { NaiveApp };

View File

@ -0,0 +1 @@
export { NaiveApp } from './common';

8
src/interface/app.ts Normal file
View File

@ -0,0 +1,8 @@
export interface ThemeSettings {
/** 深色模式 */
darkMode: boolean;
/** 主题颜色 */
themeColor: string;
/** 主题颜色列表 */
themeColorList: string[];
}

0
src/interface/common.ts Normal file
View File

View File

@ -1 +1,2 @@
export { UserInfo } from './business';
export { ThemeSettings } from './app';

View File

@ -0,0 +1,8 @@
<template>
<div>
<router-view />
</div>
</template>
<script lang="ts" setup></script>
<style scoped></style>

View File

@ -0,0 +1,3 @@
import BasicLayout from './BasicLayout.vue';
export { BasicLayout };

View File

@ -1,13 +1,33 @@
import { createApp } from 'vue';
import App from './App.vue';
import { setupRouter } from './router';
import { setupSmoothScroll, setupElementPlus } from './plugins';
import { setupStore } from './store';
import { router, setupRouter } from './router';
import { setupSmoothScroll, setupNaive } from './plugins';
import { NaiveApp } from './components';
import 'virtual:windi.css';
import './styles/css/global.css';
const app = createApp(App);
setupSmoothScroll();
setupElementPlus(app);
setupRouter(app);
async function setupApp() {
const naiveApp = createApp(NaiveApp);
const app = createApp(App);
app.mount('#app');
/** 注册naive UI组件 */
setupNaive(app);
/** 挂载全局状态 */
setupStore(app);
// 优先挂载一下 naiveApp 解决路由守卫Axios中可使用DialogMessage 等之类组件
naiveApp.mount('#naiveApp', true);
// 挂载路由
setupRouter(app);
// 路由准备就绪后挂载APP实例
await router.isReady();
app.mount('#app', true);
}
setupSmoothScroll();
setupApp();

View File

@ -1,5 +1,5 @@
import setupSmoothScroll from './smooth-scroll';
import setupElementPlus from './element-plus';
import setupNaive from './naive';
import NProgress from './nprogress';
export { setupSmoothScroll, setupElementPlus, NProgress };
export { setupSmoothScroll, setupNaive, NProgress };

9
src/plugins/naive.ts Normal file
View File

@ -0,0 +1,9 @@
import { create, NSpace, NButton, NDatePicker, NInput } from 'naive-ui';
import type { App } from 'vue';
export default function setupNaive(app: App) {
const naive = create({
components: [NSpace, NButton, NDatePicker, NInput]
});
app.use(naive);
}

View File

@ -6,7 +6,7 @@ import createRouterGuide from './permission';
const routes: Array<RouteRecordRaw> = [...customRoutes];
const router = createRouter({
export const router = createRouter({
history: createWebHistory(),
routes
});

View File

@ -1,5 +1,4 @@
import type { Router } from 'vue-router';
import { NProgress } from '@/plugins';
/**
* 路由守卫函数
@ -7,10 +6,10 @@ import { NProgress } from '@/plugins';
*/
export default function createRouterGuide(router: Router) {
router.beforeEach((to, from, next) => {
NProgress.start();
window.$loadingBar?.start();
next();
});
router.afterEach(() => {
NProgress.done();
window.$loadingBar?.finish();
});
}

View File

@ -1,4 +1,5 @@
import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '@/layouts';
/**
* 自定义路由
@ -7,16 +8,19 @@ export const customRoutes: Array<RouteRecordRaw> = [
{
name: 'root',
path: '/',
redirect: 'home'
},
{
name: 'home',
path: '/home',
component: () => import('@/views/home/index.vue')
},
{
name: 'system',
path: '/system',
component: () => import('@/views/system/index.vue')
redirect: '/home',
component: BasicLayout,
children: [
{
name: 'home',
path: '/home',
component: () => import('@/views/home/index.vue')
},
{
name: 'system',
path: '/system',
component: () => import('@/views/system/index.vue')
}
]
}
];

3
src/settings/index.ts Normal file
View File

@ -0,0 +1,3 @@
import themeSettings from './theme';
export { themeSettings };

View File

@ -0,0 +1,33 @@
import type { ThemeSettings } from '@/interface';
const themeColorList = [
'#2d8cf0',
'#0960bd',
'#0084f4',
'#009688',
'#536dfe',
'#ff5c93',
'#ee4f12',
'#0096c7',
'#9c27b0',
'#ff9800',
'#FF3D68',
'#00C1D4',
'#71EFA3',
'#171010',
'#78DEC7',
'#1768AC',
'#FB9300',
'#FC5404'
];
const themeSettings: ThemeSettings = {
/** 深色主题 */
darkMode: false,
/** 系统主题色 */
themeColor: themeColorList[0],
/** 系统内置主题色列表 */
themeColorList
};
export default themeSettings;

View File

@ -1,7 +1,13 @@
import { defineStore } from 'pinia';
import type { GlobalThemeOverrides } from 'naive-ui';
import { store } from '../../index';
import { themeSettings } from '@/settings';
import type { ThemeSettings } from '@/interface';
import { brightenColor } from '@/utils';
interface AppState {
/** 主题配置 */
themeSettings: ThemeSettings;
/** 侧边栏折叠 */
asideCollapse: boolean;
}
@ -9,8 +15,29 @@ interface AppState {
const appStore = defineStore({
id: 'app-store',
state: (): AppState => ({
themeSettings,
asideCollapse: false
}),
getters: {
/** naive UI主题配置 */
themeOverrids(): GlobalThemeOverrides {
const primaryColor = this.themeSettings.themeColor;
const primaryColorHover = brightenColor(primaryColor);
const primaryColorPressed = primaryColorHover;
const colorLoading = primaryColor;
return {
common: {
primaryColor,
primaryColorHover,
primaryColorPressed
},
LoadingBar: {
colorLoading
}
};
}
},
actions: {
handleAsideCollapse(collapse: boolean) {
this.asideCollapse = collapse;

15
src/typings/window.d.ts vendored Normal file
View File

@ -0,0 +1,15 @@
import type {
LoadingBarProviderInst,
DialogProviderInst,
MessageProviderInst,
NotificationProviderInst
} from 'naive-ui';
declare global {
interface Window {
$loadingBar?: LoadingBarProviderInst;
$dialog?: DialogProviderInst;
$message?: MessageProviderInst;
$notification?: NotificationProviderInst;
}
}

View File

@ -0,0 +1,9 @@
import chroma from 'chroma-js';
/**
* 更亮的颜色
* @param color
*/
export function brightenColor(color: string) {
return chroma(color).brighten(0.5).hex();
}

View File

@ -11,3 +11,5 @@ export {
isSet,
isMap
} from './typeof';
export { brightenColor } from './color';

View File

@ -10,5 +10,6 @@ export {
isDate,
isRegExp,
isSet,
isMap
isMap,
brightenColor
} from './common';

View File

@ -1,6 +1,49 @@
<template>
<div>Home</div>
<div>
<n-space>
<n-button v-for="item in actions" :key="item.key" type="primary" @click="handleClick(item.key)">
{{ item.label }}
</n-button>
</n-space>
</div>
</template>
<script lang="ts" setup></script>
<script lang="ts" setup>
import { useLoadingBar, useDialog, useNotification, useMessage } from 'naive-ui';
type ActionType = 'loading-bar' | 'dialog' | 'notification' | 'message';
interface Action {
key: ActionType;
label: string;
}
const loadingBar = useLoadingBar();
const dialog = useDialog();
const notification = useNotification();
const message = useMessage();
const actions: Action[] = [
{ key: 'loading-bar', label: 'loading bar' },
{ key: 'dialog', label: 'dialog' },
{ key: 'notification', label: 'notification' },
{ key: 'message', label: 'message' }
];
function handleClick(type: ActionType) {
if (type === 'loading-bar') {
loadingBar.start();
setTimeout(() => {
loadingBar.finish();
}, 5000);
}
if (type === 'dialog') {
dialog.info({ content: '弹窗示例!' });
}
if (type === 'notification') {
notification.info({ content: '通知示例!' });
}
if (type === 'message') {
message.info('消息示例!');
}
}
</script>
<style scoped></style>