diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/app/fonts/Roboto-Black.ttf | bin | 0 -> 168060 bytes | |||
-rw-r--r-- | src/app/fonts/Roboto-BlackItalic.ttf | bin | 0 -> 174108 bytes | |||
-rw-r--r-- | src/app/fonts/Roboto-Bold.ttf | bin | 0 -> 167336 bytes | |||
-rw-r--r-- | src/app/fonts/Roboto-BoldItalic.ttf | bin | 0 -> 171508 bytes | |||
-rw-r--r-- | src/app/fonts/Roboto-Italic.ttf | bin | 0 -> 170504 bytes | |||
-rw-r--r-- | src/app/fonts/Roboto-Light.ttf | bin | 0 -> 167000 bytes | |||
-rw-r--r-- | src/app/fonts/Roboto-LightItalic.ttf | bin | 0 -> 173172 bytes | |||
-rw-r--r-- | src/app/fonts/Roboto-Medium.ttf | bin | 0 -> 168644 bytes | |||
-rw-r--r-- | src/app/fonts/Roboto-MediumItalic.ttf | bin | 0 -> 173416 bytes | |||
-rw-r--r-- | src/app/fonts/Roboto-Regular.ttf | bin | 0 -> 168260 bytes | |||
-rw-r--r-- | src/app/fonts/Roboto-Thin.ttf | bin | 0 -> 168488 bytes | |||
-rw-r--r-- | src/app/fonts/Roboto-ThinItalic.ttf | bin | 0 -> 172860 bytes | |||
-rw-r--r-- | src/app/fonts/import.css | 83 | ||||
-rw-r--r-- | src/app/icons/close.png | bin | 0 -> 2661 bytes | |||
-rw-r--r-- | src/app/icons/northstar.png | bin | 0 -> 135670 bytes | |||
-rw-r--r-- | src/app/icons/titanfall2.png | bin | 0 -> 26922 bytes | |||
-rw-r--r-- | src/app/icons/viper.png | bin | 0 -> 137107 bytes | |||
-rw-r--r-- | src/app/index.html | 111 | ||||
-rw-r--r-- | src/app/launcher.js | 105 | ||||
-rw-r--r-- | src/app/main.css | 427 | ||||
-rw-r--r-- | src/app/main.js | 71 | ||||
-rw-r--r-- | src/app/roboto.ttf | bin | 87008 -> 0 bytes | |||
-rw-r--r-- | src/assets/bg/northstar.jpg | bin | 0 -> 103397 bytes | |||
-rw-r--r-- | src/assets/bg/tf2.jpg | bin | 0 -> 132623 bytes | |||
-rw-r--r-- | src/assets/bg/viper.jpg | bin | 0 -> 133337 bytes | |||
-rw-r--r-- | src/assets/ns.png | bin | 0 -> 20619 bytes | |||
-rw-r--r-- | src/assets/vanilla.png | bin | 0 -> 9139 bytes | |||
-rw-r--r-- | src/index.js | 32 | ||||
-rw-r--r-- | src/lang/en.json | 26 | ||||
-rw-r--r-- | src/lang/fr.json | 28 | ||||
-rw-r--r-- | src/requests.js | 78 | ||||
-rw-r--r-- | src/utils.js | 43 |
32 files changed, 836 insertions, 168 deletions
diff --git a/src/app/fonts/Roboto-Black.ttf b/src/app/fonts/Roboto-Black.ttf Binary files differnew file mode 100644 index 0000000..43a00e0 --- /dev/null +++ b/src/app/fonts/Roboto-Black.ttf diff --git a/src/app/fonts/Roboto-BlackItalic.ttf b/src/app/fonts/Roboto-BlackItalic.ttf Binary files differnew file mode 100644 index 0000000..5082cdc --- /dev/null +++ b/src/app/fonts/Roboto-BlackItalic.ttf diff --git a/src/app/fonts/Roboto-Bold.ttf b/src/app/fonts/Roboto-Bold.ttf Binary files differnew file mode 100644 index 0000000..3742457 --- /dev/null +++ b/src/app/fonts/Roboto-Bold.ttf diff --git a/src/app/fonts/Roboto-BoldItalic.ttf b/src/app/fonts/Roboto-BoldItalic.ttf Binary files differnew file mode 100644 index 0000000..e85e7fb --- /dev/null +++ b/src/app/fonts/Roboto-BoldItalic.ttf diff --git a/src/app/fonts/Roboto-Italic.ttf b/src/app/fonts/Roboto-Italic.ttf Binary files differnew file mode 100644 index 0000000..c9df607 --- /dev/null +++ b/src/app/fonts/Roboto-Italic.ttf diff --git a/src/app/fonts/Roboto-Light.ttf b/src/app/fonts/Roboto-Light.ttf Binary files differnew file mode 100644 index 0000000..0e97751 --- /dev/null +++ b/src/app/fonts/Roboto-Light.ttf diff --git a/src/app/fonts/Roboto-LightItalic.ttf b/src/app/fonts/Roboto-LightItalic.ttf Binary files differnew file mode 100644 index 0000000..3ad14fa --- /dev/null +++ b/src/app/fonts/Roboto-LightItalic.ttf diff --git a/src/app/fonts/Roboto-Medium.ttf b/src/app/fonts/Roboto-Medium.ttf Binary files differnew file mode 100644 index 0000000..e89b0b7 --- /dev/null +++ b/src/app/fonts/Roboto-Medium.ttf diff --git a/src/app/fonts/Roboto-MediumItalic.ttf b/src/app/fonts/Roboto-MediumItalic.ttf Binary files differnew file mode 100644 index 0000000..a5a41d3 --- /dev/null +++ b/src/app/fonts/Roboto-MediumItalic.ttf diff --git a/src/app/fonts/Roboto-Regular.ttf b/src/app/fonts/Roboto-Regular.ttf Binary files differnew file mode 100644 index 0000000..3d6861b --- /dev/null +++ b/src/app/fonts/Roboto-Regular.ttf diff --git a/src/app/fonts/Roboto-Thin.ttf b/src/app/fonts/Roboto-Thin.ttf Binary files differnew file mode 100644 index 0000000..7d084ae --- /dev/null +++ b/src/app/fonts/Roboto-Thin.ttf diff --git a/src/app/fonts/Roboto-ThinItalic.ttf b/src/app/fonts/Roboto-ThinItalic.ttf Binary files differnew file mode 100644 index 0000000..c173389 --- /dev/null +++ b/src/app/fonts/Roboto-ThinItalic.ttf diff --git a/src/app/fonts/import.css b/src/app/fonts/import.css new file mode 100644 index 0000000..c6b677a --- /dev/null +++ b/src/app/fonts/import.css @@ -0,0 +1,83 @@ +@font-face { + font-weight: 100; + font-style: italic; + font-family: "Roboto"; + src: url("Roboto-ThinItalic.ttf"); +} + +@font-face { + font-weight: 300; + font-style: italic; + font-family: "Roboto"; + src: url("Roboto-Italic.ttf"); +} + +@font-face { + font-weight: 400; + font-style: italic; + font-family: "Roboto"; + src: url("Roboto-Italic.ttf"); +} + +@font-face { + font-weight: 500; + font-style: italic; + font-family: "Roboto"; + src: url("Roboto-MediumItalic.ttf"); +} + +@font-face { + font-weight: 700; + font-style: italic; + font-family: "Roboto"; + src: url("Roboto-BoldItalic.ttf"); +} + +@font-face { + font-weight: 900; + font-style: italic; + font-family: "Roboto"; + src: url("Roboto-BlackItalic.ttf"); +} + +@font-face { + font-weight: 100; + font-style: normal; + font-family: "Roboto"; + src: url("Roboto-Thin.ttf"); +} + +@font-face { + font-weight: 300; + font-style: normal; + font-family: "Roboto"; + src: url("Roboto-Light.ttf"); +} + +@font-face { + font-weight: 400; + font-style: normal; + font-family: "Roboto"; + src: url("Roboto-Regular.ttf"); +} + +@font-face { + font-weight: 500; + font-style: normal; + font-family: "Roboto"; + src: url("Roboto-Medium.ttf"); +} + +@font-face { + font-weight: 700; + font-style: normal; + font-family: "Roboto"; + src: url("Roboto-Bold.ttf"); +} + +@font-face { + font-weight: 900; + font-style: normal; + font-family: "Roboto"; + src: url("Roboto-Black.ttf"); +} diff --git a/src/app/icons/close.png b/src/app/icons/close.png Binary files differnew file mode 100644 index 0000000..d6c162f --- /dev/null +++ b/src/app/icons/close.png diff --git a/src/app/icons/northstar.png b/src/app/icons/northstar.png Binary files differnew file mode 100644 index 0000000..f13ae27 --- /dev/null +++ b/src/app/icons/northstar.png diff --git a/src/app/icons/titanfall2.png b/src/app/icons/titanfall2.png Binary files differnew file mode 100644 index 0000000..f1caa0e --- /dev/null +++ b/src/app/icons/titanfall2.png diff --git a/src/app/icons/viper.png b/src/app/icons/viper.png Binary files differnew file mode 100644 index 0000000..281f3dd --- /dev/null +++ b/src/app/icons/viper.png diff --git a/src/app/index.html b/src/app/index.html index d9db79b..8ebffff 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -1,46 +1,103 @@ <html> <head> <meta name="viewport" content="width=device-width,initial-scale=1.0"> + <link rel="stylesheet" href="fonts/import.css"> <link rel="stylesheet" href="main.css"> + <meta charset="utf-8"> </head> <body> - <div class="lines"> - <div class="line"> - <div class="text"> - <div class="text" id="welcome">%%gui.welcome%%</div> - <div class="versions"> - <div id="vpversion"></div> - <div id="nsversion"></div> + <div id="bgHolder"></div> + + <div id="close" onclick="ipcRenderer.send('exit')"></div> + + <nav class="gamesContainer"> + <button id="vpBtn" onclick="page(0)"></button> + <button id="nsBtn" onclick="page(1)"></button> + <button id="tfBtn" onclick="page(2)"></button> + </nav> + + <div class="mainContainer"> + <div id="vpContent" class="contentContainer"> + <ul class="contentMenu"> + <li id="vpMainBtn" active onclick="showVpSection('main')">%%viper.menu.main%%</li> + <li id="vpReleaseBtn" onclick="showVpSection('release')">%%viper.menu.release%%</li> + <li id="vpInfoBtn" onclick="showVpSection('info')">%%viper.menu.info%%</li> + </ul> + <div class="contentBody"> + <div id="vpMain" class="section"> + <img src="icons/viper.png"/> + <div class="inline" style="margin-top: 20px;"> + <div id="vpversion"></div> | + <a id="setpath" href="#" onclick="setpath()">%%gui.setpath%%</a> + </div> + </div> + <div id="vpReleaseNotes" class="hidden section"></div> + <div id="vpInfo" class="hidden section"> + <h2>%%viper.menu.info.links%%</h2> + <ul> + <li>%%viper.info.discord%% <a href="https://northstar.tf/discord">northstar.tf/discord</a></li> + <li>%%viper.info.issues%% <a href="https://github.com/0neGal/viper/issues">github.com/0neGal/viper/issues</a></li> + </ul> + <h2>%%viper.menu.info.credits%%</h2> + <ul> + <li>"Titanfall|2 + Northstar" logo: <a href="https://www.steamgriddb.com/logo/47851">Aftonstjarma</a></li> + <li>Viper logo: Imply#9781</li> + </ul> </div> - </div> - <div class="buttons"> - <button id="exit" onclick="exit()">%%gui.exit%%</button> - <button id="updateBtn" onclick="update()">%%gui.update%%</button> - <button id="setpath" onclick="setpath()">%%gui.setpath%%</button> </div> </div> - <div class="line"> - <div class="text">%%gui.launch%%:</div> - <div class="buttons"> - <button id="vanilla" onclick="launchVanilla()">%%gui.launchvanilla%%</button> - <button id="northstar" onclick="launch()">%%gui.launchnorthstar%%</button> + + <div id="nsContent" class="contentContainer"> + <ul class="contentMenu"> + <li id="nsMainBtn" active onclick="showNsSection('main')">%%ns.menu.main%%</li> + <li id="nsModsBtn" onclick="showNsSection('mods')">%%ns.menu.mods%%</li> + <li id="nsReleaseBtn" onclick="showNsSection('release')">%%ns.menu.release%%</li> + </ul> + <div class="contentBody"> + <div id="nsMain" class="section"> + <div class="img"><img src="../assets/ns.png"></div> + <div class="playBtnContainer"> + <button id="playNsBtn" class="playBtn" onclick="launch()">%%gui.launch%%</button> + <div class="inline"> + <div id="nsversion"></div> + <a id="update" href="#" onclick="update()">(%%gui.update.check%%)</a> + </div> + </div> + </div> + <div id="nsMods" class="hidden section"> + <div id="modsdiv"> + </div> + <div class="line"> + <div class="text" id="modcount">%%gui.mods%%</div> + <div class="buttons modbtns"> + <button id="removemod" onclick="selected().remove()">%%gui.mods.remove%%</button> + <button id="removeall" onclick="selected(true).remove()">%%gui.mods.removeall%%</button> + <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> + </div> + </div> + </div> + <div id="nsRelease" class="hidden section"></div> </div> </div> - <div id="modsdiv"> - </div> - <div class="line"> - <div class="text" id="modcount">%%gui.mods%%</div> - <div class="buttons modbtns"> - <button id="removemod" onclick="selected().remove()">%%gui.mods.remove%%</button> - <button id="removeall" onclick="selected(true).remove()">%%gui.mods.removeall%%</button> - <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> + + <div id="tfContent" class="contentContainer"> + <ul class="contentMenu"><li style="opacity:0.0">filler</li></ul> + <div class="contentBody"> + <div class="section"> + <div class="img"><img src="../assets/vanilla.png"></div> + <div class="playBtnContainer"> + <button class="playBtn" onclick="launchVanilla()">%%gui.launch%%</button> + <div id="tf2Version"></div> + </div> + </div> </div> </div> </div> <script src="lang.js"></script> <script src="main.js"></script> + <script src="launcher.js"></script> </body> </html> diff --git a/src/app/launcher.js b/src/app/launcher.js new file mode 100644 index 0000000..9e09938 --- /dev/null +++ b/src/app/launcher.js @@ -0,0 +1,105 @@ +const markdown = require("markdown").markdown.toHTML; + +function page(page) { + let pages = document.querySelectorAll(".mainContainer .contentContainer") + let btns = document.querySelectorAll(".gamesContainer button") + + for (let i = 0; i < pages.length; i++) { + pages[i].classList.add("hidden"); + } + + for (let i = 0; i < btns.length; i++) { + btns[i].classList.add("inactive"); + } + + pages[page].classList.remove("hidden"); + btns[page].classList.remove("inactive"); + bgHolder.setAttribute("bg", page); +}; page(0) + + +ipcRenderer.on("vp-notes", (event, response) => { + let content = ""; + + for (const release of response) { + content += "# " + release.name + "\n\n" + + release.body.replaceAll("\r\n", "\n") + "\n\n\n"; + } + + vpReleaseNotes.innerHTML = markdown(content); +}); +async function loadVpReleases() { + ipcRenderer.send("get-vp-notes"); +}; loadVpReleases(); + + +ipcRenderer.on("ns-notes", (event, response) => { + let content = ""; + + for (let release of response) { + content += "# " + release.name + "\n\n" + + release.body.replaceAll("\r\n", "\nhtmlbreak") + "\n\n\n"; + } + + nsRelease.innerHTML = markdown(content).replaceAll("htmlbreak", "<br>"); +}); + +async function loadNsReleases() { + ipcRenderer.send("get-ns-notes"); +}; loadNsReleases(); + +// TODO: We gotta make this more automatic instead of switch statements +// it's both not pretty, but adding more sections requires way too much +// effort, compared to how it should be. +function showVpSection(section) { + if (!["main", "release", "info", "credits"].includes(section)) throw new Error("unknown vp section"); + vpMainBtn.removeAttribute("active"); + vpReleaseBtn.removeAttribute("active"); + vpInfoBtn.removeAttribute("active"); + + vpMain.classList.add("hidden"); + vpReleaseNotes.classList.add("hidden"); + vpInfo.classList.add("hidden"); + + switch(section) { + case "main": + vpMainBtn.setAttribute("active", ""); + vpMain.classList.remove("hidden"); + break; + case "release": + vpReleaseBtn.setAttribute("active", ""); + vpReleaseNotes.classList.remove("hidden"); + break; + case "info": + vpInfoBtn.setAttribute("active", ""); + vpInfo.classList.remove("hidden"); + break; + } +} + +function showNsSection(section) { + if (!["main", "release", "mods"].includes(section)) throw new Error("unknown ns section"); + nsMainBtn.removeAttribute("active"); + nsModsBtn.removeAttribute("active"); + nsReleaseBtn.removeAttribute("active"); + + nsMain.classList.add("hidden"); + nsMods.classList.add("hidden"); + nsRelease.classList.add("hidden"); + + switch(section) { + case "main": + nsMainBtn.setAttribute("active", ""); + nsMain.classList.remove("hidden"); + break; + case "mods": + nsModsBtn.setAttribute("active", ""); + nsMods.style.display = "block"; + nsMods.classList.remove("hidden"); + break; + case "release": + nsReleaseBtn.setAttribute("active", ""); + nsRelease.classList.remove("hidden"); + break; + } +} diff --git a/src/app/main.css b/src/app/main.css index 69b10ad..30f462e 100644 --- a/src/app/main.css +++ b/src/app/main.css @@ -1,116 +1,391 @@ :root { - --padding: 15px; - --disabled: #656E7F; - --foreground: #DDE2EB; - --background: #4C515B; - --boxbackground: #666E7F; - --subforeground: #AFAFAF; - --btnforeground: var(--foreground); - --red: #C7777F; --blue: #81A1C1; - --yellow: #ECD19A; + --orange: #D59783; + + --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); + } -@media (prefers-color-scheme: light) { - :root { - --background: #FFFFFF; - --foreground: #4C566A; - --boxbackground: #EEF0F4; - --btnforeground: var(--background); - } +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + border-radius: 10px; + background: transparent; +} + +::-webkit-scrollbar-thumb { + border-radius: 10px; + background: var(--red); } -@font-face { - font-family: "Roboto Mono"; - src: url("roboto.ttf"); +.playBtn, .gamesContainer button, #close { + cursor: pointer; } -::-webkit-scrollbar {display: none} +#close { + z-index: 1; + width: 25px; + opacity: 0.6; + height: 25px; + position: fixed; + top: var(--padding); + right: var(--padding); + background-size: contain; + transition: 0.25s ease-in-out; + background-image: url("icons/close.png"); +} -body, button, input { - font-size: 18px; - font-weight: 700; +#close:hover {opacity: 1.0} +#close:active {transform: scale(0.98)} + +body { + margin: 0; overflow: hidden; - -webkit-app-region: drag; - color: var(--foreground); - text-transform: uppercase; - background: var(--background); - font-family: "Roboto Mono", monospace; + user-select: none; + font-family: "Roboto", sans-serif; } -nobr {white-space: nowrap} +button {outline: none} +b, strong {font-weight: 700} +body, input, button {font-weight: 500} -.versions { - height: 15px; - font-size: 12px; - color: var(--subforeground); +button { + border: none; + color: white; + outline: none; + font-weight: 700; + padding: 5px 10px; + border-radius: 5px; + transition: 0.2s ease-in-out; } -.line { +button:hover {filter: brightness(110%)} +button:active {filter: brightness(90%)} + +img {pointer-events: none} + +#bgHolder { + top: 0; + left: 0; + right: 0; + bottom: 0; + pointer-events: none; + position: fixed; + transform: scale(1.1); + background-size: cover; + background-position: center; + background-repeat: no-repeat; + transition: background-image 0.5s ease-in-out; + filter: brightness(0.4) blur(2px) grayscale(0.6); +} + +#bgHolder[bg="0"] {background-image: url("../assets/bg/viper.jpg")} +#bgHolder[bg="1"] {background-image: url("../assets/bg/northstar.jpg")} +#bgHolder[bg="2"] {background-image: url("../assets/bg/tf2.jpg")} + +.gamesContainer { + width: 10%; + height: 100%; + min-width: 95px; + max-width: 120px; + + float: left; display: flex; - margin-top: var(--padding); + flex-wrap: wrap; + align-content: center; } -#modsdiv { - padding: 1px; - height: 125px; - overflow-y: scroll; - border-radius: var(--padding); - background: var(--boxbackground); - margin: calc(var(--padding) / 3) var(--padding); +.mainContainer { + height: 100%; + flex-grow: 1; + display: flex; + position: relative; } -.mod { - margin: calc(var(--padding) / 3); - border-radius: calc(var(--padding) / 2) !important; + +/* nav bar buttons */ +.gamesContainer button { + background-size: 90%; + background-position: center; + background-repeat: no-repeat; + + border: none; + transition: 0.3s ease-in-out; + background-color: transparent; + + + margin: 20px; + position: relative; + box-sizing: border-box; + flex-basis: calc(100% - 10px); } -.mod.selected {background: var(--background)} +.gamesContainer button.inactive { + opacity: 0.5; + transform: scale(0.9); +} -.mod .disabled { - color: var(--red); - position: relative; - left: var(--padding); +.gamesContainer button::before { + content: ""; + display: block; + padding-top: 100%; } -.buttons { - text-align: right; - margin-left: auto; - user-select: none; - margin-right: calc(var(--padding) / 1.9); +.gamesContainer button .content { + width: 100%; + height: 100%; + top: 0; left: 0; + position: absolute; } -.text {max-width: 38vw} -.buttons {max-width: 55vw} +#vpBtn {background-image: url("icons/viper.png")} +#nsBtn {background-image: url("icons/northstar.png")} +#tfBtn { + background-image: url("icons/titanfall2.png"); + background-size: 69%; /* nice */ +} -button, .text, .mod { - border: none; - outline: none; - user-select: none; +.contentContainer { + width: 90%; + color: white; + flex-grow: 1; + opacity: 1.0; + margin-left: 5%; + position: absolute; + transition: 0.15s ease-in-out; +} + +.contentContainer.hidden { + opacity: 0.0; + pointer-events: none; +} + +.contentMenu { + padding: 0; + flex-grow: 1; + display: flex; + font-size: 20px; + list-style: none; + margin-bottom: 0; + align-items: center; + justify-content: center; + margin-top: var(--padding); +} + +/* some sections do not need space between them and menu */ +#nsMain, #nsRelease, #vpReleaseNotes, .playBtnContainer { + margin-top: 0 !important; +} + +.contentMenu li { + opacity: 0.6; + margin: 0 26px; + cursor: pointer; + font-weight: 700; + text-align: center; + height: fit-content; + transition: opacity 0.3s ease-in-out; +} + +.contentMenu li:last-child {margin-right: 0px} +.contentMenu li:first-child {margin-left: 0px} + +.contentMenu li:hover {opacity: 0.7} + +.contentMenu li[active] { + opacity: 1.0; + pointer-events: none; +} + +.contentMenu li::after { + top: 10px; + width: 30px; + height: 5px; + opacity: 0.0; + content: " "; + display: block; + text-align: center; + position: relative; border-radius: 50px; + background: var(--red); + left: calc(50% - 15px); transition: 0.2s ease-in-out; - padding: calc(var(--padding) / 3) var(--padding); } -#welcome {padding: 0px} +.contentMenu li[active]::after { + top: 5px; + opacity: 1.0; +} -button { - color: var(--btnforeground); - -webkit-app-region: no-drag; - margin-bottom: calc(var(--padding) / 1.5); +.section { + opacity: 1.0; + position: fixed; + right: calc(var(--padding) * 2); + left: calc(100px + var(--padding)); + transition: opacity 0.15s ease-in-out; } -button:hover {opacity: 0.9} -button:active { - opacity: 0.7; - transform: scale(0.95); +.section.hidden { + opacity: 0.0; + pointer-events: none; } +.contentBody img {max-width: 100%} +.contentBody .img {text-align: center} -#setpath {background: #5E81AC} -#vanilla, #exit {background: #656E7F} -#updateBtn, #installmod {background: var(--blue)} -#togglemod, #toggleall {background: var(--yellow)} +.contentBody .section > :first-child:not(.img) { + margin-top: 35px; +} + +.contentContainer .playBtnContainer { + text-align: center; +} + +.contentContainer .playBtn { + width: 27%; + height: 11%; + border: none; + color: white; + padding: 20px; + font-size: 24px; + font-weight: bold; + margin-top: 100px; + margin-bottom: 10px; + border-radius: 10px; + background: var(--redbg); + transition: 0.3s ease-in-out; + filter: drop-shadow(0px 8px 5px rgba(0, 0, 0, 0.1)); +} + +.contentContainer .playBtn:hover { + transform: scale(1.05); + filter: drop-shadow(0px 5px 15px rgba(0, 0, 0, 0.3)) brightness(110%); +} + +.contentContainer .playBtn:active { + opacity: 0.7;transform: scale(0.98); + filter: drop-shadow(0px 5px 10px rgba(0, 0, 0, 0.4)); +} + +.contentContainer #nsMain .playBtn { + background: var(--bluebg); +} + +a { + color: var(--red); + text-decoration: none; + transition: filter 0.2s ease-in; +} + +a:hover { + filter: brightness(80%); +} + +#nsContent .contentMenu { + margin-bottom: 0; +} + +.contentBody .img img { + transform: scale(0.85); +} + +.contentBody .img { + width: 100%; + text-align: center; +} + +#nsRelease, #vpReleaseNotes { + height: 80vh; + overflow-y: scroll; + flex-direction: column; + margin-top: 10px !important; +} + +.inline * { + display: inline-block; +} + +#vpMain { + margin-top: 140px; + text-align: center; +} + +#vpMain img { + width: 20%; +} + +#vpVersion { + font-size: 16px; +} + +.simplebar-scrollbar:before { + background: var(--red) !important; +} + +#installmod {background: var(--blue)} +#togglemod, #toggleall {background: var(--orange)} #northstar, #removeall, #removemod {background: var(--red)} -button:disabled {background: var(--disabled) !important; opacity: 0.5} +button:disabled { + opacity: 0.5; + pointer-events: none; +} + +code { + font-size: 16px; + padding: 2px 5px; + border-radius: 3px; + background-color: #00000070; +} + +#nsMods .line { + display: flex; + align-items: center; + margin-top: calc(var(--padding) / 2); +} + +#modsdiv { + height: 50vh; + border-radius: 5px; + background: var(--bg); + backdrop-filter: blur(15px); + padding: calc(var(--padding) / 4); +} + +#modsdiv .mod { + display: flex; + border-radius: 5px; + transition: 0.1s ease-in-out; + margin: calc(var(--padding) / 3); + padding: calc(var(--padding) / 3); +} + +#modsdiv .mod.selected { + background: var(--selbg); +} + +#modsdiv .mod .disabled, .modbtns { + margin-left: auto; +} + +.modbtns button { + margin-left: calc(var(--padding) / 3); +} + +/* drag control */ + +#bgHolder { + user-select: none; + -webkit-app-region: drag; +} + +a, button, .contentMenu, #close, #nsRelease, #vpReleaseNotes, .mod { + -webkit-app-region: no-drag; +} diff --git a/src/app/main.js b/src/app/main.js index c365cf4..893572a 100644 --- a/src/app/main.js +++ b/src/app/main.js @@ -1,6 +1,6 @@ const fs = require("fs"); const path = require("path"); -const { ipcRenderer } = require("electron"); +const { ipcRenderer, shell } = require("electron"); const lang = require("../lang"); let shouldInstallNorthstar = false; @@ -36,10 +36,9 @@ if (fs.existsSync("viper.json")) { function exit() {ipcRenderer.send("exit")} function update() {ipcRenderer.send("update")} -/** - * Reports to the main thread about game path status. - * @param {boolean} value is game path loaded - */ +// Reports to the main process about game path status. +// @param {boolean} value is game path loaded + function setpath(value = false) { ipcRenderer.send("setpath", value); } @@ -56,16 +55,26 @@ function launchVanilla() {ipcRenderer.send("launchVanilla")} function log(msg) { console.log(msg); - welcome.innerHTML = msg; + // welcome.innerHTML = msg; } function setButtons(state) { - let buttons = document.querySelectorAll("button"); + playNsBtn.disabled = !state; +} - for (let i = 0; i < buttons.length; i++) { - buttons[i].disabled = !state; +ipcRenderer.on("ns-update-event", (event, key) => { + document.getElementById("update").innerText = `(${lang(key)})`; + console.log(key); + switch(key) { + case "cli.update.uptodate.short": + setButtons(true); + playNsBtn.innerText = lang("gui.launch"); + break; + default: + setButtons(false); + break; } -} +}); let lastselected = ""; function select(entry) { @@ -100,7 +109,12 @@ function selected(all) { return { remove: () => { - if (selected == "allmods") { + + if (selected.match(/^Northstar\./)) { + if (! confirm(lang("gui.mods.required.confirm"))) { + return; + } + } else if (selected == "allmods") { if (! confirm(lang("gui.mods.removeall.confirm"))) { return; } @@ -109,6 +123,16 @@ function selected(all) { ipcRenderer.send("removemod", selected) }, toggle: () => { + if (selected.match(/^Northstar\./)) { + if (! confirm(lang("gui.mods.required.confirm"))) { + return; + } + } else if (selected == "allmods") { + if (! confirm(lang("gui.mods.toggleall.confirm"))) { + return; + } + } + ipcRenderer.send("togglemod", selected) } } @@ -118,13 +142,6 @@ function installmod() { ipcRenderer.send("installmod") } -ipcRenderer.on("ns-updated", () => { - setButtons(true); - northstar.disabled = false; - updateBtn.innerText = lang("gui.update"); -}) -ipcRenderer.on("ns-updating", () => {setButtons(false)}) - ipcRenderer.on("newpath", (event, newpath) => { settings.gamepath = newpath; }) @@ -153,8 +170,9 @@ ipcRenderer.on("mods", (event, mods) => { }) ipcRenderer.on("version", (event, versions) => { - vpversion.innerText = lang("gui.versions.viper") + ": " + versions.vp; - nsversion.innerText = lang("gui.versions.northstar") + ": " + versions.ns; + vpversion.innerText = versions.vp; + nsversion.innerText = versions.ns; + tf2Version.innerText = versions.tf2; if (versions.ns == "unknown") { let buttons = document.querySelectorAll(".modbtns button"); @@ -164,9 +182,8 @@ ipcRenderer.on("version", (event, versions) => { } // Since Northstar is not installed, we cannot launch it - northstar.disabled = true; shouldInstallNorthstar = true; - updateBtn.innerText = lang("gui.installnorthstar"); + playNsBtn.innerText = lang("gui.installnorthstar"); } }); ipcRenderer.send("getversion"); @@ -187,6 +204,10 @@ ipcRenderer.on("wrongpath", () => { }); setlang(); -setInterval(() => { - ipcRenderer.send("setsize", document.querySelector(".lines").offsetHeight + 20); -}, 150); + +document.body.addEventListener("click", event => { + if (event.target.tagName.toLowerCase() === "a" && event.target.protocol != "file:") { + event.preventDefault(); + shell.openExternal(event.target.href); + } +}); diff --git a/src/app/roboto.ttf b/src/app/roboto.ttf Binary files differdeleted file mode 100644 index 900fce6..0000000 --- a/src/app/roboto.ttf +++ /dev/null diff --git a/src/assets/bg/northstar.jpg b/src/assets/bg/northstar.jpg Binary files differnew file mode 100644 index 0000000..01e7e55 --- /dev/null +++ b/src/assets/bg/northstar.jpg diff --git a/src/assets/bg/tf2.jpg b/src/assets/bg/tf2.jpg Binary files differnew file mode 100644 index 0000000..b6e8f2f --- /dev/null +++ b/src/assets/bg/tf2.jpg diff --git a/src/assets/bg/viper.jpg b/src/assets/bg/viper.jpg Binary files differnew file mode 100644 index 0000000..8b1d5ad --- /dev/null +++ b/src/assets/bg/viper.jpg diff --git a/src/assets/ns.png b/src/assets/ns.png Binary files differnew file mode 100644 index 0000000..a3bbf94 --- /dev/null +++ b/src/assets/ns.png diff --git a/src/assets/vanilla.png b/src/assets/vanilla.png Binary files differnew file mode 100644 index 0000000..a6ed688 --- /dev/null +++ b/src/assets/vanilla.png diff --git a/src/index.js b/src/index.js index 1b594ad..333b1c9 100644 --- a/src/index.js +++ b/src/index.js @@ -1,23 +1,24 @@ const fs = require("fs"); const path = require("path"); const { autoUpdater } = require("electron-updater"); -const { app, ipcMain, BrowserWindow } = require("electron"); +const { app, ipcMain, BrowserWindow, dialog } = require("electron"); const Emitter = require("events"); const events = new Emitter(); const utils = require("./utils"); const cli = require("./cli"); +const requests = require("./requests"); function start() { - let width = 600; win = new BrowserWindow({ - width: width, - height: 115, + width: 1000, + height: 600, show: false, title: "Viper", resizable: false, titleBarStyle: "hidden", + frame: false, icon: path.join(__dirname, "assets/icons/512x512.png"), webPreferences: { nodeIntegration: true, @@ -31,17 +32,12 @@ function start() { win.loadFile(__dirname + "/app/index.html"); ipcMain.on("exit", () => {process.exit(0)}) - ipcMain.on("setsize", (event, height) => { - win.setSize(width, height); - }) - - ipcMain.on("ns-updated", () => {win.webContents.send("ns-updated")}) - ipcMain.on("ns-updating", () => {win.webContents.send("ns-updating")}) - ipcMain.on("winLog", (event, ...args) => {win.webContents.send("log", ...args)}) - ipcMain.on("winAlert", (event, ...args) => {win.webContents.send("alert", ...args)}) - ipcMain.on("guigetmods", (event, ...args) => {win.webContents.send("mods", utils.mods.list())}) + ipcMain.on("winLog", (event, ...args) => {win.webContents.send("log", ...args)}); + ipcMain.on("winAlert", (event, ...args) => {win.webContents.send("alert", ...args)}); + ipcMain.on("ns-update-event", (event) => win.webContents.send("ns-update-event", event)); + ipcMain.on("guigetmods", (event, ...args) => {win.webContents.send("mods", utils.mods.list())}); - win.webContents.once("dom-ready", () => { + win.webContents.on("dom-ready", () => { win.webContents.send("mods", utils.mods.list()); }); @@ -99,6 +95,7 @@ ipcMain.on("newpath", (event, newpath) => { function _sendVersionsInfo() { win.webContents.send("version", { ns: utils.getNSVersion(), + tf2: utils.getTF2Version(), vp: "v" + require("../package.json").version }); } @@ -149,3 +146,10 @@ if (cli.hasArgs()) { start(); }) } + +ipcMain.on("get-ns-notes", async () => { + win.webContents.send("ns-notes", await requests.getNsReleaseNotes()); +}); +ipcMain.on("get-vp-notes", async () => { + win.webContents.send("vp-notes", await requests.getVpReleaseNotes()); +}); diff --git a/src/lang/en.json b/src/lang/en.json index bb5cf09..c2b6f98 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -13,11 +13,12 @@ "cli.setpath.noarg": "No argument provided for --setpath", "cli.update.current": "Current version:", - "cli.update.downloading": "Downloading", + "cli.update.downloading": "Downloading...", "cli.update.checking": "Checking for updates...", "cli.update.downloaddone": "Download done! Extracting...", "cli.update.finished": "Installation/Update finished!", "cli.update.uptodate": "Latest version (%s) is already installed, skipping update.", + "cli.update.uptodate.short": "Up-to-date", "cli.autoupdates.checking": "Checking for Northstar updates...", "cli.autoupdates.available": "Northstar update available!", @@ -43,6 +44,7 @@ "gui.update": "Update", "gui.setpath": "Game Path", + "gui.update.check": "Check for updates", "gui.mods": "Mods", "gui.mods.count": "Mods Installed:", "gui.mods.disabledtag": "Disabled", @@ -52,7 +54,9 @@ "gui.mods.remove": "Remove Mod", "gui.mods.removeall": "Remove All", "gui.mods.nothingselected": "You've not selected a mod.", - "gui.mods.removeall.confirm": "Removing all mods will usually require you to reinstall Northstar, are you sure?", + "gui.mods.toggleall.confirm": "Toggling all mods could disable mods required for Northstar to function. Are you sure?", + "gui.mods.removeall.confirm": "Removing all mods will usually require you to reinstall Northstar. Are you sure?", + "gui.mods.required.confirm": "You've selected a core mod, Northstar may not function without it. Are you sure?", "gui.mods.notamod": "Not a mod!", "gui.mods.extracting": "Extracting mod...", "gui.mods.installing": "Installing mod...", @@ -74,13 +78,25 @@ "gui.selectpath": "Please select the path!", "gui.gamepath.must": "The game path must be set to start Viper.", - "gui.gamepath.wrong": "This folder is not a valid game path.", + "gui.gamepath.wrong": "This folder is not a valid game path.", + "viper.menu.main": "Viper", + "viper.menu.release": "Release Notes", + "viper.menu.info": "Extras", + "viper.menu.info.links": "Links", + "viper.menu.info.credits": "Credits", + + "viper.info.discord": "Join Discord:", + "viper.info.issues": "Report issues with Viper:", + + "ns.menu.main": "Northstar Launcher", + "ns.menu.mods": "Mods", + "ns.menu.release": "Release Notes", - "general.launching": "Launching", "general.mods.enabled": "Enabled mods:", "general.mods.disabled": "Disabled mods:", "general.mods.installed": "Installed mods:", "general.missingpath": "Game path is not set!", - "general.notinstalled": "Northstar is not installed!" + "general.notinstalled": "Northstar is not installed!", + "general.launching": "Launching" } diff --git a/src/lang/fr.json b/src/lang/fr.json index 0eb083c..59a3090 100644 --- a/src/lang/fr.json +++ b/src/lang/fr.json @@ -13,11 +13,12 @@ "cli.setpath.noarg": "Aucun argument donné à --setpath", "cli.update.current": "Version actuelle :", - "cli.update.downloading": "Téléchargement en cours ", - "cli.update.checking": "Vérification des mises à jour ...", + "cli.update.downloading": "Téléchargement en cours...", + "cli.update.checking": "Vérification des mises à jour...", "cli.update.downloaddone": "Téléchargement terminé ! Extraction des fichiers...", "cli.update.finished": "Mise à jour terminée !", "cli.update.uptodate": "La dernière version (%s) est déjà installée.", + "cli.update.uptodate.short": "Votre client est à jour", "cli.autoupdates.checking": "Vérifications des mises à jour de Northstar...", "cli.autoupdates.available": "Une mise à jour de Northstar est disponible !", @@ -43,16 +44,19 @@ "gui.update": "Mise à jour", "gui.setpath": "Chemin du jeu", + "gui.update.check": "Vérifier les mises à jour", "gui.mods": "Mods", "gui.mods.count": "Mods installés :", - "gui.mods.disabledtag": "Désactivés", + "gui.mods.disabledtag": "Désactivé", "gui.mods.install": "Installer le mod", "gui.mods.toggle": "Activer/désactiver le mod", "gui.mods.toggleall": "Activer/désactiver tous les mods", "gui.mods.remove": "Supprimer le mod", "gui.mods.removeall": "Tout supprimer", "gui.mods.nothingselected": "Aucun mod n'est sélectionné.", + "gui.mods.toggleall.confirm": "Cette action pourrait désactiver des mods nécessaires au bon fonctionnement de Northstar. Souhaitez-vous faire cela ?", "gui.mods.removeall.confirm": "Supprimer tous les mods vous forcera à réinstaller Northstar, souhaitez-vous faire cela ?", + "gui.mods.required.confirm": "Vous avez sélectionné un mod de base, Northstar peut ne pas fonctionner sans celui-ci. Souhaitez-vous faire cela ?", "gui.mods.notamod": "Ceci n'est pas un mod !", "gui.mods.extracting": "Extraction du mod...", "gui.mods.installing": "Installation du mod...", @@ -74,13 +78,25 @@ "gui.selectpath": "Veuillez sélectionner le dossier où se trouve le client Titanfall 2.", "gui.gamepath.must": "Vous devez sélectionner le chemin du dossier du jeu Titanfall 2 pour pouvoir lancer Viper.", - "gui.gamepath.wrong": "Ce dossier ne contient pas le jeu Titanfall 2, et n'est donc pas valide.", + "gui.gamepath.wrong": "Ce dossier ne contient pas le jeu Titanfall 2, et n'est donc pas valide.", + "viper.menu.main": "Viper", + "viper.menu.release": "Notes de mises à jour", + "viper.menu.info": "Informations", + "viper.menu.info.links": "Liens utiles", + "viper.menu.info.credits": "Remerciements", + + "viper.info.discord": "Rejoingnez le serveur Discord :", + "viper.info.issues": "Un problème avec Viper ? Créez un ticket ici :", + + "ns.menu.main": "Lanceur Northstar", + "ns.menu.mods": "Mods", + "ns.menu.release": "Notes de mises à jour", - "general.launching": "Lancement", "general.mods.enabled": "Mods activés :", "general.mods.disabled": "Mods désactivés :", "general.mods.installed": "Mods installés :", "general.missingpath": "Le chemin du client n'est pas défini !", - "general.notinstalled": "Northstar n'est pas installé !" + "general.notinstalled": "Northstar n'est pas installé !", + "general.launching": "Lancement" } diff --git a/src/requests.js b/src/requests.js index 06c5577..5452b0d 100644 --- a/src/requests.js +++ b/src/requests.js @@ -7,6 +7,8 @@ const { https } = require("follow-redirects"); // all requests results are stored in this file const cachePath = path.join(app.getPath("cache"), "requests.json"); const NORTHSTAR_LATEST_RELEASE_KEY = "nsLatestRelease"; +const NORTHSTAR_RELEASE_NOTES_KEY = "nsReleaseNotes"; +const VIPER_RELEASE_NOTES_KEY = "vpReleaseNotes"; function _saveCache(data) { @@ -30,7 +32,6 @@ async function getLatestNsVersion() { let cache = _getRequestsCache(); if (cache[NORTHSTAR_LATEST_RELEASE_KEY] && (Date.now() - cache[NORTHSTAR_LATEST_RELEASE_KEY]["time"]) < 5 * 60 * 1000) { - console.log(`returning ${NORTHSTAR_LATEST_RELEASE_KEY} data from cache`); resolve( cache[NORTHSTAR_LATEST_RELEASE_KEY]["body"]["tag_name"] ); } else { https.get({ @@ -70,8 +71,81 @@ function getLatestNsVersionLink() { return cache[NORTHSTAR_LATEST_RELEASE_KEY]["body"].assets[0].browser_download_url; } +async function getNsReleaseNotes() { + return new Promise(resolve => { + let cache = _getRequestsCache(); + + if (cache[NORTHSTAR_RELEASE_NOTES_KEY] && (Date.now() - cache[NORTHSTAR_RELEASE_NOTES_KEY]["time"]) < 5 * 60 * 1000) { + resolve( cache[NORTHSTAR_RELEASE_NOTES_KEY]["body"] ); + } else { + https.get({ + host: "api.github.com", + port: 443, + path: "/repos/R2Northstar/Northstar/releases", + method: "GET", + headers: { "User-Agent": "viper" } + }, + + response => { + response.setEncoding("utf8"); + let responseData = ""; + + response.on("data", data => { + responseData += data; + }); + + response.on("end", _ => { + cache[NORTHSTAR_RELEASE_NOTES_KEY] = { + "time": Date.now(), + "body": JSON.parse(responseData) + }; + _saveCache(cache); + resolve( cache[NORTHSTAR_RELEASE_NOTES_KEY]["body"] ); + }); + }); + } + }); +} + +async function getVpReleaseNotes() { + return new Promise(resolve => { + let cache = _getRequestsCache(); + + if (cache[VIPER_RELEASE_NOTES_KEY] && (Date.now() - cache[VIPER_RELEASE_NOTES_KEY]["time"]) < 5 * 60 * 1000) { + resolve( cache[VIPER_RELEASE_NOTES_KEY]["body"] ); + } else { + https.get({ + host: "api.github.com", + port: 443, + path: "/repos/0negal/viper/releases", + method: "GET", + headers: { "User-Agent": "viper" } + }, + + response => { + response.setEncoding("utf8"); + let responseData = ""; + + response.on("data", data => { + responseData += data; + }); + + response.on("end", _ => { + cache[VIPER_RELEASE_NOTES_KEY] = { + "time": Date.now(), + "body": JSON.parse(responseData) + }; + _saveCache(cache); + resolve( cache[VIPER_RELEASE_NOTES_KEY]["body"] ); + }); + }); + } + }); +} module.exports = { getLatestNsVersion, - getLatestNsVersionLink + getLatestNsVersionLink, + getNsReleaseNotes, + getVpReleaseNotes }; diff --git a/src/utils.js b/src/utils.js index 87499ae..17091b4 100644 --- a/src/utils.js +++ b/src/utils.js @@ -136,6 +136,21 @@ function getNSVersion() { } } + +/** + * Loads up Titanfall|2 version from gameversion.txt file. + * TODO This file is present on Origin install, should check if it's present with + * Steam install as well. + */ +function getTF2Version() { + var versionFilePath = path.join(settings.gamepath, "gameversion.txt"); + if (fs.existsSync(versionFilePath)) { + return fs.readFileSync(versionFilePath, "utf8"); + } else { + return "unknown"; + } +} + async function update() { for (let i = 0; i < settings.excludes.length; i++) { let exclude = path.join(settings.gamepath + "/" + settings.excludes[i]); @@ -144,14 +159,14 @@ async function update() { } } - ipcMain.emit("ns-updating"); + ipcMain.emit("ns-update-event", "cli.update.checking"); console.log(lang("cli.update.checking")); var version = getNSVersion(); const latestAvailableVersion = await requests.getLatestNsVersion(); if (version === latestAvailableVersion) { - ipcMain.emit("ns-updated"); + ipcMain.emit("ns-update-event", "cli.update.uptodate.short"); console.log(lang("cli.update.uptodate"), version); winLog(lang("gui.update.uptodate")); @@ -159,9 +174,9 @@ async function update() { } else { if (version != "unknown") { console.log(lang("cli.update.current"), version); - }; console.log(lang("cli.update.downloading") + ":", latestAvailableVersion); - - winLog(lang("gui.update.downloading")); + }; + console.log(lang("cli.update.downloading") + ":", latestAvailableVersion); + ipcMain.emit("ns-update-event", "cli.update.downloading"); } https.get(requests.getLatestNsVersionLink(), (res) => { @@ -171,17 +186,18 @@ async function update() { let received = 0; res.on("data", (chunk) => { received += chunk.length; - winLog(lang("gui.update.downloading") + " " + (received / 1024 / 1024).toFixed(1) + "mb"); + ipcMain.emit("ns-update-event", lang("gui.update.downloading") + " " + (received / 1024 / 1024).toFixed(1) + "mb"); }) stream.on("finish", () => { stream.close(); winLog(lang("gui.update.extracting")); + ipcMain.emit("ns-update-event", "gui.update.extracting"); console.log(lang("cli.update.downloaddone")); fs.createReadStream(settings.zip).pipe(unzip.Extract({path: settings.gamepath})) .on("finish", () => { - fs.writeFileSync(path.join(settings.gamepath, "ns_version.txt"), latestAvailableVersion); - ipcMain.emit("getversion"); + fs.writeFileSync(path.join(settings.gamepath, "ns_version.txt"), latestAvailableVersion); + ipcMain.emit("getversion"); for (let i = 0; i < settings.excludes.length; i++) { let exclude = path.join(settings.gamepath + "/" + settings.excludes[i]); @@ -190,11 +206,11 @@ async function update() { } } - ipcMain.emit("guigetmods"); - ipcMain.emit("ns-updated"); - winLog(lang("gui.update.finished")); - console.log(lang("cli.update.finished")); - cli.exit(); + ipcMain.emit("guigetmods"); + ipcMain.emit("ns-update-event", "cli.update.uptodate.short"); + winLog(lang("gui.update.finished")); + console.log(lang("cli.update.finished")); + cli.exit(); }) }) }) @@ -487,6 +503,7 @@ module.exports = { updatevp, settings, getNSVersion, + getTF2Version, isGameRunning, setlang: (lang) => { settings.lang = lang; |