added dark mode
This commit is contained in:
Vendored
+4
@@ -35,9 +35,11 @@ declare module '@vue/runtime-core' {
|
||||
AMenu: typeof import('ant-design-vue/es')['Menu']
|
||||
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
|
||||
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
|
||||
AMenuItemGroup: typeof import('ant-design-vue/es')['MenuItemGroup']
|
||||
AModal: typeof import('ant-design-vue/es')['Modal']
|
||||
APagination: typeof import('ant-design-vue/es')['Pagination']
|
||||
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
|
||||
APopover: typeof import('ant-design-vue/es')['Popover']
|
||||
ARadio: typeof import('ant-design-vue/es')['Radio']
|
||||
ARadioButton: typeof import('ant-design-vue/es')['RadioButton']
|
||||
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
|
||||
@@ -81,6 +83,8 @@ declare module '@vue/runtime-core' {
|
||||
CustomTag: typeof import('./src/components/CustomTag.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
ThemeMenuSection: typeof import('./src/core/components/ThemeMenuSection.vue')['default']
|
||||
ThemeToggle: typeof import('./src/core/components/ThemeToggle.vue')['default']
|
||||
UploadPic: typeof import('./src/components/UploadPic.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -6,6 +6,17 @@
|
||||
<meta content="width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no" name="viewport">
|
||||
<!-- todo -->
|
||||
<title>admin </title>
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var raw = localStorage.getItem('color-schema')
|
||||
var schema = raw ? JSON.parse(raw) : 'auto'
|
||||
var prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
var isDark = schema === 'dark' || (schema !== 'light' && prefersDark)
|
||||
if (isDark) document.documentElement.classList.add('is-dark')
|
||||
} catch (e) {}
|
||||
})()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
+10
-2
@@ -11,7 +11,10 @@ import {
|
||||
|
||||
export default defineConfig({
|
||||
shortcuts: [
|
||||
// ...
|
||||
['surface', 'bg-white dark:bg-[#1f1f1f]'],
|
||||
['surface-muted', 'bg-gray-50 dark:bg-[#262626]'],
|
||||
['border-base', 'border-gray-200 dark:border-[color:var(--admin-border)]'],
|
||||
['text-muted', 'text-gray-600 dark:text-gray-400'],
|
||||
],
|
||||
theme: {
|
||||
colors: {
|
||||
@@ -20,7 +23,12 @@ export default defineConfig({
|
||||
}
|
||||
},
|
||||
presets: [
|
||||
presetUno(),
|
||||
presetUno({
|
||||
dark: {
|
||||
dark: 'html.is-dark',
|
||||
light: 'html:not(.is-dark)',
|
||||
},
|
||||
}),
|
||||
presetAttributify(),
|
||||
presetIcons(),
|
||||
presetTypography(),
|
||||
|
||||
+9
-5
@@ -6,17 +6,21 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted} from 'vue'
|
||||
import {useConfigStore} from "@/store/configStore";
|
||||
import { onMounted } from 'vue'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { initDarkmode } from '@core/stores/darkmode'
|
||||
|
||||
const router = useRouter()
|
||||
const config=useConfigStore()
|
||||
const config = useConfigStore()
|
||||
|
||||
initDarkmode()
|
||||
|
||||
function test() {
|
||||
console.log('roussss', router)
|
||||
router.push({ name: 'users' })
|
||||
}
|
||||
onMounted(async ()=>{
|
||||
await config.getConfigData()
|
||||
onMounted(async () => {
|
||||
await config.getConfigData()
|
||||
})
|
||||
|
||||
/*const router = useRouter()
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ export const changeProductActivation = async (id: number) =>
|
||||
export const changeCustomerOrderActivation = async (id: number) =>
|
||||
await useAxios.get(`/admin/product/trade/${id}`)
|
||||
|
||||
export const changeCustomerArchive = async (id: number) =>
|
||||
export const changeProductArchive = async (id: number) =>
|
||||
await useAxios.get(`/admin/product/archive/${id}`)
|
||||
|
||||
export const confirmUser = async (id: number) =>
|
||||
|
||||
@@ -81,13 +81,12 @@
|
||||
margin: 0 8px;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
border: 1px solid #d1d5db;
|
||||
border: 1px solid var(--admin-border-strong);
|
||||
border-radius: 4px;
|
||||
background-color: white;
|
||||
//@apply bg-gray-50;
|
||||
background-color: var(--admin-bg-surface);
|
||||
|
||||
&:focus-visible {
|
||||
background-color: #fff;
|
||||
background-color: var(--admin-bg-surface);
|
||||
//display: none;
|
||||
outline: none;
|
||||
border: 1px solid @primary-color !important;
|
||||
|
||||
@@ -29,7 +29,7 @@ const props = withDefaults(defineProps<Props>(), {})
|
||||
.open {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: #E5E7EB;
|
||||
background-color: var(--admin-border-strong);
|
||||
}
|
||||
|
||||
.rotate {
|
||||
@@ -40,7 +40,7 @@ const props = withDefaults(defineProps<Props>(), {})
|
||||
.ant-collapse > .ant-collapse-item > .ant-collapse-header {
|
||||
direction: rtl !important;
|
||||
justify-content: space-between !important;
|
||||
background-color: #fff !important;
|
||||
background-color: var(--admin-bg-surface) !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
@@ -206,8 +206,8 @@ function handleCancel() {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
z-index: 2;
|
||||
background: #fff;
|
||||
background: var(--admin-bg-elevated);
|
||||
padding: 8px 16px calc(16px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #f0f0f0;
|
||||
border-top: 1px solid var(--admin-border);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
footer
|
||||
>
|
||||
<div class="overflow-y-auto max-h-[70vh] mt-10">
|
||||
<div :class="[prefixCls]" class="bg-blue-50 rounded flex justify-between p-3">
|
||||
<div :class="[prefixCls]" class="admin-stat-muted rounded flex justify-between p-3">
|
||||
<div>
|
||||
<div class="font-bold">{{ props.name }}</div>
|
||||
<div class="text-primary-type mt-1">{{ props.type }}</div>
|
||||
@@ -40,15 +40,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-[#CACED8] w-full h-[1px] my-8" />
|
||||
<div class="text-[#949DB0]">{{ props.itemsTitle }}</div>
|
||||
<div class="my-8 h-px w-full bg-[var(--admin-border)]" />
|
||||
<div class="text-[var(--admin-text-secondary)]">{{ props.itemsTitle }}</div>
|
||||
<div class="grid md:grid-cols-4 mt-5 gap-5 p-5">
|
||||
<div v-for="val in props.items">
|
||||
<div class="text-[#949DB0]">{{ val.key }}</div>
|
||||
<div class="text-[var(--admin-text-secondary)]">{{ val.key }}</div>
|
||||
<div class="font-bold">{{ val.value }}</div>
|
||||
</div>
|
||||
<div class="md:col-span-5" v-if="props.description">
|
||||
<div class="text-[#949DB0]">توضیحات</div>
|
||||
<div class="text-[var(--admin-text-secondary)]">توضیحات</div>
|
||||
<div class="font-bold">{{ props.description ?? '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
:style="{ width: props.width }"
|
||||
:mode="props.mode"
|
||||
:theme="props.theme"
|
||||
:theme="resolvedTheme"
|
||||
>
|
||||
<BasicMenuItem :menu="props.menu" />
|
||||
</AMenu>
|
||||
@@ -17,6 +17,9 @@ import { defineProps } from 'vue'
|
||||
//import Icon from '@core/components/BaseIcon/src/Icon.vue'
|
||||
import BasicMenuItem from '@/components/BasicMenu/components/BasicMenuItem.vue'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
import { useAdminTheme } from '@core/composable/useAdminTheme'
|
||||
|
||||
const { menuTheme } = useAdminTheme()
|
||||
|
||||
const selectedKeys = ref<string[]>([])
|
||||
const router = useRouter()
|
||||
@@ -39,11 +42,13 @@ interface Prop {
|
||||
theme?: MenuTheme
|
||||
width?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Prop>(), {
|
||||
mode: 'inline',
|
||||
theme: 'light',
|
||||
width: '20rem'
|
||||
})
|
||||
|
||||
const resolvedTheme = computed(() => props.theme ?? menuTheme.value)
|
||||
onMounted(() => {
|
||||
selectedKeys.value = [router.currentRoute.value.name as string]
|
||||
//emits('onChange', '1')
|
||||
|
||||
@@ -104,9 +104,9 @@ function navigateTo(item: RouteRecordRaw) {
|
||||
justify-content: space-around;
|
||||
gap: 4px;
|
||||
padding: 6px 8px calc(6px + env(safe-area-inset-bottom));
|
||||
background: #fff;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.06);
|
||||
background: var(--admin-bg-surface);
|
||||
border-top: 1px solid var(--admin-border);
|
||||
box-shadow: 0 -2px 12px var(--admin-shadow);
|
||||
}
|
||||
|
||||
.mobile-bottom-nav__item {
|
||||
@@ -122,14 +122,14 @@ function navigateTo(item: RouteRecordRaw) {
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
color: #595959;
|
||||
color: var(--admin-text-secondary);
|
||||
|
||||
&--active {
|
||||
color: #1677ff;
|
||||
color: var(--admin-menu-selected-text);
|
||||
|
||||
.mobile-bottom-nav__icon-wrap {
|
||||
background: #e6f4ff;
|
||||
color: #1677ff;
|
||||
background: var(--admin-menu-selected);
|
||||
color: var(--admin-menu-selected-text);
|
||||
}
|
||||
|
||||
&::after {
|
||||
@@ -141,7 +141,7 @@ function navigateTo(item: RouteRecordRaw) {
|
||||
width: 28px;
|
||||
height: 3px;
|
||||
border-radius: 3px 3px 0 0;
|
||||
background: #1677ff;
|
||||
background: var(--admin-menu-selected-text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ function navigateTo(item: RouteRecordRaw) {
|
||||
width: 40px;
|
||||
height: 32px;
|
||||
border-radius: 10px;
|
||||
color: #292d32;
|
||||
color: var(--admin-text-muted);
|
||||
|
||||
:deep(svg path) {
|
||||
stroke: currentColor;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
</div>
|
||||
</AMenuItem>
|
||||
<AMenuDivider />
|
||||
<ThemeMenuSection />
|
||||
<AMenuItem @click="myInfoVisible = true">
|
||||
<div class="flex items-center gap-1">
|
||||
<Icon icon="vuesax-linear:profile" size="18" />
|
||||
@@ -80,6 +81,7 @@ import { message } from 'ant-design-vue/es'
|
||||
import { onMounted, ref, computed } from 'vue'
|
||||
import type { FormInstance } from 'ant-design-vue'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import ThemeMenuSection from '@core/components/ThemeMenuSection.vue'
|
||||
|
||||
const { prefixCls } = usePrefix('basic-header')
|
||||
const userStore = useUserStore()
|
||||
@@ -129,7 +131,11 @@ async function ok() {
|
||||
}
|
||||
|
||||
function clearLocalStorage() {
|
||||
const colorSchema = localStorage.getItem('color-schema')
|
||||
localStorage.clear()
|
||||
if (colorSchema) {
|
||||
localStorage.setItem('color-schema', colorSchema)
|
||||
}
|
||||
location.reload()
|
||||
}
|
||||
|
||||
@@ -142,9 +148,9 @@ function handleRefresh() {
|
||||
@prefix: ~'@{prefixCls}-basic-header';
|
||||
|
||||
.@{prefix} {
|
||||
padding: 12px 16px;
|
||||
background-color: #f5f5f5;
|
||||
border-bottom: none;
|
||||
padding: 0;
|
||||
background-color: var(--admin-bg-surface);
|
||||
border-bottom: 1px solid var(--admin-border);
|
||||
}
|
||||
|
||||
.mobile-header-bar {
|
||||
@@ -153,17 +159,18 @@ function handleRefresh() {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 12px 16px;
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 16px;
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
background: var(--admin-bg-surface);
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.mobile-header-bar__name {
|
||||
max-width: 34%;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #1f1f1f;
|
||||
color: var(--admin-text);
|
||||
line-height: 1.4;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -195,7 +202,7 @@ function handleRefresh() {
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #292d32;
|
||||
color: var(--admin-text);
|
||||
cursor: pointer;
|
||||
line-height: 0;
|
||||
|
||||
@@ -203,4 +210,17 @@ function handleRefresh() {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.hr-tamin-base-button.ant-btn-text) {
|
||||
color: var(--admin-text-secondary);
|
||||
background: transparent !important;
|
||||
border-color: transparent !important;
|
||||
box-shadow: none !important;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--admin-text);
|
||||
background: var(--admin-bg-hover) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -92,11 +92,11 @@ function handleSelect(item: RouteRecordRaw) {
|
||||
}
|
||||
|
||||
.mobile-overflow-menu__trigger--active {
|
||||
color: #1677ff;
|
||||
color: var(--admin-menu-selected-text);
|
||||
|
||||
.mobile-overflow-menu__icon-wrap {
|
||||
background: #e6f4ff;
|
||||
color: #1677ff;
|
||||
background: var(--admin-menu-selected);
|
||||
color: var(--admin-menu-selected-text);
|
||||
}
|
||||
|
||||
&::after {
|
||||
@@ -108,7 +108,7 @@ function handleSelect(item: RouteRecordRaw) {
|
||||
width: 28px;
|
||||
height: 3px;
|
||||
border-radius: 3px 3px 0 0;
|
||||
background: #1677ff;
|
||||
background: var(--admin-menu-selected-text);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="relative flex h-full min-h-0 min-w-0 w-full max-w-full flex-col overflow-hidden py-2 pr-3">
|
||||
<div class="flex shrink-0 min-w-0 items-center justify-between gap-2">
|
||||
<div class="truncate text-black font-bold">{{ props.title }}</div>
|
||||
<div class="truncate font-bold text-[var(--admin-text)]">{{ props.title }}</div>
|
||||
<slot name="extra" />
|
||||
</div>
|
||||
<div class="mt-2 min-h-0 flex-1 overflow-x-hidden overflow-y-auto p-1">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<article
|
||||
class="rounded-2xl border border-gray-200 bg-white shadow-sm"
|
||||
class="rounded-2xl border-base surface shadow-sm"
|
||||
:class="[paddingClass, clickable ? 'cursor-pointer' : '']"
|
||||
@click="clickable ? $emit('click') : undefined"
|
||||
>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
@import (less) './scroll.less';
|
||||
@import (less) "./fonts.less";
|
||||
@import (less) './var.less';
|
||||
@import (less) './theme.less';
|
||||
@import (less) './ant-override.less';
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,431 @@
|
||||
@import (less) './var.less';
|
||||
|
||||
html {
|
||||
color-scheme: light;
|
||||
--admin-primary: @gold-color-light;
|
||||
--admin-gold: @gold-color;
|
||||
--admin-gold-light: @gold-color-light;
|
||||
--admin-gold-hover: @gold-color-hover;
|
||||
--admin-bg-body: #f0f2f5;
|
||||
--admin-bg-surface: #ffffff;
|
||||
--admin-bg-elevated: #ffffff;
|
||||
--admin-bg-muted: #fafafa;
|
||||
--admin-bg-subtle: #f6f6f4;
|
||||
--admin-bg-hover: #f5f5f5;
|
||||
--admin-border: #f0f0f0;
|
||||
--admin-border-strong: #d9d9d9;
|
||||
--admin-text: rgba(0, 0, 0, 0.88);
|
||||
--admin-text-secondary: rgba(0, 0, 0, 0.45);
|
||||
--admin-text-muted: rgba(0, 0, 0, 0.65);
|
||||
--admin-shadow: rgba(0, 0, 0, 0.06);
|
||||
--admin-menu-selected: @gold-color-muted;
|
||||
--admin-menu-selected-text: @gold-color-dark;
|
||||
--admin-gradient-surface: #ffffff;
|
||||
--admin-gradient-surface-fade: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
html.is-dark {
|
||||
color-scheme: dark;
|
||||
--admin-primary: @gold-color-light;
|
||||
--admin-gold: @gold-color-light;
|
||||
--admin-gold-light: @gold-color-hover;
|
||||
--admin-gold-hover: #edd054;
|
||||
--admin-bg-body: #141414;
|
||||
--admin-bg-surface: #141414;
|
||||
--admin-bg-elevated: #1f1f1f;
|
||||
--admin-bg-muted: #262626;
|
||||
--admin-bg-subtle: #1a1a1a;
|
||||
--admin-bg-hover: rgba(201, 162, 39, 0.1);
|
||||
--admin-border: rgba(201, 162, 39, 0.18);
|
||||
--admin-border-strong: rgba(201, 162, 39, 0.32);
|
||||
--admin-text: rgba(255, 255, 255, 0.85);
|
||||
--admin-text-secondary: rgba(255, 255, 255, 0.45);
|
||||
--admin-text-muted: rgba(255, 255, 255, 0.65);
|
||||
--admin-shadow: rgba(0, 0, 0, 0.45);
|
||||
--admin-menu-selected: @gold-color-light;
|
||||
--admin-menu-selected-text: #141414;
|
||||
--admin-gradient-surface: #141414;
|
||||
--admin-gradient-surface-fade: rgba(20, 20, 20, 0.85);
|
||||
|
||||
--ant-primary-color: @gold-color-light;
|
||||
--ant-primary-color-hover: @gold-color-hover;
|
||||
--ant-primary-color-active: @gold-color;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--admin-bg-body);
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.ant-layout-header.@{prefixCls}-basic-header {
|
||||
padding: 0 12px !important;
|
||||
line-height: normal !important;
|
||||
}
|
||||
|
||||
.@{prefixCls}-base-button {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
height: auto !important;
|
||||
line-height: 1 !important;
|
||||
}
|
||||
|
||||
.ant-btn-primary {
|
||||
background: var(--admin-gold-light) !important;
|
||||
border-color: var(--admin-gold-light) !important;
|
||||
}
|
||||
|
||||
.ant-btn-primary:not([disabled]):hover,
|
||||
.ant-btn-primary:not([disabled]):focus {
|
||||
background: var(--admin-gold-hover) !important;
|
||||
border-color: var(--admin-gold-hover) !important;
|
||||
}
|
||||
|
||||
.ant-btn-primary:not([disabled]):active {
|
||||
background: var(--admin-gold) !important;
|
||||
border-color: var(--admin-gold) !important;
|
||||
}
|
||||
|
||||
.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item-selected,
|
||||
.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu-selected > .ant-menu-submenu-title {
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
background-color: var(--admin-menu-selected) !important;
|
||||
}
|
||||
|
||||
.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item-selected::after,
|
||||
.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu-selected::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn {
|
||||
color: var(--admin-gold-light) !important;
|
||||
}
|
||||
|
||||
.ant-tabs-ink-bar {
|
||||
background: var(--admin-gold-light) !important;
|
||||
}
|
||||
|
||||
.admin-bg-surface {
|
||||
background-color: var(--admin-bg-surface);
|
||||
}
|
||||
|
||||
.admin-bg-elevated {
|
||||
background-color: var(--admin-bg-elevated);
|
||||
}
|
||||
|
||||
.admin-stat-muted {
|
||||
background-color: var(--admin-bg-muted);
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.stat-inner {
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
html.is-dark {
|
||||
.stat-inner {
|
||||
border-color: var(--admin-border);
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.bg-green-100 .stat-inner {
|
||||
background: rgba(34, 197, 94, 0.12);
|
||||
border-color: rgba(34, 197, 94, 0.22);
|
||||
}
|
||||
|
||||
.bg-red-100 .stat-inner {
|
||||
background: rgba(239, 68, 68, 0.12);
|
||||
border-color: rgba(239, 68, 68, 0.22);
|
||||
}
|
||||
|
||||
.bg-amber-100 .stat-inner {
|
||||
background: rgba(245, 158, 11, 0.12);
|
||||
border-color: rgba(245, 158, 11, 0.22);
|
||||
}
|
||||
|
||||
.bg-amber-100 {
|
||||
background-color: rgba(245, 158, 11, 0.14) !important;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.bg-white\/70 {
|
||||
background-color: rgba(255, 255, 255, 0.06) !important;
|
||||
}
|
||||
|
||||
.ant-table-wrapper,
|
||||
.ant-table,
|
||||
.ant-table-container,
|
||||
.ant-table-content,
|
||||
.ant-table-thead > tr > th,
|
||||
.ant-table-tbody > tr > td {
|
||||
border-color: var(--admin-border) !important;
|
||||
}
|
||||
|
||||
.table-toolbar {
|
||||
background: transparent !important;
|
||||
}
|
||||
.bg-white {
|
||||
background-color: var(--admin-bg-elevated) !important;
|
||||
}
|
||||
|
||||
.bg-green-100 {
|
||||
background-color: rgba(34, 197, 94, 0.14) !important;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.bg-red-100 {
|
||||
background-color: rgba(239, 68, 68, 0.14) !important;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.bg-blue-100 {
|
||||
background-color: rgba(59, 130, 246, 0.14) !important;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.bg-yellow-100 {
|
||||
background-color: rgba(234, 179, 8, 0.14) !important;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.bg-orange-100,
|
||||
.bg-orange-50 {
|
||||
background-color: rgba(249, 115, 22, 0.14) !important;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.bg-blue-50 {
|
||||
background-color: rgba(59, 130, 246, 0.12) !important;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.bg-fuchsia-100 {
|
||||
background-color: rgba(217, 70, 239, 0.14) !important;
|
||||
}
|
||||
|
||||
.bg-gray-100 {
|
||||
background-color: var(--admin-bg-muted) !important;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.bg-gray-50 {
|
||||
background-color: var(--admin-bg-hover) !important;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.bg-gray-50\/60 {
|
||||
background-color: rgba(48, 48, 48, 0.65) !important;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.border-gray-100,
|
||||
.border-gray-200,
|
||||
.border-gray-300 {
|
||||
border-color: var(--admin-border) !important;
|
||||
}
|
||||
|
||||
.text-gray-400,
|
||||
.text-gray-500 {
|
||||
color: var(--admin-text-secondary) !important;
|
||||
}
|
||||
|
||||
.text-gray-600,
|
||||
.text-gray-700 {
|
||||
color: var(--admin-text-muted) !important;
|
||||
}
|
||||
|
||||
.text-gray-800,
|
||||
.text-gray-900 {
|
||||
color: var(--admin-text) !important;
|
||||
}
|
||||
|
||||
.text-green-700 {
|
||||
color: #4ade80 !important;
|
||||
}
|
||||
|
||||
.text-red-600 {
|
||||
color: #f87171 !important;
|
||||
}
|
||||
|
||||
.ant-menu-light.ant-menu-horizontal {
|
||||
background: transparent !important;
|
||||
border-bottom: 1px solid var(--admin-border) !important;
|
||||
color: var(--admin-text-muted) !important;
|
||||
}
|
||||
|
||||
.ant-menu-light.ant-menu-horizontal > .ant-menu-item,
|
||||
.ant-menu-light.ant-menu-horizontal > .ant-menu-submenu > .ant-menu-submenu-title {
|
||||
color: var(--admin-text-muted) !important;
|
||||
}
|
||||
|
||||
.ant-menu-light.ant-menu-horizontal > .ant-menu-item-selected,
|
||||
.ant-menu-light.ant-menu-horizontal > .ant-menu-submenu-selected > .ant-menu-submenu-title {
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
background: var(--admin-menu-selected) !important;
|
||||
}
|
||||
|
||||
.ant-menu-light.ant-menu-horizontal > .ant-menu-item-selected::after,
|
||||
.ant-menu-light.ant-menu-horizontal > .ant-menu-submenu-selected::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ant-menu-dark.ant-menu-horizontal {
|
||||
background: transparent !important;
|
||||
border-bottom: 1px solid var(--admin-border) !important;
|
||||
}
|
||||
|
||||
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item,
|
||||
.ant-menu-dark.ant-menu-horizontal > .ant-menu-submenu > .ant-menu-submenu-title {
|
||||
color: var(--admin-text-muted) !important;
|
||||
}
|
||||
|
||||
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item-selected,
|
||||
.ant-menu-dark.ant-menu-horizontal > .ant-menu-submenu-selected > .ant-menu-submenu-title {
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
background: var(--admin-menu-selected) !important;
|
||||
}
|
||||
|
||||
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item-selected .ant-menu-item-icon,
|
||||
.ant-menu-dark.ant-menu-horizontal > .ant-menu-submenu-selected .ant-menu-item-icon,
|
||||
.ant-menu-dark.ant-menu-horizontal > .ant-menu-submenu-selected .ant-menu-submenu-arrow {
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
}
|
||||
|
||||
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item-selected::after,
|
||||
.ant-menu-dark.ant-menu-horizontal > .ant-menu-submenu-selected::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ant-modal-content,
|
||||
.ant-modal-header,
|
||||
.ant-modal-body {
|
||||
background-color: #1f1f1f !important;
|
||||
color: rgba(255, 255, 255, 0.85) !important;
|
||||
}
|
||||
|
||||
.ant-modal-footer {
|
||||
background-color: #1f1f1f !important;
|
||||
border-top: 1px solid var(--admin-border-strong) !important;
|
||||
}
|
||||
|
||||
.ant-modal-title,
|
||||
.ant-modal-close-x {
|
||||
color: rgba(255, 255, 255, 0.85) !important;
|
||||
}
|
||||
|
||||
.ant-tabs-tab {
|
||||
color: rgba(255, 255, 255, 0.65) !important;
|
||||
}
|
||||
|
||||
.ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn {
|
||||
color: var(--admin-gold-light) !important;
|
||||
}
|
||||
|
||||
.ant-tabs-ink-bar {
|
||||
background: var(--admin-gold-light) !important;
|
||||
}
|
||||
|
||||
.ant-card {
|
||||
background: #1f1f1f !important;
|
||||
border-color: var(--admin-border-strong) !important;
|
||||
color: rgba(255, 255, 255, 0.85) !important;
|
||||
}
|
||||
|
||||
.ant-card-body {
|
||||
padding: 12px !important;
|
||||
}
|
||||
|
||||
.ant-card-head {
|
||||
background: #1f1f1f !important;
|
||||
border-color: var(--admin-border-strong) !important;
|
||||
color: rgba(255, 255, 255, 0.85) !important;
|
||||
}
|
||||
|
||||
.ant-input,
|
||||
.ant-input-affix-wrapper,
|
||||
.ant-select-selector,
|
||||
.ant-picker,
|
||||
.ant-divider {
|
||||
border-color: var(--admin-border-strong) !important;
|
||||
}
|
||||
|
||||
.ant-descriptions-item-label,
|
||||
.ant-descriptions-item-content {
|
||||
color: rgba(255, 255, 255, 0.85) !important;
|
||||
}
|
||||
|
||||
.top-menu-nav .ant-menu-horizontal > .ant-menu-item,
|
||||
.top-menu-nav .ant-menu-horizontal > .ant-menu-submenu,
|
||||
.top-menu-nav .ant-menu-horizontal > .ant-menu-submenu > .ant-menu-submenu-title {
|
||||
padding: 0 10px !important;
|
||||
height: 36px !important;
|
||||
line-height: 36px !important;
|
||||
margin-top: 0 !important;
|
||||
top: 0 !important;
|
||||
transition: background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease !important;
|
||||
}
|
||||
|
||||
.ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-selected,
|
||||
.ant-menu.ant-menu-dark .ant-menu-item-selected {
|
||||
background-color: var(--admin-menu-selected) !important;
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
}
|
||||
|
||||
.ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-selected .ant-menu-item-icon,
|
||||
.ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-selected .anticon,
|
||||
.ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-selected .ant-menu-title-content,
|
||||
.ant-menu.ant-menu-dark .ant-menu-item-selected .ant-menu-item-icon,
|
||||
.ant-menu.ant-menu-dark .ant-menu-item-selected .anticon,
|
||||
.ant-menu.ant-menu-dark .ant-menu-item-selected .ant-menu-title-content {
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
}
|
||||
|
||||
.ant-menu-dark .ant-menu-item:not(.ant-menu-item-selected):hover,
|
||||
.ant-menu-dark .ant-menu-submenu:not(.ant-menu-submenu-selected) > .ant-menu-submenu-title:hover {
|
||||
background-color: var(--admin-bg-hover) !important;
|
||||
color: var(--admin-gold-light) !important;
|
||||
}
|
||||
|
||||
.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
background: var(--admin-gold-light) !important;
|
||||
border-color: var(--admin-gold-light) !important;
|
||||
}
|
||||
|
||||
.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover,
|
||||
.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active {
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
background: var(--admin-gold-hover) !important;
|
||||
border-color: var(--admin-gold-hover) !important;
|
||||
}
|
||||
|
||||
.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)::before,
|
||||
.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover::before,
|
||||
.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active::before {
|
||||
background-color: var(--admin-gold-light) !important;
|
||||
}
|
||||
|
||||
.ant-radio-button-wrapper:hover {
|
||||
color: var(--admin-gold-hover) !important;
|
||||
}
|
||||
|
||||
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
|
||||
color: var(--admin-gold-light) !important;
|
||||
border-color: var(--admin-gold-light) !important;
|
||||
}
|
||||
|
||||
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)::before {
|
||||
background-color: var(--admin-gold-light) !important;
|
||||
}
|
||||
|
||||
.ant-input:focus,
|
||||
.ant-input-focused,
|
||||
.ant-input-affix-wrapper-focused,
|
||||
.ant-input-affix-wrapper:focus,
|
||||
.ant-select-focused:not(.ant-select-disabled) .ant-select-selector,
|
||||
.ant-picker-focused {
|
||||
border-color: var(--admin-gold-light) !important;
|
||||
box-shadow: 0 0 0 2px rgba(212, 175, 55, 0.18) !important;
|
||||
}
|
||||
}
|
||||
@@ -26,9 +26,15 @@ html{
|
||||
@header-height:56px;
|
||||
@prefixCls-font-family: 'iran-sans';
|
||||
@ant-prefix: @prefixCls;
|
||||
@primary-color:#2563eb; // #727071; //#abc2f7; //#f4474d;
|
||||
@second-color: #3b82f6; // #727071; //#abc2f7; //#f4474d;
|
||||
@third-color: #B2B2B2; // #727071; //#abc2f7; //#f4474d;
|
||||
@gold-color: #c9a227;
|
||||
@gold-color-light: #d4af37;
|
||||
@gold-color-hover: #e0bc3a;
|
||||
@gold-color-dark: #92670a;
|
||||
@gold-color-muted: rgba(201, 162, 39, 0.14);
|
||||
|
||||
@primary-color: @gold-color-light;
|
||||
@second-color: @gold-color-hover;
|
||||
@third-color: @gold-color;
|
||||
|
||||
@bg-color-1: #F9FAFB;
|
||||
@bg-color-2: #F6F6F4;
|
||||
@@ -37,10 +43,10 @@ html{
|
||||
@border-radius-base: 4px;
|
||||
|
||||
html{
|
||||
--ant-primary-color:@primary-color;
|
||||
--ant-primary-color-hover:@second-color;
|
||||
--ant-primary-color-active:@third-color;
|
||||
--ant-primary-1:#f2f3ff;//#f6f6f4;
|
||||
--ant-primary-color: @gold-color-light;
|
||||
--ant-primary-color-hover: @gold-color-hover;
|
||||
--ant-primary-color-active: @gold-color;
|
||||
--ant-primary-1: rgba(201, 162, 39, 0.12);
|
||||
--border-radius-base:@border-radius-base;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
<template>
|
||||
<AButton :type="props.type" :size="props.size" :class="[prefixCls, _class]">
|
||||
<!-- py-1 px-2-->
|
||||
<div
|
||||
class="flex items-center gap-1 justify-center flex-row-reverse gap-2 py-1 px-2"
|
||||
:class="[{ 'flex-row-reverse': suffixIcon }]"
|
||||
>
|
||||
<slot v-if="$slots.default"></slot>
|
||||
|
||||
<BaseIcon :size="iconSize" :icon="icon" v-if="icon" :class="iconClass" />
|
||||
</div>
|
||||
<AButton
|
||||
:type="props.type"
|
||||
:size="props.size"
|
||||
:class="[prefixCls, _class, { [`${prefixCls}--icon-suffix`]: suffixIcon }]"
|
||||
>
|
||||
<span v-if="icon && !suffixIcon" class="base-button__icon">
|
||||
<BaseIcon :size="resolvedIconSize" :icon="icon" :class="iconClass" />
|
||||
</span>
|
||||
<span v-if="$slots.default" class="base-button__label">
|
||||
<slot />
|
||||
</span>
|
||||
<span v-if="icon && suffixIcon" class="base-button__icon">
|
||||
<BaseIcon :size="resolvedIconSize" :icon="icon" :class="iconClass" />
|
||||
</span>
|
||||
</AButton>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { usePrefix } from '@core/composable/usePrefix'
|
||||
import { computed } from 'vue'
|
||||
import { computed, useSlots } from 'vue'
|
||||
import { baseButtonIconSize } from '@root/config'
|
||||
|
||||
interface Props {
|
||||
@@ -24,7 +28,6 @@ interface Props {
|
||||
suffixIcon?: boolean
|
||||
type?: string
|
||||
size?: string
|
||||
// prefixIcon?: string
|
||||
}
|
||||
|
||||
const slot = useSlots()
|
||||
@@ -40,17 +43,74 @@ const { prefixCls } = usePrefix('base-button')
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
iconSize: baseButtonIconSize,
|
||||
// iconLeft: false,
|
||||
iconClass: ''
|
||||
})
|
||||
|
||||
const resolvedIconSize = computed(() => {
|
||||
if (props.iconSize !== baseButtonIconSize) {
|
||||
return props.iconSize
|
||||
}
|
||||
|
||||
switch (props.size) {
|
||||
case 'small':
|
||||
return '16'
|
||||
case 'large':
|
||||
return '20'
|
||||
default:
|
||||
return '18'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix:~'@{prefixCls}-base-button';
|
||||
.@{prefix}{
|
||||
//width: fit-content;
|
||||
padding: 0;
|
||||
height: auto;
|
||||
/*padding: 8px;*/
|
||||
|
||||
.@{prefix} {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
gap: 6px;
|
||||
height: auto !important;
|
||||
min-height: 32px;
|
||||
padding: 4px 15px !important;
|
||||
line-height: 1 !important;
|
||||
white-space: nowrap;
|
||||
overflow: visible;
|
||||
vertical-align: middle;
|
||||
|
||||
&.ant-btn-sm {
|
||||
min-height: 32px;
|
||||
padding: 5px 12px !important;
|
||||
font-size: 14px;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
&.ant-btn-lg {
|
||||
min-height: 40px;
|
||||
padding: 6px 16px !important;
|
||||
}
|
||||
|
||||
&--icon-suffix {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.base-button__icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
line-height: 0;
|
||||
|
||||
:deep(.hr-tamin-icons),
|
||||
:deep(svg) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.base-button__label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
line-height: 1 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
//todo convert to async load
|
||||
import icons from '@core/assets/icons/icon.json'
|
||||
import { usePrefix } from '@core/composable/usePrefix'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
||||
import { baseIconSize } from '@root/config'
|
||||
interface Props {
|
||||
icon: string
|
||||
@@ -27,20 +27,37 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
const { prefixCls } = usePrefix('icons')
|
||||
const tempIcon = ref<string>()
|
||||
const refIcon = ref<HTMLDivElement>()
|
||||
//@ts-ignore
|
||||
tempIcon.value = icons[`${props.icon}`] as string
|
||||
|
||||
function resolveIcon(iconName: string) {
|
||||
return icons[`${iconName}` as keyof typeof icons] as string
|
||||
}
|
||||
|
||||
function applySize() {
|
||||
if (!props.size || !refIcon.value) return
|
||||
|
||||
const svg = refIcon.value.children[0] as SVGElement | undefined
|
||||
if (!svg) return
|
||||
|
||||
svg.setAttribute('width', String(props.size))
|
||||
svg.setAttribute('height', String(props.size))
|
||||
}
|
||||
|
||||
tempIcon.value = resolveIcon(props.icon)
|
||||
|
||||
watch(
|
||||
() => props.icon,
|
||||
(iconName) => {
|
||||
tempIcon.value = resolveIcon(iconName)
|
||||
nextTick(() => applySize())
|
||||
}
|
||||
)
|
||||
|
||||
const color = computed(() => {
|
||||
return props.color
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (props.size) {
|
||||
const svg: SVGElement = refIcon.value?.children[0] as SVGElement
|
||||
// console.log(svg)
|
||||
svg.setAttribute('width', props.size as string)
|
||||
svg.setAttribute('height', props.size as string)
|
||||
// console.log(props.icon)
|
||||
}
|
||||
applySize()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div :class="[prefixCls, 'min-w-0 max-w-full']">
|
||||
<ASpin tip="در حال دریافت اطلاعات..." :indicator="indicator" :spinning="loading">
|
||||
<div class="scrollable-container" id="components-affix-demo-target" ref="containerRef">
|
||||
<div class="table-toolbar sticky top-0 z-10 mb-2 shrink-0 bg-white">
|
||||
<div class="table-toolbar sticky top-0 z-10 mb-2 shrink-0">
|
||||
<div class="flex flex-col gap-2 xl:flex-row xl:items-center xl:justify-between">
|
||||
<div
|
||||
v-if="showOptionHeader"
|
||||
@@ -707,12 +707,16 @@ defineExpose({
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.table-toolbar {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.table-toolbar-extra:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ant-table-wrapper {
|
||||
border: 1px solid #eee;
|
||||
border: 1px solid var(--admin-border);
|
||||
border-radius: var(--border-radius-base);
|
||||
}
|
||||
.ant-spin-container,
|
||||
|
||||
@@ -673,7 +673,7 @@ defineExpose({
|
||||
overflow-y: auto;
|
||||
}
|
||||
.ant-table-wrapper {
|
||||
border: 1px solid #eee;
|
||||
border: 1px solid var(--admin-border);
|
||||
border-radius: var(--border-radius-base);
|
||||
}
|
||||
.ant-spin-container,
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<AMenuItemGroup title="پوسته">
|
||||
<AMenuItem
|
||||
v-for="opt in themeOptions"
|
||||
:key="opt.value"
|
||||
@click="darkmode.setSchema(opt.value)"
|
||||
>
|
||||
<div class="theme-menu-item" :class="{ 'theme-menu-item--active': colorSchema === opt.value }">
|
||||
<div class="theme-menu-item__main">
|
||||
<Icon :icon="opt.icon" size="18" />
|
||||
<span>{{ opt.label }}</span>
|
||||
</div>
|
||||
<Icon
|
||||
v-if="colorSchema === opt.value"
|
||||
icon="vuesax-linear:tick-circle"
|
||||
size="16"
|
||||
class="theme-menu-item__check"
|
||||
/>
|
||||
</div>
|
||||
</AMenuItem>
|
||||
<AMenuItem v-if="colorSchema === 'auto'" disabled class="theme-menu-hint-item">
|
||||
<span class="theme-menu-hint">وضعیت فعلی: {{ isDark ? 'تاریک' : 'روشن' }}</span>
|
||||
</AMenuItem>
|
||||
</AMenuItemGroup>
|
||||
<AMenuDivider />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import Icon from '@core/components/BaseIcon/src/Icon.vue'
|
||||
import { useAdminTheme } from '@core/composable/useAdminTheme'
|
||||
import type { DarkModeSchema } from '@core/stores/darkmode'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
const { isDark, darkmode } = useAdminTheme()
|
||||
const { colorSchema } = storeToRefs(darkmode)
|
||||
|
||||
const themeOptions: Array<{ value: DarkModeSchema; label: string; icon: string }> = [
|
||||
{ value: 'light', label: 'روشن', icon: 'vuesax-linear:sun-1' },
|
||||
{ value: 'dark', label: 'تاریک', icon: 'vuesax-linear:moon' },
|
||||
{ value: 'auto', label: 'سیستم', icon: 'vuesax-linear:monitor' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.theme-menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-width: 10rem;
|
||||
}
|
||||
|
||||
.theme-menu-item__main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.theme-menu-item--active {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.theme-menu-item__check {
|
||||
color: var(--admin-gold-light, #d4af37);
|
||||
}
|
||||
|
||||
.theme-menu-hint-item {
|
||||
height: auto !important;
|
||||
line-height: 1.3 !important;
|
||||
cursor: default !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.theme-menu-hint {
|
||||
font-size: 11px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
html.is-dark .theme-menu-hint {
|
||||
color: rgba(255, 255, 255, 0.45);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<div class="theme-toggle">
|
||||
<span v-if="showLabel" class="theme-toggle__label">پوسته</span>
|
||||
<APopover
|
||||
v-model:open="open"
|
||||
trigger="click"
|
||||
placement="bottomLeft"
|
||||
overlay-class-name="theme-toggle-popover"
|
||||
>
|
||||
<template #content>
|
||||
<div class="theme-toggle__menu">
|
||||
<button
|
||||
v-for="opt in themeOptions"
|
||||
:key="opt.value"
|
||||
type="button"
|
||||
class="theme-toggle__option"
|
||||
:class="{ 'theme-toggle__option--active': colorSchema === opt.value }"
|
||||
@click="selectSchema(opt.value)"
|
||||
>
|
||||
<BaseIcon :icon="opt.icon" size="18" />
|
||||
<span>{{ opt.label }}</span>
|
||||
</button>
|
||||
<div v-if="colorSchema === 'auto'" class="theme-toggle__hint">
|
||||
وضعیت فعلی: {{ isDark ? 'تاریک' : 'روشن' }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<BaseButton
|
||||
type="text"
|
||||
:icon="triggerIcon"
|
||||
icon-size="20"
|
||||
aria-label="انتخاب پوسته"
|
||||
/>
|
||||
</APopover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BaseIcon from '@core/components/BaseIcon/src/Icon.vue'
|
||||
import { useAdminTheme } from '@core/composable/useAdminTheme'
|
||||
import type { DarkModeSchema } from '@core/stores/darkmode'
|
||||
import { computed, ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
showLabel?: boolean
|
||||
}>(),
|
||||
{
|
||||
showLabel: true
|
||||
}
|
||||
)
|
||||
|
||||
const open = ref(false)
|
||||
const { isDark, darkmode } = useAdminTheme()
|
||||
const { colorSchema } = storeToRefs(darkmode)
|
||||
|
||||
const themeOptions: Array<{ value: DarkModeSchema; label: string; icon: string }> = [
|
||||
{ value: 'light', label: 'روشن', icon: 'vuesax-linear:sun-1' },
|
||||
{ value: 'dark', label: 'تاریک', icon: 'vuesax-linear:moon' },
|
||||
{ value: 'auto', label: 'سیستم', icon: 'vuesax-linear:monitor' }
|
||||
]
|
||||
|
||||
const triggerIcon = computed(() => {
|
||||
if (colorSchema.value === 'dark') return 'vuesax-linear:moon'
|
||||
if (colorSchema.value === 'light') return 'vuesax-linear:sun-1'
|
||||
return 'vuesax-linear:monitor'
|
||||
})
|
||||
|
||||
function selectSchema(schema: DarkModeSchema) {
|
||||
darkmode.setSchema(schema)
|
||||
open.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.theme-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.theme-toggle__label {
|
||||
font-size: 13px;
|
||||
color: var(--admin-text-secondary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.theme-toggle__menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
min-width: 9rem;
|
||||
}
|
||||
|
||||
.theme-toggle__option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
padding: 8px 10px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
background: transparent;
|
||||
color: var(--admin-text);
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease, color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background: var(--admin-bg-hover);
|
||||
color: var(--admin-gold-light);
|
||||
}
|
||||
|
||||
&--active {
|
||||
background: var(--admin-menu-selected);
|
||||
color: var(--admin-menu-selected-text);
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.theme-toggle__hint {
|
||||
margin-top: 4px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid var(--admin-border);
|
||||
font-size: 11px;
|
||||
color: var(--admin-text-secondary);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.theme-toggle-popover {
|
||||
.ant-popover-inner {
|
||||
background: var(--admin-bg-elevated);
|
||||
border: 1px solid var(--admin-border-strong);
|
||||
}
|
||||
|
||||
.ant-popover-inner-content {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.ant-popover-arrow-content::before {
|
||||
background: var(--admin-bg-elevated);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,17 @@
|
||||
import { computed } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useDarkmode } from '@core/stores/darkmode'
|
||||
|
||||
export function useAdminTheme() {
|
||||
const darkmode = useDarkmode()
|
||||
const { isDark, colorSchema } = storeToRefs(darkmode)
|
||||
|
||||
const menuTheme = computed(() => (isDark.value ? 'dark' : 'light') as 'dark' | 'light')
|
||||
|
||||
return {
|
||||
isDark,
|
||||
colorSchema,
|
||||
menuTheme,
|
||||
darkmode,
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,14 @@
|
||||
</template>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<span class="text-gray-400 text-sm">حالت نمایش</span>
|
||||
<ARadioGroup v-model:value="colorSchema" size="small">
|
||||
<ARadioButton value="light">روشن</ARadioButton>
|
||||
<ARadioButton value="dark">تاریک</ARadioButton>
|
||||
<ARadioButton value="auto">خودکار</ARadioButton>
|
||||
</ARadioGroup>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-400 text-sm">نوار کناری (Sidebar)</span>
|
||||
<ASwitch :checked="true" size="small" />
|
||||
@@ -59,10 +67,14 @@
|
||||
import { usePrefix } from '@core/composable/usePrefix'
|
||||
import { useSettingsStore } from '@core/stores/settings'
|
||||
import { useLayoutStore } from '@core/stores/layout'
|
||||
import { useDarkmode } from '@core/stores/darkmode'
|
||||
import { storeToRefs } from 'pinia'
|
||||
//const visible = ref<boolean>(false)
|
||||
const { prefixCls } = usePrefix('base-settings')
|
||||
const settingsStore = useSettingsStore()
|
||||
const layoutStore = useLayoutStore()
|
||||
const darkmode = useDarkmode()
|
||||
const { colorSchema } = storeToRefs(darkmode)
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@@ -71,7 +83,7 @@ const layoutStore = useLayoutStore()
|
||||
|
||||
.layout-item{
|
||||
cursor: pointer;
|
||||
border:2px solid #eee;
|
||||
border:2px solid var(--admin-border);
|
||||
padding:5px;
|
||||
&.active{
|
||||
border-color: @primary-color;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<!-- :class="[, isMobile ? null : 'shadow']"-->
|
||||
<!-- :theme="sideTheme"-->
|
||||
<ALayoutSider
|
||||
theme="light"
|
||||
:theme="menuTheme"
|
||||
:class="[prefixCls]"
|
||||
:width="layoutStore.sideMenu.width"
|
||||
:collapsible="layoutStore.sideMenu.collapsible"
|
||||
@@ -96,10 +96,12 @@
|
||||
import { useLayoutStore } from '@core/stores/layout'
|
||||
import { usePrefix } from '@core/composable/usePrefix'
|
||||
import BasicMenu from '@core/layouts/composnts/BasicMenu.vue'
|
||||
import { useAdminTheme } from '@core/composable/useAdminTheme'
|
||||
//import { coreVersion, version } from '../utils'
|
||||
//import { isDate } from 'lodash'
|
||||
const layoutStore = useLayoutStore()
|
||||
const { prefixCls } = usePrefix('basic-side-menu')
|
||||
const { menuTheme } = useAdminTheme()
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@@ -124,13 +126,13 @@ const { prefixCls } = usePrefix('basic-side-menu')
|
||||
}
|
||||
|
||||
.logo{
|
||||
border-bottom: 1px solid #eee;
|
||||
border-bottom: 1px solid var(--admin-border);
|
||||
overflow: hidden;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.side-version{
|
||||
border-top: 1px solid #eee;
|
||||
border-top: 1px solid var(--admin-border);
|
||||
@apply p-2;
|
||||
max-height: 50px
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<ALayoutHeader
|
||||
theme="light"
|
||||
:theme="menuTheme"
|
||||
:class="[prefixCls]"
|
||||
:style="`height:${layoutStore.header.height};line-height:${layoutStore.header.height}`"
|
||||
:style="`height:${layoutStore.header.height}`"
|
||||
>
|
||||
<!-- :style="`height:${layoutStore.header.height};line-height:${layoutStore.header.height}`"-->
|
||||
<div class="flex w-full min-w-0 items-center overflow-hidden">
|
||||
@@ -26,8 +26,8 @@
|
||||
<ADropdown placement="bottomLeft" class="ml-5">
|
||||
<a class="ant-dropdown-link" @click.prevent>
|
||||
<!-- Hover me-->
|
||||
<div class="flex items-center gap-1 text-gray-400">
|
||||
<AAvatar :src="placeholderM" />
|
||||
<div class="flex items-center gap-1 text-[var(--admin-text-secondary)]">
|
||||
<AAvatar :src="placeholderM" class="header-avatar" />
|
||||
<Icon icon="vuesax-linear:arrow-down" size="15" />
|
||||
</div>
|
||||
</a>
|
||||
@@ -40,6 +40,7 @@
|
||||
</div>
|
||||
</AMenuItem>
|
||||
<AMenuDivider />
|
||||
<ThemeMenuSection />
|
||||
<AMenuItem @click="myInfoVisible = true">
|
||||
<div class="flex items-center gap-1">
|
||||
<Icon icon="vuesax-linear:profile" size="18" />
|
||||
@@ -164,11 +165,14 @@ import type { FormInstance } from 'ant-design-vue'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import {getConfigApp} from "@/utils/config";
|
||||
import ThemeMenuSection from '@core/components/ThemeMenuSection.vue'
|
||||
import { useAdminTheme } from '@core/composable/useAdminTheme'
|
||||
const { prefixCls } = usePrefix('basic-header')
|
||||
const layoutStore = useLayoutStore()
|
||||
const store = useStaticApiListsStore()
|
||||
const userStore = useUserStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const { menuTheme } = useAdminTheme()
|
||||
|
||||
|
||||
const { width } = useWindowSize()
|
||||
@@ -223,7 +227,11 @@ function handleShowSettings() {
|
||||
}
|
||||
|
||||
function clearLocalStorage() {
|
||||
const colorSchema = localStorage.getItem('color-schema')
|
||||
localStorage.clear()
|
||||
if (colorSchema) {
|
||||
localStorage.setItem('color-schema', colorSchema)
|
||||
}
|
||||
location.reload()
|
||||
}
|
||||
</script>
|
||||
@@ -232,16 +240,35 @@ function clearLocalStorage() {
|
||||
@prefix: ~'@{prefixCls}-basic-header';
|
||||
|
||||
.@{prefix} {
|
||||
padding: unset;
|
||||
padding: 0 12px !important;
|
||||
line-height: normal !important;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
//height: unset;
|
||||
//@apply flex flex-col justify-center ;
|
||||
//height: 64px;
|
||||
//line-height: unset;
|
||||
border-bottom: 2px solid #eee;
|
||||
// height: @header-height;
|
||||
background-color: #fff;
|
||||
//@apply backdrop-blur bg-red-200;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--admin-border);
|
||||
background-color: var(--admin-bg-surface);
|
||||
|
||||
> .flex {
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-avatar {
|
||||
border: 2px solid var(--admin-border-strong);
|
||||
}
|
||||
|
||||
.hr-tamin-base-button.ant-btn-text {
|
||||
color: var(--admin-text-secondary);
|
||||
background: transparent !important;
|
||||
border-color: transparent !important;
|
||||
box-shadow: none !important;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--admin-text);
|
||||
background: var(--admin-bg-hover) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
>
|
||||
<AMenu
|
||||
:mode="layoutStore.sideMenu.mode"
|
||||
:theme="menuTheme"
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
:disabled-overflow="isTopMenu"
|
||||
>
|
||||
@@ -64,6 +65,7 @@ import { useLayoutStore } from '@core/stores/layout'
|
||||
import BaseMenuItem from '@core/layouts/composnts/BaseMenuItem.vue'
|
||||
import type { RouteRecordName, RouteRecordRaw } from 'vue-router'
|
||||
import { useRouterStore } from '@core/stores/router'
|
||||
import { useAdminTheme } from '@core/composable/useAdminTheme'
|
||||
|
||||
const SCROLL_STEP = 180
|
||||
const EDGE_THRESHOLD = 2
|
||||
@@ -73,6 +75,7 @@ const layoutStore = useLayoutStore()
|
||||
const currentRoute = useRoute()
|
||||
const selectedKeys = ref<(RouteRecordName | undefined)[]>([])
|
||||
const routerStore = useRouterStore()
|
||||
const { menuTheme } = useAdminTheme()
|
||||
const menuScrollRef = ref<HTMLElement | null>(null)
|
||||
const showLeftArrow = ref(false)
|
||||
const showRightArrow = ref(false)
|
||||
@@ -224,6 +227,77 @@ useResizeObserver(menuScrollRef, () => {
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.top-menu-scroll .ant-menu.ant-menu-horizontal {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
width: max-content;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
border-bottom: none !important;
|
||||
padding: 0 4px !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.top-menu-scroll .ant-menu-horizontal > .ant-menu-item,
|
||||
.top-menu-scroll .ant-menu-horizontal > .ant-menu-submenu,
|
||||
.top-menu-scroll .ant-menu-horizontal > .ant-menu-submenu > .ant-menu-submenu-title {
|
||||
top: 0 !important;
|
||||
margin-top: 0 !important;
|
||||
height: 36px !important;
|
||||
line-height: 36px !important;
|
||||
padding: 0 10px !important;
|
||||
margin-inline: 2px !important;
|
||||
border-radius: 6px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
transition: background-color 0.15s ease, color 0.15s ease !important;
|
||||
}
|
||||
|
||||
.top-menu-scroll .ant-menu-horizontal > .ant-menu-item::after,
|
||||
.top-menu-scroll .ant-menu-horizontal > .ant-menu-submenu::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.top-menu-scroll .ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item-selected,
|
||||
.top-menu-scroll .ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu-selected {
|
||||
background-color: var(--admin-menu-selected);
|
||||
color: var(--admin-menu-selected-text);
|
||||
}
|
||||
|
||||
.top-menu-scroll .ant-menu-horizontal.ant-menu-dark > .ant-menu-item-selected,
|
||||
.top-menu-scroll .ant-menu-horizontal.ant-menu-dark > .ant-menu-submenu-selected > .ant-menu-submenu-title {
|
||||
background-color: var(--admin-menu-selected) !important;
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
}
|
||||
|
||||
.top-menu-scroll .ant-menu-horizontal.ant-menu-dark > .ant-menu-item-selected .ant-menu-item-icon,
|
||||
.top-menu-scroll .ant-menu-horizontal.ant-menu-dark > .ant-menu-submenu-selected .ant-menu-item-icon,
|
||||
.top-menu-scroll .ant-menu-horizontal.ant-menu-dark > .ant-menu-submenu-selected .ant-menu-submenu-arrow {
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
}
|
||||
|
||||
.top-menu-scroll .ant-menu-horizontal.ant-menu-dark > .ant-menu-item:not(.ant-menu-item-selected):hover,
|
||||
.top-menu-scroll .ant-menu-horizontal.ant-menu-dark > .ant-menu-submenu:not(.ant-menu-submenu-selected):hover > .ant-menu-submenu-title {
|
||||
background-color: var(--admin-bg-hover) !important;
|
||||
color: var(--admin-gold-light) !important;
|
||||
box-shadow: inset 0 0 0 1px var(--admin-border-strong) !important;
|
||||
}
|
||||
|
||||
.top-menu-scroll .ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item-selected::after,
|
||||
.top-menu-scroll .ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu-selected::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.top-menu-scroll .ant-menu-horizontal .ant-menu-item-icon + .ant-menu-title-content,
|
||||
.top-menu-scroll .ant-menu-horizontal .ant-menu-item-icon + span {
|
||||
margin-inline-start: 6px !important;
|
||||
margin-inline-end: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.top-menu-nav__btn {
|
||||
@@ -233,31 +307,31 @@ useResizeObserver(menuScrollRef, () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 36px;
|
||||
width: 28px;
|
||||
height: 32px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
color: @primary-color;
|
||||
background: var(--admin-bg-elevated);
|
||||
color: var(--admin-gold-light);
|
||||
cursor: pointer;
|
||||
transform: translateY(-50%);
|
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06);
|
||||
box-shadow: 0 0 0 1px var(--admin-border);
|
||||
transition: background-color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: lighten(@primary-color, 53%);
|
||||
background: var(--admin-bg-hover);
|
||||
}
|
||||
|
||||
&--left {
|
||||
left: 0;
|
||||
padding-right: 4px;
|
||||
background: linear-gradient(to right, #fff 55%, rgba(255, 255, 255, 0.85));
|
||||
padding-right: 2px;
|
||||
background: linear-gradient(to right, var(--admin-gradient-surface) 60%, var(--admin-gradient-surface-fade));
|
||||
}
|
||||
|
||||
&--right {
|
||||
right: 0;
|
||||
padding-left: 4px;
|
||||
background: linear-gradient(to left, #fff 55%, rgba(255, 255, 255, 0.85));
|
||||
padding-left: 2px;
|
||||
background: linear-gradient(to left, var(--admin-gradient-surface) 60%, var(--admin-gradient-surface-fade));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,48 +341,14 @@ useResizeObserver(menuScrollRef, () => {
|
||||
overflow-y: hidden;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ant-menu {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
width: max-content;
|
||||
border-bottom: none;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item,
|
||||
.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu {
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.ant-menu-horizontal > .ant-menu-item::after,
|
||||
.ant-menu-horizontal > .ant-menu-submenu::after {
|
||||
right: 0 !important;
|
||||
left: 0 !important;
|
||||
}
|
||||
|
||||
.ant-menu-horizontal > .ant-menu-item-selected::after,
|
||||
.ant-menu-horizontal > .ant-menu-submenu-selected::after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
border-bottom: 2px solid @primary-color;
|
||||
transition: border-color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
content: '';
|
||||
}
|
||||
|
||||
.ant-menu-item-selected {
|
||||
background-color: lighten(@primary-color, 53%);
|
||||
}
|
||||
|
||||
.ant-menu-item {
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-item,
|
||||
@@ -321,40 +361,34 @@ useResizeObserver(menuScrollRef, () => {
|
||||
}
|
||||
}
|
||||
|
||||
/** start style for horizontal menu */
|
||||
|
||||
.ant-menu-horizontal {
|
||||
padding: 0 !important;
|
||||
|
||||
li {
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
/** end style for horizontal menu */
|
||||
|
||||
&-side-menu {
|
||||
.ant-menu-item:not(.ant-menu-item-disabled):not(.ant-menu-item-selected):hover,
|
||||
.ant-menu-submenu .ant-menu-submenu-title:not(.ant-menu-item-disabled):hover {
|
||||
.ant-menu:not(.ant-menu-dark) .ant-menu-item:not(.ant-menu-item-disabled):not(.ant-menu-item-selected):hover,
|
||||
.ant-menu:not(.ant-menu-dark) .ant-menu-submenu .ant-menu-submenu-title:not(.ant-menu-item-disabled):hover {
|
||||
transition: background-color 0.9ms linear;
|
||||
border-radius: var(--border-radius-base);
|
||||
color: unset !important;
|
||||
background-color: #f3f3f3 !important;
|
||||
background-color: var(--admin-bg-hover) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu {
|
||||
.ant-menu:not(.ant-menu-horizontal) {
|
||||
padding: 10px;
|
||||
user-select: none;
|
||||
|
||||
.ant-menu-item,
|
||||
.ant-menu-submenu-title {
|
||||
@apply px-2 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-title-content {
|
||||
font-size: 15px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.ant-menu-item,
|
||||
.ant-menu-submenu-title {
|
||||
@apply px-2 !important;
|
||||
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item.ant-menu-item-selected {
|
||||
&::after {
|
||||
content: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu.ant-menu-inline-collapsed > .ant-menu-item .ant-menu-item-icon + span,
|
||||
@@ -380,12 +414,6 @@ useResizeObserver(menuScrollRef, () => {
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.ant-menu-item.ant-menu-item-selected {
|
||||
&::after {
|
||||
content: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu.ant-menu-sub.ant-menu-inline {
|
||||
background-color: unset !important;
|
||||
}
|
||||
|
||||
@@ -64,11 +64,13 @@ const menu = computed(() => {
|
||||
@prefix:~ '@{prefixCls}-basic-sub-menu';
|
||||
.@{prefix}{
|
||||
|
||||
&.ant-menu-submenu-selected{
|
||||
&.ant-menu-submenu-selected {
|
||||
border-radius: var(--border-radius-base);
|
||||
background-color: var(--ant-primary-1);
|
||||
.ant-menu-submenu-arrow{
|
||||
color: var(--ant-primary)
|
||||
background-color: var(--admin-menu-selected);
|
||||
color: var(--admin-menu-selected-text);
|
||||
|
||||
.ant-menu-submenu-arrow {
|
||||
color: var(--admin-menu-selected-text);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import { computed, watchEffect } from 'vue'
|
||||
import { usePreferredDark, useStorage } from '@vueuse/core'
|
||||
import { acceptHMRUpdate, defineStore } from 'pinia'
|
||||
import { syncAntDarkStyle } from '@core/utils/syncAntDarkStyle'
|
||||
|
||||
export const DARK_MODE_BODY_CLASS = 'is-dark'
|
||||
export type DarkModeSchema = 'auto' | 'dark' | 'light'
|
||||
@@ -24,13 +25,16 @@ export const initDarkmode = () => {
|
||||
*/
|
||||
watchEffect(() => {
|
||||
if (!import.meta.env.SSR) {
|
||||
const body = document.documentElement
|
||||
const root = document.documentElement
|
||||
const isDark = darkmode.isDark
|
||||
|
||||
if (darkmode.isDark) {
|
||||
body.classList.add(DARK_MODE_BODY_CLASS)
|
||||
if (isDark) {
|
||||
root.classList.add(DARK_MODE_BODY_CLASS)
|
||||
} else {
|
||||
body.classList.remove(DARK_MODE_BODY_CLASS)
|
||||
root.classList.remove(DARK_MODE_BODY_CLASS)
|
||||
}
|
||||
|
||||
void syncAntDarkStyle(isDark)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -56,9 +60,20 @@ export const useDarkmode = defineStore('darkmode', () => {
|
||||
isDark.value = !target.checked
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
isDark.value = !isDark.value
|
||||
}
|
||||
|
||||
function setSchema(schema: DarkModeSchema) {
|
||||
colorSchema.value = schema
|
||||
}
|
||||
|
||||
return {
|
||||
isDark,
|
||||
colorSchema,
|
||||
onChange,
|
||||
toggle,
|
||||
setSchema,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export const useLayoutStore = defineStore('layout', () => {
|
||||
})*/
|
||||
|
||||
const header = reactive({
|
||||
height: '45px',
|
||||
height: '56px',
|
||||
fixed: true
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
const STYLE_ATTR = 'data-antd-dark'
|
||||
|
||||
const BRAND_OVERRIDES = `
|
||||
html.is-dark body {
|
||||
background-color: #141414;
|
||||
}
|
||||
html.is-dark {
|
||||
--ant-primary-color: #d4af37;
|
||||
--ant-primary-color-hover: #e0bc3a;
|
||||
--ant-primary-color-active: #c9a227;
|
||||
--admin-menu-selected: #d4af37;
|
||||
--admin-menu-selected-text: #141414;
|
||||
}
|
||||
html.is-dark .ant-layout-header {
|
||||
background: #141414 !important;
|
||||
border-bottom: 1px solid var(--admin-border-strong) !important;
|
||||
padding: 0 12px !important;
|
||||
}
|
||||
html.is-dark .top-menu-nav .ant-menu-dark.ant-menu-horizontal {
|
||||
background: transparent !important;
|
||||
}
|
||||
html.is-dark .ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-selected,
|
||||
html.is-dark .ant-menu.ant-menu-dark .ant-menu-item-selected,
|
||||
html.is-dark .top-menu-nav .ant-menu-dark.ant-menu-horizontal > .ant-menu-item-selected,
|
||||
html.is-dark .top-menu-nav .ant-menu-dark.ant-menu-horizontal > .ant-menu-submenu-selected > .ant-menu-submenu-title {
|
||||
background-color: var(--admin-menu-selected) !important;
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
}
|
||||
html.is-dark .ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-selected .ant-menu-item-icon,
|
||||
html.is-dark .ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-selected .anticon,
|
||||
html.is-dark .ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-selected .ant-menu-title-content,
|
||||
html.is-dark .ant-menu.ant-menu-dark .ant-menu-item-selected .ant-menu-item-icon,
|
||||
html.is-dark .ant-menu.ant-menu-dark .ant-menu-item-selected .anticon,
|
||||
html.is-dark .ant-menu.ant-menu-dark .ant-menu-item-selected .ant-menu-title-content,
|
||||
html.is-dark .top-menu-nav .ant-menu-dark.ant-menu-horizontal > .ant-menu-item-selected .ant-menu-item-icon,
|
||||
html.is-dark .top-menu-nav .ant-menu-dark.ant-menu-horizontal > .ant-menu-submenu-selected .ant-menu-item-icon,
|
||||
html.is-dark .top-menu-nav .ant-menu-dark.ant-menu-horizontal > .ant-menu-submenu-selected .ant-menu-submenu-arrow {
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
}
|
||||
html.is-dark .ant-menu-dark .ant-menu-item:not(.ant-menu-item-selected):hover,
|
||||
html.is-dark .ant-menu-dark .ant-menu-submenu:not(.ant-menu-submenu-selected) > .ant-menu-submenu-title:hover,
|
||||
html.is-dark .top-menu-nav .ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover,
|
||||
html.is-dark .top-menu-nav .ant-menu-dark.ant-menu-horizontal > .ant-menu-submenu:hover > .ant-menu-submenu-title {
|
||||
background-color: var(--admin-bg-hover) !important;
|
||||
color: var(--admin-gold-light) !important;
|
||||
box-shadow: inset 0 0 0 1px var(--admin-border-strong) !important;
|
||||
}
|
||||
html.is-dark .hr-tamin-base-button {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
height: auto !important;
|
||||
line-height: 1 !important;
|
||||
}
|
||||
html.is-dark .hr-tamin-base-button.ant-btn-sm {
|
||||
min-height: 32px !important;
|
||||
padding: 5px 12px !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
html.is-dark .ant-card-body {
|
||||
padding: 12px !important;
|
||||
}
|
||||
html.is-dark .ant-card,
|
||||
html.is-dark .ant-card-head {
|
||||
border-color: var(--admin-border-strong) !important;
|
||||
}
|
||||
html.is-dark .ant-input,
|
||||
html.is-dark .ant-input-affix-wrapper,
|
||||
html.is-dark .ant-select-selector,
|
||||
html.is-dark .ant-picker {
|
||||
border-color: var(--admin-border-strong) !important;
|
||||
}
|
||||
html.is-dark .ant-input:focus,
|
||||
html.is-dark .ant-input-focused,
|
||||
html.is-dark .ant-input-affix-wrapper-focused,
|
||||
html.is-dark .ant-input-affix-wrapper:focus,
|
||||
html.is-dark .ant-select-focused:not(.ant-select-disabled) .ant-select-selector,
|
||||
html.is-dark .ant-picker-focused {
|
||||
border-color: var(--admin-gold-light) !important;
|
||||
box-shadow: 0 0 0 2px rgba(212, 175, 55, 0.18) !important;
|
||||
}
|
||||
html.is-dark .ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
background: var(--admin-gold-light) !important;
|
||||
border-color: var(--admin-gold-light) !important;
|
||||
}
|
||||
html.is-dark .ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover,
|
||||
html.is-dark .ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active {
|
||||
color: var(--admin-menu-selected-text) !important;
|
||||
background: var(--admin-gold-hover) !important;
|
||||
border-color: var(--admin-gold-hover) !important;
|
||||
}
|
||||
html.is-dark .ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)::before,
|
||||
html.is-dark .ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover::before,
|
||||
html.is-dark .ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active::before {
|
||||
background-color: var(--admin-gold-light) !important;
|
||||
}
|
||||
html.is-dark .ant-radio-button-wrapper:hover {
|
||||
color: var(--admin-gold-hover) !important;
|
||||
}
|
||||
html.is-dark .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
|
||||
color: var(--admin-gold-light) !important;
|
||||
border-color: var(--admin-gold-light) !important;
|
||||
}
|
||||
html.is-dark .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)::before {
|
||||
background-color: var(--admin-gold-light) !important;
|
||||
}
|
||||
html.is-dark .ant-btn-primary {
|
||||
background: var(--admin-gold-light) !important;
|
||||
border-color: var(--admin-gold-light) !important;
|
||||
}
|
||||
html.is-dark .ant-btn-primary:not([disabled]):hover,
|
||||
html.is-dark .ant-btn-primary:not([disabled]):focus {
|
||||
background: var(--admin-gold-hover) !important;
|
||||
border-color: var(--admin-gold-hover) !important;
|
||||
}
|
||||
html.is-dark .ant-btn-default:not([disabled]):hover,
|
||||
html.is-dark .ant-btn-default:not([disabled]):focus {
|
||||
color: var(--admin-gold-light) !important;
|
||||
border-color: var(--admin-gold-light) !important;
|
||||
}
|
||||
@media (max-width: 376px) {
|
||||
html.is-dark .ant-card-body {
|
||||
padding: 5px !important;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
let darkStyleEl: HTMLStyleElement | null = null
|
||||
let loadingPromise: Promise<void> | null = null
|
||||
|
||||
async function injectDarkStyle() {
|
||||
if (darkStyleEl) return
|
||||
|
||||
if (!loadingPromise) {
|
||||
loadingPromise = import('ant-design-vue/dist/antd.dark.css?inline').then((mod) => {
|
||||
darkStyleEl = document.createElement('style')
|
||||
darkStyleEl.setAttribute(STYLE_ATTR, '')
|
||||
darkStyleEl.textContent = `${mod.default}\n${BRAND_OVERRIDES}`
|
||||
document.head.appendChild(darkStyleEl)
|
||||
})
|
||||
}
|
||||
|
||||
await loadingPromise
|
||||
}
|
||||
|
||||
function removeDarkStyle() {
|
||||
darkStyleEl?.remove()
|
||||
darkStyleEl = null
|
||||
loadingPromise = null
|
||||
}
|
||||
|
||||
export async function syncAntDarkStyle(isDark: boolean) {
|
||||
if (import.meta.env.SSR) return
|
||||
|
||||
if (isDark) {
|
||||
await injectDarkStyle()
|
||||
} else {
|
||||
removeDarkStyle()
|
||||
}
|
||||
}
|
||||
@@ -28,25 +28,25 @@ const props = defineProps<Prop>()
|
||||
const bgColor = computed(() => {
|
||||
switch (props.color) {
|
||||
case 'fuchsia':
|
||||
return 'bg-fuchsia-100'
|
||||
return 'bg-fuchsia-100 dark:bg-fuchsia-500/20'
|
||||
case 'orange':
|
||||
return 'bg-orange-100'
|
||||
return 'bg-orange-100 dark:bg-orange-500/20'
|
||||
case 'green':
|
||||
return 'bg-green-100'
|
||||
return 'bg-green-100 dark:bg-green-500/20'
|
||||
case 'blue':
|
||||
return 'bg-blue-100'
|
||||
return 'bg-blue-100 dark:bg-blue-500/20'
|
||||
}
|
||||
})
|
||||
const textColor = computed(() => {
|
||||
switch (props.color) {
|
||||
case 'fuchsia':
|
||||
return 'text-fuchsia-600'
|
||||
return 'text-fuchsia-600 dark:text-fuchsia-300'
|
||||
case 'orange':
|
||||
return 'text-orange-600'
|
||||
return 'text-orange-600 dark:text-orange-300'
|
||||
case 'green':
|
||||
return 'text-green-600'
|
||||
return 'text-green-600 dark:text-green-300'
|
||||
case 'blue':
|
||||
return 'text-blue-600'
|
||||
return 'text-blue-600 dark:text-blue-300'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -859,7 +859,9 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.selected_item {
|
||||
@apply ! bg- [ #0A1B37 ] ! text-white rounded-lg;
|
||||
background: #2563eb !important;
|
||||
color: #fff !important;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dashboard-chart-toolbar {
|
||||
@@ -869,10 +871,10 @@ onMounted(() => {
|
||||
gap: 0.5rem;
|
||||
|
||||
button {
|
||||
border: 1px solid #d1d5db;
|
||||
border: 1px solid var(--admin-border-strong);
|
||||
border-radius: 0.5rem;
|
||||
background: #fff;
|
||||
color: #374151;
|
||||
background: var(--admin-bg-elevated);
|
||||
color: var(--admin-text);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
font-size: 0.75rem;
|
||||
@@ -881,8 +883,8 @@ onMounted(() => {
|
||||
|
||||
&.active,
|
||||
&:hover {
|
||||
background: #0a1b37;
|
||||
border-color: #0a1b37;
|
||||
background: #2563eb;
|
||||
border-color: #2563eb;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="bg-white w-fit p-12 rounded-lg m-auto h-[35rem]" :class="[prefixCls]">
|
||||
<div class="admin-bg-elevated w-fit p-12 rounded-lg m-auto h-[35rem]" :class="[prefixCls]">
|
||||
<div class="logo flex justify-center w-full flex-col items-center">
|
||||
<img :src="getConfigApp('avatar')" class="w-[150px]" />
|
||||
</div>
|
||||
@@ -221,6 +221,8 @@ const getcode=()=>{
|
||||
@prefix: ~'@{prefixCls}-login-panel';
|
||||
|
||||
.@{prefix} {
|
||||
background-color: var(--admin-bg-elevated);
|
||||
|
||||
.logo {
|
||||
width: 330px;
|
||||
height: 148px;
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
<template>
|
||||
<div
|
||||
:style="{ backgroundImage: `url(${bg1})` }"
|
||||
class="w-screen h-screen top-0 right-0 fixed bg-cover flex z-[1000]"
|
||||
class="login-page w-screen h-screen top-0 right-0 fixed bg-cover flex z-[1000]"
|
||||
>
|
||||
<div class="login-page__toggle">
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
<LoginPanel @enter="enterTest" class="shadow-2xl" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import LoginPanel from './components/LoginPanel.vue'
|
||||
import ThemeToggle from '@core/components/ThemeToggle.vue'
|
||||
import bg1 from '../login/assets/img/loginBack.svg'
|
||||
|
||||
const emits = defineEmits(['enter'])
|
||||
@@ -19,4 +23,24 @@ function enterTest() {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
.login-page {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.login-page__toggle {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 16px;
|
||||
z-index: 1001;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 9999px;
|
||||
background: var(--admin-bg-elevated);
|
||||
border: 1px solid var(--admin-border);
|
||||
box-shadow: 0 2px 8px var(--admin-shadow);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -67,10 +67,10 @@ const help = computed(() => helpText(props.row))
|
||||
|
||||
<style lang="less" scoped>
|
||||
.setting-card {
|
||||
border: 1px solid #e8e8e8;
|
||||
border: 1px solid var(--admin-border);
|
||||
border-radius: 10px;
|
||||
padding: 14px 16px;
|
||||
background: #fff;
|
||||
background: var(--admin-bg-elevated);
|
||||
min-height: 108px;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
height: 100%;
|
||||
@@ -83,7 +83,7 @@ const help = computed(() => helpText(props.row))
|
||||
}
|
||||
|
||||
&--readonly {
|
||||
background: #fafafa;
|
||||
background: var(--admin-bg-muted);
|
||||
}
|
||||
|
||||
&--saving {
|
||||
@@ -109,14 +109,14 @@ const help = computed(() => helpText(props.row))
|
||||
&__title {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
color: var(--admin-text);
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
&__key {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
color: var(--admin-text-secondary);
|
||||
direction: ltr;
|
||||
text-align: right;
|
||||
word-break: break-all;
|
||||
@@ -125,7 +125,7 @@ const help = computed(() => helpText(props.row))
|
||||
&__help {
|
||||
margin-top: 4px;
|
||||
font-size: 11px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
color: var(--admin-text-secondary);
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ const help = computed(() => helpText(props.row))
|
||||
&__status {
|
||||
margin-top: 8px;
|
||||
font-size: 11px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
color: var(--admin-text-secondary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
@@ -589,8 +589,8 @@ async function ok() {
|
||||
align-items: flex-end;
|
||||
margin-bottom: 20px;
|
||||
padding: 14px 16px;
|
||||
background: #fafafa;
|
||||
border: 1px solid #f0f0f0;
|
||||
background: var(--admin-bg-elevated);
|
||||
border: 1px solid var(--admin-border);
|
||||
border-radius: 8px;
|
||||
|
||||
&__search {
|
||||
@@ -621,7 +621,7 @@ async function ok() {
|
||||
&__label {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: rgba(0, 0, 0, 0.55);
|
||||
color: var(--admin-text-secondary);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
@@ -633,10 +633,10 @@ async function ok() {
|
||||
.settings-section-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.55);
|
||||
color: var(--admin-text-secondary);
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 6px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
border-bottom: 1px solid var(--admin-border);
|
||||
|
||||
&--spaced {
|
||||
margin-top: 28px;
|
||||
@@ -659,11 +659,11 @@ async function ok() {
|
||||
|
||||
.settings-collapse :deep(.ant-collapse-item) {
|
||||
margin-bottom: 12px;
|
||||
background: #fff;
|
||||
border: 1px solid #f0f0f0;
|
||||
background: var(--admin-bg-elevated);
|
||||
border: 1px solid var(--admin-border);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
|
||||
box-shadow: 0 1px 3px var(--admin-shadow);
|
||||
transition: box-shadow 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
@@ -674,10 +674,10 @@ async function ok() {
|
||||
|
||||
.settings-collapse :deep(.ant-collapse-header) {
|
||||
padding: 14px 18px !important;
|
||||
background: linear-gradient(90deg, #fafafa 0%, #fff 100%);
|
||||
background: var(--admin-bg-muted);
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.settings-collapse-header {
|
||||
@@ -695,15 +695,15 @@ async function ok() {
|
||||
.settings-collapse-title {
|
||||
flex: 1;
|
||||
font-weight: 600;
|
||||
color: #2c2c2c;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.settings-empty-group {
|
||||
padding: 12px 16px;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
color: var(--admin-text-secondary);
|
||||
text-align: center;
|
||||
background: #fafafa;
|
||||
background: var(--admin-bg-muted);
|
||||
border-radius: 6px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
@@ -2,17 +2,21 @@
|
||||
<div class="h-full min-h-0 min-w-0 max-w-full overflow-hidden">
|
||||
<BasicShowContext title="لیست مشتریان">
|
||||
<template #extra>
|
||||
<BaseButton type="primary" size="small" class="flex shrink-0 md:hidden" @click="emits('add')">
|
||||
<div>افزودن</div>
|
||||
<BaseIcon icon="vuesax-linear:user-add" Size="16px" />
|
||||
<BaseButton
|
||||
v-if="isMobile"
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="vuesax-linear:user-add"
|
||||
@click="emits('add')"
|
||||
>
|
||||
افزودن
|
||||
</BaseButton>
|
||||
</template>
|
||||
<div class="flex h-full min-h-0 flex-col">
|
||||
<BaseTable v-if="!isMobile" class="h-full min-h-0 min-w-0" v-bind="tblProps" @register="submit" ref="tbl">
|
||||
<template #extraHeader>
|
||||
<BaseButton type="primary" size="small" class="flex" @click="emits('add')">
|
||||
<div>افزودن مشتری</div>
|
||||
<BaseIcon icon="vuesax-linear:user-add" Size="16px" />
|
||||
<BaseButton type="primary" size="small" icon="vuesax-linear:user-add" @click="emits('add')">
|
||||
افزودن مشتری
|
||||
</BaseButton>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<a-tabs v-if="userInfo" v-model:activeKey="activeKey">
|
||||
<a-tab-pane key="اطلاعات جامع" tab="اطلاعات جامع">
|
||||
<div class="space-y-2">
|
||||
<div class="rounded-lg bg-gray-100 w-full flex flex-col gap-3 p-3 md:flex-row md:justify-between">
|
||||
<div class="admin-stat-muted rounded-lg w-full flex flex-col gap-3 p-3 md:flex-row md:justify-between">
|
||||
<div>
|
||||
<div class="font-bold">{{ userInfo.name }}</div>
|
||||
<div class="mt-1">{{ userInfo?.mobile }}</div>
|
||||
@@ -187,7 +187,7 @@
|
||||
<div
|
||||
v-for="(item, index) in userInfo.wallet"
|
||||
:key="index"
|
||||
class="grid grid-cols-2 bg-orange-50 gap-2 rounded-lg p-2"
|
||||
class="grid grid-cols-2 bg-orange-100 dark:bg-orange-500/15 gap-2 rounded-lg p-2"
|
||||
>
|
||||
<BasicInfoItem
|
||||
title="نام قلک"
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<template>
|
||||
<div class="h-full min-h-0 min-w-0 max-w-full overflow-hidden">
|
||||
<BasicShowContext title="لیست کارت های هدیه">
|
||||
<template v-if="!customerId" #extra>
|
||||
<BaseButton type="primary" size="small" class="flex shrink-0 md:hidden" @click="emits('add', 'gift')">
|
||||
<div>افزودن</div>
|
||||
<BaseIcon icon="vuesax-linear:receipt-add" Size="16px" />
|
||||
<template v-if="!customerId && isMobile" #extra>
|
||||
<BaseButton type="primary" size="small" icon="vuesax-linear:receipt-add" @click="emits('add', 'gift')">
|
||||
افزودن
|
||||
</BaseButton>
|
||||
</template>
|
||||
|
||||
@@ -12,19 +11,17 @@
|
||||
<BaseTable v-if="!isMobile" class="h-full min-h-0 min-w-0" v-bind="tblProps" @register="submit" ref="tbl">
|
||||
<template #extraHeader>
|
||||
<div class="flex gap-2">
|
||||
<BaseButton v-if="!customerId" type="primary" size="small" class="flex" @click="emits('add', 'gift')">
|
||||
<div>افزودن کارت هدیه</div>
|
||||
<BaseIcon icon="vuesax-linear:receipt-add" Size="16px" />
|
||||
<BaseButton v-if="!customerId" type="primary" size="small" icon="vuesax-linear:receipt-add" @click="emits('add', 'gift')">
|
||||
افزودن کارت هدیه
|
||||
</BaseButton>
|
||||
<BaseButton
|
||||
v-if="!customerId && isStoreApp()"
|
||||
type="primary"
|
||||
size="small"
|
||||
class="flex"
|
||||
icon="vuesax-linear:discount-circle"
|
||||
@click="emits('add', 'discount')"
|
||||
>
|
||||
<div>افزودن کد تخفیف</div>
|
||||
<BaseIcon icon="vuesax-linear:discount-circle" Size="16px" />
|
||||
افزودن کد تخفیف
|
||||
</BaseButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
<template>
|
||||
<div class="h-full min-h-0 min-w-0 max-w-full overflow-hidden">
|
||||
<BasicShowContext title="لیست سفارشات">
|
||||
<template v-if="!customerId" #extra>
|
||||
<BaseButton type="primary" size="small" class="flex shrink-0 md:hidden" @click="emits('add')">
|
||||
<div>افزودن</div>
|
||||
<BaseIcon icon="vuesax-linear:receipt-add" Size="16px" />
|
||||
<template v-if="!customerId && isMobile" #extra>
|
||||
<BaseButton type="primary" size="small" icon="vuesax-linear:receipt-add" @click="emits('add')">
|
||||
افزودن
|
||||
</BaseButton>
|
||||
</template>
|
||||
<div class="flex h-full min-h-0 flex-col">
|
||||
<BaseTable v-if="!isMobile" class="h-full min-h-0 min-w-0" v-bind="tblProps" @register="submit" ref="tbl">
|
||||
<template #extraHeader>
|
||||
<BaseButton v-if="!customerId" type="primary" size="small" class="flex" @click="emits('add')">
|
||||
<div>افزودن سفارش</div>
|
||||
<BaseIcon icon="vuesax-linear:receipt-add" Size="16px" />
|
||||
<BaseButton v-if="!customerId" type="primary" size="small" icon="vuesax-linear:receipt-add" @click="emits('add')">
|
||||
افزودن سفارش
|
||||
</BaseButton>
|
||||
</template>
|
||||
<template #action="{ column, record }">
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
<BasicShowContext title="تاریخچه قیمت">
|
||||
<template #extra>
|
||||
<BaseButton
|
||||
v-if="isMobile"
|
||||
type="primary"
|
||||
size="small"
|
||||
class="flex shrink-0 md:hidden"
|
||||
icon="vuesax-linear:refresh"
|
||||
:loading="syncing"
|
||||
@click="emits('sync')"
|
||||
>
|
||||
<div>بهروزرسانی قیمت</div>
|
||||
<BaseIcon icon="vuesax-linear:refresh" Size="16px" />
|
||||
بهروزرسانی قیمت
|
||||
</BaseButton>
|
||||
</template>
|
||||
|
||||
@@ -20,12 +20,11 @@
|
||||
<BaseButton
|
||||
type="primary"
|
||||
size="small"
|
||||
class="flex"
|
||||
icon="vuesax-linear:refresh"
|
||||
:loading="syncing"
|
||||
@click="emits('sync')"
|
||||
>
|
||||
<div>بهروزرسانی قیمت</div>
|
||||
<BaseIcon icon="vuesax-linear:refresh" Size="16px" />
|
||||
بهروزرسانی قیمت
|
||||
</BaseButton>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
|
||||
@@ -63,13 +63,7 @@
|
||||
import type { TableInput } from '@core/type/baseTable'
|
||||
import useBaseTable from '@core/components/BaseTableOld/hooks/useBaseTable'
|
||||
import Icon from '@core/components/BaseIcon/src/Icon.vue'
|
||||
import {
|
||||
changeCustomerActivation,
|
||||
changeCustomerArchive,
|
||||
changeCustomerOrderActivation,
|
||||
getCustomerArchiveTable,
|
||||
getCustomerTable
|
||||
} from '@/api/customer'
|
||||
import { changeProductArchive } from '@/api/product'
|
||||
import { cols } from '../hooks/archiveColumns'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { usePrefix } from '@core/composable/usePrefix'
|
||||
@@ -105,37 +99,12 @@ const tblProps = ref<any>({
|
||||
})
|
||||
const loading = ref<boolean>(false)
|
||||
|
||||
async function changeCustomerActivationFunction(id: number) {
|
||||
try {
|
||||
loading.value = true
|
||||
await changeCustomerActivation(id)
|
||||
reload()
|
||||
message.success('تغییر وضعیت با موفقیت انجام شد')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function changeCustomerOrderActivationFunction(id: number) {
|
||||
try {
|
||||
loading.value = true
|
||||
await changeCustomerOrderActivation(id)
|
||||
reload()
|
||||
message.success('تغییر وضعیت سفارش دهی با موفقیت انجام شد')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
async function archiveFunction(id: number) {
|
||||
try {
|
||||
loading.value = true
|
||||
await changeCustomerArchive(id)
|
||||
await changeProductArchive(id)
|
||||
await Promise.allSettled([reload(), mobileListRef.value?.fetch?.() as Promise<void>])
|
||||
message.success('مشتری با موفقیت از بایگانی خارج شد.')
|
||||
message.success('محصول با موفقیت از بایگانی خارج شد.')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
|
||||
@@ -36,17 +36,21 @@
|
||||
|
||||
<BasicShowContext title="لیست محصولات" class="min-h-0 flex-1">
|
||||
<template #extra>
|
||||
<BaseButton type="primary" size="small" class="flex shrink-0 md:hidden" @click="emits('add')">
|
||||
<div>افزودن</div>
|
||||
<BaseIcon icon="vuesax-linear:box" Size="16px" />
|
||||
<BaseButton
|
||||
v-if="isMobile"
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="vuesax-linear:box"
|
||||
@click="emits('add')"
|
||||
>
|
||||
افزودن محصول
|
||||
</BaseButton>
|
||||
</template>
|
||||
<div class="flex h-full min-h-0 flex-col">
|
||||
<BaseTable v-if="!isMobile" class="h-full min-h-0 min-w-0" v-bind="tblProps" @register="submit" ref="tbl">
|
||||
<template #extraHeader>
|
||||
<BaseButton type="primary" size="small" class="flex" @click="emits('add')">
|
||||
<div>افزودن محصول</div>
|
||||
<BaseIcon icon="vuesax-linear:box" Size="16px" />
|
||||
<BaseButton type="primary" size="small" icon="vuesax-linear:box" @click="emits('add')">
|
||||
افزودن محصول
|
||||
</BaseButton>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import type { BaseTableColumn } from '@core/type/baseTable'
|
||||
import CustomTag from '@/components/CustomTag.vue'
|
||||
import { isStoreApp } from '@/utils/config'
|
||||
import { usePrice } from '@core/utils/usePrice'
|
||||
|
||||
function formatMoney(value: number | null | undefined) {
|
||||
return usePrice(value ?? 0, true, '').trim()
|
||||
}
|
||||
|
||||
const inventoryColumn: BaseTableColumn = {
|
||||
title: 'موجودی',
|
||||
@@ -47,7 +52,8 @@ export function getProductColumns(): BaseTableColumn[] {
|
||||
title: 'قیمت',
|
||||
dataIndex: 'price',
|
||||
key: 'price',
|
||||
type: 'Text'
|
||||
type: 'Text',
|
||||
customRender: ({ record }) => formatMoney(record.price)
|
||||
},
|
||||
{
|
||||
title: 'تعدیل قیمت (٪)',
|
||||
@@ -79,13 +85,15 @@ export function getProductColumns(): BaseTableColumn[] {
|
||||
title: 'هزینه نقدی موقع خرید',
|
||||
dataIndex: 'cash_fee_buy',
|
||||
key: 'cash_fee_buy',
|
||||
type: 'Number'
|
||||
type: 'Number',
|
||||
customRender: ({ record }) => formatMoney(record.cash_fee_buy)
|
||||
},
|
||||
{
|
||||
title: 'هزینه نقدی موقع فروش',
|
||||
dataIndex: 'cash_fee_sell',
|
||||
key: 'cash_fee_sell',
|
||||
type: 'Number'
|
||||
type: 'Number',
|
||||
customRender: ({ record }) => formatMoney(record.cash_fee_sell)
|
||||
},
|
||||
...(isStoreApp() ? [inventoryColumn] : []),
|
||||
{
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
<template>
|
||||
<div class="h-full min-h-0 min-w-0 max-w-full overflow-hidden">
|
||||
<BasicShowContext title="لیست پیامک ها">
|
||||
<template v-if="!mobile" #extra>
|
||||
<BaseButton type="primary" size="small" class="flex shrink-0 md:hidden" @click="emits('add')">
|
||||
<div>ارسال پیامک</div>
|
||||
<BaseIcon icon="vuesax-linear:sms" Size="16px" />
|
||||
<template v-if="!mobile && isMobileScreen" #extra>
|
||||
<BaseButton type="primary" size="small" icon="vuesax-linear:sms" @click="emits('add')">
|
||||
ارسال پیامک
|
||||
</BaseButton>
|
||||
</template>
|
||||
|
||||
<div class="flex h-full min-h-0 flex-col">
|
||||
<BaseTable v-if="!isMobileScreen" class="h-full min-h-0 min-w-0" v-bind="tblProps" @register="submit" ref="tbl">
|
||||
<template #extraHeader>
|
||||
<BaseButton v-if="!mobile" type="primary" size="small" class="flex" @click="emits('add')">
|
||||
<div>ارسال پیامک</div>
|
||||
<BaseIcon icon="vuesax-linear:sms" Size="16px" />
|
||||
<BaseButton v-if="!mobile" type="primary" size="small" icon="vuesax-linear:sms" @click="emits('add')">
|
||||
ارسال پیامک
|
||||
</BaseButton>
|
||||
</template>
|
||||
<template #action="{ column, record }">
|
||||
|
||||
@@ -2,18 +2,22 @@
|
||||
<div class="h-full min-h-0 min-w-0 max-w-full overflow-hidden">
|
||||
<BasicShowContext title="لیست مدیران">
|
||||
<template #extra>
|
||||
<BaseButton type="primary" size="small" class="flex shrink-0 md:hidden" @click="emits('add')">
|
||||
<div>افزودن مدیر</div>
|
||||
<BaseIcon icon="vuesax-linear:user-add" Size="16px" />
|
||||
<BaseButton
|
||||
v-if="isMobile"
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="vuesax-linear:user-add"
|
||||
@click="emits('add')"
|
||||
>
|
||||
افزودن مدیر
|
||||
</BaseButton>
|
||||
</template>
|
||||
|
||||
<div class="flex h-full min-h-0 flex-col">
|
||||
<BaseTable v-if="!isMobile" class="h-full min-h-0 min-w-0" v-bind="tblProps" @register="submit" ref="tbl">
|
||||
<template #extraHeader>
|
||||
<BaseButton type="primary" size="small" class="flex" @click="emits('add')">
|
||||
<div>افزودن مدیر</div>
|
||||
<BaseIcon icon="vuesax-linear:user-add" Size="16px" />
|
||||
<BaseButton type="primary" size="small" icon="vuesax-linear:user-add" @click="emits('add')">
|
||||
افزودن مدیر
|
||||
</BaseButton>
|
||||
</template>
|
||||
<template #action="{ column, record }">
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
>
|
||||
<div class="mb-2 font-medium">مجموع موجودی کیف پول</div>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div class="rounded-lg border border-gray-200 bg-white/70 px-2 py-1.5 text-center">
|
||||
<div class="stat-inner rounded-lg px-2 py-1.5 text-center">
|
||||
<div class="text-xs text-gray-500">ریال</div>
|
||||
<div class="mt-1 font-bold break-all">{{ usePrice(sums?.cash ?? 0) }}</div>
|
||||
</div>
|
||||
<div class="rounded-lg border border-gray-200 bg-white/70 px-2 py-1.5 text-center">
|
||||
<div class="stat-inner rounded-lg px-2 py-1.5 text-center">
|
||||
<div class="text-xs text-gray-500">گرم</div>
|
||||
<div class="mt-1 font-bold">
|
||||
{{ usePrice(Number(sums?.cashToGold ?? 0).toFixed(2), true, 'گرم') }}
|
||||
@@ -28,13 +28,13 @@
|
||||
>
|
||||
<div class="mb-2 font-medium">مجموع موجودی کیف طلا</div>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div class="rounded-lg border border-gray-200 bg-white/70 px-2 py-1.5 text-center">
|
||||
<div class="stat-inner rounded-lg px-2 py-1.5 text-center">
|
||||
<div class="text-xs text-gray-500">گرم</div>
|
||||
<div class="mt-1 font-bold">
|
||||
{{ usePrice(sums?.gold ?? 0, true, 'گرم') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-lg border border-gray-200 bg-white/70 px-2 py-1.5 text-center">
|
||||
<div class="stat-inner rounded-lg px-2 py-1.5 text-center">
|
||||
<div class="text-xs text-gray-500">ریال</div>
|
||||
<div class="mt-1 font-bold break-all">{{ usePrice(sums?.goldToCash ?? 0) }}</div>
|
||||
</div>
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
@close="confirmWeightVisible = false"
|
||||
>
|
||||
<div v-for="(item, index) in weightTransactions" :key="index">
|
||||
<div class="bg-gray-100 rounded-lg p-4 mt-2">
|
||||
<div class="admin-stat-muted rounded-lg p-4 mt-2">
|
||||
<div class="mb-4">{{ item?.title }} ({{ weightCount(item) }} عدد)</div>
|
||||
<ADivider class="!my-0 "/>
|
||||
<div v-if="weightCount(item) > 0">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<div class="mx-3 relative">
|
||||
<div class="absolute z-10 w-full">
|
||||
<div class="flex justify-between items-center bg-gray-50 rounded p-3 w-full">
|
||||
<div class="flex justify-between items-center admin-stat-muted rounded p-3 w-full">
|
||||
<span class="text-base font-bold">اقلام سفارش</span>
|
||||
<Button type="primary" size="small" v-if="edit" @click="updateOrders"
|
||||
>ثبت اطلاعات
|
||||
|
||||
Reference in New Issue
Block a user