This commit is contained in:
dap
2025-11-30 01:57:18 +08:00
152 changed files with 632 additions and 273 deletions

View File

@@ -71,17 +71,10 @@ const modelValue = defineModel({ default: '', type: String });
const visible = ref(false);
const currentSelect = ref('');
const currentPage = ref(1);
const keyword = ref('');
const keywordDebounce = refDebounced(keyword, 300);
const innerIcons = ref<string[]>([]);
/* 当检索关键词变化时,重置分页 */
watch(keywordDebounce, () => {
currentPage.value = 1;
setCurrentPage(1);
});
watchDebounced(
() => props.prefix,
async (prefix) => {
@@ -122,7 +115,7 @@ const showList = computed(() => {
);
});
const { paginationList, total, setCurrentPage } = usePagination(
const { paginationList, total, setCurrentPage, currentPage } = usePagination(
showList,
props.pageSize,
);
@@ -145,7 +138,6 @@ const handleClick = (icon: string) => {
};
const handlePageChange = (page: number) => {
currentPage.value = page;
setCurrentPage(page);
};

View File

@@ -55,16 +55,12 @@ function handleClick(event: MouseEvent) {
return;
}
const param: JsonViewerValue = {
path: '',
value: '',
depth: 0,
el: event.target,
path: pathNode.getAttribute('path') || '',
depth: Number(pathNode.getAttribute('depth')) || 0,
value: event.target.textContent || undefined,
};
param.path = pathNode.getAttribute('path') || '';
param.depth = Number(pathNode.getAttribute('depth')) || 0;
param.value = event.target.textContent || undefined;
param.value = JSON.parse(param.value);
emit('valueClick', param);
}

View File

@@ -618,13 +618,11 @@ const stickStyles = computed(() => (stick: string) => {
const stickStyle = {
width: `${stickSize.value / parentScaleX.value}px`,
height: `${stickSize.value / parentScaleY.value}px`,
[styleMapping.y[stick[0] as 'b' | 'm' | 't'] as 'height' | 'width']:
`${stickSize.value / parentScaleX.value / -2}px`,
[styleMapping.x[stick[1] as 'l' | 'm' | 'r'] as 'height' | 'width']:
`${stickSize.value / parentScaleX.value / -2}px`,
};
stickStyle[
styleMapping.y[stick[0] as 'b' | 'm' | 't'] as 'height' | 'width'
] = `${stickSize.value / parentScaleX.value / -2}px`;
stickStyle[
styleMapping.x[stick[1] as 'l' | 'm' | 'r'] as 'height' | 'width'
] = `${stickSize.value / parentScaleX.value / -2}px`;
return stickStyle;
});
@@ -1072,8 +1070,8 @@ watch(
box-sizing: border-box;
width: 100%;
height: 100%;
content: '';
outline: 1px dashed #d6d6d6;
content: '';
}
.resize-stick {

View File

@@ -1,6 +1,6 @@
import type { Ref } from 'vue';
import { computed, ref, unref } from 'vue';
import { computed, ref, unref, watch } from 'vue';
/**
* Paginates an array of items
@@ -22,7 +22,11 @@ function pagination<T = any>(list: T[], pageNo: number, pageSize: number): T[] {
return ret;
}
export function usePagination<T = any>(list: Ref<T[]>, pageSize: number) {
export function usePagination<T = any>(
list: Ref<T[]>,
pageSize: number,
totalChangeToFirstPage = true,
) {
const currentPage = ref(1);
const pageSizeRef = ref(pageSize);
@@ -38,11 +42,21 @@ export function usePagination<T = any>(list: Ref<T[]>, pageSize: number) {
return unref(list).length;
});
if (totalChangeToFirstPage) {
watch(total, () => {
setCurrentPage(1);
});
}
function setCurrentPage(page: number) {
if (page < 1 || page > unref(totalPages)) {
throw new Error('Invalid page number');
if (page === 1 && unref(totalPages) === 0) {
currentPage.value = 1;
} else {
if (page < 1 || page > unref(totalPages)) {
throw new Error('Invalid page number');
}
currentPage.value = page;
}
currentPage.value = page;
}
function setPageSize(pageSize: number) {
@@ -54,5 +68,5 @@ export function usePagination<T = any>(list: Ref<T[]>, pageSize: number) {
currentPage.value = 1;
}
return { setCurrentPage, total, setPageSize, paginationList };
return { setCurrentPage, total, setPageSize, paginationList, currentPage };
}

View File

@@ -92,7 +92,7 @@ const rightSlots = computed(() => {
list.push({ index: Number(name[2]), name: key });
}
});
return list.sort((a, b) => a.index - b.index);
return list.toSorted((a, b) => a.index - b.index);
});
const leftSlots = computed(() => {
@@ -111,7 +111,7 @@ const leftSlots = computed(() => {
list.push({ index: Number(name[2]), name: key });
}
});
return list.sort((a, b) => a.index - b.index);
return list.toSorted((a, b) => a.index - b.index);
});
function clearPreferencesAndLogout() {

View File

@@ -15,5 +15,6 @@ export { default as GlobalShortcutKeys } from './shortcut-keys/global.vue';
export { default as SwitchItem } from './switch-item.vue';
export { default as BuiltinTheme } from './theme/builtin.vue';
export { default as ColorMode } from './theme/color-mode.vue';
export { default as FontSize } from './theme/font-size.vue';
export { default as Radius } from './theme/radius.vue';
export { default as Theme } from './theme/theme.vue';

View File

@@ -0,0 +1,62 @@
<script setup lang="ts">
import { watch } from 'vue';
import { $t } from '@vben/locales';
import {
NumberField,
NumberFieldContent,
NumberFieldDecrement,
NumberFieldIncrement,
NumberFieldInput,
} from '@vben-core/shadcn-ui';
defineOptions({
name: 'PreferenceFontSize',
});
const modelValue = defineModel<number>({
default: 16,
});
const min = 15;
const max = 22;
const step = 1;
// 限制输入值在 min 和 max 之间
watch(
modelValue,
(newValue) => {
if (newValue < min) {
modelValue.value = min;
} else if (newValue > max) {
modelValue.value = max;
}
},
{ immediate: true },
);
</script>
<template>
<div class="flex w-full flex-col gap-4">
<div class="flex items-center gap-2">
<NumberField
v-model="modelValue"
:max="max"
:min="min"
:step="step"
class="w-full"
>
<NumberFieldContent>
<NumberFieldDecrement />
<NumberFieldInput />
<NumberFieldIncrement />
</NumberFieldContent>
</NumberField>
<span class="text-muted-foreground whitespace-nowrap text-xs">px</span>
</div>
<div class="text-muted-foreground text-xs">
{{ $t('preferences.theme.fontSizeTip') }}
</div>
</div>
</template>

View File

@@ -43,6 +43,7 @@ import {
ColorMode,
Content,
Copyright,
FontSize,
Footer,
General,
GlobalShortcutKeys,
@@ -85,6 +86,7 @@ const themeColorPrimary = defineModel<string>('themeColorPrimary');
const themeBuiltinType = defineModel<BuiltinThemeType>('themeBuiltinType');
const themeMode = defineModel<ThemeModeType>('themeMode');
const themeRadius = defineModel<string>('themeRadius');
const themeFontSize = defineModel<number>('themeFontSize');
const themeSemiDarkSidebar = defineModel<boolean>('themeSemiDarkSidebar');
const themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader');
@@ -328,6 +330,9 @@ async function handleReset() {
<Block :title="$t('preferences.theme.radius')">
<Radius v-model="themeRadius" />
</Block>
<Block :title="$t('preferences.theme.fontSize')">
<FontSize v-model="themeFontSize" />
</Block>
<Block :title="$t('preferences.other')">
<ColorMode
v-model:app-color-gray-mode="appColorGrayMode"

View File

@@ -66,7 +66,7 @@ function toggleTheme(event: MouseEvent) {
];
const animate = document.documentElement.animate(
{
clipPath: isDark.value ? [...clipPath].reverse() : clipPath,
clipPath: isDark.value ? [...clipPath].toReversed() : clipPath,
},
{
duration: 450,
@@ -135,8 +135,8 @@ function toggleTheme(event: MouseEvent) {
&__sun {
@apply fill-foreground/90 stroke-none;
transition: transform 1.6s cubic-bezier(0.25, 0, 0.2, 1);
transform-origin: center center;
transition: transform 1.6s cubic-bezier(0.25, 0, 0.2, 1);
&:hover > svg > & {
@apply fill-foreground/90;
@@ -146,10 +146,10 @@ function toggleTheme(event: MouseEvent) {
&__sun-beams {
@apply stroke-foreground/90 stroke-[2px];
transform-origin: center center;
transition:
transform 1.6s cubic-bezier(0.5, 1.5, 0.75, 1.25),
opacity 0.6s cubic-bezier(0.25, 0, 0.3, 1);
transform-origin: center center;
&:hover > svg > & {
@apply stroke-foreground;