mirror of
https://github.com/autismjs/monorepo.git
synced 2026-01-09 17:17:55 -05:00
updating post
This commit is contained in:
@@ -60,17 +60,22 @@ export class Observable<ObservableValue = any> {
|
||||
}
|
||||
}
|
||||
|
||||
subscribe = (subscription: Subscription<ObservableValue>) => {
|
||||
subscribe = (
|
||||
subscription: Subscription<ObservableValue>,
|
||||
leading = false,
|
||||
) => {
|
||||
const currIndex = this.#subscriptions.indexOf(subscription);
|
||||
|
||||
if (currIndex === -1) {
|
||||
this.#subscriptions.push(subscription);
|
||||
// const sub = subscription;
|
||||
// if (typeof sub === 'function') {
|
||||
// sub(this.$);
|
||||
// } else if (typeof sub !== 'function' && sub.next) {
|
||||
// sub.next(this.$);
|
||||
// }
|
||||
if (leading) {
|
||||
const sub = subscription;
|
||||
if (typeof sub === 'function') {
|
||||
sub(this.$);
|
||||
} else if (typeof sub !== 'function' && sub.next) {
|
||||
sub.next(this.$);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
|
||||
@@ -18,6 +18,10 @@ export class CustomElement extends HTMLElement implements ICustomElement {
|
||||
#mounted = false;
|
||||
#lastAttrUpdated = 0;
|
||||
#attrUpdateTimeout: any;
|
||||
|
||||
#lastPainted = 0;
|
||||
#paintTimeout: any;
|
||||
|
||||
$?: any;
|
||||
effects: any[][] = [];
|
||||
#selectors = new Map<string, Element>();
|
||||
@@ -45,8 +49,8 @@ export class CustomElement extends HTMLElement implements ICustomElement {
|
||||
return this.children[index];
|
||||
}
|
||||
|
||||
listen(store: Observable) {
|
||||
const cb = store.subscribe(this.#update);
|
||||
listen(store: Observable, leading = false) {
|
||||
const cb = store.subscribe(this.#update, leading);
|
||||
this.#unsubscribes.push(cb);
|
||||
}
|
||||
|
||||
@@ -66,7 +70,7 @@ export class CustomElement extends HTMLElement implements ICustomElement {
|
||||
return this.#selectors.get(selector);
|
||||
}
|
||||
|
||||
const el = this.shadowRoot.querySelector(selector);
|
||||
const el = this.shadowRoot!.querySelector(selector);
|
||||
|
||||
if (el) {
|
||||
this.#selectors.set(selector, el);
|
||||
@@ -103,15 +107,40 @@ export class CustomElement extends HTMLElement implements ICustomElement {
|
||||
};
|
||||
|
||||
#update = async () => {
|
||||
if (this.update) await this.update();
|
||||
this.unsubscribe();
|
||||
await this.#subscribe();
|
||||
const now = Date.now();
|
||||
|
||||
requestAnimationFrame(async () => {
|
||||
const timeSince = now - this.#lastPainted;
|
||||
const wait = 100;
|
||||
|
||||
const later = async () => {
|
||||
if (this.#paintTimeout) {
|
||||
clearTimeout(this.#paintTimeout);
|
||||
this.#paintTimeout = null;
|
||||
}
|
||||
this.#lastPainted = now;
|
||||
if (this.update) await this.update();
|
||||
this.unsubscribe();
|
||||
await this.#subscribe();
|
||||
};
|
||||
|
||||
if (timeSince > wait) {
|
||||
await later();
|
||||
} else {
|
||||
if (this.#paintTimeout) {
|
||||
clearTimeout(this.#paintTimeout);
|
||||
}
|
||||
this.#paintTimeout = setTimeout(later, Math.max(0, wait - timeSince));
|
||||
}
|
||||
|
||||
this.#lastPainted = now;
|
||||
});
|
||||
};
|
||||
|
||||
attributeChangedCallback(key: string, ov: string, nv: string) {
|
||||
if (nv === ov) return;
|
||||
|
||||
requestAnimationFrame(async () => {
|
||||
return requestAnimationFrame(async () => {
|
||||
const now = Date.now();
|
||||
const timeSince = now - this.#lastAttrUpdated;
|
||||
const wait = 100;
|
||||
@@ -137,6 +166,7 @@ export class CustomElement extends HTMLElement implements ICustomElement {
|
||||
Math.max(0, wait - timeSince),
|
||||
);
|
||||
}
|
||||
|
||||
this.#lastAttrUpdated = now;
|
||||
});
|
||||
}
|
||||
@@ -467,20 +497,17 @@ class UIRouter {
|
||||
this.$pathname.subscribe(this.update);
|
||||
}
|
||||
|
||||
#refreshPath = (evt?: any) => {
|
||||
console.log(evt?.type, evt);
|
||||
#refreshPath = () => {
|
||||
this.$pathname.$ = window.location.pathname;
|
||||
};
|
||||
|
||||
#init() {
|
||||
if (!this.#hasInit) {
|
||||
window.addEventListener('popstate', (evt) => {
|
||||
console.log('popstate');
|
||||
this.#refreshPath(evt);
|
||||
window.addEventListener('popstate', () => {
|
||||
this.#refreshPath();
|
||||
});
|
||||
window.addEventListener('DOMContentLoaded', (evt) => {
|
||||
console.log('DOMContentLoadedstate');
|
||||
this.#refreshPath(evt);
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
this.#refreshPath();
|
||||
});
|
||||
this.#hasInit = true;
|
||||
}
|
||||
|
||||
@@ -242,12 +242,11 @@ profile-image {
|
||||
--border-radius: .25rem;
|
||||
--opacity: .6;
|
||||
--color: var(--slate-400);
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: var(--text-base);
|
||||
height: var(--text-base);
|
||||
transition:
|
||||
filter 200ms ease-in-out;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
|
||||
@@ -5,7 +5,13 @@ import {
|
||||
h,
|
||||
register,
|
||||
} from '../../../lib/ui.ts';
|
||||
import { format, fromNow, userId, userName } from '../../utils/misc.ts';
|
||||
import {
|
||||
debounce,
|
||||
format,
|
||||
fromNow,
|
||||
userId,
|
||||
userName,
|
||||
} from '../../utils/misc.ts';
|
||||
import CommentIcon from '../../../static/icons/comment.svg';
|
||||
import RepostIcon from '../../../static/icons/repost.svg';
|
||||
import RepostSlate300Icon from '../../../static/icons/repost-slate-300.svg';
|
||||
@@ -37,31 +43,32 @@ export default class PostCard extends CustomElement {
|
||||
|
||||
async subscribe(): Promise<void> {
|
||||
this.listen($signer.$ecdsa);
|
||||
this.listen($editor.reference);
|
||||
|
||||
if (!this.state.hash) return;
|
||||
|
||||
const post = $node.$posts.get(this.state.hash);
|
||||
|
||||
this.listen(post);
|
||||
|
||||
if (post.$) {
|
||||
const user = $node.$users.get(post.$.creator);
|
||||
this.listen(user);
|
||||
}
|
||||
|
||||
this.listen(post);
|
||||
|
||||
const repost = $node.getRepostRef(this.state.hash);
|
||||
const tpostHash = repost?.$?.hash || this.state.hash;
|
||||
const tpost = $node.$posts.get(tpostHash);
|
||||
const messageId = tpost.$?.messageId;
|
||||
|
||||
if (!tpostHash || !messageId) return;
|
||||
$node.$replies.get(messageId).subscribe(this.update);
|
||||
$node.$posts.get(tpostHash).subscribe(this.update);
|
||||
$node.$postmetas.get(messageId).subscribe(this.update);
|
||||
|
||||
this.listen($node.$posts.get(tpostHash));
|
||||
this.listen($node.$postmetas.get(messageId));
|
||||
}
|
||||
|
||||
update = async () => {
|
||||
if (!this.shadowRoot) return;
|
||||
|
||||
const post = $node.getPost(this.state.hash);
|
||||
const repost =
|
||||
post?.subtype === PostSubtype.Repost && post.reference
|
||||
|
||||
@@ -30,7 +30,7 @@ export default class App extends CustomElement {
|
||||
hash,
|
||||
onclick: () => {
|
||||
const repost = $node.getRepostRef(hash);
|
||||
const newHash = repost?.hash || hash;
|
||||
const newHash = repost?.$?.hash || hash;
|
||||
const post = $node.getPost(newHash);
|
||||
const [creator, postHash] =
|
||||
$node.getPost(hash)!.messageId.split('/') || [];
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
boolAttr,
|
||||
connect,
|
||||
CustomElement,
|
||||
h,
|
||||
register,
|
||||
@@ -15,60 +14,107 @@ import { Observable } from '../../../lib/state.ts';
|
||||
import '../../components/Post';
|
||||
import '../../components/LeftSidebar';
|
||||
|
||||
// @connect(() => {
|
||||
// return {
|
||||
// pathname: Router.$pathname,
|
||||
// reference: $editor.reference,
|
||||
// };
|
||||
// })
|
||||
export default class PostView extends CustomElement {
|
||||
css = css.toString();
|
||||
|
||||
parents = new Observable<string[]>([]);
|
||||
|
||||
// async onupdated() {
|
||||
// const [, creator, , h] = Router.pathname.split('/');
|
||||
// const repost = $node.getRepostRef(h);
|
||||
// const messageId = !repost ? creator + '/' + h : repost.messageId;
|
||||
// const hash = repost?.hash || h;
|
||||
//
|
||||
// useEffect(
|
||||
// async () => {
|
||||
// // $node.$replies.get(messageId).subscribe(this._update);
|
||||
// // $node.$posts.get(hash).subscribe(this._update);
|
||||
// const parents = await $node.getParents(hash);
|
||||
// this.parents.$ = parents;
|
||||
// },
|
||||
// [hash, this.$.parents.$.join('+')],
|
||||
// this,
|
||||
// );
|
||||
// }
|
||||
|
||||
renderParents(): VNode {
|
||||
return h(
|
||||
'div.parents',
|
||||
...this.parents.$.map((parent: string) => {
|
||||
const [creator, hash] = parent.split('/');
|
||||
const parentHash = hash || creator;
|
||||
// @ts-ignore
|
||||
return h('post-card.parent', {
|
||||
...boolAttr('parent', true),
|
||||
hash: parentHash,
|
||||
onclick: () => {
|
||||
const url = `/${creator}/status/${hash}`;
|
||||
$editor.reference.$ = parent;
|
||||
$node.getReplies(parent);
|
||||
Router.go(url);
|
||||
},
|
||||
});
|
||||
}),
|
||||
);
|
||||
async onmount() {
|
||||
const [, , , h] = Router.pathname.split('/');
|
||||
const repost = $node.getRepostRef(h);
|
||||
const hash = repost?.$?.hash || h;
|
||||
this.parents.$ = await $node.getParents(hash);
|
||||
}
|
||||
|
||||
// async update(): Promise<void> {
|
||||
// const [, , , hash] = Router.pathname.split('/');
|
||||
// this.query('div.posts > post-card')!.setAttribute('hash', hash);
|
||||
// }
|
||||
async subscribe(): Promise<void> {
|
||||
const [, creator, , h] = Router.pathname.split('/');
|
||||
const repost = $node.getRepostRef(h);
|
||||
const messageId = !repost ? creator + '/' + h : repost?.$?.messageId;
|
||||
const hash = repost?.$?.hash || h;
|
||||
this.listen(this.parents);
|
||||
this.listen(Router.$pathname);
|
||||
this.listen($node.$posts.get(hash));
|
||||
|
||||
if (repost?.$) {
|
||||
this.listen($node.$posts.get(repost.$.hash));
|
||||
}
|
||||
if (messageId) {
|
||||
this.listen($node.$replies.get(messageId));
|
||||
}
|
||||
}
|
||||
|
||||
renderParents(): VNode[] {
|
||||
return this.parents.$.map((parent: string) => {
|
||||
const [creator, hash] = parent.split('/');
|
||||
const parentHash = hash || creator;
|
||||
// @ts-ignore
|
||||
return h('post-card.parent', {
|
||||
...boolAttr('parent', true),
|
||||
hash: parentHash,
|
||||
onclick: () => {
|
||||
const url = `/${creator}/status/${hash}`;
|
||||
$editor.reference.$ = parent;
|
||||
$node.getReplies(parent);
|
||||
Router.go(url);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async update(): Promise<void> {
|
||||
const [, , , hash] = Router.pathname.split('/');
|
||||
const [, , , h] = Router.pathname.split('/');
|
||||
const repost = $node.getRepostRef(h);
|
||||
this.parents.$ = await $node.getParents(repost?.$?.hash || h);
|
||||
this.query('div.posts > post-card')!.setAttribute('hash', hash);
|
||||
this.updateParents();
|
||||
this.updateReplies();
|
||||
}
|
||||
|
||||
updateReplies() {
|
||||
const oldReplies = Array.from(this.query('div.replies')!.children).slice();
|
||||
const newReplies = this.renderReplies().map((node) => node.createElement());
|
||||
|
||||
const maxlen = Math.max(oldReplies.length, newReplies.length);
|
||||
|
||||
for (let i = 0; i < maxlen; i++) {
|
||||
const oldEl = oldReplies[i];
|
||||
const newEl = newReplies[i]?.children[0];
|
||||
|
||||
if (!oldEl && newEl) {
|
||||
this.query('div.replies')!.append(newReplies[i]);
|
||||
} else if (oldEl && newEl) {
|
||||
if (oldEl.getAttribute('hash') !== newEl.getAttribute('hash')) {
|
||||
// oldEl.setAttribute('hash', newEl.getAttribute('hash') || '');
|
||||
oldEl.replaceWith(newReplies[i]);
|
||||
}
|
||||
} else if (oldEl && !newEl) {
|
||||
this.query('div.replies')!.removeChild(oldEl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateParents() {
|
||||
const oldParents = Array.from(this.query('div.parents')!.children).slice();
|
||||
const newParents = this.renderParents().map((node) => node.createElement());
|
||||
|
||||
const maxlen = Math.max(oldParents.length, newParents.length);
|
||||
|
||||
for (let i = 0; i < maxlen; i++) {
|
||||
const oldEl = oldParents[i];
|
||||
const newEl = newParents[i]?.children[0];
|
||||
|
||||
if (!oldEl && newEl) {
|
||||
this.query('div.parents')!.append(newParents[i]);
|
||||
} else if (oldEl && newEl) {
|
||||
if (oldEl.getAttribute('hash') !== newEl.getAttribute('hash')) {
|
||||
oldEl.setAttribute('hash', newEl.getAttribute('hash') || '');
|
||||
}
|
||||
} else if (oldEl && !newEl) {
|
||||
this.query('div.parents')!.removeChild(oldEl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const [, , , hash] = Router.pathname.split('/');
|
||||
@@ -78,41 +124,38 @@ export default class PostView extends CustomElement {
|
||||
h('left-sidebar'),
|
||||
h(
|
||||
'div.posts',
|
||||
// this.renderParents(),
|
||||
h('div.parents', this.renderParents()),
|
||||
h(`post-card`, {
|
||||
...boolAttr('comfortable', true),
|
||||
...boolAttr('displayparent', true),
|
||||
hash,
|
||||
}),
|
||||
// this.renderReplies(),
|
||||
h('div.replies', this.renderReplies()),
|
||||
h('div.posts__bottom'),
|
||||
),
|
||||
h('div.sidebar'),
|
||||
);
|
||||
}
|
||||
|
||||
renderReplies = () => {
|
||||
renderReplies = (): VNode[] => {
|
||||
const [, creator, , hash] = Router.pathname.split('/');
|
||||
const repost = $node.getRepostRef(hash);
|
||||
const messageId = repost ? repost.messageId : creator + '/' + hash;
|
||||
const replies = $node.getReplies(messageId);
|
||||
const messageId = repost ? repost.$?.messageId : creator + '/' + hash;
|
||||
const replies = $node.$replies.get(messageId!).$ || [];
|
||||
|
||||
return h(
|
||||
'div.replies',
|
||||
replies?.map((mid) => {
|
||||
const [c, _h] = mid.split('/');
|
||||
// @ts-ignore
|
||||
return h('post-card.reply', {
|
||||
hash: _h || c,
|
||||
onclick: () => {
|
||||
const url = c ? `/${c}/status/${_h}` : `/${_h}`;
|
||||
$editor.reference.$ = mid;
|
||||
$node.getReplies(mid);
|
||||
Router.go(url);
|
||||
},
|
||||
});
|
||||
}),
|
||||
);
|
||||
return replies.map((mid) => {
|
||||
const [c, _h] = mid.split('/');
|
||||
// @ts-ignore
|
||||
return h('post-card.reply', {
|
||||
hash: _h || c,
|
||||
onclick: () => {
|
||||
const url = c ? `/${c}/status/${_h}` : `/${_h}`;
|
||||
$editor.reference.$ = mid;
|
||||
$node.getReplies(mid);
|
||||
Router.go(url);
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -119,17 +119,6 @@ export class NodeStore {
|
||||
return store.$;
|
||||
};
|
||||
|
||||
async #updateReplies(messageId: string) {
|
||||
const replies = await this.node.db.db.getReplies(messageId);
|
||||
const $replies = this.$replies.get(messageId);
|
||||
$replies.$ = replies.map((p) => {
|
||||
if (this.$posts.get(p.hash).$?.hex !== p.hex) {
|
||||
this.$posts.set(p.hash, p);
|
||||
}
|
||||
return p.messageId;
|
||||
});
|
||||
}
|
||||
|
||||
async getParents(hash: string, list: string[] = []): Promise<string[]> {
|
||||
const p = this.getPost(hash);
|
||||
const post = p || (await this.node.db.db.getMessage<Post>(hash));
|
||||
@@ -165,6 +154,8 @@ export class NodeStore {
|
||||
const repostHash = rpHash || rpCreator;
|
||||
|
||||
if (repostHash) {
|
||||
console.log(repostHash, $node.$posts.get(repostHash));
|
||||
|
||||
return $node.$posts.get(repostHash);
|
||||
}
|
||||
|
||||
@@ -172,8 +163,15 @@ export class NodeStore {
|
||||
}
|
||||
|
||||
getReplies = (messageId: string) => {
|
||||
this.#updateReplies(messageId);
|
||||
const $replies = this.$replies.get(messageId);
|
||||
this.node.db.db.getReplies(messageId).then((replies) => {
|
||||
$replies.$ = replies.map((p) => {
|
||||
if (this.$posts.get(p.hash).$?.hex !== p.hex) {
|
||||
this.$posts.set(p.hash, p);
|
||||
}
|
||||
return p.messageId;
|
||||
});
|
||||
});
|
||||
return $replies.$;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user