mirror of
https://github.com/XXIIVV/webring.git
synced 2024-08-16 15:11:38 +03:00
Closed Hallway/Wiki
This commit is contained in:
parent
a4a4d64dd9
commit
50afc43c23
20
hallway.html
20
hallway.html
@ -1,20 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="stylesheet" type="text/css" href="links/fonts.css"/>
|
|
||||||
<link rel="stylesheet" type="text/css" href="links/main.css"/>
|
|
||||||
<script type="text/javascript">const module = { exports:{} }</script>
|
|
||||||
<script src="scripts/hallway.js"></script>
|
|
||||||
<script src="scripts/sites.js"></script>
|
|
||||||
<title>Hallway</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script>
|
|
||||||
const hallway = new Hallway(sites);
|
|
||||||
hallway.install(document.body);
|
|
||||||
hallway.start();
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,232 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const reChannel = /(\s|^)\/([a-zA-Z0-9]+)/g
|
|
||||||
const reUser = /((\s|^)@<[a-zA-Z0-9./:\-_+~#= ]*>)/g
|
|
||||||
const reTag = /(^|\s)(#[a-z\d-]+)/ig
|
|
||||||
const reUrl = /((https?):\/\/(([-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b)([-a-zA-Z0-9@:%_+.~#?&//=]*)))/g
|
|
||||||
|
|
||||||
function Hallway (sites) {
|
|
||||||
const feeds = {}
|
|
||||||
this.sites = sites
|
|
||||||
this._el = document.createElement('div')
|
|
||||||
this._el.id = 'hallway'
|
|
||||||
const filterAndPage = window.location.hash.split('^')
|
|
||||||
this.finder = { filter: stripHash(filterAndPage[0]), page: filterAndPage[1] || 1 }
|
|
||||||
this.cache = null
|
|
||||||
|
|
||||||
this._main = document.createElement('main')
|
|
||||||
this._main.id = 'entries'
|
|
||||||
this._footer = document.createElement('footer')
|
|
||||||
this._footer.id = 'footer'
|
|
||||||
this.readme = '<p>The <strong>Hallway</strong> is a decentralized forum, to join the conversation, add a <a href="https://github.com/XXIIVV/webring#joining-the-hallway">feed:</a> field to your entry in the <a href="https://github.com/XXIIVV/Webring/">webring</a>.</p>'
|
|
||||||
this.nav = '<p class="buttons"><a href="https://github.com/XXIIVV/webring">Information</a> | <a href="index.html">The Portal</a> | <a href="wiki.html">The Wiki</a> | <a id="opml">OPML</a></p>'
|
|
||||||
this._footer.innerHTML = `${this.readme}${this.nav}`
|
|
||||||
|
|
||||||
this.install = function (host) {
|
|
||||||
this._el.appendChild(this._main)
|
|
||||||
this._el.appendChild(this._footer)
|
|
||||||
host.appendChild(this._el)
|
|
||||||
this.findFeeds()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.start = function () {
|
|
||||||
this._main.innerHTML = 'Loading..'
|
|
||||||
this.fetchFeeds()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.refresh = function (feeds = this.cache) {
|
|
||||||
const entries = this.findEntries(feeds)
|
|
||||||
const localEntries = entries.filter(entry => this.filterExternals(entry))
|
|
||||||
const channels = this.find(localEntries, 'channel')
|
|
||||||
const users = this.find(localEntries, 'author')
|
|
||||||
const tags = this.findTags(localEntries)
|
|
||||||
const relevantEntries = localEntries
|
|
||||||
.filter(entry => !this.finder.filter || (entry.author === this.finder.filter || entry.channel === this.finder.filter || entry.tags.includes(this.finder.filter) || entry.body.includes(this.finder.filter)))
|
|
||||||
|
|
||||||
const mainHtml = `
|
|
||||||
<div><ul>
|
|
||||||
${relevantEntries.filter((_, id) => id < Number(this.finder.page) * 20 && id >= (Number(this.finder.page) - 1) * 20).reduce((acc, val) => acc + this.templateEntry(val) + '\n', '')}
|
|
||||||
</ul>
|
|
||||||
<div id='pagination'>
|
|
||||||
${[...Array(Math.ceil(relevantEntries.length / 20)).keys()].reduce((acc, num) => `${acc}<span class='${Number(hallway.finder.page) === num + 1 ? 'selected' : ''}' onclick='filter("${this.finder.filter}^${num + 1}")'>${num + 1}</span>`, '')}
|
|
||||||
</div>
|
|
||||||
<a id='showbar' onclick="toggleVisibility('aside');"></a></div>`
|
|
||||||
|
|
||||||
const aside = `
|
|
||||||
<aside id='aside'>
|
|
||||||
<a id='hidebar' onclick="toggleVisibility('aside');"></a>
|
|
||||||
<ul id='channels'>
|
|
||||||
<li onclick='filter("")' class='${hallway.finder.filter === '' ? 'selected' : ''}'><a href='#'>hallway <span class='right'>${localEntries.length}</span></a></li>
|
|
||||||
${Object.keys(channels).slice(0, 15).reduce((acc, val) => acc + `<li onclick='filter("${val}")' class='${hallway.finder.filter === val ? 'selected' : ''}'><a href='#${val}'>${val} <span class='right'>${channels[val]}</span></a></li>\n`, '')}
|
|
||||||
</ul>
|
|
||||||
<ul id='users'>
|
|
||||||
${Object.keys(users).slice(0, 15).reduce((acc, val) => acc + `<li onclick='filter("${val}")' class='${hallway.finder.filter === val ? 'selected' : ''}' href='#${val}'>${val} <span class='right'>${users[val]}</span></li>\n`, '')}
|
|
||||||
</ul>
|
|
||||||
<ul id='tags'>
|
|
||||||
${Object.keys(tags).slice(0, 15).reduce((acc, val) => acc + `<li onclick='filter("${val}")' class='${hallway.finder.filter === val ? 'selected' : ''}' href='#${val}'>#${val} <span class='right'>${tags[val]}</span></li>\n`, '')}
|
|
||||||
</ul>
|
|
||||||
</aside>`
|
|
||||||
|
|
||||||
this._main.innerHTML = `${mainHtml}${aside}`
|
|
||||||
|
|
||||||
if (feeds) {
|
|
||||||
this.cache = feeds
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entries
|
|
||||||
|
|
||||||
this.filterExternals = function (entry) {
|
|
||||||
const matches = entry.body.match(reUser)
|
|
||||||
const locals = Object.keys(feeds)
|
|
||||||
return matches ? matches.some(match => locals.some(local => match.indexOf(feeds[local].path) !== -1)) : true
|
|
||||||
}
|
|
||||||
|
|
||||||
this.find = function (entries, key) {
|
|
||||||
const h = {}
|
|
||||||
for (const entry of entries) {
|
|
||||||
if (entry && entry[key]) {
|
|
||||||
h[entry[key]] = h[entry[key]] ? h[entry[key]] + 1 : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
this.findTags = function (entries) {
|
|
||||||
const tags = {}
|
|
||||||
for (const entry of entries) {
|
|
||||||
entry.tags.map(tag => {
|
|
||||||
tags[tag] = tags[tag] ? tags[tag] + 1 : 1
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return tags
|
|
||||||
}
|
|
||||||
|
|
||||||
this.findEntries = function (feeds) {
|
|
||||||
const a = []
|
|
||||||
for (const id in feeds) {
|
|
||||||
for (const i in feeds[id].content) {
|
|
||||||
a.push(feeds[id].content[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return a.sort((a, b) => a.offset - b.offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.findMention = function (found) {
|
|
||||||
const mention = Object.keys(feeds).filter(user => found.indexOf(feeds[user].path) > -1)
|
|
||||||
return ` <span class='user local'>${mention[0]}</span>`
|
|
||||||
}
|
|
||||||
|
|
||||||
this.templateEntry = function (entry) {
|
|
||||||
entry.html = entry.body
|
|
||||||
.replace(reChannel, '$1<span class="channel">/$2</span>')
|
|
||||||
.replace(reUser, this.findMention)
|
|
||||||
.replace(reTag, '$1<span class="tag">$2</span>')
|
|
||||||
.replace(reUrl, '<a target="_blank" href="$1">$1</a>')
|
|
||||||
|
|
||||||
const filter = window.location.hash.substr(1).replace(/\+/g, ' ').toLowerCase()
|
|
||||||
const highlight = filter === entry.author.toLowerCase()
|
|
||||||
const origin = feeds[entry.author].path
|
|
||||||
|
|
||||||
return `<li class='entry ${highlight ? 'highlight' : ''}'><span class='date'>${timeAgo(Date.parse(entry.date))}</span> <a class='author' href='${origin}' target='_blank'>${entry.author}</a> <span class='body'>${entry.html}</span></li>`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Feeds
|
|
||||||
|
|
||||||
this.findFeeds = function () {
|
|
||||||
console.log('Finding feeds..')
|
|
||||||
for (const site of sites) {
|
|
||||||
if (site.feed && site.author) {
|
|
||||||
feeds[site.author] = { path: site.feed }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log(`Found ${Object.keys(feeds).length} feeds.`)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.fetchFeeds = function () {
|
|
||||||
console.log(`Fetching ${Object.keys(feeds).length} feeds..`)
|
|
||||||
for (const id in feeds) {
|
|
||||||
this.fetchFeed(id, feeds[id])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.fetchFeed = function (id, feed) {
|
|
||||||
console.log(`Fetching ${id}(${feed.path})..`)
|
|
||||||
fetch(feed.path, { cache: 'no-store' }).then(x => x.text()).then((content) => {
|
|
||||||
feeds[id].content = parseFeed(id, content)
|
|
||||||
this.refresh(feeds)
|
|
||||||
}).catch((err) => {
|
|
||||||
console.warn(`${id}`, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utils
|
|
||||||
|
|
||||||
function parseFeed (author, feed) {
|
|
||||||
const lines = feed.split('\n').filter((line) => line.substr(0, 1) !== '#')
|
|
||||||
const entries = []
|
|
||||||
for (const id in lines) {
|
|
||||||
const line = lines[id].trim()
|
|
||||||
if (line === '') { continue }
|
|
||||||
const parts = line.replace(' ', '\t').split('\t')
|
|
||||||
const date = parts[0].trim()
|
|
||||||
const body = escapeHtml(parts[1].trim()).trim()
|
|
||||||
const channel = body.substr(0, 1) === '/' ? cleanTags(body.split(' ')[0].substr(1).toLowerCase()) : body.substr(0, 1) === '@' ? 'veranda' : 'lobby'
|
|
||||||
const tags = (body.match(reTag) || []).map(a => cleanTags(a.substr(a.indexOf('#') + 1).toLowerCase()))
|
|
||||||
const offset = new Date() - new Date(date)
|
|
||||||
entries.push({ date, body, author, offset, channel, tags })
|
|
||||||
}
|
|
||||||
return entries
|
|
||||||
}
|
|
||||||
|
|
||||||
function timeAgo (dateParam) {
|
|
||||||
const date = typeof dateParam === 'object' ? dateParam : new Date(dateParam)
|
|
||||||
const today = new Date()
|
|
||||||
const yesterday = new Date(today - 86400000)
|
|
||||||
const seconds = Math.round((today - date) / 1000)
|
|
||||||
const minutes = Math.round(seconds / 60)
|
|
||||||
const isToday = today.toDateString() === date.toDateString()
|
|
||||||
const isYesterday = yesterday.toDateString() === date.toDateString()
|
|
||||||
|
|
||||||
if (seconds < 5) {
|
|
||||||
return 'just now'
|
|
||||||
} else if (seconds < 60) {
|
|
||||||
return `${seconds} seconds ago`
|
|
||||||
} else if (seconds < 90) {
|
|
||||||
return 'a minute ago'
|
|
||||||
} else if (minutes < 60) {
|
|
||||||
return `${minutes} minutes ago`
|
|
||||||
} else if (isToday) {
|
|
||||||
return `${Math.floor(minutes / 60)} hours ago`
|
|
||||||
} else if (isYesterday) {
|
|
||||||
return 'yesterday'
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${Math.floor(minutes / 1440)} days ago`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleVisibility (id) {
|
|
||||||
const e = document.getElementById(id)
|
|
||||||
if (e.style.display === 'block') { e.style.display = 'none' } else { e.style.display = 'block' }
|
|
||||||
}
|
|
||||||
|
|
||||||
function escapeHtml (unsafe) {
|
|
||||||
return unsafe.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''')
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanTags (unsafe) {
|
|
||||||
return unsafe.replace(/([^a-z0-9]+)/gi, '-')
|
|
||||||
}
|
|
||||||
|
|
||||||
function stripHash (hash) {
|
|
||||||
const decoded = decodeURIComponent(hash)
|
|
||||||
return decoded.charAt(0) === '#' ? decoded.substring(1) : decoded
|
|
||||||
}
|
|
||||||
|
|
||||||
function filter (name) {
|
|
||||||
window.location.hash = name
|
|
||||||
const filterAndPage = window.location.hash.split('^')
|
|
||||||
hallway.finder = { filter: stripHash(filterAndPage[0]), page: filterAndPage[1] || 1 }
|
|
||||||
hallway.refresh()
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
function indental (data, Type) {
|
|
||||||
function formatLine (line) {
|
|
||||||
const a = []
|
|
||||||
const h = {}
|
|
||||||
for (const child of line.children) {
|
|
||||||
if (child.key) {
|
|
||||||
if (h[child.key]) { console.warn(`Redefined key: ${child.key}.`) }
|
|
||||||
h[child.key] = child.value
|
|
||||||
} else if (child.children.length === 0 && child.content) {
|
|
||||||
a[a.length] = child.content
|
|
||||||
} else {
|
|
||||||
h[child.content.toUpperCase()] = formatLine(child)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return a.length > 0 ? a : h
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeLine (line) {
|
|
||||||
return line.indexOf(' : ') > -1 ? {
|
|
||||||
indent: line.search(/\S|$/),
|
|
||||||
content: line.trim(),
|
|
||||||
key: line.split(' : ')[0].trim().toUpperCase(),
|
|
||||||
value: line.split(' : ')[1].trim()
|
|
||||||
} : {
|
|
||||||
indent: line.search(/\S|$/),
|
|
||||||
content: line.trim(),
|
|
||||||
children: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function skipLine (line) {
|
|
||||||
return line.trim() !== '' && line.trim().substr(0, 1) !== ';' && line.trim().slice(-1) !== '`'
|
|
||||||
}
|
|
||||||
|
|
||||||
const lines = data.split('\n').filter(skipLine).map(makeLine)
|
|
||||||
|
|
||||||
// Assoc
|
|
||||||
const stack = {}
|
|
||||||
for (const line of lines) {
|
|
||||||
const target = stack[line.indent - 2]
|
|
||||||
if (target) { target.children.push(line) }
|
|
||||||
stack[line.indent] = line
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format
|
|
||||||
const h = {}
|
|
||||||
for (const id in lines) {
|
|
||||||
const line = lines[id]
|
|
||||||
if (line.indent > 0) { continue }
|
|
||||||
const key = line.content.toUpperCase()
|
|
||||||
if (h[key]) { console.warn(`Redefined key: ${key}, line ${id}.`) }
|
|
||||||
h[key] = Type ? new Type(key, formatLine(line)) : formatLine(line)
|
|
||||||
}
|
|
||||||
return h
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
const outlines = sites.filter(site => site.rss).map(site => {
|
|
||||||
return `<outline type="rss" xmlUrl="${site.rss}" title="${site.title}"/>`
|
|
||||||
})
|
|
||||||
|
|
||||||
const template = `<?xml version="1.0" encoding="UTF-8"?><opml version="1.1"><head></head><body>${outlines.join('')}</body></opml>`
|
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const a = document.getElementById('opml')
|
|
||||||
if (a) {
|
|
||||||
a.setAttribute('href', 'data:text/plain;charset=utf-8,' + window.encodeURIComponent(template))
|
|
||||||
a.setAttribute('download', 'webring.opml')
|
|
||||||
}
|
|
||||||
})
|
|
@ -1,121 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
function Portal (sites) {
|
|
||||||
this.el = document.createElement('div')
|
|
||||||
this.el.id = 'portal'
|
|
||||||
this.sites = sites
|
|
||||||
|
|
||||||
// Templates
|
|
||||||
|
|
||||||
const _readme = '<p class="readme">This webring is an attempt to inspire artists & developers to build their own website and share traffic among each other. The ring welcomes personalized websites such as <b>diaries, wikis & portfolios</b>.</p><p>To add yourself to the ring, submit a <a href="https://github.com/XXIIVV/webring/edit/master/scripts/sites.js" target="_blank">Pull Request</a>.<br />If you found a broken link, please <a href="https://github.com/XXIIVV/webring/issues/new" target="_blank">report it</a>.</p>'
|
|
||||||
const _buttons = '<p class="buttons"><a href="#random" onClick="portal.reload()">Random</a> | <a href="https://github.com/XXIIVV/webring">Information</a> <a id="icon" href="#random" onClick="portal.reload()"></a> | <a href="hallway.html">The Hallway</a> | <a href="wiki.html">The Wiki</a> | <a id="opml">OPML</a></p>'
|
|
||||||
|
|
||||||
function _directory (sites) {
|
|
||||||
const siteTypesArray = [...new Set(sites.map(site => site.type).filter(Boolean))]
|
|
||||||
const siteLangsArray = [...new Set(sites
|
|
||||||
.reduce((flattened, site) => flattened.concat(site.langs), [])
|
|
||||||
.sort())]
|
|
||||||
|
|
||||||
const siteTypes = siteTypesArray.reduce((output, siteType) =>
|
|
||||||
`${output}<a data-type="${siteType}" href="#" onclick="filterSites(event)"><${siteType}></a>`,
|
|
||||||
'<a class="currentType" data-type="all" href="#" onclick="filterSites(event)"><all></a>')
|
|
||||||
|
|
||||||
const siteLangs = siteLangsArray.reduce((output, siteLang) =>
|
|
||||||
`${output}<a data-lang="${siteLang}" href="#" onclick="filterSites(event)"><${siteLang}></a>`,
|
|
||||||
'<a class="currentLang" data-lang="all" href="#" onclick="filterSites(event)"><all></a>')
|
|
||||||
|
|
||||||
const listItems = sites.reduce((acc, site, id) =>
|
|
||||||
`${acc}<li ${_type(site)} ${_lang(site)} id='${id}'><a href='${site.url}'>${_name(site)}</a></li>`, '')
|
|
||||||
return `<nav>${siteTypes}</nav><nav>${siteLangs}</nav><main><ul>${listItems}</ul></main><footer>${_readme}${_buttons}</footer>`
|
|
||||||
}
|
|
||||||
|
|
||||||
function _name (site) {
|
|
||||||
return site.title || `${site.url.split('//')[1].replace(/\/+$/, '')}`
|
|
||||||
}
|
|
||||||
|
|
||||||
function _type (site) {
|
|
||||||
return site.type ? `data-type="${site.type} "` : ''
|
|
||||||
}
|
|
||||||
|
|
||||||
function _lang (site) {
|
|
||||||
return `data-lang="${site.langs.join(' ').trim()}"`
|
|
||||||
}
|
|
||||||
|
|
||||||
function _redirectView (site) {
|
|
||||||
return `<main><p>Redirecting to <a href="${site.url}">${site.url}</a></p></main>
|
|
||||||
<footer><p class='buttons'><a href='#' onClick="portal.reload('')">Directory</a> | <a href='#${site.url}' onClick="portal.reload()">Skip</a> | <a href='#random' onClick="portal.reload()">Random</a> | <a href='https://github.com/XXIIVV/webring'>Information</a> <a id='icon' href='#random' onClick="portal.reload()"></a></p>`
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
this.install = function (host) {
|
|
||||||
host.appendChild(this.el)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.start = function () {
|
|
||||||
const hash = window.location.hash
|
|
||||||
if (hash && hash.length > 4) {
|
|
||||||
const site = this.getSite(hash.replace('#', '').trim())
|
|
||||||
this.el.innerHTML = _redirectView(site)
|
|
||||||
setTimeout(() => { window.location = site.url }, 3000)
|
|
||||||
} else {
|
|
||||||
this.el.innerHTML = _directory(this.sites)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.reload = function () {
|
|
||||||
setTimeout(() => { window.location.reload() }, 500)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.navigate = function (target) {
|
|
||||||
setTimeout(() => { window.location.href = target }, 3000)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.navLangs = [...new Set(navigator.languages.map(lang => lang.split('-').shift()))]
|
|
||||||
|
|
||||||
this.sitesMatchingLangs = this.sites
|
|
||||||
.filter(site => site.langs && site.langs.some(lang => this.navLangs.includes(lang)))
|
|
||||||
|
|
||||||
this.nextSiteIndex = (ceiling, index) => index === ceiling ? 0 : index + 1
|
|
||||||
this.randomSite = this.sitesMatchingLangs[Math.floor(Math.random() * this.sitesMatchingLangs.length)]
|
|
||||||
|
|
||||||
this.getSite = function (hash) {
|
|
||||||
if (hash === 'random') {
|
|
||||||
return this.randomSite
|
|
||||||
} else {
|
|
||||||
const index = this.sitesMatchingLangs.findIndex(site => site.url.includes(hash))
|
|
||||||
return (index > -1)
|
|
||||||
? this.sitesMatchingLangs[this.nextSiteIndex(this.sitesMatchingLangs.length, index)]
|
|
||||||
: this.randomSite
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterSites (e) {
|
|
||||||
e.preventDefault()
|
|
||||||
const navLink = e.target
|
|
||||||
const currentFilter = navLink.dataset.lang ? 'Lang' : 'Type'
|
|
||||||
|
|
||||||
document.querySelector(`nav a.current${currentFilter}`).classList.remove(`current${currentFilter}`)
|
|
||||||
navLink.classList.add(`current${currentFilter}`)
|
|
||||||
|
|
||||||
const typeFilter = document.querySelector('nav a.currentType').dataset.type
|
|
||||||
const langFilter = document.querySelector('nav a.currentLang').dataset.lang
|
|
||||||
|
|
||||||
const sites = document.querySelectorAll('main li')
|
|
||||||
sites.forEach(el => { el.style.display = 'block' })
|
|
||||||
|
|
||||||
sites.forEach(el => {
|
|
||||||
if (typeFilter !== 'all') {
|
|
||||||
if (el.dataset.type) {
|
|
||||||
if (el.dataset.type.trim() !== typeFilter) el.style.display = 'none'
|
|
||||||
} else {
|
|
||||||
el.style.display = 'none'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (langFilter !== 'all') {
|
|
||||||
if (!el.dataset.lang.includes(langFilter)) el.style.display = 'none'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const Progress = keys => {
|
|
||||||
const stack = new Set(keys.filter(key => key))
|
|
||||||
const loaded = new Set()
|
|
||||||
const failed = new Set()
|
|
||||||
|
|
||||||
this.ratio = () => {
|
|
||||||
return loaded.size / stack.size
|
|
||||||
}
|
|
||||||
|
|
||||||
this.percentage = () => {
|
|
||||||
return (100 * this.ratio()).toFixed(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
const render = () => `
|
|
||||||
<div class='${loaded.size !== stack.size ? 'busy' : 'done'}'>
|
|
||||||
<p>
|
|
||||||
${'|'.repeat(this.ratio() * 10)}
|
|
||||||
${loaded.size !== stack.size ? this.percentage() + '% ' : ''}
|
|
||||||
${loaded.size === stack.size ? 'Complete' : 'Loading'}
|
|
||||||
${failed.size !== 0 ? `(${failed.size} failed)` : ''}
|
|
||||||
</p>
|
|
||||||
</div>`
|
|
||||||
|
|
||||||
const didLoad = (key, success) => new Promise((resolve, reject) => {
|
|
||||||
if (stack.has(key)) {
|
|
||||||
loaded.add(key)
|
|
||||||
if (!success) failed.add(key)
|
|
||||||
return resolve()
|
|
||||||
} else {
|
|
||||||
return reject()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: key => didLoad(key, true),
|
|
||||||
failure: key => didLoad(key, false),
|
|
||||||
toString: render
|
|
||||||
}
|
|
||||||
}
|
|
924
scripts/sites.js
924
scripts/sites.js
@ -1,924 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const sites = [
|
|
||||||
{
|
|
||||||
author: 'neauoire',
|
|
||||||
contact: 'aliceffekt@gmail.com',
|
|
||||||
feed: 'https://wiki.xxiivv.com/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'https://wiki.xxiivv.com/links/rss.xml',
|
|
||||||
title: 'xxiivv',
|
|
||||||
type: 'wiki',
|
|
||||||
url: 'https://wiki.xxiivv.com',
|
|
||||||
wiki: 'https://wiki.xxiivv.com/src/database/glossary.ndtl'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'http://estevancarlos.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'rho',
|
|
||||||
feed: 'https://electro.pizza/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'electro pizza',
|
|
||||||
type: 'blog',
|
|
||||||
rss: 'https://electro.pizza/feed.xml',
|
|
||||||
url: 'https://electro.pizza'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'joshavanier',
|
|
||||||
contact: 'joshavanier@protonmail.com',
|
|
||||||
feed: 'https://avanier.now.sh/tw.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'Arachne',
|
|
||||||
type: 'wiki',
|
|
||||||
url: 'https://avanier.now.sh'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'kaemura',
|
|
||||||
contact: 'chimera1190@gmail.com',
|
|
||||||
feed: 'https://kaemura.com/twttxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'kaemura.com',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'http://kaemura.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'slisne',
|
|
||||||
contact: '@slisne@merveilles.town',
|
|
||||||
feed: 'https://liamcooke.com/merveilles/tw.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'liamcooke.com',
|
|
||||||
rss: 'https://liamcooke.com/feed.xml',
|
|
||||||
url: 'https://liamcooke.com',
|
|
||||||
wiki: 'https://liamcooke.com/merveilles/wiki.ndtl'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://hraew.autophagy.io'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'http://evenunto.net'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://anxl.faith'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'xvw',
|
|
||||||
contact: 'xaviervdw@gmail.com',
|
|
||||||
langs: ['fr'],
|
|
||||||
feed: 'https://xvw.github.io/twtxt/hallway.txt',
|
|
||||||
rss: 'https://xvw.github.io/atom.xml',
|
|
||||||
title: 'planet',
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://xvw.github.io'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en', 'el'],
|
|
||||||
url: 'https://heracl.es'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://turelio.github.io'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'lectronice',
|
|
||||||
contact: 'i.love.spam@lectronice.com',
|
|
||||||
feed: 'https://lectronice.com/hallway/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'shards',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://shards.lectronice.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://craze.co.uk'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://shaneckel.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'cblgh',
|
|
||||||
contact: 'cabal://cblgh.org',
|
|
||||||
feed: 'https://cblgh.org/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'cblgh.org',
|
|
||||||
url: 'https://cblgh.org'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'afk',
|
|
||||||
contact: 'afk@ellugar.co',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'http://feeds.ellugar.co/ellugar-logs',
|
|
||||||
title: 'ellugar',
|
|
||||||
type: 'wiki',
|
|
||||||
url: 'https://ellugar.co'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Cameron Higby-Naquin',
|
|
||||||
contact: 'me@chigby.org',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'chigby.org',
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'http://chigby.org'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://longest.voyage'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Paloma Kop',
|
|
||||||
contact: 'doubleobelisk@gmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'palomakop.tv',
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'https://palomakop.tv'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://v-os.ca'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://jmandel.xyz'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'jda0',
|
|
||||||
contact: 'hi@2d4.dev',
|
|
||||||
feed: 'https://2d4.dev/tw.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: '2d4.dev',
|
|
||||||
url: 'https://2d4.dev',
|
|
||||||
wiki: 'https://2d4.dev/wiki.ndtl'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://nathanwentworth.co'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://uonai.space'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'http://controls.ee'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://wasin.io'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://inns.studio'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'http://kokorobot.ca'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'jrc03c',
|
|
||||||
contact: 'josh@ameyama.com',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'ameyama',
|
|
||||||
type: 'blog',
|
|
||||||
rss: 'https://ameyama.com/blog/rss.xml',
|
|
||||||
url: 'https://ameyama.com',
|
|
||||||
wiki: 'https://ameyama.com/data/wiki.ndtl'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'wakest',
|
|
||||||
contact: '@liaizon@wake.st',
|
|
||||||
feed: 'https://wake.st/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'wake.st',
|
|
||||||
url: 'https://wake.st'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://xarene.la'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://alex.zyzhang.me'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'http://bildwissenschaft.vortok.info'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://jakofranko.github.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://aeriform.io'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en', 'de'],
|
|
||||||
url: 'http://blog.lucasdidthis.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'npisanti',
|
|
||||||
contact: 'nicola@npisanti.com',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'http://npisanti.com/journal/rss.xml',
|
|
||||||
title: 'npisanti.com',
|
|
||||||
url: 'http://npisanti.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://underscorediscovery.ca'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'drisc',
|
|
||||||
contact: 'cory@drisc.io',
|
|
||||||
feed: 'https://drisc.io/hallway/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'drisc.io',
|
|
||||||
type: 'wiki',
|
|
||||||
url: 'https://drisc.io'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://ricky.codes'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Marshall Bowers',
|
|
||||||
contact: 'elliott.codes@gmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'maxdeviant.com',
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://maxdeviant.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://tynandebold.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'http://gytis.co'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://nomand.co'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'http://memoriata.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://mmm.s-ol.nu'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
contact: 'ubuwaits@gmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'https://chad.is/rss.xml',
|
|
||||||
url: 'https://chad.is'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://smidgeo.com/bots'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en', 'ru'],
|
|
||||||
url: 'https://iko.soy'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'http://atelieroilandsugar.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://magoz.is'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Szymon Kaliski',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'https://szymonkaliski.com/feed.xml',
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://szymonkaliski.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'setphen',
|
|
||||||
feed: 'https://phse.net/twtxt/merv.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'https://phse.net/post/index.xml',
|
|
||||||
title: 'phse.net',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://phse.net'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'rosano',
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://rosano.ca',
|
|
||||||
wiki: 'https://rosano.ca/wiki.ndtl'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://soyboysky.github.io'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://gndclouds.cc'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en', 'fr'],
|
|
||||||
url: 'https://xuv.be'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en', 'zh'],
|
|
||||||
url: 'https://dsdshcym.github.io'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'ckipp',
|
|
||||||
contact: 'ckipp@pm.me',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'chris-kipp.io',
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://chris-kipp.io'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://boffosocko.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'kodedninja',
|
|
||||||
contact: 'karamanhunor@pm.me',
|
|
||||||
feed: 'https://t.seed.hex22.org/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'hex22',
|
|
||||||
url: 'https://hex22.org'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://patrikarvidsson.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://sophieleetmaa.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://xinniw.github.io'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'm',
|
|
||||||
contact: 'mboxxed@gmail.com',
|
|
||||||
feed: 'https://mboxed.github.io/sodatsu/tw.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'sodatsu',
|
|
||||||
type: 'wiki',
|
|
||||||
url: 'https://mboxed.github.io/sodatsu'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://letters.vexingworkshop.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'tomupom',
|
|
||||||
contact: 'tom@tomhackshaw.com',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'Tom Hackshaw',
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'https://tom.org.nz',
|
|
||||||
feed: 'https://a.tom.org.nz/twtxt.txt',
|
|
||||||
wiki: 'https://a.tom.org.nz/glossary.ndtl'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
title: 'Teknari',
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://teknari.com',
|
|
||||||
author: 'teknari',
|
|
||||||
contact: 'teknari@teknari.com',
|
|
||||||
rss: 'https://teknari.com/feed.xml'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'clic',
|
|
||||||
contact: 'https://t.me/clic_laplata',
|
|
||||||
langs: ['es'],
|
|
||||||
title: 'Colectivo de Livecoders',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://colectivo-de-livecoders.gitlab.io'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['es'],
|
|
||||||
title: 'madewithtea.com',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://www.madewithtea.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'amorris',
|
|
||||||
feed: 'https://feed.amorris.ca/hallway.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'amorris',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://amorris.ca',
|
|
||||||
wiki: 'https://wiki.amorris.ca/glossary.ndtl'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'miha-co',
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'http://www.miha-co.ca'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'buzzert',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'buzzert.net',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://buzzert.net'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'stuartpb',
|
|
||||||
contact: 's@stuartpb.com',
|
|
||||||
feed: 'https://twtxt.stuartpb.com/xxiivv.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'notes.stuartpb.com',
|
|
||||||
type: 'wiki',
|
|
||||||
url: 'https://notes.stuartpb.com/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'serocell',
|
|
||||||
contact: 'psignal@s900.net',
|
|
||||||
feed: 'https://xxiii.co/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'https://serocell.com/feeds/serocell.xml',
|
|
||||||
title: 'xxiii',
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'https://xxiii.co'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'kormyen',
|
|
||||||
contact: 'h@kor.nz',
|
|
||||||
feed: 'https://kor.nz/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'kor',
|
|
||||||
type: 'wiki',
|
|
||||||
url: 'https://kor.nz',
|
|
||||||
wiki: 'https://kor.nz/db/glossary.ndtl'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'quite',
|
|
||||||
contact: 'quite@hack.org',
|
|
||||||
feed: 'https://lublin.se/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://lublin.se'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'zanneth',
|
|
||||||
contact: 'root@zanneth.com',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'zanneth.com',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://zanneth.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'eli_oat',
|
|
||||||
contact: 'hi@eli.li',
|
|
||||||
feed: 'https://txt.eli.li/twtxt/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'https://eli.li/feed.rss',
|
|
||||||
title: 'eli.li',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://eli.li'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'gueorgui',
|
|
||||||
contact: 'hello@gueorgui.net',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'Gueorgui Tcherednitchenko',
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'https://gueorgui.net'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Tate Carson',
|
|
||||||
contact: 'tatecarson@gmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'Tate Carson',
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'https://www.tatecarson.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'azlen',
|
|
||||||
contact: 'webring@azlen.me',
|
|
||||||
feed: 'https://azlen.me/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'azlen.me',
|
|
||||||
type: 'wiki',
|
|
||||||
url: 'https://azlen.me',
|
|
||||||
wiki: 'https://azlen.me/glossary.ndtl'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'vega',
|
|
||||||
contact: 'vegac@protonmail.com',
|
|
||||||
feed: 'https://opinionatedguide.github.io/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'OpGuides',
|
|
||||||
url: 'https://opinionatedguide.github.io/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'cmaughan',
|
|
||||||
contact: 'mornymorny@gmail.com',
|
|
||||||
feed: 'https://chrismaughan.com/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'CMaughan',
|
|
||||||
url: 'https://chrismaughan.com/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'RaelZero',
|
|
||||||
contact: 'gaz.gong@gmail.com',
|
|
||||||
title: 'oddworlds soliloquy',
|
|
||||||
langs: ['en', 'es'],
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://oddworlds.org/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Fundor 333',
|
|
||||||
contact: 'blog@fundor333.com',
|
|
||||||
feed: 'https://fundor333.com/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'Fundor333',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://fundor333.com/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
contact: 'm@cass.si',
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://cass.si'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'dcb',
|
|
||||||
contact: 'dotcomboom@somnolescent.net',
|
|
||||||
feed: 'https://dotcomboom.somnolescent.net/twtxt.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'somnolescent.net',
|
|
||||||
url: 'https://dotcomboom.somnolescent.net/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Nihiltarier',
|
|
||||||
contact: 'arachi@airmail.cc',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'cadmican',
|
|
||||||
url: 'https://cadmican.neocities.org/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Jonathan Skjøtt',
|
|
||||||
contact: 'jonathan@jskjott.com',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'jskjott',
|
|
||||||
url: 'https://jskjott.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'sixeyes',
|
|
||||||
contact: 'elmusho@gmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'sixey.es',
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'https://sixey.es/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: '0xdstn',
|
|
||||||
contact: '0xdstn@protonmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
title: '0xdstn',
|
|
||||||
type: 'wiki',
|
|
||||||
url: 'https://tilde.town/~dustin/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'James',
|
|
||||||
contact: 'henderson.j@protonmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'https://jameschip.io/index.xml',
|
|
||||||
title: 'James Chip',
|
|
||||||
url: 'https://jameschip.io/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Patrick Monaghan',
|
|
||||||
contact: '0x5f.manpat@gmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'https://patrick-is.cool'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'icyphox',
|
|
||||||
contact: 'x@icyphox.sh',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'https://icyphox.sh/blog/feed.xml',
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://icyphox.sh'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'roy niang',
|
|
||||||
contact: 'roy@royniang.com',
|
|
||||||
feed: 'https://telecom.royniang.com/updates.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'roy niang',
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'https://royniang.com',
|
|
||||||
wiki: 'https://telecom.royniang.com/usefulnotes.ndtl'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'raul altosaar',
|
|
||||||
contact: 'raul.altosaar@gmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'raul altosaar',
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'https://www.raul.earth/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Cristi Constantin',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'https://crlf.site/feed.xml',
|
|
||||||
title: 'Cr;Lf;',
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://crlf.site'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
contact: 'johannesg@johannesg.com',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'Jóhannes Gunnar Þorsteinsson',
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://www.johannesg.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Michael Rupert',
|
|
||||||
contact: 'michaelrupert@fastmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'Provoke Analog',
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://provokeanalog.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'eti',
|
|
||||||
contact: 'eti@eti.tf',
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://eti.tf'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'rezmason',
|
|
||||||
contact: 'jeremysachs@rezmason.net',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'rezmason.net',
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://rezmason.net'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
contact: 'email@estfyr.net',
|
|
||||||
langs: ['en', 'cz'],
|
|
||||||
title: 'estfyr.net',
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://estfyr.net'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Payson Wallach',
|
|
||||||
contact: 'payson@paysonwallach.com',
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://paysonwallach.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'icco',
|
|
||||||
contact: 'nat@natwelch.com',
|
|
||||||
langs: ['en'],
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'https://natwelch.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'whtrbt',
|
|
||||||
contact: 'pi@benjamin.gray.land',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'Park Imminent',
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://parkimminent.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'aklsh',
|
|
||||||
contact: 'akileshkannan@gmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://aklsh.github.io',
|
|
||||||
type: 'hybrid'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'hxii',
|
|
||||||
contact: 'paul@glushak.net',
|
|
||||||
langs: ['en'],
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://paulglushak.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'syx',
|
|
||||||
contact: 'hello@simone.computer',
|
|
||||||
langs: ['en', 'ita'],
|
|
||||||
title: 'Simone\'s Computer',
|
|
||||||
type: 'portfolio',
|
|
||||||
url: 'https://simone.computer'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'xj9',
|
|
||||||
contact: 'xj9@sunshinegardens.org',
|
|
||||||
feed: 'https://xj9.io/.well-known/webring/tw.txt',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'dreamspace',
|
|
||||||
type: 'blog',
|
|
||||||
rss: 'https://xj9.io/rss.xml',
|
|
||||||
url: 'https://xj9.io',
|
|
||||||
wiki: 'https://xj9.io/.well-known/webring/wiki.ndtl'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
contact: 'joe.jenett@jenett.org',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'https://simply.personal.jenett.org/feed',
|
|
||||||
title: 'jenett. simply. personal.',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://simply.personal.jenett.org'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Wally',
|
|
||||||
contact: 'qpfiffer+xxiivvwebring@gmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
rss: 'http://q.pfiffer.org/feed.xml',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'http://q.pfiffer.org/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'ashpex',
|
|
||||||
contact: 'ashpex@dismail.de',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'ashpex',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://ashpex.neocities.org'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'zvava',
|
|
||||||
contact: 'notminin@pm.me',
|
|
||||||
langs: ['en'],
|
|
||||||
title: 'zvava',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://zvava.org/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Amorphous',
|
|
||||||
contact: 'dl.amorphous@gmail.com',
|
|
||||||
langs: ['en'],
|
|
||||||
url: 'https://amorphic.space'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Edwin Wenink',
|
|
||||||
contact: 'edwinwenink@hotmail.com',
|
|
||||||
langs: ['en', 'nl'],
|
|
||||||
rss: 'https://www.edwinwenink.xyz/index.xml',
|
|
||||||
title: 'Archive Fever',
|
|
||||||
type: 'blog',
|
|
||||||
url: 'https://www.edwinwenink.xyz/'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'Anne-Laure Le Cunff',
|
|
||||||
contact: 'alecunff@gmail.com',
|
|
||||||
langs: ['en', 'fr'],
|
|
||||||
rss: 'https://www.mentalnodes.com/sitemap.xml',
|
|
||||||
title: 'Mental Nodes',
|
|
||||||
type: 'hybrid',
|
|
||||||
url: 'https://www.mentalnodes.com'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
author: 'librenauta',
|
|
||||||
contact: 'librenauta@riseup.net',
|
|
||||||
langs: ['es'],
|
|
||||||
title: 'copiona',
|
|
||||||
type: 'blog, hybrid',
|
|
||||||
url: 'https://copiona.com'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
/*
|
|
||||||
Make sure you've read the README!
|
|
||||||
Don't forget the comma on the previous entry!
|
|
||||||
No trailing slashes or commas!
|
|
||||||
Alphabetize your keys!
|
|
||||||
protocol://url.domain.ext
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (module && module.exports) {
|
|
||||||
module.exports = sites
|
|
||||||
}
|
|
176
scripts/wiki.js
176
scripts/wiki.js
@ -1,176 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const Wiki = sites => {
|
|
||||||
const entries = {}
|
|
||||||
const main = document.getElementById('main')
|
|
||||||
const aside = document.getElementById('aside')
|
|
||||||
const progress = document.getElementById('progress')
|
|
||||||
const progressCounter = Progress(sites.map(site => site.wiki))
|
|
||||||
const authors = new Set()
|
|
||||||
const terms = new Set()
|
|
||||||
|
|
||||||
const encodeUrl = text => text.replace(/ /g, '+').trim().toLowerCase()
|
|
||||||
|
|
||||||
const cleanEntry = entry => {
|
|
||||||
const temp = document.createElement('div')
|
|
||||||
temp.textContent = entry
|
|
||||||
return temp.innerHTML
|
|
||||||
}
|
|
||||||
|
|
||||||
const storeEntry = (author, url, category, term, unCleanEntry) => {
|
|
||||||
const entry = Array.isArray(unCleanEntry)
|
|
||||||
? unCleanEntry.map(x => cleanEntry(x))
|
|
||||||
: cleanEntry(unCleanEntry)
|
|
||||||
|
|
||||||
if (!(category in entries)) {
|
|
||||||
entries[category] = {}
|
|
||||||
entries[category][term] = [{ entry, authors: [{ author, url }] }]
|
|
||||||
} else if (!(term in entries[category])) {
|
|
||||||
entries[category][term] = [{ entry, authors: [{ author, url }] }]
|
|
||||||
} else {
|
|
||||||
const possibleIndex = entries[category][term].findIndex(existing => existing.entry === entry)
|
|
||||||
possibleIndex > -1
|
|
||||||
? entries[category][term][possibleIndex].authors.push({ author, url })
|
|
||||||
: entries[category][term].push({ entry, authors: [{ author, url }] })
|
|
||||||
}
|
|
||||||
terms.add(term)
|
|
||||||
authors.add(author)
|
|
||||||
}
|
|
||||||
|
|
||||||
const storeEntries = (author, url, category, entries) => {
|
|
||||||
Array.isArray(entries)
|
|
||||||
? storeEntry(author, url, category, `${category}-list-definition`, entries)
|
|
||||||
: Object.keys(entries).forEach(entry => storeEntry(author, url, category, entry, entries[entry]))
|
|
||||||
}
|
|
||||||
|
|
||||||
const transform = (author, url, ndtl) => {
|
|
||||||
Object.keys(ndtl).forEach(category => storeEntries(author, url, category, ndtl[category]))
|
|
||||||
}
|
|
||||||
|
|
||||||
const parse = (site, content) => {
|
|
||||||
console.log('Wiki', 'Parsing ' + site.wiki)
|
|
||||||
const ndtl = indental(content)
|
|
||||||
transform(site.author, site.url, ndtl)
|
|
||||||
}
|
|
||||||
|
|
||||||
const selected = (key, category) => key.toLowerCase() === category.toLowerCase()
|
|
||||||
? 'selected'
|
|
||||||
: ''
|
|
||||||
|
|
||||||
const randomTerm = () => {
|
|
||||||
const keys = Object.keys(entries)
|
|
||||||
return keys[Math.floor(Math.random() * keys.length)]
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatSideBarCat = (key, entries) => (currentHtml, cat) => {
|
|
||||||
const catLength = Object.keys(entries[cat]).length
|
|
||||||
const newHtml = `<li class='${selected(key, cat)}'}'>
|
|
||||||
<a href='#${encodeUrl(cat)}' data-msgs='${catLength}'>${cat.toLowerCase()}</a>
|
|
||||||
</li>`
|
|
||||||
return `${currentHtml}${newHtml}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatLinks = text => text.replace(
|
|
||||||
/\b((https?|dat):\/\/[^"\s]+)/g,
|
|
||||||
'<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>'
|
|
||||||
)
|
|
||||||
|
|
||||||
const formatAuthor = (authors, author) => {
|
|
||||||
return `${authors}<a class='author' target='_blank' href='${author.url}'> @${author.author}</a>`
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatEntry = (definitions, definition) => {
|
|
||||||
const formatEntryList = entryList => entryList.reduce((items, item) => `${items}<li>${formatLinks(item)}</li>`, '')
|
|
||||||
|
|
||||||
const newHtml = typeof definition.entry === 'string'
|
|
||||||
? `<li>${formatLinks(definition.entry)}
|
|
||||||
- ${definition.authors.reduce(formatAuthor, '')}
|
|
||||||
</li>`
|
|
||||||
: `<li><ul>${formatEntryList(definition.entry)}
|
|
||||||
- ${definition.authors.reduce(formatAuthor, '')}
|
|
||||||
</ul></li>`
|
|
||||||
|
|
||||||
return `${definitions}${newHtml}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatEntries = entries => (currentHtml, category) => {
|
|
||||||
const definitions = entries[category].reduce(formatEntry, '')
|
|
||||||
const title = category.endsWith('list-definition')
|
|
||||||
? ''
|
|
||||||
: `<li class='name'><strong>${category.toLowerCase()}</strong></li>`
|
|
||||||
return `${currentHtml}<ul class='term'>${title}${definitions}</ul>`
|
|
||||||
}
|
|
||||||
|
|
||||||
const findRelated = key => {
|
|
||||||
const searchOtherCategories = entry => {
|
|
||||||
return Object.keys(entries)
|
|
||||||
.filter(category => Object.keys(entries[category]).some(otherCat => otherCat === entry))
|
|
||||||
}
|
|
||||||
|
|
||||||
const foundMatches = Object.keys(entries[key])
|
|
||||||
.filter(entry => !entry.endsWith('list-definition'))
|
|
||||||
.map(searchOtherCategories)
|
|
||||||
const flattened = [].concat.apply([], foundMatches)
|
|
||||||
return Array.from(new Set(flattened)).filter(related => related !== key)
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatRelated = (allRelated, relatedCategory) => {
|
|
||||||
const newHtml = `<span><a href='#${encodeUrl(relatedCategory)}'>/${relatedCategory.toLowerCase()}</a> </span>`
|
|
||||||
return `${allRelated}${newHtml}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const refresh = key => {
|
|
||||||
if (key) {
|
|
||||||
if (entries[key] === undefined) return
|
|
||||||
const items = Object.keys(entries[key]).sort().reduce(formatEntries(entries[key]), '')
|
|
||||||
const relatedCategories = findRelated(key)
|
|
||||||
const relatedHtml = relatedCategories.length > 0
|
|
||||||
? relatedCategories.reduce(formatRelated, 'Related categories: ')
|
|
||||||
: ''
|
|
||||||
main.innerHTML = `<div class='related'><h1>${key}</h1>${relatedHtml}</div>${items}`
|
|
||||||
} else {
|
|
||||||
const html = `Click a /topic to get started, or try a <a href='#${randomTerm()}'>random page</a>`
|
|
||||||
const stats = `The wiki contains ${terms.size} terms in ${Object.keys(entries).length} categories, from ${authors.size} authors.`
|
|
||||||
main.innerHTML = `<h1>WIKI</h1>${html}<br />${stats}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const homeCat = `<li class='${selected(key, '')}'>
|
|
||||||
<a href='#' data-msgs='${terms.size}'>home</a>
|
|
||||||
</li>`
|
|
||||||
const cats = Object.keys(entries).sort().reduce(formatSideBarCat(key, entries), homeCat)
|
|
||||||
aside.innerHTML = `<ul>${cats}</ul>`
|
|
||||||
}
|
|
||||||
|
|
||||||
const refreshProgress = () => {
|
|
||||||
progress.innerHTML = `${progressCounter}`
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
initialize: hash => {
|
|
||||||
console.log('Wiki', 'Fetching...')
|
|
||||||
refreshProgress()
|
|
||||||
sites.filter(site => site.wiki && site.author).forEach(site => {
|
|
||||||
fetch(site.wiki, { cache: 'no-store' }).then(x => x.text()).then(content => {
|
|
||||||
parse(site, content)
|
|
||||||
refresh(stripHash(hash))
|
|
||||||
progressCounter.success(site.wiki).then(refreshProgress)
|
|
||||||
}).catch((err) => {
|
|
||||||
console.warn(`${site.wiki}`, err)
|
|
||||||
progressCounter.failure(site.wiki).then(refreshProgress)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
refresh: key => { refresh(key) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const decodeUrl = text => text.replace(/\+/g, ' ').trim().toUpperCase()
|
|
||||||
|
|
||||||
const stripHash = hash => {
|
|
||||||
const decoded = decodeURIComponent(hash)
|
|
||||||
return decoded.charAt(0) === '#' ? decodeUrl(decoded.substring(1)) : decoded
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('hashchange', () => {
|
|
||||||
wiki.refresh(stripHash(window.location.hash))
|
|
||||||
})
|
|
@ -1,22 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
// extract twtxt feeds from sites.js
|
|
||||||
|
|
||||||
const fs = require('fs')
|
|
||||||
const sites = require('../scripts/sites.js')
|
|
||||||
const record = { following: {} }
|
|
||||||
|
|
||||||
for (const site of sites) {
|
|
||||||
if (!site.author || !site.feed) { continue }
|
|
||||||
record.following[site.author] = site.feed
|
|
||||||
}
|
|
||||||
|
|
||||||
const json = JSON.stringify(record)
|
|
||||||
|
|
||||||
fs.writeFile('twtxt.json', json, 'utf8', (err) => {
|
|
||||||
if (err) {
|
|
||||||
console.log('An error occured while writing JSON Object to File.')
|
|
||||||
return console.log(err)
|
|
||||||
}
|
|
||||||
console.log('Done.')
|
|
||||||
})
|
|
@ -1 +0,0 @@
|
|||||||
{"following":{"neauoire":"https://wiki.xxiivv.com/twtxt.txt","rho":"https://electro.pizza/twtxt.txt","joshavanier":"https://avanier.now.sh/tw.txt","kaemura":"https://kaemura.com/twttxt.txt","slisne":"https://liamcooke.com/merveilles/tw.txt","xvw":"https://xvw.github.io/twtxt/hallway.txt","lectronice":"https://lectronice.com/hallway/twtxt.txt","cblgh":"https://cblgh.org/twtxt.txt","jda0":"https://2d4.dev/tw.txt","wakest":"https://wake.st/twtxt.txt","drisc":"https://drisc.io/hallway/twtxt.txt","setphen":"https://phse.net/twtxt/merv.txt","kodedninja":"https://t.seed.hex22.org/twtxt.txt","m":"https://mboxed.github.io/sodatsu/tw.txt","tomupom":"https://a.tom.org.nz/twtxt.txt","amorris":"https://feed.amorris.ca/hallway.txt","stuartpb":"https://twtxt.stuartpb.com/xxiivv.txt","serocell":"https://xxiii.co/twtxt.txt","kormyen":"https://kor.nz/twtxt.txt","quite":"https://lublin.se/twtxt.txt","eli_oat":"https://txt.eli.li/twtxt/twtxt.txt","azlen":"https://azlen.me/twtxt.txt","vega":"https://opinionatedguide.github.io/twtxt.txt","cmaughan":"https://chrismaughan.com/twtxt.txt","Fundor 333":"https://fundor333.com/twtxt.txt","dcb":"https://dotcomboom.somnolescent.net/twtxt.txt","roy niang":"https://telecom.royniang.com/updates.txt","xj9":"https://xj9.io/.well-known/webring/tw.txt"}}
|
|
33
wiki.html
33
wiki.html
@ -1,33 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="stylesheet" type="text/css" href="links/fonts.css"/>
|
|
||||||
<link rel="stylesheet" type="text/css" href="links/main.css"/>
|
|
||||||
<script type="text/javascript">const module = { exports:{} }</script>
|
|
||||||
<script src="scripts/progress.js"></script>
|
|
||||||
<script src="scripts/wiki.js"></script>
|
|
||||||
<script src="scripts/sites.js"></script>
|
|
||||||
<script src="scripts/indental.js"></script>
|
|
||||||
<script src="scripts/opml.js"></script>
|
|
||||||
<title>Wiki</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="wiki">
|
|
||||||
<main>
|
|
||||||
<div id="main"></div>
|
|
||||||
<aside id="aside"></aside>
|
|
||||||
</main>
|
|
||||||
<footer id="footer">
|
|
||||||
<p>The <strong>Wiki</strong> is a decentralized encyclopedia, to join the conversation, add a <a href="https://github.com/XXIIVV/webring#joining-the-wiki">wiki:</a> field to your entry in the <a href="https://github.com/XXIIVV/Webring/">webring</a>.</p>
|
|
||||||
<p class='buttons'><a href='https://github.com/XXIIVV/webring'>Information</a> | <a href="hallway.html">The Hallway</a> | <a href="index.html">The Portal</a> | <a id="opml">OPML</a></p>
|
|
||||||
<div id="progress"></div>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
const wiki = Wiki(sites)
|
|
||||||
wiki.initialize(window.location.hash)
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Loading…
Reference in New Issue
Block a user