Das Schach-Plugin ist ein einfaches Beispiel dafür, wie leicht eine Erweiterung mit Echtzeit-Kollaboration für Briefing erstellt werden kann. Der vollständige Quellcode ist unter TODO verfügbar.
index-client.ts
Die Klasse AppPlugin
ist der Einstiegspunkt. Zuerst muss ein unbenutzter name
vergeben werden. In der setup
Methode steht ein AppPluginContext
zur Verfügung, der alle weiteren Einstiegspunkte der Applikation enthält, um Funktionalität an bestimmten Stellen hinzuzufügen. Im folgenden Beispiel wird eine Vue-Komponente für den Präsentationsbereich registriert.
import type { AppPlugin, AppPluginContext } from '@briefing/_types/plugin'
import { defineAsyncComponent } from 'vue'
import { pluginName } from './_types'
class Plugin implements AppPlugin {
name = pluginName
async setup(context: AppPluginContext): Promise<void> {
context.addComponent({
name: pluginName,
title: 'Chess',
placement: 'presentation',
component: defineAsyncComponent(() => import('./components/chess.vue')) as any,
})
}
}
export default Plugin
Vue Component
Der AppGlobalContext
steht jeder Komponente über inject
zur Verfügung. Realtime Sync ist ebenfalls ein Plugin, das seine Funktionalität über state
anderen Plugins zur Verfügung stellt. appState.sync.getMO(pluginName, state).value
registriert ein einfaches Sync-Objekt, das nur Records aber keine Arrays unterstützt (LWW CRDT). Dieses kann nun ganz normal als Vue reactive
verwendet werden. Alle Änderungen werden automatisch und ohne weiteres Zutun mit allen anderen Clients im Raum geteilt. Neben diesen Managed Object (MO) steht auch eine Unterstützung von Yjs zur Verfügung, die z.B. in den Präsentationen Zeichenen und TipTap verwendet wird.
<script setup lang="ts">
import { pluginName } from '@/_types'
import type { AppGlobalContext } from '@briefing/_types/plugin'
import { inject, ref, watch } from 'vue'
import { BoardApi, BoardConfig, Move, TheChessboard } from '@/chessboard'
import { Logger, LoggerInterface } from "zeed"
import './chess.styl'
type ChessState = Record<number, Move>
let state: ChessState = {}
try {
const app = inject<AppGlobalContext>('app')
if (app) {
const appState = app.state as any
state = appState.sync.getMO(pluginName, state).value
}
}
catch (err) {
log.warn('chess err', err)
}
let ctr = 0
const boardConfig: BoardConfig = {
events: {
move: (from, to, capture) => {
state[ctr++] = { from, to }
},
},
}
let boardAPI: BoardApi
watch(() => Object.keys(state), (l) => {
while(state[ctr]) {
boardAPI?.move(state[ctr++])
}
})
</script>
<template>
<div class="chess">
<TheChessboard @board-created="(api: any) => (boardAPI = api)" :board-config="boardConfig" />
</div>
</template>