Commit 34805f9
Changed files (37)
src
components
widgets
i18n
layouts
pages
archives
categories
[category]
tags
[tag]
posts
styles
utils
src/components/widgets/Button.astro
@@ -36,7 +36,7 @@ const Tag = (href ? 'a' : Fragment) as HTMLTag;
}
&:active {
- @apply brightness-75 scale-95;
+ @apply scale-95 brightness-75;
}
}
</style>
src/components/widgets/DarkModeButton.astro
@@ -1,9 +1,9 @@
---
-import type { HTMLAttributes } from 'astro/types';
-import Button from './Button.astro';
-import { Icon } from 'astro-icon/components';
import I18nKey from '@i18n/I18nKey';
import { i18n } from '@i18n/translation';
+import { Icon } from 'astro-icon/components';
+import type { HTMLAttributes } from 'astro/types';
+import Button from './Button.astro';
interface Props extends Omit<HTMLAttributes<'button'>, 'onclick'> {
showText?: boolean;
@@ -22,7 +22,7 @@ const { class: className, showText, ...rest } = Astro.props;
<Icon class="darkmode-icon-light" name="material-symbols:light-mode-rounded" />
<Icon class="darkmode-icon-dark" name="material-symbols:dark-mode-rounded" />
<Icon class="darkmode-icon-auto" name="material-symbols:night-sight-auto-rounded" />
- {showText && <span class="darkmode-text px-2 ml-auto mr-2" />}
+ {showText && <span class="darkmode-text ml-auto mr-2 px-2" />}
</Button>
<script>
src/components/widgets/MetaIcon.astro
@@ -1,6 +1,6 @@
---
-import type { ComponentProps } from 'astro/types';
import { Icon } from 'astro-icon/components';
+import type { ComponentProps } from 'astro/types';
type Props = ComponentProps<typeof Icon>;
src/components/widgets/Pagination.astro
@@ -48,20 +48,20 @@ else {
current > 1 && (
<Button
id="prev-page-btn"
- class="theme-bg theme-border border-2 !rounded-xl mr-auto"
+ class="theme-bg theme-border mr-auto !rounded-xl border-2"
href={getPageUrl(current - 1)}
>
<Icon name="material-symbols:keyboard-double-arrow-left-rounded" class="my-1" />
</Button>
)
}
- <div class="flex justify-center items-center gap-2 mx-auto">
+ <div class="mx-auto flex items-center justify-center gap-2">
{
pages.map((p) => {
return (
<Button
class:list={[
- 'theme-bg theme-border border-2 !rounded-xl',
+ 'theme-bg theme-border !rounded-xl border-2',
current === p.page && 'theme-card-bg-hl',
]}
href={p.url}
@@ -75,7 +75,7 @@ else {
total > 1 && (
<div
id="page-jumper"
- class="flex flex-row items-center theme-card-bg theme-border mx-2 rounded-xl border-2"
+ class="theme-card-bg theme-border mx-2 flex flex-row items-center rounded-xl border-2"
data-base-url={baseUrl}
data-special-pages={specialPages?.map((p) => `${p.page}:${p.url}`).join(',')}
>
@@ -84,11 +84,11 @@ else {
type="number"
min="1"
max={total}
- class="duration-300 theme-bg border-none !active:border-none pl-4"
+ class="theme-bg !active:border-none border-none pl-4 duration-300"
/>
<Button
id="page-jumper-button"
- class="theme-card-bg !rounded-xl !m-0 relative right-0 duration-300"
+ class="theme-card-bg relative right-0 !m-0 !rounded-xl duration-300"
>
<Icon name="material-symbols:keyboard-double-arrow-right-rounded" class="my-1" />
</Button>
@@ -100,7 +100,7 @@ else {
current < total && (
<Button
id="next-page-btn"
- class="theme-bg theme-border border-2 !rounded-xl ml-auto"
+ class="theme-bg theme-border ml-auto !rounded-xl border-2"
href={getPageUrl(current + 1)}
>
<Icon name="material-symbols:keyboard-double-arrow-right-rounded" class="my-1" />
src/components/widgets/PostCard.astro
@@ -1,7 +1,7 @@
---
import MetaIcon from './MetaIcon.astro';
-import ReadMoreButton from './ReadMoreButton.astro';
import PostCardCover from './PostCardCover.astro';
+import ReadMoreButton from './ReadMoreButton.astro';
interface Props {
class?: string;
@@ -49,13 +49,13 @@ const metas: ({ icon: string; text: string; link?: string } | undefined)[] = [
<div
class:list={[
'theme-card-bg theme-border',
- 'border-2 rounded-xl p-4 flex max-md:flex-col-reverse w-full',
+ 'flex w-full rounded-xl border-2 p-4 max-md:flex-col-reverse',
className,
]}
>
- <div class="items-center px-12 py-7 w-full h-full mr-auto">
- <div class="text-2xl mb-5"><a href={url}>{title}</a></div>
- <div class="flex flex-wrap items-center mb-3 gap-x-4 gap-y-2 theme-text-second">
+ <div class="mr-auto h-full w-full items-center px-12 py-7">
+ <div class="mb-5 text-2xl"><a href={url}>{title}</a></div>
+ <div class="theme-text-second mb-3 flex flex-wrap items-center gap-x-4 gap-y-2">
{
metas.map((meta) => {
return (
@@ -63,11 +63,11 @@ const metas: ({ icon: string; text: string; link?: string } | undefined)[] = [
<div class="flex items-center gap-1">
<MetaIcon name={meta.icon} />
{meta.link ? (
- <a href={meta.link} class="text-sm font-medium">
+ <a href={meta.link} class="meta-text" title={meta.text}>
{meta.text}
</a>
) : (
- <span class="text-sm font-medium">{meta.text}</span>
+ <span class="meta-text">{meta.text}</span>
)}
</div>
)
@@ -84,3 +84,13 @@ const metas: ({ icon: string; text: string; link?: string } | undefined)[] = [
)
}
</div>
+
+<style>
+ .meta-text {
+ @apply text-sm font-medium;
+ }
+
+ a.meta-text {
+ @apply duration-100 hover:brightness-125;
+ }
+</style>
src/components/widgets/PostCardCover.astro
@@ -20,21 +20,21 @@ const { url, title, cover } = Astro.props;
<style>
a {
- @apply min-h-48 w-full md:w-3/4 md:max-w-96 relative;
- @apply active:brightness-75 active:scale-95 duration-100;
+ @apply relative min-h-48 w-full md:w-3/4 md:max-w-96;
+ @apply duration-100 active:scale-95 active:brightness-75;
}
img {
- @apply w-full h-full object-cover rounded-md;
+ @apply h-full w-full rounded-md object-cover;
}
div {
- @apply absolute inset-0 w-full h-full bg-black/60;
+ @apply absolute inset-0 h-full w-full bg-black/60;
@apply flex items-center justify-center;
- @apply opacity-0 group-hover:opacity-100 duration-300;
+ @apply opacity-0 duration-300 group-hover:opacity-100;
}
svg {
- @apply w-24 h-24 text-white;
+ @apply h-24 w-24 text-white;
}
</style>
src/components/widgets/ProfileCard.astro
@@ -1,7 +1,7 @@
---
import { profileConfig } from '@/config';
+import avatarImg from '@assets/img/avatar.jpg';
import { Image } from 'astro:assets';
-import avatarImg from '/src/assets/img/avatar.jpg';
const avaterAttr = profileConfig.avatar
? {
@@ -17,15 +17,15 @@ const avaterAttr = profileConfig.avatar
<div
id="profile-card"
transition:persist
- class="theme-card-bg theme-border rounded-xl border-2 flex flex-col items-center text-center"
+ class="theme-card-bg theme-border flex flex-col items-center rounded-xl border-2 text-center"
>
<div class="m-3 w-fit min-w-20">
<a href="/about/">
- <Image class="rounded-full border-4 w-20 h-20 theme-border" {...avaterAttr} />
+ <Image class="theme-border h-20 w-20 rounded-full border-4" {...avaterAttr} />
</a>
</div>
- <div class="mx-3 mb-5 flex flex-col w-full">
- <div class="text-lg mb-3">
+ <div class="mx-3 mb-5 flex w-full flex-col">
+ <div class="mb-3 text-lg">
<a href="/about/" class="font-bold">{profileConfig.name}</a>
</div>
<div>{profileConfig.bio}</div>
src/components/widgets/ReadMoreButton.astro
@@ -1,8 +1,8 @@
---
-import type { ComponentProps } from 'astro/types';
-import { Icon } from 'astro-icon/components';
-import { i18n } from '@i18n/translation';
import I18nKey from '@i18n/I18nKey';
+import { i18n } from '@i18n/translation';
+import { Icon } from 'astro-icon/components';
+import type { ComponentProps } from 'astro/types';
type Props = Omit<ComponentProps<typeof Icon>, 'name'>;
@@ -15,13 +15,13 @@ const { href, title, ...rest } = Astro.props;
<style>
a {
- @apply max-md:hidden duration-100;
+ @apply duration-100 max-md:hidden;
@apply hover:brightness-125;
- @apply active:brightness-75 active:scale-95;
+ @apply active:scale-95 active:brightness-75;
}
svg {
- @apply min-h-48 h-full w-12 rounded-md;
+ @apply h-full min-h-48 w-12 rounded-md;
@apply text-[var(--theme-color-light-darken)] dark:text-[var(--theme-color-dark-lighten)];
@apply bg-[var(--theme-color-light-transparent)] dark:bg-[var(--theme-color-dark-transparent)];
}
src/components/widgets/SiteInfoCard.astro
src/components/widgets/TOC.astro
@@ -11,7 +11,7 @@ const minDepth = Math.min(...headings.map((h) => h.depth));
const maxLevel = 3;
---
-<div class:list={['theme-card-bg theme-border border-2 rounded-xl p-2', className]}>
+<div class:list={['theme-card-bg theme-border rounded-xl border-2 p-2', className]}>
<div></div>
{
headings
src/components/AsideContent.astro
@@ -1,7 +0,0 @@
----
-
----
-
-<div id="aside-content">
- {}
-</div>
src/components/CategoryBar.astro
@@ -12,7 +12,7 @@ const { categories, currentCategory } = Astro.props;
<div
id="category-bar"
- class="theme-card-bg theme-border flex w-full rounded-xl px-2 py-3 border-2 mb-4"
+ class="theme-card-bg theme-border mb-4 flex w-full rounded-xl border-2 px-2 py-3"
>
<a href={`/`} class:list={[currentCategory ? '' : 'theme-card-bg-hl']}>
{i18n(I18nKey.recentPosts)}
src/components/PostPage.astro
@@ -1,8 +1,8 @@
---
-import type { BlogPostData } from '@/types/data';
import { siteConfig } from '@/config';
-import PostCard from './widgets/PostCard.astro';
+import type { BlogPostData } from '@/types/data';
import Pagination from './widgets/Pagination.astro';
+import PostCard from './widgets/PostCard.astro';
interface Props {
posts: {
src/components/Sidebar.astro
@@ -1,8 +1,6 @@
---
import { navbarConfig } from '@/config';
-
import { Icon } from 'astro-icon/components';
-
import Button from './widgets/Button.astro';
import DarkModeButton from './widgets/DarkModeButton.astro';
---
@@ -10,17 +8,17 @@ import DarkModeButton from './widgets/DarkModeButton.astro';
<div id="sidebar" transition:persist>
<div
id="sidebar-mask"
- class="fixed z-40 opacity-0 pointer-events-none w-full h-full bg-black/10 backdrop-blur-md backdrop-saturate-100 duration-500 ease-in-out"
+ class="pointer-events-none fixed z-40 h-full w-full bg-black/10 opacity-0 backdrop-blur-md backdrop-saturate-100 duration-500 ease-in-out"
>
</div>
<div
id="sidebar-menu"
- class="fixed h-full z-50 -right-1/2 w-1/2 duration-500 ease-in-out border-l-2 theme-border theme-card-bg"
+ class="theme-border theme-card-bg fixed -right-1/2 z-50 h-full w-1/2 border-l-2 duration-500 ease-in-out"
>
<div id="sidebar-site-data"></div>
<DarkModeButton
showText={true}
- class="text-lg !w-[calc(100%-1rem)] border-2 theme-border"
+ class="theme-border !w-[calc(100%-1rem)] border-2 text-lg"
/>
<div id="sidebar-menu-text-items">
{
src/components/SideToolBar.astro
@@ -15,11 +15,11 @@ import DarkModeButton from './widgets/DarkModeButton.astro';
<Button id="stb-back-to-top" class="group">
<span
id="stb-read-percentage"
- class="absolute opacity-0 duration-300 group-hover:opacity-0 text-sm"></span>
+ class="absolute text-sm opacity-0 duration-300 group-hover:opacity-0"></span>
<Icon
id="stb-back-to-top-icon"
name="material-symbols:arrow-upward-rounded"
- class="opacity-0 group-hover:opacity-100 duration-300"
+ class="opacity-0 duration-300 group-hover:opacity-100"
/>
</Button>
</div>
src/components/TimeArchives.astro
@@ -1,6 +1,6 @@
---
-import { getTimeArchives } from '@utils/content-utils';
import PostCard from '@components/widgets/PostCard.astro';
+import { getTimeArchives } from '@utils/content-utils';
type AllTimeArchives = Awaited<ReturnType<typeof getTimeArchives>>;
type YearArchives = AllTimeArchives[number];
@@ -18,7 +18,7 @@ const { group } = Astro.props;
group.map((year) => <Astro.self group={year} />)
) : 'year' in group ? (
<Fragment>
- <div class="text-2xl font-bold ml-2">
+ <div class="ml-2 text-2xl font-bold">
<a href={`/archives/${group.year}/`}>{group.year}</a>
</div>
{group.months.map((month) => (
@@ -27,7 +27,7 @@ const { group } = Astro.props;
</Fragment>
) : (
<Fragment>
- <div class="text-xl font-bold ml-3">{group.month}</div>
+ <div class="ml-3 text-xl font-bold">{group.month}</div>
{group.posts.map((post) => {
const data = post.data;
return (
src/i18n/translation.ts
@@ -1,14 +1,13 @@
-import { siteConfig } from '@/config';
import I18nKey from './I18nKey';
+import { en } from './langs/en';
+import { zh_CN } from './langs/zh_CN';
+import { zh_TW } from './langs/zh_TW';
+import { siteConfig } from '@/config';
export type Translation = {
[K in I18nKey]: string;
};
-import { en } from './langs/en';
-import { zh_CN } from './langs/zh_CN';
-import { zh_TW } from './langs/zh_TW';
-
const defaultTranslation = en;
const map: { [key: string]: Translation } = {
src/layouts/GridLayout.astro
@@ -13,9 +13,9 @@ const { title, description, lang } = Astro.props;
<div id="main-content" class="my-4 w-full">
<slot />
</div>
- <div id="aside-content" class="max-xl:hidden my-4 w-96 flex flex-col gap-4">
+ <div id="aside-content" class="my-4 flex w-96 flex-col gap-4 max-xl:hidden">
<slot name="aside-fixed" slot="aside-fixed" />
- <div class="sticky flex flex-col gap-4 top-20">
+ <div class="sticky top-20 flex flex-col gap-4">
<slot name="aside-sticky" slot="aside-sticky" />
</div>
</div>
src/layouts/MainLayout.astro
@@ -1,9 +1,9 @@
---
import Navbar from '@components/Navbar.astro';
+import PageFooter from '@components/PageFooter.astro';
import SideToolBar from '@components/SideToolBar.astro';
import Sidebar from '@components/Sidebar.astro';
import GlobalLayout from './GlobalLayout.astro';
-import PageFooter from '@components/PageFooter.astro';
interface Props {
title?: string;
@@ -18,9 +18,9 @@ const { title, description, lang } = Astro.props;
<Sidebar />
<SideToolBar />
<Navbar />
- <div id="body-wrap" class="items-center w-full">
+ <div id="body-wrap" class="w-full items-center">
<!-- Main content -->
- <div id="content-wrapper" class="flex mx-auto gap-4 max-w-screen-xl">
+ <div id="content-wrapper" class="mx-auto flex max-w-screen-xl gap-4">
<slot />
</div>
</div>
src/pages/archives/categories/[category]/[page].astro
@@ -1,11 +1,11 @@
---
-import { getCategories, getSortedPosts } from '@utils/content-utils';
-import PostPage from '@components/PostPage.astro';
import { siteConfig } from '@/config';
-import I18nKey from '@i18n/I18nKey';
-import GridLayout from '@layouts/GridLayout.astro';
import CategoryBar from '@components/CategoryBar.astro';
+import PostPage from '@components/PostPage.astro';
import ProfileCard from '@components/widgets/ProfileCard.astro';
+import I18nKey from '@i18n/I18nKey';
+import GridLayout from '@layouts/GridLayout.astro';
+import { getCategories, getSortedPosts } from '@utils/content-utils';
export async function getStaticPaths() {
const posts = await getSortedPosts();
src/pages/posts/[article].astro
@@ -1,9 +1,9 @@
---
-import { getCollection, render } from 'astro:content';
-import GridLayout from '@layouts/GridLayout.astro';
-import ProfileCard from '@components/widgets/ProfileCard.astro';
import '@/styles/article.scss';
+import ProfileCard from '@components/widgets/ProfileCard.astro';
import TOC from '@components/widgets/TOC.astro';
+import GridLayout from '@layouts/GridLayout.astro';
+import { getCollection, render } from 'astro:content';
export async function getStaticPaths() {
const articles = await getCollection('posts');
@@ -18,7 +18,7 @@ const { Content, headings } = await render(article);
---
<GridLayout>
- <div class="theme-card-bg theme-border border-2 px-6 py-4 rounded-xl">
+ <div class="theme-card-bg theme-border rounded-xl border-2 px-6 py-4">
<article>
<Content />
</article>
src/pages/[...page].astro
@@ -1,10 +1,10 @@
---
-import { getCategories, getSortedPosts } from '@utils/content-utils';
import { siteConfig } from '@/config';
import CategoryBar from '@components/CategoryBar.astro';
import PostPage from '@components/PostPage.astro';
-import GridLayout from '@layouts/GridLayout.astro';
import ProfileCard from '@components/widgets/ProfileCard.astro';
+import GridLayout from '@layouts/GridLayout.astro';
+import { getCategories, getSortedPosts } from '@utils/content-utils';
export async function getStaticPaths() {
const articles = await getSortedPosts();
src/pages/about.astro
@@ -1,8 +1,7 @@
---
-import MainLayout from '@layouts/MainLayout.astro';
-
import I18nKey from '@i18n/I18nKey';
import { i18n } from '@i18n/translation';
+import MainLayout from '@layouts/MainLayout.astro';
---
<MainLayout title={i18n(I18nKey.about)}>
src/styles/article.scss
@@ -40,7 +40,7 @@ article {
}
hr {
- @apply border-dashed border-2;
+ @apply border-2 border-dashed;
@apply mx-2 my-4;
}
src/utils/content-utils.ts
@@ -1,7 +1,7 @@
-import { getCollection } from 'astro:content';
import type { BlogPostData } from '@/types/data';
-import { i18n } from '@i18n/translation';
import I18nKey from '@i18n/I18nKey';
+import { i18n } from '@i18n/translation';
+import { getCollection } from 'astro:content';
export async function getSortedPosts(): Promise<{ body: string; data: BlogPostData }[]> {
const allBlogPosts = (await getCollection('posts')) as unknown as {
src/utils/url-utils.ts
@@ -1,3 +1,6 @@
+import i18nKey from '@i18n/I18nKey';
+import { i18n } from '@i18n/translation';
+
export function pathsEqual(path1: string, path2: string) {
const normalizedPath1 = path1.replace(/^\/|\/$/g, '').toLowerCase();
const normalizedPath2 = path2.replace(/^\/|\/$/g, '').toLowerCase();
@@ -12,3 +15,8 @@ function joinUrl(...parts: string[]): string {
export function url(path: string) {
return joinUrl('', import.meta.env.BASE_URL, path);
}
+
+export function getCategoryUrl(category: string): string {
+ if (category === i18n(i18nKey.uncategorized)) return url('/archives/category/uncategorized/');
+ return url(`/archives/categories/${category}/1/`);
+}
src/config.ts
@@ -1,11 +1,10 @@
import type {
LicenseConfig,
+ NavbarConfig,
ProfileConfig,
SiteConfig,
- NavbarConfig,
ToolBarConfig,
} from './types/config';
-
import I18nKey from '@i18n/I18nKey';
export const siteConfig: SiteConfig = {
src/content.config.ts
@@ -1,5 +1,5 @@
-import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
+import { defineCollection, z } from 'astro:content';
const postsCollection = defineCollection({
loader: glob({
.prettierrc.cjs
@@ -7,7 +7,15 @@ module.exports = {
trailingComma: 'es5',
useTabs: false,
- plugins: ['prettier-plugin-astro'],
+ importOrderSeparation: false,
+ importOrderSortSpecifiers: true,
+
+ plugins: [
+ 'prettier-plugin-astro',
+ 'prettier-plugin-tailwindcss',
+ '@trivago/prettier-plugin-sort-imports',
+ 'prettier-plugin-astro-organize-imports',
+ ],
overrides: [{ files: '*.astro', options: { parser: 'astro' } }],
};
.stylelintignore
@@ -0,0 +1,4 @@
+dist
+node_modules
+.github
+.changeset
\ No newline at end of file
astro.config.mjs
@@ -1,8 +1,7 @@
// @ts-check
-import { defineConfig } from 'astro/config';
-
import tailwind from '@astrojs/tailwind';
import icon from 'astro-icon';
+import { defineConfig } from 'astro/config';
// https://astro.build/config
export default defineConfig({
eslint.config.js
@@ -1,9 +1,9 @@
+import js from '@eslint/js';
+import typescriptParser from '@typescript-eslint/parser';
import astroEslintParser from 'astro-eslint-parser';
import eslintPluginAstro from 'eslint-plugin-astro';
import globals from 'globals';
-import js from '@eslint/js';
import tseslint from 'typescript-eslint';
-import typescriptParser from '@typescript-eslint/parser';
export default [
js.configs.recommended,
package.json
@@ -6,7 +6,8 @@
"dev": "astro dev",
"build": "astro check && astro build",
"preview": "astro preview",
- "astro": "astro"
+ "astro": "astro",
+ "lint": "prettier -w . && eslint . --fix && stylelint \"**/*.{css,scss}\" --fix && tsc --noEmit && astro check"
},
"dependencies": {
"@astrojs/tailwind": "^5.1.4",
@@ -24,6 +25,9 @@
"devDependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/ts-plugin": "^1.10.4",
+ "@eslint/js": "^9.18.0",
+ "@trivago/prettier-plugin-sort-imports": "^5.2.1",
+ "@typescript-eslint/parser": "^8.21.0",
"astro-eslint-parser": "^1.1.0",
"eslint": "^9.18.0",
"eslint-plugin-astro": "^1.3.1",
@@ -31,6 +35,8 @@
"postcss-html": "^1.8.0",
"prettier": "^3.4.2",
"prettier-plugin-astro": "^0.14.1",
+ "prettier-plugin-astro-organize-imports": "^0.4.11",
+ "prettier-plugin-tailwindcss": "^0.6.10",
"stylelint": "^16.13.2",
"stylelint-config-html": "^1.1.0",
"stylelint-config-standard-scss": "^14.0.0",
postcss.config.mjs
@@ -1,6 +1,6 @@
import postcssImport from 'postcss-import';
-import postcssNesting from 'tailwindcss/nesting/index.js';
import tailwindcss from 'tailwindcss';
+import postcssNesting from 'tailwindcss/nesting/index.js';
/** @type {import('postcss-load-config').Config} */
export default {