-
![]()
+
{{ appName }}
@@ -86,7 +109,14 @@ const { authPanelCenter, authPanelLeft, authPanelRight, isDark } =
class="bg-background-deep absolute inset-0 h-full w-full dark:bg-[#070709]"
>
-
+
![]()
@@ -125,7 +156,8 @@ const { authPanelCenter, authPanelLeft, authPanelRight, isDark } =
diff --git a/packages/effects/layouts/src/authentication/form.vue b/packages/effects/layouts/src/authentication/form.vue
index 80c907493bd..fa73e128e0c 100644
--- a/packages/effects/layouts/src/authentication/form.vue
+++ b/packages/effects/layouts/src/authentication/form.vue
@@ -2,6 +2,10 @@
defineOptions({
name: 'AuthenticationFormView',
});
+
+defineProps<{
+ dataSide?: 'bottom' | 'left' | 'right' | 'top';
+}>();
@@ -16,7 +20,8 @@ defineOptions({
diff --git a/packages/effects/layouts/src/basic/header/header.vue b/packages/effects/layouts/src/basic/header/header.vue
index 7a8cc857a01..26c92a6462d 100644
--- a/packages/effects/layouts/src/basic/header/header.vue
+++ b/packages/effects/layouts/src/basic/header/header.vue
@@ -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() {
+
+
+
diff --git a/packages/effects/layouts/src/basic/layout.vue b/packages/effects/layouts/src/basic/layout.vue
index 2dd7d2f8212..605f3cf529a 100644
--- a/packages/effects/layouts/src/basic/layout.vue
+++ b/packages/effects/layouts/src/basic/layout.vue
@@ -158,7 +158,9 @@ function clickLogo() {
function autoCollapseMenuByRouteMeta(route: RouteLocationNormalizedLoaded) {
// 只在双列模式下生效
if (
- preferences.app.layout === 'sidebar-mixed-nav' &&
+ ['header-mixed-nav', 'sidebar-mixed-nav'].includes(
+ preferences.app.layout,
+ ) &&
route.meta &&
route.meta.hideInMenu
) {
@@ -257,6 +259,7 @@ const headerSlots = computed(() => {
:class="logoClass"
:collapsed="logoCollapsed"
:src="https://github.com/preferences.logo.source"
+ :src-dark="preferences.logo.sourceDark"
:text="preferences.app.name"
:theme="showHeaderNav ? headerTheme : theme"
@click="clickLogo"
@@ -300,6 +303,9 @@ const headerSlots = computed(() => {
+
+
+
@@ -345,6 +351,8 @@ const headerSlots = computed(() => {
diff --git a/packages/effects/layouts/src/widgets/index.ts b/packages/effects/layouts/src/widgets/index.ts
index f6a4a7ba5b5..0f9e11a976e 100644
--- a/packages/effects/layouts/src/widgets/index.ts
+++ b/packages/effects/layouts/src/widgets/index.ts
@@ -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';
diff --git a/packages/effects/layouts/src/widgets/language-toggle.vue b/packages/effects/layouts/src/widgets/language-toggle.vue
index 728fca04fd0..f92432f9b46 100644
--- a/packages/effects/layouts/src/widgets/language-toggle.vue
+++ b/packages/effects/layouts/src/widgets/language-toggle.vue
@@ -31,7 +31,7 @@ async function handleUpdate(value: string | undefined) {
:model-value="preferences.app.locale"
@update:model-value="handleUpdate"
>
-
+
diff --git a/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue b/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue
index 5121d688c37..908e670601e 100644
--- a/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue
+++ b/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue
@@ -27,29 +27,30 @@ const emit = defineEmits<{
submit: [Recordable];
}>();
-const [Form, { resetForm, validate, getValues }] = useVbenForm(
- reactive({
- commonConfig: {
- hideLabel: true,
- hideRequiredMark: true,
- },
- schema: computed(() => [
- {
- component: 'VbenInputPassword' as const,
- componentProps: {
- placeholder: $t('ui.widgets.lockScreen.placeholder'),
- },
- fieldName: 'lockScreenPassword',
- formFieldProps: { validateOnBlur: false },
- label: $t('authentication.password'),
- rules: z
- .string()
- .min(1, { message: $t('ui.widgets.lockScreen.placeholder') }),
+const [Form, { resetForm, validate, getValues, getFieldComponentRef }] =
+ useVbenForm(
+ reactive({
+ commonConfig: {
+ hideLabel: true,
+ hideRequiredMark: true,
},
- ]),
- showDefaultActions: false,
- }),
-);
+ schema: computed(() => [
+ {
+ component: 'VbenInputPassword' as const,
+ componentProps: {
+ placeholder: $t('ui.widgets.lockScreen.placeholder'),
+ },
+ fieldName: 'lockScreenPassword',
+ formFieldProps: { validateOnBlur: false },
+ label: $t('authentication.password'),
+ rules: z
+ .string()
+ .min(1, { message: $t('ui.widgets.lockScreen.placeholder') }),
+ },
+ ]),
+ showDefaultActions: false,
+ }),
+ );
const [Modal] = useVbenModal({
onConfirm() {
@@ -60,6 +61,13 @@ const [Modal] = useVbenModal({
resetForm();
}
},
+ onOpened() {
+ requestAnimationFrame(() => {
+ getFieldComponentRef('lockScreenPassword')
+ ?.$el?.querySelector('[name="lockScreenPassword"]')
+ ?.focus();
+ });
+ },
});
async function handleSubmit() {
diff --git a/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue b/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue
index 6fb7a54a4e1..3f700334f17 100644
--- a/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue
+++ b/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue
@@ -37,7 +37,7 @@ const date = useDateFormat(now, 'YYYY-MM-DD dddd', { locales: locale.value });
const showUnlockForm = ref(false);
const { lockScreenPassword } = storeToRefs(accessStore);
-const [Form, { form, validate }] = useVbenForm(
+const [Form, { form, validate, getFieldComponentRef }] = useVbenForm(
reactive({
commonConfig: {
hideLabel: true,
@@ -75,6 +75,13 @@ async function handleSubmit() {
function toggleUnlockForm() {
showUnlockForm.value = !showUnlockForm.value;
+ if (showUnlockForm.value) {
+ requestAnimationFrame(() => {
+ getFieldComponentRef('password')
+ ?.$el?.querySelector('[name="password"]')
+ ?.focus();
+ });
+ }
}
useScrollLock();
diff --git a/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue b/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue
index 630882f4ab1..c69cd3aa9f7 100644
--- a/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue
+++ b/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue
@@ -2,6 +2,7 @@
import { SUPPORT_LANGUAGES } from '@vben/constants';
import { $t } from '@vben/locales';
+import InputItem from '../input-item.vue';
import SelectItem from '../select-item.vue';
import SwitchItem from '../switch-item.vue';
@@ -12,6 +13,7 @@ defineOptions({
const appLocale = defineModel('appLocale');
const appDynamicTitle = defineModel('appDynamicTitle');
const appWatermark = defineModel('appWatermark');
+const appWatermarkContent = defineModel('appWatermarkContent');
const appEnableCheckUpdates = defineModel('appEnableCheckUpdates');
@@ -22,9 +24,23 @@ const appEnableCheckUpdates = defineModel('appEnableCheckUpdates');
{{ $t('preferences.dynamicTitle') }}
-
+ {
+ if (!val) appWatermarkContent = '';
+ }
+ "
+ >
{{ $t('preferences.watermark') }}
+
+ {{ $t('preferences.watermarkContent') }}
+
{{ $t('preferences.checkUpdates') }}
diff --git a/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue b/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue
index 2bf8660c23d..8e9f09e7a34 100644
--- a/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue
+++ b/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue
@@ -3,7 +3,7 @@ import type { SelectOption } from '@vben/types';
import { useSlots } from 'vue';
-import { CircleHelp } from '@vben/icons';
+import { CircleHelp, CircleX } from '@vben/icons';
import { Input, VbenTooltip } from '@vben-core/shadcn-ui';
@@ -47,6 +47,17 @@ const slots = useSlots();
-
+
+
+ (inputValue = '')"
+ />
+
diff --git a/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue b/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue
index 27dfd28aedf..d0dba8ecce3 100644
--- a/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue
+++ b/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue
@@ -104,7 +104,7 @@ function selectColor() {
watch(
() => [modelValue.value, props.isDark] as [BuiltinThemeType, boolean],
- ([themeType, isDark]) => {
+ ([themeType, isDark], [_, isDarkPrev]) => {
const theme = builtinThemePresets.value.find(
(item) => item.type === themeType,
);
@@ -113,7 +113,9 @@ watch(
? theme.darkPrimaryColor || theme.primaryColor
: theme.primaryColor;
- themeColorPrimary.value = primaryColor || theme.color;
+ if (!(theme.type === 'custom' && isDark !== isDarkPrev)) {
+ themeColorPrimary.value = primaryColor || theme.color;
+ }
}
},
);
@@ -132,14 +134,14 @@ watch(