🛠 Podcast categories and player

This commit is contained in:
Dennis Reimann
2020-10-05 16:34:52 +02:00
parent 7507cd5249
commit 11a56902cb
13 changed files with 228 additions and 25 deletions

5
package-lock.json generated
View File

@@ -130,6 +130,11 @@
} }
} }
}, },
"amplitudejs": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/amplitudejs/-/amplitudejs-5.2.0.tgz",
"integrity": "sha512-1Bfl62RfOQElS+5mHyS/ubD8WmgFPzLNMVQmGjQv/mIHGG2KLehic7ayikNkua5Hw3fq0HDJlLVo6/bfdlqGOg=="
},
"ansi-font": { "ansi-font": {
"version": "0.0.2", "version": "0.0.2",
"resolved": "https://registry.npmjs.org/ansi-font/-/ansi-font-0.0.2.tgz", "resolved": "https://registry.npmjs.org/ansi-font/-/ansi-font-0.0.2.tgz",

View File

@@ -11,13 +11,13 @@
"scripts": { "scripts": {
"clean": "rm -rf dist generated && mkdir -p dist generated", "clean": "rm -rf dist generated && mkdir -p dist generated",
"fetch": "node tasks/fetch_feed.js", "fetch": "node tasks/fetch_feed.js",
"start": "npm-run-all clean fetch -p start:*", "start": "npm-run-all clean fetch -p build:static start:*",
"start:pages": "onchange -i -k 'pug.config.js' 'markdown.js' 'content/**' 'generated/**' 'src/**/*.pug' 'src/**/*.svg' 'tasks/generate_pages.js' -- npm run build:pages", "start:pages": "onchange -i -k 'pug.config.js' 'markdown.js' 'content/**' 'generated/**' 'src/**/*.pug' 'src/**/*.svg' 'tasks/generate_pages.js' -- npm run build:pages",
"start:styles": "onchange -i -k 'src/**/*.css' -- npm run build:styles", "start:styles": "onchange -i -k 'src/**/*.css' -- npm run build:styles",
"start:data": "onchange -i -k 'content/**/*' -- npm run build:data", "start:data": "onchange -i -k 'content/**/*' -- npm run build:data",
"start:serve": "browser-sync start --config browser-sync.config.js --watch", "start:serve": "browser-sync start --config browser-sync.config.js --watch",
"build": "npm-run-all clean fetch -p build:*", "build": "npm-run-all clean fetch -p build:*",
"build:static": "cp -r static/* dist", "build:static": "cp -r static/* dist && cp node_modules/amplitudejs/dist/amplitude.min.js dist/js/amplitude.js",
"build:data": "node tasks/generate_site_data.js", "build:data": "node tasks/generate_site_data.js",
"build:pages": "node tasks/generate_pages.js", "build:pages": "node tasks/generate_pages.js",
"build:styles": "postcss src/css/main.css --output dist/css/main.css", "build:styles": "postcss src/css/main.css --output dist/css/main.css",
@@ -27,6 +27,9 @@
"prod": "npm-run-all build optimize -s build:pages", "prod": "npm-run-all build optimize -s build:pages",
"images": "node tasks/optimize_images.js" "images": "node tasks/optimize_images.js"
}, },
"dependencies": {
"amplitudejs": "5.2.0"
},
"devDependencies": { "devDependencies": {
"autoprefixer": "10.0.1", "autoprefixer": "10.0.1",
"browser-sync": "2.26.12", "browser-sync": "2.26.12",

16
src/category.pug Normal file
View File

@@ -0,0 +1,16 @@
extends /template.pug
block main
- const current = episodes.shift()
section#podcast
h1.centered= categoryName
h2.centered Aktuelle Episode
.current
+episodePlayer(current).centered
h2.centered Weitere Episoden
.episodes
each e in episodes
+episodeItem(e)

View File

@@ -19,8 +19,8 @@
.main { .main {
flex: 1; flex: 1;
padding-top: var(--space-xl); padding-top: var(--space-xxl);
padding-bottom: var(--space-xl); padding-bottom: var(--space-xxl);
& h1, & h1,
& h2 { & h2 {
@@ -28,6 +28,12 @@
color: var(--color-secondary); color: var(--color-secondary);
} }
& .centered {
text-align: center;
margin-left: auto;
margin-righht: auto;
}
& .lead { & .lead {
margin-bottom: var(--space-xxl); margin-bottom: var(--space-xxl);
} }

View File

@@ -25,7 +25,7 @@
--space-m: .5rem; --space-m: .5rem;
--space-l: 1rem; --space-l: 1rem;
--space-xl: 2rem; --space-xl: 2rem;
--space-xxl: 4rem; --space-xxl: 3rem;
--transition-duration-fast: 0.25s; --transition-duration-fast: 0.25s;
--transition-duration-medium: 0.75s; --transition-duration-medium: 0.75s;

View File

@@ -1,12 +1,42 @@
#podcast { #podcast {
& .categories {
display: inline-flex;
flex-wrap: wrap;
list-style: none;
margin: 0 0 var(--space-xxl) 0;
& li {
margin: 0 var(--space-m) var(--space-m) 0;
}
& a {
display: inline-block;
text-align: center;
padding: var(--space-s) var(--space-l);
color: var(--color-neutral-0);
text-decoration: none;
border-radius: var(--space-xl);
border: 1px solid var(--color-secondary);
&:hover {
@media not all and (hover: none) {
color: var(--color-neutral-0);
background-color: var(--color-secondary);
text-decoration: none;
}
}
}
}
& .current {
margin-bottom: 4rem;
}
} }
.episodes { .episodes {
display: grid; display: grid;
grid-gap: var(--space-xl); grid-gap: var(--space-xl);
grid-template-columns: 1fr; grid-template-columns: 1fr;
margin: 0;
list-style: none;
@media (--up_to_L) { @media (--up_to_L) {
grid-template-columns: 1fr; grid-template-columns: 1fr;
@@ -28,7 +58,6 @@
padding: var(--space-xl); padding: var(--space-xl);
} }
& a { & a {
display: flex; display: flex;
} }
@@ -76,3 +105,82 @@
line-height: 1.2; line-height: 1.2;
} }
} }
.player {
margin: 0 auto;
border-radius: var(--space-m);
overflow: hidden;
min-width: 300px;
max-width: 480px;
}
.player__cover{
display:block;
width:100%
}
.player__bottom {
color: var(--color-body-text);
background-color: var(--color-card-bg);
padding-bottom: var(--space-l);
}
.player__progress{
display: block;
background-color: rgba(255,255,255,.25);
appearance:none;
width: 100%;
height: var(--space-m);
margin-bottom: var(--space-m);
cursor:pointer;
border:none
}
.player__progress[value] {
-webkit-appearance: none;
}
.player__progress::-webkit-progress-bar{
background-color: var(--color-secondary);
}
.player__progress::-moz-progress-bar,
.player__progress::-webkit-progress-value {
background-color: var(--color-accent);
}
.player__time{
display:flex;
justify-content:space-between;
margin:.5em 0 .75em;
padding:0 .5em;
opacity:.5;
font-size: var(--font-size-s);
}
.player__current-time{
margin-left:var(--space-m);
}
.player__duration{
margin-right:var(--space-m);
}
.player__controls{
display:flex;
align-items: center;
margin-top: var(--space-m);
padding: 0 var(--space-l);
}
.player__button{
width:70px;
height:70px;
margin-right:var(--space-l);
background-size:cover;
background-repeat:no-repeat;
cursor:pointer
}
.player__button.amplitude-paused{
background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzUiIGhlaWdodD0iNzUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMSAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48Y2lyY2xlIHN0cm9rZT0iIzQyNDM1RiIgY3g9IjM2LjUiIGN5PSIzNi41IiByPSIzNi41Ii8+PHBhdGggZD0iTTQ3LjYzIDM1LjhMMjcuNjQgMjMuNDNjLTEuNDYtLjk2LTIuNjUtLjI2LTIuNjUgMS41NlY0OWMwIDEuODEgMS4xOSAyLjUyIDIuNjUgMS41Nkw0Ny42MyAzOC4ycy43LS41LjctMS4yLS43LTEuMi0uNy0xLjJ6IiBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L2c+PC9zdmc+)
}
.player__button.amplitude-playing{
background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzUiIGhlaWdodD0iNzUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMSAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48Y2lyY2xlIHN0cm9rZT0iIzQyNDM1RiIgY3g9IjM2LjUiIGN5PSIzNi41IiByPSIzNi41Ii8+PHBhdGggZD0iTTMwLjUyIDIzSDI2LjJBMi4yIDIuMiAwIDAgMCAyNCAyNS4ydjIzLjZjMCAxLjIxLjk4IDIuMiAyLjIgMi4yaDQuMzJhMi4yIDIuMiAwIDAgMCAyLjE5LTIuMlYyNS4yYTIuMiAyLjIgMCAwIDAtMi4xOS0yLjJ6TTQ2LjkgMjNoLTQuMzJhMi4yIDIuMiAwIDAgMC0yLjE5IDIuMnYyMy42YzAgMS4yMS45OCAyLjIgMi4xOSAyLjJoNC4zM2EyLjIgMi4yIDAgMCAwIDIuMTktMi4yVjI1LjJjMC0xLjIxLS45OC0yLjItMi4yLTIuMnoiIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvZz48L3N2Zz4=)
}
.player__info{
flex:1;
text-align: left;
}
.player__album{
color:var(--color-secondary);
}

View File

@@ -13,6 +13,46 @@ mixin episodeItem(e)
time(datetime=e.date)= e.block || formatDate(e.date) time(datetime=e.date)= e.block || formatDate(e.date)
h3=e.titlePlain h3=e.titlePlain
mixin episodePlayer(e)
.player.player--single&attributes(attributes)
img.player__cover(src=imgLarge data-amplitude-song-info="cover_art_url" data-amplitude-main-song-info="true")
.player__bottom
progress.player__progress.amplitude-song-played-progress(data-amplitude-main-song-played-progress="true")
.player__time
span.player__current-time
span.player__current-minutes.amplitude-current-minutes(data-amplitude-main-current-minutes="true")
= ':'
span.player__current-seconds.amplitude-current-seconds(data-amplitude-main-current-seconds="true")
span.player__duration
span.player__duration-hours.amplitude-duration-hours(data-amplitude-main-duration-hours="true")
= ':'
span.player__duration-minutes.amplitude-duration-minutes(data-amplitude-main-duration-minutes="true")
= ':'
span.player__duration-seconds.amplitude-duration-seconds(data-amplitude-main-duration-seconds="true")
.player__controls
.player__button.amplitude-play-pause(data-amplitude-main-play-pause="true" id="play-pause")
.player__info
.player__album(data-amplitude-song-info="album" data-amplitude-main-song-info="true")
.player__name(data-amplitude-song-info="name" data-amplitude-main-song-info="true")
script.
window.Einundzwanzig = {
amplitude: {
songs: [
{
"name": "#{e.titlePlain}",
"artist": "Einundzwanzig",
"album": "#{e.categoryName + (e.number ? ` #${e.number}` : '')}",
"url": "#{e.enclosure.url}",
"cover_art_url": "#{e.image}"
}
]
}
};
mixin episodeDetails(e) mixin episodeDetails(e)
article.episodeDetails&attributes(attributes) article.episodeDetails&attributes(attributes)
.media .media

View File

@@ -62,4 +62,5 @@ html(lang="en")
.wrap .wrap
p Craig Wright is a fraud. p Craig Wright is a fraud.
script(src=assetPath("/js/main.js")) script(src=assetPath("/js/amplitude.js") defer)
script(src=assetPath("/js/main.js") defer)

View File

@@ -1,18 +1,32 @@
extends /template.pug extends /template.pug
block main block main
- const current = episodes.shift()
section#podcast section#podcast
.lead .lead.centered
h1 Podcast h1 Podcast
:markdown-it(html linkify typographer) :markdown-it(html linkify typographer)
Du findest unsere Episoden auf den üblichen Plattformen wie Du findest uns auf
[Spotify](https://open.spotify.com/show/10408JFbE1n8MexfrBv33r), [Spotify](https://open.spotify.com/show/10408JFbE1n8MexfrBv33r),
[Apple Podcasts](https://podcasts.apple.com/de/podcast/einundzwanzig-der-bitcoin-podcast/id1488229907), [Apple Podcasts](https://podcasts.apple.com/de/podcast/einundzwanzig-der-bitcoin-podcast/id1488229907),
[Overcast](https://overcast.fm/itunes1488229907/einundzwanzig-der-bitcoin-podcast) und [Overcast](https://overcast.fm/itunes1488229907/einundzwanzig-der-bitcoin-podcast) und
[Anchor](https://anchor.fm/einundzwanzig). [Anchor](https://anchor.fm/einundzwanzig).
a.button(href="https://anchor.fm/s/d8d3c38/podcast/rss") Abonnieren / RSS a.button(href="https://anchor.fm/s/d8d3c38/podcast/rss") Abonnieren / RSS
h2 Alle Episoden .centered
h2 Kategorien
ul.categories
li: a(href="/podcast/news") News
li: a(href="/podcast/interviews") Interviews
li: a(href="/podcast/lesestunde") Lesestunde
li: a(href="/podcast/der-weg") Der Weg
h2.centered Aktuelle Episode
.current
+episodePlayer(current).centered
h2.centered Weitere Episoden
.episodes .episodes
each e in episodes each e in episodes
+episodeItem(e) +episodeItem(e)

View File

@@ -2,7 +2,6 @@ extends /template.pug
block main block main
section#team section#team
.lead
h1 Team h1 Team
ul.members(data-shuffle) ul.members(data-shuffle)
each m in shuffle(team) each m in shuffle(team)

View File

@@ -42,4 +42,15 @@ document.addEventListener("DOMContentLoaded", () => {
list.innerHTML = "" list.innerHTML = ""
shuffle(items).forEach(item => list.appendChild(item)) shuffle(items).forEach(item => list.appendChild(item))
}) })
// Player
if (window.Einundzwanzig.amplitude && window.Amplitude) {
window.Amplitude.init(window.Einundzwanzig.amplitude)
document.querySelector('.player__progress').addEventListener('click', function (e) {
var offset = this.getBoundingClientRect()
var x = e.pageX - offset.left
window.Amplitude.setSongPlayedPercentage((parseFloat(x) / parseFloat(this.offsetWidth)) * 100)
})
}
}) })

View File

@@ -38,10 +38,4 @@ const parseInfo = e => {
})) }))
write('episodes', episodes) write('episodes', episodes)
// By category/season
write('news', episodes.filter(e => e.category === 'news'))
write('der-weg', episodes.filter(e => e.category === 'der-weg'))
write('interview', episodes.filter(e => e.category === 'interview'))
write('lesestunde', episodes.filter(e => e.category === 'lesestunde'))
})() })()

View File

@@ -7,11 +7,12 @@ const site = require('../generated/site-data.json')
const episodes = require('../generated/episodes.json') const episodes = require('../generated/episodes.json')
const team = require('../content/team.json') const team = require('../content/team.json')
const renderPage = (name, out, data = {}) => { const renderPage = (template, out, data = {}) => {
const file = resolve(__dirname, '..', `src/${name}.pug`) const file = resolve(__dirname, '..', `src/${template}.pug`)
const options = Object.assign({}, config, { site }, data) const options = Object.assign({}, config, { site }, data)
const rendered = pug.renderFile(file, options) const rendered = pug.renderFile(file, options)
const dst = resolve(__dirname, '..', 'dist', `${out}.html`) const dest = out === 'index' ? 'index.html' : `${out}/index.html`
const dst = resolve(__dirname, '..', 'dist', dest)
const dir = dirname(dst) const dir = dirname(dst)
mkdirSync(dir, { recursive: true }) mkdirSync(dir, { recursive: true })
@@ -19,5 +20,10 @@ const renderPage = (name, out, data = {}) => {
} }
renderPage('index', 'index', { navCurrent: 'index' }) renderPage('index', 'index', { navCurrent: 'index' })
renderPage('team', 'team/index', { navCurrent: 'team', team }) renderPage('team', 'team', { navCurrent: 'team', team })
renderPage('podcast', 'podcast/index', { navCurrent: 'podcast', episodes }) renderPage('podcast', 'podcast', { navCurrent: 'podcast', episodes: [...episodes] })
renderPage('category', 'podcast/news', { navCurrent: 'podcast', categoryName: 'News', episodes: episodes.filter(e => e.category === 'news') })
renderPage('category', 'podcast/interviews', { navCurrent: 'podcast', categoryName: 'Interviews', episodes: episodes.filter(e => e.category === 'interview') })
renderPage('category', 'podcast/lesestunde', { navCurrent: 'podcast', categoryName: 'Lesestunde', episodes: episodes.filter(e => e.category === 'lesestunde') })
renderPage('category', 'podcast/der-weg', { navCurrent: 'podcast', categoryName: 'Der Weg', episodes: episodes.filter(e => e.category === 'der-weg') })