mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-08 06:29:03 +00:00
feat(panel): render icons in switcher
This commit is contained in:
parent
681d5c13f6
commit
8745dc9313
@ -12,7 +12,7 @@ import { fileURLToPath } from "node:url";
|
|||||||
const dependencies = {
|
const dependencies = {
|
||||||
"htm.min.js": "https://unpkg.com/htm@3.1.1/mini/index.js",
|
"htm.min.js": "https://unpkg.com/htm@3.1.1/mini/index.js",
|
||||||
"twind.min.js": "https://unpkg.com/@twind/cdn@1.0.8/cdn.global.js",
|
"twind.min.js": "https://unpkg.com/@twind/cdn@1.0.8/cdn.global.js",
|
||||||
"lucide.min.js": "https://unpkg.com/lucide@0.263.0/dist/umd/lucide.min.js",
|
"lucide.min.js": "https://unpkg.com/lucide@0.264.0/dist/umd/lucide.min.js",
|
||||||
"coloris.min.js":
|
"coloris.min.js":
|
||||||
"https://cdn.jsdelivr.net/gh/mdbassit/Coloris@v0.21.0/dist/coloris.min.js",
|
"https://cdn.jsdelivr.net/gh/mdbassit/Coloris@v0.21.0/dist/coloris.min.js",
|
||||||
"coloris.min.css":
|
"coloris.min.css":
|
||||||
|
@ -7,12 +7,7 @@
|
|||||||
import { Tooltip } from "./Tooltip.mjs";
|
import { Tooltip } from "./Tooltip.mjs";
|
||||||
import { Select } from "../menu/islands/Select.mjs";
|
import { Select } from "../menu/islands/Select.mjs";
|
||||||
|
|
||||||
function PanelView(props) {
|
function View(props) {
|
||||||
const { html } = globalThis.__enhancerApi;
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
|
|
||||||
function PanelSwitcher(props) {
|
|
||||||
const { html } = globalThis.__enhancerApi;
|
const { html } = globalThis.__enhancerApi;
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
@ -37,13 +32,36 @@ function Panel({
|
|||||||
duration-[${transitionDuration}ms] group/panel`,
|
duration-[${transitionDuration}ms] group/panel`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const $resizeHandle = html`<div
|
const values = [
|
||||||
|
{
|
||||||
|
icon: html`<i class="i-type h-[16px] w-[16px]" />`,
|
||||||
|
value: "word counter",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// prettier-ignore
|
||||||
|
icon: html`<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24">
|
||||||
|
<circle cx="5" cy="7" r="2.8"/>
|
||||||
|
<circle cx="5" cy="17" r="2.79"/>
|
||||||
|
<path d="M21,5.95H11c-0.55,0-1-0.45-1-1v0c0-0.55,0.45-1,1-1h10c0.55,0,1,0.45,1,1v0C22,5.5,21.55,5.95,21,5.95z"/>
|
||||||
|
<path d="M17,10.05h-6c-0.55,0-1-0.45-1-1v0c0-0.55,0.45-1,1-1h6c0.55,0,1,0.45,1,1v0C18,9.6,17.55,10.05,17,10.05z"/>
|
||||||
|
<path d="M21,15.95H11c-0.55,0-1-0.45-1-1v0c0-0.55,0.45-1,1-1h10c0.55,0,1,0.45,1,1v0C22,15.5,21.55,15.95,21,15.95z" />
|
||||||
|
<path d="M17,20.05h-6c-0.55,0-1-0.45-1-1v0c0-0.55,0.45-1,1-1h6c0.55,0,1,0.45,1,1v0C18,19.6,17.55,20.05,17,20.05z"/>
|
||||||
|
</svg>`,
|
||||||
|
value: "outliner",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
_get = () => useState(["panelView"])[0],
|
||||||
|
_set = (value) => {
|
||||||
|
setState({ panelView: value, rerender: true });
|
||||||
|
};
|
||||||
|
|
||||||
|
const $resize = html`<div
|
||||||
class="absolute h-full w-[3px] left-[-3px]
|
class="absolute h-full w-[3px] left-[-3px]
|
||||||
z-10 transition duration-300 hover:(cursor-col-resize
|
z-10 transition duration-300 hover:(cursor-col-resize
|
||||||
shadow-[var(--theme--fg-border)_-2px_0px_0px_0px_inset])
|
shadow-[var(--theme--fg-border)_-2px_0px_0px_0px_inset])
|
||||||
active:cursor-text group-not-[open]/panel:hidden"
|
active:cursor-text group-not-[open]/panel:hidden"
|
||||||
></div>`,
|
></div>`,
|
||||||
$chevronClose = html`<button
|
$close = html`<button
|
||||||
aria-label="Close side panel"
|
aria-label="Close side panel"
|
||||||
class="user-select-none h-[24px] w-[24px] duration-[20ms]
|
class="user-select-none h-[24px] w-[24px] duration-[20ms]
|
||||||
transition inline-flex items-center justify-center mr-[10px]
|
transition inline-flex items-center justify-center mr-[10px]
|
||||||
@ -53,33 +71,29 @@ function Panel({
|
|||||||
class="i-chevrons-right w-[20px] h-[20px]
|
class="i-chevrons-right w-[20px] h-[20px]
|
||||||
text-[color:var(--theme--fg-secondary)]"
|
text-[color:var(--theme--fg-secondary)]"
|
||||||
/>
|
/>
|
||||||
</div>`;
|
</div>`,
|
||||||
|
$switcher = html`<div
|
||||||
const values = ["default", "outliner", "word counter"],
|
class="relative flex items-center
|
||||||
_get = () => useState(["panelView"])[0],
|
font-medium p-[8.5px] ml-[4px] grow"
|
||||||
_set = (value) => {
|
|
||||||
setState({ panelView: value, rerender: true });
|
|
||||||
};
|
|
||||||
|
|
||||||
const $panel = html`<aside ...${props}>
|
|
||||||
${$resizeHandle}
|
|
||||||
<div
|
|
||||||
class="flex justify-between items-center
|
|
||||||
border-(b [color:var(--theme--fg-border)])"
|
|
||||||
>
|
>
|
||||||
|
<${Select}
|
||||||
|
popupMode="dropdown"
|
||||||
|
maxWidth="${maxWidth}"
|
||||||
|
class="w-full text-left"
|
||||||
|
...${{ _get, _set, values, maxWidth: maxWidth - 56 }}
|
||||||
|
/>
|
||||||
|
</div>`,
|
||||||
|
$view = html`<div class="h-full overflow-y-auto"></div>`,
|
||||||
|
$panel = html`<aside ...${props}>
|
||||||
|
${$resize}
|
||||||
<div
|
<div
|
||||||
class="relative flex grow font-medium items-center p-[8.5px] ml-[4px]"
|
class="flex justify-between items-center
|
||||||
|
border-(b [color:var(--theme--fg-border)])"
|
||||||
>
|
>
|
||||||
<${Select}
|
${$switcher}${$close}
|
||||||
popupMode="dropdown"
|
|
||||||
maxWidth="${maxWidth}"
|
|
||||||
class="w-full text-left"
|
|
||||||
...${{ _get, _set, values, maxWidth: maxWidth - 56 }}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
${$chevronClose}
|
${$view}
|
||||||
</div>
|
</aside>`;
|
||||||
</aside>`;
|
|
||||||
|
|
||||||
let preDragWidth,
|
let preDragWidth,
|
||||||
dragStartX = 0;
|
dragStartX = 0;
|
||||||
@ -103,7 +117,7 @@ function Panel({
|
|||||||
// trigger panel close if not resized
|
// trigger panel close if not resized
|
||||||
if (dragStartX - event.clientX === 0) $panel.close();
|
if (dragStartX - event.clientX === 0) $panel.close();
|
||||||
};
|
};
|
||||||
$resizeHandle.addEventListener("mousedown", startDrag);
|
$resize.addEventListener("mousedown", startDrag);
|
||||||
|
|
||||||
const $tooltip = html`<${Tooltip}>
|
const $tooltip = html`<${Tooltip}>
|
||||||
<span>Drag</span> to resize<br />
|
<span>Drag</span> to resize<br />
|
||||||
@ -112,16 +126,18 @@ function Panel({
|
|||||||
showTooltip = (event) => {
|
showTooltip = (event) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const panelOpen = $panel.hasAttribute("open"),
|
const panelOpen = $panel.hasAttribute("open"),
|
||||||
handleHovered = $resizeHandle.matches(":hover");
|
handleHovered = $resize.matches(":hover");
|
||||||
if (!panelOpen || !handleHovered) return;
|
if (!panelOpen || !handleHovered) return;
|
||||||
const { x } = $resizeHandle.getBoundingClientRect();
|
const { x } = $resize.getBoundingClientRect();
|
||||||
$tooltip.show(x, event.clientY);
|
$tooltip.show(x, event.clientY);
|
||||||
}, 200);
|
}, 200);
|
||||||
};
|
};
|
||||||
$resizeHandle.addEventListener("mouseover", showTooltip);
|
$resize.addEventListener("mouseover", showTooltip);
|
||||||
$resizeHandle.addEventListener("mouseout", () => $tooltip.hide());
|
$resize.addEventListener("mouseout", () => $tooltip.hide());
|
||||||
$chevronClose.addEventListener("click", () => $panel.close());
|
$close.addEventListener("click", () => $panel.close());
|
||||||
|
|
||||||
|
// normally would place outside of an island, but in
|
||||||
|
// this case is necessary for syncing up animations
|
||||||
const notionHelp = ".notion-help-button",
|
const notionHelp = ".notion-help-button",
|
||||||
repositionHelp = async () => {
|
repositionHelp = async () => {
|
||||||
const $notionHelp = document.querySelector(notionHelp);
|
const $notionHelp = document.querySelector(notionHelp);
|
||||||
|
@ -6,12 +6,12 @@
|
|||||||
|
|
||||||
import { Popup } from "./Popup.mjs";
|
import { Popup } from "./Popup.mjs";
|
||||||
|
|
||||||
function Option({ value, _get, _set }) {
|
function Option({ icon = "", value = "", _get, _set }) {
|
||||||
const { html, useState } = globalThis.__enhancerApi,
|
const { html, useState } = globalThis.__enhancerApi,
|
||||||
$selected = html`<i class="ml-auto i-check w-[16px] h-[16px]"></i>`,
|
$selected = html`<i class="ml-auto i-check w-[16px] h-[16px]"></i>`,
|
||||||
$option = html`<div
|
$option = html`<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
role="button"
|
role="option"
|
||||||
class="select-none cursor-pointer rounded-[3px]
|
class="select-none cursor-pointer rounded-[3px]
|
||||||
flex items-center w-full h-[28px] px-[12px] leading-[1.2]
|
flex items-center w-full h-[28px] px-[12px] leading-[1.2]
|
||||||
transition duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
|
transition duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
|
||||||
@ -20,8 +20,11 @@ function Option({ value, _get, _set }) {
|
|||||||
if (event.key === "Enter") _set?.(value);
|
if (event.key === "Enter") _set?.(value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="mr-[6px] text-[14px] text-ellipsis overflow-hidden">
|
<div
|
||||||
${value}
|
class="mr-[6px] inline-flex items-center gap-[6px]
|
||||||
|
text-[14px] text-ellipsis overflow-hidden"
|
||||||
|
>
|
||||||
|
${icon}<span>${value}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
useState(["rerender"], async () => {
|
useState(["rerender"], async () => {
|
||||||
@ -41,7 +44,6 @@ function Select({
|
|||||||
maxWidth = 256,
|
maxWidth = 256,
|
||||||
...props
|
...props
|
||||||
}) {
|
}) {
|
||||||
let _initialValue;
|
|
||||||
const { html, extendProps, setState, useState } = globalThis.__enhancerApi,
|
const { html, extendProps, setState, useState } = globalThis.__enhancerApi,
|
||||||
// dir="rtl" overflows to the left during transition
|
// dir="rtl" overflows to the left during transition
|
||||||
$select = html`<div
|
$select = html`<div
|
||||||
@ -53,9 +55,24 @@ function Select({
|
|||||||
max-w-[${maxWidth}px] pl-[8px] pr-[28px] transition
|
max-w-[${maxWidth}px] pl-[8px] pr-[28px] transition
|
||||||
duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
|
duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
|
||||||
></div>`;
|
></div>`;
|
||||||
|
|
||||||
|
let _initialValue;
|
||||||
|
values = values.map((value) => {
|
||||||
|
value = typeof value === "string" ? { value } : value;
|
||||||
|
if (typeof value.icon === "string" && value.icon) {
|
||||||
|
value.icon = html`<i class="i-${value.icon} h-[16px] w-[16px]" />`;
|
||||||
|
} else value.icon ??= "";
|
||||||
|
value.value ??= "";
|
||||||
|
return value;
|
||||||
|
});
|
||||||
useState(["rerender"], async () => {
|
useState(["rerender"], async () => {
|
||||||
const value = (await _get?.()) ?? ($select.innerText || values[0]);
|
const value = (await _get?.()) ?? ($select.innerText || values[0].value),
|
||||||
$select.innerText = value;
|
icon = values.find((v) => v.value === value)?.icon;
|
||||||
|
$select.innerHTML = "";
|
||||||
|
// swap icon/value order for correct display when dir="rtl"
|
||||||
|
$select.append(html`<div class="inline-flex items-center gap-[6px]">
|
||||||
|
<span>${value}</span>${icon?.cloneNode?.(true) || ""}
|
||||||
|
</div>`);
|
||||||
if (_requireReload) {
|
if (_requireReload) {
|
||||||
_initialValue ??= value;
|
_initialValue ??= value;
|
||||||
if (value !== _initialValue) setState({ databaseUpdated: true });
|
if (value !== _initialValue) setState({ databaseUpdated: true });
|
||||||
@ -76,7 +93,9 @@ function Select({
|
|||||||
$select.style.width = "";
|
$select.style.width = "";
|
||||||
$select.style.background = "";
|
$select.style.background = "";
|
||||||
}}
|
}}
|
||||||
>${values.map((value) => html`<${Option} ...${{ value, _get, _set }} />`)}
|
>${values.map((value) => {
|
||||||
|
return html`<${Option} ...${{ ...value, _get, _set }} />`;
|
||||||
|
})}
|
||||||
<//>
|
<//>
|
||||||
<i
|
<i
|
||||||
class="i-chevron-down pointer-events-none
|
class="i-chevron-down pointer-events-none
|
||||||
|
6
src/vendor/lucide.min.js
vendored
6
src/vendor/lucide.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user