Skip to content

Commit d437d38

Browse files
committed
feat: allow users to configure the launch url
1 parent 6982279 commit d437d38

File tree

3 files changed

+167
-2
lines changed

3 files changed

+167
-2
lines changed

local/start.html

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,41 @@
9090
#music-btn.crossed-out:active::after {
9191
background-color: #b6b6b6; /* Darken the cross line on click */
9292
}
93+
.settings-btn {
94+
background: transparent;
95+
padding: 0;
96+
width: 21px;
97+
height: 21px;
98+
display: flex;
99+
align-items: center;
100+
justify-content: center;
101+
cursor: pointer;
102+
}
103+
.settings-btn svg {
104+
margin-top: 1px;
105+
width: 17px;
106+
height: 17px;
107+
color: #fff;
108+
}
109+
.settings-btn:active svg {
110+
color: #b6b6b6;
111+
}
112+
#settings-dialog {
113+
display: none;
114+
position: fixed;
115+
top: 50%;
116+
left: 50%;
117+
transform: translate(-50%, -50%);
118+
z-index: 9999;
119+
min-width: 320px;
120+
}
121+
#settings-overlay {
122+
display: none;
123+
position: fixed;
124+
inset: 0;
125+
background: rgba(0,0,0,0.4);
126+
z-index: 9998;
127+
}
93128
</style>
94129
<body>
95130

@@ -104,6 +139,9 @@
104139
<g fill="currentColor" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><g transform="scale(5.33333,5.33333)"><path d="M25,4c-2.209,0 -4,1.791 -4,4v19.36914l0.01758,0.02148c-0.8148,-0.25595 -1.66353,-0.38764 -2.51758,-0.39062c-4.69442,0 -8.5,3.80558 -8.5,8.5c0,4.69442 3.80558,8.5 8.5,8.5c2.2855,-0.00104 4.47428,-0.92243 6.07245,-2.55624c1.59817,-1.63382 2.47106,-3.84239 2.42169,-6.12735c0.00158,0.06211 0.00586,0.12416 0.00586,0.18359v-31.5zM30,6.39063v8.03906c0.07,0.06 0.12945,0.11969 0.18945,0.17969c3.06,3.01 4.98,4.91148 3,9.27148c-0.82,1.8 -0.23984,3.92953 1.41016,5.01953l1.90039,1.25977c7.12,-10.73 1.79039,-15.98031 -2.09961,-19.82031c-1.44,-1.43 -3.06039,-2.82922 -4.40039,-3.94922zM26.98828,35.1582l0.00195,0.00195c0.0008,0.00884 -0.00068,0.01838 0,0.02734c-0.00063,-0.00977 -0.00129,-0.01953 -0.00195,-0.0293z"></path></g></g>
105140
</svg>
106141
</button>
142+
<button class="settings-btn" onclick="openSettings()" aria-label="Minimize" style="-webkit-app-region: no-drag">
143+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 15.5A3.5 3.5 0 0 1 8.5 12 3.5 3.5 0 0 1 12 8.5a3.5 3.5 0 0 1 3.5 3.5 3.5 3.5 0 0 1-3.5 3.5m7.43-2.92c.04-.34.07-.68.07-1.08s-.03-.74-.07-1.08l2.32-1.84c.21-.16.27-.45.13-.69l-2.2-3.82c-.13-.23-.43-.31-.67-.23l-2.73 1.1c-.57-.44-1.17-.81-1.84-1.08l-.42-2.9C14.46 2.18 14.24 2 14 2h-4c-.25 0-.46.18-.49.42l-.42 2.9c-.67.27-1.27.64-1.84 1.08l-2.73-1.1c-.24-.09-.54 0-.67.23L1.65 9.35c-.14.23-.08.53.13.69l2.32 1.84c-.04.34-.07.69-.07 1.08s.03.74.07 1.08L1.78 15.88c-.21.16-.27.45-.13.69l2.2 3.82c.13.23.43.31.67.23l2.73-1.1c.57.44 1.17.81 1.84 1.08l.42 2.9c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.42-2.9c.67-.27 1.27-.64 1.84-1.08l2.73 1.1c.24.09.54 0 .67-.23l2.2-3.82c.14-.23.08-.53-.13-.69l-2.32-1.84z"/></svg>
144+
</button>
107145
<button id="min-btn" onclick="window.electronAPI.minimizeWindow()" aria-label="Minimize"></button>
108146
<button id="max-btn" onclick="toggleMaximize()" aria-label="Maximize"></button>
109147
<button id="close-btn" onclick="window.electronAPI.closeWindow()" aria-label="Close"></button>
@@ -117,13 +155,96 @@
117155

118156
</div>
119157
</div>
120-
158+
159+
<div id="url-toast" style="
160+
position: fixed;
161+
bottom: 16px;
162+
left: 50%;
163+
transform: translateX(-50%);
164+
background: rgba(0,0,0,0.7);
165+
color: #fff;
166+
font-family: Tahoma, sans-serif;
167+
font-size: 16px;
168+
padding: 12px 22px;
169+
border-radius: 8px;
170+
opacity: 0;
171+
transition: opacity 1.5s ease;
172+
pointer-events: none;
173+
white-space: nowrap;
174+
z-index: 9997;
175+
"></div>
176+
177+
<div id="settings-overlay" onclick="closeSettings()"></div>
178+
<div id="settings-dialog" class="window">
179+
<div class="title-bar">
180+
<img class="title-bar-icon" src="images/icon.png">
181+
<div class="title-bar-text">Settings</div>
182+
<div class="title-bar-controls">
183+
<button onclick="closeSettings()" aria-label="Close"></button>
184+
</div>
185+
</div>
186+
<div class="window-body" style="padding: 12px; display: flex; flex-direction: column; gap: 8px;">
187+
<label for="base-url-input" style="font-family: Tahoma, sans-serif; font-size: 12px;">Launch URL</label>
188+
<input id="base-url-input" type="text" style="width: 100%; box-sizing: border-box; font-size: 12px;" placeholder="https://sploder.online">
189+
<div style="display: flex; gap: 6px; justify-content: flex-end; margin-top: 4px;">
190+
<button onclick="saveSettings()">OK</button>
191+
<button onclick="closeSettings()">Cancel</button>
192+
</div>
193+
</div>
194+
</div>
195+
121196
</body>
122197
<script>
123198
// If URL contains music=true, show music button
124199
const urlParams = new URLSearchParams(window.location.search);
125200
if (urlParams.get('music') === 'true') {
126201
document.getElementById('music-btn').style.display = 'block';
127202
}
203+
204+
async function showUrlToast() {
205+
const url = await window.electronAPI.getBaseUrl();
206+
const toast = document.getElementById('url-toast');
207+
toast.textContent = 'Launching: ' + url;
208+
toast.style.opacity = '1';
209+
setTimeout(() => { toast.style.opacity = '0'; }, 10000);
210+
}
211+
212+
window.addEventListener('load', showUrlToast);
213+
214+
async function openSettings() {
215+
const current = await window.electronAPI.getBaseUrl();
216+
document.getElementById('base-url-input').value = current || '';
217+
document.getElementById('settings-overlay').style.display = 'block';
218+
document.getElementById('settings-dialog').style.display = 'block';
219+
document.getElementById('base-url-input').focus();
220+
}
221+
222+
function closeSettings() {
223+
document.getElementById('settings-overlay').style.display = 'none';
224+
document.getElementById('settings-dialog').style.display = 'none';
225+
}
226+
227+
async function saveSettings() {
228+
const input = document.getElementById('base-url-input');
229+
const url = input.value.trim();
230+
if (!url) return;
231+
const ok = await window.electronAPI.setBaseUrl(url);
232+
if (!ok) {
233+
input.style.outline = '2px solid red';
234+
return;
235+
}
236+
input.style.outline = '';
237+
closeSettings();
238+
showUrlToast();
239+
// Reload the content frame with the new URL
240+
const frame = document.getElementById('content-frame');
241+
const newUrl = await window.electronAPI.getUrl('update');
242+
frame.src = newUrl;
243+
}
244+
245+
document.addEventListener('keydown', (e) => {
246+
if (e.key === 'Escape') closeSettings();
247+
if (e.key === 'Enter' && document.getElementById('settings-dialog').style.display === 'block') saveSettings();
248+
});
128249
</script>
129250
</html>

src/main/index.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const { app, BrowserWindow, shell, ipcMain, session } = require("electron");
22
const path = require("path");
3+
const fs = require("fs");
34

45
// Import centralized configuration
56
const { createConfig } = require("../config");
@@ -23,6 +24,29 @@ function pathToFileURL(filePath) {
2324
const isDev = !app.isPackaged;
2425
const config = createConfig(isDev, buildConfig);
2526

27+
// Load persisted base URL from userData settings file
28+
function getSettingsPath() {
29+
return path.join(app.getPath('userData'), 'settings.json');
30+
}
31+
32+
function loadSettings() {
33+
try {
34+
const data = fs.readFileSync(getSettingsPath(), 'utf8');
35+
return JSON.parse(data);
36+
} catch {
37+
return {};
38+
}
39+
}
40+
41+
function saveSettings(settings) {
42+
fs.writeFileSync(getSettingsPath(), JSON.stringify(settings, null, 2), 'utf8');
43+
}
44+
45+
const settings = loadSettings();
46+
if (settings.baseUrl) {
47+
config.baseUrl = settings.baseUrl;
48+
}
49+
2650
// Set up IPC handlers early to ensure they're registered before window creation
2751
let win;
2852
let currentStatus = 'Playing Sploder';
@@ -95,6 +119,24 @@ ipcMain.handle('get-url', (event, endpoint) => {
95119
return config.getUrl(endpoint);
96120
});
97121

122+
ipcMain.handle('get-base-url', () => {
123+
return config.baseUrl;
124+
});
125+
126+
ipcMain.handle('set-base-url', (event, url) => {
127+
try {
128+
const parsed = new URL(url);
129+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return false;
130+
} catch {
131+
return false;
132+
}
133+
config.baseUrl = url;
134+
const s = loadSettings();
135+
s.baseUrl = url;
136+
saveSettings(s);
137+
return true;
138+
});
139+
98140
// If not on windows, disable RPC
99141
let DiscordRPC;
100142
if (process.platform == "win32") {

src/renderer/preload.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@ contextBridge.exposeInMainWorld('electronAPI', {
1515
},
1616
// Configuration API
1717
getConfig: () => ipcRenderer.invoke('get-config'),
18-
getUrl: (endpoint) => ipcRenderer.invoke('get-url', endpoint)
18+
getUrl: (endpoint) => ipcRenderer.invoke('get-url', endpoint),
19+
getBaseUrl: () => ipcRenderer.invoke('get-base-url'),
20+
setBaseUrl: (url) => ipcRenderer.invoke('set-base-url', url)
1921
});

0 commit comments

Comments
 (0)