mirror of
https://github.com/ChenQihan666/MyBlog-Next.git
synced 2026-08-14 11:29:33 +08:00
Merge branch 'astro-v2'
This commit is contained in:
@@ -18,3 +18,6 @@ pnpm-debug.log*
|
|||||||
|
|
||||||
# macOS-specific files
|
# macOS-specific files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# ignore .astro directory
|
||||||
|
.astro
|
||||||
|
|||||||
+2
-1
@@ -9,4 +9,5 @@
|
|||||||
!astro.config.mjs
|
!astro.config.mjs
|
||||||
!package.json
|
!package.json
|
||||||
!.prettierrc
|
!.prettierrc
|
||||||
!.eslintrc.json
|
!.eslintrc.json
|
||||||
|
!README.md
|
||||||
@@ -14,6 +14,7 @@ This theme is self-documented \_ which means articles/posts in this theme can al
|
|||||||
|
|
||||||
## 🔥 Features
|
## 🔥 Features
|
||||||
|
|
||||||
|
- [x] type-safe markdown
|
||||||
- [x] super fast performance
|
- [x] super fast performance
|
||||||
- [x] accessible (Keyboard/VoiceOver)
|
- [x] accessible (Keyboard/VoiceOver)
|
||||||
- [x] responsive (mobile ~ desktops)
|
- [x] responsive (mobile ~ desktops)
|
||||||
@@ -54,8 +55,11 @@ Inside of AstroPaper, you'll see the following folders and files:
|
|||||||
│ ├── assets/
|
│ ├── assets/
|
||||||
│ │ └── socialIcons.ts
|
│ │ └── socialIcons.ts
|
||||||
│ ├── components/
|
│ ├── components/
|
||||||
│ ├── contents/
|
│ ├── content/
|
||||||
│ │ └── some-blog-posts.md
|
│ │ | blog/
|
||||||
|
│ │ | └── some-blog-posts.md
|
||||||
|
│ │ └── _schemas.ts
|
||||||
|
│ │ └── config.ts
|
||||||
│ ├── layouts/
|
│ ├── layouts/
|
||||||
│ └── pages/
|
│ └── pages/
|
||||||
│ └── styles/
|
│ └── styles/
|
||||||
@@ -69,16 +73,18 @@ Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page
|
|||||||
|
|
||||||
Any static assets, like images, can be placed in the `public/` directory.
|
Any static assets, like images, can be placed in the `public/` directory.
|
||||||
|
|
||||||
All blog posts are stored in `src/contents/` directory.
|
All blog posts are stored in `src/content/blog` directory.
|
||||||
|
|
||||||
## 📖 Documentation
|
## 📖 Documentation
|
||||||
|
|
||||||
Documentation can be read in two formats\_ _markdown_ & _blog post_.
|
Documentation can be read in two formats\_ _markdown_ & _blog post_.
|
||||||
|
|
||||||
- Configuration - [markdown](src/contents/how-to-configure-astropaper-theme.md) | [blog post](https://astro-paper.pages.dev/posts/how-to-configure-astropaper-theme/)
|
- Configuration - [markdown](src/content/blog/how-to-configure-astropaper-theme.md) | [blog post](https://astro-paper.pages.dev/posts/how-to-configure-astropaper-theme/)
|
||||||
- Add Posts - [markdown](src/contents/adding-new-post.md) | [blog post](https://astro-paper.pages.dev/posts/adding-new-posts-in-astropaper-theme/)
|
- Add Posts - [markdown](src/content/blog/adding-new-post.md) | [blog post](https://astro-paper.pages.dev/posts/adding-new-posts-in-astropaper-theme/)
|
||||||
- Customize Color Schemes - [markdown](src/contents/customizing-astropaper-theme-color-schemes.md) | [blog post](https://astro-paper.pages.dev/posts/customizing-astropaper-theme-color-schemes/)
|
- Customize Color Schemes - [markdown](src/content/blog/customizing-astropaper-theme-color-schemes.md) | [blog post](https://astro-paper.pages.dev/posts/customizing-astropaper-theme-color-schemes/)
|
||||||
- Predefined Color Schemes - [markdown](src/contents/predefined-color-schemes.md) | [blog post](https://astro-paper.pages.dev/posts/predefined-color-schemes/)
|
- Predefined Color Schemes - [markdown](src/content/blog/predefined-color-schemes.md) | [blog post](https://astro-paper.pages.dev/posts/predefined-color-schemes/)
|
||||||
|
|
||||||
|
> For AstroPaper v1, check out [this branch](https://github.com/satnaing/astro-paper/tree/astro-paper-v1) and this [live URL](https://astro-paper-v1.astro-paper.pages.dev/)
|
||||||
|
|
||||||
## 💻 Tech Stack
|
## 💻 Tech Stack
|
||||||
|
|
||||||
@@ -121,17 +127,16 @@ PUBLIC_GOOGLE_SITE_VERIFICATION=your-google-site-verification-value
|
|||||||
|
|
||||||
All commands are run from the root of the project, from a terminal:
|
All commands are run from the root of the project, from a terminal:
|
||||||
|
|
||||||
| Command | Action |
|
| Command | Action |
|
||||||
| :--------------------- | :------------------------------------------------- |
|
| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `npm install` | Installs dependencies |
|
| `npm install` | Installs dependencies |
|
||||||
| `npm run dev` | Starts local dev server at `localhost:3000` |
|
| `npm run dev` | Starts local dev server at `localhost:3000` |
|
||||||
| `npm run build` | Build your production site to `./dist/` |
|
| `npm run build` | Build your production site to `./dist/` |
|
||||||
| `npm run preview` | Preview your build locally, before deploying |
|
| `npm run preview` | Preview your build locally, before deploying |
|
||||||
| `npm run format:check` | Check code format with Prettier |
|
| `npm run format:check` | Check code format with Prettier |
|
||||||
| `npm run format` | Format codes with Prettier |
|
| `npm run format` | Format codes with Prettier |
|
||||||
| `npm run cz` | Commit code changes with commitizen |
|
| `npm run sync` | Generates TypeScript types for all Astro modules. [Learn more](https://docs.astro.build/en/reference/cli-reference/#astro-sync). |
|
||||||
| `npm run astro ...` | Run CLI commands like `astro add`, `astro preview` |
|
| `npm run cz` | Commit code changes with commitizen |
|
||||||
| `npm run astro --help` | Get help using the Astro CLI |
|
|
||||||
|
|
||||||
## ✨ Feedback & Suggestions
|
## ✨ Feedback & Suggestions
|
||||||
|
|
||||||
|
|||||||
Generated
+1171
-2721
File diff suppressed because it is too large
Load Diff
+8
-6
@@ -7,6 +7,7 @@
|
|||||||
"start": "astro dev",
|
"start": "astro dev",
|
||||||
"build": "astro build",
|
"build": "astro build",
|
||||||
"preview": "astro preview",
|
"preview": "astro preview",
|
||||||
|
"sync": "astro sync",
|
||||||
"astro": "astro",
|
"astro": "astro",
|
||||||
"format:check": "prettier --check .",
|
"format:check": "prettier --check .",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
@@ -14,19 +15,19 @@
|
|||||||
"prepare": "husky install"
|
"prepare": "husky install"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/rss": "^1.0.3",
|
"@astrojs/rss": "^2.1.0",
|
||||||
"astro": "^1.9.2",
|
"astro": "^2.0.4",
|
||||||
"fuse.js": "^6.6.2",
|
"fuse.js": "^6.6.2",
|
||||||
"github-slugger": "^2.0.0",
|
"github-slugger": "^2.0.0",
|
||||||
"remark-collapse": "^0.1.2",
|
"remark-collapse": "^0.1.2",
|
||||||
"remark-toc": "^8.0.1",
|
"remark-toc": "^8.0.1",
|
||||||
"satori": "^0.1.1",
|
"satori": "^0.1.2",
|
||||||
"tailwindcss": "^3.2.4"
|
"tailwindcss": "^3.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/react": "^1.2.2",
|
"@astrojs/react": "^2.0.2",
|
||||||
"@astrojs/sitemap": "^1.0.0",
|
"@astrojs/sitemap": "^1.0.1",
|
||||||
"@astrojs/tailwind": "^2.1.3",
|
"@astrojs/tailwind": "^3.0.1",
|
||||||
"@tailwindcss/typography": "^0.5.9",
|
"@tailwindcss/typography": "^0.5.9",
|
||||||
"@types/github-slugger": "^1.3.0",
|
"@types/github-slugger": "^1.3.0",
|
||||||
"@types/react": "^18.0.27",
|
"@types/react": "^18.0.27",
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"lint-staged": "^13.1.0",
|
"lint-staged": "^13.1.0",
|
||||||
"prettier": "^2.8.3",
|
"prettier": "^2.8.3",
|
||||||
|
"prettier-plugin-tailwindcss": "^0.2.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { SocialIcons } from "src/types";
|
import type { SocialIcons } from "@types";
|
||||||
|
|
||||||
const socialIcons: SocialIcons = {
|
const socialIcons: SocialIcons = {
|
||||||
Github: `<svg
|
Github: `<svg
|
||||||
|
|||||||
@@ -22,7 +22,11 @@ breadcrumbList[0] === "posts" &&
|
|||||||
breadcrumbList.map((breadcrumb, index) =>
|
breadcrumbList.map((breadcrumb, index) =>
|
||||||
index + 1 === breadcrumbList.length ? (
|
index + 1 === breadcrumbList.length ? (
|
||||||
<li>
|
<li>
|
||||||
<span class={`${index > 0 ? "lowercase" : ""}`} aria-current="page">
|
<span
|
||||||
|
class={`${index > 0 ? "lowercase" : "capitalize"}`}
|
||||||
|
aria-current="page"
|
||||||
|
>
|
||||||
|
{/* make the last part lowercase in Home > Tags > some-tag */}
|
||||||
{breadcrumb}
|
{breadcrumb}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
@@ -39,14 +43,16 @@ breadcrumbList[0] === "posts" &&
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.breadcrumb {
|
.breadcrumb {
|
||||||
@apply max-w-3xl mx-auto px-4 w-full mt-8 mb-1;
|
@apply mx-auto mt-8 mb-1 w-full max-w-3xl px-4;
|
||||||
}
|
}
|
||||||
.breadcrumb ul li {
|
.breadcrumb ul li {
|
||||||
@apply inline;
|
@apply inline;
|
||||||
}
|
}
|
||||||
.breadcrumb ul li a,
|
.breadcrumb ul li a {
|
||||||
|
@apply capitalize opacity-70;
|
||||||
|
}
|
||||||
.breadcrumb ul li span {
|
.breadcrumb ul li span {
|
||||||
@apply opacity-70 capitalize;
|
@apply opacity-70;
|
||||||
}
|
}
|
||||||
.breadcrumb ul li:not(:last-child) a {
|
.breadcrumb ul li:not(:last-child) a {
|
||||||
@apply hover:opacity-100;
|
@apply hover:opacity-100;
|
||||||
|
|||||||
+17
-16
@@ -1,31 +1,32 @@
|
|||||||
import Datetime from "./Datetime";
|
import Datetime from "./Datetime";
|
||||||
import type { Frontmatter } from "src/types";
|
import type { BlogFrontmatter } from "@content/_schemas";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
href?: string;
|
href?: string;
|
||||||
post: Frontmatter;
|
frontmatter: BlogFrontmatter;
|
||||||
secHeading?: boolean;
|
secHeading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = {
|
export default function Card({ href, frontmatter, secHeading = true }: Props) {
|
||||||
cardContainer: "my-6",
|
const { title, pubDatetime, description } = frontmatter;
|
||||||
titleLink:
|
|
||||||
"text-skin-accent font-medium text-lg underline-offset-4 decoration-dashed focus-visible:no-underline focus-visible:underline-offset-0 inline-block",
|
|
||||||
titleHeading: "font-medium text-lg decoration-dashed hover:underline",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Card({ href, post, secHeading = true }: Props) {
|
|
||||||
return (
|
return (
|
||||||
<li className={styles.cardContainer}>
|
<li className="my-6">
|
||||||
<a href={href} className={styles.titleLink}>
|
<a
|
||||||
|
href={href}
|
||||||
|
className="inline-block text-lg font-medium text-skin-accent decoration-dashed underline-offset-4 focus-visible:no-underline focus-visible:underline-offset-0"
|
||||||
|
>
|
||||||
{secHeading ? (
|
{secHeading ? (
|
||||||
<h2 className={styles.titleHeading}>{post.title}</h2>
|
<h2 className="text-lg font-medium decoration-dashed hover:underline">
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
) : (
|
) : (
|
||||||
<h3 className={styles.titleHeading}>{post.title}</h3>
|
<h3 className="text-lg font-medium decoration-dashed hover:underline">
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
)}
|
)}
|
||||||
</a>
|
</a>
|
||||||
<Datetime datetime={post.datetime} />
|
<Datetime datetime={pubDatetime} />
|
||||||
<p>{post.description}</p>
|
<p>{description}</p>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
export interface Props {
|
export interface Props {
|
||||||
datetime: string;
|
datetime: string | Date;
|
||||||
size?: "sm" | "lg";
|
size?: "sm" | "lg";
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Datetime({ datetime, size = "sm", className }: Props) {
|
export default function Datetime({ datetime, size = "sm", className }: Props) {
|
||||||
return (
|
return (
|
||||||
<div className={`opacity-80 flex items-center space-x-2 ${className}`}>
|
<div className={`flex items-center space-x-2 opacity-80 ${className}`}>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
className={`${
|
className={`${
|
||||||
size === "sm" ? "scale-90" : "scale-100"
|
size === "sm" ? "scale-90" : "scale-100"
|
||||||
} w-6 h-6 inline-block fill-skin-base`}
|
} inline-block h-6 w-6 fill-skin-base`}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
<path d="M7 11h2v2H7zm0 4h2v2H7zm4-4h2v2h-2zm0 4h2v2h-2zm4-4h2v2h-2zm0 4h2v2h-2z"></path>
|
<path d="M7 11h2v2H7zm0 4h2v2H7zm4-4h2v2h-2zm0 4h2v2h-2zm4-4h2v2h-2zm0 4h2v2h-2z"></path>
|
||||||
@@ -25,7 +25,7 @@ export default function Datetime({ datetime, size = "sm", className }: Props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const FormattedDatetime = ({ datetime }: { datetime: string }) => {
|
const FormattedDatetime = ({ datetime }: { datetime: string | Date }) => {
|
||||||
const myDatetime = new Date(datetime);
|
const myDatetime = new Date(datetime);
|
||||||
|
|
||||||
const date = myDatetime.toLocaleDateString([], {
|
const date = myDatetime.toLocaleDateString([], {
|
||||||
|
|||||||
@@ -28,16 +28,16 @@ const { noMarginTop = false } = Astro.props;
|
|||||||
@apply w-full;
|
@apply w-full;
|
||||||
}
|
}
|
||||||
.footer-wrapper {
|
.footer-wrapper {
|
||||||
@apply py-6 sm:py-4 flex flex-col sm:flex-row-reverse justify-between items-center;
|
@apply flex flex-col items-center justify-between py-6 sm:flex-row-reverse sm:py-4;
|
||||||
}
|
}
|
||||||
.link-button {
|
.link-button {
|
||||||
@apply p-2 my-1 hover:rotate-6;
|
@apply my-1 p-2 hover:rotate-6;
|
||||||
}
|
}
|
||||||
.link-button svg {
|
.link-button svg {
|
||||||
@apply scale-125;
|
@apply scale-125;
|
||||||
}
|
}
|
||||||
.copyright-wrapper {
|
.copyright-wrapper {
|
||||||
@apply my-2 flex flex-col sm:flex-row items-center whitespace-nowrap;
|
@apply my-2 flex flex-col items-center whitespace-nowrap sm:flex-row;
|
||||||
}
|
}
|
||||||
.separator {
|
.separator {
|
||||||
@apply hidden sm:inline;
|
@apply hidden sm:inline;
|
||||||
|
|||||||
+15
-15
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import { LOGO_IMAGE, SITE } from "src/config";
|
import { LOGO_IMAGE, SITE } from "@config";
|
||||||
import Hr from "./Hr.astro";
|
import Hr from "./Hr.astro";
|
||||||
import LinkButton from "./LinkButton.astro";
|
import LinkButton from "./LinkButton.astro";
|
||||||
|
|
||||||
@@ -107,35 +107,35 @@ const { activeNav } = Astro.props;
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
#skip-to-content {
|
#skip-to-content {
|
||||||
@apply bg-skin-accent text-skin-inverted py-2 px-3 absolute -top-full focus:top-4 left-16 z-50 transition-all;
|
@apply absolute -top-full left-16 z-50 bg-skin-accent py-2 px-3 text-skin-inverted transition-all focus:top-4;
|
||||||
}
|
}
|
||||||
.nav-container {
|
.nav-container {
|
||||||
@apply max-w-3xl mx-auto flex flex-col sm:flex-row justify-between items-center;
|
@apply mx-auto flex max-w-3xl flex-col items-center justify-between sm:flex-row;
|
||||||
}
|
}
|
||||||
.top-nav-wrap {
|
.top-nav-wrap {
|
||||||
@apply relative w-full p-4 sm:py-8 flex justify-between items-start sm:items-center;
|
@apply relative flex w-full items-start justify-between p-4 sm:items-center sm:py-8;
|
||||||
}
|
}
|
||||||
.logo {
|
.logo {
|
||||||
@apply absolute sm:static font-semibold text-xl sm:text-2xl py-1;
|
@apply absolute py-1 text-xl font-semibold sm:static sm:text-2xl;
|
||||||
}
|
}
|
||||||
.hamburger-menu {
|
.hamburger-menu {
|
||||||
@apply self-end p-2 sm:hidden;
|
@apply self-end p-2 sm:hidden;
|
||||||
}
|
}
|
||||||
.hamburger-menu svg {
|
.hamburger-menu svg {
|
||||||
@apply fill-skin-base w-6 h-6 scale-125;
|
@apply h-6 w-6 scale-125 fill-skin-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
@apply w-full sm:py-0 sm:ml-2 flex flex-col items-center sm:justify-end sm:flex-row sm:space-x-4 bg-skin-fill;
|
@apply flex w-full flex-col items-center bg-skin-fill sm:ml-2 sm:flex-row sm:justify-end sm:space-x-4 sm:py-0;
|
||||||
}
|
}
|
||||||
nav ul {
|
nav ul {
|
||||||
@apply mt-4 w-44 grid grid-rows-4 grid-cols-2 gap-y-2 gap-x-2 sm:gap-y-0 sm:mt-0 sm:ml-0 sm:w-auto sm:gap-x-5;
|
@apply mt-4 grid w-44 grid-cols-2 grid-rows-4 gap-y-2 gap-x-2 sm:mt-0 sm:ml-0 sm:w-auto sm:gap-y-0 sm:gap-x-5;
|
||||||
}
|
}
|
||||||
nav ul li {
|
nav ul li {
|
||||||
@apply col-span-2 flex justify-center items-center;
|
@apply col-span-2 flex items-center justify-center;
|
||||||
}
|
}
|
||||||
nav ul li a {
|
nav ul li a {
|
||||||
@apply px-4 py-3 w-full text-center sm:px-2 sm:py-1 sm:my-0 font-medium hover:text-skin-accent;
|
@apply w-full px-4 py-3 text-center font-medium hover:text-skin-accent sm:my-0 sm:px-2 sm:py-1;
|
||||||
}
|
}
|
||||||
nav ul li:nth-child(4) a {
|
nav ul li:nth-child(4) a {
|
||||||
@apply w-auto;
|
@apply w-auto;
|
||||||
@@ -145,7 +145,7 @@ const { activeNav } = Astro.props;
|
|||||||
@apply col-span-1;
|
@apply col-span-1;
|
||||||
}
|
}
|
||||||
nav a.active {
|
nav a.active {
|
||||||
@apply underline underline-offset-4 decoration-wavy decoration-2;
|
@apply underline decoration-wavy decoration-2 underline-offset-4;
|
||||||
}
|
}
|
||||||
nav a.active svg {
|
nav a.active svg {
|
||||||
@apply fill-skin-accent;
|
@apply fill-skin-accent;
|
||||||
@@ -155,20 +155,20 @@ const { activeNav } = Astro.props;
|
|||||||
@apply p-1;
|
@apply p-1;
|
||||||
}
|
}
|
||||||
nav button svg {
|
nav button svg {
|
||||||
@apply w-6 h-6 fill-skin-base hover:fill-skin-accent;
|
@apply h-6 w-6 fill-skin-base hover:fill-skin-accent;
|
||||||
}
|
}
|
||||||
#theme-btn {
|
#theme-btn {
|
||||||
@apply p-3 sm:p-1;
|
@apply p-3 sm:p-1;
|
||||||
}
|
}
|
||||||
#theme-btn svg {
|
#theme-btn svg {
|
||||||
@apply hover:rotate-12 scale-125 sm:scale-100;
|
@apply scale-125 hover:rotate-12 sm:scale-100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-container {
|
.icon-container {
|
||||||
@apply w-6 h-5 flex-col justify-between items-end;
|
@apply h-5 w-6 flex-col items-end justify-between;
|
||||||
}
|
}
|
||||||
.icon-container div {
|
.icon-container div {
|
||||||
@apply bg-skin-inverted h-0.5 transition-all;
|
@apply h-0.5 bg-skin-inverted transition-all;
|
||||||
}
|
}
|
||||||
#first-line {
|
#first-line {
|
||||||
@apply w-full;
|
@apply w-full;
|
||||||
|
|||||||
+12
-13
@@ -2,13 +2,12 @@ import Fuse from "fuse.js";
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import Card from "@components/Card";
|
import Card from "@components/Card";
|
||||||
import slugify from "@utils/slugify";
|
import slugify from "@utils/slugify";
|
||||||
import type { Frontmatter } from "src/types";
|
import type { BlogFrontmatter } from "@content/_schemas";
|
||||||
|
|
||||||
type SearchItem = {
|
export type SearchItem = {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
headings: string[];
|
data: BlogFrontmatter;
|
||||||
frontmatter: Frontmatter;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -32,7 +31,7 @@ export default function SearchBar({ searchList }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fuse = new Fuse(searchList, {
|
const fuse = new Fuse(searchList, {
|
||||||
keys: ["title", "description", "headings"],
|
keys: ["title", "description"],
|
||||||
includeMatches: true,
|
includeMatches: true,
|
||||||
minMatchCharLength: 2,
|
minMatchCharLength: 2,
|
||||||
threshold: 0.5,
|
threshold: 0.5,
|
||||||
@@ -79,14 +78,14 @@ export default function SearchBar({ searchList }: Props) {
|
|||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
className="placeholder:italic placeholder:text-opacity-75 py-3 pl-10 pr-3
|
className="block w-full rounded border border-skin-fill
|
||||||
block bg-skin-fill w-full rounded
|
border-opacity-40 bg-skin-fill py-3 pl-10
|
||||||
border border-skin-fill border-opacity-40
|
pr-3 placeholder:italic placeholder:text-opacity-75
|
||||||
focus:outline-none focus:border-skin-accent"
|
focus:border-skin-accent focus:outline-none"
|
||||||
placeholder="Search for anything..."
|
placeholder="Search for anything..."
|
||||||
type="text"
|
type="text"
|
||||||
name="search"
|
name="search"
|
||||||
defaultValue={inputVal}
|
value={inputVal}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoFocus
|
autoFocus
|
||||||
@@ -108,9 +107,9 @@ export default function SearchBar({ searchList }: Props) {
|
|||||||
{searchResults &&
|
{searchResults &&
|
||||||
searchResults.map(({ item, refIndex }) => (
|
searchResults.map(({ item, refIndex }) => (
|
||||||
<Card
|
<Card
|
||||||
post={item.frontmatter}
|
href={`/posts/${slugify(item.data)}`}
|
||||||
href={`/posts/${slugify(item.frontmatter)}`}
|
frontmatter={item.data}
|
||||||
key={`${refIndex}-${slugify(item.frontmatter)}`}
|
key={`${refIndex}-${slugify(item.data)}`}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import { SOCIALS } from "src/config";
|
import { SOCIALS } from "@config";
|
||||||
import LinkButton from "./LinkButton.astro";
|
import LinkButton from "./LinkButton.astro";
|
||||||
import socialIcons from "@assets/socialIcons";
|
import socialIcons from "@assets/socialIcons";
|
||||||
|
|
||||||
@@ -29,6 +29,6 @@ const { centered = false } = Astro.props;
|
|||||||
@apply flex-wrap justify-center gap-1;
|
@apply flex-wrap justify-center gap-1;
|
||||||
}
|
}
|
||||||
.link-button {
|
.link-button {
|
||||||
@apply p-2 sm:p-1 hover:rotate-6;
|
@apply p-2 hover:rotate-6 sm:p-1;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ const { name, size = "sm" } = Astro.props;
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href={`/tags/${name}`}
|
href={`/tags/${name.toLowerCase()}`}
|
||||||
class={`${size === "sm" ? "pr-1 text-sm" : "pr-2 text-lg"} group`}
|
class={`${size === "sm" ? "text-sm" : "text-lg"} pr-2 group`}
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@@ -23,15 +23,15 @@ const { name, size = "sm" } = Astro.props;
|
|||||||
d="M16.018 3.815 15.232 8h-4.966l.716-3.815-1.964-.37L8.232 8H4v2h3.857l-.751 4H3v2h3.731l-.714 3.805 1.965.369L8.766 16h4.966l-.714 3.805 1.965.369.783-4.174H20v-2h-3.859l.751-4H21V8h-3.733l.716-3.815-1.965-.37zM14.106 14H9.141l.751-4h4.966l-.752 4z"
|
d="M16.018 3.815 15.232 8h-4.966l.716-3.815-1.964-.37L8.232 8H4v2h3.857l-.751 4H3v2h3.731l-.714 3.805 1.965.369L8.766 16h4.966l-.714 3.805 1.965.369.783-4.174H20v-2h-3.859l.751-4H21V8h-3.733l.716-3.815-1.965-.37zM14.106 14H9.141l.751-4h4.966l-.752 4z"
|
||||||
></path>
|
></path>
|
||||||
</svg>
|
</svg>
|
||||||
<span>{name}</span>
|
<span>{name.toLowerCase()}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
a {
|
a {
|
||||||
@apply underline decoration-dashed hover:text-skin-accent relative hover:-top-0.5 focus-visible:p-1;
|
@apply relative underline decoration-dashed hover:-top-0.5 hover:text-skin-accent focus-visible:p-1;
|
||||||
}
|
}
|
||||||
a svg {
|
a svg {
|
||||||
@apply w-6 h-6 text-skin-base scale-95 opacity-80 -mr-5 group-hover:fill-skin-accent;
|
@apply -mr-5 h-6 w-6 scale-95 text-skin-base opacity-80 group-hover:fill-skin-accent;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { z } from "astro:content";
|
||||||
|
|
||||||
|
export const blogSchema = z.object({
|
||||||
|
author: z.string().optional(),
|
||||||
|
pubDatetime: z.date(),
|
||||||
|
title: z.string(),
|
||||||
|
postSlug: z.string().optional(),
|
||||||
|
featured: z.boolean().optional(),
|
||||||
|
draft: z.boolean().optional(),
|
||||||
|
tags: z.array(z.string()).default(["others"]),
|
||||||
|
ogImage: z.string().optional(),
|
||||||
|
description: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type BlogFrontmatter = z.infer<typeof blogSchema>;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
author: Sat Naing
|
author: Sat Naing
|
||||||
datetime: 2022-09-23T15:22:00Z
|
pubDatetime: 2022-09-23T15:22:00Z
|
||||||
title: Adding new posts in AstroPaper theme
|
title: Adding new posts in AstroPaper theme
|
||||||
slug: adding-new-posts-in-astropaper-theme
|
postSlug: adding-new-posts-in-astropaper-theme
|
||||||
featured: true
|
featured: true
|
||||||
draft: false
|
draft: false
|
||||||
tags:
|
tags:
|
||||||
@@ -23,33 +23,48 @@ Frontmatter is the main place to store some important information about the post
|
|||||||
|
|
||||||
Here is the list of frontmatter property for each post.
|
Here is the list of frontmatter property for each post.
|
||||||
|
|
||||||
| Property | Description | Remark |
|
| Property | Description | Remark |
|
||||||
| ----------------- | ----------------------------------------------------------------------------------------- | ------------------------- |
|
| ----------------- | ------------------------------------------------------------------------------- | --------------------------------------------- |
|
||||||
| **_title_** | Title of the post. (h1) | required<sup>\*</sup> |
|
| **_title_** | Title of the post. (h1) | required<sup>\*</sup> |
|
||||||
| **_description_** | Description of the post. Used in post excerpt and site description of the post. | default = SITE.desc |
|
| **_description_** | Description of the post. Used in post excerpt and site description of the post. | required<sup>\*</sup> |
|
||||||
| **_author_** | Author of the post. | default = SITE.author |
|
| **_pubDatetime_** | Published datetime in ISO 8601 format. | required<sup>\*</sup> |
|
||||||
| **_datetime_** | Published datetime in ISO 8601 format. | |
|
| **_author_** | Author of the post. | default = SITE.author |
|
||||||
| **_slug_** | Slug for the post. Usually the all lowercase title seperated in `-` instead of whtiespace | default = slugified title |
|
| **_postSlug_** | Slug for the post. Will automatically be slugified. | default = slugified title |
|
||||||
| **_featured_** | Whether or not display this post in featured section of home page | default = false |
|
| **_featured_** | Whether or not display this post in featured section of home page | default = false |
|
||||||
| **_draft_** | Mark this post 'unpublished'. | default = false |
|
| **_draft_** | Mark this post 'unpublished'. | default = false |
|
||||||
| **_tags_** | Related keywords for this post. Written in array yaml format. | |
|
| **_tags_** | Related keywords for this post. Written in array yaml format. | default = others |
|
||||||
| **_ogImage_** | OG image of the post. Useful for social media sharing and SEO. | default = SITE.ogImage |
|
| **_ogImage_** | OG image of the post. Useful for social media sharing and SEO. | default = SITE.ogImage or generated SVG image |
|
||||||
|
|
||||||
`title` and `slug` fields in frontmatter must be specified.
|
Only `title`, `description` and `pubDatetime` fields in frontmatter must be specified.
|
||||||
|
|
||||||
Title is the title of the post and it is very important for search engine optimization (SEO).
|
Title and description (excerpt) are important for search engine optimization (SEO) and thus AstroPaper encourages to include these in blog posts.
|
||||||
|
|
||||||
`slug` is the unique identifier of the url. Thus, `slug` must be unique and different from other posts. The whitespace of `slug` needs to be separated with `-` or `_` but `-` is recommended. If slug is not specified, the slugified title of the post will be used as slug.
|
`slug` is the unique identifier of the url. Thus, `slug` must be unique and different from other posts. The whitespace of `slug` needs to be separated with `-` or `_` but `-` is recommended. However, even if you don't write the correct slug, AstroPaper will automatically slugify your incorrect slug. If slug is not specified, the slugified title of the post will be used as slug.
|
||||||
|
|
||||||
Here is the sample frontmatter for the post.
|
If you omit `tags` in a blog post (in other words, if no tag is specified), the default tag `others` will be used as a tag for that post. You can set the default tag in the `/src/content/_schemas.ts` file.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/contents/_schemas.ts
|
||||||
|
export const blogSchema = z.object({
|
||||||
|
// ---
|
||||||
|
// replace "others" with whatever you want
|
||||||
|
tags: z.array(z.string()).default(["others"]),
|
||||||
|
ogImage: z.string().optional(),
|
||||||
|
description: z.string(),
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sample Frontmatter
|
||||||
|
|
||||||
|
Here is the sample frontmatter for a post.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# src/contents/sample-post.md
|
# src/contents/sample-post.md
|
||||||
---
|
---
|
||||||
title: The title of the post
|
title: The title of the post
|
||||||
author: your name
|
author: your name
|
||||||
datetime: 2022-09-21T05:17:19Z
|
pubDatetime: 2022-09-21T05:17:19Z
|
||||||
slug: the-title-of-the-post
|
postSlug: the-title-of-the-post
|
||||||
featured: true
|
featured: true
|
||||||
draft: false
|
draft: false
|
||||||
tags:
|
tags:
|
||||||
@@ -101,3 +116,5 @@ My recommendation for image compression sites.
|
|||||||
### OG Image
|
### OG Image
|
||||||
|
|
||||||
The default OG image will be placed if a post does not specify the OG image. Though not required, OG image related to the post should be specify in the frontmatter. The recommended size for OG image is **_1200 X 640_** px.
|
The default OG image will be placed if a post does not specify the OG image. Though not required, OG image related to the post should be specify in the frontmatter. The recommended size for OG image is **_1200 X 640_** px.
|
||||||
|
|
||||||
|
> Since AstroPaper v1.4.0, OG images will be generated automatically if not specified. Check out [the announcement](https://astro-paper.pages.dev/posts/dynamic-og-image-generation-in-astropaper-blog-posts/).
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
---
|
||||||
|
author: Sat Naing
|
||||||
|
pubDatetime: 2023-01-30T15:57:52.737Z
|
||||||
|
title: AstroPaper 2.0
|
||||||
|
postSlug: astro-paper-2
|
||||||
|
featured: true
|
||||||
|
ogImage: https://user-images.githubusercontent.com/53733092/215771435-25408246-2309-4f8b-a781-1f3d93bdf0ec.png
|
||||||
|
tags:
|
||||||
|
- release
|
||||||
|
description: AstroPaper with the enhancements of Astro v2. Type-safe markdown contents, bug fixes and better dev experience etc.
|
||||||
|
---
|
||||||
|
|
||||||
|
Astro 2.0 has been released with some cool features, breaking changes, DX improvements, better error overlay and so on. AstroPaper takes advantage of those cool features, especially Content Collections API.
|
||||||
|
|
||||||
|
<!--  -->
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
## Features & Changes
|
||||||
|
|
||||||
|
### Type-safe Frontmatters and Redefined Blog Schema
|
||||||
|
|
||||||
|
Frontmatter of AstroPaper 2.0 markdown contents are now type-safe thanks to Astro’s Content Collections. Blog schema is defined inside the `src/content/_schemas.ts` file.
|
||||||
|
|
||||||
|
### New Home for Blog contents
|
||||||
|
|
||||||
|
All the blog posts were moved from `src/contents` to `src/content/blog` directory.
|
||||||
|
|
||||||
|
### New Fetch API
|
||||||
|
|
||||||
|
Contents are now fetched with `getCollection` function. No relative path to the content needs to be specified anymore.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// old content fetching method
|
||||||
|
- const postImportResult = import.meta.glob<MarkdownInstance<Frontmatter>>(
|
||||||
|
"../contents/**/**/*.md",);
|
||||||
|
|
||||||
|
// new content fetching method
|
||||||
|
+ const postImportResult = await getCollection("blog");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Modified Search Logic for better Search Result
|
||||||
|
|
||||||
|
In the older version of AstroPaper, when someone search some article, the search cirtea keys that will be searched are `title`, `description` and `headings` (heading means all the headings h1 ~ h6 of the blog post). In AstroPaper v2, only `title` and `description` will be searched as the user types.
|
||||||
|
|
||||||
|
### Renamed Frontmatter Properties
|
||||||
|
|
||||||
|
The following frontmatter properties are renamed.
|
||||||
|
|
||||||
|
| Old Names | New Names |
|
||||||
|
| --------- | ----------- |
|
||||||
|
| datetime | pubDatetime |
|
||||||
|
| slug | postSlug |
|
||||||
|
|
||||||
|
### Default Tag for blog post
|
||||||
|
|
||||||
|
If a blog post doesn't have any tag (in other words, frontmatter property `tags` is not specified), the default tag `others` will be used for that blog post. But you can set the default tag in the `/src/content/_schemas.ts` file.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/contents/_schemas.ts
|
||||||
|
export const blogSchema = z.object({
|
||||||
|
// ---
|
||||||
|
// replace "others" with whatever you want
|
||||||
|
tags: z.array(z.string()).default(["others"]),
|
||||||
|
ogImage: z.string().optional(),
|
||||||
|
description: z.string(),
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### New Predefined Dark Color Scheme
|
||||||
|
|
||||||
|
AstroPaper v2 has a new dark color scheme (high contrast & low contrast) which is based on Astro's dark logo. Check out [this link](https://astro-paper.pages.dev/posts/predefined-color-schemes#astro-dark) for more info.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Automatic Class Sorting
|
||||||
|
|
||||||
|
AstroPaper 2.0 includes automatic class sorting with [TailwindCSS Prettier plugin](https://tailwindcss.com/blog/automatic-class-sorting-with-prettier)
|
||||||
|
|
||||||
|
### Updated Docs & README
|
||||||
|
|
||||||
|
All the [#docs](https://astro-paper.pages.dev/tags/docs/) blog posts and [README](https://github.com/satnaing/astro-paper#readme) are updated for this AstroPaper v2.
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
- fix broken tags in the Blog Post page
|
||||||
|
- in a tag page, the last part of the breadcrumb is now updated to lower-case for consistency
|
||||||
|
- exclude draft posts in a tag page
|
||||||
|
- fix 'onChange value not updating issue' after a page reload
|
||||||
+4
-2
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
author: Sat Naing
|
author: Sat Naing
|
||||||
datetime: 2022-09-25T15:20:35Z
|
pubDatetime: 2022-09-25T15:20:35Z
|
||||||
title: Customizing AstroPaper theme color schemes
|
title: Customizing AstroPaper theme color schemes
|
||||||
slug: ""
|
postSlug: ""
|
||||||
featured: false
|
featured: false
|
||||||
draft: false
|
draft: false
|
||||||
tags:
|
tags:
|
||||||
@@ -130,3 +130,5 @@ Here is an example of changing the light color scheme.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> Check out some [predefined color schemes](https://astro-paper.pages.dev/posts/predefined-color-schemes/) AstroPaper has already crafted for you.
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
author: Sat Naing
|
author: Sat Naing
|
||||||
datetime: 2022-12-28T04:59:04.866Z
|
pubDatetime: 2022-12-28T04:59:04.866Z
|
||||||
title: Dynamic OG image generation in AstroPaper blog posts
|
title: Dynamic OG image generation in AstroPaper blog posts
|
||||||
slug: dynamic-og-image-generation-in-astropaper-blog-posts
|
postSlug: dynamic-og-image-generation-in-astropaper-blog-posts
|
||||||
featured: false
|
featured: false
|
||||||
draft: false
|
draft: false
|
||||||
tags:
|
tags:
|
||||||
+11
-11
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
author: Sat Naing
|
author: Sat Naing
|
||||||
datetime: 2022-09-23T04:58:53Z
|
pubDatetime: 2022-09-23T04:58:53Z
|
||||||
title: How to configure AstroPaper theme
|
title: How to configure AstroPaper theme
|
||||||
slug: how-to-configure-astropaper-theme
|
postSlug: how-to-configure-astropaper-theme
|
||||||
featured: true
|
featured: true
|
||||||
draft: false
|
draft: false
|
||||||
tags:
|
tags:
|
||||||
@@ -37,15 +37,15 @@ export const SITE = {
|
|||||||
|
|
||||||
Here are SITE configuration options
|
Here are SITE configuration options
|
||||||
|
|
||||||
| Options | Description |
|
| Options | Description |
|
||||||
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| `website` | Your deployed website url |
|
| `website` | Your deployed website url |
|
||||||
| `author` | Your name |
|
| `author` | Your name |
|
||||||
| `desc` | Your site description. Useful for SEO and social media sharing. |
|
| `desc` | Your site description. Useful for SEO and social media sharing. |
|
||||||
| `title` | Your site name |
|
| `title` | Your site name |
|
||||||
| `ogImage` | Your default OG image for the site. Useful for social media sharing. OG image can be updated under `/public` directory. |
|
| `ogImage` | Your default OG image for the site. Useful for social media sharing. OG images can be an external image url or they can be placed under `/public` directory. |
|
||||||
| `lightAndDarkMode` | Enable or disable `light & dark mode` for the website. If disabled, primary color scheme will be used. This option is enabled by default. |
|
| `lightAndDarkMode` | Enable or disable `light & dark mode` for the website. If disabled, primary color scheme will be used. This option is enabled by default. |
|
||||||
| `postPerPage` | You can specify how many posts will be displayed in each posts page. (eg: if you set SITE.postPerPage to 3, each page will only show 3 posts per page) |
|
| `postPerPage` | You can specify how many posts will be displayed in each posts page. (eg: if you set SITE.postPerPage to 3, each page will only show 3 posts per page) |
|
||||||
|
|
||||||
## Configuring logo or title
|
## Configuring logo or title
|
||||||
|
|
||||||
+5
-3
@@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
title: How to connect AstroPaper blog with Forestry CMS
|
title: How to connect AstroPaper blog with Forestry CMS
|
||||||
author: Sat Naing
|
author: Sat Naing
|
||||||
datetime: 2022-09-21T05:17:19Z
|
pubDatetime: 2022-09-21T05:17:19Z
|
||||||
slug: how-to-connect-astro-paper-blog-with-forestry-cms
|
postSlug: how-to-connect-astro-paper-blog-with-forestry-cms
|
||||||
featured: true
|
featured: false
|
||||||
draft: false
|
draft: false
|
||||||
tags:
|
tags:
|
||||||
- docs
|
- docs
|
||||||
@@ -15,6 +15,8 @@ description:
|
|||||||
Headless CMS.
|
Headless CMS.
|
||||||
---
|
---
|
||||||
|
|
||||||
|
> Important!!! Forestry is going to be discontinued on April 22nd, 2023. You can [read their announcement](https://forestry.io/blog/forestry.io-end-of-life/) for more info.
|
||||||
|
|
||||||
In this article, I will explain step by step process of connecting AstroPaper theme with the Forestry headless CMS. So, let's get started 🎉
|
In this article, I will explain step by step process of connecting AstroPaper theme with the Forestry headless CMS. So, let's get started 🎉
|
||||||
|
|
||||||
## Table of contents
|
## Table of contents
|
||||||
+3
-2
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
title: How Do I Develop My Portfolio Website & Blog
|
title: How Do I Develop My Portfolio Website & Blog
|
||||||
author: Sat Naing
|
author: Sat Naing
|
||||||
datetime: 2022-03-25T16:55:12.000+00:00
|
pubDatetime: 2022-03-25T16:55:12.000+00:00
|
||||||
slug: how-do-i-develop-my-portfolio-and-blog
|
postSlug: how-do-i-develop-my-portfolio-and-blog
|
||||||
featured: false
|
featured: false
|
||||||
draft: false
|
draft: false
|
||||||
tags:
|
tags:
|
||||||
@@ -10,6 +10,7 @@ tags:
|
|||||||
- TailwindCSS
|
- TailwindCSS
|
||||||
- HeadlessCMS
|
- HeadlessCMS
|
||||||
- Blog
|
- Blog
|
||||||
|
ogImage: ""
|
||||||
description:
|
description:
|
||||||
"EXAMPLE POST: My experience about developing my first portfolio website and a blog
|
"EXAMPLE POST: My experience about developing my first portfolio website and a blog
|
||||||
using NextJS and a headless CMS."
|
using NextJS and a headless CMS."
|
||||||
+48
-2
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
author: Sat Naing
|
author: Sat Naing
|
||||||
datetime: 2022-09-26T12:13:24Z
|
pubDatetime: 2022-09-26T12:13:24Z
|
||||||
title: Predefined color schemes
|
title: Predefined color schemes
|
||||||
slug: predefined-color-schemes
|
postSlug: predefined-color-schemes
|
||||||
featured: false
|
featured: false
|
||||||
draft: false
|
draft: false
|
||||||
tags:
|
tags:
|
||||||
@@ -75,6 +75,21 @@ html[data-theme="light"] {
|
|||||||
|
|
||||||
Light color scheme has to be defined as `html[data-theme="dark"]`.
|
Light color scheme has to be defined as `html[data-theme="dark"]`.
|
||||||
|
|
||||||
|
### AstroPaper 1 original Dark Theme
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```css
|
||||||
|
html[data-theme="dark"] {
|
||||||
|
--color-fill: 47, 55, 65;
|
||||||
|
--color-text-base: 230, 230, 230;
|
||||||
|
--color-accent: 26, 217, 217;
|
||||||
|
--color-card: 63, 75, 90;
|
||||||
|
--color-card-muted: 89, 107, 129;
|
||||||
|
--color-border: 59, 70, 85;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Deep Oyster
|
### Deep Oyster
|
||||||
|
|
||||||

|

|
||||||
@@ -104,3 +119,34 @@ html[data-theme="dark"] {
|
|||||||
--color-border: 134, 67, 107;
|
--color-border: 134, 67, 107;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Astro dark (High Contrast)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```css
|
||||||
|
html[data-theme="dark"] {
|
||||||
|
--color-fill: 16, 23, 42; /* higher contrast bgColor */
|
||||||
|
--color-fill: 33, 39, 55;
|
||||||
|
--color-text-base: 234, 237, 243;
|
||||||
|
--color-accent: 255, 107, 1;
|
||||||
|
--color-card: 27, 39, 70;
|
||||||
|
--color-card-muted: 138, 51, 2;
|
||||||
|
--color-border: 171, 75, 8;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Astro dark (New default dark theme in AstroPaper 2)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```css
|
||||||
|
html[data-theme="dark"] {
|
||||||
|
--color-fill: 33, 39, 55; /* lower contrast bgColor */
|
||||||
|
--color-text-base: 234, 237, 243;
|
||||||
|
--color-accent: 255, 107, 1;
|
||||||
|
--color-card: 52, 63, 96;
|
||||||
|
--color-card-muted: 138, 51, 2;
|
||||||
|
--color-border: 171, 75, 8;
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
title: My recent article 2
|
title: My recent article 2
|
||||||
author: Sat Naing
|
author: Sat Naing
|
||||||
datetime: 2022-06-06T04:06:31Z
|
pubDatetime: 2022-06-06T04:06:31Z
|
||||||
slug: my-recent-2
|
postSlug: my-recent-2
|
||||||
featured: false
|
featured: false
|
||||||
draft: true
|
draft: true
|
||||||
tags:
|
tags:
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: Tailwind Typography Plugin
|
title: Tailwind Typography Plugin
|
||||||
author: Sat Naing
|
author: Sat Naing
|
||||||
datetime: 2022-07-05T02:05:51Z
|
pubDatetime: 2022-07-05T02:05:51Z
|
||||||
featured: false
|
featured: false
|
||||||
draft: false
|
draft: false
|
||||||
tags:
|
tags:
|
||||||
- TypeScript
|
- TypeScript
|
||||||
- Astro
|
- Astro
|
||||||
|
ogImage: ""
|
||||||
description: "EXAMPLE POST: About Tailwind Typography Plugin and how you can use it effectively."
|
description: "EXAMPLE POST: About Tailwind Typography Plugin and how you can use it effectively."
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
title: How Do I Develop My Terminal Portfolio Website with React
|
title: How Do I Develop My Terminal Portfolio Website with React
|
||||||
author: Sat Naing
|
author: Sat Naing
|
||||||
datetime: 2022-06-09T03:42:51Z
|
pubDatetime: 2022-06-09T03:42:51Z
|
||||||
slug: how-do-i-develop-my-terminal-portfolio-website-with-react
|
postSlug: how-do-i-develop-my-terminal-portfolio-website-with-react
|
||||||
featured: false
|
featured: false
|
||||||
draft: false
|
draft: false
|
||||||
tags:
|
tags:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { defineCollection } from "astro:content";
|
||||||
|
import { blogSchema } from "./_schemas";
|
||||||
|
|
||||||
|
const blog = defineCollection({
|
||||||
|
schema: blogSchema,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const collections = { blog };
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import { SITE } from "src/config";
|
import { SITE } from "@config";
|
||||||
import Breadcrumbs from "@components/Breadcrumbs.astro";
|
import Breadcrumbs from "@components/Breadcrumbs.astro";
|
||||||
import Footer from "@components/Footer.astro";
|
import Footer from "@components/Footer.astro";
|
||||||
import Header from "@components/Header.astro";
|
import Header from "@components/Header.astro";
|
||||||
@@ -19,8 +19,8 @@ const { frontmatter } = Astro.props;
|
|||||||
<Header activeNav="about" />
|
<Header activeNav="about" />
|
||||||
<Breadcrumbs />
|
<Breadcrumbs />
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<section id="about" class="mb-28 prose max-w-3xl prose-img:border-0">
|
<section id="about" class="prose mb-28 max-w-3xl prose-img:border-0">
|
||||||
<h1 class="text-2xl sm:text-3xl tracking-wider">{frontmatter.title}</h1>
|
<h1 class="text-2xl tracking-wider sm:text-3xl">{frontmatter.title}</h1>
|
||||||
<slot />
|
<slot />
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import { SITE } from "src/config";
|
import { SITE } from "@config";
|
||||||
import "../styles/base.css";
|
import "../styles/base.css";
|
||||||
|
|
||||||
const googleSiteVerification = import.meta.env.PUBLIC_GOOGLE_SITE_VERIFICATION;
|
const googleSiteVerification = import.meta.env.PUBLIC_GOOGLE_SITE_VERIFICATION;
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ const { pageTitle, pageDesc } = Astro.props;
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
#main-content {
|
#main-content {
|
||||||
@apply max-w-3xl mx-auto px-4 pb-12 w-full;
|
@apply mx-auto w-full max-w-3xl px-4 pb-12;
|
||||||
}
|
}
|
||||||
#main-content h1 {
|
#main-content h1 {
|
||||||
@apply font-semibold text-2xl sm:text-3xl;
|
@apply text-2xl font-semibold sm:text-3xl;
|
||||||
}
|
}
|
||||||
#main-content p {
|
#main-content p {
|
||||||
@apply mt-2 mb-6 italic;
|
@apply mt-2 mb-6 italic;
|
||||||
|
|||||||
@@ -4,16 +4,17 @@ import Header from "@components/Header.astro";
|
|||||||
import Footer from "@components/Footer.astro";
|
import Footer from "@components/Footer.astro";
|
||||||
import Tag from "@components/Tag.astro";
|
import Tag from "@components/Tag.astro";
|
||||||
import Datetime from "@components/Datetime";
|
import Datetime from "@components/Datetime";
|
||||||
import type { MarkdownInstance } from "astro";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import type { Frontmatter } from "src/types";
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
post: MarkdownInstance<Frontmatter>;
|
post: CollectionEntry<"blog">;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { frontmatter, Content } = Astro.props.post;
|
const { post } = Astro.props;
|
||||||
|
|
||||||
const { title, author, description, ogImage, datetime, tags } = frontmatter;
|
const { title, author, description, ogImage, pubDatetime, tags } = post.data;
|
||||||
|
|
||||||
|
const { Content } = await post.render();
|
||||||
|
|
||||||
const ogUrl = new URL(ogImage ? ogImage : `${title}.svg`, Astro.url.origin)
|
const ogUrl = new URL(ogImage ? ogImage : `${title}.svg`, Astro.url.origin)
|
||||||
.href;
|
.href;
|
||||||
@@ -21,9 +22,9 @@ const ogUrl = new URL(ogImage ? ogImage : `${title}.svg`, Astro.url.origin)
|
|||||||
|
|
||||||
<Layout title={title} author={author} description={description} ogImage={ogUrl}>
|
<Layout title={title} author={author} description={description} ogImage={ogUrl}>
|
||||||
<Header />
|
<Header />
|
||||||
<div class="max-w-3xl mx-auto w-full px-2 flex justify-start">
|
<div class="mx-auto flex w-full max-w-3xl justify-start px-2">
|
||||||
<button
|
<button
|
||||||
class="mt-8 mb-2 hover:opacity-75 flex focus-outline"
|
class="focus-outline mt-8 mb-2 flex hover:opacity-75"
|
||||||
onclick="history.back()"
|
onclick="history.back()"
|
||||||
>
|
>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
@@ -35,8 +36,8 @@ const ogUrl = new URL(ogImage ? ogImage : `${title}.svg`, Astro.url.origin)
|
|||||||
</div>
|
</div>
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<h1 class="post-title">{title}</h1>
|
<h1 class="post-title">{title}</h1>
|
||||||
<Datetime datetime={datetime} size="lg" className="my-2" />
|
<Datetime datetime={pubDatetime} size="lg" className="my-2" />
|
||||||
<article id="article" role="article" class="mx-auto max-w-3xl mt-8 prose">
|
<article id="article" role="article" class="prose mx-auto mt-8 max-w-3xl">
|
||||||
<Content />
|
<Content />
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
@@ -49,10 +50,10 @@ const ogUrl = new URL(ogImage ? ogImage : `${title}.svg`, Astro.url.origin)
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
main {
|
main {
|
||||||
@apply max-w-3xl mx-auto px-4 pb-12 w-full;
|
@apply mx-auto w-full max-w-3xl px-4 pb-12;
|
||||||
}
|
}
|
||||||
.post-title {
|
.post-title {
|
||||||
@apply font-semibold text-2xl text-skin-accent;
|
@apply text-2xl font-semibold text-skin-accent;
|
||||||
}
|
}
|
||||||
.tags-container {
|
.tags-container {
|
||||||
@apply my-8;
|
@apply my-8;
|
||||||
|
|||||||
+8
-11
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import { SITE } from "src/config";
|
import { SITE } from "@config";
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
import Main from "@layouts/Main.astro";
|
import Main from "@layouts/Main.astro";
|
||||||
import Header from "@components/Header.astro";
|
import Header from "@components/Header.astro";
|
||||||
@@ -7,13 +7,12 @@ import Footer from "@components/Footer.astro";
|
|||||||
import Card from "@components/Card";
|
import Card from "@components/Card";
|
||||||
import LinkButton from "@components/LinkButton.astro";
|
import LinkButton from "@components/LinkButton.astro";
|
||||||
import slugify from "@utils/slugify";
|
import slugify from "@utils/slugify";
|
||||||
import type { MarkdownInstance } from "astro";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import type { Frontmatter } from "src/types";
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
pageNum: number;
|
pageNum: number;
|
||||||
totalPages: number;
|
totalPages: number;
|
||||||
posts: MarkdownInstance<Frontmatter>[];
|
posts: CollectionEntry<"blog">[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { pageNum, totalPages, posts } = Astro.props;
|
const { pageNum, totalPages, posts } = Astro.props;
|
||||||
@@ -27,11 +26,9 @@ const next = pageNum < totalPages ? "" : "disabled";
|
|||||||
<Main pageTitle="Posts" pageDesc="All the articles I've posted.">
|
<Main pageTitle="Posts" pageDesc="All the articles I've posted.">
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
posts.map(({ frontmatter }) => {
|
posts.map(({ data }) => (
|
||||||
return (
|
<Card href={`/posts/${slugify(data)}`} frontmatter={data} />
|
||||||
<Card href={`/posts/${slugify(frontmatter)}`} post={frontmatter} />
|
))
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</Main>
|
</Main>
|
||||||
@@ -69,10 +66,10 @@ const next = pageNum < totalPages ? "" : "disabled";
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.pagination-wrapper {
|
.pagination-wrapper {
|
||||||
@apply flex justify-center mt-auto mb-8;
|
@apply mt-auto mb-8 flex justify-center;
|
||||||
}
|
}
|
||||||
.disabled {
|
.disabled {
|
||||||
@apply opacity-50 hover:text-skin-base group-hover:fill-skin-base pointer-events-none select-none;
|
@apply pointer-events-none select-none opacity-50 hover:text-skin-base group-hover:fill-skin-base;
|
||||||
}
|
}
|
||||||
.disabled-svg {
|
.disabled-svg {
|
||||||
@apply group-hover:!fill-skin-base;
|
@apply group-hover:!fill-skin-base;
|
||||||
|
|||||||
+5
-5
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import { SITE } from "src/config";
|
import { SITE } from "@config";
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
import Header from "@components/Header.astro";
|
import Header from "@components/Header.astro";
|
||||||
import Footer from "@components/Footer.astro";
|
import Footer from "@components/Footer.astro";
|
||||||
@@ -28,15 +28,15 @@ import LinkButton from "@components/LinkButton.astro";
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
#main-content {
|
#main-content {
|
||||||
@apply max-w-3xl mx-auto flex-1 justify-center items-center flex;
|
@apply mx-auto flex max-w-3xl flex-1 items-center justify-center;
|
||||||
}
|
}
|
||||||
.not-found-wrapper {
|
.not-found-wrapper {
|
||||||
@apply flex flex-col items-center justify-center mb-14;
|
@apply mb-14 flex flex-col items-center justify-center;
|
||||||
}
|
}
|
||||||
.not-found-wrapper h1 {
|
.not-found-wrapper h1 {
|
||||||
@apply font-bold text-9xl text-skin-accent;
|
@apply text-9xl font-bold text-skin-accent;
|
||||||
}
|
}
|
||||||
.not-found-wrapper p {
|
.not-found-wrapper p {
|
||||||
@apply text-2xl sm:text-3xl mt-4;
|
@apply mt-4 text-2xl sm:text-3xl;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,24 +1,18 @@
|
|||||||
import type { APIRoute, MarkdownInstance } from "astro";
|
import { getCollection } from "astro:content";
|
||||||
import generateOgImage from "@utils/generateOgImage";
|
import generateOgImage from "@utils/generateOgImage";
|
||||||
import type { Frontmatter } from "@types";
|
import type { APIRoute } from "astro";
|
||||||
|
|
||||||
export const get: APIRoute = async ({ params }) => ({
|
export const get: APIRoute = async ({ params }) => ({
|
||||||
body: await generateOgImage(params.ogTitle),
|
body: await generateOgImage(params.ogTitle),
|
||||||
});
|
});
|
||||||
|
|
||||||
const postImportResult = import.meta.glob<MarkdownInstance<Frontmatter>>(
|
const postImportResult = await getCollection("blog", ({ data }) => !data.draft);
|
||||||
"../contents/**/**/*.md",
|
|
||||||
{
|
|
||||||
eager: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const posts = Object.values(postImportResult);
|
const posts = Object.values(postImportResult);
|
||||||
|
|
||||||
export function getStaticPaths() {
|
export function getStaticPaths() {
|
||||||
return posts
|
return posts
|
||||||
.filter(({ frontmatter }) => !frontmatter.draft)
|
.filter(({ data }) => !data.ogImage)
|
||||||
.filter(({ frontmatter }) => !frontmatter.ogImage)
|
.map(({ data }) => ({
|
||||||
.map(({ frontmatter }) => ({
|
params: { ogTitle: data.title },
|
||||||
params: { ogTitle: frontmatter.title },
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-18
@@ -1,22 +1,20 @@
|
|||||||
---
|
---
|
||||||
|
import { getCollection } from "astro:content";
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
import Header from "@components/Header.astro";
|
import Header from "@components/Header.astro";
|
||||||
import Footer from "@components/Footer.astro";
|
import Footer from "@components/Footer.astro";
|
||||||
import LinkButton from "@components/LinkButton.astro";
|
import LinkButton from "@components/LinkButton.astro";
|
||||||
import Hr from "@components/Hr.astro";
|
import Hr from "@components/Hr.astro";
|
||||||
import Card from "@components/Card";
|
import Card from "@components/Card";
|
||||||
|
import Socials from "@components/Socials.astro";
|
||||||
import getSortedPosts from "@utils/getSortedPosts";
|
import getSortedPosts from "@utils/getSortedPosts";
|
||||||
import slugify from "@utils/slugify";
|
import slugify from "@utils/slugify";
|
||||||
import type { Frontmatter } from "src/types";
|
|
||||||
import Socials from "@components/Socials.astro";
|
|
||||||
import { SOCIALS } from "@config";
|
import { SOCIALS } from "@config";
|
||||||
|
|
||||||
const posts = await Astro.glob<Frontmatter>("../contents/**/*.md");
|
const posts = await getCollection("blog");
|
||||||
|
|
||||||
const sortedPosts = getSortedPosts(posts);
|
const sortedPosts = getSortedPosts(posts);
|
||||||
const featuredPosts = sortedPosts.filter(
|
const featuredPosts = sortedPosts.filter(({ data }) => data.featured);
|
||||||
({ frontmatter }) => frontmatter.featured
|
|
||||||
);
|
|
||||||
|
|
||||||
const socialCount = SOCIALS.filter(social => social.active).length;
|
const socialCount = SOCIALS.filter(social => social.active).length;
|
||||||
---
|
---
|
||||||
@@ -76,10 +74,10 @@ const socialCount = SOCIALS.filter(social => social.active).length;
|
|||||||
<section id="featured">
|
<section id="featured">
|
||||||
<h2>Featured</h2>
|
<h2>Featured</h2>
|
||||||
<ul>
|
<ul>
|
||||||
{featuredPosts.map(({ frontmatter }) => (
|
{featuredPosts.map(({ data }) => (
|
||||||
<Card
|
<Card
|
||||||
href={`/posts/${slugify(frontmatter)}`}
|
href={`/posts/${slugify(data)}`}
|
||||||
post={frontmatter}
|
frontmatter={data}
|
||||||
secHeading={false}
|
secHeading={false}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@@ -95,11 +93,11 @@ const socialCount = SOCIALS.filter(social => social.active).length;
|
|||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
sortedPosts.map(
|
sortedPosts.map(
|
||||||
({ frontmatter }, index) =>
|
({ data }, index) =>
|
||||||
index < 4 && (
|
index < 4 && (
|
||||||
<Card
|
<Card
|
||||||
href={`/posts/${slugify(frontmatter)}`}
|
href={`/posts/${slugify(data)}`}
|
||||||
post={frontmatter}
|
frontmatter={data}
|
||||||
secHeading={false}
|
secHeading={false}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@@ -128,22 +126,22 @@ const socialCount = SOCIALS.filter(social => social.active).length;
|
|||||||
@apply pt-8 pb-6;
|
@apply pt-8 pb-6;
|
||||||
}
|
}
|
||||||
#hero h1 {
|
#hero h1 {
|
||||||
@apply inline-block font-bold my-4 sm:my-8 text-3xl sm:text-5xl;
|
@apply my-4 inline-block text-3xl font-bold sm:my-8 sm:text-5xl;
|
||||||
}
|
}
|
||||||
#hero .rss-link {
|
#hero .rss-link {
|
||||||
@apply mb-6;
|
@apply mb-6;
|
||||||
}
|
}
|
||||||
#hero .rss-icon {
|
#hero .rss-icon {
|
||||||
@apply h-6 w-6 scale-110 sm:scale-125 mb-2 sm:mb-3 fill-skin-accent;
|
@apply mb-2 h-6 w-6 scale-110 fill-skin-accent sm:mb-3 sm:scale-125;
|
||||||
}
|
}
|
||||||
#hero p {
|
#hero p {
|
||||||
@apply my-2;
|
@apply my-2;
|
||||||
}
|
}
|
||||||
.social-wrapper {
|
.social-wrapper {
|
||||||
@apply flex flex-col sm:flex-row sm:items-center mt-4;
|
@apply mt-4 flex flex-col sm:flex-row sm:items-center;
|
||||||
}
|
}
|
||||||
.social-links {
|
.social-links {
|
||||||
@apply whitespace-nowrap mr-2 sm:mb-0 mb-1;
|
@apply mr-2 mb-1 whitespace-nowrap sm:mb-0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Featured & Recent Posts Sections ===== */
|
/* ===== Featured & Recent Posts Sections ===== */
|
||||||
@@ -153,9 +151,9 @@ const socialCount = SOCIALS.filter(social => social.active).length;
|
|||||||
}
|
}
|
||||||
#featured h2,
|
#featured h2,
|
||||||
#recent-posts h2 {
|
#recent-posts h2 {
|
||||||
@apply font-semibold text-2xl tracking-wide;
|
@apply text-2xl font-semibold tracking-wide;
|
||||||
}
|
}
|
||||||
.all-posts-btn-wrapper {
|
.all-posts-btn-wrapper {
|
||||||
@apply text-center my-8;
|
@apply my-8 text-center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,53 +1,27 @@
|
|||||||
---
|
---
|
||||||
import { SITE } from "src/config";
|
import { CollectionEntry, getCollection } from "astro:content";
|
||||||
import Posts from "@layouts/Posts.astro";
|
import Posts from "@layouts/Posts.astro";
|
||||||
import PostDetails from "@layouts/PostDetails.astro";
|
import PostDetails from "@layouts/PostDetails.astro";
|
||||||
import getSortedPosts from "@utils/getSortedPosts";
|
import getSortedPosts from "@utils/getSortedPosts";
|
||||||
import getPageNumbers from "@utils/getPageNumbers";
|
import getPageNumbers from "@utils/getPageNumbers";
|
||||||
import type { MarkdownInstance } from "astro";
|
|
||||||
import type { Frontmatter } from "src/types";
|
|
||||||
import slugify from "@utils/slugify";
|
import slugify from "@utils/slugify";
|
||||||
|
import { SITE } from "@config";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
post: MarkdownInstance<Frontmatter>;
|
post: CollectionEntry<"blog">;
|
||||||
}
|
}
|
||||||
|
|
||||||
type PostResult = {
|
|
||||||
params: {
|
|
||||||
slug: string | number;
|
|
||||||
};
|
|
||||||
props?: {
|
|
||||||
post: MarkdownInstance<Record<string, any>>;
|
|
||||||
};
|
|
||||||
}[];
|
|
||||||
|
|
||||||
type PagePaths = {
|
|
||||||
params: {
|
|
||||||
slug: string;
|
|
||||||
};
|
|
||||||
}[];
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const posts = await Astro.glob<Frontmatter>("../../contents/**/*.md");
|
const posts = await getCollection("blog", ({ data }) => !data.draft);
|
||||||
|
|
||||||
const filteredPosts = posts.filter(({ frontmatter }) => !frontmatter.draft);
|
const postResult = posts.map(post => ({
|
||||||
|
params: { slug: slugify(post.data) },
|
||||||
|
props: { post },
|
||||||
|
}));
|
||||||
|
|
||||||
let postResult: PostResult = filteredPosts.map(post => {
|
const pagePaths = getPageNumbers(posts.length).map(pageNum => ({
|
||||||
return {
|
params: { slug: String(pageNum) },
|
||||||
params: {
|
}));
|
||||||
slug: slugify(post.frontmatter),
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
post,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const pagePaths: PagePaths = getPageNumbers(filteredPosts.length).map(
|
|
||||||
pageNum => ({
|
|
||||||
params: { slug: String(pageNum) },
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return [...postResult, ...pagePaths];
|
return [...postResult, ...pagePaths];
|
||||||
}
|
}
|
||||||
@@ -55,7 +29,7 @@ export async function getStaticPaths() {
|
|||||||
const { slug } = Astro.params;
|
const { slug } = Astro.params;
|
||||||
const { post } = Astro.props;
|
const { post } = Astro.props;
|
||||||
|
|
||||||
const posts = await Astro.glob<Frontmatter>("../../contents/**/*.md");
|
const posts = await getCollection("blog");
|
||||||
|
|
||||||
const sortedPosts = getSortedPosts(posts);
|
const sortedPosts = getSortedPosts(posts);
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
---
|
---
|
||||||
import { SITE } from "src/config";
|
import { SITE } from "@config";
|
||||||
import Posts from "@layouts/Posts.astro";
|
import Posts from "@layouts/Posts.astro";
|
||||||
import getSortedPosts from "@utils/getSortedPosts";
|
import getSortedPosts from "@utils/getSortedPosts";
|
||||||
import getPageNumbers from "@utils/getPageNumbers";
|
import getPageNumbers from "@utils/getPageNumbers";
|
||||||
import type { Frontmatter } from "src/types";
|
|
||||||
|
|
||||||
const posts = await Astro.glob<Frontmatter>("../../contents/**/*.md");
|
import { getCollection } from "astro:content";
|
||||||
|
|
||||||
|
const posts = await getCollection("blog");
|
||||||
|
|
||||||
const sortedPosts = getSortedPosts(posts);
|
const sortedPosts = getSortedPosts(posts);
|
||||||
|
|
||||||
|
|||||||
+12
-21
@@ -1,28 +1,19 @@
|
|||||||
import { SITE } from "src/config";
|
|
||||||
import rss from "@astrojs/rss";
|
import rss from "@astrojs/rss";
|
||||||
import type { Frontmatter } from "src/types";
|
import { getCollection } from "astro:content";
|
||||||
import type { MarkdownInstance } from "astro";
|
import { SITE } from "@config";
|
||||||
import slugify from "@utils/slugify";
|
import slugify from "@utils/slugify";
|
||||||
|
|
||||||
const postImportResult = import.meta.glob<MarkdownInstance<Frontmatter>>(
|
export async function get() {
|
||||||
"../contents/**/**/*.md",
|
const posts = await getCollection("blog", ({ data }) => !data.draft);
|
||||||
{
|
return rss({
|
||||||
eager: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const posts = Object.values(postImportResult);
|
|
||||||
|
|
||||||
export const get = () =>
|
|
||||||
rss({
|
|
||||||
title: SITE.title,
|
title: SITE.title,
|
||||||
description: SITE.desc,
|
description: SITE.desc,
|
||||||
site: SITE.website,
|
site: SITE.website,
|
||||||
items: posts
|
items: posts.map(({ data }) => ({
|
||||||
.filter(({ frontmatter }) => !frontmatter.draft)
|
link: `posts/${slugify(data)}`,
|
||||||
.map(({ frontmatter }) => ({
|
title: data.title,
|
||||||
link: `posts/${slugify(frontmatter)}`,
|
description: data.description,
|
||||||
title: frontmatter.title,
|
pubDate: new Date(data.pubDatetime),
|
||||||
description: frontmatter.description,
|
})),
|
||||||
pubDate: new Date(frontmatter.datetime),
|
|
||||||
})),
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|||||||
+8
-11
@@ -1,24 +1,21 @@
|
|||||||
---
|
---
|
||||||
import { SITE } from "src/config";
|
import { getCollection } from "astro:content";
|
||||||
|
import { SITE } from "@config";
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
import Main from "@layouts/Main.astro";
|
import Main from "@layouts/Main.astro";
|
||||||
import Header from "@components/Header.astro";
|
import Header from "@components/Header.astro";
|
||||||
import Footer from "@components/Footer.astro";
|
import Footer from "@components/Footer.astro";
|
||||||
import Search from "@components/Search";
|
import Search from "@components/Search";
|
||||||
import type { Frontmatter } from "src/types";
|
|
||||||
|
|
||||||
// Retrieve all articles
|
// Retrieve all articles
|
||||||
const posts = await Astro.glob<Frontmatter>("../contents/**/*.md");
|
const posts = await getCollection("blog", ({ data }) => !data.draft);
|
||||||
|
|
||||||
// List of items to search in
|
// List of items to search in
|
||||||
const searchList = posts
|
const searchList = posts.map(({ data }) => ({
|
||||||
.filter(({ frontmatter }) => !frontmatter.draft)
|
title: data.title,
|
||||||
.map(post => ({
|
description: data.description,
|
||||||
title: post.frontmatter.title,
|
data,
|
||||||
description: post.frontmatter.description,
|
}));
|
||||||
headings: post.getHeadings().map(h => h.text),
|
|
||||||
frontmatter: post.frontmatter,
|
|
||||||
}));
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={`Search | ${SITE.title}`}>
|
<Layout title={`Search | ${SITE.title}`}>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import { SITE } from "src/config";
|
import { CollectionEntry, getCollection } from "astro:content";
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
import Main from "@layouts/Main.astro";
|
import Main from "@layouts/Main.astro";
|
||||||
import Header from "@components/Header.astro";
|
import Header from "@components/Header.astro";
|
||||||
@@ -7,39 +7,30 @@ import Footer from "@components/Footer.astro";
|
|||||||
import Card from "@components/Card";
|
import Card from "@components/Card";
|
||||||
import getUniqueTags from "@utils/getUniqueTags";
|
import getUniqueTags from "@utils/getUniqueTags";
|
||||||
import getPostsByTag from "@utils/getPostsByTag";
|
import getPostsByTag from "@utils/getPostsByTag";
|
||||||
import type { MarkdownInstance } from "astro";
|
|
||||||
import type { Frontmatter } from "src/types";
|
|
||||||
import slugify from "@utils/slugify";
|
import slugify from "@utils/slugify";
|
||||||
|
import { SITE } from "@config";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
post: MarkdownInstance<Frontmatter>;
|
post: CollectionEntry<"blog">;
|
||||||
tag: string;
|
tag: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const posts: MarkdownInstance<Frontmatter>[] = await Astro.glob(
|
const posts = await getCollection("blog");
|
||||||
"../../contents/**/*.md"
|
|
||||||
);
|
|
||||||
|
|
||||||
const tags = getUniqueTags(posts);
|
const tags = getUniqueTags(posts);
|
||||||
|
|
||||||
return tags.map(tag => {
|
return tags.map(tag => {
|
||||||
return {
|
return {
|
||||||
params: {
|
params: { tag },
|
||||||
tag,
|
props: { tag },
|
||||||
},
|
|
||||||
props: {
|
|
||||||
tag,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { tag } = Astro.props;
|
const { tag } = Astro.props;
|
||||||
|
|
||||||
const posts: MarkdownInstance<Frontmatter>[] = await Astro.glob(
|
const posts = await getCollection("blog", ({ data }) => !data.draft);
|
||||||
"../../contents/**/*.md"
|
|
||||||
);
|
|
||||||
|
|
||||||
const tagPosts = getPostsByTag(posts, tag);
|
const tagPosts = getPostsByTag(posts, tag);
|
||||||
---
|
---
|
||||||
@@ -52,8 +43,8 @@ const tagPosts = getPostsByTag(posts, tag);
|
|||||||
>
|
>
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
tagPosts.map(({ frontmatter }) => (
|
tagPosts.map(({ data }) => (
|
||||||
<Card href={`/posts/${slugify(frontmatter)}`} post={frontmatter} />
|
<Card href={`/posts/${slugify(data)}`} frontmatter={data} />
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
---
|
---
|
||||||
import { SITE } from "src/config";
|
import { getCollection } from "astro:content";
|
||||||
import Header from "@components/Header.astro";
|
import Header from "@components/Header.astro";
|
||||||
import Footer from "@components/Footer.astro";
|
import Footer from "@components/Footer.astro";
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
import Main from "@layouts/Main.astro";
|
import Main from "@layouts/Main.astro";
|
||||||
import Tag from "@components/Tag.astro";
|
import Tag from "@components/Tag.astro";
|
||||||
import getUniqueTags from "@utils/getUniqueTags";
|
import getUniqueTags from "@utils/getUniqueTags";
|
||||||
import type { Frontmatter } from "src/types";
|
import { SITE } from "@config";
|
||||||
|
|
||||||
const posts = await Astro.glob<Frontmatter>("../../contents/**/*.md");
|
const posts = await getCollection("blog");
|
||||||
|
|
||||||
let tags = getUniqueTags(posts);
|
let tags = getUniqueTags(posts);
|
||||||
---
|
---
|
||||||
|
|||||||
+34
-34
@@ -13,12 +13,12 @@
|
|||||||
--color-border: 236, 233, 233;
|
--color-border: 236, 233, 233;
|
||||||
}
|
}
|
||||||
html[data-theme="dark"] {
|
html[data-theme="dark"] {
|
||||||
--color-fill: 47, 55, 65;
|
--color-fill: 33, 39, 55;
|
||||||
--color-text-base: 230, 230, 230;
|
--color-text-base: 234, 237, 243;
|
||||||
--color-accent: 26, 217, 217;
|
--color-accent: 255, 107, 1;
|
||||||
--color-card: 63, 75, 90;
|
--color-card: 52, 63, 96;
|
||||||
--color-card-muted: 89, 107, 129;
|
--color-card-muted: 138, 51, 2;
|
||||||
--color-border: 59, 70, 85;
|
--color-border: 171, 75, 8;
|
||||||
}
|
}
|
||||||
#sun-svg,
|
#sun-svg,
|
||||||
html[data-theme="dark"] #moon-svg {
|
html[data-theme="dark"] #moon-svg {
|
||||||
@@ -29,45 +29,45 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
@apply font-mono bg-skin-fill text-skin-base min-h-screen flex flex-col
|
@apply flex min-h-screen flex-col bg-skin-fill font-mono text-skin-base
|
||||||
selection:bg-skin-accent selection:text-skin-inverted selection:bg-opacity-70;
|
selection:bg-skin-accent selection:bg-opacity-70 selection:text-skin-inverted;
|
||||||
}
|
}
|
||||||
section,
|
section,
|
||||||
footer {
|
footer {
|
||||||
@apply max-w-3xl mx-auto px-4;
|
@apply mx-auto max-w-3xl px-4;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
@apply outline-offset-1 outline-skin-fill outline-2
|
@apply outline-2 outline-offset-1 outline-skin-fill
|
||||||
focus-visible:outline-dashed focus-visible:no-underline;
|
focus-visible:no-underline focus-visible:outline-dashed;
|
||||||
}
|
}
|
||||||
svg {
|
svg {
|
||||||
@apply w-6 h-6 inline-block fill-skin-base group-hover:fill-skin-accent;
|
@apply inline-block h-6 w-6 fill-skin-base group-hover:fill-skin-accent;
|
||||||
}
|
}
|
||||||
svg.icon-tabler {
|
svg.icon-tabler {
|
||||||
@apply w-6 h-6 scale-125 sm:scale-110 opacity-90
|
@apply inline-block h-6 w-6 scale-125 fill-transparent
|
||||||
inline-block fill-transparent stroke-2 stroke-current
|
stroke-current stroke-2 opacity-90 group-hover:fill-transparent
|
||||||
group-hover:fill-transparent;
|
sm:scale-110;
|
||||||
}
|
}
|
||||||
.prose {
|
.prose {
|
||||||
@apply prose-a:underline-offset-8 prose-ul:overflow-x-clip
|
@apply prose-headings:!mb-3 prose-headings:!text-skin-base
|
||||||
prose-a:!decoration-dashed hover:prose-a:text-skin-accent
|
prose-h3:italic prose-p:!text-skin-base
|
||||||
prose-img:mx-auto prose-img:border-2 prose-img:border-skin-line
|
prose-a:!text-skin-base prose-a:!decoration-dashed prose-a:underline-offset-8
|
||||||
prose-img:!mt-2 prose-headings:!mb-3
|
hover:prose-a:text-skin-accent prose-blockquote:!border-l-skin-accent
|
||||||
prose-th:border prose-th:border-skin-line
|
prose-blockquote:border-opacity-50 prose-blockquote:opacity-80
|
||||||
prose-td:border prose-td:border-skin-line
|
prose-figcaption:!text-skin-base prose-figcaption:opacity-70
|
||||||
prose-h3:italic
|
prose-strong:!text-skin-base
|
||||||
|
|
||||||
|
|
||||||
prose-p:!text-skin-base prose-headings:!text-skin-base
|
prose-code:rounded prose-code:bg-skin-card
|
||||||
prose-ol:!text-skin-base prose-ul:!text-skin-base prose-blockquote:opacity-80
|
prose-code:bg-opacity-75 prose-code:p-1 prose-code:!text-skin-base
|
||||||
prose-figcaption:!text-skin-base prose-figcaption:opacity-70
|
prose-code:before:!content-[''] prose-code:after:!content-['']
|
||||||
prose-code:bg-skin-card prose-code:bg-opacity-75
|
prose-pre:!text-skin-base prose-ol:!text-skin-base
|
||||||
prose-code:!text-skin-base prose-code:p-1 prose-code:rounded
|
prose-ul:overflow-x-clip prose-ul:!text-skin-base prose-li:marker:!text-skin-accent
|
||||||
prose-code:after:!content-[''] prose-code:before:!content-['']
|
prose-table:text-skin-base prose-th:border
|
||||||
prose-strong:!text-skin-base prose-table:text-skin-base
|
prose-th:border-skin-line prose-td:border
|
||||||
prose-pre:!text-skin-base prose-a:!text-skin-base
|
prose-td:border-skin-line prose-img:mx-auto
|
||||||
prose-hr:!border-skin-line prose-li:marker:!text-skin-accent
|
prose-img:!mt-2 prose-img:border-2
|
||||||
prose-blockquote:!border-l-skin-accent prose-blockquote:border-opacity-50;
|
prose-img:border-skin-line prose-hr:!border-skin-line;
|
||||||
}
|
}
|
||||||
.prose a {
|
.prose a {
|
||||||
@apply hover:!text-skin-accent;
|
@apply hover:!text-skin-accent;
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
@apply mb-2;
|
@apply mb-2;
|
||||||
}
|
}
|
||||||
.prose details {
|
.prose details {
|
||||||
@apply text-skin-base cursor-pointer inline-block select-none;
|
@apply inline-block cursor-pointer select-none text-skin-base;
|
||||||
}
|
}
|
||||||
.prose summary {
|
.prose summary {
|
||||||
@apply focus-outline;
|
@apply focus-outline;
|
||||||
@@ -121,6 +121,6 @@
|
|||||||
@apply hidden;
|
@apply hidden;
|
||||||
}
|
}
|
||||||
.focus-outline {
|
.focus-outline {
|
||||||
@apply outline-offset-1 outline-skin-fill outline-2 focus-visible:outline-dashed focus-visible:no-underline;
|
@apply outline-2 outline-offset-1 outline-skin-fill focus-visible:no-underline focus-visible:outline-dashed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,3 @@
|
|||||||
export interface Frontmatter {
|
|
||||||
title: string;
|
|
||||||
ogImage?: string;
|
|
||||||
description: string;
|
|
||||||
author: string;
|
|
||||||
datetime: string;
|
|
||||||
slug: string;
|
|
||||||
featured: boolean;
|
|
||||||
draft: boolean;
|
|
||||||
tags: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SocialObjects = {
|
export type SocialObjects = {
|
||||||
name: SocialMedia;
|
name: SocialMedia;
|
||||||
href: string;
|
href: string;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { SITE } from "src/config";
|
import { SITE } from "@config";
|
||||||
|
|
||||||
const getPageNumbers = (numberOfPosts: number) => {
|
const getPageNumbers = (numberOfPosts: number) => {
|
||||||
const numberOfPages = numberOfPosts / Number(SITE.postPerPage);
|
const numberOfPages = numberOfPosts / Number(SITE.postPerPage);
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { slufigyAll } from "./slugify";
|
import { slufigyAll } from "./slugify";
|
||||||
import type { MarkdownInstance } from "astro";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import type { Frontmatter } from "../types";
|
|
||||||
|
|
||||||
const getPostsByTag = (posts: MarkdownInstance<Frontmatter>[], tag: string) =>
|
const getPostsByTag = (posts: CollectionEntry<"blog">[], tag: string) =>
|
||||||
posts.filter(post => slufigyAll(post.frontmatter.tags).includes(tag));
|
posts.filter(post => slufigyAll(post.data.tags).includes(tag));
|
||||||
|
|
||||||
export default getPostsByTag;
|
export default getPostsByTag;
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import type { MarkdownInstance } from "astro";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import type { Frontmatter } from "../types";
|
|
||||||
|
|
||||||
const getSortedPosts = (posts: MarkdownInstance<Frontmatter>[]) =>
|
const getSortedPosts = (posts: CollectionEntry<"blog">[]) =>
|
||||||
posts
|
posts
|
||||||
.filter(({ frontmatter }) => !frontmatter.draft)
|
.filter(({ data }) => !data.draft)
|
||||||
.sort(
|
.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
Math.floor(new Date(b.frontmatter.datetime).getTime() / 1000) -
|
Math.floor(new Date(b.data.pubDatetime).getTime() / 1000) -
|
||||||
Math.floor(new Date(a.frontmatter.datetime).getTime() / 1000)
|
Math.floor(new Date(a.data.pubDatetime).getTime() / 1000)
|
||||||
);
|
);
|
||||||
|
|
||||||
export default getSortedPosts;
|
export default getSortedPosts;
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { slugifyStr } from "./slugify";
|
import { slugifyStr } from "./slugify";
|
||||||
import type { MarkdownInstance } from "astro";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import type { Frontmatter } from "../types";
|
|
||||||
|
|
||||||
const getUniqueTags = (posts: MarkdownInstance<Frontmatter>[]) => {
|
const getUniqueTags = (posts: CollectionEntry<"blog">[]) => {
|
||||||
let tags: string[] = [];
|
let tags: string[] = [];
|
||||||
const filteredPosts = posts.filter(({ frontmatter }) => !frontmatter.draft);
|
const filteredPosts = posts.filter(({ data }) => !data.draft);
|
||||||
filteredPosts.forEach(post => {
|
filteredPosts.forEach(post => {
|
||||||
tags = [...tags, ...post.frontmatter.tags]
|
tags = [...tags, ...post.data.tags]
|
||||||
.map(tag => slugifyStr(tag))
|
.map(tag => slugifyStr(tag))
|
||||||
.filter(
|
.filter(
|
||||||
(value: string, index: number, self: string[]) =>
|
(value: string, index: number, self: string[]) =>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { slug as slugger } from "github-slugger";
|
import { slug as slugger } from "github-slugger";
|
||||||
import type { Frontmatter } from "src/types";
|
import type { BlogFrontmatter } from "@content/_schemas";
|
||||||
|
|
||||||
export const slugifyStr = (str: string) => slugger(str);
|
export const slugifyStr = (str: string) => slugger(str);
|
||||||
|
|
||||||
const slugify = (frontmatter: Frontmatter) =>
|
const slugify = (post: BlogFrontmatter) =>
|
||||||
frontmatter.slug ? slugger(frontmatter.slug) : slugger(frontmatter.title);
|
post.postSlug ? slugger(post.postSlug) : slugger(post.title);
|
||||||
|
|
||||||
export const slufigyAll = (arr: string[]) => arr.map(str => slugifyStr(str));
|
export const slufigyAll = (arr: string[]) => arr.map(str => slugifyStr(str));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user