feat: note creator button on deck
This commit is contained in:
parent
65552e126b
commit
f0110e9009
@ -80,7 +80,7 @@ export default function WriteMessage({ chat }: { chat: Chat }) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<button className="btn-rnd" onClick={() => attachFile()}>
|
||||
<button className="circle flex flex-center" onClick={() => attachFile()}>
|
||||
{uploading ? <Spinner width={20} /> : <Icon name="attachment" size={20} />}
|
||||
</button>
|
||||
<div className="w-max">
|
||||
@ -97,7 +97,7 @@ export default function WriteMessage({ chat }: { chat: Chat }) {
|
||||
/>
|
||||
{error && <b className="error">{error}</b>}
|
||||
</div>
|
||||
<button className="btn-rnd" onClick={() => sendMessage()}>
|
||||
<button className="circle flex flex-center" onClick={() => sendMessage()}>
|
||||
{sending ? <Spinner width={20} /> : <Icon name="arrow-right" size={20} />}
|
||||
</button>
|
||||
</>
|
||||
|
@ -5,13 +5,13 @@ import "./Nav.css";
|
||||
import Icon from "Icons/Icon";
|
||||
import { Link } from "react-router-dom";
|
||||
import { profileLink } from "SnortUtils";
|
||||
import { NoteCreatorButton } from "Element/Event/NoteCreatorButton";
|
||||
|
||||
export function DeckNav() {
|
||||
const { publicKey } = useLogin();
|
||||
const profile = useUserProfile(publicKey);
|
||||
|
||||
const unreadDms = 0;
|
||||
const hasNotifications = false;
|
||||
|
||||
return (
|
||||
<nav className="deck flex-column f-space">
|
||||
@ -20,15 +20,12 @@ export function DeckNav() {
|
||||
<Icon name="mail" size={24} />
|
||||
{unreadDms > 0 && <span className="has-unread"></span>}
|
||||
</Link>
|
||||
<Link className="btn" to="/notifications">
|
||||
<Icon name="bell-02" size={24} />
|
||||
{hasNotifications && <span className="has-unread"></span>}
|
||||
</Link>
|
||||
<NoteCreatorButton />
|
||||
</div>
|
||||
<div className="flex-column f-center g16">
|
||||
<Link className="btn" to="/">
|
||||
{/*<Link className="btn" to="/">
|
||||
<Icon name="grid-01" size={24} />
|
||||
</Link>
|
||||
</Link>*/}
|
||||
<Link className="btn" to="/settings">
|
||||
<Icon name="settings-02" size={24} />
|
||||
</Link>
|
||||
|
@ -84,27 +84,6 @@
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.note-create-button {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
color: white;
|
||||
background: linear-gradient(90deg, rgba(239, 150, 68, 1) 0%, rgba(123, 65, 246, 1) 100%);
|
||||
border: none;
|
||||
border-radius: 100%;
|
||||
position: fixed;
|
||||
bottom: 40px;
|
||||
right: calc(((100vw - 640px) / 2) - 75px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.note-create-button {
|
||||
right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.light .note-creator textarea {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
20
packages/app/src/Element/Event/NoteCreatorButton.css
Normal file
20
packages/app/src/Element/Event/NoteCreatorButton.css
Normal file
@ -0,0 +1,20 @@
|
||||
.note-create-button {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
color: white;
|
||||
background: linear-gradient(90deg, rgba(239, 150, 68, 1) 0%, rgba(123, 65, 246, 1) 100%);
|
||||
border: none;
|
||||
border-radius: 100%;
|
||||
position: fixed;
|
||||
bottom: 40px;
|
||||
right: calc(((100vw - 640px) / 2) - 75px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.note-create-button {
|
||||
right: 16px;
|
||||
}
|
||||
}
|
51
packages/app/src/Element/Event/NoteCreatorButton.tsx
Normal file
51
packages/app/src/Element/Event/NoteCreatorButton.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import "./NoteCreatorButton.css";
|
||||
import { useRef, useMemo } from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
import { isFormElement } from "SnortUtils";
|
||||
import useKeyboardShortcut from "Hooks/useKeyboardShortcut";
|
||||
import useLogin from "Hooks/useLogin";
|
||||
import Icon from "Icons/Icon";
|
||||
import { useNoteCreator } from "State/NoteCreator";
|
||||
import { NoteCreator } from "./NoteCreator";
|
||||
|
||||
export const NoteCreatorButton = ({ className }: { className?: string }) => {
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const location = useLocation();
|
||||
const { readonly } = useLogin(s => ({ readonly: s.readonly }));
|
||||
const { show, replyTo, update } = useNoteCreator(v => ({ show: v.show, replyTo: v.replyTo, update: v.update }));
|
||||
|
||||
useKeyboardShortcut("n", event => {
|
||||
// if event happened in a form element, do nothing, otherwise focus on search input
|
||||
if (event.target && !isFormElement(event.target as HTMLElement)) {
|
||||
event.preventDefault();
|
||||
if (buttonRef.current) {
|
||||
buttonRef.current.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const shouldHideNoteCreator = useMemo(() => {
|
||||
const isReplyNoteCreatorShowing = replyTo && show;
|
||||
const hideOn = ["/settings", "/messages", "/new", "/login", "/donate", "/e", "/subscribe"];
|
||||
return readonly || isReplyNoteCreatorShowing || hideOn.some(a => location.pathname.startsWith(a));
|
||||
}, [location, readonly]);
|
||||
|
||||
if (shouldHideNoteCreator) return null;
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
ref={buttonRef}
|
||||
className={`primary circle${className ? ` ${className}` : ""}`}
|
||||
onClick={() =>
|
||||
update(v => {
|
||||
v.replyTo = undefined;
|
||||
v.show = true;
|
||||
})
|
||||
}>
|
||||
<Icon name="plus" size={16} />
|
||||
</button>
|
||||
<NoteCreator key="global-note-creator" />
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
import "./Layout.css";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { Link, Outlet, useLocation, useNavigate } from "react-router-dom";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { useUserProfile } from "@snort/system-react";
|
||||
@ -9,7 +9,6 @@ import messages from "./messages";
|
||||
|
||||
import Icon from "Icons/Icon";
|
||||
import useLoginFeed from "Feed/LoginFeed";
|
||||
import { NoteCreator } from "Element/Event/NoteCreator";
|
||||
import { mapPlanName } from "./subscribe";
|
||||
import useLogin from "Hooks/useLogin";
|
||||
import Avatar from "Element/User/Avatar";
|
||||
@ -20,10 +19,10 @@ import Spinner from "Icons/Spinner";
|
||||
import { fetchNip05Pubkey } from "Nip05/Verifier";
|
||||
import { useTheme } from "Hooks/useTheme";
|
||||
import { useLoginRelays } from "Hooks/useLoginRelays";
|
||||
import { useNoteCreator } from "State/NoteCreator";
|
||||
import { LoginUnlock } from "Element/PinPrompt";
|
||||
import useKeyboardShortcut from "Hooks/useKeyboardShortcut";
|
||||
import { LoginStore } from "Login";
|
||||
import { NoteCreatorButton } from "Element/Event/NoteCreatorButton";
|
||||
|
||||
export default function Layout() {
|
||||
const location = useLocation();
|
||||
@ -69,7 +68,7 @@ export default function Layout() {
|
||||
</header>
|
||||
)}
|
||||
<Outlet />
|
||||
<NoteCreatorButton />
|
||||
<NoteCreatorButton className="note-create-button" />
|
||||
<Toaster />
|
||||
</div>
|
||||
<LoginUnlock />
|
||||
@ -79,7 +78,7 @@ export default function Layout() {
|
||||
onClick={() => {
|
||||
LoginStore.removeSession(id);
|
||||
}}>
|
||||
<button type="button" className="btn btn-rnd">
|
||||
<button type="button" className="circle flex flex-center">
|
||||
<Icon name="close" />
|
||||
</button>
|
||||
</div>
|
||||
@ -88,47 +87,6 @@ export default function Layout() {
|
||||
);
|
||||
}
|
||||
|
||||
const NoteCreatorButton = () => {
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const location = useLocation();
|
||||
const { readonly } = useLogin(s => ({ readonly: s.readonly }));
|
||||
const { show, replyTo, update } = useNoteCreator(v => ({ show: v.show, replyTo: v.replyTo, update: v.update }));
|
||||
|
||||
useKeyboardShortcut("n", event => {
|
||||
// if event happened in a form element, do nothing, otherwise focus on search input
|
||||
if (event.target && !isFormElement(event.target as HTMLElement)) {
|
||||
event.preventDefault();
|
||||
if (buttonRef.current) {
|
||||
buttonRef.current.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const shouldHideNoteCreator = useMemo(() => {
|
||||
const isReplyNoteCreatorShowing = replyTo && show;
|
||||
const hideOn = ["/settings", "/messages", "/new", "/login", "/donate", "/e", "/subscribe"];
|
||||
return readonly || isReplyNoteCreatorShowing || hideOn.some(a => location.pathname.startsWith(a));
|
||||
}, [location, readonly]);
|
||||
|
||||
if (shouldHideNoteCreator) return;
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
ref={buttonRef}
|
||||
className="primary note-create-button"
|
||||
onClick={() =>
|
||||
update(v => {
|
||||
v.replyTo = undefined;
|
||||
v.show = true;
|
||||
})
|
||||
}>
|
||||
<Icon name="plus" size={16} />
|
||||
</button>
|
||||
<NoteCreator key="global-note-creator" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const AccountHeader = () => {
|
||||
const navigate = useNavigate();
|
||||
const { formatMessage } = useIntl();
|
||||
|
@ -33,7 +33,7 @@
|
||||
bottom: -32px;
|
||||
}
|
||||
|
||||
.settings .image-settings .avatar-stack .btn-rnd {
|
||||
.settings .image-settings .avatar-stack button {
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
width: 32px;
|
||||
|
@ -205,7 +205,11 @@ export default function ProfileSettings(props: ProfileSettingsProps) {
|
||||
{(props.avatar ?? true) && (
|
||||
<div className="avatar-stack">
|
||||
<Avatar pubkey={id} user={user} image={picture} />
|
||||
<AsyncButton type="button" className="btn-rnd" onClick={() => setNewAvatar()} disabled={readonly}>
|
||||
<AsyncButton
|
||||
type="button"
|
||||
className="circle flex flex-center"
|
||||
onClick={() => setNewAvatar()}
|
||||
disabled={readonly}>
|
||||
<Icon name="upload-01" />
|
||||
</AsyncButton>
|
||||
</div>
|
||||
|
@ -364,12 +364,9 @@ button.icon:hover {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.btn-rnd {
|
||||
.circle {
|
||||
border-radius: 100%;
|
||||
aspect-ratio: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
textarea {
|
||||
|
Loading…
x
Reference in New Issue
Block a user