Build Your Own Portable Link Viewer — A Step‑by‑Step GuideA portable link viewer is a lightweight application you can carry on a USB drive, external SSD, or even a cloud folder that lets you view, organize, and open collections of links without installing heavy software on every computer you use. This guide walks you through designing and building a simple, secure, and user-friendly portable link viewer using web technologies (HTML/CSS/JavaScript) so it runs from removable media or a synced folder with minimal dependencies.
What you’ll build
A single-folder web app that:
- Loads in a browser (no installation required).
- Stores link collections in a local JSON file.
- Lets users add, edit, delete, tag, search, and open links.
- Can optionally import/export link lists (JSON/CSV/HTML bookmark files).
- Has a clean, responsive UI and basic offline support.
Tech stack
- HTML, CSS (or a framework like Tailwind), and vanilla JavaScript (or a small framework like Svelte/Vue).
- No backend required; data stored in a JSON file on the portable drive or in LocalStorage for per-browser persistence.
- Optional: Electron if you want a desktop app packaged for Windows/macOS/Linux.
Folder structure
Create a folder (e.g., PortableLinkViewer/) with this layout:
- PortableLinkViewer/
- index.html
- styles.css
- app.js
- links.json (optional starter file)
- icons/ (optional)
- README.txt
Step 1 — Build the HTML skeleton
Create index.html with a simple layout: header, toolbar (add/search/import/export), list/grid view, and modal dialogs for adding/editing links. Use semantic elements for accessibility.
Example structure (shortened):
<!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Portable Link Viewer</title> <link rel="stylesheet" href="styles.css" /> </head> <body> <header><h1>Portable Link Viewer</h1></header> <main> <section class="toolbar">...controls...</section> <section id="links">...list/grid...</section> </main> <script src="app.js"></script> </body> </html>
Step 2 — Style with CSS
Keep styles simple and responsive. Use CSS variables for easy theming. Provide a compact list and a card/grid layout toggle.
Key tips:
- Use flexbox/grid for layout.
- High-contrast accessible colors.
- Make buttons large enough for touch use.
Step 3 — Data model and storage
Design a simple JSON schema for each link:
{ "id": "uuid", "title": "Example", "url": "https://example.com", "tags": ["project", "read-later"], "notes": "Short note", "createdAt": 1680000000000 }
Storage options:
- Local file on the USB drive: users can edit links.json directly. Use the File System Access API (where supported) to let the app read/write files on the drive.
- LocalStorage: simple per-browser persistence.
- Hybrid: load from links.json if present, otherwise fall back to LocalStorage.
Important: When running from file:// in some browsers, the File System Access API and fetch() to local files may be restricted. Prefer serving via a tiny local static server (instructions below) or rely on LocalStorage for full browser compatibility.
Step 4 — Core JavaScript features
Implement these features in app.js:
-
Initialization
- Load links from links.json using fetch() or read via File System Access API.
- If none found, load from LocalStorage.
-
Rendering
- Render link list/cards with title, domain favicon, tags, and action buttons (open, edit, delete).
- Lazy-load favicons via https://www.google.com/s2/favicons?domain=...
-
Add/Edit/Delete
- Modal form to add/edit link objects, validate URL, create UUID, set timestamps.
- Delete with undo buffer.
-
Search and Filter
- Full-text search across title, URL, and notes.
- Tag filtering and multi-tag intersection.
-
Import / Export
- Import from bookmarks.html, CSV, or JSON.
- Export current collection as JSON/CSV/bookmarks.html.
- For imports, normalize fields and deduplicate by URL.
-
File save (optional)
- If File System Access API available, allow saving changes back to links.json on the portable drive.
- Otherwise persist to LocalStorage and offer manual export.
-
Offline resilience
- Keep full app assets local so it runs without internet.
- Use service workers if you need more robust offline caching.
Step 5 — Example JavaScript snippets
A small helper to validate URLs and create UUIDs:
function isValidUrl(u) { try { new URL(u); return true; } catch { return false; } } function uuidv4() { return crypto.randomUUID ? crypto.randomUUID() : 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c=>{ const r = Math.random()*16|0; const v = c==='x'? r: (r&0x3|0x8); return v.toString(16); }); }
Rendering a link card (simplified):
function renderLinkItem(link) { const div = document.createElement('div'); div.className = 'link-card'; div.innerHTML = ` <img src="https://www.google.com/s2/favicons?domain=${new URL(link.url).hostname}" alt="" /> <a href="${link.url}" target="_blank" rel="noopener noreferrer">${escapeHtml(link.title || link.url)}</a> <div class="meta">${link.tags.join(', ')}</div> <div class="actions"> <button data-id="${link.id}" class="edit">Edit</button> <button data-id="${link.id}" class="delete">Delete</button> </div>`; return div; }
Step 6 — Handling file permissions on removable media
- On Chromium-based browsers, use the File System Access API to show a directory picker and read/write links.json directly.
- On other browsers, provide clear instructions to run a tiny local static server (e.g., Python: python -m http.server) from the drive root to avoid file:// restrictions.
- Always backup before overwriting files; implement an automatic timestamped backup when saving.
Step 7 — Import/export formats
- bookmarks.html: support common bookmark file structure exported by browsers.
- CSV: columns title,url,tags,notes.
- JSON: array of link objects in your schema.
Provide an examples folder with sample links.json for quick startup.
Step 8 — Security & privacy considerations
- Open links with rel=“noopener noreferrer” to avoid opener attacks.
- Warn users that if they run on a public machine, links opened may be saved in the browser’s history.
- Do not attempt to sync without explicit user action; syncing to cloud drives is optional.
Step 9 — Optional enhancements
- Tag suggestions, auto-categorization by domain, and keyboard shortcuts.
- A compact “quick lookup” mode for launching links fast.
- Export to mobile-friendly formats or progressive web app (PWA) packaging.
- Electron wrapper for native menu, tray icon, and auto-updates.
Step 10 — Packaging and distribution
- For a truly portable desktop app, package with Electron and include links.json in app data folder or allow choosing a folder on first run.
- For web-only portability, zip the folder and distribute the zip for users to unzip onto a USB drive.
Final notes
This approach keeps the app simple, private, and resilient. Start with LocalStorage-based functionality to iterate quickly, then add file-access and import/export features. Build incrementally: core CRUD + search, then offline/file access, then polish (themes, PWA/Electron).
Leave a Reply