aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2021-01-25 23:14:26 +0000
committers-ol <s-ol@users.noreply.github.com>2021-01-26 10:21:47 +0000
commit9ec0f8e7dfe7ec5b0a55a0ba51eeb986d54d5e9d (patch)
tree3ae404d7a404310486352330b57c5437a2b8de56
parentstyling (diff)
downloadfedidag-9ec0f8e7dfe7ec5b0a55a0ba51eeb986d54d5e9d.tar.gz
fedidag-9ec0f8e7dfe7ec5b0a55a0ba51eeb986d54d5e9d.zip
add avatars
-rw-r--r--package.json17
-rw-r--r--src/dom.js48
-rw-r--r--src/index.js86
-rw-r--r--src/ui.js89
-rw-r--r--yarn.lock90
5 files changed, 172 insertions, 158 deletions
diff --git a/package.json b/package.json
index fa84d90..a99b5ce 100644
--- a/package.json
+++ b/package.json
@@ -8,27 +8,32 @@
},
"babel": {
"presets": [
- "@babel/env",
- "@babel/react"
+ "@babel/env"
],
"plugins": [
- "@babel/plugin-proposal-class-properties"
+ "@babel/plugin-proposal-class-properties",
+ [
+ "@babel/plugin-transform-react-jsx",
+ {
+ "pragma": "dom.createElement",
+ "pragmaFrag": "dom.createFragment"
+ }
+ ]
]
},
"dependencies": {
"color-hash": "^1.0.3",
"core-js": "^3.8.3",
"dagre": "^0.8.5",
+ "date-fns": "^2.16.1",
"jsonld": "^3.3.0",
- "react": "^16.2.0",
- "react-dom": "^16.2.0",
"regenerator-runtime": "^0.13.7"
},
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/plugin-proposal-class-properties": "^7.10.4",
+ "@babel/plugin-transform-react-jsx": "^7.12.12",
"@babel/preset-env": "^7.11.5",
- "@babel/preset-react": "^7.10.4",
"babel-loader": "^8.2.2",
"html-webpack-plugin": "^4.5.0",
"webpack": "^4.20.2",
diff --git a/src/dom.js b/src/dom.js
new file mode 100644
index 0000000..9e44d0a
--- /dev/null
+++ b/src/dom.js
@@ -0,0 +1,48 @@
+export const css = ([ code] ) => {
+ const style = document.createElement('style');
+ document.head.appendChild(style);
+ style.appendChild(document.createTextNode(''));
+
+ let i = 0;
+ for (const v of code.split('}')) {
+ if (v.indexOf('{') < 0) continue;
+ style.sheet.insertRule(v + '}', i++);
+ }
+
+ return style;
+};
+
+const appendChild = (parent, child) => {
+ if (Array.isArray(child)) {
+ child.forEach((nestedChild) => appendChild(parent, nestedChild));
+ } else {
+ parent.appendChild(child.nodeType ? child : document.createTextNode(child));
+ }
+}
+
+const objectProps = { style: true, dataset: true };
+
+export const createElement = (tag, props, ...children) => {
+ if ('function' === typeof tag)
+ return tag(props, children);
+
+ const element = document.createElement(tag);
+
+ for (const [name, value] of Object.entries(props || {})) {
+ if (name.startsWith('on') && name.toLowerCase() in window) {
+ element.addEventListener(name.toLowerCase().substr(2), value);
+ } else if (objectProps[name]) {
+ Object.assign(element[name], value);
+ } else {
+ element.setAttribute(name, value.toString());
+ }
+ }
+
+ for (const child of children) {
+ appendChild(element, child);
+ }
+
+ return element;
+}
+
+export const createFragment = (props, ...children) => children;
diff --git a/src/index.js b/src/index.js
index 254821a..187464b 100644
--- a/src/index.js
+++ b/src/index.js
@@ -2,49 +2,15 @@ import 'core-js/stable';
import 'regenerator-runtime/runtime';
import * as jsonld from 'jsonld';
import dagre from 'dagre';
-import ColorHash from 'color-hash';
+import * as dom from './dom';
+import { Note } from './ui';
-const css = ([ code] ) => {
- const style = document.createElement('style');
- document.head.appendChild(style);
- style.appendChild(document.createTextNode(''));
-
- let i = 0;
- for (const v of code.split('}')) {
- if (v.indexOf('{') < 0) continue;
- style.sheet.insertRule(v + '}', i++);
- }
-
- return style;
-};
-
-css`
+dom.css`
article {
position: relative;
}
-
-section {
- position: absolute;
- overflow: hidden;
-
- width: 350px;
-
- background: #696969;
- border-radius: 8px;
-}
-
-section > header {
- padding: 0.75em 1em 0.5em;
- color: #121212;
-}
-
-section > main {
- padding: 1em;
- color: #eeeeee;
-}
`;
-const colors = new ColorHash({ lightness: 0.8 });
const context = 'https://www.w3.org/ns/activitystreams';
const userCache = {};
@@ -54,6 +20,7 @@ const loadUser = async (id) => {
const result = await jsonld.compact(id, context);
userCache[id] = result;
+ result.icon.url = new URL(result.icon.url, id).href;
return result;
}
@@ -71,31 +38,6 @@ const loadData = async () => {
const article = document.createElement('article');
document.body.appendChild(article);
-const createNode = (data) => {
- const root = document.createElement('section');
- root.dataset.dagId = data.id;
-
- const header = document.createElement('header');
- header.style.backgroundColor = data.attributedTo.color || colors.hex(data.attributedTo.id);
- const author = document.createElement('span');
- author.textContent = data.attributedTo.name || data.attributedTo.preferredUsername;
- header.appendChild(author);
- root.appendChild(header);
-
- const main = document.createElement('main');
- main.innerHTML = data.content;
- root.appendChild(main);
-
- article.appendChild(root);
-
- return {
- data,
- root,
- width: root.offsetWidth,
- height: root.offsetHeight,
- };
-};
-
loadData().then(data => {
window.dagData = data;
const graph = new dagre.graphlib.Graph();
@@ -107,14 +49,20 @@ loadData().then(data => {
graph.setGraph({});
graph.setDefaultEdgeLabel(() => ({}));
- let rootNode;
+ let rootId;
for (const data of data['@graph']) {
- const node = createNode(data);
- graph.setNode(data.id, node);
+ const dom = <Note {...data} />;
+ article.appendChild(dom);
+
+ graph.setNode(data.id, {
+ dom, data,
+ width: dom.offsetWidth,
+ height: dom.offsetHeight,
+ });
if (!data.inReplyTo || !data.inReplyTo.length)
- rootNode = node;
+ rootId = data.id;
if (data.replies && !Array.isArray(data.replies))
data.replies = [ data.replies ];
@@ -124,7 +72,6 @@ loadData().then(data => {
}
}
- console.log(rootNode);
dagre.layout(graph);
const info = graph.graph();
@@ -133,8 +80,8 @@ loadData().then(data => {
for (const id of graph.nodes()) {
const node = graph.node(id);
- node.root.style.left = `${node.x - node.width / 2}px`;
- node.root.style.top = `${node.y - node.height / 2}px`;
+ node.dom.style.left = `${node.x - node.width / 2}px`;
+ node.dom.style.top = `${node.y - node.height / 2}px`;
}
const ctx = canvas.getContext('2d');
@@ -153,5 +100,6 @@ loadData().then(data => {
ctx.stroke();
}
+ const rootNode = graph.node(rootId);
window.scrollTo(rootNode.x - window.innerWidth/2, rootNode.y);
});
diff --git a/src/ui.js b/src/ui.js
new file mode 100644
index 0000000..10755e6
--- /dev/null
+++ b/src/ui.js
@@ -0,0 +1,89 @@
+import ColorHash from 'color-hash';
+import { formatRelative } from 'date-fns';
+import * as dom from './dom';
+
+dom.css`
+body {
+ background: #1e1e1e;
+ font-family: sans-serif;
+}
+`;
+
+const now = new Date();
+const Time = ({ time }) => {
+ const dt = new Date(time);
+ return formatRelative(dt, now);
+};
+
+dom.css`
+.flex-space {
+ flex: 1;
+}
+`;
+
+const Space = () => <div class="flex-space" />;
+
+dom.css`
+section {
+ position: absolute;
+ overflow: hidden;
+
+ width: 350px;
+
+ background: #363636;
+ border-radius: 0.4em;
+}
+
+section > header {
+ display: flex;
+ flex-direction: row;
+
+ height: 2.5em;
+ line-height: 2.5em;
+
+ color: #121212;
+}
+
+section > header > * {
+ margin: 0 0.5em;
+}
+
+section > header > img {
+ height: 2em;
+ width: 2em;
+ margin: 0.25em;
+ border-radius: 0.2em;
+}
+
+section > header > .time {
+ font-size: 0.8em;
+ color: #363636;
+}
+
+section > main {
+ padding: 1em;
+ color: #eeeeee;
+ font-family: serif;
+}
+`;
+
+const colors = new ColorHash({ lightness: 0.8 });
+export const Note = ({ id, attributedTo, published, content }) => {
+ const backgroundColor = attributedTo.color || colors.hex(attributedTo.id);
+ const username = attributedTo.name || attributedTo.preferredUsername;
+
+ return (
+ <section dataset={{ id }}>
+ <header style={{ backgroundColor }}>
+ <img src={attributedTo.icon.url} />
+ <span class="user">{username}</span>
+ <Space />
+ <span class="time"><Time time={published} /></span>
+ </header>
+ <main>
+ {content}
+ </main>
+ </section>
+ );
+};
+
diff --git a/yarn.lock b/yarn.lock
index 21b1c48..797d870 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -633,21 +633,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
-"@babel/plugin-transform-react-display-name@^7.12.1":
- version "7.12.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.1.tgz#1cbcd0c3b1d6648c55374a22fc9b6b7e5341c00d"
- integrity sha512-cAzB+UzBIrekfYxyLlFqf/OagTvHLcVBb5vpouzkYkBclRPraiygVnafvAoipErZLI8ANv8Ecn6E/m5qPXD26w==
- dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
-
-"@babel/plugin-transform-react-jsx-development@^7.12.7":
- version "7.12.12"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.12.tgz#bccca33108fe99d95d7f9e82046bfe762e71f4e7"
- integrity sha512-i1AxnKxHeMxUaWVXQOSIco4tvVvvCxMSfeBMnMM06mpaJt3g+MpxYQQrDfojUQldP1xxraPSJYSMEljoWM/dCg==
- dependencies:
- "@babel/plugin-transform-react-jsx" "^7.12.12"
-
-"@babel/plugin-transform-react-jsx@^7.12.10", "@babel/plugin-transform-react-jsx@^7.12.12":
+"@babel/plugin-transform-react-jsx@^7.12.12":
version "7.12.12"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.12.tgz#b0da51ffe5f34b9a900e9f1f5fb814f9e512d25e"
integrity sha512-JDWGuzGNWscYcq8oJVCtSE61a5+XAOos+V0HrxnDieUus4UMnBEosDnY1VJqU5iZ4pA04QY7l0+JvHL1hZEfsw==
@@ -658,14 +644,6 @@
"@babel/plugin-syntax-jsx" "^7.12.1"
"@babel/types" "^7.12.12"
-"@babel/plugin-transform-react-pure-annotations@^7.12.1":
- version "7.12.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.12.1.tgz#05d46f0ab4d1339ac59adf20a1462c91b37a1a42"
- integrity sha512-RqeaHiwZtphSIUZ5I85PEH19LOSzxfuEazoY7/pWASCAIBuATQzpSVD+eT6MebeeZT2F4eSL0u4vw6n4Nm0Mjg==
- dependencies:
- "@babel/helper-annotate-as-pure" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
-
"@babel/plugin-transform-regenerator@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz#5f0a28d842f6462281f06a964e88ba8d7ab49753"
@@ -814,17 +792,6 @@
"@babel/types" "^7.4.4"
esutils "^2.0.2"
-"@babel/preset-react@^7.10.4":
- version "7.12.10"
- resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.12.10.tgz#4fed65f296cbb0f5fb09de6be8cddc85cc909be9"
- integrity sha512-vtQNjaHRl4DUpp+t+g4wvTHsLQuye+n0H/wsXIZRn69oz/fvNC7gQ4IK73zGJBaxvHoxElDvnYCthMcT7uzFoQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/plugin-transform-react-display-name" "^7.12.1"
- "@babel/plugin-transform-react-jsx" "^7.12.10"
- "@babel/plugin-transform-react-jsx-development" "^7.12.7"
- "@babel/plugin-transform-react-pure-annotations" "^7.12.1"
-
"@babel/runtime@^7.8.4":
version "7.12.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
@@ -1981,6 +1948,11 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
+date-fns@^2.16.1:
+ version "2.16.1"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.16.1.tgz#05775792c3f3331da812af253e1a935851d3834b"
+ integrity sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==
+
debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@@ -3366,7 +3338,7 @@ isstream@~0.1.2:
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
-"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
@@ -3516,13 +3488,6 @@ loglevel@^1.6.8:
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197"
integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==
-loose-envify@^1.1.0, loose-envify@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
- integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
- dependencies:
- js-tokens "^3.0.0 || ^4.0.0"
-
lower-case@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
@@ -4217,15 +4182,6 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
-prop-types@^15.6.2:
- version "15.7.2"
- resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
- integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
- dependencies:
- loose-envify "^1.4.0"
- object-assign "^4.1.1"
- react-is "^16.8.1"
-
proxy-addr@~2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
@@ -4359,30 +4315,6 @@ rdf-canonize@^2.0.1:
semver "^6.3.0"
setimmediate "^1.0.5"
-react-dom@^16.2.0:
- version "16.14.0"
- resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89"
- integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==
- dependencies:
- loose-envify "^1.1.0"
- object-assign "^4.1.1"
- prop-types "^15.6.2"
- scheduler "^0.19.1"
-
-react-is@^16.8.1:
- version "16.13.1"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
- integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
-
-react@^16.2.0:
- version "16.14.0"
- resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d"
- integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==
- dependencies:
- loose-envify "^1.1.0"
- object-assign "^4.1.1"
- prop-types "^15.6.2"
-
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
@@ -4636,14 +4568,6 @@ safe-regex@^1.1.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-scheduler@^0.19.1:
- version "0.19.1"
- resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
- integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==
- dependencies:
- loose-envify "^1.1.0"
- object-assign "^4.1.1"
-
schema-utils@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"