diff options
author | 0neGal <mail@0negal.com> | 2022-05-02 21:49:20 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-02 21:49:20 +0200 |
commit | c40e331bdc4b2375d3802a515c9b7a032118dea7 (patch) | |
tree | 77c8d84c0fc9d0fbb742cfeeb80efa4762784a9d /src/app | |
parent | 9f2f77558238c28ceb8ff4fca2096602671779e5 (diff) | |
parent | 847a2178e7823749e3096daf24dfcd3df8b236cb (diff) | |
download | Viper-c40e331bdc4b2375d3802a515c9b7a032118dea7.tar.gz Viper-c40e331bdc4b2375d3802a515c9b7a032118dea7.zip |
Merge branch 'main' into enabledmods
Diffstat (limited to 'src/app')
-rw-r--r-- | src/app/browser.js | 95 | ||||
-rw-r--r-- | src/app/icons/apply.png | bin | 0 -> 2555 bytes | |||
-rw-r--r-- | src/app/icons/check.png | bin | 0 -> 373 bytes | |||
-rw-r--r-- | src/app/icons/download.png | bin | 0 -> 2200 bytes | |||
-rw-r--r-- | src/app/icons/filter.png | bin | 0 -> 1074 bytes | |||
-rw-r--r-- | src/app/icons/settings.png | bin | 0 -> 2496 bytes | |||
-rw-r--r-- | src/app/index.html | 115 | ||||
-rw-r--r-- | src/app/launcher.js | 6 | ||||
-rw-r--r-- | src/app/main.css | 288 | ||||
-rw-r--r-- | src/app/main.js | 78 | ||||
-rw-r--r-- | src/app/settings.js | 137 | ||||
-rw-r--r-- | src/app/toast.js | 2 |
12 files changed, 659 insertions, 62 deletions
diff --git a/src/app/browser.js b/src/app/browser.js index ded12fa..e22ab3c 100644 --- a/src/app/browser.js +++ b/src/app/browser.js @@ -4,6 +4,58 @@ var packages = []; var Browser = { maxentries: 50, + filters: { + get: () => { + let filtered = []; + let unfiltered = []; + let checks = browser.querySelectorAll("#filters .check"); + + for (let i = 0; i < checks.length; i++) { + if (! checks[i].classList.contains("checked")) { + filtered.push(checks[i].getAttribute("value")); + } else { + unfiltered.push(checks[i].getAttribute("value")); + } + } + + return { + filtered, + unfiltered + }; + }, + isfiltered: (categories) => { + let filtered = Browser.filters.get().filtered; + let unfiltered = Browser.filters.get().unfiltered; + let state = false; + if (categories.length == 0) {return true} + for (let i = 0; i < categories.length; i++) { + if (filtered.includes(categories[i])) { + state = true; + continue + } else if (unfiltered.includes(categories[i])) { + state = false; + continue + } + + state = true; + } + + return state; + }, + toggle: (state) => { + if (state == false) { + filters.classList.remove("shown"); + return + } + + filters.classList.toggle("shown"); + let filterRect = filter.getBoundingClientRect(); + let spacing = parseInt(getComputedStyle(filters).getPropertyValue("--spacing")); + + filters.style.top = filterRect.bottom - spacing; + filters.style.right = filterRect.right - filterRect.left + filterRect.width - (spacing / 2); + }, + }, toggle: (state) => { if (state) { browser.scrollTo(0, 0); @@ -16,6 +68,7 @@ var Browser = { return } else if (! state) { if (state != undefined) { + Browser.filters.toggle(false); overlay.classList.remove("shown") browser.classList.remove("shown") return @@ -38,11 +91,14 @@ var Browser = { } for (let i in packages) { - if (i == Browser.maxentries) {Browser.endoflist();break} new BrowserElFromObj(packages[i]); } }, loading: (string) => { + if (Browser.filters.get().unfiltered.length == 0) { + string = lang("gui.browser.noresults"); + } + if (string) { browserEntries.innerHTML = `<div class="loading">${string}</div>`; } @@ -52,6 +108,7 @@ var Browser = { } }, endoflist: () => { + if (browserEntries.querySelector(".message")) {return} browserEntries.innerHTML += `<div class="message">${lang('gui.browser.endoflist')}</div>` }, search: (string) => { @@ -59,26 +116,25 @@ var Browser = { let res = fuse.search(string); if (res.length < 1) { - Browser.loading("No results...") + Browser.loading(lang("gui.browser.noresults")) return } for (let i = 0; i < res.length; i++) { - if (i == Browser.maxentries) {Browser.endoflist();break} new BrowserElFromObj(res[i].item); } }, setbutton: (mod, string) => { mod = normalize(mod); - if (document.getElementById(mod)) { - let elems = document.querySelectorAll(`#${mod}`); + if (browserEntries.querySelector(`#mod-${mod}`)) { + let elems = browserEntries.querySelectorAll(`.el#mod-${mod}`); for (let i = 0; i < elems.length; i++) { elems[i].querySelector(".text button").innerHTML = string; } } else { let make = (str) => { - if (document.getElementById(str)) { + if (browserEntries.querySelector(`#mod-${str}`)) { return Browser.setbutton(str, string); } else { return false; @@ -104,10 +160,6 @@ var Browser = { } } -document.body.addEventListener("keyup", (e) => { - if (e.key == "Escape") {Browser.toggle(false)} -}) - function BrowserElFromObj(obj) { let pkg = {...obj, ...obj.versions[0]}; @@ -118,11 +170,17 @@ function BrowserElFromObj(obj) { url: pkg.package_url, download: pkg.download_url, version: pkg.version_number, + categories: pkg.categories, description: pkg.description }) } function BrowserEl(properties) { + if (Browser.filters.isfiltered(properties.categories)) {return} + + let entries = browser.querySelectorAll(".el").length; + if (entries == Browser.maxentries) {Browser.endoflist();return} + properties = { title: "No name", version: "1.0.0", @@ -174,15 +232,16 @@ function BrowserEl(properties) { } browserEntries.innerHTML += ` - <div class="el" id="${normalize(properties.title)}"> + <div class="el" id="mod-${normalize(properties.title)}"> <div class="image"> <img src="${properties.image}"> + <img class="blur" src="${properties.image}"> </div> <div class="text"> <div class="title">${properties.title}</div> <div class="description">${properties.description}</div> - <button onclick="installFromURL('${properties.download}')">${installstr}</button> - <button onclick="require('electron').shell.openExternal('${properties.url}')">${lang('gui.browser.info')}</button> + <button class="install" onclick="installFromURL('${properties.download}')">${installstr}</button> + <button class="info" onclick="require('electron').shell.openExternal('${properties.url}')">${lang('gui.browser.info')}</button> <button class="visual">${properties.version}</button> <button class="visual">${lang("gui.browser.madeby")} ${properties.author}</button> </div> @@ -247,6 +306,7 @@ function normalize(items) { let searchtimeout; let searchstr = ""; search.addEventListener("keyup", () => { + Browser.filters.toggle(false); clearTimeout(searchtimeout); if (searchstr != search.value) { @@ -262,3 +322,12 @@ search.addEventListener("keyup", () => { }, 500) } }) + +browser.addEventListener("scroll", () => { + Browser.filters.toggle(false); +}) + +let checks = document.querySelectorAll(".check"); +for (let i = 0; i < checks.length; i++) { + checks[i].setAttribute("onclick", "this.classList.toggle('checked');Browser.loadfront();search.value = ''") +} diff --git a/src/app/icons/apply.png b/src/app/icons/apply.png Binary files differnew file mode 100644 index 0000000..915f809 --- /dev/null +++ b/src/app/icons/apply.png diff --git a/src/app/icons/check.png b/src/app/icons/check.png Binary files differnew file mode 100644 index 0000000..6c7f43f --- /dev/null +++ b/src/app/icons/check.png diff --git a/src/app/icons/download.png b/src/app/icons/download.png Binary files differnew file mode 100644 index 0000000..189c50d --- /dev/null +++ b/src/app/icons/download.png diff --git a/src/app/icons/filter.png b/src/app/icons/filter.png Binary files differnew file mode 100644 index 0000000..ade45ef --- /dev/null +++ b/src/app/icons/filter.png diff --git a/src/app/icons/settings.png b/src/app/icons/settings.png Binary files differnew file mode 100644 index 0000000..3f7715a --- /dev/null +++ b/src/app/icons/settings.png diff --git a/src/app/index.html b/src/app/index.html index 8222416..02a150f 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -10,15 +10,121 @@ <div id="toasts"></div> <div id="winbtns"> + <div id="settings" onclick="Settings.toggle(true)"></div> <div id="minimize" onclick="ipcRenderer.send('minimize')"></div> <div id="close" onclick="ipcRenderer.send('exit')"></div> </div> + <div id="dragUI"> + <div id="dragitems"> + <div id="icon"></div> + <div id="text">%%gui.mods.dragdrop%%</div> + </div> + </div> - <div id="overlay" onclick="Browser.toggle(false)"></div> - <div id="browser"> - <div id="misc"> + <div id="overlay" onclick="Browser.toggle(false);Settings.toggle(false)"></div> + <div class="popup" id="options"> + <div class="misc"> + <div style="width:100%"></div> + <button id="apply" onclick="Settings.toggle(false);Settings.apply()"> + <img src="icons/apply.png"> + %%gui.settings.save%% + </button> + <button id="close" onclick="Settings.toggle(false);Settings.load()"> + <img src="icons/close.png"> + %%gui.settings.discard%% + </button> + </div> + <div class="options"> + <h2>%%gui.settings.title.ns%%</h2> + <div class="option" name="nsargs"> + <div class="text"> + %%gui.settings.nsargs.title%% + <div class="desc"> + %%gui.settings.nsargs.desc%% + </div> + </div> + <div class="actions"> + <input> + </div> + </div> + <h2>%%gui.settings.title.language%%</h2> + <div class="option" name="autolang"> + <div class="text"> + %%gui.settings.autolang.title%% + <div class="desc"> + %%gui.settings.autolang.desc%% + </div> + </div> + <div class="actions"> + <button class="switch off"></button> + </div> + </div> + <div class="option" name="forcedlang"> + <div class="text"> + %%gui.settings.forcedlang.title%% + <div class="desc"> + %%gui.settings.forcedlang.desc%% + </div> + </div> + <div class="actions"> + <select onchange="Settings.switch(document.querySelector(`.option[name='autolang'] button`), false)"> + <option></option> + </select> + </div> + </div> + <h2>%%gui.settings.title.updates%%</h2> + <div class="option" name="autoupdate"> + <div class="text"> + %%gui.settings.autoupdate.title%% + <div class="desc"> + %%gui.settings.autoupdate.desc%% + </div> + </div> + <div class="actions"> + <button class="switch on"></button> + </div> + </div> + <div class="option" name="nsupdate"> + <div class="text"> + %%gui.settings.nsupdate.title%% + <div class="desc"> + %%gui.settings.nsupdate.desc%% + </div> + </div> + <div class="actions"> + <button class="switch on"></button> + </div> + </div> + <div class="option" name="excludes" type="array"> + <div class="text"> + %%gui.settings.excludes.title%% + <div class="desc"> + %%gui.settings.excludes.desc%% + </div> + </div> + <div class="actions"> + <input type="text"> + </div> + </div> + </div> + </div> + + <div class="popup" id="browser"> + <div class="overlay" id="filters"> + <div class="checks"> + <div class="check checked" value="Mods">%%gui.browser.filter.mods%%</div> + <div class="check checked" value="Skins">%%gui.browser.filter.skins%%</div> + <div class="check checked" value="Client-side">%%gui.browser.filter.client%%</div> + <div class="check" value="Server-side">%%gui.browser.filter.server%%</div> + </div> + </div> + + <div class="misc"> <input id="search" placeholder="%%gui.browser.search%%"> + <button id="filter" onclick="Browser.filters.toggle()"> + <img src="icons/filter.png"> + </button> <button id="close" onclick="Browser.toggle(false)"> <img src="icons/close.png"> </button> @@ -94,7 +200,7 @@ <button id="togglemod" onclick="selected().toggle()">%%gui.mods.toggle%%</button> <button id="toggleall" onclick="selected(true).toggle(true)">%%gui.mods.toggleall%%</button> <button id="installmod" onclick="installmod()">%%gui.mods.install%%</button> - <button id="installmod" onclick="Browser.toggle(true)">%%gui.mods.find%%</button> + <button id="findmod" onclick="Browser.toggle(true)">%%gui.mods.find%%</button> </div> </div> </div> @@ -120,6 +226,7 @@ <script src="main.js"></script> <script src="toast.js"></script> <script src="browser.js"></script> + <script src="settings.js"></script> <script src="launcher.js"></script> </body> </html> diff --git a/src/app/launcher.js b/src/app/launcher.js index 60c0d18..7b49dc4 100644 --- a/src/app/launcher.js +++ b/src/app/launcher.js @@ -17,7 +17,7 @@ function page(page) { pages[page].classList.remove("hidden"); btns[page].classList.remove("inactive"); bgHolder.setAttribute("bg", page); -}; page(0) +}; page(1) // Updates the Viper release notes @@ -25,6 +25,8 @@ ipcRenderer.on("vp-notes", (event, response) => { let content = ""; for (const release of response) { + if (release.prerelease) {continue} + content += "# " + release.name + "\n\n" + release.body.replaceAll("\r\n", "\n") + "\n\n\n"; } @@ -42,6 +44,8 @@ ipcRenderer.on("ns-notes", (event, response) => { let content = ""; for (let release of response) { + if (release.prerelease) {continue} + content += "# " + release.name + "\n\n" + release.body.replaceAll("\r\n", "\nhtmlbreak") + "\n\n\n"; } diff --git a/src/app/main.css b/src/app/main.css index a532490..99d806c 100644 --- a/src/app/main.css +++ b/src/app/main.css @@ -1,17 +1,23 @@ :root { - --red: #C7777F; - --blue: #81A1C1; - --orange: #D59783; + --red: 199, 119, 127; + --red2: 181 97 105; + + --blue: 129, 161, 193; + --blue2: 139, 143, 185; + + --orange: 213, 151, 131; + --orange2: 197 129 107; + --padding: 25px; --bg: rgba(0, 0, 0, 0.5); --selbg: rgba(80, 80, 80, 0.5); - --redbg: linear-gradient(45deg, var(--red), #FA4343); - --bluebg: linear-gradient(45deg, var(--blue), #7380ED); + --redbg: linear-gradient(45deg, rgb(var(--red)), #FA4343); + --bluebg: linear-gradient(45deg, rgb(var(--blue)), #7380ED); } -#browser, #modsdiv { +.popup, #modsdiv { outline: 1px solid #444444; border: 3px solid var(--bg); } @@ -27,22 +33,26 @@ ::-webkit-scrollbar-thumb { border-radius: 10px; - background: var(--red); + background: rgb(var(--red)); } ::selection { color: black; - background: var(--red); + background: rgb(var(--red)); } body { margin: 0; overflow: hidden; - user-select: none; } body, button, input {font-family: "Roboto", sans-serif} +body, button, img, a { + -webkit-user-drag: none; + user-select: none; +} + button {outline: none} b, strong {font-weight: 700} body, input, button {font-weight: 500} @@ -62,7 +72,7 @@ button { cursor: pointer; } -#browser { +.popup { --spacing: var(--padding); z-index: 2; @@ -81,7 +91,7 @@ button { transition: opacity 0.15s ease-in-out, transform 0.15s ease-in-out; } -#browser.shown { +.popup.shown { opacity: 1.0; pointer-events: all; transform: scale(1.0); @@ -110,7 +120,7 @@ button { 100% {opacity: 1.0} } -#browser .el, #browser #misc, #browser .loading { +.popup .el, .popup .misc, .popup .loading { --spacing: calc(var(--padding) / 2); --height: calc(var(--padding) * 3); --mischeight: calc(var(--padding) * 1.5); @@ -125,7 +135,7 @@ button { transition: 0.15s ease-in-out; } -#browser .el, #browser #search, #browser #close { +.popup .el, .popup #search, .option .actions select, .option .actions input, .popup #close, .popup .misc button { color: white; display: flex; align-items: center; @@ -137,41 +147,52 @@ button { width: calc(100% - var(--spacing) * 4); } -#browser #misc, #browser #search { +.popup .misc, .popup #search, .option .actions input { --height: var(--mischeight); } -#browser #misc { +.popup .misc { display: flex; } -#browser #search { +.popup #search, .option .actions input, .option .actions select { border: none; outline: none; transition: filter 0.15s ease-in-out; width: calc(100% - var(--spacing) * 2); } -#browser #search:focus { +.popup #search:focus, .option .actions input:focus, .option .actions button:active { filter: brightness(1.5); } -#browser #close { +.popup .misc button { --height: calc(var(--padding) * 1.5); padding: 0px; margin-left: 0px; - width: var(--height); + padding: 0px !important; + width: var(--height) !important; } -#browser #close img { +.popup .misc button img { opacity: 0.6; width: var(--height); - height: var(--height); - transform: scale(0.6); + transform: scale(0.5); + height: var(--height) !important; +} + +#options.popup .misc button { + margin-left: 0px; + width: auto !important; + padding-right: calc(var(--padding) / 2) !important; } -#browser .loading { +.popup .misc button:last-child { + margin-left: 0px !important; +} + +.popup .loading { width: 100%; color: white; display: flex; @@ -181,38 +202,166 @@ button { height: calc(100% - var(--mischeight) - var(--height)); } -#browser .message { +.popup .message { color: white; text-align: center; margin: var(--padding); width: calc(100% - var(--padding)); } -#browser .el .image, #browser .el .image img { +.popup .el .image, .popup .el .image img { width: var(--height); height: var(--height); margin-right: var(--spacing); border-radius: var(--spacing); } -#browser .el .text { +.popup .el .image img.blur { + z-index: -1; + position: relative; + filter: blur(10px); + top: calc(var(--height) * -1 + 5px); +} + +.popup .el .text { overflow: hidden; } -#browser .el .title, #browser .el .description { +.popup .el .title, .popup .el .description { height: 1.2em; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } -#browser .el .title {font-size: 1.2em} -#browser .el .description {font-size: 0.8em} -#browser .el button { - background: var(--blue); +.popup .el .title { + font-size: 1.2em; + font-weight: 700; +} + +.popup .el .description {font-size: 0.8em} +.popup .el button { + background: rgb(var(--blue)); margin-top: var(--spacing); } +.popup .el button.info { + background: rgb(var(--blue2)); +} + +.popup .options { + color: white; + margin: calc(var(--padding) / 2); +} + +.popup .options .option { + width: 100%; + display: flex; + margin-bottom: var(--padding); + justify-content: space-between; +} + +.popup .overlay { + z-index: 1; + color: white; + opacity: 0.0; + position: fixed; + pointer-events: none; + transform: scale(0.9); + background: var(--selbg); + backdrop-filter: blur(15px); + transition: 0.15s ease-in-out; + padding: calc(var(--spacing) / 2); + border-radius: calc(var(--spacing) / 2); +} + +.popup .overlay.shown { + opacity: 1.0; + pointer-events: all; + transform: scale(1.0); +} + +.checks { +} + +.check { + display:flex; + cursor: pointer; +} + +.check::before { + width: 1em; + height: 1em; + content: " "; + background-size: 75%; + filter: brightness(1.3); + background-position: center; + background-repeat: no-repeat; + transition: 0.15s ease-in-out; + background-color: var(--selbg); + margin-right: calc(var(--spacing) / 3); + border-radius: calc(var(--spacing) / 4); +} + +.check.checked::before { + background-color: rgb(var(--red)); + background-image: url(icons/check.png); +} + +.option .text {font-weight: 600} +.option .text .desc { + opacity: 0.8; + font-weight: 500; + font-size: 0.9em; + max-width: 400px; + margin-top: calc(var(--padding) / 3); +} + +.option .actions input, .option .actions select { + width: 100%; + margin: 0px; + --spacing: calc(var(--padding) / 3); +} + +.option[type=array] .actions input { + word-spacing: 15px; + margin-right: 15vw; +} + +.option .actions button { + background: var(--selbg); +} + +.switch { + width: 50px; + height: 25px; + border-radius: 50px; +} + +.switch.on { + background: rgba(var(--red), 0.2) !important; +} + +.switch::after { + left: -5px; + width: 15px; + height: 15px; + content: " "; + display: block; + background: red; + position: relative; + border-radius: 50px; + background: var(--bg); + transition: 0.2s ease-in-out; +} + +.switch.on::after { + left: 15px; + width: 20px; + opacity: 0.5; + background: rgb(var(--red)); +} + #winbtns { z-index: 2; display: flex; @@ -233,9 +382,10 @@ button { #winbtns #close {background-image: url("icons/close.png")} #winbtns #minimize {background-image: url("icons/minimize.png")} +#winbtns #settings {background-image: url("icons/settings.png")} #winbtns div:hover {opacity: 1.0} -#winbtns div:active {transform: scale(0.98)} +#winbtns div:active {transform: scale(0.95)} button:hover {filter: brightness(110%)} button:active {filter: brightness(90%)} @@ -252,7 +402,7 @@ img {pointer-events: none} background-size: cover; background-position: center; background-repeat: no-repeat; - transition: background-image 0.5s ease-in-out; + transition: background-image 0.1s ease-in-out; filter: brightness(0.4) blur(2px) grayscale(0.6); } @@ -384,7 +534,7 @@ img {pointer-events: none} text-align: center; position: relative; border-radius: 50px; - background: var(--red); + background: rgb(var(--red)); left: calc(50% - 15px); transition: 0.2s ease-in-out; } @@ -430,7 +580,7 @@ img {pointer-events: none} margin-bottom: 10px; border-radius: 10px; background: var(--redbg); - transition: 0.3s ease-in-out; + transition: 0.2s ease-in-out; filter: drop-shadow(0px 8px 5px rgba(0, 0, 0, 0.1)); } @@ -449,7 +599,7 @@ img {pointer-events: none} } a { - color: var(--red); + color: rgb(var(--red)); text-decoration: none; transition: filter 0.2s ease-in; } @@ -496,12 +646,17 @@ a:hover { } .simplebar-scrollbar:before { - background: var(--red) !important; + background: rgb(var(--red)) !important; } -#installmod {background: var(--blue)} -#togglemod, #toggleall {background: var(--orange)} -#northstar, #removeall, #removemod {background: var(--red)} +#installmod {background: rgb(var(--blue))} +#findmod {background: rgb(var(--blue2))} + +#togglemod {background: rgb(var(--orange))} +#toggleall {background: rgb(var(--orange2))} + +#removemod {background: rgb(var(--red))} +#removeall {background: rgb(var(--red2))} button:disabled { opacity: 0.5; pointer-events: none; @@ -509,6 +664,7 @@ button:disabled { button.visual { opacity: 1.0; + padding-right: 0px; pointer-events: none; background: transparent !important; } @@ -612,6 +768,58 @@ code { font-weight: 600; } +#dragUI { + top: 0; + left: 0; + right: 0; + bottom: 0; + color: white; + opacity: 0.0; + position: fixed; + z-index: 1000000; + pointer-events: none; + background: var(--bg); + backdrop-filter: blur(15px); + transition: 0.1s ease-in-out; +} + +#dragUI.shown { + opacity: 1.0; + pointer-events: all; +} + +#dragUI #dragitems { + --size: 25vw; + top: 50%; + left: 50%; + opacity: 0.6; + position: absolute; + text-align: center; + width: var(--size); + height: var(--size); + margin-top: calc(var(--size) / 2 * -1); + margin-left: calc(var(--size) / 2 * -1); +} + +#dragUI #dragitems #icon { + width: 100%; + height: 100%; + filter: invert(1); + transform: scale(0.45); + background-size: cover; + background-image: url("icons/download.png"); + transition: 0.1s ease-in-out; +} + +#dragUI.shown #dragitems #icon { + transform: scale(0.5); +} + +#dragUI #dragitems #text { + top: -5vw; + position: relative; +} + /* drag control */ #bgHolder, diff --git a/src/app/main.js b/src/app/main.js index 169f86f..95b6f4c 100644 --- a/src/app/main.js +++ b/src/app/main.js @@ -8,7 +8,11 @@ let shouldInstallNorthstar = false; // Base settings var settings = { + nsargs: "", gamepath: "", + nsupdate: true, + autolang: true, + forcedlang: "en", autoupdate: true, zip: "/northstar.zip", lang: navigator.language, @@ -23,7 +27,24 @@ ipcRenderer.send("setlang", settings.lang); // Loads the settings if (fs.existsSync("viper.json")) { - settings = {...settings, ...JSON.parse(fs.readFileSync("viper.json", "utf8"))}; + let conf = fs.readFileSync("viper.json", "utf8"); + let json = {}; + + // Validates viper.json + try { + json = JSON.parse(conf); + }catch (e) { + let reset = confirm(lang("general.invalidconfig", navigator.language) + e); + if (! reset) { + ipcRenderer.send("exit") + } else { + fs.writeFileSync("viper.json", "{}") + ipcRenderer.send("relaunch"); + } + + } + + settings = {...settings, ...json}; settings.zip = path.join(settings.gamepath + "/northstar.zip"); if (settings.gamepath.length === 0) { @@ -31,6 +52,11 @@ if (fs.existsSync("viper.json")) { } else { setpath(true); } + + let args = path.join(settings.gamepath, "ns_startup_args.txt"); + if (fs.existsSync(args)) { + settings.nsargs = fs.readFileSync(args, "utf8"); + } } else { setpath(); } @@ -74,14 +100,22 @@ function setButtons(state) { } } + disablearray(document.querySelectorAll(".playBtnContainer .playBtn")) disablearray(document.querySelectorAll("#nsMods .buttons.modbtns button")) disablearray(document.querySelectorAll("#browser #browserEntries .text button")) } +ipcRenderer.on("setbuttons", (event, state) => {setButtons(state)}) +ipcRenderer.on("gamepathlost", (event, state) => { + page(0); + setButtons(false); + alert(lang("gui.gamepath.lost")); +}) + // Frontend part of updating Northstar ipcRenderer.on("ns-update-event", (event, key) => { document.getElementById("update").innerText = `(${lang(key)})`; - console.log(key); + console.log(lang(key)); switch(key) { case "cli.update.uptodate.short": setButtons(true); @@ -156,12 +190,18 @@ function selected(all) { } } -// Tells the main process to install a mod +// Tells the main process to install a mod through the file selector function installmod() { setButtons(false); ipcRenderer.send("installmod") } +// Tells the main process to directly install a mod from this path +function installFromPath(path) { + setButtons(false); + ipcRenderer.send("installfrompath", path) +} + // Tells the main process to install a mod from a URL function installFromURL(url) { setButtons(false); @@ -242,6 +282,38 @@ ipcRenderer.on("wrongpath", () => { setlang(); +let dragtimer; +document.addEventListener("dragover", (e) => { + e.preventDefault(); + e.stopPropagation(); + dragUI.classList.add("shown"); + + clearTimeout(dragtimer); + dragtimer = setTimeout(() => { + dragUI.classList.remove("shown"); + }, 5000) +}); + +document.addEventListener("mouseover", (e) => { + clearTimeout(dragtimer); + dragUI.classList.remove("shown"); +}); + +document.addEventListener("drop", (e) => { + event.preventDefault(); + event.stopPropagation(); + + dragUI.classList.remove("shown"); + installFromPath(event.dataTransfer.files[0].path) +}); + +document.body.addEventListener("keyup", (e) => { + if (e.key == "Escape") { + Browser.toggle(false); + Settings.toggle(false); + } +}) + document.body.addEventListener("click", event => { if (event.target.tagName.toLowerCase() === "a" && event.target.protocol != "file:") { event.preventDefault(); diff --git a/src/app/settings.js b/src/app/settings.js new file mode 100644 index 0000000..23b38c9 --- /dev/null +++ b/src/app/settings.js @@ -0,0 +1,137 @@ +var Settings = { + toggle: (state) => { + if (state) { + Settings.load(); + options.scrollTo(0, 0); + overlay.classList.add("shown") + options.classList.add("shown") + + return + } else if (! state) { + if (state != undefined) { + overlay.classList.remove("shown") + options.classList.remove("shown") + return + } + } + + Settings.load(); + options.scrollTo(0, 0); + overlay.classList.toggle("shown") + options.classList.toggle("shown") + }, + apply: () => { + settings = {...settings, ...Settings.get()}; + ipcRenderer.send("savesettings", Settings.get()); + }, + reloadSwitches: () => { + let switches = document.querySelectorAll(".switch"); + + for (let i = 0; i < switches.length; i++) { + switches[i].setAttribute("onclick", `Settings.switch(${i})`); + } + }, + switch: (element, state) => { + let switches = document.querySelectorAll(".switch"); + if (switches[element]) { + element = switches[element]; + } + + let on = () => { + element.classList.add("on"); + element.classList.remove("off"); + } + + let off = () => { + element.classList.add("off"); + element.classList.remove("on"); + } + + if (state != undefined) { + if (state) {on()} else {off()} + } else { + if (element.classList.contains("on")) {off()} else {on()} + } + + Settings.reloadSwitches(); + }, + get: () => { + let opts = {}; + let options = document.querySelectorAll(".option"); + + for (let i = 0; i < options.length; i++) { + let optName = options[i].getAttribute("name"); + if (options[i].querySelector(".actions input")) { + let input = options[i].querySelector(".actions input").value; + if (options[i].getAttribute("type")) { + opts[optName] = input.split(" "); + } else { + opts[optName] = input; + } + } else if (options[i].querySelector(".actions select")) { + opts[optName] = options[i].querySelector(".actions select").value; + } else if (options[i].querySelector(".actions .switch")) { + if (options[i].querySelector(".actions .switch.on")) { + opts[optName] = true; + } else { + opts[optName] = false; + } + } + } + + return opts; + }, + load: () => { + let options = document.querySelectorAll(".option"); + + for (let i = 0; i < options.length; i++) { + let optName = options[i].getAttribute("name"); + if (optName == "forcedlang") { + let div = options[i].querySelector("select"); + + div.innerHTML = ""; + let langs = fs.readdirSync(__dirname + "/../lang"); + for (let i in langs) { + title = JSON.parse(fs.readFileSync(__dirname + `/../lang/${langs[i]}`, "utf8"))["lang.title"]; + if (title) { + div.innerHTML += `<option value="${langs[i].replace(/\..*$/, '')}">${title}</option>` + } + + } + + div.value = settings.forcedlang; + continue; + } + + if (settings[optName] != undefined) { + switch(typeof settings[optName]) { + case "string": + options[i].querySelector(".actions input").value = settings[optName]; + break + case "object": + options[i].querySelector(".actions input").value = settings[optName].join(" "); + break + case "boolean": + let switchDiv = options[i].querySelector(".actions .switch"); + if (settings[optName]) { + switchDiv.classList.add("on"); + switchDiv.classList.remove("off"); + } else { + switchDiv.classList.add("off"); + switchDiv.classList.remove("on"); + } + break + + } + } + } + + ipcRenderer.send("can-autoupdate"); + ipcRenderer.on("cant-autoupdate", () => { + document.querySelector(".option[name=autoupdate]").style.display = "none"; + }) + } +} + +Settings.reloadSwitches(); +Settings.load(); diff --git a/src/app/toast.js b/src/app/toast.js index 2a8555e..9cb8996 100644 --- a/src/app/toast.js +++ b/src/app/toast.js @@ -11,7 +11,7 @@ function Toast(properties) { switch(toast.scheme) { case "error": toast.fg = "#FFFFFF"; - toast.bg = "var(--red)"; + toast.bg = "rgb(var(--red))"; break case "success": toast.fg = "#FFFFFF"; |