Initial Commit
This commit is contained in:
commit
a927fefeba
28 changed files with 5805 additions and 0 deletions
202
pages/blog.vue
Normal file
202
pages/blog.vue
Normal file
|
@ -0,0 +1,202 @@
|
|||
<script setup>
|
||||
import { onMounted, watch, ref } from 'vue';
|
||||
import fm from 'front-matter';
|
||||
import markdownit from 'markdown-it'
|
||||
import PostCard from '../components/PostCard.vue';
|
||||
import hljs from 'highlight.js';
|
||||
|
||||
// Automatically maintained is a blog_list.json in assets/. This file contains a list of all blog posts and their metadata.
|
||||
// This file is generated by a script in the root directory of the project.
|
||||
import blog_list from '../assets/blog_list.json';
|
||||
|
||||
const md = markdownit({
|
||||
breaks: true,
|
||||
typographer: true,
|
||||
html: true,
|
||||
highlight: function (str, lang) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return '<pre><code class="hljs">' +
|
||||
hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +
|
||||
'</code></pre>';
|
||||
} catch (__) { }
|
||||
}
|
||||
|
||||
return '<pre><code class="hljs">' + md.utils.escapeHtml(str) + '</code></pre>';
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
md.renderer.rules.hr = function (tokens, idx, options, env, self) {
|
||||
return '<div class="rounded-full h-0.5 bg-purple-500 my-3"></div>'
|
||||
}
|
||||
|
||||
md.renderer.rules.softbreak = function (tokens, idx, options, env, self) {
|
||||
return '<br>'
|
||||
}
|
||||
|
||||
md.renderer.rules.hardbreak = function (tokens, idx, options, env, self) {
|
||||
return '<br><br>'
|
||||
}
|
||||
|
||||
const modules = import.meta.glob('/blog/');
|
||||
|
||||
for (const path in modules) {
|
||||
const module = await modules[path]();
|
||||
console.log(path, module.default); // module.default contains the image data
|
||||
}
|
||||
|
||||
let route = useRoute();
|
||||
console.log(route)
|
||||
|
||||
|
||||
const url = ref(null)
|
||||
url.value = route.query.post
|
||||
console.log(url.value)
|
||||
|
||||
const loading = ref(false)
|
||||
const data = ref([])
|
||||
const text = ref([])
|
||||
const error = ref([])
|
||||
|
||||
const list = ref([])
|
||||
const tagList = ref([])
|
||||
const tagFilter = ref([])
|
||||
tagFilter.value = []
|
||||
|
||||
|
||||
const background = ref('');
|
||||
const title = ref(null);
|
||||
const description = ref(null);
|
||||
const date = ref(null);
|
||||
const tags = ref(null);
|
||||
|
||||
// watch the params of the route to fetch the data again
|
||||
|
||||
fetchData(url.value)
|
||||
|
||||
|
||||
async function fetchData(url) {
|
||||
error.value = data.value = null
|
||||
loading.value = true
|
||||
console.log(url)
|
||||
try {
|
||||
data.value = await $fetch(url)
|
||||
console.log(data.value)
|
||||
const processed = fm(data.value)
|
||||
text.value = md.render(processed.body)
|
||||
console.log(text.value)
|
||||
background.value = processed.attributes.background
|
||||
title.value = processed.attributes.title
|
||||
description.value = processed.attributes.description
|
||||
date.value = processed.attributes.date
|
||||
tags.value = processed.attributes.tags
|
||||
} catch (err) {
|
||||
error.value = err.toString()
|
||||
console.error(err)
|
||||
loading.value = false
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/* If tags are specified, include only posts with those tags */
|
||||
/* else, include all posts */
|
||||
async function fetchList() {
|
||||
/*Example formatting:
|
||||
{
|
||||
"posts": [
|
||||
{
|
||||
"metadata": {
|
||||
"test": "mrrp"
|
||||
},
|
||||
"id": "test",
|
||||
"url": "/blog/test"
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
" title": "Awesome", "description": "A curated list of awesome stuff I like", "date": "2024-11-26", "tags": ["awesome", "curated"]
|
||||
},
|
||||
"id": "awesome",
|
||||
"url": "/blog/awesome"
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"test": "mrrp",
|
||||
"test2": "nya"
|
||||
},
|
||||
"id": "test2",
|
||||
"url": "/blog/test2"
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
||||
// Extract the posts
|
||||
list.value = blog_list.posts
|
||||
|
||||
// Extract the tags
|
||||
tagList.value = blog_list.posts.flatMap(post => post.metadata.tags).filter((tag, index, self) => self.indexOf(tag) === index)
|
||||
|
||||
}
|
||||
fetchList()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative z-50 flex w-full justify-center text-white">
|
||||
<div class="mt-8 flex-col text-center">
|
||||
<div v-if="url == null">
|
||||
<h1>Blog</h1>
|
||||
<div class="flex justify-center m-5">
|
||||
<div v-for="tag in tagList" :key="tag" class="m-1 text-center">
|
||||
<button
|
||||
@click="tagFilter.includes(tag) ? tagFilter.splice(tagFilter.indexOf(tag), 1) : tagFilter.push(tag)"
|
||||
class="text-xs bg-purple-800 border-purple-400 border text-white p-1 rounded-md"
|
||||
:class="tagFilter.includes(tag) ? 'border-2 border-purple-200 bg-purple-500' : 'border-1 border-purple-600 bg-purple-800 text-white'">{{
|
||||
tag }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<TransitionGroup name="list">
|
||||
<div v-for="post in tagFilter.length == 0 ? list : list.filter(post => tagFilter.some(tag => post.metadata.tags.includes(tag)))" :key="post.id">
|
||||
<PostCard :url="post.url" :key="post.id" />
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="flex flex-col">
|
||||
<h1>{{ title }}</h1>
|
||||
<div class="max-w-50 flex flex-row justify-center">
|
||||
<div v-for="tag in tags" :key="tag" class="m-1 text-center">
|
||||
<span class="text-xs bg-purple-800 border-purple-400 border text-white p-1 rounded-md">{{
|
||||
tag }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="text-pretty min-w-96 text-left max-w-4xl mt-4 p-6 max-md:w-screen rounded-md container bg-opacity-90 bg-purple-950">
|
||||
<div v-html="text"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.list-move,
|
||||
.list-enter-active,
|
||||
.list-leave-active {
|
||||
transition: all 0.5s cubic-bezier(0.55, 0, 0.1, 1);
|
||||
}
|
||||
|
||||
.list-enter-from,
|
||||
.list-leave-to {
|
||||
opacity: 0;
|
||||
transform: translate(100px, 0);
|
||||
}
|
||||
|
||||
.list-leave-active {
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
47
pages/index.vue
Normal file
47
pages/index.vue
Normal file
|
@ -0,0 +1,47 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import aboutMe from '../assets/about_me.md?raw'
|
||||
import markdownit from 'markdown-it'
|
||||
import PostCard from '../components/PostCard.vue';
|
||||
|
||||
const md = markdownit({
|
||||
breaks: true,
|
||||
typographer: true,
|
||||
html: true,
|
||||
})
|
||||
|
||||
|
||||
md.renderer.rules.hr = function(tokens, idx, options, env, self) {
|
||||
return '<div class="rounded-full h-0.5 bg-purple-500 my-3"></div>'
|
||||
}
|
||||
|
||||
md.renderer.rules.softbreak = function(tokens, idx, options, env, self) {
|
||||
return '<br>'
|
||||
}
|
||||
|
||||
md.renderer.rules.hardbreak = function(tokens, idx, options, env, self) {
|
||||
return '<br><br>'
|
||||
}
|
||||
md.renderer.rules.blockquote_open = function(tokens, idx, options, env, self) {
|
||||
return '<blockquote class="border-l-4 border-purple-500 pl-4 my-4">'
|
||||
}
|
||||
const result = ref('')
|
||||
|
||||
result.value = md.render(aboutMe);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative z-50 flex w-full justify-center text-white">
|
||||
<div class="mt-8 flex-col text-center">
|
||||
<div class="flex justify-center">
|
||||
<div class="p-2 shadow-md rounded-full bg-pink-500">
|
||||
<img class="z-20 transition-all w-40 h-40 md:w-56 md:h-56 rounded-full" src="https://avatars.githubusercontent.com/u/94077364?v=4" alt="User PFP" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="max-w-4xl mt-4 p-6 max-md:w-screen rounded-md container bg-opacity-70 bg-purple-950">
|
||||
<div v-html=result></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
Loading…
Add table
Add a link
Reference in a new issue