Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f543903654 | ||
|
|
0918ee0a65 | ||
|
|
70e6d03005 | ||
|
|
a1a58531d8 | ||
|
|
b955d857bf | ||
|
|
b00633af0f | ||
|
|
13eabc6247 | ||
|
|
fe9401c38f | ||
|
|
da781d9991 | ||
|
|
916d4b7c7f | ||
|
|
b7a654fc76 | ||
|
|
d0979544c4 | ||
|
|
e3be460793 | ||
|
|
fdc3b3bd52 | ||
|
|
cabfca770a | ||
|
|
f445902311 |
No files matched your search
@@ -1,51 +1,13 @@
|
||||
# clip2md — Design System
|
||||
|
||||
Register: **product**. Color strategy: **Restrained** (tinted neutrals + one accent ≤10%).
|
||||
Theme: **dark**. Scene: Nutzer legt spätabends oder tagsüber am Monitor schnell einen langen
|
||||
Thread ab; eine ruhige, dunkle, blendfreie Fläche hält den Fokus auf dem Text, nicht auf dem UI.
|
||||
Seit September 2026 Teil der **Klarbild-Familie** (Tokens aus `klarbild-oss/src/styles/tokens.css`).
|
||||
|
||||
## Color (OKLCH)
|
||||
- **Farbe:** warmes Papier `#EAEAE3`, Karte `#FBFBF7`, Linie `#D7D6CC`, Tinte `#16150F`, ein kräftiges Blau `#1B3BE0` (OKLCH 45% 0.23 267) für Primäraktion, Fokus, Logo. Dunkelmodus: blau getönte Neutrals, Blau aufgehellt.
|
||||
- **Schrift:** Space Grotesk (UI, Überschriften), Space Mono (Editor, Dateiname, Mono-Labels in Versalien mit 0.18em Sperrung). Self-hosted, keine Google-Fonts.
|
||||
- **Form:** Karten mit 4px Radius, Bedienelemente als Pills (999px). Kein Schatten außer 1px-Hauch und Toast/Sheet.
|
||||
- **Logo:** Klemmbrett mit Pfeil nach unten (Zwischenablage → Datei) in Blau, Wortmarke „clip**2**md" mit blauer 2. App-Icon: cremefarbenes Klemmbrett auf blauem Quadrat.
|
||||
- **Mobil:** Touch-Ziele ≥44px, Eingaben 16px (kein iOS-Zoom), `env(safe-area-inset-*)`, Einstellungen als Bottom-Sheet, Aktionsleiste als 5er-Raster mit Icon über Label, Speichern über Teilen-Menü.
|
||||
- **Motion:** ease-out-quint, 120–240ms, nur Opacity/Transform; `prefers-reduced-motion` respektiert.
|
||||
|
||||
Neutrals sind zur Marken-Hue (kühles Blau-Grau, ~265) getönt — nie reines `#000`/`#fff`.
|
||||
|
||||
| Token | OKLCH | Rolle |
|
||||
| --- | --- | --- |
|
||||
| `--bg` | `0.17 0.014 265` | App-Hintergrund (tief) |
|
||||
| `--surface` | `0.215 0.016 265` | Editor-Fläche |
|
||||
| `--raised` | `0.255 0.018 265` | Bars, Buttons |
|
||||
| `--line` | `0.32 0.02 265` | Ruhige Rahmen |
|
||||
| `--line-strong`| `0.42 0.024 265` | Aktive Rahmen |
|
||||
| `--text` | `0.95 0.006 265` | Primärtext |
|
||||
| `--muted` | `0.68 0.012 265` | Sekundärtext, Labels |
|
||||
| `--faint` | `0.5 0.012 265` | Tertiär, Legende |
|
||||
| `--accent` | `0.74 0.15 152` | Grün — Primäraktion, Fokus, „konvertiert" |
|
||||
| `--accent-ink` | `0.22 0.05 152` | Text auf Accent |
|
||||
| `--danger` | `0.66 0.16 25` | Fehler-Toast, destruktiv |
|
||||
|
||||
Accent trägt <10% der Fläche: Save-Button, Fokus-Ring, „konvertiert"-Badge. Sonst Neutrals.
|
||||
|
||||
## Typography
|
||||
|
||||
- **Sans (UI-Chrome):** Inter / system-ui. Labels, Buttons, Legende.
|
||||
- **Mono (Daten):** ui-monospace / JetBrains Mono. Editor, Dateiname, Zähler — alles, was „Inhalt" ist.
|
||||
- Scale mit ≥1.25-Kontrast: 11 (legende) · 12.5 (meta) · 14 (body/editor) · 15 (buttons) · 18 (wordmark).
|
||||
- Editor-Zeilenhöhe 1.65, `tab-size: 2`, Body-Zeilen bleiben durch die Mono-Fläche natürlich lesbar.
|
||||
|
||||
## Elevation & Layout
|
||||
|
||||
- Drei Ebenen: `bg` (App) → `surface` (Editor, das Herzstück, bekommt den Raum) → `raised` (Bars/Buttons).
|
||||
- Keine Cards, keine Schatten außer einem weichen Toast-Drop. Trennung über 1px-Linien und Ton, nicht Boxen.
|
||||
- Spacing-Rhythmus variiert bewusst: großzügig um den Editor, kompakt in der Toolbar.
|
||||
- Radius 10–12px, konsistent.
|
||||
|
||||
## Motion
|
||||
|
||||
- Ease-out-quint (`cubic-bezier(0.22, 1, 0.36, 1)`), 120–240ms. Kein Bounce.
|
||||
- Nur Opacity/Transform animieren. Toast slidet ein, Button-Press senkt 1px, „konvertiert"-Badge pulst einmal kurz, auto-aktualisierter Dateiname flasht dezent.
|
||||
- `prefers-reduced-motion`: alle nicht-essenziellen Transitions aus.
|
||||
|
||||
## Accessibility
|
||||
|
||||
- `:focus-visible` Ring in Accent, überall. Touch-Ziele ≥40px.
|
||||
- Toasts über `aria-live="polite"`. Editor & Felder korrekt gelabelt.
|
||||
- Kontrast: Text/`bg` und Accent-Ink/Accent über WCAG AA.
|
||||
## Historie
|
||||
Vorher: dunkles Theme mit Grün (v1), dann helles Editorial mit Geist und Zinnober/Blau (v2). Beides abgelöst.
|
||||
@@ -3,7 +3,7 @@ FROM nginx:1.27-alpine
|
||||
# Static single-page app — no build step.
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY security-headers.conf /etc/nginx/security-headers.conf
|
||||
COPY index.html impressum.html datenschutz.html legal.css icon-mono.svg manifest.webmanifest sw.js icon.svg /usr/share/nginx/html/
|
||||
COPY index.html clean.js impressum.html datenschutz.html imprint.html privacy.html legal.css icon-mono.svg manifest.webmanifest sw.js icon.svg icon-192.png icon-512.png icon-maskable-512.png apple-touch-icon.png /usr/share/nginx/html/
|
||||
COPY vendor/ /usr/share/nginx/html/vendor/
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
# clip2md — Paste to Markdown
|
||||
|
||||
Paste a long Reddit thread, an article, or any formatted web content, and save it as clean
|
||||
Markdown in a single keystroke. Runs entirely in your browser: nothing is uploaded, no account,
|
||||
Markdown in one click. Works on desktop and phone. Runs entirely in your browser: nothing is uploaded, no account,
|
||||
no tracking, works offline.
|
||||
|
||||
**Live demo:** https://clip2md.heidrich-digital.de
|
||||
|
||||

|
||||
|
||||
<img src="docs/screenshot-mobile.png" alt="clip2md on a phone" width="280">
|
||||
|
||||
## Why
|
||||
|
||||
Copying from the web and getting usable Markdown is usually two or three tools and a lot of
|
||||
@@ -19,8 +21,20 @@ Obsidian vault, a wiki, or a repo.
|
||||
|
||||
## Features
|
||||
|
||||
- **One-click paste.** The *Paste* button reads the clipboard directly (Async Clipboard API) and
|
||||
picks the HTML version when there is one. Browsers ask once for permission; `⌘V` always works too.
|
||||
- **Smart paste.** Formatted HTML (copy from a browser, e.g. Reddit `⌘A` → `⌘C`) is converted to
|
||||
clean Markdown. Plain text stays raw. Same `⌘V` for both, no mode switch.
|
||||
- **Page clean-up.** Pasting a whole web page drops navigation, cookie banners, share buttons and
|
||||
sidebars; articles are extracted with Mozilla Readability. *Undo clean-up* re-inserts the
|
||||
unfiltered version with one click.
|
||||
- **Reddit threads.** New and old Reddit: post title, subreddit and author on top, no vote counts or
|
||||
Reply/Share leftovers, comments as nested quotes with `(OP)` marked.
|
||||
- **Open in Obsidian.** Optional button that creates the note straight in your vault (vault and
|
||||
folder configurable), via the `obsidian://` URI and the clipboard — no file detour.
|
||||
- **History (opt-in).** Keeps the last 10 clips in this browser's IndexedDB. Off by default.
|
||||
- **iPhone shortcut.** iOS keeps web apps out of the share sheet; a four-step Shortcut fills the gap
|
||||
(see [docs/ios-shortcut.md](docs/ios-shortcut.md) or *iPhone shortcut* in the app footer).
|
||||
- **Force raw.** `⌘/Ctrl+Shift+V` pastes the next clip as plain text, skipping conversion.
|
||||
- **Live preview.** Toggle a side-by-side rendered Markdown view (marked + DOMPurify).
|
||||
- **Auto filename.** Derived from the first heading + date, e.g. `2026-08-11-my-thread.md`.
|
||||
@@ -29,11 +43,14 @@ Obsidian vault, a wiki, or a repo.
|
||||
knowledge bases like Obsidian.
|
||||
- **Conversion options.** Links as plain text, strip images, bullet marker (`-` / `*` / `+`),
|
||||
heading style (ATX `#` / Setext).
|
||||
- **Drag & drop.** Drop an `.html`, `.md` or `.txt` file to load or convert it.
|
||||
- **Open & drop files.** Pick or drop an `.html`, `.md` or `.txt` file to load or convert it.
|
||||
- **Mobile-first.** 44 px touch targets, 16 px inputs (no iOS zoom), safe-area aware, settings as a
|
||||
bottom sheet; *Save* hands the file to the share sheet (Files, Obsidian, mail) on phones.
|
||||
- **Bilingual.** English and German, switchable in the header.
|
||||
- **Light & dark.** Warm, flat, editorial light theme by default; dark mode one click away.
|
||||
- **Light & dark.** Warm paper, one strong blue, clipboard logo; dark mode one click away.
|
||||
- **Save / copy / clear**, word + character count and reading time.
|
||||
- **Installable PWA**, fully offline after first load.
|
||||
- **Installable PWA**, fully offline after first load. On Android, clip2md shows up in the
|
||||
system share sheet: share a page or selection straight into the editor.
|
||||
|
||||
Everything is **client-side**. No servers, no CDNs, no third-party requests — GDPR-friendly by
|
||||
construction.
|
||||
@@ -49,9 +66,10 @@ construction.
|
||||
|
||||
## Tech
|
||||
|
||||
- Single self-contained `index.html` (inline CSS/JS, OKLCH tokens, Geist + Geist Mono).
|
||||
- Single self-contained `index.html` (inline CSS/JS, OKLCH tokens, Space Grotesk + Space Mono).
|
||||
- Vendored, no CDN: Turndown + GFM plugin, marked, DOMPurify, fonts — all under `vendor/`.
|
||||
- Served by `nginx:alpine` (`Dockerfile` + `nginx.conf`) with a service worker for offline use.
|
||||
- Served by `nginx:alpine` (`Dockerfile` + `nginx.conf`) with a service worker for offline use
|
||||
(network-first for pages, cache-first for static assets).
|
||||
- No build step, no backend, no database.
|
||||
|
||||
## Run locally
|
||||
@@ -71,16 +89,22 @@ Any static host works — point it at this repo. The reference deployment uses
|
||||
## Update vendored libraries
|
||||
|
||||
```bash
|
||||
npm pack turndown turndown-plugin-gfm marked dompurify geist
|
||||
npm pack turndown turndown-plugin-gfm marked dompurify @mozilla/readability @fontsource/space-grotesk @fontsource/space-mono
|
||||
# turndown/dist/turndown.js -> vendor/turndown.js
|
||||
# turndown-plugin-gfm/dist/turndown-plugin-gfm.js -> vendor/turndown-plugin-gfm.js
|
||||
# marked/lib/marked.umd.js -> vendor/marked.umd.js
|
||||
# dompurify/dist/purify.min.js -> vendor/purify.min.js
|
||||
# geist/dist/fonts/**/*-Variable.woff2 -> vendor/fonts/
|
||||
# @mozilla/readability/Readability.js -> vendor/Readability.js
|
||||
# @fontsource/*/files/*-latin-{400,500,700}-normal.woff2 -> vendor/fonts/
|
||||
```
|
||||
|
||||
Bump the `CACHE` constant in `sw.js` whenever an asset changes so clients pick it up.
|
||||
|
||||
## Support
|
||||
|
||||
clip2md is free. If it saves you time: [buy me a coffee via PayPal](https://www.paypal.com/ncp/payment/54FPXDFBMP5TJ) · Gefällt dir clip2md? [Spendier mir einen Kaffee](https://www.paypal.com/ncp/payment/54FPXDFBMP5TJ).
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE). Turndown, marked, DOMPurify and Geist are under their respective MIT/OFL licenses.
|
||||
[MIT](LICENSE). Turndown, marked, DOMPurify, Mozilla Readability, Space Grotesk and Space Mono are under their respective MIT/Apache/OFL licenses.
|
||||
|
||||
|
After Width: | Height: | Size: 8.0 KiB |
@@ -0,0 +1,159 @@
|
||||
/* clip2md — page clean-up and Reddit formatting. Runs entirely in the browser.
|
||||
Exposes window.Clip2mdClean = { prepare, postprocess }. */
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var BUTTON_WORDS = /^(reply|share|report|save|saved|follow|following|subscribe|unsubscribe|join|joined|award|give award|upvote|downvote|vote|like|likes|comment|comments|copy link|copy text|embed|print|tweet|pin it|email|more|more options|show more|show less|read more|see more|continue reading|load more|view more comments|back to top|skip to content|skip to main content|accept|accept all|reject|reject all|allow all|decline|manage cookies|cookie settings|close|dismiss|sign in|log in|sign up|antworten|teilen|melden|speichern|folgen|abonnieren|beitreten|gefällt mir|kommentieren|link kopieren|drucken|mehr|mehr anzeigen|weniger anzeigen|weiterlesen|mehr laden|nach oben|zum inhalt springen|akzeptieren|alle akzeptieren|ablehnen|alle ablehnen|einstellungen|cookie-einstellungen|schließen|anmelden|registrieren)$/i;
|
||||
var JUNK_ATTR = /(^|[\s_-])(cookie|consent|gdpr|cmp|banner|newsletter|subscribe|share|sharing|social|advert|ad-slot|ads|sponsor|promo|popup|modal|overlay|sidebar|breadcrumb|related|recommend|paywall|toolbar|skip-link|comment-form|site-header|site-footer|masthead)([\s_-]|$)/i;
|
||||
var JUNK_SELECTORS = 'nav, aside, footer, form, button, input, select, textarea, dialog, iframe, noscript, template, [hidden], [aria-hidden="true"], [role="navigation"], [role="banner"], [role="contentinfo"], [role="dialog"], [role="alertdialog"], [role="complementary"], [role="search"], [role="menu"], [role="menubar"], [role="toolbar"]';
|
||||
|
||||
function textLen(el) { return el ? (el.textContent || '').replace(/\s+/g, ' ').trim().length : 0; }
|
||||
function esc(s) { return String(s).replace(/[&<>"]/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"' }[c]; }); }
|
||||
|
||||
// ---------- Generic page clean-up ----------
|
||||
function stripJunk(root) {
|
||||
var total = textLen(root) || 1, removed = 0;
|
||||
Array.prototype.slice.call(root.querySelectorAll(JUNK_SELECTORS)).forEach(function (el) {
|
||||
// Never drop the bulk of the content just because it sits in an odd wrapper.
|
||||
if (el.isConnected && textLen(el) < total * 0.5) { el.remove(); removed++; }
|
||||
});
|
||||
Array.prototype.slice.call(root.querySelectorAll('[class], [id]')).forEach(function (el) {
|
||||
if (!el.isConnected || /^(html|body|main|article)$/i.test(el.tagName)) return;
|
||||
var sig = (el.getAttribute('class') || '') + ' ' + (el.id || '');
|
||||
if (JUNK_ATTR.test(sig) && textLen(el) < total * 0.25) { el.remove(); removed++; }
|
||||
});
|
||||
Array.prototype.slice.call(root.querySelectorAll('a, span, div, li, p, strong, b')).forEach(function (el) {
|
||||
if (!el.isConnected) return;
|
||||
var t = (el.textContent || '').replace(/\s+/g, ' ').trim();
|
||||
if (t && t.length < 32 && BUTTON_WORDS.test(t) && !el.querySelector('img')) { el.remove(); removed++; }
|
||||
});
|
||||
Array.prototype.slice.call(root.querySelectorAll('img')).forEach(function (img) {
|
||||
var w = parseInt(img.getAttribute('width'), 10), h = parseInt(img.getAttribute('height'), 10);
|
||||
var alt = (img.getAttribute('alt') || '') + ' ' + (img.getAttribute('src') || '');
|
||||
if ((w && w <= 48) || (h && h <= 48) || /avatar|icon|logo|emoji|spacer|pixel|tracking/i.test(alt)) { img.remove(); removed++; }
|
||||
});
|
||||
return removed;
|
||||
}
|
||||
|
||||
function looksLikePage(doc) {
|
||||
return !!doc.querySelector('article, main, [role="main"], nav, header, footer') || doc.querySelectorAll('a').length > 25;
|
||||
}
|
||||
|
||||
// ---------- Reddit ----------
|
||||
function isReddit(doc, html) {
|
||||
if (doc.querySelector('shreddit-comment, shreddit-post, .thing.comment, .thing.link, [data-testid="comment"]')) return true;
|
||||
return /reddit\.com\/(r|user)\//i.test(html) && /\b(reply|upvote|antworten)\b/i.test(doc.body ? doc.body.textContent : '');
|
||||
}
|
||||
|
||||
function quote(lines, depth) {
|
||||
var p = new Array(depth + 1).join('> ');
|
||||
return lines.map(function (l) { return (p + l).replace(/\s+$/, ''); });
|
||||
}
|
||||
|
||||
function nearest(el, sel) { var p = el.parentElement; return p ? p.closest(sel) : null; }
|
||||
|
||||
function redditToMd(doc, toMd, labels) {
|
||||
var out = [], post, title, author, sub, body, comments = [];
|
||||
|
||||
// New Reddit (shreddit web components)
|
||||
post = doc.querySelector('shreddit-post');
|
||||
var sc = doc.querySelectorAll('shreddit-comment');
|
||||
if (post || sc.length) {
|
||||
title = post && post.getAttribute('post-title');
|
||||
author = post && post.getAttribute('author');
|
||||
sub = post && post.getAttribute('subreddit-prefixed-name');
|
||||
body = post && post.querySelector('[slot="text-body"]');
|
||||
var top = Array.prototype.filter.call(sc, function (c) { return !nearest(c, 'shreddit-comment'); });
|
||||
var renderNew = function (c, depth) {
|
||||
var a = c.getAttribute('author') || '[deleted]';
|
||||
var bodyEl = Array.prototype.filter.call(c.querySelectorAll('[slot="comment"]'), function (b) { return b.closest('shreddit-comment') === c; })[0];
|
||||
var lines = ['**u/' + a + '**' + (author && a === author ? ' (OP)' : ''), ''];
|
||||
lines = lines.concat((bodyEl ? toMd(bodyEl.innerHTML) : '').split('\n'));
|
||||
var res = quote(lines, depth);
|
||||
Array.prototype.filter.call(c.querySelectorAll('shreddit-comment'), function (k) { return nearest(k, 'shreddit-comment') === c; })
|
||||
.forEach(function (k) { res.push(quote([''], depth)[0]); res = res.concat(renderNew(k, depth + 1)); });
|
||||
return res;
|
||||
};
|
||||
top.forEach(function (c) { comments.push(renderNew(c, 1).join('\n')); });
|
||||
} else {
|
||||
// Old Reddit
|
||||
var link = doc.querySelector('.thing.link');
|
||||
var oc = doc.querySelectorAll('.thing.comment');
|
||||
if (!link && !oc.length) return null;
|
||||
if (link) {
|
||||
var ta = link.querySelector('a.title'); title = ta && ta.textContent.trim();
|
||||
var au = link.querySelector('.tagline .author'); author = au && au.textContent.trim();
|
||||
var sr = link.querySelector('.tagline .subreddit'); sub = sr && sr.textContent.trim();
|
||||
body = link.querySelector('.usertext-body .md');
|
||||
}
|
||||
var topOld = Array.prototype.filter.call(oc, function (c) { return !nearest(c, '.thing.comment'); });
|
||||
var renderOld = function (c, depth) {
|
||||
var entry = c.querySelector(':scope > .entry') || c;
|
||||
var au2 = entry.querySelector('.tagline .author'); var a = au2 ? au2.textContent.trim() : '[deleted]';
|
||||
var md = entry.querySelector('.usertext-body .md');
|
||||
var lines = ['**u/' + a + '**' + (author && a === author ? ' (OP)' : ''), ''].concat((md ? toMd(md.innerHTML) : '').split('\n'));
|
||||
var res = quote(lines, depth);
|
||||
Array.prototype.filter.call(c.querySelectorAll('.thing.comment'), function (k) { return nearest(k, '.thing.comment') === c; })
|
||||
.forEach(function (k) { res.push(quote([''], depth)[0]); res = res.concat(renderOld(k, depth + 1)); });
|
||||
return res;
|
||||
};
|
||||
topOld.forEach(function (c) { comments.push(renderOld(c, 1).join('\n')); });
|
||||
}
|
||||
|
||||
if (!title) { var h1 = doc.querySelector('h1'); title = h1 && h1.textContent.trim(); }
|
||||
if (title) out.push('# ' + title, '');
|
||||
var meta = [sub, author ? 'u/' + author : ''].filter(Boolean).join(' · ');
|
||||
if (meta) out.push('*' + meta + '*', '');
|
||||
if (body) { var b = toMd(body.innerHTML); if (b) out.push(b, ''); }
|
||||
if (comments.length) { out.push('---', '', '## ' + labels.comments + ' (' + comments.length + ')', '', comments.join('\n\n')); }
|
||||
var res = out.join('\n').replace(/\n{3,}/g, '\n\n').trim();
|
||||
return res.length > 20 ? res : null;
|
||||
}
|
||||
|
||||
var REDDIT_LINE = /^(reply|share|report|save|follow|award|upvote|downvote|vote|more replies|\d+ more repl(y|ies)|level \d+|op|edited|•|·|u\/[\w-]+ avatar|r\/[\w-]+ icon|\d+(\.\d+)?\s*[kKmM]?|\d+\s*(s|m|h|d|w|mo|y|yr|min|hr)\.?\s*ago|go to comments|sort by:?|best|top|new|controversial|old|q&a|comments|antworten|teilen|melden)$/i;
|
||||
|
||||
function postprocess(md, opts) {
|
||||
var lines = md.split('\n'), out = [], inFence = false;
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var l = lines[i], t = l.trim();
|
||||
if (/^(```|~~~)/.test(t)) { inFence = !inFence; out.push(l); continue; }
|
||||
if (inFence) { out.push(l); continue; }
|
||||
var bare = t.replace(/^[-*+]\s+/, '').replace(/^\[([^\]]*)\]\([^)]*\)$/, '$1').trim();
|
||||
if (bare && BUTTON_WORDS.test(bare)) continue;
|
||||
if (opts.reddit && bare && REDDIT_LINE.test(bare)) continue;
|
||||
if (/^\[\s*\]\([^)]*\)$/.test(t) || /^[|•·\-–—]+$/.test(t) && !/^-{3,}$/.test(t)) continue;
|
||||
out.push(l.replace(/\[\s*\]\([^)]*\)/g, ''));
|
||||
}
|
||||
return out.join('\n').replace(/\n{3,}/g, '\n\n').trim();
|
||||
}
|
||||
|
||||
/* prepare(html, opts) → { md?, html?, kind, title? }
|
||||
opts: { cleanup, reddit, toMd(htmlString)→md, labels:{comments} } */
|
||||
function prepare(html, opts) {
|
||||
var doc;
|
||||
try { doc = new DOMParser().parseFromString(html, 'text/html'); } catch (e) { return { html: html, kind: 'plain' }; }
|
||||
if (!doc || !doc.body) return { html: html, kind: 'plain' };
|
||||
|
||||
var reddit = isReddit(doc, html);
|
||||
if (opts.reddit && reddit) {
|
||||
try { var rmd = redditToMd(doc, opts.toMd, opts.labels); if (rmd) return { md: rmd, kind: 'reddit', reddit: true }; } catch (e) {}
|
||||
}
|
||||
if (!opts.cleanup) return { html: html, kind: 'plain', reddit: reddit };
|
||||
|
||||
var before = textLen(doc.body);
|
||||
if (before > 1200 && typeof window.Readability === 'function' && looksLikePage(doc) && !reddit) {
|
||||
try {
|
||||
var art = new window.Readability(doc.cloneNode(true), { charThreshold: 250, keepClasses: false }).parse();
|
||||
if (art && art.content && (art.textContent || '').trim().length > before * 0.3) {
|
||||
var content = art.content;
|
||||
if (art.title && content.indexOf(art.title) < 0) content = '<h1>' + esc(art.title) + '</h1>' + content;
|
||||
return { html: content, kind: 'article', title: art.title, reddit: reddit };
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
var n = stripJunk(doc.body);
|
||||
return { html: doc.body.innerHTML, kind: n ? 'cleaned' : 'plain', reddit: reddit };
|
||||
}
|
||||
|
||||
window.Clip2mdClean = { prepare: prepare, postprocess: postprocess };
|
||||
})();
|
||||
@@ -2,29 +2,33 @@
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta name="robots" content="noindex" />
|
||||
<meta name="theme-color" content="#faf7f2" />
|
||||
<meta name="theme-color" content="#EAEAE3" />
|
||||
<title>Datenschutzerklärung — clip2md</title>
|
||||
<link rel="icon" href="icon.svg" type="image/svg+xml" />
|
||||
<link rel="stylesheet" href="legal.css" />
|
||||
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
|
||||
<link rel="stylesheet" href="/legal.css" />
|
||||
<link rel="alternate" hreflang="de" href="https://clip2md.heidrich-digital.de/datenschutz.html" />
|
||||
<link rel="alternate" hreflang="en" href="https://clip2md.heidrich-digital.de/privacy.html" />
|
||||
<script>
|
||||
try { var t = JSON.parse(localStorage.getItem('clip2md:theme')); if (t === 'dark') document.documentElement.setAttribute('data-theme','dark'); } catch (e) {}
|
||||
try { var th = JSON.parse(localStorage.getItem('clip2md:theme')); if (th === 'dark' || (th === null && matchMedia('(prefers-color-scheme: dark)').matches)) document.documentElement.setAttribute('data-theme','dark'); } catch (e) {}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="legal-head">
|
||||
<div class="inner">
|
||||
<a class="back" href="/"><span class="wordmark">clip<b>2</b>md</span></a>
|
||||
<header class="topbar">
|
||||
<a class="brand" href="/"><svg viewBox="0 0 24 24" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="4.5" width="14" height="17" rx="1.5"/><path d="M12 9.5v7.5M8.8 13.8 12 17l3.2-3.2"/></g><rect x="8.6" y="2.4" width="6.8" height="3.8" rx="1" fill="currentColor"/></svg><span>clip<span class="two">2</span>md</span></a>
|
||||
<nav>
|
||||
<a href="impressum.html">Impressum</a>
|
||||
<a href="datenschutz.html" aria-current="page">Datenschutz</a>
|
||||
<a href="/impressum.html">Impressum</a>
|
||||
<a href="/datenschutz.html" aria-current="page">Datenschutz</a>
|
||||
<a class="lang" href="/privacy.html" hreflang="en" lang="en" title="English">EN</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="legal">
|
||||
<span class="mono-label">Rechtliches</span>
|
||||
<h1>Datenschutzerklärung</h1>
|
||||
<div class="card">
|
||||
|
||||
|
||||
<p class="intro">
|
||||
Der Text, den Sie auf dieser Seite einfügen, wird ausschließlich in Ihrem Browser
|
||||
@@ -57,6 +61,19 @@
|
||||
Zwischenablage erfolgen ebenfalls lokal über die entsprechenden Browser-Schnittstellen.
|
||||
Auch dabei werden keine Daten an uns übermittelt.
|
||||
</p>
|
||||
<p>
|
||||
Über die Schaltfläche „Einfügen" liest die Seite die Zwischenablage Ihres Geräts aus. Das
|
||||
geschieht nur, wenn Sie die Schaltfläche betätigen, und je nach Browser erst nach Ihrer
|
||||
Zustimmung. Der Inhalt wird wie beim Einfügen per Tastatur ausschließlich lokal umgewandelt.
|
||||
Auf Smartphones übergibt „Speichern" die Datei an das Teilen-Menü Ihres Betriebssystems; wohin
|
||||
Sie sie von dort weitergeben, entscheiden Sie selbst.
|
||||
</p>
|
||||
<p>
|
||||
Das Aufräumen eingefügter Webseiten und die Aufbereitung von Reddit-Threads laufen ebenfalls
|
||||
vollständig in Ihrem Browser. Der optionale Knopf „In Obsidian öffnen" legt den Text in die
|
||||
Zwischenablage und übergibt ihn an die Obsidian-App auf Ihrem Gerät; an uns oder Dritte wird
|
||||
dabei nichts übertragen.
|
||||
</p>
|
||||
|
||||
<h2>3. Lokale Speicherung Ihrer Einstellungen</h2>
|
||||
<p>
|
||||
@@ -67,6 +84,13 @@
|
||||
eingefügten Inhalte. Es handelt sich nicht um Cookies. Sie können die Werte jederzeit über
|
||||
die Einstellungen Ihres Browsers löschen.
|
||||
</p>
|
||||
<p>
|
||||
Nur wenn Sie in den Einstellungen „Letzte 10 Clips behalten" einschalten, speichert die Seite
|
||||
die zuletzt bearbeiteten Texte in der lokalen Datenbank Ihres Browsers (<span class="mono">IndexedDB</span>).
|
||||
Die Funktion ist standardmäßig ausgeschaltet. Die Einträge verlassen Ihr Gerät nicht, sind nur in
|
||||
diesem Browser sichtbar und lassen sich im Verlauf einzeln oder vollständig löschen; beim
|
||||
Ausschalten werden Sie gefragt, ob der Verlauf gelöscht werden soll.
|
||||
</p>
|
||||
<p>
|
||||
Rechtsgrundlage für diese ausschließlich lokale Speicherung ist Ihr Wunsch nach einer
|
||||
funktionsfähigen Bedienoberfläche; ein Zugriff unsererseits findet nicht statt.
|
||||
@@ -117,7 +141,7 @@
|
||||
Einwilligungsabfrage ist deshalb nicht erforderlich.
|
||||
</p>
|
||||
<p>
|
||||
Eine Ausnahme betrifft die optionale Vorschau: Enthält der von Ihnen eingefuegte Text
|
||||
Eine Ausnahme betrifft die optionale Vorschau: Enthält der von Ihnen eingefügte Text
|
||||
Bilder, die auf fremde Server verweisen, lädt Ihr Browser diese Bilder beim Anzeigen der
|
||||
Vorschau von dort. Dabei erfährt der jeweilige fremde Server Ihre IP-Adresse. Übertragen
|
||||
wird dabei nichts von Ihrem Text; die Herkunft wird durch die Einstellung
|
||||
@@ -125,7 +149,30 @@
|
||||
vermeiden möchten, lassen Sie die Vorschau ausgeschaltet.
|
||||
</p>
|
||||
|
||||
<h2>8. Ihre Rechte</h2>
|
||||
<h2>8. Unterstützung über PayPal</h2>
|
||||
<p>
|
||||
Auf der Seite finden Sie einen Link „Spenden" bzw. „Spendier mir einen Kaffee". Es handelt sich
|
||||
um einen einfachen Link; beim Aufruf von clip2md werden keine Inhalte, Skripte oder Cookies von
|
||||
PayPal geladen und keine Daten an PayPal übertragen. Erst wenn Sie den Link anklicken, verlassen
|
||||
Sie diese Seite und gelangen zu einer Zahlungsseite von PayPal.
|
||||
</p>
|
||||
<p>
|
||||
Anbieter ist die PayPal (Europe) S.à r.l. et Cie, S.C.A., 22–24 Boulevard Royal, L-2449
|
||||
Luxemburg. Für die Verarbeitung auf den Seiten von PayPal ist PayPal selbst verantwortlich; es
|
||||
gilt dessen Datenschutzerklärung:
|
||||
<a href="https://www.paypal.com/de/legalhub/privacy-full" rel="noopener nofollow">paypal.com/de/legalhub/privacy-full</a>.
|
||||
</p>
|
||||
<p>
|
||||
Wenn Sie einen Betrag zahlen, erhalten wir von PayPal die zur Abwicklung nötigen Angaben,
|
||||
insbesondere Ihren Namen, Ihre E-Mail-Adresse, den Betrag, Datum und Uhrzeit sowie die
|
||||
Transaktionsnummer. Rechtsgrundlage ist Art. 6 Abs. 1 lit. b DSGVO (Abwicklung der Zahlung)
|
||||
sowie Art. 6 Abs. 1 lit. c DSGVO in Verbindung mit den steuer- und handelsrechtlichen
|
||||
Aufbewahrungspflichten (in der Regel acht bis zehn Jahre). Eine weitere Nutzung, etwa für
|
||||
Werbung, findet nicht statt. Die Zahlung ist freiwillig; eine Gegenleistung ist damit nicht
|
||||
verbunden.
|
||||
</p>
|
||||
|
||||
<h2>9. Ihre Rechte</h2>
|
||||
<p>
|
||||
Sie haben das Recht auf Auskunft (Art. 15 DSGVO), Berichtigung (Art. 16), Löschung
|
||||
(Art. 17), Einschränkung der Verarbeitung (Art. 18), Datenübertragbarkeit (Art. 20) sowie
|
||||
@@ -133,17 +180,20 @@
|
||||
(Art. 21). Wenden Sie sich dafür an die oben genannte Adresse.
|
||||
</p>
|
||||
|
||||
<h2>9. Beschwerderecht</h2>
|
||||
<h2>10. Beschwerderecht</h2>
|
||||
<p>
|
||||
Sie können sich bei einer Datenschutz-Aufsichtsbehörde beschweren. Zuständig ist die
|
||||
Landesbeauftragte für den Datenschutz Niedersachsen, Prinzenstraße 5, 30159 Hannover.
|
||||
</p>
|
||||
|
||||
<h2>10. Stand</h2>
|
||||
<h2>11. Stand</h2>
|
||||
<p>Diese Datenschutzerklärung hat den Stand September 2026.</p>
|
||||
|
||||
</div>
|
||||
<div class="legal-foot">
|
||||
<a href="/">Zurück zum Werkzeug</a> · <a href="impressum.html">Impressum</a>
|
||||
<a href="/">← Zurück zu clip2md</a>
|
||||
<a href="/impressum.html">Impressum</a>
|
||||
<a href="https://www.paypal.com/ncp/payment/54FPXDFBMP5TJ" target="_blank" rel="noopener nofollow">Spenden</a>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# iPhone shortcut for clip2md
|
||||
|
||||
iOS does not let web apps into the share sheet. This Shortcut copies the current Safari page and opens clip2md.
|
||||
|
||||
1. Open **Shortcuts**, tap **+**, name it **clip2md**.
|
||||
2. Tap **ⓘ**, enable **Show in Share Sheet**, allow **Safari web pages**, **Rich text**, **Text**.
|
||||
3. Add **Get Details of Safari Web Page** → **Page Contents** (input: Shortcut Input).
|
||||
4. Add **Copy to Clipboard**.
|
||||
5. Add **Open URLs** → `https://clip2md.heidrich-digital.de/?from=ios` (use your own domain when self-hosting).
|
||||
|
||||
In Safari: Share → **clip2md** → tap **Paste**. iOS asks once whether clip2md may paste.
|
||||
|
||||
For a selection only, no Shortcut is needed: copy it and use the Paste button.
|
||||
|
||||
---
|
||||
|
||||
## Deutsch
|
||||
|
||||
1. App **Kurzbefehle** öffnen, **+** tippen, Name **clip2md**.
|
||||
2. **ⓘ** tippen, **Im Share-Sheet anzeigen** einschalten, **Safari-Webseiten**, **Rich Text**, **Text** zulassen.
|
||||
3. Aktion **Details von Safari-Webseite abrufen** → **Seiteninhalt**.
|
||||
4. Aktion **In Zwischenablage kopieren**.
|
||||
5. Aktion **URLs öffnen** → `https://clip2md.heidrich-digital.de/?from=ios`
|
||||
|
||||
In Safari: Teilen → **clip2md** → **Einfügen** tippen.
|
||||
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 227 KiB |
|
After Width: | Height: | Size: 193 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -1,7 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" role="img" aria-label="clip2md">
|
||||
<g fill="none" stroke="currentColor" stroke-width="44" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M118 352V166l86 94 86-94v186"/>
|
||||
<path d="M384 166v140"/>
|
||||
<path d="M338 268l46 52 46-52"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" role="img" aria-label="clip2md" xmlns:c2pa="http://c2pa.org/manifest"><metadata><c2pa:manifest>AAAWgmp1bWIAAAAeanVtZGMycGEAEQAQgAAAqgA4m3EDYzJwYQAAABZcanVtYgAAAEdqdW1kYzJtYQARABCAAACqADibcQN1cm46YzJwYTo5NjkzMWJiNy1jYTg3LTRjNWEtOGE4Ni0yNjQxYzJjODg3Y2IAAAADl2p1bWIAAAApanVtZGMyYXMAEQAQgAAAqgA4m3EDYzJwYS5hc3NlcnRpb25zAAAAALxqdW1iAAAARGp1bWRjYm9yABEAEIAAAKoAOJtxE2MycGEuaW5ncmVkaWVudC52MwAAAAAYYzJzaEd1ybodD3L6bmfkOq9bA40AAABwY2JvcqNpZGM6Zm9ybWF0bWltYWdlL3N2Zyt4bWxqaW5zdGFuY2VJRHgseG1wOmlpZDpiYmUwY2ZjNi00NGNhLTRkMWItYjRiNi04MmRjY2U1ZWQyYzJscmVsYXRpb25zaGlwaHBhcmVudE9mAAAB4mp1bWIAAABBanVtZGNib3IAEQAQgAAAqgA4m3ETYzJwYS5hY3Rpb25zLnYyAAAAABhjMnNoD8B6kTZGbHgLyzg08rdPaAAAAZljYm9yomdhY3Rpb25zgqJmYWN0aW9ua2MycGEub3BlbmVkanBhcmFtZXRlcnOha2luZ3JlZGllbnRzgaJjdXJseC1zZWxmI2p1bWJmPWMycGEuYXNzZXJ0aW9ucy9jMnBhLmluZ3JlZGllbnQudjNkaGFzaFggefl5EZp24D6m6pO00dQE2grxyV6xfE4gO+musKFljSakZmFjdGlvbngdY29tLmFudGhyb3BpYy5jbGF1ZGUucHJvdmlkZWRqcGFyYW1ldGVyc6F4H2NvbS5hbnRocm9waWMub3JpZ2luLWNvbmZpZGVuY2VndW5rbm93bmtkZXNjcmlwdGlvbnhmQ2xhdWRlIHByb3ZpZGVkIHRoaXMgZmlsZSBhdCB0aGUgcmVxdWVzdCBvZiBhIHVzZXIgYW5kIG1heSBoYXZlIGNyZWF0ZWQgb3IgbW9kaWZpZWQgdGhlIGZpbGUgY29udGVudHMubXNvZnR3YXJlQWdlbnShZG5hbWVmQ2xhdWRlcmFsbEFjdGlvbnNJbmNsdWRlZPUAAADIanVtYgAAAEBqdW1kY2JvcgARABCAAACqADibcRNjMnBhLmhhc2guZGF0YQAAAAAYYzJzaJenzbrkdVtDScW6NB1RE6oAAACAY2JvcqVjYWxnZnNoYTI1NmNwYWRNAAAAAAAAAAAAAAAAAGRoYXNoWCD6NBeqJ7Ht0mHPVl42j6FWIZFbAbXQRXPffHTHE/OE8GRuYW1lbmp1bWJmIG1hbmlmZXN0amV4Y2x1c2lvbnOBomVzdGFydBi2Zmxlbmd0aBkeBAAAAj5qdW1iAAAAJ2p1bWRjMmNsABEAEIAAAKoAOJtxA2MycGEuY2xhaW0udjIAAAACD2Nib3KlY2FsZ2ZzaGEyNTZpc2lnbmF0dXJleE1zZWxmI2p1bWJmPS9jMnBhL3VybjpjMnBhOjk2OTMxYmI3LWNhODctNGM1YS04YTg2LTI2NDFjMmM4ODdjYi9jMnBhLnNpZ25hdHVyZWppbnN0YW5jZUlEeCx4bXA6aWlkOjgyMDQyNDg5LWEwZmQtNDFkMS1iNzJiLWNiN2I3ODQ5ZGM3ZHJjcmVhdGVkX2Fzc2VydGlvbnODomN1cmx4LXNlbGYjanVtYmY9YzJwYS5hc3NlcnRpb25zL2MycGEuaW5ncmVkaWVudC52M2RoYXNoWCB5+XkRmnbgPqbqk7TR1ATaCvHJXrF8TiA76a6woWWNJqJjdXJseCpzZWxmI2p1bWJmPWMycGEuYXNzZXJ0aW9ucy9jMnBhLmFjdGlvbnMudjJkaGFzaFggaNNTgOw83IrurlIppyF4vuc6nRxPx9W196cCasAjeCSiY3VybHgpc2VsZiNqdW1iZj1jMnBhLmFzc2VydGlvbnMvYzJwYS5oYXNoLmRhdGFkaGFzaFggjA55f0u5dgptrQQn9+ArLOZjPV71ZLqDOc0AfCcWtx50Y2xhaW1fZ2VuZXJhdG9yX2luZm+jZG5hbWVvQW50aHJvcGljIEZpbGVzZ3ZlcnNpb25lMS4wLjBrc3BlY1ZlcnNpb25lMi40LjAAABA4anVtYgAAAChqdW1kYzJjcwARABCAAACqADibcQNjMnBhLnNpZ25hdHVyZQAAABAIY2JvctKEWQISogEmGCFZAgowggIGMIIBjaADAgECAhRA5aAK7sI50L64g/oGQgU9Z1UTADAKBggqhkjOPQQDAzBJMRcwFQYDVQQKEw5BbnRocm9waWMsIFBCQzEuMCwGA1UEAxMlQW50aHJvcGljIENvbnRlbnQgQ3JlZGVudGlhbHMgUm9vdCBDQTAeFw0yNjA4MDcxODQzNTZaFw0yODA4MDYxOTQzNTZaMEQxFzAVBgNVBAoTDkFudGhyb3BpYywgUEJDMSkwJwYDVQQDEyBBbnRocm9waWMgQ2xhdWRlIENvbnRlbnQgU2lnbmluZzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJh6CmvLUBgFFNU0vUKlOVtE6djd17L5SuwX0LemFisBM3dkd/3cyjxFA3Qo5S46fX0/ihY0VZ7mfb9KF703t5OjWDBWMA4GA1UdDwEB/wQEAwIHgDAVBgNVHSUEDjAMBgorBgEEAYPoXgIBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUzlHiBIFOZFsj+OPEz5o+nMHXXMIwCgYIKoZIzj0EAwMDZwAwZAIwMXMdFJ4BetLLVY7ORuE9noqbbAZOZn/aArXyTwFAZfKrPzxF2vPoJNf1+UCdg1XGAjBwX1zd9WGqYkqmL5SFqw1QySjr1zJfpJM9+1rdDwSPLMOPOjKuiXjoU/pUUeG9RwmhY3BhZFkNngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALine truncated
|
||||
<g fill="none" stroke="#000" stroke-width="30" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="146" y="124" width="220" height="284" rx="22"/>
|
||||
<path d="M256 214v124M204 288l52 52 52-52"/>
|
||||
</g>
|
||||
<rect x="198" y="92" width="116" height="64" rx="16" fill="#000"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 8.0 KiB |
@@ -1,8 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" role="img" aria-label="clip2md">
|
||||
<rect width="512" height="512" rx="112" fill="#c14a2b"/>
|
||||
<g fill="none" stroke="#fdf6f1" stroke-width="44" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M118 352V166l86 94 86-94v186"/>
|
||||
<path d="M384 166v140"/>
|
||||
<path d="M338 268l46 52 46-52"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" role="img" aria-label="clip2md" xmlns:c2pa="http://c2pa.org/manifest"><metadata><c2pa:manifest>AAAWgmp1bWIAAAAeanVtZGMycGEAEQAQgAAAqgA4m3EDYzJwYQAAABZcanVtYgAAAEdqdW1kYzJtYQARABCAAACqADibcQN1cm46YzJwYTo3NjZmY2E1NS0xNWZhLTRjMjktOWMwMi0yZWQ2YTRlMTE5N2IAAAADl2p1bWIAAAApanVtZGMyYXMAEQAQgAAAqgA4m3EDYzJwYS5hc3NlcnRpb25zAAAAALxqdW1iAAAARGp1bWRjYm9yABEAEIAAAKoAOJtxE2MycGEuaW5ncmVkaWVudC52MwAAAAAYYzJzaIxdjdUDEhE5YIY3eHT5SCoAAABwY2JvcqNpZGM6Zm9ybWF0bWltYWdlL3N2Zyt4bWxqaW5zdGFuY2VJRHgseG1wOmlpZDo1NGNhN2NlYy0wYWE0LTQ5YzMtOGI5Ny00YzUxNDdlMmJjNjJscmVsYXRpb25zaGlwaHBhcmVudE9mAAAB4mp1bWIAAABBanVtZGNib3IAEQAQgAAAqgA4m3ETYzJwYS5hY3Rpb25zLnYyAAAAABhjMnNo9xq2bExTiscFiT0oWzKpFgAAAZljYm9yomdhY3Rpb25zgqJmYWN0aW9ua2MycGEub3BlbmVkanBhcmFtZXRlcnOha2luZ3JlZGllbnRzgaJjdXJseC1zZWxmI2p1bWJmPWMycGEuYXNzZXJ0aW9ucy9jMnBhLmluZ3JlZGllbnQudjNkaGFzaFggsVAEfTnGrUgMMt4oWhSoE9/0KzYLZORmwRH2LXb/+VKkZmFjdGlvbngdY29tLmFudGhyb3BpYy5jbGF1ZGUucHJvdmlkZWRqcGFyYW1ldGVyc6F4H2NvbS5hbnRocm9waWMub3JpZ2luLWNvbmZpZGVuY2VndW5rbm93bmtkZXNjcmlwdGlvbnhmQ2xhdWRlIHByb3ZpZGVkIHRoaXMgZmlsZSBhdCB0aGUgcmVxdWVzdCBvZiBhIHVzZXIgYW5kIG1heSBoYXZlIGNyZWF0ZWQgb3IgbW9kaWZpZWQgdGhlIGZpbGUgY29udGVudHMubXNvZnR3YXJlQWdlbnShZG5hbWVmQ2xhdWRlcmFsbEFjdGlvbnNJbmNsdWRlZPUAAADIanVtYgAAAEBqdW1kY2JvcgARABCAAACqADibcRNjMnBhLmhhc2guZGF0YQAAAAAYYzJzaIs0FFpWK28j1nfpDaf+6ewAAACAY2JvcqVjYWxnZnNoYTI1NmNwYWRNAAAAAAAAAAAAAAAAAGRoYXNoWCC9PsI0VhKdqWl+KMmXDr0D88GymzjDSxOZnAykNujo+mRuYW1lbmp1bWJmIG1hbmlmZXN0amV4Y2x1c2lvbnOBomVzdGFydBi2Zmxlbmd0aBkeBAAAAj5qdW1iAAAAJ2p1bWRjMmNsABEAEIAAAKoAOJtxA2MycGEuY2xhaW0udjIAAAACD2Nib3KlY2FsZ2ZzaGEyNTZpc2lnbmF0dXJleE1zZWxmI2p1bWJmPS9jMnBhL3VybjpjMnBhOjc2NmZjYTU1LTE1ZmEtNGMyOS05YzAyLTJlZDZhNGUxMTk3Yi9jMnBhLnNpZ25hdHVyZWppbnN0YW5jZUlEeCx4bXA6aWlkOjMyYTlhZWM1LWI3NjgtNDM1Zi1hYmQwLWI3YWI0ZjM1ZDliMXJjcmVhdGVkX2Fzc2VydGlvbnODomN1cmx4LXNlbGYjanVtYmY9YzJwYS5hc3NlcnRpb25zL2MycGEuaW5ncmVkaWVudC52M2RoYXNoWCCxUAR9OcatSAwy3ihaFKgT3/QrNgtk5GbBEfYtdv/5UqJjdXJseCpzZWxmI2p1bWJmPWMycGEuYXNzZXJ0aW9ucy9jMnBhLmFjdGlvbnMudjJkaGFzaFggC2jWKBQAXG2Nl28/mppC+AVk5pvIfJUH9IZaGTTCDMaiY3VybHgpc2VsZiNqdW1iZj1jMnBhLmFzc2VydGlvbnMvYzJwYS5oYXNoLmRhdGFkaGFzaFgglSQJIGyHAJjeNhWxWBLoo/KtOZ1TONf6O1V9ENt4vf10Y2xhaW1fZ2VuZXJhdG9yX2luZm+jZG5hbWVvQW50aHJvcGljIEZpbGVzZ3ZlcnNpb25lMS4wLjBrc3BlY1ZlcnNpb25lMi40LjAAABA4anVtYgAAAChqdW1kYzJjcwARABCAAACqADibcQNjMnBhLnNpZ25hdHVyZQAAABAIY2JvctKEWQISogEmGCFZAgowggIGMIIBjaADAgECAhRA5aAK7sI50L64g/oGQgU9Z1UTADAKBggqhkjOPQQDAzBJMRcwFQYDVQQKEw5BbnRocm9waWMsIFBCQzEuMCwGA1UEAxMlQW50aHJvcGljIENvbnRlbnQgQ3JlZGVudGlhbHMgUm9vdCBDQTAeFw0yNjA4MDcxODQzNTZaFw0yODA4MDYxOTQzNTZaMEQxFzAVBgNVBAoTDkFudGhyb3BpYywgUEJDMSkwJwYDVQQDEyBBbnRocm9waWMgQ2xhdWRlIENvbnRlbnQgU2lnbmluZzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJh6CmvLUBgFFNU0vUKlOVtE6djd17L5SuwX0LemFisBM3dkd/3cyjxFA3Qo5S46fX0/ihY0VZ7mfb9KF703t5OjWDBWMA4GA1UdDwEB/wQEAwIHgDAVBgNVHSUEDjAMBgorBgEEAYPoXgIBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUzlHiBIFOZFsj+OPEz5o+nMHXXMIwCgYIKoZIzj0EAwMDZwAwZAIwMXMdFJ4BetLLVY7ORuE9noqbbAZOZn/aArXyTwFAZfKrPzxF2vPoJNf1+UCdg1XGAjBwX1zd9WGqYkqmL5SFqw1QySjr1zJfpJM9+1rdDwSPLMOPOjKuiXjoU/pUUeG9RwmhY3BhZFkNngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALine truncated
|
||||
<rect width="512" height="512" rx="104" fill="#1B3BE0"/>
|
||||
<g fill="none" stroke="#FBFBF7" stroke-width="30" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="146" y="124" width="220" height="284" rx="22"/>
|
||||
<path d="M256 214v124M204 288l52 52 52-52"/>
|
||||
</g>
|
||||
<rect x="198" y="92" width="116" height="64" rx="16" fill="#FBFBF7"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 404 B After Width: | Height: | Size: 8.1 KiB |
@@ -2,29 +2,33 @@
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta name="robots" content="noindex" />
|
||||
<meta name="theme-color" content="#faf7f2" />
|
||||
<meta name="theme-color" content="#EAEAE3" />
|
||||
<title>Impressum — clip2md</title>
|
||||
<link rel="icon" href="icon.svg" type="image/svg+xml" />
|
||||
<link rel="stylesheet" href="legal.css" />
|
||||
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
|
||||
<link rel="stylesheet" href="/legal.css" />
|
||||
<link rel="alternate" hreflang="de" href="https://clip2md.heidrich-digital.de/impressum.html" />
|
||||
<link rel="alternate" hreflang="en" href="https://clip2md.heidrich-digital.de/imprint.html" />
|
||||
<script>
|
||||
try { var t = JSON.parse(localStorage.getItem('clip2md:theme')); if (t === 'dark') document.documentElement.setAttribute('data-theme','dark'); } catch (e) {}
|
||||
try { var th = JSON.parse(localStorage.getItem('clip2md:theme')); if (th === 'dark' || (th === null && matchMedia('(prefers-color-scheme: dark)').matches)) document.documentElement.setAttribute('data-theme','dark'); } catch (e) {}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="legal-head">
|
||||
<div class="inner">
|
||||
<a class="back" href="/"><span class="wordmark">clip<b>2</b>md</span></a>
|
||||
<header class="topbar">
|
||||
<a class="brand" href="/"><svg viewBox="0 0 24 24" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="4.5" width="14" height="17" rx="1.5"/><path d="M12 9.5v7.5M8.8 13.8 12 17l3.2-3.2"/></g><rect x="8.6" y="2.4" width="6.8" height="3.8" rx="1" fill="currentColor"/></svg><span>clip<span class="two">2</span>md</span></a>
|
||||
<nav>
|
||||
<a href="impressum.html" aria-current="page">Impressum</a>
|
||||
<a href="datenschutz.html">Datenschutz</a>
|
||||
<a href="/impressum.html" aria-current="page">Impressum</a>
|
||||
<a href="/datenschutz.html">Datenschutz</a>
|
||||
<a class="lang" href="/imprint.html" hreflang="en" lang="en" title="English">EN</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="legal">
|
||||
<span class="mono-label">Rechtliches</span>
|
||||
<h1>Impressum</h1>
|
||||
<div class="card">
|
||||
|
||||
|
||||
<h2>Angaben gemäß § 5 DDG</h2>
|
||||
<table class="legal-table">
|
||||
@@ -65,12 +69,15 @@
|
||||
<h2>Urheberrecht und Lizenz</h2>
|
||||
<p>
|
||||
Der Quellcode von clip2md steht unter der MIT-Lizenz. Die eingebundenen Bibliotheken
|
||||
(Turndown, Marked, DOMPurify) und die Schriftfamilie Geist stehen unter ihren jeweiligen
|
||||
freien Lizenzen. Texte und Gestaltung dieser Seite unterliegen dem deutschen Urheberrecht.
|
||||
(Turndown, Marked, DOMPurify, Mozilla Readability; MIT- bzw. Apache-Lizenz) und die Schriftfamilien Space Grotesk und Space Mono stehen unter ihren jeweiligen
|
||||
freien Lizenzen (Schriften: SIL Open Font License). Texte und Gestaltung dieser Seite unterliegen dem deutschen Urheberrecht.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div class="legal-foot">
|
||||
<a href="/">Zurück zum Werkzeug</a> · <a href="datenschutz.html">Datenschutzerklärung</a>
|
||||
<a href="/">← Zurück zu clip2md</a>
|
||||
<a href="/datenschutz.html">Datenschutzerklärung</a>
|
||||
<a href="https://www.paypal.com/ncp/payment/54FPXDFBMP5TJ" target="_blank" rel="noopener nofollow">Spenden</a>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta name="robots" content="noindex" />
|
||||
<meta name="theme-color" content="#EAEAE3" />
|
||||
<title>Legal notice — clip2md</title>
|
||||
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
|
||||
<link rel="stylesheet" href="/legal.css" />
|
||||
<link rel="alternate" hreflang="de" href="https://clip2md.heidrich-digital.de/impressum.html" />
|
||||
<link rel="alternate" hreflang="en" href="https://clip2md.heidrich-digital.de/imprint.html" />
|
||||
<script>
|
||||
try { var th = JSON.parse(localStorage.getItem('clip2md:theme')); if (th === 'dark' || (th === null && matchMedia('(prefers-color-scheme: dark)').matches)) document.documentElement.setAttribute('data-theme','dark'); } catch (e) {}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<a class="brand" href="/"><svg viewBox="0 0 24 24" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="4.5" width="14" height="17" rx="1.5"/><path d="M12 9.5v7.5M8.8 13.8 12 17l3.2-3.2"/></g><rect x="8.6" y="2.4" width="6.8" height="3.8" rx="1" fill="currentColor"/></svg><span>clip<span class="two">2</span>md</span></a>
|
||||
<nav>
|
||||
<a href="/imprint.html" aria-current="page">Legal notice</a>
|
||||
<a href="/privacy.html">Privacy</a>
|
||||
<a class="lang" href="/impressum.html" hreflang="de" lang="de" title="Deutsch">DE</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="legal">
|
||||
<span class="mono-label">Legal</span>
|
||||
<h1>Legal notice</h1>
|
||||
<div class="card">
|
||||
<p class="intro">This is a translation provided for convenience. The German version (<a href="/impressum.html">Impressum</a>) is legally binding.</p>
|
||||
|
||||
<h2>Information pursuant to § 5 DDG (German Digital Services Act)</h2>
|
||||
<table class="legal-table">
|
||||
<tbody>
|
||||
<tr><th>Provider</th><td>Till Heidrich – Content Creation</td></tr>
|
||||
<tr><th>Owner</th><td>Till Heidrich</td></tr>
|
||||
<tr><th>Address</th><td>Rotdornweg 17<br />21255 Tostedt<br />Germany</td></tr>
|
||||
<tr><th>Email</th><td><a href="mailto:info@tillheidrich.de">info@tillheidrich.de</a></td></tr>
|
||||
<tr><th>Phone</th><td><a href="tel:+4915773953819">+49 1577 3953819</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>VAT</h2>
|
||||
<p>
|
||||
As a small business within the meaning of § 19 (1) of the German VAT Act (UStG), no VAT is
|
||||
charged and therefore no VAT identification number is held.
|
||||
</p>
|
||||
|
||||
<h2>Responsible for content pursuant to § 18 (2) MStV</h2>
|
||||
<p>Till Heidrich, address as above.</p>
|
||||
|
||||
<h2>Dispute resolution</h2>
|
||||
<p>
|
||||
The European Commission provides a platform for online dispute resolution:
|
||||
<a href="https://ec.europa.eu/consumers/odr/" rel="nofollow noopener">ec.europa.eu/consumers/odr</a>.
|
||||
We are neither obliged nor willing to take part in dispute resolution proceedings before a
|
||||
consumer arbitration board.
|
||||
</p>
|
||||
|
||||
<h2>Liability for links</h2>
|
||||
<p>
|
||||
This site contains links to external third-party websites whose content we cannot influence.
|
||||
The respective provider is always responsible for that content. No legal violations were
|
||||
apparent at the time of linking. Should we become aware of any, we will remove such links
|
||||
immediately.
|
||||
</p>
|
||||
|
||||
<h2>Copyright and licence</h2>
|
||||
<p>
|
||||
The source code of clip2md is released under the MIT licence. The bundled libraries
|
||||
(Turndown, Marked, DOMPurify, Mozilla Readability; MIT or Apache licence) and the typefaces
|
||||
Space Grotesk and Space Mono (SIL Open Font License) are subject to their respective free
|
||||
licences. Texts and design of this site are protected by German copyright law.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div class="legal-foot">
|
||||
<a href="/">← Back to clip2md</a>
|
||||
<a href="/privacy.html">Privacy policy</a>
|
||||
<a href="https://www.paypal.com/ncp/payment/54FPXDFBMP5TJ" target="_blank" rel="noopener nofollow">Donate</a>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,66 +1,73 @@
|
||||
@font-face { font-family: "Geist"; src: url("vendor/fonts/Geist-Variable.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; }
|
||||
@font-face { font-family: "Geist Mono"; src: url("vendor/fonts/GeistMono-Variable.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; }
|
||||
@font-face { font-family: "Space Grotesk"; src: url("/vendor/fonts/space-grotesk-latin-400-normal.woff2") format("woff2"); font-weight: 400; font-display: swap; }
|
||||
@font-face { font-family: "Space Grotesk"; src: url("/vendor/fonts/space-grotesk-latin-700-normal.woff2") format("woff2"); font-weight: 700; font-display: swap; }
|
||||
@font-face { font-family: "Space Mono"; src: url("/vendor/fonts/space-mono-latin-400-normal.woff2") format("woff2"); font-weight: 400; font-display: swap; }
|
||||
|
||||
:root {
|
||||
--paper: oklch(98.4% 0.006 80);
|
||||
--surface: oklch(99.6% 0.003 80);
|
||||
--line: oklch(89% 0.008 75);
|
||||
--ink: oklch(26% 0.02 55);
|
||||
--ink-2: oklch(44% 0.018 55);
|
||||
--ink-3: oklch(58% 0.014 55);
|
||||
--accent: oklch(56% 0.168 34);
|
||||
--accent-hi: oklch(52% 0.18 33);
|
||||
--r: 10px;
|
||||
--font: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
||||
--mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
||||
--paper: oklch(92.8% 0.005 95); --card: oklch(98.4% 0.004 95); --tint: oklch(95.6% 0.005 95);
|
||||
--line: oklch(86.8% 0.007 95); --mark: oklch(70% 0.006 95);
|
||||
--ink: oklch(21% 0.01 95); --ink-soft: oklch(49% 0.008 95);
|
||||
--accent: oklch(45% 0.23 267); --accent-2: oklch(38% 0.21 267); --accent-bg: oklch(45% 0.23 267 / 0.07); --on-accent: #fff;
|
||||
--radius: 4px; --shadow: 0 1px 2px oklch(21% 0.01 95 / 0.05);
|
||||
--sans: "Space Grotesk", system-ui, -apple-system, sans-serif;
|
||||
--mono: "Space Mono", ui-monospace, Menlo, monospace;
|
||||
}
|
||||
[data-theme="dark"] {
|
||||
--paper: oklch(19% 0.008 60);
|
||||
--surface: oklch(22% 0.01 60);
|
||||
--line: oklch(30% 0.012 60);
|
||||
--ink: oklch(93% 0.006 75);
|
||||
--ink-2: oklch(72% 0.012 70);
|
||||
--ink-3: oklch(60% 0.012 65);
|
||||
--accent: oklch(70% 0.15 40);
|
||||
--accent-hi: oklch(76% 0.14 42);
|
||||
--paper: oklch(17.5% 0.01 267); --card: oklch(21% 0.012 267); --tint: oklch(24% 0.014 267);
|
||||
--line: oklch(31% 0.015 267); --mark: oklch(52% 0.012 267);
|
||||
--ink: oklch(94% 0.005 95); --ink-soft: oklch(72% 0.01 95);
|
||||
--accent: oklch(70% 0.15 267); --accent-2: oklch(79% 0.12 267); --accent-bg: oklch(70% 0.15 267 / 0.14); --on-accent: oklch(17% 0.03 267);
|
||||
--shadow: 0 1px 2px oklch(0% 0 0 / 0.3);
|
||||
}
|
||||
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html { -webkit-text-size-adjust: 100%; }
|
||||
body {
|
||||
margin: 0; background: var(--paper); color: var(--ink);
|
||||
font-family: var(--font); font-size: 1rem; line-height: 1.62;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.legal-head { border-bottom: 1px solid var(--line); background: var(--surface); }
|
||||
.legal-head .inner, main.legal { width: min(100% - 2.5rem, 46rem); margin-inline: auto; }
|
||||
.legal-head .inner { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.9rem 0; }
|
||||
.legal-head a.back { display: inline-flex; align-items: center; gap: 0.45rem; text-decoration: none; color: var(--ink); font-weight: 500; }
|
||||
.legal-head .wordmark { font-family: var(--mono); font-size: 1.02rem; letter-spacing: -0.03em; }
|
||||
.legal-head .wordmark b { color: var(--accent); }
|
||||
.legal-head nav { display: flex; gap: 1.25rem; font-size: 0.875rem; }
|
||||
.legal-head nav a { color: var(--ink-3); text-decoration: none; }
|
||||
.legal-head nav a:hover, .legal-head nav a[aria-current="page"] { color: var(--accent); }
|
||||
|
||||
main.legal { padding: 3rem 0 5rem; }
|
||||
h1 { font-size: clamp(1.9rem, 1.5rem + 1.6vw, 2.5rem); letter-spacing: -0.03em; line-height: 1.12; margin: 0 0 1.5rem; }
|
||||
h2 { font-size: 1.0625rem; letter-spacing: -0.015em; margin: 2.4rem 0 0.6rem; }
|
||||
p { margin: 0 0 1em; color: var(--ink-2); }
|
||||
p.intro { color: var(--ink); }
|
||||
ul { padding-left: 1.15rem; margin: 0 0 1em; color: var(--ink-2); }
|
||||
li { margin-bottom: 0.32em; }
|
||||
body { margin: 0; background: var(--paper); color: var(--ink); font-family: var(--sans); font-size: 16px; line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased; padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }
|
||||
a { color: var(--accent); text-underline-offset: 3px; }
|
||||
a:hover { color: var(--accent-hi); }
|
||||
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }
|
||||
code, .mono { font-family: var(--mono); font-size: 0.92em; }
|
||||
a:hover { color: var(--accent-2); }
|
||||
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
||||
|
||||
table.legal-table { border-collapse: collapse; margin: 0 0 1em; }
|
||||
table.legal-table th { text-align: left; font-weight: 500; color: var(--ink-3); padding: 0.22rem 1.6rem 0.22rem 0; vertical-align: top; white-space: nowrap; font-size: 0.9375rem; }
|
||||
table.legal-table td { padding: 0.22rem 0; vertical-align: top; color: var(--ink-2); }
|
||||
.topbar { position: sticky; top: 0; z-index: 10; display: flex; align-items: center; gap: 12px;
|
||||
padding: calc(10px + env(safe-area-inset-top)) 16px 10px; border-bottom: 1px solid var(--line);
|
||||
background: color-mix(in oklab, var(--card) 88%, transparent); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
|
||||
.brand { display: inline-flex; align-items: center; gap: 9px; color: var(--ink); text-decoration: none; font-weight: 700; font-size: 1.2rem; letter-spacing: -0.02em; }
|
||||
.brand:hover { color: var(--ink); }
|
||||
.brand svg { width: 22px; height: 22px; color: var(--accent); }
|
||||
.brand .two { color: var(--accent); }
|
||||
.topbar nav { margin-left: auto; display: flex; gap: 4px; flex-wrap: wrap; }
|
||||
.topbar nav a { min-height: 40px; display: inline-flex; align-items: center; padding: 0 12px; border-radius: 999px; color: var(--ink-soft); text-decoration: none; font-size: 0.9rem; }
|
||||
.topbar nav a:hover { color: var(--ink); background: var(--tint); }
|
||||
.topbar nav a[aria-current="page"] { color: var(--accent); background: var(--accent-bg); font-weight: 700; }
|
||||
|
||||
.legal-foot { border-top: 1px solid var(--line); margin-top: 3rem; padding-top: 1.25rem; font-size: 0.875rem; color: var(--ink-3); }
|
||||
.legal-foot a { color: var(--ink-3); }
|
||||
main.legal { max-width: 760px; margin: 0 auto; padding: 32px 16px calc(64px + env(safe-area-inset-bottom)); }
|
||||
.mono-label { font-family: var(--mono); font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--ink-soft); }
|
||||
h1 { font-size: clamp(1.9rem, 1.5rem + 1.6vw, 2.5rem); letter-spacing: -0.02em; line-height: 1.12; margin: 6px 0 20px; }
|
||||
.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); padding: 8px 24px 20px; }
|
||||
h2 { font-size: 1.08rem; letter-spacing: -0.01em; margin: 1.8rem 0 0.5rem; }
|
||||
p { margin: 0 0 1em; color: var(--ink-soft); }
|
||||
p.intro { color: var(--ink); font-size: 1.05rem; margin-bottom: 20px; }
|
||||
ul { padding-left: 1.15rem; margin: 0 0 1em; color: var(--ink-soft); }
|
||||
li { margin-bottom: 0.3em; }
|
||||
code, .mono { font-family: var(--mono); font-size: 0.88em; }
|
||||
table.legal-table { border-collapse: collapse; margin: 0 0 1em; width: 100%; }
|
||||
table.legal-table th { text-align: left; font-weight: 400; color: var(--ink-soft); padding: 0.3rem 1.4rem 0.3rem 0; vertical-align: top; white-space: nowrap; font-family: var(--mono); font-size: 0.78rem; letter-spacing: .04em; }
|
||||
table.legal-table td { padding: 0.3rem 0; vertical-align: top; overflow-wrap: anywhere; }
|
||||
.legal-foot { margin-top: 24px; display: flex; gap: 8px 18px; flex-wrap: wrap; font-size: 0.9rem; }
|
||||
.legal-foot a { color: var(--ink-soft); text-decoration: none; padding: 6px 0; }
|
||||
.legal-foot a:hover { color: var(--accent); }
|
||||
|
||||
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; } }
|
||||
@media (max-width: 560px) {
|
||||
.card { padding: 4px 16px 16px; }
|
||||
.topbar nav a { padding: 0 10px; font-size: 0.85rem; }
|
||||
table.legal-table th, table.legal-table td { display: block; padding: 0; }
|
||||
table.legal-table td { margin-bottom: 10px; }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: .001ms !important; animation-duration: .001ms !important; } }
|
||||
.card > :first-child { margin-top: 18px; }
|
||||
.topbar nav a.lang { font-family: var(--mono); font-size: 0.72rem; letter-spacing: .06em; border: 1px solid var(--line); margin-left: 4px; }
|
||||
.topbar nav a.lang:hover { color: var(--accent); border-color: var(--accent); background: transparent; }
|
||||
@media (max-width: 560px) {
|
||||
.topbar { gap: 8px; padding-left: 12px; padding-right: 12px; }
|
||||
.brand { font-size: 1.05rem; }
|
||||
.topbar nav { flex-wrap: nowrap; gap: 2px; }
|
||||
.topbar nav a { padding: 0 8px; font-size: 0.8rem; }
|
||||
.topbar nav a.lang { padding: 0 7px; margin-left: 2px; }
|
||||
}
|
||||
@@ -1,13 +1,45 @@
|
||||
{
|
||||
"name": "clip2md — Paste to Markdown",
|
||||
"short_name": "clip2md",
|
||||
"description": "Paste rich text or a web page and save it as clean Markdown in one keystroke. Client-side, private, offline-capable.",
|
||||
"start_url": ".",
|
||||
"scope": ".",
|
||||
"description": "Paste rich text or a web page and save it as clean Markdown in one click. Client-side, private, offline-capable.",
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#faf7f2",
|
||||
"theme_color": "#faf7f2",
|
||||
"background_color": "#EAEAE3",
|
||||
"theme_color": "#EAEAE3",
|
||||
"icons": [
|
||||
{ "src": "icon.svg", "sizes": "any", "type": "image/svg+xml", "purpose": "any maskable" }
|
||||
]
|
||||
{
|
||||
"src": "/icon.svg",
|
||||
"sizes": "any",
|
||||
"type": "image/svg+xml",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icon-maskable-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
],
|
||||
"share_target": {
|
||||
"action": "/",
|
||||
"method": "GET",
|
||||
"params": {
|
||||
"title": "title",
|
||||
"text": "text",
|
||||
"url": "url"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,10 @@ server {
|
||||
add_header Cache-Control "no-cache";
|
||||
}
|
||||
|
||||
# Pages and icons revalidate on every load, so a deploy reaches users immediately.
|
||||
location / {
|
||||
include /etc/nginx/security-headers.conf;
|
||||
add_header Cache-Control "no-cache";
|
||||
try_files $uri $uri.html $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta name="robots" content="noindex" />
|
||||
<meta name="theme-color" content="#EAEAE3" />
|
||||
<title>Privacy policy — clip2md</title>
|
||||
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
|
||||
<link rel="stylesheet" href="/legal.css" />
|
||||
<link rel="alternate" hreflang="de" href="https://clip2md.heidrich-digital.de/datenschutz.html" />
|
||||
<link rel="alternate" hreflang="en" href="https://clip2md.heidrich-digital.de/privacy.html" />
|
||||
<script>
|
||||
try { var th = JSON.parse(localStorage.getItem('clip2md:theme')); if (th === 'dark' || (th === null && matchMedia('(prefers-color-scheme: dark)').matches)) document.documentElement.setAttribute('data-theme','dark'); } catch (e) {}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<a class="brand" href="/"><svg viewBox="0 0 24 24" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="4.5" width="14" height="17" rx="1.5"/><path d="M12 9.5v7.5M8.8 13.8 12 17l3.2-3.2"/></g><rect x="8.6" y="2.4" width="6.8" height="3.8" rx="1" fill="currentColor"/></svg><span>clip<span class="two">2</span>md</span></a>
|
||||
<nav>
|
||||
<a href="/imprint.html">Legal notice</a>
|
||||
<a href="/privacy.html" aria-current="page">Privacy</a>
|
||||
<a class="lang" href="/datenschutz.html" hreflang="de" lang="de" title="Deutsch">DE</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="legal">
|
||||
<span class="mono-label">Legal</span>
|
||||
<h1>Privacy policy</h1>
|
||||
<div class="card">
|
||||
<p class="intro">This is a translation provided for convenience. The German version (<a href="/datenschutz.html">Datenschutzerklärung</a>) is legally binding.</p>
|
||||
|
||||
<p>
|
||||
The text you paste on this site is converted exclusively in your browser. It is not
|
||||
transmitted, stored or analysed. There are no cookies, no analytics, no embedded third-party
|
||||
services and no externally loaded fonts. Only the technical access data that arises whenever a
|
||||
website is requested is collected.
|
||||
</p>
|
||||
|
||||
<h2>1. Controller</h2>
|
||||
<p>
|
||||
Till Heidrich – Content Creation<br />
|
||||
Till Heidrich<br />
|
||||
Rotdornweg 17, 21255 Tostedt, Germany<br />
|
||||
Email: <a href="mailto:info@tillheidrich.de">info@tillheidrich.de</a><br />
|
||||
Phone: <a href="tel:+4915773953819">+49 1577 3953819</a>
|
||||
</p>
|
||||
<p>There is no legal requirement to appoint a data protection officer.</p>
|
||||
|
||||
<h2>2. Processing of pasted content</h2>
|
||||
<p>
|
||||
Converting formatted text into Markdown happens entirely client-side, by JavaScript in your
|
||||
browser. Content you paste never leaves your device and is discarded when you close or reload
|
||||
the page. To that extent, we do not process any personal data within the meaning of the GDPR.
|
||||
</p>
|
||||
<p>
|
||||
Saving the result as a <code>.md</code> file and copying it to the clipboard also happen locally
|
||||
through the corresponding browser interfaces. No data is sent to us.
|
||||
</p>
|
||||
<p>
|
||||
The “Paste” button reads your device's clipboard. This only happens when you press the button
|
||||
and, depending on the browser, only after you have given permission. As with pasting via the
|
||||
keyboard, the content is converted locally only. On smartphones, “Save” hands the file to your
|
||||
operating system's share sheet; where you pass it on from there is up to you.
|
||||
</p>
|
||||
<p>
|
||||
Cleaning up pasted web pages and formatting Reddit threads also run entirely in your browser.
|
||||
The optional “Open in Obsidian” button places the text on the clipboard and hands it to the
|
||||
Obsidian app on your device; nothing is transmitted to us or third parties.
|
||||
</p>
|
||||
|
||||
<h2>3. Local storage of your settings</h2>
|
||||
<p>
|
||||
So that the site remembers your preferences, it stores values in your browser's local storage
|
||||
(<span class="mono">localStorage</span>), such as your chosen language, light or dark
|
||||
appearance and your conversion settings. These values stay on your device, are not transmitted
|
||||
to us and contain none of the content you paste. They are not cookies. You can delete them at
|
||||
any time in your browser settings.
|
||||
</p>
|
||||
<p>
|
||||
Only if you switch on “Keep the last 10 clips” in the settings does the site store the most
|
||||
recently edited texts in your browser's local database (<span class="mono">IndexedDB</span>).
|
||||
This feature is off by default. The entries never leave your device, are only visible in this
|
||||
browser and can be deleted individually or all at once in the history; when you switch the
|
||||
feature off, you are asked whether the history should be deleted.
|
||||
</p>
|
||||
<p>
|
||||
The basis for this purely local storage is your wish for a working user interface; we have no
|
||||
access to it.
|
||||
</p>
|
||||
|
||||
<h2>4. Offline use (Progressive Web App)</h2>
|
||||
<p>
|
||||
The site registers a service worker that stores the required program files in your browser's
|
||||
cache, so clip2md also works without an internet connection. Only program files of this site
|
||||
are cached, never your content. You can remove the cache via your browser's site data.
|
||||
</p>
|
||||
|
||||
<h2>5. Server log files</h2>
|
||||
<p>When this site is requested, the hosting provider automatically stores data in log files:</p>
|
||||
<ul>
|
||||
<li>IP address of the requesting device</li>
|
||||
<li>date and time of access</li>
|
||||
<li>name and URL of the requested file</li>
|
||||
<li>amount of data transferred and whether the request succeeded</li>
|
||||
<li>browser and operating system used</li>
|
||||
<li>where applicable, the previously visited page (referrer)</li>
|
||||
</ul>
|
||||
<p>
|
||||
The legal basis is Art. 6 (1) (f) GDPR. Our legitimate interest lies in the technically
|
||||
error-free operation and security of the service. The data is deleted after seven days at the
|
||||
latest and is not combined with other data sources.
|
||||
</p>
|
||||
|
||||
<h2>6. Hosting</h2>
|
||||
<p>
|
||||
This site is operated on servers of Hetzner Online GmbH, Industriestr. 25, 91710 Gunzenhausen,
|
||||
Germany. A data processing agreement pursuant to Art. 28 GDPR is in place with the provider.
|
||||
Processing takes place exclusively within the European Union. Data transfer to this site is
|
||||
encrypted via HTTPS.
|
||||
</p>
|
||||
|
||||
<h2>7. No cookies, no tracking</h2>
|
||||
<p>
|
||||
This site sets no cookies and uses no analytics, advertising or audience measurement services.
|
||||
No content is loaded from third-party servers, in particular no fonts and no scripts from
|
||||
content delivery networks. A consent banner is therefore not required.
|
||||
</p>
|
||||
<p>
|
||||
One exception concerns the optional preview: if the text you paste contains images hosted on
|
||||
third-party servers, your browser loads those images from there when the preview is shown. The
|
||||
respective server learns your IP address in the process. None of your text is transmitted, and
|
||||
the origin is not sent thanks to <span class="mono">Referrer-Policy: no-referrer</span>. If you
|
||||
want to avoid this, keep the preview switched off.
|
||||
</p>
|
||||
|
||||
<h2>8. Support via PayPal</h2>
|
||||
<p>
|
||||
The site contains a “Donate” or “Buy me a coffee” link. It is a plain link; when you open
|
||||
clip2md, no content, scripts or cookies are loaded from PayPal and no data is sent to PayPal.
|
||||
Only when you click the link do you leave this site and reach a PayPal payment page.
|
||||
</p>
|
||||
<p>
|
||||
The provider is PayPal (Europe) S.à r.l. et Cie, S.C.A., 22–24 Boulevard Royal, L-2449
|
||||
Luxembourg. PayPal itself is responsible for processing on its pages; its privacy statement
|
||||
applies:
|
||||
<a href="https://www.paypal.com/de/legalhub/privacy-full" rel="noopener nofollow">paypal.com/de/legalhub/privacy-full</a>.
|
||||
</p>
|
||||
<p>
|
||||
If you pay an amount, PayPal provides us with the details needed to process it, in particular
|
||||
your name, email address, the amount, date and time, and the transaction number. The legal basis
|
||||
is Art. 6 (1) (b) GDPR (processing the payment) and Art. 6 (1) (c) GDPR in conjunction with
|
||||
statutory tax and commercial retention obligations (usually eight to ten years). The data is not
|
||||
used for any other purpose, such as advertising. The payment is voluntary; nothing is provided
|
||||
in return.
|
||||
</p>
|
||||
|
||||
<h2>9. Your rights</h2>
|
||||
<p>
|
||||
You have the right of access (Art. 15 GDPR), rectification (Art. 16), erasure (Art. 17),
|
||||
restriction of processing (Art. 18), data portability (Art. 20) and the right to object to
|
||||
processing based on Art. 6 (1) (f) GDPR (Art. 21). To exercise these rights, please contact the
|
||||
address above.
|
||||
</p>
|
||||
|
||||
<h2>10. Right to lodge a complaint</h2>
|
||||
<p>
|
||||
You may lodge a complaint with a data protection supervisory authority. The competent authority
|
||||
is the State Commissioner for Data Protection of Lower Saxony (Die Landesbeauftragte für den
|
||||
Datenschutz Niedersachsen), Prinzenstraße 5, 30159 Hannover, Germany.
|
||||
</p>
|
||||
|
||||
<h2>11. Last updated</h2>
|
||||
<p>This privacy policy was last updated in September 2026.</p>
|
||||
|
||||
</div>
|
||||
<div class="legal-foot">
|
||||
<a href="/">← Back to clip2md</a>
|
||||
<a href="/imprint.html">Legal notice</a>
|
||||
<a href="https://www.paypal.com/ncp/payment/54FPXDFBMP5TJ" target="_blank" rel="noopener nofollow">Donate</a>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,19 +1,31 @@
|
||||
/* clip2md service worker — offline shell cache. Bump CACHE on any asset change. */
|
||||
var CACHE = 'clip2md-v3';
|
||||
/* clip2md service worker.
|
||||
Pages (navigations, .html): network first, cache only as offline fallback —
|
||||
so new or changed pages are never frozen for existing users.
|
||||
Static assets (vendor, fonts, icons): cache first. Bump CACHE on asset changes. */
|
||||
var CACHE = 'clip2md-v8';
|
||||
var ASSETS = [
|
||||
'./',
|
||||
'./index.html',
|
||||
'./impressum.html',
|
||||
'./datenschutz.html',
|
||||
'./legal.css',
|
||||
'./icon.svg',
|
||||
'./manifest.webmanifest',
|
||||
'./vendor/turndown.js',
|
||||
'./vendor/turndown-plugin-gfm.js',
|
||||
'./vendor/marked.umd.js',
|
||||
'./vendor/purify.min.js',
|
||||
'./vendor/fonts/Geist-Variable.woff2',
|
||||
'./vendor/fonts/GeistMono-Variable.woff2'
|
||||
'/',
|
||||
'/index.html',
|
||||
'/impressum.html',
|
||||
'/datenschutz.html',
|
||||
'/imprint.html',
|
||||
'/privacy.html',
|
||||
'/legal.css',
|
||||
'/icon.svg',
|
||||
'/icon-192.png',
|
||||
'/apple-touch-icon.png',
|
||||
'/manifest.webmanifest',
|
||||
'/vendor/turndown.js',
|
||||
'/vendor/turndown-plugin-gfm.js',
|
||||
'/vendor/marked.umd.js',
|
||||
'/vendor/purify.min.js',
|
||||
'/vendor/Readability.js',
|
||||
'/clean.js',
|
||||
'/vendor/fonts/space-grotesk-latin-400-normal.woff2',
|
||||
'/vendor/fonts/space-grotesk-latin-500-normal.woff2',
|
||||
'/vendor/fonts/space-grotesk-latin-700-normal.woff2',
|
||||
'/vendor/fonts/space-mono-latin-400-normal.woff2',
|
||||
'/vendor/fonts/space-mono-latin-700-normal.woff2'
|
||||
];
|
||||
|
||||
self.addEventListener('install', function (e) {
|
||||
@@ -29,18 +41,36 @@ self.addEventListener('activate', function (e) {
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', function (e) {
|
||||
if (e.request.method !== 'GET') return;
|
||||
e.respondWith(
|
||||
caches.match(e.request).then(function (hit) {
|
||||
return hit || fetch(e.request).then(function (res) {
|
||||
// Runtime-cache same-origin successful responses.
|
||||
if (res && res.ok && e.request.url.indexOf(self.location.origin) === 0) {
|
||||
var copy = res.clone();
|
||||
caches.open(CACHE).then(function (c) { c.put(e.request, copy); });
|
||||
function isPage(req, url) {
|
||||
return req.mode === 'navigate' || req.destination === 'document' || /\.html$/.test(url.pathname) || url.pathname === '/';
|
||||
}
|
||||
|
||||
self.addEventListener('fetch', function (e) {
|
||||
var req = e.request;
|
||||
if (req.method !== 'GET') return;
|
||||
var url = new URL(req.url);
|
||||
if (url.origin !== self.location.origin) return; // external links (PayPal, GitHub) untouched
|
||||
|
||||
if (isPage(req, url)) {
|
||||
e.respondWith(
|
||||
fetch(req).then(function (res) {
|
||||
if (res && res.ok) { var copy = res.clone(); caches.open(CACHE).then(function (c) { c.put(req, copy); }); }
|
||||
return res;
|
||||
}).catch(function () { return caches.match('./index.html'); });
|
||||
}).catch(function () {
|
||||
return caches.match(req).then(function (hit) {
|
||||
return hit || caches.match(url.pathname.replace(/\/$/, '/index.html')) || caches.match('/index.html');
|
||||
});
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
e.respondWith(
|
||||
caches.match(req).then(function (hit) {
|
||||
return hit || fetch(req).then(function (res) {
|
||||
if (res && res.ok) { var copy = res.clone(); caches.open(CACHE).then(function (c) { c.put(req, copy); }); }
|
||||
return res;
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
Copyright (c) 2010 Arc90 Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2020 The Space Grotesk Project Authors (https://github.com/floriankarsten/space-grotesk)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2016 The Space Mono Project Authors (https://github.com/googlefonts/spacemono) SpaceMono-Italic.ttf: Copyright 2016 The Space Mono Project Authors (https://github.com/googlefonts/spacemono) SpaceMono-Bold.ttf: Copyright 2016 The Space Mono Project Authors (https://github.com/googlefonts/spacemono) SpaceMono-BoldItalic.ttf: Copyright 2016 The Space Mono Project Authors (https://github.com/googlefonts/spacemono)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||