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 = {
|
||||
"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",
|
||||
"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":
|
||||
"https://cdn.jsdelivr.net/gh/mdbassit/Coloris@v0.21.0/dist/coloris.min.js",
|
||||
"coloris.min.css":
|
||||
|
@ -7,12 +7,7 @@
|
||||
import { Tooltip } from "./Tooltip.mjs";
|
||||
import { Select } from "../menu/islands/Select.mjs";
|
||||
|
||||
function PanelView(props) {
|
||||
const { html } = globalThis.__enhancerApi;
|
||||
return html``;
|
||||
}
|
||||
|
||||
function PanelSwitcher(props) {
|
||||
function View(props) {
|
||||
const { html } = globalThis.__enhancerApi;
|
||||
return html``;
|
||||
}
|
||||
@ -37,13 +32,36 @@ function 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]
|
||||
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]/panel:hidden"
|
||||
></div>`,
|
||||
$chevronClose = html`<button
|
||||
$close = html`<button
|
||||
aria-label="Close side panel"
|
||||
class="user-select-none h-[24px] w-[24px] duration-[20ms]
|
||||
transition inline-flex items-center justify-center mr-[10px]
|
||||
@ -53,33 +71,29 @@ function Panel({
|
||||
class="i-chevrons-right w-[20px] h-[20px]
|
||||
text-[color:var(--theme--fg-secondary)]"
|
||||
/>
|
||||
</div>`;
|
||||
|
||||
const values = ["default", "outliner", "word counter"],
|
||||
_get = () => useState(["panelView"])[0],
|
||||
_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)])"
|
||||
</div>`,
|
||||
$switcher = html`<div
|
||||
class="relative flex items-center
|
||||
font-medium p-[8.5px] ml-[4px] grow"
|
||||
>
|
||||
<${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
|
||||
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}
|
||||
popupMode="dropdown"
|
||||
maxWidth="${maxWidth}"
|
||||
class="w-full text-left"
|
||||
...${{ _get, _set, values, maxWidth: maxWidth - 56 }}
|
||||
/>
|
||||
${$switcher}${$close}
|
||||
</div>
|
||||
${$chevronClose}
|
||||
</div>
|
||||
</aside>`;
|
||||
${$view}
|
||||
</aside>`;
|
||||
|
||||
let preDragWidth,
|
||||
dragStartX = 0;
|
||||
@ -103,7 +117,7 @@ function Panel({
|
||||
// trigger panel close if not resized
|
||||
if (dragStartX - event.clientX === 0) $panel.close();
|
||||
};
|
||||
$resizeHandle.addEventListener("mousedown", startDrag);
|
||||
$resize.addEventListener("mousedown", startDrag);
|
||||
|
||||
const $tooltip = html`<${Tooltip}>
|
||||
<span>Drag</span> to resize<br />
|
||||
@ -112,16 +126,18 @@ function Panel({
|
||||
showTooltip = (event) => {
|
||||
setTimeout(() => {
|
||||
const panelOpen = $panel.hasAttribute("open"),
|
||||
handleHovered = $resizeHandle.matches(":hover");
|
||||
handleHovered = $resize.matches(":hover");
|
||||
if (!panelOpen || !handleHovered) return;
|
||||
const { x } = $resizeHandle.getBoundingClientRect();
|
||||
const { x } = $resize.getBoundingClientRect();
|
||||
$tooltip.show(x, event.clientY);
|
||||
}, 200);
|
||||
};
|
||||
$resizeHandle.addEventListener("mouseover", showTooltip);
|
||||
$resizeHandle.addEventListener("mouseout", () => $tooltip.hide());
|
||||
$chevronClose.addEventListener("click", () => $panel.close());
|
||||
$resize.addEventListener("mouseover", showTooltip);
|
||||
$resize.addEventListener("mouseout", () => $tooltip.hide());
|
||||
$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",
|
||||
repositionHelp = async () => {
|
||||
const $notionHelp = document.querySelector(notionHelp);
|
||||
|
@ -6,12 +6,12 @@
|
||||
|
||||
import { Popup } from "./Popup.mjs";
|
||||
|
||||
function Option({ value, _get, _set }) {
|
||||
function Option({ icon = "", value = "", _get, _set }) {
|
||||
const { html, useState } = globalThis.__enhancerApi,
|
||||
$selected = html`<i class="ml-auto i-check w-[16px] h-[16px]"></i>`,
|
||||
$option = html`<div
|
||||
tabindex="0"
|
||||
role="button"
|
||||
role="option"
|
||||
class="select-none cursor-pointer rounded-[3px]
|
||||
flex items-center w-full h-[28px] px-[12px] leading-[1.2]
|
||||
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);
|
||||
}}
|
||||
>
|
||||
<div class="mr-[6px] text-[14px] text-ellipsis overflow-hidden">
|
||||
${value}
|
||||
<div
|
||||
class="mr-[6px] inline-flex items-center gap-[6px]
|
||||
text-[14px] text-ellipsis overflow-hidden"
|
||||
>
|
||||
${icon}<span>${value}</span>
|
||||
</div>
|
||||
</div>`;
|
||||
useState(["rerender"], async () => {
|
||||
@ -41,7 +44,6 @@ function Select({
|
||||
maxWidth = 256,
|
||||
...props
|
||||
}) {
|
||||
let _initialValue;
|
||||
const { html, extendProps, setState, useState } = globalThis.__enhancerApi,
|
||||
// dir="rtl" overflows to the left during transition
|
||||
$select = html`<div
|
||||
@ -53,9 +55,24 @@ function Select({
|
||||
max-w-[${maxWidth}px] pl-[8px] pr-[28px] transition
|
||||
duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
|
||||
></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 () => {
|
||||
const value = (await _get?.()) ?? ($select.innerText || values[0]);
|
||||
$select.innerText = value;
|
||||
const value = (await _get?.()) ?? ($select.innerText || values[0].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) {
|
||||
_initialValue ??= value;
|
||||
if (value !== _initialValue) setState({ databaseUpdated: true });
|
||||
@ -76,7 +93,9 @@ function Select({
|
||||
$select.style.width = "";
|
||||
$select.style.background = "";
|
||||
}}
|
||||
>${values.map((value) => html`<${Option} ...${{ value, _get, _set }} />`)}
|
||||
>${values.map((value) => {
|
||||
return html`<${Option} ...${{ ...value, _get, _set }} />`;
|
||||
})}
|
||||
<//>
|
||||
<i
|
||||
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