fix: responive layout improvements

This commit is contained in:
2024-05-22 15:07:42 +01:00
parent 2a6929b894
commit 19d732c272
7 changed files with 66 additions and 48 deletions

View File

@ -1,54 +1,55 @@
import { DAY, HOUR, MINUTE, MONTH, WEEK } from "@/const"; import { DAY, HOUR, MINUTE, MONTH, WEEK } from "@/const";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
export function RelativeTime({ from }: { from: number }) { export function RelativeTime({ from, suffix }: { from: number; suffix?: boolean }) {
const diff = (new Date().getTime() - from) / 1000; const diff = (new Date().getTime() - from) / 1000;
const s = <FormattedMessage defaultMessage="ago" description="Relative time, ie. 1s ago" />;
if (diff > MONTH) { if (diff > MONTH) {
return ( return (
<FormattedMessage <FormattedMessage
defaultMessage="{m}mo" defaultMessage="{m}mo {ago}"
description="Number of month(s) relative to now" description="Number of month(s) relative to now"
values={{ m: Math.floor(diff / MONTH).toFixed(0) }} values={{ m: Math.floor(diff / MONTH).toFixed(0), ago: suffix ? s : undefined }}
/> />
); );
} else if (diff > WEEK) { } else if (diff > WEEK) {
return ( return (
<FormattedMessage <FormattedMessage
defaultMessage="{m}w" defaultMessage="{m}w {ago}"
description="Number of week(s) relative to now" description="Number of week(s) relative to now"
values={{ m: Math.floor(diff / WEEK).toFixed(0) }} values={{ m: Math.floor(diff / WEEK).toFixed(0), ago: suffix ? s : undefined }}
/> />
); );
} else if (diff > DAY) { } else if (diff > DAY) {
return ( return (
<FormattedMessage <FormattedMessage
defaultMessage="{m}d" defaultMessage="{m}d {ago}"
description="Number of day(s) relative to now" description="Number of day(s) relative to now"
values={{ m: Math.floor(diff / DAY).toFixed(0) }} values={{ m: Math.floor(diff / DAY).toFixed(0), ago: suffix ? s : undefined }}
/> />
); );
} else if (diff > HOUR) { } else if (diff > HOUR) {
return ( return (
<FormattedMessage <FormattedMessage
defaultMessage="{m}h" defaultMessage="{m}h {ago}"
description="Number of hour(s) relative to now" description="Number of hour(s) relative to now"
values={{ m: Math.floor(diff / HOUR).toFixed(0) }} values={{ m: Math.floor(diff / HOUR).toFixed(0), ago: suffix ? s : undefined }}
/> />
); );
} else if (diff > MINUTE) { } else if (diff > MINUTE) {
return ( return (
<FormattedMessage <FormattedMessage
defaultMessage="{m}h" defaultMessage="{m}h {ago}"
description="Number of minute(s) relative to now" description="Number of minute(s) relative to now"
values={{ m: Math.floor(diff / MINUTE).toFixed(0) }} values={{ m: Math.floor(diff / MINUTE).toFixed(0), ago: suffix ? s : undefined }}
/> />
); );
} else { } else {
return ( return (
<FormattedMessage <FormattedMessage
defaultMessage="{m}s" defaultMessage="{m}s {ago}"
description="Number of second(s) relative to now" description="Number of second(s) relative to now"
values={{ m: Math.floor(diff).toFixed(0) }} values={{ m: Math.floor(diff).toFixed(0), ago: suffix ? s : undefined }}
/> />
); );
} }

View File

@ -2,7 +2,7 @@ import { ReactNode } from "react";
export default function VideoGrid({ children }: { children: ReactNode }) { export default function VideoGrid({ children }: { children: ReactNode }) {
return ( return (
<div className="grid gap-5 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-7 3xl:grid-cols-8 items-start"> <div className="grid gap-5 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6 3xl:grid-cols-7 items-start">
{children} {children}
</div> </div>
); );

View File

@ -16,6 +16,7 @@ import { useUserProfile } from "@snort/system-react";
import { VideoDuration } from "./video/duration"; import { VideoDuration } from "./video/duration";
import useImgProxy from "@/hooks/img-proxy"; import useImgProxy from "@/hooks/img-proxy";
import PillOpaque from "./pill-opaque"; import PillOpaque from "./pill-opaque";
import { RelativeTime } from "./relative-time";
export function VideoTile({ export function VideoTile({
ev, ev,
@ -32,7 +33,7 @@ export function VideoTile({
style: "list" | "grid"; style: "list" | "grid";
className?: string; className?: string;
}) { }) {
const { title, image, status, participants, contentWarning, duration, recording } = extractStreamInfo(ev); const { title, image, status, participants, contentWarning, duration, recording, ends } = extractStreamInfo(ev);
const host = getHost(ev); const host = getHost(ev);
const hostProfile = useUserProfile(host); const hostProfile = useUserProfile(host);
const isGrownUp = useContentWarning(); const isGrownUp = useContentWarning();
@ -94,7 +95,17 @@ export function VideoTile({
<span className="font-medium" title={title}> <span className="font-medium" title={title}>
{(title?.length ?? 0) > 50 ? `${title?.slice(0, 47)}...` : title} {(title?.length ?? 0) > 50 ? `${title?.slice(0, 47)}...` : title}
</span> </span>
{showAuthor && <span className="text-layer-4">{getName(host, hostProfile)}</span>} {showAuthor && (
<span className="text-layer-4">
{getName(host, hostProfile)}
{ends && (
<>
{" · "}
<RelativeTime from={Number(ends) * 1000} suffix={true} />
</>
)}
</span>
)}
</div> </div>
</div> </div>
</div> </div>

View File

@ -62,10 +62,6 @@
"1qsXCO": { "1qsXCO": {
"defaultMessage": "eg. name@wallet.com" "defaultMessage": "eg. name@wallet.com"
}, },
"1y8vnu": {
"defaultMessage": "{m}s",
"description": "Number of second(s) relative to now"
},
"2/2yg+": { "2/2yg+": {
"defaultMessage": "Add" "defaultMessage": "Add"
}, },
@ -177,10 +173,6 @@
"9a9+ww": { "9a9+ww": {
"defaultMessage": "Title" "defaultMessage": "Title"
}, },
"9bAnRw": {
"defaultMessage": "{m}d",
"description": "Number of day(s) relative to now"
},
"9pMqYs": { "9pMqYs": {
"defaultMessage": "Nostr Address" "defaultMessage": "Nostr Address"
}, },
@ -259,6 +251,10 @@
"FIDK5Y": { "FIDK5Y": {
"defaultMessage": "All Time Top Zappers" "defaultMessage": "All Time Top Zappers"
}, },
"FXepR9": {
"defaultMessage": "{m}mo {ago}",
"description": "Number of month(s) relative to now"
},
"FjDlus": { "FjDlus": {
"defaultMessage": "You can always replace it with your own address later." "defaultMessage": "You can always replace it with your own address later."
}, },
@ -400,9 +396,17 @@
"OkXMLE": { "OkXMLE": {
"defaultMessage": "Max Audio Bitrate" "defaultMessage": "Max Audio Bitrate"
}, },
"OumUwz": {
"defaultMessage": "{m}s {ago}",
"description": "Number of second(s) relative to now"
},
"Oxqtyf": { "Oxqtyf": {
"defaultMessage": "We hooked you up with a lightning wallet so you can get paid by viewers right away!" "defaultMessage": "We hooked you up with a lightning wallet so you can get paid by viewers right away!"
}, },
"PDA8V2": {
"defaultMessage": "{m}h {ago}",
"description": "Number of hour(s) relative to now"
},
"PHE60k": { "PHE60k": {
"defaultMessage": "Leave blank if you do not wish to set up any goals." "defaultMessage": "Leave blank if you do not wish to set up any goals."
}, },
@ -469,16 +473,16 @@
"TDUfVk": { "TDUfVk": {
"defaultMessage": "Started" "defaultMessage": "Started"
}, },
"TNFpMZ": {
"defaultMessage": "{m}h",
"description": "Number of hour(s) relative to now"
},
"TP/cMX": { "TP/cMX": {
"defaultMessage": "Ended" "defaultMessage": "Ended"
}, },
"TwyMau": { "TwyMau": {
"defaultMessage": "Account" "defaultMessage": "Account"
}, },
"UCDS65": {
"defaultMessage": "ago",
"description": "Relative time, ie. 1s ago"
},
"UGFYV8": { "UGFYV8": {
"defaultMessage": "Welcome to zap.stream!" "defaultMessage": "Welcome to zap.stream!"
}, },
@ -519,10 +523,6 @@
"X2PZ7D": { "X2PZ7D": {
"defaultMessage": "Create Goal" "defaultMessage": "Create Goal"
}, },
"XD/ATb": {
"defaultMessage": "{m}mo",
"description": "Number of month(s) relative to now"
},
"XIvYvF": { "XIvYvF": {
"defaultMessage": "Failed to get invoice" "defaultMessage": "Failed to get invoice"
}, },
@ -572,6 +572,10 @@
"Zse7yG": { "Zse7yG": {
"defaultMessage": "Raid target" "defaultMessage": "Raid target"
}, },
"aB/rH0": {
"defaultMessage": "{m}h {ago}",
"description": "Number of minute(s) relative to now"
},
"acrOoz": { "acrOoz": {
"defaultMessage": "Continue" "defaultMessage": "Continue"
}, },
@ -681,10 +685,6 @@
"jgOqxt": { "jgOqxt": {
"defaultMessage": "Widgets" "defaultMessage": "Widgets"
}, },
"jhTFev": {
"defaultMessage": "{m}w",
"description": "Number of week(s) relative to now"
},
"jkAQj5": { "jkAQj5": {
"defaultMessage": "Stream Ended" "defaultMessage": "Stream Ended"
}, },
@ -760,10 +760,6 @@
"q9ryv4": { "q9ryv4": {
"defaultMessage": "Cover image URL (optional)" "defaultMessage": "Cover image URL (optional)"
}, },
"qRV9H5": {
"defaultMessage": "{m}h",
"description": "Number of minute(s) relative to now"
},
"qx6bv2": { "qx6bv2": {
"defaultMessage": "Stream Goal (optional)" "defaultMessage": "Stream Goal (optional)"
}, },
@ -779,6 +775,10 @@
"rgsbu9": { "rgsbu9": {
"defaultMessage": "Current Viewers" "defaultMessage": "Current Viewers"
}, },
"s+ORFl": {
"defaultMessage": "{m}d {ago}",
"description": "Number of day(s) relative to now"
},
"s5ksS7": { "s5ksS7": {
"defaultMessage": "Image Link" "defaultMessage": "Image Link"
}, },
@ -870,6 +870,10 @@
"y867Vs": { "y867Vs": {
"defaultMessage": "Volume" "defaultMessage": "Volume"
}, },
"y8ogtp": {
"defaultMessage": "{m}w {ago}",
"description": "Number of week(s) relative to now"
},
"yLxIgl": { "yLxIgl": {
"defaultMessage": "Clips" "defaultMessage": "Clips"
}, },

View File

@ -46,8 +46,8 @@ export function VideoPage({ link, evPreload }: { link: NostrLink; evPreload?: Ta
return ( return (
<div <div
className={classNames("lg:p-4 grow lg:grid lg:gap-2 lg:grid-cols-[auto_450px]", { className={classNames("xl:p-4 grow xl:grid xl:gap-2 xl:grid-cols-[auto_450px]", {
"max-w-[60dvw] mx-auto": !widePlayer, "xl:w-[1600px] xl:max-w-[1600px] mx-auto": !widePlayer,
})}> })}>
<div <div
className={classNames("min-w-0 w-full max-h-[80dvh] aspect-video mx-auto bg-black", { className={classNames("min-w-0 w-full max-h-[80dvh] aspect-video mx-auto bg-black", {

View File

@ -20,7 +20,6 @@
"1LBny5": "Stopped", "1LBny5": "Stopped",
"1q4BO/": "Not a valid URL", "1q4BO/": "Not a valid URL",
"1qsXCO": "eg. name@wallet.com", "1qsXCO": "eg. name@wallet.com",
"1y8vnu": "{m}s",
"2/2yg+": "Add", "2/2yg+": "Add",
"2lVQYF": "...more", "2lVQYF": "...more",
"2ukA4d": "{n} hours", "2ukA4d": "{n} hours",
@ -58,7 +57,6 @@
"8xVdjn": "Video Codec", "8xVdjn": "Video Codec",
"9WRlF4": "Send", "9WRlF4": "Send",
"9a9+ww": "Title", "9a9+ww": "Title",
"9bAnRw": "{m}d",
"9pMqYs": "Nostr Address", "9pMqYs": "Nostr Address",
"9rmSgv": "OBS (Open Broadcaster Software) is a free and open source software for video recording and live streaming on Windows, Mac and Linux. It is a popular choice with streamers. You'll need to install this to capture your video, audio and anything else you'd like to add to your stream. Once installed and configured to preference, add your Stream URL and Stream Key from the Stream settings to OBS to form a connection with zap.stream.", "9rmSgv": "OBS (Open Broadcaster Software) is a free and open source software for video recording and live streaming on Windows, Mac and Linux. It is a popular choice with streamers. You'll need to install this to capture your video, audio and anything else you'd like to add to your stream. Once installed and configured to preference, add your Stream URL and Stream Key from the Stream settings to OBS to form a connection with zap.stream.",
"A1zT+z": "Search results: {term}", "A1zT+z": "Search results: {term}",
@ -85,6 +83,7 @@
"ESyhzp": "Your comment for {name}", "ESyhzp": "Your comment for {name}",
"FAUhZf": "What are sats?", "FAUhZf": "What are sats?",
"FIDK5Y": "All Time Top Zappers", "FIDK5Y": "All Time Top Zappers",
"FXepR9": "{m}mo {ago}",
"FjDlus": "You can always replace it with your own address later.", "FjDlus": "You can always replace it with your own address later.",
"Fodi9+": "Get paid by viewers", "Fodi9+": "Get paid by viewers",
"G/yZLu": "Remove", "G/yZLu": "Remove",
@ -132,7 +131,9 @@
"OKhRC6": "Share", "OKhRC6": "Share",
"ObZZEz": "No clips yet", "ObZZEz": "No clips yet",
"OkXMLE": "Max Audio Bitrate", "OkXMLE": "Max Audio Bitrate",
"OumUwz": "{m}s {ago}",
"Oxqtyf": "We hooked you up with a lightning wallet so you can get paid by viewers right away!", "Oxqtyf": "We hooked you up with a lightning wallet so you can get paid by viewers right away!",
"PDA8V2": "{m}h {ago}",
"PHE60k": "Leave blank if you do not wish to set up any goals.", "PHE60k": "Leave blank if you do not wish to set up any goals.",
"PUymyQ": "Come check out {name} stream on zap.stream! {link}", "PUymyQ": "Come check out {name} stream on zap.stream! {link}",
"PXAur5": "Withdraw", "PXAur5": "Withdraw",
@ -155,9 +156,9 @@
"S39ba6": "What is OBS?", "S39ba6": "What is OBS?",
"SC2nJT": "Audio Codec", "SC2nJT": "Audio Codec",
"TDUfVk": "Started", "TDUfVk": "Started",
"TNFpMZ": "{m}h",
"TP/cMX": "Ended", "TP/cMX": "Ended",
"TwyMau": "Account", "TwyMau": "Account",
"UCDS65": "ago",
"UGFYV8": "Welcome to zap.stream!", "UGFYV8": "Welcome to zap.stream!",
"UJBFYK": "Add Card", "UJBFYK": "Add Card",
"UfSot5": "Past Streams", "UfSot5": "Past Streams",
@ -171,7 +172,6 @@
"Wp4l7+": "More Videos", "Wp4l7+": "More Videos",
"WsjXrZ": "Click on Log In", "WsjXrZ": "Click on Log In",
"X2PZ7D": "Create Goal", "X2PZ7D": "Create Goal",
"XD/ATb": "{m}mo",
"XIvYvF": "Failed to get invoice", "XIvYvF": "Failed to get invoice",
"XMGfiA": "Recent Clips", "XMGfiA": "Recent Clips",
"XgWvGA": "Reactions", "XgWvGA": "Reactions",
@ -188,6 +188,7 @@
"ZmqxZs": "You can change this later", "ZmqxZs": "You can change this later",
"ZsYhvh": "Zaps are lightning payments, which are published on nostr as receipts.", "ZsYhvh": "Zaps are lightning payments, which are published on nostr as receipts.",
"Zse7yG": "Raid target", "Zse7yG": "Raid target",
"aB/rH0": "{m}h {ago}",
"acrOoz": "Continue", "acrOoz": "Continue",
"aqjZxs": "Raid!", "aqjZxs": "Raid!",
"bD/ZwY": "Edit Cards", "bD/ZwY": "Edit Cards",
@ -224,7 +225,6 @@
"j/jueq": "Raiding {name}", "j/jueq": "Raiding {name}",
"jJLRgo": "Publish Clip", "jJLRgo": "Publish Clip",
"jgOqxt": "Widgets", "jgOqxt": "Widgets",
"jhTFev": "{m}w",
"jkAQj5": "Stream Ended", "jkAQj5": "Stream Ended",
"jr4+vD": "Markdown", "jr4+vD": "Markdown",
"jvo0vs": "Save", "jvo0vs": "Save",
@ -250,12 +250,12 @@
"pxF+t0": "Popular", "pxF+t0": "Popular",
"q+zTWM": "<s>{person}</s> zapped <s>{amount}</s> sats", "q+zTWM": "<s>{person}</s> zapped <s>{amount}</s> sats",
"q9ryv4": "Cover image URL (optional)", "q9ryv4": "Cover image URL (optional)",
"qRV9H5": "{m}h",
"qx6bv2": "Stream Goal (optional)", "qx6bv2": "Stream Goal (optional)",
"r2Jjms": "Log In", "r2Jjms": "Log In",
"rJqhFR": "Stream Setup", "rJqhFR": "Stream Setup",
"rWBFZA": "Sexually explicit material ahead!", "rWBFZA": "Sexually explicit material ahead!",
"rgsbu9": "Current Viewers", "rgsbu9": "Current Viewers",
"s+ORFl": "{m}d {ago}",
"s5ksS7": "Image Link", "s5ksS7": "Image Link",
"s7V+5p": "Confirm your age", "s7V+5p": "Confirm your age",
"sInm1h": "Zap message", "sInm1h": "Zap message",
@ -286,6 +286,7 @@
"xi3sgh": "How do i get more sats?", "xi3sgh": "How do i get more sats?",
"xmcVZ0": "Search", "xmcVZ0": "Search",
"y867Vs": "Volume", "y867Vs": "Volume",
"y8ogtp": "{m}w {ago}",
"yLxIgl": "Clips", "yLxIgl": "Clips",
"yR0V+W": "To start streaming on zap.stream, follow these steps:", "yR0V+W": "To start streaming on zap.stream, follow these steps:",
"yj8NrY": "Clip", "yj8NrY": "Clip",

View File

@ -145,6 +145,7 @@ export function extractStreamInfo(ev?: NostrEvent) {
matchTag(t, "ends", v => (ret.ends = v)); matchTag(t, "ends", v => (ret.ends = v));
matchTag(t, "service", v => (ret.service = v)); matchTag(t, "service", v => (ret.service = v));
matchTag(t, "duration", v => (ret.duration = Number(v))); matchTag(t, "duration", v => (ret.duration = Number(v)));
matchTag(t, "published_at", v => (ret.ends = v));
} }
const { regularTags, prefixedTags } = sortStreamTags(ev?.tags ?? []); const { regularTags, prefixedTags } = sortStreamTags(ev?.tags ?? []);
ret.tags = regularTags; ret.tags = regularTags;