Skip to content

Commit

Permalink
create playlist context menu item
Browse files Browse the repository at this point in the history
  • Loading branch information
D0m1nos committed Nov 26, 2024
1 parent 7f894df commit 5d2aa27
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { noticeError } from "../playlist.utils";
import { noticeError, setShowPlaylistCreateBox } from "../playlist.utils";
import Button from "@renderer/components/button/Button";
import { Input } from "@renderer/components/input/Input";
import { addNotice } from "@renderer/components/notice/NoticeContainer";
import SongImage from "@renderer/components/song/SongImage";
import Impulse from "@renderer/lib/Impulse";
import { CircleCheckIcon, XIcon } from "lucide-solid";
import { Component, createSignal, Setter } from "solid-js";
import { Component, createSignal, Signal } from "solid-js";
import { Song } from "src/@types";

export type PlaylistCreateBoxProps = {
group: string;
isOpen: Setter<boolean>;
reset: Impulse;
songSignal: Signal<Song | undefined>;
};
const PlaylistCreateBox: Component<PlaylistCreateBoxProps> = (props) => {
const [playlistName, setPlaylistName] = createSignal("");
const [createPlaylistBoxSong, setCreatePlaylistBoxSong] = props.songSignal;

const createPlaylist = async () => {
// last check is probably unnecessary
Expand All @@ -29,28 +31,50 @@ const PlaylistCreateBox: Component<PlaylistCreateBoxProps> = (props) => {

setPlaylistName("");
props.reset.pulse();
props.isOpen(false);
setShowPlaylistCreateBox(false);

addNotice({
title: "Playlist created",
description: "The playlist " + name + " has been successfully created!",
variant: "success",
icon: <CircleCheckIcon size={20} />,
});

const song = createPlaylistBoxSong();
if (song !== undefined) {
const songResult = await window.api.request("playlist::add", name, song);
setCreatePlaylistBoxSong(undefined);

if (songResult.isError) {
noticeError(songResult.error);
return;
}

addNotice({
title: "Song added",
description: "Successfully added song to playlist " + name + "!",
variant: "success",
icon: <CircleCheckIcon size={20} />,
});
}
};

return (
<div class="my-2 rounded-xl">
<div class="flex flex-row items-center justify-between px-4 pb-2 pt-3">
<h3 class="text-xl text-text">Create a new playlist</h3>
<Button variant={"outlined"} size={"square"} onClick={() => props.isOpen(false)}>
<Button
variant={"outlined"}
size={"square"}
onClick={() => setShowPlaylistCreateBox(false)}
>
<XIcon size={20} />
</Button>
</div>
<div class="m-4 mt-0 flex flex-row">
<div class="mr-4 flex items-center rounded-lg">
<SongImage
src={""}
src={createPlaylistBoxSong()?.bg}
group={props.group}
instantLoad={true}
class="h-[92px] w-[92px] rounded-lg bg-cover bg-center"
Expand Down
34 changes: 23 additions & 11 deletions src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
import InfiniteScroller from "../../InfiniteScroller";
import PlaylistCreateBox from "../playlist-create/PlaylistCreateBox";
import PlaylistItem from "../playlist-item/PlaylistItem";
import {
createPlaylistBoxSong,
setCreatePlaylistBoxSong,
setShowPlaylistCreateBox,
showPlaylistCreateBox,
} from "../playlist.utils";
import { namespace } from "@renderer/App";
import Button from "@renderer/components/button/Button";
import { Input } from "@renderer/components/input/Input";
import Impulse from "@renderer/lib/Impulse";
import { PlusIcon, SearchIcon } from "lucide-solid";
import { Component, createSignal, onCleanup, onMount, Show } from "solid-js";
import { Component, onCleanup, onMount, Show } from "solid-js";

const PlaylistList: Component = () => {
const resetListing = new Impulse();
const [showCreateBox, setShowCreateBox] = createSignal(false);

const group = namespace.create(true);

onMount(() => window.api.listen("playlist::resetList", resetListing.pulse.bind(resetListing)));
onCleanup(() =>
window.api.removeListener("playlist::resetList", resetListing.pulse.bind(resetListing)),
);
onMount(() => {
window.api.listen("playlist::resetList", resetListing.pulse.bind(resetListing));
});

onCleanup(() => {
window.api.removeListener("playlist::resetList", resetListing.pulse.bind(resetListing));
});

return (
<div class="flex h-full flex-col">
Expand All @@ -39,17 +46,22 @@ const PlaylistList: Component = () => {
</div>
<Button
onClick={() => {
setShowCreateBox(!showCreateBox());
setCreatePlaylistBoxSong(undefined);
setShowPlaylistCreateBox(!showPlaylistCreateBox());
}}
class="rounded-lg text-xl"
variant={showCreateBox() ? "secondary" : "outlined"}
variant={showPlaylistCreateBox() ? "secondary" : "outlined"}
size="square"
>
<PlusIcon size={20} />
</Button>
</div>
<Show when={showCreateBox() === true}>
<PlaylistCreateBox group={group} isOpen={setShowCreateBox} reset={resetListing} />
<Show when={showPlaylistCreateBox() === true}>
<PlaylistCreateBox
songSignal={[createPlaylistBoxSong, setCreatePlaylistBoxSong]}
group={group}
reset={resetListing}
/>
</Show>
</div>

Expand Down
11 changes: 8 additions & 3 deletions src/renderer/src/components/playlist/playlist.utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { addNotice } from "../notice/NoticeContainer";
import Impulse from "@renderer/lib/Impulse";
import { BadgeCheckIcon, CircleXIcon } from "lucide-solid";
import { CircleCheckIcon, CircleXIcon } from "lucide-solid";
import { createSignal } from "solid-js";
import { Song } from "src/@types";

Expand All @@ -9,8 +9,13 @@ const PLAYLIST_SCENE_SONGS = 1;

const [playlistActiveScene, setPlaylistActiveScene] = createSignal(PLAYLIST_SCENE_LIST);
const [activePlaylistName, setActivePlaylistName] = createSignal("");
const [createPlaylistBoxSong, setCreatePlaylistBoxSong] = createSignal<Song | undefined>(undefined);
const [showPlaylistCreateBox, setShowPlaylistCreateBox] = createSignal(false);

export { playlistActiveScene, setPlaylistActiveScene };
export { activePlaylistName, setActivePlaylistName };
export { createPlaylistBoxSong, setCreatePlaylistBoxSong };
export { showPlaylistCreateBox, setShowPlaylistCreateBox };
export { PLAYLIST_SCENE_SONGS, PLAYLIST_SCENE_LIST };

export function noticeError(error: string) {
Expand All @@ -32,7 +37,7 @@ export async function deletePlaylist(name: string, reset: Impulse) {
variant: "success",
title: "Playlist deleted",
description: "Playlist " + name + " successfully deleted!",
icon: BadgeCheckIcon({ size: 20 }),
icon: CircleCheckIcon({ size: 20 }),
});
}
}
Expand All @@ -53,7 +58,7 @@ export async function renamePlaylist(oldName: string, newName: string) {
title: "Renamed playlist",
description: "Playlist renamed successfully!",
variant: "success",
icon: BadgeCheckIcon({ size: 20 }),
icon: CircleCheckIcon({ size: 20 }),
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import DropdownList from "@renderer/components/dropdown-list/DropdownList";
import { addNotice } from "@renderer/components/notice/NoticeContainer";
import { noticeError } from "@renderer/components/playlist/playlist.utils";
import { BadgeCheckIcon, CheckIcon } from "lucide-solid";
import {
noticeError,
PLAYLIST_SCENE_LIST,
setCreatePlaylistBoxSong,
setPlaylistActiveScene,
setShowPlaylistCreateBox,
} from "@renderer/components/playlist/playlist.utils";
import { setSidebarActiveTab, SIDEBAR_PAGES } from "@renderer/scenes/main-scene/main.utils";
import { CheckIcon, CircleCheckIcon, PlusIcon } from "lucide-solid";
import { Accessor, Component, For, Setter, Show } from "solid-js";
import { Song } from "src/@types";

Expand All @@ -24,7 +31,7 @@ const PlaylistChooser: Component<PlaylistChooserProps> = (props) => {
title: "Song added",
description: "Successfully added song to playlist " + name + "!",
variant: "success",
icon: <BadgeCheckIcon size={20} />,
icon: <CircleCheckIcon size={20} />,
});
};

Expand All @@ -37,7 +44,30 @@ const PlaylistChooser: Component<PlaylistChooserProps> = (props) => {
};

return (
<DropdownList class="max-h-[95vh] w-40 overflow-auto [scrollbar-width:none]">
<DropdownList
onMouseOver={() => {
clearTimeout(props.timeoutId());
}}
onMouseLeave={() => {
props.setTimeoutId(
setTimeout(() => {
props.setShowChooser(false);
}, 320),
);
}}
class="max-h-[95vh] w-40 overflow-auto [scrollbar-width:none]"
>
<DropdownList.Item
onClick={() => {
setCreatePlaylistBoxSong(props.song);
setShowPlaylistCreateBox(true);
setSidebarActiveTab(SIDEBAR_PAGES.PLAYLISTS.value);
setPlaylistActiveScene(PLAYLIST_SCENE_LIST);
}}
>
<span>Create Playlist</span>
<PlusIcon class="text-subtext" size={20} />
</DropdownList.Item>
<For
fallback={<DropdownList.Item disabled={true}>No playlists...</DropdownList.Item>}
each={props.playlistNames}
Expand All @@ -47,16 +77,6 @@ const PlaylistChooser: Component<PlaylistChooserProps> = (props) => {
onClick={() => {
addToPlaylist(props.playlistNames[index()]);
}}
onMouseOver={() => {
clearTimeout(props.timeoutId());
}}
onMouseLeave={() => {
props.setTimeoutId(
setTimeout(() => {
props.setShowChooser(false);
}, 320),
);
}}
>
<span>{child}</span>
<Show when={isInPlaylist(props.song, props.playlistNames[index()])}>
Expand Down

0 comments on commit 5d2aa27

Please sign in to comment.