- {showProfileInfo && (
-
-
- {profileContent(profileEvent).name || shortNpub(pubkey)}
-
- {/* {tag("t", bountyEvent) && ( */}
- {/* {tag("t", bountyEvent)} */}
- {/* )} */}
-
- )}
+
+
{showProfileInfo ? (
{tag("title", bountyEvent)}
@@ -70,18 +51,52 @@ export default function BountyCard({
{/* )} */}
)}
-
-
- {Number(tag("reward", bountyEvent)).toLocaleString()}
-
-
+
+ {showProfileInfo && (
+
+ )}
+ {showProfileInfo && (
+
+
+ {profileContent(profileEvent).name || shortNpub(pubkey)}
+
+ {/* {tag("t", bountyEvent) && ( */}
+ {/* {tag("t", bountyEvent)} */}
+ {/* )} */}
+
+ )}
+
{fromNow(bountyEvent.created_at) ?? "unknown"}
- Hunters
-
+
+
+
+
+ {Number(tag("reward", bountyEvent)).toLocaleString()}
+
+ {bitcoinPrice && (
+
+ $
+ {(
+ Number(tag("reward", bountyEvent)) *
+ bitcoinPrice *
+ 0.00000001
+ )
+ .toFixed(2)
+ .toLocaleString()}
+
+ )}
+
diff --git a/src/components/bounty-feed/BountyFeed.tsx b/src/components/bounty-feed/BountyFeed.tsx
index 0f86e7c..d0ac38b 100644
--- a/src/components/bounty-feed/BountyFeed.tsx
+++ b/src/components/bounty-feed/BountyFeed.tsx
@@ -1,12 +1,12 @@
"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[];
@@ -14,6 +14,7 @@ type Props = {
eventKey: string;
tag?: string;
showProfileInfo?: boolean;
+ bitcoinPrice?: number | null;
};
export default function BountiesFeed({
@@ -22,6 +23,7 @@ export default function BountiesFeed({
eventKey,
tag,
showProfileInfo,
+ bitcoinPrice,
}: Props) {
const onEventsNotFound = () => {
toast("No bounties found", {
@@ -55,7 +57,12 @@ export default function BountiesFeed({
{(events.length > 0 ? events : initialBounties ?? []).map(
(bountyEvent) => (
-
+
),
)}
diff --git a/src/components/bounty/BackButton.tsx b/src/components/bounty/BackButton.tsx
index 29190e6..1afb481 100644
--- a/src/components/bounty/BackButton.tsx
+++ b/src/components/bounty/BackButton.tsx
@@ -7,8 +7,11 @@ export default function BackButton() {
return (
{/* TODO: route back if routing back to / if not just route to / */}
-
-
+
+
Back to all Bounties
diff --git a/src/components/bounty/BountyDetails.tsx b/src/components/bounty/BountyDetails.tsx
index 5a584a5..a1f2632 100644
--- a/src/components/bounty/BountyDetails.tsx
+++ b/src/components/bounty/BountyDetails.tsx
@@ -28,7 +28,7 @@ export default function BountyDetails({ bounty }: Props) {
return (
-
+
{bounty.content}
diff --git a/src/components/bounty/BountyMenu.tsx b/src/components/bounty/BountyMenu.tsx
index 3351b7f..c0b84c3 100644
--- a/src/components/bounty/BountyMenu.tsx
+++ b/src/components/bounty/BountyMenu.tsx
@@ -73,7 +73,7 @@ export default function BountyMenu({ bounty }: Props) {
<>
-
+
@@ -101,7 +101,11 @@ export default function BountyMenu({ bounty }: Props) {
)}
-
+
>
);
}
diff --git a/src/components/bounty/BountyTabs.tsx b/src/components/bounty/BountyTabs.tsx
index d168248..5fe65da 100644
--- a/src/components/bounty/BountyTabs.tsx
+++ b/src/components/bounty/BountyTabs.tsx
@@ -92,7 +92,7 @@ function ZapPollTab({ selectedTab }: ApplicationTabProps) {
>
+
+
+ Get Started
+ Intro To Fundsolvr
+
+
+
+ How Open Source Should Work
+
+
+ Get paid to contribute or fund open source projects and builders
+ with Sats.
+
+
+
+
+
+ );
+}
diff --git a/src/components/hero/HeroImage.svg b/src/components/hero/HeroImage.svg
new file mode 100644
index 0000000..d43437c
--- /dev/null
+++ b/src/components/hero/HeroImage.svg
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/hero/HeroImage.tsx b/src/components/hero/HeroImage.tsx
new file mode 100644
index 0000000..82ee69c
--- /dev/null
+++ b/src/components/hero/HeroImage.tsx
@@ -0,0 +1,207 @@
+export default function HeroImage() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/profile/GithubBadge.tsx b/src/components/profile/GithubBadge.tsx
index a053591..bd46fe6 100644
--- a/src/components/profile/GithubBadge.tsx
+++ b/src/components/profile/GithubBadge.tsx
@@ -63,7 +63,7 @@ export default function GithubBadge({ pubkey }: Props) {
{profileContent(profileEvent).github}
-
+
);
}
diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx
index 05e961c..49294b3 100644
--- a/src/components/ui/avatar.tsx
+++ b/src/components/ui/avatar.tsx
@@ -1,9 +1,9 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as AvatarPrimitive from "@radix-ui/react-avatar"
+import * as React from "react";
-import { cn } from "~/lib/utils"
+import * as AvatarPrimitive from "@radix-ui/react-avatar";
+import { cn } from "~/lib/utils";
const Avatar = React.forwardRef<
React.ElementRef,
@@ -13,12 +13,12 @@ const Avatar = React.forwardRef<
ref={ref}
className={cn(
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
- className
+ className,
)}
{...props}
/>
-))
-Avatar.displayName = AvatarPrimitive.Root.displayName
+));
+Avatar.displayName = AvatarPrimitive.Root.displayName;
const AvatarImage = React.forwardRef<
React.ElementRef,
@@ -29,8 +29,8 @@ const AvatarImage = React.forwardRef<
className={cn("aspect-square h-full w-full", className)}
{...props}
/>
-))
-AvatarImage.displayName = AvatarPrimitive.Image.displayName
+));
+AvatarImage.displayName = AvatarPrimitive.Image.displayName;
const AvatarFallback = React.forwardRef<
React.ElementRef,
@@ -40,11 +40,11 @@ const AvatarFallback = React.forwardRef<
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full bg-muted",
- className
+ className,
)}
{...props}
/>
-))
-AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
+));
+AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
-export { Avatar, AvatarImage, AvatarFallback }
+export { Avatar, AvatarImage, AvatarFallback };
diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx
index 827070f..7d09753 100644
--- a/src/components/ui/badge.tsx
+++ b/src/components/ui/badge.tsx
@@ -1,7 +1,7 @@
-import * as React from "react"
-import { cva, type VariantProps } from "class-variance-authority"
+import * as React from "react";
-import { cn } from "~/lib/utils"
+import { cn } from "~/lib/utils";
+import { cva, type VariantProps } from "class-variance-authority";
const badgeVariants = cva(
"inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
@@ -11,7 +11,7 @@ const badgeVariants = cva(
default:
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
secondary:
- "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ "border-transparent bg-muted text-secondary-foreground hover:bg-muted/80",
destructive:
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
outline: "text-foreground",
@@ -20,8 +20,8 @@ const badgeVariants = cva(
defaultVariants: {
variant: "default",
},
- }
-)
+ },
+);
export interface BadgeProps
extends React.HTMLAttributes,
@@ -30,7 +30,7 @@ export interface BadgeProps
function Badge({ className, variant, ...props }: BadgeProps) {
return (
- )
+ );
}
-export { Badge, badgeVariants }
+export { Badge, badgeVariants };
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index 1f9e57e..6142cf9 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -9,7 +9,8 @@ const buttonVariants = cva(
{
variants: {
variant: {
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
+ default:
+ "bg-primary text-primary-foreground hover:bg-primary-hover hover:text-primary-foreground-hover",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
success:
@@ -17,7 +18,7 @@ const buttonVariants = cva(
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary:
- "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ "bg-secondary text-secondary-foreground hover:bg-secondary-hover hover:text-secondary-foreground-hover",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx
index 6ad24b7..1036b5d 100644
--- a/src/components/ui/dropdown-menu.tsx
+++ b/src/components/ui/dropdown-menu.tsx
@@ -1,27 +1,27 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
-import { Check, ChevronRight, Circle } from "lucide-react"
+import * as React from "react";
-import { cn } from "~/lib/utils"
+import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
+import { cn } from "~/lib/utils";
+import { Check, ChevronRight, Circle } from "lucide-react";
-const DropdownMenu = DropdownMenuPrimitive.Root
+const DropdownMenu = DropdownMenuPrimitive.Root;
-const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
+const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
-const DropdownMenuGroup = DropdownMenuPrimitive.Group
+const DropdownMenuGroup = DropdownMenuPrimitive.Group;
-const DropdownMenuPortal = DropdownMenuPrimitive.Portal
+const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
-const DropdownMenuSub = DropdownMenuPrimitive.Sub
+const DropdownMenuSub = DropdownMenuPrimitive.Sub;
-const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
+const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
const DropdownMenuSubTrigger = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef & {
- inset?: boolean
+ inset?: boolean;
}
>(({ className, inset, children, ...props }, ref) => (
{children}
-))
+));
DropdownMenuSubTrigger.displayName =
- DropdownMenuPrimitive.SubTrigger.displayName
+ DropdownMenuPrimitive.SubTrigger.displayName;
const DropdownMenuSubContent = React.forwardRef<
React.ElementRef,
@@ -48,13 +48,13 @@ const DropdownMenuSubContent = React.forwardRef<
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
- className
+ className,
)}
{...props}
/>
-))
+));
DropdownMenuSubContent.displayName =
- DropdownMenuPrimitive.SubContent.displayName
+ DropdownMenuPrimitive.SubContent.displayName;
const DropdownMenuContent = React.forwardRef<
React.ElementRef,
@@ -66,18 +66,18 @@ const DropdownMenuContent = React.forwardRef<
sideOffset={sideOffset}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
- className
+ className,
)}
{...props}
/>
-))
-DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
+));
+DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
const DropdownMenuItem = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef & {
- inset?: boolean
+ inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
-))
-DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
+));
+DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef,
@@ -100,7 +100,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
- className
+ className,
)}
checked={checked}
{...props}
@@ -112,9 +112,9 @@ const DropdownMenuCheckboxItem = React.forwardRef<
{children}
-))
+));
DropdownMenuCheckboxItem.displayName =
- DropdownMenuPrimitive.CheckboxItem.displayName
+ DropdownMenuPrimitive.CheckboxItem.displayName;
const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef,
@@ -124,7 +124,7 @@ const DropdownMenuRadioItem = React.forwardRef<
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
- className
+ className,
)}
{...props}
>
@@ -135,13 +135,13 @@ const DropdownMenuRadioItem = React.forwardRef<
{children}
-))
-DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
+));
+DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
const DropdownMenuLabel = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef & {
- inset?: boolean
+ inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
-))
-DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
+));
+DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
const DropdownMenuSeparator = React.forwardRef<
React.ElementRef,
@@ -165,8 +165,8 @@ const DropdownMenuSeparator = React.forwardRef<
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
-))
-DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
+));
+DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({
className,
@@ -177,9 +177,9 @@ const DropdownMenuShortcut = ({
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
- )
-}
-DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
+ );
+};
+DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
export {
DropdownMenu,
@@ -197,4 +197,4 @@ export {
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuRadioGroup,
-}
+};
diff --git a/src/components/ui/icons/index.ts b/src/components/ui/icons/index.ts
new file mode 100644
index 0000000..e0aad05
--- /dev/null
+++ b/src/components/ui/icons/index.ts
@@ -0,0 +1,5 @@
+import Zap from "./zap";
+
+export default {
+ Zap,
+};
diff --git a/src/components/ui/icons/zap.tsx b/src/components/ui/icons/zap.tsx
new file mode 100644
index 0000000..cbeca8f
--- /dev/null
+++ b/src/components/ui/icons/zap.tsx
@@ -0,0 +1,21 @@
+type Props = {
+ className?: string;
+};
+
+export default function Zap({ className }: Props) {
+ return (
+
+
+
+ );
+}
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
index ea67563..2cd07c9 100644
--- a/src/components/ui/input.tsx
+++ b/src/components/ui/input.tsx
@@ -1,6 +1,6 @@
-import * as React from "react"
+import * as React from "react";
-import { cn } from "~/lib/utils"
+import { cn } from "~/lib/utils";
export interface InputProps
extends React.InputHTMLAttributes {}
@@ -11,15 +11,15 @@ const Input = React.forwardRef(
- )
- }
-)
-Input.displayName = "Input"
+ );
+ },
+);
+Input.displayName = "Input";
-export { Input }
+export { Input };
diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx
index 79f0c67..10713ff 100644
--- a/src/components/ui/select.tsx
+++ b/src/components/ui/select.tsx
@@ -1,16 +1,16 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as SelectPrimitive from "@radix-ui/react-select"
-import { Check, ChevronDown, ChevronUp } from "lucide-react"
+import * as React from "react";
-import { cn } from "~/lib/utils"
+import * as SelectPrimitive from "@radix-ui/react-select";
+import { cn } from "~/lib/utils";
+import { Check, ChevronDown, ChevronUp } from "lucide-react";
-const Select = SelectPrimitive.Root
+const Select = SelectPrimitive.Root;
-const SelectGroup = SelectPrimitive.Group
+const SelectGroup = SelectPrimitive.Group;
-const SelectValue = SelectPrimitive.Value
+const SelectValue = SelectPrimitive.Value;
const SelectTrigger = React.forwardRef<
React.ElementRef,
@@ -20,7 +20,7 @@ const SelectTrigger = React.forwardRef<
ref={ref}
className={cn(
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
- className
+ className,
)}
{...props}
>
@@ -29,8 +29,8 @@ const SelectTrigger = React.forwardRef<
-))
-SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
+));
+SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
const SelectScrollUpButton = React.forwardRef<
React.ElementRef,
@@ -40,14 +40,14 @@ const SelectScrollUpButton = React.forwardRef<
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
- className
+ className,
)}
{...props}
>
-))
-SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
+));
+SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
const SelectScrollDownButton = React.forwardRef<
React.ElementRef,
@@ -57,15 +57,15 @@ const SelectScrollDownButton = React.forwardRef<
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
- className
+ className,
)}
{...props}
>
-))
+));
SelectScrollDownButton.displayName =
- SelectPrimitive.ScrollDownButton.displayName
+ SelectPrimitive.ScrollDownButton.displayName;
const SelectContent = React.forwardRef<
React.ElementRef,
@@ -78,7 +78,7 @@ const SelectContent = React.forwardRef<
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
- className
+ className,
)}
position={position}
{...props}
@@ -88,7 +88,7 @@ const SelectContent = React.forwardRef<
className={cn(
"p-1",
position === "popper" &&
- "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
+ "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
)}
>
{children}
@@ -96,8 +96,8 @@ const SelectContent = React.forwardRef<
-))
-SelectContent.displayName = SelectPrimitive.Content.displayName
+));
+SelectContent.displayName = SelectPrimitive.Content.displayName;
const SelectLabel = React.forwardRef<
React.ElementRef,
@@ -108,8 +108,8 @@ const SelectLabel = React.forwardRef<
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
{...props}
/>
-))
-SelectLabel.displayName = SelectPrimitive.Label.displayName
+));
+SelectLabel.displayName = SelectPrimitive.Label.displayName;
const SelectItem = React.forwardRef<
React.ElementRef,
@@ -119,7 +119,7 @@ const SelectItem = React.forwardRef<
ref={ref}
className={cn(
"relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
- className
+ className,
)}
{...props}
>
@@ -131,8 +131,8 @@ const SelectItem = React.forwardRef<
{children}
-))
-SelectItem.displayName = SelectPrimitive.Item.displayName
+));
+SelectItem.displayName = SelectPrimitive.Item.displayName;
const SelectSeparator = React.forwardRef<
React.ElementRef,
@@ -143,8 +143,8 @@ const SelectSeparator = React.forwardRef<
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
-))
-SelectSeparator.displayName = SelectPrimitive.Separator.displayName
+));
+SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
export {
Select,
@@ -157,4 +157,4 @@ export {
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
-}
+};
diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx
index 01abca9..e17e15d 100644
--- a/src/components/ui/sheet.tsx
+++ b/src/components/ui/sheet.tsx
@@ -1,19 +1,19 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as SheetPrimitive from "@radix-ui/react-dialog"
-import { cva, type VariantProps } from "class-variance-authority"
-import { X } from "lucide-react"
+import * as React from "react";
-import { cn } from "~/lib/utils"
+import * as SheetPrimitive from "@radix-ui/react-dialog";
+import { cn } from "~/lib/utils";
+import { cva, type VariantProps } from "class-variance-authority";
+import { X } from "lucide-react";
-const Sheet = SheetPrimitive.Root
+const Sheet = SheetPrimitive.Root;
-const SheetTrigger = SheetPrimitive.Trigger
+const SheetTrigger = SheetPrimitive.Trigger;
-const SheetClose = SheetPrimitive.Close
+const SheetClose = SheetPrimitive.Close;
-const SheetPortal = SheetPrimitive.Portal
+const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef,
@@ -22,13 +22,13 @@ const SheetOverlay = React.forwardRef<
-))
-SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
+));
+SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
@@ -46,8 +46,8 @@ const sheetVariants = cva(
defaultVariants: {
side: "right",
},
- }
-)
+ },
+);
interface SheetContentProps
extends React.ComponentPropsWithoutRef,
@@ -65,14 +65,14 @@ const SheetContent = React.forwardRef<
{...props}
>
{children}
-
+
Close
-))
-SheetContent.displayName = SheetPrimitive.Content.displayName
+));
+SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
@@ -81,12 +81,12 @@ const SheetHeader = ({
-)
-SheetHeader.displayName = "SheetHeader"
+);
+SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
@@ -95,12 +95,12 @@ const SheetFooter = ({
-)
-SheetFooter.displayName = "SheetFooter"
+);
+SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef,
@@ -111,8 +111,8 @@ const SheetTitle = React.forwardRef<
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
-))
-SheetTitle.displayName = SheetPrimitive.Title.displayName
+));
+SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef,
@@ -123,8 +123,8 @@ const SheetDescription = React.forwardRef<
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
-))
-SheetDescription.displayName = SheetPrimitive.Description.displayName
+));
+SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
@@ -137,4 +137,4 @@ export {
SheetFooter,
SheetTitle,
SheetDescription,
-}
+};
diff --git a/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx
index 452f4d9..549cf84 100644
--- a/src/components/ui/sonner.tsx
+++ b/src/components/ui/sonner.tsx
@@ -1,12 +1,12 @@
-"use client"
+"use client";
-import { useTheme } from "next-themes"
-import { Toaster as Sonner } from "sonner"
+import { useTheme } from "next-themes";
+import { Toaster as Sonner } from "sonner";
-type ToasterProps = React.ComponentProps
+type ToasterProps = React.ComponentProps;
const Toaster = ({ ...props }: ToasterProps) => {
- const { theme = "system" } = useTheme()
+ const { theme = "system" } = useTheme();
return (
{
}}
{...props}
/>
- )
-}
+ );
+};
-export { Toaster }
+export { Toaster };
diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx
index 022d8b2..eef28ef 100644
--- a/src/components/ui/tabs.tsx
+++ b/src/components/ui/tabs.tsx
@@ -1,11 +1,11 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as TabsPrimitive from "@radix-ui/react-tabs"
+import * as React from "react";
-import { cn } from "~/lib/utils"
+import * as TabsPrimitive from "@radix-ui/react-tabs";
+import { cn } from "~/lib/utils";
-const Tabs = TabsPrimitive.Root
+const Tabs = TabsPrimitive.Root;
const TabsList = React.forwardRef<
React.ElementRef,
@@ -15,12 +15,12 @@ const TabsList = React.forwardRef<
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
- className
+ className,
)}
{...props}
/>
-))
-TabsList.displayName = TabsPrimitive.List.displayName
+));
+TabsList.displayName = TabsPrimitive.List.displayName;
const TabsTrigger = React.forwardRef<
React.ElementRef,
@@ -30,12 +30,12 @@ const TabsTrigger = React.forwardRef<
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
- className
+ className,
)}
{...props}
/>
-))
-TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
+));
+TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
const TabsContent = React.forwardRef<
React.ElementRef,
@@ -45,11 +45,11 @@ const TabsContent = React.forwardRef<
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
- className
+ className,
)}
{...props}
/>
-))
-TabsContent.displayName = TabsPrimitive.Content.displayName
+));
+TabsContent.displayName = TabsPrimitive.Content.displayName;
-export { Tabs, TabsList, TabsTrigger, TabsContent }
+export { Tabs, TabsList, TabsTrigger, TabsContent };
diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx
index 558a483..6478293 100644
--- a/src/components/ui/textarea.tsx
+++ b/src/components/ui/textarea.tsx
@@ -1,6 +1,6 @@
-import * as React from "react"
+import * as React from "react";
-import { cn } from "~/lib/utils"
+import { cn } from "~/lib/utils";
export interface TextareaProps
extends React.TextareaHTMLAttributes {}
@@ -10,15 +10,15 @@ const Textarea = React.forwardRef(
return (
- )
- }
-)
-Textarea.displayName = "Textarea"
+ );
+ },
+);
+Textarea.displayName = "Textarea";
-export { Textarea }
+export { Textarea };
diff --git a/src/components/ui/toast.tsx b/src/components/ui/toast.tsx
index 7d9766a..600a671 100644
--- a/src/components/ui/toast.tsx
+++ b/src/components/ui/toast.tsx
@@ -1,11 +1,11 @@
-import * as React from "react"
-import * as ToastPrimitives from "@radix-ui/react-toast"
-import { cva, type VariantProps } from "class-variance-authority"
-import { X } from "lucide-react"
+import * as React from "react";
-import { cn } from "~/lib/utils"
+import * as ToastPrimitives from "@radix-ui/react-toast";
+import { cn } from "~/lib/utils";
+import { cva, type VariantProps } from "class-variance-authority";
+import { X } from "lucide-react";
-const ToastProvider = ToastPrimitives.Provider
+const ToastProvider = ToastPrimitives.Provider;
const ToastViewport = React.forwardRef<
React.ElementRef,
@@ -15,12 +15,12 @@ const ToastViewport = React.forwardRef<
ref={ref}
className={cn(
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
- className
+ className,
)}
{...props}
/>
-))
-ToastViewport.displayName = ToastPrimitives.Viewport.displayName
+));
+ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
const toastVariants = cva(
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
@@ -35,8 +35,8 @@ const toastVariants = cva(
defaultVariants: {
variant: "default",
},
- }
-)
+ },
+);
const Toast = React.forwardRef<
React.ElementRef,
@@ -49,9 +49,9 @@ const Toast = React.forwardRef<
className={cn(toastVariants({ variant }), className)}
{...props}
/>
- )
-})
-Toast.displayName = ToastPrimitives.Root.displayName
+ );
+});
+Toast.displayName = ToastPrimitives.Root.displayName;
const ToastAction = React.forwardRef<
React.ElementRef,
@@ -60,13 +60,13 @@ const ToastAction = React.forwardRef<
-))
-ToastAction.displayName = ToastPrimitives.Action.displayName
+));
+ToastAction.displayName = ToastPrimitives.Action.displayName;
const ToastClose = React.forwardRef<
React.ElementRef,
@@ -76,15 +76,15 @@ const ToastClose = React.forwardRef<
ref={ref}
className={cn(
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
- className
+ className,
)}
toast-close=""
{...props}
>
-))
-ToastClose.displayName = ToastPrimitives.Close.displayName
+));
+ToastClose.displayName = ToastPrimitives.Close.displayName;
const ToastTitle = React.forwardRef<
React.ElementRef,
@@ -95,8 +95,8 @@ const ToastTitle = React.forwardRef<
className={cn("text-sm font-semibold", className)}
{...props}
/>
-))
-ToastTitle.displayName = ToastPrimitives.Title.displayName
+));
+ToastTitle.displayName = ToastPrimitives.Title.displayName;
const ToastDescription = React.forwardRef<
React.ElementRef,
@@ -107,12 +107,12 @@ const ToastDescription = React.forwardRef<
className={cn("text-sm opacity-90", className)}
{...props}
/>
-))
-ToastDescription.displayName = ToastPrimitives.Description.displayName
+));
+ToastDescription.displayName = ToastPrimitives.Description.displayName;
-type ToastProps = React.ComponentPropsWithoutRef
+type ToastProps = React.ComponentPropsWithoutRef;
-type ToastActionElement = React.ReactElement
+type ToastActionElement = React.ReactElement;
export {
type ToastProps,
@@ -124,4 +124,4 @@ export {
ToastDescription,
ToastClose,
ToastAction,
-}
+};
diff --git a/src/server/index.ts b/src/server/index.ts
index d1cb01e..0301fae 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -20,4 +20,33 @@ const validateGithub = async (npub: string, github: string, gist: string) => {
}
};
-export { revalidateCachedTag, validateGithub };
+const getBitcoinPrice = async () => {
+ try {
+ const response = await fetch(
+ "https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest?id=1",
+ {
+ headers: {
+ "X-CMC_PRO_API_KEY": `${process.env.CMC_API_KEY}`,
+ },
+ },
+ );
+
+ const json = (await response.json()) as {
+ data: {
+ "1": {
+ quote: {
+ USD: {
+ price: number;
+ };
+ };
+ };
+ };
+ };
+
+ return json.data["1"].quote.USD.price;
+ } catch (_) {
+ return _;
+ }
+};
+
+export { revalidateCachedTag, validateGithub, getBitcoinPrice };
diff --git a/src/store/price-store.ts b/src/store/price-store.ts
new file mode 100644
index 0000000..6d503ef
--- /dev/null
+++ b/src/store/price-store.ts
@@ -0,0 +1,22 @@
+import { create } from "zustand";
+import { createJSONStorage, devtools, persist } from "zustand/middleware";
+
+type PriceState = {
+ price: number | null;
+ setPrice: (price: number | null) => void;
+};
+
+export const usePriceStore = create()(
+ devtools(
+ persist(
+ (set, _) => ({
+ price: null,
+ setPrice: (price) => set({ price }),
+ }),
+ {
+ name: "fundsolvr-price-storage",
+ storage: createJSONStorage(() => sessionStorage),
+ },
+ ),
+ ),
+);
diff --git a/src/styles/globals.css b/src/styles/globals.css
index e7799dc..e4a0ad7 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -10,10 +10,14 @@
--card-foreground: 224 72% 5% /* gray-950 */;
--popover: 0 0% 100% /* white */;
--popover-foreground: 224 72% 5% /* gray-950 */;
- --primary: 244 76% 59% /* indigo-600 */;
- --primary-foreground: 226 100% 97% /* indigo-50 */;
- --secondary: 220 15% 96% /* gray-100 */;
- --secondary-foreground: 221 40% 11% /* gray-900 */;
+ --primary: 244 76% 59% /* #5247E6 */;
+ --primary-foreground: 228 100% 97% /* #F0F3FF */;
+ --primary-hover: 244 66% 48% /* 352ACD */;
+ --primary-foreground-hover: 0 0% 100% /* #FFFFFF */;
+ --secondary: 227 69% 5% /* #040816 */;
+ --secondary-foreground: 240 20% 99% /* #FCFCFD */;
+ --secondary-hover: 215 28% 17% /* #1F2937 */;
+ --secondary-foreground-hover: 240 20% 99% /* #FCFCFD */;
--muted: 220 15% 96% /* gray-100 */;
--muted-foreground: 220 9% 47% /* gray-500 */;
--accent: 220 15% 96% /* gray-100 */;
@@ -25,7 +29,8 @@
--outline: 220 14% 91% /* gray-200 */;
--ring: 244 76% 59% /* indigo-600 */;
--radius: 0.5rem;
-
+ --bitcoin: 27 96% 61% /* #FB923C */;
+ --bitcoin-background: 27.47, 95.4%, 82.94%, 0.15;
--nc-background: #ffffff;
--nc-container-font-family: arial;
--nc-container-font-size: 1.2em;
@@ -47,26 +52,32 @@
}
.dark {
- --background: 224 72% 5% /* gray-950 */;
+ --background: 227 69% 5% /* #040816 */;
--foreground: 210 20% 99% /* gray-50 */;
--card: 224 72% 5% /* gray-950 */;
--card-foreground: 210 20% 99% /* gray-50 */;
--popover: 224 72% 5% /* gray-950 */;
--popover-foreground: 210 20% 99% /* gray-50 */;
- --primary: 244 76% 59% /* indigo-600 */;
- --primary-foreground: 226 100% 97% /* indigo-50 */;
- --secondary: 215 28% 17% /* gray-800 */;
- --secondary-foreground: 210 20% 99% /* gray-50 */;
- --muted: 215 28% 17% /* gray-800 */;
+ --primary: 244 76% 59% /* #5247E6 */;
+ --primary-foreground: 228 100% 97% /* #F0F3FF */;
+ --primary-hover: 244 66% 48% /* 352ACD */;
+ --primary-foreground-hover: 0 0% 100% /* #FFFFFF */;
+ --secondary: 227 69% 5% /* #040816 */;
+ --secondary-foreground: 240 20% 99% /* #FCFCFD */;
+ --secondary-hover: 215 28% 17% /* #1F2937 */;
+ --secondary-foreground-hover: 240 20% 99% /* #FCFCFD */;
+ --muted: 214 40% 11% /* #111B28 */;
--muted-foreground: 218 11% 65% /* gray-400 */;
--accent: 215 28% 17% /* gray-800 */;
--accent-foreground: 210 20% 99% /* gray-50 */;
--destructive: 0 63% 31% /* red-900 */;
--destructive-foreground: 210 20% 99% /* gray-50 */;
- --border: 215 28% 17% /* gray-800 */;
+ --border: 215 28% 17% /* #1F2937 */;
--outline: 216.9 19.1% 26.7% /* gray-700 */;
--input: 215 28% 17% /* gray-800 */;
--ring: 244 76% 59% /* indigo-600 */;
+ --bitcoin: 27 96% 61% /* #FB923C */;
+ --bitcoin-background: 27.47, 95.4%, 82.94%, 0.15;
--nc-background: #040816;
--nc-container-font-family: arial;
@@ -83,7 +94,7 @@
--nc-textarea-font-family: inherit;
--nc-textarea-font-size: inherit;
--nc-text-background: #111827;
- --nc-hover-background: #333c4c;
+ --nc-hover-background: #333c4c;
--nc-text-color: #d1d5db;
--nc-text-color-dark: #9ca3af;
--nc-primary-color: #374151;
@@ -91,6 +102,10 @@
}
}
@layer base {
+ html {
+ margin-left: calc(100vw - 100%);
+ margin-right: 0;
+ }
* {
@apply border-border;
}
diff --git a/tailwind.config.ts b/tailwind.config.ts
index 9767124..5d25f24 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -11,6 +11,15 @@ module.exports = {
},
},
extend: {
+ fontSize: {
+ md: [
+ "0.9375rem",
+ {
+ lineHeight: "24px",
+ letterSpacing: "-0.45px",
+ },
+ ],
+ },
fontFamily: {
sans: ["var(--font-geist-sans)"],
mono: ["var(--font-geist-mono)"],
@@ -22,13 +31,21 @@ module.exports = {
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
+ bitcoin: {
+ DEFAULT: "hsl(var(--bitcoin))",
+ background: "hsla(var(--bitcoin-background))",
+ },
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
+ hover: "hsl(var(--primary-hover))",
+ "foreground-hover": "hsl(var(--primary-foreground-hover))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
+ hover: "hsl(var(--secondary-hover))",
+ "foreground-hover": "hsl(var(--secondary-foreground-hover))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",