refactor: refacotr preference
This commit is contained in:
22
packages/business/common-ui/src/preferences/blocks/block.vue
Normal file
22
packages/business/common-ui/src/preferences/blocks/block.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceBlock',
|
||||
});
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
title: '',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col py-4">
|
||||
<h3 class="mb-3 font-semibold leading-none tracking-tight">
|
||||
{{ title }}
|
||||
</h3>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
@@ -0,0 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceAnimation',
|
||||
});
|
||||
const pageProgress = defineModel<boolean>('pageProgress', {
|
||||
// 默认值
|
||||
default: false,
|
||||
});
|
||||
|
||||
const pageTransition = defineModel<string>('pageTransition');
|
||||
const pageTransitionEnable = defineModel<boolean>('pageTransitionEnable');
|
||||
|
||||
const transitionPreset = ['fade', 'fade-slide', 'fade-up', 'fade-down'];
|
||||
|
||||
function handleClick(value: string) {
|
||||
pageTransition.value = value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SwitchItem v-model="pageProgress">
|
||||
{{ $t('preference.page-progress') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="pageTransitionEnable">
|
||||
{{ $t('preference.page-transition') }}
|
||||
</SwitchItem>
|
||||
<div
|
||||
v-if="pageTransitionEnable"
|
||||
class="mb-2 mt-3 flex justify-between gap-3 px-2"
|
||||
>
|
||||
<div
|
||||
v-for="item in transitionPreset"
|
||||
:key="item"
|
||||
class="outline-box p-2"
|
||||
:class="{
|
||||
'outline-box-active': pageTransition === item,
|
||||
}"
|
||||
@click="handleClick(item)"
|
||||
>
|
||||
<div class="bg-accent h-10 w-12 rounded-md" :class="`${item}-slow`"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@@ -0,0 +1,35 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectListItem } from '@vben/types';
|
||||
|
||||
import { SUPPORT_LANGUAGES } from '@vben-core/preferences';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import SelectItem from '../select-item.vue';
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceGeneralConfig',
|
||||
});
|
||||
|
||||
const locale = defineModel<string>('locale');
|
||||
const dynamicTitle = defineModel<boolean>('dynamicTitle');
|
||||
const shortcutKeys = defineModel<boolean>('shortcutKeys');
|
||||
|
||||
const localeItems: SelectListItem[] = SUPPORT_LANGUAGES.map((item) => ({
|
||||
label: item.text,
|
||||
value: item.key,
|
||||
}));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectItem v-model="locale" :items="localeItems">
|
||||
{{ $t('preference.language') }}
|
||||
</SelectItem>
|
||||
<SwitchItem v-model="dynamicTitle">
|
||||
{{ $t('preference.dynamic-title') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="shortcutKeys">
|
||||
{{ $t('preference.shortcut-key') }}
|
||||
</SwitchItem>
|
||||
</template>
|
15
packages/business/common-ui/src/preferences/blocks/index.ts
Normal file
15
packages/business/common-ui/src/preferences/blocks/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export { default as Block } from './block.vue';
|
||||
export { default as Animation } from './general/animation.vue';
|
||||
export { default as General } from './general/general.vue';
|
||||
export { default as Breadcrumb } from './layout/breadcrumb.vue';
|
||||
export { default as Content } from './layout/content.vue';
|
||||
export { default as Footer } from './layout/footer.vue';
|
||||
export { default as Header } from './layout/header.vue';
|
||||
export { default as Layout } from './layout/layout.vue';
|
||||
export { default as Navigation } from './layout/navigation.vue';
|
||||
export { default as Sidebar } from './layout/sidebar.vue';
|
||||
export { default as Tabs } from './layout/tabs.vue';
|
||||
export { default as SwitchItem } from './switch-item.vue';
|
||||
export { default as ThemeColor } from './theme/color.vue';
|
||||
export { default as ColorMode } from './theme/color-mode.vue';
|
||||
export { default as Theme } from './theme/theme.vue';
|
@@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectListItem } from '@vben/types';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
import ToggleItem from '../toggle-item.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceBreadcrumbConfig',
|
||||
});
|
||||
|
||||
defineProps<{ disabled: boolean }>();
|
||||
|
||||
const breadcrumbVisible = defineModel<boolean>('breadcrumbVisible');
|
||||
const breadcrumbIcon = defineModel<boolean>('breadcrumbIcon');
|
||||
const breadcrumbStyle = defineModel<string>('breadcrumbStyle');
|
||||
const breadcrumbHome = defineModel<boolean>('breadcrumbHome');
|
||||
const breadcrumbHideOnlyOne = defineModel<boolean>('breadcrumbHideOnlyOne');
|
||||
|
||||
const typeItems: SelectListItem[] = [
|
||||
{ label: $t('preference.normal'), value: 'normal' },
|
||||
{ label: $t('preference.breadcrumb-background'), value: 'background' },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SwitchItem v-model="breadcrumbVisible" :disabled="disabled">
|
||||
{{ $t('preference.breadcrumb-enable') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem
|
||||
v-model="breadcrumbHideOnlyOne"
|
||||
:disabled="!breadcrumbVisible || disabled"
|
||||
>
|
||||
{{ $t('preference.breadcrumb-hide-only-one') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem
|
||||
v-model="breadcrumbHome"
|
||||
:disabled="!breadcrumbVisible || disabled"
|
||||
>
|
||||
{{ $t('preference.breadcrumb-home') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem
|
||||
v-model="breadcrumbIcon"
|
||||
:disabled="!breadcrumbVisible || disabled"
|
||||
>
|
||||
{{ $t('preference.breadcrumb-icon') }}
|
||||
</SwitchItem>
|
||||
<ToggleItem
|
||||
v-model="breadcrumbStyle"
|
||||
:items="typeItems"
|
||||
:disabled="!breadcrumbVisible || disabled"
|
||||
>
|
||||
{{ $t('preference.breadcrumb-style') }}
|
||||
</ToggleItem>
|
||||
</template>
|
@@ -0,0 +1,50 @@
|
||||
<script setup lang="ts">
|
||||
import { $t } from '@vben/locales';
|
||||
import { type Component, computed } from 'vue';
|
||||
|
||||
import { ContentCompact, ContentWide } from '../../icons';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceLayoutContent',
|
||||
});
|
||||
|
||||
const modelValue = defineModel<string>({ default: 'wide' });
|
||||
|
||||
const components: Record<string, Component> = {
|
||||
compact: ContentCompact,
|
||||
wide: ContentWide,
|
||||
};
|
||||
|
||||
const PRESET = computed(() => [
|
||||
{
|
||||
name: $t('preference.wide'),
|
||||
type: 'wide',
|
||||
},
|
||||
{
|
||||
name: '定宽',
|
||||
type: 'compact',
|
||||
},
|
||||
]);
|
||||
|
||||
function activeClass(theme: string): string[] {
|
||||
return theme === modelValue.value ? ['outline-box-active'] : [];
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex w-full gap-5">
|
||||
<template v-for="theme in PRESET" :key="theme.name">
|
||||
<div
|
||||
class="flex w-[100px] cursor-pointer flex-col"
|
||||
@click="modelValue = theme.type"
|
||||
>
|
||||
<div :class="activeClass(theme.type)" class="outline-box flex-center">
|
||||
<component :is="components[theme.type]" />
|
||||
</div>
|
||||
<div class="text-muted-foreground mt-2 text-center text-xs">
|
||||
{{ theme.name }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceBreadcrumbConfig',
|
||||
});
|
||||
|
||||
const footerVisible = defineModel<boolean>('footerVisible');
|
||||
const footerFixed = defineModel<boolean>('footerFixed');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SwitchItem v-model="footerVisible">
|
||||
{{ $t('preference.footer-visible') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="footerFixed" :disabled="!footerVisible">
|
||||
{{ $t('preference.footer-fixed') }}
|
||||
</SwitchItem>
|
||||
</template>
|
@@ -0,0 +1,49 @@
|
||||
<script setup lang="ts">
|
||||
import type { LayoutHeaderModeType, SelectListItem } from '@vben/types';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import SelectItem from '../select-item.vue';
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceBreadcrumbConfig',
|
||||
});
|
||||
|
||||
defineProps<{ disabled: boolean }>();
|
||||
|
||||
const headerVisible = defineModel<boolean>('headerVisible');
|
||||
const headerMode = defineModel<LayoutHeaderModeType>('headerMode');
|
||||
|
||||
const localeItems: SelectListItem[] = [
|
||||
{
|
||||
label: $t('preference.header-mode-static'),
|
||||
value: 'static',
|
||||
},
|
||||
{
|
||||
label: $t('preference.header-mode-fixed'),
|
||||
value: 'fixed',
|
||||
},
|
||||
{
|
||||
label: $t('preference.header-mode-auto'),
|
||||
value: 'auto',
|
||||
},
|
||||
{
|
||||
label: $t('preference.header-mode-auto-scroll'),
|
||||
value: 'auto-scroll',
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SwitchItem v-model="headerVisible" :disabled="disabled">
|
||||
{{ $t('preference.header-visible') }}
|
||||
</SwitchItem>
|
||||
<SelectItem
|
||||
v-model="headerMode"
|
||||
:items="localeItems"
|
||||
:disabled="!headerVisible"
|
||||
>
|
||||
{{ $t('preference.mode') }}
|
||||
</SelectItem>
|
||||
</template>
|
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceInterfaceControl',
|
||||
});
|
||||
|
||||
const tabsVisible = defineModel<boolean>('tabsVisible');
|
||||
const logoVisible = defineModel<boolean>('logoVisible');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SwitchItem v-model="tabsVisible">
|
||||
{{ $t('preference.tabs-visible') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="logoVisible">
|
||||
{{ $t('preference.logo-visible') }}
|
||||
</SwitchItem>
|
||||
</template>
|
@@ -0,0 +1,95 @@
|
||||
<script setup lang="ts">
|
||||
import type { LayoutType } from '@vben/types';
|
||||
|
||||
import { MdiQuestionMarkCircleOutline } from '@vben-core/iconify';
|
||||
import { VbenTooltip } from '@vben-core/shadcn-ui';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
import { type Component, computed } from 'vue';
|
||||
|
||||
import {
|
||||
FullContent,
|
||||
HeaderNav,
|
||||
MixedNav,
|
||||
SideMixedNav,
|
||||
SideNav,
|
||||
} from '../../icons';
|
||||
|
||||
interface PresetItem {
|
||||
name: string;
|
||||
tip: string;
|
||||
type: LayoutType;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceLayout',
|
||||
});
|
||||
|
||||
const modelValue = defineModel<LayoutType>({ default: 'side-nav' });
|
||||
|
||||
const components: Record<LayoutType, Component> = {
|
||||
'full-content': FullContent,
|
||||
'header-nav': HeaderNav,
|
||||
'mixed-nav': MixedNav,
|
||||
'side-mixed-nav': SideMixedNav,
|
||||
'side-nav': SideNav,
|
||||
};
|
||||
|
||||
const PRESET = computed((): PresetItem[] => [
|
||||
{
|
||||
name: $t('preference.vertical'),
|
||||
tip: $t('preference.vertical-tip'),
|
||||
type: 'side-nav',
|
||||
},
|
||||
{
|
||||
name: $t('preference.two-column'),
|
||||
tip: $t('preference.two-column-tip'),
|
||||
type: 'side-mixed-nav',
|
||||
},
|
||||
{
|
||||
name: $t('preference.horizontal'),
|
||||
tip: $t('preference.vertical-tip'),
|
||||
type: 'header-nav',
|
||||
},
|
||||
{
|
||||
name: $t('preference.mixed-menu'),
|
||||
tip: $t('preference.mixed-menu-tip'),
|
||||
type: 'mixed-nav',
|
||||
},
|
||||
{
|
||||
name: $t('preference.full-content'),
|
||||
tip: $t('preference.full-content-tip'),
|
||||
type: 'full-content',
|
||||
},
|
||||
]);
|
||||
|
||||
function activeClass(theme: string): string[] {
|
||||
return theme === modelValue.value ? ['outline-box-active'] : [];
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex w-full flex-wrap gap-5">
|
||||
<template v-for="theme in PRESET" :key="theme.name">
|
||||
<div
|
||||
class="flex w-[100px] cursor-pointer flex-col"
|
||||
@click="modelValue = theme.type"
|
||||
>
|
||||
<div :class="activeClass(theme.type)" class="outline-box flex-center">
|
||||
<component :is="components[theme.type]" />
|
||||
</div>
|
||||
<div
|
||||
class="text-muted-foreground flex-center hover:text-foreground mt-2 text-center text-xs"
|
||||
>
|
||||
{{ theme.name }}
|
||||
<VbenTooltip v-if="theme.tip" side="bottom">
|
||||
<template #trigger>
|
||||
<MdiQuestionMarkCircleOutline class="ml-1 cursor-help" />
|
||||
</template>
|
||||
{{ theme.tip }}
|
||||
</VbenTooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
@@ -0,0 +1,45 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectListItem } from '@vben/types';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
import ToggleItem from '../toggle-item.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceNavigationConfig',
|
||||
});
|
||||
|
||||
defineProps<{ disabled?: boolean; disabledNavigationSplit?: boolean }>();
|
||||
|
||||
const navigationStyle = defineModel<string>('navigationStyle');
|
||||
const navigationSplit = defineModel<boolean>('navigationSplit');
|
||||
const navigationAccordion = defineModel<boolean>('navigationAccordion');
|
||||
|
||||
const stylesItems: SelectListItem[] = [
|
||||
{ label: $t('preference.rounded'), value: 'rounded' },
|
||||
{ label: $t('preference.plain'), value: 'plain' },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ToggleItem
|
||||
v-model="navigationStyle"
|
||||
:items="stylesItems"
|
||||
:disabled="disabled"
|
||||
>
|
||||
{{ $t('preference.navigation-style') }}
|
||||
</ToggleItem>
|
||||
<SwitchItem
|
||||
v-model="navigationSplit"
|
||||
:disabled="disabledNavigationSplit || disabled"
|
||||
>
|
||||
{{ $t('preference.navigation-split') }}
|
||||
<template #tip>
|
||||
{{ $t('preference.navigation-split-tip') }}
|
||||
</template>
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="navigationAccordion" :disabled="disabled">
|
||||
{{ $t('preference.navigation-accordion') }}
|
||||
</SwitchItem>
|
||||
</template>
|
@@ -0,0 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceBreadcrumbConfig',
|
||||
});
|
||||
|
||||
defineProps<{ disabled: boolean }>();
|
||||
|
||||
const sideVisible = defineModel<boolean>('sideVisible');
|
||||
const sideCollapseShowTitle = defineModel<boolean>('sideCollapseShowTitle');
|
||||
const sideCollapse = defineModel<boolean>('sideCollapse');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SwitchItem v-model="sideVisible" :disabled="disabled">
|
||||
{{ $t('preference.side-visible') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="sideCollapse" :disabled="!sideVisible || disabled">
|
||||
{{ $t('preference.collapse') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem
|
||||
v-model="sideCollapseShowTitle"
|
||||
:disabled="!sideVisible || disabled"
|
||||
>
|
||||
{{ $t('preference.collapse-show-title') }}
|
||||
</SwitchItem>
|
||||
</template>
|
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceTabsConfig',
|
||||
});
|
||||
|
||||
defineProps<{ disabled?: boolean }>();
|
||||
|
||||
const tabsVisible = defineModel<boolean>('tabsVisible');
|
||||
const tabsIcon = defineModel<boolean>('tabsIcon');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SwitchItem v-model="tabsVisible" :disabled="disabled">
|
||||
{{ $t('preference.tabs-visible') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="tabsIcon" :disabled="!tabsVisible">
|
||||
{{ $t('preference.tabs-icon') }}
|
||||
</SwitchItem>
|
||||
<!-- <SwitchItem v-model="sideCollapseShowTitle" :disabled="!tabsVisible">
|
||||
{{ $t('preference.collapse-show-title') }}
|
||||
</SwitchItem> -->
|
||||
</template>
|
@@ -0,0 +1,67 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectListItem } from '@vben/types';
|
||||
|
||||
import { MdiQuestionMarkCircleOutline } from '@vben-core/iconify';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
VbenTooltip,
|
||||
} from '@vben-core/shadcn-ui';
|
||||
|
||||
import { useSlots } from 'vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceSelectItem',
|
||||
});
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
disabled?: boolean;
|
||||
items?: SelectListItem[];
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
disabled: false,
|
||||
placeholder: '',
|
||||
items: () => [],
|
||||
},
|
||||
);
|
||||
|
||||
const selectValue = defineModel<string>();
|
||||
|
||||
const slots = useSlots();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="my-1 flex w-full items-center justify-between rounded-md px-2 py-1"
|
||||
:class="{
|
||||
'hover:bg-accent': !slots.tip,
|
||||
'pointer-events-none opacity-50': disabled,
|
||||
}"
|
||||
>
|
||||
<span class="flex items-center text-sm">
|
||||
<slot></slot>
|
||||
|
||||
<VbenTooltip v-if="slots.tip" side="bottom">
|
||||
<template #trigger>
|
||||
<MdiQuestionMarkCircleOutline class="ml-1 cursor-help" />
|
||||
</template>
|
||||
<slot name="tip"></slot>
|
||||
</VbenTooltip>
|
||||
</span>
|
||||
<Select v-model="selectValue">
|
||||
<SelectTrigger class="h-7 w-[140px]">
|
||||
<SelectValue :placeholder="placeholder" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<template v-for="item in items" :key="item.value">
|
||||
<SelectItem :value="item.value"> {{ item.label }} </SelectItem>
|
||||
</template>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</template>
|
@@ -0,0 +1,44 @@
|
||||
<script setup lang="ts">
|
||||
import { MdiQuestionMarkCircleOutline } from '@vben-core/iconify';
|
||||
import { Switch, VbenTooltip } from '@vben-core/shadcn-ui';
|
||||
|
||||
import { useSlots } from 'vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceSwitchItem',
|
||||
});
|
||||
|
||||
withDefaults(defineProps<{ disabled?: boolean }>(), {
|
||||
disabled: false,
|
||||
});
|
||||
|
||||
const checked = defineModel<boolean>();
|
||||
|
||||
const slots = useSlots();
|
||||
|
||||
function handleClick() {
|
||||
checked.value = !checked.value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="hover:bg-accent my-1 flex w-full items-center justify-between rounded-md px-2 py-2"
|
||||
:class="{
|
||||
'pointer-events-none opacity-50': disabled,
|
||||
}"
|
||||
@click="handleClick"
|
||||
>
|
||||
<span class="flex items-center text-sm">
|
||||
<slot></slot>
|
||||
|
||||
<VbenTooltip v-if="slots.tip" side="bottom">
|
||||
<template #trigger>
|
||||
<MdiQuestionMarkCircleOutline class="ml-1 cursor-help" />
|
||||
</template>
|
||||
<slot name="tip"></slot>
|
||||
</VbenTooltip>
|
||||
</span>
|
||||
<Switch v-model:checked="checked" @click.stop />
|
||||
</div>
|
||||
</template>
|
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceColorMode',
|
||||
});
|
||||
|
||||
const colorWeakMode = defineModel<boolean>('colorWeakMode', {
|
||||
default: false,
|
||||
});
|
||||
|
||||
const colorGrayMode = defineModel<boolean>('colorGrayMode', {
|
||||
default: false,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SwitchItem v-model="colorWeakMode">
|
||||
{{ $t('preference.weak-mode') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="colorGrayMode">
|
||||
{{ $t('preference.gray-mode') }}
|
||||
</SwitchItem>
|
||||
</template>
|
@@ -0,0 +1,91 @@
|
||||
<script setup lang="ts">
|
||||
import { MdiEditBoxOutline } from '@vben-core/iconify';
|
||||
import { TinyColor, convertToHsl } from '@vben-core/toolkit';
|
||||
|
||||
import type { CSSProperties } from 'vue';
|
||||
|
||||
import { computed, ref, watch, watchEffect } from 'vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceColor',
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<{ colorPrimaryPresets: string[] }>(), {
|
||||
colorPrimaryPresets: () => [],
|
||||
});
|
||||
|
||||
const colorInput = ref();
|
||||
const currentColor = ref(props.colorPrimaryPresets?.[0]);
|
||||
|
||||
const modelValue = defineModel<string>();
|
||||
|
||||
const activeColor = computed((): CSSProperties => {
|
||||
return {
|
||||
outlineColor: currentColor.value,
|
||||
outlineWidth: '2px',
|
||||
};
|
||||
});
|
||||
|
||||
function isActive(color: string): string[] {
|
||||
return color === currentColor.value ? ['outline-box-active'] : [];
|
||||
}
|
||||
|
||||
const inputStyle = computed((): CSSProperties => {
|
||||
return props.colorPrimaryPresets.includes(currentColor.value)
|
||||
? {}
|
||||
: activeColor.value;
|
||||
});
|
||||
|
||||
const inputValue = computed(() => {
|
||||
return new TinyColor(modelValue.value).toHexString();
|
||||
});
|
||||
|
||||
function selectColor() {
|
||||
colorInput.value.click();
|
||||
}
|
||||
|
||||
function handleInputChange(e: Event) {
|
||||
const target = e.target as HTMLInputElement;
|
||||
modelValue.value = convertToHsl(target.value);
|
||||
}
|
||||
|
||||
// 监听颜色变化,转成系统可识别的 hsl 格式
|
||||
watch(currentColor, (val) => {
|
||||
modelValue.value = convertToHsl(val);
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
if (modelValue.value) {
|
||||
currentColor.value = modelValue.value;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex w-full flex-wrap justify-between">
|
||||
<template v-for="color in colorPrimaryPresets" :key="color">
|
||||
<div
|
||||
:class="isActive(color)"
|
||||
class="outline-box p-2"
|
||||
@click="currentColor = color"
|
||||
>
|
||||
<div
|
||||
:style="{ backgroundColor: color }"
|
||||
class="h-6 w-6 rounded-md"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
<div :style="inputStyle" class="outline-box p-2" @click="selectColor">
|
||||
<div class="flex-center bg-accent relative h-6 w-6 rounded-md">
|
||||
<MdiEditBoxOutline class="absolute z-10" />
|
||||
<input
|
||||
ref="colorInput"
|
||||
:value="inputValue"
|
||||
class="absolute inset-0 opacity-0"
|
||||
type="color"
|
||||
@input="handleInputChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@@ -0,0 +1,82 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
IcRoundMotionPhotosAuto,
|
||||
IcRoundWbSunny,
|
||||
MdiMoonAndStars,
|
||||
} from '@vben-core/iconify';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceTheme',
|
||||
});
|
||||
|
||||
const modelValue = defineModel<string>({ default: 'auto' });
|
||||
const semiDarkMenu = defineModel<boolean>('semiDarkMenu', {
|
||||
default: true,
|
||||
});
|
||||
|
||||
const THEME_PRESET = [
|
||||
{
|
||||
icon: IcRoundWbSunny,
|
||||
name: 'light',
|
||||
},
|
||||
{
|
||||
icon: MdiMoonAndStars,
|
||||
name: 'dark',
|
||||
},
|
||||
{
|
||||
icon: IcRoundMotionPhotosAuto,
|
||||
name: 'auto',
|
||||
},
|
||||
];
|
||||
|
||||
function activeClass(theme: string): string[] {
|
||||
return theme === modelValue.value ? ['outline-box-active'] : [];
|
||||
}
|
||||
|
||||
function nameView(name: string) {
|
||||
switch (name) {
|
||||
case 'light': {
|
||||
return $t('preference.light');
|
||||
}
|
||||
case 'dark': {
|
||||
return $t('preference.dark');
|
||||
}
|
||||
case 'auto': {
|
||||
return $t('preference.follow-system');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex w-full flex-wrap justify-between">
|
||||
<template v-for="theme in THEME_PRESET" :key="theme.name">
|
||||
<div
|
||||
class="flex cursor-pointer flex-col"
|
||||
@click="modelValue = theme.name"
|
||||
>
|
||||
<div
|
||||
:class="activeClass(theme.name)"
|
||||
class="outline-box flex-center py-4"
|
||||
>
|
||||
<component :is="theme.icon" class="mx-9 size-5" />
|
||||
</div>
|
||||
<div class="text-muted-foreground mt-2 text-center text-xs">
|
||||
{{ nameView(theme.name) }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<SwitchItem
|
||||
v-model="semiDarkMenu"
|
||||
:disabled="modelValue !== 'light'"
|
||||
class="mt-6"
|
||||
>
|
||||
{{ $t('preference.dark-menu') }}
|
||||
</SwitchItem>
|
||||
</div>
|
||||
</template>
|
@@ -0,0 +1,44 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectListItem } from '@vben/types';
|
||||
|
||||
import { ToggleGroup, ToggleGroupItem } from '@vben-core/shadcn-ui';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceToggleItem',
|
||||
});
|
||||
|
||||
withDefaults(defineProps<{ disabled?: boolean; items: SelectListItem[] }>(), {
|
||||
disabled: false,
|
||||
items: () => [],
|
||||
});
|
||||
|
||||
const modelValue = defineModel<string>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
disabled
|
||||
class="hover:bg-accent flex w-full items-center justify-between rounded-md px-2 py-2"
|
||||
:class="{
|
||||
'pointer-events-none opacity-50': disabled,
|
||||
}"
|
||||
>
|
||||
<span class="text-sm"><slot></slot></span>
|
||||
<ToggleGroup
|
||||
v-model="modelValue"
|
||||
type="single"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="gap-2"
|
||||
>
|
||||
<template v-for="item in items" :key="item.value">
|
||||
<ToggleGroupItem
|
||||
:value="item.value"
|
||||
class="data-[state=on]:bg-primary data-[state=on]:text-primary-foreground h-7 rounded-sm"
|
||||
>
|
||||
{{ item.label }}
|
||||
</ToggleGroupItem>
|
||||
</template>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
</template>
|
@@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<svg
|
||||
class="custom-radio-image"
|
||||
fill="none"
|
||||
height="66"
|
||||
width="104"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g>
|
||||
<rect
|
||||
id="svg_1"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.02"
|
||||
height="66"
|
||||
rx="4"
|
||||
stroke="null"
|
||||
width="104"
|
||||
x="0.13514"
|
||||
y="0.13514"
|
||||
/>
|
||||
<rect
|
||||
id="svg_8"
|
||||
fill="hsl(var(--color-primary))"
|
||||
height="9.07027"
|
||||
stroke="null"
|
||||
width="104.07934"
|
||||
x="-0.07419"
|
||||
y="-0.05773"
|
||||
/>
|
||||
<rect
|
||||
id="svg_3"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="7.52486"
|
||||
x="15.58168"
|
||||
y="3.20832"
|
||||
/>
|
||||
<path
|
||||
id="svg_12"
|
||||
d="m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z"
|
||||
fill="#ffffff"
|
||||
opacity="undefined"
|
||||
stroke="null"
|
||||
/>
|
||||
<rect
|
||||
id="svg_13"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="21.51892"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="41.98275"
|
||||
x="45.37589"
|
||||
y="13.53192"
|
||||
/>
|
||||
<path
|
||||
id="svg_14"
|
||||
d="m16.4123,15.53192c0,-1.08676 0.74096,-2 1.62271,-2l21.74653,0c0.88175,0 1.62271,0.91324 1.62271,2l0,17.24865c0,1.08676 -0.74096,2 -1.62271,2l-21.74653,0c-0.88175,0 -1.62271,-0.91324 -1.62271,-2l0,-17.24865z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
opacity="undefined"
|
||||
stroke="null"
|
||||
/>
|
||||
<rect
|
||||
id="svg_15"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="21.65405"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="71.10636"
|
||||
x="16.54743"
|
||||
y="39.34689"
|
||||
/>
|
||||
<rect
|
||||
id="svg_21"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="7.52486"
|
||||
x="28.14924"
|
||||
y="3.07319"
|
||||
/>
|
||||
<rect
|
||||
id="svg_22"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="7.52486"
|
||||
x="41.25735"
|
||||
y="3.20832"
|
||||
/>
|
||||
<rect
|
||||
id="svg_23"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="7.52486"
|
||||
x="54.23033"
|
||||
y="3.07319"
|
||||
/>
|
||||
<rect
|
||||
id="svg_4"
|
||||
fill="#ffffff"
|
||||
height="7.13843"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="7.78397"
|
||||
x="1.5327"
|
||||
y="0.881"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<svg
|
||||
class="custom-radio-image"
|
||||
fill="none"
|
||||
height="66"
|
||||
width="104"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
id="svg_1"
|
||||
d="m0.13514,4.13514c0,-2.17352 1.82648,-4 4,-4l96,0c2.17352,0 4,1.82648 4,4l0,58c0,2.17352 -1.82648,4 -4,4l-96,0c-2.17352,0 -4,-1.82648 -4,-4l0,-58z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.02"
|
||||
opacity="undefined"
|
||||
stroke="null"
|
||||
/>
|
||||
<rect
|
||||
id="svg_13"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="26.57155"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="53.18333"
|
||||
x="45.79979"
|
||||
y="3.77232"
|
||||
/>
|
||||
<path
|
||||
id="svg_14"
|
||||
d="m4.28142,5.96169c0,-1.37748 1.06465,-2.53502 2.33158,-2.53502l31.2463,0c1.26693,0 2.33158,1.15754 2.33158,2.53502l0,21.86282c0,1.37748 -1.06465,2.53502 -2.33158,2.53502l-31.2463,0c-1.26693,0 -2.33158,-1.15754 -2.33158,-2.53502l0,-21.86282z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
opacity="undefined"
|
||||
stroke="null"
|
||||
/>
|
||||
<rect
|
||||
id="svg_15"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="25.02247"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="94.39371"
|
||||
x="4.56735"
|
||||
y="34.92584"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
119
packages/business/common-ui/src/preferences/icons/header-nav.vue
Normal file
119
packages/business/common-ui/src/preferences/icons/header-nav.vue
Normal file
@@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<svg
|
||||
class="custom-radio-image"
|
||||
fill="none"
|
||||
height="66"
|
||||
width="104"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g>
|
||||
<rect
|
||||
id="svg_1"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.02"
|
||||
height="66"
|
||||
rx="4"
|
||||
stroke="null"
|
||||
width="104"
|
||||
x="0.13514"
|
||||
y="0.13514"
|
||||
/>
|
||||
<rect
|
||||
id="svg_8"
|
||||
fill="hsl(var(--color-primary))"
|
||||
height="9.07027"
|
||||
stroke="null"
|
||||
width="104.07934"
|
||||
x="-0.07419"
|
||||
y="-0.05773"
|
||||
/>
|
||||
<rect
|
||||
id="svg_3"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="7.52486"
|
||||
x="15.58168"
|
||||
y="3.20832"
|
||||
/>
|
||||
<path
|
||||
id="svg_12"
|
||||
d="m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z"
|
||||
fill="#ffffff"
|
||||
opacity="undefined"
|
||||
stroke="null"
|
||||
/>
|
||||
<rect
|
||||
id="svg_13"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="21.51892"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="53.60438"
|
||||
x="43.484"
|
||||
y="13.66705"
|
||||
/>
|
||||
<path
|
||||
id="svg_14"
|
||||
d="m3.43932,15.53192c0,-1.08676 1.03344,-2 2.26323,-2l30.33036,0c1.22979,0 2.26323,0.91324 2.26323,2l0,17.24865c0,1.08676 -1.03344,2 -2.26323,2l-30.33036,0c-1.22979,0 -2.26323,-0.91324 -2.26323,-2l0,-17.24865z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
opacity="undefined"
|
||||
stroke="null"
|
||||
/>
|
||||
<rect
|
||||
id="svg_15"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="21.65405"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="95.02528"
|
||||
x="3.30419"
|
||||
y="39.34689"
|
||||
/>
|
||||
<rect
|
||||
id="svg_21"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="7.52486"
|
||||
x="28.14924"
|
||||
y="3.07319"
|
||||
/>
|
||||
<rect
|
||||
id="svg_22"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="7.52486"
|
||||
x="41.25735"
|
||||
y="3.20832"
|
||||
/>
|
||||
<rect
|
||||
id="svg_23"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="7.52486"
|
||||
x="54.23033"
|
||||
y="3.07319"
|
||||
/>
|
||||
<rect
|
||||
id="svg_4"
|
||||
fill="#ffffff"
|
||||
height="7.13843"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="7.78397"
|
||||
x="1.5327"
|
||||
y="0.881"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
10
packages/business/common-ui/src/preferences/icons/index.ts
Normal file
10
packages/business/common-ui/src/preferences/icons/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import HeaderNav from './header-nav.vue';
|
||||
|
||||
export { default as ContentCompact } from './content-compact.vue';
|
||||
export { default as FullContent } from './full-content.vue';
|
||||
export { default as MixedNav } from './mixed-nav.vue';
|
||||
export { default as SideMixedNav } from './side-mixed-nav.vue';
|
||||
export { default as SideNav } from './side-nav.vue';
|
||||
|
||||
const ContentWide = HeaderNav;
|
||||
export { ContentWide, HeaderNav };
|
161
packages/business/common-ui/src/preferences/icons/mixed-nav.vue
Normal file
161
packages/business/common-ui/src/preferences/icons/mixed-nav.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<svg
|
||||
class="custom-radio-image"
|
||||
fill="none"
|
||||
height="66"
|
||||
width="104"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g>
|
||||
<rect
|
||||
id="svg_1"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.02"
|
||||
height="66"
|
||||
rx="4"
|
||||
stroke="null"
|
||||
width="104"
|
||||
x="0.13514"
|
||||
y="0.13514"
|
||||
/>
|
||||
<rect
|
||||
id="svg_8"
|
||||
fill="hsl(var(--color-primary))"
|
||||
height="9.07027"
|
||||
stroke="null"
|
||||
width="104.07934"
|
||||
x="-0.07419"
|
||||
y="-0.05773"
|
||||
/>
|
||||
<rect
|
||||
id="svg_3"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="7.52486"
|
||||
x="15.58168"
|
||||
y="3.20832"
|
||||
/>
|
||||
<path
|
||||
id="svg_12"
|
||||
d="m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z"
|
||||
fill="#ffffff"
|
||||
opacity="undefined"
|
||||
stroke="null"
|
||||
/>
|
||||
<rect
|
||||
id="svg_13"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="21.51892"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="44.13071"
|
||||
x="53.37873"
|
||||
y="13.45652"
|
||||
/>
|
||||
<path
|
||||
id="svg_14"
|
||||
d="m19.4393,15.74245c0,-1.08676 0.79001,-2 1.73013,-2l23.18605,0c0.94011,0 1.73013,0.91324 1.73013,2l0,17.24865c0,1.08676 -0.79001,2 -1.73013,2l-23.18605,0c-0.94011,0 -1.73013,-0.91324 -1.73013,-2l0,-17.24865z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
opacity="undefined"
|
||||
stroke="null"
|
||||
/>
|
||||
<rect
|
||||
id="svg_15"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="21.65405"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="78.39372"
|
||||
x="19.93575"
|
||||
y="39.34689"
|
||||
/>
|
||||
<rect
|
||||
id="svg_21"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="7.52486"
|
||||
x="28.14924"
|
||||
y="3.07319"
|
||||
/>
|
||||
<rect
|
||||
id="svg_22"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="7.52486"
|
||||
x="41.25735"
|
||||
y="3.20832"
|
||||
/>
|
||||
<rect
|
||||
id="svg_23"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="7.52486"
|
||||
x="54.23033"
|
||||
y="3.07319"
|
||||
/>
|
||||
<rect
|
||||
id="svg_4"
|
||||
fill="#ffffff"
|
||||
height="7.13843"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="7.78397"
|
||||
x="1.5327"
|
||||
y="0.881"
|
||||
/>
|
||||
<rect
|
||||
id="svg_5"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="56.81191"
|
||||
stroke="null"
|
||||
width="15.44642"
|
||||
x="-0.06423"
|
||||
y="9.03113"
|
||||
/>
|
||||
<path
|
||||
id="svg_2"
|
||||
d="m2.38669,15.38074c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
opacity="undefined"
|
||||
stroke="null"
|
||||
/>
|
||||
<path
|
||||
id="svg_6"
|
||||
d="m2.38669,28.43336c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
opacity="undefined"
|
||||
stroke="null"
|
||||
/>
|
||||
<path
|
||||
id="svg_7"
|
||||
d="m2.17616,41.27545c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
opacity="undefined"
|
||||
stroke="null"
|
||||
/>
|
||||
<path
|
||||
id="svg_9"
|
||||
d="m2.17616,54.32806c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
opacity="undefined"
|
||||
stroke="null"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<svg
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M19.9 12.66a1 1 0 0 1 0-1.32l1.28-1.44a1 1 0 0 0 .12-1.17l-2-3.46a1 1 0 0 0-1.07-.48l-1.88.38a1 1 0 0 1-1.15-.66l-.61-1.83a1 1 0 0 0-.95-.68h-4a1 1 0 0 0-1 .68l-.56 1.83a1 1 0 0 1-1.15.66L5 4.79a1 1 0 0 0-1 .48L2 8.73a1 1 0 0 0 .1 1.17l1.27 1.44a1 1 0 0 1 0 1.32L2.1 14.1a1 1 0 0 0-.1 1.17l2 3.46a1 1 0 0 0 1.07.48l1.88-.38a1 1 0 0 1 1.15.66l.61 1.83a1 1 0 0 0 1 .68h4a1 1 0 0 0 .95-.68l.61-1.83a1 1 0 0 1 1.15-.66l1.88.38a1 1 0 0 0 1.07-.48l2-3.46a1 1 0 0 0-.12-1.17ZM18.41 14l.8.9l-1.28 2.22l-1.18-.24a3 3 0 0 0-3.45 2L12.92 20h-2.56L10 18.86a3 3 0 0 0-3.45-2l-1.18.24l-1.3-2.21l.8-.9a3 3 0 0 0 0-4l-.8-.9l1.28-2.2l1.18.24a3 3 0 0 0 3.45-2L10.36 4h2.56l.38 1.14a3 3 0 0 0 3.45 2l1.18-.24l1.28 2.22l-.8.9a3 3 0 0 0 0 3.98m-6.77-6a4 4 0 1 0 4 4a4 4 0 0 0-4-4m0 6a2 2 0 1 1 2-2a2 2 0 0 1-2 2"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<svg
|
||||
class="custom-radio-image"
|
||||
fill="none"
|
||||
height="66"
|
||||
width="104"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g>
|
||||
<rect
|
||||
id="svg_1"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.02"
|
||||
height="66"
|
||||
rx="4"
|
||||
stroke="null"
|
||||
width="104"
|
||||
x="0.13514"
|
||||
y="0.13514"
|
||||
/>
|
||||
<path
|
||||
id="svg_2"
|
||||
d="m-3.37838,3.7543a1.93401,4.02457 0 0 1 1.93401,-4.02457l11.3488,0l0,66.40541l-11.3488,0a1.93401,4.02457 0 0 1 -1.93401,-4.02457l0,-58.35627z"
|
||||
fill="hsl(var(--color-primary))"
|
||||
stroke="null"
|
||||
/>
|
||||
<rect
|
||||
id="svg_3"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="5.47439"
|
||||
x="1.64059"
|
||||
y="15.46086"
|
||||
/>
|
||||
<rect
|
||||
id="svg_4"
|
||||
fill="#ffffff"
|
||||
height="7.67897"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="8.18938"
|
||||
x="0.58676"
|
||||
y="1.42154"
|
||||
/>
|
||||
<rect
|
||||
id="svg_8"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="9.07027"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="75.91967"
|
||||
x="25.38277"
|
||||
y="1.42876"
|
||||
/>
|
||||
<rect
|
||||
id="svg_9"
|
||||
fill="#b2b2b2"
|
||||
height="4.4"
|
||||
rx="1"
|
||||
stroke="null"
|
||||
width="3.925"
|
||||
x="27.91529"
|
||||
y="3.69284"
|
||||
/>
|
||||
<rect
|
||||
id="svg_10"
|
||||
fill="#b2b2b2"
|
||||
height="4.4"
|
||||
rx="1"
|
||||
stroke="null"
|
||||
width="3.925"
|
||||
x="80.75054"
|
||||
y="3.62876"
|
||||
/>
|
||||
<rect
|
||||
id="svg_11"
|
||||
fill="#b2b2b2"
|
||||
height="4.4"
|
||||
rx="1"
|
||||
stroke="null"
|
||||
width="3.925"
|
||||
x="87.78868"
|
||||
y="3.69981"
|
||||
/>
|
||||
<rect
|
||||
id="svg_12"
|
||||
fill="#b2b2b2"
|
||||
height="4.4"
|
||||
rx="1"
|
||||
stroke="null"
|
||||
width="3.925"
|
||||
x="94.6847"
|
||||
y="3.62876"
|
||||
/>
|
||||
<rect
|
||||
id="svg_13"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="21.51892"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="42.9287"
|
||||
x="58.75427"
|
||||
y="14.613"
|
||||
/>
|
||||
<rect
|
||||
id="svg_14"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="20.97838"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="28.36894"
|
||||
x="26.14342"
|
||||
y="14.613"
|
||||
/>
|
||||
<rect
|
||||
id="svg_15"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="21.65405"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="75.09493"
|
||||
x="26.34264"
|
||||
y="39.68822"
|
||||
/>
|
||||
<rect
|
||||
id="svg_5"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="5.47439"
|
||||
x="1.79832"
|
||||
y="28.39462"
|
||||
/>
|
||||
<rect
|
||||
id="svg_6"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="5.47439"
|
||||
x="1.64059"
|
||||
y="41.80156"
|
||||
/>
|
||||
<rect
|
||||
id="svg_7"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
stroke="null"
|
||||
width="5.47439"
|
||||
x="1.64059"
|
||||
y="55.36623"
|
||||
/>
|
||||
<rect
|
||||
id="svg_16"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="65.72065"
|
||||
stroke="null"
|
||||
width="12.49265"
|
||||
x="9.85477"
|
||||
y="-0.02618"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
153
packages/business/common-ui/src/preferences/icons/side-nav.vue
Normal file
153
packages/business/common-ui/src/preferences/icons/side-nav.vue
Normal file
@@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<svg
|
||||
class="custom-radio-image"
|
||||
fill="none"
|
||||
height="66"
|
||||
width="104"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g>
|
||||
<rect
|
||||
id="svg_1"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.02"
|
||||
height="66"
|
||||
rx="4"
|
||||
stroke="null"
|
||||
width="104"
|
||||
/>
|
||||
<path
|
||||
id="svg_2"
|
||||
d="m-3.37838,3.61916a4.4919,4.02457 0 0 1 4.4919,-4.02457l26.35848,0l0,66.40541l-26.35848,0a4.4919,4.02457 0 0 1 -4.4919,-4.02457l0,-58.35627z"
|
||||
fill="hsl(var(--color-primary))"
|
||||
stroke="null"
|
||||
/>
|
||||
<rect
|
||||
id="svg_3"
|
||||
fill="#e5e5e5"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
width="17.66"
|
||||
x="4.906"
|
||||
y="23.884"
|
||||
/>
|
||||
<rect
|
||||
id="svg_4"
|
||||
fill="#ffffff"
|
||||
height="9.706"
|
||||
rx="2"
|
||||
width="9.811"
|
||||
x="8.83"
|
||||
y="5.881"
|
||||
/>
|
||||
<path
|
||||
id="svg_5"
|
||||
d="m4.906,35.833c0,-0.75801 0.63699,-1.395 1.395,-1.395l14.87,0c0.75801,0 1.395,0.63699 1.395,1.395l0,-0.001c0,0.75801 -0.63699,1.395 -1.395,1.395l-14.87,0c-0.75801,0 -1.395,-0.63699 -1.395,-1.395l0,0.001z"
|
||||
fill="#ffffff"
|
||||
opacity="undefined"
|
||||
/>
|
||||
<rect
|
||||
id="svg_6"
|
||||
fill="#ffffff"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
width="17.66"
|
||||
x="4.906"
|
||||
y="44.992"
|
||||
/>
|
||||
<rect
|
||||
id="svg_7"
|
||||
fill="#ffffff"
|
||||
height="2.789"
|
||||
rx="1.395"
|
||||
width="17.66"
|
||||
x="4.906"
|
||||
y="55.546"
|
||||
/>
|
||||
<rect
|
||||
id="svg_8"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="9.07027"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="73.53879"
|
||||
x="28.97986"
|
||||
y="1.42876"
|
||||
/>
|
||||
<rect
|
||||
id="svg_9"
|
||||
fill="#b2b2b2"
|
||||
height="4.4"
|
||||
rx="1"
|
||||
stroke="null"
|
||||
width="3.925"
|
||||
x="32.039"
|
||||
y="3.89903"
|
||||
/>
|
||||
<rect
|
||||
id="svg_10"
|
||||
fill="#b2b2b2"
|
||||
height="4.4"
|
||||
rx="1"
|
||||
stroke="null"
|
||||
width="3.925"
|
||||
x="80.75054"
|
||||
y="3.62876"
|
||||
/>
|
||||
<rect
|
||||
id="svg_11"
|
||||
fill="#b2b2b2"
|
||||
height="4.4"
|
||||
rx="1"
|
||||
stroke="null"
|
||||
width="3.925"
|
||||
x="87.58249"
|
||||
y="3.49362"
|
||||
/>
|
||||
<rect
|
||||
id="svg_12"
|
||||
fill="#b2b2b2"
|
||||
height="4.4"
|
||||
rx="1"
|
||||
stroke="null"
|
||||
width="3.925"
|
||||
x="94.6847"
|
||||
y="3.62876"
|
||||
/>
|
||||
<rect
|
||||
id="svg_13"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="21.51892"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="45.63141"
|
||||
x="56.05157"
|
||||
y="14.613"
|
||||
/>
|
||||
<rect
|
||||
id="svg_14"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="20.97838"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="22.82978"
|
||||
x="29.38527"
|
||||
y="14.613"
|
||||
/>
|
||||
<rect
|
||||
id="svg_15"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.08"
|
||||
height="21.65405"
|
||||
rx="2"
|
||||
stroke="null"
|
||||
width="72.45771"
|
||||
x="28.97986"
|
||||
y="39.48203"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
1
packages/business/common-ui/src/preferences/index.ts
Normal file
1
packages/business/common-ui/src/preferences/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as PreferencesWidget } from './preferences-widget.vue';
|
@@ -0,0 +1,58 @@
|
||||
<script lang="ts" setup>
|
||||
import type { LocaleSupportType } from '@vben/types';
|
||||
|
||||
import {
|
||||
COLOR_PRIMARY_RESETS,
|
||||
flatPreferences,
|
||||
updatePreferences,
|
||||
} from '@vben-core/preferences';
|
||||
|
||||
import { loadLocaleMessages } from '@vben/locales';
|
||||
|
||||
import Preferences from './preferences.vue';
|
||||
|
||||
function updateLocale(value: string) {
|
||||
const locale = value as LocaleSupportType;
|
||||
updatePreferences({
|
||||
app: { locale },
|
||||
});
|
||||
// 更改预览
|
||||
loadLocaleMessages(locale);
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Preferences
|
||||
v-model:breadcrumb-visible="flatPreferences.breadcrumbEnable"
|
||||
v-model:breadcrumb-style="flatPreferences.breadcrumbStyleType"
|
||||
v-model:color-gray-mode="flatPreferences.appColorGrayMode"
|
||||
v-model:breadcrumb-icon="flatPreferences.breadcrumbShowIcon"
|
||||
v-model:color-primary="flatPreferences.themeColorPrimary"
|
||||
v-model:color-weak-mode="flatPreferences.appColorWeakMode"
|
||||
v-model:content-compact="flatPreferences.appContentCompact"
|
||||
v-model:breadcrumb-home="flatPreferences.breadcrumbShowHome"
|
||||
v-model:side-collapse="flatPreferences.sidebarCollapse"
|
||||
v-model:layout="flatPreferences.appLayout"
|
||||
v-model:semi-dark-menu="flatPreferences.appSemiDarkMenu"
|
||||
v-model:side-visible="flatPreferences.sidebarEnable"
|
||||
v-model:footer-visible="flatPreferences.footerEnable"
|
||||
v-model:tabs-visible="flatPreferences.tabbarEnable"
|
||||
v-model:header-visible="flatPreferences.headerEnable"
|
||||
v-model:header-mode="flatPreferences.headerMode"
|
||||
v-model:footer-fixed="flatPreferences.footerFixed"
|
||||
v-model:theme="flatPreferences.appThemeMode"
|
||||
v-model:dynamic-title="flatPreferences.appDynamicTitle"
|
||||
v-model:breadcrumb-hide-only-one="flatPreferences.breadcrumbHideOnlyOne"
|
||||
v-model:page-transition="flatPreferences.transitionName"
|
||||
v-model:page-progress="flatPreferences.transitionProgress"
|
||||
v-model:tabs-icon="flatPreferences.tabbarShowIcon"
|
||||
v-model:navigation-accordion="flatPreferences.navigationAccordion"
|
||||
v-model:navigation-style="flatPreferences.navigationStyleType"
|
||||
v-model:shortcut-keys="flatPreferences.shortcutKeysEnable"
|
||||
v-model:navigation-split="flatPreferences.navigationSplit"
|
||||
v-model:page-transition-enable="flatPreferences.transitionEnable"
|
||||
v-model:side-collapse-show-title="flatPreferences.sidebarCollapseShowTitle"
|
||||
:color-primary-presets="COLOR_PRIMARY_RESETS"
|
||||
:locale="flatPreferences.appLocale"
|
||||
@update:locale="updateLocale"
|
||||
/>
|
||||
</template>
|
291
packages/business/common-ui/src/preferences/preferences.vue
Normal file
291
packages/business/common-ui/src/preferences/preferences.vue
Normal file
@@ -0,0 +1,291 @@
|
||||
<script setup lang="ts">
|
||||
import type { LayoutHeaderModeType, LayoutType } from '@vben/types';
|
||||
import type { SegmentedItem } from '@vben-core/shadcn-ui';
|
||||
|
||||
import { IcRoundFolderCopy, IcRoundRestartAlt } from '@vben-core/iconify';
|
||||
import {
|
||||
preferences,
|
||||
resetPreferences,
|
||||
usePreferences,
|
||||
} from '@vben-core/preferences';
|
||||
import {
|
||||
VbenButton,
|
||||
VbenIconButton,
|
||||
VbenSegmented,
|
||||
VbenSheet,
|
||||
toast,
|
||||
} from '@vben-core/shadcn-ui';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import {
|
||||
Animation,
|
||||
Block,
|
||||
Breadcrumb,
|
||||
ColorMode,
|
||||
Content,
|
||||
Footer,
|
||||
General,
|
||||
Header,
|
||||
Layout,
|
||||
Navigation,
|
||||
Sidebar,
|
||||
Tabs,
|
||||
Theme,
|
||||
ThemeColor,
|
||||
} from './blocks';
|
||||
import Trigger from './trigger.vue';
|
||||
import { useOpenPreferences } from './use-open-preferences';
|
||||
|
||||
withDefaults(defineProps<{ colorPrimaryPresets: string[] }>(), {
|
||||
colorPrimaryPresets: () => [],
|
||||
});
|
||||
|
||||
const theme = defineModel<string>('theme');
|
||||
const locale = defineModel<string>('locale');
|
||||
const dynamicTitle = defineModel<boolean>('dynamicTitle');
|
||||
const semiDarkMenu = defineModel<boolean>('semiDarkMenu');
|
||||
const breadcrumbVisible = defineModel<boolean>('breadcrumbVisible');
|
||||
const breadcrumbIcon = defineModel<boolean>('breadcrumbIcon');
|
||||
const breadcrumbHome = defineModel<boolean>('breadcrumbHome');
|
||||
const breadcrumbStyle = defineModel<string>('breadcrumbStyle');
|
||||
const breadcrumbHideOnlyOne = defineModel<boolean>('breadcrumbHideOnlyOne');
|
||||
const sideCollapseShowTitle = defineModel<boolean>('sideCollapseShowTitle');
|
||||
const sideCollapse = defineModel<boolean>('sideCollapse');
|
||||
const colorWeakMode = defineModel<boolean>('colorWeakMode');
|
||||
const colorGrayMode = defineModel<boolean>('colorGrayMode');
|
||||
const colorPrimary = defineModel<string>('colorPrimary');
|
||||
const navigationStyle = defineModel<string>('navigationStyle');
|
||||
const navigationSplit = defineModel<boolean>('navigationSplit');
|
||||
const navigationAccordion = defineModel<boolean>('navigationAccordion');
|
||||
const pageProgress = defineModel<boolean>('pageProgress');
|
||||
const pageTransition = defineModel<string>('pageTransition');
|
||||
const pageTransitionEnable = defineModel<boolean>('pageTransitionEnable');
|
||||
const layout = defineModel<LayoutType>('layout');
|
||||
const contentCompact = defineModel<string>('contentCompact');
|
||||
const sideVisible = defineModel<boolean>('sideVisible');
|
||||
const shortcutKeys = defineModel<boolean>('shortcutKeys');
|
||||
const tabsVisible = defineModel<boolean>('tabsVisible');
|
||||
const tabsIcon = defineModel<boolean>('tabsIcon');
|
||||
// const logoVisible = defineModel<boolean>('logoVisible');
|
||||
const headerVisible = defineModel<boolean>('headerVisible');
|
||||
const headerMode = defineModel<LayoutHeaderModeType>('headerMode');
|
||||
const footerVisible = defineModel<boolean>('footerVisible');
|
||||
const footerFixed = defineModel<boolean>('footerFixed');
|
||||
|
||||
const {
|
||||
diffPreference,
|
||||
isFullContent,
|
||||
isHeaderNav,
|
||||
isMixedNav,
|
||||
isSideMixedNav,
|
||||
isSideMode,
|
||||
isSideNav,
|
||||
} = usePreferences();
|
||||
const { copy } = useClipboard();
|
||||
|
||||
const tabs = computed((): SegmentedItem[] => {
|
||||
return [
|
||||
{
|
||||
label: $t('preference.appearance'),
|
||||
value: 'appearance',
|
||||
},
|
||||
{
|
||||
label: $t('preference.layout'),
|
||||
value: 'layout',
|
||||
},
|
||||
{
|
||||
label: $t('preference.general'),
|
||||
value: 'general',
|
||||
},
|
||||
// {
|
||||
// label: $t('preference.shortcut-key'),
|
||||
// value: 'shortcutKey',
|
||||
// },
|
||||
];
|
||||
});
|
||||
|
||||
const showBreadcrumbConfig = computed(() => {
|
||||
return (
|
||||
!isFullContent.value &&
|
||||
!isMixedNav.value &&
|
||||
!isHeaderNav.value &&
|
||||
preferences.header.enable
|
||||
);
|
||||
});
|
||||
|
||||
const { openPreferences } = useOpenPreferences();
|
||||
|
||||
async function handleCopy() {
|
||||
await copy(JSON.stringify(diffPreference.value, null, 2));
|
||||
|
||||
toast($t('preference.copy-success'));
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
if (!diffPreference.value) {
|
||||
return;
|
||||
}
|
||||
resetPreferences();
|
||||
toast($t('preference.reset-success'));
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="z-100 fixed right-0 top-1/3">
|
||||
<VbenSheet
|
||||
v-model:open="openPreferences"
|
||||
:description="$t('preference.preferences-subtitle')"
|
||||
:title="$t('preference.preferences')"
|
||||
>
|
||||
<template #trigger>
|
||||
<Trigger />
|
||||
</template>
|
||||
<template #extra>
|
||||
<VbenIconButton
|
||||
class="relative"
|
||||
:disabled="!diffPreference"
|
||||
:tooltip="$t('preference.reset-tip')"
|
||||
>
|
||||
<span
|
||||
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" />
|
||||
</VbenIconButton>
|
||||
</template>
|
||||
|
||||
<div class="p-5 pt-4">
|
||||
<VbenSegmented :tabs="tabs" default-value="appearance">
|
||||
<template #appearance>
|
||||
<Block :title="$t('preference.theme')">
|
||||
<Theme v-model="theme" v-model:semi-dark-menu="semiDarkMenu" />
|
||||
</Block>
|
||||
<Block :title="$t('preference.theme-color')">
|
||||
<ThemeColor
|
||||
v-model="colorPrimary"
|
||||
:color-primary-presets="colorPrimaryPresets"
|
||||
/>
|
||||
</Block>
|
||||
<Block :title="$t('preference.other')">
|
||||
<ColorMode
|
||||
v-model:color-gray-mode="colorGrayMode"
|
||||
v-model:color-weak-mode="colorWeakMode"
|
||||
/>
|
||||
</Block>
|
||||
</template>
|
||||
<template #layout>
|
||||
<Block :title="$t('preference.layout')">
|
||||
<Layout v-model="layout" />
|
||||
</Block>
|
||||
<Block :title="$t('preference.content')">
|
||||
<Content v-model="contentCompact" />
|
||||
</Block>
|
||||
|
||||
<Block :title="$t('preference.sidebar')">
|
||||
<Sidebar
|
||||
v-model:side-visible="sideVisible"
|
||||
v-model:side-collapse="sideCollapse"
|
||||
v-model:side-collapse-show-title="sideCollapseShowTitle"
|
||||
:disabled="!isSideMode"
|
||||
/>
|
||||
</Block>
|
||||
|
||||
<Block :title="$t('preference.header')">
|
||||
<Header
|
||||
v-model:header-visible="headerVisible"
|
||||
v-model:headerMode="headerMode"
|
||||
:disabled="isFullContent"
|
||||
/>
|
||||
</Block>
|
||||
|
||||
<Block :title="$t('preference.navigation-menu')">
|
||||
<Navigation
|
||||
v-model:navigation-style="navigationStyle"
|
||||
v-model:navigation-split="navigationSplit"
|
||||
v-model:navigation-accordion="navigationAccordion"
|
||||
:disabled="isFullContent"
|
||||
:disabled-navigation-split="!isMixedNav"
|
||||
/>
|
||||
</Block>
|
||||
|
||||
<Block :title="$t('preference.breadcrumb')">
|
||||
<Breadcrumb
|
||||
v-model:breadcrumb-visible="breadcrumbVisible"
|
||||
v-model:breadcrumb-icon="breadcrumbIcon"
|
||||
v-model:breadcrumb-style="breadcrumbStyle"
|
||||
v-model:breadcrumb-home="breadcrumbHome"
|
||||
v-model:breadcrumb-hide-only-one="breadcrumbHideOnlyOne"
|
||||
:disabled="
|
||||
!showBreadcrumbConfig || !(isSideNav || isSideMixedNav)
|
||||
"
|
||||
/>
|
||||
</Block>
|
||||
|
||||
<Block :title="$t('preference.tabs')">
|
||||
<Tabs
|
||||
v-model:tabs-visible="tabsVisible"
|
||||
v-model:tabs-icon="tabsIcon"
|
||||
/>
|
||||
</Block>
|
||||
<Block :title="$t('preference.footer')">
|
||||
<Footer
|
||||
v-model:footer-visible="footerVisible"
|
||||
v-model:footer-fixed="footerFixed"
|
||||
/>
|
||||
</Block>
|
||||
</template>
|
||||
<template #general>
|
||||
<Block :title="$t('preference.general')">
|
||||
<General
|
||||
v-model:locale="locale"
|
||||
v-model:dynamic-title="dynamicTitle"
|
||||
v-model:shortcut-keys="shortcutKeys"
|
||||
/>
|
||||
</Block>
|
||||
|
||||
<Block :title="$t('preference.animation')">
|
||||
<Animation
|
||||
v-model:page-progress="pageProgress"
|
||||
v-model:page-transition="pageTransition"
|
||||
v-model:page-transition-enable="pageTransitionEnable"
|
||||
/>
|
||||
</Block>
|
||||
</template>
|
||||
<template #shortcutKey>
|
||||
<Block :title="$t('preference.general')">
|
||||
<General
|
||||
v-model:locale="locale"
|
||||
v-model:dynamic-title="dynamicTitle"
|
||||
v-model:shortcut-keys="shortcutKeys"
|
||||
/>
|
||||
</Block>
|
||||
|
||||
<Block :title="$t('preference.animation')">
|
||||
<Animation
|
||||
v-model:page-progress="pageProgress"
|
||||
v-model:page-transition="pageTransition"
|
||||
v-model:page-transition-enable="pageTransitionEnable"
|
||||
/>
|
||||
</Block>
|
||||
</template>
|
||||
</VbenSegmented>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<VbenButton
|
||||
class="mx-6 w-full"
|
||||
variant="default"
|
||||
size="sm"
|
||||
:disabled="!diffPreference"
|
||||
@click="handleCopy"
|
||||
>
|
||||
<IcRoundFolderCopy class="mr-2 size-3" />
|
||||
{{ $t('preference.copy') }}
|
||||
</VbenButton>
|
||||
</template>
|
||||
</VbenSheet>
|
||||
</div>
|
||||
</template>
|
20
packages/business/common-ui/src/preferences/trigger.vue
Normal file
20
packages/business/common-ui/src/preferences/trigger.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import { VbenButton } from '@vben-core/shadcn-ui';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import IconSetting from './icons/setting.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceTrigger',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VbenButton
|
||||
class="bg-primary flex-col-center h-9 w-9 cursor-pointer rounded-l-md rounded-r-none border-none"
|
||||
:title="$t('preference.preferences')"
|
||||
>
|
||||
<IconSetting class="text-lg" />
|
||||
</VbenButton>
|
||||
</template>
|
@@ -0,0 +1,16 @@
|
||||
import { ref } from 'vue';
|
||||
|
||||
const openPreferences = ref(false);
|
||||
|
||||
function useOpenPreferences() {
|
||||
function handleOpenPreference() {
|
||||
openPreferences.value = true;
|
||||
}
|
||||
|
||||
return {
|
||||
handleOpenPreference,
|
||||
openPreferences,
|
||||
};
|
||||
}
|
||||
|
||||
export { useOpenPreferences };
|
Reference in New Issue
Block a user