diff --git a/static/css/upload.css b/static/css/upload.css
index 78226ca..f74ff49 100644
--- a/static/css/upload.css
+++ b/static/css/upload.css
@@ -34,6 +34,59 @@
border: 1px dotted #000000;
}
+.upload-dropzone.is-dragging {
+ background: #c7d8f2;
+ outline: 2px solid #000078;
+ outline-offset: -4px;
+}
+
+.upload-dropzone:focus-visible {
+ outline: 1px dotted #000000;
+ outline-offset: -5px;
+}
+
+.upload-icon {
+ width: 34px;
+ height: 30px;
+ position: relative;
+ box-sizing: border-box;
+ background: #ffffff;
+ border: 2px solid #000000;
+ box-shadow: inset -3px -3px 0 #dfdfdf;
+}
+
+.upload-icon::before {
+ content: "";
+ position: absolute;
+ right: -2px;
+ top: -2px;
+ width: 10px;
+ height: 10px;
+ box-sizing: border-box;
+ background: #dfdfdf;
+ border-left: 2px solid #000000;
+ border-bottom: 2px solid #000000;
+}
+
+.upload-primary {
+ font-size: 18px;
+ line-height: 18px;
+ font-weight: bold;
+}
+
+.upload-secondary {
+ font-size: 13px;
+ line-height: 15px;
+}
+
+.upload-input {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+}
+
.upload-options {
flex: 0 0 auto;
display: grid;
@@ -104,59 +157,6 @@
background: #c0c0c0;
}
-.upload-dropzone.is-dragging {
- background: #c7d8f2;
- outline: 2px solid #000078;
- outline-offset: -4px;
-}
-
-.upload-dropzone:focus-visible {
- outline: 1px dotted #000000;
- outline-offset: -5px;
-}
-
-.upload-icon {
- width: 34px;
- height: 30px;
- position: relative;
- box-sizing: border-box;
- background: #ffffff;
- border: 2px solid #000000;
- box-shadow: inset -3px -3px 0 #dfdfdf;
-}
-
-.upload-icon::before {
- content: "";
- position: absolute;
- right: -2px;
- top: -2px;
- width: 10px;
- height: 10px;
- box-sizing: border-box;
- background: #dfdfdf;
- border-left: 2px solid #000000;
- border-bottom: 2px solid #000000;
-}
-
-.upload-primary {
- font-size: 18px;
- line-height: 18px;
- font-weight: bold;
-}
-
-.upload-secondary {
- font-size: 13px;
- line-height: 15px;
-}
-
-.upload-input {
- position: absolute;
- width: 1px;
- height: 1px;
- overflow: hidden;
- clip: rect(0, 0, 0, 0);
-}
-
.upload-details {
flex: 0 0 auto;
display: flex;
@@ -280,25 +280,10 @@
.upload-file-icon {
grid-row: 1 / 3;
- width: 16px;
+ width: 18px;
height: 18px;
- position: relative;
- box-sizing: border-box;
- background: #ffffff;
- border: 1px solid #000000;
- box-shadow: inset -2px -2px 0 #dfdfdf;
-}
-
-.upload-file-icon::before {
- content: "";
- position: absolute;
- top: -1px;
- right: -1px;
- width: 5px;
- height: 5px;
- background: #dfdfdf;
- border-left: 1px solid #000000;
- border-bottom: 1px solid #000000;
+ object-fit: contain;
+ image-rendering: pixelated;
}
.upload-file-name,
diff --git a/static/css/window.css b/static/css/window.css
index 82507e0..340fd7d 100644
--- a/static/css/window.css
+++ b/static/css/window.css
@@ -26,14 +26,34 @@
}
.win98-titlebar h1 {
+ min-width: 0;
margin: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
font-size: 14px;
line-height: 14px;
font-weight: bold;
}
+.win98-titlebar-label {
+ display: flex;
+ align-items: center;
+ min-width: 0;
+ gap: 5px;
+}
+
+.win98-titlebar-icon {
+ flex: 0 0 auto;
+ width: 16px;
+ height: 16px;
+ object-fit: contain;
+ image-rendering: pixelated;
+}
+
.win98-window-controls {
display: flex;
+ flex: 0 0 auto;
gap: 2px;
}
diff --git a/static/js/app.js b/static/js/app.js
index 2abc5cc..a7c8d58 100644
--- a/static/js/app.js
+++ b/static/js/app.js
@@ -36,6 +36,50 @@ function formatBytes(bytes) {
return `${size.toFixed(1)} ${units[unitIndex]}`;
}
+function iconForFile(file) {
+ const filename = file.name || "";
+ const mimeType = file.type || "";
+ const extension = filename.includes(".") ? filename.slice(filename.lastIndexOf(".")).toLowerCase() : "";
+
+ if (extension === ".exe") {
+ return "/static/img/icons/Program Files Icons - PNG/MSONSEXT.DLL_14_6-0.png";
+ }
+
+ if (mimeType.startsWith("image/")) {
+ return "/static/img/sprites/bitmap.png";
+ }
+
+ if (mimeType.startsWith("video/") || mimeType.startsWith("audio/")) {
+ return "/static/img/icons/netshow_notransm-1.png";
+ }
+
+ if (mimeType.startsWith("text/") || extension === ".md") {
+ return "/static/img/sprites/notepad_file-1.png";
+ }
+
+ if (
+ mimeType.includes("zip") ||
+ mimeType.includes("compressed") ||
+ [".rar", ".7z", ".tar", ".gz"].includes(extension)
+ ) {
+ return "/static/img/icons/Windows Icons - PNG/zipfldr.dll_14_101-0.png";
+ }
+
+ if ([".ttf", ".otf", ".woff", ".woff2"].includes(extension)) {
+ return "/static/img/sprites/font.png";
+ }
+
+ if (extension === ".pdf") {
+ return "/static/img/sprites/journal.png";
+ }
+
+ if ([".html", ".css", ".js"].includes(extension)) {
+ return "/static/img/sprites/frame_web-0.png";
+ }
+
+ return "/static/img/icons/Windows Icons - PNG/ole2.dll_14_DEFICON.png";
+}
+
function updateStatus(message) {
if (uploadStatus) {
uploadStatus.textContent = message;
@@ -124,8 +168,10 @@ function createFileRow(selectedFile) {
const row = document.createElement("div");
row.className = "upload-file-row";
- const icon = document.createElement("span");
+ const icon = document.createElement("img");
icon.className = "upload-file-icon";
+ icon.src = iconForFile(selectedFile.file);
+ icon.alt = "";
icon.setAttribute("aria-hidden", "true");
const name = document.createElement("span");
@@ -391,6 +437,10 @@ if (uploadForm) {
selectedFiles.forEach((selectedFile, index) => {
selectedFile.boxID = box.box_id;
selectedFile.boxFile = box.files[index];
+ const icon = selectedFile.row.querySelector(".upload-file-icon");
+ if (icon && selectedFile.boxFile.icon_path) {
+ icon.src = selectedFile.boxFile.icon_path;
+ }
});
await Promise.allSettled(selectedFiles.map((selectedFile) => {
diff --git a/templates/box.html b/templates/box.html
index 3607327..7e9dfbf 100644
--- a/templates/box.html
+++ b/templates/box.html
@@ -4,6 +4,7 @@
WarpBox - {{ .BoxID }}
+
@@ -14,7 +15,10 @@