mirror of
https://github.com/heyman/heynote.git
synced 2024-11-21 15:33:14 +01:00
Read dark/light mode from system, automatically listen for changes, and add button for toggling the mode to the status bar
This commit is contained in:
parent
fbac07d338
commit
2f842612fb
@ -54,7 +54,7 @@ async function createWindow() {
|
||||
// Consider using contextBridge.exposeInMainWorld
|
||||
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
contextIsolation: true,
|
||||
},
|
||||
})
|
||||
|
||||
@ -119,5 +119,12 @@ ipcMain.handle('open-win', (_, arg) => {
|
||||
childWindow.loadURL(`${url}#${arg}`)
|
||||
} else {
|
||||
childWindow.loadFile(indexHtml, { hash: arg })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
ipcMain.handle('dark-mode:set', (event, mode) => {
|
||||
nativeTheme.themeSource = mode
|
||||
})
|
||||
|
||||
ipcMain.handle('dark-mode:get', () => nativeTheme.themeSource)
|
||||
|
@ -1,3 +1,32 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
|
||||
const getComputedTheme = () => window.matchMedia('(prefers-color-scheme: dark)').matches ? "dark" : "light"
|
||||
const mediaMatch = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
let darkModeChangeListener = null
|
||||
|
||||
contextBridge.exposeInMainWorld('darkMode', {
|
||||
set: (mode) => ipcRenderer.invoke('dark-mode:set', mode),
|
||||
get: async () => {
|
||||
const mode = await ipcRenderer.invoke('dark-mode:get')
|
||||
return {
|
||||
theme: mode,
|
||||
computed: getComputedTheme(),
|
||||
}
|
||||
},
|
||||
onChange: (callback) => {
|
||||
darkModeChangeListener = (event) => {
|
||||
callback(event.matches ? "dark" : "light")
|
||||
}
|
||||
mediaMatch.addEventListener('change', darkModeChangeListener)
|
||||
return mediaMatch
|
||||
},
|
||||
removeListener() {
|
||||
mediaMatch.removeEventListener('change', darkModeChangeListener)
|
||||
},
|
||||
initial: getComputedTheme(),
|
||||
})
|
||||
|
||||
|
||||
function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) {
|
||||
return new Promise((resolve) => {
|
||||
if (condition.includes(document.readyState)) {
|
||||
|
BIN
public/icons/both-mode.png
Normal file
BIN
public/icons/both-mode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
BIN
public/icons/dark-mode.png
Normal file
BIN
public/icons/dark-mode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
BIN
public/icons/light-mode.png
Normal file
BIN
public/icons/light-mode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
36
src/App.vue
36
src/App.vue
@ -2,8 +2,7 @@
|
||||
import HelloWorld from './components/HelloWorld.vue'
|
||||
import StatusBar from './components/StatusBar.vue'
|
||||
import Editor from './components/Editor.vue'
|
||||
|
||||
console.log("[App.vue]", `Hello world from Electron ${process.versions.electron}!`)
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -18,11 +17,39 @@
|
||||
column: 1,
|
||||
language: "plaintext",
|
||||
languageAuto: true,
|
||||
theme: "dark",
|
||||
theme: window.darkMode.initial,
|
||||
initialTheme: window.darkMode.initial,
|
||||
systemTheme: 'system',
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
window.darkMode.get().then((mode) => {
|
||||
this.theme = mode.computed
|
||||
this.systemTheme = mode.theme
|
||||
})
|
||||
window.darkMode.onChange((theme) => {
|
||||
this.theme = theme
|
||||
})
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
window.darkMode.removeListener()
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleTheme() {
|
||||
let newTheme
|
||||
// when the "system" theme is used, make sure that the first click always results in amn actual theme change
|
||||
if (this.initialTheme === "light") {
|
||||
newTheme = this.systemTheme === "system" ? "dark" : (this.systemTheme === "dark" ? "light" : "system")
|
||||
} else {
|
||||
newTheme = this.systemTheme === "system" ? "light" : (this.systemTheme === "light" ? "dark" : "system")
|
||||
}
|
||||
window.darkMode.set(newTheme)
|
||||
this.systemTheme = newTheme
|
||||
},
|
||||
|
||||
onCursorChange(e) {
|
||||
//console.log("onCursorChange:", e)
|
||||
this.line = e.cursorLine.line
|
||||
@ -47,7 +74,8 @@
|
||||
:language="language"
|
||||
:languageAuto="languageAuto"
|
||||
:theme="theme"
|
||||
@toggleTheme="theme = theme === 'dark' ? 'light' : 'dark'"
|
||||
:systemTheme="systemTheme"
|
||||
@toggleTheme="toggleTheme"
|
||||
class="status"
|
||||
/>
|
||||
</template>
|
||||
|
@ -19,6 +19,7 @@
|
||||
"language",
|
||||
"languageAuto",
|
||||
"theme",
|
||||
"systemTheme",
|
||||
],
|
||||
|
||||
mounted() {
|
||||
@ -44,11 +45,13 @@
|
||||
Col <span class="num">{{ column }}</span>
|
||||
</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="status-block theme clickable" @click="$emit('toggleTheme')">{{ theme }}</div>
|
||||
<div class="status-block lang clickable">
|
||||
{{ languageName }}
|
||||
<span v-if="languageAuto" class="auto">(auto)</span>
|
||||
</div>
|
||||
<div class="status-block theme clickable" @click="$emit('toggleTheme')">
|
||||
<span :class="'icon ' + systemTheme"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -76,23 +79,45 @@
|
||||
color: rgba(255, 255, 255, 0.75)
|
||||
.status-block.lang .auto
|
||||
color: rgba(255, 255, 255, 0.55)
|
||||
.theme .icon
|
||||
opacity: 0.9
|
||||
|
||||
.spacer
|
||||
flex-grow: 1
|
||||
|
||||
.status-block
|
||||
padding: 2px 12px
|
||||
padding: 2px 10px
|
||||
cursor: default
|
||||
&:first-child
|
||||
padding-left: 12px
|
||||
&:last-child
|
||||
padding-right: 12px
|
||||
&.clickable
|
||||
cursor: pointer
|
||||
&:hover
|
||||
background: rgba(255,255,255, 0.1)
|
||||
&.line-number
|
||||
background-color: rgba(255,255,255, 0.1)
|
||||
.line-number
|
||||
color: rgba(255, 255, 255, 0.7)
|
||||
.num
|
||||
color: rgba(255, 255, 255, 1.0)
|
||||
.lang
|
||||
.auto
|
||||
color: rgba(255, 255, 255, 0.7)
|
||||
.num
|
||||
color: rgba(255, 255, 255, 1.0)
|
||||
&.lang
|
||||
.auto
|
||||
color: rgba(255, 255, 255, 0.7)
|
||||
.theme
|
||||
padding-top: 0
|
||||
padding-bottom: 0
|
||||
.icon
|
||||
display: block
|
||||
width: 14px
|
||||
height: 22px
|
||||
background-size: 14px
|
||||
background-repeat: no-repeat
|
||||
background-position: center center
|
||||
&.dark
|
||||
background-image: url("/icons/dark-mode.png")
|
||||
&.light
|
||||
background-image: url("/icons/light-mode.png")
|
||||
&.system
|
||||
background-image: url("/icons/both-mode.png")
|
||||
|
||||
</style>
|
||||
|
@ -24,7 +24,7 @@ export class HeynoteEditor {
|
||||
//minimalSetup,
|
||||
customSetup,
|
||||
|
||||
this.theme.of("dark" ? heynoteDark : heynoteLight),
|
||||
this.theme.of(theme === "dark" ? heynoteDark : heynoteLight),
|
||||
heynoteBase,
|
||||
indentUnit.of(" "),
|
||||
EditorView.scrollMargins.of(f => {
|
||||
|
Loading…
Reference in New Issue
Block a user