switch to doT templates and related cleanup

This commit is contained in:
Tyler Wilding 2022-04-12 00:42:05 -04:00
parent 58627414f5
commit 87e50f2edb
No known key found for this signature in database
GPG key ID: A89403EB356ED106
12 changed files with 215 additions and 194 deletions

View file

@ -1,42 +0,0 @@
// TODO some minimal templating might help - https://olado.github.io/doT/index.html
export const jak1_sidebar = `<div class="games">
<div class="jak-1 nav-item active">
<a data-tooltip="Jak & Daxter: The Precursor Legacy">
<img src="src/assets/images/jak-tpl.png">
</a>
</div>
<div class="jak-2 nav-item">
<a data-tooltip="Jak 2">
<img src="src/assets/images/jak-2.png">
</a>
</div>
<div class="jak-3 nav-item">
<a data-tooltip="Jak 3">
<img src="src/assets/images/jak-3.png">
</a>
</div>
</div>
<div class="spacer"></div>
<div class="controls">
<div class="console nav-item">
<a data-tooltip="Toggle Debug Console">
<i class="bi bi-terminal-fill"></i>
</a>
</div>
<div class="settings nav-item">
<a data-tooltip="Settings">
<i class="bi bi-sliders" key="settings"></i>
</a>
</div>
</div>`;
export const jak1_main = `<div class="flex-center">
<div class="logo">
<img id="logo" width="65%" src="src/assets/images/logo.png">
</div>
<div class="buttons" id="launcherControls"></div>
</div>`;

View file

@ -11,54 +11,12 @@
<body>
<div class="video-container">
<div class="overlay"></div>
<video id="background" src="src/assets/videos/background.mp4" autoplay muted loop></video>
<video id="backgroundVideo" src="src/assets/videos/background.mp4" autoplay muted loop></video>
</div>
<div class="container">
<div class="sidebar">
<div class="games">
<div class="jak-1 nav-item active">
<a data-tooltip="Jak & Daxter: The Precursor Legacy">
<img src="src/assets/images/jak-tpl.png">
</a>
</div>
<div class="jak-2 nav-item disabled">
<a data-tooltip="Jak 2 - Not Available!">
<img src="src/assets/images/jak-2.png">
</a>
</div>
<div class="jak-3 nav-item disabled">
<a data-tooltip="Jak 3 - Not Available!">
<img src="src/assets/images/jak-3.png">
</a>
</div>
</div>
<div class="spacer"></div>
<div class="controls">
<div class="console nav-item">
<a data-tooltip="Toggle Debug Console">
<i class="bi bi-terminal-fill"></i>
</a>
</div>
<div class="settings nav-item">
<a data-tooltip="Settings">
<i class="bi bi-sliders" key="settings"></i>
</a>
</div>
</div>
</div>
<div class="main">
<div class="flex-center">
<div class="logo">
<img id="logo" width="65%" src="src/assets/images/logo.png">
</div>
<div class="buttons" id="launcherControls"></div>
</div>
</div>
<div id="sidebar"></div>
<div id="main"></div>
</div>
<script defer type="module" src="/main.js"></script>

108
main.js
View file

@ -1,67 +1,35 @@
import './style.css'
import { actions, general_pane, files_pane, links_pane } from './components/settings/settings';
import { jak1_main, jak1_sidebar } from './components/jak1/jak1';
import { isoSeries } from './src/utils/iso';
import { launchGame } from './src/utils/launch';
import { getInstallStatus } from './src/utils/store';
import { initConfig, getInstallStatus, getLastActiveGame, SupportedGame } from './src/config/config';
import { mainTemplate } from './src/views/main.dot';
import { sidebarTemplate } from './src/views/sidebar.dot';
const sidebar = document.querySelector('.sidebar');
// Main App Startup Routine
(async function () {
// Create the default or load the config
await initConfig();
// Render the App
await renderApp();
}());
sidebar.onclick = e => {
switch (e.target.getAttribute('key')) {
case 'return':
document.querySelector('.main').innerHTML = jak1_main;
document.querySelector('.sidebar').innerHTML = jak1_sidebar;
break;
case 'settings':
document.querySelector('.main').innerHTML = general_pane;
document.querySelector('.sidebar').innerHTML = actions;
break;
case 'general':
document.querySelector('.main').innerHTML = general_pane;
break;
case 'links':
document.querySelector('.main').innerHTML = links_pane;
break;
case 'files':
document.querySelector('.main').innerHTML = files_pane;
break;
}
renderControls();
}
// Main App Rendering Handler
async function renderApp() {
const activeGame = await getLastActiveGame();
const gameInstalled = await getInstallStatus(activeGame);
document.getElementById("sidebar").innerHTML = sidebarTemplate({
jak1Active: activeGame.name == SupportedGame.Jak1.name,
jak2Active: activeGame.name == SupportedGame.Jak2.name,
jak3Active: activeGame.name == SupportedGame.Jak3.name,
jakxActive: activeGame.name == SupportedGame.JakX.name,
});
document.getElementById("main").innerHTML = mainTemplate({
gameInstalled: gameInstalled
});
class SupportedGame {
static Jak1 = new SupportedGame("Jak 1")
static Jak2 = new SupportedGame("Jak 2")
static Jak3 = new SupportedGame("Jak 3")
static JakX = new SupportedGame("Jak X")
constructor(name) {
this.name = name
}
}
async function isGameSetup(supportedGame) {
if (supportedGame == SupportedGame.Jak1) {
// TODO - check the installation directory and such, wherever that ends up being
const isInstalled = await getInstallStatus(supportedGame.name);
return isInstalled;
} else {
return false;
}
}
// TODO - detect last played game, right now its assumed that jak 1 is always selected by default
let activeGame = SupportedGame.Jak1;
renderControls();
export async function renderControls() {
if (document.getElementById("launcherControls") == undefined) {
return;
}
if (await isGameSetup(activeGame)) {
document.getElementById("launcherControls").innerHTML = `<button id="configBtn">CONFIG</button><button id="playBtn">PLAY</button>`;
// Setup Event Handlers
if (gameInstalled) {
document.getElementById("playBtn").onclick = () => {
launchGame();
}
@ -69,9 +37,33 @@ export async function renderControls() {
// TODO
}
} else {
document.getElementById("launcherControls").innerHTML = `<button id="setupBtn">SETUP</button>`;
document.getElementById("setupBtn").onclick = () => {
isoSeries();
}
}
const sidebar = document.getElementById('sidebar');
// TODO - not cleaned up yet!
sidebar.onclick = e => {
switch (e.target.getAttribute('key')) {
case 'return':
document.getElementById('main').innerHTML = jak1_main;
document.getElementById('sidebar').innerHTML = jak1_sidebar;
break;
case 'settings':
document.getElementById('main').innerHTML = general_pane;
document.getElementById('sidebar').innerHTML = actions;
break;
case 'general':
document.getElementById('main').innerHTML = general_pane;
break;
case 'links':
document.getElementById('main').innerHTML = links_pane;
break;
case 'files':
document.getElementById('main').innerHTML = files_pane;
break;
}
}
}

12
package-lock.json generated
View file

@ -10,6 +10,7 @@
"dependencies": {
"@tauri-apps/api": "^1.0.0-rc.3",
"bootstrap-icons": "^1.8.1",
"dot": "^2.0.0-beta.1",
"tauri-plugin-store-api": "github:tauri-apps/tauri-plugin-store"
},
"devDependencies": {
@ -2288,6 +2289,12 @@
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==",
"dev": true
},
"node_modules/dot": {
"version": "2.0.0-beta.1",
"resolved": "https://registry.npmjs.org/dot/-/dot-2.0.0-beta.1.tgz",
"integrity": "sha512-kxM7fSnNQTXOmaeGuBSXM8O3fEsBb7XSDBllkGbRwa0lJSJTxxDE/4eSNGLKZUmlFw0f1vJ5qSV2BljrgQtgIA==",
"license": "MIT"
},
"node_modules/dot-prop": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
@ -8682,6 +8689,11 @@
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==",
"dev": true
},
"dot": {
"version": "2.0.0-beta.1",
"resolved": "https://registry.npmjs.org/dot/-/dot-2.0.0-beta.1.tgz",
"integrity": "sha512-kxM7fSnNQTXOmaeGuBSXM8O3fEsBb7XSDBllkGbRwa0lJSJTxxDE/4eSNGLKZUmlFw0f1vJ5qSV2BljrgQtgIA=="
},
"dot-prop": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",

View file

@ -17,6 +17,7 @@
"dependencies": {
"@tauri-apps/api": "^1.0.0-rc.3",
"bootstrap-icons": "^1.8.1",
"dot": "^2.0.0-beta.1",
"tauri-plugin-store-api": "github:tauri-apps/tauri-plugin-store"
}
}

90
src/config/config.js Normal file
View file

@ -0,0 +1,90 @@
import { createDir, readTextFile, writeFile } from '@tauri-apps/api/fs';
import { appDir, join } from '@tauri-apps/api/path';
import { Store } from 'tauri-plugin-store-api';
export class SupportedGame {
static Jak1 = new SupportedGame("Jak 1")
static Jak2 = new SupportedGame("Jak 2")
static Jak3 = new SupportedGame("Jak 3")
static JakX = new SupportedGame("Jak X")
constructor(name) {
this.name = name
}
static fromName(name) {
switch (name) {
case this.Jak1.name:
return this.Jak1;
case this.Jak2.name:
return this.Jak2;
case this.Jak3.name:
return this.Jak3;
case this.JakX.name:
return this.JakX;
default:
return null;
}
}
}
const key_lastActiveGame = "lastActiveGame";
const store = new Store('settings.json');
// TODO - a general -- does a file exist function -- would be nice
export async function initConfig() {
const path = await join(await appDir(), 'settings.json');
try {
await readTextFile(path);
} catch (error) {
console.log('[Launcher]: Settings file not found or could not be loaded!');
await createDir(await appDir(), { recursive: true });
const initSettings = {
[SupportedGame.Jak1.name]: { "installed": false },
[SupportedGame.Jak2.name]: { "installed": false },
[SupportedGame.Jak3.name]: { "installed": false },
[key_lastActiveGame]: SupportedGame.Jak1.name
};
await writeFile({ contents: JSON.stringify(initSettings, null, 2), path: path });
console.log('[Launcher]: Settings file initialized');
}
};
/**
*
* @param {SupportedGame} supportedGame
* @returns {Promise<boolean>}
*/
export async function getInstallStatus(supportedGame) {
await store.load();
const val = await store.get(supportedGame.name);
if (val == null || !'installed' in val) {
return false;
}
return val.installed;
}
/**
* @returns {Promise<SupportedGame>}
*/
export async function getLastActiveGame() {
await store.load();
const game = await store.get(key_lastActiveGame);
if (game == null) {
return SupportedGame.Jak1;
}
return SupportedGame.fromName(game);
}
/**
* @param {SupportedGame} supportedGame
* @param {boolean} installed
* @returns
*/
export async function setInstallStatus(supportedGame, installed) {
await store.load();
await store.set(supportedGame.name, { "installed": installed });
await store.save();
}

View file

@ -2,7 +2,7 @@ import { message } from "@tauri-apps/api/dialog";
import { platform } from "@tauri-apps/api/os";
import { appDir, join } from "@tauri-apps/api/path";
import { Command } from "@tauri-apps/api/shell";
import { setInstallStatus } from '../utils/store';
import { setInstallStatus } from '../config/config';
export async function buildGame() {
const userPlatform = await platform();
@ -24,7 +24,7 @@ export async function buildGame() {
console.log(`Compiler finished with code ${data.code} and signal ${data.signal}`);
if (data.code === 0) {
message('Game Ready to play!');
setInstallStatus();
setInstallStatus(SupportedGame.Jak1, true);
return 'Compiler finished';
} else {
message('Game Ready to play!');

View file

@ -1,41 +0,0 @@
import { Store } from 'tauri-plugin-store-api';
import { renderControls } from '../../main';
import { createDir, readTextFile, writeFile } from '@tauri-apps/api/fs';
import { appDir, join } from '@tauri-apps/api/path';
const store = new Store('settings.json');
// TODO - a general -- does a file exist function -- would be nice
(async function initStore() {
const path = await join(await appDir(), 'settings.json');
try {
await readTextFile(path);
} catch (error) {
await createDir(await appDir(), { recursive: true });
const initSettings = {
"Jak 1": { "installed": false },
"Jak 2": { "installed": false },
"Jak 3": { "installed": false }
};
const x = await writeFile({ contents: JSON.stringify(initSettings, null, 2), path: path });
console.log('Created settings.json file');
// once again probably not a good idea to use this render function here
renderControls();
}
})();
export async function getInstallStatus(game) {
await store.load();
const { installed } = await store.get(game);
return installed;
}
export async function setInstallStatus() {
await store.load();
await store.set("Jak 1", { "installed": true });
await store.save();
// calling this render function from here is probably a bad idea but im not sure how else to rerender the page
renderControls();
return;
}

17
src/views/main.dot.js Normal file
View file

@ -0,0 +1,17 @@
import * as doT from 'dot';
export let mainTemplate = doT.template(`
<div class="flex-center">
<div class="logo">
<img id="logo" width="65%" src="src/assets/images/logo.png">
</div>
<div class="buttons" id="launcherControls">
{{? it.gameInstalled }}
<button id="configBtn">CONFIG</button>
<button id="playBtn">PLAY</button>
{{?? true }}
<button id="setupBtn">SETUP</button>
{{?}}
</div>
</div>
`);

34
src/views/sidebar.dot.js Normal file
View file

@ -0,0 +1,34 @@
import * as doT from 'dot';
export let sidebarTemplate = doT.template(`
<div class="games">
<div class="jak-1 nav-item{{? it.jak1Active }} active{{?? true}} disabled{{?}}">
<a data-tooltip="Jak & Daxter: The Precursor Legacy">
<img src="src/assets/images/jak-tpl.png">
</a>
</div>
<div class="jak-2 nav-item{{? it.jak2Active }} active{{?? true}} disabled{{?}}">
<a data-tooltip="Jak 2 - Not Available!">
<img src="src/assets/images/jak-2.png">
</a>
</div>
<div class="jak-3 nav-item{{? it.jak3Active }} active{{?? true}} disabled{{?}}">
<a data-tooltip="Jak 3 - Not Available!">
<img src="src/assets/images/jak-3.png">
</a>
</div>
</div>
<div class="spacer"></div>
<div class="controls">
<div class="console nav-item">
<a data-tooltip="Toggle Debug Console">
<i class="bi bi-terminal-fill"></i>
</a>
</div>
<div class="settings nav-item">
<a data-tooltip="Settings">
<i class="bi bi-sliders" key="settings"></i>
</a>
</div>
</div>
`);

View file

@ -46,7 +46,7 @@ body {
opacity: 0.35;
}
#background {
#backgroundVideo {
z-index: -1;
height: 100vh;
}
@ -55,7 +55,7 @@ body {
display: flex;
}
.sidebar {
#sidebar {
display: flex;
flex-direction: column;
height: 100vh;
@ -66,7 +66,7 @@ body {
max-width: 10vw;
}
.sidebar:hover {
#sidebar:hover {
opacity: 100%;
}
@ -145,7 +145,7 @@ body {
font-size: 35px;
}
.main {
#main {
display: flex;
justify-content: center;
flex-direction: column;