3function Hallway (sites) {
6 this.el = document.createElement('div')
9 this.install = function (host) {
10 host.appendChild(this.el)
14 this.start = function () {
15 this.el.innerHTML = 'hello.'
19 this.refresh = function (feeds) {
20 const entries = this.findEntries(feeds)
21 const channels = this.findChannels(entries)
22 const users = this.findUsers(entries)
24 const _entries = entries.filter((val,id) => { return id < 50 }).reduce((acc, val, id) => { return acc + this.templateEntry(val) + '\n' }, '')
25 const _channels = Object.keys(channels).reduce((acc, val, id) => { return acc + `<li>${val} <span class='right'>${channels[val]}</span></li>\n` }, '')
26 const _users = Object.keys(users).reduce((acc, val, id) => { return acc + `<li>${val} <span class='right'>${users[val]}</span></li>\n` }, '')
45 this.findChannels = function (entries) {
47 for (const id in entries) {
48 const entry = entries[id]
49 if (!entry.channel) { continue }
50 channels[entry.channel] = channels[entry.channel] ? channels[entry.channel] + 1 : 1
55 this.findUsers = function (entries) {
57 for (const id in entries) {
58 const entry = entries[id]
59 users[entry.author] = users[entry.author] ? users[entry.author] + 1 : 1
64 this.findEntries = function (feeds) {
66 for (const id in feeds) {
67 for (const i in feeds[id].content) {
68 a.push(feeds[id].content[i])
71 return a.sort(compare)
74 this.templateEntry = function (entry) {
75 if (entry.body.substr(0, 1) === '@') {
76 const user = entry.body.split(' ')[0]
77 entry.body = entry.body.replace(user, `<span class='user'>${user.toLowerCase()}</span>`)
80 if (entry.body.substr(0, 1) === '/') {
81 const channel = entry.body.split(' ')[0]
82 entry.body = entry.body.replace(channel, `<span class='channel'>${channel.toLowerCase()}</span>`)
85 const filter = window.location.hash.substr(1).replace(/\+/g, ' ').toLowerCase()
86 const highlight = filter == entry.author.toLowerCase()
88 return `<li class='entry ${highlight ? 'highlight' : ''}'><span class='date'>${timeAgo(Date.parse(entry.date))}</span> <a class='author' href=''>${entry.author}</a> <span class='body'>${entry.body}</span></li>`
93 this.findFeeds = function () {
94 console.log('Finding feeds..')
95 for (const id in sites) {
96 const site = sites[id]
97 if (site.feed && site.author) {
98 feeds[site.author] = { path: site.feed }
101 console.log(`Found ${Object.keys(feeds).length} feeds.`)
104 this.fetchFeeds = function () {
105 console.log(`Fetching ${Object.keys(feeds).length} feeds..`)
106 for (const id in feeds) {
107 this.fetchFeed(id, feeds[id])
111 this.fetchFeed = function (id, feed) {
112 console.log(`Fetching ${id}(${feed.path})..`)
113 fetch(feed.path, { cache: 'no-store' }).then(x => x.text()).then((content) => {
114 feeds[id].content = parseFeed(id, content)
117 console.warn(`${id}`, err)
123 this._footer = function () {
124 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 <a href="https://github.com/XXIIVV/Webring/">add it</a> to your entry in the <a href="index.html">webring</a>.</p>'
129 function compare (a, b) {
130 return a.offset < b.offset ? -1 : a.offset > b.offset ? 1 : 0
133 function parseFeed (author, feed) {
134 const lines = feed.split('\n')
136 for (const id in lines) {
137 const line = lines[id].trim()
138 if (line === '') { continue }
139 const parts = line.replace(' ', '\t').split('\t')
140 const date = parts[0].trim()
141 const body = parts[1].trim()
142 const channel = body.substr(0, 1) === '/' ? body.split(' ')[0].substr(1).toLowerCase() : null
143 const offset = new Date() - new Date(date)
144 entries.push({ date, body, author, offset, channel })
149 function timeAgo (dateParam) {
150 const date = typeof dateParam === 'object' ? dateParam : new Date(dateParam)
151 const DAY_IN_MS = 86400000 // 24 * 60 * 60 * 1000
152 const today = new Date()
153 const yesterday = new Date(today - DAY_IN_MS)
154 const seconds = Math.round((today - date) / 1000)
155 const minutes = Math.round(seconds / 60)
156 const isToday = today.toDateString() === date.toDateString()
157 const isYesterday = yesterday.toDateString() === date.toDateString()
161 } else if (seconds < 60) {
162 return `${seconds} seconds ago`
163 } else if (seconds < 90) {
164 return 'about a minute ago'
165 } else if (minutes < 60) {
166 return `${minutes} minutes ago`
167 } else if (isToday) {
168 return `${Math.floor(minutes / 60)} hours ago`
169 } else if (isYesterday) {
173 return `${Math.floor(minutes / 1440)} days ago`
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list