From acd829be60abfcffc0e461e92e05a7a4b2e54b39 Mon Sep 17 00:00:00 2001 From: Yash Vardhan Date: Tue, 7 Jul 2026 00:11:14 +0530 Subject: [PATCH 1/5] docs: Add MDX contribution guide for content creators --- frontend/CONTRIBUTING_MDX.md | 327 +++++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 frontend/CONTRIBUTING_MDX.md diff --git a/frontend/CONTRIBUTING_MDX.md b/frontend/CONTRIBUTING_MDX.md new file mode 100644 index 0000000..95f0f49 --- /dev/null +++ b/frontend/CONTRIBUTING_MDX.md @@ -0,0 +1,327 @@ +# Contributing MDX Content + +Welcome to RefMe! This guide explains how to write and structure MDX files for the project. Whether you're adding a new cheatsheet or improving existing content, these guidelines will help you maintain consistency across the project. + +## Table of Contents + +- [What is MDX?](#what-is-mdx) +- [File Structure](#file-structure) +- [Frontmatter](#frontmatter) +- [Content Structure](#content-structure) +- [Writing Guidelines](#writing-guidelines) +- [Code Examples](#code-examples) +- [Quick Checklist](#quick-checklist) + +--- + +## What is MDX? + +MDX is Markdown with JSX. It allows you to use Markdown syntax for text content while embedding code and dynamic components. For RefMe, we use MDX to create rich, interactive cheatsheets. + +**Learn more:** [MDX Documentation](https://mdxjs.com/) + +--- + +## File Structure + +### Location + +All MDX content files are stored in the `content/` directory at the root of the `frontend` folder: + +``` +frontend/ +├── content/ +│ ├── javascript.mdx +│ ├── python.mdx (example - add similar files) +│ └── typescript.mdx (example) +├── app/ +├── src/ +└── ... +``` + +### Naming Convention + +- **File names** should be lowercase and kebab-case (hyphen-separated) +- **File extension** must be `.mdx` +- Examples: `javascript.mdx`, `html-css.mdx`, `react-hooks.mdx` + +--- + +## Frontmatter + +Every MDX file must start with YAML frontmatter enclosed in triple dashes (`---`). This metadata is parsed by `gray-matter` and used throughout the application. + +### Required Fields + +```yaml +--- +title: "Language or Technology Name" +description: "A brief, engaging description of the content. This appears in listings and SEO." +category: "Category Name (e.g., 'Core Programming', 'Web Development', 'Frameworks')" +--- +``` + +### Example + +```yaml +--- +title: "JavaScript" +description: "The universal language of the web. Core syntax, ES6+ features, and modern asynchronous patterns." +category: "Core Programming" +--- +``` + +### Field Guidelines + +| Field | Purpose | Example | +| ------------- | ------------------------------------------------ | --------------------------------------------------------------- | +| `title` | The main subject of the cheatsheet | `"React Hooks"` | +| `description` | Concise explanation; appears in previews and SEO | `"Modern patterns for functional React components with hooks."` | +| `category` | Broad topic area for organization | `"Frameworks"`, `"Core Programming"`, `"DevOps"` | + +--- + +## Content Structure + +After the frontmatter, organize your content into logical sections using Markdown headers. + +### Recommended Structure + +````markdown +--- +title: "Your Topic" +description: "Your description" +category: "Category" +--- + +## Getting Started + +Introduction section explaining the basics and key concepts. + +### Subsection Title + +More detailed information about a specific aspect. + +`code block` + +## Core Concepts + +Another main section covering fundamental ideas. + +## Advanced Topics + +More complex patterns and edge cases. + +--- + +## Best Practices + +Tips, warnings, and common pitfalls. +```` + +### Section Levels + +- **Level 2 (`##`)** - Main sections (e.g., "Getting Started", "Core Concepts") +- **Level 3 (`###`)** - Subsections for breaking up large topics +- **Avoid Level 1 (`#`)** - Reserved for page titles (not needed in MDX, the title is from frontmatter) + +--- + +## Writing Guidelines + +### Tone + +- **Clear and concise** - Use simple language; avoid unnecessary jargon +- **Practical** - Focus on real-world usage patterns +- **Supportive** - Remember that readers may be beginners +- **Consistent** - Match the style of existing cheatsheets like `javascript.mdx` + +### Formatting + +- Use **bold** (`**text**`) for key terms and important concepts +- Use `inline code` for function names, variables, and keywords +- Use bullet points (`-`) for lists of related items +- Use numbered lists (`1.`) for steps or sequences + +### Example + +```markdown +## Variables & Declarations + +Modern JavaScript relies strictly on **block-scoped declarations** to prevent +memory leaks and unintended global mutations. + +- `const` prevents reassignment (use by default) +- `let` allows reassignment but maintains block scope +- `var` is function-scoped (legacy, avoid in modern code) +``` + +--- + +## Code Examples + +Code examples are essential to a good cheatsheet. Use fenced code blocks with language syntax highlighting. + +### Syntax + +````markdown +```language +code here +``` +```` + +### Supported Languages + +- `javascript` or `js` +- `typescript` or `ts` +- `python` +- `html` +- `css` +- `sql` +- `bash` or `shell` +- `json` +- `jsx` +- `tsx` +- And many more... + +### Example + +````markdown +### Arrow Functions + +Arrow functions provide concise syntax and inherit `this` from the enclosing scope. + +```javascript +// Standard function declaration +function add(a, b) { + return a + b; +} + +// Arrow function with implicit return +const multiply = (a, b) => a * b; + +// Single parameter (parentheses optional) +const square = (x) => x * x; +``` +```` + +### Best Practices for Code + +- **Realistic examples** - Show actual use cases, not contrived scenarios +- **Brevity** - Keep examples focused; use comments to explain context +- **Progressive complexity** - Start simple, then show advanced patterns +- **Consistency** - Match the style and conventions of your language/framework +- **Comments** - Add comments for non-obvious lines: + + ```javascript + // ✅ Good: Explains WHY, not what + const timeout = 0 ?? 3000; // Nullish coalescing prevents 0 from being falsy + + // ❌ Avoid: Obvious comments waste space + const timeout = 0 ?? 3000; // Set timeout to 3000 if 0 + ``` + +--- + +## Quick Checklist + +Before submitting your MDX file: + +- [ ] File is in `content/` directory with `.mdx` extension +- [ ] File name is lowercase and kebab-case (e.g., `my-topic.mdx`) +- [ ] Frontmatter is present and valid (title, description, category) +- [ ] Frontmatter fields are not empty +- [ ] All code examples have a language specified +- [ ] Content uses level 2 (`##`) headers for main sections +- [ ] Content is clear, concise, and practical +- [ ] Grammar and spelling are correct +- [ ] Links (if any) use proper Markdown syntax: `[text](url)` +- [ ] No broken references or incomplete sections + +--- + +## Example: Complete MDX File + +Here's a minimal but complete example to get started: + +````yaml +--- +title: "Markdown" +description: "Syntax for writing formatted text. Essential for documentation and README files." +category: "Writing & Documentation" +--- + +## Getting Started + +Markdown is a lightweight markup language designed for readability and simplicity. + +```markdown +# This is a heading +## This is a subheading + +This is a paragraph with **bold** and *italic* text. + +- Bullet point 1 +- Bullet point 2 +```` + +## Headers + +Headers are denoted by `#` symbols. More `#` symbols create deeper nesting. + +```markdown +# Level 1 + +## Level 2 + +### Level 3 + +#### Level 4 +``` + +## Emphasis + +Use asterisks or underscores to make text **bold** or _italic_. + +```markdown +**bold text** or **bold text** +_italic text_ or _italic text_ +``` + +## Lists + +Both ordered and unordered lists are supported. + +```markdown +- Unordered item 1 +- Unordered item 2 + - Nested item + +1. Ordered item 1 +2. Ordered item 2 +``` + +``` + +--- + +## Need Help? + +- Review [javascript.mdx](./content/javascript.mdx) for a real-world example +- Check the [MDX documentation](https://mdxjs.com/) +- Look at existing content for style and structure patterns +- Open an issue or discussion if you have questions! + +--- + +## Contributing a New Cheatsheet + +1. Create a new `.mdx` file in the `content/` directory +2. Add frontmatter with title, description, and category +3. Write clear, practical sections with code examples +4. Use this guide for formatting and structure +5. Test locally if possible (see [frontend README](./README.md)) +6. Submit a pull request with a descriptive title and message + +Thank you for contributing to RefMe! 🚀 +``` From 7fa3b61deb86a52370499a55c1e339cfc0b029e9 Mon Sep 17 00:00:00 2001 From: Yash Vardhan Date: Wed, 8 Jul 2026 21:07:46 +0530 Subject: [PATCH 2/5] chore: fix readme.md --- README.md | 206 ++++++++------------------------------------- frontend/AGENTS.md | 5 -- frontend/CLAUDE.md | 1 - 3 files changed, 37 insertions(+), 175 deletions(-) delete mode 100644 frontend/AGENTS.md delete mode 100644 frontend/CLAUDE.md diff --git a/README.md b/README.md index 2c85676..bedaab3 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,50 @@ -# RefMe\_ — Technical Documentation Hub +# RefMe\_ -A modern, responsive technical reference platform designed for developers and engineers to quickly access cheatsheets, code snippets, and documentation across multiple programming languages and frameworks. +A curated, zero-latency reference hub for modern full-stack workflows. No fluff, no endless scrolling—just the raw syntax you need to build. -Built with ❤️ by **Yash Vardhan** ([Yash Pluto](https://github.com/yash-pluto)) +Built as a side project by [Yash Vardhan](https://www.linkedin.com/in/vardhan-yash3105/) ([@Yash-pluto](https://github.com/Yash-pluto)). ---- +## The "Why" -## 🌟 Features +As developers, we constantly switch contexts between writing code, running CLI commands, managing infrastructure, and configuring tools. I got tired of opening dozens of browser tabs or repeatedly prompting AI for the same boilerplate snippets. -- **Dark & Light Theme Toggle** — Seamless theme switching with persistent storage -- **Multi-Language Support** — Comprehensive references for Python, JavaScript, TypeScript, Go, Rust, C++, React, Tailwind CSS, Docker, Kubernetes, Bash, and more -- **Responsive Design** — Optimized for desktop, tablet, and mobile devices -- **Fast Navigation** — Client-side routing with smooth page transitions -- **Code Syntax Highlighting** — Beautiful syntax-highlighted code blocks with copy-to-clipboard functionality -- **Search & Filter** — Quick access to specific references and topics -- **Professional UI** — Polished, sleek interface built with modern design principles +I built RefMe to act as a secondary brain—a highly opinionated, lightning-fast, and distraction-free environment curated specifically for quick lookups. ---- +## Under the Hood -## 🛠️ Tech Stack +This isn't a standard template. It's custom-built for speed and clarity: -- **Frontend Framework:** Next.js 16.2.4 with App Router -- **UI Library:** React 19.2.4 -- **Styling:** Tailwind CSS v4 -- **Animations:** Framer Motion -- **Code Highlighting:** react-syntax-highlighter with Prism.js -- **Icons:** lucide-react -- **Language:** TypeScript +- **Framework:** Next.js 15 (App Router) +- **Styling:** Tailwind CSS v4 with a strict monochrome/zinc palette. +- **Content:** MDX (`next-mdx-remote`) allows writing standard markdown cheatsheets while injecting custom interactive React components (like the copy-paste code blocks). +- **Layout:** Custom split-pane design with a fixed left-hand command center and a scrolling right-hand content area. +- **Icons & Typography:** Lucide React, paired with JetBrains Mono and Outfit. ---- +## Project Structure -## 📁 Project Structure - -``` +```text refme/ -├── frontend/ # Next.js application +├── frontend/ │ ├── app/ -│ │ ├── layout.tsx # Root layout with theme provider -│ │ ├── page.tsx # Homepage with hero and grid -│ │ ├── [topic]/ -│ │ │ └── page.tsx # Dynamic topic detail pages -│ │ ├── components/ -│ │ │ ├── Navbar.tsx # Navigation bar -│ │ │ ├── Hero.tsx # Hero section -│ │ │ ├── BentoGrid.tsx # Reference grid display -│ │ │ └── Footer.tsx # Footer component -│ │ └── globals.css # Global styles +│ │ ├── layout.tsx # Global layout & font configuration +│ │ ├── page.tsx # Split-pane homepage & directory search +│ │ ├── docs/ # Architecture & vision page +│ │ ├── [topic]/ # Dynamic MDX renderer for each cheatsheet +│ │ └── components/ # Interactive bits (ClientCodeBlock, DirectoryList) +│ ├── content/ # Where the actual .mdx cheatsheets live │ ├── src/ -│ │ ├── context/ -│ │ │ └── ThemeContext.tsx # Global theme management -│ │ └── data/ -│ │ ├── cheatsheets.ts # Reference content data -│ │ └── references.json # Reference metadata -│ ├── public/ # Static assets -│ └── package.json # Dependencies -└── README.md # This file +│ │ ├── context/ # Custom ThemeContext (Dark/Light mode) +│ │ ├── data/ # Directory structure definitions +│ │ └── lib/ # MDX parsing logic +│ └── tailwind.config.ts ``` ---- - -## 🚀 Getting Started - -### Prerequisites - -- Node.js 18.0 or higher -- npm or yarn package manager - -### Installation +## Running Locally 1. **Clone the repository** ```bash - git clone https://github.com/yash-pluto/refme.git + git clone [https://github.com/yash-pluto/refme.git](https://github.com/yash-pluto/refme.git) cd refme/frontend ``` @@ -81,125 +54,20 @@ refme/ npm install ``` -3. **Run the development server** - +3. **Boot it up** ```bash npm run dev ``` + The app will be running at `http://localhost:3000`. - The app will be available at `http://localhost:3000` - -4. **Build for production** - - ```bash - npm run build - npm start - ``` - ---- - -## 📖 Usage - -- **Browse Topics:** Navigate through the grid on the homepage to explore different programming languages and frameworks -- **Search References:** Use the search bar to filter topics by name -- **Toggle Theme:** Click the moon/sun icon to switch between dark and light modes -- **View Details:** Click on any reference card to access detailed cheatsheets and code snippets -- **Copy Code:** Hover over code blocks and use the copy button to add snippets to your clipboard - ---- - -## ✨ Key Components - -### Theme System - -Global theme context (`ThemeContext.tsx`) manages dark/light mode state with localStorage persistence and system preference detection. - -### Dynamic Routing - -Topic pages are dynamically generated from data using Next.js App Router, supporting routes like `/javascript`, `/python`, `/react`, etc. - -### Responsive Layout - -Mobile-first design with Tailwind CSS breakpoints ensures excellent UX across all devices. - -### Code Highlighting - -Syntax highlighting adapts to the selected theme: - -- **Dark Mode:** vscDarkPlus theme -- **Light Mode:** oneLight theme - ---- - -## 📱 Responsive Breakpoints - -- **Mobile:** < 768px — Full-width layout with collapsible sidebar -- **Tablet:** 768px - 1024px — Optimized spacing and grid adjustments -- **Desktop:** 1024px+ — Full three-column layout with sidebars - ---- - -## 🎨 Design Philosophy - -RefMe\_ prioritizes: - -- **Clarity:** Clean typography and spacing for easy reading -- **Performance:** Optimized assets and efficient client-side rendering -- **Accessibility:** Semantic HTML and keyboard navigation support -- **Consistency:** Unified color scheme and component design - ---- - -## 🔒 Security Considerations - -- All content is static or user-generated through the UI -- No backend database credentials exposed -- Environment variables properly managed -- Dependencies regularly updated - ---- - -## 🚢 Deployment - -Optimized for deployment on **Vercel**: - -```bash -npm run build -vercel deploy -``` - ---- - -## 🤝 Contributing - -Contributions are welcome! Feel free to: - -- Report bugs or issues -- Suggest new features -- Submit pull requests -- Improve documentation - ---- - -## 📄 License - -This project is created by **Yash Vardhan** and is available under the MIT License. - ---- - -## 👤 Author - -**Yash Vardhan** — Known as **Yash Pluto** - -- GitHub: [@yash-pluto](https://github.com/yash-pluto) -- Portfolio: [yashpluto.vercel.app](https://yashpluto.vercel.app) - ---- +## Adding New Content -## 🙏 Acknowledgments +Because the site runs on MDX, adding a new topic is incredibly simple: -Built with modern web technologies and a passion for clean code and excellent developer experience. RefMe\_ is designed to be your go-to technical reference platform. +1. Add a new `.mdx` file in the `frontend/content/` directory. +2. Ensure it has standard frontmatter (`title`, `description`). +3. Add the route to your `REFERENCE_DATA` structure in `app/page.tsx` so it shows up in the directory. ---- +## License -**Last Updated:** May 2026 | **Version:** 1.0.0 | **Maintained by:** Yash Vardhan (Yash Pluto) +MIT License - Do whatever you want with it. If you use the layout or code, a shoutout is appreciated! diff --git a/frontend/AGENTS.md b/frontend/AGENTS.md deleted file mode 100644 index 8bd0e39..0000000 --- a/frontend/AGENTS.md +++ /dev/null @@ -1,5 +0,0 @@ - -# This is NOT the Next.js you know - -This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. - diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md deleted file mode 100644 index 43c994c..0000000 --- a/frontend/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -@AGENTS.md From 990f62502ebfcdaae486776297b8ff0ae3f3e909 Mon Sep 17 00:00:00 2001 From: Ram Kumar Date: Wed, 8 Jul 2026 21:18:22 +0530 Subject: [PATCH 3/5] docs: Add React Cheatsheet (#18) Adds the React MDX cheatsheet to the reference library. --------- Co-authored-by: Yash Vardhan Co-authored-by: RamKumar-Muthuraj --- frontend/content/react.mdx | 667 +++++++++++++++++++++++++++++++++++++ 1 file changed, 667 insertions(+) create mode 100644 frontend/content/react.mdx diff --git a/frontend/content/react.mdx b/frontend/content/react.mdx new file mode 100644 index 0000000..9f77a5b --- /dev/null +++ b/frontend/content/react.mdx @@ -0,0 +1,667 @@ +--- +title: "React" +description: "A beginner-friendly React guide covering JSX, components, hooks, architecture, rendering, and lifecycle." +category: "Frameworks" +--- + +## Getting Started + +React is a JavaScript library for building user interfaces out of composable, reusable components. It uses a declarative model: you describe what the UI should look like for a given state, and React figures out how to update the DOM to match. You never manually write `document.createElement` or `.appendChild` — you describe the end result, and React handles the DOM manipulation for you. + +### Installation + +```bash +npm create vite@latest my-app -- --template react +cd my-app +npm install +npm run dev +``` + +### Project Structure + +```bash +my-app/ +├── src/ +│ ├── components/ +│ ├── App.jsx +│ └── main.jsx +├── index.html +├── package.json +└── vite.config.js +``` + +### A Minimal Component + +```jsx +// main.jsx +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App.jsx"; + +ReactDOM.createRoot(document.getElementById("root")).render(); + +// App.jsx +export default function App() { + return

Hello, React

; +} +``` + +--- + +## Architecture & Rendering + +Before diving into syntax, it's worth understanding what React is actually doing behind the scenes. This section explains the mental model that everything else in this guide builds on. + +### JSX Compiles to Function Calls + +JSX isn't HTML — it's syntax sugar. Every JSX element compiles down to a `React.createElement()` call, which returns a plain JavaScript object describing what you want rendered. React never touches the real DOM at this step; it's just building a description of it. + +```jsx +// What you write: +const element =

Hello

; + +// What it compiles to: +const element = React.createElement("h1", { className: "title" }, "Hello"); + +// What that actually returns (simplified): +// { +// type: "h1", +// props: { className: "title", children: "Hello" } +// } +``` + +That plain object tree is called the **Virtual DOM**: a lightweight, in-memory representation of what the UI should look like. It's just JavaScript objects — cheap to create and compare, unlike real DOM nodes, which are expensive to create and mutate. + +### Reconciliation: How React Decides What to Update + +Every time a component's state or props change, React doesn't throw away the real DOM and rebuild it from scratch. Instead it re-runs the component function to get a **new** Virtual DOM tree, then compares it against the **previous** Virtual DOM tree. This comparison process is called **reconciliation**. + +React walks both trees and only applies the minimal set of real DOM changes needed to make the browser match the new tree — this final step is called the **commit phase**. If only a button's text changed, React updates that one text node, not the entire page. + +```jsx +// Before state update: +// After setCount(1): + +// React does NOT recreate the ; +} +``` + +This one-way flow makes apps easier to debug: if a value is wrong, you only need to trace it in one direction (up through the props it was passed) instead of hunting through code that could have mutated it from anywhere. + +--- + +## JSX Basics + +JSX is a syntax extension that lets you write HTML-like markup inside JavaScript, using the rules explained above — it compiles to `React.createElement` calls that build a Virtual DOM tree. + +### Expressions & Attributes + +Any valid JavaScript expression goes inside curly braces. Attributes use camelCase instead of lowercase HTML. + +```jsx +const user = "Tommy"; +const element =

Hello, {user}!

; + +const link = Docs; +const input = ; +``` + +### className & Fragments + +`class` is reserved in JavaScript, so JSX uses `className`. Fragments group elements without adding an extra DOM node — useful because a component can only return a single root element. + +```jsx +const box =
Content
; + +function List() { + return ( + <> +
  • Item one
  • +
  • Item two
  • + + ); +} +``` + +### Conditional Rendering with Ternaries + +JSX has no `if` statements inside markup, so conditionals rely on expressions. The ternary operator is the most common pattern for choosing between two outputs inline. + +```jsx +function StatusBadge({ isOnline }) { + return {isOnline ? "🟢 Online" : "⚪ Offline"}; +} +``` + +More conditional rendering patterns (the `&&` operator and early returns) are covered in their own section further down, once components and state have been introduced. + +--- + +## Components + +Components are reusable, self-contained pieces of UI — JavaScript functions that return JSX. Modern React almost exclusively uses functional components (as opposed to older class-based components). + +### Functional Components & Props + +Props pass data from a parent component down to a child, following the unidirectional data flow described above. + +```jsx +function UserCard({ name, role }) { + return ( +
    +

    {name}

    +

    {role}

    +
    + ); +} + +; +``` + +### Default Props + +Destructured parameters can define fallback values directly, used whenever a prop isn't passed in. + +```jsx +function Button({ label = "Click me", variant = "primary" }) { + return ; +} + +; +} +``` + +### State Updates Are Asynchronous and Batched + +This trips up almost every beginner at some point: calling `setCount` does not update `count` right away. React schedules the update and re-renders the component later, batching multiple state updates together into a single re-render for performance. + +```jsx +function Counter() { + const [count, setCount] = useState(0); + + const handleClick = () => { + setCount(count + 1); + console.log(count); // Still logs the OLD value — the update hasn't applied yet + + // Calling it multiple times in a row does NOT add up the way you'd expect: + setCount(count + 1); + setCount(count + 1); + setCount(count + 1); + // Result: count only increases by 1, not 3! + // Each call uses the same "count" value from this render, + // and React batches them into one update. + }; + + return ; +} +``` + +The fix is the functional update form, covered next — it's the same category of problem javascript.mdx's `let`-in-a-loop example demonstrates: using a stale value captured at the wrong time. + +### Functional Updates + +When new state depends on the previous value, pass a function to the setter instead of a plain value. React guarantees this function receives the most up-to-date state, even across multiple queued calls. + +```jsx +const [count, setCount] = useState(0); + +const increment = () => setCount((prev) => prev + 1); + +increment(); +increment(); +increment(); +// count is guaranteed to increase by 3, because each updater function +// receives the result of the previous one — no stale values. +``` + +--- + +## Effects & the Component Lifecycle + +Older React (class components) had explicit lifecycle methods: `componentDidMount`, `componentDidUpdate`, and `componentWillUnmount`. Function components don't have these methods — instead, `useEffect` covers all three phases, controlled by its dependency array. If you've seen lifecycle methods in a tutorial before, this table is the mental bridge: + +| Lifecycle phase | Class component method | Hook equivalent | +|---|---|---| +| Mount (first render) | `componentDidMount` | `useEffect(fn, [])` | +| Update (on specific changes) | `componentDidUpdate` | `useEffect(fn, [dep1, dep2])` | +| Unmount (removed from screen) | `componentWillUnmount` | cleanup function returned from `useEffect` | + +Effects let components synchronize with external systems — APIs, subscriptions, timers, or the DOM — after the render has already happened and the DOM has been updated. + +### useEffect & Dependency Array + +The dependency array controls when the effect re-runs. An empty array means "mount only" — it runs once, after the very first render, and never again. + +```jsx +import { useEffect } from "react"; + +function DocumentTitle({ title }) { + useEffect(() => { + document.title = title; + }, [title]); // Re-runs only when `title` changes — this is the "update" phase + + return

    Check the browser tab title

    ; +} +``` + +Leaving the array off entirely makes the effect run after *every* render (rarely what you want); an empty array `[]` makes it run only once, on mount. + +### Cleanup Functions (the Unmount Phase) + +Returning a function from an effect cleans up subscriptions or timers. React calls this cleanup function right before the component is removed from the screen (unmount), and also right before the effect re-runs due to a dependency change — preventing duplicate timers or leaked subscriptions. + +```jsx +useEffect(() => { + const timerId = setInterval(() => console.log("tick"), 1000); + + return () => clearInterval(timerId); // Runs on unmount — the cleanup phase +}, []); +``` + +--- + +## Event Handling + +React wraps native DOM events in a consistent, cross-browser system called SyntheticEvent. + +### onClick & onChange + +```jsx +function NameForm() { + const [value, setValue] = useState(""); + + return ( +
    + setValue(e.target.value)} /> + +
    + ); +} +``` + +### Form Submission + +Call `preventDefault()` to stop the browser's default full-page reload. + +```jsx +function LoginForm() { + const handleSubmit = (e) => { + e.preventDefault(); + console.log("Form submitted"); + }; + + return ( +
    + +
    + ); +} +``` + +--- + +## More Conditional Rendering Patterns + +Now that components and state are covered, here are the other two conditional rendering patterns you'll use constantly, beyond the ternary shown earlier. + +### && Operator + +Renders something, or nothing at all — useful when there's no "else" case. + +```jsx +function Notifications({ count }) { + return
    {count > 0 && {count} new messages}
    ; +} +``` + +### Early Return + +Guards an entire component against an invalid or loading state, returning different JSX before the "main" render logic runs. + +```jsx +function Profile({ user }) { + if (!user) return

    Loading profile...

    ; + return

    {user.name}

    ; +} +``` + +--- + +## Lists & Keys + +### map() & Keys + +Use `Array.prototype.map` to turn an array of data into an array of elements. Keys help React's reconciliation process (explained in Architecture & Rendering) identify which items changed, were added, or were removed — and must be unique among siblings. + +```jsx +const users = [ + { id: 1, name: "Alice" }, + { id: 2, name: "Bob" }, +]; + +function UserList() { + return ( +
      + {users.map((user) => ( +
    • {user.name}
    • + ))} +
    + ); +} +``` + +### Best Practices + +- Use a stable unique identifier (like a database id) as the key, not the array index — array indices shift when items are added/removed, confusing reconciliation. +- Never omit keys when rendering lists — reconciliation becomes unreliable without them, and React will warn you in the console. +- Keep keys unique only among siblings, not globally across the app. + +--- + +## Forms + +### Controlled Components + +A controlled component keeps its value in React state, making state the single source of truth instead of the DOM. This fits the unidirectional data flow model: the input's displayed value always comes from state (down), and every keystroke updates that state (up) via `onChange`. + +```jsx +function ContactForm() { + const [email, setEmail] = useState(""); + + const handleSubmit = (e) => { + e.preventDefault(); + console.log("Submitting:", email); + }; + + return ( +
    + setEmail(e.target.value)} + /> + +
    + ); +} +``` + +--- + +## Common Hooks + +A closer look at the hooks you'll reach for most often beyond `useState` and `useEffect`, each with a complete, runnable example. + +### useMemo — Memoizing an Expensive Value + +`useMemo` re-runs a calculation only when its dependencies change, instead of on every render. Reach for it when a computation is genuinely expensive (sorting or filtering a large array, heavy math) — for cheap operations, it adds overhead without meaningful benefit. + +```jsx +import { useMemo, useState } from "react"; + +function ProductList() { + const [items] = useState([ + { id: 1, name: "Banana", price: 3 }, + { id: 2, name: "Apple", price: 1 }, + { id: 3, name: "Cherry", price: 5 }, + ]); + const [filterText, setFilterText] = useState(""); + + // Without useMemo, sorting would re-run on EVERY render, + // including renders caused by unrelated state changes like filterText typing. + const sortedItems = useMemo(() => { + console.log("Sorting..."); // Only logs when `items` actually changes + return [...items].sort((a, b) => a.price - b.price); + }, [items]); + + return ( +
    + setFilterText(e.target.value)} + placeholder="Typing here won't re-sort the list" + /> +
      + {sortedItems.map((item) => ( +
    • {item.name}: ${item.price}
    • + ))} +
    +
    + ); +} +``` + +### useCallback — Memoizing a Function Reference + +Every render creates brand-new function instances by default. `useCallback` keeps the same function reference across renders unless its dependencies change — important when passing callbacks to memoized child components, since a new function reference would defeat that memoization. + +```jsx +import { useCallback, useState } from "react"; + +function TodoApp() { + const [count, setCount] = useState(0); + + // Without useCallback, handleSelect would be a NEW function on every render, + // even though its behavior never actually changes. + const handleSelect = useCallback((id) => { + console.log("Selected item:", id); + }, []); // No dependencies — this function never needs to change + + return ( +
    +

    Unrelated counter: {count}

    + + +
    + ); +} +``` + +### useRef — Persisting a Value Without Re-rendering + +`useRef` holds a mutable value that survives across renders, but changing it does NOT trigger a re-render (unlike `useState`). It's most commonly used to directly access a DOM element. + +```jsx +import { useRef } from "react"; + +function SearchBox() { + const inputRef = useRef(null); + + const focusInput = () => { + inputRef.current.focus(); // Directly calls the DOM node's focus() method + }; + + return ( +
    + + +
    + ); +} +``` + +### useContext — Reading Shared Data Without Prop Drilling + +Passing props down through five layers of components just so the bottom one can read a value is called "prop drilling." `useContext` lets any descendant read a value directly, as long as it's wrapped in that context's Provider — no need to pass it through every layer in between. + +```jsx +import { createContext, useContext } from "react"; + +// 1. Create the context +const ThemeContext = createContext("light"); + +// 2. Provide a value somewhere up the tree +function App() { + return ( + + + + ); +} + +// 3. Any descendant can read it directly — no props passed through Toolbar +function Toolbar() { + return ; +} + +function ThemedButton() { + const theme = useContext(ThemeContext); // "dark" + return ; +} +``` + +--- + +## Tips & Best Practices + +- Prefer functional components with hooks over class components. +- Keep components small and focused on a single responsibility. +- Always use stable, unique keys when rendering lists. +- Lift state up to the nearest common ancestor when multiple components need to share it — this follows the same unidirectional data flow principle covered earlier. +- Avoid unnecessary re-renders by memoizing expensive values (`useMemo`) and callbacks (`useCallback`) where it actually matters — not by default on every value. +- Prefer composition (passing components as `children` or props) over inheritance. +- Keep side effects inside `useEffect`, not directly in the render body — remember, the entire function body re-runs on every render. + +--- + +## Common Mistakes + +### Missing Keys + +```jsx +// ❌ React can't track list items efficiently without a key +{items.map((item) =>
  • {item.name}
  • )} + +// ✅ Unique key provided +{items.map((item) =>
  • {item.name}
  • )} +``` + +### Mutating State + +```jsx +// ❌ Mutates the array directly — React won't detect the change, +// because the array reference stays the same +todos.push(newTodo); +setTodos(todos); + +// ✅ Creates a new array reference, so React knows something changed +setTodos([...todos, newTodo]); +``` + +### Infinite useEffect Loops + +```jsx +// ❌ No dependency array — setCount triggers a re-render every time, +// which re-runs the effect (since it has no array to limit it), causing an infinite loop +useEffect(() => { + setCount(count + 1); +}); + +// ✅ Dependency array controls when the effect actually re-runs +useEffect(() => { + setCount((prev) => prev + 1); +}, []); +``` + +### Calling Hooks Conditionally + +```jsx +// ❌ Hooks must not be called inside conditions, loops, or nested functions — +// React relies on hooks being called in the exact same order every render +if (isLoggedIn) { + const [user, setUser] = useState(null); +} + +// ✅ Call the hook unconditionally, then branch on the value +const [user, setUser] = useState(null); +if (isLoggedIn) { + // use `user` here +} +``` + +### Forgetting Cleanup + +```jsx +// ❌ Timer keeps running even after the component unmounts — a memory leak +useEffect(() => { + setInterval(() => console.log("tick"), 1000); +}, []); + +// ✅ Cleanup function stops the timer on unmount +useEffect(() => { + const timerId = setInterval(() => console.log("tick"), 1000); + return () => clearInterval(timerId); +}, []); +``` + +--- From e2e9a3162dc8a9c438bc5d7639da439a104638d6 Mon Sep 17 00:00:00 2001 From: Yash Vardhan Date: Wed, 8 Jul 2026 21:50:47 +0530 Subject: [PATCH 4/5] chore: add skeleton layout for non-existing page requests. --- frontend/app/[topic]/page.tsx | 8 +++++-- frontend/app/components/SkeletonTopic.tsx | 28 +++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 frontend/app/components/SkeletonTopic.tsx diff --git a/frontend/app/[topic]/page.tsx b/frontend/app/[topic]/page.tsx index a1f5e8e..5db5c6e 100644 --- a/frontend/app/[topic]/page.tsx +++ b/frontend/app/[topic]/page.tsx @@ -1,7 +1,7 @@ // app/[topic]/page.tsx import { getTopicBySlug } from "../../src/lib/mdx"; import { MDXRemote } from "next-mdx-remote/rsc"; -import { notFound } from "next/navigation"; +import SkeletonTopic from "../components/SkeletonTopic"; import TopicLayout from "./TopicLayout"; import ClientCodeBlock from "../components/ClientCodeBlock"; import { MdxH2, MdxH3, MdxP, MdxUl } from "../components/MdxTypography"; @@ -31,7 +31,11 @@ export default async function TopicPage({ const topicData = getTopicBySlug(resolvedParams.topic); if (!topicData) { - return notFound(); + return ( + + + + ); } return ( diff --git a/frontend/app/components/SkeletonTopic.tsx b/frontend/app/components/SkeletonTopic.tsx new file mode 100644 index 0000000..41acbbf --- /dev/null +++ b/frontend/app/components/SkeletonTopic.tsx @@ -0,0 +1,28 @@ +export default function SkeletonTopic({ topicKey }: { topicKey: string }) { + return ( +
    +
    +

    + The content isn't created yet! +

    +

    We're working on it — thanks for the patience.

    + +

    + In the meantime, you can check out the project's author: + + @Yash-pluto + +

    + +

    + Requested topic: {topicKey} +

    +
    +
    + ); +} From 0050039b6e7c1cdf6ee8332c1eeb27cae7d391ca Mon Sep 17 00:00:00 2001 From: Yash Vardhan Date: Sat, 8 Aug 2026 13:45:07 +0530 Subject: [PATCH 5/5] Add GitHub Actions CI workflow --- .github/workflows/ci.yml | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4f3758e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,41 @@ +name: PR Checks + +on: + pull_request: + branches: [ main ] + +jobs: + quality-checks: + runs-on: ubuntu-latest + + # Run all commands inside the frontend directory + defaults: + run: + working-directory: ./frontend + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: ./frontend/package-lock.json + + - name: Install dependencies + run: npm ci + + - name: Run ESLint + # Uses the "lint": "eslint" script from your package.json + run: npm run lint + + - name: Check TypeScript Types + # Uses npx to run the TypeScript compiler and check for errors without generating files + run: npx tsc --noEmit + + - name: Verify Next.js Build + # Uses the "build": "next build" script + # Next.js will also do a strict check here, but having them separate makes debugging easier! + run: npm run build \ No newline at end of file