Skip to content

Commit 7c4330d

Browse files
authored
Create index.html
1 parent 401ed51 commit 7c4330d

1 file changed

Lines changed: 251 additions & 0 deletions

File tree

renderer/index.html

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; script-src 'self' 'unsafe-inline'">
7+
<title>FileCC</title>
8+
<link rel="stylesheet" href="style.css" />
9+
</head>
10+
<body>
11+
12+
<div class="titlebar">
13+
<div class="titlebar-title">
14+
<span></span>
15+
FileCC
16+
</div>
17+
<div class="titlebar-controls">
18+
<button id="btnMinimize">&#8211;</button>
19+
<button id="btnMaximize">&#9633;</button>
20+
<button id="btnClose" class="close">&#10005;</button>
21+
</div>
22+
</div>
23+
24+
<div class="layout">
25+
26+
<aside class="sidebar">
27+
<div class="sidebar-label">Type</div>
28+
<button class="nav-btn active" data-type="image">
29+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="3" width="18" height="18" rx="3"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg>
30+
Image
31+
</button>
32+
<button class="nav-btn" data-type="document">
33+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><path d="M14 2v6h6M16 13H8M16 17H8M10 9H8"/></svg>
34+
Document
35+
</button>
36+
<button class="nav-btn" data-type="audio">
37+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>
38+
Audio
39+
</button>
40+
<button class="nav-btn" data-type="video">
41+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>
42+
Video
43+
</button>
44+
</aside>
45+
46+
<main class="main">
47+
48+
<div class="dropzone" id="dropzone">
49+
<div class="dropzone-icon">
50+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
51+
</div>
52+
<div class="dropzone-text">
53+
<strong>Drop file here</strong>
54+
or click to browse
55+
</div>
56+
</div>
57+
58+
<div class="file-info" id="fileInfo">
59+
<div class="file-icon" id="fileExt"></div>
60+
<div class="file-meta">
61+
<div class="file-name" id="fileName"></div>
62+
<div class="file-size" id="fileSize"></div>
63+
</div>
64+
<button class="clear-btn" id="clearBtn">
65+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
66+
</button>
67+
</div>
68+
69+
<div class="format-section">
70+
<div class="section-label">Convert to</div>
71+
<div class="format-grid" id="formatGrid"></div>
72+
</div>
73+
74+
<div class="progress-bar" id="progressBar">
75+
<div class="progress-fill indeterminate" id="progressFill"></div>
76+
</div>
77+
78+
<button class="convert-btn" id="convertBtn" disabled>
79+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/></svg>
80+
Convert
81+
</button>
82+
83+
<div class="status" id="statusBox">
84+
<span id="statusText"></span>
85+
<button class="status-open" id="statusOpen" style="display:none">Open folder</button>
86+
</div>
87+
88+
</main>
89+
</div>
90+
91+
<script>
92+
const FORMATS = {
93+
image: ['jpg', 'png', 'webp', 'avif', 'tiff', 'bmp', 'gif'],
94+
document: ['pdf', 'txt', 'html', 'docx'],
95+
audio: ['mp3', 'wav', 'flac', 'aac', 'ogg', 'm4a'],
96+
video: ['mp4', 'avi', 'mkv', 'mov', 'webm'],
97+
};
98+
99+
let currentType = 'image';
100+
let selectedFile = null;
101+
let targetFormat = null;
102+
let lastOutput = null;
103+
104+
const dropzone = document.getElementById('dropzone');
105+
const fileInfo = document.getElementById('fileInfo');
106+
const fileExt = document.getElementById('fileExt');
107+
const fileName = document.getElementById('fileName');
108+
const fileSize = document.getElementById('fileSize');
109+
const clearBtn = document.getElementById('clearBtn');
110+
const formatGrid = document.getElementById('formatGrid');
111+
const convertBtn = document.getElementById('convertBtn');
112+
const progressBar = document.getElementById('progressBar');
113+
const progressFill= document.getElementById('progressFill');
114+
const statusBox = document.getElementById('statusBox');
115+
const statusText = document.getElementById('statusText');
116+
const statusOpen = document.getElementById('statusOpen');
117+
118+
function formatBytes(bytes) {
119+
if (bytes < 1024) return bytes + ' B';
120+
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
121+
return (bytes / 1048576).toFixed(2) + ' MB';
122+
}
123+
124+
function renderFormats() {
125+
formatGrid.innerHTML = '';
126+
targetFormat = null;
127+
FORMATS[currentType].forEach(fmt => {
128+
const btn = document.createElement('button');
129+
btn.className = 'fmt-btn';
130+
btn.textContent = fmt;
131+
btn.addEventListener('click', () => {
132+
document.querySelectorAll('.fmt-btn').forEach(b => b.classList.remove('active'));
133+
btn.classList.add('active');
134+
targetFormat = fmt;
135+
updateConvertBtn();
136+
});
137+
formatGrid.appendChild(btn);
138+
});
139+
}
140+
141+
function updateConvertBtn() {
142+
convertBtn.disabled = !(selectedFile && targetFormat);
143+
}
144+
145+
function setFile(file) {
146+
selectedFile = file;
147+
fileExt.textContent = file.ext.toUpperCase();
148+
fileName.textContent = file.name;
149+
fileSize.textContent = formatBytes(file.size);
150+
dropzone.style.display = 'none';
151+
fileInfo.classList.add('visible');
152+
hideStatus();
153+
updateConvertBtn();
154+
}
155+
156+
function clearFile() {
157+
selectedFile = null;
158+
lastOutput = null;
159+
dropzone.style.display = '';
160+
fileInfo.classList.remove('visible');
161+
hideStatus();
162+
updateConvertBtn();
163+
}
164+
165+
function showStatus(type, message, outputPath) {
166+
statusBox.className = 'status visible ' + type;
167+
statusText.textContent = message;
168+
if (outputPath) {
169+
lastOutput = outputPath;
170+
statusOpen.style.display = 'inline-block';
171+
} else {
172+
statusOpen.style.display = 'none';
173+
}
174+
}
175+
176+
function hideStatus() {
177+
statusBox.className = 'status';
178+
}
179+
180+
document.querySelectorAll('.nav-btn').forEach(btn => {
181+
btn.addEventListener('click', () => {
182+
document.querySelectorAll('.nav-btn').forEach(b => b.classList.remove('active'));
183+
btn.classList.add('active');
184+
currentType = btn.dataset.type;
185+
renderFormats();
186+
clearFile();
187+
});
188+
});
189+
190+
dropzone.addEventListener('click', async () => {
191+
const file = await window.electronAPI.openFile();
192+
if (file) setFile(file);
193+
});
194+
195+
dropzone.addEventListener('dragover', e => {
196+
e.preventDefault();
197+
dropzone.classList.add('dragover');
198+
});
199+
200+
dropzone.addEventListener('dragleave', () => {
201+
dropzone.classList.remove('dragover');
202+
});
203+
204+
dropzone.addEventListener('drop', async e => {
205+
e.preventDefault();
206+
dropzone.classList.remove('dragover');
207+
const file = await window.electronAPI.openFile();
208+
if (file) setFile(file);
209+
});
210+
211+
clearBtn.addEventListener('click', clearFile);
212+
213+
convertBtn.addEventListener('click', async () => {
214+
if (!selectedFile || !targetFormat) return;
215+
216+
const baseName = selectedFile.name.replace(/\.[^/.]+$/, '') + '.' + targetFormat;
217+
const outputPath = await window.electronAPI.saveFile(baseName, targetFormat);
218+
if (!outputPath) return;
219+
220+
convertBtn.disabled = true;
221+
progressBar.classList.add('visible');
222+
hideStatus();
223+
224+
const result = await window.electronAPI.convertFile(
225+
selectedFile.path,
226+
outputPath,
227+
targetFormat
228+
);
229+
230+
progressBar.classList.remove('visible');
231+
convertBtn.disabled = false;
232+
233+
if (result.success) {
234+
showStatus('success', 'Conversion complete — ' + baseName, result.outputPath);
235+
} else {
236+
showStatus('error', 'Error: ' + result.error, null);
237+
}
238+
});
239+
240+
statusOpen.addEventListener('click', () => {
241+
if (lastOutput) window.electronAPI.showInFolder(lastOutput);
242+
});
243+
244+
document.getElementById('btnMinimize').addEventListener('click', () => window.electronAPI.minimize());
245+
document.getElementById('btnMaximize').addEventListener('click', () => window.electronAPI.maximize());
246+
document.getElementById('btnClose').addEventListener('click', () => window.electronAPI.close());
247+
248+
renderFormats();
249+
</script>
250+
</body>
251+
</html>

0 commit comments

Comments
 (0)