mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-05-06 20:42:57 +08:00
🚧 WIP(custom): rewrite manage page
This commit is contained in:
@@ -1185,7 +1185,7 @@ small {
|
||||
/* Dark mode adjustments */
|
||||
:root.dark .image-process-settings,
|
||||
:root.auto.dark .image-process-settings {
|
||||
background: var(--color-background-primary);
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
|
||||
:root.dark .settings-header,
|
||||
|
||||
@@ -63,6 +63,7 @@ const props = withDefaults(defineProps<{
|
||||
const containerRef = ref<HTMLElement | null>(null)
|
||||
const containerHeight = ref<number>(props.pageMode ? 0 : props.height)
|
||||
const containerWidth = ref<number>(0)
|
||||
const parentScrollListeners = ref<HTMLElement[]>([])
|
||||
|
||||
const itemsRef = ref<Item[]>(props.items)
|
||||
watch(() => props.items, v => { itemsRef.value = v })
|
||||
@@ -124,7 +125,7 @@ const viewportStyle = computed(() => {
|
||||
const itemStyle = computed(() =>
|
||||
isGridMode.value
|
||||
? {}
|
||||
: { height: `${props.itemHeight}px`, padding: `${props.itemPadding}px` }
|
||||
: { height: `${props.itemHeight}px` }
|
||||
)
|
||||
|
||||
function handleScroll () {
|
||||
@@ -133,7 +134,34 @@ function handleScroll () {
|
||||
updateScrollTop(c.scrollTop)
|
||||
}
|
||||
|
||||
function handlePageScroll () {
|
||||
if (!props.pageMode) return
|
||||
// Throttle the scroll handler for better performance
|
||||
const now = Date.now()
|
||||
if (now - lastScrollTime.value < 16) return // ~60fps
|
||||
lastScrollTime.value = now
|
||||
|
||||
updateContainerMetrics()
|
||||
// When in page mode, recalculate visible items based on viewport intersection
|
||||
const el = containerRef.value
|
||||
if (!el) return
|
||||
|
||||
const rect = el.getBoundingClientRect()
|
||||
const viewportHeight = window.innerHeight
|
||||
|
||||
// Calculate the intersection with the viewport
|
||||
const intersectionTop = Math.max(0, -rect.top)
|
||||
const intersectionBottom = Math.min(rect.height, viewportHeight - rect.top)
|
||||
const intersectionHeight = Math.max(0, intersectionBottom - intersectionTop)
|
||||
|
||||
if (intersectionHeight > 0) {
|
||||
// Update the virtual scroll position based on the intersection
|
||||
updateScrollTop(intersectionTop)
|
||||
}
|
||||
}
|
||||
|
||||
let ro: ResizeObserver | null = null
|
||||
const lastScrollTime = ref(0)
|
||||
|
||||
function updateContainerMetrics () {
|
||||
const el = containerRef.value
|
||||
@@ -152,7 +180,20 @@ onMounted(() => {
|
||||
if (!el) return
|
||||
ro = new ResizeObserver(updateContainerMetrics)
|
||||
ro.observe(el)
|
||||
if (props.pageMode) ro.observe(document.documentElement)
|
||||
if (props.pageMode) {
|
||||
ro.observe(document.documentElement)
|
||||
// Listen to scroll events on the window for page mode
|
||||
window.addEventListener('scroll', handlePageScroll, { passive: true })
|
||||
// Also listen to scroll events on potential scroll containers
|
||||
let parent = el.parentElement
|
||||
while (parent) {
|
||||
if (parent.scrollHeight > parent.clientHeight) {
|
||||
parent.addEventListener('scroll', handlePageScroll, { passive: true })
|
||||
parentScrollListeners.value.push(parent)
|
||||
}
|
||||
parent = parent.parentElement
|
||||
}
|
||||
}
|
||||
updateContainerMetrics()
|
||||
if (props.pageMode) {
|
||||
window.addEventListener('resize', updateContainerMetrics, { passive: true })
|
||||
@@ -162,6 +203,14 @@ onMounted(() => {
|
||||
onBeforeUnmount(() => {
|
||||
if (ro) ro.disconnect()
|
||||
window.removeEventListener('resize', updateContainerMetrics)
|
||||
if (props.pageMode) {
|
||||
window.removeEventListener('scroll', handlePageScroll)
|
||||
// Clean up parent scroll listeners
|
||||
parentScrollListeners.value.forEach(parent => {
|
||||
parent.removeEventListener('scroll', handlePageScroll)
|
||||
})
|
||||
parentScrollListeners.value = []
|
||||
}
|
||||
})
|
||||
|
||||
function scrollTo (index: number) { scrollToItem(index) }
|
||||
@@ -178,6 +227,10 @@ function refresh () {
|
||||
if (containerRef.value) {
|
||||
updateScrollTop(containerRef.value.scrollTop)
|
||||
}
|
||||
// Also trigger page scroll calculation in page mode
|
||||
if (props.pageMode) {
|
||||
handlePageScroll()
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ scrollTo, scrollToTop, scrollToBottom, setViewMode, toggleViewMode, refresh })
|
||||
@@ -203,9 +256,11 @@ defineExpose({ scrollTo, scrollToTop, scrollToBottom, setViewMode, toggleViewMod
|
||||
inset: 0 auto auto 0;
|
||||
will-change: transform;
|
||||
backface-visibility: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.virtual-scroller-viewport.is-grid {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--items-per-row, 1), minmax(0, 1fr));
|
||||
grid-auto-rows: var(--row-height, 1px);
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
{
|
||||
"app": { "title": "PicList" },
|
||||
"titleBar": { "alwaysOnTop": "Always On Top", "close": "Close", "minimize": "Minimize", "miniWindow": "Mini Window" },
|
||||
"common": { "confirm": "Confirm", "cancel": "Cancel", "close": "Close", "reset": "Reset", "import": "Import" },
|
||||
"common": {
|
||||
"confirm": "Confirm",
|
||||
"cancel": "Cancel",
|
||||
"close": "Close",
|
||||
"reset": "Reset",
|
||||
"import": "Import",
|
||||
"submit": "Submit"
|
||||
},
|
||||
"navigation": {
|
||||
"upload": "Upload",
|
||||
"manage": "Manage",
|
||||
@@ -695,74 +702,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_TITLE": "Clear file list cache database, currently in use:",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_FREE_TITLE": "Available:",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_TIPS": "After clearing, the file list will be reloaded when entering a new directory next time",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_PROMPT": "Are you sure you want to clear the file list cache database?",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_BUTTON": "Clear",
|
||||
"MANAGE_SETTING_ISSHOWTHUMBNAIL_TITLE": "Display the original image instead of format icon (requires public access permissions)",
|
||||
"MANAGE_SETTING_ISUSEPRESIGNEDURL_TITLE": "Use presigned URL for image display",
|
||||
"MANAGE_SETTING_ISSHOWLIST_TITLE": "Default display mode for the file list",
|
||||
"MANAGE_SETTING_ISSHOWLIST_ON": "List",
|
||||
"MANAGE_SETTING_ISSHOWLIST_OFF": "Card",
|
||||
"MANAGE_SETTING_ISFORCECUSTOMURLHTTPS_TITLE": "Force custom URL to use HTTPS",
|
||||
"MANAGE_SETTING_ISFORCECUSTOMURLHTTPS_TIPS": "After enabling, all operations will automatically add the https prefix to custom domains",
|
||||
"MANAGE_SETTING_ISUPLOADKEEPDIRSTRUCTURE_TITLE": "Preserve directory structure when uploading",
|
||||
"MANAGE_SETTING_ISUPLOADKEEPDIRSTRUCTURE_TIPS": "After disabling, all files will be expanded to the specified directory",
|
||||
"MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_A": "Download",
|
||||
"MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_B": " File ",
|
||||
"MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_C": "will preserve the directory structure",
|
||||
"MANAGE_SETTING_ISDOWNLOADFOLDERKEEPDIRSTRUCTURE_TITLE_D": " Folder ",
|
||||
"MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TIPS": "After enabling, the original directory structure will be preserved",
|
||||
"MANAGE_SETTING_MAX_DOWNLOAD_FILE_SIZE_TITLE": "Maximum number of files to download simultaneously (1-9999)",
|
||||
"MANAGE_SETTING_MAX_DOWNLOAD_FILE_SIZE_TIPS": "Not work on Tencent",
|
||||
"MANAGE_SETTING_MAX_DOWNLOAD_FILE_SIZE_INPUT_TIPS": "Please enter the maximum number of files to download simultaneously",
|
||||
"MANAGE_SETTING_ISIGNORECASE_TITLE": "Should file search be case-insensitive",
|
||||
"MANAGE_SETTING_ISIGNORECASE_TIPS": "After enabling, the search will be case-insensitive",
|
||||
"MANAGE_SETTING_TIMESTAMPRENAME_TITLE": "Rename uploaded files with timestamp - (highest priority)",
|
||||
"MANAGE_SETTING_TIMESTAMPRENAME_TIPS": "After enabling, the uploaded file will be renamed with the timestamp",
|
||||
"MANAGE_SETTING_RANDOMSTRINGRENAME_TITLE": "Rename uploaded files with random strings - (medium priority)",
|
||||
"MANAGE_SETTING_RANDOMSTRINGRENAME_TIPS": "Random string length is 20",
|
||||
"MANAGE_SETTING_CUSTOMRENAME_TITLE": "Rename uploaded files with custom names - (lowest priority)",
|
||||
"MANAGE_SETTING_CUSTOMRENAME_TIPS": "After enabling, the uploaded file will be renamed with the custom pattern",
|
||||
"MANAGE_SETTING_CUSTOM_PATTERN_TITLE": "Custom rename format, placeholders can be freely combined, please refer to the table below",
|
||||
"MANAGE_SETTING_CUSTOM_PATTERN_TIPS": "Please enter the custom rename format",
|
||||
"MANAGE_SETTING_CUSTOM_PATTERN_TABLE_TITLE": "Placeholder",
|
||||
"MANAGE_SETTING_CUSTOM_PATTERN_TABLE_TIPS": "Description",
|
||||
"MANAGE_SETTING_PRESIGNED_URL_EXPIRE_TITLE": "Presigned URL expiration time (seconds)",
|
||||
"MANAGE_SETTING_PRESIGNED_URL_EXPIRE_TIPS": "Please enter the presigned URL expiration time",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_TITLE": "Select default link format for copying",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_MARKDOWN": "Markdown",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_MARKDOWN_WITH_LINK": "Markdown with link",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_RAWURL": "Raw URL",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_HTML": "HTML",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_BBCODE": "BBCode",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_CUSTOM": "Custom",
|
||||
"MANAGE_SETTING_CUSTOM_COPY_FORMAT_TITLE": "Custom link format($url -> raw url, $fileName -> raw fileName)",
|
||||
"MANAGE_SETTING_CUSTOM_COPY_FORMAT_TIPS": "Please enter the custom link format",
|
||||
"MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_TITLE": "Choose default download folder",
|
||||
"MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_TIPS": "System default download directory",
|
||||
"MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_BUTTON": "Choose folder",
|
||||
"MANAGE_SETTING_COPY_MESSAGE": "Copied",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_SUCCESS": "Cleared successfully",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_FAILED": "Clear failed",
|
||||
"MANAGE_SETTING_ISENCODEURL_TITLE": "Encode URL when copy",
|
||||
"MANAGE_SETTING_ISENCODEURL_TIPS": "After enabling, the URL will be encoded when copying",
|
||||
"MANAGE_NO_DATA": "No data",
|
||||
"MANAGE_MAIN_PAGE_NEW_BUCKET": "New Bucket",
|
||||
"MANAGE_MAIN_PAGE_BACK_TO_HOME": "Home",
|
||||
"MANAGE_MAIN_PAGE_SWITCH_PICBED": "Switch",
|
||||
"MANAGE_MAIN_PAGE_SETTING": "Setting",
|
||||
"MANAGE_MAIN_PAGE_SUBMIT": "Submit",
|
||||
"MANAGE_MAIN_PAGE_TIPS": "Tips",
|
||||
"MANAGE_MAIN_PAGE_TIPS_SUCCESS": "Created successfully",
|
||||
"MANAGE_MAIN_PAGE_TIPS_FAILED": "Create failed",
|
||||
"MANAGE_MAIN_PAGE_BUCKET": "Bucket",
|
||||
"MANAGE_MAIN_PAGE_GALLERY": "Album",
|
||||
"MANAGE_MAIN_PAGE_REPOSITORY": "Repo",
|
||||
"MANAGE_BUCKET_PAGE_LOADING_TEXT": "Loading...",
|
||||
"MANAGE_BUCKET_PAGE_CUSTOM_URL_SELECT_PLACEHOLDER": "Please select a custom domain",
|
||||
"MANAGE_BUCKET_PAGE_CUSTOM_URL_INPUT_PLACEHOLDER": "Please enter a custom domain",
|
||||
@@ -774,6 +713,8 @@
|
||||
"MANAGE_BUCKET_PAGE_BATCH_COPY_URL_TOOLTIP": "Batch copy URL",
|
||||
"MANAGE_BUCKET_PAGE_COPY_FILE_INFO_TOOLTIP": "Copy file information",
|
||||
"MANAGE_BUCKET_PAGE_FORCE_REFRESH_TOOLTIP": "Force refresh file list",
|
||||
"MANAGE_BUCKET_PAGE_FULLSCREEN_TOOLTIP": "Enter fullscreen mode (F11)",
|
||||
"MANAGE_BUCKET_PAGE_EXIT_FULLSCREEN_TOOLTIP": "Exit fullscreen mode (F11)",
|
||||
"MANAGE_BUCKET_PAGE_SEARCH_PLACEHOLDER": "Search files",
|
||||
"MANAGE_BUCKET_PAGE_ROOT_FOLDER": "Root folder",
|
||||
"MANAGE_BUCKET_PAGE_FILE_NUMBER": "Number of files: ",
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
{
|
||||
"app": { "title": "PicList" },
|
||||
"titleBar": { "alwaysOnTop": "置顶", "close": "关闭", "minimize": "最小化", "miniWindow": "迷你窗口" },
|
||||
"common": { "confirm": "确认", "cancel": "取消", "close": "关闭", "reset": "重置", "import": "导入" },
|
||||
"common": {
|
||||
"confirm": "确认",
|
||||
"cancel": "取消",
|
||||
"close": "关闭",
|
||||
"reset": "重置",
|
||||
"import": "导入",
|
||||
"submit": "提交"
|
||||
},
|
||||
"navigation": {
|
||||
"upload": "上传",
|
||||
"manage": "管理",
|
||||
@@ -481,6 +488,77 @@
|
||||
"copySuccess": "复制成功"
|
||||
},
|
||||
"manage": {
|
||||
"main": {
|
||||
"openPicBedUrl": "打开图床官网",
|
||||
"newBucket": "新建存储桶",
|
||||
"loading": "加载中...",
|
||||
"backToHome": "首页",
|
||||
"switchPicBed": "切换",
|
||||
"settings": "设置",
|
||||
"bucket": "存储桶",
|
||||
"gallery": "相册",
|
||||
"repo": "仓库",
|
||||
"createSuccess": "创建成功",
|
||||
"createFailed": "创建失败"
|
||||
},
|
||||
"empty": {
|
||||
"noData": "暂无数据",
|
||||
"noDataDesc": "请先创建存储桶或上传图片"
|
||||
},
|
||||
"setting": {
|
||||
"clearCache": "清空文件列表缓存数据库,已使用 {size} 可用 {percent}%",
|
||||
"clearCacheMsg": "确定要清空缓存吗?",
|
||||
"isAutoRefreshTitle": "每次进入新目录时,是否自动刷新文件列表",
|
||||
"isAutoRefreshTips": "仅对不分页模式有效,默认在加载过一次后自动缓存到数据库来加快下次加载速度",
|
||||
"isShowThumbnailTitle": "图片显示为原图而非默认文件格式图标(需要存储桶可公开访问)",
|
||||
"isUsePreSignedUrlTitle": "是否使用预签名URL预览图片",
|
||||
"isForceCustomUrlHttpsTitle": "为自定义域名开启强制HTTPS",
|
||||
"isForceCustomUrlHttpsTips": "开启后, 复制链接等操作将会自动为自定义域名添加https前缀",
|
||||
"isEncodeUrlTitle": "复制链接时进行URL编码",
|
||||
"isEncodeUrlTips": "根据平台选择是否开启",
|
||||
"isUploadKeepDirStructureTitle": "上传时保持目录结构",
|
||||
"isUploadKeepDirStructureTips": "关闭后会将所有文件展开到指定目录下",
|
||||
"isIgnoreCaseTitle": "文件搜索时,是否忽略大小写",
|
||||
"isIgnoreCaseTips": "建议开启",
|
||||
"timestampRenameTitle": "上传文件时间戳重命名(最高优先级)",
|
||||
"timestampRenameTips": "开启后,上传的文件将自动重命名为时间戳",
|
||||
"randomStringRenameTitle": "上传文件随机字符串重命名(中优先级)",
|
||||
"randomStringRenameTips": "20位随机字符",
|
||||
"customRenameTitle": "上传文件自定义重命名(低优先级)",
|
||||
"customRenameTips": "开启后填写命名格式",
|
||||
"customRenameTableTitle": "自定义重命名格式参考表",
|
||||
"customRenameTablePlaceholder": "请输入自定义重命名格式",
|
||||
"placeholder": "占位符",
|
||||
"description": "描述",
|
||||
"copySuccess": "已复制 {name}",
|
||||
"download": "下载",
|
||||
"file": "文件",
|
||||
"folder": "文件夹",
|
||||
"keepDirStructure": "保持目录结构",
|
||||
"keepDirStructureDesc": "开启后,下载时会保持原始目录结构",
|
||||
"clearSuccess": "清空缓存成功",
|
||||
"clearFailed": "清空缓存失败",
|
||||
"notice": "通知",
|
||||
"maxDownLoadFileLimit": "最大并行下载文件数",
|
||||
"maxDownLoadFileLimitDesc": "建议根据网络情况调整",
|
||||
"preSignedUrlExpire": "预签名URL过期时间(单位: 秒)",
|
||||
"preSignedUrlExpireDesc": "建议根据实际需求调整",
|
||||
"copyFormat": {
|
||||
"title": "复制格式",
|
||||
"markdown": "Markdown",
|
||||
"rawurl": "原始URL",
|
||||
"markdown-with-link": "Markdown(带链接)",
|
||||
"html": "HTML格式",
|
||||
"bbcode": "BBCode格式",
|
||||
"custom": "自定义格式",
|
||||
"customTitle": "自定义链接格式($url为链接,$fileName为文件名)",
|
||||
"customTips": "请根据实际需求填写自定义格式"
|
||||
},
|
||||
"selectDownloadFolderTitle": "选择下载文件夹",
|
||||
"selectDownloadFolderTips": "选择下载目录",
|
||||
"defaultDownloadFolder": "系统默认下载文件夹",
|
||||
"browse": "浏览"
|
||||
},
|
||||
"login": {
|
||||
"title": "图床管理",
|
||||
"savedConfigs": "已保存配置",
|
||||
@@ -690,74 +768,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"MANAGE_SETTING_TITLE": "管理页面设置",
|
||||
"MANAGE_SETTING_ISAUTOREFRESH_TITLE": "每次进入新目录时,是否自动刷新文件列表",
|
||||
"MANAGE_SETTING_ISAUTOREFRESH_TIPS": "仅对不分页模式有效,默认在加载过一次后自动缓存到数据库来加快下次加载速度",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_TITLE": "清空文件列表缓存数据库 已占用:",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_FREE_TITLE": "剩余可用:",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_TIPS": "清空后下次进入新目录时将会重新加载文件列表",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_PROMPT": "确定要清空文件列表缓存数据库吗?",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_BUTTON": "清空",
|
||||
"MANAGE_SETTING_ISSHOWTHUMBNAIL_TITLE": "图片显示为原图而非默认文件格式图标(需要存储桶可公开访问)",
|
||||
"MANAGE_SETTING_ISUSEPRESIGNEDURL_TITLE": "使用预签名URL预览图片",
|
||||
"MANAGE_SETTING_ISSHOWLIST_TITLE": "文件列表默认显示方式",
|
||||
"MANAGE_SETTING_ISSHOWLIST_ON": "列表",
|
||||
"MANAGE_SETTING_ISSHOWLIST_OFF": "卡片",
|
||||
"MANAGE_SETTING_ISFORCECUSTOMURLHTTPS_TITLE": "为自定义域名开启强制HTTPS",
|
||||
"MANAGE_SETTING_ISFORCECUSTOMURLHTTPS_TIPS": "开启后, 复制链接等操作将会自动为自定义域名添加https前缀",
|
||||
"MANAGE_SETTING_ISUPLOADKEEPDIRSTRUCTURE_TITLE": "上传时保留目录结构",
|
||||
"MANAGE_SETTING_ISUPLOADKEEPDIRSTRUCTURE_TIPS": "关闭后会将所有文件展开到指定目录下",
|
||||
"MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_A": "下载",
|
||||
"MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_B": "文件",
|
||||
"MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_C": "时保留目录结构",
|
||||
"MANAGE_SETTING_ISDOWNLOADFOLDERKEEPDIRSTRUCTURE_TITLE_D": "文件夹",
|
||||
"MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TIPS": "开启后,下载时会保留原始目录结构",
|
||||
"MANAGE_SETTING_MAX_DOWNLOAD_FILE_SIZE_TITLE": "最大同时下载文件数(1-9999)",
|
||||
"MANAGE_SETTING_MAX_DOWNLOAD_FILE_SIZE_TIPS": "腾讯云由于后端实现不同,该设置不生效",
|
||||
"MANAGE_SETTING_MAX_DOWNLOAD_FILE_SIZE_INPUT_TIPS": "请输入最大同时下载文件数",
|
||||
"MANAGE_SETTING_ISIGNORECASE_TITLE": "文件搜索时,是否忽略大小写",
|
||||
"MANAGE_SETTING_ISIGNORECASE_TIPS": "开启后,搜索时会忽略大小写",
|
||||
"MANAGE_SETTING_TIMESTAMPRENAME_TITLE": "上传文件时间戳重命名--(优先级最高)",
|
||||
"MANAGE_SETTING_TIMESTAMPRENAME_TIPS": "开启后,上传文件时会自动重命名为时间戳",
|
||||
"MANAGE_SETTING_RANDOMSTRINGRENAME_TITLE": "上传文件随机字符串重命名--(优先级中)",
|
||||
"MANAGE_SETTING_RANDOMSTRINGRENAME_TIPS": "随机字符串长度为20",
|
||||
"MANAGE_SETTING_CUSTOMRENAME_TITLE": "上传文件自定义重命名--(优先级最低)",
|
||||
"MANAGE_SETTING_CUSTOMRENAME_TIPS": "请填写自定义重命名格式",
|
||||
"MANAGE_SETTING_CUSTOM_PATTERN_TITLE": "自定义重命名格式,占位符请参考下表,可自由组合",
|
||||
"MANAGE_SETTING_CUSTOM_PATTERN_TIPS": "请填写自定义重命名格式",
|
||||
"MANAGE_SETTING_CUSTOM_PATTERN_TABLE_TITLE": "占位符",
|
||||
"MANAGE_SETTING_CUSTOM_PATTERN_TABLE_TIPS": "描述",
|
||||
"MANAGE_SETTING_PRESIGNED_URL_EXPIRE_TITLE": "预签名URL过期时间(单位:秒)",
|
||||
"MANAGE_SETTING_PRESIGNED_URL_EXPIRE_TIPS": "请填写预签名URL过期时间",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_TITLE": "选择默认复制的链接格式",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_MARKDOWN": "Markdown",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_MARKDOWN_WITH_LINK": "Markdown(带链接)",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_RAWURL": "原始链接",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_HTML": "HTML格式",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_BBCODE": "BBCode格式",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_CUSTOM": "自定义格式",
|
||||
"MANAGE_SETTING_CUSTOM_COPY_FORMAT_TITLE": "自定义链接格式($url为链接,$fileName为文件名)",
|
||||
"MANAGE_SETTING_CUSTOM_COPY_FORMAT_TIPS": "请填写自定义链接格式",
|
||||
"MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_TITLE": "选择下载目录",
|
||||
"MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_TIPS": "系统默认下载目录",
|
||||
"MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_BUTTON": "选择目录",
|
||||
"MANAGE_SETTING_COPY_MESSAGE": "已复制",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_SUCCESS": "清除成功",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_FAILED": "清除失败",
|
||||
"MANAGE_SETTING_ISENCODEURL_TITLE": "复制链接时进行URL编码",
|
||||
"MANAGE_SETTING_ISENCODEURL_TIPS": "根据平台选择是否开启",
|
||||
"MANAGE_NO_DATA": "暂无数据",
|
||||
"MANAGE_MAIN_PAGE_NEW_BUCKET": "新建存储桶",
|
||||
"MANAGE_MAIN_PAGE_BACK_TO_HOME": "返回首页",
|
||||
"MANAGE_MAIN_PAGE_SWITCH_PICBED": "切换图床",
|
||||
"MANAGE_MAIN_PAGE_SETTING": "设置",
|
||||
"MANAGE_MAIN_PAGE_SUBMIT": "提交",
|
||||
"MANAGE_MAIN_PAGE_TIPS": "提示",
|
||||
"MANAGE_MAIN_PAGE_TIPS_SUCCESS": "创建成功",
|
||||
"MANAGE_MAIN_PAGE_TIPS_FAILED": "创建失败",
|
||||
"MANAGE_MAIN_PAGE_BUCKET": "存储桶",
|
||||
"MANAGE_MAIN_PAGE_GALLERY": "相册",
|
||||
"MANAGE_MAIN_PAGE_REPOSITORY": "仓库",
|
||||
"MANAGE_BUCKET_PAGE_LOADING_TEXT": "加载文件中...",
|
||||
"MANAGE_BUCKET_PAGE_CUSTOM_URL_SELECT_PLACEHOLDER": "请选择自定义域名",
|
||||
"MANAGE_BUCKET_PAGE_CUSTOM_URL_INPUT_PLACEHOLDER": "请输入自定义域名",
|
||||
@@ -769,6 +779,8 @@
|
||||
"MANAGE_BUCKET_PAGE_BATCH_COPY_URL_TOOLTIP": "批量复制URL",
|
||||
"MANAGE_BUCKET_PAGE_COPY_FILE_INFO_TOOLTIP": "复制文件信息",
|
||||
"MANAGE_BUCKET_PAGE_FORCE_REFRESH_TOOLTIP": "强制刷新文件列表",
|
||||
"MANAGE_BUCKET_PAGE_FULLSCREEN_TOOLTIP": "进入全屏模式 (F11)",
|
||||
"MANAGE_BUCKET_PAGE_EXIT_FULLSCREEN_TOOLTIP": "退出全屏模式 (F11)",
|
||||
"MANAGE_BUCKET_PAGE_SEARCH_PLACEHOLDER": "搜索文件",
|
||||
"MANAGE_BUCKET_PAGE_ROOT_FOLDER": "根目录",
|
||||
"MANAGE_BUCKET_PAGE_FILE_NUMBER": "文件数: ",
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
{
|
||||
"app": { "title": "PicList" },
|
||||
"titleBar": { "alwaysOnTop": "置頂", "close": "關閉", "minimize": "最小化", "miniWindow": "迷你視窗" },
|
||||
"common": { "confirm": "確認", "cancel": "取消", "close": "關閉", "reset": "重置", "import": "匯入" },
|
||||
"common": {
|
||||
"confirm": "確認",
|
||||
"cancel": "取消",
|
||||
"close": "關閉",
|
||||
"reset": "重置",
|
||||
"import": "匯入",
|
||||
"submit": "提交"
|
||||
},
|
||||
"navigation": {
|
||||
"upload": "上傳",
|
||||
"manage": "管理",
|
||||
@@ -690,74 +697,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"MANAGE_SETTING_TITLE": "管理設定",
|
||||
"MANAGE_SETTING_ISAUTOREFRESH_TITLE": "每次進入新目錄時,是否自動重新整理檔案列表",
|
||||
"MANAGE_SETTING_ISAUTOREFRESH_TIPS": "僅對不分頁模式有效,預設會在載入後自動快取至資料庫以提升下次載入速度",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_TITLE": "清空檔案列表快取資料庫 已佔用:",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_FREE_TITLE": "剩餘可用:",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_TIPS": "清空後下次進入新目錄時將會重新載入檔案列表",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_PROMPT": "確定要清空檔案列表快取資料庫嗎?",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_BUTTON": "清空",
|
||||
"MANAGE_SETTING_ISSHOWTHUMBNAIL_TITLE": "顯示圖片的原始圖像而非預設的檔案格式圖示(需要存儲桶公開訪問權限)",
|
||||
"MANAGE_SETTING_ISUSEPRESIGNEDURL_TITLE": "使用預簽名URL预览圖片",
|
||||
"MANAGE_SETTING_ISSHOWLIST_TITLE": "檔案列表預設顯示方式",
|
||||
"MANAGE_SETTING_ISSHOWLIST_ON": "列表",
|
||||
"MANAGE_SETTING_ISSHOWLIST_OFF": "卡片",
|
||||
"MANAGE_SETTING_ISFORCECUSTOMURLHTTPS_TITLE": "自定義域名啟用強制 HTTPS",
|
||||
"MANAGE_SETTING_ISFORCECUSTOMURLHTTPS_TIPS": "開啟後,複製鏈結等操作將會自動為自定義域名添加 HTTPS 前綴",
|
||||
"MANAGE_SETTING_ISUPLOADKEEPDIRSTRUCTURE_TITLE": "保留上傳時的目錄結構",
|
||||
"MANAGE_SETTING_ISUPLOADKEEPDIRSTRUCTURE_TIPS": "停用後,所有文件將會展開到指定目錄下",
|
||||
"MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_A": "下載",
|
||||
"MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_B": "文件",
|
||||
"MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_C": "時保留目錄結構",
|
||||
"MANAGE_SETTING_ISDOWNLOADFOLDERKEEPDIRSTRUCTURE_TITLE_D": "目錄",
|
||||
"MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TIPS": "啟用後,下載時會保留原始目錄結構",
|
||||
"MANAGE_SETTING_MAX_DOWNLOAD_FILE_SIZE_TITLE": "最大同時下載檔案數量(1-9999)",
|
||||
"MANAGE_SETTING_MAX_DOWNLOAD_FILE_SIZE_TIPS": "由於後端實現方式不同,此設定在腾讯云上不生效",
|
||||
"MANAGE_SETTING_MAX_DOWNLOAD_FILE_SIZE_INPUT_TIPS": "請輸入最大同時下載檔案數量",
|
||||
"MANAGE_SETTING_ISIGNORECASE_TITLE": "搜尋檔案時,是否忽略大小寫",
|
||||
"MANAGE_SETTING_ISIGNORECASE_TIPS": "啟用後,搜尋時將會忽略大小寫",
|
||||
"MANAGE_SETTING_TIMESTAMPRENAME_TITLE": "上傳檔案時間戳重新命名--(最高優先級)",
|
||||
"MANAGE_SETTING_TIMESTAMPRENAME_TIPS": "啟用後,上傳檔案時將會使用時間戳重新命名",
|
||||
"MANAGE_SETTING_RANDOMSTRINGRENAME_TITLE": "上傳檔案隨機字符串重新命名--(中優先級)",
|
||||
"MANAGE_SETTING_RANDOMSTRINGRENAME_TIPS": "隨機字符串長度為20",
|
||||
"MANAGE_SETTING_CUSTOMRENAME_TITLE": "上傳檔案自定義重新命名--(最低優先級)",
|
||||
"MANAGE_SETTING_CUSTOMRENAME_TIPS": "啟用後,上傳檔案時將會使用自定義重新命名",
|
||||
"MANAGE_SETTING_CUSTOM_PATTERN_TITLE": "自訂重新命名格式,占位符請參考下表,可自由組合",
|
||||
"MANAGE_SETTING_CUSTOM_PATTERN_TIPS": "請輸入自訂重新命名格式",
|
||||
"MANAGE_SETTING_CUSTOM_PATTERN_TABLE_TITLE": "占位符",
|
||||
"MANAGE_SETTING_CUSTOM_PATTERN_TABLE_TIPS": "說明",
|
||||
"MANAGE_SETTING_PRESIGNED_URL_EXPIRE_TITLE": "預設下載鏈結有效期(秒)",
|
||||
"MANAGE_SETTING_PRESIGNED_URL_EXPIRE_TIPS": "請輸入下載鏈結有效期",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_TITLE": "選擇預設複製的連結格式",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_MARKDOWN": "Markdown",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_MARKDOWN_WITH_LINK": "Markdown(帶連結)",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_RAWURL": "原始鏈結",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_HTML": "HTML格式",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_BBCODE": "BBCode格式",
|
||||
"MANAGE_SETTING_CHOOSE_COPY_FORMAT_CUSTOM": "自定義格式",
|
||||
"MANAGE_SETTING_CUSTOM_COPY_FORMAT_TITLE": "自定義鏈結格式($url為原始鏈結,$fileName為檔案名稱)",
|
||||
"MANAGE_SETTING_CUSTOM_COPY_FORMAT_TIPS": "請輸入自定義鏈結格式",
|
||||
"MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_TITLE": "選擇下載目錄",
|
||||
"MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_TIPS": "系統預設下載目錄",
|
||||
"MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_BUTTON": "選擇目錄",
|
||||
"MANAGE_SETTING_COPY_MESSAGE": "已複製",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_SUCCESS": "清除成功",
|
||||
"MANAGE_SETTING_CLEAR_CACHE_FAILED": "清除失敗",
|
||||
"MANAGE_SETTING_ISENCODEURL_TITLE": "複製鏈結時編碼",
|
||||
"MANAGE_SETTING_ISENCODEURL_TIPS": "啟用後,複製鏈結時將會編碼",
|
||||
"MANAGE_NO_DATA": "暫無數據",
|
||||
"MANAGE_MAIN_PAGE_NEW_BUCKET": "新建存儲桶",
|
||||
"MANAGE_MAIN_PAGE_BACK_TO_HOME": "返回首頁",
|
||||
"MANAGE_MAIN_PAGE_SWITCH_PICBED": "切換圖床",
|
||||
"MANAGE_MAIN_PAGE_SETTING": "設定",
|
||||
"MANAGE_MAIN_PAGE_SUBMIT": "提交",
|
||||
"MANAGE_MAIN_PAGE_TIPS": "提示",
|
||||
"MANAGE_MAIN_PAGE_TIPS_SUCCESS": "創建成功",
|
||||
"MANAGE_MAIN_PAGE_TIPS_FAILED": "創建失敗",
|
||||
"MANAGE_MAIN_PAGE_BUCKET": "存儲桶",
|
||||
"MANAGE_MAIN_PAGE_GALLERY": "圖庫",
|
||||
"MANAGE_MAIN_PAGE_REPOSITORY": "倉庫",
|
||||
"MANAGE_BUCKET_PAGE_LOADING_TEXT": "載入檔案中...",
|
||||
"MANAGE_BUCKET_PAGE_CUSTOM_URL_SELECT_PLACEHOLDER": "請選擇自訂域名",
|
||||
"MANAGE_BUCKET_PAGE_CUSTOM_URL_INPUT_PLACEHOLDER": "請輸入自訂域名",
|
||||
@@ -769,6 +708,8 @@
|
||||
"MANAGE_BUCKET_PAGE_BATCH_COPY_URL_TOOLTIP": "批次複製 URL",
|
||||
"MANAGE_BUCKET_PAGE_COPY_FILE_INFO_TOOLTIP": "複製檔案資訊",
|
||||
"MANAGE_BUCKET_PAGE_FORCE_REFRESH_TOOLTIP": "強制重新整理檔案列表",
|
||||
"MANAGE_BUCKET_PAGE_FULLSCREEN_TOOLTIP": "進入全螢幕模式 (F11)",
|
||||
"MANAGE_BUCKET_PAGE_EXIT_FULLSCREEN_TOOLTIP": "退出全螢幕模式 (F11)",
|
||||
"MANAGE_BUCKET_PAGE_SEARCH_PLACEHOLDER": "搜尋檔案",
|
||||
"MANAGE_BUCKET_PAGE_ROOT_FOLDER": "根目錄",
|
||||
"MANAGE_BUCKET_PAGE_FILE_NUMBER": "檔案數:",
|
||||
|
||||
226
src/renderer/manage/components/CustomSwitch.vue
Normal file
226
src/renderer/manage/components/CustomSwitch.vue
Normal file
@@ -0,0 +1,226 @@
|
||||
<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;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1.5rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.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;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
color: var(--color-text-secondary);
|
||||
transition: var(--transition-fast);
|
||||
border-radius: 50%;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.info-icon:hover {
|
||||
color: var(--color-accent);
|
||||
background: rgba(0, 122, 255, 0.1);
|
||||
}
|
||||
|
||||
.info-svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.tooltip-content {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
min-width: 200px;
|
||||
max-width: 300px;
|
||||
padding: 0.75rem;
|
||||
background: var(--color-surface-elevated);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-lg);
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.4;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.switch-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 3rem;
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
.switch-input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.switch-slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: var(--color-border);
|
||||
border-radius: 0.75rem;
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.switch-button {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
transition: var(--transition-fast);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider {
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider .switch-button {
|
||||
transform: translateX(1.5rem);
|
||||
}
|
||||
|
||||
.switch-input:focus + .switch-slider {
|
||||
box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.2);
|
||||
}
|
||||
|
||||
.switch-text {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-secondary);
|
||||
min-width: 50px;
|
||||
}
|
||||
|
||||
.switch-input:checked ~ .switch-text {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
/* Dark mode adjustments */
|
||||
:root.dark .switch-slider,
|
||||
:root.auto.dark .switch-slider {
|
||||
background: var(--color-border);
|
||||
}
|
||||
|
||||
:root.dark .tooltip-content,
|
||||
:root.auto.dark .tooltip-content {
|
||||
background: var(--color-surface-elevated);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,61 @@
|
||||
<template>
|
||||
<el-empty :description="$t('MANAGE_NO_DATA')" />
|
||||
<div class="empty-page">
|
||||
<div class="empty-container">
|
||||
<div class="empty-icon">
|
||||
<FolderOpenIcon class="icon" />
|
||||
</div>
|
||||
<div class="empty-content">
|
||||
<h3 class="empty-title">
|
||||
{{ t('pages.manage.empty.noData') }}
|
||||
</h3>
|
||||
<p class="empty-description">
|
||||
{{ t('pages.manage.empty.noDataDesc') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { FolderOpenIcon } from 'lucide-vue-next'
|
||||
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,81 +1,86 @@
|
||||
<template>
|
||||
<div class="layout">
|
||||
<div class="layout__menu">
|
||||
<div class="layout__menu__button">
|
||||
<span
|
||||
class="layout__menu__button__item"
|
||||
@click="openPicBedUrl"
|
||||
>
|
||||
<div class="manage-container">
|
||||
<!-- 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="layout__menu__button__item__icon"
|
||||
class="header-icon-img"
|
||||
>
|
||||
{{ supportedPicBedList[currentPagePicBedConfig.picBedName].name }}
|
||||
</span>
|
||||
</div>
|
||||
<el-divider
|
||||
content-position="left"
|
||||
class="layout__menu__button__divider"
|
||||
border-style="none"
|
||||
>
|
||||
<span style="font-size: 14px; color: #909399">
|
||||
<div class="header-text">
|
||||
<h2 class="header-title">
|
||||
{{ supportedPicBedList[currentPagePicBedConfig.picBedName].name }}
|
||||
</h2>
|
||||
<p class="header-subtitle">
|
||||
{{ menuTitleMap[currentPicBedName] }}
|
||||
<el-tooltip
|
||||
</p>
|
||||
</div>
|
||||
</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)"
|
||||
effect="dark"
|
||||
:content="$t('MANAGE_MAIN_PAGE_NEW_BUCKET')"
|
||||
placement="right"
|
||||
:persistent="false"
|
||||
teleported
|
||||
popper-class="layout__menu__button__divider__tooltip"
|
||||
class="action-button primary"
|
||||
@click="openNewBucketDrawer"
|
||||
>
|
||||
<el-icon
|
||||
class="layout__menu__button__divider__icon"
|
||||
color="red"
|
||||
style="top: 2px"
|
||||
@click="openNewBucketDrawer()"
|
||||
<PlusIcon class="button-icon" />
|
||||
{{ t('pages.manage.main.newBucket') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Card -->
|
||||
<div class="manage-card main-card">
|
||||
<div class="main-layout">
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h3 class="sidebar-title">
|
||||
{{ menuTitleMap[currentPicBedName] }}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-content">
|
||||
<div
|
||||
v-if="isLoadingBucketList"
|
||||
class="loading-container"
|
||||
>
|
||||
<CirclePlus />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</el-divider>
|
||||
<div />
|
||||
<el-menu
|
||||
v-loading="isLoadingBucketList"
|
||||
class="layout__menu__list"
|
||||
:default-active="getCurrentActiveBucket"
|
||||
style="width: 120px"
|
||||
active-text-color="#409EFF"
|
||||
@select="handleSelectMenu"
|
||||
<div class="loading-spinner" />
|
||||
<span class="loading-text">{{ t('pages.manage.main.loading') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="menu-list"
|
||||
>
|
||||
<el-menu-item
|
||||
v-for="item of bucketNameList"
|
||||
<div
|
||||
v-for="item in bucketNameList"
|
||||
:key="item"
|
||||
:index="item"
|
||||
class="menu-item"
|
||||
:class="{ active: item === currentSelectedBucket }"
|
||||
@click="handleSelectMenu(item)"
|
||||
>
|
||||
<span
|
||||
class="layout__menu__list__item"
|
||||
:style="{
|
||||
color: item === currentSelectedBucket ? '#409EFF' : '#606266'
|
||||
}"
|
||||
>
|
||||
<el-icon
|
||||
<FolderIcon
|
||||
v-if="currentSelectedBucket === item && currentPicBedName !== 'github'"
|
||||
class="layout__menu__list__item__icon"
|
||||
color="#409EFF"
|
||||
style="top: 2px"
|
||||
>
|
||||
<FolderOpened />
|
||||
</el-icon>
|
||||
<el-icon
|
||||
class="menu-icon active"
|
||||
/>
|
||||
<FolderIcon
|
||||
v-else-if="currentPicBedName !== 'github'"
|
||||
class="layout__menu__list__item__icon"
|
||||
color="#606266"
|
||||
style="top: 2px"
|
||||
>
|
||||
<Folder />
|
||||
</el-icon>
|
||||
class="menu-icon"
|
||||
/>
|
||||
<GitBranchIcon
|
||||
v-else-if="currentPicBedName === 'github'"
|
||||
class="menu-icon"
|
||||
/>
|
||||
<span class="menu-text">
|
||||
{{
|
||||
currentPicBedName === 'tcyun'
|
||||
? item.slice(0, item.length - 11)
|
||||
@@ -86,203 +91,257 @@
|
||||
: item
|
||||
}}
|
||||
</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
<el-menu
|
||||
class="layout__menu__setting"
|
||||
style="width: 120px"
|
||||
>
|
||||
<el-menu-item
|
||||
index="changePicBed"
|
||||
style="height: 40px"
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
<div class="footer-actions">
|
||||
<button
|
||||
class="footer-action-item"
|
||||
@click="switchPicBed('main')"
|
||||
>
|
||||
<span class="layout__menu__setting__item">
|
||||
<el-icon class="layout__menu__setting__item__icon">
|
||||
<HomeFilled />
|
||||
</el-icon>
|
||||
{{ $t('MANAGE_MAIN_PAGE_BACK_TO_HOME') }}
|
||||
</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item
|
||||
index="changePicBed"
|
||||
style="height: 40px"
|
||||
<HomeIcon class="action-icon" />
|
||||
<span class="action-text">{{ t('pages.manage.main.backToHome') }}</span>
|
||||
</button>
|
||||
<button
|
||||
class="footer-action-item"
|
||||
@click="changePicBed"
|
||||
>
|
||||
<span class="layout__menu__setting__item">
|
||||
<el-icon class="layout__menu__setting__item__icon">
|
||||
<Switch />
|
||||
</el-icon>
|
||||
{{ $t('MANAGE_MAIN_PAGE_SWITCH_PICBED') }}
|
||||
</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item
|
||||
index="bucketPageSetting"
|
||||
style="height: 40px"
|
||||
<ArrowLeftRightIcon class="action-icon" />
|
||||
<span class="action-text">{{ t('pages.manage.main.switchPicBed') }}</span>
|
||||
</button>
|
||||
<button
|
||||
class="footer-action-item"
|
||||
@click="openBucketPageSetting"
|
||||
>
|
||||
<span class="layout__menu__setting__item">
|
||||
<el-icon class="layout__menu__setting__item__icon">
|
||||
<Tools />
|
||||
</el-icon>
|
||||
{{ $t('MANAGE_MAIN_PAGE_SETTING') }}
|
||||
</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
<SettingsIcon class="action-icon" />
|
||||
<span class="action-text">{{ t('pages.manage.main.settings') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="layout__content"
|
||||
style="height: 100%; background-color: transparent; flex: 1; width: 0"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-area">
|
||||
<router-view />
|
||||
</div>
|
||||
<el-dialog
|
||||
v-model="picBedSwitchDialogVisible"
|
||||
top="30vh"
|
||||
append-to-body
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PicBed Switch Dialog -->
|
||||
<div
|
||||
v-if="picBedSwitchDialogVisible"
|
||||
class="dialog-overlay"
|
||||
@click="picBedSwitchDialogVisible = false"
|
||||
>
|
||||
<div
|
||||
class="choice-cos"
|
||||
style="display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-around"
|
||||
class="dialog-container"
|
||||
@click.stop
|
||||
>
|
||||
<el-card shadow="hover">
|
||||
<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
|
||||
style="text-align: center; display: flex; flex-direction: column"
|
||||
class="picbed-card main-card"
|
||||
@click="switchPicBed('main')"
|
||||
>
|
||||
<el-icon
|
||||
color="red"
|
||||
size="25px"
|
||||
style="margin: 0 auto"
|
||||
>
|
||||
<ChromeFilled />
|
||||
</el-icon>
|
||||
<span style="font-size: 13px; margin-top: 5px; color: red">
|
||||
{{ $t('MANAGE_MAIN_PAGE_BACK_TO_HOME') }}
|
||||
</span>
|
||||
<div class="card-icon">
|
||||
<HomeIcon class="main-icon" />
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card
|
||||
v-for="item in allPicBedConfigure"
|
||||
:key="item"
|
||||
shadow="hover"
|
||||
<div class="card-content">
|
||||
<div class="card-title main-title">
|
||||
{{ $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 />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- New Bucket Drawer -->
|
||||
<div
|
||||
v-if="nweBucketDrawerVisible"
|
||||
class="drawer-overlay"
|
||||
@click="nweBucketDrawerVisible = false"
|
||||
>
|
||||
<div
|
||||
style="text-align: center; display: flex; flex-direction: column"
|
||||
@click="switchPicBed(item.alias)"
|
||||
class="drawer-container"
|
||||
@click.stop
|
||||
>
|
||||
<el-image
|
||||
:src="`/assets/${item.picBedName}.webp`"
|
||||
class="layout__addNewBucket__icon"
|
||||
style="width: 25px; height: 25px; margin: 0 auto"
|
||||
/>
|
||||
<span style="font-size: 13px; margin-top: 5px; color: cornflowerblue">
|
||||
{{ item.alias }}
|
||||
</span>
|
||||
<div class="drawer-header">
|
||||
<h3 class="drawer-title">
|
||||
{{ t('pages.manage.main.newBucket') }}
|
||||
</h3>
|
||||
<button
|
||||
class="drawer-close"
|
||||
@click="nweBucketDrawerVisible = false"
|
||||
>
|
||||
<XIcon class="close-icon" />
|
||||
</button>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-drawer
|
||||
v-model="nweBucketDrawerVisible"
|
||||
class="layout__addNewBucket"
|
||||
append-to-body
|
||||
>
|
||||
<el-form
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
label-width="10vw"
|
||||
size="default"
|
||||
:model="newBucketConfigResult"
|
||||
:rules="rules"
|
||||
>
|
||||
<div style="position: relative; height: 10vh; width: 100%">
|
||||
<el-image
|
||||
<div class="drawer-content">
|
||||
<form @submit.prevent="createNewBucket(currentPicBedName)">
|
||||
<div class="form-header">
|
||||
<div class="form-icon">
|
||||
<img
|
||||
:src="`/assets/${currentPicBedName}.webp`"
|
||||
class="layout__addNewBucket__icon"
|
||||
style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%)"
|
||||
/>
|
||||
class="picbed-form-icon"
|
||||
>
|
||||
</div>
|
||||
<el-divider border-style="none" />
|
||||
<el-form-item
|
||||
</div>
|
||||
|
||||
<div class="form-divider" />
|
||||
|
||||
<div
|
||||
v-for="option in newBucketConfig[currentPicBedName].options"
|
||||
:key="option"
|
||||
:prop="currentPicBedName + '.' + option"
|
||||
:label="newBucketConfig[currentPicBedName].configOptions[option].description"
|
||||
class="form-group"
|
||||
>
|
||||
<el-input
|
||||
v-if="
|
||||
newBucketConfig[currentPicBedName].configOptions[option].component === 'input' &&
|
||||
currentPicBedName !== 'tcyun'
|
||||
"
|
||||
v-model.trim="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
:placeholder="newBucketConfig[currentPicBedName].configOptions[option].placeholder"
|
||||
/>
|
||||
<el-input
|
||||
v-if="
|
||||
currentPicBedName === 'tcyun' &&
|
||||
newBucketConfig[currentPicBedName].configOptions[option].component === 'input'
|
||||
"
|
||||
<label class="form-label">
|
||||
{{ newBucketConfig[currentPicBedName].configOptions[option].description }}
|
||||
</label>
|
||||
|
||||
<!-- Input field -->
|
||||
<input
|
||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'input' && currentPicBedName !== 'tcyun'"
|
||||
v-model.trim="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
type="text"
|
||||
class="form-input"
|
||||
:placeholder="newBucketConfig[currentPicBedName].configOptions[option].placeholder"
|
||||
>
|
||||
<template #append>
|
||||
{{ '-' + currentPagePicBedConfig.appId }}
|
||||
</template>
|
||||
</el-input>
|
||||
<el-select
|
||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'select'"
|
||||
v-model="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
size="large"
|
||||
:persistent="false"
|
||||
teleported
|
||||
|
||||
<!-- TCyun special input with append -->
|
||||
<div
|
||||
v-if="currentPicBedName === 'tcyun' && newBucketConfig[currentPicBedName].configOptions[option].component === 'input'"
|
||||
class="input-group"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in Object.keys(newBucketConfig[currentPicBedName].configOptions[option].options)"
|
||||
:key="item"
|
||||
:label="newBucketConfig[currentPicBedName].configOptions[option].options[item]"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<el-switch
|
||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'switch'"
|
||||
v-model="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
:active-value="true"
|
||||
:inactive-value="false"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div style="position: relative; height: 10vh; width: 100%; z-index: 1">
|
||||
<el-button
|
||||
:icon="SuccessFilled"
|
||||
type="primary"
|
||||
style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%)"
|
||||
@click="createNewBucket(currentPicBedName)"
|
||||
<input
|
||||
v-model.trim="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
type="text"
|
||||
class="form-input group-input"
|
||||
:placeholder="newBucketConfig[currentPicBedName].configOptions[option].placeholder"
|
||||
>
|
||||
{{ $t('MANAGE_MAIN_PAGE_SUBMIT') }}
|
||||
</el-button>
|
||||
<span class="input-append">{{ '-' + currentPagePicBedConfig.appId }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Select field -->
|
||||
<div
|
||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'select'"
|
||||
class="select-wrapper"
|
||||
>
|
||||
<select
|
||||
v-model="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
class="form-select"
|
||||
>
|
||||
<option
|
||||
v-for="(label, value) in newBucketConfig[currentPicBedName].configOptions[option].options"
|
||||
:key="value"
|
||||
:value="value"
|
||||
>
|
||||
{{ label }}
|
||||
</option>
|
||||
</select>
|
||||
<ChevronDownIcon class="select-arrow" />
|
||||
</div>
|
||||
|
||||
<!-- Switch field -->
|
||||
<label
|
||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'switch'"
|
||||
class="switch-label"
|
||||
>
|
||||
<input
|
||||
v-model="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||
type="checkbox"
|
||||
class="switch-input"
|
||||
:true-value="true"
|
||||
:false-value="false"
|
||||
>
|
||||
<span class="switch-slider">
|
||||
<span class="switch-button" />
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="action-button secondary"
|
||||
@click="nweBucketDrawerVisible = false"
|
||||
>
|
||||
{{ $t('common.cancel') }}
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="action-button primary"
|
||||
>
|
||||
<CheckIcon class="button-icon" />
|
||||
{{ t('common.submit') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
import {
|
||||
ChromeFilled,
|
||||
CirclePlus,
|
||||
Folder,
|
||||
FolderOpened,
|
||||
HomeFilled,
|
||||
SuccessFilled,
|
||||
Switch,
|
||||
Tools
|
||||
} from '@element-plus/icons-vue'
|
||||
import { ElNotification } from 'element-plus'
|
||||
import { computed, onBeforeMount, reactive, ref, watch } from 'vue'
|
||||
ArrowLeftRightIcon,
|
||||
CheckIcon,
|
||||
ChevronDownIcon,
|
||||
ExternalLinkIcon,
|
||||
FolderIcon,
|
||||
GitBranchIcon,
|
||||
HomeIcon,
|
||||
PlusIcon,
|
||||
SettingsIcon,
|
||||
XIcon
|
||||
} from 'lucide-vue-next'
|
||||
import { onBeforeMount, reactive, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import useMessage from '@/hooks/useMessage'
|
||||
import { useManageStore } from '@/manage/store/manageStore'
|
||||
import { supportedPicBedList } from '@/manage/utils/constants'
|
||||
import { newBucketConfig } from '@/manage/utils/newBucketConfig'
|
||||
@@ -293,6 +352,7 @@ const { t } = useI18n()
|
||||
const manageStore = useManageStore() as any
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const message = useMessage()
|
||||
|
||||
const currentAlias = ref(route.query.alias as string)
|
||||
const currentPicBedName = ref(route.query.picBedName as string)
|
||||
@@ -309,17 +369,16 @@ const isLoadingBucketList = ref(false)
|
||||
const nweBucketDrawerVisible = ref(false)
|
||||
const picBedSwitchDialogVisible = ref(false)
|
||||
|
||||
watch(route, async newRoute => {
|
||||
watch(route, async (newRoute) => {
|
||||
if (newRoute.fullPath.split('?')[0] === '/main-page/manage-main-page') {
|
||||
console.log('route changed')
|
||||
currentAlias.value = newRoute.query.alias as string
|
||||
currentPicBedName.value = newRoute.query.picBedName as string
|
||||
allPicBedConfigure = JSON.parse(newRoute.query.allPicBedConfigure as string)
|
||||
currentPagePicBedConfig = reactive(JSON.parse(newRoute.query.config as string))
|
||||
await getBucketList()
|
||||
}
|
||||
})
|
||||
|
||||
const getCurrentActiveBucket = computed(() => (bucketNameList.value.length === 0 ? '' : bucketNameList.value[0]))
|
||||
}, { deep: true })
|
||||
|
||||
const urlMap: IStringKeyMap = {
|
||||
aliyun: 'https://oss.console.aliyun.com',
|
||||
@@ -337,9 +396,9 @@ const urlMap: IStringKeyMap = {
|
||||
|
||||
const showNewIconList = ['aliyun', 'qiniu', 'tcyun', 's3plist']
|
||||
|
||||
const bucketT = t('MANAGE_MAIN_PAGE_BUCKET')
|
||||
const galleryT = t('MANAGE_MAIN_PAGE_GALLERY')
|
||||
const repositoryT = t('MANAGE_MAIN_PAGE_REPOSITORY')
|
||||
const bucketT = t('pages.manage.main.bucket')
|
||||
const galleryT = t('pages.manage.main.gallery')
|
||||
const repositoryT = t('pages.manage.main.repo')
|
||||
|
||||
const menuTitleMap: IStringKeyMap = {
|
||||
aliyun: bucketT,
|
||||
@@ -355,26 +414,8 @@ const menuTitleMap: IStringKeyMap = {
|
||||
local: ''
|
||||
}
|
||||
|
||||
const rules = ruleMap(newBucketConfig)
|
||||
|
||||
const openPicBedUrl = () => window.electron.sendRPC(IRPCActionType.OPEN_URL, urlMap[currentPagePicBedConfig.picBedName])
|
||||
|
||||
function ruleMap (options: IStringKeyMap) {
|
||||
return Object.keys(options).reduce((result, key) => {
|
||||
options[key].options.forEach((option: string) => {
|
||||
const keyName = `${key}.${option}`
|
||||
const configOption = options[key].configOptions[option]
|
||||
if (configOption.rule) {
|
||||
result[keyName] = configOption.rule
|
||||
}
|
||||
if (configOption.default) {
|
||||
newBucketConfigResult[keyName] = configOption.default
|
||||
}
|
||||
})
|
||||
return result
|
||||
}, {} as IStringKeyMap)
|
||||
}
|
||||
|
||||
function openNewBucketDrawer () {
|
||||
nweBucketDrawerVisible.value = true
|
||||
}
|
||||
@@ -390,7 +431,7 @@ function createNewBucket (picBedName: string) {
|
||||
resultValue === '' && defaultValue !== undefined
|
||||
? defaultValue
|
||||
: resultValue === undefined
|
||||
? defaultValue ?? ''
|
||||
? ''
|
||||
: resultValue
|
||||
|
||||
return result
|
||||
@@ -399,23 +440,17 @@ function createNewBucket (picBedName: string) {
|
||||
resultMap.BucketName = `${resultMap.BucketName}-${currentPagePicBedConfig.appId}`
|
||||
}
|
||||
resultMap.endpoint = currentPagePicBedConfig.endpoint
|
||||
window.electron.triggerRPC(IRPCActionType.MANAGE_CREATE_BUCKET, currentAlias, resultMap).then((result: any) => {
|
||||
window.electron.triggerRPC(IRPCActionType.MANAGE_CREATE_BUCKET, currentAlias.value, resultMap).then((result: any) => {
|
||||
if (result) {
|
||||
ElNotification({
|
||||
title: t('MANAGE_MAIN_PAGE_TIPS'),
|
||||
message: t('MANAGE_MAIN_PAGE_TIPS_SUCCESS'),
|
||||
type: 'success'
|
||||
})
|
||||
// Show success notification
|
||||
message.success(t('pages.manage.main.createSuccess'))
|
||||
nweBucketDrawerVisible.value = false
|
||||
setTimeout(() => {
|
||||
getBucketList()
|
||||
}, 2000)
|
||||
} else {
|
||||
ElNotification({
|
||||
title: t('MANAGE_MAIN_PAGE_TIPS'),
|
||||
message: t('MANAGE_MAIN_PAGE_TIPS_FAILED'),
|
||||
type: 'error'
|
||||
})
|
||||
// Show error notification
|
||||
message.error(t('pages.manage.main.createFailed'))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -427,7 +462,6 @@ async function getBucketList () {
|
||||
|
||||
const result = await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_GET_BUCKET_LIST, currentAlias.value)
|
||||
isLoadingBucketList.value = false
|
||||
|
||||
if (result.length > 0) {
|
||||
result.forEach((item: any) => {
|
||||
bucketList.value[item.Name] = item
|
||||
@@ -474,7 +508,11 @@ function handleSelectMenu (bucketName: string) {
|
||||
router.push({
|
||||
path: '/main-page/manage-main-page/manage-bucket-page',
|
||||
query: {
|
||||
configMap: JSON.stringify(configMap)
|
||||
configMap: JSON.stringify(configMap),
|
||||
alias: currentAlias.value,
|
||||
picBedName: currentPicBedName.value,
|
||||
config: JSON.stringify(currentPagePicBedConfig),
|
||||
allPicBedConfigure: JSON.stringify(allPicBedConfigure)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -515,8 +553,15 @@ function changePicBed () {
|
||||
}
|
||||
|
||||
function openBucketPageSetting () {
|
||||
console.log('Open Bucket Page Setting')
|
||||
router.push({
|
||||
path: '/main-page/manage-main-page/manage-setting-page'
|
||||
path: '/main-page/manage-main-page/manage-setting-page',
|
||||
query: {
|
||||
alias: currentAlias.value,
|
||||
picBedName: currentPicBedName.value,
|
||||
config: JSON.stringify(currentPagePicBedConfig),
|
||||
allPicBedConfigure: JSON.stringify(allPicBedConfigure)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -525,74 +570,4 @@ onBeforeMount(() => {
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
.layout
|
||||
height 100%
|
||||
display flex
|
||||
flex-direction row
|
||||
&__menu
|
||||
background: #fff
|
||||
color: #fff
|
||||
display: flex
|
||||
flex-direction: column
|
||||
border-bottom-right-radius: 4px
|
||||
z-index 1
|
||||
width: 130px
|
||||
position: relative
|
||||
&__button
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
padding-left: 0px;
|
||||
padding-top: 10px;
|
||||
&__item
|
||||
color:#2d8cf0
|
||||
width: 100%
|
||||
height: 100%
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
&:hover
|
||||
cursor: pointer
|
||||
color: orange
|
||||
&__icon
|
||||
width: 25px
|
||||
height: 25px
|
||||
&__divider
|
||||
&__icon
|
||||
&:hover
|
||||
cursor: pointer
|
||||
color: orange
|
||||
&__list
|
||||
flex: 1
|
||||
overflow-y: auto
|
||||
&__item
|
||||
width: 100%
|
||||
height: 100%
|
||||
display: flex
|
||||
color: #2d8cf0
|
||||
align-items: center
|
||||
justify-content: center
|
||||
&:hover
|
||||
cursor: pointer
|
||||
color: orange
|
||||
&__icon
|
||||
width: 25px
|
||||
height: 25px
|
||||
&__setting
|
||||
position relative
|
||||
overflow hidden
|
||||
&__item
|
||||
width: 100%
|
||||
display: flex
|
||||
align-items: center
|
||||
color: #000
|
||||
justify-content: center
|
||||
font-size: 12px
|
||||
font-family: Arial, Helvetica, sans-serif
|
||||
&:hover
|
||||
cursor: pointer
|
||||
color: orange
|
||||
&__icon
|
||||
width: 25px
|
||||
height: 25px
|
||||
</style>
|
||||
<style src="./css/ManageMain.css" scoped></style>
|
||||
|
||||
@@ -1,234 +1,253 @@
|
||||
<template>
|
||||
<div id="manage-setting">
|
||||
<el-row
|
||||
class="view-title"
|
||||
align="middle"
|
||||
justify="center"
|
||||
style="font-size: 20px; color: black"
|
||||
<div class="manage-setting-container">
|
||||
<!-- Cache Info Card -->
|
||||
<div class="setting-card content-card">
|
||||
<div class="card-content">
|
||||
<div class="setting-section">
|
||||
<div class="form-group">
|
||||
<div class="form-control">
|
||||
<button
|
||||
type="button"
|
||||
class="action-button warning"
|
||||
@click="handleConfirmClearDb"
|
||||
>
|
||||
{{ $t('MANAGE_SETTING_TITLE') }}
|
||||
</el-row>
|
||||
<el-row class="setting-list">
|
||||
<el-col
|
||||
:span="20"
|
||||
:offset="2"
|
||||
>
|
||||
<el-row style="width: 100%">
|
||||
<el-form
|
||||
label-position="left"
|
||||
label-width="50%"
|
||||
size="default"
|
||||
style="position: relative; width: 100%"
|
||||
>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span style="position: absolute; left: 0">
|
||||
<span>{{ $t('MANAGE_SETTING_CLEAR_CACHE_TITLE') }} </span>
|
||||
<span style="color: #ff4949">{{ formatFileSize(dbSize) === '' ? 0 : formatFileSize(dbSize) }} </span>
|
||||
<span> {{ $t('MANAGE_SETTING_CLEAR_CACHE_FREE_TITLE') }} </span>
|
||||
<span style="color: #ff4949">{{ dbSizeAvailableRate }} %</span>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('MANAGE_SETTING_CLEAR_CACHE_TIPS')"
|
||||
placement="right"
|
||||
:persistent="false"
|
||||
teleported
|
||||
>
|
||||
<el-icon>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<el-popconfirm
|
||||
:title="$t('MANAGE_SETTING_CLEAR_CACHE_PROMPT')"
|
||||
:confirm-button-text="$t('CONFIRM')"
|
||||
:cancel-button-text="$t('CANCEL')"
|
||||
hide-icon
|
||||
:persistent="false"
|
||||
teleported
|
||||
@confirm="handleClearDb"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
style="position: absolute; right: 0"
|
||||
>
|
||||
{{ $t('MANAGE_SETTING_CLEAR_CACHE_BUTTON') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</el-form-item>
|
||||
<DynamicSwitch
|
||||
<Trash2Icon :size="16" />
|
||||
{{ t('pages.manage.setting.clearCache', { percent: dbSizeAvailableRate, size: formatFileSize(dbSize) || 0 }) }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- General Settings Card -->
|
||||
<div class="setting-card content-card">
|
||||
<div class="card-content">
|
||||
<div class="setting-section">
|
||||
<CustomSwitch
|
||||
v-for="item in switchFieldsConfigList"
|
||||
:key="item.configName"
|
||||
v-model="form[item.configName]"
|
||||
:segments="item.segments"
|
||||
:tooltip="item.tooltip"
|
||||
:config-name="item.configName"
|
||||
:active-text="item.activeText"
|
||||
:inactive-text="item.inactiveText"
|
||||
/>
|
||||
<el-link
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Custom Rename Pattern Card -->
|
||||
<div
|
||||
v-if="form.customRename"
|
||||
style="margin-top: 10px; margin-bottom: 10px; color: #409eff"
|
||||
:underline="false"
|
||||
class="setting-card content-card"
|
||||
>
|
||||
{{ $t('MANAGE_SETTING_CUSTOM_PATTERN_TITLE') }}
|
||||
</el-link>
|
||||
<el-input
|
||||
v-if="form.customRename"
|
||||
<div class="card-content">
|
||||
<div class="setting-section">
|
||||
<div class="section-header">
|
||||
<h4 class="section-title">
|
||||
{{ t('pages.manage.setting.customRenameTableTitle') }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input
|
||||
v-model="form.customRenameFormat"
|
||||
:placeholder="$t('MANAGE_SETTING_CUSTOM_PATTERN_TIPS')"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<el-table
|
||||
v-if="form.customRename"
|
||||
:data="customRenameFormatTable"
|
||||
style="width: 100%; margin-top: 10px; margin-left: 10%"
|
||||
:header-cell-style="{ 'text-align': 'center' }"
|
||||
:cell-style="{ 'text-align': 'center' }"
|
||||
@cell-click="handleCellClick"
|
||||
type="text"
|
||||
class="form-input"
|
||||
:placeholder="t('pages.manage.setting.customRenameTablePlaceholder')"
|
||||
>
|
||||
<el-table-column
|
||||
v-for="prop in ['placeholder', 'description', 'placeholderB', 'descriptionB']"
|
||||
:key="prop"
|
||||
:prop="prop"
|
||||
:label="$t('MANAGE_SETTING_CUSTOM_PATTERN_TABLE_TITLE' as any)"
|
||||
width="150"
|
||||
/>
|
||||
</el-table>
|
||||
<br v-if="form.customRename">
|
||||
<DynamicSwitch
|
||||
</div>
|
||||
|
||||
<!-- Pattern Reference Table -->
|
||||
<div class="pattern-table-container">
|
||||
<table class="pattern-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ t('pages.manage.setting.placeholder') }}</th>
|
||||
<th>{{ t('pages.manage.setting.description') }}</th>
|
||||
<th>{{ t('pages.manage.setting.placeholder') }}</th>
|
||||
<th>{{ t('pages.manage.setting.description') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="(row, index) in customRenameFormatTable"
|
||||
:key="index"
|
||||
>
|
||||
<td
|
||||
class="clickable"
|
||||
@click="handleCellClick(row, { property: 'placeholder' })"
|
||||
>
|
||||
{{ row.placeholder }}
|
||||
</td>
|
||||
<td>{{ row.description }}</td>
|
||||
<td
|
||||
class="clickable"
|
||||
@click="handleCellClick(row, { property: 'placeholderB' })"
|
||||
>
|
||||
{{ row.placeholderB }}
|
||||
</td>
|
||||
<td>{{ row.descriptionB }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Special Settings Card -->
|
||||
<div class="setting-card content-card">
|
||||
<div class="card-content">
|
||||
<div class="setting-section">
|
||||
<!-- Special Switch Fields -->
|
||||
<CustomSwitch
|
||||
v-for="item in switchFieldsSpecialList"
|
||||
:key="item.configName"
|
||||
v-model="form[item.configName]"
|
||||
:segments="item.segments"
|
||||
:tooltip="item.tooltip"
|
||||
:config-name="item.configName"
|
||||
/>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span style="position: absolute; left: 0">
|
||||
{{ $t('MANAGE_SETTING_MAX_DOWNLOAD_FILE_SIZE_TITLE') }}
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('MANAGE_SETTING_MAX_DOWNLOAD_FILE_SIZE_TIPS')"
|
||||
placement="right"
|
||||
:persistent="false"
|
||||
teleported
|
||||
>
|
||||
<el-icon>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Download Settings Card -->
|
||||
<div class="setting-card content-card">
|
||||
<div class="card-content">
|
||||
<div class="setting-section">
|
||||
<!-- Max Download File Count -->
|
||||
<div class="form-group">
|
||||
<div class="form-label-wrapper">
|
||||
<span class="form-label">
|
||||
{{ t('pages.manage.setting.maxDownLoadFileLimit') }}
|
||||
</span>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="form.maxDownloadFileCount"
|
||||
style="position: absolute; right: 0"
|
||||
:placeholder="$t('MANAGE_SETTING_MAX_DOWNLOAD_FILE_SIZE_INPUT_TIPS')"
|
||||
:min="1"
|
||||
:max="9999"
|
||||
:step="1"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span style="position: absolute; left: 0">
|
||||
{{ $t('MANAGE_SETTING_PRESIGNED_URL_EXPIRE_TITLE') }}
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('MANAGE_SETTING_PRESIGNED_URL_EXPIRE_TIPS')"
|
||||
placement="right"
|
||||
:persistent="false"
|
||||
teleported
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<input
|
||||
v-model.number="form.maxDownloadFileCount"
|
||||
type="number"
|
||||
class="form-input number-input"
|
||||
:placeholder="t('pages.manage.setting.maxDownLoadFileLimitDesc')"
|
||||
min="1"
|
||||
max="9999"
|
||||
step="1"
|
||||
>
|
||||
<el-icon>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PreSigned URL Expire -->
|
||||
<div class="form-group">
|
||||
<div class="form-label-wrapper">
|
||||
<span class="form-label">
|
||||
{{ t('pages.manage.setting.preSignedUrlExpire') }}
|
||||
</span>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="form.PreSignedExpire"
|
||||
style="position: absolute; right: 0"
|
||||
:placeholder="$t('MANAGE_SETTING_PRESIGNED_URL_EXPIRE_TIPS')"
|
||||
:min="1"
|
||||
:step="1"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-link
|
||||
style="margin-top: 10px; margin-bottom: 10px; color: #409eff"
|
||||
:underline="false"
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<input
|
||||
v-model.number="form.PreSignedExpire"
|
||||
type="number"
|
||||
class="form-input number-input"
|
||||
:placeholder="t('pages.manage.setting.preSignedUrlExpireDesc')"
|
||||
min="1"
|
||||
step="1"
|
||||
>
|
||||
{{ $t('MANAGE_SETTING_CHOOSE_COPY_FORMAT_TITLE') }}
|
||||
</el-link>
|
||||
<br>
|
||||
<el-radio-group v-model="form.pasteFormat">
|
||||
<el-radio
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Copy Format Card -->
|
||||
<div class="setting-card content-card">
|
||||
<div class="card-content">
|
||||
<div class="setting-section">
|
||||
<div class="section-header">
|
||||
<h4 class="section-title">
|
||||
{{ t('pages.manage.setting.copyFormat.title') }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="radio-group">
|
||||
<label
|
||||
v-for="item in pasteFormatList"
|
||||
:key="item"
|
||||
class="radio-option"
|
||||
>
|
||||
<input
|
||||
v-model="form.pasteFormat"
|
||||
type="radio"
|
||||
:value="item"
|
||||
class="radio-input"
|
||||
>
|
||||
{{ $t(`MANAGE_SETTING_CHOOSE_COPY_FORMAT_${item.toUpperCase().replace(/-/g, '_')}` as any) }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<el-link
|
||||
v-if="form.pasteFormat === 'custom'"
|
||||
style="margin-top: 10px; margin-bottom: 10px; color: #409eff"
|
||||
:underline="false"
|
||||
>
|
||||
{{ $t('MANAGE_SETTING_CUSTOM_COPY_FORMAT_TITLE') }}
|
||||
</el-link>
|
||||
<el-input
|
||||
v-if="form.pasteFormat === 'custom'"
|
||||
v-model="form.customPasteFormat"
|
||||
:placeholder="$t('MANAGE_SETTING_CUSTOM_COPY_FORMAT_TIPS')"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div>
|
||||
<el-link
|
||||
style="margin-top: 10px; margin-bottom: 10px; color: #409eff"
|
||||
:underline="false"
|
||||
>
|
||||
{{ $t('MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_TITLE') }}
|
||||
</el-link>
|
||||
<span class="radio-custom" />
|
||||
<span class="radio-text">
|
||||
{{ t(`pages.manage.setting.copyFormat.${item}`) }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<el-input
|
||||
v-model="form.downloadDir"
|
||||
disabled
|
||||
:placeholder="$t('MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_TIPS')"
|
||||
style="width: 100%; margin-top: 10px"
|
||||
|
||||
<!-- Custom Copy Format -->
|
||||
<div
|
||||
class="form-group"
|
||||
>
|
||||
<template #append>
|
||||
<el-button
|
||||
type="primary"
|
||||
<div class="form-label-wrapper">
|
||||
<span class="form-label">
|
||||
{{ t('pages.manage.setting.copyFormat.customTitle') }}
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="form.customPasteFormat"
|
||||
type="text"
|
||||
class="form-input"
|
||||
:placeholder="t('pages.manage.setting.copyFormat.customTips')"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Download Folder Card -->
|
||||
<div class="setting-card content-card">
|
||||
<div class="card-content">
|
||||
<div class="setting-section">
|
||||
<div class="section-header">
|
||||
<h4 class="section-title">
|
||||
{{ t('pages.manage.setting.selectDownloadFolderTitle') }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input
|
||||
v-model="form.downloadDir"
|
||||
type="text"
|
||||
class="form-input group-input"
|
||||
disabled
|
||||
:placeholder="t('pages.manage.setting.defaultDownloadFolder')"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="input-append-button"
|
||||
@click="handleDownloadDirClick"
|
||||
>
|
||||
<el-icon>
|
||||
<Folder />
|
||||
</el-icon>
|
||||
{{ $t('MANAGE_SETTING_CHOOSE_DOWNLOAD_FOLDER_BUTTON') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form>
|
||||
<el-divider border-style="none" />
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<FolderIcon :size="16" />
|
||||
{{ t('pages.manage.setting.browse') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Folder, InfoFilled } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { FolderIcon, Trash2Icon } from 'lucide-vue-next'
|
||||
import { onBeforeMount, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import DynamicSwitch from '@/manage/components/DynamicSwitch.vue'
|
||||
import useConfirm from '@/hooks/useConfirm'
|
||||
import useMessage from '@/hooks/useMessage'
|
||||
import CustomSwitch from '@/manage/components/CustomSwitch.vue'
|
||||
import { fileCacheDbInstance } from '@/manage/store/bucketFileDb'
|
||||
import { customRenameFormatTable, formatFileSize } from '@/manage/utils/common'
|
||||
import { getConfig, saveConfig } from '@/manage/utils/dataSender'
|
||||
@@ -236,13 +255,14 @@ import { IRPCActionType } from '@/utils/enum'
|
||||
import type { IStringKeyMap } from '#/types/types'
|
||||
|
||||
const { t } = useI18n()
|
||||
const message = useMessage()
|
||||
const { confirm } = useConfirm()
|
||||
const form = ref<IStringKeyMap>({
|
||||
timestampRename: false,
|
||||
randomStringRename: false,
|
||||
customRename: false,
|
||||
isAutoRefresh: false,
|
||||
isShowThumbnail: false,
|
||||
isShowList: false,
|
||||
isUsePreSignedUrl: false,
|
||||
isIgnoreCase: false,
|
||||
isForceCustomUrlHttps: false,
|
||||
@@ -275,7 +295,6 @@ settingsKeys.forEach(key => {
|
||||
const switchFieldsList = [
|
||||
'isAutoRefresh',
|
||||
'isShowThumbnail',
|
||||
'isShowList',
|
||||
'isUsePreSignedUrl',
|
||||
'isForceCustomUrlHttps',
|
||||
'isEncodeUrl',
|
||||
@@ -285,23 +304,23 @@ const switchFieldsList = [
|
||||
'randomStringRename',
|
||||
'customRename'
|
||||
]
|
||||
const switchFieldsNoTipsList = ['isShowThumbnail', 'isShowList', 'isUsePreSignedUrl']
|
||||
const switchFieldsHasActiveTextList = ['isShowList']
|
||||
const switchFieldsNoTipsList = ['isShowThumbnail', 'isUsePreSignedUrl']
|
||||
const switchFieldsHasActiveTextList = [] as string[]
|
||||
|
||||
const switchFieldsConfigList = switchFieldsList.map(item => ({
|
||||
configName: item,
|
||||
segments: [
|
||||
{
|
||||
text: t(`MANAGE_SETTING_${item.toUpperCase()}_TITLE` as any),
|
||||
style: 'color: black;'
|
||||
text: t(`pages.manage.setting.${item}Title` as any),
|
||||
style: 'color: var(--color-text-primary);'
|
||||
}
|
||||
],
|
||||
tooltip: switchFieldsNoTipsList.includes(item) ? undefined : t(`MANAGE_SETTING_${item.toUpperCase()}_TIPS` as any),
|
||||
tooltip: switchFieldsNoTipsList.includes(item) ? undefined : t(`pages.manage.setting.${item}Tips` as any),
|
||||
activeText: switchFieldsHasActiveTextList.includes(item)
|
||||
? t(`MANAGE_SETTING_${item.toUpperCase()}_ON` as any)
|
||||
? t(`pages.manage.setting.${item}On` as any)
|
||||
: undefined,
|
||||
inactiveText: switchFieldsHasActiveTextList.includes(item)
|
||||
? t(`MANAGE_SETTING_${item.toUpperCase()}_OFF` as any)
|
||||
? t(`pages.manage.setting.${item}Off` as any)
|
||||
: undefined
|
||||
}))
|
||||
|
||||
@@ -310,37 +329,37 @@ const switchFieldsSpecialList = [
|
||||
configName: 'isDownloadFileKeepDirStructure',
|
||||
segments: [
|
||||
{
|
||||
text: t('MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_A'),
|
||||
style: 'color: black;'
|
||||
text: t('pages.manage.setting.download'),
|
||||
style: 'color: var(--color-text-primary);'
|
||||
},
|
||||
{
|
||||
text: t('MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_B'),
|
||||
text: t('pages.manage.setting.file'),
|
||||
style: 'color: orange;'
|
||||
},
|
||||
{
|
||||
text: t('MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_C'),
|
||||
style: 'color: black;'
|
||||
text: t('pages.manage.setting.keepDirStructure'),
|
||||
style: 'color: var(--color-text-primary);'
|
||||
}
|
||||
],
|
||||
tooltip: t('MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TIPS')
|
||||
tooltip: t('pages.manage.setting.keepDirStructureDesc')
|
||||
},
|
||||
{
|
||||
configName: 'isDownloadFolderKeepDirStructure',
|
||||
segments: [
|
||||
{
|
||||
text: t('MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_A'),
|
||||
style: 'color: black;'
|
||||
text: t('pages.manage.setting.download'),
|
||||
style: 'color: var(--color-text-primary);'
|
||||
},
|
||||
{
|
||||
text: t('MANAGE_SETTING_ISDOWNLOADFOLDERKEEPDIRSTRUCTURE_TITLE_D'),
|
||||
style: 'color: coral;'
|
||||
text: t('pages.manage.setting.folder'),
|
||||
style: 'color: orange;'
|
||||
},
|
||||
{
|
||||
text: t('MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TITLE_C'),
|
||||
style: 'color: black;'
|
||||
text: t('pages.manage.setting.keepDirStructure'),
|
||||
style: 'color: var(--color-text-primary);'
|
||||
}
|
||||
],
|
||||
tooltip: t('MANAGE_SETTING_ISDOWNLOADFILEKEEPDIRSTRUCTURE_TIPS')
|
||||
tooltip: t('pages.manage.setting.keepDirStructureDesc')
|
||||
}
|
||||
]
|
||||
|
||||
@@ -360,18 +379,33 @@ async function handleDownloadDirClick () {
|
||||
|
||||
const handleCellClick = (row: any, column: any) => {
|
||||
navigator.clipboard.writeText(row[column.property])
|
||||
ElMessage.success(`${t('MANAGE_SETTING_COPY_MESSAGE')}${row[column.property]}`)
|
||||
message.success(`${t('pages.manage.setting.copySuccess', { name: row[column.property] })}`)
|
||||
}
|
||||
|
||||
function handleClearDb () {
|
||||
function handleConfirmClearDb () {
|
||||
confirm({
|
||||
title: t('pages.manage.setting.notice'),
|
||||
message: t('pages.manage.setting.clearCacheMsg'),
|
||||
type: 'warning',
|
||||
confirmButtonText: t('common.confirm'),
|
||||
cancelButtonText: t('common.cancel'),
|
||||
center: true
|
||||
}).then(result => {
|
||||
if (result) {
|
||||
confirmClearDb()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function confirmClearDb () {
|
||||
fileCacheDbInstance
|
||||
.delete()
|
||||
.then(() => {
|
||||
getIndexDbSize()
|
||||
ElMessage.success(t('MANAGE_SETTING_CLEAR_CACHE_SUCCESS'))
|
||||
message.success(t('pages.manage.setting.clearSuccess'))
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.error(t('MANAGE_SETTING_CLEAR_CACHE_FAILED'))
|
||||
message.error(t('pages.manage.setting.clearFailed'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -388,8 +422,4 @@ onBeforeMount(() => {
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
#manage-setting
|
||||
height 100%
|
||||
overflow-y auto
|
||||
</style>
|
||||
<style scoped src="./css/ManageSetting.css"></style>
|
||||
|
||||
1272
src/renderer/manage/pages/css/BucketPage.css
Normal file
1272
src/renderer/manage/pages/css/BucketPage.css
Normal file
File diff suppressed because it is too large
Load Diff
647
src/renderer/manage/pages/css/ManageMain.css
Normal file
647
src/renderer/manage/pages/css/ManageMain.css
Normal file
@@ -0,0 +1,647 @@
|
||||
/* ManageMain Page Styles */
|
||||
|
||||
.manage-container {
|
||||
height: 97%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.manage-card {
|
||||
background: var(--color-background-secondary);
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--color-border);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.header-card {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
width: 68px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.header-icon-img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.header-text .header-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
margin: 0 0 0.01rem 0;
|
||||
}
|
||||
|
||||
.header-text .header-subtitle {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.main-card {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
min-height: 0; /* Fix for flex overflow */
|
||||
}
|
||||
|
||||
.main-layout {
|
||||
display: flex;
|
||||
height:99%;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 160px;
|
||||
background: var(--color-surface-secondary);
|
||||
border-right: 1px solid var(--color-border);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0; /* Fix for flex overflow */
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 1rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0.5rem;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid var(--color-border);
|
||||
border-top: 2px solid var(--color-accent);
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.menu-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem;
|
||||
border-radius: var(--radius-md);
|
||||
cursor: pointer;
|
||||
transition: var(--transition-fast);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
background: var(--color-surface);
|
||||
}
|
||||
|
||||
.menu-item.active {
|
||||
background: var(--color-accent);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.menu-item.active .menu-icon {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--color-text-secondary);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.menu-icon.active {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.menu-text {
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
border-top: 1px solid var(--color-border);
|
||||
padding: 0.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.footer-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.footer-action-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem;
|
||||
border-radius: var(--radius-md);
|
||||
cursor: pointer;
|
||||
transition: var(--transition-fast);
|
||||
font-size: 0.875rem;
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--color-text-primary);
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer-action-item:hover {
|
||||
background: var(--color-surface);
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--color-text-secondary);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.action-text {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.content-area {
|
||||
flex: 1;
|
||||
padding: 1.5rem;
|
||||
overflow-y: auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: var(--radius-lg);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: var(--transition-fast);
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.action-button.primary {
|
||||
background: var(--color-accent);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.action-button.primary:hover {
|
||||
background: var(--color-accent-hover);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.action-button.secondary {
|
||||
background: var(--color-surface-elevated);
|
||||
color: var(--color-text-primary);
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.action-button.secondary:hover {
|
||||
background: var(--color-surface);
|
||||
border-color: var(--color-accent);
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.button-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/* Dialog styles */
|
||||
.dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.dialog-container {
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--color-border);
|
||||
box-shadow: var(--shadow-xl);
|
||||
max-width: 600px;
|
||||
width: 90%;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
padding: 1.5rem 1.5rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dialog-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
padding: 0.25rem;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius-sm);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.dialog-close:hover {
|
||||
background: var(--color-surface-elevated);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.choice-cos {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.picbed-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
cursor: pointer;
|
||||
transition: var(--transition-fast);
|
||||
position: relative;
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.picbed-card:hover {
|
||||
border-color: var(--color-accent);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.picbed-card.active {
|
||||
border-color: var(--color-accent);
|
||||
background-color: rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
|
||||
.picbed-card.main-card {
|
||||
border-color: var(--color-error);
|
||||
}
|
||||
|
||||
.picbed-card.main-card:hover {
|
||||
border-color: var(--color-error);
|
||||
background-color: rgba(255, 59, 48, 0.1);
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.picbed-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.main-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: var(--color-error);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.main-title {
|
||||
color: var(--color-error);
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
/* Drawer styles */
|
||||
.drawer-overlay {
|
||||
position: fixed;
|
||||
top: 32px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.drawer-container {
|
||||
background: var(--color-surface);
|
||||
height: 100vh;
|
||||
width: 400px;
|
||||
max-width: 90vw;
|
||||
overflow-y: auto;
|
||||
box-shadow: var(--shadow-xl);
|
||||
}
|
||||
|
||||
.drawer-header {
|
||||
padding: 1.5rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.drawer-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.drawer-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
padding: 0.25rem;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius-sm);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.drawer-close:hover {
|
||||
background: var(--color-surface-elevated);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.drawer-content {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.form-header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.form-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.picbed-form-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.form-divider {
|
||||
height: 1px;
|
||||
background: var(--color-border);
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-surface-elevated);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 0.875rem;
|
||||
transition: var(--transition-fast);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-accent);
|
||||
box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.2);
|
||||
}
|
||||
|
||||
.input-group {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.group-input {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.input-append {
|
||||
padding: 0.75rem;
|
||||
background: var(--color-background-secondary);
|
||||
border: 1px solid var(--color-border);
|
||||
border-left: none;
|
||||
border-top-right-radius: var(--radius-md);
|
||||
border-bottom-right-radius: var(--radius-md);
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.select-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form-select {
|
||||
width: 100%;
|
||||
padding: 0.75rem 2.5rem 0.75rem 0.75rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-surface-elevated);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 0.875rem;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.form-select:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-accent);
|
||||
box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.2);
|
||||
}
|
||||
|
||||
.select-arrow {
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--color-text-secondary);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.switch-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switch-input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switch-slider {
|
||||
position: relative;
|
||||
width: 3rem;
|
||||
height: 1.5rem;
|
||||
background: var(--color-border);
|
||||
border-radius: 0.75rem;
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.switch-button {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
transition: var(--transition-fast);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider {
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.switch-input:checked + .switch-slider .switch-button {
|
||||
transform: translateX(1.5rem);
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 2rem;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
515
src/renderer/manage/pages/css/ManageSetting.css
Normal file
515
src/renderer/manage/pages/css/ManageSetting.css
Normal file
@@ -0,0 +1,515 @@
|
||||
/* Container */
|
||||
.manage-setting-container {
|
||||
padding: 1rem;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Card Base */
|
||||
.setting-card {
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border-secondary);
|
||||
border-radius: var(--radius-xl);
|
||||
overflow: hidden;
|
||||
transition: var(--transition-medium);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.setting-card:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
|
||||
/* Header Card */
|
||||
.header-card .card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 1.5rem;
|
||||
border-bottom: 1px solid var(--color-border-secondary);
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
color: var(--color-blue-common);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-content h1 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
margin: 0;
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
.header-content p {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* Action Button Base */
|
||||
.action-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-surface-elevated);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
transition: var(--transition-fast);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.action-button:hover {
|
||||
background: var(--color-background-secondary);
|
||||
border-color: var(--color-border-darker);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.action-button:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.action-button.primary {
|
||||
background: var(--color-blue-common);
|
||||
color: white;
|
||||
border-color: var(--color-blue-common);
|
||||
}
|
||||
|
||||
.action-button.primary:hover {
|
||||
background: var(--color-accent);
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.action-button.secondary {
|
||||
background: var(--color-background-secondary);
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.action-button.warning {
|
||||
background: var(--color-warning);
|
||||
color: white;
|
||||
border-color: var(--color-warning);
|
||||
}
|
||||
|
||||
.action-button.warning:hover {
|
||||
background: var(--color-warning);
|
||||
border-color: var(--color-warning);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.action-button .button-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/* Content Cards */
|
||||
.content-card {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 1.25rem;
|
||||
}
|
||||
|
||||
/* Setting sections with reduced spacing */
|
||||
.setting-section {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.setting-section + .setting-section {
|
||||
margin-top: 1rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid var(--color-border-secondary);
|
||||
}
|
||||
|
||||
/* Form Groups */
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-label-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-surface-elevated);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 0.875rem;
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-accent);
|
||||
box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.2);
|
||||
}
|
||||
|
||||
.form-input:disabled {
|
||||
background: var(--color-background-secondary);
|
||||
color: var(--color-text-tertiary);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.number-input {
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
/* Cache Info */
|
||||
.cache-info {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-text-secondary);
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.cache-size {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Section Headers */
|
||||
.section-header {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-accent);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Pattern Table */
|
||||
.pattern-table-container {
|
||||
margin-top: 0.75rem;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.pattern-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.pattern-table th {
|
||||
background: var(--color-background-secondary);
|
||||
padding: 0.5rem;
|
||||
border: 1px solid var(--color-border);
|
||||
font-weight: 500;
|
||||
color: var(--color-text-primary);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pattern-table td {
|
||||
padding: 0.5rem;
|
||||
border: 1px solid var(--color-border);
|
||||
color: var(--color-text-secondary);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pattern-table td.clickable {
|
||||
cursor: pointer;
|
||||
color: var(--color-accent);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.pattern-table td.clickable:hover {
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
/* Radio Groups */
|
||||
.radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.radio-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
padding: 0.625rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
transition: var(--transition-fast);
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
.radio-option:hover {
|
||||
border-color: var(--color-accent);
|
||||
background: var(--color-surface);
|
||||
}
|
||||
|
||||
.radio-input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.radio-custom {
|
||||
position: relative;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
border: 2px solid var(--color-border);
|
||||
border-radius: 50%;
|
||||
background: var(--color-surface-elevated);
|
||||
transition: var(--transition-fast);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.radio-custom::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-accent);
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.radio-input:checked + .radio-custom {
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.radio-input:checked + .radio-custom::after {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
|
||||
.radio-text {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-primary);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Input Groups */
|
||||
.input-group {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.group-input {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.input-append-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--color-accent);
|
||||
color: white;
|
||||
border: none;
|
||||
border-top-right-radius: var(--radius-md);
|
||||
border-bottom-right-radius: var(--radius-md);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.input-append-button:hover {
|
||||
background: var(--color-accent-hover);
|
||||
}
|
||||
|
||||
/* Dialog Styles */
|
||||
.dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.dialog-container {
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--color-border);
|
||||
box-shadow: var(--shadow-xl);
|
||||
max-width: 400px;
|
||||
width: 90%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
padding: 1.5rem 1.5rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dialog-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
padding: 0.25rem;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius-sm);
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.dialog-close:hover {
|
||||
background: var(--color-surface-elevated);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.confirm-message {
|
||||
color: var(--color-text-secondary);
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
padding: 0 1.5rem 1.5rem;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* Dark mode adjustments */
|
||||
:root.dark .manage-setting-container,
|
||||
:root.auto.dark .manage-setting-container {
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
|
||||
:root.dark .form-input,
|
||||
:root.auto.dark .form-input {
|
||||
background: var(--color-surface-elevated);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
|
||||
:root.dark .radio-custom,
|
||||
:root.auto.dark .radio-custom {
|
||||
background: var(--color-surface-elevated);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
|
||||
:root.dark .pattern-table th,
|
||||
:root.auto.dark .pattern-table th {
|
||||
background: var(--color-surface-elevated);
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.manage-setting-container {
|
||||
padding: 0.75rem;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.header-card .card-header {
|
||||
padding: 1rem;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.pattern-table {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.pattern-table th,
|
||||
.pattern-table td {
|
||||
padding: 0.375rem;
|
||||
}
|
||||
|
||||
.radio-option {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
padding: 0.625rem;
|
||||
}
|
||||
}
|
||||
@@ -613,7 +613,7 @@ small {
|
||||
/* Dark mode adjustments */
|
||||
:root.dark .piclist-settings,
|
||||
:root.auto.dark .piclist-settings {
|
||||
background: var(--color-background-primary);
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
|
||||
:root.dark .settings-header,
|
||||
|
||||
Reference in New Issue
Block a user