Redo page styles

This commit is contained in:
Kieran 2023-07-24 18:15:14 +01:00
parent 9d06a07df3
commit a881fd06a0
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
14 changed files with 165 additions and 312 deletions

View File

@ -1,6 +1,7 @@
.goal {
font-size: 16px;
font-weight: 600;
margin-bottom: 14px;
}
.goal p {

View File

@ -1,64 +1,19 @@
.live-chat {
grid-area: chat;
display: flex;
flex-direction: column;
padding: 8px 16px;
border: none;
height: calc(100vh - 56px - 64px - 36px - 230px);
gap: var(--gap-s);
}
.live-chat ::-webkit-scrollbar {
width: 8px;
}
@media (min-width: 768px) {
.profile-info {
width: calc(100vw - 600px - 16px);
}
.live-chat {
width: calc(100vw - 600px - 16px);
height: calc(100vh - 56px - 64px - 16px);
}
.video-content video {
width: 100%;
}
}
@media (min-width: 1020px) {
.profile-info {
width: unset;
padding: 0;
}
.live-chat {
height: calc(100vh - 72px - 96px);
padding: 24px 16px 8px 24px;
border: 1px solid #171717;
border-radius: 24px;
}
.live-chat {
width: auto;
}
}
@media (min-width: 2000px) {
.live-chat {
height: calc(100vh - 72px - 96px - 120px - 56px);
}
}
.live-chat > .header {
display: none;
}
@media (min-width: 768px){
.live-chat > .header {
display: flex;
justify-content: space-between
}
.live-chat .header {
display: flex;
align-items: center;
justify-content: space-between;
}
.live-chat .header .title {
@ -158,9 +113,9 @@
.top-zappers {
display: flex;
flex-direction: column;
gap: 16px;
gap: var(--gap-s);
border-bottom: 1px solid var(--border, #171717);
padding-bottom: 18px;
padding-bottom: var(--gap-s);
}
.top-zappers h3 {
@ -170,12 +125,6 @@
font-weight: 600;
}
@media (max-width: 768px) {
.top-zappers h3 {
display: none;
}
}
.top-zappers-container {
display: flex;
overflow-y: hidden;

View File

@ -14,7 +14,7 @@ export function Tags({
const status = findTag(ev, "status");
const start = findTag(ev, "starts");
return (
<div className="tags">
<>
{children}
{status === StreamState.Planned && (
<span className="pill">
@ -30,6 +30,6 @@ export function Tags({
{a}
</span>
))}
</div>
</>
);
}

View File

@ -7,6 +7,21 @@ body {
color: white;
}
:root {
--gap-l: 32px;
--gap-m: 24px;
--gap-s: 16px;
--header-height: 48px;
}
@media(max-width: 1020px) {
:root {
--gap-l: 24px;
--gap-m: 16px;
--gap-s: 8px;
}
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;

View File

@ -48,10 +48,6 @@ const router = createBrowserRouter([
path: "/p/:npub",
element: <ProfilePage />,
},
{
path: "/nsfw",
element: <RootPage nsfw={true} />,
},
{
path: "/:id",
element: <StreamPage />,

View File

@ -0,0 +1,30 @@
import { useState } from "react";
import { useNavigate } from "react-router-dom";
export function ContentWarningOverlay() {
const navigate = useNavigate();
const [is18Plus, setIs18Plus] = useState(
Boolean(window.localStorage.getItem("accepted-content-warning"))
);
if (is18Plus) return null;
function grownUp() {
window.localStorage.setItem("accepted-content-warning", "true");
setIs18Plus(true);
}
return (
<div className="fullscreen-exclusive age-check">
<h1>Sexually explicit material ahead!</h1>
<h2>Confirm your age</h2>
<div className="flex g24">
<button className="btn btn-warning" onClick={grownUp}>
Yes, I am over 18
</button>
<button className="btn" onClick={() => navigate("/")}>
No, I am under 18
</button>
</div>
</div>
);
}

View File

@ -1,22 +1,16 @@
.popout-chat {
display: grid;
grid-template-areas:
"main-content";
grid-template-rows: 1fr;
grid-template-columns: 1fr;
height: 100vh;
gap: 0;
}
.popout-chat .live-chat {
padding: 8px 16px;
width: 100vw;
height: calc(100vh - 32px);
width: calc(100vw - 32px);
height: calc(100vh - 16px);
margin-left: 0;
border: unset;
border-radius: unset;
}
.popout-chat .live-chat .messages {
overflow: hidden;
padding-right: unset;
}
.popout-chat.embed .live-chat .messages::-webkit-scrollbar {
display: none;
}

View File

@ -9,14 +9,14 @@ export function ChatPopout() {
const link = parseNostrLink(params.id!);
const { data: ev } = useEventFeed(link, true);
const chat = new URL(window.location.href).searchParams.get("chat");
const chat = Boolean(new URL(window.location.href).searchParams.get("chat"));
return (
<div className="popout-chat">
<div className={`popout-chat${chat ? "" : " embed"}`}>
<LiveChat
ev={ev}
link={link}
options={{
canWrite: Boolean(chat),
canWrite: chat,
showHeader: false,
}}
/>

View File

@ -1,95 +1,36 @@
.page {
display: grid;
gap: 0;
grid-template-areas:
"header"
"main-content"
"profile"
"chat";
grid-template-rows: 64px 230px 56px 1fr;
grid-template-columns: 1fr;
height: 100vh;
--page-pad-tb: 16px;
--page-pad-lr: 40px;
--header-page-padding: calc(var(--page-pad-tb) + var(--page-pad-tb));
padding: var(--page-pad-tb) var(--page-pad-lr);
display: flex;
flex-direction: column;
gap: var(--gap-s);
}
.page.only-content {
display: grid;
height: 100vh;
grid-template-areas:
"header"
"main-content";
grid-template-rows: 64px 1fr;
grid-template-columns: 1fr;
.page.stream {
height: calc(100vh - var(--header-page-padding));
overflow: hidden;
}
@media (min-width: 768px) {
@media (max-width: 1020px) {
.page {
display: grid;
height: 100vh;
grid-template-areas:
"header header"
"main-content profile"
"main-content chat";
grid-template-rows: 64px min-content;
grid-template-columns: 600px 1fr;
gap: 0;
--page-pad-tb: 8px;
--page-pad-lr: 0;
}
.video-content video {
height: 100%;
.page.stream {
display: flex;
flex-direction: column;
}
}
@media (min-width: 1020px) {
.page {
display: grid;
height: calc(100vh - 72px);
padding: 0 40px;
grid-template-columns: auto 376px;
grid-template-rows: unset;
grid-template-areas:
"header header"
"main-content chat"
"profile chat";
gap: 0;
}
}
@media (min-width: 2000px) {
.page {
padding: 0 40px;
grid-template-columns: auto 450px;
}
.video-content {
max-height: calc(100vh - 320px);
}
.video-content video {
height: 100%;
header {
padding: 0 16px;
}
}
header {
grid-area: header;
align-items: center;
display: grid;
grid-template-columns: min-content min-content min-content auto;
padding: 8px 16px;
gap: 8px;
white-space: nowrap;
}
@media (min-width: 1020px) {
header {
gap: 24px;
padding: 24px 0 32px 0;
}
.page.only-content {
grid-template-rows: 88px 1fr;
}
display: flex;
gap: 24px;
}
header .logo {
@ -178,7 +119,7 @@ button span.hide-on-mobile {
}
.zap-icon {
color: #FF8D2B;
color: #ff8d2b;
}
.tags {
@ -194,7 +135,7 @@ button span.hide-on-mobile {
top: 0;
left: 0;
z-index: 999;
background: #0A0A0A;
background: #0a0a0a;
}
.age-check {

View File

@ -1,7 +1,7 @@
import "./layout.css";
import { useState } from "react";
import * as Dialog from "@radix-ui/react-dialog";
import { Outlet, useNavigate, useLocation, Link } from "react-router-dom";
import { Outlet, useNavigate } from "react-router-dom";
import { Helmet } from "react-helmet";
import { Icon } from "element/icon";
@ -16,7 +16,6 @@ import { Login } from "index";
export function LayoutPage() {
const navigate = useNavigate();
const login = useLogin();
const location = useLocation();
const [showLogin, setShowLogin] = useState(false);
function loggedIn() {
@ -81,21 +80,9 @@ export function LayoutPage() {
</Dialog.Root>
);
}
const isNsfw = window.location.pathname === "/nsfw";
return (
<div
className={
location.pathname === "/" ||
location.pathname.startsWith("/p/") ||
location.pathname.startsWith("/providers") ||
location.pathname === "/nsfw"
? "page only-content"
: location.pathname.startsWith("/chat/")
? "page chat"
: "page"
}
>
<div className={`page${location.pathname.startsWith("/naddr1") ? " stream" : ""}`}>
<Helmet>
<title>Home - zap.stream</title>
</Helmet>
@ -105,47 +92,15 @@ export function LayoutPage() {
<input className="search-input" type="text" placeholder="Search" />
<Icon name="search" size={15} />
</div>
<Link to={"/nsfw"}>
<div className={`btn-header${isNsfw ? " active" : ""}`}>
Adult (18+)
</div>
</Link>
<div className="f-grow">
{/* Future menu items go here */}
</div>
<div className="header-right">
{loggedIn()}
{loggedOut()}
</div>
</header>
<Outlet />
{isNsfw && <ContentWarningOverlay />}
</div>
);
}
function ContentWarningOverlay() {
const navigate = useNavigate();
const [is18Plus, setIs18Plus] = useState(
Boolean(window.localStorage.getItem("accepted-content-warning"))
);
if (is18Plus) return null;
function grownUp() {
window.localStorage.setItem("accepted-content-warning", "true");
setIs18Plus(true);
}
return (
<div className="fullscreen-exclusive age-check">
<h1>Sexually explicit material ahead!</h1>
<h2>Confirm your age</h2>
<div className="flex g24">
<button className="btn btn-warning" onClick={grownUp}>
Yes, I am over 18
</button>
<button className="btn" onClick={() => navigate("/")}>
No, I am under 18
</button>
</div>
</div>
);
}
}

View File

@ -1,7 +1,7 @@
.video-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 32px;
gap: var(--gap-l);
padding: 40px 0;
}
@ -18,7 +18,6 @@
.video-grid {
display: grid;
grid-template-columns: 1fr;
gap: 32px;
padding: 16px;
}
}
@ -35,11 +34,6 @@
}
}
.homepage {
width: 100%;
grid-area: main-content;
}
.divider {
display: flex;
}

View File

@ -12,7 +12,7 @@ import { VideoTile } from "../element/video-tile";
import { findTag } from "../utils";
import { LIVE_STREAM } from "../const";
export function RootPage({ nsfw }: { nsfw?: boolean }) {
export function RootPage() {
const rb = useMemo(() => {
const rb = new RequestBuilder("root");
rb.withOptions({
@ -31,7 +31,7 @@ export function RootPage({ nsfw }: { nsfw?: boolean }) {
);
const feedSorted = useMemo(() => {
if (feed.data) {
return [...feed.data].filter(a => nsfw ? findTag(a, "content-warning") !== undefined : findTag(a, "content-warning") === undefined).sort((a, b) => {
return [...feed.data].sort((a, b) => {
const aStatus = findTag(a, "status")!;
const bStatus = findTag(b, "status")!;
if (aStatus === bStatus) {
@ -44,7 +44,7 @@ export function RootPage({ nsfw }: { nsfw?: boolean }) {
});
}
return [];
}, [feed.data, nsfw]);
}, [feed.data]);
const live = feedSorted.filter(
(a) => findTag(a, "status") === StreamState.Live

View File

@ -1,43 +1,77 @@
.video-content {
grid-area: main-content;
.stream-page {
display: grid;
grid-template-columns: auto 450px;
gap: var(--gap-m);
height: calc(100vh - var(--header-page-padding) - var(--header-height) - var(--gap-s));
}
.video-content video {
max-height: 230px;
width: 100vw;
max-width: 100vw;
background: #000;
.stream-page .video-content {
overflow-y: auto;
height: fit-content;
gap: var(--gap-s);
display: flex;
flex-direction: column;
}
.live-chat {
max-width: calc(100vw - 32px);
.stream-page .video-content video {
width: 100%;
}
.stream-page .live-chat {
padding: 24px 16px 8px 24px;
border: 1px solid #171717;
border-radius: 24px;
height: calc(100vh - var(--header-page-padding) - var(--header-height) - var(--gap-s) - 24px - 8px);
}
@media (max-width: 1020px) {
.stream-page {
display: flex;
flex-direction: column;
height: calc(100vh - var(--header-page-padding) - var(--header-height) - var(--gap-s));
}
.stream-page .video-content {
overflow-y: visible;
}
.stream-page .live-chat {
border-radius: 0;
border: 0;
padding: 8px 16px;
height: unset;
min-height: 0;
}
.stream-page .live-chat .top-zappers h3,
.stream-page .live-chat .header {
display: none;
}
.stream-page .info {
flex-direction: column;
}
.stream-page .stream-info {
display: none;
}
.stream-page .profile-info {
width: calc(100% - 32px);
}
}
.profile-info {
display: flex;
justify-content: space-between;
padding: 0 16px;
gap: 24px;
gap: var(--gap-m);
}
.profile-info .btn {
padding: 12px 16px;
}
@media (min-width: 768px) {
.video-content {
height: calc(100vh - 64px);
}
.video-content video {
max-height: unset;
}
.profile-info {
max-height: 42px;
}
}
.pill {
font-weight: 700;
font-size: 14px;
@ -55,53 +89,6 @@
background: rgba(23, 23, 23, 0.7);
}
@media (min-width: 1020px) {
.info {
display: flex;
align-items: flex-start;
justify-content: space-between;
}
.video-content video {
width: unset;
}
.profile-info {
width: unset;
}
}
.live-chat .header {
display: none;
}
.stream-info {
display: none;
}
@media (min-width: 1020px) {
.live-chat .header {
display: block;
}
.stream-info {
display: block;
}
.video-content {
height: 100%;
}
.live-chat {
margin-left: 32px;
}
}
.info {
grid-area: profile;
margin-top: 8px;
}
.info h1 {
margin: 0 0 8px 0;
font-weight: 600;

View File

@ -45,7 +45,7 @@ function ProfileInfo({ ev, goal }: { ev?: NostrEvent; goal?: TaggedRawEvent }) {
const viewers = Number(findTag(ev, "current_participants") ?? "0");
return (
<>
<div className="flex info">
<div className="flex f-center info">
<div className="f-grow stream-info">
<h1>{findTag(ev, "title")}</h1>
<p>{findTag(ev, "summary")}</p>
@ -76,7 +76,7 @@ function ProfileInfo({ ev, goal }: { ev?: NostrEvent; goal?: TaggedRawEvent }) {
</div>
)}
</div>
<div className="profile-info w-max">
<div className="profile-info">
<Profile pubkey={host ?? ""} />
<div className="flex g12">
{ev && (
@ -100,18 +100,6 @@ function ProfileInfo({ ev, goal }: { ev?: NostrEvent; goal?: TaggedRawEvent }) {
);
}
function VideoPlayer({ ev }: { ev?: NostrEvent }) {
const stream = findTag(ev, "streaming");
const image = findTag(ev, "image");
const status = findTag(ev, "status");
return (
<div className="video-content">
<LiveVideoPlayer stream={stream} poster={image} status={status} />
</div>
);
}
export function StreamPage() {
const params = useParams();
const link = parseNostrLink(params.id!);
@ -122,6 +110,7 @@ export function StreamPage() {
const title = findTag(ev, "title");
const summary = findTag(ev, "summary");
const image = findTag(ev, "image");
const stream = findTag(ev, "streaming");
const tags = ev?.tags.filter((a) => a[0] === "t").map((a) => a[1]) ?? [];
const descriptionContent = [
@ -130,7 +119,7 @@ export function StreamPage() {
...tags,
].join(", ");
return (
<>
<div className="stream-page">
<Helmet>
<title>{`${title} - zap.stream`}</title>
<meta name="description" content={descriptionContent} />
@ -143,9 +132,11 @@ export function StreamPage() {
<meta property="og:description" content={descriptionContent} />
<meta property="og:image" content={image ?? ""} />
</Helmet>
<VideoPlayer ev={ev} />
<ProfileInfo ev={ev} goal={goal} />
<div className="video-content">
<LiveVideoPlayer stream={stream} poster={image} status={status} />
<ProfileInfo ev={ev} goal={goal} />
</div>
<LiveChat link={link} ev={ev} goal={goal} />
</>
</div>
);
}