diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..2a2505d --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +NAME=Max Mustermann +SLOGAN=Senior Developer · Tech Enthusiast diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..7612528 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,47 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +A self-hosted LinkedIn Post Formatter that converts text with formatting markers (`**bold**`, `_italic_`) into Unicode Mathematical Alphanumeric Symbols. LinkedIn only accepts plain Unicode text (no HTML/Markdown), so the tool converts text into Unicode variants that *appear* formatted in the LinkedIn feed. + +## Running the Project + +```bash +npm start # Start server on port 3000 +PORT=8080 node server.js # Custom port +docker compose up -d # Docker deployment +``` + +There are no build, test, or lint steps. + +## Architecture + +The project is intentionally minimal: + +- **`server.js`** — 16-line Express server that only serves static files from `public/` and supports a `PORT` env var. +- **`public/index.html`** — The entire application: HTML, CSS, and JavaScript all inlined in one file (~289 lines). No frameworks, no bundler, no external dependencies. + +All formatting logic lives in `public/index.html` as vanilla JavaScript: + +- `applyInline(text, variant)` — Processes `**text**` (bold) and `_text_` (italic) markers within a variant pass +- `mapAll(text, map)` — Applies Unicode character mapping char-by-char +- `liParagraph(text)` — Inserts zero-width spaces (`\u200b`) between double newlines to preserve paragraph breaks when pasting into LinkedIn (which strips trailing blank lines) +- Six output variants: Sans (standard), Bold Sans, Italic Sans, Bold Italic Sans, Monospace, Plain + +The Unicode character maps are JavaScript objects mapping A–Z, a–z, 0–9 to their Unicode Mathematical Alphanumeric equivalents (e.g., bold sans, italic sans, monospace). + +## Key Implementation Details + +**Zero-width space trick:** LinkedIn strips trailing blank lines on paste. The app inserts `\u200b` between `\n\n` sequences to preserve paragraph structure. + +**Character limit:** LinkedIn max is 3000 characters. The counter uses color-coded feedback (green → amber → red) with `toLocaleString('de-DE')` formatting. + +**Clipboard fallback:** Uses `navigator.clipboard.writeText()` with a `document.execCommand('copy')` fallback for older browsers. + +**Keyboard shortcuts:** Ctrl/Cmd+B (bold), Ctrl/Cmd+I (italic), Ctrl/Cmd+Enter (generate preview). + +## Language + +The UI and all user-facing text is in **German**. Keep new UI additions in German. diff --git a/docker-compose.yml b/docker-compose.yml index 9c3e834..a429243 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,3 +5,4 @@ services: ports: - "3000:3000" restart: unless-stopped + env_file: .env diff --git a/package-lock.json b/package-lock.json index 283a2b0..8237c54 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "linkedin-formatter", "version": "1.1.0", "dependencies": { + "dotenv": "^17.4.1", "express": "^4.18.2" } }, @@ -156,6 +157,18 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dotenv": { + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.1.tgz", + "integrity": "sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", diff --git a/package.json b/package.json index cb86b72..933f5b3 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "start": "node server.js" }, "dependencies": { + "dotenv": "^17.4.1", "express": "^4.18.2" } } diff --git a/public/index.html b/public/index.html index 311c0db..4e3db0a 100644 --- a/public/index.html +++ b/public/index.html @@ -189,8 +189,8 @@ function generate(){