Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"bracketSpacing": false,
"printWidth": 100,
"proseWrap": "never",
"requirePragma": false,
"trailingComma": "all",
"useTabs": true,
"endOfLine": "auto",
"overrides": [
{
"files": [
".prettierrc",
"*.json"
],
"options": {
"printWidth": 200,
"tabWidth": 2
}
}
]
}
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ This is a starter template for [Learn Next.js](https://nextjs.org/learn).

This is a project for learning, attempt is to create a light version of Spotify

# TODO

- bottom bar could be a single area instead of being divided into 3, similar as Spotify's
- warning in console about classes being created should be fixed
- error thrown in the animated playback svg

# Music Copyright

ACTION by Alex-Productions | https://onsound.eu/
Expand Down
197 changes: 91 additions & 106 deletions components/IconButtons/IconButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,126 +1,111 @@
import styled from "styled-components";

const StyledButton = styled.button`
border: none;
background: none;
display: flex;
justify-content: center;
align-items: center;
border: none;
background: none;
display: flex;
justify-content: center;
align-items: center;

svg:hover {
fill: white;
}
svg:hover {
fill: white;
}

svg {
fill: var(--diminished-text-color);
}
svg {
fill: var(--diminished-text-color);
}
`;

export const ClockButton = ({ onClick }: { onClick?: VoidFunction }) => {
return (
<StyledButton onClick={onClick}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="18px"
viewBox="0 -960 960 960"
width="18px"
>
<path d="m612-292 56-56-148-148v-184h-80v216l172 172ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 320q133 0 226.5-93.5T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160Z" />
</svg>
</StyledButton>
);
export const ClockButton = ({onClick}: {onClick?: VoidFunction}) => {
return (
<StyledButton onClick={onClick}>
<svg xmlns="http://www.w3.org/2000/svg" height="18px" viewBox="0 -960 960 960" width="18px">
<path d="m612-292 56-56-148-148v-184h-80v216l172 172ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 320q133 0 226.5-93.5T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160Z" />
</svg>
</StyledButton>
);
};

export const SkipNextButton = ({ onClick }: { onClick?: VoidFunction }) => {
return (
<StyledButton onClick={onClick}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 -960 960 960"
width="24px"
>
<path d="M660-240v-480h80v480h-80Zm-440 0v-480l360 240-360 240Zm80-240Zm0 90 136-90-136-90v180Z" />
</svg>
</StyledButton>
);
export const SkipNextButton = ({onClick}: {onClick?: VoidFunction}) => {
return (
<StyledButton onClick={onClick}>
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px">
<path d="M660-240v-480h80v480h-80Zm-440 0v-480l360 240-360 240Zm80-240Zm0 90 136-90-136-90v180Z" />
</svg>
</StyledButton>
);
};

export const SkipPreviousButton = ({ onClick }: { onClick?: VoidFunction }) => {
return (
<StyledButton onClick={onClick}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 -960 960 960"
width="24px"
>
<path d="M220-240v-480h80v480h-80Zm520 0L380-480l360-240v480Zm-80-240Zm0 90v-180l-136 90 136 90Z" />
</svg>
</StyledButton>
);
export const SkipPreviousButton = ({onClick}: {onClick?: VoidFunction}) => {
return (
<StyledButton onClick={onClick}>
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px">
<path d="M220-240v-480h80v480h-80Zm520 0L380-480l360-240v480Zm-80-240Zm0 90v-180l-136 90 136 90Z" />
</svg>
</StyledButton>
);
};

export const PlayButton = ({ onClick }: { onClick?: VoidFunction }) => {
return (
<StyledButton onClick={onClick}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 -960 960 960"
width="24px"
fill="var(--text-on-main-bg)"
>
<path d="M320-200v-560l440 280-440 280Zm80-280Zm0 134 210-134-210-134v268Z" />
</svg>
</StyledButton>
);
export const PlayButton = ({onClick}: {onClick?: VoidFunction}) => {
return (
<StyledButton onClick={onClick}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 -960 960 960"
width="24px"
fill="var(--text-on-main-bg)"
>
<path d="M320-200v-560l440 280-440 280Zm80-280Zm0 134 210-134-210-134v268Z" />
</svg>
</StyledButton>
);
};

export const PauseButton = ({ onClick }: { onClick?: VoidFunction }) => {
return (
<StyledButton onClick={onClick}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 -960 960 960"
width="24px"
fill="var(--text-on-main-bg)"
>
<path d="M520-200v-560h240v560H520Zm-320 0v-560h240v560H200Zm400-80h80v-400h-80v400Zm-320 0h80v-400h-80v400Zm0-400v400-400Zm320 0v400-400Z" />
</svg>
</StyledButton>
);
export const PauseButton = ({onClick}: {onClick?: VoidFunction}) => {
return (
<StyledButton onClick={onClick}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 -960 960 960"
width="24px"
fill="var(--text-on-main-bg)"
>
<path d="M520-200v-560h240v560H520Zm-320 0v-560h240v560H200Zm400-80h80v-400h-80v400Zm-320 0h80v-400h-80v400Zm0-400v400-400Zm320 0v400-400Z" />
</svg>
</StyledButton>
);
};

export const VolumeDownButton = ({ onClick }: { onClick?: VoidFunction }) => {
return (
<StyledButton onClick={onClick}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 -960 960 960"
width="24px"
fill="#5f6368"
>
<path d="M200-360v-240h160l200-200v640L360-360H200Zm440 40v-322q45 21 72.5 65t27.5 97q0 53-27.5 96T640-320ZM480-606l-86 86H280v80h114l86 86v-252ZM380-480Z" />
</svg>
</StyledButton>
);
export const VolumeDownButton = ({onClick}: {onClick?: VoidFunction}) => {
return (
<StyledButton onClick={onClick}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 -960 960 960"
width="24px"
fill="#5f6368"
>
<path d="M200-360v-240h160l200-200v640L360-360H200Zm440 40v-322q45 21 72.5 65t27.5 97q0 53-27.5 96T640-320ZM480-606l-86 86H280v80h114l86 86v-252ZM380-480Z" />
</svg>
</StyledButton>
);
};

export const MutedButton = ({ onClick }: { onClick?: VoidFunction }) => {
return (
<StyledButton onClick={onClick}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 -960 960 960"
width="24px"
fill="#5f6368"
>
<path d="M792-56 671-177q-25 16-53 27.5T560-131v-82q14-5 27.5-10t25.5-12L480-368v208L280-360H120v-240h128L56-792l56-56 736 736-56 56Zm-8-232-58-58q17-31 25.5-65t8.5-70q0-94-55-168T560-749v-82q124 28 202 125.5T840-481q0 53-14.5 102T784-288ZM650-422l-90-90v-130q47 22 73.5 66t26.5 96q0 15-2.5 29.5T650-422ZM480-592 376-696l104-104v208Zm-80 238v-94l-72-72H200v80h114l86 86Zm-36-130Z" />
</svg>
</StyledButton>
);
export const MutedButton = ({onClick}: {onClick?: VoidFunction}) => {
return (
<StyledButton onClick={onClick}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 -960 960 960"
width="24px"
fill="#5f6368"
>
<path d="M792-56 671-177q-25 16-53 27.5T560-131v-82q14-5 27.5-10t25.5-12L480-368v208L280-360H120v-240h128L56-792l56-56 736 736-56 56Zm-8-232-58-58q17-31 25.5-65t8.5-70q0-94-55-168T560-749v-82q124 28 202 125.5T840-481q0 53-14.5 102T784-288ZM650-422l-90-90v-130q47 22 73.5 66t26.5 96q0 15-2.5 29.5T650-422ZM480-592 376-696l104-104v208Zm-80 238v-94l-72-72H200v80h114l86 86Zm-36-130Z" />
</svg>
</StyledButton>
);
};
10 changes: 5 additions & 5 deletions components/Library.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import styles from "./library.module.css";

export const Library = () => {
return (
<div className={`${styles.libraryContainer} card`}>
<p>Your library</p>
</div>
);
return (
<div className={`${styles.libraryContainer} card`}>
<p>Your library</p>
</div>
);
};
105 changes: 44 additions & 61 deletions components/PlaybackControls.tsx
Original file line number Diff line number Diff line change
@@ -1,77 +1,60 @@
import styled from "styled-components";
import styles from "./playbackControls.module.css";
import { ProgressBar } from "./ProgressBar";
import { SkipNextButton, SkipPreviousButton } from "./IconButtons/IconButtons";
import {ProgressBar} from "./ProgressBar";
import {SkipNextButton, SkipPreviousButton} from "./IconButtons/IconButtons";

const StyledButton = styled.button<{ $bgColor?: string }>`
background-color: ${(props) => (props.$bgColor ? props.$bgColor : "white")};
border-radius: 50%;
width: 40px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
border: none;
const StyledButton = styled.button<{$bgColor?: string}>`
background-color: ${(props) => (props.$bgColor ? props.$bgColor : "white")};
border-radius: 50%;
width: 40px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
border: none;
`;

const StyledPlayPauseButton = styled(StyledButton)`
&:hover {
transform: scale(1.05);
}
&:hover {
transform: scale(1.05);
}
`;

const PlayPauseButton = ({
isPaused,
onClick,
}: {
isPaused: boolean;
onClick: () => void;
}) => {
return (
<StyledPlayPauseButton onClick={onClick}>
{isPaused ? (
<img src="/play_arrow_24dp.svg" />
) : (
<img src="/pause_24dp.svg" />
)}
</StyledPlayPauseButton>
);
const PlayPauseButton = ({isPaused, onClick}: {isPaused: boolean; onClick: () => void}) => {
return (
<StyledPlayPauseButton onClick={onClick}>
{isPaused ? <img src="/play_arrow_24dp.svg" /> : <img src="/pause_24dp.svg" />}
</StyledPlayPauseButton>
);
};

export const PlaybackControls = ({
pausePlayOnclick,
totalPlaybackDuration,
currentPlaybackTime,
isPlaybackPaused,
onSeek,
pausePlayOnclick,
totalPlaybackDuration,
currentPlaybackTime,
isPlaybackPaused,
onSeek,
}: {
pausePlayOnclick: () => void;
totalPlaybackDuration: React.ComponentProps<
typeof ProgressBar
>["totalPlaybackDuration"];
currentPlaybackTime: React.ComponentProps<
typeof ProgressBar
>["currentPlaybackTime"];
onSeek: React.ComponentProps<typeof ProgressBar>["onSeek"];
isPlaybackPaused: boolean;
pausePlayOnclick: () => void;
totalPlaybackDuration: React.ComponentProps<typeof ProgressBar>["totalPlaybackDuration"];
currentPlaybackTime: React.ComponentProps<typeof ProgressBar>["currentPlaybackTime"];
onSeek: React.ComponentProps<typeof ProgressBar>["onSeek"];
isPlaybackPaused: boolean;
}) => {
return (
<div className={styles.playbackControls}>
<div id="button-container" className={styles.buttonContainer}>
<SkipPreviousButton />
return (
<div className={styles.playbackControls}>
<div id="button-container" className={styles.buttonContainer}>
<SkipPreviousButton />

<PlayPauseButton
onClick={pausePlayOnclick}
isPaused={isPlaybackPaused}
/>
<PlayPauseButton onClick={pausePlayOnclick} isPaused={isPlaybackPaused} />

<SkipNextButton />
</div>
<ProgressBar
currentPlaybackTime={currentPlaybackTime}
totalPlaybackDuration={totalPlaybackDuration}
onSeek={onSeek}
/>
</div>
);
<SkipNextButton />
</div>
<ProgressBar
currentPlaybackTime={currentPlaybackTime}
totalPlaybackDuration={totalPlaybackDuration}
onSeek={onSeek}
/>
</div>
);
};
Loading