mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-04 12:49: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";
|
||||
|
||||
function Panel(
|
||||
{
|
||||
_getWidth,
|
||||
_setWidth,
|
||||
_getOpen,
|
||||
_setOpen,
|
||||
minWidth = 260,
|
||||
maxWidth = 520,
|
||||
...props
|
||||
},
|
||||
...children
|
||||
) {
|
||||
function Panel({
|
||||
_getWidth,
|
||||
_setWidth,
|
||||
_getOpen,
|
||||
_setOpen,
|
||||
minWidth = 260,
|
||||
maxWidth = 640,
|
||||
...props
|
||||
}) {
|
||||
const { html, extendProps } = globalThis.__enhancerApi;
|
||||
extendProps(props, {
|
||||
class: `notion-enhancer--side-panel order-2 shrink-0
|
||||
transition-[width] open:w-[var(--side\\_panel--width)]
|
||||
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}>
|
||||
<span>Drag</span> to resize<br />
|
||||
<span>Click</span> to closed
|
||||
<//>`,
|
||||
$panel = html`<aside ...${props}>
|
||||
<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])"
|
||||
onmouseover=${function (event) {
|
||||
setTimeout(() => {
|
||||
const panelOpen = $panel.hasAttribute("open"),
|
||||
handleHovered = this.matches(":hover");
|
||||
console.log(panelOpen, handleHovered);
|
||||
if (!panelOpen || !handleHovered) return;
|
||||
const { x } = this.getBoundingClientRect();
|
||||
$tooltip.show(x, event.clientY);
|
||||
}, 200);
|
||||
}}
|
||||
onmouseout=${() => $tooltip.hide()}
|
||||
onclick=${() => $panel.close()}
|
||||
></div>
|
||||
<div>Hello world.</div>
|
||||
</aside>`;
|
||||
showTooltip = (event) => {
|
||||
setTimeout(() => {
|
||||
const panelOpen = $panel.hasAttribute("open"),
|
||||
handleHovered = $resizeHandle.matches(":hover");
|
||||
if (!panelOpen || !handleHovered) return;
|
||||
const { x } = $resizeHandle.getBoundingClientRect();
|
||||
$tooltip.show(x, event.clientY);
|
||||
}, 200);
|
||||
};
|
||||
$resizeHandle.addEventListener("mouseover", showTooltip);
|
||||
$resizeHandle.addEventListener("mouseout", $tooltip.hide);
|
||||
$resizeHandle.addEventListener("click", $panel.close);
|
||||
|
||||
let preDragWidth,
|
||||
dragStartX = 0;
|
||||
const startDrag = async (event) => {
|
||||
dragStartX = event.clientX;
|
||||
preDragWidth = await _getWidth?.();
|
||||
if (isNaN(preDragWidth)) preDragWidth = minWidth;
|
||||
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",
|
||||
repositionHelp = async (attempts = 0) => {
|
||||
@ -80,12 +104,12 @@ function Panel(
|
||||
$notionHelp.animate(keyframes, options);
|
||||
};
|
||||
|
||||
$panel.resize = async (width) => {
|
||||
$panel.resize = async (width, dragActive = false) => {
|
||||
$tooltip.hide();
|
||||
if (width) {
|
||||
width = Math.max(width, minWidth);
|
||||
width = Math.min(width, maxWidth);
|
||||
_setWidth?.(width);
|
||||
if (!dragActive) _setWidth?.(width);
|
||||
} else width = await _getWidth?.();
|
||||
if (isNaN(width)) width = minWidth;
|
||||
$panel.style.setProperty("--side_panel--width", `${width}px`);
|
||||
|
@ -29,7 +29,11 @@ function Tooltip(props, ...children) {
|
||||
if (!document.contains($tooltip)) $notionApp?.append($tooltip);
|
||||
requestAnimationFrame(() => {
|
||||
$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.onshow?.();
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user