diff --git a/EXERCISE_CONTRIBUTION_GUIDE.md b/EXERCISE_CONTRIBUTION_GUIDE.md new file mode 100644 index 000000000..092ace57f --- /dev/null +++ b/EXERCISE_CONTRIBUTION_GUIDE.md @@ -0,0 +1,162 @@ +# Guide to Adding or Editing Starklings Exercises + +This guide will help you add new exercises or edit existing ones in the Starklings project, an interactive platform to learn Cairo and Starknet. + +## 📁 Project Structure + +Starklings exercises are organized as follows: + +``` +starklings/ +├── exercises/ # 📂 Main exercises directory +│ ├── arrays/ # 📂 Array exercises +│ ├── variables/ # 📂 Variable exercises +│ ├── functions/ # 📂 Function exercises +│ ├── starknet/ # 📂 Starknet-specific exercises +│ └── ... # 📂 Other categories +├── info.toml # ⚙️ Exercises and hints configuration +``` + +## 🔧 Exercise Components + +Each exercise in Starklings has **3 main components**: + +### 1. 📄 Exercise File (`.cairo`) +- **Location**: `exercises//.cairo` +- **Contains**: Cairo code with descriptive comments and the marker `// I AM NOT DONE` + +### 2. 📝 Configuration in `info.toml` +- **Location**: `info.toml` (project root) +- **Contains**: Exercise metadata, execution mode, and hints + +📋 **Prerequisites:** +• You must have the project forked in your GitHub account +• Your fork must be synced with the main repository + +## ✏️ Editing an Existing Exercise + +### Edit the Exercise Description + +To change the description of an exercise (for example, `arrays1.cairo`): + +1. **Open the exercise file:** + ```bash + exercises/arrays/arrays1.cairo + ``` + +2. **Edit the comments at the top of the file:** + ```cairo + // Your new exercise description here + // Explain what the student should do + // You can use multiple comment lines + + // I AM NOT DONE ← This marker must stay + + fn create_array() -> Array { + // ... exercise code + } + ``` + +**⚠️ Important:** +- Only edit the comments at the top of the file +- **Do NOT remove** the `// I AM NOT DONE` line (it's needed for the system) +- Use `//` for all descriptions + +### Edit the Exercise Hint + +To change the hint shown to students: + +1. **Open the configuration file:** + ```bash + info.toml + ``` + +2. **Find the exercise section:** + ```toml + [[exercises]] + name = "arrays1" + path = "exercises/arrays/arrays1.cairo" + mode = "test" + hint = """ + Your new hint here. + You can use multiple lines. + Give key concepts or subtle tips. + """ + ``` + +## ➕ Adding a New Exercise + +### Step 1: Create the Exercise File + +1. **Go to the right category** (or create a new one): + ```bash + cd exercises// + ``` + +2. **Create the `.cairo` file:** + ```cairo + // Clear and concise exercise description + // Explain what concept it teaches + // Give specific instructions + + // I AM NOT DONE + + fn example_exercise() { + // Starter code with blanks or errors + // for the student to complete + } + + // Test or verification code + #[test] + fn test_example() { + // Tests to validate the solution + } + ``` + +### Step 2: Configure in `info.toml` + +1. **Open `info.toml`** and find your category section + +2. **Add the exercise configuration:** + ```toml + [[exercises]] + name = "new_exercise" # Unique exercise name + path = "exercises/category/new_exercise.cairo" # Path to the file + mode = "test" # "test", "run", or "build" + hint = """ + Helpful hint for the student. + Can include: + - Links to docs: https://book.cairo-lang.org/... + - Key concepts to remember + - Tips about the solution (not the full answer) + """ + ``` + +## 🔄 Exercise Modes + +In `info.toml`, each exercise has a `mode` field that determines how it runs: + +- **`"test"`**: Runs the exercise tests +- **`"run"`**: Runs the main program + +## ✅ Best Practices + +### For Exercise Descriptions: +- 📝 Be clear and concise +- 🎯 Focus on one concept per exercise +- 📚 Mention previous concepts if needed +- 🔍 Give enough context without revealing the solution + +### For Hints: +- 💡 Give tips, not full solutions +- 🔗 Include links to relevant docs +- 📖 Explain key concepts if needed +- 🎯 Be specific about what to look for + +### For Code: +- 🏗️ Include useful starter code +- ✅ Add tests to validate the solution +- 🚫 Keep the `// I AM NOT DONE` marker +- 📦 Import needed dependencies + +With this guide and the quick edit buttons, you can now easily add and edit Starklings exercises! 🚀 diff --git a/app/client/src/components/pages/Workspace/Workspace.tsx b/app/client/src/components/pages/Workspace/Workspace.tsx index 20e31d18e..412c6a6fa 100644 --- a/app/client/src/components/pages/Workspace/Workspace.tsx +++ b/app/client/src/components/pages/Workspace/Workspace.tsx @@ -1,9 +1,16 @@ import { Editor } from "@monaco-editor/react"; import RefreshIcon from "@mui/icons-material/Refresh"; +import { Edit } from "@mui/icons-material"; import { Alert, AlertTitle, Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, IconButton, Link, TextField, @@ -18,6 +25,8 @@ import { useNavigate, useParams, useSearchParams } from "react-router-dom"; import { CURRENT_EXERCISE, EXERCISE_SOLUTION, + GITHUB_ENABLED, + USERNAME, } from "../../../constants/localStorage"; import { useGetExercise } from "../../../queries/useGetExercise"; import { useGetExercises } from "../../../queries/useGetExercises"; @@ -55,6 +64,7 @@ export const Workspace = () => { const navigate = useNavigate(); const [hint, setHint] = useState(undefined); const [warning, setWarning] = useState(undefined); + const [editDialogOpen, setEditDialogOpen] = useState(false); const isTest = data?.mode === "test"; const { mutate: getHint, @@ -91,6 +101,19 @@ export const Workspace = () => { setWarning(undefined); }; + const openEditDialog = () => { + setEditDialogOpen(true); + }; + + const closeEditDialog = () => { + setEditDialogOpen(false); + }; + + const handleEditAction = (action: () => void) => { + closeEditDialog(); + action(); + }; + const handleCompileClick = async () => { let mode; if (data?.mode === "test") { @@ -191,6 +214,41 @@ export const Workspace = () => { setEditorValue(data?.code ?? ""); }; + const handleAddExerciseClick = () => { + window.open("https://github.com/shramee/starklings/blob/main/EXERCISE_CONTRIBUTION_GUIDE.md", "_blank"); + }; + + const handleEditExerciseClick = () => { + if (data?.path) { + const githubUsername = localStorage.getItem(USERNAME); + window.open(`https://github.com/${githubUsername}/starklings/edit/main/${data.path}`, "_blank"); + } + }; + + const handleEditHintClick = async () => { + const githubUsername = localStorage.getItem(USERNAME); + + try { + const response = await fetch(`https://raw.githubusercontent.com/${githubUsername}/starklings/main/info.toml`); + const content = await response.text(); + + const lines = content.split('\n'); + const searchPattern = `name = "${data?.id}"`; + const lineNumber = lines.findIndex(line => line.trim() === searchPattern) + 1; + + if (lineNumber > 0) { + window.open(`https://github.com/${githubUsername}/starklings/edit/main/info.toml#L${lineNumber}`, "_blank"); + } else { + window.open(`https://github.com/${githubUsername}/starklings/edit/main/info.toml`, "_blank"); + } + } catch (error) { + console.error('Error fetching info.toml:', error); + window.open(`https://github.com/${githubUsername}/starklings/edit/main/info.toml`, "_blank"); + } + }; + + const isGitHubConnected = !!localStorage.getItem(GITHUB_ENABLED); + return ( @@ -209,9 +267,21 @@ export const Workspace = () => { > {/* description */} - - {data?.name} - + + + {data?.name} + + + + + + + {isLoading && } {data && ( @@ -378,6 +448,131 @@ export const Workspace = () => { {isMobileOnly && } + + {/* Edit Dialog */} + + + 🛠️ Edit Options - {data?.name} + + + + 📋 Prerequisites: +
+ • You must have the project forked in your GitHub account +
+ • Your fork must be synced with the main repository +
+ • You must be logged into GitHub in Starklings +
+ + + + + {isGitHubConnected && ( + + )} + + {isGitHubConnected && ( + + )} + + {!isGitHubConnected && ( + + + ⚠️ GitHub not connected + + + Connect your GitHub account to access exercise editing options. + + + )} + +
+ + + +
); -}; \ No newline at end of file +};