update icon & change PLGL to PLWL
This commit is contained in:
parent
e017187af5
commit
1aa603aeac
18 changed files with 117 additions and 110 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# PLGL — Portable Linux Wine Launcher
|
||||
# PLWL — Portable Linux Wine Launcher
|
||||
|
||||
A portable launcher for Windows games and applications on Linux.
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ npm start
|
|||
|
||||
- **System Wine** — uses the `wine` binary from PATH.
|
||||
- **Imported builds** — drop any wine or Proton build into `files/wines/`. The folder may contain the build directly, or one level of nesting (zip-extracted layouts are detected automatically).
|
||||
- **Proton without Steam** — fully supported. Proton is invoked like Steam does it: `STEAM_COMPAT_CLIENT_INSTALL_PATH` points to a fake steam client folder, `STEAM_COMPAT_DATA_PATH` is a per-build compat folder, and the prefix lives at `<compat>/pfx` which PLGL links to its own prefix folder. No Steam installation required (GE builds work out of the box; for a few Valve builds that refuse to run without a client, PLGL fakes a minimal steam folder in `files/data/fake-steam`).
|
||||
- **Proton without Steam** — fully supported. Proton is invoked like Steam does it: `STEAM_COMPAT_CLIENT_INSTALL_PATH` points to a fake steam client folder, `STEAM_COMPAT_DATA_PATH` is a per-build compat folder, and the prefix lives at `<compat>/pfx` which PLWL links to its own prefix folder. No Steam installation required (GE builds work out of the box; for a few Valve builds that refuse to run without a client, PLWL fakes a minimal steam folder in `files/data/fake-steam`).
|
||||
|
||||
## Translations
|
||||
|
||||
|
|
|
|||
26
build.sh
26
build.sh
|
|
@ -3,36 +3,36 @@ set -e
|
|||
cd "$(dirname "$0")"
|
||||
|
||||
VERSION=$(node -p "require('./package.json').version")
|
||||
OUT="build/PLGL-$VERSION.tar.gz"
|
||||
OUT="build/PLWL-$VERSION.tar.gz"
|
||||
|
||||
bash tools/svg2png.sh renderer/plgl.svg renderer/plgl.png 256
|
||||
bash tools/svg2png.sh renderer/plwl.svg renderer/plwl.png 256
|
||||
|
||||
rm -rf build/dist
|
||||
mkdir -p build/dist/PLGL build/files
|
||||
mkdir -p build/dist/PLWL build/files
|
||||
|
||||
cp -r src renderer tools files package.json build/dist/PLGL/
|
||||
cp -r src renderer tools files package.json build/dist/PLWL/
|
||||
cp -r files/translations build/files/ 2>/dev/null || true
|
||||
|
||||
if [ ! -d node_modules/electron/dist ]; then
|
||||
npm install
|
||||
fi
|
||||
mkdir -p build/dist/PLGL/node_modules/electron
|
||||
cp -r node_modules/electron/dist build/dist/PLGL/node_modules/electron/
|
||||
cp node_modules/electron/package.json build/dist/PLGL/node_modules/electron/
|
||||
cp package.json build/dist/PLGL/
|
||||
cp package-lock.json build/dist/PLGL/ 2>/dev/null || true
|
||||
mkdir -p build/dist/PLWL/node_modules/electron
|
||||
cp -r node_modules/electron/dist build/dist/PLWL/node_modules/electron/
|
||||
cp node_modules/electron/package.json build/dist/PLWL/node_modules/electron/
|
||||
cp package.json build/dist/PLWL/
|
||||
cp package-lock.json build/dist/PLWL/ 2>/dev/null || true
|
||||
|
||||
cat > build/dist/PLGL/run.sh << 'EOF'
|
||||
cat > build/dist/PLWL/run.sh << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
bash tools/svg2png.sh renderer/plgl.svg renderer/plgl.png 256
|
||||
bash tools/svg2png.sh renderer/plwl.svg renderer/plwl.png 256
|
||||
exec ./node_modules/electron/dist/electron . "$@"
|
||||
EOF
|
||||
chmod +x build/dist/PLGL/run.sh
|
||||
chmod +x build/dist/PLWL/run.sh
|
||||
|
||||
mkdir -p build
|
||||
tar -czf "$OUT" -C build/dist PLGL
|
||||
tar -czf "$OUT" -C build/dist PLWL
|
||||
rm -rf build/dist
|
||||
|
||||
echo "Built $OUT"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"nameSelf": "English"
|
||||
},
|
||||
"texts": {
|
||||
"app.title": "PLGL",
|
||||
"app.title": "PLWL",
|
||||
"app.subtitle": "Portable Linux Wine Launcher",
|
||||
|
||||
"nav.library": "Apps",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"nameSelf": "Polski"
|
||||
},
|
||||
"texts": {
|
||||
"app.title": "PLGL",
|
||||
"app.title": "PLWL",
|
||||
"app.subtitle": "Przenośny launcher Wine dla Linuksa",
|
||||
|
||||
"nav.library": "Aplikacje",
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "plgl",
|
||||
"name": "plwl",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "plgl",
|
||||
"name": "plwl",
|
||||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"electron": "^33.2.0"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "plgl",
|
||||
"productName": "PLGL",
|
||||
"name": "plwl",
|
||||
"productName": "PLWL",
|
||||
"version": "0.1.0",
|
||||
"description": "Portable Linux Wine Launcher",
|
||||
"main": "src/main.js",
|
||||
|
|
|
|||
114
renderer/app.js
114
renderer/app.js
|
|
@ -234,11 +234,11 @@ function showView(name) {
|
|||
|
||||
async function loadAll() {
|
||||
const [langs, settings, wines, prefixes, games] = await Promise.all([
|
||||
window.plgl.i18nList(),
|
||||
window.plgl.settingsGet(),
|
||||
window.plgl.winesList(),
|
||||
window.plgl.prefixesList(),
|
||||
window.plgl.gamesList()
|
||||
window.plwl.i18nList(),
|
||||
window.plwl.settingsGet(),
|
||||
window.plwl.winesList(),
|
||||
window.plwl.prefixesList(),
|
||||
window.plwl.gamesList()
|
||||
])
|
||||
state.langs = langs
|
||||
state.settings = settings
|
||||
|
|
@ -250,7 +250,7 @@ async function loadAll() {
|
|||
}
|
||||
|
||||
async function loadLangTexts(code) {
|
||||
const lang = await window.plgl.i18nGet(code)
|
||||
const lang = await window.plwl.i18nGet(code)
|
||||
if (lang && lang.texts) {
|
||||
state.texts = lang.texts
|
||||
state.lang = code
|
||||
|
|
@ -263,7 +263,7 @@ function wineLabel(id) {
|
|||
}
|
||||
|
||||
function iconUrl(id) {
|
||||
return `plgl-icon://${encodeURIComponent(id)}/icon`
|
||||
return `plwl-icon://${encodeURIComponent(id)}/icon`
|
||||
}
|
||||
|
||||
function fmtPlaytime(seconds) {
|
||||
|
|
@ -276,7 +276,7 @@ function fmtPlaytime(seconds) {
|
|||
}
|
||||
|
||||
async function attachCardIcon(card, game) {
|
||||
const p = await window.plgl.gamesIconPath(game.id)
|
||||
const p = await window.plwl.gamesIconPath(game.id)
|
||||
if (!p) return
|
||||
const img = document.createElement('img')
|
||||
img.className = 'game-icon'
|
||||
|
|
@ -324,26 +324,26 @@ function renderLibrary() {
|
|||
killBtn.style.display = isRunning ? '' : 'none'
|
||||
}
|
||||
runningCards.set(game.id, { applyRunning, lastMeta, game })
|
||||
window.plgl.gamesIsRunning(game.id).then(applyRunning)
|
||||
window.plwl.gamesIsRunning(game.id).then(applyRunning)
|
||||
playBtn.onclick = () => playGame(game)
|
||||
killBtn.onclick = async () => {
|
||||
await window.plgl.gamesKill(game.id)
|
||||
await window.plwl.gamesKill(game.id)
|
||||
applyRunning(false)
|
||||
}
|
||||
card.querySelector('[data-act=config]').onclick = () => openGameConfig(game.id)
|
||||
card.querySelector('[data-act=folder]').onclick = () => window.plgl.shellOpenPath(game.workdir)
|
||||
card.querySelector('[data-act=folder]').onclick = () => window.plwl.shellOpenPath(game.workdir)
|
||||
card.querySelector('[data-act=logs]').onclick = async () => {
|
||||
const logs = await window.plgl.gamesGetLogs(game.id)
|
||||
if (logs.length) window.plgl.shellShowItemInFolder(logs[logs.length - 1])
|
||||
const logs = await window.plwl.gamesGetLogs(game.id)
|
||||
if (logs.length) window.plwl.shellShowItemInFolder(logs[logs.length - 1])
|
||||
else toast(t('library.viewLogs'))
|
||||
}
|
||||
card.querySelector('[data-act=remove]').onclick = async () => {
|
||||
const note = game.mode === 'copy' || game.mode === 'move' ? t('library.removeFilesNote') : ''
|
||||
const ok = await confirmModal(t('library.removeConfirm', game.name, note), t('library.remove'))
|
||||
if (!ok) return
|
||||
await window.plgl.gamesRemove(game.id)
|
||||
await window.plwl.gamesRemove(game.id)
|
||||
toast(t('toast.gameRemoved', game.name), 'success')
|
||||
state.games = await window.plgl.gamesList()
|
||||
state.games = await window.plwl.gamesList()
|
||||
renderLibrary()
|
||||
}
|
||||
list.appendChild(card)
|
||||
|
|
@ -352,7 +352,7 @@ function renderLibrary() {
|
|||
}
|
||||
|
||||
async function playGame(game) {
|
||||
const res = await window.plgl.gamesRun(game.id)
|
||||
const res = await window.plwl.gamesRun(game.id)
|
||||
if (res.ok) {
|
||||
const entry = runningCards.get(game.id)
|
||||
if (entry) entry.applyRunning(true)
|
||||
|
|
@ -367,8 +367,8 @@ async function playGame(game) {
|
|||
}
|
||||
|
||||
async function refreshLibraryData() {
|
||||
state.games = await window.plgl.gamesList()
|
||||
const runningList = await window.plgl.gamesListRunning()
|
||||
state.games = await window.plwl.gamesList()
|
||||
const runningList = await window.plwl.gamesListRunning()
|
||||
const runningSet = new Set(runningList)
|
||||
for (const [id, entry] of runningCards) {
|
||||
entry.applyRunning(runningSet.has(id))
|
||||
|
|
@ -381,7 +381,7 @@ async function refreshLibraryData() {
|
|||
}
|
||||
|
||||
function wireRealtime() {
|
||||
window.plgl.onGamesChanged(() => {
|
||||
window.plwl.onGamesChanged(() => {
|
||||
if (state.currentView === 'library') refreshLibraryData()
|
||||
})
|
||||
}
|
||||
|
|
@ -404,7 +404,7 @@ async function startImportFlow() {
|
|||
btn.onclick = async () => {
|
||||
const mode = btn.dataset.mode
|
||||
closeModal()
|
||||
const srcDir = await window.plgl.gamesPickFolder()
|
||||
const srcDir = await window.plwl.gamesPickFolder()
|
||||
if (!srcDir) return
|
||||
await doImport(srcDir, mode)
|
||||
}
|
||||
|
|
@ -419,16 +419,16 @@ async function doImport(srcDir, mode) {
|
|||
<p id="import-status"></p>
|
||||
`)
|
||||
let count = 0
|
||||
window.plgl.onImportProgress(() => {
|
||||
window.plwl.onImportProgress(() => {
|
||||
count++
|
||||
const status = modal.querySelector('#import-status')
|
||||
if (status) status.textContent = t('import.fileDone', count)
|
||||
})
|
||||
try {
|
||||
const game = await window.plgl.gamesImport(srcDir, mode)
|
||||
const game = await window.plwl.gamesImport(srcDir, mode)
|
||||
closeModal()
|
||||
toast(t('toast.importDone', game.name), 'success')
|
||||
state.games = await window.plgl.gamesList()
|
||||
state.games = await window.plwl.gamesList()
|
||||
renderLibrary()
|
||||
await openGameConfig(game.id)
|
||||
} catch (err) {
|
||||
|
|
@ -466,9 +466,9 @@ function renderPrefixes() {
|
|||
const defBtn = row.querySelector('[data-act=default]')
|
||||
defBtn.textContent = t('prefixes.makeDefault')
|
||||
defBtn.onclick = async () => {
|
||||
const res = await window.plgl.prefixesSetDefault(p.name)
|
||||
const res = await window.plwl.prefixesSetDefault(p.name)
|
||||
if (res && res.ok !== false) toast(t('toast.prefixDefault', p.name), 'success')
|
||||
state.prefixes = await window.plgl.prefixesList()
|
||||
state.prefixes = await window.plwl.prefixesList()
|
||||
renderPrefixes()
|
||||
}
|
||||
const delBtn = row.querySelector('[data-act=delete]')
|
||||
|
|
@ -476,11 +476,11 @@ function renderPrefixes() {
|
|||
delBtn.onclick = async () => {
|
||||
const ok = await confirmModal(t('prefixes.deleteConfirm', p.name), t('prefixes.delete'))
|
||||
if (!ok) return
|
||||
const res = await window.plgl.prefixesDelete(p.name)
|
||||
const res = await window.plwl.prefixesDelete(p.name)
|
||||
if (res.ok) toast(t('toast.prefixDeleted', p.name), 'success')
|
||||
else if (res.error === 'isMain') toast(t('prefixes.mainLocked'), 'error')
|
||||
else toast(t('toast.prefixDeleteFailed', p.name), 'error')
|
||||
state.prefixes = await window.plgl.prefixesList()
|
||||
state.prefixes = await window.plwl.prefixesList()
|
||||
renderPrefixes()
|
||||
}
|
||||
list.appendChild(row)
|
||||
|
|
@ -521,9 +521,9 @@ function renderWines() {
|
|||
const defBtn = row.querySelector('[data-act=default]')
|
||||
defBtn.textContent = t('wines.makeDefault')
|
||||
defBtn.onclick = async () => {
|
||||
const res = await window.plgl.winesSetDefault(w.id)
|
||||
const res = await window.plwl.winesSetDefault(w.id)
|
||||
if (res && res.ok) {
|
||||
state.settings = await window.plgl.settingsGet()
|
||||
state.settings = await window.plwl.settingsGet()
|
||||
toast(t('wines.defaultSet', w.label), 'success')
|
||||
}
|
||||
renderWines()
|
||||
|
|
@ -534,11 +534,11 @@ function renderWines() {
|
|||
delBtn.onclick = async () => {
|
||||
const ok = await confirmModal(t('wines.deleteConfirm', w.label), t('wines.delete'))
|
||||
if (!ok) return
|
||||
const res = await window.plgl.winesDelete(w.id)
|
||||
const res = await window.plwl.winesDelete(w.id)
|
||||
if (res.ok) {
|
||||
toast(t('wines.deleted', w.label), 'success')
|
||||
state.wines = await window.plgl.winesList()
|
||||
state.settings = await window.plgl.settingsGet()
|
||||
state.wines = await window.plwl.winesList()
|
||||
state.settings = await window.plwl.settingsGet()
|
||||
} else if (res.error === 'isSystem') {
|
||||
toast(t('wines.systemLocked'), 'error')
|
||||
}
|
||||
|
|
@ -561,12 +561,12 @@ function renderSettings() {
|
|||
}
|
||||
|
||||
async function saveSettings() {
|
||||
state.settings = await window.plgl.settingsSet({
|
||||
state.settings = await window.plwl.settingsSet({
|
||||
language: selects['set-language'].value,
|
||||
defaultWine: selects['set-wine'].value
|
||||
})
|
||||
await window.plgl.prefixesSetDefault(selects['set-prefix'].value || state.prefixes.default)
|
||||
state.prefixes = await window.plgl.prefixesList()
|
||||
await window.plwl.prefixesSetDefault(selects['set-prefix'].value || state.prefixes.default)
|
||||
state.prefixes = await window.plwl.prefixesList()
|
||||
const lang = selects['set-language'].value
|
||||
if (lang !== state.lang) {
|
||||
await loadLangTexts(lang)
|
||||
|
|
@ -601,7 +601,7 @@ function renderPrefixOptions(selectId, selected) {
|
|||
async function refreshConfigIcon() {
|
||||
const game = state.currentGame
|
||||
if (!game) return
|
||||
const p = await window.plgl.gamesIconPath(game.id)
|
||||
const p = await window.plwl.gamesIconPath(game.id)
|
||||
const img = qs('#gc-icon')
|
||||
const ph = qs('#gc-icon-placeholder')
|
||||
img.onerror = () => {
|
||||
|
|
@ -703,8 +703,8 @@ async function saveGameConfig() {
|
|||
env,
|
||||
dllOverrides: readOverrides()
|
||||
}
|
||||
await window.plgl.gamesUpdate(game.id, patch)
|
||||
state.games = await window.plgl.gamesList()
|
||||
await window.plwl.gamesUpdate(game.id, patch)
|
||||
state.games = await window.plwl.gamesList()
|
||||
toast(t('config.saved'), 'success')
|
||||
if (state.currentView === 'gameconfig') {
|
||||
state.currentGame = { ...state.currentGame, ...patch }
|
||||
|
|
@ -722,7 +722,7 @@ function renderTools() {
|
|||
btn.innerHTML = `${ICONS.terminal()}<span>${tool}</span>`
|
||||
btn.onclick = async () => {
|
||||
const game = state.currentGame
|
||||
const res = await window.plgl.gamesRunTool(game.id, tool, '')
|
||||
const res = await window.plwl.gamesRunTool(game.id, tool, '')
|
||||
if (res.ok) toast(t('toast.started', tool))
|
||||
else toast(t('toast.startFailed', tool, res.error || ''), 'error')
|
||||
}
|
||||
|
|
@ -735,7 +735,7 @@ async function runCustomTool() {
|
|||
if (!input) return
|
||||
const [tool, ...rest] = input.split(/\s+/)
|
||||
const game = state.currentGame
|
||||
const res = await window.plgl.gamesRunTool(game.id, tool, rest.join(' '))
|
||||
const res = await window.plwl.gamesRunTool(game.id, tool, rest.join(' '))
|
||||
if (res.ok) toast(t('toast.started', tool))
|
||||
else toast(t('toast.startFailed', tool, res.error || ''), 'error')
|
||||
}
|
||||
|
|
@ -751,54 +751,54 @@ function wireEvents() {
|
|||
const input = qs('#prefix-name-input')
|
||||
const name = input.value.trim()
|
||||
if (!name) return
|
||||
const res = await window.plgl.prefixesCreate(name)
|
||||
const res = await window.plwl.prefixesCreate(name)
|
||||
if (!res.ok) {
|
||||
toast(t(res.error === 'alreadyExists' ? 'prefixes.exists' : 'prefixes.invalidName'), 'error')
|
||||
return
|
||||
}
|
||||
input.value = ''
|
||||
toast(t('toast.prefixCreated', res.name), 'success')
|
||||
state.prefixes = await window.plgl.prefixesList()
|
||||
state.prefixes = await window.plwl.prefixesList()
|
||||
renderPrefixes()
|
||||
})
|
||||
qs('#btn-wines-rescan').addEventListener('click', async () => {
|
||||
await window.plgl.winesRefresh()
|
||||
state.wines = await window.plgl.winesList()
|
||||
await window.plwl.winesRefresh()
|
||||
state.wines = await window.plwl.winesList()
|
||||
renderWines()
|
||||
})
|
||||
qs('#btn-wines-import').addEventListener('click', async () => {
|
||||
const srcDir = await window.plgl.dialogPickFile({ properties: ['openDirectory'], title: t('wines.importPick') })
|
||||
const srcDir = await window.plwl.dialogPickFile({ properties: ['openDirectory'], title: t('wines.importPick') })
|
||||
if (!srcDir) return
|
||||
const modal = showModal(`
|
||||
<h2>${t('wines.importing')}</h2>
|
||||
<div class="progress-row"><progress></progress></div>
|
||||
`)
|
||||
const res = await window.plgl.winesImport(srcDir)
|
||||
const res = await window.plwl.winesImport(srcDir)
|
||||
closeModal()
|
||||
if (res.ok) {
|
||||
toast(t('wines.imported', res.path), 'success')
|
||||
state.wines = await window.plgl.winesList()
|
||||
state.wines = await window.plwl.winesList()
|
||||
} else {
|
||||
toast(t('toast.importFailed') + ': ' + (res.error || ''), 'error')
|
||||
}
|
||||
renderWines()
|
||||
})
|
||||
qs('#btn-settings-save').addEventListener('click', saveSettings)
|
||||
qs('#btn-open-files').addEventListener('click', () => window.plgl.shellOpenPath(window.plgl.FILES_DIR))
|
||||
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('#gc-override-add').addEventListener('click', addOverrideRow)
|
||||
qs('#gc-exe-browse').addEventListener('click', async () => {
|
||||
const p = await window.plgl.dialogPickFile({ properties: ['openFile'], defaultPath: qs('#gc-workdir').value || window.plgl.FILES_DIR })
|
||||
const p = await window.plwl.dialogPickFile({ properties: ['openFile'], defaultPath: qs('#gc-workdir').value || window.plwl.FILES_DIR })
|
||||
if (p) qs('#gc-exe').value = p
|
||||
})
|
||||
qs('#gc-workdir-browse').addEventListener('click', async () => {
|
||||
const p = await window.plgl.dialogPickFile({ properties: ['openDirectory'], defaultPath: qs('#gc-exe').value || window.plgl.FILES_DIR })
|
||||
const p = await window.plwl.dialogPickFile({ properties: ['openDirectory'], defaultPath: qs('#gc-exe').value || window.plwl.FILES_DIR })
|
||||
if (p) qs('#gc-workdir').value = p
|
||||
})
|
||||
qs('#gc-tool-run').addEventListener('click', runCustomTool)
|
||||
qs('#gc-icon-auto').addEventListener('click', async () => {
|
||||
const res = await window.plgl.gamesAutoIcon(state.currentGame.id)
|
||||
const res = await window.plwl.gamesAutoIcon(state.currentGame.id)
|
||||
if (res.ok) {
|
||||
toast(t('config.icon.set'), 'success')
|
||||
refreshConfigIcon()
|
||||
|
|
@ -807,7 +807,7 @@ function wireEvents() {
|
|||
}
|
||||
})
|
||||
qs('#gc-icon-browse').addEventListener('click', async () => {
|
||||
const p = await window.plgl.dialogPickFile({
|
||||
const p = await window.plwl.dialogPickFile({
|
||||
properties: ['openFile'],
|
||||
title: t('config.icon.pick'),
|
||||
filters: [{ name: t('config.icon.pick'), extensions: ['png', 'jpg', 'jpeg', 'svg', 'ico', 'webp', 'gif', 'bmp', 'exe'] }]
|
||||
|
|
@ -815,25 +815,25 @@ function wireEvents() {
|
|||
if (!p) return
|
||||
let res
|
||||
if (p.toLowerCase().endsWith('.exe')) {
|
||||
res = await window.plgl.gamesSetIconFile(state.currentGame.id, p)
|
||||
res = await window.plwl.gamesSetIconFile(state.currentGame.id, p)
|
||||
if (res.ok) toast(t('config.icon.set'), 'success')
|
||||
else toast(t('config.icon.noIcon'), 'error')
|
||||
} else {
|
||||
res = await window.plgl.gamesSetIconFile(state.currentGame.id, p)
|
||||
res = await window.plwl.gamesSetIconFile(state.currentGame.id, p)
|
||||
if (res.ok) toast(t('config.icon.set'), 'success')
|
||||
else toast(t('config.icon.noIcon'), 'error')
|
||||
}
|
||||
refreshConfigIcon()
|
||||
})
|
||||
qs('#gc-icon-reset').addEventListener('click', async () => {
|
||||
await window.plgl.gamesResetIcon(state.currentGame.id)
|
||||
await window.plwl.gamesResetIcon(state.currentGame.id)
|
||||
refreshConfigIcon()
|
||||
})
|
||||
qs('#btn-gc-clear-playtime').addEventListener('click', async () => {
|
||||
const ok = await confirmModal(t('config.clearPlaytimeConfirm'), t('config.clearPlaytime'))
|
||||
if (!ok) return
|
||||
await window.plgl.gamesClearPlaytime(state.currentGame.id)
|
||||
state.games = await window.plgl.gamesList()
|
||||
await window.plwl.gamesClearPlaytime(state.currentGame.id)
|
||||
state.games = await window.plwl.gamesList()
|
||||
state.currentGame = state.games.find(g => g.id === state.currentGame.id)
|
||||
toast(t('config.playtimeCleared'), 'success')
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: plgl-icon:;">
|
||||
<title>PLGL</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: plwl-icon:;">
|
||||
<title>PLWL</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<loading id="loading">
|
||||
<div class="loading-inner">
|
||||
<div class="loading-logo">PLGL</div>
|
||||
<div class="loading-logo">PLWL</div>
|
||||
<p id="loadingstatus"></p>
|
||||
</div>
|
||||
</loading>
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB |
|
|
@ -1,14 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#2a2a2e"/>
|
||||
<stop offset="1" stop-color="#161618"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect x="16" y="16" width="224" height="224" rx="48" fill="url(#bg)" stroke="#3c3c42" stroke-width="4"/>
|
||||
<g fill="none" stroke="#eaeaf0" stroke-width="14" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M78 88l40 40-40 40"/>
|
||||
<path d="M132 168h46"/>
|
||||
</g>
|
||||
<path d="M186 64c0 22-14 34-30 38v18h-16v-18c-16-4-30-16-30-38 0-4 3-8 8-8s8 4 8 8c0 12 8 20 22 20s22-8 22-20c0-4 3-8 8-8s8 4 8 8z" fill="#eaeaf0"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 688 B |
BIN
renderer/plwl.png
Normal file
BIN
renderer/plwl.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
21
renderer/plwl.svg
Normal file
21
renderer/plwl.svg
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="#2a2a2e"/>
|
||||
<stop offset="1" stop-color="#161618"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<rect x="16" y="16" width="224" height="224" rx="48" fill="url(#bg)" stroke="#3c3c42" stroke-width="4"/>
|
||||
|
||||
<path d="M 145 108 C 148 126 159 135 168 135 C 177 135 188 126 191 108 Z" fill="#eaeaf0"/>
|
||||
|
||||
<g fill="none" stroke="#eaeaf0" stroke-width="10" stroke-linecap="round" stroke-linejoin="round">
|
||||
|
||||
<path d="M 66 100 L 94 128 L 66 156"/>
|
||||
|
||||
<path d="M 140 78 C 140 120 158 138 168 138 C 178 138 196 120 196 78"/>
|
||||
<path d="M 168 138 V 178"/>
|
||||
<path d="M 146 178 H 190"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 755 B |
2
run.sh
2
run.sh
|
|
@ -7,7 +7,7 @@ if [ ! -d node_modules ]; then
|
|||
npm install
|
||||
fi
|
||||
|
||||
bash tools/svg2png.sh renderer/plgl.svg renderer/plgl.png 256
|
||||
bash tools/svg2png.sh renderer/plwl.svg renderer/plwl.png 256
|
||||
|
||||
mkdir -p build/files
|
||||
cp -r files/translations build/files/ 2>/dev/null || true
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
|
||||
const APP_NAME = 'PLGL'
|
||||
const APP_NAME = 'PLWL'
|
||||
|
||||
function findPng() {
|
||||
const p = path.resolve(__dirname, '..', 'renderer', 'plgl.png')
|
||||
const p = path.resolve(__dirname, '..', 'renderer', 'plwl.png')
|
||||
try {
|
||||
fs.accessSync(p)
|
||||
return p
|
||||
|
|
@ -24,7 +24,7 @@ function writeIconThemeDirs(png) {
|
|||
for (const [dir, size] of Object.entries(sizes)) {
|
||||
const themeDir = path.join(base, 'hicolor', dir, 'apps')
|
||||
fs.mkdirSync(themeDir, { recursive: true })
|
||||
fs.copyFileSync(png, path.join(themeDir, 'plgl.png'))
|
||||
fs.copyFileSync(png, path.join(themeDir, 'plwl.png'))
|
||||
}
|
||||
const desktopDir = path.join(home, '.local', 'share', 'applications')
|
||||
fs.mkdirSync(desktopDir, { recursive: true })
|
||||
|
|
@ -33,12 +33,12 @@ function writeIconThemeDirs(png) {
|
|||
'Type=Application',
|
||||
`Name=${APP_NAME}`,
|
||||
'Comment=Portable Linux Wine Launcher',
|
||||
'Exec=plgl',
|
||||
`Icon=plgl`,
|
||||
'Exec=plwl',
|
||||
`Icon=plwl`,
|
||||
'Terminal=false',
|
||||
'Categories=Game;'
|
||||
].join('\n')
|
||||
fs.writeFileSync(path.join(desktopDir, 'plgl.desktop'), desktop)
|
||||
fs.writeFileSync(path.join(desktopDir, 'plwl.desktop'), desktop)
|
||||
} catch {}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const importer = require('./importer')
|
|||
const i18n = require('./i18n')
|
||||
const { createMainWindow } = require('./window')
|
||||
|
||||
app.setName('PLGL')
|
||||
app.setName('PLWL')
|
||||
|
||||
let win = null
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ function scanGamesFolder(dir, depth, out) {
|
|||
for (const e of entries) {
|
||||
if (!e.isDirectory()) continue
|
||||
const full = path.join(dir, e.name)
|
||||
if (require('fs').existsSync(path.join(full, '.plgl-imported'))) {
|
||||
if (require('fs').existsSync(path.join(full, '.plwl-imported'))) {
|
||||
out.push(full)
|
||||
} else {
|
||||
scanGamesFolder(full, depth - 1, out)
|
||||
|
|
@ -190,7 +190,7 @@ ipcMain.handle('games:import', async (e, srcDir, mode) => {
|
|||
}
|
||||
const game = await importer.importGame(srcDir, mode, onProgress)
|
||||
library.addGame(game)
|
||||
require('fs').writeFileSync(path.join(game.workdir, '.plgl-imported'), '')
|
||||
require('fs').writeFileSync(path.join(game.workdir, '.plwl-imported'), '')
|
||||
return game
|
||||
})
|
||||
|
||||
|
|
@ -309,7 +309,7 @@ app.whenReady().then(async () => {
|
|||
setAppIcon(app)
|
||||
} catch {}
|
||||
}
|
||||
protocol.handle('plgl-icon', request => {
|
||||
protocol.handle('plwl-icon', request => {
|
||||
const id = decodeURIComponent(new URL(request.url).hostname)
|
||||
const dir = path.join(DIRS.DATA, 'icons', id)
|
||||
let file = null
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const fs = require('fs')
|
|||
|
||||
const APP_ROOT = path.resolve(__dirname, '..')
|
||||
|
||||
const BUILD = process.env.PLGL_BUILD_DIR || path.join(APP_ROOT, 'build')
|
||||
const BUILD = process.env.PLWL_BUILD_DIR || path.join(APP_ROOT, 'build')
|
||||
const BUNDLED = path.join(APP_ROOT, 'files')
|
||||
|
||||
const FILES = path.join(BUILD, 'files')
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
const { DIRS } = require('./paths')
|
||||
|
||||
contextBridge.exposeInMainWorld('plgl', {
|
||||
contextBridge.exposeInMainWorld('plwl', {
|
||||
FILES_DIR: DIRS.FILES,
|
||||
i18nList: () => ipcRenderer.invoke('i18n:list'),
|
||||
i18nGet: code => ipcRenderer.invoke('i18n:get', code),
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ const DIST = path.resolve(__dirname, '..', 'renderer')
|
|||
|
||||
function resolveIcon() {
|
||||
const candidates = [
|
||||
path.join(DIST, 'plgl.png'),
|
||||
path.join(DIST, 'plgl.svg')
|
||||
path.join(DIST, 'plwl.png'),
|
||||
path.join(DIST, 'plwl.svg')
|
||||
]
|
||||
for (const c of candidates) {
|
||||
try {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue