Skip to content

Commit

Permalink
Refactor music player and add volume controls
Browse files Browse the repository at this point in the history
  • Loading branch information
0xi4o committed Aug 26, 2024
1 parent 118e731 commit 29e7b05
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 61 deletions.
61 changes: 7 additions & 54 deletions app/components/common/editor.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Suspense, useContext, useEffect, useRef, useState } from 'react'
import ReactPlayer from 'react-player'

import { BubbleMenu } from '@tiptap/extension-bubble-menu'
import { CharacterCount } from '@tiptap/extension-character-count'
Expand All @@ -19,7 +18,6 @@ import {
} from '@tiptap/react'
import { StarterKit } from '@tiptap/starter-kit'
import { common, createLowlight } from 'lowlight'
import { PauseIcon, PlayIcon } from 'lucide-react'
import PreferencesDialog from '~/components/common/preferences-dialog'
import {
E2EEIndicator,
Expand All @@ -33,16 +31,14 @@ import {
Writer,
WritingSessionTimer,
} from '~/components/editor'
import { Button } from '~/components/ui/button'
import MusicPlayer from '~/components/editor/music-player'
import { ScrollArea } from '~/components/ui/scroll-area'
import { MUSIC_STATIONS } from '~/lib/constants'
import { useAutoSave, useKeyboardShortcuts } from '~/lib/hooks'
import { AureliusContext, AureliusProviderData } from '~/lib/providers/aurelius'
import {
EditorData,
EditorShortcuts,
EditorToolbarMode,
MusicChannels,
WritingSessionStatus,
} from '~/lib/types'

Expand Down Expand Up @@ -267,55 +263,12 @@ const Editor = ({
</section>
<section className='w-screen fixed bottom-0 left-0 grid grid-cols-2 z-10'>
{!!settings?.enableMusicPlayer ? (
<div
className={`p-4 flex items-center transition-opacity duration-100 hover:opacity-100 ${focusMode ? 'opacity-5' : 'opacity-100'}`}
>
{isMusicPlaying ? (
<Button
className='w-9 h-9'
onClick={() => setIsMusicPlaying?.(false)}
size='icon'
variant='outline'
>
<PauseIcon className='w-4 h-4' />
</Button>
) : (
<Button
className='w-9 h-9'
onClick={() => setIsMusicPlaying?.(true)}
size='icon'
variant='outline'
>
<PlayIcon className='w-4 h-4' />
</Button>
)}
<Suspense fallback={<div>Loading...</div>}>
<ReactPlayer
playing={isMusicPlaying}
// @ts-ignore
url={
settings?.youtubeLink ||
MUSIC_STATIONS[
settings?.musicChannel as MusicChannels
]
}
width='0'
height='0'
loop={true}
config={{
youtube: {
playerVars: {
control: 1,
start: 1,
},
},
}}
/>
</Suspense>
</div>
) : (
<div />
)}
<MusicPlayer
focusMode={focusMode}
isMusicPlaying={isMusicPlaying}
setIsMusicPlaying={setIsMusicPlaying}
/>
) : null}
<div
className={`flex items-center justify-end p-4 gap-4 transition-opacity duration-100 hover:opacity-100 ${focusMode ? 'opacity-5' : 'opacity-100'}`}
>
Expand Down
112 changes: 112 additions & 0 deletions app/components/editor/music-player.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { Suspense, useContext, useState } from 'react'
import ReactPlayer from 'react-player'

import {
PauseIcon,
PlayIcon,
Volume1Icon,
Volume2Icon,
VolumeXIcon,
} from 'lucide-react'
import { Button } from '~/components/ui/button'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '~/components/ui/popover'
import { Separator } from '~/components/ui/separator'
import { Slider } from '~/components/ui/slider'
import { MUSIC_STATIONS } from '~/lib/constants'
import { AureliusContext, AureliusProviderData } from '~/lib/providers/aurelius'
import { MusicChannels } from '~/lib/types'

type MusicPlayerProps = {
focusMode: boolean
isMusicPlaying: boolean
setIsMusicPlaying: (isPlaying: boolean) => void
}

const MusicPlayer = ({
focusMode,
isMusicPlaying,
setIsMusicPlaying,
}: MusicPlayerProps) => {
const { settings } = useContext<AureliusProviderData>(AureliusContext)

const [volume, setVolume] = useState(50)

return (
<div
className={`p-4 flex items-center transition-opacity duration-100 hover:opacity-100 ${focusMode ? 'opacity-5' : 'opacity-100'}`}
>
<div className='flex items-center h-9 bg-background rounded-lg border border-border'>
<Popover>
<PopoverTrigger asChild>
<Button className='w-9 h-9' size='icon' variant='ghost'>
{volume === 0 ? (
<VolumeXIcon className='w-4 h-4' />
) : volume > 0 && volume <= 50 ? (
<Volume1Icon className='w-4 h-4' />
) : (
<Volume2Icon className='w-4 h-4' />
)}
</Button>
</PopoverTrigger>
<PopoverContent className='w-9 h-48 p-0 flex justify-center py-4'>
<Slider
max={100}
min={0}
onValueChange={(value) => setVolume(value[0])}
orientation='vertical'
value={[volume]}
/>
</PopoverContent>
</Popover>
<Separator orientation='vertical' />
{isMusicPlaying ? (
<Button
className='w-9 h-9'
onClick={() => setIsMusicPlaying?.(false)}
size='icon'
variant='ghost'
>
<PauseIcon className='w-4 h-4' />
</Button>
) : (
<Button
className='w-9 h-9'
onClick={() => setIsMusicPlaying?.(true)}
size='icon'
variant='ghost'
>
<PlayIcon className='w-4 h-4' />
</Button>
)}
</div>
<Suspense fallback={<div>Loading...</div>}>
<ReactPlayer
playing={isMusicPlaying}
// @ts-ignore
url={
settings?.youtubeLink ||
MUSIC_STATIONS[settings?.musicChannel as MusicChannels]
}
width='0'
height='0'
loop={true}
volume={volume / 100}
config={{
youtube: {
playerVars: {
control: 1,
start: 1,
},
},
}}
/>
</Suspense>
</div>
)
}

export default MusicPlayer
45 changes: 45 additions & 0 deletions app/components/ui/slider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as React from 'react'

import * as SliderPrimitive from '@radix-ui/react-slider'
import { cn } from '~/lib/utils'

const Slider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
>(({ className, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn(
'relative flex touch-none select-none',
props.orientation === 'vertical'
? 'h-full flex-col justify-center'
: 'w-full items-center',
className
)}
{...props}
>
<SliderPrimitive.Track
className={cn(
'relative grow overflow-hidden rounded-full bg-secondary',
props.orientation === 'vertical' ? 'h-full w-2' : 'h-2 w-full'
)}
>
<SliderPrimitive.Range
className={cn(
'absolute bg-primary',
props.orientation === 'vertical' ? 'w-full' : 'h-full'
)}
/>
</SliderPrimitive.Track>
<SliderPrimitive.Thumb
className={cn(
'flex h-5 w-5 rounded-full border-2 border-primary ring-offset-background transition-colors disabled:pointer-events-none disabled:opacity-50',
'bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
props.orientation === 'vertical' ? '-ml-1.5' : ''
)}
/>
</SliderPrimitive.Root>
))
Slider.displayName = SliderPrimitive.Root.displayName

export { Slider }
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slider": "^1.2.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.0",
Expand Down Expand Up @@ -69,7 +70,7 @@
"github-slugger": "^2.0.0",
"isbot": "^5.1.12",
"lowlight": "^3.1.0",
"lucide-react": "^0.407.0",
"lucide-react": "0.436.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-player": "^2.16.0",
Expand Down
47 changes: 41 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 29e7b05

Please sign in to comment.