From db48bc05434eea9f6de7628ef2f066a33a524a9d Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Thu, 17 Oct 2024 23:00:27 +0200 Subject: [PATCH 01/19] base context menu working --- .../song/context-menu/SongContextMenu.tsx | 61 +++++++++++++------ .../components/song/song-item/SongItem.tsx | 22 +++++-- .../components/song/song-list/SongList.tsx | 3 +- 3 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx index 5b424801..90b05a71 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx @@ -1,15 +1,26 @@ import "../../../assets/css/song/song-context-menu.css"; -import { Accessor, Component, createEffect, For, onCleanup, onMount, Show, Signal } from "solid-js"; +import { + Accessor, + Component, + createEffect, + createSignal, + For, + onCleanup, + onMount, + Show, + Signal, +} from "solid-js"; type SongContextMenuProps = { show: Signal; coords: Accessor<[number, number]>; - container: any; children: any; + isContextOpen: Signal; }; const SongContextMenu: Component = (props) => { const [show, setShow] = props.show; + const [pos, setPos] = createSignal<[number, number]>(props.coords()); let menu: HTMLDivElement | undefined; const windowContextMenu = (evt: MouseEvent) => { @@ -19,21 +30,19 @@ const SongContextMenu: Component = (props) => { return; } - const targetItem = t.closest(".song-item"); - const menuParent = menu?.closest(".song-item"); + const targetItem = t.closest(".group"); + const menuParent = menu?.closest(".group"); + setPos([evt.layerX, evt.layerY]); + + // console.log(menu, targetItem, menuParent, evt.target); + // console.log(props.children); if (targetItem === menuParent) { evt.stopPropagation(); - return; + } else { + setShow(false); + props.isContextOpen[1](false); } - - setShow(false); - }; - - const calculatePosition = () => { - const c = props.coords(); - menu?.style.setProperty("--x", `${Math.round(c[0])}px`); - menu?.style.setProperty("--y", `${Math.round(c[1])}px`); }; onMount(() => { @@ -45,22 +54,36 @@ const SongContextMenu: Component = (props) => { return; } - calculatePosition(); - window.addEventListener("click", () => setShow(false), { once: true }); + props.isContextOpen[1](true); + + window.addEventListener( + "click", + () => { + setShow(false); + props.isContextOpen[1](false); + }, + { once: true }, + ); window.addEventListener("contextmenu", windowContextMenu); }); }); onCleanup(() => { - window.removeEventListener("click", () => setShow(false)); + window.removeEventListener("click", () => { + setShow(false); + props.isContextOpen[1](false); + }); window.removeEventListener("contextmenu", windowContextMenu); - menu?.removeEventListener("click", (evt) => evt.stopPropagation()); }); return ( -
-
+
+
{(child) => child}
diff --git a/src/renderer/src/components/song/song-item/SongItem.tsx b/src/renderer/src/components/song/song-item/SongItem.tsx index f25ebc94..07e597c3 100644 --- a/src/renderer/src/components/song/song-item/SongItem.tsx +++ b/src/renderer/src/components/song/song-item/SongItem.tsx @@ -2,9 +2,9 @@ import { ResourceID, Song } from "../../../../../@types"; import draggable from "../../../lib/draggable/draggable"; import SongHint from "../SongHint"; import SongImage from "../SongImage"; -import { ignoreClickInContextMenu } from "../context-menu/SongContextMenu"; +import SongContextMenu, { ignoreClickInContextMenu } from "../context-menu/SongContextMenu"; import { song as selectedSong } from "../song.utils"; -import { Component, createSignal, onMount } from "solid-js"; +import { Component, createSignal, onMount, Signal } from "solid-js"; type SongItemProps = { song: Song; @@ -14,6 +14,7 @@ type SongItemProps = { draggable?: true; onDrop?: (before: Element | null) => any; children?: any; + isContextOpen: Signal; }; const SongItem: Component = ({ @@ -24,9 +25,10 @@ const SongItem: Component = ({ draggable: isDraggable, onDrop, selectable, + isContextOpen, }) => { const showSignal = createSignal(false); - const [, setCoords] = createSignal<[number, number]>([0, 0], { equals: false }); + const [coords, setCoords] = createSignal<[number, number]>([0, 0], { equals: false }); let item: HTMLDivElement | undefined; const showMenu = (evt: MouseEvent) => { @@ -35,7 +37,12 @@ const SongItem: Component = ({ return; } - setCoords([evt.clientX, evt.clientY]); + if (isContextOpen[0]() === true) { + return; + } + + setCoords([evt.layerX, evt.layerY]); + console.log(coords()); showSignal[1](true); }; @@ -58,7 +65,7 @@ const SongItem: Component = ({ return (
= ({ group={group} /> -
+

{song.title}

{song.artist}

+ + {...children} +
); }; diff --git a/src/renderer/src/components/song/song-list/SongList.tsx b/src/renderer/src/components/song/song-list/SongList.tsx index 0ebad9e9..4588239c 100644 --- a/src/renderer/src/components/song/song-list/SongList.tsx +++ b/src/renderer/src/components/song/song-list/SongList.tsx @@ -22,6 +22,7 @@ const SongList: Component = (props) => { const [order, setOrder] = createSignal({ option: "title", direction: "asc" }); const [count, setCount] = createSignal(0); + const isContextOpen = createSignal(false); const [payload, setPayload] = createSignal({ view: props, @@ -88,7 +89,7 @@ const SongList: Component = (props) => { reset={resetListing} fallback={
No songs...
} builder={(s) => ( - +
- - {...children} -
); }; diff --git a/src/renderer/src/components/song/song-list/SongList.tsx b/src/renderer/src/components/song/song-list/SongList.tsx index 4588239c..2e93fa29 100644 --- a/src/renderer/src/components/song/song-list/SongList.tsx +++ b/src/renderer/src/components/song/song-list/SongList.tsx @@ -1,14 +1,15 @@ -import { Optional, Order, ResourceID, SongsQueryPayload, Tag } from "../../../../../@types"; +import { Optional, Order, ResourceID, Song, SongsQueryPayload, Tag } from "../../../../../@types"; import { SearchQueryError } from "../../../../../main/lib/search-parser/@search-types"; import { namespace } from "../../../App"; import Impulse from "../../../lib/Impulse"; import { none, some } from "../../../lib/rust-like-utils-client/Optional"; import InfiniteScroller from "../../InfiniteScroller"; +import SongContextMenu from "../context-menu/SongContextMenu"; import PlayNext from "../context-menu/items/PlayNext"; import SongItem from "../song-item/SongItem"; import SongListSearch from "../song-list-search/SongListSearch"; import { songsSearch } from "./song-list.utils"; -import { Component, createEffect, createSignal, onCleanup, onMount } from "solid-js"; +import { Component, createEffect, createSignal, onCleanup, onMount, Show } from "solid-js"; export type SongViewProps = { isAllSongs?: boolean; @@ -22,7 +23,10 @@ const SongList: Component = (props) => { const [order, setOrder] = createSignal({ option: "title", direction: "asc" }); const [count, setCount] = createSignal(0); - const isContextOpen = createSignal(false); + + const showSignal = createSignal(false); + const [song, setSong] = createSignal(); + const [queryCreated, setQueryCreated] = createSignal(false); const [payload, setPayload] = createSignal({ view: props, @@ -69,6 +73,7 @@ const SongList: Component = (props) => { startSong: songResource, ...payload(), }); + setQueryCreated(true); }; const group = namespace.create(true); @@ -89,15 +94,26 @@ const SongList: Component = (props) => { reset={resetListing} fallback={
No songs...
} builder={(s) => ( - - - - +
+ +
)} />
+ + + + + + ); }; From 99f25a4dc703c6857613ba0462cd87252d5c22d4 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Fri, 18 Oct 2024 00:49:11 +0200 Subject: [PATCH 03/19] styling and queue context menu --- .../song/context-menu/SongContextMenu.tsx | 6 ++--- .../song/context-menu/SongContextMenuItem.tsx | 8 +++--- .../song/context-menu/items/PlayNext.tsx | 3 ++- .../components/song/song-list/SongList.tsx | 12 ++++++--- .../components/song/song-queue/SongQueue.tsx | 27 +++++++++++++++++-- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx index e2fe1ec5..224753ef 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx @@ -30,7 +30,7 @@ const SongContextMenu: Component = (props) => { const targetItem = t.closest(".group"); if (targetItem !== null) { - setPos([evt.clientX, evt.clientY - 52]); + setPos([evt.offsetX + 30, evt.clientY - 52]); } }; @@ -64,11 +64,11 @@ const SongContextMenu: Component = (props) => { return (
-
+
{(child) => child}
diff --git a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx index 4c72d171..b6dfe97e 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx @@ -1,3 +1,4 @@ +import Button from "@renderer/components/button/Button"; import { Component, onCleanup } from "solid-js"; type SongContextMenuItemProps = { @@ -18,12 +19,13 @@ const SongContextMenuItem: Component = (props) => { }); return ( - + ); }; diff --git a/src/renderer/src/components/song/context-menu/items/PlayNext.tsx b/src/renderer/src/components/song/context-menu/items/PlayNext.tsx index 7b49c33c..26a6061a 100644 --- a/src/renderer/src/components/song/context-menu/items/PlayNext.tsx +++ b/src/renderer/src/components/song/context-menu/items/PlayNext.tsx @@ -15,7 +15,8 @@ const PlayNext: Component = (props) => { } }} > - Play Next +

Play next

+ ); }; diff --git a/src/renderer/src/components/song/song-list/SongList.tsx b/src/renderer/src/components/song/song-list/SongList.tsx index 2e93fa29..964f1aff 100644 --- a/src/renderer/src/components/song/song-list/SongList.tsx +++ b/src/renderer/src/components/song/song-list/SongList.tsx @@ -5,6 +5,7 @@ import Impulse from "../../../lib/Impulse"; import { none, some } from "../../../lib/rust-like-utils-client/Optional"; import InfiniteScroller from "../../InfiniteScroller"; import SongContextMenu from "../context-menu/SongContextMenu"; +import SongContextMenuItem from "../context-menu/SongContextMenuItem"; import PlayNext from "../context-menu/items/PlayNext"; import SongItem from "../song-item/SongItem"; import SongListSearch from "../song-list-search/SongListSearch"; @@ -110,9 +111,14 @@ const SongList: Component = (props) => { - + { + console.log("yo"); + }} + > +

Add to playlist

+ +
); diff --git a/src/renderer/src/components/song/song-queue/SongQueue.tsx b/src/renderer/src/components/song/song-queue/SongQueue.tsx index 8ba9e344..1de32aa4 100644 --- a/src/renderer/src/components/song/song-queue/SongQueue.tsx +++ b/src/renderer/src/components/song/song-queue/SongQueue.tsx @@ -3,6 +3,7 @@ import { namespace } from "../../../App"; import Impulse from "../../../lib/Impulse"; import scrollIfNeeded from "../../../lib/tungsten/scroll-if-needed"; import InfiniteScroller from "../../InfiniteScroller"; +import SongContextMenu from "../context-menu/SongContextMenu"; import SongContextMenuItem from "../context-menu/SongContextMenuItem"; import SongItem from "../song-item/SongItem"; import { setSongQueueModalOpen } from "./song-queue.utils"; @@ -11,6 +12,8 @@ import { Component, createSignal, onCleanup, onMount } from "solid-js"; const SongQueue: Component = () => { const [count, setCount] = createSignal(0); + const showSignal = createSignal(false); + const [song, setSong] = createSignal(); const resetListing = new Impulse(); const group = namespace.create(true); let view: HTMLDivElement | undefined; @@ -105,14 +108,34 @@ const SongQueue: Component = () => { draggable={true} onSelect={() => window.api.request("queue::play", s.path)} onDrop={onDrop(s)} + showSignal={showSignal} + setSong={setSong} > - window.api.request("queue::removeSong", s.path)}> + {/* window.api.request("queue::removeSong", s.path)}> Remove from queue - + */} )} /> + + { + console.log("yo"); + }} + > +

Add to playlist

+ +
+ { + console.log("remove " + song()?.title); + }} + > +

Remove from queue

+ +
+
); }; From 288e60d85e2ec5e07a0fa441953ae145c551c85d Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Fri, 18 Oct 2024 00:57:38 +0200 Subject: [PATCH 04/19] add remove from queue functionality --- .../src/components/song/song-list/SongList.tsx | 3 ++- .../src/components/song/song-queue/SongQueue.tsx | 11 ++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/renderer/src/components/song/song-list/SongList.tsx b/src/renderer/src/components/song/song-list/SongList.tsx index 964f1aff..4fb352bf 100644 --- a/src/renderer/src/components/song/song-list/SongList.tsx +++ b/src/renderer/src/components/song/song-list/SongList.tsx @@ -111,9 +111,10 @@ const SongList: Component = (props) => { + { - console.log("yo"); + console.log("todo"); }} >

Add to playlist

diff --git a/src/renderer/src/components/song/song-queue/SongQueue.tsx b/src/renderer/src/components/song/song-queue/SongQueue.tsx index 1de32aa4..655134d3 100644 --- a/src/renderer/src/components/song/song-queue/SongQueue.tsx +++ b/src/renderer/src/components/song/song-queue/SongQueue.tsx @@ -110,26 +110,23 @@ const SongQueue: Component = () => { onDrop={onDrop(s)} showSignal={showSignal} setSong={setSong} - > - {/* window.api.request("queue::removeSong", s.path)}> - Remove from queue - */} - + > )} /> { - console.log("yo"); + console.log("todo"); }} >

Add to playlist

+ { - console.log("remove " + song()?.title); + window.api.request("queue::removeSong", song()?.path); }} >

Remove from queue

From 105c74b8f03d20b3b67fd85077c4f5b607284277 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Fri, 18 Oct 2024 01:05:51 +0200 Subject: [PATCH 05/19] remove unused function --- .../song/context-menu/SongContextMenu.tsx | 19 ------------------- .../components/song/song-item/SongItem.tsx | 3 +-- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx index 224753ef..5168fb9a 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx @@ -77,22 +77,3 @@ const SongContextMenu: Component = (props) => { }; export default SongContextMenu; - -export function ignoreClickInContextMenu(fn: (evt: MouseEvent) => any): (evt: MouseEvent) => void { - return (evt: MouseEvent) => { - const t = evt.target; - - if (!(t instanceof HTMLElement)) { - fn(evt); - return; - } - - const menu = t.closest(".song-menu"); - - if (menu !== null) { - return; - } - - fn(evt); - }; -} diff --git a/src/renderer/src/components/song/song-item/SongItem.tsx b/src/renderer/src/components/song/song-item/SongItem.tsx index d25e5b33..f9086bad 100644 --- a/src/renderer/src/components/song/song-item/SongItem.tsx +++ b/src/renderer/src/components/song/song-item/SongItem.tsx @@ -2,7 +2,6 @@ import { ResourceID, Song } from "../../../../../@types"; import draggable from "../../../lib/draggable/draggable"; import SongHint from "../SongHint"; import SongImage from "../SongImage"; -import { ignoreClickInContextMenu } from "../context-menu/SongContextMenu"; import { song as selectedSong } from "../song.utils"; import { Component, onMount, Setter, Signal } from "solid-js"; @@ -41,7 +40,7 @@ const SongItem: Component = ({ } draggable(item, { - onClick: ignoreClickInContextMenu(() => onSelect(song.path)), + onClick: () => onSelect(song.path), onDrop: onDrop ?? (() => {}), createHint: SongHint, useOnlyAsOnClickBinder: !isDraggable || selectedSong().path === song.path, From 2d615ece8feb736b3a187d9e7654e034723dafb0 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:18:07 +0200 Subject: [PATCH 06/19] use Lucide icons --- .../src/components/song/context-menu/SongContextMenuItem.tsx | 2 +- .../src/components/song/context-menu/items/PlayNext.tsx | 3 ++- src/renderer/src/components/song/song-list/SongList.tsx | 3 ++- src/renderer/src/components/song/song-queue/SongQueue.tsx | 5 +++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx index b6dfe97e..95789713 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx @@ -22,7 +22,7 @@ const SongContextMenuItem: Component = (props) => { diff --git a/src/renderer/src/components/song/context-menu/items/PlayNext.tsx b/src/renderer/src/components/song/context-menu/items/PlayNext.tsx index 26a6061a..aa7e93f2 100644 --- a/src/renderer/src/components/song/context-menu/items/PlayNext.tsx +++ b/src/renderer/src/components/song/context-menu/items/PlayNext.tsx @@ -1,5 +1,6 @@ import { Song } from "../../../../../../@types"; import SongContextMenuItem from "../SongContextMenuItem"; +import { ListStartIcon } from "lucide-solid"; import { Component } from "solid-js"; type SongPlayNextProps = { @@ -16,7 +17,7 @@ const PlayNext: Component = (props) => { }} >

Play next

- +
); }; diff --git a/src/renderer/src/components/song/song-list/SongList.tsx b/src/renderer/src/components/song/song-list/SongList.tsx index 4fb352bf..4d716b91 100644 --- a/src/renderer/src/components/song/song-list/SongList.tsx +++ b/src/renderer/src/components/song/song-list/SongList.tsx @@ -10,6 +10,7 @@ import PlayNext from "../context-menu/items/PlayNext"; import SongItem from "../song-item/SongItem"; import SongListSearch from "../song-list-search/SongListSearch"; import { songsSearch } from "./song-list.utils"; +import { PlusIcon } from "lucide-solid"; import { Component, createEffect, createSignal, onCleanup, onMount, Show } from "solid-js"; export type SongViewProps = { @@ -118,7 +119,7 @@ const SongList: Component = (props) => { }} >

Add to playlist

- +
diff --git a/src/renderer/src/components/song/song-queue/SongQueue.tsx b/src/renderer/src/components/song/song-queue/SongQueue.tsx index 655134d3..5008a8e3 100644 --- a/src/renderer/src/components/song/song-queue/SongQueue.tsx +++ b/src/renderer/src/components/song/song-queue/SongQueue.tsx @@ -8,6 +8,7 @@ import SongContextMenuItem from "../context-menu/SongContextMenuItem"; import SongItem from "../song-item/SongItem"; import { setSongQueueModalOpen } from "./song-queue.utils"; import Button from "@renderer/components/button/Button"; +import { DeleteIcon, PlusIcon } from "lucide-solid"; import { Component, createSignal, onCleanup, onMount } from "solid-js"; const SongQueue: Component = () => { @@ -121,7 +122,7 @@ const SongQueue: Component = () => { }} >

Add to playlist

- + { }} >

Remove from queue

- +
From 69edfaa69a54f701918015c64716720cbf4f63b0 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Fri, 18 Oct 2024 18:13:39 +0200 Subject: [PATCH 07/19] clamp menu to avoid clipping --- .../song/context-menu/SongContextMenu.tsx | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx index 5168fb9a..09b87e34 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx @@ -1,8 +1,8 @@ import "../../../assets/css/song/song-context-menu.css"; +import { computePosition, inline, shift } from "@floating-ui/dom"; import { Component, - createEffect, - createSignal, + createEffect, // createSignal, For, onCleanup, onMount, @@ -17,7 +17,6 @@ type SongContextMenuProps = { const SongContextMenu: Component = (props) => { const [show, setShow] = props.show; - const [pos, setPos] = createSignal<[number, number]>([0, 0]); let menu: HTMLDivElement | undefined; const windowContextMenu = (evt: MouseEvent) => { @@ -29,8 +28,22 @@ const SongContextMenu: Component = (props) => { const targetItem = t.closest(".group"); - if (targetItem !== null) { - setPos([evt.offsetX + 30, evt.clientY - 52]); + if (targetItem !== null && menu !== undefined) { + const useCustomCoords = { + name: "useCustomCoords", + fn() { + return { x: evt.offsetX + 30, y: evt.clientY - 52 }; + }, + }; + + computePosition(targetItem, menu, { + middleware: [useCustomCoords, inline(), shift({ crossAxis: true })], + }).then(({ x, y }) => { + Object.assign(menu.style, { + left: `${x}px`, + top: `${y}px`, + }); + }); } }; @@ -63,11 +76,7 @@ const SongContextMenu: Component = (props) => { return ( -
+
{(child) => child}
From b996e272ae92654629143cfd8d87357fdb214c26 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 19 Oct 2024 17:26:56 +0200 Subject: [PATCH 08/19] user popover component properly --- .../src/components/popover/Popover.tsx | 6 +- .../song/context-menu/SongContextMenu.tsx | 78 ++--------------- .../song/context-menu/items/AddToPlaylist.tsx | 25 ++++++ .../context-menu/items/RemoveFromQueue.tsx | 25 ++++++ .../components/song/song-item/SongItem.tsx | 86 ++++++++++++------- .../components/song/song-list/SongList.tsx | 41 +++------ .../components/song/song-queue/SongQueue.tsx | 34 ++------ 7 files changed, 135 insertions(+), 160 deletions(-) create mode 100644 src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx create mode 100644 src/renderer/src/components/song/context-menu/items/RemoveFromQueue.tsx diff --git a/src/renderer/src/components/popover/Popover.tsx b/src/renderer/src/components/popover/Popover.tsx index 3151bfe3..2ea356ba 100644 --- a/src/renderer/src/components/popover/Popover.tsx +++ b/src/renderer/src/components/popover/Popover.tsx @@ -5,6 +5,7 @@ import "./styles.css"; import { computePosition, ComputePositionReturn, + Middleware, offset, OffsetOptions, Placement, @@ -20,6 +21,7 @@ export type Props = { defaultProp?: boolean; isOpen?: Accessor; onValueChange?: (newOpen: boolean) => void; + middlewares?: Middleware[]; }; export type Context = ReturnType; @@ -53,10 +55,12 @@ function useProviderValue(props: Props) { return; } + const localMiddlewares: Middleware[] = props.middlewares === undefined ? [] : props.middlewares; + computePosition(trigger, content, { placement: props.placement, strategy: "fixed", - middleware: [offset(props.offset)], + middleware: [offset(props.offset), ...localMiddlewares], }).then(setPosition); }; diff --git a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx index 09b87e34..75d05858 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx @@ -1,87 +1,19 @@ import "../../../assets/css/song/song-context-menu.css"; -import { computePosition, inline, shift } from "@floating-ui/dom"; -import { - Component, - createEffect, // createSignal, - For, - onCleanup, - onMount, - Show, - Signal, -} from "solid-js"; +import { Component, For } from "solid-js"; type SongContextMenuProps = { - show: Signal; children: any; }; const SongContextMenu: Component = (props) => { - const [show, setShow] = props.show; let menu: HTMLDivElement | undefined; - const windowContextMenu = (evt: MouseEvent) => { - const t = evt.target; - - if (!(t instanceof HTMLElement)) { - return; - } - - const targetItem = t.closest(".group"); - - if (targetItem !== null && menu !== undefined) { - const useCustomCoords = { - name: "useCustomCoords", - fn() { - return { x: evt.offsetX + 30, y: evt.clientY - 52 }; - }, - }; - - computePosition(targetItem, menu, { - middleware: [useCustomCoords, inline(), shift({ crossAxis: true })], - }).then(({ x, y }) => { - Object.assign(menu.style, { - left: `${x}px`, - top: `${y}px`, - }); - }); - } - }; - - onMount(() => { - createEffect(() => { - const s = show(); - - if (s === false) { - window.removeEventListener("contextmenu", windowContextMenu); - return; - } - - window.addEventListener( - "click", - () => { - setShow(false); - }, - { once: true }, - ); - window.addEventListener("contextmenu", windowContextMenu); - }); - }); - - onCleanup(() => { - window.removeEventListener("click", () => { - setShow(false); - }); - window.removeEventListener("contextmenu", windowContextMenu); - }); - return ( - -
-
- {(child) => child} -
+
+
+ {(child) => child}
- +
); }; diff --git a/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx new file mode 100644 index 00000000..ac69f14a --- /dev/null +++ b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx @@ -0,0 +1,25 @@ +import { Song } from "../../../../../../@types"; +import SongContextMenuItem from "../SongContextMenuItem"; +import { PlusIcon } from "lucide-solid"; +import { Component } from "solid-js"; + +type AddToPlaylistProps = { + path: Song["path"] | undefined; +}; + +const AddToPlaylist: Component = (props) => { + return ( + { + if (props.path !== undefined && props.path !== "") { + console.log("TODO: add " + props.path + " to playlist"); + } + }} + > +

Add to Playlist

+ +
+ ); +}; + +export default AddToPlaylist; diff --git a/src/renderer/src/components/song/context-menu/items/RemoveFromQueue.tsx b/src/renderer/src/components/song/context-menu/items/RemoveFromQueue.tsx new file mode 100644 index 00000000..d176b9c8 --- /dev/null +++ b/src/renderer/src/components/song/context-menu/items/RemoveFromQueue.tsx @@ -0,0 +1,25 @@ +import SongContextMenuItem from "../SongContextMenuItem"; +import { DeleteIcon } from "lucide-solid"; +import { Component } from "solid-js"; +import { Song } from "src/@types"; + +type RemoveFromQueueProps = { + path: Song["path"] | undefined; +}; + +const RemoveFromQueue: Component = (props) => { + return ( + { + if (props.path !== undefined && props.path !== "") { + window.api.request("queue::removeSong", props.path); + } + }} + > +

Remove from queue

+ +
+ ); +}; + +export default RemoveFromQueue; diff --git a/src/renderer/src/components/song/song-item/SongItem.tsx b/src/renderer/src/components/song/song-item/SongItem.tsx index f9086bad..ac8acc5f 100644 --- a/src/renderer/src/components/song/song-item/SongItem.tsx +++ b/src/renderer/src/components/song/song-item/SongItem.tsx @@ -3,7 +3,12 @@ import draggable from "../../../lib/draggable/draggable"; import SongHint from "../SongHint"; import SongImage from "../SongImage"; import { song as selectedSong } from "../song.utils"; -import { Component, onMount, Setter, Signal } from "solid-js"; +import { flip, offset } from "@floating-ui/dom"; +import Button from "@renderer/components/button/Button"; +import Popover from "@renderer/components/popover/Popover"; +import { EllipsisVerticalIcon } from "lucide-solid"; +import { Component, createSignal, onMount } from "solid-js"; +import { Portal } from "solid-js/web"; type SongItemProps = { song: Song; @@ -13,8 +18,6 @@ type SongItemProps = { draggable?: true; onDrop?: (before: Element | null) => any; children?: any; - showSignal: Signal; - setSong: Setter; }; const SongItem: Component = ({ @@ -24,15 +27,10 @@ const SongItem: Component = ({ draggable: isDraggable, onDrop, selectable, - showSignal, - setSong, + children, }) => { let item: HTMLDivElement | undefined; - - const showMenu = () => { - setSong(song); - showSignal[1](true); - }; + const [localShow, setLocalShow] = createSignal(false); onMount(() => { if (!item) { @@ -52,32 +50,58 @@ const SongItem: Component = ({ }); return ( -
- + + { + setLocalShow(false); + }} + > + {...children} + + +
+ data-active={selectedSong().path === song.path} + ref={item} + data-url={song.bg} + onContextMenu={() => setLocalShow(true)} + > + + +
+
+

+ {song.title} +

+

{song.artist}

+
-
-

- {song.title} -

-

{song.artist}

+ + + +
-
+ ); }; diff --git a/src/renderer/src/components/song/song-list/SongList.tsx b/src/renderer/src/components/song/song-list/SongList.tsx index 4d716b91..49d0e794 100644 --- a/src/renderer/src/components/song/song-list/SongList.tsx +++ b/src/renderer/src/components/song/song-list/SongList.tsx @@ -1,16 +1,15 @@ -import { Optional, Order, ResourceID, Song, SongsQueryPayload, Tag } from "../../../../../@types"; +import { Optional, Order, ResourceID, SongsQueryPayload, Tag } from "../../../../../@types"; import { SearchQueryError } from "../../../../../main/lib/search-parser/@search-types"; import { namespace } from "../../../App"; import Impulse from "../../../lib/Impulse"; import { none, some } from "../../../lib/rust-like-utils-client/Optional"; import InfiniteScroller from "../../InfiniteScroller"; import SongContextMenu from "../context-menu/SongContextMenu"; -import SongContextMenuItem from "../context-menu/SongContextMenuItem"; +import AddToPlaylist from "../context-menu/items/AddToPlaylist"; import PlayNext from "../context-menu/items/PlayNext"; import SongItem from "../song-item/SongItem"; import SongListSearch from "../song-list-search/SongListSearch"; import { songsSearch } from "./song-list.utils"; -import { PlusIcon } from "lucide-solid"; import { Component, createEffect, createSignal, onCleanup, onMount, Show } from "solid-js"; export type SongViewProps = { @@ -25,10 +24,7 @@ const SongList: Component = (props) => { const [order, setOrder] = createSignal({ option: "title", direction: "asc" }); const [count, setCount] = createSignal(0); - - const showSignal = createSignal(false); - const [song, setSong] = createSignal(); - const [queryCreated, setQueryCreated] = createSignal(false); + const [isQueueExist, setIsQueueExist] = createSignal(false); const [payload, setPayload] = createSignal({ view: props, @@ -75,7 +71,7 @@ const SongList: Component = (props) => { startSong: songResource, ...payload(), }); - setQueryCreated(true); + setIsQueueExist(true); }; const group = namespace.create(true); @@ -97,31 +93,18 @@ const SongList: Component = (props) => { fallback={
No songs...
} builder={(s) => (
- + + + + + + + +
)} />
- - - - - - { - console.log("todo"); - }} - > -

Add to playlist

- -
-
); }; diff --git a/src/renderer/src/components/song/song-queue/SongQueue.tsx b/src/renderer/src/components/song/song-queue/SongQueue.tsx index 5008a8e3..779a2def 100644 --- a/src/renderer/src/components/song/song-queue/SongQueue.tsx +++ b/src/renderer/src/components/song/song-queue/SongQueue.tsx @@ -4,17 +4,15 @@ import Impulse from "../../../lib/Impulse"; import scrollIfNeeded from "../../../lib/tungsten/scroll-if-needed"; import InfiniteScroller from "../../InfiniteScroller"; import SongContextMenu from "../context-menu/SongContextMenu"; -import SongContextMenuItem from "../context-menu/SongContextMenuItem"; +import AddToPlaylist from "../context-menu/items/AddToPlaylist"; +import RemoveFromQueue from "../context-menu/items/RemoveFromQueue"; import SongItem from "../song-item/SongItem"; import { setSongQueueModalOpen } from "./song-queue.utils"; import Button from "@renderer/components/button/Button"; -import { DeleteIcon, PlusIcon } from "lucide-solid"; import { Component, createSignal, onCleanup, onMount } from "solid-js"; const SongQueue: Component = () => { const [count, setCount] = createSignal(0); - const showSignal = createSignal(false); - const [song, setSong] = createSignal(); const resetListing = new Impulse(); const group = namespace.create(true); let view: HTMLDivElement | undefined; @@ -109,31 +107,15 @@ const SongQueue: Component = () => { draggable={true} onSelect={() => window.api.request("queue::play", s.path)} onDrop={onDrop(s)} - showSignal={showSignal} - setSong={setSong} - > + > + + + + + )} />
- - { - console.log("todo"); - }} - > -

Add to playlist

- -
- - { - window.api.request("queue::removeSong", song()?.path); - }} - > -

Remove from queue

- -
-
); }; From efa735e62ef38bd2cfb0880d63a0424757f59176 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 19 Oct 2024 17:56:14 +0200 Subject: [PATCH 09/19] fix button click playing song --- .../components/song/context-menu/SongContextMenu.tsx | 12 ++++++++++++ .../src/components/song/song-item/SongItem.tsx | 5 +++-- src/renderer/src/scenes/main-scene/MainScene.tsx | 6 +++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx index 75d05858..c450b121 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx @@ -18,3 +18,15 @@ const SongContextMenu: Component = (props) => { }; export default SongContextMenu; + +export function ignoreClickInContextMenu(fn: (evt: MouseEvent) => any): (evt: MouseEvent) => void { + return (evt: MouseEvent) => { + const t = evt.target; + + if (!(t instanceof HTMLElement)) { + return; + } + + fn(evt); + }; +} diff --git a/src/renderer/src/components/song/song-item/SongItem.tsx b/src/renderer/src/components/song/song-item/SongItem.tsx index ac8acc5f..4cca0443 100644 --- a/src/renderer/src/components/song/song-item/SongItem.tsx +++ b/src/renderer/src/components/song/song-item/SongItem.tsx @@ -2,6 +2,7 @@ import { ResourceID, Song } from "../../../../../@types"; import draggable from "../../../lib/draggable/draggable"; import SongHint from "../SongHint"; import SongImage from "../SongImage"; +import { ignoreClickInContextMenu } from "../context-menu/SongContextMenu"; import { song as selectedSong } from "../song.utils"; import { flip, offset } from "@floating-ui/dom"; import Button from "@renderer/components/button/Button"; @@ -38,7 +39,7 @@ const SongItem: Component = ({ } draggable(item, { - onClick: () => onSelect(song.path), + onClick: ignoreClickInContextMenu(() => onSelect(song.path)), onDrop: onDrop ?? (() => {}), createHint: SongHint, useOnlyAsOnClickBinder: !isDraggable || selectedSong().path === song.path, @@ -86,7 +87,7 @@ const SongItem: Component = ({ group={group} /> -
+

{song.title} diff --git a/src/renderer/src/scenes/main-scene/MainScene.tsx b/src/renderer/src/scenes/main-scene/MainScene.tsx index b2821748..2e6bf079 100644 --- a/src/renderer/src/scenes/main-scene/MainScene.tsx +++ b/src/renderer/src/scenes/main-scene/MainScene.tsx @@ -171,13 +171,13 @@ const QueueModal: Component = () => { createEffect(() => { if (songQueueModalOpen()) { - document.addEventListener("mousedown", handleOutsideClick); + document.addEventListener("click", handleOutsideClick); } else { - document.removeEventListener("mousedown", handleOutsideClick); + document.removeEventListener("click", handleOutsideClick); } onCleanup(() => { - document.removeEventListener("mousedown", handleOutsideClick); + document.removeEventListener("click", handleOutsideClick); }); }); From c8d638eaa089b21b6239b70dd59afcfe362028b6 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 19 Oct 2024 18:06:04 +0200 Subject: [PATCH 10/19] fix queue closing on context click --- .../src/components/song/song-item/SongItem.tsx | 3 ++- src/renderer/src/scenes/main-scene/MainScene.tsx | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/components/song/song-item/SongItem.tsx b/src/renderer/src/components/song/song-item/SongItem.tsx index 4cca0443..08a8afe1 100644 --- a/src/renderer/src/components/song/song-item/SongItem.tsx +++ b/src/renderer/src/components/song/song-item/SongItem.tsx @@ -61,7 +61,8 @@ const SongItem: Component = ({ { + onClick={(e) => { + e.stopImmediatePropagation(); setLocalShow(false); }} > diff --git a/src/renderer/src/scenes/main-scene/MainScene.tsx b/src/renderer/src/scenes/main-scene/MainScene.tsx index 2e6bf079..a95af5a4 100644 --- a/src/renderer/src/scenes/main-scene/MainScene.tsx +++ b/src/renderer/src/scenes/main-scene/MainScene.tsx @@ -164,8 +164,14 @@ const QueueModal: Component = () => { let queueModal: HTMLDivElement | undefined; const handleOutsideClick = (event: MouseEvent) => { - if (queueModal && !queueModal.contains(event.target as Node)) { - toggleSongQueueModalOpen(); + if (event.target instanceof HTMLElement) { + if ( + queueModal && + !queueModal.contains(event.target as Node) && + event.target.closest(".popover-overlay") === null + ) { + toggleSongQueueModalOpen(); + } } }; From 816aeca5bea6ff069f37dc8af2e0e28b65b4af6f Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 19 Oct 2024 21:17:15 +0200 Subject: [PATCH 11/19] context menu styling, fix vertical clipping --- .../src/components/song/context-menu/SongContextMenu.tsx | 4 ++-- .../components/song/context-menu/SongContextMenuItem.tsx | 8 +++----- .../song/context-menu/items/RemoveFromQueue.tsx | 4 ++-- src/renderer/src/components/song/song-item/SongItem.tsx | 4 ++-- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx index c450b121..755b3ac4 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenu.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenu.tsx @@ -9,8 +9,8 @@ const SongContextMenu: Component = (props) => { let menu: HTMLDivElement | undefined; return ( -
-
+
+
{(child) => child}
diff --git a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx index 95789713..a75b5777 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx @@ -1,4 +1,3 @@ -import Button from "@renderer/components/button/Button"; import { Component, onCleanup } from "solid-js"; type SongContextMenuItemProps = { @@ -19,13 +18,12 @@ const SongContextMenuItem: Component = (props) => { }); return ( - + ); }; diff --git a/src/renderer/src/components/song/context-menu/items/RemoveFromQueue.tsx b/src/renderer/src/components/song/context-menu/items/RemoveFromQueue.tsx index d176b9c8..ab6e38a7 100644 --- a/src/renderer/src/components/song/context-menu/items/RemoveFromQueue.tsx +++ b/src/renderer/src/components/song/context-menu/items/RemoveFromQueue.tsx @@ -16,8 +16,8 @@ const RemoveFromQueue: Component = (props) => { } }} > -

Remove from queue

- +

Remove from queue

+ ); }; diff --git a/src/renderer/src/components/song/song-item/SongItem.tsx b/src/renderer/src/components/song/song-item/SongItem.tsx index 08a8afe1..75e3008d 100644 --- a/src/renderer/src/components/song/song-item/SongItem.tsx +++ b/src/renderer/src/components/song/song-item/SongItem.tsx @@ -4,7 +4,7 @@ import SongHint from "../SongHint"; import SongImage from "../SongImage"; import { ignoreClickInContextMenu } from "../context-menu/SongContextMenu"; import { song as selectedSong } from "../song.utils"; -import { flip, offset } from "@floating-ui/dom"; +import { flip, offset, shift } from "@floating-ui/dom"; import Button from "@renderer/components/button/Button"; import Popover from "@renderer/components/popover/Popover"; import { EllipsisVerticalIcon } from "lucide-solid"; @@ -54,7 +54,7 @@ const SongItem: Component = ({ From 289143a9319960fdd772db4e77e743684dc30df7 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 19 Oct 2024 21:45:17 +0200 Subject: [PATCH 12/19] pass context menu as prop, fix trigger button --- .../components/song/song-item/SongItem.tsx | 21 +++++++++---------- .../components/song/song-list/SongList.tsx | 21 ++++++++++++------- .../components/song/song-queue/SongQueue.tsx | 13 ++++++------ 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/renderer/src/components/song/song-item/SongItem.tsx b/src/renderer/src/components/song/song-item/SongItem.tsx index 75e3008d..4a4ff18b 100644 --- a/src/renderer/src/components/song/song-item/SongItem.tsx +++ b/src/renderer/src/components/song/song-item/SongItem.tsx @@ -5,10 +5,9 @@ import SongImage from "../SongImage"; import { ignoreClickInContextMenu } from "../context-menu/SongContextMenu"; import { song as selectedSong } from "../song.utils"; import { flip, offset, shift } from "@floating-ui/dom"; -import Button from "@renderer/components/button/Button"; import Popover from "@renderer/components/popover/Popover"; import { EllipsisVerticalIcon } from "lucide-solid"; -import { Component, createSignal, onMount } from "solid-js"; +import { Component, createSignal, JSXElement, onMount } from "solid-js"; import { Portal } from "solid-js/web"; type SongItemProps = { @@ -18,7 +17,7 @@ type SongItemProps = { onSelect: (songResource: ResourceID) => any; draggable?: true; onDrop?: (before: Element | null) => any; - children?: any; + contextMenu: JSXElement; }; const SongItem: Component = ({ @@ -28,7 +27,7 @@ const SongItem: Component = ({ draggable: isDraggable, onDrop, selectable, - children, + contextMenu, }) => { let item: HTMLDivElement | undefined; const [localShow, setLocalShow] = createSignal(false); @@ -54,7 +53,7 @@ const SongItem: Component = ({ @@ -66,7 +65,7 @@ const SongItem: Component = ({ setLocalShow(false); }} > - {...children} + {contextMenu}
= ({ group={group} /> -
+

{song.title} @@ -96,11 +95,11 @@ const SongItem: Component = ({

{song.artist}

- - - + +
diff --git a/src/renderer/src/components/song/song-list/SongList.tsx b/src/renderer/src/components/song/song-list/SongList.tsx index 49d0e794..62df4c5b 100644 --- a/src/renderer/src/components/song/song-list/SongList.tsx +++ b/src/renderer/src/components/song/song-list/SongList.tsx @@ -93,14 +93,19 @@ const SongList: Component = (props) => { fallback={
No songs...
} builder={(s) => (
- - - - - - - - + + + + + + + } + >
)} /> diff --git a/src/renderer/src/components/song/song-queue/SongQueue.tsx b/src/renderer/src/components/song/song-queue/SongQueue.tsx index 779a2def..7aa87ec3 100644 --- a/src/renderer/src/components/song/song-queue/SongQueue.tsx +++ b/src/renderer/src/components/song/song-queue/SongQueue.tsx @@ -107,12 +107,13 @@ const SongQueue: Component = () => { draggable={true} onSelect={() => window.api.request("queue::play", s.path)} onDrop={onDrop(s)} - > - - - - - + contextMenu={ + + + + + } + > )} />
From c64683ef424cf8e31c2787db35ffb08351d9c626 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 19 Oct 2024 21:57:36 +0200 Subject: [PATCH 13/19] allow ContextMenuItem styling --- .../components/song/context-menu/SongContextMenuItem.tsx | 8 ++++++-- .../song/context-menu/items/RemoveFromQueue.tsx | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx index a75b5777..9eb182bd 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx @@ -1,8 +1,9 @@ -import { Component, onCleanup } from "solid-js"; +import { Component, JSX, onCleanup } from "solid-js"; type SongContextMenuItemProps = { onClick: (event: MouseEvent) => any; children: any; + class?: JSX.HTMLAttributes["class"]; }; const SongContextMenuItem: Component = (props) => { @@ -20,7 +21,10 @@ const SongContextMenuItem: Component = (props) => { return ( diff --git a/src/renderer/src/components/song/context-menu/items/RemoveFromQueue.tsx b/src/renderer/src/components/song/context-menu/items/RemoveFromQueue.tsx index ab6e38a7..532ff1c8 100644 --- a/src/renderer/src/components/song/context-menu/items/RemoveFromQueue.tsx +++ b/src/renderer/src/components/song/context-menu/items/RemoveFromQueue.tsx @@ -15,6 +15,7 @@ const RemoveFromQueue: Component = (props) => { window.api.request("queue::removeSong", props.path); } }} + class="hover:bg-red/20" >

Remove from queue

From a356a23a7a57b862a8f16e91ea82f4c3a8f4cd23 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sun, 20 Oct 2024 22:38:42 +0200 Subject: [PATCH 14/19] remove passing middlewares as a prop --- src/renderer/src/components/popover/Popover.tsx | 12 +++++++----- .../src/components/song/song-item/SongItem.tsx | 6 +++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/renderer/src/components/popover/Popover.tsx b/src/renderer/src/components/popover/Popover.tsx index 2ea356ba..63589e23 100644 --- a/src/renderer/src/components/popover/Popover.tsx +++ b/src/renderer/src/components/popover/Popover.tsx @@ -5,10 +5,13 @@ import "./styles.css"; import { computePosition, ComputePositionReturn, - Middleware, + flip, + FlipOptions, offset, OffsetOptions, Placement, + shift, + ShiftOptions, } from "@floating-ui/dom"; import useControllableState from "@renderer/lib/controllable-state"; import { createSignal, createContext, useContext, ParentComponent, Accessor } from "solid-js"; @@ -17,11 +20,12 @@ export const DEFAULT_POPOVER_OPEN = false; export type Props = { offset?: OffsetOptions; + flip?: FlipOptions; + shift?: ShiftOptions; placement?: Placement; defaultProp?: boolean; isOpen?: Accessor; onValueChange?: (newOpen: boolean) => void; - middlewares?: Middleware[]; }; export type Context = ReturnType; @@ -55,12 +59,10 @@ function useProviderValue(props: Props) { return; } - const localMiddlewares: Middleware[] = props.middlewares === undefined ? [] : props.middlewares; - computePosition(trigger, content, { placement: props.placement, strategy: "fixed", - middleware: [offset(props.offset), ...localMiddlewares], + middleware: [offset(props.offset), shift(props.shift), flip(props.flip)], }).then(setPosition); }; diff --git a/src/renderer/src/components/song/song-item/SongItem.tsx b/src/renderer/src/components/song/song-item/SongItem.tsx index 4a4ff18b..1b1ba32b 100644 --- a/src/renderer/src/components/song/song-item/SongItem.tsx +++ b/src/renderer/src/components/song/song-item/SongItem.tsx @@ -4,7 +4,6 @@ import SongHint from "../SongHint"; import SongImage from "../SongImage"; import { ignoreClickInContextMenu } from "../context-menu/SongContextMenu"; import { song as selectedSong } from "../song.utils"; -import { flip, offset, shift } from "@floating-ui/dom"; import Popover from "@renderer/components/popover/Popover"; import { EllipsisVerticalIcon } from "lucide-solid"; import { Component, createSignal, JSXElement, onMount } from "solid-js"; @@ -53,9 +52,10 @@ const SongItem: Component = ({ From 76868158a5735aa4ab95601e59a45cac25ca1e15 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sun, 20 Oct 2024 23:42:08 +0200 Subject: [PATCH 15/19] disable button instead of hiding it --- .../components/song/context-menu/SongContextMenuItem.tsx | 9 +++++++-- .../src/components/song/context-menu/items/PlayNext.tsx | 2 ++ src/renderer/src/components/song/song-item/SongItem.tsx | 2 +- src/renderer/src/components/song/song-list/SongList.tsx | 6 ++---- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx index 9eb182bd..31f25a58 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx @@ -3,11 +3,13 @@ import { Component, JSX, onCleanup } from "solid-js"; type SongContextMenuItemProps = { onClick: (event: MouseEvent) => any; children: any; - class?: JSX.HTMLAttributes["class"]; + class?: JSX.ButtonHTMLAttributes["class"]; + disabled?: JSX.ButtonHTMLAttributes["disabled"]; }; const SongContextMenuItem: Component = (props) => { let item: HTMLElement | undefined; + const buttonDisabled = props.disabled !== undefined ? props.disabled : false; const divAccessor = (div: HTMLElement) => { div.addEventListener("click", props.onClick); @@ -22,9 +24,12 @@ const SongContextMenuItem: Component = (props) => { diff --git a/src/renderer/src/components/song/context-menu/items/PlayNext.tsx b/src/renderer/src/components/song/context-menu/items/PlayNext.tsx index aa7e93f2..d94d1cd3 100644 --- a/src/renderer/src/components/song/context-menu/items/PlayNext.tsx +++ b/src/renderer/src/components/song/context-menu/items/PlayNext.tsx @@ -5,6 +5,7 @@ import { Component } from "solid-js"; type SongPlayNextProps = { path: Song["path"] | undefined; + disabled: boolean; }; const PlayNext: Component = (props) => { @@ -15,6 +16,7 @@ const PlayNext: Component = (props) => { window.api.request("queue::playNext", props.path); } }} + disabled={props.disabled} >

Play next

diff --git a/src/renderer/src/components/song/song-item/SongItem.tsx b/src/renderer/src/components/song/song-item/SongItem.tsx index 1b1ba32b..a5f36c66 100644 --- a/src/renderer/src/components/song/song-item/SongItem.tsx +++ b/src/renderer/src/components/song/song-item/SongItem.tsx @@ -53,7 +53,7 @@ const SongItem: Component = ({ isOpen={localShow} onValueChange={setLocalShow} placement="right" - offset={{ crossAxis: 30, mainAxis: 10 }} + offset={{ crossAxis: 20 }} shift={{ crossAxis: false }} flip={{}} > diff --git a/src/renderer/src/components/song/song-list/SongList.tsx b/src/renderer/src/components/song/song-list/SongList.tsx index 62df4c5b..dc4f6d9c 100644 --- a/src/renderer/src/components/song/song-list/SongList.tsx +++ b/src/renderer/src/components/song/song-list/SongList.tsx @@ -10,7 +10,7 @@ import PlayNext from "../context-menu/items/PlayNext"; import SongItem from "../song-item/SongItem"; import SongListSearch from "../song-list-search/SongListSearch"; import { songsSearch } from "./song-list.utils"; -import { Component, createEffect, createSignal, onCleanup, onMount, Show } from "solid-js"; +import { Component, createEffect, createSignal, onCleanup, onMount } from "solid-js"; export type SongViewProps = { isAllSongs?: boolean; @@ -99,9 +99,7 @@ const SongList: Component = (props) => { onSelect={createQueue} contextMenu={ - - - + } From b7e6978a99522b788dfb60f1fa0dba23e1fbf880 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Mon, 21 Oct 2024 00:04:38 +0200 Subject: [PATCH 16/19] open context menu on mouse position --- .../src/components/popover/Popover.tsx | 25 ++++++++++++++++++- .../song/context-menu/SongContextMenuItem.tsx | 2 +- .../components/song/song-item/SongItem.tsx | 16 +++++++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/components/popover/Popover.tsx b/src/renderer/src/components/popover/Popover.tsx index 63589e23..2076b61e 100644 --- a/src/renderer/src/components/popover/Popover.tsx +++ b/src/renderer/src/components/popover/Popover.tsx @@ -23,6 +23,7 @@ export type Props = { flip?: FlipOptions; shift?: ShiftOptions; placement?: Placement; + mousePos?: Accessor<[number, number]>; defaultProp?: boolean; isOpen?: Accessor; onValueChange?: (newOpen: boolean) => void; @@ -51,6 +52,23 @@ function useProviderValue(props: Props) { listenResize(); }; + let lastMousePos: [number, number]; + const useCustomCoords = { + name: "useCustomCoords", + fn() { + if ( + props.mousePos !== undefined && + props.mousePos() !== lastMousePos && + props.mousePos()[0] !== 0 && + props.mousePos()[1] !== 0 + ) { + lastMousePos = props.mousePos(); + return { x: props.mousePos()[0], y: props.mousePos()[1] }; + } + return {}; + }, + }; + const listenResize = () => { const trigger = triggerRef(); const content = contentRef(); @@ -62,7 +80,12 @@ function useProviderValue(props: Props) { computePosition(trigger, content, { placement: props.placement, strategy: "fixed", - middleware: [offset(props.offset), shift(props.shift), flip(props.flip)], + middleware: [ + props.mousePos !== undefined && useCustomCoords, + offset(props.offset), + props.shift && shift(props.shift), + props.flip && flip(props.flip), + ], }).then(setPosition); }; diff --git a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx index 31f25a58..63b6ebb2 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx @@ -27,7 +27,7 @@ const SongContextMenuItem: Component = (props) => { "flex flex-row items-center justify-between gap-3 rounded-md bg-thick-material p-2 text-left transition-colors duration-200 hover:cursor-pointer hover:bg-accent/20 " + props.class } - // classList sometimes work sometimes it doesn't, should i use a Switch-Match + // classList sometimes work sometimes it doesn't, should i use a Switch-Match ? classList={{ "text-subtext/20 hover:bg-inherit hover:cursor-auto": buttonDisabled }} disabled={buttonDisabled} > diff --git a/src/renderer/src/components/song/song-item/SongItem.tsx b/src/renderer/src/components/song/song-item/SongItem.tsx index a5f36c66..e8430a69 100644 --- a/src/renderer/src/components/song/song-item/SongItem.tsx +++ b/src/renderer/src/components/song/song-item/SongItem.tsx @@ -30,6 +30,7 @@ const SongItem: Component = ({ }) => { let item: HTMLDivElement | undefined; const [localShow, setLocalShow] = createSignal(false); + const [mousePos, setMousePos] = createSignal<[number, number]>([0, 0]); onMount(() => { if (!item) { @@ -53,9 +54,10 @@ const SongItem: Component = ({ isOpen={localShow} onValueChange={setLocalShow} placement="right" - offset={{ crossAxis: 20 }} - shift={{ crossAxis: false }} + offset={{ crossAxis: 5, mainAxis: 5 }} + shift={{}} flip={{}} + mousePos={mousePos} > @@ -76,7 +78,10 @@ const SongItem: Component = ({ data-active={selectedSong().path === song.path} ref={item} data-url={song.bg} - onContextMenu={() => setLocalShow(true)} + onContextMenu={(e) => { + setMousePos([e.clientX, e.clientY]); + setLocalShow(true); + }} > = ({
- +
From 5224b50050513773c1a5a68f3394e090e1ac80ef Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:28:05 +0200 Subject: [PATCH 17/19] fix button styling --- .../song/context-menu/SongContextMenuItem.tsx | 12 ++++++------ .../src/components/song/song-item/SongItem.tsx | 15 +++++++++------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx index 63b6ebb2..6fb56ac6 100644 --- a/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx +++ b/src/renderer/src/components/song/context-menu/SongContextMenuItem.tsx @@ -1,4 +1,5 @@ import { Component, JSX, onCleanup } from "solid-js"; +import { twMerge } from "tailwind-merge"; type SongContextMenuItemProps = { onClick: (event: MouseEvent) => any; @@ -23,12 +24,11 @@ const SongContextMenuItem: Component = (props) => { return (