mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2024-04-21 12:32:08 +00:00
chore (rewrite): viewerpage refactoring
This commit is contained in:
@@ -9,7 +9,7 @@ export default async function main() {
|
||||
try {
|
||||
await Promise.all([ // procedure with no outside dependencies
|
||||
setup_translation(),
|
||||
// setup_xdg_open(),
|
||||
setup_xdg_open(),
|
||||
// setup_cache(), // TODO: dependency on session
|
||||
setup_device(),
|
||||
// setup_sw(), // TODO
|
||||
@@ -92,7 +92,7 @@ function setup_translation() {
|
||||
|
||||
async function setup_xdg_open() {
|
||||
window.overrides = {};
|
||||
await loadJS("/overrides/xdg-open.js");
|
||||
return loadJS(import.meta.url, "/overrides/xdg-open.js");
|
||||
}
|
||||
|
||||
async function setup_device() {
|
||||
|
||||
@@ -1,20 +1,3 @@
|
||||
/* chromecast */
|
||||
:root {
|
||||
--disconnected-color: #F2F2F2;
|
||||
--connected-color: var(--primary);
|
||||
}
|
||||
|
||||
google-cast-launcher {
|
||||
display: inline-block;
|
||||
height: 23px;
|
||||
width: 23px;
|
||||
cursor: pointer;
|
||||
padding: 0 5px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.component_menubar {
|
||||
background: var(--dark);
|
||||
color: #f1f1f1;
|
||||
@@ -63,23 +46,26 @@ google-cast-launcher {
|
||||
width: 21px;
|
||||
}
|
||||
|
||||
.menubar-appear {
|
||||
display: inline-block;
|
||||
opacity: 0;
|
||||
transform: translateY(2px);
|
||||
}
|
||||
|
||||
.menubar-appear.menubar-appear-active {
|
||||
opacity: 1;
|
||||
transform: translateY(0px);
|
||||
transition: all 0.25s ease-out;
|
||||
transition-delay: 0.30s;
|
||||
}
|
||||
|
||||
|
||||
/* icons in additional menu */
|
||||
.component_menubar .action-item [is="component-dropdown"] .dropdown_button {
|
||||
border: none;
|
||||
padding: 2px 0px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* chromecast */
|
||||
:root {
|
||||
--disconnected-color: #F2F2F2;
|
||||
--connected-color: var(--primary);
|
||||
}
|
||||
|
||||
google-cast-launcher {
|
||||
display: inline-block;
|
||||
height: 23px;
|
||||
width: 23px;
|
||||
cursor: pointer;
|
||||
padding: 0 5px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { createElement } from "../lib/skeleton/index.js";
|
||||
import { animate, slideYIn } from "../lib/animate.js";
|
||||
import { basename } from "../lib/path.js";
|
||||
import assert from "../lib/assert.js";
|
||||
import { loadCSS } from "../helpers/loader.js";
|
||||
|
||||
await loadCSS(import.meta.url, "./menubar.css");
|
||||
|
||||
import "./dropdown.js";
|
||||
|
||||
export default class ComponentMenubar extends window.HTMLElement {
|
||||
@@ -26,6 +25,19 @@ export default class ComponentMenubar extends window.HTMLElement {
|
||||
`;
|
||||
}
|
||||
|
||||
async connectedCallback() {
|
||||
await loadCSS(import.meta.url, "./menubar.css");
|
||||
const $title = this.querySelector(".titlebar");
|
||||
$title.style.opacity = 0;
|
||||
this.timeoutID = setTimeout(() => {
|
||||
animate($title, { time: 250, keyframes: slideYIn(2) });
|
||||
}, 300);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
clearTimeout(this.timeoutID);
|
||||
}
|
||||
|
||||
render($fragment) {
|
||||
this.querySelector(".action-item").appendChild($fragment);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ import { qs } from "../../lib/dom.js";
|
||||
import { onDestroy } from "../../lib/skeleton/lifecycle.js";
|
||||
import { loadCSS, loadJS } from "../../helpers/loader.js";
|
||||
import { settings_get, settings_put } from "../../lib/settings.js";
|
||||
import assert from "../../lib/assert.js";
|
||||
|
||||
import ctrlError from "../ctrl_error.js";
|
||||
|
||||
import { ICON } from "./common_icon.js";
|
||||
import { formatTimecode } from "./common_player.js";
|
||||
import { transition, getDownloadUrl } from "./common.js";
|
||||
|
||||
import "../../components/menubar.js";
|
||||
@@ -23,19 +25,22 @@ export default function(render) {
|
||||
<div class="audioplayer_container">
|
||||
<div class="audioplayer_box">
|
||||
<div data-bind="loader" class="hidde">
|
||||
<div class="audioplayer_loader" style="width: 31%;"></div>
|
||||
<span class="percent">31%</span>
|
||||
<div class="audioplayer_loader"></div>
|
||||
<span class="percent"></span>
|
||||
<img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0nMTIwcHgnIGhlaWdodD0nMTIwcHgnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIiBjbGFzcz0idWlsLXJpbmctYWx0Ij4KICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibm9uZSIgY2xhc3M9ImJrIj48L3JlY3Q+CiAgPGNpcmNsZSBjeD0iNTAiIGN5PSI1MCIgcj0iNDAiIHN0cm9rZT0ibm9uZSIgZmlsbD0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48L2NpcmNsZT4KICA8Y2lyY2xlIGN4PSI1MCIgY3k9IjUwIiByPSI0MCIgc3Ryb2tlPSIjNmY2ZjZmIiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+CiAgICA8YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJzdHJva2UtZGFzaG9mZnNldCIgZHVyPSIycyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIGZyb209IjAiIHRvPSI1MDIiPjwvYW5pbWF0ZT4KICAgIDxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9InN0cm9rZS1kYXNoYXJyYXkiIGR1cj0iMnMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB2YWx1ZXM9IjE1MC42IDEwMC40OzEgMjUwOzE1MC42IDEwMC40Ij48L2FuaW1hdGU+CiAgPC9jaXJjbGU+Cjwvc3ZnPgo=" alt="loading">
|
||||
</div>
|
||||
<div id="waveform"></div>
|
||||
<div class="audioplayer_control" style="opacity: 1;">
|
||||
<div class="audioplayer_control hidden">
|
||||
<div class="buttons no-select">
|
||||
<span>
|
||||
<img class="component_icon" draggable="false" src="${ICON.PLAY}" alt="play">
|
||||
<img class="component_icon hidden" draggable="false" src="${ICON.PAUSE}" alt="pause">
|
||||
<component-icon name="loading" class="hidden"></component-icon>
|
||||
</span>
|
||||
<span>
|
||||
<img class="component_icon" draggable="false" src="${ICON.VOLUME_NORMAL}" alt="volume">
|
||||
<img class="component_icon hidden" draggable="false" src="${ICON.VOLUME_MUTE}" alt="volume_mute">
|
||||
<img class="component_icon hidden" draggable="false" src="${ICON.VOLUME_LOW}" alt="volume_low">
|
||||
<img class="component_icon hidden" draggable="false" src="${ICON.VOLUME_NORMAL}" alt="volume">
|
||||
</span>
|
||||
<input type="range" min="0" max="100" value="52">
|
||||
</div>
|
||||
@@ -53,23 +58,75 @@ export default function(render) {
|
||||
transition(qs($page, ".audioplayer_box"));
|
||||
|
||||
const $control = {
|
||||
main: qs($page, `.audioplayer_control`),
|
||||
|
||||
play: qs($page, `.audioplayer_control [alt="play"]`),
|
||||
pause: qs($page, `.audioplayer_control [alt="pause"]`),
|
||||
// loading: qs($page, `.audioplayer_control component-icon[name="loading"]`),
|
||||
loading: qs($page, `.audioplayer_control component-icon[name="loading"]`),
|
||||
};
|
||||
const $volume = {
|
||||
range: qs($page, `input[type="range"]`),
|
||||
// icon_mute: qs($page, `img[alt="volume_mute"]`),
|
||||
// icon_low: qs($page, `img[alt="volume_low"]`),
|
||||
// icon_normal: qs($page, `img[alt="volume"]`),
|
||||
};
|
||||
const setVolume = (volume, wavesurfer) => {
|
||||
wavesurfer.setVolume(volume / 100);
|
||||
icon_mute: qs($page, `img[alt="volume_mute"]`),
|
||||
icon_low: qs($page, `img[alt="volume_low"]`),
|
||||
icon_normal: qs($page, `img[alt="volume"]`),
|
||||
};
|
||||
const currentTime$ = new rxjs.BehaviorSubject([
|
||||
0, // time of lastSeek: we want to start from the start
|
||||
0, // seek offset to align with wavesurfer currentTime in the audiocontext
|
||||
0, // starting time - does change when seeking to another point
|
||||
0, // offset to align the audio context currentTime. otherwise when seeking, the
|
||||
// currentTime keep growing and progress bar goes haywire
|
||||
]);
|
||||
const currentTime = (wavesurfer) => {
|
||||
return currentTime$.value[0] + (wavesurfer.backend.ac.currentTime - currentTime$.value[1]);
|
||||
};
|
||||
const setVolume = (volume, wavesurfer) => {
|
||||
settings_put("volume", volume);
|
||||
wavesurfer.setVolume(volume / 100);
|
||||
$volume.range.value = volume;
|
||||
if (volume === 0) {
|
||||
$volume.icon_mute.classList.remove("hidden");
|
||||
$volume.icon_low.classList.add("hidden");
|
||||
$volume.icon_normal.classList.add("hidden");
|
||||
} else if (volume < 50) {
|
||||
$volume.icon_mute.classList.add("hidden");
|
||||
$volume.icon_low.classList.remove("hidden");
|
||||
$volume.icon_normal.classList.add("hidden");
|
||||
} else {
|
||||
$volume.icon_mute.classList.add("hidden");
|
||||
$volume.icon_low.classList.add("hidden");
|
||||
$volume.icon_normal.classList.remove("hidden");
|
||||
}
|
||||
};
|
||||
const setStatus = (status, wavesurfer) => {
|
||||
switch (status) {
|
||||
case "PLAYING":
|
||||
$control.play.classList.add("hidden");
|
||||
$control.pause.classList.remove("hidden");
|
||||
$control.loading.classList.add("hidden");
|
||||
wavesurfer.backend.ac.resume();
|
||||
break;
|
||||
case "PAUSED":
|
||||
$control.play.classList.remove("hidden");
|
||||
$control.pause.classList.add("hidden");
|
||||
$control.loading.classList.add("hidden");
|
||||
wavesurfer.backend.ac.suspend();
|
||||
break;
|
||||
case "BUFFERING":
|
||||
$control.play.classList.add("hidden");
|
||||
$control.pause.classList.add("hidden");
|
||||
$control.loading.classList.remove("hidden");
|
||||
break;
|
||||
default:
|
||||
assert.fail(status);
|
||||
}
|
||||
}
|
||||
const setSeek = (newTime, wavesurfer) => {
|
||||
currentTime$.next([newTime, wavesurfer.backend.ac.currentTime]);
|
||||
wavesurfer.backend.source.stop(0);
|
||||
wavesurfer.backend.disconnectSource();
|
||||
wavesurfer.backend.createSource();
|
||||
wavesurfer.backend.startPosition = newTime;
|
||||
wavesurfer.backend.source.start(0, newTime);
|
||||
};
|
||||
|
||||
// feature1: setup the dom
|
||||
const setup$ = rxjs.of(qs($page, "#waveform")).pipe(
|
||||
@@ -85,13 +142,16 @@ export default function(render) {
|
||||
barWidth: 1,
|
||||
}))),
|
||||
rxjs.tap((wavesurfer) => {
|
||||
window.audio = wavesurfer; // TODO: remove
|
||||
wavesurfer.load(getDownloadUrl());
|
||||
wavesurfer.on("error", (err) => {
|
||||
wavesurfer.on("error", (err) => { // TODO: one liner to check
|
||||
throw new Error(err)
|
||||
});
|
||||
wavesurfer.on("ready", () => {
|
||||
$control.main.classList.remove("hidden");
|
||||
qs($control.main, "#totalDuration").textContent = formatTimecode(wavesurfer.getDuration());
|
||||
});
|
||||
onDestroy(() => wavesurfer.destroy())
|
||||
}),
|
||||
rxjs.tap((wavesurfer) => onDestroy(() => wavesurfer.destroy())),
|
||||
rxjs.catchError(ctrlError()),
|
||||
rxjs.shareReplay(1),
|
||||
);
|
||||
@@ -115,7 +175,7 @@ export default function(render) {
|
||||
}),
|
||||
));
|
||||
|
||||
// feature3: prepare the data source
|
||||
// feature3: connect the audio
|
||||
const ready$ = setup$.pipe(
|
||||
rxjs.mergeMap((wavesurfer) => new rxjs.Observable((observer) => {
|
||||
wavesurfer.on("ready", () => observer.next(wavesurfer));
|
||||
@@ -127,65 +187,121 @@ export default function(render) {
|
||||
wavesurfer.backend.startPosition = 0;
|
||||
wavesurfer.backend.lastPlay = 0;
|
||||
wavesurfer.backend.source.start(0, 0);
|
||||
wavesurfer.backend.ac.suspend();
|
||||
})));
|
||||
|
||||
// feature: player control - volume
|
||||
// feature4: hint of song progress
|
||||
effect(setup$.pipe(
|
||||
rxjs.mergeMap(() => rxjs.merge(
|
||||
onClick($control.play).pipe(rxjs.mapTo(STATUS_PLAYING)),
|
||||
rxjs.fromEvent(document, "keydown").pipe(rxjs.mapTo(STATUS_PLAYING)),
|
||||
)),
|
||||
rxjs.first(),
|
||||
rxjs.mergeMap((status) => setup$.pipe(rxjs.tap((wavesurfer) => setStatus(status, wavesurfer)))),
|
||||
rxjs.switchMap((wavesurfer) => rxjs.animationFrames().pipe(
|
||||
rxjs.tap(() => {
|
||||
const _currentTime = currentTime(wavesurfer)
|
||||
const percent = _currentTime / wavesurfer.getDuration();
|
||||
if (percent > 1) return;
|
||||
wavesurfer.drawer.progress(percent);
|
||||
qs($control.main, "#currentTime").textContent = formatTimecode(_currentTime);
|
||||
}),
|
||||
)),
|
||||
));
|
||||
|
||||
// feature5: player control - play / pause
|
||||
effect(setup$.pipe(
|
||||
rxjs.mergeMap((wavesurfer) => rxjs.merge(
|
||||
onClick($control.play).pipe(rxjs.mapTo(STATUS_PLAYING)),
|
||||
onClick($control.pause).pipe(rxjs.mapTo(STATUS_PAUSED)),
|
||||
).pipe(
|
||||
rxjs.tap((status) => setStatus(status, wavesurfer)),
|
||||
)),
|
||||
));
|
||||
|
||||
// feature6: player control - volume
|
||||
effect(setup$.pipe(
|
||||
rxjs.switchMap(() => rxjs.fromEvent($volume.range, "input").pipe(rxjs.map((e) => e.target.value))),
|
||||
rxjs.startWith(settings_get("volume") === null ? 80 : settings_get("volume")),
|
||||
rxjs.mergeMap((volume) => setup$.pipe(rxjs.tap((wavesurfer) => setVolume(volume, wavesurfer)))),
|
||||
rxjs.mergeMap((volume) => setup$.pipe(rxjs.tap((wavesurfer) => setVolume(parseInt(volume), wavesurfer)))),
|
||||
));
|
||||
|
||||
// feature: player control - seek
|
||||
effect(setup$.pipe(
|
||||
// feature7: player control - seek
|
||||
effect(ready$.pipe(
|
||||
rxjs.mergeMap((wavesurfer) => rxjs.fromEvent(qs($page, "#waveform"), "click").pipe(
|
||||
rxjs.map((e) => ({ e, wavesurfer })),
|
||||
)),
|
||||
rxjs.map(({ e, wavesurfer }) => {
|
||||
const rec = e.target.getBoundingClientRect();
|
||||
const rec = e.target.closest("#waveform").getBoundingClientRect();
|
||||
return { wavesurfer, progress: (e.clientX - rec.x) / rec.width };
|
||||
}),
|
||||
rxjs.tap(({ progress, wavesurfer }) => {
|
||||
wavesurfer.drawer.progress(progress);
|
||||
|
||||
const newTime = wavesurfer.getDuration() * progress;
|
||||
|
||||
currentTime$.next([newTime, wavesurfer.backend.ac.currentTime]);
|
||||
wavesurfer.backend.source.stop(0);
|
||||
wavesurfer.backend.disconnectSource();
|
||||
wavesurfer.backend.createSource();
|
||||
wavesurfer.backend.startPosition = newTime;
|
||||
wavesurfer.backend.source.start(0, newTime);
|
||||
setSeek(newTime, wavesurfer);
|
||||
}),
|
||||
));
|
||||
|
||||
// feature4: time progression
|
||||
// feature8: player control - keyboard shortcut
|
||||
effect(ready$.pipe(
|
||||
rxjs.mergeMap(() => rxjs.merge(
|
||||
onClick($control.play).pipe(rxjs.mapTo(STATUS_PLAYING)),
|
||||
onClick($control.pause).pipe(rxjs.mapTo(STATUS_PAUSED)),
|
||||
)),
|
||||
rxjs.mergeMap((status) => setup$.pipe(rxjs.tap((wavesurfer) => {
|
||||
switch (status) {
|
||||
case STATUS_PLAYING:
|
||||
wavesurfer.backend.ac.resume();
|
||||
$control.play.classList.add("hidden");
|
||||
$control.pause.classList.remove("hidden");
|
||||
break;
|
||||
case STATUS_PAUSED:
|
||||
wavesurfer.backend.ac.suspend();
|
||||
$control.play.classList.remove("hidden");
|
||||
$control.pause.classList.add("hidden");
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown state");
|
||||
}
|
||||
}))),
|
||||
rxjs.switchMap((wavesurfer) => rxjs.animationFrames().pipe(
|
||||
rxjs.tap(() => {
|
||||
const percent = (currentTime$.value[0] + (wavesurfer.backend.ac.currentTime - currentTime$.value[1])) / wavesurfer.getDuration();
|
||||
if (percent > 1) return;
|
||||
wavesurfer.drawer.progress(percent);
|
||||
rxjs.switchMap((wavesurfer) => rxjs.fromEvent(document, "keydown").pipe(
|
||||
rxjs.map((e) => e.code),
|
||||
rxjs.tap((code) => {
|
||||
switch(code) {
|
||||
case "Space":
|
||||
case "KeyK":
|
||||
setStatus(
|
||||
wavesurfer.backend.ac.state === "suspended" ?
|
||||
STATUS_PLAYING : STATUS_PAUSED,
|
||||
wavesurfer,
|
||||
);
|
||||
break;
|
||||
case "KeyM":
|
||||
setVolume(wavesurfer.getVolume() > 0 ? 0 : settings_get("volume"), wavesurfer);
|
||||
break;
|
||||
case "ArrowUp":
|
||||
setVolume(Math.min(wavesurfer.getVolume()*100 + 10, 100), wavesurfer);
|
||||
break;
|
||||
case "ArrowDown":
|
||||
setVolume(Math.max(wavesurfer.getVolume()*100 - 10, 0), wavesurfer);
|
||||
break;
|
||||
case "KeyL":
|
||||
setSeek(Math.min(wavesurfer.getDuration(), currentTime(wavesurfer) + 10), wavesurfer);
|
||||
break;
|
||||
case "KeyJ":
|
||||
setSeek(Math.max(0, currentTime(wavesurfer) - 10), wavesurfer);
|
||||
break;
|
||||
case "Digit0":
|
||||
setSeek(0, wavesurfer);
|
||||
break;
|
||||
case "Digit1":
|
||||
setSeek(wavesurfer.getDuration() / 10, wavesurfer);
|
||||
break;
|
||||
case "Digit2":
|
||||
setSeek(2 * wavesurfer.getDuration() / 10, wavesurfer);
|
||||
break;
|
||||
case "Digit3":
|
||||
setSeek(3 * wavesurfer.getDuration() / 10, wavesurfer);
|
||||
break;
|
||||
case "Digit4":
|
||||
setSeek(4 * wavesurfer.getDuration() / 10, wavesurfer);
|
||||
break;
|
||||
case "Digit5":
|
||||
setSeek(5 * wavesurfer.getDuration() / 10, wavesurfer);
|
||||
break;
|
||||
case "Digit6":
|
||||
setSeek(6 * wavesurfer.getDuration() / 10, wavesurfer);
|
||||
break;
|
||||
case "Digit7":
|
||||
setSeek(7 * wavesurfer.getDuration() / 10, wavesurfer);
|
||||
break;
|
||||
case "Digit8":
|
||||
setSeek(8 * wavesurfer.getDuration() / 10, wavesurfer);
|
||||
break;
|
||||
case "Digit9":
|
||||
setSeek(9 * wavesurfer.getDuration() / 10, wavesurfer);
|
||||
break;
|
||||
}
|
||||
}),
|
||||
)),
|
||||
));
|
||||
|
||||
@@ -28,7 +28,8 @@ export default function(render) {
|
||||
replacements: "blobUrl",
|
||||
});
|
||||
const rendition = book.renderTo($epub, {
|
||||
height: "100%", width: "100%",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
flow: "scrolled-doc",
|
||||
method: "continuous",
|
||||
allowScriptedContent: false,
|
||||
|
||||
@@ -17,11 +17,13 @@ export default async function(render) {
|
||||
const $page = createElement(`
|
||||
<div class="component_ide">
|
||||
<component-menubar class="hidden"></component-menubar>
|
||||
<div class="component_editor"></div>
|
||||
<div class="component_editor hidden"></div>
|
||||
</div>
|
||||
`);
|
||||
render($page);
|
||||
|
||||
const $editor = qs($page, ".component_editor");
|
||||
const $menubar = qs($page, "component-menubar");
|
||||
const content$ = ajax(getDownloadUrl()).pipe(
|
||||
rxjs.map(({ response }) => response),
|
||||
rxjs.shareReplay(),
|
||||
@@ -33,7 +35,7 @@ export default async function(render) {
|
||||
ajax("/about").pipe(rxjs.delay(TIME_BEFORE_ABORT_EDIT), rxjs.map(() => null)),
|
||||
).pipe(
|
||||
rxjs.mergeMap((content) => {
|
||||
if (content === null || has_binary(content)) {
|
||||
// if (content === null || has_binary(content)) {
|
||||
return rxjs.from(initDownloader()).pipe(
|
||||
removeLoader,
|
||||
rxjs.mergeMap(() => {
|
||||
@@ -41,12 +43,13 @@ export default async function(render) {
|
||||
return rxjs.EMPTY;
|
||||
}),
|
||||
);
|
||||
}
|
||||
// }
|
||||
return rxjs.of(content);
|
||||
}),
|
||||
removeLoader,
|
||||
rxjs.tap((content) => {
|
||||
window.CodeMirror(qs($page, ".component_editor"), {
|
||||
$editor.classList.remove("hidden");
|
||||
window.CodeMirror($editor, {
|
||||
value: content,
|
||||
lineNumbers: true,
|
||||
// mode: mode,
|
||||
@@ -62,8 +65,8 @@ export default async function(render) {
|
||||
matchTags: { bothTags: true },
|
||||
autoCloseTags: true,
|
||||
});
|
||||
transition(qs($page, ".component_editor"));
|
||||
qs($page, "component-menubar").classList.remove("hidden");
|
||||
transition($editor);
|
||||
$menubar.classList.remove("hidden");
|
||||
}),
|
||||
rxjs.catchError(ctrlError()),
|
||||
))
|
||||
|
||||
@@ -18,21 +18,21 @@ export default function(render) {
|
||||
const $page = createElement(`
|
||||
<div class="component_formviewer">
|
||||
<component-menubar></component-menubar>
|
||||
<div class="formviewer_container">
|
||||
<div class="formviewer_container hidden">
|
||||
<form class="sticky box"></form>
|
||||
</div>
|
||||
<button is="component-fab"></button>
|
||||
</div>
|
||||
`);
|
||||
render($page);
|
||||
transition(qs($page, ".formviewer_container"));
|
||||
|
||||
const file$ = new rxjs.ReplaySubject(1);
|
||||
const $container = qs($page, ".formviewer_container");
|
||||
const $fab = qs($page, `[is="component-fab"]`);
|
||||
const formState = () => [...new FormData(qs($page, "form"))].reduce((acc, el) => {
|
||||
acc[el[0]] = el[1];
|
||||
return acc;
|
||||
}, {});
|
||||
const file$ = new rxjs.ReplaySubject(1);
|
||||
|
||||
// feature1: setup the dom
|
||||
effect(getFile$().pipe(
|
||||
@@ -55,6 +55,10 @@ export default function(render) {
|
||||
`),
|
||||
}))).pipe(
|
||||
applyMutation(qs($page, "form"), "replaceChildren"),
|
||||
rxjs.tap(() => {
|
||||
$container.classList.remove("hidden");
|
||||
transition($container);
|
||||
}),
|
||||
rxjs.mapTo(formSpec),
|
||||
)),
|
||||
rxjs.tap((formSpec) => file$.next(formObjToJSON(formSpec))),
|
||||
|
||||
@@ -6,7 +6,6 @@ body:not(.dark-mode) .component_appframe {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.component_appframe iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
@@ -1,17 +1,42 @@
|
||||
import { createElement } from "../../lib/skeleton/index.js";
|
||||
import rxjs, { effect } from "../../lib/rx.js";
|
||||
import { loadCSS } from "../../helpers/loader.js";
|
||||
import assert from "../../lib/assert.js";
|
||||
|
||||
import ctrlError from "../ctrl_error.js";
|
||||
|
||||
export default function(render, opts = {}) {
|
||||
const { endpoint = null } = opts;
|
||||
|
||||
assert.truthy(endpoint);
|
||||
const $page = createElement(`
|
||||
<div class="component_appframe">
|
||||
<component-menubar></component-menubar>
|
||||
<div>
|
||||
IFRAME
|
||||
</div>
|
||||
<iframe src="${getFrameUrl(endpoint)}"></iframe>
|
||||
</div>
|
||||
`);
|
||||
render($page);
|
||||
|
||||
effect(rxjs.fromEvent(window, "message").pipe(
|
||||
rxjs.filter((event) => event.origin === location.origin),
|
||||
rxjs.tap((event) => { // TODO: notification
|
||||
switch(event.data.type) {
|
||||
case "notify::info":
|
||||
notify.send(t(event.data.message), "info");
|
||||
break;
|
||||
case "notify::error":
|
||||
notify.send(t(event.data.message), "error");
|
||||
break
|
||||
}
|
||||
}),
|
||||
));
|
||||
|
||||
effect(rxjs.of(assert.truthy(endpoint)).pipe(
|
||||
rxjs.catchError(ctrlError()),
|
||||
));
|
||||
}
|
||||
|
||||
export function init() {
|
||||
return loadCSS(import.meta.url, "./application_iframe.css");
|
||||
}
|
||||
|
||||
function getFrameUrl(endpoint) {
|
||||
return endpoint + "?path=/home/mickael/Downloads/office.docx" + "&share=";
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
body:not(.dark-mode) .component_imageviewer .component_image_container, body:not(.dark-mode) .component_imageviewer .component_image_container .fullscreen .component_pager .wrapper > span {
|
||||
.component_imageviewer .component_image_container,
|
||||
body:not(.dark-mode) .component_imageviewer .component_image_container .fullscreen .component_pager .wrapper > span {
|
||||
background: #525659;
|
||||
}
|
||||
|
||||
.component_imageviewer, .component_imageviewer .component_image_container > .images_wrapper, .component_imageviewer .component_image_container > .images_wrapper > span, .component_imageviewer .component_image_container > .images_wrapper > span > div {
|
||||
.component_imageviewer, .component_imageviewer .component_image_container > .images_wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
@@ -27,7 +28,7 @@ body:not(.dark-mode) .component_imageviewer .component_image_container, body:not
|
||||
.component_imageviewer .component_image_container.fullscreen .component_pager .wrapper > span {
|
||||
background: var(--dark);
|
||||
}
|
||||
.component_imageviewer .component_image_container.fullscreen img[srcset] {
|
||||
.component_imageviewer .component_image_container.fullscreen img.photo {
|
||||
background: var(--color);
|
||||
}
|
||||
@media screen and (max-height: 410px) {
|
||||
@@ -162,7 +163,7 @@ body:not(.dark-mode) .component_imageviewer .component_image_container, body:not
|
||||
.component_imageviewer .component_image_container .images_aside .content .more_container .meta_key .value {
|
||||
color: var(--bg-color);
|
||||
}
|
||||
.component_imageviewer .component_image_container img[srcset] {
|
||||
.component_imageviewer .component_image_container img.photo:not(.error) {
|
||||
margin: auto;
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
@@ -171,7 +172,7 @@ body:not(.dark-mode) .component_imageviewer .component_image_container, body:not
|
||||
box-shadow: rgba(0, 0, 0, 0.14) 0px 4px 5px 0px, rgba(0, 0, 0, 0.12) 0px 1px 10px 0px, rgba(0, 0, 0, 0.2) 0px 2px 4px -1px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.component_imageviewer .component_image_container img[srcset].idle {
|
||||
.component_imageviewer .component_image_container img.photo.idle {
|
||||
transition: 0.2s ease transform;
|
||||
}
|
||||
|
||||
@@ -196,7 +197,6 @@ body:not(.dark-mode) .component_imageviewer .component_image_container, body:not
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
.component_imageviewer .component_image_container img.error {
|
||||
filter: contrast(0.8);
|
||||
width: 160px;
|
||||
|
||||
@@ -11,6 +11,7 @@ import Hls from "../../lib/vendor/hlsjs/hls.js";
|
||||
import ctrlError from "../ctrl_error.js";
|
||||
|
||||
import { transition, getDownloadUrl } from "./common.js";
|
||||
import { formatTimecode } from "./common_player.js";
|
||||
import { ICON } from "./common_icon.js";
|
||||
import { menubarDownload, buildMenubar } from "./common_menubar.js";
|
||||
import { render as renderMenubar } from "../../components/menubar.js";
|
||||
@@ -367,9 +368,3 @@ export function init() {
|
||||
if (typeof window.overrides["video-map-sources"] !== "function") window.overrides["video-map-sources"] = (s) => (s);
|
||||
});
|
||||
}
|
||||
|
||||
function formatTimecode(seconds) {
|
||||
return String(parseInt(seconds / 60)).padStart(2, "0") +
|
||||
":"+
|
||||
String(parseInt(seconds % 60)).padStart(2, "0");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
export function formatTimecode(seconds) {
|
||||
return String(parseInt(seconds / 60)).padStart(2, "0") +
|
||||
":"+
|
||||
String(parseInt(seconds % 60)).padStart(2, "0");
|
||||
}
|
||||
|
||||
// TODO: abstract setVolume, setSeek and setStatus
|
||||
Reference in New Issue
Block a user