From 96895c9786474a624265c806aba1c8a1d3c84d7c Mon Sep 17 00:00:00 2001 From: maruson08 Date: Thu, 20 Aug 2026 21:05:43 +0900 Subject: [PATCH 1/7] =?UTF-8?q?=E2=99=BB=EF=B8=8F[Refactor]=20Consolidate?= =?UTF-8?q?=20shared=20tool=20interaction=20styles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/file-input-queue-state.test.mjs | 5 ++- tests/pdf-to-images.test.mjs | 2 +- tools/pdf/images-to-pdf/index.html | 2 +- tools/pdf/merge/index.html | 2 +- tools/pdf/metadata/index.html | 2 +- tools/pdf/organize/index.html | 2 +- tools/pdf/split/index.html | 2 +- tools/pdf/split/tool.css | 26 --------------- tools/pdf/to-images/index.html | 2 +- tools/pdf/to-images/tool.css | 5 --- tools/{pdf/images-to-pdf => shared}/tool.css | 35 +++++++++++++++++--- 11 files changed, 39 insertions(+), 46 deletions(-) rename tools/{pdf/images-to-pdf => shared}/tool.css (71%) diff --git a/tests/file-input-queue-state.test.mjs b/tests/file-input-queue-state.test.mjs index 0be02ed..fb5a273 100644 --- a/tests/file-input-queue-state.test.mjs +++ b/tests/file-input-queue-state.test.mjs @@ -68,13 +68,12 @@ for (const tool of tools) { testStateContract(tool); } -const sharedCss = read("tools/pdf/images-to-pdf/tool.css"); +const sharedCss = read("tools/shared/tool.css"); assert.match(sharedCss, /\.drop-zone__picker\s*\{[^}]*position:\s*absolute;[^}]*inset:\s*0;/s, "Picker label does not cover the complete drop zone"); assert.match(sharedCss, /\.drop-zone:has\(#file-input:focus-visible\)\s*\{[^}]*outline:/s, "Keyboard focus is not visible on the drop zone"); assert.match(sharedCss, /\.local-note a\s*\{[^}]*z-index:\s*2;/s, "Privacy link is not isolated from picker activation"); assert.match(sharedCss, /\.queue-empty\[hidden\]\s*\{\s*display:\s*none;/, "Queue hidden state can be overridden by authored display styles"); -const splitCss = read("tools/pdf/split/tool.css"); -assert.match(splitCss, /\.source-empty\[hidden\]\s*\{\s*display:\s*none;/, "Split source hidden state can be overridden by authored display styles"); +assert.match(sharedCss, /\.source-empty\[hidden\][^{]*\{\s*display:\s*none;/, "Source hidden state can be overridden by authored display styles"); console.log("File input and queue state regression checks passed."); diff --git a/tests/pdf-to-images.test.mjs b/tests/pdf-to-images.test.mjs index 5d3d560..52a785f 100644 --- a/tests/pdf-to-images.test.mjs +++ b/tests/pdf-to-images.test.mjs @@ -95,7 +95,7 @@ function testArchitectureAndUi() { const sharedRenderer = read("tools/shared/pdf-renderer.js"); const app = read("tools/pdf/to-images/app.js"); const html = read("tools/pdf/to-images/index.html"); - const css = read("tools/pdf/to-images/tool.css"); + const css = `${read("tools/shared/tool.css")}\n${read("tools/pdf/to-images/tool.css")}`; assert.match(converter, /canvas\.toBlob\(/); assert.doesNotMatch(converter, /toDataURL|base64/i); assert.match(converter, /canvas\.width = 1;[\s\S]*canvas\.height = 1/); diff --git a/tools/pdf/images-to-pdf/index.html b/tools/pdf/images-to-pdf/index.html index 8f3dd18..5eace56 100644 --- a/tools/pdf/images-to-pdf/index.html +++ b/tools/pdf/images-to-pdf/index.html @@ -15,7 +15,7 @@ - + diff --git a/tools/pdf/merge/index.html b/tools/pdf/merge/index.html index 2f66cf5..265a041 100644 --- a/tools/pdf/merge/index.html +++ b/tools/pdf/merge/index.html @@ -2,7 +2,7 @@ Merge PDF — Secure Tools - + diff --git a/tools/pdf/metadata/index.html b/tools/pdf/metadata/index.html index 36b67df..a81b3ad 100644 --- a/tools/pdf/metadata/index.html +++ b/tools/pdf/metadata/index.html @@ -2,7 +2,7 @@ PDF Metadata Inspector & Cleaner — Secure Tools - + diff --git a/tools/pdf/organize/index.html b/tools/pdf/organize/index.html index 929835a..becde27 100644 --- a/tools/pdf/organize/index.html +++ b/tools/pdf/organize/index.html @@ -2,7 +2,7 @@ Organize PDF — Secure Tools - + diff --git a/tools/pdf/split/index.html b/tools/pdf/split/index.html index 80292cf..c73a97a 100644 --- a/tools/pdf/split/index.html +++ b/tools/pdf/split/index.html @@ -2,7 +2,7 @@ Split PDF — Secure Tools - + diff --git a/tools/pdf/split/tool.css b/tools/pdf/split/tool.css index be78163..ec102c3 100644 --- a/tools/pdf/split/tool.css +++ b/tools/pdf/split/tool.css @@ -1,28 +1,2 @@ -.source-panel { padding: var(--space-5); } -.source-panel__header { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-4); } -.source-panel__header h2 { margin: 0; font-size: 1.35rem; } -.source-empty { display: grid; min-height: 8rem; place-items: center; margin: 0; padding: var(--space-5); border: 1px dashed var(--border); border-radius: var(--radius-md); color: var(--text-secondary); text-align: center; } -.source-empty[hidden] { display: none; } -.source-card { display: grid; grid-template-columns: 4.5rem minmax(0, 1fr) auto; align-items: center; gap: var(--space-3); padding: var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-primary); } -.source-card[hidden] { display: none; } -.pdf-file-icon { display: grid; width: 4.5rem; height: 4.5rem; place-items: center; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--accent-soft); color: var(--accent); font-size: 0.72rem; font-weight: 800; letter-spacing: 0.08em; } -.source-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .split-modes { padding: var(--space-5); } .split-modes > h2 { margin-bottom: var(--space-4); font-size: 1.35rem; } -.mode-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-3); margin: 0 0 var(--space-5); padding: 0; border: 0; } -.mode-option { display: flex; min-width: 0; gap: var(--space-3); padding: var(--space-4); border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-primary); cursor: pointer; } -.mode-option:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); } -.mode-option input { flex: 0 0 auto; margin-top: 0.2rem; accent-color: var(--accent); } -.mode-option strong, .mode-option span { display: block; } -.mode-option span { margin-top: var(--space-1); color: var(--text-secondary); font-size: 0.78rem; line-height: 1.4; } -.mode-panel { max-width: 38rem; } -.mode-panel[hidden] { display: none; } -.field-error { min-height: 1.25rem; margin: var(--space-2) 0 0; color: var(--tool-danger); font-size: 0.78rem; } -.field input[aria-invalid="true"] { border-color: var(--tool-danger); } -@media (max-width: 48rem) { .mode-list { grid-template-columns: 1fr; } } -@media (max-width: 38rem) { - .source-card { grid-template-columns: 3.75rem minmax(0, 1fr); } - .pdf-file-icon { width: 3.75rem; height: 3.75rem; } - .source-card .queue-action { grid-column: 1 / -1; width: 100%; } - .source-name { white-space: normal; overflow-wrap: anywhere; } -} diff --git a/tools/pdf/to-images/index.html b/tools/pdf/to-images/index.html index 80c03dc..94a4d08 100644 --- a/tools/pdf/to-images/index.html +++ b/tools/pdf/to-images/index.html @@ -2,7 +2,7 @@ PDF to Images — Secure Tools - + diff --git a/tools/pdf/to-images/tool.css b/tools/pdf/to-images/tool.css index 30c093c..e7acdd9 100644 --- a/tools/pdf/to-images/tool.css +++ b/tools/pdf/to-images/tool.css @@ -1,13 +1,8 @@ .conversion-options { padding: var(--space-5); } .conversion-options > h2 { margin-bottom: var(--space-4); font-size: 1.35rem; } .conversion-options .mode-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } -.settings select { width: 100%; min-height: 2.75rem; padding: .65rem .75rem; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-primary); color: var(--text-primary); } .settings input[type="range"] { width: 100%; accent-color: var(--accent); } .settings output { color: var(--text-secondary); font-variant-numeric: tabular-nums; } #quality-field[hidden], #range-panel[hidden], #cancel-conversion[hidden], #conversion-progress[hidden] { display: none; } -.tool-actions { display: grid; gap: var(--space-2); } -.tool-status[data-tone="error"] { color: var(--tool-danger); } -.tool-status[data-tone="success"] { color: var(--tool-success); } -@media (prefers-reduced-motion: reduce) { .mode-option { transition: none; } } @media (max-width: 48rem) { .conversion-options .mode-list { grid-template-columns: 1fr; } } @media (max-width: 38rem) { .conversion-options, .settings { padding: var(--space-4); } .tool-actions .button { width: 100%; } } diff --git a/tools/pdf/images-to-pdf/tool.css b/tools/shared/tool.css similarity index 71% rename from tools/pdf/images-to-pdf/tool.css rename to tools/shared/tool.css index 5766233..cb3f4e7 100644 --- a/tools/pdf/images-to-pdf/tool.css +++ b/tools/shared/tool.css @@ -1,5 +1,5 @@ -:root { --tool-danger: #b42318; --tool-danger-soft: #fce8e6; } -:root[data-resolved-theme="dark"] { --tool-danger: #ff9187; --tool-danger-soft: #3b211f; } +:root { --tool-danger: #b42318; --tool-danger-soft: #fce8e6; --tool-warning: #8a5700; --tool-success: var(--accent); } +:root[data-resolved-theme="dark"] { --tool-danger: #ff9187; --tool-danger-soft: #3b211f; --tool-warning: #f2bd63; } .tool-main { padding-block: var(--space-7) var(--space-8); } .tool-intro { position: relative; max-width: 52rem; margin-bottom: var(--space-7); padding-left: var(--space-5); border-left: 2px solid var(--accent); } @@ -24,6 +24,16 @@ .local-note strong { color: var(--accent); } .local-note a { position: relative; z-index: 2; color: var(--text-primary); font-weight: 700; } +.source-panel { padding: var(--space-5); } +.source-panel__header { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-4); } +.source-panel__header h2 { margin: 0; font-size: 1.35rem; } +.source-empty { display: grid; min-height: 8rem; place-items: center; margin: 0; padding: var(--space-5); border: 1px dashed var(--border); border-radius: var(--radius-md); color: var(--text-secondary); text-align: center; } +.source-empty[hidden], .source-card[hidden], .source-summary[hidden] { display: none; } +.source-card { display: grid; grid-template-columns: 4.5rem minmax(0, 1fr) auto; align-items: center; gap: var(--space-3); padding: var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-primary); } +.pdf-file-icon { display: grid; width: 4.5rem; height: 4.5rem; place-items: center; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--accent-soft); color: var(--accent); font-size: 0.72rem; font-weight: 800; letter-spacing: 0.08em; } +.source-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.source-summary { margin: 0; color: var(--text-secondary); } + .queue { min-width: 0; padding: var(--space-5); } .queue-header { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-4); } .queue-header h2 { margin: 0; font-size: 1.35rem; } @@ -50,6 +60,16 @@ .field input, .field select { width: 100%; min-height: 2.75rem; padding: 0.55rem 0.7rem; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-primary); color: var(--text-primary); transition: border-color var(--transition-fast), background-color var(--transition-theme); } .field input:hover, .field select:hover { border-color: var(--border-strong); } .field-help { margin: 0; color: var(--text-secondary); font-size: 0.72rem; } +.field-error { min-height: 1.25rem; margin: var(--space-2) 0 0; color: var(--tool-danger); font-size: 0.78rem; } +.field input[aria-invalid="true"] { border-color: var(--tool-danger); } +.mode-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-3); margin: 0 0 var(--space-5); padding: 0; border: 0; } +.mode-option { display: flex; min-width: 0; gap: var(--space-3); padding: var(--space-4); border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-primary); cursor: pointer; } +.mode-option:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); } +.mode-option input { flex: 0 0 auto; margin-top: 0.2rem; accent-color: var(--accent); } +.mode-option strong, .mode-option span { display: block; } +.mode-option span { margin-top: var(--space-1); color: var(--text-secondary); font-size: 0.78rem; line-height: 1.4; } +.mode-panel { max-width: 38rem; } +.mode-panel[hidden] { display: none; } .check-field { display: flex; gap: var(--space-2); align-items: flex-start; margin-bottom: var(--space-3); font-size: 0.82rem; line-height: 1.45; } .check-field input { width: 1rem; height: 1rem; flex: 0 0 auto; margin-top: 0.2rem; accent-color: var(--accent); } .tool-actions { display: grid; gap: var(--space-2); margin-top: var(--space-5); padding-top: var(--space-5); border-top: 1px solid var(--border); } @@ -58,10 +78,11 @@ .generation-progress { width: 100%; height: 0.55rem; margin-top: var(--space-4); accent-color: var(--accent); } .tool-status { min-height: 3rem; margin: var(--space-3) 0 0; color: var(--text-secondary); font-size: 0.82rem; line-height: 1.5; } .tool-status[data-tone="error"] { color: var(--tool-danger); } -.tool-status[data-tone="warning"] { color: #8a5700; } -:root[data-resolved-theme="dark"] .tool-status[data-tone="warning"] { color: #f2bd63; } -.tool-status[data-tone="success"] { color: var(--accent); } +.tool-status[data-tone="warning"] { color: var(--tool-warning); } +.tool-status[data-tone="success"] { color: var(--tool-success); } +@media (prefers-reduced-motion: reduce) { .mode-option { transition: none; } } +@media (max-width: 48rem) { .mode-list { grid-template-columns: 1fr; } } @media (max-width: 60rem) { .tool-layout { grid-template-columns: 1fr; } .settings { position: static; } @@ -76,6 +97,10 @@ .settings h2, .check-field, .tool-actions, .generation-progress, .tool-status { grid-column: auto; } .queue-item { grid-template-columns: 3.75rem minmax(0, 1fr); } .queue-thumbnail { width: 3.75rem; height: 3.75rem; } + .source-card { grid-template-columns: 3.75rem minmax(0, 1fr); } + .pdf-file-icon { width: 3.75rem; height: 3.75rem; } + .source-card .queue-action { grid-column: 1 / -1; width: 100%; } + .source-name { white-space: normal; overflow-wrap: anywhere; } .queue-actions { grid-column: 1 / -1; justify-content: flex-end; padding-top: var(--space-2); border-top: 1px solid var(--border); } .queue-action { width: 2.75rem; height: 2.75rem; } } From d0fe7e3fdf3bb5ea7f7cbb9e4d5d899ce714524b Mon Sep 17 00:00:00 2001 From: maruson08 Date: Thu, 20 Aug 2026 21:09:12 +0900 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=8E=80[Style]=20Standardize=20tool=20?= =?UTF-8?q?input=20and=20queue=20interfaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/locales/de.js | 4 ++-- js/locales/en.js | 4 ++-- js/locales/es.js | 4 ++-- js/locales/fr.js | 4 ++-- js/locales/ja.js | 4 ++-- js/locales/ko.js | 4 ++-- tools/pdf/images-to-pdf/index.html | 6 +++--- tools/pdf/merge/index.html | 2 +- tools/pdf/metadata/index.html | 2 +- tools/shared/tool.css | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/js/locales/de.js b/js/locales/de.js index 4f4b401..4a607d9 100644 --- a/js/locales/de.js +++ b/js/locales/de.js @@ -342,7 +342,7 @@ export const de = { "queue": { "title": "PDF-Bestellung", "count": "PDFs: {count}", - "empty": "Noch keine PDFs ausgewählt. Hinzugefügte Dateien werden von oben nach unten zusammengeführt.", + "empty": "Noch keine PDFs hinzugefügt.", "meta": "{size} · {pages} Seite(n)", "moveUp": "PDF nach oben verschieben", "moveDown": "PDF nach unten verschieben", @@ -401,7 +401,7 @@ export const de = { "queue": { "title": "Bildreihenfolge", "count": "Bilder: {count}", - "empty": "Noch keine Bilder ausgewählt. Hinzugefügte Bilder werden hier in der Reihenfolge der PDF-Seiten angezeigt.", + "empty": "Noch keine Bilder hinzugefügt.", "previewAlt": "Vorschau von {name}", "meta": "{size} · Seite {page}", "moveUp": "Bild nach oben verschieben", diff --git a/js/locales/en.js b/js/locales/en.js index 87bc4f3..175e6d9 100644 --- a/js/locales/en.js +++ b/js/locales/en.js @@ -135,7 +135,7 @@ export const en = { eyebrow: "PDF tool", title: "Merge PDF", description: "Arrange PDF files and combine every page into one document. Files stay on this device.", drop: { title: "Add your PDFs", description: "Drop PDF files here or use the picker. The queue order becomes the document order.", choose: "Choose PDFs", localTitle: "Processed locally.", localBody: "Your PDFs never leave this device.", privacyLink: "How privacy works" }, queue: { - title: "PDF order", count: "PDFs: {count}", empty: "No PDFs selected yet. Added files will be merged from top to bottom.", + title: "PDF order", count: "PDFs: {count}", empty: "No PDFs added yet.", meta: "{size} · {pages} page(s)", moveUp: "Move PDF up", moveDown: "Move PDF down", remove: "Remove PDF", }, settings: { @@ -159,7 +159,7 @@ export const en = { eyebrow: "Image tool", title: "Images to PDF", description: "Arrange JPEG, PNG, and WebP images and save them as one PDF. Everything happens on this device.", drop: { title: "Add your images", description: "Drop files here or use the picker. JPEG, PNG, and WebP can be mixed.", choose: "Choose images", localTitle: "Processed locally.", localBody: "Your images never leave this device.", privacyLink: "How privacy works" }, - queue: { title: "Image order", count: "Images: {count}", empty: "No images selected yet. Added images will appear here in PDF page order.", previewAlt: "Preview of {name}", meta: "{size} · page {page}", moveUp: "Move image up", moveDown: "Move image down", remove: "Remove image" }, + queue: { title: "Image order", count: "Images: {count}", empty: "No images added yet.", previewAlt: "Preview of {name}", meta: "{size} · page {page}", moveUp: "Move image up", moveDown: "Move image down", remove: "Remove image" }, settings: { title: "PDF settings", filename: "Output filename", filenameHelp: "A .pdf extension is added automatically.", pageSize: "Page size", a4: "A4", letter: "Letter", imageSize: "Match image", orientation: "Orientation", auto: "Automatic", portrait: "Portrait", landscape: "Landscape", fit: "Image fit", contain: "Fit entire image", cover: "Fill page", diff --git a/js/locales/es.js b/js/locales/es.js index 75a0cec..15e91fd 100644 --- a/js/locales/es.js +++ b/js/locales/es.js @@ -342,7 +342,7 @@ export const es = { "queue": { "title": "Pedido PDF", "count": "PDF: {count}", - "empty": "Aún no hay archivos PDF seleccionados. Los archivos agregados se fusionarán de arriba a abajo.", + "empty": "Aún no hay archivos PDF.", "meta": "{size} · {pages} página(s)", "moveUp": "Mover PDF hacia arriba", "moveDown": "Mover PDF hacia abajo", @@ -401,7 +401,7 @@ export const es = { "queue": { "title": "Orden de imágenes", "count": "Imágenes: {count}", - "empty": "Aún no hay imágenes seleccionadas. Las imágenes agregadas aparecerán aquí en el orden de las páginas PDF.", + "empty": "Aún no hay imágenes.", "previewAlt": "Vista previa de {name}", "meta": "{size} · página {page}", "moveUp": "Mover imagen hacia arriba", diff --git a/js/locales/fr.js b/js/locales/fr.js index c98d01a..a77d125 100644 --- a/js/locales/fr.js +++ b/js/locales/fr.js @@ -342,7 +342,7 @@ export const fr = { "queue": { "title": "Commande PDF", "count": "PDF : {count}", - "empty": "Aucun PDF sélectionné pour le moment. Les fichiers ajoutés seront fusionnés de haut en bas.", + "empty": "Aucun PDF ajouté.", "meta": "{size} · Pages {pages}", "moveUp": "Déplacer le PDF vers le haut", "moveDown": "Déplacer le PDF vers le bas", @@ -401,7 +401,7 @@ export const fr = { "queue": { "title": "Ordre des images", "count": "Images : {count}", - "empty": "Aucune image sélectionnée pour le moment. Les images ajoutées apparaîtront ici dans l’ordre des pages PDF.", + "empty": "Aucune image ajoutée.", "previewAlt": "Aperçu de {name}", "meta": "{size} · page {page}", "moveUp": "Déplacer l'image vers le haut", diff --git a/js/locales/ja.js b/js/locales/ja.js index 3065ab5..22fe11a 100644 --- a/js/locales/ja.js +++ b/js/locales/ja.js @@ -342,7 +342,7 @@ export const ja = { "queue": { "title": "PDF注文", "count": "PDF: {count}", - "empty": "PDF がまだ選択されていません。追加されたファイルは上から下にマージされます。", + "empty": "PDFはまだ追加されていません。", "meta": "{size} · {pages} ページ", "moveUp": "PDF を上に移動", "moveDown": "PDF を下に移動", @@ -401,7 +401,7 @@ export const ja = { "queue": { "title": "画像順", "count": "画像: {count}", - "empty": "画像がまだ選択されていません。追加された画像は PDF ページ順にここに表示されます。", + "empty": "画像はまだ追加されていません。", "previewAlt": "{name} のプレビュー", "meta": "{size} · ページ {page}", "moveUp": "画像を上に移動", diff --git a/js/locales/ko.js b/js/locales/ko.js index 823e47b..ca4e104 100644 --- a/js/locales/ko.js +++ b/js/locales/ko.js @@ -118,7 +118,7 @@ export const ko = { eyebrow: "PDF 도구", title: "PDF 합치기", description: "PDF 파일의 순서를 정하고 모든 페이지를 하나의 문서로 합치세요. 파일은 이 기기에 머뭅니다.", drop: { title: "PDF 추가", description: "PDF를 여기에 놓거나 파일 선택 버튼을 누르세요. 목록 순서대로 합칩니다.", choose: "PDF 선택", localTitle: "이 기기에서 바로 처리합니다.", localBody: "PDF는 외부로 전송되지 않습니다.", privacyLink: "개인정보 보호 방식" }, queue: { - title: "PDF 순서", count: "PDF: {count}개", empty: "아직 선택한 PDF가 없습니다. 추가한 파일은 위에서 아래 순서로 합쳐집니다.", + title: "PDF 순서", count: "PDF: {count}개", empty: "추가된 PDF가 없습니다.", meta: "{size} · {pages}페이지", moveUp: "PDF를 위로 이동", moveDown: "PDF를 아래로 이동", remove: "PDF 제거", }, settings: { @@ -141,7 +141,7 @@ export const ko = { imageToPdf: { eyebrow: "이미지 도구", title: "이미지를 PDF로", description: "JPEG, PNG, WebP 이미지를 원하는 순서로 정리해 하나의 PDF로 저장하세요. 모든 처리는 이 기기에서 이루어집니다.", drop: { title: "이미지 추가", description: "파일을 여기에 놓거나 파일 선택 버튼을 누르세요. JPEG, PNG, WebP를 함께 추가할 수 있습니다.", choose: "이미지 선택", localTitle: "이 기기에서 바로 처리합니다.", localBody: "이미지는 외부로 전송되지 않습니다.", privacyLink: "개인정보 보호 방식" }, - queue: { title: "이미지 순서", count: "이미지: {count}개", empty: "아직 선택한 이미지가 없습니다. 추가한 순서대로 PDF 페이지가 만들어집니다.", previewAlt: "{name} 미리보기", meta: "{size} · {page}페이지", moveUp: "이미지를 위로 이동", moveDown: "이미지를 아래로 이동", remove: "이미지 제거" }, + queue: { title: "이미지 순서", count: "이미지: {count}개", empty: "추가된 이미지가 없습니다.", previewAlt: "{name} 미리보기", meta: "{size} · {page}페이지", moveUp: "이미지를 위로 이동", moveDown: "이미지를 아래로 이동", remove: "이미지 제거" }, settings: { title: "PDF 설정", filename: "출력 파일명", filenameHelp: ".pdf 확장자는 자동으로 추가됩니다.", pageSize: "페이지 크기", a4: "A4", letter: "Letter", imageSize: "이미지 크기에 맞춤", orientation: "페이지 방향", auto: "자동", portrait: "세로", landscape: "가로", fit: "이미지 맞춤", contain: "전체 이미지 표시", cover: "페이지 채우기", margin: "여백 (mm)", diff --git a/tools/pdf/images-to-pdf/index.html b/tools/pdf/images-to-pdf/index.html index 5eace56..924cc79 100644 --- a/tools/pdf/images-to-pdf/index.html +++ b/tools/pdf/images-to-pdf/index.html @@ -49,7 +49,7 @@

Images to PDF

Add your images

Drop files here or use the picker. JPEG, PNG, and WebP can be mixed.

- +

Processed locally. Your images never leave this device. How privacy works

@@ -57,8 +57,8 @@

Add your images

Image order

0 images
-

No images selected yet. Added images will appear here in PDF page order.

-
    +

    No images added yet.

    +
      diff --git a/tools/pdf/merge/index.html b/tools/pdf/merge/index.html index 265a041..20ca5a4 100644 --- a/tools/pdf/merge/index.html +++ b/tools/pdf/merge/index.html @@ -8,7 +8,7 @@

      PDF tool

      Merge PDF

      Arrange PDF files and combine every page into one document. Files stay on this device.

      Add your PDFs

      Drop PDF files here or use the picker. The queue order becomes the document order.

      Processed locally. Your PDFs never leave this device. How privacy works

      -

      PDF order

      PDFs: 0

      No PDFs selected yet. Added files will be merged from top to bottom.

        +

        PDF order

        PDFs: 0

        No PDFs added yet.

          diff --git a/tools/pdf/metadata/index.html b/tools/pdf/metadata/index.html index a81b3ad..fc0f3c2 100644 --- a/tools/pdf/metadata/index.html +++ b/tools/pdf/metadata/index.html @@ -9,7 +9,7 @@

          PDF privacy tool

          PDF Metadata Inspector & Cleaner

          Review common document metadata and create a cleaned copy without uploading your PDF.

          Add one PDF

          Drop a PDF here or use the picker. Choosing another file replaces the current source.

          Processed locally. Your PDF never leaves this device. How privacy works

          -
          diff --git a/tools/pdf/metadata/tool.css b/tools/pdf/metadata/tool.css index 3a02d4f..d35b6d0 100644 --- a/tools/pdf/metadata/tool.css +++ b/tools/pdf/metadata/tool.css @@ -2,7 +2,6 @@ .metadata-workspace [hidden], .metadata-comparison[hidden] { display: none; } .scope-note, .metadata-workspace, -.metadata-output, .metadata-comparison { margin-top: var(--space-5); padding: var(--space-5); } .scope-note { border-left: .25rem solid var(--accent); } .scope-note h2, @@ -11,18 +10,17 @@ .metadata-toolbar p, .inspector-heading h3, .inspector-heading p, -.metadata-output p, .metadata-comparison h2, .metadata-comparison p { margin: 0; } .scope-note p, .metadata-toolbar p, .inspector-heading p, .metadata-toolbar #source-summary, -.metadata-output p, .metadata-comparison p { color: var(--text-secondary); } .metadata-toolbar, .inspector-heading, .selection-actions { flex-wrap: wrap; justify-content: flex-end; } +.metadata-toolbar, .inspector-heading { display: flex; justify-content: space-between; gap: var(--space-4); } .selection-actions { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); } .inspector-heading { margin-top: var(--space-5); align-items: flex-start; } .metadata-table-wrap { margin-top: var(--space-4); overflow-x: auto; } @@ -36,9 +34,7 @@ .metadata-table tr:has(input:checked) { background: color-mix(in srgb, var(--accent) 8%, transparent); } .metadata-value { display: block; max-width: 48rem; overflow-wrap: anywhere; white-space: pre-wrap; } .truncation-note { display: block; margin-top: var(--space-2); color: var(--text-secondary); font-size: .78rem; } -.metadata-output { display: grid; grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem) auto; align-items: end; gap: var(--space-5); } -.output-scope { margin-top: var(--space-2) !important; font-size: .85rem; } -.metadata-output .field { margin: 0; } +.tool-output .output-scope { margin-top: var(--space-2); font-size: .85rem; } .comparison-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); margin-top: var(--space-4); } .comparison-grid > div { padding: var(--space-4); border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-subtle); } .comparison-grid h3 { margin-top: 0; } @@ -50,12 +46,10 @@ .metadata-table tr { scroll-behavior: auto; transition: none; } } @media (max-width: 54rem) { - .metadata-output { grid-template-columns: 1fr; align-items: stretch; } - .metadata-output .button { width: 100%; } .inspector-heading { flex-direction: column; } } @media (max-width: 38rem) { - .scope-note, .metadata-workspace, .metadata-output, .metadata-comparison { padding: var(--space-4); } + .scope-note, .metadata-workspace, .tool-output, .metadata-comparison { padding: var(--space-4); } .metadata-toolbar { align-items: flex-start; flex-direction: column; } .selection-actions { width: 100%; align-items: stretch; flex-direction: column; } .selection-actions .button, .metadata-toolbar .button { width: 100%; } diff --git a/tools/pdf/organize/index.html b/tools/pdf/organize/index.html index becde27..6a187a4 100644 --- a/tools/pdf/organize/index.html +++ b/tools/pdf/organize/index.html @@ -9,6 +9,6 @@

          PDF tool

          Organize PDF

          Reorder, rotate, or remove pages without changing the original PDF. Everything stays on this device.

          Add one PDF

          Drop a PDF here or use the picker.

          Processed locally. Your PDF never leaves this device. How privacy works

          Page workspace

          No PDF selected yet.

            -

            Export organized PDF

            The original PDF is unchanged. Export copies its pages in the order shown above.

            A .pdf extension is added automatically.

            +

            Export organized PDF

            The original PDF is unchanged. Export copies its pages in the order shown above.

            A .pdf extension is added automatically.

            diff --git a/tools/pdf/organize/tool.css b/tools/pdf/organize/tool.css index 12386d7..13f0169 100644 --- a/tools/pdf/organize/tool.css +++ b/tools/pdf/organize/tool.css @@ -1,6 +1,6 @@ .organizer { margin-top: var(--space-5); padding: var(--space-5); } .organizer-toolbar { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); padding-bottom: var(--space-4); border-bottom: 1px solid var(--border); } -.organizer-toolbar h2, .organizer-output h2 { margin: 0 0 var(--space-2); font-size: 1.35rem; } +.organizer-toolbar h2 { margin: 0 0 var(--space-2); font-size: 1.35rem; } .organizer-toolbar__actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-2); align-items: center; } .source-empty, .source-summary { margin: 0; color: var(--text-secondary); } .source-empty[hidden], .source-summary[hidden], .dirty-state[hidden] { display: none; } @@ -19,12 +19,8 @@ .page-actions { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2); } .page-action { min-height: 2.5rem; padding: .35rem; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-secondary); color: var(--text-primary); cursor: pointer; font-size: 1rem; } .page-action:hover:not(:disabled) { border-color: var(--border-strong); background: var(--bg-subtle); } -.page-action:disabled { opacity: .35; cursor: not-allowed; } +.page-action:disabled { border-color: var(--border); background: var(--bg-subtle); color: var(--status-muted); cursor: not-allowed; } .page-action--remove { grid-column: span 3; color: var(--tool-danger); } -.organizer-output { display: grid; grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem) auto; align-items: end; gap: var(--space-5); margin-top: var(--space-5); padding: var(--space-5); } -.organizer-output p { margin: 0; color: var(--text-secondary); } -.organizer-output .field { margin: 0; } .organizer-status { max-width: 60rem; } @media (prefers-reduced-motion: reduce) { .page-card { transition: none; } } -@media (max-width: 54rem) { .organizer-output { grid-template-columns: 1fr; align-items: stretch; } .organizer-output .button { width: 100%; } } @media (max-width: 38rem) { .organizer { padding: var(--space-4); } .organizer-toolbar { flex-direction: column; } .organizer-toolbar__actions { width: 100%; justify-content: stretch; } .organizer-toolbar__actions .button { flex: 1 1 9rem; } .page-grid { grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: var(--space-3); } .page-preview { min-height: 10rem; } } diff --git a/tools/shared/tool.css b/tools/shared/tool.css index 88bda24..e861c69 100644 --- a/tools/shared/tool.css +++ b/tools/shared/tool.css @@ -1,5 +1,5 @@ -:root { --tool-danger: #b42318; --tool-danger-soft: #fce8e6; --tool-warning: #8a5700; --tool-success: var(--accent); } -:root[data-resolved-theme="dark"] { --tool-danger: #ff9187; --tool-danger-soft: #3b211f; --tool-warning: #f2bd63; } +:root { --tool-danger: #b42318; --tool-danger-soft: #fce8e6; --tool-warning: #8a5700; --tool-warning-soft: #fff4d8; --tool-success: var(--accent); } +:root[data-resolved-theme="dark"] { --tool-danger: #ff9187; --tool-danger-soft: #3b211f; --tool-warning: #f2bd63; --tool-warning-soft: #3a2b12; } .tool-main { padding-block: var(--space-7) var(--space-8); } .tool-intro { position: relative; max-width: 52rem; margin-bottom: var(--space-7); padding-left: var(--space-5); border-left: 2px solid var(--accent); } @@ -51,7 +51,7 @@ .queue-action { width: 2.5rem; height: 2.5rem; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-secondary); color: var(--text-primary); cursor: pointer; transition: border-color var(--transition-fast), background-color var(--transition-fast); } .queue-action:hover:not(:disabled) { border-color: var(--border-strong); background: var(--bg-subtle); } .queue-action--remove:hover:not(:disabled) { border-color: var(--tool-danger); background: var(--tool-danger-soft); color: var(--tool-danger); } -.queue-action:disabled { opacity: 0.35; cursor: not-allowed; } +.queue-action:disabled { border-color: var(--border); background: var(--bg-subtle); color: var(--status-muted); cursor: not-allowed; } .settings { position: sticky; top: var(--space-4); padding: var(--space-5); } .settings h2 { margin-bottom: var(--space-5); padding-bottom: var(--space-4); border-bottom: 1px solid var(--border); font-size: 1.35rem; } @@ -73,16 +73,25 @@ .check-field { display: flex; gap: var(--space-2); align-items: flex-start; margin-bottom: var(--space-3); font-size: 0.82rem; line-height: 1.45; } .check-field input { width: 1rem; height: 1rem; flex: 0 0 auto; margin-top: 0.2rem; accent-color: var(--accent); } .tool-actions { display: grid; gap: var(--space-2); margin-top: var(--space-5); padding-top: var(--space-5); border-top: 1px solid var(--border); } -.tool-actions .button { width: 100%; cursor: pointer; } -.button:disabled { opacity: 0.45; cursor: not-allowed; } +.tool-actions .button { width: 100%; } .generation-progress { width: 100%; height: 0.55rem; margin-top: var(--space-4); accent-color: var(--accent); } -.tool-status { min-height: 3rem; margin: var(--space-3) 0 0; color: var(--text-secondary); font-size: 0.82rem; line-height: 1.5; } -.tool-status[data-tone="error"] { color: var(--tool-danger); } -.tool-status[data-tone="warning"] { color: var(--tool-warning); } -.tool-status[data-tone="success"] { color: var(--tool-success); } +.tool-status { margin: var(--space-3) 0 0; padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-left-width: 0.25rem; border-radius: var(--radius-sm); background: var(--bg-subtle); color: var(--text-secondary); font-size: 0.82rem; line-height: 1.5; } +.tool-status:empty { display: none; } +.tool-status[data-tone="error"] { border-color: var(--tool-danger); background: var(--tool-danger-soft); color: var(--tool-danger); } +.tool-status[data-tone="warning"] { border-color: var(--tool-warning); background: var(--tool-warning-soft); color: var(--tool-warning); } +.tool-status[data-tone="success"] { border-color: var(--tool-success); background: var(--accent-soft); color: var(--tool-success); } +.tool-output { display: grid; grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem) auto; align-items: end; gap: var(--space-5); margin-top: var(--space-5); padding: var(--space-5); } +.tool-output > * { min-width: 0; } +.tool-output h2 { margin: 0 0 var(--space-2); font-size: 1.35rem; } +.tool-output p { margin: 0; color: var(--text-secondary); } +.tool-output .field { margin: 0; } @media (prefers-reduced-motion: reduce) { .mode-option { transition: none; } } @media (max-width: 48rem) { .mode-list { grid-template-columns: 1fr; } } +@media (max-width: 54rem) { + .tool-output { grid-template-columns: 1fr; align-items: stretch; } + .tool-output .button { width: 100%; } +} @media (max-width: 60rem) { .tool-layout { grid-template-columns: 1fr; } .settings { position: static; } From e54d851ce6e239ad5e71d3797f51a78147d59276 Mon Sep 17 00:00:00 2001 From: maruson08 Date: Thu, 20 Aug 2026 21:21:30 +0900 Subject: [PATCH 4/7] =?UTF-8?q?=F0=9F=8E=80[Style]=20Polish=20shared=20sit?= =?UTF-8?q?e=20chrome=20and=20theme=20consistency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 404.html | 2 +- about/index.html | 2 +- css/base.css | 2 ++ css/categories.css | 1 + index.html | 2 +- privacy/index.html | 2 +- tools/image/index.html | 4 ++-- tools/media/index.html | 4 ++-- tools/pdf/images-to-pdf/index.html | 2 +- tools/pdf/index.html | 2 +- tools/pdf/merge/index.html | 2 +- tools/pdf/metadata/index.html | 2 +- tools/pdf/organize/index.html | 2 +- tools/pdf/organize/tool.css | 2 +- tools/pdf/split/index.html | 2 +- tools/pdf/to-images/index.html | 2 +- tools/privacy/index.html | 4 ++-- tools/scan/index.html | 4 ++-- 18 files changed, 23 insertions(+), 20 deletions(-) diff --git a/404.html b/404.html index 15227c1..662e665 100644 --- a/404.html +++ b/404.html @@ -19,7 +19,7 @@

            404

            This page is not here.

            The address may be outdated or mistyped.

            Return home
            - + diff --git a/about/index.html b/about/index.html index 4e44d24..6ae8b98 100644 --- a/about/index.html +++ b/about/index.html @@ -44,7 +44,7 @@

            Local-first and open

            The project favors static, understandable code and a privacy model that anyone can verify through source and network inspection.

            - + diff --git a/css/base.css b/css/base.css index 9ab1b08..c57dd48 100644 --- a/css/base.css +++ b/css/base.css @@ -15,6 +15,7 @@ --focus: #1673c9; --status-muted: #74766f; --shadow-sm: 0 1px 2px rgb(23 24 22 / 5%); + --preview-backdrop: #d7d8da; --radius-sm: 0.4rem; --radius-md: 0.75rem; --radius-lg: 1.15rem; @@ -48,6 +49,7 @@ --focus: #66b5ff; --status-muted: #9b9e96; --shadow-sm: 0 1px 2px rgb(0 0 0 / 20%); + --preview-backdrop: #2b2e29; } *, *::before, *::after { box-sizing: border-box; } diff --git a/css/categories.css b/css/categories.css index 32cbfae..43c3a00 100644 --- a/css/categories.css +++ b/css/categories.css @@ -11,6 +11,7 @@ .category-tool { display: flex; min-width: 0; min-height: 12rem; flex-direction: column; align-items: flex-start; padding: var(--space-5); color: inherit; text-decoration: none; } .category-tool__top { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: var(--space-4); margin-bottom: auto; } .category-tool h2 { margin: var(--space-5) 0 var(--space-2); font-size: clamp(1.3rem, 3vw, 1.75rem); } +.category-tool > .status { margin-bottom: auto; } .category-tool p { margin: 0; color: var(--text-secondary); } a.category-tool { transition: border-color var(--transition-fast), transform var(--transition-fast); } a.category-tool:hover { border-color: var(--border-strong); transform: translateY(-2px); } diff --git a/index.html b/index.html index 9a852dd..5a16e8d 100644 --- a/index.html +++ b/index.html @@ -143,7 +143,7 @@

            Open by design.

            - + diff --git a/tools/pdf/index.html b/tools/pdf/index.html index fb76cdc..d717cce 100644 --- a/tools/pdf/index.html +++ b/tools/pdf/index.html @@ -15,4 +15,4 @@
          1. Available

            PDF to Images

            Convert ordered PDF pages to PNG, JPEG, or WebP images.

          2. Available

            PDF Metadata

            Inspect common document metadata and create a verified cleaned copy.

          3. Available tools process file contents in browser memory. Planned items are clearly marked.

            - + diff --git a/tools/pdf/merge/index.html b/tools/pdf/merge/index.html index 20ca5a4..d8d4371 100644 --- a/tools/pdf/merge/index.html +++ b/tools/pdf/merge/index.html @@ -10,5 +10,5 @@

            Add your PDFs

            Drop PDF files here or use the picker. The queue order becomes the document order.

            Processed locally. Your PDFs never leave this device. How privacy works

            PDF order

            PDFs: 0

            No PDFs added yet.

              - + diff --git a/tools/pdf/metadata/index.html b/tools/pdf/metadata/index.html index 3618da2..777d714 100644 --- a/tools/pdf/metadata/index.html +++ b/tools/pdf/metadata/index.html @@ -15,5 +15,5 @@ - + diff --git a/tools/pdf/organize/index.html b/tools/pdf/organize/index.html index 6a187a4..b689e95 100644 --- a/tools/pdf/organize/index.html +++ b/tools/pdf/organize/index.html @@ -10,5 +10,5 @@

              Add one PDF

              Drop a PDF here or use the picker.

              Processed locally. Your PDF never leaves this device. How privacy works

              Page workspace

              No PDF selected yet.

                Export organized PDF

                The original PDF is unchanged. Export copies its pages in the order shown above.

                A .pdf extension is added automatically.

                - + diff --git a/tools/pdf/organize/tool.css b/tools/pdf/organize/tool.css index 13f0169..4175dfc 100644 --- a/tools/pdf/organize/tool.css +++ b/tools/pdf/organize/tool.css @@ -11,7 +11,7 @@ .page-card[draggable="true"] { cursor: grab; } .page-card[data-dragging="true"] { opacity: .55; } .page-card[data-drop-target="true"] { border-color: var(--accent); background: var(--accent-soft); } -.page-preview { display: grid; min-height: 12rem; place-items: center; overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-sm); background: #d7d8da; } +.page-preview { display: grid; min-height: 12rem; place-items: center; overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--preview-backdrop); } .page-preview canvas { display: block; width: min(100%, 12.5rem); max-height: 17rem; object-fit: contain; background: #fff; box-shadow: 0 1px 4px rgb(0 0 0 / .18); } .page-label { display: flex; justify-content: space-between; gap: var(--space-2); margin: var(--space-3) 0; font-size: .78rem; } .page-label strong { overflow-wrap: anywhere; } diff --git a/tools/pdf/split/index.html b/tools/pdf/split/index.html index c73a97a..dc3b105 100644 --- a/tools/pdf/split/index.html +++ b/tools/pdf/split/index.html @@ -13,5 +13,5 @@

                Examples: 1-3, 5, 2,4,7, or 5,1,3. Duplicates are preserved.

                - + diff --git a/tools/pdf/to-images/index.html b/tools/pdf/to-images/index.html index 94a4d08..c1b5359 100644 --- a/tools/pdf/to-images/index.html +++ b/tools/pdf/to-images/index.html @@ -11,5 +11,5 @@

                Source PDF

                No PDF selected yet.

                Pages to convert

                Choose which pages to convert
                - + diff --git a/tools/privacy/index.html b/tools/privacy/index.html index b79d10a..e10d993 100644 --- a/tools/privacy/index.html +++ b/tools/privacy/index.html @@ -1,6 +1,6 @@ Privacy tools — Secure Tools - + -

                Tool category

                Privacy tools

                Inspect and remove hidden file details without sharing the source file.

                • Coming soon

                  Metadata Inspector

                  See what identifying information a file contains.

                • Coming soon

                  Metadata Cleaner

                  Create a copy with supported metadata removed.

                This category is planned. No unavailable item is presented as working.

                +

                Tool category

                Privacy tools

                Inspect and remove hidden file details without sharing the source file.

                • Coming soon

                  Metadata Inspector

                  See what identifying information a file contains.

                • Coming soon

                  Metadata Cleaner

                  Create a copy with supported metadata removed.

                This category is planned. No unavailable item is presented as working.

                diff --git a/tools/scan/index.html b/tools/scan/index.html index 2615521..8b0d12c 100644 --- a/tools/scan/index.html +++ b/tools/scan/index.html @@ -1,6 +1,6 @@ Scan and OCR tools — Secure Tools - + -

                Tool category

                Scan & OCR tools

                Turn scans into useful documents while keeping source material on your device.

                • Coming soon

                  Image to text

                  Recognize text from an image locally.

                • Coming soon

                  Document scanner

                  Crop and clean photographed documents.

                This category is planned. No unavailable item is presented as working.

                +

                Tool category

                Scan & OCR tools

                Turn scans into useful documents while keeping source material on your device.

                • Coming soon

                  Image to text

                  Recognize text from an image locally.

                • Coming soon

                  Document scanner

                  Crop and clean photographed documents.

                This category is planned. No unavailable item is presented as working.

                From bb415eb773dac7a4bc588555debb71a3b9b45e81 Mon Sep 17 00:00:00 2001 From: maruson08 Date: Thu, 20 Aug 2026 21:22:48 +0900 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=90=9B[Fix]=20Resolve=20cross-tool=20?= =?UTF-8?q?accessibility=20inconsistencies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/pdf/metadata/index.html | 2 +- tools/pdf/organize/index.html | 2 +- tools/shared/tool.css | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/pdf/metadata/index.html b/tools/pdf/metadata/index.html index 777d714..9ecc1d6 100644 --- a/tools/pdf/metadata/index.html +++ b/tools/pdf/metadata/index.html @@ -9,7 +9,7 @@

                PDF privacy tool

                PDF Metadata Inspector & Cleaner

                Review common document metadata and create a cleaned copy without uploading your PDF.

                Add one PDF

                Drop a PDF here or use the picker. Choosing another file replaces the current source.

                Processed locally. Your PDF never leaves this device. How privacy works

                -