~ d e s i g n ~

This commit is contained in:
wryk 2020-01-07 19:23:49 +01:00
commit 8633b8534b
8 changed files with 7575 additions and 0 deletions

7
.babelrc Normal file
View File

@ -0,0 +1,7 @@
{
"plugins": [
["@babel/plugin-transform-runtime", {
"corejs": 3
}]
]
}

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
node_modules
dist
.cache
.env

7392
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

27
package.json Normal file
View File

@ -0,0 +1,27 @@
{
"name": "eldritch-cafe-radio",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "parcel src/index.html",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.7.7",
"@babel/plugin-transform-runtime": "^7.7.6",
"parcel": "^1.12.4",
"parcel-plugin-svelte": "^4.0.5",
"svelte": "^3.16.7"
},
"dependencies": {
"@babel/runtime-corejs3": "^7.7.7",
"get-urls": "^9.2.0"
},
"browserslist": [
"last 1 chrome versions"
]
}

92
src/App.svelte Normal file
View File

@ -0,0 +1,92 @@
<main class="app">
<header class="header">
<h1>
Eldritch Radio
</h1>
</header>
<section class="player">
{#if selectedEntry}
Playing <a href={selectedEntry.url}>{selectedEntry.url}</a>
{:else}
Loading ...
{/if}
</section>
<section class="queue">
{#await entriesPromise}
Loading radio please wait
{:then entries}
<ul>
{#each entries as entry}
<li>
<a href={entry.url}>{entry.url}</a>
<small>{entry.tags}</small>
</li>
{/each}
</ul>
{:catch error}
Oops, something went wrong : {error}
{/await}
<header>
<a href="https://{domain}/">{domain}</a> - {@html hashtags.map(hashtag => `<a href="https://${domain}/tags/${hashtag}">#${hashtag}</a>`)}
</header>
</section>
</main>
<script>
import { onMount } from 'svelte';
import { fetchEntries } from './util.js'
export let domain
export let hashtags
let entriesPromise = new Promise(() => {})
let selectedEntry = null
onMount(() => {
entriesPromise = fetchEntries(domain, hashtags)
entriesPromise.then(entries => {
[selectedEntry] = entries
})
})
</script>
<style>
.app {
display: grid;
grid-template-columns: 1fr;
grid-template-areas:
"header"
"player"
"queue";
}
.header {
grid-area: header;
}
.player {
grid-area: player;
}
.queue {
grid-area: queue;
}
@media (min-width: 992px) {
.app {
grid-template-columns: 2fr 3fr;
grid-template-rows: auto 1fr;
grid-template-areas:
"header queue"
"player queue"
}
}
</style>

12
src/index.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="main.js"></script>
</body>
</html>

16
src/main.js Normal file
View File

@ -0,0 +1,16 @@
import App from './App.svelte'
const app = new App({
target: document.body,
props: {
domain: 'eldritch.cafe',
hashtags: [
'np',
'nowplaying',
'tootradio',
'pouetradio'
]
}
})
export default app

25
src/util.js Normal file
View File

@ -0,0 +1,25 @@
import getUrls from 'get-urls'
export async function fetchEntries(domain, hashtags) {
const response = await fetch(`https://${domain}/api/v1/timelines/tag/${hashtags[0]}`)
const statuses = await response.json()
const entries = statuses
.map(status => {
const [url] = Array.from(getUrls(status.content)).filter(isSupportedUrl)
const tags = intersection(status.tags.map(tag => tag.name), hashtags)
return { status, url, tags }
})
.filter(entry => entry.url != null)
return entries
}
function isSupportedUrl(url) {
return (new URL(url)).hostname === 'youtube.com'
}
function intersection(xs, ys) {
return xs.filter(x => ys.includes(x));
}