feat: the last commit of year
This commit is contained in:
@@ -17,35 +17,35 @@ export function ColumnHeader({
|
||||
queryKey,
|
||||
icon,
|
||||
}: {
|
||||
id: string;
|
||||
id: number;
|
||||
title: string;
|
||||
queryKey?: string[];
|
||||
icon?: ReactNode;
|
||||
}) {
|
||||
const queryClient = useQueryClient();
|
||||
const { removeColumn } = useColumnContext();
|
||||
const { moveColumn, removeColumn } = useColumnContext();
|
||||
|
||||
const refresh = async () => {
|
||||
if (queryKey) await queryClient.refetchQueries({ queryKey });
|
||||
};
|
||||
|
||||
const moveLeft = async () => {
|
||||
removeColumn(id);
|
||||
moveColumn(id, "left");
|
||||
};
|
||||
|
||||
const moveRight = async () => {
|
||||
removeColumn(id);
|
||||
moveColumn(id, "right");
|
||||
};
|
||||
|
||||
const deleteWidget = async () => {
|
||||
removeColumn(id);
|
||||
await removeColumn(id);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-11 w-full shrink-0 items-center justify-between border-b border-neutral-100 px-3 dark:border-neutral-900">
|
||||
<div className="flex items-center justify-between w-full px-3 border-b h-11 shrink-0 border-neutral-100 dark:border-neutral-900">
|
||||
<div className="inline-flex items-center gap-4">
|
||||
<div className="h-5 w-1 shrink-0 rounded-full bg-blue-500" />
|
||||
<div className="text-neutral-800 dark:text-neutral-200 inline-flex items-center gap-2 flex-1">
|
||||
<div className="w-1 h-5 bg-blue-500 rounded-full shrink-0" />
|
||||
<div className="inline-flex items-center flex-1 gap-2 text-neutral-800 dark:text-neutral-200">
|
||||
{icon ? icon : <ThreadIcon className="size-4" />}
|
||||
<div className="text-sm font-medium">{title}</div>
|
||||
</div>
|
||||
@@ -55,7 +55,7 @@ export function ColumnHeader({
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-6 w-6 items-center justify-center"
|
||||
className="inline-flex items-center justify-center w-6 h-6"
|
||||
>
|
||||
<HorizontalDotsIcon className="size-4" />
|
||||
</button>
|
||||
@@ -66,7 +66,7 @@ export function ColumnHeader({
|
||||
<button
|
||||
type="button"
|
||||
onClick={refresh}
|
||||
className="inline-flex h-9 items-center gap-2 rounded-lg px-3 text-sm font-medium text-neutral-700 hover:bg-blue-100 hover:text-blue-500 focus:outline-none dark:text-neutral-300 dark:hover:bg-neutral-900 dark:hover:text-neutral-50"
|
||||
className="inline-flex items-center gap-2 px-3 text-sm font-medium rounded-lg h-9 text-neutral-700 hover:bg-blue-100 hover:text-blue-500 focus:outline-none dark:text-neutral-300 dark:hover:bg-neutral-900 dark:hover:text-neutral-50"
|
||||
>
|
||||
<RefreshIcon className="size-5" />
|
||||
Refresh
|
||||
@@ -76,7 +76,7 @@ export function ColumnHeader({
|
||||
<button
|
||||
type="button"
|
||||
onClick={moveLeft}
|
||||
className="inline-flex h-9 items-center gap-2 rounded-lg px-3 text-sm font-medium text-neutral-700 hover:bg-blue-100 hover:text-blue-500 focus:outline-none dark:text-neutral-300 dark:hover:bg-neutral-900 dark:hover:text-neutral-50"
|
||||
className="inline-flex items-center gap-2 px-3 text-sm font-medium rounded-lg h-9 text-neutral-700 hover:bg-blue-100 hover:text-blue-500 focus:outline-none dark:text-neutral-300 dark:hover:bg-neutral-900 dark:hover:text-neutral-50"
|
||||
>
|
||||
<ArrowLeftIcon className="size-5" />
|
||||
Move left
|
||||
@@ -86,18 +86,18 @@ export function ColumnHeader({
|
||||
<button
|
||||
type="button"
|
||||
onClick={moveRight}
|
||||
className="inline-flex h-9 items-center gap-2 rounded-lg px-3 text-sm font-medium text-neutral-700 hover:bg-blue-100 hover:text-blue-500 focus:outline-none dark:text-neutral-300 dark:hover:bg-neutral-900 dark:hover:text-neutral-50"
|
||||
className="inline-flex items-center gap-2 px-3 text-sm font-medium rounded-lg h-9 text-neutral-700 hover:bg-blue-100 hover:text-blue-500 focus:outline-none dark:text-neutral-300 dark:hover:bg-neutral-900 dark:hover:text-neutral-50"
|
||||
>
|
||||
<ArrowRightIcon className="size-5" />
|
||||
Move right
|
||||
</button>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator className="my-1 h-px bg-neutral-100 dark:bg-neutral-900" />
|
||||
<DropdownMenu.Separator className="h-px my-1 bg-neutral-100 dark:bg-neutral-900" />
|
||||
<DropdownMenu.Item asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={deleteWidget}
|
||||
className="inline-flex h-9 items-center gap-2 rounded-lg px-3 text-sm font-medium text-red-500 hover:bg-red-500 hover:text-red-50 focus:outline-none"
|
||||
className="inline-flex items-center gap-2 px-3 text-sm font-medium text-red-500 rounded-lg h-9 hover:bg-red-500 hover:text-red-50 focus:outline-none"
|
||||
>
|
||||
<TrashIcon className="size-5" />
|
||||
Delete
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IColumn } from "@lume/types";
|
||||
import { COL_TYPES } from "@lume/utils";
|
||||
import { NDKEvent } from "@nostr-dev-kit/ndk";
|
||||
import {
|
||||
ReactNode,
|
||||
createContext,
|
||||
@@ -13,9 +12,10 @@ import { useStorage } from "../../provider";
|
||||
|
||||
type ColumnContext = {
|
||||
columns: IColumn[];
|
||||
addColumn: (column: IColumn) => void;
|
||||
removeColumn: (id: string) => void;
|
||||
loadAllColumns: () => void;
|
||||
addColumn: (column: IColumn) => Promise<void>;
|
||||
removeColumn: (id: number) => Promise<void>;
|
||||
moveColumn: (id: number, position: "left" | "right") => void;
|
||||
loadAllColumns: () => Promise<IColumn[]>;
|
||||
};
|
||||
|
||||
const ColumnContext = createContext<ColumnContext>(null);
|
||||
@@ -24,7 +24,7 @@ export function ColumnProvider({ children }: { children: ReactNode }) {
|
||||
const storage = useStorage();
|
||||
const [columns, setColumns] = useState<IColumn[]>([
|
||||
{
|
||||
id: "9999",
|
||||
id: 9999,
|
||||
title: "Newsfeed",
|
||||
content: "",
|
||||
kind: COL_TYPES.newsfeed,
|
||||
@@ -44,11 +44,28 @@ export function ColumnProvider({ children }: { children: ReactNode }) {
|
||||
if (result) setColumns((prev) => [...prev, column]);
|
||||
}, []);
|
||||
|
||||
const removeColumn = useCallback(async (id: string) => {
|
||||
const removeColumn = useCallback(async (id: number) => {
|
||||
await storage.removeWidget(id);
|
||||
setColumns((prev) => prev.filter((t) => t.id !== id));
|
||||
}, []);
|
||||
|
||||
const moveColumn = useCallback(
|
||||
(id: number, position: "left" | "right") => {
|
||||
const newCols = [...columns];
|
||||
|
||||
const col = newCols.find((el) => el.id === id);
|
||||
const colIndex = newCols.findIndex((el) => el.id === id);
|
||||
|
||||
newCols.splice(colIndex, 1);
|
||||
|
||||
if (position === "left") newCols.splice(colIndex - 1, 0, col);
|
||||
if (position === "right") newCols.splice(colIndex + 1, 0, col);
|
||||
|
||||
setColumns(newCols);
|
||||
},
|
||||
[columns],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
|
||||
@@ -63,7 +80,7 @@ export function ColumnProvider({ children }: { children: ReactNode }) {
|
||||
|
||||
return (
|
||||
<ColumnContext.Provider
|
||||
value={{ columns, addColumn, removeColumn, loadAllColumns }}
|
||||
value={{ columns, addColumn, removeColumn, moveColumn, loadAllColumns }}
|
||||
>
|
||||
{children}
|
||||
</ColumnContext.Provider>
|
||||
|
||||
@@ -14,23 +14,23 @@ export function NotePin() {
|
||||
<Tooltip.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
addColumn({
|
||||
onClick={async () =>
|
||||
await addColumn({
|
||||
kind: COL_TYPES.thread,
|
||||
title: "Thread",
|
||||
content: event.id,
|
||||
})
|
||||
}
|
||||
className="inline-flex h-7 w-max items-center justify-center gap-2 rounded-full bg-neutral-100 hover:bg-neutral-200 dark:hover:bg-neutral-800 px-2 text-sm font-medium 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" />
|
||||
Pin
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content className="bg-neutral-950 text-white -left-10 inline-flex h-7 select-none items-center justify-center rounded-md 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
|
||||
<Tooltip.Arrow className="fill-neutral-950" />
|
||||
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { ReactionIcon } from "@lume/icons";
|
||||
import * as HoverCard from "@radix-ui/react-hover-card";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { useNoteContext } from "../provider";
|
||||
|
||||
const REACTIONS = [
|
||||
@@ -49,7 +48,7 @@ export function NoteReaction() {
|
||||
|
||||
setOpen(false);
|
||||
} catch (e) {
|
||||
toast.error(e);
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -58,22 +57,22 @@ export function NoteReaction() {
|
||||
<HoverCard.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-600 dark:text-neutral-400"
|
||||
className="inline-flex items-center justify-center group h-7 w-7 text-neutral-600 dark:text-neutral-400"
|
||||
>
|
||||
{reaction ? (
|
||||
<img
|
||||
src={getReactionImage(reaction)}
|
||||
alt={reaction}
|
||||
className="size-5"
|
||||
className="size-6"
|
||||
/>
|
||||
) : (
|
||||
<ReactionIcon className="size-5 group-hover:text-blue-500" />
|
||||
<ReactionIcon className="size-6 group-hover:text-blue-500" />
|
||||
)}
|
||||
</button>
|
||||
</HoverCard.Trigger>
|
||||
<HoverCard.Portal>
|
||||
<HoverCard.Content
|
||||
className="select-none rounded-lg bg-neutral-950 px-1 py-1 text-sm will-change-[transform,opacity] data-[state=open]:data-[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-slideRightAndFade data-[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-[side=top]:animate-slideDownAndFade"
|
||||
className="select-none rounded-lg bg-neutral-950 dark:bg-neutral-50 px-1 py-1 text-sm will-change-[transform,opacity] data-[state=open]:data-[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-slideRightAndFade data-[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-[side=top]:animate-slideDownAndFade"
|
||||
sideOffset={0}
|
||||
side="top"
|
||||
>
|
||||
@@ -81,56 +80,56 @@ export function NoteReaction() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => react("👏")}
|
||||
className="inline-flex h-8 w-8 items-center justify-center rounded-md backdrop-blur-xl hover:bg-white/10"
|
||||
className="inline-flex items-center justify-center w-8 h-8 rounded-md backdrop-blur-xl hover:bg-white/10 dark:hover:bg-black/10"
|
||||
>
|
||||
<img
|
||||
src="/clapping_hands.png"
|
||||
alt="Clapping Hands"
|
||||
className="h-6 w-6"
|
||||
className="size-6"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => react("🤪")}
|
||||
className="inline-flex h-8 w-8 items-center justify-center rounded-md backdrop-blur-xl hover:bg-white/10"
|
||||
className="inline-flex items-center justify-center w-8 h-8 rounded-md backdrop-blur-xl hover:bg-white/10 dark:hover:bg-black/10"
|
||||
>
|
||||
<img
|
||||
src="/face_with_tongue.png"
|
||||
alt="Face with Tongue"
|
||||
className="h-6 w-6"
|
||||
className="size-6"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => react("😮")}
|
||||
className="inline-flex h-8 w-8 items-center justify-center rounded-md backdrop-blur-xl hover:bg-white/10"
|
||||
className="inline-flex items-center justify-center w-8 h-8 rounded-md backdrop-blur-xl hover:bg-white/10 dark:hover:bg-black/10"
|
||||
>
|
||||
<img
|
||||
src="/face_with_open_mouth.png"
|
||||
alt="Face with Open Mouth"
|
||||
className="h-6 w-6"
|
||||
className="size-6"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => react("😢")}
|
||||
className="inline-flex h-8 w-8 items-center justify-center rounded-md backdrop-blur-xl hover:bg-white/10"
|
||||
className="inline-flex items-center justify-center w-8 h-8 rounded-md backdrop-blur-xl hover:bg-white/10 dark:hover:bg-black/10"
|
||||
>
|
||||
<img
|
||||
src="/crying_face.png"
|
||||
alt="Crying Face"
|
||||
className="h-6 w-6"
|
||||
className="size-6"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => react("🤡")}
|
||||
className="inline-flex h-8 w-8 items-center justify-center rounded-md backdrop-blur-xl hover:bg-white/10"
|
||||
className="inline-flex items-center justify-center w-8 h-8 rounded-md backdrop-blur-xl hover:bg-white/10 dark:hover:bg-black/10"
|
||||
>
|
||||
<img src="/clown_face.png" alt="Clown Face" className="h-6 w-6" />
|
||||
<img src="/clown_face.png" alt="Clown Face" className="size-6" />
|
||||
</button>
|
||||
</div>
|
||||
<HoverCard.Arrow className="fill-neutral-950" />
|
||||
<HoverCard.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
||||
</HoverCard.Content>
|
||||
</HoverCard.Portal>
|
||||
</HoverCard.Root>
|
||||
|
||||
@@ -26,15 +26,15 @@ export function NoteReply({
|
||||
}).toString(),
|
||||
})
|
||||
}
|
||||
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-600 dark:text-neutral-400"
|
||||
className="inline-flex items-center justify-center group h-7 w-7 text-neutral-600 dark:text-neutral-400"
|
||||
>
|
||||
<ReplyIcon className="h-5 w-5 group-hover:text-blue-500" />
|
||||
<ReplyIcon className="size-6 group-hover:text-blue-500" />
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content className="inline-flex h-7 select-none items-center justify-center rounded-md bg-neutral-950 px-3.5 text-sm text-white 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">
|
||||
Quick reply
|
||||
<Tooltip.Arrow className="fill-neutral-950" />
|
||||
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
|
||||
@@ -29,20 +29,20 @@ export function NoteRepost() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={submit}
|
||||
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-600 dark:text-neutral-400"
|
||||
className="inline-flex items-center justify-center group h-7 w-7 text-neutral-600 dark:text-neutral-400"
|
||||
>
|
||||
<RepostIcon
|
||||
className={twMerge(
|
||||
"h-5 w-5 group-hover:text-blue-600",
|
||||
"size-6 group-hover:text-blue-600",
|
||||
isRepost ? "text-blue-500" : "",
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content className="inline-flex h-7 select-none items-center justify-center rounded-md bg-neutral-950 px-3.5 text-sm text-white 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
|
||||
<Tooltip.Arrow className="fill-neutral-950" />
|
||||
<Tooltip.Arrow className="fill-neutral-950 dark:fill-neutral-50" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
|
||||
@@ -107,32 +107,32 @@ export function NoteZap() {
|
||||
<Dialog.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-600 dark:text-neutral-400"
|
||||
className="inline-flex items-center justify-center group h-7 w-7 text-neutral-600 dark:text-neutral-400"
|
||||
>
|
||||
<ZapIcon className="h-5 w-5 group-hover:text-blue-500" />
|
||||
<ZapIcon className="size-6 group-hover:text-blue-500" />
|
||||
</button>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/20 backdrop-blur-sm dark:bg-black/20" />
|
||||
<Dialog.Content className="fixed inset-0 z-50 flex min-h-full items-center justify-center">
|
||||
<div className="relative h-min w-full max-w-xl rounded-xl bg-white dark:bg-black">
|
||||
<div className="inline-flex w-full shrink-0 items-center justify-between px-5 py-3">
|
||||
<Dialog.Content className="fixed inset-0 z-50 flex items-center justify-center min-h-full">
|
||||
<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="w-6" />
|
||||
<Dialog.Title className="text-center font-semibold">
|
||||
<Dialog.Title className="font-semibold text-center">
|
||||
Send tip to{" "}
|
||||
{user?.name ||
|
||||
user?.displayName ||
|
||||
displayNpub(event.pubkey, 16)}
|
||||
</Dialog.Title>
|
||||
<Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md bg-neutral-100 dark:bg-neutral-900">
|
||||
<CancelIcon className="h-4 w-4" />
|
||||
<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 className="overflow-y-auto overflow-x-hidden px-5 pb-5">
|
||||
<div className="px-5 pb-5 overflow-x-hidden overflow-y-auto">
|
||||
{!invoice ? (
|
||||
<>
|
||||
<div className="relative flex h-40 flex-col">
|
||||
<div className="inline-flex h-full flex-1 items-center justify-center gap-1">
|
||||
<div className="relative flex flex-col h-40">
|
||||
<div className="inline-flex items-center justify-center flex-1 h-full gap-1">
|
||||
<CurrencyInput
|
||||
placeholder="0"
|
||||
defaultValue={"21"}
|
||||
@@ -142,9 +142,9 @@ export function NoteZap() {
|
||||
max={10000} // 1M sats
|
||||
maxLength={10000} // 1M sats
|
||||
onValueChange={(value) => setAmount(value)}
|
||||
className="w-full flex-1 border-none bg-transparent text-right text-4xl font-semibold placeholder:text-neutral-600 focus:outline-none focus:ring-0 dark:text-neutral-400"
|
||||
className="flex-1 w-full text-4xl font-semibold text-right bg-transparent border-none placeholder:text-neutral-600 focus:outline-none focus:ring-0 dark:text-neutral-400"
|
||||
/>
|
||||
<span className="w-full flex-1 text-left text-4xl font-semibold text-neutral-600 dark:text-neutral-400">
|
||||
<span className="flex-1 w-full text-4xl font-semibold text-left text-neutral-600 dark:text-neutral-400">
|
||||
sats
|
||||
</span>
|
||||
</div>
|
||||
@@ -186,7 +186,7 @@ export function NoteZap() {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex w-full flex-col gap-2">
|
||||
<div className="flex flex-col w-full gap-2 mt-4">
|
||||
<input
|
||||
name="zapMessage"
|
||||
value={zapMessage}
|
||||
@@ -203,7 +203,7 @@ export function NoteZap() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => createZapRequest()}
|
||||
className="inline-flex h-11 w-full items-center justify-center rounded-lg bg-blue-500 px-4 font-medium text-white hover:bg-blue-600"
|
||||
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"
|
||||
>
|
||||
{isCompleted ? (
|
||||
<p className="leading-tight">Successfully zapped</p>
|
||||
@@ -229,7 +229,7 @@ export function NoteZap() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => createZapRequest()}
|
||||
className="inline-flex h-11 w-full items-center justify-center rounded-lg bg-blue-500 px-4 font-medium text-white hover:bg-blue-600"
|
||||
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"
|
||||
>
|
||||
Create Lightning invoice
|
||||
</button>
|
||||
@@ -238,13 +238,13 @@ export function NoteZap() {
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="mt-3 flex flex-col items-center justify-center gap-4">
|
||||
<div className="rounded-md bg-neutral-100 p-3 dark:bg-neutral-900">
|
||||
<div className="flex flex-col items-center justify-center gap-4 mt-3">
|
||||
<div className="p-3 rounded-md bg-neutral-100 dark:bg-neutral-900">
|
||||
<QRCodeSVG value={invoice} size={256} />
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-1">
|
||||
<h3 className="text-lg font-medium">Scan to zap</h3>
|
||||
<span className="text-center text-sm text-neutral-600 dark:text-neutral-400">
|
||||
<span className="text-sm text-center text-neutral-600 dark:text-neutral-400">
|
||||
You must use Bitcoin wallet which support Lightning
|
||||
<br />
|
||||
such as: Blue Wallet, Bitkit, Phoenix,...
|
||||
|
||||
@@ -7,14 +7,14 @@ export function Hashtag({ tag }: { tag: string }) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
addColumn({
|
||||
onClick={async () =>
|
||||
await addColumn({
|
||||
kind: COL_TYPES.hashtag,
|
||||
title: tag,
|
||||
content: tag,
|
||||
})
|
||||
}
|
||||
className="cursor-default break-all text-blue-500 hover:text-blue-600"
|
||||
className="text-blue-500 break-all cursor-default hover:text-blue-600"
|
||||
>
|
||||
{tag}
|
||||
</button>
|
||||
|
||||
@@ -24,7 +24,7 @@ export const MentionNote = memo(function MentionNote({
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="w-full cursor-default rounded-lg bg-neutral-100 p-3 dark:bg-neutral-900">
|
||||
<div className="w-full p-3 my-1 rounded-lg cursor-default bg-neutral-100 dark:bg-neutral-900">
|
||||
Loading
|
||||
</div>
|
||||
);
|
||||
@@ -32,7 +32,7 @@ export const MentionNote = memo(function MentionNote({
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<div className="w-full cursor-default rounded-lg bg-neutral-100 p-3 dark:bg-neutral-900">
|
||||
<div className="w-full p-3 my-1 rounded-lg cursor-default bg-neutral-100 dark:bg-neutral-900">
|
||||
Failed to fetch event
|
||||
</div>
|
||||
);
|
||||
@@ -40,11 +40,11 @@ export const MentionNote = memo(function MentionNote({
|
||||
|
||||
return (
|
||||
<Note.Provider event={data}>
|
||||
<Note.Root className="flex w-full cursor-default flex-col gap-1 rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<div className="mt-3 px-3">
|
||||
<Note.Root className="flex flex-col w-full gap-1 my-1 rounded-lg cursor-default bg-neutral-100 dark:bg-neutral-900">
|
||||
<div className="px-3 mt-3">
|
||||
<Note.User variant="mention" />
|
||||
</div>
|
||||
<div className="mt-1 px-3 pb-3">
|
||||
<div className="px-3 pb-3 mt-1">
|
||||
{renderKind(data)}
|
||||
<Link
|
||||
to={`/events/${data.id}`}
|
||||
|
||||
@@ -13,14 +13,14 @@ export const MentionUser = memo(function MentionUser({
|
||||
|
||||
return (
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger className="break-words text-blue-500 hover:text-blue-600">
|
||||
<DropdownMenu.Trigger className="text-blue-500 break-words hover:text-blue-600">
|
||||
{`@${user?.name || user?.displayName || user?.username || "anon"}`}
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content className="left-[50px] z-50 relative flex w-[200px] flex-col overflow-hidden rounded-xl border border-neutral-200 bg-neutral-950 focus:outline-none dark:border-neutral-900">
|
||||
<DropdownMenu.Item asChild>
|
||||
<Link
|
||||
to={`/users/${pubkey}`}
|
||||
className="inline-flex h-10 items-center px-4 text-sm text-white hover:bg-neutral-900 focus:outline-none"
|
||||
className="inline-flex items-center h-10 px-4 text-sm text-white hover:bg-neutral-900 focus:outline-none"
|
||||
>
|
||||
View profile
|
||||
</Link>
|
||||
@@ -28,14 +28,14 @@ export const MentionUser = memo(function MentionUser({
|
||||
<DropdownMenu.Item asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
addColumn({
|
||||
onClick={async () =>
|
||||
await addColumn({
|
||||
kind: COL_TYPES.user,
|
||||
title: user?.name || user?.displayName || "",
|
||||
content: pubkey,
|
||||
})
|
||||
}
|
||||
className="inline-flex h-10 items-center px-4 text-sm text-white hover:bg-neutral-900 focus:outline-none"
|
||||
className="inline-flex items-center h-10 px-4 text-sm text-white hover:bg-neutral-900 focus:outline-none"
|
||||
>
|
||||
Pin
|
||||
</button>
|
||||
|
||||
@@ -39,7 +39,7 @@ export function ImagePreview({ url }: { url: string }) {
|
||||
|
||||
return (
|
||||
// biome-ignore lint/a11y/useKeyWithClickEvents: <explanation>
|
||||
<div onClick={open} className="group relative">
|
||||
<div onClick={open} className="relative my-1 group">
|
||||
<img
|
||||
src={url}
|
||||
alt={url}
|
||||
@@ -47,17 +47,17 @@ export function ImagePreview({ url }: { url: string }) {
|
||||
decoding="async"
|
||||
style={{ contentVisibility: "auto" }}
|
||||
onError={fallback}
|
||||
className="h-auto w-full rounded-lg border border-neutral-200/50 object-cover dark:border-neutral-800/50"
|
||||
className="object-cover w-full h-auto border rounded-lg border-neutral-200/50 dark:border-neutral-800/50"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => downloadImage(e)}
|
||||
className="absolute right-2 top-2 z-10 hidden h-10 w-10 items-center justify-center rounded-lg bg-blue-500 group-hover:inline-flex hover:bg-blue-600"
|
||||
className="absolute z-10 items-center justify-center hidden w-10 h-10 bg-blue-500 rounded-lg right-2 top-2 group-hover:inline-flex hover:bg-blue-600"
|
||||
>
|
||||
{downloaded ? (
|
||||
<CheckCircleIcon className="h-5 w-5 text-white" />
|
||||
<CheckCircleIcon className="w-5 h-5 text-white" />
|
||||
) : (
|
||||
<DownloadIcon className="h-5 w-5 text-white" />
|
||||
<DownloadIcon className="w-5 h-5 text-white" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -11,11 +11,11 @@ export function LinkPreview({ url }: { url: string }) {
|
||||
|
||||
if (status === "pending") {
|
||||
return (
|
||||
<div className="flex w-full flex-col rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<div className="h-48 w-full animate-pulse bg-neutral-300 dark:bg-neutral-700" />
|
||||
<div className="flex flex-col w-full my-1 rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<div className="w-full h-48 animate-pulse bg-neutral-300 dark:bg-neutral-700" />
|
||||
<div className="flex flex-col gap-2 px-3 py-3">
|
||||
<div className="h-3 w-2/3 animate-pulse rounded bg-neutral-300 dark:bg-neutral-700" />
|
||||
<div className="h-3 w-3/4 animate-pulse rounded bg-neutral-300 dark:bg-neutral-700" />
|
||||
<div className="w-2/3 h-3 rounded animate-pulse bg-neutral-300 dark:bg-neutral-700" />
|
||||
<div className="w-3/4 h-3 rounded animate-pulse bg-neutral-300 dark:bg-neutral-700" />
|
||||
<span className="mt-2.5 text-sm leading-none text-neutral-600 dark:text-neutral-400">
|
||||
{domain.hostname}
|
||||
</span>
|
||||
@@ -42,29 +42,29 @@ export function LinkPreview({ url }: { url: string }) {
|
||||
to={url}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="flex w-full flex-col rounded-lg bg-neutral-100 dark:bg-neutral-900"
|
||||
className="flex flex-col w-full my-1 overflow-hidden rounded-lg bg-neutral-100 dark:bg-neutral-900"
|
||||
>
|
||||
{isImage(data.image) ? (
|
||||
<img
|
||||
src={data.image}
|
||||
alt={url}
|
||||
className="h-48 w-full rounded-t-lg bg-white object-cover"
|
||||
className="object-cover w-full h-48 bg-white rounded-t-lg"
|
||||
/>
|
||||
) : null}
|
||||
<div className="flex flex-col items-start px-3 py-3">
|
||||
<div className="flex flex-col items-start gap-1 text-left">
|
||||
{data.title ? (
|
||||
<div className="break-all text-base font-semibold text-neutral-900 dark:text-neutral-100">
|
||||
<div className="text-base font-semibold break-all text-neutral-900 dark:text-neutral-100">
|
||||
{data.title}
|
||||
</div>
|
||||
) : null}
|
||||
{data.description ? (
|
||||
<div className="mb-2 line-clamp-3 break-all text-sm text-neutral-700 dark:text-neutral-400">
|
||||
<div className="mb-2 text-sm break-all line-clamp-3 text-neutral-700 dark:text-neutral-400">
|
||||
{data.description}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="break-all text-sm text-neutral-600 dark:text-neutral-400">
|
||||
<div className="text-sm break-all text-neutral-600 dark:text-neutral-400">
|
||||
{domain.hostname}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@ export function VideoPreview({ url }: { url: string }) {
|
||||
return (
|
||||
<MediaPlayer
|
||||
src={url}
|
||||
className="w-full overflow-hidden rounded-lg"
|
||||
className="w-full my-1 overflow-hidden rounded-lg"
|
||||
aspectRatio="16/9"
|
||||
load="visible"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user