Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

10 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ“ Notes App โ€” File System Edition

A lightweight note-taking web app built with Node.js, Express, and EJS โ€” no database required. Notes are stored as plain .txt files on the server.


โœจ Features

  • ๐Ÿ“„ Create notes from a clean web form
  • ๐Ÿ’พ Store notes as .txt files locally
  • ๐Ÿ  View all notes on the home page
  • ๐Ÿ” Open and read individual notes
  • โœ๏ธ Edit existing notes (rename + update content)
  • ๐ŸŽจ Clean dark UI with Tailwind CSS

๐Ÿ›  Tech Stack

Technology Purpose
Node.js Runtime environment
Express Web framework
EJS Template engine
fs module File system storage
Tailwind CSS Styling (via CDN)

๐Ÿš€ Getting Started

Prerequisites

1. Clone the repository

git clone git@github.com:mackcodes/notes-server-filesystem.git

2. Move into the project folder

cd notes-server-filesystem

3. Install dependencies

npm install

4. Start the server

# Production
npm run start

# Development (auto-restart on file changes)
npm run dev

5. Open in browser

http://localhost:3000

๐Ÿ“ Project Structure

notes-server-filesystem/
โ”œโ”€โ”€ server.js               โ† main server file
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ files/
โ”‚   โ””โ”€โ”€ *.txt               โ† notes stored here
โ”œโ”€โ”€ public/
โ”‚   โ”œโ”€โ”€ images/
โ”‚   โ”‚   โ””โ”€โ”€ favicon.svg
โ”‚   โ”œโ”€โ”€ javascripts/
โ”‚   โ””โ”€โ”€ stylesheets/
โ””โ”€โ”€ views/
    โ”œโ”€โ”€ index.ejs           โ† home page
    โ”œโ”€โ”€ edit.ejs            โ† edit note form
    โ””โ”€โ”€ show.ejs            โ† single note page

๐Ÿ”— Routes

Method Route Description
GET / Render all notes
POST /create Create a new note
GET /file/:filename Render a single note
GET /edit/:filename Render edit form for a note
POST /edit Save note edits (rename + content update)

โœ๏ธ How Editing Works

  1. Click Edit on a note card from the home page.
  2. The app opens /edit/:filename and pre-fills:
    • current filename (readonly)
    • editable new filename
    • existing note details
  3. On submit, the app:
    • renames the file if the name changed
    • rewrites file content with updated title + details
  4. The title is stored on line 1 and details are stored from line 2 onward.

Example update flow:

Old file: LearnNode.txt
New file: LearnExpress.txt

Final file content:
LearnExpress
Updated note details...

๐Ÿ’พ Note Storage Format

Each note is saved as a .txt file like this:

My Note Title
This is the first line of details.
This is the second line of details.
  • Line 1 โ†’ used as the note title
  • Remaining lines โ†’ used as note content

๐Ÿงฉ About EJS

EJS stands for Embedded JavaScript. It is a template engine that lets you write HTML with JavaScript logic inside it. Instead of sending plain HTML, your Express server processes the .ejs file, injects dynamic data into it, and then sends the final HTML to the browser.

Think of it like this:

Express (data) + EJS (template) = Final HTML sent to browser

How EJS fits in this project

Browser requests /
        โ†“
Express reads all .txt files from /files
        โ†“
Passes file list to index.ejs via res.render()
        โ†“
EJS loops through files and builds HTML cards
        โ†“
Final HTML is sent back to browser

In server.js:

app.get('/', function(req, res) {
    fs.readdir('./files', function(err, files) {
        res.render('index', { files: files, titles: titles });
        //                    โ†‘ this data is sent to index.ejs
    });
});

In index.ejs, you receive and use that data:

<% files.forEach(function(val, index) { %>
    <h1><%= titles[index] %></h1>
<% }) %>

EJS Tags โ€” Full Reference

Tag Name Purpose Example
<%= %> Output tag Prints value to HTML (safe, escaped) <%= username %>
<% %> Scriptlet tag Runs JS logic, prints nothing <% if(x > 0) { %>
<%- %> Unescaped tag Prints raw HTML (be careful!) <%- htmlContent %>
<%# %> Comment tag EJS comment, not sent to browser <%# this is a note %>
<%_ %> Whitespace tag Removes whitespace before tag <%_ if(x) { %>

Output tag <%= %>

Used to display a variable value in HTML. EJS automatically escapes special characters to prevent XSS attacks.

<h1><%= title %></h1>
<p><%= filedata %></p>
<a href="/file/<%= filename %>">Open</a>

Scriptlet tag <% %>

Used to write JavaScript logic โ€” if, for, forEach, etc. Does not print anything to HTML on its own.

<% if (files.length > 0) { %>
    <p>You have notes!</p>
<% } else { %>
    <p>No notes yet.</p>
<% } %>
<% files.forEach(function(file, index) { %>
    <div>
        <h2><%= titles[index] %></h2>
    </div>
<% }) %>

Unescaped tag <%- %>

Prints raw HTML directly. Use carefully โ€” never use with user input as it can cause security issues.

<%- '<strong>bold text</strong>' %>

EJS in this project โ€” real examples

index.ejs โ€” loop through notes and render cards:

<% if(files.length > 0){ %>
    <% files.forEach(function(val, index){ %>
        <div class="task bg-zinc-800 rounded-md p-4">
            <h1><%= titles[index] %></h1>
            <a href="/file/<%= val %>">Read more</a>
        </div>
    <% }) %>
<% } else { %>
    <h3>No tasks yet</h3>
<% } %>

show.ejs โ€” display a single note:

<h1><%= filename %></h1>
<pre><%= filedata %></pre>

Setting up EJS in Express

app.set("view engine", "ejs");  // tell Express to use EJS
res.render("index", { files: files, titles: titles });
//          โ†‘ file name inside views/    โ†‘ data passed to template

EJS automatically looks inside the views/ folder โ€” no need to write the full path or .ejs extension.


๐Ÿ–ผ Static Assets & Favicon

Static files are served from the public/ folder.

app.use(express.static(path.join(__dirname, "public")));
File path Browser path
public/images/favicon.svg /images/favicon.svg

Add favicon in your EJS files:

<link rel="icon" type="image/svg+xml" href="/images/favicon.svg" />

๐Ÿ› Common Issues & Fixes

Favicon not showing

  • Confirm file exists at public/images/favicon.svg
  • Use /images/favicon.svg (not ../public/...)
  • Hard refresh: Ctrl + Shift + R

Port already in use

# Find and kill process on port 3000
kill -9 $(lsof -t -i:3000)

Files not listed on home page

  • Make sure files end with .txt
  • Make sure files are inside the files/ folder

๐Ÿ”ฎ Future Improvements

  • Add note delete feature
  • Add validation for empty title/details
  • Sanitize title into safe filenames
  • Add timestamps (created/updated)
  • Migrate to database storage (MongoDB/PostgreSQL)
  • Add tests for routes and file operations

๐Ÿ“š Useful References


๐Ÿ“„ License

MIT ยฉ 2026


About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages