chore (rewrite): improve user experience

This commit is contained in:
MickaelK 2024-07-05 18:31:04 +10:00
parent 3c47bb15ac
commit 591e50053c
8 changed files with 43 additions and 20 deletions

View file

@ -45,7 +45,10 @@ class Loader extends window.HTMLElement {
customElements.define("component-loader", Loader);
export function createLoader($parent, opts = {}) {
const { wait = 250 } = opts;
const {
wait = 250,
append = ($loader) => $parent.appendChild($loader),
} = opts;
const $icon = createElement(`
<div class="component_loader">
<style>
@ -58,16 +61,13 @@ export function createLoader($parent, opts = {}) {
<component-icon name="loading"></component-icon>
</div>
`);
let $cache = null;
const id = window.setTimeout(() => {
$cache = $parent;
$parent.appendChild($icon);
append($icon);
animate($icon, { time: 750, keyframes: opacityIn() });
}, wait);
const cancel = () => {
clearTimeout(id);
if(!$cache) return;
$icon.remove();
};

View file

@ -33,17 +33,22 @@
margin-left: -3px;
margin-right: -3px;
}
.touch-yes [is="component_submenu"] .component_submenu .action button img {
width: 16px;
height: 16px;
}
[is="component_submenu"] .component_submenu .action.left {
margin-right: 2px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: flex;
}
[is="component_submenu"] .component_submenu .action.right:hover,
.touch-no [is="component_submenu"] .component_submenu .action.right:hover,
[is="component_submenu"] .component_submenu .action.right.hover{
background: var(--border);
}
[is="component_submenu"] .component_submenu .action button:hover {
.touch-no [is="component_submenu"] .component_submenu .action button:hover {
filter: brightness(0.9);
background: var(--border);
}

View file

@ -104,10 +104,13 @@ export function createThing({
$placeholder.classList.add("placeholder");
$placeholder.setAttribute("src", IMAGE.THUMBNAIL_PLACEHOLDER);
$img.parentElement.appendChild($placeholder);
$img.setAttribute("src", "api/files/cat?path=" + encodeURIComponent(path) + "&thumbnail=true");
$img.src = "api/files/cat?path=" + encodeURIComponent(path) + "&thumbnail=true";
$img.loaded = false;
const t = new Date();
$img.onload = async () => {
const duration = new Date() - t;
$img.loaded = true;
await Promise.all([
animate($img, {
keyframes: opacityIn(),
@ -120,6 +123,15 @@ export function createThing({
]);
$placeholder.remove();
};
const id = setInterval(() => { // cancellation when image is outside the viewport
if ($img.loaded === true) return clearInterval(id);
else if (typeof $thing.checkVisibility !== "function") return clearInterval(id);
else if ($thing.checkVisibility() === false) {
$img.src = "";
clearInterval(id);
return;
}
}, 250);
}
if (loading) {

View file

@ -23,7 +23,9 @@ export default function(render) {
// feature1: setup the dom
const $epub = qs($page, `[data-bind="epub"]`);
const removeLoader = createLoader($page);
const removeLoader = createLoader($page, {
append: ($loader) => $page.insertBefore($loader, qs($page, ".ebookviewer_container")),
});
const setup$ = rxjs.of($epub).pipe(
rxjs.mergeMap(async($epub) => {
const book = new window.ePub.Book({
@ -42,12 +44,10 @@ export default function(render) {
rendition.destroy();
});
book.open(getDownloadUrl());
await new Promise((done) => {
rendition.hooks.render.register(() => {
rendition$.next(rendition);
done();
});
});
await new Promise((done) => rendition.hooks.render.register(() => {
rendition$.next(rendition);
done();
}));
}),
removeLoader,
rxjs.catchError(ctrlError()),

View file

@ -19,7 +19,7 @@ export default function(render) {
<component-menubar></component-menubar>
<div class="component_image_container">
<div class="images_wrapper">
<img class="photo idle hidden" draggable="true" src="${getDownloadUrl()}">
<img class="photo idle hidden" src="${getDownloadUrl()}&size=${window.innerWidth}">
</div>
<div class="images_aside scroll-y"></div>
<div class="component_pager hidden"></div>

View file

@ -27,12 +27,14 @@
}
.component_menubar .action-item {
padding-right: 10px;
display: flex;
align-items: center;
}
.component_menubar .action-item .component_icon {
height: 19px;
width: 19px;
cursor: pointer;
padding: 9px 2px 0px 2px;
padding: 0 2px;
}
.component_menubar .action-item .download-button .component_icon {
padding-right: 1px;

View file

@ -7,7 +7,10 @@ export const options = () => ajax({
method: "OPTIONS",
}).pipe(rxjs.map((res) => res.responseHeaders.allow.replace(/\r/, "").split(", ")));
export const cat = () => ajax(getDownloadUrl()).pipe(
export const cat = () => ajax({
url: getDownloadUrl(),
method: "GET",
}).pipe(
rxjs.map(({ response }) => response),
);

View file

@ -34,12 +34,13 @@ func init() {
Hooks.Register.ProcessFileContentBeforeSend(func(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
if GetMimeType(req.URL.Query().Get("path")) != "image/svg+xml" {
return reader, nil
} else if disable_svg() == true {
return reader, ErrNotAllowed
} else if disable_svg() == false {
return reader, nil
}
// XSS
(*res).Header().Set("Content-Security-Policy", "script-src 'none'; default-src 'none'; img-src 'self'")
(*res).Header().Set("Content-Type", "text/plain")
// XML bomb
txt, _ := ioutil.ReadAll(reader)
if regexp.MustCompile("(?is)entity").Match(txt) {