@selenite/graph-editor
Version:
A graph editor for visual programming, based on rete and svelte.
125 lines (124 loc) • 4.24 kB
JavaScript
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);
}
}