fixes:
- make prefix imported games paths relative to prefix - show placeholder icon as fallback - fix crossed working/exe directories - fix broken working dir in prefix imported games
This commit is contained in:
parent
b83e530392
commit
66f42f30cc
8 changed files with 74 additions and 10 deletions
|
|
@ -166,6 +166,7 @@ class CustomSelect {
|
|||
this.options = options
|
||||
this.value = value
|
||||
this.onChange = onChange
|
||||
this.disabled = false
|
||||
this.render()
|
||||
if (!this.host.dataset.wired) {
|
||||
this.wire()
|
||||
|
|
@ -173,6 +174,11 @@ class CustomSelect {
|
|||
}
|
||||
}
|
||||
|
||||
setDisabled(v) {
|
||||
this.disabled = !!v
|
||||
this.host.classList.toggle('disabled', this.disabled)
|
||||
}
|
||||
|
||||
render() {
|
||||
const selected = this.options.find(o => o.value === this.value)
|
||||
this.host.classList.add('custom-select')
|
||||
|
|
@ -219,6 +225,7 @@ class CustomSelect {
|
|||
}
|
||||
|
||||
toggle() {
|
||||
if (this.disabled) return
|
||||
const wasOpen = this.host.classList.contains('open')
|
||||
CustomSelect.closeAll()
|
||||
if (!wasOpen) this.host.classList.add('open')
|
||||
|
|
@ -357,15 +364,23 @@ function fmtPlaytime(seconds) {
|
|||
}
|
||||
|
||||
async function attachCardIcon(card, game) {
|
||||
// placeholder first so every card has a stable icon slot; swapped for the
|
||||
// real icon once it loads - games without one just keep the placeholder
|
||||
const ph = document.createElement('div')
|
||||
ph.className = 'game-icon placeholder'
|
||||
card.prepend(ph)
|
||||
const p = await window.plwl.gamesIconPath(game.id)
|
||||
if (!p) return
|
||||
const img = document.createElement('img')
|
||||
img.className = 'game-icon'
|
||||
img.alt = ''
|
||||
img.onerror = () => img.remove()
|
||||
img.onload = () => card.prepend(img)
|
||||
img.onerror = () => img.remove() // placeholder stays visible
|
||||
img.onload = () => {
|
||||
ph.remove()
|
||||
card.prepend(img)
|
||||
}
|
||||
img.src = iconUrl(game.id)
|
||||
if (img.complete && img.naturalWidth > 0) card.prepend(img)
|
||||
if (img.complete && img.naturalWidth > 0) img.onload()
|
||||
}
|
||||
|
||||
function renderLibrary() {
|
||||
|
|
@ -817,6 +832,12 @@ async function openGameConfig(id) {
|
|||
qs('#gc-env').value = Object.entries(game.env || {}).map(([k, v]) => `${k}=${v}`).join('\n')
|
||||
renderWineOptions('gc-wine', game.wine)
|
||||
renderPrefixOptions('gc-prefix', game.prefix)
|
||||
// apps imported from a prefix are pinned to it (their paths are prefix-
|
||||
// relative) - the select is locked, not just corrected on save
|
||||
const prefixLocked = game.importSource === 'prefix'
|
||||
selects['gc-prefix'].setDisabled(prefixLocked)
|
||||
const lockHint = qs('#gc-prefix-lock-hint')
|
||||
if (lockHint) lockHint.style.display = prefixLocked ? '' : 'none'
|
||||
renderOverrides(game.dllOverrides || [])
|
||||
renderTools()
|
||||
}
|
||||
|
|
@ -994,12 +1015,16 @@ function wireEvents() {
|
|||
qs('#btn-gc-shortcut').addEventListener('click', createAppShortcut)
|
||||
qs('#gc-override-add').addEventListener('click', addOverrideRow)
|
||||
qs('#gc-exe-browse').addEventListener('click', async () => {
|
||||
const cur = absPathInput(qs('#gc-workdir').value.trim())
|
||||
// start from the field being edited (exe picker from the exe field) and
|
||||
// resolve the SHOWN path (prefix apps display pfx/drive_c/...) to an
|
||||
// absolute one - absPathInput alone would pass the prefix-relative form
|
||||
// through and the picker would open at the process cwd ('/')
|
||||
const cur = absGamePathInput(qs('#gc-exe').value.trim(), state.currentGame)
|
||||
const p = await window.plwl.dialogPickFile({ properties: ['openFile'], defaultPath: cur || window.plwl.FILES_DIR })
|
||||
if (p) qs('#gc-exe').value = displayGamePath(p, state.currentGame)
|
||||
})
|
||||
qs('#gc-workdir-browse').addEventListener('click', async () => {
|
||||
const cur = absPathInput(qs('#gc-exe').value.trim())
|
||||
const cur = absGamePathInput(qs('#gc-workdir').value.trim(), state.currentGame)
|
||||
const p = await window.plwl.dialogPickFile({ properties: ['openDirectory'], defaultPath: cur || window.plwl.FILES_DIR })
|
||||
if (p) qs('#gc-workdir').value = displayGamePath(p, state.currentGame)
|
||||
})
|
||||
|
|
@ -1012,8 +1037,12 @@ function wireEvents() {
|
|||
applyIconResult(await window.plwl.gamesAutoIcon(state.currentGame.id))
|
||||
})
|
||||
qs('#gc-icon-browse').addEventListener('click', async () => {
|
||||
// start in the app's own folder (prefix apps included) - that is where
|
||||
// the exe with the embedded icon most likely lives
|
||||
const start = absGamePathInput(qs('#gc-workdir').value.trim(), state.currentGame)
|
||||
const p = await window.plwl.dialogPickFile({
|
||||
properties: ['openFile'],
|
||||
defaultPath: start || window.plwl.FILES_DIR,
|
||||
title: t('config.icon.pick'),
|
||||
filters: [{ name: t('config.icon.pick'), extensions: ['png', 'jpg', 'jpeg', 'svg', 'ico', 'webp', 'gif', 'bmp', 'exe'] }]
|
||||
})
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@
|
|||
|
||||
<label class="field-label" data-t="config.prefix"></label>
|
||||
<span id="gc-prefix"></span>
|
||||
<p class="subtitle" id="gc-prefix-lock-hint" data-t="config.prefixLockedHint" style="display:none"></p>
|
||||
|
||||
<label class="field-label" data-t="config.env"></label>
|
||||
<textarea id="gc-env" rows="3" data-ph="config.envHint"></textarea>
|
||||
|
|
|
|||
|
|
@ -476,6 +476,21 @@ select {
|
|||
background: rgba(255, 255, 255, 0.03);
|
||||
align-self: flex-start;
|
||||
}
|
||||
.game-icon.placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--darker-text-color);
|
||||
opacity: 0.45;
|
||||
}
|
||||
.game-icon.placeholder::before {
|
||||
content: '';
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
background: currentColor;
|
||||
-webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'><rect x='3' y='3' width='18' height='18' rx='2'/><circle cx='8.5' cy='8.5' r='1.5'/><path d='M21 15l-5-5L5 21'/></svg>") center / contain no-repeat;
|
||||
mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'><rect x='3' y='3' width='18' height='18' rx='2'/><circle cx='8.5' cy='8.5' r='1.5'/><path d='M21 15l-5-5L5 21'/></svg>") center / contain no-repeat;
|
||||
}
|
||||
.game-card:hover { border-color: rgba(255, 255, 255, 0.2); }
|
||||
.game-card h3 {
|
||||
font-size: 1.05rem;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue