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
8 changes: 4 additions & 4 deletions apps/www/app/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { FeatureTrailSection } from "@/components/feature-trail-section"
import { FeatureGrid } from "@/components/features"
import { Hero } from "@/components/hero"
import { ImmersiveScrollPlayer } from "@/components/immersive-scroll-player"
import { PlayerContainer } from "@/components/player-container"
import { AudioPlayerHover } from "@/components/players/audio-player/hover-player"
import { VideoPlayerContainer } from "@/components/players/video-player/player-container"
import { ScrollIndicator } from "@/components/scroll-indicator"
import { YouTubeMusicHoverPlayer } from "@/components/youtube-music-hover-player"

export default function Home() {
return (
Expand All @@ -21,7 +21,7 @@ export default function Home() {
/>
}
>
<PlayerContainer />
<VideoPlayerContainer />
</Suspense>
</ImmersiveScrollPlayer>
<ScrollIndicator />
Expand Down Expand Up @@ -71,7 +71,7 @@ export default function Home() {
</p>
</div>
</FeatureTrailSection>
<YouTubeMusicHoverPlayer />
<AudioPlayerHover />
<div
className={`
mx-auto w-full
Expand Down
17 changes: 9 additions & 8 deletions apps/www/components/blocks/block-showcase.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { ReactNode } from "react"

import { LinearMediaPlayer } from "@/registry/default/blocks/linear-player/components/media-player"
import { YouTubeMusicPlayer } from "@/registry/pro/blocks/youtube-music/components/media-player"
import { AudioPlayerDemo } from "@/components/players/audio-player/demo-player"
import { VIDEO_PLAYER_DEMO_ASSETS } from "@/components/players/video-player/demo-assets"
import { VideoPlayer } from "@/registry/default/blocks/video-player/components/media-player"

import { BlockPreviewPane } from "./preview-background"
import { BlockPreviewWithToolbar } from "./preview-pane"
Expand All @@ -11,23 +12,23 @@ type BlockShowcaseDefinition = {
}

const blockShowcaseRegistry = {
"linear-player": {
"audio-player": {
component: () => (
<BlockPreviewWithToolbar>
<div className="flex size-full">
<div className="flex size-full items-end">
<BlockPreviewPane>
<LinearMediaPlayer as="video" />
<AudioPlayerDemo />
</BlockPreviewPane>
</div>
</BlockPreviewWithToolbar>
),
},
"youtube-music": {
"video-player": {
component: () => (
<BlockPreviewWithToolbar>
<div className="flex size-full items-end">
<div className="flex size-full">
<BlockPreviewPane>
<YouTubeMusicPlayer />
<VideoPlayer playlist={VIDEO_PLAYER_DEMO_ASSETS} />
</BlockPreviewPane>
</div>
</BlockPreviewWithToolbar>
Expand Down
14 changes: 12 additions & 2 deletions apps/www/components/blocks/info-pane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,18 @@ export function BlockInfoPane({
`}
>
<DocsPage>
<DocsTitle className="text-4xl">{title}</DocsTitle>
<DocsDescription>{description}</DocsDescription>
<DocsTitle
className="
text-3xl
sm:text-4xl
md:text-5xl
"
>
{title}
</DocsTitle>
<DocsDescription className="mt-1 leading-relaxed">
{description}
</DocsDescription>
<DocsBody>{content}</DocsBody>
</DocsPage>
</div>
Expand Down
8 changes: 4 additions & 4 deletions apps/www/components/blocks/preview-pane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export function BlockPreviewWithToolbar({
const [reloadKey, setReloadKey] = useState(0)
const panelRef = useRef<HTMLDivElement>(null)
const [panelRect, setPanelRect] = useState({
height: 0,
left: 0,
height: "100%",
left: "100%",
top: 0,
width: 0,
})
Expand All @@ -37,8 +37,8 @@ export function BlockPreviewWithToolbar({
if (!panelRef.current) return
const rect = panelRef.current.getBoundingClientRect()
setPanelRect({
height: rect.height,
left: rect.left,
height: rect.height as any,
left: rect.left as any,
top: rect.top,
width: rect.width,
})
Expand Down
4 changes: 2 additions & 2 deletions apps/www/components/hero-buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { motion } from "motion/react"
import Link from "next/link"
import { useCopyToClipboard } from "react-use"

const command = "npx shadcn add @limeplay/linear-player"
const command = "npx shadcn add @limeplay/video-player"
const MotionLink = motion.create(Link)

export default function HeroButtons() {
Expand Down Expand Up @@ -84,7 +84,7 @@ export default function HeroButtons() {
hover:bg-primary/90
md:flex
`}
href="/blocks/linear-player"
href="/blocks/video-player"
initial={{ padding: "0px 20px" }}
transition={{
bounce: 0.6,
Expand Down
46 changes: 46 additions & 0 deletions apps/www/components/mdx-components.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { MDXComponents } from "mdx/types"
import type { ReactNode } from "react"

import { createGenerator } from "fumadocs-typescript"
import { AutoTypeTable } from "fumadocs-typescript/ui"
Expand All @@ -17,7 +18,9 @@ export function getMDXComponents(components?: MDXComponents): MDXComponents {
<AutoTypeTable {...props} generator={generator} />
),
...TabsComponents,
Attribution,
ComponentPreview,
License,
pre: ({ ref: _ref, ...props }: React.ComponentPropsWithRef<typeof Pre>) => (
<CodeBlock {...props} keepBackground>
<Pre>{props.children}</Pre>
Expand All @@ -26,3 +29,46 @@ export function getMDXComponents(components?: MDXComponents): MDXComponents {
...components,
}
}

function Attribution({
children,
href,
name,
}: {
children?: ReactNode
href?: string
name: string
}) {
return (
<section>
<h2>Attribution</h2>
<p>
Inspired by{" "}
{href ? (
<a href={href} rel="noreferrer" target="_blank">
{name}
</a>
) : (
name
)}
.
</p>
{children}
</section>
)
}

function License() {
return (
<section>
<h2>License & Usage</h2>
<ul>
<li>Free to use and modify in personal and commercial projects.</li>
<li>Attribution to Limeplay is appreciated but not required.</li>
<li>
Do not resell the registry item as a standalone component library.
</li>
</ul>
</section>
)
}
43 changes: 43 additions & 0 deletions apps/www/components/players/audio-player/demo-player.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use client"

import { useEffect, useState } from "react"

import type { AudioPlayerAsset } from "@/registry/default/blocks/audio-player/components/media-player"

import { AudioPlayer } from "@/registry/default/blocks/audio-player/components/media-player"

import {
AUDIO_PLAYER_DEMO_PLAYLIST_ID,
fetchAudioPlayerDemoPlaylist,
} from "./demo"

export interface AudioPlayerDemoProps {
playlistId?: string
}

export function AudioPlayerDemo({
playlistId = AUDIO_PLAYER_DEMO_PLAYLIST_ID,
}: AudioPlayerDemoProps) {
const [playlist, setPlaylist] = useState<AudioPlayerAsset[]>([])

useEffect(() => {
const abortController = new AbortController()

void fetchAudioPlayerDemoPlaylist(playlistId, abortController.signal)
.then((items) => {
if (!abortController.signal.aborted) {
setPlaylist(items)
}
})
.catch((error: unknown) => {
if (error instanceof DOMException && error.name === "AbortError") return
console.error("Failed to load audio player demo playlist:", error)
})

return () => {
abortController.abort()
}
}, [playlistId])

return <AudioPlayer playlist={playlist} />
}
57 changes: 57 additions & 0 deletions apps/www/components/players/audio-player/demo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type {
AudioPlayerAsset,
PlaybackUrls,
} from "@/registry/default/blocks/audio-player/components/media-player"

export const AUDIO_PLAYER_DEMO_PLAYLIST_ID = "324531068"

const API_BASE_URL = "https://limeplay.winoff.workers.dev/api/playlist"

export interface AudioPlayerPlaylistApiResponse {
cached_at: string
expires_at: string
items: AudioPlayerPlaylistAssetItem[]
}

export interface AudioPlayerPlaylistAssetItem {
artwork_url: string
description?: string
duration: number
full_duration: number
genre?: string
has_downloads_left: boolean
label_name?: null | string
playback: PlaybackUrls
tag_list?: string
title: string
urn: string
waveform_url?: string
}

export async function fetchAudioPlayerDemoPlaylist(
playlistId: string,
signal: AbortSignal
): Promise<AudioPlayerAsset[]> {
const response = await fetch(`${API_BASE_URL}/${playlistId}`, { signal })

if (!response.ok) {
throw new Error(`Failed to fetch playlist: ${response.statusText}`)
}

const data: AudioPlayerPlaylistApiResponse = await response.json()
return data.items.map(toAudioPlayerAsset)
}

function toAudioPlayerAsset(
item: AudioPlayerPlaylistAssetItem
): AudioPlayerAsset {
return {
description: item.description,
duration: item.duration,
genre: item.genre,
id: item.urn,
playbackUrls: item.playback,
poster: item.artwork_url,
title: item.title,
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
"use client"

import { SquareArrowOutUpRightIcon } from "lucide-react"
import { AudioLinesIcon, SquareArrowOutUpRightIcon } from "lucide-react"
import { motion } from "motion/react"
import Link from "next/link"

import { Button } from "@/components/ui/button"
import { YouTubeMusicPlayer } from "@/registry/pro/blocks/youtube-music/components/media-player"

export function YouTubeMusicHoverPlayer() {
import { AudioPlayerDemo } from "./demo-player"

export function AudioPlayerHover() {
return (
<motion.div
animate="closed"
Expand All @@ -31,38 +32,26 @@ export function YouTubeMusicHoverPlayer() {
>
<div className="flex h-14 w-fit flex-row items-center gap-3 rounded-t-3xl bg-black px-4">
<div className="flex w-full items-center justify-center gap-1">
<svg
height="36px"
viewBox="0 0 48 48"
width="36px"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="24" cy="24" fill="#f44336" r="20" />
<polygon fill="#fff" points="21,29 29,24 21,19" />
<path
d="M24,14c5.5,0,10,4.476,10,10s-4.476,10-10,10S14,29.5,14,24S18.5,14,24,14"
fill="none"
stroke="#fff"
strokeMiterlimit="10"
/>
</svg>
<span className="flex size-9 items-center justify-center rounded-full bg-white text-black">
<AudioLinesIcon className="size-5" />
</span>
<span className="text-3xl font-semibold tracking-tight text-white">
Music
Audio
</span>
</div>
<div className="my-auto h-8 w-0.5 rounded-md bg-muted-foreground"></div>
<Button asChild size="xs">
<Link
className="text-sm font-semibold tracking-tight"
href="/blocks/youtube-music"
href="/blocks/audio-player"
>
Install Now
<SquareArrowOutUpRightIcon className="ml-1" />
</Link>
</Button>
</div>
</motion.div>
<YouTubeMusicPlayer />
<AudioPlayerDemo />
</motion.div>
)
}
Loading
Loading