mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-05-06 20:42:57 +08:00
✨ Feature(custom): migrate all pages to tailwind
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
- 优化相册页面卡片样式,边界更清晰,提升选择框视觉效果。
|
- 优化相册页面卡片样式,边界更清晰,提升选择框视觉效果。
|
||||||
- 优化多个页面在窄屏下的显示,避免内容溢出。
|
- 优化多个页面在窄屏下的显示,避免内容溢出。
|
||||||
- 文件浏览侧边栏名称超出宽度时支持滚动显示完整名称。
|
- 文件浏览侧边栏名称超出宽度时支持滚动显示完整名称。
|
||||||
|
- 优化了视频播放页面的显示效果。
|
||||||
- 相册页面支持显示已选数量、匹配的 URL 列表和记忆过滤器状态。
|
- 相册页面支持显示已选数量、匹配的 URL 列表和记忆过滤器状态。
|
||||||
- 支持浏览完整插件列表、查看详情及一键安装。
|
- 支持浏览完整插件列表、查看详情及一键安装。
|
||||||
- 新增新手引导页面,首次运行自动弹出。
|
- 新增新手引导页面,首次运行自动弹出。
|
||||||
@@ -38,6 +39,7 @@
|
|||||||
|
|
||||||
- 修复了管理页面中排序下拉框显示异常的问题。
|
- 修复了管理页面中排序下拉框显示异常的问题。
|
||||||
- 修复了管理页面图床列表未正确高亮当前选中项的问题。
|
- 修复了管理页面图床列表未正确高亮当前选中项的问题。
|
||||||
|
- 修复了管理页面markdown预览内容没有正确渲染的问题。
|
||||||
- 修复了暗色模式下任务页面的显示异常。
|
- 修复了暗色模式下任务页面的显示异常。
|
||||||
- 修复了图床设置页面“设置为默认图床”按钮状态更新不及时的问题。
|
- 修复了图床设置页面“设置为默认图床”按钮状态更新不及时的问题。
|
||||||
- 修复了预处理设置页面中,图床水印独立设置按钮状态不同步的问题。
|
- 修复了预处理设置页面中,图床水印独立设置按钮状态不同步的问题。
|
||||||
|
|||||||
@@ -29,3 +29,4 @@
|
|||||||
@utility no-drag-region {
|
@utility no-drag-region {
|
||||||
-webkit-app-region: none;
|
-webkit-app-region: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,7 +175,6 @@ function validateForm(): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearFieldError(fieldName: string) {
|
function clearFieldError(fieldName: string) {
|
||||||
console.log('Clearing error for field:', fieldName)
|
|
||||||
if (validationErrors[fieldName]) {
|
if (validationErrors[fieldName]) {
|
||||||
delete validationErrors[fieldName]
|
delete validationErrors[fieldName]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,14 @@
|
|||||||
<span v-if="required" class="ml-1 text-danger">*</span>
|
<span v-if="required" class="ml-1 text-danger">*</span>
|
||||||
</label>
|
</label>
|
||||||
<slot name="title-extra"></slot>
|
<slot name="title-extra"></slot>
|
||||||
<div v-if="tips" class="relative">
|
<div v-if="tips" class="group relative inline-block">
|
||||||
<div
|
<div
|
||||||
class="flex h-[20px] w-[20px] cursor-pointer items-center justify-center rounded-full p-[2px] text-secondary hover:bg-bg-secondary hover:text-accent"
|
class="flex h-[20px] w-[20px] cursor-pointer items-center justify-center rounded-full p-[2px] text-secondary hover:bg-bg-secondary hover:text-accent"
|
||||||
@click="toggleTooltip()"
|
|
||||||
>
|
>
|
||||||
<Info :size="16" />
|
<Info :size="16" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="visibleTooltips"
|
class="invisible absolute top-[125%] left-1/2 z-1000 w-max max-w-[200px] translate-x-[-50%] rounded-md border border-border bg-bg-tertiary p-2 text-center text-xs text-main opacity-0 shadow-md transition-opacity duration-300 group-hover:visible group-hover:opacity-100"
|
||||||
class="absolute top-full left-0 z-1000 max-w-[300px] min-w-[200px] rounded-md border border-border bg-bg-secondary p-3 text-xs leading-[1.4] text-main shadow-lg max-md:max-w-[250px] max-md:min-w-[150px]"
|
|
||||||
v-html="transformMarkdownToHTML(tips)"
|
v-html="transformMarkdownToHTML(tips)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,7 +60,6 @@ const [modelValue, modifiers] = defineModel<any>({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const type = ref('text')
|
const type = ref('text')
|
||||||
const visibleTooltips = ref(false)
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isPassword = false,
|
isPassword = false,
|
||||||
@@ -80,10 +77,6 @@ const {
|
|||||||
tips?: string
|
tips?: string
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
function toggleTooltip() {
|
|
||||||
visibleTooltips.value = !visibleTooltips.value
|
|
||||||
}
|
|
||||||
|
|
||||||
function transformMarkdownToHTML(markdown: string) {
|
function transformMarkdownToHTML(markdown: string) {
|
||||||
try {
|
try {
|
||||||
return marked.parse(markdown)
|
return marked.parse(markdown)
|
||||||
|
|||||||
@@ -29,16 +29,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<slot name="title-extra"></slot>
|
<slot name="title-extra"></slot>
|
||||||
<div v-if="tips" class="relative">
|
<div v-if="tips" class="group relative inline-block">
|
||||||
<div
|
<div
|
||||||
class="flex h-[20px] w-[20px] cursor-pointer items-center justify-center rounded-full p-[2px] text-secondary hover:bg-bg-secondary hover:text-accent"
|
class="flex h-[20px] w-[20px] cursor-pointer items-center justify-center rounded-full p-[2px] text-secondary hover:bg-bg-secondary hover:text-accent"
|
||||||
@click="toggleTooltip()"
|
|
||||||
>
|
>
|
||||||
<Info :size="16" />
|
<Info :size="16" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="visibleTooltips"
|
class="invisible absolute top-[125%] left-1/2 z-1000 w-max max-w-[200px] translate-x-[-50%] rounded-md border border-border bg-bg-tertiary p-2 text-center text-xs text-main opacity-0 shadow-md transition-opacity duration-300 group-hover:visible group-hover:opacity-100"
|
||||||
class="absolute top-full left-0 z-1000 max-w-[300px] min-w-[200px] rounded-md border border-border bg-bg-secondary p-3 text-xs leading-[1.4] text-main shadow-lg max-md:max-w-[250px] max-md:min-w-[150px]"
|
|
||||||
v-html="transformMarkdownToHTML(tips)"
|
v-html="transformMarkdownToHTML(tips)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -48,12 +46,10 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Info } from 'lucide-vue-next'
|
import { Info } from 'lucide-vue-next'
|
||||||
import { marked } from 'marked'
|
import { marked } from 'marked'
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted } from 'vue'
|
||||||
|
|
||||||
const emit = defineEmits(['change'])
|
const emit = defineEmits(['change'])
|
||||||
|
|
||||||
const visibleTooltips = ref(false)
|
|
||||||
|
|
||||||
const modelValue = defineModel<boolean>()
|
const modelValue = defineModel<boolean>()
|
||||||
const {
|
const {
|
||||||
title = '',
|
title = '',
|
||||||
@@ -75,10 +71,6 @@ const {
|
|||||||
tighter?: boolean
|
tighter?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
function toggleTooltip() {
|
|
||||||
visibleTooltips.value = !visibleTooltips.value
|
|
||||||
}
|
|
||||||
|
|
||||||
function transformMarkdownToHTML(markdown: string) {
|
function transformMarkdownToHTML(markdown: string) {
|
||||||
try {
|
try {
|
||||||
return marked.parse(markdown)
|
return marked.parse(markdown)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@apply m-0 h-full p-0 w-full bg-transparent;
|
@apply m-0 h-full w-full bg-transparent p-0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
@@ -180,14 +180,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes slide-right {
|
@keyframes slide-right {
|
||||||
from {
|
from {
|
||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -40,16 +40,16 @@
|
|||||||
>
|
>
|
||||||
<div class="flex h-full w-full">
|
<div class="flex h-full w-full">
|
||||||
<div
|
<div
|
||||||
class="flex min-h-0 max-w-[400px] min-w-[40px] flex-col border-r-2 border-r-border transition-all duration-100 ease-out"
|
class="flex min-h-0 w-[40px] max-w-[400px] min-w-[40px] flex-col border-r-2 border-r-border transition-all duration-100 ease-out"
|
||||||
:style="{ width: sidebarWidth + 'px' }"
|
:style="{ width: sidebarWidth + 'px' }"
|
||||||
>
|
>
|
||||||
<div class="shrink-0 border-b-2 border-b-border-secondary p-2">
|
<div v-if="menuTitleMap[currentPicBedName]" class="shrink-0 border-b-2 border-b-border-secondary p-2">
|
||||||
<h3 class="m-0 text-center text-sm font-semibold text-secondary">
|
<h3 class="m-0 text-center text-sm font-semibold text-secondary">
|
||||||
{{ menuTitleMap[currentPicBedName] }}
|
{{ menuTitleMap[currentPicBedName] }}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="min-h-0 flex-1 overflow-y-auto p-2">
|
<div class="min-h-0 flex-1 overflow-y-auto">
|
||||||
<div v-if="isLoadingBucketList" class="flex flex-col items-center justify-center gap-2 p-8">
|
<div v-if="isLoadingBucketList" class="flex flex-col items-center justify-center gap-2 p-8">
|
||||||
<div
|
<div
|
||||||
class="h-[25px] w-[25px] animate-spin rounded-full border-3 border-t-2 border-border border-t-accent"
|
class="h-[25px] w-[25px] animate-spin rounded-full border-3 border-t-2 border-border border-t-accent"
|
||||||
@@ -287,7 +287,7 @@ const configMap = ref<any>(null)
|
|||||||
const currentAlias = ref(route.query.alias as string)
|
const currentAlias = ref(route.query.alias as string)
|
||||||
const currentPicBedName = ref(route.query.picBedName as string)
|
const currentPicBedName = ref(route.query.picBedName as string)
|
||||||
|
|
||||||
const sidebarWidth = ref(160)
|
const sidebarWidth = ref(120)
|
||||||
const isResizing = ref(false)
|
const isResizing = ref(false)
|
||||||
|
|
||||||
let allPicBedConfigure = JSON.parse(route.query.allPicBedConfigure as string)
|
let allPicBedConfigure = JSON.parse(route.query.allPicBedConfigure as string)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -242,12 +242,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex shrink-0 flex-col justify-between">
|
<div class="flex min-w-0 shrink-0 flex-col justify-between">
|
||||||
<div
|
<div
|
||||||
class="mb-1.5 overflow-hidden text-sm font-medium text-ellipsis whitespace-nowrap text-main"
|
class="mb-1.5 w-full truncate text-center text-sm font-medium text-main"
|
||||||
:title="(item.fileName || '').toString().length > 30 ? item.fileName || '' : ''"
|
:title="(item.fileName || '').toString().length > 30 ? item.fileName || '' : ''"
|
||||||
>
|
>
|
||||||
<div class="text-center">{{ formatFileName(item.fileName || '') }}</div>
|
{{ formatFileName(item.fileName || '') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mr-2 flex items-center justify-between">
|
<div class="mr-2 flex items-center justify-between">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
:class="[osGlobal === 'linux' ? 'rounded-none bg-size-[100vh_100vw]' : 'rounded-full bg-size-[90vh_90vw]']"
|
:class="[osGlobal === 'linux' ? 'rounded-none bg-size-[100vh_100vw]' : 'rounded-full bg-size-[90vh_90vw]']"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
id="upload-area"
|
ref="uploadArea"
|
||||||
class="h-full w-full transition-all duration-200 ease-in-out"
|
class="h-full w-full transition-all duration-200 ease-in-out"
|
||||||
:class="{
|
:class="{
|
||||||
'bg-[rgba(0,0,0,0.3)]': dragover,
|
'bg-[rgba(0,0,0,0.3)]': dragover,
|
||||||
@@ -35,11 +35,12 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { IConfig } from 'piclist'
|
import type { IConfig } from 'piclist'
|
||||||
import { onBeforeMount, onBeforeUnmount, ref, watch } from 'vue'
|
import { onBeforeMount, onBeforeUnmount, ref, useTemplateRef, watch } from 'vue'
|
||||||
|
|
||||||
import { osGlobal } from '@/hooks/useGlobal'
|
import { osGlobal } from '@/hooks/useGlobal'
|
||||||
import { isUrl } from '@/utils/common'
|
import { isUrl } from '@/utils/common'
|
||||||
import { getConfig } from '@/utils/dataSender'
|
import { getConfig } from '@/utils/dataSender'
|
||||||
|
import { useDragEventListeners } from '@/utils/drag'
|
||||||
import { IRPCActionType } from '@/utils/enum'
|
import { IRPCActionType } from '@/utils/enum'
|
||||||
|
|
||||||
const logoPath = ref('')
|
const logoPath = ref('')
|
||||||
@@ -51,6 +52,9 @@ const wX = ref(-1)
|
|||||||
const wY = ref(-1)
|
const wY = ref(-1)
|
||||||
const screenX = ref(-1)
|
const screenX = ref(-1)
|
||||||
const screenY = ref(-1)
|
const screenY = ref(-1)
|
||||||
|
const uploadArea = useTemplateRef<HTMLDivElement>('uploadArea')
|
||||||
|
|
||||||
|
useDragEventListeners(uploadArea)
|
||||||
|
|
||||||
let removeListeners: () => void = () => {}
|
let removeListeners: () => void = () => {}
|
||||||
|
|
||||||
|
|||||||
@@ -135,7 +135,7 @@
|
|||||||
small
|
small
|
||||||
no-border
|
no-border
|
||||||
:title="t('pages.settings.system.isHideDock')"
|
:title="t('pages.settings.system.isHideDock')"
|
||||||
@change="handleHideDockChange(formOfSetting.isHideDock)"
|
@change="handleHideDockChange"
|
||||||
/>
|
/>
|
||||||
</SettingCard>
|
</SettingCard>
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@
|
|||||||
small
|
small
|
||||||
no-border
|
no-border
|
||||||
:title="t('pages.settings.system.miniWindowOnTop')"
|
:title="t('pages.settings.system.miniWindowOnTop')"
|
||||||
@click="handleMiniWindowOntop(formOfSetting.miniWindowOntop)"
|
@change="handleMiniWindowOntop"
|
||||||
/>
|
/>
|
||||||
</SettingCard>
|
</SettingCard>
|
||||||
|
|
||||||
@@ -197,7 +197,7 @@
|
|||||||
no-border
|
no-border
|
||||||
:title="t('pages.settings.system.autoLaunch')"
|
:title="t('pages.settings.system.autoLaunch')"
|
||||||
:description="t('pages.settings.system.autoLaunchDesc')"
|
:description="t('pages.settings.system.autoLaunchDesc')"
|
||||||
@change="handleAutoStartChange(formOfSetting.autoStart)"
|
@change="handleAutoStartChange"
|
||||||
/>
|
/>
|
||||||
</SettingCard>
|
</SettingCard>
|
||||||
<CustomNavCard
|
<CustomNavCard
|
||||||
|
|||||||
@@ -111,6 +111,7 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
id="upload-area"
|
id="upload-area"
|
||||||
|
ref="uploadArea"
|
||||||
class="group/upload relative flex h-full w-full cursor-pointer items-center justify-center rounded-xl border-2 border-dashed border-border bg-bg-secondary px-1 py-12 duration-medium ease-standard focus-visible:focus-ring focus-visible:outline-offset-4 max-md:px-4 max-md:py-8 max-xs:px-2 max-xs:py-6 [:hover,.drag-active]:border-accent [:hover,.drag-active]:bg-[linear-gradient(135deg,var(--color-surface-elevated)_0%,color-mix(in_srgb,var(--color-accent),transparent_95%)_100%)] [:hover,.drag-active]:shadow-lg [:hover,.drag-active&]:-translate-y-[2px]"
|
class="group/upload relative flex h-full w-full cursor-pointer items-center justify-center rounded-xl border-2 border-dashed border-border bg-bg-secondary px-1 py-12 duration-medium ease-standard focus-visible:focus-ring focus-visible:outline-offset-4 max-md:px-4 max-md:py-8 max-xs:px-2 max-xs:py-6 [:hover,.drag-active]:border-accent [:hover,.drag-active]:bg-[linear-gradient(135deg,var(--color-surface-elevated)_0%,color-mix(in_srgb,var(--color-accent),transparent_95%)_100%)] [:hover,.drag-active]:shadow-lg [:hover,.drag-active&]:-translate-y-[2px]"
|
||||||
:class="{ 'drag-active': dragover }"
|
:class="{ 'drag-active': dragover }"
|
||||||
@drop.prevent="onDrop"
|
@drop.prevent="onDrop"
|
||||||
@@ -736,7 +737,8 @@ interface IUploadTaskQueueStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useDragEventListeners()
|
const uploadArea = useTemplateRef('uploadArea')
|
||||||
|
useDragEventListeners(uploadArea)
|
||||||
const $router = useRouter()
|
const $router = useRouter()
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
import { onBeforeUnmount, onMounted } from 'vue'
|
import { onBeforeUnmount, onMounted, type Ref } from 'vue'
|
||||||
|
|
||||||
function disableDrag(e: DragEvent) {
|
export function useDragEventListeners(dropZoneRef: Ref<HTMLElement | null>) {
|
||||||
const dropzone = document.getElementById('upload-area')
|
function disableDrag(e: DragEvent) {
|
||||||
if (dropzone === null || !dropzone.contains(e.target as Node)) {
|
const dropzone = dropZoneRef.value
|
||||||
e.preventDefault()
|
if (!dropzone || !dropzone.contains(e.target as Node)) {
|
||||||
e.dataTransfer!.effectAllowed = 'none'
|
e.preventDefault()
|
||||||
e.dataTransfer!.dropEffect = 'none'
|
if (e.dataTransfer) {
|
||||||
|
e.dataTransfer.effectAllowed = 'none'
|
||||||
|
e.dataTransfer.dropEffect = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export function useDragEventListeners() {
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.addEventListener('dragenter', disableDrag, false)
|
window.addEventListener('dragenter', disableDrag, false)
|
||||||
window.addEventListener('dragover', disableDrag)
|
window.addEventListener('dragover', disableDrag, false)
|
||||||
window.addEventListener('drop', disableDrag)
|
window.addEventListener('drop', disableDrag, false)
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.removeEventListener('dragenter', disableDrag, false)
|
window.removeEventListener('dragenter', disableDrag, false)
|
||||||
window.removeEventListener('dragover', disableDrag)
|
window.removeEventListener('dragover', disableDrag, false)
|
||||||
window.removeEventListener('drop', disableDrag)
|
window.removeEventListener('drop', disableDrag, false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,6 @@
|
|||||||
| .amv | AMV视频文件 | .mpg | MPEG视频文件 |
|
| .amv | AMV视频文件 | .mpg | MPEG视频文件 |
|
||||||
| .avi | AVI视频文件 | .mts | AVCHD视频文件 |
|
| .avi | AVI视频文件 | .mts | AVCHD视频文件 |
|
||||||
| .flac | FLAC音频文件 | .ogg | Ogg Vorbis音频文件 |
|
| .flac | FLAC音频文件 | .ogg | Ogg Vorbis音频文件 |
|
||||||
| .flv | Flash视频文件 | .ogv | Ogg Theora视频文件 |
|
|
||||||
| .m2ts | M2TS视频文件 | .vob | DVD视频文件 |
|
| .m2ts | M2TS视频文件 | .vob | DVD视频文件 |
|
||||||
| .m4a | MPEG-4音频文件 | .wav | WAV音频文件 |
|
| .m4a | MPEG-4音频文件 | .wav | WAV音频文件 |
|
||||||
| .m4v | MPEG-4视频文件 | .webm | WebM视频文件 |
|
| .m4v | MPEG-4视频文件 | .webm | WebM视频文件 |
|
||||||
|
|||||||
Reference in New Issue
Block a user