mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-11 15:59:03 +00:00
feat: make side panel resizeable
This commit is contained in:
parent
8d679ae3c5
commit
94460375bf
@ -1,31 +0,0 @@
|
|||||||
/**
|
|
||||||
* notion-enhancer: components
|
|
||||||
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
|
||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
|
||||||
*/
|
|
||||||
|
|
||||||
#enhancer--tooltip {
|
|
||||||
font-family: var(--theme--font_sans);
|
|
||||||
background: var(--theme--ui_tooltip);
|
|
||||||
border-radius: 3px;
|
|
||||||
box-shadow: var(--theme--ui_shadow) 0px 1px 4px;
|
|
||||||
color: var(--theme--ui_tooltip-description);
|
|
||||||
display: none;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 1.4;
|
|
||||||
max-width: 20rem;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 4px 8px;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 999999999999999999;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
#enhancer--tooltip p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
#enhancer--tooltip b,
|
|
||||||
#enhancer--tooltip strong {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--theme--ui_tooltip-title);
|
|
||||||
}
|
|
@ -1,118 +0,0 @@
|
|||||||
/**
|
|
||||||
* notion-enhancer: components
|
|
||||||
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
|
||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/** shared notion-style elements */
|
|
||||||
|
|
||||||
import { fs, web } from '../index.mjs';
|
|
||||||
|
|
||||||
let $stylesheet, _$tooltip;
|
|
||||||
|
|
||||||
const countLines = ($el) =>
|
|
||||||
[...$el.getClientRects()].reduce(
|
|
||||||
(prev, val) => (prev.some((p) => p.y === val.y) ? prev : [...prev, val]),
|
|
||||||
[]
|
|
||||||
).length,
|
|
||||||
position = ($ref, offsetDirection, maxLines) => {
|
|
||||||
_$tooltip.style.top = `0px`;
|
|
||||||
_$tooltip.style.left = `0px`;
|
|
||||||
const rect = $ref.getBoundingClientRect(),
|
|
||||||
{ offsetWidth, offsetHeight } = _$tooltip,
|
|
||||||
pad = 6;
|
|
||||||
let x = rect.x,
|
|
||||||
y = Math.floor(rect.y);
|
|
||||||
|
|
||||||
if (['top', 'bottom'].includes(offsetDirection)) {
|
|
||||||
if (offsetDirection === 'top') y -= offsetHeight + pad;
|
|
||||||
if (offsetDirection === 'bottom') y += rect.height + pad;
|
|
||||||
x -= offsetWidth / 2 - rect.width / 2;
|
|
||||||
_$tooltip.style.left = `${x}px`;
|
|
||||||
_$tooltip.style.top = `${y}px`;
|
|
||||||
const testLines = () => countLines(_$tooltip.firstElementChild) > maxLines,
|
|
||||||
padEdgesX = testLines();
|
|
||||||
while (testLines()) {
|
|
||||||
_$tooltip.style.left = `${window.innerWidth - x > x ? x++ : x--}px`;
|
|
||||||
}
|
|
||||||
if (padEdgesX) {
|
|
||||||
x += window.innerWidth - x > x ? pad : -pad;
|
|
||||||
_$tooltip.style.left = `${x}px`;
|
|
||||||
}
|
|
||||||
_$tooltip.style.textAlign = 'center';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (['left', 'right'].includes(offsetDirection)) {
|
|
||||||
y -= offsetHeight / 2 - rect.height / 2;
|
|
||||||
if (offsetDirection === 'left') x -= offsetWidth + pad;
|
|
||||||
if (offsetDirection === 'right') x += rect.width + pad;
|
|
||||||
_$tooltip.style.left = `${x}px`;
|
|
||||||
_$tooltip.style.top = `${y}px`;
|
|
||||||
_$tooltip.style.textAlign = 'start';
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* add a tooltip to show extra information on hover
|
|
||||||
* @param {HTMLElement} $ref - the element that will trigger the tooltip when hovered
|
|
||||||
* @param {string|HTMLElement} $content - markdown or element content of the tooltip
|
|
||||||
* @param {object=} options - configuration of how the tooltip should be displayed
|
|
||||||
* @param {number=} options.delay - the amount of time in ms the element needs to be hovered over
|
|
||||||
* for the tooltip to be shown (default: 100)
|
|
||||||
* @param {string=} options.offsetDirection - which side of the element the tooltip
|
|
||||||
* should be shown on: 'top', 'bottom', 'left' or 'right' (default: 'bottom')
|
|
||||||
* @param {number=} options.maxLines - the max number of lines that the content may be wrapped
|
|
||||||
* to, used to position and size the tooltip correctly (default: 1)
|
|
||||||
*/
|
|
||||||
export const addTooltip = async (
|
|
||||||
$ref,
|
|
||||||
$content,
|
|
||||||
{ delay = 100, offsetDirection = 'bottom', maxLines = 1 } = {}
|
|
||||||
) => {
|
|
||||||
if (!$stylesheet) {
|
|
||||||
$stylesheet = web.loadStylesheet('api/components/tooltip.css');
|
|
||||||
_$tooltip = web.html`<div id="enhancer--tooltip"></div>`;
|
|
||||||
web.render(document.body, _$tooltip);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!globalThis.markdownit) await import(fs.localPath('dep/markdown-it.min.js'));
|
|
||||||
const md = markdownit({ linkify: true });
|
|
||||||
|
|
||||||
if (!($content instanceof Element))
|
|
||||||
$content = web.html`<div style="display:inline">
|
|
||||||
${$content
|
|
||||||
.split('\n')
|
|
||||||
.map((text) => md.renderInline(text))
|
|
||||||
.join('<br>')}
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
let displayDelay;
|
|
||||||
$ref.addEventListener('mouseover', (_event) => {
|
|
||||||
if (!displayDelay) {
|
|
||||||
displayDelay = setTimeout(async () => {
|
|
||||||
if ($ref.matches(':hover')) {
|
|
||||||
if (_$tooltip.style.display !== 'block') {
|
|
||||||
_$tooltip.style.display = 'block';
|
|
||||||
web.render(web.empty(_$tooltip), $content);
|
|
||||||
position($ref, offsetDirection, maxLines);
|
|
||||||
await _$tooltip.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 65 })
|
|
||||||
.finished;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
displayDelay = undefined;
|
|
||||||
}, delay);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$ref.addEventListener('mouseout', async (_event) => {
|
|
||||||
displayDelay = undefined;
|
|
||||||
if (_$tooltip.style.display === 'block' && !$ref.matches(':hover')) {
|
|
||||||
await _$tooltip.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 65 }).finished;
|
|
||||||
_$tooltip.style.display = '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
@ -17,50 +17,74 @@
|
|||||||
|
|
||||||
import { Tooltip } from "./Tooltip.mjs";
|
import { Tooltip } from "./Tooltip.mjs";
|
||||||
|
|
||||||
function Panel(
|
function Panel({
|
||||||
{
|
_getWidth,
|
||||||
_getWidth,
|
_setWidth,
|
||||||
_setWidth,
|
_getOpen,
|
||||||
_getOpen,
|
_setOpen,
|
||||||
_setOpen,
|
minWidth = 260,
|
||||||
minWidth = 260,
|
maxWidth = 640,
|
||||||
maxWidth = 520,
|
...props
|
||||||
...props
|
}) {
|
||||||
},
|
|
||||||
...children
|
|
||||||
) {
|
|
||||||
const { html, extendProps } = globalThis.__enhancerApi;
|
const { html, extendProps } = globalThis.__enhancerApi;
|
||||||
extendProps(props, {
|
extendProps(props, {
|
||||||
class: `notion-enhancer--side-panel order-2 shrink-0
|
class: `notion-enhancer--side-panel order-2 shrink-0
|
||||||
transition-[width] open:w-[var(--side\\_panel--width)]
|
transition-[width] open:w-[var(--side\\_panel--width)]
|
||||||
w-0 border-l-1 border-[color:var(--theme--fg-border)]
|
w-0 border-l-1 border-[color:var(--theme--fg-border)]
|
||||||
relative bg-[color:var(--theme--bg-primary)]`,
|
relative bg-[color:var(--theme--bg-primary)] group`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const $resizeHandle = html`<div
|
||||||
|
class="absolute h-full w-[3px] left-[-3px]
|
||||||
|
z-10 transition duration-300 hover:(cursor-col-resize
|
||||||
|
shadow-[var(--theme--fg-border)_-2px_0px_0px_0px_inset])
|
||||||
|
active:cursor-text group-not-[open]:hidden"
|
||||||
|
></div>`,
|
||||||
|
$panel = html`<aside ...${props}>
|
||||||
|
${$resizeHandle}
|
||||||
|
<div>Hello world.</div>
|
||||||
|
</aside>`;
|
||||||
|
|
||||||
const $tooltip = html`<${Tooltip}>
|
const $tooltip = html`<${Tooltip}>
|
||||||
<span>Drag</span> to resize<br />
|
<span>Drag</span> to resize<br />
|
||||||
<span>Click</span> to closed
|
<span>Click</span> to closed
|
||||||
<//>`,
|
<//>`,
|
||||||
$panel = html`<aside ...${props}>
|
showTooltip = (event) => {
|
||||||
<div
|
setTimeout(() => {
|
||||||
class="absolute h-full w-[3px] left-[-3px] z-10
|
const panelOpen = $panel.hasAttribute("open"),
|
||||||
transition duration-300 hover:(cursor-col-resize
|
handleHovered = $resizeHandle.matches(":hover");
|
||||||
shadow-[var(--theme--fg-border)_-2px_0px_0px_0px_inset])"
|
if (!panelOpen || !handleHovered) return;
|
||||||
onmouseover=${function (event) {
|
const { x } = $resizeHandle.getBoundingClientRect();
|
||||||
setTimeout(() => {
|
$tooltip.show(x, event.clientY);
|
||||||
const panelOpen = $panel.hasAttribute("open"),
|
}, 200);
|
||||||
handleHovered = this.matches(":hover");
|
};
|
||||||
console.log(panelOpen, handleHovered);
|
$resizeHandle.addEventListener("mouseover", showTooltip);
|
||||||
if (!panelOpen || !handleHovered) return;
|
$resizeHandle.addEventListener("mouseout", $tooltip.hide);
|
||||||
const { x } = this.getBoundingClientRect();
|
$resizeHandle.addEventListener("click", $panel.close);
|
||||||
$tooltip.show(x, event.clientY);
|
|
||||||
}, 200);
|
let preDragWidth,
|
||||||
}}
|
dragStartX = 0;
|
||||||
onmouseout=${() => $tooltip.hide()}
|
const startDrag = async (event) => {
|
||||||
onclick=${() => $panel.close()}
|
dragStartX = event.clientX;
|
||||||
></div>
|
preDragWidth = await _getWidth?.();
|
||||||
<div>Hello world.</div>
|
if (isNaN(preDragWidth)) preDragWidth = minWidth;
|
||||||
</aside>`;
|
document.addEventListener("mousemove", onDrag);
|
||||||
|
document.addEventListener("mouseup", endDrag);
|
||||||
|
$panel.style.transitionDuration = "0ms";
|
||||||
|
},
|
||||||
|
onDrag = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const newWidth = preDragWidth + (dragStartX - event.clientX);
|
||||||
|
$panel.resize(newWidth, true);
|
||||||
|
},
|
||||||
|
endDrag = (event) => {
|
||||||
|
document.removeEventListener("mousemove", onDrag);
|
||||||
|
document.removeEventListener("mouseup", endDrag);
|
||||||
|
const finalWidth = preDragWidth + (dragStartX - event.clientX);
|
||||||
|
$panel.style.transitionDuration = "";
|
||||||
|
$panel.resize(finalWidth);
|
||||||
|
};
|
||||||
|
$resizeHandle.addEventListener("mousedown", startDrag);
|
||||||
|
|
||||||
const notionHelp = ".notion-help-button",
|
const notionHelp = ".notion-help-button",
|
||||||
repositionHelp = async (attempts = 0) => {
|
repositionHelp = async (attempts = 0) => {
|
||||||
@ -80,12 +104,12 @@ function Panel(
|
|||||||
$notionHelp.animate(keyframes, options);
|
$notionHelp.animate(keyframes, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
$panel.resize = async (width) => {
|
$panel.resize = async (width, dragActive = false) => {
|
||||||
$tooltip.hide();
|
$tooltip.hide();
|
||||||
if (width) {
|
if (width) {
|
||||||
width = Math.max(width, minWidth);
|
width = Math.max(width, minWidth);
|
||||||
width = Math.min(width, maxWidth);
|
width = Math.min(width, maxWidth);
|
||||||
_setWidth?.(width);
|
if (!dragActive) _setWidth?.(width);
|
||||||
} else width = await _getWidth?.();
|
} else width = await _getWidth?.();
|
||||||
if (isNaN(width)) width = minWidth;
|
if (isNaN(width)) width = minWidth;
|
||||||
$panel.style.setProperty("--side_panel--width", `${width}px`);
|
$panel.style.setProperty("--side_panel--width", `${width}px`);
|
||||||
|
@ -29,7 +29,11 @@ function Tooltip(props, ...children) {
|
|||||||
if (!document.contains($tooltip)) $notionApp?.append($tooltip);
|
if (!document.contains($tooltip)) $notionApp?.append($tooltip);
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
$tooltip.setAttribute("open", true);
|
$tooltip.setAttribute("open", true);
|
||||||
$tooltip.style.left = `${x - $tooltip.clientWidth - 6}px`;
|
x -= $tooltip.clientWidth + 6;
|
||||||
|
if (x < 0) x += $tooltip.clientWidth + 12;
|
||||||
|
y -= $tooltip.clientHeight / 2;
|
||||||
|
if (y < 0) y += $tooltip.clientHeight / 2;
|
||||||
|
$tooltip.style.left = `${x}px`;
|
||||||
$tooltip.style.top = `${y}px`;
|
$tooltip.style.top = `${y}px`;
|
||||||
$tooltip.onshow?.();
|
$tooltip.onshow?.();
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user