feat: add swap component (#4149)
parent
b28740042b
commit
83fcdec37c
|
@ -239,9 +239,11 @@ css 变量内的颜色,必须使用 `hsl` 格式,如 `0 0% 100%`,不需要
|
||||||
|
|
||||||
```css
|
```css
|
||||||
/* */
|
/* */
|
||||||
:root {
|
.dark,
|
||||||
|
.dark[data-theme='custom'],
|
||||||
|
.dark[data-theme='default'] {
|
||||||
/* Background color for <Card /> */
|
/* Background color for <Card /> */
|
||||||
--card: 0 0% 30%;
|
--card: 222.34deg 10.43% 12.27%;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import ora, { Ora } from 'ora';
|
import ora, { type Ora } from 'ora';
|
||||||
|
|
||||||
interface SpinnerOptions {
|
interface SpinnerOptions {
|
||||||
failedText?: string;
|
failedText?: string;
|
||||||
|
|
|
@ -52,12 +52,12 @@
|
||||||
--secondary-foreground: 0 0% 98%;
|
--secondary-foreground: 0 0% 98%;
|
||||||
|
|
||||||
/* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
|
/* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
|
||||||
--accent: 240 3.7% 15.9%;
|
--accent: 216 5% 19%;
|
||||||
--accent-hover: 240 3.7% 20.9%;
|
--accent-hover: 216 5% 24%;
|
||||||
--accent-foreground: 0 0% 98%;
|
--accent-foreground: 0 0% 98%;
|
||||||
|
|
||||||
/* Darker color */
|
/* Darker color */
|
||||||
--heavy: 240 3.7% 20.9%;
|
--heavy: 216 5% 24%;
|
||||||
--heavy-foreground: var(--accent-foreground);
|
--heavy-foreground: var(--accent-foreground);
|
||||||
|
|
||||||
/* Default border color */
|
/* Default border color */
|
||||||
|
|
|
@ -89,7 +89,7 @@
|
||||||
|
|
||||||
/* menu */
|
/* menu */
|
||||||
--sidebar: 0 0% 100%;
|
--sidebar: 0 0% 100%;
|
||||||
--sidebar-deep: 210 11.11% 96.47%;
|
--sidebar-deep: 0 0% 100%;
|
||||||
--menu: var(--sidebar);
|
--menu: var(--sidebar);
|
||||||
|
|
||||||
accent-color: var(--primary);
|
accent-color: var(--primary);
|
||||||
|
|
|
@ -84,7 +84,7 @@ function handleToggleMenu() {
|
||||||
</div>
|
</div>
|
||||||
<VbenIconButton
|
<VbenIconButton
|
||||||
v-if="showToggleBtn || isMobile"
|
v-if="showToggleBtn || isMobile"
|
||||||
class="my-0 ml-2 mr-1 rounded"
|
class="my-0 ml-2 mr-1 rounded-md"
|
||||||
@click="handleToggleMenu"
|
@click="handleToggleMenu"
|
||||||
>
|
>
|
||||||
<Menu class="size-4" />
|
<Menu class="size-4" />
|
||||||
|
|
|
@ -24,9 +24,8 @@ interface Props {
|
||||||
domVisible?: boolean;
|
domVisible?: boolean;
|
||||||
/**
|
/**
|
||||||
* 扩展区域宽度
|
* 扩展区域宽度
|
||||||
* @default 180
|
|
||||||
*/
|
*/
|
||||||
extraWidth?: number;
|
extraWidth: number;
|
||||||
/**
|
/**
|
||||||
* 固定扩展区域
|
* 固定扩展区域
|
||||||
* @default false
|
* @default false
|
||||||
|
@ -69,13 +68,12 @@ interface Props {
|
||||||
/**
|
/**
|
||||||
* 主题
|
* 主题
|
||||||
*/
|
*/
|
||||||
theme?: string;
|
theme: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 宽度
|
* 宽度
|
||||||
* @default 180
|
|
||||||
*/
|
*/
|
||||||
width?: number;
|
width: number;
|
||||||
/**
|
/**
|
||||||
* zIndex
|
* zIndex
|
||||||
* @default 0
|
* @default 0
|
||||||
|
@ -87,7 +85,6 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
collapseHeight: 42,
|
collapseHeight: 42,
|
||||||
collapseWidth: 48,
|
collapseWidth: 48,
|
||||||
domVisible: true,
|
domVisible: true,
|
||||||
extraWidth: 180,
|
|
||||||
fixedExtra: false,
|
fixedExtra: false,
|
||||||
isSidebarMixed: false,
|
isSidebarMixed: false,
|
||||||
marginTop: 0,
|
marginTop: 0,
|
||||||
|
@ -95,8 +92,6 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
paddingTop: 0,
|
paddingTop: 0,
|
||||||
show: true,
|
show: true,
|
||||||
showCollapseButton: true,
|
showCollapseButton: true,
|
||||||
theme: 'dark',
|
|
||||||
width: 180,
|
|
||||||
zIndex: 0,
|
zIndex: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -181,10 +176,8 @@ const extraContentStyle = computed((): CSSProperties => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const collapseStyle = computed((): CSSProperties => {
|
const collapseStyle = computed((): CSSProperties => {
|
||||||
const { collapseHeight } = props;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
height: `${collapseHeight}px`,
|
height: `${props.collapseHeight}px`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
import type { LayoutType } from '@vben-core/typings';
|
||||||
|
|
||||||
|
import type { VbenLayoutProps } from '../vben-layout';
|
||||||
|
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
export function useLayout(props: VbenLayoutProps) {
|
||||||
|
const currentLayout = computed(() =>
|
||||||
|
props.isMobile ? 'sidebar-nav' : (props.layout as LayoutType),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否全屏显示content,不需要侧边、底部、顶部、tab区域
|
||||||
|
*/
|
||||||
|
const isFullContent = computed(() => currentLayout.value === 'full-content');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否侧边混合模式
|
||||||
|
*/
|
||||||
|
const isSidebarMixedNav = computed(
|
||||||
|
() => currentLayout.value === 'sidebar-mixed-nav',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为头部导航模式
|
||||||
|
*/
|
||||||
|
const isHeaderNav = computed(() => currentLayout.value === 'header-nav');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为混合导航模式
|
||||||
|
*/
|
||||||
|
const isMixedNav = computed(() => currentLayout.value === 'mixed-nav');
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentLayout,
|
||||||
|
isFullContent,
|
||||||
|
isHeaderNav,
|
||||||
|
isMixedNav,
|
||||||
|
isSidebarMixedNav,
|
||||||
|
};
|
||||||
|
}
|
|
@ -62,12 +62,6 @@ interface VbenLayoutProps {
|
||||||
* @default 48
|
* @default 48
|
||||||
*/
|
*/
|
||||||
headerHeight?: number;
|
headerHeight?: number;
|
||||||
/**
|
|
||||||
* header高度增加高度
|
|
||||||
* 在顶部存在导航时,额外加高header高度
|
|
||||||
* @default 10
|
|
||||||
*/
|
|
||||||
headerHeightOffset?: number;
|
|
||||||
/**
|
/**
|
||||||
* 顶栏是否隐藏
|
* 顶栏是否隐藏
|
||||||
* @default false
|
* @default false
|
||||||
|
@ -133,11 +127,7 @@ interface VbenLayoutProps {
|
||||||
* @default 80
|
* @default 80
|
||||||
*/
|
*/
|
||||||
sidebarMixedWidth?: number;
|
sidebarMixedWidth?: number;
|
||||||
/**
|
|
||||||
* 侧边栏是否半深色
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
sidebarSemiDark?: boolean;
|
|
||||||
/**
|
/**
|
||||||
* 侧边栏
|
* 侧边栏
|
||||||
* @default dark
|
* @default dark
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
LayoutSidebar,
|
LayoutSidebar,
|
||||||
LayoutTabbar,
|
LayoutTabbar,
|
||||||
} from './components';
|
} from './components';
|
||||||
|
import { useLayout } from './hooks/use-layout';
|
||||||
|
|
||||||
interface Props extends VbenLayoutProps {}
|
interface Props extends VbenLayoutProps {}
|
||||||
|
|
||||||
|
@ -32,7 +33,6 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
footerFixed: true,
|
footerFixed: true,
|
||||||
footerHeight: 32,
|
footerHeight: 32,
|
||||||
headerHeight: 50,
|
headerHeight: 50,
|
||||||
headerHeightOffset: 10,
|
|
||||||
headerHidden: false,
|
headerHidden: false,
|
||||||
headerMode: 'fixed',
|
headerMode: 'fixed',
|
||||||
headerToggleSidebarButton: true,
|
headerToggleSidebarButton: true,
|
||||||
|
@ -43,7 +43,6 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
sidebarExtraCollapsedWidth: 60,
|
sidebarExtraCollapsedWidth: 60,
|
||||||
sidebarHidden: false,
|
sidebarHidden: false,
|
||||||
sidebarMixedWidth: 80,
|
sidebarMixedWidth: 80,
|
||||||
sidebarSemiDark: true,
|
|
||||||
sidebarTheme: 'dark',
|
sidebarTheme: 'dark',
|
||||||
sidebarWidth: 180,
|
sidebarWidth: 180,
|
||||||
sideCollapseWidth: 60,
|
sideCollapseWidth: 60,
|
||||||
|
@ -73,57 +72,23 @@ const {
|
||||||
|
|
||||||
const { y: mouseY } = useMouse({ target: contentRef, type: 'client' });
|
const { y: mouseY } = useMouse({ target: contentRef, type: 'client' });
|
||||||
|
|
||||||
const realLayout = computed(() =>
|
const {
|
||||||
props.isMobile ? 'sidebar-nav' : props.layout,
|
currentLayout,
|
||||||
);
|
isFullContent,
|
||||||
|
isHeaderNav,
|
||||||
/**
|
isMixedNav,
|
||||||
* 是否全屏显示content,不需要侧边、底部、顶部、tab区域
|
isSidebarMixedNav,
|
||||||
*/
|
} = useLayout(props);
|
||||||
const fullContent = computed(() => realLayout.value === 'full-content');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否侧边混合模式
|
|
||||||
*/
|
|
||||||
const isSidebarMixedNav = computed(
|
|
||||||
() => realLayout.value === 'sidebar-mixed-nav',
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否为头部导航模式
|
|
||||||
*/
|
|
||||||
const isHeaderNav = computed(() => realLayout.value === 'header-nav');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否为混合导航模式
|
|
||||||
*/
|
|
||||||
const isMixedNav = computed(() => realLayout.value === 'mixed-nav');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 顶栏是否自动隐藏
|
* 顶栏是否自动隐藏
|
||||||
*/
|
*/
|
||||||
const isHeaderAutoMode = computed(() => props.headerMode === 'auto');
|
const isHeaderAutoMode = computed(() => props.headerMode === 'auto');
|
||||||
|
|
||||||
/**
|
|
||||||
* header区域高度
|
|
||||||
*/
|
|
||||||
const getHeaderHeight = computed(() => {
|
|
||||||
const { headerHeight, headerHeightOffset } = props;
|
|
||||||
|
|
||||||
// if (!headerVisible) {
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 顶部存在导航时,增加10
|
|
||||||
const offset = isMixedNav.value || isHeaderNav.value ? headerHeightOffset : 0;
|
|
||||||
|
|
||||||
return headerHeight + offset;
|
|
||||||
});
|
|
||||||
|
|
||||||
const headerWrapperHeight = computed(() => {
|
const headerWrapperHeight = computed(() => {
|
||||||
let height = 0;
|
let height = 0;
|
||||||
if (props.headerVisible && !props.headerHidden) {
|
if (props.headerVisible && !props.headerHidden) {
|
||||||
height += getHeaderHeight.value;
|
height += props.headerHeight;
|
||||||
}
|
}
|
||||||
if (props.tabbarEnable) {
|
if (props.tabbarEnable) {
|
||||||
height += props.tabbarHeight;
|
height += props.tabbarHeight;
|
||||||
|
@ -151,8 +116,8 @@ const sidebarEnableState = computed(() => {
|
||||||
* 侧边区域离顶部高度
|
* 侧边区域离顶部高度
|
||||||
*/
|
*/
|
||||||
const sidebarMarginTop = computed(() => {
|
const sidebarMarginTop = computed(() => {
|
||||||
const { isMobile } = props;
|
const { headerHeight, isMobile } = props;
|
||||||
return isMixedNav.value && !isMobile ? getHeaderHeight.value : 0;
|
return isMixedNav.value && !isMobile ? headerHeight : 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -195,30 +160,13 @@ const sidebarExtraWidth = computed(() => {
|
||||||
/**
|
/**
|
||||||
* 是否侧边栏模式,包含混合侧边
|
* 是否侧边栏模式,包含混合侧边
|
||||||
*/
|
*/
|
||||||
const isSideMode = computed(() =>
|
const isSideMode = computed(
|
||||||
['mixed-nav', 'sidebar-mixed-nav', 'sidebar-nav'].includes(realLayout.value),
|
() =>
|
||||||
|
currentLayout.value === 'mixed-nav' ||
|
||||||
|
currentLayout.value === 'sidebar-mixed-nav' ||
|
||||||
|
currentLayout.value === 'sidebar-nav',
|
||||||
);
|
);
|
||||||
|
|
||||||
const showSidebar = computed(() => {
|
|
||||||
// if (isMixedNav.value && !props.sideHidden) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
return isSideMode.value && sidebarEnable.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
const sidebarFace = computed(() => {
|
|
||||||
const { sidebarSemiDark, sidebarTheme } = props;
|
|
||||||
const isDark = sidebarTheme === 'dark' || sidebarSemiDark;
|
|
||||||
return {
|
|
||||||
theme: isDark ? 'dark' : 'light',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 遮罩可见性
|
|
||||||
*/
|
|
||||||
const maskVisible = computed(() => !sidebarCollapse.value && props.isMobile);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* header fixed值
|
* header fixed值
|
||||||
*/
|
*/
|
||||||
|
@ -232,13 +180,25 @@ const headerFixed = computed(() => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const showSidebar = computed(() => {
|
||||||
|
// if (isMixedNav.value && !props.sideHidden) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
return isSideMode.value && sidebarEnable.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 遮罩可见性
|
||||||
|
*/
|
||||||
|
const maskVisible = computed(() => !sidebarCollapse.value && props.isMobile);
|
||||||
|
|
||||||
const mainStyle = computed(() => {
|
const mainStyle = computed(() => {
|
||||||
let width = '100%';
|
let width = '100%';
|
||||||
let sidebarAndExtraWidth = 'unset';
|
let sidebarAndExtraWidth = 'unset';
|
||||||
if (
|
if (
|
||||||
headerFixed.value &&
|
headerFixed.value &&
|
||||||
realLayout.value !== 'header-nav' &&
|
currentLayout.value !== 'header-nav' &&
|
||||||
realLayout.value !== 'mixed-nav' &&
|
currentLayout.value !== 'mixed-nav' &&
|
||||||
showSidebar.value &&
|
showSidebar.value &&
|
||||||
!props.isMobile
|
!props.isMobile
|
||||||
) {
|
) {
|
||||||
|
@ -253,7 +213,7 @@ const mainStyle = computed(() => {
|
||||||
? getSideCollapseWidth.value
|
? getSideCollapseWidth.value
|
||||||
: props.sidebarMixedWidth;
|
: props.sidebarMixedWidth;
|
||||||
const sideWidth = sidebarExtraCollapse.value
|
const sideWidth = sidebarExtraCollapse.value
|
||||||
? getSideCollapseWidth.value
|
? props.sidebarExtraCollapsedWidth
|
||||||
: props.sidebarWidth;
|
: props.sidebarWidth;
|
||||||
|
|
||||||
// 100% - 侧边菜单混合宽度 - 菜单宽度
|
// 100% - 侧边菜单混合宽度 - 菜单宽度
|
||||||
|
@ -312,7 +272,7 @@ const contentStyle = computed((): CSSProperties => {
|
||||||
return {
|
return {
|
||||||
marginTop:
|
marginTop:
|
||||||
fixed &&
|
fixed &&
|
||||||
!fullContent.value &&
|
!isFullContent.value &&
|
||||||
!headerIsHidden.value &&
|
!headerIsHidden.value &&
|
||||||
(!isHeaderAutoMode.value || scrollY.value < headerWrapperHeight.value)
|
(!isHeaderAutoMode.value || scrollY.value < headerWrapperHeight.value)
|
||||||
? `${headerWrapperHeight.value}px`
|
? `${headerWrapperHeight.value}px`
|
||||||
|
@ -330,11 +290,11 @@ const headerZIndex = computed(() => {
|
||||||
const headerWrapperStyle = computed((): CSSProperties => {
|
const headerWrapperStyle = computed((): CSSProperties => {
|
||||||
const fixed = headerFixed.value;
|
const fixed = headerFixed.value;
|
||||||
return {
|
return {
|
||||||
height: fullContent.value ? '0' : `${headerWrapperHeight.value}px`,
|
height: isFullContent.value ? '0' : `${headerWrapperHeight.value}px`,
|
||||||
left: isMixedNav.value ? 0 : mainStyle.value.sidebarAndExtraWidth,
|
left: isMixedNav.value ? 0 : mainStyle.value.sidebarAndExtraWidth,
|
||||||
position: fixed ? 'fixed' : 'static',
|
position: fixed ? 'fixed' : 'static',
|
||||||
top:
|
top:
|
||||||
headerIsHidden.value || fullContent.value
|
headerIsHidden.value || isFullContent.value
|
||||||
? `-${headerWrapperHeight.value}px`
|
? `-${headerWrapperHeight.value}px`
|
||||||
: 0,
|
: 0,
|
||||||
width: mainStyle.value.width,
|
width: mainStyle.value.width,
|
||||||
|
@ -403,7 +363,10 @@ watch(
|
||||||
watch(
|
watch(
|
||||||
[() => props.headerMode, () => mouseY.value],
|
[() => props.headerMode, () => mouseY.value],
|
||||||
() => {
|
() => {
|
||||||
if (!isHeaderAutoMode.value || isMixedNav.value || fullContent.value) {
|
if (!isHeaderAutoMode.value || isMixedNav.value || isFullContent.value) {
|
||||||
|
if (props.headerMode !== 'auto-scroll') {
|
||||||
|
headerIsHidden.value = false;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
headerIsHidden.value = true;
|
headerIsHidden.value = true;
|
||||||
|
@ -439,7 +402,7 @@ watch(
|
||||||
if (
|
if (
|
||||||
props.headerMode !== 'auto-scroll' ||
|
props.headerMode !== 'auto-scroll' ||
|
||||||
isMixedNav.value ||
|
isMixedNav.value ||
|
||||||
fullContent.value
|
isFullContent.value
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -465,8 +428,6 @@ function handleOpenMenu() {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="relative flex min-h-full w-full">
|
<div class="relative flex min-h-full w-full">
|
||||||
<slot name="preferences"></slot>
|
|
||||||
<slot name="floating-groups"></slot>
|
|
||||||
<LayoutSidebar
|
<LayoutSidebar
|
||||||
v-if="sidebarEnableState"
|
v-if="sidebarEnableState"
|
||||||
v-model:collapse="sidebarCollapse"
|
v-model:collapse="sidebarCollapse"
|
||||||
|
@ -478,12 +439,12 @@ function handleOpenMenu() {
|
||||||
:dom-visible="!isMobile"
|
:dom-visible="!isMobile"
|
||||||
:extra-width="sidebarExtraWidth"
|
:extra-width="sidebarExtraWidth"
|
||||||
:fixed-extra="sidebarExpandOnHover"
|
:fixed-extra="sidebarExpandOnHover"
|
||||||
:header-height="isMixedNav ? 0 : getHeaderHeight"
|
:header-height="isMixedNav ? 0 : headerHeight"
|
||||||
:is-sidebar-mixed="isSidebarMixedNav"
|
:is-sidebar-mixed="isSidebarMixedNav"
|
||||||
:margin-top="sidebarMarginTop"
|
:margin-top="sidebarMarginTop"
|
||||||
:mixed-width="sidebarMixedWidth"
|
:mixed-width="sidebarMixedWidth"
|
||||||
:show="showSidebar"
|
:show="showSidebar"
|
||||||
:theme="sidebarFace.theme"
|
:theme="sidebarTheme"
|
||||||
:width="getSidebarWidth"
|
:width="getSidebarWidth"
|
||||||
:z-index="sidebarZIndex"
|
:z-index="sidebarZIndex"
|
||||||
@leave="() => emit('sideMouseLeave')"
|
@leave="() => emit('sideMouseLeave')"
|
||||||
|
@ -518,10 +479,10 @@ function handleOpenMenu() {
|
||||||
<LayoutHeader
|
<LayoutHeader
|
||||||
v-if="headerVisible"
|
v-if="headerVisible"
|
||||||
:full-width="!isSideMode"
|
:full-width="!isSideMode"
|
||||||
:height="getHeaderHeight"
|
:height="headerHeight"
|
||||||
:is-mixed-nav="isMixedNav"
|
:is-mixed-nav="isMixedNav"
|
||||||
:is-mobile="isMobile"
|
:is-mobile="isMobile"
|
||||||
:show="!fullContent && !headerHidden"
|
:show="!isFullContent && !headerHidden"
|
||||||
:show-toggle-btn="showHeaderToggleButton"
|
:show-toggle-btn="showHeaderToggleButton"
|
||||||
:sidebar-width="sidebarWidth"
|
:sidebar-width="sidebarWidth"
|
||||||
:width="mainStyle.width"
|
:width="mainStyle.width"
|
||||||
|
@ -563,7 +524,7 @@ function handleOpenMenu() {
|
||||||
v-if="footerEnable"
|
v-if="footerEnable"
|
||||||
:fixed="footerFixed"
|
:fixed="footerFixed"
|
||||||
:height="footerHeight"
|
:height="footerHeight"
|
||||||
:show="!fullContent"
|
:show="!isFullContent"
|
||||||
:width="footerWidth"
|
:width="footerWidth"
|
||||||
:z-index="zIndex"
|
:z-index="zIndex"
|
||||||
>
|
>
|
||||||
|
|
|
@ -479,8 +479,8 @@ $namespace: vben;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-horizontal:not(.is-rounded) {
|
&.is-horizontal:not(.is-rounded) {
|
||||||
--menu-item-height: 60px;
|
--menu-item-height: 40px;
|
||||||
--menu-item-radius: 0px;
|
--menu-item-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-horizontal.is-rounded {
|
&.is-horizontal.is-rounded {
|
||||||
|
@ -514,7 +514,7 @@ $namespace: vben;
|
||||||
--menu-item-hover-background-color: hsl(var(--accent));
|
--menu-item-hover-background-color: hsl(var(--accent));
|
||||||
--menu-item-hover-color: hsl(var(--primary));
|
--menu-item-hover-color: hsl(var(--primary));
|
||||||
--menu-submenu-active-color: hsl(var(--primary));
|
--menu-submenu-active-color: hsl(var(--primary));
|
||||||
--menu-submenu-active-background-color: hsl(var(--primary) / 30%);
|
--menu-submenu-active-background-color: hsl(var(--primary) / 15%);
|
||||||
--menu-submenu-hover-color: hsl(var(--primary));
|
--menu-submenu-hover-color: hsl(var(--primary));
|
||||||
--menu-submenu-hover-background-color: hsl(var(--accent));
|
--menu-submenu-hover-background-color: hsl(var(--accent));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ export * from './scrollbar';
|
||||||
export * from './segmented';
|
export * from './segmented';
|
||||||
export * from './sheet';
|
export * from './sheet';
|
||||||
export * from './spinner';
|
export * from './spinner';
|
||||||
|
export * from './swap';
|
||||||
export * from './tooltip';
|
export * from './tooltip';
|
||||||
export * from './ui/alert-dialog';
|
export * from './ui/alert-dialog';
|
||||||
export * from './ui/avatar';
|
export * from './ui/avatar';
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export { default as Spinner } from './spinner.vue';
|
export { default as VbenSpinner } from './spinner.vue';
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as VbenSwap } from './swap.vue';
|
|
@ -0,0 +1,126 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
interface Props {
|
||||||
|
/**
|
||||||
|
* @zh_CN 交换模式
|
||||||
|
*/
|
||||||
|
mode?: 'flip' | 'rotate';
|
||||||
|
/**
|
||||||
|
* @zh_CN 开启时的样式
|
||||||
|
*/
|
||||||
|
offClass?: string;
|
||||||
|
/**
|
||||||
|
* @zh_CN 关闭时的样式
|
||||||
|
*/
|
||||||
|
onClass?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'Swap',
|
||||||
|
});
|
||||||
|
|
||||||
|
withDefaults(defineProps<Props>(), {
|
||||||
|
mode: 'rotate',
|
||||||
|
onClass: '',
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<label
|
||||||
|
:class="{
|
||||||
|
'swap-flip': mode === 'flip',
|
||||||
|
'swap-rotate': mode === 'rotate',
|
||||||
|
}"
|
||||||
|
class="swap"
|
||||||
|
>
|
||||||
|
<input class="hidden" type="checkbox" />
|
||||||
|
|
||||||
|
<div :class="onClass" class="swap-on">
|
||||||
|
<slot name="swap-on"></slot>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div :class="offClass" class="swap-off">
|
||||||
|
<slot name="swap-off"></slot>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.swap {
|
||||||
|
@apply relative inline-grid cursor-pointer select-none place-content-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap > * {
|
||||||
|
@apply col-start-1 row-start-1 duration-300 ease-out;
|
||||||
|
|
||||||
|
transition-property: transform, opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap-rotate .swap-on,
|
||||||
|
.swap-rotate .swap-indeterminate,
|
||||||
|
.swap-rotate input:indeterminate ~ .swap-on {
|
||||||
|
@apply rotate-45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap-rotate input:checked ~ .swap-off,
|
||||||
|
.swap-active:where(.swap-rotate) .swap-off,
|
||||||
|
.swap-rotate input:indeterminate ~ .swap-off {
|
||||||
|
@apply -rotate-45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap-rotate input:checked ~ .swap-on,
|
||||||
|
.swap-active:where(.swap-rotate) .swap-on,
|
||||||
|
.swap-rotate input:indeterminate ~ .swap-indeterminate {
|
||||||
|
@apply rotate-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap-flip {
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
perspective: 16em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap-flip .swap-on,
|
||||||
|
.swap-flip .swap-indeterminate,
|
||||||
|
.swap-flip input:indeterminate ~ .swap-on {
|
||||||
|
@apply opacity-100;
|
||||||
|
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
backface-visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap-flip input:checked ~ .swap-off,
|
||||||
|
.swap-active:where(.swap-flip) .swap-off,
|
||||||
|
.swap-flip input:indeterminate ~ .swap-off {
|
||||||
|
@apply opacity-100;
|
||||||
|
|
||||||
|
transform: rotateY(-180deg);
|
||||||
|
backface-visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap-flip input:checked ~ .swap-on,
|
||||||
|
.swap-active:where(.swap-flip) .swap-on,
|
||||||
|
.swap-flip input:indeterminate ~ .swap-indeterminate {
|
||||||
|
transform: rotateY(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap input {
|
||||||
|
@apply appearance-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap .swap-on,
|
||||||
|
.swap .swap-indeterminate,
|
||||||
|
.swap input:indeterminate ~ .swap-on {
|
||||||
|
@apply opacity-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap input:checked ~ .swap-off,
|
||||||
|
.swap-active .swap-off,
|
||||||
|
.swap input:indeterminate ~ .swap-off {
|
||||||
|
@apply opacity-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swap input:checked ~ .swap-on,
|
||||||
|
.swap-active .swap-on,
|
||||||
|
.swap input:indeterminate ~ .swap-indeterminate {
|
||||||
|
@apply opacity-100;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -30,7 +30,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
<template>
|
<template>
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay
|
<DialogOverlay
|
||||||
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 border-border fixed inset-0 z-[1000] grid place-items-center overflow-y-auto bg-black/80"
|
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 border-border fixed inset-0 z-[1000] grid place-items-center overflow-y-auto border bg-black/80"
|
||||||
>
|
>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
:class="
|
:class="
|
||||||
|
|
|
@ -9,10 +9,10 @@ export const sheetVariants = cva(
|
||||||
variants: {
|
variants: {
|
||||||
side: {
|
side: {
|
||||||
bottom:
|
bottom:
|
||||||
'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
|
'inset-x-0 bottom-0 border-t border-border data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
|
||||||
left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',
|
left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',
|
||||||
right:
|
right:
|
||||||
'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
|
'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
|
||||||
top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
|
top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,7 @@ import type { HTMLAttributes } from 'vue';
|
||||||
import { cva, type VariantProps } from 'class-variance-authority';
|
import { cva, type VariantProps } from 'class-variance-authority';
|
||||||
|
|
||||||
export const toastVariants = cva(
|
export const toastVariants = cva(
|
||||||
'group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full',
|
'group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border border-border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full',
|
||||||
{
|
{
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: 'default',
|
variant: 'default',
|
||||||
|
|
|
@ -41,7 +41,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
v-bind="{ ...forwarded, ...$attrs }"
|
v-bind="{ ...forwarded, ...$attrs }"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'bg-accent text-accent-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border z-[1000] overflow-hidden rounded-sm px-4 py-2 text-xs shadow-md',
|
'bg-accent text-accent-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border shadow-float z-[1000] overflow-hidden rounded-sm border px-4 py-2 text-xs',
|
||||||
props.class,
|
props.class,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
```bash
|
```bash
|
||||||
# 进入目标应用目录,例如 apps/xxxx-app
|
# 进入目标应用目录,例如 apps/xxxx-app
|
||||||
# cd apps/xxxx-app
|
# cd apps/xxxx-app
|
||||||
pnpm add @vben/constants --workspace
|
pnpm add @vben/constants
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用
|
### 使用
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
```bash
|
```bash
|
||||||
# 进入目标应用目录,例如 apps/xxxx-app
|
# 进入目标应用目录,例如 apps/xxxx-app
|
||||||
# cd apps/xxxx-app
|
# cd apps/xxxx-app
|
||||||
pnpm add @vben/hooks --workspace
|
pnpm add @vben/hooks
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用
|
### 使用
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { RouterView } from 'vue-router';
|
||||||
import { useContentHeight } from '@vben/hooks';
|
import { useContentHeight } from '@vben/hooks';
|
||||||
import { preferences, usePreferences } from '@vben/preferences';
|
import { preferences, usePreferences } from '@vben/preferences';
|
||||||
import { storeToRefs, useTabbarStore } from '@vben/stores';
|
import { storeToRefs, useTabbarStore } from '@vben/stores';
|
||||||
import { Spinner } from '@vben-core/shadcn-ui';
|
import { VbenSpinner } from '@vben-core/shadcn-ui';
|
||||||
|
|
||||||
import { IFrameRouterView } from '../../iframe';
|
import { IFrameRouterView } from '../../iframe';
|
||||||
import { useContentSpinner } from './use-content-spinner';
|
import { useContentSpinner } from './use-content-spinner';
|
||||||
|
@ -86,7 +86,7 @@ function transformComponent(
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="relative h-full">
|
<div class="relative h-full">
|
||||||
<Spinner
|
<VbenSpinner
|
||||||
v-if="preferences.transition.loading"
|
v-if="preferences.transition.loading"
|
||||||
:spinning="spinning"
|
:spinning="spinning"
|
||||||
:style="contentStyles"
|
:style="contentStyles"
|
||||||
|
|
|
@ -41,6 +41,7 @@ const {
|
||||||
isSideMixedNav,
|
isSideMixedNav,
|
||||||
layout,
|
layout,
|
||||||
sidebarCollapsed,
|
sidebarCollapsed,
|
||||||
|
theme,
|
||||||
} = usePreferences();
|
} = usePreferences();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const { updateWatermark } = useWatermark();
|
const { updateWatermark } = useWatermark();
|
||||||
|
@ -50,7 +51,7 @@ const headerMenuTheme = computed(() => {
|
||||||
return isDark.value ? 'dark' : 'light';
|
return isDark.value ? 'dark' : 'light';
|
||||||
});
|
});
|
||||||
|
|
||||||
const theme = computed(() => {
|
const sidebarTheme = computed(() => {
|
||||||
const dark = isDark.value || preferences.theme.semiDarkMenu;
|
const dark = isDark.value || preferences.theme.semiDarkMenu;
|
||||||
return dark ? 'dark' : 'light';
|
return dark ? 'dark' : 'light';
|
||||||
});
|
});
|
||||||
|
@ -170,8 +171,7 @@ const headerSlots = computed(() => {
|
||||||
:sidebar-expand-on-hover="preferences.sidebar.expandOnHover"
|
:sidebar-expand-on-hover="preferences.sidebar.expandOnHover"
|
||||||
:sidebar-extra-collapse="preferences.sidebar.extraCollapse"
|
:sidebar-extra-collapse="preferences.sidebar.extraCollapse"
|
||||||
:sidebar-hidden="preferences.sidebar.hidden"
|
:sidebar-hidden="preferences.sidebar.hidden"
|
||||||
:sidebar-semi-dark="preferences.theme.semiDarkMenu"
|
:sidebar-theme="sidebarTheme"
|
||||||
:sidebar-theme="theme"
|
|
||||||
:sidebar-width="preferences.sidebar.width"
|
:sidebar-width="preferences.sidebar.width"
|
||||||
:tabbar-enable="preferences.tabbar.enable"
|
:tabbar-enable="preferences.tabbar.enable"
|
||||||
:tabbar-height="preferences.tabbar.height"
|
:tabbar-height="preferences.tabbar.height"
|
||||||
|
@ -192,14 +192,6 @@ const headerSlots = computed(() => {
|
||||||
updatePreferences({ sidebar: { extraCollapse: value } })
|
updatePreferences({ sidebar: { extraCollapse: value } })
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<template v-if="preferences.app.enablePreferences" #preferences>
|
|
||||||
<Preferences @clear-preferences-and-logout="clearPreferencesAndLogout" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #floating-groups>
|
|
||||||
<VbenBackTop />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- logo -->
|
<!-- logo -->
|
||||||
<template #logo>
|
<template #logo>
|
||||||
<VbenLogo
|
<VbenLogo
|
||||||
|
@ -256,7 +248,7 @@ const headerSlots = computed(() => {
|
||||||
:default-active="sidebarActive"
|
:default-active="sidebarActive"
|
||||||
:menus="wrapperMenus(sidebarMenus)"
|
:menus="wrapperMenus(sidebarMenus)"
|
||||||
:rounded="isMenuRounded"
|
:rounded="isMenuRounded"
|
||||||
:theme="theme"
|
:theme="sidebarTheme"
|
||||||
mode="vertical"
|
mode="vertical"
|
||||||
@select="handleMenuSelect"
|
@select="handleMenuSelect"
|
||||||
/>
|
/>
|
||||||
|
@ -267,7 +259,7 @@ const headerSlots = computed(() => {
|
||||||
:active-path="extraActiveMenu"
|
:active-path="extraActiveMenu"
|
||||||
:menus="wrapperMenus(headerMenus)"
|
:menus="wrapperMenus(headerMenus)"
|
||||||
:rounded="isMenuRounded"
|
:rounded="isMenuRounded"
|
||||||
:theme="theme"
|
:theme="sidebarTheme"
|
||||||
@default-select="handleDefaultSelect"
|
@default-select="handleDefaultSelect"
|
||||||
@enter="handleMenuMouseEnter"
|
@enter="handleMenuMouseEnter"
|
||||||
@select="handleMixedMenuSelect"
|
@select="handleMixedMenuSelect"
|
||||||
|
@ -280,7 +272,7 @@ const headerSlots = computed(() => {
|
||||||
:collapse="preferences.sidebar.extraCollapse"
|
:collapse="preferences.sidebar.extraCollapse"
|
||||||
:menus="wrapperMenus(extraMenus)"
|
:menus="wrapperMenus(extraMenus)"
|
||||||
:rounded="isMenuRounded"
|
:rounded="isMenuRounded"
|
||||||
:theme="theme"
|
:theme="sidebarTheme"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #side-extra-title>
|
<template #side-extra-title>
|
||||||
|
@ -325,6 +317,13 @@ const headerSlots = computed(() => {
|
||||||
<Transition v-if="preferences.widget.lockScreen" name="slide-up">
|
<Transition v-if="preferences.widget.lockScreen" name="slide-up">
|
||||||
<slot v-if="lockStore.isLockScreen" name="lock-screen"></slot>
|
<slot v-if="lockStore.isLockScreen" name="lock-screen"></slot>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
|
<template v-if="preferences.app.enablePreferences">
|
||||||
|
<Preferences
|
||||||
|
@clear-preferences-and-logout="clearPreferencesAndLogout"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<VbenBackTop />
|
||||||
</template>
|
</template>
|
||||||
</VbenAdminLayout>
|
</VbenAdminLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import { preferences } from '@vben/preferences';
|
import { preferences } from '@vben/preferences';
|
||||||
import { useTabbarStore } from '@vben/stores';
|
import { useTabbarStore } from '@vben/stores';
|
||||||
import { Spinner } from '@vben-core/shadcn-ui';
|
import { VbenSpinner } from '@vben-core/shadcn-ui';
|
||||||
|
|
||||||
defineOptions({ name: 'IFrameRouterView' });
|
defineOptions({ name: 'IFrameRouterView' });
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ function showSpinning(index: number) {
|
||||||
v-show="routeShow(item)"
|
v-show="routeShow(item)"
|
||||||
class="relative size-full"
|
class="relative size-full"
|
||||||
>
|
>
|
||||||
<Spinner :spinning="showSpinning(index)" />
|
<VbenSpinner :spinning="showSpinning(index)" />
|
||||||
<iframe
|
<iframe
|
||||||
:src="item.meta.iframeSrc as string"
|
:src="item.meta.iframeSrc as string"
|
||||||
class="size-full"
|
class="size-full"
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
```bash
|
```bash
|
||||||
# 进入目标应用目录,例如 apps/xxxx-app
|
# 进入目标应用目录,例如 apps/xxxx-app
|
||||||
# cd apps/xxxx-app
|
# cd apps/xxxx-app
|
||||||
pnpm add @vben/icons --workspace
|
pnpm add @vben/icons
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用
|
### 使用
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
```bash
|
```bash
|
||||||
# 进入目标应用目录,例如 apps/xxxx-app
|
# 进入目标应用目录,例如 apps/xxxx-app
|
||||||
# cd apps/xxxx-app
|
# cd apps/xxxx-app
|
||||||
pnpm add @vben/styles --workspace
|
pnpm add @vben/styles
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用
|
### 使用
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
```bash
|
```bash
|
||||||
# 进入目标应用目录,例如 apps/xxxx-app
|
# 进入目标应用目录,例如 apps/xxxx-app
|
||||||
# cd apps/xxxx-app
|
# cd apps/xxxx-app
|
||||||
pnpm add @vben/types --workspace
|
pnpm add @vben/types
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用
|
### 使用
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
```bash
|
```bash
|
||||||
# 进入目标应用目录,例如 apps/xxxx-app
|
# 进入目标应用目录,例如 apps/xxxx-app
|
||||||
# cd apps/xxxx-app
|
# cd apps/xxxx-app
|
||||||
pnpm add @vben/utils --workspace
|
pnpm add @vben/utils
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用
|
### 使用
|
||||||
|
|
Loading…
Reference in New Issue