Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12dfec7330 | ||
|
|
20b9d3a460 | ||
|
|
0fa06d3ebd | ||
|
|
9b7328688a |
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Build-Ausgaben / Zwischenstände
|
||||
webview2/out/
|
||||
webview2/bin/
|
||||
webview2/obj/
|
||||
|
||||
# (Falls die Electron-Variante mal dazukommt)
|
||||
electron/node_modules/
|
||||
electron/dist/
|
||||
node_modules/
|
||||
|
||||
# System
|
||||
Thumbs.db
|
||||
Desktop.ini
|
||||
.DS_Store
|
||||
187
README.md
@@ -1,154 +1,87 @@
|
||||
# MyStart
|
||||
|
||||
Deine persönliche Startseite / neue-Tab-Seite als eigenständige Windows-App –
|
||||
angepasst aus dem quelloffenen Projekt **nightTab**.
|
||||
Persönliche Startseite / neue-Tab-Seite als eigenständige Windows-App –
|
||||
angepasst aus dem quelloffenen Projekt **nightTab**, komplett auf Deutsch.
|
||||
|
||||
Dieses Repo enthält die **Quellen zum Bauen** der App. Die fertige `MyStart.exe`
|
||||
selbst ist ein Build-Artefakt und liegt nicht im Repo.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Schnellstart
|
||||
## Was die App kann
|
||||
|
||||
1. **`MyStart.exe`** doppelklicken.
|
||||
2. Beim ersten Start meldet sich evtl. **Windows SmartScreen**
|
||||
(„Der Computer wurde durch Windows geschützt"), weil die Datei nicht
|
||||
signiert ist. → **Weitere Informationen** → **Trotzdem ausführen**.
|
||||
Das ist bei selbstgebauten Programmen normal.
|
||||
3. Fertig – MyStart öffnet sich in einem eigenen Fenster.
|
||||
- Angepasste, **komplett deutsche** nightTab-Oberfläche
|
||||
- Eigenständige, schnelle **WebView2/.NET-Einzeldatei** (~48 MB, Start ~2 s,
|
||||
danach praktisch sofort)
|
||||
- **Randloses Fenster** mit eigenen Knöpfen oben rechts (Verschieben ⠿,
|
||||
Minimieren –, Max./Wiederherstellen □, Schließen ✕); Verschieben auch per
|
||||
`Alt` + Ziehen
|
||||
- **Autostart-Schalter** direkt in den Einstellungen (Einstellungen → MyStart)
|
||||
- Dunkler, schlanker Scrollbalken
|
||||
- Import nimmt **MyStart-** und alte **nightTab**-Sicherungen an
|
||||
- Externe Links öffnen im Standard-Browser
|
||||
|
||||
> **Hinweis zur Startzeit:** Die App entpackt sich bei jedem Start kurz selbst
|
||||
> (sie bringt alles Nötige mit). Der Start dauert daher **ca. 11 Sekunden** –
|
||||
> danach läuft alles flüssig.
|
||||
|
||||
Keine Installation nötig. Du kannst `MyStart.exe` beliebig verschieben
|
||||
(Desktop, USB-Stick, anderer PC) – sie läuft überall eigenständig.
|
||||
Daten der App liegen zur Laufzeit unter `%LOCALAPPDATA%\MyStart`.
|
||||
|
||||
---
|
||||
|
||||
## ✨ Funktionen
|
||||
|
||||
- **Lesezeichen & Gruppen** frei anordnen, benennen, mit Icon/Bild/Buchstabe
|
||||
- **Design komplett anpassbar:** Farben, Akzent, Schriftarten, Hintergrund
|
||||
(Farbe, Verlauf, Bild oder Video), Radius, Schatten, Deckkraft
|
||||
- **Kopfzeile** mit Begrüßung, Uhr, Datum und Suchfeld
|
||||
- **Suche** über die gewünschte Suchmaschine direkt aus dem Startbildschirm
|
||||
- **Komplett auf Deutsch**
|
||||
|
||||
---
|
||||
|
||||
## 🇩🇪 Deutsche Oberfläche
|
||||
|
||||
Die gesamte Bedienoberfläche ist auf Deutsch – Menüs, Einstellungen,
|
||||
Schaltflächen, Hilfetexte und Meldungen.
|
||||
|
||||
*Kleine Ausnahme:* Die Farbnamen im Akzent-Farbwähler
|
||||
(z. B. „Light grey", „Dark red") sind englisch geblieben. Sie hängen technisch
|
||||
mit internen Funktionen zusammen und lassen sich nicht gefahrlos übersetzen.
|
||||
Es sind reine Bezeichnungen von Farbkacheln – die Funktion ist unberührt.
|
||||
|
||||
---
|
||||
|
||||
## 💾 Einstellungen, Lesezeichen & Backups
|
||||
|
||||
**Speicherort deiner Daten:**
|
||||
```
|
||||
%APPDATA%\MyStart
|
||||
```
|
||||
(entspricht `C:\Users\<DeinName>\AppData\Roaming\MyStart`)
|
||||
|
||||
Deine Einstellungen und Lesezeichen bleiben erhalten – auch wenn du die
|
||||
`MyStart.exe` verschiebst oder umbenennst.
|
||||
|
||||
**Sicherung erstellen:** Einstellungen → **Daten** → **Sichern**
|
||||
**Sicherung einspielen:** Einstellungen → **Daten** → **Wiederherstellen**
|
||||
|
||||
> Der Import akzeptiert **beide** Backup-Typen: die von **MyStart** erstellten
|
||||
> *und* alte **nightTab**-Sicherungen.
|
||||
|
||||
**Alles zurücksetzen:** den Ordner `%APPDATA%\MyStart` löschen.
|
||||
|
||||
---
|
||||
|
||||
## ℹ️ Info-Seite (Einstellungen → MyStart)
|
||||
|
||||
Zeigt Logo, Name, Version und deine Links:
|
||||
- **Website:** https://m-viper.de
|
||||
- **Git:** https://git.viper.ipv64.net
|
||||
|
||||
Alle Links (auch normale Lesezeichen) öffnen sich in deinem
|
||||
**Standard-Browser**, nicht innerhalb der App.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Was gegenüber dem Original geändert wurde
|
||||
|
||||
- Umbenannt von **nightTab** → **MyStart** (überall)
|
||||
- Menüpunkte **„Support"** und **„Coffee"** (Spenden) entfernt
|
||||
- **Info-Seite** vereinfacht: Logo + Name + Version 1.0.0 + deine Links
|
||||
- Externe Links öffnen im **Standard-Browser**
|
||||
- Import nimmt **nightTab- und MyStart-Sicherungen** an
|
||||
- **Komplette deutsche Übersetzung** der Oberfläche
|
||||
- Als **eigenständige `.exe`** verpackt (kein Browser-Add-on, keine Installation)
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Gut zu wissen
|
||||
|
||||
- **Startzeit ~11 s** – bauartbedingt (Einzeldatei, entpackt sich bei jedem
|
||||
Start). Auf Wunsch gibt es Alternativen (schnellere Ordner-Version o. Ä.).
|
||||
- **SmartScreen-Warnung** beim ersten Start ist normal (siehe Schnellstart).
|
||||
- Als **echte neue-Tab-Seite** im Browser (automatisch bei jedem Tab)
|
||||
funktioniert nur eine echte Browser-Erweiterung – das ist eine
|
||||
Chrome-Beschränkung. MyStart öffnest du bewusst per Doppelklick.
|
||||
|
||||
---
|
||||
|
||||
## 📦 Inhalt des Backup-Ordners
|
||||
## Aufbau des Repos
|
||||
|
||||
```
|
||||
MyStart-Backup\
|
||||
├─ MyStart.exe Die fertige App (Doppelklick zum Starten)
|
||||
├─ MyStart-App.html Dieselbe App als einzelne HTML-Datei (Notfall-Variante,
|
||||
│ in jedem Browser öffenbar)
|
||||
├─ README.md Diese Datei
|
||||
├─ LIESMICH.txt Kurzanleitung als Textdatei
|
||||
└─ projekt\ Alle Dateien zum Neubauen / Weiteranpassen
|
||||
├─ bundle.js Baut die angepasste, deutsche App aus der Quelle
|
||||
├─ quelle-nightTab\ Unveränderte Original-Quelle (nightTab 7.3.0)
|
||||
└─ electron\
|
||||
├─ main.js Fensterlogik, externe Links im Standardbrowser
|
||||
├─ package.json Bau-Einstellungen (electron-builder)
|
||||
├─ de.json Deutsche Übersetzung (Steuerelemente/Labels)
|
||||
├─ de2.json Deutsche Übersetzung (Hilfe-/Meldungstexte)
|
||||
├─ app\index.html Die fertig angepasste, deutsche App
|
||||
└─ build\icon.ico App-Icon
|
||||
bundle.js Baut aus der Quelle die angepasste, deutsche App-HTML
|
||||
lang/ Deutsche Übersetzungen
|
||||
de.json Steuerelemente / Labels
|
||||
de2.json Hilfe- / Meldungstexte
|
||||
quelle-nightTab/ Unveränderte Original-Quelle (nightTab 7.3.0, GPL v3)
|
||||
webview2/ Die Windows-App (.NET + WebView2)
|
||||
Program.cs Fenster, Knöpfe, Verschieben, Autostart, externe Links
|
||||
MyStart.csproj Bau-Einstellungen (.NET)
|
||||
app.ico App-Icon (auch build/icon.ico)
|
||||
app-index.html Von bundle.js erzeugt (die fertige App) *
|
||||
README.md
|
||||
.gitignore
|
||||
```
|
||||
\* `webview2/app-index.html` wird von `bundle.js` erzeugt. Sie ist mit
|
||||
eingecheckt, damit `dotnet publish` sofort funktioniert – nach Änderungen an
|
||||
`bundle.js`, `lang/` oder der Quelle einfach neu erzeugen (siehe unten).
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Neu bauen (nur bei Änderungen nötig)
|
||||
## Bauen
|
||||
|
||||
Voraussetzung: **Node.js** installiert.
|
||||
**Voraussetzungen:** [Node.js](https://nodejs.org) und das
|
||||
[.NET SDK](https://dotnet.microsoft.com/download) (Windows, x64).
|
||||
|
||||
```bash
|
||||
# 1) Einmalig im Ordner projekt\electron:
|
||||
npm install
|
||||
# 1) Angepasste, deutsche App-HTML erzeugen
|
||||
# (schreibt standardmäßig nach webview2/app-index.html)
|
||||
node bundle.js
|
||||
|
||||
# 2) Angepasste deutsche App erzeugen (im Ordner projekt):
|
||||
node bundle.js "./electron/app/index.html"
|
||||
|
||||
# 3) Die .exe bauen (im Ordner projekt\electron):
|
||||
npx electron-builder --win portable --x64
|
||||
# Ergebnis: projekt\electron\dist\MyStart.exe
|
||||
# 2) Die Windows-.exe bauen
|
||||
cd webview2
|
||||
dotnet publish -c Release -r win-x64 -o ./out
|
||||
# Ergebnis: webview2/out/MyStart.exe
|
||||
```
|
||||
|
||||
> `bundle.js` liest die Quelle aus `C:\Users\Viper\Desktop\nightTab`.
|
||||
> Fehlt dieser Ordner, in `bundle.js` den Pfad auf `projekt\quelle-nightTab`
|
||||
> anpassen.
|
||||
`bundle.js` liest die Quelle relativ aus `quelle-nightTab/` – das Repo baut
|
||||
also auf jedem Rechner ohne Pfadanpassung.
|
||||
|
||||
---
|
||||
|
||||
## 📄 Herkunft & Lizenz
|
||||
## Anpassen
|
||||
|
||||
MyStart basiert auf **nightTab** von zombieFox
|
||||
- **Übersetzungen:** `lang/de.json` (Labels) und `lang/de2.json` (Sätze) ändern,
|
||||
dann Schritt 1+2 erneut.
|
||||
- **Info-Seite, Umbenennung, Autostart-Schalter, Fenster-Knöpfe, Scrollbalken
|
||||
usw.:** stecken als Transformationen in `bundle.js`.
|
||||
- **Fensterlogik / Autostart / externe Links:** `webview2/Program.cs`.
|
||||
|
||||
---
|
||||
|
||||
## Herkunft & Lizenz
|
||||
|
||||
Basiert auf **nightTab** von zombieFox
|
||||
(https://github.com/zombieFox/nightTab), veröffentlicht unter der
|
||||
**GNU General Public License v3.0**. Diese Anpassung ist zum persönlichen
|
||||
Gebrauch bestimmt.
|
||||
**GNU General Public License v3.0**. Der Ordner `quelle-nightTab/` enthält den
|
||||
unveränderten nightTab-Build; die Anpassungen in diesem Repo unterliegen
|
||||
ebenfalls der GPL v3.
|
||||
|
||||
437
bundle.js
Normal file
@@ -0,0 +1,437 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Original nightTab source (input) lives next to this script.
|
||||
const root = path.join(__dirname, 'quelle-nightTab');
|
||||
// Output HTML: explicit arg, else default to the WebView2 project.
|
||||
const out = process.argv[2] || path.join(__dirname, 'webview2', 'app-index.html');
|
||||
const APPNAME = 'MyStart';
|
||||
|
||||
let css = fs.readFileSync(path.join(root, 'index.41b2d2a8cee846b032b5.css'), 'utf8');
|
||||
|
||||
const mime = { woff2: 'font/woff2', woff: 'font/woff', ttf: 'font/ttf' };
|
||||
css = css.replace(/url\((font\/[^)]+)\)/g, (m, rel) => {
|
||||
const p = path.join(root, rel);
|
||||
const ext = rel.split('.').pop();
|
||||
const b64 = fs.readFileSync(p).toString('base64');
|
||||
return `url(data:${mime[ext] || 'application/octet-stream'};base64,${b64})`;
|
||||
});
|
||||
|
||||
let initJs = fs.readFileSync(path.join(root, 'initialBackground.js'), 'utf8');
|
||||
let mainJs = fs.readFileSync(path.join(root, 'index.09153abdbaa791fa4f0e.js'), 'utf8');
|
||||
|
||||
// --- 1) Remove the "Support" and "Coffee" entries from the settings menu ---
|
||||
const navSnippet = '{name:"Support",active:!1,overscroll:!1},{name:"Coffee",active:!1,overscroll:!1},';
|
||||
if (!mainJs.includes(navSnippet)) throw new Error('navData snippet not found — aborting');
|
||||
mainJs = mainJs.replace(navSnippet, '');
|
||||
|
||||
// --- 1b) Rebuild the About page: logo + name + version + own website & git links ---
|
||||
const aStart = 'const t=new Pa({text:"GitHub.';
|
||||
const aEndMarker = ',s,o,n]))';
|
||||
const i = mainJs.indexOf(aStart);
|
||||
if (i < 0) throw new Error('About block start not found — aborting');
|
||||
const j = mainJs.indexOf(aEndMarker, i);
|
||||
if (j < 0) throw new Error('About block end not found — aborting');
|
||||
const aboutBody =
|
||||
'const t=new Pa({text:"m-viper.de",href:"https://m-viper.de",openNew:!0}),' +
|
||||
'a=new Pa({text:"git.viper.ipv64.net",href:"https://git.viper.ipv64.net",openNew:!0}),' +
|
||||
's=y("p");s.innerHTML=`Website: ${t.link().outerHTML}`;' +
|
||||
'const o=y("p");o.innerHTML=`Git: ${a.link().outerHTML}`,' +
|
||||
'e.appendChild(y("div",[y("div|class:version",[_t.render(),' +
|
||||
'y("div|class:version-details",[y("h1:MyStart|class:version-app-name"),' +
|
||||
'y("p:Version 1.0.1|class:version-number")])]),y("hr"),s,o,y("div|id:mystart-autostart-row,class:mystart-autostart-row")]))';
|
||||
mainJs = mainJs.slice(0, i) + aboutBody + mainJs.slice(j + aEndMarker.length);
|
||||
|
||||
// --- 2) Rename branding (visible text + storage keys) consistently ---
|
||||
const rename = (s) => s.split('nightTab').join(APPNAME);
|
||||
mainJs = rename(mainJs);
|
||||
initJs = rename(initJs);
|
||||
|
||||
// --- 3) Import: accept BOTH original nightTab backups and MyStart backups ---
|
||||
// After rename the two validation gates only accept the "MyStart" marker key;
|
||||
// re-add acceptance of the original "nightTab" marker so old backups import too.
|
||||
const importGates = [
|
||||
['JSON.parse(t).MyStart||JSON.parse(t)[nt.toLowerCase()]',
|
||||
'JSON.parse(t).MyStart||JSON.parse(t).nightTab||JSON.parse(t)[nt.toLowerCase()]'],
|
||||
['JSON.parse(r.target.result).MyStart||JSON.parse(r.target.result)[nt.toLowerCase()]',
|
||||
'JSON.parse(r.target.result).MyStart||JSON.parse(r.target.result).nightTab||JSON.parse(r.target.result)[nt.toLowerCase()]'],
|
||||
];
|
||||
for (const [from, to] of importGates) {
|
||||
if (!mainJs.includes(from)) throw new Error('import gate not found: ' + from);
|
||||
mainJs = mainJs.replace(from, to);
|
||||
}
|
||||
|
||||
// --- 4) German UI: translate the DISPLAY of menu tabs/sub-tabs/headers only.
|
||||
// The underlying name stays English because it is used as a routing key
|
||||
// (makeId = first word lowercased). __TR maps display text, keyed by that id.
|
||||
const menuMap = {
|
||||
theme:'Design', layout:'Layout', header:'Kopfzeile', bookmark:'Lesezeichen',
|
||||
group:'Gruppe', toolbar:'Werkzeugleiste', data:'Daten', mystart:'MyStart',
|
||||
preset:'Vorlage', saved:'Gespeichert', style:'Stil', colour:'Farbe',
|
||||
accent:'Akzent', font:'Schrift', radius:'Radius', shadow:'Schatten',
|
||||
shade:'Schattierung', opacity:'Deckkraft', background:'Hintergrund',
|
||||
search:'Suche', scaling:'Skalierung', area:'Bereich', padding:'Innenabstand',
|
||||
gutter:'Abstand', alignment:'Ausrichtung', page:'Seite', greeting:'Begrüßung',
|
||||
transitional:'Übergangswörter', clock:'Uhr', date:'Datum', general:'Allgemein',
|
||||
orientation:'Ausrichtung', sort:'Sortierung', name:'Name', size:'Größe',
|
||||
location:'Ort', position:'Position', controls:'Steuerung',
|
||||
restore:'Wiederherstellen', backup:'Sichern', clear:'Löschen',
|
||||
};
|
||||
const trInfra =
|
||||
'window.__MT=' + JSON.stringify(menuMap) + ';' +
|
||||
'window.__TR=function(s){if(s==null)return s;var k=String(s).split(" ")[0].toLowerCase();return window.__MT[k]||s;};';
|
||||
|
||||
// Autostart toggle: renders a CUSTOM slider switch into the About page's
|
||||
// #mystart-autostart-row (native checkboxes are hidden by nightTab's CSS:
|
||||
// opacity:0/position:absolute/pointer-events:none). Talks to the native host
|
||||
// via postMessage; the host reads/writes the HKCU Run key.
|
||||
const autostartJs = `(function(){
|
||||
var A={enabled:false,supported:!!(window.chrome&&window.chrome.webview)};
|
||||
window.__mystartAutostart=A;
|
||||
function paint(){
|
||||
var tr=document.getElementById('mystart-autostart-track');
|
||||
var kn=document.getElementById('mystart-autostart-knob');
|
||||
if(!tr||!kn)return;
|
||||
tr.style.background=A.enabled?'#2ea043':'#565d68';
|
||||
kn.style.left=A.enabled?'23px':'3px';
|
||||
}
|
||||
if(A.supported){
|
||||
window.chrome.webview.addEventListener('message',function(ev){
|
||||
var d=ev.data;if(d&&d.type==='autostart'){A.enabled=!!d.enabled;paint();}
|
||||
});
|
||||
}
|
||||
function render(row){
|
||||
var wrap=document.createElement('div');
|
||||
wrap.style.cssText='display:flex;align-items:center;gap:10px;margin-top:18px;cursor:pointer;user-select:none;';
|
||||
var track=document.createElement('div');
|
||||
track.id='mystart-autostart-track';
|
||||
track.style.cssText='position:relative;width:46px;height:26px;border-radius:13px;background:#565d68;flex:0 0 auto;transition:background .15s;box-sizing:border-box;';
|
||||
var knob=document.createElement('div');
|
||||
knob.id='mystart-autostart-knob';
|
||||
knob.style.cssText='position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:#fff;transition:left .15s;box-shadow:0 1px 2px rgba(0,0,0,.4);box-sizing:border-box;';
|
||||
track.appendChild(knob);
|
||||
var txt=document.createElement('span');
|
||||
txt.textContent='Mit Windows starten (minimiert)';
|
||||
if(!A.supported){wrap.style.opacity='0.5';wrap.style.cursor='default';wrap.title='Nur in der MyStart-App verfügbar.';}
|
||||
wrap.appendChild(track);wrap.appendChild(txt);row.appendChild(wrap);
|
||||
paint();
|
||||
wrap.addEventListener('click',function(){
|
||||
if(!A.supported)return;
|
||||
A.enabled=!A.enabled;paint();
|
||||
try{window.chrome.webview.postMessage({type:'autostart-set',value:A.enabled});}catch(e){}
|
||||
});
|
||||
if(A.supported){try{window.chrome.webview.postMessage({type:'autostart-get'});}catch(e){}}
|
||||
}
|
||||
function ensure(){
|
||||
var row=document.getElementById('mystart-autostart-row');
|
||||
if(row&&!document.getElementById('mystart-autostart-track'))render(row);
|
||||
}
|
||||
new MutationObserver(ensure).observe(document.documentElement,{childList:true,subtree:true});
|
||||
ensure();
|
||||
})();`;
|
||||
|
||||
// Frameless-window controls (minimize / maximize-restore / close) in the top-right
|
||||
// corner. Only shown inside the app (WebView2 host); they postMessage to the host.
|
||||
const windowControlsJs = `(function(){
|
||||
if(!(window.chrome&&window.chrome.webview))return;
|
||||
function send(t){try{window.chrome.webview.postMessage({type:t});}catch(e){}}
|
||||
function mk(glyph,title,type,isClose){
|
||||
var b=document.createElement('div');
|
||||
b.textContent=glyph;b.title=title;
|
||||
b.style.cssText='width:44px;height:30px;display:flex;align-items:center;justify-content:center;font-family:"Segoe UI",system-ui,sans-serif;font-size:14px;line-height:1;color:#d0d4db;cursor:pointer;transition:background .1s,color .1s;-webkit-user-select:none;user-select:none;';
|
||||
b.onmouseenter=function(){b.style.background=isClose?'#e81123':'rgba(255,255,255,0.18)';b.style.color='#fff';};
|
||||
b.onmouseleave=function(){b.style.background='transparent';b.style.color='#d0d4db';};
|
||||
b.onclick=function(){send(type);};
|
||||
return b;
|
||||
}
|
||||
function mkGrip(){
|
||||
var g=document.createElement('div');
|
||||
g.title='Fenster verschieben (ziehen) — oder Alt + ziehen';
|
||||
g.style.cssText='width:34px;height:30px;display:flex;align-items:center;justify-content:center;color:#9aa0aa;cursor:move;-webkit-user-select:none;user-select:none;';
|
||||
g.innerHTML='<svg width="10" height="16" viewBox="0 0 10 16" fill="currentColor"><circle cx="2" cy="2" r="1.4"/><circle cx="8" cy="2" r="1.4"/><circle cx="2" cy="8" r="1.4"/><circle cx="8" cy="8" r="1.4"/><circle cx="2" cy="14" r="1.4"/><circle cx="8" cy="14" r="1.4"/></svg>';
|
||||
g.onmouseenter=function(){g.style.color='#fff';};
|
||||
g.onmouseleave=function(){g.style.color='#9aa0aa';};
|
||||
g.addEventListener('mousedown',function(ev){if(ev.button!==0)return;ev.preventDefault();send('window-drag');});
|
||||
return g;
|
||||
}
|
||||
function add(){
|
||||
if(!document.body||document.getElementById('mystart-winctrls'))return;
|
||||
var bar=document.createElement('div');
|
||||
bar.id='mystart-winctrls';
|
||||
bar.style.cssText='position:fixed;top:0;right:0;display:flex;align-items:center;z-index:2147483647;';
|
||||
bar.appendChild(mkGrip());
|
||||
bar.appendChild(mk('\\u2013','Minimieren','window-min',false));
|
||||
bar.appendChild(mk('\\u25A1','Maximieren / Wiederherstellen','window-max',false));
|
||||
bar.appendChild(mk('\\u2715','Schließen','window-close',true));
|
||||
document.body.appendChild(bar);
|
||||
}
|
||||
if(document.body)add();else document.addEventListener('DOMContentLoaded',add);
|
||||
new MutationObserver(function(){if(!document.getElementById('mystart-winctrls'))add();}).observe(document.documentElement,{childList:true,subtree:true});
|
||||
// Alt + left-drag anywhere -> move the window (non-blocking).
|
||||
document.addEventListener('mousedown',function(ev){
|
||||
if(ev.button===0&&ev.altKey){ev.preventDefault();send('window-drag');}
|
||||
},true);
|
||||
// Edge/corner resize: the WebView fills the whole window, so the OS never
|
||||
// sees the real window border to hit-test for a resize drag -- every mouse
|
||||
// event lands in the page first. Watch the pointer ourselves near the
|
||||
// viewport edges and hand off to the native resize loop, same trick as
|
||||
// the drag grip above.
|
||||
var RM=6; // px from the true edge that counts as a resize zone
|
||||
var CURSOR={n:'ns-resize',s:'ns-resize',e:'ew-resize',w:'ew-resize',
|
||||
ne:'nesw-resize',sw:'nesw-resize',nw:'nwse-resize',se:'nwse-resize'};
|
||||
function edgeAt(x,y){
|
||||
var w=window.innerWidth,h=window.innerHeight;
|
||||
var l=x<=RM,r=x>=w-RM,t=y<=RM,b=y>=h-RM;
|
||||
if(t&&l)return'nw';if(t&&r)return'ne';if(b&&l)return'sw';if(b&&r)return'se';
|
||||
if(l)return'w';if(r)return'e';if(t)return'n';if(b)return's';
|
||||
return null;
|
||||
}
|
||||
document.addEventListener('mousemove',function(ev){
|
||||
if(ev.buttons)return; // an active drag (e.g. scrollbar) is in progress -> leave it alone
|
||||
var onCtrls=ev.target.closest&&ev.target.closest('#mystart-winctrls');
|
||||
var edge=onCtrls?null:edgeAt(ev.clientX,ev.clientY);
|
||||
document.documentElement.style.cursor=edge?CURSOR[edge]:'';
|
||||
},true);
|
||||
document.addEventListener('mousedown',function(ev){
|
||||
if(ev.button!==0)return;
|
||||
if(ev.target.closest&&ev.target.closest('#mystart-winctrls'))return;
|
||||
var edge=edgeAt(ev.clientX,ev.clientY);
|
||||
if(edge){ev.preventDefault();send2('window-resize',{edge:edge});}
|
||||
},true);
|
||||
document.addEventListener('mouseleave',function(){document.documentElement.style.cursor='';},true);
|
||||
function send2(t,extra){try{window.chrome.webview.postMessage(Object.assign({type:t},extra));}catch(e){}}
|
||||
})();`;
|
||||
|
||||
mainJs = trInfra + autostartJs + windowControlsJs + mainJs;
|
||||
|
||||
const trPatches = [
|
||||
// panel header (top-level AND sub, both go through element.header)
|
||||
['y("h1:"+e+"|class:menu-item-header-text")',
|
||||
'y("h1:"+window.__TR(e)+"|class:menu-item-header-text")'],
|
||||
// top-level nav tab label
|
||||
['new Fe({text:e.name,style:["link"],block:!0,classList:["menu-nav-tab"]',
|
||||
'new Fe({text:window.__TR(e.name),style:["link"],block:!0,classList:["menu-nav-tab"]'],
|
||||
// sub-level nav label (href keeps makeId -> English routing key)
|
||||
['y("a:"+e+"|href:#menu-content-item-"+this.makeId(e)',
|
||||
'y("a:"+window.__TR(e)+"|href:#menu-content-item-"+this.makeId(e)'],
|
||||
];
|
||||
for (const [from, to] of trPatches) {
|
||||
if (!mainJs.includes(from)) throw new Error('translate patch not found: ' + from);
|
||||
mainJs = mainJs.replace(from, to);
|
||||
}
|
||||
|
||||
// --- 5) Translate safe, unique display strings (search box, greeting, key texts).
|
||||
// Tolerant: each is applied only if the exact literal is present. Structural
|
||||
// names and icon labels are deliberately NOT touched.
|
||||
const dict = [
|
||||
// search box placeholder (base + engine name is appended after it)
|
||||
['?"Find bookmarks or search":"Search"', '?"Lesezeichen finden oder suchen mit":"Suchen mit"'],
|
||||
// greeting words
|
||||
['"Good morning"', '"Guten Morgen"'],
|
||||
['"Good afternoon"', '"Guten Tag"'],
|
||||
['"Good evening"', '"Guten Abend"'],
|
||||
['"Good night"', '"Gute Nacht"'],
|
||||
['"Hello"', '"Hallo"'],
|
||||
['"Welcome"', '"Willkommen"'],
|
||||
['"Greetings"', '"Grüße"'],
|
||||
// Data panel / confirmation descriptions (post-rename -> contain MyStart)
|
||||
['"Restore a previously exported MyStart backup."', '"Eine zuvor exportierte MyStart-Sicherung wiederherstellen."'],
|
||||
['"Restoring from a MyStart backup"', '"Aus einer MyStart-Sicherung wiederherstellen"'],
|
||||
['"Clear all data to reset MyStart to the default state."', '"Alle Daten löschen, um MyStart auf den Ausgangszustand zurückzusetzen."'],
|
||||
['"Clear MyStart data except bookmarks?"', '"MyStart-Daten außer Lesezeichen löschen?"'],
|
||||
['"Or drop a MyStart backup file here."', '"Oder ziehe eine MyStart-Sicherungsdatei hierher."'],
|
||||
// universal button
|
||||
['text:"Add"', 'text:"Hinzufügen"'],
|
||||
];
|
||||
for (const [from, to] of dict) {
|
||||
if (mainJs.includes(from)) mainJs = mainJs.split(from).join(to);
|
||||
}
|
||||
|
||||
// --- 6) Full German UI: translate every remaining visible control/label/tooltip.
|
||||
// Applied ONLY to value positions (:"...") so routing names (name:"Theme",
|
||||
// sub:["Style"], case"layout") and the icon database stay untouched. The button
|
||||
// behaviour lives in func()/keys, never in the display text, so this is safe.
|
||||
const chrome = Object.entries(JSON.parse(fs.readFileSync(path.join(__dirname, 'lang', 'de.json'), 'utf8')));
|
||||
const _unusedChrome = [
|
||||
['Add', 'Hinzufügen'],
|
||||
['Add 10 random bookmarks', '10 zufällige Lesezeichen hinzufügen'],
|
||||
['Add a group', 'Gruppe hinzufügen'],
|
||||
['Add a new Bookmark', 'Neues Lesezeichen hinzufügen'],
|
||||
['Add a new Group', 'Neue Gruppe hinzufügen'],
|
||||
['Add unique accent to each Bookmark', 'Jedem Lesezeichen eigene Akzentfarbe geben'],
|
||||
['Adjust Visual Element position', 'Position des Symbols anpassen'],
|
||||
['Area alignment', 'Ausrichtung des Bereichs'],
|
||||
['Bold', 'Fett'],
|
||||
['Bookmark area alignment', 'Ausrichtung des Lesezeichen-Bereichs'],
|
||||
['Bookmark area background colour', 'Hintergrundfarbe des Lesezeichen-Bereichs'],
|
||||
['By icon', 'Nach Icon'],
|
||||
['By letter', 'Nach Buchstabe'],
|
||||
['By name', 'Nach Name'],
|
||||
['Clear all data', 'Alle Daten löschen'],
|
||||
['Clear all except bookmarks', 'Alles außer Lesezeichen löschen'],
|
||||
['Clear all MyStart data?', 'Alle MyStart-Daten löschen?'],
|
||||
['Clear search', 'Suche leeren'],
|
||||
['Close settings menu', 'Einstellungen schließen'],
|
||||
['Collapse this Group', 'Diese Gruppe einklappen'],
|
||||
['Copy to clipboard', 'In die Zwischenablage kopieren'],
|
||||
['Drag bookmark to reorder', 'Lesezeichen ziehen zum Umsortieren'],
|
||||
['Drag group to reorder', 'Gruppe ziehen zum Umsortieren'],
|
||||
['Drag header item to reorder', 'Kopfzeilen-Element ziehen zum Umsortieren'],
|
||||
['Edit saved themes', 'Gespeicherte Designs bearbeiten'],
|
||||
['Edit this bookmark', 'Dieses Lesezeichen bearbeiten'],
|
||||
['Edit this group', 'Diese Gruppe bearbeiten'],
|
||||
['Edit this saved theme', 'Dieses gespeicherte Design bearbeiten'],
|
||||
['Edit unnamed bookmark', 'Unbenanntes Lesezeichen bearbeiten'],
|
||||
['Edit unnamed group', 'Unbenannte Gruppe bearbeiten'],
|
||||
['Enter edit bookmark mode', 'Bearbeitungsmodus für Lesezeichen'],
|
||||
['Export data', 'Daten exportieren'],
|
||||
['Google Font', 'Google-Schriftart'],
|
||||
['Google font name', 'Name der Google-Schriftart'],
|
||||
['Group details area alignment', 'Ausrichtung des Gruppen-Detailbereichs'],
|
||||
['Header area alignment', 'Ausrichtung des Kopfzeilen-Bereichs'],
|
||||
['Header background colour', 'Hintergrundfarbe der Kopfzeile'],
|
||||
['Header item alignment', 'Ausrichtung der Kopfzeilen-Elemente'],
|
||||
['Hide all', 'Alle ausblenden'],
|
||||
['How to link to a video file.', 'So verlinkst du eine Videodatei.'],
|
||||
['Import', 'Importieren'],
|
||||
['Import from clipboard', 'Aus Zwischenablage importieren'],
|
||||
['Large button', 'Große Schaltfläche'],
|
||||
['Layout Direction', 'Layout-Richtung'],
|
||||
['Layout background colour', 'Hintergrundfarbe des Layouts'],
|
||||
['Light', 'Dünn'],
|
||||
['Line button', 'Linien-Schaltfläche'],
|
||||
['Link button', 'Link-Schaltfläche'],
|
||||
['Medium button', 'Mittlere Schaltfläche'],
|
||||
['More controls', 'Mehr Optionen'],
|
||||
['Move this bookmark left', 'Dieses Lesezeichen nach links'],
|
||||
['Move this bookmark right', 'Dieses Lesezeichen nach rechts'],
|
||||
['Move this group down', 'Diese Gruppe nach unten'],
|
||||
['Move this group right', 'Diese Gruppe nach rechts'],
|
||||
['Move this group up', 'Diese Gruppe nach oben'],
|
||||
['Name hide', 'Name ausblenden'],
|
||||
['Name show', 'Name anzeigen'],
|
||||
['New Bookmark', 'Neues Lesezeichen'],
|
||||
['New Group', 'Neue Gruppe'],
|
||||
['New Tab', 'Neuer Tab'],
|
||||
['Only icons', 'Nur Icons'],
|
||||
['Only images', 'Nur Bilder'],
|
||||
['Only letters', 'Nur Buchstaben'],
|
||||
['Open all Bookmarks in this Group', 'Alle Lesezeichen dieser Gruppe öffnen'],
|
||||
['Open settings menu', 'Einstellungen öffnen'],
|
||||
['Random Group name', 'Zufälliger Gruppenname'],
|
||||
['Random colour', 'Zufällige Farbe'],
|
||||
['Random theme name', 'Zufälliger Designname'],
|
||||
['Randomise now', 'Jetzt zufällig'],
|
||||
['Regular', 'Normal'],
|
||||
['Remove', 'Entfernen'],
|
||||
['Remove all accent overrides', 'Alle Akzent-Überschreibungen entfernen'],
|
||||
['Remove icon', 'Icon entfernen'],
|
||||
['Remove this bookmark', 'Dieses Lesezeichen entfernen'],
|
||||
['Remove this group', 'Diese Gruppe entfernen'],
|
||||
['Remove this saved theme', 'Dieses gespeicherte Design entfernen'],
|
||||
['Remove unnamed bookmark', 'Unbenanntes Lesezeichen entfernen'],
|
||||
['Reset to default', 'Auf Standard zurücksetzen'],
|
||||
['Ring button', 'Ring-Schaltfläche'],
|
||||
['Save', 'Speichern'],
|
||||
['Save current theme', 'Aktuelles Design speichern'],
|
||||
['Scrollbar', 'Bildlaufleiste'],
|
||||
['Search Bookmarks or', 'Lesezeichen durchsuchen oder'],
|
||||
['Search box size', 'Größe des Suchfelds'],
|
||||
['Search box width', 'Breite des Suchfelds'],
|
||||
['Search engine', 'Suchmaschine'],
|
||||
['Search engine name', 'Name der Suchmaschine'],
|
||||
['Search text alignment', 'Textausrichtung der Suche'],
|
||||
['Show all', 'Alle anzeigen'],
|
||||
['Small button', 'Kleine Schaltfläche'],
|
||||
['Start of the week', 'Wochenbeginn'],
|
||||
['Toolbar position', 'Position der Werkzeugleiste'],
|
||||
['Visual Element and Name alignment', 'Ausrichtung von Symbol und Name'],
|
||||
['Why has this changed?', 'Warum hat sich das geändert?'],
|
||||
['Word length', 'Wortlänge'],
|
||||
['Wording', 'Formulierung'],
|
||||
['You can restore all or parts of a backup file. The following data will be restored:',
|
||||
'Du kannst eine Sicherung ganz oder teilweise wiederherstellen. Folgende Daten werden wiederhergestellt:'],
|
||||
// placeholders
|
||||
['Example', 'Beispiel'],
|
||||
['Example group', 'Beispielgruppe'],
|
||||
['Example theme', 'Beispiel-Design'],
|
||||
['FontAwesome Brands or Icons', 'FontAwesome Brands oder Icons'],
|
||||
['Hex code', 'Hex-Code'],
|
||||
['Nickname, alias or superhero name', 'Spitzname, Alias oder Heldenname'],
|
||||
];
|
||||
// Locate the FontAwesome icon array (mr=[{name:"500px"...]) so we NEVER touch it.
|
||||
const iconStart = mainJs.indexOf('mr=[{name:"500px"');
|
||||
let iconEnd = -1;
|
||||
if (iconStart >= 0) {
|
||||
const bracket = mainJs.indexOf('[', iconStart);
|
||||
let depth = 0;
|
||||
for (let i = bracket; i < mainJs.length; i++) {
|
||||
const c = mainJs[i];
|
||||
if (c === '[') depth++;
|
||||
else if (c === ']') { depth--; if (depth === 0) { iconEnd = i + 1; break; } }
|
||||
else if (c === '"') { i++; while (i < mainJs.length && mainJs[i] !== '"') { if (mainJs[i] === '\\') i++; i++; } }
|
||||
}
|
||||
}
|
||||
if (iconStart < 0 || iconEnd < 0) throw new Error('icon region not found — aborting translation');
|
||||
|
||||
const before = mainJs.slice(0, iconStart);
|
||||
const iconRegion = mainJs.slice(iconStart, iconEnd);
|
||||
const after = mainJs.slice(iconEnd);
|
||||
|
||||
// Only translate genuine DISPLAY properties, and only outside the icon data.
|
||||
const displayProps = ['labelText', 'text', 'description', 'label', 'title', 'placeholder', 'heading', 'successText', 'tabText'];
|
||||
const jsEsc = (v) => v.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||
const translateChrome = (s) => {
|
||||
for (const [en, de] of chrome) {
|
||||
const deEsc = jsEsc(de);
|
||||
for (const p of displayProps) {
|
||||
const from = p + ':"' + en + '"';
|
||||
if (s.includes(from)) s = s.split(from).join(p + ':"' + deEsc + '"');
|
||||
}
|
||||
}
|
||||
return s;
|
||||
};
|
||||
mainJs = translateChrome(before) + iconRegion + translateChrome(after);
|
||||
|
||||
// --- 7) Long help/feedback/description sentences (y-DSL `y("p:..")`, text:[..] arrays,
|
||||
// and description:"..."). Safe via exact match because these strings are long & unique.
|
||||
const de2 = Object.entries(JSON.parse(fs.readFileSync(path.join(__dirname, 'lang', 'de2.json'), 'utf8')));
|
||||
for (const [en, de] of de2) {
|
||||
const deEsc = jsEsc(de);
|
||||
// quoted literal (arrays, description:"...", any "..." occurrence)
|
||||
mainJs = mainJs.split('"' + en + '"').join('"' + deEsc + '"');
|
||||
// y-DSL with trailing attributes: y("p:TEXT|class:..")
|
||||
mainJs = mainJs.split(':' + en + '|').join(':' + deEsc + '|');
|
||||
// y-DSL without attributes: y("p:TEXT")
|
||||
mainJs = mainJs.split(':' + en + '"').join(':' + deEsc + '"');
|
||||
}
|
||||
|
||||
// --- 8) Two font-field hints that contain escaped quotes in the source literal. ---
|
||||
const fontHints = [
|
||||
['Clear the field to use the default font "Fjalla One".', 'Feld leeren, um die Standardschrift "Fjalla One" zu verwenden.'],
|
||||
['Clear the field to use the default font "Open Sans".', 'Feld leeren, um die Standardschrift "Open Sans" zu verwenden.'],
|
||||
];
|
||||
for (const [en, de] of fontHints) {
|
||||
if (mainJs.includes(en)) mainJs = mainJs.split(en).join(de);
|
||||
}
|
||||
|
||||
const favSvg = fs.readFileSync(path.join(root, 'icon/favicon.svg'));
|
||||
const favData = 'data:image/svg+xml;base64,' + favSvg.toString('base64');
|
||||
|
||||
const html = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no"><title>${APPNAME}</title><link rel="icon" type="image/svg+xml" class="favicon" href="${favData}"/><style media="screen">html,body {background-color: rgb(0, 0, 0);}@media (prefers-color-scheme: dark) {html,body {background-color: rgb(0, 0, 0);}}@media (prefers-color-scheme: light) {html,body {background-color: rgb(255, 255, 255);}}</style>
|
||||
<style>${css}</style>
|
||||
<style>/* Scrollbalken ans dunkle MyStart-Design anpassen (schlank, dunkel, ohne Pfeile) */
|
||||
::-webkit-scrollbar{width:10px;height:10px;}
|
||||
::-webkit-scrollbar-track{background:transparent;}
|
||||
::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,0.22);border-radius:8px;border:2px solid transparent;background-clip:padding-box;}
|
||||
::-webkit-scrollbar-thumb:hover{background-color:rgba(255,255,255,0.38);background-clip:padding-box;}
|
||||
::-webkit-scrollbar-button{display:none;height:0;width:0;}
|
||||
::-webkit-scrollbar-corner{background:transparent;}</style>
|
||||
<script>${initJs}</script>
|
||||
</head><body>
|
||||
<script>${mainJs}</script>
|
||||
</body></html>`;
|
||||
|
||||
fs.writeFileSync(out, html);
|
||||
const kb = (fs.statSync(out).size / 1024).toFixed(0);
|
||||
console.log('Written: ' + out + ' (' + kb + ' KB) [Support/Coffee removed, renamed to ' + APPNAME + ']');
|
||||
338
lang/de.json
Normal file
@@ -0,0 +1,338 @@
|
||||
{
|
||||
"24 hours": "24 Stunden",
|
||||
"Accent": "Akzent",
|
||||
"Accent colour": "Akzentfarbe",
|
||||
"Add": "Hinzufügen",
|
||||
"Add 10 random bookmarks": "10 zufällige Lesezeichen hinzufügen",
|
||||
"Add a group": "Gruppe hinzufügen",
|
||||
"Add a new Bookmark": "Neues Lesezeichen hinzufügen",
|
||||
"Add a new Group": "Neue Gruppe hinzufügen",
|
||||
"Add to existing bookmarks": "Zu vorhandenen Lesezeichen hinzufügen",
|
||||
"Add unique accent to each Bookmark": "Jedem Lesezeichen eigene Akzentfarbe geben",
|
||||
"Address": "Adresse",
|
||||
"Adjust Visual Element position": "Position des Symbols anpassen",
|
||||
"Align horizontal": "Horizontal ausrichten",
|
||||
"Align vertical": "Vertikal ausrichten",
|
||||
"All opacity": "Gesamt-Deckkraft",
|
||||
"Any": "Beliebig",
|
||||
"Apply Layout to other Bookmarks": "Layout auf andere Lesezeichen anwenden",
|
||||
"Apply Theme to other Bookmarks": "Design auf andere Lesezeichen anwenden",
|
||||
"Area alignment": "Ausrichtung des Bereichs",
|
||||
"Arrange the Visual Element and Name side by side.": "Symbol und Name nebeneinander anordnen.",
|
||||
"As number": "Als Zahl",
|
||||
"As word": "Als Wort",
|
||||
"Auto": "Automatisch",
|
||||
"Auto change Accent hue": "Akzent-Farbton automatisch ändern",
|
||||
"Auto width": "Automatische Breite",
|
||||
"Automatic": "Automatisch",
|
||||
"backed up your data?": "deine Daten gesichert?",
|
||||
"Background blur": "Hintergrund-Unschärfe",
|
||||
"Background by Accent": "Hintergrund nach Akzent",
|
||||
"Background by Theme": "Hintergrund nach Design",
|
||||
"Background colour": "Hintergrundfarbe",
|
||||
"Background gradient angle": "Winkel des Hintergrund-Verlaufs",
|
||||
"Background gradient end": "Ende des Hintergrund-Verlaufs",
|
||||
"Background gradient start": "Beginn des Hintergrund-Verlaufs",
|
||||
"Background image URL": "Hintergrundbild-URL",
|
||||
"Background opacity": "Hintergrund-Deckkraft",
|
||||
"Background video URL": "Hintergrundvideo-URL",
|
||||
"Block": "Block",
|
||||
"Blue": "Blau",
|
||||
"Blur": "Unschärfe",
|
||||
"Bold": "Fett",
|
||||
"Bookmark": "Lesezeichen",
|
||||
"Bookmark area alignment": "Ausrichtung des Lesezeichen-Bereichs",
|
||||
"Bookmark area background colour": "Hintergrundfarbe des Lesezeichen-Bereichs",
|
||||
"Bookmark area width": "Breite des Lesezeichen-Bereichs",
|
||||
"Bookmark border": "Lesezeichen-Rahmen",
|
||||
"Bookmark icon": "Lesezeichen-Icon",
|
||||
"Bookmark image": "Lesezeichen-Bild",
|
||||
"Bookmark letter": "Lesezeichen-Buchstabe",
|
||||
"Bookmark name": "Lesezeichen-Name",
|
||||
"Bookmark size": "Lesezeichen-Größe",
|
||||
"Bookmark tile to span across two columns.": "Lesezeichen-Kachel über zwei Spalten spannen.",
|
||||
"Bookmarks": "Lesezeichen",
|
||||
"Bookmarks then Group details": "Lesezeichen, dann Gruppendetails",
|
||||
"Bookmarks then Header": "Lesezeichen, dann Kopfzeile",
|
||||
"Border": "Rahmen",
|
||||
"Bottom": "Unten",
|
||||
"Bottom Center": "Unten Mitte",
|
||||
"Bottom Left": "Unten Links",
|
||||
"Bottom left": "Unten links",
|
||||
"Bottom Right": "Unten Rechts",
|
||||
"Bottom right": "Unten rechts",
|
||||
"By icon": "Nach Icon",
|
||||
"By letter": "Nach Buchstabe",
|
||||
"By name": "Nach Name",
|
||||
"Center": "Mitte",
|
||||
"Center Center": "Mitte Mitte",
|
||||
"Center Left": "Mitte Links",
|
||||
"Center Right": "Mitte Rechts",
|
||||
"Change delay": "Verzögerung ändern",
|
||||
"Change steps": "Schritte ändern",
|
||||
"Clear all data": "Alle Daten löschen",
|
||||
"Clear all except bookmarks": "Alles außer Lesezeichen löschen",
|
||||
"Clear all MyStart data?": "Alle MyStart-Daten löschen?",
|
||||
"Clear MyStart data except bookmarks?": "MyStart-Daten außer Lesezeichen löschen?",
|
||||
"Clear search": "Suche leeren",
|
||||
"Close settings menu": "Einstellungen schließen",
|
||||
"Collapse this Group": "Diese Gruppe einklappen",
|
||||
"Colour": "Farbe",
|
||||
"Contrast end": "Kontrast-Ende",
|
||||
"Contrast range": "Kontrast-Bereich",
|
||||
"Contrast start": "Kontrast-Beginn",
|
||||
"Copy to clipboard": "In die Zwischenablage kopieren",
|
||||
"Corners radius": "Eckenradius",
|
||||
"Custom": "Benutzerdefiniert",
|
||||
"Custom Accent": "Eigener Akzent",
|
||||
"Custom colour": "Eigene Farbe",
|
||||
"Custom greeting text": "Eigener Begrüßungstext",
|
||||
"Custom width": "Eigene Breite",
|
||||
"Dark": "Dunkel",
|
||||
"Dark mode": "Dunkler Modus",
|
||||
"Date / Month": "Datum / Monat",
|
||||
"Define how wide the Search box should be inside the Header Area.": "Lege fest, wie breit das Suchfeld im Kopfbereich sein soll.",
|
||||
"Display an Image or video Background on this Bookmark tile.": "Ein Bild oder Video als Hintergrund dieser Lesezeichen-Kachel anzeigen.",
|
||||
"Display font": "Anzeige-Schriftart",
|
||||
"Display Letters, Icon or an Image on this Bookmark hexagon.": "Buchstaben, Icon oder ein Bild auf diesem Lesezeichen anzeigen.",
|
||||
"Divider between Header and Bookmark area": "Trennlinie zwischen Kopf- und Lesezeichen-Bereich",
|
||||
"Drag bookmark to reorder": "Lesezeichen ziehen zum Umsortieren",
|
||||
"Drag group to reorder": "Gruppe ziehen zum Umsortieren",
|
||||
"Drag header item to reorder": "Kopfzeilen-Element ziehen zum Umsortieren",
|
||||
"Edit saved themes": "Gespeicherte Designs bearbeiten",
|
||||
"Edit this bookmark": "Dieses Lesezeichen bearbeiten",
|
||||
"Edit this group": "Diese Gruppe bearbeiten",
|
||||
"Edit this saved theme": "Dieses gespeicherte Design bearbeiten",
|
||||
"Edit unnamed bookmark": "Unbenanntes Lesezeichen bearbeiten",
|
||||
"Edit unnamed group": "Unbenannte Gruppe bearbeiten",
|
||||
"Effects may not be visible if Theme Shadow is set to 0.": "Effekte sind evtl. nicht sichtbar, wenn der Design-Schatten auf 0 steht.",
|
||||
"Enter edit bookmark mode": "Bearbeitungsmodus für Lesezeichen",
|
||||
"Example": "Beispiel",
|
||||
"Example group": "Beispielgruppe",
|
||||
"Example theme": "Beispiel-Design",
|
||||
"Existing Group": "Vorhandene Gruppe",
|
||||
"Export data": "Daten exportieren",
|
||||
"Favicon URL": "Favicon-URL",
|
||||
"Follow the system Light or Dark mode.": "Dem hellen oder dunklen Systemmodus folgen.",
|
||||
"Font weight": "Schriftstärke",
|
||||
"FontAwesome Brands or Icons": "FontAwesome Brands oder Icons",
|
||||
"Force on to a new line and seperate from other Header items.": "In eine neue Zeile zwingen und von anderen Kopf-Elementen trennen.",
|
||||
"Format": "Format",
|
||||
"Global size": "Gesamtgröße",
|
||||
"Google Font": "Google-Schriftart",
|
||||
"Google font name": "Name der Google-Schriftart",
|
||||
"Gradient": "Verlauf",
|
||||
"Grayscale": "Graustufen",
|
||||
"Green": "Grün",
|
||||
"Group": "Gruppe",
|
||||
"Group details area alignment": "Ausrichtung des Gruppen-Detailbereichs",
|
||||
"Group details then Bookmarks": "Gruppendetails, dann Lesezeichen",
|
||||
"Group name": "Gruppenname",
|
||||
"Group toolbar": "Gruppen-Werkzeugleiste",
|
||||
"Group toolbar size": "Größe der Gruppen-Werkzeugleiste",
|
||||
"Grow on Bookmark hover": "Beim Überfahren vergrößern",
|
||||
"Gutter": "Abstand",
|
||||
"Header area alignment": "Ausrichtung des Kopfbereichs",
|
||||
"Header area background colour": "Hintergrundfarbe des Kopfbereichs",
|
||||
"Header area width": "Breite des Kopfbereichs",
|
||||
"Header background colour": "Hintergrundfarbe der Kopfzeile",
|
||||
"Header item alignment": "Ausrichtung der Kopf-Elemente",
|
||||
"Header then Bookmarks": "Kopfzeile, dann Lesezeichen",
|
||||
"Hex code": "Hex-Code",
|
||||
"Hidden": "Ausgeblendet",
|
||||
"Hide all": "Alle ausblenden",
|
||||
"Horizontal": "Horizontal",
|
||||
"How to link to a video file.": "So verlinkst du eine Videodatei.",
|
||||
"Hue": "Farbton",
|
||||
"Icon": "Icon",
|
||||
"Image": "Bild",
|
||||
"Import": "Importieren",
|
||||
"Import from clipboard": "Aus Zwischenablage importieren",
|
||||
"Import from file": "Aus Datei importieren",
|
||||
"In a corner": "In einer Ecke",
|
||||
"In the Header": "In der Kopfzeile",
|
||||
"Italic": "Kursiv",
|
||||
"Large button": "Große Schaltfläche",
|
||||
"Layout": "Layout",
|
||||
"Layout area width": "Breite des Layout-Bereichs",
|
||||
"Layout background colour": "Hintergrundfarbe des Layouts",
|
||||
"Layout Direction": "Layout-Richtung",
|
||||
"Left": "Links",
|
||||
"Letter": "Buchstabe",
|
||||
"Light": "Dünn",
|
||||
"Light mode": "Heller Modus",
|
||||
"Lightness": "Helligkeit",
|
||||
"Line button": "Linien-Schaltfläche",
|
||||
"Link button": "Link-Schaltfläche",
|
||||
"List": "Liste",
|
||||
"Long": "Lang",
|
||||
"Medium button": "Mittlere Schaltfläche",
|
||||
"Monday": "Montag",
|
||||
"Month / Date": "Monat / Datum",
|
||||
"More controls": "Mehr Optionen",
|
||||
"Move this bookmark left": "Dieses Lesezeichen nach links",
|
||||
"Move this bookmark right": "Dieses Lesezeichen nach rechts",
|
||||
"Move this group down": "Diese Gruppe nach unten",
|
||||
"Move this group right": "Diese Gruppe nach rechts",
|
||||
"Move this group up": "Diese Gruppe nach oben",
|
||||
"Name": "Name",
|
||||
"Name attribute": "Name-Attribut",
|
||||
"Name hide": "Name ausblenden",
|
||||
"Name show": "Name anzeigen",
|
||||
"Name size": "Namensgröße",
|
||||
"Name then visual element": "Name, dann Symbol",
|
||||
"New Bookmark": "Neues Lesezeichen",
|
||||
"New Group": "Neue Gruppe",
|
||||
"New line": "Neue Zeile",
|
||||
"New Tab": "Neuer Tab",
|
||||
"Nickname, alias or superhero name": "Spitzname, Alias oder Heldenname",
|
||||
"No background colour behind the Bookmark area.": "Keine Hintergrundfarbe hinter dem Lesezeichen-Bereich.",
|
||||
"No background colour behind the Header area.": "Keine Hintergrundfarbe hinter dem Kopfbereich.",
|
||||
"No background colour behind the Layout.": "Keine Hintergrundfarbe hinter dem Layout.",
|
||||
"None": "Keine",
|
||||
"Normal": "Normal",
|
||||
"Only icons": "Nur Icons",
|
||||
"Only images": "Nur Bilder",
|
||||
"Only letters": "Nur Buchstaben",
|
||||
"Opacity": "Deckkraft",
|
||||
"Open all Bookmarks in this Group": "Alle Lesezeichen dieser Gruppe öffnen",
|
||||
"Open all button will appear if there is at least one Bookmark in this Group.": "Die Schaltfläche \"Alle öffnen\" erscheint, wenn diese Gruppe mindestens ein Lesezeichen enthält.",
|
||||
"Open Bookmarks in a new tab": "Lesezeichen in neuem Tab öffnen",
|
||||
"Open Search results in a new tab": "Suchergebnisse in neuem Tab öffnen",
|
||||
"Open settings menu": "Einstellungen öffnen",
|
||||
"Or drop a MyStart backup file here.": "Oder ziehe eine MyStart-Sicherungsdatei hierher.",
|
||||
"Order the Bookmarks area to appear before the Group details area.": "Den Lesezeichen-Bereich vor dem Gruppen-Detailbereich anzeigen.",
|
||||
"Order the Bookmarks area to appear before the Header area.": "Den Lesezeichen-Bereich vor dem Kopfbereich anzeigen.",
|
||||
"Order the Group details area to appear before the Bookmarks area.": "Den Gruppen-Detailbereich vor dem Lesezeichen-Bereich anzeigen.",
|
||||
"Order the Header area to appear before the Bookmarks area.": "Den Kopfbereich vor dem Lesezeichen-Bereich anzeigen.",
|
||||
"Ordinal numbers": "Ordnungszahlen",
|
||||
"Override the Theme Accent.": "Den Design-Akzent überschreiben.",
|
||||
"Override the Theme colour.": "Die Design-Farbe überschreiben.",
|
||||
"Pastel": "Pastell",
|
||||
"Place the Name before the Visual Element.": "Den Namen vor dem Symbol platzieren.",
|
||||
"Place the Visual Element before the Name.": "Das Symbol vor dem Namen platzieren.",
|
||||
"Position": "Position",
|
||||
"Primary colour": "Primärfarbe",
|
||||
"Random Accent colour on load/refresh": "Zufällige Akzentfarbe beim Laden/Aktualisieren",
|
||||
"Random colour": "Zufällige Farbe",
|
||||
"Random Group name": "Zufälliger Gruppenname",
|
||||
"Random theme name": "Zufälliger Designname",
|
||||
"Randomise now": "Jetzt zufällig",
|
||||
"Red": "Rot",
|
||||
"Regular": "Normal",
|
||||
"Remove": "Entfernen",
|
||||
"Remove all accent overrides": "Alle Akzent-Überschreibungen entfernen",
|
||||
"Remove icon": "Icon entfernen",
|
||||
"Remove this bookmark": "Dieses Lesezeichen entfernen",
|
||||
"Remove this group": "Diese Gruppe entfernen",
|
||||
"Remove this saved theme": "Dieses gespeicherte Design entfernen",
|
||||
"Remove unnamed bookmark": "Unbenanntes Lesezeichen entfernen",
|
||||
"Replace existing bookmarks": "Vorhandene Lesezeichen ersetzen",
|
||||
"Reset to default": "Auf Standard zurücksetzen",
|
||||
"Restoring from a MyStart backup": "Aus einer MyStart-Sicherung wiederherstellen",
|
||||
"Right": "Rechts",
|
||||
"Ring button": "Ring-Schaltfläche",
|
||||
"Rotate": "Drehen",
|
||||
"Saturated": "Gesättigt",
|
||||
"Saturation": "Sättigung",
|
||||
"Save": "Speichern",
|
||||
"Save current theme": "Aktuelles Design speichern",
|
||||
"Scale": "Skalierung",
|
||||
"Scroll past end": "Über das Ende hinaus scrollen",
|
||||
"Scrollbar": "Bildlaufleiste",
|
||||
"Search": "Suche",
|
||||
"Search Bookmarks or": "Lesezeichen durchsuchen oder",
|
||||
"Search box": "Suchfeld",
|
||||
"Search box size": "Größe des Suchfelds",
|
||||
"Search box width": "Breite des Suchfelds",
|
||||
"Search box will grow to best fit available space.": "Das Suchfeld wächst, um den verfügbaren Platz optimal zu nutzen.",
|
||||
"Search engine": "Suchmaschine",
|
||||
"Search engine name": "Name der Suchmaschine",
|
||||
"Search text alignment": "Textausrichtung der Suche",
|
||||
"Separator character": "Trennzeichen",
|
||||
"Settings": "Einstellungen",
|
||||
"Shade blur": "Schattierungs-Unschärfe",
|
||||
"Shade end": "Schattierungs-Ende",
|
||||
"Shade opacity": "Schattierungs-Deckkraft",
|
||||
"Shade start": "Schattierungs-Beginn",
|
||||
"Shade start and end": "Schattierung Beginn und Ende",
|
||||
"Shadow size": "Schattengröße",
|
||||
"Short": "Kurz",
|
||||
"Short and wide Bookmark tiles.": "Kurze, breite Lesezeichen-Kacheln.",
|
||||
"Show Accent control": "Akzent-Steuerung anzeigen",
|
||||
"Show Add control": "Hinzufügen-Steuerung anzeigen",
|
||||
"Show all": "Alle anzeigen",
|
||||
"Show background": "Hintergrund anzeigen",
|
||||
"Show Bookmark line": "Lesezeichen-Linie anzeigen",
|
||||
"Show Bookmarks": "Lesezeichen anzeigen",
|
||||
"Show Collapse": "Einklappen anzeigen",
|
||||
"Show Date": "Datum anzeigen",
|
||||
"Show Day": "Wochentag anzeigen",
|
||||
"Show Edit control": "Bearbeiten-Steuerung anzeigen",
|
||||
"Show Greeting": "Begrüßung anzeigen",
|
||||
"Show Group name": "Gruppenname anzeigen",
|
||||
"Show hours": "Stunden anzeigen",
|
||||
"Show minutes": "Minuten anzeigen",
|
||||
"Show Month": "Monat anzeigen",
|
||||
"Show Name": "Name anzeigen",
|
||||
"Show Open all": "\"Alle öffnen\" anzeigen",
|
||||
"Show Search": "Suche anzeigen",
|
||||
"Show seconds": "Sekunden anzeigen",
|
||||
"Show separator": "Trennzeichen anzeigen",
|
||||
"Show shadow on Bookmark hover": "Schatten beim Überfahren anzeigen",
|
||||
"Show Transitional words": "Übergangswörter anzeigen",
|
||||
"Show URL on Bookmark hover": "URL beim Überfahren anzeigen",
|
||||
"Show Visual Element": "Symbol anzeigen",
|
||||
"Show Year": "Jahr anzeigen",
|
||||
"Size": "Größe",
|
||||
"Small button": "Kleine Schaltfläche",
|
||||
"Space around Header and Bookmark Area": "Abstand um Kopf- und Lesezeichen-Bereich",
|
||||
"Space between Header and Bookmark items": "Abstand zwischen Kopf- und Lesezeichen-Elementen",
|
||||
"Square shaped Bookmark tiles.": "Quadratische Lesezeichen-Kacheln.",
|
||||
"Stack the Header and Bookmarks in a column one above the other.": "Kopfzeile und Lesezeichen in einer Spalte übereinander anordnen.",
|
||||
"Stack the Header and Bookmarks in a row side by side.": "Kopfzeile und Lesezeichen in einer Reihe nebeneinander anordnen.",
|
||||
"Stack the Visual Element and Name one above the other.": "Symbol und Name übereinander anordnen.",
|
||||
"Start of the week": "Wochenbeginn",
|
||||
"Sunday": "Sonntag",
|
||||
"Tall tile": "Hohe Kachel",
|
||||
"The Collapse button will show or hide the Bookmaks in this Group.": "Die Einklappen-Schaltfläche zeigt oder verbirgt die Lesezeichen dieser Gruppe.",
|
||||
"Theme": "Design",
|
||||
"Theme Accent": "Design-Akzent",
|
||||
"Theme colour": "Design-Farbe",
|
||||
"Thin": "Dünn",
|
||||
"This includes the Colour, Accent, Fonts, Background and any saved Custom Themes.": "Dies umfasst Farbe, Akzent, Schriftarten, Hintergrund und alle gespeicherten eigenen Designs.",
|
||||
"Title": "Titel",
|
||||
"Toolbar": "Werkzeugleiste",
|
||||
"Toolbar position": "Position der Werkzeugleiste",
|
||||
"Toolbar size": "Größe der Werkzeugleiste",
|
||||
"Top": "Oben",
|
||||
"Top Center": "Oben Mitte",
|
||||
"Top Left": "Oben Links",
|
||||
"Top left": "Oben links",
|
||||
"Top Right": "Oben Rechts",
|
||||
"Top right": "Oben rechts",
|
||||
"Transparent": "Transparent",
|
||||
"Use a custom colour behind the Bookmark area.": "Eine eigene Farbe hinter dem Lesezeichen-Bereich verwenden.",
|
||||
"Use a custom colour behind the Header area.": "Eine eigene Farbe hinter dem Kopfbereich verwenden.",
|
||||
"Use a custom colour behind the Layout.": "Eine eigene Farbe hinter dem Layout verwenden.",
|
||||
"Use the Accent colour for the Background.": "Die Akzentfarbe für den Hintergrund verwenden.",
|
||||
"Use the Accent defined by the Theme.": "Den vom Design festgelegten Akzent verwenden.",
|
||||
"Use the Background colour defined by the Theme.": "Die vom Design festgelegte Hintergrundfarbe verwenden.",
|
||||
"Use the Colour defined by the Theme.": "Die vom Design festgelegte Farbe verwenden.",
|
||||
"Useful for just displaying your name.": "Praktisch, um nur deinen Namen anzuzeigen.",
|
||||
"User interface font": "Schriftart der Oberfläche",
|
||||
"Vertical": "Vertikal",
|
||||
"Video": "Video",
|
||||
"Vignette": "Vignette",
|
||||
"Visual & Name": "Symbol & Name",
|
||||
"Visual Element and Name alignment": "Ausrichtung von Symbol und Name",
|
||||
"Visual element then name": "Symbol, dann Name",
|
||||
"Visual shadow": "Symbol-Schatten",
|
||||
"Visual size": "Symbolgröße",
|
||||
"Why has this changed?": "Warum hat sich das geändert?",
|
||||
"Wide tile": "Breite Kachel",
|
||||
"Width": "Breite",
|
||||
"Word length": "Wortlänge",
|
||||
"Wording": "Formulierung",
|
||||
"You can restore all or parts of a backup file. The following data will be restored:": "Du kannst eine Sicherung ganz oder teilweise wiederherstellen. Folgende Daten werden wiederhergestellt:"
|
||||
}
|
||||
66
lang/de2.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"Add more than one URL separated by spaces or on new lines for a random background image on load.": "Gib mehrere URLs durch Leerzeichen oder Zeilenumbrüche getrennt an, um beim Laden ein zufälliges Hintergrundbild zu erhalten.",
|
||||
"Add more than one URL separated by spaces or on new lines for a random background video on load.": "Gib mehrere URLs durch Leerzeichen oder Zeilenumbrüche getrennt an, um beim Laden ein zufälliges Hintergrundvideo zu erhalten.",
|
||||
"Alternatively, it is possible to wipe all settings but keep the current Bookmarks and Groups.": "Alternativ kannst du alle Einstellungen löschen, aber die aktuellen Lesezeichen und Gruppen behalten.",
|
||||
"Applying a Preset will replace the current Colour, Accent, Font, Style, Opacity, Radius, Shadow, Shade and Background.": "Eine Vorlage ersetzt die aktuelle Farbe, Akzent, Schrift, Stil, Deckkraft, Radius, Schatten, Schattierung und Hintergrund.",
|
||||
"Are you sure you want to clear all MyStart Bookmarks and Settings? MyStart will be restore to the default state.": "Möchtest du wirklich alle MyStart-Lesezeichen und -Einstellungen löschen? MyStart wird auf den Ausgangszustand zurückgesetzt.",
|
||||
"Auto change Accent hue will not work when the Accent colour is a grey or black.": "Der automatische Akzent-Farbtonwechsel funktioniert nicht, wenn die Akzentfarbe grau oder schwarz ist.",
|
||||
"Background image only supports a direct URL to an image file.": "Für das Hintergrundbild wird nur eine direkte URL zu einer Bilddatei unterstützt.",
|
||||
"Background video only supports a direct URL to a video file. Supports MP4 and WebM format.": "Für das Hintergrundvideo wird nur eine direkte URL zu einer Videodatei unterstützt. Unterstützt MP4 und WebM.",
|
||||
"Backgrounds, Bookmarks and Modals use shades from the left.": "Hintergründe, Lesezeichen und Dialoge nutzen Schattierungen von links.",
|
||||
"Bookmark border can also be changed when editing individual Bookmarks.": "Der Lesezeichen-Rahmen kann auch beim Bearbeiten einzelner Lesezeichen geändert werden.",
|
||||
"Bookmark custom Accent can also be changed when editing individual Bookmarks.": "Der eigene Akzent eines Lesezeichens kann auch beim Bearbeiten einzelner Lesezeichen geändert werden.",
|
||||
"Change parameters after .../random/ for more options. Loading times may vary.": "Ändere die Parameter nach .../random/ für mehr Optionen. Ladezeiten können variieren.",
|
||||
"Change the opacity of Search bar, Bookmarks, Group controls and the Toolbar.": "Ändere die Deckkraft von Suchleiste, Lesezeichen, Gruppen-Steuerung und Werkzeugleiste.",
|
||||
"Change the Visual Element and Name position, scale and orientation.": "Ändere Position, Größe und Ausrichtung von Symbol und Name.",
|
||||
"Clear all data to reset MyStart to the default state.": "Alle Daten löschen, um MyStart auf den Ausgangszustand zurückzusetzen.",
|
||||
"Display a Name above this Group.": "Einen Namen über dieser Gruppe anzeigen.",
|
||||
"Display controls to open all or show/hide the Bookmarks in this Group.": "Steuerung anzeigen, um alle Lesezeichen dieser Gruppe zu öffnen oder ein-/auszublenden.",
|
||||
"Display Letters, Icon, Image and a Name on this Bookmark tile.": "Buchstaben, Icon, Bild und einen Namen auf dieser Lesezeichen-Kachel anzeigen.",
|
||||
"Display the URL and Controls either at the top or bottom of a Bookmark Tile.": "URL und Steuerung entweder oben oder unten auf einer Lesezeichen-Kachel anzeigen.",
|
||||
"Download a backup of your MyStart Bookmarks and Settings.": "Eine Sicherung deiner MyStart-Lesezeichen und -Einstellungen herunterladen.",
|
||||
"Effects may not be visible if the Bookmark Area is full width.": "Effekte sind evtl. nicht sichtbar, wenn der Lesezeichen-Bereich die volle Breite hat.",
|
||||
"Effects may not be visible if the Header Area is full width.": "Effekte sind evtl. nicht sichtbar, wenn der Kopfbereich die volle Breite hat.",
|
||||
"For a light look switch to the Light Style and then select a Primary colour. And vice versa for a dark look.": "Für ein helles Aussehen zum hellen Stil wechseln und eine Primärfarbe wählen. Für ein dunkles Aussehen umgekehrt.",
|
||||
"Group Collapse": "Gruppe einklappen",
|
||||
"Group Names can also be changed by editing individual Groups.": "Gruppennamen können auch beim Bearbeiten einzelner Gruppen geändert werden.",
|
||||
"Group Open all": "Gruppe: Alle öffnen",
|
||||
"Group toolbar collapse button can also be changed by editing individual Groups.": "Die Einklappen-Schaltfläche der Gruppen-Werkzeugleiste kann auch beim Bearbeiten einzelner Gruppen geändert werden.",
|
||||
"Group toolbar open all button can also be changed by editing individual Groups.": "Die \"Alle öffnen\"-Schaltfläche der Gruppen-Werkzeugleiste kann auch beim Bearbeiten einzelner Gruppen geändert werden.",
|
||||
"Local images can no longer be used. Images must be hosted somewhere online.": "Lokale Bilder können nicht mehr verwendet werden. Bilder müssen online gehostet sein.",
|
||||
"Move the Contrast range controls close together for a muted look.": "Schiebe die Kontrast-Regler nah zusammen für einen gedämpften Look.",
|
||||
"Move the Contrast range controls far apart from each other for a sharp vivid look.": "Schiebe die Kontrast-Regler weit auseinander für einen scharfen, kräftigen Look.",
|
||||
"No Bookmarks in this Group": "Keine Lesezeichen in dieser Gruppe",
|
||||
"No Groups or Bookmarks": "Keine Gruppen oder Lesezeichen",
|
||||
"Not a JSON file. Make sure the selected file came from MyStart.": "Keine JSON-Datei. Stelle sicher, dass die Datei von MyStart stammt.",
|
||||
"Not all fonts support all weights. Refer to the Google Font page to see which are available.": "Nicht alle Schriftarten unterstützen alle Stärken. Auf der Google-Fonts-Seite siehst du, welche verfügbar sind.",
|
||||
"Not supported by all browsers.": "Nicht von allen Browsern unterstützt.",
|
||||
"Not the right kind of data. Make sure the clipboard holds data from MyStart or a MyStart backup JSON file.": "Falsche Art von Daten. Stelle sicher, dass die Zwischenablage Daten von MyStart oder eine MyStart-Sicherungs-JSON enthält.",
|
||||
"Not the right kind of JSON file. Make sure the selected file came from MyStart.": "Falsche Art von JSON-Datei. Stelle sicher, dass die Datei von MyStart stammt.",
|
||||
"Nothing selected to import.": "Nichts zum Importieren ausgewählt.",
|
||||
"Only available when Date or Time is shown.": "Nur verfügbar, wenn Datum oder Uhrzeit angezeigt wird.",
|
||||
"Only available when the Toolbar is positioned in a corner.": "Nur verfügbar, wenn die Werkzeugleiste in einer Ecke positioniert ist.",
|
||||
"Only available when the Toolbar is positioned inside the Header.": "Nur verfügbar, wenn die Werkzeugleiste in der Kopfzeile positioniert ist.",
|
||||
"Opacity can also be changed when editing individual Bookmarks.": "Die Deckkraft kann auch beim Bearbeiten einzelner Lesezeichen geändert werden.",
|
||||
"Ordering": "Reihenfolge",
|
||||
"Override the Theme and Accent colour.": "Design- und Akzentfarbe überschreiben.",
|
||||
"Position the Toolbar in one of the four corners of the window.": "Die Werkzeugleiste in einer der vier Ecken des Fensters positionieren.",
|
||||
"Position the Toolbar inside the Header or in a corner of the window.": "Die Werkzeugleiste in der Kopfzeile oder in einer Ecke des Fensters positionieren.",
|
||||
"Restore a previously exported MyStart backup.": "Eine zuvor exportierte MyStart-Sicherung wiederherstellen.",
|
||||
"Saving a Theme will record the current Colour, Accent, Font, Style, Opacity, Radius, Shadow, Shade and Background.": "Beim Speichern eines Designs werden die aktuelle Farbe, Akzent, Schrift, Stil, Deckkraft, Radius, Schatten, Schattierung und Hintergrund festgehalten.",
|
||||
"Sets the name attribute on the Search input field.": "Legt das name-Attribut des Such-Eingabefelds fest.",
|
||||
"Success! Restoring MyStart Bookmarks and Settings.": "Erfolg! MyStart-Lesezeichen und -Einstellungen werden wiederhergestellt.",
|
||||
"Take care as a fast changing Accent hue may cause performance issues.": "Vorsicht: Ein schnell wechselnder Akzent-Farbton kann die Leistung beeinträchtigen.",
|
||||
"Text and form elements use shades from the right.": "Text und Formularelemente nutzen Schattierungen von rechts.",
|
||||
"The colour of the Border is defined by the Accent which can also be changed when editing individual Bookmarks.": "Die Rahmenfarbe wird durch den Akzent bestimmt, der auch beim Bearbeiten einzelner Lesezeichen geändert werden kann.",
|
||||
"The Group to place this Bookmark in.": "Die Gruppe, in die dieses Lesezeichen gehört.",
|
||||
"The position of this Group.": "Die Position dieser Gruppe.",
|
||||
"This can not be undone.": "Dies kann nicht rückgängig gemacht werden.",
|
||||
"This defines the name passed to the search engine when submitting. If not sure leave blank.": "Legt den Namen fest, der beim Absenden an die Suchmaschine übergeben wird. Im Zweifel leer lassen.",
|
||||
"This file can later be imported on this or another deivce.": "Diese Datei kann später auf diesem oder einem anderen Gerät importiert werden.",
|
||||
"Unsplash can be used for random images, eg:": "Unsplash kann für zufällige Bilder genutzt werden, z. B.:",
|
||||
"Visual shadow only applies to a Letter or Icon.": "Der Symbol-Schatten gilt nur für Buchstaben oder Icons.",
|
||||
"You will lose Bookmarks by clearing all data.": "Beim Löschen aller Daten gehen die Lesezeichen verloren.",
|
||||
"YouTube page URLs <strong>can not</strong> be used.": "YouTube-Seiten-URLs <strong>können nicht</strong> verwendet werden.",
|
||||
"YouTube page URLs can not be used.": "YouTube-Seiten-URLs können nicht verwendet werden."
|
||||
}
|
||||
1
quelle-nightTab/_metadata/verified_contents.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"description":"treehash per file","signed_content":{"payload":"eyJjb250ZW50X2hhc2hlcyI6W3siYmxvY2tfc2l6ZSI6NDA5NiwiZGlnZXN0Ijoic2hhMjU2IiwiZmlsZXMiOlt7InBhdGgiOiJmb250L2ZhLWJyYW5kcy00MDAudHRmIiwicm9vdF9oYXNoIjoiSjBmSDRJNmtKYkt1ak5LNFhpdE5fSGh6WDkzZ1Jsa1ZqSkpFNVhiZU0ydyJ9LHsicGF0aCI6ImZvbnQvZmEtYnJhbmRzLTQwMC53b2ZmIiwicm9vdF9oYXNoIjoiaVpJYWc2dW0zTGdVUm90TkJSYUVvRXpFeC1MZjBkMm8wQW44SWJzR1ZBSSJ9LHsicGF0aCI6ImZvbnQvZmEtYnJhbmRzLTQwMC53b2ZmMiIsInJvb3RfaGFzaCI6ImxfVGhlWGZhYzF4VU1yUWtyQzVRd1kzUlMxZDNmX3pvOVhfV1lnVnVsekkifSx7InBhdGgiOiJmb250L2ZhLXJlZ3VsYXItNDAwLnR0ZiIsInJvb3RfaGFzaCI6Ii0tem4tSnpiWTVyY0dESjZyVFI4QUpFeGxRN05WX1AwNTV4YVJmZTV2VDQifSx7InBhdGgiOiJmb250L2ZhLXJlZ3VsYXItNDAwLndvZmYiLCJyb290X2hhc2giOiJ3REJFX2xkUE1GbzF1LWQ3SnVwa0RtRUZxa05rRWxhWG9zWG1iR2M1YUFnIn0seyJwYXRoIjoiZm9udC9mYS1yZWd1bGFyLTQwMC53b2ZmMiIsInJvb3RfaGFzaCI6IlRXU0pLVUdWREVrN3hEYzBYMF9MOEYtNGtpNGg1TVdPeUJvdU1Ob1RZR1UifSx7InBhdGgiOiJmb250L2ZhLXNvbGlkLTkwMC50dGYiLCJyb290X2hhc2giOiJ2WWlhMUZXR1JvbXo0d29oVFMtZnBCSjIzWWZFYXllc29EOFNyNmNIR3E4In0seyJwYXRoIjoiZm9udC9mYS1zb2xpZC05MDAud29mZiIsInJvb3RfaGFzaCI6IkpRRUNmZ0szUlJBR3dRQnh1dVZ1TGpVV0o1aG56ZzBUcWQ0TXlNdGJUV1kifSx7InBhdGgiOiJmb250L2ZhLXNvbGlkLTkwMC53b2ZmMiIsInJvb3RfaGFzaCI6Il9hSzNPUjBLSk9fRms3OE94MDFoRkthZVN5YnRGWk1GYzRUOHlvVXBzNncifSx7InBhdGgiOiJmb250L2ZqYWxsYS1vbmUtNDAwLnR0ZiIsInJvb3RfaGFzaCI6IlJuc3pGUThOTlVCek9xdVJsZndqY0VlV3ZjYndHbkszOF9xRjE3U094Q2MifSx7InBhdGgiOiJmb250L2ZqYWxsYS1vbmUtNDAwLndvZmYiLCJyb290X2hhc2giOiJfUktQQ1JXcXJNQWtXVEhKa01adGRKcHRIVXUyNVVFRXByblY5cElkeVdNIn0seyJwYXRoIjoiZm9udC9mamFsbGEtb25lLTQwMC53b2ZmMiIsInJvb3RfaGFzaCI6IkotNUhqbUZOMUtOU0pqYnNGMEpJbnZfdW5pWjlkQ3NiejEyN2x4a0dyY2sifSx7InBhdGgiOiJmb250L29wZW4tc2Fucy00MDAudHRmIiwicm9vdF9oYXNoIjoiN1psSG9hTmJrQmowb1RlQW5mX0pLTkR3dm9lbEQyVzdhQjVPM2xKY3lBbyJ9LHsicGF0aCI6ImZvbnQvb3Blbi1zYW5zLTQwMC53b2ZmIiwicm9vdF9oYXNoIjoiVGdJaEhWU0ZmenczcnUwdi1iRFNac0plMlp2TTFTcUdmT1pGSzFCbzQ3YyJ9LHsicGF0aCI6ImZvbnQvb3Blbi1zYW5zLTQwMC53b2ZmMiIsInJvb3RfaGFzaCI6IkNDVmZrYjVZd3JwQ1k4QVBIZkZrRmF0a1U0b1R6bzdpM1BoYlMwWUZWd2cifSx7InBhdGgiOiJpY29uL2Zhdmljb24uc3ZnIiwicm9vdF9oYXNoIjoicGlxcGt6X0FaQmNqU0pJVW1SenRLOTh2U0NneGdKSWhTS2dkYmRVQ2JGayJ9LHsicGF0aCI6Imljb24vaWNvbi0xMjgucG5nIiwicm9vdF9oYXNoIjoieDRmWHc2NlBkN0djb1I2a2Q2d3cwUXNlUG1PSm4wNFZJRE1ncmlKb3ZGcyJ9LHsicGF0aCI6Imljb24vaWNvbi0xNi5wbmciLCJyb290X2hhc2giOiIwWUgzY1AwdG80b3VuWVd5MS1kSHZDWVdxRXZRWDVDSmxSblo0ZV8wSHJNIn0seyJwYXRoIjoiaWNvbi9pY29uLTQ4LnBuZyIsInJvb3RfaGFzaCI6InRFT1RBSUtXMEwxcU12UUUtUEdRcGdUS0ZGekJ0bTc4M3NHcEZOSTJEV2MifSx7InBhdGgiOiJpY29uL2ljb24tNTEyLnBuZyIsInJvb3RfaGFzaCI6ImV6ZnRfZHZfV3Z5WDhyWmlINm1NR2Y3dTNsSmxYa25IeTJVUjhCZDlyeEUifSx7InBhdGgiOiJpY29uL2ljb24tNTEyLnN2ZyIsInJvb3RfaGFzaCI6IkMxM0pKV0VyTF9DQmdRQUU0QXRvdldybVB5M3NNV3pwWVhqOE1ic0hMSXMifSx7InBhdGgiOiJpbmRleC4wOTE1M2FiZGJhYTc5MWZhNGYwZS5qcyIsInJvb3RfaGFzaCI6IjRlWG5XZFgyMlgtNWJKMmxJaE95Yl9qTHh4N2liUzBORlVUb080Y3ViVmcifSx7InBhdGgiOiJpbmRleC40MWIyZDJhOGNlZTg0NmIwMzJiNS5jc3MiLCJyb290X2hhc2giOiJxTWpmTHd1SEdXeEFUS1VrQTNaT2x0VS1YSWNXZXZZRlQwX3JhMThtN25ZIn0seyJwYXRoIjoiaW5kZXguaHRtbCIsInJvb3RfaGFzaCI6IkQ1QVhyemhJZ2FOWDJXOGdHbjFuVE5aVzVaejk1c1pyVEZ6M2FjQWtaZmMifSx7InBhdGgiOiJpbml0aWFsQmFja2dyb3VuZC5qcyIsInJvb3RfaGFzaCI6ImdUOEdrcTR0VmwwS3JJRHpaVmpEbDR6VHZCOXhJQWZya0ZIbEVkM05hdTQifSx7InBhdGgiOiJtYW5pZmVzdC5qc29uIiwicm9vdF9oYXNoIjoiZUloOXFCVG5BRVFEX1RjZkRQSkxndmNiZDlhNFJMTGFkT1R6b1JvUXlnZyJ9XSwiZm9ybWF0IjoidHJlZWhhc2giLCJoYXNoX2Jsb2NrX3NpemUiOjQwOTZ9XSwiaXRlbV9pZCI6ImhkcGNhZGlnamtiY3BubGNwYmNvaHBhZmlhZWZhbmtpIiwiaXRlbV92ZXJzaW9uIjoiNy4zLjAiLCJwcm90b2NvbF92ZXJzaW9uIjoxfQ","signatures":[{"header":{"kid":"publisher"},"protected":"eyJhbGciOiJSUzI1NiJ9","signature":"AH2eEYBozWVLmNI8-mzd6t3CG_8lLznCJTlaal18SKD2gZsZJYuo8TMYqRAcNzeEP5yuOK7LO0ubtAdnMlLeHa4iz0Bllrbm6f3OOprPEhRk79HZOJ5tSrhsXLJAwREeANKDkj3mFYY8LahCQHGgy7kGdFMr-CtVEUq6ERNa7_NdF7sPZp5QAUgztaryarFGLWLz5w6q3CtccgAKlDLL7AFypzkonZ__obVGxSVlTx-BbIft6w-j13kpzId1hxVTqOCqMKAz_enT47TQ9O-RWKZajhOBLSF1vK1WyycARsEf2T5haihJx-RxBc6SKXdihCdpmjI5Hg_O3RywYEWkjw"},{"header":{"kid":"webstore"},"protected":"eyJhbGciOiJSUzI1NiJ9","signature":"WROLbS0lyADKb3zzsn15iCoJNTuclaOHwAPkQTybiG4xwsYiFHMihQ5gzZmmLuj_HneVaFNZ7UFjNGMTsQPXqIQ9greSv4AnyODgg7aZgOm4Zu15AW952z1JOTBxoQv-ethMGBfCCGobAnIm8a9-iDP2CA43EBgvIdxecl13efu203XjEa2cXhy9UhToY35ZJOf9Yp5KVJ6UvQAUsazlQyRxpL7xdNB9xfHnI6zesuZCu5FXqvtCN4lBc-u3cnTNmz6D-XJp22lOeEiX5r_GQac23cLjMFjXf18sUkMT5iVIQzYxojgtBDVydaRnuqs2naDt2admH_7GaTYDKJ27NQ"}]}}]
|
||||
BIN
quelle-nightTab/font/fa-brands-400.ttf
Normal file
BIN
quelle-nightTab/font/fa-brands-400.woff
Normal file
BIN
quelle-nightTab/font/fa-brands-400.woff2
Normal file
BIN
quelle-nightTab/font/fa-regular-400.ttf
Normal file
BIN
quelle-nightTab/font/fa-regular-400.woff
Normal file
BIN
quelle-nightTab/font/fa-regular-400.woff2
Normal file
BIN
quelle-nightTab/font/fa-solid-900.ttf
Normal file
BIN
quelle-nightTab/font/fa-solid-900.woff
Normal file
BIN
quelle-nightTab/font/fa-solid-900.woff2
Normal file
BIN
quelle-nightTab/font/fjalla-one-400.ttf
Normal file
BIN
quelle-nightTab/font/fjalla-one-400.woff
Normal file
BIN
quelle-nightTab/font/fjalla-one-400.woff2
Normal file
BIN
quelle-nightTab/font/open-sans-400.ttf
Normal file
BIN
quelle-nightTab/font/open-sans-400.woff
Normal file
BIN
quelle-nightTab/font/open-sans-400.woff2
Normal file
31
quelle-nightTab/icon/favicon.svg
Normal file
@@ -0,0 +1,31 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
.cross {
|
||||
fill: #ffffff;
|
||||
}
|
||||
.circle {
|
||||
fill: #000000;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
.cross {
|
||||
fill: #ffffff;
|
||||
}
|
||||
.circle {
|
||||
fill: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.cross {
|
||||
fill: #000000;
|
||||
}
|
||||
.circle {
|
||||
fill: #ffffff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<circle cx="8" cy="8" r="8" class="circle"/>
|
||||
<path d="M11.6875 7H4.3125C4.13991 7 4 7.13991 4 7.3125V8.6875C4 8.86009 4.13991 9 4.3125 9H11.6875C11.8601 9 12 8.86009 12 8.6875V7.3125C12 7.13991 11.8601 7 11.6875 7Z" class="cross"/>
|
||||
<path d="M8.6875 4H7.3125C7.13991 4 7 4.13991 7 4.3125V11.6875C7 11.8601 7.13991 12 7.3125 12H8.6875C8.86009 12 9 11.8601 9 11.6875V4.3125C9 4.13991 8.86009 4 8.6875 4Z" class="cross"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 916 B |
BIN
quelle-nightTab/icon/icon-128.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
quelle-nightTab/icon/icon-16.png
Normal file
|
After Width: | Height: | Size: 404 B |
BIN
quelle-nightTab/icon/icon-48.png
Normal file
|
After Width: | Height: | Size: 995 B |
BIN
quelle-nightTab/icon/icon-512.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
31
quelle-nightTab/icon/icon-512.svg
Normal file
@@ -0,0 +1,31 @@
|
||||
<svg viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
.cross {
|
||||
fill: #939BAE;
|
||||
}
|
||||
.circle {
|
||||
fill: #252931;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
.cross {
|
||||
fill: #939BAE;
|
||||
}
|
||||
.circle {
|
||||
fill: #252931;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.cross {
|
||||
fill: #252931;
|
||||
}
|
||||
.circle {
|
||||
fill: #939BAE;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<circle cx="256" cy="256" r="256" class="circle"/>
|
||||
<path d="M374 224H138C132.477 224 128 228.477 128 234V278C128 283.523 132.477 288 138 288H374C379.523 288 384 283.523 384 278V234C384 228.477 379.523 224 374 224Z" class="cross"/>
|
||||
<path d="M278 128H234C228.477 128 224 132.477 224 138V374C224 379.523 228.477 384 234 384H278C283.523 384 288 379.523 288 374V138C288 132.477 283.523 128 278 128Z" class="cross"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 888 B |
1
quelle-nightTab/index.09153abdbaa791fa4f0e.js
Normal file
1
quelle-nightTab/index.41b2d2a8cee846b032b5.css
Normal file
1
quelle-nightTab/index.html
Normal file
@@ -0,0 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no"><title>New Tab</title><link rel="icon" type="image/svg+xml" class="favicon" href="icon/favicon.svg"/><style media="screen">html,body {background-color: rgb(0, 0, 0);}@media (prefers-color-scheme: dark) {html,body {background-color: rgb(0, 0, 0);}}@media (prefers-color-scheme: light) {html,body {background-color: rgb(255, 255, 255);}}</style><script src="initialBackground.js" async></script><script defer="defer" src="index.09153abdbaa791fa4f0e.js"></script><link href="index.41b2d2a8cee846b032b5.css" rel="stylesheet"></head><body></body></html>
|
||||
1
quelle-nightTab/initialBackground.js
Normal file
@@ -0,0 +1 @@
|
||||
if(localStorage.getItem("nightTabStyle")){const e=document.createElement("style");switch(e.type="text/css",e.media="screen",localStorage.getItem("nightTabStyle")){case"light":e.innerHTML="html, body {background-color: rgb(255, 255, 255);}";break;case"dark":e.innerHTML="html, body {background-color: rgb(0, 0, 0);}"}document.querySelector("head").appendChild(e)}
|
||||
18
quelle-nightTab/manifest.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"update_url": "https://clients2.google.com/service/update2/crx",
|
||||
|
||||
"name": "nightTab",
|
||||
"short_name": "nightTab",
|
||||
"description": "A neutral new tab page accented with a chosen colour. Customise the layout, style, background and bookmarks in nightTab.",
|
||||
"version": "7.3.0",
|
||||
"manifest_version": 2,
|
||||
"chrome_url_overrides": {
|
||||
"newtab": "index.html"
|
||||
},
|
||||
"icons": {
|
||||
"16": "icon/icon-16.png",
|
||||
"48": "icon/icon-48.png",
|
||||
"128": "icon/icon-128.png",
|
||||
"512": "icon/icon-512.png"
|
||||
}
|
||||
}
|
||||
32
webview2/MyStart.csproj
Normal file
@@ -0,0 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net10.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<AssemblyName>MyStart</AssemblyName>
|
||||
<RootNamespace>MyStart</RootNamespace>
|
||||
<Version>1.0.1</Version>
|
||||
<ApplicationIcon>app.ico</ApplicationIcon>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<SelfContained>true</SelfContained>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3485.44" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="app-index.html" />
|
||||
<EmbeddedResource Include="app.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
264
webview2/Program.cs
Normal file
@@ -0,0 +1,264 @@
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Win32;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.WinForms;
|
||||
|
||||
namespace MyStart;
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
|
||||
bool minimized = args.Any(a =>
|
||||
a.Equals("--minimized", StringComparison.OrdinalIgnoreCase) ||
|
||||
a.Equals("--min", StringComparison.OrdinalIgnoreCase) ||
|
||||
a.Equals("--autostart", StringComparison.OrdinalIgnoreCase));
|
||||
Application.Run(new MainForm(minimized));
|
||||
}
|
||||
}
|
||||
|
||||
class MainForm : Form
|
||||
{
|
||||
private readonly WebView2 _web = new() { Dock = DockStyle.Fill };
|
||||
private const string Host = "mystart.local";
|
||||
private bool _pendingMaximize;
|
||||
|
||||
public MainForm(bool startMinimized = false)
|
||||
{
|
||||
Text = "MyStart";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Width = 1280;
|
||||
Height = 800;
|
||||
MinimumSize = new System.Drawing.Size(480, 360);
|
||||
ShowInTaskbar = true;
|
||||
BackColor = System.Drawing.Color.Black;
|
||||
// No title bar / border. Close with Alt+F4, minimize via the taskbar button.
|
||||
FormBorderStyle = FormBorderStyle.None;
|
||||
|
||||
if (startMinimized)
|
||||
{
|
||||
// Autostart: sit minimized on the taskbar; restore to a normal window on first open.
|
||||
WindowState = FormWindowState.Minimized;
|
||||
_pendingMaximize = true;
|
||||
Resize += (_, _) =>
|
||||
{
|
||||
if (_pendingMaximize && WindowState != FormWindowState.Minimized)
|
||||
{
|
||||
_pendingMaximize = false;
|
||||
WindowState = FormWindowState.Normal;
|
||||
}
|
||||
};
|
||||
}
|
||||
// else: leave WindowState at its default (Normal) -> starts as a normal
|
||||
// 1280x800 window, not maximized/fullscreen.
|
||||
|
||||
try
|
||||
{
|
||||
var asm = Assembly.GetExecutingAssembly();
|
||||
var icoName = asm.GetManifestResourceNames()
|
||||
.FirstOrDefault(n => n.EndsWith("app.ico", StringComparison.OrdinalIgnoreCase));
|
||||
if (icoName != null)
|
||||
{
|
||||
using var s = asm.GetManifestResourceStream(icoName);
|
||||
if (s != null) Icon = new Icon(s);
|
||||
}
|
||||
}
|
||||
catch { /* icon optional */ }
|
||||
|
||||
Controls.Add(_web);
|
||||
Shown += async (_, _) => await InitAsync();
|
||||
}
|
||||
|
||||
// Keep a borderless maximized window from covering the taskbar.
|
||||
protected override void OnHandleCreated(EventArgs e)
|
||||
{
|
||||
base.OnHandleCreated(e);
|
||||
MaximizedBounds = Screen.FromHandle(Handle).WorkingArea;
|
||||
}
|
||||
|
||||
private async Task InitAsync()
|
||||
{
|
||||
// Persistent data dir -> localStorage (settings/bookmarks) survive across runs
|
||||
// and independent of where the .exe lives.
|
||||
string dataDir = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"MyStart");
|
||||
Directory.CreateDirectory(dataDir);
|
||||
|
||||
var env = await CoreWebView2Environment.CreateAsync(null, dataDir);
|
||||
await _web.EnsureCoreWebView2Async(env);
|
||||
|
||||
// Extract the embedded app to a fixed folder, served via a stable origin.
|
||||
string appDir = Path.Combine(dataDir, "app");
|
||||
Directory.CreateDirectory(appDir);
|
||||
string htmlPath = Path.Combine(appDir, "index.html");
|
||||
var asm = Assembly.GetExecutingAssembly();
|
||||
string resName = asm.GetManifestResourceNames()
|
||||
.First(n => n.EndsWith("app-index.html", StringComparison.OrdinalIgnoreCase));
|
||||
await using (var res = asm.GetManifestResourceStream(resName)!)
|
||||
await using (var file = File.Create(htmlPath))
|
||||
await res.CopyToAsync(file);
|
||||
|
||||
var core = _web.CoreWebView2;
|
||||
core.SetVirtualHostNameToFolderMapping(Host, appDir, CoreWebView2HostResourceAccessKind.Allow);
|
||||
core.Settings.IsStatusBarEnabled = false;
|
||||
core.Settings.AreDefaultContextMenusEnabled = true;
|
||||
core.Settings.IsWebMessageEnabled = true;
|
||||
|
||||
// Autostart toggle from the in-app "MyStart" info page.
|
||||
core.WebMessageReceived += (_, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(e.WebMessageAsJson);
|
||||
var root = doc.RootElement;
|
||||
if (!root.TryGetProperty("type", out var t)) return;
|
||||
switch (t.GetString())
|
||||
{
|
||||
case "autostart-get":
|
||||
PostAutostartState();
|
||||
break;
|
||||
case "autostart-set":
|
||||
bool on = root.TryGetProperty("value", out var v) &&
|
||||
v.ValueKind == JsonValueKind.True;
|
||||
SetAutostart(on);
|
||||
PostAutostartState();
|
||||
break;
|
||||
case "window-drag":
|
||||
StartWindowDrag();
|
||||
break;
|
||||
case "window-resize":
|
||||
if (root.TryGetProperty("edge", out var edgeProp))
|
||||
StartWindowResize(edgeProp.GetString());
|
||||
break;
|
||||
case "window-min":
|
||||
WindowState = FormWindowState.Minimized;
|
||||
break;
|
||||
case "window-max":
|
||||
WindowState = WindowState == FormWindowState.Maximized
|
||||
? FormWindowState.Normal : FormWindowState.Maximized;
|
||||
break;
|
||||
case "window-close":
|
||||
Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch { /* ignore malformed messages */ }
|
||||
};
|
||||
|
||||
// Bookmark links that open a new window -> user's default browser.
|
||||
core.NewWindowRequested += (_, e) =>
|
||||
{
|
||||
e.Handled = true;
|
||||
OpenExternal(e.Uri);
|
||||
};
|
||||
|
||||
// Same-tab clicks to external sites -> default browser, keep the app loaded.
|
||||
core.NavigationStarting += (_, e) =>
|
||||
{
|
||||
var uri = e.Uri ?? string.Empty;
|
||||
if (uri.StartsWith("https://" + Host, StringComparison.OrdinalIgnoreCase)) return; // internal
|
||||
if (uri.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
|
||||
uri.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
e.Cancel = true;
|
||||
OpenExternal(uri);
|
||||
}
|
||||
};
|
||||
|
||||
core.Navigate("https://" + Host + "/index.html");
|
||||
}
|
||||
|
||||
// --- Autostart (per-user HKCU Run key, points at THIS exe with --minimized) ---
|
||||
private const string RunKeyPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||
private const string RunValueName = "MyStart";
|
||||
private static string ExePath => Environment.ProcessPath ?? Application.ExecutablePath;
|
||||
|
||||
private static bool IsAutostartEnabled()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var k = Registry.CurrentUser.OpenSubKey(RunKeyPath, false);
|
||||
return k?.GetValue(RunValueName) is string v && v.Length > 0;
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
private static void SetAutostart(bool on)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var k = Registry.CurrentUser.OpenSubKey(RunKeyPath, true)
|
||||
?? Registry.CurrentUser.CreateSubKey(RunKeyPath, true);
|
||||
if (k == null) return;
|
||||
if (on) k.SetValue(RunValueName, "\"" + ExePath + "\" --minimized");
|
||||
else if (k.GetValue(RunValueName) != null) k.DeleteValue(RunValueName, false);
|
||||
}
|
||||
catch { /* ignore */ }
|
||||
}
|
||||
|
||||
private void PostAutostartState()
|
||||
{
|
||||
var json = "{\"type\":\"autostart\",\"enabled\":" +
|
||||
(IsAutostartEnabled() ? "true" : "false") + "}";
|
||||
try { _web.CoreWebView2.PostWebMessageAsJson(json); } catch { }
|
||||
}
|
||||
|
||||
// --- Free window drag for the borderless window (page sends "window-drag"
|
||||
// on grip mousedown / Alt+drag; we hand off to the native move loop). ---
|
||||
[System.Runtime.InteropServices.DllImport("user32.dll")]
|
||||
private static extern bool ReleaseCapture();
|
||||
[System.Runtime.InteropServices.DllImport("user32.dll")]
|
||||
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
|
||||
private const int WM_NCLBUTTONDOWN = 0xA1;
|
||||
private const int HTCAPTION = 0x2;
|
||||
|
||||
private void StartWindowDrag()
|
||||
{
|
||||
// A maximized window can't be moved -> restore first, centred under cursor-ish.
|
||||
if (WindowState == FormWindowState.Maximized)
|
||||
WindowState = FormWindowState.Normal;
|
||||
ReleaseCapture();
|
||||
SendMessage(Handle, WM_NCLBUTTONDOWN, (IntPtr)HTCAPTION, IntPtr.Zero);
|
||||
}
|
||||
|
||||
// --- Free window resize for the borderless window. The WebView2 control
|
||||
// fills the entire client area, so the OS never gets a chance to hit-test
|
||||
// the window's own edges for a resize cursor/drag -- every mouse message
|
||||
// lands in the browser first. The page (bundle.js) instead watches the
|
||||
// mouse position itself, and on mousedown within a few px of an edge/
|
||||
// corner sends "window-resize" with which edge; we hand off to the same
|
||||
// native resize loop Windows uses for a normal sizable window. ---
|
||||
private static readonly Dictionary<string, int> ResizeEdges = new()
|
||||
{
|
||||
["n"] = 12, ["s"] = 15, ["e"] = 11, ["w"] = 10,
|
||||
["ne"] = 14, ["nw"] = 13, ["se"] = 17, ["sw"] = 16,
|
||||
};
|
||||
|
||||
private void StartWindowResize(string? edge)
|
||||
{
|
||||
// Only a normal (non-maximized, non-minimized) window can be resized this way.
|
||||
if (WindowState != FormWindowState.Normal) return;
|
||||
if (edge == null || !ResizeEdges.TryGetValue(edge, out var htCode)) return;
|
||||
ReleaseCapture();
|
||||
SendMessage(Handle, WM_NCLBUTTONDOWN, (IntPtr)htCode, IntPtr.Zero);
|
||||
}
|
||||
|
||||
private static void OpenExternal(string uri)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
|
||||
{
|
||||
FileName = uri,
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
124
webview2/app-index.html
Normal file
BIN
webview2/app.ico
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
webview2/build/icon.ico
Normal file
|
After Width: | Height: | Size: 9.3 KiB |