diff --git a/README.md b/README.md index e64fd38..e0a2443 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,17 @@
-

Markdown Viewer

- - Markdown Viewer Logo -
-
-

A Markdown Editor That Lives in Your Browser, Desktop, and a Single URL.

-

Fast GitHub-style Markdown editing with live preview, diagrams, LaTeX, syntax highlighting, PDF export, and multi-tab support across web, desktop, and Docker.

+ Markdown Viewer Logo -

- Live Production Demo · - Documentation Wiki · - Issue Tracker · - Releases -

+

Markdown Viewer

-

- License - Latest release - Last commit - Stars -

+ **A Markdown Editor That Lives in Your Browser, Desktop, and a Single URL.** + + *Fast GitHub-style Markdown editing with live preview, diagrams, LaTeX, syntax highlighting, PDF export, and multi-tab support across web, desktop, and Docker.* + + [![License](https://img.shields.io/github/license/ThisIs-Developer/Markdown-Viewer?style=flat-square&color=2ea043)](https://github.com/ThisIs-Developer/Markdown-Viewer/blob/main/LICENSE) + [![Latest Release](https://img.shields.io/github/v/release/ThisIs-Developer/Markdown-Viewer?style=flat-square&color=3178C6)](https://github.com/ThisIs-Developer/Markdown-Viewer/releases) + [![Last Commit](https://img.shields.io/github/last-commit/ThisIs-Developer/Markdown-Viewer?style=flat-square)](https://github.com/ThisIs-Developer/Markdown-Viewer/commits/main) + [![Stars](https://img.shields.io/github/stars/ThisIs-Developer/Markdown-Viewer?style=flat-square&color=dfb317)](https://github.com/ThisIs-Developer/Markdown-Viewer/stargazers)

@@ -33,6 +24,11 @@ OOSMetrics

+ + 🌐 **English** • 简体中文日本語한국어Português (Brasil) + + [Live Production Demo](https://markdownviewer.pages.dev/) • [Documentation Wiki](wiki/Home) • [Issue Tracker](https://github.com/ThisIs-Developer/Markdown-Viewer/issues) • [Releases](https://github.com/ThisIs-Developer/Markdown-Viewer/releases) +

@@ -42,35 +38,26 @@ ## Table of Contents -- [About the Project](#about-the-project) -- [Key Features](#key-features) -- [System Architecture](#system-architecture) - - [High-Level Architecture Diagram](#high-level-architecture-diagram) - - [Core File Walkthrough](#core-file-walkthrough) -- [Under-the-Hood Subsystems Deep-Dive](#under-the-hood-subsystems-deep-dive) - - [1. Global State & Session Persistence](#1-global-state--session-persistence) - - [2. Document Tab & Session Lifecycle](#2-document-tab--session-lifecycle) - - [3. Tab Overflow & Navigation](#3-tab-overflow--navigation) - - [4. Responsive Pane Resizer & View Mode Layout Controller](#4-responsive-pane-resizer--view-mode-layout-controller) - - [5. Rich Text Editor History & Undo/Redo Engine](#5-rich-text-editor-history--undoredo-engine) - - [6. Dynamic Line-Number Gutter & Selection Highlighter](#6-dynamic-line-number-gutter--selection-highlighter) - - [7. Web Worker Segmented Markdown Compilation & Sanitization](#7-web-worker-segmented-markdown-compilation--sanitization) - - [8. Throttled Bidirectional Scroll Synchronization](#8-throttled-bidirectional-scroll-synchronization) - - [9. Interactive Mermaid Diagram & MathJax LaTeX Renderer](#9-interactive-mermaid-diagram--mathjax-latex-renderer) - - [10. Draggable Find/Replace Search & Diff Preview Engine](#10-draggable-findreplace-search--diff-preview-engine) - - [11. Layout-Aware PDF Export & URL Sharing Subsystem](#11-layout-aware-pdf-export--url-sharing-subsystem) -- [Getting Started & Installation](#getting-started--installation) - - [Option 1: Docker (Pre-built Image)](#option-1-docker-pre-built-image) - - [Option 2: Docker Compose (Local Build)](#option-2-docker-compose-local-build) - - [Option 3: Local Static Web Server](#option-3-local-static-web-server) - - [Option 4: Desktop Application](#option-4-desktop-application) -- [Usage Guide & Keyboard Shortcuts](#usage-guide--keyboard-shortcuts) -- [Project Directory Structure](#project-directory-structure) -- [Built With (Technology Stack)](#built-with-technology-stack) -- [Contributing & Code Quality](#contributing--code-quality) -- [Showcase & Community Projects](#showcase--community-projects) -- [License](#license) -- [Contact & Support](#contact--support) +

+ 📂 Table of Contents (Click to expand) +
+ + - [About the Project](#about-the-project) + - [Key Features](#key-features) + - [System Architecture](#system-architecture) + - [High-Level Architecture Diagram](#high-level-architecture-diagram) + - [Core File Walkthrough](#core-file-walkthrough) + - [Getting Started & Installation](#getting-started--installation) + - [Usage Guide & Keyboard Shortcuts](#usage-guide--keyboard-shortcuts) + - [Project Directory Structure](#project-directory-structure) + - [Built With (Technology Stack)](#built-with-technology-stack) + - [Contributing & Code Quality](#contributing--code-quality) + - [Showcase & Community Projects](#showcase--community-projects) + - [Contributors](#contributors) + - [📈 Development Journey](#-development-journey) + - [License](#license) + - [Contact & Support](#contact--support) +
--- @@ -84,30 +71,139 @@ Designed with privacy and performance at its core, the application performs all ## Key Features -* **🖊️ Decoupled Split-Screen Editing:** Type Markdown in a customized text editor with a dynamic line-number gutter and see updates render instantly. -* **📐 LaTeX Math Notation:** Full integration with MathJax for typesetting inline and block mathematical formulas. -

- - Markdown Viewer - LaTeX math editor rendering display and inline mathematical equations using MathJax in dark mode -

-* **📊 Interactive Mermaid Diagrams:** Render flowcharts, Gantt charts, sequence diagrams, and more. Diagrams feature a toolbar for zooming, panning, copying, and exporting. -

- Markdown Viewer - Rendered interactive Mermaid.js diagram flowchart in preview with zoom, pan, and SVG image export toolbar - Markdown Viewer - Rendered interactive Mermaid.js diagram flowchart in preview with zoom, pan, and SVG image export toolbar -

-* **⚡ Off-Thread Parsing & Incremental Patching:** Document parsing is offloaded to a background Web Worker. Rendered updates patch only changed DOM nodes to keep browser resources free. -* **📤 Professional Export Suite:** Export documents as raw Markdown (`.md`), standalone formatted HTML (`.html`) with inline styles, or high-resolution paginated PDF (`.pdf`). -* **📥 Multi-Source File Import:** Drag & drop local files or browse and download multiple Markdown files from a public GitHub repository URL. -

- Markdown Viewer - Import Markdown files from public GitHub repository tree with recursive directory browser and tab integration - Markdown Viewer - Import Markdown files from public GitHub repository tree with recursive directory browser and tab integration -

-* **🔗 URL-Encoded Compressed Sharing:** Compress your document's text utilizing DEFLATE compression and encode it directly into a shareable URL hash. No server-side database required. -

- Markdown Viewer - Serverless document sharing using URL-encoded DEFLATE compressed markdown hash in edit or view-only mode -

-* **💾 Multi-Document Tab bar:** Organize multiple files inside tab components featuring drag-and-drop reordering, title renaming, and local session persistence. -* **🔒 Privacy & Security Focus:** No analytics, tracking beacons, or backend servers. HTML output is sanitized via DOMPurify to eliminate Cross-Site Scripting (XSS) threats. +### 🖊️ Decoupled Split-Screen Editing +Type Markdown in the custom editor and watch it render in real-time in the live preview pane. +

+ Decoupled Split-Screen Editing +

+ +### 📐 LaTeX Math Notation +Render inline and display mathematical formulas natively using the MathJax typesetting engine. +

+ LaTeX Math Notation +

+ +### 📊 Interactive Mermaid Diagrams +Generate flowcharts, Gantt charts, and sequence diagrams with zoom, pan, and SVG export controls. +

+ Interactive Mermaid Diagrams + Mermaid Toolbar +

+ +### 🗺️ Interactive Map Renderers +Parse and visualize GeoJSON and TopoJSON map files directly inside your preview area. +

+ Interactive Map Renderers +

+ +### 📦 STL 3D Model Renderer +Render and interact with STL (ASCII/Binary) files featuring perspective controls, flat shading, and reset controls. +

+ STL 3D Model Renderer +

+ +### 🎼 ABC Music Notation Renderers +Render client-side ABC music notation directly to beautifully styled SVG sheet music with full offline rendering support. +

+ ABC Music Notation Renderers +

+ +### 📑 Multi-Document Tab Workspace +Organize multiple open files inside drag-and-drop tabs with local session persistence and tab context menus. +

+ Multi-Document Tab Workspace +

+ +### 🔍 Find & Replace with AST Scoping & Diff Preview +Perform scoped searches using regular expressions, syntax scopes, and side-by-side visual diff replacements. +

+ Find & Replace with Diff Preview +

+ +### 🛠️ Formatting Toolbar & Quick Modals +Quickly insert markdown elements, tables, emojis, and symbols using dedicated formatting toolbar modals. +

+ Formatting Toolbar & Quick Modals +

+ +### 🌐 Multi-Language Translation (i18n) +Access a fully localized user interface with support for English, Simplified Chinese, Japanese, Korean, Portuguese, and more. +

+ Multi-Language Translation (i18n) +

+ +### 📤 Layout-Aware PDF, HTML & PNG Export +Export your documents to raw Markdown, centered inline HTML, high-quality PNG images, or paginated PDF with re-engineered page breaks. +

+ Layout-Aware PDF, HTML & PNG Export +

+ +### 🔗 Serverless Compressed URL Sharing +Share view or edit mode documents database-free via zlib DEFLATE compressed URL hashes. +

+ Serverless Compressed URL Sharing +

+ +### 📥 Multi-Source File Import +Drag and drop local files, or import directories recursively directly from public GitHub repositories. +

+ Multi-Source File Import + File Import selection +

+ +### ⚡ Performance & Web Worker Compilation +Compile Markdown off-thread using a background Web Worker and cache gutter wrapping coordinates to avoid layout thrashing. +

+ Performance & Web Worker Compilation +

+ +### 🔒 Security Hardening & PWA Offline Support +Work offline via local Service Worker caching, protected by SHA-384 subresource integrity check policies. +

+ Security Hardening & PWA Offline Support +

+ +### 📝 GitHub-Style Alert Blocks +Format and render official GitHub-style admonitions (`> [!NOTE]`, etc.) with correct color schemes and icons. +

+ GitHub-Style Alert Blocks +

+ +### 📊 Estimated Reading Time & Word Stats +Track word count, character count, and estimated reading time dynamically via a live status counter. +

+ Estimated Reading Time & Word Stats +

+ +### 🎨 Custom Theme Toggle +Switch instantly between light and dark themes with CSS-variable based syntax highlighting. +

+ Custom Theme Toggle +

+ +### ↩️ Custom History State (Undo/Redo) +Restore and redo editor history individually per document tab using custom-built in-memory history state stacks. +

+ Custom History State (Undo/Redo) +

+ +### ⌨️ Comprehensive Keyboard Shortcuts +Increase typing efficiency with native keybinds for file saving, sync scrolling, tab management, and text editing. +

+ Comprehensive Keyboard Shortcuts +

+ +### 📂 Full-Window Drag-and-Drop Overlay +Drag markdown files anywhere onto the browser window to instantly import and open them in the workspace. +

+ Full-Window Drag-and-Drop Overlay +

+ +### 🧭 Throttled Bidirectional Scroll Sync +Keep the editor and preview pane aligned using scroll lock mechanisms and requestAnimationFrame coordinates mapping. +

+ Throttled Bidirectional Scroll Sync +

--- @@ -125,8 +221,10 @@ graph TD CSS["styles.css
(Custom Themes & Reset)"] Script["script.js
(UI Orchestration)"] Editor["Markdown Editor
(Textarea + Gutter)"] - Preview["Preview Pane
(Isolated Render Area)"] + Preview["Preview Pane
(Direct DOM Render Area)"] Modal["Mermaid Modal
(Zoom & Drag-to-Pan)"] + i18n["i18n Localization Engine
(Dictionary translation)"] + DOMPurify["DOMPurify.js
(Strict XSS Sanitizer)"] end %% Background Web Worker Group @@ -138,16 +236,21 @@ graph TD %% Storage Group subgraph Storage ["Local Storage & Network Proxy"] - LS["localStorage
(Tabs, Settings, Session)"] + LS["localStorage
(Tabs, Settings, Shadow Cache)"] Cache["Browser Cache
(Service Worker sw.js)"] + LocalAssets["Local Static Assets
(Icons, sample.md, manifest)"] end %% Third-Party Utilities - subgraph CDNs ["Third-Party CDN Libraries (Lazy Loaded)"] + subgraph CDNs ["Third-Party CDN Libraries (Lazy Loaded / Local Offline Mapped)"] MathJax["MathJax.js
(LaTeX Math)"] Mermaid["Mermaid.js
(Diagrams)"] - PDF["jsPDF & html2canvas
(PDF Export Pipeline)"] - Pako["Pako.js
(zlib share encoder)"] + PDF["jsPDF & html2canvas
(PDF/PNG Export)"] + Pako["Pako.js
(DEFLATE share encoder)"] + JoyPixels["JoyPixels.js/css
(Emoji Tool)"] + Leaflet["Leaflet.js/css & TopoJSON
(Interactive Maps)"] + ThreeJS["Three.js, loaders & controls
(3D STL Viewer)"] + Abcjs["abcjs-basic.js
(Sheet Music)"] end %% Native Desktop Layer @@ -161,28 +264,46 @@ graph TD PWorker -- "3. Load Scripts" --> MarkedLib PWorker -- "3. Load Scripts" --> HljsLib PWorker -- "4. Returns Compiled HTML Blocks & Hashes" --> Script - Script -- "5. Incremental Patching (replaceWith)" --> Preview - Script -- "6. Debounced State Auto-Save" --> LS + Script -- "5. Sanitize HTML segments" --> DOMPurify + DOMPurify -- "6. Incremental Patching / Full Fallback" --> Preview + Script -- "7. Debounced State Auto-Save" --> LS + LS -. "Shadow Cache Sync" .-> Script + + %% Scroll sync loop + Editor -- "Proportional Scroll Sync (RAF)" --> Preview + Preview -- "Proportional Scroll Sync (RAF)" --> Editor %% Dynamic Loading triggers - Script -- "Lazy Load (Math strings detected)" --> MathJax - Script -- "Lazy Load (Mermaid block detected)" --> Mermaid - Script -- "Lazy Load (On PDF Export click)" --> PDF - Script -- "Lazy Load (On Share click)" --> Pako + Script -- "Lazy Load (Math string detected)" --> MathJax + Script -- "Lazy Load (Mermaid class detected)" --> Mermaid + Script -- "Lazy Load (On Export click)" --> PDF + Script -- "Lazy Load (On Share click/hash load)" --> Pako + Script -- "Lazy Load (Colons detected)" --> JoyPixels + Script -- "Lazy Load (geo/topojson map class)" --> Leaflet + Script -- "Lazy Load (stl-viewer class)" --> ThreeJS + Script -- "Lazy Load (abc music class)" --> Abcjs %% Downstream Rendering outputs MathJax -- "Inject Math formulas" --> Preview Mermaid -- "Draw SVGs + Toolbars" --> Preview - Preview -- "Double click diagram" --> Modal - PDF -- "Capture sandboxed canvas" --> Script + Preview -- "Click toolbar Zoom button" --> Modal + PDF -- "Capture sandboxed canvas (useCORS)" --> Script + JoyPixels -- "Render emojis" --> Preview + Leaflet -- "Render interactive maps" --> Preview + ThreeJS -- "Render 3D STL model" --> Preview + Abcjs -- "Render sheet music" --> Preview %% Network Proxy Caching Cache -. "Network-First (App Assets)" .-> HTML Cache -. "Network-First (App Assets)" .-> Script Cache -. "Network-First (App Assets)" .-> CSS - Cache -. "Cache-First (5.4MB bundles)" .-> CDNs + Cache -. "Network-First (App Assets)" .-> PWorker + Cache -. "Network-First (App Assets)" .-> sw.js + Cache -. "Stale-While-Revalidate" .-> LocalAssets + Cache -. "Cache-First (Lazy-loaded assets)" .-> CDNs %% Desktop Logic + Script -- "Redirect CDNs to /libs/ offline copies" --> Script Script -- "Access OS API if wrapped" --> Neu ``` @@ -196,147 +317,62 @@ graph TD --- -## Under-the-Hood Subsystems Deep-Dive - -Markdown Viewer employs custom-engineered client-side engines to deliver production-grade performance. Below is a detailed breakdown of the 11 core subsystems. For full source code listings and in-depth details of each implementation, please check the [Features Wiki](wiki/Features). - -### 1. Global State & Session Persistence -The global state manages application-wide preferences (such as theme, text direction, active tab, and split-pane ratio). It uses an **in-memory shadowing cache** to skip repeated parsing/serialization cycles over the synchronous `localStorage` block (preventing blocking disk I/O). - -Theme switches write the theme attribute directly to the HTML document root to avoid visual flash or full-page layout reflows during loading. CSS transitions are strictly scoped to color properties to prevent costly layout recalculations: - -$$\text{document.documentElement.setAttribute("data-theme", theme)}$$ - -### 2. Document Tab & Session Lifecycle -Document files reside in an isolated document tab array structure. Tab dragging reorders tabs using the HTML5 Drag and Drop API, updating the underlying index array. Dropdown menus are positioned relative to the tab's bounding rectangle via `getBoundingClientRect()`. Keyboard accessibility mappings (`ArrowRight`, `ArrowLeft`, `Home`, `End`, `Enter`, `Space`) coordinate focus states inside the tab-list. - -### 3. Tab Overflow & Navigation -When open tabs exceed the horizontal viewport, the tab bar switches to an overflow state. Vertical mouse scroll wheel inputs are intercepted and translated to horizontal scroll coordinates to enable side-scrolling: - -$$\Delta X_{\text{scroll}} = \Delta Y_{\text{wheel}}$$ - -Overflow check checks the inequality `scrollWidth > clientWidth` to toggle the visibility of click-to-scroll navigation arrows. - -### 4. Responsive Pane Resizer & View Mode Layout Controller -The horizontal resizer calculates the percentage width of the editor relative to its parent container during window resizing: - -$$\text{Percent}_{\text{editor}} = \text{clamp}\left(\frac{X_{\text{mouse}} - X_{\text{container-left}}}{W_{\text{container}}} \times 100, 20\\%, 80\\%\right)$$ - -The event loop tracks global resizing states on window mouse and touch move events, updating layout grid constraints via CSS properties. - -### 5. Rich Text Editor History & Undo/Redo Engine -To maintain separate command histories when navigating multiple documents, the history manager maintains tab-specific undo/redo stacks. Edits are batched to avoid bloated memory allocations; updates are pushed to the history stack only when transition boundaries occur, word borders (spaces) are typed, or keyboard idle time exceeds 300ms. - -### 6. Dynamic Line-Number Gutter & Selection Highlighter -To keep line numbers in the gutter aligned with wrapped text in the transparent editor area, the gutter employs font-size wrap calculations: - -$$\text{LineHeight} = \text{fontSize} \times 1.5$$ - -$$\text{wrapCount} = \text{Math.ceil}\left(\frac{\text{TextLength} \times \text{CharWidth}}{\text{EditorWidth}}\right)$$ - -DOM gutter paints are scheduled via `requestAnimationFrame` to prevent layout thrashing. A background overlay matches the text scroll coordinates to highlight find-and-replace queries. - -### 7. Web Worker Segmented Markdown Compilation & Sanitization -Document parsing is offloaded to `preview-worker.js` on a background thread. Before offloading, the system runs safety checks to ensure the document contains no global definitions or complex footnotes. If safe, the worker tokenizes the text into blocks on double-newlines, calculates 32-bit FNV-1a hashes for each segment: - -$$H_i = (H_{i-1} \oplus d_i) \times p$$ - -where $p = 16777619$ (FNV prime) and $H_0 = 2166136261$ (offset basis). Only modified blocks are re-parsed, saving substantial CPU cycles. - -### 8. Throttled Bidirectional Scroll Synchronization -Proportional scrolling coordinates positions between the text editor and preview pane: - -$$Y_{\text{target}} = \frac{Y_{\text{source}}}{H_{\text{source-scroll}} - H_{\text{source-client}}} \times (H_{\text{target-scroll}} - H_{\text{target-client}})$$ - -Scrolling feedback loops are prevented using state locks and decoupled animation schedules using `requestAnimationFrame` with a 50ms release timeout. - -### 9. Interactive Mermaid Diagram & MathJax LaTeX Renderer -MathJax typesets equations asynchronously. A cleanup script strips MathJax's default assistive markup elements to prevent duplicate accessibility readings. Rendered SVG diagrams are manipulated in zoom modals using transform translation matrices: - -$$\mathbf{T}_{\text{svg}} = \text{translate}(X_{\text{pan}}, Y_{\text{pan}}) \times \text{scale}(S_{\text{zoom}})$$ - -### 10. Draggable Find/Replace Search & Diff Preview Engine -Regular expression searches are parsed inside try-catch validation locks to avoid breaking runtime operations. The floating panel coordinates are clamped inside the window bounds: - -$$X_{\text{clamp}} = \max(0, \min(X_{\text{mouse}}, W_{\text{window}} - W_{\text{panel}}))$$ - -$$Y_{\text{clamp}} = \max(0, \min(Y_{\text{mouse}}, H_{\text{window}} - H_{\text{panel}}))$$ - -A diff comparison engine computes modified line buffers to display a red/green visual preview before applying replacements. - -

- Markdown Viewer - Draggable find and replace panel with scoped search filters for Mermaid diagrams, LaTeX equations, and raw text diff preview -

- -### 11. Layout-Aware PDF Export & URL Sharing Subsystem -PDF generation uses a multi-pass stabilization cascade loop (up to 10 iterations) to align layout components: -- Inline SVGs are converted to Base64 PNGs. -- Header elements near borders are shifted down via `.pdf-page-break-spacer` to prevent orphan tags. -- Tables are dynamically split and `` elements are re-injected onto split tables. -- Text element slicing is prevented by shifting lines downward past page cuts: - -$$\text{Shift} = (Y_{\text{boundary}} - Y_{\text{line-top}}) + 4\text{px}$$ +## Getting Started & Installation -Documents are shared database-free via zlib DEFLATE compressed Base64 hashes. +### 💻 Option 1: Quick Local Run (No Installation/No Server) +Because Markdown Viewer runs completely client-side utilizing standard HTML, CSS, and JavaScript, you can run it instantly directly from your filesystem: +1. Clone or download the repository to your local machine. +2. Open the repository folder in your system **File Manager**. +3. Simply double-click **`index.html`** to open the editor directly in your default web browser. --- -## Getting Started & Installation - -### Option 1: Docker (Pre-built Image) -Deploy the pre-compiled image hosted on the GitHub Container Registry (GHCR): +### 🐳 Option 2: Docker Container Deployment +If you prefer running the application inside a containerized environment, choose one of the following methods: +**Pre-built Docker Image (GHCR):** ```bash -docker pull ghcr.io/thisis-developer/markdown-viewer:sha-15eafb0 docker run -d \ --name markdown-viewer \ -p 8080:80 \ --restart unless-stopped \ ghcr.io/thisis-developer/markdown-viewer:latest ``` +Open **[http://localhost:8080](http://localhost:8080)** in your browser. -Open **http://localhost:8080** in your browser. - -### Option 2: Docker Compose (Local Build) -Clone the repository and spin up the container using Compose: - +**Local Docker Compose Build:** ```bash git clone https://github.com/ThisIs-Developer/Markdown-Viewer.git cd Markdown-Viewer docker compose up -d ``` -The application will start on **http://localhost:8080**. - -### Option 3: Local Static Web Server -Because the code runs completely client-side, you can host the root directory using any static web server: - -```bash -# Clone the repository -git clone https://github.com/ThisIs-Developer/Markdown-Viewer.git -cd Markdown-Viewer - -# Open VSCode IDE -open index.html -and run on localhost http://127.0.0.1:5500 in your browser. - -# OR Serve with Python (built-in, no dependencies) -python3 -m http.server 8080 - -# Serve with Node.js serve -npx serve . -p 8080 -``` -Open **http://localhost:8080**. - -### Option 4: Desktop Application -Pre-built desktop binaries are available on the [Releases](https://github.com/ThisIs-Developer/Markdown-Viewer/releases) page for Windows, Linux, and macOS. +Open **[http://localhost:8080](http://localhost:8080)** in your browser. -To build the desktop application locally from source: -1. Navigate to the `desktop-app/` directory. -2. Run `npm install` followed by `node setup-binaries.js` to download Neutralino binaries. -3. Synchronize files with `node prepare.js`. -4. Compile using `npm run build` (for Windows embedded) or `npm run build:portable`. +--- -For detailed desktop app settings, see the [Desktop App Wiki](wiki/Desktop-App). +### 🖥️ Option 3: Building the Desktop Application +You can compile and run a native standalone desktop app (Windows, macOS, or Linux) locally from source: +1. Clone the repository and navigate into the `desktop-app/` directory: + ```bash + cd desktop-app + ``` +2. Open the `desktop-app` directory in your system **File Manager**. +3. Open a command prompt/terminal inside this folder and run the installation and build commands: + ```powershell + # Install node dependencies and download Neutralino binaries + npm install + node setup-binaries.js + + # Synchronize resources with the main web app + node prepare.js + + # Build/compile the application for Windows and other systems + npm run build + # Or build a standalone portable executable + npm run build:portable + ``` + +*Note: You can also download prebuilt standalone binaries directly from the [Releases](https://github.com/ThisIs-Developer/Markdown-Viewer/releases) page without compiling it yourself.* --- @@ -352,17 +388,15 @@ For detailed desktop app settings, see the [Desktop App Wiki](wiki/Desktop-App). | Action | Windows / Linux | macOS | | :--- | :--- | :--- | | **Export raw Markdown** | `Ctrl + S` | `⌘ + S` | -| **Copy Rich HTML** | `Ctrl + C` (with no text selected) | `⌘ + C` (with no text selected) | -| **Toggle Scroll Sync** | `Ctrl + Shift + S` | `⌘ + Shift + S` | -| **Open a New Tab** | `Ctrl + T` | `⌘ + T` | -| **Close the Active Tab** | `Ctrl + W` | `⌘ + W` | -| **Open Find & Replace** | `Ctrl + F` | `⌘ + F` | -| **Undo Last Edit** | `Ctrl + Z` | `⌘ + Z` | +| **Copy plain text Markdown** | `Ctrl + C` (with no text selected) | `⌘ + C` (with no text selected) | +| **Toggle Scroll Sync** | `Ctrl + Shift + S` (in Split view) | `⌘ + Shift + S` (in Split view) | +| **Open a New Tab** | `Ctrl + T` (desktop) / `Alt + Shift + T` (web) | `⌘ + T` (desktop) / `⌥ + ⇧ + T` (web) | +| **Close the Active Tab** | `Ctrl + W` (desktop) / `Alt + Shift + W` (web) | `⌘ + W` (desktop) / `⌥ + ⇧ + W` (web) | +| **Open Find & Replace** | `Ctrl + F` / `Ctrl + H` (replace) | `⌘ + F` / `⌘ + H` (replace) | +| **Undo Last Edit** | `Ctrl + Z` (when editor active) | `⌘ + Z` (when editor active) | | **Redo Last Edit** | `Ctrl + Shift + Z` / `Ctrl + Y` | `⌘ + Shift + Z` / `⌘ + Y` | -| **Insert Code Block** | `Ctrl + Shift + C` | `⌘ + Shift + C` | -| **Toggle Fullscreen Editor** | `F11` | `F11` | -| **Insert 2-space Indent** | `Tab` | `Tab` | -| **Outdent Line** | `Shift + Tab` | `Shift + Tab` | +| **Insert 2-space Indent** | `Tab` (when editor active) | `Tab` (when editor active) | + --- @@ -392,20 +426,34 @@ Markdown-Viewer/ ## Built With (Technology Stack) +

+ HTML5 + CSS3 + JavaScript + Bootstrap + NeutralinoJS +

+ | Library Name | Version | Role in App | Loading Method | | :--- | :--- | :--- | :--- | -| **Marked.js** | 9.1.6 | Parses markdown content to HTML elements. | Defer (Upfront) | -| **Highlight.js** | 11.9.0 | Adds syntax highlighting to code sections. | Defer (Upfront) | -| **DOMPurify** | 3.0.9 | Sanitizes HTML outputs. | Defer (Upfront) | -| **FileSaver.js** | 2.0.5 | Manages file saving on the client side. | Defer (Upfront) | -| **js-yaml** | 4.1.0 | Parses YAML frontmatter headers. | Defer (Upfront) | -| **Bootstrap** | 5.3.2 | Provides component structures and modal panels. | Upfront Script | -| **Mermaid.js** | 11.15.0 | Renders diagrams and charts. | Lazy-loaded on diagram find | -| **MathJax** | 3.2.2 | Renders math formulas. | Lazy-loaded on math find | -| **jsPDF** | 2.5.1 | Generates PDF documents. | Lazy-loaded on PDF request | -| **html2canvas** | 1.4.1 | Captures HTML layouts as canvas objects. | Lazy-loaded on PDF request | -| **pako.js** | 2.1.0 | Compresses shared links. | Lazy-loaded on share request | -| **JoyPixels** | 9.0.1 | Renders emoji sets. | Lazy-loaded on emoji select | +| **[Marked.js](https://marked.js.org/)** | 9.1.6 | Parses markdown content to HTML elements. | Defer (Upfront) | +| **[Highlight.js](https://highlightjs.org/)** | 11.9.0 | Adds syntax highlighting to code sections. | Defer (Upfront) | +| **[DOMPurify](https://github.com/cure53/DOMPurify)** | 3.0.9 | Sanitizes HTML outputs against XSS. | Defer (Upfront) | +| **[FileSaver.js](https://github.com/eligrey/FileSaver.js/)** | 2.0.5 | Manages file saving on the client side. | Defer (Upfront) | +| **[js-yaml](https://github.com/nodeca/js-yaml)** | 4.1.0 | Parses YAML frontmatter headers. | Defer (Upfront) | +| **[Bootstrap](https://getbootstrap.com)** | 5.3.2 | Provides component structures and modal panels. | Upfront Script | +| **[Bootstrap Icons](https://icons.getbootstrap.com/)** | 1.11.3 | Provides responsive vector symbols across formatting tools and headers. | Preloaded (Upfront) | +| **[GitHub Markdown CSS](https://github.com/sindresorhus/github-markdown-css)** | 5.3.0 | Matches GitHub's exact light and dark typography rendering styles. | Upfront / Exports | +| **[Mermaid.js](https://mermaid.js.org/)** | 11.15.0 | Renders interactive flowcharts and diagrams. | Lazy-loaded on diagram find | +| **[MathJax](https://www.mathjax.org/)** | 3.2.2 | Renders mathematical LaTeX expressions. | Lazy-loaded on math find | +| **[jsPDF](https://github.com/parallax/jsPDF)** | 2.5.1 | Generates paginated PDF documents client-side. | Lazy-loaded on PDF request | +| **[html2canvas](https://html2canvas.hertzen.com/)** | 1.4.1 | Captures HTML layouts as canvas objects. | Lazy-loaded on PDF request | +| **[pako.js](https://github.com/nodeca/pako)** | 2.1.0 | Handles DEFLATE compression for share links. | Lazy-loaded on share request | +| **[JoyPixels](https://www.joypixels.com/)** | 9.0.1 | Renders standard emoji sets. | Lazy-loaded on emoji select | +| **[Leaflet](https://leafletjs.com/)** | 1.9.4 | Powers interactive GeoJSON and TopoJSON map overlays. | Lazy-loaded on map detection | +| **[TopoJSON](https://github.com/topojson/topojson)** | 3.0.2 | Parses TopoJSON structures into standard GeoJSON coordinates. | Lazy-loaded on topojson detection | +| **[Three.js](https://threejs.org/)** | r128 | Renders STL 3D models with canvas viewports. | Lazy-loaded on STL file detection | +| **[ABC Music Notation (abcjs)](https://www.abcjs.net/)** | 6.5.2 | Renders sheet music notation from raw text definitions. | Lazy-loaded on abc music detection | --- diff --git a/desktop-app/prepare.js b/desktop-app/prepare.js index 80f70e8..79df5b0 100644 --- a/desktop-app/prepare.js +++ b/desktop-app/prepare.js @@ -243,6 +243,41 @@ async function prepareOfflineDependencies() { url: "https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js", dest: path.join(LIBS_DIR, "OrbitControls.js"), hash: null + }, + { + url: "https://cdn.jsdelivr.net/npm/mermaid@11.15.0/dist/mermaid.min.js", + dest: path.join(LIBS_DIR, "mermaid.min.js"), + hash: null + }, + { + url: "https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.min.js", + dest: path.join(LIBS_DIR, "tex-mml-chtml.min.js"), + hash: null + }, + { + url: "https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js", + dest: path.join(LIBS_DIR, "jspdf.umd.min.js"), + hash: null + }, + { + url: "https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js", + dest: path.join(LIBS_DIR, "html2canvas.min.js"), + hash: null + }, + { + url: "https://cdnjs.cloudflare.com/ajax/libs/pako/2.1.0/pako.min.js", + dest: path.join(LIBS_DIR, "pako.min.js"), + hash: null + }, + { + url: "https://cdn.jsdelivr.net/npm/emoji-toolkit@9.0.1/lib/js/joypixels.min.js", + dest: path.join(LIBS_DIR, "joypixels.min.js"), + hash: null + }, + { + url: "https://cdn.jsdelivr.net/npm/emoji-toolkit@9.0.1/extras/css/joypixels.min.css", + dest: path.join(LIBS_DIR, "joypixels.min.css"), + hash: null } ]; diff --git a/desktop-app/resources/js/script.js b/desktop-app/resources/js/script.js index 5ebd865..8586cad 100644 --- a/desktop-app/resources/js/script.js +++ b/desktop-app/resources/js/script.js @@ -45,6 +45,13 @@ document.addEventListener("DOMContentLoaded", function () { // Resolve local paths for desktop (Neutralinojs) offline support if (typeof Neutralino !== 'undefined') { + CDN.mermaid = '/libs/mermaid.min.js'; + CDN.mathjax = '/libs/tex-mml-chtml.min.js'; + CDN.jspdf = '/libs/jspdf.umd.min.js'; + CDN.html2canvas = '/libs/html2canvas.min.js'; + CDN.pako = '/libs/pako.min.js'; + CDN.joypixels = '/libs/joypixels.min.js'; + CDN.joypixels_css = '/libs/joypixels.min.css'; CDN.abcjs = '/libs/abcjs-basic-min.js'; CDN.leaflet_css = '/libs/leaflet.css'; CDN.leaflet_js = '/libs/leaflet.js'; diff --git a/script.js b/script.js index 5ebd865..8586cad 100644 --- a/script.js +++ b/script.js @@ -45,6 +45,13 @@ document.addEventListener("DOMContentLoaded", function () { // Resolve local paths for desktop (Neutralinojs) offline support if (typeof Neutralino !== 'undefined') { + CDN.mermaid = '/libs/mermaid.min.js'; + CDN.mathjax = '/libs/tex-mml-chtml.min.js'; + CDN.jspdf = '/libs/jspdf.umd.min.js'; + CDN.html2canvas = '/libs/html2canvas.min.js'; + CDN.pako = '/libs/pako.min.js'; + CDN.joypixels = '/libs/joypixels.min.js'; + CDN.joypixels_css = '/libs/joypixels.min.css'; CDN.abcjs = '/libs/abcjs-basic-min.js'; CDN.leaflet_css = '/libs/leaflet.css'; CDN.leaflet_js = '/libs/leaflet.js'; diff --git a/wiki/Localization.md b/wiki/Localization.md new file mode 100644 index 0000000..e2472f8 --- /dev/null +++ b/wiki/Localization.md @@ -0,0 +1,98 @@ +# Localization & Internationalization (i18n) + +Markdown Viewer (v3.7.5) features a fully client-side translation engine that translates all user interface menus, modals, and tooltips dynamically. + +--- + +## 🌐 Supported Languages + +The application currently supports **14 language locales**: + +| Locale Code | Language Name | Flag / Display Name | +| :--- | :--- | :--- | +| **`en`** | English | 🇺🇸 English | +| **`zh`** | 简体中文 (Simplified Chinese) | 🇨🇳 简体中文 | +| **`tw`** | 繁體中文 (Traditional Chinese) | 🇹🇼 繁體中文 | +| **`ja`** | 日本語 (Japanese) | 🇯🇵 日本語 | +| **`ko`** | 한국어 (Korean) | 🇰🇷 한국어 | +| **`pt`** | Português (Brasil) | 🇧🇷 Português (Brasil) | +| **`es`** | Español (Spanish) | 🇪🇸 Español | +| **`fr`** | Français (French) | 🇫🇷 Français | +| **`de`** | Deutsch (German) | 🇩🇪 Deutsch | +| **`ru`** | Русский (Russian) | 🇷🇺 Русский | +| **`it`** | Italiano (Italian) | 🇮🇹 Italiano | +| **`tr`** | Türkçe (Turkish) | 🇹РУ Türkçe | +| **`pl`** | Polski (Polish) | 🇵🇱 Polski | +| **`uk`** | Українська (Ukrainian) | 🇺🇦 Українська | + +--- + +## ⚙️ Architecture & Selection Precedence + +When a user visits the application, the translation engine resolves the locale using the following precedence cascade: + +```mermaid +graph TD + A["1. URL Query Parameter (?lang=zh)"] -->|Found| B["Apply Language Settings"] + A -->|Not Found| C["2. localStorage ('app-lang')"] + C -->|Found| B + C -->|Not Found| D["3. Browser Language (navigator.language)"] + D -->|Match| B + D -->|No Match| E["4. Default Locale ('en')"] + E --> B +``` + +### 1. URL Query Parameter Mapping +If the URL contains a `?lang=` query parameter (e.g., `https://markdownviewer.pages.dev/?lang=pt`), it overrides all other settings. + +### 2. Local Storage Persistence +When a user manually selects a language from the dropdown menu, their choice is saved to `localStorage` under the key `'app-lang'`. This preference is loaded on subsequent visits. + +### 3. Automatic Browser Detection +If no parameter or storage key is found, the engine queries `navigator.language` and falls back to matching the user's primary browser settings. + +--- + +## 📝 Localization Dictionary Schema + +All translations are defined statically within `script.js` inside the `I18N_DICTS` object. The localized items use the following dictionary schema: + +```javascript +{ + title: "Markdown Viewer", + subtitle: "Live Markdown Editor", + new: "New", + open: "Open", + export: "Export", + exportMd: "Markdown (.md)", + exportHtml: "HTML", + exportPdf: "PDF", + exportPng: "Image (.png)", + copy: "Copy", + copied: "Copied!", + share: "Share", + reset: "Reset", + editor: "Editor", + split: "Split", + preview: "Preview", + minRead: "Min read", + words: "Words", + chars: "Chars", + switchRtl: "Switch to RTL", + switchLtr: "Switch to LTR", + darkMode: "Dark Mode", + lightMode: "Light Mode", + helpTitle: "Markdown Viewer Help", + aboutTitle: "About Markdown", + shareTitle: "Share Document", + renameTitle: "Rename File", + insertLink: "Insert Link", + insertRef: "Insert Quote", + insertImg: "Insert Image", + insertTable: "Insert Table", + findReplace: "Find & Replace", + placeholder: "Type your markdown here...", + loadingEmojis: "Loading emojis...", + loadingFiles: "Fetching file structure..." +} +```