Upload via GUI (22 Dateien)
This commit is contained in:
+328
-41
@@ -97,18 +97,262 @@ const PIX = {
|
||||
] },
|
||||
};
|
||||
|
||||
// baut aus dem Raster ein SVG (skaliert scharf, da reine Rechtecke)
|
||||
function pixelIconSvg(key, size) {
|
||||
// baut aus dem Raster ein SVG
|
||||
function pixelIconRects(key, scale = 1, offsetX = 0, offsetY = 0) {
|
||||
const def = PIX[key] || PIX.grass;
|
||||
let rects = '';
|
||||
def.r.forEach((row, y) => {
|
||||
for (let x = 0; x < 16 && x < row.length; x++) {
|
||||
const col = def.p[row[x]];
|
||||
if (!col || col === '#00000000') continue;
|
||||
rects += `<rect x="${x}" y="${y}" width="1" height="1" fill="${col}"/>`;
|
||||
rects += `<rect x="${offsetX + (x * scale)}" y="${offsetY + (y * scale)}" width="${scale}" height="${scale}" fill="${col}"/>`;
|
||||
}
|
||||
});
|
||||
return `<svg viewBox="0 0 16 16" width="${size}" height="${size}" shape-rendering="crispEdges">${rects}</svg>`;
|
||||
return rects;
|
||||
}
|
||||
|
||||
function pixelIconSvg(key, size) {
|
||||
const rects = pixelIconRects(key);
|
||||
return `<svg viewBox="0 0 16 16" width="${size}" height="${size}">${rects}</svg>`;
|
||||
}
|
||||
|
||||
const HD_ICON_THEMES = {
|
||||
grass: { glyph: 'loop', bg: '#46b96c', shade: '#1f5b33', glow: '#95f08a' },
|
||||
dirt: { glyph: 'cube', bg: '#a96d43', shade: '#58311a', glow: '#d9a56e' },
|
||||
stone: { glyph: 'cube', bg: '#98a3b3', shade: '#495364', glow: '#dfe5ef' },
|
||||
planks: { glyph: 'cube', bg: '#cf9b61', shade: '#704521', glow: '#f2cb97' },
|
||||
tnt: { glyph: 'crate', bg: '#db4d45', shade: '#6d1d18', glow: '#fff2d2' },
|
||||
obsidian: { glyph: 'cube', bg: '#6f5cd7', shade: '#25184d', glow: '#b8abff' },
|
||||
netherrack: { glyph: 'cube', bg: '#c14f4f', shade: '#5d1717', glow: '#ff9a7b' },
|
||||
crafting: { glyph: 'grid', bg: '#bf8750', shade: '#613a20', glow: '#f5d5a4' },
|
||||
furnace: { glyph: 'forge', bg: '#7e8997', shade: '#38414c', glow: '#ffbd67' },
|
||||
bookshelf: { glyph: 'books', bg: '#b77a4d', shade: '#5b331f', glow: '#ffd966' },
|
||||
diamondblock: { glyph: 'cube', bg: '#42d0d7', shade: '#14606d', glow: '#dfffff' },
|
||||
goldblock: { glyph: 'cube', bg: '#f0bf3c', shade: '#8b5a09', glow: '#fff1a1' },
|
||||
emeraldblock: { glyph: 'cube', bg: '#2ec97b', shade: '#0b5a35', glow: '#b4ffd7' },
|
||||
redstoneblock: { glyph: 'cube', bg: '#e14d51', shade: '#75191d', glow: '#ffb1b4' },
|
||||
diamond: { glyph: 'gem', bg: '#47dce0', shade: '#126b79', glow: '#defcff' },
|
||||
emerald: { glyph: 'gem', bg: '#2fd485', shade: '#0d683c', glow: '#d8ffe8' },
|
||||
gold: { glyph: 'ingot', bg: '#f2c44e', shade: '#8d6208', glow: '#fff3b4' },
|
||||
iron: { glyph: 'ingot', bg: '#b9c3d1', shade: '#57606d', glow: '#f5f8fc' },
|
||||
redstone: { glyph: 'spark', bg: '#ea5956', shade: '#7e1717', glow: '#ffc8c6' },
|
||||
coal: { glyph: 'coal', bg: '#59606b', shade: '#1f242b', glow: '#cfd5df' },
|
||||
sword: { glyph: 'sword', bg: '#5d9ff4', shade: '#1f477c', glow: '#eef6ff' },
|
||||
pickaxe: { glyph: 'pickaxe', bg: '#57a8de', shade: '#1f5276', glow: '#ebf8ff' },
|
||||
axe: { glyph: 'axe', bg: '#6997df', shade: '#27456c', glow: '#eef4ff' },
|
||||
bow: { glyph: 'bow', bg: '#b97a58', shade: '#5c3522', glow: '#ffe1cb' },
|
||||
apple: { glyph: 'apple', bg: '#ea5353', shade: '#7e1717', glow: '#ffd3d3' },
|
||||
goldenapple: { glyph: 'apple', bg: '#f0c44f', shade: '#8c6208', glow: '#fff1b2' },
|
||||
book: { glyph: 'book', bg: '#7a5ad3', shade: '#33205f', glow: '#ece4ff' },
|
||||
enchantedbook: { glyph: 'bookSpark', bg: '#6f63e7', shade: '#272266', glow: '#d9fcff' },
|
||||
map: { glyph: 'map', bg: '#5aa67d', shade: '#1d563f', glow: '#f0f1c9' },
|
||||
star: { glyph: 'star', bg: '#5f7ce0', shade: '#22357c', glow: '#ffffff' },
|
||||
endereye: { glyph: 'eye', bg: '#3da984', shade: '#124a40', glow: '#ccfff0' },
|
||||
enderpearl: { glyph: 'pearl', bg: '#4cc0c7', shade: '#155b62', glow: '#e6ffff' },
|
||||
blaze: { glyph: 'flame', bg: '#ef8b38', shade: '#7c3a06', glow: '#ffe3a3' },
|
||||
xp: { glyph: 'bottle', bg: '#3ea977', shade: '#15503a', glow: '#dcffe0' },
|
||||
cake: { glyph: 'cake', bg: '#f08cab', shade: '#8a3453', glow: '#fff6dc' },
|
||||
bucket: { glyph: 'bucket', bg: '#5b94dc', shade: '#1f4a79', glow: '#d8f1ff' },
|
||||
lava: { glyph: 'bucket', bg: '#ec7134', shade: '#862d08', glow: '#ffd4ab' },
|
||||
tnt_item: { glyph: 'powder', bg: '#9ba2af', shade: '#404753', glow: '#fff4ce' },
|
||||
creeper: { glyph: 'creeper', bg: '#67c35b', shade: '#234f1c', glow: '#d7ffd0' },
|
||||
chest: { glyph: 'chest', bg: '#c4884f', shade: '#653a1d', glow: '#f5d28f' },
|
||||
potion: { glyph: 'potion', bg: '#8d63d9', shade: '#3b2466', glow: '#ffd7f5' },
|
||||
nether: { glyph: 'flame', bg: '#d65a3b', shade: '#6b2111', glow: '#ffd1a0' },
|
||||
end: { glyph: 'eye', bg: '#3f8d7d', shade: '#153f39', glow: '#d6fff4' },
|
||||
};
|
||||
|
||||
const LEGACY_REAL_ICON_MAP = {
|
||||
chest: 'chest',
|
||||
creeper: 'creeper',
|
||||
potion: 'potion',
|
||||
nether: 'blaze',
|
||||
end: 'endereye',
|
||||
tnt_item: 'tnt_item',
|
||||
};
|
||||
|
||||
function hdIconTheme(key) {
|
||||
return HD_ICON_THEMES[key] || { glyph: 'letter', bg: '#5b6474', shade: '#252b34', glow: '#e8edf7' };
|
||||
}
|
||||
|
||||
function hdIconGlyph(key, theme) {
|
||||
switch (theme.glyph) {
|
||||
case 'cube':
|
||||
return `
|
||||
<path d="M32 18 44 24 32 30 20 24Z"/>
|
||||
<path d="M20 24v14l12 7 12-7V24"/>
|
||||
<path d="M32 30v15"/>
|
||||
`;
|
||||
case 'loop':
|
||||
return `
|
||||
<path d="M22 33c0-4 3-7 7-7 5 0 7 6 11 6 3 0 6-3 6-7s-3-7-7-7c-5 0-7 6-11 6-3 0-6-3-6-7s3-7 7-7"/>
|
||||
`;
|
||||
case 'crate':
|
||||
return `
|
||||
<rect x="19" y="20" width="26" height="24" rx="5"/>
|
||||
<path d="M19 28h26M32 20v24M24 24h16M24 40h16"/>
|
||||
`;
|
||||
case 'grid':
|
||||
return `
|
||||
<rect x="18" y="18" width="28" height="28" rx="7"/>
|
||||
<path d="M27 18v28M37 18v28M18 27h28M18 37h28"/>
|
||||
`;
|
||||
case 'forge':
|
||||
return `
|
||||
<rect x="18" y="18" width="28" height="28" rx="7"/>
|
||||
<path d="M25 27h14v9H25zM24 40h16"/>
|
||||
`;
|
||||
case 'books':
|
||||
return `
|
||||
<rect x="18" y="17" width="9" height="30" rx="3"/>
|
||||
<rect x="28" y="15" width="8" height="32" rx="3"/>
|
||||
<rect x="37" y="19" width="9" height="28" rx="3"/>
|
||||
`;
|
||||
case 'gem':
|
||||
return `
|
||||
<path d="M32 17 45 29 32 46 19 29Z"/>
|
||||
<path d="M24 22h16M20 29h24M32 17v29"/>
|
||||
`;
|
||||
case 'ingot':
|
||||
return `
|
||||
<path d="M22 26h20l5 12H17Z"/>
|
||||
<path d="M26 21h12l5 5H21Z"/>
|
||||
`;
|
||||
case 'spark':
|
||||
return `
|
||||
<path d="M32 17 35 26 45 28 37 34 39 44 32 39 25 44 27 34 19 28 29 26Z"/>
|
||||
`;
|
||||
case 'coal':
|
||||
return `
|
||||
<path d="M24 19h16l7 11-7 15H24l-7-15Z"/>
|
||||
<path d="M24 19 32 30 40 19"/>
|
||||
`;
|
||||
case 'sword':
|
||||
return `
|
||||
<path d="M37 18 46 27 35 38 26 29Z"/>
|
||||
<path d="M28 31 18 41M24 45l-4 4M27 42l-7 2"/>
|
||||
`;
|
||||
case 'pickaxe':
|
||||
return `
|
||||
<path d="M19 26c7-7 16-9 26-6"/>
|
||||
<path d="M33 20 22 45"/>
|
||||
`;
|
||||
case 'axe':
|
||||
return `
|
||||
<path d="M25 19c8 0 15 5 17 13-8 2-14-1-18-8"/>
|
||||
<path d="M31 19 22 46"/>
|
||||
`;
|
||||
case 'bow':
|
||||
return `
|
||||
<path d="M24 18c9 8 9 20 0 28"/>
|
||||
<path d="M39 18v28M27 22 39 32 27 42"/>
|
||||
`;
|
||||
case 'apple':
|
||||
return `
|
||||
<path d="M32 23c7 0 13 5 13 12s-6 13-13 13-13-6-13-13 6-12 13-12Z"/>
|
||||
<path d="M32 19c0-3 2-5 5-6M36 18c3 0 5 1 7 3"/>
|
||||
`;
|
||||
case 'book':
|
||||
return `
|
||||
<path d="M20 19h12c3 0 5 2 5 5v21H24c-2 0-4 1-4 2Z"/>
|
||||
<path d="M44 19H32c-3 0-5 2-5 5v21h13c2 0 4 1 4 2Z"/>
|
||||
`;
|
||||
case 'bookSpark':
|
||||
return `
|
||||
<path d="M20 19h12c3 0 5 2 5 5v21H24c-2 0-4 1-4 2Z"/>
|
||||
<path d="M44 19H32c-3 0-5 2-5 5v21h13c2 0 4 1 4 2Z"/>
|
||||
<path d="M45 17 47 22 52 24 47 26 45 31 43 26 38 24 43 22Z"/>
|
||||
`;
|
||||
case 'map':
|
||||
return `
|
||||
<path d="M18 20 28 16 38 20 46 17v27l-8 3-10-4-10 4Z"/>
|
||||
<path d="M28 16v27M38 20v27"/>
|
||||
`;
|
||||
case 'star':
|
||||
return `
|
||||
<path d="M32 17 36 26 46 27 38 34 40 44 32 39 24 44 26 34 18 27 28 26Z"/>
|
||||
`;
|
||||
case 'eye':
|
||||
return `
|
||||
<path d="M16 32c5-8 10-12 16-12s11 4 16 12c-5 8-10 12-16 12s-11-4-16-12Z"/>
|
||||
<circle cx="32" cy="32" r="5"/>
|
||||
`;
|
||||
case 'pearl':
|
||||
return `
|
||||
<circle cx="32" cy="32" r="13"/>
|
||||
<path d="M26 27c2-2 4-3 7-3"/>
|
||||
`;
|
||||
case 'flame':
|
||||
return `
|
||||
<path d="M34 17c5 8 9 12 9 19 0 7-4 13-11 13s-11-5-11-12c0-7 5-11 10-17 0 4 1 6 4 10 2-6 1-9-1-13Z"/>
|
||||
`;
|
||||
case 'bottle':
|
||||
return `
|
||||
<path d="M28 18h8v6l4 6v12c0 5-3 8-8 8s-8-3-8-8V30l4-6Z"/>
|
||||
<path d="M25 39h14"/>
|
||||
`;
|
||||
case 'cake':
|
||||
return `
|
||||
<path d="M18 30h28v14H18Z"/>
|
||||
<path d="M18 30c3-4 7-6 14-6s11 2 14 6M26 24v6M32 23v7M38 24v6"/>
|
||||
`;
|
||||
case 'bucket':
|
||||
return `
|
||||
<path d="M22 22h20l-3 22H25Z"/>
|
||||
<path d="M26 22c0-4 2-7 6-7s6 3 6 7"/>
|
||||
`;
|
||||
case 'powder':
|
||||
return `
|
||||
<circle cx="24" cy="34" r="4"/>
|
||||
<circle cx="33" cy="28" r="5"/>
|
||||
<circle cx="41" cy="36" r="3"/>
|
||||
`;
|
||||
case 'creeper':
|
||||
return `
|
||||
<rect x="21" y="18" width="22" height="28" rx="6"/>
|
||||
<rect x="25" y="24" width="4" height="5" rx="1" fill="currentColor" stroke="none"/>
|
||||
<rect x="35" y="24" width="4" height="5" rx="1" fill="currentColor" stroke="none"/>
|
||||
<path d="M26 40h12l-2-7h-8Z" fill="currentColor" stroke="none"/>
|
||||
`;
|
||||
case 'chest':
|
||||
return `
|
||||
<rect x="18" y="22" width="28" height="22" rx="5"/>
|
||||
<path d="M18 29h28M32 29v8"/>
|
||||
`;
|
||||
case 'potion':
|
||||
return `
|
||||
<path d="M28 17h8v5l4 6v13c0 6-3 9-8 9s-8-3-8-9V28l4-6Z"/>
|
||||
<path d="M25 39h14"/>
|
||||
`;
|
||||
case 'letter':
|
||||
return `<text x="32" y="40" text-anchor="middle" font-size="22" font-weight="700" font-family="Segoe UI, sans-serif" fill="currentColor" stroke="none">${escapeHtml((key || '?').slice(0, 1).toUpperCase())}</text>`;
|
||||
default:
|
||||
return pixelIconSvg(key, 44);
|
||||
}
|
||||
}
|
||||
|
||||
function hdIconSvg(key, size = 44) {
|
||||
const theme = hdIconTheme(key);
|
||||
const gid = `g-${String(key || 'icon').replace(/[^a-z0-9_-]/gi, '-')}-${size}`;
|
||||
return `
|
||||
<svg viewBox="0 0 64 64" width="${size}" height="${size}" aria-hidden="true">
|
||||
<defs>
|
||||
<clipPath id="${gid}-clip">
|
||||
<rect x="8" y="8" width="48" height="48" rx="12"/>
|
||||
</clipPath>
|
||||
<filter id="${gid}-shadow" x="-20%" y="-20%" width="140%" height="140%">
|
||||
<feDropShadow dx="0" dy="2" stdDeviation="2" flood-color="rgba(0,0,0,.28)"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<g filter="url(#${gid}-shadow)">
|
||||
<g clip-path="url(#${gid}-clip)">${pixelIconRects('grass', 3, 8, 8)}</g>
|
||||
<rect x="8" y="8" width="48" height="48" rx="12" fill="rgba(18,28,16,.10)"/>
|
||||
<rect x="8" y="8" width="48" height="48" rx="12" fill="none" stroke="rgba(255,255,255,.18)" stroke-width="1.5"/>
|
||||
</g>
|
||||
<g fill="none" stroke="${theme.glow}" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round">
|
||||
${hdIconGlyph(key, theme)}
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
||||
|
||||
const ICON_KEYS = Object.keys(PIX);
|
||||
@@ -122,15 +366,40 @@ let mcIcons = {};
|
||||
async function loadMcIcons() {
|
||||
try {
|
||||
let list = await window.api.iconsList();
|
||||
if (!list.length) {
|
||||
const needRefresh = !list.length || !['potion', 'chest', 'creeper', 'paper', 'slimeball', 'cookie'].every((key) => list.some((i) => i.key === key));
|
||||
if (needRefresh) {
|
||||
const res = await window.api.iconsExtract();
|
||||
list = (res && res.ok) ? res.icons : [];
|
||||
if (res && res.ok && Array.isArray(res.icons) && res.icons.length) list = res.icons;
|
||||
}
|
||||
mcIcons = Object.fromEntries(list.map((i) => [i.key, i]));
|
||||
await buildIsoCubes(); // räumliche Block-Symbole vorbereiten
|
||||
} catch { mcIcons = {}; }
|
||||
}
|
||||
|
||||
function resolveRealIconKey(key) {
|
||||
if (mcIcons[key]) return key;
|
||||
const mapped = LEGACY_REAL_ICON_MAP[key];
|
||||
if (mapped && mcIcons[mapped]) return mapped;
|
||||
return '';
|
||||
}
|
||||
|
||||
function realItemIconSvg(key, size = 44) {
|
||||
const realKey = resolveRealIconKey(key);
|
||||
if (!realKey) return '';
|
||||
const real = mcIcons[realKey];
|
||||
if (!real) return '';
|
||||
const theme = hdIconTheme(realKey);
|
||||
const src = iso3dEnabled && BLOCK_KEYS.has(realKey) && isoCache[realKey] ? isoCache[realKey] : real.dataUri;
|
||||
const plate = BLOCK_KEYS.has(realKey)
|
||||
? `<rect x="8" y="8" width="48" height="48" rx="15" fill="${theme.bg}" opacity=".16"/>`
|
||||
: `<circle cx="32" cy="32" r="22" fill="${theme.bg}" opacity=".14"/>`;
|
||||
return `
|
||||
<svg class="mc-item-icon" viewBox="0 0 64 64" width="${size}" height="${size}" aria-hidden="true">
|
||||
${plate}
|
||||
<image href="${src}" x="10" y="10" width="44" height="44" preserveAspectRatio="xMidYMid meet"/>
|
||||
</svg>`;
|
||||
}
|
||||
|
||||
// erzeugt die Würfel-Darstellungen einmalig im Voraus
|
||||
async function buildIsoCubes() {
|
||||
const jobs = Object.values(mcIcons)
|
||||
@@ -157,10 +426,11 @@ function renderIsoCube(key) {
|
||||
const img = isoSources[key];
|
||||
if (!img) return null;
|
||||
|
||||
const S = 64, c = document.createElement('canvas');
|
||||
const S = 96, c = document.createElement('canvas');
|
||||
c.width = S; c.height = S;
|
||||
const g = c.getContext('2d');
|
||||
g.imageSmoothingEnabled = false;
|
||||
g.imageSmoothingEnabled = true;
|
||||
if ('imageSmoothingQuality' in g) g.imageSmoothingQuality = 'high';
|
||||
const w = 26, h = 15, cx = S / 2, top = 8;
|
||||
|
||||
const face = (m, bright) => {
|
||||
@@ -187,15 +457,12 @@ function renderIsoCube(key) {
|
||||
return out;
|
||||
}
|
||||
|
||||
// liefert das Icon-Markup: echte Textur bevorzugt, sonst eigene Pixel-Grafik
|
||||
// liefert das Icon-Markup als skalierbares HD-SVG; eigene Bilder der Instanz bleiben separat erhalten
|
||||
function iconOf(key, size = 44) {
|
||||
const real = mcIcons[key];
|
||||
if (real) {
|
||||
let src = real.dataUri;
|
||||
if (iso3dEnabled && BLOCK_KEYS.has(key) && isoCache[key]) src = isoCache[key];
|
||||
return `<img src="${src}" width="${size}" height="${size}" style="image-rendering:pixelated;display:block" alt="" />`;
|
||||
}
|
||||
return pixelIconSvg(key, size);
|
||||
const real = realItemIconSvg(key, size);
|
||||
if (real) return real;
|
||||
if (PIX[key]) return pixelIconSvg(key, size);
|
||||
return hdIconSvg(key, size);
|
||||
}
|
||||
|
||||
const LOADER_LABEL = {
|
||||
@@ -687,7 +954,7 @@ function buildCard(inst) {
|
||||
|
||||
const iconHtml = inst.iconData
|
||||
? `<img class="card-icon-img" src="${inst.iconData}" alt="" />`
|
||||
: `<span class="card-icon">${iconOf(inst.icon)}</span>`;
|
||||
: `<span class="card-icon">${iconOf(inst.icon, 60)}</span>`;
|
||||
// Tooltip: Name, Version/Loader und – falls vorhanden – die Notizen
|
||||
const loaderTxt = inst.minecraft.loader && inst.minecraft.loader !== 'vanilla'
|
||||
? ' · ' + (LOADER_LABEL[inst.minecraft.loader] || inst.minecraft.loader) : '';
|
||||
@@ -867,6 +1134,7 @@ async function updateLoaderVersions(preselect) {
|
||||
// alle wählbaren Icons: echte Minecraft-Texturen zuerst, dann die eigenen
|
||||
function availableIcons() {
|
||||
const real = Object.values(mcIcons).map((i) => ({ key: i.key, label: i.label, real: true }));
|
||||
if (real.length) return real;
|
||||
const own = ICON_KEYS
|
||||
.filter((k) => !mcIcons[k])
|
||||
.map((k) => ({ key: k, label: ICON_LABELS[k] || k, real: false }));
|
||||
@@ -1045,7 +1313,7 @@ async function selectInstance(id) {
|
||||
|
||||
const iconData = inst.customImage ? await window.api.instanceIcon(id) : null;
|
||||
if (iconData) el('p-icon').innerHTML = `<img src="${iconData}" alt="" />`;
|
||||
else { el('p-icon').innerHTML = iconOf(inst.icon, 56); }
|
||||
else { el('p-icon').innerHTML = iconOf(inst.icon, 60); }
|
||||
el('p-name').textContent = inst.name;
|
||||
|
||||
const loaderTxt = inst.minecraft.loader && inst.minecraft.loader !== 'vanilla'
|
||||
@@ -1386,10 +1654,13 @@ async function installMod(mod, btn, item) {
|
||||
}
|
||||
|
||||
// ---------- Einstellungen ----------
|
||||
function setSettingsPane(paneId) {
|
||||
document.querySelectorAll('.snav').forEach((button) => button.classList.toggle('on', button.dataset.pane === paneId));
|
||||
document.querySelectorAll('.spane').forEach((pane) => pane.classList.toggle('hidden', pane.id !== paneId));
|
||||
}
|
||||
|
||||
async function openSettings() {
|
||||
// immer mit der ersten Sektion starten
|
||||
document.querySelectorAll('.snav').forEach((x, i) => x.classList.toggle('on', i === 0));
|
||||
document.querySelectorAll('.spane').forEach((p) => p.classList.toggle('hidden', p.id !== 'pane-launcher'));
|
||||
setSettingsPane('pane-general');
|
||||
|
||||
const s = await window.api.getSettings();
|
||||
el('s-theme').value = s.theme || 'dark';
|
||||
@@ -1433,8 +1704,25 @@ async function openSettings() {
|
||||
await refreshJavaStatus(s.javaPath);
|
||||
|
||||
const info = await window.api.appInfo();
|
||||
el('s-appinfo').innerHTML =
|
||||
`Version ${info.version}<br><span class="mono">${escapeHtml(info.userData)}</span>`;
|
||||
el('s-appinfo').innerHTML = [
|
||||
['Name', info.name || 'AeroMC'],
|
||||
['Version', info.version || '–'],
|
||||
['Autor', info.author || 'Nicht hinterlegt'],
|
||||
['Webseite', info.homepage || 'Nicht hinterlegt', info.homepage || ''],
|
||||
['Gitseite', info.gitpage || 'Nicht hinterlegt', info.gitpage || ''],
|
||||
].map(([label, value, url]) => {
|
||||
const renderedValue = url
|
||||
? `<a href="#" class="info-meta-link" data-url="${escapeHtml(url)}">${escapeHtml(value)}</a>`
|
||||
: escapeHtml(value || '–');
|
||||
return `<div class="settings-kv-row"><span class="settings-kv-label">${escapeHtml(label)}</span><span class="settings-kv-value">${renderedValue}</span></div>`;
|
||||
}).join('');
|
||||
for (const link of el('s-appinfo').querySelectorAll('.info-meta-link')) {
|
||||
link.addEventListener('click', (evt) => {
|
||||
evt.preventDefault();
|
||||
const url = link.dataset.url;
|
||||
if (url) window.api.openExternal(url);
|
||||
});
|
||||
}
|
||||
show('modal-settings');
|
||||
await renderAccounts('s-accounts'); // Konten direkt in den Einstellungen zeigen
|
||||
applyBedrockVisibility(); // aktualisiert auch den Hinweistext
|
||||
@@ -1867,29 +2155,28 @@ function wire() {
|
||||
});
|
||||
el('s-java').addEventListener('change', (e) => refreshJavaStatus(e.target.value.trim()));
|
||||
el('btn-save-settings').addEventListener('click', saveSettings);
|
||||
document.querySelectorAll('.snav').forEach((b) => b.addEventListener('click', () => {
|
||||
document.querySelectorAll('.snav').forEach((x) => x.classList.toggle('on', x === b));
|
||||
document.querySelectorAll('.spane').forEach((p) => p.classList.toggle('hidden', p.id !== b.dataset.pane));
|
||||
}));
|
||||
document.querySelectorAll('.snav').forEach((b) => b.addEventListener('click', () => setSettingsPane(b.dataset.pane)));
|
||||
el('s-open-accounts').addEventListener('click', () => { hide('modal-settings'); openLogin(); });
|
||||
el('s-add-account').addEventListener('click', () => { hide('modal-settings'); openLogin().then(addAccount); });
|
||||
|
||||
// Updates
|
||||
el('upd-install').addEventListener('click', startUpdate);
|
||||
el('s-check-update').addEventListener('click', async () => {
|
||||
const st = el('s-update-status');
|
||||
st.textContent = 'Suche nach Updates …';
|
||||
const info = await window.api.updateCheck();
|
||||
if (info.error) { st.textContent = '✖ ' + info.error; return; }
|
||||
if (info.noReleases) { st.textContent = 'Noch keine Veröffentlichung vorhanden.'; return; }
|
||||
if (info.available) {
|
||||
st.textContent = `Version ${info.latestVersion} verfügbar.`;
|
||||
hide('modal-settings');
|
||||
showUpdateDialog(info);
|
||||
} else {
|
||||
st.textContent = `Du hast bereits die neueste Version (v${info.currentVersion}).`;
|
||||
}
|
||||
});
|
||||
if (el('s-check-update')) {
|
||||
el('s-check-update').addEventListener('click', async () => {
|
||||
const st = el('s-update-status');
|
||||
st.textContent = 'Suche nach Updates …';
|
||||
const info = await window.api.updateCheck();
|
||||
if (info.error) { st.textContent = '✖ ' + info.error; return; }
|
||||
if (info.noReleases) { st.textContent = 'Noch keine Veröffentlichung vorhanden.'; return; }
|
||||
if (info.available) {
|
||||
st.textContent = `Version ${info.latestVersion} verfügbar.`;
|
||||
hide('modal-settings');
|
||||
showUpdateDialog(info);
|
||||
} else {
|
||||
st.textContent = `Du hast bereits die neueste Version (v${info.currentVersion}).`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Microsoft-Login / Kontoverwaltung
|
||||
el('btn-account').addEventListener('click', openLogin);
|
||||
|
||||
Reference in New Issue
Block a user