Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/game blocks #2

Merged
merged 5 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .yarn/install-state.gz
Binary file not shown.
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export default tseslint.config(
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/restrict-template-expressions': 'off',
},
},
);
8 changes: 7 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inknut+Antiqua:wght@300;400;500;600;700;800;900&display=swap"
rel="stylesheet"
/>
</head>
<body>
<div id="root"></div>
<div id="root" style="max-width: 100vw; width: 100%"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"dependencies": {
"@hookform/resolvers": "^3.10.0",
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-popover": "^1.1.4",
"@radix-ui/react-slot": "^1.1.1",
Expand Down
Binary file added public/images/footer/footer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/libra-card.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/sun.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/textures/green.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions src/components/common/About/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';

export const AboutSection = () => {
return (
<div className="grid w-full grid-cols-2 bg-[url('/images/textures/green.png')] bg-repeat font-inknut *:pb-[60px] *:pt-[80px]">
<div className="flex h-full min-h-full w-full flex-col justify-between border-r border-black pl-[140px] pr-[100px]">
<div className="space-y-8">
<p className="text-[60px] font-light leading-[72px]">About Tarot</p>
<p className="text-[20px] font-light leading-[28px]">
Lorem ipsum dolor sit amet consectetur. Posuere auctor vivamus sed leo non pellentesque. Massa sed eget est
porta facilisis rhoncus mauris. Pellentesque malesuada morbi volutpat dictum. Sollicitudin suspendisse
aliquam imperdiet rutrum interdum. Dignissim in diam vestibulum sodales nibh nec scelerisque id. Sit
facilisi vestibulum etiam nunc a. Ullamcorper amet sed etiam ac adipiscing mauris cursus blandit vitae.
Lacus eget gravida morbi condimentum lobortis a. Blandit gravida dictum mollis scelerisque feugiat dis.
</p>
</div>

<img src="/images/sun.png" alt="tarot1" className="!mt-auto ml-auto h-[320px] w-[305px]" />
</div>

<div className="w-full space-y-8 pl-[100px] pr-[140px]">
<p className="text-[60px] font-light leading-[72px]">Rules</p>

<div className="flex w-full max-w-full flex-row justify-between overflow-x-hidden *:h-[248px] *:w-[173px] 2xl:*:h-[310px] 2xl:*:w-[217px]">
<img src="/images/libra-card.png" alt="tarot1" />
<img src="/images/libra-card.png" alt="tarot2" />
<img src="/images/libra-card.png" alt="tarot3" />
</div>

<Accordion type="single" defaultValue="item-0">
{new Array(6).fill(0).map((_, i) => (
<AccordionItem value={`item-${i}`} key={i}>
<AccordionTrigger>Is it accessible?</AccordionTrigger>
<AccordionContent>Yes. It adheres to the WAI-ARIA design pattern.</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
</div>
);
};
10 changes: 10 additions & 0 deletions src/components/common/Footer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const Footer = () => {
return (
<div className="flex h-[920px] w-full flex-col items-end justify-end bg-[url('/images/footer/footer.png')] bg-center font-inknut">
<p className="mb-[100px] flex w-full flex-row justify-between px-[140px] text-[20px] font-light leading-[28px]">
<span>@{new Date().getFullYear()}. All rights reserved.</span>
<span>Powered by TarotSol AI</span>
</p>
</div>
);
};
90 changes: 90 additions & 0 deletions src/components/pages/game/game.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { useWallet } from '@solana/wallet-adapter-react';
import { useEffect } from 'react';
import { SubmitHandler, useForm } from 'react-hook-form';
import { toast } from 'react-toastify';
import { z } from 'zod';

import { ConnectWalletButton } from '@/components/common/Header/connect-wallet-button';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import useMakePrediction from '@/hooks/contracts/write/use-make-prediction';

const TarotRequestSchema = z.object({
question: z
.string()
.min(3)
.max(1000)
.regex(/^[a-zA-Z0-9.,!? ]+$/, 'Only English letters and numbers are allowed')
.refine((value) => value.trim() !== '', { message: 'String cannot consist of only spaces' }),
});

type TarotRequestSchemaType = z.infer<typeof TarotRequestSchema>;

export const GameSection = () => {
const { publicKey } = useWallet();
const { mutateAsync: transfer, isSuccess, isPending, data: predictionAnswer } = useMakePrediction();

const {
register,
handleSubmit,
watch,
setValue,
formState: { errors },
} = useForm<TarotRequestSchemaType>({ resolver: zodResolver(TarotRequestSchema) });

const onSubmit: SubmitHandler<TarotRequestSchemaType> = async (data, e) => {
e?.preventDefault();
console.log('SubmitHandler data', data);
await transfer(watch('question').trim());
};

useEffect(() => {
if (predictionAnswer) {
setValue('question', predictionAnswer + '\n' + watch('question'));
}
}, [isSuccess, predictionAnswer, setValue, watch]);

return (
<div className="mx-auto w-[600px] max-w-[600px] rounded-lg bg-gray-50 p-6 shadow-md">
<h1 className="mb-6 text-center text-3xl font-semibold text-gray-800">Game Page</h1>
<form onSubmit={handleSubmit(onSubmit)} className="w-full space-y-4">
<Input
asChild
error={errors.question && <span className="text-sm text-red-600">{errors.question.message}</span>}
>
<textarea
{...register('question')}
disabled={isPending}
placeholder="Enter your question here..."
className="max-h-[500px] min-h-[150px] w-full resize-y rounded-lg border border-gray-300 p-3 text-black shadow-sm placeholder:text-black focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
/>
</Input>
<Button
type="button"
onClick={async () => {
const questionValue = watch('question');
if (questionValue) {
await navigator.clipboard.writeText(questionValue);
toast.success('Copied!');
}
}}
className="w-full rounded-lg bg-gray-200 px-4 py-2 text-sm font-medium text-gray-700 shadow-md transition hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2"
>
Copy Text
</Button>
<Button
className={`mt-4 w-full rounded-lg bg-blue-500 px-4 py-2 text-white shadow-md transition hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:bg-gray-400`}
type="submit"
disabled={!publicKey || isPending}
>
Make a Prediction
</Button>
</form>
<div className="mt-4">
<ConnectWalletButton />
</div>
</div>
);
};
58 changes: 58 additions & 0 deletions src/components/ui/accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use client';

import * as React from 'react';
import * as AccordionPrimitive from '@radix-ui/react-accordion';
import { ChevronDown } from 'lucide-react';

import { cn } from '@/lib/utils';

const Accordion = AccordionPrimitive.Root;

const AccordionItem = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
<AccordionPrimitive.Item ref={ref} className={cn('border-b border-black', className)} {...props} />
));
AccordionItem.displayName = 'AccordionItem';

const AccordionTrigger = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
'flex flex-1 items-center justify-between px-2 py-6 text-left text-[20px] font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
className,
)}
{...props}
>
{children}

<ChevronDown
className="shrink-0 text-muted-foreground transition-transform duration-200"
size={20}
stroke="black"
/>
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
));
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;

const AccordionContent = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Content
ref={ref}
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden px-2 text-[20px]"
{...props}
>
<div className={cn('pb-4 pt-0', className)}>{children}</div>
</AccordionPrimitive.Content>
));
AccordionContent.displayName = AccordionPrimitive.Content.displayName;

export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
1 change: 0 additions & 1 deletion src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
@tailwind utilities;

body {
margin: 10px;
place-items: center;
min-height: 100vh;
background-color: #83a4c5;
Expand Down
2 changes: 1 addition & 1 deletion src/layouts/default-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Outlet } from 'react-router';

export function DefaultLayout() {
return (
<main>
<main className="w-full">
<Outlet />
</main>
);
Expand Down
95 changes: 8 additions & 87 deletions src/pages/game-page.tsx
Original file line number Diff line number Diff line change
@@ -1,92 +1,13 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { useWallet } from '@solana/wallet-adapter-react';
import { useEffect } from 'react';
import { SubmitHandler, useForm } from 'react-hook-form';
import { toast } from 'react-toastify';
import { z } from 'zod';

import { ConnectWalletButton } from '@/components/common/Header/connect-wallet-button';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import useMakePrediction from '@/hooks/contracts/write/use-make-prediction';

const TarotRequestSchema = z.object({
question: z
.string()
.min(3)
.max(1000)
.regex(/^[a-zA-Z0-9.,!? ]+$/, 'Only English letters and numbers are allowed')
.refine((value) => value.trim() !== '', { message: 'String cannot consist of only spaces' }),
});

type TarotRequestSchemaType = z.infer<typeof TarotRequestSchema>;
import { AboutSection } from '@/components/common/About';
import { Footer } from '@/components/common/Footer';
import { GameSection } from '@/components/pages/game/game';

export default function GamePage() {
const { publicKey } = useWallet();
const { mutateAsync: transfer, isSuccess, isPending, data: predictionAnswer } = useMakePrediction();

console.log('predictionAnswer', predictionAnswer);

const {
register,
handleSubmit,
watch,
setValue,
formState: { errors },
} = useForm<TarotRequestSchemaType>({ resolver: zodResolver(TarotRequestSchema) });

const onSubmit: SubmitHandler<TarotRequestSchemaType> = async (data, e) => {
e?.preventDefault();
console.log('SubmitHandler data', data);
await transfer(watch('question').trim());
};

useEffect(() => {
if (predictionAnswer) {
setValue('question', predictionAnswer + '\n' + watch('question'));
}
}, [isSuccess, predictionAnswer, setValue, watch]);

return (
<div className="mx-auto w-[600px] max-w-[600px] rounded-lg bg-gray-50 p-6 shadow-md">
<h1 className="mb-6 text-center text-3xl font-semibold text-gray-800">Game Page</h1>
<form onSubmit={handleSubmit(onSubmit)} className="w-full space-y-4">
<Input
asChild
error={errors.question && <span className="text-sm text-red-600">{errors.question.message}</span>}
>
<textarea
{...register('question')}
disabled={isPending}
placeholder="Enter your question here..."
className="max-h-[500px] min-h-[150px] w-full resize-y rounded-lg border border-gray-300 p-3 text-black shadow-sm placeholder:text-black focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
/>
</Input>
<Button
type="button"
onClick={async () => {
const questionValue = watch('question');
if (questionValue) {
await navigator.clipboard.writeText(questionValue);
toast.success('Copied!');
}
}}
className="w-full rounded-lg bg-gray-200 px-4 py-2 text-sm font-medium text-gray-700 shadow-md transition hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2"
>
Copy Text
</Button>
<Button
className={`mt-4 w-full rounded-lg bg-blue-500 px-4 py-2 text-white shadow-md transition hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:bg-gray-400`}
type="submit"
disabled={!publicKey || isPending}
>
Make a Prediction
</Button>
</form>
<div className="mt-4">
<ConnectWalletButton />
</div>
</div>
<>
<GameSection />
<AboutSection />
<Footer />
</>
);
}
18 changes: 18 additions & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,24 @@ const config = {
md: '768px',
lg: '1024px',
xl: '1440px',
'2xl': '1820px',
},
fontFamily: {
inknut: ['"Inknut Antiqua"', 'serif'],
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
Expand Down
Loading
Loading