Add blog
This commit is contained in:
parent
c0a63a4a97
commit
2c103f70ae
18 changed files with 205 additions and 84 deletions
|
@ -15,6 +15,6 @@
|
|||
"@types/marked": "^5.0.0",
|
||||
"astro": "^2.6.4",
|
||||
"astro-icon": "^0.8.1",
|
||||
"marked": "^5.1.0"
|
||||
"micromark": "^3.2.0"
|
||||
}
|
||||
}
|
||||
|
|
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
|
@ -6,7 +6,7 @@ specifiers:
|
|||
'@types/marked': ^5.0.0
|
||||
astro: ^2.6.4
|
||||
astro-icon: ^0.8.1
|
||||
marked: ^5.1.0
|
||||
micromark: ^3.2.0
|
||||
|
||||
dependencies:
|
||||
',mmarked': link:@types/,mmarked
|
||||
|
@ -14,7 +14,7 @@ dependencies:
|
|||
'@types/marked': 5.0.0
|
||||
astro: 2.6.4
|
||||
astro-icon: 0.8.1
|
||||
marked: 5.1.0
|
||||
micromark: 3.2.0
|
||||
|
||||
packages:
|
||||
|
||||
|
@ -1868,12 +1868,6 @@ packages:
|
|||
resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
|
||||
dev: false
|
||||
|
||||
/marked/5.1.0:
|
||||
resolution: {integrity: sha512-z3/nBe7aTI8JDszlYLk7dDVNpngjw0o1ZJtrA9kIfkkHcIF+xH7mO23aISl4WxP83elU+MFROgahqdpd05lMEQ==}
|
||||
engines: {node: '>= 18'}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/mdast-util-definitions/5.1.2:
|
||||
resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==}
|
||||
dependencies:
|
||||
|
|
|
@ -2,27 +2,56 @@
|
|||
import styles from "../styles/BlogPost.module.css"
|
||||
import Divider from "../components/Divider.astro"
|
||||
|
||||
import type { CollectionEntry } from "astro:content"
|
||||
import { CollectionEntry, getCollection } from "astro:content"
|
||||
interface Props {
|
||||
post: CollectionEntry<"blog">
|
||||
standalone?: Boolean
|
||||
}
|
||||
|
||||
const { data: post, render } = Astro.props.post
|
||||
const { post: postEntry, standalone = true } = Astro.props
|
||||
const { data: post, render } = postEntry
|
||||
const { Content } = await render()
|
||||
const pubDate = new Intl.DateTimeFormat("en-US", {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric"
|
||||
}).format(post.pubDate)
|
||||
const blog = await getCollection("blog")
|
||||
const index = blog.findIndex((blogPost) => blogPost.id === postEntry.id)
|
||||
const prev = blog[index - 1]
|
||||
const next = blog[index + 1]
|
||||
---
|
||||
|
||||
<section class={styles.jumbo}>
|
||||
<section class={`${styles.jumbo} ${standalone ? styles.standalone : ""}`}>
|
||||
<section class={styles.top}>
|
||||
{standalone && <a href="/blog">< Go Back</a>}
|
||||
<span class={styles.date}>{pubDate}</span>
|
||||
</section>
|
||||
<h2 class={styles.title}>
|
||||
{post.title}
|
||||
</h2>
|
||||
<Divider />
|
||||
<article class={styles.description}>
|
||||
<Content />
|
||||
{standalone ? <Content /> : post.description}
|
||||
</article>
|
||||
{standalone ? "" : <span class={styles.more}>Read More</span>}
|
||||
{
|
||||
standalone ? (
|
||||
<section class={styles.links}>
|
||||
{prev ? (
|
||||
<a href={`/blog/${prev.slug}`}>< {prev.data.title}</a>
|
||||
) : (
|
||||
<span>< Previous Article</span>
|
||||
)}
|
||||
|
||||
{next ? (
|
||||
<a href={`/blog/${next.slug}`}>{next.data.title} ></a>
|
||||
) : (
|
||||
<span>Next Article ></span>
|
||||
)}
|
||||
</section>
|
||||
) : (
|
||||
""
|
||||
)
|
||||
}
|
||||
</section>
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
title: "Welcome to my blog!"
|
||||
pubDate: 1687027268667
|
||||
---
|
||||
|
||||
# **Test**
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
title: "Welcome to my blog!"
|
||||
pubDate: 1687027268667
|
||||
---
|
||||
|
||||
# **Test**
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
title: "Welcome to my blog!"
|
||||
pubDate: 1687027268667
|
||||
---
|
||||
|
||||
# **Test**
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
title: "Welcome to my blog!"
|
||||
pubDate: 1687027268667
|
||||
---
|
||||
|
||||
# **Test**
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
title: "Welcome to my blog!"
|
||||
pubDate: 1687027268667
|
||||
---
|
||||
|
||||
# **Test**
|
10
src/content/blog/welcome copy 2.md
Normal file
10
src/content/blog/welcome copy 2.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: "Welcome to my blog!"
|
||||
pubDate: 1687027268667
|
||||
category: "other"
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit **amet**, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
|
||||
Lorem ipsum dolor sit **amet**, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
8
src/content/blog/welcome copy.md
Normal file
8
src/content/blog/welcome copy.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
title: "Welcome to my blog!"
|
||||
pubDate: 1687027268667
|
||||
category: "other"
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
|
@ -1,4 +1,8 @@
|
|||
---
|
||||
title: "Welcome to my blog!"
|
||||
pubDate: 1687027268667
|
||||
category: "other"
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
|
|
|
@ -3,24 +3,26 @@ import { rssSchema } from "@astrojs/rss"
|
|||
|
||||
const blogCollection = defineCollection({
|
||||
type: "content",
|
||||
schema: rssSchema
|
||||
schema: rssSchema.extend({
|
||||
category: z.enum(["web", "bot", "linux", "other"])
|
||||
})
|
||||
})
|
||||
|
||||
const projectsCollection = defineCollection({
|
||||
type: "content",
|
||||
schema: z.object({
|
||||
name: z.string(),
|
||||
github: z.string().optional(),
|
||||
github: z.string().url().optional(),
|
||||
overview: z.string(),
|
||||
customLink: z
|
||||
.object({
|
||||
name: z.string(),
|
||||
url: z.string()
|
||||
url: z.string().url()
|
||||
})
|
||||
.optional(),
|
||||
mainImage: z.string(),
|
||||
thumbImage: z.string(),
|
||||
demoLink: z.string().optional()
|
||||
demoLink: z.string().url().optional()
|
||||
})
|
||||
})
|
||||
|
|
@ -12,6 +12,23 @@ const posts = await getCollection("blog")
|
|||
<div class={styles.container}>
|
||||
<aside class={styles.sidebar}>
|
||||
<input type="text" placeholder="Search..." id="search" />
|
||||
|
||||
<section class={styles.radios}>
|
||||
<input type="radio" name="category" id="all" checked />
|
||||
<label for="all">All</label>
|
||||
|
||||
<input type="radio" name="category" id="linux" />
|
||||
<label for="linux">Linux</label>
|
||||
|
||||
<input type="radio" name="category" id="web" />
|
||||
<label for="web">Web Development</label>
|
||||
|
||||
<input type="radio" name="category" id="bot" />
|
||||
<label for="bot">Discord Bot Development</label>
|
||||
|
||||
<input type="radio" name="category" id="other" />
|
||||
<label for="other">Other</label>
|
||||
</section>
|
||||
</aside>
|
||||
<div class={styles.right}>
|
||||
<article class={styles.description}>
|
||||
|
@ -29,9 +46,9 @@ const posts = await getCollection("blog")
|
|||
class={styles.link}
|
||||
href={`/blog/${post.slug}`}
|
||||
data-title={post.data.title}
|
||||
data-tags=""
|
||||
data-category={post.data.category}
|
||||
>
|
||||
<BlogPost post={post} />
|
||||
<BlogPost post={post} standalone={false} />
|
||||
</a>
|
||||
))
|
||||
}
|
||||
|
@ -40,23 +57,63 @@ const posts = await getCollection("blog")
|
|||
</Layout>
|
||||
|
||||
<script>
|
||||
let category = "all"
|
||||
const searchBar = document.querySelector("#search") as HTMLInputElement
|
||||
const posts = document.querySelectorAll(
|
||||
"[data-title]"
|
||||
) as NodeListOf<HTMLElement>
|
||||
const radios = document.querySelectorAll('input[type="radio"]')
|
||||
const urlParams = new URLSearchParams(location.search)
|
||||
const set = (name: string, value: string) => {
|
||||
urlParams.set(name, value)
|
||||
history.replaceState({}, "", `?${urlParams}`)
|
||||
}
|
||||
|
||||
radios.forEach((radio) =>
|
||||
radio.addEventListener("click", ({ target }) => {
|
||||
if (target instanceof HTMLInputElement) {
|
||||
set("category", target.id)
|
||||
category = target.id
|
||||
filterByCategory()
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
const search = () =>
|
||||
posts.forEach((post) =>
|
||||
post.setAttribute(
|
||||
"aria-hidden",
|
||||
post.dataset.title
|
||||
filter(
|
||||
(post) =>
|
||||
!!post.dataset.title
|
||||
?.toLowerCase()
|
||||
?.includes(searchBar.value.toLowerCase())
|
||||
? "false"
|
||||
: "true"
|
||||
)
|
||||
)
|
||||
|
||||
searchBar?.addEventListener("input", search)
|
||||
addEventListener("load", search)
|
||||
const filterByCategory = () =>
|
||||
filter((post) =>
|
||||
category == "all" ? true : post.dataset.category == category
|
||||
)
|
||||
|
||||
const filter = (condition: (element: HTMLElement) => boolean) =>
|
||||
posts.forEach((post) =>
|
||||
post.setAttribute("aria-hidden", (!condition(post)).toString())
|
||||
)
|
||||
|
||||
searchBar?.addEventListener("input", () => {
|
||||
set("search", searchBar.value)
|
||||
search()
|
||||
})
|
||||
|
||||
addEventListener("load", () => {
|
||||
searchBar.value = urlParams.get("search") ?? ""
|
||||
Array.from(radios).find((radio) => {
|
||||
if (
|
||||
radio instanceof HTMLInputElement &&
|
||||
radio.id == urlParams.get("category")
|
||||
) {
|
||||
radio.checked = true
|
||||
category = radio.id
|
||||
}
|
||||
})
|
||||
search()
|
||||
filterByCategory()
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import rss from "@astrojs/rss"
|
||||
import { getCollection } from "astro:content"
|
||||
import { marked } from "marked"
|
||||
import { micromark } from "micromark"
|
||||
|
||||
export const get = async (context) => {
|
||||
const blog = await getCollection("blog")
|
||||
|
@ -11,10 +11,7 @@ export const get = async (context) => {
|
|||
site: context.site,
|
||||
items: blog.map((post) => ({
|
||||
link: `/blog/${post.slug}/`,
|
||||
content: marked.parse(post.body, {
|
||||
mangle: false,
|
||||
headerIds: false
|
||||
}),
|
||||
content: micromark(post.body),
|
||||
...post.data
|
||||
})),
|
||||
customData: "<language>en-us</language>",
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
.link {
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
width: 100%;
|
||||
color: unset;
|
||||
text-decoration: none;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.description {
|
||||
|
@ -35,6 +33,7 @@
|
|||
.sidebar {
|
||||
display: flex;
|
||||
position: sticky;
|
||||
gap: 1rem;
|
||||
top: 8rem;
|
||||
height: 80vh;
|
||||
flex-direction: column;
|
||||
|
@ -47,6 +46,21 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
[aria-hidden="true"] {
|
||||
[aria-hidden="true"],
|
||||
.radios [type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.radios :checked + label {
|
||||
color: var(--primary);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.radios {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,38 @@
|
|||
.jumbo {
|
||||
display: flex;
|
||||
padding: 1rem 1.5rem;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.jumbo.standalone {
|
||||
max-width: 80rem;
|
||||
}
|
||||
|
||||
.more {
|
||||
margin-top: 1.5rem;
|
||||
padding: 1rem;
|
||||
border: 2px solid var(--primary);
|
||||
border-radius: 20rem;
|
||||
backdrop-filter: blur(2rem);
|
||||
background: rgb(0 0 0 / 0.3);
|
||||
box-shadow: 0 0 2rem black;
|
||||
transition: scale 0.2s;
|
||||
}
|
||||
|
||||
.more:hover {
|
||||
scale: 1.05;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.date {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
color: hsl(37 10% 58%);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
@ -18,9 +41,9 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.description p {
|
||||
.description {
|
||||
font-size: 1.3rem;
|
||||
max-width: 40rem;
|
||||
max-width: 60rem;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
|
@ -37,8 +60,20 @@
|
|||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.description :is(strong, em) {
|
||||
display: block;
|
||||
.links {
|
||||
width: 100%;
|
||||
text-align: justify;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.links * {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.links a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.links span {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
background: rgb(0 0 0 / 0.1);
|
||||
border: 2px solid var(--primary);
|
||||
backdrop-filter: blur(2rem);
|
||||
border-radius: 2rem;
|
||||
padding: 2rem;
|
||||
border-radius: 1.5rem;
|
||||
padding: 1.5rem;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
height: 100%;
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
color-scheme: dark light;
|
||||
scroll-behavior: smooth;
|
||||
|
||||
--primary: #4e94e4;
|
||||
--secondary: #354b5f;
|
||||
--primary: hsl(212, 74%, 60%);
|
||||
--secondary: hsl(209, 28%, 29%);
|
||||
--muted: hsl(0, 0%, 54%);
|
||||
}
|
||||
|
||||
body {
|
||||
|
@ -40,7 +41,7 @@ main {
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
:is(article, section, aside):not(section *, nav *, header *) {
|
||||
:is(article, section, aside):not(section *, nav *, header *, aside *) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 1rem;
|
||||
|
@ -52,7 +53,7 @@ main {
|
|||
}
|
||||
|
||||
:is(article, section, aside):not(section *, nav *, header *):hover {
|
||||
scale: 102%;
|
||||
scale: 101.5%;
|
||||
}
|
||||
|
||||
@media (min-width: 500px) {
|
||||
|
|
Loading…
Add table
Reference in a new issue