Create a Custom Module
This guide teaches you how to create a new data module for OpenTree.
1. Define the Data Model
// packages/main/src/database/models/Mood.ts
import { DataTypes, Model } from 'sequelize'
export class Mood extends Model {
id!: string
mood!: string // 😊 😢 😡
note?: string
date!: string
}
Mood.init({
id: { type: DataTypes.UUID, primaryKey: true, defaultValue: DataTypes.UUIDV4 },
mood: { type: DataTypes.STRING, allowNull: false },
note: { type: DataTypes.TEXT },
date: { type: DataTypes.DATEONLY, allowNull: false },
}, { tableName: 'moods', sequelize })
2. Register IPC Handlers
// packages/main/src/ipc/mood.ts
import { ipcMain } from 'electron'
import { Mood } from '../database/models/Mood'
export function registerMoodIpc() {
ipcMain.handle('mood-get-all', async () => {
return await Mood.findAll({ order: [['date', 'DESC']] })
})
ipcMain.handle('mood-create', async (_, data) => {
return await Mood.create(data)
})
ipcMain.handle('mood-update', async (_, id, data) => {
await Mood.update(data, { where: { id } })
return await Mood.findByPk(id)
})
ipcMain.handle('mood-delete', async (_, id) => {
return await Mood.destroy({ where: { id } })
})
}
3. Expose to Renderer Process
// packages/main/src/preload.ts
contextBridge.exposeInMainWorld('electronAPI', {
// ... existing modules
mood: {
getAll: () => ipcRenderer.invoke('mood-get-all'),
create: (data) => ipcRenderer.invoke('mood-create', data),
update: (id, data) => ipcRenderer.invoke('mood-update', id, data),
remove: (id) => ipcRenderer.invoke('mood-delete', id),
},
})
4. Integrate in Metaverse
// static/metaverse-v2/app.js
// Add to getWtElectronAPI
mood: {
getAll: () => ipc.invoke('mood-get-all'),
create: (data) => ipc.invoke('mood-create', data),
update: (id, data) => ipc.invoke('mood-update', id, data),
remove: (id) => ipc.invoke('mood-delete', id),
},
// Add render function
async function renderMoodModule(body, title) {
title.textContent = '😊 Mood'
const api = getWtElectronAPI()
const items = await api.mood.getAll()
body.innerHTML = ''
// Render list...
}
5. Add Floating Button
<!-- index.html -->
<button class="float-btn mod-btn" data-mod="mood" title="Mood (J)">
<span class="btn-icon">😊</span>
<span class="btn-label">Mood</span>
</button>
6. Bind Keyboard Shortcut
// app.js
else if (key === 'j') openMod('mood')
7. Connect to renderModule
} else if (id === 'mood') {
renderMoodModule(body, title)
}
Done!
Your custom module is now available in both the World Tree and Metaverse!