feat(ui): 优化移动端响应式布局和交互体验
- 添加移动端侧边栏抽屉导航,支持触控滑动操作 - 优化 MaterialListNew 页面移动端适配,重构工具栏布局 - 统一日历组件默认语言为中文,增强本地化支持 - 更新依赖包添加 date-fns 和 vaul-vue 用于日期处理和抽屉组件 - 改进 iOS 滚动体验,添加触摸滚动优化 - 调整主布局结构,优化全屏高度和溢出处理 - 修复移动端分类切换器显示问题,优化按钮样式
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
|
||||
|
||||
<title>牟野营销</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"aplayer": "^1.10.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"dayjs": "^1.11.18",
|
||||
"lucide-vue-next": "^0.575.0",
|
||||
"markdown-it": "^14.1.0",
|
||||
@@ -34,6 +35,7 @@
|
||||
"reka-ui": "^2.9.2",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"tailwindcss": "^4.2.1",
|
||||
"vaul-vue": "^0.4.1",
|
||||
"vue": "^3.5.22",
|
||||
"vue-router": "^4.5.1",
|
||||
"vue-sonner": "^2.0.9",
|
||||
|
||||
@@ -32,7 +32,7 @@ defineExpose({ changeLocale, locale })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container min-h-screen bg-background text-foreground antialiased">
|
||||
<div class="app-container h-screen overflow-hidden bg-background text-foreground antialiased">
|
||||
<SvgSprite />
|
||||
|
||||
<!-- vue-sonner Toaster 全局配置 -->
|
||||
|
||||
@@ -74,7 +74,7 @@ function isActive(item) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Sidebar collapsible="none" class="h-[calc(100vh-70px)] border-r">
|
||||
<Sidebar collapsible="offcanvas" class="h-svh border-r">
|
||||
<SidebarContent>
|
||||
<SidebarGroup v-for="group in visibleNavConfig" :key="group.group">
|
||||
<SidebarGroupLabel>{{ group.group }}</SidebarGroupLabel>
|
||||
|
||||
@@ -3,11 +3,13 @@ import { computed } from 'vue'
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useTheme } from '@/composables/useTheme'
|
||||
import { useSidebar } from '@/components/ui/sidebar'
|
||||
import UserDropdown from '@/components/UserDropdown.vue'
|
||||
import BrandLogo from '@/components/BrandLogo.vue'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const { isDark, toggleTheme } = useTheme()
|
||||
const { isMobile, toggleSidebar } = useSidebar()
|
||||
|
||||
// 计算是否应该显示用户组件
|
||||
const shouldShowUser = computed(() => {
|
||||
@@ -18,10 +20,16 @@ const shouldShowUser = computed(() => {
|
||||
|
||||
<template>
|
||||
<header
|
||||
class="p-1 fixed top-0 left-0 right-0 flex items-center px-6 h-[70px] bg-background/80 border-b border-border/50 z-50"
|
||||
style="backdrop-filter: blur(12px)"
|
||||
class="sticky top-0 flex items-center px-6 h-[70px] bg-background/80 border-b border-border/50 z-40 backdrop-blur-xl"
|
||||
>
|
||||
<div class="flex items-center gap-4 flex-1">
|
||||
<button
|
||||
v-if="isMobile"
|
||||
class="flex items-center justify-center w-9 h-9 rounded-md hover:bg-accent transition-colors"
|
||||
@click="toggleSidebar"
|
||||
>
|
||||
<Icon icon="lucide:menu" class="w-5 h-5" />
|
||||
</button>
|
||||
<BrandLogo :size="36" />
|
||||
</div>
|
||||
|
||||
@@ -41,10 +49,6 @@ const shouldShowUser = computed(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
header {
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
.theme-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -14,6 +14,7 @@ import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, Cale
|
||||
const props = withDefaults(defineProps<CalendarRootProps & { class?: HTMLAttributes["class"], layout?: LayoutTypes, yearRange?: DateValue[] }>(), {
|
||||
modelValue: undefined,
|
||||
layout: undefined,
|
||||
locale: 'zh-CN',
|
||||
})
|
||||
const emits = defineEmits<CalendarRootEmits>()
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@ import { RangeCalendarRoot, useForwardPropsEmits } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { RangeCalendarCell, RangeCalendarCellTrigger, RangeCalendarGrid, RangeCalendarGridBody, RangeCalendarGridHead, RangeCalendarGridRow, RangeCalendarHeadCell, RangeCalendarHeader, RangeCalendarHeading, RangeCalendarNextButton, RangeCalendarPrevButton } from "."
|
||||
|
||||
const props = defineProps<RangeCalendarRootProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = withDefaults(defineProps<RangeCalendarRootProps & { class?: HTMLAttributes["class"] }>(), {
|
||||
locale: 'zh-CN',
|
||||
})
|
||||
|
||||
const emits = defineEmits<RangeCalendarRootEmits>()
|
||||
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
<script setup>
|
||||
import { SidebarProvider } from '@/components/ui/sidebar'
|
||||
import { SidebarProvider, SidebarInset } from '@/components/ui/sidebar'
|
||||
import TopNav from '@/components/TopNav.vue'
|
||||
import SidebarNav from '@/components/SidebarNav.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SidebarProvider
|
||||
:style="{ '--sidebar-width': '220px' }"
|
||||
class="flex flex-col min-h-screen bg-background"
|
||||
>
|
||||
<TopNav />
|
||||
<div class="flex flex-1 pt-[70px]">
|
||||
<SidebarNav />
|
||||
<main class="flex-1 h-[calc(100vh-70px)] overflow-hidden">
|
||||
<SidebarProvider class="h-full bg-background">
|
||||
<SidebarNav />
|
||||
<SidebarInset class="flex flex-col h-full overflow-hidden">
|
||||
<TopNav />
|
||||
<div class="flex-1 overflow-auto">
|
||||
<RouterView v-slot="{ Component }">
|
||||
<keep-alive>
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
</RouterView>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
</template>
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import 'normalize.css'
|
||||
import 'aplayer/dist/APlayer.min.css'
|
||||
import 'vue-sonner/style.css'
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import './theme.css'
|
||||
|
||||
// 初始化 dayjs 为中文
|
||||
dayjs.locale('zh-cn');
|
||||
|
||||
const app = createApp(App)
|
||||
const pinia = createPinia()
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
|
||||
@@ -410,11 +410,23 @@ body {
|
||||
scrollbar-gutter: stable both-edges;
|
||||
}
|
||||
|
||||
/* 平滑滚动 */
|
||||
/* 平滑滚动 - 桌面端 */
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* iOS 丝滑滚动优化 */
|
||||
@supports (-webkit-touch-callout: none) {
|
||||
html, body {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
/* 任何可滚动容器 */
|
||||
[style*="overflow"], .overflow-auto, .overflow-y-auto, .overflow-x-auto {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
}
|
||||
|
||||
/* 选中文本样式 */
|
||||
::selection {
|
||||
background: oklch(0.55 0.14 270 / 0.20);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<FullWidthLayout :show-padding="false" class="material-list-layout">
|
||||
<div class="material-list-container">
|
||||
<!-- 左侧分组面板 - 仅混剪素材显示 -->
|
||||
<!-- 左侧分组面板 - 桌面端显示,移动端隐藏 -->
|
||||
<transition name="sidebar-slide">
|
||||
<div
|
||||
v-show="activeCategory === 'MIX'"
|
||||
class="w-[220px] bg-card border-r border-border flex flex-col px-3 py-5 shrink-0"
|
||||
class="hidden md:flex w-[220px] bg-card border-r border-border flex-col px-3 py-5 shrink-0"
|
||||
>
|
||||
<!-- 分组列表 -->
|
||||
<div class="flex flex-col h-full">
|
||||
@@ -72,49 +72,67 @@
|
||||
<!-- 右侧内容区域 -->
|
||||
<div class="material-content">
|
||||
<!-- 顶部工具栏 -->
|
||||
<div class="flex items-center justify-between px-6 py-4 bg-card border-b border-border gap-6">
|
||||
<!-- 分类切换器 - 胶囊式设计 -->
|
||||
<div class="flex bg-muted/50 rounded-full p-1 gap-1">
|
||||
<button
|
||||
class="flex items-center gap-2 px-6 py-2 rounded-full cursor-pointer text-sm font-medium transition-all duration-200"
|
||||
:class="activeCategory === 'MIX'
|
||||
? 'bg-primary text-primary-foreground shadow-sm'
|
||||
: 'text-muted-foreground hover:text-foreground hover:bg-muted'"
|
||||
@click="handleCategoryChange('MIX')"
|
||||
>
|
||||
<Icon icon="lucide:video" class="text-base" />
|
||||
<span>混剪素材</span>
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center gap-2 px-6 py-2 rounded-full cursor-pointer text-sm font-medium transition-all duration-200"
|
||||
:class="activeCategory === 'DIGITAL_HUMAN'
|
||||
? 'bg-primary text-primary-foreground shadow-sm'
|
||||
: 'text-muted-foreground hover:text-foreground hover:bg-muted'"
|
||||
@click="handleCategoryChange('DIGITAL_HUMAN')"
|
||||
>
|
||||
<Icon icon="lucide:user" class="text-base" />
|
||||
<span>数字人素材</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 搜索和操作区 -->
|
||||
<div class="flex items-center gap-3">
|
||||
<!-- 存储配额显示 -->
|
||||
<div class="flex items-center gap-2 px-3 py-2 bg-muted rounded-lg border border-border">
|
||||
<span class="text-xs text-muted-foreground">存储空间</span>
|
||||
<span class="text-xs font-medium">{{ userStore.usedStorage.toFixed(2) }} / {{ userStore.totalStorage }} GB</span>
|
||||
<div class="w-20 h-1 bg-border rounded-full overflow-hidden">
|
||||
<div
|
||||
class="h-full bg-gradient-to-r from-primary to-primary/70 rounded-full transition-all duration-300"
|
||||
:style="{ width: `${Math.min((userStore.usedStorage / userStore.totalStorage) * 100, 100)}%` }"
|
||||
></div>
|
||||
<div class="toolbar-container">
|
||||
<!-- 第一行:分类切换 + 操作按钮 -->
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<!-- 移动端:分组按钮 + 分类切换器 -->
|
||||
<div class="flex items-center gap-2">
|
||||
<Button
|
||||
v-if="activeCategory === 'MIX'"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="md:hidden shrink-0"
|
||||
@click="groupDrawerOpen = true"
|
||||
>
|
||||
<Icon icon="lucide:folder" class="size-4 mr-1" />
|
||||
{{ currentGroupName }}
|
||||
</Button>
|
||||
<!-- 分类切换器 -->
|
||||
<div class="flex bg-muted/50 rounded-full p-0.5 md:p-1 gap-0.5 md:gap-1">
|
||||
<button
|
||||
class="category-btn"
|
||||
:class="activeCategory === 'MIX' ? 'active' : ''"
|
||||
@click="handleCategoryChange('MIX')"
|
||||
>
|
||||
<Icon icon="lucide:video" class="size-4 md:size-[18px]" />
|
||||
<span class="hidden sm:inline">混剪素材</span>
|
||||
</button>
|
||||
<button
|
||||
class="category-btn"
|
||||
:class="activeCategory === 'DIGITAL_HUMAN' ? 'active' : ''"
|
||||
@click="handleCategoryChange('DIGITAL_HUMAN')"
|
||||
>
|
||||
<Icon icon="lucide:user" class="size-4 md:size-[18px]" />
|
||||
<span class="hidden sm:inline">数字人素材</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative flex items-center">
|
||||
|
||||
<!-- 操作按钮区 -->
|
||||
<div class="flex items-center gap-2">
|
||||
<!-- 存储配额 - 桌面端显示 -->
|
||||
<div class="hidden lg:flex items-center gap-2 px-3 py-1.5 bg-muted rounded-lg border border-border text-xs">
|
||||
<span class="text-muted-foreground">存储</span>
|
||||
<span class="font-medium">{{ userStore.usedStorage.toFixed(1) }}/{{ userStore.totalStorage }}GB</span>
|
||||
</div>
|
||||
<!-- 上传按钮 -->
|
||||
<Button
|
||||
size="sm"
|
||||
:disabled="activeCategory === 'MIX' && (!selectedGroupId || groupList.length === 0)"
|
||||
@click="handleOpenUploadModal"
|
||||
>
|
||||
<Icon icon="lucide:upload" class="size-4 md:mr-2" />
|
||||
<span class="hidden md:inline">上传</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 第二行:搜索框 -->
|
||||
<div class="flex items-center gap-2 mt-3">
|
||||
<div class="relative flex-1">
|
||||
<Input
|
||||
v-model="searchKeyword"
|
||||
placeholder="搜索文件名..."
|
||||
class="w-72"
|
||||
@keypress-enter="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
@@ -125,13 +143,6 @@
|
||||
<Icon icon="lucide:x" class="size-3" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
:disabled="activeCategory === 'MIX' && (!selectedGroupId || groupList.length === 0)"
|
||||
@click="handleOpenUploadModal"
|
||||
>
|
||||
<Icon icon="lucide:upload" class="mr-2 size-4" />
|
||||
上传
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -334,6 +345,48 @@
|
||||
:video-url="previewUrl"
|
||||
:title="previewTitle"
|
||||
/>
|
||||
|
||||
<!-- 移动端分组抽屉 -->
|
||||
<Drawer :open="groupDrawerOpen" @update:open="groupDrawerOpen = $event">
|
||||
<DrawerContent class="max-h-[85vh]">
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>选择分组</DrawerTitle>
|
||||
</DrawerHeader>
|
||||
<div class="flex-1 overflow-y-auto px-4 pb-4">
|
||||
<!-- 新建分组按钮 -->
|
||||
<Button
|
||||
variant="outline"
|
||||
class="w-full mb-3"
|
||||
@click="groupDrawerOpen = false; handleOpenCreateGroupModal()"
|
||||
>
|
||||
<Icon icon="lucide:plus" class="size-4 mr-2" />
|
||||
新建分组
|
||||
</Button>
|
||||
<!-- 分组列表 -->
|
||||
<div class="space-y-1">
|
||||
<div
|
||||
v-for="group in groupList"
|
||||
:key="group.id"
|
||||
class="flex items-center justify-between px-4 py-3 cursor-pointer rounded-xl transition-all"
|
||||
:class="selectedGroupId === group.id
|
||||
? 'bg-primary/10 text-primary'
|
||||
: 'hover:bg-muted active:bg-muted'"
|
||||
@click="handleSelectGroup(group)"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<Icon
|
||||
icon="lucide:folder"
|
||||
class="size-5"
|
||||
:class="selectedGroupId === group.id ? 'text-primary' : 'text-muted-foreground'"
|
||||
/>
|
||||
<span class="font-medium">{{ group.name }}</span>
|
||||
</div>
|
||||
<span class="text-sm text-muted-foreground">{{ group.fileCount }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</div>
|
||||
</FullWidthLayout>
|
||||
</template>
|
||||
@@ -356,6 +409,15 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import {
|
||||
Drawer,
|
||||
DrawerClose,
|
||||
DrawerContent,
|
||||
DrawerFooter,
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
DrawerTrigger,
|
||||
} from '@/components/ui/drawer';
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
@@ -370,8 +432,8 @@ import {
|
||||
import MaterialUploadModal from '@/components/material/MaterialUploadModal.vue';
|
||||
import MaterialService, { MaterialGroupService } from '@/api/material';
|
||||
import FullWidthLayout from '@/layouts/components/FullWidthLayout.vue';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import VideoPreviewModal from '@/components/VideoPreviewModal.vue';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
|
||||
// 用户状态(获取存储配额)
|
||||
const userStore = useUserStore()
|
||||
@@ -388,6 +450,7 @@ const searchKeyword = ref('')
|
||||
// 模态框状态
|
||||
const uploadModalVisible = ref(false)
|
||||
const createGroupModalVisible = ref(false)
|
||||
const groupDrawerOpen = ref(false)
|
||||
|
||||
// 表单数据
|
||||
const createGroupForm = reactive({
|
||||
@@ -421,6 +484,12 @@ const pagination = reactive({
|
||||
// 计算总页数
|
||||
const totalPages = computed(() => Math.ceil(pagination.total / pagination.pageSize))
|
||||
|
||||
// 当前分组名称
|
||||
const currentGroupName = computed(() => {
|
||||
const group = groupList.value.find(g => g.id === selectedGroupId.value)
|
||||
return group?.name || '选择分组'
|
||||
})
|
||||
|
||||
// 方法
|
||||
const handleCategoryChange = async (category) => {
|
||||
activeCategory.value = category
|
||||
@@ -448,6 +517,7 @@ const handleSelectGroup = (group) => {
|
||||
if (selectedGroupId.value === group.id) return
|
||||
|
||||
selectedGroupId.value = group.id
|
||||
groupDrawerOpen.value = false // 关闭抽屉
|
||||
loadFileList()
|
||||
}
|
||||
|
||||
@@ -831,7 +901,6 @@ onMounted(async () => {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
background: var(--background);
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
@@ -845,6 +914,59 @@ onMounted(async () => {
|
||||
transition: all var(--duration-slow) cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 工具栏容器
|
||||
// ========================================
|
||||
.toolbar-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 12px 16px;
|
||||
background: var(--card);
|
||||
border-bottom: 1px solid var(--border);
|
||||
|
||||
@media (min-width: 768px) {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
padding: 16px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 分类按钮
|
||||
// ========================================
|
||||
.category-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 9999px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
color: var(--muted-foreground);
|
||||
border: none;
|
||||
background: transparent;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
padding: 8px 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--foreground);
|
||||
background: var(--muted);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: var(--primary);
|
||||
color: var(--primary-foreground);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 过渡动画
|
||||
// ========================================
|
||||
|
||||
@@ -718,7 +718,7 @@ onMounted(() => {
|
||||
.mix-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
height: 100%;
|
||||
background: @bg-page;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
<RangeCalendar
|
||||
v-model="selectedDateRange"
|
||||
:number-of-months="2"
|
||||
locale="zh-CN"
|
||||
@update:model-value="handleDateSelect"
|
||||
/>
|
||||
</PopoverContent>
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
v-for="item in NAV_ITEMS"
|
||||
:key="item.type"
|
||||
:value="item.type"
|
||||
class="h-9 px-4 gap-2 rounded-lg bg-transparent transition-all data-[state=active]:bg-primary data-[state=active]:text-white data-[state=inactive]:text-muted-foreground data-[state=inactive]:hover:bg-muted focus-visible:ring-0 focus-visible:outline-none"
|
||||
class="h-9 px-3 md:px-4 gap-2 rounded-lg bg-transparent transition-all data-[state=active]:bg-primary data-[state=active]:text-white data-[state=inactive]:text-muted-foreground data-[state=inactive]:hover:bg-muted focus-visible:ring-0 focus-visible:outline-none"
|
||||
>
|
||||
<Icon :icon="item.icon" class="size-4" />
|
||||
<span class="font-medium">{{ item.label }}</span>
|
||||
<span class="font-medium hidden sm:inline">{{ item.label }}</span>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
|
||||
Reference in New Issue
Block a user