From 421f637eba46ef3c8169f066efceb0900bba0d44 Mon Sep 17 00:00:00 2001 From: Nicholai Date: Wed, 14 Jan 2026 14:59:00 -0700 Subject: [PATCH] splinky dingus --- .gitignore | 25 ++ App.tsx | 133 ++++++++ README.md | 547 ++++++++++++++++++++++++++++++ components/ContentRenderer.tsx | 138 ++++++++ components/GitWorkflowDiagram.tsx | 183 ++++++++++ components/Sidebar.tsx | 99 ++++++ components/TerminalBlock.tsx | 163 +++++++++ constants.tsx | 244 +++++++++++++ index.html | 154 +++++++++ index.tsx | 15 + metadata.json | 5 + package.json | 26 ++ public/_headers | 14 + tsconfig.json | 29 ++ types.ts | 29 ++ vite.config.ts | 23 ++ wrangler.toml | 6 + 17 files changed, 1833 insertions(+) create mode 100644 .gitignore create mode 100644 App.tsx create mode 100644 README.md create mode 100644 components/ContentRenderer.tsx create mode 100644 components/GitWorkflowDiagram.tsx create mode 100644 components/Sidebar.tsx create mode 100644 components/TerminalBlock.tsx create mode 100644 constants.tsx create mode 100644 index.html create mode 100644 index.tsx create mode 100644 metadata.json create mode 100644 package.json create mode 100644 public/_headers create mode 100644 tsconfig.json create mode 100644 types.ts create mode 100644 vite.config.ts create mode 100644 wrangler.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a2bf63c --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +bun.lock diff --git a/App.tsx b/App.tsx new file mode 100644 index 0000000..9aedb62 --- /dev/null +++ b/App.tsx @@ -0,0 +1,133 @@ +import React, { useLayoutEffect, useRef } from 'react'; +import { Sidebar } from './components/Sidebar'; +import { GUIDE_CONTENT } from './constants'; +import { ContentRenderer } from './components/ContentRenderer'; +import { GitBranch, ArrowDown, Leaf } from 'lucide-react'; +import gsap from 'gsap'; +import { ScrollTrigger } from 'gsap/ScrollTrigger'; + +gsap.registerPlugin(ScrollTrigger); + +const App: React.FC = () => { + const mainRef = useRef(null); + const heroRef = useRef(null); + const titleRef = useRef(null); + const subtitleRef = useRef(null); + + useLayoutEffect(() => { + const ctx = gsap.context(() => { + // Hero Animation + const tl = gsap.timeline(); + + tl.fromTo(titleRef.current, + { y: 50, opacity: 0, rotate: 2 }, + { y: 0, opacity: 1, rotate: 0, duration: 1, ease: "power3.out" } + ) + .fromTo(subtitleRef.current, + { y: 20, opacity: 0 }, + { y: 0, opacity: 1, duration: 0.8, ease: "power2.out" }, + "-=0.5" + ); + + // Section Entry Animations + const sections = gsap.utils.toArray('.guide-section'); + sections.forEach(section => { + gsap.fromTo(section, + { opacity: 0, y: 50 }, + { + opacity: 1, + y: 0, + duration: 0.8, + ease: "power2.out", + scrollTrigger: { + trigger: section, + start: "top 80%", + toggleActions: "play none none reverse" + } + } + ); + }); + }, mainRef); + + return () => ctx.revert(); + }, []); + + return ( +
+ + +
+ {/* Hero Section */} +
+ {/* Subtle blurred blobs */} +
+
+ +
+
+ + Interactive Guide +
+ +

+ Git Guide
+ + for Sylvi 🌿 + +

+ +

+ Welcome! This guide will walk you through version control from the ground up. + Think of it as a time machine for your code—save snapshots, experiment freely, + and never lose your work again. +

+ +
+ + Scroll to start learning +
+
+
+ + {/* Content Sections */} +
+ {GUIDE_CONTENT.map((section, index) => ( +
+
+ + {index + 1} + +

{section.title.split('. ')[1]}

+
+ +
+ {section.blocks.map((block, i) => ( + + ))} +
+ + {index < GUIDE_CONTENT.length - 1 && ( +
+ )} +
+ ))} + + {/* Footer */} +
+

+ + Made for Sylvi +

+

Remember, Nicholai is just a message away if you get stuck!

+
+
+
+
+ ); +}; + +export default App; \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..20d677d --- /dev/null +++ b/README.md @@ -0,0 +1,547 @@ +# Git Guide for Sylvi 🌿 + +Welcome! This guide will walk you through git from the ground up. Git is a version control system that helps you track changes in your projects, collaborate with others, and never lose your work. Think of it as a time machine for your code—you can save snapshots of your project at any point and jump back to them whenever you need. + +## Table of Contents + +1. What is Git? +2. Initial Setup +3. Understanding File Types in Git +4. Creating Your First Repository +5. The Basic Git Workflow +6. Cloning Repositories +7. Branching & Merging +8. Common Pitfalls & How to Fix Them +9. Using Gitea's Web Interface +10. Quick Reference Cheat Sheet + +## 1. What is Git? + +Git is a **version control system**. Imagine you're working on a game design document, and you want to try out a new idea for a level, but you're not sure if it'll work. With git, you can save your current version, try the new idea, and if it doesn't work out, you can go back to exactly where you were before. No "final_FINAL_v3_actually_final.txt" nonsense. + +Git tracks changes to files over time, creating a history of your project. Every time you "save" (which we call a **commit**), git takes a snapshot of your entire project. You can view any of these snapshots at any time, compare them, or even combine changes from different versions. + +## 2. Initial Setup + +First, let's configure git with your information. Open your terminal and run these commands: +```bash +# Set your name (this will appear in your commits) +git config --global user.name "Sylvi" + +# Set your email (use the email you registered with Gitea) +git config --global user.email "your-email@example.com" + +# Set your default text editor (optional, but helpful) +git config --global core.editor "nano" # or vim, code, etc. + +# Check your configuration +git config --list +``` + +**💡 Why This Matters** + +Every change you make in git is tagged with your name and email. This helps everyone (including future you) know who made which changes and when. + +## 3. Understanding File Types in Git + +When working with git, you'll encounter a few special files and formats. Let's break them down: + +### .git Directory + +This hidden folder is where git stores all its magic. It contains the entire history of your project, all your commits, branches, and configuration. You'll never need to edit files in here directly—git handles it all. If you delete this folder, you lose all your git history (but not your current files). + +### .gitignore File + +This file tells git which files or folders to ignore. It's super useful for keeping temporary files, build artifacts, or sensitive data out of your repository. +``` +# Example .gitignore file +# Ignore all .log files +*.log + +# Ignore the node_modules directory +node_modules/ + +# Ignore OS-specific files +.DS_Store +Thumbs.db + +# Ignore your personal config +config/secrets.json +``` + +### README.md + +Not required by git, but it's a convention to include a README file (usually in Markdown format) that explains what your project is, how to use it, and any other important information. This is the first thing people see when they visit your repository. + +### LICENSE + +If you're sharing your code, it's good practice to include a license file that specifies how others can use your work. Common options include MIT, GPL, or Creative Commons licenses. + +### Common File Formats You'll Work With + +- **.md** - Markdown files (like README.md) for documentation +- **.html, .css, .js** - Web development files +- **.json** - Configuration and data files +- **.yml/.yaml** - Configuration files (common in DevOps) +- **.txt** - Plain text files +- **No extension** - Shell scripts, config files (like .gitignore) + +**Binary Files:** Images (.png, .jpg), compiled code, videos, etc. Git can track these, but it can't show you the differences between versions like it can with text files. + +## 4. Creating Your First Repository + +There are two ways to start with git: create a new repository from scratch, or clone an existing one. Let's start with creating one locally. + +### Method 1: Local Repository (Command Line) +```bash +# Create a new directory for your project +mkdir my-awesome-project +cd my-awesome-project + +# Initialize a git repository +git init + +# Check the status (you should see "No commits yet") +git status +``` + +That's it! You now have a git repository. The `git init` command created that `.git` folder we talked about earlier. + +### Method 2: Create on Gitea First (Web Interface) + +You can also create a repository through Gitea's web interface, then clone it to your computer. This is often easier when you want to set up a README, license, or .gitignore right away. + +1. Log into your Gitea account +2. Click the "+" icon or "New Repository" button +3. Give it a name, description, and choose whether it's public or private +4. Optionally add a README, .gitignore template, and license +5. Click "Create Repository" + +Gitea will then show you the commands to clone it to your computer (we'll cover cloning in section 6). + +### Practice Exercise #1 + +Create a new directory called `git-practice` and initialize it as a git repository. Then check its status. + +**Solution:** +```bash +mkdir git-practice +cd git-practice +git init +git status +``` + +You should see a message like "On branch main" (or master) and "No commits yet". + +## 5. The Basic Git Workflow + +The core git workflow has three main stages, and once you understand these, everything else falls into place: + +1. **Working Directory** - Your actual files that you're editing +2. **Staging Area** - Files you've marked to be included in the next commit +3. **Repository** - The committed history of your project + +Here's the typical flow: + +### Step 1: Make Changes + +Create or edit files in your project. +```bash +# Create a new file +echo "# My Awesome Project" > README.md + +# Check what's changed +git status +``` + +Git will show you that `README.md` is an "untracked file." It knows the file exists, but it's not tracking changes to it yet. + +### Step 2: Stage Changes + +Tell git which changes you want to include in the next commit. This is like packing a box before you ship it. +```bash +# Stage a specific file +git add README.md + +# Or stage all changes at once +git add . + +# Check status again +git status +``` + +Now the file shows up under "Changes to be committed." It's in the staging area. + +### Step 3: Commit Changes + +Create a snapshot of your staged changes with a message describing what you did. +```bash +# Commit with a message +git commit -m "Add README file" + +# View your commit history +git log +``` + +**💡 Writing Good Commit Messages** + +Your commit messages should be clear and descriptive. Think of them as notes to your future self (or your collaborators). Good examples: + +- ✅ "Add player movement controls" +- ✅ "Fix collision detection bug in level 3" +- ✅ "Update homepage layout with new color scheme" +- ❌ "stuff" (too vague) +- ❌ "fixed bug" (which bug?) + +### Step 4: Push to Remote + +If you're working with Gitea (or any remote repository), you'll want to push your commits to the server so they're backed up and others can see them. +```bash +# Push your commits to the remote repository +git push origin main + +# Or if your default branch is named 'master' +git push origin master +``` + +**Origin** is the name git gives to your remote repository (the one on Gitea). **Main** (or master) is the name of your primary branch. + +**⚠️ First Push Setup** + +The first time you push to a new repository, you might need to set up the connection: +```bash +# Add your Gitea repository as the remote +git remote add origin https://your-gitea-instance.com/username/repo-name.git + +# Set the default upstream branch +git push -u origin main +``` + +After this initial setup, you can just use `git push`. + +### Step 5: Pull Updates + +If you're collaborating with others (or working on multiple computers), you'll need to pull changes from the remote repository before you start working. +```bash +# Fetch and merge changes from the remote +git pull origin main +``` + +This downloads any new commits from Gitea and merges them into your local repository. + +### Practice Exercise #2 + +In your `git-practice` directory: + +1. Create a file called `index.html` with some basic HTML +2. Stage the file +3. Commit it with a descriptive message +4. View your commit history + +**Solution:** +```bash +# Create the file (you can use your favorite editor instead of echo) +echo "

Hello!

" > index.html + +# Stage it +git add index.html + +# Commit it +git commit -m "Add basic HTML homepage" + +# View history +git log +``` + +## 6. Cloning Repositories + +Cloning is how you download a copy of an existing repository from Gitea (or GitHub, GitLab, etc.) to your computer. It's like getting a complete copy of someone else's project, including all its history. +```bash +# Clone a repository +git clone https://your-gitea-instance.com/username/repo-name.git + +# Clone into a specific directory name +git clone https://your-gitea-instance.com/username/repo-name.git my-local-folder + +# Clone and automatically set up remote tracking +git clone https://your-gitea-instance.com/username/repo-name.git +cd repo-name +git remote -v # Shows your remote connections +``` + +When you clone, git automatically sets up the remote connection for you (it calls it "origin"), so you can immediately start pushing and pulling. + +**💡 HTTPS vs SSH** + +You'll see two types of URLs for cloning: HTTPS (`https://...`) and SSH (`git@...`). HTTPS is simpler to start with—you'll just need to enter your username and password when pushing. SSH is more secure and convenient once set up, but requires generating and adding SSH keys to Gitea. + +### Practice Exercise #3 + +Find a repository on your Gitea instance (maybe one of Nicholai's projects, with permission!) and clone it to your computer. Explore the files and check out the commit history with `git log`. + +## 7. Branching & Merging + +Branches are one of git's most powerful features. They let you work on new features or experiments without affecting the main codebase. Think of them like parallel universes for your project—you can try things out in one branch, and if they don't work, you can just delete that branch without any consequences to your main code. + +### Understanding Branches + +When you create a new repository, you start on a default branch (usually called `main` or `master`). This is your primary timeline. When you create a new branch, you're creating a copy of the current state that you can modify independently. + +### Creating and Switching Branches +```bash +# Create a new branch +git branch new-feature + +# Switch to that branch +git checkout new-feature + +# Or create and switch in one command +git checkout -b new-feature + +# See all your branches +git branch + +# The branch with * is your current branch +``` + +Now any commits you make will be on the `new-feature` branch, not on `main`. + +### Merging Branches + +Once you're happy with your changes on a branch, you can merge them back into your main branch. +```bash +# Switch back to main +git checkout main + +# Merge the new-feature branch into main +git merge new-feature + +# Delete the branch if you're done with it +git branch -d new-feature +``` + +### A Typical Branching Workflow + +1. You're working on `main` and want to add a new feature +2. Create a new branch: `git checkout -b add-menu-system` +3. Make your changes and commit them to this branch +4. Switch back to main: `git checkout main` +5. Merge your feature: `git merge add-menu-system` +6. Delete the feature branch: `git branch -d add-menu-system` + +**⚠️ Merge Conflicts** + +Sometimes, git can't automatically merge branches because the same lines of code were changed in both branches. This is called a **merge conflict**. Don't panic! Git will mark the conflicting sections in your files, and you'll need to manually choose which changes to keep. + +Files with conflicts will look like this: +``` +<<<<<<< HEAD +Your changes on the current branch +======= +Changes from the branch being merged +>>>>>>> new-feature +``` + +Edit the file to keep what you want, remove the markers, then stage and commit the resolved file. + +### Practice Exercise #4 + +In your practice repository: + +1. Create a new branch called `experiment` +2. Switch to it and make some changes to your HTML file +3. Commit those changes +4. Switch back to `main` +5. Merge the `experiment` branch into `main` + +**Solution:** +```bash +git checkout -b experiment +# Edit index.html with your editor +git add index.html +git commit -m "Try experimental layout" +git checkout main +git merge experiment +git branch -d experiment +``` + +## 8. Common Pitfalls & How to Fix Them + +Everyone makes mistakes with git. Here are some common ones and how to recover from them. + +### Mistake #1: Committed to the Wrong Branch + +If you haven't pushed yet: +```bash +# Create a new branch with your current changes +git branch correct-branch + +# Reset the current branch to the previous commit +git reset --hard HEAD~1 + +# Switch to the correct branch +git checkout correct-branch +``` + +### Mistake #2: Want to Undo the Last Commit +```bash +# Undo the last commit but keep the changes +git reset --soft HEAD~1 + +# Undo the last commit and discard the changes (careful!) +git reset --hard HEAD~1 + +# Undo the last commit and create a new commit that reverses it +git revert HEAD +``` + +`revert` is safer if you've already pushed, as it doesn't rewrite history. + +### Mistake #3: Accidentally Staged the Wrong Files +```bash +# Unstage a specific file +git reset HEAD file-name.txt + +# Unstage all files +git reset HEAD +``` + +### Mistake #4: Need to See What Changed +```bash +# See unstaged changes +git diff + +# See staged changes +git diff --staged + +# See changes in a specific file +git diff file-name.txt + +# See changes between commits +git diff commit1 commit2 +``` + +### Mistake #5: Merge Conflict Panic + +If you're in the middle of a merge and want to abort: +```bash +git merge --abort +``` + +To resolve conflicts properly: + +1. Open the conflicting files +2. Look for the conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) +3. Decide which changes to keep and edit the file +4. Remove the conflict markers +5. Stage the resolved file: `git add file-name.txt` +6. Complete the merge: `git commit` + +### Mistake #6: Pushed Sensitive Data (Passwords, Keys, etc.) + +**⚠️ Important Security Warning** + +If you accidentally commit and push sensitive information (passwords, API keys, etc.), removing it from git history isn't enough—you should consider that data compromised. Change the passwords/keys immediately, then remove them from git history. + +This is why .gitignore is so important! Always ignore files with sensitive data. + +## 9. Using Gitea's Web Interface + +While the command line is powerful, Gitea's web interface can be more convenient for certain tasks. + +### Viewing Files and Commits + +Browse your repository's files, view the commit history, and see who changed what. Click on any commit to see the exact changes (the "diff"). + +### Creating and Editing Files + +You can create new files or edit existing ones directly in the browser. This is handy for quick fixes or updating documentation. + +### Pull Requests + +If you're collaborating with Nicholai or others, pull requests (PRs) are how you propose changes. You create a branch, push your changes, then open a PR in Gitea to ask for those changes to be merged into the main branch. Others can review your code and suggest changes before merging. + +### Issues + +Gitea has a built-in issue tracker for reporting bugs, requesting features, or discussing ideas. Each issue can have labels, assignees, and comments. + +### Releases + +When your project reaches a milestone, you can create a release—a snapshot of your code at that point, usually with a version number (like v1.0.0). + +**💡 Gitea vs GitHub** + +Gitea is very similar to GitHub—the interface and workflows are almost identical. If you learn one, you'll be comfortable with the other. The main difference is that Gitea is self-hosted (running on Nicholai's server), while GitHub is a cloud service. + +## 10. Quick Reference Cheat Sheet + +### Repository Setup +```bash +git init # Create a new repository +git clone # Clone an existing repository +git remote add origin # Connect to a remote repository +``` + +### Basic Workflow +```bash +git status # Check what's changed +git add # Stage a file +git add . # Stage all changes +git commit -m "message" # Commit staged changes +git push origin main # Push to remote +git pull origin main # Pull from remote +``` + +### Branching +```bash +git branch # List branches +git branch # Create a new branch +git checkout # Switch to a branch +git checkout -b # Create and switch to a new branch +git merge # Merge a branch into current branch +git branch -d # Delete a branch +``` + +### Viewing History +```bash +git log # View commit history +git log --oneline # Compact commit history +git diff # See unstaged changes +git diff --staged # See staged changes +git show # Show details of a commit +``` + +### Undoing Changes +```bash +git reset HEAD # Unstage a file +git reset --soft HEAD~1 # Undo last commit, keep changes +git reset --hard HEAD~1 # Undo last commit, discard changes +git revert # Create new commit that undoes changes +git checkout -- # Discard changes to a file +``` + +### Helpful Commands +```bash +git config --list # View your configuration +git remote -v # View remote connections +git branch -a # List all branches (including remote) +git fetch # Download remote changes without merging +git clean -fd # Remove untracked files and directories +``` + +--- + +## Where to Go From Here + +This guide covers the essentials, but git has a lot more to offer. As you get comfortable with these basics, you might want to explore: + +- **Git hooks** - Automate tasks when certain git events happen +- **Rebasing** - An alternative to merging that keeps history cleaner +- **Stashing** - Temporarily save changes without committing +- **Submodules** - Include other git repositories within your project +- **Tags** - Mark specific commits as important milestones + +The best way to learn git is to use it. Start with small personal projects, make frequent commits with good messages, and don't be afraid to experiment—that's what branches are for! And remember, Nicholai's just a message away if you get stuck. + +Happy coding! 🌱 + diff --git a/components/ContentRenderer.tsx b/components/ContentRenderer.tsx new file mode 100644 index 0000000..bf4a67a --- /dev/null +++ b/components/ContentRenderer.tsx @@ -0,0 +1,138 @@ +import React from 'react'; +import { ContentBlock } from '../types'; +import { TerminalBlock } from './TerminalBlock'; +import { GitWorkflowDiagram } from './GitWorkflowDiagram'; +import { AlertTriangle, Lightbulb, Info, CheckCircle2, ChevronDown } from 'lucide-react'; +import gsap from 'gsap'; + +interface ContentRendererProps { + block: ContentBlock; +} + +const Callout: React.FC<{ variant?: string; content: string }> = ({ variant = 'info', content }) => { + const getIcon = () => { + switch(variant) { + case 'warning': return ; + case 'tip': return ; + case 'success': return ; + default: return ; + } + }; + + const getStyles = () => { + switch(variant) { + case 'warning': return 'bg-destructive/10 border-destructive/20 text-destructive-foreground'; + case 'tip': return 'bg-accent/10 border-accent/20 text-accent-foreground'; + case 'success': return 'bg-primary/10 border-primary/20 text-primary-foreground'; + default: return 'bg-blue-50 border-blue-200 text-blue-900'; + } + }; + + // Adjusting styles to match new variables more closely for text colors where simple bg/text classes might fail due to variable usage + // The tailwind classes using vars (like text-primary) work if defined in config, which we did. + const getContainerClass = () => { + switch(variant) { + case 'warning': return 'bg-red-50 border-red-200 text-red-900'; + case 'tip': return 'bg-amber-50 border-amber-200 text-amber-900'; + case 'success': return 'bg-green-50 border-green-200 text-green-900'; + default: return 'bg-blue-50 border-blue-200 text-blue-900'; + } + } + + return ( +
+
{getIcon()}
+

{content}

+
+ ); +}; + +const Collapsible: React.FC<{ content: any, variant?: string }> = ({ content, variant }) => { + const [isOpen, setIsOpen] = React.useState(false); + const bodyRef = React.useRef(null); + const contentRef = React.useRef(null); + + React.useEffect(() => { + if (!contentRef.current || !bodyRef.current) return; + + if (isOpen) { + gsap.to(bodyRef.current, { + height: contentRef.current.scrollHeight, + duration: 0.4, + ease: "power2.out", + opacity: 1 + }); + } else { + gsap.to(bodyRef.current, { + height: 0, + duration: 0.3, + ease: "power2.in", + opacity: 0 + }); + } + }, [isOpen]); + + const isPractice = variant === 'success'; + + return ( +
+ +
+
+ {Array.isArray(content.body) && content.body.map((subBlock: ContentBlock, idx: number) => ( + + ))} +
+
+
+ ); +}; + +export const ContentRenderer: React.FC = ({ block }) => { + switch (block.type) { + case 'paragraph': + return

{block.content as string}

; + case 'code': + return ; + case 'callout': + return ; + case 'list': + return ( +
    + {(block.content as string[]).map((item, i) => ( +
  • {item}
  • + ))} +
+ ); + case 'ordered-list': + return ( +
    + {(block.content as string[]).map((item, i) => ( +
  1. {item}
  2. + ))} +
+ ); + case 'subheading': + return

+ + {block.content as string} +

; + case 'collapsible': + return ; + case 'diagram': + return ; + default: + return null; + } +}; \ No newline at end of file diff --git a/components/GitWorkflowDiagram.tsx b/components/GitWorkflowDiagram.tsx new file mode 100644 index 0000000..2d3dc8b --- /dev/null +++ b/components/GitWorkflowDiagram.tsx @@ -0,0 +1,183 @@ +import React, { useState, useRef, useEffect } from 'react'; +import gsap from 'gsap'; +import { FileText, ArrowRight, Database, Layers, HardDrive, RefreshCw } from 'lucide-react'; + +export const GitWorkflowDiagram: React.FC = () => { + const [state, setState] = useState<'modified' | 'staged' | 'committed'>('modified'); + + // Refs for animation targets + const fileRef = useRef(null); + const workingDirRef = useRef(null); + const stagingRef = useRef(null); + const repoRef = useRef(null); + const containerRef = useRef(null); + + useEffect(() => { + // Initial entrance animation + gsap.fromTo(containerRef.current, + { opacity: 0, scale: 0.95 }, + { opacity: 1, scale: 1, duration: 0.8, ease: "power2.out" } + ); + }, []); + + useEffect(() => { + const ctx = gsap.context(() => { + // Reset file position when state changes, then animate to new spot + // Note: In a real complex app we might calculate exact coordinates using getBoundingClientRect + // For this demo, we'll rely on the React re-render to place it in the DOM, then animate "from" the previous position if possible, + // or just animate "in" to emphasize the move. + + // Simple scale/pop effect on change + if (fileRef.current) { + gsap.fromTo(fileRef.current, + { scale: 0.5, opacity: 0, y: 20 }, + { scale: 1, opacity: 1, y: 0, duration: 0.5, ease: "back.out(1.7)" } + ); + } + }, containerRef); + + return () => ctx.revert(); + }, [state]); + + const handleReset = () => { + setState('modified'); + }; + + return ( +
+
+

Interactive Workflow

+ +
+ + {/* Zones Container */} +
+ + {/* Working Directory Zone */} +
+
+ + Working Directory +
+

Where you edit files.

+ + {state === 'modified' && ( +
+ +
+
script.js
+
Modified
+
+
+ )} + +
+ +
+
+ + {/* Staging Area Zone */} +
+
+ + Staging Area +
+

Files ready to commit.

+ + {state === 'staged' && ( +
+ +
+
script.js
+
Staged
+
+
+ )} + +
+ +
+
+ + {/* Repository Zone */} +
+
+ + Repository +
+

Saved history.

+ + {state === 'committed' && ( +
+ +
+
script.js
+
Committed
+
+
+ )} + +
+ +
+
+ + {/* Connecting Arrows (Visual only, hidden on mobile for cleaner look) */} +
+ +
+
+ +
+ +
+ +
+ {state === 'modified' && "You have changed a file. It's in your Working Directory."} + {state === 'staged' && "You've added the file to the Staging Area. It's ready to be part of the next snapshot."} + {state === 'committed' && "Success! The file is safely stored in the Repository history."} +
+
+ ); +}; diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx new file mode 100644 index 0000000..1e3772d --- /dev/null +++ b/components/Sidebar.tsx @@ -0,0 +1,99 @@ +import React, { useState, useEffect } from 'react'; +import { GUIDE_CONTENT } from '../constants'; +import { Leaf, Menu, X, GitBranch } from 'lucide-react'; + +export const Sidebar: React.FC = () => { + const [activeId, setActiveId] = useState(''); + const [isMobileOpen, setIsMobileOpen] = useState(false); + + useEffect(() => { + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + setActiveId(entry.target.id); + } + }); + }, + { rootMargin: '-20% 0px -60% 0px' } + ); + + GUIDE_CONTENT.forEach((section) => { + const element = document.getElementById(section.id); + if (element) observer.observe(element); + }); + + return () => observer.disconnect(); + }, []); + + const scrollToSection = (id: string) => { + const element = document.getElementById(id); + if (element) { + element.scrollIntoView({ behavior: 'smooth' }); + setIsMobileOpen(false); + } + }; + + return ( + <> + {/* Mobile Toggle */} +
+ +
+ + {/* Sidebar Container */} + + + ); +}; \ No newline at end of file diff --git a/components/TerminalBlock.tsx b/components/TerminalBlock.tsx new file mode 100644 index 0000000..3ddb41e --- /dev/null +++ b/components/TerminalBlock.tsx @@ -0,0 +1,163 @@ +import React, { useRef, useLayoutEffect, useState } from 'react'; +import { Copy, Check, Sprout, Leaf, Wind } from 'lucide-react'; +import gsap from 'gsap'; +import { ScrollTrigger } from 'gsap/ScrollTrigger'; + +gsap.registerPlugin(ScrollTrigger); + +interface TerminalBlockProps { + code: string; + language?: string; +} + +export const TerminalBlock: React.FC = ({ code, language = 'bash' }) => { + const [copied, setCopied] = useState(false); + const containerRef = useRef(null); + const copyBtnRef = useRef(null); + + const handleCopy = () => { + navigator.clipboard.writeText(code); + setCopied(true); + + // Organic "rustle" animation on click + if (copyBtnRef.current) { + gsap.to(copyBtnRef.current, { + rotate: 15, + scale: 1.1, + duration: 0.1, + yoyo: true, + repeat: 1, + ease: "sine.inOut" + }); + } + + setTimeout(() => setCopied(false), 2000); + }; + + useLayoutEffect(() => { + const ctx = gsap.context(() => { + // Growth animation using a "spring-like" organic entry + gsap.fromTo(containerRef.current, + { + opacity: 0, + y: 40, + scale: 0.95, + skewX: -1 + }, + { + opacity: 1, + y: 0, + scale: 1, + skewX: 0, + duration: 1, + ease: "elastic.out(1, 0.75)", + scrollTrigger: { + trigger: containerRef.current, + start: "top 92%", + } + } + ); + }, containerRef); + + return () => ctx.revert(); + }, []); + + return ( +
+ {/* Texture Overlay from index.html */} +
+ + {/* Nature-inspired Gradient Mask */} +
+ + {/* Organic Header - "The Pebble" style */} +
+
+
+ {/* Organic leaf-shaded dots */} +
+
+
+
+
+ + + {language} + +
+
+ + +
+ + {/* Code Area */} +
+
+          
+            {code.split('\n').map((line, i) => {
+                const isComment = line.trim().startsWith('#');
+                const isCommand = line.trim().startsWith('git');
+                return (
+                    
+                        {/* Subtle line highlight */}
+                        
+ + + {line} + + {'\n'} + + ); + })} + +
+
+ + {/* Decorative Organic Elements */} +
+ +
+ + {/* "Growing" accent line at bottom */} +
+
+ ); +}; \ No newline at end of file diff --git a/constants.tsx b/constants.tsx new file mode 100644 index 0000000..5b941db --- /dev/null +++ b/constants.tsx @@ -0,0 +1,244 @@ +import { SectionData } from './types'; + +export const GUIDE_CONTENT: SectionData[] = [ + { + id: "intro", + title: "1. What is Git?", + blocks: [ + { + type: 'paragraph', + content: "Git is a version control system. Imagine you're working on a game design document, and you want to try out a new idea for a level, but you're not sure if it'll work. With git, you can save your current version, try the new idea, and if it doesn't work out, you can go back to exactly where you were before. No \"final_FINAL_v3_actually_final.txt\" nonsense." + }, + { + type: 'paragraph', + content: "Git tracks changes to files over time, creating a history of your project. Every time you \"save\" (which we call a commit), git takes a snapshot of your entire project. You can view any of these snapshots at any time, compare them, or even combine changes from different versions." + } + ] + }, + { + id: "setup", + title: "2. Initial Setup", + blocks: [ + { + type: 'paragraph', + content: "First, let's configure git with your information. Open your terminal and run these commands:" + }, + { + type: 'code', + language: 'bash', + content: `# Set your name (this will appear in your commits) +git config --global user.name "Sylvi" + +# Set your email (use the email you registered with Gitea) +git config --global user.email "your-email@example.com" + +# Set your default text editor (optional, but helpful) +git config --global core.editor "nano" + +# Check your configuration +git config --list` + }, + { + type: 'callout', + variant: 'tip', + content: "Every change you make in git is tagged with your name and email. This helps everyone (including future you) know who made which changes and when." + } + ] + }, + { + id: "file-types", + title: "3. Understanding Files", + blocks: [ + { + type: 'paragraph', + content: "When working with git, you'll encounter a few special files and formats. Let's break them down:" + }, + { + type: 'subheading', + content: ".git Directory" + }, + { + type: 'paragraph', + content: "This hidden folder is where git stores all its magic. It contains the entire history of your project. You'll never need to edit files in here directly—git handles it all." + }, + { + type: 'subheading', + content: ".gitignore File" + }, + { + type: 'paragraph', + content: "This file tells git which files or folders to ignore. It's super useful for keeping temporary files, build artifacts, or sensitive data out of your repository." + }, + { + type: 'code', + language: 'plaintext', + content: `# Example .gitignore file +*.log +node_modules/ +.DS_Store +Thumbs.db +config/secrets.json` + }, + { + type: 'collapsible', + content: { + title: "📄 Common File Formats You'll Work With", + body: [ + { + type: 'list', + content: [ + ".md - Markdown files (like README.md) for documentation", + ".html, .css, .js - Web development files", + ".json - Configuration and data files", + ".yml/.yaml - Configuration files", + "Binary Files: Images, compiled code, etc." + ] + } + ] + } + } + ] + }, + { + id: "creating-repo", + title: "4. Creating Your First Repo", + blocks: [ + { + type: 'paragraph', + content: "There are two ways to start with git: create a new repository from scratch, or clone an existing one." + }, + { + type: 'subheading', + content: "Method 1: Local Repository" + }, + { + type: 'code', + language: 'bash', + content: `# Create a new directory for your project +mkdir my-awesome-project +cd my-awesome-project + +# Initialize a git repository +git init + +# Check the status (you should see "No commits yet") +git status` + }, + { + type: 'subheading', + content: "Method 2: Create on Gitea First" + }, + { + type: 'ordered-list', + content: [ + "Log into your Gitea account", + "Click the '+' icon or 'New Repository' button", + "Give it a name and description", + "Click 'Create Repository'" + ] + }, + { + type: 'collapsible', + variant: 'success', + content: { + title: "✏️ Practice Exercise #1", + body: [ + { type: 'paragraph', content: "Create a new directory called 'git-practice' and initialize it as a git repository. Then check its status." }, + { type: 'subheading', content: "Solution:" }, + { type: 'code', language: 'bash', content: "mkdir git-practice\ncd git-practice\ngit init\ngit status" } + ] + } + } + ] + }, + { + id: "basic-workflow", + title: "5. The Basic Workflow", + blocks: [ + { + type: 'paragraph', + content: "The core git workflow has three main stages: Working Directory (your files), Staging Area (files marked for commit), and Repository (saved history)." + }, + { + type: 'diagram', + content: 'workflow' + }, + { type: 'subheading', content: "Step 1: Make Changes" }, + { type: 'code', language: 'bash', content: `echo "# My Awesome Project" > README.md\ngit status` }, + + { type: 'subheading', content: "Step 2: Stage Changes" }, + { type: 'paragraph', content: "Tell git which changes you want to include in the next commit." }, + { type: 'code', language: 'bash', content: `git add README.md\n# Or stage all\ngit add .` }, + + { type: 'subheading', content: "Step 3: Commit Changes" }, + { type: 'paragraph', content: "Create a snapshot of your staged changes." }, + { type: 'code', language: 'bash', content: `git commit -m "Add README file"` }, + + { type: 'callout', variant: 'info', content: "Tip: Write clear commit messages! 'Add player movement controls' is better than 'stuff'." }, + + { type: 'subheading', content: "Step 4: Push to Remote" }, + { type: 'code', language: 'bash', content: `git push origin main` }, + { type: 'callout', variant: 'warning', content: "First push? You might need: git push -u origin main" } + ] + }, + { + id: "cloning", + title: "6. Cloning Repositories", + blocks: [ + { type: 'paragraph', content: "Cloning is how you download a copy of an existing repository from Gitea to your computer." }, + { type: 'code', language: 'bash', content: `git clone https://your-gitea-instance.com/username/repo-name.git` }, + { type: 'callout', variant: 'info', content: "HTTPS is simpler (username/password). SSH is more secure but requires key setup." } + ] + }, + { + id: "branching", + title: "7. Branching & Merging", + blocks: [ + { type: 'paragraph', content: "Branches are like parallel universes for your project. You can try things out without affecting the main code." }, + { type: 'code', language: 'bash', content: `# Create and switch to new branch +git checkout -b new-feature + +# Make changes... + +# Switch back to main +git checkout main + +# Merge the new feature +git merge new-feature + +# Delete the old branch +git branch -d new-feature` }, + { type: 'callout', variant: 'warning', content: "Merge Conflicts happen when git can't automatically combine changes. Don't panic! Open the file, look for <<<<<<< HEAD, fix it, and commit." } + ] + }, + { + id: "common-pitfalls", + title: "8. Common Pitfalls", + blocks: [ + { type: 'collapsible', content: { title: "Mistake #1: Committed to Wrong Branch", body: [ + { type: 'paragraph', content: "If you haven't pushed yet:" }, + { type: 'code', language: 'bash', content: `git branch correct-branch\ngit reset --hard HEAD~1\ngit checkout correct-branch` } + ]} }, + { type: 'collapsible', content: { title: "Mistake #2: Undo Last Commit", body: [ + { type: 'paragraph', content: "Undo commit but keep changes:" }, + { type: 'code', language: 'bash', content: `git reset --soft HEAD~1` } + ]} }, + { type: 'collapsible', content: { title: "Mistake #3: Pushed Sensitive Data", body: [ + { type: 'callout', variant: 'warning', content: "If you push passwords/keys, consider them compromised. Change the passwords immediately." } + ]} } + ] + }, + { + id: "cheat-sheet", + title: "9. Cheat Sheet", + blocks: [ + { type: 'paragraph', content: "Quick reference for your daily workflow." }, + { type: 'code', language: 'bash', content: `git status # Check status +git add . # Stage all +git commit -m "m" # Commit +git push # Upload +git pull # Download +git log --oneline # History` } + ] + } +]; diff --git a/index.html b/index.html new file mode 100644 index 0000000..b397899 --- /dev/null +++ b/index.html @@ -0,0 +1,154 @@ + + + + + + Git Guide for Sylvi 🌿 + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/index.tsx b/index.tsx new file mode 100644 index 0000000..6ca5361 --- /dev/null +++ b/index.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; + +const rootElement = document.getElementById('root'); +if (!rootElement) { + throw new Error("Could not find root element to mount to"); +} + +const root = ReactDOM.createRoot(rootElement); +root.render( + + + +); \ No newline at end of file diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..7f692d2 --- /dev/null +++ b/metadata.json @@ -0,0 +1,5 @@ +{ + "name": "Sylvi's Git Guide", + "description": "An interactive, animated guide to Git version control, tailored for Sylvi.", + "requestFramePermissions": [] +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..2113cbf --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "sylvi's-git-guide", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "deploy": "bun run build && wrangler pages deploy dist", + "pages:dev": "wrangler pages dev dist --port 8788" + }, + "dependencies": { + "react": "^19.2.3", + "lucide-react": "^0.562.0", + "react-dom": "^19.2.3", + "gsap": "^3.14.2" + }, + "devDependencies": { + "@types/node": "^22.14.0", + "@vitejs/plugin-react": "^5.0.0", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "wrangler": "^4.59.1" + } +} diff --git a/public/_headers b/public/_headers new file mode 100644 index 0000000..903195c --- /dev/null +++ b/public/_headers @@ -0,0 +1,14 @@ +/* + X-Frame-Options: DENY + X-Content-Type-Options: nosniff + Referrer-Policy: strict-origin-when-cross-origin + Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=() + +/*.js + Cache-Control: public, max-age=31536000, immutable + +/*.css + Cache-Control: public, max-age=31536000, immutable + +/index.html + Cache-Control: public, max-age=0, must-revalidate diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2c6eed5 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ES2022", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "ESNext", + "lib": [ + "ES2022", + "DOM", + "DOM.Iterable" + ], + "skipLibCheck": true, + "types": [ + "node" + ], + "moduleResolution": "bundler", + "isolatedModules": true, + "moduleDetection": "force", + "allowJs": true, + "jsx": "react-jsx", + "paths": { + "@/*": [ + "./*" + ] + }, + "allowImportingTsExtensions": true, + "noEmit": true + } +} \ No newline at end of file diff --git a/types.ts b/types.ts new file mode 100644 index 0000000..04cf92d --- /dev/null +++ b/types.ts @@ -0,0 +1,29 @@ +import { ReactNode } from "react"; + +export type ContentType = + | 'paragraph' + | 'code' + | 'callout' + | 'list' + | 'ordered-list' + | 'subheading' + | 'collapsible' + | 'diagram'; + +export interface ContentBlock { + type: ContentType; + content: string | string[] | { title: string; body: ContentBlock[] }; + variant?: 'warning' | 'info' | 'success' | 'tip'; + language?: string; +} + +export interface SectionData { + id: string; + title: string; + blocks: ContentBlock[]; +} + +export interface NavItem { + id: string; + label: string; +} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..ee5fb8d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,23 @@ +import path from 'path'; +import { defineConfig, loadEnv } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, '.', ''); + return { + server: { + port: 3000, + host: '0.0.0.0', + }, + plugins: [react()], + define: { + 'process.env.API_KEY': JSON.stringify(env.GEMINI_API_KEY), + 'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY) + }, + resolve: { + alias: { + '@': path.resolve(__dirname, '.'), + } + } + }; +}); diff --git a/wrangler.toml b/wrangler.toml new file mode 100644 index 0000000..5a89753 --- /dev/null +++ b/wrangler.toml @@ -0,0 +1,6 @@ +name = "sylvi-git-guide" +compatibility_date = "2025-01-14" +main = "workers-site/index.js" + +[site] +bucket = "./dist"