Skip to content

Commit

Permalink
Adding changes to Frontend visual + GuessRandomNumberGame (#18)
Browse files Browse the repository at this point in the history
* adding nice visual to fhewordle

* feat: add fhewordle mock to the frontend

* change sample

* adding a guess random number game to the hardhat examples

* adding guess random number game
  • Loading branch information
poppyseedDev authored Jan 13, 2025
1 parent 154b351 commit b16af88
Show file tree
Hide file tree
Showing 25 changed files with 43,056 additions and 13,484 deletions.
23 changes: 15 additions & 8 deletions frontend-visual/app/dapps/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import Header from '@/components/Header'
import Link from 'next/link'
import Image from 'next/image'
"use client";

import Header from "@/components/Header";
import Link from "next/link";
import Image from "next/image";

export default function DAppPage({ params }: { params: { slug: string } }) {
const dAppTitle = params.slug.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ')
const dAppTitle = params.slug
.split("-")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(" ");

return (
<>
Expand All @@ -14,9 +19,12 @@ export default function DAppPage({ params }: { params: { slug: string } }) {
</Link>
<div className="w-full max-w-2xl mx-auto mt-8">
<div className="bg-white shadow-[6px_6px_0_0_rgba(0,0,0,1)] p-8 relative overflow-hidden">
<h1 className="text-4xl font-bold mb-4 text-gray-800 font-telegraf relative z-10">{dAppTitle}</h1>
<h1 className="text-4xl font-bold mb-4 text-gray-800 font-telegraf relative z-10">
{dAppTitle}
</h1>
<p className="text-gray-600 relative z-10">
This is the page for the {dAppTitle} dApp. More details and functionality can be added here.
This is the page for the {dAppTitle} dApp. More details and
functionality can be added here.
</p>
</div>
</div>
Expand All @@ -25,6 +33,5 @@ export default function DAppPage({ params }: { params: { slug: string } }) {
<p>&copy; 2023 Zama dApps. All rights reserved.</p>
</footer>
</>
)
);
}

38 changes: 38 additions & 0 deletions frontend-visual/app/dapps/wordle/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"use client";

import Header from "@/components/Header";
import Link from "next/link";
import Image from "next/image";
import WordleGame from "@/components/fheWordle/WordleGame";

export default function DAppPage() {
return (
<>
<Header />
<main className="flex-grow container mx-auto px-4 py-16">
<Link href="/" className="text-black hover:underline mb-4 inline-block">
&larr; Back to dApps
</Link>
<div className="w-full max-w-2xl mx-auto mt-8">
<div className="bg-white shadow-[6px_6px_0_0_rgba(0,0,0,1)] p-8 relative overflow-hidden">
<h1 className="text-4xl font-bold mb-4 text-gray-800 font-telegraf relative z-10">
FHEWordle
</h1>
<p className="text-gray-600 relative z-10">
FHEWordle is a privacy-preserving version of the popular word game
Wordle, powered by Fully Homomorphic Encryption (FHE). In this
game, your guesses and the target word remain encrypted at all
times, ensuring complete privacy while still allowing you to play
the classic word-guessing game. Try to guess the 5-letter word in
6 attempts or less!
</p>
<WordleGame />
</div>
</div>
</main>
<footer className="bg-yellow-400 py-6 text-center text-gray-800">
<p>&copy; 2023 Zama dApps. All rights reserved.</p>
</footer>
</>
);
}
21 changes: 12 additions & 9 deletions frontend-visual/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import Header from '@/components/Header'
import DAppCard from '@/components/DAppCard'
import Header from "@/components/Header";
import DAppCard from "@/components/DAppCard";

const dApps = [
{ title: 'EIP-712', slug: 'eip-712' },
{ title: 'ERC-20', slug: 'erc-20' },
{ title: 'Blind auction', slug: 'blind-auction' },
]
{ title: "EIP-712", slug: "eip-712" },
{ title: "ERC-20", slug: "erc-20" },
{ title: "Blind auction", slug: "blind-auction" },
{ title: "FHEWordle", slug: "wordle" },
];

export default function Home() {
return (
<>
<Header />
<main className="flex-grow container mx-auto px-4 py-16">
<h1 className="text-5xl font-bold mb-16 text-center text-gray-800 font-telegraf-bold">
Explore <span className="font-telegraf-light">Decentralized Applications</span>
Explore{" "}
<span className="font-telegraf-light">
Decentralized Applications
</span>
</h1>
<div className="max-w-screen-lg mx-auto grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-16 justify-items-center">
{dApps.map((dApp) => (
Expand All @@ -25,6 +29,5 @@ export default function Home() {
<p>&copy; 2024 Zama dApps. All rights reserved.</p>
</footer>
</>
)
);
}

104 changes: 104 additions & 0 deletions frontend-visual/components/fheWordle/WordleGame.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { useState, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { AlertCircle } from "lucide-react";
import { VALID_WORDS } from "./validWordsList";

const WORD_LENGTH = 5;
const MAX_GUESSES = 6;
const WORDS = VALID_WORDS.map((word) => word.toUpperCase());

export default function WordleGame() {
const [targetWord, setTargetWord] = useState("");
const [currentGuess, setCurrentGuess] = useState("");
const [guesses, setGuesses] = useState<string[]>([]);
const [feedback, setFeedback] = useState<string[][]>([]);
const [gameOver, setGameOver] = useState(false);
const [message, setMessage] = useState("");

useEffect(() => {
setTargetWord(WORDS[Math.floor(Math.random() * WORDS.length)]);
}, []);

const handleGuess = () => {
if (currentGuess.length !== WORD_LENGTH) {
setMessage("Please enter a 5-letter word");
return;
}

if (!WORDS.includes(currentGuess)) {
setMessage("Not a valid word");
return;
}

const newFeedback = currentGuess.split("").map((letter, index) => {
if (letter === targetWord[index]) return "correct";
if (targetWord.includes(letter)) return "present";
return "absent";
});

setGuesses([...guesses, currentGuess]);
setFeedback([...feedback, newFeedback]);
setCurrentGuess("");
setMessage("");

if (currentGuess === targetWord) {
setGameOver(true);
setMessage("Congratulations! You guessed the word!");
} else if (guesses.length + 1 === MAX_GUESSES) {
setGameOver(true);
setMessage(`Game over! The word was ${targetWord}`);
}
};

const renderGuess = (guess: string, feedbackRow: string[]) => {
return guess.split("").map((letter, index) => (
<div
key={index}
className={`w-12 h-12 border-2 flex items-center justify-center text-2xl font-bold
${
feedbackRow[index] === "correct"
? "bg-green-500 border-green-600"
: feedbackRow[index] === "present"
? "bg-yellow-500 border-yellow-600"
: "bg-gray-300 border-gray-400"
}`}
>
{letter}
</div>
));
};

return (
<div className="flex flex-col items-center justify-center">
<div className="space-y-2 mt-4 mb-4">
{guesses.map((guess, i) => (
<div key={i} className="flex space-x-2">
{renderGuess(guess, feedback[i])}
</div>
))}
</div>
{!gameOver && (
<div className="flex space-x-2 mb-4">
<Input
type="text"
value={currentGuess}
onChange={(e) => setCurrentGuess(e.target.value.toUpperCase())}
maxLength={WORD_LENGTH}
className="w-40 text-center text-2xl uppercase"
disabled={gameOver}
/>
<Button onClick={handleGuess} disabled={gameOver}>
Guess
</Button>
</div>
)}
{message && (
<div className="flex items-center space-x-2 text-red-500">
<AlertCircle className="h-5 w-5" />
<span>{message}</span>
</div>
)}
</div>
);
}
Loading

0 comments on commit b16af88

Please sign in to comment.