Feature(custom): support upload multiple urls

This commit is contained in:
Kuingsmile
2025-08-29 13:36:00 +08:00
parent 7df95c8328
commit e76b84b7a2
7 changed files with 109 additions and 14 deletions

View File

@@ -1,6 +1,6 @@
<template>
<Teleport to="body">
<div v-if="showInputBoxVisible" class="inputbox-overlay" @click="handleInputBoxCancel">
<div v-if="showInputBoxVisible" class="inputbox-overlay">
<div class="inputbox-container" @click.stop>
<div class="inputbox-header">
<h3 class="inputbox-title">
@@ -11,7 +11,17 @@
</button>
</div>
<div class="inputbox-content">
<textarea
v-if="inputBoxOptions.multiLine"
v-model="inputBoxValue"
:placeholder="inputBoxOptions.placeholder"
class="inputbox-textarea"
rows="4"
@keyup.ctrl.enter="handleInputBoxConfirm"
@keyup.escape="handleInputBoxCancel"
/>
<input
v-else
v-model="inputBoxValue"
:placeholder="inputBoxOptions.placeholder"
class="inputbox-input"
@@ -47,7 +57,8 @@ const inputBoxValue = ref('')
const showInputBoxVisible = ref(false)
const inputBoxOptions = reactive({
title: '',
placeholder: ''
placeholder: '',
multiLine: false
})
let removeInputBoxListenerCallback: () => void = () => {}
@@ -60,6 +71,7 @@ function initInputBoxValue(options: IShowInputBoxOption) {
inputBoxValue.value = options.value || ''
inputBoxOptions.title = options.title || ''
inputBoxOptions.placeholder = options.placeholder || ''
inputBoxOptions.multiLine = options.multiLine || false
showInputBoxVisible.value = true
}
@@ -200,6 +212,30 @@ export default {
color: rgb(156 163 175);
}
.inputbox-textarea {
width: 100%;
border: 1px solid rgb(209 213 219);
border-radius: 0.375rem;
padding: 0.5rem 0.75rem;
background: white;
color: rgb(17 24 39);
font-size: 0.875rem;
font-family: inherit;
transition: all 0.2s ease;
outline: none;
resize: vertical;
min-height: 4rem;
}
.inputbox-textarea:focus {
border-color: rgb(59 130 246);
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.inputbox-textarea::placeholder {
color: rgb(156 163 175);
}
:root.dark .inputbox-input,
:root.auto.dark .inputbox-input {
background: rgb(55 65 81);
@@ -218,6 +254,24 @@ export default {
color: rgb(107 114 128);
}
:root.dark .inputbox-textarea,
:root.auto.dark .inputbox-textarea {
background: rgb(55 65 81);
border-color: rgb(75 85 99);
color: rgb(243 244 246);
}
:root.dark .inputbox-textarea:focus,
:root.auto.dark .inputbox-textarea:focus {
border-color: rgb(59 130 246);
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
:root.dark .inputbox-textarea::placeholder,
:root.auto.dark .inputbox-textarea::placeholder {
color: rgb(107 114 128);
}
.inputbox-actions {
display: flex;
gap: 0.75rem;

View File

@@ -51,9 +51,12 @@
"clipboardPicture": "Clipboard",
"clickToUpload": "Click to Upload",
"urlUpload": "URL Upload",
"inputUrlTip": "Please enter URL",
"inputUrlTip": "Please enter URL(s)",
"httpPrefixTip": "Starts with http:// or https://",
"multipleUrlsHint": "Each URL on a separate line for multiple uploads",
"inputValidUrl": "Please enter a valid URL",
"invalidUrlsFound": "Invalid URLs found: {urls}",
"uploadingMultipleUrls": "Uploading {count} URLs...",
"linkFormat": "Link Format",
"outputFormat": "Output Format",
"urlType": { "title": "Link Type", "normal": "Long Link", "short": "Short Link" }

View File

@@ -51,9 +51,12 @@
"clipboardPicture": "剪贴板图片",
"clickToUpload": "点击上传",
"urlUpload": "URL上传",
"inputUrlTip": "请输入URL",
"inputUrlTip": "请输入URL地址",
"httpPrefixTip": "http://或https://开头",
"multipleUrlsHint": "多个URL请分行输入",
"inputValidUrl": "请输入合法的URL",
"invalidUrlsFound": "发现无效的URL: {urls}",
"uploadingMultipleUrls": "正在上传 {count} 个URL...",
"linkFormat": "链接格式",
"outputFormat": "输出格式",
"urlType": { "title": "链接类型", "normal": "长链接", "short": "短链接" }

View File

@@ -51,9 +51,12 @@
"clipboardPicture": "剪貼板圖片",
"clickToUpload": "點擊上傳",
"urlUpload": "URL上傳",
"inputUrlTip": "請輸入URL",
"inputUrlTip": "請輸入URL地址",
"httpPrefixTip": "以http://或https://開頭",
"multipleUrlsHint": "多個URL請分行輸入",
"inputValidUrl": "請輸入合法的URL",
"invalidUrlsFound": "發現無效的URL: {urls}",
"uploadingMultipleUrls": "正在上傳 {count} 個URL...",
"linkFormat": "連結格式",
"outputFormat": "輸出格式",
"urlType": { "title": "連結類型", "normal": "長連結", "short": "短連結" }

View File

@@ -354,20 +354,50 @@ async function uploadURLFiles() {
$bus.emit(SHOW_INPUT_BOX, {
value: isUrl(str) ? str : '',
title: t('pages.upload.inputUrlTip'),
placeholder: t('pages.upload.httpPrefixTip')
placeholder: t('pages.upload.httpPrefixTip') + '\n' + t('pages.upload.multipleUrlsHint'),
multiLine: true
})
}
function handleInputBoxValue(val: string) {
if (val === '') return
if (isUrl(val)) {
window.electron.sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [
{
path: val
}
])
const urls = val
.split('\n')
.map(url => url.trim())
.filter(url => url !== '')
if (urls.length === 0) return
const invalidUrls: string[] = []
const validUrls: string[] = []
urls.forEach(url => {
if (isUrl(url)) {
validUrls.push(url)
} else {
message.error(t('pages.upload.inputValidUrl'))
invalidUrls.push(url)
}
})
if (invalidUrls.length > 0) {
const errorMessage =
invalidUrls.length === 1
? t('pages.upload.inputValidUrl') + ': ' + invalidUrls[0]
: t('pages.upload.invalidUrlsFound', {
count: invalidUrls.length,
urls: invalidUrls.slice(0, 3).join(', ') + (invalidUrls.length > 3 ? '...' : '')
})
message.error(errorMessage)
}
if (validUrls.length > 0) {
const filesToUpload = validUrls.map(url => ({ path: url }))
window.electron.sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, filesToUpload)
if (validUrls.length > 1) {
message.success(t('pages.upload.uploadingMultipleUrls', { count: validUrls.length }))
}
}
}

View File

@@ -9,6 +9,7 @@ type IEvent = {
value: string
title: string
placeholder: string
multiLine?: boolean
}
}

View File

@@ -260,6 +260,7 @@ export interface IShowInputBoxOption {
value?: string
title: string
placeholder: string
multiLine?: boolean
}
export type IShowFileExplorerOption = IObj