Skip to content
Merged
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
3 changes: 2 additions & 1 deletion app/dashboard/[[...tab]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { useEffect, useState, useCallback, useRef } from "react";
import { useParams } from "next/navigation";
import { copyText } from "@/lib/clipboard";
import VideoPlayer from "@/components/VideoPlayer";
import { formatApiKeyTime } from "@/lib/api-key-time";
import { formatStoredWebhookPayload } from "@/lib/webhook-payload";
import {
Expand Down Expand Up @@ -723,7 +724,7 @@ function VideosPanel({ onError, onOk }: { onError: (m: string) => void; onOk: (m
<div className="video-grid">
{reels.map((m) => (
<figure key={m.id} className="video-cell">
<video src={m.url} poster={m.thumb || undefined} controls preload="metadata" playsInline />
<VideoPlayer className="video-stage" src={m.url} poster={m.thumb} />
<figcaption className="row" style={{ justifyContent: "space-between", alignItems: "center" }}>
<span>{m.title}</span>
<button className="btn2 ghost" disabled={busy} onClick={() => del(m.id)}>Delete</button>
Expand Down
5 changes: 5 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,9 @@ h2 { font-family: var(--display); font-weight: 400; text-transform: uppercase; f
.video-cell:hover { border-color: var(--acid); }
.video-cell video { display: block; width: 100%; max-height: 60vh; background: #000; aspect-ratio: 16 / 9; object-fit: contain; }
.video-cell.portrait video { aspect-ratio: 9 / 16; }
/* House player (@profullstack/player) stage: same box the raw <video> had. */
.video-cell .video-stage { width: 100%; height: auto; max-height: 60vh; aspect-ratio: 16 / 9; }
.video-cell.portrait .video-stage { aspect-ratio: 9 / 16; }
.video-cell figcaption { font-family: var(--mono); font-size: 11px; color: var(--ash); padding: 8px 10px; text-transform: uppercase; letter-spacing: .08em; word-break: break-word; }

/* Tenant "Post it" share row */
Expand Down Expand Up @@ -416,6 +419,7 @@ dialog.qhelp::backdrop { background: rgba(0,0,0,.72); backdrop-filter: blur(2px)
/* Tenant uploaded-video gallery */
.t-videos { display: grid; gap: 12px; max-width: 460px; margin: 22px auto 0; width: 100%; }
.t-video { width: 100%; border: 1px solid var(--line); border-radius: 10px; background: #000; display: block; }
.t-video.pux-player { height: auto; aspect-ratio: 16 / 9; }

/* Highlighted code blocks (content blocks) + copy button */
.code-wrap { position: relative; margin: 14px 0; }
Expand Down Expand Up @@ -469,6 +473,7 @@ dialog.qhelp::backdrop { background: rgba(0,0,0,.72); backdrop-filter: blur(2px)
/* mixed-media repo assets: video/audio tiles + dashboard chips */
.t-asset-av { aspect-ratio: 1/1; width: 100%; padding: 0; background: #000; }
.t-asset-av video, video.t-asset-av { width: 100%; height: 100%; object-fit: cover; }
.t-asset-av > .pux-player, .t-asset-audio > .pux-player { width: 100%; height: 100%; }
.t-asset-audio { grid-column: 1 / -1; aspect-ratio: auto; width: 100%; padding: 8px; }
.t-asset-audio audio, audio.t-asset-audio { width: 100%; }
.t-asset-chip { aspect-ratio: auto; padding: 8px 10px; font-family: var(--mono); font-size: 11px; color: var(--ash); text-align: center; word-break: break-word; }
Expand Down
3 changes: 2 additions & 1 deletion app/videos/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from "node:path";
import type { Metadata } from "next";
import { listMedia } from "@/lib/db";
import { hasThumb } from "@/lib/media";
import VideoPlayer from "@/components/VideoPlayer";

export const dynamic = "force-dynamic";

Expand Down Expand Up @@ -70,7 +71,7 @@ export default async function VideosPage() {
<div className="video-grid">
{reels.map((r) => (
<figure key={r.src} className={`video-cell${r.portrait ? " portrait" : ""}`}>
<video src={r.src} poster={r.poster} controls preload="metadata" playsInline />
<VideoPlayer className="video-stage" src={r.src} poster={r.poster} />
<figcaption>{r.title}</figcaption>
</figure>
))}
Expand Down
11 changes: 11 additions & 0 deletions bun.lock

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

11 changes: 8 additions & 3 deletions components/Tenant.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import SharePost from "./SharePost";
import LinkIcon, { kindFromUrl } from "./LinkIcon";
import CrawlProofAd from "./CrawlProofAd";
import CodeCopy from "./CodeCopy";
import VideoPlayer from "./VideoPlayer";
import { renderMarkdown } from "@/lib/markdown";

/**
Expand Down Expand Up @@ -113,7 +114,7 @@ export default function Tenant({ cfg }: { cfg: TenantConfig }) {
{cfg.videos.length > 0 && (
<div id="videos" className="t-videos" aria-label="Videos">
{cfg.videos.map((v, i) => (
<video key={i} className="t-video" controls preload="metadata" playsInline src={v.url} poster={v.poster || undefined} />
<VideoPlayer key={i} className="t-video" src={v.url} poster={v.poster} />
))}
</div>
)}
Expand All @@ -122,9 +123,13 @@ export default function Tenant({ cfg }: { cfg: TenantConfig }) {
<div className="t-assets" aria-label="Assets">
{cfg.assets.map((a, i) =>
a.kind === "video" ? (
<video key={i} className="t-asset t-asset-av" controls preload="metadata" playsInline src={a.url} title={a.label} />
<div key={i} className="t-asset t-asset-av" title={a.label}>
<VideoPlayer src={a.url} />
</div>
) : a.kind === "audio" ? (
<audio key={i} className="t-asset t-asset-audio" controls preload="none" src={a.url} title={a.label} />
<div key={i} className="t-asset t-asset-audio" title={a.label}>
<VideoPlayer src={a.url} audio />
</div>
) : (
<a key={i} className="t-asset" href={a.url} target="_blank" rel="noopener noreferrer" title={a.label}>
<img src={a.url} alt={a.label} loading="lazy" />
Expand Down
31 changes: 31 additions & 0 deletions components/VideoPlayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"use client";
import { Player } from "@profullstack/player/react";
import "@profullstack/player/player.css";

/**
* The house player (@profullstack/player): one control bar that hides itself,
* full screen on every device including iPhone, MP4/HLS/MPEG-TS/audio sniffed
* from the URL. Server components render this instead of a raw <video>/<audio>.
*/
export default function VideoPlayer({
src,
poster,
audio,
className,
}: {
src: string;
poster?: string | null;
audio?: boolean;
className?: string;
}) {
return (
<Player
src={src}
poster={poster || undefined}
audio={audio}
className={className}
shareable={false}
useTimeParam={false}
/>
);
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@profullstack/coinpay-onboard": "0.3.1",
"@profullstack/footer": "latest",
"@profullstack/libsql-pg": "^0.1.4",
"@profullstack/player": "0.17.0",
"@profullstack/profile": "0.1.6",
"@profullstack/redeem-credits": "0.2.0",
"@profullstack/stack": "0.5.0",
Expand Down
Loading