Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

webui: enable 'Play/Shuffle' artist tracks button

+1041 -288
+2
webui/rockbox/src/App.tsx
··· 5 5 import AlbumDetails from "./Components/AlbumDetails"; 6 6 import ArtistDetails from "./Components/ArtistDetails"; 7 7 import FilesPage from "./Containers/Files"; 8 + import LikesPage from "./Containers/Likes"; 8 9 9 10 function App() { 10 11 return ( ··· 17 18 <Route path="/artists/:id" element={<ArtistDetails />} /> 18 19 <Route path="/tracks" element={<TracksPage />} /> 19 20 <Route path="/files" element={<FilesPage />} /> 21 + <Route path="/likes" element={<LikesPage />} /> 20 22 </Routes> 21 23 </BrowserRouter> 22 24 );
+27
webui/rockbox/src/Components/Album/Album.stories.tsx
··· 1 + import type { Meta, StoryObj } from "@storybook/react"; 2 + 3 + import Album from "./Album"; 4 + import { albums } from "../Albums/mocks"; 5 + import { fn } from "@storybook/test"; 6 + 7 + // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export 8 + const meta = { 9 + title: "Components/Album", 10 + component: Album, 11 + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs 12 + tags: ["autodocs"], 13 + // More on argTypes: https://storybook.js.org/docs/api/argtypes 14 + } satisfies Meta<typeof Album>; 15 + 16 + export default meta; 17 + type Story = StoryObj<typeof meta>; 18 + 19 + // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args 20 + export const Default: Story = { 21 + args: { 22 + onPlay: fn(), 23 + onLike: fn(), 24 + onUnLike: fn(), 25 + album: albums[0], 26 + }, 27 + };
+31
webui/rockbox/src/Components/Album/Album.test.tsx
··· 1 + import { render } from "@testing-library/react"; 2 + import { vi } from "vitest"; 3 + import Album from "./Album"; 4 + import { albums } from "../Albums/mocks"; 5 + import Providers from "../../Providers"; 6 + import { MemoryRouter } from "react-router-dom"; 7 + import { MockedProvider } from "@apollo/client/testing"; 8 + import { mocks } from "../../mocks"; 9 + 10 + describe("Album", () => { 11 + it("should render", () => { 12 + const onPlay = vi.fn(); 13 + const onUnLike = vi.fn(); 14 + const onLike = vi.fn(); 15 + const { container } = render( 16 + <MemoryRouter initialEntries={["/"]}> 17 + <MockedProvider mocks={mocks}> 18 + <Providers> 19 + <Album 20 + album={albums[0]} 21 + onPlay={onPlay} 22 + onUnLike={onUnLike} 23 + onLike={onLike} 24 + /> 25 + </Providers> 26 + </MockedProvider> 27 + </MemoryRouter> 28 + ); 29 + expect(container).toMatchSnapshot(); 30 + }); 31 + });
+66
webui/rockbox/src/Components/Album/Album.tsx
··· 1 + /* eslint-disable @typescript-eslint/no-explicit-any */ 2 + import { FC } from "react"; 3 + import { 4 + AlbumCover, 5 + AlbumFooterMenu, 6 + AlbumTitle, 7 + Artist, 8 + FloatingButton, 9 + Hover, 10 + Link, 11 + NoAlbumCover, 12 + Year, 13 + } from "./styles"; 14 + import Play from "../Icons/Play"; 15 + import ContextMenu from "./ContextMenu"; 16 + import HeartOutline from "../Icons/HeartOutline"; 17 + import AlbumArt from "../../Assets/albumart.svg"; 18 + 19 + export type AlbumProps = { 20 + album: any; 21 + onPlay: (album: any) => void; 22 + onLike: (album: any) => void; 23 + onUnLike: (album: any) => void; 24 + }; 25 + 26 + const Album: FC<AlbumProps> = (props) => { 27 + return ( 28 + <div style={{ position: "relative", width: "100%" }}> 29 + <Hover> 30 + <AlbumFooterMenu> 31 + <div 32 + style={{ 33 + backgroundColor: "#ffffffda", 34 + height: 40, 35 + width: 40, 36 + borderRadius: 20, 37 + display: "flex", 38 + justifyContent: "center", 39 + alignItems: "center", 40 + }} 41 + onClick={() => props.onPlay(props.album)} 42 + > 43 + <Play small color="#000" /> 44 + </div> 45 + <ContextMenu item={props.album} /> 46 + <FloatingButton onClick={() => props.onLike(props.album)}> 47 + <HeartOutline color="#fff" size={20} /> 48 + </FloatingButton> 49 + </AlbumFooterMenu> 50 + </Hover> 51 + <Link to={`/albums/${props.album.id}`}> 52 + {props.album.cover && ( 53 + <AlbumCover src={props.album.cover} effect="opacity" /> 54 + )} 55 + {!props.album.cover && <NoAlbumCover src={AlbumArt} />} 56 + <AlbumTitle>{props.album.title}</AlbumTitle> 57 + </Link> 58 + <Artist to={`/artists/${props.album.artistId}`}> 59 + {props.album.artist} 60 + </Artist> 61 + <Year>{props.album.year}</Year> 62 + </div> 63 + ); 64 + }; 65 + 66 + export default Album;
+30
webui/rockbox/src/Components/Album/AlbumWithData.tsx
··· 1 + /* eslint-disable @typescript-eslint/no-explicit-any */ 2 + import { FC } from "react"; 3 + import Album from "./Album"; 4 + import { usePlayAlbumMutation } from "../../Hooks/GraphQL"; 5 + 6 + export type AlbumWithDataProps = { 7 + album: any; 8 + }; 9 + 10 + const AlbumWithData: FC<AlbumWithDataProps> = ({ album }) => { 11 + const [playAlbum] = usePlayAlbumMutation(); 12 + 13 + const onPlay = ({ id: albumId }: any) => { 14 + playAlbum({ 15 + variables: { 16 + albumId, 17 + }, 18 + }); 19 + }; 20 + return ( 21 + <Album 22 + album={album} 23 + onLike={() => {}} 24 + onPlay={onPlay} 25 + onUnLike={() => {}} 26 + /> 27 + ); 28 + }; 29 + 30 + export default AlbumWithData;
+145
webui/rockbox/src/Components/Album/__snapshots__/Album.test.tsx.snap
··· 1 + // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 + 3 + exports[`Album > should render 1`] = ` 4 + <div> 5 + <div 6 + class="" 7 + > 8 + <div 9 + style="position: relative; width: 100%;" 10 + > 11 + <button 12 + class="css-12ezcoy" 13 + > 14 + <div 15 + class="css-15yrfky" 16 + > 17 + <div 18 + style="background-color: rgba(255, 255, 255, 0.855); height: 40px; width: 40px; border-radius: 20px; display: flex; justify-content: center; align-items: center;" 19 + > 20 + <svg 21 + fill="none" 22 + height="20" 23 + width="20" 24 + xmlns="http://www.w3.org/2000/svg" 25 + > 26 + <path 27 + class="ionicon" 28 + d="M7.386 16c-.23 0-.456-.057-.656-.165-.45-.24-.73-.706-.73-1.213V4.378a1.387 1.387 0 0 1 2.071-1.197l9.296 5.241c.394.232.633.64.633 1.077 0 .438-.239.845-.633 1.078L8.07 15.819a1.39 1.39 0 0 1-.684.181Z" 29 + style="fill: #000;" 30 + /> 31 + </svg> 32 + </div> 33 + <div 34 + class="css-113iyi7" 35 + > 36 + <button 37 + class="css-10bvv2v" 38 + > 39 + <div 40 + aria-expanded="false" 41 + aria-haspopup="true" 42 + class="css-10n9a0h" 43 + > 44 + <svg 45 + aria-hidden="true" 46 + class="StyledIconBase-sc-ea9ulj-0 dmvaRK" 47 + color="#fff" 48 + fill="currentColor" 49 + focusable="false" 50 + height="24" 51 + viewBox="0 0 512 512" 52 + width="24" 53 + xmlns="http://www.w3.org/2000/svg" 54 + > 55 + <circle 56 + cx="256" 57 + cy="256" 58 + r="48" 59 + /> 60 + <circle 61 + cx="416" 62 + cy="256" 63 + r="48" 64 + /> 65 + <circle 66 + cx="96" 67 + cy="256" 68 + r="48" 69 + /> 70 + </svg> 71 + </div> 72 + </button> 73 + </div> 74 + <button 75 + class="css-10n9a0h" 76 + > 77 + <svg 78 + fill="none" 79 + height="20" 80 + style="padding-top: 1px;" 81 + width="20" 82 + xmlns="http://www.w3.org/2000/svg" 83 + > 84 + <g 85 + class="ionicon" 86 + style="fill: #fff;" 87 + > 88 + <path 89 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 90 + fill="none" 91 + stroke="currentColor" 92 + stroke-linecap="round" 93 + stroke-linejoin="round" 94 + style="fill: none;" 95 + /> 96 + <path 97 + class="stroke-shape" 98 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 99 + stroke="currentColor" 100 + stroke-linecap="round" 101 + stroke-linejoin="round" 102 + style="fill: none; stroke-width: 2; stroke: #fff; stroke-opacity: 1;" 103 + /> 104 + </g> 105 + </svg> 106 + </button> 107 + </div> 108 + </button> 109 + <a 110 + class="css-11g9kr1" 111 + href="/albums/1" 112 + > 113 + <span 114 + class=" lazy-load-image-background opacity" 115 + style="color: transparent; display: inline-block;" 116 + > 117 + <img 118 + class="css-1g7adp4" 119 + src="https://resources.tidal.com/images/b80f3852/73e5/43d6/90ea/021d1fad2bbe/320x320.jpg" 120 + /> 121 + </span> 122 + <div 123 + class="css-e68bk5" 124 + > 125 + The End, So Far 126 + </div> 127 + </a> 128 + <a 129 + class="css-9sbfuc" 130 + href="/artists/1" 131 + > 132 + Slipknot 133 + </a> 134 + <div 135 + class="css-1q570sn" 136 + > 137 + 2022 138 + </div> 139 + </div> 140 + </div> 141 + <div 142 + class="" 143 + /> 144 + </div> 145 + `;
+3
webui/rockbox/src/Components/Album/index.tsx
··· 1 + import Album from "./AlbumWithData"; 2 + 3 + export default Album;
+87
webui/rockbox/src/Components/Album/styles.tsx
··· 1 + import styled from "@emotion/styled"; 2 + import { LazyLoadImage } from "react-lazy-load-image-component"; 3 + import { Link as RouterLink } from "react-router-dom"; 4 + 5 + export const AlbumCover = styled(LazyLoadImage)` 6 + width: 100%; 7 + border-radius: 3px; 8 + cursor: pointer; 9 + `; 10 + 11 + export const NoAlbumCover = styled.img` 12 + width: 100%; 13 + border-radius: 3px; 14 + cursor: pointer; 15 + `; 16 + 17 + export const Artist = styled(RouterLink)` 18 + color: #828282; 19 + font-size: 14px; 20 + text-overflow: ellipsis; 21 + overflow: hidden; 22 + white-space: nowrap; 23 + cursor: pointer; 24 + text-decoration: none; 25 + `; 26 + 27 + export const Year = styled.div` 28 + color: #828282; 29 + font-size: 12px; 30 + font-weight: 400; 31 + margin-bottom: 56px; 32 + `; 33 + 34 + export const AlbumTitle = styled.div` 35 + font-size: 14px; 36 + text-overflow: ellipsis; 37 + overflow: hidden; 38 + white-space: nowrap; 39 + cursor: pointer; 40 + color: #000; 41 + `; 42 + 43 + export const AlbumFooterMenu = styled.div` 44 + position: absolute; 45 + bottom: 60px; 46 + left: 10px; 47 + height: 60px; 48 + display: flex; 49 + flex-direction: row; 50 + align-items: center; 51 + justify-content: space-between; 52 + width: calc(100% - 20px); 53 + z-index: 1; 54 + `; 55 + 56 + export const Hover = styled.button` 57 + color: transparent; 58 + background-color: transparent; 59 + border: none; 60 + opacity: 0 !important; 61 + cursor: pointer; 62 + &:hover, 63 + &:focus { 64 + color: #000; 65 + opacity: 1 !important; 66 + } 67 + `; 68 + 69 + export const FloatingButton = styled.button` 70 + height: 40px; 71 + width: 40px; 72 + border-radius: 20px; 73 + display: flex; 74 + justify-content: center; 75 + align-items: center; 76 + border: none; 77 + cursor: pointer; 78 + background-color: transparent; 79 + 80 + &:hover { 81 + background-color: #434242b5; 82 + } 83 + `; 84 + 85 + export const Link = styled(RouterLink)` 86 + text-decoration: none; 87 + `;
+40
webui/rockbox/src/Components/AlbumDetails/__snapshots__/AlbumDetails.test.tsx.snap
··· 95 95 <a 96 96 class="css-tujm8o" 97 97 color="initial" 98 + href="/likes" 99 + > 100 + <svg 101 + fill="none" 102 + height="20" 103 + style="padding-top: 1px;" 104 + width="20" 105 + xmlns="http://www.w3.org/2000/svg" 106 + > 107 + <g 108 + class="ionicon" 109 + style="fill: initial;" 110 + > 111 + <path 112 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 113 + fill="none" 114 + stroke="currentColor" 115 + stroke-linecap="round" 116 + stroke-linejoin="round" 117 + style="fill: none;" 118 + /> 119 + <path 120 + class="stroke-shape" 121 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 122 + stroke="currentColor" 123 + stroke-linecap="round" 124 + stroke-linejoin="round" 125 + style="fill: none; stroke-width: 2; stroke: initial; stroke-opacity: 1;" 126 + /> 127 + </g> 128 + </svg> 129 + <div 130 + style="margin-left: 6px;" 131 + > 132 + Likes 133 + </div> 134 + </a> 135 + <a 136 + class="css-tujm8o" 137 + color="initial" 98 138 href="/files" 99 139 > 100 140 <svg
-1
webui/rockbox/src/Components/Albums/Albums.stories.tsx
··· 20 20 export const Default: Story = { 21 21 args: { 22 22 onFilter: fn(), 23 - onPlay: fn(), 24 23 onLike: fn(), 25 24 onUnLike: fn(), 26 25 albums,
-2
webui/rockbox/src/Components/Albums/Albums.test.tsx
··· 9 9 10 10 describe("Albums", () => { 11 11 it("should render", () => { 12 - const onPlay = vi.fn(); 13 12 const onFilter = vi.fn(); 14 13 const onUnLike = vi.fn(); 15 14 const onLike = vi.fn(); ··· 19 18 <Providers> 20 19 <Albums 21 20 albums={albums} 22 - onPlay={onPlay} 23 21 onFilter={onFilter} 24 22 onUnLike={onUnLike} 25 23 onLike={onLike}
+3 -55
webui/rockbox/src/Components/Albums/Albums.tsx
··· 4 4 import MainView from "../MainView"; 5 5 import Sidebar from "../Sidebar"; 6 6 import ControlBar from "../ControlBar"; 7 - import AlbumArt from "../../Assets/albumart.svg"; 8 - import { 9 - AlbumCover, 10 - AlbumFooterMenu, 11 - AlbumTitle, 12 - Artist, 13 - Container, 14 - FilterContainer, 15 - FloatingButton, 16 - Hover, 17 - Scrollable, 18 - Title, 19 - Year, 20 - Link, 21 - NoAlbumCover, 22 - } from "./styles"; 7 + import { Container, FilterContainer, Scrollable, Title } from "./styles"; 23 8 import Filter from "../Filter"; 24 - import Play from "../Icons/Play"; 25 - import HeartOutline from "../Icons/HeartOutline"; 26 - import ContextMenu from "./ContextMenu"; 9 + import Album from "../Album"; 27 10 28 11 export type AlbumsProps = { 29 12 albums: any[]; 30 13 onFilter: (filter: string) => void; 31 - onPlay: (album: any) => void; 32 14 onLike: (album: any) => void; 33 15 onUnLike: (album: any) => void; 34 16 }; ··· 53 35 > 54 36 {albums.map((item) => ( 55 37 <Cell key={item.id}> 56 - <div style={{ position: "relative", width: "100%" }}> 57 - <Hover> 58 - <AlbumFooterMenu> 59 - <div 60 - style={{ 61 - backgroundColor: "#ffffffda", 62 - height: 40, 63 - width: 40, 64 - borderRadius: 20, 65 - display: "flex", 66 - justifyContent: "center", 67 - alignItems: "center", 68 - }} 69 - onClick={() => props.onPlay(item)} 70 - > 71 - <Play small color="#000" /> 72 - </div> 73 - <ContextMenu item={item} /> 74 - <FloatingButton onClick={() => props.onLike(item)}> 75 - <HeartOutline color="#fff" size={20} /> 76 - </FloatingButton> 77 - </AlbumFooterMenu> 78 - </Hover> 79 - <Link to={`/albums/${item.id}`}> 80 - {item.cover && ( 81 - <AlbumCover src={item.cover} effect="opacity" /> 82 - )} 83 - {!item.cover && <NoAlbumCover src={AlbumArt} />} 84 - <AlbumTitle>{item.title}</AlbumTitle> 85 - </Link> 86 - <Artist to={`/artists/${item.artistId}`}> 87 - {item.artist} 88 - </Artist> 89 - <Year>{item.year}</Year> 90 - </div> 38 + <Album album={item} /> 91 39 </Cell> 92 40 ))} 93 41 </Grid>
+1 -12
webui/rockbox/src/Components/Albums/AlbumsWithData.tsx
··· 1 1 import { FC, useEffect, useState } from "react"; 2 2 import Albums from "./Albums"; 3 - import { useGetAlbumsQuery, usePlayAlbumMutation } from "../../Hooks/GraphQL"; 3 + import { useGetAlbumsQuery } from "../../Hooks/GraphQL"; 4 4 5 5 const AlbumsWithData: FC = () => { 6 6 // eslint-disable-next-line @typescript-eslint/no-explicit-any 7 7 const [albums, setAlbums] = useState<any[]>([]); 8 8 const { data } = useGetAlbumsQuery(); 9 - const [playAlbum] = usePlayAlbumMutation(); 10 - 11 - // eslint-disable-next-line @typescript-eslint/no-explicit-any 12 - const onPlay = ({ id: albumId }: any) => { 13 - playAlbum({ 14 - variables: { 15 - albumId, 16 - }, 17 - }); 18 - }; 19 9 20 10 useEffect(() => { 21 11 if (data) { ··· 37 27 onFilter={() => {}} 38 28 albums={albums} 39 29 onLike={() => {}} 40 - onPlay={onPlay} 41 30 onUnLike={() => {}} 42 31 /> 43 32 );
webui/rockbox/src/Components/Albums/ContextMenu/ChildMenu.tsx webui/rockbox/src/Components/Album/ContextMenu/ChildMenu.tsx
webui/rockbox/src/Components/Albums/ContextMenu/ContextMenu.stories.tsx webui/rockbox/src/Components/Album/ContextMenu/ContextMenu.stories.tsx
webui/rockbox/src/Components/Albums/ContextMenu/ContextMenu.test.tsx webui/rockbox/src/Components/Album/ContextMenu/ContextMenu.test.tsx
webui/rockbox/src/Components/Albums/ContextMenu/ContextMenu.tsx webui/rockbox/src/Components/Album/ContextMenu/ContextMenu.tsx
webui/rockbox/src/Components/Albums/ContextMenu/ContextMenuWithData.tsx webui/rockbox/src/Components/Album/ContextMenu/ContextMenuWithData.tsx
webui/rockbox/src/Components/Albums/ContextMenu/__snapshots__/ContextMenu.test.tsx.snap webui/rockbox/src/Components/Album/ContextMenu/__snapshots__/ContextMenu.test.tsx.snap
webui/rockbox/src/Components/Albums/ContextMenu/index.tsx webui/rockbox/src/Components/Album/ContextMenu/index.tsx
webui/rockbox/src/Components/Albums/ContextMenu/styles.tsx webui/rockbox/src/Components/Album/ContextMenu/styles.tsx
+40
webui/rockbox/src/Components/Albums/__snapshots__/Albums.test.tsx.snap
··· 95 95 <a 96 96 class="css-tujm8o" 97 97 color="initial" 98 + href="/likes" 99 + > 100 + <svg 101 + fill="none" 102 + height="20" 103 + style="padding-top: 1px;" 104 + width="20" 105 + xmlns="http://www.w3.org/2000/svg" 106 + > 107 + <g 108 + class="ionicon" 109 + style="fill: initial;" 110 + > 111 + <path 112 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 113 + fill="none" 114 + stroke="currentColor" 115 + stroke-linecap="round" 116 + stroke-linejoin="round" 117 + style="fill: none;" 118 + /> 119 + <path 120 + class="stroke-shape" 121 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 122 + stroke="currentColor" 123 + stroke-linecap="round" 124 + stroke-linejoin="round" 125 + style="fill: none; stroke-width: 2; stroke: initial; stroke-opacity: 1;" 126 + /> 127 + </g> 128 + </svg> 129 + <div 130 + style="margin-left: 6px;" 131 + > 132 + Likes 133 + </div> 134 + </a> 135 + <a 136 + class="css-tujm8o" 137 + color="initial" 98 138 href="/files" 99 139 > 100 140 <svg
+4 -49
webui/rockbox/src/Components/ArtistDetails/ArtistDetails.tsx
··· 4 4 import ControlBar from "../ControlBar"; 5 5 import { 6 6 SmallAlbumCover, 7 - AlbumTitle, 8 - Artist, 9 7 BackButton, 10 8 ButtonGroup, 11 9 Container, 12 10 ContentWrapper, 13 - Hover, 14 11 Label, 15 12 MainView, 16 13 Name, 17 14 Separator, 18 15 Title, 19 - Year, 20 - AlbumCover, 21 16 Link, 22 - AlbumFooterMenu, 23 - FloatingButton, 24 - NoAlbumCover, 25 17 } from "./styles"; 26 18 import ArrowBack from "../Icons/ArrowBack"; 27 19 import Shuffle from "../Icons/Shuffle"; ··· 29 21 import Button from "../Button"; 30 22 import { createColumnHelper } from "@tanstack/react-table"; 31 23 import { Track } from "../../Types/track"; 32 - import { EllipsisHorizontal } from "@styled-icons/ionicons-sharp"; 33 - import HeartOutline from "../Icons/HeartOutline"; 34 24 import Table from "../Table"; 35 25 import AlbumArt from "../../Assets/albumart.svg"; 36 26 import { Cell, Grid } from "baseui/layout-grid"; 37 - import { Link as RouterLink } from "react-router-dom"; 38 27 import "./styles.css"; 39 28 import ContextMenu from "../ContextMenu"; 29 + import Album from "../Album"; 40 30 41 31 const columnHelper = createColumnHelper<Track>(); 42 32 const columns = [ ··· 162 152 </BackButton> 163 153 <Name>{props.name}</Name> 164 154 <ButtonGroup> 165 - <Button onClick={() => {}} kind="primary"> 155 + <Button onClick={props.onPlayAll} kind="primary"> 166 156 <Label> 167 157 <Play small color="#fff" /> 168 158 <div style={{ marginLeft: 7 }}>Play</div> 169 159 </Label> 170 160 </Button> 171 161 <Separator /> 172 - <Button onClick={() => {}} kind="secondary"> 162 + <Button onClick={props.onShuffleAll} kind="secondary"> 173 163 <Label> 174 164 <Shuffle color="#fe099c" /> 175 165 <div style={{ marginLeft: 7 }}>Shuffle</div> ··· 187 177 > 188 178 {props.albums.map((item) => ( 189 179 <Cell key={item.id}> 190 - <div style={{ position: "relative", width: "100%" }}> 191 - <Hover> 192 - <AlbumFooterMenu> 193 - <div 194 - style={{ 195 - backgroundColor: "#ffffffbc", 196 - height: 40, 197 - width: 40, 198 - borderRadius: 20, 199 - display: "flex", 200 - justifyContent: "center", 201 - alignItems: "center", 202 - }} 203 - > 204 - <Play small color="#000" /> 205 - </div> 206 - <FloatingButton> 207 - <EllipsisHorizontal size={24} color="#fff" /> 208 - </FloatingButton> 209 - <FloatingButton> 210 - <HeartOutline color="#fff" /> 211 - </FloatingButton> 212 - </AlbumFooterMenu> 213 - </Hover> 214 - <RouterLink to={`/albums/${item.id}`}> 215 - {item.albumArt && ( 216 - <AlbumCover src={item.albumArt} effect="opacity" /> 217 - )} 218 - {!item.albumArt && <NoAlbumCover src={AlbumArt} />} 219 - </RouterLink> 220 - </div> 221 - <AlbumTitle to={`/albums/${item.id}`}> 222 - {item.title} 223 - </AlbumTitle> 224 - <Artist>{item.artist}</Artist> 225 - <Year>{item.year}</Year> 180 + <Album album={item} /> 226 181 </Cell> 227 182 ))} 228 183 </Grid>
+18 -4
webui/rockbox/src/Components/ArtistDetails/ArtistDetailsWithData.tsx
··· 1 1 import { FC } from "react"; 2 2 import ArtistDetails from "./ArtistDetails"; 3 3 import { useNavigate, useParams } from "react-router-dom"; 4 - import { useGetArtistQuery } from "../../Hooks/GraphQL"; 4 + import { 5 + useGetArtistQuery, 6 + usePlayArtistTracksMutation, 7 + } from "../../Hooks/GraphQL"; 5 8 import { useTimeFormat } from "../../Hooks/useFormat"; 6 9 7 10 const ArtistDetailsWithData: FC = () => { ··· 12 15 id: id!, 13 16 }, 14 17 }); 18 + const [playArtistTracks] = usePlayArtistTracksMutation(); 15 19 const { formatTime } = useTimeFormat(); 16 20 const tracks = 17 21 data?.artist?.tracks.map((x) => ({ ··· 22 26 const albums = 23 27 data?.artist?.albums.map((x) => ({ 24 28 ...x, 25 - albumArt: x.albumArt ? `http://localhost:6062/covers/${x.albumArt}` : "", 29 + cover: x.albumArt ? `http://localhost:6062/covers/${x.albumArt}` : "", 26 30 })) || []; 31 + 32 + const onPlayAll = (shuffle: boolean) => { 33 + playArtistTracks({ 34 + variables: { 35 + artistId: id!, 36 + shuffle, 37 + }, 38 + }); 39 + }; 40 + 27 41 return ( 28 42 <ArtistDetails 29 43 name={data?.artist?.name || ""} 30 44 // eslint-disable-next-line @typescript-eslint/no-explicit-any 31 45 tracks={(tracks as any) || []} 32 46 albums={albums || []} 33 - onPlayAll={() => {}} 34 - onShuffleAll={() => {}} 47 + onPlayAll={() => onPlayAll(false)} 48 + onShuffleAll={() => onPlayAll(true)} 35 49 onPlayAlbum={() => {}} 36 50 onLikeAlbum={() => {}} 37 51 onUnLikeAlbum={() => {}}
+223 -165
webui/rockbox/src/Components/ArtistDetails/__snapshots__/ArtistDetails.test.tsx.snap
··· 95 95 <a 96 96 class="css-tujm8o" 97 97 color="initial" 98 + href="/likes" 99 + > 100 + <svg 101 + fill="none" 102 + height="20" 103 + style="padding-top: 1px;" 104 + width="20" 105 + xmlns="http://www.w3.org/2000/svg" 106 + > 107 + <g 108 + class="ionicon" 109 + style="fill: initial;" 110 + > 111 + <path 112 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 113 + fill="none" 114 + stroke="currentColor" 115 + stroke-linecap="round" 116 + stroke-linejoin="round" 117 + style="fill: none;" 118 + /> 119 + <path 120 + class="stroke-shape" 121 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 122 + stroke="currentColor" 123 + stroke-linecap="round" 124 + stroke-linejoin="round" 125 + style="fill: none; stroke-width: 2; stroke: initial; stroke-opacity: 1;" 126 + /> 127 + </g> 128 + </svg> 129 + <div 130 + style="margin-left: 6px;" 131 + > 132 + Likes 133 + </div> 134 + </a> 135 + <a 136 + class="css-tujm8o" 137 + color="initial" 98 138 href="/files" 99 139 > 100 140 <svg ··· 1021 1061 class="css-12ezcoy" 1022 1062 > 1023 1063 <div 1024 - class="css-1jrgpod" 1064 + class="css-15yrfky" 1025 1065 > 1026 1066 <div 1027 - style="background-color: rgba(255, 255, 255, 0.737); height: 40px; width: 40px; border-radius: 20px; display: flex; justify-content: center; align-items: center;" 1067 + style="background-color: rgba(255, 255, 255, 0.855); height: 40px; width: 40px; border-radius: 20px; display: flex; justify-content: center; align-items: center;" 1028 1068 > 1029 1069 <svg 1030 1070 fill="none" ··· 1039 1079 /> 1040 1080 </svg> 1041 1081 </div> 1042 - <button 1043 - class="css-10n9a0h" 1082 + <div 1083 + class="css-113iyi7" 1044 1084 > 1045 - <svg 1046 - aria-hidden="true" 1047 - class="StyledIconBase-sc-ea9ulj-0 dmvaRK" 1048 - color="#fff" 1049 - fill="currentColor" 1050 - focusable="false" 1051 - height="24" 1052 - viewBox="0 0 512 512" 1053 - width="24" 1054 - xmlns="http://www.w3.org/2000/svg" 1085 + <button 1086 + class="css-10bvv2v" 1055 1087 > 1056 - <circle 1057 - cx="256" 1058 - cy="256" 1059 - r="48" 1060 - /> 1061 - <circle 1062 - cx="416" 1063 - cy="256" 1064 - r="48" 1065 - /> 1066 - <circle 1067 - cx="96" 1068 - cy="256" 1069 - r="48" 1070 - /> 1071 - </svg> 1072 - </button> 1088 + <div 1089 + aria-expanded="false" 1090 + aria-haspopup="true" 1091 + class="css-10n9a0h" 1092 + > 1093 + <svg 1094 + aria-hidden="true" 1095 + class="StyledIconBase-sc-ea9ulj-0 dmvaRK" 1096 + color="#fff" 1097 + fill="currentColor" 1098 + focusable="false" 1099 + height="24" 1100 + viewBox="0 0 512 512" 1101 + width="24" 1102 + xmlns="http://www.w3.org/2000/svg" 1103 + > 1104 + <circle 1105 + cx="256" 1106 + cy="256" 1107 + r="48" 1108 + /> 1109 + <circle 1110 + cx="416" 1111 + cy="256" 1112 + r="48" 1113 + /> 1114 + <circle 1115 + cx="96" 1116 + cy="256" 1117 + r="48" 1118 + /> 1119 + </svg> 1120 + </div> 1121 + </button> 1122 + </div> 1073 1123 <button 1074 1124 class="css-10n9a0h" 1075 1125 > ··· 1106 1156 </div> 1107 1157 </button> 1108 1158 <a 1159 + class="css-11g9kr1" 1109 1160 href="/albums/1" 1110 1161 > 1111 - <span 1112 - class=" lazy-load-image-background opacity" 1113 - style="color: transparent; display: inline-block;" 1162 + <img 1163 + class="css-1g7adp4" 1164 + src="/src/Assets/albumart.svg" 1165 + /> 1166 + <div 1167 + class="css-e68bk5" 1114 1168 > 1115 - <img 1116 - class="css-1g7adp4" 1117 - src="https://resources.tidal.com/images/09b59e6e/717e/43e3/b2e2/d2a153c24775/320x320.jpg" 1118 - /> 1119 - </span> 1169 + Random Access Memories 1170 + </div> 1120 1171 </a> 1121 - </div> 1122 - <a 1123 - class="css-1g6cdnz" 1124 - href="/albums/1" 1125 - > 1126 - Random Access Memories 1127 - </a> 1128 - <div 1129 - class="css-8g9w67" 1130 - > 1131 - Daft Punk 1132 - </div> 1133 - <div 1134 - class="css-1q570sn" 1135 - > 1136 - 2013 1172 + <a 1173 + class="css-9sbfuc" 1174 + href="/artists/undefined" 1175 + > 1176 + Daft Punk 1177 + </a> 1178 + <div 1179 + class="css-1q570sn" 1180 + > 1181 + 2013 1182 + </div> 1137 1183 </div> 1138 1184 </div> 1139 1185 <div ··· 1146 1192 class="css-12ezcoy" 1147 1193 > 1148 1194 <div 1149 - class="css-1jrgpod" 1195 + class="css-15yrfky" 1150 1196 > 1151 1197 <div 1152 - style="background-color: rgba(255, 255, 255, 0.737); height: 40px; width: 40px; border-radius: 20px; display: flex; justify-content: center; align-items: center;" 1198 + style="background-color: rgba(255, 255, 255, 0.855); height: 40px; width: 40px; border-radius: 20px; display: flex; justify-content: center; align-items: center;" 1153 1199 > 1154 1200 <svg 1155 1201 fill="none" ··· 1164 1210 /> 1165 1211 </svg> 1166 1212 </div> 1167 - <button 1168 - class="css-10n9a0h" 1213 + <div 1214 + class="css-113iyi7" 1169 1215 > 1170 - <svg 1171 - aria-hidden="true" 1172 - class="StyledIconBase-sc-ea9ulj-0 dmvaRK" 1173 - color="#fff" 1174 - fill="currentColor" 1175 - focusable="false" 1176 - height="24" 1177 - viewBox="0 0 512 512" 1178 - width="24" 1179 - xmlns="http://www.w3.org/2000/svg" 1216 + <button 1217 + class="css-10bvv2v" 1180 1218 > 1181 - <circle 1182 - cx="256" 1183 - cy="256" 1184 - r="48" 1185 - /> 1186 - <circle 1187 - cx="416" 1188 - cy="256" 1189 - r="48" 1190 - /> 1191 - <circle 1192 - cx="96" 1193 - cy="256" 1194 - r="48" 1195 - /> 1196 - </svg> 1197 - </button> 1219 + <div 1220 + aria-expanded="false" 1221 + aria-haspopup="true" 1222 + class="css-10n9a0h" 1223 + > 1224 + <svg 1225 + aria-hidden="true" 1226 + class="StyledIconBase-sc-ea9ulj-0 dmvaRK" 1227 + color="#fff" 1228 + fill="currentColor" 1229 + focusable="false" 1230 + height="24" 1231 + viewBox="0 0 512 512" 1232 + width="24" 1233 + xmlns="http://www.w3.org/2000/svg" 1234 + > 1235 + <circle 1236 + cx="256" 1237 + cy="256" 1238 + r="48" 1239 + /> 1240 + <circle 1241 + cx="416" 1242 + cy="256" 1243 + r="48" 1244 + /> 1245 + <circle 1246 + cx="96" 1247 + cy="256" 1248 + r="48" 1249 + /> 1250 + </svg> 1251 + </div> 1252 + </button> 1253 + </div> 1198 1254 <button 1199 1255 class="css-10n9a0h" 1200 1256 > ··· 1231 1287 </div> 1232 1288 </button> 1233 1289 <a 1290 + class="css-11g9kr1" 1234 1291 href="/albums/2" 1235 1292 > 1236 - <span 1237 - class=" lazy-load-image-background opacity" 1238 - style="color: transparent; display: inline-block;" 1293 + <img 1294 + class="css-1g7adp4" 1295 + src="/src/Assets/albumart.svg" 1296 + /> 1297 + <div 1298 + class="css-e68bk5" 1239 1299 > 1240 - <img 1241 - class="css-1g7adp4" 1242 - src="https://resources.tidal.com/images/866bb671/5ec8/4b45/8a60/50e51f5dbf10/320x320.jpg" 1243 - /> 1244 - </span> 1300 + Tron: Legacy 1301 + </div> 1245 1302 </a> 1246 - </div> 1247 - <a 1248 - class="css-1g6cdnz" 1249 - href="/albums/2" 1250 - > 1251 - Tron: Legacy 1252 - </a> 1253 - <div 1254 - class="css-8g9w67" 1255 - > 1256 - Daft Punk 1257 - </div> 1258 - <div 1259 - class="css-1q570sn" 1260 - > 1261 - 2010 1303 + <a 1304 + class="css-9sbfuc" 1305 + href="/artists/undefined" 1306 + > 1307 + Daft Punk 1308 + </a> 1309 + <div 1310 + class="css-1q570sn" 1311 + > 1312 + 2010 1313 + </div> 1262 1314 </div> 1263 1315 </div> 1264 1316 <div ··· 1271 1323 class="css-12ezcoy" 1272 1324 > 1273 1325 <div 1274 - class="css-1jrgpod" 1326 + class="css-15yrfky" 1275 1327 > 1276 1328 <div 1277 - style="background-color: rgba(255, 255, 255, 0.737); height: 40px; width: 40px; border-radius: 20px; display: flex; justify-content: center; align-items: center;" 1329 + style="background-color: rgba(255, 255, 255, 0.855); height: 40px; width: 40px; border-radius: 20px; display: flex; justify-content: center; align-items: center;" 1278 1330 > 1279 1331 <svg 1280 1332 fill="none" ··· 1289 1341 /> 1290 1342 </svg> 1291 1343 </div> 1292 - <button 1293 - class="css-10n9a0h" 1344 + <div 1345 + class="css-113iyi7" 1294 1346 > 1295 - <svg 1296 - aria-hidden="true" 1297 - class="StyledIconBase-sc-ea9ulj-0 dmvaRK" 1298 - color="#fff" 1299 - fill="currentColor" 1300 - focusable="false" 1301 - height="24" 1302 - viewBox="0 0 512 512" 1303 - width="24" 1304 - xmlns="http://www.w3.org/2000/svg" 1347 + <button 1348 + class="css-10bvv2v" 1305 1349 > 1306 - <circle 1307 - cx="256" 1308 - cy="256" 1309 - r="48" 1310 - /> 1311 - <circle 1312 - cx="416" 1313 - cy="256" 1314 - r="48" 1315 - /> 1316 - <circle 1317 - cx="96" 1318 - cy="256" 1319 - r="48" 1320 - /> 1321 - </svg> 1322 - </button> 1350 + <div 1351 + aria-expanded="false" 1352 + aria-haspopup="true" 1353 + class="css-10n9a0h" 1354 + > 1355 + <svg 1356 + aria-hidden="true" 1357 + class="StyledIconBase-sc-ea9ulj-0 dmvaRK" 1358 + color="#fff" 1359 + fill="currentColor" 1360 + focusable="false" 1361 + height="24" 1362 + viewBox="0 0 512 512" 1363 + width="24" 1364 + xmlns="http://www.w3.org/2000/svg" 1365 + > 1366 + <circle 1367 + cx="256" 1368 + cy="256" 1369 + r="48" 1370 + /> 1371 + <circle 1372 + cx="416" 1373 + cy="256" 1374 + r="48" 1375 + /> 1376 + <circle 1377 + cx="96" 1378 + cy="256" 1379 + r="48" 1380 + /> 1381 + </svg> 1382 + </div> 1383 + </button> 1384 + </div> 1323 1385 <button 1324 1386 class="css-10n9a0h" 1325 1387 > ··· 1356 1418 </div> 1357 1419 </button> 1358 1420 <a 1421 + class="css-11g9kr1" 1359 1422 href="/albums/3" 1360 1423 > 1361 - <span 1362 - class=" lazy-load-image-background opacity" 1363 - style="color: transparent; display: inline-block;" 1424 + <img 1425 + class="css-1g7adp4" 1426 + src="/src/Assets/albumart.svg" 1427 + /> 1428 + <div 1429 + class="css-e68bk5" 1364 1430 > 1365 - <img 1366 - class="css-1g7adp4" 1367 - src="https://resources.tidal.com/images/f853861c/0c5f/4e73/b608/eeb00618fe6f/320x320.jpg" 1368 - /> 1369 - </span> 1431 + Homework 1432 + </div> 1433 + </a> 1434 + <a 1435 + class="css-9sbfuc" 1436 + href="/artists/undefined" 1437 + > 1438 + Daft Punk 1370 1439 </a> 1371 - </div> 1372 - <a 1373 - class="css-1g6cdnz" 1374 - href="/albums/3" 1375 - > 1376 - Homework 1377 - </a> 1378 - <div 1379 - class="css-8g9w67" 1380 - > 1381 - Daft Punk 1382 - </div> 1383 - <div 1384 - class="css-1q570sn" 1385 - > 1386 - 2001 1440 + <div 1441 + class="css-1q570sn" 1442 + > 1443 + 2001 1444 + </div> 1387 1445 </div> 1388 1446 </div> 1389 1447 </div>
+40
webui/rockbox/src/Components/Artists/__snapshots__/Artists.test.tsx.snap
··· 95 95 <a 96 96 class="css-tujm8o" 97 97 color="initial" 98 + href="/likes" 99 + > 100 + <svg 101 + fill="none" 102 + height="20" 103 + style="padding-top: 1px;" 104 + width="20" 105 + xmlns="http://www.w3.org/2000/svg" 106 + > 107 + <g 108 + class="ionicon" 109 + style="fill: initial;" 110 + > 111 + <path 112 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 113 + fill="none" 114 + stroke="currentColor" 115 + stroke-linecap="round" 116 + stroke-linejoin="round" 117 + style="fill: none;" 118 + /> 119 + <path 120 + class="stroke-shape" 121 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 122 + stroke="currentColor" 123 + stroke-linecap="round" 124 + stroke-linejoin="round" 125 + style="fill: none; stroke-width: 2; stroke: initial; stroke-opacity: 1;" 126 + /> 127 + </g> 128 + </svg> 129 + <div 130 + style="margin-left: 6px;" 131 + > 132 + Likes 133 + </div> 134 + </a> 135 + <a 136 + class="css-tujm8o" 137 + color="initial" 98 138 href="/files" 99 139 > 100 140 <svg
+40
webui/rockbox/src/Components/Files/__snapshots__/Files.test.tsx.snap
··· 93 93 </div> 94 94 </a> 95 95 <a 96 + class="css-tujm8o" 97 + color="initial" 98 + href="/likes" 99 + > 100 + <svg 101 + fill="none" 102 + height="20" 103 + style="padding-top: 1px;" 104 + width="20" 105 + xmlns="http://www.w3.org/2000/svg" 106 + > 107 + <g 108 + class="ionicon" 109 + style="fill: initial;" 110 + > 111 + <path 112 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 113 + fill="none" 114 + stroke="currentColor" 115 + stroke-linecap="round" 116 + stroke-linejoin="round" 117 + style="fill: none;" 118 + /> 119 + <path 120 + class="stroke-shape" 121 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 122 + stroke="currentColor" 123 + stroke-linecap="round" 124 + stroke-linejoin="round" 125 + style="fill: none; stroke-width: 2; stroke: initial; stroke-opacity: 1;" 126 + /> 127 + </g> 128 + </svg> 129 + <div 130 + style="margin-left: 6px;" 131 + > 132 + Likes 133 + </div> 134 + </a> 135 + <a 96 136 class="css-8v05qj" 97 137 color="#fe099c" 98 138 href="/files"
+22
webui/rockbox/src/Components/Likes/Likes.tsx
··· 1 + /* eslint-disable @typescript-eslint/no-explicit-any */ 2 + import { FC } from "react"; 3 + import Sidebar from "../Sidebar"; 4 + import ControlBar from "../ControlBar"; 5 + import { Container, ContentWrapper, Title } from "./styles"; 6 + import MainView from "../MainView"; 7 + 8 + const Likes: FC = () => { 9 + return ( 10 + <Container> 11 + <Sidebar active="likes" /> 12 + <MainView> 13 + <ControlBar /> 14 + <ContentWrapper> 15 + <Title>Likes</Title> 16 + </ContentWrapper> 17 + </MainView> 18 + </Container> 19 + ); 20 + }; 21 + 22 + export default Likes;
+8
webui/rockbox/src/Components/Likes/LikesWithData.tsx
··· 1 + import { FC } from "react"; 2 + import Likes from "./Likes"; 3 + 4 + const LikesWithData: FC = () => { 5 + return <Likes />; 6 + }; 7 + 8 + export default LikesWithData;
+3
webui/rockbox/src/Components/Likes/index.tsx
··· 1 + import Likes from "./LikesWithData"; 2 + 3 + export default Likes;
+108
webui/rockbox/src/Components/Likes/styles.tsx
··· 1 + import styled from "@emotion/styled"; 2 + import { Link } from "react-router-dom"; 3 + 4 + export const Container = styled.div` 5 + display: flex; 6 + flex-direction: row; 7 + width: 100%; 8 + height: 100%; 9 + `; 10 + 11 + export const Title = styled.div` 12 + font-size: 24px; 13 + font-family: RockfordSansMedium; 14 + margin-bottom: 20px; 15 + `; 16 + 17 + export const IconButton = styled.button` 18 + background-color: transparent; 19 + cursor: pointer; 20 + border: none; 21 + display: flex; 22 + align-items: center; 23 + justify-content: center; 24 + &:hover { 25 + opacity: 0.6; 26 + } 27 + `; 28 + 29 + export const Hover = styled.button` 30 + color: transparent; 31 + background-color: transparent; 32 + border: none; 33 + opacity: 1 !important; 34 + cursor: pointer; 35 + &:hover, 36 + &:focus { 37 + color: #000; 38 + opacity: 1 !important; 39 + } 40 + `; 41 + 42 + export const ButtonGroup = styled.div` 43 + display: flex; 44 + flex-direction: row; 45 + align-items: center; 46 + `; 47 + 48 + export const ContentWrapper = styled.div` 49 + overflow-y: auto; 50 + height: calc(100vh - 100px); 51 + padding-left: 20px; 52 + padding-right: 20px; 53 + `; 54 + 55 + export const AlbumCover = styled.img` 56 + height: 48px; 57 + width: 48px; 58 + `; 59 + 60 + export const Directory = styled(Link)` 61 + color: #000; 62 + margin-left: 10px; 63 + text-decoration: none; 64 + font-family: RockfordSansRegular; 65 + width: calc(100vw - 500px); 66 + max-width: calc(100vw - 500px); 67 + text-overflow: ellipsis; 68 + overflow: hidden; 69 + white-space: nowrap; 70 + display: block; 71 + &:hover { 72 + text-decoration: underline; 73 + } 74 + `; 75 + 76 + export const AudioFile = styled.div` 77 + color: #000; 78 + margin-left: 10px; 79 + text-decoration: none; 80 + font-family: RockfordSansRegular; 81 + width: calc(100vw - 500px); 82 + max-width: calc(100vw - 500px); 83 + text-overflow: ellipsis; 84 + overflow: hidden; 85 + white-space: nowrap; 86 + display: block; 87 + cursor: pointer; 88 + &:hover { 89 + text-decoration: underline; 90 + } 91 + `; 92 + 93 + export const BackButton = styled.button` 94 + border: none; 95 + cursor: pointer; 96 + display: flex; 97 + align-items: center; 98 + justify-content: center; 99 + height: 30px; 100 + width: 30px; 101 + left: 20px; 102 + border-radius: 15px; 103 + background-color: #f7f7f8; 104 + margin-top: 45px; 105 + margin-bottom: 46px; 106 + position: absolute; 107 + z-index: 1; 108 + `;
+9
webui/rockbox/src/Components/Sidebar/Sidebar.tsx
··· 5 5 import Artist from "../Icons/Artist"; 6 6 import Track from "../Icons/Track"; 7 7 import RockboxLogo from "../../Assets/rockbox-icon.svg"; 8 + import HeartOutline from "../Icons/HeartOutline"; 8 9 9 10 export type SidebarProps = { 10 11 active: string; ··· 46 47 <MenuItem color={active === "songs" ? "#fe099c" : "initial"} to="/tracks"> 47 48 <Track height={20} color={active === "songs" ? "#fe099c" : "initial"} /> 48 49 <div style={{ marginLeft: 6 }}>Songs</div> 50 + </MenuItem> 51 + <MenuItem color={active === "likes" ? "#fe099c" : "initial"} to="/likes"> 52 + <HeartOutline 53 + height={20} 54 + width={20} 55 + color={active === "likes" ? "#fe099c" : "initial"} 56 + /> 57 + <div style={{ marginLeft: 6 }}>Likes</div> 49 58 </MenuItem> 50 59 <MenuItem color={active === "files" ? "#fe099c" : "initial"} to="/files"> 51 60 <HardDrive
+40
webui/rockbox/src/Components/Sidebar/__snapshots__/Sidebar.test.tsx.snap
··· 92 92 <a 93 93 class="css-tujm8o" 94 94 color="initial" 95 + href="/likes" 96 + > 97 + <svg 98 + fill="none" 99 + height="20" 100 + style="padding-top: 1px;" 101 + width="20" 102 + xmlns="http://www.w3.org/2000/svg" 103 + > 104 + <g 105 + class="ionicon" 106 + style="fill: initial;" 107 + > 108 + <path 109 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 110 + fill="none" 111 + stroke="currentColor" 112 + stroke-linecap="round" 113 + stroke-linejoin="round" 114 + style="fill: none;" 115 + /> 116 + <path 117 + class="stroke-shape" 118 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 119 + stroke="currentColor" 120 + stroke-linecap="round" 121 + stroke-linejoin="round" 122 + style="fill: none; stroke-width: 2; stroke: initial; stroke-opacity: 1;" 123 + /> 124 + </g> 125 + </svg> 126 + <div 127 + style="margin-left: 6px;" 128 + > 129 + Likes 130 + </div> 131 + </a> 132 + <a 133 + class="css-tujm8o" 134 + color="initial" 95 135 href="/files" 96 136 > 97 137 <svg
+40
webui/rockbox/src/Components/Tracks/__snapshots__/Tracks.test.tsx.snap
··· 95 95 <a 96 96 class="css-tujm8o" 97 97 color="initial" 98 + href="/likes" 99 + > 100 + <svg 101 + fill="none" 102 + height="20" 103 + style="padding-top: 1px;" 104 + width="20" 105 + xmlns="http://www.w3.org/2000/svg" 106 + > 107 + <g 108 + class="ionicon" 109 + style="fill: initial;" 110 + > 111 + <path 112 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 113 + fill="none" 114 + stroke="currentColor" 115 + stroke-linecap="round" 116 + stroke-linejoin="round" 117 + style="fill: none;" 118 + /> 119 + <path 120 + class="stroke-shape" 121 + d="M13.534 4C11.167 4 10 6.364 10 6.364S8.833 4 6.466 4C4.543 4 3.02 5.63 3 7.575c-.04 4.038 3.162 6.91 6.672 9.323a.578.578 0 0 0 .656 0c3.51-2.413 6.712-5.285 6.672-9.323C16.98 5.63 15.457 4 13.534 4Z" 122 + stroke="currentColor" 123 + stroke-linecap="round" 124 + stroke-linejoin="round" 125 + style="fill: none; stroke-width: 2; stroke: initial; stroke-opacity: 1;" 126 + /> 127 + </g> 128 + </svg> 129 + <div 130 + style="margin-left: 6px;" 131 + > 132 + Likes 133 + </div> 134 + </a> 135 + <a 136 + class="css-tujm8o" 137 + color="initial" 98 138 href="/files" 99 139 > 100 140 <svg
+8
webui/rockbox/src/Containers/Likes/LikesPage.tsx
··· 1 + import { FC } from "react"; 2 + import Likes from "../../Components/Likes"; 3 + 4 + const LikesPage: FC = () => { 5 + return <Likes />; 6 + }; 7 + 8 + export default LikesPage;
+3
webui/rockbox/src/Containers/Likes/index.tsx
··· 1 + import Likes from "./LikesPage"; 2 + 3 + export default Likes;