From 5ce239764136c42b2db6383faef70ea6adae7e9d Mon Sep 17 00:00:00 2001 From: Kuingsmile <96409857+Kuingsmile@users.noreply.github.com> Date: Wed, 31 Dec 2025 13:51:09 +0800 Subject: [PATCH] :sparkles: Feature(custom): optimize picbed config edit page --- src/renderer/i18n/locales/en.json | 8 +- src/renderer/i18n/locales/zh-CN.json | 6 +- src/renderer/i18n/locales/zh-TW.json | 6 +- src/renderer/pages/picbeds/Picbeds.css | 586 ++++++++++++++++++++++++ src/renderer/pages/picbeds/index.vue | 611 +++++-------------------- 5 files changed, 712 insertions(+), 505 deletions(-) create mode 100644 src/renderer/pages/picbeds/Picbeds.css diff --git a/src/renderer/i18n/locales/en.json b/src/renderer/i18n/locales/en.json index d6073247..d5a50ac8 100644 --- a/src/renderer/i18n/locales/en.json +++ b/src/renderer/i18n/locales/en.json @@ -585,6 +585,7 @@ } }, "picBedConfigs": { + "configSettings": "Configuration Settings", "copyAPI": "Copy Upload API", "copyAPIFailed": "Copy API Address Failed", "copyAPISucceed": "Copy API Address Succeed", @@ -592,14 +593,15 @@ "importConfigSuccess": "Import Config Success", "loadConfigFailed": "Load Config Failed, Please Check If Config File Is Correct", "loadPicBedListFailed": "Load PicBed List Failed", - "noConfigOptions": "No Config Options", + "noConfigOptions": "No Configuration Options", + "noConfigOptionsDesc": "This uploader does not have any configuration options available.", "noConfigs": "No Configs", "resetFailed": "Reset Failed, Please Check If Config Options Are Correct", "resetSuccess": "Reset Success", + "selectConfig": "Select Configuration", "setFailedInfo": "Set Failed, Please Check If Config Options Are Correct", "setSuccess": "Set Success", - "title": "Config", - "viewDoc": "View Document", + "viewDoc": "Documentation", "viewDocFailed": "View Document Failed" }, "plugin": { diff --git a/src/renderer/i18n/locales/zh-CN.json b/src/renderer/i18n/locales/zh-CN.json index 1ae676e5..1caf26d7 100644 --- a/src/renderer/i18n/locales/zh-CN.json +++ b/src/renderer/i18n/locales/zh-CN.json @@ -585,6 +585,7 @@ } }, "picBedConfigs": { + "configSettings": "配置设置", "copyAPI": "复制上传API", "copyAPIFailed": "复制API地址失败", "copyAPISucceed": "复制API地址成功", @@ -593,13 +594,14 @@ "loadConfigFailed": "加载配置失败, 请检查配置文件是否正确", "loadPicBedListFailed": "加载图床列表失败", "noConfigOptions": "暂无配置项", + "noConfigOptionsDesc": "该上传器没有可用的配置选项。", "noConfigs": "配置为空", "resetFailed": "重置失败, 请检查配置项是否正确", "resetSuccess": "重置成功", + "selectConfig": "选择配置", "setFailedInfo": "设置失败, 请检查配置项是否正确", "setSuccess": "设置成功", - "title": "配置", - "viewDoc": "查看文档", + "viewDoc": "文档", "viewDocFailed": "查看文档失败" }, "plugin": { diff --git a/src/renderer/i18n/locales/zh-TW.json b/src/renderer/i18n/locales/zh-TW.json index b238988c..5bfd3d66 100644 --- a/src/renderer/i18n/locales/zh-TW.json +++ b/src/renderer/i18n/locales/zh-TW.json @@ -585,6 +585,7 @@ } }, "picBedConfigs": { + "configSettings": "配置設定", "copyAPI": "複製上傳API", "copyAPIFailed": "複製 API 位址失敗", "copyAPISucceed": "複製 API 位址成功", @@ -593,13 +594,14 @@ "loadConfigFailed": "載入配置失敗,請檢查配置文件是否正確", "loadPicBedListFailed": "載入圖床列表失敗", "noConfigOptions": "暫無配置項", + "noConfigOptionsDesc": "該上傳器沒有可用的配置選項。", "noConfigs": "配置為空", "resetFailed": "重設失敗,請檢查配置項是否正確", "resetSuccess": "重設成功", + "selectConfig": "選擇配置", "setFailedInfo": "設定失敗,請檢查配置項是否正確", "setSuccess": "設定成功", - "title": "配置", - "viewDoc": "查看文件", + "viewDoc": "文檔", "viewDocFailed": "查看文件失敗" }, "plugin": { diff --git a/src/renderer/pages/picbeds/Picbeds.css b/src/renderer/pages/picbeds/Picbeds.css new file mode 100644 index 00000000..f7797668 --- /dev/null +++ b/src/renderer/pages/picbeds/Picbeds.css @@ -0,0 +1,586 @@ +/* Page Container */ +.picbeds-page { + position: relative; + overflow: hidden auto; + min-height: 100vh; + background: var(--color-background); +} + +/* Ambient Background Effect */ +.ambient-bg { + position: fixed; + top: -50%; + left: -50%; + z-index: 0; + width: 200%; + height: 200%; + background: + radial-gradient(circle at 30% 20%, rgb(var(--accent-rgb) / 8%) 0%, transparent 50%), + radial-gradient(circle at 70% 80%, rgb(16 185 129 / 6%) 0%, transparent 50%), + radial-gradient(circle at 50% 50%, rgb(59 130 246 / 4%) 0%, transparent 40%); + animation: ambient-drift 25s ease-in-out infinite; + pointer-events: none; +} + +@keyframes ambient-drift { + 0%, + 100% { + transform: translate(0, 0) rotate(0deg); + } + + 33% { + transform: translate(2%, -1%) rotate(1deg); + } + + 66% { + transform: translate(-1%, 2%) rotate(-0.5deg); + } +} + +/* Main Container */ +.page-container { + position: relative; + z-index: 1; + display: flex; + margin: 0 auto; + padding: 2rem; + max-width: 1000px; + flex-direction: column; + gap: 1.5rem; +} + +.page-header { + display: flex; + justify-content: space-between; + align-items: center; + border: 1px solid rgb(var(--accent-rgb) / 15%); + border-radius: 20px; + padding: 1.5rem 2rem; + background: linear-gradient( + 135deg, + rgb(var(--accent-rgb) / 6%) 0%, + var(--color-surface) 50%, + rgb(16 185 129 / 4%) 100% + ); + box-shadow: + 0 4px 24px rgb(0 0 0 / 8%), + 0 1px 2px rgb(0 0 0 / 4%), + inset 0 1px 0 rgb(255 255 255 / 5%); + backdrop-filter: blur(10px); + flex-wrap: wrap; + gap: 1.5rem; +} + +.header-content { + display: flex; + align-items: center; + gap: 1rem; +} + +.header-icon { + display: flex; + justify-content: center; + align-items: center; + border-radius: 14px; + width: 56px; + height: 56px; + color: var(--color-accent); + background: linear-gradient(135deg, rgb(var(--accent-rgb) / 20%) 0%, rgb(var(--accent-rgb) / 10%) 100%); + box-shadow: + 0 4px 12px rgb(var(--accent-rgb) / 20%), + inset 0 1px 0 rgb(255 255 255 / 10%); +} + +.header-text { + display: flex; + flex-direction: column; + gap: 0.25rem; +} + +.title-row { + display: flex; + align-items: center; + gap: 0.75rem; +} + +.page-title { + margin: 0; + font-size: 1.5rem; + font-weight: 700; + color: var(--color-text-primary); + letter-spacing: -0.025em; +} + +.page-subtitle { + margin: 0; + font-size: 0.875rem; + color: var(--color-text-secondary); +} + +.doc-link-btn { + display: inline-flex; + align-items: center; + border: 1px solid rgb(var(--accent-rgb) / 20%); + border-radius: 8px; + padding: 0.375rem 0.75rem; + font-size: 0.75rem; + font-weight: 500; + color: var(--color-accent); + background: rgb(var(--accent-rgb) / 8%); + transition: all 0.2s ease; + gap: 0.375rem; + cursor: pointer; +} + +.doc-link-btn:hover { + border-color: var(--color-accent); + background: rgb(var(--accent-rgb) / 15%); + transform: translateY(-1px); +} + +.header-actions { + display: flex; + gap: 0.75rem; +} + +.btn { + position: relative; + display: inline-flex; + justify-content: center; + align-items: center; + overflow: hidden; + border: none; + border-radius: 12px; + padding: 0.75rem 1.25rem; + font-size: 0.875rem; + font-family: inherit; + font-weight: 600; + transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); + gap: 0.5rem; + cursor: pointer; +} + +.btn-secondary { + color: var(--color-text-primary); + background: var(--color-surface-elevated); + box-shadow: + 0 2px 8px rgb(0 0 0 / 8%), + inset 0 1px 0 rgb(255 255 255 / 5%); +} + +.btn-secondary:hover { + background: var(--color-surface); + transform: translateY(-2px); + box-shadow: + 0 4px 16px rgb(0 0 0 / 12%), + inset 0 1px 0 rgb(255 255 255 / 8%); +} + +.btn-outline { + border: 1px solid var(--color-border); + color: var(--color-text-secondary); + background: transparent; +} + +.btn-outline:hover { + border-color: var(--color-text-secondary); + color: var(--color-text-primary); + background: var(--color-surface-elevated); + transform: translateY(-1px); +} + +.btn-success { + color: white; + background: linear-gradient(135deg, #10b981 0%, #059669 100%); + box-shadow: + 0 4px 14px rgb(16 185 129 / 35%), + 0 2px 4px rgb(0 0 0 / 10%), + inset 0 1px 0 rgb(255 255 255 / 15%); +} + +.btn-success:hover { + transform: translateY(-2px); + box-shadow: + 0 8px 24px rgb(16 185 129 / 45%), + 0 4px 8px rgb(0 0 0 / 15%), + inset 0 1px 0 rgb(255 255 255 / 20%); +} + +.btn-warning { + color: white; + background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); + box-shadow: + 0 4px 14px rgb(245 158 11 / 35%), + 0 2px 4px rgb(0 0 0 / 10%), + inset 0 1px 0 rgb(255 255 255 / 15%); +} + +.btn-warning:hover { + transform: translateY(-2px); + box-shadow: + 0 8px 24px rgb(245 158 11 / 45%), + 0 4px 8px rgb(0 0 0 / 15%); +} + +.btn-glow::before { + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent 0%, rgb(255 255 255 / 20%) 50%, transparent 100%); + transition: left 0.5s ease; + content: ''; +} + +.btn-glow:hover::before { + left: 100%; +} + +.main-content { + flex: 1; +} + +/* Config Card */ +.config-card { + overflow: hidden; + border: 1px solid var(--color-border-secondary); + border-radius: 20px; + background: var(--color-surface); + box-shadow: + 0 4px 24px rgb(0 0 0 / 6%), + 0 1px 2px rgb(0 0 0 / 4%); + animation: card-enter 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} + +@keyframes card-enter { + from { + opacity: 0; + transform: translateY(20px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +.card-header { + display: flex; + align-items: center; + border-bottom: 1px solid var(--color-border-secondary); + padding: 1.25rem 1.5rem; + background: var(--color-surface-elevated); + gap: 0.75rem; +} + +.card-header-icon { + display: flex; + justify-content: center; + align-items: center; + border-radius: 10px; + width: 36px; + height: 36px; + color: var(--color-accent); + background: rgb(var(--accent-rgb) / 12%); +} + +.card-title { + margin: 0; + font-size: 1rem; + font-weight: 600; + color: var(--color-text-primary); +} + +.card-body { + padding: 1.5rem; +} + +/* Action Buttons */ +.action-buttons { + display: flex; + margin-top: 2rem; + border-top: 1px solid var(--color-border-secondary); + padding-top: 1.5rem; + gap: 0.75rem; + flex-wrap: wrap; +} + +.dropdown-wrapper { + position: relative; +} + +.dropdown-trigger { + position: relative; +} + +.dropdown-chevron { + margin-left: 0.25rem; + transition: transform 0.2s ease; +} + +.dropdown-chevron.rotated { + transform: rotate(180deg); +} + +.dropdown-menu { + position: absolute; + right: 0; + bottom: calc(100% + 8px); + z-index: 1000; + overflow: hidden; + border: 1px solid var(--color-border); + border-radius: 14px; + min-width: 220px; + background: var(--color-surface); + box-shadow: + 0 -12px 40px rgb(0 0 0 / 15%), + 0 -4px 12px rgb(0 0 0 / 8%); +} + +.dropdown-header { + padding: 0.75rem 1rem; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + color: var(--color-text-tertiary); + background: var(--color-surface-elevated); + letter-spacing: 0.05em; +} + +.dropdown-items { + overflow-y: auto; + max-height: 250px; +} + +.dropdown-item { + display: flex; + align-items: center; + border: none; + padding: 0.75rem 1rem; + width: 100%; + font-size: 0.875rem; + text-align: left; + color: var(--color-text-primary); + background: transparent; + transition: all 0.15s ease; + gap: 0.625rem; + cursor: pointer; +} + +.dropdown-item:hover { + color: var(--color-accent); + background: rgb(var(--accent-rgb) / 8%); +} + +.dropdown-item svg { + color: var(--color-text-tertiary); + transition: color 0.15s ease; +} + +.dropdown-item:hover svg { + color: var(--color-accent); +} + +/* Dropdown Transition */ +.dropdown-enter-active, +.dropdown-leave-active { + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); +} + +.dropdown-enter-from, +.dropdown-leave-to { + opacity: 0; + transform: translateY(8px) scale(0.95); +} + +.empty-state-card { + overflow: hidden; + border: 1px solid var(--color-border-secondary); + border-radius: 20px; + background: var(--color-surface); + box-shadow: 0 4px 24px rgb(0 0 0 / 6%); + animation: card-enter 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} + +.empty-state { + padding: 4rem 2rem; + text-align: center; +} + +.empty-icon-wrapper { + display: inline-flex; + justify-content: center; + align-items: center; + margin-bottom: 1.5rem; + border: 2px dashed var(--color-border); + border-radius: 20px; + width: 96px; + height: 96px; + color: var(--color-text-tertiary); + background: var(--color-surface-elevated); +} + +.empty-title { + margin: 0 0 0.5rem; + font-size: 1.25rem; + font-weight: 600; + color: var(--color-text-primary); +} + +.empty-description { + margin: 0; + font-size: 0.9rem; + color: var(--color-text-secondary); +} + +.loading-overlay { + position: fixed; + inset: 0; + z-index: 2000; + display: flex; + justify-content: center; + align-items: center; + background: rgb(0 0 0 / 60%); + backdrop-filter: blur(8px); +} + +.loading-content { + display: flex; + flex-direction: column; + align-items: center; + gap: 1.25rem; +} + +.loading-spinner { + position: relative; + display: flex; + justify-content: center; + align-items: center; + width: 64px; + height: 64px; +} + +.spinner-ring { + position: absolute; + inset: 0; + border: 3px solid rgb(255 255 255 / 15%); + border-top-color: white; + border-radius: 50%; + animation: spin 1s linear infinite; +} + +.spinner-icon { + color: white; + animation: pulse 2s ease-in-out infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +@keyframes pulse { + 0%, + 100% { + opacity: 0.6; + transform: scale(1); + } + + 50% { + opacity: 1; + transform: scale(1.1); + } +} + +.loading-text { + font-size: 0.9rem; + font-weight: 500; + color: white; +} + +/* Fade Transition */ +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.3s ease; +} + +.fade-enter-from, +.fade-leave-to { + opacity: 0; +} + +@media (width <= 768px) { + .page-container { + padding: 1rem; + gap: 1rem; + } + + .page-header { + align-items: stretch; + border-radius: 16px; + padding: 1.25rem; + flex-direction: column; + } + + .header-content { + justify-content: center; + text-align: center; + flex-direction: column; + } + + .header-icon { + width: 48px; + height: 48px; + } + + .title-row { + justify-content: center; + flex-wrap: wrap; + } + + .page-title { + font-size: 1.25rem; + } + + .header-actions { + justify-content: center; + } + + .config-card { + border-radius: 16px; + } + + .card-body { + padding: 1.25rem; + } + + .action-buttons { + flex-direction: column; + } + + .btn { + justify-content: center; + width: 100%; + } + + .dropdown-menu { + right: auto; + left: 0; + min-width: 100%; + } +} + +@media (width >= 1024px) { + .page-container { + padding: 2.5rem; + } +} + +.btn:focus-visible, +.doc-link-btn:focus-visible, +.dropdown-item:focus-visible { + outline: 1px solid var(--color-accent); + outline-offset: 2px; +} \ No newline at end of file diff --git a/src/renderer/pages/picbeds/index.vue b/src/renderer/pages/picbeds/index.vue index eca6c4ba..d3064023 100644 --- a/src/renderer/pages/picbeds/index.vue +++ b/src/renderer/pages/picbeds/index.vue @@ -1,101 +1,138 @@ - +