Merge pull request 'add edit icon' (#12) from i9 into main

Reviewed-on: https://codeberg.org/macchiato/pages/pulls/12
file-group-page
bat 3 years ago
commit 3b3fcac3f6

@ -12,8 +12,9 @@ customElements.define('m-page-menu', PageMenu)
class Setup { class Setup {
async run() { async run() {
navigator.serviceWorker const sw = navigator.serviceWorker
.addEventListener('controllerchange', () => {
sw.addEventListener('controllerchange', () => {
if (this.registration.active) { if (this.registration.active) {
window.location.reload(true) window.location.reload(true)
} }

@ -5,11 +5,19 @@ export class Header extends HTMLElement {
</svg>`, </svg>`,
dot: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-three-dots" viewBox="0 0 16 16"> dot: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-three-dots" viewBox="0 0 16 16">
<path d="M3 9.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/> <path d="M3 9.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/>
</svg>`,
edit: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-square" viewBox="0 0 16 16">
<path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z"/>
<path fill-rule="evenodd" d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5v11z"/>
</svg>`,
check: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check-lg" viewBox="0 0 16 16">
<path d="M12.736 3.97a.733.733 0 0 1 1.047 0c.286.289.29.756.01 1.05L7.88 12.01a.733.733 0 0 1-1.065.02L3.217 8.384a.757.757 0 0 1 0-1.06.733.733 0 0 1 1.047 0l3.052 3.093 5.4-6.425a.247.247 0 0 1 .02-.022Z"/>
</svg>`, </svg>`,
} }
constructor() { constructor() {
super() super()
this.editing = false
this.attachShadow({mode: 'open'}) this.attachShadow({mode: 'open'})
this.addButton(this.icons.menu, 'nav', () => { this.addButton(this.icons.menu, 'nav', () => {
this.menu.pages = this.getPages() this.menu.pages = this.getPages()
@ -17,6 +25,11 @@ export class Header extends HTMLElement {
this.overlay.classList.add('open') this.overlay.classList.add('open')
}) })
this.addDivider() this.addDivider()
this.editBtn = this.addButton(this.editIcon, 'edit', () => {
this.dispatchEvent(new CustomEvent(
'click-edit', {bubbles: true}
))
})
this.addButton(this.icons.dot, 'page', () => { this.addButton(this.icons.dot, 'page', () => {
this.pageMenuPanel.classList.add('open') this.pageMenuPanel.classList.add('open')
this.overlay.classList.add('open') this.overlay.classList.add('open')
@ -33,6 +46,7 @@ export class Header extends HTMLElement {
if (onClick) { if (onClick) {
b.addEventListener('click', onClick) b.addEventListener('click', onClick)
} }
return b
} }
addDivider() { addDivider() {
@ -53,7 +67,7 @@ export class Header extends HTMLElement {
this.overlay.addEventListener('click', () => { this.overlay.addEventListener('click', () => {
this.close() this.close()
}) })
this.menu.addEventListener('close', () => { this.menu.addEventListener('close-menu', () => {
this.close() this.close()
}) })
} }
@ -76,7 +90,7 @@ export class Header extends HTMLElement {
el.click() el.click()
this.shadowRoot.removeChild(el) this.shadowRoot.removeChild(el)
}) })
this.pageMenu.addEventListener('close', () => { this.pageMenu.addEventListener('close-menu', () => {
this.close() this.close()
}) })
this.pageMenuPanel = document.createElement('div') this.pageMenuPanel = document.createElement('div')
@ -166,4 +180,19 @@ export class Header extends HTMLElement {
getPages() { getPages() {
return Object.keys(localStorage).slice().sort() return Object.keys(localStorage).slice().sort()
} }
set editing(value) {
this._editing = value
if (this.editBtn) {
this.editBtn.innerHTML = this.editIcon
}
}
get editing() {
return this._editing
}
get editIcon() {
return this.editing ? this.icons.check : this.icons.edit
}
} }

@ -2,12 +2,9 @@ export class Layout extends HTMLElement {
constructor() { constructor() {
super() super()
this.attachShadow({mode: 'open'}) this.attachShadow({mode: 'open'})
this.csp = "default-src 'self' 'unsafe-inline' 'unsafe-eval'"
this.header = document.createElement('m-header') this.header = document.createElement('m-header')
this.shadowRoot.appendChild(this.header) this.editing = false
this.load()
addEventListener('hashchange', () => {
this.load()
})
} }
connectedCallback() { connectedCallback() {
@ -24,13 +21,24 @@ export class Layout extends HTMLElement {
} }
` `
this.shadowRoot.appendChild(style) this.shadowRoot.appendChild(style)
this.header.editing = this.editing
this.header.addEventListener('click-edit', () => {
this.editing = !this.editing
})
this.shadowRoot.appendChild(this.header)
this.load()
addEventListener('hashchange', () => {
this.load()
})
} }
load() { load() {
const path = this.path const path = this.path
const prevPage = this.page const prevPage = this.page
this.page = document.createElement('m-page') this.page = document.createElement('m-page')
this.page.csp = this.csp
this.page.path = path this.page.path = path
this.editing = this.editing
if (prevPage !== undefined) { if (prevPage !== undefined) {
prevPage.remove() prevPage.remove()
} }
@ -39,9 +47,18 @@ export class Layout extends HTMLElement {
} }
get path() { get path() {
return new URL( return '/hello'
window.location.hash.slice(1) || '/', }
window.location
).pathname set editing(value) {
this._editing = value
this.header.editing = this.editing
if (this.page) {
this.page.editing = this.editing
}
}
get editing() {
return this._editing
} }
} }

@ -35,7 +35,7 @@ export class NavMenu extends HTMLElement {
this.shadowRoot.addEventListener('click', e => { this.shadowRoot.addEventListener('click', e => {
if (e.target.classList.contains('page')) { if (e.target.classList.contains('page')) {
this.dispatchEvent(new CustomEvent( this.dispatchEvent(new CustomEvent(
'close', {bubbles: true} 'close-menu', {bubbles: true}
)) ))
} }
}) })

@ -45,7 +45,7 @@ export class PageMenu extends HTMLElement {
this.shadowRoot.appendChild(btn) this.shadowRoot.appendChild(btn)
btn.addEventListener('click', () => { btn.addEventListener('click', () => {
this.dispatchEvent(new CustomEvent( this.dispatchEvent(new CustomEvent(
'close', {bubbles: true} 'close-menu', {bubbles: true}
)) ))
handler() handler()
}) })

@ -17,7 +17,7 @@ const frameHtml = `<!doctype html>
</head> </head>
<body> <body>
<iframe srcdoc="" sandbox="allow-scripts"></iframe> <iframe srcdoc="" sandbox="allow-scripts"></iframe>
<script type="module"> ${'<'}script type="module">
const frame = document.getElementsByTagName('iframe')[0] const frame = document.getElementsByTagName('iframe')[0]
addEventListener('message', event => { addEventListener('message', event => {
const d = event.data const d = event.data
@ -27,7 +27,7 @@ addEventListener('message', event => {
frame.postMessage(event.data) frame.postMessage(event.data)
} }
}) })
</script> ${'</'}script>
</body> </body>
</html>` </html>`
@ -35,12 +35,11 @@ export class Page extends HTMLElement {
constructor() { constructor() {
super() super()
const shadow = this.attachShadow({mode: 'open'}) const shadow = this.attachShadow({mode: 'open'})
this.csp = "default-src 'self' 'unsafe-inline' 'unsafe-eval'"
//this.editing = false
this.textArea = document.createElement('textarea') this.textArea = document.createElement('textarea')
this.textArea.addEventListener('input', e => { this.textArea.addEventListener('input', e => {
localStorage.setItem( this.body = e.target.value
this.path,
e.target.value
)
}) })
const div = document.createElement('div') const div = document.createElement('div')
div.classList.add('twrap') div.classList.add('twrap')
@ -49,9 +48,7 @@ export class Page extends HTMLElement {
} }
connectedCallback() { connectedCallback() {
this.textArea.value = localStorage.getItem( this.textArea.value = this.body
this.path
) ?? ''
const style = document.createElement('style') const style = document.createElement('style')
style.textContent = ` style.textContent = `
:host { :host {
@ -76,35 +73,90 @@ export class Page extends HTMLElement {
width: 100%; width: 100%;
height: 90vh; height: 90vh;
} }
:host(.editing) iframe {
display: none;
}
:host(.viewing) textarea {
display: none;
}
` `
this.shadowRoot.append(style) this.shadowRoot.append(style)
if (this.path.startsWith('/sandbox/')) { this.initFrame()
this.initFrame() this.editing = this.editing
}
} }
initFrame() { initFrame() {
const wrap = document.createElement('div') const wrap = document.createElement('div')
this.shadowRoot.appendChild(wrap) this.shadowRoot.appendChild(wrap)
const tmp = document.createElement('iframe') const tmp = document.createElement('iframe')
tmp.sandbox = "allow-same-origin allow-scripts" if (this.csp !== undefined) {
const url = new URL( tmp.sandbox = "allow-same-origin allow-scripts"
'/-/frame', location.href const url = new URL(
) '/-/frame', location.href
url.searchParams.set( )
'csp', url.searchParams.set('csp', this.csp)
"default-src 'self' 'unsafe-inline' 'unsafe-eval'" url.searchParams.set('html', frameHtml)
) tmp.src = url.href
url.searchParams.set('html', frameHtml) } else {
tmp.src = url.href tmp.sandbox = "allow-scripts"
tmp.srcdoc = frameHtml
}
wrap.insertAdjacentHTML( wrap.insertAdjacentHTML(
'beforeend', tmp.outerHTML 'beforeend', tmp.outerHTML
) )
const frames = wrap.getElementsByTagName('iframe') const frames = wrap.getElementsByTagName('iframe')
this.frame = frames[frames.length - 1] this.frame = frames[frames.length - 1]
this.textArea.addEventListener('blur', e => { this.textArea.addEventListener('blur', e => {
const msg = ['srcdoc', e.target.value] this.display(e.target.value)
this.frame.contentWindow.postMessage(msg) })
this.frame.addEventListener('load', () => {
this.display(this.body)
}) })
} }
display(value) {
let doc = value
if (!(/<\w/).test(doc.substring(0, 30))) {
doc = `<pre style="white-space: pre-wrap; margin: 8px 12px; font-family: monospace;">` +
doc.replace("<", "&lt;").replace(">", "&gt;") +
`</pre>`
}
const msg = ['srcdoc', doc]
this.frame.contentWindow.postMessage(msg, '*')
}
set body(value) {
try {
localStorage.setItem(this.path, value)
} catch (err) {
console.error(err)
}
}
get body() {
try {
return localStorage.getItem(this.path)
} catch (err) {
console.error(err)
return ''
}
}
set editing(value) {
this._editing = value
if (this.shadowRoot.host) {
const classes = this.shadowRoot.host.classList
if (this.editing) {
classes.add('editing')
classes.remove('viewing')
} else {
classes.add('viewing')
classes.remove('editing')
}
}
}
get editing() {
return this._editing
}
} }

@ -13,6 +13,7 @@ async function initCache() {
} }
self.addEventListener("install", event => { self.addEventListener("install", event => {
self.skipWaiting()
event.waitUntil(initCache()) event.waitUntil(initCache())
}) })

Loading…
Cancel
Save