diff --git a/.gitignore b/.gitignore
index 7dd7cefd964..a07eb52d84e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,7 @@ package-lock.json
# Misc
_sass/vendors
assets/js/dist
+
+# Astro
+.astro/
+dist/
diff --git a/README.ASTRO.md b/README.ASTRO.md
new file mode 100644
index 00000000000..faf3773d56f
--- /dev/null
+++ b/README.ASTRO.md
@@ -0,0 +1,281 @@
+# Astro Chirpy
+
+A minimal, responsive, and feature-rich Astro theme for technical writing, migrated from the popular [Jekyll Chirpy theme](https://github.com/cotes2020/jekyll-theme-chirpy).
+
+## Features
+
+- **Lightning Fast** - Built with Astro for optimal performance
+- **Clean Design** - Minimal and elegant interface
+- **Dark Mode** - Automatic theme switching with manual toggle
+- **Fully Responsive** - Works perfectly on all devices
+- **SEO Optimized** - Built-in SEO best practices
+- **MDX Support** - Write content in Markdown or MDX
+- **Tags & Categories** - Organize your content effectively
+- **TypeScript Ready** - Full TypeScript support
+- **Accessible** - WCAG compliant
+
+## Project Structure
+
+```
+astro-chirpy/
+├── public/ # Static assets
+├── src/
+│ ├── components/ # Astro components
+│ │ ├── Head.astro
+│ │ ├── Sidebar.astro
+│ │ ├── Topbar.astro
+│ │ ├── Footer.astro
+│ │ └── ...
+│ ├── content/ # Content collections
+│ │ ├── posts/ # Blog posts
+│ │ └── tabs/ # Navigation tabs
+│ ├── data/ # Data files (YAML)
+│ │ ├── authors.yml
+│ │ ├── contact.yml
+│ │ ├── locales/ # 33 language translations
+│ │ └── ...
+│ ├── layouts/ # Astro layouts
+│ │ ├── BaseLayout.astro
+│ │ └── PostLayout.astro
+│ ├── pages/ # Routes
+│ │ ├── index.astro # Home page
+│ │ ├── [slug].astro # Tab pages
+│ │ └── posts/
+│ │ └── [...slug].astro # Blog posts
+│ ├── scripts/ # TypeScript modules
+│ │ ├── main.ts
+│ │ └── theme.ts
+│ ├── styles/ # SCSS styles
+│ │ ├── abstracts/
+│ │ ├── base/
+│ │ ├── components/
+│ │ ├── layout/
+│ │ ├── pages/
+│ │ └── themes/
+│ └── config.ts # Site configuration
+├── astro.config.mjs # Astro configuration
+├── tsconfig.json # TypeScript configuration
+└── package.json
+```
+
+## Getting Started
+
+### Prerequisites
+
+- Node.js 18+
+- npm or yarn
+
+### Installation
+
+1. **Install dependencies:**
+
+```bash
+npm install
+```
+
+2. **Configure your site:**
+
+Edit `src/config.ts` to customize your site settings:
+
+```typescript
+export const SITE = {
+ title: 'Your Site Title',
+ tagline: 'Your tagline',
+ description: 'Site description',
+ url: 'https://your-site.com',
+ // ... more settings
+};
+```
+
+3. **Run the development server:**
+
+```bash
+npm run dev
+```
+
+Visit `http://localhost:4321` to see your site!
+
+## Creating Content
+
+### Writing Posts
+
+Create a new Markdown file in `src/content/posts/`:
+
+```markdown
+---
+title: Your Post Title
+date: 2024-01-15T10:00:00+00:00
+categories: [Category1, Category2]
+tags: [tag1, tag2, tag3]
+description: Brief description of your post
+pin: false
+---
+
+Your content here...
+```
+
+#### Frontmatter Options
+
+- `title` (required) - Post title
+- `date` (required) - Publication date
+- `categories` - Array of categories
+- `tags` - Array of tags
+- `description` - Post description for SEO and previews
+- `image` - Featured image object
+ - `path` - Image path
+ - `alt` - Alt text
+ - `lqip` - Low Quality Image Placeholder
+- `pin` - Pin post to top of home page
+- `hidden` - Hide post from listings
+- `toc` - Enable/disable table of contents
+- `comments` - Enable/disable comments
+- `author` - Author ID from authors.yml
+
+### Creating Tabs
+
+Add a new tab in `src/content/tabs/`:
+
+```markdown
+---
+title: Tab Title
+icon: fas fa-icon-name
+order: 1
+---
+
+Tab content...
+```
+
+## Customization
+
+### Styling
+
+Styles are organized in `src/styles/`:
+
+- `abstracts/` - Variables, mixins, functions
+- `base/` - Base styles and typography
+- `components/` - Component styles
+- `layout/` - Layout styles
+- `pages/` - Page-specific styles
+- `themes/` - Light and dark themes
+
+### Configuration
+
+Main site configuration is in `src/config.ts`:
+
+```typescript
+// Site settings
+export const SITE = { ... };
+
+// Social media
+export const SOCIAL = { ... };
+
+// Analytics
+export const ANALYTICS = { ... };
+
+// Comments
+export const COMMENTS = { ... };
+
+// Features
+export const FEATURES = { ... };
+```
+
+## Deployment
+
+### Build for Production
+
+```bash
+npm run build
+```
+
+The built site will be in the `dist/` directory.
+
+### Preview Production Build
+
+```bash
+npm run preview
+```
+
+### Deploy
+
+You can deploy to any static hosting service:
+
+- **Vercel**: Connect your repo for automatic deployments
+- **Netlify**: Drag and drop `dist/` folder or connect repo
+- **GitHub Pages**: Use GitHub Actions
+- **Cloudflare Pages**: Connect your repo
+
+## Commands
+
+| Command | Action |
+|---------|--------|
+| `npm run dev` | Start development server |
+| `npm run build` | Build production site |
+| `npm run preview` | Preview production build |
+| `npm run astro` | Run Astro CLI commands |
+| `npm run lint:js` | Lint JavaScript/TypeScript |
+| `npm run lint:scss` | Lint SCSS files |
+
+## Migration from Jekyll Chirpy
+
+### Key Differences
+
+1. **No Ruby/Jekyll** - Pure JavaScript/TypeScript ecosystem
+2. **Content Collections** - Type-safe content with Astro's content collections
+3. **Component-based** - Reusable Astro components instead of Liquid includes
+4. **Faster Builds** - Significantly faster build times with Astro
+5. **Modern Tooling** - Vite, TypeScript, and modern JavaScript
+
+### What's Migrated
+
+✅ Core layouts and design
+✅ Responsive sidebar navigation
+✅ Dark/Light theme toggle
+✅ Post listings with pagination support
+✅ Categories and tags
+✅ SCSS styles
+✅ 33 language locales
+✅ SEO optimization
+✅ Analytics integration (Google Analytics, etc.)
+✅ Social media integration
+
+### What's Different
+
+- Search functionality (to be implemented)
+- PWA features (to be implemented)
+- Comment systems (to be integrated)
+- Some Jekyll-specific features
+
+### Migration Steps
+
+If you're migrating from Jekyll Chirpy:
+
+1. Copy your posts from `_posts/` to `src/content/posts/`
+2. Update post frontmatter (mostly compatible)
+3. Copy custom tabs from `_tabs/` to `src/content/tabs/`
+4. Update `src/config.ts` with your `_config.yml` settings
+5. Copy any custom assets to `public/`
+
+## Contributing
+
+Contributions are welcome! Please feel free to submit a Pull Request.
+
+## License
+
+This project is licensed under the MIT License - see the original [Jekyll Chirpy theme](https://github.com/cotes2020/jekyll-theme-chirpy) for details.
+
+## Credits
+
+- Original theme: [Jekyll Chirpy](https://github.com/cotes2020/jekyll-theme-chirpy) by [Cotes Chung](https://github.com/cotes2020)
+- Built with [Astro](https://astro.build)
+- Icons by [Font Awesome](https://fontawesome.com)
+- Styling with [Bootstrap](https://getbootstrap.com) and custom SCSS
+
+## Support
+
+- [Documentation](https://astro.build)
+- [Astro Discord](https://astro.build/chat)
+- [GitHub Issues](https://github.com/your-repo/issues)
+
+---
+
+Made using [Astro](https://astro.build)
diff --git a/astro.config.mjs b/astro.config.mjs
new file mode 100644
index 00000000000..0aeb70b8322
--- /dev/null
+++ b/astro.config.mjs
@@ -0,0 +1,26 @@
+import { defineConfig } from 'astro/config';
+import mdx from '@astrojs/mdx';
+import sitemap from '@astrojs/sitemap';
+
+// https://astro.build/config
+export default defineConfig({
+ site: 'https://example.com', // Update this to your site URL
+ integrations: [
+ mdx(),
+ sitemap(),
+ ],
+ markdown: {
+ syntaxHighlight: 'shiki',
+ shikiConfig: {
+ theme: 'github-dark',
+ wrap: true
+ }
+ },
+ vite: {
+ resolve: {
+ alias: {
+ '@': '/src'
+ }
+ }
+ }
+});
diff --git a/netlify.toml b/netlify.toml
new file mode 100644
index 00000000000..bc171e92175
--- /dev/null
+++ b/netlify.toml
@@ -0,0 +1,75 @@
+# Netlify configuration for Astro Chirpy
+# https://docs.netlify.com/configure-builds/file-based-configuration/
+
+[build]
+ # Build command
+ command = "npm run build"
+
+ # Directory to publish (Astro output)
+ publish = "dist"
+
+ # Set Node.js version
+ [build.environment]
+ NODE_VERSION = "18"
+
+# Redirect rules
+[[redirects]]
+ # SPA fallback (if needed for dynamic routes)
+ from = "/*"
+ to = "/404.html"
+ status = 404
+
+# Headers for security and performance
+[[headers]]
+ for = "/*"
+ [headers.values]
+ # Security headers
+ X-Frame-Options = "DENY"
+ X-Content-Type-Options = "nosniff"
+ X-XSS-Protection = "1; mode=block"
+ Referrer-Policy = "strict-origin-when-cross-origin"
+
+ # Cache control for HTML (don't cache)
+ Cache-Control = "public, max-age=0, must-revalidate"
+
+[[headers]]
+ for = "/assets/*"
+ [headers.values]
+ # Cache static assets for 1 year
+ Cache-Control = "public, max-age=31536000, immutable"
+
+[[headers]]
+ for = "/*.js"
+ [headers.values]
+ # Cache JavaScript files
+ Cache-Control = "public, max-age=31536000, immutable"
+
+[[headers]]
+ for = "/*.css"
+ [headers.values]
+ # Cache CSS files
+ Cache-Control = "public, max-age=31536000, immutable"
+
+[[headers]]
+ for = "/fonts/*"
+ [headers.values]
+ # Cache fonts for 1 year
+ Cache-Control = "public, max-age=31536000, immutable"
+
+[[headers]]
+ for = "/images/*"
+ [headers.values]
+ # Cache images for 1 year
+ Cache-Control = "public, max-age=31536000, immutable"
+
+# Plugin configuration
+[[plugins]]
+ # Netlify plugin for Astro (if available)
+ package = "@astrojs/netlify"
+
+# Development server settings
+[dev]
+ command = "npm run dev"
+ port = 4321
+ targetPort = 4321
+ autoLaunch = false
diff --git a/package.json b/package.json
index 61e4a425a0b..160c33efb34 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
- "name": "jekyll-theme-chirpy",
- "version": "7.4.1",
- "description": "A minimal, responsive, and feature-rich Jekyll theme for technical writing.",
+ "name": "astro-chirpy",
+ "version": "1.0.0",
+ "description": "A minimal, responsive, and feature-rich Astro theme for technical writing, migrated from Jekyll Chirpy.",
"repository": {
"type": "git",
"url": "git+https://github.com/cotes2020/jekyll-theme-chirpy.git"
@@ -15,21 +15,25 @@
"homepage": "https://github.com/cotes2020/jekyll-theme-chirpy/",
"type": "module",
"scripts": {
- "build": "concurrently npm:build:*",
- "build:css": "node purgecss.js",
- "build:js": "rollup -c --bundleConfigAsCjs --environment BUILD:production",
- "watch:js": "rollup -c --bundleConfigAsCjs -w",
- "lint:js": "eslint",
- "lint:scss": "stylelint _sass/**/*.scss",
+ "dev": "astro dev",
+ "start": "astro dev",
+ "build": "astro check && astro build",
+ "preview": "astro preview",
+ "astro": "astro",
+ "lint:js": "eslint src/**/*.{js,ts,astro}",
+ "lint:scss": "stylelint src/styles/**/*.scss",
"lint:fix:scss": "npm run lint:scss -- --fix",
- "test": "npm run lint:js && npm run lint:scss",
- "prepare": "husky"
+ "test": "npm run lint:js && npm run lint:scss"
},
"dependencies": {
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.8"
},
"devDependencies": {
+ "@astrojs/check": "^0.9.5",
+ "@astrojs/mdx": "^4.3.10",
+ "@astrojs/rss": "^4.0.13",
+ "@astrojs/sitemap": "^3.6.0",
"@babel/core": "^7.28.4",
"@babel/plugin-transform-class-properties": "^7.27.1",
"@babel/plugin-transform-private-methods": "^7.27.1",
@@ -42,6 +46,7 @@
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/exec": "^7.1.0",
"@semantic-release/git": "^10.0.1",
+ "astro": "^5.15.4",
"concurrently": "^9.2.1",
"conventional-changelog-conventionalcommits": "^9.1.0",
"eslint": "^9.38.0",
@@ -49,9 +54,11 @@
"husky": "^9.1.7",
"purgecss": "^7.0.2",
"rollup": "^4.52.5",
+ "sass": "^1.93.3",
"semantic-release": "^25.0.1",
"stylelint": "^16.25.0",
- "stylelint-config-standard-scss": "^16.0.0"
+ "stylelint-config-standard-scss": "^16.0.0",
+ "typescript": "^5.9.3"
},
"prettier": {
"trailingComma": "none"
diff --git a/public/.nojekyll b/public/.nojekyll
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/src/components/Footer.astro b/src/components/Footer.astro
new file mode 100644
index 00000000000..6922ae371f7
--- /dev/null
+++ b/src/components/Footer.astro
@@ -0,0 +1,27 @@
+---
+import { SITE, SOCIAL } from '@/config';
+
+export interface Props {
+ lang?: string;
+}
+
+const { lang } = Astro.props;
+const currentYear = new Date().getFullYear();
+---
+
+
diff --git a/src/components/Head.astro b/src/components/Head.astro
new file mode 100644
index 00000000000..ce51198e242
--- /dev/null
+++ b/src/components/Head.astro
@@ -0,0 +1,107 @@
+---
+import { SITE, SOCIAL, ANALYTICS, FEATURES, WEBMASTER_VERIFICATIONS } from '@/config';
+import { ViewTransitions } from 'astro:transitions';
+
+export interface Props {
+ title?: string;
+ description?: string;
+ image?: string;
+}
+
+const { title, description, image } = Astro.props;
+
+const pageTitle = title ? `${title} | ${SITE.title}` : SITE.title;
+const pageDescription = description || SITE.description;
+const pageImage = image || SITE.social_preview_image;
+const canonicalURL = new URL(Astro.url.pathname, SITE.url).href;
+
+// Handle image URL (add CDN if needed)
+const getImageUrl = (src: string) => {
+ if (!src) return '';
+ if (src.startsWith('http://') || src.startsWith('https://')) return src;
+ if (src.startsWith('/') && SITE.cdn) return `${SITE.cdn}${src}`;
+ return src;
+};
+
+const socialImage = getImageUrl(pageImage);
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {pageTitle}
+
+
+
+
+
+
+
+
+ {socialImage && }
+
+
+
+
+
+
+
+ {socialImage && }
+
+
+ {WEBMASTER_VERIFICATIONS.google && }
+ {WEBMASTER_VERIFICATIONS.bing && }
+ {WEBMASTER_VERIFICATIONS.yandex && }
+ {WEBMASTER_VERIFICATIONS.baidu && }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {import.meta.env.PROD && ANALYTICS.google.id && (
+
+
+ )}
+
+
+
+
diff --git a/src/components/SearchResults.astro b/src/components/SearchResults.astro
new file mode 100644
index 00000000000..d9023ce45ff
--- /dev/null
+++ b/src/components/SearchResults.astro
@@ -0,0 +1,49 @@
+---
+export interface Props {
+ lang?: string;
+}
+
+const { lang } = Astro.props;
+---
+
+
+
+
+
+
Type to search...
+
+
+
+
+
+
diff --git a/src/components/Sidebar.astro b/src/components/Sidebar.astro
new file mode 100644
index 00000000000..1eb4c5d2610
--- /dev/null
+++ b/src/components/Sidebar.astro
@@ -0,0 +1,142 @@
+---
+import { SITE, FEATURES } from '@/config';
+import { CONTACT_LINKS } from '@/config-contact';
+import { getCollection } from 'astro:content';
+
+export interface Props {
+ lang?: string;
+}
+
+const { lang = SITE.lang } = Astro.props;
+
+// Get tabs from content collection
+const tabs = await getCollection('tabs');
+const sortedTabs = tabs.sort((a, b) => a.data.order - b.data.order);
+
+// Get avatar URL
+const getAvatarUrl = (src: string) => {
+ if (!src) return '';
+ if (src.startsWith('http://') || src.startsWith('https://')) return src;
+ if (src.startsWith('/') && SITE.cdn) return `${SITE.cdn}${src}`;
+ return src;
+};
+
+const avatarUrl = getAvatarUrl(SITE.avatar);
+
+// Simple locale strings
+const locales: Record = {
+ en: {
+ tabs: {
+ home: 'HOME'
+ }
+ }
+};
+
+const locale = locales[lang] || locales.en;
+
+// Process contact links
+const contactLinks = CONTACT_LINKS.filter((entry: any) => {
+ if (entry.type === 'github') {
+ return SITE.github?.username;
+ }
+ if (entry.type === 'twitter') {
+ return SITE.twitter?.username;
+ }
+ if (entry.type === 'email') {
+ return SITE.social?.email;
+ }
+ return true;
+}).map((entry: any) => {
+ let url = '';
+
+ if (entry.type === 'github') {
+ url = `https://github.com/${SITE.github?.username || ''}`;
+ } else if (entry.type === 'twitter') {
+ url = `https://twitter.com/${SITE.twitter?.username || ''}`;
+ } else if (entry.type === 'rss') {
+ url = '/rss.xml';
+ } else {
+ url = entry.url || '';
+ }
+
+ return { ...entry, url };
+});
+---
+
+
+
+
+
diff --git a/src/components/Topbar.astro b/src/components/Topbar.astro
new file mode 100644
index 00000000000..fd3bda0af3d
--- /dev/null
+++ b/src/components/Topbar.astro
@@ -0,0 +1,111 @@
+---
+export interface Props {
+ lang?: string;
+}
+
+const { lang } = Astro.props;
+const currentPath = Astro.url.pathname;
+---
+
+
+
+
diff --git a/src/components/TrendingTags.astro b/src/components/TrendingTags.astro
new file mode 100644
index 00000000000..2fd0d72d80d
--- /dev/null
+++ b/src/components/TrendingTags.astro
@@ -0,0 +1,41 @@
+---
+import { getCollection } from 'astro:content';
+
+export interface Props {
+ lang?: string;
+}
+
+const { lang } = Astro.props;
+
+// Get all posts and count tags
+const posts = await getCollection('posts');
+const tagCounts = new Map();
+
+posts
+ .filter(post => !post.data.hidden)
+ .forEach(post => {
+ if (post.data.tags) {
+ post.data.tags.forEach(tag => {
+ tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1);
+ });
+ }
+ });
+
+// Sort by count and get top 10
+const trendingTags = Array.from(tagCounts.entries())
+ .sort((a, b) => b[1] - a[1])
+ .slice(0, 10);
+---
+
+{trendingTags.length > 0 && (
+
+
Trending Tags
+
+ {trendingTags.map(([tag, count]) => (
+
+ {tag}
+
+ ))}
+
+
+)}
diff --git a/src/components/UpdateList.astro b/src/components/UpdateList.astro
new file mode 100644
index 00000000000..8410c92aa99
--- /dev/null
+++ b/src/components/UpdateList.astro
@@ -0,0 +1,33 @@
+---
+import { getCollection } from 'astro:content';
+
+export interface Props {
+ lang?: string;
+}
+
+const { lang } = Astro.props;
+
+// Get recently updated posts
+const posts = await getCollection('posts');
+const recentlyUpdated = posts
+ .filter(post => !post.data.hidden)
+ .sort((a, b) => {
+ const dateA = new Date(a.data.date);
+ const dateB = new Date(b.data.date);
+ return dateB.getTime() - dateA.getTime();
+ })
+ .slice(0, 5);
+---
+
+{recentlyUpdated.length > 0 && (
+
+
Recently Updated
+
+ {recentlyUpdated.map((post) => (
+ -
+ {post.data.title}
+
+ ))}
+
+
+)}
diff --git a/src/config-contact.ts b/src/config-contact.ts
new file mode 100644
index 00000000000..cd7d026c932
--- /dev/null
+++ b/src/config-contact.ts
@@ -0,0 +1,31 @@
+// Contact links configuration
+export const CONTACT_LINKS = [
+ {
+ type: 'github',
+ icon: 'fab fa-github'
+ },
+ {
+ type: 'twitter',
+ icon: 'fa-brands fa-x-twitter'
+ },
+ {
+ type: 'email',
+ icon: 'fas fa-envelope'
+ },
+ {
+ type: 'rss',
+ icon: 'fas fa-rss'
+ }
+];
+
+// You can add more social links here:
+// {
+// type: 'linkedin',
+// icon: 'fab fa-linkedin',
+// url: 'https://linkedin.com/in/username'
+// },
+// {
+// type: 'mastodon',
+// icon: 'fab fa-mastodon',
+// url: 'https://mastodon.social/@username'
+// }
diff --git a/src/config.ts b/src/config.ts
new file mode 100644
index 00000000000..3c0c731b007
--- /dev/null
+++ b/src/config.ts
@@ -0,0 +1,113 @@
+export const SITE = {
+ title: 'Chirpy',
+ tagline: 'A text-focused Jekyll theme',
+ description: 'A minimal, responsive and feature-rich Jekyll theme for technical writing.',
+ url: 'https://example.com', // Update this to your site URL
+ baseurl: '',
+ lang: 'en',
+ timezone: 'Asia/Shanghai',
+ cdn: 'https://chirpy-img.netlify.app',
+ avatar: '/commons/avatar.jpg',
+ social_preview_image: '',
+ social: {
+ name: 'your_full_name',
+ email: 'example@domain.com',
+ },
+ github: {
+ username: 'github_username',
+ },
+ twitter: {
+ username: 'twitter_username',
+ },
+};
+
+export const SOCIAL = {
+ name: 'your_full_name',
+ email: 'example@domain.com',
+ links: [
+ 'https://twitter.com/username',
+ 'https://github.com/username',
+ ],
+};
+
+export const GITHUB = {
+ username: 'github_username',
+};
+
+export const TWITTER = {
+ username: 'twitter_username',
+};
+
+export const ANALYTICS = {
+ google: {
+ id: '',
+ },
+ goatcounter: {
+ id: '',
+ },
+ umami: {
+ id: '',
+ domain: '',
+ },
+ matomo: {
+ id: '',
+ domain: '',
+ },
+ cloudflare: {
+ id: '',
+ },
+ fathom: {
+ id: '',
+ },
+};
+
+export const PAGEVIEWS = {
+ provider: '', // 'goatcounter'
+};
+
+export const COMMENTS = {
+ provider: '', // 'disqus' | 'utterances' | 'giscus'
+ disqus: {
+ shortname: '',
+ },
+ utterances: {
+ repo: '',
+ issue_term: '',
+ },
+ giscus: {
+ repo: '',
+ repo_id: '',
+ category: '',
+ category_id: '',
+ mapping: 'pathname',
+ strict: '0',
+ input_position: 'bottom',
+ lang: 'en',
+ reactions_enabled: '1',
+ },
+};
+
+export const FEATURES = {
+ toc: true,
+ theme_mode: '', // 'light' | 'dark' | '' (empty for system default with toggle)
+ pwa: {
+ enabled: true,
+ cache: {
+ enabled: true,
+ deny_paths: [],
+ },
+ },
+};
+
+export const PAGINATION = {
+ postsPerPage: 10,
+};
+
+export const WEBMASTER_VERIFICATIONS = {
+ google: '',
+ bing: '',
+ alexa: '',
+ yandex: '',
+ baidu: '',
+ facebook: '',
+};
diff --git a/src/content/config.ts b/src/content/config.ts
new file mode 100644
index 00000000000..484f51b3074
--- /dev/null
+++ b/src/content/config.ts
@@ -0,0 +1,38 @@
+import { defineCollection, z } from 'astro:content';
+
+const posts = defineCollection({
+ type: 'content',
+ schema: z.object({
+ title: z.string(),
+ date: z.coerce.date(),
+ categories: z.array(z.string()).optional(),
+ tags: z.array(z.string()).optional(),
+ author: z.string().optional(),
+ description: z.string().optional(),
+ image: z.object({
+ path: z.string(),
+ alt: z.string().optional(),
+ lqip: z.string().optional(),
+ no_bg: z.boolean().optional(),
+ }).optional(),
+ pin: z.boolean().optional(),
+ hidden: z.boolean().optional(),
+ toc: z.boolean().default(true),
+ comments: z.boolean().default(true),
+ math: z.boolean().optional(),
+ mermaid: z.boolean().optional(),
+ media_subpath: z.string().optional(),
+ render_with_liquid: z.boolean().optional(),
+ }),
+});
+
+const tabs = defineCollection({
+ type: 'content',
+ schema: z.object({
+ title: z.string(),
+ icon: z.string(),
+ order: z.number(),
+ }),
+});
+
+export const collections = { posts, tabs };
diff --git a/src/content/posts/welcome-to-astro-chirpy.md b/src/content/posts/welcome-to-astro-chirpy.md
new file mode 100644
index 00000000000..a1f1e35afd8
--- /dev/null
+++ b/src/content/posts/welcome-to-astro-chirpy.md
@@ -0,0 +1,75 @@
+---
+title: Welcome to Astro Chirpy
+date: 2024-01-15T10:00:00+00:00
+categories: [Blogging, Tutorial]
+tags: [astro, chirpy, migration]
+description: A minimal, responsive and feature-rich Astro theme for technical writing, migrated from Jekyll Chirpy.
+pin: true
+---
+
+## Welcome! 🎉
+
+This is **Astro Chirpy**, a migration of the popular Jekyll Chirpy theme to Astro. This theme maintains the clean, minimal design while leveraging Astro's modern features for blazing-fast performance.
+
+## Features
+
+### Performance
+- ⚡ Lightning-fast page loads with Astro
+- 🎯 Zero JS by default
+- 📦 Optimized bundle sizes
+
+### Design
+- 🎨 Clean, minimal design
+- 🌓 Dark/Light mode toggle
+- 📱 Fully responsive
+- ♿ Accessible
+
+### Developer Experience
+- 🚀 Easy to customize
+- 📝 MDX support
+- 🔧 TypeScript ready
+- 🎭 Component-based architecture
+
+## Getting Started
+
+To create a new post, add a markdown file to `src/content/posts/` with the following frontmatter:
+
+```yaml
+---
+title: Your Post Title
+date: 2024-01-15T10:00:00+00:00
+categories: [Category1, Category2]
+tags: [tag1, tag2]
+description: Brief description of your post
+---
+```
+
+## Syntax Highlighting
+
+The theme supports syntax highlighting out of the box:
+
+```javascript
+function greet(name) {
+ console.log(`Hello, ${name}!`);
+}
+
+greet('Astro Chirpy');
+```
+
+```python
+def fibonacci(n):
+ if n <= 1:
+ return n
+ return fibonacci(n-1) + fibonacci(n-2)
+
+print(fibonacci(10))
+```
+
+## Next Steps
+
+1. Customize your site configuration in `src/config.ts`
+2. Add your own posts to `src/content/posts/`
+3. Modify the tabs in `src/content/tabs/`
+4. Update the styling in `src/styles/`
+
+Happy blogging! 📝
diff --git a/src/content/tabs/about.md b/src/content/tabs/about.md
new file mode 100644
index 00000000000..771852d2a04
--- /dev/null
+++ b/src/content/tabs/about.md
@@ -0,0 +1,16 @@
+---
+title: About
+icon: fas fa-info-circle
+order: 1
+---
+
+# About
+
+This is the about page. Replace this content with information about yourself or your blog.
+
+## Features
+
+- Built with Astro
+- Migrated from Jekyll Chirpy theme
+- Fast and modern
+- SEO optimized
diff --git a/src/content/tabs/archives.md b/src/content/tabs/archives.md
new file mode 100644
index 00000000000..8d54db770a3
--- /dev/null
+++ b/src/content/tabs/archives.md
@@ -0,0 +1,11 @@
+---
+title: Archives
+icon: fas fa-archive
+order: 2
+---
+
+# Archives
+
+Browse all posts by date.
+
+
diff --git a/src/content/tabs/categories.md b/src/content/tabs/categories.md
new file mode 100644
index 00000000000..218f0de916e
--- /dev/null
+++ b/src/content/tabs/categories.md
@@ -0,0 +1,11 @@
+---
+title: Categories
+icon: fas fa-folder-open
+order: 3
+---
+
+# Categories
+
+Browse posts by category.
+
+
diff --git a/src/content/tabs/tags.md b/src/content/tabs/tags.md
new file mode 100644
index 00000000000..95c60f39743
--- /dev/null
+++ b/src/content/tabs/tags.md
@@ -0,0 +1,11 @@
+---
+title: Tags
+icon: fas fa-tags
+order: 4
+---
+
+# Tags
+
+Browse posts by tags.
+
+
diff --git a/src/data/authors.yml b/src/data/authors.yml
new file mode 100644
index 00000000000..f012012135a
--- /dev/null
+++ b/src/data/authors.yml
@@ -0,0 +1,17 @@
+## Template › https://github.com/jekyll/jekyll-seo-tag/blob/master/docs/advanced-usage.md#setting-author-url
+# -------------------------------------
+# {author_id}:
+# name: {full name}
+# twitter: {twitter_of_author}
+# url: {homepage_of_author}
+# -------------------------------------
+
+cotes:
+ name: Cotes Chung
+ twitter: cotes2020
+ url: https://github.com/cotes2020/
+
+sille_bille:
+ name: Dinesh Prasanth Moluguwan Krishnamoorthy
+ twitter: dinesh_MKD
+ url: https://github.com/SilleBille/
diff --git a/src/data/contact.yml b/src/data/contact.yml
new file mode 100644
index 00000000000..ed40acb7e97
--- /dev/null
+++ b/src/data/contact.yml
@@ -0,0 +1,40 @@
+# The contact options.
+
+- type: github
+ icon: "fab fa-github"
+
+- type: twitter
+ icon: "fa-brands fa-x-twitter"
+
+- type: email
+ icon: "fas fa-envelope"
+ noblank: true # open link in current tab
+
+- type: rss
+ icon: "fas fa-rss"
+ noblank: true
+# Uncomment and complete the url below to enable more contact options
+#
+# - type: mastodon
+# icon: 'fab fa-mastodon' # icons powered by
+# url: '' # Fill with your Mastodon account page, rel="me" will be applied for verification
+#
+# - type: linkedin
+# icon: 'fab fa-linkedin' # icons powered by
+# url: '' # Fill with your Linkedin homepage
+#
+# - type: stack-overflow
+# icon: 'fab fa-stack-overflow'
+# url: '' # Fill with your stackoverflow homepage
+#
+# - type: bluesky
+# icon: 'fa-brands fa-bluesky'
+# url: '' # Fill with your Bluesky profile link
+#
+# - type: reddit
+# icon: 'fa-brands fa-reddit'
+# url: '' # Fill with your Reddit profile link
+#
+# - type: threads
+# icon: 'fa-brands fa-threads'
+# url: '' # Fill with your Threads profile link
diff --git a/src/data/locales/ar.yml b/src/data/locales/ar.yml
new file mode 100644
index 00000000000..a79e020091e
--- /dev/null
+++ b/src/data/locales/ar.yml
@@ -0,0 +1,91 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: منشور
+ category: فئة
+ tag: وسم
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: الرئيسية
+ categories: الفئات
+ tags: الوسوم
+ archives: الأرشيف
+ about: حول
+
+# the text displayed in the search bar & search results
+search:
+ hint: بحث
+ cancel: إلغاء
+ no_results: نأسف! لا يوجد نتائج.
+
+panel:
+ lastmod: المحدثة مؤخرا
+ trending_tags: الوسوم الشائعة
+ toc: محتويات
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: هذا المنشور تحت ترخيص :LICENSE_NAME بواسطة المؤلف.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: بعض الحقوق محفوظة.
+ verbose: >-
+ ما لم يذكر خلاف ذلك ، يتم ترخيص منشورات المدونة على هذا الموقع
+ بموجب ترخيص Creative Commons Attribution 4.0 International (CC BY 4.0) من قبل المؤلف.
+
+meta: باستخدام :PLATFORM السمة :THEME
+
+not_found:
+ statement: عذرا, الرابط التالي غير صالح أو انه يشير إلى صفحة غير موجودة.
+
+notification:
+ update_found: يتوفر اصدار جديد للمحتوى.
+ update: تحديث
+
+# ----- Posts related labels -----
+
+post:
+ written_by: بواسطة
+ posted: نشّر
+ updated: حدّث
+ words: كلمات
+ pageview_measure: مشاهدات
+ read_time:
+ unit: دقيقة
+ prompt: قراءة
+ relate_posts: إقرأ المزيد
+ share: شارك
+ button:
+ next: الأجدد
+ previous: الأقدم
+ copy_code:
+ succeed: تم النسخ!
+ share_link:
+ title: أنسخ الرابط
+ succeed: تم نسخ الرابط بنجاح!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure:
+ singular: فئة
+ plural: فئات
+ post_measure:
+ singular: منشور
+ plural: منشورات
diff --git a/src/data/locales/bg-BG.yml b/src/data/locales/bg-BG.yml
new file mode 100644
index 00000000000..3fb060fdae3
--- /dev/null
+++ b/src/data/locales/bg-BG.yml
@@ -0,0 +1,81 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Публикация
+ category: Категория
+ tag: Таг
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Начало
+ categories: Категории
+ tags: Тагове
+ archives: Архив
+ about: За мен
+
+# the text displayed in the search bar & search results
+search:
+ hint: търси
+ cancel: Отмени
+ no_results: Упс! Не са намерени резултати.
+
+panel:
+ lastmod: Наскоро обновени
+ trending_tags: Популярни тагове
+ toc: Съдържание
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Тази публикация е лицензирана под :LICENSE_NAME от автора.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Някои права запазени.
+ verbose: >-
+ Освен ако не е посочено друго, публикациите в блога на този сайт са лицензирани
+ под лиценза Creative Commons Attribution 4.0 (CC BY 4.0) от автора.
+
+meta: Създадено чрез :PLATFORM и :THEME тема
+
+not_found:
+ statement: Съжалявам, но на този URL адрес няма налично съдържание.
+
+notification:
+ update_found: Налична е нова версия на съдържанието.
+ update: Обнови
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Автор
+ posted: Публикувана
+ updated: Обновена
+ words: думи
+ pageview_measure: преглеждания
+ read_time:
+ unit: мин
+ prompt: четиво
+ relate_posts: Още за четене
+ share: Споделете
+ button:
+ next: По-нови
+ previous: По-стари
+ copy_code:
+ succeed: Копирано!
+ share_link:
+ title: Копирай линк
+ succeed: Линкът е копиран успешно!
+
+# categories page
+categories:
+ category_measure:
+ singular: категория
+ plural: категории
+ post_measure:
+ singular: публикация
+ plural: публикации
diff --git a/src/data/locales/ca-ES.yml b/src/data/locales/ca-ES.yml
new file mode 100644
index 00000000000..e3d5b39ceae
--- /dev/null
+++ b/src/data/locales/ca-ES.yml
@@ -0,0 +1,84 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Entrada
+ category: Categoria
+ tag: Etiqueta
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Inici
+ categories: Categories
+ tags: Etiquetes
+ archives: Arxiu
+ about: Sobre
+
+# the text displayed in the search bar & search results
+search:
+ hint: Cercar
+ cancel: Cancel·lar
+ no_results: Ups! No s'han trobat resultats.
+
+panel:
+ lastmod: Actualitzat recentment
+ trending_tags: Etiquetes populars
+ toc: Taula de continguts
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Aquesta entrada està llicenciada sota :LICENSE_NAME per l'autor.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Alguns drets reservats.
+ verbose: >-
+ Excepte que s'indiqui explícitament, les entrades d'aquest blog estan llicenciades
+ sota la llicència Creative Commons Attribution 4.0 International (CC BY 4.0) per l'autor.
+
+meta: Fet amb :PLATFORM utilitzant el tema :THEME
+
+not_found:
+ statement: Ho sentim, hem perdut aquesta URL o apunta a alguna cosa que no existeix.
+
+notification:
+ update_found: Hi ha una nova versió de contingut disponible.
+ update: Actualitzar
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Per
+ posted: Publicat
+ updated: Actualitzat
+ words: paraules
+ pageview_measure: visites
+ read_time:
+ unit: min
+ prompt: " de lectura"
+ relate_posts: Entrades relacionades
+ share: Compartir
+ button:
+ next: Següent
+ previous: Anterior
+ copy_code:
+ succeed: Copiat!
+ share_link:
+ title: Copiar enllaç
+ succeed: Enllaç copiat!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%Y/%m/%d"
+ dayjs: "YYYY/MM/DD"
+
+# categories page
+categories:
+ category_measure: categories
+ post_measure: entrades
diff --git a/src/data/locales/cs-CZ.yml b/src/data/locales/cs-CZ.yml
new file mode 100644
index 00000000000..cf93f614a6b
--- /dev/null
+++ b/src/data/locales/cs-CZ.yml
@@ -0,0 +1,89 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Příspěvek
+ category: Kategorie
+ tag: Štítek
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Domů
+ categories: Kategorie
+ tags: Štítky
+ archives: Archivy
+ about: O mně
+
+# the text displayed in the search bar & search results
+search:
+ hint: hledat
+ cancel: Zrušit
+ no_results: Ups! Žádný výsledek nenalezen.
+
+panel:
+ lastmod: Nedávno aktualizováno
+ trending_tags: Trendy štítky
+ toc: Obsah
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Tento příspěvek je licencován pod :LICENSE_NAME autorem.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Některá práva vyhrazena.
+ verbose: >-
+ Pokud není uvedeno jinak, jsou příspěvky na tomto webu licencovány
+ pod licencí Creative Commons Attribution 4.0 International (CC BY 4.0) Licence autora.
+
+meta: Použití :PLATFORM s motivem :THEME
+
+not_found:
+ statement: Omlouváme se, adresu URL jsme špatně umístili nebo odkazuje na něco, co neexistuje.
+
+notification:
+ update_found: Je k dispozici nová verze obsahu.
+ update: Aktualizace
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Od
+ posted: Zveřejněno
+ updated: Aktualizováno
+ words: slova
+ pageview_measure: zhlednutí
+ read_time:
+ unit: minut
+ prompt: čtení
+ relate_posts: Další čtení
+ share: Sdílet
+ button:
+ next: Novější
+ previous: Starší
+ copy_code:
+ succeed: Zkopírováno!
+ share_link:
+ title: Kopírovat odkaz
+ succeed: Zkopírováno!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure: kategorie
+ post_measure:
+ singular: příspěvěk
+ plural: příspěvky
diff --git a/src/data/locales/da-DK.yml b/src/data/locales/da-DK.yml
new file mode 100644
index 00000000000..4b41fb389ea
--- /dev/null
+++ b/src/data/locales/da-DK.yml
@@ -0,0 +1,86 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Opslag
+ category: Kategori
+ tag: Tag
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Hjem
+ categories: Kategorier
+ tags: Tags
+ archives: Arkiv
+ about: Om siden
+
+# the text displayed in the search bar & search results
+search:
+ hint: søg
+ cancel: Afbryd
+ no_results: Ups! Ingen resultater fundet.
+
+panel:
+ lastmod: Senest opdateret
+ trending_tags: Populære tags
+ toc: Indhold
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Dette opslag er licenseret under :LICENSE_NAME af forfatteren.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Nogle rettigheder forbeholdes.
+ verbose: >-
+ Medmindre andet er angivet, er opslag på denne side beskyttet
+ under Creative Commons Attribution 4.0 International (CC BY 4.0) licensen af forfatteren.
+
+# meta: Using the :THEME theme for :PLATFORM.
+
+not_found:
+ statement: Beklager, vi har malpaceret denne URL, eller den peger på et sted, som ikke findes.
+
+notification:
+ update_found: En ny version af indholdet er fundet!
+ update: Opdater
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Af
+ posted: Udgivet
+ updated: Opdateret
+ words: ord
+ pageview_measure: visninger
+ read_time:
+ unit: min
+ prompt: læsetid
+ relate_posts: Læs videre
+ share: Del
+ button:
+ next: Nyere
+ previous: Ældre
+ copy_code:
+ succeed: Kopieret!
+ share_link:
+ title: Kopier link
+ succeed: Link kopieret!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%Y/%m/%d"
+ dayjs: "YYYY/MM/DD"
+
+# categories page
+categories:
+ category_measure:
+ singular: kategori
+ plural: kategorier
+ post_measure: opslag
diff --git a/src/data/locales/de-DE.yml b/src/data/locales/de-DE.yml
new file mode 100644
index 00000000000..6c9d91d469b
--- /dev/null
+++ b/src/data/locales/de-DE.yml
@@ -0,0 +1,87 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Eintrag
+ category: Kategorie
+ tag: Tag
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Startseite
+ categories: Kategorien
+ tags: Tags
+ archives: Archiv
+ about: Über
+
+# the text displayed in the search bar & search results
+search:
+ hint: Suche
+ cancel: Abbrechen
+ no_results: Ups! Keine Einträge gefunden.
+
+panel:
+ lastmod: Kürzlich aktualisiert
+ trending_tags: Beliebte Tags
+ toc: Inhalt
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Dieser Eintrag ist vom Autor unter :LICENSE_NAME lizensiert.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Einige Rechte vorbehalten.
+ verbose: >-
+ Alle Einträge auf dieser Seite stehen, soweit nicht anders angegeben, unter der Lizenz Creative Commons Attribution 4.0 (CC BY 4.0).
+
+meta: Powered by :PLATFORM with :THEME theme
+
+not_found:
+ statement: Entschuldigung, dieser Link verweist auf keine vorhandene Ressource.
+
+notification:
+ update_found: Eine neue Version ist verfügbar.
+ update: Neue Version
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Von
+ posted: Veröffentlicht
+ updated: Aktualisiert
+ words: Wörter
+ pageview_measure: Aufrufe
+ read_time:
+ unit: Minuten
+ prompt: Lesezeit
+ relate_posts: Weiterlesen
+ share: Teilen
+ button:
+ next: Nächster Eintrag
+ previous: Eintrag vorher
+ copy_code:
+ succeed: Kopiert!
+ share_link:
+ title: Link kopieren
+ succeed: Link erfolgreich kopiert!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%d.%m.%Y"
+ dayjs: "DD.MM.YYYY"
+
+# categories page
+categories:
+ category_measure:
+ singular: Kategorie
+ plural: Kategorien
+ post_measure:
+ singular: Eintrag
+ plural: Einträge
diff --git "a/src/data/locales/dv\342\200\221MV.yml" "b/src/data/locales/dv\342\200\221MV.yml"
new file mode 100644
index 00000000000..680ca1f8b4c
--- /dev/null
+++ "b/src/data/locales/dv\342\200\221MV.yml"
@@ -0,0 +1,90 @@
+# The layout text of site in Dhivehi (Maldives)
+
+# ----- Commons label -----
+
+layout:
+ post: ޕޯސްޓް
+ category: ނަތީޖާ
+ tag: ޓެގް
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: ހުންނަ
+ categories: ނަތީޖާތައް
+ tags: ޓެގްތައް
+ archives: އާރޗިވްސް
+ about: އިންސާން
+
+# the text displayed in the search bar & search results
+search:
+ hint: ސާރޗް
+ cancel: ކެންސަލް
+ no_results: އޮޕްސް! އެއްވެސް ނުފެނުނީ.
+
+panel:
+ lastmod: އާދަމާ އޮޕްޑޭޓްކުރި
+ trending_tags: މަރާހު ޓެގްތައް
+ toc: ކޮންޓެންސް
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: މި ޕޯސްޓް :LICENSE_NAME އިން ލައިސަންސްކުރާ ނުވަތަ މުޤައްރާއަށް.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: އެކީ ބާރަށް ހުށަހަޅާ.
+ verbose: >-
+ އަދި އެ ރަނގަޅުގައި ނުލާހެވެސް، މި ސައިޓުގެ ޕޯސްޓްތައް
+ މުޤައްރާއަށް Creative Commons Attribution 4.0 International (CC BY 4.0) ލައިސަންސްކުރަނީ.
+
+meta: :PLATFORM އަށް :THEME ތީމް ބަލާލާށެވެ.
+
+not_found:
+ statement: ސޯރީ، މި ޔޫ.އާރއެލް މަށެވެއްނެ ނުވަތަ އެކަމެއް ނުވެއެވެ.
+
+notification:
+ update_found: ޔޫ ވާރޝަން ހުރިހާ.
+ update: އޮޕްޑޭޓް
+
+# ----- Posts related labels -----
+
+post:
+ written_by: ލެކްއޯލް
+ posted: ޕޯސްޓްކުރެވި
+ updated: އޮޕްޑޭޓްކުރެވި
+ words: ބަސް
+ pageview_measure: ބަނޑުކުރާ
+ read_time:
+ unit: މިނެޓް
+ prompt: އިސްކާރު
+ relate_posts: އެއްޗެހި ފަހުރަށްދަން
+ share: ސެއާރް
+ button:
+ next: އަދާވަނަ
+ previous: ކޮނޯނި
+ copy_code:
+ succeed: ކޮޕީ ކުރެވި!
+ share_link:
+ title: ލިންކް ކޮޕީ ކުރު
+ succeed: ލިންކް ހަދަންކުރެވި!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+categories:
+ category_measure:
+ singular: ނަތީޖާ
+ plural: ނަތީޖާތައް
+ post_measure:
+ singular: ޕޯސްޓް
+ plural: ޕޯސްޓްތައް
diff --git a/src/data/locales/el-GR.yml b/src/data/locales/el-GR.yml
new file mode 100644
index 00000000000..b6d2a866379
--- /dev/null
+++ b/src/data/locales/el-GR.yml
@@ -0,0 +1,91 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Δημοσίευση
+ category: Κατηγορία
+ tag: Ετικέτα
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Home
+ categories: Κατηγορίες
+ tags: Ετικέτες
+ archives: Αρχεία
+ about: Σχετικά
+
+# the text displayed in the search bar & search results
+search:
+ hint: αναζήτηση
+ cancel: Ακύρωση
+ no_results: Oops! Κανένα αποτέλεσμα δεν βρέθηκε.
+
+panel:
+ lastmod: Σχετικά ενημερωμένα
+ trending_tags: Ετικέτες τάσης
+ toc: Περιεχόμενα
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Η δημοσίευση αυτή βρίσκεται υπο την άδεια :LICENSE_NAME Greekforce1821.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Ορισμένα δικαιώματα reserved.
+ verbose: >-
+ Εκτός αλλού ή οπουδήποτε αλλού, τα blog posts σε αυτήν την σελίδα βρίσκονται υπο την άδεια
+ Creative Commons Attribution 4.0 International (CC BY 4.0) του δημιουργού.
+
+meta: Αξιοποιώντας την :PLATFORM theme :THEME
+
+not_found:
+ statement: Συγνώμη, έχουμε τοποθετήσει λάθος αυτήν την διεύθυνση URL ή υποδεικνύει κάτι που δεν υπάρχει.
+
+notification:
+ update_found: Υπάρχει διαθέσιμη μια νέα έκδοση του περιεχομένου.
+ update: Ενημέρωση
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Από
+ posted: Δημοσιεύθηκε
+ updated: Ενημερώθηκε
+ words: λέξεις
+ pageview_measure: προβολές
+ read_time:
+ unit: Λεπτά
+ prompt: διαβάσματος
+ relate_posts: Περισσότερα
+ share: Κοινοποιήστε
+ button:
+ next: Νεότερα
+ previous: Παλαιότερα
+ copy_code:
+ succeed: Αντιγράφθηκε!
+ share_link:
+ title: Αντιγραφή συνδέσμου
+ succeed: Η διεύθυνση αντιγράφθηκε με επιτυχία!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure:
+ singular: Κατηγορία
+ plural: Κατηγορίες
+ post_measure:
+ singular: Δημοσίευση
+ plural: Δημοσιεύσεις
diff --git a/src/data/locales/en.yml b/src/data/locales/en.yml
new file mode 100644
index 00000000000..152d090ac21
--- /dev/null
+++ b/src/data/locales/en.yml
@@ -0,0 +1,91 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Post
+ category: Category
+ tag: Tag
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Home
+ categories: Categories
+ tags: Tags
+ archives: Archives
+ about: About
+
+# the text displayed in the search bar & search results
+search:
+ hint: search
+ cancel: Cancel
+ no_results: Oops! No results found.
+
+panel:
+ lastmod: Recently Updated
+ trending_tags: Trending Tags
+ toc: Contents
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: This post is licensed under :LICENSE_NAME by the author.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Some rights reserved.
+ verbose: >-
+ Except where otherwise noted, the blog posts on this site are licensed
+ under the Creative Commons Attribution 4.0 International (CC BY 4.0) License by the author.
+
+meta: Using the :THEME theme for :PLATFORM.
+
+not_found:
+ statement: Sorry, we've misplaced that URL or it's pointing to something that doesn't exist.
+
+notification:
+ update_found: A new version of content is available.
+ update: Update
+
+# ----- Posts related labels -----
+
+post:
+ written_by: By
+ posted: Posted
+ updated: Updated
+ words: words
+ pageview_measure: views
+ read_time:
+ unit: min
+ prompt: read
+ relate_posts: Further Reading
+ share: Share
+ button:
+ next: Newer
+ previous: Older
+ copy_code:
+ succeed: Copied!
+ share_link:
+ title: Copy link
+ succeed: Link copied successfully!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure:
+ singular: category
+ plural: categories
+ post_measure:
+ singular: post
+ plural: posts
diff --git a/src/data/locales/es-ES.yml b/src/data/locales/es-ES.yml
new file mode 100644
index 00000000000..8f8d149ea3e
--- /dev/null
+++ b/src/data/locales/es-ES.yml
@@ -0,0 +1,77 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Entrada
+ category: Categoría
+ tag: Etiqueta
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Inicio
+ categories: Categorías
+ tags: Etiquetas
+ archives: Archivo
+ about: Acerca de
+
+# the text displayed in the search bar & search results
+search:
+ hint: Buscar
+ cancel: Cancelar
+ no_results: ¡Oops! No se encuentran resultados.
+
+panel:
+ lastmod: Actualizado recientemente
+ trending_tags: Etiquetas populares
+ toc: Contenido
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Esta entrada está licenciada bajo :LICENSE_NAME por el autor.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Algunos derechos reservados.
+ verbose: >-
+ Salvo que se indique explícitamente, las entradas de este blog están licenciadas
+ bajo la Creative Commons Attribution 4.0 International (CC BY 4.0) License por el autor.
+
+meta: Hecho con :PLATFORM usando el tema :THEME
+
+not_found:
+ statement: Lo sentimos, hemos perdido esa URL o apunta a algo que no existe.
+
+notification:
+ update_found: Hay una nueva versión de contenido disponible.
+ update: Actualizar
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Por
+ posted: Publicado
+ updated: Actualizado
+ words: palabras
+ pageview_measure: visitas
+ read_time:
+ unit: min
+ prompt: " de lectura"
+ relate_posts: Lecturas adicionales
+ share: Compartir
+ button:
+ next: Nuevo
+ previous: Anterior
+ copy_code:
+ succeed: ¡Copiado!
+ share_link:
+ title: Copiar enlace
+ succeed: ¡Enlace copiado!
+
+# categories page
+categories:
+ category_measure: categorias
+ post_measure: entradas
diff --git a/src/data/locales/fa-IR.yml b/src/data/locales/fa-IR.yml
new file mode 100644
index 00000000000..7a33deb1209
--- /dev/null
+++ b/src/data/locales/fa-IR.yml
@@ -0,0 +1,91 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: پست
+ category: دستهبندی
+ tag: برچسب
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: خانه
+ categories: دستهبندیها
+ tags: برچسبها
+ archives: آرشیو
+ about: درباره
+
+# the text displayed in the search bar & search results
+search:
+ hint: جستجو
+ cancel: لغو
+ no_results: متأسفیم! هیچ نتیجهای یافت نشد.
+
+panel:
+ lastmod: آخرین بهروزرسانی
+ trending_tags: برچسبهای پرطرفدار
+ toc: فهرست مطالب
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: این پست تحت مجوز :LICENSE_NAME توسط نویسنده منتشر شده است.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: برخی حقوق محفوظ است.
+ verbose: >-
+ بهجز مواردی که خلاف آن ذکر شده باشد، محتوای پستهای این وبلاگ
+ تحت مجوز Creative Commons Attribution 4.0 International (CC BY 4.0) توسط نویسنده منتشر شدهاند.
+
+meta: با استفاده از قالب :THEME برای :PLATFORM
+
+not_found:
+ statement: متأسفیم، لینک زیر معتبر نیست یا به صفحهای که وجود ندارد اشاره میکند.
+
+notification:
+ update_found: نسخه جدیدی از محتوا موجود است.
+ update: بهروزرسانی
+
+# ----- Posts related labels -----
+
+post:
+ written_by: نوشته شده توسط
+ posted: منتشر شده
+ updated: بهروزرسانی شده
+ words: کلمه
+ pageview_measure: بازدید
+ read_time:
+ unit: "دقیقه "
+ prompt: " زمان مطالعه"
+ relate_posts: بیشتر بخوانید
+ share: اشتراکگذاری
+ button:
+ next: جدیدتر
+ previous: قدیمیتر
+ copy_code:
+ succeed: کپی شد!
+ share_link:
+ title: کپی لینک
+ succeed: لینک با موفقیت کپی شد!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure:
+ singular: دستهبندی
+ plural: دستهبندی
+ post_measure:
+ singular: پست
+ plural: پست
diff --git a/src/data/locales/fi-FI.yml b/src/data/locales/fi-FI.yml
new file mode 100644
index 00000000000..60c9862054f
--- /dev/null
+++ b/src/data/locales/fi-FI.yml
@@ -0,0 +1,90 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Julkaisu
+ category: Kateogoria
+ tag: Tagi
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Koti
+ categories: Kateogoriat
+ tags: Tagit
+ archives: Arkistot
+ about: Minusta
+
+# the text displayed in the search bar & search results
+search:
+ hint: etsi
+ cancel: Peruuta
+ no_results: Hups! Ei tuloksia.
+
+panel:
+ lastmod: Viimeksi päivitetty
+ trending_tags: Trendaavat tagit
+ toc: Sisältö
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Tämä julkaisu on lisenssoitu :LICENSE_NAME julkaisijan toimesta.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Jotkut oikeudet pidätetään.
+ verbose: >-
+ Paitsi jos erikseen mainitaan on kaikki sisältö Creative Commons Attribution 4.0 International (CC BY 4.0) Lisensoitu kirjoittajan toimesta.
+
+meta: Käytetään :PLATFORM iä Teema :THEME
+
+not_found:
+ statement: Valitettavasti tällä URL-osoitteella ei ole saatavilla sisältöä.
+
+notification:
+ update_found: Uusi versio sisällöstä on saatavilla.
+ update: Päivitä
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Kirjoittaja
+ posted: Julkaistu
+ updated: Päivitetty
+ words: sanaa
+ pageview_measure: katselukertoja
+ read_time:
+ unit: minuuttia
+ prompt: lukea
+ relate_posts: Jatka lukemista
+ share: Jaa
+ button:
+ next: Uudempi
+ previous: Vanhempi
+ copy_code:
+ succeed: Kopiotu!
+ share_link:
+ title: Kopioi linkki
+ succeed: Linkki kopioitu onnistuneesti!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure:
+ singular: kategoria
+ plural: kategoriat
+ post_measure:
+ singular: julkaisu
+ plural: julkaisut
diff --git a/src/data/locales/fr-FR.yml b/src/data/locales/fr-FR.yml
new file mode 100644
index 00000000000..dce83c9f4e4
--- /dev/null
+++ b/src/data/locales/fr-FR.yml
@@ -0,0 +1,77 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Post
+ category: Catégorie
+ tag: Tag
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Accueil
+ categories: Catégories
+ tags: Tags
+ archives: Archives
+ about: À propos
+
+# the text displayed in the search bar & search results
+search:
+ hint: recherche
+ cancel: Annuler
+ no_results: Oups ! Aucun résultat trouvé.
+
+panel:
+ lastmod: Récemment mis à jour
+ trending_tags: Tags tendance
+ toc: Contenu
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Cet article est sous licence :LICENSE_NAME par l'auteur.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/deed.fr
+
+ # Displayed in the footer
+ brief: Certains droits réservés.
+ verbose: >-
+ Sauf mention contraire, les articles de ce site sont publiés
+ sous la licence Creative Commons Attribution 4.0 International (CC BY 4.0) par l'auteur.
+
+meta: Propulsé par :PLATFORM avec le thème :THEME
+
+not_found:
+ statement: Désolé, nous avons égaré cette URL ou elle pointe vers quelque chose qui n'existe pas.
+
+notification:
+ update_found: Une nouvelle version du contenu est disponible.
+ update: Mise à jour
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Par
+ posted: Posté
+ updated: Mis à jour
+ words: mots
+ pageview_measure: vues
+ read_time:
+ unit: min
+ prompt: lire
+ relate_posts: Autres lectures
+ share: Partager
+ button:
+ next: Plus récent
+ previous: Plus ancien
+ copy_code:
+ succeed: Copié !
+ share_link:
+ title: Copier le lien
+ succeed: Lien copié avec succès !
+
+# categories page
+categories:
+ category_measure: catégories
+ post_measure: posts
diff --git a/src/data/locales/hu-HU.yml b/src/data/locales/hu-HU.yml
new file mode 100644
index 00000000000..be3a31b7d63
--- /dev/null
+++ b/src/data/locales/hu-HU.yml
@@ -0,0 +1,92 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Bejegyzés
+ category: Kategória
+ tag: Címke
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Kezdőlap
+ categories: Kategóriák
+ tags: Címkék
+ archives: Archívum
+ about: Bemutatkozás
+
+# the text displayed in the search bar & search results
+search:
+ hint: keresés
+ cancel: Mégse
+ no_results: Hoppá! Nincs találat a keresésre.
+
+panel:
+ lastmod: Legutóbb frissítve
+ trending_tags: Népszerű Címkék
+ toc: Tartalom
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: A bejegyzést a szerző :LICENSE_NAME licenc alatt engedélyezte.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Néhány jog fenntartva.
+ verbose: >-
+ Az oldalon található tartalmak
+ Creative Commons Attribution 4.0 International (CC BY 4.0) licenccel rendelkeznek,
+ hacsak másképp nincs jelezve.
+
+meta: Készítve :THEME témával a :PLATFORM platformra.
+
+not_found:
+ statement: Sajnáljuk, az URL-t rosszul helyeztük el, vagy valami nem létezőre mutat.
+
+notification:
+ update_found: Elérhető a tartalom új verziója.
+ update: Frissítés
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Szerző
+ posted: Létrehozva
+ updated: Frissítve
+ words: szó
+ pageview_measure: látogató
+ read_time:
+ unit: perc
+ prompt: elolvasni
+ relate_posts: További olvasnivaló
+ share: Megosztás
+ button:
+ next: Újabb
+ previous: Régebbi
+ copy_code:
+ succeed: Másolva!
+ share_link:
+ title: Link másolása
+ succeed: Link sikeresen másolva!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%Y. %B. %e."
+ dayjs: "YYYY. MMMM D."
+ archives:
+ strftime: "%B"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure:
+ singular: kategória
+ plural: kategória
+ post_measure:
+ singular: bejegyzés
+ plural: bejegyzés
diff --git a/src/data/locales/id-ID.yml b/src/data/locales/id-ID.yml
new file mode 100644
index 00000000000..d772ec34f1a
--- /dev/null
+++ b/src/data/locales/id-ID.yml
@@ -0,0 +1,77 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Postingan
+ category: Kategori
+ tag: Tagar
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Beranda
+ categories: Kategori
+ tags: Tagar
+ archives: Arsip
+ about: Tentang
+
+# the text displayed in the search bar & search results
+search:
+ hint: Cari
+ cancel: Batal
+ no_results: Ups! Tidak ada hasil yang ditemukan.
+
+panel:
+ lastmod: Postingan Terbaru
+ trending_tags: Tagar Terpopuler
+ toc: Konten
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Postingan ini dilisensikan di bawah :LICENSE_NAME oleh penulis.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Sebagian konten dilindungi.
+ verbose: >-
+ Kecuali jika dinyatakan, Postingan blog di situs ini dilisensikan
+ di bawah Lisensi Creative Commons Attribution 4.0 International (CC BY 4.0) oleh penulis.
+
+meta: Didukung oleh :PLATFORM dengan tema :THEME
+
+not_found:
+ statement: Maaf, kami gagal menemukan URL itu atau memang mengarah ke sesuatu yang tidak ada.
+
+notification:
+ update_found: Versi konten baru tersedia.
+ update: Perbarui
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Oleh
+ posted: Diterbitkan
+ updated: Diperbarui
+ words: kata
+ pageview_measure: dilihat
+ read_time:
+ unit: menit
+ prompt: baca
+ relate_posts: Postingan Lainya
+ share: Bagikan
+ button:
+ next: Terbaru
+ previous: Terlama
+ copy_code:
+ succeed: Disalin!
+ share_link:
+ title: Salin tautan
+ succeed: Tautan berhasil disalin!
+
+# categories page
+categories:
+ category_measure: kategori
+ post_measure: Postingan
diff --git a/src/data/locales/it-IT.yml b/src/data/locales/it-IT.yml
new file mode 100644
index 00000000000..c8dfb447c2c
--- /dev/null
+++ b/src/data/locales/it-IT.yml
@@ -0,0 +1,90 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Post
+ category: Categoria
+ tag: Tag
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Pagina principale
+ categories: Categorie
+ tags: Tags
+ archives: Archivio
+ about: Informazioni
+
+# the text displayed in the search bar & search results
+search:
+ hint: ricerca
+ cancel: Cancella
+ no_results: Oops! La ricerca non ha fornito risultati.
+
+panel:
+ lastmod: Aggiornati recentemente
+ trending_tags: Tags più cliccati
+ toc: Contenuti
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Questo post è sotto licenza :LICENSE_NAME a nome dell'autore.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Alcuni diritti riservati.
+ verbose: >-
+ Eccetto quando esplicitamente menzionato, i post di questo blog sono da ritenersi sotto
+ i termini di licenza Creative Commons Attribution 4.0 International (CC BY 4.0).
+
+meta: Servizio offerto da :PLATFORM con tema :THEME
+not_found:
+ statement: Ci scusiamo, non è stato possibile trovare l'URL in questione. Potrebbe puntare ad una pagina non esistente.
+
+notification:
+ update_found: Nuova versione del contenuto disponibile.
+ update: Aggiornamento
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Da
+ posted: Postato
+ updated: Aggiornato
+ words: parole
+ pageview_measure: visioni
+ read_time:
+ unit: min
+ prompt: lettura
+ relate_posts: Continua a leggere
+ share: Condividi
+ button:
+ next: Più recenti
+ previous: Meno recenti
+ copy_code:
+ succeed: Copiato!
+ share_link:
+ title: Copia link
+ succeed: Link copiato con successo!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure:
+ singular: categoria
+ plural: categorie
+ post_measure:
+ singular: post
+ plural: posts
diff --git a/src/data/locales/ja-JP.yml b/src/data/locales/ja-JP.yml
new file mode 100644
index 00000000000..8e016b997c4
--- /dev/null
+++ b/src/data/locales/ja-JP.yml
@@ -0,0 +1,84 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: 投稿
+ category: カテゴリー
+ tag: タグ
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: ホーム
+ categories: カテゴリー
+ tags: タグ
+ archives: アーカイブ
+ about: このサイトについて
+
+# the text displayed in the search bar & search results
+search:
+ hint: 検索
+ cancel: キャンセル
+ no_results: 該当なし
+
+panel:
+ lastmod: 最近更新された投稿
+ trending_tags: トレンドのタグ
+ toc: コンテンツ
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: この投稿は投稿者によって :LICENSE_NAME の下でライセンスされています。
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Some rights reserved.
+ verbose: >-
+ Except where otherwise noted, the blog posts on this site are licensed
+ under the Creative Commons Attribution 4.0 International (CC BY 4.0) License by the author.
+
+meta: :PLATFORM 用の :THEME を使用しています。
+
+not_found:
+ statement: このURLは存在しないものを指し示しています。
+
+notification:
+ update_found: 新しいバージョンが利用可能です。
+ update: 更新
+
+# ----- Posts related labels -----
+
+post:
+ written_by: 投稿者
+ posted: 投稿日
+ updated: 更新日
+ words: 語
+ pageview_measure: 回閲覧
+ read_time:
+ unit: 分
+ prompt: で読めます
+ relate_posts: さらに読む
+ share: シェア
+ button:
+ next: 次
+ previous: 前
+ copy_code:
+ succeed: コピーしました
+ share_link:
+ title: リンクをコピー
+ succeed: リンクをコピーしました
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%Y/%m/%d"
+ dayjs: "YYYY/MM/DD"
+
+# categories page
+categories:
+ category_measure: カテゴリー
+ post_measure: 投稿
diff --git a/src/data/locales/ko-KR.yml b/src/data/locales/ko-KR.yml
new file mode 100644
index 00000000000..82976349c88
--- /dev/null
+++ b/src/data/locales/ko-KR.yml
@@ -0,0 +1,84 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: 포스트
+ category: 카테고리
+ tag: 태그
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: 홈
+ categories: 카테고리
+ tags: 태그
+ archives: 아카이브
+ about: 정보
+
+# the text displayed in the search bar & search results
+search:
+ hint: 검색
+ cancel: 취소
+ no_results: 검색 결과가 없습니다.
+
+panel:
+ lastmod: 최근 업데이트
+ trending_tags: 인기 태그
+ toc: 바로가기
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: 이 기사는 저작권자의 :LICENSE_NAME 라이센스를 따릅니다.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: 일부 권리 보유
+ verbose: >-
+ 명시되지 않는 한 이 사이트의 블로그 게시물은 작성자의
+ Creative Commons Attribution 4.0 International(CC BY 4.0) 라이선스에 따라 사용이 허가되었습니다.
+
+meta: Powered by :PLATFORM with :THEME theme
+
+not_found:
+ statement: 해당 URL은 존재하지 않습니다.
+
+notification:
+ update_found: 새 버전의 콘텐츠를 사용할 수 있습니다.
+ update: 업데이트
+
+# ----- Posts related labels -----
+
+post:
+ written_by: By
+ posted: 게시
+ updated: 업데이트
+ words: 단어
+ pageview_measure: 조회
+ read_time:
+ unit: 분
+ prompt: 읽는 시간
+ relate_posts: 관련된 글
+ share: 공유하기
+ button:
+ next: 다음 글
+ previous: 이전 글
+ copy_code:
+ succeed: 복사되었습니다!
+ share_link:
+ title: 링크 복사하기
+ succeed: 링크가 복사되었습니다!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%Y/%m/%d"
+ dayjs: "YYYY/MM/DD"
+
+# categories page
+categories:
+ category_measure: 카테고리
+ post_measure: 포스트
diff --git a/src/data/locales/ku-IQ.yml b/src/data/locales/ku-IQ.yml
new file mode 100644
index 00000000000..bcc53565f92
--- /dev/null
+++ b/src/data/locales/ku-IQ.yml
@@ -0,0 +1,91 @@
+# The layout text of site in Kurdish (Sorani)
+
+# ----- Commons label -----
+
+layout:
+ post: بابەت
+ category: هاوپۆل
+ tag: تاگ
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: سەرەکی
+ categories: هاوپۆلەکان
+ tags: تاگەکان
+ archives: ئەرشیف
+ about: دەربارە
+
+# the text displayed in the search bar & search results
+search:
+ hint: گەڕان
+ cancel: هەڵوەشاندنەوە
+ no_results: ببوورە! هیچ ئەنجامێک نەدۆزرایەوە.
+
+panel:
+ lastmod: دوایین نوێکردنەوەکان
+ trending_tags: تاگە باوەکان
+ toc: ناوەڕۆک
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: ئەم بابەتە لەلایەن نووسەرەوە بە مۆڵەتی :LICENSE_NAME بڵاوکراوەتەوە.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: هەندێک مافی پارێزراوە.
+ verbose: >-
+ تەنها لەو شوێنانەی کە بە پێچەوانەوە ئاماژەی پێدراوە، بابەتەکانی بڵۆگ لەم سایتەدا
+ لەژێر مۆڵەتی Creative Commons Attribution 4.0 International (CC BY 4.0) لەلایەن نووسەرەوە مۆڵەتیان پێدراوە.
+
+meta: بە بەکارهێنانی :PLATFORM لەگەڵ ڕووکاری :THEME
+
+not_found:
+ statement: ببوورە، ئەم بەستەرە نادۆزرێتەوە یان ئاماژە بە شتێک دەکات کە بوونی نییە.
+
+notification:
+ update_found: وەشانێکی نوێی ناوەڕۆک بەردەستە.
+ update: نوێکردنەوە
+
+# ----- Posts related labels -----
+
+post:
+ written_by: نووسەر
+ posted: بڵاوکراوەتەوە
+ updated: نوێکراوەتەوە
+ words: وشە
+ pageview_measure: بینین
+ read_time:
+ unit: خولەک
+ prompt: خوێندنەوە
+ relate_posts: بابەتی پەیوەندیدار
+ share: بڵاوکردنەوە
+ button:
+ next: نوێتر
+ previous: کۆنتر
+ copy_code:
+ succeed: کۆپی کرا!
+ share_link:
+ title: کۆپی بەستەر
+ succeed: بەستەر بە سەرکەوتوویی کۆپی کرا!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%d %b, %Y"
+ dayjs: "DD MMM, YYYY"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure:
+ singular: هاوپۆل
+ plural: هاوپۆل
+ post_measure:
+ singular: بابەت
+ plural: بابەت
diff --git a/src/data/locales/my-MM.yml b/src/data/locales/my-MM.yml
new file mode 100644
index 00000000000..d5bf728f9a9
--- /dev/null
+++ b/src/data/locales/my-MM.yml
@@ -0,0 +1,77 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: ပို့စ်
+ category: ကဏ္ဍ
+ tag: နာမ(တက်ဂ်)
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: အဓိကစာမျက်နှာ
+ categories: ကဏ္ဍများ
+ tags: နာမ(တက်ဂ်)များ
+ archives: မှတ်တမ်းတိုက်
+ about: အကြောင်းအရာ
+
+# the text displayed in the search bar & search results
+search:
+ hint: ရှာဖွေမည်
+ cancel: ဖျက်သိမ်းမည်
+ no_results: အိုး! ဘာမှမရှိပါ
+
+panel:
+ lastmod: မကြာသေးမီကမွမ်းမံထားသည်
+ trending_tags: ခေတ်စားနေသည့်တက်ဂ်များ
+ toc: အကြောင်းအရာများ
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: ဤပို့စ်သည်စာရေးသူ၏ :LICENSE_NAME လိုင်စင်ရထားသည်။
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: မူပိုင်ခွင့်အချို့ကို လက်ဝယ်ထားသည်။
+ verbose: >-
+ အခြားမှတ်သားထားချက်များမှလွဲ၍ ဤဆိုက်ရှိ ဘလော့ဂ်ပို့စ်များသည် စာရေးသူ၏
+ Creative Commons Attribution 4.0 International (CC BY 4.0) အောက်တွင် လိုင်စင်ရထားပါသည်။
+
+meta: Powered by :PLATFORM with :THEME theme
+
+not_found:
+ statement: ဝမ်းနည်းပါသည်၊ ကျွန်ုပ်တို့သည် အဆိုပါ URL ကို မှားယွင်းစွာ နေရာချထားခြင်း သို့မဟုတ် ၎င်းသည် မရှိသောအရာကို ညွှန်ပြနေပါသည်။
+
+notification:
+ update_found: အကြောင်းအရာဗားရှင်းအသစ်ကို ရနိုင်ပါပြီ။
+ update: အပ်ဒိတ်
+
+# ----- Posts related labels -----
+
+post:
+ written_by: ကရေးသားခဲ့သည်။
+ posted: တင်ထားခဲ့သည်။
+ updated: မွမ်းမံထားခဲ့သည်။
+ words: စကားလုံးများ
+ pageview_measure: အမြင်များ
+ read_time:
+ unit: မိနစ်
+ prompt: ဖတ်ပါမည်
+ relate_posts: နောက်ထပ်ဖတ်ရန်
+ share: မျှဝေရန်
+ button:
+ next: အသစ်များ
+ previous: အဟောင်းများ
+ copy_code:
+ succeed: ကူးယူလိုက်ပြီ။
+ share_link:
+ title: လင့်ခ်ကို ကူးယူရန်
+ succeed: လင့်ခ်ကို ကူးယူလိုက်ပြီ။
+
+# categories page
+categories:
+ category_measure: ကဏ္ဍများ
+ post_measure: ပို့စ်များ
diff --git a/src/data/locales/nl-NL.yml b/src/data/locales/nl-NL.yml
new file mode 100644
index 00000000000..d7e8016d00d
--- /dev/null
+++ b/src/data/locales/nl-NL.yml
@@ -0,0 +1,90 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Post
+ category: Categorie
+ tag: Tag
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Startpagina
+ categories: Categorieën
+ tags: Tags
+ archives: Archief
+ about: Over
+
+# the text displayed in the search bar & search results
+search:
+ hint: Zoek
+ cancel: Annuleer
+ no_results: Oops! Geen resultaat gevonden.
+
+panel:
+ lastmod: Recent Bijgewerkt
+ trending_tags: Trending Tags
+ toc: Inhoud
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Alle posts zijn onder :LICENSE_NAME gepubliceerd door de auteur.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Sommige rechten voorbehouden.
+ verbose: >-
+ Tenzij anders vermeld, alle posts zijn onder de
+ Creative Commons Attribution 4.0 International (CC BY 4.0) gepubliceerd door de auteur.
+
+meta: Gebruikt :THEME
+
+not_found:
+ statement: Sorry, we hebben de URL verkeerd geplaatst of hij verwijst naar iets dat niet bestaat.
+
+notification:
+ update_found: Nieuwe versie van inhoud beschikbaar.
+ update: Update
+
+# ----- Posts related labels -----
+post:
+ written_by: Door
+ posted: Posted
+ updated: Bijgewerkt
+ words: woorden
+ pageview_measure: Gelezen
+ read_time:
+ unit: min
+ prompt: lees
+ relate_posts: Verder Lezen
+ share: Deel
+ button:
+ next: Volgende
+ previous: Vorige
+ copy_code:
+ succeed: Gekopieerd!
+ share_link:
+ title: Link kopiëren
+ succeed: Succesvol gekopieerd!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure:
+ singular: categorie
+ plural: categorieën
+ post_measure:
+ singular: post
+ plural: posts
diff --git "a/src/data/locales/ps\342\200\221AF.yml" "b/src/data/locales/ps\342\200\221AF.yml"
new file mode 100644
index 00000000000..fca6877238c
--- /dev/null
+++ "b/src/data/locales/ps\342\200\221AF.yml"
@@ -0,0 +1,90 @@
+# The layout text of site in Pashto (Afghanistan)
+
+# ----- Commons label -----
+
+layout:
+ post: لیکنه
+ category: وېشنيزه
+ tag: ټګ
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: کورپاڼه
+ categories: وېشنيزې
+ tags: ټګونه
+ archives: آرشيف
+ about: په اړه
+
+# the text displayed in the search bar & search results
+search:
+ hint: لټون
+ cancel: لغوه
+ no_results: ها! هېڅ پایله ونه موندل شوه.
+
+panel:
+ lastmod: وروستی تازه
+ trending_tags: مشهور ټګونه
+ toc: منځپانګه
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: دا لیکنه د :LICENSE_NAME جواز لاندې د لیکوال له خوا خپره شوې ده.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: ځینې حقونه خوندي دي.
+ verbose: >-
+ تر هغه ځایه چې بل ډول نه وي یاد شوي، د دې سایټ لیکنې
+ د لیکوال له خوا د کریټېو کامنز د انتساب 4.0 نړیوال (CC BY 4.0) جواز لاندې خپرېږي.
+
+meta: د :PLATFORM لپاره د :THEME موضوع کاروي.
+
+not_found:
+ statement: بښنه غواړو، دغه URL ناسم دی یا هغه څه ته اشاره کوي چې شتون نه لري.
+
+notification:
+ update_found: نوې نسخه شتون لري.
+ update: تازه
+
+# ----- Posts related labels -----
+
+post:
+ written_by: لیکوال
+ posted: خپره شوې
+ updated: تازه شوې
+ words: کلمې
+ pageview_measure: کتنې
+ read_time:
+ unit: دقیقې
+ prompt: لوستل
+ relate_posts: نوره لوستنه
+ share: شریکول
+ button:
+ next: نوی
+ previous: زوړ
+ copy_code:
+ succeed: کاپي شو!
+ share_link:
+ title: لینک کاپي کړئ
+ succeed: لینک بریالي کاپي شو!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+categories:
+ category_measure:
+ singular: وېشنيزه
+ plural: وېشنيزې
+ post_measure:
+ singular: لیکنه
+ plural: لیکنې
diff --git a/src/data/locales/pt-BR.yml b/src/data/locales/pt-BR.yml
new file mode 100644
index 00000000000..7ca60a74b31
--- /dev/null
+++ b/src/data/locales/pt-BR.yml
@@ -0,0 +1,77 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Post
+ category: Categoria
+ tag: Tag
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Home
+ categories: Categorias
+ tags: Tags
+ archives: Arquivos
+ about: Sobre
+
+# the text displayed in the search bar & search results
+search:
+ hint: Buscar
+ cancel: Cancelar
+ no_results: Oops! Nenhum resultado encontrado.
+
+panel:
+ lastmod: Atualizados recentemente
+ trending_tags: Trending Tags
+ toc: Conteúdo
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Esta postagem está licenciada sob :LICENSE_NAME pelo autor.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Alguns direitos reservados.
+ verbose: >-
+ Exceto onde indicado de outra forma, as postagens do blog neste site são licenciadas sob a
+ Creative Commons Attribution 4.0 International (CC BY 4.0) License pelo autor.
+
+meta: Feito com :PLATFORM usando o tema :THEME
+
+not_found:
+ statement: Desculpe, a página não foi encontrada.
+
+notification:
+ update_found: Uma nova versão do conteúdo está disponível.
+ update: atualização
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Por
+ posted: Postado em
+ updated: Atualizado
+ words: palavras
+ pageview_measure: visualizações
+ read_time:
+ unit: min
+ prompt: " de leitura"
+ relate_posts: Leia também
+ share: Compartilhar
+ button:
+ next: Próximo
+ previous: Anterior
+ copy_code:
+ succeed: Copiado!
+ share_link:
+ title: Copie o link
+ succeed: Link copiado com sucesso!
+
+# categories page
+categories:
+ category_measure: categorias
+ post_measure: posts
diff --git a/src/data/locales/ru-RU.yml b/src/data/locales/ru-RU.yml
new file mode 100644
index 00000000000..868ba95787f
--- /dev/null
+++ b/src/data/locales/ru-RU.yml
@@ -0,0 +1,87 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Пост
+ category: Категория
+ tag: Тег
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Главная
+ categories: Категории
+ tags: Теги
+ archives: Архив
+ about: О сайте
+
+# the text displayed in the search bar & search results
+search:
+ hint: поиск
+ cancel: Отмена
+ no_results: Упс! Ничего не найдено.
+
+panel:
+ lastmod: Недавно обновлено
+ trending_tags: Популярные теги
+ toc: Содержание
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Авторский пост защищен лицензией :LICENSE_NAME.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Некоторые права защищены.
+ verbose: >-
+ Если не указано иное, авторские посты на этом сайте защищены лицензией Creative Commons Attribution 4.0 International (CC BY 4.0).
+
+meta: Использует тему :THEME для :PLATFORM
+
+not_found:
+ statement: Извините, мы перепутали URL-адрес или он указывает на что-то несуществующее.
+
+notification:
+ update_found: Доступна новая версия контента.
+ update: Обновить
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Автор
+ posted: Опубликовано
+ updated: Обновлено
+ words: слов
+ pageview_measure: просмотров
+ read_time:
+ unit: мин.
+ prompt: чтения
+ relate_posts: Похожие посты
+ share: Поделиться
+ button:
+ next: Следующий пост
+ previous: Предыдущий пост
+ copy_code:
+ succeed: Скопировано!
+ share_link:
+ title: Скопировать ссылку
+ succeed: Ссылка успешно скопирована!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%d.%m.%Y"
+ dayjs: "DD.MM.YYYY"
+
+# categories page
+categories:
+ category_measure:
+ singular: категория
+ plural: категории
+ post_measure:
+ singular: пост
+ plural: посты
diff --git a/src/data/locales/sl-SI.yml b/src/data/locales/sl-SI.yml
new file mode 100644
index 00000000000..4d9434d4436
--- /dev/null
+++ b/src/data/locales/sl-SI.yml
@@ -0,0 +1,91 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Objava #Post
+ category: Kategorija #Category
+ tag: Oznaka #Tag
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Domov #Home
+ categories: Kategorije #Categories
+ tags: Oznake #Tags
+ archives: Arhiv #Archives
+ about: O meni #About
+
+# the text displayed in the search bar & search results
+search:
+ hint: išči #search
+ cancel: Prekliči #Cancel
+ no_results: Ups! Vsebina ni bila najdena #Oops! No results found.
+
+panel:
+ lastmod: Nedavno Posodobljeno #Recently Updated
+ trending_tags: Priljubljene Oznake #Trending Tags
+ toc: Vsebina #Contents
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Ta objava je licencirana pod :LICENCE_NAME s strani avtorja. #This post is licensed under :LICENSE_NAME by the author.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Nekatere pravice pridržane. #Some rights reserved.
+ verbose: >-
+ Razen kjer navedeno drugače, vse objave spletnega dnevnika so licencirane
+ pod Creative Commons Attribution 4.0 International (CC BY 4.0) s strani avtorja.
+
+meta: Uporabljena :PLATFORM tema :THEME #Using the :PLATFORM theme :THEME
+
+not_found:
+ statement: Oprostite, hiperpovezava je neustrezna ali vsebina ne obstajata. #Sorry, we've misplaced that URL or it's pointing to something that doesn't exist.
+
+notification:
+ update_found: Novejša različica vsebine je na voljo. #A new version of content is available.
+ update: Posodobi #Update
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Od #By
+ posted: Objavljeno #Posted
+ updated: Posodobljeno #Updated
+ words: besede #words
+ pageview_measure: ogledi #views
+ read_time:
+ unit: min
+ prompt: beri #read
+ relate_posts: Nadaljnje branje #Further Reading
+ share: Deli #Share
+ button:
+ next: Novejše #Newer
+ previous: Starejše #Older
+ copy_code:
+ succeed: Kopirano! #Copied!
+ share_link:
+ title: Kopiraj povezavo #Copy link
+ succeed: Povezava uspešno kopirana! #Link copied successfully!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%e %b, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure:
+ singular: kategorija #category
+ plural: kategorije #categories
+ post_measure:
+ singular: objava #post
+ plural: objave #posts
diff --git a/src/data/locales/sv-SE.yml b/src/data/locales/sv-SE.yml
new file mode 100644
index 00000000000..decb59cf31f
--- /dev/null
+++ b/src/data/locales/sv-SE.yml
@@ -0,0 +1,91 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Inlägg #Post
+ category: Kategori #Category
+ tag: Tagga #Tag
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Hem #Home
+ categories: Kategorier #Categories
+ tags: Taggar #Tags
+ archives: Arkiv #Archives
+ about: Om #About
+
+# the text displayed in the search bar & search results
+search:
+ hint: sök
+ cancel: Avbryt
+ no_results: Hoppsan! Hittade inga sökträffar.
+
+panel:
+ lastmod: Senast uppdaterad
+ trending_tags: Trendande taggar
+ toc: Innehåll
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Den här posten är publicerad under licensen :LICENSE_NAME av författaren.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Vissa rättigheter är reserverade.
+ verbose: >-
+ Om inte annat anges är blogginläggen på denna webbplats licensierade
+ under Creative Commons Attribution 4.0 International (CC BY 4.0) av författaren.
+
+meta: Byggd med :PLATFORM och temat :THEME
+
+not_found:
+ statement: Ursäkta, vi har tappat bort den här webbadressen eller så pekar den på något som inte längre finns.
+
+notification:
+ update_found: Det finns en ny version av innehållet.
+ update: Uppdatera sidan
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Av
+ posted: Postad
+ updated: Uppdaterad
+ words: ord
+ pageview_measure: visningar
+ read_time:
+ unit: min
+ prompt: läsning
+ relate_posts: Mer läsning
+ share: Dela
+ button:
+ next: Nyare
+ previous: Äldre
+ copy_code:
+ succeed: Kopierat!
+ share_link:
+ title: Kopiera länk
+ succeed: Länken har kopierats!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure:
+ singular: kategori
+ plural: kategorier
+ post_measure:
+ singular: inlägg
+ plural: inlägg
diff --git a/src/data/locales/th.yml b/src/data/locales/th.yml
new file mode 100644
index 00000000000..a3f41a0e16e
--- /dev/null
+++ b/src/data/locales/th.yml
@@ -0,0 +1,91 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: โพสต์
+ category: หมวดหมู่
+ tag: แท็ก
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: หน้าแรก
+ categories: หมวดหมู่
+ tags: แท็ก
+ archives: คลังเก็บ
+ about: เกี่ยวกับ
+
+# the text displayed in the search bar & search results
+search:
+ hint: ค้นหา
+ cancel: ยกเลิก
+ no_results: โอ๊ะ! ไม่พบผลลัพธ์
+
+panel:
+ lastmod: อัปเดตล่าสุด
+ trending_tags: แท็กยอดนิยม
+ toc: เนื้อหา
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: โพสต์นี้อยู่ภายใต้การอนุญาต :LICENSE_NAME โดยผู้เขียน
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: สงวนลิขสิทธิ์เป็นบางส่วน
+ verbose: >-
+ เว้นแต่ว่าจะระบุเป็นอย่างอื่น โพสต์บนเว็บไซต์นี้อยู่ภายใต้
+ สัญญาอนุญาตครีเอทีฟคอมมอนส์แบบ 4.0 นานาชาติ (CC BY 4.0) โดยผู้เขียน
+
+meta: กำลังใช้ธีมของ :PLATFORM ชื่อ :THEME
+
+not_found:
+ statement: ขออภัย เราวาง URL นั้นไว้ผิดที่ หรือมันชี้ไปยังสิ่งที่ไม่มีอยู่
+
+notification:
+ update_found: มีเวอร์ชันใหม่ของเนื้อหา
+ update: อัปเดต
+
+# ----- Posts related labels -----
+
+post:
+ written_by: โดย
+ posted: โพสต์เมื่อ
+ updated: อัปเดตเมื่อ
+ words: คำ
+ pageview_measure: ครั้ง
+ read_time:
+ unit: นาที
+ prompt: อ่าน
+ relate_posts: อ่านต่อ
+ share: แชร์
+ button:
+ next: ใหม่กว่า
+ previous: เก่ากว่า
+ copy_code:
+ succeed: คัดลอกแล้ว!
+ share_link:
+ title: คัดลอกลิงก์
+ succeed: คัดลอกลิงก์เรียบร้อยแล้ว!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+# categories page
+categories:
+ category_measure:
+ singular: หมวดหมู่
+ plural: หมวดหมู่
+ post_measure:
+ singular: โพสต์
+ plural: โพสต์
diff --git a/src/data/locales/tr-TR.yml b/src/data/locales/tr-TR.yml
new file mode 100644
index 00000000000..768f57cd1c6
--- /dev/null
+++ b/src/data/locales/tr-TR.yml
@@ -0,0 +1,77 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Gönderi
+ category: Kategori
+ tag: Etiket
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Ana Sayfa
+ categories: Kategoriler
+ tags: Etiketler
+ archives: Arşiv
+ about: Hakkında
+
+# the text displayed in the search bar & search results
+search:
+ hint: Ara...
+ cancel: İptal
+ no_results: Hop! Öyle bir şey bulamadım.
+
+panel:
+ lastmod: Son Güncellenenler
+ trending_tags: Yükselen Etiketler
+ toc: İçindekiler
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Bu gönderi :LICENSE_NAME lisansı altındadır.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/deed.tr
+
+ # Displayed in the footer
+ brief: Bazı hakları saklıdır.
+ verbose: >-
+ Aksi belirtilmediği sürece, bu sitedeki gönderiler Creative Commons Atıf 4.0 Uluslararası (CC BY 4.0) Lisansı altındadır.
+ Kısaca sayfa linkini vererek değiştirebilir / paylaşabilirsiniz.
+
+meta: :PLATFORM ve :THEME teması
+
+not_found:
+ statement: Üzgünüz, bu linki yanlış yerleştirdik veya var olmayan bir şeye işaret ediyor.
+
+notification:
+ update_found: İçeriğin yeni bir sürümü mevcut.
+ update: Güncelle
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Yazan
+ posted: Gönderim
+ updated: Güncelleme
+ words: sözcük
+ pageview_measure: görüntülenme
+ read_time:
+ unit: dakikada
+ prompt: okunabilir
+ relate_posts: Benzer Gönderiler
+ share: Paylaş
+ button:
+ next: İleri
+ previous: Geri
+ copy_code:
+ succeed: Kopyalandı.
+ share_link:
+ title: Linki kopyala
+ succeed: Link kopyalandı.
+
+# categories page
+categories:
+ category_measure: kategori
+ post_measure: gönderi
diff --git a/src/data/locales/uk-UA.yml b/src/data/locales/uk-UA.yml
new file mode 100644
index 00000000000..8fef52e8569
--- /dev/null
+++ b/src/data/locales/uk-UA.yml
@@ -0,0 +1,77 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Публікація
+ category: Категорія
+ tag: Тег
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Домашня сторінка
+ categories: Категорії
+ tags: Теги
+ archives: Архів
+ about: Про сайт
+
+# the text displayed in the search bar & search results
+search:
+ hint: пошук
+ cancel: Скасувати
+ no_results: Ох! Нічого не знайдено.
+
+panel:
+ lastmod: Нещодавно оновлено
+ trending_tags: Популярні теги
+ toc: Зміст
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Публікація захищена ліцензією :LICENSE_NAME.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Деякі права захищено.
+ verbose: >-
+ Публікації на сайті захищено ліцензією Creative Commons Attribution 4.0 International (CC BY 4.0),
+ якщо інше не вказано в тексті.
+
+meta: Powered by :PLATFORM with :THEME theme
+
+not_found:
+ statement: Вибачте, це посилання вказує на ресурс, що не існує.
+
+notification:
+ update_found: Доступна нова версія вмісту.
+ update: Оновлення
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Автор
+ posted: Час публікації
+ updated: Оновлено
+ words: слів
+ pageview_measure: переглядів
+ read_time:
+ unit: хвилин
+ prompt: читання
+ relate_posts: Вас також може зацікавити
+ share: Поділитися
+ button:
+ next: Попередня публікація
+ previous: Наступна публікація
+ copy_code:
+ succeed: Успішно скопійовано!
+ share_link:
+ title: Скопіювати посилання
+ succeed: Посилання успішно скопійовано!
+
+# categories page
+categories:
+ category_measure: категорії
+ post_measure: публікації
diff --git a/src/data/locales/ur-PK.yml b/src/data/locales/ur-PK.yml
new file mode 100644
index 00000000000..e5184df171c
--- /dev/null
+++ b/src/data/locales/ur-PK.yml
@@ -0,0 +1,90 @@
+# The layout text of site in Urdu (Pakistan)
+
+# ----- Commons label -----
+
+layout:
+ post: تحریر
+ category: زمرہ
+ tag: ٹیگ
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: گھر
+ categories: زمروں
+ tags: ٹیگز
+ archives: محفوظات
+ about: تعارف
+
+# the text displayed in the search bar & search results
+search:
+ hint: تلاش
+ cancel: منسوخ
+ no_results: اوہ! کوئی نتیجہ نہیں ملا۔
+
+panel:
+ lastmod: حال ہی میں اپ ڈیٹ
+ trending_tags: مقبول ٹیگز
+ toc: مواد
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: یہ تحریر :LICENSE_NAME کے تحت مصنف کی جانب سے لائسنس یافتہ ہے۔
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: کچھ حقوق محفوظ ہیں۔
+ verbose: >-
+ جب تک کہ دوسری صورت میں ذکر نہ ہو، اس سائٹ کی تحریریں
+ مصنف کی جانب سے تخلیقی العام انتساب 4.0 بین الاقوامی (CC BY 4.0) لائسنس کے تحت دستیاب ہیں۔
+
+meta: :PLATFORM کے لیے :THEME تھیم استعمال کیا جا رہا ہے۔
+
+not_found:
+ statement: معذرت، یہ URL غلط ہے یا جس چیز کی طرف اشارہ کر رہا ہے وہ موجود نہیں۔
+
+notification:
+ update_found: نیا مواد دستیاب ہے۔
+ update: اپ ڈیٹ
+
+# ----- Posts related labels -----
+
+post:
+ written_by: از
+ posted: شائع شدہ
+ updated: اپ ڈیٹ شدہ
+ words: لفظ
+ pageview_measure: مشاہدات
+ read_time:
+ unit: منٹ
+ prompt: پڑھیں
+ relate_posts: مزید مطالعہ
+ share: شیئر
+ button:
+ next: نیا
+ previous: پرانا
+ copy_code:
+ succeed: کاپی ہو گیا!
+ share_link:
+ title: لنک کاپی کریں
+ succeed: لنک کامیابی سے کاپی ہو گیا!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%b %e, %Y"
+ dayjs: "ll"
+ archives:
+ strftime: "%b"
+ dayjs: "MMM"
+
+categories:
+ category_measure:
+ singular: زمرہ
+ plural: زمروں
+ post_measure:
+ singular: تحریر
+ plural: تحریریں
diff --git a/src/data/locales/vi-VN.yml b/src/data/locales/vi-VN.yml
new file mode 100644
index 00000000000..6c2ceffde38
--- /dev/null
+++ b/src/data/locales/vi-VN.yml
@@ -0,0 +1,76 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: Bài viết
+ category: Danh mục
+ tag: Thẻ
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: Trang chủ
+ categories: Các danh mục
+ tags: Các thẻ
+ archives: Lưu trữ
+ about: Giới thiệu
+
+# the text displayed in the search bar & search results
+search:
+ hint: tìm kiếm
+ cancel: Hủy
+ no_results: Không có kết quả tìm kiếm.
+
+panel:
+ lastmod: Mới cập nhật
+ trending_tags: Các thẻ thịnh hành
+ toc: Mục lục
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: Bài viết này được cấp phép bởi tác giả theo giấy phép :LICENSE_NAME.
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: Một số quyền được bảo lưu.
+ verbose: >-
+ Trừ khi có ghi chú khác, các bài viết đăng trên trang này được cấp phép bởi tác giả theo giấy phép Creative Commons Attribution 4.0 International (CC BY 4.0).
+
+meta: Trang web này được tạo bởi :PLATFORM với chủ đề :THEME
+
+not_found:
+ statement: Xin lỗi, chúng tôi đã đặt nhầm URL hoặc đường dẫn trỏ đến một trang nào đó không tồn tại.
+
+notification:
+ update_found: Đã có phiên bản mới của nội dung.
+ update: Cập nhật
+
+# ----- Posts related labels -----
+
+post:
+ written_by: Viết bởi
+ posted: Đăng lúc
+ updated: Cập nhật lúc
+ words: từ
+ pageview_measure: lượt xem
+ read_time:
+ unit: phút
+ prompt: đọc
+ relate_posts: Bài viết liên quan
+ share: Chia sẻ
+ button:
+ next: Mới hơn
+ previous: Cũ hơn
+ copy_code:
+ succeed: Đã sao chép!
+ share_link:
+ title: Sao chép đường dẫn
+ succeed: Đã sao chép đường dẫn thành công!
+
+# categories page
+categories:
+ category_measure: danh mục
+ post_measure: bài viết
diff --git a/src/data/locales/zh-CN.yml b/src/data/locales/zh-CN.yml
new file mode 100644
index 00000000000..5c134101834
--- /dev/null
+++ b/src/data/locales/zh-CN.yml
@@ -0,0 +1,83 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: 文章
+ category: 分类
+ tag: 标签
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: 首页
+ categories: 分类
+ tags: 标签
+ archives: 归档
+ about: 关于
+
+# the text displayed in the search bar & search results
+search:
+ hint: 搜索
+ cancel: 取消
+ no_results: 搜索结果为空
+
+panel:
+ lastmod: 最近更新
+ trending_tags: 热门标签
+ toc: 文章内容
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: 本文由作者按照 :LICENSE_NAME 进行授权
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: 保留部分权利。
+ verbose: >-
+ 除非另有说明,本网站上的博客文章均由作者按照知识共享署名 4.0 国际 (CC BY 4.0) 许可协议进行授权。
+
+meta: 本站采用 :PLATFORM 主题 :THEME
+
+not_found:
+ statement: 抱歉,我们放错了该 URL,或者它指向了不存在的内容。
+
+notification:
+ update_found: 发现新版本的内容。
+ update: 更新
+
+# ----- Posts related labels -----
+
+post:
+ written_by: 作者
+ posted: 发表于
+ updated: 更新于
+ words: 字
+ pageview_measure: 次浏览
+ read_time:
+ unit: 分钟
+ prompt: 阅读
+ relate_posts: 相关文章
+ share: 分享
+ button:
+ next: 下一篇
+ previous: 上一篇
+ copy_code:
+ succeed: 已复制!
+ share_link:
+ title: 分享链接
+ succeed: 链接已复制!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%Y/%m/%d"
+ dayjs: "YYYY/MM/DD"
+
+# categories page
+categories:
+ category_measure: 个分类
+ post_measure: 篇文章
diff --git a/src/data/locales/zh-TW.yml b/src/data/locales/zh-TW.yml
new file mode 100644
index 00000000000..33a4330bb0f
--- /dev/null
+++ b/src/data/locales/zh-TW.yml
@@ -0,0 +1,83 @@
+# The layout text of site
+
+# ----- Commons label -----
+
+layout:
+ post: 文章
+ category: 分類
+ tag: 標籤
+
+# The tabs of sidebar
+tabs:
+ # format: :
+ home: 首頁
+ categories: 分類
+ tags: 標籤
+ archives: 封存
+ about: 關於
+
+# the text displayed in the search bar & search results
+search:
+ hint: 搜尋
+ cancel: 取消
+ no_results: 沒有搜尋結果
+
+panel:
+ lastmod: 最近更新
+ trending_tags: 熱門標籤
+ toc: 文章摘要
+
+copyright:
+ # Shown at the bottom of the post
+ license:
+ template: 本文章以 :LICENSE_NAME 授權
+ name: CC BY 4.0
+ link: https://creativecommons.org/licenses/by/4.0/
+
+ # Displayed in the footer
+ brief: 保留部份權利。
+ verbose: >-
+ 除非另有說明,否則本網誌的文章均由作者按照姓名標示 4.0 國際 (CC BY 4.0) 授權條款進行授權。
+
+meta: 本網站使用 :PLATFORM 產生,採用 :THEME 主題
+
+not_found:
+ statement: 抱歉,您可能正在存取一個已被移動的 URL,或者它從未存在。
+
+notification:
+ update_found: 發現新版本更新。
+ update: 更新
+
+# ----- Posts related labels -----
+
+post:
+ written_by: 作者
+ posted: 發布於
+ updated: 更新於
+ words: 字
+ pageview_measure: 次瀏覽
+ read_time:
+ unit: 分鐘
+ prompt: 閱讀
+ relate_posts: 相關文章
+ share: 分享
+ button:
+ next: 下一篇
+ previous: 上一篇
+ copy_code:
+ succeed: 已複製!
+ share_link:
+ title: 分享連結
+ succeed: 已複製連結!
+
+# Date time format.
+# See: ,
+df:
+ post:
+ strftime: "%Y/%m/%d"
+ dayjs: "YYYY/MM/DD"
+
+# categories page
+categories:
+ category_measure: 個分類
+ post_measure: 篇文章
diff --git a/src/data/media.yml b/src/data/media.yml
new file mode 100644
index 00000000000..9cd69b4ce95
--- /dev/null
+++ b/src/data/media.yml
@@ -0,0 +1,18 @@
+- extension: mp3
+ mime_type: mpeg
+- extension: mov
+ mime_type: quicktime
+- extension: avi
+ mime_type: x-msvideo
+- extension: mkv
+ mime_type: x-matroska
+- extension: ogv
+ mime_type: ogg
+- extension: weba
+ mime_type: webm
+- extension: 3gp
+ mime_type: 3gpp
+- extension: 3g2
+ mime_type: 3gpp2
+- extension: mid
+ mime_type: midi
diff --git a/src/data/origin/basic.yml b/src/data/origin/basic.yml
new file mode 100644
index 00000000000..2d5298229d3
--- /dev/null
+++ b/src/data/origin/basic.yml
@@ -0,0 +1,39 @@
+# fonts
+
+webfonts: /assets/lib/fonts/main.css
+
+# Libraries
+
+toc:
+ css: /assets/lib/tocbot/tocbot.min.css
+ js: /assets/lib/tocbot/tocbot.min.js
+
+fontawesome:
+ css: /assets/lib/fontawesome-free/css/all.min.css
+
+search:
+ js: /assets/lib/simple-jekyll-search/simple-jekyll-search.min.js
+
+mermaid:
+ js: /assets/lib/mermaid/mermaid.min.js
+
+dayjs:
+ js:
+ common: /assets/lib/dayjs/dayjs.min.js
+ locale: /assets/lib/dayjs/locale/en.js
+ relativeTime: /assets/lib/dayjs/plugin/relativeTime.js
+ localizedFormat: /assets/lib/dayjs/plugin/localizedFormat.js
+
+glightbox:
+ css: /assets/lib/glightbox/glightbox.min.css
+ js: /assets/lib/glightbox/glightbox.min.js
+
+lazy-polyfill:
+ css: /assets/lib/loading-attribute-polyfill/loading-attribute-polyfill.min.css
+ js: /assets/lib/loading-attribute-polyfill/loading-attribute-polyfill.umd.min.js
+
+clipboard:
+ js: /assets/lib/clipboard/clipboard.min.js
+
+mathjax:
+ js: /assets/lib/mathjax/tex-chtml.js
diff --git a/src/data/origin/cors.yml b/src/data/origin/cors.yml
new file mode 100644
index 00000000000..ce99f814109
--- /dev/null
+++ b/src/data/origin/cors.yml
@@ -0,0 +1,54 @@
+# Resource Hints
+resource_hints:
+ - url: https://fonts.googleapis.com
+ links:
+ - rel: preconnect
+ - rel: dns-prefetch
+ - url: https://fonts.gstatic.com
+ links:
+ - rel: preconnect
+ opts: [crossorigin]
+ - rel: dns-prefetch
+ - url: https://cdn.jsdelivr.net
+ links:
+ - rel: preconnect
+ - rel: dns-prefetch
+
+# Web Fonts
+webfonts: https://fonts.googleapis.com/css2?family=Lato:wght@300;400&family=Source+Sans+Pro:wght@400;600;700;900&display=swap
+
+# Libraries
+
+toc:
+ css: https://cdn.jsdelivr.net/npm/tocbot@4.36.4/dist/tocbot.min.css
+ js: https://cdn.jsdelivr.net/npm/tocbot@4.36.4/dist/tocbot.min.js
+
+fontawesome:
+ css: https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@7.1.0/css/all.min.css
+
+search:
+ js: https://cdn.jsdelivr.net/npm/simple-jekyll-search@1.10.0/dest/simple-jekyll-search.min.js
+
+mermaid:
+ js: https://cdn.jsdelivr.net/npm/mermaid@11.12.0/dist/mermaid.min.js
+
+dayjs:
+ js:
+ common: https://cdn.jsdelivr.net/npm/dayjs@1.11.18/dayjs.min.js
+ locale: https://cdn.jsdelivr.net/npm/dayjs@1.11.18/locale/:LOCALE.js
+ relativeTime: https://cdn.jsdelivr.net/npm/dayjs@1.11.18/plugin/relativeTime.js
+ localizedFormat: https://cdn.jsdelivr.net/npm/dayjs@1.11.18/plugin/localizedFormat.js
+
+glightbox:
+ css: https://cdn.jsdelivr.net/npm/glightbox@3.3.0/dist/css/glightbox.min.css
+ js: https://cdn.jsdelivr.net/npm/glightbox@3.3.0/dist/js/glightbox.min.js
+
+lazy-polyfill:
+ css: https://cdn.jsdelivr.net/npm/loading-attribute-polyfill@2.1.1/dist/loading-attribute-polyfill.min.css
+ js: https://cdn.jsdelivr.net/npm/loading-attribute-polyfill@2.1.1/dist/loading-attribute-polyfill.umd.min.js
+
+clipboard:
+ js: https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js
+
+mathjax:
+ js: https://cdn.jsdelivr.net/npm/mathjax@3.2.2/es5/tex-chtml.js
diff --git a/src/data/share.yml b/src/data/share.yml
new file mode 100644
index 00000000000..edbc02b26b0
--- /dev/null
+++ b/src/data/share.yml
@@ -0,0 +1,50 @@
+# Sharing options at the bottom of the post.
+# Icons from
+
+platforms:
+ - type: Twitter
+ icon: "fa-brands fa-square-x-twitter"
+ link: "https://twitter.com/intent/tweet?text=TITLE&url=URL"
+
+ - type: Facebook
+ icon: "fab fa-facebook-square"
+ link: "https://www.facebook.com/sharer/sharer.php?title=TITLE&u=URL"
+
+ - type: Telegram
+ icon: "fab fa-telegram"
+ link: "https://t.me/share/url?url=URL&text=TITLE"
+
+ # Uncomment below if you need to.
+ #
+ # - type: Linkedin
+ # icon: "fab fa-linkedin"
+ # link: "https://www.linkedin.com/feed/?shareActive=true&shareUrl=URL"
+ #
+ # - type: Weibo
+ # icon: "fab fa-weibo"
+ # link: "https://service.weibo.com/share/share.php?title=TITLE&url=URL"
+ #
+ # - type: Mastodon
+ # icon: "fa-brands fa-mastodon"
+ # # See: https://github.com/justinribeiro/share-to-mastodon#properties
+ # instances:
+ # - label: mastodon.social
+ # link: "https://mastodon.social/"
+ # - label: mastodon.online
+ # link: "https://mastodon.online/"
+ # - label: fosstodon.org
+ # link: "https://fosstodon.org/"
+ # - label: photog.social
+ # link: "https://photog.social/"
+ #
+ # - type: Bluesky
+ # icon: "fa-brands fa-bluesky"
+ # link: "https://bsky.app/intent/compose?text=TITLE%20URL"
+ #
+ # - type: Reddit
+ # icon: "fa-brands fa-square-reddit"
+ # link: "https://www.reddit.com/submit?url=URL&title=TITLE"
+ #
+ # - type: Threads
+ # icon: "fa-brands fa-square-threads"
+ # link: "https://www.threads.net/intent/post?text=TITLE%20URL"
diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro
new file mode 100644
index 00000000000..b6abe8bf933
--- /dev/null
+++ b/src/layouts/BaseLayout.astro
@@ -0,0 +1,99 @@
+---
+import { SITE, FEATURES } from '@/config';
+import Head from '@components/Head.astro';
+import Sidebar from '@components/Sidebar.astro';
+import Topbar from '@components/Topbar.astro';
+import Footer from '@components/Footer.astro';
+import SearchResults from '@components/SearchResults.astro';
+import UpdateList from '@components/UpdateList.astro';
+import TrendingTags from '@components/TrendingTags.astro';
+import '@styles/main.scss';
+
+export interface Props {
+ title?: string;
+ description?: string;
+ image?: string;
+ lang?: string;
+ panelIncludes?: string[];
+ tailIncludes?: string[];
+ refactorContent?: boolean;
+}
+
+const {
+ title,
+ description,
+ image,
+ lang = SITE.lang,
+ panelIncludes = [],
+ tailIncludes = [],
+ refactorContent = false
+} = Astro.props;
+
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {tailIncludes.map((include) => (
+
+
{include}
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {FEATURES.pwa.enabled && (
+
+
+ )}
+
+
+
+
diff --git a/src/layouts/PostLayout.astro b/src/layouts/PostLayout.astro
new file mode 100644
index 00000000000..d4744411ff7
--- /dev/null
+++ b/src/layouts/PostLayout.astro
@@ -0,0 +1,112 @@
+---
+import BaseLayout from './BaseLayout.astro';
+import type { CollectionEntry } from 'astro:content';
+import { SITE } from '@/config';
+
+export interface Props {
+ post: CollectionEntry<'posts'>;
+}
+
+const { post } = Astro.props;
+const { title, description, date, categories, tags, image, author } = post.data;
+
+const formattedDate = new Date(date).toLocaleDateString(SITE.lang, {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric'
+});
+---
+
+
+
+
+
+ {image?.path && (
+
+

+
+ )}
+
+
+
+
+
+ {tags && tags.length > 0 && (
+
+ )}
+
+
+
+
diff --git a/src/pages/[...slug].astro b/src/pages/[...slug].astro
new file mode 100644
index 00000000000..ca24e65e189
--- /dev/null
+++ b/src/pages/[...slug].astro
@@ -0,0 +1,34 @@
+---
+import { getCollection } from 'astro:content';
+import BaseLayout from '@layouts/BaseLayout.astro';
+
+export async function getStaticPaths() {
+ const tabs = await getCollection('tabs');
+ return tabs.map((tab) => ({
+ params: { slug: tab.slug },
+ props: { tab },
+ }));
+}
+
+const { tab } = Astro.props;
+const { Content } = await tab.render();
+---
+
+
+
+
{tab.data.title}
+
+
+
+
+
diff --git a/src/pages/index.astro b/src/pages/index.astro
new file mode 100644
index 00000000000..5305dfc443d
--- /dev/null
+++ b/src/pages/index.astro
@@ -0,0 +1,160 @@
+---
+import BaseLayout from '@layouts/BaseLayout.astro';
+import { getCollection } from 'astro:content';
+import { PAGINATION, SITE } from '@/config';
+
+// Get all posts
+const allPosts = await getCollection('posts');
+
+// Separate pinned and normal posts
+const pinnedPosts = allPosts.filter(post => post.data.pin && !post.data.hidden);
+const normalPosts = allPosts.filter(post => !post.data.pin && !post.data.hidden);
+
+// Sort by date (newest first)
+const sortByDate = (a: any, b: any) => {
+ return new Date(b.data.date).getTime() - new Date(a.data.date).getTime();
+};
+
+pinnedPosts.sort(sortByDate);
+normalPosts.sort(sortByDate);
+
+// Combine for first page (pinned first, then normal)
+const postsPerPage = PAGINATION.postsPerPage;
+const displayPosts = [...pinnedPosts, ...normalPosts].slice(0, postsPerPage);
+
+// Helper to get image URL
+const getImageUrl = (post: any) => {
+ const image = post.data.image;
+ if (!image) return null;
+
+ const src = image.path || image;
+ if (src.startsWith('http://') || src.startsWith('https://')) return src;
+ if (src.startsWith('/') && SITE.cdn) return `${SITE.cdn}${src}`;
+ return src;
+};
+
+// Format date
+const formatDate = (date: Date) => {
+ return new Date(date).toLocaleDateString(SITE.lang, {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric'
+ });
+};
+---
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/posts/[...slug].astro b/src/pages/posts/[...slug].astro
new file mode 100644
index 00000000000..f936c1a63e1
--- /dev/null
+++ b/src/pages/posts/[...slug].astro
@@ -0,0 +1,19 @@
+---
+import { getCollection } from 'astro:content';
+import PostLayout from '@layouts/PostLayout.astro';
+
+export async function getStaticPaths() {
+ const posts = await getCollection('posts');
+ return posts.map((post) => ({
+ params: { slug: post.slug },
+ props: { post },
+ }));
+}
+
+const { post } = Astro.props;
+const { Content } = await post.render();
+---
+
+
+
+
diff --git a/src/scripts/main.ts b/src/scripts/main.ts
new file mode 100644
index 00000000000..2c5bfed911a
--- /dev/null
+++ b/src/scripts/main.ts
@@ -0,0 +1,75 @@
+// Main application JavaScript
+import './theme';
+
+// Back to top button
+function initBackToTop() {
+ const backToTopBtn = document.getElementById('back-to-top');
+ if (!backToTopBtn) return;
+
+ const toggleVisibility = () => {
+ if (window.scrollY > 300) {
+ backToTopBtn.style.display = 'block';
+ } else {
+ backToTopBtn.style.display = 'none';
+ }
+ };
+
+ window.addEventListener('scroll', toggleVisibility);
+ toggleVisibility(); // Initial check
+
+ backToTopBtn.addEventListener('click', () => {
+ window.scrollTo({
+ top: 0,
+ behavior: 'smooth'
+ });
+ });
+}
+
+// Sidebar mobile toggle
+function initSidebar() {
+ const sidebar = document.getElementById('sidebar');
+ const mask = document.getElementById('mask');
+ const sidebarTrigger = document.getElementById('sidebar-trigger');
+
+ if (!sidebar || !mask || !sidebarTrigger) return;
+
+ sidebarTrigger.addEventListener('click', () => {
+ sidebar.classList.toggle('shown');
+ mask.classList.toggle('d-none');
+ });
+
+ mask.addEventListener('click', () => {
+ sidebar.classList.remove('shown');
+ mask.classList.add('d-none');
+ });
+}
+
+// Image lazy loading with fallback
+function initImageLoading() {
+ // Add loading error handlers
+ const images = document.querySelectorAll('img[loading="lazy"]');
+ images.forEach((img) => {
+ img.addEventListener('error', function(this: HTMLImageElement) {
+ this.style.display = 'none';
+ });
+ });
+}
+
+// Initialize on DOM ready
+if (typeof document !== 'undefined') {
+ document.addEventListener('DOMContentLoaded', () => {
+ initBackToTop();
+ initSidebar();
+ initImageLoading();
+ });
+
+ // Re-initialize on page navigation (for view transitions)
+ document.addEventListener('astro:after-swap', () => {
+ initBackToTop();
+ initSidebar();
+ initImageLoading();
+ });
+}
+
+// Export for use in other modules
+export { initBackToTop, initSidebar, initImageLoading };
diff --git a/src/scripts/theme.ts b/src/scripts/theme.ts
new file mode 100644
index 00000000000..5567d45b787
--- /dev/null
+++ b/src/scripts/theme.ts
@@ -0,0 +1,59 @@
+// Theme management
+export const THEME_KEY = 'theme';
+export const THEME_ATTR = 'data-mode';
+
+export type Theme = 'light' | 'dark';
+
+export function getThemePreference(): Theme {
+ const stored = localStorage.getItem(THEME_KEY);
+ if (stored === 'light' || stored === 'dark') {
+ return stored;
+ }
+
+ // Check system preference
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
+}
+
+export function setTheme(theme: Theme) {
+ document.documentElement.setAttribute(THEME_ATTR, theme);
+ localStorage.setItem(THEME_KEY, theme);
+
+ // Dispatch event for components that need to react to theme changes
+ window.dispatchEvent(new CustomEvent('themechange', { detail: { theme } }));
+}
+
+export function toggleTheme() {
+ const current = getThemePreference();
+ const next = current === 'light' ? 'dark' : 'light';
+ setTheme(next);
+ return next;
+}
+
+export function initTheme() {
+ const theme = getThemePreference();
+ document.documentElement.setAttribute(THEME_ATTR, theme);
+}
+
+// Initialize theme on page load
+if (typeof window !== 'undefined') {
+ // Apply theme immediately to prevent flash
+ initTheme();
+
+ // Setup theme toggle
+ document.addEventListener('DOMContentLoaded', () => {
+ const toggleBtn = document.getElementById('mode-toggle');
+ if (toggleBtn) {
+ toggleBtn.addEventListener('click', () => {
+ toggleTheme();
+ });
+ }
+ });
+
+ // Listen for system theme changes
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
+ // Only auto-switch if user hasn't set a preference
+ if (!localStorage.getItem(THEME_KEY)) {
+ setTheme(e.matches ? 'dark' : 'light');
+ }
+ });
+}
diff --git a/src/styles/abstracts/_breakpoints.scss b/src/styles/abstracts/_breakpoints.scss
new file mode 100644
index 00000000000..e40cefeee36
--- /dev/null
+++ b/src/styles/abstracts/_breakpoints.scss
@@ -0,0 +1,73 @@
+@use 'sass:map';
+
+$-breakpoints: (
+ // 1 column
+ sm: 576px,
+ md: 768px,
+ // 2 columns
+ lg: 850px,
+ // 3 columns
+ xl: 1200px,
+ xxl: 1400px,
+ xxxl: 1650px
+);
+
+@function get($breakpoint) {
+ @return map.get($-breakpoints, $breakpoint);
+}
+
+/* Less than the given width */
+@mixin lt($width) {
+ @media all and (max-width: calc(#{$width} - 1px)) {
+ @content;
+ }
+}
+
+/* Less than or equal to the given width */
+@mixin lte($width) {
+ @media all and (max-width: $width) {
+ @content;
+ }
+}
+
+@mixin sm {
+ @media all and (min-width: get(sm)) {
+ @content;
+ }
+}
+
+@mixin md {
+ @media all and (min-width: get(md)) {
+ @content;
+ }
+}
+
+@mixin lg {
+ @media all and (min-width: get(lg)) {
+ @content;
+ }
+}
+
+@mixin xl {
+ @media all and (min-width: get(xl)) {
+ @content;
+ }
+}
+
+@mixin xxl {
+ @media all and (min-width: get(xxl)) {
+ @content;
+ }
+}
+
+@mixin xxxl {
+ @media all and (min-width: get(xxxl)) {
+ @content;
+ }
+}
+
+@mixin between($min, $max) {
+ @media all and (min-width: $min) and (max-width: $max) {
+ @content;
+ }
+}
diff --git a/src/styles/abstracts/_index.scss b/src/styles/abstracts/_index.scss
new file mode 100644
index 00000000000..6c9e21cf46b
--- /dev/null
+++ b/src/styles/abstracts/_index.scss
@@ -0,0 +1,4 @@
+@forward 'variables';
+@forward 'mixins';
+@forward 'placeholders';
+@forward 'breakpoints';
diff --git a/src/styles/abstracts/_mixins.scss b/src/styles/abstracts/_mixins.scss
new file mode 100644
index 00000000000..c5eeee3cafc
--- /dev/null
+++ b/src/styles/abstracts/_mixins.scss
@@ -0,0 +1,80 @@
+@mixin text-ellipsis {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+@mixin mt-mb($value) {
+ margin-top: $value;
+ margin-bottom: $value;
+}
+
+@mixin ml-mr($value) {
+ margin-left: $value;
+ margin-right: $value;
+}
+
+@mixin pt-pb($val) {
+ padding-top: $val;
+ padding-bottom: $val;
+}
+
+@mixin pl-pr($val, $important: false) {
+ @if $important {
+ padding-left: $val !important;
+ padding-right: $val !important;
+ } @else {
+ padding-left: $val;
+ padding-right: $val;
+ }
+}
+
+@mixin placeholder {
+ color: var(--text-muted-color) !important;
+}
+
+@mixin placeholder-focus {
+ opacity: 0.6;
+}
+
+@mixin label($font-size: 1rem, $font-weight: 600, $color: var(--label-color)) {
+ color: $color;
+ font-size: $font-size;
+ font-weight: $font-weight;
+}
+
+@mixin align-center {
+ position: relative;
+ left: 50%;
+ transform: translateX(-50%);
+}
+
+@mixin prompt($type, $fa-content, $fa-style: 'solid', $rotate: 0) {
+ &.prompt-#{$type} {
+ background-color: var(--prompt-#{$type}-bg);
+
+ &::before {
+ content: $fa-content;
+ color: var(--prompt-#{$type}-icon-color);
+ font: var(--fa-font-#{$fa-style});
+
+ @if $rotate != 0 {
+ transform: rotate(#{$rotate}deg);
+ }
+ }
+ }
+}
+
+@mixin slide($append: null) {
+ $basic: transform 0.4s ease;
+
+ @if $append {
+ transition: $basic, $append;
+ } @else {
+ transition: $basic;
+ }
+}
+
+@mixin max-w-100 {
+ max-width: 100%;
+}
diff --git a/src/styles/abstracts/_placeholders.scss b/src/styles/abstracts/_placeholders.scss
new file mode 100644
index 00000000000..d8a10604620
--- /dev/null
+++ b/src/styles/abstracts/_placeholders.scss
@@ -0,0 +1,163 @@
+@use 'variables' as v;
+@use 'mixins' as mx;
+
+%heading {
+ color: var(--heading-color);
+ font-weight: 400;
+ font-family: v.$font-family-heading;
+ scroll-margin-top: 3.5rem;
+}
+
+%anchor {
+ .anchor {
+ font-size: 80%;
+ }
+
+ @media (hover: hover) {
+ .anchor {
+ visibility: hidden;
+ opacity: 0;
+ transition: opacity 0.25s ease-in, visibility 0s ease-in 0.25s;
+ }
+
+ &:hover {
+ .anchor {
+ visibility: visible;
+ opacity: 1;
+ transition: opacity 0.25s ease-in, visibility 0s ease-in 0s;
+ }
+ }
+ }
+}
+
+%tag-hover {
+ @extend %link-color;
+
+ background: var(--tag-hover);
+ border-color: var(--tag-hover);
+ transition: background 0.35s ease-in-out;
+}
+
+%table-cell {
+ padding: 0.4rem 1rem;
+ font-size: 95%;
+ white-space: nowrap;
+}
+
+%link-hover {
+ color: #d2603a !important;
+ border-bottom: 1px solid #d2603a;
+ text-decoration: none;
+}
+
+%link-color {
+ color: var(--link-color);
+}
+
+%link-underline {
+ border-bottom: 1px solid var(--link-underline-color);
+}
+
+%clickable-transition {
+ transition: all 0.3s ease-in-out;
+}
+
+%no-cursor {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+%no-bottom-border {
+ border-bottom: none;
+}
+
+%cursor-pointer {
+ cursor: pointer;
+}
+
+%normal-font-style {
+ font-style: normal;
+}
+
+%rounded {
+ border-radius: v.$radius-lg;
+}
+
+%img-caption {
+ + em {
+ display: block;
+ text-align: center;
+ font-style: normal;
+ font-size: 80%;
+ padding: 0;
+ color: #6d6c6c;
+ }
+}
+
+%sidebar-links {
+ color: var(--sidebar-muted-color);
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+%text-clip {
+ display: -webkit-box;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+}
+
+%text-ellipsis {
+ @include mx.text-ellipsis;
+}
+
+%text-highlight {
+ color: var(--text-muted-highlight-color);
+ font-weight: 600;
+}
+
+%text-sm {
+ font-size: 0.85rem;
+}
+
+%text-xs {
+ font-size: 0.8rem;
+}
+
+%sup-fn-target {
+ &:target {
+ background-color: var(--footnote-target-bg);
+ width: -moz-fit-content;
+ width: -webkit-fit-content;
+ width: fit-content;
+ transition: background-color 1.75s ease-in-out;
+ }
+}
+
+%btn-color {
+ button i {
+ color: #999999;
+ }
+}
+
+%code-snippet-bg {
+ background-color: var(--highlight-bg-color);
+}
+
+%code-snippet-padding {
+ padding-left: 1rem;
+ padding-right: 1.5rem;
+}
+
+%max-w-100 {
+ max-width: 100%;
+}
+
+%panel-border {
+ border-left: 1px solid var(--main-border-color);
+}
diff --git a/src/styles/abstracts/_variables.scss b/src/styles/abstracts/_variables.scss
new file mode 100644
index 00000000000..0194e40baa3
--- /dev/null
+++ b/src/styles/abstracts/_variables.scss
@@ -0,0 +1,30 @@
+/* sidebar */
+
+$sidebar-width: 260px !default; /* the basic width */
+$sidebar-width-large: 300px !default; /* screen width: >= 1650px */
+$sb-btn-gap: 0.8rem !default;
+$sb-btn-gap-lg: 1rem !default;
+
+/* other framework sizes */
+
+$topbar-height: 3rem !default;
+$search-max-width: 200px !default;
+$footer-height: 5rem !default;
+$footer-height-large: 6rem !default; /* screen width: < 850px */
+$main-content-max-width: 1250px !default;
+$radius-sm: 6px !default;
+$radius-lg: 10px !default;
+$back2top-size: 2.75rem !default;
+
+/* syntax highlight */
+
+$code-font-size: 0.85rem !default;
+$code-header-height: 2.25rem !default;
+$code-dot-size: 0.75rem !default;
+$code-dot-gap: 0.5rem !default;
+$code-icon-width: 1.75rem !default;
+
+/* fonts */
+
+$font-family-base: 'Source Sans Pro', 'Microsoft Yahei', sans-serif !default;
+$font-family-heading: Lato, 'Microsoft Yahei', sans-serif !default;
diff --git a/src/styles/base/_base.scss b/src/styles/base/_base.scss
new file mode 100644
index 00000000000..b512a484cc2
--- /dev/null
+++ b/src/styles/base/_base.scss
@@ -0,0 +1,483 @@
+@use '../abstracts/variables' as v;
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/mixins' as mx;
+@use '../abstracts/placeholders';
+@use '../themes/light';
+@use '../themes/dark';
+
+:root {
+ font-size: 16px;
+}
+
+html {
+ @media (prefers-color-scheme: light) {
+ &:not([data-mode]),
+ &[data-mode='light'] {
+ @include light.styles;
+ }
+
+ &[data-mode='dark'] {
+ @include dark.styles;
+ }
+ }
+
+ @media (prefers-color-scheme: dark) {
+ &:not([data-mode]),
+ &[data-mode='dark'] {
+ @include dark.styles;
+ }
+
+ &[data-mode='light'] {
+ @include light.styles;
+ }
+ }
+
+ @include bp.lg {
+ overflow-y: scroll;
+ }
+}
+
+body {
+ background: var(--main-bg);
+ padding: env(safe-area-inset-top) env(safe-area-inset-right)
+ env(safe-area-inset-bottom) env(safe-area-inset-left);
+ color: var(--text-color);
+ -webkit-font-smoothing: antialiased;
+ font-family: v.$font-family-base;
+}
+
+h1.dynamic-title {
+ @include bp.lt(bp.get(lg)) {
+ display: none;
+
+ ~ .content {
+ margin-top: 2.5rem;
+ }
+ }
+}
+
+main {
+ &.col-12 {
+ @include bp.xxxl {
+ padding-right: 4.5rem !important;
+ }
+ }
+}
+
+.preview-img {
+ aspect-ratio: 40 / 21;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+
+ @extend %rounded;
+
+ &:not(.no-bg) {
+ background: var(--img-bg);
+ }
+
+ img {
+ height: 100%;
+ -o-object-fit: cover;
+ object-fit: cover;
+
+ @extend %rounded;
+
+ @at-root #post-list & {
+ width: 100%;
+ }
+ }
+}
+
+.post-preview {
+ @extend %rounded;
+
+ border: 0;
+ background: var(--card-bg);
+ box-shadow: var(--card-shadow);
+
+ &::before {
+ @extend %rounded;
+
+ content: '';
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ background-color: var(--card-hover-bg);
+ opacity: 0;
+ transition: opacity 0.35s ease-in-out;
+ }
+
+ &:hover {
+ &::before {
+ opacity: 0.3;
+ }
+ }
+}
+
+.post-meta {
+ @extend %text-sm;
+
+ a {
+ &:not([class]):hover {
+ @extend %link-hover;
+ }
+ }
+
+ em {
+ @extend %normal-font-style;
+ }
+}
+
+.content {
+ font-size: 1.08rem;
+ margin-top: 2rem;
+ overflow-wrap: break-word;
+
+ @include bp.xl {
+ font-size: 1.03rem;
+ }
+
+ a {
+ &.popup {
+ @extend %no-cursor;
+ @extend %img-caption;
+ @include mx.mt-mb(0.5rem);
+
+ cursor: zoom-in;
+ }
+
+ &:not(.img-link) {
+ @extend %link-underline;
+
+ &:hover {
+ @extend %link-hover;
+ }
+ }
+ }
+
+ ol,
+ ul {
+ &:not([class]),
+ &.task-list {
+ -webkit-padding-start: 1.75rem;
+ padding-inline-start: 1.75rem;
+
+ li {
+ margin: 0.25rem 0;
+ padding-left: 0.25rem;
+ }
+
+ ol,
+ ul {
+ -webkit-padding-start: 1.25rem;
+ padding-inline-start: 1.25rem;
+ margin: 0.5rem 0;
+ }
+ }
+ }
+
+ ul.task-list {
+ -webkit-padding-start: 1.25rem;
+ padding-inline-start: 1.25rem;
+
+ li {
+ list-style-type: none;
+ padding-left: 0;
+
+ /* checkbox icon */
+ > i {
+ width: 2rem;
+ margin-left: -1.25rem;
+ color: var(--checkbox-color);
+
+ &.checked {
+ color: var(--checkbox-checked-color);
+ }
+ }
+
+ ul {
+ -webkit-padding-start: 1.75rem;
+ padding-inline-start: 1.75rem;
+ }
+ }
+
+ input[type='checkbox'] {
+ margin: 0 0.5rem 0.2rem -1.3rem;
+ vertical-align: middle;
+ }
+ } /* ul */
+
+ dl > dd {
+ margin-left: 1rem;
+ }
+
+ ::marker {
+ color: var(--text-muted-color);
+ }
+
+ .table-wrapper > table {
+ @include bp.lg {
+ min-width: 70%;
+ }
+ }
+} /* .content */
+
+.tag:hover {
+ @extend %tag-hover;
+}
+
+.post-tag {
+ display: inline-block;
+ min-width: 2rem;
+ text-align: center;
+ border-radius: 0.5rem;
+ border: 1px solid var(--btn-border-color);
+ padding: 0 0.4rem;
+ color: var(--text-muted-color);
+ line-height: 1.3rem;
+
+ &:not(:last-child) {
+ margin-right: 0.2rem;
+ }
+}
+
+.rounded-10 {
+ border-radius: 10px !important;
+}
+
+.img-link {
+ color: transparent;
+ display: inline-flex;
+}
+
+.shimmer {
+ overflow: hidden;
+ position: relative;
+ background: var(--img-bg);
+
+ &::before {
+ content: '';
+ position: absolute;
+ background: var(--shimmer-bg);
+ height: 100%;
+ width: 100%;
+ -webkit-animation: shimmer 1.3s infinite;
+ animation: shimmer 1.3s infinite;
+ }
+
+ @-webkit-keyframes shimmer {
+ 0% {
+ transform: translateX(-100%);
+ }
+
+ 100% {
+ transform: translateX(100%);
+ }
+ }
+
+ @keyframes shimmer {
+ 0% {
+ transform: translateX(-100%);
+ }
+
+ 100% {
+ transform: translateX(100%);
+ }
+ }
+}
+
+.embed-video {
+ width: 100%;
+ height: 100%;
+ margin-bottom: 1rem;
+ aspect-ratio: 16 / 9;
+
+ @extend %rounded;
+
+ &.twitch {
+ aspect-ratio: 310 / 189;
+ }
+
+ &.file {
+ display: block;
+ width: auto;
+ height: auto;
+ max-width: 100%;
+ max-height: 100%;
+ margin: auto;
+ margin-bottom: 0;
+ }
+
+ @extend %img-caption;
+}
+
+.embed-audio {
+ width: 100%;
+
+ &.file {
+ display: block;
+ }
+
+ &.spotify {
+ border-radius: 14px;
+ }
+
+ @extend %img-caption;
+}
+
+/* --- Effects classes --- */
+
+.flex-grow-1 {
+ flex-grow: 1 !important;
+}
+
+.btn-box-shadow {
+ box-shadow: var(--card-shadow);
+}
+
+/* overwrite bootstrap muted */
+.text-muted {
+ color: var(--text-muted-color) !important;
+}
+
+/* Overwrite bootstrap tooltip */
+.tooltip-inner {
+ font-size: 0.7rem;
+ max-width: 220px;
+ text-align: left;
+}
+
+/* Overwrite bootstrap outline button */
+.btn.btn-outline-primary {
+ &:not(.disabled):hover {
+ border-color: #007bff !important;
+ }
+}
+
+.disabled {
+ color: rgb(206 196 196);
+ pointer-events: auto;
+ cursor: not-allowed;
+}
+
+.hide-border-bottom {
+ border-bottom: none !important;
+}
+
+.input-focus {
+ box-shadow: none;
+ border-color: var(--input-focus-border-color) !important;
+ background: center !important;
+ transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
+}
+
+.left {
+ float: left;
+ margin: 0.75rem 1rem 1rem 0;
+}
+
+.right {
+ float: right;
+ margin: 0.75rem 0 1rem 1rem;
+}
+
+/* --- Overriding --- */
+
+/* mermaid */
+.mermaid {
+ text-align: center;
+}
+
+/* MathJax */
+mjx-container {
+ overflow-y: hidden;
+ min-width: auto !important;
+}
+
+@media (hover: hover) {
+ #sidebar ul > li:last-child::after {
+ transition: top 0.5s ease;
+ }
+
+ .nav-link {
+ transition: background-color 0.3s ease-in-out;
+ }
+
+ .post-preview {
+ transition: background-color 0.35s ease-in-out;
+ }
+}
+
+#mask {
+ inset: 0 0 0 0;
+}
+
+#main-wrapper {
+ position: relative;
+
+ @include mx.pl-pr(0);
+
+ @include bp.lt(bp.get(lg)) {
+ @include mx.slide;
+ }
+
+ @include bp.lg {
+ margin-left: v.$sidebar-width;
+ }
+
+ @include bp.xxxl {
+ margin-left: v.$sidebar-width-large;
+ }
+
+ > .container {
+ min-height: 100vh;
+
+ @include bp.lte(bp.get(md)) {
+ @include mx.max-w-100;
+ @include mx.pl-pr(0);
+ }
+
+ @include bp.lt(bp.get(lg)) {
+ max-width: 100%;
+ }
+
+ /* Pad horizontal */
+ @include bp.between(992px, calc(#{bp.get(xl)} - 1px)) {
+ .col-lg-11 {
+ flex: 0 0 96%;
+ max-width: 96%;
+ }
+ }
+
+ @include bp.lt(bp.get(xl)) {
+ > .row {
+ justify-content: center !important;
+ }
+ }
+
+ @include bp.xxxl {
+ max-width: v.$main-content-max-width;
+
+ @include mx.pl-pr(1.75rem, true);
+ }
+ }
+}
+
+/* --- basic wrappers --- */
+
+#topbar-wrapper.row,
+#main-wrapper > .container > .row,
+#search-result-wrapper > .row {
+ @include mx.ml-mr(0);
+}
+
+#tail-wrapper {
+ @include bp.xxxl {
+ padding-right: 4.5rem !important;
+ }
+
+ > :not(script) {
+ margin-top: 3rem;
+ }
+}
diff --git a/src/styles/base/_index.scss b/src/styles/base/_index.scss
new file mode 100644
index 00000000000..611d28ff4ab
--- /dev/null
+++ b/src/styles/base/_index.scss
@@ -0,0 +1,4 @@
+@forward 'reset';
+@forward 'base';
+@forward 'typography';
+@forward 'syntax';
diff --git a/src/styles/base/_reset.scss b/src/styles/base/_reset.scss
new file mode 100644
index 00000000000..1e5a6294662
--- /dev/null
+++ b/src/styles/base/_reset.scss
@@ -0,0 +1,41 @@
+@use '../abstracts/mixins' as *;
+
+::-webkit-input-placeholder {
+ @include placeholder;
+}
+
+::-moz-placeholder {
+ @include placeholder;
+}
+
+:-ms-input-placeholder {
+ @include placeholder;
+}
+
+::-ms-input-placeholder {
+ @include placeholder;
+}
+
+::placeholder {
+ @include placeholder;
+}
+
+:focus::-webkit-input-placeholder {
+ @include placeholder-focus;
+}
+
+:focus::-moz-placeholder {
+ @include placeholder-focus;
+}
+
+:focus:-ms-input-placeholder {
+ @include placeholder-focus;
+}
+
+:focus::-ms-input-placeholder {
+ @include placeholder-focus;
+}
+
+:focus::placeholder {
+ @include placeholder-focus;
+}
diff --git a/src/styles/base/_syntax.scss b/src/styles/base/_syntax.scss
new file mode 100644
index 00000000000..34ddbe600f4
--- /dev/null
+++ b/src/styles/base/_syntax.scss
@@ -0,0 +1,252 @@
+@use '../abstracts/variables' as v;
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/mixins' as mx;
+@use '../abstracts/placeholders';
+
+.highlighter-rouge {
+ color: var(--highlighter-rouge-color);
+ margin-top: 0.5rem;
+ margin-bottom: 1.2em; /* Override BS Inline-code style */
+}
+
+.highlight {
+ @extend %rounded;
+ @extend %code-snippet-bg;
+
+ overflow: auto;
+ padding-bottom: 0.75rem;
+
+ @at-root figure#{&} {
+ @extend %code-snippet-bg;
+ }
+
+ pre {
+ margin-bottom: 0;
+ font-size: v.$code-font-size;
+ line-height: 1.4rem;
+ }
+
+ table {
+ td {
+ &:first-child {
+ display: inline-block;
+ margin-left: 1rem;
+ margin-right: 0.75rem;
+ }
+
+ &:last-child {
+ padding-right: 2rem !important;
+ }
+
+ pre {
+ overflow: visible; /* Fixed iOS safari overflow-x */
+ word-break: normal; /* Fixed iOS safari linenos code break */
+ }
+ }
+ }
+
+ .lineno {
+ text-align: right;
+ color: var(--highlight-lineno-color);
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -o-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ }
+} /* .highlight */
+
+code {
+ -webkit-hyphens: none;
+ -ms-hyphens: none;
+ hyphens: none;
+ color: var(--code-color);
+
+ &.highlighter-rouge {
+ font-size: v.$code-font-size;
+ padding: 3px 5px;
+ overflow-wrap: break-word;
+ border-radius: v.$radius-sm;
+ background-color: var(--inline-code-bg);
+ }
+
+ &.filepath {
+ background-color: inherit;
+ color: var(--filepath-text-color);
+ font-weight: 600;
+ padding: 0;
+ }
+
+ a > &.highlighter-rouge {
+ padding-bottom: 0; /* show link's underlinke */
+ color: inherit;
+ }
+
+ a:hover > &.highlighter-rouge {
+ border-bottom: none;
+ }
+
+ blockquote & {
+ color: inherit;
+ }
+}
+
+td.rouge-code {
+ @extend %code-snippet-padding;
+
+ /*
+ Prevent some browser extends from
+ changing the URL string of code block.
+ */
+ a {
+ color: inherit !important;
+ border-bottom: none !important;
+ pointer-events: none;
+ }
+}
+
+div[class^='language-'] {
+ @extend %rounded;
+ @extend %code-snippet-bg;
+
+ box-shadow: var(--language-border-color) 0 0 0 1px;
+
+ .content > & {
+ @include mx.ml-mr(-1rem);
+
+ border-radius: 0;
+
+ @include bp.sm {
+ @include mx.ml-mr(0);
+
+ border-radius: v.$radius-lg;
+ }
+ }
+
+ .code-header {
+ @include bp.sm {
+ @include mx.ml-mr(0);
+
+ $dot-margin: 1rem;
+
+ &::before {
+ content: '';
+ display: inline-block;
+ margin-left: $dot-margin;
+ width: v.$code-dot-size;
+ height: v.$code-dot-size;
+ border-radius: 50%;
+ background-color: var(--code-header-muted-color);
+ box-shadow: (v.$code-dot-size + v.$code-dot-gap) 0 0
+ var(--code-header-muted-color),
+ (v.$code-dot-size + v.$code-dot-gap) * 2 0 0
+ var(--code-header-muted-color);
+ }
+
+ span {
+ // center the text of label
+ margin-left: calc(($dot-margin + v.$code-dot-size) / 2 * -1);
+ }
+ }
+ }
+
+ .highlight {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ }
+}
+
+/* Hide line numbers for default, console, and terminal code snippets */
+div {
+ &.nolineno,
+ &.language-plaintext,
+ &.language-console,
+ &.language-terminal {
+ td:first-child {
+ padding: 0 !important;
+ margin-right: 0;
+
+ .lineno {
+ display: none;
+ }
+ }
+ }
+}
+
+.code-header {
+ @extend %no-cursor;
+
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ height: v.$code-header-height;
+ margin-left: 0.75rem;
+ margin-right: 0.25rem;
+
+ /* the label block */
+ span {
+ line-height: v.$code-header-height;
+
+ /* label icon */
+ i {
+ font-size: 1rem;
+ width: v.$code-icon-width;
+ color: var(--code-header-icon-color);
+
+ &.small {
+ font-size: 70%;
+ }
+ }
+
+ @at-root [file] #{&} > i {
+ position: relative;
+ top: 1px; /* center the file icon */
+ }
+
+ /* label text */
+ &::after {
+ content: attr(data-label-text);
+ font-size: 0.85rem;
+ font-weight: 600;
+ color: var(--code-header-text-color);
+ }
+ }
+
+ /* clipboard */
+ button {
+ @extend %cursor-pointer;
+ @extend %rounded;
+
+ border: 1px solid transparent;
+ height: v.$code-header-height;
+ width: v.$code-header-height;
+ padding: 0;
+ background-color: inherit;
+
+ i {
+ color: var(--code-header-icon-color);
+ }
+
+ &[timeout] {
+ &:hover {
+ border-color: var(--clipboard-checked-color);
+ }
+
+ i {
+ color: var(--clipboard-checked-color);
+ }
+ }
+
+ &:focus {
+ outline: none;
+ }
+
+ &:not([timeout]):hover {
+ background-color: rgb(128 128 128 / 37%);
+
+ i {
+ color: white;
+ }
+ }
+ }
+}
diff --git a/src/styles/base/_typography.scss b/src/styles/base/_typography.scss
new file mode 100644
index 00000000000..8b679726e91
--- /dev/null
+++ b/src/styles/base/_typography.scss
@@ -0,0 +1,264 @@
+@use '../abstracts/variables' as v;
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/mixins' as mx;
+@use '../abstracts/placeholders';
+
+@for $i from 1 through 5 {
+ h#{$i} {
+ @extend %heading;
+
+ @if $i > 1 {
+ @extend %anchor;
+ }
+
+ @if $i < 5 {
+ $size-factor: 0.25rem;
+
+ @if $i > 1 {
+ $size-factor: 0.18rem;
+
+ main & {
+ @if $i == 2 {
+ margin: 2.5rem 0 1.25rem;
+ } @else {
+ margin: 2rem 0 1rem;
+ }
+ }
+ }
+
+ font-size: 1rem + (5 - $i) * $size-factor;
+ } @else {
+ font-size: 1.05rem;
+ }
+ }
+}
+
+a {
+ @extend %link-color;
+
+ text-decoration: none;
+}
+
+img {
+ max-width: 100%;
+ height: auto;
+ transition: all 0.35s ease-in-out;
+
+ .blur & {
+ $blur: 20px;
+
+ -webkit-filter: blur($blur);
+ filter: blur($blur);
+ }
+}
+
+blockquote {
+ border-left: 0.125rem solid var(--blockquote-border-color);
+ padding-left: 1rem;
+ color: var(--blockquote-text-color);
+ margin-top: 0.5rem;
+
+ > p:last-child {
+ margin-bottom: 0;
+ }
+
+ &[class^='prompt-'] {
+ border-left: 0;
+ position: relative;
+ padding: 1rem 1rem 1rem 3rem;
+ color: var(--prompt-text-color);
+
+ @extend %rounded;
+
+ &::before {
+ text-align: center;
+ width: 3rem;
+ position: absolute;
+ left: 0.25rem;
+ margin-top: 0.4rem;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ }
+ }
+
+ @include mx.prompt('tip', '\f0eb', $fa-style: 'regular');
+ @include mx.prompt('info', '\f06a', $rotate: 180);
+ @include mx.prompt('warning', '\f06a');
+ @include mx.prompt('danger', '\f071');
+}
+
+kbd {
+ font-family: Lato, sans-serif;
+ display: inline-block;
+ vertical-align: middle;
+ line-height: 1.3rem;
+ min-width: 1.75rem;
+ text-align: center;
+ margin: 0 0.3rem;
+ padding-top: 0.1rem;
+ color: var(--kbd-text-color);
+ background-color: var(--kbd-bg-color);
+ border-radius: v.$radius-sm;
+ border: solid 1px var(--kbd-wrap-color);
+ box-shadow: inset 0 -2px 0 var(--kbd-wrap-color);
+}
+
+hr {
+ border-color: var(--main-border-color);
+ opacity: 1;
+}
+
+footer {
+ background-color: var(--main-bg);
+ height: v.$footer-height;
+ border-top: 1px solid var(--main-border-color);
+
+ @extend %text-xs;
+
+ a {
+ @extend %text-highlight;
+
+ &:hover {
+ @extend %link-hover;
+ }
+ }
+
+ em {
+ @extend %text-highlight;
+ }
+
+ p {
+ text-align: center;
+ margin-bottom: 0;
+ }
+}
+
+/* fontawesome icons */
+i {
+ &.far,
+ &.fas {
+ @extend %no-cursor;
+ }
+}
+
+sup {
+ @extend %sup-fn-target;
+}
+
+main {
+ line-height: 1.75;
+
+ h1 {
+ margin-top: 2rem;
+
+ @include bp.lg {
+ margin-top: 3rem;
+ }
+ }
+
+ p {
+ > a.popup {
+ &:not(.normal):not(.left):not(.right) {
+ @include mx.align-center;
+ }
+ }
+ }
+
+ .categories,
+ #tags,
+ #archives {
+ a:not(:hover) {
+ @extend %no-bottom-border;
+ }
+ }
+
+ @include bp.lte(bp.get(sm)) {
+ .content {
+ > blockquote[class^='prompt-'] {
+ @include mx.ml-mr(-1rem);
+
+ border-radius: 0;
+ max-width: none;
+ }
+ }
+ }
+}
+
+.footnotes > ol {
+ padding-left: 2rem;
+ margin-top: 0.5rem;
+
+ > li {
+ &:not(:last-child) {
+ margin-bottom: 0.3rem;
+ }
+
+ @extend %sup-fn-target;
+
+ > p {
+ margin-left: 0.25em;
+
+ @include mx.mt-mb(0);
+ }
+ }
+}
+
+.footnote {
+ @at-root a#{&} {
+ @include mx.ml-mr(1px);
+ @include mx.pl-pr(2px);
+
+ border-bottom-style: none !important;
+ }
+}
+
+.reversefootnote {
+ @at-root a#{&} {
+ font-size: 0.6rem;
+ line-height: 1;
+ position: relative;
+ bottom: 0.25em;
+ margin-left: 0.25em;
+ border-bottom-style: none !important;
+ }
+}
+
+/* --- Begin of Markdown table style --- */
+
+/* it will be created by Liquid */
+.table-wrapper {
+ overflow-x: auto;
+ margin-bottom: 1.5rem;
+
+ > table {
+ min-width: 100%;
+ overflow-x: auto;
+ border-spacing: 0;
+
+ thead {
+ border-bottom: solid 2px rgb(210 215 217 / 75%);
+
+ th {
+ @extend %table-cell;
+ }
+ }
+
+ tbody {
+ tr {
+ border-bottom: 1px solid var(--tb-border-color);
+
+ &:nth-child(2n) {
+ background-color: var(--tb-even-bg);
+ }
+
+ &:nth-child(2n + 1) {
+ background-color: var(--tb-odd-bg);
+ }
+
+ td {
+ @extend %table-cell;
+ }
+ }
+ } /* tbody */
+ } /* table */
+}
diff --git a/src/styles/components/_buttons.scss b/src/styles/components/_buttons.scss
new file mode 100644
index 00000000000..bd7363e5586
--- /dev/null
+++ b/src/styles/components/_buttons.scss
@@ -0,0 +1,51 @@
+@use '../abstracts/variables' as v;
+@use '../abstracts/breakpoints' as bp;
+
+#back-to-top {
+ visibility: hidden;
+ opacity: 0;
+ z-index: 1;
+ cursor: pointer;
+ position: fixed;
+ right: 1rem;
+ bottom: calc(v.$footer-height-large - v.$back2top-size / 2);
+ background: var(--button-bg);
+ color: var(--btn-backtotop-color);
+ padding: 0;
+ width: v.$back2top-size;
+ height: v.$back2top-size;
+ border-radius: 50%;
+ border: 1px solid var(--btn-backtotop-border-color);
+ transition: opacity 0.5s ease-in-out, transform 0.2s ease-out;
+
+ @include bp.lg {
+ right: 5%;
+ bottom: calc(v.$footer-height - v.$back2top-size / 2);
+ }
+
+ @include bp.xxl {
+ right: calc((100vw - v.$sidebar-width - 1140px) / 2 + 3rem);
+ }
+
+ @include bp.xxxl {
+ right: calc(
+ (100vw - v.$sidebar-width-large - v.$main-content-max-width) / 2 + 2rem
+ );
+ }
+
+ &:hover {
+ transform: translate3d(0, -5px, 0);
+ -webkit-transform: translate3d(0, -5px, 0);
+ }
+
+ i {
+ line-height: v.$back2top-size;
+ position: relative;
+ bottom: 2px;
+ }
+
+ &.show {
+ opacity: 1;
+ visibility: visible;
+ }
+}
diff --git a/src/styles/components/_index.scss b/src/styles/components/_index.scss
new file mode 100644
index 00000000000..ffbb9083479
--- /dev/null
+++ b/src/styles/components/_index.scss
@@ -0,0 +1,2 @@
+@forward 'buttons';
+@forward 'popups';
diff --git a/src/styles/components/_popups.scss b/src/styles/components/_popups.scss
new file mode 100644
index 00000000000..e94fcde368f
--- /dev/null
+++ b/src/styles/components/_popups.scss
@@ -0,0 +1,172 @@
+@use '../abstracts/variables' as v;
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/placeholders';
+
+/* PWA update popup */
+#notification {
+ @-webkit-keyframes popup {
+ from {
+ opacity: 0;
+ bottom: 0;
+ }
+ }
+
+ @keyframes popup {
+ from {
+ opacity: 0;
+ bottom: 0;
+ }
+ }
+
+ .toast-header {
+ background: none;
+ border-bottom: none;
+ color: inherit;
+ }
+
+ .toast-body {
+ font-family: Lato, sans-serif;
+ line-height: 1.25rem;
+
+ button {
+ font-size: 90%;
+ min-width: 4rem;
+ }
+ }
+
+ &.toast {
+ &.show {
+ display: block;
+ min-width: 20rem;
+ border-radius: 0.5rem;
+ -webkit-backdrop-filter: blur(10px);
+ backdrop-filter: blur(10px);
+ background-color: rgb(255 255 255 / 50%);
+ color: #1b1b1eba;
+ position: fixed;
+ left: 50%;
+ bottom: 20%;
+ transform: translateX(-50%);
+ -webkit-animation: popup 0.8s;
+ animation: popup 0.8s;
+ }
+ }
+}
+
+#toc-popup {
+ $slide-in: slide-in 0.3s ease-out;
+ $slide-out: slide-out 0.3s ease-out;
+ $curtain-height: 2rem;
+ $backdrop: blur(5px);
+
+ border-color: var(--toc-popup-border-color);
+ border-width: 1px;
+ border-radius: v.$radius-lg;
+ color: var(--text-color);
+ background: var(--card-bg);
+ margin-top: v.$topbar-height;
+ min-width: 20rem;
+ font-size: 1.05rem;
+
+ @include bp.sm {
+ max-width: 32rem;
+ }
+
+ &[open] {
+ -webkit-animation: $slide-in;
+ animation: $slide-in;
+ }
+
+ &[closing] {
+ -webkit-animation: $slide-out;
+ animation: $slide-out;
+ }
+
+ @include bp.lg {
+ left: v.$sidebar-width;
+ }
+
+ .header {
+ @extend %btn-color;
+
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ background-color: inherit;
+ border-bottom: 1px solid var(--main-border-color);
+
+ .label {
+ font-family: v.$font-family-heading;
+ }
+ }
+
+ button {
+ > i {
+ font-size: 1.25rem;
+ vertical-align: middle;
+ }
+
+ &:focus-visible {
+ box-shadow: none;
+ }
+ }
+
+ ul {
+ list-style-type: none;
+ padding-left: 0;
+
+ li {
+ ul,
+ & + li {
+ margin-top: 0.25rem;
+ }
+
+ a {
+ display: flex;
+ line-height: 1.5;
+ padding: 0.375rem 0;
+ padding-right: 1.125rem;
+
+ &.toc-link::before {
+ display: none;
+ }
+ }
+ }
+ }
+
+ @for $i from 2 through 4 {
+ .node-name--H#{$i} {
+ padding-left: 1.125rem * ($i - 1);
+ }
+ }
+
+ .is-active-link {
+ color: var(--toc-highlight) !important;
+ font-weight: 600;
+ }
+
+ &::-webkit-backdrop {
+ -webkit-backdrop-filter: $backdrop;
+ backdrop-filter: $backdrop;
+ }
+
+ &::backdrop {
+ -webkit-backdrop-filter: $backdrop;
+ backdrop-filter: $backdrop;
+ }
+
+ &::after {
+ display: flex;
+ content: '';
+ position: relative;
+ background: linear-gradient(transparent, var(--card-bg) 70%);
+ height: $curtain-height;
+ }
+
+ #toc-popup-content {
+ overflow: auto;
+ max-height: calc(100vh - 4 * v.$topbar-height);
+ font-family: v.$font-family-heading;
+ margin-bottom: -$curtain-height;
+ }
+}
diff --git a/src/styles/layout/_footer.scss b/src/styles/layout/_footer.scss
new file mode 100644
index 00000000000..fd49ea041f2
--- /dev/null
+++ b/src/styles/layout/_footer.scss
@@ -0,0 +1,36 @@
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/variables' as v;
+@use '../abstracts/mixins' as mx;
+@use '../abstracts/placeholders';
+
+footer {
+ background-color: var(--main-bg);
+ height: v.$footer-height;
+ border-top: 1px solid var(--main-border-color);
+
+ @extend %text-xs;
+
+ @include bp.lt(bp.get(lg)) {
+ @include mx.slide;
+
+ height: v.$footer-height-large;
+ padding: 1.5rem 0;
+ }
+
+ a {
+ @extend %text-highlight;
+
+ &:hover {
+ @extend %link-hover;
+ }
+ }
+
+ em {
+ @extend %text-highlight;
+ }
+
+ p {
+ text-align: center;
+ margin-bottom: 0;
+ }
+}
diff --git a/src/styles/layout/_index.scss b/src/styles/layout/_index.scss
new file mode 100644
index 00000000000..fa75daf9377
--- /dev/null
+++ b/src/styles/layout/_index.scss
@@ -0,0 +1,4 @@
+@forward 'sidebar';
+@forward 'topbar';
+@forward 'panel';
+@forward 'footer';
diff --git a/src/styles/layout/_panel.scss b/src/styles/layout/_panel.scss
new file mode 100644
index 00000000000..c0d5e9ebc57
--- /dev/null
+++ b/src/styles/layout/_panel.scss
@@ -0,0 +1,70 @@
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/mixins' as mx;
+@use '../abstracts/placeholders';
+
+.access {
+ top: 2rem;
+ transition: top 0.2s ease-in-out;
+ margin-top: 3rem;
+
+ &:only-child {
+ position: -webkit-sticky;
+ position: sticky;
+ }
+
+ > section {
+ @extend %panel-border;
+
+ padding-left: 1rem;
+
+ &:not(:first-child) {
+ margin-top: 4rem;
+ }
+ }
+
+ .content {
+ font-size: 0.9rem;
+ }
+}
+
+#panel-wrapper {
+ /* the headings */
+ .panel-heading {
+ font-family: inherit;
+ line-height: inherit;
+
+ @include mx.label(inherit);
+ }
+
+ .post-tag {
+ line-height: 1.05rem;
+ font-size: 0.85rem;
+ border-radius: 0.8rem;
+ padding: 0.3rem 0.5rem;
+ margin: 0 0.35rem 0.5rem 0;
+
+ &:hover {
+ transition: all 0.3s ease-in;
+ }
+ }
+
+ > :last-child {
+ margin-bottom: 4rem;
+ }
+
+ @include bp.lt(bp.get(xl)) {
+ display: none;
+ }
+}
+
+#access-lastmod {
+ a {
+ color: inherit;
+
+ &:hover {
+ @extend %link-hover;
+ }
+
+ @extend %no-bottom-border;
+ }
+}
diff --git a/src/styles/layout/_sidebar.scss b/src/styles/layout/_sidebar.scss
new file mode 100644
index 00000000000..eaad470c6c4
--- /dev/null
+++ b/src/styles/layout/_sidebar.scss
@@ -0,0 +1,258 @@
+@use '../abstracts/variables' as v;
+@use '../abstracts/mixins' as mx;
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/placeholders';
+
+$btn-border-width: 3px;
+$btn-mb: 0.5rem;
+$sidebar-display: 'sidebar-display'; /* the attribute for sidebar display */
+
+#sidebar {
+ @include mx.pl-pr(0);
+
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 100%;
+ overflow-y: auto;
+ width: v.$sidebar-width;
+ background: var(--sidebar-bg);
+ border-right: 1px solid var(--sidebar-border-color);
+
+ /* Hide scrollbar for IE, Edge and Firefox */
+ -ms-overflow-style: none; /* IE and Edge */
+ scrollbar-width: none; /* Firefox */
+
+ /* Hide scrollbar for Chrome, Safari and Opera */
+ &::-webkit-scrollbar {
+ display: none;
+ }
+
+ @include bp.lt(bp.get(lg)) {
+ @include mx.slide;
+
+ transform: translateX(-#{v.$sidebar-width}); /* hide */
+ -webkit-transform: translateX(-#{v.$sidebar-width});
+
+ [#{$sidebar-display}] & {
+ transform: translateX(0);
+ }
+ }
+
+ @include bp.xxxl {
+ width: v.$sidebar-width-large;
+ }
+
+ %sidebar-link-hover {
+ &:hover {
+ color: var(--sidebar-active-color);
+ }
+ }
+
+ a {
+ @extend %sidebar-links;
+ }
+
+ #avatar {
+ display: block;
+ width: 6.5rem;
+ height: 6.5rem;
+ overflow: hidden;
+ box-shadow: var(--avatar-border-color) 0 0 0 2px;
+ transform: translateZ(0); /* fixed the zoom in Safari */
+
+ @include bp.sm {
+ width: 7rem;
+ height: 7rem;
+ }
+
+ img {
+ transition: transform 0.5s;
+
+ &:hover {
+ transform: scale(1.2);
+ }
+ }
+ }
+
+ .profile-wrapper {
+ @include mx.mt-mb(2.5rem);
+ @extend %clickable-transition;
+
+ padding-left: 2.5rem;
+ padding-right: 1.25rem;
+ width: 100%;
+
+ @include bp.lg {
+ margin-top: 3rem;
+ }
+
+ @include bp.xxxl {
+ margin-top: 3.5rem;
+ margin-bottom: 2.5rem;
+ padding-left: 3.5rem;
+ }
+ }
+
+ .site-title {
+ @extend %clickable-transition;
+ @extend %sidebar-link-hover;
+
+ font-family: inherit;
+ font-weight: 900;
+ font-size: 1.75rem;
+ line-height: 1.2;
+ letter-spacing: 0.25px;
+ margin-top: 1.25rem;
+ margin-bottom: 0.5rem;
+ width: fit-content;
+ color: var(--site-title-color);
+ }
+
+ .site-subtitle {
+ font-size: 95%;
+ color: var(--site-subtitle-color);
+ margin-top: 0.25rem;
+ word-spacing: 1px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ }
+
+ ul {
+ margin-bottom: 2rem;
+
+ li.nav-item {
+ opacity: 0.9;
+ width: 100%;
+
+ @include mx.pl-pr(1.5rem);
+
+ @include bp.xxxl {
+ @include mx.pl-pr(2.75rem);
+ }
+
+ a.nav-link {
+ @include mx.pt-pb(0.6rem);
+
+ display: flex;
+ align-items: center;
+ border-radius: 0.75rem;
+ font-weight: 600;
+
+ &:hover {
+ background-color: var(--sidebar-hover-bg);
+ }
+
+ i {
+ font-size: 95%;
+ opacity: 0.8;
+ margin-right: 1.5rem;
+ }
+
+ span {
+ font-size: 90%;
+ letter-spacing: 0.2px;
+ }
+ }
+
+ &.active {
+ .nav-link {
+ color: var(--sidebar-active-color);
+ background-color: var(--sidebar-hover-bg);
+
+ span {
+ opacity: 1;
+ }
+ }
+ }
+
+ &:not(:first-child) {
+ margin-top: 0.25rem;
+ }
+ }
+ }
+
+ .sidebar-bottom {
+ padding-left: 2rem;
+ padding-right: 1rem;
+ margin-bottom: 1.5rem;
+
+ @include bp.xxxl {
+ padding-left: 2.75rem;
+ margin-bottom: 1.75rem;
+ }
+
+ $btn-size: 1.75rem;
+
+ %button {
+ width: $btn-size;
+ height: $btn-size;
+ margin-bottom: $btn-mb; // multi line gap
+ border-radius: 50%;
+ color: var(--sidebar-btn-color);
+ background-color: var(--sidebar-btn-bg);
+ text-align: center;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ &:not(:focus-visible) {
+ box-shadow: var(--sidebar-border-color) 0 0 0 1px;
+ }
+
+ &:hover {
+ background-color: var(--sidebar-hover-bg);
+ }
+ }
+
+ a {
+ @extend %button;
+ @extend %sidebar-link-hover;
+ @extend %clickable-transition;
+
+ &:not(:last-child) {
+ margin-right: v.$sb-btn-gap;
+
+ @include bp.xxxl {
+ margin-right: v.$sb-btn-gap-lg;
+ }
+ }
+ }
+
+ i {
+ line-height: $btn-size;
+ }
+
+ #mode-toggle {
+ @extend %button;
+ @extend %sidebar-links;
+ @extend %sidebar-link-hover;
+ }
+
+ .icon-border {
+ @extend %no-cursor;
+ @include mx.ml-mr(calc((v.$sb-btn-gap - $btn-border-width) / 2));
+
+ background-color: var(--sidebar-btn-color);
+ content: '';
+ width: $btn-border-width;
+ height: $btn-border-width;
+ border-radius: 50%;
+ margin-bottom: $btn-mb;
+
+ @include bp.xxxl {
+ @include mx.ml-mr(calc((v.$sb-btn-gap-lg - $btn-border-width) / 2));
+ }
+ }
+ } /* .sidebar-bottom */
+} /* #sidebar */
+
+[#{$sidebar-display}] {
+ #main-wrapper {
+ @include bp.lt(bp.get(lg)) {
+ transform: translateX(v.$sidebar-width);
+ }
+ }
+}
diff --git a/src/styles/layout/_topbar.scss b/src/styles/layout/_topbar.scss
new file mode 100644
index 00000000000..eb0aea9b0ca
--- /dev/null
+++ b/src/styles/layout/_topbar.scss
@@ -0,0 +1,86 @@
+@use '../abstracts/variables' as v;
+@use '../abstracts/mixins' as mx;
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/placeholders';
+
+#topbar-wrapper {
+ height: v.$topbar-height;
+ background-color: var(--topbar-bg);
+
+ @include bp.lt(bp.get(lg)) {
+ @include mx.slide(top 0.2s ease);
+
+ left: 0;
+ }
+}
+
+#topbar {
+ @extend %btn-color;
+
+ #breadcrumb {
+ font-size: 1rem;
+ color: var(--text-muted-color);
+ padding-left: 0.5rem;
+
+ a:hover {
+ @extend %link-hover;
+ }
+
+ span {
+ &:not(:last-child) {
+ &::after {
+ content: '›';
+ padding: 0 0.3rem;
+ }
+ }
+ }
+
+ @include bp.lt(bp.get(lg)) {
+ display: none;
+ }
+
+ @include bp.between(bp.get(lg), calc(#{bp.get(xl)} - 1px)) {
+ width: 65%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ word-break: keep-all;
+ white-space: nowrap;
+ }
+ }
+
+ @include bp.lte(bp.get(md)) {
+ @include mx.max-w-100;
+ }
+
+ @include bp.lt(bp.get(lg)) {
+ max-width: 100%;
+ }
+}
+
+#topbar-title {
+ display: none;
+ font-size: 1.1rem;
+ font-weight: 600;
+ font-family: sans-serif;
+ color: var(--topbar-text-color);
+ text-align: center;
+ width: 70%;
+ word-break: keep-all;
+
+ @include bp.lt(bp.get(lg)) {
+ display: block;
+ }
+
+ @include bp.lg {
+ text-align: left;
+ }
+}
+
+#sidebar-trigger,
+#search-trigger {
+ display: none;
+
+ @include bp.lt(bp.get(lg)) {
+ display: block;
+ }
+}
diff --git a/src/styles/main.bundle.scss b/src/styles/main.bundle.scss
new file mode 100644
index 00000000000..5d84f938ec6
--- /dev/null
+++ b/src/styles/main.bundle.scss
@@ -0,0 +1,2 @@
+@use 'vendors/bootstrap';
+@use 'main';
diff --git a/src/styles/main.scss b/src/styles/main.scss
new file mode 100644
index 00000000000..3bbb70d6515
--- /dev/null
+++ b/src/styles/main.scss
@@ -0,0 +1,4 @@
+@forward 'base';
+@forward 'components';
+@forward 'layout';
+@forward 'pages';
diff --git a/src/styles/pages/_archives.scss b/src/styles/pages/_archives.scss
new file mode 100644
index 00000000000..86e77a89b48
--- /dev/null
+++ b/src/styles/pages/_archives.scss
@@ -0,0 +1,140 @@
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/placeholders';
+
+#archives {
+ letter-spacing: 0.03rem;
+
+ @include bp.lt(bp.get(sm)) {
+ margin-top: -1rem;
+
+ ul {
+ letter-spacing: 0;
+ }
+ }
+
+ $timeline-width: 4px;
+
+ %timeline {
+ content: '';
+ width: $timeline-width;
+ position: relative;
+ float: left;
+ background-color: var(--timeline-color);
+ }
+
+ .year {
+ height: 3.5rem;
+ font-size: 1.5rem;
+ position: relative;
+ left: 2px;
+ margin-left: -$timeline-width;
+
+ &::before {
+ @extend %timeline;
+
+ height: 72px;
+ left: 79px;
+ bottom: 16px;
+ }
+
+ &:first-child::before {
+ @extend %timeline;
+
+ height: 32px;
+ top: 24px;
+ }
+
+ /* Year dot */
+ &::after {
+ content: '';
+ display: inline-block;
+ position: relative;
+ border-radius: 50%;
+ width: 12px;
+ height: 12px;
+ left: 21.5px;
+ border: 3px solid;
+ background-color: var(--timeline-year-dot-color);
+ border-color: var(--timeline-node-bg);
+ box-shadow: 0 0 2px 0 #c2c6cc;
+ z-index: 1;
+ }
+ }
+
+ ul {
+ li {
+ font-size: 1.1rem;
+ line-height: 3rem;
+
+ @extend %text-ellipsis;
+
+ &:nth-child(odd) {
+ background-color: var(--main-bg, #ffffff);
+ background-image: linear-gradient(
+ to left,
+ #ffffff,
+ #fbfbfb,
+ #fbfbfb,
+ #fbfbfb,
+ #ffffff
+ );
+ }
+
+ &::before {
+ @extend %timeline;
+
+ top: 0;
+ left: 77px;
+ height: 3.1rem;
+ }
+ }
+
+ &:last-child li:last-child::before {
+ height: 1.5rem;
+ }
+ } /* #archives ul */
+
+ .date {
+ white-space: nowrap;
+ display: inline-block;
+ position: relative;
+ right: 0.5rem;
+
+ &.month {
+ width: 1.4rem;
+ text-align: center;
+ }
+
+ &.day {
+ font-size: 85%;
+ font-family: Lato, sans-serif;
+ }
+ }
+
+ a {
+ /* post title in Archvies */
+ margin-left: 2.5rem;
+ position: relative;
+ top: 0.1rem;
+
+ &:hover {
+ border-bottom: none;
+ }
+
+ &::before {
+ /* the dot before post title */
+ content: '';
+ display: inline-block;
+ position: relative;
+ border-radius: 50%;
+ width: 8px;
+ height: 8px;
+ float: left;
+ top: 1.35rem;
+ left: 71px;
+ background-color: var(--timeline-node-bg);
+ box-shadow: 0 0 3px 0 #c2c6cc;
+ z-index: 1;
+ }
+ }
+} /* #archives */
diff --git a/src/styles/pages/_categories.scss b/src/styles/pages/_categories.scss
new file mode 100644
index 00000000000..64a2df500c5
--- /dev/null
+++ b/src/styles/pages/_categories.scss
@@ -0,0 +1,82 @@
+@use '../abstracts/variables' as v;
+@use '../abstracts/placeholders';
+
+%-category-icon-color {
+ color: gray;
+}
+
+.categories {
+ margin-bottom: 2rem;
+ border-color: var(--categories-border);
+
+ &.card,
+ .list-group {
+ @extend %rounded;
+ }
+
+ .card-header {
+ $radius: calc(v.$radius-lg - 1px);
+
+ padding: 0.75rem;
+ border-radius: $radius;
+ border-bottom: 0;
+
+ &.hide-border-bottom {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ }
+ }
+
+ i {
+ @extend %-category-icon-color;
+
+ font-size: 86%; /* fontawesome icons */
+ }
+
+ .list-group-item {
+ border-left: none;
+ border-right: none;
+ padding-left: 2rem;
+
+ &:first-child {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ }
+
+ &:last-child {
+ border-bottom: 0;
+ }
+ }
+} /* .categories */
+
+.category-trigger {
+ width: 1.7rem;
+ height: 1.7rem;
+ border-radius: 50%;
+ text-align: center;
+ color: #6c757d !important;
+
+ i {
+ position: relative;
+ height: 0.7rem;
+ width: 1rem;
+ transition: transform 300ms ease;
+ }
+
+ &:hover {
+ i {
+ color: var(--categories-icon-hover-color);
+ }
+ }
+}
+
+/* only works on desktop */
+@media (hover: hover) {
+ .category-trigger:hover {
+ background-color: var(--categories-hover-bg);
+ }
+}
+
+.rotate {
+ transform: rotate(-90deg);
+}
diff --git a/src/styles/pages/_category-tag.scss b/src/styles/pages/_category-tag.scss
new file mode 100644
index 00000000000..0a827121bad
--- /dev/null
+++ b/src/styles/pages/_category-tag.scss
@@ -0,0 +1,63 @@
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/mixins' as mx;
+@use '../abstracts/placeholders';
+
+.dash {
+ margin: 0 0.5rem 0.6rem 0.5rem;
+ border-bottom: 2px dotted var(--dash-color);
+}
+
+#page-category,
+#page-tag {
+ ul > li {
+ line-height: 1.5rem;
+ padding: 0.6rem 0;
+
+ /* dot */
+ &::before {
+ background: #999999;
+ width: 5px;
+ height: 5px;
+ border-radius: 50%;
+ display: block;
+ content: '';
+ position: relative;
+ top: 0.6rem;
+ margin-right: 0.5rem;
+
+ @include bp.lt(bp.get(sm)) {
+ margin: 0 0.5rem;
+ }
+ }
+
+ /* post's title */
+ > a {
+ @extend %no-bottom-border;
+
+ font-size: 1.1rem;
+
+ @include bp.lt(bp.get(sm)) {
+ @include mx.text-ellipsis;
+ }
+ }
+ }
+}
+
+/* tag icon */
+#page-tag h1 > i {
+ font-size: 1.2rem;
+}
+
+#page-category h1 > i {
+ font-size: 1.25rem;
+}
+
+#page-category,
+#page-tag,
+#access-lastmod {
+ a:hover {
+ @extend %link-hover;
+
+ margin-bottom: -1px; /* Avoid jumping */
+ }
+}
diff --git a/src/styles/pages/_home.scss b/src/styles/pages/_home.scss
new file mode 100644
index 00000000000..84f4b4aae5b
--- /dev/null
+++ b/src/styles/pages/_home.scss
@@ -0,0 +1,170 @@
+@use '../abstracts/variables' as v;
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/placeholders';
+
+#post-list {
+ margin-top: 2rem;
+
+ @include bp.lg {
+ margin-top: 2.5rem;
+ }
+
+ .card-wrapper {
+ &:hover {
+ text-decoration: none;
+ }
+
+ &:not(:last-child) {
+ margin-bottom: 1.25rem;
+ }
+ }
+
+ .card {
+ border: 0;
+ background: none;
+
+ %img-radius {
+ border-radius: v.$radius-lg v.$radius-lg 0 0;
+
+ @include bp.md {
+ border-radius: 0 v.$radius-lg v.$radius-lg 0;
+ }
+ }
+
+ .preview-img {
+ @extend %img-radius;
+
+ img {
+ @extend %img-radius;
+ }
+ }
+
+ .card-body {
+ height: 100%;
+ padding: 1rem;
+
+ @include bp.md {
+ padding: 1.75rem 1.75rem 1.25rem;
+ }
+
+ .card-title {
+ @extend %text-clip;
+
+ color: var(--heading-color) !important;
+ font-size: 1.25rem;
+ }
+
+ %muted {
+ color: var(--text-muted-color) !important;
+ }
+
+ .card-text {
+ @include bp.md {
+ display: inherit !important;
+ }
+
+ &.content {
+ @extend %muted;
+
+ p {
+ @extend %text-clip;
+
+ line-height: 1.5;
+ margin: 0;
+ }
+ }
+ }
+
+ .post-meta {
+ @extend %muted;
+
+ i {
+ &:not(:first-child) {
+ margin-left: 1.5rem;
+
+ @include bp.md {
+ margin-left: 1.75rem;
+ }
+ }
+ }
+
+ em {
+ @extend %normal-font-style;
+
+ color: inherit;
+ }
+
+ > div:first-child {
+ display: block;
+
+ @extend %text-ellipsis;
+ }
+ }
+ }
+ }
+} /* #post-list */
+
+.pagination {
+ color: var(--text-color);
+ font-family: Lato, sans-serif;
+ justify-content: space-evenly;
+
+ @include bp.lg {
+ font-size: 0.85rem;
+ justify-content: center;
+ }
+
+ a:hover {
+ text-decoration: none;
+ }
+
+ .page-item {
+ @include bp.lt(bp.get(lg)) {
+ &:not(:first-child):not(:last-child) {
+ display: none;
+ }
+ }
+
+ @include bp.lg {
+ &:not(:last-child) {
+ margin-right: 0.7rem;
+ }
+ }
+
+ .page-link {
+ color: var(--btn-patinator-text-color);
+ padding: 0 0.6rem;
+ border-radius: 0.5rem;
+ border: 0;
+ background-color: inherit;
+ }
+
+ &.active {
+ .page-link {
+ background-color: var(--btn-paginator-hover-color);
+ }
+ }
+
+ &:not(.active) {
+ .page-link {
+ &:hover {
+ box-shadow: inset var(--btn-border-color) 0 0 0 1px;
+ }
+ }
+ }
+
+ &.disabled {
+ cursor: not-allowed;
+
+ .page-link {
+ color: rgb(108 117 125 / 57%);
+ }
+ }
+ } /* .page-item */
+
+ .page-index {
+ @include bp.lg {
+ display: none;
+ }
+ }
+}
diff --git a/src/styles/pages/_index.scss b/src/styles/pages/_index.scss
new file mode 100644
index 00000000000..74e9ea6eb55
--- /dev/null
+++ b/src/styles/pages/_index.scss
@@ -0,0 +1,7 @@
+@forward 'search';
+@forward 'home';
+@forward 'post';
+@forward 'categories';
+@forward 'tags';
+@forward 'archives';
+@forward 'category-tag';
diff --git a/src/styles/pages/_post.scss b/src/styles/pages/_post.scss
new file mode 100644
index 00000000000..2cd3eee3352
--- /dev/null
+++ b/src/styles/pages/_post.scss
@@ -0,0 +1,496 @@
+@use '../abstracts/variables' as v;
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/mixins' as mx;
+@use '../abstracts/placeholders';
+
+%-btn-post-nav {
+ width: 50%;
+ position: relative;
+ border-color: var(--btn-border-color);
+}
+
+@mixin -dot($pl: 0.25rem, $pr: 0.25rem) {
+ content: '\2022';
+ padding-left: $pl;
+ padding-right: $pr;
+}
+
+header {
+ .post-desc {
+ @extend %heading;
+
+ font-size: 1.125rem;
+ line-height: 1.6;
+ }
+
+ .post-meta {
+ span + span::before {
+ @include -dot;
+ }
+
+ em,
+ time {
+ @extend %text-highlight;
+ }
+
+ em {
+ a {
+ color: inherit;
+ }
+ }
+ }
+
+ h1 + .post-meta {
+ margin-top: 1.5rem;
+ }
+}
+
+.post-tail-wrapper {
+ @extend %text-sm;
+
+ margin-top: 6rem;
+ border-bottom: 1px double var(--main-border-color);
+
+ .license-wrapper {
+ line-height: 1.2rem;
+
+ > a {
+ @extend %text-highlight;
+
+ &:hover {
+ @extend %link-hover;
+ }
+ }
+
+ span:last-child {
+ @extend %text-sm;
+ }
+ } /* .license-wrapper */
+
+ .post-meta a:not(:hover) {
+ @extend %link-underline;
+ }
+
+ .share-wrapper {
+ vertical-align: middle;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ %icon-size {
+ font-size: 1.125rem;
+ }
+
+ .share-icons {
+ display: flex;
+
+ i {
+ color: var(--btn-share-color);
+
+ @extend %icon-size;
+ }
+
+ > * {
+ @extend %icon-size;
+
+ margin-left: 0.5rem;
+
+ &:hover {
+ i {
+ @extend %btn-share-hover;
+ }
+ }
+ }
+
+ button {
+ padding: 0;
+ border: none;
+ line-height: inherit;
+
+ @extend %cursor-pointer;
+ }
+ } /* .share-icons */
+ } /* .share-wrapper */
+}
+
+.post-tail-bottom {
+ @include bp.lte(bp.get(sm)) {
+ flex-wrap: wrap-reverse !important;
+
+ > div:first-child {
+ width: 100%;
+ margin-top: 1rem;
+ }
+ }
+}
+
+.share-mastodon {
+ /* See: https://github.com/justinribeiro/share-to-mastodon#properties */
+ --wc-stm-font-family: v.$font-family-base;
+ --wc-stm-dialog-background-color: var(--card-bg);
+ --wc-stm-form-button-border: 1px solid var(--btn-border-color);
+ --wc-stm-form-submit-background-color: var(--sidebar-btn-bg);
+ --wc-stm-form-cancel-background-color: var(--sidebar-btn-bg);
+ --wc-stm-form-button-background-color-hover: #007bff;
+ --wc-stm-form-button-color-hover: white;
+
+ font-size: 1rem;
+}
+
+.post-tags {
+ line-height: 2rem;
+
+ .post-tag {
+ &:hover {
+ @extend %tag-hover;
+ }
+ }
+}
+
+.post-navigation {
+ @include bp.lt(bp.get(lg)) {
+ @include mx.pl-pr(0);
+ @include mx.ml-mr(-0.5rem);
+ }
+
+ .btn {
+ @extend %-btn-post-nav;
+
+ &:not(:hover) {
+ color: var(--link-color);
+ }
+
+ &:hover {
+ &:not(.disabled)::before {
+ color: whitesmoke;
+ }
+ }
+
+ &.disabled {
+ @extend %-btn-post-nav;
+
+ pointer-events: auto;
+ cursor: not-allowed;
+ background: none;
+ color: gray;
+ }
+
+ &.btn-outline-primary.disabled:focus {
+ box-shadow: none;
+ }
+
+ &::before {
+ color: var(--text-muted-color);
+ font-size: 0.65rem;
+ text-transform: uppercase;
+ content: attr(aria-label);
+ }
+
+ &:first-child {
+ border-radius: v.$radius-lg 0 0 v.$radius-lg;
+ left: 0.5px;
+ }
+
+ &:last-child {
+ border-radius: 0 v.$radius-lg v.$radius-lg 0;
+ right: 0.5px;
+ }
+ }
+
+ p {
+ font-size: 1.1rem;
+ line-height: 1.5rem;
+ margin-top: 0.3rem;
+ white-space: normal;
+ }
+} /* .post-navigation */
+
+@media (hover: hover) {
+ .post-navigation {
+ .btn,
+ .btn::before {
+ transition: all 0.35s ease-in-out;
+ }
+ }
+}
+
+@-webkit-keyframes fade-up {
+ from {
+ opacity: 0;
+ margin-top: 4rem;
+ }
+
+ to {
+ opacity: 1;
+ }
+}
+
+@keyframes fade-up {
+ from {
+ opacity: 0;
+ margin-top: 4rem;
+ }
+
+ to {
+ opacity: 1;
+ }
+}
+
+/* TOC panel */
+
+%top-cover {
+ content: '';
+ display: block;
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ width: 100%;
+ height: 3rem;
+ background: linear-gradient(var(--main-bg) 50%, transparent);
+}
+
+#toc-wrapper {
+ top: 0;
+ transition: top 0.2s ease-in-out;
+ overflow-y: auto;
+ max-height: 100vh;
+ scrollbar-width: none;
+ margin-top: 2rem;
+
+ &:not(.invisible) {
+ -webkit-animation: fade-up 0.8s;
+ animation: fade-up 0.8s;
+ }
+
+ ul {
+ list-style: none;
+ font-size: 0.85rem;
+ line-height: 1.25;
+ padding-left: 0;
+
+ li {
+ a {
+ padding: 0.4rem 0 0.4rem 1.25rem;
+ }
+ }
+
+ /* Overwrite TOC plugin style */
+
+ .toc-link {
+ display: block;
+
+ @extend %text-ellipsis;
+
+ &:hover {
+ color: var(--toc-highlight);
+ text-decoration: none;
+ }
+
+ &::before {
+ display: none;
+ }
+ }
+
+ .is-active-link {
+ color: var(--toc-highlight) !important;
+ font-weight: 600;
+
+ &::before {
+ display: inline-block;
+ width: 1px;
+ height: 1.25rem;
+ background-color: var(--toc-highlight) !important;
+ }
+ }
+
+ ul {
+ padding-left: 0.75rem;
+ }
+ }
+
+ @at-root .toc-border-cover {
+ @extend %top-cover;
+
+ margin-bottom: -4rem;
+ }
+
+ &::before {
+ @extend %top-cover;
+ }
+
+ &::after {
+ content: '';
+ position: fixed;
+ bottom: 0;
+ width: 15%;
+ height: 2.25rem;
+ margin-left: -1px;
+ background: linear-gradient(transparent, var(--main-bg) 70%);
+ }
+
+ > * {
+ @extend %panel-border;
+ }
+}
+
+/* --- TOC button, bar and popup in mobile/tablet --- */
+
+#toc-bar {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ margin: 0 -1rem;
+ height: v.$topbar-height;
+ background: var(--main-bg);
+ border-bottom: 1px solid var(--main-border-color);
+ transition: all 0.2s ease-in-out;
+
+ @extend %btn-color;
+
+ @include bp.xl {
+ display: none !important;
+ }
+
+ .label {
+ @extend %heading;
+
+ margin-left: 0.375rem;
+ padding: 0 0.75rem;
+ color: inherit;
+ }
+
+ &.invisible {
+ top: -#{v.$topbar-height};
+ transition: none;
+ }
+}
+
+#toc-solo-trigger {
+ color: var(--text-muted-color);
+ border-color: var(--btn-border-color);
+ border-radius: v.$radius-lg;
+
+ @include bp.xl {
+ display: none !important;
+ }
+
+ .label {
+ font-size: 1rem;
+ font-family: v.$font-family-heading;
+ }
+
+ &:hover {
+ box-shadow: none;
+ background: none;
+ }
+}
+
+@mixin slide-in {
+ from {
+ opacity: 0.7;
+ transform: translateY(-#{v.$topbar-height});
+ }
+
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@mixin slide-out {
+ 0% {
+ transform: translateY(0);
+ opacity: 1;
+ }
+
+ 100% {
+ transform: translateY(-#{v.$topbar-height});
+ opacity: 0;
+ }
+}
+
+@-webkit-keyframes slide-in {
+ @include slide-in;
+}
+
+@keyframes slide-in {
+ @include slide-in;
+}
+
+@-webkit-keyframes slide-out {
+ @include slide-out;
+}
+
+@keyframes slide-out {
+ @include slide-out;
+}
+
+/* --- Related Posts --- */
+
+#related-posts {
+ > h3 {
+ @include mx.label(1.1rem, 600);
+ }
+
+ time {
+ @extend %normal-font-style;
+ @extend %text-xs;
+
+ color: var(--text-muted-color);
+ }
+
+ p {
+ @extend %text-ellipsis;
+
+ font-size: 0.9rem;
+ margin-bottom: 0.5rem;
+ white-space: break-spaces;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ }
+
+ .card {
+ h4 {
+ @extend %text-clip;
+ }
+ }
+}
+
+/* stylelint-disable-next-line selector-id-pattern */
+#disqus_thread {
+ min-height: 8.5rem;
+}
+
+.utterances {
+ max-width: 100%;
+ min-height: 269px;
+}
+
+%btn-share-hover {
+ color: var(--btn-share-hover-color) !important;
+}
+
+.share-label {
+ @include mx.label(inherit, 400, inherit);
+
+ &::after {
+ content: ':';
+ }
+}
+
+.content > p > img {
+ @include bp.lte(bp.get(md)) {
+ max-width: calc(100% + 1rem);
+ }
+}
+
+h2,
+h3,
+h4 {
+ @include bp.xl {
+ scroll-margin-top: 2rem;
+ }
+}
diff --git a/src/styles/pages/_search.scss b/src/styles/pages/_search.scss
new file mode 100644
index 00000000000..dfb044edd6a
--- /dev/null
+++ b/src/styles/pages/_search.scss
@@ -0,0 +1,184 @@
+@use '../abstracts/breakpoints' as bp;
+@use '../abstracts/variables' as v;
+@use '../abstracts/placeholders';
+
+search {
+ display: flex;
+ width: 100%;
+ border-radius: 1rem;
+ border: 1px solid var(--search-border-color);
+ background: var(--main-bg);
+ padding: 0 0.5rem;
+
+ i {
+ z-index: 2;
+ font-size: 0.9rem;
+ color: var(--search-icon-color);
+ }
+
+ @include bp.lt(bp.get(lg)) {
+ display: none;
+ }
+
+ @include bp.lg {
+ max-width: v.$search-max-width;
+ }
+
+ @include bp.xl {
+ margin-right: 4rem;
+ }
+
+ @include bp.xxxl {
+ margin-right: calc(
+ v.$main-content-max-width / 4 - v.$search-max-width - 0.75rem
+ );
+ }
+}
+
+#search-result-wrapper {
+ display: none;
+ height: 100%;
+ width: 100%;
+ overflow: auto;
+
+ .content {
+ margin-top: 2rem;
+ }
+
+ @include bp.lt(bp.get(lg)) {
+ width: 100%;
+
+ .content {
+ letter-spacing: 0;
+ }
+ }
+
+ @include bp.lg {
+ max-width: v.$main-content-max-width;
+ justify-content: start !important;
+ }
+}
+
+#search-results {
+ padding-bottom: 3rem;
+
+ @include bp.between(bp.get(lg), calc(#{bp.get(xl)} - 1px)) {
+ > div {
+ max-width: 700px;
+ }
+ }
+
+ a {
+ font-size: 1.4rem;
+ line-height: 1.5rem;
+
+ &:hover {
+ @extend %link-hover;
+ }
+
+ @extend %link-color;
+ @extend %no-bottom-border;
+ @extend %heading;
+ }
+
+ > article {
+ width: 100%;
+
+ &:not(:last-child) {
+ margin-bottom: 1rem;
+ }
+
+ @include bp.xl {
+ width: 45%;
+
+ &:nth-child(odd) {
+ margin-right: 1.5rem;
+ }
+
+ &:nth-child(even) {
+ margin-left: 1.5rem;
+ }
+
+ &:last-child:nth-child(odd) {
+ position: relative;
+ right: 24.3%;
+ }
+ }
+
+ h2 {
+ line-height: 2.5rem;
+ }
+
+ /* icons */
+ i {
+ color: #818182;
+ margin-right: 0.15rem;
+ font-size: 80%;
+ }
+
+ > p {
+ @extend %text-ellipsis;
+
+ white-space: break-spaces;
+ display: -webkit-box;
+ -webkit-line-clamp: 3;
+ -webkit-box-orient: vertical;
+ }
+ }
+}
+
+/* 'Cancel' link */
+#search-cancel {
+ color: var(--link-color);
+ display: none;
+ white-space: nowrap;
+
+ @extend %cursor-pointer;
+}
+
+#search-input {
+ background: center;
+ border: 0;
+ border-radius: 0;
+ padding: 0.18rem 0.3rem;
+ color: var(--text-color);
+ height: auto;
+
+ &:focus {
+ box-shadow: none;
+ }
+
+ @include bp.xl {
+ transition: all 0.3s ease-in-out;
+ }
+}
+
+#search-hints {
+ padding: 0 1rem;
+
+ @include bp.lg {
+ display: none;
+ }
+
+ h4 {
+ margin-bottom: 1.5rem;
+ }
+
+ .post-tag {
+ display: inline-block;
+ line-height: 1rem;
+ font-size: 1rem;
+ background: var(--search-tag-bg);
+ border: none;
+ padding: 0.5rem;
+ margin: 0 1.25rem 1rem 0;
+
+ &::before {
+ content: '#';
+ color: var(--text-muted-color);
+ padding-right: 0.2rem;
+ }
+
+ @extend %link-color;
+ }
+}
diff --git a/src/styles/pages/_tags.scss b/src/styles/pages/_tags.scss
new file mode 100644
index 00000000000..d22f20d6cd7
--- /dev/null
+++ b/src/styles/pages/_tags.scss
@@ -0,0 +1,23 @@
+@use '../abstracts/breakpoints' as bp;
+
+.tag {
+ border-radius: 0.7em;
+ padding: 6px 8px 7px;
+ margin-right: 0.8rem;
+ line-height: 3rem;
+ letter-spacing: 0;
+ border: 1px solid var(--tag-border) !important;
+ box-shadow: 0 0 3px 0 var(--tag-shadow);
+
+ span {
+ margin-left: 0.6em;
+ font-size: 0.7em;
+ font-family: Oswald, sans-serif;
+ }
+}
+
+#tags {
+ @include bp.lt(bp.get(lg)) {
+ justify-content: center !important;
+ }
+}
diff --git a/src/styles/themes/_dark.scss b/src/styles/themes/_dark.scss
new file mode 100644
index 00000000000..aae652213d4
--- /dev/null
+++ b/src/styles/themes/_dark.scss
@@ -0,0 +1,303 @@
+@mixin styles {
+ color-scheme: dark;
+
+ /* Framework color */
+ --main-bg: rgb(27 27 30);
+ --mask-bg: rgb(68 69 70);
+ --main-border-color: rgb(44 45 45);
+
+ /* Common color */
+ --text-color: rgb(175 176 177);
+ --text-muted-color: #868686;
+ --text-muted-highlight-color: #aeaeae;
+ --heading-color: #cccccc;
+ --label-color: #a7a7a7;
+ --blockquote-border-color: rgb(66 66 66);
+ --blockquote-text-color: #868686;
+ --link-color: rgb(138 180 248);
+ --link-underline-color: rgb(82 108 150);
+ --button-bg: #1e1e1e;
+ --btn-border-color: #2e2f31;
+ --btn-backtotop-color: var(--text-color);
+ --btn-backtotop-border-color: #212122;
+ --card-header-bg: #292929;
+ --checkbox-color: rgb(118 120 121);
+ --checkbox-checked-color: var(--link-color);
+ --img-bg: radial-gradient(circle, rgb(22 22 24) 0%, rgb(32 32 32) 100%);
+ --shimmer-bg: linear-gradient(
+ 90deg,
+ rgb(255 255 255 / 0%) 0%,
+ rgb(58 55 55 / 40%) 50%,
+ rgb(255 255 255 / 0%) 100%
+ );
+
+ /* Sidebar */
+ --site-title-color: #717070;
+ --site-subtitle-color: #868686;
+ --sidebar-bg: #1e1e1e;
+ --sidebar-border-color: #292929;
+ --sidebar-muted-color: #868686;
+ --sidebar-active-color: rgb(255 255 255 / 95%);
+ --sidebar-hover-bg: #262626;
+ --sidebar-btn-bg: #232328;
+ --sidebar-btn-color: #787878;
+ --avatar-border-color: rgb(206 206 206 / 90%);
+
+ /* Topbar */
+ --topbar-bg: rgb(27 27 30 / 64%);
+ --topbar-text-color: var(--text-color);
+ --search-border-color: rgb(55 55 55);
+ --search-icon-color: rgb(100 102 105);
+ --input-focus-border-color: rgb(112 114 115);
+
+ /* Home page */
+ --post-list-text-color: rgb(175 176 177);
+ --btn-patinator-text-color: var(--text-color);
+ --btn-paginator-hover-color: #2e2e2e;
+
+ /* Posts */
+ --toc-highlight: rgb(116 178 243);
+ --toc-popup-border-color: #373737;
+ --tag-hover: rgb(43 56 62);
+ --tb-odd-bg: #252526; /* odd rows of the posts' table */
+ --tb-even-bg: rgb(31 31 34); /* even rows of the posts' table */
+ --tb-border-color: var(--tb-odd-bg);
+ --footnote-target-bg: rgb(63 81 181);
+ --btn-share-color: #6c757d;
+ --btn-share-hover-color: #bfc1ca;
+ --card-bg: #1e1e1e;
+ --card-hover-bg: #464d51;
+ --card-shadow: rgb(21 21 21 / 72%) 0 6px 18px 0,
+ rgb(137 135 135 / 24%) 0 0 0 1px;
+ --kbd-wrap-color: #6a6a6a;
+ --kbd-text-color: #d3d3d3;
+ --kbd-bg-color: #242424;
+ --prompt-text-color: rgb(216 212 212 / 75%);
+ --prompt-tip-bg: rgb(22 60 36 / 64%);
+ --prompt-tip-icon-color: rgb(15 164 15 / 81%);
+ --prompt-info-bg: rgb(7 59 104 / 80%);
+ --prompt-info-icon-color: #0075d1;
+ --prompt-warning-bg: rgb(90 69 3 / 88%);
+ --prompt-warning-icon-color: rgb(255 165 0 / 80%);
+ --prompt-danger-bg: rgb(86 28 8 / 80%);
+ --prompt-danger-icon-color: #cd0202;
+
+ /* Tags */
+ --tag-border: rgb(59 79 88);
+ --tag-shadow: rgb(32 33 33);
+ --dash-color: rgb(63 65 68);
+ --search-tag-bg: #292828;
+
+ /* Categories */
+ --categories-border: rgb(64 66 69 / 50%);
+ --categories-hover-bg: rgb(73 75 76);
+ --categories-icon-hover-color: white;
+
+ /* Archive */
+ --timeline-node-bg: rgb(150 152 156);
+ --timeline-color: rgb(63 65 68);
+ --timeline-year-dot-color: var(--timeline-color);
+
+ /* Code highlight colors */
+ --language-border-color: #2d2d2d;
+ --highlight-bg-color: #151515;
+ --highlighter-rouge-color: #c9def1;
+ --highlight-lineno-color: #808080;
+ --inline-code-bg: rgb(255 255 255 / 5%);
+ --code-color: #b0b0b0;
+ --code-header-text-color: #6a6a6a;
+ --code-header-muted-color: #353535;
+ --code-header-icon-color: #565656;
+ --clipboard-checked-color: #2bcc2b;
+ --filepath-text-color: #cacaca;
+
+ .light {
+ display: none;
+ }
+
+ /* Categories */
+ .categories.card,
+ .list-group-item {
+ background-color: var(--card-bg);
+ }
+
+ .categories {
+ .card-header {
+ background-color: var(--card-header-bg);
+ }
+
+ .list-group-item {
+ border-left: none;
+ border-right: none;
+ padding-left: 2rem;
+ border-color: var(--categories-border);
+
+ &:last-child {
+ border-bottom-color: var(--card-bg);
+ }
+ }
+ }
+
+ #archives li:nth-child(odd) {
+ background-image: linear-gradient(
+ to left,
+ rgb(26 26 30),
+ rgb(39 39 45),
+ rgb(39 39 45),
+ rgb(39 39 45),
+ rgb(26 26 30)
+ );
+ }
+
+ /* stylelint-disable-next-line selector-id-pattern */
+ #disqus_thread {
+ color-scheme: none;
+ }
+
+ /* --- Syntax highlight theme from `rougify style base16.dark` --- */
+
+ .highlight .gp {
+ color: #87939d;
+ }
+
+ .highlight table td {
+ padding: 5px;
+ }
+
+ .highlight table pre {
+ margin: 0;
+ }
+
+ .highlight,
+ .highlight .w {
+ color: #d0d0d0;
+ background-color: #151515;
+ }
+
+ .highlight .err {
+ color: #151515;
+ background-color: #ac4142;
+ }
+
+ .highlight .c,
+ .highlight .ch,
+ .highlight .cd,
+ .highlight .cm,
+ .highlight .cpf,
+ .highlight .c1,
+ .highlight .cs {
+ color: #848484;
+ }
+
+ .highlight .cp {
+ color: #f4bf75;
+ }
+
+ .highlight .nt {
+ color: #f4bf75;
+ }
+
+ .highlight .o,
+ .highlight .ow {
+ color: #d0d0d0;
+ }
+
+ .highlight .p,
+ .highlight .pi {
+ color: #d0d0d0;
+ }
+
+ .highlight .gi {
+ color: #90a959;
+ }
+
+ .highlight .gd {
+ color: #f08a8b;
+ background-color: #320000;
+ }
+
+ .highlight .gh {
+ color: #6a9fb5;
+ background-color: #151515;
+ font-weight: bold;
+ }
+
+ .highlight .k,
+ .highlight .kn,
+ .highlight .kp,
+ .highlight .kr,
+ .highlight .kv {
+ color: #aa759f;
+ }
+
+ .highlight .kc {
+ color: #d28445;
+ }
+
+ .highlight .kt {
+ color: #d28445;
+ }
+
+ .highlight .kd {
+ color: #d28445;
+ }
+
+ .highlight .s,
+ .highlight .sb,
+ .highlight .sc,
+ .highlight .dl,
+ .highlight .sd,
+ .highlight .s2,
+ .highlight .sh,
+ .highlight .sx,
+ .highlight .s1 {
+ color: #90a959;
+ }
+
+ .highlight .sa {
+ color: #aa759f;
+ }
+
+ .highlight .sr {
+ color: #75b5aa;
+ }
+
+ .highlight .si {
+ color: #b76d45;
+ }
+
+ .highlight .se {
+ color: #b76d45;
+ }
+
+ .highlight .nn {
+ color: #f4bf75;
+ }
+
+ .highlight .nc {
+ color: #f4bf75;
+ }
+
+ .highlight .no {
+ color: #f4bf75;
+ }
+
+ .highlight .na {
+ color: #6a9fb5;
+ }
+
+ .highlight .m,
+ .highlight .mb,
+ .highlight .mf,
+ .highlight .mh,
+ .highlight .mi,
+ .highlight .il,
+ .highlight .mo,
+ .highlight .mx {
+ color: #90a959;
+ }
+
+ .highlight .ss {
+ color: #90a959;
+ }
+}
diff --git a/src/styles/themes/_light.scss b/src/styles/themes/_light.scss
new file mode 100644
index 00000000000..48d47558a8f
--- /dev/null
+++ b/src/styles/themes/_light.scss
@@ -0,0 +1,309 @@
+@mixin styles {
+ /* Framework color */
+ --main-bg: white;
+ --mask-bg: #c1c3c5;
+ --main-border-color: #f3f3f3;
+
+ /* Common color */
+ --text-color: #34343c;
+ --text-muted-color: #757575;
+ --text-muted-highlight-color: inherit;
+ --heading-color: #2a2a2a;
+ --label-color: #585858;
+ --blockquote-border-color: #eeeeee;
+ --blockquote-text-color: #757575;
+ --link-color: #0056b2;
+ --link-underline-color: #dee2e6;
+ --button-bg: #ffffff;
+ --btn-border-color: #e9ecef;
+ --btn-backtotop-color: #686868;
+ --btn-backtotop-border-color: #f1f1f1;
+ --checkbox-color: #c5c5c5;
+ --checkbox-checked-color: #07a8f7;
+ --img-bg: radial-gradient(circle, rgb(255 255 255) 0%, rgb(239 239 239) 100%);
+ --shimmer-bg: linear-gradient(
+ 90deg,
+ rgb(250 250 250 / 0%) 0%,
+ rgb(232 230 230 / 100%) 50%,
+ rgb(250 250 250 / 0%) 100%
+ );
+
+ /* Sidebar */
+ --site-title-color: rgb(113 113 113);
+ --site-subtitle-color: #717171;
+ --sidebar-bg: #f6f8fa;
+ --sidebar-border-color: #efefef;
+ --sidebar-muted-color: #545454;
+ --sidebar-active-color: #1d1d1d;
+ --sidebar-hover-bg: rgb(223 233 241 / 64%);
+ --sidebar-btn-bg: white;
+ --sidebar-btn-color: #8e8e8e;
+ --avatar-border-color: white;
+
+ /* Topbar */
+ --topbar-bg: rgb(255 255 255 / 70%);
+ --topbar-text-color: rgb(78 78 78);
+ --search-border-color: rgb(240 240 240);
+ --search-icon-color: #c2c6cc;
+ --input-focus-border-color: #b8b8b8;
+
+ /* Home page */
+ --post-list-text-color: dimgray;
+ --btn-patinator-text-color: #555555;
+ --btn-paginator-hover-color: var(--sidebar-bg);
+
+ /* Posts */
+ --toc-highlight: #0550ae;
+ --toc-popup-border-color: lightgray;
+ --btn-share-color: gray;
+ --btn-share-hover-color: #0d6efd;
+ --card-bg: white;
+ --card-hover-bg: #e2e2e2;
+ --card-shadow: rgb(104 104 104 / 5%) 0 2px 6px 0,
+ rgb(211 209 209 / 15%) 0 0 0 1px;
+ --footnote-target-bg: lightcyan;
+ --tb-odd-bg: #fbfcfd;
+ --tb-border-color: #eaeaea;
+ --dash-color: silver;
+ --kbd-wrap-color: #bdbdbd;
+ --kbd-text-color: var(--text-color);
+ --kbd-bg-color: white;
+ --prompt-text-color: rgb(46 46 46 / 77%);
+ --prompt-tip-bg: rgb(123 247 144 / 20%);
+ --prompt-tip-icon-color: #03b303;
+ --prompt-info-bg: #e1f5fe;
+ --prompt-info-icon-color: #0070cb;
+ --prompt-warning-bg: rgb(255 243 205);
+ --prompt-warning-icon-color: #ef9c03;
+ --prompt-danger-bg: rgb(248 215 218 / 56%);
+ --prompt-danger-icon-color: #df3c30;
+
+ /* Tags */
+ --tag-border: #dee2e6;
+ --tag-shadow: var(--btn-border-color);
+ --tag-hover: rgb(222 226 230);
+ --search-tag-bg: #f8f9fa;
+
+ /* Categories */
+ --categories-border: rgb(0 0 0 / 12.5%);
+ --categories-hover-bg: var(--btn-border-color);
+ --categories-icon-hover-color: darkslategray;
+
+ /* Archive */
+ --timeline-color: rgb(0 0 0 / 7.5%);
+ --timeline-node-bg: #c2c6cc;
+ --timeline-year-dot-color: #ffffff;
+
+ /* --- Custom code light mode colors --- */
+ --language-border-color: #ececec;
+ --highlight-bg-color: #f6f8fa;
+ --highlighter-rouge-color: #3f596f;
+ --highlight-lineno-color: #9e9e9e;
+ --inline-code-bg: rgb(25 25 28 / 5%);
+ --code-color: #3a3a3a;
+ --code-header-text-color: #a3a3a3;
+ --code-header-muted-color: #e5e5e5;
+ --code-header-icon-color: #c9c8c8;
+ --clipboard-checked-color: #43c743;
+
+ [class^='prompt-'] {
+ --link-underline-color: rgb(219 216 216);
+ }
+
+ .dark {
+ display: none;
+ }
+
+ /* --- Syntax highlight theme from `rougify style github` --- */
+
+ .highlight table td {
+ padding: 5px;
+ }
+
+ .highlight table pre {
+ margin: 0;
+ }
+
+ .highlight,
+ .highlight .w {
+ color: #24292f;
+ background-color: #f6f8fa;
+ }
+
+ .highlight .k,
+ .highlight .kd,
+ .highlight .kn,
+ .highlight .kp,
+ .highlight .kr,
+ .highlight .kt,
+ .highlight .kv {
+ color: #cf222e;
+ }
+
+ .highlight .gr {
+ color: #f6f8fa;
+ }
+
+ .highlight .gd {
+ color: #82071e;
+ background-color: #ffebe9;
+ }
+
+ .highlight .nb {
+ color: #953800;
+ }
+
+ .highlight .nc {
+ color: #953800;
+ }
+
+ .highlight .no {
+ color: #953800;
+ }
+
+ .highlight .nn {
+ color: #953800;
+ }
+
+ .highlight .sr {
+ color: #116329;
+ }
+
+ .highlight .na {
+ color: #116329;
+ }
+
+ .highlight .nt {
+ color: #116329;
+ }
+
+ .highlight .gi {
+ color: #116329;
+ background-color: #dafbe1;
+ }
+
+ .highlight .kc {
+ color: #0550ae;
+ }
+
+ .highlight .l,
+ .highlight .ld,
+ .highlight .m,
+ .highlight .mb,
+ .highlight .mf,
+ .highlight .mh,
+ .highlight .mi,
+ .highlight .il,
+ .highlight .mo,
+ .highlight .mx {
+ color: #0550ae;
+ }
+
+ .highlight .sb {
+ color: #0550ae;
+ }
+
+ .highlight .bp {
+ color: #0550ae;
+ }
+
+ .highlight .ne {
+ color: #0550ae;
+ }
+
+ .highlight .nl {
+ color: #0550ae;
+ }
+
+ .highlight .py {
+ color: #0550ae;
+ }
+
+ .highlight .nv,
+ .highlight .vc,
+ .highlight .vg,
+ .highlight .vi,
+ .highlight .vm {
+ color: #0550ae;
+ }
+
+ .highlight .o,
+ .highlight .ow {
+ color: #0550ae;
+ }
+
+ .highlight .gh {
+ color: #0550ae;
+ font-weight: bold;
+ }
+
+ .highlight .gu {
+ color: #0550ae;
+ font-weight: bold;
+ }
+
+ .highlight .s,
+ .highlight .sa,
+ .highlight .sc,
+ .highlight .dl,
+ .highlight .sd,
+ .highlight .s2,
+ .highlight .se,
+ .highlight .sh,
+ .highlight .sx,
+ .highlight .s1,
+ .highlight .ss {
+ color: #0a3069;
+ }
+
+ .highlight .nd {
+ color: #8250df;
+ }
+
+ .highlight .nf,
+ .highlight .fm {
+ color: #8250df;
+ }
+
+ .highlight .err {
+ color: #f6f8fa;
+ background-color: #82071e;
+ }
+
+ .highlight .c,
+ .highlight .ch,
+ .highlight .cd,
+ .highlight .cm,
+ .highlight .cp,
+ .highlight .cpf,
+ .highlight .c1,
+ .highlight .cs {
+ color: #68717a;
+ }
+
+ .highlight .gl {
+ color: #68717a;
+ }
+
+ .highlight .gt {
+ color: #68717a;
+ }
+
+ .highlight .ni {
+ color: #24292f;
+ }
+
+ .highlight .si {
+ color: #24292f;
+ }
+
+ .highlight .ge {
+ color: #24292f;
+ font-style: italic;
+ }
+
+ .highlight .gs {
+ color: #24292f;
+ font-weight: bold;
+ }
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 00000000000..ce67e1348e9
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "extends": "astro/tsconfigs/strict",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["src/*"],
+ "@components/*": ["src/components/*"],
+ "@layouts/*": ["src/layouts/*"],
+ "@data/*": ["src/data/*"],
+ "@styles/*": ["src/styles/*"],
+ "@scripts/*": ["src/scripts/*"]
+ }
+ },
+ "exclude": [
+ "_includes",
+ "_layouts",
+ "_javascript",
+ "_plugins",
+ "_posts",
+ "_sass",
+ "_tabs",
+ "assets",
+ "tools",
+ "node_modules"
+ ]
+}