From 17f798f11fd6e00abf4d952c5c5e16bba983372b Mon Sep 17 00:00:00 2001 From: bat Date: Fri, 31 Mar 2023 08:29:01 +0000 Subject: [PATCH] Add delete and move and rename --- components/dialog.js | 62 +++++++++++++++++++++---- components/header.js | 100 ++++++++++++++++++++++++++++++---------- components/layout.js | 2 +- components/page-menu.js | 32 +------------ 4 files changed, 130 insertions(+), 66 deletions(-) diff --git a/components/dialog.js b/components/dialog.js index 4f55a63..7bea2e0 100644 --- a/components/dialog.js +++ b/components/dialog.js @@ -2,31 +2,73 @@ export class Dialog extends HTMLElement { constructor() { super() this.attachShadow({mode: 'open'}) - this.windowEl = document.createElement('div') - this.windowEl.classList.add('window') this.headerEl = document.createElement('div') this.headerEl.classList.add('header') this.bodyEl = document.createElement('div') this.bodyEl.classList.add('body') this.footerEl = document.createElement('div') this.footerEl.classList.add('footer') - this.windowEl.replaceChildren( + this.dialogEl = document.createElement('dialog') + this.dialogEl.replaceChildren( this.headerEl, this.bodyEl, this.footerEl ) - this.shadowRoot.appendChild(this.windowEl) + this.dialogEl.addEventListener('click', e => { + const rect = this.dialogEl.getBoundingClientRect(); + const clickedInDialog = ( + rect.top <= e.clientY && + e.clientY <= rect.top + rect.height && + rect.left <= e.clientX && + e.clientX <= rect.left + rect.width + ) + if (e.target === this.dialogEl && !clickedInDialog) { + this.close() + } + }) + this.shadowRoot.appendChild(this.dialogEl) } connectedCallback() { - this.textArea.value = this.body const style = document.createElement('style') style.textContent = ` - :host { - overflow-y: auto; - display: flex; - flex-direction: column; - align-items: stretch; + dialog { + margin-top: 120px; + min-width: 80%; + border: 1px solid rgba(0, 0, 0, 0.3); + border-radius: 6px; + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + } + dialog::backdrop { + opacity: 0; + transition: opacity 0.3s ease-in; + background-color: rgba(0, 0, 0, .25); + } + dialog.opened::backdrop { + opacity: 1; + } + dialog.closing { + visibility: hidden; + } + dialog.closing::backdrop { + visibility: visible; } ` this.shadowRoot.append(style) + this.headerEl.setAttribute('part', 'header') + this.bodyEl.setAttribute('part', 'body') + this.footerEl.setAttribute('part', 'footer') + } + + open() { + this.dialogEl.showModal(); + this.dialogEl.classList.add('opened') + } + + close() { + this.dialogEl.classList.remove('opened') + this.dialogEl.classList.add('closing') + setTimeout(() => { + this.dialogEl.close() + this.dialogEl.classList.remove('closing') + }, 500) } } \ No newline at end of file diff --git a/components/header.js b/components/header.js index 25fc5b7..acd274d 100644 --- a/components/header.js +++ b/components/header.js @@ -17,18 +17,29 @@ export class Header extends HTMLElement { textEn = { download: 'Download', - rename: 'Rename', + rename: 'Move/Rename', delete: 'Delete', + confirmDelete: f => ( + `Are you sure you want to delete ${f}?` + ), + cancel: 'Cancel', + alreadyExists: 'There is already a page with that name.', } textEs = { download: 'Descargar', - rename: 'Renombrar', + rename: 'Mover/Renombrar', delete: 'Borrar', + confirmDelete: f => ( + `¿Desea borrar ${f}?` + ), + cancel: 'Cancelar', + alreadyExists: 'Ya existe una página con ese nombre.', } constructor() { super() + this.language = navigator.language this.editing = false this.attachShadow({mode: 'open'}) this.addButton(this.icons.menu, 'nav', () => { @@ -48,7 +59,8 @@ export class Header extends HTMLElement { }) this.addMenu() this.addPageMenu() - //this.addDialogPanel() + this.dialogWrap = document.createElement('div') + this.shadowRoot.appendChild(this.dialogWrap) } connectedCallback() { @@ -100,9 +112,6 @@ export class Header extends HTMLElement { left: 0; opacity: 15%; } - div.overlay.open.dialog { - opacity: 50%; - } button.page { position: relative; } @@ -134,6 +143,10 @@ export class Header extends HTMLElement { div.page-menu.open { display: block; } + m-dialog::part(footer) { + padding-top: 15px; + text-align: right; + } ` this.shadowRoot.append(style) } @@ -174,7 +187,7 @@ export class Header extends HTMLElement { addPageMenu() { this.pageMenu = document.createElement('m-page-menu') - this.pageMenu.add('download', () => { + this.pageMenu.add(this.text.download, () => { const text = localStorage.getItem(this.path) const sp = this.path.split('/') const filename = sp[sp.length - 1] @@ -190,14 +203,63 @@ export class Header extends HTMLElement { el.click() this.shadowRoot.removeChild(el) }) - /*this.pageMenu.add('rename', () => { + this.pageMenu.add(this.text.rename, () => { const dialog = document.createElement('m-dialog') - dialog.title = this.text.rename - this.showDialog(dialog) + this.dialogWrap.replaceChildren(dialog) + const input = document.createElement('input') + input.style.width = '85%' + dialog.bodyEl.appendChild(input) + const cancelBtn = document.createElement('button') + cancelBtn.innerText = this.text.cancel + cancelBtn.addEventListener('click', () => { + dialog.close() + }) + const confirmBtn = document.createElement('button') + confirmBtn.innerText = this.text.rename + confirmBtn.style.marginLeft = '3px' + confirmBtn.addEventListener('click', () => { + const newPath = input.value + if (newPath !== this.path) { + localStorage.setItem( + newPath, + localStorage.getItem(this.path) + ) + } + localStorage.removeItem(this.path) + window.location.hash = newPath + dialog.close() + }) + dialog.footerEl.replaceChildren( + cancelBtn, confirmBtn + ) + dialog.open() + }) + this.pageMenu.add(this.text.delete, () => { + const dialog = document.createElement('m-dialog') + this.dialogWrap.replaceChildren(dialog) + const p = document.createElement('p') + p.innerText = this.text.confirmDelete( + JSON.stringify(this.path) + ) + dialog.bodyEl.appendChild(p) + const cancelBtn = document.createElement('button') + cancelBtn.innerText = this.text.cancel + cancelBtn.addEventListener('click', () => { + dialog.close() + }) + const confirmBtn = document.createElement('button') + confirmBtn.innerText = this.text.delete + confirmBtn.style.marginLeft = '3px' + confirmBtn.addEventListener('click', () => { + localStorage.removeItem(this.path) + window.location.hash = '/' + dialog.close() + }) + dialog.footerEl.replaceChildren( + cancelBtn, confirmBtn + ) + dialog.open() }) - this.pageMenu.add('delete', () => { - - })*/ this.pageMenu.addEventListener('close-menu', () => { this.close() }) @@ -208,18 +270,6 @@ export class Header extends HTMLElement { this.shadowRoot.appendChild(this.pageMenuPanel) } - addDialogPanel() { - this.dialogPanel = document.createElement('div') - this.dialogPanel.classList.add('dialog-panel') - this.shadowRoot.appendChild(this.dialogPanel) - } - - showDialog(dialog) { - this.overlay.classList.add('open', 'dialog') - this.dialogPanel.replaceChildren(dialog) - this.dialogPanel.classList.add('open') - } - close() { this.overlay.classList.add('closing') this.overlay.classList.remove('open') diff --git a/components/layout.js b/components/layout.js index 955fd7f..d200f7c 100644 --- a/components/layout.js +++ b/components/layout.js @@ -48,7 +48,7 @@ export class Layout extends HTMLElement { return new URL( window.location.hash.slice(1) || '/', window.location - ).pathname + ).pathname.replace(/^%23/, '#') } set editing(value) { diff --git a/components/page-menu.js b/components/page-menu.js index e071eca..e4df343 100644 --- a/components/page-menu.js +++ b/components/page-menu.js @@ -1,22 +1,7 @@ export class PageMenu extends HTMLElement { - icons = {} - - textEn = { - download: 'Download', - rename: 'Rename', - delete: 'Delete', - } - - textEs = { - download: 'Descargar', - rename: 'Renombrar', - delete: 'Borrar', - } - constructor() { super() this.attachShadow({mode: 'open'}) - this.language = navigator.language } connectedCallback() { @@ -43,9 +28,9 @@ export class PageMenu extends HTMLElement { this.shadowRoot.append(style) } - add(name, handler) { + add(text, handler) { const btn = document.createElement('button') - btn.innerText = this.text[name] + btn.innerText = text this.shadowRoot.appendChild(btn) btn.addEventListener('click', () => { this.dispatchEvent(new CustomEvent( @@ -54,17 +39,4 @@ export class PageMenu extends HTMLElement { handler() }) } - - get language() { - return this._language - } - - set language(language) { - this._language = language - this.text = this.langEs ? this.textEs : this.textEn - } - - get langEs() { - return /^es\b/.test(this.language) - } } \ No newline at end of file