parent
c0cf92ebf3
commit
efa765ea84
@ -1,9 +1,7 @@
|
|||||||
import "./NoteCreator.css";
|
import "./NoteCreator.css";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import Attachment from "Icons/Attachment";
|
import Attachment from "Icons/Attachment";
|
||||||
import Plus from "Icons/Plus";
|
|
||||||
import useEventPublisher from "Feed/EventPublisher";
|
import useEventPublisher from "Feed/EventPublisher";
|
||||||
import { openFile } from "Util";
|
import { openFile } from "Util";
|
||||||
import Textarea from "Element/Textarea";
|
import Textarea from "Element/Textarea";
|
||||||
@ -29,110 +27,107 @@ function NotePreview({ note }: NotePreviewProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface NoteCreatorProps {
|
export interface NoteCreatorProps {
|
||||||
show: boolean
|
show: boolean
|
||||||
setShow: (s: boolean) => void
|
setShow: (s: boolean) => void
|
||||||
replyTo?: NEvent,
|
replyTo?: NEvent,
|
||||||
onSend?: Function,
|
onSend?: Function,
|
||||||
autoFocus: boolean
|
autoFocus: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NoteCreator(props: NoteCreatorProps) {
|
export function NoteCreator(props: NoteCreatorProps) {
|
||||||
const { show, setShow, replyTo, onSend, autoFocus } = props
|
const { show, setShow, replyTo, onSend, autoFocus } = props
|
||||||
const publisher = useEventPublisher();
|
const publisher = useEventPublisher();
|
||||||
const [note, setNote] = useState<string>();
|
const [note, setNote] = useState<string>();
|
||||||
const [error, setError] = useState<string>();
|
const [error, setError] = useState<string>();
|
||||||
const [active, setActive] = useState<boolean>(false);
|
const [active, setActive] = useState<boolean>(false);
|
||||||
const uploader = useFileUpload();
|
const uploader = useFileUpload();
|
||||||
const hasErrors = (error?.length ?? 0) > 0
|
const hasErrors = (error?.length ?? 0) > 0
|
||||||
|
|
||||||
async function sendNote() {
|
async function sendNote() {
|
||||||
if (note) {
|
if (note) {
|
||||||
let ev = replyTo ? await publisher.reply(replyTo, note) : await publisher.note(note);
|
let ev = replyTo ? await publisher.reply(replyTo, note) : await publisher.note(note);
|
||||||
console.debug("Sending note: ", ev);
|
console.debug("Sending note: ", ev);
|
||||||
publisher.broadcast(ev);
|
publisher.broadcast(ev);
|
||||||
setNote("");
|
setNote("");
|
||||||
setShow(false);
|
setShow(false);
|
||||||
if (typeof onSend === "function") {
|
if (typeof onSend === "function") {
|
||||||
onSend();
|
onSend();
|
||||||
}
|
}
|
||||||
setActive(false);
|
setActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function attachFile() {
|
||||||
|
try {
|
||||||
|
let file = await openFile();
|
||||||
|
if (file) {
|
||||||
|
let rx = await uploader.upload(file, file.name);
|
||||||
|
if (rx.url) {
|
||||||
|
setNote(n => `${n ? `${n}\n` : ""}${rx.url}`);
|
||||||
|
} else if (rx?.error) {
|
||||||
|
setError(rx.error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
setError(error?.message)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function attachFile() {
|
function onChange(ev: any) {
|
||||||
try {
|
const { value } = ev.target
|
||||||
let file = await openFile();
|
setNote(value)
|
||||||
if (file) {
|
if (value) {
|
||||||
let rx = await uploader.upload(file, file.name);
|
setActive(true)
|
||||||
if (rx.url) {
|
} else {
|
||||||
setNote(n => `${n ? `${n}\n` : ""}${rx.url}`);
|
setActive(false)
|
||||||
} else if (rx?.error) {
|
|
||||||
setError(rx.error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
setError(error?.message)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onChange(ev: any) {
|
function cancel(ev: any) {
|
||||||
const { value } = ev.target
|
setShow(false)
|
||||||
setNote(value)
|
setNote("")
|
||||||
if (value) {
|
}
|
||||||
setActive(true)
|
|
||||||
} else {
|
|
||||||
setActive(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancel(ev: any) {
|
function onSubmit(ev: React.MouseEvent<HTMLButtonElement>) {
|
||||||
setShow(false)
|
ev.stopPropagation();
|
||||||
setNote("")
|
sendNote().catch(console.warn);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSubmit(ev: React.MouseEvent<HTMLButtonElement>) {
|
return (
|
||||||
ev.stopPropagation();
|
<>
|
||||||
sendNote().catch(console.warn);
|
{show && (
|
||||||
}
|
<Modal
|
||||||
|
className="note-creator-modal"
|
||||||
return (
|
onClose={() => setShow(false)}
|
||||||
<>
|
>
|
||||||
<button className="note-create-button" type="button" onClick={() => setShow(!show)}>
|
{replyTo && (
|
||||||
<Plus />
|
<NotePreview note={replyTo} />
|
||||||
</button>
|
)}
|
||||||
{show && (
|
<div className={`flex note-creator ${replyTo ? 'note-reply' : ''}`}>
|
||||||
<Modal
|
<div className="flex f-col mr10 f-grow">
|
||||||
className="note-creator-modal"
|
<Textarea
|
||||||
onClose={() => setShow(false)}
|
autoFocus={autoFocus}
|
||||||
>
|
className={`textarea ${active ? "textarea--focused" : ""}`}
|
||||||
{replyTo && (
|
onChange={onChange}
|
||||||
<NotePreview note={replyTo} />
|
value={note}
|
||||||
)}
|
onFocus={() => setActive(true)}
|
||||||
<div className={`flex note-creator ${replyTo ? 'note-reply' : ''}`}>
|
/>
|
||||||
<div className="flex f-col mr10 f-grow">
|
<button type="button" className="attachment" onClick={(e) => attachFile()}>
|
||||||
<Textarea
|
<Attachment />
|
||||||
autoFocus={autoFocus}
|
</button>
|
||||||
className={`textarea ${active ? "textarea--focused" : ""}`}
|
|
||||||
onChange={onChange}
|
|
||||||
value={note}
|
|
||||||
onFocus={() => setActive(true)}
|
|
||||||
/>
|
|
||||||
<button type="button" className="attachment" onClick={(e) => attachFile()}>
|
|
||||||
<Attachment />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{hasErrors && <span className="error">{error}</span>}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="note-creator-actions">
|
{hasErrors && <span className="error">{error}</span>}
|
||||||
<button className="secondary" type="button" onClick={cancel}>
|
</div>
|
||||||
Cancel
|
<div className="note-creator-actions">
|
||||||
</button>
|
<button className="secondary" type="button" onClick={cancel}>
|
||||||
<button type="button" onClick={onSubmit}>
|
Cancel
|
||||||
{replyTo ? 'Reply' : 'Send'}
|
</button>
|
||||||
</button>
|
<button type="button" onClick={onSubmit}>
|
||||||
</div>
|
{replyTo ? 'Reply' : 'Send'}
|
||||||
</Modal>
|
</button>
|
||||||
)}
|
</div>
|
||||||
</>
|
</Modal>
|
||||||
);
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import "./Layout.css";
|
import "./Layout.css";
|
||||||
import { useEffect } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { Outlet, useNavigate } from "react-router-dom";
|
import { Outlet, useNavigate } from "react-router-dom";
|
||||||
import Envelope from "Icons/Envelope";
|
import Envelope from "Icons/Envelope";
|
||||||
@ -18,9 +18,12 @@ import useModeration from "Hooks/useModeration";
|
|||||||
import { IndexedUDB, useDb } from "State/Users/Db";
|
import { IndexedUDB, useDb } from "State/Users/Db";
|
||||||
import { db } from "Db";
|
import { db } from "Db";
|
||||||
import { bech32ToHex } from "Util";
|
import { bech32ToHex } from "Util";
|
||||||
|
import { NoteCreator } from "Element/NoteCreator";
|
||||||
|
import Plus from "Icons/Plus";
|
||||||
|
|
||||||
|
|
||||||
export default function Layout() {
|
export default function Layout() {
|
||||||
|
const [show, setShow] = useState(false)
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { loggedOut, publicKey, relays, notifications, readNotifications, dms, preferences, newUserKey } = useSelector((s: RootState) => s.login);
|
const { loggedOut, publicKey, relays, notifications, readNotifications, dms, preferences, newUserKey } = useSelector((s: RootState) => s.login);
|
||||||
@ -174,8 +177,12 @@ export default function Layout() {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<Outlet />
|
<Outlet />
|
||||||
|
|
||||||
|
<button className="note-create-button" type="button" onClick={() => setShow(!show)}>
|
||||||
|
<Plus />
|
||||||
|
</button>
|
||||||
|
<NoteCreator replyTo={undefined} autoFocus={true} show={show} setShow={setShow} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import { useSelector } from "react-redux";
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
import { RootState } from "State/Store";
|
import { RootState } from "State/Store";
|
||||||
import { NoteCreator } from "Element/NoteCreator";
|
|
||||||
import Timeline from "Element/Timeline";
|
import Timeline from "Element/Timeline";
|
||||||
import { HexKey } from "Nostr";
|
import { HexKey } from "Nostr";
|
||||||
import { TimelineSubject } from "Feed/TimelineFeed";
|
import { TimelineSubject } from "Feed/TimelineFeed";
|
||||||
@ -16,7 +15,6 @@ const RootTab = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function RootPage() {
|
export default function RootPage() {
|
||||||
const [show, setShow] = useState(false)
|
|
||||||
const [loggedOut, pubKey, follows] = useSelector<RootState, [boolean | undefined, HexKey | undefined, HexKey[]]>(s => [s.login.loggedOut, s.login.publicKey, s.login.follows]);
|
const [loggedOut, pubKey, follows] = useSelector<RootState, [boolean | undefined, HexKey | undefined, HexKey[]]>(s => [s.login.loggedOut, s.login.publicKey, s.login.follows]);
|
||||||
const [tab, setTab] = useState(RootTab.Posts);
|
const [tab, setTab] = useState(RootTab.Posts);
|
||||||
|
|
||||||
@ -45,8 +43,7 @@ export default function RootPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div></> : null}
|
</div></> : null}
|
||||||
{followHints()}
|
{followHints()}
|
||||||
<Timeline key={tab} subject={timelineSubect} postsOnly={tab === RootTab.Posts} method={"TIME_RANGE"} window={tab === RootTab.Global ? 60 : undefined}/>
|
<Timeline key={tab} subject={timelineSubect} postsOnly={tab === RootTab.Posts} method={"TIME_RANGE"} window={tab === RootTab.Global ? 60 : undefined} />
|
||||||
<NoteCreator replyTo={undefined} autoFocus={true} show={show} setShow={setShow} />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user