Skip to content

Commit

Permalink
add blog (#163)
Browse files Browse the repository at this point in the history
  • Loading branch information
jchavarri authored Feb 9, 2024
1 parent f295d1e commit ace187e
Show file tree
Hide file tree
Showing 25 changed files with 2,593 additions and 1 deletion.
37 changes: 37 additions & 0 deletions .github/workflows/deploy-blog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: deploy blog

on:
push:
branches:
- master
tags-ignore:
- 'v*'

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: yarn
- name: Build blog
run: make build-blog
- name: Configure Git user
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
- name: Fetch and checkout gh-pages
run: |
git fetch origin gh-pages --depth=1
git checkout gh-pages
- name: Copy published site into folder
run: mv blog blog2 && cp -TRv blog2/.vitepress/dist/ blog/
- name: Add blog files to git index
run: git add blog
- name: Committing
run: git commit -m 'Deployed blog from ${{ github.sha }}'
- name: Push
run: git push
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: check and deploy
name: check and deploy docs and playground

on:
push:
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,7 @@ build-playground: ## Builds the playground
.PHONY: build-site
build-site: build-playground ## Builds the whole site (including playground)
yarn && yarn docs:build

.PHONY: build-blog
build-blog: ## Builds the blog
cd blog && yarn && yarn build
3 changes: 3 additions & 0 deletions blog/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
.vitepress/cache
4 changes: 4 additions & 0 deletions blog/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
semi: false
singleQuote: true
printWidth: 80
trailingComma: none
10 changes: 10 additions & 0 deletions blog/.vitepress/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineConfig } from 'vitepress'
import { genFeed } from './genFeed.js'

export default defineConfig({
title: 'Sandtracks',
description: 'The official blog for the Melange project',
cleanUrls: true,
base: '/blog/',
buildEnd: genFeed
})
50 changes: 50 additions & 0 deletions blog/.vitepress/genFeed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import path from 'path'
import { writeFileSync } from 'fs'
import { Feed } from 'feed'
import { createContentLoader, type SiteConfig } from 'vitepress'

const baseUrl = `https://melange.re/blog`

export async function genFeed(config: SiteConfig) {
const feed = new Feed({
title: 'Sandtracks',
description: 'The official blog for the Melange project',
id: baseUrl,
link: baseUrl,
language: 'en',
copyright:
'Copyright (c) 2021-present, Melange blog contributors'
})

const posts = await createContentLoader('posts/*.md', {
excerpt: true,
render: true
}).load()

posts.sort(
(a, b) =>
+new Date(b.frontmatter.date as string) -
+new Date(a.frontmatter.date as string)
)

for (const { url, excerpt, frontmatter, html } of posts) {
feed.addItem({
title: frontmatter.title,
id: `${baseUrl}${url}`,
link: `${baseUrl}${url}`,
description: excerpt,
content: html?.replaceAll('​', ''),
author: [
{
name: frontmatter.author,
link: frontmatter.twitter
? `https://twitter.com/${frontmatter.twitter}`
: undefined
}
],
date: frontmatter.date
})
}

writeFileSync(path.join(config.outDir, 'feed.rss'), feed.rss2())
}
73 changes: 73 additions & 0 deletions blog/.vitepress/theme/Article.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<script setup lang="ts">
import Date from './Date.vue'
import Author from './Author.vue'
import { computed } from 'vue'
import { useData, useRoute } from 'vitepress'
import { data as posts } from './posts.data.js'
const { frontmatter: data } = useData()
const route = useRoute()
function findCurrentIndex() {
return posts.findIndex((p) => p.url === route.path)
}
// use the customData date which contains pre-resolved date info
const date = computed(() => posts[findCurrentIndex()].date)
const nextPost = computed(() => posts[findCurrentIndex() - 1])
const prevPost = computed(() => posts[findCurrentIndex() + 1])
</script>

<template>
<article class="xl:divide-y xl:divide-gray-200 dark:xl:divide-slate-200/5">
<header class="pt-6 xl:pb-10 space-y-1 text-center">
<Date :date="date" />
<h1
class="text-3xl leading-9 font-extrabold text-gray-900 dark:text-white tracking-tight sm:text-4xl sm:leading-10 md:text-5xl md:leading-14"
>
{{ data.title }}
</h1>
</header>

<div
class="divide-y xl:divide-y-0 divide-gray-200 dark:divide-slate-200/5 xl:grid xl:grid-cols-4 xl:gap-x-10 pb-16 xl:pb-20"
style="grid-template-rows: auto 1fr"
>
<Author />
<div
class="divide-y divide-gray-200 dark:divide-slate-200/5 xl:pb-0 xl:col-span-3 xl:row-span-2"
>
<Content class="prose dark:prose-invert max-w-none pt-10 pb-8" />
</div>

<footer
class="text-sm font-medium leading-5 divide-y divide-gray-200 dark:divide-slate-200/5 xl:col-start-1 xl:row-start-2"
>
<div v-if="nextPost" class="py-8">
<h2
class="text-xs tracking-wide uppercase text-gray-500 dark:text-white"
>
Next Article
</h2>
<div class="link">
<a :href="nextPost.url">{{ nextPost.title }}</a>
</div>
</div>
<div v-if="prevPost" class="py-8">
<h2
class="text-xs tracking-wide uppercase text-gray-500 dark:text-white"
>
Previous Article
</h2>
<div class="link">
<a :href="prevPost.url">{{ prevPost.title }}</a>
</div>
</div>
<div class="pt-8">
<a class="link" href="/blog">← Back to the blog</a>
</div>
</footer>
</div>
</article>
</template>
45 changes: 45 additions & 0 deletions blog/.vitepress/theme/Author.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<script setup lang="ts">
import { useData } from 'vitepress'
const { frontmatter } = useData()
</script>

<template>
<dl class="pt-6 pb-10 xl:pt-11 xl:border-b xl:border-gray-200 dark:xl:border-slate-200/5">
<dt class="sr-only">Authors</dt>
<dd>
<ul
class="flex justify-center xl:block space-x-8 sm:space-x-12 xl:space-x-0 xl:space-y-8"
>
<li class="flex items-center space-x-2">
<img
v-if="frontmatter.gravatar"
:src="'https://gravatar.com/avatar/' + frontmatter.gravatar"
alt="author image"
class="w-10 h-10 rounded-full"
/>
<img
v-else-if="frontmatter.avatar"
:src="frontmatter.avatar"
alt="author image"
class="w-10 h-10 rounded-full"
/>
<dl class="text-sm font-medium leading-5 whitespace-nowrap">
<dt class="sr-only">Name</dt>
<dd class="text-gray-900 dark:text-white">{{ frontmatter.author }}</dd>
<dt v-if="frontmatter.twitter" class="sr-only">Twitter</dt>
<dd v-if="frontmatter.twitter">
<a
:href="'https://twitter.com/' + frontmatter.twitter"
target="_blank"
rel="noopnener noreferrer"
class="link"
>{{ frontmatter.twitter }}</a
>
</dd>
</dl>
</li>
</ul>
</dd>
</dl>
</template>
18 changes: 18 additions & 0 deletions blog/.vitepress/theme/Date.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script setup lang="ts">
import type { Post } from './posts.data.js'
const props = defineProps<{ date: Post['date'] }>()
function getDateTime() {
return new Date(props.date.time).toISOString()
}
</script>

<template>
<dl>
<dt class="sr-only">Published on</dt>
<dd class="text-base leading-6 font-medium text-gray-500 dark:text-gray-300">
<time :datetime="getDateTime()">{{ date.string }}</time>
</dd>
</dl>
</template>
48 changes: 48 additions & 0 deletions blog/.vitepress/theme/Home.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script setup lang="ts">
import Date from './Date.vue'
import { data as posts } from './posts.data.js'
import { useData } from 'vitepress'
const { frontmatter } = useData()
</script>

<template>
<div class="divide-y divide-gray-200 dark:divide-slate-200/5">
<div class="pt-6 pb-8 space-y-2 md:space-y-5">
<h1
class="text-3xl leading-9 font-extrabold text-gray-900 dark:text-white tracking-tight sm:text-4xl sm:leading-10 md:text-6xl md:leading-14"
>
{{ frontmatter.title }}
</h1>
<p class="text-lg leading-7 text-gray-500 dark:text-white">
{{ frontmatter.subtext }}
</p>
</div>
<ul class="divide-y divide-gray-200 dark:divide-slate-200/5">
<li class="py-12" v-for="{ title, url, date, excerpt } of posts">
<article
class="space-y-2 xl:grid xl:grid-cols-4 xl:space-y-0 xl:items-baseline"
>
<Date :date="date" />
<div class="space-y-5 xl:col-span-3">
<div class="space-y-6">
<h2 class="text-2xl leading-8 font-bold tracking-tight">
<a class="text-gray-900 dark:text-white" :href="url">{{
title
}}</a>
</h2>
<div
v-if="excerpt"
class="prose dark:prose-invert max-w-none text-gray-500 dark:text-gray-300"
v-html="excerpt"
></div>
</div>
<div class="text-base leading-6 font-medium">
<a class="link" aria-label="read more" :href="url">Read more →</a>
</div>
</div>
</article>
</li>
</ul>
</div>
</template>
52 changes: 52 additions & 0 deletions blog/.vitepress/theme/Layout.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<script setup lang="ts">
import { useData } from 'vitepress'
import Home from './Home.vue'
import Article from './Article.vue'
import NotFound from './NotFound.vue'
const { page, frontmatter } = useData()
</script>

<template>
<div class="antialiased dark:bg-zinc-900">
<div class="max-w-3xl mx-auto px-4 sm:px-6 xl:max-w-5xl xl:px-0">
<nav class="flex justify-between items-center py-10 font-bold">
<a class="text-xl" href="/blog/" aria-label="Sandtracks">
<span
v-if="!frontmatter.index"
class="hidden md:inline dark:text-white"
>Sandtracks</span
>
</a>
<div class="text-sm text-gray-500 dark:text-white leading-5">
<a
class="hover:text-gray-700 dark:hover:text-gray-200"
href="https://github.com/melange-re/melange-re.github.io/"
target="_blank"
rel="noopener"
><span class="hidden sm:inline">GitHub </span>Source</a
>
<span class="mr-2 ml-2">·</span>
<a
class="hover:text-gray-700 dark:hover:text-gray-200"
href="/feed.rss"
>RSS<span class="hidden sm:inline"> Feed</span></a
>
<span class="mr-2 ml-2">·</span>
<a
class="hover:text-gray-700 dark:hover:text-gray-200"
href="https://melange.re"
target="_blank"
rel="noopener"
>melange.re →</a
>
</div>
</nav>
</div>
<main class="max-w-3xl mx-auto px-4 sm:px-6 xl:max-w-5xl xl:px-0">
<Home v-if="frontmatter.index" />
<NotFound v-else-if="page.isNotFound" />
<Article v-else />
</main>
</div>
</template>
3 changes: 3 additions & 0 deletions blog/.vitepress/theme/NotFound.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<h1 class="text-3xl font-bold">404 Page Not Found</h1>
</template>
6 changes: 6 additions & 0 deletions blog/.vitepress/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import './style.css'
import Layout from './Layout.vue'

export default {
Layout
}
Loading

0 comments on commit ace187e

Please sign in to comment.