on master help sign in
First draft
39efe03Devine Lu Linvega
links/main.css+26−13
@@ -2,28 +2,41 @@
2
2
3body { background:#f4f4f4; padding:0px; margin:0px; }
3body { background:#f4f4f4; padding:0px; margin:0px; }
4body div { display:block; background: #111;min-height: calc(100vh - 60px);width: calc(100vw - 60px);margin: 15px;color: #333;padding: 15px;font-family:'input_mono_regular', 'Monospaced','Courier New',courier;font-size:11px; position: relative; border-radius: 2px; color:white;}
4body div { display:block; background: #111;min-height: calc(100vh - 60px);width: calc(100vw - 60px);margin: 15px;color: #333;padding: 15px;font-family:'input_mono_regular', 'Monospaced','Courier New',courier;font-size:11px; position: relative; border-radius: 2px; color:white;}
5−body div #icon { display: block;width: 30px;height: 30px;background-image: url(../icon.white.svg);background-size: cover;background-repeat: no-repeat;position: absolute;bottom: 15px;right:15px;background-position: center;padding:0px }
5+body div ul { max-width: 800px; border-bottom: 2px solid white;padding-bottom: 15px;margin-bottom:15px; overflow: hidden;}
6body div p { display:block; padding:0px 5px; line-height: 20px}
6body div p { display:block; padding:0px 5px; line-height: 20px}
7body div p a { text-decoration: underline;}
7body div p a { text-decoration: underline;}
8body div p a:hover { text-decoration: underline; }
8body div p a:hover { text-decoration: underline; }
9body div p b { font-weight: normal; font-family: 'input_mono_medium' }
9body div p b { font-weight: normal; font-family: 'input_mono_medium' }
10body div p.readme { max-width:500px; }
10body div p.readme { max-width:500px; }
11−body div ul { max-width: 800px; border-bottom: 2px solid white;padding-bottom: 15px;margin-bottom:15px; overflow: hidden; columns:3;}
11+
12+/* Hallway */
13+
14+body #hallway .entry { line-height: 16px; display: block }
15+body #hallway .entry .date { color:#555; }
16+body #hallway .entry .date:after { content: ")" }
17+body #hallway .entry .author { font-family: 'input_mono_medium' }
18+body #hallway .entry .author:after { content:":"; }
19+body #hallway .entry .body { }
20+
21+/* Portal */
22+
23+body #portal #icon { display: block;width: 30px;height: 30px;background-image: url(../icon.white.svg);background-size: cover;background-repeat: no-repeat;position: absolute;bottom: 15px;right:15px;background-position: center;padding:0px }
24+body #portal ul { columns:3; }
12−body div ul li { display:block; padding-left:5px; text-overflow: ellipsis; text-transform: lowercase;}
25+body #portal ul li { display:block; padding-left:5px; text-overflow: ellipsis; text-transform: lowercase;}
13−body div ul li.wiki::after { content:"<wiki>"; color:#555; }
26+body #portal ul li.wiki::after { content:"<wiki>"; color:#555; }
14−body div ul li.blog::after { content:"<blog>"; color:#555; }
27+body #portal ul li.blog::after { content:"<blog>"; color:#555; }
15−body div ul li a { line-height: 20px; padding:0px 5px; text-decoration: none;}
28+body #portal ul li a { line-height: 20px; padding:0px 5px; text-decoration: none;}
16−body div ul li a:visited { color:#ccc; text-decoration: none;}
29+body #portal ul li a:visited { color:#ccc; text-decoration: none;}
17−body div ul li a:hover { text-decoration: underline; }
30+body #portal ul li a:hover { text-decoration: underline; }
18
31
19@media (max-width: 730px) {
32@media (max-width: 730px) {
20− body div ul li span.counter { display: none }
33+ body #portal ul li span.counter { display: none }
21}
34}
22@media (max-width: 630px) {
35@media (max-width: 630px) {
23− body div ul { columns: 2 !important; }
36+ body #portal ul { columns: 2 !important; }
24− body div ul li span.counter { display: none }
37+ body #portal ul li span.counter { display: none }
25}
38}
26@media (max-width: 530px) {
39@media (max-width: 530px) {
27− body div ul { columns: 1 !important; }
40+ body #portal ul { columns: 1 !important; }
28− body div ul li span.counter { display: inline }
41+ body #portal ul li span.counter { display: inline }
29}
42}
scripts/hallway.js+52−3
@@ -4,6 +4,7 @@ function Hallway (sites) {
4 const feeds = {}
4 const feeds = {}
5 this.sites = sites
5 this.sites = sites
6 this.el = document.createElement('div')
6 this.el = document.createElement('div')
7+ this.el.id = 'hallway'
7
8
8 this.install = function (host) {
9 this.install = function (host) {
9 host.appendChild(this.el)
10 host.appendChild(this.el)
@@ -18,10 +19,38 @@ function Hallway (sites) {
18 }
19 }
19
20
20 this.refresh = function () {
21 this.refresh = function () {
21− console.log('!!')
22+ const entries = this.sortEntries()
23+ let html = ''
24+ for (const id in entries) {
25+ html += `${this.templateEntry(entries[id])}\n`
26+ }
27+ this.el.innerHTML = `<ul>${html}</ul>${this._footer()}`
22 }
28 }
23
29
24− //
30+ // Entries
31+
32+ this.sortEntries = function () {
33+ const a = []
34+ for (const id in feeds) {
35+ const feed = feeds[id]
36+ for (const i in feed.content) {
37+ const entry = feed.content[i]
38+ a.push(entry)
39+ }
40+ }
41+ return a
42+ }
43+
44+ this.templateEntry = function (entry) {
45+ const now = new Date()
46+ const then = Date.parse(entry.date)
47+ const diff = (now - then)
48+ const date = Math.floor(diff / 86400000)
49+
50+ return `<li class='entry'><span class='date'>${date}</span> <span class='author'>${entry.author}</span> <span class='body'>${entry.body}</span></li>`
51+ }
52+
53+ // Feeds
25
54
26 this.findFeeds = function () {
55 this.findFeeds = function () {
27 console.log('Finding feeds..')
56 console.log('Finding feeds..')
@@ -44,8 +73,28 @@ function Hallway (sites) {
44 this.fetchFeed = function (id, feed) {
73 this.fetchFeed = function (id, feed) {
45 console.log(`Fetching ${id}(${feed.path})..`)
74 console.log(`Fetching ${id}(${feed.path})..`)
46 Promise.all([ fetch(feed.path).then(x => x.text()) ]).then(([content]) => {
75 Promise.all([ fetch(feed.path).then(x => x.text()) ]).then(([content]) => {
47− feeds[id].content = content
76+ feeds[id].content = parseFeed(id, content)
48 this.refresh()
77 this.refresh()
49 })
78 })
50 }
79 }
80+
81+ // Extras
82+
83+ this._footer = function () {
84+ return '<p>The <b>Hallway</b> is a decentralized forum, to join the conversation, simply create yourself a <a href="https://twtxt.readthedocs.io/en/stable/user/twtxtfile.html">twtxt</a> feed and add it to your entry in the webring.</p>'
85+ }
86+
87+ // Utils
88+
89+ function parseFeed (author, feed) {
90+ const lines = feed.split('\n')
91+ const entries = []
92+ for (const id in lines) {
93+ const line = lines[id]
94+ const date = line.substr(0, 25).trim()
95+ const body = line.substr(26).trim()
96+ entries.push({ date, body, author })
97+ }
98+ return entries
99+ }
51}
100}
scripts/portal.js+2−1
@@ -2,6 +2,7 @@
2
2
3function Portal (sites) {
3function Portal (sites) {
4 this.el = document.createElement('div')
4 this.el = document.createElement('div')
5+ this.el.id = 'portal'
5 this.sites = sites
6 this.sites = sites
6
7
7 // Templates
8 // Templates
@@ -11,7 +12,7 @@ function Portal (sites) {
11 }
12 }
12
13
13 function _buttons () {
14 function _buttons () {
14− return `<p class='buttons'><a href='#random' onClick="portal.reload('random')">Random</a> | <a href='https://github.com/XXIIVV/webring'>Information</a> <a id='icon' href='#random' onClick="portal.reload('random')"></a> | <a id="opml">OPML</a></p>`
15+ return `<p class='buttons'><a href='#random' onClick="portal.reload('random')">Random</a> | <a href='https://github.com/XXIIVV/webring'>Information</a> <a id='icon' href='#random' onClick="portal.reload('random')"></a> | <a href="hallway.html">The Hallway</a> | <a id="opml">OPML</a></p>`
15 }
16 }
16
17
17 function _directory (sites) {
18 function _directory (sites) {