what the fuck have I done
This commit is contained in:
318
app/page.tsx
318
app/page.tsx
@ -1,68 +1,294 @@
|
|||||||
'use client'
|
"use client";
|
||||||
import theme from "@/theme";
|
import theme from "@/theme";
|
||||||
import { Button, ChakraProvider, Container, Flex, Heading, Image, Input, Text } from "@chakra-ui/react";
|
import {
|
||||||
import { useState } from "react";
|
Button,
|
||||||
|
ChakraProvider,
|
||||||
|
Container,
|
||||||
|
Flex,
|
||||||
|
Heading,
|
||||||
|
Image,
|
||||||
|
Input,
|
||||||
|
Text,
|
||||||
|
Box,
|
||||||
|
Separator,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { useEffect, useState, useRef } from "react";
|
||||||
|
import { useSearchParams } from "next/navigation";
|
||||||
import { toaster } from "@/components/ui/toaster";
|
import { toaster } from "@/components/ui/toaster";
|
||||||
import { feelingFree } from "@/actions";
|
import { getRandomResultFromGCI, lmgcitfy } from "@/actions";
|
||||||
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const [query, setQuery] = useState<string | undefined>(undefined);
|
// state shit
|
||||||
const feelingFreedom = async () => {
|
const [query, setQuery] = useState<string>("");
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [link, setLink] = useState<string>("");
|
||||||
|
// animation refs
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
const normalButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
|
const luckyButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
|
const cursorRef = useRef<HTMLImageElement>(null);
|
||||||
|
// query shit
|
||||||
|
const passedInParams = useSearchParams();
|
||||||
|
const passedInQuery = passedInParams.get("query");
|
||||||
|
const isFeelingLucky = passedInParams.get("lucky");
|
||||||
|
// handle shit
|
||||||
|
const handleGenerateLink = async (feelingLucky: boolean) => {
|
||||||
|
if (!query) {
|
||||||
|
toaster.error({ description: "You must provide a search query." });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const queryParams = new URLSearchParams();
|
||||||
|
|
||||||
|
queryParams.append("query", query);
|
||||||
try {
|
try {
|
||||||
|
setLoading(true);
|
||||||
if (!query) {
|
let result: APIResult<string>;
|
||||||
throw new Error('You must provide a search query.');
|
if (feelingLucky) {
|
||||||
|
queryParams.append("lucky", "true");
|
||||||
|
result = await getRandomResultFromGCI(query);
|
||||||
|
} else {
|
||||||
|
result = await lmgcitfy(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchParams = new URLSearchParams();
|
|
||||||
searchParams.set('query', query)
|
|
||||||
|
|
||||||
const result = await feelingFree(searchParams.toString());
|
|
||||||
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
throw new Error(result.payload);
|
toaster.create({
|
||||||
}
|
type: "error",
|
||||||
|
title: "Error",
|
||||||
toaster.create({ title: 'Redirecting...', description: 'Was that so hard?', type: 'success' })
|
description: result.errorMessage,
|
||||||
setTimeout(() => {
|
});
|
||||||
window.location.href = result.payload;
|
|
||||||
}, 2000)
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof Error) {
|
|
||||||
toaster.create({ type: 'error', title: 'Error', description: error.message })
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
setLink(
|
||||||
|
`${window.location.protocol}//${window.location.host}/?${queryParams.toString()}`,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
toaster.error({ description: error.message });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toaster.error({ description: "Something went wrong." });
|
||||||
|
return;
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCursorMove = () => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
// we have to stack this because browser paints the first render, then we request twice to paint the third render which applies the necessary changes for the transition (gay)
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
const input = inputRef.current!.getBoundingClientRect();
|
||||||
|
const inputTargetWidth = input.x + input.width / 3;
|
||||||
|
const inputTargetHeight = input.y + input.height / 2;
|
||||||
|
cursorRef.current!.style.left = `${inputTargetWidth}px`;
|
||||||
|
cursorRef.current!.style.top = `${inputTargetHeight}px`;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!passedInQuery) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
const handleMoveToButton = () => {
|
||||||
const lmgcitfy = () => {
|
let buttonRef;
|
||||||
if (!query) {
|
if (isFeelingLucky === "true") {
|
||||||
toaster.create({ title: 'Error', description: 'You must enter a search query.', type: 'error' });
|
buttonRef = luckyButtonRef;
|
||||||
return;
|
} else {
|
||||||
}
|
buttonRef = normalButtonRef;
|
||||||
const searchParams = new URLSearchParams();
|
}
|
||||||
|
|
||||||
|
const boundingRect = buttonRef.current!.getBoundingClientRect();
|
||||||
|
const buttonX = boundingRect.x + boundingRect.width / 2;
|
||||||
|
const buttonY = boundingRect.y + boundingRect.height / 2;
|
||||||
|
cursorRef.current!.style.left = `${buttonX}px`;
|
||||||
|
cursorRef.current!.style.top = `${buttonY}px`;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
buttonRef.current!.style.scale = `0.95`;
|
||||||
|
}, 1250);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
buttonRef.current!.style.scale = `1`;
|
||||||
|
}, 2350);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
toaster.create({
|
||||||
|
type: "success",
|
||||||
|
title: "LMGCITFY",
|
||||||
|
description: "Was that so hard?",
|
||||||
|
});
|
||||||
|
}, 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTypingAnimation = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const chars = passedInQuery!.split("");
|
||||||
|
let counter = 0;
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
if (inputRef.current!.value.length < chars.length) {
|
||||||
|
const splitValue = inputRef.current!.value.split("");
|
||||||
|
splitValue.push(chars[counter]);
|
||||||
|
inputRef.current!.value = splitValue.join("");
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
if (chars.length === inputRef.current!.value.length) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
|
||||||
|
handleMoveToButton();
|
||||||
|
}
|
||||||
|
}, 75);
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getGCILink = async () => {
|
||||||
|
let result: APIResult<string>;
|
||||||
|
if (isFeelingLucky === "true") {
|
||||||
|
result = await getRandomResultFromGCI(passedInQuery);
|
||||||
|
} else {
|
||||||
|
result = await lmgcitfy(passedInQuery);
|
||||||
|
}
|
||||||
|
if (result.error) {
|
||||||
|
toaster.create({
|
||||||
|
type: "error",
|
||||||
|
title: "Error",
|
||||||
|
description: result.errorMessage,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const link = result.payload;
|
||||||
|
|
||||||
|
setTimeout(() => (window.location.href = link), 9000);
|
||||||
|
};
|
||||||
|
handleCursorMove();
|
||||||
|
handleTypingAnimation();
|
||||||
|
getGCILink();
|
||||||
|
}, [passedInQuery, isFeelingLucky]);
|
||||||
|
|
||||||
searchParams.append('query', query);
|
|
||||||
window.location.href = `https://guncadindex.com/search?${searchParams}`;
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<ChakraProvider value={theme}>
|
<ChakraProvider value={theme}>
|
||||||
<Container backgroundColor={'#2a2a2a'} borderRadius={'lg'} boxShadow={'0 0 12px #4a4a4a'} py={4} width={{ base: '90%', md: '50%' }} overflow={'hidden'}>
|
<Image
|
||||||
<Flex justify={'center'} align={'center'} p={2} mb={4}>
|
src={"/cursor.png"}
|
||||||
<Image src={'/gci_logo_large.png'} height={{ base: '50px', md: '75px' }} alt="GunCAD Index logo" />
|
height={"24px"}
|
||||||
<Flex flexDir={'column'} mx={4} >
|
alt="Fake cursor"
|
||||||
<Heading size={{ base: '2xl', md: '5xl' }} fontFamily={'var(--font-ibm)'} lineHeight={1}>GunCAD Index</Heading>
|
ref={cursorRef}
|
||||||
<Text fontSize={{ base: 'sm', md: 'xl' }} ml={{ md: 1 }} fontFamily={'var(--font-ibm)'}>A search engine for guns.</Text>
|
visibility={passedInParams.toString().length > 0 ? "visible" : "hidden"}
|
||||||
|
position={"fixed"}
|
||||||
|
top={0}
|
||||||
|
left={0}
|
||||||
|
zIndex={1000}
|
||||||
|
transition={"top 2s, left 2s"}
|
||||||
|
/>
|
||||||
|
<Container
|
||||||
|
backgroundColor={"#2a2a2a"}
|
||||||
|
borderRadius={"lg"}
|
||||||
|
boxShadow={"0 0 12px #4a4a4a"}
|
||||||
|
py={4}
|
||||||
|
width={{ base: "90%", md: "60%" }}
|
||||||
|
overflow={"hidden"}
|
||||||
|
animationStyle={"scale-fade-in"}
|
||||||
|
animationDuration={"slowest"}
|
||||||
|
>
|
||||||
|
<Flex justify={"center"} align={"center"} p={2} mb={4}>
|
||||||
|
<Image
|
||||||
|
src={"/gci_logo_large.png"}
|
||||||
|
height={{ base: "50px", md: "75px" }}
|
||||||
|
alt="GunCAD Index logo"
|
||||||
|
/>
|
||||||
|
<Flex flexDir={"column"} mx={4}>
|
||||||
|
<Heading
|
||||||
|
size={{ base: "2xl", md: "5xl" }}
|
||||||
|
fontFamily={"var(--font-ibm)"}
|
||||||
|
lineHeight={1}
|
||||||
|
>
|
||||||
|
GunCAD Index
|
||||||
|
</Heading>
|
||||||
|
<Text
|
||||||
|
fontSize={{ base: "sm", md: "xl" }}
|
||||||
|
ml={{ md: 1 }}
|
||||||
|
fontFamily={"var(--font-ibm)"}
|
||||||
|
>
|
||||||
|
A search engine for guns.
|
||||||
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Input variant={'outline'} borderRadius={'lg'} border={'1px solid #4a4a4a'} size={'lg'} placeholder="Enter your query here" onChange={(e) => setQuery(e.target.value)} />
|
<Input
|
||||||
<Flex justify={'space-around'} gapY={4} flexDir={{ base: 'column', md: 'row' }} p={2} my={4}>
|
variant={"outline"}
|
||||||
<Button colorPalette={'green'} variant={'solid'} size={'lg'} onClick={() => lmgcitfy()}>Search on GCI</Button>
|
borderRadius={"lg"}
|
||||||
<Button colorPalette={'white'} variant={'outline'} size={'lg'} border={'1px solid #4a4a4a'} color={'#FFF'} onClick={() => feelingFreedom()}>I'm feeling free</Button>
|
border={"1px solid #4a4a4a"}
|
||||||
|
size={"lg"}
|
||||||
|
placeholder="Enter your query here"
|
||||||
|
ref={inputRef}
|
||||||
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
|
/>
|
||||||
|
<Flex
|
||||||
|
justify={"space-around"}
|
||||||
|
gapY={4}
|
||||||
|
flexDir={{ base: "column", md: "row" }}
|
||||||
|
p={2}
|
||||||
|
my={4}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
colorPalette={"green"}
|
||||||
|
variant={"solid"}
|
||||||
|
size={"lg"}
|
||||||
|
onClick={() => {
|
||||||
|
handleGenerateLink(false);
|
||||||
|
}}
|
||||||
|
loading={loading}
|
||||||
|
ref={normalButtonRef}
|
||||||
|
>
|
||||||
|
Search on GCI
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
colorPalette={"white"}
|
||||||
|
variant={"outline"}
|
||||||
|
size={"lg"}
|
||||||
|
border={"1px solid #4a4a4a"}
|
||||||
|
color={"#FFF"}
|
||||||
|
onClick={() => {
|
||||||
|
handleGenerateLink(true);
|
||||||
|
}}
|
||||||
|
loading={loading}
|
||||||
|
ref={luckyButtonRef}
|
||||||
|
>
|
||||||
|
I'm feeling free
|
||||||
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Box
|
||||||
|
display={link ? "block" : "none"}
|
||||||
|
animationStyle={link ? "slide-fade-in" : undefined}
|
||||||
|
animationDuration={"slowest"}
|
||||||
|
>
|
||||||
|
<Separator
|
||||||
|
background={
|
||||||
|
"linear-gradient(to right, transparent 0%, #FFFFFF60 50%, transparent 100%)"
|
||||||
|
}
|
||||||
|
mb={4}
|
||||||
|
height={"2px"}
|
||||||
|
/>
|
||||||
|
<Flex flexDirection={"column"} gapY={4}>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
variant={"subtle"}
|
||||||
|
readOnly={true}
|
||||||
|
value={link}
|
||||||
|
border={"1px solid #4a4a4a"}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant={"outline"}
|
||||||
|
border={"1px solid #4a4a4a"}
|
||||||
|
onClick={() => {
|
||||||
|
navigator.clipboard.writeText(link);
|
||||||
|
toaster.create({ description: "Copied link to clipboard" });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Copy Link
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
</Container>
|
</Container>
|
||||||
</ChakraProvider>
|
</ChakraProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user