From dcd2c0aa7e2506354fa04c9111a9d375a9969a87 Mon Sep 17 00:00:00 2001 From: Jean-Romain Garnier Date: Tue, 26 Dec 2023 15:29:51 +0100 Subject: [PATCH] Show search in modal view --- src/app/page.module.css | 4 +- src/app/page.tsx | 51 +++++--- src/app/search.module.css | 16 +++ src/app/{form.tsx => search.tsx} | 13 +- src/app/titlebar.module.css | 75 ++++++++++++ src/app/titlebar.tsx | 112 ++++++++++++++++++ ...rack.module.css => track_cover.module.css} | 12 +- src/app/track_cover.tsx | 2 +- src/app/track_list.module.css | 14 +-- src/app/track_list.tsx | 24 +++- 10 files changed, 285 insertions(+), 38 deletions(-) create mode 100644 src/app/search.module.css rename src/app/{form.tsx => search.tsx} (82%) create mode 100644 src/app/titlebar.module.css create mode 100644 src/app/titlebar.tsx rename src/app/{track.module.css => track_cover.module.css} (78%) diff --git a/src/app/page.module.css b/src/app/page.module.css index ab686ca..f7ac367 100644 --- a/src/app/page.module.css +++ b/src/app/page.module.css @@ -1,3 +1,3 @@ -.main { - margin: 10px; +.body { + padding: 10px; } diff --git a/src/app/page.tsx b/src/app/page.tsx index 4473ca7..a801aa6 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,9 +1,41 @@ import { getQueue, getCurrentPlayback } from "@/utils/queue"; import styles from "./page.module.css"; import { redirect } from "next/navigation"; +import TitleBar from "./titlebar"; import TrackCover from "./track_cover"; import TrackList from "./track_list"; -import Form from "./form"; + +interface Props { + queue: any; + currentPlayback: any; +} + +export function Body({ queue, currentPlayback }: Props) { + return ( +
+

Currently playing

+ {(() => { + if ( + currentPlayback?.isPlaying && + currentPlayback.item?.type === "track" + ) { + return ; + } else { + return
Play any song on Spotify to get started!
; + } + })()} +
+

Queue

+ {(() => { + if (queue !== null && queue.length > 0) { + return ; + } else { + return
Your song queue is empty.
; + } + })()} +
+ ); +} export default async function Home() { const [queue, currentPlayback] = await Promise.all([ @@ -14,21 +46,8 @@ export default async function Home() { return (
-
- - {currentPlayback?.isPlaying && currentPlayback.item?.type === "track" && ( - <> -

Currently playing

- - - )} - - {queue.length > 0 && ( - <> -

Queue

- - - )} + +
); } diff --git a/src/app/search.module.css b/src/app/search.module.css new file mode 100644 index 0000000..a6ac99d --- /dev/null +++ b/src/app/search.module.css @@ -0,0 +1,16 @@ +.input { + border: 1px solid #999999; + height: 40px; + box-sizing: border-box; + padding: 1px 10px; + outline: none; + transition: 0.2s ease-in-out; + width: 100%; + border-radius: 20px; + margin-bottom: 5px; +} + +.input:focus { + transition: 0.2s ease-in-out; + border: 1px solid #1fdf64; +} diff --git a/src/app/form.tsx b/src/app/search.tsx similarity index 82% rename from src/app/form.tsx rename to src/app/search.tsx index 0a723d0..d87d6eb 100644 --- a/src/app/form.tsx +++ b/src/app/search.tsx @@ -1,12 +1,14 @@ "use client"; import { useEffect, useState } from "react"; +import { useRouter } from "next/navigation"; import * as Spotify from "spotify-api.js"; import { pushTrack, searchTracks } from "./actions"; import { TrackHeader, TrackItem } from "./track_list"; -import { useRouter } from "next/navigation"; +import styles from "./search.module.css"; +import track_styles from "./track_list.module.css"; -export default function Form() { +export default function Search() { const router = useRouter(); const [query, setQuery] = useState(""); const [results, setResults] = useState([]); @@ -32,17 +34,18 @@ export default function Form() { return ( -

Add a song

setQuery(e.target.value)} /> {results.length > 0 && ( <> - +
- + undefined} /> {results.map((track, index) => ( diff --git a/src/app/titlebar.module.css b/src/app/titlebar.module.css new file mode 100644 index 0000000..b047517 --- /dev/null +++ b/src/app/titlebar.module.css @@ -0,0 +1,75 @@ +.header { + display: table; + width: 100%; + background-color: #1fdf64; + padding: 5px 10px 5px 10px; + margin: 0; +} + +.header div { + display: table-row; +} + +.header div div { + display: table-cell; + width: auto; +} + +.header .icon { + width: 25px; + height: 25px; + vertical-align: middle; + display: inline-block; +} + +.header .title { + width: 100%; + padding: 0 20px 0 20px; + vertical-align: middle; + display: inline-block; +} + +.header button { + width: 100px; + vertical-align: middle; + display: inline-block; +} + +.modal { + width: 90%; + height: 90%; + margin: 2% 5% 5% 5%; + border-width: 1px; + border-color: black; + padding: 10px; + border-radius: 20px; +} + +.modal::backdrop { + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(10px); +} + +.modal_header { + width: 100%; + display: table; + padding-bottom: 10px; +} + +.modal_header div { + display: table-cell; + width: auto; +} + +.modal_header h1 { + width: 100%; + vertical-align: middle; + display: inline-block; +} + +.modal_header button { + width: 25px; + height: 25px; + vertical-align: middle; + display: inline-block; +} diff --git a/src/app/titlebar.tsx b/src/app/titlebar.tsx new file mode 100644 index 0000000..1cb936d --- /dev/null +++ b/src/app/titlebar.tsx @@ -0,0 +1,112 @@ +"use client"; +import { + useRef, + useEffect, + useState, + DispatchWithoutAction, + ReactNode, + MouseEvent, +} from "react"; +import Image from "next/image"; +import styles from "./titlebar.module.css"; +import Search from "./search"; + +interface Props { + title: string | undefined; + children: ReactNode; + isOpen: boolean; + handleClose: DispatchWithoutAction; +} + +function Modal({ title, children, isOpen, handleClose }: Props) { + const dialogRef = useRef(null); + + const close = () => { + dialogRef.current?.close(); + }; + + function handleClickOutside(event: MouseEvent) { + if (!dialogRef.current) { + return; + } + + const box = dialogRef.current?.getBoundingClientRect(); + if ( + event.pageX < box.left || + event.pageX > box.right || + event.pageY < box.top + window.scrollY || + event.pageY > box.bottom + window.scrollY + ) { + close(); + } + } + + useEffect(() => { + const dialog = dialogRef.current; + if (isOpen && !dialogRef.current?.open) { + dialog?.showModal(); + document.body.style.overflow = "hidden"; + } else { + dialog?.close(); + document.body.style.overflow = ""; + } + }, [isOpen]); + + return ( + +
+
+

{title}

+
+
+ +
+
+ {children} +
+ ); +} + +export default function TitleBar() { + const [isOpen, setIsOpen] = useState(false); + const showSongModel = () => { + setIsOpen(true); + }; + const hideSongModel = () => { + setIsOpen(false); + }; + + return ( +
+
+
+
+ +
+
+

Spotify collab

+
+
+ +
+
+
+ + + +
+ ); +} diff --git a/src/app/track.module.css b/src/app/track_cover.module.css similarity index 78% rename from src/app/track.module.css rename to src/app/track_cover.module.css index 3ff8869..65868f0 100644 --- a/src/app/track.module.css +++ b/src/app/track_cover.module.css @@ -44,5 +44,15 @@ table .cover_column { } .duration { - width: 150px; + width: 100px; +} + +@media (max-width: 760px) { + .cover { + width: 80px; + height: 80px; + } + table .cover_column { + width: 80px; + } } diff --git a/src/app/track_cover.tsx b/src/app/track_cover.tsx index b61adc4..a2d3934 100644 --- a/src/app/track_cover.tsx +++ b/src/app/track_cover.tsx @@ -1,7 +1,7 @@ import Image from "next/image"; import * as Spotify from "spotify-api.js"; import { formatDuration } from "@/utils/ui"; -import styles from "./track.module.css"; +import styles from "./track_cover.module.css"; interface Props { currentPlayback: Spotify.CurrentPlayback; diff --git a/src/app/track_list.module.css b/src/app/track_list.module.css index 932eef4..da61298 100644 --- a/src/app/track_list.module.css +++ b/src/app/track_list.module.css @@ -13,7 +13,7 @@ padding: 5px; } -table .cover_column { +.cover_column { width: 50px; } @@ -30,12 +30,6 @@ table .cover_column { cursor: auto; } -.index { - height: 50px; - line-height: 50px; - text-align: center; -} - .cover { width: 50px; height: 50px; @@ -52,3 +46,9 @@ table .cover_column { .artist { color: #777777; } + +@media (max-width: 760px) { + .album { + display: none; + } +} diff --git a/src/app/track_list.tsx b/src/app/track_list.tsx index 9b41871..f2288cf 100644 --- a/src/app/track_list.tsx +++ b/src/app/track_list.tsx @@ -4,20 +4,28 @@ import * as Spotify from "spotify-api.js"; import { formatDuration } from "@/utils/ui"; import styles from "./track_list.module.css"; +interface HeaderProps { + onClick?: DispatchWithoutAction; +} + interface ItemProps { index: number; track: Spotify.Track; onClick?: DispatchWithoutAction; } -export function TrackHeader() { +export function TrackHeader({ onClick }: HeaderProps) { return (
- + {onClick === undefined && ( + <> + + + )} - - + + ); } @@ -31,7 +39,11 @@ export function TrackItem({ index, track, onClick }: ItemProps) { }`} role="gridcell" > - + {onClick === undefined && ( + <> + + + )} - + {items.map((track, index) => (
{"#"}#Title AlbumDurationAlbum🕗
{index}.{index}. album cover