mirror of
https://github.com/autismjs/monorepo.git
synced 2026-01-09 17:17:55 -05:00
add basic editor state
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -8,5 +8,5 @@ coverage/
|
||||
dev-build/
|
||||
bin/
|
||||
.autism/
|
||||
#**/src/**/*.css
|
||||
#**/src/**/*.css.map
|
||||
**/src/**/*.css
|
||||
**/src/**/*.css.map
|
||||
@@ -95,7 +95,7 @@ export class ObservableMap<keyType = string, ValueType = any> {
|
||||
}
|
||||
}
|
||||
|
||||
export function obervable(target: any, key: string) {
|
||||
export function observable(target: any, key: string) {
|
||||
const currentValue = target[key];
|
||||
let currentStore = new Observable(currentValue);
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ type DOMOptions = {
|
||||
onclick?(): void;
|
||||
} & { [key: string]: string };
|
||||
|
||||
type VNodeOption = VNode | string | (() => VNode | VNode[]);
|
||||
type VNodeOption = VNode | string | (() => VNode | VNode[]) | boolean;
|
||||
type VNodeOptions = VNodeOption | VNodeOption[];
|
||||
|
||||
export const h = (
|
||||
@@ -391,6 +391,10 @@ export const h = (
|
||||
return [new VNode({ tagName: 'text', content: nodeOrText })];
|
||||
}
|
||||
|
||||
if (typeof nodeOrText === 'boolean') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const nodes = nodeOrText();
|
||||
let retNodes = nodes;
|
||||
|
||||
@@ -480,3 +484,9 @@ export function disabled(bool?: any): { disabled?: 'true' } {
|
||||
if (!!bool) obj.disabled = 'true';
|
||||
return obj;
|
||||
}
|
||||
|
||||
export function boolAttr(key: string, bool?: any): { [key: string]: 'true' } {
|
||||
const obj: { [key: string]: 'true' } = {};
|
||||
if (!!bool) obj[key] = 'true';
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
button {
|
||||
transition: opacity 100ms ease-in-out;
|
||||
button,
|
||||
.button {
|
||||
display: var(--display, flex);
|
||||
flex-flow: var(--flex-flow, row);
|
||||
align-items: var(--align-items, center);
|
||||
padding: var(--padding, .25rem .5rem);
|
||||
cursor: pointer;
|
||||
border: var(--border, 1px solid var(--slate-200));
|
||||
border-radius: var(--border-radius);
|
||||
gap: var(--gap, 0);
|
||||
font-family: var(--font-family, var(--font-sans));
|
||||
font-size: var(--font-size, .875rem);
|
||||
@@ -13,6 +14,7 @@ button {
|
||||
background-color: var(--background-color, var(--slate-100));
|
||||
width: var(--width);
|
||||
opacity: var(--opacity, .9);
|
||||
font-weight: var(--font-weight, var(--font-normal));
|
||||
|
||||
&:hover {
|
||||
opacity: var(--opacity, .7);
|
||||
|
||||
@@ -5,8 +5,11 @@ export default class Button extends CustomElement {
|
||||
css = css.toString();
|
||||
|
||||
render() {
|
||||
const { disabled } = this.state;
|
||||
const btnProps: any = { disabled };
|
||||
const { disabled, active } = this.state;
|
||||
const btnProps: any = {
|
||||
disabled,
|
||||
className: active ? 'button--active' : '',
|
||||
};
|
||||
|
||||
if (!disabled) {
|
||||
delete btnProps.disabled;
|
||||
@@ -14,7 +17,7 @@ export default class Button extends CustomElement {
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
return h('button', btnProps, h('slot'));
|
||||
return h('button.button', btnProps, h('slot'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
}
|
||||
|
||||
textarea.content {
|
||||
transition: background-color 100ms ease-in-out, border 100ms ease-in-out;
|
||||
outline: none;
|
||||
grid-column-start: 1;
|
||||
grid-column-end: 3;
|
||||
|
||||
@@ -11,19 +11,20 @@ import { userId, userName } from '../../utils/misc.ts';
|
||||
import { MessageType, Post, PostSubtype } from '@message';
|
||||
import { Observable } from '../../../lib/state.ts';
|
||||
import css from './index.scss';
|
||||
import $editor from '../../state/editor.ts';
|
||||
|
||||
@connect(() => {
|
||||
const content = new Observable('');
|
||||
|
||||
return {
|
||||
content,
|
||||
ecdsa: $signer.$ecdsa,
|
||||
reference: $editor.reference,
|
||||
};
|
||||
})
|
||||
export default class Editor extends CustomElement {
|
||||
css = css.toString();
|
||||
onSubmit = () => {
|
||||
const creator = $signer.publicKey;
|
||||
const creator = this.state.creator;
|
||||
const content = this.$.content.$;
|
||||
|
||||
const post = new Post({
|
||||
@@ -56,12 +57,16 @@ export default class Editor extends CustomElement {
|
||||
};
|
||||
|
||||
render(): VNode {
|
||||
const creator = $signer.publicKey;
|
||||
const name = userName($signer.publicKey) || 'Anonymous';
|
||||
const handle = userId($signer.publicKey) || '';
|
||||
const creator = this.state.creator;
|
||||
const name = userName(creator) || 'Anonymous';
|
||||
const handle = userId(creator) || '';
|
||||
|
||||
return h(
|
||||
'div.editor',
|
||||
!!$editor.reference.$ &&
|
||||
h('post-card', {
|
||||
hash: $editor.reference.$,
|
||||
}),
|
||||
h(
|
||||
'div.post',
|
||||
h('profile-image', {
|
||||
|
||||
@@ -1,33 +1,39 @@
|
||||
import { CustomElement, h, register } from '../../../lib/ui.ts';
|
||||
import { connect, CustomElement, h, register } from '../../../lib/ui.ts';
|
||||
import css from './index.scss';
|
||||
import $signer from '../../state/signer.ts';
|
||||
import '../Editor';
|
||||
import { ProofType } from '@message';
|
||||
import $node from '../../state/node.ts';
|
||||
|
||||
@connect(() => ({
|
||||
ecdsa: $signer.$ecdsa,
|
||||
}))
|
||||
export default class LeftSidebar extends CustomElement {
|
||||
css = css.toString();
|
||||
|
||||
onSubmit = async (e: CustomEvent) => {
|
||||
const { post, reset } = e.detail;
|
||||
|
||||
if (post) {
|
||||
if ($signer.$ecdsa.$?.privateKey) {
|
||||
post.commit({
|
||||
type: ProofType.ECDSA,
|
||||
value: $signer.$ecdsa.$.sign(post.hash),
|
||||
});
|
||||
|
||||
await $node.node.publish(post);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return h(
|
||||
`div.left-sidebar`,
|
||||
// @ts-ignore
|
||||
h('post-editor', {
|
||||
onsubmit: async (e: CustomEvent) => {
|
||||
const { post, reset } = e.detail;
|
||||
|
||||
if (post) {
|
||||
if ($signer.$ecdsa.$?.privateKey) {
|
||||
post.commit({
|
||||
type: ProofType.ECDSA,
|
||||
value: $signer.$ecdsa.$.sign(post.hash),
|
||||
});
|
||||
|
||||
await $node.node.publish(post);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
},
|
||||
creator: $signer.$ecdsa.$?.publicKey,
|
||||
onsubmit: this.onSubmit,
|
||||
}),
|
||||
h('c-button[disabled=true]', 'Import Private Key'),
|
||||
h(
|
||||
|
||||
@@ -73,41 +73,79 @@ profile-image {
|
||||
.comment-btn,
|
||||
.like-btn,
|
||||
.repost-btn {
|
||||
--background-color: transparent;
|
||||
--border: 1px solid transparent;
|
||||
--gap: .5rem;
|
||||
--font-family: var(--font-mono);
|
||||
--font-size: var(--text-base);
|
||||
--padding: .125rem .25rem;
|
||||
--opacity: .85;
|
||||
--padding: .25rem .375rem;
|
||||
--border-radius: .25rem;
|
||||
--opacity: 1;
|
||||
|
||||
img {
|
||||
width: var(--text-base);
|
||||
height: var(--text-base);
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
--opacity: .7;
|
||||
img {
|
||||
opacity: .75;
|
||||
}
|
||||
}
|
||||
|
||||
&[active=true],
|
||||
&:active {
|
||||
--opacity: 1;
|
||||
--font-weight: var(--font-medium);
|
||||
img {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.comment-btn {
|
||||
--color: var(--blue-600);
|
||||
--background-color: var(--blue-100);
|
||||
--border: 1px solid var(--blue-400);
|
||||
--color: var(--blue-200);
|
||||
|
||||
&:hover {
|
||||
--background-color: var(--blue-100);
|
||||
--color: var(--blue-400);
|
||||
}
|
||||
|
||||
&[active=true],
|
||||
&:active {
|
||||
--background-color: var(--blue-200);
|
||||
--color: var(--blue-600);
|
||||
}
|
||||
}
|
||||
|
||||
.repost-btn {
|
||||
--color: var(--green-600);
|
||||
--background-color: var(--green-100);
|
||||
--border: 1px solid var(--green-400);
|
||||
--color: var(--green-200);
|
||||
|
||||
&:hover {
|
||||
--background-color: var(--green-100);
|
||||
--color: var(--green-400);
|
||||
}
|
||||
|
||||
&[active=true],
|
||||
&:active {
|
||||
--background-color: var(--green-200);
|
||||
--color: var(--green-600);
|
||||
}
|
||||
}
|
||||
|
||||
.like-btn {
|
||||
--color: var(--red-600);
|
||||
--background-color: var(--red-100);
|
||||
--border: 1px solid var(--red-400);
|
||||
--color: var(--red-200);
|
||||
|
||||
&:hover {
|
||||
--background-color: var(--red-100);
|
||||
--color: var(--red-400);
|
||||
}
|
||||
|
||||
&[active=true],
|
||||
&:active {
|
||||
--background-color: var(--red-200);
|
||||
--color: var(--red-600);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,10 @@
|
||||
import { connect, CustomElement, h, register } from '../../../lib/ui.ts';
|
||||
import {
|
||||
boolAttr,
|
||||
connect,
|
||||
CustomElement,
|
||||
h,
|
||||
register,
|
||||
} from '../../../lib/ui.ts';
|
||||
import { fromNow, userId, userName } from '../../utils/misc.ts';
|
||||
import CommentIcon from '../../../static/icons/comment.svg';
|
||||
import RepostIcon from '../../../static/icons/repost.svg';
|
||||
@@ -7,6 +13,7 @@ import '../ProfileImage';
|
||||
import '../Button';
|
||||
import css from './index.scss';
|
||||
import $node from '../../state/node.ts';
|
||||
import $editor from '../../state/editor.ts';
|
||||
|
||||
@connect((el) => {
|
||||
const hash = el.state.hash;
|
||||
@@ -15,6 +22,7 @@ import $node from '../../state/node.ts';
|
||||
return {
|
||||
post,
|
||||
user,
|
||||
reference: $editor.reference,
|
||||
};
|
||||
})
|
||||
export default class Post extends CustomElement {
|
||||
@@ -25,18 +33,18 @@ export default class Post extends CustomElement {
|
||||
css = css.toString();
|
||||
|
||||
comment = () => {
|
||||
console.log('comment button clicked: ', this.state.hash);
|
||||
$editor.reference.$ = this.state.hash;
|
||||
};
|
||||
|
||||
render() {
|
||||
const p = this.$.post?.$;
|
||||
const u = this.$.user?.$;
|
||||
const p = $node.$posts.get(this.state.hash);
|
||||
const u = $node.$users.get(p.$?.creator || '');
|
||||
|
||||
const creator = p?.json.creator || '';
|
||||
const createat = fromNow(p?.json.createdAt) || '';
|
||||
const content = p?.json.content || '';
|
||||
const name = u?.name || userName(p?.json.creator) || 'Anonymous';
|
||||
const handle = userId(p?.json.creator) || '';
|
||||
const creator = p.$?.json.creator || '';
|
||||
const createat = fromNow(p.$?.json.createdAt) || '';
|
||||
const content = p.$?.json.content || '';
|
||||
const name = u.$?.name || userName(p.$?.json.creator) || 'Anonymous';
|
||||
const handle = userId(p.$?.json.creator) || '';
|
||||
|
||||
return h(
|
||||
'div.post',
|
||||
@@ -56,6 +64,7 @@ export default class Post extends CustomElement {
|
||||
'c-button.comment-btn',
|
||||
// @ts-ignore
|
||||
{
|
||||
...boolAttr('active', $editor.reference.$ === this.state.hash),
|
||||
onclick: this.comment,
|
||||
},
|
||||
h('img', { src: CommentIcon }),
|
||||
|
||||
10
packages/web/src/state/editor.ts
Normal file
10
packages/web/src/state/editor.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Observable, ObservableMap } from '../../lib/state';
|
||||
|
||||
export class Editor {
|
||||
reference = new Observable('');
|
||||
drafts = new ObservableMap<string, { content: string }>();
|
||||
}
|
||||
|
||||
const $editor = new Editor();
|
||||
|
||||
export default $editor;
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Observable } from '../../lib/state.ts';
|
||||
import { ECDSA } from '@autismjs/crypto/src';
|
||||
import { ECDSA } from '@crypto';
|
||||
|
||||
export class Signer {
|
||||
$ecdsa: Observable<ECDSA | null> = new Observable<ECDSA | null>(null);
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
import dayjs from 'dayjs';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import updateLocale from 'dayjs/plugin/updateLocale';
|
||||
dayjs.extend(relativeTime);
|
||||
dayjs.extend(updateLocale);
|
||||
dayjs.updateLocale('en', {
|
||||
relativeTime: {
|
||||
future: 'in %s',
|
||||
past: '%s ago',
|
||||
s: '%ds',
|
||||
m: '1m',
|
||||
mm: '%dm',
|
||||
h: '1h',
|
||||
hh: '%dh',
|
||||
d: '1d',
|
||||
dd: '%dd',
|
||||
M: '1mo',
|
||||
MM: '%dmo',
|
||||
y: '1y',
|
||||
yy: '%dy',
|
||||
},
|
||||
});
|
||||
|
||||
export function userId(pubkey?: string) {
|
||||
if (!pubkey) return null;
|
||||
|
||||
Reference in New Issue
Block a user