vimalk78's picture
feat: add frontend controls for similarity temperature and difficulty weight
5686111
import React, { useState, useEffect } from 'react';
import TopicSelector from './components/TopicSelector';
import PuzzleGrid from './components/PuzzleGrid';
import ClueList from './components/ClueList';
import DebugTab from './components/DebugTab';
import AdvancedSettings from './components/AdvancedSettings';
import LoadingSpinner from './components/LoadingSpinner';
import useCrossword from './hooks/useCrossword';
import './styles/puzzle.css';
function App() {
const [selectedTopics, setSelectedTopics] = useState([]);
const [customTopics, setCustomTopics] = useState([]);
const [difficulty, setDifficulty] = useState('medium');
const [showSolution, setShowSolution] = useState(false);
const [customSentence, setCustomSentence] = useState('');
const [multiTheme, setMultiTheme] = useState(true);
const [activeTab, setActiveTab] = useState('puzzle');
// Advanced settings state
const [similarityTemperature, setSimilarityTemperature] = useState(0.2);
const [difficultyWeight, setDifficultyWeight] = useState(0.5);
const {
puzzle,
loading,
error,
topics,
fetchTopics,
generatePuzzle,
resetPuzzle
} = useCrossword();
useEffect(() => {
fetchTopics();
}, [fetchTopics]);
const handleGeneratePuzzle = async () => {
// Combine predefined and custom topics
const allTopics = [...selectedTopics, ...customTopics.filter(t => t.trim())];
if (allTopics.length === 0 && !customSentence.trim()) {
alert('Please select at least one topic or provide a custom sentence');
return;
}
setShowSolution(false);
await generatePuzzle(allTopics, difficulty, false, customSentence, multiTheme, {
similarityTemperature,
difficultyWeight
});
};
const handleTopicsChange = (topics) => {
setSelectedTopics(topics);
};
const handleSentenceChange = (sentence) => {
setCustomSentence(sentence);
};
const handleMultiThemeChange = (enabled) => {
setMultiTheme(enabled);
};
const handleCustomTopicsChange = (topics) => {
setCustomTopics(topics);
};
const handleReset = () => {
resetPuzzle();
setSelectedTopics([]);
setCustomTopics([]);
setShowSolution(false);
setDifficulty('medium');
setCustomSentence('');
setMultiTheme(true);
setActiveTab('puzzle');
setSimilarityTemperature(0.2);
setDifficultyWeight(0.5);
};
const handleRevealSolution = () => {
setShowSolution(true);
};
return (
<div className="crossword-app">
<header className="app-header">
<h1 className="app-title">Crossword Puzzle Generator</h1>
<p>Select topics and generate your custom crossword puzzle!</p>
</header>
<TopicSelector
onTopicsChange={handleTopicsChange}
availableTopics={topics}
selectedTopics={selectedTopics}
customTopics={customTopics}
onCustomTopicsChange={handleCustomTopicsChange}
customSentence={customSentence}
onSentenceChange={handleSentenceChange}
multiTheme={multiTheme}
onMultiThemeChange={handleMultiThemeChange}
/>
<AdvancedSettings
similarityTemperature={similarityTemperature}
onTemperatureChange={setSimilarityTemperature}
difficultyWeight={difficultyWeight}
onWeightChange={setDifficultyWeight}
/>
<div className="puzzle-controls">
<select
value={difficulty}
onChange={(e) => setDifficulty(e.target.value)}
className="control-btn"
>
<option value="easy">Easy</option>
<option value="medium">Medium</option>
<option value="hard">Hard</option>
</select>
<button
onClick={handleGeneratePuzzle}
disabled={loading || (selectedTopics.length === 0 && customTopics.filter(t => t.trim()).length === 0 && !customSentence.trim())}
className="control-btn generate-btn"
>
{loading ? 'Generating...' : 'Generate Puzzle'}
</button>
<button
onClick={handleReset}
className="control-btn reset-btn"
>
Reset
</button>
{puzzle && !showSolution && (
<button
onClick={handleRevealSolution}
className="control-btn reveal-btn"
>
Reveal Solution
</button>
)}
</div>
{error && (
<div className="error-message">
Error: {error}
</div>
)}
{loading && <LoadingSpinner />}
{puzzle && !loading && (
<>
{/* Tab Navigation */}
<div className="tab-nav">
<button
className={`tab-btn ${activeTab === 'puzzle' ? 'active' : ''}`}
onClick={() => setActiveTab('puzzle')}
>
Puzzle
</button>
{puzzle.debug && (
<button
className={`tab-btn ${activeTab === 'debug' ? 'active' : ''}`}
onClick={() => setActiveTab('debug')}
>
Debug
</button>
)}
</div>
{/* Tab Content */}
{activeTab === 'puzzle' && (
<div className="puzzle-layout">
<PuzzleGrid
grid={puzzle.grid}
clues={puzzle.clues}
showSolution={showSolution}
/>
<ClueList clues={puzzle.clues} />
</div>
)}
{activeTab === 'debug' && puzzle.debug && (
<DebugTab debugData={puzzle.debug} />
)}
</>
)}
{!puzzle && !loading && !error && (
<div style={{ textAlign: 'center', padding: '40px', color: '#7f8c8d' }}>
Select topics and click "Generate Puzzle" to start!
</div>
)}
</div>
);
}
export default App;