diff --git a/package.json b/package.json index 1ec78edc..9e5dc344 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "main": "index.js", "scripts": { "build": "webpack-cli -p", - "start": "webpack-dev-server -d --content-base ./public" + "start": "webpack-dev-server -d --content-base ./public --host 0.0.0.0" }, "keywords": [], "author": "Misode", diff --git a/src/app/hooks/renderHtml.ts b/src/app/hooks/renderHtml.ts index 85528071..cfbed461 100644 --- a/src/app/hooks/renderHtml.ts +++ b/src/app/hooks/renderHtml.ts @@ -86,7 +86,9 @@ export const renderHtml: Hook<[any, Mounter], [string, string, string]> = { ${help(childPath, mounter)} ${cPrefix} - + ${cSuffix} ${cBody ? `
${cBody}
` : ''} @@ -125,7 +127,9 @@ export const renderHtml: Hook<[any, Mounter], [string, string, string]> = { ${help(childPath, mounter)} ${cPrefix} - + ${cSuffix} ${cBody ? `
${cBody}
` : ''} @@ -180,7 +184,9 @@ export const renderHtml: Hook<[any, Mounter], [string, string, string]> = { ${error(childPath, mounter)} ${help(childPath, mounter)} ${cPrefix} - + ${cSuffix} ${cBody ? `
${cBody}
` : ''} @@ -259,7 +265,6 @@ function hashString(str: string) { } function pathLocale(path: Path, params?: string[]): string { - // return path.getContext().slice(-5).join('.') return segmentedLocale(path.getContext(), params) ?? path.getContext()[path.getContext().length - 1] ?? '' } @@ -287,3 +292,57 @@ const popupIcon = (type: string, icon: keyof typeof Octicon, popup: string, moun ${popup}${Octicon[icon]} ` } + +const contextMenu = (path: ModelPath, mounter: Mounter) => { + const id = mounter.register(el => { + const openMenu = () => { + const popup = document.createElement('div') + popup.classList.add('node-menu') + + const helpMessage = segmentedLocale(path.contextPush('help').getContext(), [], 6) + if (helpMessage) popup.insertAdjacentHTML('beforeend', `${helpMessage}`) + + const context = path.getContext().join('.') + popup.insertAdjacentHTML('beforeend', ` + `) + popup.querySelector('.menu-item .btn')?.addEventListener('click', () => { + const inputEl = document.createElement('input') + inputEl.value = context + el.appendChild(inputEl) + inputEl.select() + document.execCommand('copy') + el.removeChild(inputEl) + }) + + el.appendChild(popup) + document.body.addEventListener('click', () => { + try {el.removeChild(popup)} catch (e) {} + }, { capture: true, once: true }) + document.body.addEventListener('contextmenu', () => { + try {el.removeChild(popup)} catch (e) {} + }, { capture: true, once: true }) + } + el.addEventListener('contextmenu', evt => { + openMenu() + evt.preventDefault() + }) + let timer: any = null + el.addEventListener('touchstart', () => { + timer = setTimeout(() => { + openMenu() + timer = null + }, 800) + }) + el.addEventListener('touchend', () => { + if (timer) { + clearTimeout(timer) + timer = null + } + }) + }) + return `data-id="${id}"` +} diff --git a/src/styles/nodes.css b/src/styles/nodes.css index 8b259989..7bf3cdf9 100644 --- a/src/styles/nodes.css +++ b/src/styles/nodes.css @@ -12,6 +12,7 @@ --node-indent-border: #b9b9b9; --node-popup-background: #1f2020e6; --node-popup-text: #dadada; + --node-popup-text-dimmed: #b4b4b4; --category-predicate: #65b5b8; --category-predicate-border: #187e81; --category-predicate-background: #95c5c7; @@ -37,6 +38,7 @@ --node-indent-border: #454749; --node-popup-background: #0a0a0ae6; --node-popup-text: #dadada; + --node-popup-text-dimmed: #b4b4b4; --category-predicate: #306163; --category-predicate-border: #224849; --category-predicate-background: #1d3333; @@ -52,8 +54,9 @@ .node-header { display: inline-flex; + position: relative; align-items: center; - max-width: 100%; + width: 100%; } .node-header > * { @@ -68,6 +71,7 @@ padding: 0 9px; line-height: 1.94rem; white-space: nowrap; + user-select: none; background-color: var(--node-background-label); } @@ -221,6 +225,54 @@ button.remove { fill: var(--node-remove); } +.node-menu { + position: absolute; + left: 0; + top: 100%; + width: min-content; + margin-top: 4px; + margin-left: 4px; + z-index: 1; + color: var(--node-popup-text); + font-size: 16px; + border-radius: 3px; + background-color: var(--node-popup-background); +} + +.node-menu::after { + content: ""; + position: absolute; + bottom: 100%; + left: 0; + margin-left: 6px; + border-width: 5px; + border-style: solid; + border-color: transparent transparent var(--node-popup-background) transparent; +} + +.menu-item { + padding: 4px; + display: flex; + align-items: center; + white-space: normal; +} + +.menu-item > * { + margin-right: 4px; +} + +.menu-item .btn { + padding: 8px; +} + +span.menu-item { + padding: 4px 8px; +} + +.menu-item-context { + color: var(--node-popup-text-dimmed); +} + /* Node body and list entry */ .node {