mirror of
https://github.com/remvze/moodist.git
synced 2025-12-17 00:44:14 +00:00
feat: add lofi music play
This commit is contained in:
parent
af096077ae
commit
fcbe50c78c
8 changed files with 246 additions and 0 deletions
56
package-lock.json
generated
56
package-lock.json
generated
|
|
@ -30,6 +30,7 @@
|
|||
"react-hotkeys-hook": "3.2.1",
|
||||
"react-icons": "4.11.0",
|
||||
"react-wrap-balancer": "1.1.0",
|
||||
"react-youtube": "10.1.0",
|
||||
"uuid": "10.0.0",
|
||||
"zustand": "4.4.3"
|
||||
},
|
||||
|
|
@ -19285,6 +19286,12 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/load-script": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz",
|
||||
"integrity": "sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/load-yaml-file": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz",
|
||||
|
|
@ -22343,6 +22350,23 @@
|
|||
"react": ">=16.8.0 || ^17.0.0 || ^18"
|
||||
}
|
||||
},
|
||||
"node_modules/react-youtube": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-10.1.0.tgz",
|
||||
"integrity": "sha512-ZfGtcVpk0SSZtWCSTYOQKhfx5/1cfyEW1JN/mugGNfAxT3rmVJeMbGpA9+e78yG21ls5nc/5uZJETE3cm3knBg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"prop-types": "15.8.1",
|
||||
"youtube-player": "5.5.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.x"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=0.14.1"
|
||||
}
|
||||
},
|
||||
"node_modules/read-pkg": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz",
|
||||
|
|
@ -23844,6 +23868,12 @@
|
|||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/sister": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/sister/-/sister-3.0.2.tgz",
|
||||
"integrity": "sha512-p19rtTs+NksBRKW9qn0UhZ8/TUI9BPw9lmtHny+Y3TinWlOa9jWh9xB0AtPSdmOy49NJJJSSe0Ey4C7h0TrcYA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/sisteransi": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
|
|
@ -27593,6 +27623,32 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/youtube-player": {
|
||||
"version": "5.5.2",
|
||||
"resolved": "https://registry.npmjs.org/youtube-player/-/youtube-player-5.5.2.tgz",
|
||||
"integrity": "sha512-ZGtsemSpXnDky2AUYWgxjaopgB+shFHgXVpiJFeNB5nWEugpW1KWYDaHKuLqh2b67r24GtP6HoSW5swvf0fFIQ==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"debug": "^2.6.6",
|
||||
"load-script": "^1.0.0",
|
||||
"sister": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/youtube-player/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/youtube-player/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.23.8",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
"react-hotkeys-hook": "3.2.1",
|
||||
"react-icons": "4.11.0",
|
||||
"react-wrap-balancer": "1.1.0",
|
||||
"react-youtube": "10.1.0",
|
||||
"uuid": "10.0.0",
|
||||
"zustand": "4.4.3"
|
||||
},
|
||||
|
|
|
|||
1
src/components/modals/lofi/index.ts
Normal file
1
src/components/modals/lofi/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { LofiModal } from './lofi';
|
||||
86
src/components/modals/lofi/lofi.module.css
Normal file
86
src/components/modals/lofi/lofi.module.css
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
.title {
|
||||
margin-bottom: 12px;
|
||||
font-family: var(--font-heading);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.notice {
|
||||
& p {
|
||||
line-height: 1.4;
|
||||
color: var(--color-foreground-subtle);
|
||||
}
|
||||
|
||||
& .buttons {
|
||||
display: flex;
|
||||
column-gap: 8px;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-top: 12px;
|
||||
|
||||
& button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 40px;
|
||||
padding: 0 16px;
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground);
|
||||
cursor: pointer;
|
||||
background: var(--color-neutral-200);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
|
||||
&.primary {
|
||||
color: var(--color-neutral-50);
|
||||
background: var(--color-neutral-950);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.videos {
|
||||
margin-top: 20px;
|
||||
|
||||
& .video {
|
||||
&:not(:last-of-type) {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
& h2 {
|
||||
margin-bottom: 8px;
|
||||
font-size: var(--font-sm);
|
||||
color: var(--color-foreground-subtle);
|
||||
|
||||
& span {
|
||||
display: inline-block;
|
||||
color: var(--color-foreground-subtler);
|
||||
|
||||
&.index {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
& strong {
|
||||
font-weight: 500;
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
& .container {
|
||||
padding: 8px;
|
||||
background-color: var(--color-neutral-50);
|
||||
border: 1px solid var(--color-neutral-300);
|
||||
border-radius: 12px;
|
||||
|
||||
& .iframe {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
aspect-ratio: 560 / 315;
|
||||
border: 1px solid var(--color-neutral-200);
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
src/components/modals/lofi/lofi.tsx
Normal file
85
src/components/modals/lofi/lofi.tsx
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import { useState } from 'react';
|
||||
import YouTube from 'react-youtube';
|
||||
|
||||
import { Modal } from '@/components/modal/modal';
|
||||
|
||||
import styles from './lofi.module.css';
|
||||
import { padNumber } from '@/helpers/number';
|
||||
|
||||
interface LofiProps {
|
||||
onClose: () => void;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
const videos = [
|
||||
{
|
||||
channel: 'Lofi Girl',
|
||||
id: 'jfKfPfyJRdk',
|
||||
title: 'lofi hip hop radio',
|
||||
},
|
||||
{
|
||||
channel: 'Lofi Girl',
|
||||
id: '4xDzrJKXOOY',
|
||||
title: 'synthwave radio',
|
||||
},
|
||||
{
|
||||
channel: 'Lofi Girl',
|
||||
id: 'P6Segk8cr-c',
|
||||
title: 'sad lofi radio',
|
||||
},
|
||||
{
|
||||
channel: 'Lofi Girl',
|
||||
id: 'S_MOd40zlYU',
|
||||
title: 'dark ambient radio',
|
||||
},
|
||||
{
|
||||
channel: 'Lofi Girl',
|
||||
id: 'TtkFsfOP9QI',
|
||||
title: 'peaceful piano radio',
|
||||
},
|
||||
];
|
||||
|
||||
export function LofiModal({ onClose, show }: LofiProps) {
|
||||
const [isAccepted, setIsAccepted] = useState(false);
|
||||
|
||||
return (
|
||||
<Modal persist show={show} onClose={onClose}>
|
||||
<h1 className={styles.title}>Lofi Music Player</h1>
|
||||
|
||||
{!isAccepted ? (
|
||||
<div className={styles.notice}>
|
||||
<p>
|
||||
This feature plays music using embedded YouTube videos. By
|
||||
continuing, you agree to connect to YouTube, which may collect data
|
||||
in accordance with their privacy policy. We do not control or track
|
||||
this data.
|
||||
</p>
|
||||
|
||||
<div className={styles.buttons}>
|
||||
<button onClick={onClose}>Cancel</button>
|
||||
<button
|
||||
className={styles.primary}
|
||||
onClick={() => setIsAccepted(true)}
|
||||
>
|
||||
Continue
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.videos}>
|
||||
{videos.map((video, index) => (
|
||||
<div className={styles.video} key={video.id}>
|
||||
<h2>
|
||||
<span className={styles.index}>{padNumber(index + 1, 2)}</span>{' '}
|
||||
<strong>{video.channel}</strong> <span>/</span> {video.title}
|
||||
</h2>
|
||||
<div className={styles.container}>
|
||||
<YouTube iframeClassName={styles.iframe} videoId={video.id} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
@ -12,3 +12,4 @@ export { Todo as TodoItem } from './todo';
|
|||
export { Countdown as CountdownItem } from './countdown';
|
||||
export { Binaural as BinauralItem } from './binaural';
|
||||
export { Isochronic as IsochronicItem } from './isochronic';
|
||||
export { Lofi as LofiItem } from './lofi';
|
||||
|
|
|
|||
11
src/components/toolbar/menu/items/lofi.tsx
Normal file
11
src/components/toolbar/menu/items/lofi.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { FaHeadphonesAlt } from 'react-icons/fa/index';
|
||||
|
||||
import { Item } from '../item';
|
||||
|
||||
interface LofiProps {
|
||||
open: () => void;
|
||||
}
|
||||
|
||||
export function Lofi({ open }: LofiProps) {
|
||||
return <Item icon={<FaHeadphonesAlt />} label="Lofi Music" onClick={open} />;
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ import {
|
|||
CountdownItem,
|
||||
BinauralItem,
|
||||
IsochronicItem,
|
||||
LofiItem,
|
||||
} from './items';
|
||||
import { Divider } from './divider';
|
||||
import { ShareLinkModal } from '@/components/modals/share-link';
|
||||
|
|
@ -28,6 +29,7 @@ import { SleepTimerModal } from '@/components/modals/sleep-timer';
|
|||
import { BreathingExerciseModal } from '@/components/modals/breathing';
|
||||
import { BinauralModal } from '@/components/modals/binaural';
|
||||
import { IsochronicModal } from '@/components/modals/isochronic';
|
||||
import { LofiModal } from '@/components/modals/lofi';
|
||||
import { Pomodoro, Notepad, Todo, Countdown } from '@/components/toolbox';
|
||||
import { Slider } from '@/components/slider';
|
||||
|
||||
|
|
@ -51,6 +53,7 @@ export function Menu() {
|
|||
breathing: false,
|
||||
countdown: false,
|
||||
isochronic: false,
|
||||
lofi: false,
|
||||
notepad: false,
|
||||
pomodoro: false,
|
||||
presets: false,
|
||||
|
|
@ -137,6 +140,7 @@ export function Menu() {
|
|||
<Divider />
|
||||
<BinauralItem open={() => open('binaural')} />
|
||||
<IsochronicItem open={() => open('isochronic')} />
|
||||
<LofiItem open={() => open('lofi')} />
|
||||
|
||||
<Divider />
|
||||
<ShortcutsItem open={() => open('shortcuts')} />
|
||||
|
|
@ -193,6 +197,7 @@ export function Menu() {
|
|||
show={modals.isochronic}
|
||||
onClose={() => close('isochronic')}
|
||||
/>
|
||||
<LofiModal show={modals.lofi} onClose={() => close('lofi')} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue