Merge branch 'main' into fix-downloader
This commit is contained in:
@@ -117,7 +117,7 @@ defineExpose({
|
||||
<div class="flex-center">
|
||||
<VbenCheckbox
|
||||
v-if="showRememberMe"
|
||||
v-model:checked="rememberMe"
|
||||
v-model="rememberMe"
|
||||
name="rememberMe"
|
||||
>
|
||||
{{ $t('authentication.rememberMe') }}
|
||||
|
||||
@@ -39,7 +39,7 @@ withDefaults(defineProps<Props>(), {
|
||||
class="flex cursor-pointer justify-between gap-x-6 py-5"
|
||||
>
|
||||
<div class="flex min-w-0 items-center gap-x-4">
|
||||
<VbenCheckbox v-model:checked="item.completed" name="completed" />
|
||||
<VbenCheckbox v-model="item.completed" name="completed" />
|
||||
<div class="min-w-0 flex-auto">
|
||||
<p class="text-foreground text-sm font-semibold leading-6">
|
||||
{{ item.title }}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import type { ToolbarType } from './types';
|
||||
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { preferences, usePreferences } from '@vben/preferences';
|
||||
|
||||
import { Copyright } from '../basic/copyright';
|
||||
@@ -11,6 +13,7 @@ import Toolbar from './toolbar.vue';
|
||||
interface Props {
|
||||
appName?: string;
|
||||
logo?: string;
|
||||
logoDark?: string;
|
||||
pageTitle?: string;
|
||||
pageDescription?: string;
|
||||
sloganImage?: string;
|
||||
@@ -20,10 +23,11 @@ interface Props {
|
||||
clickLogo?: () => void;
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
appName: '',
|
||||
copyright: true,
|
||||
logo: '',
|
||||
logoDark: '',
|
||||
pageDescription: '',
|
||||
pageTitle: '',
|
||||
sloganImage: '',
|
||||
@@ -34,6 +38,18 @@ withDefaults(defineProps<Props>(), {
|
||||
|
||||
const { authPanelCenter, authPanelLeft, authPanelRight, isDark } =
|
||||
usePreferences();
|
||||
|
||||
/**
|
||||
* @zh_CN 根据主题选择合适的 logo 图标
|
||||
*/
|
||||
const logoSrc = computed(() => {
|
||||
// 如果是暗色主题且提供了 logoDark,则使用暗色主题的 logo
|
||||
if (isDark.value && props.logoDark) {
|
||||
return props.logoDark;
|
||||
}
|
||||
// 否则使用默认的 logo
|
||||
return props.logo;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -65,14 +81,21 @@ const { authPanelCenter, authPanelLeft, authPanelRight, isDark } =
|
||||
<slot name="logo">
|
||||
<!-- 头部 Logo 和应用名称 -->
|
||||
<div
|
||||
v-if="logo || appName"
|
||||
v-if="logoSrc || appName"
|
||||
class="absolute left-0 top-0 z-10 flex flex-1"
|
||||
@click="clickLogo"
|
||||
>
|
||||
<div
|
||||
class="text-foreground lg:text-foreground ml-4 mt-4 flex flex-1 items-center sm:left-6 sm:top-6"
|
||||
>
|
||||
<img v-if="logo" :alt="appName" :src="logo" class="mr-2" width="42" />
|
||||
<img
|
||||
v-if="logoSrc"
|
||||
:key="logoSrc"
|
||||
:alt="appName"
|
||||
:src="logoSrc"
|
||||
class="mr-2"
|
||||
width="42"
|
||||
/>
|
||||
<p v-if="appName" class="m-0 text-xl font-medium">
|
||||
{{ appName }}
|
||||
</p>
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
LanguageToggle,
|
||||
PreferencesButton,
|
||||
ThemeToggle,
|
||||
TimezoneButton,
|
||||
} from '../../widgets';
|
||||
|
||||
interface Props {
|
||||
@@ -66,15 +67,21 @@ const rightSlots = computed(() => {
|
||||
name: 'language-toggle',
|
||||
});
|
||||
}
|
||||
if (preferences.widget.fullscreen) {
|
||||
if (preferences.widget.timezone) {
|
||||
list.push({
|
||||
index: REFERENCE_VALUE + 40,
|
||||
name: 'timezone',
|
||||
});
|
||||
}
|
||||
if (preferences.widget.fullscreen) {
|
||||
list.push({
|
||||
index: REFERENCE_VALUE + 50,
|
||||
name: 'fullscreen',
|
||||
});
|
||||
}
|
||||
if (preferences.widget.notification) {
|
||||
list.push({
|
||||
index: REFERENCE_VALUE + 50,
|
||||
index: REFERENCE_VALUE + 60,
|
||||
name: 'notification',
|
||||
});
|
||||
}
|
||||
@@ -166,6 +173,9 @@ function clearPreferencesAndLogout() {
|
||||
<template v-else-if="slot.name === 'fullscreen'">
|
||||
<VbenFullScreen class="mr-1" />
|
||||
</template>
|
||||
<template v-else-if="slot.name === 'timezone'">
|
||||
<TimezoneButton class="mr-1 mt-[2px]" />
|
||||
</template>
|
||||
</slot>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@@ -259,6 +259,7 @@ const headerSlots = computed(() => {
|
||||
:class="logoClass"
|
||||
:collapsed="logoCollapsed"
|
||||
:src="preferences.logo.source"
|
||||
:src-dark="preferences.logo.sourceDark"
|
||||
:text="preferences.app.name"
|
||||
:theme="showHeaderNav ? headerTheme : theme"
|
||||
@click="clickLogo"
|
||||
@@ -302,6 +303,9 @@ const headerSlots = computed(() => {
|
||||
<template #notification>
|
||||
<slot name="notification"></slot>
|
||||
</template>
|
||||
<template #timezone>
|
||||
<slot name="timezone"></slot>
|
||||
</template>
|
||||
<template v-for="item in headerSlots" #[item]>
|
||||
<slot :name="item"></slot>
|
||||
</template>
|
||||
@@ -347,6 +351,8 @@ const headerSlots = computed(() => {
|
||||
<VbenLogo
|
||||
v-if="preferences.logo.enable"
|
||||
:fit="preferences.logo.fit"
|
||||
:src="preferences.logo.source"
|
||||
:src-dark="preferences.logo.sourceDark"
|
||||
:text="preferences.app.name"
|
||||
:theme="theme"
|
||||
>
|
||||
|
||||
@@ -8,4 +8,5 @@ export * from './lock-screen';
|
||||
export * from './notification';
|
||||
export * from './preferences';
|
||||
export * from './theme-toggle';
|
||||
export * from './timezone';
|
||||
export * from './user-dropdown';
|
||||
|
||||
@@ -50,6 +50,6 @@ function handleClick() {
|
||||
<span v-if="$slots.shortcut" class="ml-auto mr-2 text-xs opacity-60">
|
||||
<slot name="shortcut"></slot>
|
||||
</span>
|
||||
<Switch v-model:checked="checked" @click.stop />
|
||||
<Switch v-model="checked" @click.stop />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
1
packages/effects/layouts/src/widgets/timezone/index.ts
Normal file
1
packages/effects/layouts/src/widgets/timezone/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as TimezoneButton } from './timezone-button.vue';
|
||||
@@ -0,0 +1,87 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, unref } from 'vue';
|
||||
|
||||
import { createIconifyIcon } from '@vben/icons';
|
||||
import { $t } from '@vben/locales';
|
||||
import { useTimezoneStore } from '@vben/stores';
|
||||
|
||||
import { useVbenModal } from '@vben-core/popup-ui';
|
||||
import {
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
VbenIconButton,
|
||||
} from '@vben-core/shadcn-ui';
|
||||
|
||||
const TimezoneIcon = createIconifyIcon('fluent-mdl2:world-clock');
|
||||
|
||||
const timezoneStore = useTimezoneStore();
|
||||
|
||||
const timezoneRef = ref<string | undefined>();
|
||||
|
||||
const timezoneOptionsRef = ref<
|
||||
{
|
||||
label: string;
|
||||
value: string;
|
||||
}[]
|
||||
>([]);
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
fullscreenButton: false,
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
modalApi.setState({ confirmLoading: true });
|
||||
const timezone = unref(timezoneRef);
|
||||
if (timezone) {
|
||||
await timezoneStore.setTimezone(timezone);
|
||||
}
|
||||
modalApi.close();
|
||||
} finally {
|
||||
modalApi.setState({ confirmLoading: false });
|
||||
}
|
||||
},
|
||||
async onOpenChange(isOpen) {
|
||||
if (isOpen) {
|
||||
timezoneRef.value = unref(timezoneStore.timezone);
|
||||
timezoneOptionsRef.value = await timezoneStore.getTimezoneOptions();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const handleClick = () => {
|
||||
modalApi.open();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VbenIconButton
|
||||
:tooltip="$t('ui.widgets.timezone.setTimezone')"
|
||||
class="hover:animate-[shrink_0.3s_ease-in-out]"
|
||||
@click="handleClick"
|
||||
>
|
||||
<TimezoneIcon class="text-foreground size-4" />
|
||||
</VbenIconButton>
|
||||
<Modal :title="$t('ui.widgets.timezone.setTimezone')">
|
||||
<div class="timezone-container">
|
||||
<RadioGroup v-model="timezoneRef" class="flex flex-col gap-2">
|
||||
<div
|
||||
class="flex cursor-pointer items-center gap-2"
|
||||
v-for="item in timezoneOptionsRef"
|
||||
:key="`container${item.value}`"
|
||||
>
|
||||
<RadioGroupItem :id="item.value" :value="item.value" />
|
||||
<label :for="item.value" class="cursor-pointer">{{
|
||||
item.label
|
||||
}}</label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.timezone-container {
|
||||
padding-left: 20px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user