mirror of
https://github.com/johndoe6345789/snippet-pastebin.git
synced 2026-04-24 13:34:55 +00:00
Generated by Spark: Find a way to make it run Python code - my dad likes to do Euler problems and other code challenges. Maybe there's a good node lib that can simulate Python 3. Add some Python examples to template lib.
This commit is contained in:
28
PRD.md
28
PRD.md
@@ -26,18 +26,18 @@ A code snippet management application with an integrated component library showc
|
||||
- Success criteria: Snippet appears in grid immediately with proper syntax highlighting
|
||||
|
||||
**Snippet Viewing**
|
||||
- Functionality: Full-screen viewer with syntax highlighting, split-screen live preview for React code, and copy functionality
|
||||
- Purpose: Easy reading, testing, and copying of saved snippets
|
||||
- Functionality: Full-screen viewer with syntax highlighting, split-screen live preview for React code, Python execution for Python code, and copy functionality
|
||||
- Purpose: Easy reading, testing, executing, and copying of saved snippets
|
||||
- Trigger: Click on any snippet card
|
||||
- Progression: User clicks snippet → Full viewer opens → User reads code → Toggles preview if available → Copies if needed → Closes viewer
|
||||
- Success criteria: Code displays with proper formatting, live preview renders React components accurately, copy works reliably
|
||||
- Progression: User clicks snippet → Full viewer opens → User reads code → Toggles preview/execution if available → Copies if needed → Closes viewer
|
||||
- Success criteria: Code displays with proper formatting, live preview renders React components accurately, Python code executes with output display, copy works reliably
|
||||
|
||||
**Split-Screen Code Editor with Live Preview**
|
||||
- Functionality: Interactive code editor with live React component preview, resizable panels, and view mode switching (code-only, split, preview-only)
|
||||
- Purpose: Enable real-time testing and visualization of React code while editing
|
||||
- Trigger: Enable "Enable split-screen preview" checkbox when creating/editing JSX/TSX/JavaScript/TypeScript snippets
|
||||
- Progression: User enables preview → Split editor appears → User types code → Preview updates in real-time → User adjusts panel sizes or switches view modes → Saves snippet
|
||||
- Success criteria: Preview updates within 100ms of code changes, no lag during typing, error messages display clearly with AI help option
|
||||
**Split-Screen Code Editor with Live Preview/Execution**
|
||||
- Functionality: Interactive code editor with live React component preview for React code, Python execution for Python snippets, resizable panels, and view mode switching (code-only, split, preview/output-only)
|
||||
- Purpose: Enable real-time testing and visualization of React code and Python execution while editing
|
||||
- Trigger: Enable "Enable split-screen preview" checkbox when creating/editing JSX/TSX/JavaScript/TypeScript/Python snippets
|
||||
- Progression: User enables preview → Split editor appears → User types code → Preview/output updates in real-time → User adjusts panel sizes or switches view modes → Saves snippet
|
||||
- Success criteria: React preview updates within 100ms of code changes, Python code executes reliably using Pyodide (WebAssembly Python), no lag during typing, error messages display clearly with AI help option
|
||||
|
||||
**Snippet Organization**
|
||||
- Functionality: Real-time search across title, description, language, and code content
|
||||
@@ -60,11 +60,11 @@ A code snippet management application with an integrated component library showc
|
||||
- Success criteria: Demo loads with working example code, users can edit and see instant changes, educational cards explain key features
|
||||
|
||||
**Database Management & Settings**
|
||||
- Functionality: Settings page with storage backend selection (IndexedDB or Flask), database statistics, backup/restore, and data migration
|
||||
- Purpose: Enable users to choose between local browser storage or remote Flask backend, manage their data, export/import snippets, and migrate between storage backends
|
||||
- Functionality: Settings page with storage backend selection (IndexedDB or Flask), database statistics, backup/restore, data migration, and Python template library with Project Euler examples
|
||||
- Purpose: Enable users to choose between local browser storage or remote Flask backend, manage their data, export/import snippets, migrate between storage backends, and quickly load Python coding challenge examples
|
||||
- Trigger: Navigate to "Settings" via hamburger menu
|
||||
- Progression: User opens settings → Selects storage backend (IndexedDB or Flask) → Configures Flask URL if needed → Tests connection → Migrates data if switching backends → Views database stats → Exports backup if needed → Can import previous backups → Manages sample data → Can clear all data if needed
|
||||
- Success criteria: Backend switching works seamlessly, Flask connection test validates server availability, data migration preserves all snippets, shows accurate statistics, export creates valid .db file, import restores data correctly, clear operation requires confirmation
|
||||
- Progression: User opens settings → Selects storage backend (IndexedDB or Flask) → Configures Flask URL if needed → Tests connection → Migrates data if switching backends → Views database stats → Exports backup if needed → Can import previous backups → Loads Python Euler problem templates → Manages sample data → Can clear all data if needed
|
||||
- Success criteria: Backend switching works seamlessly, Flask connection test validates server availability, data migration preserves all snippets, shows accurate statistics, export creates valid .db file, import restores data correctly, Python templates load successfully, clear operation requires confirmation
|
||||
|
||||
## Data Persistence
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>CodeSnippet - Share & Organize Code</title>
|
||||
<title>CodeSnippet - Share & Run Code (Python, React & More)</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:wght@400;500;600;700&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
|
||||
15
package-lock.json
generated
15
package-lock.json
generated
@@ -58,6 +58,7 @@
|
||||
"marked": "^15.0.7",
|
||||
"next-themes": "^0.4.6",
|
||||
"octokit": "^4.1.2",
|
||||
"pyodide": "^0.29.1",
|
||||
"react": "^19.0.0",
|
||||
"react-day-picker": "^9.6.7",
|
||||
"react-dom": "^19.0.0",
|
||||
@@ -8495,6 +8496,19 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pyodide": {
|
||||
"version": "0.29.1",
|
||||
"resolved": "https://registry.npmjs.org/pyodide/-/pyodide-0.29.1.tgz",
|
||||
"integrity": "sha512-mpk9jtkiM7Ugh1r9P9dbR8vKrmf0lED32hBZq+Fn1kkkBiUoOjSsJEWcyprugICpiFpIXpUOf80ZrvFXkQMk2g==",
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
"@types/emscripten": "^1.41.4",
|
||||
"ws": "^8.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||
@@ -10288,7 +10302,6 @@
|
||||
"version": "8.18.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
||||
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"marked": "^15.0.7",
|
||||
"next-themes": "^0.4.6",
|
||||
"octokit": "^4.1.2",
|
||||
"pyodide": "^0.29.1",
|
||||
"react": "^19.0.0",
|
||||
"react-day-picker": "^9.6.7",
|
||||
"react-dom": "^19.0.0",
|
||||
|
||||
@@ -89,7 +89,8 @@ function AppContent() {
|
||||
<footer className="border-t border-border mt-24">
|
||||
<div className="container mx-auto px-6 py-8">
|
||||
<div className="text-center text-sm text-muted-foreground">
|
||||
<p>Save, organize, and share your code snippets with beautiful syntax highlighting</p>
|
||||
<p>Save, organize, and share your code snippets with beautiful syntax highlighting and live execution</p>
|
||||
<p className="mt-2 text-xs">Supports React preview and Python execution via Pyodide</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
123
src/components/PythonOutput.tsx
Normal file
123
src/components/PythonOutput.tsx
Normal file
@@ -0,0 +1,123 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
import { Play, CircleNotch } from '@phosphor-icons/react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { runPythonCode, getPyodide, isPyodideReady } from '@/lib/pyodide-runner'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
interface PythonOutputProps {
|
||||
code: string
|
||||
}
|
||||
|
||||
export function PythonOutput({ code }: PythonOutputProps) {
|
||||
const [output, setOutput] = useState<string>('')
|
||||
const [error, setError] = useState<string>('')
|
||||
const [isRunning, setIsRunning] = useState(false)
|
||||
const [isInitializing, setIsInitializing] = useState(!isPyodideReady())
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPyodideReady()) {
|
||||
setIsInitializing(true)
|
||||
getPyodide()
|
||||
.then(() => {
|
||||
setIsInitializing(false)
|
||||
toast.success('Python environment ready!')
|
||||
})
|
||||
.catch((err) => {
|
||||
setIsInitializing(false)
|
||||
toast.error('Failed to load Python environment')
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleRun = async () => {
|
||||
if (isInitializing) {
|
||||
toast.info('Python environment is still loading...')
|
||||
return
|
||||
}
|
||||
|
||||
setIsRunning(true)
|
||||
setOutput('')
|
||||
setError('')
|
||||
|
||||
try {
|
||||
const result = await runPythonCode(code)
|
||||
setOutput(result.output)
|
||||
if (result.error) {
|
||||
setError(result.error)
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : String(err))
|
||||
} finally {
|
||||
setIsRunning(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full bg-card">
|
||||
<div className="flex items-center justify-between p-4 border-b border-border">
|
||||
<h3 className="text-sm font-semibold text-foreground">Python Output</h3>
|
||||
<Button
|
||||
onClick={handleRun}
|
||||
disabled={isRunning || isInitializing}
|
||||
size="sm"
|
||||
className="gap-2"
|
||||
>
|
||||
{isRunning || isInitializing ? (
|
||||
<>
|
||||
<CircleNotch className="animate-spin" size={16} />
|
||||
{isInitializing ? 'Loading...' : 'Running...'}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Play size={16} weight="fill" />
|
||||
Run
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-auto p-4">
|
||||
{!output && !error && (
|
||||
<div className="flex items-center justify-center h-full text-muted-foreground text-sm">
|
||||
Click "Run" to execute the Python code
|
||||
</div>
|
||||
)}
|
||||
|
||||
{output && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<Card className="p-4 bg-background">
|
||||
<pre className="text-sm font-mono whitespace-pre-wrap text-foreground">
|
||||
{output}
|
||||
</pre>
|
||||
</Card>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
className="mt-4"
|
||||
>
|
||||
<Card className="p-4 bg-destructive/10 border-destructive/20">
|
||||
<div className="flex items-start gap-2">
|
||||
<div className="text-destructive font-semibold text-sm">Error:</div>
|
||||
<pre className="text-sm font-mono whitespace-pre-wrap text-destructive flex-1">
|
||||
{error}
|
||||
</pre>
|
||||
</div>
|
||||
</Card>
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { Copy, Pencil, X, Check, SplitVertical } from '@phosphor-icons/react'
|
||||
import { Snippet } from '@/lib/types'
|
||||
import { MonacoEditor } from '@/components/MonacoEditor'
|
||||
import { ReactPreview } from '@/components/ReactPreview'
|
||||
import { PythonOutput } from '@/components/PythonOutput'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useState } from 'react'
|
||||
import { strings, appConfig, LANGUAGE_COLORS } from '@/lib/config'
|
||||
@@ -40,6 +41,7 @@ export function SnippetViewer({ snippet, open, onOpenChange, onEdit, onCopy }: S
|
||||
}
|
||||
|
||||
const canPreview = snippet.hasPreview && appConfig.previewEnabledLanguages.includes(snippet.language)
|
||||
const isPython = snippet.language === 'Python'
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
@@ -134,12 +136,16 @@ export function SnippetViewer({ snippet, open, onOpenChange, onEdit, onCopy }: S
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<ReactPreview
|
||||
code={snippet.code}
|
||||
language={snippet.language}
|
||||
functionName={snippet.functionName}
|
||||
inputParameters={snippet.inputParameters}
|
||||
/>
|
||||
{isPython ? (
|
||||
<PythonOutput code={snippet.code} />
|
||||
) : (
|
||||
<ReactPreview
|
||||
code={snippet.code}
|
||||
language={snippet.language}
|
||||
functionName={snippet.functionName}
|
||||
inputParameters={snippet.inputParameters}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { MonacoEditor } from '@/components/MonacoEditor'
|
||||
import { ReactPreview } from '@/components/ReactPreview'
|
||||
import { PythonOutput } from '@/components/PythonOutput'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'
|
||||
import { Code, Eye, SplitHorizontal } from '@phosphor-icons/react'
|
||||
@@ -27,7 +28,8 @@ export function SplitScreenEditor({
|
||||
}: SplitScreenEditorProps) {
|
||||
const [viewMode, setViewMode] = useState<ViewMode>('split')
|
||||
|
||||
const isPreviewSupported = ['JSX', 'TSX', 'JavaScript', 'TypeScript'].includes(language)
|
||||
const isPreviewSupported = ['JSX', 'TSX', 'JavaScript', 'TypeScript', 'Python'].includes(language)
|
||||
const isPython = language === 'Python'
|
||||
|
||||
if (!isPreviewSupported) {
|
||||
return (
|
||||
@@ -69,7 +71,7 @@ export function SplitScreenEditor({
|
||||
className="gap-2 h-8"
|
||||
>
|
||||
<Eye className="h-4 w-4" />
|
||||
<span className="hidden sm:inline">Preview</span>
|
||||
<span className="hidden sm:inline">{isPython ? 'Output' : 'Preview'}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -88,12 +90,16 @@ export function SplitScreenEditor({
|
||||
)}
|
||||
|
||||
{viewMode === 'preview' && (
|
||||
<ReactPreview
|
||||
code={value}
|
||||
language={language}
|
||||
functionName={functionName}
|
||||
inputParameters={inputParameters}
|
||||
/>
|
||||
isPython ? (
|
||||
<PythonOutput code={value} />
|
||||
) : (
|
||||
<ReactPreview
|
||||
code={value}
|
||||
language={language}
|
||||
functionName={functionName}
|
||||
inputParameters={inputParameters}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
|
||||
{viewMode === 'split' && (
|
||||
@@ -108,12 +114,16 @@ export function SplitScreenEditor({
|
||||
</ResizablePanel>
|
||||
<ResizableHandle withHandle />
|
||||
<ResizablePanel defaultSize={50} minSize={30}>
|
||||
<ReactPreview
|
||||
code={value}
|
||||
language={language}
|
||||
functionName={functionName}
|
||||
inputParameters={inputParameters}
|
||||
/>
|
||||
{isPython ? (
|
||||
<PythonOutput code={value} />
|
||||
) : (
|
||||
<ReactPreview
|
||||
code={value}
|
||||
language={language}
|
||||
functionName={functionName}
|
||||
inputParameters={inputParameters}
|
||||
/>
|
||||
)}
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
)}
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
"border": "border-gray-500/30"
|
||||
}
|
||||
},
|
||||
"previewEnabledLanguages": ["JSX", "TSX", "JavaScript", "TypeScript"],
|
||||
"previewEnabledLanguages": ["JSX", "TSX", "JavaScript", "TypeScript", "Python"],
|
||||
"defaultLanguage": "JavaScript",
|
||||
"codePreviewMaxLength": 150,
|
||||
"copiedTimeout": 2000
|
||||
|
||||
@@ -116,5 +116,68 @@
|
||||
"language": "CSS",
|
||||
"category": "layout",
|
||||
"code": ".grid-container {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 2rem;\n padding: 2rem;\n}\n\n.grid-item {\n padding: 1.5rem;\n border-radius: 0.5rem;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n}\n\n.featured {\n grid-column: span 2;\n}\n\n@media (max-width: 768px) {\n .featured {\n grid-column: span 1;\n }\n}"
|
||||
},
|
||||
{
|
||||
"id": "python-euler-1",
|
||||
"title": "Project Euler #1: Multiples of 3 or 5",
|
||||
"description": "Find the sum of all multiples of 3 or 5 below 1000",
|
||||
"language": "Python",
|
||||
"category": "euler",
|
||||
"hasPreview": true,
|
||||
"code": "# Project Euler Problem 1\n# Find the sum of all multiples of 3 or 5 below 1000\n\ndef solve_euler_1(limit=1000):\n total = 0\n for i in range(limit):\n if i % 3 == 0 or i % 5 == 0:\n total += i\n return total\n\nresult = solve_euler_1(1000)\nprint(f\"The sum of all multiples of 3 or 5 below 1000 is: {result}\")\n\n# More efficient solution using arithmetic series\ndef solve_euler_1_optimized(limit=1000):\n def sum_divisible_by(n):\n p = (limit - 1) // n\n return n * p * (p + 1) // 2\n \n return sum_divisible_by(3) + sum_divisible_by(5) - sum_divisible_by(15)\n\nresult_optimized = solve_euler_1_optimized(1000)\nprint(f\"Optimized solution: {result_optimized}\")"
|
||||
},
|
||||
{
|
||||
"id": "python-euler-2",
|
||||
"title": "Project Euler #2: Even Fibonacci Numbers",
|
||||
"description": "Find the sum of even-valued Fibonacci numbers not exceeding 4 million",
|
||||
"language": "Python",
|
||||
"category": "euler",
|
||||
"hasPreview": true,
|
||||
"code": "# Project Euler Problem 2\n# Find the sum of even-valued Fibonacci numbers not exceeding 4 million\n\ndef solve_euler_2(limit=4_000_000):\n a, b = 1, 2\n total = 0\n \n while a <= limit:\n if a % 2 == 0:\n total += a\n a, b = b, a + b\n \n return total\n\nresult = solve_euler_2(4_000_000)\nprint(f\"The sum of even Fibonacci numbers not exceeding 4 million is: {result}\")\n\n# Show the first few even Fibonacci numbers\nprint(\"\\nFirst 10 even Fibonacci numbers:\")\na, b = 1, 2\ncount = 0\nwhile count < 10:\n if a % 2 == 0:\n print(f\" {count + 1}. {a}\")\n count += 1\n a, b = b, a + b"
|
||||
},
|
||||
{
|
||||
"id": "python-euler-6",
|
||||
"title": "Project Euler #6: Sum Square Difference",
|
||||
"description": "Find the difference between sum of squares and square of sum",
|
||||
"language": "Python",
|
||||
"category": "euler",
|
||||
"hasPreview": true,
|
||||
"code": "# Project Euler Problem 6\n# Find the difference between the sum of the squares of the first 100 natural numbers\n# and the square of the sum\n\ndef solve_euler_6(n=100):\n # Sum of squares: 1^2 + 2^2 + ... + n^2\n sum_of_squares = sum(i**2 for i in range(1, n + 1))\n \n # Square of sum: (1 + 2 + ... + n)^2\n square_of_sum = sum(range(1, n + 1)) ** 2\n \n difference = square_of_sum - sum_of_squares\n \n return sum_of_squares, square_of_sum, difference\n\nsum_sq, sq_sum, diff = solve_euler_6(100)\nprint(f\"Sum of squares (1² + 2² + ... + 100²) = {sum_sq}\")\nprint(f\"Square of sum (1 + 2 + ... + 100)² = {sq_sum}\")\nprint(f\"Difference = {diff}\")\n\n# Using mathematical formulas for efficiency\ndef solve_euler_6_optimized(n=100):\n # Formula: sum of squares = n(n+1)(2n+1)/6\n sum_of_squares = n * (n + 1) * (2 * n + 1) // 6\n \n # Formula: sum = n(n+1)/2, so square of sum = [n(n+1)/2]^2\n square_of_sum = (n * (n + 1) // 2) ** 2\n \n return square_of_sum - sum_of_squares\n\nprint(f\"\\nOptimized solution: {solve_euler_6_optimized(100)}\")"
|
||||
},
|
||||
{
|
||||
"id": "python-fibonacci",
|
||||
"title": "Fibonacci Sequence Generator",
|
||||
"description": "Generate Fibonacci numbers using different approaches",
|
||||
"language": "Python",
|
||||
"category": "algorithms",
|
||||
"hasPreview": true,
|
||||
"code": "# Generate Fibonacci sequence using different methods\n\n# Method 1: Iterative\ndef fibonacci_iterative(n):\n if n <= 0:\n return []\n elif n == 1:\n return [0]\n \n fib = [0, 1]\n for i in range(2, n):\n fib.append(fib[i-1] + fib[i-2])\n return fib\n\nprint(\"First 15 Fibonacci numbers (iterative):\")\nprint(fibonacci_iterative(15))\n\n# Method 2: Generator (memory efficient)\ndef fibonacci_generator(n):\n a, b = 0, 1\n count = 0\n while count < n:\n yield a\n a, b = b, a + b\n count += 1\n\nprint(\"\\nFirst 15 Fibonacci numbers (generator):\")\nprint(list(fibonacci_generator(15)))\n\n# Method 3: Recursive (with memoization)\ndef fibonacci_recursive(n, memo={}):\n if n in memo:\n return memo[n]\n if n <= 1:\n return n\n memo[n] = fibonacci_recursive(n-1, memo) + fibonacci_recursive(n-2, memo)\n return memo[n]\n\nprint(\"\\n20th Fibonacci number (recursive with memoization):\")\nprint(fibonacci_recursive(20))"
|
||||
},
|
||||
{
|
||||
"id": "python-prime-numbers",
|
||||
"title": "Prime Number Generator",
|
||||
"description": "Find prime numbers using the Sieve of Eratosthenes",
|
||||
"language": "Python",
|
||||
"category": "algorithms",
|
||||
"hasPreview": true,
|
||||
"code": "# Prime number algorithms\n\n# Method 1: Simple prime checker\ndef is_prime(n):\n if n < 2:\n return False\n if n == 2:\n return True\n if n % 2 == 0:\n return False\n \n # Check odd divisors up to sqrt(n)\n i = 3\n while i * i <= n:\n if n % i == 0:\n return False\n i += 2\n return True\n\nprint(\"Prime numbers up to 50:\")\nprimes = [n for n in range(2, 51) if is_prime(n)]\nprint(primes)\n\n# Method 2: Sieve of Eratosthenes (efficient for finding many primes)\ndef sieve_of_eratosthenes(limit):\n if limit < 2:\n return []\n \n # Create a boolean array and initialize all as true\n is_prime = [True] * (limit + 1)\n is_prime[0] = is_prime[1] = False\n \n p = 2\n while p * p <= limit:\n if is_prime[p]:\n # Mark all multiples of p as not prime\n for i in range(p * p, limit + 1, p):\n is_prime[i] = False\n p += 1\n \n return [i for i in range(limit + 1) if is_prime[i]]\n\nprint(\"\\nFirst 25 primes using Sieve:\")\nall_primes = sieve_of_eratosthenes(100)\nprint(all_primes[:25])\nprint(f\"\\nTotal primes up to 100: {len(all_primes)}\")"
|
||||
},
|
||||
{
|
||||
"id": "python-data-structures",
|
||||
"title": "Python Data Structures Demo",
|
||||
"description": "Working with lists, dictionaries, sets, and tuples",
|
||||
"language": "Python",
|
||||
"category": "basics",
|
||||
"hasPreview": true,
|
||||
"code": "# Python data structures examples\n\n# Lists (mutable, ordered)\nfruits = ['apple', 'banana', 'cherry', 'date']\nprint(\"Lists:\")\nprint(f\" Original: {fruits}\")\nfruits.append('elderberry')\nprint(f\" After append: {fruits}\")\nprint(f\" Second item: {fruits[1]}\")\n\n# Dictionaries (key-value pairs)\nperson = {\n 'name': 'Alice',\n 'age': 30,\n 'city': 'New York',\n 'hobbies': ['reading', 'coding', 'hiking']\n}\nprint(\"\\nDictionaries:\")\nprint(f\" Person: {person}\")\nprint(f\" Name: {person['name']}\")\nprint(f\" Hobbies: {', '.join(person['hobbies'])}\")\n\n# Sets (unique, unordered)\nnumbers = {1, 2, 3, 4, 5, 3, 2, 1}\nprint(\"\\nSets (duplicates removed):\")\nprint(f\" Numbers: {numbers}\")\nmore_numbers = {4, 5, 6, 7, 8}\nprint(f\" Union: {numbers | more_numbers}\")\nprint(f\" Intersection: {numbers & more_numbers}\")\n\n# Tuples (immutable, ordered)\ncoordinates = (10, 20)\nprint(\"\\nTuples:\")\nprint(f\" Coordinates: {coordinates}\")\nx, y = coordinates\nprint(f\" x={x}, y={y}\")\n\n# List comprehensions\nsquares = [x**2 for x in range(1, 11)]\nprint(f\"\\nList comprehension (squares): {squares}\")\nevens = [x for x in range(1, 21) if x % 2 == 0]\nprint(f\"Even numbers 1-20: {evens}\")"
|
||||
},
|
||||
{
|
||||
"id": "python-file-operations",
|
||||
"title": "Python File Operations",
|
||||
"description": "Reading and writing files with error handling",
|
||||
"language": "Python",
|
||||
"category": "basics",
|
||||
"hasPreview": true,
|
||||
"code": "# Python file operations (simulated for web environment)\n\n# Note: In a real environment, these would work with actual files\n# Here we demonstrate the patterns\n\nprint(\"File Operations Patterns:\\n\")\n\n# Writing to a file\nprint(\"1. Writing to a file:\")\nfile_content = \"\"\"# Example of writing to a file\ntry:\n with open('example.txt', 'w') as f:\n f.write('Hello, World!\\\\n')\n f.write('This is a second line.\\\\n')\n print(' ✓ File written successfully')\nexcept IOError as e:\n print(f' ✗ Error writing file: {e}')\n\"\"\"\nprint(file_content)\n\n# Reading from a file\nprint(\"\\n2. Reading from a file:\")\nread_example = \"\"\"try:\n with open('example.txt', 'r') as f:\n content = f.read()\n print(content)\nexcept FileNotFoundError:\n print(' ✗ File not found')\nexcept IOError as e:\n print(f' ✗ Error reading file: {e}')\n\"\"\"\nprint(read_example)\n\n# Reading lines\nprint(\"\\n3. Reading line by line:\")\nlines_example = \"\"\"with open('example.txt', 'r') as f:\n for line_num, line in enumerate(f, 1):\n print(f' Line {line_num}: {line.strip()}')\n\"\"\"\nprint(lines_example)\n\n# Demonstrate string operations as alternative\nprint(\"\\n4. Working with text data:\")\ntext_data = \"Hello, World!\\nThis is a second line.\\nAnd a third!\"\nlines = text_data.split('\\n')\nprint(f\" Total lines: {len(lines)}\")\nfor i, line in enumerate(lines, 1):\n print(f\" Line {i}: {line}\")"
|
||||
}
|
||||
]
|
||||
|
||||
66
src/lib/pyodide-runner.ts
Normal file
66
src/lib/pyodide-runner.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { loadPyodide, PyodideInterface } from 'pyodide'
|
||||
|
||||
let pyodideInstance: PyodideInterface | null = null
|
||||
let pyodideLoading: Promise<PyodideInterface> | null = null
|
||||
|
||||
export async function getPyodide(): Promise<PyodideInterface> {
|
||||
if (pyodideInstance) {
|
||||
return pyodideInstance
|
||||
}
|
||||
|
||||
if (pyodideLoading) {
|
||||
return pyodideLoading
|
||||
}
|
||||
|
||||
pyodideLoading = loadPyodide({
|
||||
indexURL: 'https://cdn.jsdelivr.net/pyodide/v0.26.4/full/',
|
||||
}).then((pyodide) => {
|
||||
pyodideInstance = pyodide
|
||||
return pyodide
|
||||
})
|
||||
|
||||
return pyodideLoading
|
||||
}
|
||||
|
||||
export async function runPythonCode(code: string): Promise<{ output: string; error?: string }> {
|
||||
try {
|
||||
const pyodide = await getPyodide()
|
||||
|
||||
pyodide.runPython(`
|
||||
import sys
|
||||
from io import StringIO
|
||||
sys.stdout = StringIO()
|
||||
sys.stderr = StringIO()
|
||||
`)
|
||||
|
||||
let result: any
|
||||
try {
|
||||
result = await pyodide.runPythonAsync(code)
|
||||
} catch (err) {
|
||||
const stderr = pyodide.runPython('sys.stderr.getvalue()')
|
||||
const stdout = pyodide.runPython('sys.stdout.getvalue()')
|
||||
return {
|
||||
output: stdout || '',
|
||||
error: stderr || (err instanceof Error ? err.message : String(err))
|
||||
}
|
||||
}
|
||||
|
||||
const stdout = pyodide.runPython('sys.stdout.getvalue()')
|
||||
|
||||
let output = stdout || ''
|
||||
if (result !== undefined && result !== null) {
|
||||
output += (output ? '\n' : '') + String(result)
|
||||
}
|
||||
|
||||
return { output: output || '(no output)' }
|
||||
} catch (err) {
|
||||
return {
|
||||
output: '',
|
||||
error: err instanceof Error ? err.message : String(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isPyodideReady(): boolean {
|
||||
return pyodideInstance !== null
|
||||
}
|
||||
Reference in New Issue
Block a user