feat: cms integration

This commit is contained in:
Cory Dransfeldt 2024-06-01 07:16:49 -07:00
parent ff77bdaf36
commit d23243b177
No known key found for this signature in database
1050 changed files with 1032 additions and 27229 deletions

View file

@ -16,7 +16,7 @@ export default async function () {
image,
release_date,
release_link,
artists (name_string, genre, mbid, country)
artists (name_string, mbid, country)
`)
.gt('release_date', today)
@ -31,8 +31,7 @@ export default async function () {
title: album['name'],
date: DateTime.fromISO(album['release_date']).toLocaleString(DateTime.DATE_FULL),
url: album['release_link'],
artist_url: `https://coryd.dev/music/artists/${sanitizeMediaString(album['artists']['name_string'])}-${sanitizeMediaString(parseCountryField(album['artists']['country']))}`,
genre: album['artists']['genre'],
artist_url: `/music/artists/${sanitizeMediaString(album['artists']['name_string'])}-${sanitizeMediaString(parseCountryField(album['artists']['country']))}`,
mbid: album['artists']['mbid'],
timestamp: DateTime.fromISO(album['release_date']).toSeconds()
}

View file

@ -1,8 +1,8 @@
import { createClient } from '@supabase/supabase-js'
import { parseCountryField } from '../../config/utilities/index.js'
const SUPABASE_URL = process.env.SUPABASE_URL || 'YOUR_SUPABASE_URL'
const SUPABASE_KEY = process.env.SUPABASE_KEY || 'YOUR_SUPABASE_KEY'
const SUPABASE_URL = process.env.SUPABASE_URL
const SUPABASE_KEY = process.env.SUPABASE_KEY
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
const PAGE_SIZE = 50
@ -36,13 +36,29 @@ const fetchPaginatedData = async (table, selectFields) => {
return data
}
export default async function () {
const artists = await fetchPaginatedData('artists', 'mbid, name_string, image, genre, total_plays, country, description, favorite')
const albums = await fetchPaginatedData('albums', 'mbid, name, release_year, artist_mbid, total_plays')
const fetchGenreMapping = async () => {
const { data, error } = await supabase
.from('genres')
.select('id, name')
if (error) {
console.error('Error fetching genres:', error)
return {}
}
return data.reduce((acc, genre) => {
acc[genre.id] = genre.name
return acc
}, {})
}
export default async function () {
const genreMapping = await fetchGenreMapping()
const artists = await fetchPaginatedData('artists', 'id, mbid, name_string, image, total_plays, country, description, favorite, genres')
const albums = await fetchPaginatedData('albums', 'mbid, name, release_year, total_plays, artist')
const albumsByArtist = albums.reduce((acc, album) => {
if (!acc[album.artist_mbid]) acc[album.artist_mbid] = []
acc[album.artist_mbid].push({
if (!acc[album.artist]) acc[album.artist] = []
acc[album.artist].push({
id: album.id,
name: album.name,
release_year: album.release_year,
@ -51,10 +67,11 @@ export default async function () {
return acc
}, {})
artists.forEach(artist => {
artist.albums = albumsByArtist[artist.mbid]?.sort((a, b) => a['release_year'] - b['release_year']) || []
for (const artist of artists) {
artist.albums = albumsByArtist[artist.id]?.sort((a, b) => a['release_year'] - b['release_year']) || []
artist.country = parseCountryField(artist.country)
})
artist.genres = genreMapping[artist.genres] || ''
}
return artists
}

View file

@ -1,30 +1,77 @@
import { createRequire } from 'module'
import { createClient } from '@supabase/supabase-js'
const require = createRequire(import.meta.url)
const books = require('./json/read.json')
const SUPABASE_URL = process.env.SUPABASE_URL
const SUPABASE_KEY = process.env.SUPABASE_KEY
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
const PAGE_SIZE = 1000
const fetchTagsForBook = async (bookId) => {
const { data, error } = await supabase
.from('books_tags')
.select('tags(id, name)')
.eq('books_id', bookId)
if (error) {
console.error(`Error fetching tags for book ${bookId}:`, error)
return []
}
return data.map(bt => bt.tags.name)
}
async function fetchAllBooks() {
let books = []
let from = 0
let to = PAGE_SIZE - 1
while (true) {
const { data, error } = await supabase
.from('books')
.select('*')
.range(from, to)
if (error) {
console.error('Error fetching data from Supabase:', error)
break
}
for (const book of data) {
book.tags = await fetchTagsForBook(book.id)
}
books = books.concat(data)
if (data.length < PAGE_SIZE) break
from += PAGE_SIZE
to += PAGE_SIZE
}
return books
}
export default async function () {
const books = await fetchAllBooks()
return books.map(book => {
let authors = ''
let date = book?.['dateAdded']
if (book['authors']?.length > 1) authors = book['authors'].join(', ')
if (book['authors']?.length === 1) authors = book['authors'][0]
if (book?.['dateStarted']) date = book['dateStarted']
if (book?.['dateFinished']) date = book['dateFinished']
const author = book['author'] || ''
let date = book?.['date_finished']
if (book?.['date_started']) date = book['date_started']
if (book?.['date_finished']) date = book['date_finished']
return {
title: book['title'],
authors,
author,
description: book['description'],
image: book['thumbnail'],
url: `https://coryd.dev/books/${book['isbn']}`,
url: `/books/${book['isbn']}`,
date,
status: book['status'],
tags: book['tags'],
categories: book['categories']?.length > 1 ? book['categories'].join(', ') : book['categories']?.[0],
rating: book['rating'] !== 'unrated' ? book['rating'] : '',
isbn: book['isbn'],
type: 'book',
}
})
}
}

View file

@ -1,8 +1,8 @@
import { createClient } from '@supabase/supabase-js'
import { parseCountryField } from '../../config/utilities/index.js'
const SUPABASE_URL = process.env.SUPABASE_URL || 'YOUR_SUPABASE_URL'
const SUPABASE_KEY = process.env.SUPABASE_KEY || 'YOUR_SUPABASE_KEY'
const SUPABASE_URL = process.env.SUPABASE_URL
const SUPABASE_KEY = process.env.SUPABASE_KEY
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
export default async function fetchGenresWithArtists() {

File diff suppressed because it is too large Load diff

View file

@ -3,42 +3,42 @@ export default {
{
title: 'Stay True',
authors: 'Hua Hsu',
image: 'https://coryd.dev/media/books/9780385547772-stay-true.jpg',
image: '/media/books/9780385547772-stay-true.jpg',
url: 'https://openlibrary.org/isbn/9780593663660',
type: 'book',
},
{
title: 'Where Are Your Boys Tonight?',
authors: 'Chris Payne',
image: 'https://coryd.dev/media/books/9780063251281-where-are-your-boys-tonight.jpg',
image: '/media/books/9780063251281-where-are-your-boys-tonight.jpg',
url: 'https://openlibrary.org/isbn/9780063161573',
type: 'book',
},
{
title: 'Trouble Boys',
authors: 'Bob Mehr',
image: 'https://coryd.dev/media/books/0306818795-trouble-boys.jpg',
image: '/media/books/0306818795-trouble-boys.jpg',
url: 'https://openlibrary.org/isbn/9780306818790',
type: 'book',
},
{
title: 'Corporate Rock Sucks',
authors: 'Jim Ruland',
image: 'https://coryd.dev/media/books/9780306925481-corporate-rock-sucks.jpg',
image: '/media/books/9780306925481-corporate-rock-sucks.jpg',
url: 'https://openlibrary.org/isbn/9780306925474',
type: 'book',
},
{
title: 'Tracers in the Dark',
authors: 'Andy Greenberg',
image: 'https://coryd.dev/media/books/0593315618-tracers-in-the-dark.jpg',
image: '/media/books/0593315618-tracers-in-the-dark.jpg',
url: 'http://openlibrary.org/isbn/9780385548106',
type: 'book',
},
{
title: 'Girl in a Band',
authors: 'Kim Gordon',
image: 'https://coryd.dev/media/books/9780062295897-kim-gordon-girl-in-a-band.jpg',
image: '/media/books/9780062295897-kim-gordon-girl-in-a-band.jpg',
url: 'https://openlibrary.org/isbn/9780062295910',
type: 'book',
}
@ -47,56 +47,56 @@ export default {
{
title: 'the whaler',
artist: 'home is where',
image: 'https://coryd.dev/media/albums/home-is-where-the-whaler.jpg',
image: '/media/albums/home-is-where-the-whaler.jpg',
url: 'https://musicbrainz.org/release-group/6fe3516f-c324-4265-8f43-d902f3a4cc20',
type: 'album',
},
{
title: 'The Enduring Spirit',
artist: 'Tomb Mold',
image: 'https://coryd.dev/media/albums/tomb-mold-the-enduring-spirit.jpg',
image: '/media/albums/tomb-mold-the-enduring-spirit.jpg',
url: 'https://musicbrainz.org/release-group/cd3e5dfb-acca-4856-80f6-2e095ac3270d',
type: 'album',
},
{
title: 'A Dialogue With The Eeriest Sublime',
artist: 'Vertebra Atlantis',
image: 'https://coryd.dev/media/albums/vertebra-atlantis-a-dialogue-with-the-eeriest-sublime.jpg',
image: '/media/albums/vertebra-atlantis-a-dialogue-with-the-eeriest-sublime.jpg',
url: 'https://musicbrainz.org/release-group/b8f1913b-f461-443c-a26c-377b259f2af6',
type: 'album',
},
{
title: 'ONE MORE TIME...',
artist: 'blink-182',
image: 'https://coryd.dev/media/albums/blink-182-one-more-time.jpg',
image: '/media/albums/blink-182-one-more-time.jpg',
url: 'https://musicbrainz.org/release-group/520d6d45-19c8-4ee1-a954-180e7902f3da',
type: 'album',
},
{
title: 'Life Like',
artist: 'Dead Bob',
image: 'https://coryd.dev/media/albums/dead-bob-life-like.jpg',
image: '/media/albums/dead-bob-life-like.jpg',
url: 'https://musicbrainz.org/release-group/ab53e625-74af-4a09-a8ff-e1c08dbae596',
type: 'album',
},
{
title: 'Threads of Unknowing',
artist: 'VoidCeremony',
image: 'https://coryd.dev/media/albums/voidceremony-threads-of-unknowing.jpg',
image: '/media/albums/voidceremony-threads-of-unknowing.jpg',
url: 'https://musicbrainz.org/release-group/f1f91cde-ff57-41c8-bd58-28c236b3f0c6',
type: 'album',
},
{
title: 'Why Would I Watch',
artist: 'Hot Mulligan',
image: 'https://coryd.dev/media/albums/hot-mulligan-why-would-i-watch.jpg',
image: '/media/albums/hot-mulligan-why-would-i-watch.jpg',
url: 'https://musicbrainz.org/release-group/5afd31ea-3a96-4b99-a477-4d121efaedec',
type: 'album',
},
{
title: 'Losing What We Love',
artist: 'Knuckle Puck',
image: 'https://coryd.dev/media/albums/knuckle-puck-losing-what-we-love.jpg',
image: '/media/albums/knuckle-puck-losing-what-we-love.jpg',
url: 'https://musicbrainz.org/release-group/b51d8882-3854-400a-b79b-4353a77a389b',
type: 'album',
}

55
src/_data/links.js Normal file
View file

@ -0,0 +1,55 @@
import { createClient } from '@supabase/supabase-js'
const SUPABASE_URL = process.env.SUPABASE_URL
const SUPABASE_KEY = process.env.SUPABASE_KEY
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
const PAGE_SIZE = 50
const fetchTagsForLink = async (linkId) => {
const { data, error } = await supabase
.from('links_tags')
.select('tags(id, name)')
.eq('links_id', linkId)
if (error) {
console.error(`Error fetching tags for link ${linkId}:`, error)
return []
}
return data.map((lt) => lt.tags.name)
}
const fetchAllLinks = async () => {
let links = []
let page = 0
let fetchMore = true
while (fetchMore) {
const { data, error } = await supabase
.from('links')
.select('*, authors (name, url)')
.order('date', { ascending: false })
.range(page * PAGE_SIZE, (page + 1) * PAGE_SIZE - 1)
if (error) {
console.error('Error fetching links:', error)
return links
}
if (data.length < PAGE_SIZE) fetchMore = false
for (const link of data) {
link.tags = await fetchTagsForLink(link.id)
}
links = links.concat(data)
page++
}
return links
}
export default async function () {
return await fetchAllLinks()
}

View file

@ -51,7 +51,7 @@ export default async function () {
lastWatched: item['last_watched'],
dateAdded: item['last_watched'],
year: item['year'],
url: `https://coryd.dev/watching/movies/${item['tmdb_id']}`,
url: `/watching/movies/${item['tmdb_id']}`,
description: `${item['title']} (${item['year']})<br/>Watched at: ${DateTime.fromISO(item['last_watched'], { zone: 'utc' }).setZone('America/Los_Angeles').toFormat('MMMM d, yyyy, h:mma')}`,
image: `https://coryd.dev/media/movies/poster-${item['tmdb_id']}.jpg`,
backdrop: `https://coryd.dev/media/movies/backdrops/backdrop-${item['tmdb_id']}.jpg`,
@ -76,6 +76,5 @@ export default async function () {
recentlyWatched: formatMovieData(recentlyWatchedMovies),
favorites: formatMovieData(favoriteMovies).sort((a, b) => a['title'].localeCompare(b['title'])),
collection: formatMovieData(collectedMovies),
toWatch: formatMovieData(movies, false).sort((a, b) => a['title'].localeCompare(b['title'])),
}
}

View file

@ -59,8 +59,25 @@ const fetchAllTimeData = async (fields, table) => {
return rows
}
const fetchGenreMapping = async () => {
const { data, error } = await supabase
.from('genres')
.select('id, name')
if (error) {
console.error('Error fetching genres:', error)
return {}
}
return data.reduce((acc, genre) => {
acc[genre.id] = genre.name
return acc
}, {})
}
const aggregateData = (data, groupByField, groupByType) => {
const aggregation = {}
const genreMapping = fetchGenreMapping()
data.forEach(item => {
const key = item[groupByField]
@ -70,21 +87,21 @@ const aggregateData = (data, groupByField, groupByType) => {
title: item[groupByField],
plays: 0,
mbid: item['albums']['mbid'],
url: `https://coryd.dev/music/artists/${sanitizeMediaString(item['artist_name'])}-${sanitizeMediaString(parseCountryField(item['artists']['country']))}`,
url: `/music/artists/${sanitizeMediaString(item['artist_name'])}-${sanitizeMediaString(parseCountryField(item['artists']['country']))}`,
image: item['albums']?.['image'] || '',
timestamp: item['listened_at'],
type: groupByType,
genre: item['artists']?.['genre'] || ''
genre: genreMapping[item['artists']['genre']] || ''
}
} else {
aggregation[key] = {
title: item[groupByField],
plays: 0,
mbid: item[groupByType]?.['mbid'] || '',
url: `https://coryd.dev/music/artists/${sanitizeMediaString(item['artist_name'])}-${sanitizeMediaString(parseCountryField(item['artists']['country']))}`,
url: `/music/artists/${sanitizeMediaString(item['artist_name'])}-${sanitizeMediaString(parseCountryField(item['artists']['country']))}`,
image: item[groupByType]?.image || '',
type: groupByType,
genre: item['artists']?.['genre'] || ''
genre: genreMapping[item['artists']['genre']] || ''
}
}
if (
@ -106,11 +123,11 @@ const aggregateData = (data, groupByField, groupByType) => {
const aggregateGenres = (data) => {
const genreAggregation = {}
const genreMapping = fetchGenreMapping()
data.forEach(item => {
const genre = item.artists.genre
if (!genreAggregation[genre]) {
genreAggregation[genre] = { genre, plays: 0 }
}
const genre = genreMapping[item['artists']['genre']] || ''
if (!genreAggregation[genre]) genreAggregation[genre] = { genre, plays: 0 }
genreAggregation[genre]['plays']++
})
return Object.values(genreAggregation).sort((a, b) => b['plays'] - a['plays'])
@ -130,7 +147,7 @@ export default async function() {
album_name,
album_key,
listened_at,
artists (mbid, image, genre, country),
artists (mbid, image, genres, country),
albums (mbid, image)
`

62
src/_data/posts.js Normal file
View file

@ -0,0 +1,62 @@
import { createClient } from '@supabase/supabase-js'
import { DateTime } from 'luxon'
import slugify from 'slugify'
const SUPABASE_URL = process.env.SUPABASE_URL
const SUPABASE_KEY = process.env.SUPABASE_KEY
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
const PAGE_SIZE = 50
const fetchTagsForPost = async (postId) => {
const { data, error } = await supabase
.from('posts_tags')
.select('tags(id, name)')
.eq('posts_id', postId)
if (error) {
console.error(`Error fetching tags for post ${postId}:`, error)
return []
}
return data.map(pt => pt.tags.name)
}
const fetchAllPosts = async () => {
let posts = []
let page = 0
let fetchMore = true
while (fetchMore) {
const { data, error } = await supabase
.from('posts')
.select('*')
.order('date', { ascending: false })
.range(page * PAGE_SIZE, (page + 1) * PAGE_SIZE - 1)
if (error) {
console.error('Error fetching posts:', error)
return posts
}
if (data.length < PAGE_SIZE) fetchMore = false
for (const post of data) {
post.tags = await fetchTagsForPost(post.id)
post.url = `/posts/${DateTime.fromISO(post.date).year}/${slugify(post.title, {
replacement: '-',
remove: /[#,&,+()$~%.'":*?<>{}\[\]\/\\|`!@\^\—]/g,
lower: true,
})}/`
}
posts = posts.concat(data)
page++
}
return posts
}
export default async function () {
return await fetchAllPosts()
}

View file

@ -90,14 +90,14 @@ export default async function () {
showEpisodesMap[showTmdbId].episodes.push({
name: showTitle,
url: `https://coryd.dev/watching/shows/${showTmdbId}`,
url: `/watching/shows/${showTmdbId}`,
subtext: `${showTitle} • S${seasonNumber}E${episodeNumber}`,
episode: episodeNumber,
season: seasonNumber,
tmdbId: showTmdbId,
type: 'tv',
image: `https://coryd.dev/media/shows/poster-${showTmdbId}.jpg`,
backdrop: `https://coryd.dev/media/shows/backdrops/backdrop-${showTmdbId}.jpg`,
image: `/media/shows/poster-${showTmdbId}.jpg`,
backdrop: `/media/shows/backdrops/backdrop-${showTmdbId}.jpg`,
dateAdded: lastWatchedAt,
lastWatchedAt
})
@ -114,7 +114,7 @@ export default async function () {
if (show.episodes.length > 1) {
episodeData.push({
name: show.title,
url: `https://coryd.dev/watching/shows/${show['tmdbId']}`,
url: `/watching/shows/${show['tmdbId']}`,
subtext: `S${startingSeason}E${startingEpisode} - S${endingSeason}E${endingEpisode}`,
startingEpisode,
startingSeason,
@ -124,8 +124,8 @@ export default async function () {
collected: show['collected'],
favorite: show['favorite'],
type: 'tv-range',
image: `https://coryd.dev/media/shows/poster-${show['tmdbId']}.jpg`,
backdrop: `https://coryd.dev/media/shows/backdrops/backdrop-${show['tmdbId']}.jpg`,
image: `/media/shows/poster-${show['tmdbId']}.jpg`,
backdrop: `/media/shows/backdrops/backdrop-${show['tmdbId']}.jpg`,
})
} else {
const singleEpisode = show['episodes'][0]
@ -140,7 +140,7 @@ export default async function () {
const favoriteShows = shows.filter(show => show['favorite'])
const collectedShows = shows.filter(show => show['collected'])
const toWatch = shows.map(show => ({...show, url: `https://coryd.dev/watching/shows/${show['tmdb_id']}`})).filter(show => !show.episodes.some(episode => episode.last_watched_at)).sort((a, b) => a['title'].localeCompare(b['title']))
const toWatch = shows.map(show => ({...show, url: `/watching/shows/${show['tmdb_id']}`})).filter(show => !show.episodes.some(episode => episode.last_watched_at)).sort((a, b) => a['title'].localeCompare(b['title']))
return {
shows,

View file

@ -25,7 +25,7 @@
{%- assign pageDescription = meta.siteDescription -%}
{%- if schema == 'blog' -%}
{%- assign pageDescription = post_excerpt | markdown | strip_html -%}
{%- assign pageDescription = post.description | markdown | strip_html -%}
{%- elsif artist.description -%}
{%- assign pageDescription = artist.description | truncate: 300 -%}
{%- elsif book.description -%}
@ -42,9 +42,6 @@
{%- assign ogImage = meta.meta_data.opengraph_default -%}
{%- case schema -%}
{%- when 'blog' -%}
{%- assign ogBlogSlug = title | slugifyString -%}
{%- assign ogImage = meta.url | append: '/assets/img/ogi/' | append: ogBlogSlug | append: '-preview.png' -%}
{%- when 'music' -%}
{%- assign ogImage = music.recent.artists[0].image -%}
{%- when 'music-index' -%}

View file

@ -10,7 +10,7 @@
"id": "{{ entry.url | btoa }}",
"title": "{{ entry.title | replaceQuotes }}",
"url": "{{ entry.url }}",
"content_text": "{{ entry.title | replaceQuotes }}{% if entry.url | tagLookup: tagMap %} {{ entry.url | tagLookup: tagMap }} {{ entry.url }}{% else %} {{ entry.url }}{% endif %}",
"content_text": "{{ entry.title | replaceQuotes }} {{ entry.url }}",
"date_published": "{{ entry.date | stringToRFC822Date }}"
}{% if not forloop.last %},{% endif %}
{%- endfor %}

View file

@ -15,17 +15,16 @@
<height>144</height>
</image>
{% for entry in entries limit: 20 -%}
{% assign author = entry.url | stripUtm | authorLookup %}
{% assign rating = entry.rating %}
<item>
<title>
{{ entry.title | escape }}
{% if author %} via {{ author }}{% endif %}
{% if entry.authors %} via {{ entry.authors.name }}{% endif %}
{% if rating %} ({{ rating }}){% endif %}
</title>
<link>{{ entry.url | stripUtm | encodeAmp }}</link>
<link>{{ entry.url | encodeAmp }}</link>
<pubDate>{{ entry.date | stringToRFC822Date }}</pubDate>
<guid>{{ entry.url | stripUtm | encodeAmp }}</guid>
<guid>{{ entry.url | encodeAmp }}</guid>
<description>{{ entry.excerpt | escape }}</description>
</item>
{%- endfor %}

View file

@ -1,7 +1,7 @@
{%- assign posts = postData | filterByPostType: postType %}
<div class="article-widget-wrapper">
<div class="section-header-wrapper">
<h2 id="artists" class="section-header posts flex-centered">
<h2 class="section-header posts flex-centered">
{% tablericon icon title %}
{{ title }}
</h2>
@ -15,11 +15,11 @@
</time>
</div>
<a href="{{ post.url }}">
<h2 class="flex-centered">{{ post.data.title }}</h2>
<h2 class="flex-centered">{{ post.title }}</h2>
</a>
<span class="p-author h-card hidden">{{ meta.siteName }}</span>
<div class="p-summary hidden">{{ post.data.post_excerpt }}</div>
{{ post.data.post_excerpt | markdown | truncateByWordCount: 25 }}
{{ post.description | truncate: 300 }}
</article>
{% endfor %}
{% if postType != 'featured' %}

View file

@ -3,7 +3,7 @@
<div class="media-grid {% if shape == 'square' %}square{% else %}vertical{% endif %}">
{% for item in media limit: count | default: media.size %}
{% assign alt = item.alt | strip | escape %}
<a href="{{ item.url | stripUtm }}" title="{{ alt }}">
<a href="{{ item.url }}" title="{{ alt }}">
<div class="item-wrapper shadow">
<div class="meta-text">
{% if item.title %}

View file

@ -1,14 +1,14 @@
{% assign posts = posts | getPopularPosts: analytics %}
{% if posts.size > 0 %}
{% assign postData = posts | getPopularPosts: analytics %}
{% if postData.size > 0 %}
<h2 class="link-list-header flex-centered">
{% tablericon "flame" "Popular" %}
Popular posts
</h2>
<ul class="link-list">
{% for post in posts limit: 5 %}
{% for post in postData limit: 5 %}
<li>
<a class="no-underline" href="{{post.url}}" title="{{ post.data.title | escape}}">
{{ post.data.title }}
<a class="no-underline" href="{{ post.url }}" title="{{ post.title | escape}}">
{{ post.title }}
</a>
</li>
{% endfor %}

View file

@ -5,12 +5,11 @@
</h2>
<ul class="link-list">
{% for link in links limit: 5 %}
{% assign author = link.data.link | stripUtm | authorLookup %}
<li>
<a href="{{ link.data.link }}" title="{{ link.data.title | escape }}">
{{ link.data.title }}
<a href="{{ link.link }}" title="{{ link.title | escape }}">
{{ link.title }}
</a>
{% if author %} via {{ author }}{% endif %}
{% if link.authors %} via <a href="{{ link.authors.url }}">{{ link.authors.name }}</a>{% endif %}
</li>
{% endfor %}
</ul>

View file

@ -1,4 +0,0 @@
<script type="module" src="/assets/scripts/components/webcare-webshare.js"></script>
<webcare-webshare share-text="{{ title }} {{ url | tagLookup: tagMap }}" share-url="{{ url }}" copy-text="{{ title }} {{ url | tagLookup: tagMap }} {{ url }}">
<button class="share icon-small icon-center-vertical" disabled>{% tablericon "share" "Share" %}</button>
</webcare-webshare>

View file

@ -1,6 +0,0 @@
{% assign filteredTags = tags | filterTags %}
<div{% if hasSpace %} style="margin-bottom:var(--sizing-md)"{% endif %}>
{% for tag in filteredTags limit: 10 %}
<a class="tag-element" href="/tags/{{ tag | downcase }}">{{ tag | formatTag }}</a>
{% endfor %}
</div>

View file

@ -7,21 +7,19 @@ schema: blog
<div class="default-wrapper">
<article class="h-entry">
<div class="flex-centered gap-xs icon-small icon-light">
{% render "partials/widgets/share-button.liquid", url:postUrl, title:title, tagMap:collections.tagMap %}
{% tablericon "calendar-month" "Date" %}
<time class="dt-published" datetime="{{ date }}">
{{ date | date: "%B %e, %Y" }}
</time>
</div>
<h2 class="p-name">{{ title }}</h2>
<div class="text-small">{% render "partials/widgets/tags.liquid", tags:tags %}</div>
<span class="p-author h-card hidden">{{ meta.author }}</span>
<div class="p-summary hidden">{{ post_excerpt }}</div>
<div class="p-summary hidden">{{ post.description }}</div>
<div class="e-content">
{% render "partials/banners/old-post.liquid", date:date %}
{% render "partials/banners/old-post.liquid", date:post.date %}
{{ content }}
</div>
</article>
</div>
{% render "partials/widgets/mastodon-post.liquid", postUrl:postUrl, linkPosts:linkPosts %}
{% render "partials/widgets/addon-links.liquid", posts:collections.posts, analytics:analytics, links:collections.links %}
{% render "partials/widgets/addon-links.liquid", posts:posts, analytics:analytics, links:collections.links %}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Some files were not shown because too many files have changed in this diff Show more