@@ -311,7 +329,7 @@ function UploadResult({ image }: { image: Image }) {
})}
-
+
)
@@ -326,3 +344,8 @@ function isSupportedImageFile(file: File) {
if (['image/jpeg', 'image/png', 'image/webp', 'image/gif'].includes(file.type)) return true
return file.type === '' && /\.(?:jpe?g|png|webp|gif)$/i.test(file.name)
}
+
+function storedVisibility(): Visibility | 'default' {
+ const value = readLocalStorage(visibilityStorageKey)
+ return value === 'public' || value === 'private' ? value : 'default'
+}
diff --git a/web/src/i18n/en-US.json b/web/src/i18n/en-US.json
index 0ac4ea7..6b2dbd0 100644
--- a/web/src/i18n/en-US.json
+++ b/web/src/i18n/en-US.json
@@ -90,6 +90,9 @@
"visibility": "Visibility",
"visibilityDefault": "Use system default",
"uploadCount": "Upload {{count}} files",
+ "copyCompleted": "Copy all successful links",
+ "copyCompletedFormat": "Copy {{format}} for {{count}} successful images",
+ "completedLinks": "{{count}} images uploaded successfully. Copy all links at once.",
"empty": "No files are queued.",
"progress": "Upload progress {{percent}}%",
"result": "{{format}} · {{before}} → {{after}} · saved {{percent}}%",
@@ -165,6 +168,8 @@
"copyLinksHelp": "The main button copies the current format; use the menu to switch between direct, Markdown, BBCode, and HTML.",
"readyLink": "Link ready",
"copySelectedFormat": "Copy {{format}}",
+ "copySelectedLinks": "Copy links",
+ "copySelectedLinksFormat": "Copy {{format}} for {{count}} selected images",
"chooseLinkFormat": "Choose link format",
"linkFormat": {
"direct": "Copy direct link",
@@ -188,6 +193,10 @@
"uploadedAt": "Uploaded at",
"processing": "Processing summary",
"aliases": "Historical paths",
+ "aliasPath": "New historical path",
+ "addAlias": "Add historical path",
+ "aliasSaving": "Adding…",
+ "aliasCreateFailed": "Unable to add the historical path. Check its format or conflicts.",
"noAliases": "This image has no historical path aliases."
},
"visibility": {
@@ -339,6 +348,7 @@
},
"toast": {
"linkCopied": "Copied {{format}}",
+ "linksCopied": "Copied {{format}} for {{count}} images",
"linkCopiedSimple": "Link copied",
"copyFailed": "Copy failed. Check browser clipboard permission.",
"operationFailed": "The operation failed. Try again.",
diff --git a/web/src/i18n/zh-CN.json b/web/src/i18n/zh-CN.json
index 7a766dc..c15b982 100644
--- a/web/src/i18n/zh-CN.json
+++ b/web/src/i18n/zh-CN.json
@@ -90,6 +90,9 @@
"visibility": "可见性",
"visibilityDefault": "使用系统默认值",
"uploadCount": "上传 {{count}} 个文件",
+ "copyCompleted": "复制全部成功链接",
+ "copyCompletedFormat": "复制 {{count}} 张成功图片的{{format}}",
+ "completedLinks": "{{count}} 张图片已上传成功,可一次复制全部链接。",
"empty": "还没有待上传文件。",
"progress": "上传进度 {{percent}}%",
"result": "{{format}} · {{before}} → {{after}} · 节省 {{percent}}%",
@@ -165,6 +168,8 @@
"copyLinksHelp": "主按钮复制当前格式,右侧菜单可切换直链、Markdown、BBCode 或 HTML。",
"readyLink": "链接已就绪",
"copySelectedFormat": "复制{{format}}",
+ "copySelectedLinks": "复制链接",
+ "copySelectedLinksFormat": "复制选中 {{count}} 张图片的{{format}}",
"chooseLinkFormat": "选择链接格式",
"linkFormat": {
"direct": "复制直链",
@@ -188,6 +193,10 @@
"uploadedAt": "上传时间",
"processing": "处理摘要",
"aliases": "历史路径",
+ "aliasPath": "新历史路径",
+ "addAlias": "添加历史路径",
+ "aliasSaving": "正在添加…",
+ "aliasCreateFailed": "历史路径添加失败,请检查路径格式或冲突。",
"noAliases": "这张图片没有历史路径映射。"
},
"visibility": {
@@ -339,6 +348,7 @@
},
"toast": {
"linkCopied": "已复制{{format}}",
+ "linksCopied": "已复制 {{count}} 张图片的{{format}}",
"linkCopiedSimple": "链接已复制",
"copyFailed": "复制失败,请检查浏览器剪贴板权限。",
"operationFailed": "操作失败,请重试。",
diff --git a/web/src/lib/image-links.ts b/web/src/lib/image-links.ts
index 7632599..6d382b5 100644
--- a/web/src/lib/image-links.ts
+++ b/web/src/lib/image-links.ts
@@ -16,6 +16,10 @@ export function imageLinks(image: LinkableImage): Record
{
}
}
+export function imageLinksText(images: readonly LinkableImage[], format: LinkFormat) {
+ return images.map((image) => imageLinks(image)[format]).join('\n')
+}
+
export async function copyText(value: string) {
await navigator.clipboard.writeText(value)
}
diff --git a/web/src/styles/globals.css b/web/src/styles/globals.css
index 2281c94..2f61543 100644
--- a/web/src/styles/globals.css
+++ b/web/src/styles/globals.css
@@ -2432,6 +2432,11 @@ input[type="checkbox"]:disabled {
height: 9px;
}
+.floating-batch-actions .copy-link-control[data-compact],
+.floating-batch-actions .copy-link-control[data-compact] .copy-link-caret {
+ height: 36px;
+}
+
.copy-link-main {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
@@ -2489,6 +2494,11 @@ input[type="checkbox"]:disabled {
bottom: calc(100% + 8px);
}
+.floating-batch-actions .copy-format-menu {
+ top: auto;
+ bottom: calc(100% + 20px);
+}
+
@keyframes ui-menu-in {
from { opacity: 0; transform: translateY(-4px) scale(0.98); }
to { opacity: 1; transform: translateY(0) scale(1); }
@@ -3036,7 +3046,7 @@ input[type="checkbox"]:disabled {
.floating-batch-actions {
min-width: 0;
- overflow-x: auto;
+ overflow: visible;
}
.floating-batch-actions [data-slot="button"] span {