Upload via GUI (123 Dateien)
This commit is contained in:
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 484 B |
Binary file not shown.
|
After Width: | Height: | Size: 542 B |
Binary file not shown.
|
After Width: | Height: | Size: 211 B |
Binary file not shown.
|
After Width: | Height: | Size: 536 B |
Binary file not shown.
|
After Width: | Height: | Size: 572 B |
+424
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* designs.css – wählbare Designs (Optionen → Darstellung → Design)
|
||||
* ---------------------------------------------------------------
|
||||
* Klassisch (hell/dunkel) steht in styles.css. Die Designs hier bauen
|
||||
* auf den dunklen Regeln auf (data-theme="dark") und überschreiben sie über
|
||||
* data-design – gleiche Spezifität, deshalb muss diese Datei NACH styles.css
|
||||
* geladen werden.
|
||||
*/
|
||||
|
||||
/* ===================== Design-Auswahl in den Optionen ===================== */
|
||||
.design-raster{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
|
||||
.settings-card-wide .design-raster{grid-template-columns:repeat(5,minmax(0,1fr))}
|
||||
@media (max-width:900px){.settings-card-wide .design-raster{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
||||
.design-wahl{display:flex;flex-direction:column;gap:5px;padding:6px;border:1px solid var(--border);border-radius:8px;background:none;color:var(--text);font-family:inherit;font-size:12px;cursor:pointer;text-align:left}
|
||||
.design-wahl:hover{border-color:var(--sel-br)}
|
||||
.design-wahl.on{border-color:var(--sel-br);box-shadow:0 0 0 1px var(--sel-br);background:var(--sel)}
|
||||
.design-wahl small{font-size:12px;font-weight:600;padding:0 2px}
|
||||
.dv{position:relative;display:block;width:100%;align-self:stretch;height:58px;border-radius:5px;overflow:hidden;border:1px solid rgba(0,0,0,.25)}
|
||||
.dv i,.dv b,.dv em{position:absolute;display:block}
|
||||
.dv i{left:0;right:0;top:0;height:11px}
|
||||
.dv em{top:11px;right:0;bottom:0;width:24%}
|
||||
.dv b{left:10px;top:20px;width:22px;height:22px;border-radius:3px}
|
||||
.dv-dark{background:#242426}.dv-dark i{background:#333337}.dv-dark em{background:#2d2d30;border-left:1px solid #3f3f46}.dv-dark b{background:#0e639c;border:1px solid #1177bb}
|
||||
.dv-light{background:#e2e2e2}.dv-light i{background:#f0f0f0;border-bottom:1px solid #c4c7cc}.dv-light em{background:#f0f0f0;border-left:1px solid #c4c7cc}.dv-light b{background:#dce8f6;border:1px solid #3a6ea5}
|
||||
.dv-aero{background:radial-gradient(60px 30px at 35% 10px,rgba(64,126,232,.55),transparent 70%),linear-gradient(to right,rgba(148,175,255,.09) 1px,transparent 1px) 0 0/9px 9px,linear-gradient(to bottom,rgba(148,175,255,.09) 1px,transparent 1px) 0 0/9px 9px,#05070d}
|
||||
.dv-aero i{background:rgba(10,14,26,.95);border-bottom:1px solid rgba(148,175,255,.18)}
|
||||
.dv-aero em{background:#0a0e1a;border-left:1px solid rgba(148,175,255,.18)}
|
||||
.dv-aero b{border-radius:7px;background:linear-gradient(135deg,#8fd8ff,#407ee8 60%,#2658be);box-shadow:0 4px 12px -3px rgba(64,126,232,.9)}
|
||||
.dv-lila{background:radial-gradient(60px 30px at 35% 10px,rgba(139,92,246,.6),transparent 70%),linear-gradient(to right,rgba(196,165,255,.09) 1px,transparent 1px) 0 0/9px 9px,linear-gradient(to bottom,rgba(196,165,255,.09) 1px,transparent 1px) 0 0/9px 9px,#08050f}
|
||||
.dv-lila i{background:rgba(15,10,26,.95);border-bottom:1px solid rgba(196,165,255,.18)}
|
||||
.dv-lila em{background:#0f0a1a;border-left:1px solid rgba(196,165,255,.18)}
|
||||
.dv-lila b{border-radius:7px;background:linear-gradient(135deg,#e8beff,#8b5cf6 60%,#6d28d9);box-shadow:0 4px 12px -3px rgba(139,92,246,.9)}
|
||||
.dv-mc{background:url(assets/design/erde-dunkel.png) 0 0/24px 24px;image-rendering:pixelated}
|
||||
.dv-mc i{height:12px;background:url(assets/design/gras.png) 0 0/16px 4px repeat-x,url(assets/design/schiefer.png) 0 0/24px 24px;border-bottom:1px solid #000}
|
||||
.dv-mc em{background:url(assets/design/schiefer.png) 0 0/24px 24px;border-left:1px solid #000}
|
||||
.dv-mc b{border-radius:0;background:#3c8527;border:1px solid #000;box-shadow:inset 1px 1px 0 #6cc349,inset -1px -1px 0 #1d4d13}
|
||||
|
||||
/* ===================================================================== */
|
||||
/* ============ Designs: AeroMC (Blau, wie die Webseite) & Nachtlila ===== */
|
||||
/* ===================================================================== */
|
||||
/* Beide Designs teilen sich alle Regeln unten; sie unterscheiden sich nur in
|
||||
der Palette. --p-* ohne "#" sind RGB-Tripel, damit rgba(var(--p-…),.5) geht. */
|
||||
:root[data-design="aero"]{
|
||||
--p-akzent:64,126,232; --p-tief:38,88,190; --p-akzent2:104,196,250; --p-hell:143,216,255;
|
||||
--p-linie:148,175,255; --p-win:10,14,26; --p-surface:13,20,40; --p-surface2:16,26,53; --p-schatten:2,4,10;
|
||||
--p-akzent-hover:#4f8df0; --p-tief-hover:#2c63cc; --p-aktiv:#0b1226; --p-konsole:#03050a;
|
||||
--win:#0a0e1a; --area:#05070d; --bar:#0d1428; --surface:#0d1428; --surface2:#101a35; --input:#070b16;
|
||||
--text:#e8ecfb; --dim:#93a0c4; --link:#8fd8ff;
|
||||
}
|
||||
:root[data-design="lila"]{
|
||||
--p-akzent:139,92,246; --p-tief:109,40,217; --p-akzent2:192,132,252; --p-hell:232,190,255;
|
||||
--p-linie:196,165,255; --p-win:15,10,26; --p-surface:24,15,41; --p-surface2:32,20,56; --p-schatten:6,3,12;
|
||||
--p-akzent-hover:#9d72ff; --p-tief-hover:#7c3aed; --p-aktiv:#140c24; --p-konsole:#050309;
|
||||
--win:#0f0a1a; --area:#08050f; --bar:#180f29; --surface:#180f29; --surface2:#201438; --input:#0b0715;
|
||||
--text:#f0eafb; --dim:#a99cc6; --link:#e8beff;
|
||||
}
|
||||
:root:is([data-design="aero"],[data-design="lila"]){
|
||||
--border:rgba(var(--p-linie),.14); --border2:rgba(var(--p-linie),.09);
|
||||
--sel:rgba(var(--p-akzent),.20); --sel-br:var(--p-akzent-hover); --accent:rgb(var(--p-akzent));
|
||||
--danger:#ff7a8a; --play:#4ade80;
|
||||
--cyan:rgb(var(--p-hell)); --cyan-soft:rgb(var(--p-akzent2));
|
||||
--stat-bar:rgb(var(--p-akzent2));
|
||||
--titel-bg:var(--win); --titel-fg:var(--text);
|
||||
}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) ::selection{background:rgb(var(--p-akzent));color:#fff}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .titel-text{font-weight:600;background:linear-gradient(120deg,rgb(var(--p-hell)),rgb(var(--p-akzent)) 70%);-webkit-background-clip:text;background-clip:text;color:transparent}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) body{background:var(--area)}
|
||||
|
||||
/* Werkzeugleiste */
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .toolbar{background:rgba(var(--p-win),.94);border-bottom:1px solid var(--border);padding:7px 8px;gap:2px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .tbtn{border-radius:999px;padding:6px 10px;color:var(--text)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .tbtn:hover{background:var(--surface);border-color:var(--border)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .tbtn:active{background:var(--surface2)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .tbtn svg,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) #btn-new svg,:root:is([data-design="aero"],[data-design="lila"]) #btn-import svg,:root:is([data-design="aero"],[data-design="lila"]) #btn-open-dir svg,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) #btn-console svg,:root:is([data-design="aero"],[data-design="lila"]) #btn-account svg,:root:is([data-design="aero"],[data-design="lila"]) #btn-settings svg,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .acct-av svg{color:var(--cyan-soft)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .tbsep{background:var(--border)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .search-wrap input{border-radius:999px;padding:5px 12px;width:150px}
|
||||
|
||||
/* Instanzliste: Raster und blaues Leuchten wie im Kopf der Webseite */
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .workspace{background:var(--area)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .list-area{background:
|
||||
radial-gradient(520px 260px at 32% -60px,rgba(var(--p-akzent),.30),transparent 70%),
|
||||
linear-gradient(to right,rgba(var(--p-linie),.05) 1px,transparent 1px) 0 0/44px 44px,
|
||||
linear-gradient(to bottom,rgba(var(--p-linie),.05) 1px,transparent 1px) 0 0/44px 44px,
|
||||
var(--area)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .group-header{color:var(--text);padding:8px 4px 4px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .group-header .chev{color:var(--cyan-soft)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .group-header::after{background:linear-gradient(to right,rgba(var(--p-linie),.22),rgba(var(--p-linie),.04))}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .group-grid{gap:6px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .card{border-radius:14px;padding:8px 4px 6px;transition:background .15s,border-color .15s,box-shadow .15s}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .card:hover{background:rgba(var(--p-surface),.85);border-color:var(--border)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .card.sel{background:linear-gradient(180deg,rgba(var(--p-akzent),.24),rgba(var(--p-tief),.14));border-color:rgba(var(--p-akzent2),.55);box-shadow:0 10px 28px -14px rgba(var(--p-akzent),.95),0 0 0 1px rgba(var(--p-hell),.08) inset}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .card.sel .card-name{background:linear-gradient(120deg,rgb(var(--p-akzent2)),rgb(var(--p-akzent)) 60%,rgb(var(--p-tief)));color:#fff;border-radius:999px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .card-icon-img{border-radius:10px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .card-taste{border-radius:999px;background:linear-gradient(120deg,rgb(var(--p-akzent2)),rgb(var(--p-akzent)))}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .empty h2{background:linear-gradient(120deg,rgb(var(--p-hell)),rgb(var(--p-akzent)) 60%,rgb(var(--p-tief)));-webkit-background-clip:text;background-clip:text;color:transparent;font-size:26px}
|
||||
|
||||
/* Seitenleiste */
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .side{background:var(--win);border-left:1px solid var(--border);padding:10px 6px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .side-ico img{border-radius:12px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .side-grp{color:var(--cyan-soft)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .hr{background:var(--border);margin:8px 4px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .sbtn{border-radius:999px;margin-bottom:1px;padding:5px 2px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .sbtn:hover{background:var(--surface);border-color:var(--border)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .sbtn.play{color:#fff;background:linear-gradient(180deg,rgb(var(--p-akzent)),rgb(var(--p-tief)));border-color:transparent;box-shadow:0 0 0 1px rgba(255,255,255,.08) inset,0 10px 24px -12px rgba(var(--p-akzent),.95);padding:7px 4px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .sbtn.play:hover{background:linear-gradient(180deg,var(--p-akzent-hover),var(--p-tief-hover))}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .sbtn.del:hover{color:var(--danger);border-color:rgba(255,122,138,.35)}
|
||||
|
||||
/* Statusleiste */
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .statusbar{background:var(--win);border-top:1px solid var(--border)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .st-row{color:var(--dim)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .st-row2{background:var(--input);border-top-color:var(--border2)}
|
||||
|
||||
/* Dialoge */
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .modal{background:rgba(var(--p-schatten),.68);backdrop-filter:blur(3px)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .modal-card{background:var(--win);border:1px solid var(--border);border-radius:16px;box-shadow:0 30px 80px -20px rgba(0,0,0,.85),0 0 0 1px rgba(var(--p-hell),.04)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .modal-head{background:linear-gradient(180deg,rgba(var(--p-surface2),.9),rgba(var(--p-win),.9));border-bottom:1px solid var(--border);padding:12px 16px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .modal-body{background:var(--win)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .modal-foot{background:var(--win);border-top:1px solid var(--border);padding:12px 16px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .modal-close{color:var(--dim)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .modal-close:hover{color:var(--cyan)}
|
||||
|
||||
/* Eingabefelder */
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .search-wrap input,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .field input,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .field select,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .field textarea,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .mods-search input,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .mods-search select,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .mods-filters select,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .mmc-bar select,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .clip-length select,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .path-row input,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .se-farbzeile input[type=text],
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .se-feld select{background:var(--input);color:var(--text);border-color:var(--border);border-radius:10px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .search-wrap input{border-radius:999px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .search-wrap input:focus,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .field input:focus,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .field select:focus,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .field textarea:focus,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .mods-search input:focus,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .path-row input:focus{border-color:var(--cyan-soft);box-shadow:0 0 0 3px rgba(var(--p-akzent2),.15)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) input[type=checkbox],:root:is([data-design="aero"],[data-design="lila"]) input[type=radio],:root:is([data-design="aero"],[data-design="lila"]) input[type=range]{accent-color:rgb(var(--p-akzent))}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .login-usercode{background:var(--input);color:var(--text);border-color:var(--border);border-radius:12px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .upd-notes{background:var(--input);border-radius:10px}
|
||||
|
||||
/* Knöpfe – rund wie auf der Webseite */
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .btn{border-radius:999px;padding:7px 15px;background:var(--surface);border-color:var(--border);color:var(--text);transition:background .15s,border-color .15s,transform .15s}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .btn:hover{background:var(--surface2);border-color:rgba(var(--p-linie),.32)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .btn:active{background:var(--p-aktiv)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .btn-primary{background:linear-gradient(180deg,rgb(var(--p-akzent)),rgb(var(--p-tief)));border-color:transparent;color:#fff;box-shadow:0 0 0 1px rgba(255,255,255,.08) inset,0 10px 28px -12px rgba(var(--p-akzent),.9)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .btn-primary:hover{background:linear-gradient(180deg,var(--p-akzent-hover),var(--p-tief-hover));transform:translateY(-1px)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .btn-primary:disabled{transform:none}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .btn-danger{color:var(--danger);border-color:rgba(255,122,138,.35)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .btn-danger:hover{background:rgba(255,122,138,.10);border-color:rgba(255,122,138,.6)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .btn-mini{padding:4px 10px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .badge{background:var(--surface2);color:var(--dim);border-color:var(--border);border-radius:999px}
|
||||
|
||||
/* Listen, Kacheln, Tabs */
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .mods-list,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .account-item,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .screen-thumb{background:var(--input);border-color:var(--border);border-radius:12px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .mod-icon,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .account-av,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .icon-preview{background:var(--surface2);border-radius:8px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .mod-item{border-radius:10px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .mod-item+.mod-item{border-color:var(--border2)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .mod-item:hover{background:var(--surface)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .mtab{border-radius:10px 10px 0 0}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .mtab.on{background:var(--surface);border-color:var(--border);color:var(--cyan)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .advanced{background:var(--surface);border-color:var(--border);border-radius:12px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .console-out{background:var(--p-konsole);border-color:var(--border);border-radius:12px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .stat-tile,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .crash-fund,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .share-code-box,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .share-preview,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .clip-bar,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .wahl-option{border-radius:12px;background:var(--surface)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .chat-verlauf{background:var(--input);border-radius:12px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .chat-blase{background:var(--surface2);border-radius:14px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .chat-blase.ich{background:linear-gradient(180deg,rgb(var(--p-akzent)),rgb(var(--p-tief)));border-color:transparent}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .stat-bar{border-radius:0 6px 6px 0;background:linear-gradient(90deg,rgb(var(--p-akzent)),rgb(var(--p-akzent2)))}
|
||||
|
||||
/* Einstellungen */
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .settings-body{background:var(--area)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .settings-nav{background:var(--win);border-right-color:var(--border)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .snav{border-radius:10px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .snav:hover{background:var(--surface)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .snav.on{background:linear-gradient(120deg,rgba(var(--p-akzent),.30),rgba(var(--p-tief),.18));border-color:rgba(var(--p-akzent2),.40);box-shadow:none}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .settings-card{background:var(--surface);border-color:var(--border);border-radius:16px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .settings-kv-row,
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .about-brand{border-bottom-color:var(--border2)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .appinfo-item{background:rgba(var(--p-linie),.04);border-color:var(--border2);border-radius:12px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .info-meta-link{color:var(--cyan)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .settings-hero h4{background:linear-gradient(120deg,rgb(var(--p-hell)),rgb(var(--p-akzent)) 70%);-webkit-background-clip:text;background-clip:text;color:transparent}
|
||||
|
||||
/* Kontextmenü, Hinweis, Bildlaufleisten */
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .ctx{background:var(--surface);border-color:var(--border);border-radius:12px;box-shadow:0 18px 40px -12px rgba(0,0,0,.8)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .ctx-item{border-radius:8px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .ctx-item:hover{background:rgba(var(--p-akzent),.22)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .toast{background:var(--surface2);border:1px solid var(--border);border-radius:999px;padding:10px 18px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) ::-webkit-scrollbar-thumb{background:rgba(var(--p-linie),.18);border-color:var(--area)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) ::-webkit-scrollbar-thumb:hover{background:rgba(var(--p-linie),.3)}
|
||||
|
||||
/* Skin-Editor */
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .se-modus{border-radius:999px;background:var(--surface)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .se-modus-btn.on{background:linear-gradient(180deg,rgb(var(--p-akzent)),rgb(var(--p-tief)))}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .se-tool,:root:is([data-design="aero"],[data-design="lila"]) .se-ebene{background:var(--surface)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .se-tool{border-radius:10px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .se-ebenen{border-radius:10px}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .se-buehne,:root:is([data-design="aero"],[data-design="lila"]) .se-mini{border-radius:14px;background:var(--input)}
|
||||
:root:is([data-design="aero"],[data-design="lila"]) .design-wahl{border-radius:12px}
|
||||
|
||||
/* ===================================================================== */
|
||||
/* ===================== Design: Minecraft ============================= */
|
||||
/* ===================================================================== */
|
||||
@font-face{font-family:"AeroPixel";src:url(assets/aeropixel.ttf) format("truetype");font-display:block}
|
||||
:root[data-design="minecraft"]{
|
||||
--win:#313233; --area:#1e1e1f; --bar:#48494a;
|
||||
--border:#000; --border2:#1a1a1b;
|
||||
--text:#ffffff; --dim:#b8b9bc;
|
||||
--sel:#2f6b1f; --sel-br:#6cc349; --link:#86d75e; --accent:#3c8527;
|
||||
--danger:#ff5555; --play:#6cc349; --input:#000;
|
||||
--stat-bar:#6cc349;
|
||||
--pixel:"AeroPixel","Segoe UI",sans-serif;
|
||||
--mc-schatten:2px 2px 0 #3f3f3f;
|
||||
}
|
||||
:root[data-design="minecraft"] body{background:var(--area)}
|
||||
:root[data-design="minecraft"] ::selection{background:#3c8527;color:#fff}
|
||||
:root[data-design="minecraft"]{--titel-bg:#1e1e1f;--titel-fg:#ffffff}
|
||||
:root[data-design="minecraft"] .titel-text{font-family:var(--pixel);font-size:16px;text-shadow:var(--mc-schatten);padding-bottom:2px}
|
||||
|
||||
/* Wiederkehrender Block-Knopf: grauer Stein mit hellem/dunklem Rand */
|
||||
:root[data-design="minecraft"] .btn,
|
||||
:root[data-design="minecraft"] .sbtn,
|
||||
:root[data-design="minecraft"] .snav,
|
||||
:root[data-design="minecraft"] .se-tool,
|
||||
:root[data-design="minecraft"] .wahl-option{
|
||||
background:#58595b;color:#fff;border:2px solid #000;border-radius:0;
|
||||
box-shadow:inset 2px 2px 0 #8b8c8f,inset -2px -2px 0 #36373a;
|
||||
text-shadow:1px 1px 0 #2a2a2a}
|
||||
:root[data-design="minecraft"] .btn:hover,
|
||||
:root[data-design="minecraft"] .sbtn:hover,
|
||||
:root[data-design="minecraft"] .snav:hover,
|
||||
:root[data-design="minecraft"] .se-tool:hover:not(:disabled),
|
||||
:root[data-design="minecraft"] .wahl-option:hover{background:#6a6b6f;border-color:#fff;box-shadow:inset 2px 2px 0 #a3a4a8,inset -2px -2px 0 #3e3f42}
|
||||
:root[data-design="minecraft"] .btn:active,
|
||||
:root[data-design="minecraft"] .sbtn:active{background:#48494b;box-shadow:inset -2px -2px 0 #8b8c8f,inset 2px 2px 0 #36373a}
|
||||
:root[data-design="minecraft"] .btn:disabled,
|
||||
:root[data-design="minecraft"] .sbtn:disabled{background:#2b2b2c;color:#8b8b8b;box-shadow:none;border-color:#000;text-shadow:none;opacity:1}
|
||||
:root[data-design="minecraft"] .sbtn:disabled:hover{background:#2b2b2c;border-color:#000}
|
||||
/* grün wie der Spielen-Knopf */
|
||||
:root[data-design="minecraft"] .btn-primary,
|
||||
:root[data-design="minecraft"] .sbtn.play,
|
||||
:root[data-design="minecraft"] .snav.on,
|
||||
:root[data-design="minecraft"] .se-tool.on,
|
||||
:root[data-design="minecraft"] .wahl-option.an{background:#3c8527;color:#fff;box-shadow:inset 2px 2px 0 #6cc349,inset -2px -2px 0 #1d4d13}
|
||||
:root[data-design="minecraft"] .btn-primary:hover,
|
||||
:root[data-design="minecraft"] .sbtn.play:hover{background:#4a9a33;box-shadow:inset 2px 2px 0 #82d65c,inset -2px -2px 0 #24601a;border-color:#fff}
|
||||
:root[data-design="minecraft"] .btn-danger{background:#8c2b2b;box-shadow:inset 2px 2px 0 #c55050,inset -2px -2px 0 #561616}
|
||||
:root[data-design="minecraft"] .btn-danger:hover{background:#a33434;border-color:#fff;box-shadow:inset 2px 2px 0 #d86262,inset -2px -2px 0 #651b1b}
|
||||
:root[data-design="minecraft"] .sbtn.del:hover{background:#8c2b2b;color:#fff;box-shadow:inset 2px 2px 0 #c55050,inset -2px -2px 0 #561616}
|
||||
|
||||
/* Werkzeugleiste: Schiefer mit Grasnarbe */
|
||||
:root[data-design="minecraft"] .toolbar{
|
||||
background:url(assets/design/gras.png) 0 0/32px 8px repeat-x,url(assets/design/schiefer.png) 0 0/64px 64px;
|
||||
image-rendering:pixelated;border-bottom:2px solid #000;padding:11px 8px 6px}
|
||||
:root[data-design="minecraft"] .tbtn{color:#fff;border-radius:0;text-shadow:1px 1px 0 #1a1a1a;image-rendering:auto}
|
||||
:root[data-design="minecraft"] .tbtn:hover{background:rgba(0,0,0,.35);border-color:#fff}
|
||||
:root[data-design="minecraft"] .tbtn:active{background:rgba(0,0,0,.5)}
|
||||
:root[data-design="minecraft"] .tbtn svg,:root[data-design="minecraft"] #btn-console svg,:root[data-design="minecraft"] .acct-av svg{color:#e6e6e6}
|
||||
:root[data-design="minecraft"] #btn-new svg,:root[data-design="minecraft"] #btn-account svg{color:#7fd858}
|
||||
:root[data-design="minecraft"] #btn-import svg{color:#6db8ff}
|
||||
:root[data-design="minecraft"] #btn-open-dir svg{color:#f2c94c}
|
||||
:root[data-design="minecraft"] #btn-settings svg{color:#d0d0d0}
|
||||
:root[data-design="minecraft"] .tbsep{background:#000;width:2px}
|
||||
:root[data-design="minecraft"] .tb-badge{border-radius:0;background:#ff5555;box-shadow:inset -1px -1px 0 #a32a2a}
|
||||
|
||||
/* Eingabefelder: schwarz mit grauem Rand wie im Spiel */
|
||||
:root[data-design="minecraft"] .search-wrap input,
|
||||
:root[data-design="minecraft"] .field input,
|
||||
:root[data-design="minecraft"] .field select,
|
||||
:root[data-design="minecraft"] .field textarea,
|
||||
:root[data-design="minecraft"] .mods-search input,
|
||||
:root[data-design="minecraft"] .mods-search select,
|
||||
:root[data-design="minecraft"] .mods-filters select,
|
||||
:root[data-design="minecraft"] .mmc-bar select,
|
||||
:root[data-design="minecraft"] .clip-length select,
|
||||
:root[data-design="minecraft"] .path-row input,
|
||||
:root[data-design="minecraft"] .login-usercode,
|
||||
:root[data-design="minecraft"] .upd-notes,
|
||||
:root[data-design="minecraft"] .se-farbzeile input[type=text],
|
||||
:root[data-design="minecraft"] .se-feld select{background:#000;color:#fff;border:1px solid #a0a0a0;border-radius:0}
|
||||
:root[data-design="minecraft"] .search-wrap input:focus,
|
||||
:root[data-design="minecraft"] .field input:focus,
|
||||
:root[data-design="minecraft"] .field select:focus,
|
||||
:root[data-design="minecraft"] .field textarea:focus,
|
||||
:root[data-design="minecraft"] .mods-search input:focus,
|
||||
:root[data-design="minecraft"] .path-row input:focus{border-color:#fff;box-shadow:none}
|
||||
:root[data-design="minecraft"] input[type=checkbox],:root[data-design="minecraft"] input[type=radio],:root[data-design="minecraft"] input[type=range]{accent-color:#3c8527}
|
||||
|
||||
/* Instanzliste auf dunkler Erde */
|
||||
:root[data-design="minecraft"] .workspace{background:var(--area)}
|
||||
:root[data-design="minecraft"] .list-area{background:url(assets/design/erde-dunkel.png) 0 0/64px 64px;image-rendering:pixelated}
|
||||
:root[data-design="minecraft"] .list-area::after,
|
||||
:root[data-design="minecraft"] .list{image-rendering:auto}
|
||||
:root[data-design="minecraft"] .group-header{font-family:var(--pixel);font-size:16px;font-weight:400;color:#fff;text-shadow:var(--mc-schatten);padding:8px 4px 4px}
|
||||
:root[data-design="minecraft"] .group-count{color:#b8b9bc}
|
||||
:root[data-design="minecraft"] .group-header .chev{color:#fff;font-family:"Segoe UI",sans-serif;font-size:10px}
|
||||
:root[data-design="minecraft"] .group-header::after{height:2px;background:rgba(0,0,0,.55);box-shadow:0 1px 0 rgba(255,255,255,.08)}
|
||||
:root[data-design="minecraft"] .card{border-radius:0}
|
||||
:root[data-design="minecraft"] .card-name{color:#fff;text-shadow:1px 1px 0 #1a1a1a}
|
||||
:root[data-design="minecraft"] .card:hover{background:rgba(0,0,0,.35);border-color:rgba(255,255,255,.35)}
|
||||
:root[data-design="minecraft"] .card.sel{background:rgba(0,0,0,.6);border-color:#fff;outline:1px solid #fff;outline-offset:-2px}
|
||||
:root[data-design="minecraft"] .card.sel .card-name{background:none;color:#ffff7f;border-radius:0}
|
||||
:root[data-design="minecraft"] .card-taste{border-radius:0;background:#3c8527;box-shadow:inset -1px -1px 0 #1d4d13}
|
||||
:root[data-design="minecraft"] .card-icon-img{border-radius:0}
|
||||
:root[data-design="minecraft"] .empty h2{font-family:var(--pixel);font-weight:400;font-size:24px;color:#fff;text-shadow:3px 3px 0 #3f3f3f}
|
||||
:root[data-design="minecraft"] .empty p{color:#d0d0d0}
|
||||
|
||||
/* Seitenleiste: Knöpfe gestapelt wie im Pausenmenü */
|
||||
:root[data-design="minecraft"] .side{background:url(assets/design/schiefer.png) 0 0/64px 64px;image-rendering:pixelated;border-left:2px solid #000;padding:10px 6px}
|
||||
:root[data-design="minecraft"] .side>*{image-rendering:auto}
|
||||
:root[data-design="minecraft"] .side-title{font-family:var(--pixel);font-size:16px;font-weight:400;text-shadow:var(--mc-schatten)}
|
||||
:root[data-design="minecraft"] .side-grp{color:#86d75e}
|
||||
:root[data-design="minecraft"] .side-ico img{border-radius:0}
|
||||
:root[data-design="minecraft"] .side-empty{color:#d0d0d0}
|
||||
:root[data-design="minecraft"] .hr{background:#000;height:2px;margin:6px 0}
|
||||
:root[data-design="minecraft"] .sbtn{margin-bottom:3px;padding:5px 2px}
|
||||
:root[data-design="minecraft"] .sbtn.play{font-family:var(--pixel);font-size:16px;font-weight:400;padding:6px 4px 7px;text-shadow:var(--mc-schatten)}
|
||||
|
||||
/* Statusleiste */
|
||||
:root[data-design="minecraft"] .statusbar{background:url(assets/design/schiefer.png) 0 0/64px 64px;image-rendering:pixelated;border-top:2px solid #000}
|
||||
:root[data-design="minecraft"] .st-row{color:#e6e6e6;text-shadow:1px 1px 0 #1a1a1a}
|
||||
:root[data-design="minecraft"] .st-row2{background:rgba(0,0,0,.4);border-top:2px solid #000}
|
||||
|
||||
/* Dialoge: dunkles Steinfenster mit Holzbalken als Kopf */
|
||||
:root[data-design="minecraft"] .modal{background:rgba(0,0,0,.62)}
|
||||
:root[data-design="minecraft"] .modal-card{background:#313233;border:2px solid #000;border-radius:0;box-shadow:inset 2px 2px 0 #5a5b5d,inset -2px -2px 0 #1e1e1f,0 10px 30px rgba(0,0,0,.6)}
|
||||
:root[data-design="minecraft"] .modal-head{background:url(assets/design/bretter.png) 0 0/64px 64px;image-rendering:pixelated;border-bottom:2px solid #000;margin:2px 2px 0}
|
||||
:root[data-design="minecraft"] .modal-head h3{font-family:var(--pixel);font-size:16px;font-weight:400;color:#fff;text-shadow:var(--mc-schatten)}
|
||||
:root[data-design="minecraft"] .modal-head>*{image-rendering:auto}
|
||||
:root[data-design="minecraft"] .modal-body{background:#313233;margin:0 2px}
|
||||
:root[data-design="minecraft"] .modal-foot{background:#262627;border-top:2px solid #000;margin:0 2px 2px}
|
||||
:root[data-design="minecraft"] .modal-close{color:#fff;text-shadow:1px 1px 0 #3f3f3f;font-size:16px}
|
||||
:root[data-design="minecraft"] .modal-close:hover{color:#ffff7f}
|
||||
:root[data-design="minecraft"] .popout-host .modal-card{box-shadow:inset 2px 2px 0 #5a5b5d,inset -2px -2px 0 #1e1e1f}
|
||||
|
||||
/* Listen, Kacheln, Tabs */
|
||||
:root[data-design="minecraft"] .mods-list,
|
||||
:root[data-design="minecraft"] .account-item,
|
||||
:root[data-design="minecraft"] .screen-thumb,
|
||||
:root[data-design="minecraft"] .chat-verlauf,
|
||||
:root[data-design="minecraft"] .console-out{background:#000;border:2px solid #000;border-radius:0;box-shadow:inset 1px 1px 0 #3a3a3c}
|
||||
:root[data-design="minecraft"] .account-item{background:#1e1e1f}
|
||||
:root[data-design="minecraft"] .account-item.active{border-color:#6cc349}
|
||||
:root[data-design="minecraft"] .mod-icon,
|
||||
:root[data-design="minecraft"] .account-av,
|
||||
:root[data-design="minecraft"] .icon-preview{background:#48494a;border-radius:0}
|
||||
:root[data-design="minecraft"] .mod-item{border-radius:0}
|
||||
:root[data-design="minecraft"] .mod-item+.mod-item{border-color:#2a2a2b}
|
||||
:root[data-design="minecraft"] .mod-item:hover{background:#262627;outline:1px solid #8b8b8b;outline-offset:-1px}
|
||||
:root[data-design="minecraft"] .mods-tabs{border-bottom:2px solid #000}
|
||||
:root[data-design="minecraft"] .mtab{border-radius:0;color:#c8c8c8;margin-bottom:-2px;border-width:2px}
|
||||
:root[data-design="minecraft"] .mtab.on{background:#48494a;border-color:#000;color:#fff;text-shadow:1px 1px 0 #2a2a2a}
|
||||
:root[data-design="minecraft"] .advanced,
|
||||
:root[data-design="minecraft"] .stat-tile,
|
||||
:root[data-design="minecraft"] .crash-fund,
|
||||
:root[data-design="minecraft"] .share-code-box,
|
||||
:root[data-design="minecraft"] .share-preview,
|
||||
:root[data-design="minecraft"] .clip-bar,
|
||||
:root[data-design="minecraft"] .crash-unklar{background:#262627;border:2px solid #000;border-radius:0;box-shadow:inset 1px 1px 0 #48494a}
|
||||
:root[data-design="minecraft"] .crash-fund{border-left:4px solid #3c8527}
|
||||
:root[data-design="minecraft"] .badge{border-radius:0;background:#48494a;color:#e6e6e6;border-color:#000}
|
||||
:root[data-design="minecraft"] .chat-blase{border-radius:0;background:#48494a;border:2px solid #000}
|
||||
:root[data-design="minecraft"] .chat-blase.ich{background:#3c8527;border-color:#000}
|
||||
:root[data-design="minecraft"] .stat-bar{border-radius:0;box-shadow:inset 0 -2px 0 #3c8527}
|
||||
:root[data-design="minecraft"] .mod-new{border-radius:0}
|
||||
:root[data-design="minecraft"] .friend-avatar{border-radius:0}
|
||||
|
||||
/* Einstellungen */
|
||||
:root[data-design="minecraft"] .settings-body{background:url(assets/design/erde-dunkel.png) 0 0/64px 64px;image-rendering:pixelated}
|
||||
:root[data-design="minecraft"] .settings-body>*{image-rendering:auto}
|
||||
:root[data-design="minecraft"] .settings-nav{background:rgba(0,0,0,.45);border-right:2px solid #000;gap:4px}
|
||||
:root[data-design="minecraft"] .settings-nav-label{color:#d0d0d0;text-shadow:1px 1px 0 #1a1a1a}
|
||||
:root[data-design="minecraft"] .snav{padding:8px 12px}
|
||||
:root[data-design="minecraft"] .settings-hero h4{font-family:var(--pixel);font-size:24px;font-weight:400;text-shadow:3px 3px 0 #3f3f3f}
|
||||
:root[data-design="minecraft"] .settings-hero p{color:#d0d0d0}
|
||||
:root[data-design="minecraft"] .settings-card{background:#313233;border:2px solid #000;border-radius:0;box-shadow:inset 2px 2px 0 #5a5b5d,inset -2px -2px 0 #1e1e1f}
|
||||
:root[data-design="minecraft"] .settings-card h5{font-family:var(--pixel);font-size:16px;font-weight:400;text-shadow:var(--mc-schatten)}
|
||||
:root[data-design="minecraft"] .settings-kv-row,
|
||||
:root[data-design="minecraft"] .about-brand{border-bottom-color:#1a1a1b}
|
||||
:root[data-design="minecraft"] .appinfo-item{background:#262627;border:2px solid #000;border-radius:0}
|
||||
:root[data-design="minecraft"] .info-meta-link{color:#86d75e}
|
||||
:root[data-design="minecraft"] .spane h4{font-family:var(--pixel);font-size:16px;font-weight:400;text-shadow:var(--mc-schatten)}
|
||||
|
||||
/* Kontextmenü, Hinweis, Bildlaufleisten */
|
||||
:root[data-design="minecraft"] .ctx{background:#1e1e1f;border:2px solid #000;border-radius:0;box-shadow:inset 1px 1px 0 #48494a,0 8px 24px rgba(0,0,0,.5)}
|
||||
:root[data-design="minecraft"] .ctx-item{border-radius:0;text-shadow:1px 1px 0 #000}
|
||||
:root[data-design="minecraft"] .ctx-item:hover{background:#3c8527}
|
||||
:root[data-design="minecraft"] .ctx-danger:hover{background:#8c2b2b}
|
||||
:root[data-design="minecraft"] .ctx-sep{background:#000;height:2px}
|
||||
:root[data-design="minecraft"] .toast{background:#212122;border:2px solid #000;border-radius:0;box-shadow:inset 2px 2px 0 #4a4a4c,inset -2px -2px 0 #111,0 6px 20px rgba(0,0,0,.5);text-shadow:1px 1px 0 #000}
|
||||
:root[data-design="minecraft"] .toast.err{background:#5c1a1a}
|
||||
:root[data-design="minecraft"] ::-webkit-scrollbar-thumb{background:#8b8b8b;border:3px solid var(--area);border-radius:0;box-shadow:inset -2px -2px 0 #555}
|
||||
:root[data-design="minecraft"] ::-webkit-scrollbar-thumb:hover{background:#a8a8a8}
|
||||
|
||||
/* Skin-Editor */
|
||||
:root[data-design="minecraft"] .se-modus{border:2px solid #000;border-radius:0;background:#2b2b2c}
|
||||
:root[data-design="minecraft"] .se-modus-btn{color:#d0d0d0;text-shadow:1px 1px 0 #000}
|
||||
:root[data-design="minecraft"] .se-modus-btn+.se-modus-btn{border-left:2px solid #000}
|
||||
:root[data-design="minecraft"] .se-modus-btn.on{background:#3c8527;color:#fff;box-shadow:inset 2px 2px 0 #6cc349,inset -2px -2px 0 #1d4d13}
|
||||
:root[data-design="minecraft"] .se-ebenen{border:2px solid #000;border-radius:0}
|
||||
:root[data-design="minecraft"] .se-ebene{background:#2b2b2c;color:#d0d0d0}
|
||||
:root[data-design="minecraft"] .se-ebene+.se-ebene{border-left:2px solid #000}
|
||||
:root[data-design="minecraft"] .se-ebene.on{background:#3c8527;color:#fff}
|
||||
:root[data-design="minecraft"] .se-buehne,:root[data-design="minecraft"] .se-mini{border:2px solid #000;border-radius:0;background:#1e1e1f}
|
||||
:root[data-design="minecraft"] .se-farbfeld{border-radius:0;border-color:#000}
|
||||
:root[data-design="minecraft"] .se-titel{color:#d0d0d0}
|
||||
:root[data-design="minecraft"] .design-wahl{border-radius:0;border:2px solid #000;background:#262627}
|
||||
:root[data-design="minecraft"] .design-wahl.on{border-color:#fff;box-shadow:none;background:#2f6b1f}
|
||||
:root[data-design="minecraft"] .dv{border-radius:0}
|
||||
+157
-8
@@ -6,8 +6,15 @@
|
||||
content="default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'; img-src 'self' data: https:; connect-src 'self';" />
|
||||
<title>AeroMC</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
<link rel="stylesheet" href="designs.css" />
|
||||
</head>
|
||||
<body>
|
||||
<!-- Eigene Titelleiste (Fensterknöpfe zeichnet Windows rechts darüber) -->
|
||||
<div class="titelleiste">
|
||||
<img src="assets/logo.png" alt="" class="titel-logo" />
|
||||
<span class="titel-text">AeroMC</span>
|
||||
</div>
|
||||
|
||||
<!-- Obere Werkzeugleiste (MultiMC-Stil: Icon + Text) -->
|
||||
<header class="toolbar">
|
||||
<button id="btn-new" class="tbtn" data-ic="plus" title="Neue Instanz (Strg+N)">Instanz hinzufügen</button>
|
||||
@@ -250,14 +257,7 @@
|
||||
</div>
|
||||
<div class="settings-grid">
|
||||
<section class="settings-card">
|
||||
<h5>Oberfläche</h5>
|
||||
<label class="field">
|
||||
<span>Design</span>
|
||||
<select id="s-theme">
|
||||
<option value="dark">Dunkel</option>
|
||||
<option value="light">Hell</option>
|
||||
</select>
|
||||
</label>
|
||||
<h5>Instanzliste</h5>
|
||||
<label class="field">
|
||||
<span>Instanzen sortieren</span>
|
||||
<select id="s-sortby">
|
||||
@@ -323,6 +323,37 @@
|
||||
<p>Optik der Oberfläche und visuelle Extras für die Instanzansicht.</p>
|
||||
</div>
|
||||
<div class="settings-grid">
|
||||
<section class="settings-card settings-card-wide">
|
||||
<h5>Design</h5>
|
||||
<div class="field">
|
||||
<select id="s-theme" class="hidden">
|
||||
<option value="dark">Klassisch – Dunkel</option>
|
||||
<option value="light">Klassisch – Hell</option>
|
||||
<option value="aero">AeroMC</option>
|
||||
<option value="lila">Nachtlila</option>
|
||||
<option value="minecraft">Minecraft</option>
|
||||
</select>
|
||||
<div class="design-raster">
|
||||
<button type="button" class="design-wahl" data-design="dark" title="Der bewährte Launcher-Look in Dunkelgrau">
|
||||
<span class="dv dv-dark"><i></i><b></b><em></em></span><small>Klassisch Dunkel</small>
|
||||
</button>
|
||||
<button type="button" class="design-wahl" data-design="light" title="Der bewährte Launcher-Look in Hell">
|
||||
<span class="dv dv-light"><i></i><b></b><em></em></span><small>Klassisch Hell</small>
|
||||
</button>
|
||||
<button type="button" class="design-wahl" data-design="aero" title="Nachtblau mit Cyan-Akzenten – wie die AeroMC-Webseite">
|
||||
<span class="dv dv-aero"><i></i><b></b><em></em></span><small>AeroMC</small>
|
||||
</button>
|
||||
<button type="button" class="design-wahl" data-design="lila" title="Wie AeroMC, nur in dunklem Lila">
|
||||
<span class="dv dv-lila"><i></i><b></b><em></em></span><small>Nachtlila</small>
|
||||
</button>
|
||||
<button type="button" class="design-wahl" data-design="minecraft" title="Block-Optik wie im Spiel">
|
||||
<span class="dv dv-mc"><i></i><b></b><em></em></span><small>Minecraft</small>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<small class="hint">Ein Klick zeigt das Design sofort an – mit „Speichern“ gilt es in allen Fenstern.</small>
|
||||
</section>
|
||||
|
||||
<section class="settings-card">
|
||||
<h5>Icons</h5>
|
||||
<label class="checkbox-field">
|
||||
@@ -350,6 +381,14 @@
|
||||
<option value="spooky">Unheimlich</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>Armform</span>
|
||||
<select id="s-bgskin-model" title="Bei „Automatisch“ wird die Armform übernommen, die beim Konto eingestellt ist">
|
||||
<option value="auto">Automatisch (vom Konto)</option>
|
||||
<option value="classic">Normal (breite Arme, Steve)</option>
|
||||
<option value="slim">Schmal (Alex)</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>Deckkraft: <span id="s-bgskin-val">55</span> %</span>
|
||||
<input id="s-bgskin-opacity" type="range" min="10" max="100" step="5" />
|
||||
@@ -1213,6 +1252,7 @@
|
||||
</div>
|
||||
<div class="modal-foot">
|
||||
<button id="skin-reset" class="btn btn-danger">Auf Standard zurücksetzen</button>
|
||||
<button id="skin-editor" class="btn" title="Skin selbst pixeln – mit Grundschicht und 2. Schicht">Im Editor bearbeiten…</button>
|
||||
<div class="spacer"></div>
|
||||
<button class="btn" data-close>Schließen</button>
|
||||
<button id="skin-apply" class="btn btn-primary" disabled>Skin setzen</button>
|
||||
@@ -1220,6 +1260,86 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===================== Dialog: Skin-Editor ===================== -->
|
||||
<div id="modal-skineditor" class="modal hidden">
|
||||
<div class="modal-card se-karte">
|
||||
<div class="modal-head">
|
||||
<h3>Skin-Editor</h3>
|
||||
<div class="se-modus">
|
||||
<button class="se-modus-btn on" data-se-modus="2d" title="Auf der aufgeklappten Vorlage malen">2D-Vorlage</button>
|
||||
<button class="se-modus-btn" data-se-modus="3d" title="Direkt auf der drehbaren Figur malen">3D-Figur</button>
|
||||
</div>
|
||||
<button class="modal-close" data-close>✕</button>
|
||||
</div>
|
||||
<div class="modal-body se-body">
|
||||
<aside class="se-werkzeuge">
|
||||
<div class="se-gruppe">
|
||||
<div class="se-titel">Werkzeug</div>
|
||||
<div class="se-tools">
|
||||
<button class="se-tool on" data-se-tool="stift" title="Stift (B)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20h4L18 10l-4-4L4 16v4zM14 6l4 4"/></svg><span>Stift</span></button>
|
||||
<button class="se-tool" data-se-tool="radierer" title="Radierer (E)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 20h12M5.5 14.5l8-8a2 2 0 012.8 0l2.2 2.2a2 2 0 010 2.8L11 19H8.5l-3-3a1.1 1.1 0 010-1.5zM9 11l5 5"/></svg><span>Radierer</span></button>
|
||||
<button class="se-tool" data-se-tool="pipette" title="Pipette (I) – auch Alt+Klick"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 7l3 3M5 19l1-4 8.5-8.5a2.1 2.1 0 013 3L9 18l-4 1zM15.5 5.5l1.5-1.5a2.1 2.1 0 013 3l-1.5 1.5"/></svg><span>Pipette</span></button>
|
||||
<button class="se-tool" data-se-tool="fuellen" title="Füllen (G) – färbt gleichfarbige Pixel einer Seite"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 11l7-7 7 7-7 7zM5 11h14M20 16s1.5 2 1.5 3a1.5 1.5 0 01-3 0c0-1 1.5-3 1.5-3z"/></svg><span>Füllen</span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="se-gruppe">
|
||||
<div class="se-titel">Farbe</div>
|
||||
<div class="se-farbzeile">
|
||||
<input id="se-farbe" type="color" value="#3a6ea5" title="Farbe wählen" />
|
||||
<input id="se-hex" type="text" maxlength="7" spellcheck="false" value="#3a6ea5" />
|
||||
</div>
|
||||
<div id="se-zuletzt" class="se-zuletzt"></div>
|
||||
</div>
|
||||
<div class="se-gruppe">
|
||||
<div class="se-titel">Ebene</div>
|
||||
<div class="se-ebenen">
|
||||
<button class="se-ebene on" data-se-schicht="0" title="Die eigentliche Figur (L wechselt)">Grundschicht</button>
|
||||
<button class="se-ebene" data-se-schicht="1" title="Hülle über der Figur – Haare, Jacke, Ärmel … (L wechselt)">2. Schicht</button>
|
||||
</div>
|
||||
<label class="se-check"><input id="se-aussen" type="checkbox" checked /> 2. Schicht zeigen</label>
|
||||
<label class="se-check"><input id="se-durch" type="checkbox" checked /> Grundschicht durchscheinen</label>
|
||||
<button id="se-leeren" class="btn btn-mini">2. Schicht leeren</button>
|
||||
</div>
|
||||
<div class="se-gruppe">
|
||||
<div class="se-titel">Optionen</div>
|
||||
<label class="se-check" title="Malt gleichzeitig auf der anderen Körperseite (M)"><input id="se-spiegeln" type="checkbox" /> Spiegeln (links ↔ rechts)</label>
|
||||
<label class="se-feld"><span>Armform</span>
|
||||
<select id="se-variante">
|
||||
<option value="classic">Klassisch (Steve)</option>
|
||||
<option value="slim">Schmal (Alex)</option>
|
||||
</select>
|
||||
</label>
|
||||
<div class="se-undo">
|
||||
<button id="se-undo" class="btn btn-mini" title="Rückgängig (Strg+Z)" disabled>↶ Rückgängig</button>
|
||||
<button id="se-redo" class="btn btn-mini" title="Wiederholen (Strg+Y)" disabled>↷ Wiederholen</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<section class="se-mitte">
|
||||
<div id="se-buehne" class="se-buehne">
|
||||
<div id="se-2d" class="se-ansicht se-2d"><canvas id="se-2d-canvas"></canvas></div>
|
||||
</div>
|
||||
<div id="se-info" class="se-info hint"></div>
|
||||
</section>
|
||||
<aside class="se-seite">
|
||||
<div id="se-mini-titel" class="se-titel">3D-Vorschau</div>
|
||||
<div id="se-mini" class="se-mini">
|
||||
<div id="se-3d" class="se-ansicht se-3d"><canvas id="se-3d-canvas"></canvas><span id="se-3d-leer" class="hint se-3d-leer">wird geladen …</span></div>
|
||||
</div>
|
||||
<p class="hint se-tipp">Beide Ansichten sind bemalbar. Die <b>2. Schicht</b> liegt wie eine Hülle über der Figur – lässt man Pixel darin frei, wirken Haare, Kapuzen oder Ärmel plastisch.</p>
|
||||
</aside>
|
||||
</div>
|
||||
<div class="modal-foot se-fuss">
|
||||
<button id="se-neu" class="btn" title="Mit einer leeren Vorlage beginnen">Neu</button>
|
||||
<button id="se-laden" class="btn" title="Den Skin deines angemeldeten Kontos laden">Aktuellen Skin laden</button>
|
||||
<button id="se-oeffnen" class="btn">PNG öffnen…</button>
|
||||
<button id="se-speichern" class="btn">Als PNG speichern…</button>
|
||||
<span id="se-status" class="hint se-status"></span>
|
||||
<button id="se-uebernehmen" class="btn btn-primary">Als Skin übernehmen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===================== Dialog: Logdateien ===================== -->
|
||||
<div id="modal-logs" class="modal hidden">
|
||||
<div class="modal-card modal-lg">
|
||||
@@ -1364,6 +1484,7 @@
|
||||
<button id="import-tab-modpack" class="mtab" data-kind="modpack">Modpack</button>
|
||||
<button id="import-tab-mc" class="mtab" data-kind="mc">Minecraft Launcher</button>
|
||||
<button id="import-tab-cf" class="mtab" data-kind="cf">CurseForge</button>
|
||||
<button id="import-tab-mr" class="mtab" data-kind="mr">Modrinth App</button>
|
||||
<button id="import-tab-mmc" class="mtab" data-kind="mmc">MultiMC / Prism</button>
|
||||
<button id="import-tab-technic" class="mtab" data-kind="technic">Technic</button>
|
||||
<button id="import-tab-code" class="mtab" data-kind="code">Per Code</button>
|
||||
@@ -1460,6 +1581,31 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="import-pane-mr" class="import-pane hidden">
|
||||
<label class="field">
|
||||
<span>Datenordner der Modrinth App</span>
|
||||
<div class="path-row">
|
||||
<input id="mr-path" type="text" placeholder="leer lassen = Standardort (%APPDATA%\ModrinthApp)" />
|
||||
<button id="mr-pick" class="btn">Wählen…</button>
|
||||
<button id="mr-scan" class="btn btn-primary">Suchen</button>
|
||||
</div>
|
||||
<small id="mr-status" class="hint">Leer lassen nutzt automatisch den Standardort der Modrinth App.</small>
|
||||
</label>
|
||||
|
||||
<div id="mr-result" class="hidden">
|
||||
<div class="mmc-bar">
|
||||
<label class="checkbox-field" style="margin:0">
|
||||
<input id="mr-all" type="checkbox" checked /> <span>Alle auswählen</span>
|
||||
</label>
|
||||
<label class="checkbox-field" style="margin:0">
|
||||
<input id="mr-copy" type="checkbox" checked /> <span>Spieldaten mitkopieren (Welten, Mods, Konfiguration)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div id="mr-list" class="mods-list"></div>
|
||||
<p class="hint" style="margin-top:8px">Übernommen werden Name, Gruppe, Symbol, Minecraft-Version, Loader, Arbeitsspeicher, Java-Einstellungen und die Spielzeit. Modrinth-Modpacks bleiben mit ihrem Paket verknüpft und lassen sich in AeroMC weiter aktualisieren.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="import-pane-mmc" class="import-pane hidden">
|
||||
<label class="field">
|
||||
<span>MultiMC- oder Prism-Ordner</span>
|
||||
@@ -1540,6 +1686,7 @@
|
||||
<div id="mc-progress" class="hint hidden"></div>
|
||||
<div id="mmc-progress" class="hint hidden"></div>
|
||||
<div id="cf-progress" class="hint hidden"></div>
|
||||
<div id="mr-progress" class="hint hidden"></div>
|
||||
<div id="technic-progress" class="hint hidden"></div>
|
||||
<div id="code-progress" class="hint hidden"></div>
|
||||
<div class="spacer"></div>
|
||||
@@ -1548,6 +1695,7 @@
|
||||
<button id="import-modpack-do" class="btn btn-primary hidden">Modpack wählen…</button>
|
||||
<button id="mc-do" class="btn btn-primary hidden" disabled>Übernehmen</button>
|
||||
<button id="cf-do" class="btn btn-primary hidden" disabled>Übernehmen</button>
|
||||
<button id="mr-do" class="btn btn-primary hidden" disabled>Übernehmen</button>
|
||||
<button id="mmc-do" class="btn btn-primary hidden" disabled>Übernehmen</button>
|
||||
<button id="technic-do" class="btn btn-primary hidden" disabled>Übernehmen</button>
|
||||
<button id="code-do" class="btn btn-primary hidden" disabled>Instanz anlegen</button>
|
||||
@@ -1656,5 +1804,6 @@
|
||||
<canvas id="skin-canvas" width="420" height="700" style="display:none"></canvas>
|
||||
<script src="vendor/skinview3d.js"></script>
|
||||
<script src="renderer.js"></script>
|
||||
<script src="skineditor.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+211
-8
@@ -29,6 +29,7 @@ const bedrock = require('./bedrock');
|
||||
const backup = require('./backup');
|
||||
const mmcimport = require('./mmcimport');
|
||||
const cfimport = require('./cfimport');
|
||||
const mrimport = require('./mrimport');
|
||||
const mcimport = require('./mcimport');
|
||||
const technicimport = require('./technicimport');
|
||||
const technicdiscover = require('./technicdiscover');
|
||||
@@ -112,6 +113,7 @@ const POPOUT_SPEC = {
|
||||
screens: { title: 'AeroMC – Bildschirmfotos', width: 860, height: 680, minWidth: 640, minHeight: 480 },
|
||||
servers: { title: 'AeroMC – Server', width: 860, height: 680, minWidth: 640, minHeight: 480 },
|
||||
skin: { title: 'AeroMC – Skin', width: 860, height: 680, minWidth: 640, minHeight: 480 },
|
||||
skineditor: { title: 'AeroMC – Skin-Editor', width: 1180, height: 800, minWidth: 920, minHeight: 600 },
|
||||
bedrock: { title: 'AeroMC – Bedrock', width: 860, height: 680, minWidth: 640, minHeight: 480 },
|
||||
login: { title: 'AeroMC – Konten', width: 460, height: 460, minWidth: 420, minHeight: 380 },
|
||||
import: { title: 'AeroMC – Import', width: 860, height: 680, minWidth: 640, minHeight: 480 },
|
||||
@@ -171,7 +173,7 @@ function openPopout(modalId, params) {
|
||||
minWidth: spec.minWidth,
|
||||
minHeight: spec.minHeight,
|
||||
title: spec.title || POPOUT_DEFAULT.title,
|
||||
backgroundColor: '#1b1e24',
|
||||
backgroundColor: fensterFarbe(),
|
||||
icon: windowIcon(),
|
||||
frame: false, // eigener dunkler Kopfbereich (Titel + ✕) ersetzt die native Titelleiste
|
||||
show: false,
|
||||
@@ -211,6 +213,12 @@ ipcMain.on('recording:guard', (_e, active) => { recordingGuardActive = !!active;
|
||||
|
||||
ipcMain.on('debug:rendererError', (_e, msg) => console.error('[Renderer-Fehler]', msg));
|
||||
ipcMain.on('popout:open', (_e, modalId, params) => openPopout(modalId, params));
|
||||
// Design gewechselt -> Fensterknöpfe oben rechts umfärben (nur Hauptfenster,
|
||||
// die Popup-Fenster haben ihren eigenen Kopf)
|
||||
ipcMain.on('window:titleBar', (e, design) => {
|
||||
if (!mainWindow || mainWindow.isDestroyed() || e.sender !== mainWindow.webContents) return;
|
||||
try { mainWindow.setTitleBarOverlay(titelleistenFarben(design)); } catch { /* ältere Windows-Fassung */ }
|
||||
});
|
||||
ipcMain.on('popout:hide', (e) => {
|
||||
const w = BrowserWindow.fromWebContents(e.sender);
|
||||
if (w && !w.isDestroyed()) w.hide();
|
||||
@@ -714,6 +722,28 @@ function verknuepfungsIcon(ziel) {
|
||||
return windowIcon() || ziel;
|
||||
}
|
||||
|
||||
// Eigene Titelleiste im Hauptfenster: Minimieren/Maximieren/Schließen bleiben
|
||||
// echte Windows-Knöpfe (Andocken, Fensterlayouts …), Windows zeichnet sie aber
|
||||
// in den Farben des Designs. Die Farben müssen zu --titel-bg/--titel-fg in
|
||||
// styles.css bzw. designs.css passen.
|
||||
const TITELLEISTE = {
|
||||
dark: { color: '#2d2d30', symbolColor: '#e4e4e6' },
|
||||
light: { color: '#f0f0f0', symbolColor: '#1c1c1c' },
|
||||
aero: { color: '#0a0e1a', symbolColor: '#e8ecfb' },
|
||||
lila: { color: '#0f0a1a', symbolColor: '#f0eafb' },
|
||||
minecraft: { color: '#1e1e1f', symbolColor: '#ffffff' },
|
||||
};
|
||||
function titelleistenFarben(design) {
|
||||
return Object.assign({ height: 32 }, TITELLEISTE[design] || TITELLEISTE.dark);
|
||||
}
|
||||
|
||||
// Grundfarbe eines neuen Fensters passend zum Design – sonst blitzt beim
|
||||
// Öffnen kurz die falsche Farbe auf, bis die Oberfläche gezeichnet ist
|
||||
function fensterFarbe() {
|
||||
const design = (store.getSettings() || {}).theme;
|
||||
return { light: '#f0f0f0', aero: '#05070d', lila: '#08050f', minecraft: '#313233' }[design] || '#1b1e24';
|
||||
}
|
||||
|
||||
function windowIcon() {
|
||||
const png = path.join(__dirname, 'assets', 'logo.png');
|
||||
const ico = path.join(__dirname, 'assets', 'icon.ico');
|
||||
@@ -728,10 +758,12 @@ function createWindow(startHidden) {
|
||||
height: 820,
|
||||
minWidth: 940,
|
||||
minHeight: 640,
|
||||
backgroundColor: '#1b1e24',
|
||||
backgroundColor: fensterFarbe(),
|
||||
title: 'AeroMC',
|
||||
icon: windowIcon(),
|
||||
autoHideMenuBar: true,
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay: titelleistenFarben((store.getSettings() || {}).theme),
|
||||
show: !startHidden,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
@@ -800,7 +832,7 @@ function oeffneVorbereitetenImport() {
|
||||
try {
|
||||
const daten = JSON.parse(fs.readFileSync(datei, 'utf8').replace(/^/, ''));
|
||||
quellen = (Array.isArray(daten.sources) ? daten.sources : [])
|
||||
.filter((q) => q && ['mc', 'cf', 'mmc', 'technic'].includes(q.kind))
|
||||
.filter((q) => q && ['mc', 'cf', 'mr', 'mmc', 'technic'].includes(q.kind))
|
||||
.map((q) => ({ kind: q.kind, path: typeof q.path === 'string' ? q.path : '' }));
|
||||
} catch { /* beschädigt -> verwerfen */ }
|
||||
try { fs.unlinkSync(datei); } catch { /* egal */ }
|
||||
@@ -1028,9 +1060,8 @@ ipcMain.handle('settings:save', (_e, patch) => {
|
||||
// (die speichert bei jedem Klick auf eine Instanz mit) – sonst baut das
|
||||
// Hauptfenster bei jedem Klick seine ganze Liste neu auf und die flackert.
|
||||
const nurLetzteInstanz = patch && Object.keys(patch).every((k) => k === 'lastSelectedId');
|
||||
if (!nurLetzteInstanz && mainWindow && !mainWindow.isDestroyed()) {
|
||||
mainWindow.webContents.send('settings:changed', s);
|
||||
}
|
||||
// an alle Fenster: das Design muss auch in offenen Popup-Fenstern wechseln
|
||||
if (!nurLetzteInstanz) broadcast('settings:changed', s);
|
||||
return s;
|
||||
});
|
||||
|
||||
@@ -1733,6 +1764,30 @@ async function aktivesToken() {
|
||||
return acc && acc.mcAccessToken ? acc.mcAccessToken : null;
|
||||
}
|
||||
|
||||
// Armform (breit/schmal) eines beliebigen Kontos – steht in den Textur-Angaben
|
||||
// des öffentlichen Profils bei Mojang (SKIN.metadata.model = "slim").
|
||||
// Ergebnis 10 Minuten merken, nach eigenen Skin-Änderungen sofort verwerfen.
|
||||
const armformCache = new Map(); // uuid -> { modell, zeit }
|
||||
ipcMain.handle('skin:modelFor', async (_e, uuid) => {
|
||||
const id = String(uuid || '').replace(/-/g, '').toLowerCase();
|
||||
if (!/^[0-9a-f]{32}$/.test(id)) return 'classic';
|
||||
const gemerkt = armformCache.get(id);
|
||||
if (gemerkt && Date.now() - gemerkt.zeit < 10 * 60 * 1000) return gemerkt.modell;
|
||||
try {
|
||||
const res = await fetch('https://sessionserver.mojang.com/session/minecraft/profile/' + id, { headers: { 'User-Agent': 'AeroMC-Launcher' } });
|
||||
if (!res.ok) return gemerkt ? gemerkt.modell : 'classic';
|
||||
const profil = await res.json();
|
||||
const eigenschaft = (profil.properties || []).find((p) => p.name === 'textures');
|
||||
const texturen = eigenschaft ? JSON.parse(Buffer.from(eigenschaft.value, 'base64').toString('utf8')) : {};
|
||||
const skin = texturen.textures && texturen.textures.SKIN;
|
||||
const modell = skin && skin.metadata && skin.metadata.model === 'slim' ? 'slim' : 'classic';
|
||||
armformCache.set(id, { modell, zeit: Date.now() });
|
||||
return modell;
|
||||
} catch {
|
||||
return gemerkt ? gemerkt.modell : 'classic';
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('skin:profile', async () => {
|
||||
const token = await aktivesToken();
|
||||
if (!token) return { ok: false, message: 'Kein angemeldetes Konto.' };
|
||||
@@ -1764,7 +1819,7 @@ ipcMain.handle('skin:apply', async (_e, dateiPfad, variante) => {
|
||||
if (!token) return { ok: false, message: 'Kein angemeldetes Konto.' };
|
||||
try {
|
||||
const res = await skins.setzeSkin(token, dateiPfad, variante);
|
||||
if (res && res.ok) broadcast('skin:changed');
|
||||
if (res && res.ok) { armformCache.clear(); broadcast('skin:changed'); }
|
||||
return res;
|
||||
}
|
||||
catch (err) { return { ok: false, message: 'Skin konnte nicht gesetzt werden: ' + err.message }; }
|
||||
@@ -1775,11 +1830,78 @@ ipcMain.handle('skin:reset', async () => {
|
||||
if (!token) return { ok: false, message: 'Kein angemeldetes Konto.' };
|
||||
try {
|
||||
const res = await skins.setzeSkinZurueck(token);
|
||||
if (res && res.ok) broadcast('skin:changed');
|
||||
if (res && res.ok) { armformCache.clear(); broadcast('skin:changed'); }
|
||||
return res;
|
||||
}
|
||||
catch (err) { return { ok: false, message: 'Zurücksetzen fehlgeschlagen: ' + err.message }; }
|
||||
});
|
||||
|
||||
// ---------- Skin-Editor ----------
|
||||
// Der Editor malt in eine Canvas – fremde Bildadressen (textures.minecraft.net)
|
||||
// würden sie "verunreinigen" und das Auslesen der Pixel verbieten. Deshalb holt
|
||||
// der Hauptprozess die Datei und reicht sie als data:-Adresse weiter.
|
||||
const PNG_KENNUNG = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
||||
function skinPngAusBase64(base64) {
|
||||
const daten = Buffer.from(String(base64 || ''), 'base64');
|
||||
if (daten.length < 33 || !daten.subarray(0, 8).equals(PNG_KENNUNG)) return null;
|
||||
if (daten.readUInt32BE(16) !== 64 || daten.readUInt32BE(20) !== 64) return null;
|
||||
return daten;
|
||||
}
|
||||
|
||||
ipcMain.handle('skin:currentData', async () => {
|
||||
const token = await aktivesToken();
|
||||
if (!token) return { ok: false, message: 'Kein angemeldetes Konto.' };
|
||||
try {
|
||||
const p = await skins.holeProfil(token);
|
||||
if (!p.ok) return p;
|
||||
if (!p.skinUrl) return { ok: false, standard: true, variante: p.variante, message: 'Das Konto nutzt den Standard-Skin.' };
|
||||
const res = await fetch(p.skinUrl);
|
||||
if (!res.ok) return { ok: false, message: 'Skin-Datei nicht abrufbar (HTTP ' + res.status + ').' };
|
||||
const daten = Buffer.from(await res.arrayBuffer());
|
||||
return { ok: true, name: p.name, variante: p.variante, dataUri: 'data:image/png;base64,' + daten.toString('base64') };
|
||||
} catch (err) {
|
||||
return { ok: false, message: 'Skin konnte nicht geladen werden: ' + err.message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('skin:readData', (_e, dateiPfad) => {
|
||||
const geprueft = skins.pruefeDatei(dateiPfad);
|
||||
if (!geprueft.ok) return geprueft;
|
||||
try { return { ok: true, dataUri: 'data:image/png;base64,' + fs.readFileSync(dateiPfad).toString('base64') }; }
|
||||
catch (err) { return { ok: false, message: 'Datei nicht lesbar: ' + err.message }; }
|
||||
});
|
||||
|
||||
ipcMain.handle('skin:saveData', async (e, base64) => {
|
||||
const daten = skinPngAusBase64(base64);
|
||||
if (!daten) return { ok: false, message: 'Ungültige Skin-Daten.' };
|
||||
const res = await dialog.showSaveDialog(BrowserWindow.fromWebContents(e.sender) || mainWindow, {
|
||||
title: 'Skin speichern',
|
||||
defaultPath: path.join(app.getPath('pictures'), 'skin.png'),
|
||||
filters: [{ name: 'PNG-Bild', extensions: ['png'] }],
|
||||
});
|
||||
if (res.canceled || !res.filePath) return { ok: false, canceled: true };
|
||||
try { fs.writeFileSync(res.filePath, daten); return { ok: true, pfad: res.filePath }; }
|
||||
catch (err) { return { ok: false, message: 'Speichern fehlgeschlagen: ' + err.message }; }
|
||||
});
|
||||
|
||||
ipcMain.handle('skin:applyData', async (_e, base64, variante) => {
|
||||
const daten = skinPngAusBase64(base64);
|
||||
if (!daten) return { ok: false, message: 'Ungültige Skin-Daten.' };
|
||||
const token = await aktivesToken();
|
||||
if (!token) return { ok: false, message: 'Kein angemeldetes Konto.' };
|
||||
const tmp = path.join(app.getPath('temp'), 'aeromc-skin-editor.png');
|
||||
try {
|
||||
fs.writeFileSync(tmp, daten);
|
||||
const res = await skins.setzeSkin(token, tmp, variante);
|
||||
if (res && res.ok) { armformCache.clear(); broadcast('skin:changed', { quelle: 'editor' }); }
|
||||
return res;
|
||||
} catch (err) {
|
||||
return { ok: false, message: 'Skin konnte nicht gesetzt werden: ' + err.message };
|
||||
} finally {
|
||||
try { fs.unlinkSync(tmp); } catch { /* egal */ }
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('auth:remove', (_e, id) => auth.removeAccount(id));
|
||||
ipcMain.handle('auth:logout', () => { auth.clearAccount(); return true; });
|
||||
|
||||
@@ -3732,6 +3854,87 @@ ipcMain.handle('cf:import', (_e, entries, copyData) => {
|
||||
return { ok: true, imported: done, failed };
|
||||
});
|
||||
|
||||
// ---------- Modrinth App ----------
|
||||
ipcMain.handle('mr:pickFolder', async (e) => {
|
||||
const res = await dialog.showOpenDialog(BrowserWindow.fromWebContents(e.sender) || mainWindow, {
|
||||
title: 'Datenordner der Modrinth App wählen (meist %APPDATA%\\ModrinthApp)',
|
||||
defaultPath: mrimport.standardOrdner(),
|
||||
properties: ['openDirectory'],
|
||||
});
|
||||
return res.canceled ? null : res.filePaths[0];
|
||||
});
|
||||
|
||||
ipcMain.handle('mr:scan', async (_e, folder) => {
|
||||
try { return await mrimport.scan(folder); }
|
||||
catch (err) { return { ok: false, reason: err.message }; }
|
||||
});
|
||||
|
||||
/*
|
||||
* War die Instanz in der Modrinth App mit einem Modrinth-Modpack verknüpft,
|
||||
* übernehmen wir die Verknüpfung – samt der Liste der Dateien, die zum Paket
|
||||
* gehören. Ohne diese Liste würde "Modpack aktualisieren" alte Mods liegen
|
||||
* lassen; deshalb wird die Paketdatei einmal geladen und nur ihr Inhaltsverzeichnis
|
||||
* gelesen. Klappt das nicht (offline …), bleibt die Instanz ohne Verknüpfung.
|
||||
*/
|
||||
async function verknuepfeModrinthModpack(instId, link) {
|
||||
const kopf = { headers: { 'User-Agent': 'AeroMC-Launcher', Accept: 'application/json' } };
|
||||
const vres = await fetch(`https://api.modrinth.com/v2/version/${encodeURIComponent(link.versionId)}`, kopf);
|
||||
if (!vres.ok) return false;
|
||||
const version = await vres.json();
|
||||
const datei = (version.files || []).find((f) => f.primary) || (version.files || [])[0];
|
||||
if (!datei || !datei.url) return false;
|
||||
const dl = await fetch(datei.url, { headers: { 'User-Agent': 'AeroMC-Launcher' } });
|
||||
if (!dl.ok) return false;
|
||||
const buf = Buffer.from(await dl.arrayBuffer());
|
||||
const zip = forge.readZipIndex(buf);
|
||||
if (!zip['modrinth.index.json']) return false;
|
||||
const index = JSON.parse(forge.readZipEntry(buf, zip['modrinth.index.json']).toString('utf8').replace(/^\uFEFF/, ''));
|
||||
const dateien = (index.files || [])
|
||||
.filter((f) => f.path && !(f.env && f.env.client === 'unsupported'))
|
||||
.map((f) => String(f.path).replace(/\\/g, '/'));
|
||||
for (const prefix of ['overrides/', 'client-overrides/']) {
|
||||
for (const name of Object.keys(zip)) if (name.startsWith(prefix) && !name.endsWith('/')) dateien.push(name.slice(prefix.length));
|
||||
}
|
||||
let titel = index.name || '';
|
||||
try {
|
||||
const pres = await fetch(`https://api.modrinth.com/v2/project/${encodeURIComponent(link.projectId)}`, kopf);
|
||||
if (pres.ok) titel = (await pres.json()).title || titel;
|
||||
} catch { /* Titel ist nur Zierde */ }
|
||||
store.updateInstance(instId, {
|
||||
modpack: {
|
||||
quelle: 'modrinth',
|
||||
name: index.name || titel,
|
||||
title: titel,
|
||||
projectId: link.projectId,
|
||||
versionId: link.versionId,
|
||||
versionNummer: version.version_number || '',
|
||||
dateien,
|
||||
},
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
ipcMain.handle('mr:import', async (_e, entries, copyData) => {
|
||||
const done = [];
|
||||
const failed = [];
|
||||
const liste = entries || [];
|
||||
for (const entry of liste) {
|
||||
try {
|
||||
const imported = mrimport.importOne(store, entry, copyData !== false);
|
||||
if (entry.modpack && entry.modpack.projectId && entry.modpack.versionId) {
|
||||
broadcast('mr:progress', { current: done.length + failed.length, total: liste.length, detail: 'Modpack-Verknüpfung für ' + entry.name });
|
||||
try { imported.modpack = await verknuepfeModrinthModpack(imported.id, entry.modpack); }
|
||||
catch { imported.modpack = false; }
|
||||
}
|
||||
done.push(imported);
|
||||
}
|
||||
catch (err) { failed.push({ name: entry.name, message: err.message }); }
|
||||
broadcast('mr:progress', { current: done.length + failed.length, total: liste.length });
|
||||
}
|
||||
if (done.length) broadcast('instances:changed');
|
||||
return { ok: true, imported: done, failed };
|
||||
});
|
||||
|
||||
ipcMain.handle('mc:pickFolder', async (e) => {
|
||||
const res = await dialog.showOpenDialog(BrowserWindow.fromWebContents(e.sender) || mainWindow, {
|
||||
title: 'Minecraft-Launcher-Ordner wählen (meist .minecraft)',
|
||||
|
||||
Reference in New Issue
Block a user