updated styling pt.2

This commit is contained in:
2025-11-25 21:07:48 +01:00
parent 98d199b6d1
commit b448ded507
3 changed files with 133 additions and 36 deletions

View File

@@ -49,14 +49,15 @@ body {
color: var(--text-primary);
line-height: 1.6;
transition: background-color 0.3s ease, color 0.3s ease;
overflow: hidden;
}
.container {
margin: 4vh;
padding: 0;
min-height: 100vh;
display: flex;
flex-direction: column;
height: 92vh;
}
.header {
@@ -131,9 +132,23 @@ body {
}
.theme-toggle {
width: 1.75rem;
height: 1.75rem;
padding: 0;
border: none;
background: var(--text-secondary);
-webkit-mask: var(--icon) center/60% no-repeat;
mask: var(--icon) center/60% no-repeat;
-webkit-mask-size: 60%;
mask-size: 60%;
background-repeat: no-repeat;
background-position: center;
border-radius: 6px;
cursor: pointer;
}
.theme-toggle:active {
transform: scale(0.98);
}
.btn:hover {
@@ -147,15 +162,16 @@ body {
}
.content {
padding: 1.5rem;
padding: 0 1.5rem;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
border-bottom: 1px solid var(--border-color);
background-color: var(--bg-secondary);
transition: background-color 0.3s ease, border-color 0.3s ease;
overflow: scroll;
height: 100%;
}
.meta {
@@ -221,6 +237,13 @@ body {
overflow-x: auto;
}
.file-row a,
.btn,
.theme-toggle {
outline: none;
-webkit-tap-highlight-color: transparent;
}
.file-list {
display: flex;
flex-direction: column;
@@ -229,14 +252,11 @@ body {
background: transparent;
border-radius: 0.25rem;
overflow: hidden;
/* if you want a border around the whole list: */
/* border: 1px solid var(--border-color); */
}
/* Each row uses grid to emulate columns */
.file-row {
display: grid;
grid-template-columns: 2.5rem 1fr 10.5rem 14rem; /* icon | name | size | modified */
grid-template-columns: 2.5rem 1fr 10.5rem 14rem;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
@@ -246,12 +266,22 @@ body {
background: transparent;
}
/* last row - optional: remove border */
.file-row > div:first-child {
display: flex;
align-items: center;
justify-content: center;
align-self: center;
}
.file-row .name {
align-self: center;
display: block;
}
.file-list .file-row:last-child {
border-bottom: none;
}
/* icon cell (keeps the look from your table td.icon) */
.file-row > div:first-child {
width: 2.5rem;
height: 2rem;
@@ -263,20 +293,26 @@ body {
/* name cell */
.file-row .name {
display: flex;
align-items: center; /* vertically center the link text with the icon */
min-width: 0; /* allow ellipsis to work inside flex items */
font-weight: 500;
color: var(--text-primary);
overflow: hidden;
overflow: hidden; /* keep long names from breaking layout */
text-overflow: ellipsis;
white-space: nowrap;
}
/* name link */
.file-row .name a {
color: inherit;
text-decoration: none;
display: inline-block;
display: block; /* block-level so height:100% works reliably */
width: 100%;
overflow: hidden;
height: 100%; /* fill the .name (including padding row gives) */
line-height: 1.2; /* control baseline — tweak if you want tighter/looser text */
text-decoration: none;
color: inherit;
padding: 0; /* avoid extra internal vertical padding */
overflow: hidden; /* ensure ellipsis works on the link text */
text-overflow: ellipsis;
white-space: nowrap;
}
@@ -302,8 +338,7 @@ body {
}
/* hover / focus */
.file-row:hover,
.file-row:focus-within {
.file-row:hover {
background-color: var(--file-hover);
}
@@ -311,11 +346,6 @@ body {
transform: translateY(0.5px);
}
.file-row a:focus {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.file-list.compact .file-row {
padding: 0.5rem;
grid-template-columns: 2rem 1fr 8.5rem 12rem;
@@ -347,13 +377,15 @@ body {
grid-template-columns: 2.5rem 1fr;
grid-template-rows: auto auto;
gap: 0.25rem 0.5rem;
align-items: start;
align-items: center; /* center items rather than start */
padding: 0.6rem;
}
.file-row > div:first-child {
grid-row: 1 / span 2;
align-self: start;
align-self: center; /* was start, now center */
width: 2.5rem;
height: 2.5rem; /* slightly bigger on mobile for touch */
}
.file-row .name {
@@ -361,6 +393,14 @@ body {
grid-row: 1;
white-space: normal;
overflow: visible;
align-self: center;
}
@media (max-width: 480px) {
.file-row .name a {
padding-left: 4px;
padding-right: 4px;
}
}
.file-row .size {
@@ -376,6 +416,15 @@ body {
}
}
@media (max-width: 480px) {
.theme-toggle {
width: 1.5rem;
height: 1.5rem;
-webkit-mask-size: 56%;
mask-size: 56%;
}
}
.view-list .file-list {
display: block;
}

View File

@@ -13,7 +13,7 @@
<div class="container">
<div class="header">
<div class="breadcrumbs">Folder Path</div>
<div class="path-container" id="pathContainer">
<div class="path-container">
@{directory}
</div>
<div class="controls">
@@ -27,8 +27,8 @@
</div>
<div class="content">
<div class="listing" id="listing">
<div class="file-list" id="fileList">
<div class="listing">
<div class="file-list">
@{files}
</div>
</div>

View File

@@ -3,6 +3,7 @@ module util
import os
import time
import encoding.base64
pub struct Database {
pub:
@@ -32,10 +33,51 @@ pub:
is_dir bool
size i64
modified i64
icon string
}
pub struct Utility {}
pub fn Utility.get_icon(ext string, is_dir bool) string {
icons := {
'dir': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640v400q0 33-23.5 56.5T800-160H160Zm0-80h640v-400H447l-80-80H160v480Zm0 0v-480 480Z"/></svg>' //'icon-dir'
'pdf': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/></svg>' // 'icon-pdf',
'txt': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M280-280h280v-80H280v80Zm0-160h400v-80H280v80Zm0-160h400v-80H280v80Zm-80 480q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z"/></svg>'
'md': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M280-280h280v-80H280v80Zm0-160h400v-80H280v80Zm0-160h400v-80H280v80Zm-80 480q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z"/></svg>'
'json': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg>'
'xml': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg>'
'jpg': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z"/></svg>'
'jpeg': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z"/></svg>'
'png': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z"/></svg>'
'gif': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z"/></svg>'
'svg': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z"/></svg>'
'zip': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M640-480v-80h80v80h-80Zm0 80h-80v-80h80v80Zm0 80v-80h80v80h-80ZM447-640l-80-80H160v480h400v-80h80v80h160v-400H640v80h-80v-80H447ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640v400q0 33-23.5 56.5T800-160H160Zm0-80v-480 480Z"/></svg>'
'rar': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M640-480v-80h80v80h-80Zm0 80h-80v-80h80v80Zm0 80v-80h80v80h-80ZM447-640l-80-80H160v480h400v-80h80v80h160v-400H640v80h-80v-80H447ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640v400q0 33-23.5 56.5T800-160H160Zm0-80v-480 480Z"/></svg>'
'7z': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M640-480v-80h80v80h-80Zm0 80h-80v-80h80v80Zm0 80v-80h80v80h-80ZM447-640l-80-80H160v480h400v-80h80v80h160v-400H640v80h-80v-80H447ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640v400q0 33-23.5 56.5T800-160H160Zm0-80v-480 480Z"/></svg>'
'mp3': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M430-200q38 0 64-26t26-64v-150h120v-80H480v155q-11-8-23.5-11.5T430-380q-38 0-64 26t-26 64q0 38 26 64t64 26ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/></svg>'
'mp4': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M360-240h160q17 0 28.5-11.5T560-280v-40l80 42v-164l-80 42v-40q0-17-11.5-28.5T520-480H360q-17 0-28.5 11.5T320-440v160q0 17 11.5 28.5T360-240ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/></svg>'
'avi': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M360-240h160q17 0 28.5-11.5T560-280v-40l80 42v-164l-80 42v-40q0-17-11.5-28.5T520-480H360q-17 0-28.5 11.5T320-440v160q0 17 11.5 28.5T360-240ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/></svg>'
'mov': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M360-240h160q17 0 28.5-11.5T560-280v-40l80 42v-164l-80 42v-40q0-17-11.5-28.5T520-480H360q-17 0-28.5 11.5T320-440v160q0 17 11.5 28.5T360-240ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/></svg>'
'java': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg>'
'py': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg>'
'js': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg>'
'ts': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg>'
'v': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg>'
'html': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm0-80h420v-140H160v140Zm500 0h140v-360H660v360ZM160-460h420v-140H160v140Z"/></svg>'
'css': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm0-80h420v-140H160v140Zm500 0h140v-360H660v360ZM160-460h420v-140H160v140Z"/></svg>'
'exe': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm0-80h640v-400H160v400Zm140-40-56-56 103-104-104-104 57-56 160 160-160 160Zm180 0v-80h240v80H480Z"/></svg>'
'unknown': '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/></svg>'
}
return Utility.svg_to_data_uri(if is_dir { icons['dir'] } else { icons[ext] or {
icons['unknown']} })
}
pub fn Utility.svg_to_data_uri(svg string) string {
return svg
// return 'data:image/svg+xml;base64,${base64.encode(svg.bytes())}'
}
pub fn Utility.format_size(bytes i64) string {
if bytes == 0 {
return '-'
@@ -70,6 +112,7 @@ pub fn Utility.list_files(dir_path string, relative string) ![]FileEntry {
full_path := os.join_path(dir_path, file)
is_dir := os.is_dir(full_path)
file_info := os.stat(full_path)!
file_ext := full_path.split('.').last()
entries << FileEntry{
name: if is_dir { '${file}/' } else { file }
@@ -78,6 +121,7 @@ pub fn Utility.list_files(dir_path string, relative string) ![]FileEntry {
is_dir: is_dir
size: if !is_dir { file_info.size } else { 0 }
modified: file_info.mtime
icon: Utility.get_icon(file_ext, is_dir)
}
}
@@ -139,7 +183,7 @@ pub fn HtmlBuilder.generate_file_list(entries []FileEntry, current_path string)
return '<div class="empty-state"><p>This folder is empty</p></div>', '<span class="meta-item"><b>0</b> directories</span><span class="meta-item"><b>0</b> files</span><span class="meta-item"><b>0B</b> total</span>'
}
mut html := '<table class="file-table"><thead><tr><th></th><th>Name</th><th>Size</th><th>Modified</th></tr></thead><tbody>'
mut html := '<div class="file-list">'
mut dir_count := 0
mut file_count := 0
@@ -149,21 +193,25 @@ pub fn HtmlBuilder.generate_file_list(entries []FileEntry, current_path string)
if entry.is_dir {
dir_count++
file_class := 'directory'
html += '<tr class="file-row ${file_class}"><td>icon</td>'
html += '<td class="name"><a href="${entry.path}">${entry.name}</a></td>'
html += '<td class="size">-</td>'
html += '<td class="date">${Utility.format_date(entry.modified)}</td></tr>'
html += '<div class="file-row ${file_class}">'
html += '<div>${entry.icon}</div>'
html += '<div class="name"><a href="${entry.path}">${entry.name}</a></div>'
html += '<div class="size">-</div>'
html += '<div class="date">${Utility.format_date(entry.modified)}</div>'
html += '</div>'
} else {
file_count++
total_size += entry.size
html += '<tr class="file-row file"><td>icon</td>'
html += '<td class="name"><a href="${entry.path}">${entry.name}</a></td>'
html += '<td class="size">${Utility.format_size(entry.size)}</td>'
html += '<td class="date">${Utility.format_date(entry.modified)}</td></tr>'
html += '<div class="file-row file">'
html += '<div>${entry.icon}</div>'
html += '<div class="name"><a href="${entry.path}">${entry.name}</a></div>'
html += '<div class="size">${Utility.format_size(entry.size)}</div>'
html += '<div class="date">${Utility.format_date(entry.modified)}</div>'
html += '</div>'
}
}
html += '</tbody></table>'
html += '</div>'
return html, '<span class="meta-item"><b>${dir_count}</b> directories</span><span class="meta-item"><b>${file_count}</b> files</span><span class="meta-item"><b>${Utility.format_size(total_size)}</b> total</span>'
}