Skip to content
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
118 changes: 118 additions & 0 deletions front-end/components/AncientRunicPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React from "react";

const AncientRunicPage = ({
variant = "default",
centerText = "ᛋᚢᛗᛗᛟᚾᛖᚱ'ᛋ ᛏᛟᛗᛖ",
runeColor = "#8b7355",
runeCount = 9
}) => {
// Different rune sets for variety
const runeSymbols = {
default: ["ᚠ", "ᚢ", "ᚦ", "ᚨ", "ᚱ", "ᚲ", "ᚷ", "ᚹ", "ᚺ", "ᚾ", "ᛁ", "ᛃ"],
power: ["ᛉ", "ᛊ", "ᛏ", "ᛒ", "ᛖ", "ᛗ", "ᛚ", "ᛜ", "ᛞ", "ᛟ"],
mystical: ["◉", "◈", "◊", "✦", "✧", "✺", "✹", "❂", "✶", "✷"],
elements: ["🜁", "🜂", "🜃", "🜄", "☿", "♀", "♂", "♃", "♄", "⚡"],
};

const runes = React.useMemo(() => {
const runes = [];
const usedRunes = (runeSymbols[variant] || runeSymbols.default).slice(0, runeCount);

for (let i = 0; i < usedRunes.length; i++) {
runes.push({
symbol: usedRunes[i],
x: `${15 + (Math.random() * 70)}%`,
y: `${15 + (Math.random() * 70)}%`,
rotation: Math.random() * 360,
opacity: 0.3 + Math.random() * 0.4,
});
}
return runes;
}, [variant, runeCount]);

// Different circle patterns based on variant
const circlePatterns = {
default: { circles: 3 },
power: { circles: 5 },
mystical: { circles: 4 },
elements: { circles: 2 },
};

const pattern = circlePatterns[variant] || circlePatterns.default;

return (
<div className="relative w-full h-full overflow-hidden">
<style jsx>{`
.rune-symbol {
position: absolute;
font-size: 3rem;
color: ${runeColor};
font-family: serif;
user-select: none;
pointer-events: none;
text-shadow: 0 0 10px rgba(139, 115, 85, 0.3);
}

.center-circle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border: 3px solid rgba(139, 115, 85, 0.3);
border-radius: 50%;
}

.ancient-text {
position: absolute;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
text-align: center;
font-family: Georgia, serif;
font-style: italic;
color: rgba(86, 55, 78, 0.6);
font-size: 0.9rem;
letter-spacing: 2px;
}
`}</style>

{/* Central decorative circles */}
{Array.from({ length: pattern.circles }).map((_, i) => (
<div
key={i}
className="center-circle"
style={{
width: `${200 - i * 40}px`,
height: `${200 - i * 40}px`,
opacity: 0.5 - i * 0.1,
}}
/>
))}

{/* Static runes */}
{runes.map((rune, index) => (
<div
key={index}
className="rune-symbol"
style={{
left: rune.x,
top: rune.y,
transform: `rotate(${rune.rotation}deg)`,
opacity: rune.opacity,
}}
>
{rune.symbol}
</div>
))}

{/* Ancient text at bottom */}
{centerText && (
<div className="ancient-text">
{centerText}
</div>
)}
</div>
);
};

export default AncientRunicPage;
78 changes: 78 additions & 0 deletions front-end/components/ChatInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React, { useState } from "react";

const ChatInput = ({ onSendMessage, isLoading }) => {
const [input, setInput] = useState("");

const handleSubmit = (e) => {
e.preventDefault();
if (!input.trim() || isLoading) return;

onSendMessage(input);
setInput("");
};

const handleKeyPress = (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSubmit(e);
}
};

return (
<div className="flex flex-col items-center justify-center h-full p-8">
<h2 className="section-title">Ask the Book</h2>

<div className="bg-black bg-opacity-70 rounded-lg p-8 w-full max-w-2xl">
<div className="mb-4">
<p className="text-gray-300 text-sm mb-4">
Ask questions about your gameplay, get strategic advice, or learn more about your matches.
</p>
</div>

<form onSubmit={handleSubmit} className="space-y-4">
<div>
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={handleKeyPress}
disabled={isLoading}
className="w-full px-4 py-3 bg-gray-800 bg-opacity-70 border border-gray-700 rounded text-white focus:outline-none focus:border-gray-500 resize-none"
placeholder="What would you like to know about your gameplay?"
rows={6}
/>
</div>

<div className="flex justify-between items-center">
<span className="text-gray-400 text-sm">
{input.length > 0 && `${input.length} characters`}
</span>

<button
type="submit"
disabled={!input.trim() || isLoading}
className="magical-button disabled:opacity-50 disabled:cursor-not-allowed"
>
<span className="button-text">
{isLoading ? "Sending..." : "Enter"}
</span>
<div className="particles">
<span className="particle"></span>
<span className="particle"></span>
<span className="particle"></span>
<span className="particle"></span>
</div>
</button>
</div>
</form>

{isLoading && (
<div className="mt-4 flex items-center justify-center text-gray-400">
<div className="animate-pulse">The Book is thinking...</div>
</div>
)}
</div>
</div>
);
};

export default ChatInput;
66 changes: 66 additions & 0 deletions front-end/components/ChatOutput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useRef, useEffect } from "react";

const ChatOutput = ({ messages }) => {
const messagesEndRef = useRef(null);

const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
};

useEffect(() => {
scrollToBottom();
}, [messages]);

return (
<div className="flex flex-col h-full p-8">
<h2 className="section-title">Book&apos;s Wisdom</h2>

<div className="flex-1 bg-black bg-opacity-70 rounded-lg p-6 overflow-hidden flex flex-col">
<div className="flex-1 overflow-y-auto space-y-4 pr-2">
{messages.length === 0 ? (
<div className="flex items-center justify-center h-full">
<p className="text-gray-400 text-center">
No messages yet. Ask a question to get started.
</p>
</div>
) : (
<>
{messages.map((msg, idx) => (
<div
key={idx}
className={`flex ${
msg.sender === "user" ? "justify-end" : "justify-start"
}`}
>
<div
className={`max-w-[80%] rounded-lg p-4 ${
msg.sender === "user"
? "bg-blue-600 bg-opacity-60 text-white"
: "bg-gray-800 bg-opacity-60 text-gray-100"
}`}
>
{msg.sender === "bot" && (
<div className="flex items-center gap-2 mb-2">
<span className="text-yellow-400 text-xl">🔮</span>
<span className="text-sm font-semibold text-yellow-400">
Book
</span>
</div>
)}
<p className="whitespace-pre-wrap break-words">{msg.text}</p>
<span className="text-xs text-gray-400 mt-2 block">
{msg.timestamp}
</span>
</div>
</div>
))}
<div ref={messagesEndRef} />
</>
)}
</div>
</div>
</div>
);
};

export default ChatOutput;
Loading