Skip to content

Commit 73f88c4

Browse files
committed
Merge remote-tracking branch 'origin/simon' into language-validation
2 parents 8028224 + 4a67b78 commit 73f88c4

16 files changed

Lines changed: 226 additions & 313 deletions
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>devs-sesa-beginner-hackathon-2026</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "devs-sesa-beginner-hackathon-2026",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc -b && vite build",
9+
"lint": "eslint .",
10+
"preview": "vite preview"
11+
},
12+
"dependencies": {
13+
"react": "^19.2.4",
14+
"react-dom": "^19.2.4",
15+
"react-router": "^7.14.1"
16+
},
17+
"devDependencies": {
18+
"@eslint/js": "^9.39.4",
19+
"@types/node": "^24.12.2",
20+
"@types/react": "^19.2.14",
21+
"@types/react-dom": "^19.2.3",
22+
"@vitejs/plugin-react": "^6.0.1",
23+
"eslint": "^9.39.4",
24+
"eslint-plugin-react-hooks": "^7.0.1",
25+
"eslint-plugin-react-refresh": "^0.5.2",
26+
"globals": "^17.4.0",
27+
"typescript": "~6.0.2",
28+
"typescript-eslint": "^8.58.0",
29+
"vite": "^8.0.4"
30+
}
31+
}

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
</head>
99
<body>
1010
<div id="root"></div>
11+
<script src="https://cdn.jsdelivr.net/pyodide/v0.27.0/full/pyodide.js"></script>
1112
<script type="module" src="/src/main.tsx"></script>
1213
</body>
1314
</html>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Routes, Route } from "react-router";
2+
import Home from "./pages/home/Home";
3+
4+
// Defines which URL path corresponds to which page component.
5+
function App() {
6+
return (
7+
<Routes>
8+
<Route path="/" element={<Home />} />
9+
</Routes>
10+
);
11+
}
12+
13+
export default App;

src/.ipynb_checkpoints/index-checkpoint.css

Whitespace-only changes.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { StrictMode } from "react";
2+
import { createRoot } from "react-dom/client";
3+
import { HashRouter } from "react-router";
4+
import App from "./App";
5+
import "./index.css";
6+
7+
// Entry point of the application.
8+
createRoot(document.getElementById("root")!).render(
9+
<StrictMode>
10+
<HashRouter>
11+
<App />
12+
</HashRouter>
13+
</StrictMode>,
14+
);

src/App.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import { Routes, Route } from "react-router";
22
import Home from "./pages/home/Home";
3-
import ApiExample from "./pages/api-example/ApiExample";
43

54
// Defines which URL path corresponds to which page component.
65
function App() {
76
return (
87
<Routes>
98
<Route path="/" element={<Home />} />
10-
<Route path="/api-example" element={<ApiExample />} />
119
</Routes>
1210
);
1311
}

src/components/LevelComponent.tsx

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import React, { useState, useEffect, useRef } from 'react'
2+
3+
export default function LevelComponent() {
4+
const [code, setCode] = useState("Enter code here!")
5+
const [output, setOutput] = useState("")
6+
const [pyodideReady, setPyodideReady] = useState(false)
7+
const pyodideRef = useRef<any>(null)
8+
9+
// Load Pyodide on mount
10+
useEffect(() => {
11+
const loadPyodide = async () => {
12+
// @ts-ignore
13+
pyodideRef.current = await window.loadPyodide()
14+
setPyodideReady(true)
15+
}
16+
loadPyodide()
17+
}, [])
18+
19+
const runCode = async () => {
20+
if (!pyodideRef.current) return
21+
22+
// Capture stdout
23+
await pyodideRef.current.runPythonAsync(`
24+
import sys
25+
import io
26+
sys.stdout = io.StringIO()
27+
`)
28+
29+
try {
30+
await pyodideRef.current.runPythonAsync(code)
31+
const result = await pyodideRef.current.runPythonAsync(`sys.stdout.getvalue()`)
32+
setOutput(result)
33+
} catch (err: any) {
34+
setOutput(err.message)
35+
}
36+
}
37+
38+
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
39+
if (e.key === "Tab") {
40+
e.preventDefault()
41+
const el = e.target as HTMLTextAreaElement
42+
const { selectionStart, selectionEnd } = el
43+
const newValue = code.slice(0, selectionStart) + " " + code.slice(selectionEnd)
44+
setCode(newValue)
45+
requestAnimationFrame(() => {
46+
el.selectionStart = el.selectionEnd = selectionStart + 4
47+
})
48+
}
49+
}
50+
51+
return (
52+
<div className="w-screen h-screen grid grid-cols-2 font-mono bg-gray-100">
53+
54+
{/* Left panel */}
55+
<div className="flex flex-col gap-3 p-4">
56+
<div className="flex gap-3">
57+
<div className="flex-1 bg-green-950 border-2 border-white rounded-2xl p-3 text-white">
58+
<div className="italic font-bold mb-2">PYTHON CODE</div>
59+
<pre className="text-sm leading-relaxed m-0">
60+
{`nums = [1,2,3]
61+
sum = 0
62+
for i in nums:
63+
sum += i
64+
print(sum)`}
65+
</pre>
66+
</div>
67+
<div className="flex-1 bg-green-950 border-[3px] border-white rounded-2xl p-3 text-white">
68+
<div className="italic font-bold mb-2">ALIEN CODE</div>
69+
<pre className="text-sm leading-relaxed m-0">
70+
{`plz make nums [1,2,3] ty
71+
plz make sums 0 ty
72+
plz i go through nums ty
73+
plz add i to sum ty
74+
plz print sum ty`}
75+
</pre>
76+
</div>
77+
</div>
78+
<div className="bg-green-950 rounded-lg px-5 py-4 text-white text-sm">
79+
GOAL: IN <strong className="font-mono">ALIEN CODE</strong>, print the square of all numbers.
80+
</div>
81+
82+
{/* Output */}
83+
<div className="bg-zinc-900 rounded-lg p-4 text-green-400 text-sm font-mono h-32 overflow-auto">
84+
<div className="text-zinc-500 mb-1">Output:</div>
85+
<pre>{output}</pre>
86+
</div>
87+
88+
</div>
89+
90+
{/* Right panel */}
91+
<div className="flex flex-col gap-3 m-4">
92+
93+
{/* Editor */}
94+
<div className="flex-1 bg-zinc-700 rounded-lg overflow-hidden">
95+
<textarea
96+
value={code}
97+
onChange={(e) => setCode(e.target.value)}
98+
onKeyDown={handleKeyDown}
99+
spellCheck={false}
100+
className="w-full h-full bg-transparent text-white text-sm font-mono p-4 resize-none outline-none"
101+
/>
102+
</div>
103+
104+
{/* Run button */}
105+
<button
106+
onClick={runCode}
107+
disabled={!pyodideReady}
108+
className="bg-green-700 hover:bg-green-600 disabled:bg-zinc-500 text-white font-bold py-2 rounded-lg"
109+
>
110+
{pyodideReady ? "Run" : "Loading Python..."}
111+
</button>
112+
113+
</div>
114+
115+
</div>
116+
)
117+
}

src/index.css

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1 @@
1-
body {
2-
margin: 0;
3-
font-family: sans-serif;
4-
background-color: #0f172a;
5-
color: white;
6-
}
7-
8-
.page {
9-
max-width: 1100px;
10-
margin: 0 auto;
11-
padding: 60px 40px;
12-
}
1+
@import "tailwindcss";

src/pages/api-example/ApiExample.module.css

Lines changed: 0 additions & 102 deletions
This file was deleted.

0 commit comments

Comments
 (0)