Skip to content

Commit b87425d

Browse files
committed
More changes
1 parent d197366 commit b87425d

12 files changed

+190
-126
lines changed

.github/copilot-instructions.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Stretchly Development Assistant
2+
3+
You are a specialized assistant for developers working on Stretchly, a break-time reminder application that encourages regular stretching and healthy work habits.
4+
5+
## Technical Stack
6+
- ElectronJS for cross-platform desktop functionality
7+
- NodeJS backend
8+
- JavaScript (following StandardJS style guidelines) using ESM (ECMAScript Modules)
9+
- HTML and CSS for UI components
10+
11+
## Development Guidelines
12+
- Follow StandardJS style (like no semicolons, 2-space indentation)
13+
- Prefer ES6+ features (like arrow functions, destructuring, etc.)
14+
- Maintain cross-platform compatibility (Windows, macOS, Linux)
15+
- Use appropriate Electron APIs for native functionality
16+
- Maintain accessibility standards in UI components
17+
- Keep performance in mind, especially for background processes
18+
19+
## Code Organization
20+
- Respect the existing project structure
21+
- Place new functionality in appropriate modules
22+
- Follow the established patterns for event handling
23+
24+
## Testing Expectations
25+
- Suggest tests for new functionality
26+
- Consider edge cases in different operating systems
27+
28+
When suggesting code changes, explain your reasoning and how they align with Stretchly's goals of promoting healthy computer use.

app/break-preload.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { contextBridge, ipcRenderer } from 'electron'
22
import humanizeDuration from 'humanize-duration'
33
import * as utils from './utils/utils.js'
4-
import './expose-process.js'
4+
import './exposes/expose-process.js'
55

66
contextBridge.exposeInMainWorld('i18next', {
77
t: (key, options) => ipcRenderer.invoke('i18next-translate', key, options),

app/contributor-preferences-preload.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ipcRenderer, contextBridge } from 'electron'
2-
import './expose-process.js'
2+
import './exposes/expose-process.js'
33

44
contextBridge.exposeInMainWorld('settings', {
55
currentSettings: async () => {

app/microbreak-preload.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { contextBridge, ipcRenderer } from 'electron'
22
import humanizeDuration from 'humanize-duration'
33
import * as utils from './utils/utils.js'
4-
import './expose-process.js'
4+
import './exposes/expose-process.js'
55

66
contextBridge.exposeInMainWorld('i18next', {
77
t: (key, options) => ipcRenderer.invoke('i18next-translate', key, options),

app/preferences-preload.mjs

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,7 @@
1-
import { ipcRenderer, shell, contextBridge } from 'electron'
2-
import './expose-process.js'
1+
import { exposeGlobal, exposeI18next, exposeProcess, exposeSettings, exposeStretchly } from './utils/context-bridge-exposers.js'
32

4-
contextBridge.exposeInMainWorld('settings', {
5-
currentSettings: async () => {
6-
return await ipcRenderer.invoke('current-settings')
7-
},
8-
saveSettings: async (key, value) => {
9-
ipcRenderer.send('save-setting', key, value)
10-
}
11-
})
12-
13-
contextBridge.exposeInMainWorld('i18next', {
14-
t: (key, options) => ipcRenderer.invoke('i18next-translate', key, options),
15-
dir: () => ipcRenderer.invoke('i18next-dir')
16-
})
17-
18-
contextBridge.exposeInMainWorld('electronAPI', {
19-
onTranslate: (callback) => ipcRenderer.on('translate', () => callback()),
20-
onEnableContributorPreferences: (callback) => ipcRenderer.on('enable-contributor-preferences', () => callback()),
21-
openExternal: (path) => shell.openExternal(path),
22-
openPath: (path) => shell.openPath(path),
23-
getWindowBounds: () => ipcRenderer.invoke('get-window-bounds'),
24-
getVersion: () => ipcRenderer.invoke('get-version'),
25-
setWindowSize: (width, height) => ipcRenderer.send('set-window-size', width, height),
26-
openContributorPreferences: () => ipcRenderer.send('open-contributor-preferences'),
27-
openSyncPreferences: () => ipcRenderer.send('open-sync-preferences'),
28-
showDebug: () => ipcRenderer.invoke('show-debug'),
29-
restoreDefaults: () => ipcRenderer.send('restore-defaults'),
30-
playSound: (name) => ipcRenderer.send('play-sound', name),
31-
openContributorAuth: (provider) => ipcRenderer.send('open-contributor-auth', provider)
32-
})
33-
34-
contextBridge.exposeInMainWorld('global', {
35-
setValue: (name, value) => ipcRenderer.send('set-global-value', name, value),
36-
getValue: (name) => ipcRenderer.invoke('get-global-value', name)
37-
})
3+
exposeGlobal()
4+
exposeI18next()
5+
exposeProcess()
6+
exposeSettings()
7+
exposeStretchly()

app/preferences-renderer.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const versionChecker = new VersionChecker()
88
let eventsAttached = false
99

1010
window.onload = async (e) => {
11-
const bounds = await window.electronAPI.getWindowBounds()
11+
const bounds = await window.stretchly.getWindowBounds()
1212
const settings = await window.settings.currentSettings()
1313

1414
new HtmlTranslate(document).translate()
@@ -50,7 +50,7 @@ window.onload = async (e) => {
5050
const [
5151
reference, timeleft, breaknumber,
5252
postponesnumber, settingsfile, logsfile, doNotDisturb
53-
] = await window.electronAPI.showDebug()
53+
] = await window.stretchly.showDebug()
5454
const debugInfo = document.querySelector('.debug > :first-child')
5555
if (debugInfo.style.display === 'block') {
5656
debugInfo.style.display = 'none'
@@ -73,7 +73,7 @@ window.onload = async (e) => {
7373
}
7474
}
7575

76-
window.electronAPI.onTranslate(async () => {
76+
window.stretchly.onTranslate(async () => {
7777
new HtmlTranslate(document).translate()
7878
document.querySelectorAll('input[type="range"]').forEach(async range => {
7979
const settings = await window.settings.currentSettings()
@@ -88,7 +88,7 @@ window.onload = async (e) => {
8888
setWindowHeight()
8989
})
9090

91-
window.electronAPI.onEnableContributorPreferences(() => {
91+
window.stretchly.onEnableContributorPreferences(() => {
9292
showContributorPreferencesButton()
9393
})
9494

@@ -111,12 +111,12 @@ window.onload = async (e) => {
111111

112112
document.querySelector('[name="contributorPreferences"]').onclick = (event) => {
113113
event.preventDefault()
114-
window.electronAPI.openContributorPreferences()
114+
window.stretchly.openContributorPreferences()
115115
}
116116

117117
document.querySelector('[name="syncPreferences"]').onclick = (event) => {
118118
event.preventDefault()
119-
window.electronAPI.openSyncPreferences()
119+
window.stretchly.openSyncPreferences()
120120
}
121121

122122
// TODO refactor out?
@@ -226,7 +226,7 @@ window.onload = async (e) => {
226226
document.querySelectorAll('.sounds img').forEach(preview => {
227227
if (!eventsAttached) {
228228
preview.onclick = (event) =>
229-
window.electronAPI.playSound(preview.closest('div').querySelector('input').value)
229+
window.stretchly.playSound(preview.closest('div').querySelector('input').value)
230230
}
231231
})
232232

@@ -248,22 +248,22 @@ window.onload = async (e) => {
248248
})
249249

250250
document.querySelector('.settings > div > button').onclick = (event) => {
251-
window.electronAPI.restoreDefaults()
251+
window.stretchly.restoreDefaults()
252252
}
253253

254254
document.querySelectorAll('.about a').forEach((item) => {
255255
item.onclick = (event) => {
256256
event.preventDefault()
257257
if (event.target.classList.contains('file')) {
258-
window.electronAPI.openPath(event.target.innerHTML)
258+
window.electronApi.openPath(event.target.innerHTML)
259259
} else {
260-
window.electronAPI.openExternal(event.target.href)
260+
window.electronApi.openExternal(event.target.href)
261261
}
262262
}
263263
})
264264

265265
document.querySelector('[name="becomePatron"]').onclick = () => {
266-
window.electronAPI.openExternal('https://hovancik.net/stretchly/sponsor')
266+
window.electronApi.openExternal('https://hovancik.net/stretchly/sponsor')
267267
}
268268

269269
document.querySelector('[name="alreadyContributor"]').onclick = () => {
@@ -279,11 +279,11 @@ window.onload = async (e) => {
279279
document.querySelectorAll('.authenticate a').forEach((button) => {
280280
button.onclick = (event) => {
281281
event.preventDefault()
282-
window.electronAPI.openContributorAuth(button.dataset.provider)
282+
window.stretchly.openContributorAuth(button.dataset.provider)
283283
}
284284
})
285285

286-
document.querySelector('.version').innerHTML = await window.electronAPI.getVersion()
286+
document.querySelector('.version').innerHTML = await window.stretchly.getVersion()
287287
versionChecker.latest()
288288
.then(version => {
289289
document.querySelector('.latestVersion').innerHTML = version.replace('v', '')
@@ -312,7 +312,7 @@ window.onload = async (e) => {
312312
}
313313
}
314314
if (height) {
315-
window.electronAPI.setWindowSize(bounds.width, height)
315+
window.stretchly.setWindowSize(bounds.width, height)
316316
}
317317
}
318318

app/process-preload.mjs

Lines changed: 16 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,17 @@
1-
import { contextBridge, ipcRenderer, shell } from 'electron'
2-
import semver from 'semver'
3-
import * as utils from './utils/utils.js'
1+
import {
2+
exposeElectronApi,
3+
exposeGlobal,
4+
exposeI18next,
5+
exposeProcess,
6+
exposeSemver,
7+
exposeStretchly,
8+
exposeUtils
9+
} from './utils/context-bridge-exposers.js'
410

5-
contextBridge.exposeInMainWorld('electronAPI', {
6-
onPlaySound: (callback) => ipcRenderer.on('play-sound',
7-
(_event, file, volume) => callback(file, volume)),
8-
onShowNotification: (callback) => ipcRenderer.on('show-notification',
9-
(_event, text, silent) => callback(text, silent)),
10-
onCheckVersion: (callback) => ipcRenderer.on('check-version',
11-
(_event, oldVersion, notify, silent) => callback(oldVersion, notify, silent)),
12-
updateTray: () => ipcRenderer.send('update-tray'),
13-
openExternal: (path) => shell.openExternal(path)
14-
})
15-
16-
contextBridge.exposeInMainWorld('semver', {
17-
valid: (version) => semver.valid(version),
18-
clean: (version) => semver.clean(version),
19-
coerce: (version) => semver.coerce(version),
20-
gt: (a, b) => semver.gt(a, b),
21-
gte: (a, b) => semver.gte(a, b)
22-
})
23-
24-
contextBridge.exposeInMainWorld('process', {
25-
platform: () => process.platform,
26-
getSystemVersion: () => process.getSystemVersion()
27-
})
28-
29-
contextBridge.exposeInMainWorld('global', {
30-
setValue: (name, value) => ipcRenderer.send('set-global-value', name, value),
31-
getValue: (name) => ipcRenderer.invoke('get-global-value', name)
32-
})
33-
34-
contextBridge.exposeInMainWorld('i18next', {
35-
t: (key, options) => ipcRenderer.invoke('i18next-translate', key, options)
36-
})
37-
38-
contextBridge.exposeInMainWorld('utils', {
39-
shouldShowNotificationTitle: (platform, systemVersion) => {
40-
return utils.shouldShowNotificationTitle(platform, systemVersion, semver)
41-
}
42-
})
11+
exposeElectronApi()
12+
exposeGlobal()
13+
exposeI18next()
14+
exposeProcess()
15+
exposeStretchly()
16+
exposeSemver()
17+
exposeUtils()

app/process-renderer.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import VersionChecker from './utils/versionChecker.js'
22

33
window.onload = async (e) => {
4-
window.electronAPI.onPlaySound((file, volume) => {
4+
window.stretchly.onPlaySound((file, volume) => {
55
__electronLog.info(`Stretchly: playing audio/${file}.wav (volume: ${volume})`)
66
const audio = new Audio(`audio/${file}.wav`)
77
audio.volume = volume
88
audio.play()
99
})
1010

11-
window.electronAPI.onShowNotification(async (text, silent) => {
11+
window.stretchly.onShowNotification(async (text, silent) => {
1212
__electronLog.info(`Stretchly: showing notification "${text}" (silent: ${silent})`)
1313
const title = await window.utils.shouldShowNotificationTitle(
1414
await window.process.platform,
@@ -24,7 +24,7 @@ window.onload = async (e) => {
2424
setTimeout(() => notification.close(), 7000)
2525
})
2626

27-
window.electronAPI.onCheckVersion(async (oldVersion, notify, silent) => {
27+
window.stretchly.onCheckVersion(async (oldVersion, notify, silent) => {
2828
if (window.global.getValue('isNewVersion') && notify) {
2929
notifyNewVersion(silent)
3030
} else {
@@ -36,7 +36,7 @@ window.onload = async (e) => {
3636
__electronLog.info(`Stretchly: checking for new version (local: ${oldVersion}, remote: ${cleanVersion})`)
3737
if (await window.semver.valid(cleanVersion) && await window.semver.gt(cleanVersion, oldVersion)) {
3838
await window.global.setValue('isNewVersion', true)
39-
window.electronAPI.updateTray()
39+
window.stretchly.updateTray()
4040
if (notify) {
4141
notifyNewVersion(silent)
4242
}
@@ -55,6 +55,6 @@ window.onload = async (e) => {
5555
body: await window.i18next.t('process.newVersionAvailable'),
5656
silent
5757
})
58-
notification.onclick = () => window.electronAPI.openExternal('https://hovancik.net/stretchly/downloads')
58+
notification.onclick = () => window.electronApi.openExternal('https://hovancik.net/stretchly/downloads')
5959
}
6060
}

0 commit comments

Comments
 (0)