mirror of
https://github.com/autismjs/monorepo.git
synced 2026-01-09 17:17:55 -05:00
add basic observables
This commit is contained in:
@@ -56,7 +56,7 @@ export type Subscription<ValueType = any> =
|
||||
}
|
||||
| ((value: ValueType) => void);
|
||||
|
||||
export class Observables<ObservableValue = any> {
|
||||
export class Observable<ObservableValue = any> {
|
||||
#state: ObservableValue;
|
||||
#error: Error | null = null;
|
||||
#subscriptions: Subscription[] = [];
|
||||
@@ -114,3 +114,20 @@ export class Observables<ObservableValue = any> {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class ObservableMap<keyType = string, ValueType = any> {
|
||||
#map: Map<keyType, Observable<ValueType | null>> = new Map();
|
||||
|
||||
get(key: keyType) {
|
||||
const exist = this.#map.get(key);
|
||||
if (!exist) {
|
||||
this.#map.set(key, new Observable(null));
|
||||
}
|
||||
return this.#map.get(key);
|
||||
}
|
||||
|
||||
set(key: keyType, value: ValueType) {
|
||||
const post = this.get(key)!;
|
||||
post.state = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,10 +36,10 @@ export const Q = (root: ShadowRoot | Element) => {
|
||||
renderFn: (data: any) => Element | DocumentFragment,
|
||||
) => void;
|
||||
} => {
|
||||
const list = Array.prototype.map.call(
|
||||
const list: any[] = Array.prototype.map.call(
|
||||
root.querySelectorAll(str),
|
||||
E,
|
||||
) as Element[];
|
||||
);
|
||||
|
||||
// @ts-ignore
|
||||
list.patch = (
|
||||
@@ -58,8 +58,8 @@ export const Q = (root: ShadowRoot | Element) => {
|
||||
root.append(renderFn(data));
|
||||
} else if (last && !data) {
|
||||
root.removeChild(last);
|
||||
} else if (lastKey !== currKey) {
|
||||
root.replaceChild(renderFn(data), last);
|
||||
} else if (last && lastKey !== currKey) {
|
||||
root.replaceChild(renderFn(data), last.el);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -74,6 +74,7 @@ const E = (el: Element | null) => {
|
||||
if (!el) return el;
|
||||
|
||||
return {
|
||||
el: el,
|
||||
content: (content: string) => {
|
||||
el.textContent = content;
|
||||
return el;
|
||||
|
||||
@@ -19,14 +19,21 @@ export default class Post extends CustomElement {
|
||||
|
||||
async connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.loadPost();
|
||||
}
|
||||
|
||||
async loadPost() {
|
||||
const store = getStore();
|
||||
const node = store.get<NodeStore>('node');
|
||||
const hash = this.dataset.hash!;
|
||||
const post = await node.getPost(hash);
|
||||
const post = await node.$posts.get(hash);
|
||||
const q = Q(this.shadowRoot!);
|
||||
q.find('div#creator')!.content(post?.json.creator || '');
|
||||
q.find('div#content')!.content(post?.json.content || '');
|
||||
q.find('div#createdAt')!.content(post?.json.createdAt.toDateString() || '');
|
||||
|
||||
post!.subscribe((p) => {
|
||||
q.find('div#creator')!.content(p.json.creator || '');
|
||||
q.find('div#content')!.content(p.json.content || '');
|
||||
q.find('div#createdAt')!.content(p.json.createdAt.toDateString() || '');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,21 +20,25 @@ export default class App extends CustomElement {
|
||||
|
||||
async connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.subscribeToPosts();
|
||||
}
|
||||
|
||||
subscribeToPosts() {
|
||||
const state = getStore();
|
||||
const node = state.get<NodeState>('node');
|
||||
const app = this.shadowRoot!.querySelector('div.app')!;
|
||||
const q = Q(app);
|
||||
|
||||
node.posts.subscribe<PostType[]>((posts) => {
|
||||
node.$globalPosts.subscribe<string[]>((hashes) => {
|
||||
const app = this.shadowRoot!.querySelector('div.app')!;
|
||||
const q = Q(app);
|
||||
const old = q.findAll('post-card');
|
||||
|
||||
old.patch(
|
||||
posts,
|
||||
(post: PostType) => post.messageId,
|
||||
(post: PostType) =>
|
||||
hashes,
|
||||
(hash: string) => hash,
|
||||
(hash: string) =>
|
||||
html(`
|
||||
<post-card
|
||||
key="${post.messageId}"
|
||||
data-hash="${post.hash}"
|
||||
key="${hash}"
|
||||
data-hash="${hash}"
|
||||
/>
|
||||
`),
|
||||
);
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import Store, { Observables, type StateOptions } from '../../lib/state.ts';
|
||||
import Store, {
|
||||
ObservableMap,
|
||||
Observable,
|
||||
type StateOptions,
|
||||
} from '../../lib/state.ts';
|
||||
import { Autism } from '@autismjs/protocol/src/services/browser.ts';
|
||||
import { Post } from '@autismjs/message';
|
||||
|
||||
export default class Node extends Store {
|
||||
node: Autism;
|
||||
wait: Promise<void>;
|
||||
posts = new Observables<Post[]>([]);
|
||||
#wait: Promise<void>;
|
||||
|
||||
$globalPosts = new Observable<string[]>([]);
|
||||
$posts = new ObservableMap<string, Post>();
|
||||
|
||||
constructor(options?: StateOptions) {
|
||||
super(options);
|
||||
@@ -33,15 +39,23 @@ export default class Node extends Store {
|
||||
|
||||
this.updatePosts();
|
||||
|
||||
this.wait = new Promise(async (r) => {
|
||||
this.#wait = new Promise(async (r) => {
|
||||
await this.node.start();
|
||||
this.updatePosts();
|
||||
r();
|
||||
});
|
||||
}
|
||||
|
||||
async waitForStart() {
|
||||
return this.#wait;
|
||||
}
|
||||
|
||||
updatePosts = async () => {
|
||||
this.posts.state = await this.node.db.db.getPosts();
|
||||
const posts = await this.node.db.db.getPosts();
|
||||
this.$globalPosts.state = posts.map((p) => {
|
||||
this.$posts.set(p.hash, p);
|
||||
return p.hash;
|
||||
});
|
||||
};
|
||||
|
||||
getPost = async (hash: string): Promise<Post | null> => {
|
||||
|
||||
Reference in New Issue
Block a user