Preferences WIP
This commit is contained in:
@@ -143,6 +143,11 @@ app.whenReady().then(async () => {
|
|||||||
ipcMain.on("open-note-window", (_, noteId) => {
|
ipcMain.on("open-note-window", (_, noteId) => {
|
||||||
createNoteWindow(noteId);
|
createNoteWindow(noteId);
|
||||||
});
|
});
|
||||||
|
const broadcastNoteChange = (event, data) => {
|
||||||
|
BrowserWindow.getAllWindows().forEach((win) => {
|
||||||
|
win.webContents.send(event, data);
|
||||||
|
});
|
||||||
|
};
|
||||||
const registry = new PluginRegistry();
|
const registry = new PluginRegistry();
|
||||||
registry.register(filesystemPlugin);
|
registry.register(filesystemPlugin);
|
||||||
registry.register(supabasePlugin);
|
registry.register(supabasePlugin);
|
||||||
@@ -162,6 +167,8 @@ app.whenReady().then(async () => {
|
|||||||
}
|
}
|
||||||
return await adapter[method](...args);
|
return await adapter[method](...args);
|
||||||
});
|
});
|
||||||
|
broadcastNoteChange("plugin-changed", pluginId);
|
||||||
|
console.log("activePlugin: ", pluginId);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
await setActivePlugin(initialConfig.activeAdapter);
|
await setActivePlugin(initialConfig.activeAdapter);
|
||||||
@@ -177,11 +184,6 @@ app.whenReady().then(async () => {
|
|||||||
ipcMain.handle("setActivePlugin", async (_, pluginId) => {
|
ipcMain.handle("setActivePlugin", async (_, pluginId) => {
|
||||||
return await setActivePlugin(pluginId);
|
return await setActivePlugin(pluginId);
|
||||||
});
|
});
|
||||||
const broadcastNoteChange = (event, data) => {
|
|
||||||
BrowserWindow.getAllWindows().forEach((win) => {
|
|
||||||
win.webContents.send(event, data);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
ipcMain.on("note-changed", (_, event, data) => {
|
ipcMain.on("note-changed", (_, event, data) => {
|
||||||
broadcastNoteChange(event, data);
|
broadcastNoteChange(event, data);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ const api = {
|
|||||||
onNoteDeleted: (callback) => {
|
onNoteDeleted: (callback) => {
|
||||||
ipcRenderer.on("note-deleted", (_, data) => callback(data));
|
ipcRenderer.on("note-deleted", (_, data) => callback(data));
|
||||||
},
|
},
|
||||||
|
onPluginChanged: (callback) => {
|
||||||
|
ipcRenderer.on("plugin-changed", (_, data) => callback(data));
|
||||||
|
},
|
||||||
notifyNoteChanged: (event, data) => {
|
notifyNoteChanged: (event, data) => {
|
||||||
ipcRenderer.send("note-changed", event, data);
|
ipcRenderer.send("note-changed", event, data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,13 @@ app.whenReady().then(async () => {
|
|||||||
createNoteWindow(noteId)
|
createNoteWindow(noteId)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Broadcast note changes to all windows
|
||||||
|
const broadcastNoteChange = (event, data) => {
|
||||||
|
BrowserWindow.getAllWindows().forEach((win) => {
|
||||||
|
win.webContents.send(event, data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Create plugin registry
|
// Create plugin registry
|
||||||
const registry = new PluginRegistry()
|
const registry = new PluginRegistry()
|
||||||
|
|
||||||
@@ -102,6 +109,8 @@ app.whenReady().then(async () => {
|
|||||||
return await adapter[method](...args)
|
return await adapter[method](...args)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
broadcastNoteChange('plugin-changed', pluginId)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,13 +133,6 @@ app.whenReady().then(async () => {
|
|||||||
return await setActivePlugin(pluginId)
|
return await setActivePlugin(pluginId)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Broadcast note changes to all windows
|
|
||||||
const broadcastNoteChange = (event, data) => {
|
|
||||||
BrowserWindow.getAllWindows().forEach((win) => {
|
|
||||||
win.webContents.send(event, data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle note change events from renderer
|
// Handle note change events from renderer
|
||||||
ipcMain.on('note-changed', (_, event, data) => {
|
ipcMain.on('note-changed', (_, event, data) => {
|
||||||
broadcastNoteChange(event, data)
|
broadcastNoteChange(event, data)
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ const api = {
|
|||||||
onNoteDeleted: (callback) => {
|
onNoteDeleted: (callback) => {
|
||||||
ipcRenderer.on('note-deleted', (_, data) => callback(data))
|
ipcRenderer.on('note-deleted', (_, data) => callback(data))
|
||||||
},
|
},
|
||||||
|
onPluginChanged: (callback) => {
|
||||||
|
ipcRenderer.on('plugin-changed', (_, data) => callback(data))
|
||||||
|
},
|
||||||
notifyNoteChanged: (event, data) => {
|
notifyNoteChanged: (event, data) => {
|
||||||
ipcRenderer.send('note-changed', event, data)
|
ipcRenderer.send('note-changed', event, data)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
<div :class="classes" :style="styles">
|
<div :class="classes" :style="styles">
|
||||||
<Nav />
|
<Nav />
|
||||||
|
|
||||||
<router-view :key="$route.fullPath" />
|
<Suspense>
|
||||||
|
<router-view :key="$route.fullPath" />
|
||||||
|
</Suspense>
|
||||||
|
|
||||||
<Menu />
|
<Menu />
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,18 @@
|
|||||||
|
|
||||||
<div class="menu-wrap layout-block">
|
<div class="menu-wrap layout-block">
|
||||||
<new-note class="menu-item" @noteOpened="closeMenu" />
|
<new-note class="menu-item" @noteOpened="closeMenu" />
|
||||||
<router-link class="menu-item" to="/category"
|
<router-link class="menu-item" to="/category">
|
||||||
>+ New Capitulum</router-link
|
+ New Capitulum
|
||||||
>
|
</router-link>
|
||||||
<theme-switcher class="menu-item" />
|
<theme-switcher class="menu-item" />
|
||||||
<router-link class="menu-item" to="/instructions"
|
<router-link class="menu-item" to="/instructions">
|
||||||
>Instructio</router-link
|
Instructio
|
||||||
>
|
</router-link>
|
||||||
<button class="menu-item">Import</button>
|
<button class="menu-item">Import</button>
|
||||||
<button class="menu-item">Export</button>
|
<button class="menu-item">Export</button>
|
||||||
|
<router-link class="menu-item" to="/preferences">
|
||||||
|
Preferences
|
||||||
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|||||||
@@ -29,8 +29,14 @@ export default () => {
|
|||||||
return configPromise
|
return configPromise
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const refreshConfig = async () => {
|
||||||
|
config.value = await window.api.getConfig()
|
||||||
|
configResolve()
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
config,
|
config,
|
||||||
ensureConfig,
|
ensureConfig,
|
||||||
|
refreshConfig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ const setupListeners = () => {
|
|||||||
|
|
||||||
window.api.onNoteCreated(updateCacheCount)
|
window.api.onNoteCreated(updateCacheCount)
|
||||||
window.api.onNoteUpdated(updateCacheCount)
|
window.api.onNoteUpdated(updateCacheCount)
|
||||||
|
window.api.onPluginChanged(async () => {
|
||||||
|
const api = await getNotesAPI()
|
||||||
|
await api.init()
|
||||||
|
|
||||||
|
notesChangeCount.value++
|
||||||
|
})
|
||||||
|
|
||||||
// Todo update cache
|
// Todo update cache
|
||||||
window.api.onNoteDeleted(() => {
|
window.api.onNoteDeleted(() => {
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import { ref, onMounted } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
import useConfig from './useConfig'
|
||||||
|
|
||||||
|
export default async () => {
|
||||||
|
const { refreshConfig } = useConfig()
|
||||||
|
|
||||||
export default () => {
|
|
||||||
const plugins = ref([])
|
const plugins = ref([])
|
||||||
|
|
||||||
onMounted(async () => {
|
plugins.value = await window.api.listPlugins()
|
||||||
plugins.value = await window.api.listPlugins()
|
|
||||||
})
|
|
||||||
|
|
||||||
const setActivePlugin = async (pluginId) => {
|
const setActivePlugin = async (pluginId) => {
|
||||||
await window.api.setActivePlugin(pluginId)
|
await window.api.setActivePlugin(pluginId)
|
||||||
|
await refreshConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ export default class NotesAPI {
|
|||||||
async init() {
|
async init() {
|
||||||
await this._initSodium()
|
await this._initSodium()
|
||||||
await this.adapter.init()
|
await this.adapter.init()
|
||||||
|
this.notesCache.clear()
|
||||||
|
|
||||||
const encryptedNotes = await this.adapter.getAll()
|
const encryptedNotes = await this.adapter.getAll()
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import IpcAdapter from '@/libs/core/IpcAdapter.js'
|
|||||||
import useConfig from '@/composables/useConfig.js'
|
import useConfig from '@/composables/useConfig.js'
|
||||||
|
|
||||||
// Singleton pattern to make sure only one instance of NotesAPI exists
|
// Singleton pattern to make sure only one instance of NotesAPI exists
|
||||||
|
|
||||||
let notesAPI = null
|
let notesAPI = null
|
||||||
let initPromise = null
|
let initPromise = null
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import CreateCategory from '@/views/CreateCategory.vue'
|
|||||||
import Category from '@/views/Category.vue'
|
import Category from '@/views/Category.vue'
|
||||||
import Instructions from '@/views/Instructions.vue'
|
import Instructions from '@/views/Instructions.vue'
|
||||||
import Search from '@/views/Search.vue'
|
import Search from '@/views/Search.vue'
|
||||||
|
import Preferences from '@/views/Preferences.vue'
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{ path: '/', name: 'directory', component: Directory },
|
{ path: '/', name: 'directory', component: Directory },
|
||||||
@@ -14,6 +15,7 @@ const routes = [
|
|||||||
{ path: '/category/:id', name: 'category', component: Category },
|
{ path: '/category/:id', name: 'category', component: Category },
|
||||||
{ path: '/instructions', name: 'instructions', component: Instructions },
|
{ path: '/instructions', name: 'instructions', component: Instructions },
|
||||||
{ path: '/search', name: 'search', component: Search },
|
{ path: '/search', name: 'search', component: Search },
|
||||||
|
{ path: '/preferences', name: 'preferences', component: Preferences },
|
||||||
]
|
]
|
||||||
|
|
||||||
export const router = createRouter({
|
export const router = createRouter({
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ a,
|
|||||||
button,
|
button,
|
||||||
input,
|
input,
|
||||||
pre,
|
pre,
|
||||||
span {
|
span,
|
||||||
|
label,
|
||||||
|
li {
|
||||||
@include p;
|
@include p;
|
||||||
}
|
}
|
||||||
.bold {
|
.bold {
|
||||||
|
|||||||
@@ -12,17 +12,6 @@
|
|||||||
<div class="notes">
|
<div class="notes">
|
||||||
<note-row v-for="note in notes" :note="note" :key="note.id" />
|
<note-row v-for="note in notes" :note="note" :key="note.id" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-for="plugin in plugins" :key="plugin.id">
|
|
||||||
<input
|
|
||||||
v-model="activePlugin"
|
|
||||||
type="radio"
|
|
||||||
name="plugins"
|
|
||||||
:value="plugin.id"
|
|
||||||
:id="plugin.id"
|
|
||||||
/>
|
|
||||||
<label :for="plugin.id">{{ plugin.name }}</label>
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -38,9 +27,6 @@ const { categories, loadCategories, loadCategoryNotes, notesChangeCount } =
|
|||||||
useNotes()
|
useNotes()
|
||||||
|
|
||||||
const { config } = useConfig()
|
const { config } = useConfig()
|
||||||
const { plugins, setActivePlugin } = usePlugins()
|
|
||||||
|
|
||||||
const activePlugin = ref(config.value?.activeAdapter)
|
|
||||||
|
|
||||||
const notes = ref()
|
const notes = ref()
|
||||||
|
|
||||||
@@ -56,10 +42,6 @@ onMounted(async () => {
|
|||||||
watch(notesChangeCount, async () => {
|
watch(notesChangeCount, async () => {
|
||||||
await refreshNotes()
|
await refreshNotes()
|
||||||
})
|
})
|
||||||
watch(activePlugin, async (pluginId) => {
|
|
||||||
await setActivePlugin(pluginId)
|
|
||||||
await refreshNotes()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@@ -67,18 +49,6 @@ main.directory {
|
|||||||
padding-top: 18px;
|
padding-top: 18px;
|
||||||
padding-bottom: 30px;
|
padding-bottom: 30px;
|
||||||
|
|
||||||
input[type='radio'] {
|
|
||||||
display: block;
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
margin-right: 10px;
|
|
||||||
border: 1px solid white;
|
|
||||||
|
|
||||||
&:checked {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin: 17px 0 24px;
|
margin: 17px 0 24px;
|
||||||
|
|||||||
86
src/renderer/src/views/Preferences.vue
Normal file
86
src/renderer/src/views/Preferences.vue
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<template>
|
||||||
|
<main class="preferences layout-block">
|
||||||
|
<router-link to="/" class="back"><- Back</router-link>
|
||||||
|
|
||||||
|
<h1 class="mono">Storage Plugin</h1>
|
||||||
|
|
||||||
|
<div v-for="plugin in plugins" class="plugin" :key="plugin.id">
|
||||||
|
<input
|
||||||
|
v-model="activePluginId"
|
||||||
|
name="plugins"
|
||||||
|
type="radio"
|
||||||
|
:id="plugin.id"
|
||||||
|
:value="plugin.id"
|
||||||
|
/>
|
||||||
|
<label :for="plugin.id">
|
||||||
|
<p class="name bold">{{ plugin.name }}</p>
|
||||||
|
<p class="description">{{ plugin.description }}</p>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import usePlugins from '@/composables/usePlugins'
|
||||||
|
import useConfig from '@/composables/useConfig'
|
||||||
|
import { ref, onMounted, watch } from 'vue'
|
||||||
|
|
||||||
|
const { plugins, setActivePlugin } = await usePlugins()
|
||||||
|
const { config, ensureConfig } = useConfig()
|
||||||
|
|
||||||
|
const activePluginId = ref(plugins.value[0].id)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await ensureConfig()
|
||||||
|
activePluginId.value = config.value.activeAdapter
|
||||||
|
|
||||||
|
watch(activePluginId, async (id) => {
|
||||||
|
await setActivePlugin(id)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.preferences {
|
||||||
|
padding-top: 8px;
|
||||||
|
|
||||||
|
.back {
|
||||||
|
opacity: 0.25;
|
||||||
|
display: block;
|
||||||
|
margin-top: 9px;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='radio'] {
|
||||||
|
display: block;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
border: 1px solid white;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:checked {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.description {
|
||||||
|
color: var(--grey-100);
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||||
import useNotes from '@/composables/useNotes'
|
import useNotes from '@/composables/useNotes'
|
||||||
import NoteRow from '@/components/NoteRow.vue'
|
import NoteRow from '@/components/NoteRow.vue'
|
||||||
import _debounce from 'lodash/debounce'
|
import _debounce from 'lodash/debounce'
|
||||||
@@ -39,6 +39,10 @@ onMounted(async () => {
|
|||||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||||
searchInput.value?.focus()
|
searchInput.value?.focus()
|
||||||
})
|
})
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
query.value = ''
|
||||||
|
searchResults.value = []
|
||||||
|
})
|
||||||
|
|
||||||
const onSearch = async () => {
|
const onSearch = async () => {
|
||||||
await search(query.value)
|
await search(query.value)
|
||||||
|
|||||||
Reference in New Issue
Block a user