feat: add swap component (#4149)

pull/48/MERGE
Vben 2024-08-14 20:37:21 +08:00 committed by GitHub
parent b28740042b
commit 83fcdec37c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 260 additions and 146 deletions

View File

@ -239,9 +239,11 @@ css 变量内的颜色,必须使用 `hsl` 格式,如 `0 0% 100%`,不需要
```css
/* */
:root {
.dark,
.dark[data-theme='custom'],
.dark[data-theme='default'] {
/* Background color for <Card /> */
--card: 0 0% 30%;
--card: 222.34deg 10.43% 12.27%;
}
```

View File

@ -1,4 +1,4 @@
import ora, { Ora } from 'ora';
import ora, { type Ora } from 'ora';
interface SpinnerOptions {
failedText?: string;

View File

@ -52,12 +52,12 @@
--secondary-foreground: 0 0% 98%;
/* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
--accent: 240 3.7% 15.9%;
--accent-hover: 240 3.7% 20.9%;
--accent: 216 5% 19%;
--accent-hover: 216 5% 24%;
--accent-foreground: 0 0% 98%;
/* Darker color */
--heavy: 240 3.7% 20.9%;
--heavy: 216 5% 24%;
--heavy-foreground: var(--accent-foreground);
/* Default border color */

View File

@ -89,7 +89,7 @@
/* menu */
--sidebar: 0 0% 100%;
--sidebar-deep: 210 11.11% 96.47%;
--sidebar-deep: 0 0% 100%;
--menu: var(--sidebar);
accent-color: var(--primary);

View File

@ -84,7 +84,7 @@ function handleToggleMenu() {
</div>
<VbenIconButton
v-if="showToggleBtn || isMobile"
class="my-0 ml-2 mr-1 rounded"
class="my-0 ml-2 mr-1 rounded-md"
@click="handleToggleMenu"
>
<Menu class="size-4" />

View File

@ -24,9 +24,8 @@ interface Props {
domVisible?: boolean;
/**
* 扩展区域宽度
* @default 180
*/
extraWidth?: number;
extraWidth: number;
/**
* 固定扩展区域
* @default false
@ -69,13 +68,12 @@ interface Props {
/**
* 主题
*/
theme?: string;
theme: string;
/**
* 宽度
* @default 180
*/
width?: number;
width: number;
/**
* zIndex
* @default 0
@ -87,7 +85,6 @@ const props = withDefaults(defineProps<Props>(), {
collapseHeight: 42,
collapseWidth: 48,
domVisible: true,
extraWidth: 180,
fixedExtra: false,
isSidebarMixed: false,
marginTop: 0,
@ -95,8 +92,6 @@ const props = withDefaults(defineProps<Props>(), {
paddingTop: 0,
show: true,
showCollapseButton: true,
theme: 'dark',
width: 180,
zIndex: 0,
});
@ -181,10 +176,8 @@ const extraContentStyle = computed((): CSSProperties => {
});
const collapseStyle = computed((): CSSProperties => {
const { collapseHeight } = props;
return {
height: `${collapseHeight}px`,
height: `${props.collapseHeight}px`,
};
});

View File

@ -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),
);
/**
* contenttab
*/
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,
};
}

View File

@ -62,12 +62,6 @@ interface VbenLayoutProps {
* @default 48
*/
headerHeight?: number;
/**
* header
* header
* @default 10
*/
headerHeightOffset?: number;
/**
*
* @default false
@ -133,11 +127,7 @@ interface VbenLayoutProps {
* @default 80
*/
sidebarMixedWidth?: number;
/**
*
* @default false
*/
sidebarSemiDark?: boolean;
/**
*
* @default dark

View File

@ -13,6 +13,7 @@ import {
LayoutSidebar,
LayoutTabbar,
} from './components';
import { useLayout } from './hooks/use-layout';
interface Props extends VbenLayoutProps {}
@ -32,7 +33,6 @@ const props = withDefaults(defineProps<Props>(), {
footerFixed: true,
footerHeight: 32,
headerHeight: 50,
headerHeightOffset: 10,
headerHidden: false,
headerMode: 'fixed',
headerToggleSidebarButton: true,
@ -43,7 +43,6 @@ const props = withDefaults(defineProps<Props>(), {
sidebarExtraCollapsedWidth: 60,
sidebarHidden: false,
sidebarMixedWidth: 80,
sidebarSemiDark: true,
sidebarTheme: 'dark',
sidebarWidth: 180,
sideCollapseWidth: 60,
@ -73,57 +72,23 @@ const {
const { y: mouseY } = useMouse({ target: contentRef, type: 'client' });
const realLayout = computed(() =>
props.isMobile ? 'sidebar-nav' : props.layout,
);
/**
* 是否全屏显示content不需要侧边底部顶部tab区域
*/
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 {
currentLayout,
isFullContent,
isHeaderNav,
isMixedNav,
isSidebarMixedNav,
} = useLayout(props);
/**
* 顶栏是否自动隐藏
*/
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(() => {
let height = 0;
if (props.headerVisible && !props.headerHidden) {
height += getHeaderHeight.value;
height += props.headerHeight;
}
if (props.tabbarEnable) {
height += props.tabbarHeight;
@ -151,8 +116,8 @@ const sidebarEnableState = computed(() => {
* 侧边区域离顶部高度
*/
const sidebarMarginTop = computed(() => {
const { isMobile } = props;
return isMixedNav.value && !isMobile ? getHeaderHeight.value : 0;
const { headerHeight, isMobile } = props;
return isMixedNav.value && !isMobile ? headerHeight : 0;
});
/**
@ -195,30 +160,13 @@ const sidebarExtraWidth = computed(() => {
/**
* 是否侧边栏模式包含混合侧边
*/
const isSideMode = computed(() =>
['mixed-nav', 'sidebar-mixed-nav', 'sidebar-nav'].includes(realLayout.value),
const isSideMode = computed(
() =>
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值
*/
@ -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(() => {
let width = '100%';
let sidebarAndExtraWidth = 'unset';
if (
headerFixed.value &&
realLayout.value !== 'header-nav' &&
realLayout.value !== 'mixed-nav' &&
currentLayout.value !== 'header-nav' &&
currentLayout.value !== 'mixed-nav' &&
showSidebar.value &&
!props.isMobile
) {
@ -253,7 +213,7 @@ const mainStyle = computed(() => {
? getSideCollapseWidth.value
: props.sidebarMixedWidth;
const sideWidth = sidebarExtraCollapse.value
? getSideCollapseWidth.value
? props.sidebarExtraCollapsedWidth
: props.sidebarWidth;
// 100% - -
@ -312,7 +272,7 @@ const contentStyle = computed((): CSSProperties => {
return {
marginTop:
fixed &&
!fullContent.value &&
!isFullContent.value &&
!headerIsHidden.value &&
(!isHeaderAutoMode.value || scrollY.value < headerWrapperHeight.value)
? `${headerWrapperHeight.value}px`
@ -330,11 +290,11 @@ const headerZIndex = computed(() => {
const headerWrapperStyle = computed((): CSSProperties => {
const fixed = headerFixed.value;
return {
height: fullContent.value ? '0' : `${headerWrapperHeight.value}px`,
height: isFullContent.value ? '0' : `${headerWrapperHeight.value}px`,
left: isMixedNav.value ? 0 : mainStyle.value.sidebarAndExtraWidth,
position: fixed ? 'fixed' : 'static',
top:
headerIsHidden.value || fullContent.value
headerIsHidden.value || isFullContent.value
? `-${headerWrapperHeight.value}px`
: 0,
width: mainStyle.value.width,
@ -403,7 +363,10 @@ watch(
watch(
[() => 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;
}
headerIsHidden.value = true;
@ -439,7 +402,7 @@ watch(
if (
props.headerMode !== 'auto-scroll' ||
isMixedNav.value ||
fullContent.value
isFullContent.value
) {
return;
}
@ -465,8 +428,6 @@ function handleOpenMenu() {
<template>
<div class="relative flex min-h-full w-full">
<slot name="preferences"></slot>
<slot name="floating-groups"></slot>
<LayoutSidebar
v-if="sidebarEnableState"
v-model:collapse="sidebarCollapse"
@ -478,12 +439,12 @@ function handleOpenMenu() {
:dom-visible="!isMobile"
:extra-width="sidebarExtraWidth"
:fixed-extra="sidebarExpandOnHover"
:header-height="isMixedNav ? 0 : getHeaderHeight"
:header-height="isMixedNav ? 0 : headerHeight"
:is-sidebar-mixed="isSidebarMixedNav"
:margin-top="sidebarMarginTop"
:mixed-width="sidebarMixedWidth"
:show="showSidebar"
:theme="sidebarFace.theme"
:theme="sidebarTheme"
:width="getSidebarWidth"
:z-index="sidebarZIndex"
@leave="() => emit('sideMouseLeave')"
@ -518,10 +479,10 @@ function handleOpenMenu() {
<LayoutHeader
v-if="headerVisible"
:full-width="!isSideMode"
:height="getHeaderHeight"
:height="headerHeight"
:is-mixed-nav="isMixedNav"
:is-mobile="isMobile"
:show="!fullContent && !headerHidden"
:show="!isFullContent && !headerHidden"
:show-toggle-btn="showHeaderToggleButton"
:sidebar-width="sidebarWidth"
:width="mainStyle.width"
@ -563,7 +524,7 @@ function handleOpenMenu() {
v-if="footerEnable"
:fixed="footerFixed"
:height="footerHeight"
:show="!fullContent"
:show="!isFullContent"
:width="footerWidth"
:z-index="zIndex"
>

View File

@ -479,8 +479,8 @@ $namespace: vben;
}
&.is-horizontal:not(.is-rounded) {
--menu-item-height: 60px;
--menu-item-radius: 0px;
--menu-item-height: 40px;
--menu-item-radius: 6px;
}
&.is-horizontal.is-rounded {
@ -514,7 +514,7 @@ $namespace: vben;
--menu-item-hover-background-color: hsl(var(--accent));
--menu-item-hover-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-background-color: hsl(var(--accent));
}

View File

@ -22,6 +22,7 @@ export * from './scrollbar';
export * from './segmented';
export * from './sheet';
export * from './spinner';
export * from './swap';
export * from './tooltip';
export * from './ui/alert-dialog';
export * from './ui/avatar';

View File

@ -1 +1 @@
export { default as Spinner } from './spinner.vue';
export { default as VbenSpinner } from './spinner.vue';

View File

@ -0,0 +1 @@
export { default as VbenSwap } from './swap.vue';

View File

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

View File

@ -30,7 +30,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<template>
<DialogPortal>
<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
:class="

View File

@ -9,10 +9,10 @@ export const sheetVariants = cva(
variants: {
side: {
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',
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',
},
},

View File

@ -5,7 +5,7 @@ import type { HTMLAttributes } from 'vue';
import { cva, type VariantProps } from 'class-variance-authority';
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: {
variant: 'default',

View File

@ -41,7 +41,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
v-bind="{ ...forwarded, ...$attrs }"
:class="
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,
)
"

View File

@ -9,7 +9,7 @@
```bash
# 进入目标应用目录,例如 apps/xxxx-app
# cd apps/xxxx-app
pnpm add @vben/constants --workspace
pnpm add @vben/constants
```
### 使用

View File

@ -9,7 +9,7 @@
```bash
# 进入目标应用目录,例如 apps/xxxx-app
# cd apps/xxxx-app
pnpm add @vben/hooks --workspace
pnpm add @vben/hooks
```
### 使用

View File

@ -10,7 +10,7 @@ import { RouterView } from 'vue-router';
import { useContentHeight } from '@vben/hooks';
import { preferences, usePreferences } from '@vben/preferences';
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 { useContentSpinner } from './use-content-spinner';
@ -86,7 +86,7 @@ function transformComponent(
<template>
<div class="relative h-full">
<Spinner
<VbenSpinner
v-if="preferences.transition.loading"
:spinning="spinning"
:style="contentStyles"

View File

@ -41,6 +41,7 @@ const {
isSideMixedNav,
layout,
sidebarCollapsed,
theme,
} = usePreferences();
const userStore = useUserStore();
const { updateWatermark } = useWatermark();
@ -50,7 +51,7 @@ const headerMenuTheme = computed(() => {
return isDark.value ? 'dark' : 'light';
});
const theme = computed(() => {
const sidebarTheme = computed(() => {
const dark = isDark.value || preferences.theme.semiDarkMenu;
return dark ? 'dark' : 'light';
});
@ -170,8 +171,7 @@ const headerSlots = computed(() => {
:sidebar-expand-on-hover="preferences.sidebar.expandOnHover"
:sidebar-extra-collapse="preferences.sidebar.extraCollapse"
:sidebar-hidden="preferences.sidebar.hidden"
:sidebar-semi-dark="preferences.theme.semiDarkMenu"
:sidebar-theme="theme"
:sidebar-theme="sidebarTheme"
:sidebar-width="preferences.sidebar.width"
:tabbar-enable="preferences.tabbar.enable"
:tabbar-height="preferences.tabbar.height"
@ -192,14 +192,6 @@ const headerSlots = computed(() => {
updatePreferences({ sidebar: { extraCollapse: value } })
"
>
<template v-if="preferences.app.enablePreferences" #preferences>
<Preferences @clear-preferences-and-logout="clearPreferencesAndLogout" />
</template>
<template #floating-groups>
<VbenBackTop />
</template>
<!-- logo -->
<template #logo>
<VbenLogo
@ -256,7 +248,7 @@ const headerSlots = computed(() => {
:default-active="sidebarActive"
:menus="wrapperMenus(sidebarMenus)"
:rounded="isMenuRounded"
:theme="theme"
:theme="sidebarTheme"
mode="vertical"
@select="handleMenuSelect"
/>
@ -267,7 +259,7 @@ const headerSlots = computed(() => {
:active-path="extraActiveMenu"
:menus="wrapperMenus(headerMenus)"
:rounded="isMenuRounded"
:theme="theme"
:theme="sidebarTheme"
@default-select="handleDefaultSelect"
@enter="handleMenuMouseEnter"
@select="handleMixedMenuSelect"
@ -280,7 +272,7 @@ const headerSlots = computed(() => {
:collapse="preferences.sidebar.extraCollapse"
:menus="wrapperMenus(extraMenus)"
:rounded="isMenuRounded"
:theme="theme"
:theme="sidebarTheme"
/>
</template>
<template #side-extra-title>
@ -325,6 +317,13 @@ const headerSlots = computed(() => {
<Transition v-if="preferences.widget.lockScreen" name="slide-up">
<slot v-if="lockStore.isLockScreen" name="lock-screen"></slot>
</Transition>
<template v-if="preferences.app.enablePreferences">
<Preferences
@clear-preferences-and-logout="clearPreferencesAndLogout"
/>
</template>
<VbenBackTop />
</template>
</VbenAdminLayout>
</template>

View File

@ -6,7 +6,7 @@ import { useRoute } from 'vue-router';
import { preferences } from '@vben/preferences';
import { useTabbarStore } from '@vben/stores';
import { Spinner } from '@vben-core/shadcn-ui';
import { VbenSpinner } from '@vben-core/shadcn-ui';
defineOptions({ name: 'IFrameRouterView' });
@ -73,7 +73,7 @@ function showSpinning(index: number) {
v-show="routeShow(item)"
class="relative size-full"
>
<Spinner :spinning="showSpinning(index)" />
<VbenSpinner :spinning="showSpinning(index)" />
<iframe
:src="item.meta.iframeSrc as string"
class="size-full"

View File

@ -9,7 +9,7 @@
```bash
# 进入目标应用目录,例如 apps/xxxx-app
# cd apps/xxxx-app
pnpm add @vben/icons --workspace
pnpm add @vben/icons
```
### 使用

View File

@ -9,7 +9,7 @@
```bash
# 进入目标应用目录,例如 apps/xxxx-app
# cd apps/xxxx-app
pnpm add @vben/styles --workspace
pnpm add @vben/styles
```
### 使用

View File

@ -9,7 +9,7 @@
```bash
# 进入目标应用目录,例如 apps/xxxx-app
# cd apps/xxxx-app
pnpm add @vben/types --workspace
pnpm add @vben/types
```
### 使用

View File

@ -9,7 +9,7 @@
```bash
# 进入目标应用目录,例如 apps/xxxx-app
# cd apps/xxxx-app
pnpm add @vben/utils --workspace
pnpm add @vben/utils
```
### 使用