mirror of
https://github.com/luminous-devs/lume.git
synced 2024-09-29 16:30:55 +00:00
feat: migrate note component to i18n
This commit is contained in:
parent
b97676dd3e
commit
698bd78684
@ -32,6 +32,7 @@
|
|||||||
"re-resizable": "^6.9.11",
|
"re-resizable": "^6.9.11",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-currency-input-field": "^3.6.14",
|
"react-currency-input-field": "^3.6.14",
|
||||||
|
"react-i18next": "^14.0.1",
|
||||||
"react-router-dom": "^6.21.3",
|
"react-router-dom": "^6.21.3",
|
||||||
"react-string-replace": "^1.1.1",
|
"react-string-replace": "^1.1.1",
|
||||||
"sonner": "^1.3.1",
|
"sonner": "^1.3.1",
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import { PinIcon } from "@lume/icons";
|
import { PinIcon } from "@lume/icons";
|
||||||
import { COL_TYPES } from "@lume/utils";
|
import { COL_TYPES } from "@lume/utils";
|
||||||
import * as Tooltip from "@radix-ui/react-tooltip";
|
import * as Tooltip from "@radix-ui/react-tooltip";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { useColumnContext } from "../../column/provider";
|
import { useColumnContext } from "../../column/provider";
|
||||||
import { useNoteContext } from "../provider";
|
import { useNoteContext } from "../provider";
|
||||||
|
|
||||||
export function NotePin() {
|
export function NotePin() {
|
||||||
const event = useNoteContext();
|
const event = useNoteContext();
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
const { addColumn } = useColumnContext();
|
const { addColumn } = useColumnContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -24,12 +27,12 @@ export function NotePin() {
|
|||||||
className="inline-flex items-center justify-center gap-2 pl-2 pr-3 text-sm font-medium rounded-full h-7 w-max bg-neutral-100 hover:bg-neutral-200 dark:hover:bg-neutral-800 dark:bg-neutral-900"
|
className="inline-flex items-center justify-center gap-2 pl-2 pr-3 text-sm font-medium rounded-full h-7 w-max bg-neutral-100 hover:bg-neutral-200 dark:hover:bg-neutral-800 dark:bg-neutral-900"
|
||||||
>
|
>
|
||||||
<PinIcon className="size-4" />
|
<PinIcon className="size-4" />
|
||||||
Pin
|
{t("note.buttons.pin")}
|
||||||
</button>
|
</button>
|
||||||
</Tooltip.Trigger>
|
</Tooltip.Trigger>
|
||||||
<Tooltip.Portal>
|
<Tooltip.Portal>
|
||||||
<Tooltip.Content className="inline-flex h-7 select-none text-neutral-50 dark:text-neutral-950 items-center justify-center rounded-md bg-neutral-950 dark:bg-neutral-50 px-3.5 text-sm will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade">
|
<Tooltip.Content className="inline-flex h-7 select-none text-neutral-50 dark:text-neutral-950 items-center justify-center rounded-md bg-neutral-950 dark:bg-neutral-50 px-3.5 text-sm will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade">
|
||||||
Pin note
|
{t("note.buttons.pinTooltip")}
|
||||||
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
||||||
</Tooltip.Content>
|
</Tooltip.Content>
|
||||||
</Tooltip.Portal>
|
</Tooltip.Portal>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { ReplyIcon } from "@lume/icons";
|
import { ReplyIcon } from "@lume/icons";
|
||||||
import * as Tooltip from "@radix-ui/react-tooltip";
|
import * as Tooltip from "@radix-ui/react-tooltip";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useNoteContext } from "../provider";
|
import { useNoteContext } from "../provider";
|
||||||
|
|
||||||
@ -7,6 +8,8 @@ export function NoteReply() {
|
|||||||
const event = useNoteContext();
|
const event = useNoteContext();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip.Provider>
|
<Tooltip.Provider>
|
||||||
<Tooltip.Root delayDuration={150}>
|
<Tooltip.Root delayDuration={150}>
|
||||||
@ -21,7 +24,7 @@ export function NoteReply() {
|
|||||||
</Tooltip.Trigger>
|
</Tooltip.Trigger>
|
||||||
<Tooltip.Portal>
|
<Tooltip.Portal>
|
||||||
<Tooltip.Content className="inline-flex h-7 select-none text-neutral-50 dark:text-neutral-950 items-center justify-center rounded-md bg-neutral-950 dark:bg-neutral-50 px-3.5 text-sm will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade">
|
<Tooltip.Content className="inline-flex h-7 select-none text-neutral-50 dark:text-neutral-950 items-center justify-center rounded-md bg-neutral-950 dark:bg-neutral-50 px-3.5 text-sm will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade">
|
||||||
View thread
|
{t("note.menu.viewThread")}
|
||||||
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
||||||
</Tooltip.Content>
|
</Tooltip.Content>
|
||||||
</Tooltip.Portal>
|
</Tooltip.Portal>
|
||||||
|
@ -5,6 +5,7 @@ import * as Tooltip from "@radix-ui/react-tooltip";
|
|||||||
import { useSetAtom } from "jotai";
|
import { useSetAtom } from "jotai";
|
||||||
import { nip19 } from "nostr-tools";
|
import { nip19 } from "nostr-tools";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useNoteContext } from "../provider";
|
import { useNoteContext } from "../provider";
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ export function NoteRepost() {
|
|||||||
const setEditorValue = useSetAtom(editorValueAtom);
|
const setEditorValue = useSetAtom(editorValueAtom);
|
||||||
const setIsEditorOpen = useSetAtom(editorAtom);
|
const setIsEditorOpen = useSetAtom(editorAtom);
|
||||||
|
|
||||||
|
const [t] = useTranslation();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [isRepost, setIsRepost] = useState(false);
|
const [isRepost, setIsRepost] = useState(false);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
@ -81,7 +83,7 @@ export function NoteRepost() {
|
|||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
<Tooltip.Portal>
|
<Tooltip.Portal>
|
||||||
<Tooltip.Content className="inline-flex h-7 select-none text-neutral-50 dark:text-neutral-950 items-center justify-center rounded-md bg-neutral-950 dark:bg-neutral-50 px-3.5 text-sm will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade">
|
<Tooltip.Content className="inline-flex h-7 select-none text-neutral-50 dark:text-neutral-950 items-center justify-center rounded-md bg-neutral-950 dark:bg-neutral-50 px-3.5 text-sm will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade">
|
||||||
Repost
|
{t("note.buttons.repost")}
|
||||||
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
||||||
</Tooltip.Content>
|
</Tooltip.Content>
|
||||||
</Tooltip.Portal>
|
</Tooltip.Portal>
|
||||||
@ -96,7 +98,7 @@ export function NoteRepost() {
|
|||||||
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"
|
||||||
>
|
>
|
||||||
<RepostIcon className="size-4" />
|
<RepostIcon className="size-4" />
|
||||||
Repost
|
{t("note.buttons.repost")}
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
<DropdownMenu.Item asChild>
|
<DropdownMenu.Item asChild>
|
||||||
@ -106,7 +108,7 @@ export function NoteRepost() {
|
|||||||
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"
|
||||||
>
|
>
|
||||||
<ReplyIcon className="size-4" />
|
<ReplyIcon className="size-4" />
|
||||||
Quote
|
{t("note.buttons.quote")}
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
|
@ -8,6 +8,7 @@ import * as Tooltip from "@radix-ui/react-tooltip";
|
|||||||
import { QRCodeSVG } from "qrcode.react";
|
import { QRCodeSVG } from "qrcode.react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import CurrencyInput from "react-currency-input-field";
|
import CurrencyInput from "react-currency-input-field";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useProfile } from "../../../hooks/useProfile";
|
import { useProfile } from "../../../hooks/useProfile";
|
||||||
import { useNoteContext } from "../provider";
|
import { useNoteContext } from "../provider";
|
||||||
@ -23,6 +24,7 @@ export function NoteZap() {
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [invoice, setInvoice] = useState<string>(null);
|
const [invoice, setInvoice] = useState<string>(null);
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
const { user } = useProfile(event.pubkey);
|
const { user } = useProfile(event.pubkey);
|
||||||
|
|
||||||
const createZapRequest = async (instant?: boolean) => {
|
const createZapRequest = async (instant?: boolean) => {
|
||||||
@ -99,7 +101,7 @@ export function NoteZap() {
|
|||||||
</Tooltip.Trigger>
|
</Tooltip.Trigger>
|
||||||
<Tooltip.Portal>
|
<Tooltip.Portal>
|
||||||
<Tooltip.Content className="inline-flex h-7 select-none text-neutral-50 dark:text-neutral-950 items-center justify-center rounded-md bg-neutral-950 dark:bg-neutral-50 px-3.5 text-sm will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade">
|
<Tooltip.Content className="inline-flex h-7 select-none text-neutral-50 dark:text-neutral-950 items-center justify-center rounded-md bg-neutral-950 dark:bg-neutral-50 px-3.5 text-sm will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade">
|
||||||
Zap
|
{t("note.zap.tooltip")}
|
||||||
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
||||||
</Tooltip.Content>
|
</Tooltip.Content>
|
||||||
</Tooltip.Portal>
|
</Tooltip.Portal>
|
||||||
@ -124,7 +126,7 @@ export function NoteZap() {
|
|||||||
</Dialog.Trigger>
|
</Dialog.Trigger>
|
||||||
<Tooltip.Portal>
|
<Tooltip.Portal>
|
||||||
<Tooltip.Content className="inline-flex h-7 select-none text-neutral-50 dark:text-neutral-950 items-center justify-center rounded-md bg-neutral-950 dark:bg-neutral-50 px-3.5 text-sm will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade">
|
<Tooltip.Content className="inline-flex h-7 select-none text-neutral-50 dark:text-neutral-950 items-center justify-center rounded-md bg-neutral-950 dark:bg-neutral-50 px-3.5 text-sm will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade">
|
||||||
Zap
|
{t("note.zap.tooltip")}
|
||||||
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
||||||
</Tooltip.Content>
|
</Tooltip.Content>
|
||||||
</Tooltip.Portal>
|
</Tooltip.Portal>
|
||||||
@ -145,7 +147,7 @@ export function NoteZap() {
|
|||||||
<div className="inline-flex items-center justify-center 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{" "}
|
{t("note.zap.modalTitle")}{" "}
|
||||||
{user?.name ||
|
{user?.name ||
|
||||||
user?.displayName ||
|
user?.displayName ||
|
||||||
displayNpub(event.pubkey, 16)}
|
displayNpub(event.pubkey, 16)}
|
||||||
@ -217,7 +219,7 @@ export function NoteZap() {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect="off"
|
autoCorrect="off"
|
||||||
autoCapitalize="off"
|
autoCapitalize="off"
|
||||||
placeholder="Enter message (optional)"
|
placeholder={t("note.zap.messagePlaceholder")}
|
||||||
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"
|
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">
|
||||||
@ -227,10 +229,10 @@ export function NoteZap() {
|
|||||||
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"
|
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"
|
? t("note.zap.buttonFinish")
|
||||||
: isLoading
|
: isLoading
|
||||||
? "Processing..."
|
? t("note.zap.buttonLoading")
|
||||||
: "Zap"}
|
: t("note.zap.zap")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -241,11 +243,11 @@ export function NoteZap() {
|
|||||||
<QRCodeSVG value={invoice} size={256} />
|
<QRCodeSVG value={invoice} size={256} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-center gap-1">
|
<div className="flex flex-col items-center gap-1">
|
||||||
<h3 className="text-lg font-medium">Scan to zap</h3>
|
<h3 className="text-lg font-medium">
|
||||||
|
{t("note.zap.invoiceButton")}
|
||||||
|
</h3>
|
||||||
<span className="text-center text-sm text-neutral-600 dark:text-neutral-400">
|
<span className="text-center text-sm text-neutral-600 dark:text-neutral-400">
|
||||||
You must use Bitcoin wallet which support Lightning
|
{t("note.zap.invoiceFooter")}
|
||||||
<br />
|
|
||||||
such as: Blue Wallet, Bitkit, Phoenix,...
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { NOSTR_MENTIONS } from "@lume/utils";
|
import { NOSTR_MENTIONS } from "@lume/utils";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { nip19 } from "nostr-tools";
|
|
||||||
import { ReactNode, useMemo } from "react";
|
import { ReactNode, useMemo } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import reactStringReplace from "react-string-replace";
|
import reactStringReplace from "react-string-replace";
|
||||||
import { useEvent } from "../../hooks/useEvent";
|
import { useEvent } from "../../hooks/useEvent";
|
||||||
@ -13,6 +13,7 @@ export function NoteChild({
|
|||||||
eventId,
|
eventId,
|
||||||
isRoot,
|
isRoot,
|
||||||
}: { eventId: string; isRoot?: boolean }) {
|
}: { eventId: string; isRoot?: boolean }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { isLoading, isError, data } = useEvent(eventId);
|
const { isLoading, isError, data } = useEvent(eventId);
|
||||||
|
|
||||||
const richContent = useMemo(() => {
|
const richContent = useMemo(() => {
|
||||||
@ -91,7 +92,7 @@ export function NoteChild({
|
|||||||
return (
|
return (
|
||||||
<div className="relative flex gap-3">
|
<div className="relative flex gap-3">
|
||||||
<div className="relative flex-1 rounded-md bg-neutral-200 px-2 py-2 dark:bg-neutral-800">
|
<div className="relative flex-1 rounded-md bg-neutral-200 px-2 py-2 dark:bg-neutral-800">
|
||||||
Failed to fetch event
|
{t("note.error")}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -111,7 +112,7 @@ export function NoteChild({
|
|||||||
<div className="absolute left-2 top-2 inline-flex items-center gap-1.5 font-semibold leading-tight">
|
<div className="absolute left-2 top-2 inline-flex items-center gap-1.5 font-semibold leading-tight">
|
||||||
<User.Name className="max-w-[10rem] truncate" />
|
<User.Name className="max-w-[10rem] truncate" />
|
||||||
<div className="font-normal text-neutral-700 dark:text-neutral-300">
|
<div className="font-normal text-neutral-700 dark:text-neutral-300">
|
||||||
{isRoot ? "posted:" : "replied:"}
|
{isRoot ? t("note.posted") : t("note.replied")}:
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</User.Root>
|
</User.Root>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { PinIcon } from "@lume/icons";
|
import { PinIcon } from "@lume/icons";
|
||||||
import { COL_TYPES, NOSTR_MENTIONS } from "@lume/utils";
|
import { COL_TYPES, NOSTR_MENTIONS } from "@lume/utils";
|
||||||
import { ReactNode, useMemo } from "react";
|
import { ReactNode, useMemo } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import reactStringReplace from "react-string-replace";
|
import reactStringReplace from "react-string-replace";
|
||||||
import { useEvent } from "../../../hooks/useEvent";
|
import { useEvent } from "../../../hooks/useEvent";
|
||||||
@ -13,6 +14,7 @@ export function MentionNote({
|
|||||||
eventId,
|
eventId,
|
||||||
openable = true,
|
openable = true,
|
||||||
}: { eventId: string; openable?: boolean }) {
|
}: { eventId: string; openable?: boolean }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { addColumn } = useColumnContext();
|
const { addColumn } = useColumnContext();
|
||||||
const { isLoading, isError, data } = useEvent(eventId);
|
const { isLoading, isError, data } = useEvent(eventId);
|
||||||
|
|
||||||
@ -98,7 +100,7 @@ export function MentionNote({
|
|||||||
contentEditable={false}
|
contentEditable={false}
|
||||||
className="w-full p-3 my-1 rounded-lg cursor-default bg-neutral-100 dark:bg-neutral-900"
|
className="w-full p-3 my-1 rounded-lg cursor-default bg-neutral-100 dark:bg-neutral-900"
|
||||||
>
|
>
|
||||||
Failed to fetch event.
|
{t("note.error")}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -127,7 +129,7 @@ export function MentionNote({
|
|||||||
to={`/events/${data.id}`}
|
to={`/events/${data.id}`}
|
||||||
className="text-sm text-blue-500 hover:text-blue-600"
|
className="text-sm text-blue-500 hover:text-blue-600"
|
||||||
>
|
>
|
||||||
Show more
|
{t("note.showMore")}
|
||||||
</Link>
|
</Link>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { COL_TYPES } from "@lume/utils";
|
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 { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { useArk } from "../../../hooks/useArk";
|
import { useArk } from "../../../hooks/useArk";
|
||||||
import { useProfile } from "../../../hooks/useProfile";
|
import { useProfile } from "../../../hooks/useProfile";
|
||||||
@ -10,6 +11,7 @@ export function MentionUser({ pubkey }: { pubkey: string }) {
|
|||||||
const cleanPubkey = ark.getCleanPubkey(pubkey);
|
const cleanPubkey = ark.getCleanPubkey(pubkey);
|
||||||
|
|
||||||
const { isLoading, isError, user } = useProfile(pubkey);
|
const { isLoading, isError, user } = useProfile(pubkey);
|
||||||
|
const { t } = useTranslation();
|
||||||
const { addColumn } = useColumnContext();
|
const { addColumn } = useColumnContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -27,7 +29,7 @@ export function MentionUser({ pubkey }: { pubkey: string }) {
|
|||||||
to={`/users/${cleanPubkey}`}
|
to={`/users/${cleanPubkey}`}
|
||||||
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
|
{t("note.buttons.viewProfile")}
|
||||||
</Link>
|
</Link>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
<DropdownMenu.Item asChild>
|
<DropdownMenu.Item asChild>
|
||||||
@ -36,13 +38,13 @@ export function MentionUser({ pubkey }: { pubkey: string }) {
|
|||||||
onClick={async () =>
|
onClick={async () =>
|
||||||
await addColumn({
|
await addColumn({
|
||||||
kind: COL_TYPES.user,
|
kind: COL_TYPES.user,
|
||||||
title: user?.name || user?.displayName || "Profile",
|
title: user?.name || user?.displayName || "User",
|
||||||
content: cleanPubkey,
|
content: cleanPubkey,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
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"
|
||||||
>
|
>
|
||||||
Pin
|
{t("note.buttons.pin")}
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
|
@ -5,6 +5,7 @@ import { writeText } from "@tauri-apps/plugin-clipboard-manager";
|
|||||||
import { nip19 } from "nostr-tools";
|
import { nip19 } from "nostr-tools";
|
||||||
import { type EventPointer } from "nostr-tools/lib/types/nip19";
|
import { type EventPointer } from "nostr-tools/lib/types/nip19";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
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 { useColumnContext } from "../column/provider";
|
||||||
@ -13,7 +14,10 @@ import { useNoteContext } from "./provider";
|
|||||||
export function NoteMenu() {
|
export function NoteMenu() {
|
||||||
const event = useNoteContext();
|
const event = useNoteContext();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
const { addColumn } = useColumnContext();
|
const { addColumn } = useColumnContext();
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
const copyID = async () => {
|
const copyID = async () => {
|
||||||
@ -67,7 +71,7 @@ export function NoteMenu() {
|
|||||||
onClick={() => copyLink()}
|
onClick={() => copyLink()}
|
||||||
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 thread
|
{t("note.menu.viewThread")}
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
<DropdownMenu.Item asChild>
|
<DropdownMenu.Item asChild>
|
||||||
@ -76,7 +80,7 @@ export function NoteMenu() {
|
|||||||
onClick={() => navigate(`/events/${event.id}`)}
|
onClick={() => navigate(`/events/${event.id}`)}
|
||||||
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"
|
||||||
>
|
>
|
||||||
Copy shareable link
|
{t("note.menu.copyLink")}
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
<DropdownMenu.Item asChild>
|
<DropdownMenu.Item asChild>
|
||||||
@ -85,7 +89,7 @@ export function NoteMenu() {
|
|||||||
onClick={() => copyID()}
|
onClick={() => copyID()}
|
||||||
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"
|
||||||
>
|
>
|
||||||
Copy note ID
|
{t("note.menu.copyNoteId")}
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
<DropdownMenu.Item asChild>
|
<DropdownMenu.Item asChild>
|
||||||
@ -94,7 +98,7 @@ export function NoteMenu() {
|
|||||||
onClick={() => copyNpub()}
|
onClick={() => copyNpub()}
|
||||||
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"
|
||||||
>
|
>
|
||||||
Copy author ID
|
{t("note.menu.copyAuthorId")}
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
<DropdownMenu.Item asChild>
|
<DropdownMenu.Item asChild>
|
||||||
@ -102,7 +106,7 @@ 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 author
|
{t("note.menu.viewAuthor")}
|
||||||
</Link>
|
</Link>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
<DropdownMenu.Item asChild>
|
<DropdownMenu.Item asChild>
|
||||||
@ -117,7 +121,7 @@ export function NoteMenu() {
|
|||||||
}
|
}
|
||||||
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"
|
||||||
>
|
>
|
||||||
Pin author
|
{t("note.menu.pinAuthor")}
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenu.Item>
|
</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" />
|
||||||
@ -127,7 +131,7 @@ export function NoteMenu() {
|
|||||||
onClick={() => copyRaw()}
|
onClick={() => copyRaw()}
|
||||||
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"
|
||||||
>
|
>
|
||||||
Copy raw event
|
{t("note.menu.copyRaw")}
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
<DropdownMenu.Item asChild>
|
<DropdownMenu.Item asChild>
|
||||||
@ -136,7 +140,7 @@ export function NoteMenu() {
|
|||||||
onClick={muteUser}
|
onClick={muteUser}
|
||||||
className="inline-flex items-center gap-3 px-3 text-sm font-medium text-red-500 rounded-lg h-9 hover:bg-red-500 hover:text-red-50 focus:outline-none"
|
className="inline-flex items-center gap-3 px-3 text-sm font-medium text-red-500 rounded-lg h-9 hover:bg-red-500 hover:text-red-50 focus:outline-none"
|
||||||
>
|
>
|
||||||
Mute
|
{t("note.menu.mute")}
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { useArk } from "../../hooks/useArk";
|
import { useArk } from "../../hooks/useArk";
|
||||||
import { AppHandler } from "./appHandler";
|
import { AppHandler } from "./appHandler";
|
||||||
import { useNoteContext } from "./provider";
|
import { useNoteContext } from "./provider";
|
||||||
@ -7,6 +8,7 @@ export function NIP89({ className }: { className?: string }) {
|
|||||||
const ark = useArk();
|
const ark = useArk();
|
||||||
const event = useNoteContext();
|
const event = useNoteContext();
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
const { isLoading, isError, data } = useQuery({
|
const { isLoading, isError, data } = useQuery({
|
||||||
queryKey: ["app-recommend", event.id],
|
queryKey: ["app-recommend", event.id],
|
||||||
queryFn: () => {
|
queryFn: () => {
|
||||||
@ -33,7 +35,7 @@ export function NIP89({ className }: { className?: string }) {
|
|||||||
<div className="flex flex-col rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
<div className="flex flex-col rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||||
<div className="inline-flex items-center justify-between h-10 px-3 border-b shrink-0 border-neutral-200 dark:border-neutral-800">
|
<div className="inline-flex items-center justify-between h-10 px-3 border-b shrink-0 border-neutral-200 dark:border-neutral-800">
|
||||||
<p className="text-sm font-medium text-amber-400">
|
<p className="text-sm font-medium text-amber-400">
|
||||||
Lume isn't support this event
|
{t("nip89.unsupported")}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
||||||
{event.kind}
|
{event.kind}
|
||||||
@ -41,10 +43,10 @@ export function NIP89({ className }: { className?: string }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col flex-1 gap-2 px-3 py-3">
|
<div className="flex flex-col flex-1 gap-2 px-3 py-3">
|
||||||
<span className="text-sm font-medium uppercase text-neutral-600 dark:text-neutral-400">
|
<span className="text-sm font-medium uppercase text-neutral-600 dark:text-neutral-400">
|
||||||
Open with
|
{t("nip89.openWith")}
|
||||||
</span>
|
</span>
|
||||||
{data.map((item, index) => (
|
{data.map((item) => (
|
||||||
<AppHandler key={item[1] + index} tag={item} />
|
<AppHandler key={item[1]} tag={item} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,6 +3,7 @@ import { NDKEventWithReplies } from "@lume/types";
|
|||||||
import { cn } from "@lume/utils";
|
import { cn } from "@lume/utils";
|
||||||
import * as Collapsible from "@radix-ui/react-collapsible";
|
import * as Collapsible from "@radix-ui/react-collapsible";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { Note } from "..";
|
import { Note } from "..";
|
||||||
import { ChildReply } from "./childReply";
|
import { ChildReply } from "./childReply";
|
||||||
|
|
||||||
@ -11,6 +12,7 @@ export function Reply({
|
|||||||
}: {
|
}: {
|
||||||
event: NDKEventWithReplies;
|
event: NDKEventWithReplies;
|
||||||
}) {
|
}) {
|
||||||
|
const [t] = useTranslation();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -30,7 +32,9 @@ export function Reply({
|
|||||||
className={cn("size-5", open ? "rotate-180 transform" : "")}
|
className={cn("size-5", open ? "rotate-180 transform" : "")}
|
||||||
/>
|
/>
|
||||||
{`${event.replies?.length} ${
|
{`${event.replies?.length} ${
|
||||||
event.replies?.length === 1 ? "reply" : "replies"
|
event.replies?.length === 1
|
||||||
|
? t("note.reply.single")
|
||||||
|
: t("note.reply.plural")
|
||||||
}`}
|
}`}
|
||||||
</div>
|
</div>
|
||||||
</Collapsible.Trigger>
|
</Collapsible.Trigger>
|
||||||
|
@ -2,6 +2,7 @@ import { RepostIcon } from "@lume/icons";
|
|||||||
import { cn } from "@lume/utils";
|
import { cn } from "@lume/utils";
|
||||||
import { NDKEvent, NostrEvent } from "@nostr-dev-kit/ndk";
|
import { NDKEvent, NostrEvent } from "@nostr-dev-kit/ndk";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { Note } from "..";
|
import { Note } from "..";
|
||||||
import { useArk } from "../../../hooks/useArk";
|
import { useArk } from "../../../hooks/useArk";
|
||||||
import { User } from "../../user";
|
import { User } from "../../user";
|
||||||
@ -12,6 +13,7 @@ export function RepostNote({
|
|||||||
}: { event: NDKEvent; className?: string }) {
|
}: { event: NDKEvent; className?: string }) {
|
||||||
const ark = useArk();
|
const ark = useArk();
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
const {
|
const {
|
||||||
isLoading,
|
isLoading,
|
||||||
isError,
|
isError,
|
||||||
@ -51,7 +53,7 @@ export function RepostNote({
|
|||||||
<User.Avatar className="size-6 shrink-0 rounded object-cover" />
|
<User.Avatar className="size-6 shrink-0 rounded object-cover" />
|
||||||
<div className="inline-flex items-baseline gap-1">
|
<div className="inline-flex items-baseline gap-1">
|
||||||
<User.Name className="font-medium text-neutral-900 dark:text-neutral-100" />
|
<User.Name className="font-medium text-neutral-900 dark:text-neutral-100" />
|
||||||
<span className="text-blue-500">reposted</span>
|
<span className="text-blue-500">{t("note.reposted")}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</User.Root>
|
</User.Root>
|
||||||
@ -59,10 +61,6 @@ export function RepostNote({
|
|||||||
<div className="px-3 mb-3 select-text">
|
<div className="px-3 mb-3 select-text">
|
||||||
<div className="flex flex-col items-start justify-start px-3 py-3 bg-red-100 rounded-lg dark:bg-red-900">
|
<div className="flex flex-col items-start justify-start px-3 py-3 bg-red-100 rounded-lg dark:bg-red-900">
|
||||||
<p className="text-red-500">Failed to get event</p>
|
<p className="text-red-500">Failed to get event</p>
|
||||||
<p className="text-sm">
|
|
||||||
You can consider enable Outbox in Settings for better event
|
|
||||||
discovery.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Note.Root>
|
</Note.Root>
|
||||||
@ -85,7 +83,7 @@ export function RepostNote({
|
|||||||
<User.Avatar className="size-6 shrink-0 rounded object-cover" />
|
<User.Avatar className="size-6 shrink-0 rounded object-cover" />
|
||||||
<div className="inline-flex items-baseline gap-1">
|
<div className="inline-flex items-baseline gap-1">
|
||||||
<User.Name className="font-medium text-neutral-900 dark:text-neutral-100" />
|
<User.Name className="font-medium text-neutral-900 dark:text-neutral-100" />
|
||||||
<span className="text-blue-500">reposted</span>
|
<span className="text-blue-500">{t("note.reposted")}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</User.Root>
|
</User.Root>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { PinIcon } from "@lume/icons";
|
import { PinIcon } from "@lume/icons";
|
||||||
import { COL_TYPES, cn } from "@lume/utils";
|
import { COL_TYPES, cn } from "@lume/utils";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { Note } from ".";
|
import { Note } from ".";
|
||||||
import { useArk } from "../../hooks/useArk";
|
import { useArk } from "../../hooks/useArk";
|
||||||
@ -18,6 +19,7 @@ export function NoteThread({
|
|||||||
tags: event.tags,
|
tags: event.tags,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
const { addColumn } = useColumnContext();
|
const { addColumn } = useColumnContext();
|
||||||
|
|
||||||
if (!thread) return null;
|
if (!thread) return null;
|
||||||
@ -36,7 +38,7 @@ export function NoteThread({
|
|||||||
to={`/events/${thread?.rootEventId || thread?.replyEventId}`}
|
to={`/events/${thread?.rootEventId || thread?.replyEventId}`}
|
||||||
className="self-start text-blue-500 hover:text-blue-600"
|
className="self-start text-blue-500 hover:text-blue-600"
|
||||||
>
|
>
|
||||||
Show thread
|
{t("note.showThread")}
|
||||||
</Link>
|
</Link>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { UnverifiedIcon, VerifiedIcon } from "@lume/icons";
|
import { VerifiedIcon } from "@lume/icons";
|
||||||
import { cn, displayNpub } from "@lume/utils";
|
import { cn, displayNpub } from "@lume/utils";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { useArk } from "../../hooks/useArk";
|
import { useArk } from "../../hooks/useArk";
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { NDKUserProfile } from "@nostr-dev-kit/ndk";
|
||||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { useArk } from "./useArk";
|
import { useArk } from "./useArk";
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ export function useProfile(pubkey: string) {
|
|||||||
return profile;
|
return profile;
|
||||||
},
|
},
|
||||||
initialData: () => {
|
initialData: () => {
|
||||||
return queryClient.getQueryData(["user", pubkey]);
|
return queryClient.getQueryData(["user", pubkey]) as NDKUserProfile;
|
||||||
},
|
},
|
||||||
refetchOnMount: false,
|
refetchOnMount: false,
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-hook-form": "^7.49.3",
|
"react-hook-form": "^7.49.3",
|
||||||
"react-hotkeys-hook": "^4.4.4",
|
"react-hotkeys-hook": "^4.4.4",
|
||||||
|
"react-i18next": "^14.0.1",
|
||||||
"react-router-dom": "^6.21.3",
|
"react-router-dom": "^6.21.3",
|
||||||
"slate": "^0.101.5",
|
"slate": "^0.101.5",
|
||||||
"slate-react": "^0.101.6",
|
"slate-react": "^0.101.6",
|
||||||
|
@ -365,6 +365,9 @@ importers:
|
|||||||
react-currency-input-field:
|
react-currency-input-field:
|
||||||
specifier: ^3.6.14
|
specifier: ^3.6.14
|
||||||
version: 3.6.14(react@18.2.0)
|
version: 3.6.14(react@18.2.0)
|
||||||
|
react-i18next:
|
||||||
|
specifier: ^14.0.1
|
||||||
|
version: 14.0.1(i18next@23.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||||
react-router-dom:
|
react-router-dom:
|
||||||
specifier: ^6.21.3
|
specifier: ^6.21.3
|
||||||
version: 6.21.3(react-dom@18.2.0)(react@18.2.0)
|
version: 6.21.3(react-dom@18.2.0)(react@18.2.0)
|
||||||
@ -999,6 +1002,9 @@ importers:
|
|||||||
react-hotkeys-hook:
|
react-hotkeys-hook:
|
||||||
specifier: ^4.4.4
|
specifier: ^4.4.4
|
||||||
version: 4.4.4(react-dom@18.2.0)(react@18.2.0)
|
version: 4.4.4(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
react-i18next:
|
||||||
|
specifier: ^14.0.1
|
||||||
|
version: 14.0.1(i18next@23.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||||
react-router-dom:
|
react-router-dom:
|
||||||
specifier: ^6.21.3
|
specifier: ^6.21.3
|
||||||
version: 6.21.3(react-dom@18.2.0)(react@18.2.0)
|
version: 6.21.3(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
@ -3,11 +3,55 @@
|
|||||||
"relay": "Relay",
|
"relay": "Relay",
|
||||||
"continue": "Continue",
|
"continue": "Continue",
|
||||||
"loading": "Loading",
|
"loading": "Loading",
|
||||||
|
"error": "Error",
|
||||||
"moveLeft": "Move Left",
|
"moveLeft": "Move Left",
|
||||||
"moveRight": "Move Right",
|
"moveRight": "Move Right",
|
||||||
"newColumn": "New Column",
|
"newColumn": "New Column",
|
||||||
"inspect": "Inspect"
|
"inspect": "Inspect"
|
||||||
},
|
},
|
||||||
|
"nip89": {
|
||||||
|
"unsupported": "Lume isn't support this event",
|
||||||
|
"openWith": "Open with"
|
||||||
|
},
|
||||||
|
"note": {
|
||||||
|
"showThread": "Show thread",
|
||||||
|
"showMore": "Show more",
|
||||||
|
"error": "Failed to fetch event.",
|
||||||
|
"posted": "posted",
|
||||||
|
"replied": "replied",
|
||||||
|
"reposted": "reposted",
|
||||||
|
"menu": {
|
||||||
|
"viewThread": "View thread",
|
||||||
|
"copyLink": "Copy shareable link",
|
||||||
|
"copyNoteId": "Copy note ID",
|
||||||
|
"copyAuthorId": "Copy author ID",
|
||||||
|
"viewAuthor": "View author",
|
||||||
|
"pinAuthor": "Pin author",
|
||||||
|
"copyRaw": "Copy raw event",
|
||||||
|
"mute": "Mute"
|
||||||
|
},
|
||||||
|
"buttons": {
|
||||||
|
"pin": "Pin",
|
||||||
|
"pinTooltip": "Pin Note",
|
||||||
|
"repost": "Repost",
|
||||||
|
"quote": "Quote",
|
||||||
|
"viewProfile": "View profile"
|
||||||
|
},
|
||||||
|
"zap": {
|
||||||
|
"zap": "Zap",
|
||||||
|
"tooltip": "Send zap",
|
||||||
|
"modalTitle": "Send zap to",
|
||||||
|
"messagePlaceholder": "Enter message (optional)",
|
||||||
|
"buttonFinish": "Zapped",
|
||||||
|
"buttonLoading": "Processing...",
|
||||||
|
"invoiceButton": "Scan to zap",
|
||||||
|
"invoiceFooter": "You must use Bitcoin wallet which support Lightning\nsuch as: Blue Wallet, Bitkit, Phoenix,..."
|
||||||
|
},
|
||||||
|
"reply": {
|
||||||
|
"single": "reply",
|
||||||
|
"plural": "replies"
|
||||||
|
}
|
||||||
|
},
|
||||||
"welcome": {
|
"welcome": {
|
||||||
"title": "Lume is a magnificent client for Nostr to meet, explore\nand freely share your thoughts with everyone.",
|
"title": "Lume is a magnificent client for Nostr to meet, explore\nand freely share your thoughts with everyone.",
|
||||||
"signup": "Join Nostr",
|
"signup": "Join Nostr",
|
||||||
|
Loading…
Reference in New Issue
Block a user