diff options
Diffstat (limited to 'client/src/ui/Discussion.js')
| -rw-r--r-- | client/src/ui/Discussion.js | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/client/src/ui/Discussion.js b/client/src/ui/Discussion.js new file mode 100644 index 0000000..5fef693 --- /dev/null +++ b/client/src/ui/Discussion.js @@ -0,0 +1,122 @@ +import { h } from 'preact'; +import { useState, useEffect } from 'preact/hooks'; +import Layout from '../layout'; +import css from './css'; +import { Links } from './Links'; +import { Note } from './Note'; + +css` +article { + position: absolute; + inset: 0; + + overflow: auto; +} + +article > h1 { + display: flex; + align-items: baseline; + + position: sticky; + inset: 0; + bottom: auto; + z-index: 200; + + margin: 0; + padding: 0.75rem 1.5rem; + background: var(--theme-title-bg); + color: var(--theme-title-fg); +} + +article > h1 > span { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +article > h1 .back { + font-size: 0.8em; + color: inherit; + opacity: 0.5; + + margin-left: 1em; +} + +article > div { + position: relative; + margin: 2rem 2rem 6rem; +} +`; + +const tmp = document.createElement('span'); + +export const Discussion = ({ + name, items, collapsed, + toggleCollapsed, toggleSelected, +}) => { + const [{ width, height, positions, links }, setState] = useState({ + width: 0, + height: 0, + positions: {}, + links: [], + }); + + const layout = new Layout(); + const setNodeSize = layout.addNode.bind(layout); + + useEffect(() => { + layout.render().then(setState); + }, [ items, collapsed ]); + + tmp.innerHTML = name; + name = tmp.innerText; + + return ( + <article> + <h1> + <span>{name}</span> + <a class="back" href="?">back</a> + </h1> + <div> + <Links width={width} height={height} links={links} /> + <div> + {Object.values(items).map((item) => { + const isCollapsed = collapsed[item.id]; + const hidden = + item.inReplyTo.every(p => collapsed[p.id]) + && item.replies.every(c => collapsed[c.id]) + && item.inReplyTo.length !== 0; + if (hidden) + return; + + const onlyParent = item.inReplyTo.length === 1 && items[item.inReplyTo[0].id]; + + for (const reply of item.replies) { + if (isCollapsed && collapsed[reply.id]) + continue; + + layout.addLink(item.id, reply.id); + } + + return ( + <Note + {...item} + smallHeader={ + onlyParent // only one parent post + && onlyParent.attributedTo === item.attributedTo // posted by same user + && onlyParent.published === item.published // in the same second + } + collapsed={isCollapsed} + position={positions[item.id]} + onCollapse={toggleCollapsed} + onSelect={toggleSelected} + onSize={setNodeSize} + /> + ); + })} + </div> + </div> + </article> + ); +}; + |
