From b0dba0c040131367b4252ea7439f0c12e7901438 Mon Sep 17 00:00:00 2001 From: "Justin Craig-Kuhn (JCK)" Date: Fri, 20 Dec 2024 11:30:22 -0800 Subject: [PATCH] Add cover art inspector --- app/javascript/components/CoverArt.jsx | 6 +- .../components/CoverArtInspector.jsx | 92 +++++++++++++++++++ app/javascript/components/Show.jsx | 3 +- app/javascript/components/pages/Faq.jsx | 1 + app/javascript/components/routes/routes.js | 6 ++ app/javascript/stylesheets/content.css.scss | 25 +++++ 6 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 app/javascript/components/CoverArtInspector.jsx diff --git a/app/javascript/components/CoverArt.jsx b/app/javascript/components/CoverArt.jsx index 2fd87ead..a9e616b2 100644 --- a/app/javascript/components/CoverArt.jsx +++ b/app/javascript/components/CoverArt.jsx @@ -1,6 +1,7 @@ import React, { useState } from "react"; +import { Link } from "react-router-dom"; -const CoverArt = ({ coverArtUrls, albumCoverUrl, openAppModal, size = "small", css, selectedOption }) => { +const CoverArt = ({ coverArtUrls, albumCoverUrl, openAppModal, closeAppModal, size = "small", css, selectedOption }) => { const [isLoaded, setIsLoaded] = useState(false); const handleOpenModal = () => { @@ -26,7 +27,8 @@ const CoverArt = ({ coverArtUrls, albumCoverUrl, openAppModal, size = "small", c )}
- Images generated by DALL-E with prompt assistance from ChatGPT. + Images generated by DALL-E with prompt assistance from ChatGPT.
+ Browse All Art
); diff --git a/app/javascript/components/CoverArtInspector.jsx b/app/javascript/components/CoverArtInspector.jsx new file mode 100644 index 00000000..f72cf994 --- /dev/null +++ b/app/javascript/components/CoverArtInspector.jsx @@ -0,0 +1,92 @@ +export const coverArtInspectorLoader = async ({ request }) => { + const url = new URL(request.url); + const page = url.searchParams.get("page") || 1; + const perPage = url.searchParams.get("per_page") || 50; + + try { + const response = await fetch(`/api/v2/shows?page=${page}&per_page=${perPage}`); + if (!response.ok) throw response; + const data = await response.json(); + return { + shows: data.shows, + totalPages: data.total_pages, + totalEntries: data.total_entries, + page: parseInt(page, 10) - 1, + perPage: parseInt(perPage) + }; + } catch (error) { + throw new Response("Error fetching data", { status: 500 }); + } +}; + +import React, { useState } from "react"; +import { useLoaderData, useNavigate, useOutletContext } from "react-router-dom"; +import { Helmet } from "react-helmet-async"; +import LayoutWrapper from "./layout/LayoutWrapper"; +import CoverArt from "./CoverArt"; +import Pagination from "./controls/Pagination"; +import { paginationHelper } from "./helpers/pagination"; +import { formatNumber } from "./helpers/utils"; + +const CoverArtInspector = () => { + const { shows, totalPages, totalEntries, page, perPage } = useLoaderData(); + const { openAppModal, closeAppModal } = useOutletContext(); + const [selectedOption, setSelectedOption] = useState("coverArt"); + const { + tempPerPage, + handlePageClick, + handlePerPageInputChange, + handlePerPageBlurOrEnter + } = paginationHelper(page, "", perPage); + + const handleOptionChange = (e) => { + setSelectedOption(e.target.value); + }; + + const sidebarContent = ( +
+

Cover Art

+

{formatNumber(totalEntries)} total

+
+ +
+
+ ); + + return ( + <> + + Cover Art - Phish.in + + +
+ {shows.map((show) => ( + + ))} +
+ +
+ + ); +}; + +export default CoverArtInspector; diff --git a/app/javascript/components/Show.jsx b/app/javascript/components/Show.jsx index ca1e6c0c..6cdc9549 100644 --- a/app/javascript/components/Show.jsx +++ b/app/javascript/components/Show.jsx @@ -32,7 +32,7 @@ const Show = ({ trackSlug }) => { const show = useLoaderData(); const [tracks, setTracks] = useState(show.tracks); const trackRefs = useRef([]); - const { playTrack, mapboxToken, openAppModal } = useOutletContext(); + const { playTrack, mapboxToken, openAppModal, closeAppModal } = useOutletContext(); const [matchedTrack, setMatchedTrack] = useState(tracks[0]); const [showIncompleteNotification, setShowIncompleteNotification] = useState(show.incomplete); const [showAdminNotesNotification, setShowAdminNotesNotification] = useState(!!show.admin_notes); @@ -89,6 +89,7 @@ const Show = ({ trackSlug }) => { coverArtUrls={show.cover_art_urls} albumCoverUrl={show.album_cover_url} openAppModal={openAppModal} + closeAppModal={closeAppModal} size="medium" /> diff --git a/app/javascript/components/pages/Faq.jsx b/app/javascript/components/pages/Faq.jsx index 1d28fac1..fd1ad622 100644 --- a/app/javascript/components/pages/Faq.jsx +++ b/app/javascript/components/pages/Faq.jsx @@ -81,6 +81,7 @@ const Faq = () => {

How is album cover art created?

Album covers are generated with a combination of automation scripts and the assistance of ChatGPT and Dall-E.

+ Browse All Art

How can I contribute?

diff --git a/app/javascript/components/routes/routes.js b/app/javascript/components/routes/routes.js index 08bc516f..c30c1d9d 100644 --- a/app/javascript/components/routes/routes.js +++ b/app/javascript/components/routes/routes.js @@ -22,6 +22,7 @@ import TopShows, { topShowsLoader } from "../TopShows"; import TopTracks, { topTracksLoader } from "../TopTracks"; import VenueIndex, { venueIndexLoader } from "../VenueIndex"; import VenueShows, { venueShowsLoader } from "../VenueShows"; +import CoverArtInspector, { coverArtInspectorLoader } from "../CoverArtInspector"; // Simple pages with no sidebar import ApiDocs from "../pages/ApiDocs"; @@ -181,6 +182,11 @@ const routes = (props) => [ path: "/settings", element: , }, + { + path: "/cover-art", + element: , + loader: coverArtInspectorLoader, + }, { path: "*", element: , diff --git a/app/javascript/stylesheets/content.css.scss b/app/javascript/stylesheets/content.css.scss index aa3a9e41..a7a6dc37 100644 --- a/app/javascript/stylesheets/content.css.scss +++ b/app/javascript/stylesheets/content.css.scss @@ -439,6 +439,31 @@ main { } } +.cover-art-inspector-container { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); + gap: 1rem; + padding: 1rem; + width: 100%; + + .cover-art-inspector { + width: 128px; + height: 128px; + border-radius: 8px; + object-fit: cover; + transition: transform 0.2s ease; + + &:hover { + transform: scale(1.05); + cursor: pointer; + } + } + + .cover-art { + background-color: transparent !important; + } +} + .grid-view { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));