poll creation
This commit is contained in:
@ -7,7 +7,6 @@
|
||||
background-color: var(--modal-bg-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 42;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@ -17,12 +16,7 @@
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
width: 500px;
|
||||
min-height: 10vh;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.modal-body {
|
||||
width: 100vw;
|
||||
margin: 0 10px;
|
||||
}
|
||||
border: 1px solid var(--font-tertiary-color);
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
resize: none;
|
||||
background-color: var(--note-bg);
|
||||
border-radius: 10px 10px 0 0;
|
||||
min-height: 120px;
|
||||
min-height: 100px;
|
||||
max-width: stretch;
|
||||
min-width: stretch;
|
||||
max-height: 210px;
|
||||
@ -41,6 +41,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.note-creator.poll textarea {
|
||||
min-height: 120px;
|
||||
}
|
||||
.note-creator-actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
@ -50,19 +53,22 @@
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.note-creator .attachment {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
bottom: 12px;
|
||||
.note-creator .insert {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: stretch;
|
||||
}
|
||||
|
||||
.note-creator .insert > button {
|
||||
width: 48px;
|
||||
height: 36px;
|
||||
background: var(--gray-dark);
|
||||
color: white;
|
||||
border-radius: 100px;
|
||||
border-radius: 17px;
|
||||
margin-right: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.note-creator .attachment:hover {
|
||||
@ -87,19 +93,11 @@
|
||||
position: absolute;
|
||||
left: 16px;
|
||||
bottom: 12px;
|
||||
font-color: var(--error);
|
||||
color: var(--error);
|
||||
margin-right: 12px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.note-creator .btn {
|
||||
border-radius: 20px;
|
||||
font-weight: bold;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--font-color);
|
||||
font-size: var(--font-size);
|
||||
}
|
||||
|
||||
.note-create-button {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
@ -114,31 +112,10 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media (min-width: 520px) {
|
||||
.note-create-button {
|
||||
right: 10vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1020px) {
|
||||
.note-create-button {
|
||||
right: calc(50% - 360px);
|
||||
}
|
||||
}
|
||||
|
||||
.note-creator-modal .modal-body {
|
||||
background: var(--modal-bg-color);
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.note-creator-modal {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.note-creator-modal .modal-body {
|
||||
margin-top: 20vh;
|
||||
}
|
||||
}
|
||||
|
||||
.note-preview {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import "./NoteCreator.css";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { TaggedRawEvent } from "@snort/nostr";
|
||||
import { EventKind, TaggedRawEvent } from "@snort/nostr";
|
||||
|
||||
import Icon from "Icons/Icon";
|
||||
import useEventPublisher from "Feed/EventPublisher";
|
||||
@ -21,6 +21,7 @@ import {
|
||||
setZapForward,
|
||||
setSensitive,
|
||||
reset,
|
||||
setPollOptions,
|
||||
} from "State/NoteCreator";
|
||||
import type { RootState } from "State/Store";
|
||||
import { LNURL } from "LNURL";
|
||||
@ -56,6 +57,7 @@ export function NoteCreator() {
|
||||
const showAdvanced = useSelector((s: RootState) => s.noteCreator.showAdvanced);
|
||||
const zapForward = useSelector((s: RootState) => s.noteCreator.zapForward);
|
||||
const sensitive = useSelector((s: RootState) => s.noteCreator.sensitive);
|
||||
const pollOptions = useSelector((s: RootState) => s.noteCreator.pollOptions);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
async function sendNote() {
|
||||
@ -81,8 +83,14 @@ export function NoteCreator() {
|
||||
extraTags ??= [];
|
||||
extraTags.push(["content-warning", sensitive]);
|
||||
}
|
||||
const ev = replyTo ? await publisher.reply(replyTo, note, extraTags) : await publisher.note(note, extraTags);
|
||||
console.debug("Sending note: ", ev);
|
||||
const kind = pollOptions ? EventKind.Polls : EventKind.TextNote;
|
||||
if (pollOptions) {
|
||||
extraTags ??= [];
|
||||
extraTags.push(...pollOptions.map((a, i) => ["poll_option", i.toString(), a]));
|
||||
}
|
||||
const ev = replyTo
|
||||
? await publisher.reply(replyTo, note, extraTags, kind)
|
||||
: await publisher.note(note, extraTags, kind);
|
||||
publisher.broadcast(ev);
|
||||
dispatch(reset());
|
||||
}
|
||||
@ -127,7 +135,7 @@ export function NoteCreator() {
|
||||
|
||||
async function loadPreview() {
|
||||
if (preview) {
|
||||
dispatch(setPreview(null));
|
||||
dispatch(setPreview(undefined));
|
||||
} else {
|
||||
const tmpNote = await publisher.note(note);
|
||||
if (tmpNote) {
|
||||
@ -151,6 +159,52 @@ export function NoteCreator() {
|
||||
}
|
||||
}
|
||||
|
||||
function renderPollOptions() {
|
||||
if (pollOptions) {
|
||||
return (
|
||||
<>
|
||||
<h4>
|
||||
<FormattedMessage defaultMessage="Poll Options" />
|
||||
</h4>
|
||||
{pollOptions?.map((a, i) => (
|
||||
<div className="form-group w-max" key={`po-${i}`}>
|
||||
<div>
|
||||
<FormattedMessage defaultMessage="Option: {n}" values={{ n: i + 1 }} />
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" value={a} onChange={e => changePollOption(i, e.target.value)} />
|
||||
{i > 1 && (
|
||||
<button onClick={() => removePollOption(i)} className="ml5">
|
||||
<Icon name="close" size={14} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<button onClick={() => dispatch(setPollOptions([...pollOptions, ""]))}>
|
||||
<Icon name="plus" size={14} />
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function changePollOption(i: number, v: string) {
|
||||
if (pollOptions) {
|
||||
const copy = [...pollOptions];
|
||||
copy[i] = v;
|
||||
dispatch(setPollOptions(copy));
|
||||
}
|
||||
}
|
||||
|
||||
function removePollOption(i: number) {
|
||||
if (pollOptions) {
|
||||
const copy = [...pollOptions];
|
||||
copy.splice(i, 1);
|
||||
dispatch(setPollOptions(copy));
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{show && (
|
||||
@ -158,8 +212,8 @@ export function NoteCreator() {
|
||||
{replyTo && <NotePreview note={replyTo} />}
|
||||
{preview && getPreviewNote()}
|
||||
{!preview && (
|
||||
<div className={`flex note-creator ${replyTo ? "note-reply" : ""}`}>
|
||||
<div className="flex f-col mr10 f-grow">
|
||||
<div className={`flex note-creator${replyTo ? " note-reply" : ""}${pollOptions ? " poll" : ""}`}>
|
||||
<div className="flex f-col f-grow">
|
||||
<Textarea
|
||||
autoFocus
|
||||
className={`textarea ${active ? "textarea--focused" : ""}`}
|
||||
@ -172,9 +226,17 @@ export function NoteCreator() {
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<button type="button" className="attachment" onClick={attachFile}>
|
||||
<Icon name="attachment" />
|
||||
</button>
|
||||
{renderPollOptions()}
|
||||
<div className="insert">
|
||||
{pollOptions === undefined && !replyTo && (
|
||||
<button type="button" onClick={() => dispatch(setPollOptions(["A", "B"]))}>
|
||||
<Icon name="pie-chart" />
|
||||
</button>
|
||||
)}
|
||||
<button type="button" onClick={attachFile}>
|
||||
<Icon name="attachment" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{error && <span className="error">{error}</span>}
|
||||
</div>
|
||||
|
@ -96,6 +96,7 @@ export default function useEventPublisher() {
|
||||
},
|
||||
broadcast: (ev: RawEvent | undefined) => {
|
||||
if (ev) {
|
||||
console.debug(ev);
|
||||
System.BroadcastEvent(ev);
|
||||
}
|
||||
},
|
||||
@ -179,9 +180,9 @@ export default function useEventPublisher() {
|
||||
return await signEvent(ev);
|
||||
}
|
||||
},
|
||||
note: async (msg: string, extraTags?: Array<Array<string>>) => {
|
||||
note: async (msg: string, extraTags?: Array<Array<string>>, kind?: EventKind) => {
|
||||
if (pubKey) {
|
||||
const ev = EventExt.forPubKey(pubKey, EventKind.TextNote);
|
||||
const ev = EventExt.forPubKey(pubKey, kind ?? EventKind.TextNote);
|
||||
processContent(ev, msg);
|
||||
if (extraTags) {
|
||||
for (const et of extraTags) {
|
||||
@ -218,9 +219,9 @@ export default function useEventPublisher() {
|
||||
/**
|
||||
* Reply to a note
|
||||
*/
|
||||
reply: async (replyTo: TaggedRawEvent, msg: string, extraTags?: Array<Array<string>>) => {
|
||||
reply: async (replyTo: TaggedRawEvent, msg: string, extraTags?: Array<Array<string>>, kind?: EventKind) => {
|
||||
if (pubKey) {
|
||||
const ev = EventExt.forPubKey(pubKey, EventKind.TextNote);
|
||||
const ev = EventExt.forPubKey(pubKey, kind ?? EventKind.TextNote);
|
||||
|
||||
const thread = EventExt.extractThread(ev);
|
||||
if (thread) {
|
||||
|
@ -6,11 +6,12 @@ interface NoteCreatorStore {
|
||||
note: string;
|
||||
error: string;
|
||||
active: boolean;
|
||||
preview: RawEvent | null;
|
||||
replyTo: TaggedRawEvent | null;
|
||||
preview?: RawEvent;
|
||||
replyTo?: TaggedRawEvent;
|
||||
showAdvanced: boolean;
|
||||
zapForward: string;
|
||||
sensitive: string;
|
||||
pollOptions?: Array<string>;
|
||||
}
|
||||
|
||||
const InitState: NoteCreatorStore = {
|
||||
@ -18,8 +19,6 @@ const InitState: NoteCreatorStore = {
|
||||
note: "",
|
||||
error: "",
|
||||
active: false,
|
||||
preview: null,
|
||||
replyTo: null,
|
||||
showAdvanced: false,
|
||||
zapForward: "",
|
||||
sensitive: "",
|
||||
@ -41,10 +40,10 @@ const NoteCreatorSlice = createSlice({
|
||||
setActive: (state, action: PayloadAction<boolean>) => {
|
||||
state.active = action.payload;
|
||||
},
|
||||
setPreview: (state, action: PayloadAction<RawEvent | null>) => {
|
||||
setPreview: (state, action: PayloadAction<RawEvent | undefined>) => {
|
||||
state.preview = action.payload;
|
||||
},
|
||||
setReplyTo: (state, action: PayloadAction<TaggedRawEvent | null>) => {
|
||||
setReplyTo: (state, action: PayloadAction<TaggedRawEvent | undefined>) => {
|
||||
state.replyTo = action.payload;
|
||||
},
|
||||
setShowAdvanced: (state, action: PayloadAction<boolean>) => {
|
||||
@ -56,6 +55,9 @@ const NoteCreatorSlice = createSlice({
|
||||
setSensitive: (state, action: PayloadAction<string>) => {
|
||||
state.sensitive = action.payload;
|
||||
},
|
||||
setPollOptions: (state, action: PayloadAction<Array<string> | undefined>) => {
|
||||
state.pollOptions = action.payload;
|
||||
},
|
||||
reset: () => InitState,
|
||||
},
|
||||
});
|
||||
@ -70,6 +72,7 @@ export const {
|
||||
setShowAdvanced,
|
||||
setZapForward,
|
||||
setSensitive,
|
||||
setPollOptions,
|
||||
reset,
|
||||
} = NoteCreatorSlice.actions;
|
||||
|
||||
|
Reference in New Issue
Block a user