mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-07-14 00:51:47 +08:00
🎨 Style(custom): lint code
This commit is contained in:
@@ -7,9 +7,7 @@ import vue from '@vitejs/plugin-vue'
|
|||||||
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
|
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
main: {
|
main: {
|
||||||
plugins: [
|
plugins: [externalizeDepsPlugin()],
|
||||||
externalizeDepsPlugin()
|
|
||||||
],
|
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': resolve('src/renderer'),
|
'@': resolve('src/renderer'),
|
||||||
@@ -22,7 +20,8 @@ export default defineConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
preload: {
|
preload: {
|
||||||
plugins: [externalizeDepsPlugin(),
|
plugins: [
|
||||||
|
externalizeDepsPlugin(),
|
||||||
VueI18nPlugin({
|
VueI18nPlugin({
|
||||||
/* options */
|
/* options */
|
||||||
// locale messages resource pre-compile option
|
// locale messages resource pre-compile option
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import eslint from '@eslint/js'
|
import eslint from '@eslint/js'
|
||||||
import standard from '@vue/eslint-config-standard'
|
import standard from '@vue/eslint-config-standard'
|
||||||
|
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
|
||||||
import simpleImportSort from 'eslint-plugin-simple-import-sort'
|
import simpleImportSort from 'eslint-plugin-simple-import-sort'
|
||||||
import eslintPluginUnicorn from 'eslint-plugin-unicorn'
|
import eslintPluginUnicorn from 'eslint-plugin-unicorn'
|
||||||
import pluginVue from 'eslint-plugin-vue'
|
import pluginVue from 'eslint-plugin-vue'
|
||||||
@@ -18,6 +19,7 @@ export default tseslint.config(
|
|||||||
...tseslint.configs.stylistic,
|
...tseslint.configs.stylistic,
|
||||||
...pluginVue.configs['flat/recommended'],
|
...pluginVue.configs['flat/recommended'],
|
||||||
...standard,
|
...standard,
|
||||||
|
eslintPluginPrettierRecommended,
|
||||||
{
|
{
|
||||||
plugins: {
|
plugins: {
|
||||||
'simple-import-sort': simpleImportSort,
|
'simple-import-sort': simpleImportSort,
|
||||||
|
|||||||
15
package.json
15
package.json
@@ -25,10 +25,10 @@
|
|||||||
"dev": "electron-vite dev --watch",
|
"dev": "electron-vite dev --watch",
|
||||||
"i18n": "node ./scripts/gen-i18n-types.js",
|
"i18n": "node ./scripts/gen-i18n-types.js",
|
||||||
"link": "node ./scripts/link.js",
|
"link": "node ./scripts/link.js",
|
||||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.vue src/",
|
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.vue src/ scripts/ .",
|
||||||
"lint:dpdm": "dpdm -T --tsconfig ./tsconfig.json --no-tree --no-warning --exit-code circular:1 src/main/index.ts",
|
"lint:dpdm": "dpdm -T --tsconfig ./tsconfig.json --no-tree --no-warning --exit-code circular:1 src/main/index.ts",
|
||||||
"lint:dpdm:renderer": "dpdm -T --tsconfig ./tsconfig.json --no-tree --no-warning --exit-code circular:1 src/renderer/main.ts",
|
"lint:dpdm:renderer": "dpdm -T --tsconfig ./tsconfig.json --no-tree --no-warning --exit-code circular:1 src/renderer/main.ts",
|
||||||
"lint:fix": "eslint --fix --ext .js,.jsx,.ts,.tsx,.vue src/",
|
"lint:fix": "eslint --fix --ext .js,.jsx,.ts,.tsx,.vue src/ scripts/ .",
|
||||||
"ncu": "node ./scripts/check-dep.js",
|
"ncu": "node ./scripts/check-dep.js",
|
||||||
"postinstall": "electron-builder install-app-deps",
|
"postinstall": "electron-builder install-app-deps",
|
||||||
"postuninstall": "electron-builder install-app-deps",
|
"postuninstall": "electron-builder install-app-deps",
|
||||||
@@ -44,7 +44,6 @@
|
|||||||
"@aws-sdk/client-s3": "^3.864.0",
|
"@aws-sdk/client-s3": "^3.864.0",
|
||||||
"@aws-sdk/lib-storage": "^3.864.0",
|
"@aws-sdk/lib-storage": "^3.864.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.864.0",
|
"@aws-sdk/s3-request-presigner": "^3.864.0",
|
||||||
"@electron-toolkit/preload": "^3.0.2",
|
|
||||||
"@headlessui/vue": "^1.7.23",
|
"@headlessui/vue": "^1.7.23",
|
||||||
"@highlightjs/vue-plugin": "^2.1.2",
|
"@highlightjs/vue-plugin": "^2.1.2",
|
||||||
"@nodelib/fs.walk": "^3.0.1",
|
"@nodelib/fs.walk": "^3.0.1",
|
||||||
@@ -53,11 +52,12 @@
|
|||||||
"@piclist/store": "^3.0.0",
|
"@piclist/store": "^3.0.0",
|
||||||
"@smithy/node-http-handler": "^4.1.1",
|
"@smithy/node-http-handler": "^4.1.1",
|
||||||
"@videojs-player/vue": "^1.0.0",
|
"@videojs-player/vue": "^1.0.0",
|
||||||
"@vueuse/core": "^13.6.0",
|
|
||||||
"ali-oss": "^6.23.0",
|
"ali-oss": "^6.23.0",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
|
"chalk": "^5.5.0",
|
||||||
"compare-versions": "^6.1.1",
|
"compare-versions": "^6.1.1",
|
||||||
"cos-nodejs-sdk-v5": "^2.15.4",
|
"cos-nodejs-sdk-v5": "^2.15.4",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
"dexie": "^3.2.4",
|
"dexie": "^3.2.4",
|
||||||
"electron-updater": "^6.6.2",
|
"electron-updater": "^6.6.2",
|
||||||
"fast-xml-parser": "^5.2.5",
|
"fast-xml-parser": "^5.2.5",
|
||||||
@@ -78,13 +78,12 @@
|
|||||||
"piclist": "^2.0.0",
|
"piclist": "^2.0.0",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"pinia-plugin-persistedstate": "^4.5.0",
|
"pinia-plugin-persistedstate": "^4.5.0",
|
||||||
"proxy-agent": "^6.5.0",
|
|
||||||
"qiniu": "7.14.0",
|
"qiniu": "7.14.0",
|
||||||
"qrcode.vue": "^3.6.0",
|
"qrcode.vue": "^3.6.0",
|
||||||
"querystring": "^0.2.1",
|
|
||||||
"semver": "^7.7.2",
|
"semver": "^7.7.2",
|
||||||
"shell-path": "3.0.0",
|
"shell-path": "3.0.0",
|
||||||
"ssh2-no-cpu-features": "^2.0.0",
|
"ssh2-no-cpu-features": "^2.0.0",
|
||||||
|
"tunnel": "^0.0.6",
|
||||||
"upyun": "^3.4.6",
|
"upyun": "^3.4.6",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
"video.js": "^8.23.4",
|
"video.js": "^8.23.4",
|
||||||
@@ -112,9 +111,7 @@
|
|||||||
"@types/video.js": "^7.3.58",
|
"@types/video.js": "^7.3.58",
|
||||||
"@types/write-file-atomic": "^4.0.3",
|
"@types/write-file-atomic": "^4.0.3",
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@vue/eslint-config-prettier": "^10.2.0",
|
|
||||||
"@vue/eslint-config-standard": "^9.0.1",
|
"@vue/eslint-config-standard": "^9.0.1",
|
||||||
"@vue/eslint-config-typescript": "^14.6.0",
|
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"dpdm": "^3.14.0",
|
"dpdm": "^3.14.0",
|
||||||
"electron": "^36.7.4",
|
"electron": "^36.7.4",
|
||||||
@@ -122,10 +119,12 @@
|
|||||||
"electron-devtools-installer": "^4.0.0",
|
"electron-devtools-installer": "^4.0.0",
|
||||||
"electron-vite": "^4.0.0",
|
"electron-vite": "^4.0.0",
|
||||||
"eslint": "^9.33.0",
|
"eslint": "^9.33.0",
|
||||||
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-prettier": "^5.5.4",
|
"eslint-plugin-prettier": "^5.5.4",
|
||||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||||
"eslint-plugin-unicorn": "^60.0.0",
|
"eslint-plugin-unicorn": "^60.0.0",
|
||||||
"eslint-plugin-vue": "^10.4.0",
|
"eslint-plugin-vue": "^10.4.0",
|
||||||
|
"globals": "^16.3.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"node-bump-version": "^2.0.0",
|
"node-bump-version": "^2.0.0",
|
||||||
"npm-check-updates": "^18.0.2",
|
"npm-check-updates": "^18.0.2",
|
||||||
|
|||||||
@@ -6,7 +6,13 @@ import shortKeyService from 'apis/app/shortKey/shortKeyService'
|
|||||||
import GuiApi from 'apis/gui'
|
import GuiApi from 'apis/gui'
|
||||||
import { globalShortcut } from 'electron'
|
import { globalShortcut } from 'electron'
|
||||||
|
|
||||||
import type { IKeyCommandType, IPluginShortKeyConfig, IShortKeyConfig, IShortKeyConfigs, IShortKeyHandler } from '#/types/types'
|
import type {
|
||||||
|
IKeyCommandType,
|
||||||
|
IPluginShortKeyConfig,
|
||||||
|
IShortKeyConfig,
|
||||||
|
IShortKeyConfigs,
|
||||||
|
IShortKeyHandler
|
||||||
|
} from '#/types/types'
|
||||||
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant'
|
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant'
|
||||||
import { configPaths } from '~/utils/configPaths'
|
import { configPaths } from '~/utils/configPaths'
|
||||||
|
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ export function createTray (tooltip: string) {
|
|||||||
// drop-files only be supported in macOS
|
// drop-files only be supported in macOS
|
||||||
// so the tray window must be available
|
// so the tray window must be available
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
(tray as any).on('drop-files', async (_: Event, files: string[]) => {
|
;(tray as any).on('drop-files', async (_: Event, files: string[]) => {
|
||||||
const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
|
const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
|
||||||
const rawInput = cloneDeep(files)
|
const rawInput = cloneDeep(files)
|
||||||
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
|
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
|
||||||
|
|||||||
@@ -8,7 +8,16 @@ import { BrowserWindow, dialog, ipcMain, IpcMainEvent, MessageBoxOptions, Notifi
|
|||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
|
||||||
import type { IGuiApi, ImgInfo, IShowFileExplorerOption, IShowInputBoxOption, IShowMessageBoxOption, IShowMessageBoxResult, IShowNotificationOption, IUploadOption } from '#/types/types'
|
import type {
|
||||||
|
IGuiApi,
|
||||||
|
ImgInfo,
|
||||||
|
IShowFileExplorerOption,
|
||||||
|
IShowInputBoxOption,
|
||||||
|
IShowMessageBoxOption,
|
||||||
|
IShowMessageBoxResult,
|
||||||
|
IShowNotificationOption,
|
||||||
|
IUploadOption
|
||||||
|
} from '#/types/types'
|
||||||
import { SHOW_INPUT_BOX } from '~/events/constant'
|
import { SHOW_INPUT_BOX } from '~/events/constant'
|
||||||
import { T as $t } from '~/i18n'
|
import { T as $t } from '~/i18n'
|
||||||
import { handleCopyUrl } from '~/utils/common'
|
import { handleCopyUrl } from '~/utils/common'
|
||||||
|
|||||||
@@ -85,11 +85,15 @@ const getPluginList = async (): Promise<IPicGoPlugin[]> => {
|
|||||||
},
|
},
|
||||||
uploader: {
|
uploader: {
|
||||||
name: uploaderName,
|
name: uploaderName,
|
||||||
config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.uploader as keyof typeof IPicGoHelperType, picgo))
|
config: handleConfigWithFunction(
|
||||||
|
getConfig(uploaderName, IPicGoHelperType.uploader as keyof typeof IPicGoHelperType, picgo)
|
||||||
|
)
|
||||||
},
|
},
|
||||||
transformer: {
|
transformer: {
|
||||||
name: transformerName,
|
name: transformerName,
|
||||||
config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.transformer as keyof typeof IPicGoHelperType, picgo))
|
config: handleConfigWithFunction(
|
||||||
|
getConfig(uploaderName, IPicGoHelperType.transformer as keyof typeof IPicGoHelperType, picgo)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
enabled: picgo.getConfig(`picgoPlugins.${pluginList[i]}`),
|
enabled: picgo.getConfig(`picgoPlugins.${pluginList[i]}`),
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ import { sendToolboxResWithType } from '~/events/rpc/routes/toolbox/utils'
|
|||||||
import { T as $t } from '~/i18n'
|
import { T as $t } from '~/i18n'
|
||||||
import { IToolboxItemCheckStatus, IToolboxItemType } from '~/utils/enum'
|
import { IToolboxItemCheckStatus, IToolboxItemType } from '~/utils/enum'
|
||||||
|
|
||||||
export const checkFileMap: IToolboxCheckerMap<
|
export const checkFileMap: IToolboxCheckerMap<string> = {
|
||||||
string
|
|
||||||
> = {
|
|
||||||
[IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async (event: IpcMainEvent) => {
|
[IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async (event: IpcMainEvent) => {
|
||||||
const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.IS_CONFIG_FILE_BROKEN)
|
const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.IS_CONFIG_FILE_BROKEN)
|
||||||
sendToolboxRes(event, {
|
sendToolboxRes(event, {
|
||||||
@@ -62,9 +60,7 @@ export const checkFileMap: IToolboxCheckerMap<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fixFileMap: IToolboxFixMap<
|
export const fixFileMap: IToolboxFixMap<string> = {
|
||||||
string
|
|
||||||
> = {
|
|
||||||
[IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async () => {
|
[IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async () => {
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(dbPathChecker())
|
fs.unlinkSync(dbPathChecker())
|
||||||
|
|||||||
@@ -241,9 +241,15 @@ class LifeCycle {
|
|||||||
if (lastPosition[0] < 0 || lastPosition[0] > width || lastPosition[1] < 0 || lastPosition[1] > height) {
|
if (lastPosition[0] < 0 || lastPosition[0] > width || lastPosition[1] < 0 || lastPosition[1] > height) {
|
||||||
miniWindow.setPosition(width - 100, height - 100)
|
miniWindow.setPosition(width - 100, height - 100)
|
||||||
db.set(configPaths.settings.miniWindowPosition, [width - 100, height - 100])
|
db.set(configPaths.settings.miniWindowPosition, [width - 100, height - 100])
|
||||||
} else if (lastPosition[0] + miniWindow.getSize()[0] > width || lastPosition[1] + miniWindow.getSize()[1] > height) {
|
} else if (
|
||||||
|
lastPosition[0] + miniWindow.getSize()[0] > width ||
|
||||||
|
lastPosition[1] + miniWindow.getSize()[1] > height
|
||||||
|
) {
|
||||||
miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1])
|
miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1])
|
||||||
db.set(configPaths.settings.miniWindowPosition, [width - miniWindow.getSize()[0], height - miniWindow.getSize()[1]])
|
db.set(configPaths.settings.miniWindowPosition, [
|
||||||
|
width - miniWindow.getSize()[0],
|
||||||
|
height - miniWindow.getSize()[1]
|
||||||
|
])
|
||||||
} else {
|
} else {
|
||||||
miniWindow.setPosition(lastPosition[0], lastPosition[1])
|
miniWindow.setPosition(lastPosition[0], lastPosition[1])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ class S3plistApi {
|
|||||||
const { BucketName, region, acl, endpoint } = configMap
|
const { BucketName, region, acl, endpoint } = configMap
|
||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new ListBucketsCommand({})
|
const command = new ListBucketsCommand({})
|
||||||
@@ -255,7 +255,7 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
const result: IStringKeyMap[] = []
|
const result: IStringKeyMap[] = []
|
||||||
const endpoint = (options.endpoint as string) || ''
|
const endpoint = (options.endpoint as string) || ''
|
||||||
options.region = endpoint.includes('cloudflarestorage') ? 'auto' : 'us-east-1'
|
options.region = endpoint.includes('cloudflarestorage') ? 'auto' : 'us-east-1'
|
||||||
@@ -331,7 +331,7 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
do {
|
do {
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new ListObjectsV2Command({
|
const command = new ListObjectsV2Command({
|
||||||
@@ -396,7 +396,7 @@ class S3plistApi {
|
|||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
do {
|
do {
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new ListObjectsV2Command({
|
const command = new ListObjectsV2Command({
|
||||||
@@ -457,10 +457,10 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
const options = ({
|
const options = {
|
||||||
|
...this.baseOptions,
|
||||||
...this.baseOptions, region: String(region) || 'us-east-1'
|
region: String(region) || 'us-east-1'
|
||||||
}) as S3ClientConfig
|
} as S3ClientConfig
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new ListObjectsV2Command({
|
const command = new ListObjectsV2Command({
|
||||||
Bucket: bucket,
|
Bucket: bucket,
|
||||||
@@ -500,10 +500,10 @@ class S3plistApi {
|
|||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
const options = ({
|
const options = {
|
||||||
|
...this.baseOptions,
|
||||||
...this.baseOptions, region: String(region) || 'us-east-1'
|
region: String(region) || 'us-east-1'
|
||||||
}) as S3ClientConfig
|
} as S3ClientConfig
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new CopyObjectCommand({
|
const command = new CopyObjectCommand({
|
||||||
Bucket: bucketName,
|
Bucket: bucketName,
|
||||||
@@ -545,7 +545,7 @@ class S3plistApi {
|
|||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new DeleteObjectCommand({
|
const command = new DeleteObjectCommand({
|
||||||
@@ -581,7 +581,7 @@ class S3plistApi {
|
|||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
do {
|
do {
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new ListObjectsV2Command({
|
const command = new ListObjectsV2Command({
|
||||||
@@ -616,7 +616,7 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
if (allFileList.Contents.length > 0) {
|
if (allFileList.Contents.length > 0) {
|
||||||
const cycle = Math.ceil(allFileList.Contents.length / 1000)
|
const cycle = Math.ceil(allFileList.Contents.length / 1000)
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
for (let i = 0; i < cycle; i++) {
|
for (let i = 0; i < cycle; i++) {
|
||||||
@@ -661,7 +661,7 @@ class S3plistApi {
|
|||||||
const { bucketName, region, key, expires } = configMap
|
const { bucketName, region, key, expires } = configMap
|
||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const signedUrl = await getSignedUrl(
|
const signedUrl = await getSignedUrl(
|
||||||
@@ -690,7 +690,7 @@ class S3plistApi {
|
|||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new PutObjectCommand({
|
const command = new PutObjectCommand({
|
||||||
@@ -764,7 +764,7 @@ class S3plistApi {
|
|||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const fileStream = fs.createReadStream(filePath)
|
const fileStream = fs.createReadStream(filePath)
|
||||||
|
|||||||
@@ -346,7 +346,9 @@ class TcyunApi {
|
|||||||
region,
|
region,
|
||||||
key: item.Prefix
|
key: item.Prefix
|
||||||
}))
|
}))
|
||||||
) { return false }
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const cycles = Math.ceil(allFileList.Contents.length / 1000)
|
const cycles = Math.ceil(allFileList.Contents.length / 1000)
|
||||||
for (let i = 0; i < cycles; i++) {
|
for (let i = 0; i < cycles; i++) {
|
||||||
|
|||||||
@@ -18,23 +18,14 @@ export class AESHelper {
|
|||||||
readonly key: Buffer
|
readonly key: Buffer
|
||||||
|
|
||||||
constructor(password?: string) {
|
constructor(password?: string) {
|
||||||
const pwd =
|
const pwd = password ?? picgo.getConfig<string>(configPaths.settings.aesPassword) ?? 'aesPassword'
|
||||||
password ??
|
|
||||||
picgo.getConfig<string>(configPaths.settings.aesPassword) ??
|
|
||||||
'aesPassword'
|
|
||||||
this.key = AESHelper.#deriveKey(pwd)
|
this.key = AESHelper.#deriveKey(pwd)
|
||||||
}
|
}
|
||||||
|
|
||||||
static #deriveKey(password: string): Buffer {
|
static #deriveKey(password: string): Buffer {
|
||||||
const cached = this.#keyCache.get(password)
|
const cached = this.#keyCache.get(password)
|
||||||
if (cached) return cached
|
if (cached) return cached
|
||||||
const key = crypto.pbkdf2Sync(
|
const key = crypto.pbkdf2Sync(password, this.#SALT, this.#ITERATIONS, this.#KEYLEN, this.#DIGEST)
|
||||||
password,
|
|
||||||
this.#SALT,
|
|
||||||
this.#ITERATIONS,
|
|
||||||
this.#KEYLEN,
|
|
||||||
this.#DIGEST
|
|
||||||
)
|
|
||||||
this.#keyCache.set(password, key)
|
this.#keyCache.set(password, key)
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
@@ -42,10 +33,7 @@ export class AESHelper {
|
|||||||
encrypt(plainText: string): string {
|
encrypt(plainText: string): string {
|
||||||
const iv = crypto.randomBytes(AESHelper.#IV_LENGTH)
|
const iv = crypto.randomBytes(AESHelper.#IV_LENGTH)
|
||||||
const cipher = crypto.createCipheriv(AESHelper.#ALGO, this.key, iv)
|
const cipher = crypto.createCipheriv(AESHelper.#ALGO, this.key, iv)
|
||||||
const encrypted = Buffer.concat([
|
const encrypted = Buffer.concat([cipher.update(plainText, 'utf8'), cipher.final()])
|
||||||
cipher.update(plainText, 'utf8'),
|
|
||||||
cipher.final()
|
|
||||||
])
|
|
||||||
return `${iv.toString('hex')}${AESHelper.#SEP}${encrypted.toString('hex')}`
|
return `${iv.toString('hex')}${AESHelper.#SEP}${encrypted.toString('hex')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,10 +51,7 @@ export class AESHelper {
|
|||||||
if (iv.length !== AESHelper.#IV_LENGTH) return '{}'
|
if (iv.length !== AESHelper.#IV_LENGTH) return '{}'
|
||||||
|
|
||||||
const decipher = crypto.createDecipheriv(AESHelper.#ALGO, this.key, iv)
|
const decipher = crypto.createDecipheriv(AESHelper.#ALGO, this.key, iv)
|
||||||
const decrypted = Buffer.concat([
|
const decrypted = Buffer.concat([decipher.update(Buffer.from(encryptedHex, 'hex')), decipher.final()])
|
||||||
decipher.update(Buffer.from(encryptedHex, 'hex')),
|
|
||||||
decipher.final()
|
|
||||||
])
|
|
||||||
return decrypted.toString('utf8')
|
return decrypted.toString('utf8')
|
||||||
} catch {
|
} catch {
|
||||||
return '{}'
|
return '{}'
|
||||||
|
|||||||
@@ -48,7 +48,12 @@ function copyFileOutsideOfElectronAsar (sourceInAsarArchive: string, destOutside
|
|||||||
function resolveMacWorkFlow() {
|
function resolveMacWorkFlow() {
|
||||||
const dest = `${os.homedir()}/Library/Services/Upload pictures with PicList.workflow`
|
const dest = `${os.homedir()}/Library/Services/Upload pictures with PicList.workflow`
|
||||||
try {
|
try {
|
||||||
copyFileOutsideOfElectronAsar(path.join(__dirname, '../../resources', 'Upload pictures with PicList.workflow').replace('app.asar', 'app.asar.unpacked'), dest)
|
copyFileOutsideOfElectronAsar(
|
||||||
|
path
|
||||||
|
.join(__dirname, '../../resources', 'Upload pictures with PicList.workflow')
|
||||||
|
.replace('app.asar', 'app.asar.unpacked'),
|
||||||
|
dest
|
||||||
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,24 @@
|
|||||||
import type { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
|
import type { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
|
||||||
|
|
||||||
import type { IAliYunConfig, IAwsS3PListUserConfig, IGitHubConfig, IImgurConfig, ILocalConfig, ILskyConfig, IPicBedType, IQiniuConfig, IServerConfig, ISftpPlistConfig, IShortKeyConfig, ISMMSConfig, ISyncConfig, ITcYunConfig, IUploaderConfig, IUpYunConfig, IWebdavPlistConfig } from '#/types/types'
|
import type {
|
||||||
|
IAliYunConfig,
|
||||||
|
IAwsS3PListUserConfig,
|
||||||
|
IGitHubConfig,
|
||||||
|
IImgurConfig,
|
||||||
|
ILocalConfig,
|
||||||
|
ILskyConfig,
|
||||||
|
IPicBedType,
|
||||||
|
IQiniuConfig,
|
||||||
|
IServerConfig,
|
||||||
|
ISftpPlistConfig,
|
||||||
|
IShortKeyConfig,
|
||||||
|
ISMMSConfig,
|
||||||
|
ISyncConfig,
|
||||||
|
ITcYunConfig,
|
||||||
|
IUploaderConfig,
|
||||||
|
IUpYunConfig,
|
||||||
|
IWebdavPlistConfig
|
||||||
|
} from '#/types/types'
|
||||||
|
|
||||||
export type manualPageOpenType = 'window' | 'browser'
|
export type manualPageOpenType = 'window' | 'browser'
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
import picgo from '@core/picgo'
|
import picgo from '@core/picgo'
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
|
|
||||||
import type { IPicGoPluginConfig, IPicGoPluginOriginConfig, IStringKeyMap, IUploaderConfigItem, IUploaderConfigListItem } from '#/types/types'
|
import type {
|
||||||
|
IPicGoPluginConfig,
|
||||||
|
IPicGoPluginOriginConfig,
|
||||||
|
IStringKeyMap,
|
||||||
|
IUploaderConfigItem,
|
||||||
|
IUploaderConfigListItem
|
||||||
|
} from '#/types/types'
|
||||||
import { setTrayToolTip, trimValues } from '~/utils/common'
|
import { setTrayToolTip, trimValues } from '~/utils/common'
|
||||||
import { configPaths } from '~/utils/configPaths'
|
import { configPaths } from '~/utils/configPaths'
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ export class MemoryMonitor {
|
|||||||
heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024),
|
heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024),
|
||||||
external: Math.round(memUsage.external / 1024 / 1024)
|
external: Math.round(memUsage.external / 1024 / 1024)
|
||||||
}
|
}
|
||||||
console.log(`[Memory] RSS: ${mbUsage.rss}MB, Heap: ${mbUsage.heapUsed}/${mbUsage.heapTotal}MB, External: ${mbUsage.external}MB`)
|
console.log(
|
||||||
|
`[Memory] RSS: ${mbUsage.rss}MB, Heap: ${mbUsage.heapUsed}/${mbUsage.heapTotal}MB, External: ${mbUsage.external}MB`
|
||||||
|
)
|
||||||
|
|
||||||
if (mbUsage.heapUsed / mbUsage.heapTotal > 0.8 && global.gc) {
|
if (mbUsage.heapUsed / mbUsage.heapTotal > 0.8 && global.gc) {
|
||||||
console.log('[Memory] Triggering garbage collection')
|
console.log('[Memory] Triggering garbage collection')
|
||||||
|
|||||||
@@ -24,9 +24,15 @@ export function openMiniWindow (hideSettingWindow: boolean = true) {
|
|||||||
if (lastPosition[0] < 0 || lastPosition[0] > width || lastPosition[1] < 0 || lastPosition[1] > height) {
|
if (lastPosition[0] < 0 || lastPosition[0] > width || lastPosition[1] < 0 || lastPosition[1] > height) {
|
||||||
miniWindow.setPosition(width - 100, height - 100)
|
miniWindow.setPosition(width - 100, height - 100)
|
||||||
db.set(configPaths.settings.miniWindowPosition, [width - 100, height - 100])
|
db.set(configPaths.settings.miniWindowPosition, [width - 100, height - 100])
|
||||||
} else if (lastPosition[0] + miniWindow.getSize()[0] > width || lastPosition[1] + miniWindow.getSize()[1] > height) {
|
} else if (
|
||||||
|
lastPosition[0] + miniWindow.getSize()[0] > width ||
|
||||||
|
lastPosition[1] + miniWindow.getSize()[1] > height
|
||||||
|
) {
|
||||||
miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1])
|
miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1])
|
||||||
db.set(configPaths.settings.miniWindowPosition, [width - miniWindow.getSize()[0], height - miniWindow.getSize()[1]])
|
db.set(configPaths.settings.miniWindowPosition, [
|
||||||
|
width - miniWindow.getSize()[0],
|
||||||
|
height - miniWindow.getSize()[1]
|
||||||
|
])
|
||||||
} else {
|
} else {
|
||||||
miniWindow.setPosition(lastPosition[0], lastPosition[1])
|
miniWindow.setPosition(lastPosition[0], lastPosition[1])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div id="app" :key="pageReloadCount">
|
||||||
id="app"
|
|
||||||
:key="pageReloadCount"
|
|
||||||
>
|
|
||||||
<router-view />
|
<router-view />
|
||||||
<UIServiceProvider />
|
<UIServiceProvider />
|
||||||
</div>
|
</div>
|
||||||
@@ -39,7 +36,6 @@ onMounted(async () => {
|
|||||||
console.error('Failed to load settings:', error)
|
console.error('Failed to load settings:', error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|||||||
@@ -1,29 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="image-container">
|
<div class="image-container">
|
||||||
<div
|
<div v-if="isLoading" class="loading-placeholder">
|
||||||
v-if="isLoading"
|
|
||||||
class="loading-placeholder"
|
|
||||||
>
|
|
||||||
<div class="loading-spinner" />
|
<div class="loading-spinner" />
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
v-else-if="!hasError"
|
v-else-if="!hasError"
|
||||||
:src="
|
:src="isShowThumbnail && item.isImage ? base64Image : `./assets/icons/${getFileIconPath(item.fileName ?? '')}`"
|
||||||
isShowThumbnail && item.isImage
|
|
||||||
? base64Image
|
|
||||||
: `./assets/icons/${getFileIconPath(item.fileName ?? '')}`
|
|
||||||
"
|
|
||||||
alt=""
|
alt=""
|
||||||
class="image"
|
class="image"
|
||||||
@load="handleImageLoad"
|
@load="handleImageLoad"
|
||||||
@error="handleImageError"
|
@error="handleImageError"
|
||||||
>
|
/>
|
||||||
<img
|
<img v-else :src="`./assets/icons/${getFileIconPath(item.fileName ?? '')}`" alt="" class="image" />
|
||||||
v-else
|
|
||||||
:src="`./assets/icons/${getFileIconPath(item.fileName ?? '')}`"
|
|
||||||
alt=""
|
|
||||||
class="image"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -109,7 +97,11 @@ onBeforeMount(async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% { transform: rotate(0deg); }
|
0% {
|
||||||
100% { transform: rotate(360deg); }
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="image-container">
|
<div class="image-container">
|
||||||
<div
|
<div v-if="isLoading" class="loading-placeholder">
|
||||||
v-if="isLoading"
|
|
||||||
class="loading-placeholder"
|
|
||||||
>
|
|
||||||
<div class="loading-spinner" />
|
<div class="loading-spinner" />
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
@@ -13,13 +10,8 @@
|
|||||||
class="image"
|
class="image"
|
||||||
@load="handleImageLoad"
|
@load="handleImageLoad"
|
||||||
@error="handleImageError"
|
@error="handleImageError"
|
||||||
>
|
/>
|
||||||
<img
|
<img v-else :src="iconPath" alt="" class="image" />
|
||||||
v-else
|
|
||||||
:src="iconPath"
|
|
||||||
alt=""
|
|
||||||
class="image"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -57,7 +49,11 @@ async function getUrl () {
|
|||||||
try {
|
try {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
hasError.value = false
|
hasError.value = false
|
||||||
preSignedUrl.value = await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_GET_PRE_SIGNED_URL, props.alias, props.config)
|
preSignedUrl.value = await window.electron.triggerRPC<any>(
|
||||||
|
IRPCActionType.MANAGE_GET_PRE_SIGNED_URL,
|
||||||
|
props.alias,
|
||||||
|
props.config
|
||||||
|
)
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to get pre-signed URL:', error)
|
console.error('Failed to get pre-signed URL:', error)
|
||||||
@@ -117,7 +113,11 @@ onMounted(getUrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% { transform: rotate(0deg); }
|
0% {
|
||||||
100% { transform: rotate(360deg); }
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -3,26 +3,17 @@
|
|||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="settings-header">
|
<div class="settings-header">
|
||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
<Settings
|
<Settings :size="24" class="header-icon" />
|
||||||
:size="24"
|
|
||||||
class="header-icon"
|
|
||||||
/>
|
|
||||||
<div>
|
<div>
|
||||||
<h1>{{ $t('pages.imageProcess.title') }}</h1>
|
<h1>{{ $t('pages.imageProcess.title') }}</h1>
|
||||||
<p>{{ $t('pages.imageProcess.description') }}</p>
|
<p>{{ $t('pages.imageProcess.description') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<button
|
<button class="btn btn-secondary" @click="closeDialog">
|
||||||
class="btn btn-secondary"
|
|
||||||
@click="closeDialog"
|
|
||||||
>
|
|
||||||
{{ $t('pages.imageProcess.cancel') }}
|
{{ $t('pages.imageProcess.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="btn btn-primary" @click="handleSaveConfig">
|
||||||
class="btn btn-primary"
|
|
||||||
@click="handleSaveConfig"
|
|
||||||
>
|
|
||||||
<Save :size="16" />
|
<Save :size="16" />
|
||||||
{{ $t('pages.imageProcess.confirm') }}
|
{{ $t('pages.imageProcess.confirm') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -38,10 +29,7 @@
|
|||||||
:class="{ active: activeTab === tab.id }"
|
:class="{ active: activeTab === tab.id }"
|
||||||
@click="activeTab = tab.id"
|
@click="activeTab = tab.id"
|
||||||
>
|
>
|
||||||
<component
|
<component :is="tab.icon" :size="18" />
|
||||||
:is="tab.icon"
|
|
||||||
:size="18"
|
|
||||||
/>
|
|
||||||
<span>{{ tab.label }}</span>
|
<span>{{ tab.label }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -49,10 +37,7 @@
|
|||||||
<!-- Settings Content -->
|
<!-- Settings Content -->
|
||||||
<div class="settings-content">
|
<div class="settings-content">
|
||||||
<!-- General Settings Tab -->
|
<!-- General Settings Tab -->
|
||||||
<div
|
<div v-if="activeTab === 'general'" class="tab-content">
|
||||||
v-if="activeTab === 'general'"
|
|
||||||
class="tab-content"
|
|
||||||
>
|
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<h2>{{ $t('pages.imageProcess.general.skipProcessExtList') }}</h2>
|
<h2>{{ $t('pages.imageProcess.general.skipProcessExtList') }}</h2>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -73,11 +58,7 @@
|
|||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isRemoveExif" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isRemoveExif"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.general.isRemoveExif') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.general.isRemoveExif') }}</span>
|
||||||
@@ -87,16 +68,8 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.general.quality') }}</label>
|
<label>{{ $t('pages.imageProcess.general.quality') }}</label>
|
||||||
<input
|
<input v-model.number="compressForm.quality" type="range" min="1" max="100" class="form-range" />
|
||||||
v-model.number="compressForm.quality"
|
<div class="range-value">{{ compressForm.quality }}%</div>
|
||||||
type="range"
|
|
||||||
min="1"
|
|
||||||
max="100"
|
|
||||||
class="form-range"
|
|
||||||
>
|
|
||||||
<div class="range-value">
|
|
||||||
{{ compressForm.quality }}%
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,11 +79,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isConvert" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isConvert"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.general.isConvert') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.general.isConvert') }}</span>
|
||||||
@@ -118,21 +87,11 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="compressForm.isConvert" class="form-grid">
|
||||||
v-if="compressForm.isConvert"
|
|
||||||
class="form-grid"
|
|
||||||
>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.general.destinationFormat') }}</label>
|
<label>{{ $t('pages.imageProcess.general.destinationFormat') }}</label>
|
||||||
<select
|
<select v-model="compressForm.convertFormat" class="form-input">
|
||||||
v-model="compressForm.convertFormat"
|
<option v-for="format in availableFormat" :key="format" :value="format">
|
||||||
class="form-input"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
v-for="format in availableFormat"
|
|
||||||
:key="format"
|
|
||||||
:value="format"
|
|
||||||
>
|
|
||||||
{{ format.toUpperCase() }}
|
{{ format.toUpperCase() }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -144,7 +103,7 @@
|
|||||||
v-model="formatConvertObj"
|
v-model="formatConvertObj"
|
||||||
class="form-textarea"
|
class="form-textarea"
|
||||||
rows="3"
|
rows="3"
|
||||||
placeholder="{"jpg": "png", "png": "jpg"}"
|
placeholder='{"jpg": "png", "png": "jpg"}'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -152,21 +111,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Watermark Tab -->
|
<!-- Watermark Tab -->
|
||||||
<div
|
<div v-if="activeTab === 'watermark'" class="tab-content">
|
||||||
v-if="activeTab === 'watermark'"
|
|
||||||
class="tab-content"
|
|
||||||
>
|
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<h2>{{ $t('pages.imageProcess.watermark.title') }}</h2>
|
<h2>{{ $t('pages.imageProcess.watermark.title') }}</h2>
|
||||||
<p>{{ $t('pages.imageProcess.watermark.description') }}</p>
|
<p>{{ $t('pages.imageProcess.watermark.description') }}</p>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="waterMarkForm.isAddWatermark" type="checkbox" class="switch-input" />
|
||||||
v-model="waterMarkForm.isAddWatermark"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.watermark.isAdd') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.watermark.isAdd') }}</span>
|
||||||
@@ -174,30 +126,17 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="waterMarkForm.isAddWatermark" class="watermark-settings">
|
||||||
v-if="waterMarkForm.isAddWatermark"
|
|
||||||
class="watermark-settings"
|
|
||||||
>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.watermark.type') }}</label>
|
<label>{{ $t('pages.imageProcess.watermark.type') }}</label>
|
||||||
<div class="radio-group">
|
<div class="radio-group">
|
||||||
<label class="radio-option">
|
<label class="radio-option">
|
||||||
<input
|
<input v-model="waterMarkForm.watermarkType" type="radio" value="text" class="radio-input" />
|
||||||
v-model="waterMarkForm.watermarkType"
|
|
||||||
type="radio"
|
|
||||||
value="text"
|
|
||||||
class="radio-input"
|
|
||||||
>
|
|
||||||
<span class="radio-indicator" />
|
<span class="radio-indicator" />
|
||||||
<span class="radio-label">{{ $t('pages.imageProcess.watermark.text') }}</span>
|
<span class="radio-label">{{ $t('pages.imageProcess.watermark.text') }}</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="radio-option">
|
<label class="radio-option">
|
||||||
<input
|
<input v-model="waterMarkForm.watermarkType" type="radio" value="image" class="radio-input" />
|
||||||
v-model="waterMarkForm.watermarkType"
|
|
||||||
type="radio"
|
|
||||||
value="image"
|
|
||||||
class="radio-input"
|
|
||||||
>
|
|
||||||
<span class="radio-indicator" />
|
<span class="radio-indicator" />
|
||||||
<span class="radio-label">{{ $t('pages.imageProcess.watermark.image') }}</span>
|
<span class="radio-label">{{ $t('pages.imageProcess.watermark.image') }}</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -207,11 +146,7 @@
|
|||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="waterMarkForm.isFullScreenWatermark" type="checkbox" class="switch-input" />
|
||||||
v-model="waterMarkForm.isFullScreenWatermark"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.watermark.isFullScreen') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.watermark.isFullScreen') }}</span>
|
||||||
@@ -227,10 +162,8 @@
|
|||||||
min="-360"
|
min="-360"
|
||||||
max="360"
|
max="360"
|
||||||
class="form-range"
|
class="form-range"
|
||||||
>
|
/>
|
||||||
<div class="range-value">
|
<div class="range-value">{{ waterMarkForm.watermarkDegree }}°</div>
|
||||||
{{ waterMarkForm.watermarkDegree }}°
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -242,18 +175,13 @@
|
|||||||
max="1"
|
max="1"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
class="form-range"
|
class="form-range"
|
||||||
>
|
/>
|
||||||
<div class="range-value">
|
<div class="range-value">{{ Math.round((waterMarkForm.watermarkScaleRatio || 0) * 100) }}%</div>
|
||||||
{{ Math.round((waterMarkForm.watermarkScaleRatio || 0) * 100) }}%
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Text Watermark Settings -->
|
<!-- Text Watermark Settings -->
|
||||||
<div
|
<div v-if="waterMarkForm.watermarkType === 'text'" class="form-grid">
|
||||||
v-if="waterMarkForm.watermarkType === 'text'"
|
|
||||||
class="form-grid"
|
|
||||||
>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.watermark.inputText') }}</label>
|
<label>{{ $t('pages.imageProcess.watermark.inputText') }}</label>
|
||||||
<input
|
<input
|
||||||
@@ -261,7 +189,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
:placeholder="$t('pages.imageProcess.watermark.inputTextPlaceholder')"
|
:placeholder="$t('pages.imageProcess.watermark.inputTextPlaceholder')"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -271,45 +199,35 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
:placeholder="$t('pages.imageProcess.watermark.textFontPathPlaceholder')"
|
:placeholder="$t('pages.imageProcess.watermark.textFontPathPlaceholder')"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.watermark.color') }}</label>
|
<label>{{ $t('pages.imageProcess.watermark.color') }}</label>
|
||||||
<div class="color-input-group">
|
<div class="color-input-group">
|
||||||
<input
|
<input v-model="waterMarkForm.watermarkColor" type="color" class="form-color" />
|
||||||
v-model="waterMarkForm.watermarkColor"
|
|
||||||
type="color"
|
|
||||||
class="form-color"
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
v-model="waterMarkForm.watermarkColor"
|
v-model="waterMarkForm.watermarkColor"
|
||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
placeholder="#CCCCCC73"
|
placeholder="#CCCCCC73"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Image Watermark Settings -->
|
<!-- Image Watermark Settings -->
|
||||||
<div
|
<div v-if="waterMarkForm.watermarkType === 'image'" class="form-group">
|
||||||
v-if="waterMarkForm.watermarkType === 'image'"
|
|
||||||
class="form-group"
|
|
||||||
>
|
|
||||||
<label>{{ $t('pages.imageProcess.watermark.imagePath') }}</label>
|
<label>{{ $t('pages.imageProcess.watermark.imagePath') }}</label>
|
||||||
<input
|
<input
|
||||||
v-model="waterMarkForm.watermarkImagePath"
|
v-model="waterMarkForm.watermarkImagePath"
|
||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
:placeholder="$t('pages.imageProcess.watermark.imagePathPlaceholder')"
|
:placeholder="$t('pages.imageProcess.watermark.imagePathPlaceholder')"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="waterMarkForm.watermarkType === 'image'" class="form-group">
|
||||||
v-if="waterMarkForm.watermarkType === 'image'"
|
|
||||||
class="form-group"
|
|
||||||
>
|
|
||||||
<label>{{ $t('pages.imageProcess.watermark.imageOpacity') }}</label>
|
<label>{{ $t('pages.imageProcess.watermark.imageOpacity') }}</label>
|
||||||
<input
|
<input
|
||||||
v-model.number="waterMarkForm.watermarkImageOpacity"
|
v-model.number="waterMarkForm.watermarkImageOpacity"
|
||||||
@@ -318,7 +236,7 @@
|
|||||||
max="255"
|
max="255"
|
||||||
step="1"
|
step="1"
|
||||||
class="form-range"
|
class="form-range"
|
||||||
>
|
/>
|
||||||
<div class="range-value">
|
<div class="range-value">
|
||||||
{{ waterMarkForm.watermarkImageOpacity || 0 }}
|
{{ waterMarkForm.watermarkImageOpacity || 0 }}
|
||||||
</div>
|
</div>
|
||||||
@@ -345,10 +263,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Transform Tab -->
|
<!-- Transform Tab -->
|
||||||
<div
|
<div v-if="activeTab === 'transform'" class="tab-content">
|
||||||
v-if="activeTab === 'transform'"
|
|
||||||
class="tab-content"
|
|
||||||
>
|
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<h2>{{ $t('pages.imageProcess.transform.title') }}</h2>
|
<h2>{{ $t('pages.imageProcess.transform.title') }}</h2>
|
||||||
<p>{{ $t('pages.imageProcess.transform.description') }}</p>
|
<p>{{ $t('pages.imageProcess.transform.description') }}</p>
|
||||||
@@ -356,11 +271,7 @@
|
|||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isFlip" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isFlip"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.transform.isFlip') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.transform.isFlip') }}</span>
|
||||||
@@ -370,11 +281,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isFlop" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isFlop"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.transform.isFlop') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.transform.isFlop') }}</span>
|
||||||
@@ -390,11 +297,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isRotate" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isRotate"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.transform.isRotate') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.transform.isRotate') }}</span>
|
||||||
@@ -402,21 +305,10 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="compressForm.isRotate" class="form-group">
|
||||||
v-if="compressForm.isRotate"
|
|
||||||
class="form-group"
|
|
||||||
>
|
|
||||||
<label>{{ $t('pages.imageProcess.transform.rotationDegree') }}</label>
|
<label>{{ $t('pages.imageProcess.transform.rotationDegree') }}</label>
|
||||||
<input
|
<input v-model.number="compressForm.rotateDegree" type="range" min="-360" max="360" class="form-range" />
|
||||||
v-model.number="compressForm.rotateDegree"
|
<div class="range-value">{{ compressForm.rotateDegree }}°</div>
|
||||||
type="range"
|
|
||||||
min="-360"
|
|
||||||
max="360"
|
|
||||||
class="form-range"
|
|
||||||
>
|
|
||||||
<div class="range-value">
|
|
||||||
{{ compressForm.rotateDegree }}°
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -426,11 +318,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isReSize" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isReSize"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.transform.isResize') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.transform.isResize') }}</span>
|
||||||
@@ -438,42 +326,28 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="compressForm.isReSize" class="resize-settings">
|
||||||
v-if="compressForm.isReSize"
|
|
||||||
class="resize-settings"
|
|
||||||
>
|
|
||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.transform.resizeWidth') }}</label>
|
<label>{{ $t('pages.imageProcess.transform.resizeWidth') }}</label>
|
||||||
<input
|
<input v-model.number="compressForm.reSizeWidth" type="number" min="0" class="form-input" />
|
||||||
v-model.number="compressForm.reSizeWidth"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
class="form-input"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.transform.resizeHeight') }}</label>
|
<label>{{ $t('pages.imageProcess.transform.resizeHeight') }}</label>
|
||||||
<input
|
<input v-model.number="compressForm.reSizeHeight" type="number" min="0" class="form-input" />
|
||||||
v-model.number="compressForm.reSizeHeight"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
class="form-input"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="((compressForm.reSizeHeight || 0) > 0 && (compressForm.reSizeWidth || 0) === 0) || ((compressForm.reSizeWidth || 0) > 0 && (compressForm.reSizeHeight || 0) === 0)"
|
v-if="
|
||||||
|
((compressForm.reSizeHeight || 0) > 0 && (compressForm.reSizeWidth || 0) === 0) ||
|
||||||
|
((compressForm.reSizeWidth || 0) > 0 && (compressForm.reSizeHeight || 0) === 0)
|
||||||
|
"
|
||||||
class="form-group"
|
class="form-group"
|
||||||
>
|
>
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.skipReSizeOfSmallImg" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.skipReSizeOfSmallImg"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.transform.skipResizeOfSmallImgHeight') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.transform.skipResizeOfSmallImgHeight') }}</span>
|
||||||
@@ -488,11 +362,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isReSizeByPercent" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isReSizeByPercent"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.transform.isResizeByPercent') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.transform.isResizeByPercent') }}</span>
|
||||||
@@ -501,21 +371,10 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="compressForm.isReSizeByPercent" class="form-group">
|
||||||
v-if="compressForm.isReSizeByPercent"
|
|
||||||
class="form-group"
|
|
||||||
>
|
|
||||||
<label>{{ $t('pages.imageProcess.transform.resizePercent') }}</label>
|
<label>{{ $t('pages.imageProcess.transform.resizePercent') }}</label>
|
||||||
<input
|
<input v-model.number="compressForm.reSizePercent" type="range" min="1" max="500" class="form-range" />
|
||||||
v-model.number="compressForm.reSizePercent"
|
<div class="range-value">{{ compressForm.reSizePercent }}%</div>
|
||||||
type="range"
|
|
||||||
min="1"
|
|
||||||
max="500"
|
|
||||||
class="form-range"
|
|
||||||
>
|
|
||||||
<div class="range-value">
|
|
||||||
{{ compressForm.reSizePercent }}%
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="image-container">
|
<div class="image-container">
|
||||||
<div
|
<div v-if="isLoading" class="loading-placeholder">
|
||||||
v-if="isLoading"
|
|
||||||
class="loading-placeholder"
|
|
||||||
>
|
|
||||||
<div class="loading-spinner" />
|
<div class="loading-spinner" />
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
@@ -13,13 +10,8 @@
|
|||||||
class="image"
|
class="image"
|
||||||
@load="handleImageLoad"
|
@load="handleImageLoad"
|
||||||
@error="handleImageError"
|
@error="handleImageError"
|
||||||
>
|
/>
|
||||||
<img
|
<img v-else :src="iconPath" alt="" class="image" />
|
||||||
v-else
|
|
||||||
:src="iconPath"
|
|
||||||
alt=""
|
|
||||||
class="image"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -148,7 +140,11 @@ onMounted(fetchImage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% { transform: rotate(0deg); }
|
0% {
|
||||||
100% { transform: rotate(360deg); }
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,22 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div
|
<div v-if="showInputBoxVisible" class="inputbox-overlay" @click="handleInputBoxCancel">
|
||||||
v-if="showInputBoxVisible"
|
<div class="inputbox-container" @click.stop>
|
||||||
class="inputbox-overlay"
|
|
||||||
@click="handleInputBoxCancel"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="inputbox-container"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
<div class="inputbox-header">
|
<div class="inputbox-header">
|
||||||
<h3 class="inputbox-title">
|
<h3 class="inputbox-title">
|
||||||
{{ inputBoxOptions.title || t('pages.inputBox.title') }}
|
{{ inputBoxOptions.title || t('pages.inputBox.title') }}
|
||||||
</h3>
|
</h3>
|
||||||
<button
|
<button class="inputbox-close" @click="handleInputBoxCancel">
|
||||||
class="inputbox-close"
|
|
||||||
@click="handleInputBoxCancel"
|
|
||||||
>
|
|
||||||
<X :size="20" />
|
<X :size="20" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,19 +18,13 @@
|
|||||||
type="text"
|
type="text"
|
||||||
@keyup.enter="handleInputBoxConfirm"
|
@keyup.enter="handleInputBoxConfirm"
|
||||||
@keyup.escape="handleInputBoxCancel"
|
@keyup.escape="handleInputBoxCancel"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="inputbox-actions">
|
<div class="inputbox-actions">
|
||||||
<button
|
<button class="inputbox-btn cancel-btn" @click="handleInputBoxCancel">
|
||||||
class="inputbox-btn cancel-btn"
|
|
||||||
@click="handleInputBoxCancel"
|
|
||||||
>
|
|
||||||
{{ t('common.cancel') }}
|
{{ t('common.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="inputbox-btn confirm-btn primary" @click="handleInputBoxConfirm">
|
||||||
class="inputbox-btn confirm-btn primary"
|
|
||||||
@click="handleInputBoxConfirm"
|
|
||||||
>
|
|
||||||
{{ t('common.confirm') }}
|
{{ t('common.confirm') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,7 +50,7 @@ const inputBoxOptions = reactive({
|
|||||||
placeholder: ''
|
placeholder: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
let removeInputBoxListenerCallback: (() => void) = () => {}
|
let removeInputBoxListenerCallback: () => void = () => {}
|
||||||
|
|
||||||
function handleIpcInputBoxEvent(options: IShowInputBoxOption) {
|
function handleIpcInputBoxEvent(options: IShowInputBoxOption) {
|
||||||
initInputBoxValue(options)
|
initInputBoxValue(options)
|
||||||
@@ -126,7 +110,9 @@ export default {
|
|||||||
.inputbox-container {
|
.inputbox-container {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
box-shadow:
|
||||||
|
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
||||||
|
0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||||
max-width: 32rem;
|
max-width: 32rem;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
|
|||||||
@@ -1,36 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<nav
|
<nav class="navigation" :class="{ collapsed: isCollapsed }">
|
||||||
class="navigation"
|
|
||||||
:class="{ collapsed: isCollapsed }"
|
|
||||||
>
|
|
||||||
<div class="title-bar">
|
<div class="title-bar">
|
||||||
<div
|
<div v-if="!isCollapsed" class="app-title">
|
||||||
v-if="!isCollapsed"
|
<div class="app-text" @click="openGithubPage">
|
||||||
class="app-title"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="app-text"
|
|
||||||
@click="openGithubPage"
|
|
||||||
>
|
|
||||||
{{ t('app.title') }}
|
{{ t('app.title') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="app-version">
|
<div class="app-version">v{{ version }}</div>
|
||||||
v{{ version }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
:title="isCollapsed ? t('navigation.expand') : t('navigation.collapse')"
|
:title="isCollapsed ? t('navigation.expand') : t('navigation.collapse')"
|
||||||
class="collapse-button"
|
class="collapse-button"
|
||||||
@click="isCollapsed = !isCollapsed"
|
@click="isCollapsed = !isCollapsed"
|
||||||
>
|
>
|
||||||
<ChevronLeftIcon
|
<ChevronLeftIcon v-if="!isCollapsed" :size="20" />
|
||||||
v-if="!isCollapsed"
|
<ChevronRightIcon v-else :size="20" />
|
||||||
:size="20"
|
|
||||||
/>
|
|
||||||
<ChevronRightIcon
|
|
||||||
v-else
|
|
||||||
:size="20"
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -47,33 +30,18 @@
|
|||||||
:title="`${item.name}`"
|
:title="`${item.name}`"
|
||||||
>
|
>
|
||||||
<div class="nav-icon-container">
|
<div class="nav-icon-container">
|
||||||
<component
|
<component :is="item.icon" :size="18" />
|
||||||
:is="item.icon"
|
|
||||||
:size="18"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span v-if="!isCollapsed" class="nav-label">{{ item.name }}</span>
|
||||||
v-if="!isCollapsed"
|
|
||||||
class="nav-label"
|
|
||||||
>{{ item.name }}</span>
|
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<Disclosure
|
<Disclosure v-if="!isCollapsed" v-slot="{ open }" as="div" class="nav-submenu">
|
||||||
v-if="!isCollapsed"
|
|
||||||
v-slot="{ open }"
|
|
||||||
as="div"
|
|
||||||
class="nav-submenu"
|
|
||||||
>
|
|
||||||
<DisclosureButton class="nav-item submenu-trigger">
|
<DisclosureButton class="nav-item submenu-trigger">
|
||||||
<div class="nav-icon-container">
|
<div class="nav-icon-container">
|
||||||
<DatabaseIcon :size="18" />
|
<DatabaseIcon :size="18" />
|
||||||
</div>
|
</div>
|
||||||
<span class="nav-label">{{ t('navigation.picbed') }}</span>
|
<span class="nav-label">{{ t('navigation.picbed') }}</span>
|
||||||
<ChevronDownIcon
|
<ChevronDownIcon :size="16" class="submenu-arrow" :class="{ 'rotate-180': open }" />
|
||||||
:size="16"
|
|
||||||
class="submenu-arrow"
|
|
||||||
:class="{ 'rotate-180': open }"
|
|
||||||
/>
|
|
||||||
</DisclosureButton>
|
</DisclosureButton>
|
||||||
<DisclosurePanel class="submenu-panel">
|
<DisclosurePanel class="submenu-panel">
|
||||||
<router-link
|
<router-link
|
||||||
@@ -86,12 +54,7 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
</DisclosurePanel>
|
</DisclosurePanel>
|
||||||
</Disclosure>
|
</Disclosure>
|
||||||
<div
|
<div v-else class="nav-item collapsed-picbed" :title="t('navigation.picbed')" @click="isCollapsed = !isCollapsed">
|
||||||
v-else
|
|
||||||
class="nav-item collapsed-picbed"
|
|
||||||
:title="t('navigation.picbed')"
|
|
||||||
@click="isCollapsed = !isCollapsed"
|
|
||||||
>
|
|
||||||
<div class="nav-icon-container">
|
<div class="nav-icon-container">
|
||||||
<DatabaseIcon :size="18" />
|
<DatabaseIcon :size="18" />
|
||||||
</div>
|
</div>
|
||||||
@@ -105,37 +68,19 @@
|
|||||||
:title="`${item.name}`"
|
:title="`${item.name}`"
|
||||||
>
|
>
|
||||||
<div class="nav-icon-container">
|
<div class="nav-icon-container">
|
||||||
<component
|
<component :is="item.icon" :size="18" />
|
||||||
:is="item.icon"
|
|
||||||
:size="18"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span v-if="!isCollapsed" class="nav-label">{{ item.name }}</span>
|
||||||
v-if="!isCollapsed"
|
|
||||||
class="nav-label"
|
|
||||||
>{{ item.name }}</span>
|
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-footer">
|
<div class="sidebar-footer">
|
||||||
<button
|
<button class="footer-button" :title="t('navigation.moreOptions')" @click="openMenu">
|
||||||
class="footer-button"
|
|
||||||
:title="t('navigation.moreOptions')"
|
|
||||||
@click="openMenu"
|
|
||||||
>
|
|
||||||
<Info :size="20" />
|
<Info :size="20" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<TransitionRoot
|
<TransitionRoot appear :show="qrcodeVisible" as="template">
|
||||||
appear
|
<Dialog as="div" class="qr-dialog" @close="qrcodeVisible = false">
|
||||||
:show="qrcodeVisible"
|
|
||||||
as="template"
|
|
||||||
>
|
|
||||||
<Dialog
|
|
||||||
as="div"
|
|
||||||
class="qr-dialog"
|
|
||||||
@close="qrcodeVisible = false"
|
|
||||||
>
|
|
||||||
<div class="dialog-container">
|
<div class="dialog-container">
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as="template"
|
as="template"
|
||||||
@@ -154,28 +99,16 @@
|
|||||||
<div class="dialog-content">
|
<div class="dialog-content">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">{{ t('navigation.choosePicBed') }}</label>
|
<label class="form-label">{{ t('navigation.choosePicBed') }}</label>
|
||||||
<Listbox
|
<Listbox v-model="choosedPicBedForQRCode" multiple>
|
||||||
v-model="choosedPicBedForQRCode"
|
|
||||||
multiple
|
|
||||||
>
|
|
||||||
<div class="listbox-container">
|
<div class="listbox-container">
|
||||||
<ListboxButton class="listbox-button">
|
<ListboxButton class="listbox-button">
|
||||||
<span
|
<span v-if="choosedPicBedForQRCode.length === 0" class="placeholder">
|
||||||
v-if="choosedPicBedForQRCode.length === 0"
|
|
||||||
class="placeholder"
|
|
||||||
>
|
|
||||||
{{ t('navigation.selectPicBeds') }}
|
{{ t('navigation.selectPicBeds') }}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span v-else class="selected-count">
|
||||||
v-else
|
|
||||||
class="selected-count"
|
|
||||||
>
|
|
||||||
{{ choosedPicBedForQRCode.length }} {{ t('navigation.selected') }}
|
{{ choosedPicBedForQRCode.length }} {{ t('navigation.selected') }}
|
||||||
</span>
|
</span>
|
||||||
<ChevronDownIcon
|
<ChevronDownIcon :size="16" class="listbox-arrow" />
|
||||||
:size="16"
|
|
||||||
class="listbox-arrow"
|
|
||||||
/>
|
|
||||||
</ListboxButton>
|
</ListboxButton>
|
||||||
|
|
||||||
<transition
|
<transition
|
||||||
@@ -190,15 +123,9 @@
|
|||||||
v-slot="{ active, selected }"
|
v-slot="{ active, selected }"
|
||||||
:value="picbed.type"
|
:value="picbed.type"
|
||||||
>
|
>
|
||||||
<li
|
<li class="listbox-option" :class="{ active, selected }">
|
||||||
class="listbox-option"
|
|
||||||
:class="{ active, selected }"
|
|
||||||
>
|
|
||||||
<span>{{ picbed.name }}</span>
|
<span>{{ picbed.name }}</span>
|
||||||
<CheckIcon
|
<CheckIcon v-if="selected" :size="16" />
|
||||||
v-if="selected"
|
|
||||||
:size="16"
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
</ListboxOption>
|
</ListboxOption>
|
||||||
</ListboxOptions>
|
</ListboxOptions>
|
||||||
@@ -206,33 +133,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</Listbox>
|
</Listbox>
|
||||||
|
|
||||||
<button
|
<button v-if="choosedPicBedForQRCode.length > 0" class="copy-button" @click="handleCopyPicBedConfig">
|
||||||
v-if="choosedPicBedForQRCode.length > 0"
|
|
||||||
class="copy-button"
|
|
||||||
@click="handleCopyPicBedConfig"
|
|
||||||
>
|
|
||||||
<CopyIcon :size="16" />
|
<CopyIcon :size="16" />
|
||||||
{{ t('navigation.copyPicBedConfig') }}
|
{{ t('navigation.copyPicBedConfig') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="choosedPicBedForQRCode.length > 0" class="qr-container">
|
||||||
v-if="choosedPicBedForQRCode.length > 0"
|
<qrcode-vue :size="280" :value="picBedConfigString" class="qr-code" />
|
||||||
class="qr-container"
|
|
||||||
>
|
|
||||||
<qrcode-vue
|
|
||||||
:size="280"
|
|
||||||
:value="picBedConfigString"
|
|
||||||
class="qr-code"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dialog-actions">
|
<div class="dialog-actions">
|
||||||
<button
|
<button class="cancel-button" @click="qrcodeVisible = false">
|
||||||
class="cancel-button"
|
|
||||||
@click="qrcodeVisible = false"
|
|
||||||
>
|
|
||||||
{{ $t('navigation.close') }}
|
{{ $t('navigation.close') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -259,7 +172,20 @@ import {
|
|||||||
TransitionRoot
|
TransitionRoot
|
||||||
} from '@headlessui/vue'
|
} from '@headlessui/vue'
|
||||||
import { pick } from 'lodash-es'
|
import { pick } from 'lodash-es'
|
||||||
import { BriefcaseBusiness, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, CopyIcon, DatabaseIcon, ImagesIcon, Info, PlugIcon, Settings, UploadIcon } from 'lucide-vue-next'
|
import {
|
||||||
|
BriefcaseBusiness,
|
||||||
|
CheckIcon,
|
||||||
|
ChevronDownIcon,
|
||||||
|
ChevronLeftIcon,
|
||||||
|
ChevronRightIcon,
|
||||||
|
CopyIcon,
|
||||||
|
DatabaseIcon,
|
||||||
|
ImagesIcon,
|
||||||
|
Info,
|
||||||
|
PlugIcon,
|
||||||
|
Settings,
|
||||||
|
UploadIcon
|
||||||
|
} from 'lucide-vue-next'
|
||||||
import QrcodeVue from 'qrcode.vue'
|
import QrcodeVue from 'qrcode.vue'
|
||||||
import pkg from 'root/package.json'
|
import pkg from 'root/package.json'
|
||||||
import { computed, nextTick, onBeforeMount, onBeforeUnmount, reactive, Ref, ref, watch } from 'vue'
|
import { computed, nextTick, onBeforeMount, onBeforeUnmount, reactive, Ref, ref, watch } from 'vue'
|
||||||
@@ -286,7 +212,7 @@ const picBedConfigString = ref('')
|
|||||||
let removeIpcListener: () => void = () => {}
|
let removeIpcListener: () => void = () => {}
|
||||||
|
|
||||||
// Save collapsed state to localStorage when it changes
|
// Save collapsed state to localStorage when it changes
|
||||||
watch(isCollapsed, (newValue) => {
|
watch(isCollapsed, newValue => {
|
||||||
localStorage.setItem('navigation-collapsed', JSON.stringify(newValue))
|
localStorage.setItem('navigation-collapsed', JSON.stringify(newValue))
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -304,9 +230,7 @@ watch(
|
|||||||
{ deep: true }
|
{ deep: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
const visiblePicBeds = computed(() =>
|
const visiblePicBeds = computed(() => picBedGlobal.value.filter(item => item.visible))
|
||||||
picBedGlobal.value.filter(item => item.visible)
|
|
||||||
)
|
|
||||||
|
|
||||||
const qrCodeHandler = () => {
|
const qrCodeHandler = () => {
|
||||||
qrcodeVisible.value = true
|
qrcodeVisible.value = true
|
||||||
@@ -351,7 +275,6 @@ onBeforeMount(() => {
|
|||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
removeIpcListener()
|
removeIpcListener()
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="toolbox-handler">
|
<div class="toolbox-handler">
|
||||||
<button
|
<button class="handler-button" @click="() => props.handler(value)">
|
||||||
class="handler-button"
|
|
||||||
@click="() => props.handler(value)"
|
|
||||||
>
|
|
||||||
{{ props.handlerText }}
|
{{ props.handlerText }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
status: string
|
status: string
|
||||||
value: any
|
value: any
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<component
|
<component :is="icon" class="toolbox-status-icon" :style="{ color }" />
|
||||||
:is="icon"
|
|
||||||
class="toolbox-status-icon"
|
|
||||||
:style="{ color }"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div id="config-form" :class="[{ white: props.colorMode === 'white' }]">
|
||||||
id="config-form"
|
<form ref="$form" class="config-form" @submit.prevent>
|
||||||
:class="[{ white: props.colorMode === 'white' }]"
|
|
||||||
>
|
|
||||||
<form
|
|
||||||
ref="$form"
|
|
||||||
class="config-form"
|
|
||||||
@submit.prevent
|
|
||||||
>
|
|
||||||
<!-- Config Name Field -->
|
<!-- Config Name Field -->
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
<label class="form-label">{{ t('pages.configForm.configName') }}</label>
|
<label class="form-label">{{ t('pages.configForm.configName') }}</label>
|
||||||
@@ -20,11 +13,8 @@
|
|||||||
:placeholder="t('pages.configForm.configNamePlaceholder')"
|
:placeholder="t('pages.configForm.configNamePlaceholder')"
|
||||||
:class="{ error: validationErrors._configName }"
|
:class="{ error: validationErrors._configName }"
|
||||||
@input="clearFieldError('_configName')"
|
@input="clearFieldError('_configName')"
|
||||||
>
|
/>
|
||||||
<div
|
<div v-if="validationErrors._configName" class="error-message">
|
||||||
v-if="validationErrors._configName"
|
|
||||||
class="error-message"
|
|
||||||
>
|
|
||||||
{{ validationErrors._configName }}
|
{{ validationErrors._configName }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -39,14 +29,8 @@
|
|||||||
>
|
>
|
||||||
<div class="form-label-wrapper">
|
<div class="form-label-wrapper">
|
||||||
<label class="form-label">{{ item.alias || item.name }}</label>
|
<label class="form-label">{{ item.alias || item.name }}</label>
|
||||||
<div
|
<div v-if="showTooltips && item.tips" class="tooltip-wrapper">
|
||||||
v-if="showTooltips && item.tips"
|
<div class="info-icon" @click="toggleTooltip(item.name + index)">
|
||||||
class="tooltip-wrapper"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="info-icon"
|
|
||||||
@click="toggleTooltip(item.name + index)"
|
|
||||||
>
|
|
||||||
<Info :size="20" />
|
<Info :size="20" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -67,23 +51,17 @@
|
|||||||
:placeholder="item.message || item.name"
|
:placeholder="item.message || item.name"
|
||||||
:class="{ error: validationErrors[item.name] }"
|
:class="{ error: validationErrors[item.name] }"
|
||||||
@input="clearFieldError(item.name)"
|
@input="clearFieldError(item.name)"
|
||||||
>
|
/>
|
||||||
|
|
||||||
<!-- Select (Single) -->
|
<!-- Select (Single) -->
|
||||||
<div
|
<div v-else-if="item.type === 'list' && item.choices" class="select-wrapper">
|
||||||
v-else-if="item.type === 'list' && item.choices"
|
|
||||||
class="select-wrapper"
|
|
||||||
>
|
|
||||||
<select
|
<select
|
||||||
v-model="ruleForm[item.name]"
|
v-model="ruleForm[item.name]"
|
||||||
class="form-select"
|
class="form-select"
|
||||||
:class="{ error: validationErrors[item.name] }"
|
:class="{ error: validationErrors[item.name] }"
|
||||||
@change="clearFieldError(item.name)"
|
@change="clearFieldError(item.name)"
|
||||||
>
|
>
|
||||||
<option
|
<option value="" disabled>
|
||||||
value=""
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
{{ item.message || item.name }}
|
{{ item.message || item.name }}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
@@ -100,15 +78,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Multi-Select (Checkbox style) -->
|
<!-- Multi-Select (Checkbox style) -->
|
||||||
<div
|
<div v-else-if="item.type === 'checkbox' && item.choices" class="checkbox-group">
|
||||||
v-else-if="item.type === 'checkbox' && item.choices"
|
<div v-for="choice in item.choices" :key="choice.value || choice" class="checkbox-item">
|
||||||
class="checkbox-group"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="choice in item.choices"
|
|
||||||
:key="choice.value || choice"
|
|
||||||
class="checkbox-item"
|
|
||||||
>
|
|
||||||
<label class="checkbox-label">
|
<label class="checkbox-label">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -116,7 +87,7 @@
|
|||||||
:checked="Array.isArray(ruleForm[item.name]) && ruleForm[item.name].includes(choice.value || choice)"
|
:checked="Array.isArray(ruleForm[item.name]) && ruleForm[item.name].includes(choice.value || choice)"
|
||||||
class="checkbox-input"
|
class="checkbox-input"
|
||||||
@change="handleCheckboxChange(item.name, choice.value || choice, $event)"
|
@change="handleCheckboxChange(item.name, choice.value || choice, $event)"
|
||||||
>
|
/>
|
||||||
<span class="checkbox-custom" />
|
<span class="checkbox-custom" />
|
||||||
<span class="checkbox-text">{{ choice.name || choice.value || choice }}</span>
|
<span class="checkbox-text">{{ choice.name || choice.value || choice }}</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -124,29 +95,23 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Switch/Toggle -->
|
<!-- Switch/Toggle -->
|
||||||
<label
|
<label v-else-if="item.type === 'confirm'" class="switch-label">
|
||||||
v-else-if="item.type === 'confirm'"
|
|
||||||
class="switch-label"
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
v-model="ruleForm[item.name]"
|
v-model="ruleForm[item.name]"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="switch-input"
|
class="switch-input"
|
||||||
@change="clearFieldError(item.name)"
|
@change="clearFieldError(item.name)"
|
||||||
>
|
/>
|
||||||
<span class="switch-slider">
|
<span class="switch-slider">
|
||||||
<span class="switch-button" />
|
<span class="switch-button" />
|
||||||
</span>
|
</span>
|
||||||
<span class="switch-text">
|
<span class="switch-text">
|
||||||
{{ ruleForm[item.name] ? (item.confirmText || 'Yes') : (item.cancelText || 'No') }}
|
{{ ruleForm[item.name] ? item.confirmText || 'Yes' : item.cancelText || 'No' }}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<!-- Validation Error -->
|
<!-- Validation Error -->
|
||||||
<div
|
<div v-if="validationErrors[item.name]" class="error-message">
|
||||||
v-if="validationErrors[item.name]"
|
|
||||||
class="error-message"
|
|
||||||
>
|
|
||||||
{{ validationErrors[item.name] }}
|
{{ validationErrors[item.name] }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -325,10 +290,7 @@ async function handleConfig (val: IPicGoPluginConfig[]) {
|
|||||||
let defaultValue = item.default !== undefined ? item.default : item.type === 'checkbox' ? [] : null
|
let defaultValue = item.default !== undefined ? item.default : item.type === 'checkbox' ? [] : null
|
||||||
|
|
||||||
if (item.type === 'checkbox') {
|
if (item.type === 'checkbox') {
|
||||||
const defaults =
|
const defaults = item.choices?.filter((i: any) => i.checked).map((i: any) => i.value) || []
|
||||||
item.choices
|
|
||||||
?.filter((i: any) => i.checked)
|
|
||||||
.map((i: any) => i.value) || []
|
|
||||||
defaultValue = union(defaultValue, defaults)
|
defaultValue = union(defaultValue, defaults)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,10 +305,7 @@ async function handleConfig (val: IPicGoPluginConfig[]) {
|
|||||||
let defaultValue = item.default !== undefined ? item.default : item.type === 'checkbox' ? [] : null
|
let defaultValue = item.default !== undefined ? item.default : item.type === 'checkbox' ? [] : null
|
||||||
|
|
||||||
if (item.type === 'checkbox') {
|
if (item.type === 'checkbox') {
|
||||||
const defaults =
|
const defaults = item.choices?.filter((i: any) => i.checked).map((i: any) => i.value) || []
|
||||||
item.choices
|
|
||||||
?.filter((i: any) => i.checked)
|
|
||||||
.map((i: any) => i.value) || []
|
|
||||||
defaultValue = union(defaultValue, defaults)
|
defaultValue = union(defaultValue, defaults)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div ref="containerRef" class="virtual-scroller" :style="{ height: `${containerHeight}px` }" @scroll="handleScroll">
|
||||||
ref="containerRef"
|
<div class="virtual-scroller-content" :style="contentStyles">
|
||||||
class="virtual-scroller"
|
|
||||||
:style="{ height: `${containerHeight}px` }"
|
|
||||||
@scroll="handleScroll"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="virtual-scroller-content"
|
|
||||||
:style="contentStyles"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="virtual-scroller-viewport"
|
class="virtual-scroller-viewport"
|
||||||
:class="{ 'is-grid': isGridMode, 'is-list': !isGridMode }"
|
:class="{ 'is-grid': isGridMode, 'is-list': !isGridMode }"
|
||||||
@@ -16,14 +8,15 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="realIndex in visibleIndexes"
|
v-for="realIndex in visibleIndexes"
|
||||||
:key="itemsRef[realIndex] && itemsRef[realIndex][props.keyField || 'id'] ? itemsRef[realIndex][props.keyField || 'id'] : realIndex"
|
:key="
|
||||||
|
itemsRef[realIndex] && itemsRef[realIndex][props.keyField || 'id']
|
||||||
|
? itemsRef[realIndex][props.keyField || 'id']
|
||||||
|
: realIndex
|
||||||
|
"
|
||||||
class="virtual-scroller-item"
|
class="virtual-scroller-item"
|
||||||
:style="itemStyle"
|
:style="itemStyle"
|
||||||
>
|
>
|
||||||
<slot
|
<slot :item="itemsRef[realIndex]" :index="realIndex" />
|
||||||
:item="itemsRef[realIndex]"
|
|
||||||
:index="realIndex"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -36,9 +29,13 @@ import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|||||||
import { useVirtualGrid } from '@/hooks/useVirtualGrid'
|
import { useVirtualGrid } from '@/hooks/useVirtualGrid'
|
||||||
|
|
||||||
type Item = any
|
type Item = any
|
||||||
interface Breakpoint { min: number; cols: number }
|
interface Breakpoint {
|
||||||
|
min: number
|
||||||
|
cols: number
|
||||||
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
items: Item[]
|
items: Item[]
|
||||||
itemHeight: number
|
itemHeight: number
|
||||||
height?: number
|
height?: number
|
||||||
@@ -49,7 +46,8 @@ const props = withDefaults(defineProps<{
|
|||||||
keyField?: string
|
keyField?: string
|
||||||
itemPadding?: number
|
itemPadding?: number
|
||||||
viewMode?: 'list' | 'grid'
|
viewMode?: 'list' | 'grid'
|
||||||
}>(), {
|
}>(),
|
||||||
|
{
|
||||||
height: 400,
|
height: 400,
|
||||||
gridItems: 1,
|
gridItems: 1,
|
||||||
gridBreakpoints: () => [],
|
gridBreakpoints: () => [],
|
||||||
@@ -58,7 +56,8 @@ const props = withDefaults(defineProps<{
|
|||||||
keyField: 'id',
|
keyField: 'id',
|
||||||
itemPadding: 0,
|
itemPadding: 0,
|
||||||
viewMode: 'grid'
|
viewMode: 'grid'
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const containerRef = ref<HTMLElement | null>(null)
|
const containerRef = ref<HTMLElement | null>(null)
|
||||||
const containerHeight = ref<number>(props.pageMode ? 0 : props.height)
|
const containerHeight = ref<number>(props.pageMode ? 0 : props.height)
|
||||||
@@ -66,15 +65,23 @@ const containerWidth = ref<number>(0)
|
|||||||
const parentScrollListeners = ref<HTMLElement[]>([])
|
const parentScrollListeners = ref<HTMLElement[]>([])
|
||||||
|
|
||||||
const itemsRef = ref<Item[]>(props.items)
|
const itemsRef = ref<Item[]>(props.items)
|
||||||
watch(() => props.items, v => { itemsRef.value = v })
|
watch(
|
||||||
|
() => props.items,
|
||||||
|
v => {
|
||||||
|
itemsRef.value = v
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const localViewMode = ref<'list' | 'grid'>(props.viewMode)
|
const localViewMode = ref<'list' | 'grid'>(props.viewMode)
|
||||||
watch(() => props.viewMode, v => { localViewMode.value = v })
|
watch(
|
||||||
|
() => props.viewMode,
|
||||||
const sortedBreakpoints = computed<Breakpoint[]>(() =>
|
v => {
|
||||||
[...props.gridBreakpoints].sort((a, b) => a.min - b.min)
|
localViewMode.value = v
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const sortedBreakpoints = computed<Breakpoint[]>(() => [...props.gridBreakpoints].sort((a, b) => a.min - b.min))
|
||||||
|
|
||||||
const isForcedList = computed(() => localViewMode.value === 'list')
|
const isForcedList = computed(() => localViewMode.value === 'list')
|
||||||
|
|
||||||
const effectiveCols = computed<number>(() => {
|
const effectiveCols = computed<number>(() => {
|
||||||
@@ -92,13 +99,8 @@ const effectiveCols = computed<number>(() => {
|
|||||||
|
|
||||||
const isGridMode = computed(() => effectiveCols.value > 1)
|
const isGridMode = computed(() => effectiveCols.value > 1)
|
||||||
|
|
||||||
const {
|
const { gridCalculations, visibleIndexes, viewportOffset, updateScrollTop, scrollToItem, scrollToTop, scrollToBottom } =
|
||||||
gridCalculations,
|
useVirtualGrid({
|
||||||
visibleIndexes,
|
|
||||||
viewportOffset,
|
|
||||||
updateScrollTop,
|
|
||||||
scrollToItem, scrollToTop, scrollToBottom
|
|
||||||
} = useVirtualGrid({
|
|
||||||
items: itemsRef,
|
items: itemsRef,
|
||||||
itemHeight: props.itemHeight,
|
itemHeight: props.itemHeight,
|
||||||
containerHeight,
|
containerHeight,
|
||||||
@@ -122,11 +124,7 @@ const viewportStyle = computed(() => {
|
|||||||
return base
|
return base
|
||||||
})
|
})
|
||||||
|
|
||||||
const itemStyle = computed(() =>
|
const itemStyle = computed(() => (isGridMode.value ? {} : { height: `${props.itemHeight}px` }))
|
||||||
isGridMode.value
|
|
||||||
? {}
|
|
||||||
: { height: `${props.itemHeight}px` }
|
|
||||||
)
|
|
||||||
|
|
||||||
function handleScroll() {
|
function handleScroll() {
|
||||||
const c = containerRef.value
|
const c = containerRef.value
|
||||||
@@ -206,7 +204,9 @@ onBeforeUnmount(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function scrollTo (index: number) { scrollToItem(index) }
|
function scrollTo(index: number) {
|
||||||
|
scrollToItem(index)
|
||||||
|
}
|
||||||
|
|
||||||
function setViewMode(mode: 'list' | 'grid') {
|
function setViewMode(mode: 'list' | 'grid') {
|
||||||
localViewMode.value = mode
|
localViewMode.value = mode
|
||||||
@@ -266,5 +266,4 @@ defineExpose({ scrollTo, scrollToTop, scrollToBottom, setViewMode, toggleViewMod
|
|||||||
.virtual-scroller-viewport.is-grid .virtual-scroller-item {
|
.virtual-scroller-viewport.is-grid .virtual-scroller-item {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,72 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div v-if="isOpen" class="messagebox-overlay" @click="onCancel">
|
||||||
v-if="isOpen"
|
<div class="messagebox-container" @click.stop>
|
||||||
class="messagebox-overlay"
|
|
||||||
@click="onCancel"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="messagebox-container"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
<div class="messagebox-header">
|
<div class="messagebox-header">
|
||||||
<h3 class="messagebox-title">
|
<h3 class="messagebox-title">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</h3>
|
</h3>
|
||||||
<button
|
<button v-if="showClose" class="messagebox-close" @click="onCancel">×</button>
|
||||||
v-if="showClose"
|
|
||||||
class="messagebox-close"
|
|
||||||
@click="onCancel"
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="messagebox-content">
|
<div class="messagebox-content">
|
||||||
<div
|
<div v-if="type" class="messagebox-icon">
|
||||||
v-if="type"
|
<component :is="iconComponent" :size="48" />
|
||||||
class="messagebox-icon"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="iconComponent"
|
|
||||||
:size="48"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="messagebox-message">
|
<div class="messagebox-message">
|
||||||
<p>{{ message }}</p>
|
<p>{{ message }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="center" class="messagebox-actions center">
|
||||||
v-if="center"
|
<button class="messagebox-btn cancel-btn" @click="onCancel">
|
||||||
class="messagebox-actions center"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="messagebox-btn cancel-btn"
|
|
||||||
@click="onCancel"
|
|
||||||
>
|
|
||||||
{{ cancelButtonText }}
|
{{ cancelButtonText }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="messagebox-btn confirm-btn" :class="confirmButtonClass" @click="onConfirm">
|
||||||
class="messagebox-btn confirm-btn"
|
|
||||||
:class="confirmButtonClass"
|
|
||||||
@click="onConfirm"
|
|
||||||
>
|
|
||||||
{{ confirmButtonText }}
|
{{ confirmButtonText }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-else class="messagebox-actions">
|
||||||
v-else
|
<button class="messagebox-btn confirm-btn" :class="confirmButtonClass" @click="onConfirm">
|
||||||
class="messagebox-actions"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="messagebox-btn confirm-btn"
|
|
||||||
:class="confirmButtonClass"
|
|
||||||
@click="onConfirm"
|
|
||||||
>
|
|
||||||
{{ confirmButtonText }}
|
{{ confirmButtonText }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="messagebox-btn cancel-btn" @click="onCancel">
|
||||||
class="messagebox-btn cancel-btn"
|
|
||||||
@click="onCancel"
|
|
||||||
>
|
|
||||||
{{ cancelButtonText }}
|
{{ cancelButtonText }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -164,7 +125,9 @@ export default {
|
|||||||
.messagebox-container {
|
.messagebox-container {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
box-shadow:
|
||||||
|
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
||||||
|
0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||||
max-width: 32rem;
|
max-width: 32rem;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
@@ -239,19 +202,19 @@ export default {
|
|||||||
color: rgb(107 114 128);
|
color: rgb(107 114 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
.messagebox-icon svg[data-lucide="alert-triangle"] {
|
.messagebox-icon svg[data-lucide='alert-triangle'] {
|
||||||
color: rgb(245 158 11);
|
color: rgb(245 158 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
.messagebox-icon svg[data-lucide="info"] {
|
.messagebox-icon svg[data-lucide='info'] {
|
||||||
color: rgb(59 130 246);
|
color: rgb(59 130 246);
|
||||||
}
|
}
|
||||||
|
|
||||||
.messagebox-icon svg[data-lucide="check-circle"] {
|
.messagebox-icon svg[data-lucide='check-circle'] {
|
||||||
color: rgb(34 197 94);
|
color: rgb(34 197 94);
|
||||||
}
|
}
|
||||||
|
|
||||||
.messagebox-icon svg[data-lucide="x-circle"] {
|
.messagebox-icon svg[data-lucide='x-circle'] {
|
||||||
color: rgb(239 68 68);
|
color: rgb(239 68 68);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="message-container">
|
<div class="message-container">
|
||||||
<TransitionGroup
|
<TransitionGroup name="message" tag="div">
|
||||||
name="message"
|
<div v-for="message in messages" :key="message.id" class="message-toast" :class="getMessageClass(message.type)">
|
||||||
tag="div"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="message in messages"
|
|
||||||
:key="message.id"
|
|
||||||
class="message-toast"
|
|
||||||
:class="getMessageClass(message.type)"
|
|
||||||
>
|
|
||||||
<div class="message-icon">
|
<div class="message-icon">
|
||||||
<component
|
<component :is="getIconComponent(message.type)" :size="20" />
|
||||||
:is="getIconComponent(message.type)"
|
|
||||||
:size="20"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="message-content">
|
<div class="message-content">
|
||||||
{{ message.message }}
|
{{ message.message }}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button v-if="message.showClose" class="message-close" @click="removeMessage(message.id)">
|
||||||
v-if="message.showClose"
|
|
||||||
class="message-close"
|
|
||||||
@click="removeMessage(message.id)"
|
|
||||||
>
|
|
||||||
<X :size="16" />
|
<X :size="16" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -149,7 +134,9 @@ export default {
|
|||||||
padding: 0.75rem 1rem;
|
padding: 0.75rem 1rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
box-shadow:
|
||||||
|
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
||||||
|
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||||
max-width: 24rem;
|
max-width: 24rem;
|
||||||
min-width: 20rem;
|
min-width: 20rem;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
|
|||||||
@@ -48,20 +48,9 @@ const toggleTheme = () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="theme-switcher">
|
<div class="theme-switcher">
|
||||||
<button
|
<button class="theme-toggle-btn" :class="{ collapsed }" :title="t('settings.theme.toggle')" @click="toggleTheme">
|
||||||
class="theme-toggle-btn"
|
<component :is="currentThemeOption.icon" :size="18" />
|
||||||
:class="{ collapsed }"
|
<span v-if="!collapsed" class="theme-label">{{ currentThemeOption.label }}</span>
|
||||||
:title="t('settings.theme.toggle')"
|
|
||||||
@click="toggleTheme"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="currentThemeOption.icon"
|
|
||||||
:size="18"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
v-if="!collapsed"
|
|
||||||
class="theme-label"
|
|
||||||
>{{ currentThemeOption.label }}</span>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,42 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div class="title-bar" data-drag-region>
|
||||||
class="title-bar"
|
|
||||||
data-drag-region
|
|
||||||
>
|
|
||||||
<div class="title-bar-content">
|
<div class="title-bar-content">
|
||||||
<div
|
<div v-if="osGlobal !== 'darwin'" class="title-left">
|
||||||
v-if="osGlobal !== 'darwin'"
|
|
||||||
class="title-left"
|
|
||||||
>
|
|
||||||
<div class="app-icon">
|
<div class="app-icon">
|
||||||
<img
|
<img :src="defaultLogo" alt="App Icon" width="20" height="20" />
|
||||||
:src="defaultLogo"
|
|
||||||
alt="App Icon"
|
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="title-center">
|
<div class="title-center">
|
||||||
<!-- Progress bar in title bar -->
|
<!-- Progress bar in title bar -->
|
||||||
<div
|
<div v-if="isShowprogress" class="progress-container">
|
||||||
v-if="isShowprogress"
|
|
||||||
class="progress-container"
|
|
||||||
>
|
|
||||||
<div class="progress-bar">
|
<div class="progress-bar">
|
||||||
<div
|
<div class="progress-fill" :style="{ width: `${progress}%` }" />
|
||||||
class="progress-fill"
|
|
||||||
:style="{ width: `${progress}%` }"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="progress-text">{{ progress }}%</span>
|
<span class="progress-text">{{ progress }}%</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div class="title-right">
|
||||||
class="title-right"
|
|
||||||
>
|
|
||||||
<div class="window-controls">
|
<div class="window-controls">
|
||||||
<button
|
<button
|
||||||
class="control-button pin-button"
|
class="control-button pin-button"
|
||||||
@@ -44,30 +25,15 @@
|
|||||||
:title="$t('titleBar.alwaysOnTop')"
|
:title="$t('titleBar.alwaysOnTop')"
|
||||||
@click="setAlwaysOnTop"
|
@click="setAlwaysOnTop"
|
||||||
>
|
>
|
||||||
<PinIcon
|
<PinIcon :color="isAlwaysOnTop ? '#CE6769' : '#6B7280'" :size="14" />
|
||||||
:color="isAlwaysOnTop ? '#CE6769' : '#6B7280'"
|
|
||||||
:size="14"
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="control-button minimize-button" :title="$t('titleBar.minimize')" @click="minimizeWindow">
|
||||||
class="control-button minimize-button"
|
|
||||||
:title="$t('titleBar.minimize')"
|
|
||||||
@click="minimizeWindow"
|
|
||||||
>
|
|
||||||
<MinusIcon :size="14" />
|
<MinusIcon :size="14" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="control-button mini-button" :title="$t('titleBar.miniWindow')" @click="openMiniWindow">
|
||||||
class="control-button mini-button"
|
|
||||||
:title="$t('titleBar.miniWindow')"
|
|
||||||
@click="openMiniWindow"
|
|
||||||
>
|
|
||||||
<ShrinkIcon :size="14" />
|
<ShrinkIcon :size="14" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="control-button close-button" :title="$t('titleBar.close')" @click="closeWindow">
|
||||||
class="control-button close-button"
|
|
||||||
:title="$t('titleBar.close')"
|
|
||||||
@click="closeWindow"
|
|
||||||
>
|
|
||||||
<XIcon :size="14" />
|
<XIcon :size="14" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ const handleCancel = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const showConfirm = (options: ConfirmOptions): Promise<boolean> => {
|
const showConfirm = (options: ConfirmOptions): Promise<boolean> => {
|
||||||
return new Promise((resolve) => {
|
return new Promise(resolve => {
|
||||||
Object.assign(confirmOptions, {
|
Object.assign(confirmOptions, {
|
||||||
title: 'Confirm',
|
title: 'Confirm',
|
||||||
type: 'info',
|
type: 'info',
|
||||||
|
|||||||
@@ -78,6 +78,5 @@ export const useAppStore = defineStore('app', () => {
|
|||||||
setTheme,
|
setTheme,
|
||||||
toggleTheme,
|
toggleTheme,
|
||||||
applyTheme
|
applyTheme
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,13 +10,7 @@ export interface UseVirtualGridOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useVirtualGrid(options: UseVirtualGridOptions) {
|
export function useVirtualGrid(options: UseVirtualGridOptions) {
|
||||||
const {
|
const { items, itemHeight, containerHeight, gridItems = 1, bufferFactor = 0.5 } = options
|
||||||
items,
|
|
||||||
itemHeight,
|
|
||||||
containerHeight,
|
|
||||||
gridItems = 1,
|
|
||||||
bufferFactor = 0.5
|
|
||||||
} = options
|
|
||||||
|
|
||||||
const gridItemsRef = isRef(gridItems) ? gridItems : ref(gridItems)
|
const gridItemsRef = isRef(gridItems) ? gridItems : ref(gridItems)
|
||||||
const scrollTop = ref(0)
|
const scrollTop = ref(0)
|
||||||
@@ -43,7 +37,7 @@ export function useVirtualGrid (options: UseVirtualGridOptions) {
|
|||||||
return { startRow: 0, endRow: 0, visibleRows: 0 }
|
return { startRow: 0, endRow: 0, visibleRows: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
const buffer = Math.ceil(height / rowHeight * bufferFactor)
|
const buffer = Math.ceil((height / rowHeight) * bufferFactor)
|
||||||
const startRow = Math.max(0, Math.floor(scrollTop.value / rowHeight) - buffer)
|
const startRow = Math.max(0, Math.floor(scrollTop.value / rowHeight) - buffer)
|
||||||
const visibleRows = Math.ceil(height / rowHeight) + buffer * 2
|
const visibleRows = Math.ceil(height / rowHeight) + buffer * 2
|
||||||
const endRow = Math.min(totalRows, startRow + visibleRows)
|
const endRow = Math.min(totalRows, startRow + visibleRows)
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div id="main" class="app-container">
|
||||||
id="main"
|
|
||||||
class="app-container"
|
|
||||||
>
|
|
||||||
<InputBoxDialog />
|
<InputBoxDialog />
|
||||||
<TitleBar />
|
<TitleBar />
|
||||||
<div class="app-background">
|
<div class="app-background">
|
||||||
@@ -12,15 +9,9 @@
|
|||||||
<main class="main-content">
|
<main class="main-content">
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<router-view v-slot="{ Component, route }">
|
<router-view v-slot="{ Component, route }">
|
||||||
<transition
|
<transition name="page" mode="out-in">
|
||||||
name="page"
|
|
||||||
mode="out-in"
|
|
||||||
>
|
|
||||||
<keep-alive :include="keepAlivePages">
|
<keep-alive :include="keepAlivePages">
|
||||||
<component
|
<component :is="Component" :key="route.path" />
|
||||||
:is="Component"
|
|
||||||
:key="route.path"
|
|
||||||
/>
|
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
|
|||||||
@@ -2,26 +2,12 @@
|
|||||||
<div class="switch-container">
|
<div class="switch-container">
|
||||||
<div class="switch-label-wrapper">
|
<div class="switch-label-wrapper">
|
||||||
<span class="switch-label-text">
|
<span class="switch-label-text">
|
||||||
<span
|
<span v-for="(segment, index) in segments" :key="index" :style="segment.style">
|
||||||
v-for="(segment, index) in segments"
|
|
||||||
:key="index"
|
|
||||||
:style="segment.style"
|
|
||||||
>
|
|
||||||
{{ segment.text }}
|
{{ segment.text }}
|
||||||
</span>
|
</span>
|
||||||
<div
|
<div v-if="tooltip" class="tooltip-wrapper">
|
||||||
v-if="tooltip"
|
<div class="info-icon" @click="toggleTooltip">
|
||||||
class="tooltip-wrapper"
|
<svg viewBox="0 0 20 20" fill="currentColor" class="info-svg">
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="info-icon"
|
|
||||||
@click="toggleTooltip"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
class="info-svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
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"
|
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"
|
||||||
@@ -29,10 +15,7 @@
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-show="showTooltip" class="tooltip-content">
|
||||||
v-show="showTooltip"
|
|
||||||
class="tooltip-content"
|
|
||||||
>
|
|
||||||
{{ tooltip }}
|
{{ tooltip }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -40,19 +23,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="switch-control">
|
<div class="switch-control">
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
<input
|
<input v-model="value" type="checkbox" class="switch-input" />
|
||||||
v-model="value"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider">
|
<span class="switch-slider">
|
||||||
<span class="switch-button" />
|
<span class="switch-button" />
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div v-if="activeText || inactiveText" class="switch-text">
|
||||||
v-if="activeText || inactiveText"
|
|
||||||
class="switch-text"
|
|
||||||
>
|
|
||||||
{{ value ? activeText : inactiveText }}
|
{{ value ? activeText : inactiveText }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,10 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<button
|
<button class="action-button" @click="refreshConfigs">
|
||||||
class="action-button"
|
|
||||||
@click="refreshConfigs"
|
|
||||||
>
|
|
||||||
<RefreshCwIcon :size="16" />
|
<RefreshCwIcon :size="16" />
|
||||||
{{ t('pages.manage.login.refresh') }}
|
{{ t('pages.manage.login.refresh') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -28,10 +25,7 @@
|
|||||||
<div class="login-card tabs-card">
|
<div class="login-card tabs-card">
|
||||||
<div class="tabs-container">
|
<div class="tabs-container">
|
||||||
<div class="tabs-nav-wrapper">
|
<div class="tabs-nav-wrapper">
|
||||||
<div
|
<div ref="tabsNav" class="tabs-nav">
|
||||||
ref="tabsNav"
|
|
||||||
class="tabs-nav"
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
v-for="item in tabItems"
|
v-for="item in tabItems"
|
||||||
:key="item.key"
|
:key="item.key"
|
||||||
@@ -39,16 +33,8 @@
|
|||||||
:class="{ active: activeName === item.key }"
|
:class="{ active: activeName === item.key }"
|
||||||
@click="handleTabChange(item.key)"
|
@click="handleTabChange(item.key)"
|
||||||
>
|
>
|
||||||
<FolderIcon
|
<FolderIcon v-if="item.key === 'login'" :size="16" />
|
||||||
v-if="item.key === 'login'"
|
<img v-else :src="`./assets/${item.key}.webp`" class="tab-icon" :alt="item.name" />
|
||||||
:size="16"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
v-else
|
|
||||||
:src="`./assets/${item.key}.webp`"
|
|
||||||
class="tab-icon"
|
|
||||||
:alt="item.name"
|
|
||||||
>
|
|
||||||
<span>{{ item.name }}</span>
|
<span>{{ item.name }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -60,35 +46,18 @@
|
|||||||
<div class="login-card content-card">
|
<div class="login-card content-card">
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<!-- Main Config List Tab -->
|
<!-- Main Config List Tab -->
|
||||||
<div
|
<div v-if="activeName === 'login'" class="config-list-container">
|
||||||
v-if="activeName === 'login'"
|
<div v-if="sortedAllConfigAliasMap.length === 0" class="empty-state">
|
||||||
class="config-list-container"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="sortedAllConfigAliasMap.length === 0"
|
|
||||||
class="empty-state"
|
|
||||||
>
|
|
||||||
<div class="empty-icon">
|
<div class="empty-icon">
|
||||||
<DatabaseIcon :size="48" />
|
<DatabaseIcon :size="48" />
|
||||||
</div>
|
</div>
|
||||||
<h3>{{ t('pages.manage.login.noConfigs') }}</h3>
|
<h3>{{ t('pages.manage.login.noConfigs') }}</h3>
|
||||||
<p>{{ t('pages.manage.login.noConfigsDesc') }}</p>
|
<p>{{ t('pages.manage.login.noConfigsDesc') }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-else class="config-grid">
|
||||||
v-else
|
<div v-for="item in sortedAllConfigAliasMap" :key="item.alias" class="config-item">
|
||||||
class="config-grid"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="item in sortedAllConfigAliasMap"
|
|
||||||
:key="item.alias"
|
|
||||||
class="config-item"
|
|
||||||
>
|
|
||||||
<div class="config-header">
|
<div class="config-header">
|
||||||
<img
|
<img :src="`./assets/${item.picBedName}.webp`" class="config-icon" :alt="item.picBedName" />
|
||||||
:src="`./assets/${item.picBedName}.webp`"
|
|
||||||
class="config-icon"
|
|
||||||
:alt="item.picBedName"
|
|
||||||
>
|
|
||||||
<div class="config-info">
|
<div class="config-info">
|
||||||
<h4 class="config-alias">
|
<h4 class="config-alias">
|
||||||
{{ item.alias }}
|
{{ item.alias }}
|
||||||
@@ -100,22 +69,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="config-details">
|
<div class="config-details">
|
||||||
<button
|
<button class="details-button" @click="toggleConfigDetails(item.alias)">
|
||||||
class="details-button"
|
|
||||||
@click="toggleConfigDetails(item.alias)"
|
|
||||||
>
|
|
||||||
<InfoIcon :size="14" />
|
<InfoIcon :size="14" />
|
||||||
{{ t('pages.manage.login.viewDetails') }}
|
{{ t('pages.manage.login.viewDetails') }}
|
||||||
<ChevronDownIcon
|
<ChevronDownIcon :size="14" :class="{ rotated: expandedConfigs.includes(item.alias) }" />
|
||||||
:size="14"
|
|
||||||
:class="{ rotated: expandedConfigs.includes(item.alias) }"
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div
|
<div v-if="expandedConfigs.includes(item.alias)" class="config-table">
|
||||||
v-if="expandedConfigs.includes(item.alias)"
|
|
||||||
class="config-table"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
v-for="tableItem in formObjToTableData(item.config)"
|
v-for="tableItem in formObjToTableData(item.config)"
|
||||||
:key="tableItem.key"
|
:key="tableItem.key"
|
||||||
@@ -129,17 +89,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="config-actions">
|
<div class="config-actions">
|
||||||
<button
|
<button class="action-button primary" @click="handleConfigClick(item)">
|
||||||
class="action-button primary"
|
|
||||||
@click="handleConfigClick(item)"
|
|
||||||
>
|
|
||||||
<PointerIcon :size="16" />
|
<PointerIcon :size="16" />
|
||||||
{{ t('pages.manage.login.enter') }}
|
{{ t('pages.manage.login.enter') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="action-button danger" @click="handleConfigRemove(item.alias)">
|
||||||
class="action-button danger"
|
|
||||||
@click="handleConfigRemove(item.alias)"
|
|
||||||
>
|
|
||||||
<TrashIcon :size="16" />
|
<TrashIcon :size="16" />
|
||||||
{{ t('pages.manage.login.delete') }}
|
{{ t('pages.manage.login.delete') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -149,14 +103,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- PicBed Configuration Tabs -->
|
<!-- PicBed Configuration Tabs -->
|
||||||
<div
|
<div v-else class="picbed-config-container">
|
||||||
v-else
|
<div v-if="supportedPicBedList[activeName]" class="picbed-config">
|
||||||
class="picbed-config-container"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="supportedPicBedList[activeName]"
|
|
||||||
class="picbed-config"
|
|
||||||
>
|
|
||||||
<!-- Info Section -->
|
<!-- Info Section -->
|
||||||
<div class="info-section">
|
<div class="info-section">
|
||||||
<div class="info-card primary">
|
<div class="info-card primary">
|
||||||
@@ -167,10 +115,7 @@
|
|||||||
<LinkIcon :size="20" />
|
<LinkIcon :size="20" />
|
||||||
<p>
|
<p>
|
||||||
{{ supportedPicBedList[activeName].referenceText }}
|
{{ supportedPicBedList[activeName].referenceText }}
|
||||||
<button
|
<button class="link-button" @click="handleReferenceClick(supportedPicBedList[activeName].refLink)">
|
||||||
class="link-button"
|
|
||||||
@click="handleReferenceClick(supportedPicBedList[activeName].refLink)"
|
|
||||||
>
|
|
||||||
{{ supportedPicBedList[activeName].refLink }}
|
{{ supportedPicBedList[activeName].refLink }}
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
@@ -187,10 +132,9 @@
|
|||||||
>
|
>
|
||||||
<label class="form-label">
|
<label class="form-label">
|
||||||
{{ supportedPicBedList[activeName].configOptions[option].description }}
|
{{ supportedPicBedList[activeName].configOptions[option].description }}
|
||||||
<span
|
<span v-if="supportedPicBedList[activeName].configOptions[option].required" class="required-marker"
|
||||||
v-if="supportedPicBedList[activeName].configOptions[option].required"
|
>*</span
|
||||||
class="required-marker"
|
>
|
||||||
>*</span>
|
|
||||||
<button
|
<button
|
||||||
v-if="supportedPicBedList[activeName].configOptions[option].tooltip"
|
v-if="supportedPicBedList[activeName].configOptions[option].tooltip"
|
||||||
class="tooltip-button"
|
class="tooltip-button"
|
||||||
@@ -211,7 +155,7 @@
|
|||||||
:disabled="!!supportedPicBedList[activeName].configOptions[option].disabled"
|
:disabled="!!supportedPicBedList[activeName].configOptions[option].disabled"
|
||||||
@blur="validateField(activeName, option)"
|
@blur="validateField(activeName, option)"
|
||||||
@input="clearFieldError(activeName + '.' + option)"
|
@input="clearFieldError(activeName + '.' + option)"
|
||||||
>
|
/>
|
||||||
|
|
||||||
<!-- Boolean Switch -->
|
<!-- Boolean Switch -->
|
||||||
<label
|
<label
|
||||||
@@ -222,7 +166,7 @@
|
|||||||
v-model="configResult[activeName + '.' + option]"
|
v-model="configResult[activeName + '.' + option]"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="validateField(activeName, option)"
|
@change="validateField(activeName, option)"
|
||||||
>
|
/>
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@@ -236,7 +180,7 @@
|
|||||||
:placeholder="supportedPicBedList[activeName].configOptions[option].placeholder"
|
:placeholder="supportedPicBedList[activeName].configOptions[option].placeholder"
|
||||||
@blur="validateField(activeName, option)"
|
@blur="validateField(activeName, option)"
|
||||||
@input="clearFieldError(activeName + '.' + option)"
|
@input="clearFieldError(activeName + '.' + option)"
|
||||||
>
|
/>
|
||||||
|
|
||||||
<!-- Select Dropdown -->
|
<!-- Select Dropdown -->
|
||||||
<div
|
<div
|
||||||
@@ -253,7 +197,9 @@
|
|||||||
{{ t('pages.manage.login.selectPlaceholder') }}
|
{{ t('pages.manage.login.selectPlaceholder') }}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
v-for="[key, value] in Object.entries(supportedPicBedList[activeName].configOptions[option].selectOptions)"
|
v-for="[key, value] in Object.entries(
|
||||||
|
supportedPicBedList[activeName].configOptions[option].selectOptions
|
||||||
|
)"
|
||||||
:key="key"
|
:key="key"
|
||||||
:value="key"
|
:value="key"
|
||||||
>
|
>
|
||||||
@@ -263,10 +209,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error Message -->
|
<!-- Error Message -->
|
||||||
<div
|
<div v-if="formErrors[activeName + '.' + option]" class="error-message">
|
||||||
v-if="formErrors[activeName + '.' + option]"
|
|
||||||
class="error-message"
|
|
||||||
>
|
|
||||||
{{ formErrors[activeName + '.' + option] }}
|
{{ formErrors[activeName + '.' + option] }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -275,22 +218,13 @@
|
|||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<div class="action-section">
|
<div class="action-section">
|
||||||
<div class="import-section">
|
<div class="import-section">
|
||||||
<div
|
<div v-if="currentAliasList.length > 0" class="dropdown-container">
|
||||||
v-if="currentAliasList.length > 0"
|
<button class="dropdown-trigger action-button secondary" @click="toggleImportDropdown">
|
||||||
class="dropdown-container"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="dropdown-trigger action-button secondary"
|
|
||||||
@click="toggleImportDropdown"
|
|
||||||
>
|
|
||||||
<DownloadIcon :size="16" />
|
<DownloadIcon :size="16" />
|
||||||
{{ t('pages.manage.login.import') }}
|
{{ t('pages.manage.login.import') }}
|
||||||
<ChevronDownIcon :size="16" />
|
<ChevronDownIcon :size="16" />
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div v-if="importDropdownOpen" class="dropdown-menu">
|
||||||
v-if="importDropdownOpen"
|
|
||||||
class="dropdown-menu"
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
v-for="alias in currentAliasList"
|
v-for="alias in currentAliasList"
|
||||||
:key="alias"
|
:key="alias"
|
||||||
@@ -304,17 +238,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="main-actions">
|
<div class="main-actions">
|
||||||
<button
|
<button class="action-button primary" @click="handleConfigChange(activeName)">
|
||||||
class="action-button primary"
|
|
||||||
@click="handleConfigChange(activeName)"
|
|
||||||
>
|
|
||||||
<SaveIcon :size="16" />
|
<SaveIcon :size="16" />
|
||||||
{{ t('pages.manage.login.save') }}
|
{{ t('pages.manage.login.save') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="action-button danger" @click="handleConfigReset(activeName)">
|
||||||
class="action-button danger"
|
|
||||||
@click="handleConfigReset(activeName)"
|
|
||||||
>
|
|
||||||
<RotateCcwIcon :size="16" />
|
<RotateCcwIcon :size="16" />
|
||||||
{{ t('pages.manage.login.reset') }}
|
{{ t('pages.manage.login.reset') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -322,28 +250,19 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Existing Configurations Table -->
|
<!-- Existing Configurations Table -->
|
||||||
<div
|
<div v-if="dataForTable.length > 0" class="config-table-section">
|
||||||
v-if="dataForTable.length > 0"
|
|
||||||
class="config-table-section"
|
|
||||||
>
|
|
||||||
<h3>{{ t('pages.manage.login.configTabTitle') }}</h3>
|
<h3>{{ t('pages.manage.login.configTabTitle') }}</h3>
|
||||||
<div class="responsive-table">
|
<div class="responsive-table">
|
||||||
<table class="config-table">
|
<table class="config-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th
|
<th v-for="option in supportedPicBedList[activeName].options" :key="option">
|
||||||
v-for="option in supportedPicBedList[activeName].options"
|
|
||||||
:key="option"
|
|
||||||
>
|
|
||||||
{{ supportedPicBedList[activeName].configOptions[option].description }}
|
{{ supportedPicBedList[activeName].configOptions[option].description }}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr
|
<tr v-for="(row, index) in dataForTable" :key="index">
|
||||||
v-for="(row, index) in dataForTable"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<td
|
<td
|
||||||
v-for="option in supportedPicBedList[activeName].options"
|
v-for="option in supportedPicBedList[activeName].options"
|
||||||
:key="option"
|
:key="option"
|
||||||
@@ -633,15 +552,9 @@ async function handleConfigChange (name: string) {
|
|||||||
dataForTable.length = 0
|
dataForTable.length = 0
|
||||||
getDataForTable()
|
getDataForTable()
|
||||||
if (aliasList.includes(resultMap.alias)) {
|
if (aliasList.includes(resultMap.alias)) {
|
||||||
notifyUser(
|
notifyUser(`${t('pages.manage.login.configChangeMsg')}${resultMap.alias}`, 'warning')
|
||||||
`${t('pages.manage.login.configChangeMsg')}${resultMap.alias}`,
|
|
||||||
'warning'
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
notifyUser(
|
notifyUser(`${t('pages.manage.login.configSaveMsg')}${resultMap.alias}`, 'success')
|
||||||
`${t('pages.manage.login.configSaveMsg')}${resultMap.alias}`,
|
|
||||||
'success'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -671,17 +584,11 @@ const handleConfigRemove = async (name: string) => {
|
|||||||
if (!result) return
|
if (!result) return
|
||||||
try {
|
try {
|
||||||
removeConfig('picBed', name)
|
removeConfig('picBed', name)
|
||||||
notifyUser(
|
notifyUser(t('pages.manage.login.deleteConfigSuccessMsg'), 'success')
|
||||||
t('pages.manage.login.deleteConfigSuccessMsg'),
|
|
||||||
'success'
|
|
||||||
)
|
|
||||||
manageStore.refreshConfig()
|
manageStore.refreshConfig()
|
||||||
getAllConfigAliasArray()
|
getAllConfigAliasArray()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifyUser(
|
notifyUser(t('pages.manage.login.deleteConfigFailedMsg'), 'error')
|
||||||
t('pages.manage.login.deleteConfigFailedMsg'),
|
|
||||||
'error'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,7 @@
|
|||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
<div class="header-icon">
|
<div class="header-icon">
|
||||||
<img
|
<img :src="`./assets/${currentPagePicBedConfig.picBedName}.webp`" class="header-icon-img" />
|
||||||
:src="`./assets/${currentPagePicBedConfig.picBedName}.webp`"
|
|
||||||
class="header-icon-img"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="header-text">
|
<div class="header-text">
|
||||||
<h2 class="header-title">
|
<h2 class="header-title">
|
||||||
@@ -20,10 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<button
|
<button class="action-button secondary" @click="openPicBedUrl">
|
||||||
class="action-button secondary"
|
|
||||||
@click="openPicBedUrl"
|
|
||||||
>
|
|
||||||
<ExternalLinkIcon class="button-icon" />
|
<ExternalLinkIcon class="button-icon" />
|
||||||
{{ t('pages.manage.main.openPicBedUrl') }}
|
{{ t('pages.manage.main.openPicBedUrl') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -42,11 +36,7 @@
|
|||||||
<!-- Main Content Card -->
|
<!-- Main Content Card -->
|
||||||
<div class="manage-card main-card">
|
<div class="manage-card main-card">
|
||||||
<div class="main-layout">
|
<div class="main-layout">
|
||||||
<div
|
<div ref="sidebar" class="sidebar" :style="{ width: sidebarWidth + 'px' }">
|
||||||
ref="sidebar"
|
|
||||||
class="sidebar"
|
|
||||||
:style="{ width: sidebarWidth + 'px' }"
|
|
||||||
>
|
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<h3 class="sidebar-title">
|
<h3 class="sidebar-title">
|
||||||
{{ menuTitleMap[currentPicBedName] }}
|
{{ menuTitleMap[currentPicBedName] }}
|
||||||
@@ -54,17 +44,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sidebar-content">
|
<div class="sidebar-content">
|
||||||
<div
|
<div v-if="isLoadingBucketList" class="loading-container">
|
||||||
v-if="isLoadingBucketList"
|
|
||||||
class="loading-container"
|
|
||||||
>
|
|
||||||
<div class="loading-spinner" />
|
<div class="loading-spinner" />
|
||||||
<span class="loading-text">{{ t('pages.manage.main.loading') }}</span>
|
<span class="loading-text">{{ t('pages.manage.main.loading') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-else class="menu-list">
|
||||||
v-else
|
|
||||||
class="menu-list"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
v-for="item in bucketNameList"
|
v-for="item in bucketNameList"
|
||||||
:key="item"
|
:key="item"
|
||||||
@@ -76,18 +60,9 @@
|
|||||||
v-if="currentSelectedBucket === item && currentPicBedName !== 'github'"
|
v-if="currentSelectedBucket === item && currentPicBedName !== 'github'"
|
||||||
class="menu-icon active"
|
class="menu-icon active"
|
||||||
/>
|
/>
|
||||||
<FolderIcon
|
<FolderIcon v-else-if="currentPicBedName !== 'github'" class="menu-icon" />
|
||||||
v-else-if="currentPicBedName !== 'github'"
|
<GitBranchIcon v-else-if="currentPicBedName === 'github'" class="menu-icon" />
|
||||||
class="menu-icon"
|
<span class="menu-text" :title="item">
|
||||||
/>
|
|
||||||
<GitBranchIcon
|
|
||||||
v-else-if="currentPicBedName === 'github'"
|
|
||||||
class="menu-icon"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class="menu-text"
|
|
||||||
:title="item"
|
|
||||||
>
|
|
||||||
{{ truncateText(item, currentPicBedName) }}
|
{{ truncateText(item, currentPicBedName) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -96,24 +71,15 @@
|
|||||||
|
|
||||||
<div class="sidebar-footer">
|
<div class="sidebar-footer">
|
||||||
<div class="footer-actions">
|
<div class="footer-actions">
|
||||||
<button
|
<button class="footer-action-item" @click="switchPicBed('main')">
|
||||||
class="footer-action-item"
|
|
||||||
@click="switchPicBed('main')"
|
|
||||||
>
|
|
||||||
<HomeIcon class="action-icon" />
|
<HomeIcon class="action-icon" />
|
||||||
<span class="action-text">{{ t('pages.manage.main.backToHome') }}</span>
|
<span class="action-text">{{ t('pages.manage.main.backToHome') }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="footer-action-item" @click="changePicBed">
|
||||||
class="footer-action-item"
|
|
||||||
@click="changePicBed"
|
|
||||||
>
|
|
||||||
<ArrowLeftRightIcon class="action-icon" />
|
<ArrowLeftRightIcon class="action-icon" />
|
||||||
<span class="action-text">{{ t('pages.manage.main.switchPicBed') }}</span>
|
<span class="action-text">{{ t('pages.manage.main.switchPicBed') }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="footer-action-item" @click="openBucketPageSetting">
|
||||||
class="footer-action-item"
|
|
||||||
@click="openBucketPageSetting"
|
|
||||||
>
|
|
||||||
<SettingsIcon class="action-icon" />
|
<SettingsIcon class="action-icon" />
|
||||||
<span class="action-text">{{ t('pages.manage.main.settings') }}</span>
|
<span class="action-text">{{ t('pages.manage.main.settings') }}</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -122,50 +88,31 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Resize Handle -->
|
<!-- Resize Handle -->
|
||||||
<div
|
<div class="resize-handle" @mousedown="startResize">
|
||||||
class="resize-handle"
|
|
||||||
@mousedown="startResize"
|
|
||||||
>
|
|
||||||
<div class="resize-line" />
|
<div class="resize-line" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div ref="contentArea" class="content-area">
|
||||||
ref="contentArea"
|
|
||||||
class="content-area"
|
|
||||||
>
|
|
||||||
<router-view />
|
<router-view />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- PicBed Switch Dialog -->
|
<!-- PicBed Switch Dialog -->
|
||||||
<div
|
<div v-if="picBedSwitchDialogVisible" class="dialog-overlay" @click="picBedSwitchDialogVisible = false">
|
||||||
v-if="picBedSwitchDialogVisible"
|
<div class="dialog-container" @click.stop>
|
||||||
class="dialog-overlay"
|
|
||||||
@click="picBedSwitchDialogVisible = false"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="dialog-container"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
<div class="dialog-header">
|
<div class="dialog-header">
|
||||||
<h3 class="dialog-title">
|
<h3 class="dialog-title">
|
||||||
{{ t('pages.manage.main.switchPicBed') }}
|
{{ t('pages.manage.main.switchPicBed') }}
|
||||||
</h3>
|
</h3>
|
||||||
<button
|
<button class="dialog-close" @click="picBedSwitchDialogVisible = false">
|
||||||
class="dialog-close"
|
|
||||||
@click="picBedSwitchDialogVisible = false"
|
|
||||||
>
|
|
||||||
<XIcon class="close-icon" />
|
<XIcon class="close-icon" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="dialog-content">
|
<div class="dialog-content">
|
||||||
<div class="choice-cos">
|
<div class="choice-cos">
|
||||||
<!-- Back to main card -->
|
<!-- Back to main card -->
|
||||||
<div
|
<div class="picbed-card main-card" @click="switchPicBed('main')">
|
||||||
class="picbed-card main-card"
|
|
||||||
@click="switchPicBed('main')"
|
|
||||||
>
|
|
||||||
<div class="card-icon">
|
<div class="card-icon">
|
||||||
<HomeIcon class="main-icon" />
|
<HomeIcon class="main-icon" />
|
||||||
</div>
|
</div>
|
||||||
@@ -185,20 +132,14 @@
|
|||||||
@click="switchPicBed(String(alias))"
|
@click="switchPicBed(String(alias))"
|
||||||
>
|
>
|
||||||
<div class="card-icon">
|
<div class="card-icon">
|
||||||
<img
|
<img :src="`./assets/${config.picBedName}.webp`" class="picbed-icon" />
|
||||||
:src="`./assets/${config.picBedName}.webp`"
|
|
||||||
class="picbed-icon"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
{{ config.alias }}
|
{{ config.alias }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="String(alias) === currentAlias" class="check-icon">
|
||||||
v-if="String(alias) === currentAlias"
|
|
||||||
class="check-icon"
|
|
||||||
>
|
|
||||||
<CheckIcon />
|
<CheckIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -208,23 +149,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- New Bucket Drawer -->
|
<!-- New Bucket Drawer -->
|
||||||
<div
|
<div v-if="nweBucketDrawerVisible" class="drawer-overlay" @click="nweBucketDrawerVisible = false">
|
||||||
v-if="nweBucketDrawerVisible"
|
<div class="drawer-container" @click.stop>
|
||||||
class="drawer-overlay"
|
|
||||||
@click="nweBucketDrawerVisible = false"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="drawer-container"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
<div class="drawer-header">
|
<div class="drawer-header">
|
||||||
<h3 class="drawer-title">
|
<h3 class="drawer-title">
|
||||||
{{ t('pages.manage.main.newBucket') }}
|
{{ t('pages.manage.main.newBucket') }}
|
||||||
</h3>
|
</h3>
|
||||||
<button
|
<button class="drawer-close" @click="nweBucketDrawerVisible = false">
|
||||||
class="drawer-close"
|
|
||||||
@click="nweBucketDrawerVisible = false"
|
|
||||||
>
|
|
||||||
<XIcon class="close-icon" />
|
<XIcon class="close-icon" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -232,36 +163,35 @@
|
|||||||
<form @submit.prevent="createNewBucket(currentPicBedName)">
|
<form @submit.prevent="createNewBucket(currentPicBedName)">
|
||||||
<div class="form-header">
|
<div class="form-header">
|
||||||
<div class="form-icon">
|
<div class="form-icon">
|
||||||
<img
|
<img :src="`./assets/${currentPicBedName}.webp`" class="picbed-form-icon" />
|
||||||
:src="`./assets/${currentPicBedName}.webp`"
|
|
||||||
class="picbed-form-icon"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-divider" />
|
<div class="form-divider" />
|
||||||
|
|
||||||
<div
|
<div v-for="option in newBucketConfig[currentPicBedName].options" :key="option" class="form-group">
|
||||||
v-for="option in newBucketConfig[currentPicBedName].options"
|
|
||||||
:key="option"
|
|
||||||
class="form-group"
|
|
||||||
>
|
|
||||||
<label class="form-label">
|
<label class="form-label">
|
||||||
{{ newBucketConfig[currentPicBedName].configOptions[option].description }}
|
{{ newBucketConfig[currentPicBedName].configOptions[option].description }}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<!-- Input field -->
|
<!-- Input field -->
|
||||||
<input
|
<input
|
||||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'input' && currentPicBedName !== 'tcyun'"
|
v-if="
|
||||||
|
newBucketConfig[currentPicBedName].configOptions[option].component === 'input' &&
|
||||||
|
currentPicBedName !== 'tcyun'
|
||||||
|
"
|
||||||
v-model.trim="newBucketConfigResult[currentPicBedName + '.' + option]"
|
v-model.trim="newBucketConfigResult[currentPicBedName + '.' + option]"
|
||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
:placeholder="newBucketConfig[currentPicBedName].configOptions[option].placeholder"
|
:placeholder="newBucketConfig[currentPicBedName].configOptions[option].placeholder"
|
||||||
>
|
/>
|
||||||
|
|
||||||
<!-- TCyun special input with append -->
|
<!-- TCyun special input with append -->
|
||||||
<div
|
<div
|
||||||
v-if="currentPicBedName === 'tcyun' && newBucketConfig[currentPicBedName].configOptions[option].component === 'input'"
|
v-if="
|
||||||
|
currentPicBedName === 'tcyun' &&
|
||||||
|
newBucketConfig[currentPicBedName].configOptions[option].component === 'input'
|
||||||
|
"
|
||||||
class="input-group"
|
class="input-group"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -269,7 +199,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="form-input group-input"
|
class="form-input group-input"
|
||||||
:placeholder="newBucketConfig[currentPicBedName].configOptions[option].placeholder"
|
:placeholder="newBucketConfig[currentPicBedName].configOptions[option].placeholder"
|
||||||
>
|
/>
|
||||||
<span class="input-append">{{ '-' + currentPagePicBedConfig.appId }}</span>
|
<span class="input-append">{{ '-' + currentPagePicBedConfig.appId }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -278,10 +208,7 @@
|
|||||||
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'select'"
|
v-if="newBucketConfig[currentPicBedName].configOptions[option].component === 'select'"
|
||||||
class="select-wrapper"
|
class="select-wrapper"
|
||||||
>
|
>
|
||||||
<select
|
<select v-model="newBucketConfigResult[currentPicBedName + '.' + option]" class="form-select">
|
||||||
v-model="newBucketConfigResult[currentPicBedName + '.' + option]"
|
|
||||||
class="form-select"
|
|
||||||
>
|
|
||||||
<option
|
<option
|
||||||
v-for="(label, value) in newBucketConfig[currentPicBedName].configOptions[option].options"
|
v-for="(label, value) in newBucketConfig[currentPicBedName].configOptions[option].options"
|
||||||
:key="value"
|
:key="value"
|
||||||
@@ -304,7 +231,7 @@
|
|||||||
class="switch-input"
|
class="switch-input"
|
||||||
:true-value="true"
|
:true-value="true"
|
||||||
:false-value="false"
|
:false-value="false"
|
||||||
>
|
/>
|
||||||
<span class="switch-slider">
|
<span class="switch-slider">
|
||||||
<span class="switch-button" />
|
<span class="switch-button" />
|
||||||
</span>
|
</span>
|
||||||
@@ -312,17 +239,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button
|
<button type="button" class="action-button secondary" @click="nweBucketDrawerVisible = false">
|
||||||
type="button"
|
|
||||||
class="action-button secondary"
|
|
||||||
@click="nweBucketDrawerVisible = false"
|
|
||||||
>
|
|
||||||
{{ $t('common.cancel') }}
|
{{ $t('common.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button type="submit" class="action-button primary">
|
||||||
type="submit"
|
|
||||||
class="action-button primary"
|
|
||||||
>
|
|
||||||
<CheckIcon class="button-icon" />
|
<CheckIcon class="button-icon" />
|
||||||
{{ t('common.submit') }}
|
{{ t('common.submit') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -423,7 +343,9 @@ const truncateText = (text: string, picBedName: string): string => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(route, async (newRoute) => {
|
watch(
|
||||||
|
route,
|
||||||
|
async newRoute => {
|
||||||
if (newRoute.fullPath.split('?')[0] === '/main-page/manage-main-page') {
|
if (newRoute.fullPath.split('?')[0] === '/main-page/manage-main-page') {
|
||||||
currentAlias.value = newRoute.query.alias as string
|
currentAlias.value = newRoute.query.alias as string
|
||||||
currentPicBedName.value = newRoute.query.picBedName as string
|
currentPicBedName.value = newRoute.query.picBedName as string
|
||||||
@@ -431,7 +353,9 @@ watch(route, async (newRoute) => {
|
|||||||
currentPagePicBedConfig = reactive(JSON.parse(newRoute.query.config as string))
|
currentPagePicBedConfig = reactive(JSON.parse(newRoute.query.config as string))
|
||||||
await getBucketList()
|
await getBucketList()
|
||||||
}
|
}
|
||||||
}, { deep: true })
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
watch(sidebarWidth, () => {}, { immediate: false })
|
watch(sidebarWidth, () => {}, { immediate: false })
|
||||||
|
|
||||||
@@ -483,11 +407,7 @@ function createNewBucket (picBedName: string) {
|
|||||||
const resultValue = newBucketConfigResult[resultKey]
|
const resultValue = newBucketConfigResult[resultKey]
|
||||||
|
|
||||||
result[key] =
|
result[key] =
|
||||||
resultValue === '' && defaultValue !== undefined
|
resultValue === '' && defaultValue !== undefined ? defaultValue : resultValue === undefined ? '' : resultValue
|
||||||
? defaultValue
|
|
||||||
: resultValue === undefined
|
|
||||||
? ''
|
|
||||||
: resultValue
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}, {} as IStringKeyMap)
|
}, {} as IStringKeyMap)
|
||||||
|
|||||||
@@ -6,13 +6,14 @@
|
|||||||
<div class="setting-section">
|
<div class="setting-section">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<button
|
<button type="button" class="action-button warning" @click="handleConfirmClearDb">
|
||||||
type="button"
|
|
||||||
class="action-button warning"
|
|
||||||
@click="handleConfirmClearDb"
|
|
||||||
>
|
|
||||||
<Trash2Icon :size="16" />
|
<Trash2Icon :size="16" />
|
||||||
{{ t('pages.manage.setting.clearCache', { percent: dbSizeAvailableRate, size: formatFileSize(dbSize) || 0 }) }}
|
{{
|
||||||
|
t('pages.manage.setting.clearCache', {
|
||||||
|
percent: dbSizeAvailableRate,
|
||||||
|
size: formatFileSize(dbSize) || 0
|
||||||
|
})
|
||||||
|
}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,10 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Custom Rename Pattern Card -->
|
<!-- Custom Rename Pattern Card -->
|
||||||
<div
|
<div v-if="form.customRename" class="setting-card content-card">
|
||||||
v-if="form.customRename"
|
|
||||||
class="setting-card content-card"
|
|
||||||
>
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="setting-section">
|
<div class="setting-section">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -55,7 +53,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
:placeholder="t('pages.manage.setting.customRenameTablePlaceholder')"
|
:placeholder="t('pages.manage.setting.customRenameTablePlaceholder')"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pattern Reference Table -->
|
<!-- Pattern Reference Table -->
|
||||||
@@ -70,21 +68,12 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr
|
<tr v-for="(row, index) in customRenameFormatTable" :key="index">
|
||||||
v-for="(row, index) in customRenameFormatTable"
|
<td class="clickable" @click="handleCellClick(row, { property: 'placeholder' })">
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<td
|
|
||||||
class="clickable"
|
|
||||||
@click="handleCellClick(row, { property: 'placeholder' })"
|
|
||||||
>
|
|
||||||
{{ row.placeholder }}
|
{{ row.placeholder }}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ row.description }}</td>
|
<td>{{ row.description }}</td>
|
||||||
<td
|
<td class="clickable" @click="handleCellClick(row, { property: 'placeholderB' })">
|
||||||
class="clickable"
|
|
||||||
@click="handleCellClick(row, { property: 'placeholderB' })"
|
|
||||||
>
|
|
||||||
{{ row.placeholderB }}
|
{{ row.placeholderB }}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ row.descriptionB }}</td>
|
<td>{{ row.descriptionB }}</td>
|
||||||
@@ -132,7 +121,7 @@
|
|||||||
min="1"
|
min="1"
|
||||||
max="9999"
|
max="9999"
|
||||||
step="1"
|
step="1"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -151,7 +140,7 @@
|
|||||||
:placeholder="t('pages.manage.setting.preSignedUrlExpireDesc')"
|
:placeholder="t('pages.manage.setting.preSignedUrlExpireDesc')"
|
||||||
min="1"
|
min="1"
|
||||||
step="1"
|
step="1"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -168,17 +157,8 @@
|
|||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="radio-group">
|
<div class="radio-group">
|
||||||
<label
|
<label v-for="item in pasteFormatList" :key="item" class="radio-option">
|
||||||
v-for="item in pasteFormatList"
|
<input v-model="form.pasteFormat" type="radio" :value="item" class="radio-input" />
|
||||||
:key="item"
|
|
||||||
class="radio-option"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
v-model="form.pasteFormat"
|
|
||||||
type="radio"
|
|
||||||
:value="item"
|
|
||||||
class="radio-input"
|
|
||||||
>
|
|
||||||
<span class="radio-custom" />
|
<span class="radio-custom" />
|
||||||
<span class="radio-text">
|
<span class="radio-text">
|
||||||
{{ t(`pages.manage.setting.copyFormat.${item}`) }}
|
{{ t(`pages.manage.setting.copyFormat.${item}`) }}
|
||||||
@@ -187,9 +167,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Custom Copy Format -->
|
<!-- Custom Copy Format -->
|
||||||
<div
|
<div class="form-group">
|
||||||
class="form-group"
|
|
||||||
>
|
|
||||||
<div class="form-label-wrapper">
|
<div class="form-label-wrapper">
|
||||||
<span class="form-label">
|
<span class="form-label">
|
||||||
{{ t('pages.manage.setting.copyFormat.customTitle') }}
|
{{ t('pages.manage.setting.copyFormat.customTitle') }}
|
||||||
@@ -200,7 +178,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
:placeholder="t('pages.manage.setting.copyFormat.customTips')"
|
:placeholder="t('pages.manage.setting.copyFormat.customTips')"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -223,12 +201,8 @@
|
|||||||
class="form-input group-input"
|
class="form-input group-input"
|
||||||
disabled
|
disabled
|
||||||
:placeholder="t('pages.manage.setting.defaultDownloadFolder')"
|
:placeholder="t('pages.manage.setting.defaultDownloadFolder')"
|
||||||
>
|
/>
|
||||||
<button
|
<button type="button" class="input-append-button" @click="handleDownloadDirClick">
|
||||||
type="button"
|
|
||||||
class="input-append-button"
|
|
||||||
@click="handleDownloadDirClick"
|
|
||||||
>
|
|
||||||
<FolderIcon :size="16" />
|
<FolderIcon :size="16" />
|
||||||
{{ t('pages.manage.setting.browse') }}
|
{{ t('pages.manage.setting.browse') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -316,12 +290,8 @@ const switchFieldsConfigList = switchFieldsList.map(item => ({
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
tooltip: switchFieldsNoTipsList.includes(item) ? undefined : t(`pages.manage.setting.${item}Tips` as any),
|
tooltip: switchFieldsNoTipsList.includes(item) ? undefined : t(`pages.manage.setting.${item}Tips` as any),
|
||||||
activeText: switchFieldsHasActiveTextList.includes(item)
|
activeText: switchFieldsHasActiveTextList.includes(item) ? t(`pages.manage.setting.${item}On` as any) : undefined,
|
||||||
? t(`pages.manage.setting.${item}On` as any)
|
inactiveText: switchFieldsHasActiveTextList.includes(item) ? t(`pages.manage.setting.${item}Off` as any) : undefined
|
||||||
: undefined,
|
|
||||||
inactiveText: switchFieldsHasActiveTextList.includes(item)
|
|
||||||
? t(`pages.manage.setting.${item}Off` as any)
|
|
||||||
: undefined
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const switchFieldsSpecialList = [
|
const switchFieldsSpecialList = [
|
||||||
|
|||||||
@@ -16,54 +16,27 @@
|
|||||||
<div class="sync-delete-toggle">
|
<div class="sync-delete-toggle">
|
||||||
<span class="toggle-label">{{ t('pages.gallery.isAlwaysForceReload') }}</span>
|
<span class="toggle-label">{{ t('pages.gallery.isAlwaysForceReload') }}</span>
|
||||||
<label class="custom-switch">
|
<label class="custom-switch">
|
||||||
<input
|
<input v-model="isAlwaysForceReload" type="checkbox" @change="handleIsAlwaysForceReload" />
|
||||||
v-model="isAlwaysForceReload"
|
|
||||||
type="checkbox"
|
|
||||||
@change="handleIsAlwaysForceReload"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="sync-delete-toggle">
|
<div class="sync-delete-toggle">
|
||||||
<span class="toggle-label">{{ t('pages.gallery.syncDelete') }}</span>
|
<span class="toggle-label">{{ t('pages.gallery.syncDelete') }}</span>
|
||||||
<label class="custom-switch">
|
<label class="custom-switch">
|
||||||
<input
|
<input v-model="deleteCloud" type="checkbox" @change="handleDeleteCloudFile" />
|
||||||
v-model="deleteCloud"
|
|
||||||
type="checkbox"
|
|
||||||
@change="handleDeleteCloudFile"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button class="action-button view-mode-toggle" :title="getViewModeLabel()" @click="toggleViewMode">
|
||||||
class="action-button view-mode-toggle"
|
<component :is="getViewModeIcon()" :size="16" />
|
||||||
:title="getViewModeLabel()"
|
|
||||||
@click="toggleViewMode"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="getViewModeIcon()"
|
|
||||||
:size="16"
|
|
||||||
/>
|
|
||||||
{{ getViewModeLabel() }}
|
{{ getViewModeLabel() }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="action-button" @click="toggleHandleBar">
|
||||||
class="action-button"
|
<ChevronDownIcon v-if="!handleBarActive" :size="16" />
|
||||||
@click="toggleHandleBar"
|
<ChevronUpIcon v-else :size="16" />
|
||||||
>
|
|
||||||
<ChevronDownIcon
|
|
||||||
v-if="!handleBarActive"
|
|
||||||
:size="16"
|
|
||||||
/>
|
|
||||||
<ChevronUpIcon
|
|
||||||
v-else
|
|
||||||
:size="16"
|
|
||||||
/>
|
|
||||||
{{ handleBarActive ? t('pages.gallery.hideFilters') : t('pages.gallery.showFilters') }}
|
{{ handleBarActive ? t('pages.gallery.hideFilters') : t('pages.gallery.showFilters') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="action-button" @click="refreshPage">
|
||||||
class="action-button"
|
|
||||||
@click="refreshPage"
|
|
||||||
>
|
|
||||||
<RefreshCwIcon :size="16" />
|
<RefreshCwIcon :size="16" />
|
||||||
{{ t('pages.gallery.refresh') }}
|
{{ t('pages.gallery.refresh') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -73,10 +46,7 @@
|
|||||||
|
|
||||||
<!-- Filter Controls Card -->
|
<!-- Filter Controls Card -->
|
||||||
<transition name="filter-slide">
|
<transition name="filter-slide">
|
||||||
<div
|
<div v-show="handleBarActive" class="gallery-card filter-card">
|
||||||
v-show="handleBarActive"
|
|
||||||
class="gallery-card filter-card"
|
|
||||||
>
|
|
||||||
<div class="filter-content">
|
<div class="filter-content">
|
||||||
<div class="filter-row">
|
<div class="filter-row">
|
||||||
<div class="filter-group">
|
<div class="filter-group">
|
||||||
@@ -91,20 +61,9 @@
|
|||||||
<span v-else>{{ choosedPicBed.length }} {{ t('pages.gallery.selected') }}</span>
|
<span v-else>{{ choosedPicBed.length }} {{ t('pages.gallery.selected') }}</span>
|
||||||
<ChevronDownIcon :size="16" />
|
<ChevronDownIcon :size="16" />
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div v-show="picBedDropdownOpen" class="multiselect-dropdown">
|
||||||
v-show="picBedDropdownOpen"
|
<label v-for="item in picBedGlobal" :key="item.type" class="multiselect-option">
|
||||||
class="multiselect-dropdown"
|
<input v-model="choosedPicBed" type="checkbox" :value="item.type" />
|
||||||
>
|
|
||||||
<label
|
|
||||||
v-for="item in picBedGlobal"
|
|
||||||
:key="item.type"
|
|
||||||
class="multiselect-option"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
v-model="choosedPicBed"
|
|
||||||
type="checkbox"
|
|
||||||
:value="item.type"
|
|
||||||
>
|
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -114,34 +73,16 @@
|
|||||||
<div class="filter-group">
|
<div class="filter-group">
|
||||||
<label class="filter-label">{{ t('pages.gallery.dateRange') }}</label>
|
<label class="filter-label">{{ t('pages.gallery.dateRange') }}</label>
|
||||||
<div class="date-range-picker">
|
<div class="date-range-picker">
|
||||||
<input
|
<input v-model="dateRangeStart" type="date" class="date-input" placeholder="Start date" />
|
||||||
v-model="dateRangeStart"
|
|
||||||
type="date"
|
|
||||||
class="date-input"
|
|
||||||
placeholder="Start date"
|
|
||||||
>
|
|
||||||
<span class="date-separator">-</span>
|
<span class="date-separator">-</span>
|
||||||
<input
|
<input v-model="dateRangeEnd" type="date" class="date-input" placeholder="End date" />
|
||||||
v-model="dateRangeEnd"
|
|
||||||
type="date"
|
|
||||||
class="date-input"
|
|
||||||
placeholder="End date"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="filter-group">
|
<div class="filter-group">
|
||||||
<label class="filter-label">{{ t('pages.gallery.pasteFormat') }}</label>
|
<label class="filter-label">{{ t('pages.gallery.pasteFormat') }}</label>
|
||||||
<select
|
<select v-model="pasteStyle" class="custom-select" @change="handlePasteStyleChange">
|
||||||
v-model="pasteStyle"
|
<option v-for="(value, key) in pasteStyleMap" :key="key" :value="value">
|
||||||
class="custom-select"
|
|
||||||
@change="handlePasteStyleChange"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
v-for="(value, key) in pasteStyleMap"
|
|
||||||
:key="key"
|
|
||||||
:value="value"
|
|
||||||
>
|
|
||||||
{{ key }}
|
{{ key }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -149,16 +90,8 @@
|
|||||||
|
|
||||||
<div class="filter-group">
|
<div class="filter-group">
|
||||||
<label class="filter-label">{{ t('pages.gallery.urlType') }}</label>
|
<label class="filter-label">{{ t('pages.gallery.urlType') }}</label>
|
||||||
<select
|
<select v-model="useShortUrl" class="custom-select" @change="handleUseShortUrlChange">
|
||||||
v-model="useShortUrl"
|
<option v-for="(value, key) in shortURLMap" :key="key" :value="value">
|
||||||
class="custom-select"
|
|
||||||
@change="handleUseShortUrlChange"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
v-for="(value, key) in shortURLMap"
|
|
||||||
:key="key"
|
|
||||||
:value="value"
|
|
||||||
>
|
|
||||||
{{ key }}
|
{{ key }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -167,19 +100,12 @@
|
|||||||
<div class="filter-group">
|
<div class="filter-group">
|
||||||
<label class="filter-label">{{ t('pages.gallery.sort') }}</label>
|
<label class="filter-label">{{ t('pages.gallery.sort') }}</label>
|
||||||
<div class="sort-dropdown">
|
<div class="sort-dropdown">
|
||||||
<button
|
<button class="sort-button" :class="{ active: sortDropdownOpen }" @click="toggleSortDropdown($event)">
|
||||||
class="sort-button"
|
|
||||||
:class="{ active: sortDropdownOpen }"
|
|
||||||
@click="toggleSortDropdown($event)"
|
|
||||||
>
|
|
||||||
<SortAscIcon :size="14" />
|
<SortAscIcon :size="14" />
|
||||||
{{ t('pages.gallery.sort') }}
|
{{ t('pages.gallery.sort') }}
|
||||||
<ChevronDownIcon :size="14" />
|
<ChevronDownIcon :size="14" />
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div v-show="sortDropdownOpen" class="sort-options">
|
||||||
v-show="sortDropdownOpen"
|
|
||||||
class="sort-options"
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
v-for="key in ['name', 'ext', 'time', 'check']"
|
v-for="key in ['name', 'ext', 'time', 'check']"
|
||||||
:key="key"
|
:key="key"
|
||||||
@@ -197,21 +123,14 @@
|
|||||||
<div class="filter-row">
|
<div class="filter-row">
|
||||||
<div class="search-group">
|
<div class="search-group">
|
||||||
<div class="search-input-wrapper">
|
<div class="search-input-wrapper">
|
||||||
<SearchIcon
|
<SearchIcon :size="16" class="search-icon" />
|
||||||
:size="16"
|
|
||||||
class="search-icon"
|
|
||||||
/>
|
|
||||||
<input
|
<input
|
||||||
v-model="searchText"
|
v-model="searchText"
|
||||||
type="text"
|
type="text"
|
||||||
class="search-input"
|
class="search-input"
|
||||||
:placeholder="$t('pages.gallery.searchFilename')"
|
:placeholder="$t('pages.gallery.searchFilename')"
|
||||||
>
|
/>
|
||||||
<button
|
<button v-if="searchText" class="clear-button" @click="cleanSearch">
|
||||||
v-if="searchText"
|
|
||||||
class="clear-button"
|
|
||||||
@click="cleanSearch"
|
|
||||||
>
|
|
||||||
<XIcon :size="14" />
|
<XIcon :size="14" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -219,32 +138,21 @@
|
|||||||
|
|
||||||
<div class="search-group">
|
<div class="search-group">
|
||||||
<div class="search-input-wrapper">
|
<div class="search-input-wrapper">
|
||||||
<LinkIcon
|
<LinkIcon :size="16" class="search-icon" />
|
||||||
:size="16"
|
|
||||||
class="search-icon"
|
|
||||||
/>
|
|
||||||
<input
|
<input
|
||||||
v-model="searchTextURL"
|
v-model="searchTextURL"
|
||||||
type="text"
|
type="text"
|
||||||
class="search-input"
|
class="search-input"
|
||||||
:placeholder="t('pages.gallery.searchUrl')"
|
:placeholder="t('pages.gallery.searchUrl')"
|
||||||
>
|
/>
|
||||||
<button
|
<button v-if="searchTextURL" class="clear-button" @click="cleanSearchUrl">
|
||||||
v-if="searchTextURL"
|
|
||||||
class="clear-button"
|
|
||||||
@click="cleanSearchUrl"
|
|
||||||
>
|
|
||||||
<XIcon :size="14" />
|
<XIcon :size="14" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<button
|
<button class="action-btn copy-btn" :class="{ active: isMultiple(choosedList) }" @click="multiCopy">
|
||||||
class="action-btn copy-btn"
|
|
||||||
:class="{ active: isMultiple(choosedList) }"
|
|
||||||
@click="multiCopy"
|
|
||||||
>
|
|
||||||
<ClipboardIcon :size="16" />
|
<ClipboardIcon :size="16" />
|
||||||
{{ t('pages.gallery.copy') }}
|
{{ t('pages.gallery.copy') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -256,19 +164,11 @@
|
|||||||
<EditIcon :size="16" />
|
<EditIcon :size="16" />
|
||||||
{{ t('pages.gallery.edit') }}
|
{{ t('pages.gallery.edit') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="action-btn delete-btn" :class="{ active: isMultiple(choosedList) }" @click="multiRemove">
|
||||||
class="action-btn delete-btn"
|
|
||||||
:class="{ active: isMultiple(choosedList) }"
|
|
||||||
@click="multiRemove"
|
|
||||||
>
|
|
||||||
<TrashIcon :size="16" />
|
<TrashIcon :size="16" />
|
||||||
{{ t('pages.gallery.delete') }}
|
{{ t('pages.gallery.delete') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="action-btn select-btn" :class="{ active: filterList.length > 0 }" @click="toggleSelectAll">
|
||||||
class="action-btn select-btn"
|
|
||||||
:class="{ active: filterList.length > 0 }"
|
|
||||||
@click="toggleSelectAll"
|
|
||||||
>
|
|
||||||
<CheckSquareIcon :size="16" />
|
<CheckSquareIcon :size="16" />
|
||||||
{{ isAllSelected ? t('pages.gallery.cancel') : t('pages.gallery.selectAll') }}
|
{{ isAllSelected ? t('pages.gallery.cancel') : t('pages.gallery.selectAll') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -280,14 +180,8 @@
|
|||||||
|
|
||||||
<!-- Gallery Grid -->
|
<!-- Gallery Grid -->
|
||||||
<div class="gallery-card gallery-content">
|
<div class="gallery-card gallery-content">
|
||||||
<div
|
<div v-if="filterList.length === 0" class="empty-state">
|
||||||
v-if="filterList.length === 0"
|
<ImageIcon :size="64" class="empty-icon" />
|
||||||
class="empty-state"
|
|
||||||
>
|
|
||||||
<ImageIcon
|
|
||||||
:size="64"
|
|
||||||
class="empty-icon"
|
|
||||||
/>
|
|
||||||
<h3>{{ t('pages.gallery.noImagesFound') }}</h3>
|
<h3>{{ t('pages.gallery.noImagesFound') }}</h3>
|
||||||
<p>{{ t('pages.gallery.tryAdjustingFilters') }}</p>
|
<p>{{ t('pages.gallery.tryAdjustingFilters') }}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -308,53 +202,37 @@
|
|||||||
:item-padding="8"
|
:item-padding="8"
|
||||||
>
|
>
|
||||||
<template #default="{ item, index }">
|
<template #default="{ item, index }">
|
||||||
<div
|
<div class="gallery-item" :class="{ selected: choosedList[item.id || ''] }">
|
||||||
class="gallery-item"
|
<div class="image-container" @click="zoomImage(index)">
|
||||||
:class="{ selected: choosedList[item.id || ''] }"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="image-container"
|
|
||||||
@click="zoomImage(index)"
|
|
||||||
>
|
|
||||||
<img
|
<img
|
||||||
:src="imageErrorStates[item.key || '']
|
:src="
|
||||||
|
imageErrorStates[item.key || '']
|
||||||
? './errorLoading.png'
|
? './errorLoading.png'
|
||||||
: isAlwaysForceReload ? addCacheBustParam(item.src) : item.src"
|
: isAlwaysForceReload
|
||||||
|
? addCacheBustParam(item.src)
|
||||||
|
: item.src
|
||||||
|
"
|
||||||
class="gallery-image"
|
class="gallery-image"
|
||||||
:class="{ loading: !imageLoadStates[item.key || ''] }"
|
:class="{ loading: !imageLoadStates[item.key || ''] }"
|
||||||
@load="onImageLoad(item.key || '')"
|
@load="onImageLoad(item.key || '')"
|
||||||
@error="onImageError(item.key || '')"
|
@error="onImageError(item.key || '')"
|
||||||
>
|
/>
|
||||||
<div
|
<div v-if="!imageLoadStates[item.key || '']" class="image-loader">
|
||||||
v-if="!imageLoadStates[item.key || '']"
|
|
||||||
class="image-loader"
|
|
||||||
>
|
|
||||||
<div class="loader-spinner" />
|
<div class="loader-spinner" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="image-info">
|
<div class="image-info">
|
||||||
<div
|
<div class="image-name" :title="item.fileName">
|
||||||
class="image-name"
|
|
||||||
:title="item.fileName"
|
|
||||||
>
|
|
||||||
{{ formatFileName(item.fileName || '') }}
|
{{ formatFileName(item.fileName || '') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="image-actions">
|
<div class="image-actions">
|
||||||
<div class="action-icons">
|
<div class="action-icons">
|
||||||
<button
|
<button :title="t('pages.gallery.copy')" class="icon-button copy-icon" @click.stop="copy(item)">
|
||||||
:title="t('pages.gallery.copy')"
|
|
||||||
class="icon-button copy-icon"
|
|
||||||
@click.stop="copy(item)"
|
|
||||||
>
|
|
||||||
<ClipboardIcon :size="16" />
|
<ClipboardIcon :size="16" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button :title="t('pages.gallery.edit')" class="icon-button edit-icon" @click.stop="openDialog(item)">
|
||||||
:title="t('pages.gallery.edit')"
|
|
||||||
class="icon-button edit-icon"
|
|
||||||
@click.stop="openDialog(item)"
|
|
||||||
>
|
|
||||||
<EditIcon :size="16" />
|
<EditIcon :size="16" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -370,8 +248,8 @@
|
|||||||
<input
|
<input
|
||||||
v-model="choosedList[item.id ? item.id : '']"
|
v-model="choosedList[item.id ? item.id : '']"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="(e) => handleChooseImage((e.target as HTMLInputElement).checked, index)"
|
@change="e => handleChooseImage((e.target as HTMLInputElement).checked, index)"
|
||||||
>
|
/>
|
||||||
<span class="checkbox-mark" />
|
<span class="checkbox-mark" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -393,36 +271,20 @@
|
|||||||
>
|
>
|
||||||
<div class="modal-backdrop" />
|
<div class="modal-backdrop" />
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<button
|
<button class="modal-close" @click="handleClose">
|
||||||
class="modal-close"
|
|
||||||
@click="handleClose"
|
|
||||||
>
|
|
||||||
<XIcon :size="24" />
|
<XIcon :size="24" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Zoom controls -->
|
<!-- Zoom controls -->
|
||||||
<div class="zoom-controls">
|
<div class="zoom-controls">
|
||||||
<button
|
<button class="zoom-btn" :disabled="imagePreviewState.scale <= 0.1" @click="zoomOut">
|
||||||
class="zoom-btn"
|
|
||||||
:disabled="imagePreviewState.scale <= 0.1"
|
|
||||||
@click="zoomOut"
|
|
||||||
>
|
|
||||||
<span>-</span>
|
<span>-</span>
|
||||||
</button>
|
</button>
|
||||||
<span class="zoom-level">{{ Math.round(imagePreviewState.scale * 100) }}%</span>
|
<span class="zoom-level">{{ Math.round(imagePreviewState.scale * 100) }}%</span>
|
||||||
<button
|
<button class="zoom-btn" :disabled="imagePreviewState.scale >= 5" @click="zoomIn">
|
||||||
class="zoom-btn"
|
|
||||||
:disabled="imagePreviewState.scale >= 5"
|
|
||||||
@click="zoomIn"
|
|
||||||
>
|
|
||||||
<span>+</span>
|
<span>+</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="zoom-btn reset-btn" @click="resetImageTransform">Reset</button>
|
||||||
class="zoom-btn reset-btn"
|
|
||||||
@click="resetImageTransform"
|
|
||||||
>
|
|
||||||
Reset
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="image-navigation">
|
<div class="image-navigation">
|
||||||
@@ -452,7 +314,7 @@
|
|||||||
:style="imageTransformStyle"
|
:style="imageTransformStyle"
|
||||||
@dragstart.prevent
|
@dragstart.prevent
|
||||||
@contextmenu.prevent
|
@contextmenu.prevent
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
@@ -466,9 +328,7 @@
|
|||||||
|
|
||||||
<div class="image-details">
|
<div class="image-details">
|
||||||
<h3>{{ currentPreviewImage?.intro }}</h3>
|
<h3>{{ currentPreviewImage?.intro }}</h3>
|
||||||
<div class="image-counter">
|
<div class="image-counter">{{ gallerySliderControl.index + 1 }} / {{ filterList.length }}</div>
|
||||||
{{ gallerySliderControl.index + 1 }} / {{ filterList.length }}
|
|
||||||
</div>
|
|
||||||
<div class="image-help-text">
|
<div class="image-help-text">
|
||||||
{{ t('pages.gallery.previewHelp') }}
|
{{ t('pages.gallery.previewHelp') }}
|
||||||
</div>
|
</div>
|
||||||
@@ -479,43 +339,22 @@
|
|||||||
|
|
||||||
<!-- Edit URL Modal -->
|
<!-- Edit URL Modal -->
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<div
|
<div v-if="dialogVisible" class="modal-overlay" @click="dialogVisible = false">
|
||||||
v-if="dialogVisible"
|
<div class="modal-container" @click.stop>
|
||||||
class="modal-overlay"
|
|
||||||
@click="dialogVisible = false"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="modal-container"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3>{{ t('pages.gallery.changeImageUrl') }}</h3>
|
<h3>{{ t('pages.gallery.changeImageUrl') }}</h3>
|
||||||
<button
|
<button class="modal-close-btn" @click="dialogVisible = false">
|
||||||
class="modal-close-btn"
|
|
||||||
@click="dialogVisible = false"
|
|
||||||
>
|
|
||||||
<XIcon :size="20" />
|
<XIcon :size="20" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<input
|
<input v-model="imgInfo.imgUrl" type="text" class="form-input" placeholder="Enter new URL" />
|
||||||
v-model="imgInfo.imgUrl"
|
|
||||||
type="text"
|
|
||||||
class="form-input"
|
|
||||||
placeholder="Enter new URL"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button
|
<button class="btn-secondary" @click="dialogVisible = false">
|
||||||
class="btn-secondary"
|
|
||||||
@click="dialogVisible = false"
|
|
||||||
>
|
|
||||||
{{ t('common.cancel') }}
|
{{ t('common.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="btn-primary" @click="confirmModify">
|
||||||
class="btn-primary"
|
|
||||||
@click="confirmModify"
|
|
||||||
>
|
|
||||||
{{ t('common.confirm') }}
|
{{ t('common.confirm') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -525,21 +364,11 @@
|
|||||||
|
|
||||||
<!-- Batch Rename Modal -->
|
<!-- Batch Rename Modal -->
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<div
|
<div v-if="isShowBatchRenameDialog" class="modal-overlay" @click="isShowBatchRenameDialog = false">
|
||||||
v-if="isShowBatchRenameDialog"
|
<div class="modal-container large" @click.stop>
|
||||||
class="modal-overlay"
|
|
||||||
@click="isShowBatchRenameDialog = false"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="modal-container large"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3>{{ t('pages.gallery.batchEditUrl') }}</h3>
|
<h3>{{ t('pages.gallery.batchEditUrl') }}</h3>
|
||||||
<button
|
<button class="modal-close-btn" @click="isShowBatchRenameDialog = false">
|
||||||
class="modal-close-btn"
|
|
||||||
@click="isShowBatchRenameDialog = false"
|
|
||||||
>
|
|
||||||
<XIcon :size="20" />
|
<XIcon :size="20" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -553,32 +382,21 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
:placeholder="t('pages.gallery.regexPatternPlaceholder')"
|
:placeholder="t('pages.gallery.regexPatternPlaceholder')"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">
|
<label class="form-label">
|
||||||
{{ t('pages.gallery.replacedWith') }}
|
{{ t('pages.gallery.replacedWith') }}
|
||||||
<button
|
<button class="info-button" @click="showFormatInfo = !showFormatInfo">
|
||||||
class="info-button"
|
|
||||||
@click="showFormatInfo = !showFormatInfo"
|
|
||||||
>
|
|
||||||
<InfoIcon :size="16" />
|
<InfoIcon :size="16" />
|
||||||
</button>
|
</button>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input v-model="batchRenameReplace" type="text" class="form-input" placeholder="Ex. {Y}-{m}-{uuid}" />
|
||||||
v-model="batchRenameReplace"
|
|
||||||
type="text"
|
|
||||||
class="form-input"
|
|
||||||
placeholder="Ex. {Y}-{m}-{uuid}"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Format Info Panel -->
|
<!-- Format Info Panel -->
|
||||||
<div
|
<div v-if="showFormatInfo" class="form-group">
|
||||||
v-if="showFormatInfo"
|
|
||||||
class="form-group"
|
|
||||||
>
|
|
||||||
<label>{{ t('pages.settings.upload.availablePlaceholders') }}</label>
|
<label>{{ t('pages.settings.upload.availablePlaceholders') }}</label>
|
||||||
<div class="placeholder-help">
|
<div class="placeholder-help">
|
||||||
<div class="placeholder-category">
|
<div class="placeholder-category">
|
||||||
@@ -635,16 +453,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button
|
<button class="btn-secondary" @click="isShowBatchRenameDialog = false">
|
||||||
class="btn-secondary"
|
|
||||||
@click="isShowBatchRenameDialog = false"
|
|
||||||
>
|
|
||||||
{{ t('common.cancel') }}
|
{{ t('common.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="btn-primary" @click="handleBatchRename()">
|
||||||
class="btn-primary"
|
|
||||||
@click="handleBatchRename()"
|
|
||||||
>
|
|
||||||
{{ t('common.confirm') }}
|
{{ t('common.confirm') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -860,7 +672,7 @@ const currentPreviewImage = computed(() => {
|
|||||||
const imageTransformStyle = computed(() => {
|
const imageTransformStyle = computed(() => {
|
||||||
return {
|
return {
|
||||||
transform: `translate(${imagePreviewState.translateX}px, ${imagePreviewState.translateY}px) scale(${imagePreviewState.scale})`,
|
transform: `translate(${imagePreviewState.translateX}px, ${imagePreviewState.translateY}px) scale(${imagePreviewState.scale})`,
|
||||||
cursor: imagePreviewState.isDragging ? 'grabbing' : (imagePreviewState.scale > 1 ? 'grab' : 'default'),
|
cursor: imagePreviewState.isDragging ? 'grabbing' : imagePreviewState.scale > 1 ? 'grab' : 'default',
|
||||||
transition: imagePreviewState.isDragging ? 'none' : 'transform 0.2s ease-out'
|
transition: imagePreviewState.isDragging ? 'none' : 'transform 0.2s ease-out'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -944,9 +756,8 @@ function handleImageWheel (event: WheelEvent) {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const delta = event.deltaY > 0 ? -1 : 1
|
const delta = event.deltaY > 0 ? -1 : 1
|
||||||
const zoomFactor = 1.1
|
const zoomFactor = 1.1
|
||||||
const newScale = delta > 0
|
const newScale =
|
||||||
? Math.min(imagePreviewState.scale * zoomFactor, 5)
|
delta > 0 ? Math.min(imagePreviewState.scale * zoomFactor, 5) : Math.max(imagePreviewState.scale / zoomFactor, 0.1)
|
||||||
: Math.max(imagePreviewState.scale / zoomFactor, 0.1)
|
|
||||||
|
|
||||||
imagePreviewState.scale = newScale
|
imagePreviewState.scale = newScale
|
||||||
|
|
||||||
@@ -1089,7 +900,7 @@ onBeforeRouteUpdate((to, from) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
async function initConf() {
|
async function initConf() {
|
||||||
viewMode.value = localStorage.getItem('galleryViewMode') as 'list' | 'grid' || 'grid'
|
viewMode.value = (localStorage.getItem('galleryViewMode') as 'list' | 'grid') || 'grid'
|
||||||
pasteStyle.value = (await getConfig(configPaths.settings.pasteStyle)) || IPasteStyle.MARKDOWN
|
pasteStyle.value = (await getConfig(configPaths.settings.pasteStyle)) || IPasteStyle.MARKDOWN
|
||||||
useShortUrl.value = (await getConfig(configPaths.settings.useShortUrl))
|
useShortUrl.value = (await getConfig(configPaths.settings.useShortUrl))
|
||||||
? t('pages.gallery.shortUrl')
|
? t('pages.gallery.shortUrl')
|
||||||
@@ -1193,12 +1004,14 @@ async function updateGallery () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(filterList, () => { clearChoosedList() })
|
watch(filterList, () => {
|
||||||
|
clearChoosedList()
|
||||||
|
})
|
||||||
|
|
||||||
let searchDebounceTimer: ReturnType<typeof setTimeout> | null = null
|
let searchDebounceTimer: ReturnType<typeof setTimeout> | null = null
|
||||||
let searchURLDebounceTimer: ReturnType<typeof setTimeout> | null = null
|
let searchURLDebounceTimer: ReturnType<typeof setTimeout> | null = null
|
||||||
|
|
||||||
watch(searchText, (newVal) => {
|
watch(searchText, newVal => {
|
||||||
if (searchDebounceTimer) clearTimeout(searchDebounceTimer)
|
if (searchDebounceTimer) clearTimeout(searchDebounceTimer)
|
||||||
searchDebounceTimer = setTimeout(() => {
|
searchDebounceTimer = setTimeout(() => {
|
||||||
debouncedSearchText.value = newVal
|
debouncedSearchText.value = newVal
|
||||||
@@ -1208,7 +1021,7 @@ watch(searchText, (newVal) => {
|
|||||||
}, 300)
|
}, 300)
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(searchTextURL, (newVal) => {
|
watch(searchTextURL, newVal => {
|
||||||
if (searchURLDebounceTimer) clearTimeout(searchURLDebounceTimer)
|
if (searchURLDebounceTimer) clearTimeout(searchURLDebounceTimer)
|
||||||
searchURLDebounceTimer = setTimeout(() => {
|
searchURLDebounceTimer = setTimeout(() => {
|
||||||
debouncedSearchTextURL.value = newVal
|
debouncedSearchTextURL.value = newVal
|
||||||
@@ -1294,7 +1107,9 @@ function remove (item: ImgInfo, _: number) {
|
|||||||
}).then(async result => {
|
}).then(async result => {
|
||||||
if (!result) return
|
if (!result) return
|
||||||
const file = await $$db.getById(item.id!)
|
const file = await $$db.getById(item.id!)
|
||||||
const isNeedDeleteCloudFile = await getConfig(configPaths.settings.deleteCloudFile) && picBedsCanbeDeleted.includes(item?.type || 'placeholder')
|
const isNeedDeleteCloudFile =
|
||||||
|
(await getConfig(configPaths.settings.deleteCloudFile)) &&
|
||||||
|
picBedsCanbeDeleted.includes(item?.type || 'placeholder')
|
||||||
if (isNeedDeleteCloudFile) {
|
if (isNeedDeleteCloudFile) {
|
||||||
const result = await ALLApi.delete(getRawData(item))
|
const result = await ALLApi.delete(getRawData(item))
|
||||||
if (result) {
|
if (result) {
|
||||||
@@ -1569,10 +1384,12 @@ function handleBatchRename () {
|
|||||||
confirmButtonText: t('common.confirm'),
|
confirmButtonText: t('common.confirm'),
|
||||||
cancelButtonText: t('common.cancel'),
|
cancelButtonText: t('common.cancel'),
|
||||||
center: true
|
center: true
|
||||||
}).then(result => {
|
})
|
||||||
|
.then(result => {
|
||||||
if (!result) return
|
if (!result) return
|
||||||
rename()
|
rename()
|
||||||
}).catch(() => {
|
})
|
||||||
|
.catch(() => {
|
||||||
message.info(t('pages.gallery.canceled'))
|
message.info(t('pages.gallery.canceled'))
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -1597,7 +1414,7 @@ onBeforeUnmount(async () => {
|
|||||||
// Clear timers
|
// Clear timers
|
||||||
if (searchDebounceTimer) clearTimeout(searchDebounceTimer)
|
if (searchDebounceTimer) clearTimeout(searchDebounceTimer)
|
||||||
if (searchURLDebounceTimer) clearTimeout(searchURLDebounceTimer)
|
if (searchURLDebounceTimer) clearTimeout(searchURLDebounceTimer)
|
||||||
isAlwaysForceReload.value = await getConfig(configPaths.settings.isAlwaysForceReload) || false
|
isAlwaysForceReload.value = (await getConfig(configPaths.settings.isAlwaysForceReload)) || false
|
||||||
})
|
})
|
||||||
|
|
||||||
onActivated(async () => {
|
onActivated(async () => {
|
||||||
|
|||||||
@@ -18,17 +18,9 @@
|
|||||||
style="width: 100%; height: 100%; border-radius: 50%"
|
style="width: 100%; height: 100%; border-radius: 50%"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
@dragstart.prevent
|
@dragstart.prevent
|
||||||
>
|
/>
|
||||||
<div
|
<div id="upload-dragger" @dblclick="openUploadWindow">
|
||||||
id="upload-dragger"
|
<input id="file-uploader" type="file" multiple @change="onChange" />
|
||||||
@dblclick="openUploadWindow"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
id="file-uploader"
|
|
||||||
type="file"
|
|
||||||
multiple
|
|
||||||
@change="onChange"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -21,19 +21,11 @@
|
|||||||
<DownloadIcon :size="16" />
|
<DownloadIcon :size="16" />
|
||||||
{{ t('pages.plugin.importLocal') }}
|
{{ t('pages.plugin.importLocal') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="action-button secondary" :title="t('pages.plugin.updateAll')" @click="handleUpdateAllPlugin">
|
||||||
class="action-button secondary"
|
|
||||||
:title="t('pages.plugin.updateAll')"
|
|
||||||
@click="handleUpdateAllPlugin"
|
|
||||||
>
|
|
||||||
<RefreshCwIcon :size="16" />
|
<RefreshCwIcon :size="16" />
|
||||||
{{ t('pages.plugin.updateAll') }}
|
{{ t('pages.plugin.updateAll') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="action-button" :title="t('pages.plugin.pluginList')" @click="goAwesomeList">
|
||||||
class="action-button"
|
|
||||||
:title="t('pages.plugin.pluginList')"
|
|
||||||
@click="goAwesomeList"
|
|
||||||
>
|
|
||||||
<ExternalLinkIcon :size="16" />
|
<ExternalLinkIcon :size="16" />
|
||||||
{{ t('pages.plugin.list') }}
|
{{ t('pages.plugin.list') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -45,21 +37,14 @@
|
|||||||
<div class="plugin-card search-card">
|
<div class="plugin-card search-card">
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<div class="search-input-wrapper">
|
<div class="search-input-wrapper">
|
||||||
<SearchIcon
|
<SearchIcon class="search-icon" :size="20" />
|
||||||
class="search-icon"
|
|
||||||
:size="20"
|
|
||||||
/>
|
|
||||||
<input
|
<input
|
||||||
v-model="searchText"
|
v-model="searchText"
|
||||||
type="text"
|
type="text"
|
||||||
class="search-input"
|
class="search-input"
|
||||||
:placeholder="t('pages.plugin.searchPlaceholder')"
|
:placeholder="t('pages.plugin.searchPlaceholder')"
|
||||||
>
|
/>
|
||||||
<button
|
<button v-if="searchText" class="clear-button" @click="cleanSearch">
|
||||||
v-if="searchText"
|
|
||||||
class="clear-button"
|
|
||||||
@click="cleanSearch"
|
|
||||||
>
|
|
||||||
<XIcon :size="16" />
|
<XIcon :size="16" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,20 +53,11 @@
|
|||||||
|
|
||||||
<!-- Reload Notice -->
|
<!-- Reload Notice -->
|
||||||
<transition name="notice">
|
<transition name="notice">
|
||||||
<div
|
<div v-if="needReload" class="plugin-card notice-card">
|
||||||
v-if="needReload"
|
|
||||||
class="plugin-card notice-card"
|
|
||||||
>
|
|
||||||
<div class="notice-content">
|
<div class="notice-content">
|
||||||
<AlertCircleIcon
|
<AlertCircleIcon class="notice-icon" :size="20" />
|
||||||
class="notice-icon"
|
|
||||||
:size="20"
|
|
||||||
/>
|
|
||||||
<span class="notice-text">{{ t('pages.plugin.needRestart') }}</span>
|
<span class="notice-text">{{ t('pages.plugin.needRestart') }}</span>
|
||||||
<button
|
<button class="action-button small" @click="reloadApp">
|
||||||
class="action-button small"
|
|
||||||
@click="reloadApp"
|
|
||||||
>
|
|
||||||
{{ t('pages.plugin.restartApp') }}
|
{{ t('pages.plugin.restartApp') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -89,10 +65,7 @@
|
|||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<!-- Loading Overlay -->
|
<!-- Loading Overlay -->
|
||||||
<div
|
<div v-if="loading" class="loading-overlay">
|
||||||
v-if="loading"
|
|
||||||
class="loading-overlay"
|
|
||||||
>
|
|
||||||
<div class="loading-spinner" />
|
<div class="loading-spinner" />
|
||||||
<span class="loading-text">{{ t('pages.plugin.loading') }}</span>
|
<span class="loading-text">{{ t('pages.plugin.loading') }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,12 +79,7 @@
|
|||||||
:class="{ disabled: !item.enabled && !searchText }"
|
:class="{ disabled: !item.enabled && !searchText }"
|
||||||
>
|
>
|
||||||
<!-- Plugin Badge -->
|
<!-- Plugin Badge -->
|
||||||
<div
|
<div v-if="!item.gui" class="cli-badge">CLI</div>
|
||||||
v-if="!item.gui"
|
|
||||||
class="cli-badge"
|
|
||||||
>
|
|
||||||
CLI
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Update Badge -->
|
<!-- Update Badge -->
|
||||||
<div
|
<div
|
||||||
@@ -123,17 +91,9 @@
|
|||||||
|
|
||||||
<!-- Plugin Header -->
|
<!-- Plugin Header -->
|
||||||
<div class="plugin-header">
|
<div class="plugin-header">
|
||||||
<img
|
<img class="plugin-logo" :src="item.logo" :onerror="setSrc" alt="" />
|
||||||
class="plugin-logo"
|
|
||||||
:src="item.logo"
|
|
||||||
:onerror="setSrc"
|
|
||||||
alt=""
|
|
||||||
>
|
|
||||||
<div class="plugin-info">
|
<div class="plugin-info">
|
||||||
<h3
|
<h3 class="plugin-name" @click="openHomepage(item.homepage)">
|
||||||
class="plugin-name"
|
|
||||||
@click="openHomepage(item.homepage)"
|
|
||||||
>
|
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
<span class="plugin-version">v{{ item.version }}</span>
|
<span class="plugin-version">v{{ item.version }}</span>
|
||||||
</h3>
|
</h3>
|
||||||
@@ -154,55 +114,31 @@
|
|||||||
<div class="plugin-actions">
|
<div class="plugin-actions">
|
||||||
<template v-if="searchText">
|
<template v-if="searchText">
|
||||||
<template v-if="!item.hasInstall">
|
<template v-if="!item.hasInstall">
|
||||||
<button
|
<button v-if="!item.ing" class="plugin-button install-button" @click="installPlugin(item)">
|
||||||
v-if="!item.ing"
|
|
||||||
class="plugin-button install-button"
|
|
||||||
@click="installPlugin(item)"
|
|
||||||
>
|
|
||||||
<DownloadIcon :size="16" />
|
<DownloadIcon :size="16" />
|
||||||
{{ t('pages.plugin.install') }}
|
{{ t('pages.plugin.install') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button v-else class="plugin-button installing-button" disabled>
|
||||||
v-else
|
|
||||||
class="plugin-button installing-button"
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
<div class="button-spinner" />
|
<div class="button-spinner" />
|
||||||
{{ t('pages.plugin.installing') }}
|
{{ t('pages.plugin.installing') }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<button
|
<button v-else class="plugin-button installed-button" disabled>
|
||||||
v-else
|
|
||||||
class="plugin-button installed-button"
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
<CheckIcon :size="16" />
|
<CheckIcon :size="16" />
|
||||||
{{ t('pages.plugin.installed') }}
|
{{ t('pages.plugin.installed') }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<button
|
<button v-if="item.ing" class="plugin-button processing-button" disabled>
|
||||||
v-if="item.ing"
|
|
||||||
class="plugin-button processing-button"
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
<div class="button-spinner" />
|
<div class="button-spinner" />
|
||||||
{{ t('pages.plugin.doingSomething') }}
|
{{ t('pages.plugin.doingSomething') }}
|
||||||
</button>
|
</button>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<button
|
<button v-if="item.enabled" class="plugin-button settings-button" @click="buildContextMenu(item)">
|
||||||
v-if="item.enabled"
|
|
||||||
class="plugin-button settings-button"
|
|
||||||
@click="buildContextMenu(item)"
|
|
||||||
>
|
|
||||||
<SettingsIcon :size="16" />
|
<SettingsIcon :size="16" />
|
||||||
{{ t('pages.plugin.settings') }}
|
{{ t('pages.plugin.settings') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button v-else class="plugin-button disabled-button" @click="buildContextMenu(item)">
|
||||||
v-else
|
|
||||||
class="plugin-button disabled-button"
|
|
||||||
@click="buildContextMenu(item)"
|
|
||||||
>
|
|
||||||
<XCircleIcon :size="16" />
|
<XCircleIcon :size="16" />
|
||||||
{{ t('pages.plugin.disabled') }}
|
{{ t('pages.plugin.disabled') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -213,22 +149,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty State -->
|
<!-- Empty State -->
|
||||||
<div
|
<div v-if="!loading && pluginList.length === 0" class="plugin-card empty-state">
|
||||||
v-if="!loading && pluginList.length === 0"
|
|
||||||
class="plugin-card empty-state"
|
|
||||||
>
|
|
||||||
<div class="empty-content">
|
<div class="empty-content">
|
||||||
<PackageIcon
|
<PackageIcon class="empty-icon" :size="48" />
|
||||||
class="empty-icon"
|
|
||||||
:size="48"
|
|
||||||
/>
|
|
||||||
<h3>{{ searchText ? t('pages.plugin.noPluginsFound') : t('pages.plugin.NoPluginsInstalled') }}</h3>
|
<h3>{{ searchText ? t('pages.plugin.noPluginsFound') : t('pages.plugin.NoPluginsInstalled') }}</h3>
|
||||||
<p>{{ searchText ? t('pages.plugin.tryDifferentSearch') : t('pages.plugin.installPluginsToGetStarted') }}</p>
|
<p>{{ searchText ? t('pages.plugin.tryDifferentSearch') : t('pages.plugin.installPluginsToGetStarted') }}</p>
|
||||||
<button
|
<button v-if="!searchText" class="action-button" @click="goAwesomeList">
|
||||||
v-if="!searchText"
|
|
||||||
class="action-button"
|
|
||||||
@click="goAwesomeList"
|
|
||||||
>
|
|
||||||
<ExternalLinkIcon :size="16" />
|
<ExternalLinkIcon :size="16" />
|
||||||
{{ t('pages.plugin.browsePlugins') }}
|
{{ t('pages.plugin.browsePlugins') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -237,23 +163,13 @@
|
|||||||
|
|
||||||
<!-- Config Modal -->
|
<!-- Config Modal -->
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<div
|
<div v-if="dialogVisible" class="modal-overlay" @click="dialogVisible = false">
|
||||||
v-if="dialogVisible"
|
<div class="modal-container" @click.stop>
|
||||||
class="modal-overlay"
|
|
||||||
@click="dialogVisible = false"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="modal-container"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h2 class="modal-title">
|
<h2 class="modal-title">
|
||||||
{{ t('pages.plugin.configThing', { c: configName }) }}
|
{{ t('pages.plugin.configThing', { c: configName }) }}
|
||||||
</h2>
|
</h2>
|
||||||
<button
|
<button class="modal-close" @click="dialogVisible = false">
|
||||||
class="modal-close"
|
|
||||||
@click="dialogVisible = false"
|
|
||||||
>
|
|
||||||
<XIcon :size="20" />
|
<XIcon :size="20" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -269,16 +185,10 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button
|
<button class="btn btn-secondary" @click="dialogVisible = false">
|
||||||
class="btn btn-secondary"
|
|
||||||
@click="dialogVisible = false"
|
|
||||||
>
|
|
||||||
{{ t('common.cancel') }}
|
{{ t('common.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="btn btn-primary" @click="handleConfirmConfig">
|
||||||
class="btn btn-primary"
|
|
||||||
@click="handleConfirmConfig"
|
|
||||||
>
|
|
||||||
{{ t('common.confirm') }}
|
{{ t('common.confirm') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -397,15 +307,7 @@ const pluginListHandler = (list: IPicGoPlugin[]) => {
|
|||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const installPluginHandler = (
|
const installPluginHandler = ({ success, body }: { success: boolean; body: string }) => {
|
||||||
{
|
|
||||||
success,
|
|
||||||
body
|
|
||||||
}: {
|
|
||||||
success: boolean
|
|
||||||
body: string
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
pluginList.value.forEach(item => {
|
pluginList.value.forEach(item => {
|
||||||
if (item.fullName === body) {
|
if (item.fullName === body) {
|
||||||
@@ -446,7 +348,11 @@ const uninstallSuccessHandler = (plugin: string) => {
|
|||||||
pluginNameList.value = pluginNameList.value.filter(item => item !== plugin)
|
pluginNameList.value = pluginNameList.value.filter(item => item !== plugin)
|
||||||
}
|
}
|
||||||
|
|
||||||
const picgoConfigPluginHandler = (_currentType: 'plugin' | 'transformer' | 'uploader', _configName: string, _config: any) => {
|
const picgoConfigPluginHandler = (
|
||||||
|
_currentType: 'plugin' | 'transformer' | 'uploader',
|
||||||
|
_configName: string,
|
||||||
|
_config: any
|
||||||
|
) => {
|
||||||
currentType.value = _currentType
|
currentType.value = _currentType
|
||||||
configName.value = _configName
|
configName.value = _configName
|
||||||
config.value = _config
|
config.value = _config
|
||||||
|
|||||||
@@ -15,20 +15,12 @@
|
|||||||
autofocus
|
autofocus
|
||||||
@keyup.enter="confirmName"
|
@keyup.enter="confirmName"
|
||||||
@input="clearValidationError"
|
@input="clearValidationError"
|
||||||
>
|
/>
|
||||||
<button
|
<button v-if="form.fileName" type="button" class="input-clear" @click="clearFileName">
|
||||||
v-if="form.fileName"
|
|
||||||
type="button"
|
|
||||||
class="input-clear"
|
|
||||||
@click="clearFileName"
|
|
||||||
>
|
|
||||||
<XIcon :size="16" />
|
<XIcon :size="16" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="validationError" class="validation-error">
|
||||||
v-if="validationError"
|
|
||||||
class="validation-error"
|
|
||||||
>
|
|
||||||
{{ validationError }}
|
{{ validationError }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -36,18 +28,10 @@
|
|||||||
|
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button
|
<button type="button" class="btn btn-secondary" @click="cancel">
|
||||||
type="button"
|
|
||||||
class="btn btn-secondary"
|
|
||||||
@click="cancel"
|
|
||||||
>
|
|
||||||
{{ $t('common.cancel') }}
|
{{ $t('common.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button type="submit" class="btn btn-primary" :disabled="!form.fileName.trim()">
|
||||||
type="submit"
|
|
||||||
class="btn btn-primary"
|
|
||||||
:disabled="!form.fileName.trim()"
|
|
||||||
>
|
|
||||||
{{ $t('common.confirm') }}
|
{{ $t('common.confirm') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -135,7 +119,6 @@ onBeforeMount(() => {
|
|||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.electron.ipcRendererRemoveAllListeners(RENAME_FILE_NAME)
|
window.electron.ipcRendererRemoveAllListeners(RENAME_FILE_NAME)
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
@@ -155,7 +138,9 @@ export default {
|
|||||||
.rename-card {
|
.rename-card {
|
||||||
background: var(--color-background-primary);
|
background: var(--color-background-primary);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
box-shadow:
|
||||||
|
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
||||||
|
0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
@@ -329,7 +314,6 @@ export default {
|
|||||||
.form-actions {
|
.form-actions {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Focus styles for accessibility */
|
/* Focus styles for accessibility */
|
||||||
@@ -346,7 +330,8 @@ export default {
|
|||||||
|
|
||||||
/* Animation for error state */
|
/* Animation for error state */
|
||||||
@keyframes shake {
|
@keyframes shake {
|
||||||
0%, 100% {
|
0%,
|
||||||
|
100% {
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
}
|
}
|
||||||
25% {
|
25% {
|
||||||
@@ -364,6 +349,8 @@ export default {
|
|||||||
/* Dark mode adjustments */
|
/* Dark mode adjustments */
|
||||||
:root.dark .rename-card,
|
:root.dark .rename-card,
|
||||||
:root.auto.dark .rename-card {
|
:root.auto.dark .rename-card {
|
||||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.3), 0 10px 10px -5px rgba(0, 0, 0, 0.2);
|
box-shadow:
|
||||||
|
0 20px 25px -5px rgba(0, 0, 0, 0.3),
|
||||||
|
0 10px 10px -5px rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -3,10 +3,7 @@
|
|||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="shortkey-header">
|
<div class="shortkey-header">
|
||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
<KeyboardIcon
|
<KeyboardIcon :size="24" class="header-icon" />
|
||||||
:size="24"
|
|
||||||
class="header-icon"
|
|
||||||
/>
|
|
||||||
<div>
|
<div>
|
||||||
<h1>{{ t('pages.shortKey.title') }}</h1>
|
<h1>{{ t('pages.shortKey.title') }}</h1>
|
||||||
<p>{{ ' ' }}</p>
|
<p>{{ ' ' }}</p>
|
||||||
@@ -28,11 +25,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr
|
<tr v-for="(item, index) in list" :key="item.name" class="table-row">
|
||||||
v-for="(item, index) in list"
|
|
||||||
:key="item.name"
|
|
||||||
class="table-row"
|
|
||||||
>
|
|
||||||
<td class="name-cell">
|
<td class="name-cell">
|
||||||
<div class="shortcut-name">
|
<div class="shortcut-name">
|
||||||
{{ item.label ? item.label : item.name }}
|
{{ item.label ? item.label : item.name }}
|
||||||
@@ -40,21 +33,12 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="key-cell">
|
<td class="key-cell">
|
||||||
<div class="key-binding">
|
<div class="key-binding">
|
||||||
<kbd
|
<kbd v-if="item.key" class="key-display">{{ item.key }}</kbd>
|
||||||
v-if="item.key"
|
<span v-else class="no-binding">{{ t('pages.shortKey.noBinding') }}</span>
|
||||||
class="key-display"
|
|
||||||
>{{ item.key }}</kbd>
|
|
||||||
<span
|
|
||||||
v-else
|
|
||||||
class="no-binding"
|
|
||||||
>{{ t('pages.shortKey.noBinding') }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="status-cell">
|
<td class="status-cell">
|
||||||
<span
|
<span class="status-badge" :class="{ 'status-enabled': item.enable, 'status-disabled': !item.enable }">
|
||||||
class="status-badge"
|
|
||||||
:class="{ 'status-enabled': item.enable, 'status-disabled': !item.enable }"
|
|
||||||
>
|
|
||||||
{{ item.enable ? t('pages.shortKey.enabled') : t('pages.shortKey.disabled') }}
|
{{ item.enable ? t('pages.shortKey.enabled') : t('pages.shortKey.disabled') }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -70,10 +54,7 @@
|
|||||||
>
|
>
|
||||||
{{ item.enable ? t('pages.shortKey.disable') : t('pages.shortKey.enable') }}
|
{{ item.enable ? t('pages.shortKey.disable') : t('pages.shortKey.enable') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="btn btn-sm btn-secondary" @click="openKeyBindingDialog(item, index)">
|
||||||
class="btn btn-sm btn-secondary"
|
|
||||||
@click="openKeyBindingDialog(item, index)"
|
|
||||||
>
|
|
||||||
<Edit :size="14" />
|
<Edit :size="14" />
|
||||||
{{ t('pages.shortKey.edit') }}
|
{{ t('pages.shortKey.edit') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -87,20 +68,13 @@
|
|||||||
|
|
||||||
<!-- Key Binding Modal -->
|
<!-- Key Binding Modal -->
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<div
|
<div v-if="keyBindingVisible" class="modal-overlay" @click.self="cancelKeyBinding">
|
||||||
v-if="keyBindingVisible"
|
|
||||||
class="modal-overlay"
|
|
||||||
@click.self="cancelKeyBinding"
|
|
||||||
>
|
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3 class="modal-title">
|
<h3 class="modal-title">
|
||||||
{{ t('pages.shortKey.changeUpload') }}
|
{{ t('pages.shortKey.changeUpload') }}
|
||||||
</h3>
|
</h3>
|
||||||
<button
|
<button class="modal-close" @click="cancelKeyBinding">
|
||||||
class="modal-close"
|
|
||||||
@click="cancelKeyBinding"
|
|
||||||
>
|
|
||||||
<XIcon :size="20" />
|
<XIcon :size="20" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -113,23 +87,17 @@
|
|||||||
:placeholder="t('pages.shortKey.pressKeys')"
|
:placeholder="t('pages.shortKey.pressKeys')"
|
||||||
readonly
|
readonly
|
||||||
@keydown.prevent="keyDetect($event as KeyboardEvent)"
|
@keydown.prevent="keyDetect($event as KeyboardEvent)"
|
||||||
>
|
/>
|
||||||
<div class="input-hint">
|
<div class="input-hint">
|
||||||
{{ t('pages.shortKey.pressHint') }}
|
{{ t('pages.shortKey.pressHint') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button
|
<button class="btn btn-secondary" @click="cancelKeyBinding">
|
||||||
class="btn btn-secondary"
|
|
||||||
@click="cancelKeyBinding"
|
|
||||||
>
|
|
||||||
{{ $t('CANCEL') }}
|
{{ $t('CANCEL') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="btn btn-primary" @click="confirmKeyBinding">
|
||||||
class="btn btn-primary"
|
|
||||||
@click="confirmKeyBinding"
|
|
||||||
>
|
|
||||||
{{ $t('common.confirm') }}
|
{{ $t('common.confirm') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,11 +4,7 @@
|
|||||||
<div class="toolbox-card header-card">
|
<div class="toolbox-card header-card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
<img
|
<img class="header-logo" :src="defaultLogo" alt="Toolbox Logo" />
|
||||||
class="header-logo"
|
|
||||||
:src="defaultLogo"
|
|
||||||
alt="Toolbox Logo"
|
|
||||||
>
|
|
||||||
<div class="header-text">
|
<div class="header-text">
|
||||||
<h1 class="header-title">
|
<h1 class="header-title">
|
||||||
{{ t('pages.toolbox.title') }}
|
{{ t('pages.toolbox.title') }}
|
||||||
@@ -20,12 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<template v-if="progress !== 100">
|
<template v-if="progress !== 100">
|
||||||
<button
|
<button class="action-button" :class="{ disabled: isLoading }" :disabled="isLoading" @click="handleCheck">
|
||||||
class="action-button"
|
|
||||||
:class="{ disabled: isLoading }"
|
|
||||||
:disabled="isLoading"
|
|
||||||
@click="handleCheck"
|
|
||||||
>
|
|
||||||
<span>{{ t('pages.toolbox.startScan') }}</span>
|
<span>{{ t('pages.toolbox.startScan') }}</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
@@ -36,20 +27,14 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-else-if="!isAllSuccess">
|
<template v-else-if="!isAllSuccess">
|
||||||
<template v-if="canFixLength !== 0">
|
<template v-if="canFixLength !== 0">
|
||||||
<button
|
<button class="action-button" @click="handleFix">
|
||||||
class="action-button"
|
|
||||||
@click="handleFix"
|
|
||||||
>
|
|
||||||
<span>{{ t('pages.toolbox.startFix') }}</span>
|
<span>{{ t('pages.toolbox.startFix') }}</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="cant-fix-container">
|
<div class="cant-fix-container">
|
||||||
<span class="cant-fix-text">{{ $t('pages.toolbox.autoFixFail') }}</span>
|
<span class="cant-fix-text">{{ $t('pages.toolbox.autoFixFail') }}</span>
|
||||||
<button
|
<button class="action-button secondary small" @click="handleCheck">
|
||||||
class="action-button secondary small"
|
|
||||||
@click="handleCheck"
|
|
||||||
>
|
|
||||||
<span>{{ t('pages.toolbox.reScan') }}</span>
|
<span>{{ t('pages.toolbox.reScan') }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -63,10 +48,7 @@
|
|||||||
<div class="toolbox-card progress-card">
|
<div class="toolbox-card progress-card">
|
||||||
<div class="progress-container">
|
<div class="progress-container">
|
||||||
<div class="progress-bar">
|
<div class="progress-bar">
|
||||||
<div
|
<div class="progress-fill" :style="{ width: `${progress}%` }" />
|
||||||
class="progress-fill"
|
|
||||||
:style="{ width: `${progress}%` }"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="progress-text">{{ Math.round(progress) }}%</span>
|
<span class="progress-text">{{ Math.round(progress) }}%</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,32 +68,19 @@
|
|||||||
'item-loading': item.status === IToolboxItemCheckStatus.LOADING
|
'item-loading': item.status === IToolboxItemCheckStatus.LOADING
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div
|
<div class="item-header" @click="toggleItem(key)">
|
||||||
class="item-header"
|
|
||||||
@click="toggleItem(key)"
|
|
||||||
>
|
|
||||||
<div class="item-title">
|
<div class="item-title">
|
||||||
<span>{{ item.title }}</span>
|
<span>{{ item.title }}</span>
|
||||||
<toolbox-status-icon :status="item.status" />
|
<toolbox-status-icon :status="item.status" />
|
||||||
</div>
|
</div>
|
||||||
<div class="item-chevron">
|
<div class="item-chevron">
|
||||||
<svg
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
>
|
|
||||||
<polyline points="6,9 12,15 18,9" />
|
<polyline points="6,9 12,15 18,9" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<transition name="item-content">
|
<transition name="item-content">
|
||||||
<div
|
<div v-if="activeTypes.includes(key)" class="item-content">
|
||||||
v-if="activeTypes.includes(key)"
|
|
||||||
class="item-content"
|
|
||||||
>
|
|
||||||
<div class="item-message">
|
<div class="item-message">
|
||||||
{{ item.msg || '' }}
|
{{ item.msg || '' }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,24 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="tray-page">
|
<div id="tray-page">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div
|
<div class="tray-header" @click="openSettingWindow">
|
||||||
class="tray-header"
|
|
||||||
@click="openSettingWindow"
|
|
||||||
>
|
|
||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
<span class="header-text">
|
<span class="header-text">
|
||||||
{{ t('pages.tray.openMainWindow') }}
|
{{ t('pages.tray.openMainWindow') }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-arrow">
|
<div class="header-arrow">
|
||||||
<svg
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
width="14"
|
|
||||||
height="14"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
>
|
|
||||||
<path d="m9 18 6-6-6-6" />
|
<path d="m9 18 6-6-6-6" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
@@ -27,10 +17,7 @@
|
|||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<div class="tray-content">
|
<div class="tray-content">
|
||||||
<!-- Clipboard Files Section -->
|
<!-- Clipboard Files Section -->
|
||||||
<div
|
<div v-if="clipboardFiles.length > 0" class="section">
|
||||||
v-if="clipboardFiles.length > 0"
|
|
||||||
class="section"
|
|
||||||
>
|
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<div class="section-title">
|
<div class="section-title">
|
||||||
{{ t('pages.tray.waitForUpload') }}
|
{{ t('pages.tray.waitForUpload') }}
|
||||||
@@ -48,15 +35,8 @@
|
|||||||
@click="uploadClipboardFiles"
|
@click="uploadClipboardFiles"
|
||||||
>
|
>
|
||||||
<div class="image-container">
|
<div class="image-container">
|
||||||
<img
|
<img :src="item.imgUrl" class="image" @error="onImageError" />
|
||||||
:src="item.imgUrl"
|
<div v-if="uploadFlag" class="upload-overlay">
|
||||||
class="image"
|
|
||||||
@error="onImageError"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="uploadFlag"
|
|
||||||
class="upload-overlay"
|
|
||||||
>
|
|
||||||
<div class="spinner" />
|
<div class="spinner" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -72,42 +52,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="image-grid">
|
<div class="image-grid">
|
||||||
<div
|
<div v-for="item in files" :key="item.imgUrl" class="image-item" @click="copyTheLink(item)">
|
||||||
v-for="item in files"
|
|
||||||
:key="item.imgUrl"
|
|
||||||
class="image-item"
|
|
||||||
@click="copyTheLink(item)"
|
|
||||||
>
|
|
||||||
<div class="image-container">
|
<div class="image-container">
|
||||||
<img
|
<img v-lazy="item.imgUrl" class="image" @error="onImageError" />
|
||||||
v-lazy="item.imgUrl"
|
|
||||||
class="image"
|
|
||||||
@error="onImageError"
|
|
||||||
>
|
|
||||||
<div class="image-overlay">
|
<div class="image-overlay">
|
||||||
<div
|
<div class="image-title" :title="item.fileName">
|
||||||
class="image-title"
|
|
||||||
:title="item.fileName"
|
|
||||||
>
|
|
||||||
{{ item.fileName }}
|
{{ item.fileName }}
|
||||||
</div>
|
</div>
|
||||||
<div class="copy-indicator">
|
<div class="copy-indicator">
|
||||||
<svg
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
width="12"
|
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
|
||||||
height="12"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
>
|
|
||||||
<rect
|
|
||||||
x="9"
|
|
||||||
y="9"
|
|
||||||
width="13"
|
|
||||||
height="13"
|
|
||||||
rx="2"
|
|
||||||
ry="2"
|
|
||||||
/>
|
|
||||||
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
|
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,24 +13,15 @@
|
|||||||
<span class="provider-name">{{ picBedName }}</span>
|
<span class="provider-name">{{ picBedName }}</span>
|
||||||
<span class="provider-config">{{ picBedConfigName || 'Default' }}</span>
|
<span class="provider-config">{{ picBedConfigName || 'Default' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<EditIcon
|
<EditIcon :size="16" class="provider-arrow" />
|
||||||
:size="16"
|
|
||||||
class="provider-arrow"
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<button
|
<button class="action-button secondary" @click="handleImageProcess">
|
||||||
class="action-button secondary"
|
|
||||||
@click="handleImageProcess"
|
|
||||||
>
|
|
||||||
<Settings :size="16" />
|
<Settings :size="16" />
|
||||||
<span>{{ t('pages.upload.imageProcessName') }}</span>
|
<span>{{ t('pages.upload.imageProcessName') }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="action-button" @click="handleChangePicBed">
|
||||||
class="action-button"
|
|
||||||
@click="handleChangePicBed"
|
|
||||||
>
|
|
||||||
<ArrowLeftRightIcon :size="16" />
|
<ArrowLeftRightIcon :size="16" />
|
||||||
<span>{{ t('pages.upload.changePicBed') }}</span>
|
<span>{{ t('pages.upload.changePicBed') }}</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -65,28 +56,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input id="file-uploader" ref="fileInput" type="file" multiple style="display: none" @change="onChange" />
|
||||||
id="file-uploader"
|
|
||||||
ref="fileInput"
|
|
||||||
type="file"
|
|
||||||
multiple
|
|
||||||
style="display: none"
|
|
||||||
@change="onChange"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Progress Bar -->
|
<!-- Progress Bar -->
|
||||||
<transition name="progress">
|
<transition name="progress">
|
||||||
<div
|
<div v-if="showProgress" class="progress-container">
|
||||||
v-if="showProgress"
|
|
||||||
class="progress-container"
|
|
||||||
>
|
|
||||||
<div class="progress-bar">
|
<div class="progress-bar">
|
||||||
<div
|
<div class="progress-fill" :class="{ 'progress-error': showError }" :style="{ width: `${progress}%` }" />
|
||||||
class="progress-fill"
|
|
||||||
:class="{ 'progress-error': showError }"
|
|
||||||
:style="{ width: `${progress}%` }"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="progress-text">
|
<span class="progress-text">
|
||||||
{{ showError ? t('pages.upload.uploadFailed') : `${progress}%` }}
|
{{ showError ? t('pages.upload.uploadFailed') : `${progress}%` }}
|
||||||
@@ -103,17 +80,11 @@
|
|||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="quick-actions">
|
<div class="quick-actions">
|
||||||
<button
|
<button class="quick-action-button" @click="uploadClipboardFiles">
|
||||||
class="quick-action-button"
|
|
||||||
@click="uploadClipboardFiles"
|
|
||||||
>
|
|
||||||
<ClipboardIcon :size="20" />
|
<ClipboardIcon :size="20" />
|
||||||
<span>{{ t('pages.upload.clipboardPicture') }}</span>
|
<span>{{ t('pages.upload.clipboardPicture') }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="quick-action-button" @click="uploadURLFiles">
|
||||||
class="quick-action-button"
|
|
||||||
@click="uploadURLFiles"
|
|
||||||
>
|
|
||||||
<LinkIcon :size="20" />
|
<LinkIcon :size="20" />
|
||||||
<span>{{ t('pages.upload.urlUpload') }}</span>
|
<span>{{ t('pages.upload.urlUpload') }}</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -149,18 +120,10 @@
|
|||||||
<div class="setting-group">
|
<div class="setting-group">
|
||||||
<label class="setting-label">{{ t('pages.upload.urlType.title') }}</label>
|
<label class="setting-label">{{ t('pages.upload.urlType.title') }}</label>
|
||||||
<div class="url-toggle">
|
<div class="url-toggle">
|
||||||
<button
|
<button class="toggle-button" :class="{ active: !useShortUrl }" @click="updateUrlType(false)">
|
||||||
class="toggle-button"
|
|
||||||
:class="{ active: !useShortUrl }"
|
|
||||||
@click="updateUrlType(false)"
|
|
||||||
>
|
|
||||||
<span>{{ t('pages.upload.urlType.normal') }}</span>
|
<span>{{ t('pages.upload.urlType.normal') }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="toggle-button" :class="{ active: useShortUrl }" @click="updateUrlType(true)">
|
||||||
class="toggle-button"
|
|
||||||
:class="{ active: useShortUrl }"
|
|
||||||
@click="updateUrlType(true)"
|
|
||||||
>
|
|
||||||
<span>{{ t('pages.upload.urlType.short') }}</span>
|
<span>{{ t('pages.upload.urlType.short') }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -170,23 +133,13 @@
|
|||||||
|
|
||||||
<!-- Image Process Dialog -->
|
<!-- Image Process Dialog -->
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<div
|
<div v-if="imageProcessDialogVisible" class="modal-overlay" @click.stop>
|
||||||
v-if="imageProcessDialogVisible"
|
<div class="modal-container" @click.stop>
|
||||||
class="modal-overlay"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="modal-container"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3 class="modal-title">
|
<h3 class="modal-title">
|
||||||
{{ t('pages.imageProcess.title') }}
|
{{ t('pages.imageProcess.title') }}
|
||||||
</h3>
|
</h3>
|
||||||
<button
|
<button class="modal-close" @click="imageProcessDialogVisible = false">
|
||||||
class="modal-close"
|
|
||||||
@click="imageProcessDialogVisible = false"
|
|
||||||
>
|
|
||||||
<XIcon :size="20" />
|
<XIcon :size="20" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -200,7 +153,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ArrowLeftRightIcon, ClipboardIcon, EditIcon, LinkIcon, Settings, UploadCloudIcon, XIcon } from 'lucide-vue-next'
|
import {
|
||||||
|
ArrowLeftRightIcon,
|
||||||
|
ClipboardIcon,
|
||||||
|
EditIcon,
|
||||||
|
LinkIcon,
|
||||||
|
Settings,
|
||||||
|
UploadCloudIcon,
|
||||||
|
XIcon
|
||||||
|
} from 'lucide-vue-next'
|
||||||
import { onBeforeMount, onBeforeUnmount, ref, watch } from 'vue'
|
import { onBeforeMount, onBeforeUnmount, ref, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
@@ -246,8 +207,8 @@ watch(picBedGlobal, () => {
|
|||||||
getDefaultPicBed()
|
getDefaultPicBed()
|
||||||
})
|
})
|
||||||
|
|
||||||
let removeUploadProgressListenerCallback: (() => void) = () => {}
|
let removeUploadProgressListenerCallback: () => void = () => {}
|
||||||
let removeSyncPicBedListenerCallback: (() => void) = () => {}
|
let removeSyncPicBedListenerCallback: () => void = () => {}
|
||||||
|
|
||||||
function uploadProgressHandler(p: number): void {
|
function uploadProgressHandler(p: number): void {
|
||||||
if (p !== -1) {
|
if (p !== -1) {
|
||||||
@@ -285,7 +246,10 @@ async function handlePicBedNameClick (_picBedName: string, picBedConfigName: str
|
|||||||
const formatedpicBedConfigName = picBedConfigName || 'Default'
|
const formatedpicBedConfigName = picBedConfigName || 'Default'
|
||||||
const currentPicBed = await getConfig<string>(configPaths.picBed.current)
|
const currentPicBed = await getConfig<string>(configPaths.picBed.current)
|
||||||
const currentPicBedConfig = ((await getConfig<any[]>(`uploader.${currentPicBed}`)) as any) || {}
|
const currentPicBedConfig = ((await getConfig<any[]>(`uploader.${currentPicBed}`)) as any) || {}
|
||||||
const configList = await window.electron.triggerRPC<IUploaderConfigItem>(IRPCActionType.PICBED_GET_CONFIG_LIST, currentPicBed)
|
const configList = await window.electron.triggerRPC<IUploaderConfigItem>(
|
||||||
|
IRPCActionType.PICBED_GET_CONFIG_LIST,
|
||||||
|
currentPicBed
|
||||||
|
)
|
||||||
const currentConfigList = configList?.configList ?? []
|
const currentConfigList = configList?.configList ?? []
|
||||||
const config = currentConfigList.find((item: any) => item._configName === formatedpicBedConfigName)
|
const config = currentConfigList.find((item: any) => item._configName === formatedpicBedConfigName)
|
||||||
$router.push({
|
$router.push({
|
||||||
@@ -436,7 +400,6 @@ onBeforeMount(() => {
|
|||||||
removeSyncPicBedListenerCallback = window.electron.ipcRendererOn('syncPicBed', syncPicBedHandler)
|
removeSyncPicBedListenerCallback = window.electron.ipcRendererOn('syncPicBed', syncPicBedHandler)
|
||||||
$bus.on(SHOW_INPUT_BOX_RESPONSE, handleInputBoxValue)
|
$bus.on(SHOW_INPUT_BOX_RESPONSE, handleInputBoxValue)
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|||||||
@@ -25,10 +25,7 @@
|
|||||||
<div class="config-update-time">
|
<div class="config-update-time">
|
||||||
{{ formatTime(item._updatedAt) }}
|
{{ formatTime(item._updatedAt) }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="defaultConfigId === item._id" class="default-badge">
|
||||||
v-if="defaultConfigId === item._id"
|
|
||||||
class="default-badge"
|
|
||||||
>
|
|
||||||
{{ t('pages.uploaderConfig.selected') }}
|
{{ t('pages.uploaderConfig.selected') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -53,10 +50,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Add New Config Button -->
|
<!-- Add New Config Button -->
|
||||||
<div
|
<div class="config-item config-item-add" @click="addNewConfig">
|
||||||
class="config-item config-item-add"
|
|
||||||
@click="addNewConfig"
|
|
||||||
>
|
|
||||||
<div class="add-content">
|
<div class="add-content">
|
||||||
<Plus :size="32" />
|
<Plus :size="32" />
|
||||||
<span class="add-text">{{ t('pages.uploaderConfig.addNew') }}</span>
|
<span class="add-text">{{ t('pages.uploaderConfig.addNew') }}</span>
|
||||||
@@ -68,11 +62,7 @@
|
|||||||
<!-- Actions Card -->
|
<!-- Actions Card -->
|
||||||
<div class="config-card actions-card">
|
<div class="config-card actions-card">
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<button
|
<button class="primary-button" :disabled="store?.state.defaultPicBed === type" @click="setDefaultPicBed(type)">
|
||||||
class="primary-button"
|
|
||||||
:disabled="store?.state.defaultPicBed === type"
|
|
||||||
@click="setDefaultPicBed(type)"
|
|
||||||
>
|
|
||||||
<DatabaseIcon :size="16" />
|
<DatabaseIcon :size="16" />
|
||||||
<span>{{ t('pages.uploaderConfig.setAsDefault') }}</span>
|
<span>{{ t('pages.uploaderConfig.setAsDefault') }}</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -133,7 +123,10 @@ onBeforeMount(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
async function getCurrentConfigList() {
|
async function getCurrentConfigList() {
|
||||||
const configList = await window.electron.triggerRPC<IUploaderConfigItem>(IRPCActionType.PICBED_GET_CONFIG_LIST, type.value)
|
const configList = await window.electron.triggerRPC<IUploaderConfigItem>(
|
||||||
|
IRPCActionType.PICBED_GET_CONFIG_LIST,
|
||||||
|
type.value
|
||||||
|
)
|
||||||
curConfigList.value = configList?.configList ?? []
|
curConfigList.value = configList?.configList ?? []
|
||||||
defaultConfigId.value = configList?.defaultId ?? ''
|
defaultConfigId.value = configList?.defaultId ?? ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,65 +5,33 @@
|
|||||||
<!-- Header Section -->
|
<!-- Header Section -->
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<div class="header-title-section">
|
<div class="header-title-section">
|
||||||
<h1
|
<h1 class="page-title" @click="handleNameClick">{{ picBedName }} {{ t('pages.picBedConfigs.title') }}</h1>
|
||||||
class="page-title"
|
<button class="link-button" :title="t('pages.picBedConfigs.viewDoc')" @click="handleNameClick">
|
||||||
@click="handleNameClick"
|
|
||||||
>
|
|
||||||
{{ picBedName }} {{ t('pages.picBedConfigs.title') }}
|
|
||||||
</h1>
|
|
||||||
<button
|
|
||||||
class="link-button"
|
|
||||||
:title="t('pages.picBedConfigs.viewDoc')"
|
|
||||||
@click="handleNameClick"
|
|
||||||
>
|
|
||||||
<ExternalLink :size="20" />
|
<ExternalLink :size="20" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button class="action-button primary" @click="handleCopyApi">
|
||||||
class="action-button primary"
|
|
||||||
@click="handleCopyApi"
|
|
||||||
>
|
|
||||||
<Copy :size="20" />
|
<Copy :size="20" />
|
||||||
{{ t('pages.picBedConfigs.copyAPI') }}
|
{{ t('pages.picBedConfigs.copyAPI') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Config Form Section -->
|
<!-- Config Form Section -->
|
||||||
<div
|
<div v-if="config.length > 0" class="form-section">
|
||||||
v-if="config.length > 0"
|
<config-form :id="type" ref="$configForm" :config="config" type="uploader" color-mode="white">
|
||||||
class="form-section"
|
|
||||||
>
|
|
||||||
<config-form
|
|
||||||
:id="type"
|
|
||||||
ref="$configForm"
|
|
||||||
:config="config"
|
|
||||||
type="uploader"
|
|
||||||
color-mode="white"
|
|
||||||
>
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<button
|
<button class="action-button secondary" type="button" @click="handleReset">
|
||||||
class="action-button secondary"
|
|
||||||
type="button"
|
|
||||||
@click="handleReset"
|
|
||||||
>
|
|
||||||
<RotateCcw :size="18" />
|
<RotateCcw :size="18" />
|
||||||
{{ t('common.reset') }}
|
{{ t('common.reset') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button class="action-button success" type="button" @click="handleConfirm">
|
||||||
class="action-button success"
|
|
||||||
type="button"
|
|
||||||
@click="handleConfirm"
|
|
||||||
>
|
|
||||||
<Check :size="18" />
|
<Check :size="18" />
|
||||||
{{ t('common.confirm') }}
|
{{ t('common.confirm') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div
|
<div v-if="picBedConfigList.length > 0" class="dropdown-wrapper">
|
||||||
v-if="picBedConfigList.length > 0"
|
|
||||||
class="dropdown-wrapper"
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
class="action-button warning dropdown-trigger"
|
class="action-button warning dropdown-trigger"
|
||||||
type="button"
|
type="button"
|
||||||
@@ -91,11 +59,7 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<transition name="dropdown">
|
<transition name="dropdown">
|
||||||
<div
|
<div v-show="dropdownVisible" class="dropdown-menu" :class="{ 'dropdown-up': true }">
|
||||||
v-show="dropdownVisible"
|
|
||||||
class="dropdown-menu"
|
|
||||||
:class="{ 'dropdown-up': true }"
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
v-for="item in picBedConfigList"
|
v-for="item in picBedConfigList"
|
||||||
:key="item._id"
|
:key="item._id"
|
||||||
@@ -112,15 +76,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty State -->
|
<!-- Empty State -->
|
||||||
<div
|
<div v-else class="empty-state">
|
||||||
v-else
|
|
||||||
class="empty-state"
|
|
||||||
>
|
|
||||||
<div class="empty-content">
|
<div class="empty-content">
|
||||||
<FolderOpen
|
<FolderOpen class="empty-icon" :size="48" />
|
||||||
class="empty-icon"
|
|
||||||
:size="48"
|
|
||||||
/>
|
|
||||||
<h3>{{ t('pages.picBedConfigs.noConfigOptions') }}</h3>
|
<h3>{{ t('pages.picBedConfigs.noConfigOptions') }}</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -128,10 +86,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Loading Overlay -->
|
<!-- Loading Overlay -->
|
||||||
<div
|
<div v-if="loading" class="loading-overlay">
|
||||||
v-if="loading"
|
|
||||||
class="loading-overlay"
|
|
||||||
>
|
|
||||||
<div class="loading-spinner" />
|
<div class="loading-spinner" />
|
||||||
<span class="loading-text">Loading...</span>
|
<span class="loading-text">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -195,7 +150,12 @@ const handleConfirm = async () => {
|
|||||||
const result = (await $configForm.value?.validate()) || false
|
const result = (await $configForm.value?.validate()) || false
|
||||||
if (result !== false) {
|
if (result !== false) {
|
||||||
const rawResult = getRawData(result)
|
const rawResult = getRawData(result)
|
||||||
await window.electron.triggerRPC<void>(IRPCActionType.UPLOADER_UPDATE_CONFIG, type.value, rawResult?._id, rawResult)
|
await window.electron.triggerRPC<void>(
|
||||||
|
IRPCActionType.UPLOADER_UPDATE_CONFIG,
|
||||||
|
type.value,
|
||||||
|
rawResult?._id,
|
||||||
|
rawResult
|
||||||
|
)
|
||||||
message.success(t('pages.picBedConfigs.setSuccess'))
|
message.success(t('pages.picBedConfigs.setSuccess'))
|
||||||
$router.back()
|
$router.back()
|
||||||
} else {
|
} else {
|
||||||
@@ -222,7 +182,9 @@ async function getPicBeds () {
|
|||||||
|
|
||||||
async function getPicBedConfigList() {
|
async function getPicBedConfigList() {
|
||||||
try {
|
try {
|
||||||
const res = (await window.electron.triggerRPC<IUploaderConfigItem>(IRPCActionType.PICBED_GET_CONFIG_LIST, type.value)) || undefined
|
const res =
|
||||||
|
(await window.electron.triggerRPC<IUploaderConfigItem>(IRPCActionType.PICBED_GET_CONFIG_LIST, type.value)) ||
|
||||||
|
undefined
|
||||||
const configList = res?.configList || []
|
const configList = res?.configList || []
|
||||||
picBedConfigList.value = configList.filter(item => item._id !== $route.params.configId)
|
picBedConfigList.value = configList.filter(item => item._id !== $route.params.configId)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -626,8 +588,12 @@ export default {
|
|||||||
|
|
||||||
/* Animations */
|
/* Animations */
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% { transform: rotate(0deg); }
|
0% {
|
||||||
100% { transform: rotate(360deg); }
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dark mode adjustments */
|
/* Dark mode adjustments */
|
||||||
|
|||||||
@@ -1,6 +1,24 @@
|
|||||||
import type { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
|
import type { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
|
||||||
|
|
||||||
import type { IAliYunConfig, IAwsS3PListUserConfig, IGitHubConfig, IImgurConfig, ILocalConfig, ILskyConfig, IPicBedType, IQiniuConfig, IServerConfig, ISftpPlistConfig, IShortKeyConfig, ISMMSConfig, ISyncConfig, ITcYunConfig, IUploaderConfig, IUpYunConfig, IWebdavPlistConfig } from '#/types/types'
|
import type {
|
||||||
|
IAliYunConfig,
|
||||||
|
IAwsS3PListUserConfig,
|
||||||
|
IGitHubConfig,
|
||||||
|
IImgurConfig,
|
||||||
|
ILocalConfig,
|
||||||
|
ILskyConfig,
|
||||||
|
IPicBedType,
|
||||||
|
IQiniuConfig,
|
||||||
|
IServerConfig,
|
||||||
|
ISftpPlistConfig,
|
||||||
|
IShortKeyConfig,
|
||||||
|
ISMMSConfig,
|
||||||
|
ISyncConfig,
|
||||||
|
ITcYunConfig,
|
||||||
|
IUploaderConfig,
|
||||||
|
IUpYunConfig,
|
||||||
|
IWebdavPlistConfig
|
||||||
|
} from '#/types/types'
|
||||||
|
|
||||||
export type manualPageOpenType = 'window' | 'browser'
|
export type manualPageOpenType = 'window' | 'browser'
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { onBeforeUnmount, onMounted } from 'vue'
|
|||||||
|
|
||||||
function disableDrag(e: DragEvent) {
|
function disableDrag(e: DragEvent) {
|
||||||
const dropzone = document.getElementById('upload-area')
|
const dropzone = document.getElementById('upload-area')
|
||||||
if (dropzone === null || !dropzone.contains((e.target as Node))) {
|
if (dropzone === null || !dropzone.contains(e.target as Node)) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.dataTransfer!.effectAllowed = 'none'
|
e.dataTransfer!.effectAllowed = 'none'
|
||||||
e.dataTransfer!.dropEffect = 'none'
|
e.dataTransfer!.dropEffect = 'none'
|
||||||
|
|||||||
@@ -29,11 +29,9 @@ export interface IRPCRouter {
|
|||||||
|
|
||||||
export type IToolboxChecker<T = any> = (event: IpcMainEvent) => Promise<T>
|
export type IToolboxChecker<T = any> = (event: IpcMainEvent) => Promise<T>
|
||||||
|
|
||||||
export type IToolboxCheckerMap<T extends string> =
|
export type IToolboxCheckerMap<T extends string> = Record<T, IToolboxChecker>
|
||||||
Record<T, IToolboxChecker>
|
|
||||||
|
|
||||||
export type IToolboxFixMap<T extends string> =
|
export type IToolboxFixMap<T extends string> = Record<T, IToolboxChecker<IToolboxCheckRes>>
|
||||||
Record<T, IToolboxChecker<IToolboxCheckRes>>
|
|
||||||
|
|
||||||
export interface IToolboxCheckRes {
|
export interface IToolboxCheckRes {
|
||||||
type: string
|
type: string
|
||||||
|
|||||||
6
src/universal/types/shims-tsx.d.ts
vendored
6
src/universal/types/shims-tsx.d.ts
vendored
@@ -13,7 +13,6 @@ import { ILocales, ILocalesKey } from '#/types/i18n'
|
|||||||
import { IStringKeyMap } from '#/types/types'
|
import { IStringKeyMap } from '#/types/types'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
||||||
export namespace JSX {
|
export namespace JSX {
|
||||||
export interface Element extends VNode {}
|
export interface Element extends VNode {}
|
||||||
export interface IntrinsicElements {
|
export interface IntrinsicElements {
|
||||||
@@ -33,7 +32,7 @@ declare global {
|
|||||||
ipcRendererRemoveAllListeners: (channel: string) => void
|
ipcRendererRemoveAllListeners: (channel: string) => void
|
||||||
clipboard: {
|
clipboard: {
|
||||||
writeText: typeof clipboard.writeText
|
writeText: typeof clipboard.writeText
|
||||||
},
|
}
|
||||||
showFilePath: (file: File) => string
|
showFilePath: (file: File) => string
|
||||||
}
|
}
|
||||||
node: {
|
node: {
|
||||||
@@ -43,7 +42,7 @@ declare global {
|
|||||||
basename: typeof path.basename
|
basename: typeof path.basename
|
||||||
normalize: typeof path.normalize
|
normalize: typeof path.normalize
|
||||||
extname: typeof path.extname
|
extname: typeof path.extname
|
||||||
sep: typeof path.sep,
|
sep: typeof path.sep
|
||||||
posix: {
|
posix: {
|
||||||
sep: typeof path.posix.sep
|
sep: typeof path.posix.sep
|
||||||
}
|
}
|
||||||
@@ -64,7 +63,6 @@ declare global {
|
|||||||
mime: {
|
mime: {
|
||||||
lookup: typeof mime.lookup
|
lookup: typeof mime.lookup
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
i18n: {
|
i18n: {
|
||||||
setLocales: (lang: string, locales: ILocales) => void
|
setLocales: (lang: string, locales: ILocales) => void
|
||||||
|
|||||||
@@ -88,7 +88,8 @@ describe('AESHelper', () => {
|
|||||||
|
|
||||||
const a = new AESHelper(uniquePwd)
|
const a = new AESHelper(uniquePwd)
|
||||||
const b = new AESHelper(uniquePwd)
|
const b = new AESHelper(uniquePwd)
|
||||||
a.encrypt('x'); b.encrypt('y')
|
a.encrypt('x')
|
||||||
|
b.encrypt('y')
|
||||||
|
|
||||||
const callsForPwd = spy.mock.calls.filter(args => args[0] === uniquePwd)
|
const callsForPwd = spy.mock.calls.filter(args => args[0] === uniquePwd)
|
||||||
expect(callsForPwd.length).toBe(1)
|
expect(callsForPwd.length).toBe(1)
|
||||||
|
|||||||
268
yarn.lock
268
yarn.lock
@@ -1042,11 +1042,6 @@
|
|||||||
ajv "^6.12.0"
|
ajv "^6.12.0"
|
||||||
ajv-keywords "^3.4.1"
|
ajv-keywords "^3.4.1"
|
||||||
|
|
||||||
"@electron-toolkit/preload@^3.0.2":
|
|
||||||
version "3.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@electron-toolkit/preload/-/preload-3.0.2.tgz#ee5bb33aba48741c5bc539a9a6faad0be455465e"
|
|
||||||
integrity sha512-TWWPToXd8qPRfSXwzf5KVhpXMfONaUuRAZJHsKthKgZR/+LqX1dZVSSClQ8OTAEduvLGdecljCsoT2jSshfoUg==
|
|
||||||
|
|
||||||
"@electron/asar@3.2.18":
|
"@electron/asar@3.2.18":
|
||||||
version "3.2.18"
|
version "3.2.18"
|
||||||
resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.18.tgz#fa607f829209bab8b9e0ce6658d3fe81b2cba517"
|
resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.18.tgz#fa607f829209bab8b9e0ce6658d3fe81b2cba517"
|
||||||
@@ -2841,11 +2836,6 @@
|
|||||||
resolved "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
|
resolved "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
|
||||||
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
|
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
|
||||||
|
|
||||||
"@tootallnate/quickjs-emscripten@^0.23.0":
|
|
||||||
version "0.23.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c"
|
|
||||||
integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==
|
|
||||||
|
|
||||||
"@tsconfig/node10@^1.0.7":
|
"@tsconfig/node10@^1.0.7":
|
||||||
version "1.0.9"
|
version "1.0.9"
|
||||||
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
|
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
|
||||||
@@ -3153,11 +3143,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/video.js/-/video.js-7.3.58.tgz#7e8cdafee25c75d6eb18f530b93ac52edff53c03"
|
resolved "https://registry.yarnpkg.com/@types/video.js/-/video.js-7.3.58.tgz#7e8cdafee25c75d6eb18f530b93ac52edff53c03"
|
||||||
integrity sha512-1CQjuSrgbv1/dhmcfQ83eVyYbvGyqhTvb2Opxr0QCV+iJ4J6/J+XWQ3Om59WiwCd1MN3rDUHasx5XRrpUtewYQ==
|
integrity sha512-1CQjuSrgbv1/dhmcfQ83eVyYbvGyqhTvb2Opxr0QCV+iJ4J6/J+XWQ3Om59WiwCd1MN3rDUHasx5XRrpUtewYQ==
|
||||||
|
|
||||||
"@types/web-bluetooth@^0.0.21":
|
|
||||||
version "0.0.21"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz#525433c784aed9b457aaa0ee3d92aeb71f346b63"
|
|
||||||
integrity sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==
|
|
||||||
|
|
||||||
"@types/write-file-atomic@^4.0.3":
|
"@types/write-file-atomic@^4.0.3":
|
||||||
version "4.0.3"
|
version "4.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/write-file-atomic/-/write-file-atomic-4.0.3.tgz#bda169b8369022e2c87028671fa4b742c08d98c9"
|
resolved "https://registry.yarnpkg.com/@types/write-file-atomic/-/write-file-atomic-4.0.3.tgz#bda169b8369022e2c87028671fa4b742c08d98c9"
|
||||||
@@ -3172,21 +3157,6 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@8.38.0":
|
|
||||||
version "8.38.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz#6e5220d16f2691ab6d983c1737dd5b36e17641b7"
|
|
||||||
integrity sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==
|
|
||||||
dependencies:
|
|
||||||
"@eslint-community/regexpp" "^4.10.0"
|
|
||||||
"@typescript-eslint/scope-manager" "8.38.0"
|
|
||||||
"@typescript-eslint/type-utils" "8.38.0"
|
|
||||||
"@typescript-eslint/utils" "8.38.0"
|
|
||||||
"@typescript-eslint/visitor-keys" "8.38.0"
|
|
||||||
graphemer "^1.4.0"
|
|
||||||
ignore "^7.0.0"
|
|
||||||
natural-compare "^1.4.0"
|
|
||||||
ts-api-utils "^2.1.0"
|
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@8.39.1":
|
"@typescript-eslint/eslint-plugin@8.39.1":
|
||||||
version "8.39.1"
|
version "8.39.1"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.1.tgz#28dffcb5272d20afe250bfeec3173263db5528a0"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.1.tgz#28dffcb5272d20afe250bfeec3173263db5528a0"
|
||||||
@@ -3202,17 +3172,6 @@
|
|||||||
natural-compare "^1.4.0"
|
natural-compare "^1.4.0"
|
||||||
ts-api-utils "^2.1.0"
|
ts-api-utils "^2.1.0"
|
||||||
|
|
||||||
"@typescript-eslint/parser@8.38.0":
|
|
||||||
version "8.38.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.38.0.tgz#6723a5ea881e1777956b1045cba30be5ea838293"
|
|
||||||
integrity sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/scope-manager" "8.38.0"
|
|
||||||
"@typescript-eslint/types" "8.38.0"
|
|
||||||
"@typescript-eslint/typescript-estree" "8.38.0"
|
|
||||||
"@typescript-eslint/visitor-keys" "8.38.0"
|
|
||||||
debug "^4.3.4"
|
|
||||||
|
|
||||||
"@typescript-eslint/parser@8.39.1":
|
"@typescript-eslint/parser@8.39.1":
|
||||||
version "8.39.1"
|
version "8.39.1"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.39.1.tgz#7f8f9ecfc7e172d67e42c366fa198e42324e5d50"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.39.1.tgz#7f8f9ecfc7e172d67e42c366fa198e42324e5d50"
|
||||||
@@ -3268,17 +3227,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.1.tgz#17f13b4ad481e7bec7c249ee1854078645b34b12"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.1.tgz#17f13b4ad481e7bec7c249ee1854078645b34b12"
|
||||||
integrity sha512-ePUPGVtTMR8XMU2Hee8kD0Pu4NDE1CN9Q1sxGSGd/mbOtGZDM7pnhXNJnzW63zk/q+Z54zVzj44HtwXln5CvHA==
|
integrity sha512-ePUPGVtTMR8XMU2Hee8kD0Pu4NDE1CN9Q1sxGSGd/mbOtGZDM7pnhXNJnzW63zk/q+Z54zVzj44HtwXln5CvHA==
|
||||||
|
|
||||||
"@typescript-eslint/type-utils@8.38.0":
|
|
||||||
version "8.38.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz#a56cd84765fa6ec135fe252b5db61e304403a85b"
|
|
||||||
integrity sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types" "8.38.0"
|
|
||||||
"@typescript-eslint/typescript-estree" "8.38.0"
|
|
||||||
"@typescript-eslint/utils" "8.38.0"
|
|
||||||
debug "^4.3.4"
|
|
||||||
ts-api-utils "^2.1.0"
|
|
||||||
|
|
||||||
"@typescript-eslint/type-utils@8.39.1":
|
"@typescript-eslint/type-utils@8.39.1":
|
||||||
version "8.39.1"
|
version "8.39.1"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.39.1.tgz#642f9fb96173649e2928fea0375b1d74d31906c2"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.39.1.tgz#642f9fb96173649e2928fea0375b1d74d31906c2"
|
||||||
@@ -3332,16 +3280,6 @@
|
|||||||
semver "^7.6.0"
|
semver "^7.6.0"
|
||||||
ts-api-utils "^2.1.0"
|
ts-api-utils "^2.1.0"
|
||||||
|
|
||||||
"@typescript-eslint/utils@8.38.0", "@typescript-eslint/utils@^8.32.1", "@typescript-eslint/utils@^8.35.1":
|
|
||||||
version "8.38.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.38.0.tgz#5f10159899d30eb92ba70e642ca6f754bddbf15a"
|
|
||||||
integrity sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==
|
|
||||||
dependencies:
|
|
||||||
"@eslint-community/eslint-utils" "^4.7.0"
|
|
||||||
"@typescript-eslint/scope-manager" "8.38.0"
|
|
||||||
"@typescript-eslint/types" "8.38.0"
|
|
||||||
"@typescript-eslint/typescript-estree" "8.38.0"
|
|
||||||
|
|
||||||
"@typescript-eslint/utils@8.39.1":
|
"@typescript-eslint/utils@8.39.1":
|
||||||
version "8.39.1"
|
version "8.39.1"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.39.1.tgz#58a834f89f93b786ada2cd14d77fa63c3c8f408b"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.39.1.tgz#58a834f89f93b786ada2cd14d77fa63c3c8f408b"
|
||||||
@@ -3352,6 +3290,16 @@
|
|||||||
"@typescript-eslint/types" "8.39.1"
|
"@typescript-eslint/types" "8.39.1"
|
||||||
"@typescript-eslint/typescript-estree" "8.39.1"
|
"@typescript-eslint/typescript-estree" "8.39.1"
|
||||||
|
|
||||||
|
"@typescript-eslint/utils@^8.32.1":
|
||||||
|
version "8.38.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.38.0.tgz#5f10159899d30eb92ba70e642ca6f754bddbf15a"
|
||||||
|
integrity sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==
|
||||||
|
dependencies:
|
||||||
|
"@eslint-community/eslint-utils" "^4.7.0"
|
||||||
|
"@typescript-eslint/scope-manager" "8.38.0"
|
||||||
|
"@typescript-eslint/types" "8.38.0"
|
||||||
|
"@typescript-eslint/typescript-estree" "8.38.0"
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@8.38.0":
|
"@typescript-eslint/visitor-keys@8.38.0":
|
||||||
version "8.38.0"
|
version "8.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz#a9765a527b082cb8fc60fd8a16e47c7ad5b60ea5"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz#a9765a527b082cb8fc60fd8a16e47c7ad5b60ea5"
|
||||||
@@ -3713,14 +3661,6 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
rfdc "^1.4.1"
|
rfdc "^1.4.1"
|
||||||
|
|
||||||
"@vue/eslint-config-prettier@^10.2.0":
|
|
||||||
version "10.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@vue/eslint-config-prettier/-/eslint-config-prettier-10.2.0.tgz#49a5ed571acb81820a216e6d88ebf1f3def321d0"
|
|
||||||
integrity sha512-GL3YBLwv/+b86yHcNNfPJxOTtVFJ4Mbc9UU3zR+KVoG7SwGTjPT+32fXamscNumElhcpXW3mT0DgzS9w32S7Bw==
|
|
||||||
dependencies:
|
|
||||||
eslint-config-prettier "^10.0.1"
|
|
||||||
eslint-plugin-prettier "^5.2.2"
|
|
||||||
|
|
||||||
"@vue/eslint-config-standard@^9.0.1":
|
"@vue/eslint-config-standard@^9.0.1":
|
||||||
version "9.0.1"
|
version "9.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@vue/eslint-config-standard/-/eslint-config-standard-9.0.1.tgz#d2a864c3a810c43e3b5323ea5d70598638c9c0f5"
|
resolved "https://registry.yarnpkg.com/@vue/eslint-config-standard/-/eslint-config-standard-9.0.1.tgz#d2a864c3a810c43e3b5323ea5d70598638c9c0f5"
|
||||||
@@ -3733,16 +3673,6 @@
|
|||||||
eslint-plugin-promise "^7.2.1"
|
eslint-plugin-promise "^7.2.1"
|
||||||
globals "^16.0.0"
|
globals "^16.0.0"
|
||||||
|
|
||||||
"@vue/eslint-config-typescript@^14.6.0":
|
|
||||||
version "14.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@vue/eslint-config-typescript/-/eslint-config-typescript-14.6.0.tgz#c526574c1f23972441752360b547bd19a7371e33"
|
|
||||||
integrity sha512-UpiRY/7go4Yps4mYCjkvlIbVWmn9YvPGQDxTAlcKLphyaD77LjIu3plH4Y9zNT0GB4f3K5tMmhhtRhPOgrQ/bQ==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/utils" "^8.35.1"
|
|
||||||
fast-glob "^3.3.3"
|
|
||||||
typescript-eslint "^8.35.1"
|
|
||||||
vue-eslint-parser "^10.2.0"
|
|
||||||
|
|
||||||
"@vue/language-core@3.0.5":
|
"@vue/language-core@3.0.5":
|
||||||
version "3.0.5"
|
version "3.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-3.0.5.tgz#c296c65e7b2e6d69fbf2088f0208a55362825323"
|
resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-3.0.5.tgz#c296c65e7b2e6d69fbf2088f0208a55362825323"
|
||||||
@@ -3795,25 +3725,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.18.tgz#529f24a88d3ed678d50fd5c07455841fbe8ac95e"
|
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.18.tgz#529f24a88d3ed678d50fd5c07455841fbe8ac95e"
|
||||||
integrity sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==
|
integrity sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==
|
||||||
|
|
||||||
"@vueuse/core@^13.6.0":
|
|
||||||
version "13.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-13.6.0.tgz#4137f63dc4cef2ff8ae74ee146d6b6070d707878"
|
|
||||||
integrity sha512-DJbD5fV86muVmBgS9QQPddVX7d9hWYswzlf4bIyUD2dj8GC46R1uNClZhVAmsdVts4xb2jwp1PbpuiA50Qee1A==
|
|
||||||
dependencies:
|
|
||||||
"@types/web-bluetooth" "^0.0.21"
|
|
||||||
"@vueuse/metadata" "13.6.0"
|
|
||||||
"@vueuse/shared" "13.6.0"
|
|
||||||
|
|
||||||
"@vueuse/metadata@13.6.0":
|
|
||||||
version "13.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-13.6.0.tgz#49196025c96c7daeb591c20a54b61cc336af99b6"
|
|
||||||
integrity sha512-rnIH7JvU7NjrpexTsl2Iwv0V0yAx9cw7+clymjKuLSXG0QMcLD0LDgdNmXic+qL0SGvgSVPEpM9IDO/wqo1vkQ==
|
|
||||||
|
|
||||||
"@vueuse/shared@13.6.0":
|
|
||||||
version "13.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-13.6.0.tgz#872fdbd725fb4e3a12bd5aab85af9a5db0b1e481"
|
|
||||||
integrity sha512-pDykCSoS2T3fsQrYqf9SyF0QXWHmcGPQ+qiOVjlYSzlWd9dgppB2bFSM1GgKKkt7uzn0BBMV3IbJsUfHG2+BCg==
|
|
||||||
|
|
||||||
"@xmldom/xmldom@^0.8.3":
|
"@xmldom/xmldom@^0.8.3":
|
||||||
version "0.8.6"
|
version "0.8.6"
|
||||||
resolved "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.6.tgz#8a1524eb5bd5e965c1e3735476f0262469f71440"
|
resolved "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.6.tgz#8a1524eb5bd5e965c1e3735476f0262469f71440"
|
||||||
@@ -4145,13 +4056,6 @@ assertion-error@^2.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7"
|
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7"
|
||||||
integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==
|
integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==
|
||||||
|
|
||||||
ast-types@^0.13.4:
|
|
||||||
version "0.13.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782"
|
|
||||||
integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==
|
|
||||||
dependencies:
|
|
||||||
tslib "^2.0.1"
|
|
||||||
|
|
||||||
astral-regex@^2.0.0:
|
astral-regex@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
|
resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
|
||||||
@@ -4223,11 +4127,6 @@ base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1:
|
|||||||
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||||
|
|
||||||
basic-ftp@^5.0.2:
|
|
||||||
version "5.0.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/basic-ftp/-/basic-ftp-5.0.5.tgz#14a474f5fffecca1f4f406f1c26b18f800225ac0"
|
|
||||||
integrity sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==
|
|
||||||
|
|
||||||
bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2:
|
bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmmirror.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
|
resolved "https://registry.npmmirror.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
|
||||||
@@ -4538,6 +4437,11 @@ chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
|
|||||||
ansi-styles "^4.1.0"
|
ansi-styles "^4.1.0"
|
||||||
supports-color "^7.1.0"
|
supports-color "^7.1.0"
|
||||||
|
|
||||||
|
chalk@^5.5.0:
|
||||||
|
version "5.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.5.0.tgz#67ada1df5ca809dc84c9b819d76418ddcf128428"
|
||||||
|
integrity sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==
|
||||||
|
|
||||||
change-case@^5.4.4:
|
change-case@^5.4.4:
|
||||||
version "5.4.4"
|
version "5.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/change-case/-/change-case-5.4.4.tgz#0d52b507d8fb8f204343432381d1a6d7bff97a02"
|
resolved "https://registry.yarnpkg.com/change-case/-/change-case-5.4.4.tgz#0d52b507d8fb8f204343432381d1a6d7bff97a02"
|
||||||
@@ -5092,11 +4996,6 @@ data-uri-to-buffer@^4.0.0:
|
|||||||
resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e"
|
resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e"
|
||||||
integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==
|
integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==
|
||||||
|
|
||||||
data-uri-to-buffer@^6.0.2:
|
|
||||||
version "6.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz#8a58bb67384b261a38ef18bea1810cb01badd28b"
|
|
||||||
integrity sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==
|
|
||||||
|
|
||||||
dateformat@^2.0.0:
|
dateformat@^2.0.0:
|
||||||
version "2.2.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.npmmirror.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062"
|
resolved "https://registry.npmmirror.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062"
|
||||||
@@ -5203,15 +5102,6 @@ defu@^6.1.4:
|
|||||||
resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479"
|
resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479"
|
||||||
integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==
|
integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==
|
||||||
|
|
||||||
degenerator@^5.0.0:
|
|
||||||
version "5.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-5.0.1.tgz#9403bf297c6dad9a1ece409b37db27954f91f2f5"
|
|
||||||
integrity sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==
|
|
||||||
dependencies:
|
|
||||||
ast-types "^0.13.4"
|
|
||||||
escodegen "^2.1.0"
|
|
||||||
esprima "^4.0.1"
|
|
||||||
|
|
||||||
delayed-stream@~1.0.0:
|
delayed-stream@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||||
@@ -5656,7 +5546,7 @@ eslint-compat-utils@^0.5.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
semver "^7.5.4"
|
semver "^7.5.4"
|
||||||
|
|
||||||
eslint-config-prettier@^10.0.1:
|
eslint-config-prettier@^10.1.8:
|
||||||
version "10.1.8"
|
version "10.1.8"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz#15734ce4af8c2778cc32f0b01b37b0b5cd1ecb97"
|
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz#15734ce4af8c2778cc32f0b01b37b0b5cd1ecb97"
|
||||||
integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==
|
integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==
|
||||||
@@ -5718,14 +5608,6 @@ eslint-plugin-n@^17.16.2, eslint-plugin-n@^17.20.0:
|
|||||||
semver "^7.6.3"
|
semver "^7.6.3"
|
||||||
ts-declaration-location "^1.0.6"
|
ts-declaration-location "^1.0.6"
|
||||||
|
|
||||||
eslint-plugin-prettier@^5.2.2:
|
|
||||||
version "5.5.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.3.tgz#1f88e9220a72ac8be171eec5f9d4e4d529b5f4a0"
|
|
||||||
integrity sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==
|
|
||||||
dependencies:
|
|
||||||
prettier-linter-helpers "^1.0.0"
|
|
||||||
synckit "^0.11.7"
|
|
||||||
|
|
||||||
eslint-plugin-prettier@^5.5.4:
|
eslint-plugin-prettier@^5.5.4:
|
||||||
version "5.5.4"
|
version "5.5.4"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz#9d61c4ea11de5af704d4edf108c82ccfa7f2e61c"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz#9d61c4ea11de5af704d4edf108c82ccfa7f2e61c"
|
||||||
@@ -6460,15 +6342,6 @@ get-tsconfig@^4.10.1, get-tsconfig@^4.8.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
resolve-pkg-maps "^1.0.0"
|
resolve-pkg-maps "^1.0.0"
|
||||||
|
|
||||||
get-uri@^6.0.1:
|
|
||||||
version "6.0.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.5.tgz#714892aa4a871db671abc5395e5e9447bc306a16"
|
|
||||||
integrity sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==
|
|
||||||
dependencies:
|
|
||||||
basic-ftp "^5.0.2"
|
|
||||||
data-uri-to-buffer "^6.0.2"
|
|
||||||
debug "^4.3.4"
|
|
||||||
|
|
||||||
getpass@^0.1.1:
|
getpass@^0.1.1:
|
||||||
version "0.1.7"
|
version "0.1.7"
|
||||||
resolved "https://registry.npmmirror.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
|
resolved "https://registry.npmmirror.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
|
||||||
@@ -6859,7 +6732,7 @@ http-proxy-agent@^5.0.0:
|
|||||||
agent-base "6"
|
agent-base "6"
|
||||||
debug "4"
|
debug "4"
|
||||||
|
|
||||||
http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.1:
|
http-proxy-agent@^7.0.0:
|
||||||
version "7.0.2"
|
version "7.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e"
|
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e"
|
||||||
integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==
|
integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==
|
||||||
@@ -6900,7 +6773,7 @@ https-proxy-agent@^5.0.0:
|
|||||||
agent-base "6"
|
agent-base "6"
|
||||||
debug "4"
|
debug "4"
|
||||||
|
|
||||||
https-proxy-agent@^7.0.0, https-proxy-agent@^7.0.6:
|
https-proxy-agent@^7.0.0:
|
||||||
version "7.0.6"
|
version "7.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9"
|
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9"
|
||||||
integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==
|
integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==
|
||||||
@@ -7091,14 +6964,6 @@ inquirer@^6.0.0, inquirer@^6.3.1:
|
|||||||
strip-ansi "^5.1.0"
|
strip-ansi "^5.1.0"
|
||||||
through "^2.3.6"
|
through "^2.3.6"
|
||||||
|
|
||||||
ip-address@^9.0.5:
|
|
||||||
version "9.0.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a"
|
|
||||||
integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==
|
|
||||||
dependencies:
|
|
||||||
jsbn "1.1.0"
|
|
||||||
sprintf-js "^1.1.3"
|
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
||||||
@@ -7372,11 +7237,6 @@ js-yaml@^4.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
argparse "^2.0.1"
|
argparse "^2.0.1"
|
||||||
|
|
||||||
jsbn@1.1.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040"
|
|
||||||
integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==
|
|
||||||
|
|
||||||
jsbn@~0.1.0:
|
jsbn@~0.1.0:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.npmmirror.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
resolved "https://registry.npmmirror.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||||
@@ -7706,7 +7566,7 @@ lru-cache@^6.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
yallist "^4.0.0"
|
yallist "^4.0.0"
|
||||||
|
|
||||||
lru-cache@^7.14.1, lru-cache@^7.7.1:
|
lru-cache@^7.7.1:
|
||||||
version "7.18.3"
|
version "7.18.3"
|
||||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89"
|
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89"
|
||||||
integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
|
integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
|
||||||
@@ -8243,11 +8103,6 @@ nested-property@^4.0.0:
|
|||||||
resolved "https://registry.npmjs.org/nested-property/-/nested-property-4.0.0.tgz#a67b5a31991e701e03cdbaa6453bc5b1011bb88d"
|
resolved "https://registry.npmjs.org/nested-property/-/nested-property-4.0.0.tgz#a67b5a31991e701e03cdbaa6453bc5b1011bb88d"
|
||||||
integrity sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA==
|
integrity sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA==
|
||||||
|
|
||||||
netmask@^2.0.2:
|
|
||||||
version "2.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7"
|
|
||||||
integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==
|
|
||||||
|
|
||||||
node-abi@^3.45.0:
|
node-abi@^3.45.0:
|
||||||
version "3.75.0"
|
version "3.75.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.75.0.tgz#2f929a91a90a0d02b325c43731314802357ed764"
|
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.75.0.tgz#2f929a91a90a0d02b325c43731314802357ed764"
|
||||||
@@ -8587,28 +8442,6 @@ p-try@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
|
resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
|
||||||
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
|
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
|
||||||
|
|
||||||
pac-proxy-agent@^7.1.0:
|
|
||||||
version "7.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz#9cfaf33ff25da36f6147a20844230ec92c06e5df"
|
|
||||||
integrity sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==
|
|
||||||
dependencies:
|
|
||||||
"@tootallnate/quickjs-emscripten" "^0.23.0"
|
|
||||||
agent-base "^7.1.2"
|
|
||||||
debug "^4.3.4"
|
|
||||||
get-uri "^6.0.1"
|
|
||||||
http-proxy-agent "^7.0.0"
|
|
||||||
https-proxy-agent "^7.0.6"
|
|
||||||
pac-resolver "^7.0.1"
|
|
||||||
socks-proxy-agent "^8.0.5"
|
|
||||||
|
|
||||||
pac-resolver@^7.0.1:
|
|
||||||
version "7.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-7.0.1.tgz#54675558ea368b64d210fd9c92a640b5f3b8abb6"
|
|
||||||
integrity sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==
|
|
||||||
dependencies:
|
|
||||||
degenerator "^5.0.0"
|
|
||||||
netmask "^2.0.2"
|
|
||||||
|
|
||||||
package-json-from-dist@^1.0.0:
|
package-json-from-dist@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505"
|
resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505"
|
||||||
@@ -8935,20 +8768,6 @@ promise-retry@^2.0.1:
|
|||||||
err-code "^2.0.2"
|
err-code "^2.0.2"
|
||||||
retry "^0.12.0"
|
retry "^0.12.0"
|
||||||
|
|
||||||
proxy-agent@^6.5.0:
|
|
||||||
version "6.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.5.0.tgz#9e49acba8e4ee234aacb539f89ed9c23d02f232d"
|
|
||||||
integrity sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==
|
|
||||||
dependencies:
|
|
||||||
agent-base "^7.1.2"
|
|
||||||
debug "^4.3.4"
|
|
||||||
http-proxy-agent "^7.0.1"
|
|
||||||
https-proxy-agent "^7.0.6"
|
|
||||||
lru-cache "^7.14.1"
|
|
||||||
pac-proxy-agent "^7.1.0"
|
|
||||||
proxy-from-env "^1.1.0"
|
|
||||||
socks-proxy-agent "^8.0.5"
|
|
||||||
|
|
||||||
proxy-from-env@^1.1.0:
|
proxy-from-env@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||||
@@ -9013,11 +8832,6 @@ qs@~6.5.2:
|
|||||||
resolved "https://registry.npmmirror.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
|
resolved "https://registry.npmmirror.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
|
||||||
integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==
|
integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==
|
||||||
|
|
||||||
querystring@^0.2.1:
|
|
||||||
version "0.2.1"
|
|
||||||
resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd"
|
|
||||||
integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==
|
|
||||||
|
|
||||||
querystringify@^2.1.1:
|
querystringify@^2.1.1:
|
||||||
version "2.2.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
|
resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
|
||||||
@@ -9603,15 +9417,6 @@ socks-proxy-agent@^7.0.0:
|
|||||||
debug "^4.3.3"
|
debug "^4.3.3"
|
||||||
socks "^2.6.2"
|
socks "^2.6.2"
|
||||||
|
|
||||||
socks-proxy-agent@^8.0.5:
|
|
||||||
version "8.0.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz#b9cdb4e7e998509d7659d689ce7697ac21645bee"
|
|
||||||
integrity sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==
|
|
||||||
dependencies:
|
|
||||||
agent-base "^7.1.2"
|
|
||||||
debug "^4.3.4"
|
|
||||||
socks "^2.8.3"
|
|
||||||
|
|
||||||
socks@^2.6.2:
|
socks@^2.6.2:
|
||||||
version "2.7.1"
|
version "2.7.1"
|
||||||
resolved "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55"
|
resolved "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55"
|
||||||
@@ -9620,14 +9425,6 @@ socks@^2.6.2:
|
|||||||
ip "^2.0.0"
|
ip "^2.0.0"
|
||||||
smart-buffer "^4.2.0"
|
smart-buffer "^4.2.0"
|
||||||
|
|
||||||
socks@^2.8.3:
|
|
||||||
version "2.8.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.6.tgz#e335486a2552f34f932f0c27d8dbb93f2be867aa"
|
|
||||||
integrity sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA==
|
|
||||||
dependencies:
|
|
||||||
ip-address "^9.0.5"
|
|
||||||
smart-buffer "^4.2.0"
|
|
||||||
|
|
||||||
source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.1:
|
source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
|
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
|
||||||
@@ -9692,11 +9489,6 @@ sprintf-js@^1.1.2:
|
|||||||
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673"
|
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673"
|
||||||
integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==
|
integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==
|
||||||
|
|
||||||
sprintf-js@^1.1.3:
|
|
||||||
version "1.1.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a"
|
|
||||||
integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==
|
|
||||||
|
|
||||||
ssh2-no-cpu-features@^2.0.0:
|
ssh2-no-cpu-features@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/ssh2-no-cpu-features/-/ssh2-no-cpu-features-2.0.0.tgz#5ae1358979e57e7c72c4c1c71b826908496d4a60"
|
resolved "https://registry.yarnpkg.com/ssh2-no-cpu-features/-/ssh2-no-cpu-features-2.0.0.tgz#5ae1358979e57e7c72c4c1c71b826908496d4a60"
|
||||||
@@ -10222,11 +10014,6 @@ tslib@^1.9.0:
|
|||||||
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||||
|
|
||||||
tslib@^2.0.1, tslib@^2.6.2:
|
|
||||||
version "2.6.2"
|
|
||||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
|
|
||||||
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
|
|
||||||
|
|
||||||
tslib@^2.1.0, tslib@^2.3.1:
|
tslib@^2.1.0, tslib@^2.3.1:
|
||||||
version "2.3.1"
|
version "2.3.1"
|
||||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
|
resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
|
||||||
@@ -10242,6 +10029,11 @@ tslib@^2.5.0:
|
|||||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410"
|
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410"
|
||||||
integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==
|
integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==
|
||||||
|
|
||||||
|
tslib@^2.6.2:
|
||||||
|
version "2.6.2"
|
||||||
|
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
|
||||||
|
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
|
||||||
|
|
||||||
tunnel-agent@^0.6.0:
|
tunnel-agent@^0.6.0:
|
||||||
version "0.6.0"
|
version "0.6.0"
|
||||||
resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||||
@@ -10251,7 +10043,7 @@ tunnel-agent@^0.6.0:
|
|||||||
|
|
||||||
tunnel@^0.0.6:
|
tunnel@^0.0.6:
|
||||||
version "0.0.6"
|
version "0.0.6"
|
||||||
resolved "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
|
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
|
||||||
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
|
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
|
||||||
|
|
||||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||||
@@ -10294,16 +10086,6 @@ typedarray@^0.0.6:
|
|||||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||||
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
|
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
|
||||||
|
|
||||||
typescript-eslint@^8.35.1:
|
|
||||||
version "8.38.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.38.0.tgz#e73af7618139f07b16e2fae715eedaabb41ee8b0"
|
|
||||||
integrity sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/eslint-plugin" "8.38.0"
|
|
||||||
"@typescript-eslint/parser" "8.38.0"
|
|
||||||
"@typescript-eslint/typescript-estree" "8.38.0"
|
|
||||||
"@typescript-eslint/utils" "8.38.0"
|
|
||||||
|
|
||||||
typescript-eslint@^8.39.1:
|
typescript-eslint@^8.39.1:
|
||||||
version "8.39.1"
|
version "8.39.1"
|
||||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.39.1.tgz#13075a676522041cbe421d98fb504ef535a6e4b3"
|
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.39.1.tgz#13075a676522041cbe421d98fb504ef535a6e4b3"
|
||||||
|
|||||||
Reference in New Issue
Block a user