feat: tabs adds a variety of style configurations
							parent
							
								
									ebf73b2df9
								
							
						
					
					
						commit
						3a91a24e0d
					
				|  | @ -69,10 +69,12 @@ const defaultPreferences: Preferences = { | |||
|     width: 240, | ||||
|   }, | ||||
|   tabbar: { | ||||
|     dragable: true, | ||||
|     enable: true, | ||||
|     keepAlive: true, | ||||
|     persist: true, | ||||
|     showIcon: true, | ||||
|     styleType: 'chrome', | ||||
|   }, | ||||
|   theme: { | ||||
|     builtinType: 'default', | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ import type { | |||
|   NavigationStyleType, | ||||
|   PageTransitionType, | ||||
|   SupportedLanguagesType, | ||||
|   TabsStyleType, | ||||
|   ThemeModeType, | ||||
| } from '@vben-core/typings'; | ||||
| 
 | ||||
|  | @ -135,6 +136,8 @@ interface ShortcutKeyPreferences { | |||
| } | ||||
| 
 | ||||
| interface TabbarPreferences { | ||||
|   /** 是否开启多标签页拖拽 */ | ||||
|   dragable: boolean; | ||||
|   /** 是否开启多标签页 */ | ||||
|   enable: boolean; | ||||
|   /** 开启标签页缓存功能 */ | ||||
|  | @ -143,6 +146,8 @@ interface TabbarPreferences { | |||
|   persist: boolean; | ||||
|   /** 是否开启多标签页图标 */ | ||||
|   showIcon: boolean; | ||||
|   /** 标签页风格 */ | ||||
|   styleType: TabsStyleType; | ||||
| } | ||||
| 
 | ||||
| interface ThemePreferences { | ||||
|  |  | |||
|  | @ -176,6 +176,14 @@ | |||
|       "enable": "Enable Tab Bar", | ||||
|       "icon": "Show Tabbar Icon", | ||||
|       "persist": "Persist Tabs", | ||||
|       "dragable": "Enable Dragable Sort", | ||||
|       "styleType": { | ||||
|         "title": "Tabs Style", | ||||
|         "chrome": "Chrome", | ||||
|         "card": "Card", | ||||
|         "plain": "Plain", | ||||
|         "brisk": "Brisk" | ||||
|       }, | ||||
|       "contextMenu": { | ||||
|         "reload": "Reload", | ||||
|         "close": "Close", | ||||
|  |  | |||
|  | @ -176,6 +176,14 @@ | |||
|       "enable": "启用标签栏", | ||||
|       "icon": "显示标签栏图标", | ||||
|       "persist": "持久化标签页", | ||||
|       "dragable": "启动拖拽排序", | ||||
|       "styleType": { | ||||
|         "title": "标签页风格", | ||||
|         "chrome": "谷歌", | ||||
|         "card": "卡片", | ||||
|         "plain": "朴素", | ||||
|         "brisk": "轻快" | ||||
|       }, | ||||
|       "contextMenu": { | ||||
|         "reload": "重新加载", | ||||
|         "close": "关闭", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| import type { SortableOptions } from 'sortablejs'; | ||||
| import type Sortable from 'sortablejs'; | ||||
| 
 | ||||
| function useSortable<T extends HTMLElement>( | ||||
|   sortableContainer: T, | ||||
|  | @ -22,7 +23,7 @@ function useSortable<T extends HTMLElement>( | |||
|       delayOnTouchOnly: true, | ||||
|       ...options, | ||||
|     }); | ||||
|     return sortable; | ||||
|     return sortable as Sortable; | ||||
|   }; | ||||
| 
 | ||||
|   return { | ||||
|  | @ -31,3 +32,5 @@ function useSortable<T extends HTMLElement>( | |||
| } | ||||
| 
 | ||||
| export { useSortable }; | ||||
| 
 | ||||
| export type { Sortable }; | ||||
|  |  | |||
|  | @ -44,6 +44,8 @@ type AccessModeType = 'allow-all' | 'backend' | 'frontend'; | |||
| 
 | ||||
| type NavigationStyleType = 'plain' | 'rounded'; | ||||
| 
 | ||||
| type TabsStyleType = 'brisk' | 'card' | 'chrome' | 'plain'; | ||||
| 
 | ||||
| type PageTransitionType = 'fade' | 'fade-down' | 'fade-slide' | 'fade-up'; | ||||
| 
 | ||||
| type AuthPageLayoutType = 'panel-center' | 'panel-left' | 'panel-right'; | ||||
|  | @ -60,5 +62,6 @@ export type { | |||
|   NavigationStyleType, | ||||
|   PageTransitionType, | ||||
|   SupportedLanguagesType, | ||||
|   TabsStyleType, | ||||
|   ThemeModeType, | ||||
| }; | ||||
|  |  | |||
|  | @ -267,7 +267,7 @@ function handleMouseleave() { | |||
|     <div v-if="slots.logo" :style="headerStyle"> | ||||
|       <slot name="logo"></slot> | ||||
|     </div> | ||||
|     <VbenScrollbar :style="contentStyle"> | ||||
|     <VbenScrollbar :style="contentStyle" shadow> | ||||
|       <slot></slot> | ||||
|     </VbenScrollbar> | ||||
| 
 | ||||
|  | @ -297,7 +297,7 @@ function handleMouseleave() { | |||
|       <div v-if="!extraCollapse" :style="extraTitleStyle"> | ||||
|         <slot name="extra-title"></slot> | ||||
|       </div> | ||||
|       <VbenScrollbar :style="extraContentStyle" class="py-4"> | ||||
|       <VbenScrollbar :style="extraContentStyle" class="py-4" shadow> | ||||
|         <slot name="extra"></slot> | ||||
|       </VbenScrollbar> | ||||
|     </div> | ||||
|  |  | |||
|  | @ -39,8 +39,5 @@ const style = computed((): CSSProperties => { | |||
| <template> | ||||
|   <section :style="style" class="border-border flex w-full"> | ||||
|     <slot></slot> | ||||
|     <div class="flex items-center"> | ||||
|       <slot name="toolbar"></slot> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  |  | |||
|  | @ -2,15 +2,22 @@ | |||
| import type { HTMLAttributes } from 'vue'; | ||||
| import { ref } from 'vue'; | ||||
| 
 | ||||
| import { ScrollArea } from '@vben-core/shadcn-ui/components/ui/scroll-area'; | ||||
| import { | ||||
|   ScrollArea, | ||||
|   ScrollBar, | ||||
| } from '@vben-core/shadcn-ui/components/ui/scroll-area'; | ||||
| import { cn } from '@vben-core/toolkit'; | ||||
| 
 | ||||
| interface Props { | ||||
|   class?: HTMLAttributes['class']; | ||||
|   horizontal?: boolean; | ||||
|   shadow?: boolean; | ||||
| } | ||||
| 
 | ||||
| const props = withDefaults(defineProps<Props>(), { | ||||
|   class: '', | ||||
|   horizontal: false, | ||||
|   shadow: false, | ||||
| }); | ||||
| 
 | ||||
| const isAtTop = ref(true); | ||||
|  | @ -33,6 +40,7 @@ function handleScroll(event: Event) { | |||
|     class="relative" | ||||
|   > | ||||
|     <div | ||||
|       v-if="shadow" | ||||
|       :class="{ | ||||
|         'opacity-100': !isAtTop, | ||||
|       }" | ||||
|  | @ -40,11 +48,13 @@ function handleScroll(event: Event) { | |||
|     ></div> | ||||
|     <slot></slot> | ||||
|     <div | ||||
|       v-if="shadow" | ||||
|       :class="{ | ||||
|         'opacity-100': !isAtTop && !isAtBottom, | ||||
|       }" | ||||
|       class="scrollbar-bottom-shadow pointer-events-none absolute bottom-0 z-10 h-16 w-full opacity-0 transition-opacity duration-1000 ease-in-out will-change-[opacity]" | ||||
|     ></div> | ||||
|     <ScrollBar v-if="horizontal" orientation="horizontal" /> | ||||
|   </ScrollArea> | ||||
| </template> | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,13 +5,13 @@ import type { TabConfig, TabsProps } from '../../types'; | |||
| 
 | ||||
| import { computed, nextTick, onMounted, ref, watch } from 'vue'; | ||||
| 
 | ||||
| import { MdiPin } from '@vben-core/iconify'; | ||||
| import { IcRoundClose, MdiPin } from '@vben-core/iconify'; | ||||
| import { VbenContextMenu, VbenIcon } from '@vben-core/shadcn-ui'; | ||||
| 
 | ||||
| interface Props extends TabsProps {} | ||||
| 
 | ||||
| defineOptions({ | ||||
|   name: 'TabsChrome', | ||||
|   name: 'VbenTabsChrome', | ||||
|   // eslint-disable-next-line perfectionist/sort-objects | ||||
|   inheritAttrs: false, | ||||
| }); | ||||
|  | @ -94,7 +94,10 @@ function handleUnpinTab(tab: TabConfig) { | |||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <div :style="style" class="tabs-chrome bg-accent size-full pt-1"> | ||||
|   <div | ||||
|     :style="style" | ||||
|     class="tabs-chrome bg-accent size-full flex-1 overflow-hidden pt-1" | ||||
|   > | ||||
|     <!-- footer -> 4px --> | ||||
|     <div | ||||
|       ref="contentRef" | ||||
|  | @ -157,16 +160,11 @@ function handleUnpinTab(tab: TabConfig) { | |||
|                 class="tabs-chrome__extra absolute right-[calc(var(--gap)*2)] top-1/2 z-[3] size-4 translate-y-[-50%] opacity-0 transition-opacity group-hover:opacity-100" | ||||
|               > | ||||
|                 <!-- close-icon --> | ||||
|                 <svg | ||||
|                 <IcRoundClose | ||||
|                   v-show="!tab.affixTab && tabsView.length > 1 && tab.closable" | ||||
|                   class="hover:bg-accent hover:stroke-accent-foreground size-full cursor-pointer rounded-full transition-all" | ||||
|                   height="12" | ||||
|                   stroke="#595959" | ||||
|                   width="12" | ||||
|                   class="hover:bg-accent stroke-accent-foreground/80 hover:stroke-accent-foreground mt-[2px] size-3 cursor-pointer rounded-full transition-all" | ||||
|                   @click.stop="handleClose(tab.key)" | ||||
|                 > | ||||
|                   <path d="M 4 4 L 12 12 M 12 4 L 4 12" /> | ||||
|                 </svg> | ||||
|                 /> | ||||
|                 <MdiPin | ||||
|                   v-show="tab.affixTab && tabsView.length > 1 && tab.closable" | ||||
|                   class="hover:bg-accent hover:stroke-accent-foreground mt-[2px] size-3.5 cursor-pointer rounded-full transition-all" | ||||
|  | @ -186,7 +184,7 @@ function handleUnpinTab(tab: TabConfig) { | |||
|                 /> | ||||
| 
 | ||||
|                 <span | ||||
|                   class="tabs-chrome__label ml-[var(--gap)] flex-1 overflow-hidden whitespace-nowrap" | ||||
|                   class="tabs-chrome__label text-accent-foreground ml-[var(--gap)] flex-1 overflow-hidden whitespace-nowrap" | ||||
|                 > | ||||
|                   {{ tab.title }} | ||||
|                 </span> | ||||
|  |  | |||
|  | @ -1,11 +1,141 @@ | |||
| <script lang="ts" setup> | ||||
| import { VbenScrollbar } from '@vben-core/shadcn-ui'; | ||||
| import type { TabConfig, TabsProps } from '../../types'; | ||||
| 
 | ||||
| import { computed } from 'vue'; | ||||
| 
 | ||||
| import { IcRoundClose, MdiPin } from '@vben-core/iconify'; | ||||
| import { VbenContextMenu, VbenIcon, VbenScrollbar } from '@vben-core/shadcn-ui'; | ||||
| import { TabDefinition } from '@vben-core/typings'; | ||||
| 
 | ||||
| interface Props extends TabsProps {} | ||||
| 
 | ||||
| defineOptions({ | ||||
|   name: 'VbenTabs', | ||||
|   // eslint-disable-next-line perfectionist/sort-objects | ||||
|   inheritAttrs: false, | ||||
| }); | ||||
| const props = withDefaults(defineProps<Props>(), { | ||||
|   contentClass: 'vben-tabs-content', | ||||
|   contextMenus: () => [], | ||||
|   tabs: () => [], | ||||
| }); | ||||
| 
 | ||||
| const emit = defineEmits<{ close: [string]; unpin: [TabDefinition] }>(); | ||||
| const active = defineModel<string>('active'); | ||||
| 
 | ||||
| const typeWithClass = computed(() => { | ||||
|   const typeClasses: Record<string, { content: string }> = { | ||||
|     brisk: { | ||||
|       content: `h-full  after:content-['']  after:absolute after:bottom-0 after:left-0 after:w-full after:h-[1.5px] after:bg-primary after:scale-x-0 after:transition-[transform] after:ease-out after:duration-300 hover:after:scale-x-100 after:origin-left [&.is-active]:after:scale-x-100`, | ||||
|     }, | ||||
|     card: { | ||||
|       content: 'h-[90%] rounded-md mr-1', | ||||
|     }, | ||||
|     plain: { | ||||
|       content: 'h-full', | ||||
|     }, | ||||
|   }; | ||||
| 
 | ||||
|   return typeClasses[props.styleType || 'plain']; | ||||
| }); | ||||
| 
 | ||||
| const tabsView = computed((): TabConfig[] => { | ||||
|   return props.tabs.map((tab) => { | ||||
|     return { | ||||
|       ...tab, | ||||
|       affixTab: !!tab.meta?.affixTab, | ||||
|       closable: Reflect.has(tab.meta, 'tabClosable') | ||||
|         ? !!tab.meta.tabClosable | ||||
|         : true, | ||||
|       icon: tab.meta.icon as string, | ||||
|       key: tab.fullPath || tab.path, | ||||
|       title: (tab.meta?.title || tab.name) as string, | ||||
|     }; | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| function handleClose(key: string) { | ||||
|   emit('close', key); | ||||
| } | ||||
| 
 | ||||
| function handleUnpinTab(tab: TabConfig) { | ||||
|   emit('unpin', tab); | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <div class="bg-accent size-full"> | ||||
|     <VbenScrollbar> | ||||
|       <slot></slot> | ||||
|   <div class="bg-accent h-full flex-1 overflow-hidden"> | ||||
|     <VbenScrollbar class="h-full" horizontal> | ||||
|       <div | ||||
|         :class="contentClass" | ||||
|         class="relative !flex h-full w-max items-center" | ||||
|       > | ||||
|         <TransitionGroup name="slide-down"> | ||||
|           <div | ||||
|             v-for="(tab, i) in tabsView" | ||||
|             :key="tab.key" | ||||
|             :class="[ | ||||
|               { | ||||
|                 'is-active bg-background': tab.key === active, | ||||
|                 dragable: !tab.affixTab, | ||||
|               }, | ||||
|               typeWithClass.content, | ||||
|             ]" | ||||
|             :data-index="i" | ||||
|             class="[&:not(.is-active)]:hover:bg-accent group relative flex cursor-pointer select-none transition-all duration-300" | ||||
|             @click="active = tab.key" | ||||
|           > | ||||
|             <VbenContextMenu | ||||
|               :handler-data="tab" | ||||
|               :menus="contextMenus" | ||||
|               :modal="false" | ||||
|               item-class="pr-6" | ||||
|             > | ||||
|               <div class="relative flex size-full items-center"> | ||||
|                 <!-- extra --> | ||||
|                 <div | ||||
|                   class="absolute right-1.5 top-1/2 z-[3] translate-y-[-50%] overflow-hidden opacity-0 transition-opacity group-hover:opacity-100 group-[.is-active]:opacity-100" | ||||
|                 > | ||||
|                   <!-- close-icon --> | ||||
|                   <IcRoundClose | ||||
|                     v-show=" | ||||
|                       !tab.affixTab && tabsView.length > 1 && tab.closable | ||||
|                     " | ||||
|                     class="hover:bg-accent stroke-accent-foreground/80 hover:stroke-accent-foreground size-3 cursor-pointer rounded-full transition-all" | ||||
|                     @click.stop="handleClose(tab.key)" | ||||
|                   /> | ||||
|                   <MdiPin | ||||
|                     v-show="tab.affixTab && tabsView.length > 1 && tab.closable" | ||||
|                     class="hover:bg-accent hover:stroke-accent-foreground mt-[2px] size-3.5 cursor-pointer rounded-full transition-all" | ||||
|                     @click.stop="handleUnpinTab(tab)" | ||||
|                   /> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <!-- tab-item-main --> | ||||
|                 <div | ||||
|                   class="mx-3 mr-3 flex h-full items-center overflow-hidden rounded-tl-[5px] rounded-tr-[5px] pr-3 transition-all duration-300" | ||||
|                 > | ||||
|                   <!-- <div | ||||
|                   class="mx-3 ml-3 mr-2 flex h-full items-center overflow-hidden rounded-tl-[5px] rounded-tr-[5px] transition-all duration-300 group-hover:mr-2 group-hover:pr-4 group-[.is-active]:pr-4" | ||||
|                 > --> | ||||
|                   <VbenIcon | ||||
|                     v-if="showIcon" | ||||
|                     :icon="tab.icon" | ||||
|                     class="mr-2 flex size-4 items-center overflow-hidden" | ||||
|                     fallback | ||||
|                   /> | ||||
| 
 | ||||
|                   <span | ||||
|                     class="text-accent-foreground flex-1 overflow-hidden whitespace-nowrap" | ||||
|                   > | ||||
|                     {{ tab.title }} | ||||
|                   </span> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </VbenContextMenu> | ||||
|           </div> | ||||
|         </TransitionGroup> | ||||
|       </div> | ||||
|     </VbenScrollbar> | ||||
|   </div> | ||||
| </template> | ||||
|  |  | |||
|  | @ -1,11 +1,12 @@ | |||
| <script setup lang="ts"> | ||||
| import type { Sortable } from '@vben-core/hooks'; | ||||
| import type { TabDefinition } from '@vben-core/typings'; | ||||
| 
 | ||||
| import { nextTick, onMounted } from 'vue'; | ||||
| import { nextTick, onMounted, onUnmounted, ref } from 'vue'; | ||||
| 
 | ||||
| import { useForwardPropsEmits, useSortable } from '@vben-core/hooks'; | ||||
| 
 | ||||
| import { TabsChrome } from './components'; | ||||
| import { Tabs, TabsChrome } from './components'; | ||||
| import { TabsProps } from './types'; | ||||
| 
 | ||||
| interface Props extends TabsProps {} | ||||
|  | @ -17,6 +18,7 @@ defineOptions({ | |||
| const props = withDefaults(defineProps<Props>(), { | ||||
|   contentClass: 'vben-tabs-content', | ||||
|   dragable: true, | ||||
|   styleType: 'chrome', | ||||
| }); | ||||
| 
 | ||||
| const emit = defineEmits<{ | ||||
|  | @ -27,13 +29,15 @@ const emit = defineEmits<{ | |||
| 
 | ||||
| const forward = useForwardPropsEmits(props, emit); | ||||
| 
 | ||||
| const sortableInstance = ref<Sortable | null>(null); | ||||
| 
 | ||||
| // 可能会找到拖拽的子元素,这里需要确保拖拽的dom时tab元素 | ||||
| const findParentElement = (element: HTMLElement) => { | ||||
| function findParentElement(element: HTMLElement) { | ||||
|   const parentCls = 'group'; | ||||
|   return element.classList.contains(parentCls) | ||||
|     ? element | ||||
|     : element.closest(`.${parentCls}`); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| async function initTabsSortable() { | ||||
|   await nextTick(); | ||||
|  | @ -80,7 +84,7 @@ async function initTabsSortable() { | |||
|     }, | ||||
|     onMove(evt) { | ||||
|       const parent = findParentElement(evt.related); | ||||
|       return parent?.classList.contains('dragable'); | ||||
|       return parent?.classList.contains('dragable') && props.dragable; | ||||
|     }, | ||||
|     onStart: () => { | ||||
|       el.style.cursor = 'grabbing'; | ||||
|  | @ -88,12 +92,17 @@ async function initTabsSortable() { | |||
|     }, | ||||
|   }); | ||||
| 
 | ||||
|   await initializeSortable(); | ||||
|   sortableInstance.value = await initializeSortable(); | ||||
| } | ||||
| 
 | ||||
| onMounted(initTabsSortable); | ||||
| 
 | ||||
| onUnmounted(() => { | ||||
|   sortableInstance.value?.destroy(); | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <TabsChrome v-bind="forward" /> | ||||
|   <TabsChrome v-if="styleType === 'chrome'" v-bind="forward" /> | ||||
|   <Tabs v-else v-bind="forward" /> | ||||
| </template> | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| import type { IContextMenuItem } from '@vben-core/shadcn-ui'; | ||||
| import type { TabDefinition } from '@vben-core/typings'; | ||||
| import type { TabDefinition, TabsStyleType } from '@vben-core/typings'; | ||||
| 
 | ||||
| interface TabsProps { | ||||
|   /** | ||||
|  | @ -21,7 +21,6 @@ interface TabsProps { | |||
|    * 仅限 tabs-chrome | ||||
|    */ | ||||
|   gap?: number; | ||||
| 
 | ||||
|   /** | ||||
|    * @zh_CN tab 最大宽度 | ||||
|    * 仅限 tabs-chrome | ||||
|  | @ -33,10 +32,15 @@ interface TabsProps { | |||
|    * 仅限 tabs-chrome | ||||
|    */ | ||||
|   minWidth?: number; | ||||
| 
 | ||||
|   /** | ||||
|    * @zh_CN 是否显示图标 | ||||
|    */ | ||||
|   showIcon?: boolean; | ||||
|   /** | ||||
|    * @zh_CN 标签页风格 | ||||
|    */ | ||||
|   styleType?: TabsStyleType; | ||||
| 
 | ||||
|   /** | ||||
|    * @zh_CN 选项卡数据 | ||||
|  |  | |||
|  | @ -41,7 +41,9 @@ if (!preferences.tabbar.persist) { | |||
|   <TabsView | ||||
|     :active="currentActive" | ||||
|     :context-menus="createContextMenus" | ||||
|     :dragable="preferences.tabbar.dragable" | ||||
|     :show-icon="showIcon" | ||||
|     :style-type="preferences.tabbar.styleType" | ||||
|     :tabs="currentTabs" | ||||
|     @close="handleClose" | ||||
|     @sort-tabs="coreTabbarStore.sortTabs" | ||||
|  |  | |||
|  | @ -1,6 +1,10 @@ | |||
| <script setup lang="ts"> | ||||
| import { $t } from '@vben-core/locales'; | ||||
| import { computed } from 'vue'; | ||||
| 
 | ||||
| import { $t } from '@vben-core/locales'; | ||||
| import { SelectOption } from '@vben-core/typings'; | ||||
| 
 | ||||
| import SelectItem from '../select-item.vue'; | ||||
| import SwitchItem from '../switch-item.vue'; | ||||
| 
 | ||||
| defineOptions({ | ||||
|  | @ -12,6 +16,28 @@ defineProps<{ disabled?: boolean }>(); | |||
| const tabbarEnable = defineModel<boolean>('tabbarEnable'); | ||||
| const tabbarShowIcon = defineModel<boolean>('tabbarShowIcon'); | ||||
| const tabbarPersist = defineModel<boolean>('tabbarPersist'); | ||||
| const tabbarDragable = defineModel<boolean>('tabbarDragable'); | ||||
| const tabbarStyleType = defineModel<string>('tabbarStyleType'); | ||||
| 
 | ||||
| const styleItems = computed((): SelectOption[] => [ | ||||
|   { | ||||
|     label: $t('preferences.tabbar.styleType.chrome'), | ||||
|     value: 'chrome', | ||||
|   }, | ||||
|   { | ||||
|     label: $t('preferences.tabbar.styleType.plain'), | ||||
|     value: 'plain', | ||||
|   }, | ||||
|   { | ||||
|     label: $t('preferences.tabbar.styleType.card'), | ||||
|     value: 'card', | ||||
|   }, | ||||
| 
 | ||||
|   { | ||||
|     label: $t('preferences.tabbar.styleType.brisk'), | ||||
|     value: 'brisk', | ||||
|   }, | ||||
| ]); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|  | @ -24,4 +50,10 @@ const tabbarPersist = defineModel<boolean>('tabbarPersist'); | |||
|   <SwitchItem v-model="tabbarPersist" :disabled="!tabbarEnable"> | ||||
|     {{ $t('preferences.tabbar.persist') }} | ||||
|   </SwitchItem> | ||||
|   <SwitchItem v-model="tabbarDragable" :disabled="!tabbarEnable"> | ||||
|     {{ $t('preferences.tabbar.dragable') }} | ||||
|   </SwitchItem> | ||||
|   <SelectItem v-model="tabbarStyleType" :items="styleItems"> | ||||
|     {{ $t('preferences.tabbar.styleType.title') }} | ||||
|   </SelectItem> | ||||
| </template> | ||||
|  |  | |||
|  | @ -95,6 +95,8 @@ const breadcrumbHideOnlyOne = defineModel<boolean>('breadcrumbHideOnlyOne'); | |||
| const tabbarEnable = defineModel<boolean>('tabbarEnable'); | ||||
| const tabbarShowIcon = defineModel<boolean>('tabbarShowIcon'); | ||||
| const tabbarPersist = defineModel<boolean>('tabbarPersist'); | ||||
| const tabbarDragable = defineModel<boolean>('tabbarDragable'); | ||||
| const tabbarStyleType = defineModel<string>('tabbarStyleType'); | ||||
| 
 | ||||
| const navigationStyleType = defineModel<NavigationStyleType>( | ||||
|   'navigationStyleType', | ||||
|  | @ -346,9 +348,11 @@ async function handleReset() { | |||
| 
 | ||||
|             <Block :title="$t('preferences.tabbar.title')"> | ||||
|               <Tabbar | ||||
|                 v-model:tabbar-dragable="tabbarDragable" | ||||
|                 v-model:tabbar-enable="tabbarEnable" | ||||
|                 v-model:tabbar-persist="tabbarPersist" | ||||
|                 v-model:tabbar-show-icon="tabbarShowIcon" | ||||
|                 v-model:tabbar-style-type="tabbarStyleType" | ||||
|               /> | ||||
|             </Block> | ||||
|             <Block :title="$t('preferences.widget.title')"> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 vben
						vben