Skip to content

Commit e387800

Browse files
ayutazclaude
andcommitted
Implement Phase 3: Multiple file support and batch processing
Features implemented: - Multiple file upload (up to 20 files) - File list management with thumbnails - Web Worker for parallel processing - Batch conversion with progress tracking - JSZip integration for bulk download - Individual and ZIP download options - Dithering algorithms (Floyd-Steinberg, Ordered, Atkinson) - Enhanced UI for multiple files UI improvements: - File list section with status indicators - Grid layout for preview items - Progress bar with percentage - Download section with multiple options Technical changes: - Created app-v2.js for enhanced version - Added batchProcessor.js for queue management - Implemented imageProcessor.worker.js - Added CDN links for JSZip and FileSaver.js 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 37aecb9 commit e387800

5 files changed

Lines changed: 1225 additions & 17 deletions

File tree

index.html

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ <h1 class="title">Image to Pixel Art</h1>
2525
</svg>
2626
<p class="upload-text">画像をドラッグ&ドロップ<br>または</p>
2727
<button class="upload-button" id="uploadButton">ファイルを選択</button>
28-
<input type="file" id="fileInput" class="file-input" accept="image/*" hidden>
29-
<p class="upload-info">対応形式: JPEG, PNG, GIF, WebP</p>
28+
<input type="file" id="fileInput" class="file-input" accept="image/*" multiple hidden>
29+
<p class="upload-info">対応形式: JPEG, PNG, GIF, WebP<br>最大20ファイルまで選択可能</p>
3030
</div>
3131
</div>
3232
</section>
@@ -77,21 +77,21 @@ <h2 class="section-title">変換設定</h2>
7777
</div>
7878
</section>
7979

80+
<!-- ファイルリスト -->
81+
<section class="file-list-section" id="fileListSection" style="display: none;">
82+
<h2 class="section-title">選択されたファイル (<span id="fileCount">0</span>/20)</h2>
83+
<div class="file-list" id="fileList"></div>
84+
</section>
85+
8086
<!-- プレビューエリア -->
8187
<section class="preview-section" id="previewSection" style="display: none;">
8288
<h2 class="section-title">変換結果</h2>
83-
<div class="preview-container">
84-
<div class="preview-box">
85-
<h3 class="preview-title">元の画像</h3>
86-
<canvas id="originalCanvas" class="preview-canvas"></canvas>
87-
</div>
88-
<div class="preview-box">
89-
<h3 class="preview-title">変換後</h3>
90-
<canvas id="resultCanvas" class="preview-canvas"></canvas>
91-
<div class="preview-actions">
92-
<button class="btn btn-success" id="downloadButton">ダウンロード</button>
93-
</div>
94-
</div>
89+
<div class="preview-container" id="previewContainer">
90+
<!-- 動的に生成 -->
91+
</div>
92+
<div class="download-section" id="downloadSection" style="display: none;">
93+
<button class="btn btn-success" id="downloadAllButton">すべてダウンロード (ZIP)</button>
94+
<button class="btn btn-primary" id="downloadSingleButton">個別ダウンロード</button>
9595
</div>
9696
</section>
9797

@@ -112,6 +112,11 @@ <h3 class="preview-title">変換後</h3>
112112
</footer>
113113
</div>
114114

115-
<script src="src/js/app.js"></script>
115+
<!-- External Libraries -->
116+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
117+
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
118+
119+
<!-- Main Application -->
120+
<script src="src/js/app-v2.js"></script>
116121
</body>
117122
</html>

src/css/main.css

Lines changed: 147 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,15 +243,160 @@ body {
243243
box-shadow: 0 4px 12px rgba(72, 187, 120, 0.4);
244244
}
245245

246+
/* File List Section */
247+
.file-list-section {
248+
margin-bottom: 40px;
249+
}
250+
251+
.file-list {
252+
display: grid;
253+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
254+
gap: 16px;
255+
max-height: 400px;
256+
overflow-y: auto;
257+
padding: 16px;
258+
background: #f7fafc;
259+
border-radius: 8px;
260+
}
261+
262+
.file-item {
263+
background: white;
264+
border: 2px solid #e2e8f0;
265+
border-radius: 8px;
266+
padding: 12px;
267+
position: relative;
268+
transition: all 0.3s;
269+
}
270+
271+
.file-item:hover {
272+
border-color: #667eea;
273+
transform: translateY(-2px);
274+
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
275+
}
276+
277+
.file-item-name {
278+
font-size: 14px;
279+
color: #2d3748;
280+
margin-bottom: 8px;
281+
white-space: nowrap;
282+
overflow: hidden;
283+
text-overflow: ellipsis;
284+
}
285+
286+
.file-item-size {
287+
font-size: 12px;
288+
color: #a0aec0;
289+
margin-bottom: 8px;
290+
}
291+
292+
.file-item-status {
293+
font-size: 12px;
294+
font-weight: 600;
295+
padding: 4px 8px;
296+
border-radius: 4px;
297+
text-align: center;
298+
}
299+
300+
.file-item-status.pending {
301+
background: #e2e8f0;
302+
color: #4a5568;
303+
}
304+
305+
.file-item-status.processing {
306+
background: #fef5e7;
307+
color: #f39c12;
308+
}
309+
310+
.file-item-status.completed {
311+
background: #d5f4e6;
312+
color: #27ae60;
313+
}
314+
315+
.file-item-status.error {
316+
background: #ffeaa7;
317+
color: #d63031;
318+
}
319+
320+
.file-item-remove {
321+
position: absolute;
322+
top: 8px;
323+
right: 8px;
324+
width: 20px;
325+
height: 20px;
326+
border: none;
327+
background: #e74c3c;
328+
color: white;
329+
border-radius: 50%;
330+
cursor: pointer;
331+
font-size: 12px;
332+
display: flex;
333+
align-items: center;
334+
justify-content: center;
335+
transition: all 0.3s;
336+
}
337+
338+
.file-item-remove:hover {
339+
background: #c0392b;
340+
transform: scale(1.1);
341+
}
342+
343+
.file-item-thumbnail {
344+
width: 100%;
345+
height: 120px;
346+
object-fit: cover;
347+
border-radius: 4px;
348+
margin-bottom: 8px;
349+
}
350+
246351
/* Preview Section */
247352
.preview-section {
248353
margin-bottom: 40px;
249354
}
250355

251356
.preview-container {
252357
display: grid;
253-
grid-template-columns: 1fr 1fr;
254-
gap: 32px;
358+
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
359+
gap: 24px;
360+
max-height: 600px;
361+
overflow-y: auto;
362+
padding: 16px;
363+
background: #f7fafc;
364+
border-radius: 8px;
365+
}
366+
367+
.preview-item {
368+
background: white;
369+
border-radius: 8px;
370+
padding: 16px;
371+
text-align: center;
372+
}
373+
374+
.preview-item-title {
375+
font-size: 14px;
376+
font-weight: 600;
377+
color: #2d3748;
378+
margin-bottom: 12px;
379+
white-space: nowrap;
380+
overflow: hidden;
381+
text-overflow: ellipsis;
382+
}
383+
384+
.preview-item-canvas {
385+
width: 100%;
386+
max-width: 200px;
387+
height: auto;
388+
border: 2px solid #e2e8f0;
389+
border-radius: 4px;
390+
margin-bottom: 12px;
391+
}
392+
393+
/* Download Section */
394+
.download-section {
395+
margin-top: 24px;
396+
text-align: center;
397+
display: flex;
398+
gap: 16px;
399+
justify-content: center;
255400
}
256401

257402
.preview-box {

0 commit comments

Comments
 (0)