Skip to content

Commit f9c69a4

Browse files
96 create page for testing filytypes (#119)
* Created test-files/ directory for testing files and the file-test.html page in www/. * Added the design of the file-test.html page * Added JavaScript logic to display files * Fixed warnings * - Cleaned up unused HTML code - Made the JavaScript safer and easier to read - Added comments and docstrings to the JavaScript - Added test files, the soundbite is taken from a royalty-free music library and was combined with the GIF version of the logo to create the video files * - Removed duplicate test.jpg file outside test-files/ directory. - Applied CodeRabbit suggestions JavaScript if-statement.
1 parent 5280790 commit f9c69a4

13 files changed

Lines changed: 348 additions & 0 deletions

File tree

www/file-test.html

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
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+
<title>File Type Test</title>
7+
<style>
8+
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600&family=IBM+Plex+Sans:wght@300;400&display=swap');
9+
10+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
11+
12+
:root {
13+
--bg: #0a0f1e;
14+
--surface: #101828;
15+
--border: #1e3050;
16+
--accent: #e8f0ff;
17+
--text: #c8d8f0;
18+
--text-dim: #4a6080;
19+
--radius: 4px;
20+
}
21+
22+
body {
23+
background: var(--bg);
24+
color: var(--text);
25+
font-family: 'IBM Plex Sans', sans-serif;
26+
font-weight: 300;
27+
min-height: 100vh;
28+
display: flex;
29+
flex-direction: column;
30+
align-items: center;
31+
justify-content: center;
32+
padding: 2rem;
33+
}
34+
35+
h1 {
36+
font-family: 'IBM Plex Mono', monospace;
37+
font-size: 0.75rem;
38+
font-weight: 600;
39+
letter-spacing: 0.2em;
40+
text-transform: uppercase;
41+
color: var(--accent);
42+
margin-bottom: 2rem;
43+
}
44+
45+
.card {
46+
width: 100%;
47+
max-width: 760px;
48+
background: var(--surface);
49+
border: 1px solid var(--border);
50+
border-radius: var(--radius);
51+
overflow: hidden;
52+
}
53+
54+
.card-header {
55+
display: flex;
56+
align-items: center;
57+
gap: 1rem;
58+
padding: 1rem 1.25rem;
59+
border-bottom: 1px solid var(--border);
60+
background: #0a0f1e;
61+
}
62+
63+
.card-header label {
64+
font-family: 'IBM Plex Mono', monospace;
65+
font-size: 0.7rem;
66+
letter-spacing: 0.12em;
67+
text-transform: uppercase;
68+
color: var(--text-dim);
69+
white-space: nowrap;
70+
}
71+
72+
select {
73+
flex: 1;
74+
background: var(--bg);
75+
color: var(--text);
76+
border: 1px solid var(--border);
77+
border-radius: var(--radius);
78+
padding: 0.45rem 0.75rem;
79+
font-family: 'IBM Plex Mono', monospace;
80+
font-size: 0.8rem;
81+
appearance: none;
82+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23555'/%3E%3C/svg%3E");
83+
background-repeat: no-repeat;
84+
background-position: right 0.75rem center;
85+
cursor: pointer;
86+
transition: border-color 0.15s;
87+
}
88+
89+
select:hover, select:focus {
90+
border-color: var(--accent);
91+
outline: none;
92+
}
93+
94+
select option {
95+
background: #0a0f1e;
96+
}
97+
98+
.viewer {
99+
position: relative;
100+
min-height: 420px;
101+
display: flex;
102+
align-items: center;
103+
justify-content: center;
104+
padding: 1.5rem;
105+
}
106+
107+
.placeholder {
108+
display: flex;
109+
flex-direction: column;
110+
align-items: center;
111+
gap: 0.75rem;
112+
color: var(--text-dim);
113+
font-family: 'IBM Plex Mono', monospace;
114+
font-size: 0.75rem;
115+
letter-spacing: 0.08em;
116+
}
117+
118+
.placeholder svg {
119+
opacity: 0.3;
120+
}
121+
122+
#content-area {
123+
width: 100%;
124+
height: 100%;
125+
display: flex;
126+
align-items: center;
127+
justify-content: center;
128+
}
129+
130+
#content-area img {
131+
max-width: 100%;
132+
max-height: 380px;
133+
object-fit: contain;
134+
border-radius: var(--radius);
135+
display: block;
136+
}
137+
138+
#content-area video {
139+
max-width: 100%;
140+
max-height: 380px;
141+
border-radius: var(--radius);
142+
background: #050a14;
143+
}
144+
145+
#content-area audio {
146+
width: 100%;
147+
max-width: 480px;
148+
accent-color: var(--accent);
149+
}
150+
151+
#content-area pre {
152+
width: 100%;
153+
background: var(--bg);
154+
border: 1px solid var(--border);
155+
border-radius: var(--radius);
156+
padding: 1.25rem;
157+
font-family: 'IBM Plex Mono', monospace;
158+
font-size: 0.78rem;
159+
line-height: 1.7;
160+
color: #aaa;
161+
overflow: auto;
162+
max-height: 380px;
163+
white-space: pre-wrap;
164+
word-break: break-word;
165+
}
166+
167+
#content-area embed,
168+
#content-area iframe {
169+
width: 100%;
170+
height: 380px;
171+
border: none;
172+
border-radius: var(--radius);
173+
background: #fff;
174+
}
175+
176+
.tag {
177+
font-family: 'IBM Plex Mono', monospace;
178+
font-size: 0.65rem;
179+
letter-spacing: 0.1em;
180+
text-transform: uppercase;
181+
color: var(--text-dim);
182+
padding: 0.25rem 0.6rem;
183+
border: 1px solid var(--border);
184+
border-radius: 2px;
185+
background: #0a0f1e;
186+
}
187+
188+
.card-footer {
189+
padding: 0.65rem 1.25rem;
190+
border-top: 1px solid var(--border);
191+
background: #0a0f1e;
192+
display: flex;
193+
align-items: center;
194+
justify-content: space-between;
195+
}
196+
197+
.filepath {
198+
font-family: 'IBM Plex Mono', monospace;
199+
font-size: 0.7rem;
200+
color: var(--text-dim);
201+
}
202+
203+
.filepath span {
204+
color: var(--accent);
205+
}
206+
</style>
207+
</head>
208+
<body>
209+
210+
<h1>File Type Viewer</h1>
211+
212+
<div class="card">
213+
<div class="card-header">
214+
<label for="file-select">Type</label>
215+
<select id="file-select" onchange="loadFile(this.value)">
216+
<option value="">— select a file type —</option>
217+
<optgroup label="Images">
218+
<option value="jpeg">JPEG (.jpeg)</option>
219+
<option value="jpg">JPG (.jpg)</option>
220+
<option value="png">PNG (.png)</option>
221+
<option value="gif">GIF (.gif)</option>
222+
<option value="webp">WebP (.webp)</option>
223+
<option value="svg">SVG (.svg)</option>
224+
</optgroup>
225+
<optgroup label="Text">
226+
<option value="txt">TXT (.txt)</option>
227+
</optgroup>
228+
<optgroup label="Document">
229+
<option value="pdf">PDF (.pdf)</option>
230+
</optgroup>
231+
<optgroup label="Video">
232+
<option value="mp4">MP4 (.mp4)</option>
233+
<option value="webm">WebM (.webm)</option>
234+
</optgroup>
235+
<optgroup label="Audio">
236+
<option value="mp3">MP3 (.mp3)</option>
237+
<option value="wav">WAV (.wav)</option>
238+
</optgroup>
239+
</select>
240+
<span class="tag" id="type-tag"></span>
241+
</div>
242+
243+
<div class="viewer">
244+
<div id="content-area">
245+
<div class="placeholder">
246+
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
247+
<rect x="3" y="3" width="18" height="18" rx="2"/>
248+
<path d="M3 9h18M9 21V9"/>
249+
</svg>
250+
select a file type above
251+
</div>
252+
</div>
253+
</div>
254+
255+
<div class="card-footer">
256+
<span class="filepath" id="filepath-display"></span>
257+
</div>
258+
</div>
259+
260+
<!-- JavaScript which handles file selection and display -->
261+
<script>
262+
// A const mapping the path, category of file and label of each supported file format
263+
const types = {
264+
jpg: { path: '/test-files/test.jpg', category: 'image', label: 'jpg' },
265+
jpeg: { path: '/test-files/test.jpeg', category: 'image', label: 'jpeg' },
266+
png: { path: '/test-files/test.png', category: 'image', label: 'png' },
267+
gif: { path: '/test-files/test.gif', category: 'image', label: 'gif' },
268+
webp: { path: '/test-files/test.webp', category: 'image', label: 'webp' },
269+
svg: { path: '/test-files/test.svg', category: 'image', label: 'svg' },
270+
txt: { path: '/test-files/test.txt', category: 'text', label: 'plain' },
271+
pdf: { path: '/test-files/test.pdf', category: 'pdf', label: 'pdf' },
272+
mp4: { path: '/test-files/test.mp4', category: 'video', label: 'video/mp4' },
273+
webm: { path: '/test-files/test.webm', category: 'video', label: 'video/webm' },
274+
mp3: { path: '/test-files/test.mp3', category: 'audio', label: 'audio/mpeg' },
275+
wav: { path: '/test-files/test.wav', category: 'audio', label: 'audio/wav' },
276+
};
277+
278+
/**
279+
* Loads the type of file selected in the dropdown menu.
280+
* @param fileType
281+
*/
282+
function loadFile(fileType) {
283+
const contentArea = document.getElementById('content-area');
284+
const typeTag = document.getElementById('type-tag');
285+
const filePathDisplay = document.getElementById('filepath-display');
286+
287+
// If no filetype is selected then show a message prompting the user to select a file type
288+
if (!fileType || !types[fileType]) {
289+
contentArea.innerHTML = `<div class="placeholder"><svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>select a file type above</div>`;
290+
typeTag.textContent = '—';
291+
filePathDisplay.innerHTML = '—';
292+
return;
293+
}
294+
295+
// Assigns a variable to each value in the types const and displays the information in the card header
296+
const { path, category, label } = types[fileType];
297+
typeTag.textContent = fileType;
298+
filePathDisplay.innerHTML = `<span>${path}</span>`;
299+
300+
// Displays the file type based on category
301+
if (category === 'image') {
302+
const image = document.createElement('img');
303+
image.src = path;
304+
image.alt = `test ${fileType}`;
305+
image.onerror = () => {
306+
image.outerHTML = `<span style = "color:#4a6080;font-family:monospace;font-size:.8rem">file not found: ${path}</span>`;
307+
};
308+
contentArea.innerHTML = '';
309+
contentArea.appendChild(image);
310+
} else if (category === 'text') {
311+
fetch(path)
312+
.then(response => { if (!response.ok) { throw new Error('not found'); } return response.text(); })
313+
.then(responseText => {
314+
const pre = document.createElement('pre');
315+
pre.textContent = responseText;
316+
contentArea.innerHTML = '';
317+
contentArea.appendChild(pre);
318+
})
319+
.catch(() => { contentArea.innerHTML = `<span style="color:#555;font-family:monospace;font-size:.8rem">file not found: ${path}</span>`; });
320+
} else if (category === 'pdf') {
321+
contentArea.innerHTML = `<embed src="${path}" type="application/pdf">`;
322+
} else if (category === 'video') {
323+
const video = document.createElement('video');
324+
video.controls = true;
325+
video.innerHTML = `<source src="${path}" type="${label}">Your browser does not support this video format.`;
326+
video.onerror = () => {
327+
contentArea.innerHTML = `<span style="color:#4a6080;font-family:monospace;font-size:.8rem">file not found: ${path}</span>`;
328+
};
329+
contentArea.innerHTML = '';
330+
contentArea.appendChild(video);
331+
} else if (category === 'audio') {
332+
const audio = document.createElement('audio');
333+
audio.controls = true;
334+
audio.innerHTML = `<source src="${path}" type="${label}">Your browser does not support this audio format.`;
335+
audio.onerror = () => {
336+
contentArea.innerHTML = `<span style="color:#4a6080;font-family:monospace;font-size:.8rem">file not found: ${path}</span>`;
337+
};
338+
contentArea.innerHTML = '';
339+
contentArea.appendChild(audio);
340+
}
341+
}
342+
</script>
343+
</body>
344+
</html>

www/test-files/test.gif

275 KB
Loading

www/test-files/test.jpeg

8.96 KB
Loading
File renamed without changes.

www/test-files/test.mp3

149 KB
Binary file not shown.

www/test-files/test.mp4

98.2 KB
Binary file not shown.

www/test-files/test.pdf

9.15 KB
Binary file not shown.

www/test-files/test.png

22.6 KB
Loading

www/test-files/test.svg

Lines changed: 3 additions & 0 deletions
Loading

www/test-files/test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

0 commit comments

Comments
 (0)