This is the source code for my blog, which is built with Astro, and deployed to Netlify.
- 银河渡舟的小站: https://suborbit.net
- Markdown and MDX support
- More markdown syntax
- Responsive Design
- RSS
- Sitemap
- Algolia Search
- Comments
- Dark Mode
- Pagination
- View Transitions
- TypeScript support
- Outdate Tip
- License Info
git clone https://https://github.com/izmttk/astro-mecure.git
cd astro-mecure
npm install
# or if you want to develop the site
npm install -D
npm run dev
npm run build
npm run preview
You can deploy your site to any static hosting provider.
But when you enable giscus comments, you need to set HTTP header Allow-Access-Control-Origin
to *
or giscus.app
in your server.
Otherwise, you will get a CORS error. This is necessary for giscus custom theme to work properly.
All commands are run from the root of the project, from a terminal:
Command | Action |
---|---|
npm install |
Installs dependencies |
npm run dev |
Starts local dev server |
npm run build |
Build your production site to /dist/ |
npm run preview |
Preview your build locally, before deploying |
npm run create-post |
Create a new post in /src/content/blog/ |
npm run create-component |
Create a new component in /src/components/ |
- Astro (static site generator)
- React (ui library)
- TypeScript (static type checker)
- Tailwind CSS (utility-first css framework)
- PostCSS (css post-processor)
- Radix UI (headless ui components)
- React Use (react hooks)
- Jotai (state management)
- React Spring (animations)
- unplugin-icons (icon plugin for vite)
- date-fns (date utility library)
- some other libs have not been listed yet.
/
├── plugins/ # remark and rehype plugins
├── public/ # static assets for the site
│ ├── assets/
│ └── favicon.ico
├── scripts/ # some useful scripts
├── src/
│ ├── assets/
│ ├── components/
│ ├── content/
│ │ ├── authors/ # where author bios live
│ │ ├── blog/ # where blog posts live, write your post here
│ │ │ └── _drafts/ # drafts will not be built or pushed to git
│ │ ├── friends/ # where friends info live
│ │ └── config.ts # astro's content collection config
│ ├── hooks/ # react hooks
│ ├── layouts/ # some layouts
│ ├── pages/ # routes
│ ├── partials/ # partials which is combination of components
│ ├── store/ # global store
│ ├── styles/ # styles
│ ├── utils/ # utility functions
│ ├── config.ts # theme config
│ ├── env.d.ts
│ ├── shim.d.ts
│ └── types.ts # all types
├── .gitignore
├── astro.config.ts # astro config
├── package.json
├── postcss.config.cjs # postcss config
├── tailwind.config.ts # tailwind config
└── tsconfig.json
An example of a blog post frontmatter:
---
title: Hello, Astro!
slug: hello-astro
date: 2022-01-01
updateDate: 2022-01-01 08:00:00
author: john
description: This is a blog post.
image: hello-astro.jpg
tags:
- Astro
- Blog
- Markdown
category:
- Web Development
- Frontend
- Astro
draft: false
cardVariant: blur
---
-
title
requiredTitle of the post.
-
slug
slug of the post used in the url.
-
date
Date of the post. If not provided, it will use the first git commit date of the post file.
You can use a relaxed format like
2022-01-01
,2022-01-01 08:00:00
, or ISO 8601 format. e.g.2022-01-01T08:00:00Z
. -
updateDate
Date of the last update. If not provided, it will use the last git commit date of the post file.
-
author
Author id of the post. The author should be defined in
src/content/authors/
previously. If author id can't be found,config.author
will be used as the default author name.Authors in
src/content/authors/
should be defined injson
format. The file name is the corresponding author id.// src/content/authors/john.json { "name": "John", "description": "This is a bio of John Doe.", }
Default value is
default
. You can createdefault.json
as the default author. -
description
Description of the post.
-
image
Cover image of the post. Use a relative file path to the markdown file. Any path that can't be resolved will be reserved as is.
-
tags
Tags of the post. Tags is a set without hierarchical structure. One post can have multiple tags. For example,
[Astro, Blog, Markdown]
means the post is tagged withAstro
,Blog
, andMarkdown
. -
category
Category of the post. Categories is a tree structure. One post must have only one category. For example,
[Web Development, Frontend, Astro]
means the post is in theWeb Development/Frontend/Astro
category. If not provided, the post will be in theUncategorized
category. -
draft
Whether the post is a draft. default is
false
. Any file or folder starts with_
will be ignored in astro's content collection. -
cardVariant
Card style of the post shown in the home page. It can be
blur
,material
,full
, orplain
. default isblur
.Still working in progress.
export default {
title: 'My Blog',
description: 'This is my blog.',
author: 'John',
favicon: '/favicon.ico',
navbar: { /* ... */ },
hero: { /* ... */ },
sidebar: { /* ... */ },
pagination: { /* ... */ },
article: { /* ... */ },
comment: { /* ... */ },
footer: { /* ... */ },
algolia: { /* ... */ }
}
more details in config.ts
Some fields are of type Image
, you can provide a string or an ImageMetadata
object.
If it's a string, it will be kept as is. If it's an ImageMetadata
object, it will be processed by astro built-in optimization.
If you want to process your image with astro, you can write your config like this:
import AvatarImage from './assets/avatar.jpg';
const config = {
// imported image
avatar: AvatarImage
// or even using dymatic import
background: import('./assets/background.jpg')
}
Some fields are url strings which can be clicked to navigate to the target page. But if you want to set an internal link, you can use the url
utility function to generate the url. It will join the base url of the site and the provided path.
import { url } from '@/utils/url';
const config = {
// internal link: /base-path/your-path
link: url('/your-path'),
}
Some fields are icon strings which can be used to show an icon. The format of the icon is <pack>:<icon>
, such as tabler:home
. You can explore more icons in Icônes. Before using a pack, you need to install icon set dependencies. For example, to use mdi
icons, you need to install @iconify-json/mdi
package.
npm install @iconify-json/mdi
We have already installed tabler
and mingcute
icons for you.
Type: string
Title of your site. This will be used in the meta data of your site.
Type: string
Description of your site. This will be used in the meta data of your site.
Type: string
Author name of the site. This will be used in the meta data of your site.
Type: string
Path to the favicon of your site. You need to put your favicon in the public
folder.
Navbar is always floating on top of viewport. It can be disabled by setting navbar
to false
, or you should provide a navbar
object with the following options.
Type: Image | AstroComponentFactory | undefined
Default: undefined
Brand logo of the site. It will be shown at the left side of the navbar.
To customize the logo, you can provide an astro component as the logo. For example:
import LogoWithAnimation from '@/custom/NavLogo.astro';
const config = {
navbar: {
logo: LogoWithAnimation,
// or you can use dynamic import
// logo: import('@/custom/NavLogo.astro'),
}
}
Type: MenuConfig
Default: []
Menu will be shown in the navbar. The type of MenuItem
is:
type MenuConfig = (MenuSubItemConfig | MenuLinkItemConfig)[];
interface MenuLinkItemConfig {
label: string;
url: string;
icon?: string;
}
interface MenuSubItemConfig {
label: string;
icon?: string;
children: MenuConfig;
}
-
label
Type:
string
Label of the menu item.
-
url
Type:
string
URL of the menu item. sub menu item has no url.
-
icon
Type:
string | undefined
Default:
undefined
Each item supports an optional icon before the label.
-
children
Type:
MenuConfig
Default:
[]
For sub menu item, you can provide a
children
array to create a dropdown menu, which follows the same format asMenuConfig
. Sub menu supports cascading.{ label: 'menu demo', icon: 'tabler:menu-2', children: [ { label: 'SubItem1', url: '#', icon: 'tabler:circle'}, { label: 'SubItem2', url: '#', icon: 'tabler:circle'}, { label: 'SubItem3', icon: 'tabler:menu-2', children: [ { label: 'SubItem1', url: '#', icon: 'tabler:circle'}, { label: 'SubItem2', url: '#', icon: 'tabler:circle'}, { label: 'SubItem3', url: '#', icon: 'tabler:circle'} ] } ] }
Type: boolean
Default: true
Whether to show search button in navbar.
Type: boolean
Default: true
Whether to show dark mode switch button in navbar.
Hero section is the first area of a web page, providing some key information of the page. It can be disabled by setting hero
to false
.
Type: Image
Background image of the hero section.
Type: string | undefined
Default: undefined
Description in hero section. It will be shown below the title or logo.
Type: string | AstroComponentFactory |undefined
Default: undefined
Title in hero section. Title will be only displayed in homepage. If not provided, the title of the site(see title
in site options) will be used.
To customize the title, you can provide an astro component as the title. For example:
import LogoWithAnimation from '@/custom/Logo.astro';
const config = {
hero: {
title: LogoWithAnimation,
// or you can use dynamic import
// title: import('@/custom/Logo.astro'),
}
}
Sidebar is a section on the right side of the page. It contains some widgets and can be disabled by setting sidebar
to false
.
Type: WidgetConfig[]
Default: []
We provide 4 types of widgets: profile
, tag-cloud
, category-tree
, and component
. They will be shown in the order you provide.
Each widget has 3 public properties: name
, title
, and show
.
-
name
Type:
'profile' | 'tag-cloud' | 'category-tree' | 'component'
Name of the widget.
-
title
Type:
string | undefined
Title of the widget. Title will be shown at the top of the widget.
-
show
Type:
boolean
Default:
true
Show or hide the widget.
-
author
Type:
string | undefined
Author Name shown in the profile widget.
-
avatar
Type:
Image | undefined
Avatar image shown in the profile widget.
-
description
Type:
string | undefined
Description shown in the profile widget.
-
socialIcons
Type:
SocialIcon[]
Default:
[]
Social icons. The type of
SocialIcon
is:interface SocialIcon { label: string; color?: string; icon: string; // format: <pack>:<icon> url: string; }
-
sortBy
Type:
'label' | 'count'
Default:
'count'
Sort the tags by tag label or article count.
-
order
Type:
'asc' | 'desc'
Default:
'desc'
Sort the tags in ascending or descending order.
-
limit
Type:
number | undefined
Default:
30
Limit the number of tags shown in the tag cloud widget. If you set
limit
toundefined
, all tags will be shown.
-
sortBy
Type:
'label' | 'count'
Default:
'count'
Sort the tags by tag label or article count.
-
order
Type:
'asc' | 'desc'
Default:
'desc'
Sort the tags in ascending or descending order.
-
limit
Type:
number | undefined
Default:
undefined
Limit the number of categories shown in the category tree widget. If you set
limit
toundefined
, all categories will be shown. -
expandDepth
Type:
number
Default:
2
The depth of the category tree to expand. Any category deeper than this depth will not be shown.
-
component
Type:
AstroComponentFactory
You can provide an astro component to the widget as a totally custom widget. For example:
import Greeting from '@/components/Greeting.astro'; const config = { widgets: [ { name: 'component', component: Greeting }, { // or you can use dynamic import name: 'component', component: import('@/components/Greeting.astro') } ] }
When a page contains a list of articles, pagination will be shown at the bottom of the page. It can be disabled by setting pagination
to false
.
Type: number
Default: 10
The number of articles per page.
Type: boolean
Default: true
Show or hide prev/next control buttons.
Type: boolean
Default: false
Show or hide first/last control buttons.
Type: number
Default: 1
Amount of sibling pages on left/right side of current page.
Type: number
Default: 1
Amount of pages visible on left/right edges.
Options for some elements in the article page.
Type: false | outdateTipConfig
Show an outdate tip at the top of the article when the article is out of date. It can be disabled by setting outdateTip
to false
.
outdateTipConfig
is an object with outdateLimit
properties.
Type: number
Default: 30
The number of days after which the article is considered out of date.
Type: false | licenseConfig
Show a license info at the bottom of the article. It can be disabled by setting license
to false
.
licenseConfig
is an object containing licenseName
, licenseUrl
, infoText
properties.
Type: string
Name of the license, e.g. CC BY-NC-SA 4.0
. If you use CC license, you can find the license name in the CC License Chooser.
Type: string | undefined
Default: undefined
URL of the license, e.g. https://creativecommons.org/licenses/by-nc-sa/4.0/
.
Type: string | undefined
Default: undefined
Info text of the license, e.g. This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
.
We support two comment providers: giscus
and waline
now. You can choose one of them. It can be disabled by setting comment
to false
.
Type: giscus | waline
Choose a comment provider.
Type: giscusOptions | walineOptions
Options for the comment provider. You can find the details in the Giscus Component and Waline Component Props documentation.
Footer section is at the bottom of every page. It can be disabled by setting footer
to false
.
Type: FooterLink[]
Links in the footer. The type of FooterLink
is:
interface FooterLink {
label: string;
url: string;
}
-
label
Type:
string
Label of the link.
-
url
Type:
string
URL of the link.
Type: string[]
Default: []
A set of declarative statements in the footer. It can be used to declare the license, the author, the technology stack, etc.
Type: boolean
Default: true
Whether to show the generator info in the footer.
Type: boolean
Default: true
Whether to show the RSS link in the footer.
Type: boolean
Default: true
Whether to show the sitemap link in the footer.
We support Algolia DocSearch now. You should apply for Algolia DocSearch and get the appId
, apiKey
, and indexName
.
Type: string
Your Algolia application ID.
Type: string
Your Algolia Search API key.
Type: string
Your Algolia index name.