@@ -30,7 +39,7 @@ const createModal = async() => createElement(`
class ModalComponent extends window.HTMLElement {
async trigger($node, opts = {}) {
- const $modal = await createModal();
+ const $modal = await create();
const close$ = new rxjs.Subject();
const { onQuit = nop, withButtonsLeft = null, withButtonsRight = null } = opts;
@@ -44,20 +53,20 @@ class ModalComponent extends window.HTMLElement {
if (currentLabel === null) return $button.remove();
$button.textContent = currentLabel;
- $button.onclick = () => close$.next(currentLabel);
+ $button.onclick = () => close$.next({ label: currentLabel, id: i+1 });
});
effect(rxjs.fromEvent($modal, "click").pipe(
rxjs.filter((e) => e.target.getAttribute("id") === "modal-box"),
- rxjs.tap(() => close$.next()),
+ rxjs.tap(() => close$.next({ id: 0 })),
));
effect(rxjs.fromEvent(window, "keydown").pipe(
rxjs.filter((e) => e.keyCode === 27),
- rxjs.tap(() => close$.next()),
+ rxjs.tap(() => close$.next({ id: 0 })),
));
// feature: closing the modal
effect(close$.pipe(
- rxjs.tap((label) => onQuit(label)),
+ rxjs.tap(onQuit),
rxjs.tap(() => animate(qs($modal, "div > div"), {
time: 200,
keyframes: [
diff --git a/public/assets/lib/skeleton/index.js b/public/assets/lib/skeleton/index.js
index 3965cc16..2d30ac04 100644
--- a/public/assets/lib/skeleton/index.js
+++ b/public/assets/lib/skeleton/index.js
@@ -80,4 +80,4 @@ export function createRender($parent) {
};
}
-export function nop() {}
+export function nop() { Promise.resolve(); }
diff --git a/public/assets/pages/ctrl_filespage.js b/public/assets/pages/ctrl_filespage.js
index 3a35d24f..a6d6055e 100644
--- a/public/assets/pages/ctrl_filespage.js
+++ b/public/assets/pages/ctrl_filespage.js
@@ -7,6 +7,7 @@ import WithShell, { init as initShell } from "../components/decorator_shell_file
import { getState$ } from "./filespage/ctrl_filesystem_state.js";
import componentFilesystem, { init as initFilesystem } from "./filespage/ctrl_filesystem.js";
import componentSubmenu, { init as initSubmenu } from "./filespage/ctrl_submenu.js";
+import componentNewItem, { init as initNewItem } from "./filespage/ctrl_newitem.js";
import "../components/breadcrumb.js";
@@ -15,6 +16,7 @@ export default WithShell(function(render) {
`);
@@ -31,11 +33,14 @@ export default WithShell(function(render) {
// feature3: render the menubar
componentSubmenu(createRender(qs($page, "[is=\"component_submenu\"]")));
+
+ // feature4: render the creation menu
+ componentNewItem(createRender(qs($page, "[is=\"component_newitem\"]")));
});
export function init() {
return Promise.all([
loadCSS(import.meta.url, "./ctrl_filespage.css"),
- initShell(), initFilesystem(), initSubmenu(),
+ initShell(), initFilesystem(), initSubmenu(), initNewItem(),
]);
}
diff --git a/public/assets/pages/filespage/ctrl_newitem.css b/public/assets/pages/filespage/ctrl_newitem.css
new file mode 100644
index 00000000..e9246320
--- /dev/null
+++ b/public/assets/pages/filespage/ctrl_newitem.css
@@ -0,0 +1,10 @@
+.component_newitem {
+ overflow: hidden;
+}
+
+.component_newitem .component_thing {
+ margin: 0 2px;
+}
+.component_newitem .component_thing .component_action {
+ display: block;
+}
diff --git a/public/assets/pages/filespage/ctrl_newitem.js b/public/assets/pages/filespage/ctrl_newitem.js
new file mode 100644
index 00000000..9f57f5d8
--- /dev/null
+++ b/public/assets/pages/filespage/ctrl_newitem.js
@@ -0,0 +1,92 @@
+import { createElement, onDestroy } from "../../lib/skeleton/index.js";
+import rxjs, { effect, onClick, preventDefault } from "../../lib/rx.js";
+import { qs } from "../../lib/dom.js";
+import { animate } from "../../lib/animate.js";
+import { loadCSS } from "../../helpers/loader.js";
+
+import { getAction$ } from "./model_action.js";
+
+export default async function(render) {
+ const $node = createElement(`
+
+
+
+
![directory]()
+
+
+
+
+
+
+

+
+
+
+
+
+
+ `);
+ $node.classList.add("hidden");
+
+ const $input = qs($node, "input[type=\"text\"]");
+ const $icon = qs($node, ".component_icon");
+ const $remove = qs($node, ".action");
+
+ // feature1: setup the dom
+ effect(getAction$().pipe(
+ rxjs.map((targetName) => {
+ if (targetName === "NEW_FILE") return {
+ targetName,
+ alt: "file",
+ img: "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTYiIHdpZHRoPSIxNiI+CiAgPHBhdGggc3R5bGU9ImNvbG9yOiMwMDAwMDA7dGV4dC1pbmRlbnQ6MDt0ZXh0LXRyYW5zZm9ybTpub25lO2ZpbGw6IzhjOGM4YztmaWxsLW9wYWNpdHk6MTtzdHJva2Utd2lkdGg6MC45ODQ4MTA0MSIgZD0ibSAyLDEzLjA4MjQxMiAwLjAxOTQ2MiwxLjQ5MjM0NyBjIDVlLTYsMC4yMjIxNDUgMC4yMDU1OTAyLDAuNDI0MjYyIDAuNDMxMTUwMiwwLjQyNDI3MiBMIDEzLjU4OTYxMiwxNSBDIDEzLjgxNTE3MywxNC45OTk5OTUgMTMuOTk5OTksMTQuNzk3ODc0IDE0LDE0LjU3NTcyOSB2IC0xLjQ5MzMxNyBjIC00LjE3MTg2OTIsMC42NjIwMjMgLTcuNjUxNjkyOCwwLjM5ODY5NiAtMTIsMCB6IiAvPgogIDxwYXRoIHN0eWxlPSJjb2xvcjojMDAwMDAwO3RleHQtaW5kZW50OjA7dGV4dC10cmFuc2Zvcm06bm9uZTtkaXNwbGF5OmlubGluZTtmaWxsOiNhYWFhYWE7c3Ryb2tlLXdpZHRoOjAuOTg0MDgxMjciIGQ9Ik0gMi4zNTAxLDEuMDAxMzMxMiBDIDIuMTUyNTksMS4wMzgzMjQ3IDEuOTk2NTksMS4yMjcyNzIzIDIuMDAwMDksMS40MjQ5MzU2IFYgMTQuMTMzNDU3IGMgNWUtNiwwLjIyMTgxNiAwLjIwNTIzLDAuNDIzNjM0IDAuNDMwNzksMC40MjM2NDQgbCAxMS4xMzksLTEuMDFlLTQgYyAwLjIyNTU2LC02ZS02IDAuNDMwMTEsLTAuMjAwNzU4IDAuNDMwMTIsLTAuNDIyNTc0IGwgNi43ZS00LC05LjgyMjY0MjYgYyAtMi40ODQwNDYsLTEuMzU1MDA2IC0yLjQzNTIzNCwtMi4wMzEyMjU0IC0zLjUwMDEsLTMuMzA5NzA3IC0wLjA0MywtMC4wMTU4ODIgMC4wNDYsMC4wMDE3NCAwLDAgTCAyLjQzMDY3LDEuMDAxMTA4IEMgMi40MDM4MywwLjk5ODU5IDIuMzc2NzQsMC45OTg1OSAyLjM0OTksMS4wMDExMDggWiIgLz4KICA8cGF0aCBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDojOGM4YzhjO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojOWU3NTc1O3N0cm9rZS13aWR0aDowO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiIGQ9Im0gMTAuNTAwNTcsMS4wMDIwNzY0IGMgMCwzLjI3NjgwMjggLTAuMDA1MiwzLjE3MzkxNjEgMC4zNjI5MjEsMy4yNjk4MjAyIDAuMjgwMTA5LDAuMDcyOTg0IDMuMTM3MTgsMC4wMzk4ODcgMy4xMzcxOCwwLjAzOTg4NyAtMS4xMjAwNjcsLTEuMDU1NjY5MiAtMi4zMzM0LC0yLjIwNjQ3MTMgLTMuNTAwMSwtMy4zMDk3MDc0IHoiIC8+Cjwvc3ZnPg==",
+ };
+ if (targetName === "NEW_FOLDER") return {
+ targetName,
+ alt: "directory",
+ img: "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBoZWlnaHQ9IjE2IiB3aWR0aD0iMTYiPgogIDxnIHRyYW5zZm9ybT0ibWF0cml4KDAuODY2NjY0MzEsMCwwLDAuODY2NjcsLTE3Mi4wNDU3OCwtODY0LjMyNzU5KSIgc3R5bGU9ImZpbGw6Izc1YmJkOTtmaWxsLW9wYWNpdHk6MC45NDExNzY0NztmaWxsLXJ1bGU6ZXZlbm9kZCI+CiAgICA8cGF0aCBzdHlsZT0iZmlsbDojNzViYmQ5O2ZpbGwtb3BhY2l0eTowLjk0MTE3NjQ3O2ZpbGwtcnVsZTpldmVub2RkIiBkPSJtIDIwMC4yLDk5OS43MiBjIC0wLjI4OTEzLDAgLTAuNTMxMjUsMC4yNDIxIC0wLjUzMTI1LDAuNTMxMiB2IDEyLjc4NCBjIDAsMC4yOTg1IDAuMjMyNjQsMC41MzEyIDAuNTMxMjUsMC41MzEyIGggMTUuMDkxIGMgMC4yOTg2LDAgMC41MzEyNCwtMC4yMzI3IDAuNTMxMjQsLTAuNTMxMiBsIDRlLTQsLTEwLjQ3NCBjIDAsLTAuMjg4OSAtMC4yNDIxMSwtMC41MzM4IC0wLjUzMTI0LC0wLjUzMzggbCAtNy41NDU3LDVlLTQgLTIuMzA3NiwtMi4zMDc4MyB6IiAvPgogIDwvZz4KICA8ZyB0cmFuc2Zvcm09Im1hdHJpeCgwLjg2NjY3LDAsMCwwLjg2NjY3LC0xNzIuMDQ2OTIsLTg2NC43ODM0KSIgc3R5bGU9ImZpbGw6IzlhZDFlZDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZCI+CiAgICA8cGF0aCBzdHlsZT0iZmlsbDojOWFkMWVkO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkIiBkPSJtIDIwMC4yLDk5OS43MiBjIC0wLjI4OTEzLDAgLTAuNTMxMjUsMC4yNDIxIC0wLjUzMTI1LDAuNTMxMiB2IDEyLjc4NCBjIDAsMC4yOTg1IDAuMjMyNjQsMC41MzEyIDAuNTMxMjUsMC41MzEyIGggMTUuMDkxIGMgMC4yOTg2LDAgMC41MzEyNCwtMC4yMzI3IDAuNTMxMjQsLTAuNTMxMiBsIDRlLTQsLTEwLjQ3NCBjIDAsLTAuMjg4OSAtMC4yNDIxMSwtMC41MzM4IC0wLjUzMTI0LC0wLjUzMzggbCAtNy41NDU3LDVlLTQgLTIuMzA3NiwtMi4zMDc4MyB6IiAvPgogIDwvZz4KPC9zdmc+Cg==",
+ };
+ return null;
+ }),
+ rxjs.filter((val) => val),
+ rxjs.tap(({ img, alt, targetName }) => {
+ $icon.setAttribute("src", `data:image/svg+xml;base64,${img}`);
+ $icon.setAttribute("alt", alt);
+ $input.value = "";
+ if ($node.classList.contains("hidden")) animate($node, {
+ keyframes: [{ height: `0px` }, { height: "50px" }],
+ time: 100, fill: "forwards",
+ });
+ $node.classList.remove("hidden")
+ render($node);
+ $input.focus();
+ }),
+ ));
+
+ // feature2: remove the component
+ effect(rxjs.merge(
+ onClick($remove),
+ rxjs.fromEvent(window, "keydown").pipe(
+ rxjs.filter((e) => e.keyCode === 27),
+ ),
+ rxjs.fromEvent($input, "blur").pipe(
+ rxjs.filter(() => !$input.value),
+ ),
+ ).pipe(rxjs.tap(async () => {
+ await animate($node, {
+ keyframes: [{ height: "50px" }, { height: `0px` }],
+ time: 50,
+ fill: "backwards",
+ });
+ $node.classList.add("hidden");
+ })));
+
+ // feature3: submit form
+ effect(rxjs.fromEvent($node, "submit").pipe(
+ preventDefault(),
+ rxjs.tap(() => console.log("SUBMIT")),
+ ));
+}
+
+export function init() {
+ return loadCSS(import.meta.url, "./ctrl_newitem.css");
+}
diff --git a/public/assets/pages/filespage/ctrl_submenu.js b/public/assets/pages/filespage/ctrl_submenu.js
index 6893387e..c15f3999 100644
--- a/public/assets/pages/filespage/ctrl_submenu.js
+++ b/public/assets/pages/filespage/ctrl_submenu.js
@@ -1,13 +1,26 @@
-import { onDestroy, createElement, createFragment } from "../../lib/skeleton/index.js";
-import rxjs, { effect, applyMutation, onClick } from "../../lib/rx.js";
+import { onDestroy, createElement, createFragment, nop } from "../../lib/skeleton/index.js";
+import rxjs, { effect, applyMutation, onClick, preventDefault } from "../../lib/rx.js";
import { animate } from "../../lib/animate.js";
import { loadCSS } from "../../helpers/loader.js";
import { qs } from "../../lib/dom.js";
import { getSelection$, clearSelection } from "./model_files.js";
+import { setAction } from "./model_action.js";
+
+import componentShare from "./modal_share.js";
+import componentEmbed from "./modal_embed.js";
+import componentTag from "./modal_tag.js";
+import componentRename from "./modal_rename.js";
+import componentDelete from "./modal_delete.js";
import "../../components/dropdown.js";
import "../../components/icon.js";
+import { createModal } from "../../components/modal.js";
+const modalOpt = {
+ withButtonsRight: "OK",
+ withButtonsLeft: "CANCEL",
+};
+
export default async function(render) {
const $page = createElement(`