mirror of
https://github.com/heyman/heynote.git
synced 2024-11-25 01:13:17 +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
|
// Consider using contextBridge.exposeInMainWorld
|
||||||
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
|
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
contextIsolation: false,
|
contextIsolation: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -119,5 +119,12 @@ ipcMain.handle('open-win', (_, arg) => {
|
|||||||
childWindow.loadURL(`${url}#${arg}`)
|
childWindow.loadURL(`${url}#${arg}`)
|
||||||
} else {
|
} else {
|
||||||
childWindow.loadFile(indexHtml, { hash: arg })
|
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']) {
|
function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (condition.includes(document.readyState)) {
|
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 HelloWorld from './components/HelloWorld.vue'
|
||||||
import StatusBar from './components/StatusBar.vue'
|
import StatusBar from './components/StatusBar.vue'
|
||||||
import Editor from './components/Editor.vue'
|
import Editor from './components/Editor.vue'
|
||||||
|
|
||||||
console.log("[App.vue]", `Hello world from Electron ${process.versions.electron}!`)
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -18,11 +17,39 @@
|
|||||||
column: 1,
|
column: 1,
|
||||||
language: "plaintext",
|
language: "plaintext",
|
||||||
languageAuto: true,
|
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: {
|
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) {
|
onCursorChange(e) {
|
||||||
//console.log("onCursorChange:", e)
|
//console.log("onCursorChange:", e)
|
||||||
this.line = e.cursorLine.line
|
this.line = e.cursorLine.line
|
||||||
@ -47,7 +74,8 @@
|
|||||||
:language="language"
|
:language="language"
|
||||||
:languageAuto="languageAuto"
|
:languageAuto="languageAuto"
|
||||||
:theme="theme"
|
:theme="theme"
|
||||||
@toggleTheme="theme = theme === 'dark' ? 'light' : 'dark'"
|
:systemTheme="systemTheme"
|
||||||
|
@toggleTheme="toggleTheme"
|
||||||
class="status"
|
class="status"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
"language",
|
"language",
|
||||||
"languageAuto",
|
"languageAuto",
|
||||||
"theme",
|
"theme",
|
||||||
|
"systemTheme",
|
||||||
],
|
],
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -44,11 +45,13 @@
|
|||||||
Col <span class="num">{{ column }}</span>
|
Col <span class="num">{{ column }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<div class="status-block theme clickable" @click="$emit('toggleTheme')">{{ theme }}</div>
|
|
||||||
<div class="status-block lang clickable">
|
<div class="status-block lang clickable">
|
||||||
{{ languageName }}
|
{{ languageName }}
|
||||||
<span v-if="languageAuto" class="auto">(auto)</span>
|
<span v-if="languageAuto" class="auto">(auto)</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="status-block theme clickable" @click="$emit('toggleTheme')">
|
||||||
|
<span :class="'icon ' + systemTheme"></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -76,23 +79,45 @@
|
|||||||
color: rgba(255, 255, 255, 0.75)
|
color: rgba(255, 255, 255, 0.75)
|
||||||
.status-block.lang .auto
|
.status-block.lang .auto
|
||||||
color: rgba(255, 255, 255, 0.55)
|
color: rgba(255, 255, 255, 0.55)
|
||||||
|
.theme .icon
|
||||||
|
opacity: 0.9
|
||||||
|
|
||||||
.spacer
|
.spacer
|
||||||
flex-grow: 1
|
flex-grow: 1
|
||||||
|
|
||||||
.status-block
|
.status-block
|
||||||
padding: 2px 12px
|
padding: 2px 10px
|
||||||
cursor: default
|
cursor: default
|
||||||
|
&:first-child
|
||||||
|
padding-left: 12px
|
||||||
|
&:last-child
|
||||||
|
padding-right: 12px
|
||||||
&.clickable
|
&.clickable
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
&:hover
|
&:hover
|
||||||
background: rgba(255,255,255, 0.1)
|
background-color: rgba(255,255,255, 0.1)
|
||||||
&.line-number
|
.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)
|
color: rgba(255, 255, 255, 0.7)
|
||||||
.num
|
.theme
|
||||||
color: rgba(255, 255, 255, 1.0)
|
padding-top: 0
|
||||||
&.lang
|
padding-bottom: 0
|
||||||
.auto
|
.icon
|
||||||
color: rgba(255, 255, 255, 0.7)
|
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>
|
</style>
|
||||||
|
@ -24,7 +24,7 @@ export class HeynoteEditor {
|
|||||||
//minimalSetup,
|
//minimalSetup,
|
||||||
customSetup,
|
customSetup,
|
||||||
|
|
||||||
this.theme.of("dark" ? heynoteDark : heynoteLight),
|
this.theme.of(theme === "dark" ? heynoteDark : heynoteLight),
|
||||||
heynoteBase,
|
heynoteBase,
|
||||||
indentUnit.of(" "),
|
indentUnit.of(" "),
|
||||||
EditorView.scrollMargins.of(f => {
|
EditorView.scrollMargins.of(f => {
|
||||||
|
Loading…
Reference in New Issue
Block a user