spotlight media & thread modals
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Martti Malmi 2023-12-06 11:29:14 +02:00
parent fabf0f372f
commit 8dc0c28377
6 changed files with 36 additions and 117 deletions

View File

@ -3,12 +3,13 @@ import ProfileImage from "@/Element/User/ProfileImage";
import { FormattedMessage } from "react-intl";
import Icon from "@/Icons/Icon";
import { NostrLink, TaggedNostrEvent } from "@snort/system";
import { ReactNode } from "react";
import { ReactNode, useState } from "react";
import { TimelineFragment } from "@/Element/Feed/TimelineFragment";
import { transformTextCached } from "@/Hooks/useTextTransformCache";
import useImgProxy from "@/Hooks/useImgProxy";
import { Link } from "react-router-dom";
import { DisplayAs } from "@/Element/Feed/DisplayAsSelector";
import { SpotlightThreadModal } from "@/Element/Spotlight/SpotlightThreadModal";
export interface TimelineRendererProps {
frags: Array<TimelineFragment>;
@ -27,6 +28,7 @@ export interface TimelineRendererProps {
export function TimelineRenderer(props: TimelineRendererProps) {
const { ref, inView } = useInView();
const { proxy } = useImgProxy();
const [modalThread, setModalThread] = useState<NostrLink | undefined>(undefined);
const renderNotes = () => {
return props.frags.map(frag => (
@ -57,6 +59,9 @@ export function TimelineRenderer(props: TimelineRendererProps) {
if (props.noteOnClick) {
props.noteOnClick(e);
clickEvent.preventDefault();
} else if (window.innerWidth >= 768) {
setModalThread(NostrLink.fromEvent(e));
clickEvent.preventDefault();
}
};
@ -118,6 +123,13 @@ export function TimelineRenderer(props: TimelineRendererProps) {
</>
)}
{props.displayAs === "grid" ? renderGrid() : renderNotes()}
{modalThread && (
<SpotlightThreadModal
thread={modalThread}
onClose={() => setModalThread(undefined)}
onBack={() => setModalThread(undefined)}
/>
)}
</>
);
}

View File

@ -5,6 +5,7 @@ import { ReactNode, useEffect } from "react";
export interface ModalProps {
id: string;
className?: string;
bodyClassName?: string;
onClose?: (e: React.MouseEvent | KeyboardEvent) => void;
onClick?: (e: React.MouseEvent) => void;
children: ReactNode;
@ -60,7 +61,7 @@ export default function Modal(props: ModalProps) {
return createPortal(
<div className={`modal${props.className ? ` ${props.className}` : ""}`} onClick={props.onClose}>
<div className="modal-body" onClick={props.onClose}>
<div className={props.bodyClassName || "modal-body"} onClick={props.onClose}>
<div
onClick={e => {
e.stopPropagation();

View File

@ -1,46 +0,0 @@
.modal.spotlight .modal-body {
border: none;
border-radius: unset;
width: unset;
height: unset;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
}
.spotlight img,
.spotlight video {
max-width: 100vw !important;
max-height: 99vh !important;
aspect-ratio: unset !important;
width: unset !important;
}
.spotlight .details {
text-align: right;
position: absolute;
top: 28px;
right: 28px;
gap: 18px;
display: flex;
font-size: 15px;
font-weight: 400;
line-height: 24px;
align-items: center;
user-select: none;
}
.spotlight .left {
position: absolute;
left: 24px;
top: 50vh;
transform: rotate(180deg);
}
.spotlight .right {
position: absolute;
right: 24px;
top: 50vh;
}

View File

@ -1,4 +1,3 @@
import "./SpotlightMedia.css";
import { useEffect, useMemo, useState } from "react";
import Modal from "@/Element/Modal";
import Icon from "@/Icons/Icon";
@ -60,16 +59,16 @@ export function SpotlightMedia(props: SpotlightMediaProps) {
}
return (
<div className="spotlight">
<ProxyImg src={image} />
<div className="details">
{props.images.length > 1 && `${idx + 1}/${props.images.length}`}
<>
<ProxyImg src={image} className="max-h-screen max-w-full" />
<div className="select-none absolute flex flex-row items-center gap-4 cursor-pointer left-0 top-0 p-4">
<Icon name="x-close" size={24} onClick={props.onClose} />
{props.images.length > 1 && `${idx + 1}/${props.images.length}`}
</div>
{props.images.length > 1 && (
<>
<Icon
className="left"
className="absolute left-2 top-1/2 rotate-180 cursor-pointer"
name="arrowFront"
size={24}
onClick={e => {
@ -78,7 +77,7 @@ export function SpotlightMedia(props: SpotlightMediaProps) {
}}
/>
<Icon
className="right"
className="absolute right-2 top-1/2 cursor-pointer"
name="arrowFront"
size={24}
onClick={e => {
@ -88,13 +87,18 @@ export function SpotlightMedia(props: SpotlightMediaProps) {
/>
</>
)}
</div>
</>
);
}
export function SpotlightMediaModal(props: SpotlightMediaProps) {
return (
<Modal id="spotlight" onClick={props.onClose} onClose={props.onClose} className="spotlight">
<Modal
id="spotlight"
onClick={props.onClose}
onClose={props.onClose}
className="spotlight"
bodyClassName="h-screen w-screen flex items-center justify-center">
<SpotlightMedia {...props} />
</Modal>
);

View File

@ -11,11 +11,15 @@ export function SpotlightThreadModal(props: { thread: NostrLink; onClose?: () =>
const onBack = () => props.onBack?.();
return (
<Modal id="thread-overlay" onClose={onClose} className="thread-overlay thread">
<Modal id="thread-overlay" onClose={onClose} bodyClassName={"flex flex-1"}>
<ThreadContextWrapper link={props.thread}>
<SpotlightFromThread onClose={onClose} />
<div>
<Thread onBack={onBack} disableSpotlight={true} />
<div className="flex flex-row h-screen w-screen">
<div className="flex w-2/3 items-center justify-center overflow-hidden">
<SpotlightFromThread onClose={onClose} />
</div>
<div className="flex w-1/3 flex-shrink-0 overflow-y-auto bg-bg-color">
<Thread onBack={onBack} disableSpotlight={true} />
</div>
</div>
</ThreadContextWrapper>
</Modal>

View File

@ -36,59 +36,3 @@
.deck-layout .deck-cols > div > div:not(:first-of-type) {
overflow-y: scroll;
}
.modal.thread-overlay > .modal-body {
background-color: unset;
padding: 0;
width: 100vw;
height: 100vh;
--border-color: #3a3a3a;
}
.modal.thread-overlay > .modal-body > div {
display: flex;
flex-direction: row;
border-radius: unset;
justify-content: center;
gap: 16px;
}
.modal.thread-overlay.thread > .modal-body > div > div:last-of-type {
width: 550px;
min-width: 550px;
height: 100vh;
overflow-y: auto;
background-color: var(--gray-superdark);
}
.modal.thread-overlay.long-form > .modal-body > div > div:last-of-type {
width: 660px;
height: calc(100vh - 48px);
padding: 48px 56px 0 56px;
overflow-y: auto;
background-color: var(--gray-superdark);
}
.thread-overlay .spotlight {
flex-grow: 1;
margin: auto;
text-align: center;
}
.thread-overlay .spotlight .details {
right: calc(28px + 550px + 16px);
}
.thread-overlay .spotlight .right {
right: calc(24px + 550px + 16px);
}
.thread-overlay .spotlight img,
.thread-overlay .spotlight video {
max-width: calc(100vw - 550px - 16px);
}
.thread-overlay .main-content {
border: 0;
border-bottom: 1px solid var(--border-color);
}