Merge remote-tracking branch 'Soybean/v2.0' into v2.0

# Conflicts:
#	src/typings/components.d.ts
This commit is contained in:
xlsea
2025-08-14 18:14:31 +08:00
12 changed files with 101 additions and 34 deletions

View File

@ -0,0 +1,42 @@
<script lang="ts" setup>
import { computed, useSlots } from 'vue';
import type { PopoverPlacement } from 'naive-ui';
defineOptions({ name: 'IconTooltip' });
interface Props {
icon?: string;
localIcon?: string;
desc?: string;
placement?: PopoverPlacement;
}
const props = withDefaults(defineProps<Props>(), {
icon: 'mdi-help-circle',
localIcon: '',
desc: '',
placement: 'top'
});
const slots = useSlots();
const hasCustomTrigger = computed(() => Boolean(slots.trigger));
if (!hasCustomTrigger.value && !props.icon && !props.localIcon) {
throw new Error('icon or localIcon is required when no custom trigger slot is provided');
}
</script>
<template>
<NTooltip :placement="placement">
<template #trigger>
<slot name="trigger">
<div class="cursor-pointer">
<SvgIcon :icon="icon" :local-icon="localIcon" />
</div>
</slot>
</template>
<slot>
<span>{{ desc }}</span>
</slot>
</NTooltip>
</template>

View File

@ -38,6 +38,13 @@ export function useNaiveTable<ResponseData, ApiData>(options: UseNaiveTableOptio
getColumns
});
// calculate the total width of the table this is used for horizontal scrolling
const scrollX = computed(() => {
return result.columns.value.reduce((acc, column) => {
return acc + Number(column.width ?? column.minWidth ?? 120);
}, 0);
});
scope.run(() => {
watch(
() => appStore.locale,
@ -51,7 +58,10 @@ export function useNaiveTable<ResponseData, ApiData>(options: UseNaiveTableOptio
scope.stop();
});
return result;
return {
...result,
scrollX
};
}
type PaginationParams = Pick<PaginationProps, 'page' | 'pageSize'>;

View File

@ -30,15 +30,17 @@ const { selectedKey } = useMenu();
/>
</Teleport>
<Teleport :to="`#${GLOBAL_SIDER_MENU_ID}`">
<FirstLevelMenu
:menus="firstLevelMenus"
:active-menu-key="activeFirstLevelMenuKey"
:sider-collapse="appStore.siderCollapse"
:dark-mode="themeStore.darkMode"
:theme-color="themeStore.themeColor"
@select="handleSelectFirstLevelMenu"
@toggle-sider-collapse="appStore.toggleSiderCollapse"
/>
<div class="h-full pt-2">
<FirstLevelMenu
:menus="firstLevelMenus"
:active-menu-key="activeFirstLevelMenuKey"
:sider-collapse="appStore.siderCollapse"
:dark-mode="themeStore.darkMode"
:theme-color="themeStore.themeColor"
@select="handleSelectFirstLevelMenu"
@toggle-sider-collapse="appStore.toggleSiderCollapse"
/>
</div>
</Teleport>
</template>

View File

@ -80,7 +80,7 @@ function handleChangeMode(mode: UnionKey.ThemeLayoutMode) {
class="flex-col-center cursor-pointer"
@click="handleChangeMode(key)"
>
<NTooltip :placement="item.placement">
<IconTooltip :placement="item.placement">
<template #trigger>
<div
class="h-64px w-96px gap-6px rd-4px p-6px shadow ring-2 ring-transparent transition-all hover:ring-primary"
@ -92,7 +92,7 @@ function handleChangeMode(mode: UnionKey.ThemeLayoutMode) {
</div>
</template>
{{ $t(`theme.layout.layoutMode.${key}_detail`) }}
</NTooltip>
</IconTooltip>
<p class="mt-8px text-12px">{{ $t(themeLayoutModeRecord[key]) }}</p>
</div>
</div>

View File

@ -13,7 +13,7 @@ defineProps<Props>();
<template>
<div class="w-full flex-y-center justify-between">
<div>
<div class="flex-y-center">
<span class="pr-8px text-base-text">{{ label }}</span>
<slot name="suffix"></slot>
</div>

View File

@ -36,27 +36,28 @@ const swatches: string[] = [
<template>
<NDivider>{{ $t('theme.appearance.themeColor.title') }}</NDivider>
<div class="flex-col-stretch gap-12px">
<NTooltip placement="top-start">
<template #trigger>
<SettingItem key="recommend-color" :label="$t('theme.appearance.recommendColor')">
<NSwitch v-model:value="themeStore.recommendColor" />
</SettingItem>
<SettingItem key="recommend-color" :label="$t('theme.appearance.recommendColor')">
<template #suffix>
<IconTooltip>
<p>
<span class="pr-12px">{{ $t('theme.appearance.recommendColorDesc') }}</span>
<br />
<NButton
text
tag="a"
href="https://uicolors.app/create"
target="_blank"
rel="noopener noreferrer"
class="text-gray"
>
https://uicolors.app/create
</NButton>
</p>
</IconTooltip>
</template>
<p>
<span class="pr-12px">{{ $t('theme.appearance.recommendColorDesc') }}</span>
<br />
<NButton
text
tag="a"
href="https://uicolors.app/create"
target="_blank"
rel="noopener noreferrer"
class="text-gray"
>
https://uicolors.app/create
</NButton>
</p>
</NTooltip>
<NSwitch v-model:value="themeStore.recommendColor" />
</SettingItem>
<SettingItem
v-for="(_, key) in themeStore.themeColors"
:key="key"

View File

@ -19,6 +19,9 @@ const isWrapperScrollMode = computed(() => themeStore.layout.scrollMode === 'wra
<NDivider>{{ $t('theme.layout.content.title') }}</NDivider>
<TransitionGroup tag="div" name="setting-list" class="flex-col-stretch gap-12px">
<SettingItem key="1" :label="$t('theme.layout.content.scrollMode.title')">
<template #suffix>
<IconTooltip :desc="$t('theme.layout.content.scrollMode.tip')" />
</template>
<NSelect
v-model:value="themeStore.layout.scrollMode"
:options="translateOptions(themeScrollModeOptions)"

View File

@ -27,6 +27,9 @@ const themeStore = useThemeStore();
<NSwitch v-model:value="themeStore.tab.visible" />
</SettingItem>
<SettingItem v-if="themeStore.tab.visible" key="2" :label="$t('theme.layout.tab.cache')">
<template #suffix>
<IconTooltip :desc="$t('theme.layout.tab.cacheTip')" />
</template>
<NSwitch v-model:value="themeStore.tab.cache" />
</SettingItem>
<SettingItem v-if="themeStore.tab.visible" key="3" :label="$t('theme.layout.tab.height')">

View File

@ -133,6 +133,7 @@ const local: App.I18n.Schema = {
title: 'Tab Settings',
visible: 'Tab Visible',
cache: 'Tag Bar Info Cache',
cacheTip: 'One-click to open/close global keepalive',
height: 'Tab Height',
mode: {
title: 'Tab Mode',
@ -168,6 +169,7 @@ const local: App.I18n.Schema = {
title: 'Content Area Settings',
scrollMode: {
title: 'Scroll Mode',
tip: 'The theme scroll only scrolls the main part, the outer scroll can carry the header and footer together',
wrapper: 'Wrapper',
content: 'Content'
},

View File

@ -130,6 +130,7 @@ const local: App.I18n.Schema = {
title: '标签栏设置',
visible: '显示标签栏',
cache: '标签栏信息缓存',
cacheTip: '一键开启/关闭全局 keepalive',
height: '标签栏高度',
mode: {
title: '标签栏风格',
@ -165,6 +166,7 @@ const local: App.I18n.Schema = {
title: '内容区域设置',
scrollMode: {
title: '滚动模式',
tip: '主题滚动仅 main 部分滚动,外层滚动可携带头部底部一起滚动',
wrapper: '外层滚动',
content: '主体滚动'
},

View File

@ -426,6 +426,7 @@ declare namespace App {
title: string;
visible: string;
cache: string;
cacheTip: string;
height: string;
mode: { title: string } & Record<UnionKey.ThemeTabMode, string>;
};
@ -455,7 +456,7 @@ declare namespace App {
};
content: {
title: string;
scrollMode: { title: string } & Record<UnionKey.ThemeScrollMode, string>;
scrollMode: { title: string; tip: string } & Record<UnionKey.ThemeScrollMode, string>;
page: {
animate: string;
mode: { title: string } & Record<UnionKey.ThemePageAnimateMode, string>;

View File

@ -46,6 +46,7 @@ declare module 'vue' {
'IconQuill:collapse': typeof import('~icons/quill/collapse')['default']
'IconQuill:expand': typeof import('~icons/quill/expand')['default']
'IconSimpleIcons:gitee': typeof import('~icons/simple-icons/gitee')['default']
IconTooltip: typeof import('./../components/common/icon-tooltip.vue')['default']
IconUilSearch: typeof import('~icons/uil/search')['default']
JsonPreview: typeof import('./../components/custom/json-preview.vue')['default']
LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']