perf: reorganize the icons and reduce the volume
This commit is contained in:
@@ -4,12 +4,7 @@ import type { Preferences } from './types';
|
||||
|
||||
import { markRaw, reactive, readonly, watch } from 'vue';
|
||||
|
||||
import {
|
||||
StorageManager,
|
||||
generatorColorVariables,
|
||||
merge,
|
||||
updateCSSVariables,
|
||||
} from '@vben-core/toolkit';
|
||||
import { StorageManager, merge } from '@vben-core/toolkit';
|
||||
|
||||
import {
|
||||
breakpointsTailwind,
|
||||
@@ -18,7 +13,7 @@ import {
|
||||
} from '@vueuse/core';
|
||||
|
||||
import { defaultPreferences } from './config';
|
||||
import { BUILT_IN_THEME_PRESETS } from './constants';
|
||||
import { updateCSSVariables } from './update-css-variables';
|
||||
|
||||
const STORAGE_KEY = 'preferences';
|
||||
const STORAGE_KEY_LOCALE = `${STORAGE_KEY}-locale`;
|
||||
@@ -48,11 +43,10 @@ class PreferenceManager {
|
||||
});
|
||||
constructor() {
|
||||
this.cache = new StorageManager();
|
||||
// this.flattenedState = reactive(flattenObject(this.state));
|
||||
|
||||
this.savePreferences = useDebounceFn(
|
||||
(preference: Preferences) => this._savePreferences(preference),
|
||||
100,
|
||||
200,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -76,7 +70,7 @@ class PreferenceManager {
|
||||
const themeUpdates = updates.theme || {};
|
||||
const appUpdates = updates.app || {};
|
||||
if (themeUpdates && Object.keys(themeUpdates).length > 0) {
|
||||
this.updateTheme(this.state);
|
||||
updateCSSVariables(this.state);
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -130,7 +124,7 @@ class PreferenceManager {
|
||||
this.updatePreferences({
|
||||
theme: { mode: isDark ? 'dark' : 'light' },
|
||||
});
|
||||
this.updateTheme(this.state);
|
||||
updateCSSVariables(this.state);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -153,101 +147,6 @@ class PreferenceManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新 CSS 变量
|
||||
* @param preference - 当前偏好设置对象,它的颜色值将被转换成 HSL 格式并设置为 CSS 变量。
|
||||
*/
|
||||
private updateMainColors(preference: Preferences) {
|
||||
if (!preference.theme) {
|
||||
return;
|
||||
}
|
||||
const { colorDestructive, colorPrimary, colorSuccess, colorWarning } =
|
||||
preference.theme;
|
||||
|
||||
const colorVariables = generatorColorVariables([
|
||||
{ color: colorPrimary, name: 'primary' },
|
||||
{ alias: 'warning', color: colorWarning, name: 'yellow' },
|
||||
{ alias: 'success', color: colorSuccess, name: 'green' },
|
||||
{ alias: 'destructive', color: colorDestructive, name: 'red' },
|
||||
]);
|
||||
|
||||
if (colorPrimary) {
|
||||
document.documentElement.style.setProperty(
|
||||
'--primary',
|
||||
colorVariables['--primary-500'],
|
||||
);
|
||||
}
|
||||
|
||||
if (colorVariables['--green-500']) {
|
||||
colorVariables['--success'] = colorVariables['--green-500'];
|
||||
}
|
||||
if (colorVariables['--yellow-500']) {
|
||||
colorVariables['--warning'] = colorVariables['--yellow-500'];
|
||||
}
|
||||
if (colorVariables['--red-500']) {
|
||||
colorVariables['--destructive'] = colorVariables['--red-500'];
|
||||
}
|
||||
updateCSSVariables(colorVariables);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新主题
|
||||
* @param preferences - 当前偏好设置对象,它的主题值将被用来设置文档的主题。
|
||||
*/
|
||||
private updateTheme(preferences: Preferences) {
|
||||
// 当修改到颜色变量时,更新 css 变量
|
||||
const root = document.documentElement;
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
|
||||
const theme = preferences?.theme ?? {};
|
||||
|
||||
const { builtinType, colorPrimary, mode, radius } = theme;
|
||||
|
||||
if (Reflect.has(theme, 'mode')) {
|
||||
const dark = isDarkTheme(mode);
|
||||
root.classList.toggle('dark', dark);
|
||||
}
|
||||
|
||||
if (Reflect.has(theme, 'builtinType')) {
|
||||
const rootTheme = root.dataset.theme;
|
||||
if (rootTheme !== builtinType) {
|
||||
root.dataset.theme = builtinType;
|
||||
}
|
||||
}
|
||||
|
||||
const currentBuiltType = BUILT_IN_THEME_PRESETS.find(
|
||||
(item) => item.type === builtinType,
|
||||
);
|
||||
|
||||
let builtinTypeColorPrimary: string | undefined = '';
|
||||
|
||||
if (currentBuiltType) {
|
||||
const isDark = isDarkTheme(this.state.theme.mode);
|
||||
|
||||
const color = isDark
|
||||
? currentBuiltType.darkPrimaryColor || currentBuiltType.primaryColor
|
||||
: currentBuiltType.primaryColor;
|
||||
builtinTypeColorPrimary = color || currentBuiltType.color;
|
||||
}
|
||||
|
||||
if (
|
||||
builtinTypeColorPrimary ||
|
||||
Reflect.has(theme, 'colorPrimary') ||
|
||||
Reflect.has(theme, 'colorDestructive') ||
|
||||
Reflect.has(theme, 'colorSuccess') ||
|
||||
Reflect.has(theme, 'colorWarning')
|
||||
) {
|
||||
preferences.theme.colorPrimary = builtinTypeColorPrimary || colorPrimary;
|
||||
this.updateMainColors(preferences);
|
||||
}
|
||||
|
||||
if (Reflect.has(theme, 'radius')) {
|
||||
document.documentElement.style.setProperty('--radius', `${radius}rem`);
|
||||
}
|
||||
}
|
||||
|
||||
clearCache() {
|
||||
[STORAGE_KEY, STORAGE_KEY_LOCALE, STORAGE_KEY_THEME].forEach((key) => {
|
||||
this.cache?.removeItem(key);
|
||||
|
118
packages/@core/forward/preferences/src/update-css-variables.ts
Normal file
118
packages/@core/forward/preferences/src/update-css-variables.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import type { Preferences } from './types';
|
||||
|
||||
import {
|
||||
updateCSSVariables as executeUpdateCSSVariables,
|
||||
generatorColorVariables,
|
||||
} from '@vben-core/toolkit';
|
||||
|
||||
import { BUILT_IN_THEME_PRESETS } from './constants';
|
||||
|
||||
/**
|
||||
* 更新主题的 CSS 变量以及其他 CSS 变量
|
||||
* @param preferences - 当前偏好设置对象,它的主题值将被用来设置文档的主题。
|
||||
*/
|
||||
function updateCSSVariables(preferences: Preferences) {
|
||||
// 当修改到颜色变量时,更新 css 变量
|
||||
const root = document.documentElement;
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
|
||||
const theme = preferences?.theme ?? {};
|
||||
|
||||
const { builtinType, colorPrimary, mode, radius } = theme;
|
||||
|
||||
// html 设置 dark 类
|
||||
if (Reflect.has(theme, 'mode')) {
|
||||
const dark = isDarkTheme(mode);
|
||||
root.classList.toggle('dark', dark);
|
||||
}
|
||||
|
||||
// html 设置 data-theme=[builtinType]
|
||||
if (Reflect.has(theme, 'builtinType')) {
|
||||
const rootTheme = root.dataset.theme;
|
||||
if (rootTheme !== builtinType) {
|
||||
root.dataset.theme = builtinType;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前的内置主题
|
||||
const currentBuiltType = BUILT_IN_THEME_PRESETS.find(
|
||||
(item) => item.type === builtinType,
|
||||
);
|
||||
|
||||
let builtinTypeColorPrimary: string | undefined = '';
|
||||
|
||||
if (currentBuiltType) {
|
||||
const isDark = isDarkTheme(preferences.theme.mode);
|
||||
// 设置不同主题的主要颜色
|
||||
const color = isDark
|
||||
? currentBuiltType.darkPrimaryColor || currentBuiltType.primaryColor
|
||||
: currentBuiltType.primaryColor;
|
||||
builtinTypeColorPrimary = color || currentBuiltType.color;
|
||||
}
|
||||
|
||||
// 如果内置主题颜色和自定义颜色都不存在,则不更新主题颜色
|
||||
if (
|
||||
builtinTypeColorPrimary ||
|
||||
Reflect.has(theme, 'colorPrimary') ||
|
||||
Reflect.has(theme, 'colorDestructive') ||
|
||||
Reflect.has(theme, 'colorSuccess') ||
|
||||
Reflect.has(theme, 'colorWarning')
|
||||
) {
|
||||
preferences.theme.colorPrimary = builtinTypeColorPrimary || colorPrimary;
|
||||
updateMainColorVariables(preferences);
|
||||
}
|
||||
|
||||
// 更新圆角
|
||||
if (Reflect.has(theme, 'radius')) {
|
||||
document.documentElement.style.setProperty('--radius', `${radius}rem`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新主要的 CSS 变量
|
||||
* @param preference - 当前偏好设置对象,它的颜色值将被转换成 HSL 格式并设置为 CSS 变量。
|
||||
*/
|
||||
function updateMainColorVariables(preference: Preferences) {
|
||||
if (!preference.theme) {
|
||||
return;
|
||||
}
|
||||
const { colorDestructive, colorPrimary, colorSuccess, colorWarning } =
|
||||
preference.theme;
|
||||
|
||||
const colorVariables = generatorColorVariables([
|
||||
{ color: colorPrimary, name: 'primary' },
|
||||
{ alias: 'warning', color: colorWarning, name: 'yellow' },
|
||||
{ alias: 'success', color: colorSuccess, name: 'green' },
|
||||
{ alias: 'destructive', color: colorDestructive, name: 'red' },
|
||||
]);
|
||||
|
||||
if (colorPrimary) {
|
||||
document.documentElement.style.setProperty(
|
||||
'--primary',
|
||||
colorVariables['--primary-500'],
|
||||
);
|
||||
}
|
||||
|
||||
if (colorVariables['--green-500']) {
|
||||
colorVariables['--success'] = colorVariables['--green-500'];
|
||||
}
|
||||
if (colorVariables['--yellow-500']) {
|
||||
colorVariables['--warning'] = colorVariables['--yellow-500'];
|
||||
}
|
||||
if (colorVariables['--red-500']) {
|
||||
colorVariables['--destructive'] = colorVariables['--red-500'];
|
||||
}
|
||||
executeUpdateCSSVariables(colorVariables);
|
||||
}
|
||||
|
||||
function isDarkTheme(theme: string) {
|
||||
let dark = theme === 'dark';
|
||||
if (theme === 'auto') {
|
||||
dark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
}
|
||||
return dark;
|
||||
}
|
||||
|
||||
export { updateCSSVariables };
|
@@ -27,6 +27,10 @@ function usePreferences() {
|
||||
return isDarkTheme(preferences.theme.mode);
|
||||
});
|
||||
|
||||
const isMobile = computed(() => {
|
||||
return appPreferences.value.isMobile;
|
||||
});
|
||||
|
||||
const theme = computed(() => {
|
||||
return isDark.value ? 'dark' : 'light';
|
||||
});
|
||||
@@ -35,7 +39,7 @@ function usePreferences() {
|
||||
* @zh_CN 布局方式
|
||||
*/
|
||||
const layout = computed(() =>
|
||||
appPreferences.value.isMobile ? 'sidebar-nav' : appPreferences.value.layout,
|
||||
isMobile.value ? 'sidebar-nav' : appPreferences.value.layout,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -109,6 +113,16 @@ function usePreferences() {
|
||||
return appPreferences.value.authPageLayout === 'panel-center';
|
||||
});
|
||||
|
||||
/**
|
||||
* @zh_CN 内容是否已经最大化
|
||||
* 排除 full-content模式
|
||||
*/
|
||||
const contentIsMaximize = computed(() => {
|
||||
const headerIsHidden = preferences.header.hidden;
|
||||
const sidebarIsHidden = preferences.sidebar.hidden;
|
||||
return headerIsHidden && sidebarIsHidden && !isFullContent.value;
|
||||
});
|
||||
|
||||
/**
|
||||
* @zh_CN 是否启用全局搜索快捷键
|
||||
*/
|
||||
@@ -138,17 +152,6 @@ function usePreferences() {
|
||||
return enable && globalPreferences;
|
||||
});
|
||||
|
||||
/**
|
||||
* @zh_CN 内容是否已经最大化
|
||||
* 排除 full-content模式
|
||||
*/
|
||||
const contentIsMaximize = computed(() => {
|
||||
const headerIsHidden = preferences.header.hidden;
|
||||
const sidebarIsHidden = preferences.sidebar.hidden;
|
||||
|
||||
return headerIsHidden && sidebarIsHidden && !isFullContent.value;
|
||||
});
|
||||
|
||||
return {
|
||||
authPanelCenter,
|
||||
authPanelLeft,
|
||||
@@ -163,6 +166,7 @@ function usePreferences() {
|
||||
isFullContent,
|
||||
isHeaderNav,
|
||||
isMixedNav,
|
||||
isMobile,
|
||||
isSideMixedNav,
|
||||
isSideMode,
|
||||
isSideNav,
|
||||
|
@@ -15,7 +15,7 @@
|
||||
--card-foreground: 210 40% 98%;
|
||||
|
||||
/* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */
|
||||
--popover: 222.82deg 8.43% 16.27%;
|
||||
--popover: 222.82deg 8.43% 12.27%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
|
||||
/* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
|
||||
|
@@ -36,6 +36,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify/vue": "^4.1.2",
|
||||
"lucide-vue-next": "^0.408.0",
|
||||
"vue": "^3.4.32"
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
export * from './create-icon';
|
||||
export * from './material';
|
||||
export * from './mdi';
|
||||
export * from './lucide';
|
||||
|
||||
export * from './mdi';
|
||||
export * from '@iconify/vue';
|
||||
|
46
packages/@core/shared/icons/src/lucide.ts
Normal file
46
packages/@core/shared/icons/src/lucide.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
export {
|
||||
ArrowDown,
|
||||
ArrowLeft,
|
||||
ArrowLeftToLine,
|
||||
ArrowRightLeft,
|
||||
ArrowRightToLine,
|
||||
ArrowUp,
|
||||
ArrowUpToLine,
|
||||
Bell,
|
||||
BookOpenText,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
CircleHelp,
|
||||
Copy,
|
||||
CornerDownLeft,
|
||||
Disc3 as IconDefault,
|
||||
Ellipsis,
|
||||
ExternalLink,
|
||||
Eye,
|
||||
EyeOff,
|
||||
FoldHorizontal,
|
||||
Fullscreen,
|
||||
Github,
|
||||
InspectionPanel,
|
||||
Languages,
|
||||
LoaderCircle,
|
||||
LockKeyhole,
|
||||
LogOut,
|
||||
MailCheck,
|
||||
Maximize,
|
||||
Menu,
|
||||
Minimize,
|
||||
Minimize2,
|
||||
MoonStar,
|
||||
Palette,
|
||||
PanelLeft,
|
||||
PanelRight,
|
||||
RotateCw,
|
||||
Search,
|
||||
SearchX,
|
||||
Sun,
|
||||
SunMoon,
|
||||
SwatchBook,
|
||||
UserRoundPen,
|
||||
X,
|
||||
} from 'lucide-vue-next';
|
@@ -1,88 +0,0 @@
|
||||
import { createIconifyIcon } from './create-icon';
|
||||
|
||||
export const IconDefault = createIconifyIcon('ic:round-auto-awesome');
|
||||
|
||||
export const IcRoundKeyboardArrowDown = createIconifyIcon(
|
||||
'ic:round-keyboard-arrow-down',
|
||||
);
|
||||
|
||||
export const IcRoundChevronRight = createIconifyIcon('ic:round-chevron-right');
|
||||
|
||||
export const IcRoundMenu = createIconifyIcon('ic:round-menu');
|
||||
|
||||
export const IcRoundMoreHoriz = createIconifyIcon('ic:round-more-horiz');
|
||||
|
||||
export const IcRoundFitScreen = createIconifyIcon('ic:round-fit-screen');
|
||||
|
||||
export const IcTwotoneFitScreen = createIconifyIcon('ic:twotone-fit-screen');
|
||||
|
||||
export const IcRoundColorLens = createIconifyIcon('ic:round-color-lens');
|
||||
|
||||
export const IcRoundMoreVert = createIconifyIcon('ic:round-more-vert');
|
||||
|
||||
export const IcRoundFullscreen = createIconifyIcon('ic:round-fullscreen');
|
||||
|
||||
export const IcRoundFullscreenExit = createIconifyIcon(
|
||||
'ic:round-fullscreen-exit',
|
||||
);
|
||||
|
||||
export const IcRoundClose = createIconifyIcon('ic:round-close');
|
||||
|
||||
export const IcRoundRestartAlt = createIconifyIcon('ic:round-restart-alt');
|
||||
|
||||
export const IcRoundLogout = createIconifyIcon('ic:round-logout');
|
||||
|
||||
export const IcOutlineVisibility = createIconifyIcon('ic:outline-visibility');
|
||||
|
||||
export const IcOutlineVisibilityOff = createIconifyIcon(
|
||||
'ic:outline-visibility-off',
|
||||
);
|
||||
|
||||
export const IcRoundSearch = createIconifyIcon('ic:round-search');
|
||||
|
||||
export const IcRoundFolderCopy = createIconifyIcon('ic:round-folder-copy');
|
||||
|
||||
export const IcRoundSubdirectoryArrowLeft = createIconifyIcon(
|
||||
'ic:round-subdirectory-arrow-left',
|
||||
);
|
||||
export const IcRoundArrowUpward = createIconifyIcon('ic:round-arrow-upward');
|
||||
|
||||
export const IcRoundArrowDownward = createIconifyIcon(
|
||||
'ic:round-arrow-downward',
|
||||
);
|
||||
|
||||
export const IcBaselineLanguage = createIconifyIcon('ic:baseline-language');
|
||||
|
||||
export const IcRoundSearchOff = createIconifyIcon('ic:round-search-off');
|
||||
|
||||
export const IcRoundNotificationsNone = createIconifyIcon(
|
||||
'ic:round-notifications-none',
|
||||
);
|
||||
|
||||
export const IcRoundMarkEmailRead = createIconifyIcon(
|
||||
'ic:round-mark-email-read',
|
||||
);
|
||||
|
||||
export const IcRoundWbSunny = createIconifyIcon('ic:round-wb-sunny');
|
||||
|
||||
export const IcRoundMotionPhotosAuto = createIconifyIcon(
|
||||
'ic:round-motion-photos-auto',
|
||||
);
|
||||
|
||||
export const IcRoundSettingsSuggest = createIconifyIcon(
|
||||
'ic:round-settings-suggest',
|
||||
);
|
||||
|
||||
export const IcRoundArrowBackIosNew = createIconifyIcon(
|
||||
'ic:round-arrow-back-ios-new',
|
||||
);
|
||||
|
||||
export const IcRoundMultipleStop = createIconifyIcon('ic:round-multiple-stop');
|
||||
|
||||
export const IcRoundTableView = createIconifyIcon('ic:round-table-view');
|
||||
|
||||
export const IcRoundRefresh = createIconifyIcon('ic:round-refresh');
|
||||
|
||||
export const IcRoundCreditScore = createIconifyIcon('ic:round-credit-score');
|
||||
|
||||
export const IcRoundLock = createIconifyIcon('ic:round-lock');
|
@@ -2,8 +2,6 @@ import { createIconifyIcon } from './create-icon';
|
||||
|
||||
export const MdiKeyboardEsc = createIconifyIcon('mdi:keyboard-esc');
|
||||
|
||||
export const MdiLoading = createIconifyIcon('mdi:loading');
|
||||
|
||||
export const MdiWechat = createIconifyIcon('mdi:wechat');
|
||||
|
||||
export const MdiGithub = createIconifyIcon('mdi:github');
|
||||
@@ -16,34 +14,6 @@ export const MdiPin = createIconifyIcon('mdi:pin');
|
||||
|
||||
export const MdiPinOff = createIconifyIcon('mdi:pin-off');
|
||||
|
||||
export const MdiFormatHorizontalAlignLeft = createIconifyIcon(
|
||||
'mdi:format-horizontal-align-left',
|
||||
);
|
||||
|
||||
export const MdiFormatHorizontalAlignRight = createIconifyIcon(
|
||||
'mdi:format-horizontal-align-right',
|
||||
);
|
||||
|
||||
export const MdiArrowExpandHorizontal = createIconifyIcon(
|
||||
'mdi:arrow-expand-horizontal',
|
||||
);
|
||||
|
||||
export const MdiMenuClose = createIconifyIcon('mdi:menu-close');
|
||||
|
||||
export const MdiMenuOpen = createIconifyIcon('mdi:menu-open');
|
||||
|
||||
export const MdiDockLeft = createIconifyIcon('mdi:dock-left');
|
||||
|
||||
export const MdiDockRight = createIconifyIcon('mdi:dock-right');
|
||||
|
||||
export const MdiDockBottom = createIconifyIcon('mdi:dock-bottom');
|
||||
|
||||
export const MdiDriveDocument = createIconifyIcon('mdi:drive-document');
|
||||
|
||||
export const MdiMoonAndStars = createIconifyIcon('mdi:moon-and-stars');
|
||||
|
||||
export const MdiEditBoxOutline = createIconifyIcon('mdi:edit-box-outline');
|
||||
|
||||
export const MdiQuestionMarkCircleOutline = createIconifyIcon(
|
||||
'mdi:question-mark-circle-outline',
|
||||
);
|
||||
|
@@ -2,7 +2,7 @@
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { computed, useSlots } from 'vue';
|
||||
|
||||
import { IcRoundMenu } from '@vben-core/icons';
|
||||
import { Menu } from '@vben-core/icons';
|
||||
import { VbenIconButton } from '@vben-core/shadcn-ui';
|
||||
|
||||
interface Props {
|
||||
@@ -108,7 +108,7 @@ function handleToggleMenu() {
|
||||
class="my-0 ml-2 mr-1 rounded"
|
||||
@click="handleToggleMenu"
|
||||
>
|
||||
<IcRoundMenu class="size-5" />
|
||||
<Menu class="size-4" />
|
||||
</VbenIconButton>
|
||||
<slot></slot>
|
||||
</header>
|
||||
|
@@ -12,7 +12,7 @@ interface Props {
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
fixed: true,
|
||||
height: 30,
|
||||
height: 38,
|
||||
});
|
||||
|
||||
const style = computed((): CSSProperties => {
|
||||
|
@@ -13,7 +13,7 @@ function handleCollapsed() {
|
||||
class="flex-center hover:text-foreground text-foreground/60 hover:bg-accent-hover bg-accent absolute bottom-2 left-3 z-10 cursor-pointer rounded-sm p-1 transition-all duration-300"
|
||||
@click.stop="handleCollapsed"
|
||||
>
|
||||
<MdiMenuClose v-if="collapsed" />
|
||||
<MdiMenuOpen v-else />
|
||||
<MdiMenuClose v-if="collapsed" class="size-4" />
|
||||
<MdiMenuOpen v-else class="size-4" />
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -19,7 +19,7 @@ import {
|
||||
} from 'vue';
|
||||
|
||||
import { useNamespace } from '@vben-core/hooks';
|
||||
import { IcRoundMoreHoriz } from '@vben-core/icons';
|
||||
import { Ellipsis } from '@vben-core/icons';
|
||||
import { isHttpUrl } from '@vben-core/toolkit';
|
||||
|
||||
import { UseResizeObserverReturn, useResizeObserver } from '@vueuse/core';
|
||||
@@ -338,7 +338,7 @@ function removeMenuItem(item: MenuItemRegistered) {
|
||||
</template>
|
||||
<SubMenu is-sub-menu-more path="sub-menu-more">
|
||||
<template #title>
|
||||
<IcRoundMoreHoriz />
|
||||
<Ellipsis class="size-4" />
|
||||
</template>
|
||||
<template v-for="item in getSlot.slotMore" :key="item.key">
|
||||
<component :is="item" />
|
||||
@@ -852,9 +852,9 @@ $namespace: vben;
|
||||
cursor: pointer;
|
||||
background: var(--menu-submenu-hover-background-color) !important;
|
||||
|
||||
svg {
|
||||
fill: var(--menu-submenu-hover-color);
|
||||
}
|
||||
// svg {
|
||||
// fill: var(--menu-submenu-hover-color);
|
||||
// }
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -4,10 +4,7 @@ import type { MenuItemProps } from '../interface';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { useNamespace } from '@vben-core/hooks';
|
||||
import {
|
||||
IcRoundChevronRight,
|
||||
IcRoundKeyboardArrowDown,
|
||||
} from '@vben-core/icons';
|
||||
import { ChevronDown, ChevronRight } from '@vben-core/icons';
|
||||
import { VbenIcon } from '@vben-core/shadcn-ui';
|
||||
|
||||
import { useMenuContext } from '../hooks';
|
||||
@@ -67,8 +64,8 @@ const hiddenTitle = computed(() => {
|
||||
const iconComp = computed(() => {
|
||||
return (mode.value === 'horizontal' && !isFirstLevel.value) ||
|
||||
(mode.value === 'vertical' && collapse.value)
|
||||
? IcRoundChevronRight
|
||||
: IcRoundKeyboardArrowDown;
|
||||
? ChevronRight
|
||||
: ChevronDown;
|
||||
});
|
||||
|
||||
const iconArrowStyle = computed(() => {
|
||||
@@ -102,6 +99,7 @@ const iconArrowStyle = computed(() => {
|
||||
v-show="showArrowIcon"
|
||||
:class="[e('icon-arrow')]"
|
||||
:style="iconArrowStyle"
|
||||
class="size-4"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -3,7 +3,7 @@ import type { BacktopProps } from './backtop';
|
||||
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { IcRoundArrowUpward } from '@vben-core/icons';
|
||||
import { ArrowUpToLine } from '@vben-core/icons';
|
||||
|
||||
import { VbenButton } from '../button';
|
||||
import { useBackTop } from './use-backtop';
|
||||
@@ -37,7 +37,7 @@ const { handleClick, visible } = useBackTop(props);
|
||||
variant="icon"
|
||||
@click="handleClick"
|
||||
>
|
||||
<IcRoundArrowUpward />
|
||||
<ArrowUpToLine class="size-4" />
|
||||
</VbenButton>
|
||||
</transition>
|
||||
</template>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { IBreadcrumb } from './interface';
|
||||
|
||||
import { IcRoundKeyboardArrowDown } from '@vben-core/icons';
|
||||
import { ChevronDown } from '@vben-core/icons';
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
@@ -56,7 +56,7 @@ function handleClick(path?: string) {
|
||||
class="size-5"
|
||||
/>
|
||||
{{ item.title }}
|
||||
<IcRoundKeyboardArrowDown class="size-5" />
|
||||
<ChevronDown class="size-4" />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<template
|
||||
|
@@ -2,7 +2,7 @@
|
||||
import type { HTMLAttributes } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { MdiLoading } from '@vben-core/icons';
|
||||
import { LoaderCircle } from '@vben-core/icons';
|
||||
import {
|
||||
type ButtonVariants,
|
||||
buttonVariants,
|
||||
@@ -40,9 +40,9 @@ const isDisabled = computed(() => {
|
||||
:class="cn(buttonVariants({ variant, size }), props.class)"
|
||||
:disabled="isDisabled"
|
||||
>
|
||||
<MdiLoading
|
||||
<LoaderCircle
|
||||
v-if="loading"
|
||||
class="text-md mr-2 flex-shrink-0 animate-spin"
|
||||
class="text-md mr-2 size-4 flex-shrink-0 animate-spin"
|
||||
/>
|
||||
<slot></slot>
|
||||
</Primitive>
|
||||
|
@@ -81,7 +81,7 @@ function handleClick(menu: IContextMenuItem) {
|
||||
<component
|
||||
:is="menu.icon"
|
||||
v-if="menu.icon"
|
||||
class="mr-1 w-6 text-lg"
|
||||
class="mr-2 size-4 text-lg"
|
||||
/>
|
||||
|
||||
{{ menu.text }}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { IcRoundFullscreen, IcRoundFullscreenExit } from '@vben-core/icons';
|
||||
import { Maximize, Minimize } from '@vben-core/icons';
|
||||
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
|
||||
@@ -22,7 +22,7 @@ isFullscreen.value = !!(
|
||||
</script>
|
||||
<template>
|
||||
<VbenIconButton @click="toggle">
|
||||
<IcRoundFullscreenExit v-if="isFullscreen" class="size-6" />
|
||||
<IcRoundFullscreen v-else class="size-6" />
|
||||
<Minimize v-if="isFullscreen" class="size-4" />
|
||||
<Maximize v-else class="size-4" />
|
||||
</VbenIconButton>
|
||||
</template>
|
||||
|
@@ -2,12 +2,12 @@
|
||||
import { type Component, computed } from 'vue';
|
||||
|
||||
import { Icon, IconDefault } from '@vben-core/icons';
|
||||
import { isHttpUrl, isObject, isString } from '@vben-core/toolkit';
|
||||
import { isFunction, isHttpUrl, isObject, isString } from '@vben-core/toolkit';
|
||||
|
||||
const props = defineProps<{
|
||||
// 没有是否显示默认图标
|
||||
fallback?: boolean;
|
||||
icon?: Component | string;
|
||||
icon?: Component | Function | string;
|
||||
}>();
|
||||
|
||||
const isRemoteIcon = computed(() => {
|
||||
@@ -15,7 +15,8 @@ const isRemoteIcon = computed(() => {
|
||||
});
|
||||
|
||||
const isComponent = computed(() => {
|
||||
return !isString(props.icon) && isObject(props.icon);
|
||||
const { icon } = props;
|
||||
return !isString(icon) && (isObject(icon) || isFunction(icon));
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, useSlots } from 'vue';
|
||||
|
||||
import { IcOutlineVisibility, IcOutlineVisibilityOff } from '@vben-core/icons';
|
||||
import { Eye, EyeOff } from '@vben-core/icons';
|
||||
import {
|
||||
type InputProps,
|
||||
VbenInput,
|
||||
@@ -48,8 +48,8 @@ const show = ref(false);
|
||||
class="hover:text-foreground text-foreground/60 absolute inset-y-0 right-0 top-3 flex cursor-pointer pr-3 text-lg leading-5"
|
||||
@click="show = !show"
|
||||
>
|
||||
<IcOutlineVisibility v-if="show" />
|
||||
<IcOutlineVisibilityOff v-else />
|
||||
<Eye v-if="show" class="size-4" />
|
||||
<EyeOff v-else class="size-4" />
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
@@ -42,7 +42,7 @@ function handleScroll(event: Event) {
|
||||
<div
|
||||
v-if="shadow"
|
||||
:class="{
|
||||
'opacity-100': !isAtTop,
|
||||
'border-border border-t opacity-100': !isAtTop,
|
||||
}"
|
||||
class="scrollbar-top-shadow pointer-events-none absolute top-0 z-10 h-12 w-full opacity-0 transition-opacity duration-300 ease-in-out will-change-[opacity]"
|
||||
></div>
|
||||
@@ -50,7 +50,7 @@ function handleScroll(event: Event) {
|
||||
<div
|
||||
v-if="shadow"
|
||||
:class="{
|
||||
'opacity-100': !isAtTop && !isAtBottom,
|
||||
'border-border border-b opacity-100': !isAtTop && !isAtBottom,
|
||||
}"
|
||||
class="scrollbar-bottom-shadow pointer-events-none absolute bottom-0 z-10 h-12 w-full opacity-0 transition-opacity duration-300 ease-in-out will-change-[opacity]"
|
||||
></div>
|
||||
|
@@ -17,7 +17,7 @@ import {
|
||||
SheetTrigger,
|
||||
} from '@vben-core/shadcn-ui/components/ui/sheet';
|
||||
|
||||
import { Cross2Icon } from '@radix-icons/vue';
|
||||
import { X } from 'lucide-vue-next';
|
||||
|
||||
interface Props {
|
||||
cancelText?: string;
|
||||
@@ -87,12 +87,12 @@ function handlerSubmit() {
|
||||
class="data-[state=open]:bg-secondary cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
|
||||
>
|
||||
<VbenIconButton>
|
||||
<Cross2Icon class="size-4" />
|
||||
<X class="size-4" />
|
||||
</VbenIconButton>
|
||||
</SheetClose>
|
||||
</SheetHeader>
|
||||
<div class="h-full pb-16">
|
||||
<VbenScrollbar class="h-full">
|
||||
<VbenScrollbar class="h-full" shadow>
|
||||
<slot></slot>
|
||||
</VbenScrollbar>
|
||||
</div>
|
||||
|
@@ -5,7 +5,7 @@ import type { TabConfig, TabsProps } from '../../types';
|
||||
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import { IcRoundClose, MdiPin } from '@vben-core/icons';
|
||||
import { MdiPin, X } from '@vben-core/icons';
|
||||
import { VbenContextMenu, VbenIcon, VbenScrollbar } from '@vben-core/shadcn-ui';
|
||||
|
||||
interface Props extends TabsProps {}
|
||||
@@ -146,7 +146,7 @@ function scrollIntoView() {
|
||||
class="tabs-chrome__extra absolute right-[calc(var(--gap)*2)] top-1/2 z-[3] size-4 translate-y-[-50%] opacity-0 transition-opacity group-hover:opacity-100"
|
||||
> -->
|
||||
<!-- close-icon -->
|
||||
<IcRoundClose
|
||||
<X
|
||||
v-show="
|
||||
!tab.affixTab && tabsView.length > 1 && tab.closable
|
||||
"
|
||||
|
@@ -3,7 +3,7 @@ import type { TabConfig, TabsProps } from '../../types';
|
||||
|
||||
import { computed, watch } from 'vue';
|
||||
|
||||
import { IcRoundClose, MdiPin } from '@vben-core/icons';
|
||||
import { MdiPin, X } from '@vben-core/icons';
|
||||
import { VbenContextMenu, VbenIcon, VbenScrollbar } from '@vben-core/shadcn-ui';
|
||||
import { TabDefinition } from '@vben-core/typings';
|
||||
|
||||
@@ -115,7 +115,7 @@ function scrollIntoView() {
|
||||
class="absolute right-1.5 top-1/2 z-[3] translate-y-[-50%] overflow-hidden opacity-0 transition-opacity group-hover:opacity-100 group-[.is-active]:opacity-100"
|
||||
> -->
|
||||
<!-- close-icon -->
|
||||
<IcRoundClose
|
||||
<X
|
||||
v-show="
|
||||
!tab.affixTab && tabsView.length > 1 && tab.closable
|
||||
"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { DropdownMenuProps } from '@vben-core/shadcn-ui';
|
||||
|
||||
import { IcRoundKeyboardArrowDown } from '@vben-core/icons';
|
||||
import { ChevronDown } from '@vben-core/icons';
|
||||
import { VbenDropdownMenu } from '@vben-core/shadcn-ui';
|
||||
|
||||
defineProps<DropdownMenuProps>();
|
||||
@@ -10,9 +10,9 @@ defineProps<DropdownMenuProps>();
|
||||
<template>
|
||||
<VbenDropdownMenu :menus="menus" :modal="false">
|
||||
<div
|
||||
class="flex-center hover:bg-muted hover:text-foreground text-muted-foreground border-border h-full cursor-pointer border-l px-1.5 text-lg font-semibold"
|
||||
class="flex-center hover:bg-muted hover:text-foreground text-muted-foreground border-border h-full cursor-pointer border-l px-2 text-lg font-semibold"
|
||||
>
|
||||
<IcRoundKeyboardArrowDown class="size-5" />
|
||||
<ChevronDown class="size-4" />
|
||||
</div>
|
||||
</VbenDropdownMenu>
|
||||
</template>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { IcRoundFitScreen, IcTwotoneFitScreen } from '@vben-core/icons';
|
||||
import { Fullscreen, Minimize2 } from '@vben-core/icons';
|
||||
|
||||
const screen = defineModel<boolean>('screen');
|
||||
|
||||
@@ -13,7 +13,7 @@ function toggleScreen() {
|
||||
class="flex-center hover:bg-muted hover:text-foreground text-muted-foreground border-border h-full cursor-pointer border-l px-2 text-lg font-semibold"
|
||||
@click="toggleScreen"
|
||||
>
|
||||
<IcTwotoneFitScreen v-if="screen" />
|
||||
<IcRoundFitScreen v-else />
|
||||
<Minimize2 v-if="screen" class="size-4" />
|
||||
<Fullscreen v-else class="size-4" />
|
||||
</div>
|
||||
</template>
|
||||
|
Reference in New Issue
Block a user