feat: better clips

This commit is contained in:
2023-12-13 14:40:52 +00:00
parent 3d21e1ca19
commit 565de1a19e
41 changed files with 425 additions and 166 deletions

View File

@ -85,16 +85,6 @@ header button {
}
}
.hide-on-mobile {
display: none;
}
@media (min-width: 1020px) {
.hide-on-mobile {
display: block;
}
}
.tags {
display: flex;
flex-wrap: wrap;

View File

@ -110,10 +110,10 @@ export function LayoutPage() {
return (
<Dialog.Root open={showLogin} onOpenChange={setShowLogin}>
<button type="button" className="btn btn-border" onClick={handleLogin}>
<AsyncButton className="btn btn-border" onClick={handleLogin}>
<FormattedMessage defaultMessage="Login" id="AyGauy" />
<Icon name="login" />
</button>
</AsyncButton>
<Dialog.Portal>
<Dialog.Overlay className="dialog-overlay" />
<Dialog.Content className="dialog-content">

View File

@ -15,11 +15,12 @@ import { MuteButton } from "@/element/mute-button";
import { useProfile } from "@/hooks/profile";
import useTopZappers from "@/hooks/top-zappers";
import { Text } from "@/element/text";
import { StreamState } from "@/index";
import { findTag } from "@/utils";
import { StatePill } from "@/element/state-pill";
import { Avatar } from "@/element/avatar";
import { ZapperRow } from "@/element/zapper-row";
import { StreamState } from "@/const";
import AsyncButton from "@/element/async-button";
function TopZappers({ zaps }: { zaps: ParsedZap[] }) {
const zappers = useTopZappers(zaps);
@ -88,10 +89,10 @@ export function ProfilePage() {
aTag={liveEvent ? `${liveEvent.kind}:${liveEvent.pubkey}:${findTag(liveEvent, "d")}` : undefined}
lnurl={zapTarget}
button={
<button className="btn">
<AsyncButton className="btn">
<Icon name="zap-filled" className="zap-button-icon" />
<FormattedMessage defaultMessage="Zap" id="fBI91o" />
</button>
</AsyncButton>
}
targetName={profile?.name || link.id}
/>

View File

@ -6,6 +6,7 @@ import Owncast from "@/owncast.png";
import Cloudflare from "@/cloudflare.png";
import { ConfigureOwncast } from "./owncast";
import { ConfigureNostrType } from "./nostr";
import AsyncButton from "@/element/async-button";
export function StreamProvidersPage() {
const navigate = useNavigate();
@ -37,9 +38,9 @@ export function StreamProvidersPage() {
<div className="paper">
<h3>{mapName(p)}</h3>
{mapLogo(p)}
<button className="btn btn-border" onClick={() => navigate(p)}>
<AsyncButton className="btn btn-border" onClick={() => navigate(p)}>
+ Configure
</button>
</AsyncButton>
</div>
);
}

View File

@ -4,9 +4,9 @@ import { FormattedMessage } from "react-intl";
import AsyncButton from "@/element/async-button";
import { StatePill } from "@/element/state-pill";
import { StreamState } from "@/index";
import { StreamProviderInfo, StreamProviderStore } from "@/providers";
import { NostrStreamProvider } from "@/providers/zsz";
import { StreamState } from "@/const";
export function ConfigureNostrType() {
const [url, setUrl] = useState("");
@ -55,14 +55,14 @@ export function ConfigureNostrType() {
</div>
)}
<div>
<button
<AsyncButton
className="btn btn-border"
onClick={() => {
StreamProviderStore.add(new NostrStreamProvider(new URL(url).host, url));
navigate("/");
}}>
<FormattedMessage defaultMessage="Save" id="jvo0vs" />
</button>
</AsyncButton>
</div>
</>
);

View File

@ -3,9 +3,9 @@ import { useNavigate } from "react-router-dom";
import AsyncButton from "@/element/async-button";
import { StatePill } from "@/element/state-pill";
import { StreamState } from "@/index";
import { StreamProviderInfo, StreamProviderStore } from "@/providers";
import { OwncastProvider } from "@/providers/owncast";
import { StreamState } from "@/const";
export function ConfigureOwncast() {
const [url, setUrl] = useState("");
@ -55,14 +55,14 @@ export function ConfigureOwncast() {
</div>
)}
<div>
<button
<AsyncButton
className="btn btn-border"
onClick={() => {
StreamProviderStore.add(new OwncastProvider(url, token));
navigate("/");
}}>
Save
</button>
</AsyncButton>
</div>
</>
);

View File

@ -8,9 +8,11 @@ import { useLogin } from "@/hooks/login";
import Copy from "@/element/copy";
import { NostrProviderDialog } from "@/element/nostr-provider-dialog";
import { useStreamProvider } from "@/hooks/stream-provider";
import { Login, StreamState } from "..";
import { Login } from "..";
import { StatePill } from "@/element/state-pill";
import { NostrStreamProvider } from "@/providers";
import { StreamState } from "@/const";
import AsyncButton from "@/element/async-button";
const enum Tab {
Account,
@ -105,9 +107,9 @@ export function SettingsPage() {
<div className="flex flex-col gap-2">
<div className="flex gap-2">
{[Tab.Account].map(t => (
<button onClick={() => setTab(t)} className="rounded-xl px-3 py-2 bg-gray-2 hover:bg-gray-1">
<AsyncButton onClick={() => setTab(t)} className="rounded-xl px-3 py-2 bg-gray-2 hover:bg-gray-1">
{tabName(t)}
</button>
</AsyncButton>
))}
</div>
<div className="p-5 bg-gray-2 rounded-3xl flex flex-col gap-3">{tabContent()}</div>

View File

@ -14,7 +14,6 @@ import { LiveChat } from "@/element/live-chat";
import AsyncButton from "@/element/async-button";
import { useLogin } from "@/hooks/login";
import { useZapGoal } from "@/hooks/goals";
import { StreamState } from "@/index";
import { SendZapsDialog } from "@/element/send-zap";
import { NewStreamDialog } from "@/element/new-stream";
import { Tags } from "@/element/tags";
@ -27,6 +26,8 @@ import { ContentWarningOverlay, isContentWarningAccepted } from "@/element/conte
import { useCurrentStreamFeed } from "@/hooks/current-stream-feed";
import { useStreamLink } from "@/hooks/stream-link";
import { FollowButton } from "@/element/follow-button";
import { ClipButton } from "@/element/clip-button";
import { StreamState } from "@/const";
function ProfileInfo({ ev, goal }: { ev?: TaggedNostrEvent; goal?: TaggedNostrEvent }) {
const system = useContext(SnortContext);
@ -52,8 +53,8 @@ function ProfileInfo({ ev, goal }: { ev?: TaggedNostrEvent; goal?: TaggedNostrEv
const viewers = Number(participants ?? "0");
return (
<>
<div className="flex items-center info">
<div className="grow stream-info">
<div className="flex gap-2 max-lg:px-2 max-xl:flex-col">
<div className="grow flex flex-col gap-2 max-xl:hidden">
<h1>{title}</h1>
<p>{summary}</p>
<div className="tags">
@ -77,15 +78,14 @@ function ProfileInfo({ ev, goal }: { ev?: TaggedNostrEvent; goal?: TaggedNostrEv
</div>
)}
</div>
<div className="profile-info">
<div className="flex justify-between sm:gap-4 max-sm:gap-2 nowrap max-md:flex-col lg:items-center">
<Profile pubkey={host ?? ""} />
<div className="flex gap-2">
<div className="hide-on-mobile">
<FollowButton pubkey={host} />
</div>
<FollowButton pubkey={host} hideWhenFollowing={true} />
{ev && (
<>
<ShareMenu ev={ev} />
<ClipButton ev={ev} />
{zapTarget && (
<SendZapsDialog
lnurl={zapTarget}
@ -135,7 +135,11 @@ export function StreamPage({ link, evPreload }: { evPreload?: NostrEvent; link:
return <ContentWarningOverlay />;
}
const descriptionContent = [title, (summary?.length ?? 0) > 0 ? summary : "Nostr live streaming", ...tags].join(", ");
const descriptionContent = [
title,
(summary?.length ?? 0) > 0 ? summary : "Nostr live streaming",
...(tags ?? []),
].join(", ");
return (
<div className="stream-page full-page-height">
<Helmet>
@ -149,7 +153,12 @@ export function StreamPage({ link, evPreload }: { evPreload?: NostrEvent; link:
</Helmet>
<div className="video-content">
<Suspense>
<LiveVideoPlayer stream={status === StreamState.Live ? stream : recording} poster={image} status={status} />
<LiveVideoPlayer
title={title}
stream={status === StreamState.Live ? stream : recording}
poster={image}
status={status}
/>
</Suspense>
<ProfileInfo ev={ev} goal={goal} />
<StreamCards host={host} />

View File

@ -14,6 +14,7 @@ import { Views } from "./widgets/views";
import { Music } from "./widgets/music";
import groupBy from "lodash/groupBy";
import { hexToBech32 } from "@snort/shared";
import AsyncButton from "@/element/async-button";
interface ZapAlertConfigurationProps {
npub: string;
@ -78,6 +79,7 @@ function ZapAlertConfiguration({ npub, baseUrl }: ZapAlertConfigurationProps) {
sender: login?.pubkey,
amount: 1_000_000,
targetEvents: [],
created_at: 0,
}}
/>
<div className="text-to-speech-settings">
@ -151,9 +153,9 @@ function ZapAlertConfiguration({ npub, baseUrl }: ZapAlertConfigurationProps) {
onChange={ev => setTestText(ev.target.value)}
/>
</div>
<button disabled={testText.length === 0} className="btn" onClick={testVoice}>
<AsyncButton disabled={testText.length === 0} className="btn" onClick={testVoice}>
<FormattedMessage defaultMessage="Test voice" id="d5zWyh" />
</button>
</AsyncButton>
</>
)}
</>