UNPKG

@selenite/graph-editor

Version:

A graph editor for visual programming, based on rete and svelte.

125 lines (124 loc) 4.24 kB
import { persisted } from '@selenite/commons'; import { GitHubDataSource } from './datasources'; import { IndexedDBSource } from './db.svelte'; import { FavoritesManager } from './FavoritesManager.svelte'; import { get } from 'svelte/store'; import { debounce } from 'lodash-es'; import { untrack } from 'svelte'; export const userStore = persisted('user', ''); export class NodeStorage { static pullDataSourcesInterval = 5000; static mainStorage = new IndexedDBSource(); static sources = [ new GitHubDataSource('https://github.com/Selenite-GEOS/macro-blocks/tree/main/macro-blocks') ]; static #instance; static get instance() { if (!NodeStorage.#instance) { NodeStorage.#instance = new NodeStorage(); } return NodeStorage.#instance; } numGraphs = $state(0); graphs = $state([]); static get macroblocks() { return NodeStorage.instance.graphs; } data = $state({ tags: [], favorites: [], paths: [], userBlocks: [] }); updateData = debounce(() => { console.debug('Deriving data'); const paths = []; const tags = new Set(); const favorites = []; const user = get(userStore); const userBlocks = []; for (const graph of this.graphs) { for (const tag of graph.tags ?? []) tags.add(tag); if (FavoritesManager.isFavorite(graph.id)) favorites.push(graph); if (graph.path) paths.push(graph.path); if (user && graph.author === user) userBlocks.push(graph); } NodeStorage.instance.data = { paths, favorites, tags: Array.from(tags), userBlocks }; }, 10); static get favorites() { return NodeStorage.instance.data.favorites; } static get tags() { return NodeStorage.instance.data.tags; } static get userBlocks() { return NodeStorage.instance.data.userBlocks; } static get paths() { return NodeStorage.instance.data.paths; } static get data() { return NodeStorage.instance.data; } constructor() { const { unsubscribe } = NodeStorage.mainStorage.numGraphs.subscribe((num) => { this.numGraphs = num; }); const favoritesManager = FavoritesManager.instance; userStore.subscribe(() => { this.updateData(); }); $effect.root(() => { $effect(() => { favoritesManager.favorites; untrack(() => { this.updateData(); }); }); }); NodeStorage.mainStorage.graphs.subscribe((graphs) => { console.debug('Update macro blocks'); this.graphs = graphs; this.updateData(); }); NodeStorage.updateLoop(); if (import.meta.hot) { import.meta.hot.on('vite:beforeUpdate', () => { // unsubscribe(); clearTimeout(NodeStorage.updateTimeout); }); } console.debug('Setting up NodeStorage.'); } static updateTimeout; static async updateLoop() { await NodeStorage.pullSources(); NodeStorage.updateTimeout = setTimeout(NodeStorage.updateLoop, NodeStorage.pullDataSourcesInterval); } static get numGraphs() { return NodeStorage.instance.numGraphs; } static get graphs() { return NodeStorage.instance.graphs; } static getGraphs() { return NodeStorage.mainStorage.getGraphs(); } static getGraph(id) { return NodeStorage.mainStorage.getGraph(id); } static saveGraph(graph) { return NodeStorage.mainStorage.saveGraph(graph); } static clearGraphs() { return NodeStorage.mainStorage.clearGraphs(); } static deleteMacro(id) { return NodeStorage.mainStorage.deleteMacro(id); } static async pullSources() { // console.debug('Pulling sources'); const res = (await Promise.all(NodeStorage.sources.map((source) => source.getGraphs()))).flat(); NodeStorage.mainStorage.saveGraphs(res); // console.debug('Pulled sources', res); } }