feat: polish

This commit is contained in:
reya 2024-01-26 14:15:25 +07:00
parent bef1f136ad
commit b0a443c002
17 changed files with 114 additions and 80 deletions

View File

@ -48,7 +48,7 @@ export function BackupSettingScreen() {
<button <button
type="button" type="button"
onClick={() => removePrivkey()} onClick={() => removePrivkey()}
className="mt-2 inline-flex h-11 w-full items-center justify-center gap-2 rounded-lg bg-red-200 px-6 font-medium text-red-500 hover:bg-red-500 hover:text-white focus:outline-none dark:hover:text-white" className="mt-2 inline-flex h-11 w-full items-center justify-center gap-2 rounded-lg bg-red-200 dark:bg-red-800 px-6 font-medium text-red-500 hover:bg-red-500 hover:text-white focus:outline-none dark:hover:text-white"
> >
Remove private key Remove private key
</button> </button>

View File

@ -10,6 +10,7 @@ import { NDKKind, NDKUserProfile } from "@nostr-dev-kit/ndk";
import { useQueryClient } from "@tanstack/react-query"; import { useQueryClient } from "@tanstack/react-query";
import { useState } from "react"; import { useState } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { AvatarUpload } from "./components/avatarUpload"; import { AvatarUpload } from "./components/avatarUpload";
import { CoverUpload } from "./components/coverUpload"; import { CoverUpload } from "./components/coverUpload";
@ -92,6 +93,9 @@ export function ProfileSettingScreen() {
return content; return content;
}); });
// notify
toast.success("You've updated profile successfully.");
// reset state // reset state
setPicture(null); setPicture(null);
setBanner(null); setBanner(null);
@ -112,7 +116,7 @@ export function ProfileSettingScreen() {
className="h-full w-full rounded-t-xl object-cover" className="h-full w-full rounded-t-xl object-cover"
/> />
) : ( ) : (
<div className="h-full w-full rounded-t-xl bg-neutral-200 dark:bg-neutral-900" /> <div className="h-full w-full rounded-t-xl bg-neutral-200 dark:bg-neutral-800" />
)} )}
<div className="absolute right-4 top-4"> <div className="absolute right-4 top-4">
<CoverUpload setBanner={setBanner} /> <CoverUpload setBanner={setBanner} />
@ -236,7 +240,7 @@ export function ProfileSettingScreen() {
<button <button
type="submit" type="submit"
disabled={!isValid || loading} disabled={!isValid || loading}
className="mx-auto inline-flex h-10 w-24 transform items-center justify-center gap-1 rounded-lg bg-blue-500 font-medium text-white hover:bg-blue-600 focus:outline-none active:translate-y-1 disabled:pointer-events-none disabled:opacity-50" className="inline-flex items-center justify-center w-24 pb-[2px] font-semibold border-t rounded-lg border-neutral-900 dark:border-neutral-800 h-9 bg-neutral-950 text-neutral-50 dark:bg-neutral-900 hover:bg-neutral-900 dark:hover:bg-neutral-800"
> >
{loading ? ( {loading ? (
<LoaderIcon className="size-4 animate-spin" /> <LoaderIcon className="size-4 animate-spin" />

View File

@ -46,11 +46,9 @@ export function ColumnHeader({
<DropdownMenu.Root> <DropdownMenu.Root>
<div className="flex items-center justify-center gap-2 px-3 w-full border-b h-11 shrink-0 border-neutral-100 dark:border-neutral-900"> <div className="flex items-center justify-center gap-2 px-3 w-full border-b h-11 shrink-0 border-neutral-100 dark:border-neutral-900">
<DropdownMenu.Trigger asChild> <DropdownMenu.Trigger asChild>
<div className="inline-flex items-center gap-3"> <div className="inline-flex items-center gap-1.5">
<div className="inline-flex items-center gap-2"> <div className="text-[13px] font-medium">{title}</div>
<div className="text-[13px] font-medium">{title}</div> <ChevronDownIcon className="size-5" />
<ChevronDownIcon className="size-5 mt-px" />
</div>
</div> </div>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Portal> <DropdownMenu.Portal>
@ -96,7 +94,7 @@ export function ColumnHeader({
Move right Move right
</button> </button>
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Separator className="h-px my-1 bg-white/10 dark:bg-black/10" /> <DropdownMenu.Separator className="h-px my-1 bg-black/10 dark:bg-white/10" />
<DropdownMenu.Item asChild> <DropdownMenu.Item asChild>
<button <button
type="button" type="button"

View File

@ -110,6 +110,7 @@ export function InterestModal({
<div className="flex flex-wrap items-center gap-3"> <div className="flex flex-wrap items-center gap-3">
{topic.content.map((hashtag) => ( {topic.content.map((hashtag) => (
<button <button
key={hashtag}
type="button" type="button"
onClick={() => toggleHashtag(hashtag)} onClick={() => toggleHashtag(hashtag)}
className={cn( className={cn(

View File

@ -131,10 +131,18 @@ export function NoteZap() {
</Tooltip.Root> </Tooltip.Root>
</Tooltip.Provider> </Tooltip.Provider>
<Dialog.Portal> <Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/10 backdrop-blur-sm dark:bg-white/10" /> <Dialog.Overlay className="fixed inset-0 z-50 bg-black/20 backdrop-blur-sm dark:bg-white/20" />
<Dialog.Content className="fixed inset-0 z-50 flex items-center justify-center min-h-full"> <Dialog.Content className="fixed inset-0 z-50 flex items-center justify-center min-h-full">
<Dialog.Close className="absolute top-5 right-5 z-50">
<div className="flex flex-col gap-1.5">
<div className="inline-flex items-center justify-center size-10 rounded-lg bg-white dark:bg-black">
<CancelIcon className="size-5" />
</div>
<span className="text-sm font-medium">Esc</span>
</div>
</Dialog.Close>
<div className="relative w-full max-w-xl bg-white h-min rounded-xl dark:bg-black"> <div className="relative w-full max-w-xl bg-white h-min rounded-xl dark:bg-black">
<div className="inline-flex items-center justify-between w-full px-5 py-3 shrink-0"> <div className="inline-flex items-center justify-center w-full px-5 py-3 shrink-0">
<div className="w-6" /> <div className="w-6" />
<Dialog.Title className="font-semibold text-center"> <Dialog.Title className="font-semibold text-center">
Send zap to{" "} Send zap to{" "}
@ -142,13 +150,10 @@ export function NoteZap() {
user?.displayName || user?.displayName ||
displayNpub(event.pubkey, 16)} displayNpub(event.pubkey, 16)}
</Dialog.Title> </Dialog.Title>
<Dialog.Close className="inline-flex items-center justify-center w-6 h-6 rounded-md bg-neutral-100 dark:bg-neutral-900">
<CancelIcon className="w-4 h-4" />
</Dialog.Close>
</div> </div>
{!invoice ? ( {!invoice ? (
<div className="px-5 pb-5 overflow-x-hidden overflow-y-auto"> <div className="px-5 pb-5 overflow-x-hidden overflow-y-auto">
<div className="relative flex flex-col h-40"> <div className="relative flex flex-col h-36">
<div className="inline-flex items-center justify-center flex-1 h-full gap-1"> <div className="inline-flex items-center justify-center flex-1 h-full gap-1">
<CurrencyInput <CurrencyInput
placeholder="0" placeholder="0"
@ -213,13 +218,13 @@ export function NoteZap() {
autoCorrect="off" autoCorrect="off"
autoCapitalize="off" autoCapitalize="off"
placeholder="Enter message (optional)" placeholder="Enter message (optional)"
className="w-full resize-none rounded-lg border-transparent bg-neutral-100 px-3 py-3 !outline-none placeholder:text-neutral-600 focus:border-blue-500 focus:ring focus:ring-blue-200 dark:bg-neutral-900 dark:text-neutral-400" className="w-full resize-none rounded-lg border-transparent bg-neutral-100 px-3 py-3 !outline-none placeholder:text-neutral-600 focus:border-blue-500 focus:ring focus:ring-blue-200 dark:bg-neutral-950 dark:text-neutral-400"
/> />
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<button <button
type="button" type="button"
onClick={() => createZapRequest()} onClick={() => createZapRequest()}
className="inline-flex items-center justify-center w-full px-4 font-medium text-white bg-blue-500 rounded-lg h-11 hover:bg-blue-600" className="inline-flex items-center justify-center w-full pb-[2px] font-semibold border-t rounded-lg border-neutral-900 dark:border-neutral-800 h-9 bg-neutral-950 text-neutral-50 dark:bg-neutral-900 hover:bg-neutral-900 dark:hover:bg-neutral-800"
> >
{isCompleted {isCompleted
? "Zapped" ? "Zapped"

View File

@ -1,4 +1,5 @@
import { HorizontalDotsIcon } from "@lume/icons"; import { HorizontalDotsIcon } from "@lume/icons";
import { COL_TYPES } from "@lume/utils";
import * as DropdownMenu from "@radix-ui/react-dropdown-menu"; import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
import { writeText } from "@tauri-apps/plugin-clipboard-manager"; import { writeText } from "@tauri-apps/plugin-clipboard-manager";
import { nip19 } from "nostr-tools"; import { nip19 } from "nostr-tools";
@ -6,12 +7,13 @@ import { type EventPointer } from "nostr-tools/lib/types/nip19";
import { useState } from "react"; import { useState } from "react";
import { Link, useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { toast } from "sonner"; import { toast } from "sonner";
import { useColumnContext } from "../column/provider";
import { useNoteContext } from "./provider"; import { useNoteContext } from "./provider";
export function NoteMenu() { export function NoteMenu() {
const event = useNoteContext(); const event = useNoteContext();
const navigate = useNavigate(); const navigate = useNavigate();
const { addColumn } = useColumnContext();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const copyID = async () => { const copyID = async () => {
@ -52,9 +54,9 @@ export function NoteMenu() {
<DropdownMenu.Trigger asChild> <DropdownMenu.Trigger asChild>
<button <button
type="button" type="button"
className="inline-flex items-center justify-center w-6 h-6" className="inline-flex items-center justify-center size-6"
> >
<HorizontalDotsIcon className="w-4 h-4 text-neutral-800 hover:text-blue-500 dark:text-neutral-200" /> <HorizontalDotsIcon className="size-4 hover:text-blue-500 dark:text-neutral-200" />
</button> </button>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Portal> <DropdownMenu.Portal>
@ -100,9 +102,24 @@ export function NoteMenu() {
to={`/users/${event.pubkey}`} to={`/users/${event.pubkey}`}
className="inline-flex items-center gap-3 px-3 text-sm font-medium rounded-lg h-9 text-black/70 hover:bg-black/10 hover:text-black focus:outline-none dark:text-white/70 dark:hover:bg-white/10 dark:hover:text-white" className="inline-flex items-center gap-3 px-3 text-sm font-medium rounded-lg h-9 text-black/70 hover:bg-black/10 hover:text-black focus:outline-none dark:text-white/70 dark:hover:bg-white/10 dark:hover:text-white"
> >
View profile View author
</Link> </Link>
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item asChild>
<button
type="button"
onClick={() =>
addColumn({
kind: COL_TYPES.user,
title: "User",
content: event.pubkey,
})
}
className="inline-flex items-center gap-3 px-3 text-sm font-medium rounded-lg h-9 text-black/70 hover:bg-black/10 hover:text-black focus:outline-none dark:text-white/70 dark:hover:bg-white/10 dark:hover:text-white"
>
Pin author
</button>
</DropdownMenu.Item>
<DropdownMenu.Separator className="h-px my-1 bg-black/10 dark:bg-white/10" /> <DropdownMenu.Separator className="h-px my-1 bg-black/10 dark:bg-white/10" />
<DropdownMenu.Item asChild> <DropdownMenu.Item asChild>
<button <button

View File

@ -8,7 +8,7 @@ export function ChildReply({
<Note.Provider event={event}> <Note.Provider event={event}>
<Note.Root className="py-2"> <Note.Root className="py-2">
<div className="flex items-center justify-between h-14"> <div className="flex items-center justify-between h-14">
<Note.User className="flex-1" /> <Note.User className="flex-1 pr-2" />
<Note.Menu /> <Note.Menu />
</div> </div>
<Note.Content /> <Note.Content />

View File

@ -18,7 +18,7 @@ export function Reply({
<Note.Provider event={event}> <Note.Provider event={event}>
<Note.Root className="pt-2"> <Note.Root className="pt-2">
<div className="flex items-center justify-between h-14"> <div className="flex items-center justify-between h-14">
<Note.User className="flex-1 pr-1" /> <Note.User className="flex-1 pr-2" />
<Note.Menu /> <Note.Menu />
</div> </div>
<Note.Content /> <Note.Content />

View File

@ -93,7 +93,7 @@ export function RepostNote({
<Note.Provider event={repostEvent}> <Note.Provider event={repostEvent}>
<div className="relative flex flex-col gap-2 px-3"> <div className="relative flex flex-col gap-2 px-3">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<Note.User className="flex-1 pr-1" /> <Note.User className="flex-1 pr-2" />
<Note.Menu /> <Note.Menu />
</div> </div>
<Note.Content /> <Note.Content />

View File

@ -15,7 +15,7 @@ export function TextNote({
)} )}
> >
<div className="flex items-center justify-between px-3 h-14"> <div className="flex items-center justify-between px-3 h-14">
<Note.User className="flex-1 pr-1" /> <Note.User className="flex-1 pr-2" />
<Note.Menu /> <Note.Menu />
</div> </div>
<Note.Thread className="mb-2" /> <Note.Thread className="mb-2" />

View File

@ -87,31 +87,18 @@ export const LumeProvider = ({ children }: PropsWithChildren<object>) => {
async function initNDK() { async function initNDK() {
const explicitRelayUrls = normalizeRelayUrlSet([ const explicitRelayUrls = normalizeRelayUrlSet([
"wss://nostr.mutinywallet.com/",
"wss://bostr.nokotaro.com/", "wss://bostr.nokotaro.com/",
]); ]);
// #TODO: user should config outbox relays
const outboxRelayUrls = normalizeRelayUrlSet(["wss://purplepag.es/"]);
// #TODO: user should config blacklist relays
// Skip connect depot tunnel url
const blacklistRelayUrls = normalizeRelayUrlSet(
storage.settings.tunnelUrl.length
? [storage.settings.tunnelUrl, "wss://brb.io/"]
: ["wss://brb.io/"],
);
const tauriCache = new NDKCacheAdapterTauri(storage); const tauriCache = new NDKCacheAdapterTauri(storage);
const ndk = new NDK({ const ndk = new NDK({
cacheAdapter: tauriCache, cacheAdapter: tauriCache,
explicitRelayUrls, explicitRelayUrls,
outboxRelayUrls,
blacklistRelayUrls,
enableOutboxModel: !storage.settings.lowPower, enableOutboxModel: !storage.settings.lowPower,
autoConnectUserRelays: !storage.settings.lowPower, autoConnectUserRelays: !storage.settings.lowPower,
autoFetchUserMutelist: !storage.settings.lowPower, autoFetchUserMutelist: !storage.settings.lowPower,
// clientName: "Lume", clientName: "Lume",
// clientNip89: '',
}); });
// use tauri fetch // use tauri fetch

View File

@ -17,7 +17,7 @@ export function LogoutIcon(
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
strokeWidth="2" strokeWidth="2"
d="M18.189 9a15 15 0 012.654 2.556c.105.13.157.287.157.444m-2.811 3a14.998 14.998 0 002.654-2.556A.704.704 0 0021 12m0 0H8m5-7.472A6 6 0 003 9v6a6 6 0 0010 4.472" d="M5.812 9a15.001 15.001 0 00-2.655 2.556A.703.703 0 003 12m2.812 3a15 15 0 01-2.655-2.556A.703.703 0 013 12m0 0h13m-5-7.472A6 6 0 0121 9v6a6 6 0 01-10 4.472"
/> />
</svg> </svg>
); );

View File

@ -1,21 +1,24 @@
import { SVGProps } from 'react'; import { SVGProps } from "react";
export function UserIcon(props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>) { export function UserIcon(
return ( props: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
<svg ) {
xmlns="http://www.w3.org/2000/svg" return (
width="24" <svg
height="24" xmlns="http://www.w3.org/2000/svg"
fill="none" width="24"
viewBox="0 0 24 24" height="24"
{...props} fill="none"
> viewBox="0 0 24 24"
<path {...props}
stroke="currentColor" >
strokeLinejoin="round" <path
strokeWidth="1.5" stroke="currentColor"
d="M5.857 18.916C7.171 16.996 9.332 15.75 12 15.75c2.668 0 4.83 1.247 6.143 3.166m-12.286 0A9.215 9.215 0 0012 21.25c2.358 0 4.51-.882 6.143-2.334m-12.286 0a9.25 9.25 0 1112.286 0M15.25 10a3.25 3.25 0 11-6.5 0 3.25 3.25 0 016.5 0z" strokeLinecap="round"
></path> strokeLinejoin="round"
</svg> strokeWidth="2"
); d="M18.995 19.147C18.893 17.393 17.367 16 15.5 16h-7c-1.867 0-3.393 1.393-3.495 3.147m13.99 0A9.97 9.97 0 0022 12c0-5.523-4.477-10-10-10S2 6.477 2 12a9.97 9.97 0 003.005 7.147m13.99 0A9.967 9.967 0 0112 22a9.967 9.967 0 01-6.995-2.853M15 10a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
);
} }

View File

@ -1,5 +1,5 @@
import { useArk, useProfile } from "@lume/ark"; import { useArk, useProfile } from "@lume/ark";
import { SettingsIcon } from "@lume/icons"; import { SettingsIcon, UserIcon } from "@lume/icons";
import { cn, useNetworkStatus } from "@lume/utils"; import { cn, useNetworkStatus } from "@lume/utils";
import * as Avatar from "@radix-ui/react-avatar"; import * as Avatar from "@radix-ui/react-avatar";
import * as DropdownMenu from "@radix-ui/react-dropdown-menu"; import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
@ -54,17 +54,27 @@ export function ActiveAccount() {
<DropdownMenu.Content <DropdownMenu.Content
side="right" side="right"
sideOffset={5} sideOffset={5}
className="flex w-[200px] p-2 flex-col overflow-hidden rounded-2xl bg-black/70 dark:bg-white/10 backdrop-blur-xl focus:outline-none" className="relative top-5 flex w-[200px] p-2 flex-col overflow-hidden rounded-2xl bg-white/50 dark:bg-black/50 ring-1 ring-black/10 dark:ring-white/10 backdrop-blur-2xl focus:outline-none"
> >
<DropdownMenu.Item asChild> <DropdownMenu.Item asChild>
<Link <Link
to="/settings/" to="/settings/profile"
className="inline-flex items-center gap-2 px-3 text-sm font-medium rounded-lg h-9 text-white/50 hover:bg-black/10 hover:text-white focus:outline-none dark:text-white/50 dark:hover:bg-white/10 dark:hover:text-white" className="inline-flex items-center gap-3 px-3 text-sm font-medium rounded-lg h-9 text-black/70 hover:bg-black/10 hover:text-black focus:outline-none dark:text-white/70 dark:hover:bg-white/10 dark:hover:text-white"
> >
<SettingsIcon className="size-5" /> <UserIcon className="size-4" />
Edit profile
</Link>
</DropdownMenu.Item>
<DropdownMenu.Item asChild>
<Link
to="/settings/"
className="inline-flex items-center gap-3 px-3 text-sm font-medium rounded-lg h-9 text-black/70 hover:bg-black/10 hover:text-black focus:outline-none dark:text-white/70 dark:hover:bg-white/10 dark:hover:text-white"
>
<SettingsIcon className="size-4" />
Settings Settings
</Link> </Link>
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Separator className="h-px my-1 bg-black/10 dark:bg-white/10" />
<Logout /> <Logout />
</DropdownMenu.Content> </DropdownMenu.Content>
</DropdownMenu.Portal> </DropdownMenu.Portal>

View File

@ -35,9 +35,9 @@ export function Logout() {
<AlertDialog.Trigger asChild> <AlertDialog.Trigger asChild>
<button <button
type="button" type="button"
className="inline-flex items-center gap-2 px-3 text-sm font-medium rounded-lg h-9 text-white/50 hover:bg-black/10 hover:text-white focus:outline-none dark:text-white/50 dark:hover:bg-white/10 dark:hover:text-white" className="inline-flex items-center gap-3 px-3 text-sm font-medium rounded-lg h-9 text-black/70 hover:bg-black/10 hover:text-black focus:outline-none dark:text-white/70 dark:hover:bg-white/10 dark:hover:text-white"
> >
<LogoutIcon className="size-5" /> <LogoutIcon className="size-4" />
Logout Logout
</button> </button>
</AlertDialog.Trigger> </AlertDialog.Trigger>

View File

@ -106,7 +106,7 @@ const Image = ({ attributes, children, element }) => {
return ( return (
<div {...attributes}> <div {...attributes}>
{children} {children}
<div contentEditable={false} className="relative"> <div contentEditable={false} className="relative my-2">
<img <img
src={element.url} src={element.url}
alt={element.url} alt={element.url}
@ -155,7 +155,7 @@ const Event = ({ attributes, element, children }) => {
<div <div
contentEditable={false} contentEditable={false}
onClick={() => Transforms.removeNodes(editor, { at: path })} onClick={() => Transforms.removeNodes(editor, { at: path })}
className="relative user-select-none" className="relative user-select-none my-2"
> >
<MentionNote <MentionNote
eventId={element.eventId.replace("nostr:", "")} eventId={element.eventId.replace("nostr:", "")}
@ -319,11 +319,9 @@ export function EditorForm() {
setTarget(null); setTarget(null);
}} }}
> >
<div className="flex items-center justify-between h-16 px-3 border-b shrink-0 border-neutral-100 dark:border-neutral-900 bg-neutral-50 dark:bg-neutral-950"> <div className="flex items-center justify-between h-16 pl-7 pr-3 border-b shrink-0 border-neutral-100 dark:border-neutral-900 bg-neutral-50 dark:bg-neutral-950">
<div> <div>
<h3 className="font-semibold text-neutral-700 dark:text-neutral-500"> <h3 className="font-medium">New Post</h3>
New Post
</h3>
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
<div className="inline-flex items-center gap-2"> <div className="inline-flex items-center gap-2">
@ -346,7 +344,7 @@ export function EditorForm() {
<div className="py-6 h-full overflow-y-auto px-7"> <div className="py-6 h-full overflow-y-auto px-7">
<Editable <Editable
key={JSON.stringify(editorValue)} key={JSON.stringify(editorValue)}
autoFocus={false} autoFocus={true}
autoCapitalize="none" autoCapitalize="none"
autoCorrect="none" autoCorrect="none"
spellCheck={false} spellCheck={false}
@ -361,9 +359,9 @@ export function EditorForm() {
className="top-[-9999px] left-[-9999px] absolute z-10 w-[250px] p-1 bg-white border border-neutral-50 dark:border-neutral-900 dark:bg-neutral-950 rounded-lg shadow-lg" className="top-[-9999px] left-[-9999px] absolute z-10 w-[250px] p-1 bg-white border border-neutral-50 dark:border-neutral-900 dark:bg-neutral-950 rounded-lg shadow-lg"
> >
{filters.map((contact, i) => ( {filters.map((contact, i) => (
// biome-ignore lint/a11y/useKeyWithClickEvents: <explanation> <button
<div
key={contact.npub} key={contact.npub}
type="button"
onClick={() => { onClick={() => {
Transforms.select(editor, target); Transforms.select(editor, target);
insertMention(editor, contact); insertMention(editor, contact);
@ -379,7 +377,7 @@ export function EditorForm() {
</div> </div>
</User.Root> </User.Root>
</User.Provider> </User.Provider>
</div> </button>
))} ))}
</div> </div>
</Portal> </Portal>

View File

@ -2,7 +2,7 @@ import { NDKCacheUserProfile } from "@lume/types";
import { ReactNode } from "react"; import { ReactNode } from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import { BaseEditor, Transforms } from "slate"; import { BaseEditor, Transforms } from "slate";
import { type ReactEditor } from "slate-react"; import { ReactEditor } from "slate-react";
export const Portal = ({ children }: { children?: ReactNode }) => { export const Portal = ({ children }: { children?: ReactNode }) => {
return typeof document === "object" return typeof document === "object"
@ -36,6 +36,8 @@ export const insertImage = (editor: ReactEditor | BaseEditor, url: string) => {
}, },
]; ];
// @ts-ignore, idk
ReactEditor.focus(editor);
Transforms.insertNodes(editor, image); Transforms.insertNodes(editor, image);
Transforms.insertNodes(editor, extraText); Transforms.insertNodes(editor, extraText);
}; };
@ -44,15 +46,24 @@ export const insertMention = (
editor: ReactEditor | BaseEditor, editor: ReactEditor | BaseEditor,
contact: NDKCacheUserProfile, contact: NDKCacheUserProfile,
) => { ) => {
const text = { text: "" };
const mention = { const mention = {
type: "mention", type: "mention",
npub: `nostr:${contact.npub}`, npub: `nostr:${contact.npub}`,
name: contact.name || contact.displayName || "anon", name: contact.name || contact.displayName || "anon",
children: [{ text: "" }], children: [text],
}; };
const extraText = [
{
type: "paragraph",
children: [text],
},
];
// @ts-ignore, idk
ReactEditor.focus(editor);
Transforms.insertNodes(editor, mention); Transforms.insertNodes(editor, mention);
Transforms.move(editor); Transforms.insertNodes(editor, extraText);
}; };
export const insertNostrEvent = ( export const insertNostrEvent = (