diff --git a/currentVersion.md b/currentVersion.md index af8cbb51..57199435 100644 --- a/currentVersion.md +++ b/currentVersion.md @@ -2,15 +2,16 @@ ### ✨ 新增功能 -- windows下新增便携模式,无需安装即可运行,数据存储在程序目录下的`data`文件夹中,支持自动更新 +- windows下新增便携模式,无需安装即可运行,数据存储在程序目录下的`data`文件夹中,支持自动更新;Linux下新增`rpm`安装包 - 新增自定义主题功能,主题仓库[PicList ThemeHub](https://github.com/Kuingsmile/PicList-ThemeHub) - 12个内置主题供选择,如bilibili、二次元、极夜紫、gemini等风格 - 相册页面多项优化,支持显示已选择图片数量,匹配的url列表和记忆过滤器打开状态 +- 插件页面现在可以浏览所有插件列表,查看详情和安装 - 新增教学引导页面,首次运行时会自动弹出 - 现在支持关闭GPU加速,解决部分兼容性问题 - 新增高级动画设置,开启后可获得更好的UI体验 -- Linux下新增rpm安装包 -- 优化了相册页面的加载速度 + +- 优化了多个页面的加载速度和浏览性能 ### 🐛 问题修复 diff --git a/currentVersion_en.md b/currentVersion_en.md index 39789212..b7d976c8 100644 --- a/currentVersion_en.md +++ b/currentVersion_en.md @@ -2,15 +2,15 @@ ### ✨ New Features -- Added portable mode on Windows, allowing the program to run without installation. Data is stored in the `data` folder within the program directory, and automatic updates are supported. +- Added portable mode on Windows, allowing the program to run without installation. Data is stored in the `data` folder within the program directory, and automatic updates are supported. Added `rpm` installation package for Linux - Added custom theme functionality, with a theme repository available at [PicList ThemeHub](https://github.com/Kuingsmile/PicList-ThemeHub) - 12 built-in themes available, such as bilibili, ACG, Night Purple, gemini styles - Multiple optimizations on the album page, supporting display of the number of selected images, matching URL list, and remembering filter open state +- Plugin page now allows browsing of all plugin lists, viewing details, and installation - Added tutorial guide page, which automatically pops up on first run - Now supports disabling GPU acceleration to resolve some compatibility issues - Added advanced animation settings for a better UI experience -- Added rpm installation package for Linux -- Optimized the loading speed of the album page +- Optimized the loading speed of multiple pages and browsing performance ### 🐛 Bug Fixes diff --git a/src/renderer/i18n/locales/en.json b/src/renderer/i18n/locales/en.json index 39b09cb6..2039287f 100644 --- a/src/renderer/i18n/locales/en.json +++ b/src/renderer/i18n/locales/en.json @@ -1,5 +1,7 @@ { - "app": { "title": "PicList" }, + "app": { + "title": "PicList" + }, "common": { "cancel": "Cancel", "close": "Close", @@ -664,6 +666,7 @@ "viewDocFailed": "View Document Failed" }, "plugin": { + "browseAllPlugins": "Browse All Plugins", "browsePlugins": "Browse Plugins", "configThing": "Config {c}", "description": "PicList Plugin Management", @@ -676,12 +679,15 @@ "installPluginsToGetStarted": "Please install plugins to get started", "list": "Plugin List", "loading": "Loading...", + "loadingPlugins": "Loading plugins...", "needRestart": "Need Restart to Take Effect", "noPluginsFound": "No Plugins Found", "NoPluginsInstalled": "No Plugins Installed", "notGuiImplement": "This plugin does not have a GUI implementation, continue?", + "openRemoteList": "Open Remote Plugin List", "pluginList": "Plugin List", "restartApp": "Restart Application", + "searchInBrowse": "Search in Browse", "searchPlaceholder": "Search for PicGo plugins on npm, or click the button above to view the excellent plugin list", "setResult": "Set Result", "setSuccess": "Set Success", @@ -800,7 +806,10 @@ "syncConfigProxy": "Proxy", "syncConfiguration": "Sync Platform", "syncEndpointConfig": "Endpoint Configuration", - "syncResult": { "failed": "Sync Failed", "success": "Sync Successful" }, + "syncResult": { + "failed": "Sync Failed", + "success": "Sync Successful" + }, "title": "Sync", "upDownloadDesc": "Sync configuration files and gallery data to cloud", "upDownloadSettings": "Sync Config & Gallery", @@ -1098,7 +1107,11 @@ "uploadHint": "All formats are supported, but images are recommended", "uploadingMultipleUrls": "Uploading {count} URLs...", "uploadViewHint": "Click to open picbeds settings", - "urlType": { "normal": "Long Link", "short": "Short Link", "title": "Link Type" }, + "urlType": { + "normal": "Long Link", + "short": "Short Link", + "title": "Link Type" + }, "urlUpload": "URL Upload" }, "uploaderConfig": { @@ -1135,5 +1148,10 @@ "toggle": "Toggle Theme" } }, - "titleBar": { "alwaysOnTop": "Always On Top", "close": "Close", "minimize": "Minimize", "miniWindow": "Mini Window" } + "titleBar": { + "alwaysOnTop": "Always On Top", + "close": "Close", + "minimize": "Minimize", + "miniWindow": "Mini Window" + } } diff --git a/src/renderer/i18n/locales/zh-CN.json b/src/renderer/i18n/locales/zh-CN.json index 72b8ac61..5dd15dbc 100644 --- a/src/renderer/i18n/locales/zh-CN.json +++ b/src/renderer/i18n/locales/zh-CN.json @@ -1,5 +1,7 @@ { - "app": { "title": "PicList" }, + "app": { + "title": "PicList" + }, "common": { "cancel": "取消", "close": "关闭", @@ -664,6 +666,7 @@ "viewDocFailed": "查看文档失败" }, "plugin": { + "browseAllPlugins": "浏览所有插件", "browsePlugins": "浏览插件", "configThing": "配置 {c}", "description": "PicList 插件管理页面", @@ -676,12 +679,15 @@ "installPluginsToGetStarted": "请先安装插件以开始使用", "list": "插件列表", "loading": "加载中...", + "loadingPlugins": "正在加载插件...", "needRestart": "需要重启生效", "noPluginsFound": "未找到插件", "NoPluginsInstalled": "暂无已安装插件", "notGuiImplement": "该插件未对可视化界面进行优化, 是否继续安装?", + "openRemoteList": "打开远程插件列表", "pluginList": "插件列表", "restartApp": "重启应用", + "searchInBrowse": "搜索插件", "searchPlaceholder": "搜索 npm 上的 PicGo 插件,或者点击上方按钮查看优秀插件列表", "setResult": "设置结果", "setSuccess": "设置成功", @@ -763,7 +769,12 @@ "downloadSettings": "下载配置", "fileManagement": "文件管理", "galleryDB": "相册数据库同步", - "gitea": { "branch": "分支名", "repo": "仓库名", "token": "访问令牌", "username": "用户名" }, + "gitea": { + "branch": "分支名", + "repo": "仓库名", + "token": "访问令牌", + "username": "用户名" + }, "giteaHost": "Gitea 地址", "gitee": { "branch": "Gitee 分支名", @@ -795,7 +806,10 @@ "syncConfigProxy": "代理", "syncConfiguration": "同步平台", "syncEndpointConfig": "平台设置", - "syncResult": { "failed": "同步失败", "success": "同步成功" }, + "syncResult": { + "failed": "同步失败", + "success": "同步成功" + }, "title": "同步", "upDownloadDesc": "同步配置文件和相册数据到云端", "upDownloadSettings": "同步配置和相册", @@ -1093,7 +1107,11 @@ "uploadHint": "支持所有文件类型,但推荐仅上传图片", "uploadingMultipleUrls": "正在上传 {count} 个URL...", "uploadViewHint": "点击打开图床设置", - "urlType": { "normal": "长链接", "short": "短链接", "title": "链接类型" }, + "urlType": { + "normal": "长链接", + "short": "短链接", + "title": "链接类型" + }, "urlUpload": "URL上传" }, "uploaderConfig": { @@ -1130,5 +1148,10 @@ "toggle": "切换主题" } }, - "titleBar": { "alwaysOnTop": "置顶", "close": "关闭", "minimize": "最小化", "miniWindow": "迷你窗口" } + "titleBar": { + "alwaysOnTop": "置顶", + "close": "关闭", + "minimize": "最小化", + "miniWindow": "迷你窗口" + } } diff --git a/src/renderer/i18n/locales/zh-TW.json b/src/renderer/i18n/locales/zh-TW.json index 26b0bfad..626d84a9 100644 --- a/src/renderer/i18n/locales/zh-TW.json +++ b/src/renderer/i18n/locales/zh-TW.json @@ -1,5 +1,7 @@ { - "app": { "title": "PicList" }, + "app": { + "title": "PicList" + }, "common": { "cancel": "取消", "close": "關閉", @@ -664,6 +666,7 @@ "viewDocFailed": "查看文件失敗" }, "plugin": { + "browseAllPlugins": "瀏覽所有插件", "browsePlugins": "瀏覽插件", "configThing": "配置 {c}", "description": "PicList 插件管理頁面", @@ -676,12 +679,15 @@ "installPluginsToGetStarted": "請先安裝插件以開始使用", "list": "插件列表", "loading": "載入中...", - "needRestart": "需要重啟生效", + "loadingPlugins": "正在加載插件...", + "needRestart": "需要重啟才能生效", "noPluginsFound": "未找到插件", "NoPluginsInstalled": "尚未安裝任何插件", "notGuiImplement": "該插件未針對圖形介面進行優化,是否繼續安裝?", + "openRemoteList": "打開遠程插件列表", "pluginList": "插件列表", "restartApp": "重啟應用", + "searchInBrowse": "在瀏覽中搜索", "searchPlaceholder": "搜尋 npm 上的 PicGo 插件,或者點擊上方按鈕查看優秀插件列表", "setResult": "設定結果", "setSuccess": "設定成功", @@ -763,7 +769,12 @@ "downloadSettings": "下載配置", "fileManagement": "文件管理", "galleryDB": "相冊數據庫同步", - "gitea": { "branch": "分支名", "repo": "倉庫名", "token": "訪問令牌", "username": "用戶名" }, + "gitea": { + "branch": "分支名", + "repo": "倉庫名", + "token": "訪問令牌", + "username": "用戶名" + }, "giteaHost": "Gitea 地址", "gitee": { "branch": "Gitee 分支名", @@ -795,7 +806,10 @@ "syncConfigProxy": "代理", "syncConfiguration": "同步平台", "syncEndpointConfig": "平台配置", - "syncResult": { "failed": "同步失敗", "success": "同步成功" }, + "syncResult": { + "failed": "同步失敗", + "success": "同步成功" + }, "title": "同步", "upDownloadDesc": "同步配置文件和相冊數據到雲端", "upDownloadSettings": "同步配置和相冊", @@ -1093,7 +1107,11 @@ "uploadHint": "支持所有文件類型,但推薦僅上傳圖片", "uploadingMultipleUrls": "正在上傳 {count} 個URL...", "uploadViewHint": "點擊打開圖床設定", - "urlType": { "normal": "長連結", "short": "短連結", "title": "連結類型" }, + "urlType": { + "normal": "長連結", + "short": "短連結", + "title": "連結類型" + }, "urlUpload": "URL上傳" }, "uploaderConfig": { @@ -1130,5 +1148,10 @@ "toggle": "切換主題" } }, - "titleBar": { "alwaysOnTop": "置頂", "close": "關閉", "minimize": "最小化", "miniWindow": "迷你視窗" } + "titleBar": { + "alwaysOnTop": "置頂", + "close": "關閉", + "minimize": "最小化", + "miniWindow": "迷你視窗" + } } diff --git a/src/renderer/pages/Plugin.vue b/src/renderer/pages/Plugin.vue index 1bbbb875..a09a1acb 100644 --- a/src/renderer/pages/Plugin.vue +++ b/src/renderer/pages/Plugin.vue @@ -1,7 +1,7 @@ @@ -252,6 +349,11 @@ const enableAdvancedAnimation = ref(false) const latestVersionMap = reactive>({}) const $configForm = useTemplateRef('$configForm') const strictSearch = useStorage('plugin-strict-search', true) +const showPluginListMenu = ref(false) +const showBrowseDialog = ref(false) +const browseSearchText = ref('') +const browsePlugins = ref([]) +const loadingBrowse = ref(false) function setSrc(e: Event) { const target = e.target as HTMLImageElement @@ -274,6 +376,21 @@ const npmSearchText = computed(() => { : searchText.value }) +const filteredBrowsePlugins = computed(() => { + if (!browseSearchText.value) { + return browsePlugins.value + } + const search = browseSearchText.value.toLowerCase() + return browsePlugins.value.filter(plugin => { + return ( + plugin.name.toLowerCase().includes(search) || + plugin.fullName.toLowerCase().includes(search) || + plugin.description?.toLowerCase().includes(search) || + plugin.author?.toLowerCase().includes(search) + ) + }) +}) + let getSearchResult: DebouncedFunc<(val: string) => void> watch(npmSearchText, (val: string) => { @@ -293,6 +410,14 @@ watch(dialogVisible, (val: boolean) => { } }) +watch(showBrowseDialog, (val: boolean) => { + if (val) { + document.body.style.overflow = 'hidden' + } else { + document.body.style.overflow = 'auto' + } +}) + async function getLatestVersionOfPlugIn(pluginName: string) { try { const res = await fetch(`https://registry.npmjs.com/${pluginName}`) @@ -333,6 +458,13 @@ const installPluginHandler = ({ success, body }: { success: boolean; body: strin item.hasInstall = success } }) + // Update browse dialog if open + browsePlugins.value.forEach(item => { + if (item.fullName === body) { + item.ing = false + item.hasInstall = success + } + }) } const updateSuccessHandler = (plugin: string) => { @@ -543,9 +675,60 @@ function openHomepage(url: string) { } function goAwesomeList() { + showPluginListMenu.value = false window.electron.sendRPC(IRPCActionType.OPEN_URL, 'https://github.com/PicGo/Awesome-PicGo') } +function togglePluginListMenu() { + showPluginListMenu.value = !showPluginListMenu.value +} + +async function openBrowsePluginsDialog() { + showPluginListMenu.value = false + showBrowseDialog.value = true + browseSearchText.value = '' + await fetchAllPlugins() +} + +function closeBrowseDialog() { + showBrowseDialog.value = false + browseSearchText.value = '' +} + +async function fetchAllPlugins() { + loadingBrowse.value = true + try { + const res = await fetch('https://registry.npmjs.com/-/v1/search?text=picgo-plugin-&size=250') + const data = await res.json() + browsePlugins.value = data.objects + .filter((item: INPMSearchResultObject) => { + return item.package.name.startsWith('picgo-plugin-') + }) + .map((item: INPMSearchResultObject) => { + return handleSearchResult(item) + }) + .sort((a: IPicGoPlugin, b: IPicGoPlugin) => { + return b.fullName.localeCompare(a.fullName) + }) + } catch (err) { + console.error('Failed to fetch plugins:', err) + } finally { + loadingBrowse.value = false + } +} + +function installPluginFromBrowse(item: IPicGoPlugin) { + if (!item.gui) { + if (confirm(t('pages.plugin.notGuiImplement'))) { + item.ing = true + window.electron.sendRPC(IRPCActionType.PLUGIN_INSTALL, item.fullName) + } + } else { + item.ing = true + window.electron.sendRPC(IRPCActionType.PLUGIN_INSTALL, item.fullName) + } +} + function handleImportLocalPlugin() { window.electron.sendRPC(IRPCActionType.PLUGIN_IMPORT_LOCAL) loading.value = true @@ -569,6 +752,14 @@ onBeforeMount(async () => { getSearchResult = debounce(_getSearchResult, 50) initConf() needReload.value = (await getConfig(configPaths.needReload)) || false + + // Close dropdown menu when clicking outside + document.addEventListener('click', (e: MouseEvent) => { + const target = e.target as HTMLElement + if (!target.closest('.dropdown-wrapper')) { + showPluginListMenu.value = false + } + }) }) onBeforeUnmount(() => { diff --git a/src/renderer/pages/css/PluginPage.css b/src/renderer/pages/css/PluginPage.css index 8c70f63d..88fdd8d3 100644 --- a/src/renderer/pages/css/PluginPage.css +++ b/src/renderer/pages/css/PluginPage.css @@ -33,6 +33,15 @@ html, body { box-shadow: var(--shadow-md); } +.header-card { + overflow: visible; + border: 1px solid var(--color-border-secondary); + border-radius: var(--radius-xl); + background: var(--color-background-secondary); + box-shadow: var(--shadow-sm); + transition: var(--transition-medium); +} + /* Header Card */ .header-card .card-header { display: flex; @@ -353,8 +362,8 @@ html, body { } .cli-badge { - color: var(--color-blue-common); - background: var(--color-info); + color: var(--color-text-primary); + background: var(--color-accent); } .update-badge { @@ -380,6 +389,7 @@ html, body { } .plugin-info { + position: relative; flex: 1; min-width: 0; } @@ -575,7 +585,7 @@ html, body { width: 100%; max-width: 70vw; max-height: 80vh; - background: var(--color-surface); + background: var(--color-background-tertiary); box-shadow: var(--shadow-xl); flex-direction: column; } @@ -783,3 +793,117 @@ html, body { outline: 2px solid var(--color-accent); outline-offset: 2px; } + +/* Dropdown Menu */ +.dropdown-wrapper { + position: relative; +} + +.dropdown-menu { + position: absolute; + top: calc(100% + 0.5rem); + right: 0; + z-index: 1000; + min-width: 200px; + border: 1px solid var(--color-border-secondary); + border-radius: var(--radius-md); + background: var(--color-background-tertiary); + box-shadow: var(--shadow-lg); + padding: 0.5rem; +} + +.dropdown-item { + display: flex; + align-items: center; + border: none; + border-radius: var(--radius-sm); + padding: 0.75rem 1rem; + width: 100%; + font-size: 0.875rem; + font-family: inherit; + font-weight: 500; + color: var(--color-text-primary); + background: transparent; + transition: var(--transition-fast); + gap: 0.5rem; + cursor: pointer; + text-align: left; +} + +.dropdown-item:hover { + background: var(--color-background-hover); + color: var(--color-accent); +} + +.dropdown-item svg { + flex-shrink: 0; +} + +/* Browse Modal */ +.browse-modal { + max-width: 900px; + max-height: 80vh; + width: 90%; +} + +.browse-content { + display: flex; + max-height: 600px; + flex-direction: column; + gap: 1rem; +} + +.browse-search { + flex-shrink: 0; +} + +.browse-loading { + display: flex; + justify-content: center; + align-items: center; + padding: 3rem 1rem; + flex-direction: column; + gap: 1rem; +} + +.browse-plugin-grid { + display: grid; + overflow-y: auto; + padding: 0.5rem; + gap: 1rem; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); +} + +.browse-plugin-item { + display: flex; + border: 1px solid var(--color-border-secondary); + border-radius: var(--radius-lg); + padding: 1rem; + background: var(--color-background-primary); + flex-direction: column; + gap: 0.75rem; + transition: var(--transition-medium); +} + +.browse-plugin-item:hover { + border-color: var(--color-accent); + box-shadow: var(--shadow-md); + transform: translateY(-2px); +} + +.browse-plugin-item .plugin-actions { + margin-top: auto; +} + +.cli-badge-browser { + position: absolute; + top: 0; + right: 0; + z-index: 1; + border-radius: var(--radius-sm); + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + font-weight: 600; + color: var(--color-text-primary); + background: var(--color-accent); +}