Update page background and add sharing
Change the entire page background to a subtle green upon successful completion of the rules of inference puzzle. Add share links and a unique URL for direct access to the interactive.
This commit is contained in:
parent
1bb24d2620
commit
b6a3ad2c59
4 changed files with 59 additions and 4 deletions
|
|
@ -49,6 +49,7 @@ import GridTilingPuzzlePage from './pages/GridTilingPuzzlePage';
|
||||||
import SunnyLinesPuzzlePage from './pages/SunnyLinesPuzzlePage';
|
import SunnyLinesPuzzlePage from './pages/SunnyLinesPuzzlePage';
|
||||||
import SikiniaParliamentPuzzlePage from './pages/SikiniaParliamentPuzzlePage';
|
import SikiniaParliamentPuzzlePage from './pages/SikiniaParliamentPuzzlePage';
|
||||||
import NQueensPuzzlePage from './pages/NQueensPuzzlePage';
|
import NQueensPuzzlePage from './pages/NQueensPuzzlePage';
|
||||||
|
import RulesOfInferencePlaygroundPage from './pages/RulesOfInferencePlaygroundPage';
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
|
|
@ -107,6 +108,7 @@ const App = () => (
|
||||||
<Route path="/puzzles/n-queens" element={<NQueensPuzzlePage />} />
|
<Route path="/puzzles/n-queens" element={<NQueensPuzzlePage />} />
|
||||||
<Route path="/discrete-math/foundations/zeckendorf" element={<ZeckendorfGamePage />} />
|
<Route path="/discrete-math/foundations/zeckendorf" element={<ZeckendorfGamePage />} />
|
||||||
<Route path="/discrete-math/foundations/zeckendorf-search" element={<ZeckendorfSearchTrickPage />} />
|
<Route path="/discrete-math/foundations/zeckendorf-search" element={<ZeckendorfSearchTrickPage />} />
|
||||||
|
<Route path="/discrete-math/foundations/rules-of-inference" element={<RulesOfInferencePlaygroundPage />} />
|
||||||
<Route path="/guessing-game" element={<GuessingGamePage />} />
|
<Route path="/guessing-game" element={<GuessingGamePage />} />
|
||||||
|
|
||||||
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
|
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ function DropZone({ children, onDrop, className }: { children?: React.ReactNode;
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RulesOfInferencePlayground() {
|
export default function RulesOfInferencePlayground({ onComplete }: { onComplete?: (completed: boolean) => void }) {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const [exampleId, setExampleId] = useState(EXAMPLES[0].id);
|
const [exampleId, setExampleId] = useState(EXAMPLES[0].id);
|
||||||
const example = useMemo(() => EXAMPLES.find((e) => e.id === exampleId)!, [exampleId]);
|
const example = useMemo(() => EXAMPLES.find((e) => e.id === exampleId)!, [exampleId]);
|
||||||
|
|
@ -139,7 +139,8 @@ export default function RulesOfInferencePlayground() {
|
||||||
setSteps([]);
|
setSteps([]);
|
||||||
setActivePremises([]);
|
setActivePremises([]);
|
||||||
setActiveRule(undefined);
|
setActiveRule(undefined);
|
||||||
}, [exampleId]);
|
onComplete?.(false);
|
||||||
|
}, [exampleId, onComplete]);
|
||||||
|
|
||||||
const availableStatements = useMemo(
|
const availableStatements = useMemo(
|
||||||
() => Array.from(new Set([...(example?.premises ?? []), ...steps.map((s) => s.result)])),
|
() => Array.from(new Set([...(example?.premises ?? []), ...steps.map((s) => s.result)])),
|
||||||
|
|
@ -220,6 +221,7 @@ export default function RulesOfInferencePlayground() {
|
||||||
|
|
||||||
if (result === example.conclusion) {
|
if (result === example.conclusion) {
|
||||||
toast({ title: "Proof complete!", description: "You successfully derived the target conclusion!" });
|
toast({ title: "Proof complete!", description: "You successfully derived the target conclusion!" });
|
||||||
|
onComplete?.(true);
|
||||||
} else {
|
} else {
|
||||||
toast({ title: "Step added", description: "Continue building your proof with the new statement." });
|
toast({ title: "Step added", description: "Continue building your proof with the new statement." });
|
||||||
}
|
}
|
||||||
|
|
@ -254,7 +256,7 @@ export default function RulesOfInferencePlayground() {
|
||||||
setActivePremises((prev) => prev.filter((x) => x !== p));
|
setActivePremises((prev) => prev.filter((x) => x !== p));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`min-h-[70vh] space-y-4 transition-colors duration-500 ${reachedTarget ? 'bg-green-50/50 dark:bg-green-950/20' : ''}`}>
|
<div className={`min-h-[70vh] space-y-4 transition-colors duration-500 ${reachedTarget && !onComplete ? 'bg-green-50/50 dark:bg-green-950/20' : ''}`}>
|
||||||
{/* Top controls */}
|
{/* Top controls */}
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Select value={exampleId} onValueChange={setExampleId}>
|
<Select value={exampleId} onValueChange={setExampleId}>
|
||||||
|
|
|
||||||
51
src/pages/RulesOfInferencePlaygroundPage.tsx
Normal file
51
src/pages/RulesOfInferencePlaygroundPage.tsx
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import RulesOfInferencePlayground from "@/components/RulesOfInferencePlayground";
|
||||||
|
import SocialShare from "@/components/SocialShare";
|
||||||
|
|
||||||
|
const RulesOfInferencePlaygroundPage = () => {
|
||||||
|
const [isCompleted, setIsCompleted] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`min-h-screen transition-colors duration-500 p-6 ${
|
||||||
|
isCompleted ? 'bg-green-50/50 dark:bg-green-950/20' : 'bg-background'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="max-w-4xl mx-auto space-y-6">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Link
|
||||||
|
to="/themes/discrete-math/foundations"
|
||||||
|
className="text-primary hover:text-primary/80 font-medium"
|
||||||
|
>
|
||||||
|
← Back to Foundations
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
to="/themes/discrete-math"
|
||||||
|
className="text-primary hover:text-primary/80 font-medium"
|
||||||
|
>
|
||||||
|
Back to Discrete Math →
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h1 className="text-3xl font-bold text-foreground">Rules of Inference Playground</h1>
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
Practice applying resolution and equivalence rules to derive conclusions step by step.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<RulesOfInferencePlayground onComplete={setIsCompleted} />
|
||||||
|
|
||||||
|
<SocialShare
|
||||||
|
title="Rules of Inference Playground - Interactive Logic Learning"
|
||||||
|
description="Practice applying resolution and equivalence rules to derive conclusions step by step in this interactive logic playground."
|
||||||
|
url={window.location.href}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RulesOfInferencePlaygroundPage;
|
||||||
|
|
@ -59,7 +59,7 @@ const interactives: Interactive[] = [{
|
||||||
description: "Practice applying resolution and equivalence rules to derive conclusions step by step.",
|
description: "Practice applying resolution and equivalence rules to derive conclusions step by step.",
|
||||||
tags: ["logic", "proofs", "inference", "resolution", "deduction"],
|
tags: ["logic", "proofs", "inference", "resolution", "deduction"],
|
||||||
component: RulesOfInferencePlayground,
|
component: RulesOfInferencePlayground,
|
||||||
greenScreenPath: "/themes/discrete-math/foundations"
|
greenScreenPath: "/discrete-math/foundations/rules-of-inference"
|
||||||
}];
|
}];
|
||||||
const Foundations = () => {
|
const Foundations = () => {
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue