mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-05-06 20:42:57 +08:00
✨ Feature(custom): rewrite tray page for macos
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<div class="title-bar">
|
||||
<div class="app-title">
|
||||
<div class="app-text">
|
||||
{{ $t('app.title') }}
|
||||
{{ t('app.title') }}
|
||||
</div>
|
||||
<div class="app-version">
|
||||
v{{ version }}
|
||||
@@ -40,7 +40,7 @@
|
||||
<div class="nav-icon-container">
|
||||
<DatabaseIcon :size="18" />
|
||||
</div>
|
||||
<span class="nav-label">{{ $t('navigation.picbed') }}</span>
|
||||
<span class="nav-label">{{ t('navigation.picbed') }}</span>
|
||||
<ChevronDownIcon
|
||||
:size="16"
|
||||
class="submenu-arrow"
|
||||
@@ -62,7 +62,7 @@
|
||||
<div class="sidebar-footer">
|
||||
<button
|
||||
class="footer-button"
|
||||
:title="$t('navigation.moreOptions')"
|
||||
:title="t('navigation.moreOptions')"
|
||||
@click="openMenu"
|
||||
>
|
||||
<Info :size="20" />
|
||||
@@ -103,12 +103,12 @@
|
||||
>
|
||||
<DialogPanel class="dialog-panel">
|
||||
<DialogTitle class="dialog-title">
|
||||
{{ $t('navigation.picBedQrCode') }}
|
||||
{{ t('navigation.picBedQrCode') }}
|
||||
</DialogTitle>
|
||||
|
||||
<div class="dialog-content">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('navigation.choosePicBed') }}</label>
|
||||
<label class="form-label">{{ t('navigation.choosePicBed') }}</label>
|
||||
<Listbox
|
||||
v-model="choosedPicBedForQRCode"
|
||||
multiple
|
||||
@@ -119,13 +119,13 @@
|
||||
v-if="choosedPicBedForQRCode.length === 0"
|
||||
class="placeholder"
|
||||
>
|
||||
{{ $t('navigation.selectPicBeds') }}
|
||||
{{ t('navigation.selectPicBeds') }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
class="selected-count"
|
||||
>
|
||||
{{ choosedPicBedForQRCode.length }} {{ $t('navigation.selected') }}
|
||||
{{ choosedPicBedForQRCode.length }} {{ t('navigation.selected') }}
|
||||
</span>
|
||||
<ChevronDownIcon
|
||||
:size="16"
|
||||
@@ -167,7 +167,7 @@
|
||||
@click="handleCopyPicBedConfig"
|
||||
>
|
||||
<CopyIcon :size="16" />
|
||||
{{ $t('navigation.copyPicBedConfig') }}
|
||||
{{ t('navigation.copyPicBedConfig') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -264,7 +264,7 @@ function openMenu () {
|
||||
|
||||
function handleCopyPicBedConfig () {
|
||||
window.electron.clipboard.writeText(picBedConfigString.value)
|
||||
$message.success(t('COPY_PICBED_CONFIG_SUCCEED'))
|
||||
$message.success(t('navigation.copySuccess'))
|
||||
}
|
||||
|
||||
const navigationItems = computed(() => [
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"moreOptions": "More Options",
|
||||
"picBedQrCode": "PicBed QR Code",
|
||||
"choosePicBed": "Choose PicBed",
|
||||
"selectPicBeds": "Select PicBeds"
|
||||
"selectPicBeds": "Select PicBeds",
|
||||
"copySuccess": "Copy Success"
|
||||
},
|
||||
"settings": {
|
||||
"theme": {
|
||||
@@ -347,6 +348,7 @@
|
||||
"pluginList": "Plugin List",
|
||||
"notGuiImplement": "This plugin does not have a GUI implementation, continue?",
|
||||
"updateSuccess": "Update Success",
|
||||
"setResult": "Set Result",
|
||||
"setSuccess": "Set Success"
|
||||
},
|
||||
"inputBox": {
|
||||
@@ -476,35 +478,14 @@
|
||||
"inputRegexTip": "Please enter the matching string",
|
||||
"noMatch": "No matching items found",
|
||||
"noItemsNeedRename": "No items need to be renamed"
|
||||
},
|
||||
"tray": {
|
||||
"openMainWindow": "Open Main Window",
|
||||
"waitForUpload": "Waiting for Upload",
|
||||
"uploaded": "Uploaded",
|
||||
"copySuccess": "Copy Success"
|
||||
}
|
||||
},
|
||||
"OPEN_MAIN_WINDOW": "Open Main Window",
|
||||
"OPERATION_SUCCEED": "Operation Succeed",
|
||||
"REFRESH": "Refresh",
|
||||
"CHOOSE_PICBED": "Choose Picbed",
|
||||
"COPY_PICBED_CONFIG": "Copy Picbed Config",
|
||||
"COPY_PICBED_CONFIG_SUCCEED": "Copy Picbed Config Succeed",
|
||||
"INPUT": "Input",
|
||||
"CANCEL": "Cancel",
|
||||
"CONFIRM": "Confirm",
|
||||
"RESET_PICBED_CONFIG": "Reset",
|
||||
"CHOOSE_SHOWED_PICBED": "Choose Showed Picbed",
|
||||
"CHOOSE_PASTE_FORMAT": "Choose Paste Format",
|
||||
"COPY": "Copy",
|
||||
"DELETE": "Delete",
|
||||
"SELECT_ALL": "Select All",
|
||||
"COPY_LINK_SUCCEED": "Copy Link Succeed",
|
||||
"SETTINGS": "Settings",
|
||||
"SETTINGS_OPEN": "Open",
|
||||
"SETTINGS_CLOSE": "Close",
|
||||
"SETTINGS_RESULT": "Result",
|
||||
"UPLOADER_CONFIG_PLACEHOLDER": "Please Enter Configuration Name",
|
||||
"SELECTED_SETTING_HINT": "Selected",
|
||||
"WAIT_TO_UPLOAD": "Wait to Upload",
|
||||
"ALREADY_UPLOAD": "Already Uploaded",
|
||||
"TIPS_DRAG_VALID_PICTURE_OR_URL": "Drag valid picture or url to here",
|
||||
"TIPS_SET_SUCCEED": "Set successfully",
|
||||
"TIPS_RESET_SUCCEED": "Reset successfully",
|
||||
"MANAGE_SETTING_TITLE": "Manage Setting",
|
||||
"MANAGE_SETTING_ISAUTOREFRESH_TITLE": "Auto refresh file list when entering new directory",
|
||||
"MANAGE_SETTING_ISAUTOREFRESH_TIPS": "Only applies to non-paginated mode, data is cached to indexdb to speed up loading speed",
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"moreOptions": "更多选项",
|
||||
"picBedQrCode": "图床配置二维码",
|
||||
"choosePicBed": "选择图床",
|
||||
"selectPicBeds": "请选择图床"
|
||||
"selectPicBeds": "请选择图床",
|
||||
"copySuccess": "复制成功"
|
||||
},
|
||||
"settings": {
|
||||
"theme": {
|
||||
@@ -342,6 +343,7 @@
|
||||
"pluginList": "插件列表",
|
||||
"notGuiImplement": "该插件未对可视化界面进行优化, 是否继续安装?",
|
||||
"updateSuccess": "插件更新成功",
|
||||
"setResult": "设置结果",
|
||||
"setSuccess": "设置成功"
|
||||
},
|
||||
"inputBox": {
|
||||
@@ -471,35 +473,14 @@
|
||||
"inputRegexTip": "请输入匹配字符串",
|
||||
"noMatch": "未找到匹配项",
|
||||
"noItemsNeedRename": "没有需要重命名的项目"
|
||||
},
|
||||
"tray": {
|
||||
"openMainWindow": "打开主窗口",
|
||||
"waitForUpload": "等待上传",
|
||||
"uploaded": "已上传",
|
||||
"copySuccess": "复制成功"
|
||||
}
|
||||
},
|
||||
"OPEN_MAIN_WINDOW": "打开主窗口",
|
||||
"OPERATION_SUCCEED": "操作成功",
|
||||
"REFRESH": "刷新",
|
||||
"CHOOSE_PICBED": "选择图床",
|
||||
"COPY_PICBED_CONFIG": "复制图床配置",
|
||||
"COPY_PICBED_CONFIG_SUCCEED": "复制图床配置成功",
|
||||
"INPUT": "输入框",
|
||||
"CANCEL": "取消",
|
||||
"CONFIRM": "确定",
|
||||
"RESET_PICBED_CONFIG": "重置",
|
||||
"CHOOSE_SHOWED_PICBED": "请选择显示的图床",
|
||||
"CHOOSE_PASTE_FORMAT": "请选择粘贴的格式",
|
||||
"COPY": "复制",
|
||||
"DELETE": "删除",
|
||||
"SELECT_ALL": "全选",
|
||||
"COPY_LINK_SUCCEED": "复制链接成功",
|
||||
"SETTINGS": "设置",
|
||||
"SETTINGS_OPEN": "开",
|
||||
"SETTINGS_CLOSE": "关",
|
||||
"SETTINGS_RESULT": "设置结果",
|
||||
"UPLOADER_CONFIG_PLACEHOLDER": "请输入配置名称",
|
||||
"SELECTED_SETTING_HINT": "已选中",
|
||||
"WAIT_TO_UPLOAD": "等待上传",
|
||||
"ALREADY_UPLOAD": "已上传",
|
||||
"TIPS_DRAG_VALID_PICTURE_OR_URL": "请拖入合法的图片文件或者图片URL地址",
|
||||
"TIPS_SET_SUCCEED": "设置成功",
|
||||
"TIPS_RESET_SUCCEED": "重置成功",
|
||||
"MANAGE_SETTING_TITLE": "管理页面设置",
|
||||
"MANAGE_SETTING_ISAUTOREFRESH_TITLE": "每次进入新目录时,是否自动刷新文件列表",
|
||||
"MANAGE_SETTING_ISAUTOREFRESH_TIPS": "仅对不分页模式有效,默认在加载过一次后自动缓存到数据库来加快下次加载速度",
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"moreOptions": "更多選項",
|
||||
"picBedQrCode": "圖床配置 QRCODE",
|
||||
"choosePicBed": "選擇圖床",
|
||||
"selectPicBeds": "請選擇圖床"
|
||||
"selectPicBeds": "請選擇圖床",
|
||||
"copySuccess": "複製成功"
|
||||
},
|
||||
"settings": {
|
||||
"theme": {
|
||||
@@ -342,6 +343,7 @@
|
||||
"pluginList": "插件列表",
|
||||
"notGuiImplement": "該插件未針對圖形介面進行優化,是否繼續安裝?",
|
||||
"updateSuccess": "插件更新成功",
|
||||
"setResult": "設定結果",
|
||||
"setSuccess": "設定成功"
|
||||
},
|
||||
"inputBox": {
|
||||
@@ -468,38 +470,17 @@
|
||||
"listView": "列表",
|
||||
"gridView": "網格",
|
||||
"isAlwaysForceReload": "無快取",
|
||||
"inputRegexTip": "请输入匹配字符串",
|
||||
"noMatch": "未找到匹配项",
|
||||
"noItemsNeedRename": "没有需要重命名的项目"
|
||||
"inputRegexTip": "請輸入匹配字串",
|
||||
"noMatch": "未找到匹配項",
|
||||
"noItemsNeedRename": "沒有需要重命名的項目"
|
||||
},
|
||||
"tray": {
|
||||
"openMainWindow": "打開主窗口",
|
||||
"waitForUpload": "等待上傳",
|
||||
"uploaded": "已上傳",
|
||||
"copySuccess": "複製成功"
|
||||
}
|
||||
},
|
||||
"OPEN_MAIN_WINDOW": "打開主視窗",
|
||||
"OPERATION_SUCCEED": "操作成功",
|
||||
"REFRESH": "刷新",
|
||||
"CHOOSE_PICBED": "選擇圖床",
|
||||
"COPY_PICBED_CONFIG": "複製圖床設定",
|
||||
"COPY_PICBED_CONFIG_SUCCEED": "複製圖床設定成功",
|
||||
"INPUT": "輸入框",
|
||||
"CANCEL": "取消",
|
||||
"CONFIRM": "確定",
|
||||
"RESET_PICBED_CONFIG": "重置",
|
||||
"CHOOSE_SHOWED_PICBED": "請選擇顯示的圖床",
|
||||
"CHOOSE_PASTE_FORMAT": "請選擇貼上的格式",
|
||||
"COPY": "複製",
|
||||
"DELETE": "刪除",
|
||||
"SELECT_ALL": "全選",
|
||||
"COPY_LINK_SUCCEED": "複製連結成功",
|
||||
"SETTINGS": "設定",
|
||||
"SETTINGS_OPEN": "開",
|
||||
"SETTINGS_CLOSE": "關",
|
||||
"SETTINGS_RESULT": "設定結果",
|
||||
"UPLOADER_CONFIG_PLACEHOLDER": "請輸入配置名稱",
|
||||
"SELECTED_SETTING_HINT": "已選中",
|
||||
"WAIT_TO_UPLOAD": "等待上傳",
|
||||
"ALREADY_UPLOAD": "已上傳",
|
||||
"TIPS_DRAG_VALID_PICTURE_OR_URL": "請拖入合法的圖片檔案或者圖片URL地址",
|
||||
"TIPS_SET_SUCCEED": "設定成功",
|
||||
"TIPS_RESET_SUCCEED": "重置成功",
|
||||
"MANAGE_SETTING_TITLE": "管理設定",
|
||||
"MANAGE_SETTING_ISAUTOREFRESH_TITLE": "每次進入新目錄時,是否自動重新整理檔案列表",
|
||||
"MANAGE_SETTING_ISAUTOREFRESH_TIPS": "僅對不分頁模式有效,預設會在載入後自動快取至資料庫以提升下次載入速度",
|
||||
|
||||
@@ -36,10 +36,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { IpcRendererEvent } from 'electron'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { IConfig } from 'piclist'
|
||||
import { onBeforeMount, onBeforeUnmount, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { isUrl } from '@/utils/common'
|
||||
import { getConfig } from '@/utils/dataSender'
|
||||
@@ -47,7 +45,6 @@ import { IRPCActionType } from '@/utils/enum'
|
||||
import { osGlobal } from '@/utils/global'
|
||||
import type { IFileWithPath } from '#/types/types'
|
||||
|
||||
const { t } = useI18n()
|
||||
const logoPath = ref('')
|
||||
const dragover = ref(false)
|
||||
const progress = ref(0)
|
||||
@@ -116,8 +113,6 @@ function onDrop (e: DragEvent) {
|
||||
const str = e.dataTransfer!.getData(items[0].type)
|
||||
if (isUrl(str)) {
|
||||
window.electron.sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [{ path: str }])
|
||||
} else {
|
||||
ElMessage.error(t('TIPS_DRAG_VALID_PICTURE_OR_URL'))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,8 +129,6 @@ function handleURLDrag (items: DataTransferItemList, dataTransfer: DataTransfer)
|
||||
path: urlMatch[1]
|
||||
}
|
||||
])
|
||||
} else {
|
||||
ElMessage.error(t('TIPS_DRAG_VALID_PICTURE_OR_URL'))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -555,7 +555,7 @@ async function handleConfirmConfig () {
|
||||
break
|
||||
}
|
||||
if ('Notification' in window) {
|
||||
const successNotification = new Notification(t('SETTINGS_RESULT'), {
|
||||
const successNotification = new Notification(t('pages.plugin.setResult'), {
|
||||
body: t('pages.plugin.setSuccess')
|
||||
})
|
||||
successNotification.onclick = () => {
|
||||
|
||||
@@ -1,58 +1,117 @@
|
||||
<template>
|
||||
<div id="tray-page">
|
||||
<!-- Header -->
|
||||
<div
|
||||
class="open-main-window"
|
||||
class="tray-header"
|
||||
@click="openSettingWindow"
|
||||
>
|
||||
{{ $t('OPEN_MAIN_WINDOW') }}
|
||||
<div class="header-content">
|
||||
<span class="header-text">
|
||||
{{ t('pages.tray.openMainWindow') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="header-arrow">
|
||||
<svg
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d="m9 18 6-6-6-6" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
|
||||
<!-- Content -->
|
||||
<div class="tray-content">
|
||||
<!-- Clipboard Files Section -->
|
||||
<div
|
||||
v-if="clipboardFiles.length > 0"
|
||||
class="wait-upload-img"
|
||||
class="section"
|
||||
>
|
||||
<div class="list-title">
|
||||
{{ $t('WAIT_TO_UPLOAD') }}
|
||||
<div class="section-header">
|
||||
<div class="section-title">
|
||||
{{ t('pages.tray.waitForUpload') }}
|
||||
</div>
|
||||
<div class="section-badge">
|
||||
{{ clipboardFiles.length }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="(item, index) in clipboardFiles"
|
||||
:key="index"
|
||||
class="img-list"
|
||||
>
|
||||
<div class="image-grid">
|
||||
<div
|
||||
class="upload-img__container"
|
||||
:class="{ upload: uploadFlag }"
|
||||
v-for="(item, index) in clipboardFiles"
|
||||
:key="index"
|
||||
class="image-item"
|
||||
:class="{ uploading: uploadFlag }"
|
||||
@click="uploadClipboardFiles"
|
||||
>
|
||||
<img
|
||||
:src="item.imgUrl"
|
||||
class="upload-img"
|
||||
>
|
||||
<div class="image-container">
|
||||
<img
|
||||
:src="item.imgUrl"
|
||||
class="image"
|
||||
@error="onImageError"
|
||||
>
|
||||
<div
|
||||
v-if="uploadFlag"
|
||||
class="upload-overlay"
|
||||
>
|
||||
<div class="spinner" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uploaded-img">
|
||||
<div class="list-title">
|
||||
{{ $t('ALREADY_UPLOAD') }}
|
||||
|
||||
<!-- Uploaded Files Section -->
|
||||
<div class="section">
|
||||
<div class="section-header">
|
||||
<div class="section-title">
|
||||
{{ t('pages.tray.uploaded') }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="item in files"
|
||||
:key="item.imgUrl"
|
||||
class="img-list"
|
||||
>
|
||||
<div class="image-grid">
|
||||
<div
|
||||
class="upload-img__container"
|
||||
v-for="item in files"
|
||||
:key="item.imgUrl"
|
||||
class="image-item"
|
||||
@click="copyTheLink(item)"
|
||||
>
|
||||
<img
|
||||
v-lazy="item.imgUrl"
|
||||
class="upload-img"
|
||||
>
|
||||
<div
|
||||
class="upload-img__title"
|
||||
:title="item.fileName"
|
||||
>
|
||||
{{ item.fileName }}
|
||||
<div class="image-container">
|
||||
<img
|
||||
v-lazy="item.imgUrl"
|
||||
class="image"
|
||||
@error="onImageError"
|
||||
>
|
||||
<div class="image-overlay">
|
||||
<div
|
||||
class="image-title"
|
||||
:title="item.fileName"
|
||||
>
|
||||
{{ item.fileName }}
|
||||
</div>
|
||||
<div class="copy-indicator">
|
||||
<svg
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<rect
|
||||
x="9"
|
||||
y="9"
|
||||
width="13"
|
||||
height="13"
|
||||
rx="2"
|
||||
ry="2"
|
||||
/>
|
||||
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -82,7 +141,7 @@ type IResult<T> = T & {
|
||||
}
|
||||
const files = ref<IResult<ImgInfo>[]>([])
|
||||
const notification = reactive({
|
||||
title: t('COPY_LINK_SUCCEED'),
|
||||
title: t('pages.tray.copySuccess'),
|
||||
body: ''
|
||||
})
|
||||
|
||||
@@ -94,7 +153,7 @@ function openSettingWindow () {
|
||||
}
|
||||
|
||||
async function getData () {
|
||||
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 }))!.data
|
||||
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 10 }))!.data
|
||||
}
|
||||
|
||||
const formatCustomLink = (customLink: string, item: ImgInfo) => {
|
||||
@@ -181,6 +240,11 @@ function uploadClipboardFiles () {
|
||||
window.electron.sendRPC(IRPCActionType.TRAY_UPLOAD_CLIPBOARD_FILES)
|
||||
}
|
||||
|
||||
function onImageError (event: Event) {
|
||||
const img = event.target as HTMLImageElement
|
||||
img.style.display = 'none'
|
||||
}
|
||||
|
||||
const dragFilesHandler = async (_: IpcRendererEvent, _files: string[]) => {
|
||||
for (const file of _files) {
|
||||
await $$db.insert(file)
|
||||
@@ -207,9 +271,9 @@ const updateFilesHandler = () => {
|
||||
getData()
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
onBeforeMount(async () => {
|
||||
disableDragFile()
|
||||
getData()
|
||||
await getData()
|
||||
window.electron.ipcRendererOn('dragFiles', dragFilesHandler)
|
||||
window.electron.ipcRendererOn('clipboardFiles', clipboardFilesHandler)
|
||||
window.electron.ipcRendererOn('uploadFiles', uploadFilesHandler)
|
||||
@@ -230,88 +294,242 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
<style lang="stylus" scoped>
|
||||
/* Global styles */
|
||||
body::-webkit-scrollbar
|
||||
width 0px
|
||||
|
||||
#tray-page
|
||||
background-color transparent
|
||||
.open-main-window
|
||||
background #000
|
||||
height 20px
|
||||
line-height 20px
|
||||
text-align center
|
||||
color #858585
|
||||
font-size 12px
|
||||
cursor pointer
|
||||
transition all .2s ease-in-out
|
||||
width 196px
|
||||
height 350px
|
||||
background rgba(255, 255, 255, 0.95)
|
||||
backdrop-filter blur(20px)
|
||||
display flex
|
||||
flex-direction column
|
||||
overflow hidden
|
||||
font-family -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif
|
||||
|
||||
/* Header */
|
||||
.tray-header
|
||||
background var(--color-text-tertiary)
|
||||
padding 8px 12px
|
||||
cursor pointer
|
||||
transition all 0.2s ease
|
||||
display flex
|
||||
align-items center
|
||||
justify-content space-between
|
||||
min-height 32px
|
||||
border-radius 0 0 8px 8px
|
||||
|
||||
&:hover
|
||||
transform translateY(-1px)
|
||||
box-shadow 0 4px 6px rgba(102, 126, 234, 0.3)
|
||||
|
||||
.header-content
|
||||
display flex
|
||||
align-items center
|
||||
gap 8px
|
||||
flex 1
|
||||
|
||||
.header-text
|
||||
color white
|
||||
font-size 11px
|
||||
font-weight 500
|
||||
opacity 0.95
|
||||
|
||||
.header-arrow
|
||||
color white
|
||||
opacity 0.8
|
||||
transition transform 0.2s ease
|
||||
display flex
|
||||
align-items center
|
||||
|
||||
.tray-header:hover .header-arrow
|
||||
transform translateX(2px)
|
||||
|
||||
/* Content */
|
||||
.tray-content
|
||||
flex 1
|
||||
padding 8px
|
||||
overflow-y auto
|
||||
overflow-x hidden
|
||||
|
||||
.tray-content::-webkit-scrollbar
|
||||
width 4px
|
||||
|
||||
.tray-content::-webkit-scrollbar-track
|
||||
background rgba(0, 0, 0, 0.05)
|
||||
border-radius 2px
|
||||
|
||||
.tray-content::-webkit-scrollbar-thumb
|
||||
background rgba(0, 0, 0, 0.2)
|
||||
border-radius 2px
|
||||
|
||||
&:hover
|
||||
background rgba(0, 0, 0, 0.3)
|
||||
|
||||
/* Section */
|
||||
.section
|
||||
margin-bottom 12px
|
||||
|
||||
&:last-child
|
||||
margin-bottom 0
|
||||
|
||||
.section-header
|
||||
display flex
|
||||
align-items center
|
||||
justify-content space-between
|
||||
margin-bottom 6px
|
||||
padding 0 2px
|
||||
|
||||
.section-title
|
||||
font-size 10px
|
||||
font-weight 600
|
||||
color #666
|
||||
text-transform uppercase
|
||||
letter-spacing 0.5px
|
||||
|
||||
.section-badge
|
||||
background rgba(102, 126, 234, 0.1)
|
||||
color #667eea
|
||||
font-size 9px
|
||||
font-weight 600
|
||||
padding 2px 6px
|
||||
border-radius 8px
|
||||
min-width 16px
|
||||
text-align center
|
||||
|
||||
/* Image Grid */
|
||||
.image-grid
|
||||
display grid
|
||||
grid-template-columns repeat(2, 1fr)
|
||||
gap 6px
|
||||
|
||||
.image-item
|
||||
position relative
|
||||
cursor pointer
|
||||
border-radius 6px
|
||||
overflow hidden
|
||||
transition all 0.2s ease
|
||||
background rgba(255, 255, 255, 0.8)
|
||||
border 1px solid rgba(0, 0, 0, 0.08)
|
||||
|
||||
&:hover
|
||||
transform translateY(-2px)
|
||||
box-shadow 0 4px 12px rgba(0, 0, 0, 0.15)
|
||||
border-color rgba(102, 126, 234, 0.3)
|
||||
|
||||
&.uploading
|
||||
cursor not-allowed
|
||||
opacity 0.7
|
||||
|
||||
.image-container
|
||||
position relative
|
||||
width 100%
|
||||
height 60px
|
||||
overflow hidden
|
||||
|
||||
.image
|
||||
width 100%
|
||||
height 100%
|
||||
object-fit cover
|
||||
transition transform 0.2s ease
|
||||
|
||||
.image-item:hover .image
|
||||
transform scale(1.05)
|
||||
|
||||
/* Upload Overlay */
|
||||
.upload-overlay
|
||||
position absolute
|
||||
top 0
|
||||
left 0
|
||||
right 0
|
||||
bottom 0
|
||||
background rgba(255, 255, 255, 0.9)
|
||||
display flex
|
||||
align-items center
|
||||
justify-content center
|
||||
|
||||
.spinner
|
||||
width 16px
|
||||
height 16px
|
||||
border 2px solid rgba(102, 126, 234, 0.2)
|
||||
border-left-color #667eea
|
||||
border-radius 50%
|
||||
animation spin 1s linear infinite
|
||||
|
||||
@keyframes spin
|
||||
0%
|
||||
transform rotate(0deg)
|
||||
100%
|
||||
transform rotate(360deg)
|
||||
|
||||
/* Image Overlay */
|
||||
.image-overlay
|
||||
position absolute
|
||||
bottom 0
|
||||
left 0
|
||||
right 0
|
||||
background linear-gradient(transparent, rgba(0, 0, 0, 0.7))
|
||||
padding 6px 4px 4px
|
||||
display flex
|
||||
align-items flex-end
|
||||
justify-content space-between
|
||||
transform translateY(100%)
|
||||
transition transform 0.2s ease
|
||||
|
||||
.image-item:hover .image-overlay
|
||||
transform translateY(0)
|
||||
|
||||
.image-title
|
||||
color white
|
||||
font-size 9px
|
||||
font-weight 500
|
||||
max-width 60px
|
||||
overflow hidden
|
||||
text-overflow ellipsis
|
||||
white-space nowrap
|
||||
line-height 1.2
|
||||
|
||||
.copy-indicator
|
||||
color white
|
||||
opacity 0.8
|
||||
display flex
|
||||
align-items center
|
||||
|
||||
/* Responsive adjustments for very small content */
|
||||
@media (max-width: 200px)
|
||||
.image-grid
|
||||
grid-template-columns 1fr
|
||||
|
||||
.header-text
|
||||
font-size 10px
|
||||
|
||||
.section-title
|
||||
font-size 9px
|
||||
|
||||
/* Dark theme support */
|
||||
@media (prefers-color-scheme: dark)
|
||||
#tray-page
|
||||
background rgba(30, 30, 30, 0.95)
|
||||
color #fff
|
||||
|
||||
.section-title
|
||||
color #999
|
||||
|
||||
.image-item
|
||||
background rgba(40, 40, 40, 0.8)
|
||||
border-color rgba(255, 255, 255, 0.1)
|
||||
|
||||
&:hover
|
||||
color: #fff;
|
||||
background #49B1F5
|
||||
.list-title
|
||||
text-align center
|
||||
color #858585
|
||||
font-size 12px
|
||||
padding 6px 0
|
||||
position relative
|
||||
&:before
|
||||
content ''
|
||||
position absolute
|
||||
height 1px
|
||||
width calc(100% - 36px)
|
||||
bottom 0
|
||||
left 18px
|
||||
background #858585
|
||||
// .header-arrow
|
||||
// position absolute
|
||||
// top 12px
|
||||
// left 50%
|
||||
// margin-left -10px
|
||||
// width: 0;
|
||||
// height: 0;
|
||||
// border-left: 10px solid transparent
|
||||
// border-right: 10px solid transparent
|
||||
// border-bottom: 10px solid rgba(255,255,255, 1)
|
||||
.content
|
||||
position absolute
|
||||
top 20px
|
||||
width 100%
|
||||
.img-list
|
||||
padding 4px 8px
|
||||
display flex
|
||||
justify-content space-between
|
||||
align-items center
|
||||
// height 45px
|
||||
cursor pointer
|
||||
transition all .2s ease-in-out
|
||||
border-color rgba(102, 126, 234, 0.5)
|
||||
|
||||
.tray-content::-webkit-scrollbar-track
|
||||
background rgba(255, 255, 255, 0.05)
|
||||
|
||||
.tray-content::-webkit-scrollbar-thumb
|
||||
background rgba(255, 255, 255, 0.2)
|
||||
|
||||
&:hover
|
||||
background #49B1F5
|
||||
.upload-img__index
|
||||
color #fff
|
||||
.upload-img__container
|
||||
display flex
|
||||
flex-direction column
|
||||
justify-content center
|
||||
align-items center
|
||||
.upload-img
|
||||
max-width 100%
|
||||
object-fit scale-down
|
||||
margin 0 auto
|
||||
&__container
|
||||
display flex
|
||||
flex-direction column
|
||||
justify-content center
|
||||
align-items center
|
||||
width 100%
|
||||
padding 8px 8px 4px
|
||||
height 100%
|
||||
&.upload
|
||||
cursor not-allowed
|
||||
&__title
|
||||
text-align center
|
||||
overflow hidden
|
||||
text-overflow ellipsis
|
||||
white-space nowrap
|
||||
color #ddd
|
||||
font-size 14px
|
||||
margin-top 4px
|
||||
background rgba(255, 255, 255, 0.3)
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user