add tray & creating shortcuts

This commit is contained in:
olcxja 2026-09-26 13:57:12 +02:00
commit 1097a1f441
11 changed files with 452 additions and 22 deletions

View file

@ -26,14 +26,14 @@ function t(key, ...args) {
}
const ICONS = {
// app grid — the library view (games AND other Windows apps)
// app grid - the library view (games AND other Windows apps)
library: () => '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="3.5" width="7.5" height="7.5" rx="2"/><rect x="13" y="3.5" width="7.5" height="7.5" rx="2"/><rect x="3.5" y="13" width="7.5" height="7.5" rx="2"/><rect x="13" y="13" width="7.5" height="7.5" rx="2"/></svg>',
// stacked layers — wine prefixes stacked on top of each other
// stacked layers - wine prefixes stacked on top of each other
prefixes: () => '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3 3.5 7.25 12 11.5l8.5-4.25L12 3Z"/><path d="m3.5 12.25 8.5 4.25 8.5-4.25"/><path d="m3.5 16.75 8.5 4.25 8.5-4.25"/></svg>',
// wine glass — wine/proton runners
// wine glass - wine/proton runners
wines: () => '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 22h8"/><path d="M12 15v7"/><path d="M7 10h10"/><path d="M12 15a5 5 0 0 0 5-5c0-2-.5-4-2-8H9c-1.5 4-2 6-2 8a5 5 0 0 0 5 5Z"/></svg>',
settings: () => '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19 12a7 7 0 0 0-.1-1.2l2-1.5-2-3.5-2.4 1a7 7 0 0 0-2-1.2L14 3h-4l-.5 2.6a7 7 0 0 0-2 1.2l-2.4-1-2 3.5 2 1.5a7 7 0 0 0 0 2.4l-2 1.5 2 3.5 2.4-1a7 7 0 0 0 2 1.2L10 21h4l.5-2.6a7 7 0 0 0 2-1.2l2.4 1 2-3.5-2-1.5c.06-.4.1-.8.1-1.2z"/></svg>',
// arrow into a tray — import
// arrow into a tray - import
import: () => '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v10"/><path d="m8 9 4 4 4-4"/><path d="M4 16v2.5A2.5 2.5 0 0 0 6.5 21h11a2.5 2.5 0 0 0 2.5-2.5V16"/></svg>',
config: () => '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 21v-7M4 10V3M12 21v-9M12 8V3M20 21v-5M20 12V3M1 14h6M9 8h6M17 16h6"/></svg>',
folder: () => '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>',
@ -619,12 +619,14 @@ function renderSettings() {
selects['set-language'].update(state.langs.map(l => ({ value: l.code, label: l.nameSelf })), state.lang)
selects['set-wine'].update(state.wines.map(w => ({ value: w.id, label: w.label })), state.settings.defaultWine || 'system')
selects['set-prefix'].update(state.prefixes.prefixes.map(p => ({ value: p.name, label: p.name })), state.prefixes.default)
qs('#set-closetotray').checked = state.settings.closeToTray !== false
}
async function saveSettings() {
state.settings = await window.plwl.settingsSet({
language: selects['set-language'].value,
defaultWine: selects['set-wine'].value
defaultWine: selects['set-wine'].value,
closeToTray: qs('#set-closetotray').checked
})
await window.plwl.prefixesSetDefault(selects['set-prefix'].value || state.prefixes.default)
state.prefixes = await window.plwl.prefixesList()
@ -702,6 +704,17 @@ async function openGameConfig(id) {
renderTools()
}
async function createAppShortcut() {
const game = state.currentGame
if (!game) return
const res = await window.plwl.gamesCreateShortcut(game.id)
if (res && res.ok) {
toast(t('config.shortcutCreated', game.name), 'success')
} else {
toast(t('config.shortcutFailed') + ': ' + ((res && res.error) || ''), 'error')
}
}
function renderOverrides(overrides) {
const box = qs('#gc-overrides')
box.innerHTML = ''
@ -848,6 +861,7 @@ function wireEvents() {
qs('#btn-open-files').addEventListener('click', () => window.plwl.shellOpenPath(window.plwl.FILES_DIR))
qs('#btn-gc-back').addEventListener('click', () => showView('library'))
qs('#btn-gc-save').addEventListener('click', saveGameConfig)
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())

View file

@ -101,6 +101,10 @@
<span id="set-wine"></span>
<label class="field-label" data-t="settings.defaultPrefix"></label>
<span id="set-prefix"></span>
<label class="check-label">
<input type="checkbox" id="set-closetotray">
<span data-t="settings.closeToTray"></span>
</label>
<div class="form-actions">
<button class="button primary" id="btn-settings-save" data-t="settings.save"></button>
<button class="button" id="btn-open-files" data-t="settings.openFiles"></button>
@ -163,6 +167,7 @@
<div class="form-actions">
<button class="button danger" id="btn-gc-clear-playtime" data-t="config.clearPlaytime"></button>
<button class="button" id="btn-gc-shortcut" data-t="config.shortcut"></button>
<button class="button primary" id="btn-gc-save" data-t="config.save"></button>
</div>
</div>

View file

@ -284,6 +284,55 @@ input:active, textarea:active { background-color: rgba(255, 255, 255, 0.1); }
input:focus, textarea:focus { border-color: rgba(255, 255, 255, 0.25); background-color: rgba(255, 255, 255, 0.1); }
textarea { resize: vertical; font-family: inherit; }
/* --- checkbox: styled to match the app (radius, borders, press feedback) --- */
.check-label {
display: flex;
align-items: center;
gap: 0.7rem;
margin-top: 1.1rem; /* extra breathing room below the custom-select */
margin-bottom: var(--button-margin);
cursor: pointer;
color: var(--darker-text-color);
user-select: none;
}
.check-label:hover { color: var(--text-color); }
input[type='checkbox'] {
-webkit-appearance: none;
appearance: none;
width: 1.7rem;
height: 1.7rem;
min-height: 0;
flex: 0 0 auto;
margin: 0;
padding: 0;
border-radius: 0.65rem;
background-color: rgba(255, 255, 255, 0.05);
border: var(--border-width) solid var(--light-border-color);
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
backface-visibility: hidden;
transform: translateZ(0);
transition: all 0.15s ease;
}
input[type='checkbox']:hover { background-color: rgba(255, 255, 255, 0.09); }
input[type='checkbox']:active { background-color: rgba(255, 255, 255, 0.1); transform: var(--press-scale); }
input[type='checkbox']:focus-visible { border-color: rgba(255, 255, 255, 0.25); }
input[type='checkbox']:checked {
background-color: var(--text-color);
border-color: var(--text-color);
}
input[type='checkbox']:checked::before {
content: '';
width: 0.95rem;
height: 0.95rem;
background: var(--main-bg-color);
-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='3.5' stroke-linecap='round' stroke-linejoin='round'><path d='M4 12.5l5.5 5.5L20 6.5'/></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='3.5' stroke-linecap='round' stroke-linejoin='round'><path d='M4 12.5l5.5 5.5L20 6.5'/></svg>") center / contain no-repeat;
}
.check-label input[type='checkbox']:checked + span { color: var(--text-color); }
select {
display: none;
}