mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-06 21:49:03 +00:00
side panel component: working except switcher
This commit is contained in:
parent
33e8907d4f
commit
bc38f5d972
@ -21,5 +21,5 @@ export * as fmt from './fmt.mjs';
|
|||||||
export * as registry from './registry.mjs';
|
export * as registry from './registry.mjs';
|
||||||
/** helpers for manipulation of a webpage */
|
/** helpers for manipulation of a webpage */
|
||||||
export * as web from './web.mjs';
|
export * as web from './web.mjs';
|
||||||
/** notion-style elements inc. the sidebar */
|
/** shared notion-style elements */
|
||||||
export * as components from './components/_.mjs';
|
export * as components from './components/_.mjs';
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* notion-style elements inc. the sidebar
|
* shared notion-style elements
|
||||||
* @module notion-enhancer/api/components
|
* @module notion-enhancer/api/components
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -18,4 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
export { tooltip } from './tooltip.mjs';
|
export { tooltip } from './tooltip.mjs';
|
||||||
|
|
||||||
export { side } from './tooltip.mjs';
|
/**
|
||||||
|
* generate an icon from the feather icons set
|
||||||
|
* @param {string} name - the name/id of the icon
|
||||||
|
* @param {object} attrs - an object of attributes to apply to the icon e.g. classes
|
||||||
|
* @returns {string} an svg string
|
||||||
|
*/
|
||||||
|
export { feather } from './feather.mjs';
|
||||||
|
|
||||||
|
export { panel } from './panel.mjs';
|
||||||
|
36
extension/api/components/feather.mjs
Normal file
36
extension/api/components/feather.mjs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* notion-enhancer: api
|
||||||
|
* (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
|
||||||
|
* @module notion-enhancer/api/components/feather
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { fs, web } from '../_.mjs';
|
||||||
|
|
||||||
|
let _$iconSheet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generate an icon from the feather icons set
|
||||||
|
* @param {string} name - the name/id of the icon
|
||||||
|
* @param {object} attrs - an object of attributes to apply to the icon e.g. classes
|
||||||
|
* @returns {string} an svg string
|
||||||
|
*/
|
||||||
|
export const feather = async (name, attrs = {}) => {
|
||||||
|
if (!_$iconSheet) {
|
||||||
|
_$iconSheet = web.html`${await fs.getText('dep/feather-sprite.svg')}`;
|
||||||
|
}
|
||||||
|
attrs.style = (
|
||||||
|
(attrs.style ? attrs.style + ';' : '') +
|
||||||
|
'stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;fill:none;'
|
||||||
|
).trim();
|
||||||
|
attrs.viewBox = '0 0 24 24';
|
||||||
|
return `<svg ${Object.entries(attrs)
|
||||||
|
.map(([key, val]) => `${web.escape(key)}="${web.escape(val)}"`)
|
||||||
|
.join(' ')}>${_$iconSheet.getElementById(name)?.innerHTML}</svg>`;
|
||||||
|
};
|
151
extension/api/components/panel.css
Normal file
151
extension/api/components/panel.css
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* notion-enhancer core: components
|
||||||
|
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||||
|
* (c) 2021 CloudHill <rl.cloudhill@gmail.com> (https://github.com/CloudHill)
|
||||||
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--component--panel-width: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#enhancer--panel-hover-trigger {
|
||||||
|
height: 100vh;
|
||||||
|
width: 2.5rem;
|
||||||
|
max-height: 100%;
|
||||||
|
z-index: 999;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: width 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
#enhancer--panel-hover-trigger[data-enhancer-panel-pinned] {
|
||||||
|
/* taking up the physical space of the panel to move topbar buttons */
|
||||||
|
position: relative;
|
||||||
|
width: var(--component--panel-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
.notion-cursor-listener > div[style*='flex-end'] {
|
||||||
|
transition: margin-right 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
.notion-cursor-listener > div[style*='flex-end'][data-enhancer-panel-pinned] {
|
||||||
|
margin-right: var(--component--panel-width);
|
||||||
|
}
|
||||||
|
.notion-frame {
|
||||||
|
transition: padding-right 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
.notion-frame[data-enhancer-panel-pinned] {
|
||||||
|
padding-right: var(--component--panel-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
#enhancer--panel {
|
||||||
|
z-index: 999;
|
||||||
|
position: absolute;
|
||||||
|
background: var(--theme--bg_secondary);
|
||||||
|
width: var(--component--panel-width);
|
||||||
|
right: calc(-1 * var(--component--panel-width));
|
||||||
|
opacity: 0;
|
||||||
|
height: 100vh;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
transition: 300ms ease-in;
|
||||||
|
|
||||||
|
margin-top: 5rem;
|
||||||
|
max-height: calc(100vh - 10rem);
|
||||||
|
}
|
||||||
|
#enhancer--panel-hover-trigger:hover + #enhancer--panel:not([data-enhancer-panel-pinned]),
|
||||||
|
#enhancer--panel:not([data-enhancer-panel-pinned]):hover {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(calc(-1 * var(--component--panel-width)));
|
||||||
|
box-shadow: var(--theme--ui_shadow, rgba(15, 15, 15, 0.05)) 0px 0px 0px 1px,
|
||||||
|
var(--theme--ui_shadow, rgba(15, 15, 15, 0.1)) 0px 3px 6px,
|
||||||
|
var(--theme--ui_shadow, rgba(15, 15, 15, 0.2)) 0px 9px 24px !important;
|
||||||
|
}
|
||||||
|
#enhancer--panel[data-enhancer-panel-pinned] {
|
||||||
|
opacity: 1;
|
||||||
|
max-height: 100%;
|
||||||
|
margin-top: 0;
|
||||||
|
transform: translateX(calc(-1 * var(--component--panel-width)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#enhancer--panel-header {
|
||||||
|
font-size: 1.35rem;
|
||||||
|
font-weight: bold;
|
||||||
|
display: flex;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
#enhancer--panel-content {
|
||||||
|
font-size: 1rem;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
}
|
||||||
|
#enhancer--panel-header-title {
|
||||||
|
padding-left: 0.5em;
|
||||||
|
padding-bottom: 0.1em;
|
||||||
|
}
|
||||||
|
#enhancer--panel-header-title > p {
|
||||||
|
margin: 0;
|
||||||
|
height: 1em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
#enhancer--panel-header-title > p svg,
|
||||||
|
#enhancer--panel-header-title > p img {
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
}
|
||||||
|
#enhancer--panel-header-title > p span {
|
||||||
|
font-size: 0.9em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
#enhancer--panel-header-toggle {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
#enhancer--panel-header-toggle,
|
||||||
|
#enhancer--panel-header-switcher {
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0;
|
||||||
|
transition: 300ms ease-in-out;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
#enhancer--panel-header-switcher svg {
|
||||||
|
width: 0.5em;
|
||||||
|
height: 0.5em;
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#enhancer--panel:not([data-enhancer-panel-pinned]) #enhancer--panel-header-toggle {
|
||||||
|
transform: rotateZ(-180deg);
|
||||||
|
}
|
||||||
|
#enhancer--panel:hover #enhancer--panel-header-toggle,
|
||||||
|
#enhancer--panel:hover #enhancer--panel-header-switcher {
|
||||||
|
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);
|
||||||
|
}
|
141
extension/api/components/panel.mjs
Normal file
141
extension/api/components/panel.mjs
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* notion-enhancer: api
|
||||||
|
* (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
|
||||||
|
* @module notion-enhancer/api/components/side-panel
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { web, components, registry } from '../_.mjs';
|
||||||
|
const db = await registry.db('36a2ffc9-27ff-480e-84a7-c7700a7d232d');
|
||||||
|
|
||||||
|
let $panel,
|
||||||
|
_views = [];
|
||||||
|
|
||||||
|
export const panel = async (icon, title, generator = () => {}) => {
|
||||||
|
_views.push({
|
||||||
|
icon: web.html`${icon}`,
|
||||||
|
title: web.html`<span>${web.escape(title)}</span>`,
|
||||||
|
$elem: generator(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!$panel) {
|
||||||
|
$panel = web.html`<div id="enhancer--panel"></div>`;
|
||||||
|
|
||||||
|
const notionRightSidebarSelector = '.notion-cursor-listener > div[style*="flex-end"]';
|
||||||
|
await web.whenReady([notionRightSidebarSelector]);
|
||||||
|
web.loadStylesheet('api/components/panel.css');
|
||||||
|
|
||||||
|
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>`;
|
||||||
|
|
||||||
|
// opening/closing
|
||||||
|
const $notionFrame = document.querySelector('.notion-frame'),
|
||||||
|
$notionRightSidebar = document.querySelector(notionRightSidebarSelector),
|
||||||
|
$pinnedToggle = web.html`<div id="enhancer--panel-header-toggle">
|
||||||
|
${await components.feather('chevrons-right')}
|
||||||
|
</div>`,
|
||||||
|
$hoverTrigger = web.html`<div id="enhancer--panel-hover-trigger"></div>`,
|
||||||
|
panelPinnedAttr = 'data-enhancer-panel-pinned',
|
||||||
|
isPinned = () => $panel.hasAttribute(panelPinnedAttr),
|
||||||
|
isRightSidebarOpen = () =>
|
||||||
|
$notionRightSidebar.matches('[style*="border-left: 1px solid rgba(0, 0, 0, 0)"]'),
|
||||||
|
togglePanel = () => {
|
||||||
|
const $elems = [$notionRightSidebar, $hoverTrigger, $panel];
|
||||||
|
if (isPinned()) {
|
||||||
|
if (isRightSidebarOpen()) $elems.push($notionFrame);
|
||||||
|
for (const $elem of $elems) $elem.removeAttribute(panelPinnedAttr);
|
||||||
|
} else {
|
||||||
|
$elems.push($notionFrame);
|
||||||
|
for (const $elem of $elems) $elem.setAttribute(panelPinnedAttr, 'true');
|
||||||
|
}
|
||||||
|
db.set(['panel.pinned'], isPinned());
|
||||||
|
};
|
||||||
|
web.addDocumentObserver(() => {
|
||||||
|
if (isPinned()) {
|
||||||
|
if (isRightSidebarOpen()) {
|
||||||
|
$notionFrame.removeAttribute(panelPinnedAttr);
|
||||||
|
} else {
|
||||||
|
$notionFrame.setAttribute(panelPinnedAttr, 'true');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [notionRightSidebarSelector]);
|
||||||
|
if (await db.get(['panel.pinned'])) togglePanel();
|
||||||
|
web.addHotkeyListener(await db.get(['panel.hotkey']), togglePanel);
|
||||||
|
$pinnedToggle.addEventListener('click', 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 $switcherTrigger = web.html`<div id="enhancer--panel-header-switcher">
|
||||||
|
${await components.feather('chevron-up')}
|
||||||
|
${await components.feather('chevron-down')}
|
||||||
|
</div>`,
|
||||||
|
renderView = (view) => {
|
||||||
|
web.render(web.empty($title), web.render(web.html`<p></p>`, view.icon, view.title));
|
||||||
|
web.render(web.empty($content), view.$elem);
|
||||||
|
};
|
||||||
|
renderView(_views[0]);
|
||||||
|
|
||||||
|
web.render(
|
||||||
|
$panel,
|
||||||
|
web.render($header, $switcherTrigger, $title, $pinnedToggle),
|
||||||
|
$content,
|
||||||
|
$resizeHandle
|
||||||
|
);
|
||||||
|
$notionRightSidebar.after($hoverTrigger, $panel);
|
||||||
|
}
|
||||||
|
};
|
@ -1,6 +0,0 @@
|
|||||||
/*
|
|
||||||
* notion-enhancer core: components
|
|
||||||
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
|
||||||
* (c) 2021 CloudHill <rl.cloudhill@gmail.com> (https://github.com/CloudHill)
|
|
||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
|
||||||
*/
|
|
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* notion-enhancer: api
|
|
||||||
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
|
||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* notion-style elements inc. the sidebar
|
|
||||||
* @module notion-enhancer/api/components/side-panel
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { web } from '../_.mjs';
|
|
||||||
|
|
||||||
let _$sidebar;
|
|
||||||
|
|
||||||
export const sidebar = (icon, name, loader = ($panel) => {}) => {
|
|
||||||
if (!_$sidebar) {
|
|
||||||
web.loadStylesheet('api/components/sidebar.css');
|
|
||||||
_$sidebar = web.html`<div id="enhancer--sidebar"></div>`;
|
|
||||||
web.render(document.body, _$sidebar);
|
|
||||||
}
|
|
||||||
};
|
|
@ -7,7 +7,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* notion-style elements inc. the sidebar
|
* shared notion-style elements
|
||||||
* @module notion-enhancer/api/components/tooltip
|
* @module notion-enhancer/api/components/tooltip
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -22,8 +22,8 @@ let _$tooltip;
|
|||||||
*/
|
*/
|
||||||
export const tooltip = ($ref, text) => {
|
export const tooltip = ($ref, text) => {
|
||||||
if (!_$tooltip) {
|
if (!_$tooltip) {
|
||||||
web.loadStylesheet('api/components/tooltip.css');
|
|
||||||
_$tooltip = web.html`<div id="enhancer--tooltip"></div>`;
|
_$tooltip = web.html`<div id="enhancer--tooltip"></div>`;
|
||||||
|
web.loadStylesheet('api/components/tooltip.css');
|
||||||
web.render(document.body, _$tooltip);
|
web.render(document.body, _$tooltip);
|
||||||
}
|
}
|
||||||
text = fmt.md.render(text);
|
text = fmt.md.render(text);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* @module notion-enhancer/api/fmt
|
* @module notion-enhancer/api/fmt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { web, fs } from './_.mjs';
|
import { web, fs, components } from './_.mjs';
|
||||||
|
|
||||||
import '../dep/prism.min.js';
|
import '../dep/prism.min.js';
|
||||||
/** syntax highlighting using https://prismjs.com/ */
|
/** syntax highlighting using https://prismjs.com/ */
|
||||||
@ -21,7 +21,7 @@ Prism.hooks.add('complete', async (event) => {
|
|||||||
event.element.parentElement.removeAttribute('tabindex');
|
event.element.parentElement.removeAttribute('tabindex');
|
||||||
event.element.parentElement.parentElement
|
event.element.parentElement.parentElement
|
||||||
.querySelector('.copy-to-clipboard-button')
|
.querySelector('.copy-to-clipboard-button')
|
||||||
.prepend(web.html`${await web.icon('clipboard')}`);
|
.prepend(web.html`${await components.feather('clipboard')}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
import '../dep/markdown-it.min.js';
|
import '../dep/markdown-it.min.js';
|
||||||
|
@ -13,12 +13,6 @@
|
|||||||
|
|
||||||
import { fs, fmt } from './_.mjs';
|
import { fs, fmt } from './_.mjs';
|
||||||
|
|
||||||
const _hotkeyEventListeners = [],
|
|
||||||
_documentObserverListeners = [],
|
|
||||||
_documentObserverEvents = [];
|
|
||||||
|
|
||||||
let _hotkeyEvent, _documentObserver;
|
|
||||||
|
|
||||||
import '../dep/jscolor.min.js';
|
import '../dep/jscolor.min.js';
|
||||||
/** color picker with alpha channel using https://jscolor.com/ */
|
/** color picker with alpha channel using https://jscolor.com/ */
|
||||||
export const jscolor = JSColor;
|
export const jscolor = JSColor;
|
||||||
@ -144,21 +138,27 @@ export const loadStylesheet = (path) => {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
const _hotkeyEvent = document.addEventListener('keyup', (event) => {
|
||||||
* generate an icon from the feather icons set
|
if (document.activeElement.nodeName === 'INPUT') return;
|
||||||
* @param {string} name - the name/id of the icon
|
for (const hotkey of _hotkeyEventListeners) {
|
||||||
* @param {object} attrs - an object of attributes to apply to the icon e.g. classes
|
const pressed = hotkey.keys.every((key) => {
|
||||||
* @returns {string} an svg string
|
key = key.toLowerCase();
|
||||||
*/
|
const modifiers = {
|
||||||
export const icon = (name, attrs = {}) => {
|
metaKey: ['meta', 'os', 'win', 'cmd', 'command'],
|
||||||
attrs.style = (
|
ctrlKey: ['ctrl', 'control'],
|
||||||
(attrs.style || '') +
|
shiftKey: ['shift'],
|
||||||
';stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;fill:none;'
|
altKey: ['alt'],
|
||||||
).trim();
|
};
|
||||||
return `<svg ${Object.entries(attrs)
|
for (const modifier in modifiers) {
|
||||||
.map(([key, val]) => `${escape(key)}="${escape(val)}"`)
|
const pressed = modifiers[modifier].includes(key) && event[modifier];
|
||||||
.join(' ')}><use xlink:href="${fs.localPath('dep/feather-sprite.svg')}#${name}" /></svg>`;
|
if (pressed) return true;
|
||||||
};
|
}
|
||||||
|
if (key === event.key.toLowerCase()) return true;
|
||||||
|
});
|
||||||
|
if (pressed) hotkey.callback();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
_hotkeyEventListeners = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* register a hotkey listener to the page
|
* register a hotkey listener to the page
|
||||||
@ -169,28 +169,6 @@ export const icon = (name, attrs = {}) => {
|
|||||||
*/
|
*/
|
||||||
export const addHotkeyListener = (keys, callback) => {
|
export const addHotkeyListener = (keys, callback) => {
|
||||||
if (typeof keys === 'string') keys = keys.split('+');
|
if (typeof keys === 'string') keys = keys.split('+');
|
||||||
if (!_hotkeyEvent) {
|
|
||||||
_hotkeyEvent = document.addEventListener('keyup', (event) => {
|
|
||||||
if (document.activeElement.nodeName === 'INPUT') return;
|
|
||||||
for (const hotkey of _hotkeyEventListeners) {
|
|
||||||
const pressed = hotkey.keys.every((key) => {
|
|
||||||
key = key.toLowerCase();
|
|
||||||
const modifiers = {
|
|
||||||
metaKey: ['meta', 'os', 'win', 'cmd', 'command'],
|
|
||||||
ctrlKey: ['ctrl', 'control'],
|
|
||||||
shiftKey: ['shift'],
|
|
||||||
altKey: ['alt'],
|
|
||||||
};
|
|
||||||
for (const modifier in modifiers) {
|
|
||||||
const pressed = modifiers[modifier].includes(key) && event[modifier];
|
|
||||||
if (pressed) return true;
|
|
||||||
}
|
|
||||||
if (key === event.key.toLowerCase()) return true;
|
|
||||||
});
|
|
||||||
if (pressed) hotkey.callback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_hotkeyEventListeners.push({ keys, callback });
|
_hotkeyEventListeners.push({ keys, callback });
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
@ -203,40 +181,39 @@ export const removeHotkeyListener = (callback) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const _documentObserver = new MutationObserver((list, observer) => {
|
||||||
|
if (!_documentObserverEvents.length)
|
||||||
|
requestIdleCallback(() => (queue) => {
|
||||||
|
while (queue.length) {
|
||||||
|
const event = queue.shift();
|
||||||
|
for (const listener of _documentObserverListeners) {
|
||||||
|
if (
|
||||||
|
!listener.selectors.length ||
|
||||||
|
listener.selectors.some(
|
||||||
|
(selector) =>
|
||||||
|
event.target.matches(selector) || event.target.matches(`${selector} *`)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
listener.callback(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_documentObserverEvents.push(...list);
|
||||||
|
}),
|
||||||
|
_documentObserverListeners = [],
|
||||||
|
_documentObserverEvents = [];
|
||||||
|
_documentObserver.observe(document.body, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
attributes: true,
|
||||||
|
});
|
||||||
/**
|
/**
|
||||||
* add a listener to watch for changes to the dom
|
* add a listener to watch for changes to the dom
|
||||||
* @param {onDocumentObservedCallback} callback
|
* @param {onDocumentObservedCallback} callback
|
||||||
* @param {array<string>} [selectors]
|
* @param {array<string>} [selectors]
|
||||||
*/
|
*/
|
||||||
export const addDocumentObserver = (callback, selectors = []) => {
|
export const addDocumentObserver = (callback, selectors = []) => {
|
||||||
if (!_documentObserver) {
|
|
||||||
const handle = (queue) => {
|
|
||||||
while (queue.length) {
|
|
||||||
const event = queue.shift();
|
|
||||||
for (const listener of _documentObserverListeners) {
|
|
||||||
if (
|
|
||||||
!listener.selectors.length ||
|
|
||||||
listener.selectors.some(
|
|
||||||
(selector) =>
|
|
||||||
event.target.matches(selector) || event.target.matches(`${selector} *`)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
listener.callback(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_documentObserver = new MutationObserver((list, observer) => {
|
|
||||||
if (!_documentObserverEvents.length)
|
|
||||||
requestIdleCallback(() => handle(_documentObserverEvents));
|
|
||||||
_documentObserverEvents.push(...list);
|
|
||||||
});
|
|
||||||
_documentObserver.observe(document.body, {
|
|
||||||
childList: true,
|
|
||||||
subtree: true,
|
|
||||||
attributes: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_documentObserverListeners.push({ callback, selectors });
|
_documentObserverListeners.push({ callback, selectors });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export default async function (api, db) {
|
export default async function (api, db) {
|
||||||
const { web } = api;
|
const { web, components } = api;
|
||||||
await web.whenReady();
|
await web.whenReady();
|
||||||
|
|
||||||
let _lastPage = {};
|
let _lastPage = {};
|
||||||
@ -30,4 +30,8 @@ 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>`;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "components",
|
"name": "components",
|
||||||
"id": "36a2ffc9-27ff-480e-84a7-c7700a7d232d",
|
"id": "36a2ffc9-27ff-480e-84a7-c7700a7d232d",
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"description": "notion-style elements reused by other mods, inc. the sidebar.",
|
"description": "shared notion-style elements.",
|
||||||
"tags": ["core"],
|
"tags": ["core"],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
@ -24,10 +24,10 @@
|
|||||||
"options": [
|
"options": [
|
||||||
{
|
{
|
||||||
"type": "hotkey",
|
"type": "hotkey",
|
||||||
"key": "side-panel-hotkey",
|
"key": "panel.hotkey",
|
||||||
"label": "toggle enhancer sidebar hotkey",
|
"label": "toggle panel hotkey",
|
||||||
"value": "Ctrl+Alt+\\",
|
"value": "Ctrl+Alt+\\",
|
||||||
"tooltip": "opens/closes the extra sidebar in notion - will only work if a mod is making use of it."
|
"tooltip": "opens/closes the side panel in notion - will only work if a mod is making use of it."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ export const options = {
|
|||||||
toggle: async (mod, opt) => {
|
toggle: async (mod, opt) => {
|
||||||
const checked = await profileDB.get([mod.id, opt.key], opt.value),
|
const checked = await profileDB.get([mod.id, opt.key], opt.value),
|
||||||
$toggle = blocks.toggle(opt.label, checked),
|
$toggle = blocks.toggle(opt.label, checked),
|
||||||
$tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = $toggle.children[0],
|
$label = $toggle.children[0],
|
||||||
$input = $toggle.children[1];
|
$input = $toggle.children[1];
|
||||||
if (opt.tooltip) {
|
if (opt.tooltip) {
|
||||||
@ -73,7 +73,7 @@ export const options = {
|
|||||||
},
|
},
|
||||||
select: async (mod, opt) => {
|
select: async (mod, opt) => {
|
||||||
const value = await profileDB.get([mod.id, opt.key], opt.values[0]),
|
const value = await profileDB.get([mod.id, opt.key], opt.values[0]),
|
||||||
$tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = web.render(
|
$label = web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
|
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
|
||||||
@ -88,7 +88,7 @@ export const options = {
|
|||||||
$select = web.html`<select class="input">
|
$select = web.html`<select class="input">
|
||||||
${$options.join('')}
|
${$options.join('')}
|
||||||
</select>`,
|
</select>`,
|
||||||
$icon = web.html`${web.icon('chevron-down', { class: 'input-icon' })}`;
|
$icon = web.html`${await components.feather('chevron-down', { class: 'input-icon' })}`;
|
||||||
if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
|
if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
|
||||||
$select.addEventListener('change', async (event) => {
|
$select.addEventListener('change', async (event) => {
|
||||||
await profileDB.set([mod.id, opt.key], $select.value);
|
await profileDB.set([mod.id, opt.key], $select.value);
|
||||||
@ -98,13 +98,13 @@ export const options = {
|
|||||||
},
|
},
|
||||||
text: async (mod, opt) => {
|
text: async (mod, opt) => {
|
||||||
const value = await profileDB.get([mod.id, opt.key], opt.value),
|
const value = await profileDB.get([mod.id, opt.key], opt.value),
|
||||||
$tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = web.render(
|
$label = web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
|
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
|
||||||
),
|
),
|
||||||
$input = web.html`<input type="text" class="input" value="${web.escape(value)}">`,
|
$input = web.html`<input type="text" class="input" value="${web.escape(value)}">`,
|
||||||
$icon = web.html`${web.icon('type', { class: 'input-icon' })}`;
|
$icon = web.html`${await components.feather('type', { class: 'input-icon' })}`;
|
||||||
if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
|
if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
|
||||||
$input.addEventListener('change', async (event) => {
|
$input.addEventListener('change', async (event) => {
|
||||||
await profileDB.set([mod.id, opt.key], $input.value);
|
await profileDB.set([mod.id, opt.key], $input.value);
|
||||||
@ -114,13 +114,13 @@ export const options = {
|
|||||||
},
|
},
|
||||||
number: async (mod, opt) => {
|
number: async (mod, opt) => {
|
||||||
const value = await profileDB.get([mod.id, opt.key], opt.value),
|
const value = await profileDB.get([mod.id, opt.key], opt.value),
|
||||||
$tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = web.render(
|
$label = web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
|
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
|
||||||
),
|
),
|
||||||
$input = web.html`<input type="number" class="input" value="${value}">`,
|
$input = web.html`<input type="number" class="input" value="${value}">`,
|
||||||
$icon = web.html`${web.icon('hash', { class: 'input-icon' })}`;
|
$icon = web.html`${await components.feather('hash', { class: 'input-icon' })}`;
|
||||||
if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
|
if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
|
||||||
$input.addEventListener('change', async (event) => {
|
$input.addEventListener('change', async (event) => {
|
||||||
await profileDB.set([mod.id, opt.key], $input.value);
|
await profileDB.set([mod.id, opt.key], $input.value);
|
||||||
@ -130,13 +130,13 @@ export const options = {
|
|||||||
},
|
},
|
||||||
color: async (mod, opt) => {
|
color: async (mod, opt) => {
|
||||||
const value = await profileDB.get([mod.id, opt.key], opt.value),
|
const value = await profileDB.get([mod.id, opt.key], opt.value),
|
||||||
$tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = web.render(
|
$label = web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
|
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
|
||||||
),
|
),
|
||||||
$input = web.html`<input type="text" class="input">`,
|
$input = web.html`<input type="text" class="input">`,
|
||||||
$icon = web.html`${web.icon('droplet', { class: 'input-icon' })}`,
|
$icon = web.html`${await components.feather('droplet', { class: 'input-icon' })}`,
|
||||||
paint = () => {
|
paint = () => {
|
||||||
$input.style.background = $picker.toBackground();
|
$input.style.background = $picker.toBackground();
|
||||||
$input.style.color = $picker.isLight() ? '#000' : '#fff';
|
$input.style.color = $picker.isLight() ? '#000' : '#fff';
|
||||||
@ -163,7 +163,7 @@ export const options = {
|
|||||||
},
|
},
|
||||||
file: async (mod, opt) => {
|
file: async (mod, opt) => {
|
||||||
const { filename } = (await profileDB.get([mod.id, opt.key], {})) || {},
|
const { filename } = (await profileDB.get([mod.id, opt.key], {})) || {},
|
||||||
$tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = web.render(
|
$label = web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
|
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
|
||||||
@ -172,7 +172,7 @@ export const options = {
|
|||||||
$input = web.html`<input type="file" class="hidden" accept=${web.escape(
|
$input = web.html`<input type="file" class="hidden" accept=${web.escape(
|
||||||
opt.extensions.join(',')
|
opt.extensions.join(',')
|
||||||
)}>`,
|
)}>`,
|
||||||
$icon = web.html`${web.icon('file', { class: 'input-icon' })}`,
|
$icon = web.html`${await components.feather('file', { class: 'input-icon' })}`,
|
||||||
$filename = web.html`<span>${web.escape(filename || 'none')}</span>`,
|
$filename = web.html`<span>${web.escape(filename || 'none')}</span>`,
|
||||||
$latest = web.render(web.html`<button class="file-latest">Latest: </button>`, $filename);
|
$latest = web.render(web.html`<button class="file-latest">Latest: </button>`, $filename);
|
||||||
if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
|
if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
|
||||||
@ -201,13 +201,13 @@ export const options = {
|
|||||||
},
|
},
|
||||||
hotkey: async (mod, opt) => {
|
hotkey: async (mod, opt) => {
|
||||||
const value = await profileDB.get([mod.id, opt.key], opt.value),
|
const value = await profileDB.get([mod.id, opt.key], opt.value),
|
||||||
$tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = web.render(
|
$label = web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
|
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
|
||||||
),
|
),
|
||||||
$input = web.html`<input type="text" class="input" value="${web.escape(value)}">`,
|
$input = web.html`<input type="text" class="input" value="${web.escape(value)}">`,
|
||||||
$icon = web.html`${web.icon('command', { class: 'input-icon' })}`;
|
$icon = web.html`${await components.feather('command', { class: 'input-icon' })}`;
|
||||||
if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
|
if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
|
||||||
$input.addEventListener('keydown', async (event) => {
|
$input.addEventListener('keydown', async (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { env, fs, storage, registry, web } from '../../api/_.mjs';
|
import { env, fs, storage, registry, web, components } from '../../api/_.mjs';
|
||||||
import { notifications } from './notifications.mjs';
|
import { notifications } from './notifications.mjs';
|
||||||
import { blocks, options } from './blocks.mjs';
|
import { blocks, options } from './blocks.mjs';
|
||||||
import './styles.mjs';
|
import './styles.mjs';
|
||||||
@ -74,17 +74,17 @@ $profile.addEventListener('click', async (event) => {
|
|||||||
pattern="/^[A-Za-z0-9_-]+$/"
|
pattern="/^[A-Za-z0-9_-]+$/"
|
||||||
>`,
|
>`,
|
||||||
$export = web.html`<button class="profile-export">
|
$export = web.html`<button class="profile-export">
|
||||||
${web.icon('download', { class: 'profile-icon-action' })}
|
${await components.feather('download', { class: 'profile-icon-action' })}
|
||||||
</button>`,
|
</button>`,
|
||||||
$import = web.html`<label class="profile-import">
|
$import = web.html`<label class="profile-import">
|
||||||
<input type="file" class="hidden" accept="application/json">
|
<input type="file" class="hidden" accept="application/json">
|
||||||
${web.icon('upload', { class: 'profile-icon-action' })}
|
${await components.feather('upload', { class: 'profile-icon-action' })}
|
||||||
</label>`,
|
</label>`,
|
||||||
$save = web.html`<button class="profile-save">
|
$save = web.html`<button class="profile-save">
|
||||||
${web.icon('save', { class: 'profile-icon-text' })} Save
|
${await components.feather('save', { class: 'profile-icon-text' })} Save
|
||||||
</button>`,
|
</button>`,
|
||||||
$delete = web.html`<button class="profile-delete">
|
$delete = web.html`<button class="profile-delete">
|
||||||
${web.icon('trash-2', { class: 'profile-icon-text' })} Delete
|
${await components.feather('trash-2', { class: 'profile-icon-text' })} Delete
|
||||||
</button>`,
|
</button>`,
|
||||||
$error = web.html`<p class="profile-error"></p>`;
|
$error = web.html`<p class="profile-error"></p>`;
|
||||||
$export.addEventListener('click', async (event) => {
|
$export.addEventListener('click', async (event) => {
|
||||||
@ -175,12 +175,12 @@ $profile.addEventListener('click', async (event) => {
|
|||||||
web.render(
|
web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
$select,
|
$select,
|
||||||
web.html`${web.icon('chevron-down', { class: 'input-icon' })}`
|
web.html`${await components.feather('chevron-down', { class: 'input-icon' })}`
|
||||||
),
|
),
|
||||||
web.render(
|
web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
$edit,
|
$edit,
|
||||||
web.html`${web.icon('type', { class: 'input-icon' })}`
|
web.html`${await components.feather('type', { class: 'input-icon' })}`
|
||||||
),
|
),
|
||||||
web.render(web.html`<p class="profile-actions"></p>`, $export, $import, $save, $delete),
|
web.render(web.html`<p class="profile-actions"></p>`, $export, $import, $save, $delete),
|
||||||
$error
|
$error
|
||||||
@ -288,7 +288,7 @@ const _$modListCache = {},
|
|||||||
web.render(
|
web.render(
|
||||||
web.html`<label class="search-container"></label>`,
|
web.html`<label class="search-container"></label>`,
|
||||||
$search,
|
$search,
|
||||||
web.html`${web.icon('search', { class: 'input-icon' })}`
|
web.html`${await components.feather('search', { class: 'input-icon' })}`
|
||||||
),
|
),
|
||||||
message ? web.html`<p class="main-message">${web.escape(message)}</p>` : '',
|
message ? web.html`<p class="main-message">${web.escape(message)}</p>` : '',
|
||||||
$list
|
$list
|
||||||
@ -303,14 +303,13 @@ const $notionNavItem = web.html`<h1 class="nav-notion">
|
|||||||
/width="\d+" height="\d+"/,
|
/width="\d+" height="\d+"/,
|
||||||
`class="nav-notion-icon"`
|
`class="nav-notion-icon"`
|
||||||
)}
|
)}
|
||||||
<a href="https://notion-enhancer.github.io/" target="_blank">notion-enhancer</a>
|
<span>notion-enhancer</span>
|
||||||
</h1>`;
|
</h1>`;
|
||||||
$notionNavItem.children[0].addEventListener('click', env.focusNotion);
|
$notionNavItem.addEventListener('click', env.focusNotion);
|
||||||
|
|
||||||
const $coreNavItem = web.html`<a href="?view=core" class="nav-item">core</a>`,
|
const $coreNavItem = web.html`<a href="?view=core" class="nav-item">core</a>`,
|
||||||
$extensionsNavItem = web.html`<a href="?view=extensions" class="nav-item">extensions</a>`,
|
$extensionsNavItem = web.html`<a href="?view=extensions" class="nav-item">extensions</a>`,
|
||||||
$themesNavItem = web.html`<a href="?view=themes" class="nav-item">themes</a>`,
|
$themesNavItem = web.html`<a href="?view=themes" class="nav-item">themes</a>`;
|
||||||
$communityNavItem = web.html`<a href="https://discord.gg/sFWPXtA" class="nav-item">community</a>`;
|
|
||||||
|
|
||||||
web.render(
|
web.render(
|
||||||
document.body,
|
document.body,
|
||||||
@ -324,7 +323,8 @@ web.render(
|
|||||||
$coreNavItem,
|
$coreNavItem,
|
||||||
$extensionsNavItem,
|
$extensionsNavItem,
|
||||||
$themesNavItem,
|
$themesNavItem,
|
||||||
$communityNavItem
|
web.html`<a href="https://notion-enhancer.github.io" class="nav-item">docs</a>`,
|
||||||
|
web.html`<a href="https://discord.gg/sFWPXtA" class="nav-item">community</a>`
|
||||||
),
|
),
|
||||||
$main
|
$main
|
||||||
),
|
),
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { env, fs, storage, fmt, registry, web } from '../../api/_.mjs';
|
import { env, fs, storage, fmt, registry, web, components } from '../../api/_.mjs';
|
||||||
import { tw } from './styles.mjs';
|
import { tw } from './styles.mjs';
|
||||||
|
|
||||||
export const notifications = {
|
export const notifications = {
|
||||||
@ -16,7 +16,7 @@ export const notifications = {
|
|||||||
registry.welcomeNotification,
|
registry.welcomeNotification,
|
||||||
...(await fs.getJSON('https://notion-enhancer.github.io/notifications.json')),
|
...(await fs.getJSON('https://notion-enhancer.github.io/notifications.json')),
|
||||||
],
|
],
|
||||||
add({ icon, message, id = undefined, color = undefined, link = undefined }) {
|
async add({ icon, message, id = undefined, color = undefined, link = undefined }) {
|
||||||
const $notification = link
|
const $notification = link
|
||||||
? web.html`<a
|
? web.html`<a
|
||||||
href="${web.escape(link)}"
|
href="${web.escape(link)}"
|
||||||
@ -47,16 +47,16 @@ export const notifications = {
|
|||||||
web.html`<span class="notification-text markdown-inline">
|
web.html`<span class="notification-text markdown-inline">
|
||||||
${fmt.md.renderInline(message)}
|
${fmt.md.renderInline(message)}
|
||||||
</span>`,
|
</span>`,
|
||||||
web.html`${web.icon(icon, { class: 'notification-icon' })}`
|
web.html`${await components.feather(icon, { class: 'notification-icon' })}`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return $notification;
|
return $notification;
|
||||||
},
|
},
|
||||||
_onChange: false,
|
_onChange: false,
|
||||||
onChange() {
|
async onChange() {
|
||||||
if (this._onChange) return;
|
if (this._onChange) return;
|
||||||
this._onChange = true;
|
this._onChange = true;
|
||||||
const $notification = this.add({
|
const $notification = await this.add({
|
||||||
icon: 'refresh-cw',
|
icon: 'refresh-cw',
|
||||||
message: 'Reload to apply changes.',
|
message: 'Reload to apply changes.',
|
||||||
});
|
});
|
||||||
|
@ -36,13 +36,13 @@ const customClasses = {
|
|||||||
'notification-icon': apply`fill-current opacity-75 h-4 w-4 mx-2`,
|
'notification-icon': apply`fill-current opacity-75 h-4 w-4 mx-2`,
|
||||||
'body-container': apply`flex w-full h-full overflow-hidden`,
|
'body-container': apply`flex w-full h-full overflow-hidden`,
|
||||||
'content-container': apply`h-full w-full-96`,
|
'content-container': apply`h-full w-full-96`,
|
||||||
'nav': apply`px-4 py-3 flex flex-wrap items-center border-b border-divider h-48 sm:h-32 lg:h-16`,
|
'nav': apply`px-4 py-3 flex flex-wrap items-center border-b border-divider h-64 sm:h-48 md:h-32 lg:h-16`,
|
||||||
'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-focus`,
|
||||||
'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-48 sm: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`,
|
||||||
'mods-list': apply`flex flex-wrap`,
|
'mods-list': apply`flex flex-wrap`,
|
||||||
'mod-container': apply`w-full md:w-1/2 lg:w-1/3 xl:w-1/4 2xl:w-1/5 px-2.5 py-2.5 box-border`,
|
'mod-container': apply`w-full md:w-1/2 lg:w-1/3 xl:w-1/4 2xl:w-1/5 px-2.5 py-2.5 box-border`,
|
||||||
@ -145,6 +145,7 @@ setup({
|
|||||||
'full-16': 'calc(100% - 4rem)',
|
'full-16': 'calc(100% - 4rem)',
|
||||||
'full-32': 'calc(100% - 8rem)',
|
'full-32': 'calc(100% - 8rem)',
|
||||||
'full-48': 'calc(100% - 12rem)',
|
'full-48': 'calc(100% - 12rem)',
|
||||||
|
'full-64': 'calc(100% - 16rem)',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user