mirror of
https://github.com/cool-team-official/cool-admin-vue.git
synced 2024-11-01 06:02:38 +08:00
添加主题模块
This commit is contained in:
parent
c3b382f654
commit
112cb37802
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "front-next",
|
||||
"version": "5.0.3",
|
||||
"version": "5.1.0",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"build": "vite build",
|
||||
|
@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<svg :class="svgClass" :style="style" aria-hidden="true">
|
||||
<use :xlink:href="iconName" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref } from "vue";
|
||||
import { isNumber } from "/@/cool/utils";
|
||||
|
||||
export default defineComponent({
|
||||
name: "icon-svg",
|
||||
|
||||
cool: {
|
||||
global: true
|
||||
},
|
||||
|
||||
props: {
|
||||
name: {
|
||||
type: String
|
||||
},
|
||||
className: {
|
||||
type: String
|
||||
},
|
||||
size: {
|
||||
type: [String, Number]
|
||||
}
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const style = ref<any>({
|
||||
fontSize: isNumber(props.size) ? props.size + "px" : props.size
|
||||
});
|
||||
|
||||
const iconName = computed<string>(() => `#icon-${props.name}`);
|
||||
const svgClass = computed<Array<string>>(() => {
|
||||
return ["icon-svg", `icon-svg__${props.name}`, String(props.className || "")];
|
||||
});
|
||||
|
||||
return {
|
||||
style,
|
||||
iconName,
|
||||
svgClass
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.icon-svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="app-process">
|
||||
<div class="app-process__left hidden-xs-only" @click="toScroll(true)">
|
||||
<el-icon><arrow-left /></el-icon>
|
||||
<div class="app-process__back" @click="router.back">
|
||||
<el-icon :size="15"><arrow-left /></el-icon>
|
||||
</div>
|
||||
|
||||
<div :ref="setRefs('scroller')" class="app-process__scroller">
|
||||
@ -16,19 +16,11 @@
|
||||
@contextmenu.stop.prevent="openCM($event, item)"
|
||||
>
|
||||
<span>{{ item.label }}</span>
|
||||
<el-icon
|
||||
v-if="index > 0"
|
||||
class="el-icon-close"
|
||||
@mousedown.stop="onDel(Number(index))"
|
||||
>
|
||||
<el-icon v-if="index > 0" @mousedown.stop="onDel(Number(index))">
|
||||
<close />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="app-process__right hidden-xs-only" @click="toScroll(false)">
|
||||
<el-icon><arrow-right /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -36,11 +28,11 @@
|
||||
import { watch } from "vue";
|
||||
import { last } from "/@/cool/utils";
|
||||
import { useCool } from "/@/cool";
|
||||
import { ArrowLeft, ArrowRight, Close } from "@element-plus/icons-vue";
|
||||
import { ArrowLeft, Close } from "@element-plus/icons-vue";
|
||||
import { ContextMenu } from "@cool-vue/crud";
|
||||
import { useBaseStore } from "/$/base";
|
||||
|
||||
const { refs, setRefs, store, route, router }: any = useCool();
|
||||
const { refs, setRefs, route, router } = useCool();
|
||||
const { process } = useBaseStore();
|
||||
|
||||
// 跳转
|
||||
@ -61,11 +53,6 @@ function scrollTo(left: number) {
|
||||
});
|
||||
}
|
||||
|
||||
// 左右移动
|
||||
function toScroll(f: boolean) {
|
||||
scrollTo(refs.value.scroller.scrollLeft + (f ? -100 : 100));
|
||||
}
|
||||
|
||||
// 调整滚动位置
|
||||
function adScroll(index: number) {
|
||||
const el = refs.value[`item-${index}`];
|
||||
@ -103,8 +90,7 @@ function openCM(e: any, item: any) {
|
||||
{
|
||||
label: "关闭其他",
|
||||
callback(done) {
|
||||
store.commit(
|
||||
"SET_PROCESS",
|
||||
process.set(
|
||||
process.list.filter((e: any) => e.value == item.value || e.value == "/")
|
||||
);
|
||||
done();
|
||||
@ -114,10 +100,7 @@ function openCM(e: any, item: any) {
|
||||
{
|
||||
label: "关闭所有",
|
||||
callback(done) {
|
||||
store.commit(
|
||||
"SET_PROCESS",
|
||||
process.list.filter((e: any) => e.value == "/")
|
||||
);
|
||||
process.set(process.list.filter((e: any) => e.value == "/"));
|
||||
done();
|
||||
toPath();
|
||||
}
|
||||
@ -143,30 +126,22 @@ watch(
|
||||
margin-bottom: 10px;
|
||||
padding: 0 10px;
|
||||
|
||||
&__left,
|
||||
&__right {
|
||||
&__back {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
height: 30px;
|
||||
padding: 0 2px;
|
||||
padding: 0 10px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
|
||||
&:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
|
||||
&__left {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&__right {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
&__scroller {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
@ -222,6 +197,8 @@ watch(
|
||||
&.active {
|
||||
span {
|
||||
color: var(--color-primary);
|
||||
font-weight: bold;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
i {
|
||||
|
@ -155,7 +155,7 @@ export default defineComponent({
|
||||
.app-slider {
|
||||
height: 100%;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
|
||||
background-color: var(--menu-bg-color);
|
||||
background-color: #2f3447;
|
||||
|
||||
&__logo {
|
||||
display: flex;
|
||||
@ -215,7 +215,6 @@ export default defineComponent({
|
||||
|
||||
.icon-svg,
|
||||
span {
|
||||
// color: var(--menu-font-color);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
@ -224,7 +223,7 @@ export default defineComponent({
|
||||
.el-sub-menu__title,
|
||||
&-item,
|
||||
&__title {
|
||||
color: var(--menu-font-color);
|
||||
color: #eee;
|
||||
letter-spacing: 0.5px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
|
@ -17,7 +17,9 @@
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<ul class="app-topbar__tools">
|
||||
<cl-theme />
|
||||
<li>
|
||||
<cl-theme />
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- 用户信息 -->
|
||||
@ -107,16 +109,12 @@ function onCommand(name: string) {
|
||||
align-items: center;
|
||||
list-style: none;
|
||||
height: 45px;
|
||||
padding: 0 10px;
|
||||
margin-right: 10px;
|
||||
width: 45px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
|
||||
i {
|
||||
font-size: 18px;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
<div class="app-views" v-if="!app.loading">
|
||||
<router-view v-slot="{ Component }">
|
||||
<keep-alive :include="caches">
|
||||
<component :is="Component" />
|
||||
<transition name="el-fade-in-linear">
|
||||
<component :is="Component" />
|
||||
</transition>
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
</div>
|
||||
|
@ -27,7 +27,7 @@ const { app } = useBaseStore();
|
||||
<style lang="scss" scoped>
|
||||
.page-layout {
|
||||
display: flex;
|
||||
background-color: var(--view-bg-color);
|
||||
background-color: #f7f7f7;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
@ -59,42 +59,7 @@ import { useCrud, useUpsert, useTable, useForm, useAdvSearch } from "@cool-vue/c
|
||||
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: {
|
||||
page() {
|
||||
return Promise.resolve({
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
name: "A"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "B"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "C"
|
||||
}
|
||||
],
|
||||
pagination: {
|
||||
total: 3,
|
||||
size: 10,
|
||||
page: 1
|
||||
}
|
||||
});
|
||||
},
|
||||
info() {
|
||||
return Promise.resolve({
|
||||
id: 1,
|
||||
name: "A"
|
||||
});
|
||||
},
|
||||
update() {
|
||||
return Promise.reject({
|
||||
message: "错误"
|
||||
});
|
||||
}
|
||||
}
|
||||
service: "test"
|
||||
},
|
||||
(app) => {
|
||||
app.refresh();
|
||||
@ -131,8 +96,6 @@ const Upsert = useUpsert({
|
||||
},
|
||||
{
|
||||
label: "crud",
|
||||
group: "2",
|
||||
hidden: ":isEdit",
|
||||
component: {
|
||||
name: "slot-crud"
|
||||
}
|
||||
|
@ -1,35 +1,30 @@
|
||||
<template>
|
||||
<div class="cl-theme" @click="open">
|
||||
<el-badge type="primary" is-dot>
|
||||
<icon-svg name="icon-discover"></icon-svg>
|
||||
<icon-svg name="icon-discover" :size="15"></icon-svg>
|
||||
</el-badge>
|
||||
</div>
|
||||
|
||||
<el-drawer v-model="visible" title="设置主题" size="350px">
|
||||
<el-drawer v-model="visible" title="设置主题" size="350px" append-to-body>
|
||||
<el-form label-position="top">
|
||||
<el-form-item label="推荐">
|
||||
<ul class="cl-theme__comd">
|
||||
<el-tooltip
|
||||
v-for="(item, name) in themes"
|
||||
:key="name"
|
||||
:content="item.label"
|
||||
placement="top"
|
||||
>
|
||||
<li
|
||||
<li @click="setComd(item)" v-for="(item, name) in themes" :key="name">
|
||||
<div
|
||||
class="w"
|
||||
:style="{
|
||||
backgroundColor: item.color
|
||||
}"
|
||||
@click="setComd(item)"
|
||||
>
|
||||
<check v-show="item.color == form.theme.color" />
|
||||
</li>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
<span>{{ item.label }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider></el-divider>
|
||||
|
||||
<el-form-item label="主色">
|
||||
<el-form-item label="自定义主色">
|
||||
<el-color-picker v-model="form.color" @change="setColor" />
|
||||
<span class="ml-10px">{{ form.color }}</span>
|
||||
</el-form-item>
|
||||
@ -43,6 +38,7 @@ import { setTheme, themes } from "../utils";
|
||||
import { module } from "/@/cool/utils";
|
||||
import store from "store";
|
||||
import { Check } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
export default defineComponent({
|
||||
name: "cl-theme",
|
||||
@ -74,7 +70,9 @@ export default defineComponent({
|
||||
|
||||
function setComd(item: any) {
|
||||
form.theme = item;
|
||||
form.color = item.color;
|
||||
setTheme(item);
|
||||
ElMessage.success(`切换主题:${item.label}`);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -92,31 +90,43 @@ export default defineComponent({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cl-theme {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
&__comd {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
li {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
list-style: none;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 3px;
|
||||
margin: 5px 10px 5px 0;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
line-height: 20px;
|
||||
margin-right: 15px;
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.w {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 3px;
|
||||
margin: 5px 10px 5px 0;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
line-height: 20px;
|
||||
padding: 2px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.el-icon {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.el-icon {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,6 @@
|
||||
export default {
|
||||
name: "blue"
|
||||
// color: "",
|
||||
// rules: {
|
||||
// "--view-bg-color": "#f7f7f7",
|
||||
// "--menu-bg-color": "#2f3447",
|
||||
// "--menu-font-color": "#ffffff",
|
||||
// "--topbar-bg-color": "#ffffff",
|
||||
// "--topbar-font-color": "#000000"
|
||||
// }
|
||||
// 推荐主题:'jihei', 'guolv', 'jiangzi'
|
||||
name: "default"
|
||||
// 自定义主题色
|
||||
// color: "#4165d7"
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import store from "store";
|
||||
import { App } from "vue";
|
||||
import { setTheme } from "./utils";
|
||||
import "./static/css/index.scss";
|
||||
|
||||
export default {
|
||||
install(_: App, options: any) {
|
||||
|
60
src/modules/theme/static/css/index.scss
Normal file
60
src/modules/theme/static/css/index.scss
Normal file
@ -0,0 +1,60 @@
|
||||
.theme {
|
||||
&-jihei {
|
||||
.page-layout {
|
||||
background-color: rgba(47, 52, 71, 0.9);
|
||||
|
||||
.app-topbar {
|
||||
background-color: transparent;
|
||||
color: #fff;
|
||||
|
||||
span {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-breadcrumb {
|
||||
span {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
&__item {
|
||||
&:last-child {
|
||||
span {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-jiangzi {
|
||||
.page-layout {
|
||||
.app-slider__logo {
|
||||
background-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.app-slider {
|
||||
background-color: #fff;
|
||||
|
||||
.el-sub-menu__title,
|
||||
.el-menu-item {
|
||||
color: #000;
|
||||
background-color: transparent !important;
|
||||
|
||||
&:hover,
|
||||
&.is-active {
|
||||
.icon-svg,
|
||||
span {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
border-right: 3px solid var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -20,42 +20,32 @@ function mix(color1: string, color2: string, weight: number) {
|
||||
export const themes = [
|
||||
{
|
||||
label: "钴蓝",
|
||||
name: "blue",
|
||||
color: "#4165d7",
|
||||
rules: {
|
||||
"--menu-bg-color": "#2f3447",
|
||||
"--menu-font-color": "#ffffff"
|
||||
}
|
||||
name: "default",
|
||||
color: "#4165d7"
|
||||
},
|
||||
{
|
||||
label: "极黑",
|
||||
name: "black",
|
||||
color: "#2f3447"
|
||||
name: "jihei",
|
||||
color: "#222222"
|
||||
},
|
||||
{
|
||||
label: "果绿",
|
||||
name: "green",
|
||||
name: "guolv",
|
||||
color: "#51C21A"
|
||||
},
|
||||
{
|
||||
label: "酱紫",
|
||||
name: "purple",
|
||||
color: "#d0378d",
|
||||
rules: {
|
||||
"--view-bg-color": "#f7f7f7",
|
||||
"--menu-bg-color": "#ffffff",
|
||||
"--menu-font-color": "#000000"
|
||||
}
|
||||
name: "jiangzi",
|
||||
color: "#d0378d"
|
||||
}
|
||||
];
|
||||
|
||||
declare interface Options {
|
||||
color?: string;
|
||||
name?: string;
|
||||
rules?: any;
|
||||
}
|
||||
|
||||
export function setTheme({ color, name, rules }: Options) {
|
||||
export function setTheme({ color, name }: Options) {
|
||||
// 主题配置
|
||||
const theme = store.get("theme") || {};
|
||||
|
||||
@ -76,16 +66,8 @@ export function setTheme({ color, name, rules }: Options) {
|
||||
const item = themes.find((e) => e.name == name);
|
||||
|
||||
if (item) {
|
||||
theme.name = name;
|
||||
color = item.color;
|
||||
rules = item.rules;
|
||||
|
||||
switch (name) {
|
||||
case "blue":
|
||||
break;
|
||||
case "black":
|
||||
break;
|
||||
}
|
||||
document.querySelector("#app")?.setAttribute("class", `theme-${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,18 +81,11 @@ export function setTheme({ color, name, rules }: Options) {
|
||||
el.style.setProperty(`${pre}-light-${i}`, mix(color, mixWhite, i * 0.1));
|
||||
el.style.setProperty(`${pre}-dark-${i}`, mix(color, mixBlack, i * 0.1));
|
||||
}
|
||||
|
||||
// 缓存
|
||||
theme.color = color;
|
||||
}
|
||||
|
||||
if (rules) {
|
||||
for (const i in rules) {
|
||||
el.style.setProperty(i, rules[i]);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(theme);
|
||||
// 缓存
|
||||
theme.name = name;
|
||||
theme.color = color;
|
||||
|
||||
store.set("theme", theme);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user