Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

certificates
Binary file modified bun.lockb
Binary file not shown.
11 changes: 5 additions & 6 deletions src/app/(site)/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,13 @@ export default function CreateBounty() {
<div className="mr-1 flex items-center">
<TabsList className="bg-background">
<TabsTrigger
className="data-[state=active]:bg-secondary"
className="data-[state=active]:bg-muted"
value="write"
>
Write
</TabsTrigger>
<TabsTrigger
className="data-[state=active]:bg-secondary"
className="data-[state=active]:bg-muted"
value="preview"
>
Preview
Expand Down Expand Up @@ -256,7 +256,7 @@ export default function CreateBounty() {
</FormControl>
</TabsContent>
<TabsContent value="preview">
<div className="max-h-[28rem] min-h-[12rem] w-full overflow-y-auto rounded-md border border-input bg-secondary/20">
<div className="max-h-[28rem] min-h-[12rem] w-full overflow-y-auto rounded-md border border-input bg-muted/90">
<article className="prose prose-sm w-full px-3 py-2 dark:prose-invert">
<Markdown>{form.getValues().description}</Markdown>
</article>
Expand All @@ -282,8 +282,7 @@ export default function CreateBounty() {
role="combobox"
className={cn(
"justify-between",
!field.value &&
"bg-secondary/20 text-muted-foreground",
!field.value && "bg-muted/90 text-muted-foreground",
)}
>
{field.value
Expand Down Expand Up @@ -344,7 +343,7 @@ export default function CreateBounty() {
control={form.control}
name="shouldNotify"
render={({ field }) => (
<FormItem className="flex flex-row items-start space-x-3 space-y-0 rounded-md border bg-secondary/20 p-4">
<FormItem className="flex flex-row items-start space-x-3 space-y-0 rounded-md border bg-muted/90 p-4">
<FormControl>
<Checkbox
checked={field.value}
Expand Down
3 changes: 2 additions & 1 deletion src/app/(site)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Footer from "~/components/footer/Footer";
import Header from "~/components/header/Header";
import Hero from "~/components/hero/Hero";
import RelaySheet from "~/components/relays/RelaySheet";


export default function RootLayout({
children,
}: {
Expand All @@ -16,6 +16,7 @@ export default function RootLayout({
<div className="mx-auto w-full max-w-7xl">
<div className="mx-auto max-w-4xl">
<Header />
<Hero />
{children}
<RelaySheet />
<Footer />
Expand Down
7 changes: 6 additions & 1 deletion src/app/(site)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export default async function HomePage({
filter["#p"] = [publicKey];
}

const bitcoinPrice = parseFloat(
await (await fetch("https://blockchain.info/q/24hrprice")).text(),
);

return (
<div className="w-full flex-col items-center">
{loggedIn && (
Expand All @@ -55,7 +59,7 @@ export default async function HomePage({
Bounties
</h1>
<div className="mr-1 flex items-center">
<TabsList className="bg-secondary/90">
<TabsList className="bg-muted">
<TabsTrigger asChild value="open">
<Link href={"?tab=open"} replace={true}>
Open
Expand All @@ -82,6 +86,7 @@ export default async function HomePage({
initialBounties={[]}
filter={filter}
eventKey={selectedTab}
bitcoinPrice={bitcoinPrice}
/>
</div>
);
Expand Down
11 changes: 5 additions & 6 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import { ThemeProvider } from "~/context/ThemeProvider";
import { GeistMono } from "geist/font/mono";
import { GeistSans } from "geist/font/sans";
import type { Metadata } from "next";
import { Inter } from "next/font/google";

import "~/styles/globals.css";

import AuthProvider from "~/context/AuthProvider";
import { Toaster } from "~/components/ui/sonner";
import AuthProvider from "~/context/AuthProvider";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: "Fundsolvr",
Expand All @@ -19,11 +22,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<html
className={`${GeistSans.variable} ${GeistMono.variable}`}
lang="en"
suppressHydrationWarning
>
<html className={inter.className} lang="en" suppressHydrationWarning>
<body className="flex h-full w-full">
<ThemeProvider
attribute="class"
Expand Down
8 changes: 2 additions & 6 deletions src/components/applications/ApplicantCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import useAuth from "~/hooks/useAuth";
import { fromNow } from "~/lib/utils";
import { useRelayStore } from "~/store/relay-store";
import { type Event } from "nostr-tools";
import {
tag,
useBatchedEvents,
useBatchedProfiles,
} from "react-nostr";
import { tag, useBatchedEvents, useBatchedProfiles } from "react-nostr";

import Profile from "../bounty/Profile";
import GithubBadge from "../profile/GithubBadge";
Expand Down Expand Up @@ -39,7 +35,7 @@ export default function ApplicationCard({
);

return (
<li className="flex items-center gap-x-4 rounded-md border bg-secondary/50 p-4">
<li className="flex items-center gap-x-4 rounded-md border bg-muted/50 p-4">
<div className="flex w-full flex-col gap-y-1">
<span className="flex w-full justify-between pb-1">
<span className="flex items-center gap-x-2 text-sm font-light text-muted-foreground">
Expand Down
3 changes: 2 additions & 1 deletion src/components/applications/ApplicantMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
type ATagParams,
} from "react-nostr";
import { toast } from "sonner";

import { ViewRawDialog } from "../misc/ViewRawDialog";

type Props = {
Expand Down Expand Up @@ -87,7 +88,7 @@ export default function ApplicantMenu({ applicantEvent, bountyEvent }: Props) {
<>
<DropdownMenu>
<DropdownMenuTrigger>
<div className="flex h-9 w-9 items-center justify-center whitespace-nowrap rounded-md border border-input bg-background text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:bg-secondary/70 dark:hover:bg-secondary/60">
<div className="flex h-9 w-9 items-center justify-center whitespace-nowrap rounded-md border border-input bg-background text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:bg-muted/70 dark:hover:bg-muted/60">
<MoreVertical className="h-4 w-4" />
</div>
</DropdownMenuTrigger>
Expand Down
77 changes: 46 additions & 31 deletions src/components/bounty-feed/BountyCard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
/* eslint-disable @next/next/no-img-element */

import { SatoshiV2Icon } from "@bitcoin-design/bitcoin-icons-react/filled";
import { BOT_AVATAR_ENDPOINT } from "~/lib/constants";
import { fromNow } from "~/lib/utils";
import { useRelayStore } from "~/store/relay-store";
Expand All @@ -17,45 +16,27 @@ import {
} from "react-nostr";

import ApplicationCount from "../applications/ApplicationCount";
import Zap from "../ui/icons/zap";

type Props = {
bountyEvent: Event;
showProfileInfo?: boolean;
bitcoinPrice?: number | null;
};

export default function BountyCard({
bountyEvent,
showProfileInfo = true,
bitcoinPrice,
}: Props) {
const pubkey = bountyEvent.pubkey;
const { subRelays } = useRelayStore();

const profileEvent = useBatchedProfiles(bountyEvent.pubkey, subRelays);

return (
<Link href={`/b/${createNaddr(bountyEvent, subRelays)}`}>
<li className="flex cursor-pointer items-center gap-x-4 border-t p-4 hover:bg-muted/40">
{showProfileInfo && (
<img
src={
profileContent(profileEvent).picture ||
BOT_AVATAR_ENDPOINT + pubkey
}
alt=""
className="aspect-square w-16 rounded-md border border-border dark:border-border"
/>
)}
<div className="flex w-full flex-col gap-y-1">
{showProfileInfo && (
<span className="flex w-full justify-between pb-1">
<span className="text-sm font-light text-muted-foreground">
{profileContent(profileEvent).name || shortNpub(pubkey)}
</span>
{/* {tag("t", bountyEvent) && ( */}
{/* <Badge variant="outline">{tag("t", bountyEvent)}</Badge> */}
{/* )} */}
</span>
)}
<li className="flex cursor-pointer items-center gap-x-4 rounded-md p-2.5 hover:bg-muted md:p-6">
<div className="flex w-full flex-col">
{showProfileInfo ? (
<span className="text-base text-card-foreground">
{tag("title", bountyEvent)}
Expand All @@ -70,18 +51,52 @@ export default function BountyCard({
{/* )} */}
</span>
)}
<span className="flex items-center text-lg font-semibold text-orange-500 dark:text-orange-400">
<SatoshiV2Icon className="h-6 w-6" />
{Number(tag("reward", bountyEvent)).toLocaleString()}
</span>
<span className="flex w-full justify-between pt-2 text-sm font-light text-muted-foreground">
<div className="mt-2 flex flex-row items-center gap-2 text-sm font-light text-muted-foreground">
{showProfileInfo && (
<img
src={
profileContent(profileEvent).picture ||
BOT_AVATAR_ENDPOINT + pubkey
}
alt=""
className="aspect-square w-5 rounded-md border border-border dark:border-border"
/>
)}
{showProfileInfo && (
<span className="flex justify-between">
<span>
{profileContent(profileEvent).name || shortNpub(pubkey)}
</span>
{/* {tag("t", bountyEvent) && ( */}
{/* <Badge variant="outline">{tag("t", bountyEvent)}</Badge> */}
{/* )} */}
</span>
)}

<span>{fromNow(bountyEvent.created_at) ?? "unknown"}</span>
<span className="flex items-center gap-x-1">
<User className="h-4 w-4" />
<ApplicationCount bounty={bountyEvent} />
Hunters
</span>
</span>
</div>
<div className="bg-bitcoin-background text-bitcoin mt-3 flex items-center gap-2 self-start rounded-md px-3 py-2 text-lg font-semibold">
<div className="flex flex-row items-center">
<Zap className="h-5 w-5" />
<span>{Number(tag("reward", bountyEvent)).toLocaleString()}</span>
</div>
{bitcoinPrice && (
<span className="text-md font-normal text-black dark:text-white">
$
{(
Number(tag("reward", bountyEvent)) *
bitcoinPrice *
0.00000001
)
.toFixed(2)
.toLocaleString()}
</span>
)}
</div>
</div>
</li>
</Link>
Expand Down
11 changes: 9 additions & 2 deletions src/components/bounty-feed/BountyFeed.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
"use client";

import { useRelayStore } from "~/store/relay-store";
import { type Event, type Filter } from "nostr-tools";
import { useSubscribe } from "react-nostr";
import { toast } from "sonner";

import BountyCard from "./BountyCard";
import BountyLoadButton from "./BountyLoadButton";
import { useRelayStore } from "~/store/relay-store";

type Props = {
initialBounties?: Event[];
filter: Filter;
eventKey: string;
tag?: string;
showProfileInfo?: boolean;
bitcoinPrice?: number | null;
};

export default function BountiesFeed({
Expand All @@ -22,6 +23,7 @@ export default function BountiesFeed({
eventKey,
tag,
showProfileInfo,
bitcoinPrice,
}: Props) {
const onEventsNotFound = () => {
toast("No bounties found", {
Expand Down Expand Up @@ -55,7 +57,12 @@ export default function BountiesFeed({
<ul className="flex w-full flex-col">
{(events.length > 0 ? events : initialBounties ?? []).map(
(bountyEvent) => (
<BountyCard key={bountyEvent.id} bountyEvent={bountyEvent} showProfileInfo={showProfileInfo} />
<BountyCard
key={bountyEvent.id}
bountyEvent={bountyEvent}
showProfileInfo={showProfileInfo}
bitcoinPrice={bitcoinPrice}
/>
),
)}
</ul>
Expand Down
7 changes: 5 additions & 2 deletions src/components/bounty/BackButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ export default function BackButton() {
return (
<Link href="/">
{/* TODO: route back if routing back to / if not just route to / */}
<Button variant="outline" className="flex dark:bg-secondary/70 dark:hover:bg-secondary/60">
<ArrowLeftIcon className="h-4 w-4 mr-1" />
<Button
variant="outline"
className="flex dark:bg-muted/70 dark:hover:bg-muted/60"
>
<ArrowLeftIcon className="mr-1 h-4 w-4" />
Back to all Bounties
</Button>
</Link>
Expand Down
2 changes: 1 addition & 1 deletion src/components/bounty/BountyDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function BountyDetails({ bounty }: Props) {

return (
<div className="flex flex-col gap-y-4">
<div className="min-h-[12rem] w-full rounded-md border border-input bg-secondary/20">
<div className="min-h-[12rem] w-full rounded-md border border-input bg-muted/20">
<article className="prose prose-sm w-full p-4 dark:prose-invert">
<Markdown>{bounty.content}</Markdown>
</article>
Expand Down
8 changes: 6 additions & 2 deletions src/components/bounty/BountyMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export default function BountyMenu({ bounty }: Props) {
<>
<DropdownMenu>
<DropdownMenuTrigger>
<div className="flex h-9 w-9 items-center justify-center whitespace-nowrap rounded-md border border-input bg-background text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:bg-secondary/70 dark:hover:bg-secondary/60">
<div className="flex h-9 w-9 items-center justify-center whitespace-nowrap rounded-md border border-input bg-background text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:bg-muted/70 dark:hover:bg-muted/60">
<MoreVertical className="h-4 w-4" />
</div>
</DropdownMenuTrigger>
Expand Down Expand Up @@ -101,7 +101,11 @@ export default function BountyMenu({ bounty }: Props) {
)}
</DropdownMenuContent>
</DropdownMenu>
<ViewRawDialog open={viewRawOpen} setOpen={setViewRawOpen} event={bounty} />
<ViewRawDialog
open={viewRawOpen}
setOpen={setViewRawOpen}
event={bounty}
/>
</>
);
}
2 changes: 1 addition & 1 deletion src/components/bounty/BountyTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ function ZapPollTab({ selectedTab }: ApplicationTabProps) {
>
<ZapIcon
className={cn(
selectedTab === "applications"
selectedTab === "poll"
? "text-indigo-600 dark:text-indigo-500"
: "text-muted-foreground group-hover:text-foreground",
"-ml-0.5 mr-2 h-5 w-5",
Expand Down
Loading