File uploads in note creator
This commit is contained in:
11
src/Util.js
Normal file
11
src/Util.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
export async function openFile() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let elm = document.createElement("input");
|
||||||
|
elm.type = "file";
|
||||||
|
elm.onchange = (e) => {
|
||||||
|
resolve(e.target.files[0]);
|
||||||
|
};
|
||||||
|
elm.click();
|
||||||
|
});
|
||||||
|
}
|
18
src/element/NoteCreator.css
Normal file
18
src/element/NoteCreator.css
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
.note-creator {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-creator textarea {
|
||||||
|
min-height: 40px;
|
||||||
|
max-height: 300px;
|
||||||
|
border-radius: 10px 10px 0 0;
|
||||||
|
max-width: -webkit-fill-available;
|
||||||
|
min-width: -webkit-fill-available;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-creator .actions {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 0 0 10px 10px;
|
||||||
|
background-color: #222;
|
||||||
|
}
|
@ -1,11 +1,18 @@
|
|||||||
|
import "./NoteCreator.css";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import useEventPublisher from "../feed/EventPublisher";
|
import useEventPublisher from "../feed/EventPublisher";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { faPaperclip } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { openFile } from "../Util";
|
||||||
|
import VoidUpload from "../feed/VoidUpload";
|
||||||
|
import { FileExtensionRegex } from "../Const";
|
||||||
|
|
||||||
export function NoteCreator(props) {
|
export function NoteCreator(props) {
|
||||||
const replyTo = props.replyTo;
|
const replyTo = props.replyTo;
|
||||||
const onSend = props.onSend;
|
const onSend = props.onSend;
|
||||||
const publisher = useEventPublisher();
|
const publisher = useEventPublisher();
|
||||||
const [note, setNote] = useState("");
|
const [note, setNote] = useState("");
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
async function sendNote() {
|
async function sendNote() {
|
||||||
let ev = replyTo ?
|
let ev = replyTo ?
|
||||||
@ -20,11 +27,28 @@ export function NoteCreator(props) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function attachFile() {
|
||||||
|
let file = await openFile();
|
||||||
|
let rsp = await VoidUpload(file);
|
||||||
|
let ext = file.name.match(FileExtensionRegex)[1];
|
||||||
|
|
||||||
|
// extension tricks note parser to embed the content
|
||||||
|
let url = rsp.metadata.url ?? `https://void.cat/d/${rsp.id}.${ext}`;
|
||||||
|
|
||||||
|
setNote(n => `${n}\n{url}`);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{replyTo ? <small>{`Reply to: ${replyTo.Id.substring(0, 8)}`}</small> : null}
|
{replyTo ? <small>{`Reply to: ${replyTo.Id.substring(0, 8)}`}</small> : null}
|
||||||
<div className="flex">
|
<div className="flex note-creator">
|
||||||
<input type="text" placeholder="Sup?" value={note} onChange={(e) => setNote(e.target.value)} className="f-grow mr10"></input>
|
<div className="flex f-col mr10 f-grow">
|
||||||
|
<textarea placeholder="Say something!" value={note} onChange={(e) => setNote(e.target.value)} />
|
||||||
|
<div className="actions">
|
||||||
|
<FontAwesomeIcon icon={faPaperclip} size="xl" onClick={(e) => attachFile()}/>
|
||||||
|
{error.length > 0 ? <b className="error">{error}</b> : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="btn" onClick={() => sendNote()}>Send</div>
|
<div className="btn" onClick={() => sendNote()}>Send</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
.profile {
|
.profile {
|
||||||
display: flex;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile > div:last-child {
|
.profile > div:last-child {
|
||||||
flex-grow: 1;
|
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import Modal from "../element/Modal";
|
|||||||
import { logout } from "../state/Login";
|
import { logout } from "../state/Login";
|
||||||
import FollowButton from "../element/FollowButton";
|
import FollowButton from "../element/FollowButton";
|
||||||
import VoidUpload from "../feed/VoidUpload";
|
import VoidUpload from "../feed/VoidUpload";
|
||||||
|
import { openFile } from "../Util";
|
||||||
|
|
||||||
export default function ProfilePage() {
|
export default function ProfilePage() {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@ -112,17 +113,6 @@ export default function ProfilePage() {
|
|||||||
publisher.broadcast(ev);
|
publisher.broadcast(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openFile() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let elm = document.createElement("input");
|
|
||||||
elm.type = "file";
|
|
||||||
elm.onchange = (e) => {
|
|
||||||
resolve(e.target.files[0]);
|
|
||||||
};
|
|
||||||
elm.click();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function setNewAvatar() {
|
async function setNewAvatar() {
|
||||||
let file = await openFile();
|
let file = await openFile();
|
||||||
console.log(file);
|
console.log(file);
|
||||||
@ -195,7 +185,7 @@ export default function ProfilePage() {
|
|||||||
<div className="btn" onClick={(e) => setShowLnQr(true)}>
|
<div className="btn" onClick={(e) => setShowLnQr(true)}>
|
||||||
<FontAwesomeIcon icon={faQrcode} size="xl" />
|
<FontAwesomeIcon icon={faQrcode} size="xl" />
|
||||||
</div>
|
</div>
|
||||||
<div> ⚡️ {lud16}</div>
|
<div className="f-ellipsis"> ⚡️ {lud16.length > 20 ? lud16.substring(0, 20) : lud16}</div>
|
||||||
</div> : null}
|
</div> : null}
|
||||||
{showLnQr === true ?
|
{showLnQr === true ?
|
||||||
<Modal onClose={() => setShowLnQr(false)}>
|
<Modal onClose={() => setShowLnQr(false)}>
|
||||||
@ -208,7 +198,7 @@ export default function ProfilePage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="profile">
|
<div className="profile flex">
|
||||||
<div>
|
<div>
|
||||||
<div style={{ backgroundImage: `url(${picture.length === 0 ? Nostrich : picture})` }} className="avatar">
|
<div style={{ backgroundImage: `url(${picture.length === 0 ? Nostrich : picture})` }} className="avatar">
|
||||||
{isMe ?
|
{isMe ?
|
||||||
@ -219,7 +209,7 @@ export default function ProfilePage() {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="f-grow">
|
||||||
{isMe ? editor() : details()}
|
{isMe ? editor() : details()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user