better auth set up
This commit is contained in:
parent
80b178306e
commit
36b76f943a
@ -111,7 +111,7 @@ export default function ProfilePage({
|
|||||||
<div className="mx-auto max-w-[800px] space-y-6">
|
<div className="mx-auto max-w-[800px] space-y-6">
|
||||||
<div className="flex max-w-2xl flex-col gap-5">
|
<div className="flex max-w-2xl flex-col gap-5">
|
||||||
{demo.map((e) => (
|
{demo.map((e) => (
|
||||||
<SubscriptionCard {...e} />
|
<SubscriptionCard key={e.id} {...e} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="">
|
<div className="">
|
||||||
|
@ -4,7 +4,7 @@ export default function Keystone() {
|
|||||||
return (
|
return (
|
||||||
<div className="center hidden sm:flex">
|
<div className="center hidden sm:flex">
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
href="/app"
|
||||||
className="center fixed h-[var(--header-height)] w-[var(--sidebar-closed-width)] gap-x-3 border-r text-primary hover:text-primary/80 xl:w-[var(--sidebar-open-width)] xl:justify-start xl:pl-5"
|
className="center fixed h-[var(--header-height)] w-[var(--sidebar-closed-width)] gap-x-3 border-r text-primary hover:text-primary/80 xl:w-[var(--sidebar-open-width)] xl:justify-start xl:pl-5"
|
||||||
>
|
>
|
||||||
<Logo className="h-[30px] w-[30px]" />
|
<Logo className="h-[30px] w-[30px]" />
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
import { useEffect } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import useCurrentUser from "@/lib/hooks/useCurrentUser";
|
import useCurrentUser from "@/lib/hooks/useCurrentUser";
|
||||||
@ -17,18 +18,26 @@ import {
|
|||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { RiNotification4Line } from "react-icons/ri";
|
import { RiNotification4Line } from "react-icons/ri";
|
||||||
import { SiRelay } from "react-icons/si";
|
import { SiRelay } from "react-icons/si";
|
||||||
import { RELAYS } from "@/constants";
|
|
||||||
import StatusIndicator from "@/components/StatusIndicator";
|
import StatusIndicator from "@/components/StatusIndicator";
|
||||||
import { type NDKUser } from "@nostr-dev-kit/ndk";
|
import { type NDKUser } from "@nostr-dev-kit/ndk";
|
||||||
import { truncateText, getTwoLetters } from "@/lib/utils";
|
import { truncateText, getTwoLetters } from "@/lib/utils";
|
||||||
import { useNDK } from "@/app/_providers/ndk";
|
import { useNDK } from "@/app/_providers/ndk";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
const LoginModal = dynamic(() => import("@/components/Modals/Login"), {
|
const LoginModal = dynamic(() => import("@/components/Modals/Login"), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function AuthActions() {
|
export default function AuthActions() {
|
||||||
const modal = useModal();
|
const modal = useModal();
|
||||||
const { currentUser, logout } = useCurrentUser();
|
const { currentUser, logout, attemptLogin } = useCurrentUser();
|
||||||
|
useEffect(() => {
|
||||||
|
attemptLogin();
|
||||||
|
}, []);
|
||||||
if (currentUser) {
|
if (currentUser) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -53,8 +62,9 @@ export default function AuthActions() {
|
|||||||
|
|
||||||
export function Notifications({ user }: { user: NDKUser }) {
|
export function Notifications({ user }: { user: NDKUser }) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<TooltipProvider>
|
||||||
<DropdownMenuTrigger asChild>
|
<Tooltip delayDuration={100}>
|
||||||
|
<TooltipTrigger>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
@ -62,50 +72,67 @@ export function Notifications({ user }: { user: NDKUser }) {
|
|||||||
>
|
>
|
||||||
<RiNotification4Line className="h-[18px] w-[18px] text-foreground" />
|
<RiNotification4Line className="h-[18px] w-[18px] text-foreground" />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</TooltipTrigger>
|
||||||
<DropdownMenuContent className="z-header+ w-56" align="end" forceMount>
|
<TooltipContent align="center">
|
||||||
<DropdownMenuLabel className="font-normal">
|
<p>Coming Soon</p>
|
||||||
<div className="flex flex-col space-y-1">
|
</TooltipContent>
|
||||||
{user.profile?.displayName || user.profile?.name ? (
|
</Tooltip>
|
||||||
<>
|
</TooltipProvider>
|
||||||
<p className="text-sm font-medium leading-none">
|
|
||||||
{user.profile?.displayName ?? user.profile.name}
|
|
||||||
</p>
|
|
||||||
<p className="text-xs leading-none text-muted-foreground">
|
|
||||||
m@example.com
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<p className="text-sm font-medium leading-none">
|
|
||||||
{truncateText(user.npub)}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</DropdownMenuLabel>
|
|
||||||
<DropdownMenuSeparator />
|
|
||||||
<DropdownMenuGroup>
|
|
||||||
<DropdownMenuItem>
|
|
||||||
Profile
|
|
||||||
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
|
||||||
</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem>
|
|
||||||
Billing
|
|
||||||
<DropdownMenuShortcut>⌘B</DropdownMenuShortcut>
|
|
||||||
</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem>
|
|
||||||
Settings
|
|
||||||
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
|
||||||
</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem>New Team</DropdownMenuItem>
|
|
||||||
</DropdownMenuGroup>
|
|
||||||
<DropdownMenuSeparator />
|
|
||||||
<DropdownMenuItem>
|
|
||||||
Log out
|
|
||||||
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
|
||||||
</DropdownMenuItem>
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
);
|
);
|
||||||
|
// return (
|
||||||
|
// <DropdownMenu>
|
||||||
|
// <DropdownMenuTrigger asChild>
|
||||||
|
// <Button
|
||||||
|
// variant="ghost"
|
||||||
|
// size="icon"
|
||||||
|
// className="center relative h-8 w-8 rounded-full bg-muted text-foreground"
|
||||||
|
// >
|
||||||
|
// <RiNotification4Line className="h-[18px] w-[18px] text-foreground" />
|
||||||
|
// </Button>
|
||||||
|
// </DropdownMenuTrigger>
|
||||||
|
// <DropdownMenuContent className="z-header+ w-56" align="end" forceMount>
|
||||||
|
// <DropdownMenuLabel className="font-normal">
|
||||||
|
// <div className="flex flex-col space-y-1">
|
||||||
|
// {user.profile?.displayName || user.profile?.name ? (
|
||||||
|
// <>
|
||||||
|
// <p className="text-sm font-medium leading-none">
|
||||||
|
// {user.profile?.displayName ?? user.profile.name}
|
||||||
|
// </p>
|
||||||
|
// <p className="text-xs leading-none text-muted-foreground">
|
||||||
|
// m@example.com
|
||||||
|
// </p>
|
||||||
|
// </>
|
||||||
|
// ) : (
|
||||||
|
// <p className="text-sm font-medium leading-none">
|
||||||
|
// {truncateText(user.npub)}
|
||||||
|
// </p>
|
||||||
|
// )}
|
||||||
|
// </div>
|
||||||
|
// </DropdownMenuLabel>
|
||||||
|
// <DropdownMenuSeparator />
|
||||||
|
// <DropdownMenuGroup>
|
||||||
|
// <DropdownMenuItem>
|
||||||
|
// Profile
|
||||||
|
// <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
||||||
|
// </DropdownMenuItem>
|
||||||
|
// <DropdownMenuItem>
|
||||||
|
// Billing
|
||||||
|
// <DropdownMenuShortcut>⌘B</DropdownMenuShortcut>
|
||||||
|
// </DropdownMenuItem>
|
||||||
|
// <DropdownMenuItem>
|
||||||
|
// Settings
|
||||||
|
// <DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
||||||
|
// </DropdownMenuItem>
|
||||||
|
// <DropdownMenuItem>New Team</DropdownMenuItem>
|
||||||
|
// </DropdownMenuGroup>
|
||||||
|
// <DropdownMenuSeparator />
|
||||||
|
// <DropdownMenuItem>
|
||||||
|
// Log out
|
||||||
|
// <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
||||||
|
// </DropdownMenuItem>
|
||||||
|
// </DropdownMenuContent>
|
||||||
|
// </DropdownMenu>
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
export function Relays() {
|
export function Relays() {
|
||||||
const { ndk } = useNDK();
|
const { ndk } = useNDK();
|
||||||
|
@ -48,7 +48,10 @@ export default function HorizontalCarousel() {
|
|||||||
return (
|
return (
|
||||||
<div className="scrollbar-thumb-rounded-full mr-auto flex min-w-0 max-w-full snap-x snap-mandatory overflow-x-auto pl-5 pr-[50vw] scrollbar-thin sm:pr-[200px]">
|
<div className="scrollbar-thumb-rounded-full mr-auto flex min-w-0 max-w-full snap-x snap-mandatory overflow-x-auto pl-5 pr-[50vw] scrollbar-thin sm:pr-[200px]">
|
||||||
{cards.map((creator, index) => (
|
{cards.map((creator, index) => (
|
||||||
<div className={cn("snap-start pl-2 sm:pl-5", index === 0 && "pl-5")}>
|
<div
|
||||||
|
key={index}
|
||||||
|
className={cn("snap-start pl-2 sm:pl-5", index === 0 && "pl-5")}
|
||||||
|
>
|
||||||
<CreatorCard key={creator.displayName} {...creator} />
|
<CreatorCard key={creator.displayName} {...creator} />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
@ -86,7 +86,7 @@ export default function Modal({
|
|||||||
</FocusTrap>
|
</FocusTrap>
|
||||||
<motion.div
|
<motion.div
|
||||||
key="desktop-backdrop"
|
key="desktop-backdrop"
|
||||||
className="z-overlay fixed inset-0 bg-background bg-opacity-10 backdrop-blur"
|
className="z-overlay fixed inset-0 bg-background/40 backdrop-blur"
|
||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
exit={{ opacity: 0 }}
|
exit={{ opacity: 0 }}
|
||||||
|
@ -3,7 +3,6 @@ import { parse } from "node-html-parser";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { validateUrl } from "@/lib/utils";
|
import { validateUrl } from "@/lib/utils";
|
||||||
|
|
||||||
|
|
||||||
type MetaData = {
|
type MetaData = {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
@ -81,6 +80,10 @@ async function handler(req: NextRequest) {
|
|||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Error", err);
|
console.log("Error", err);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Internal Server Error" },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
60
components/DropDownMenu/index.tsx
Normal file
60
components/DropDownMenu/index.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuGroup,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
|
type OptionLink = {
|
||||||
|
href: string;
|
||||||
|
type: "link";
|
||||||
|
};
|
||||||
|
type OptionButton = {
|
||||||
|
onClick: () => void;
|
||||||
|
type: "button";
|
||||||
|
};
|
||||||
|
type Option = {
|
||||||
|
label: string;
|
||||||
|
} & (OptionLink | OptionButton);
|
||||||
|
|
||||||
|
type DropDownMenuProps = {
|
||||||
|
options: Option[];
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function DropDownMenu({ children, options }: DropDownMenuProps) {
|
||||||
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent className="z-header+ w-56" align="end" forceMount>
|
||||||
|
<DropdownMenuGroup>
|
||||||
|
{options.map((o) => {
|
||||||
|
if (o.type === "button") {
|
||||||
|
return (
|
||||||
|
<DropdownMenuItem key={o.label}>
|
||||||
|
<button
|
||||||
|
onClick={o.onClick}
|
||||||
|
className="flex w-full justify-between"
|
||||||
|
>
|
||||||
|
{o.label}
|
||||||
|
</button>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<DropdownMenuItem key={o.label}>
|
||||||
|
<Link href={o.href} className="flex w-full justify-between">
|
||||||
|
{o.label}
|
||||||
|
</Link>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</DropdownMenuGroup>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
}
|
@ -4,10 +4,34 @@ import { type Event } from "nostr-tools";
|
|||||||
import { RenderText } from "../TextRendering";
|
import { RenderText } from "../TextRendering";
|
||||||
import { getTagsValues } from "@/lib/nostr/utils";
|
import { getTagsValues } from "@/lib/nostr/utils";
|
||||||
import LinkCard from "@/components/LinkCard";
|
import LinkCard from "@/components/LinkCard";
|
||||||
export default function Kind1({ content, tags }: Event) {
|
import { copyText } from "@/lib/utils";
|
||||||
|
import { nip19 } from "nostr-tools";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
export default function Kind1(props: Event) {
|
||||||
|
const { content, pubkey, tags } = props;
|
||||||
const r = getTagsValues("r", tags);
|
const r = getTagsValues("r", tags);
|
||||||
|
const npub = nip19.npubEncode(pubkey);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container
|
||||||
|
pubkey={pubkey}
|
||||||
|
actionOptions={[
|
||||||
|
{
|
||||||
|
label: "View profile",
|
||||||
|
href: `/${npub}`,
|
||||||
|
type: "link",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Copy raw data",
|
||||||
|
type: "button",
|
||||||
|
onClick: () => {
|
||||||
|
void copyText(JSON.stringify(props));
|
||||||
|
toast.success("Copied Text!");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
<CardDescription className="text-base text-foreground">
|
<CardDescription className="text-base text-foreground">
|
||||||
<RenderText text={content} />
|
<RenderText text={content} />
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
|
@ -5,13 +5,13 @@ import { getTagValues, getTagsValues } from "@/lib/nostr/utils";
|
|||||||
import { type Event } from "nostr-tools";
|
import { type Event } from "nostr-tools";
|
||||||
import { removeDuplicates } from "@/lib/utils";
|
import { removeDuplicates } from "@/lib/utils";
|
||||||
|
|
||||||
export default function Kind30023({ content, tags }: Event) {
|
export default function Kind30023({ content, pubkey, tags }: Event) {
|
||||||
const title = getTagValues("title", tags);
|
const title = getTagValues("title", tags);
|
||||||
const summary = getTagValues("summary", tags);
|
const summary = getTagValues("summary", tags);
|
||||||
const contentTags = removeDuplicates(getTagsValues("t", tags));
|
const contentTags = removeDuplicates(getTagsValues("t", tags));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container contentTags={contentTags}>
|
<Container pubkey={pubkey} contentTags={contentTags}>
|
||||||
<CardTitle className="mb-1.5 line-clamp-2 text-lg font-semibold">
|
<CardTitle className="mb-1.5 line-clamp-2 text-lg font-semibold">
|
||||||
{title}
|
{title}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
|
@ -2,9 +2,9 @@ import Container from "./components/Container";
|
|||||||
import { CardTitle, CardDescription } from "@/components/ui/card";
|
import { CardTitle, CardDescription } from "@/components/ui/card";
|
||||||
import { type Event } from "nostr-tools";
|
import { type Event } from "nostr-tools";
|
||||||
|
|
||||||
export default function Kind3745({}: Event) {
|
export default function Kind3745({ pubkey }: Event) {
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container pubkey={pubkey}>
|
||||||
<CardTitle className="mb-1.5 line-clamp-2 text-lg font-semibold">
|
<CardTitle className="mb-1.5 line-clamp-2 text-lg font-semibold">
|
||||||
The start of the Nostr revolution
|
The start of the Nostr revolution
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
|
@ -9,23 +9,48 @@ import { ReactNode } from "react";
|
|||||||
import ProfileHeader from "./ProfileHeader";
|
import ProfileHeader from "./ProfileHeader";
|
||||||
import Actions from "./Actions";
|
import Actions from "./Actions";
|
||||||
import Tags from "./Tags";
|
import Tags from "./Tags";
|
||||||
import { type Event } from "nostr-tools";
|
import DropDownMenu from "@/components/DropDownMenu";
|
||||||
|
|
||||||
|
type OptionLink = {
|
||||||
|
href: string;
|
||||||
|
type: "link";
|
||||||
|
};
|
||||||
|
type OptionButton = {
|
||||||
|
onClick: () => void;
|
||||||
|
type: "button";
|
||||||
|
};
|
||||||
|
type Option = {
|
||||||
|
label: string;
|
||||||
|
} & (OptionLink | OptionButton);
|
||||||
|
|
||||||
type CreatorCardProps = {
|
type CreatorCardProps = {
|
||||||
|
pubkey: string;
|
||||||
contentTags?: string[];
|
contentTags?: string[];
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
actionOptions?: Option[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Container({ children, contentTags }: CreatorCardProps) {
|
export default function Container({
|
||||||
|
children,
|
||||||
|
contentTags,
|
||||||
|
pubkey,
|
||||||
|
actionOptions = [],
|
||||||
|
}: CreatorCardProps) {
|
||||||
return (
|
return (
|
||||||
<Card className="relative overflow-hidden">
|
<Card className="relative overflow-hidden">
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 p-4 pb-4">
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 p-4 pb-4">
|
||||||
<ProfileHeader />
|
<ProfileHeader pubkey={pubkey} />
|
||||||
<div className="-mr-1 flex items-center gap-x-1.5 text-xs text-muted-foreground">
|
<div className="-mr-1 flex items-center gap-x-1.5 text-xs text-muted-foreground">
|
||||||
{formatDate(new Date("10-5-23"), "MMM Do")}
|
{formatDate(new Date("10-5-23"), "MMM Do")}
|
||||||
<Button size={"sm"} variant={"ghost"} className="center h-6 w-6 p-0">
|
<DropDownMenu options={actionOptions}>
|
||||||
|
<Button
|
||||||
|
size={"sm"}
|
||||||
|
variant={"ghost"}
|
||||||
|
className="center h-6 w-6 p-0"
|
||||||
|
>
|
||||||
<RiMoreFill className="h-4 w-4" />
|
<RiMoreFill className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
</DropDownMenu>
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="px-4 pb-3">
|
<CardContent className="px-4 pb-3">
|
||||||
|
@ -1,25 +1,30 @@
|
|||||||
import { Avatar, AvatarImage, AvatarFallback } from "@radix-ui/react-avatar";
|
import { Avatar, AvatarImage, AvatarFallback } from "@radix-ui/react-avatar";
|
||||||
import { HiCheckBadge } from "react-icons/hi2";
|
import { HiCheckBadge } from "react-icons/hi2";
|
||||||
|
import Link from "next/link";
|
||||||
|
import useProfile from "@/lib/hooks/useProfile";
|
||||||
|
import { nip19 } from "nostr-tools";
|
||||||
|
import { getTwoLetters, getNameToShow } from "@/lib/utils";
|
||||||
|
|
||||||
type ProfileHeaderProps = {};
|
type ProfileHeaderProps = {
|
||||||
export default function ProfileHeader({}: ProfileHeaderProps) {
|
pubkey: string;
|
||||||
|
};
|
||||||
|
export default function ProfileHeader({ pubkey }: ProfileHeaderProps) {
|
||||||
|
const { profile } = useProfile(pubkey);
|
||||||
|
const npub = nip19.npubEncode(pubkey);
|
||||||
return (
|
return (
|
||||||
<div className="center gap-x-3">
|
<Link href={`/${npub}`} className="center group gap-x-3">
|
||||||
<Avatar className="center h-8 w-8 overflow-hidden rounded-sm bg-muted">
|
<Avatar className="center h-8 w-8 overflow-hidden rounded-sm bg-muted">
|
||||||
<AvatarImage
|
<AvatarImage src={profile.image} alt={profile.displayName} />
|
||||||
src={
|
<AvatarFallback className="text-xs">
|
||||||
"https://images.unsplash.com/photo-1566492031773-4f4e44671857?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=4&w=256&h=256&q=60"
|
{getTwoLetters({ npub, profile })}
|
||||||
}
|
</AvatarFallback>
|
||||||
alt="user"
|
|
||||||
/>
|
|
||||||
<AvatarFallback className="text-xs">SC</AvatarFallback>
|
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<div className="center 5 gap-1">
|
<div className="center 5 gap-1">
|
||||||
<span className="text-xs uppercase text-muted-foreground">
|
<span className="text-xs uppercase text-muted-foreground group-hover:underline">
|
||||||
Derek Seivers
|
{getNameToShow({ npub, profile })}
|
||||||
</span>
|
</span>
|
||||||
<HiCheckBadge className="h-4 w-4 text-primary" />
|
{!!profile.nip05 && <HiCheckBadge className="h-4 w-4 text-primary" />}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@ import Container from "./components/Container";
|
|||||||
import { CardTitle, CardDescription } from "@/components/ui/card";
|
import { CardTitle, CardDescription } from "@/components/ui/card";
|
||||||
import { type Event } from "nostr-tools";
|
import { type Event } from "nostr-tools";
|
||||||
|
|
||||||
export default function KindDefault({}: Event) {
|
export default function KindDefault({ pubkey }: Event) {
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container pubkey={pubkey}>
|
||||||
<CardTitle className="mb-1.5 line-clamp-2 text-lg font-semibold">
|
<CardTitle className="mb-1.5 line-clamp-2 text-lg font-semibold">
|
||||||
The start of the Nostr revolution
|
The start of the Nostr revolution
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
|
@ -10,7 +10,7 @@ import useCurrentUser from "@/lib/hooks/useCurrentUser";
|
|||||||
|
|
||||||
export default function LoginModal() {
|
export default function LoginModal() {
|
||||||
const { loginWithNip07 } = useNDK();
|
const { loginWithNip07 } = useNDK();
|
||||||
const { loginWithPubkey } = useCurrentUser();
|
const { loginWithPubkey, currentUser } = useCurrentUser();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const modal = useModal();
|
const modal = useModal();
|
||||||
|
|
||||||
@ -29,9 +29,7 @@ export default function LoginModal() {
|
|||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error("NO auth");
|
throw new Error("NO auth");
|
||||||
}
|
}
|
||||||
console.log("LOGIN", user);
|
|
||||||
await loginWithPubkey(nip19.decode(user.npub).data.toString());
|
await loginWithPubkey(nip19.decode(user.npub).data.toString());
|
||||||
|
|
||||||
// keys?.setKeys({
|
// keys?.setKeys({
|
||||||
// privkey: "",
|
// privkey: "",
|
||||||
// pubkey: ,
|
// pubkey: ,
|
||||||
@ -56,6 +54,11 @@ export default function LoginModal() {
|
|||||||
getConnected(shouldReconnect);
|
getConnected(shouldReconnect);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentUser) {
|
||||||
|
modal?.hide();
|
||||||
|
}
|
||||||
|
}, [currentUser]);
|
||||||
|
|
||||||
async function handleLogin() {
|
async function handleLogin() {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
@ -17,7 +17,10 @@ export default function Template({ title, children, className }: ModalProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn("relative w-full grow p-4 md:rounded-lg md:p-6", className)}
|
className={cn(
|
||||||
|
"relative w-full grow border bg-background p-4 shadow md:rounded-lg md:p-6",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<div className="mb-4 flex items-center justify-between">
|
<div className="mb-4 flex items-center justify-between">
|
||||||
<h1
|
<h1
|
||||||
|
@ -4,6 +4,7 @@ import currentUserStore from "@/lib/stores/currentUser";
|
|||||||
// import useEvents from "@/lib/hooks/useEvents";
|
// import useEvents from "@/lib/hooks/useEvents";
|
||||||
import { UserSchema } from "@/types";
|
import { UserSchema } from "@/types";
|
||||||
import { useNDK } from "@/app/_providers/ndk";
|
import { useNDK } from "@/app/_providers/ndk";
|
||||||
|
import { nip19 } from "nostr-tools";
|
||||||
|
|
||||||
export default function useCurrentUser() {
|
export default function useCurrentUser() {
|
||||||
const {
|
const {
|
||||||
@ -38,6 +39,21 @@ export default function useCurrentUser() {
|
|||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
async function attemptLogin() {
|
||||||
|
const shouldReconnect = localStorage.getItem("shouldReconnect");
|
||||||
|
if (!shouldReconnect || typeof window.nostr === "undefined") return;
|
||||||
|
const user = await loginWithNip07();
|
||||||
|
if (!user) {
|
||||||
|
throw new Error("NO auth");
|
||||||
|
}
|
||||||
|
console.log("LOGIN", user);
|
||||||
|
await loginWithPubkey(nip19.decode(user.npub).data.toString());
|
||||||
|
if (typeof window.webln !== "undefined") {
|
||||||
|
await window.webln.enable();
|
||||||
|
}
|
||||||
|
console.log("connected ");
|
||||||
|
}
|
||||||
|
|
||||||
function logout() {
|
function logout() {
|
||||||
localStorage.removeItem("shouldReconnect");
|
localStorage.removeItem("shouldReconnect");
|
||||||
setCurrentUser(null);
|
setCurrentUser(null);
|
||||||
@ -73,5 +89,6 @@ export default function useCurrentUser() {
|
|||||||
logout,
|
logout,
|
||||||
updateUser: handleUpdateUser,
|
updateUser: handleUpdateUser,
|
||||||
loginWithPubkey,
|
loginWithPubkey,
|
||||||
|
attemptLogin,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,17 @@ export function truncateText(text: string, size?: number) {
|
|||||||
let length = size ?? 5;
|
let length = size ?? 5;
|
||||||
return text.slice(0, length) + "..." + text.slice(-length);
|
return text.slice(0, length) + "..." + text.slice(-length);
|
||||||
}
|
}
|
||||||
|
export function getNameToShow(user: {
|
||||||
|
npub: string;
|
||||||
|
profile?: {
|
||||||
|
displayName?: string;
|
||||||
|
name?: string;
|
||||||
|
};
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
user.profile?.displayName ?? user.profile?.name ?? truncateText(user.npub)
|
||||||
|
);
|
||||||
|
}
|
||||||
export function getTwoLetters(user: {
|
export function getTwoLetters(user: {
|
||||||
npub: string;
|
npub: string;
|
||||||
profile?: {
|
profile?: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user