diff options
Diffstat (limited to 'gui/src/components/modals')
| -rw-r--r-- | gui/src/components/modals/Modal.tsx | 72 | ||||
| -rw-r--r-- | gui/src/components/modals/ShipModal.tsx | 48 | ||||
| -rw-r--r-- | gui/src/components/modals/UserModal.tsx | 65 |
3 files changed, 185 insertions, 0 deletions
diff --git a/gui/src/components/modals/Modal.tsx b/gui/src/components/modals/Modal.tsx new file mode 100644 index 0000000..e7bae78 --- /dev/null +++ b/gui/src/components/modals/Modal.tsx @@ -0,0 +1,72 @@ +import useLocalState from "@/state/state"; +import { useEffect, useRef, useState } from "react"; + +function Modal({ children }: any) { + const { setModal } = useLocalState((s) => ({ setModal: s.setModal })); + function onKey(event: any) { + if (event.key === "Escape") setModal(null); + } + useEffect(() => { + document.addEventListener("keyup", onKey); + return () => { + document.removeEventListener("keyup", onKey); + }; + }, [children]); + + function clickAway(e: React.MouseEvent) { + console.log("clicked away"); + e.stopPropagation(); + if (!modalRef.current || !modalRef.current.contains(e.target)) + setModal(null); + } + const modalRef = useRef(null); + return ( + <div id="modal-background" onClick={clickAway}> + <div id="modal" ref={modalRef}> + {children} + </div> + </div> + ); +} +export default Modal; + +export function Welcome() { + return ( + <Modal> + <div id="welcome-msg"> + <h1>Welcome to Nostril!</h1> + <p> + Trill is the world's only truly free and sovereign social media + platform, powered by Urbit. + </p> + <p> + Click on the crow icon on the top left to see all available feeds. + </p> + <p>The Global feed should be populated by default.</p> + <p>Follow people soon so your Global feed doesn't go stale.</p> + <p> + Trill is still on beta. The UI is Mobile only, we recommend you use + your phone or the browser dev tools. Desktop UI is on the works. + </p> + <p> + If you have any feedback please reach out to us on Groups at + ~hoster-dozzod-sortug/trill or here at ~polwex + </p> + </div> + </Modal> + ); +} + +export function Tooltip({ children, text, className }: any) { + const [show, toggle] = useState(false); + return ( + <div + className={"tooltip-wrapper " + (className || "")} + onMouseOver={() => toggle(true)} + onMouseOut={() => toggle(false)} + > + {children} + {show && <div className="tooltip">{text}</div>} + </div> + ); +} diff --git a/gui/src/components/modals/ShipModal.tsx b/gui/src/components/modals/ShipModal.tsx new file mode 100644 index 0000000..e823a3a --- /dev/null +++ b/gui/src/components/modals/ShipModal.tsx @@ -0,0 +1,48 @@ +import type { Ship } from "@/types/urbit"; +import Modal from "./Modal"; +import Avatar from "../Avatar"; +import Icon from "@/components/Icon"; +import useLocalState from "@/state/state"; +import { useLocation } from "wouter"; +import toast from "react-hot-toast"; + +export default function ({ ship }: { ship: Ship }) { + const { setModal, api } = useLocalState((s) => ({ + setModal: s.setModal, + api: s.api, + })); + const [_, navigate] = useLocation(); + function close() { + setModal(null); + } + async function copy(e: React.MouseEvent) { + e.stopPropagation(); + await navigator.clipboard.writeText(ship); + toast.success("Copied to clipboard"); + } + return ( + <Modal close={close}> + <div id="ship-modal"> + <div className="flex"> + <Avatar p={ship} size={60} /> + <Icon + name="copy" + size={20} + className="copy-icon cp" + onClick={copy} + title="Copy ship name" + /> + </div> + <div className="buttons f1"> + <button onClick={() => navigate(`/feed/${ship}`)}>Feed</button> + <button onClick={() => navigate(`/pals/${ship}`)}>Profile</button> + {ship !== api!.airlock.our && ( + <> + <button onClick={() => navigate(`/chat/dm/${ship}`)}>DM</button> + </> + )} + </div> + </div> + </Modal> + ); +} diff --git a/gui/src/components/modals/UserModal.tsx b/gui/src/components/modals/UserModal.tsx new file mode 100644 index 0000000..6e3089d --- /dev/null +++ b/gui/src/components/modals/UserModal.tsx @@ -0,0 +1,65 @@ +import Modal from "./Modal"; +import Avatar from "../Avatar"; +import Icon from "@/components/Icon"; +import useLocalState from "@/state/state"; +import { useLocation } from "wouter"; +import toast from "react-hot-toast"; +import type { UserType } from "@/types/nostrill"; + +export default function ({ + user, + userString, +}: { + user: UserType; + userString: string; +}) { + const { setModal, api, pubkey } = useLocalState((s) => ({ + setModal: s.setModal, + api: s.api, + pubkey: s.pubkey, + })); + const [_, navigate] = useLocation(); + function close() { + setModal(null); + } + const itsMe = + "urbit" in user + ? user.urbit === api?.airlock.our + : "nostr" in user + ? user.nostr === pubkey + : false; + async function copy(e: React.MouseEvent) { + e.stopPropagation(); + await navigator.clipboard.writeText(userString); + toast.success("Copied to clipboard"); + } + return ( + <Modal close={close}> + <div id="ship-modal"> + <div className="flex"> + <Avatar user={user} userString={userString} size={60} /> + <Icon + name="copy" + size={20} + className="copy-icon cp" + onClick={copy} + title="Copy ship name" + /> + </div> + <div className="buttons f1"> + <button onClick={() => navigate(`/feed/${userString}`)}>Feed</button> + <button onClick={() => navigate(`/pals/${userString}`)}> + Profile + </button> + {itsMe && ( + <> + <button onClick={() => navigate(`/chat/dm/${userString}`)}> + DM + </button> + </> + )} + </div> + </div> + </Modal> + ); +} |
