diff --git a/scripts/efp-lookup.ts b/scripts/efp-lookup.ts deleted file mode 100755 index 08013ba2..00000000 --- a/scripts/efp-lookup.ts +++ /dev/null @@ -1,377 +0,0 @@ -#!/usr/bin/env bun -import { createPublicClient, http, type Address } from "viem"; -import { base } from "viem/chains"; -import { EFP_CONTRACTS } from "../src/lib/efp/config"; -import { efpAccountMetadataAbi, efpListRegistryAbi, efpListRecordsAbi } from "../src/lib/efp/abi"; -import { decodeListOp } from "../src/lib/efp/operations"; - -const client = createPublicClient({ - chain: base, - transport: http("https://mainnet.base.org"), -}); - -// Parse command line arguments -const args = process.argv.slice(2); -if (args.length === 0) { - console.log("EFP Lookup Tool"); - console.log("==============="); - console.log("\nUsage:"); - console.log(" bun scripts/efp-lookup.ts [options]"); - console.log("\nCommands:"); - console.log(" user
- Get user's primary list and metadata"); - console.log(" list - Get list details and storage location"); - console.log(" following - Show all addresses followed by a list"); - console.log(" follows
- Check if list follows an address"); - console.log(" storage - Decode storage location for a list"); - console.log(" operations - Show all operations for a list"); - console.log("\nExamples:"); - console.log(" bun scripts/efp-lookup.ts user 0x82ad2f310831d6d7d1f95B08c96EF0771cdC94B2"); - console.log(" bun scripts/efp-lookup.ts list 43802"); - console.log(" bun scripts/efp-lookup.ts following 43802"); - console.log(" bun scripts/efp-lookup.ts follows 43802 0x860bd5121068724e600c719380b87e093ff3bdb8"); - console.log(" bun scripts/efp-lookup.ts operations 43802"); - process.exit(0); -} - -const command = args[0]; - -async function getUserData(address: Address) { - console.log(`\nFetching EFP data for user: ${address}`); - console.log("=".repeat(60)); - - try { - // Get primary list - const primaryList = await client.readContract({ - address: EFP_CONTRACTS.EFPAccountMetadata, - abi: efpAccountMetadataAbi, - functionName: "getValue", - args: [address, "primary-list"], - }); - - if (primaryList === "0x") { - console.log("❌ No primary list set for this user"); - return; - } - - const listId = BigInt(primaryList); - console.log(`✓ Primary List ID: ${listId}`); - - // Get storage location first to get the slot - const storageLocation = await getStorageLocation(listId.toString()); - - // Get list metadata from ListRecords contract using the slot - const manager = await client.readContract({ - address: storageLocation.contractAddress, - abi: efpListRecordsAbi, - functionName: "getListManager", - args: [storageLocation.slot], - }); - - const user = await client.readContract({ - address: storageLocation.contractAddress, - abi: efpListRecordsAbi, - functionName: "getListUser", - args: [storageLocation.slot], - }); - - console.log(`✓ List Manager: ${manager}`); - console.log(`✓ List User: ${user}`); - } catch (error) { - console.error("Error:", error); - } -} - -async function getStorageLocation(listId: string, verbose = false) { - const listIdBigInt = BigInt(listId); - - const storageLocationHex = await client.readContract({ - address: EFP_CONTRACTS.EFPListRegistry, - abi: efpListRegistryAbi, - functionName: "getListStorageLocation", - args: [listIdBigInt], - }); - - const bytes = Buffer.from(storageLocationHex.slice(2), "hex"); - - const version = bytes[0]; - const listType = bytes[1]; - const chainId = BigInt("0x" + bytes.subarray(2, 34).toString("hex")); - const contractAddress = ("0x" + bytes.subarray(34, 54).toString("hex")) as Address; - const slot = BigInt("0x" + bytes.subarray(54, 86).toString("hex")); - - console.log("\nStorage Location:"); - console.log(` Raw: ${storageLocationHex}`); - console.log(` Version: ${version}`); - console.log(` List Type: ${listType} (${listType === 1 ? "onchain" : "unknown"})`); - console.log(` Chain ID: ${chainId} (${chainId === 8453n ? "Base" : "Unknown"})`); - console.log(` Contract: ${contractAddress}`); - console.log(` Slot: ${slot}`); - console.log(` Slot (hex): 0x${slot.toString(16)}`); - - if (verbose) { - console.log("\nDecoded bytes:"); - console.log(` Version (1 byte): 0x${bytes.subarray(0, 1).toString("hex")}`); - console.log(` Type (1 byte): 0x${bytes.subarray(1, 2).toString("hex")}`); - console.log(` Chain ID (32 bytes): 0x${bytes.subarray(2, 34).toString("hex")}`); - console.log(` Contract (20 bytes): 0x${bytes.subarray(34, 54).toString("hex")}`); - console.log(` Slot (32 bytes): 0x${bytes.subarray(54, 86).toString("hex")}`); - } - - return { contractAddress, slot }; -} - -async function getListDetails(listId: string) { - console.log(`\nFetching details for List ID: ${listId}`); - console.log("=".repeat(60)); - - try { - // Get storage location first - const storage = await getStorageLocation(listId); - - // Get list metadata from ListRecords contract using the slot - const manager = await client.readContract({ - address: storage.contractAddress, - abi: efpListRecordsAbi, - functionName: "getListManager", - args: [storage.slot], - }); - - const user = await client.readContract({ - address: storage.contractAddress, - abi: efpListRecordsAbi, - functionName: "getListUser", - args: [storage.slot], - }); - - console.log(`✓ Manager: ${manager}`); - console.log(`✓ User: ${user}`); - - // Get list operations count - const listOps = await client.readContract({ - address: storage.contractAddress, - abi: efpListRecordsAbi, - functionName: "getAllListOps", - args: [storage.slot], - }); - - console.log(`\n✓ Total Operations: ${listOps.length}`); - - // Count follows - const addresses = new Set(); - for (const opData of listOps) { - const decoded = decodeListOp(opData); - if (!decoded) continue; - - if (decoded.opcode === 0x01) { - addresses.add(decoded.record.address.toLowerCase()); - } else if (decoded.opcode === 0x02) { - addresses.delete(decoded.record.address.toLowerCase()); - } - } - - console.log(`✓ Currently Following: ${addresses.size} addresses`); - } catch (error) { - console.error("Error:", error); - } -} - -async function getFollowing(listId: string) { - console.log(`\nFetching addresses followed by List ID: ${listId}`); - console.log("=".repeat(60)); - - try { - const storage = await getStorageLocation(listId); - - const listOps = await client.readContract({ - address: storage.contractAddress, - abi: efpListRecordsAbi, - functionName: "getAllListOps", - args: [storage.slot], - }); - - const followMap = new Map(); - - for (const opData of listOps) { - const decoded = decodeListOp(opData); - if (!decoded) continue; - - const addr = decoded.record.address.toLowerCase(); - if (decoded.opcode === 0x01) { - followMap.set(addr, true); - } else if (decoded.opcode === 0x02) { - followMap.set(addr, false); - } - } - - const following = Array.from(followMap.entries()) - .filter(([_, isFollowing]) => isFollowing) - .map(([addr]) => addr); - - console.log(`\nCurrently following ${following.length} addresses:`); - following.forEach((addr, i) => { - console.log(`${i + 1}. ${addr}`); - }); - } catch (error) { - console.error("Error:", error); - } -} - -async function checkFollows(listId: string, targetAddress: Address) { - console.log(`\nChecking if List ${listId} follows ${targetAddress}`); - console.log("=".repeat(60)); - - try { - const storage = await getStorageLocation(listId); - - const listOps = await client.readContract({ - address: storage.contractAddress, - abi: efpListRecordsAbi, - functionName: "getAllListOps", - args: [storage.slot], - }); - - let isFollowing = false; - const target = targetAddress.toLowerCase(); - - for (const opData of listOps) { - const decoded = decodeListOp(opData); - if (!decoded) continue; - - if (decoded.record.address.toLowerCase() === target) { - if (decoded.opcode === 0x01) { - isFollowing = true; - console.log(`✓ ADD operation found`); - } else if (decoded.opcode === 0x02) { - isFollowing = false; - console.log(`✓ REMOVE operation found`); - } - } - } - - console.log(`\nResult: ${isFollowing ? "✅ FOLLOWING" : "❌ NOT FOLLOWING"}`); - } catch (error) { - console.error("Error:", error); - } -} - -async function showOperations(listId: string) { - console.log(`\nFetching all operations for List ID: ${listId}`); - console.log("=".repeat(60)); - - try { - const storage = await getStorageLocation(listId, true); // verbose storage info - - const listOps = await client.readContract({ - address: storage.contractAddress, - abi: efpListRecordsAbi, - functionName: "getAllListOps", - args: [storage.slot], - }); - - console.log(`\nTotal Operations: ${listOps.length}`); - console.log("-".repeat(60)); - - listOps.forEach((opData, index) => { - console.log(`\nOperation ${index + 1}:`); - console.log(` Raw: ${opData}`); - - const decoded = decodeListOp(opData); - if (decoded) { - console.log(` Version: ${decoded.version}`); - console.log(` Opcode: 0x${decoded.opcode.toString(16).padStart(2, '0')} (${decoded.opcode === 0x01 ? "ADD" : decoded.opcode === 0x02 ? "REMOVE" : "UNKNOWN"})`); - console.log(` Record Version: ${decoded.record.version}`); - console.log(` Record Type: ${decoded.record.recordType} (${decoded.record.recordType === 1 ? "address" : decoded.record.recordType === 2 ? "list" : "unknown"})`); - console.log(` Address: ${decoded.record.address}`); - - // Show the decoded bytes - const bytes = Buffer.from(opData.slice(2), "hex"); - console.log(` Decoded bytes:`); - console.log(` Version: 0x${bytes.subarray(0, 1).toString("hex")}`); - console.log(` Opcode: 0x${bytes.subarray(1, 2).toString("hex")}`); - console.log(` Record data: 0x${bytes.subarray(2).toString("hex")}`); - } else { - console.log(` Failed to decode operation`); - } - }); - - // Show current state summary - console.log("\n" + "=".repeat(60)); - console.log("Current State Summary:"); - - const followMap = new Map(); - for (const opData of listOps) { - const decoded = decodeListOp(opData); - if (!decoded) continue; - - const addr = decoded.record.address.toLowerCase(); - if (decoded.opcode === 0x01) { - followMap.set(addr, true); - } else if (decoded.opcode === 0x02) { - followMap.set(addr, false); - } - } - - const following = Array.from(followMap.entries()) - .filter(([_, isFollowing]) => isFollowing); - - console.log(`Currently following ${following.length} addresses`); - } catch (error) { - console.error("Error:", error); - } -} - -// Execute command -switch (command) { - case "user": - if (!args[1]) { - console.error("Error: Please provide a user address"); - process.exit(1); - } - await getUserData(args[1] as Address); - break; - - case "list": - if (!args[1]) { - console.error("Error: Please provide a list ID"); - process.exit(1); - } - await getListDetails(args[1]); - break; - - case "following": - if (!args[1]) { - console.error("Error: Please provide a list ID"); - process.exit(1); - } - await getFollowing(args[1]); - break; - - case "follows": - if (!args[1] || !args[2]) { - console.error("Error: Please provide both list ID and target address"); - process.exit(1); - } - await checkFollows(args[1], args[2] as Address); - break; - - case "storage": - if (!args[1]) { - console.error("Error: Please provide a list ID"); - process.exit(1); - } - await getStorageLocation(args[1], true); // verbose mode for storage command - break; - - case "operations": - if (!args[1]) { - console.error("Error: Please provide a list ID"); - process.exit(1); - } - await showOperations(args[1]); - break; - - default: - console.error(`Unknown command: ${command}`); - console.log("Run without arguments to see usage"); - process.exit(1); -} \ No newline at end of file diff --git a/src/atoms/backgroundTheme.ts b/src/atoms/backgroundTheme.ts deleted file mode 100644 index 1cfeeec2..00000000 --- a/src/atoms/backgroundTheme.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { atom } from "jotai"; -import { atomWithStorage } from "jotai/utils"; -import type { BackgroundMode } from "~/hooks/useBackgroundTheme"; -import type { PhotoCredits } from "~/utils/unsplash"; - -const STORAGE_KEY = "leading-color"; -const MODE_KEY = "background-mode"; -const IMAGE_KEY = "background-image"; -const CREDITS_KEY = "background-image-credits"; -const INTENSITY_KEY = "background-intensity"; -const BLUR_KEY = "background-blur"; -const IMAGE_TYPE_KEY = "background-image-type"; - -export const backgroundColorIdAtom = atomWithStorage(STORAGE_KEY, "default"); -export const backgroundModeAtom = atomWithStorage(MODE_KEY, "none"); -export const backgroundImageUrlAtom = atomWithStorage(IMAGE_KEY, ""); -export const imageCreditsAtom = atomWithStorage(CREDITS_KEY, null); -export const intensityAtom = atomWithStorage(INTENSITY_KEY, 0.5); -export const blurAtom = atomWithStorage(BLUR_KEY, 0); -export const imageTypeAtom = atomWithStorage<"unsplash" | "local">(IMAGE_TYPE_KEY, "unsplash"); - -export const imageLoadingAtom = atom(false); diff --git a/src/components/BackgroundGradient.tsx b/src/components/BackgroundGradient.tsx deleted file mode 100644 index bb33ffa4..00000000 --- a/src/components/BackgroundGradient.tsx +++ /dev/null @@ -1,95 +0,0 @@ -"use client"; - -import { useTheme } from "next-themes"; -import { useMemo } from "react"; -import { backgroundColors, useBackgroundTheme } from "~/hooks/useBackgroundTheme"; - -export function BackgroundGradient() { - const { backgroundMode, intensity, backgroundColorId, blur, backgroundImageUrl } = useBackgroundTheme(); - const { resolvedTheme } = useTheme(); - - const gradientPattern = useMemo(() => { - const color = backgroundColors.find((c) => c.id === backgroundColorId) || backgroundColors[0]; - const isDark = resolvedTheme === "dark"; - const baseOpacity = isDark ? 0.6 : 0.65; - const opacity = baseOpacity * intensity; - - const { r, g, b } = color.rgb; - - let color1: string; - let color2: string; - let color3: string; - - if (color.id === "default") { - if (isDark) { - color1 = `rgba(${r}, ${g}, ${b}, ${opacity * 0.5})`; - color2 = `rgba(${r + 20}, ${g + 20}, ${b + 20}, ${opacity * 0.6})`; - color3 = `rgba(${r - 20}, ${g - 20}, ${b - 20}, ${opacity * 0.4})`; - } else { - color1 = `rgba(${r}, ${g}, ${b}, ${opacity * 0.4})`; - color2 = `rgba(${r - 20}, ${g - 20}, ${b - 20}, ${opacity * 0.5})`; - color3 = `rgba(${r + 20}, ${g + 20}, ${b + 20}, ${opacity * 0.3})`; - } - } else if (color.id === "black_and_white") { - if (isDark) { - color1 = `rgba(255, 255, 255, ${opacity * 0.75})`; - color2 = `rgba(128, 128, 128, ${opacity})`; - color3 = `rgba(64, 64, 64, ${opacity})`; - } else { - color1 = `rgba(0, 0, 0, ${opacity * 0.75})`; - color2 = `rgba(128, 128, 128, ${opacity})`; - color3 = `rgba(192, 192, 192, ${opacity})`; - } - } else { - const clamp = (val: number) => Math.min(Math.max(val, 0), 255); - const shift = 30; - color1 = `rgba(${r}, ${g}, ${b}, ${opacity * 0.75})`; - color2 = `rgba(${clamp(r + shift)}, ${clamp(g - shift / 2)}, ${clamp(b + shift / 2)}, ${opacity})`; - color3 = `rgba(${clamp(r - shift / 2)}, ${clamp(g + shift / 2)}, ${clamp(b - shift)}, ${opacity})`; - } - - return `radial-gradient(ellipse at top, ${color1} 0%, transparent 70%), radial-gradient(ellipse at bottom right, ${color2} 0%, transparent 70%), radial-gradient(ellipse at center left, ${color3} 0%, transparent 70%)`; - }, [backgroundColorId, resolvedTheme, intensity]); - - return ( -
- {backgroundMode === "none" && ( -
{ - const color = backgroundColors.find((c) => c.id === backgroundColorId); - const r = color?.rgb.r || 148; - const g = color?.rgb.g || 158; - const b = color?.rgb.b || 158; - return `rgb(${r}, ${g}, ${b})`; - })(), - opacity: intensity * 0.3, - }} - /> - )} - {backgroundMode === "gradient" && ( -
- )} - {backgroundMode === "image" && backgroundImageUrl && ( -
- )} -
- ); -} diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/src/components/Transitions.tsx b/src/components/Transitions.tsx deleted file mode 100644 index 9514e593..00000000 --- a/src/components/Transitions.tsx +++ /dev/null @@ -1,32 +0,0 @@ -"use client"; - -import { type PropsWithChildren, useRef } from "react"; -import { useInViewport } from "react-in-viewport"; - -export const FadeIn = ({ - children, - oneShot = true, - className, -}: PropsWithChildren & { oneShot?: boolean; className?: string }) => { - const myRef = useRef(); - let fired = false; - - const { inViewport, enterCount, leaveCount } = useInViewport( - myRef, - { rootMargin: "0px", threshold: 0.5, root: null }, - { disconnectOnLeave: true }, - {}, - ); - - if (oneShot && enterCount > 0) { - fired = true; - } - - const viewportStyle = inViewport || fired ? "opacity-100" : "opacity-0"; - - return ( -
- {children} -
- ); -}; diff --git a/src/components/TrendingCommunitiesPage.tsx b/src/components/TrendingCommunitiesPage.tsx deleted file mode 100644 index 940c00d1..00000000 --- a/src/components/TrendingCommunitiesPage.tsx +++ /dev/null @@ -1,34 +0,0 @@ -"use client"; - -import type { Group } from "@cartel-sh/ui"; -import { ArrowLeft } from "lucide-react"; -import { CommunityView } from "~/components/communities/CommunityView"; -import { Feed } from "~/components/Feed"; -import Link from "~/components/Link"; - -const CommunityViewWrapper = ({ item }: { item: Group }) => { - return ; -}; - -export default function TrendingCommunitiesPage() { - return ( -
-
- - - Back - -

Trending Communities

-
- - - ItemView={CommunityViewWrapper} - endpoint="/api/communities/trending" - queryKey={["trending-communities"]} - /> -
- ); -} diff --git a/src/components/communities/Community.tsx b/src/components/communities/Community.tsx deleted file mode 100644 index a59c6bbb..00000000 --- a/src/components/communities/Community.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { - AtSignIcon, - Bitcoin, - CameraIcon, - CircleSlashIcon, - FrameIcon, - GlobeIcon, - HammerIcon, - KeyboardOffIcon, - LaughIcon, - LeafIcon, - LibraryIcon, - LineChartIcon, - MusicIcon, - PaletteIcon, - PartyPopperIcon, - SproutIcon, - TreeDeciduousIcon, - WrenchIcon, -} from "lucide-react"; - -export type Community = { - id: string; - name: string; - description?: string; - avatar?: string; -}; - -export const stringToCommunity = (community: string) => { - return { - id: community, - name: `/${community}`, - description: null, - image: null, - }; -}; - -export const getCommunityTags = (community: string) => { - if (community === "" || !community) return []; - - const prefixes = ["", "interest-", "community-", "orbcommunities", "channel-", "topic-"]; - const tags = prefixes.map((prefix) => `${prefix}${community}`); - - return tags; -}; - -export const getCommunityIcon = (community: string) => { - let icon = null; - switch (community) { - case "paper": - icon = ; - break; - case "lens": - icon = ; - break; - case "art": - icon = ; - break; - case "trading": - icon = ; - break; - case "raave": - icon = ; - break; - case "afk": - icon = ; - break; - case "touchgrass": - icon = ; - break; - case "photography": - icon = ; - break; - case "bonsai": - icon = ; - break; - case "defi": - icon = ; - break; - case "zk": - icon = ; - break; - case "lips": - icon = ; - break; - case "metaverse": - icon = ; - break; - case "design": - icon = ; - break; - case "music": - icon = ; - break; - case "memes": - icon = ; - break; - case "books": - icon = ; - break; - case "developers": - icon = ; - break; - case "build": - icon = ; - break; - default: - icon = null; - break; - } - return icon; -}; diff --git a/src/components/communities/CommunityHandle.tsx b/src/components/communities/CommunityHandle.tsx deleted file mode 100644 index 39d2e33d..00000000 --- a/src/components/communities/CommunityHandle.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import Link from "~/components/Link"; - -export const CommunityHandle = ({ handle }: { handle: string }) => { - return ( - - /{handle} - - ); -}; diff --git a/src/components/communities/TrendingCommunities.tsx b/src/components/communities/TrendingCommunities.tsx deleted file mode 100644 index fa1978fb..00000000 --- a/src/components/communities/TrendingCommunities.tsx +++ /dev/null @@ -1,74 +0,0 @@ -"use client"; - -import Link from "~/components/Link"; -import { useCommunity } from "~/hooks/useCommunity"; -import { Skeleton } from "../ui/skeleton"; -import { CommunityView } from "./CommunityView"; - -interface TrendingCommunitiesProps { - communityAddresses: string[]; - showAll?: boolean; -} - -function TrendingCommunityItem({ address, isVertical = true }: { address: string; isVertical?: boolean }) { - const { data: community, isLoading } = useCommunity(address); - - if (isLoading) { - return ( -
- -
- ); - } - - if (!community) { - return null; - } - - return ( -
- -
- ); -} - -export function TrendingCommunities({ communityAddresses, showAll = false }: TrendingCommunitiesProps) { - if (communityAddresses.length === 0) { - return null; - } - - const displayAddresses = showAll ? communityAddresses : communityAddresses.slice(0, 4); - - return ( -
-
-

Trending Communities

- {!showAll && communityAddresses.length > 4 && ( - - Show all - - )} -
- {showAll ? ( -
- {displayAddresses.map((address, index) => ( - - ))} -
- ) : ( -
-
- {displayAddresses.map((address, index) => ( - - ))} -
-
- {displayAddresses.slice(0, 3).map((address, index) => ( - - ))} -
-
- )} -
- ); -} diff --git a/src/components/menu/Search.tsx b/src/components/menu/Search.tsx deleted file mode 100644 index 594a402c..00000000 --- a/src/components/menu/Search.tsx +++ /dev/null @@ -1,69 +0,0 @@ -"use client"; - -import { zodResolver } from "@hookform/resolvers/zod"; -import { SearchIcon } from "lucide-react"; -import { usePathname, useRouter } from "next/navigation"; -import { useForm } from "react-hook-form"; -import * as z from "zod"; -import Link from "~/components/Link"; -import { Form, FormControl, FormField, FormItem } from "~/components/ui/form"; -import { Input } from "~/components/ui/input"; -import { Button } from "../ui/button"; - -export const SearchButton = () => { - const pathname = usePathname(); - - if (pathname !== "/search") { - return ( - - - - ); - } -}; - -export const SearchBar = ({ defaultText = "" }: { defaultText: string }) => { - const formSchema = z.object({ input: z.string() }); - const pathname = usePathname(); - const router = useRouter(); - - if (pathname === "/search" && defaultText === "") { - return; - } - - const form = useForm>({ - resolver: zodResolver(formSchema), - defaultValues: { - input: defaultText, - }, - }); - - const onSubmit = (values: z.infer) => { - if (!values) return; - router.push(`/search?q=${values.input}`); - }; - - return ( -
-
- - ( - - - - - - )} - /> - - - -
- ); -}; diff --git a/src/components/notifications/NotificationButton.tsx b/src/components/notifications/NotificationButton.tsx deleted file mode 100644 index 5bbc7c0d..00000000 --- a/src/components/notifications/NotificationButton.tsx +++ /dev/null @@ -1,31 +0,0 @@ -"use client"; - -import { BellIcon } from "lucide-react"; -import { usePathname } from "next/navigation"; -import Link from "~/components/Link"; -import { useNotifications } from "~/components/notifications/NotificationsContext"; -import { Button } from "~/components/ui/button"; - -export const NotificationButton = () => { - const { newCount, refresh } = useNotifications(); - const pathname = usePathname(); - - const handleClick = () => { - if (pathname === "/notifications") { - refresh(); - } - }; - - return ( - - - - ); -}; diff --git a/src/components/post/PostBadges.tsx b/src/components/post/PostBadges.tsx deleted file mode 100644 index 53957a03..00000000 --- a/src/components/post/PostBadges.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import type { Post } from "@cartel-sh/ui"; -import { Edit2Icon } from "lucide-react"; -import { Button } from "../ui/button"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip"; - -export function EditedIndicator({ post }: { post: Post }) { - const lastUpdated = post.updatedAt ? post.updatedAt.toLocaleString() : post.createdAt.toLocaleString(); - const tooltipText = `last updated at ${lastUpdated}`; - - if (post.createdAt.toUTCString() === post.updatedAt.toUTCString()) return null; - - return ( - - - - - - -

{tooltipText}

-
-
-
- ); -} diff --git a/src/components/post/PostCommentSkeleton.tsx b/src/components/post/PostCommentSkeleton.tsx deleted file mode 100644 index 4f4e5695..00000000 --- a/src/components/post/PostCommentSkeleton.tsx +++ /dev/null @@ -1,22 +0,0 @@ -export const CommentSkeleton = ({ isLastComment = false }: { isLastComment?: boolean }) => { - return ( -
-
- -
- -
-
-
-
-
- -
-
-
-
-
-
-
- ); -}; diff --git a/src/components/ui/bg-pattern.tsx b/src/components/ui/bg-pattern.tsx deleted file mode 100644 index 765fc6cf..00000000 --- a/src/components/ui/bg-pattern.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import React from "react"; -import { cn } from "@/src/utils"; - -type BGVariantType = "dots" | "diagonal-stripes" | "grid" | "horizontal-lines" | "vertical-lines" | "checkerboard"; -type BGMaskType = - | "fade-center" - | "fade-edges" - | "fade-edges-bottom" - | "fade-top" - | "fade-bottom" - | "fade-left" - | "fade-right" - | "fade-x" - | "fade-y" - | "none"; - -type BGPatternProps = React.ComponentProps<"div"> & { - variant?: BGVariantType; - mask?: BGMaskType; - size?: number; - fill?: string; -}; - -const maskClasses: Record = { - "fade-edges": "[mask-image:radial-gradient(ellipse_at_center,hsl(var(--background)),transparent)]", - "fade-edges-bottom": - "[mask-image:radial-gradient(ellipse_60%_100%_at_50%_0%,hsl(var(--background))_0%,hsl(var(--background))_30%,transparent_70%)]", - "fade-center": "[mask-image:radial-gradient(ellipse_at_center,transparent,hsl(var(--background)))]", - "fade-top": "[mask-image:linear-gradient(to_bottom,transparent,hsl(var(--background)))]", - "fade-bottom": "[mask-image:linear-gradient(to_bottom,hsl(var(--background)),transparent)]", - "fade-left": "[mask-image:linear-gradient(to_right,transparent,hsl(var(--background)))]", - "fade-right": "[mask-image:linear-gradient(to_right,hsl(var(--background)),transparent)]", - "fade-x": "[mask-image:linear-gradient(to_right,transparent,hsl(var(--background)),transparent)]", - "fade-y": "[mask-image:linear-gradient(to_bottom,transparent,hsl(var(--background)),transparent)]", - none: "", -}; - -function getBgImage(variant: BGVariantType, fill: string, size: number) { - // Convert theme color names to CSS custom properties - const colorValue = - fill.startsWith("#") || fill.startsWith("rgb") || fill.startsWith("hsl") ? fill : `hsl(var(--${fill}))`; - - switch (variant) { - case "dots": - return `radial-gradient(${colorValue} 1px, transparent 1px)`; - case "grid": - return `linear-gradient(to right, ${colorValue} 1px, transparent 1px), linear-gradient(to bottom, ${colorValue} 1px, transparent 1px)`; - case "diagonal-stripes": - return `repeating-linear-gradient(45deg, ${colorValue}, ${colorValue} 1px, transparent 1px, transparent ${size}px)`; - case "horizontal-lines": - return `linear-gradient(to bottom, ${colorValue} 1px, transparent 1px)`; - case "vertical-lines": - return `linear-gradient(to right, ${colorValue} 1px, transparent 1px)`; - case "checkerboard": - return `linear-gradient(45deg, ${colorValue} 25%, transparent 25%), linear-gradient(-45deg, ${colorValue} 25%, transparent 25%), linear-gradient(45deg, transparent 75%, ${colorValue} 75%), linear-gradient(-45deg, transparent 75%, ${colorValue} 75%)`; - default: - return undefined; - } -} - -const BGPattern = ({ - variant = "grid", - mask = "none", - size = 24, - fill = "#252525", - className, - style, - ...props -}: BGPatternProps) => { - const bgSize = `${size}px ${size}px`; - const backgroundImage = getBgImage(variant, fill, size); - - return ( -
- ); -}; - -BGPattern.displayName = "BGPattern"; -export { BGPattern }; diff --git a/src/components/ui/carousel.tsx b/src/components/ui/carousel.tsx deleted file mode 100644 index 1b4cd2f3..00000000 --- a/src/components/ui/carousel.tsx +++ /dev/null @@ -1,225 +0,0 @@ -"use client"; - -import useEmblaCarousel, { type UseEmblaCarouselType } from "embla-carousel-react"; -import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"; -import * as React from "react"; - -import { Button } from "@/src/components/ui/button"; -import { cn } from "@/src/utils"; - -type CarouselApi = UseEmblaCarouselType[1]; -type UseCarouselParameters = Parameters; -type CarouselOptions = UseCarouselParameters[0]; -type CarouselPlugin = UseCarouselParameters[1]; - -type CarouselProps = { - opts?: CarouselOptions; - plugins?: CarouselPlugin; - orientation?: "horizontal" | "vertical"; - setApi?: (api: CarouselApi) => void; -}; - -type CarouselContextProps = { - carouselRef: ReturnType[0]; - api: ReturnType[1]; - scrollPrev: () => void; - scrollNext: () => void; - canScrollPrev: boolean; - canScrollNext: boolean; -} & CarouselProps; - -const CarouselContext = React.createContext(null); - -function useCarousel() { - const context = React.useContext(CarouselContext); - - if (!context) { - throw new Error("useCarousel must be used within a "); - } - - return context; -} - -const Carousel = React.forwardRef & CarouselProps>( - ({ orientation = "horizontal", opts, setApi, plugins, className, children, ...props }, ref) => { - const [carouselRef, api] = useEmblaCarousel( - { - ...opts, - axis: orientation === "horizontal" ? "x" : "y", - }, - plugins, - ); - const [canScrollPrev, setCanScrollPrev] = React.useState(false); - const [canScrollNext, setCanScrollNext] = React.useState(false); - - const onSelect = React.useCallback((api: CarouselApi) => { - if (!api) { - return; - } - - setCanScrollPrev(api.canScrollPrev()); - setCanScrollNext(api.canScrollNext()); - }, []); - - const scrollPrev = React.useCallback(() => { - api?.scrollPrev(); - }, [api]); - - const scrollNext = React.useCallback(() => { - api?.scrollNext(); - }, [api]); - - const handleKeyDown = React.useCallback( - (event: React.KeyboardEvent) => { - if (event.key === "ArrowLeft") { - event.preventDefault(); - scrollPrev(); - } else if (event.key === "ArrowRight") { - event.preventDefault(); - scrollNext(); - } - }, - [scrollPrev, scrollNext], - ); - - React.useEffect(() => { - if (!api || !setApi) { - return; - } - - setApi(api); - }, [api, setApi]); - - React.useEffect(() => { - if (!api) { - return; - } - - onSelect(api); - api.on("reInit", onSelect); - api.on("select", onSelect); - - return () => { - api?.off("select", onSelect); - }; - }, [api, onSelect]); - - return ( - -
- {children} -
-
- ); - }, -); -Carousel.displayName = "Carousel"; - -const CarouselContent = React.forwardRef>( - ({ className, ...props }, ref) => { - const { carouselRef, orientation } = useCarousel(); - - return ( -
-
-
- ); - }, -); -CarouselContent.displayName = "CarouselContent"; - -const CarouselItem = React.forwardRef>( - ({ className, ...props }, ref) => { - const { orientation } = useCarousel(); - - return ( -
- ); - }, -); -CarouselItem.displayName = "CarouselItem"; - -const CarouselPrevious = React.forwardRef>( - ({ className, variant = "outline", size = "icon", ...props }, ref) => { - const { orientation, scrollPrev, canScrollPrev } = useCarousel(); - - return ( - - ); - }, -); -CarouselPrevious.displayName = "CarouselPrevious"; - -const CarouselNext = React.forwardRef>( - ({ className, variant = "outline", size = "icon", ...props }, ref) => { - const { orientation, scrollNext, canScrollNext } = useCarousel(); - - return ( - - ); - }, -); -CarouselNext.displayName = "CarouselNext"; - -export { type CarouselApi, Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext }; diff --git a/src/components/ui/radio-group.tsx b/src/components/ui/radio-group.tsx deleted file mode 100644 index 917055e2..00000000 --- a/src/components/ui/radio-group.tsx +++ /dev/null @@ -1,38 +0,0 @@ -"use client"; - -import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"; -import { Circle } from "lucide-react"; -import * as React from "react"; - -import { cn } from "@/src/utils"; - -const RadioGroup = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => { - return ; -}); -RadioGroup.displayName = RadioGroupPrimitive.Root.displayName; - -const RadioGroupItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => { - return ( - - - - - - ); -}); -RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName; - -export { RadioGroup, RadioGroupItem }; diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx deleted file mode 100644 index 6aaea6df..00000000 --- a/src/components/ui/select.tsx +++ /dev/null @@ -1,145 +0,0 @@ -"use client"; - -import * as SelectPrimitive from "@radix-ui/react-select"; -import { Check, ChevronDown, ChevronUp } from "lucide-react"; -import * as React from "react"; - -import { cn } from "@/src/utils"; - -const Select = SelectPrimitive.Root; - -const SelectGroup = SelectPrimitive.Group; - -const SelectValue = SelectPrimitive.Value; - -const SelectTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - span]:line-clamp-1", - className, - )} - {...props} - > - {children} - - - - -)); -SelectTrigger.displayName = SelectPrimitive.Trigger.displayName; - -const SelectScrollUpButton = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - -)); -SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName; - -const SelectScrollDownButton = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - -)); -SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName; - -const SelectContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, position = "popper", ...props }, ref) => ( - - - - - {children} - - - - -)); -SelectContent.displayName = SelectPrimitive.Content.displayName; - -const SelectLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -SelectLabel.displayName = SelectPrimitive.Label.displayName; - -const SelectItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - - - - - {children} - -)); -SelectItem.displayName = SelectPrimitive.Item.displayName; - -const SelectSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -SelectSeparator.displayName = SelectPrimitive.Separator.displayName; - -export { - Select, - SelectGroup, - SelectValue, - SelectTrigger, - SelectContent, - SelectLabel, - SelectItem, - SelectSeparator, - SelectScrollUpButton, - SelectScrollDownButton, -}; diff --git a/src/components/ui/separator.tsx b/src/components/ui/separator.tsx deleted file mode 100644 index 6961f97c..00000000 --- a/src/components/ui/separator.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import * as SeparatorPrimitive from "@radix-ui/react-separator"; -import * as React from "react"; - -import { cn } from "@/src/utils"; - -const Separator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => ( - -)); -Separator.displayName = SeparatorPrimitive.Root.displayName; - -export { Separator }; diff --git a/src/components/ui/slider.tsx b/src/components/ui/slider.tsx deleted file mode 100644 index d609e011..00000000 --- a/src/components/ui/slider.tsx +++ /dev/null @@ -1,25 +0,0 @@ -"use client"; - -import * as SliderPrimitive from "@radix-ui/react-slider"; -import * as React from "react"; - -import { cn } from "~/utils"; - -const Slider = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - - - - -)); -Slider.displayName = SliderPrimitive.Root.displayName; - -export { Slider }; diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx deleted file mode 100644 index 344166f4..00000000 --- a/src/components/ui/textarea.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import * as React from "react"; - -import { cn } from "@/src/utils"; - -export type TextareaProps = React.TextareaHTMLAttributes; - -const Textarea = React.forwardRef(({ className, ...props }, ref) => { - return ( -