diff --git a/README.md b/README.md index 49a5eb5..92eb38e 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,36 @@ npm run package Output goes to the `dist/` folder. Targets: NSIS/ZIP (Windows), DMG/ZIP (macOS), AppImage/DEB (Linux). ---- + +## Installing on Linux + +**DEB** (Debian, Ubuntu, Mint, Pop!_OS, and other Debian-based distros): + +```bash +sudo apt install ./moilstack-md_*.deb +``` + +**AppImage** (works on virtually any distro — Fedora, Arch, openSUSE, Ubuntu, etc. — no installation required): + +```bash +chmod +x moilstack-md-*.AppImage +./moilstack-md-*.AppImage +``` + +If it fails to launch with a FUSE-related error (some minimal or newer distros, e.g. Fedora 41+, ship without FUSE2 by default), either install FUSE: + +```bash +# Fedora +sudo dnf install fuse fuse-libs +# Ubuntu/Debian +sudo apt install fuse +``` + +or skip FUSE entirely and extract-and-run instead: + +```bash +./moilstack-md-*.AppImage --appimage-extract-and-run +``` ## AI Assistant Setup diff --git a/build/icons/1024x1024.png b/build/icons/1024x1024.png new file mode 100644 index 0000000..e8eabdb Binary files /dev/null and b/build/icons/1024x1024.png differ diff --git a/build/icons/128x128.png b/build/icons/128x128.png new file mode 100644 index 0000000..4e453cb Binary files /dev/null and b/build/icons/128x128.png differ diff --git a/build/icons/16x16.png b/build/icons/16x16.png new file mode 100644 index 0000000..90f9288 Binary files /dev/null and b/build/icons/16x16.png differ diff --git a/build/icons/256x256.png b/build/icons/256x256.png new file mode 100644 index 0000000..7f7b7f8 Binary files /dev/null and b/build/icons/256x256.png differ diff --git a/build/icons/32x32.png b/build/icons/32x32.png new file mode 100644 index 0000000..3711332 Binary files /dev/null and b/build/icons/32x32.png differ diff --git a/build/icons/48x48.png b/build/icons/48x48.png new file mode 100644 index 0000000..94587ab Binary files /dev/null and b/build/icons/48x48.png differ diff --git a/build/icons/512x512.png b/build/icons/512x512.png new file mode 100644 index 0000000..2cf1332 Binary files /dev/null and b/build/icons/512x512.png differ diff --git a/build/icons/64x64.png b/build/icons/64x64.png new file mode 100644 index 0000000..a4ed8db Binary files /dev/null and b/build/icons/64x64.png differ diff --git a/build/make-app-icon.js b/build/make-app-icon.js index 7382d82..7a966e4 100644 --- a/build/make-app-icon.js +++ b/build/make-app-icon.js @@ -4,10 +4,15 @@ const fs = require('fs'); const path = require('path'); const os = require('os'); -const PNG_SRC = path.join(__dirname, '../src/assets/icon.png'); -const ICO_DEST = path.join(__dirname, '../src/assets/icon.ico'); -const APPX_DIR = path.join(__dirname, 'appx'); -const SIZES = [16, 32, 44, 48, 150, 256, 310]; +const PNG_SRC = path.join(__dirname, '../src/assets/icon.png'); +const ICO_DEST = path.join(__dirname, '../src/assets/icon.ico'); +const APPX_DIR = path.join(__dirname, 'appx'); +const LINUX_DIR = path.join(__dirname, 'icons'); +const SIZES = [16, 32, 44, 48, 150, 256, 310]; +// electron-builder's Linux icon set: named by size so its packager can read +// dimensions from the filename instead of decoding the PNG (see build/icons +// vs. a single flat icon.png — the latter trips app-builder's size sniffer). +const LINUX_SIZES = [16, 32, 48, 64, 128, 256, 512, 1024]; const APPX_ASSETS = [ { name: 'Square44x44Logo.png', size: 44 }, @@ -52,6 +57,18 @@ async function run() { console.log(` ${asset.name} (${w}x${h}) ✓`); } console.log(`Done → ${APPX_DIR}`); + + console.log('Generating Linux icon set…'); + if (!fs.existsSync(LINUX_DIR)) fs.mkdirSync(LINUX_DIR); + for (const size of LINUX_SIZES) { + const outPath = path.join(LINUX_DIR, `${size}x${size}.png`); + await sharp(pngBuffer) + .resize(size, size, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) + .png() + .toFile(outPath); + console.log(` ${size}x${size} ✓`); + } + console.log(`Done → ${LINUX_DIR}`); } run().catch(err => { diff --git a/package.json b/package.json index fc5cef1..226a4fb 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ }, "build": { "appId": "com.moilstack.markdown", - "productName": "MoilStack .md", + "productName": "moilstack-md", + "icon": "build/icons", "copyright": "Copyright © 2026 MoilStack", "directories": { "output": "dist" @@ -38,14 +39,14 @@ "zip" ], "icon": "src/assets/icon.ico", - "artifactName": "MoilStack.md.${ext}" + "artifactName": "moilstack-md.${ext}" }, "nsis": { "oneClick": false, "allowToChangeInstallationDirectory": true, "createDesktopShortcut": true, "createStartMenuShortcut": true, - "shortcutName": "MoilStack .md", + "shortcutName": "moilstack-md", "include": "build/installer.nsh" }, "appx": { diff --git a/src/renderer/markdownRenderer.js b/src/renderer/markdownRenderer.js index b7751f3..e3eb772 100644 --- a/src/renderer/markdownRenderer.js +++ b/src/renderer/markdownRenderer.js @@ -175,9 +175,26 @@ const MarkdownRenderer = (() => { * @param {string} src Raw Markdown source. * @returns {string} HTML output. */ + /** + * Strip a leading YAML frontmatter block (used for tags, etc.) so it never + * renders as visible content — mirrors the skip logic in ipc.js's + * _extractFirstLine/_extractTags on the main-process side. + */ + function _stripFrontmatter(src) { + if (!src.startsWith('---')) return src; + const fmEnd = src.indexOf('\n---', 3); + if (fmEnd === -1) return src; + const afterDelim = fmEnd + 4; // past "\n---" + const nextNewline = src.indexOf('\n', afterDelim); + return nextNewline === -1 ? '' : src.slice(nextNewline + 1); + } + function parseMarkdown(src) { if (!src || !src.trim()) return ''; + src = _stripFrontmatter(src); + if (!src.trim()) return ''; + const lines = src.split('\n'); const out = []; let i = 0;