feat: the last commit of year

This commit is contained in:
2023-12-31 20:53:51 +07:00
parent b1d2496f8e
commit 56fab1dda6
28 changed files with 277 additions and 227 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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,...

View File

@@ -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>

View File

@@ -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}`}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"
>