spotlight media & thread modals
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
fabf0f372f
commit
8dc0c28377
@ -3,12 +3,13 @@ import ProfileImage from "@/Element/User/ProfileImage";
|
|||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import Icon from "@/Icons/Icon";
|
import Icon from "@/Icons/Icon";
|
||||||
import { NostrLink, TaggedNostrEvent } from "@snort/system";
|
import { NostrLink, TaggedNostrEvent } from "@snort/system";
|
||||||
import { ReactNode } from "react";
|
import { ReactNode, useState } from "react";
|
||||||
import { TimelineFragment } from "@/Element/Feed/TimelineFragment";
|
import { TimelineFragment } from "@/Element/Feed/TimelineFragment";
|
||||||
import { transformTextCached } from "@/Hooks/useTextTransformCache";
|
import { transformTextCached } from "@/Hooks/useTextTransformCache";
|
||||||
import useImgProxy from "@/Hooks/useImgProxy";
|
import useImgProxy from "@/Hooks/useImgProxy";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { DisplayAs } from "@/Element/Feed/DisplayAsSelector";
|
import { DisplayAs } from "@/Element/Feed/DisplayAsSelector";
|
||||||
|
import { SpotlightThreadModal } from "@/Element/Spotlight/SpotlightThreadModal";
|
||||||
|
|
||||||
export interface TimelineRendererProps {
|
export interface TimelineRendererProps {
|
||||||
frags: Array<TimelineFragment>;
|
frags: Array<TimelineFragment>;
|
||||||
@ -27,6 +28,7 @@ export interface TimelineRendererProps {
|
|||||||
export function TimelineRenderer(props: TimelineRendererProps) {
|
export function TimelineRenderer(props: TimelineRendererProps) {
|
||||||
const { ref, inView } = useInView();
|
const { ref, inView } = useInView();
|
||||||
const { proxy } = useImgProxy();
|
const { proxy } = useImgProxy();
|
||||||
|
const [modalThread, setModalThread] = useState<NostrLink | undefined>(undefined);
|
||||||
|
|
||||||
const renderNotes = () => {
|
const renderNotes = () => {
|
||||||
return props.frags.map(frag => (
|
return props.frags.map(frag => (
|
||||||
@ -57,6 +59,9 @@ export function TimelineRenderer(props: TimelineRendererProps) {
|
|||||||
if (props.noteOnClick) {
|
if (props.noteOnClick) {
|
||||||
props.noteOnClick(e);
|
props.noteOnClick(e);
|
||||||
clickEvent.preventDefault();
|
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()}
|
{props.displayAs === "grid" ? renderGrid() : renderNotes()}
|
||||||
|
{modalThread && (
|
||||||
|
<SpotlightThreadModal
|
||||||
|
thread={modalThread}
|
||||||
|
onClose={() => setModalThread(undefined)}
|
||||||
|
onBack={() => setModalThread(undefined)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { ReactNode, useEffect } from "react";
|
|||||||
export interface ModalProps {
|
export interface ModalProps {
|
||||||
id: string;
|
id: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
bodyClassName?: string;
|
||||||
onClose?: (e: React.MouseEvent | KeyboardEvent) => void;
|
onClose?: (e: React.MouseEvent | KeyboardEvent) => void;
|
||||||
onClick?: (e: React.MouseEvent) => void;
|
onClick?: (e: React.MouseEvent) => void;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@ -60,7 +61,7 @@ export default function Modal(props: ModalProps) {
|
|||||||
|
|
||||||
return createPortal(
|
return createPortal(
|
||||||
<div className={`modal${props.className ? ` ${props.className}` : ""}`} onClick={props.onClose}>
|
<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
|
<div
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
@ -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;
|
|
||||||
}
|
|
@ -1,4 +1,3 @@
|
|||||||
import "./SpotlightMedia.css";
|
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import Modal from "@/Element/Modal";
|
import Modal from "@/Element/Modal";
|
||||||
import Icon from "@/Icons/Icon";
|
import Icon from "@/Icons/Icon";
|
||||||
@ -60,16 +59,16 @@ export function SpotlightMedia(props: SpotlightMediaProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="spotlight">
|
<>
|
||||||
<ProxyImg src={image} />
|
<ProxyImg src={image} className="max-h-screen max-w-full" />
|
||||||
<div className="details">
|
<div className="select-none absolute flex flex-row items-center gap-4 cursor-pointer left-0 top-0 p-4">
|
||||||
{props.images.length > 1 && `${idx + 1}/${props.images.length}`}
|
|
||||||
<Icon name="x-close" size={24} onClick={props.onClose} />
|
<Icon name="x-close" size={24} onClick={props.onClose} />
|
||||||
|
{props.images.length > 1 && `${idx + 1}/${props.images.length}`}
|
||||||
</div>
|
</div>
|
||||||
{props.images.length > 1 && (
|
{props.images.length > 1 && (
|
||||||
<>
|
<>
|
||||||
<Icon
|
<Icon
|
||||||
className="left"
|
className="absolute left-2 top-1/2 rotate-180 cursor-pointer"
|
||||||
name="arrowFront"
|
name="arrowFront"
|
||||||
size={24}
|
size={24}
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
@ -78,7 +77,7 @@ export function SpotlightMedia(props: SpotlightMediaProps) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Icon
|
<Icon
|
||||||
className="right"
|
className="absolute right-2 top-1/2 cursor-pointer"
|
||||||
name="arrowFront"
|
name="arrowFront"
|
||||||
size={24}
|
size={24}
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
@ -88,13 +87,18 @@ export function SpotlightMedia(props: SpotlightMediaProps) {
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SpotlightMediaModal(props: SpotlightMediaProps) {
|
export function SpotlightMediaModal(props: SpotlightMediaProps) {
|
||||||
return (
|
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} />
|
<SpotlightMedia {...props} />
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
@ -11,11 +11,15 @@ export function SpotlightThreadModal(props: { thread: NostrLink; onClose?: () =>
|
|||||||
const onBack = () => props.onBack?.();
|
const onBack = () => props.onBack?.();
|
||||||
|
|
||||||
return (
|
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}>
|
<ThreadContextWrapper link={props.thread}>
|
||||||
<SpotlightFromThread onClose={onClose} />
|
<div className="flex flex-row h-screen w-screen">
|
||||||
<div>
|
<div className="flex w-2/3 items-center justify-center overflow-hidden">
|
||||||
<Thread onBack={onBack} disableSpotlight={true} />
|
<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>
|
</div>
|
||||||
</ThreadContextWrapper>
|
</ThreadContextWrapper>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -36,59 +36,3 @@
|
|||||||
.deck-layout .deck-cols > div > div:not(:first-of-type) {
|
.deck-layout .deck-cols > div > div:not(:first-of-type) {
|
||||||
overflow-y: scroll;
|
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);
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user