content
This commit is contained in:
parent
5a3003abe5
commit
3a91d248e9
@ -42,9 +42,7 @@ export default function ProfilePage({
|
||||
{!!profile?.banner && (
|
||||
<Image
|
||||
className="absolute inset-0 h-full w-full object-cover align-middle"
|
||||
src={
|
||||
"https://images.lumacdn.com/cdn-cgi/image/format=auto,fit=cover,dpr=2,quality=75,width=1250,height=357.14285714285717/calendar-cover-images/4m/c50dff9c-12e1-4b8a-ae95-68a36364b760"
|
||||
}
|
||||
src={profile.banner}
|
||||
width={400}
|
||||
height={100}
|
||||
alt="banner"
|
||||
@ -58,9 +56,7 @@ export default function ProfilePage({
|
||||
<div className="z-1 ml-[calc(-1_*_3px)] overflow-hidden rounded-[0.5rem] bg-background p-[3px] sm:ml-[calc(-1_*_4px)] sm:p-[4px] lg:ml-[calc(-1_*_6px)] lg:rounded-[1rem] lg:p-[6px]">
|
||||
{profile?.image ? (
|
||||
<Image
|
||||
src={
|
||||
"https://images.lumacdn.com/cdn-cgi/image/format=auto,fit=cover,dpr=2,background=white,quality=75,width=96,height=96/calendars/hw/70772773-6d97-4fbb-a076-fc4dee603080"
|
||||
}
|
||||
src={profile.image}
|
||||
className="aspect-square w-[4rem] overflow-hidden rounded-[calc(0.5rem_-_3px)] object-cover object-center sm:w-[4.5rem] sm:rounded-[calc(0.5rem_-_4px)] md:w-[5rem] lg:w-[6rem] lg:rounded-[calc(1rem_-_6px)]"
|
||||
unoptimized
|
||||
alt="profile picture"
|
||||
|
@ -102,6 +102,7 @@ function Creator({ npub }: { npub: string }) {
|
||||
"",
|
||||
summary:
|
||||
getTagValues("summary", e.tags) ?? getTagValues("r", e.tags) ?? e.content,
|
||||
href: `/article/${e.encode()}`,
|
||||
}));
|
||||
|
||||
return (
|
||||
|
@ -12,6 +12,8 @@ import { DUMMY_30023 } from "@/constants";
|
||||
import Link from "next/link";
|
||||
import useEvents from "@/lib/hooks/useEvents";
|
||||
import { Event } from "nostr-tools";
|
||||
import KindLoading from "@/components/KindCard/loading";
|
||||
|
||||
export default function LongFormContentSection() {
|
||||
const { events } = useEvents({
|
||||
filter: {
|
||||
@ -28,14 +30,23 @@ export default function LongFormContentSection() {
|
||||
</Button>
|
||||
</SectionHeader>
|
||||
<SectionContent className="sm:lg-feed-cols relative mx-auto flex flex-col gap-4">
|
||||
{events.map((e) => {
|
||||
const event = e.rawEvent() as Event;
|
||||
return (
|
||||
<Link key={e.id} href={`/article/${e.tagId}`}>
|
||||
<KindCard {...event} />
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
{events?.length ? (
|
||||
events.map((e) => {
|
||||
const event = e.rawEvent() as Event;
|
||||
return (
|
||||
<Link key={e.id} href={`/article/${e.tagId}`}>
|
||||
<KindCard {...event} />
|
||||
</Link>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<>
|
||||
<KindLoading />
|
||||
<KindLoading />
|
||||
<KindLoading />
|
||||
<KindLoading />
|
||||
</>
|
||||
)}
|
||||
</SectionContent>
|
||||
</Section>
|
||||
);
|
||||
|
@ -1,12 +0,0 @@
|
||||
"use client";
|
||||
import Article from "@/containers/Article";
|
||||
|
||||
export default function ArticlePage({
|
||||
params: { eventId },
|
||||
}: {
|
||||
params: {
|
||||
eventId: string;
|
||||
};
|
||||
}) {
|
||||
return <Article />;
|
||||
}
|
39
app/(app)/article/[naddr]/page.tsx
Normal file
39
app/(app)/article/[naddr]/page.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
"use client";
|
||||
import { useEffect } from "react";
|
||||
import Article from "@/containers/Article";
|
||||
import { useNDK } from "@nostr-dev-kit/ndk-react";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import Spinner from "@/components/spinner";
|
||||
import useEvents from "@/lib/hooks/useEvents";
|
||||
export default function ArticlePage({
|
||||
params: { naddr },
|
||||
}: {
|
||||
params: {
|
||||
naddr: string;
|
||||
};
|
||||
}) {
|
||||
const { ndk } = useNDK();
|
||||
const { data, type } = nip19.decode(naddr);
|
||||
const { events } = useEvents({
|
||||
filter:
|
||||
type === "naddr"
|
||||
? {
|
||||
kinds: [data.kind],
|
||||
authors: [data.pubkey],
|
||||
["#d"]: [data.identifier],
|
||||
limit: 1,
|
||||
}
|
||||
: {},
|
||||
});
|
||||
|
||||
if (events?.[0]) {
|
||||
return <Article event={events[0]} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="center pt-20 text-primary">
|
||||
<Spinner />
|
||||
{events.length}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -19,6 +19,7 @@ type CreatorCardProps = {
|
||||
id: string;
|
||||
title: string;
|
||||
summary: string;
|
||||
href: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
@ -39,7 +40,11 @@ export default function CreatorCard({
|
||||
<div className="absolute inset-0 bg-background/60 backdrop-blur-md transition-all">
|
||||
<div className="group relative flex h-full w-full flex-col items-center justify-end transition-all">
|
||||
<CardHeader className="absolute inset-x-0 top-[59%] transform pt-4 text-center transition-all duration-300 group-hover:top-[8px] group-hover:ml-[75px] group-hover:text-left">
|
||||
<CardTitle>{getNameToShow({ profile, npub })}</CardTitle>
|
||||
<Link href={`/${npub}`}>
|
||||
<CardTitle className="hover:underline">
|
||||
{getNameToShow({ profile, npub })}
|
||||
</CardTitle>
|
||||
</Link>
|
||||
<CardDescription className="line-clamp-3 group-hover:text-xs">
|
||||
{profile?.about}
|
||||
</CardDescription>
|
||||
@ -65,7 +70,7 @@ export default function CreatorCard({
|
||||
{recentWork.map((item) => (
|
||||
<li key={item.id} className="w-full overflow-hidden">
|
||||
<Link
|
||||
href={`/${item.id}`}
|
||||
href={item.href}
|
||||
className="flex max-w-full items-center justify-between overflow-hidden py-1.5 pl-4 pr-2 transition-colors hover:bg-muted hover:text-primary"
|
||||
>
|
||||
<div className="shrink overflow-x-hidden">
|
||||
|
@ -14,7 +14,7 @@ export default function Kind30023({ content, pubkey, tags }: Event) {
|
||||
|
||||
return (
|
||||
<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 leading-6">
|
||||
{title}
|
||||
</CardTitle>
|
||||
<CardDescription className="line-clamp-4 text-sm">
|
||||
|
@ -37,7 +37,7 @@ export default function Container({
|
||||
actionOptions = [],
|
||||
}: CreatorCardProps) {
|
||||
return (
|
||||
<Card className="relative overflow-hidden">
|
||||
<Card className="relative flex h-full flex-col overflow-hidden">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 p-4 pb-4">
|
||||
<ProfileHeader pubkey={pubkey} />
|
||||
<div className="-mr-1 flex items-center gap-x-1.5 text-xs text-muted-foreground">
|
||||
@ -53,14 +53,16 @@ export default function Container({
|
||||
</DropDownMenu>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="px-4 pb-3">
|
||||
<CardContent className="flex grow flex-col px-4 pb-3">
|
||||
{children}
|
||||
{!!contentTags?.length && (
|
||||
<div className="-mb-2 mt-1 max-h-[52px] overflow-hidden">
|
||||
<Tags tags={contentTags} />
|
||||
</div>
|
||||
)}
|
||||
<Actions />
|
||||
<div className="mt-auto">
|
||||
{!!contentTags?.length && (
|
||||
<div className="-mb-1 mt-1 max-h-[52px] overflow-hidden">
|
||||
<Tags tags={contentTags} />
|
||||
</div>
|
||||
)}
|
||||
<Actions />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
@ -19,12 +19,34 @@ export default function ProfileHeader({ pubkey }: ProfileHeaderProps) {
|
||||
{getTwoLetters({ npub, profile })}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="center 5 gap-1">
|
||||
<span className="text-xs uppercase text-muted-foreground group-hover:underline">
|
||||
{getNameToShow({ npub, profile })}
|
||||
</span>
|
||||
{!!profile?.nip05 && <HiCheckBadge className="h-4 w-4 text-primary" />}
|
||||
</div>
|
||||
{profile?.displayName || profile?.name ? (
|
||||
<div className="flex flex-col gap-0">
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="text-sm font-medium text-foreground group-hover:underline">
|
||||
{getNameToShow({ npub, profile })}
|
||||
</span>
|
||||
{!!profile?.nip05 && (
|
||||
<HiCheckBadge className="h-4 w-4 text-primary" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
{!!profile.nip05 && (
|
||||
<span className="text-[11px] text-muted-foreground">
|
||||
{profile.nip05}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="text-sm uppercase text-foreground group-hover:underline">
|
||||
{getNameToShow({ npub, profile })}
|
||||
</span>
|
||||
{!!profile?.nip05 && (
|
||||
<HiCheckBadge className="h-4 w-4 text-primary" />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
21
components/KindCard/loading.tsx
Normal file
21
components/KindCard/loading.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import Container from "./components/Container";
|
||||
import { CardTitle, CardDescription } from "@/components/ui/card";
|
||||
import { type Event } from "nostr-tools";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
|
||||
export default function KindLoading() {
|
||||
return (
|
||||
<Container
|
||||
pubkey={
|
||||
"f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca"
|
||||
}
|
||||
>
|
||||
<div className="space-y-2 text-muted-foreground">
|
||||
<Skeleton className="mb-2 h-4 w-1/3 bg-muted" />
|
||||
<Skeleton className="h-4 w-1/2 bg-muted" />
|
||||
<Skeleton className="h-4 w-2/5 bg-muted" />
|
||||
<Skeleton className="h-4 w-4/5 bg-muted" />
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
@ -12,7 +12,6 @@ type MarkdoneProps = {
|
||||
};
|
||||
export default function Markdown({ content }: MarkdoneProps) {
|
||||
const { resolvedTheme } = useTheme();
|
||||
// const [blocks, setBlocks] = useState<Block[]>();
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const editor: BlockNoteEditor = useBlockNote({
|
||||
@ -22,12 +21,10 @@ export default function Markdown({ content }: MarkdoneProps) {
|
||||
useEffect(() => {
|
||||
if (editor) {
|
||||
if (content) {
|
||||
console.log("initial md", content);
|
||||
// Whenever the current Markdown content changes, converts it to an array
|
||||
// of Block objects and replaces the editor's content with them.
|
||||
const getBlocks = async () => {
|
||||
const blocks: Block[] = await editor.markdownToBlocks(content);
|
||||
console.log("Blocks", blocks);
|
||||
editor.replaceBlocks(editor.topLevelBlocks, blocks);
|
||||
setLoading(false);
|
||||
};
|
||||
@ -41,7 +38,7 @@ export default function Markdown({ content }: MarkdoneProps) {
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="">
|
||||
<div className="center py-20 text-primary">
|
||||
<Spinner />
|
||||
</div>
|
||||
);
|
||||
|
@ -1,11 +1,11 @@
|
||||
export const EXPLORE_CREATORS = [
|
||||
"npub1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzsevkk5s",
|
||||
"npub1l2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqutajft",
|
||||
"npub1u6qhg5ucu3xza4nlz94q90y720tr6l09avnq8y3yfp5qrv9v8sus3tnd7t",
|
||||
"npub1sg6plzptd64u62a878hep2kev88swjh3tw00gjsfl8f237lmu63q0uf63m",
|
||||
"npub19mduaf5569jx9xz555jcx3v06mvktvtpu0zgk47n4lcpjsz43zzqhj6vzk",
|
||||
"npub1dc9p7jzjhj86g2uqgltq4qvnpkyfqn9r72kdlddcgyat3j05gnjsgjc8rz",
|
||||
"npub1qny3tkh0acurzla8x3zy4nhrjz5zd8l9sy9jys09umwng00manysew95gx",
|
||||
"npub1l2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqutajft",
|
||||
];
|
||||
|
||||
export const BANNER =
|
||||
|
@ -1,7 +1,7 @@
|
||||
export const RELAYS = [
|
||||
"wss://nostr.pub.wellorder.net",
|
||||
"wss://nostr.drss.io",
|
||||
"wss://nostr.swiss-enigma.ch",
|
||||
"wss://relay.damus.io",
|
||||
"wss://nostr.mom",
|
||||
"wss://nos.lol",
|
||||
"wss://nostr.wine",
|
||||
"wss://relay.damus.io",
|
||||
"wss://nostr.swiss-enigma.ch",
|
||||
];
|
||||
|
@ -7,56 +7,46 @@ import { Avatar, AvatarImage, AvatarFallback } from "@radix-ui/react-avatar";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { formatDate } from "@/lib/utils/dates";
|
||||
import Actions from "./Actions";
|
||||
import Logo from "@/assets/Logo";
|
||||
import { NDKEvent } from "@nostr-dev-kit/ndk";
|
||||
import { getTagAllValues, getTagValues } from "@/lib/nostr/utils";
|
||||
import useProfile from "@/lib/hooks/useProfile";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { getNameToShow, getTwoLetters } from "@/lib/utils";
|
||||
|
||||
export default function ArticlePage() {
|
||||
type ArticleProps = {
|
||||
event: NDKEvent;
|
||||
};
|
||||
|
||||
export default function ArticlePage({ event }: ArticleProps) {
|
||||
const Viewer = useMemo(
|
||||
() => dynamic(() => import("@/components/LongForm"), { ssr: false }),
|
||||
[],
|
||||
);
|
||||
console.log(event);
|
||||
const router = useRouter();
|
||||
const markdown = `Do you have any thoughts of YakiHonne? Share it and earn SATs!
|
||||
|
||||
Comment2Earn | Earn SATs by sharing your comments on YakiHonne
|
||||
|
||||
Earn SATs by sharing your comments on YakiHonne.
|
||||
|
||||
⏰2nd - 15th Oct
|
||||
|
||||
### Follow Us
|
||||
|
||||
- Nostr: npub1yzvxlwp7wawed5vgefwfmugvumtp8c8t0etk3g8sky4n0ndvyxesnxrf8q
|
||||
- Twitter: https://twitter.com/YakiHonne
|
||||
- Facebook Profile: https://www.facebook.com/profi…1715056704
|
||||
- Facebook Page: https://www.facebook.com/profi…2076811240
|
||||
- Facebook Group: https://www.facebook.com/group…4539860115
|
||||
- Youtube: https://www.youtube.com/channe…f4EyFJ7BlA
|
||||
|
||||
### How to Get SATs:
|
||||
1. Post your thoughts about YakiHonne on at least one of the above social media, and be sure to @ YakiHonne.
|
||||
2. Follow YakiHonne on at least one of the social media above.
|
||||
3. Back to this article, leave your social account which followed YakiHonne in the Comments.
|
||||
4. Be zapped with SATs.
|
||||
|
||||
### What You Will Get:
|
||||
1. 500 SATs, if you finished all steps.
|
||||
2. 1000 SATs, if you finished all steps and`;
|
||||
const markdown = event.content;
|
||||
const pubkey = event.pubkey;
|
||||
const createdAt = getTagValues("published_at", event.tags)
|
||||
? parseInt(getTagValues("published_at", event.tags) as string)
|
||||
: event.created_at;
|
||||
const { profile } = useProfile(pubkey);
|
||||
const npub = nip19.npubEncode(pubkey);
|
||||
const title = getTagValues("title", event.tags);
|
||||
const summary = getTagValues("summary", event.tags);
|
||||
const tags = getTagAllValues("t", event.tags);
|
||||
|
||||
return (
|
||||
<div className="relative @container">
|
||||
<div className="sticky inset-x-0 top-0 z-10 flex items-center justify-between border-b bg-background pb-4 pt-4">
|
||||
<div className="center gap-x-3">
|
||||
<Avatar className="center h-8 w-8 overflow-hidden rounded-sm bg-muted">
|
||||
<AvatarImage
|
||||
src={
|
||||
"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"
|
||||
}
|
||||
alt="user"
|
||||
/>
|
||||
<AvatarFallback className="text-xs">SC</AvatarFallback>
|
||||
<AvatarImage src={profile?.image} alt="user" />
|
||||
<AvatarFallback className="text-xs">
|
||||
{getTwoLetters({ profile, npub })}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<span className="text-xs uppercase text-muted-foreground">
|
||||
Derek Seivers
|
||||
{getNameToShow({ profile, npub })}
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
@ -79,27 +69,27 @@ export default function ArticlePage() {
|
||||
<article className="prose dark:prose-invert prose-zinc relative mx-auto max-w-3xl pt-7">
|
||||
<div className="">
|
||||
<div className="flex items-center justify-between gap-1 lg:mb-2">
|
||||
<Button variant={"link"} className="px-0">
|
||||
Balaji's News Letter
|
||||
</Button>
|
||||
{tags.map((t) => (
|
||||
<Button variant={"link"} className="px-0">
|
||||
{t}
|
||||
</Button>
|
||||
))}
|
||||
|
||||
<div className="center text-xs text-muted-foreground/50">
|
||||
<span className="mr-2.5">
|
||||
{formatDate(new Date("10-2-22"), "MMMM Do, YYYY")}
|
||||
</span>
|
||||
{!!createdAt && (
|
||||
<span className="mr-2.5">
|
||||
{formatDate(new Date(createdAt * 1000), "MMMM Do, YYYY")}
|
||||
</span>
|
||||
)}
|
||||
<span className="h-3 w-[1px] rounded-full bg-muted-foreground/50"></span>
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="">
|
||||
This is the large title for the article. It's time to take over.
|
||||
</h1>
|
||||
<h1 className="">{title}</h1>
|
||||
<div className="mb-3 flex items-center justify-end">
|
||||
<Actions />
|
||||
</div>
|
||||
<div className="rounded-r-lg border-l-[4px] border-primary bg-muted p-4">
|
||||
<p className="m-0">
|
||||
Here is a short summary for the article that you are about to
|
||||
start reading. Get ready to really enojy your self.
|
||||
</p>
|
||||
<p className="m-0">{summary} </p>
|
||||
</div>
|
||||
</div>
|
||||
<Viewer content={markdown} />
|
||||
|
Loading…
x
Reference in New Issue
Block a user