Skip to content

Evlos/portal

Repository files navigation

██████   ██████  ██████  ████████  █████  ██
██   ██ ██    ██ ██   ██    ██    ██   ██ ██
██████  ██    ██ ██████     ██    ███████ ██
██      ██    ██ ██   ██    ██    ██   ██ ██
██       ██████  ██   ██    ██    ██   ██ ███████

// BOOKMARKS — terminal link vault

A cyberpunk-style minimalist bookmark management website built with Flask and SQLite, featuring drag-and-drop sorting, multi-column layout, light/dark theme switching, and one-click Docker deployment.

Python Flask SQLite Docker License: GPL v3


✦ Preview

Preview

Preview


✦ Features

  • CRUD operations — Add, edit, and delete bookmarks with custom titles.
  • Edit mode — Click [ EDIT ] in the top-right corner to enter edit mode; the button turns yellow. Only in edit mode are the per-item EDIT and DEL buttons visible, and drag-and-drop reordering enabled. Click again to exit.
  • Add mode — Click [ ADD ] in the top-right corner to reveal the ADD NEW ENTRY form. A [ CANCEL ] button inside the form exits add mode without submitting. Add mode and edit mode are mutually exclusive.
  • Multi-column layout — Switch the entry list between 1 / 2 / 3 / 4 column grid layouts via the toolbar next to the entry count. Column preference is persisted across sessions.
  • Light / Dark theme — Toggle between the default dark terminal palette and a high-contrast light mode via the [ LIGHT ] / [ DARK ] button in the header. Theme preference is persisted across sessions.
  • Persistent preferences — Column layout and theme selections are saved to localStorage and automatically restored on every page load.
  • Delete confirmation — Deleting a bookmark requires a second confirmation via a modal overlay, preventing accidental removal.
  • Drag-and-drop sorting — Drag items to instantly reorder them using SortableJS (only available in edit mode). Edit mode automatically switches to single-column layout for reliable drag behaviour; the entire row acts as the drag target.
  • Inline editing — Click EDIT to expand the editing panel directly in the list, eliminating the need for page redirects.
  • Toast notifications — Lightweight, terminal-style pop-ups appear after every action.
  • Zero frontend dependencies — The project only imports SortableJS via CDN, avoiding heavy frontend frameworks.
  • SQLite persistence — Data is securely stored in a local file without needing an external database.
  • One-click Docker deployment — The multi-stage Alpine build keeps the container image extremely small.
  • Comprehensive test coverage — Full workflow testing with pytest covers the homepage, adding, deleting, editing, and reordering.

✦ UI Modes

Mode Trigger Effect
Normal Default Read-only view; EDIT/DEL buttons and drag handle hidden; multi-column layout available
Edit mode [ EDIT ] button (top-right) Auto-switches to single column; shows compact single-line entries; entire row is draggable; shows EDIT/DEL buttons
Add mode [ ADD ] button (top-right) Reveals the ADD NEW ENTRY form; [ CANCEL ] hides it again
Light mode [ LIGHT ] button (top-right) Switches to a high-contrast light palette; preference saved automatically

Edit mode and add mode are mutually exclusive — activating one automatically exits the other.

✦ Tech Stack

Layer Technology
Backend framework Python 3.12 · Flask
Data storage SQLite (data/bookmarks.db)
Template engine Jinja2
Frontend interaction Vanilla JS · SortableJS 1.15
UI style Cyberpunk terminal, pure CSS variables
Preference persistence localStorage
Containerization Docker (Alpine multi-stage build)
Testing framework pytest · Flask Test Client

✦ Quick Start

Method 1: GitHub Container Registry (Simplest)

# Pull and run the pre-built image directly
docker run -d \
  -p 5000:5000 \
  -v $(pwd)/data:/app/data \
  --name portal \
  ghcr.io/evlos/portal:latest

Visit http://localhost:5000 to start using the app.

Method 2: Local Docker Build

# Build the image
docker build -t portal .

# Run the container with a mounted volume for persistent data
docker run -d \
  -p 5000:5000 \
  -v $(pwd)/data:/app/data \
  --name portal \
  portal

Visit http://localhost:5000 to start using the app.

Method 3: Run Locally

# Clone the repository
git clone <repo-url>
cd portal

# Install dependencies
pip install -r requirements.txt

# Start the server
python app.py

✦ API Endpoints

Method Path Description
GET / Home page, renders the bookmark list
POST /add Add a new bookmark (form submission)
POST /edit/<id> Edit a bookmark (JSON)
POST /delete/<id> Delete a bookmark (returns JSON)
POST /reorder Update sorting order (JSON array of IDs)

✦ Project Structure

portal/
├── app.py                 # Main Flask app, routing and database logic
├── templates/
│   └── index.html         # Single-page frontend, Jinja2 + vanilla JS
├── tests/
│   ├── conftest.py        # pytest fixtures, isolated test database
│   └── test_app.py        # Complete test cases
├── Dockerfile             # Alpine multi-stage build
├── requirements.txt       # Python dependencies
└── LICENSE                # GPL v3

✦ Run Tests

pip install pytest
pytest tests/ -v

✦ License

This project is open-sourced under the GNU General Public License v3.0.

About

A cyberpunk-style minimalist bookmark management website built with Flask and SQLite, featuring drag-and-drop sorting and one-click Docker deployment.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors