mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-05-06 20:42:57 +08:00
🚧 WIP(custom): re-design manage main page
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
- 重新设计了管理功能的全部页面
|
||||
- 重构了几乎全部页面,优化了数十项UI细节问题,整体风格更加统一
|
||||
- 相册页面多项优化,支持显示已选择图片数量,匹配的url列表和记忆过滤器打开状态
|
||||
- 优化了管理文件浏览页面侧边栏名字的显示,现在在超出宽度时会滚动显示完整名称
|
||||
- 插件页面现在可以浏览所有插件列表,查看详情和安装
|
||||
- 新增教学引导页面,首次运行时会自动弹出
|
||||
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
<template>
|
||||
<div class="switch-container">
|
||||
<div class="switch-label-wrapper">
|
||||
<span class="switch-label-text">
|
||||
<span v-for="(segment, index) in segments" :key="index" :style="segment.style">
|
||||
{{ segment.text }}
|
||||
</span>
|
||||
<div v-if="tooltip" class="tooltip-wrapper">
|
||||
<div class="info-icon" @click="toggleTooltip">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor" class="info-svg">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div v-show="showTooltip" class="tooltip-content">
|
||||
{{ tooltip }}
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<div class="switch-control">
|
||||
<label class="switch">
|
||||
<input v-model="value" type="checkbox" class="switch-input" />
|
||||
<span class="switch-slider">
|
||||
<span class="switch-button" />
|
||||
</span>
|
||||
</label>
|
||||
<div v-if="activeText || inactiveText" class="switch-text">
|
||||
{{ value ? activeText : inactiveText }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
defineProps<{
|
||||
tooltip?: string
|
||||
activeText?: string
|
||||
inactiveText?: string
|
||||
segments?: { text: string; style: string }[]
|
||||
}>()
|
||||
|
||||
const value = defineModel<boolean>()
|
||||
const showTooltip = ref(false)
|
||||
|
||||
const toggleTooltip = () => {
|
||||
showTooltip.value = !showTooltip.value
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.switch-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 1rem;
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
|
||||
.switch-label-wrapper {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.switch-label-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.tooltip-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: var(--radius-round);
|
||||
padding: 2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
color: var(--color-text-secondary);
|
||||
transition: var(--transition-fast);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.info-icon:hover {
|
||||
color: var(--color-accent);
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
|
||||
.info-svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.tooltip-content {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem;
|
||||
min-width: 200px;
|
||||
max-width: 300px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
box-shadow: var(--shadow-lg);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.switch-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 44px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.switch-input {
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.switch-slider {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 24px;
|
||||
background: linear-gradient(180deg, #d0d3d9 0%, #c0c4cc 100%);
|
||||
box-shadow: inset 0 1px 3px rgb(0 0 0 / 15%);
|
||||
transition: all var(--transition-medium);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switch-button {
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
left: 2px;
|
||||
border-radius: var(--radius-round);
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
background: linear-gradient(180deg, #ffffff 0%, #f5f5f5 100%);
|
||||
box-shadow:
|
||||
0 2px 6px rgb(0 0 0 / 20%),
|
||||
0 1px 2px rgb(0 0 0 / 10%);
|
||||
transition: all var(--transition-medium);
|
||||
content: '';
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider {
|
||||
background: var(--color-accent);
|
||||
box-shadow:
|
||||
inset 0 1px 3px rgb(0 0 0 / 10%),
|
||||
0 2px 8px color-mix(in srgb, var(--color-accent), transparent 30%);
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider .switch-button {
|
||||
transform: translateX(23px);
|
||||
}
|
||||
|
||||
.switch-input:focus + .switch-slider {
|
||||
box-shadow: 0 0 0 2px rgb(0 122 255 / 20%);
|
||||
}
|
||||
|
||||
.switch-text {
|
||||
min-width: 50px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.switch-input:checked ~ .switch-text {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
</style>
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div class="empty-page">
|
||||
<div class="empty-container">
|
||||
<div class="empty-icon">
|
||||
<FolderOpenIcon class="icon" />
|
||||
<div class="flex h-full items-center justify-center p-8">
|
||||
<div class="flex max-w-[400px] flex-col items-center text-center">
|
||||
<div class="mb-6">
|
||||
<FolderOpenIcon class="h-[64px] w-[64px] text-secondary" />
|
||||
</div>
|
||||
<div class="empty-content">
|
||||
<h3 class="empty-title">
|
||||
<div class="flex flex-col gap-2">
|
||||
<h3 class="mb-2 text-xl font-semibold text-main">
|
||||
{{ t('pages.manage.empty.noData') }}
|
||||
</h3>
|
||||
<p class="empty-description">
|
||||
<p class="text-sm leading-[1.5] text-secondary">
|
||||
{{ t('pages.manage.empty.noDataDesc') }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -22,40 +22,3 @@ import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.empty-page
|
||||
height 100%
|
||||
display flex
|
||||
align-items center
|
||||
justify-content center
|
||||
padding 2rem
|
||||
|
||||
.empty-container
|
||||
display flex
|
||||
flex-direction column
|
||||
align-items center
|
||||
text-align center
|
||||
max-width 400px
|
||||
|
||||
.empty-icon
|
||||
margin-bottom 1.5rem
|
||||
|
||||
.icon
|
||||
width 64px
|
||||
height 64px
|
||||
color var(--color-text-secondary)
|
||||
|
||||
.empty-content
|
||||
.empty-title
|
||||
font-size 1.25rem
|
||||
font-weight 600
|
||||
color var(--color-text-primary)
|
||||
margin 0 0 0.5rem 0
|
||||
|
||||
.empty-description
|
||||
font-size 0.875rem
|
||||
color var(--color-text-secondary)
|
||||
margin 0
|
||||
line-height 1.5
|
||||
</style>
|
||||
|
||||
@@ -1,52 +1,60 @@
|
||||
<template>
|
||||
<div class="manage-container">
|
||||
<div
|
||||
class="relative z-1 flex h-full w-full flex-col items-center justify-start gap-2 rounded-xl border-none p-2 shadow-sm"
|
||||
>
|
||||
<!-- Header Card -->
|
||||
<div class="manage-card header-card">
|
||||
<div class="card-header">
|
||||
<div class="header-content">
|
||||
<div class="header-icon">
|
||||
<img :src="`./assets/${currentPagePicBedConfig.picBedName}.webp`" class="header-icon-img" />
|
||||
</div>
|
||||
<div class="header-text">
|
||||
<h2 class="header-title">
|
||||
{{ supportedPicBedList[currentPagePicBedConfig.picBedName].name }}
|
||||
</h2>
|
||||
<p class="header-subtitle">
|
||||
{{ menuTitleMap[currentPicBedName] }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex w-full items-center justify-between gap-4 rounded-xl border border-border-secondary p-0 shadow-sm">
|
||||
<div class="flex flex-wrap items-center gap-1 p-1 max-md:justify-center max-md:text-center">
|
||||
<div class="flex h-[34px] w-[34px] shrink-0 items-center justify-center rounded-md bg-bg-secondary">
|
||||
<img :src="`./assets/${currentPagePicBedConfig.picBedName}.webp`" class="h-[24px] w-[24px] object-contain" />
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button class="action-button secondary" @click="openPicBedUrl">
|
||||
<ExternalLinkIcon class="button-icon" />
|
||||
{{ t('pages.manage.main.openPicBedUrl') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="showNewIconList.includes(currentPicBedName)"
|
||||
class="action-button primary"
|
||||
@click="openNewBucketDrawer"
|
||||
>
|
||||
<PlusIcon class="button-icon" />
|
||||
{{ t('pages.manage.main.newBucket') }}
|
||||
</button>
|
||||
<div class="flex flex-row items-center justify-center gap-2 max-md:text-center">
|
||||
<h2 class="m-0 text-xl font-bold tracking-tight text-main">
|
||||
{{ supportedPicBedList[currentPagePicBedConfig.picBedName].name }}
|
||||
</h2>
|
||||
<p class="m-0 text-sm font-semibold text-secondary">
|
||||
{{ menuTitleMap[currentPicBedName] }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mr-2 flex items-center justify-center gap-3">
|
||||
<CustomButton
|
||||
type="secondary"
|
||||
:text="t('pages.manage.main.openPicBedUrl')"
|
||||
:icon="ExternalLinkIcon"
|
||||
@click="openPicBedUrl"
|
||||
/>
|
||||
<CustomButton
|
||||
v-if="showNewIconList.includes(currentPicBedName)"
|
||||
type="secondary"
|
||||
:text="t('pages.manage.main.newBucket')"
|
||||
:icon="PlusIcon"
|
||||
@click="openNewBucketDrawer"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Card -->
|
||||
<div class="manage-card main-card">
|
||||
<div class="main-layout">
|
||||
<div class="sidebar" :style="{ width: sidebarWidth + 'px' }">
|
||||
<div class="sidebar-header">
|
||||
<h3 class="sidebar-title">
|
||||
<div
|
||||
class="flex w-full flex-1 items-center gap-4 overflow-hidden rounded-xl border border-border-secondary p-2 shadow-md"
|
||||
>
|
||||
<div class="flex h-full w-full">
|
||||
<div
|
||||
class="flex min-h-0 max-w-[400px] min-w-[120px] flex-col border-r-2 border-r-border transition-all duration-100 ease-out"
|
||||
:style="{ width: sidebarWidth + 'px' }"
|
||||
>
|
||||
<div class="shrink-0 border-b-2 border-b-border-secondary p-2">
|
||||
<h3 class="m-0 text-center text-sm font-semibold text-secondary">
|
||||
{{ menuTitleMap[currentPicBedName] }}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-content">
|
||||
<div v-if="isLoadingBucketList" class="loading-container">
|
||||
<div class="loading-spinner" />
|
||||
<span class="loading-text">{{ t('pages.manage.main.loading') }}</span>
|
||||
<div class="min-h-0 flex-1 overflow-y-auto p-2">
|
||||
<div v-if="isLoadingBucketList" class="flex flex-col items-center justify-center gap-2 p-8">
|
||||
<div
|
||||
class="h-[25px] w-[25px] animate-spin rounded-full border-3 border-t-2 border-border border-t-accent"
|
||||
/>
|
||||
<span class="text-sm font-semibold text-secondary">{{ t('pages.manage.main.loading') }}</span>
|
||||
</div>
|
||||
<div v-else class="menu-list">
|
||||
<div
|
||||
@@ -56,41 +64,54 @@
|
||||
:class="{ active: item === currentSelectedBucket }"
|
||||
@click="handleSelectMenu(item)"
|
||||
>
|
||||
<FolderIcon
|
||||
v-if="currentSelectedBucket === item && currentPicBedName !== 'github'"
|
||||
class="menu-icon active"
|
||||
/>
|
||||
<FolderIcon v-else-if="currentPicBedName !== 'github'" class="menu-icon" />
|
||||
<GitBranchIcon v-else-if="currentPicBedName === 'github'" class="menu-icon" />
|
||||
<span class="menu-text" :title="item">
|
||||
{{ truncateText(item, currentPicBedName) }}
|
||||
<span
|
||||
class="group/badge overflow-hidden text-sm font-medium text-ellipsis whitespace-nowrap text-secondary"
|
||||
>
|
||||
<div class="min-w-0 flex-1 overflow-hidden">
|
||||
<div
|
||||
class="flex overflow-hidden text-ellipsis whitespace-nowrap group-hover/badge:w-fit group-hover/badge:animate-[badge-scroll_5s_linear_infinite] group-hover/badge:text-clip"
|
||||
>
|
||||
<span class="leading-none whitespace-nowrap group-hover/badge:pr-[20px]">{{ item }}</span>
|
||||
<span class="hidden leading-none whitespace-nowrap group-hover/badge:block">{{ item }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
<div class="footer-actions">
|
||||
<button class="footer-action-item" @click="switchPicBed('main')">
|
||||
<HomeIcon class="action-icon" />
|
||||
<span class="action-text">{{ t('pages.manage.main.backToHome') }}</span>
|
||||
</button>
|
||||
<button class="footer-action-item" @click="changePicBed">
|
||||
<ArrowLeftRightIcon class="action-icon" />
|
||||
<span class="action-text">{{ t('pages.manage.main.switchPicBed') }}</span>
|
||||
</button>
|
||||
<button class="footer-action-item" @click="openBucketPageSetting">
|
||||
<SettingsIcon class="action-icon" />
|
||||
<span class="action-text">{{ t('pages.manage.main.settings') }}</span>
|
||||
</button>
|
||||
<div class="border-t border-t-border-secondary p-2">
|
||||
<div class="flex flex-col gap-1">
|
||||
<CustomButton
|
||||
type="secondary"
|
||||
:text="t('pages.manage.main.backToHome')"
|
||||
:icon="HomeIcon"
|
||||
class="border-none"
|
||||
@click="switchPicBed('main')"
|
||||
/>
|
||||
<CustomButton
|
||||
type="secondary"
|
||||
:text="t('pages.manage.main.switchPicBed')"
|
||||
:icon="ArrowLeftRightIcon"
|
||||
class="border-none"
|
||||
@click="changePicBed"
|
||||
/>
|
||||
<CustomButton
|
||||
type="secondary"
|
||||
:text="t('pages.manage.main.settings')"
|
||||
:icon="SettingsIcon"
|
||||
class="border-none"
|
||||
@click="openBucketPageSetting"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Resize Handle -->
|
||||
<div class="resize-handle" @mousedown="startResize">
|
||||
<div class="resize-line" />
|
||||
</div>
|
||||
<div
|
||||
class="group/resize relative flex w-[4px] shrink-0 cursor-col-resize items-center justify-center bg-transparent hover:bg-accent/70"
|
||||
@mousedown="startResize"
|
||||
></div>
|
||||
|
||||
<div class="content-area">
|
||||
<router-view />
|
||||
@@ -106,54 +127,51 @@
|
||||
enter-from-class="opacity-0"
|
||||
leave-to-class="opacity-0"
|
||||
>
|
||||
<div v-if="picBedSwitchDialogVisible" class="dialog-overlay" @click="picBedSwitchDialogVisible = false">
|
||||
<div class="dialog-container" @click.stop>
|
||||
<div class="dialog-header">
|
||||
<h3 class="dialog-title">
|
||||
{{ t('pages.manage.main.switchPicBed') }}
|
||||
</h3>
|
||||
<button class="dialog-close" @click="picBedSwitchDialogVisible = false">
|
||||
<XIcon class="close-icon" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="dialog-content">
|
||||
<div class="choice-cos">
|
||||
<!-- Back to main card -->
|
||||
<div class="picbed-card main-card" @click="switchPicBed('main')">
|
||||
<div class="card-icon">
|
||||
<HomeIcon class="main-icon" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-title main-title">
|
||||
{{ $t('pages.manage.main.backToHome') }}
|
||||
</div>
|
||||
<CustomModal
|
||||
v-if="picBedSwitchDialogVisible"
|
||||
v-model:visible="picBedSwitchDialogVisible"
|
||||
:title="t('pages.manage.main.switchPicBed')"
|
||||
>
|
||||
<div class="no-scrollbar h-full w-full overflow-auto p-8">
|
||||
<div class="grid grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-4">
|
||||
<!-- Back to main card -->
|
||||
<div
|
||||
class="relative flex cursor-pointer flex-col items-center rounded-lg border-2 border-success/80 bg-bg-secondary p-6 transition-all duration-fast ease-apple"
|
||||
@click="switchPicBed('main')"
|
||||
>
|
||||
<div class="mb-3 flex h-[40px] w-[40px] items-center justify-center">
|
||||
<HomeIcon class="h-[24px] w-[24px] text-main" />
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="text-sm font-semibold text-main">
|
||||
{{ $t('pages.manage.main.backToHome') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PicBed cards -->
|
||||
<div
|
||||
v-for="(config, alias) in allPicBedConfigure"
|
||||
:key="String(alias)"
|
||||
class="picbed-card"
|
||||
:class="{ active: String(alias) === currentAlias }"
|
||||
@click="switchPicBed(String(alias))"
|
||||
>
|
||||
<div class="card-icon">
|
||||
<img :src="`./assets/${config.picBedName}.webp`" class="picbed-icon" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">
|
||||
{{ config.alias }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="String(alias) === currentAlias" class="check-icon">
|
||||
<CheckIcon />
|
||||
<!-- PicBed cards -->
|
||||
<div
|
||||
v-for="(config, alias) in allPicBedConfigure"
|
||||
:key="String(alias)"
|
||||
class="relative flex cursor-pointer flex-col items-center rounded-lg border-2 border-border/80 bg-bg-secondary p-6 transition-all duration-fast ease-apple [.active]:border-accent"
|
||||
:class="{ active: String(alias) === currentAlias }"
|
||||
@click="switchPicBed(String(alias))"
|
||||
>
|
||||
<div class="mb-3 flex h-[40px] w-[40px] items-center justify-center">
|
||||
<img :src="`./assets/${config.picBedName}.webp`" class="h-[32px] w-[32px] object-contain" />
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="text-sm font-semibold text-main">
|
||||
{{ config.alias }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="String(alias) === currentAlias" class="absolute top-2 right-2 h-[20px] w-[20px] text-accent">
|
||||
<CheckIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CustomModal>
|
||||
</transition>
|
||||
|
||||
<!-- New Bucket Drawer -->
|
||||
@@ -268,17 +286,17 @@ import {
|
||||
CheckIcon,
|
||||
ChevronDownIcon,
|
||||
ExternalLinkIcon,
|
||||
FolderIcon,
|
||||
GitBranchIcon,
|
||||
HomeIcon,
|
||||
PlusIcon,
|
||||
SettingsIcon,
|
||||
XIcon,
|
||||
} from 'lucide-vue-next'
|
||||
import { computed, onBeforeMount, reactive, ref, watch } from 'vue'
|
||||
import { onBeforeMount, reactive, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import CustomButton from '@/components/common/CustomButton.vue'
|
||||
import CustomModal from '@/components/common/CustomModal.vue'
|
||||
import useMessage from '@/hooks/useMessage'
|
||||
import { useManageStore } from '@/manage/store/manageStore'
|
||||
import { supportedPicBedList } from '@/manage/utils/constants'
|
||||
@@ -309,46 +327,6 @@ const isLoadingBucketList = ref(false)
|
||||
const nweBucketDrawerVisible = ref(false)
|
||||
const picBedSwitchDialogVisible = ref(false)
|
||||
|
||||
const maxTextLength = computed(() => {
|
||||
const fixedSpace = 16 + 12 + 24 + 8
|
||||
const availableWidth = sidebarWidth.value - fixedSpace
|
||||
const estimatedCharWidth = 14 * 0.6
|
||||
const maxChars = Math.floor(availableWidth / estimatedCharWidth)
|
||||
return Math.max(6, Math.min(maxChars, 60))
|
||||
})
|
||||
|
||||
const truncateText = (text: string, picBedName: string): string => {
|
||||
if (!text) return ''
|
||||
|
||||
if (picBedName === 'tcyun') {
|
||||
const baseName = text.slice(0, text.length - 11)
|
||||
if (baseName.length <= maxTextLength.value) {
|
||||
return baseName
|
||||
}
|
||||
return `${baseName.slice(0, maxTextLength.value - 3)}...`
|
||||
} else if (picBedName === 'github') {
|
||||
if (text.length <= maxTextLength.value) {
|
||||
return text
|
||||
}
|
||||
const minSideLength = 3
|
||||
const totalEllipsis = 2 // '..'
|
||||
const availableForContent = maxTextLength.value - totalEllipsis
|
||||
|
||||
if (availableForContent < minSideLength * 2) {
|
||||
return `${text.slice(0, maxTextLength.value - 3)}...`
|
||||
}
|
||||
|
||||
const prefixLength = Math.ceil(availableForContent / 2)
|
||||
const suffixLength = availableForContent - prefixLength
|
||||
return `${text.slice(0, prefixLength)}..${text.slice(-suffixLength)}`
|
||||
} else {
|
||||
if (text.length <= maxTextLength.value) {
|
||||
return text
|
||||
}
|
||||
return `${text.slice(0, maxTextLength.value - 3)}...`
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
route,
|
||||
async newRoute => {
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
tag="div"
|
||||
class="flex max-w-[calc(100%-300px)] flex-wrap items-center gap-[0.2rem] [.has-many]:max-w-[300px]"
|
||||
:class="{ 'has-many': favoritePicbeds.length >= 4 }"
|
||||
enter-active-class="transition-all duration-200 ease-apple"
|
||||
leave-active-class="transition-all duration-200 ease-apple"
|
||||
enter-from-class="opacity-0"
|
||||
leave-to-class="opacity-0"
|
||||
>
|
||||
<button
|
||||
v-for="picbedType in favoritePicbeds"
|
||||
|
||||
Reference in New Issue
Block a user