From 083c63cec425bb2c8e6f4f9a90c3ddfec2273b36 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 5 Feb 2021 20:06:26 +0100 Subject: reimplement collapsing --- src/index.js | 110 +++++++++++++++++++++++++++++++++------------------------ src/ui/Note.js | 14 +++++--- 2 files changed, 73 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/index.js b/src/index.js index 090b67a..4b46ac7 100644 --- a/src/index.js +++ b/src/index.js @@ -95,8 +95,42 @@ class GraphContainer extends Component { } } -const App = ({ discussion }) => { - const { name, items } = discussion; +class CollapseContainer extends Component { + state = {}; + + toggle = (id) => { + const { items } = this.props; + + const state = Object.assign({}, this.state); + state[id] = state[id] ? false : 'explicit'; + + this.setState(this.update(items[id], state)); + } + + update(node, state) { + const { items } = this.props; + + if (state[node.id] !== 'explicit') { + state[node.id] = + node.inReplyTo.length + && node.inReplyTo.every(p => state[p.id]); + } + + for (const child of node.replies) + this.update(items[child.id], state); + + return state; + } + + render() { + return this.props.render({ + collapsed: this.state, + toggleCollapsed: this.toggle, + }); + } +} + +const App = ({ name, items, collapsed, toggleCollapsed }) => { const [{ width, height, positions, links }, setState] = useState({ width: 0, height: 0, @@ -109,7 +143,7 @@ const App = ({ discussion }) => { useEffect(() => { layout.render().then(setState); - }, [ items ]); + }, [ items, collapsed ]); return (
@@ -118,14 +152,20 @@ const App = ({ discussion }) => {
{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]); + if (hidden) + return; + const onlyParent = item.inReplyTo.length === 1 && items[item.inReplyTo[0].id]; for (const reply of item.replies) { - const to = items[reply.id]; - if (item.collapsed && to.collapsed) + if (isCollapsed && collapsed[reply.id]) continue; - layout.addLink(item.id, to.id); + layout.addLink(item.id, reply.id); } return ( @@ -136,8 +176,9 @@ const App = ({ discussion }) => { && onlyParent.attributedTo === item.attributedTo // posted by same user && onlyParent.published === item.published // in the same second } + collapsed={isCollapsed} position={positions[item.id]} - onHide={hideNote} + onHide={toggleCollapsed} onSize={setNodeSize} /> ); @@ -149,45 +190,20 @@ const App = ({ discussion }) => { }; const graph = document.location.hash ? document.location.hash.substr(1) : 'lib/graph.json'; -const app = } />; +const app = ( + ( + ( + + )} + /> + )} /> +); render(app, document.body); window.app = app; - -// update collapsed nodes starting with id -// returns list of (potentially) affected nodes -const updateCollapsed = (graph, node, updated=[]) => { - updated.push(node.data.id); - - if (node.collapsed !== 'explicit') { - node.collapsed = - node.data.inReplyTo.length - && node.data.inReplyTo.every(p => graph[p.id].collapsed); - } - - for (const child of node.data.replies) - updateCollapsed(graph, graph[child.id], updated); - - return updated; -}; - -const hideNote = (e) => { - const clicked = graph[e.currentTarget.parentElement.dataset.id]; - clicked.collapsed = clicked.collapsed ? false : 'explicit'; - - for (const id of updateCollapsed(graph, clicked)) { - const node = graph[id]; - - if (node.collapsed) { - const noParents = node.data.inReplyTo.every(p => graph[p.id].collapsed); - const noChildren = node.data.replies.every(c => graph[c.id].collapsed); - node.dom.className = noParents && noChildren ? 'hidden' : 'collapsed'; - } else { - node.dom.className = ''; - } - } - - layoutNodes(graph) - .then(() => clicked.dom.scrollIntoView({ block: 'nearest', inline: 'nearest' })) - .catch(err => console.error(err)); -}; - diff --git a/src/ui/Note.js b/src/ui/Note.js index b7387a8..36691d4 100644 --- a/src/ui/Note.js +++ b/src/ui/Note.js @@ -2,6 +2,7 @@ import { render, h, Fragment } from 'preact'; import { useRef, useLayoutEffect } from 'preact/hooks'; import ColorHash from 'color-hash'; import { formatRelative } from 'date-fns'; +import cn from 'classnames'; import css from './css'; const now = new Date(); @@ -121,7 +122,7 @@ section.collapsed > main { const colors = new ColorHash({ lightness: 0.8 }); export const Note = ({ id, type, attributedTo, published, content, - smallHeader = false, position, + smallHeader = false, collapsed = false, position, onHide, onSize, }) => { const backgroundColor = attributedTo.color || colors.hex(attributedTo.id); @@ -131,6 +132,11 @@ export const Note = ({ onSize(id, root.current.offsetWidth, root.current.offsetHeight); }); + const onClickHeader = (e) => { + e.preventDefault(); + onHide(id); + }; + return (
{smallHeader - ?
- :
+ ?
+ :
}
{content} -- cgit v1.2.3