diff --git a/layout.js b/layout.js new file mode 100644 index 0000000..d6f4a61 --- /dev/null +++ b/layout.js @@ -0,0 +1,145 @@ +import { EditorBuild } from "/loader/editor-build.js" + +export class Layout extends HTMLElement { + cspProfiles = { + local: "default-src 'self' 'unsafe-inline' 'unsafe-eval'", + jsCdns: "default-src cdn.jsdelivr.com data.jsdelivr.com unpkg.com 'self' 'unsafe-inline' 'unsafe-eval'", + open: undefined, + } + + constructor() { + super() + this.attachShadow({mode: 'open'}) + this.csp = "default-src 'self' 'unsafe-inline' 'unsafe-eval'" + this.header = document.createElement('m-header') + this.dialogWrap = document.createElement('div') + this.header.dialogWrap = this.dialogWrap + this.pageActions = document.createElement( + 'm-page-actions' + ) + this.pageActions.cspProfiles = this.cspProfiles + this.header.pageActions = this.pageActions + this.shadowRoot.append( + this.header, + this.dialogWrap, + this.pageActions, + ) + } + + connectedCallback() { + const style = document.createElement('style') + style.textContent = ` + :host { + display: flex; + flex-direction: column; + align-items: stretch; + height: 100svh; + min-height: 100svh; + max-height: 100svh; + overflow-y: hidden; + position: relative; + } + m-page, m-file-group-page { + flex-grow: 1; + } + m-dialog::part(footer) { + padding-top: 15px; + } + ` + this.shadowRoot.appendChild(style) + this.header.editing = this.editing + this.header.addEventListener('click-edit', () => { + this.editing = !this.editing + }) + this.header.addEventListener('create-page', () => { + this.editing = true + }) + this.load() + addEventListener('hashchange', () => { + this.load() + }) + this.addEventListener('hash-change', () => { + this.load() + }) + this.addEventListener('settings-change', () => { + this.load() + }) + } + + load() { + const path = this.path + this.editing = false + const prevPage = this.page + let isGroup = false + const body = localStorage.getItem(path) || '' + if (body.match(/^\s*{/)) { + try { + const bodyData = JSON.parse(body) + isGroup = ( + Array.isArray(bodyData?.files) && + bodyData.type === 'm-file-group' + ) + } catch (err) { + // do nothing, is not file group + } + } + this.page = document.createElement( + isGroup ? 'm-file-group-page' : 'm-page' + ) + if (isGroup) { + this.page.cspOff = this.csp === undefined + this.page.cspProfiles = this.cspProfiles + } else { + this.page.csp = this.csp + } + if (isGroup) { + this.page.editorBuild = this.editorBuild + } + this.page.path = path + this.editing = this.editing + if (prevPage !== undefined) { + prevPage.remove() + } + this.shadowRoot.appendChild(this.page) + this.header.path = path + this.pageActions.path = path + this.pageActions.page = this.page + } + + get path() { + const hash = ( + location.hash.slice(1) || '/' + ) + return hash.startsWith('/') ? new URL( + hash, + location.href + ).pathname : hash + } + + set editing(value) { + sessionStorage.setItem( + 'editing', value ? 'true' : 'false' + ) + this.header.editing = this.editing + if (this.page) { + this.page.editing = this.editing + } + } + + get editing() { + try { + return ( + sessionStorage.getItem('editing') === 'true' + ) + } catch (e) { + return false + } + } + + get editorBuild() { + if (this._editorBuild === undefined) { + this._editorBuild = new EditorBuild() + } + return this._editorBuild + } +} \ No newline at end of file