From 2e9e3b1503db60c0a06fd91ce3ba1e0f76f9d570 Mon Sep 17 00:00:00 2001 From: jtgi Date: Tue, 25 Jun 2024 20:20:16 +0900 Subject: [PATCH] chore: misc layout fixes --- .gitignore | 1 + src/app/[identifier]/page.tsx | 132 +++++++++++++-------------- src/app/layout.tsx | 74 ++++++++------- src/components/cast-component.tsx | 2 +- src/components/home.tsx | 28 +++--- src/components/profile-component.tsx | 2 +- src/components/search.tsx | 65 ++++++------- src/hooks/useClipboard.ts | 23 +++++ src/lib/utils.ts | 1 + 9 files changed, 171 insertions(+), 157 deletions(-) create mode 100644 src/hooks/useClipboard.ts diff --git a/.gitignore b/.gitignore index fd3dbb5..00bba9b 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ yarn-error.log* # local env files .env*.local +.env # vercel .vercel diff --git a/src/app/[identifier]/page.tsx b/src/app/[identifier]/page.tsx index 0f593a7..c2add27 100644 --- a/src/app/[identifier]/page.tsx +++ b/src/app/[identifier]/page.tsx @@ -1,7 +1,10 @@ -'use client' +"use client"; import Modal from "@/components/modal-component"; +import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader } from "@/components/ui/card"; +import { useClipboard } from "@/hooks/useClipboard"; import { fetchCastAndFidData } from "@/lib/utils"; +import { CopyCheckIcon, CopyIcon, UserIcon } from "lucide-react"; import Link from "next/link"; import { useEffect, useState } from "react"; @@ -12,12 +15,12 @@ interface ResponseProps { const isNumeric = (str: string): boolean => { return !isNaN(Number(str)) && !isNaN(parseFloat(str)) && !/^0x/.test(str); -} +}; const renderSkeletonHeader = () => ( - +
- +

@@ -28,16 +31,12 @@ const renderSkeletonHeader = () => ( ); -const copyToClipboard = (text: string) => { - navigator.clipboard.writeText(text).then(() => { - }).catch(err => { - }); -}; - export default function Page({ params }: ResponseProps) { const identifier = decodeURIComponent(params.identifier); const fid: number | null = isNumeric(identifier) ? Number(identifier) : null; const hash = fid ? null : identifier; + + const { copied, copy } = useClipboard(); const [data, setData] = useState(null); const [modalData, setModalData] = useState(null); const [modalTitle, setModalTitle] = useState(""); @@ -47,14 +46,14 @@ export default function Page({ params }: ResponseProps) { const fetchData = async () => { setLoading(true); - const data = await fetchCastAndFidData(hash, fid) as any; + const data = (await fetchCastAndFidData(hash, fid)) as any; const checkWarning = (message: any) => { const expectedTypes = [ "USER_DATA_TYPE_PFP", "USER_DATA_TYPE_DISPLAY", "USER_DATA_TYPE_BIO", - "USER_DATA_TYPE_USERNAME" + "USER_DATA_TYPE_USERNAME", ]; if (message?.messages) { @@ -65,7 +64,7 @@ export default function Page({ params }: ResponseProps) { } }); - const missingTypes = expectedTypes.filter(type => !foundTypes.has(type)); + const missingTypes = expectedTypes.filter((type) => !foundTypes.has(type)); return missingTypes; } @@ -83,14 +82,14 @@ export default function Page({ params }: ResponseProps) { if (!username || username === expectedUsername) missingObjects.push("Username"); return missingObjects; - } + }; const warpcastAuthorMissing = checkWarning(data.apiData.warpcast?.author); const neynarAuthorMissing = checkWarning(data.apiData.neynar?.author?.author); const warpcastAuthorHubMissing = checkWarning(data.hubData?.[0]?.author); const neynarAuthorHubMissing = checkWarning(data.hubData?.[1]?.author); - const warpcastCastMissing = [] as any - const neynarCastMissing = [] as any + const warpcastCastMissing = [] as any; + const neynarCastMissing = [] as any; setData({ ...data, @@ -101,7 +100,7 @@ export default function Page({ params }: ResponseProps) { warpcastCastMissing, neynarCastMissing, warpcastCastHubMissing: [], - neynarCastHubMissing: [] + neynarCastHubMissing: [], }); setLoading(false); @@ -124,10 +123,14 @@ export default function Page({ params }: ResponseProps) { const { warpcast, neynar } = data?.apiData ?? {}; const { - warpcastAuthorMissing, neynarAuthorMissing, - warpcastAuthorHubMissing, neynarAuthorHubMissing, - warpcastCastMissing, neynarCastMissing, - warpcastCastHubMissing, neynarCastHubMissing + warpcastAuthorMissing, + neynarAuthorMissing, + warpcastAuthorHubMissing, + neynarAuthorHubMissing, + warpcastCastMissing, + neynarCastMissing, + warpcastCastHubMissing, + neynarCastHubMissing, } = data ?? {}; const hubs = data?.hubData ?? []; @@ -138,25 +141,27 @@ export default function Page({ params }: ResponseProps) { const { author: warpcastAuthor, cast: warpcastCast } = warpcast || {}; const { author: neynarAuthor, cast: neynarCast } = neynar || {}; - const authorFid = warpcastCast?.author?.fid || neynarCast?.cast?.author?.fid + const authorFid = warpcastCast?.author?.fid || neynarCast?.cast?.author?.fid; + + const renderHeader = (label: string, data: any | null, missingObjects: string[]) => { + if (!data) { + return null; + } - const renderHeader = (label: string, data: any, missingObjects: string[]) => { - let icon = '✅'; + let icon = "✅"; if (data?.error) { - icon = '❌'; + icon = "❌"; } else if (missingObjects.length > 0) { - icon = '⚠️'; + icon = "⚠️"; } return ( + ) : null} + + {authorFid ? ( + - ) : null -} - -{ authorFid ? ( - -
- View Author Profile -
- - ) : null -} -
- + > + + View Author Profile + + + ) : null} + - -
+
{loading ? ( <> {renderSkeletonHeader()} @@ -206,14 +205,14 @@ export default function Page({ params }: ResponseProps) { ) : ( <> - {warpcastAuthor && renderHeader('Warpcast API', warpcastAuthor, warpcastAuthorMissing)} - {warpcastCast && renderHeader('Warpcast API', warpcastCast, warpcastCastMissing)} - {nemesAuthor && renderHeader('Warpcast Hub (Hoyt)', nemesAuthor, warpcastAuthorHubMissing)} - {nemesCast && renderHeader('Warpcast Hub (Hoyt)', nemesCast, warpcastCastHubMissing)} - {neynarHubAuthor && renderHeader('Neynar Hub', neynarHubAuthor, neynarAuthorHubMissing)} - {neynarHubCast && renderHeader('Neynar Hub', neynarHubCast, neynarCastHubMissing)} - {neynarAuthor && renderHeader('Neynar API', neynarAuthor, neynarAuthorMissing)} - {neynarCast && renderHeader('Neynar API', neynarCast, neynarCastMissing)} + {renderHeader("Warpcast API", warpcastAuthor, warpcastAuthorMissing)} + {renderHeader("Warpcast API", warpcastCast, warpcastCastMissing)} + {renderHeader("Warpcast Hub (Hoyt)", nemesAuthor, warpcastAuthorHubMissing)} + {renderHeader("Warpcast Hub (Hoyt)", nemesCast, warpcastCastHubMissing)} + {renderHeader("Neynar Hub", neynarHubAuthor, neynarAuthorHubMissing)} + {renderHeader("Neynar Hub", neynarHubCast, neynarCastHubMissing)} + {renderHeader("Neynar API", neynarAuthor, neynarAuthorMissing)} + {renderHeader("Neynar API", neynarCast, neynarCastMissing)} )}
@@ -221,4 +220,3 @@ export default function Page({ params }: ResponseProps) { ); } - diff --git a/src/app/layout.tsx b/src/app/layout.tsx index b1bd5f9..75f2f28 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,12 +1,15 @@ -'use client' +/* eslint-disable @next/next/no-img-element */ +"use client"; import "./globals.css"; import Link from "next/link"; import Providers from "./providers"; import Search from "@/components/search"; -import { usePathname } from 'next/navigation' +import { usePathname } from "next/navigation"; import { useEffect } from "react"; import { seo } from "@/constants"; import { Card, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { DownloadIcon } from "lucide-react"; export default function RootLayout({ children, @@ -15,7 +18,7 @@ export default function RootLayout({ }>) { return ( - + @@ -26,39 +29,40 @@ export default function RootLayout({ - - -
- - - -
-
- -

Farcaster Explorer

- -
-
- -
-
- {children} -
- - + +
+ +
+
+ + + +
- - - Download cast action - - - -
-
- {//open in new page - } - - +
+ +

Farcaster Explorer

+ + +
+
+
+ +
{children}
+ +
+ +
+ +
); diff --git a/src/components/cast-component.tsx b/src/components/cast-component.tsx index 58bedf0..7b9bc6d 100644 --- a/src/components/cast-component.tsx +++ b/src/components/cast-component.tsx @@ -9,7 +9,7 @@ export function CastComponent({cast,warpcastUrl}: any) { const avatarImg = cast.author.pfp_url ? cast.author.pfp_url : null return ( - + diff --git a/src/components/home.tsx b/src/components/home.tsx index 75577da..e3e01ef 100644 --- a/src/components/home.tsx +++ b/src/components/home.tsx @@ -6,29 +6,27 @@ import { FIDPFP, exampleCast, warpcastURLCast, warpcastURLCastURL, warpcastURLPF export default function Home() { return ( -
-
-
-
+
+
+

Example hash

- +
-
-

Example Warpcast cast url

- +
+

Example FID

+
-
-
-

Example FID

- +
+
+

Example Warpcast cast url

+
-
+

Example Warpcast profile url

- +
-
); } \ No newline at end of file diff --git a/src/components/profile-component.tsx b/src/components/profile-component.tsx index 79d851d..590157b 100644 --- a/src/components/profile-component.tsx +++ b/src/components/profile-component.tsx @@ -7,7 +7,7 @@ export function ProfileComponent({pfp,url}: any) { if(!pfp) return null; return ( - + diff --git a/src/components/search.tsx b/src/components/search.tsx index 5b8100a..a7acde5 100644 --- a/src/components/search.tsx +++ b/src/components/search.tsx @@ -1,49 +1,38 @@ -'use client' +"use client"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useRouter } from "next13-progressbar"; import { usePathname } from "next/navigation"; +import { SearchIcon } from "lucide-react"; -export default function Search({ -}: Readonly<{ - -}>) { - const searchParams = usePathname() - - - const [identifier, setIdentifier] = useState(""); +export default function Search() { const router = useRouter(); - - const handleKeyPress = (e: any) => { - if (e.key === "Enter") { - router.push(`/${encodeURIComponent(identifier)}`); - } - }; + const path = usePathname(); + const [identifier, setIdentifier] = useState(decodeURIComponent(path.slice(1))); useEffect(() => { - if(searchParams === "/") { - setIdentifier("") - } - else { - setIdentifier(decodeURIComponent(searchParams.split("/")[1])) - } - }, [searchParams]) + const identifier = decodeURIComponent(path.slice(1)); + setIdentifier(identifier); + }, [path]); return ( -
- { - setIdentifier(e.target.value); - }} - onKeyDown={handleKeyPress} - /> - -
+
{ + e.preventDefault(); + router.push(`/${encodeURIComponent(identifier)}`); + }} + > + setIdentifier(e.currentTarget.value)} + /> + +
); -} \ No newline at end of file +} diff --git a/src/hooks/useClipboard.ts b/src/hooks/useClipboard.ts new file mode 100644 index 0000000..c8ffda7 --- /dev/null +++ b/src/hooks/useClipboard.ts @@ -0,0 +1,23 @@ +import { useState, useRef } from "react"; + +export function useClipboard() { + const [copied, setCopied] = useState(false); + const ref = useRef(); + + const copy = async (text: string) => { + try { + await navigator.clipboard.writeText(text); + setCopied(true); + + if (ref.current) { + clearTimeout(ref.current); + } + + setTimeout(() => setCopied(false), 1_000); + } catch (err) { + // cool + } + }; + + return { copy, copied }; + } \ No newline at end of file diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 22d4da9..fbb1194 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -341,3 +341,4 @@ export const isValidWarpcastUrl = (url: string | null) => { if (!url) return false; return url.includes('https://warpcast.com'); }; +