feat: add swap component (#4149)
parent
b28740042b
commit
83fcdec37c
|
@ -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%;
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import ora, { Ora } from 'ora';
|
||||
import ora, { type Ora } from 'ora';
|
||||
|
||||
interface SpinnerOptions {
|
||||
failedText?: string;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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`,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
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
|
||||
|
|
|
@ -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"
|
||||
>
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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>
|
||||
<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="
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
```bash
|
||||
# 进入目标应用目录,例如 apps/xxxx-app
|
||||
# cd apps/xxxx-app
|
||||
pnpm add @vben/constants --workspace
|
||||
pnpm add @vben/constants
|
||||
```
|
||||
|
||||
### 使用
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
```bash
|
||||
# 进入目标应用目录,例如 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 { 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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
```bash
|
||||
# 进入目标应用目录,例如 apps/xxxx-app
|
||||
# cd apps/xxxx-app
|
||||
pnpm add @vben/icons --workspace
|
||||
pnpm add @vben/icons
|
||||
```
|
||||
|
||||
### 使用
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
```bash
|
||||
# 进入目标应用目录,例如 apps/xxxx-app
|
||||
# cd apps/xxxx-app
|
||||
pnpm add @vben/styles --workspace
|
||||
pnpm add @vben/styles
|
||||
```
|
||||
|
||||
### 使用
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
```bash
|
||||
# 进入目标应用目录,例如 apps/xxxx-app
|
||||
# cd apps/xxxx-app
|
||||
pnpm add @vben/types --workspace
|
||||
pnpm add @vben/types
|
||||
```
|
||||
|
||||
### 使用
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
```bash
|
||||
# 进入目标应用目录,例如 apps/xxxx-app
|
||||
# cd apps/xxxx-app
|
||||
pnpm add @vben/utils --workspace
|
||||
pnpm add @vben/utils
|
||||
```
|
||||
|
||||
### 使用
|
||||
|
|
Loading…
Reference in New Issue