mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-06 21:49:03 +00:00
cleanup panel: fade long titles, remember last open, bugfixes
This commit is contained in:
parent
6656b639d7
commit
42cfc69357
@ -26,4 +26,11 @@ export { tooltip } from './tooltip.mjs';
|
|||||||
*/
|
*/
|
||||||
export { feather } from './feather.mjs';
|
export { feather } from './feather.mjs';
|
||||||
|
|
||||||
export { panel } from './panel.mjs';
|
/**
|
||||||
|
* adds a view to the enhancer's side panel
|
||||||
|
* @param {string} param0.id - a uuid, used to restore it on reload if it was last open
|
||||||
|
* @param {string} param0.icon - an svg string
|
||||||
|
* @param {string} param0.title - the name of the view
|
||||||
|
* @param {Element} param0.$content - an element containing the content of the view
|
||||||
|
*/
|
||||||
|
export { addPanelView } from './panel.mjs';
|
||||||
|
@ -85,9 +85,12 @@
|
|||||||
height: 1em;
|
height: 1em;
|
||||||
width: 1em;
|
width: 1em;
|
||||||
}
|
}
|
||||||
.enhancer--panel-view-title span {
|
.enhancer--panel-view-title .enhancer--panel-view-title-text {
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
margin-left: 0.5em;
|
margin: 0 0 0 0.75em;
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#enhancer--panel-header {
|
#enhancer--panel-header {
|
||||||
@ -97,77 +100,24 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
padding: 0.75rem 0 0.75rem 1rem;
|
||||||
#enhancer--panel-header .enhancer--panel-view-title {
|
--scoped--bg: var(--theme--bg_secondary);
|
||||||
font-size: 1.2rem;
|
background: var(--scoped--bg);
|
||||||
}
|
|
||||||
#enhancer--panel-content {
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
}
|
||||||
#enhancer--panel-header-title {
|
#enhancer--panel-header-title {
|
||||||
padding: 0 0.5em 0.1em 1rem;
|
max-width: calc(100% - 4.25rem);
|
||||||
}
|
}
|
||||||
#enhancer--panel-header-switcher {
|
#enhancer--panel-header-title .enhancer--panel-view-title {
|
||||||
padding: 4px;
|
font-size: 1.2rem;
|
||||||
margin: 0.75rem 0;
|
|
||||||
}
|
}
|
||||||
#enhancer--panel-header-toggle {
|
#enhancer--panel-header-title .enhancer--panel-view-title-text {
|
||||||
margin-left: auto;
|
max-width: calc(100% - 1.75em);
|
||||||
padding-right: 1rem;
|
position: relative;
|
||||||
height: 100%;
|
|
||||||
width: 2.5em;
|
|
||||||
opacity: 0;
|
|
||||||
display: flex;
|
|
||||||
}
|
}
|
||||||
#enhancer--panel-header-toggle > div {
|
.enhancer--panel-view-title-fade-edge {
|
||||||
margin: auto 0 auto auto;
|
display: inline-block;
|
||||||
}
|
width: 0.75rem;
|
||||||
#enhancer--panel-header-switcher,
|
|
||||||
#enhancer--panel-header-toggle > div {
|
|
||||||
color: var(--theme--icon_secondary);
|
|
||||||
height: 1em;
|
height: 1em;
|
||||||
width: 1em;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
border-radius: 3px;
|
|
||||||
transition: 300ms ease-in-out;
|
|
||||||
}
|
|
||||||
#enhancer--panel-header-switcher:hover,
|
|
||||||
#enhancer--panel-header-switcher:focus,
|
|
||||||
#enhancer--panel-header-toggle > div:hover,
|
|
||||||
#enhancer--panel-header-toggle > div:focus {
|
|
||||||
background: var(--theme--ui_interactive-hover);
|
|
||||||
}
|
|
||||||
#enhancer--panel #enhancer--panel-header-toggle svg {
|
|
||||||
transition: 300ms ease-in-out;
|
|
||||||
}
|
|
||||||
#enhancer--panel:not([data-enhancer-panel-pinned]) #enhancer--panel-header-toggle svg {
|
|
||||||
transform: rotateZ(-180deg);
|
|
||||||
}
|
|
||||||
#enhancer--panel:hover #enhancer--panel-header-toggle {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#enhancer--panel-resize {
|
|
||||||
position: absolute;
|
|
||||||
left: -5px;
|
|
||||||
height: 100%;
|
|
||||||
width: 10px;
|
|
||||||
}
|
|
||||||
#enhancer--panel[data-enhancer-panel-pinned] #enhancer--panel-resize {
|
|
||||||
cursor: col-resize;
|
|
||||||
}
|
|
||||||
#enhancer--panel-resize div {
|
|
||||||
transition: background 150ms ease-in-out;
|
|
||||||
background: transparent;
|
|
||||||
width: 2px;
|
|
||||||
margin-left: 4px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
#enhancer--panel[data-enhancer-panel-pinned] #enhancer--panel-resize:hover div {
|
|
||||||
background: var(--theme--ui_divider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#enhancer--panel-switcher-overlay-container {
|
#enhancer--panel-switcher-overlay-container {
|
||||||
@ -199,9 +149,89 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: background 300ms ease;
|
position: relative;
|
||||||
|
--scoped--bg: var(--theme--bg_popup);
|
||||||
|
background: var(--scoped--bg);
|
||||||
}
|
}
|
||||||
|
#enhancer--panel-header:hover,
|
||||||
|
#enhancer--panel-header:focus-within,
|
||||||
.enhancer--panel-switcher-item:hover,
|
.enhancer--panel-switcher-item:hover,
|
||||||
.enhancer--panel-switcher-item:focus {
|
.enhancer--panel-switcher-item:focus {
|
||||||
background: var(--theme--ui_interactive-hover);
|
--scoped--bg: var(--theme--ui_interactive-hover);
|
||||||
|
}
|
||||||
|
#enhancer--panel-header:active,
|
||||||
|
.enhancer--panel-switcher-item:active {
|
||||||
|
background: var(--theme--ui_interactive-active);
|
||||||
|
}
|
||||||
|
.enhancer--panel-view-title-fade-edge:after {
|
||||||
|
content: '';
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 0.75rem;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
transparent 0%,
|
||||||
|
var(--scoped--bg) 50%,
|
||||||
|
var(--scoped--bg) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#enhancer--panel-content {
|
||||||
|
margin: 0.75rem 1rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
#enhancer--panel-header-switcher {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
#enhancer--panel-header-toggle {
|
||||||
|
margin-left: auto;
|
||||||
|
padding-right: 1rem;
|
||||||
|
height: 100%;
|
||||||
|
width: 2.5em;
|
||||||
|
opacity: 0;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
#enhancer--panel-header-toggle > div {
|
||||||
|
margin: auto 0 auto auto;
|
||||||
|
}
|
||||||
|
#enhancer--panel-header-switcher,
|
||||||
|
#enhancer--panel-header-toggle > div {
|
||||||
|
color: var(--theme--icon_secondary);
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
transition: 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
#enhancer--panel #enhancer--panel-header-toggle svg {
|
||||||
|
transition: 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
#enhancer--panel:not([data-enhancer-panel-pinned]) #enhancer--panel-header-toggle svg {
|
||||||
|
transform: rotateZ(-180deg);
|
||||||
|
}
|
||||||
|
#enhancer--panel:hover #enhancer--panel-header-toggle {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#enhancer--panel-resize {
|
||||||
|
position: absolute;
|
||||||
|
left: -5px;
|
||||||
|
height: 100%;
|
||||||
|
width: 10px;
|
||||||
|
}
|
||||||
|
#enhancer--panel[data-enhancer-panel-pinned] #enhancer--panel-resize {
|
||||||
|
cursor: col-resize;
|
||||||
|
}
|
||||||
|
#enhancer--panel-resize div {
|
||||||
|
transition: background 150ms ease-in-out;
|
||||||
|
background: transparent;
|
||||||
|
width: 2px;
|
||||||
|
margin-left: 4px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
#enhancer--panel[data-enhancer-panel-pinned] #enhancer--panel-resize:hover div {
|
||||||
|
background: var(--theme--ui_divider);
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,8 @@
|
|||||||
import { web, components, registry } from '../_.mjs';
|
import { web, components, registry } from '../_.mjs';
|
||||||
const db = await registry.db('36a2ffc9-27ff-480e-84a7-c7700a7d232d');
|
const db = await registry.db('36a2ffc9-27ff-480e-84a7-c7700a7d232d');
|
||||||
|
|
||||||
let $panel,
|
const _views = [],
|
||||||
_views = [];
|
svgExpand = web.raw`<svg viewBox="-1 -1 9 11">
|
||||||
|
|
||||||
const svgExpand = web.raw`<svg viewBox="-1 -1 9 11">
|
|
||||||
<path d="M 3.5 0L 3.98809 -0.569442L 3.5 -0.987808L 3.01191 -0.569442L 3.5 0ZM 3.5 9L 3.01191
|
<path d="M 3.5 0L 3.98809 -0.569442L 3.5 -0.987808L 3.01191 -0.569442L 3.5 0ZM 3.5 9L 3.01191
|
||||||
9.56944L 3.5 9.98781L 3.98809 9.56944L 3.5 9ZM 0.488094 3.56944L 3.98809 0.569442L 3.01191
|
9.56944L 3.5 9.98781L 3.98809 9.56944L 3.5 9ZM 0.488094 3.56944L 3.98809 0.569442L 3.01191
|
||||||
-0.569442L -0.488094 2.43056L 0.488094 3.56944ZM 3.01191 0.569442L 6.51191 3.56944L 7.48809
|
-0.569442L -0.488094 2.43056L 0.488094 3.56944ZM 3.01191 0.569442L 6.51191 3.56944L 7.48809
|
||||||
@ -26,183 +24,222 @@ const svgExpand = web.raw`<svg viewBox="-1 -1 9 11">
|
|||||||
5.43056L 3.01191 8.43056L 3.98809 9.56944Z"></path>
|
5.43056L 3.01191 8.43056L 3.98809 9.56944Z"></path>
|
||||||
</svg>`;
|
</svg>`;
|
||||||
|
|
||||||
export const panel = async (icon, title, generator = () => {}) => {
|
// open + close
|
||||||
_views.push({
|
let $notionFrame,
|
||||||
icon: web.html`${icon}`,
|
$notionRightSidebar,
|
||||||
title: web.html`<span>${web.escape(title)}</span>`,
|
// resize
|
||||||
$elem: generator(),
|
dragStartX,
|
||||||
});
|
dragStartWidth,
|
||||||
|
dragEventsFired,
|
||||||
|
panelWidth,
|
||||||
|
// render content
|
||||||
|
$notionApp;
|
||||||
|
|
||||||
if (!$panel) {
|
// open + close
|
||||||
$panel = web.html`<div id="enhancer--panel"></div>`;
|
const $panel = web.html`<div id="enhancer--panel"></div>`,
|
||||||
|
$pinnedToggle = web.html`<div id="enhancer--panel-header-toggle" tabindex="0"><div>
|
||||||
const notionRightSidebarSelector = '.notion-cursor-listener > div[style*="flex-end"]';
|
${await components.feather('chevrons-right')}
|
||||||
await web.whenReady([notionRightSidebarSelector]);
|
</div></div>`,
|
||||||
web.loadStylesheet('api/components/panel.css');
|
$hoverTrigger = web.html`<div id="enhancer--panel-hover-trigger"></div>`,
|
||||||
|
panelPinnedAttr = 'data-enhancer-panel-pinned',
|
||||||
// opening/closing
|
isPinned = () => $panel.hasAttribute(panelPinnedAttr),
|
||||||
const $notionFrame = document.querySelector('.notion-frame'),
|
togglePanel = () => {
|
||||||
$notionRightSidebar = document.querySelector(notionRightSidebarSelector),
|
const $elems = [$notionRightSidebar, $notionFrame, $hoverTrigger, $panel];
|
||||||
$pinnedToggle = web.html`<div id="enhancer--panel-header-toggle"><div>
|
if (isPinned()) {
|
||||||
${await components.feather('chevrons-right')}
|
closeSwitcher();
|
||||||
</div></div>`,
|
for (const $elem of $elems) $elem.removeAttribute(panelPinnedAttr);
|
||||||
$hoverTrigger = web.html`<div id="enhancer--panel-hover-trigger"></div>`,
|
} else {
|
||||||
panelPinnedAttr = 'data-enhancer-panel-pinned',
|
for (const $elem of $elems) $elem.setAttribute(panelPinnedAttr, 'true');
|
||||||
isPinned = () => $panel.hasAttribute(panelPinnedAttr),
|
|
||||||
togglePanel = () => {
|
|
||||||
const $elems = [$notionRightSidebar, $notionFrame, $hoverTrigger, $panel];
|
|
||||||
if (isPinned()) {
|
|
||||||
closeSwitcher();
|
|
||||||
for (const $elem of $elems) $elem.removeAttribute(panelPinnedAttr);
|
|
||||||
} else {
|
|
||||||
for (const $elem of $elems) $elem.setAttribute(panelPinnedAttr, 'true');
|
|
||||||
}
|
|
||||||
db.set(['panel.pinned'], isPinned());
|
|
||||||
};
|
|
||||||
if (await db.get(['panel.pinned'])) togglePanel();
|
|
||||||
web.addHotkeyListener(await db.get(['panel.hotkey']), togglePanel);
|
|
||||||
$pinnedToggle.addEventListener('click', (event) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
togglePanel();
|
|
||||||
});
|
|
||||||
|
|
||||||
// resizing
|
|
||||||
let dragStartX,
|
|
||||||
dragStartWidth,
|
|
||||||
dragEventsFired,
|
|
||||||
panelWidth = await db.get(['panel.width'], 240);
|
|
||||||
const $resizeHandle = web.html`<div id="enhancer--panel-resize"><div></div></div>`,
|
|
||||||
updateWidth = async () => {
|
|
||||||
document.documentElement.style.setProperty(
|
|
||||||
'--component--panel-width',
|
|
||||||
panelWidth + 'px'
|
|
||||||
);
|
|
||||||
db.set(['panel.width'], panelWidth);
|
|
||||||
},
|
|
||||||
resizeDrag = (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
dragEventsFired = true;
|
|
||||||
panelWidth = dragStartWidth + (dragStartX - event.clientX);
|
|
||||||
if (panelWidth < 190) panelWidth = 190;
|
|
||||||
if (panelWidth > 480) panelWidth = 480;
|
|
||||||
$panel.style.width = panelWidth + 'px';
|
|
||||||
$hoverTrigger.style.width = panelWidth + 'px';
|
|
||||||
$notionFrame.style.paddingRight = panelWidth + 'px';
|
|
||||||
$notionRightSidebar.style.right = panelWidth + 'px';
|
|
||||||
},
|
|
||||||
resizeEnd = (event) => {
|
|
||||||
$panel.style.width = '';
|
|
||||||
$hoverTrigger.style.width = '';
|
|
||||||
$notionFrame.style.paddingRight = '';
|
|
||||||
$notionRightSidebar.style.right = '';
|
|
||||||
updateWidth();
|
|
||||||
$resizeHandle.style.cursor = '';
|
|
||||||
document.body.removeEventListener('mousemove', resizeDrag);
|
|
||||||
document.body.removeEventListener('mouseup', resizeEnd);
|
|
||||||
},
|
|
||||||
resizeStart = (event) => {
|
|
||||||
dragStartX = event.clientX;
|
|
||||||
dragStartWidth = panelWidth;
|
|
||||||
$resizeHandle.style.cursor = 'auto';
|
|
||||||
document.body.addEventListener('mousemove', resizeDrag);
|
|
||||||
document.body.addEventListener('mouseup', resizeEnd);
|
|
||||||
};
|
|
||||||
updateWidth();
|
|
||||||
$resizeHandle.addEventListener('mousedown', resizeStart);
|
|
||||||
$resizeHandle.addEventListener('click', () => {
|
|
||||||
if (dragEventsFired) {
|
|
||||||
dragEventsFired = false;
|
|
||||||
} else togglePanel();
|
|
||||||
});
|
|
||||||
|
|
||||||
// view selection
|
|
||||||
const $title = web.html`<div id="enhancer--panel-header-title"></div>`,
|
|
||||||
$header = web.render(web.html`<div id="enhancer--panel-header"></div>`, $title),
|
|
||||||
$content = web.html`<div id="enhancer--panel-content"></div>`,
|
|
||||||
$switcherTrigger = web.html`<div id="enhancer--panel-header-switcher">
|
|
||||||
${svgExpand}
|
|
||||||
</div>`,
|
|
||||||
$notionApp = document.querySelector('.notion-app-inner'),
|
|
||||||
$switcherOverlayContainer = web.html`<div id="enhancer--panel-switcher-overlay-container"></div>`,
|
|
||||||
$switcher = web.html`<div id="enhancer--panel-switcher"></div>`,
|
|
||||||
isSwitcherOpen = () => document.body.contains($switcher),
|
|
||||||
renderView = (view) => {
|
|
||||||
web.render(
|
|
||||||
web.empty($title),
|
|
||||||
web.render(
|
|
||||||
web.html`<p class="enhancer--panel-view-title"></p>`,
|
|
||||||
view.icon,
|
|
||||||
view.title
|
|
||||||
)
|
|
||||||
);
|
|
||||||
web.render(web.empty($content), view.$elem);
|
|
||||||
},
|
|
||||||
openSwitcher = () => {
|
|
||||||
if (!isPinned()) return togglePanel();
|
|
||||||
web.render($notionApp, $switcherOverlayContainer);
|
|
||||||
web.empty($switcher);
|
|
||||||
for (const view of _views) {
|
|
||||||
const $item = web.render(
|
|
||||||
web.html`<div class="enhancer--panel-switcher-item" tabindex="0"></div>`,
|
|
||||||
web.render(
|
|
||||||
web.html`<p class="enhancer--panel-view-title"></p>`,
|
|
||||||
view.icon.cloneNode(true),
|
|
||||||
view.title.cloneNode(true)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$item.addEventListener('click', () => renderView(view));
|
|
||||||
web.render($switcher, $item);
|
|
||||||
}
|
|
||||||
const rect = $header.getBoundingClientRect();
|
|
||||||
web.render(
|
|
||||||
web.empty($switcherOverlayContainer),
|
|
||||||
web.render(
|
|
||||||
web.html`<div style="position: fixed; top: ${rect.top}px; left: ${rect.left}px;
|
|
||||||
width: ${rect.width}px; height: ${rect.height}px;"></div>`,
|
|
||||||
web.render(
|
|
||||||
web.html`<div style="position: relative; top: 100%; pointer-events: auto;"></div>`,
|
|
||||||
$switcher
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$switcher.firstElementChild.focus();
|
|
||||||
$switcher.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 200 });
|
|
||||||
};
|
|
||||||
function closeSwitcher() {
|
|
||||||
$switcher.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 200 }).onfinish = () =>
|
|
||||||
$switcherOverlayContainer.remove();
|
|
||||||
}
|
}
|
||||||
web.addHotkeyListener(['Escape'], () => {
|
db.set(['panel.pinned'], isPinned());
|
||||||
if (isSwitcherOpen()) closeSwitcher();
|
},
|
||||||
});
|
// resize
|
||||||
web.addHotkeyListener(['Enter'], () => {
|
$resizeHandle = web.html`<div id="enhancer--panel-resize"><div></div></div>`,
|
||||||
if (isSwitcherOpen()) document.activeElement.click();
|
updateWidth = async () => {
|
||||||
});
|
document.documentElement.style.setProperty('--component--panel-width', panelWidth + 'px');
|
||||||
document.addEventListener('keydown', (event) => {
|
db.set(['panel.width'], panelWidth);
|
||||||
if (isSwitcherOpen()) {
|
},
|
||||||
if (event.key === 'ArrowUp') {
|
resizeDrag = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
dragEventsFired = true;
|
||||||
|
panelWidth = dragStartWidth + (dragStartX - event.clientX);
|
||||||
|
if (panelWidth < 190) panelWidth = 190;
|
||||||
|
if (panelWidth > 480) panelWidth = 480;
|
||||||
|
$panel.style.width = panelWidth + 'px';
|
||||||
|
$hoverTrigger.style.width = panelWidth + 'px';
|
||||||
|
$notionFrame.style.paddingRight = panelWidth + 'px';
|
||||||
|
$notionRightSidebar.style.right = panelWidth + 'px';
|
||||||
|
},
|
||||||
|
resizeEnd = (event) => {
|
||||||
|
$panel.style.width = '';
|
||||||
|
$hoverTrigger.style.width = '';
|
||||||
|
$notionFrame.style.paddingRight = '';
|
||||||
|
$notionRightSidebar.style.right = '';
|
||||||
|
updateWidth();
|
||||||
|
$resizeHandle.style.cursor = '';
|
||||||
|
document.body.removeEventListener('mousemove', resizeDrag);
|
||||||
|
document.body.removeEventListener('mouseup', resizeEnd);
|
||||||
|
},
|
||||||
|
resizeStart = (event) => {
|
||||||
|
dragStartX = event.clientX;
|
||||||
|
dragStartWidth = panelWidth;
|
||||||
|
$resizeHandle.style.cursor = 'auto';
|
||||||
|
document.body.addEventListener('mousemove', resizeDrag);
|
||||||
|
document.body.addEventListener('mouseup', resizeEnd);
|
||||||
|
},
|
||||||
|
// render content
|
||||||
|
$panelTitle = web.html`<div id="enhancer--panel-header-title"></div>`,
|
||||||
|
$header = web.render(web.html`<div id="enhancer--panel-header"></div>`, $panelTitle),
|
||||||
|
$panelContent = web.html`<div id="enhancer--panel-content"></div>`,
|
||||||
|
$switcher = web.html`<div id="enhancer--panel-switcher"></div>`,
|
||||||
|
$switcherTrigger = web.html`<div id="enhancer--panel-header-switcher" tabindex="0">
|
||||||
|
${svgExpand}
|
||||||
|
</div>`,
|
||||||
|
$switcherOverlayContainer = web.html`<div id="enhancer--panel-switcher-overlay-container"></div>`,
|
||||||
|
isSwitcherOpen = () => document.body.contains($switcher),
|
||||||
|
openSwitcher = () => {
|
||||||
|
if (!isPinned()) return togglePanel();
|
||||||
|
web.render($notionApp, $switcherOverlayContainer);
|
||||||
|
web.empty($switcher);
|
||||||
|
for (const view of _views) {
|
||||||
|
const open = $panelTitle.contains(view.$title),
|
||||||
|
$item = web.render(
|
||||||
|
web.html`<div class="enhancer--panel-switcher-item" tabindex="0" ${
|
||||||
|
open ? 'data-open' : ''
|
||||||
|
}></div>`,
|
||||||
|
web.render(
|
||||||
|
web.html`<span class="enhancer--panel-view-title"></span>`,
|
||||||
|
view.$icon.cloneNode(true),
|
||||||
|
view.$title.cloneNode(true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$item.addEventListener('click', () => {
|
||||||
|
renderView(view);
|
||||||
|
db.set(['panel.open'], view.id);
|
||||||
|
});
|
||||||
|
web.render($switcher, $item);
|
||||||
|
}
|
||||||
|
const rect = $header.getBoundingClientRect();
|
||||||
|
web.render(
|
||||||
|
web.empty($switcherOverlayContainer),
|
||||||
|
web.render(
|
||||||
|
web.html`<div style="position: fixed; top: ${rect.top}px; left: ${rect.left}px;
|
||||||
|
width: ${rect.width}px; height: ${rect.height}px;"></div>`,
|
||||||
|
web.render(
|
||||||
|
web.html`<div style="position: relative; top: 100%; pointer-events: auto;"></div>`,
|
||||||
|
$switcher
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$switcher.querySelector('[data-open]').focus();
|
||||||
|
$switcher.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 200 });
|
||||||
|
document.addEventListener('keydown', switcherKeyListeners);
|
||||||
|
},
|
||||||
|
closeSwitcher = () => {
|
||||||
|
document.removeEventListener('keydown', switcherKeyListeners);
|
||||||
|
$switcher.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 200 }).onfinish = () =>
|
||||||
|
$switcherOverlayContainer.remove();
|
||||||
|
},
|
||||||
|
switcherKeyListeners = (event) => {
|
||||||
|
if (isSwitcherOpen()) {
|
||||||
|
switch (event.key) {
|
||||||
|
case 'Escape':
|
||||||
|
closeSwitcher();
|
||||||
|
event.stopPropagation();
|
||||||
|
break;
|
||||||
|
case 'Enter':
|
||||||
|
document.activeElement.click();
|
||||||
|
event.stopPropagation();
|
||||||
|
break;
|
||||||
|
case 'ArrowUp':
|
||||||
const $prev = event.target.previousElementSibling;
|
const $prev = event.target.previousElementSibling;
|
||||||
($prev || event.target.parentElement.lastElementChild).focus();
|
($prev || event.target.parentElement.lastElementChild).focus();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
break;
|
||||||
if (event.key === 'ArrowDown') {
|
case 'ArrowDown':
|
||||||
const $next = event.target.nextElementSibling;
|
const $next = event.target.nextElementSibling;
|
||||||
($next || event.target.parentElement.firstElementChild).focus();
|
($next || event.target.parentElement.firstElementChild).focus();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
$header.addEventListener('click', openSwitcher);
|
},
|
||||||
$switcherTrigger.addEventListener('click', openSwitcher);
|
renderView = (view) => {
|
||||||
$switcherOverlayContainer.addEventListener('click', closeSwitcher);
|
|
||||||
renderView(_views[0]);
|
|
||||||
|
|
||||||
web.render(
|
web.render(
|
||||||
$panel,
|
web.empty($panelTitle),
|
||||||
web.render($header, $title, $switcherTrigger, $pinnedToggle),
|
web.render(
|
||||||
$content,
|
web.html`<span class="enhancer--panel-view-title"></span>`,
|
||||||
$resizeHandle
|
view.$icon,
|
||||||
|
view.$title
|
||||||
|
)
|
||||||
);
|
);
|
||||||
$notionRightSidebar.after($hoverTrigger, $panel);
|
web.render(web.empty($panelContent), view.$content);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
async function createPanel() {
|
||||||
|
const notionRightSidebarSelector = '.notion-cursor-listener > div[style*="flex-end"]';
|
||||||
|
await web.whenReady([notionRightSidebarSelector]);
|
||||||
|
$notionFrame = document.querySelector('.notion-frame');
|
||||||
|
$notionRightSidebar = document.querySelector(notionRightSidebarSelector);
|
||||||
|
if (await db.get(['panel.pinned'])) togglePanel();
|
||||||
|
web.addHotkeyListener(await db.get(['panel.hotkey']), togglePanel);
|
||||||
|
$pinnedToggle.addEventListener('click', (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
togglePanel();
|
||||||
|
});
|
||||||
|
web.render(
|
||||||
|
$panel,
|
||||||
|
web.render($header, $panelTitle, $switcherTrigger, $pinnedToggle),
|
||||||
|
$panelContent,
|
||||||
|
$resizeHandle
|
||||||
|
);
|
||||||
|
|
||||||
|
await enablePanelResize();
|
||||||
|
await createViews();
|
||||||
|
|
||||||
|
$notionRightSidebar.after($hoverTrigger, $panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function enablePanelResize() {
|
||||||
|
panelWidth = await db.get(['panel.width'], 240);
|
||||||
|
updateWidth();
|
||||||
|
$resizeHandle.addEventListener('mousedown', resizeStart);
|
||||||
|
$resizeHandle.addEventListener('click', () => {
|
||||||
|
if (dragEventsFired) {
|
||||||
|
dragEventsFired = false;
|
||||||
|
} else togglePanel();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createViews() {
|
||||||
|
$notionApp = document.querySelector('.notion-app-inner');
|
||||||
|
$header.addEventListener('click', openSwitcher);
|
||||||
|
$switcherTrigger.addEventListener('click', openSwitcher);
|
||||||
|
$switcherOverlayContainer.addEventListener('click', closeSwitcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
web.loadStylesheet('api/components/panel.css');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a view to the enhancer's side panel
|
||||||
|
* @param {string} param0.id - a uuid, used to restore the last open view on reload
|
||||||
|
* @param {string} param0.icon - an svg string
|
||||||
|
* @param {string} param0.title - the name of the view
|
||||||
|
* @param {Element} param0.$content - an element containing the content of the view
|
||||||
|
*/
|
||||||
|
export const addPanelView = async ({ id, icon, title, $content }) => {
|
||||||
|
const view = {
|
||||||
|
id,
|
||||||
|
$icon: web.html`<span class="enhancer--panel-view-title-icon">
|
||||||
|
${icon}
|
||||||
|
</span>`,
|
||||||
|
$title: web.html`<span class="enhancer--panel-view-title-text">
|
||||||
|
${web.escape(title)}
|
||||||
|
<span class="enhancer--panel-view-title-fade-edge"> </span>
|
||||||
|
</span>`,
|
||||||
|
$content,
|
||||||
|
};
|
||||||
|
_views.push(view);
|
||||||
|
if (_views.length === 1) await createPanel();
|
||||||
|
if (_views.length === 1 || (await db.get(['panel.open'])) === id) renderView(view);
|
||||||
};
|
};
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
|
|
||||||
import { fmt, web } from '../_.mjs';
|
import { fmt, web } from '../_.mjs';
|
||||||
|
|
||||||
let _$tooltip;
|
const _$tooltip = web.html`<div id="enhancer--tooltip"></div>`;
|
||||||
|
web.loadStylesheet('api/components/tooltip.css');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add a tooltip to show extra information on hover
|
* add a tooltip to show extra information on hover
|
||||||
@ -21,11 +22,7 @@ let _$tooltip;
|
|||||||
* @param {string} text - the markdown content of the tooltip
|
* @param {string} text - the markdown content of the tooltip
|
||||||
*/
|
*/
|
||||||
export const tooltip = ($ref, text) => {
|
export const tooltip = ($ref, text) => {
|
||||||
if (!_$tooltip) {
|
web.render(document.body, _$tooltip);
|
||||||
_$tooltip = web.html`<div id="enhancer--tooltip"></div>`;
|
|
||||||
web.loadStylesheet('api/components/tooltip.css');
|
|
||||||
web.render(document.body, _$tooltip);
|
|
||||||
}
|
|
||||||
text = fmt.md.render(text);
|
text = fmt.md.render(text);
|
||||||
$ref.addEventListener('mouseover', (event) => {
|
$ref.addEventListener('mouseover', (event) => {
|
||||||
_$tooltip.innerHTML = text;
|
_$tooltip.innerHTML = text;
|
||||||
|
@ -30,11 +30,4 @@ export default async function (api, db) {
|
|||||||
_lastPage = getCurrentPage();
|
_lastPage = getCurrentPage();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
components.panel(await components.feather('sidebar'), 'Test Panel', ($panel) => {
|
|
||||||
return web.html`<p>test</p>`;
|
|
||||||
});
|
|
||||||
components.panel(await components.feather('users'), 'Other Panel', ($panel) => {
|
|
||||||
return web.html`<p>yay</p>`;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ const customClasses = {
|
|||||||
'nav-notion': apply`flex items-center font-semibold text-xl cursor-pointer select-none mr-4
|
'nav-notion': apply`flex items-center font-semibold text-xl cursor-pointer select-none mr-4
|
||||||
ml-4 sm:mb-4 md:w-full lg:(w-auto ml-0 mb-0)`,
|
ml-4 sm:mb-4 md:w-full lg:(w-auto ml-0 mb-0)`,
|
||||||
'nav-notion-icon': apply`h-12 w-12 mr-5 sm:(h-6 w-6 mr-3)`,
|
'nav-notion-icon': apply`h-12 w-12 mr-5 sm:(h-6 w-6 mr-3)`,
|
||||||
'nav-item': apply`ml-4 px-3 py-2 rounded-md text-sm font-medium hover:bg-interactive-hover focus:bg-interactive-focus`,
|
'nav-item': apply`ml-4 px-3 py-2 rounded-md text-sm font-medium hover:bg-interactive-hover focus:bg-interactive-active`,
|
||||||
'nav-item-selected': apply`ml-4 px-3 py-2 rounded-md text-sm font-medium ring-1 ring-divider bg-notion-secondary`,
|
'nav-item-selected': apply`ml-4 px-3 py-2 rounded-md text-sm font-medium ring-1 ring-divider bg-notion-secondary`,
|
||||||
'main': apply`transition px-4 py-3 overflow-y-auto max-h-full-64 sm:max-h-full-48 md:max-h-full-32 lg:max-h-full-16`,
|
'main': apply`transition px-4 py-3 overflow-y-auto max-h-full-64 sm:max-h-full-48 md:max-h-full-32 lg:max-h-full-16`,
|
||||||
'main-message': apply`mx-2.5 my-2.5 px-px text-sm text-foreground-secondary text-justify`,
|
'main-message': apply`mx-2.5 my-2.5 px-px text-sm text-foreground-secondary text-justify`,
|
||||||
@ -110,7 +110,7 @@ setup({
|
|||||||
'foreground': 'var(--theme--text)',
|
'foreground': 'var(--theme--text)',
|
||||||
'foreground-secondary': 'var(--theme--text_secondary)',
|
'foreground-secondary': 'var(--theme--text_secondary)',
|
||||||
'interactive-hover': 'var(--theme--ui_interactive-hover)',
|
'interactive-hover': 'var(--theme--ui_interactive-hover)',
|
||||||
'interactive-focus': 'var(--theme--ui_interactive-focus)',
|
'interactive-active': 'var(--theme--ui_interactive-active)',
|
||||||
'tag': 'var(--theme--tag_default)',
|
'tag': 'var(--theme--tag_default)',
|
||||||
'tag-text': 'var(--theme--tag_default-text)',
|
'tag-text': 'var(--theme--tag_default-text)',
|
||||||
'toggle': {
|
'toggle': {
|
||||||
|
@ -349,7 +349,7 @@ body,
|
|||||||
.notion-default-overlay-container
|
.notion-default-overlay-container
|
||||||
[style*='grid-template-columns: [boolean-start] 60px [boolean-end property-start] 120px [property-end opererator-start] 110px [operator-end value-start] auto [value-end menu-start] 32px [menu-end];']
|
[style*='grid-template-columns: [boolean-start] 60px [boolean-end property-start] 120px [property-end opererator-start] 110px [operator-end value-start] auto [value-end menu-start] 32px [menu-end];']
|
||||||
.notion-focusable[style*='background: rgb(223, 223, 222);'] {
|
.notion-focusable[style*='background: rgb(223, 223, 222);'] {
|
||||||
background: var(--theme--ui_interactive-focus) !important;
|
background: var(--theme--ui_interactive-active) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notion-focusable-within,
|
.notion-focusable-within,
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
--theme--ui_shadow: rgba(15, 15, 15, 0.15);
|
--theme--ui_shadow: rgba(15, 15, 15, 0.15);
|
||||||
--theme--ui_divider: rgb(237, 237, 236);
|
--theme--ui_divider: rgb(237, 237, 236);
|
||||||
--theme--ui_interactive-hover: rgba(55, 53, 47, 0.08);
|
--theme--ui_interactive-hover: rgba(55, 53, 47, 0.08);
|
||||||
--theme--ui_interactive-focus: rgba(55, 53, 47, 0.16);
|
--theme--ui_interactive-active: rgba(55, 53, 47, 0.16);
|
||||||
--theme--ui_toggle-on: var(--theme--accent_blue);
|
--theme--ui_toggle-on: var(--theme--accent_blue);
|
||||||
--theme--ui_toggle-off: rgba(135, 131, 120, 0.3);
|
--theme--ui_toggle-off: rgba(135, 131, 120, 0.3);
|
||||||
--theme--ui_toggle-feature: #fff;
|
--theme--ui_toggle-feature: #fff;
|
||||||
@ -211,7 +211,7 @@
|
|||||||
--theme--ui_shadow: rgba(15, 15, 15, 0.15);
|
--theme--ui_shadow: rgba(15, 15, 15, 0.15);
|
||||||
--theme--ui_divider: rgb(255, 255, 255, 0.07);
|
--theme--ui_divider: rgb(255, 255, 255, 0.07);
|
||||||
--theme--ui_interactive-hover: rgb(71, 76, 80);
|
--theme--ui_interactive-hover: rgb(71, 76, 80);
|
||||||
--theme--ui_interactive-focus: rgb(63, 68, 71);
|
--theme--ui_interactive-active: rgb(63, 68, 71);
|
||||||
--theme--ui_toggle-on: var(--theme--accent_blue);
|
--theme--ui_toggle-on: var(--theme--accent_blue);
|
||||||
--theme--ui_toggle-off: rgba(202, 204, 206, 0.3);
|
--theme--ui_toggle-off: rgba(202, 204, 206, 0.3);
|
||||||
--theme--ui_toggle-feature: #fff;
|
--theme--ui_toggle-feature: #fff;
|
||||||
|
Loading…
Reference in New Issue
Block a user