Compare commits

..

7 Commits

Author SHA1 Message Date
sigoden
e9383d71ed chore(release): version v0.15.0 2022-06-10 08:41:51 +08:00
sigoden
8258dabe4a fix: query dir param 2022-06-10 08:00:27 +08:00
Joe Koop
0e236b61f6 feat: add empty state placeholder to page(#30)
* added "Empty folder" text to the page

* added text for nonexistent directory and no search results
2022-06-10 07:41:09 +08:00
sigoden
09788ed031 chore: update favicon 2022-06-09 22:49:01 +08:00
Joe Koop
46ebe978ae feat: add basic dark theme (#29) 2022-06-09 22:16:43 +08:00
sigoden
e01f2030e1 chore: optimize code 2022-06-09 21:35:52 +08:00
Joe Koop
8d03ec151a fix: encode webdav href as uri (#28)
* Revert "fix: filename xml escaping"

This reverts commit ce154d9ebc.

* webdav filenames are fixed
2022-06-09 21:28:35 +08:00
7 changed files with 86 additions and 15 deletions

View File

@@ -2,6 +2,18 @@
All notable changes to this project will be documented in this file.
## [0.15.0] - 2022-06-10
### Bug Fixes
- Encode webdav href as uri ([#28](https://github.com/sigoden/duf/issues/28))
- Query dir param
### Features
- Add basic dark theme ([#29](https://github.com/sigoden/duf/issues/29))
- Add empty state placeholder to page([#30](https://github.com/sigoden/duf/issues/30))
## [0.14.0] - 2022-06-07
### Bug Fixes

2
Cargo.lock generated
View File

@@ -286,7 +286,7 @@ dependencies = [
[[package]]
name = "duf"
version = "0.14.0"
version = "0.15.0"
dependencies = [
"async-walkdir",
"async_zip",

View File

@@ -1,6 +1,6 @@
[package]
name = "duf"
version = "0.14.0"
version = "0.15.0"
edition = "2021"
authors = ["sigoden <sigoden@gmail.com>"]
description = "Duf is a simple file server."

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@@ -97,6 +97,11 @@ body {
padding: 0 1em;
}
.empty-folder {
display: block;
padding-top: 1rem;
}
.uploaders-table th,
.paths-table th {
text-align: left;
@@ -173,3 +178,39 @@ body {
.uploader {
padding-right: 1em;
}
/* dark theme */
@media (prefers-color-scheme: dark) {
body {
background-color: #000;
}
html,
.breadcrumb>b,
.searchbar #search {
color: #fff;
}
.uploaders-table th,
.paths-table th {
color: #ddd;
}
svg,
.path svg {
fill: #d0e6ff;
}
.searchbar {
background-color: #111;
border-color: #fff6;
}
.searchbar svg {
fill: #fff6;
}
.path a {
color: #3191ff;
}
}

View File

@@ -7,6 +7,12 @@
* @property {number} size
*/
// https://stackoverflow.com/a/901144/3642588
const params = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop),
});
const dirEmptyNote = params.q ? 'No results' : DATA.dir_exists ? 'Empty folder' : 'Folder will be created when a file is uploaded';
/**
* @type Element
@@ -54,6 +60,7 @@ class Uploader {
</tr>`);
$uploadersTable.classList.remove("hidden");
this.$uploadStatus = document.getElementById(`uploadStatus${idx}`);
document.querySelector('.main i.empty-folder').remove();
const ajax = new XMLHttpRequest();
ajax.upload.addEventListener("progress", e => this.progress(e), false);
@@ -180,6 +187,8 @@ async function deletePath(index) {
DATA.paths[index] = null;
if (!DATA.paths.find(v => !!v)) {
$pathsTable.classList.add("hidden");
document.querySelector('.main').insertAdjacentHTML("afterbegin", '<i class="empty-folder"></i>');
document.querySelector('.main .empty-folder').textContent = dirEmptyNote;
}
} else {
throw new Error(await res.text())
@@ -275,6 +284,10 @@ function ready() {
$pathsTableBody = document.querySelector(".paths-table tbody");
$uploadersTable = document.querySelector(".uploaders-table");
if (params.q) {
document.getElementById('search').value = params.q;
}
addBreadcrumb(DATA.breadcrumb);
if (Array.isArray(DATA.paths)) {
const len = DATA.paths.length;
@@ -284,6 +297,10 @@ function ready() {
for (let i = 0; i < len; i++) {
addPath(DATA.paths[i], i);
}
if (len == 0) {
document.querySelector('.main').insertAdjacentHTML("afterbegin", '<i class="empty-folder"></i>');
document.querySelector('.main .empty-folder').textContent = dirEmptyNote;
}
}
if (DATA.allow_upload) {
dropzone();

View File

@@ -191,8 +191,8 @@ impl InnerService {
self.handle_render_index(path, headers, &mut res).await?;
} else if query == "zip" {
self.handle_zip_dir(path, &mut res).await?;
} else if query.starts_with("q=") {
self.handle_query_dir(path, &query[3..], &mut res).await?;
} else if let Some(q) = query.strip_prefix("q=") {
self.handle_query_dir(path, q, &mut res).await?;
} else {
self.handle_ls_dir(path, true, &mut res).await?;
}
@@ -325,7 +325,7 @@ impl InnerService {
}
}
};
self.send_index(path, paths, res)
self.send_index(path, paths, res, exist)
}
async fn handle_query_dir(
@@ -354,7 +354,7 @@ impl InnerService {
}
}
}
self.send_index(path, paths, res)
self.send_index(path, paths, res, true)
}
async fn handle_zip_dir(&self, path: &Path, res: &mut Response) -> BoxResult<()> {
@@ -645,6 +645,7 @@ impl InnerService {
path: &Path,
mut paths: Vec<PathItem>,
res: &mut Response,
exist: bool,
) -> BoxResult<()> {
paths.sort_unstable();
let rel_path = match self.args.path.parent() {
@@ -656,6 +657,7 @@ impl InnerService {
paths,
allow_upload: self.args.allow_upload,
allow_delete: self.args.allow_delete,
dir_exists: exist,
};
let data = serde_json::to_string(&data).unwrap();
let output = INDEX_HTML.replace(
@@ -802,6 +804,7 @@ struct IndexData {
paths: Vec<PathItem>,
allow_upload: bool,
allow_delete: bool,
dir_exists: bool,
}
#[derive(Debug, Serialize, Eq, PartialEq, Ord, PartialOrd)]
@@ -816,10 +819,12 @@ struct PathItem {
impl PathItem {
pub fn to_dav_xml(&self, prefix: &str) -> String {
let mtime = Utc.timestamp_millis(self.mtime as i64).to_rfc2822();
let href = encode_uri(&format!("{}{}", prefix, &self.name));
let displayname = escape_str_pcdata(&self.base_name);
match self.path_type {
PathType::Dir | PathType::SymlinkDir => format!(
r#"<D:response>
<D:href>{}{}</D:href>
<D:href>{}</D:href>
<D:propstat>
<D:prop>
<D:displayname>{}</D:displayname>
@@ -829,14 +834,11 @@ impl PathItem {
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>"#,
escape_str_pcdata(prefix),
escape_str_pcdata(&self.name),
escape_str_pcdata(&self.base_name),
mtime
href, displayname, mtime
),
PathType::File | PathType::SymlinkFile => format!(
r#"<D:response>
<D:href>{}{}</D:href>
<D:href>{}</D:href>
<D:propstat>
<D:prop>
<D:displayname>{}</D:displayname>
@@ -847,9 +849,8 @@ impl PathItem {
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>"#,
escape_str_pcdata(prefix),
escape_str_pcdata(&self.name),
escape_str_pcdata(&self.base_name),
href,
displayname,
self.size.unwrap_or_default(),
mtime
),