This commit is contained in:
2023-07-18 16:14:38 +01:00
parent d41b485eb2
commit 06b9dba09b
28 changed files with 522 additions and 503 deletions

View File

@ -1,5 +1,5 @@
.link-preview-container {
border-radius: 0px 0px 12px 12px;
border-radius: 12px;
background: #151515;
overflow: hidden;
}
@ -14,11 +14,26 @@
.link-preview-title {
padding: 0 10px 10px 10px;
line-height: 21px;
}
.link-preview-title > h1 {
padding: 0;
font-size: 16px;
font-weight: 700;
}
.link-preview-container:hover .link-preview-title > h1 {
color: var(--highlight);
}
.link-preview-title > small {
color: var(--font-secondary-color);
font-size: small;
font-size: 14px;
}
.link-preview-title > small.host {
font-size: 12px;
}
.link-preview-image {
@ -30,3 +45,7 @@
background-size: cover;
background-position: center;
}
.light .link-preview-container {
background: #ddd;
}

View File

@ -73,15 +73,12 @@ const LinkPreview = ({ url }: { url: string }) => {
{preview && (
<a href={url} onClick={e => e.stopPropagation()} target="_blank" rel="noreferrer" className="ext">
{previewElement()}
<p className="link-preview-title">
{preview?.title}
{preview?.description && (
<>
<br />
<small>{preview.description.slice(0, 160)}</small>
</>
)}
</p>
<div className="link-preview-title">
<h1>{preview?.title}</h1>
{preview?.description && <small>{preview.description.slice(0, 160)}</small>}
<br />
<small className="host">{new URL(url).host}</small>
</div>
</a>
)}
{!preview && <Spinner className="f-center" />}

View File

@ -1,47 +0,0 @@
.live-chat {
height: calc(100vh - 100px);
display: flex;
flex-direction: column;
}
.live-chat > div:nth-child(1) {
font-size: 24px;
line-height: 29px;
font-weight: bold;
}
.live-chat > div:nth-child(2) {
flex-grow: 1;
display: flex;
gap: 16px;
flex-direction: column-reverse;
margin-block-end: 20px;
overflow-y: auto;
}
.live-chat > div:nth-child(3) {
display: flex;
gap: 10px;
}
.live-chat .message {
display: inline-flex;
align-items: center;
gap: 8px;
}
.live-chat .message .name {
display: inline-flex;
align-items: center;
color: var(--highlight);
font-weight: 600;
cursor: pointer;
user-select: none;
}
.live-chat .message .avatar {
width: 24px;
height: 24px;
display: inline-block;
margin-right: 8px;
}

View File

@ -1,92 +0,0 @@
import "./LiveChat.css";
import { EventKind, NostrLink, TaggedNostrEvent } from "@snort/system";
import { useUserProfile } from "@snort/system-react";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { FormattedMessage, useIntl } from "react-intl";
import Textarea from "Element/Textarea";
import { useLiveChatFeed } from "Feed/LiveChatFeed";
import useEventPublisher from "Feed/EventPublisher";
import { getDisplayName } from "Element/ProfileImage";
import Avatar from "Element/Avatar";
import AsyncButton from "Element/AsyncButton";
import Text from "Element/Text";
import { System } from "index";
import { profileLink } from "SnortUtils";
export function LiveChat({ ev, link }: { ev: TaggedNostrEvent; link: NostrLink }) {
const [chat, setChat] = useState("");
const messages = useLiveChatFeed(link);
const pub = useEventPublisher();
const { formatMessage } = useIntl();
async function sendChatMessage() {
if (chat.length > 1) {
const reply = await pub?.generic(eb => {
return eb
.kind(1311 as EventKind)
.content(chat)
.tag(["a", `${link.kind}:${link.author}:${link.id}`])
.processContent();
});
if (reply) {
console.debug(reply);
System.BroadcastEvent(reply);
}
setChat("");
}
}
return (
<div className="live-chat">
<div>
<FormattedMessage defaultMessage="Stream Chat" />
</div>
<div>
{[...(messages.data ?? [])]
.sort((a, b) => b.created_at - a.created_at)
.map(a => (
<ChatMessage ev={a} key={a.id} />
))}
</div>
<div>
<Textarea
autoFocus={false}
className=""
onChange={v => setChat(v.target.value)}
value={chat}
onFocus={() => {}}
placeholder={formatMessage({
defaultMessage: "Message...",
})}
onKeyDown={async e => {
if (e.code === "Enter") {
e.preventDefault();
await sendChatMessage();
}
}}
/>
<AsyncButton onClick={sendChatMessage}>
<FormattedMessage defaultMessage="Send" />
</AsyncButton>
</div>
</div>
);
}
function ChatMessage({ ev }: { ev: TaggedNostrEvent }) {
const profile = useUserProfile(System, ev.pubkey);
const navigate = useNavigate();
return (
<div className="message">
<div className="name" onClick={() => navigate(profileLink(ev.pubkey, ev.relays))}>
<Avatar user={profile} />
{getDisplayName(profile, ev.pubkey)}:
</div>
<span>
<Text disableMedia={true} content={ev.content} creator={ev.pubkey} tags={ev.tags} />
</span>
</div>
);
}

View File

@ -13,7 +13,7 @@ import { useWallet } from "Wallet";
import { PaymentsCache } from "Cache";
import { Payment } from "Db";
import PageSpinner from "Element/PageSpinner";
import { LiveVideoPlayer } from "Element/LiveVideoPlayer";
/*
[
"imeta",
@ -183,9 +183,6 @@ export function MediaElement(props: MediaElementProps) {
} else if (props.mime.startsWith("audio/")) {
return <audio key={props.url} src={url} controls onError={() => probeFor402()} />;
} else if (props.mime.startsWith("video/")) {
if (props.url.endsWith(".m3u8")) {
return <LiveVideoPlayer stream={props.url} />;
}
return <video key={props.url} src={url} controls onError={() => probeFor402()} />;
} else {
return (

View File

@ -1,5 +1,8 @@
.note {
min-height: 110px;
display: flex;
flex-direction: column;
gap: 12px;
}
.note:hover {
@ -64,30 +67,13 @@
padding: 5px;
}
.note-quote.note > .body {
padding-left: 0;
}
.note > .body .text-frag {
padding-left: 61px;
}
.note > .body .text-frag {
text-overflow: ellipsis;
white-space: pre-wrap;
word-break: normal;
overflow-x: hidden;
overflow-y: visible;
}
.note > .body img,
.note > .body video,
.note > .body audio {
margin-top: 16px;
}
.note > .footer {
padding: 16px 0 0px 61px;
display: inline;
}
.note .footer .footer-reactions {

View File

@ -98,7 +98,7 @@ export default function Note(props: NoteProps) {
const deletions = useMemo(() => getReactions(related, ev.id, EventKind.Deletion), [related]);
const { isMuted } = useModeration();
const isOpMuted = isMuted(ev?.pubkey);
const { ref, inView, entry } = useInView({ triggerOnce: true });
const { ref, inView } = useInView({ triggerOnce: true });
const login = useLogin();
const { pinned, bookmarked } = login;
const publisher = useEventPublisher();

View File

@ -36,7 +36,7 @@ export function NoteContextMenu({ ev, ...props }: NosteContextMenuProps) {
const dispatch = useDispatch();
const { formatMessage } = useIntl();
const login = useLogin();
const { pinned, bookmarked, publicKey, preferences: prefs, relays } = login;
const { pinned, bookmarked, publicKey, preferences: prefs } = login;
const { mute, block } = useModeration();
const publisher = useEventPublisher();
const showReBroadcastModal = useSelector((s: RootState) => s.reBroadcast.show);

View File

@ -244,9 +244,7 @@ export default function NoteFooter(props: NoteFooterProps) {
allocatePool={true}
/>
</div>
<div className="zaps-container">
<ZapsSummary zaps={zaps} />
</div>
<ZapsSummary zaps={zaps} />
</>
);
}

View File

@ -2,7 +2,7 @@ import { NostrEvent } from "@snort/system";
import { FormattedMessage, FormattedNumber } from "react-intl";
import { LNURL } from "@snort/shared";
import { dedupe, hexToBech32, unixNow } from "SnortUtils";
import { dedupe, hexToBech32 } from "SnortUtils";
import FollowListBase from "Element/FollowListBase";
import AsyncButton from "Element/AsyncButton";
import { useWallet } from "Wallet";

View File

@ -5,7 +5,6 @@ import { useIntl, FormattedMessage } from "react-intl";
import { HexKey, NostrEvent, EventPublisher } from "@snort/system";
import { LNURL, LNURLError, LNURLErrorCode, LNURLInvoice, LNURLSuccessAction } from "@snort/shared";
import { System } from "index";
import { formatShort } from "Number";
import Icon from "Icons/Icon";
import useEventPublisher from "Feed/EventPublisher";

View File

@ -2,11 +2,9 @@
display: flex;
align-items: center;
flex-direction: row;
overflow-x: scroll;
-ms-overflow-style: none; /* for Internet Explorer, Edge */
scrollbar-width: none; /* Firefox */
margin-bottom: 18px;
white-space: nowrap;
text-align: center;
user-select: none;
}
.tabs::-webkit-scrollbar {
@ -14,22 +12,16 @@
}
.tab {
flex: 1;
padding: 16px;
color: var(--font-tertiary-color);
border: 1px solid var(--border-color);
border-radius: 16px;
font-weight: 600;
font-size: 14px;
padding: 6px 12px;
text-align: center;
font-feature-settings: "tnum";
}
.tab:not(:last-of-type) {
margin-right: 8px;
font-weight: 500;
font-size: 16px;
letter-spacing: 0.2px;
}
.tab.active {
border-color: var(--font-color);
border-bottom: 1px solid var(--highlight);
color: var(--font-color);
}
@ -44,5 +36,5 @@
}
.tab:hover {
border-color: var(--font-color);
border-color: var(--highlight);
}

View File

@ -21,7 +21,7 @@ interface TabElementProps extends Omit<TabsProps, "tabs"> {
export const TabElement = ({ t, tab, setTab }: TabElementProps) => {
return (
<div
className={`tab ${tab.value === t.value ? "active" : ""} ${t.disabled ? "disabled" : ""}`}
className={`tab${tab.value === t.value ? " active" : ""}${t.disabled ? " disabled" : ""}`}
onClick={() => !t.disabled && setTab(t)}>
{t.text}
</div>

View File

@ -45,10 +45,8 @@
}
.zaps-summary {
margin-top: 8px;
display: flex;
flex-direction: row;
margin-left: 56px;
}
.note.thread-root .zaps-summary {