Browse Source

perf: reorganize the icons and reduce the volume

vince 8 months ago
parent
commit
910a3553ac
54 changed files with 341 additions and 404 deletions
  1. 3 3
      apps/web-antd/src/layouts/basic.vue
  2. 2 0
      apps/web-antd/src/router/routes/modules/dashboard.ts
  3. 2 2
      apps/web-antd/src/router/routes/modules/vben.ts
  4. 1 1
      package.json
  5. 5 106
      packages/@core/forward/preferences/src/preferences.ts
  6. 118 0
      packages/@core/forward/preferences/src/update-css-variables.ts
  7. 16 12
      packages/@core/forward/preferences/src/use-preferences.ts
  8. 1 1
      packages/@core/shared/design/src/design-tokens/dark/index.css
  9. 1 0
      packages/@core/shared/icons/package.json
  10. 2 2
      packages/@core/shared/icons/src/index.ts
  11. 46 0
      packages/@core/shared/icons/src/lucide.ts
  12. 0 88
      packages/@core/shared/icons/src/material.ts
  13. 0 30
      packages/@core/shared/icons/src/mdi.ts
  14. 2 2
      packages/@core/ui-kit/layout-ui/src/components/layout-header.vue
  15. 1 1
      packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue
  16. 2 2
      packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-collapse-button.vue
  17. 5 5
      packages/@core/ui-kit/menu-ui/src/components/menu.vue
  18. 4 6
      packages/@core/ui-kit/menu-ui/src/components/sub-menu-content.vue
  19. 2 2
      packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue
  20. 2 2
      packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb.vue
  21. 3 3
      packages/@core/ui-kit/shadcn-ui/src/components/button/button.vue
  22. 1 1
      packages/@core/ui-kit/shadcn-ui/src/components/context-menu/context-menu.vue
  23. 3 3
      packages/@core/ui-kit/shadcn-ui/src/components/full-screen/full-screen.vue
  24. 4 3
      packages/@core/ui-kit/shadcn-ui/src/components/icon/icon.vue
  25. 3 3
      packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue
  26. 2 2
      packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue
  27. 3 3
      packages/@core/ui-kit/shadcn-ui/src/components/sheet/sheet.vue
  28. 2 2
      packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue
  29. 2 2
      packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue
  30. 3 3
      packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue
  31. 3 3
      packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue
  32. 3 3
      packages/effects/common-ui/src/fallback/fallback.vue
  33. 1 2
      packages/effects/layouts/src/basic/layout.vue
  34. 17 17
      packages/effects/layouts/src/basic/tabbar/use-tabs.ts
  35. 2 2
      packages/effects/layouts/src/widgets/color-toggle.vue
  36. 13 13
      packages/effects/layouts/src/widgets/global-search/global-search.vue
  37. 3 3
      packages/effects/layouts/src/widgets/global-search/search-panel.vue
  38. 2 2
      packages/effects/layouts/src/widgets/language-toggle.vue
  39. 7 7
      packages/effects/layouts/src/widgets/layout-toggle.vue
  40. 2 2
      packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue
  41. 3 6
      packages/effects/layouts/src/widgets/notification/notification.vue
  42. 2 2
      packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue
  43. 2 2
      packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue
  44. 2 2
      packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue
  45. 2 2
      packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue
  46. 2 2
      packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue
  47. 2 2
      packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue
  48. 4 8
      packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue
  49. 6 7
      packages/effects/layouts/src/widgets/preferences/preferences-sheet.vue
  50. 4 4
      packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue
  51. 4 8
      packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue
  52. 5 9
      packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue
  53. 1 1
      packages/icons/README.md
  54. 8 5
      pnpm-lock.yaml

+ 3 - 3
apps/web-antd/src/layouts/basic.vue

@@ -4,7 +4,7 @@ import { useRouter } from 'vue-router';
 
 import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
 import { LOGIN_PATH } from '@vben/constants';
-import { IcRoundCreditScore, MdiDriveDocument, MdiGithub } from '@vben/icons';
+import { BookOpenText, CircleHelp, MdiGithub } from '@vben/icons';
 import {
   BasicLayout,
   LockScreen,
@@ -61,7 +61,7 @@ const menus = computed(() => [
         target: '_blank',
       });
     },
-    icon: MdiDriveDocument,
+    icon: BookOpenText,
     text: $t('widgets.document'),
   },
   {
@@ -79,7 +79,7 @@ const menus = computed(() => [
         target: '_blank',
       });
     },
-    icon: IcRoundCreditScore,
+    icon: CircleHelp,
     text: $t('widgets.qa'),
   },
 ]);

+ 2 - 0
apps/web-antd/src/router/routes/modules/dashboard.ts

@@ -7,6 +7,7 @@ const routes: RouteRecordRaw[] = [
   {
     component: BasicLayout,
     meta: {
+      icon: 'lucide:layout-dashboard',
       order: -1,
       title: $t('page.dashboard.title'),
     },
@@ -20,6 +21,7 @@ const routes: RouteRecordRaw[] = [
         component: () => import('#/views/dashboard/analytics/index.vue'),
         meta: {
           affixTab: true,
+          icon: 'lucide:area-chart',
           title: $t('page.dashboard.analytics'),
         },
       },

+ 2 - 2
apps/web-antd/src/router/routes/modules/vben.ts

@@ -24,7 +24,7 @@ const routes: RouteRecordRaw[] = [
         component: () => import('#/views/_core/vben/about/index.vue'),
         meta: {
           badgeType: 'dot',
-          icon: 'mdi:creative-commons',
+          icon: 'lucide:copyright',
           title: $t('page.vben.about'),
         },
       },
@@ -33,7 +33,7 @@ const routes: RouteRecordRaw[] = [
         path: 'document',
         component: IFrameView,
         meta: {
-          icon: 'mdi:flame-circle',
+          icon: 'lucide:book-open-text',
           iframeSrc: 'https://doc.vvbin.cn/',
           keepAlive: true,
           title: $t('page.vben.document'),

+ 1 - 1
package.json

@@ -66,7 +66,7 @@
     "@vue/test-utils": "^2.4.6",
     "cross-env": "^7.0.3",
     "cspell": "^8.11.0",
-    "husky": "^9.0.11",
+    "husky": "^9.1.0",
     "is-ci": "^3.0.1",
     "jsdom": "^24.1.0",
     "rimraf": "^6.0.1",

+ 5 - 106
packages/@core/forward/preferences/src/preferences.ts

@@ -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 - 0
packages/@core/forward/preferences/src/update-css-variables.ts

@@ -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 };

+ 16 - 12
packages/@core/forward/preferences/src/use-preferences.ts

@@ -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,

+ 1 - 1
packages/@core/shared/design/src/design-tokens/dark/index.css

@@ -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 /> */

+ 1 - 0
packages/@core/shared/icons/package.json

@@ -36,6 +36,7 @@
   },
   "dependencies": {
     "@iconify/vue": "^4.1.2",
+    "lucide-vue-next": "^0.408.0",
     "vue": "^3.4.32"
   }
 }

+ 2 - 2
packages/@core/shared/icons/src/index.ts

@@ -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 - 0
packages/@core/shared/icons/src/lucide.ts

@@ -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';

+ 0 - 88
packages/@core/shared/icons/src/material.ts

@@ -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');

+ 0 - 30
packages/@core/shared/icons/src/mdi.ts

@@ -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 - 2
packages/@core/ui-kit/layout-ui/src/components/layout-header.vue

@@ -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>

+ 1 - 1
packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue

@@ -12,7 +12,7 @@ interface Props {
 
 const props = withDefaults(defineProps<Props>(), {
   fixed: true,
-  height: 30,
+  height: 38,
 });
 
 const style = computed((): CSSProperties => {

+ 2 - 2
packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-collapse-button.vue

@@ -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>

+ 5 - 5
packages/@core/ui-kit/menu-ui/src/components/menu.vue

@@ -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 - 6
packages/@core/ui-kit/menu-ui/src/components/sub-menu-content.vue

@@ -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>

+ 2 - 2
packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue

@@ -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>

+ 2 - 2
packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb.vue

@@ -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

+ 3 - 3
packages/@core/ui-kit/shadcn-ui/src/components/button/button.vue

@@ -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>

+ 1 - 1
packages/@core/ui-kit/shadcn-ui/src/components/context-menu/context-menu.vue

@@ -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 }}

+ 3 - 3
packages/@core/ui-kit/shadcn-ui/src/components/full-screen/full-screen.vue

@@ -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>

+ 4 - 3
packages/@core/ui-kit/shadcn-ui/src/components/icon/icon.vue

@@ -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>
 

+ 3 - 3
packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue

@@ -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>

+ 2 - 2
packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue

@@ -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>

+ 3 - 3
packages/@core/ui-kit/shadcn-ui/src/components/sheet/sheet.vue

@@ -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>

+ 2 - 2
packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue

@@ -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
                     "

+ 2 - 2
packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue

@@ -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
                     "

+ 3 - 3
packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue

@@ -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>

+ 3 - 3
packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue

@@ -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>

+ 3 - 3
packages/effects/common-ui/src/fallback/fallback.vue

@@ -4,7 +4,7 @@ import type { FallbackProps } from './fallback';
 import { computed, defineAsyncComponent } from 'vue';
 import { useRouter } from 'vue-router';
 
-import { IcRoundArrowBackIosNew, IcRoundRefresh } from '@vben-core/icons';
+import { ArrowLeft, RotateCw } from '@vben-core/icons';
 import { $t } from '@vben-core/locales';
 import { VbenButton } from '@vben-core/shadcn-ui';
 
@@ -151,11 +151,11 @@ function refresh() {
       </p>
       <slot v-if="$slots.action" name="action"></slot>
       <VbenButton v-else-if="showBack" size="lg" @click="back">
-        <IcRoundArrowBackIosNew class="mr-2" />
+        <ArrowLeft class="mr-2 size-4" />
         {{ $t('common.backToHome') }}
       </VbenButton>
       <VbenButton v-else-if="showRefresh" size="lg" @click="refresh">
-        <IcRoundRefresh class="mr-2" />
+        <RotateCw class="mr-2 size-4" />
         {{ $t('common.refresh') }}
       </VbenButton>
     </div>

+ 1 - 2
packages/effects/layouts/src/basic/layout.vue

@@ -30,7 +30,7 @@ defineOptions({ name: 'BasicLayout' });
 
 const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
 
-const { isDark, isHeaderNav, isMixedNav, isSideMixedNav, layout } =
+const { isDark, isHeaderNav, isMixedNav, isMobile, isSideMixedNav, layout } =
   usePreferences();
 
 const headerMenuTheme = computed(() => {
@@ -63,7 +63,6 @@ const logoCollapse = computed(() => {
     return false;
   }
 
-  const { isMobile } = preferences.app;
   const { collapsed } = preferences.sidebar;
 
   if (!collapsed && isMobile) {

+ 17 - 17
packages/effects/layouts/src/basic/tabbar/use-tabs.ts

@@ -9,17 +9,17 @@ import { computed, ref, watch } from 'vue';
 import { useRoute, useRouter } from 'vue-router';
 
 import {
-  IcRoundClose,
-  IcRoundFitScreen,
-  IcRoundMultipleStop,
-  IcRoundRefresh,
-  IcRoundTableView,
-  IcTwotoneFitScreen,
-  MdiArrowExpandHorizontal,
-  MdiFormatHorizontalAlignLeft,
-  MdiFormatHorizontalAlignRight,
+  ArrowLeftToLine,
+  ArrowRightLeft,
+  ArrowRightToLine,
+  ExternalLink,
+  FoldHorizontal,
+  Fullscreen,
   MdiPin,
   MdiPinOff,
+  Minimize2,
+  RotateCw,
+  X,
 } from '@vben-core/icons';
 import { $t, useI18n } from '@vben-core/locales';
 import { updatePreferences, usePreferences } from '@vben-core/preferences';
@@ -131,7 +131,7 @@ function useTabs() {
         handler: async () => {
           await coreTabbarStore.closeTab(tab, router);
         },
-        icon: IcRoundClose,
+        icon: X,
         key: 'close',
         text: $t('preferences.tabbar.contextMenu.close'),
       },
@@ -154,7 +154,7 @@ function useTabs() {
           }
           updateContentScreen(!contentIsMaximize.value);
         },
-        icon: contentIsMaximize.value ? IcRoundFitScreen : IcTwotoneFitScreen,
+        icon: contentIsMaximize.value ? Minimize2 : Fullscreen,
         key: contentIsMaximize.value ? 'restore-maximize' : 'maximize',
         text: contentIsMaximize.value
           ? $t('preferences.tabbar.contextMenu.restoreMaximize')
@@ -165,7 +165,7 @@ function useTabs() {
         handler: async () => {
           await coreTabbarStore.refresh(router);
         },
-        icon: IcRoundRefresh,
+        icon: RotateCw,
         key: 'reload',
         text: $t('preferences.tabbar.contextMenu.reload'),
       },
@@ -178,7 +178,7 @@ function useTabs() {
           const url = `${origin}${hash ? '/#' : ''}${fullPath}`;
           openWindow(url, { target: '_blank' });
         },
-        icon: IcRoundTableView,
+        icon: ExternalLink,
         key: 'open-in-new-window',
         separator: true,
         text: $t('preferences.tabbar.contextMenu.openInNewWindow'),
@@ -189,7 +189,7 @@ function useTabs() {
         handler: async () => {
           await coreTabbarStore.closeLeftTabs(tab);
         },
-        icon: MdiFormatHorizontalAlignLeft,
+        icon: ArrowLeftToLine,
         key: 'close-left',
         text: $t('preferences.tabbar.contextMenu.closeLeft'),
       },
@@ -198,7 +198,7 @@ function useTabs() {
         handler: async () => {
           await coreTabbarStore.closeRightTabs(tab);
         },
-        icon: MdiFormatHorizontalAlignRight,
+        icon: ArrowRightToLine,
         key: 'close-right',
         separator: true,
         text: $t('preferences.tabbar.contextMenu.closeRight'),
@@ -208,7 +208,7 @@ function useTabs() {
         handler: async () => {
           await coreTabbarStore.closeOtherTabs(tab);
         },
-        icon: MdiArrowExpandHorizontal,
+        icon: FoldHorizontal,
         key: 'close-other',
         text: $t('preferences.tabbar.contextMenu.closeOther'),
       },
@@ -217,7 +217,7 @@ function useTabs() {
         handler: async () => {
           await coreTabbarStore.closeAllTabs(router);
         },
-        icon: IcRoundMultipleStop,
+        icon: ArrowRightLeft,
         key: 'close-all',
         text: $t('preferences.tabbar.contextMenu.closeAll'),
       },

+ 2 - 2
packages/effects/layouts/src/widgets/color-toggle.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { BuiltinThemeType } from '@vben-core/typings';
 
-import { IcRoundColorLens } from '@vben-core/icons';
+import { Palette } from '@vben-core/icons';
 import {
   COLOR_PRESETS,
   preferences,
@@ -56,7 +56,7 @@ function handleUpdate(value: BuiltinThemeType) {
     </div>
 
     <VbenIconButton>
-      <IcRoundColorLens class="text-primary size-5" />
+      <Palette class="text-primary size-4" />
     </VbenIconButton>
   </div>
 </template>

+ 13 - 13
packages/effects/layouts/src/widgets/global-search/global-search.vue

@@ -4,11 +4,11 @@ import type { MenuRecordRaw } from '@vben-core/typings';
 import { onMounted, onUnmounted, ref, watch } from 'vue';
 
 import {
-  IcRoundArrowDownward,
-  IcRoundArrowUpward,
-  IcRoundSearch,
-  IcRoundSubdirectoryArrowLeft,
+  ArrowDown,
+  ArrowUp,
+  CornerDownLeft,
   MdiKeyboardEsc,
+  Search,
 } from '@vben-core/icons';
 import { $t } from '@vben-core/locales';
 import {
@@ -87,8 +87,8 @@ onMounted(() => {
           class="md:bg-accent group flex h-8 cursor-pointer items-center gap-3 rounded-2xl border-none bg-none px-2 py-0.5 outline-none"
           @click="toggleOpen()"
         >
-          <IcRoundSearch
-            class="text-muted-foreground group-hover:text-foreground size-4 group-hover:opacity-100"
+          <Search
+            class="text-muted-foreground group-hover:text-foreground size-3 group-hover:opacity-100"
           />
           <span
             class="text-muted-foreground group-hover:text-foreground hidden text-xs duration-300 md:block"
@@ -111,13 +111,13 @@ onMounted(() => {
       >
         <DialogHeader>
           <DialogTitle
-            class="border-border flex h-12 items-center gap-5 border-b px-5 font-normal"
+            class="border-border flex h-12 items-center gap-3 border-b px-5 font-normal"
           >
-            <IcRoundSearch class="mt-1 size-4" />
+            <Search class="text-muted-foreground size-4" />
             <input
               v-model="keyword"
               :placeholder="$t('widgets.search.searchNavigate')"
-              class="ring-none placeholder:text-muted-foreground w-[80%] rounded-md border border-none bg-transparent p-2 text-sm outline-none ring-0 ring-offset-transparent focus-visible:ring-transparent"
+              class="ring-none placeholder:text-muted-foreground w-[80%] rounded-md border border-none bg-transparent p-2 pl-0 text-sm outline-none ring-0 ring-offset-transparent focus-visible:ring-transparent"
             />
           </DialogTitle>
           <DialogDescription />
@@ -127,16 +127,16 @@ onMounted(() => {
           class="text-muted-foreground border-border hidden flex-row rounded-b-2xl border-t px-4 py-2 text-xs sm:flex sm:justify-start sm:gap-x-4"
         >
           <div class="flex items-center">
-            <IcRoundSubdirectoryArrowLeft class="mr-1" />
+            <CornerDownLeft class="mr-1 size-3" />
             {{ $t('widgets.search.select') }}
           </div>
           <div class="flex items-center">
-            <IcRoundArrowUpward class="mr-2" />
-            <IcRoundArrowDownward class="mr-2" />
+            <ArrowUp class="mr-2 size-3" />
+            <ArrowDown class="mr-2 size-3" />
             {{ $t('widgets.search.navigate') }}
           </div>
           <div class="flex items-center">
-            <MdiKeyboardEsc class="mr-1" />
+            <MdiKeyboardEsc class="mr-1 size-3" />
             {{ $t('widgets.search.close') }}
           </div>
         </DialogFooter>

+ 3 - 3
packages/effects/layouts/src/widgets/global-search/search-panel.vue

@@ -4,7 +4,7 @@ import type { MenuRecordRaw } from '@vben-core/typings';
 import { nextTick, onMounted, ref, shallowRef, watch } from 'vue';
 import { useRouter } from 'vue-router';
 
-import { IcRoundClose, IcRoundSearchOff } from '@vben-core/icons';
+import { SearchX, X } from '@vben-core/icons';
 import { $t } from '@vben-core/locales';
 import { VbenIcon, VbenScrollbar } from '@vben-core/shadcn-ui';
 import { mapTree, traverseTreeValues, uniqueByField } from '@vben-core/toolkit';
@@ -221,7 +221,7 @@ onMounted(() => {
         v-if="keyword && searchResults.length === 0"
         class="text-muted-foreground text-center"
       >
-        <IcRoundSearchOff class="size-12" />
+        <SearchX class="mx-auto size-12" />
         <p class="my-10 text-xs">
           {{ $t('widgets.search.noResults') }}
           <span class="text-foreground text-sm font-medium">
@@ -271,7 +271,7 @@ onMounted(() => {
             class="flex-center dark:hover:bg-accent hover:text-primary-foreground rounded-full p-1 hover:scale-110"
             @click.stop="removeItem(index)"
           >
-            <IcRoundClose />
+            <X class="size-4" />
           </div>
         </li>
       </ul>

+ 2 - 2
packages/effects/layouts/src/widgets/language-toggle.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { SupportedLanguagesType } from '@vben-core/typings';
 
-import { IcBaselineLanguage } from '@vben-core/icons';
+import { Languages } from '@vben-core/icons';
 import { loadLocaleMessages } from '@vben-core/locales';
 import {
   SUPPORT_LANGUAGES,
@@ -36,7 +36,7 @@ async function handleUpdate(value: string) {
       @update:model-value="handleUpdate"
     >
       <VbenIconButton>
-        <IcBaselineLanguage class="size-5" />
+        <Languages class="size-4" />
       </VbenIconButton>
     </VbenDropdownRadioMenu>
   </div>

+ 7 - 7
packages/effects/layouts/src/widgets/layout-toggle.vue

@@ -4,7 +4,7 @@ import type { AuthPageLayoutType } from '@vben-core/typings';
 
 import { computed } from 'vue';
 
-import { MdiDockBottom, MdiDockLeft, MdiDockRight } from '@vben-core/icons';
+import { InspectionPanel, PanelLeft, PanelRight } from '@vben-core/icons';
 import { $t } from '@vben-core/locales';
 import {
   preferences,
@@ -19,17 +19,17 @@ defineOptions({
 
 const menus = computed((): VbenDropdownMenuItem[] => [
   {
-    icon: MdiDockLeft,
+    icon: PanelLeft,
     key: 'panel-left',
     text: $t('authentication.layout.alignLeft'),
   },
   {
-    icon: MdiDockBottom,
+    icon: InspectionPanel,
     key: 'panel-center',
     text: $t('authentication.layout.center'),
   },
   {
-    icon: MdiDockRight,
+    icon: PanelRight,
     key: 'panel-right',
     text: $t('authentication.layout.alignRight'),
   },
@@ -53,9 +53,9 @@ function handleUpdate(value: string) {
     @update:model-value="handleUpdate"
   >
     <VbenIconButton>
-      <MdiDockRight v-if="authPanelRight" class="size-5" />
-      <MdiDockLeft v-if="authPanelLeft" class="size-5" />
-      <MdiDockBottom v-if="authPanelCenter" class="size-5" />
+      <PanelRight v-if="authPanelRight" class="size-4" />
+      <PanelLeft v-if="authPanelLeft" class="size-4" />
+      <InspectionPanel v-if="authPanelCenter" class="size-4" />
     </VbenIconButton>
   </VbenDropdownRadioMenu>
 </template>

+ 2 - 2
packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import { computed, reactive, ref, watchEffect } from 'vue';
 
-import { IcRoundLock } from '@vben-core/icons';
+import { LockKeyhole } from '@vben-core/icons';
 import { $t, useI18n } from '@vben-core/locales';
 import {
   VbenAvatar,
@@ -92,7 +92,7 @@ function toggleUnlockForm() {
           class="flex-col-center text-foreground/80 hover:text-foreground group my-4 cursor-pointer text-xl font-semibold"
           @click="toggleUnlockForm"
         >
-          <IcRoundLock
+          <LockKeyhole
             class="size-5 transition-all duration-300 group-hover:scale-125"
           />
           <span>{{ $t('widgets.lockScreen.unlock') }}</span>

+ 3 - 6
packages/effects/layouts/src/widgets/notification/notification.vue

@@ -1,10 +1,7 @@
 <script lang="ts" setup>
 import type { NotificationItem } from './types';
 
-import {
-  IcRoundMarkEmailRead,
-  IcRoundNotificationsNone,
-} from '@vben-core/icons';
+import { Bell, MailCheck } from '@vben-core/icons';
 import { $t } from '@vben-core/locales';
 import {
   VbenButton,
@@ -75,7 +72,7 @@ function handleClick(item: NotificationItem) {
             v-if="dot"
             class="bg-primary absolute right-0.5 top-0.5 h-2 w-2 rounded"
           ></span>
-          <IcRoundNotificationsNone class="size-5" />
+          <Bell class="size-4" />
         </VbenIconButton>
       </div>
     </template>
@@ -87,7 +84,7 @@ function handleClick(item: NotificationItem) {
           :tooltip="$t('widgets.markAllAsRead')"
           @click="handleMakeAll"
         >
-          <IcRoundMarkEmailRead />
+          <MailCheck class="size-4" />
         </VbenIconButton>
       </div>
       <VbenScrollbar v-if="notifications.length > 0">

+ 2 - 2
packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue

@@ -3,7 +3,7 @@ import type { SelectOption } from '@vben-core/typings';
 
 import { useSlots } from 'vue';
 
-import { MdiQuestionMarkCircleOutline } from '@vben-core/icons';
+import { CircleHelp } from '@vben-core/icons';
 import { Input, VbenTooltip } from '@vben-core/shadcn-ui';
 
 defineOptions({
@@ -41,7 +41,7 @@ const slots = useSlots();
 
       <VbenTooltip v-if="slots.tip" side="bottom">
         <template #trigger>
-          <MdiQuestionMarkCircleOutline class="ml-1 cursor-help" />
+          <CircleHelp class="ml-1 size-3 cursor-help" />
         </template>
         <slot name="tip"></slot>
       </VbenTooltip>

+ 2 - 2
packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue

@@ -3,7 +3,7 @@ import type { LayoutType } from '@vben-core/typings';
 
 import { type Component, computed } from 'vue';
 
-import { MdiQuestionMarkCircleOutline } from '@vben-core/icons';
+import { CircleHelp } from '@vben-core/icons';
 import { $t } from '@vben-core/locales';
 import { VbenTooltip } from '@vben-core/shadcn-ui';
 
@@ -84,7 +84,7 @@ function activeClass(theme: string): string[] {
           {{ theme.name }}
           <VbenTooltip v-if="theme.tip" side="bottom">
             <template #trigger>
-              <MdiQuestionMarkCircleOutline class="ml-1 cursor-help" />
+              <CircleHelp class="ml-1 size-3 cursor-help" />
             </template>
             {{ theme.tip }}
           </VbenTooltip>

+ 2 - 2
packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue

@@ -3,7 +3,7 @@ import type { SelectOption } from '@vben-core/typings';
 
 import { useSlots } from 'vue';
 
-import { MdiQuestionMarkCircleOutline } from '@vben-core/icons';
+import { CircleHelp } from '@vben-core/icons';
 import {
   NumberField,
   NumberFieldContent,
@@ -48,7 +48,7 @@ const slots = useSlots();
 
       <VbenTooltip v-if="slots.tip" side="bottom">
         <template #trigger>
-          <MdiQuestionMarkCircleOutline class="ml-1 cursor-help" />
+          <CircleHelp class="ml-1 size-3 cursor-help" />
         </template>
         <slot name="tip"></slot>
       </VbenTooltip>

+ 2 - 2
packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue

@@ -3,7 +3,7 @@ import type { SelectOption } from '@vben-core/typings';
 
 import { useSlots } from 'vue';
 
-import { MdiQuestionMarkCircleOutline } from '@vben-core/icons';
+import { CircleHelp } from '@vben-core/icons';
 import {
   Select,
   SelectContent,
@@ -48,7 +48,7 @@ const slots = useSlots();
 
       <VbenTooltip v-if="slots.tip" side="bottom">
         <template #trigger>
-          <MdiQuestionMarkCircleOutline class="ml-1 cursor-help" />
+          <CircleHelp class="ml-1 size-3 cursor-help" />
         </template>
         <slot name="tip"></slot>
       </VbenTooltip>

+ 2 - 2
packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import { useSlots } from 'vue';
 
-import { MdiQuestionMarkCircleOutline } from '@vben-core/icons';
+import { CircleHelp } from '@vben-core/icons';
 import { Switch, VbenTooltip } from '@vben-core/shadcn-ui';
 
 defineOptions({
@@ -34,7 +34,7 @@ function handleClick() {
 
       <VbenTooltip v-if="slots.tip" side="bottom">
         <template #trigger>
-          <MdiQuestionMarkCircleOutline class="ml-1 cursor-help" />
+          <CircleHelp class="ml-1 size-3 cursor-help" />
         </template>
         <slot name="tip"></slot>
       </VbenTooltip>

+ 2 - 2
packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue

@@ -3,7 +3,7 @@ import type { BuiltinThemeType } from '@vben-core/typings';
 
 import { computed, ref } from 'vue';
 
-import { MdiEditBoxOutline } from '@vben-core/icons';
+import { UserRoundPen } from '@vben-core/icons';
 import { $t } from '@vben-core/locales';
 import {
   BUILT_IN_THEME_PRESETS,
@@ -114,7 +114,7 @@ function selectColor() {
           <template v-else>
             <div class="size-full px-10 py-2" @click.stop="selectColor">
               <div class="flex-center relative size-5 rounded-sm">
-                <MdiEditBoxOutline
+                <UserRoundPen
                   class="absolute z-10 size-5 opacity-60 group-hover:opacity-100"
                 />
                 <input

+ 4 - 8
packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue

@@ -3,11 +3,7 @@ import type { ThemeModeType } from '@vben-core/typings';
 
 import type { Component } from 'vue';
 
-import {
-  IcRoundMotionPhotosAuto,
-  IcRoundWbSunny,
-  MdiMoonAndStars,
-} from '@vben-core/icons';
+import { MoonStar, Sun, SunMoon } from '@vben-core/icons';
 import { $t } from '@vben-core/locales';
 
 import SwitchItem from '../switch-item.vue';
@@ -23,15 +19,15 @@ const themeSemiDarkMenu = defineModel<boolean>('themeSemiDarkMenu', {
 
 const THEME_PRESET: Array<{ icon: Component; name: ThemeModeType }> = [
   {
-    icon: IcRoundWbSunny,
+    icon: Sun,
     name: 'light',
   },
   {
-    icon: MdiMoonAndStars,
+    icon: MoonStar,
     name: 'dark',
   },
   {
-    icon: IcRoundMotionPhotosAuto,
+    icon: SunMoon,
     name: 'auto',
   },
 ];

+ 6 - 7
packages/effects/layouts/src/widgets/preferences/preferences-sheet.vue

@@ -13,7 +13,7 @@ import type {
 
 import { computed, ref } from 'vue';
 
-import { IcRoundFolderCopy, IcRoundRestartAlt } from '@vben-core/icons';
+import { Copy, RotateCw, SwatchBook } from '@vben-core/icons';
 import { $t, loadLocaleMessages } from '@vben-core/locales';
 import {
   clearPreferencesCache,
@@ -51,7 +51,6 @@ import {
   Theme,
   Widget,
 } from './blocks';
-import IconSetting from './icons/setting.vue';
 import { useOpenPreferences } from './use-open-preferences';
 
 const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
@@ -225,9 +224,9 @@ async function handleReset() {
       <template #trigger>
         <VbenButton
           :title="$t('preferences.title')"
-          class="bg-primary flex-col-center h-12 w-12 cursor-pointer rounded-l-lg rounded-r-none border-none"
+          class="bg-primary flex-col-center h-10 w-10 cursor-pointer rounded-l-lg rounded-r-none border-none"
         >
-          <IconSetting class="duration-3000 fill-primary-foreground text-2xl" />
+          <SwatchBook class="size-5" />
         </VbenButton>
       </template>
       <template #extra>
@@ -241,7 +240,7 @@ async function handleReset() {
               v-if="diffPreference"
               class="bg-primary absolute right-0.5 top-0.5 h-2 w-2 rounded"
             ></span>
-            <IcRoundRestartAlt class="size-5" @click="handleReset" />
+            <RotateCw class="size-4" @click="handleReset" />
           </VbenIconButton>
         </div>
       </template>
@@ -408,7 +407,7 @@ async function handleReset() {
           variant="default"
           @click="handleCopy"
         >
-          <IcRoundFolderCopy class="mr-2 size-3" />
+          <Copy class="mr-2 size-3" />
           {{ $t('preferences.copyPreferences') }}
         </VbenButton>
         <VbenButton
@@ -418,7 +417,7 @@ async function handleReset() {
           variant="ghost"
           @click="handleClearCache"
         >
-          <!-- <IcRoundRestartAlt class="mr-2 size-4" /> -->
+          <!-- <RotateCw class="mr-2 size-4" /> -->
           {{ $t('preferences.clearAndLogout') }}
         </VbenButton>
       </template>

+ 4 - 4
packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue

@@ -34,7 +34,7 @@ const bindProps = computed(() => {
     : {
         class: 'rounded-full',
         size: 'icon' as const,
-        style: { padding: '6px' },
+        style: { padding: '7px' },
         variant: 'icon' as const,
       };
 });
@@ -130,18 +130,18 @@ function toggleTheme(event: MouseEvent) {
   }
 
   &__sun {
-    @apply fill-foreground/80 stroke-none;
+    @apply fill-foreground/70 stroke-none;
 
     transition: transform 1.6s cubic-bezier(0.25, 0, 0.2, 1);
     transform-origin: center center;
 
     &:hover > svg > & {
-      @apply fill-foreground/80;
+      @apply fill-foreground/70;
     }
   }
 
   &__sun-beams {
-    @apply stroke-foreground/80 stroke-[2px];
+    @apply stroke-foreground/70 stroke-[2px];
 
     transition:
       transform 1.6s cubic-bezier(0.5, 1.5, 0.75, 1.25),

+ 4 - 8
packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue

@@ -1,11 +1,7 @@
 <script lang="ts" setup>
 import type { ThemeModeType } from '@vben-core/typings';
 
-import {
-  IcRoundMotionPhotosAuto,
-  IcRoundWbSunny,
-  MdiMoonAndStars,
-} from '@vben-core/icons';
+import { MoonStar, Sun, SunMoon } from '@vben-core/icons';
 import { $t } from '@vben-core/locales';
 import {
   preferences,
@@ -38,17 +34,17 @@ const { isDark } = usePreferences();
 
 const PRESETS = [
   {
-    icon: IcRoundWbSunny,
+    icon: Sun,
     name: 'light',
     title: $t('preferences.theme.light'),
   },
   {
-    icon: MdiMoonAndStars,
+    icon: MoonStar,
     name: 'dark',
     title: $t('preferences.theme.dark'),
   },
   {
-    icon: IcRoundMotionPhotosAuto,
+    icon: SunMoon,
     name: 'auto',
     title: $t('preferences.followSystem'),
   },

+ 5 - 9
packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue

@@ -4,11 +4,7 @@ import type { AnyFunction } from '@vben-core/typings';
 import type { Component } from 'vue';
 import { computed, ref } from 'vue';
 
-import {
-  IcRoundLock,
-  IcRoundLogout,
-  IcRoundSettingsSuggest,
-} from '@vben-core/icons';
+import { LockKeyhole, LogOut, SwatchBook } from '@vben-core/icons';
 import { $t } from '@vben-core/locales';
 import { preferences, usePreferences } from '@vben-core/preferences';
 import {
@@ -203,7 +199,7 @@ if (enableShortcutKey.value) {
         class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
         @click="menu.handler"
       >
-        <VbenIcon :icon="menu.icon" class="mr-2 size-5" />
+        <VbenIcon :icon="menu.icon" class="mr-2 size-4" />
         {{ menu.text }}
       </DropdownMenuItem>
       <DropdownMenuSeparator />
@@ -211,7 +207,7 @@ if (enableShortcutKey.value) {
         class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
         @click="handleOpenPreference"
       >
-        <IcRoundSettingsSuggest class="mr-2 size-5" />
+        <SwatchBook class="mr-2 size-4" />
         {{ $t('preferences.title') }}
         <DropdownMenuShortcut v-if="enablePreferencesShortcutKey">
           {{ altView }} ,
@@ -222,7 +218,7 @@ if (enableShortcutKey.value) {
         class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
         @click="handleOpenLock"
       >
-        <IcRoundLock class="mr-2 size-5" />
+        <LockKeyhole class="mr-2 size-4" />
         {{ $t('widgets.lockScreen.title') }}
         <DropdownMenuShortcut v-if="enableLockScreenShortcutKey">
           {{ altView }} L
@@ -233,7 +229,7 @@ if (enableShortcutKey.value) {
         class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
         @click="handleLogout"
       >
-        <IcRoundLogout class="mr-2 size-5" />
+        <LogOut class="mr-2 size-4" />
         {{ $t('common.logout') }}
         <DropdownMenuShortcut v-if="enableLogoutShortcutKey">
           {{ altView }} Q

+ 1 - 1
packages/icons/README.md

@@ -15,5 +15,5 @@ pnpm add @vben/icons --workspace
 ### 使用
 
 ```ts
-import { IcRoundClose } from '@vben/icons';
+import { X } from '@vben/icons';
 ```

+ 8 - 5
pnpm-lock.yaml

@@ -67,8 +67,8 @@ importers:
         specifier: ^8.11.0
         version: 8.11.0
       husky:
-        specifier: ^9.0.11
-        version: 9.0.11
+        specifier: ^9.1.0
+        version: 9.1.0
       is-ci:
         specifier: ^3.0.1
         version: 3.0.1
@@ -680,6 +680,9 @@ importers:
       '@iconify/vue':
         specifier: ^4.1.2
         version: 4.1.2(vue@3.4.32(typescript@5.5.3))
+      lucide-vue-next:
+        specifier: ^0.408.0
+        version: 0.408.0(vue@3.4.32(typescript@5.5.3))
       vue:
         specifier: ^3.4.32
         version: 3.4.32(typescript@5.5.3)
@@ -5844,8 +5847,8 @@ packages:
   humanize-ms@1.2.1:
     resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
 
-  husky@9.0.11:
-    resolution: {integrity: sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==}
+  husky@9.1.0:
+    resolution: {integrity: sha512-8XCjbomYTGdNF2h50dio3T3zghmZ9f/ZNzr99YwSkvDdhEjJGs5qzy8tbFx+SG8yCx2wn9nMVfZxVrr/yT8gNQ==}
     engines: {node: '>=18'}
     hasBin: true
 
@@ -14945,7 +14948,7 @@ snapshots:
     dependencies:
       ms: 2.1.3
 
-  husky@9.0.11: {}
+  husky@9.1.0: {}
 
   iconv-lite@0.4.24:
     dependencies: