feat: better clips
This commit is contained in:
@ -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;
|
||||
|
@ -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">
|
||||
|
@ -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}
|
||||
/>
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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>
|
||||
</>
|
||||
);
|
||||
|
@ -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>
|
||||
</>
|
||||
);
|
||||
|
@ -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>
|
||||
|
@ -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} />
|
||||
|
@ -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>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
Reference in New Issue
Block a user