Upload via GUI (138 Dateien)
This commit is contained in:
+105
-9
@@ -1564,7 +1564,9 @@ async function applySkinBackground(uuidOverride) {
|
||||
// schmaler Alex-Skin mit breiten Armen falsch aus (grauer Streifen am Arm)
|
||||
let modell = s.bgSkinModel === 'slim' || s.bgSkinModel === 'classic' ? s.bgSkinModel : '';
|
||||
if (!modell) { try { modell = await window.api.skinModelFor(uuid); } catch { modell = 'classic'; } }
|
||||
const local = await renderSkin3D(`https://crafthead.net/skin/${uuid}`, s.bgSkinPose || 'walking', { modell });
|
||||
let umhang = null;
|
||||
try { const r = await window.api.capeForUuid(uuid); umhang = r ? r.dataUri : null; } catch { /* ohne Umhang */ }
|
||||
const local = await renderSkin3D(`https://crafthead.net/skin/${uuid}`, s.bgSkinPose || 'walking', { modell, umhang });
|
||||
if (local) { root.style.setProperty('--bg-skin', `url("${local}")`); return; }
|
||||
|
||||
// 2) Rückfall: externe Render-Dienste
|
||||
@@ -1711,6 +1713,7 @@ async function renderSkin3D(quelle, poseKey, opts = {}) {
|
||||
viewer.autoRotate = false;
|
||||
viewer.animation = null;
|
||||
pose.apply(viewer.playerObject);
|
||||
if (opts.umhang) { try { await viewer.loadCape(opts.umhang); } catch { /* ohne Umhang */ } }
|
||||
|
||||
viewer.render();
|
||||
const data = canvas.toDataURL('image/png');
|
||||
@@ -1740,6 +1743,7 @@ const ICONS_SVG = {
|
||||
export: '<path d="M12 21V9m0 0l-4 4m4-4l4 4M4 4h16"/>',
|
||||
trash: '<path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13"/>',
|
||||
chart: '<path d="M4 20V10M10 20V4M16 20v-7M22 20H2"/>',
|
||||
search: '<circle cx="11" cy="11" r="7"/><path d="M20 20l-4.2-4.2"/>',
|
||||
};
|
||||
function svgIcon(name) {
|
||||
const p = ICONS_SVG[name];
|
||||
@@ -1909,6 +1913,17 @@ function buildCard(inst) {
|
||||
return card;
|
||||
}
|
||||
|
||||
// Suchfeld in der Werkzeugleiste: standardmäßig nur eine Lupe
|
||||
function sucheOeffnen() {
|
||||
el('search-wrap').classList.add('offen');
|
||||
el('search').focus();
|
||||
el('search').select();
|
||||
}
|
||||
function sucheSchliessen() {
|
||||
el('search-wrap').classList.remove('offen');
|
||||
if (document.activeElement === el('search')) el('search').blur();
|
||||
}
|
||||
|
||||
function render() {
|
||||
const q = el('search').value.trim().toLowerCase();
|
||||
const grid = el('grid');
|
||||
@@ -2607,7 +2622,7 @@ function schliesseSkinViewer(bildId) {
|
||||
* Mausrad zoomt -- kommt von skinview3d selbst). Klappt das Rendern nicht,
|
||||
* wird stattdessen ein Hinweistext gezeigt.
|
||||
*/
|
||||
async function zeigeSkinFigur(bildId, leerId, textur, leerText) {
|
||||
async function zeigeSkinFigur(bildId, leerId, textur, leerText, umhang) {
|
||||
schliesseSkinViewer(bildId);
|
||||
const canvas = el(bildId);
|
||||
const leer = el(leerId);
|
||||
@@ -2644,6 +2659,7 @@ async function zeigeSkinFigur(bildId, leerId, textur, leerText) {
|
||||
viewer.autoRotate = false;
|
||||
viewer.animation = null;
|
||||
pose.apply(viewer.playerObject);
|
||||
if (umhang) { try { await viewer.loadCape(umhang); } catch { /* ohne Umhang weiter */ } }
|
||||
viewer.controls.enableRotate = true;
|
||||
viewer.controls.enableZoom = true;
|
||||
viewer.controls.enablePan = false;
|
||||
@@ -2679,14 +2695,78 @@ async function openSkin() {
|
||||
// Armform zuerst setzen – davon hängt ab, wie die Figur gerendert wird
|
||||
if (p.variante) el('skin-variante').value = p.variante === 'slim' ? 'slim' : 'classic';
|
||||
skinTexturAktuell = p.skinUrl || '';
|
||||
await ladeUmhangInfo();
|
||||
await zeigeSkinFigur('skin-aktuell', 'skin-aktuell-leer', skinTexturAktuell,
|
||||
'Standard-Skin (keine eigene Datei hinterlegt)');
|
||||
'Standard-Skin (keine eigene Datei hinterlegt)', skinUmhang);
|
||||
}
|
||||
|
||||
// ---------- Umhänge im Skin-Fenster ----------
|
||||
let skinUmhang = null; // data:-Adresse des angezeigten Umhangs (AeroMC vor offiziell)
|
||||
|
||||
async function ladeUmhangInfo() {
|
||||
const sel = el('skin-cape-offiziell');
|
||||
const info = await window.api.capeInfo();
|
||||
sel.innerHTML = '<option value="">Kein Umhang</option>';
|
||||
if (!info.ok) {
|
||||
el('skin-cape-aero').textContent = info.message || '–';
|
||||
el('skin-cape-remove').classList.add('hidden');
|
||||
skinUmhang = null;
|
||||
return;
|
||||
}
|
||||
for (const c of info.offiziell) {
|
||||
const o = document.createElement('option');
|
||||
o.value = c.id;
|
||||
o.textContent = c.name;
|
||||
if (c.aktiv) o.selected = true;
|
||||
sel.appendChild(o);
|
||||
}
|
||||
sel.disabled = !info.offiziell.length;
|
||||
sel.title = info.offiziell.length ? 'Nur Umhänge, die dein Konto bei Mojang besitzt' : 'Dein Konto besitzt keinen offiziellen Umhang';
|
||||
if (info.aeromc) {
|
||||
el('skin-cape-aero').textContent = `Hochgeladen (${info.aeromc.width}×${info.aeromc.height})`;
|
||||
el('skin-cape-remove').classList.remove('hidden');
|
||||
el('skin-cape-edit').textContent = 'Bearbeiten…';
|
||||
} else {
|
||||
el('skin-cape-aero').textContent = info.aeromcFehlt ? 'Server noch nicht bereit' : info.aeromcFehler ? 'Umhang-Server nicht erreichbar' : 'Noch keiner';
|
||||
el('skin-cape-aero').title = info.aeromcFehler || '';
|
||||
el('skin-cape-remove').classList.add('hidden');
|
||||
el('skin-cape-edit').textContent = 'Gestalten…';
|
||||
}
|
||||
const konto = await window.api.authStatus();
|
||||
const r = konto && konto.profile ? await window.api.capeForUuid(konto.profile.id) : null;
|
||||
skinUmhang = r ? r.dataUri : null;
|
||||
}
|
||||
|
||||
async function waehleOffiziellenUmhang() {
|
||||
const sel = el('skin-cape-offiziell');
|
||||
sel.disabled = true;
|
||||
el('skin-cape-status').textContent = 'Umhang wird gesetzt …';
|
||||
const res = await window.api.capeSetOfficial(sel.value || null);
|
||||
sel.disabled = false;
|
||||
if (res.ok) {
|
||||
el('skin-cape-status').textContent = sel.value ? '✔ Offizieller Umhang gesetzt.' : '✔ Kein offizieller Umhang mehr.';
|
||||
await ladeUmhangInfo();
|
||||
await zeigeSkinFigur('skin-aktuell', 'skin-aktuell-leer', skinTexturAktuell, 'Standard-Skin (keine eigene Datei hinterlegt)', skinUmhang);
|
||||
} else {
|
||||
el('skin-cape-status').textContent = '✖ ' + (res.message || 'Fehlgeschlagen.');
|
||||
}
|
||||
}
|
||||
|
||||
function entferneAeroUmhang() {
|
||||
askConfirm('AeroMC-Umhang entfernen?', 'Dein eigener Umhang wird vom AeroMC-Umhang-Server gelöscht. Hast du ihn nicht als PNG gespeichert, ist er danach weg.', 'Entfernen', async () => {
|
||||
const res = await window.api.capeRemove();
|
||||
el('skin-cape-status').textContent = res.ok ? '✔ AeroMC-Umhang entfernt.' : '✖ ' + (res.message || 'Fehlgeschlagen.');
|
||||
if (res.ok) {
|
||||
await ladeUmhangInfo();
|
||||
await zeigeSkinFigur('skin-aktuell', 'skin-aktuell-leer', skinTexturAktuell, 'Standard-Skin (keine eigene Datei hinterlegt)', skinUmhang);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Armform gewechselt -> beide Figuren neu zeichnen
|
||||
async function skinVarianteGewechselt() {
|
||||
if (skinTexturAktuell) await zeigeSkinFigur('skin-aktuell', 'skin-aktuell-leer', skinTexturAktuell, '');
|
||||
if (skinTexturNeu) await zeigeSkinFigur('skin-neu', 'skin-neu-leer', skinTexturNeu, '');
|
||||
if (skinTexturAktuell) await zeigeSkinFigur('skin-aktuell', 'skin-aktuell-leer', skinTexturAktuell, '', skinUmhang);
|
||||
if (skinTexturNeu) await zeigeSkinFigur('skin-neu', 'skin-neu-leer', skinTexturNeu, '', skinUmhang);
|
||||
}
|
||||
|
||||
async function waehleSkinDatei() {
|
||||
@@ -2697,7 +2777,7 @@ async function waehleSkinDatei() {
|
||||
gewaehlterSkin = res.pfad;
|
||||
el('skin-pfad').value = res.pfad;
|
||||
skinTexturNeu = res.dataUri || '';
|
||||
await zeigeSkinFigur('skin-neu', 'skin-neu-leer', skinTexturNeu, 'Vorschau nicht verfügbar');
|
||||
await zeigeSkinFigur('skin-neu', 'skin-neu-leer', skinTexturNeu, 'Vorschau nicht verfügbar', skinUmhang);
|
||||
el('skin-status').textContent = `${res.breite}×${res.hoehe} Pixel – sieht gut aus.`;
|
||||
el('skin-apply').disabled = false;
|
||||
}
|
||||
@@ -4918,6 +4998,7 @@ async function openSettings(pane) {
|
||||
el('s-friends').checked = s.friendsEnabled !== false;
|
||||
el('s-friends-server').checked = s.friendsShareServer !== false;
|
||||
el('s-auto-mod-updates').checked = !!s.autoModUpdates;
|
||||
el('s-aeromc-capes').checked = s.aeromcCapes !== false;
|
||||
el('s-autostart').checked = !!s.autostart;
|
||||
el('s-auto-java').checked = s.autoJava !== false;
|
||||
el('s-autobackup').checked = !!s.autoBackupEnabled;
|
||||
@@ -5051,6 +5132,7 @@ async function saveSettings() {
|
||||
friendsEnabled: el('s-friends').checked,
|
||||
friendsShareServer: el('s-friends-server').checked,
|
||||
autoModUpdates: el('s-auto-mod-updates').checked,
|
||||
aeromcCapes: el('s-aeromc-capes').checked,
|
||||
autostart: el('s-autostart').checked,
|
||||
autoJava: el('s-auto-java').checked,
|
||||
autoBackupEnabled: el('s-autobackup').checked,
|
||||
@@ -5527,6 +5609,18 @@ function wire() {
|
||||
// ohne Wrapper käme das Klick-Ereignis als Bereichsname an
|
||||
el('btn-settings').addEventListener('click', () => openSettings());
|
||||
el('search').addEventListener('input', render);
|
||||
el('btn-search').addEventListener('click', () => sucheOeffnen());
|
||||
el('search').addEventListener('keydown', (e) => {
|
||||
if (e.key !== 'Escape') return;
|
||||
// Esc gehört hier der Suche, nicht dem globalen Dialog-Schließen
|
||||
e.stopPropagation();
|
||||
el('search').value = '';
|
||||
render();
|
||||
sucheSchliessen();
|
||||
});
|
||||
// leer verlassen = wieder zur Lupe; mit Suchbegriff bleibt das Feld offen,
|
||||
// damit man sieht, dass die Liste gerade gefiltert ist
|
||||
el('search').addEventListener('blur', () => { if (!el('search').value.trim()) sucheSchliessen(); });
|
||||
|
||||
el('btn-open-dir').addEventListener('click', () => {
|
||||
if (currentDetailId) window.api.openInstanceFolder(currentDetailId);
|
||||
@@ -5925,6 +6019,9 @@ function wire() {
|
||||
el('login-skin').addEventListener('click', openSkin);
|
||||
el('skin-pick').addEventListener('click', waehleSkinDatei);
|
||||
el('skin-variante').addEventListener('change', skinVarianteGewechselt);
|
||||
el('skin-cape-offiziell').addEventListener('change', waehleOffiziellenUmhang);
|
||||
el('skin-cape-edit').addEventListener('click', () => window.openSkinEditor({ modus: 'umhang', quelle: 'aktuell' }));
|
||||
el('skin-cape-remove').addEventListener('click', entferneAeroUmhang);
|
||||
el('skin-apply').addEventListener('click', setzeSkin);
|
||||
// gewählte Datei (sonst der aktuelle Skin des Kontos) im Editor öffnen
|
||||
el('skin-editor').addEventListener('click', () => window.openSkinEditor(gewaehlterSkin
|
||||
@@ -6274,8 +6371,7 @@ function wire() {
|
||||
// der eine eigene Suche hat (Mods, Modpack-Katalog, Import …)
|
||||
if (strg && e.key.toLowerCase() === 'f' && !modalOffen) {
|
||||
e.preventDefault();
|
||||
el('search').focus();
|
||||
el('search').select();
|
||||
sucheOeffnen();
|
||||
return;
|
||||
}
|
||||
// Strg+1 … Strg+5: Schnellstart-Instanz starten (nur im Hauptfenster)
|
||||
@@ -6535,7 +6631,7 @@ window.addEventListener('DOMContentLoaded', async () => {
|
||||
window.api.onSkinChanged((info) => {
|
||||
if (!POPOUT) refreshSkinBackground();
|
||||
// im Editor gesetzt -> offenes Skin-Fenster zeigt sonst noch den alten Stand
|
||||
if (POPOUT === 'skin' && info.quelle === 'editor' && !el('modal-skin').classList.contains('hidden')) openSkin();
|
||||
if (POPOUT === 'skin' && (info.quelle === 'editor' || info.quelle === 'umhang') && !el('modal-skin').classList.contains('hidden')) openSkin();
|
||||
});
|
||||
window.api.onInstancesChanged(() => { if (!POPOUT) reload(); });
|
||||
try { showAuthHealth(await window.api.authHealth()); } catch { /* noch keine Prüfung */ }
|
||||
|
||||
Reference in New Issue
Block a user