Top Portable Link Viewer Tools for Mobile and USB Drives


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:

  1. Initialization

    • Load links from links.json using fetch() or read via File System Access API.
    • If none found, load from LocalStorage.
  2. Rendering

  3. Add/Edit/Delete

    • Modal form to add/edit link objects, validate URL, create UUID, set timestamps.
    • Delete with undo buffer.
  4. Search and Filter

    • Full-text search across title, URL, and notes.
    • Tag filtering and multi-tag intersection.
  5. 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.
  6. 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.
  7. 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).

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *