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

Adding changes to Frontend visual + GuessRandomNumberGame #18

Merged
merged 5 commits into from
Jan 13, 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
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