Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
|
053e54838f |
77
.gitignore
vendored
|
@ -1,23 +1,68 @@
|
|||
# build output
|
||||
dist/
|
||||
# Build and Release Folders
|
||||
bin/
|
||||
bin-debug/
|
||||
bin-release/
|
||||
[Oo]bj/ # FlashDevelop obj
|
||||
[Bb]in/ # FlashDevelop bin
|
||||
|
||||
# generated types
|
||||
.astro/
|
||||
# Other files and folders
|
||||
.settings/
|
||||
.hugo_build.lock
|
||||
.nova/
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
# Executables
|
||||
*.swf
|
||||
*.air
|
||||
*.ipa
|
||||
*.apk
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
# Hugo
|
||||
public/
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
.env.production
|
||||
# Backup Files
|
||||
*.markdown~
|
||||
*.md~
|
||||
|
||||
# macOS-specific files
|
||||
# Apache
|
||||
.htpasswd
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Build directories
|
||||
public
|
||||
dist
|
||||
|
||||
# Dependency directory
|
||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||
node_modules
|
||||
package-lock.json
|
||||
bower_components
|
||||
|
||||
# Mac File System File...utterly useless to anyone but me.
|
||||
.DS_Store
|
||||
|
||||
.vercel
|
||||
# AWS stuff for publishing static files
|
||||
.aws-credentials.json
|
||||
.awspublish*
|
3
.vscode/extensions.json
vendored
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"recommendations": ["biomejs.biome", "astro-build.astro-vscode"]
|
||||
}
|
22
.vscode/settings.json
vendored
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[javascriptreact]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": "explicit",
|
||||
"quickfix.biome": "always",
|
||||
"source.organizeImports.biome": "always"
|
||||
},
|
||||
"frontMatter.dashboard.openOnStart": false
|
||||
}
|
21
LICENSE
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2024 saicaca
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
58
README.es.md
|
@ -1,58 +0,0 @@
|
|||
# 🍥Fuwari
|
||||
|
||||
Un tema estático para blogs construido con [Astro](https://astro.build).
|
||||
|
||||
[**🖥️ Demostración en Vivo (Vercel)**](https://fuwari.vercel.app) /
|
||||
[**📦 Versión Antigua de Hexo**](https://github.com/saicaca/hexo-theme-vivia) /
|
||||
|
||||
> Versión del README: `2024-04-07`
|
||||
|
||||

|
||||
|
||||
## ✨ Características
|
||||
|
||||
- [x] Construido con [Astro](https://astro.build) y [Tailwind CSS](https://tailwindcss.com)
|
||||
- [x] Animaciones suaves y transiciones de página
|
||||
- [x] Modo claro / oscuro
|
||||
- [x] Colores del tema y banner personalizables
|
||||
- [x] Diseño responsivo
|
||||
- [ ] Comentarios
|
||||
- [x] Buscador
|
||||
- [ ] TOC (Tabla de Contenidos)
|
||||
|
||||
## 🚀 Cómo Usar
|
||||
|
||||
1. [Genera un nuevo repositorio](https://github.com/saicaca/fuwari/generate) desde esta plantilla o haz un fork de este repositorio.
|
||||
2. Para editar tu blog localmente, clona tu repositorio, ejecuta `pnpm install` y `pnpm add sharp` para instalar las dependencias.
|
||||
- Instala [pnpm](https://pnpm.io) `npm install -g pnpm` si aún no lo tienes.
|
||||
3. Edita el archivo de configuración `src/config.ts` para personalizar tu blog.
|
||||
4. Ejecuta `pnpm new-post <nombre-de-archivo>` para crear una nueva entrada y edítala en `src/content/posts/`.
|
||||
5. Despliega tu blog en Vercel, Netlify, GitHub Pages, etc., siguiendo [las guías](https://docs.astro.build/en/guides/deploy/). Necesitas editar la configuración del sitio en `astro.config.mjs` antes del despliegue.
|
||||
|
||||
## ⚙️ Cabecera de las Entradas
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Mi Primer Post en el Blog
|
||||
published: 2023-09-09
|
||||
description: Esta es la primera entrada de mi nuevo blog con Astro.
|
||||
image: /images/cover.jpg
|
||||
tags: [Foo, Bar]
|
||||
category: Front-end
|
||||
draft: false
|
||||
---
|
||||
```
|
||||
|
||||
## 🧞 Comandos
|
||||
|
||||
Todos los comandos se ejecutan desde la raíz del proyecto, desde una terminal:
|
||||
|
||||
| Comando | Acción |
|
||||
|:------------------------------------|:--------------------------------------------------|
|
||||
| `pnpm install` y `pnpm add sharp` | Instala las dependencias |
|
||||
| `pnpm dev` | Inicia el servidor de desarrollo local en `localhost:4321` |
|
||||
| `pnpm build` | Compila tu web para producción en `./dist/` |
|
||||
| `pnpm preview` | Previsualiza la web localmente, antes del despliegue |
|
||||
| `pnpm new-post <nombre-de-archivo>` | Crea una nueva entrada |
|
||||
| `pnpm astro ...` | Ejecuta comandos CLI como `astro add`, `astro check` |
|
||||
| `pnpm astro --help` | Obtén ayuda para usar el CLI de Astro |
|
|
@ -1,55 +0,0 @@
|
|||
# 🍥Fuwari
|
||||
|
||||
[Astro](https://astro.build)で構築された静的ブログテンプレート
|
||||
|
||||
[**🖥️ライブデモ (Vercel)**](https://fuwari.vercel.app) / [**🌏中文**](https://github.com/saicaca/fuwari/blob/main/README.zh-CN.md) / [**🌏日本語**](https://github.com/saicaca/fuwari/blob/main/README.ja-JP.md) / [**📦旧Hexoバージョン**](https://github.com/saicaca/hexo-theme-vivia)
|
||||
|
||||

|
||||
|
||||
## ✨ 特徴
|
||||
|
||||
- [x] [Astro](https://astro.build)及び [Tailwind CSS](https://tailwindcss.com)で構築
|
||||
- [x] スムーズなアニメーションとページ遷移
|
||||
- [x] ライト/ダークテーマ対応
|
||||
- [x] カスタマイズ可能なテーマカラーとバナー
|
||||
- [x] レスポンシブデザイン
|
||||
- [ ] コメント機能
|
||||
- [x] 検索機能
|
||||
- [ ] 目次
|
||||
|
||||
## 🚀 使用方法
|
||||
|
||||
1. [テンプレート](https://github.com/saicaca/fuwari/generate)から新しいリポジトリを作成するかCloneをします。
|
||||
2. ブログをローカルで編集するには、リポジトリをクローンした後、`pnpm install` と `pnpm add sharp` を実行して依存関係をインストールします。
|
||||
- [pnpm](https://pnpm.io)がインストールされていない場合は `npm install -g pnpm` で導入可能です。
|
||||
3. `src/config.ts`ファイルを編集する事でブログを自分好みにカスタマイズ出来ます。
|
||||
4. `pnpm new-post <filename>`で新しい記事を作成し、`src/content/posts/`.フォルダ内で編集します。
|
||||
5. 作成したブログをVercel、Netlify、GitHub Pagesなどにデプロイするには[ガイド](https://docs.astro.build/ja/guides/deploy/)に従って下さい。加えて、別途デプロイを行う前に`astro.config.mjs`を編集してサイト構成を変更する必要があります。
|
||||
|
||||
## ⚙️ 記事のフロントマター
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: My First Blog Post
|
||||
published: 2023-09-09
|
||||
description: This is the first post of my new Astro blog.
|
||||
image: /images/cover.jpg
|
||||
tags: [Foo, Bar]
|
||||
category: Front-end
|
||||
draft: false
|
||||
---
|
||||
```
|
||||
|
||||
## 🧞 コマンド
|
||||
|
||||
すべてのコマンドは、ターミナルでプロジェクトのルートから実行する必要があります:
|
||||
|
||||
| Command | Action |
|
||||
|:------------------------------------|:-------------------------------------------------|
|
||||
| `pnpm install` AND `pnpm add sharp` | 依存関係のインストール |
|
||||
| `pnpm dev` | `localhost:4321`で開発用ローカルサーバーを起動 |
|
||||
| `pnpm build` | `./dist/`にビルド内容を出力 |
|
||||
| `pnpm preview` | デプロイ前の内容をローカルでプレビュー |
|
||||
| `pnpm new-post <filename>` | 新しい投稿を作成 |
|
||||
| `pnpm astro ...` | `astro add`, `astro check`の様なコマンドを実行する際に使用 |
|
||||
| `pnpm astro --help` | Astro CLIのヘルプを表示 |
|
57
README.ko.md
|
@ -1,57 +0,0 @@
|
|||
# 🍥Fuwari
|
||||
|
||||
[Astro](https://astro.build)로 구축된 정적 블로그 템플릿입니다.
|
||||
|
||||
[**🖥️미리보기 (Vercel)**](https://fuwari.vercel.app) /
|
||||
[**📦Old Hexo Version**](https://github.com/saicaca/hexo-theme-vivia)
|
||||
|
||||
> README 버전: `2024-04-07`
|
||||
|
||||

|
||||
|
||||
## ✨ 특징
|
||||
|
||||
- [x] [Astro](https://astro.build) 및 [Tailwind CSS](https://tailwindcss.com)로 구축됨
|
||||
- [x] 부드러운 애니메이션 및 페이지 전환
|
||||
- [x] 라이트 모드 / 다크 모드
|
||||
- [x] 사용자 정의 가능한 테마 색상 및 배너
|
||||
- [x] 반응형 디자인
|
||||
- [ ] 댓글
|
||||
- [x] 검색
|
||||
- [ ] 목차
|
||||
## 🚀 사용하는 방법
|
||||
|
||||
1. 이 템플릿에서 [새 저장소를 생성](https://github.com/saicaca/fuwari/generate)하거나 이 저장소를 포크하세요.
|
||||
2. 블로그를 로컬에서 편집하려면 저장소를 복제하고 `pnpm install` 및 `pnpm add sharp`를 실행하여 종속성을 설치하세요.
|
||||
- 아직 [pnpm](https://pnpm.io)을 설치하지 않았다면 `npm install -g pnpm`을 실행하여 [pnpm](https://pnpm.io)을 설치하세요.
|
||||
3. 블로그를 사용자 정의하려면 `src/config.ts` 구성 파일을 편집하세요.
|
||||
4. `pnpm new-post <filename>`을 실행하여 새 게시물을 만들고 `src/content/posts/`에서 편집하세요.
|
||||
5. [가이드](https://docs.astro.build/en/guides/deploy/)에 따라 블로그를 Vercel, Netlify, GitHub 페이지 등에 배포하세요. 배포하기 전에 `astro.config.mjs`에서 사이트 구성을 편집해야 합니다.
|
||||
|
||||
## ⚙️ 게시물의 머리말 설정
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: 내 첫 블로그 게시물
|
||||
published: 2023-09-09
|
||||
description: 내 새로운 Astro 블로그의 첫 번째 게시물입니다!
|
||||
image: /images/cover.jpg
|
||||
tags: [푸, 바, 오]
|
||||
category: 앞-끝
|
||||
draft: false
|
||||
---
|
||||
```
|
||||
|
||||
## 🧞 명령어
|
||||
|
||||
모든 명령어는 프로젝트 최상단, 터미널에서 실행됩니다:
|
||||
|
||||
| Command | Action |
|
||||
|:------------------------------------|:-------------------------------------------------|
|
||||
| `pnpm install` AND `pnpm add sharp` | 종속성을 설치합니다. |
|
||||
| `pnpm dev` | `localhost:4321`에서 로컬 개발 서버를 시작합니다. |
|
||||
| `pnpm build` | `./dist/`에 프로덕션 사이트를 구축합니다. |
|
||||
| `pnpm preview` | 배포하기 전에 로컬에서 빌드 미리보기 |
|
||||
| `pnpm new-post <filename>` | 새 게시물 작성 |
|
||||
| `pnpm astro ...` | `astro add`, `astro check`와 같은 CLI 명령어 실행 |
|
||||
| `pnpm astro --help` | Astro CLI를 사용하여 도움 받기 |
|
55
README.md
|
@ -1,55 +0,0 @@
|
|||
# 🍥Fuwari
|
||||
|
||||
A static blog template built with [Astro](https://astro.build).
|
||||
|
||||
[**🖥️Live Demo (Vercel)**](https://fuwari.vercel.app) / [**🌏中文 README**](https://github.com/saicaca/fuwari/blob/main/README.zh-CN.md) / [**🌏日本語 README**](https://github.com/saicaca/fuwari/blob/main/README.ja-JP.md) / [**📦Old Hexo Version**](https://github.com/saicaca/hexo-theme-vivia)
|
||||
|
||||

|
||||
|
||||
## ✨ Features
|
||||
|
||||
- [x] Built with [Astro](https://astro.build) and [Tailwind CSS](https://tailwindcss.com)
|
||||
- [x] Smooth animations and page transitions
|
||||
- [x] Light / dark mode
|
||||
- [x] Customizable theme colors & banner
|
||||
- [x] Responsive design
|
||||
- [ ] Comments
|
||||
- [x] Search
|
||||
- [ ] TOC
|
||||
|
||||
## 🚀 How to Use
|
||||
|
||||
1. [Generate a new repository](https://github.com/saicaca/fuwari/generate) from this template or fork this repository.
|
||||
2. To edit your blog locally, clone your repository, run `pnpm install` AND `pnpm add sharp` to install dependencies.
|
||||
- Install [pnpm](https://pnpm.io) `npm install -g pnpm` if you haven't.
|
||||
3. Edit the config file `src/config.ts` to customize your blog.
|
||||
4. Run `pnpm new-post <filename>` to create a new post and edit it in `src/content/posts/`.
|
||||
5. Deploy your blog to Vercel, Netlify, GitHub Pages, etc. following [the guides](https://docs.astro.build/en/guides/deploy/). You need to edit the site configuration in `astro.config.mjs` before deployment.
|
||||
|
||||
## ⚙️ Frontmatter of Posts
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: My First Blog Post
|
||||
published: 2023-09-09
|
||||
description: This is the first post of my new Astro blog.
|
||||
image: /images/cover.jpg
|
||||
tags: [Foo, Bar]
|
||||
category: Front-end
|
||||
draft: false
|
||||
---
|
||||
```
|
||||
|
||||
## 🧞 Commands
|
||||
|
||||
All commands are run from the root of the project, from a terminal:
|
||||
|
||||
| Command | Action |
|
||||
|:------------------------------------|:-------------------------------------------------|
|
||||
| `pnpm install` AND `pnpm add sharp` | Installs dependencies |
|
||||
| `pnpm dev` | Starts local dev server at `localhost:4321` |
|
||||
| `pnpm build` | Build your production site to `./dist/` |
|
||||
| `pnpm preview` | Preview your build locally, before deploying |
|
||||
| `pnpm new-post <filename>` | Create a new post |
|
||||
| `pnpm astro ...` | Run CLI commands like `astro add`, `astro check` |
|
||||
| `pnpm astro --help` | Get help using the Astro CLI |
|
59
README.th.md
|
@ -1,59 +0,0 @@
|
|||
# 🍥Fuwari
|
||||
|
||||
แม่แบบสำหรับเว็บบล็อกแบบ static สร้างด้วย [Astro](https://astro.build)
|
||||
|
||||
[**🖥️ ตัวอย่างการใช้งานจริง (Vercel)**](https://fuwari.vercel.app) /
|
||||
[**📦 เวอร์ชั่นเก่าสำหรับ Hexo**](https://github.com/saicaca/hexo-theme-vivia)
|
||||
|
||||
> เวอร์ชั่นของ README: `2024-09-10`
|
||||
|
||||

|
||||
|
||||
## ✨ คุณสมบัติ
|
||||
|
||||
- [x] สร้างด้วย [Astro](https://astro.build) และ [Tailwind CSS](https://tailwindcss.com)
|
||||
- [x] มีอนิเมชั่นและการเปลี่ยนหน้าอย่างลื่นไหล
|
||||
- [x] รองรับโหมดสว่าง / โหมดมืด
|
||||
- [x] ปรับแต่งสีธีมและแบนเนอร์ได้
|
||||
- [x] Responsive design (หน้าตาเว็บปรับเปลี่ยนตามขนาดจอ)
|
||||
- [ ] การแสดงความคิดเห็น
|
||||
- [x] การค้นหา
|
||||
- [ ] TOC (สารบัญ)
|
||||
|
||||
## 🚀 วิธีใช้งาน
|
||||
|
||||
1. [Generate repository ใหม่](https://github.com/saicaca/fuwari/generate)ขึ้นมาจากแม่แบบนี้ หรือจะ fork repository นี้ก็ได้
|
||||
2. เริ่มแก้ไขบล็อกของคุณแบบ local โดยการ clone repository ของคุณ (จากข้อ 1) ไว้ในเครื่องของคุณ แล้วรันคำสั่ง `pnpm install` และ `pnpm add sharp` เพื่อติดตั้ง dependencies ที่จำเป็น
|
||||
- ติดตั้ง [pnpm](https://pnpm.io) ด้วยคำสั่ง `npm install -g pnpm` ถ้ายังไม่เคยติดตั้ง
|
||||
3. แก้ไขไฟล์การตั้งค่า `src/config.ts` เพื่อปรับแต่งบล็อกของคุณ
|
||||
4. รันคำสั่ง `pnpm new-post <filename>` เพื่อสร้างโพสต์ใหม่ใน `src/content/posts/` และแก้ไขไฟล์โพสต์นั้นๆ ให้สมบูรณ์
|
||||
5. Deploy เว็บบล็อกของคุณไปยัง Vercel, Netlify, GitHub Pages หรือบริการอื่นๆ โดยอ้างอิงวิธีการจาก[คู่มือนี้](https://docs.astro.build/en/guides/deploy/) อย่าลืมแก้ไขการตั้งค่าเว็บไซต์ในไฟล์ `astro.config.mjs` ก่อนที่คุณจะ deploy เว็บ
|
||||
|
||||
## ⚙️ Frontmatter ของโพสต์
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: โพสต์แรกของฉัน
|
||||
published: 2023-09-09
|
||||
description: นี่คือโพสต์แรกของเว็บบล็อก Astro อันใหม่ของฉัน
|
||||
image: ./cover.jpg
|
||||
tags: [Foo, Bar]
|
||||
category: Front-end
|
||||
draft: false
|
||||
lang: jp # เขียนค่านี้เมื่อภาษาของโพสต์นั้นๆ แตกต่างจากภาษาของเว็บไซต์ที่ตั้งค่าไว้ใน `config.ts` เท่านั้น
|
||||
---
|
||||
```
|
||||
|
||||
## 🧞 คำสั่ง
|
||||
|
||||
คำสั่งที่รันได้ใน terminal จาก root ของโปรเจค:
|
||||
|
||||
| คำสั่ง | ผลที่เกิด |
|
||||
|:------------------------------------|:--------------------------------------------------|
|
||||
| `pnpm install` และ `pnpm add sharp` | ติดตั้ง dependencies |
|
||||
| `pnpm dev` | เปิดเซิร์ฟเวอร์เพื่อพัฒนาเว็บแบบ local ที่ `localhost:4321` |
|
||||
| `pnpm build` | Build เว็บไซต์แบบพร้อมใช้งานจริงไปยังโฟลเดอร์ `./dist/` |
|
||||
| `pnpm preview` | ดูตัวอย่าง build ของคุณแบบ local ก่อนที่จะ deploy จริง |
|
||||
| `pnpm new-post <filename>` | สร้างโพสต์ใหม่ |
|
||||
| `pnpm astro ...` | รันคำสั่ง CLI เช่น `astro add`, `astro check` |
|
||||
| `pnpm astro --help` | ดูข้อมูลเพิ่มเติมเกี่ยวกับ Astro CLI |
|
|
@ -1,55 +0,0 @@
|
|||
# 🍥Fuwari
|
||||
|
||||
基于 [Astro](https://astro.build) 开发的静态博客模板。
|
||||
|
||||
[**🖥️在线预览(Vercel)**](https://fuwari.vercel.app) / [**🌏English README**](https://github.com/saicaca/fuwari) / [**🌏日本語 README**](https://github.com/saicaca/fuwari/blob/main/README.ja-JP.md) / [**📦旧 Hexo 版本**](https://github.com/saicaca/hexo-theme-vivia)
|
||||
|
||||

|
||||
|
||||
## ✨ 功能特性
|
||||
|
||||
- [x] 基于 Astro 和 Tailwind CSS 开发
|
||||
- [x] 流畅的动画和页面过渡
|
||||
- [x] 亮色 / 暗色模式
|
||||
- [x] 自定义主题色和横幅图片
|
||||
- [x] 响应式设计
|
||||
- [ ] 评论
|
||||
- [x] 搜索
|
||||
- [ ] 文内目录
|
||||
|
||||
## 🚀 使用方法
|
||||
|
||||
1. 使用此模板[生成新仓库](https://github.com/saicaca/fuwari/generate)或 Fork 此仓库
|
||||
2. 进行本地开发,Clone 新的仓库,执行 `pnpm install` 和 `pnpm add sharp` 以安装依赖
|
||||
- 若未安装 [pnpm](https://pnpm.io),执行 `npm install -g pnpm`
|
||||
3. 通过配置文件 `src/config.ts` 自定义博客
|
||||
4. 执行 `pnpm new-post <filename>` 创建新文章,并在 `src/content/posts/` 目录中编辑
|
||||
5. 参考[官方指南](https://docs.astro.build/zh-cn/guides/deploy/)将博客部署至 Vercel, Netlify, GitHub Pages 等;部署前需编辑 `astro.config.mjs` 中的站点设置。
|
||||
|
||||
## ⚙️ 文章 Frontmatter
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: My First Blog Post
|
||||
published: 2023-09-09
|
||||
description: This is the first post of my new Astro blog.
|
||||
image: /images/cover.jpg
|
||||
tags: [Foo, Bar]
|
||||
category: Front-end
|
||||
draft: false
|
||||
---
|
||||
```
|
||||
|
||||
## 🧞 指令
|
||||
|
||||
下列指令均需要在项目根目录执行:
|
||||
|
||||
| Command | Action |
|
||||
|:----------------------------------|:----------------------------------|
|
||||
| `pnpm install` 并 `pnpm add sharp` | 安装依赖 |
|
||||
| `pnpm dev` | 在 `localhost:4321` 启动本地开发服务器 |
|
||||
| `pnpm build` | 构建网站至 `./dist/` |
|
||||
| `pnpm preview` | 本地预览已构建的网站 |
|
||||
| `pnpm new-post <filename>` | 创建新文章 |
|
||||
| `pnpm astro ...` | 执行 `astro add`, `astro check` 等指令 |
|
||||
| `pnpm astro --help` | 显示 Astro CLI 帮助 |
|
6
archetypes/default.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: "{{ replace .Name "-" " " | title }}"
|
||||
date: {{ .Date }}
|
||||
draft: true
|
||||
---
|
||||
|
192
astro.config.mjs
|
@ -1,192 +0,0 @@
|
|||
import sitemap from '@astrojs/sitemap'
|
||||
import svelte from '@astrojs/svelte'
|
||||
import tailwind from '@astrojs/tailwind'
|
||||
import swup from '@swup/astro'
|
||||
import Compress from 'astro-compress'
|
||||
import icon from 'astro-icon'
|
||||
import { defineConfig } from 'astro/config'
|
||||
import Color from 'colorjs.io'
|
||||
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
|
||||
import rehypeComponents from 'rehype-components' /* Render the custom directive content */
|
||||
import rehypeKatex from 'rehype-katex'
|
||||
import rehypeSlug from 'rehype-slug'
|
||||
import remarkDirective from 'remark-directive' /* Handle directives */
|
||||
import remarkGithubAdmonitionsToDirectives from 'remark-github-admonitions-to-directives'
|
||||
import remarkMath from 'remark-math'
|
||||
import { AdmonitionComponent } from './src/plugins/rehype-component-admonition.mjs'
|
||||
import { GithubCardComponent } from './src/plugins/rehype-component-github-card.mjs'
|
||||
import { parseDirectiveNode } from './src/plugins/remark-directive-rehype.js'
|
||||
import { remarkReadingTime } from './src/plugins/remark-reading-time.mjs'
|
||||
|
||||
const oklchToHex = str => {
|
||||
const DEFAULT_HUE = 250
|
||||
const regex = /-?\d+(\.\d+)?/g
|
||||
const matches = str.string.match(regex)
|
||||
const lch = [matches[0], matches[1], DEFAULT_HUE]
|
||||
return new Color('oklch', lch).to('srgb').toString({
|
||||
format: 'hex',
|
||||
})
|
||||
}
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
site: 'https://hack13.blog/',
|
||||
base: '/',
|
||||
trailingSlash: 'always',
|
||||
redirects: {
|
||||
'/feed': '/rss.xml',
|
||||
'/2010/06/new-blog': '/posts/new-blog',
|
||||
'/2012/04/been-a-while': '/posts/been-a-while',
|
||||
'/2012/04/my-take-on-opensim-grids': '/posts/my-take-on-opensim-grids',
|
||||
'/2012/04/my-vision-of-the-hypergrid': '/posts/my-vision-of-the-hypergrid',
|
||||
'/2012/04/we-have-hypergrid-use-it': '/posts/we-have-hypergrid-use-it',
|
||||
'/2012/05/coming-changes': '/posts/coming-changes',
|
||||
'/2012/06/timothys-thoughts': '/posts/timothys-thoughts',
|
||||
'/2012/07/finding-my-place': '/posts/finding-my-place',
|
||||
'/2012/07/lil-about-me-some-rage': '/posts/lil-about-me-some-rage',
|
||||
'/2012/08/battle-of-business-vs-opensource':
|
||||
'/posts/2012-08-09-battle-of-business-vs-opensource',
|
||||
'/2012/12/new-years-resolutions': '/posts/2012-12-31-new-years-resolutions',
|
||||
'/2013/02/explaining-opensim-memory-usage':
|
||||
'/posts/2013-02-11-explaining-opensim-memory-usage',
|
||||
'/2013/02/thank-you': '/posts/2013-02-13-thank-you',
|
||||
'/2013/02/needing-rest': '/posts/2013-02-20-needing-rest',
|
||||
'/2013/02/top-10-reasons-not-to-give-up-on-aurora-sim':
|
||||
'/posts/2013-02-21-top-10-reasons-not-to-give-up-on-aurora-sim',
|
||||
'/2013/02/who-is-timothy-vyperhoxleyrogers':
|
||||
'/posts/2013-02-23-who-is-timothy-vyperhoxleyrogers',
|
||||
'/2013/03/why-i-closed-aurorascape':
|
||||
'/posts/2013-03-05-why-i-closed-aurorascape',
|
||||
'/2013/03/closed-vs-open-really': '/posts/2013-03-11-closed-vs-open-really',
|
||||
'/2013/04/moving-up-around': '/posts/2013-04-08-moving-up-around',
|
||||
'/2013/04/my-clocks-are-ticking': '/posts/2013-04-26-my-clocks-are-ticking',
|
||||
'/2013/06/upset-with-stiffled-innovation':
|
||||
'/posts/2013-06-19-upset-with-stiffled-innovation',
|
||||
'/2013/08/depression': '/posts/2013-08-12-depression',
|
||||
'/2013/09/my-response-to-kitely-marketplace':
|
||||
'/posts/2013-09-02-my-response-to-kitely-marketplace',
|
||||
'/2013/11/why-i-dont-use-the-cloud':
|
||||
'/posts/2013-11-03-why-i-dont-use-the-cloud',
|
||||
'/2016/01/moved-to-wordpress': '/posts/2016-01-04-moved-to-wordpress',
|
||||
'/2018/01/where-has-tim-been': '/posts/2018-01-06-where-has-tim-been',
|
||||
'/2018/01/taking-control-of-my-cloud-storage':
|
||||
'/posts/2018-01-14-taking-control-of-my-cloud-storage',
|
||||
'/2018/04/finding-my-linux-distro':
|
||||
'/posts/2018-04-26-finding-my-linux-distro',
|
||||
'/2019/01/2019-goals': '/posts/2019-01-26-2019-goals',
|
||||
'/2019/01/speeding-up-zadaroo-files':
|
||||
'/posts/2019-01-28-speeding-up-zadaroo-files',
|
||||
'/2021/10/cloudflare-workers-and-pages':
|
||||
'/posts/2021-10-29-cloudflare-workers-and-pages',
|
||||
'/2022/02/struggling-with-anxiety':
|
||||
'/posts/2022-02-02-struggling-with-anxiety',
|
||||
'/2022/02/nft-polarization': '/posts/2022-02-17-nft-polarization',
|
||||
'/2022/04/neosvr-event-hosting': '/posts/2022-04-17-neosvr-event-hosting',
|
||||
'/2022/05/continuing-to-find-myself':
|
||||
'/posts/2022-05-08-continuing-to-find-myself',
|
||||
'/2023/05/decentralized-protocols':
|
||||
'/posts/2023-05-03-decentralized-protocols',
|
||||
'/2023/09/perspectives': '/posts/2023-09-16-upset-over-crypto',
|
||||
'/2023/12/mff-2023-fedi-panel': '/posts/2023-12-06-mff-2023-panel',
|
||||
},
|
||||
integrations: [
|
||||
tailwind(),
|
||||
swup({
|
||||
theme: false,
|
||||
animationClass: 'transition-',
|
||||
containers: ['main'],
|
||||
smoothScrolling: true,
|
||||
cache: true,
|
||||
preload: true,
|
||||
accessibility: true,
|
||||
globalInstance: true,
|
||||
}),
|
||||
icon({
|
||||
include: {
|
||||
'material-symbols': ['*'],
|
||||
'fa6-brands': ['*'],
|
||||
'fa6-regular': ['*'],
|
||||
'fa6-solid': ['*'],
|
||||
},
|
||||
}),
|
||||
Compress({
|
||||
Image: false,
|
||||
}),
|
||||
svelte(),
|
||||
sitemap(),
|
||||
],
|
||||
markdown: {
|
||||
remarkPlugins: [
|
||||
remarkMath,
|
||||
remarkReadingTime,
|
||||
remarkGithubAdmonitionsToDirectives,
|
||||
remarkDirective,
|
||||
parseDirectiveNode,
|
||||
],
|
||||
rehypePlugins: [
|
||||
rehypeKatex,
|
||||
rehypeSlug,
|
||||
[
|
||||
rehypeComponents,
|
||||
{
|
||||
components: {
|
||||
github: GithubCardComponent,
|
||||
note: (x, y) => AdmonitionComponent(x, y, 'note'),
|
||||
tip: (x, y) => AdmonitionComponent(x, y, 'tip'),
|
||||
important: (x, y) => AdmonitionComponent(x, y, 'important'),
|
||||
caution: (x, y) => AdmonitionComponent(x, y, 'caution'),
|
||||
warning: (x, y) => AdmonitionComponent(x, y, 'warning'),
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
rehypeAutolinkHeadings,
|
||||
{
|
||||
behavior: 'append',
|
||||
properties: {
|
||||
className: ['anchor'],
|
||||
},
|
||||
content: {
|
||||
type: 'element',
|
||||
tagName: 'span',
|
||||
properties: {
|
||||
className: ['anchor-icon'],
|
||||
'data-pagefind-ignore': true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value: '#',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
vite: {
|
||||
build: {
|
||||
rollupOptions: {
|
||||
onwarn(warning, warn) {
|
||||
// temporarily suppress this warning
|
||||
if (
|
||||
warning.message.includes('is dynamically imported by') &&
|
||||
warning.message.includes('but also statically imported by')
|
||||
) {
|
||||
return
|
||||
}
|
||||
warn(warning)
|
||||
},
|
||||
},
|
||||
},
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
stylus: {
|
||||
define: {
|
||||
oklchToHex: oklchToHex,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
66
biome.json
|
@ -1,66 +0,0 @@
|
|||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.4.1/schema.json",
|
||||
"extends": [],
|
||||
"files": { "ignoreUnknown": true },
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"formatWithErrors": false,
|
||||
"ignore": [],
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineWidth": 80
|
||||
},
|
||||
"javascript": {
|
||||
"parser": {
|
||||
"unsafeParameterDecoratorsEnabled": true
|
||||
},
|
||||
"formatter": {
|
||||
"quoteStyle": "single",
|
||||
"jsxQuoteStyle": "single",
|
||||
"trailingComma": "all",
|
||||
"semicolons": "asNeeded",
|
||||
"arrowParentheses": "asNeeded"
|
||||
}
|
||||
},
|
||||
"json": {
|
||||
"parser": { "allowComments": true },
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineWidth": 80
|
||||
}
|
||||
},
|
||||
"linter": {
|
||||
"ignore": [],
|
||||
"rules": {
|
||||
"a11y": {
|
||||
"recommended": true
|
||||
},
|
||||
"complexity": {
|
||||
"recommended": true
|
||||
},
|
||||
"correctness": {
|
||||
"recommended": true
|
||||
},
|
||||
"performance": {
|
||||
"recommended": true
|
||||
},
|
||||
"security": {
|
||||
"recommended": true
|
||||
},
|
||||
"style": {
|
||||
"recommended": true
|
||||
},
|
||||
"suspicious": {
|
||||
"recommended": true
|
||||
},
|
||||
"nursery": {
|
||||
"recommended": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
config.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
baseURL = "https://hack13.me"
|
||||
languageCode = "en-us"
|
||||
title = "Hack13 Site"
|
||||
theme = "hacksite"
|
||||
sectionPagesMenu = "main"
|
||||
|
||||
[menu]
|
||||
[[menu.main]]
|
||||
identifier = "home"
|
||||
name = "Home"
|
||||
title = "home"
|
||||
weight = "10"
|
||||
url = "/"
|
||||
[[menu.main]]
|
||||
identifier = "posts"
|
||||
name = "Blog"
|
||||
title = "posts"
|
||||
weight = "15"
|
||||
url = "/posts/"
|
53
content/about.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
title: "About Me"
|
||||
menu:
|
||||
main:
|
||||
weight: 40
|
||||
---
|
||||
# About Me
|
||||
### Short Bio
|
||||
Why hello there, I am Hack13... Just some fox you met on the internet, or stumbled upon. I have am a Linux and UNIX SysAdmin by day and hobbyist developer by night.
|
||||
I also love playing in VR, my current favorite platform is NeosVR followed by VRChat from time to time. I enjoy the more nerdy community and flexibility NeosVR gives
|
||||
to me as a person who loves to tinker and make things. However, I know that VRChat is slowly becoming a bit better with allowing things like NeosVR but I don't ever
|
||||
think the platforms will be the same.
|
||||
|
||||
Where do I go from here? I am not fully sure, I am still figuring myself out. I have recently come out as Non-Binary, and I am still discovering myself, and exploring
|
||||
the more feminine side of myself. We shall see what happens and where it goes, and don't be affraind to say hello!
|
||||
|
||||
### Contact Info
|
||||
|
||||
{{< rawhtml >}}
|
||||
<div class="container">
|
||||
<center>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<i class="fab fa-telegram-plane fa-5x"></i><br><a href="https://t.me/kite5521" target="_blank">@kite5521</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<i class="fab fa-discord fa-5x"></i><br>@hack13#4761
|
||||
</div>
|
||||
<div class="col">
|
||||
<i class="fab fa-mastodon fa-5x"></i><br><a href="https://meow.social/@hack13" target="_blank">@hack13</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<i class="fab fa-twitter fa-5x"></i><br><a href="https://twitter.com/kite552" target="_blank">@kite552</a>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<i class="fab fa-github fa-5x"></i><br><a href="https://github.com/hack13" target="_blank">hack13</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<i class="fab fa-gitlab fa-5x"></i><br><a href="https://gitlab.com/hack13" target="_blank">hack13</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<i class="fab fa-lastfm fa-5x"></i><br><a href="https://www.last.fm/user/dothacker552" target="_blank">dothacker552</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<i class="far fa-envelope-open fa-5x"></i><br><a href="mailto:me@hack13.me">me<i class="fas fa-at"></i>hack13.me</a>
|
||||
</div>
|
||||
</div>
|
||||
</center>
|
||||
</div>
|
||||
{{< /rawhtml >}}
|
72
content/api.md
Normal file
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
title: "API"
|
||||
menu:
|
||||
main:
|
||||
weight: 25
|
||||
---
|
||||
# API Docs
|
||||
|
||||
{{< rawhtml >}}
|
||||
<div class="container">
|
||||
<div class="accordion" id="accordionExample">
|
||||
<div class="card">
|
||||
<div class="card-header" id="headingOne">
|
||||
<h2 class="mb-0">
|
||||
<button class="btn btn-link btn-block text-left" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||
LastFM - For NeosVR
|
||||
</button>
|
||||
</h2>
|
||||
</div>
|
||||
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordionExample">
|
||||
<div class="card-body">
|
||||
<strong>URI:</strong> <code>https://api.hack13.dev/lastfm/?username=<i>your-lastfm-username</i></code>
|
||||
<br />
|
||||
<strong>Example Response:</strong>
|
||||
<pre><code>
|
||||
"PUNCHING BAG","blackwinterwells","https://www.last.fm/music/blackwinterwells/_/PUNCHING+BAG",true
|
||||
</code></pre>
|
||||
<strong>Response Breakdown:</strong>
|
||||
<pre><code>
|
||||
<i>"Song Name"</i>,<i>"Artist Name"</i>,<i>"LastFM Song Page Link"</i>,<i>Now Playing</i>
|
||||
</code></pre>
|
||||
<ul>
|
||||
<li>Song Name <span class="badge badge-info">String</span></li>
|
||||
<li>Artist Name <span class="badge badge-info">String</span></li>
|
||||
<li>Song LastFM Page Link <span class="badge badge-info">String/URL</span></li>
|
||||
<li>Now Playing <span class="badge badge-info">Bool</span></li>
|
||||
</ul>
|
||||
<strong>API Source Code:</strong> <a href="https://gist.github.com/hack13/1e6c9340815814e9286b5d2ee566bb50" target="_blank">GitHub Gist</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header" id="headingTwo">
|
||||
<h2 class="mb-0">
|
||||
<button class="btn btn-link btn-block text-left collapsed" type="button" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
||||
Coming Soon ...
|
||||
</button>
|
||||
</h2>
|
||||
</div>
|
||||
<div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionExample">
|
||||
<div class="card-body">
|
||||
Nothing here yet...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header" id="headingThree">
|
||||
<h2 class="mb-0">
|
||||
<button class="btn btn-link btn-block text-left collapsed" type="button" data-toggle="collapse" data-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
||||
Coming Soon ...
|
||||
</button>
|
||||
</h2>
|
||||
</div>
|
||||
<div id="collapseThree" class="collapse" aria-labelledby="headingThree" data-parent="#accordionExample">
|
||||
<div class="card-body">
|
||||
Nothing here yet...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{< /rawhtml >}}
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
title: New Blog
|
||||
description: This is the very first post ever on this blog
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
published: 2010-06-01
|
||||
draft: false
|
||||
tags: [OpenSim]
|
||||
category: Archive
|
||||
date: 2010-06-01T19:28:00+00:00
|
||||
url: /2010/06/new-blog/
|
||||
categories:
|
||||
- Archived
|
||||
|
||||
---
|
||||
Hello this is your friendly OSgrid Folf (fox/wolf) who loves to explore the grid and help out those who I can. I want to start off by saying this blog has no official connection to OSgrid nor its operations. I am just here righting about my experiences in OSgrid and how much I enjoy it and helping people out in it.
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
title: Been A While
|
||||
description: It has been quite a while since I have posted some updates to this old blog of mine...
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
published: 2012-04-04
|
||||
tags: [Personal]
|
||||
category: Archive
|
||||
draft: false
|
||||
date: 2012-04-04T21:38:00+00:00
|
||||
url: /2012/04/been-a-while/
|
||||
categories:
|
||||
- Archived
|
||||
|
||||
---
|
||||
It has been quite a while since I have posted some updates to this old blog of mine. I will be more active on this personal blog, because well I think I need to have a personal blog. I know it seems kinda bad as running an opensim grid, and having my own personal thoughts xD but you know what, I don't care. I support the freedom of speech and free flow of thought. So I will be posting my little rants here, my thoughts, and ideas for opensim. Now they will not always directly reflect my views on Cyber Wrld, I will say this I do plan on keeping Cyber Wrld a free and Open Source grid. We just run stable releases of OpenSim instead of bleeding edge, and we have support for currency and voice grid wide. We are still supporting those who want to try hosting their own regions with us.
|
|
@ -1,10 +1,11 @@
|
|||
---
|
||||
title: My Take on OpenSim Grids
|
||||
description: I am tired of all the fighting over virtual worlds, I mean mainly the OpenSim grids...
|
||||
draft: false
|
||||
published: 2012-04-05
|
||||
category: Archive
|
||||
tags: [OpenSim, Opinion]
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2012-04-05T02:26:00+00:00
|
||||
url: /2012/04/my-take-on-opensim-grids/
|
||||
categories:
|
||||
- Archived
|
||||
|
||||
---
|
||||
I am tired of all the fighting over virtual worlds, I mean mainly the OpenSim grids. I hear people arguing over having the hypergrid turned off or that they allow anyone to make oar and iar backups of their creations. I do not mind this, I actually think this is a good thing. Variety helps economy, we shouldn't be a at throat competition with other grids, but rather friendly competition. I understand how some grids cannot be public, because they want the ultimate security. Yes this can be argued, but the best systems are systems with access restricted to public. Now in the since of contributing back, we do need to consider that some of these grids also have to stay closed source if they put in stuff that makes it work better, but the parts of code belong to another company and they are being leased for use only with a said grid. So I see it understandable, and I think it is good to see grids branch off and do their own thing, that's for them, and what their user base wants.</p>
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
title: My Vision of the HyperGrid
|
||||
description: I have been thinking for a long time, and you know I think I have my idea of how I really want Cyber Wrld...
|
||||
author: Timothy Rogers
|
||||
tags: [Personal, OpenSim]
|
||||
published: 2012-04-05
|
||||
category: Archive
|
||||
draft: false
|
||||
type: post
|
||||
date: 2012-04-05T18:06:00+00:00
|
||||
url: /2012/04/my-vision-of-the-hypergrid/
|
||||
categories:
|
||||
- General
|
||||
|
||||
---
|
||||
I have been thinking for a long time, and you know I think I have my idea of how I really want Cyber Wrld to use the HyperGrid, and well I have been doing it already in a sense. But here it is, a way for people to come hang out on our grid. Not only that, have our grid as a shopping destination. We use OMC, letting people come to our grid and purchase items in world, even without an OMC account and pay through paypal. Take the stuff back home, or just come to our grid directly and sell stuff here and go out and explore. I mean I sound like I am plugging my grid here, but that is what I envision for Cyber Wrld. Being a hub for shopping, visitors, parties and more. I mean we are fully open for leaving our grid and coming back home, nothing too dangerous there.
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
title: We Have HyperGrid USE IT!!!!
|
||||
description: It is starting to sadden me, I have slowly become aware of things, that I rather not have come into knowing...
|
||||
author: Timothy Rogers
|
||||
tags: [OpenSim, Opinion]
|
||||
published: 2012-04-11
|
||||
category: Archive
|
||||
draft: false
|
||||
type: post
|
||||
date: 2012-04-11T21:23:00+00:00
|
||||
url: /2012/04/we-have-hypergrid-use-it/
|
||||
categories:
|
||||
- General
|
||||
|
||||
---
|
||||
It is starting to sadden me, I have slowly become aware of things, that I rather not have come into knowing. Now I have learned that one of the most famous content creators of virtual worlds named Linda Kellie might be pulling out of virtual worlds all together. I am sorry to hear that, but I do respect and understand her reasoning. It is very difficult for grid owners such as myself to regulate the flow of content over the metaverse, reason why my grid doesn’t just allow anyone to connect their regions. I urge her to keep creating and just go standalone. Saying that makes me want to go into a conversation I had with my developer not to long ago.
|
83
content/posts/2012-05-05-coming-changes.md
Normal file
|
@ -0,0 +1,83 @@
|
|||
---
|
||||
title: Coming Changes
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2012-05-05T11:17:00+00:00
|
||||
url: /2012/05/coming-changes/
|
||||
categories:
|
||||
- Archived
|
||||
|
||||
---
|
||||
{{< rawhtml >}}
|
||||
<div dir="ltr">
|
||||
</p>
|
||||
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
</p>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<a href="http://3.bp.blogspot.com/-vkIcs3lVHyQ/T6S5NvtVEfI/AAAAAAAAAQE/o-Dk6As1Ly4/s1600/Snapshot_001.png"><img loading="lazy" border="0" height="167" src="https://3.bp.blogspot.com/-vkIcs3lVHyQ/T6S5NvtVEfI/AAAAAAAAAQE/o-Dk6As1Ly4/s320/Snapshot_001.png" width="320" /></a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<p>
|
||||
</p>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
Me reading in our new office location in OSgrid
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<p>
|
||||
</tbody> </table>
|
||||
|
||||
<p>
|
||||
As you might have heard, I have recently moved my entire grid to OSgrid. This was a decision made my grid residents, and I was inclined to agree as I want to go back to focusing on community related efforts for the HyperGrid. So moving everything to OSgrid, allows me to not worry about any of the issues, just worry about all the work I need to get done for the community.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
I am not just working on the furry community for the hypergrid, but I want to bring together everyone, all walks of life. I am still working on creating a site, that will help residents of all hypergrid enabled grids come together and interact on a social network level. I feel the reason we are all having troubles of the hypergrid, is we are all spread to thin. We need to increase ourselves in community, to do this we just need to pull all our numbers together.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
I know that I cannot please everyone all the time, so I am still going to be offering some really nice deals on OSgrid region hosting. I will be introducing a few new features and places to the sites I have been wanting to work on for bringing the hypergrid community all together.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
</div>
|
||||
|
||||
<table align="center" cellpadding="0" cellspacing="0">
|
||||
</p>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<a href="http://4.bp.blogspot.com/-9hL4j-axGZM/T6S5PbIZhcI/AAAAAAAAAQU/7jwUHX9stNo/s1600/Snapshot_003.png"><img loading="lazy" border="0" height="167" src="https://4.bp.blogspot.com/-9hL4j-axGZM/T6S5PbIZhcI/AAAAAAAAAQU/7jwUHX9stNo/s320/Snapshot_003.png" width="320" /></a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<p>
|
||||
</p>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
Enjoying the view of the new regions from up above
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<p>
|
||||
</tbody> </table> </div>
|
||||
|
||||
<p>
|
||||
</div>
|
||||
{{< /rawhtml >}}
|
|
@ -1,10 +1,11 @@
|
|||
---
|
||||
title: Timothy’s Thoughts
|
||||
description: I have to admit lately, I have been quite depressed about a lot of things in RL. I have not let effect my work...
|
||||
tags: [OpenSim, AuroraSim]
|
||||
published: 2012-06-11
|
||||
category: Archive
|
||||
draft: false
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2012-06-11T19:29:00+00:00
|
||||
url: /2012/06/timothys-thoughts/
|
||||
categories:
|
||||
- Archived
|
||||
|
||||
---
|
||||
I have to admit lately, I have been quite depressed about a lot of things in RL. I have not let effect my work, but it has made it harder to stay focused on work. I am kinda glad Cyber Wrld has not yet worked its way back into any grid list anywhere, as well it hasn't been doing too well at all. Well hasn't been doing anything at all, I have added several features and got a ton of work done to it, and it is ready for production use, minus currency and a few other small things.
|
|
@ -1,10 +1,11 @@
|
|||
---
|
||||
title: Finding My Place
|
||||
description: SoftPaw Estates is starting to really kick off and do quite well for itself. Clients are already telling me that they love the service...
|
||||
tags: [OpenSim]
|
||||
published: 2012-07-02
|
||||
category: Archive
|
||||
draft: false
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2012-07-02T00:57:00+00:00
|
||||
url: /2012/07/finding-my-place/
|
||||
categories:
|
||||
- Archived
|
||||
|
||||
---
|
||||
SoftPaw Estates is starting to really kick off and do quite well for itself. Clients are already telling me that they love the service. I have been cranking out updates to the webui, that should be launching soon, something that I think is long deserved and greatly needed. The ability to control your region from a web page. I haven't determined how much I will be charging, but I am looking for current clients will be getting it at no additional cost, however if clients in the future wish to have the web panel, I will charge 5-10usd extra for it.
|
|
@ -1,10 +1,11 @@
|
|||
---
|
||||
title: Lil About Me & Some Rage
|
||||
author: First off you might be asking why the hell am I putting a Nicki Minaj music video on my blog? Well although I am hypocritical...
|
||||
tags: [Vent, Opinion]
|
||||
published: 2012-07-14
|
||||
category: Archive
|
||||
draft: false
|
||||
title: 'Lil About Me & Some Rage'
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2012-07-14T23:17:00+00:00
|
||||
url: /2012/07/lil-about-me-some-rage/
|
||||
categories:
|
||||
- Archived
|
||||
|
||||
---
|
||||
First off you might be asking why the hell am I putting a Nicki Minaj music video on my blog? Well although I am hypocritical, I have accepted the fact that the lyrics of this song is what I have done to move forward with my life. My good friend Linda Kellie, I have come to view her as life hero, someone who knows what it is to live with the same things I deal with. I have ADHD, and I am sick and tired of people saying it is not a real disorder, because you try being me. It is really like the joke people make, ADH-oooo look shiny thing! I get off track so much I have to use my computer to keep my mind focused, it is called Attention Deficit Hyperactivity Disorder. Because of this disorder, I am unable to complete many tasks that are set before me in timely fashions reasons I have a smart phone and computer with timers and locks to remind me what I am doing. It is much worse than people make it out to be, and because of this, I had developed depression, why because when I am not working on things, I am working my mind and it tends to wonder to extremes with questions that cannot be answered and that drives me crazy and gets me depressed.
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
title: Battle of Business vs OpenSource
|
||||
description: Alright lately I have been getting overwhelmed with all the drama of the oldest argument in the world of internet technologies. So who should win? Big business or opensource projects? Well the answer is simple, THE ARE NOT AT WAR!!!!
|
||||
tags: [OpenSim, Opinion]
|
||||
published: 2012-08-09
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2012-08-09T04:02:00+00:00
|
||||
url: /2012/08/battle-of-business-vs-opensource/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
|
||||
---
|
||||
Alright lately I have been getting overwhelmed with all the drama of the oldest argument in the world of internet technologies. So who should win? Big business or opensource projects? Well the answer is simple, THE ARE NOT AT WAR!!!!
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
title: New Years Resolutions
|
||||
description: It is that time of the year, when people start making New Year Resolutions. Well I have never really made any other than once for a class assignment. But this year I really think I need to make some real resolutions. So I thought I would post them here on my personal blog for everyone to read and be aware.
|
||||
tags: [Personal]
|
||||
published: 2012-12-31
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2012-12-31T14:40:00+00:00
|
||||
url: /2012/12/new-years-resolutions/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
|
||||
---
|
||||
It is that time of the year, when people start making New Year Resolutions. Well I have never really made any other than once for a class assignment. But this year I really think I need to make some real resolutions. So I thought I would post them here on my personal blog for everyone to read and be aware.
|
|
@ -1,12 +1,12 @@
|
|||
---
|
||||
title: Explaining OpenSim Memory Usage
|
||||
description: I have had a couple people ask me to show them some tips and show them how to conserve memory usage in OpenSim. So I am going to be using sim-on-a-stick for today's tips and tricks...
|
||||
tags: [Resources, OpenSim]
|
||||
published: 2013-02-11
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-02-11T20:15:00+00:00
|
||||
url: /2013/02/explaining-opensim-memory-usage/
|
||||
category: Archive
|
||||
draft: false
|
||||
|
||||
categories:
|
||||
- Resources
|
||||
- Archived
|
||||
---
|
||||
I have had a couple people ask me to show them some tips and show them how to conserve memory usage in OpenSim. So I am going to be using sim-on-a-stick for today's tips and tricks. Now the reason for this is because now with sim-on-a-stick, we have the database running in MySQL which saves a bit of memory, and the fact it is already setup and ready to go out of the box.</p>
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
title: Thank You
|
||||
description: Thank You AuroraScape Community
|
||||
tags: [AuroraSim]
|
||||
published: 2013-02-13
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-02-13T23:32:00+00:00
|
||||
url: /2013/02/thank-you/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
- Aurora-Sim
|
||||
|
||||
---
|
||||
Thank You AuroraScape Community,
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
title: Needing Rest
|
||||
description: It sure has been a long first 20 days, I can't believe how far all of us have come. Yes after the upgrade happened, we lost a nice chunk of regions, but I am sure we will be getting them back soon. All I can say is I am taking a few steps back for the next few days, from grid upgrades.
|
||||
tags: [AuroraSim]
|
||||
published: 2013-02-20
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-02-20T05:43:00+00:00
|
||||
url: /2013/02/needing-rest/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
|
||||
---
|
||||
It sure has been a long first 20 days, I can't believe how far all of us have come. Yes after the upgrade happened, we lost a nice chunk of regions, but I am sure we will be getting them back soon. All I can say is I am taking a few steps back for the next few days, from grid upgrades. I will still be around, doing money cash outs, trouble shooting, and processing orders. I just need a break.
|
|
@ -1,14 +1,15 @@
|
|||
---
|
||||
title: Top 10 Reasons Not To Give Up On Aurora-Sim
|
||||
description: I am very sad to see so many people tell me that I should give up on Aurora-Sim, and that it is a waste. I think it is mostly been placed there because people remember its biggest tank, and the failure of Nova Grid.
|
||||
tags: [AuroraSim]
|
||||
published: 2013-02-21
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-02-21T05:48:00+00:00
|
||||
url: /2013/02/top-10-reasons-not-to-give-up-on-aurora-sim/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
- Aurora-Sim
|
||||
|
||||
---
|
||||
I am very sad to see so many people tell me that I should give up on Aurora-Sim, and that it is a waste. I think it is mostly been placed there because people remember its biggest tank, and the failure of Nova Grid. So I am going to show you the top 10 reasons why I think the metaverse should give it another shot, and get back to helping with its development.
|
||||
I am very sad to see so many people tell me that I should give up on Aurora-Sim, and that it is a waste. I think it is mostly been placed there because people remember its biggest tank, and the failure of Nova Grid. So I am going to show you the top 10 reasons why I think the metaverse should give it another shot, and get back to helping with its development.</p>
|
||||
|
||||
**Ready Out of the Box:** When you download the latest aurora-sim master code, and compile it. First time run, it has a built in fully functional WebUI, Fully Working Groups, Fully Working Profiles, Fully Working Search, and easy to use Region GUI. All of this is built into the code, all running for the core code. This all works even in standalone mode all out of the single Aurora.exe!
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
title: Who Is Timothy Vyper/Hoxley/Rogers
|
||||
description: I just keep reading all this stuff about all these other grids, and the people who have influences there. Now that I am a grid owner, been making myself know more and more over the past year with all the things I have started. Grid-Press, SoftPaw Estates, Zetamex, and my latest AuroraScape.
|
||||
tags: [Personal]
|
||||
published: 2013-02-23
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-02-23T01:43:00+00:00
|
||||
url: /2013/02/who-is-timothy-vyperhoxleyrogers/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
- Personal
|
||||
|
||||
---
|
||||
I just keep reading all this stuff about all these other grids, and the people who have influences there. Now that I am a grid owner, been making myself know more and more over the past year with all the things I have started. Grid-Press, SoftPaw Estates, Zetamex, and my latest AuroraScape. I will admit I am not perfect, hell I never even went to college! Also another zinger for all you people, did you all know that I am only 20 years old? This year I turn 21, on April 28th. Which surprises a lot of people when I tell them all that, but I did take some college classes in High School, because my school was merged with the local college (due to budget cuts) and got 3 certification, that don't mean crap now.
|
|
@ -1,14 +1,15 @@
|
|||
---
|
||||
title: Why I Closed AuroraScape
|
||||
description: I first want to thank everyone who was on AuroraScape, and I have to apologize to all of you. I know the life of AuroraScape was short but there are multiple reasons to this, and I mean no ill intent to the developers of Aurora by what I have to say in this blog.
|
||||
tags: [AuroraSim]
|
||||
published: 2013-03-05
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-03-05T22:20:00+00:00
|
||||
url: /2013/03/why-i-closed-aurorascape/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
- Aurora-Sim
|
||||
|
||||
---
|
||||
I first want to thank everyone who was on AuroraScape, and I have to apologize to all of you. I know the life of AuroraScape was short but there are multiple reasons to this, and I mean no ill intent to the developers of Aurora by what I have to say in this blog. Firstly, AuroraScape was doing pretty good. But that was how it looked on the outside, there were a lot of problems, things I just cannot work on as I am not a programmer. The software is very stable, very easy to use, and works out of the box. That I am not trying to fight with, but there was just too many people bitching about it.
|
||||
I first want to thank everyone who was on AuroraScape, and I have to apologize to all of you. I know the life of AuroraScape was short but there are multiple reasons to this, and I mean no ill intent to the developers of Aurora by what I have to say in this blog.Firstly, AuroraScape was doing pretty good. But that was how it looked on the outside, there were a lot of problems, things I just cannot work on as I am not a programmer. The software is very stable, very easy to use, and works out of the box. That I am not trying to fight with, but there was just too many people bitching about it.
|
||||
|
||||
I know I shouldn't let people bitching about the software help me close the grid down, but it is not so simple. Many people were just not willing to even give AuroraScape a shot, and many people who joined began to drop out right away. The interest in Aurora-Sim was so limited, and one of the biggest reasons is because the lack of HyperGrid. There were people who literately said things like I will never support an open grid without hypergrid and that type of thing travels and makes other say it and more people see it. People were publicly bitching and complaining about the grid without even giving it a shot. We kept loosing people because of it.
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
title: Closed vs Open? Really?
|
||||
description: I am dealing with a lot of people getting stressed over the debate of if grids should all be open or at least have hypergrid open. I am just going to put this out there, there are tons of people who want everything free in life, and never want to pay for anything.
|
||||
tags: [OpenSim]
|
||||
published: 2013-03-11T12:03:00+00:00
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-03-11T12:03:00+00:00
|
||||
url: /2013/03/closed-vs-open-really/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
- OpenSimulator
|
||||
|
||||
---
|
||||
I am dealing with a lot of people getting stressed over the debate of if grids should all be open or at least have hypergrid open. I am just going to put this out there, there are tons of people who want everything free in life, and never want to pay for anything. I am sorry but the world requires money for us to get things done.
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
title: Moving Up & Around
|
||||
description: It has been one hell of a past month, I have had to deal with a lot of drama in my real personal life. Sometimes I wish we could all just live in virtual worlds, but drama would just pile up their too...
|
||||
tags: [Personal]
|
||||
published: 2013-04-08
|
||||
title: 'Moving Up & Around'
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-04-08T13:17:00+00:00
|
||||
url: /2013/04/moving-up-around/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
- Personal
|
||||
|
||||
---
|
||||
It has been one hell of a past month, I have had to deal with a lot of drama in my real personal life. Sometimes I wish we could all just live in virtual worlds, but drama would just pile up their too... so what else is new on that. But besides that point, I have been doing some plotting and planning with Zetamex these past few days so going to be talking a bit about that in this blog. I am also going to gloat about my new boy friend, because I can tell you right now, without him this past month would have just been me crying my heart out.
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
title: My Clocks Are Ticking
|
||||
description: Well it has been a while since I have written on my personal blog again. However I have been feeling a little down lately and I think I need to write to pick up my spirits a bit again.
|
||||
tags: [Personal]
|
||||
published: 2013-04-26
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-04-26T01:41:00+00:00
|
||||
url: /2013/04/my-clocks-are-ticking/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
- Personal
|
||||
|
||||
---
|
||||
Well it has been a while since I have written on my personal blog again. However I have been feeling a little down lately and I think I need to write to pick up my spirits a bit again. I just been going through a lot of feelings lately. I guess I should start from the top, which is well I am just so immersed in my work I feel I am loosing more and more touch with my real life. I mean not that is a bad thing, but I am getting to the point that I blow off my boyfriend. I already lost one boyfriend, that I had been with for 2 years, it wasn't only because I was so immersed in my work there were other reasons but this was part of it.
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
title: Upset With Stiffled Innovation
|
||||
description: I am constantly hearing about all these people stiffing innovation, well today I had the last straw I could take. Before I begin, I want to make sure say this boldly and clearly.
|
||||
tags: [OpenSim]
|
||||
published: 2013-06-19
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-06-19T12:04:00+00:00
|
||||
url: /2013/06/upset-with-stiffled-innovation/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
- OpenSimulator
|
||||
|
||||
---
|
||||
I am constantly hearing about all these people stiffing innovation, well today I had the last straw I could take. Before I begin, I want to make sure say this boldly and clearly. **I do not directly represent Zetamex's personal interests, Zetamex represents it's own identity at http://blog.zetamex.com/ and anything said on this blog is unrelated to Zetamex's personal interests.** Now that I got that out of the way, I want to tell you how I was rudely addressed for the last time.
|
|
@ -1,14 +1,15 @@
|
|||
---
|
||||
title: Depression
|
||||
description: Well I never thought the day would come when I would say that I feel depressed with my work, well I been this way quite a bit lately. Work is getting harder and harder to keep up with lately, not due to being over extended, just that Zetamex seems to be falling behind lately.
|
||||
tags: [Personal]
|
||||
published: 2013-08-12
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-08-12T11:27:00+00:00
|
||||
url: /2013/08/depression/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
- Personal
|
||||
|
||||
---
|
||||
Well I never thought the day would come when I would say that I feel depressed with my work, well I been this way quite a bit lately. Work is getting harder and harder to keep up with lately, not due to being over extended, just that Zetamex seems to be falling behind lately.
|
||||
Well I never thought the day would come when I would say that I feel depressed with my work, well I been this way quite a bit lately. Work is getting harder and harder to keep up with lately, not due to being over extended, just that Zetamex seems to be falling behind lately.</p>
|
||||
|
||||
I try my absolute hardest to provide the latest and greatest opensim features, code, and even give back as much as I can. But it just seems that I have started to hit a road block. Which has just made me keep pushing and pushing harder, but it doesn't seem to be budging at all. I mean Zetaworlds is delayed because I am just to finish the new ZetaPanel 2.0 which is very complex piece of work. I am the only developer of it, and it so hard to put together since I am not even a real programmer.
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
---
|
||||
title: My Response To Kitely Marketplace
|
||||
description: Alright I know right now everyone has been all over this we need to embrace the Kitely Marketplace thing for a while now. However that being said, I want to take to the side and take some notes at some...
|
||||
tags: [OpenSim, Opinion]
|
||||
published: 2013-09-02
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-09-02T02:04:00+00:00
|
||||
url: /2013/09/my-response-to-kitely-marketplace/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Arhived
|
||||
- Opinion
|
||||
- OpenSimulator
|
||||
|
||||
---
|
||||
Alright I know right now everyone has been all over this we need to embrace the Kitely Marketplace thing for a while now. However that being said, I want to take to the side and take some notes at some of the advantages and disadvantages of operating business in virtual worlds like this. The insecurities, the profitability, and the over all feeling I take from the whole ordeal.
|
|
@ -1,10 +1,13 @@
|
|||
---
|
||||
title: I Apologzie to Kitely & Don’t Be Fooled
|
||||
description: I want to start out this by saying I am only human, hell I know I make more mistakes than most people I know. I admit this and never claim to be perfect, and I most certainly will not say I know what I am doing unless I do.
|
||||
tags: [Opinion, OpenSim]
|
||||
published: 2013-09-19
|
||||
title: 'I Apologzie to Kitely & Don’t Be Fooled'
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-09-19T08:02:00+00:00
|
||||
url: /2013/09/i-apologzie-to-kitely-dont-be-fooled/
|
||||
category: Archive
|
||||
categories:
|
||||
- Opinion
|
||||
- Archived
|
||||
- OpenSimulator
|
||||
|
||||
---
|
||||
I want to start out this by saying I am only human, hell I know I make more mistakes than most people I know. I admit this and never claim to be perfect, and I most certainly will not say I know what I am doing unless I do. I am human, and I do get limits pushed and get upset just like everyone else in the world. What I am referencing to is comments I have deleted on the Kitely blog.
|
|
@ -1,11 +1,13 @@
|
|||
---
|
||||
title: Why I Don’t Use The Cloud
|
||||
description: I have been asked a couple times why I don't want to build Zetamex off the cloud, and well the biggest answer is that the cloud is not really right for the old fashioned and classic usage of opensimulator.
|
||||
tags: [OpenSim, Opinion]
|
||||
published: 2013-11-03
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2013-11-03T04:09:00+00:00
|
||||
url: /2013/11/why-i-dont-use-the-cloud/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Opinion
|
||||
- Archived
|
||||
- OpenSimulator
|
||||
|
||||
---
|
||||
I have been asked a couple times why I don't want to build Zetamex off the cloud, and well the biggest answer is that the cloud is not really right for the old fashioned and classic usage of opensimulator. The second reason is that it is much more cost efficient to avoid using the cloud, and using dedicated hardware.
|
|
@ -1,12 +1,13 @@
|
|||
---
|
||||
title: Moved To WordPress
|
||||
description: I have decided to move to WordPress after a long time of inactivity on my personal blog. I just feel there is not a real nice place to get OpenSim related news on the internet anymore, other then people's personal blogs and the blogs themselves of other grids.
|
||||
tags: [Personal]
|
||||
published: 2016-01-04
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2016-01-04T03:08:24+00:00
|
||||
url: /2016/01/moved-to-wordpress/
|
||||
#featured_image: /wp-content/uploads/2016/01/AKAzWTD.jpg
|
||||
category: Archive
|
||||
draft: false
|
||||
featured_image: /wp-content/uploads/2016/01/AKAzWTD.jpg
|
||||
categories:
|
||||
- Archived
|
||||
- Personal
|
||||
|
||||
---
|
||||
I have decided to move to WordPress after a long time of inactivity on my personal blog. I just feel there is not a real nice place to get OpenSim related news on the internet anymore, other then people's personal blogs and the blogs themselves of other grids. It also still saddens me to this say, that the certain site people go to, still does not provide a good source for OpenSim content.
|
|
@ -1,11 +1,13 @@
|
|||
---
|
||||
title: Modern InWorldz Website
|
||||
description: I just really want to take a step back and say I was really happy to see the new site by InWorldz. It looks very nice, however I only have one complaint... When launching a new theme, I would really like to see it implemented throughout before released to the public...
|
||||
tags: [Opinion, OpenSim]
|
||||
published: 2016-01-07
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2016-01-07T03:16:59+00:00
|
||||
url: /2016/01/modern-inworldz-website/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Opinion
|
||||
- Archived
|
||||
- OpenSimulator
|
||||
|
||||
---
|
||||
I just really want to take a step back and say I was really happy to see the new site by InWorldz. It looks very nice, however I only have one complaint... When launching a new theme, I would really like to see it implemented throughout before released to the public... Because the second you login, you are redirected to a part of the site of the old design. From what I saw only the home page contains the new theme.
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
title: Where Has Tim Been?
|
||||
description: Well, it has been a while since I have been around. I have deleted some of my social media presence because it is needed for how I been feeling. For those who do not know, I work as my primary job these days a UNIX/Linux System Administrator.
|
||||
tags: [Personal]
|
||||
published: 2018-01-06
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2018-01-06T09:14:00+00:00
|
||||
url: /2018/01/where-has-tim-been/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Archived
|
||||
- Personal
|
||||
|
||||
---
|
||||
Well, it has been a while since I have been around. I have deleted some of my social media presence because it is needed for how I been feeling. For those who do not know, I work as my primary job these days a UNIX/Linux System Administrator. Which has turned into something that has been a very demanding job that I wasn’t aware of?
|
|
@ -1,10 +1,12 @@
|
|||
---
|
||||
title: Taking Control of My Cloud Storage
|
||||
description: So I have been someone who has been working with a lot of sync services over the years. Dropbox, Mega, Google Drive, and even open source solutions like Seafile, OwnCloud/NextCloud, and Sparkle Share.
|
||||
tags: [Opinion, Resources]
|
||||
published: 2018-01-14
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2018-01-14T03:09:03+00:00
|
||||
url: /2018/01/taking-control-of-my-cloud-storage/
|
||||
category: Archive
|
||||
categories:
|
||||
- Opinion
|
||||
- Resources
|
||||
|
||||
---
|
||||
So I have been someone who has been working with a lot of sync services over the years. Dropbox, Mega, Google Drive, and even open source solutions like Seafile, OwnCloud/NextCloud, and Sparkle Share. But these have all been keeping me locked in with paying for more than I need and the commercial ones paying with my privacy. So I wanted to look into a way of handling my files in a cheaper and more reliable way.
|
|
@ -1,12 +1,11 @@
|
|||
---
|
||||
title: Whats Next For Tim?
|
||||
description: I had a lot of fun working with OpenSimulator over the past few years, it was fun but I have got a more demanding job and new skills to acquire for that job that now just take up far more time than I have to work on anything OpenSimulator.
|
||||
tags: [Personal]
|
||||
published: 2018-02-13
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2018-02-13T04:33:28+00:00
|
||||
url: /2018/02/whats-next-for-tim/
|
||||
category: Archive
|
||||
draft: false
|
||||
|
||||
categories:
|
||||
- Personal
|
||||
---
|
||||
I had a lot of fun working with OpenSimulator over the past few years, it was fun but I have got a more demanding job and new skills to acquire for that job that now just take up far more time than I have to work on anything OpenSimulator. I am at this time no longer involved with OpenSimulator in any way other than running my own little standalone that I rarely will go on due to my lack of time but just so I can keep and enjoy my content I own and can have on my own machine something that I have always loved about OpenSimulator the ability to truly own your content if you host it yourself(or a provider like Zetamex Network, Dreamland Metaverse, etc). It is sad to part ways from the community just I feel like it is kinda my time to move on.
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
---
|
||||
title: Finding My Linux Distro
|
||||
description: I have been on a bit of a journey looking for the right Linux distribution for myself. It has been a bit of a challenge, because I have been bouncing around a lot over the past couple months trying to find the one that fits me best.
|
||||
tags: [Personal, Opinion]
|
||||
published: 2018-04-26
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2018-04-26T17:31:59+00:00
|
||||
draft: true
|
||||
url: /2018/04/finding-my-linux-distro
|
||||
category: Archive
|
||||
categories:
|
||||
- Opinion
|
||||
- Personal
|
||||
|
||||
---
|
||||
I have been on a bit of a journey looking for the right Linux distribution for myself. It has been a bit of a challenge, because I have been bouncing around a lot over the past couple months trying to find the one that fits me best. There are the LTS(Long Term Support), standard release cycles, and of course the rolling release ones out there.
|
|
@ -1,10 +1,11 @@
|
|||
---
|
||||
title: 2019 Goals
|
||||
description: So it has been a while since I have written anything on this site, or let alone touched it. So I have decided to give it a bit of a refresh and set some new goals for 2019 to try and meet. With that said, I want to thank you for taking a peek back at my site after a year of nothing new.
|
||||
tags: [Personal]
|
||||
published: 2019-01-26
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2019-01-26T15:37:59+00:00
|
||||
url: /2019/01/2019-goals/
|
||||
category: Archive
|
||||
categories:
|
||||
- Personal
|
||||
|
||||
---
|
||||
So it has been a while since I have written anything on this site, or let alone touched it. So I have decided to give it a bit of a refresh and set some new goals for 2019 to try and meet. With that said, I want to thank you for taking a peek back at my site after a year of nothing new. I have been working really hard at my day job that keeps me very busy managing lots of servers. However, I plan to take back my personal life somewhat this year as my biggest goal and start getting back into working on hobby projects in my spare time. With that said, I plan on talking about some of my projects that I have worked on here and there and some of the stuff I have done to keep doing through the year.
|
|
@ -1,11 +1,16 @@
|
|||
---
|
||||
title: Speeding Up Zadaroo Files
|
||||
description: As some people may know, I host Zadaroo from an agreement with the original owner that I would continue to host it for as long as I can. Which I believe will be a long time, as it isn't that expensive to host.
|
||||
tags: [CDN, Cloudflare, Wasabi]
|
||||
published: 2019-01-28
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2019-01-28T12:50:19+00:00
|
||||
url: /2019/01/speeding-up-zadaroo-files/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Resources
|
||||
tags:
|
||||
- CDN
|
||||
- Cloudflare
|
||||
- nginx
|
||||
- Wasabi
|
||||
|
||||
---
|
||||
As some people may know, I host Zadaroo from an agreement with the original owner that I would continue to host it for as long as I can. Which I believe will be a long time, as it isn't that expensive to host. I have up till a few months ago hosted all the files on OVH Object Storage in their Canadian datacenters. Doing that costed me around 5-6/month just in bandwidth fees, as believe it or not Zadaroo continues to this day consuming around 500-600gb of bandwidth a month, which would be too expensive to host on a provider like AWS. Also, keep in mind this is only for all the files behind Zadaroo, not the site itself as the files are hosted separately because I wanted to ensure the best downloads I could.
|
||||
|
@ -14,12 +19,16 @@ Recently I wanted to try and move away from OVH, not because it is really bad or
|
|||
|
||||
So I moved everything to Wasabi, but then realized that we were going to lose the ability to let people keep using the original files.zadaroo.com domain that I know many people still rely on for loading OARs and such from the site. So I came up with using the Linode box as a proxy server to pass the requests back to Wasabi using the old domain to mask the Wasabi address and it worked! However, this meant I was using my Linode bandwidth to reserve the files, but that was fine for now. Below is configuration I used to mask the Wasabi address.
|
||||
|
||||
{{< rawhtml >}}
|
||||
<script src="https://gitlab.com/snippets/1802178.js"></script>
|
||||
{{< /rawhtml >}}
|
||||
|
||||
So I was forced to stop using Wasabi due to 2 outages, and this latest one from them lasting over 48 hours... I found this to be unacceptable. I quickly in the first 12 hours switched Zadaroo Files over to Backblaze B2 because I didn't want to stop people from being able to download all the files from Zadaroo.
|
||||
|
||||
{{< rawhtml >}}
|
||||
<center><blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="en" dir="ltr">Due to the Wasabi outage, Zadaroo Files back-end has been seamlessly failed over to <a href="https://twitter.com/backblaze?ref_src=twsrc%5Etfw">@backblaze</a> B2 to ensure you can keep downloading those OAR files :)</p>— kite552🦊 (@kite552) <a href="https://twitter.com/kite552/status/1088987607604826112?ref_src=twsrc%5Etfw">January 26, 2019</a></blockquote>
|
||||
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></center>
|
||||
{{< /rawhtml >}}
|
||||
|
||||
In my haste switching over to Backblaze's B2 Zadaroo Files backup, I didn't realize that even though I had set it up exactly the same way as Wasabi reverse proxy... it was redirecting instead to the B2 address. I tried editing it to force files.zadaroo.com to stay but it was triggering Cloudflare's security back-end and preventing the site from loading. So I decided to use my last page rule, because I was already taking advantage of Backblaze and Cloudflare's partnership for free unlimited bandwidth. So with switched to a page rule from Cloudflare's settings, I tested and confirmed it was working at rewriting files.zadaroo.com to the correct path for b2.zadaroo.com/file/zadaroo-backup/ and as an added benefit no more going through Linode and I noticed that downloads were even faster now.
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
---
|
||||
title: Cloudflare Workers and Pages
|
||||
description: It sure has been a while since I have posted anything here on my blog... that said you might have realized that the site has changed and maybe even noticed it might be a tad bit faster for you.
|
||||
tags: [Resources, Personal, Cloudflare]
|
||||
published: 2021-10-29
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2021-10-29
|
||||
url: /2021/10/cloudflare-workers-and-pages/
|
||||
category: Archive
|
||||
draft: false
|
||||
categories:
|
||||
- Personal
|
||||
- Resources
|
||||
|
||||
---
|
||||
|
||||
It sure has been a while since I have posted anything here on my blog... that said you might have realized that the site has changed and maybe even noticed it might be a tad bit faster for you. Well that is because I have started to pick back up coding, because I really do wanna get back into DevOps. That said, I am back to my old shinigans of trying to build things and host them as cheap as possible while not compromising on performance.
|
||||
|
||||
## Back to Cloudflare
|
||||
|
@ -19,9 +21,9 @@ That said, their latest service they have released public called [Pages](https:/
|
|||
## Pages A Free CI/CD Dream
|
||||
|
||||
So the big reason why I have migrated to Cloudflare Pages for my site, is because it is so much easier to work on my site, test changes before they go public. I am able to push my changes to my GitHub repo for my site, and it kicks off a job immediately to update the site. It also builds the other branches on the fly as well, but gives them a unique link that isn't mapped to the regular live link so you can see the development builds of your site beside your live site.
|
||||
|
||||
{{< rawhtml >}}<center>{{< /rawhtml >}}
|
||||

|
||||
|
||||
{{< rawhtml >}}</center>{{< /rawhtml >}}
|
||||
As you can see from the image above you can see how it pulls, builds, and generates a unique site link for each commit. So as you can see, it on the back-end remaps your domain to the deployment link of the latest build. All the previous build hang around as well, so if I mess up on a build I can click the dots next to the build I need to go back to and the site will immediately roll back to that version of the site.
|
||||
|
||||
So I know you might be asking why I don't just use GitHub's built in Pages service. Well there are a couple reasons, and there are two big ones. The first one is that Cloudflare Pages push your site to all their edge nodes, so no matter where in the world someone visits the site, it will be loaded from the closest Cloudflare edge node. The second big feature is the extra features of ability to have custom error pages, routes, and more to your site.
|
||||
|
@ -29,13 +31,9 @@ So I know you might be asking why I don't just use GitHub's built in Pages servi
|
|||
## Workers Saving Me Money
|
||||
|
||||
So as I stated earlier, I also have been hosting an API server for people to use that uses my key to check against the [LastFM API](https://last.fm/) to get their Now Playing data and able to use it inside of NeosVR. I have to parse it into something not JSON or XML so that it is more easy to parse the data in game. So I was using a PHP script, but looking at the Cloudflare Workers... I am able to allow 100,000 requests every 24 hours. I haven't gotten over 45% usage yet. But even when I do the pricing is very affordable and there is no cold starts. All I had to do was teach myself JavaScript... which only took a day.
|
||||
|
||||
<center>
|
||||
|
||||
{{< rawhtml >}}<center>{{< /rawhtml >}}
|
||||

|
||||
|
||||
</center>
|
||||
|
||||
{{< rawhtml >}}</center>{{< /rawhtml >}}
|
||||
The image above shows the weekly report of my workers usage data. You also see, I have setup a lastfm-legacy that maps overtop of the old link for the lastfm system some people are still pointing at but has been re-written on the back-end to JavaScript on a Worker so that it gives them time to update to the new one.
|
||||
|
||||
So long story short, I am very happy to be back and learning JavaScript and doing new things. I am working on a Discord Bot right now for CyberFurz a small project I operate. I will be writing up on that soon once I finish everything on that front. Anyways, thank you for reading!
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
title: Struggling With Anxiety
|
||||
description: So I am sorry I haven’t been good lately, I am not ok and I know a lot of people are not ok lately. I know that a lot of people in my personal and professional life look up to me.
|
||||
tags: [Personal, Mental Health]
|
||||
published: 2022-02-02
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2022-02-02
|
||||
url: /2022/02/struggling-with-anxiety/
|
||||
category: Life
|
||||
draft: false
|
||||
categories:
|
||||
- Personal
|
||||
|
||||
---
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
title: NFT Polarization
|
||||
description: So it is crazy to me how polarized people seem to be over NFT’s these days, and crypto in general...
|
||||
tags: [Crypto]
|
||||
published: 2022-02-17
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2022-02-17
|
||||
url: /2022/02/nft-polarization/
|
||||
category: Crypto
|
||||
draft: false
|
||||
categories:
|
||||
- Personal
|
||||
- Opinion
|
||||
|
||||
---
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
title: The Tech Side of Hosting a NeosVR Event
|
||||
description: So in case you had no idea, I assisted with hosting the back-end of a NeosVR event this past weekend. It was great, but it was a very short notice event, I jumped in and volunteered as I saw the event organizer starting to get overwhelmed with just how big their event got.
|
||||
tags: [Personal, NeosVR, Resonite]
|
||||
published: 2022-04-17
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2022-04-17
|
||||
url: /2022/04/neosvr-event-hosting/
|
||||
category: VR
|
||||
draft: false
|
||||
categories:
|
||||
- Personal
|
||||
|
||||
---
|
||||
|
||||
|
@ -14,17 +14,21 @@ So in case you had no idea, I assisted with hosting the back-end of a NeosVR eve
|
|||
### The Hardware Breakdown
|
||||
|
||||
So if you have ever followed me or looked at my work, I am all about bang for the buck. I decided to use the [Hetzner Cloud](https://www.hetzner.com/cloud) for this event with their new Data Center location based in the USA. This is because most of the attendees were based in North America. Also we were able to take advantage of their instance pricing.
|
||||
{{< rawhtml >}}
|
||||
<center>
|
||||
<img src="/post-pics/2022/LGQ2GFbz7D6rntVRTYVqwhwX.webp" alt="pricing screenshot" /> <img src="/post-pics/2022/1MhfuY5BLaDOVHuso0Pw17kZ.webp" alt="pricing screenshot" />
|
||||
<img src="/post-pics/2022/LGQ2GFbz7D6rntVRTYVqwhwX.webp" />
|
||||
<img src="/post-pics/2022/1MhfuY5BLaDOVHuso0Pw17kZ.webp" />
|
||||
</center>
|
||||
{{</ rawhtml >}}
|
||||
|
||||
We used the CPX41 and CPX51 instances for the event. I used the CPX41 instance for the Main Stage of the event which also doubled as the Parent session for the other sessions. The actual break out sessions where we wanted to make sure that people who were building and working on avatars and logix were on the CPX51’s which was probably overkill...
|
||||
|
||||
### NeosVR Headless Configurations
|
||||
|
||||
So the documentation for headless client configurations sadly is not quite there, especially when it comes to running events with nested sessions. In fact at the time of writing this, the wiki page for nested sessions doesn’t exist and is a dead link... However, that aside by searching through the NeosVR Discord server and various bug report filings on the GitHub I was able to put together how to configure the nested sessions configuration. Which is basically parentSessionId is a JSON array...
|
||||
<center>
|
||||
<img src="/post-pics/2022/event-layout.webp" alt="event layout" />
|
||||
</center>
|
||||
{{< rawhtml >}}<center>{{</ rawhtml >}}
|
||||

|
||||
{{< rawhtml >}}</center>{{</ rawhtml >}}
|
||||
|
||||
So as you can see from the above diagram, we used a total of 3 cloud instances. I figured since the Main Stage was simply to be a filter point and simple gathering zone, it could be on a slightly less powerful instance. Then the people with Unity and NeosVR knowledge most likely would be doing some crazy Logix or other funny things, we thought it would be best to have them isolated out on their own system. We then put the Intermediate and New Users onto the same back-end system just because we felt those two worlds shouldn’t be too heavy, as they were going to mainly be doing basic setting up your avatar and showing off the basics of NeosVR.
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
title: Continuing To Find Myself
|
||||
description: Hi there... I have been struggling with my identity lately... and I been scared about it. The reason I am scared? To put it bluntly, cancel culture and the people who are very harsh gate keeping...
|
||||
tags: [Enby, Trans]
|
||||
published: 2022-05-08
|
||||
author: Timothy Rogers
|
||||
type: post
|
||||
date: 2022-05-08
|
||||
url: /2022/05/continuing-to-find-myself/
|
||||
category: Life
|
||||
draft: false
|
||||
categories:
|
||||
- Personal
|
||||
|
||||
---
|
||||
|
68
content/privacy.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
title: "Privacy"
|
||||
menu:
|
||||
main:
|
||||
weight: 50
|
||||
---
|
||||
# Projects
|
||||
|
||||
{{< rawhtml >}}
|
||||
<div class="container">
|
||||
<h2>Privacy Policy of <span class="website_url">https://zadaroo.com & https://hack13.me</span></h2>
|
||||
<p>At <span class="website_name">Zadaroo</span>, we collect and manage user data according to the following Privacy Policy.</p>
|
||||
|
||||
<h3>Data Collected</h3>
|
||||
|
||||
<p>We collect information you provide directly to us. For example, we collect information when you create an account, subscribe, participate in any interactive features of our services, fill out a form, request customer support or otherwise communicate with us. The types of information we may collect include your name, email address, postal address, credit card information and other contact or identifying information you choose to provide.</p>
|
||||
|
||||
<p>We collect anonymous data from every visitor of the Website to monitor traffic and fix bugs. For example, we collect information like web requests, the data sent in response to such requests, the Internet Protocol address, the browser type, the browser language, and a timestamp for the request.</p>
|
||||
|
||||
<p>We also use various technologies to collect information, and this may include sending cookies to your computer. Cookies are small data files stored on your hard drive or in your device memory that helps us to improve our services and your experience, see which areas and features of our services are popular and count visits. We may also collect information using web beacons (also known as "tracking pixels"). Web beacons are electronic images that may be used in our services or emails and to track count visits or understand usage and campaign effectiveness. Our Privacy Policy was created with the help of the <a href="https://www.privacy-policy-template.com">Privacy Policy Template</a> and the <a href="https://www.generateprivacypolicy.com">Generate Privacy Policy Generator</a>.</p>
|
||||
|
||||
<h3>Use of the Data</h3>
|
||||
|
||||
<p>We only use your personal information to provide you the <span class="website_name">Zadaroo</span> services or to communicate with you about the Website or the services.</p>
|
||||
|
||||
<p>We employ industry standard techniques to protect against unauthorized access of data about you that we store, including personal information.</p>
|
||||
|
||||
<p>We do not share personal information you have provided to us without your consent, unless:</p>
|
||||
|
||||
<ul>
|
||||
<li>Doing so is appropriate to carry out your own request</li>
|
||||
<li>We believe it's needed to enforce our legal agreements or that is legally required</li>
|
||||
<li>We believe it's needed to detect, prevent or address fraud, security or technical issues</li>
|
||||
</ul>
|
||||
|
||||
<h3>Sharing of Data</h3>
|
||||
|
||||
<p>We don't share your personal information with third parties. Aggregated, anonymized data is periodically transmitted to external services to help us improve the Website and service.</p>
|
||||
|
||||
<p>We may allow third parties to provide analytics services. These third parties may use cookies, web beacons and other technologies to collect information about your use of the services and other websites, including your IP address, web browser, pages viewed, time spent on pages, links clicked and conversion information.</p>
|
||||
|
||||
<p>We also use social buttons provided by services like Twitter, Google+, LinkedIn and Facebook. Your use of these third party services is entirely optional. We are not responsible for the privacy policies and/or practices of these third party services, and you are responsible for reading and understanding those third party services' privacy policies.</p>
|
||||
|
||||
<h3>Cookies</h3>
|
||||
|
||||
<p>We may use cookies on our site to remember your preferences.</p>
|
||||
|
||||
<p>For more general information on cookies, please read <a href="https://www.cookieconsent.com/what-are-cookies/">"What Are Cookies"</a>.</p>
|
||||
|
||||
<h3>Opt-Out, Communication Preferences</h3>
|
||||
|
||||
<p>You may modify your communication preferences and/or opt-out from specific communications at any time. Please specify and adjust your preferences.</p>
|
||||
|
||||
<h3>Security</h3>
|
||||
|
||||
<p>We take reasonable steps to protect personally identifiable information from loss, misuse, and unauthorized access, disclosure, alteration, or destruction. But, you should keep in mind that no Internet transmission is ever completely secure or error-free. In particular, email sent to or from the Sites may not be secure.</p>
|
||||
|
||||
<h3>About Children</h3>
|
||||
|
||||
<p>The Website is not intended for children under the age of 13. We do not knowingly collect personally identifiable information via the Website from visitors in this age group.</p>
|
||||
|
||||
<h3>Changes to the Privacy Policy</h3>
|
||||
|
||||
<p>We may amend this Privacy Policy from time to time. Use of information we collect now is subject to the Privacy Policy in effect at the time such information is used.</p>
|
||||
|
||||
<p>If we make major changes in the way we collect or use information, we will notify you by posting an announcement on the Website or sending you an email.</p>
|
||||
</div>
|
||||
{{< /rawhtml >}}
|
97
content/projects.md
Normal file
|
@ -0,0 +1,97 @@
|
|||
---
|
||||
title: "Projects"
|
||||
menu:
|
||||
main:
|
||||
weight: 30
|
||||
---
|
||||
# Projects
|
||||
|
||||
{{< rawhtml >}}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">About</th>
|
||||
<th scope="col">Tags</th>
|
||||
<th scope="col">Link(s)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Cyberfurz</th>
|
||||
<td>Just a collection of services I offer for free for furries of the metaverse.</td>
|
||||
<td><span class="badge badge-info">Photos</span> <span class="badge badge-info">Service</span></td>
|
||||
<td>
|
||||
<a href="https://cyberfurz.com" target="_blank" class="btn btn-secondary">Visit</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Zadaroo</th>
|
||||
<td>Free public OpenSimulator resources licensed under CC0.</td>
|
||||
<td><span class="badge badge-info">OpenSimulator</span> <span class="badge badge-info">Service</span></td>
|
||||
<td>
|
||||
<a href="https://zadaroo.com" target="_blank" class="btn btn-secondary">Visit</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3>Code:</h3>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">About</th>
|
||||
<th scope="col">Tags</th>
|
||||
<th scope="col">Link(s)</th>
|
||||
<th scope="col">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Ansible OpenNIC Setup</th>
|
||||
<td>Simple Ansible Playbook to install and configure an OpenNIC Tier 2 node on multiple distributions of Linux.</td>
|
||||
<td><span class="badge badge-info">Ansible Playbook</span> <span class="badge badge-info">Automation</span></td>
|
||||
<td>
|
||||
<a href="https://github.com/hack13/ansible-opennic-setup" target="_blank" class="btn btn-secondary"><i class="fab fa-github"></i></a>
|
||||
</td>
|
||||
<td><h4><span class="badge badge-warning">Un-Maintained</span></h4></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Ansible OpenSim Grid</th>
|
||||
<td>Grid Setup for OpenSim using Ansible on CentOS 7</td>
|
||||
<td><span class="badge badge-info">Ansible Playbook</span> <span class="badge badge-info">Automation</span></td>
|
||||
<td>
|
||||
<a href="https://github.com/hack13/ansible-opensim-grid" target="_blank" class="btn btn-secondary"><i class="fab fa-github"></i></a>
|
||||
</td>
|
||||
<td><h4><span class="badge badge-danger">Discontinued</span></h4></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">OpenSim Libre Panel</th>
|
||||
<td>OpenSimulator Standalone/Grid Management System</td>
|
||||
<td><span class="badge badge-info">PHP</span> <span class="badge badge-info">SQL</span></td>
|
||||
<td>
|
||||
<a href="https://github.com/hack13/opensim-libre-panel" target="_blank" class="btn btn-secondary"><i class="fab fa-github"></i></a>
|
||||
</td>
|
||||
<td><h4><span class="badge badge-danger">Discontinued</span></h4></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Zadaroo</th>
|
||||
<td>A static redesign of the Zadaroo site, to provide a more streamlined site.</td>
|
||||
<td><span class="badge badge-info">HTML</span> <span class="badge badge-info">JavaScript</span></td>
|
||||
<td>
|
||||
<a href="https://github.com/hack13/Zadaroo" target="_blank" class="btn btn-secondary"><i class="fab fa-github"></i></a>
|
||||
</td>
|
||||
<td><h4><span class="badge badge-success">Completed</span></h4></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{< /rawhtml >}}
|
6
content/testing/apple.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Apple
|
||||
url: /testing/apple
|
||||
---
|
||||
# This is an Apple
|
||||
I am a test page made on an Apple iPad
|
|
@ -1,62 +0,0 @@
|
|||
{
|
||||
"$schema": "https://frontmatter.codes/frontmatter.schema.json",
|
||||
"frontMatter.framework.id": "astro",
|
||||
"frontMatter.preview.host": "http://localhost:4321",
|
||||
"frontMatter.content.publicFolder": "public",
|
||||
"frontMatter.content.pageFolders": [
|
||||
{
|
||||
"title": "posts",
|
||||
"path": "[[workspace]]/src/content/posts"
|
||||
}
|
||||
],
|
||||
"frontMatter.taxonomy.contentTypes": [
|
||||
{
|
||||
"name": "default",
|
||||
"pageBundle": true,
|
||||
"previewPath": "'blog'",
|
||||
"filePrefix": null,
|
||||
"clearEmpty": true,
|
||||
"fields": [
|
||||
{
|
||||
"title": "title",
|
||||
"name": "title",
|
||||
"type": "string",
|
||||
"single": true
|
||||
},
|
||||
{
|
||||
"title": "description",
|
||||
"name": "description",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"title": "published",
|
||||
"name": "published",
|
||||
"type": "datetime",
|
||||
"default": "{{now}}",
|
||||
"isPublishDate": true
|
||||
},
|
||||
{
|
||||
"title": "preview",
|
||||
"name": "image",
|
||||
"type": "image",
|
||||
"isPreviewImage": true
|
||||
},
|
||||
{
|
||||
"title": "tags",
|
||||
"name": "tags",
|
||||
"type": "list"
|
||||
},
|
||||
{
|
||||
"title": "category",
|
||||
"name": "category",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"title": "draft",
|
||||
"name": "draft",
|
||||
"type": "boolean"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
20
layouts/post/single.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
{{- partial "head.html" . -}}
|
||||
<body>
|
||||
{{- partial "header.html" . -}}
|
||||
<br>
|
||||
<main role="main">
|
||||
<div class="container">
|
||||
{{- block "main" . }}{{- end }}
|
||||
<h1>{{ .Params.title }}</h1>
|
||||
<strong>Author:</strong> {{ .Params.author }} | <strong>Published:</strong> {{ .Date.Format "Jan 2, 2006" }} <hr/>
|
||||
{{ .Content }}
|
||||
<button class="btn btn-secondary" onclick="window.history.go(-1)">⇽ Go Back</button>
|
||||
<br/>
|
||||
</div>
|
||||
</main>
|
||||
{{- partial "footer.html" . -}}
|
||||
</body>
|
||||
</html>
|
||||
|
2
layouts/shortcodes/rawhtml.html
Normal file
|
@ -0,0 +1,2 @@
|
|||
<!-- raw html -->
|
||||
{{.Inner}}
|
72
package.json
|
@ -1,72 +0,0 @@
|
|||
{
|
||||
"name": "fuwari",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
"build": "astro build && pagefind --site dist",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro",
|
||||
"new-post": "node scripts/new-post.js",
|
||||
"format": "biome format --write ./src",
|
||||
"lint": "biome check --apply ./src"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.3",
|
||||
"@astrojs/rss": "^4.0.7",
|
||||
"@astrojs/sitemap": "^3.1.6",
|
||||
"@astrojs/svelte": "^5.7.0",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@fontsource-variable/jetbrains-mono": "^5.0.21",
|
||||
"@fontsource/roboto": "^5.0.13",
|
||||
"@swup/astro": "^1.4.1",
|
||||
"astro": "^4.14.5",
|
||||
"astro-compress": "^2.2.28",
|
||||
"astro-icon": "1.1.0",
|
||||
"colorjs.io": "^0.5.0",
|
||||
"hastscript": "^9.0.0",
|
||||
"markdown-it": "^14.1.0",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
"overlayscrollbars": "^2.8.3",
|
||||
"pagefind": "^1.1.0",
|
||||
"reading-time": "^1.5.0",
|
||||
"rehype-autolink-headings": "^7.1.0",
|
||||
"rehype-components": "^0.3.0",
|
||||
"rehype-katex": "^7.0.0",
|
||||
"rehype-slug": "^6.0.0",
|
||||
"remark-directive": "^3.0.0",
|
||||
"remark-directive-rehype": "^0.4.2",
|
||||
"remark-math": "^6.0.0",
|
||||
"sanitize-html": "^2.13.0",
|
||||
"sharp": "^0.33.4",
|
||||
"svelte": "^4.2.18",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"typescript": "^5.5.2",
|
||||
"unist-util-visit": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/ts-plugin": "^1.10.1",
|
||||
"@biomejs/biome": "1.8.2",
|
||||
"@iconify-json/fa6-brands": "^1.1.19",
|
||||
"@iconify-json/fa6-regular": "^1.1.19",
|
||||
"@iconify-json/fa6-solid": "^1.1.21",
|
||||
"@iconify-json/material-symbols": "^1.1.82",
|
||||
"@iconify/svelte": "^4.0.2",
|
||||
"@rollup/plugin-yaml": "^4.1.2",
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"@types/markdown-it": "^14.1.1",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"@types/sanitize-html": "^2.11.0",
|
||||
"remark-github-admonitions-to-directives": "^1.0.5",
|
||||
"sass": "^1.77.6",
|
||||
"stylus": "^0.63.0"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"vite-imagetools": "^6.2.7",
|
||||
"sharp": "^0.33.0"
|
||||
}
|
||||
},
|
||||
"packageManager": "pnpm@9.5.0-beta.3+sha512.8b0c4d7fd9937d73f06ad284e681ddfd0f08b8f792a4f854a3ea24d1c7ade57dfe952ce88ed174d57da694e8323f0bb5a25011f780ed2787759c647b35263fa1"
|
||||
}
|
10581
pnpm-lock.yaml
generated
|
@ -1,11 +0,0 @@
|
|||
import postcssImport from 'postcss-import';
|
||||
import postcssNesting from 'tailwindcss/nesting/index.js';
|
||||
import tailwindcss from 'tailwindcss';
|
||||
|
||||
export default {
|
||||
plugins: {
|
||||
'postcss-import': postcssImport, // to combine multiple css files
|
||||
'tailwindcss/nesting': postcssNesting,
|
||||
tailwindcss: tailwindcss,
|
||||
}
|
||||
};
|
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 426 B |
Before Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 554 B |
Before Width: | Height: | Size: 30 KiB |
|
@ -1,52 +0,0 @@
|
|||
/* This is a script to create a new post markdown file with front-matter */
|
||||
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
|
||||
function getDate() {
|
||||
const today = new Date()
|
||||
const year = today.getFullYear()
|
||||
const month = String(today.getMonth() + 1).padStart(2, "0")
|
||||
const day = String(today.getDate()).padStart(2, "0")
|
||||
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
const args = process.argv.slice(2)
|
||||
|
||||
if (args.length === 0) {
|
||||
console.error(`Error: No filename argument provided
|
||||
Usage: npm run new-post -- <filename>`)
|
||||
process.exit(1) // Terminate the script and return error code 1
|
||||
}
|
||||
|
||||
let fileName = args[0]
|
||||
|
||||
// Add .md extension if not present
|
||||
const fileExtensionRegex = /\.(md|mdx)$/i
|
||||
if (!fileExtensionRegex.test(fileName)) {
|
||||
fileName += ".md"
|
||||
}
|
||||
|
||||
const targetDir = "./src/content/posts/"
|
||||
const fullPath = path.join(targetDir, fileName)
|
||||
|
||||
if (fs.existsSync(fullPath)) {
|
||||
console.error(`Error:File ${fullPath} already exists `)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const content = `---
|
||||
title: ${args[0]}
|
||||
published: ${getDate()}
|
||||
description: ''
|
||||
image: ''
|
||||
tags: []
|
||||
category: ''
|
||||
draft: false
|
||||
---
|
||||
`
|
||||
|
||||
fs.writeFileSync(path.join(targetDir, fileName), content)
|
||||
|
||||
console.log(`Post ${fullPath} created`)
|
Before Width: | Height: | Size: 406 KiB |
Before Width: | Height: | Size: 877 KiB |
Before Width: | Height: | Size: 558 KiB |
|
@ -1,128 +0,0 @@
|
|||
---
|
||||
import {getSortedPosts} from "../utils/content-utils";
|
||||
import {getPostUrlBySlug} from "../utils/url-utils";
|
||||
import {i18n} from "../i18n/translation";
|
||||
import I18nKey from "../i18n/i18nKey";
|
||||
import {UNCATEGORIZED} from "@constants/constants";
|
||||
|
||||
interface Props {
|
||||
keyword: string;
|
||||
tags: string[];
|
||||
categories: string[];
|
||||
}
|
||||
const { keyword, tags, categories} = Astro.props;
|
||||
|
||||
let posts = await getSortedPosts()
|
||||
|
||||
if (Array.isArray(tags) && tags.length > 0) {
|
||||
posts = posts.filter(post =>
|
||||
Array.isArray(post.data.tags) && post.data.tags.some(tag => tags.includes(tag))
|
||||
);
|
||||
}
|
||||
|
||||
if (Array.isArray(categories) && categories.length > 0) {
|
||||
posts = posts.filter(post =>
|
||||
(post.data.category && categories.includes(post.data.category)) ||
|
||||
(!post.data.category && categories.includes(UNCATEGORIZED))
|
||||
);
|
||||
}
|
||||
|
||||
const groups = function () {
|
||||
const groupedPosts = posts.reduce((grouped, post) => {
|
||||
const year = post.data.published.getFullYear()
|
||||
if (!grouped[year]) {
|
||||
grouped[year] = []
|
||||
}
|
||||
grouped[year].push(post)
|
||||
return grouped
|
||||
}, {})
|
||||
|
||||
// convert the object to an array
|
||||
const groupedPostsArray = Object.keys(groupedPosts).map(key => ({
|
||||
year: key,
|
||||
posts: groupedPosts[key]
|
||||
}))
|
||||
|
||||
// sort years by latest first
|
||||
groupedPostsArray.sort((a, b) => b.year - a.year)
|
||||
return groupedPostsArray;
|
||||
}();
|
||||
|
||||
function formatDate(date: Date) {
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
return `${month}-${day}`;
|
||||
}
|
||||
|
||||
function formatTag(tag: string[]) {
|
||||
return tag.map(t => `#${t}`).join(' ');
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
<div class="card-base px-8 py-6">
|
||||
{
|
||||
groups.map(group => (
|
||||
<div>
|
||||
<div class="flex flex-row w-full items-center h-[3.75rem]">
|
||||
<div class="w-[15%] md:w-[10%] transition text-2xl font-bold text-right text-75">{group.year}</div>
|
||||
<div class="w-[15%] md:w-[10%]">
|
||||
<div class="h-3 w-3 bg-none rounded-full outline outline-[var(--primary)] mx-auto -outline-offset-[2px] z-50 outline-3"></div>
|
||||
</div>
|
||||
<div class="w-[70%] md:w-[80%] transition text-left text-50">{group.posts.length} {i18n(I18nKey.postsCount)}</div>
|
||||
</div>
|
||||
{group.posts.map(post => (
|
||||
<a href={getPostUrlBySlug(post.slug)}
|
||||
aria-label={post.data.title}
|
||||
class="group btn-plain block h-10 w-full rounded-lg hover:text-[initial]"
|
||||
>
|
||||
<div class="flex flex-row justify-start items-center h-full">
|
||||
<!-- date -->
|
||||
<div class="w-[15%] md:w-[10%] transition text-sm text-right text-50">
|
||||
{formatDate(post.data.published)}
|
||||
</div>
|
||||
<!-- dot and line -->
|
||||
<div class="w-[15%] md:w-[10%] relative dash-line h-full flex items-center">
|
||||
<div class="transition-all mx-auto w-1 h-1 rounded group-hover:h-5
|
||||
bg-[oklch(0.5_0.05_var(--hue))] group-hover:bg-[var(--primary)]
|
||||
outline outline-4 z-50
|
||||
outline-[var(--card-bg)]
|
||||
group-hover:outline-[var(--btn-plain-bg-hover)]
|
||||
group-active:outline-[var(--btn-plain-bg-active)]
|
||||
"
|
||||
></div>
|
||||
</div>
|
||||
<!-- post title -->
|
||||
<div class="w-[70%] md:max-w-[65%] md:w-[65%] text-left font-bold
|
||||
group-hover:translate-x-1 transition-all group-hover:text-[var(--primary)]
|
||||
text-75 pr-8 whitespace-nowrap overflow-ellipsis overflow-hidden"
|
||||
>
|
||||
{post.data.title}
|
||||
</div>
|
||||
<!-- tag list -->
|
||||
<div class="hidden md:block md:w-[15%] text-left text-sm transition
|
||||
whitespace-nowrap overflow-ellipsis overflow-hidden
|
||||
text-30"
|
||||
>{formatTag(post.data.tags)}</div>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer components {
|
||||
.dash-line {
|
||||
}
|
||||
.dash-line::before {
|
||||
content: "";
|
||||
@apply w-[10%] h-full absolute -top-1/2 left-[calc(50%_-_1px)] -top-[50%] border-l-[2px]
|
||||
border-dashed pointer-events-none border-[var(--line-color)] transition
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
|
||||
import {siteConfig} from "../config";
|
||||
|
||||
---
|
||||
|
||||
<div id="config-carrier" data-hue={siteConfig.themeColor.hue}>
|
||||
</div>
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
|
||||
import { profileConfig } from '../config'
|
||||
---
|
||||
|
||||
<div class="card-base max-w-[var(--page-width)] min-h-[4.5rem] rounded-b-none mx-auto flex items-center px-6">
|
||||
<div class="transition text-50 text-sm">
|
||||
© 2024 {profileConfig.name}. All Rights Reserved.
|
||||
<br>
|
||||
Powered by <a class="link text-[var(--primary)] font-medium" target="_blank" href="https://github.com/saicaca/fuwari">Fuwari</a> & <a class="link text-[var(--primary)] font-medium" target="_blank" href="https://astro.build">Astro</a>
|
||||
</div>
|
||||
</div>
|
||||
<script defer src="https://stats.hack13.cloud/script.js" data-website-id="d1001cd6-aa86-4ae0-82ca-8562331a4c96"></script>
|
|
@ -1,298 +0,0 @@
|
|||
---
|
||||
|
||||
---
|
||||
|
||||
<div>
|
||||
<slot/>
|
||||
</div>
|
||||
|
||||
<style is:global lang="stylus">
|
||||
|
||||
/* utils */
|
||||
white(a)
|
||||
rgba(255, 255, 255, a)
|
||||
|
||||
black(a)
|
||||
rgba(0, 0, 0, a)
|
||||
|
||||
isOklch(c)
|
||||
return substr(c, 0, 5) == 'oklch'
|
||||
|
||||
oklch_fallback(c)
|
||||
str = '' + c // convert color value to string
|
||||
if isOklch(str)
|
||||
return convert(oklchToHex(str))
|
||||
return c
|
||||
|
||||
color_set(colors)
|
||||
@supports (color: oklch(0 0 0))
|
||||
:root
|
||||
for key, value in colors
|
||||
{key}: value[0]
|
||||
:root.dark
|
||||
for key, value in colors
|
||||
if length(value) > 1
|
||||
{key}: value[1]
|
||||
/* provide fallback color for oklch */
|
||||
@supports not (color: oklch(0 0 0))
|
||||
:root
|
||||
for key, value in colors
|
||||
{key}: oklch_fallback(value[0])
|
||||
:root.dark
|
||||
for key, value in colors
|
||||
if length(value) > 1
|
||||
{key}: oklch_fallback(value[1])
|
||||
|
||||
rainbow-light = linear-gradient(to right, oklch(0.80 0.10 0), oklch(0.80 0.10 30), oklch(0.80 0.10 60), oklch(0.80 0.10 90), oklch(0.80 0.10 120), oklch(0.80 0.10 150), oklch(0.80 0.10 180), oklch(0.80 0.10 210), oklch(0.80 0.10 240), oklch(0.80 0.10 270), oklch(0.80 0.10 300), oklch(0.80 0.10 330), oklch(0.80 0.10 360))
|
||||
rainbow-dark = linear-gradient(to right, oklch(0.70 0.10 0), oklch(0.70 0.10 30), oklch(0.70 0.10 60), oklch(0.70 0.10 90), oklch(0.70 0.10 120), oklch(0.70 0.10 150), oklch(0.70 0.10 180), oklch(0.70 0.10 210), oklch(0.70 0.10 240), oklch(0.70 0.10 270), oklch(0.70 0.10 300), oklch(0.70 0.10 330), oklch(0.70 0.10 360))
|
||||
|
||||
:root
|
||||
--radius-large 1rem
|
||||
|
||||
--banner-height-home 60vh
|
||||
--banner-height 40vh
|
||||
|
||||
--content-delay 150ms
|
||||
|
||||
color_set({
|
||||
--primary: oklch(0.70 0.14 var(--hue)) oklch(0.75 0.14 var(--hue))
|
||||
--page-bg: oklch(0.95 0.01 var(--hue)) oklch(0.16 0.014 var(--hue))
|
||||
--card-bg: white oklch(0.23 0.015 var(--hue))
|
||||
|
||||
--btn-content: oklch(0.55 0.12 var(--hue)) oklch(0.75 0.1 var(--hue))
|
||||
|
||||
--btn-regular-bg: oklch(0.95 0.025 var(--hue)) oklch(0.33 0.035 var(--hue))
|
||||
--btn-regular-bg-hover: oklch(0.9 0.05 var(--hue)) oklch(0.38 0.04 var(--hue))
|
||||
--btn-regular-bg-active: oklch(0.85 0.08 var(--hue)) oklch(0.43 0.045 var(--hue))
|
||||
|
||||
--btn-plain-bg-hover: oklch(0.95 0.025 var(--hue)) oklch(0.30 0.035 var(--hue))
|
||||
--btn-plain-bg-active: oklch(0.98 0.01 var(--hue)) oklch(0.27 0.025 var(--hue))
|
||||
|
||||
--btn-card-bg-hover: oklch(0.98 0.005 var(--hue)) oklch(0.3 0.03 var(--hue))
|
||||
--btn-card-bg-active: oklch(0.9 0.03 var(--hue)) oklch(0.35 0.035 var(--hue))
|
||||
|
||||
--enter-btn-bg: var(--btn-regular-bg)
|
||||
--enter-btn-bg-hover: var(--btn-regular-bg-hover)
|
||||
--enter-btn-bg-active: var(--btn-regular-bg-active)
|
||||
|
||||
--deep-text: oklch(0.25 0.02 var(--hue))
|
||||
|
||||
--title-active: oklch(0.6 0.1 var(--hue))
|
||||
|
||||
--line-divider: black(0.08) white(0.08)
|
||||
|
||||
--line-color: black(0.1) white(0.1)
|
||||
--meta-divider: black(0.2) white(0.2)
|
||||
|
||||
--inline-code-bg: var(--btn-regular-bg)
|
||||
--inline-code-color: var(--btn-content)
|
||||
--selection-bg: oklch(0.90 0.05 var(--hue)) oklch(0.40 0.08 var(--hue))
|
||||
--codeblock-selection: oklch(0.40 0.08 var(--hue))
|
||||
--codeblock-bg: oklch(0.2 0.015 var(--hue)) oklch(0.17 0.015 var(--hue))
|
||||
|
||||
--license-block-bg: black(0.03) var(--codeblock-bg)
|
||||
|
||||
--link-underline: oklch(0.93 0.04 var(--hue)) oklch(0.40 0.08 var(--hue))
|
||||
--link-hover: oklch(0.95 0.025 var(--hue)) oklch(0.40 0.08 var(--hue))
|
||||
--link-active: oklch(0.90 0.05 var(--hue)) oklch(0.35 0.07 var(--hue))
|
||||
|
||||
--float-panel-bg: white oklch(0.19 0.015 var(--hue))
|
||||
|
||||
--scrollbar-bg-light: black(0.4)
|
||||
--scrollbar-bg-hover-light: black(0.5)
|
||||
--scrollbar-bg-active-light: black(0.6)
|
||||
|
||||
--scrollbar-bg-dark: white(0.4)
|
||||
--scrollbar-bg-hover-dark: white(0.5)
|
||||
--scrollbar-bg-active-dark: white(0.6)
|
||||
|
||||
--scrollbar-bg: var(--scrollbar-bg-light) var(--scrollbar-bg-dark)
|
||||
--scrollbar-bg-hover: var(--scrollbar-bg-hover-light) var(--scrollbar-bg-hover-dark)
|
||||
--scrollbar-bg-active: var(--scrollbar-bg-active-light) var(--scrollbar-bg-active-dark)
|
||||
|
||||
--color-selection-bar: rainbow-light rainbow-dark
|
||||
|
||||
--display-light-icon: 1 0
|
||||
--display-dark-icon: 0 1
|
||||
|
||||
--admonitions-color-tip: oklch(0.7 0.14 180) oklch(0.75 0.14 180)
|
||||
--admonitions-color-note: oklch(0.7 0.14 250) oklch(0.75 0.14 250)
|
||||
--admonitions-color-important: oklch(0.7 0.14 310) oklch(0.75 0.14 310)
|
||||
--admonitions-color-warning: oklch(0.7 0.14 60) oklch(0.75 0.14 60)
|
||||
--admonitions-color-caution: oklch(0.6 0.2 25) oklch(0.65 0.2 25)
|
||||
})
|
||||
|
||||
|
||||
/* some global styles */
|
||||
::selection
|
||||
background-color: var(--selection-bg)
|
||||
|
||||
.scrollbar-base.os-scrollbar
|
||||
transition: width 0.15s ease-in-out, height 0.15s ease-in-out, opacity 0.15s, visibility 0.15s, top 0.15s, right 0.15s, bottom 0.15s, left 0.15s;
|
||||
pointer-events: unset;
|
||||
&.os-scrollbar-horizontal
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
height: 16px;
|
||||
.os-scrollbar-track .os-scrollbar-handle
|
||||
height: 4px;
|
||||
border-radius: 4px;
|
||||
&:hover
|
||||
.os-scrollbar-track .os-scrollbar-handle
|
||||
height: 8px;
|
||||
&.px-2
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
&.os-scrollbar-vertical
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
width: 16px;
|
||||
.os-scrollbar-track .os-scrollbar-handle
|
||||
width: 4px;
|
||||
border-radius: 4px;
|
||||
&:hover
|
||||
.os-scrollbar-track .os-scrollbar-handle
|
||||
width: 8px;
|
||||
&.py-1
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
|
||||
.scrollbar-auto
|
||||
&.os-scrollbar
|
||||
--os-handle-bg: var(--scrollbar-bg);
|
||||
--os-handle-bg-hover: var(--scrollbar-bg-hover);
|
||||
--os-handle-bg-active: var(--scrollbar-bg-active);
|
||||
|
||||
.scrollbar-dark
|
||||
&.os-scrollbar
|
||||
--os-handle-bg: var(--scrollbar-bg-dark);
|
||||
--os-handle-bg-hover: var(--scrollbar-bg-hover-dark);
|
||||
--os-handle-bg-active: var(--scrollbar-bg-active-dark);
|
||||
|
||||
.scrollbar-light
|
||||
&.os-scrollbar
|
||||
--os-handle-bg: var(--scrollbar-bg-light);
|
||||
--os-handle-bg-hover: var(--scrollbar-bg-hover-light);
|
||||
--os-handle-bg-active: var(--scrollbar-bg-active-light);
|
||||
|
||||
|
||||
</style>
|
||||
<style is:global lang="scss">
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer components {
|
||||
.card-base {
|
||||
@apply rounded-[var(--radius-large)] overflow-hidden bg-[var(--card-bg)] transition;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6, p, a, span, li, ul, ol, blockquote, code, pre, table, th, td, strong {
|
||||
@apply transition;
|
||||
}
|
||||
.card-shadow {
|
||||
@apply drop-shadow-[0_2px_4px_rgba(0,0,0,0.005)]
|
||||
}
|
||||
.expand-animation {
|
||||
@apply relative before:ease-out before:transition active:bg-none hover:before:bg-[var(--btn-plain-bg-hover)] active:before:bg-[var(--btn-plain-bg-active)] z-0
|
||||
before:absolute before:rounded-[inherit] before:inset-0 before:scale-[0.85] hover:before:scale-100 before:-z-10
|
||||
}
|
||||
.link {
|
||||
@apply transition rounded-md p-1 -m-1 expand-animation;
|
||||
}
|
||||
.link-lg {
|
||||
@apply transition rounded-md p-1.5 -m-1.5 expand-animation;
|
||||
}
|
||||
.float-panel {
|
||||
@apply top-[5.25rem] rounded-[var(--radius-large)] overflow-hidden bg-[var(--float-panel-bg)] transition shadow-xl dark:shadow-none
|
||||
}
|
||||
.float-panel-closed {
|
||||
@apply -translate-y-1 opacity-0 pointer-events-none
|
||||
}
|
||||
.search-panel mark {
|
||||
@apply bg-transparent text-[var(--primary)]
|
||||
}
|
||||
|
||||
.btn-card {
|
||||
@apply transition flex items-center justify-center bg-[var(--card-bg)] hover:bg-[var(--btn-card-bg-hover)]
|
||||
active:bg-[var(--btn-card-bg-active)]
|
||||
}
|
||||
.btn-card.disabled {
|
||||
@apply pointer-events-none text-black/10 dark:text-white/10
|
||||
}
|
||||
.btn-plain {
|
||||
@apply transition relative flex items-center justify-center bg-none
|
||||
text-black/75 hover:text-[var(--primary)] dark:text-white/75 dark:hover:text-[var(--primary)];
|
||||
&:not(.scale-animation) {
|
||||
@apply hover:bg-[var(--btn-plain-bg-hover)] active:bg-[var(--btn-plain-bg-active)]
|
||||
}
|
||||
&.scale-animation {
|
||||
@apply expand-animation;
|
||||
&.current-theme-btn {
|
||||
@apply before:scale-100 before:opacity-100 before:bg-[var(--btn-plain-bg-hover)] text-[var(--primary)]
|
||||
}
|
||||
}
|
||||
}
|
||||
.btn-regular {
|
||||
@apply transition flex items-center justify-center bg-[var(--btn-regular-bg)] hover:bg-[var(--btn-regular-bg-hover)] active:bg-[var(--btn-regular-bg-active)]
|
||||
text-[var(--btn-content)] dark:text-white/75
|
||||
}
|
||||
|
||||
.link-underline {
|
||||
@apply transition underline decoration-2 decoration-dashed decoration-[var(--link-underline)]
|
||||
hover:decoration-[var(--link-hover)] active:decoration-[var(--link-active)] underline-offset-[0.25rem]
|
||||
}
|
||||
|
||||
.text-90 {
|
||||
@apply text-black/90 dark:text-white/90
|
||||
}
|
||||
.text-75 {
|
||||
@apply text-black/75 dark:text-white/75
|
||||
}
|
||||
.text-50 {
|
||||
@apply text-black/50 dark:text-white/50
|
||||
}
|
||||
.text-30 {
|
||||
@apply text-black/30 dark:text-white/30
|
||||
}
|
||||
.text-25 {
|
||||
@apply text-black/25 dark:text-white/25
|
||||
}
|
||||
|
||||
html.is-changing .transition-fade {
|
||||
@apply transition-all duration-200
|
||||
}
|
||||
html.is-animating .transition-fade {
|
||||
@apply opacity-0 translate-y-4
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in-up {
|
||||
0% {
|
||||
transform: translateY(2rem);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.onload-animation {
|
||||
opacity: 0;
|
||||
animation: 300ms fade-in-up;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
#top-row {
|
||||
animation-delay: 0ms
|
||||
}
|
||||
#sidebar {
|
||||
animation-delay: 100ms
|
||||
}
|
||||
#content-wrapper {
|
||||
animation-delay: var(--content-delay);
|
||||
}
|
||||
#footer {
|
||||
animation-delay: 400ms;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
|
@ -1,120 +0,0 @@
|
|||
<script lang="ts">
|
||||
import type { LIGHT_DARK_MODE } from '@/types/config.ts'
|
||||
import {
|
||||
AUTO_MODE,
|
||||
DARK_MODE,
|
||||
LIGHT_MODE,
|
||||
} from '@constants/constants.ts'
|
||||
import I18nKey from '@i18n/i18nKey'
|
||||
import { i18n } from '@i18n/translation'
|
||||
import Icon from '@iconify/svelte'
|
||||
import {
|
||||
applyThemeToDocument,
|
||||
getStoredTheme,
|
||||
setTheme,
|
||||
} from '@utils/setting-utils.ts'
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
const seq: LIGHT_DARK_MODE[] = [
|
||||
LIGHT_MODE,
|
||||
DARK_MODE,
|
||||
AUTO_MODE,
|
||||
]
|
||||
let mode: LIGHT_DARK_MODE = AUTO_MODE
|
||||
|
||||
onMount(() => {
|
||||
mode = getStoredTheme()
|
||||
const darkModePreference = window.matchMedia(
|
||||
'(prefers-color-scheme: dark)',
|
||||
)
|
||||
const changeThemeWhenSchemeChanged: Parameters<
|
||||
typeof darkModePreference.addEventListener<'change'>
|
||||
>[1] = e => {
|
||||
applyThemeToDocument(mode)
|
||||
}
|
||||
darkModePreference.addEventListener(
|
||||
'change',
|
||||
changeThemeWhenSchemeChanged,
|
||||
)
|
||||
return () => {
|
||||
darkModePreference.removeEventListener(
|
||||
'change',
|
||||
changeThemeWhenSchemeChanged,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
function switchScheme(newMode: LIGHT_DARK_MODE) {
|
||||
mode = newMode
|
||||
setTheme(newMode)
|
||||
}
|
||||
|
||||
function toggleScheme() {
|
||||
let i = 0
|
||||
for (; i < seq.length; i++) {
|
||||
if (seq[i] === mode) {
|
||||
break
|
||||
}
|
||||
}
|
||||
switchScheme(seq[(i + 1) % seq.length])
|
||||
}
|
||||
|
||||
function showPanel() {
|
||||
const panel = document.querySelector('#light-dark-panel')
|
||||
panel.classList.remove('float-panel-closed')
|
||||
}
|
||||
|
||||
function hidePanel() {
|
||||
const panel = document.querySelector('#light-dark-panel')
|
||||
panel.classList.add('float-panel-closed')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<!-- z-50 make the panel higher than other float panels -->
|
||||
<div class="relative z-50" role="menu" tabindex="-1" on:mouseleave={hidePanel}>
|
||||
<button aria-label="Light/Dark Mode" role="menuitem" class="relative btn-plain scale-animation rounded-lg h-11 w-11 active:scale-90" id="scheme-switch" on:click={toggleScheme} on:mouseenter={showPanel}>
|
||||
<div class="absolute" class:opacity-0={mode !== LIGHT_MODE}>
|
||||
<Icon icon="material-symbols:wb-sunny-outline-rounded" class="text-[1.25rem]"></Icon>
|
||||
</div>
|
||||
<div class="absolute" class:opacity-0={mode !== DARK_MODE}>
|
||||
<Icon icon="material-symbols:dark-mode-outline-rounded" class="text-[1.25rem]"></Icon>
|
||||
</div>
|
||||
<div class="absolute" class:opacity-0={mode !== AUTO_MODE}>
|
||||
<Icon icon="material-symbols:radio-button-partial-outline" class="text-[1.25rem]"></Icon>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div id="light-dark-panel" class="hidden lg:block absolute transition float-panel-closed top-11 -right-2 pt-5" >
|
||||
<div class="card-base float-panel p-2">
|
||||
<button class="flex transition whitespace-nowrap items-center justify-start w-full btn-plain scale-animation rounded-lg h-9 px-3 font-medium active:scale-95 mb-0.5"
|
||||
class:current-theme-btn={mode === LIGHT_MODE}
|
||||
on:click={() => switchScheme(LIGHT_MODE)}
|
||||
>
|
||||
<Icon icon="material-symbols:wb-sunny-outline-rounded" class="text-[1.25rem] mr-3"></Icon>
|
||||
{i18n(I18nKey.lightMode)}
|
||||
</button>
|
||||
<button class="flex transition whitespace-nowrap items-center justify-start w-full btn-plain scale-animation rounded-lg h-9 px-3 font-medium active:scale-95 mb-0.5"
|
||||
class:current-theme-btn={mode === DARK_MODE}
|
||||
on:click={() => switchScheme(DARK_MODE)}
|
||||
>
|
||||
<Icon icon="material-symbols:dark-mode-outline-rounded" class="text-[1.25rem] mr-3"></Icon>
|
||||
{i18n(I18nKey.darkMode)}
|
||||
</button>
|
||||
<button class="flex transition whitespace-nowrap items-center justify-start w-full btn-plain scale-animation rounded-lg h-9 px-3 font-medium active:scale-95"
|
||||
class:current-theme-btn={mode === AUTO_MODE}
|
||||
on:click={() => switchScheme(AUTO_MODE)}
|
||||
>
|
||||
<Icon icon="material-symbols:radio-button-partial-outline" class="text-[1.25rem] mr-3"></Icon>
|
||||
{i18n(I18nKey.systemMode)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="css">
|
||||
.current-setting {
|
||||
background: var(--btn-plain-bg-hover);
|
||||
color: var(--primary);
|
||||
}
|
||||
</style>
|
|
@ -1,120 +0,0 @@
|
|||
---
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import DisplaySettings from "./widget/DisplaySettings.svelte";
|
||||
import {LinkPreset, NavBarLink} from "../types/config";
|
||||
import {navBarConfig, siteConfig} from "../config";
|
||||
import NavMenuPanel from "./widget/NavMenuPanel.astro";
|
||||
import Search from "./Search.svelte";
|
||||
import {LinkPresets} from "../constants/link-presets";
|
||||
import LightDarkSwitch from "./LightDarkSwitch.svelte";
|
||||
import {url} from "../utils/url-utils";
|
||||
const className = Astro.props.class;
|
||||
|
||||
let links: NavBarLink[] = navBarConfig.links.map((item: NavBarLink | LinkPreset): NavBarLink => {
|
||||
if (typeof item === "number") {
|
||||
return LinkPresets[item]
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
---
|
||||
<div class:list={[
|
||||
className,
|
||||
"card-base sticky top-0 overflow-visible max-w-[var(--page-width)] h-[4.5rem] rounded-t-none mx-auto flex items-center justify-between px-4"]}>
|
||||
<a href={url('/')} class="btn-plain scale-animation rounded-lg h-[3.25rem] px-5 font-bold active:scale-95">
|
||||
<div class="flex flex-row text-[var(--primary)] items-center text-md">
|
||||
<Icon name="material-symbols:home-outline-rounded" size={"1.75rem"} class="mb-1 mr-2" />
|
||||
{siteConfig.title}
|
||||
</div>
|
||||
</a>
|
||||
<div class="hidden md:flex">
|
||||
{links.map((l) => {
|
||||
return <a aria-label={l.name} href={l.external ? l.url : url(l.url)} target={l.external ? "_blank" : null}
|
||||
class="btn-plain scale-animation rounded-lg h-11 font-bold px-5 active:scale-95"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
{l.name}
|
||||
{l.external && <Icon size="14" name="fa6-solid:arrow-up-right-from-square" class="transition -translate-y-[1px] ml-1 text-black/[0.2] dark:text-white/[0.2]"></Icon>}
|
||||
</div>
|
||||
</a>;
|
||||
})}
|
||||
</div>
|
||||
<div class="flex">
|
||||
<!--<SearchPanel client:load>-->
|
||||
<Search client:load>
|
||||
<Icon slot="search-icon" name="material-symbols:search" size={"1.25rem"} class="absolute pointer-events-none ml-3 transition my-auto text-black/30 dark:text-white/30"></Icon>
|
||||
<!--<Icon slot="arrow-icon" name="material-symbols:chevron-right-rounded" size={"1.25rem"} class="transition my-auto text-[var(--primary)]"></Icon>-->
|
||||
<Icon slot="arrow-icon" name="fa6-solid:chevron-right" size={"0.75rem"} class="transition translate-x-0.5 my-auto text-[var(--primary)]"></Icon>
|
||||
<Icon slot="search-switch" name="material-symbols:search" size={"1.25rem"}></Icon>
|
||||
</Search>
|
||||
{!siteConfig.themeColor.fixed && (
|
||||
<button aria-label="Display Settings" class="btn-plain scale-animation rounded-lg h-11 w-11 active:scale-90" id="display-settings-switch">
|
||||
<Icon name="material-symbols:palette-outline" size={"1.25rem"}></Icon>
|
||||
</button>
|
||||
)}
|
||||
<LightDarkSwitch client:load></LightDarkSwitch>
|
||||
<button aria-label="Menu" name="Nav Menu" class="btn-plain scale-animation rounded-lg w-11 h-11 active:scale-90 md:hidden" id="nav-menu-switch">
|
||||
<Icon name="material-symbols:menu-rounded" size={"1.25rem"}></Icon>
|
||||
</button>
|
||||
</div>
|
||||
<NavMenuPanel links={links}></NavMenuPanel>
|
||||
<DisplaySettings client:only="svelte">
|
||||
<Icon slot="restore-icon" name="fa6-solid:arrow-rotate-left" size={"0.875rem"} class=""></Icon>
|
||||
</DisplaySettings>
|
||||
</div>
|
||||
|
||||
<style lang="stylus">
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
function switchTheme() {
|
||||
if (localStorage.theme === 'dark') {
|
||||
document.documentElement.classList.remove('dark');
|
||||
localStorage.theme = 'light';
|
||||
} else {
|
||||
document.documentElement.classList.add('dark');
|
||||
localStorage.theme = 'dark';
|
||||
}
|
||||
}
|
||||
|
||||
function loadButtonScript() {
|
||||
let switchBtn = document.getElementById("scheme-switch");
|
||||
switchBtn.addEventListener("click", function () {
|
||||
switchTheme()
|
||||
});
|
||||
|
||||
let settingBtn = document.getElementById("display-settings-switch");
|
||||
if (settingBtn) {
|
||||
settingBtn.addEventListener("click", function () {
|
||||
let settingPanel = document.getElementById("display-setting");
|
||||
settingPanel.classList.toggle("float-panel-closed");
|
||||
});
|
||||
}
|
||||
|
||||
let menuBtn = document.getElementById("nav-menu-switch");
|
||||
menuBtn.addEventListener("click", function () {
|
||||
let menuPanel = document.getElementById("nav-menu-panel");
|
||||
menuPanel.classList.toggle("float-panel-closed");
|
||||
});
|
||||
}
|
||||
|
||||
loadButtonScript();
|
||||
|
||||
document.addEventListener('astro:after-swap', () => {
|
||||
loadButtonScript();
|
||||
}, { once: false });
|
||||
</script>
|
||||
|
||||
{import.meta.env.PROD && <script is:inline define:vars={{scriptUrl: url('/pagefind/pagefind.js')}}>
|
||||
async function loadPagefind() {
|
||||
const pagefind = await import(scriptUrl)
|
||||
await pagefind.options({
|
||||
'excerptLength': 20
|
||||
})
|
||||
pagefind.init()
|
||||
window.pagefind = pagefind
|
||||
pagefind.search('') // speed up the first search
|
||||
}
|
||||
loadPagefind()
|
||||
</script>}
|
|
@ -1,95 +0,0 @@
|
|||
---
|
||||
import path from "path";
|
||||
import PostMetadata from "./PostMeta.astro";
|
||||
import ImageWrapper from "./misc/ImageWrapper.astro";
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import {i18n} from "../i18n/translation";
|
||||
import I18nKey from "../i18n/i18nKey";
|
||||
import {getDir} from "../utils/url-utils";
|
||||
|
||||
interface Props {
|
||||
class: string;
|
||||
entry: any;
|
||||
title: string;
|
||||
url: string;
|
||||
published: Date;
|
||||
tags: string[];
|
||||
category: string;
|
||||
image: string;
|
||||
description: string;
|
||||
words: number;
|
||||
draft: boolean;
|
||||
style: string;
|
||||
}
|
||||
const { entry, title, url, published, tags, category, image, description, words, style } = Astro.props;
|
||||
const className = Astro.props.class;
|
||||
|
||||
const hasCover = image !== undefined && image !== null && image !== '';
|
||||
|
||||
const coverWidth = "28%";
|
||||
|
||||
const { remarkPluginFrontmatter } = await entry.render();
|
||||
|
||||
---
|
||||
<div class:list={["card-base flex flex-col-reverse md:flex-col w-full rounded-[var(--radius-large)] overflow-hidden relative", className]} style={style}>
|
||||
<div class:list={["pl-6 md:pl-9 pr-6 md:pr-2 pt-6 md:pt-7 pb-6 relative", {"w-full md:w-[calc(100%_-_52px_-_12px)]": !hasCover, "w-full md:w-[calc(100%_-_var(--coverWidth)_-_12px)]": hasCover}]}>
|
||||
<a href={url}
|
||||
class="transition group w-full block font-bold mb-3 text-3xl text-90
|
||||
hover:text-[var(--primary)] dark:hover:text-[var(--primary)]
|
||||
active:text-[var(--title-active)] dark:active:text-[var(--title-active)]
|
||||
before:w-1 before:h-5 before:rounded-md before:bg-[var(--primary)]
|
||||
before:absolute before:top-[35px] before:left-[18px] before:hidden md:before:block
|
||||
">
|
||||
{title}
|
||||
<Icon class="inline text-[var(--primary)] md:hidden translate-y-0.5 absolute" name="material-symbols:chevron-right-rounded" size="2rem" ></Icon>
|
||||
<Icon class="text-[var(--primary)] transition hidden md:inline absolute translate-y-0.5 opacity-0 group-hover:opacity-100 -translate-x-1 group-hover:translate-x-0" name="material-symbols:chevron-right-rounded" size="2rem" ></Icon>
|
||||
</a>
|
||||
|
||||
<!-- metadata -->
|
||||
<PostMetadata published={published} tags={tags} category={category} hideTagsForMobile={true} class="mb-4"></PostMetadata>
|
||||
|
||||
<!-- description -->
|
||||
<div class="transition text-75 mb-3.5 pr-4">
|
||||
{ description }
|
||||
</div>
|
||||
|
||||
<!-- word count and read time -->
|
||||
<div class="text-sm text-black/30 dark:text-white/30 flex gap-4 transition">
|
||||
<div>{remarkPluginFrontmatter.words} {" " + i18n(I18nKey.wordsCount)}</div>
|
||||
<div>|</div>
|
||||
<div>{remarkPluginFrontmatter.minutes} {" " + i18n(I18nKey.minutesCount)}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{hasCover && <a href={url} aria-label={title}
|
||||
class:list={["group",
|
||||
"max-h-[20vh] md:max-h-none mx-4 mt-4 -mb-2 md:mb-0 md:mx-0 md:mt-0",
|
||||
"md:w-[var(--coverWidth)] relative md:absolute md:top-3 md:bottom-3 md:right-3 rounded-xl overflow-hidden active:scale-95"
|
||||
]} >
|
||||
<div class="absolute pointer-events-none z-10 w-full h-full group-hover:bg-black/30 group-active:bg-black/50 transition"></div>
|
||||
<div class="absolute pointer-events-none z-20 w-full h-full flex items-center justify-center ">
|
||||
<Icon name="material-symbols:chevron-right-rounded"
|
||||
class="transition opacity-0 group-hover:opacity-100 scale-50 group-hover:scale-100 text-white text-5xl">
|
||||
</Icon>
|
||||
</div>
|
||||
<ImageWrapper src={image} basePath={path.join("content/posts/", getDir(entry.id))} alt="Cover Image of the Post"
|
||||
class="w-full h-full">
|
||||
</ImageWrapper>
|
||||
</a>}
|
||||
|
||||
{!hasCover &&
|
||||
<a href={url} aria-label={title} class="hidden md:flex btn-regular w-[3.25rem]
|
||||
absolute right-3 top-3 bottom-3 rounded-xl bg-[var(--enter-btn-bg)]
|
||||
hover:bg-[var(--enter-btn-bg-hover)] active:bg-[var(--enter-btn-bg-active)] active:scale-95
|
||||
">
|
||||
<Icon name="material-symbols:chevron-right-rounded"
|
||||
class="transition text-[var(--primary)] text-4xl mx-auto">
|
||||
</Icon>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
<div class="transition border-t-[1px] border-dashed mx-6 border-black/10 dark:border-white/[0.15] last:border-t-0 md:hidden"></div>
|
||||
|
||||
<style lang="stylus" define:vars={{coverWidth}}>
|
||||
</style>
|
|
@ -1,77 +0,0 @@
|
|||
---
|
||||
import {formatDateToYYYYMMDD} from "../utils/date-utils";
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import {i18n} from "../i18n/translation";
|
||||
import I18nKey from "../i18n/i18nKey";
|
||||
import {url} from "../utils/url-utils";
|
||||
|
||||
interface Props {
|
||||
class: string;
|
||||
published: Date;
|
||||
tags: string[];
|
||||
category: string;
|
||||
hideTagsForMobile: boolean;
|
||||
}
|
||||
const {published, tags, category, hideTagsForMobile} = Astro.props;
|
||||
const className = Astro.props.class;
|
||||
---
|
||||
|
||||
<div class:list={["flex flex-wrap text-neutral-500 dark:text-neutral-400 items-center gap-4 gap-x-4 gap-y-2", className]}>
|
||||
<!-- publish date -->
|
||||
<div class="flex items-center">
|
||||
<div class="meta-icon"
|
||||
>
|
||||
<Icon name="material-symbols:calendar-today-outline-rounded" class="text-xl"></Icon>
|
||||
</div>
|
||||
<span class="text-50 text-sm font-medium">{formatDateToYYYYMMDD(published)}</span>
|
||||
</div>
|
||||
|
||||
<!-- categories -->
|
||||
<div class="flex items-center">
|
||||
<div class="meta-icon"
|
||||
>
|
||||
<Icon name="material-symbols:menu-rounded" class="text-xl"></Icon>
|
||||
</div>
|
||||
<div class="flex flex-row flex-nowrap items-center">
|
||||
<a href={url(`/archive/category/${category || 'uncategorized'}/`)} aria-label=`View all posts in the ${category} category`
|
||||
class="link-lg transition text-50 text-sm font-medium
|
||||
hover:text-[var(--primary)] dark:hover:text-[var(--primary)] whitespace-nowrap">
|
||||
{category || i18n(I18nKey.uncategorized)}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- tags -->
|
||||
<div class:list={["items-center", {"flex": !hideTagsForMobile, "hidden md:flex": hideTagsForMobile}]}>
|
||||
<div class="meta-icon"
|
||||
>
|
||||
<Icon name="material-symbols:tag-rounded" class="text-xl"></Icon>
|
||||
</div>
|
||||
<div class="flex flex-row flex-nowrap items-center">
|
||||
{(tags && tags.length > 0) && tags.map((tag, i) => (
|
||||
<div class:list={[{"hidden": i == 0}, "mx-1.5 text-[var(--meta-divider)] text-sm"]}>/</div>
|
||||
<a href={url(`/archive/tag/${tag}/`)} aria-label=`View all posts with the ${tag} tag`
|
||||
class="link-lg transition text-50 text-sm font-medium
|
||||
hover:text-[var(--primary)] dark:hover:text-[var(--primary)] whitespace-nowrap">
|
||||
{tag}
|
||||
</a>
|
||||
))}
|
||||
{!(tags && tags.length > 0) && <div class="transition text-50 text-sm font-medium">{i18n(I18nKey.noTags)}</div>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@tailwind components;
|
||||
|
||||
@layer components {
|
||||
.meta-icon {
|
||||
@apply w-8 h-8 transition rounded-md flex items-center justify-center bg-[var(--btn-regular-bg)]
|
||||
text-[var(--btn-content)] mr-2
|
||||
}
|
||||
.with-divider {
|
||||
@apply before:content-['/'] before:ml-1.5 before:mr-1.5 before:text-[var(--meta-divider)] before:text-sm
|
||||
before:font-medium before:first-of-type:hidden before:transition
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,28 +0,0 @@
|
|||
---
|
||||
import {getPostUrlBySlug} from "@utils/url-utils";
|
||||
import PostCard from "./PostCard.astro";
|
||||
|
||||
const {page} = Astro.props;
|
||||
|
||||
let delay = 0
|
||||
const interval = 50
|
||||
---
|
||||
<div class="transition flex flex-col rounded-[var(--radius-large)] bg-[var(--card-bg)] py-1 md:py-0 md:bg-transparent md:gap-4 mb-4">
|
||||
{page.data.map((entry: { data: { draft: boolean; title: string; tags: string[]; category: string; published: Date; image: string; description: string; }; slug: string; }) => {
|
||||
return (
|
||||
<PostCard
|
||||
entry={entry}
|
||||
title={entry.data.title}
|
||||
tags={entry.data.tags}
|
||||
category={entry.data.category}
|
||||
published={entry.data.published}
|
||||
url={getPostUrlBySlug(entry.slug)}
|
||||
image={entry.data.image}
|
||||
description={entry.data.description}
|
||||
draft={entry.data.draft}
|
||||
class:list="onload-animation"
|
||||
style={`animation-delay: calc(var(--content-delay) + ${delay++ * interval}ms);`}
|
||||
></PostCard>
|
||||
);
|
||||
})}
|
||||
</div>
|
|
@ -1,116 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte'
|
||||
import {url} from "@utils/url-utils.ts"
|
||||
import { i18n } from '@i18n/translation';
|
||||
import I18nKey from '@i18n/i18nKey';
|
||||
let keywordDesktop = ''
|
||||
let keywordMobile = ''
|
||||
let result = []
|
||||
const fakeResult = [{
|
||||
url: url('/'),
|
||||
meta: {
|
||||
title: 'This Is a Fake Search Result'
|
||||
},
|
||||
excerpt: 'Because the search cannot work in the <mark>dev</mark> environment.'
|
||||
}, {
|
||||
url: url('/'),
|
||||
meta: {
|
||||
title: 'If You Want to Test the Search'
|
||||
},
|
||||
excerpt: 'Try running <mark>npm build && npm preview</mark> instead.'
|
||||
}]
|
||||
|
||||
let search = (keyword: string, isDesktop: boolean) => {}
|
||||
|
||||
onMount(() => {
|
||||
search = async (keyword: string, isDesktop: boolean) => {
|
||||
let panel = document.getElementById('search-panel')
|
||||
if (!panel)
|
||||
return
|
||||
|
||||
if (!keyword && isDesktop) {
|
||||
panel.classList.add("float-panel-closed")
|
||||
return
|
||||
}
|
||||
|
||||
let arr = [];
|
||||
if (import.meta.env.PROD) {
|
||||
const ret = await pagefind.search(keyword)
|
||||
for (const item of ret.results) {
|
||||
arr.push(await item.data())
|
||||
}
|
||||
} else {
|
||||
// Mock data for non-production environment
|
||||
// arr = JSON.parse('[{"url":"/","content":"Simple Guides for Fuwari. Cover image source: Source. This blog template is built with Astro. For the things that are not mentioned in this guide, you may find the answers in the Astro Docs. Front-matter of Posts. --- title: My First Blog Post published: 2023-09-09 description: This is the first post of my new Astro blog. image: ./cover.jpg tags: [Foo, Bar] category: Front-end draft: false ---AttributeDescription title. The title of the post. published. The date the post was published. description. A short description of the post. Displayed on index page. image. The cover image path of the post. 1. Start with http:// or https://: Use web image 2. Start with /: For image in public dir 3. With none of the prefixes: Relative to the markdown file. tags. The tags of the post. category. The category of the post. draft. If this post is still a draft, which won’t be displayed. Where to Place the Post Files. Your post files should be placed in src/content/posts/ directory. You can also create sub-directories to better organize your posts and assets. src/content/posts/ ├── post-1.md └── post-2/ ├── cover.png └── index.md.","word_count":187,"filters":{},"meta":{"title":"This Is a Fake Search Result"},"anchors":[{"element":"h2","id":"front-matter-of-posts","text":"Front-matter of Posts","location":34},{"element":"h2","id":"where-to-place-the-post-files","text":"Where to Place the Post Files","location":151}],"weighted_locations":[{"weight":10,"balanced_score":57600,"location":3}],"locations":[3],"raw_content":"Simple Guides for Fuwari. Cover image source: Source. This blog template is built with Astro. For the things that are not mentioned in this guide, you may find the answers in the Astro Docs. Front-matter of Posts. --- title: My First Blog Post published: 2023-09-09 description: This is the first post of my new Astro blog. image: ./cover.jpg tags: [Foo, Bar] category: Front-end draft: false ---AttributeDescription title. The title of the post. published. The date the post was published. description. A short description of the post. Displayed on index page. image. The cover image path of the post. 1. Start with http:// or https://: Use web image 2. Start with /: For image in public dir 3. With none of the prefixes: Relative to the markdown file. tags. The tags of the post. category. The category of the post. draft. If this post is still a draft, which won’t be displayed. Where to Place the Post Files. Your post files should be placed in src/content/posts/ directory. You can also create sub-directories to better organize your posts and assets. src/content/posts/ ├── post-1.md └── post-2/ ├── cover.png └── index.md.","raw_url":"/posts/guide/","excerpt":"Because the search cannot work in the <mark>dev</mark> environment.","sub_results":[{"title":"Simple Guides for Fuwari - Fuwari","url":"/posts/guide/","weighted_locations":[{"weight":10,"balanced_score":57600,"location":3}],"locations":[3],"excerpt":"Simple Guides for <mark>Fuwari.</mark> Cover image source: Source. This blog template is built with Astro. For the things that are not mentioned in this guide, you may find the answers"}]},{"url":"/","content":"About. This is the demo site for Fuwari. Sources of images used in this site. Unsplash. 星と少女 by Stella. Rabbit - v1.4 Showcase by Rabbit_YourMajesty.","word_count":25,"filters":{},"meta":{"title":"If You Want to Test the Search"},"anchors":[{"element":"h1","id":"about","text":"About","location":0},{"element":"h3","id":"sources-of-images-used-in-this-site","text":"Sources of images used in this site","location":8}],"weighted_locations":[{"weight":1,"balanced_score":576,"location":7}],"locations":[7],"raw_content":"About. This is the demo site for Fuwari. Sources of images used in this site. Unsplash. 星と少女 by Stella. Rabbit - v1.4 Showcase by Rabbit_YourMajesty.","raw_url":"/about/","excerpt":"Try running <mark>npm build && npm preview</mark> instead.","sub_results":[{"title":"About","url":"/about/#about","anchor":{"element":"h1","id":"about","text":"About","location":0},"weighted_locations":[{"weight":1,"balanced_score":576,"location":7}],"locations":[7],"excerpt":"About. This is the demo site for <mark>Fuwari.</mark>"}]}]')
|
||||
arr = fakeResult
|
||||
}
|
||||
|
||||
if (!arr.length && isDesktop) {
|
||||
panel.classList.add("float-panel-closed")
|
||||
return
|
||||
}
|
||||
|
||||
if (isDesktop) {
|
||||
panel.classList.remove("float-panel-closed")
|
||||
}
|
||||
result = arr
|
||||
}
|
||||
})
|
||||
|
||||
const togglePanel = () => {
|
||||
let panel = document.getElementById('search-panel')
|
||||
panel?.classList.toggle("float-panel-closed")
|
||||
}
|
||||
|
||||
$: search(keywordDesktop, true)
|
||||
$: search(keywordMobile, false)
|
||||
</script>
|
||||
|
||||
<!-- search bar for desktop view -->
|
||||
<div id="search-bar" class="hidden lg:flex transition-all items-center h-11 mr-2 rounded-lg
|
||||
bg-black/[0.04] hover:bg-black/[0.06] focus-within:bg-black/[0.06]
|
||||
dark:bg-white/5 dark:hover:bg-white/10 dark:focus-within:bg-white/10
|
||||
">
|
||||
<slot name="search-icon"></slot>
|
||||
<input placeholder="{i18n(I18nKey.search)}" bind:value={keywordDesktop} on:focus={() => search(keywordDesktop, true)}
|
||||
class="transition-all pl-10 text-sm bg-transparent outline-0
|
||||
h-full w-40 active:w-60 focus:w-60 text-black/50 dark:text-white/50"
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- toggle btn for phone/tablet view -->
|
||||
<button on:click={togglePanel} aria-label="Search Panel" id="search-switch"
|
||||
class="btn-plain scale-animation lg:hidden rounded-lg w-11 h-11 active:scale-90">
|
||||
<slot name="search-switch"></slot>
|
||||
</button>
|
||||
|
||||
<!-- search panel -->
|
||||
<div id="search-panel" class="float-panel float-panel-closed search-panel absolute md:w-[30rem]
|
||||
top-20 left-4 md:left-[unset] right-4 shadow-2xl rounded-2xl p-2">
|
||||
|
||||
<!-- search bar inside panel for phone/tablet -->
|
||||
<div id="search-bar-inside" class="flex relative lg:hidden transition-all items-center h-11 rounded-xl
|
||||
bg-black/[0.04] hover:bg-black/[0.06] focus-within:bg-black/[0.06]
|
||||
dark:bg-white/5 dark:hover:bg-white/10 dark:focus-within:bg-white/10
|
||||
">
|
||||
<slot name="search-icon"></slot>
|
||||
<input placeholder="Search" bind:value={keywordMobile}
|
||||
class="pl-10 absolute inset-0 text-sm bg-transparent outline-0
|
||||
focus:w-60 text-black/50 dark:text-white/50"
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- search results -->
|
||||
{#each result as item}
|
||||
<a href={item.url}
|
||||
class="transition first-of-type:mt-2 lg:first-of-type:mt-0 group block
|
||||
rounded-xl text-lg px-3 py-2 hover:bg-[var(--btn-plain-bg-hover)] active:bg-[var(--btn-plain-bg-active)]">
|
||||
<div class="transition text-90 inline-flex font-bold group-hover:text-[var(--primary)]">
|
||||
{item.meta.title}<slot name="arrow-icon"></slot>
|
||||
</div>
|
||||
<div class="transition text-sm text-50">
|
||||
{@html item.excerpt}
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
|
@ -1,57 +0,0 @@
|
|||
---
|
||||
import { Icon } from 'astro-icon/components';
|
||||
---
|
||||
|
||||
<!-- There can't be a filter on parent element, or it will break `fixed` -->
|
||||
<div class="back-to-top-wrapper hidden lg:block">
|
||||
<div id="back-to-top-btn" class="back-to-top-btn hide flex items-center rounded-2xl overflow-hidden transition" onclick="backToTop()">
|
||||
<button aria-label="Back to Top" class="btn-card h-[3.75rem] w-[3.75rem]">
|
||||
<Icon name="material-symbols:keyboard-arrow-up-rounded" class="mx-auto"></Icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="stylus">
|
||||
.back-to-top-wrapper
|
||||
width: 3.75rem
|
||||
height: 3.75rem
|
||||
position: absolute
|
||||
right: 0
|
||||
top: 0
|
||||
|
||||
.back-to-top-btn
|
||||
color: var(--primary)
|
||||
font-size: 2.25rem
|
||||
font-weight: bold
|
||||
border: none
|
||||
position: fixed
|
||||
bottom: 15rem
|
||||
opacity: 1
|
||||
cursor: pointer
|
||||
transform: translateX(5rem)
|
||||
i
|
||||
font-size: 1.75rem
|
||||
&.hide
|
||||
transform: translateX(5rem) scale(0.9)
|
||||
opacity: 0
|
||||
pointer-events: none
|
||||
&:active
|
||||
transform: translateX(5rem) scale(0.9)
|
||||
|
||||
</style>
|
||||
|
||||
<script is:raw>
|
||||
function backToTop() {
|
||||
window.scroll({ top: 0, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
function scrollFunction() {
|
||||
let btn = document.getElementById('back-to-top-btn');
|
||||
if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) {
|
||||
btn.classList.remove('hide')
|
||||
} else {
|
||||
btn.classList.add('hide')
|
||||
}
|
||||
}
|
||||
window.onscroll = scrollFunction
|
||||
</script>
|
|
@ -1,43 +0,0 @@
|
|||
---
|
||||
interface Props {
|
||||
badge?: string
|
||||
url?: string
|
||||
label?: string
|
||||
}
|
||||
const { badge, url, name } = Astro.props
|
||||
---
|
||||
<a href={url} aria-label={name}>
|
||||
<button
|
||||
class:list={`
|
||||
w-full
|
||||
h-10
|
||||
rounded-lg
|
||||
bg-none
|
||||
hover:bg-[var(--btn-plain-bg-hover)]
|
||||
active:bg-[var(--btn-plain-bg-active)]
|
||||
transition-all
|
||||
pl-2
|
||||
hover:pl-3
|
||||
|
||||
text-neutral-700
|
||||
hover:text-[var(--primary)]
|
||||
dark:text-neutral-300
|
||||
dark:hover:text-[var(--primary)]
|
||||
`
|
||||
}
|
||||
>
|
||||
<div class="flex items-center justify-between relative mr-2">
|
||||
<div class="overflow-hidden text-left whitespace-nowrap overflow-ellipsis ">
|
||||
<slot></slot>
|
||||
</div>
|
||||
{ badge !== undefined && badge !== null && badge !== '' &&
|
||||
<div class="transition h-7 ml-4 min-w-[2rem] rounded-lg text-sm font-bold
|
||||
text-[var(--btn-content)] dark:text-[var(--deep-text)]
|
||||
bg-[oklch(0.95_0.025_var(--hue))] dark:bg-[var(--primary)]
|
||||
flex items-center justify-center">
|
||||
{ badge }
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</button>
|
||||
</a>
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
interface Props {
|
||||
size?: string;
|
||||
dot?: boolean;
|
||||
href?: string;
|
||||
label?: string;
|
||||
}
|
||||
const { size, dot, href, label }: Props = Astro.props;
|
||||
---
|
||||
<a href={href} aria-label={label} class="btn-regular h-8 text-sm px-3 rounded-lg">
|
||||
{dot && <div class="h-1 w-1 bg-[var(--btn-content)] dark:bg-[var(--card-bg)] transition rounded-md mr-2"></div>}
|
||||
<slot></slot>
|
||||
</a>
|
|
@ -1,91 +0,0 @@
|
|||
---
|
||||
import type { Page } from "astro";
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import {url} from "../../utils/url-utils";
|
||||
interface Props {
|
||||
page: Page;
|
||||
class?: string;
|
||||
style?: string;
|
||||
}
|
||||
|
||||
const {page, style} = Astro.props;
|
||||
|
||||
const HIDDEN = -1;
|
||||
|
||||
const className = Astro.props.class;
|
||||
|
||||
const ADJ_DIST = 2;
|
||||
const VISIBLE = ADJ_DIST * 2 + 1;
|
||||
|
||||
// for test
|
||||
let count = 1;
|
||||
let l = page.currentPage, r = page.currentPage;
|
||||
while (0 < l - 1 && r + 1 <= page.lastPage && count + 2 <= VISIBLE) {
|
||||
count += 2;
|
||||
l--;
|
||||
r++;
|
||||
}
|
||||
while (0 < l - 1 && count < VISIBLE) {
|
||||
count++;
|
||||
l--;
|
||||
}
|
||||
while (r + 1 <= page.lastPage && count < VISIBLE) {
|
||||
count++;
|
||||
r++;
|
||||
}
|
||||
|
||||
let pages: number[] = [];
|
||||
if (l > 1)
|
||||
pages.push(1);
|
||||
if (l == 3)
|
||||
pages.push(2);
|
||||
if (l > 3)
|
||||
pages.push(HIDDEN);
|
||||
for (let i = l; i <= r; i++)
|
||||
pages.push(i);
|
||||
if (r < page.lastPage - 2)
|
||||
pages.push(HIDDEN);
|
||||
if (r == page.lastPage - 2)
|
||||
pages.push(page.lastPage - 1);
|
||||
if (r < page.lastPage)
|
||||
pages.push(page.lastPage);
|
||||
|
||||
const getPageUrl = (p: number) => {
|
||||
if (p == 1)
|
||||
return '/';
|
||||
return `/${p}/`;
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
<div class:list={[className, "flex flex-row gap-3 justify-center"]} style={style}>
|
||||
<a href={url(page.url.prev)} aria-label={page.url.prev ? "Previous Page" : null}
|
||||
class:list={["btn-card overflow-hidden rounded-lg text-[var(--primary)] w-11 h-11",
|
||||
{"disabled": page.url.prev == undefined}
|
||||
]}
|
||||
>
|
||||
<Icon name="material-symbols:chevron-left-rounded" size="1.75rem"></Icon>
|
||||
</a>
|
||||
<div class="bg-[var(--card-bg)] flex flex-row rounded-lg items-center text-neutral-700 dark:text-neutral-300 font-bold">
|
||||
{pages.map((p) => {
|
||||
if (p == HIDDEN)
|
||||
return <Icon name="material-symbols:more-horiz" class="mx-1"/>;
|
||||
if (p == page.currentPage)
|
||||
return <div class="h-11 w-11 rounded-lg bg-[var(--primary)] flex items-center justify-center
|
||||
font-bold text-white dark:text-black/70"
|
||||
>
|
||||
{p}
|
||||
</div>
|
||||
return <a href={url(getPageUrl(p))} aria-label=`Page ${p}`
|
||||
class="btn-card w-11 h-11 rounded-lg overflow-hidden active:scale-[0.85]"
|
||||
>{p}</a>
|
||||
})}
|
||||
</div>
|
||||
<a href={url(page.url.next)} aria-label={page.url.next ? "Next Page" : null}
|
||||
class:list={["btn-card overflow-hidden rounded-lg text-[var(--primary)] w-11 h-11",
|
||||
{"disabled": page.url.next == undefined}
|
||||
]}
|
||||
>
|
||||
<Icon name="material-symbols:chevron-right-rounded" size="1.75rem"></Icon>
|
||||
</a>
|
||||
</div>
|
|
@ -1,37 +0,0 @@
|
|||
---
|
||||
import path from "path";
|
||||
interface Props {
|
||||
id?: string
|
||||
src: string;
|
||||
class?: string;
|
||||
alt?: string
|
||||
position?: string;
|
||||
basePath?: string
|
||||
}
|
||||
import { Image } from 'astro:assets';
|
||||
import { url } from "../../utils/url-utils";
|
||||
|
||||
const {id, src, alt, position = 'center', basePath = '/'} = Astro.props;
|
||||
const className = Astro.props.class;
|
||||
|
||||
const isLocal = !(src.startsWith('/') || src.startsWith('http') || src.startsWith('https') || src.startsWith('data:'));
|
||||
const isPublic = src.startsWith('/');
|
||||
|
||||
// TODO temporary workaround for images dynamic import
|
||||
// https://github.com/withastro/astro/issues/3373
|
||||
let img;
|
||||
if (isLocal) {
|
||||
const files = import.meta.glob<ImageMetadata>("../../**", { import: 'default' });
|
||||
let normalizedPath = path.normalize(path.join("../../", basePath, src)).replace(/\\/g, "/");
|
||||
img = await (files[normalizedPath])();
|
||||
}
|
||||
|
||||
const imageClass = 'w-full h-full object-cover';
|
||||
const imageStyle = `object-position: ${position}`
|
||||
---
|
||||
<div class:list={[className, 'overflow-hidden relative']}>
|
||||
<div class="transition absolute inset-0 dark:bg-black/10 bg-opacity-50 pointer-events-none"></div>
|
||||
{isLocal && <Image src={img} alt={alt || ""} class={imageClass} style={imageStyle}/>}
|
||||
{!isLocal && <img src={isPublic ? url(src) : src} alt={alt || ""} class={imageClass} style={imageStyle}/>}
|
||||
</div>
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
---
|
||||
import {formatDateToYYYYMMDD} from "../../utils/date-utils";
|
||||
import { Icon } from 'astro-icon/components';
|
||||
import {licenseConfig, profileConfig} from "../../config";
|
||||
import {i18n} from "../../i18n/translation";
|
||||
import I18nKey from "../../i18n/i18nKey";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
slug: string;
|
||||
pubDate: Date;
|
||||
class: string;
|
||||
}
|
||||
|
||||
const { title, slug, pubDate } = Astro.props;
|
||||
const className = Astro.props.class;
|
||||
const profileConf = profileConfig;
|
||||
const licenseConf = licenseConfig;
|
||||
const postUrl = decodeURIComponent(Astro.url.toString());
|
||||
|
||||
---
|
||||
<div class=`relative transition overflow-hidden bg-[var(--license-block-bg)] py-5 px-6 ${className}`>
|
||||
<div class="transition font-bold text-black/75 dark:text-white/75">
|
||||
{title}
|
||||
</div>
|
||||
<a href={postUrl} class="link text-[var(--primary)]">
|
||||
{postUrl}
|
||||
</a>
|
||||
<div class="flex gap-6 mt-2">
|
||||
<div>
|
||||
<div class="transition text-black/30 dark:text-white/30 text-sm">{i18n(I18nKey.author)}</div>
|
||||
<div class="transition text-black/75 dark:text-white/75 whitespace-nowrap">{profileConf.name}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="transition text-black/30 dark:text-white/30 text-sm">{i18n(I18nKey.publishedAt)}</div>
|
||||
<div class="transition text-black/75 dark:text-white/75 whitespace-nowrap">{formatDateToYYYYMMDD(pubDate)}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="transition text-black/30 dark:text-white/30 text-sm">{i18n(I18nKey.license)}</div>
|
||||
<a href={licenseConf.url} target="_blank" class="link text-[var(--primary)] whitespace-nowrap">{licenseConf.name}</a>
|
||||
</div>
|
||||
</div>
|
||||
<Icon name="fa6-brands:creative-commons" class="transition absolute pointer-events-none right-6 top-1/2 -translate-y-1/2 text-black/5 dark:text-white/5" size="240"></Icon>
|
||||
</div>
|
|
@ -1,491 +0,0 @@
|
|||
---
|
||||
import '@fontsource-variable/jetbrains-mono';
|
||||
import '@fontsource-variable/jetbrains-mono/wght-italic.css';
|
||||
|
||||
interface Props {
|
||||
class: string;
|
||||
}
|
||||
const className = Astro.props.class;
|
||||
---
|
||||
<div data-pagefind-body class=`prose dark:prose-invert prose-base max-w-none custom-md ${className}`>
|
||||
<!--<div class="prose dark:prose-invert max-w-none custom-md">-->
|
||||
<!--<div class="max-w-none custom-md">-->
|
||||
<slot/>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const observer = new MutationObserver(addPreCopyButton);
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
document.addEventListener("DOMContentLoaded", addPreCopyButton);
|
||||
|
||||
function addPreCopyButton() {
|
||||
observer.disconnect();
|
||||
|
||||
let codeBlocks = Array.from(document.querySelectorAll("pre"));
|
||||
|
||||
for (let codeBlock of codeBlocks) {
|
||||
if (codeBlock.parentElement?.nodeName === "DIV" && codeBlock.parentElement?.classList.contains("code-block")) continue
|
||||
|
||||
let wrapper = document.createElement("div");
|
||||
wrapper.className = "relative code-block";
|
||||
|
||||
let copyButton = document.createElement("button");
|
||||
copyButton.className = "copy-btn btn-regular-dark absolute active:scale-90 h-8 w-8 top-2 right-2 opacity-75 text-sm p-1.5 rounded-lg transition-all ease-in-out";
|
||||
|
||||
codeBlock.setAttribute("tabindex", "0");
|
||||
if (codeBlock.parentNode) {
|
||||
codeBlock.parentNode.insertBefore(wrapper, codeBlock);
|
||||
}
|
||||
|
||||
let copyIcon = `<svg class="copy-btn-icon copy-icon" xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px"><path d="M368.37-237.37q-34.48 0-58.74-24.26-24.26-24.26-24.26-58.74v-474.26q0-34.48 24.26-58.74 24.26-24.26 58.74-24.26h378.26q34.48 0 58.74 24.26 24.26 24.26 24.26 58.74v474.26q0 34.48-24.26 58.74-24.26 24.26-58.74 24.26H368.37Zm0-83h378.26v-474.26H368.37v474.26Zm-155 238q-34.48 0-58.74-24.26-24.26-24.26-24.26-58.74v-515.76q0-17.45 11.96-29.48 11.97-12.02 29.33-12.02t29.54 12.02q12.17 12.03 12.17 29.48v515.76h419.76q17.45 0 29.48 11.96 12.02 11.97 12.02 29.33t-12.02 29.54q-12.03 12.17-29.48 12.17H213.37Zm155-238v-474.26 474.26Z"/></svg>`
|
||||
let successIcon = `<svg class="copy-btn-icon success-icon" xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px"><path d="m389-377.13 294.7-294.7q12.58-12.67 29.52-12.67 16.93 0 29.61 12.67 12.67 12.68 12.67 29.53 0 16.86-12.28 29.14L419.07-288.41q-12.59 12.67-29.52 12.67-16.94 0-29.62-12.67L217.41-430.93q-12.67-12.68-12.79-29.45-.12-16.77 12.55-29.45 12.68-12.67 29.62-12.67 16.93 0 29.28 12.67L389-377.13Z"/></svg>`
|
||||
copyButton.innerHTML = `<div>${copyIcon} ${successIcon}</div>
|
||||
`
|
||||
|
||||
wrapper.appendChild(codeBlock);
|
||||
wrapper.appendChild(copyButton);
|
||||
|
||||
let timeout;
|
||||
copyButton.addEventListener("click", async () => {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
let text = codeBlock?.querySelector("code")?.innerText;
|
||||
await navigator.clipboard.writeText(text);
|
||||
copyButton.classList.add("success");
|
||||
timeout = setTimeout(() => {
|
||||
copyButton.classList.remove("success");
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Styles for copy-code-button -->
|
||||
<style lang="css" is:global>
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer components {
|
||||
.btn-regular-dark {
|
||||
@apply flex items-center justify-center
|
||||
bg-[oklch(0.45_0.01_var(--hue))] hover:bg-[oklch(0.50_0.01_var(--hue))] active:bg-[oklch(0.55_0.01_var(--hue))]
|
||||
dark:bg-[oklch(0.30_0.02_var(--hue))] dark:hover:bg-[oklch(0.35_0.03_var(--hue))] dark:active:bg-[oklch(0.40_0.03_var(--hue))]
|
||||
}
|
||||
.btn-regular-dark.success {
|
||||
@apply bg-[oklch(0.75_0.14_var(--hue))] dark:bg-[oklch(0.75_0.14_var(--hue))]
|
||||
}
|
||||
|
||||
.copy-btn-icon {
|
||||
@apply absolute top-1/2 left-1/2 transition -translate-x-1/2 -translate-y-1/2
|
||||
}
|
||||
.copy-btn .copy-icon {
|
||||
@apply opacity-100 fill-white dark:fill-white/75
|
||||
}
|
||||
.copy-btn.success .copy-icon {
|
||||
@apply opacity-0 fill-[var(--deep-text)]
|
||||
}
|
||||
.copy-btn .success-icon {
|
||||
@apply opacity-0
|
||||
}
|
||||
.copy-btn.success .success-icon {
|
||||
@apply opacity-100
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="stylus" is:global>
|
||||
.custom-md
|
||||
h1, h2, h3, h4, h5, h6
|
||||
.anchor
|
||||
margin: -0.125rem !important
|
||||
margin-left: 0.2ch !important
|
||||
padding: 0.125rem !important
|
||||
user-select: none !important
|
||||
opacity: 0 !important
|
||||
text-decoration: none !important
|
||||
transition: opacity 0.15s ease-in-out, background 0.15s ease-in-out !important
|
||||
|
||||
.anchor-icon
|
||||
margin-left: 0.45ch !important
|
||||
margin-right: 0.45ch !important
|
||||
|
||||
&:hover
|
||||
.anchor
|
||||
opacity: 1 !important
|
||||
|
||||
a:not(.no-styling)
|
||||
position: relative
|
||||
background: none
|
||||
margin: -0.25rem
|
||||
padding: 0.25rem
|
||||
border-radius: 0.375rem
|
||||
font-weight: 500
|
||||
color: var(--primary)
|
||||
text-decoration-line: underline
|
||||
text-decoration-color: var(--link-underline)
|
||||
text-decoration-thickness: 0.125rem
|
||||
text-decoration-style: dashed
|
||||
text-underline-offset: 0.25rem
|
||||
/*&:after*/
|
||||
/* content: ''*/
|
||||
/* position: absolute*/
|
||||
/* left: 2px*/
|
||||
/* right: 2px*/
|
||||
/* bottom: 4px*/
|
||||
/* height: 6px*/
|
||||
/* border-radius: 3px*/
|
||||
/* background: var(--link-hover)*/
|
||||
/* transition: background 0.15s ease-in-out;*/
|
||||
/* z-index: -1;*/
|
||||
|
||||
&:hover
|
||||
background: var(--link-hover)
|
||||
text-decoration-color: var(--link-hover)
|
||||
|
||||
&:active
|
||||
background: var(--link-active)
|
||||
text-decoration-color: var(--link-active)
|
||||
|
||||
code
|
||||
font-family: 'JetBrains Mono Variable', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace
|
||||
background: var(--inline-code-bg)
|
||||
color: var(--inline-code-color)
|
||||
padding: 0.125rem 0.25rem
|
||||
border-radius: 0.25rem
|
||||
overflow: hidden
|
||||
counter-reset: line
|
||||
|
||||
&:before
|
||||
content: none
|
||||
|
||||
&:after
|
||||
content: none
|
||||
|
||||
span.line
|
||||
&:before
|
||||
content: counter(line)
|
||||
counter-increment: line
|
||||
direction: rtl
|
||||
display: inline-block
|
||||
margin-right: 1rem
|
||||
width: 1rem
|
||||
color: rgba(255, 255, 255, 0.25)
|
||||
&:last-child:empty, &:last-child:has(> span:empty:only-child)
|
||||
display: none
|
||||
|
||||
pre
|
||||
background: var(--codeblock-bg) !important
|
||||
border-radius: 0.75rem
|
||||
padding-left: 1.25rem
|
||||
padding-right: 1.25rem
|
||||
|
||||
code
|
||||
color: unset
|
||||
font-size: 0.875rem
|
||||
padding: 0
|
||||
background: none
|
||||
|
||||
::selection
|
||||
background: var(--codeblock-selection)
|
||||
|
||||
span.br::selection
|
||||
background: var(--codeblock-selection)
|
||||
|
||||
ul
|
||||
li
|
||||
&::marker
|
||||
color: var(--primary)
|
||||
|
||||
ol
|
||||
li
|
||||
&::marker
|
||||
color: var(--primary)
|
||||
|
||||
blockquote
|
||||
font-style: normal
|
||||
font-weight: inherit
|
||||
border-left-color: rgba(0, 0, 0, 0)
|
||||
position: relative;
|
||||
|
||||
&:before
|
||||
content: ''
|
||||
position: absolute
|
||||
left: -0.25rem
|
||||
display: block
|
||||
transition: background 0.15s ease-in-out;
|
||||
background: var(--btn-regular-bg)
|
||||
height: 100%
|
||||
width: 0.25rem
|
||||
border-radius: 1rem
|
||||
|
||||
p
|
||||
&:before
|
||||
content: none
|
||||
|
||||
&:after
|
||||
content: none
|
||||
|
||||
blockquote.admonition
|
||||
.bdm-title
|
||||
display: flex
|
||||
align-items: center
|
||||
margin-bottom: -.9rem
|
||||
font-weight: bold
|
||||
|
||||
&:before
|
||||
content: ' '
|
||||
display: inline-block
|
||||
font-size: inherit
|
||||
overflow: visible
|
||||
margin-right: .6rem
|
||||
height: 1em
|
||||
width: 1em
|
||||
vertical-align: -.126em
|
||||
mask-size: contain
|
||||
mask-position: center
|
||||
mask-repeat: no-repeat
|
||||
transform: translateY(-0.0625rem)
|
||||
&.bdm-tip
|
||||
.bdm-title
|
||||
color: var(--admonitions-color-tip)
|
||||
|
||||
&:before
|
||||
background: var(--admonitions-color-tip)
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' width='16' height='16' aria-hidden='true'%3E%3Cpath d='M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z'%3E%3C/path%3E%3C/svg%3E")
|
||||
|
||||
&:before
|
||||
background: var(--admonitions-color-tip)
|
||||
&.bdm-note
|
||||
.bdm-title
|
||||
color: var(--admonitions-color-note)
|
||||
|
||||
&:before
|
||||
background: var(--admonitions-color-note)
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' width='16' height='16' aria-hidden='true'%3E%3Cpath fill='var(--admonitions-color-tip)' d='M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z'%3E%3C/path%3E%3C/svg%3E")
|
||||
|
||||
&:before
|
||||
background: var(--admonitions-color-note)
|
||||
&.bdm-important
|
||||
.bdm-title
|
||||
color: var(--admonitions-color-important)
|
||||
|
||||
&:before
|
||||
background: var(--admonitions-color-important)
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' width='16' height='16' aria-hidden='true'%3E%3Cpath d='M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z'%3E%3C/path%3E%3C/svg%3E")
|
||||
|
||||
&:before
|
||||
background: var(--admonitions-color-important)
|
||||
&.bdm-warning
|
||||
.bdm-title
|
||||
color: var(--admonitions-color-warning)
|
||||
|
||||
&:before
|
||||
background: var(--admonitions-color-warning)
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' width='16' height='16' aria-hidden='true'%3E%3Cpath d='M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z'%3E%3C/path%3E%3C/svg%3E")
|
||||
|
||||
&:before
|
||||
background: var(--admonitions-color-warning)
|
||||
&.bdm-caution
|
||||
.bdm-title
|
||||
color: var(--admonitions-color-caution)
|
||||
|
||||
&:before
|
||||
background: var(--admonitions-color-caution)
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' width='16' height='16' aria-hidden='true'%3E%3Cpath d='M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z'%3E%3C/path%3E%3C/svg%3E")
|
||||
|
||||
&:before
|
||||
background: var(--admonitions-color-caution)
|
||||
|
||||
img
|
||||
border-radius: 0.75rem
|
||||
|
||||
hr
|
||||
border-color: var(--line-divider)
|
||||
border-style: dashed
|
||||
|
||||
iframe
|
||||
border-radius: 0.75rem
|
||||
margin-left: auto
|
||||
margin-right: auto
|
||||
max-width: 100%
|
||||
|
||||
a.card-github
|
||||
display: block
|
||||
background: var(--license-block-bg)
|
||||
position: relative
|
||||
margin: 0.5rem 0
|
||||
padding: 1.1rem 1.5rem 1.1rem 1.5rem
|
||||
color: var(--tw-prose-body)
|
||||
border-radius: var(--radius-large)
|
||||
text-decoration-thickness: 0px
|
||||
text-decoration-line: none
|
||||
|
||||
&:hover
|
||||
background-color: var(--btn-regular-bg-hover)
|
||||
|
||||
.gc-titlebar
|
||||
color: var(--btn-content)
|
||||
|
||||
.gc-stars, .gc-forks, .gc-license, .gc-description
|
||||
color: var(--tw-prose-headings)
|
||||
|
||||
&:before
|
||||
background-color: var(--tw-prose-headings)
|
||||
|
||||
&:active
|
||||
scale: .98
|
||||
background-color: var(--btn-regular-bg-active);
|
||||
|
||||
.gc-titlebar
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: space-between
|
||||
margin-bottom: 0.5rem
|
||||
color: var(--tw-prose-headings)
|
||||
font-size: 1.25rem
|
||||
font-weight: 500
|
||||
|
||||
.gc-titlebar-left
|
||||
display: flex
|
||||
flex-flow: row nowrap
|
||||
gap: 0.5rem
|
||||
|
||||
.gc-repo
|
||||
font-weight: bold
|
||||
|
||||
.gc-owner
|
||||
font-weight: 300
|
||||
position: relative
|
||||
display: flex
|
||||
flex-flow: row nowrap
|
||||
gap: 0.5rem
|
||||
align-items: center
|
||||
|
||||
.gc-avatar
|
||||
display: block
|
||||
overflow: hidden
|
||||
width: 1.5rem
|
||||
height: 1.5rem
|
||||
margin-top: -0.1rem
|
||||
background-color: var(--primary)
|
||||
background-size: cover
|
||||
border-radius: 50%
|
||||
|
||||
.gc-description
|
||||
margin-bottom: 0.7rem
|
||||
font-size: 1rem
|
||||
font-weight: 300
|
||||
line-height: 1.5rem
|
||||
color: var(--tw-prose-body)
|
||||
|
||||
.gc-infobar
|
||||
display: flex
|
||||
flex-flow: row nowrap
|
||||
gap: 1.5rem
|
||||
color: var(--tw-prose-body)
|
||||
width: fit-content
|
||||
|
||||
.gc-language
|
||||
display: none
|
||||
|
||||
.gc-stars, .gc-forks, .gc-license, .github-logo
|
||||
font-weight: 500
|
||||
font-size: 0.875rem
|
||||
opacity: 0.9;
|
||||
|
||||
&:before
|
||||
content: ' '
|
||||
display: inline-block
|
||||
height: 1.3em
|
||||
width: 1.3em
|
||||
margin-right: .4rem
|
||||
vertical-align: -.24em
|
||||
font-size: inherit
|
||||
background-color: var(--tw-prose-body)
|
||||
overflow: visible
|
||||
mask-size: contain
|
||||
mask-position: center
|
||||
mask-repeat: no-repeat
|
||||
transition-property: background-color, background;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1)
|
||||
transition-duration: 0.15s
|
||||
|
||||
.gc-stars
|
||||
&:before
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' height='16' viewBox='0 0 16 16' version='1.1' width='16'%3E%3Cpath d='M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z'%3E%3C/path%3E%3C/svg%3E")
|
||||
|
||||
.gc-license
|
||||
&:before
|
||||
margin-right: .5rem
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' height='16' viewBox='0 0 16 16' version='1.1' width='16'%3E%3Cpath d='M8.75.75V2h.985c.304 0 .603.08.867.231l1.29.736c.038.022.08.033.124.033h2.234a.75.75 0 0 1 0 1.5h-.427l2.111 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.006.005-.01.01-.045.04c-.21.176-.441.327-.686.45C14.556 10.78 13.88 11 13 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L12.178 4.5h-.162c-.305 0-.604-.079-.868-.231l-1.29-.736a.245.245 0 0 0-.124-.033H8.75V13h2.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5h2.5V3.5h-.984a.245.245 0 0 0-.124.033l-1.289.737c-.265.15-.564.23-.869.23h-.162l2.112 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.016.015-.045.04c-.21.176-.441.327-.686.45C4.556 10.78 3.88 11 3 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L2.178 4.5H1.75a.75.75 0 0 1 0-1.5h2.234a.249.249 0 0 0 .125-.033l1.288-.737c.265-.15.564-.23.869-.23h.984V.75a.75.75 0 0 1 1.5 0Zm2.945 8.477c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L13 6.327Zm-10 0c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L3 6.327Z'%3E%3C/path%3E%3C/svg%3E")
|
||||
|
||||
.gc-forks
|
||||
&:before
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' height='16' viewBox='0 0 16 16' version='1.1' width='16'%3E%3Cpath d='M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z'%3E%3C/path%3E%3C/svg%3E")
|
||||
|
||||
.github-logo
|
||||
font-size: 1.25rem
|
||||
|
||||
&:before
|
||||
background-color: var(--tw-prose-headings)
|
||||
margin-right: 0
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='31' height='32' viewBox='0 0 496 512'%3E%3Cpath fill='%23a1f7cb' d='M165.9 397.4c0 2-2.3 3.6-5.2 3.6c-3.3.3-5.6-1.3-5.6-3.6c0-2 2.3-3.6 5.2-3.6c3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9c2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9c.3 2 2.9 3.3 5.9 2.6c2.9-.7 4.9-2.6 4.6-4.6c-.3-1.9-3-3.2-5.9-2.9M244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2c12.8 2.3 17.3-5.6 17.3-12.1c0-6.2-.3-40.4-.3-61.4c0 0-70 15-84.7-29.8c0 0-11.4-29.1-27.8-36.6c0 0-22.9-15.7 1.6-15.4c0 0 24.9 2 38.6 25.8c21.9 38.6 58.6 27.5 72.9 20.9c2.3-16 8.8-27.1 16-33.7c-55.9-6.2-112.3-14.3-112.3-110.5c0-27.5 7.6-41.3 23.6-58.9c-2.6-6.5-11.1-33.3 2.6-67.9c20.9-6.5 69 27 69 27c20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27c13.7 34.7 5.2 61.4 2.6 67.9c16 17.7 25.8 31.5 25.8 58.9c0 96.5-58.9 104.2-114.8 110.5c9.2 7.9 17 22.9 17 46.4c0 33.7-.3 75.4-.3 83.6c0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252C496 113.3 383.5 8 244.8 8M97.2 352.9c-1.3 1-1 3.3.7 5.2c1.6 1.6 3.9 2.3 5.2 1c1.3-1 1-3.3-.7-5.2c-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9c1.6 1 3.6.7 4.3-.7c.7-1.3-.3-2.9-2.3-3.9c-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2c2.3 2.3 5.2 2.6 6.5 1c1.3-1.3.7-4.3-1.3-6.2c-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9c1.6 2.3 4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2c-1.4-2.3-4-3.3-5.6-2'/%3E%3C/svg%3E")
|
||||
|
||||
a.card-github.fetch-waiting
|
||||
pointer-events: none
|
||||
opacity: 0.7
|
||||
transition: opacity 0.15s ease-in-out
|
||||
|
||||
.gc-description, .gc-infobar
|
||||
background-color: var(--tw-prose-body)
|
||||
color: transparent
|
||||
opacity: 0.5;
|
||||
border-radius: 0.5rem
|
||||
animation: pulsate 2s infinite linear
|
||||
user-select: none
|
||||
|
||||
&:before
|
||||
background-color: transparent
|
||||
|
||||
.gc-avatar
|
||||
display: none
|
||||
|
||||
.gc-repo
|
||||
margin-left: -0.1rem
|
||||
|
||||
a.card-github.fetch-error
|
||||
pointer-events: all
|
||||
opacity: 1
|
||||
|
||||
@keyframes pulsate
|
||||
0%
|
||||
opacity: 0.15
|
||||
50%
|
||||
opacity: 0.25
|
||||
100%
|
||||
opacity: 0.15
|
||||
|
||||
.card-github, .gc-description, .gc-titlebar, .gc-stars, .gc-forks, .gc-license, .gc-avatar, github-logo
|
||||
transition-property: all
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1)
|
||||
transition-duration: 0.15s
|
||||
|
||||
</style>
|
||||
|
||||
<style lang="css" is:global>
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer components {
|
||||
.custom-md h1 {
|
||||
@apply text-3xl
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1,38 +0,0 @@
|
|||
---
|
||||
import WidgetLayout from "./WidgetLayout.astro";
|
||||
|
||||
import {i18n} from "../../i18n/translation";
|
||||
import I18nKey from "../../i18n/i18nKey";
|
||||
import {Category, getCategoryList} from "../../utils/content-utils";
|
||||
import {getCategoryUrl} from "../../utils/url-utils";
|
||||
import ButtonLink from "../control/ButtonLink.astro";
|
||||
|
||||
const categories = await getCategoryList();
|
||||
|
||||
const COLLAPSED_HEIGHT = "7.5rem";
|
||||
const COLLAPSE_THRESHOLD = 5;
|
||||
|
||||
const isCollapsed = categories.length >= COLLAPSE_THRESHOLD;
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
style?: string;
|
||||
}
|
||||
const className = Astro.props.class
|
||||
const style = Astro.props.style
|
||||
|
||||
---
|
||||
|
||||
<WidgetLayout name={i18n(I18nKey.categories)} id="categories" isCollapsed={isCollapsed} collapsedHeight={COLLAPSED_HEIGHT}
|
||||
class={className} style={style}
|
||||
>
|
||||
{categories.map((c) =>
|
||||
<ButtonLink
|
||||
url={getCategoryUrl(c.name)}
|
||||
badge={c.count}
|
||||
label=`View all posts in the ${c.name} category`
|
||||
>
|
||||
{c.name}
|
||||
</ButtonLink>
|
||||
)}
|
||||
</WidgetLayout>
|
|
@ -1,91 +0,0 @@
|
|||
<script lang="ts">
|
||||
import {i18n} from '@i18n/translation';
|
||||
import I18nKey from '@i18n/i18nKey';
|
||||
import {getDefaultHue, getHue, setHue} from '@utils/setting-utils';
|
||||
|
||||
let hue = getHue()
|
||||
const defaultHue = getDefaultHue()
|
||||
|
||||
function resetHue() {
|
||||
hue = getDefaultHue()
|
||||
}
|
||||
|
||||
$: if (hue || hue === 0) {
|
||||
setHue(hue)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="display-setting" class="float-panel float-panel-closed absolute transition-all w-80 right-4 px-4 py-4">
|
||||
<div class="flex flex-row gap-2 mb-3 items-center justify-between">
|
||||
<div class="flex gap-2 font-bold text-lg text-neutral-900 dark:text-neutral-100 transition relative ml-3
|
||||
before:w-1 before:h-4 before:rounded-md before:bg-[var(--primary)]
|
||||
before:absolute before:-left-3 before:top-[0.33rem]"
|
||||
>
|
||||
{i18n(I18nKey.themeColor)}
|
||||
<button aria-label="Reset to Default" class="btn-regular w-7 h-7 rounded-md active:scale-90"
|
||||
class:opacity-0={hue === defaultHue} class:pointer-events-none={hue === defaultHue} on:click={resetHue}>
|
||||
<div class="text-[var(--btn-content)]">
|
||||
<slot name="restore-icon"></slot>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex gap-1">
|
||||
<div id="hueValue" class="transition bg-[var(--btn-regular-bg)] w-10 h-7 rounded-md flex justify-center
|
||||
font-bold text-sm items-center text-[var(--btn-content)]">
|
||||
{hue}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full h-6 px-1 bg-[oklch(0.80_0.10_0)] dark:bg-[oklch(0.70_0.10_0)] rounded select-none">
|
||||
<input aria-label={i18n(I18nKey.themeColor)} type="range" min="0" max="360" bind:value={hue}
|
||||
class="slider" id="colorSlider" step="5" style="width: 100%;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<style lang="stylus">
|
||||
#display-setting
|
||||
input[type="range"]
|
||||
-webkit-appearance: none;
|
||||
height: 1.5rem;
|
||||
background-image: var(--color-selection-bar)
|
||||
transition: background-image 0.15s ease-in-out
|
||||
|
||||
/* Input Thumb */
|
||||
::-webkit-slider-thumb
|
||||
-webkit-appearance: none;
|
||||
height: 1rem;
|
||||
width: 0.5rem;
|
||||
border-radius: 0.125rem;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
box-shadow: none;
|
||||
&:hover
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
&:active
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
|
||||
::-moz-range-thumb
|
||||
-webkit-appearance: none;
|
||||
height: 1rem;
|
||||
width: 0.5rem;
|
||||
border-radius: 0.125rem;
|
||||
border-width: 0
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
box-shadow: none;
|
||||
&:hover
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
&:active
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
|
||||
&::-ms-thumb
|
||||
-webkit-appearance: none;
|
||||
height: 1rem;
|
||||
width: 0.5rem;
|
||||
border-radius: 0.125rem;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
box-shadow: none;
|
||||
&:hover
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
&:active
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
</style>
|
|
@ -1,32 +0,0 @@
|
|||
---
|
||||
import {NavBarLink} from "../../types/config";
|
||||
import {Icon} from "astro-icon/components";
|
||||
import {url} from "../../utils/url-utils";
|
||||
|
||||
interface Props {
|
||||
links: NavBarLink[],
|
||||
}
|
||||
|
||||
const links = Astro.props.links;
|
||||
---
|
||||
<div id="nav-menu-panel" class:list={["float-panel float-panel-closed absolute transition-all fixed right-4 px-2 py-2"]}>
|
||||
{links.map((link) => (
|
||||
<a href={link.external ? link.url : url(link.url)} class="group flex justify-between items-center py-2 pl-3 pr-1 rounded-lg gap-8
|
||||
hover:bg-[var(--btn-plain-bg-hover)] active:bg-[var(--btn-plain-bg-active)] transition
|
||||
"
|
||||
target={link.external ? "_blank" : null}
|
||||
>
|
||||
<div class="transition text-black/75 dark:text-white/75 font-bold group-hover:text-[var(--primary)] group-active:text-[var(--primary)]">
|
||||
{link.name}
|
||||
</div>
|
||||
{!link.external && <Icon name="material-symbols:chevron-right-rounded"
|
||||
class="transition text-[var(--primary)]" size="20"
|
||||
>
|
||||
</Icon>}
|
||||
{link.external && <Icon name="fa6-solid:arrow-up-right-from-square"
|
||||
class="transition text-black/25 dark:text-white/25 -translate-x-1" size="12"
|
||||
>
|
||||
</Icon>}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
|
@ -1,39 +0,0 @@
|
|||
---
|
||||
import ImageWrapper from "../misc/ImageWrapper.astro";
|
||||
import {Icon} from "astro-icon/components";
|
||||
import {profileConfig} from "../../config";
|
||||
import {url} from "../../utils/url-utils";
|
||||
|
||||
const config = profileConfig;
|
||||
---
|
||||
<div class="card-base p-3">
|
||||
<a aria-label="Go to About Page" href={url('/about/')}
|
||||
class="group block relative mx-auto mt-1 lg:mx-0 lg:mt-0 mb-3
|
||||
max-w-[240px] lg:max-w-none overflow-hidden rounded-xl active:scale-95">
|
||||
<div class="absolute transition pointer-events-none group-hover:bg-black/30 group-active:bg-black/50
|
||||
w-full h-full z-50 flex items-center justify-center">
|
||||
<Icon name="fa6-regular:address-card"
|
||||
class="transition opacity-0 scale-90 group-hover:scale-100 group-hover:opacity-100 text-white text-5xl">
|
||||
</Icon>
|
||||
</div>
|
||||
<ImageWrapper src={config.avatar} alt="Profile Image of the Author" class="mx-auto lg:w-full h-full lg:mt-0 "></ImageWrapper>
|
||||
</a>
|
||||
<div class="px-2">
|
||||
<div class="font-bold text-xl text-center mb-1 dark:text-neutral-50 transition">{config.name}</div>
|
||||
<div class="h-1 w-5 bg-[var(--primary)] mx-auto rounded-full mb-2 transition"></div>
|
||||
<div class="text-center text-neutral-400 mb-2.5 transition">{config.bio}</div>
|
||||
<div class="flex gap-2 justify-center mb-1">
|
||||
{config.links.length > 1 && config.links.map(item =>
|
||||
<a rel="me" aria-label={item.name} href={item.url} target="_blank" class="btn-regular rounded-lg h-10 w-10 active:scale-90">
|
||||
<Icon name={item.icon} size="1.5rem"></Icon>
|
||||
</a>
|
||||
)}
|
||||
{config.links.length == 1 && <a rel="me" aria-label={config.links[0].name} href={config.links[0].url} target="_blank"
|
||||
class="btn-regular rounded-lg h-10 gap-2 px-3 font-bold active:scale-95">
|
||||
<Icon name={config.links[0].icon} size="1.5rem"></Icon>
|
||||
{config.links[0].name}
|
||||
</a>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
---
|
||||
import Profile from "./Profile.astro";
|
||||
import Tag from "./Tags.astro";
|
||||
import Categories from "./Categories.astro";
|
||||
|
||||
const className = Astro.props.class;
|
||||
---
|
||||
<div id="sidebar" class:list={[className, "w-full"]}>
|
||||
<div class="flex flex-col w-full gap-4 mb-4">
|
||||
<Profile></Profile>
|
||||
</div>
|
||||
<div class="flex flex-col w-full gap-4 top-4 sticky top-4">
|
||||
<Categories class="onload-animation" style="animation-delay: 150ms"></Categories>
|
||||
<Tag class="onload-animation" style="animation-delay: 200ms"></Tag>
|
||||
</div>
|
||||
</div>
|
|
@ -1,261 +0,0 @@
|
|||
---
|
||||
import type { MarkdownHeading } from 'astro';
|
||||
import { siteConfig } from "../../config";
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
headings: MarkdownHeading[]
|
||||
}
|
||||
|
||||
let { headings = [] } = Astro.props;
|
||||
|
||||
let minDepth = 10;
|
||||
for (const heading of headings) {
|
||||
minDepth = Math.min(minDepth, heading.depth);
|
||||
}
|
||||
|
||||
const className = Astro.props.class
|
||||
|
||||
const removeTailingHash = (text: string) => {
|
||||
let lastIndexOfHash = text.lastIndexOf('#');
|
||||
if (lastIndexOfHash != text.length - 1) {
|
||||
return text;
|
||||
}
|
||||
|
||||
return text.substring(0, lastIndexOfHash);
|
||||
}
|
||||
|
||||
let heading1Count = 1;
|
||||
|
||||
const maxLevel = siteConfig.toc.depth;
|
||||
---
|
||||
<table-of-contents class:list={[className, "group"]}>
|
||||
{headings.filter((heading) => heading.depth < minDepth + maxLevel).map((heading) =>
|
||||
<a href={`#${heading.slug}`} class="px-2 flex gap-2 relative transition w-full min-h-9 rounded-xl
|
||||
hover:bg-[var(--toc-btn-hover)] active:bg-[var(--toc-btn-active)] py-2
|
||||
">
|
||||
<div class:list={["transition w-5 h-5 shrink-0 rounded-lg text-xs flex items-center justify-center font-bold",
|
||||
{
|
||||
"bg-[var(--toc-badge-bg)] text-[var(--btn-content)]": heading.depth == minDepth,
|
||||
"ml-4": heading.depth == minDepth + 1,
|
||||
"ml-8": heading.depth == minDepth + 2,
|
||||
}
|
||||
]}
|
||||
>
|
||||
{heading.depth == minDepth && heading1Count++}
|
||||
{heading.depth == minDepth + 1 && <div class="transition w-2 h-2 rounded-[0.1875rem] bg-[var(--toc-badge-bg)]"></div>}
|
||||
{heading.depth == minDepth + 2 && <div class="transition w-1.5 h-1.5 rounded-sm bg-black/5 dark:bg-white/10"></div>}
|
||||
</div>
|
||||
<div class:list={["transition text-sm", {
|
||||
"text-50": heading.depth == minDepth || heading.depth == minDepth + 1,
|
||||
"text-30": heading.depth == minDepth + 2,
|
||||
}]}>{removeTailingHash(heading.text)}</div>
|
||||
</a>
|
||||
)}
|
||||
<div id="active-indicator" class:list={[{'hidden': headings.length == 0}, "-z-10 absolute bg-[var(--toc-btn-hover)] left-0 right-0 rounded-xl transition-all " +
|
||||
"group-hover:bg-transparent border-2 border-[var(--toc-btn-hover)] group-hover:border-[var(--toc-btn-active)] border-dashed"]}></div>
|
||||
</table-of-contents>
|
||||
|
||||
|
||||
<script>
|
||||
class TableOfContents extends HTMLElement {
|
||||
tocEl: HTMLElement | null = null;
|
||||
visibleClass = "visible";
|
||||
observer: IntersectionObserver;
|
||||
anchorNavTarget: HTMLElement | null = null;
|
||||
headingIdxMap = new Map<string, number>();
|
||||
headings: HTMLElement[] = [];
|
||||
sections: HTMLElement[] = [];
|
||||
tocEntries: HTMLAnchorElement[] = [];
|
||||
active: boolean[] = [];
|
||||
activeIndicator: HTMLElement | null = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.observer = new IntersectionObserver(
|
||||
this.markVisibleSection, { threshold: 0 }
|
||||
);
|
||||
};
|
||||
|
||||
markVisibleSection = (entries: IntersectionObserverEntry[]) => {
|
||||
entries.forEach((entry) => {
|
||||
const id = entry.target.children[0]?.getAttribute("id");
|
||||
const idx = id ? this.headingIdxMap.get(id) : undefined;
|
||||
if (idx != undefined)
|
||||
this.active[idx] = entry.isIntersecting;
|
||||
|
||||
if (entry.isIntersecting && this.anchorNavTarget == entry.target.firstChild)
|
||||
this.anchorNavTarget = null;
|
||||
});
|
||||
|
||||
if (!this.active.includes(true))
|
||||
this.fallback();
|
||||
this.update();
|
||||
};
|
||||
|
||||
toggleActiveHeading = () => {
|
||||
let i = this.active.length - 1;
|
||||
let min = this.active.length - 1, max = 0;
|
||||
while (i >= 0 && !this.active[i]) {
|
||||
this.tocEntries[i].classList.remove(this.visibleClass);
|
||||
i--;
|
||||
}
|
||||
while (i >= 0 && this.active[i]) {
|
||||
this.tocEntries[i].classList.add(this.visibleClass);
|
||||
min = Math.min(min, i);
|
||||
max = Math.max(max, i);
|
||||
i--;
|
||||
}
|
||||
while (i >= 0) {
|
||||
this.tocEntries[i].classList.remove(this.visibleClass);
|
||||
i--;
|
||||
}
|
||||
let parentOffset = this.tocEl?.getBoundingClientRect().top || 0;
|
||||
let scrollOffset = this.tocEl?.scrollTop || 0;
|
||||
let top = this.tocEntries[min].getBoundingClientRect().top - parentOffset + scrollOffset;
|
||||
let bottom = this.tocEntries[max].getBoundingClientRect().bottom - parentOffset + scrollOffset;
|
||||
this.activeIndicator?.setAttribute("style", `top: ${top}px; height: ${bottom - top}px`);
|
||||
};
|
||||
|
||||
scrollToActiveHeading = () => {
|
||||
// If the TOC widget can accommodate both the topmost
|
||||
// and bottommost items, scroll to the topmost item.
|
||||
// Otherwise, scroll to the bottommost one.
|
||||
|
||||
if (this.anchorNavTarget || !this.tocEl) return;
|
||||
const activeHeading =
|
||||
document.querySelectorAll<HTMLDivElement>(`#toc .${this.visibleClass}`);
|
||||
if (!activeHeading.length) return;
|
||||
|
||||
const topmost = activeHeading[0];
|
||||
const bottommost = activeHeading[activeHeading.length - 1];
|
||||
const tocHeight = this.tocEl.clientHeight;
|
||||
|
||||
let top;
|
||||
if (bottommost.getBoundingClientRect().bottom -
|
||||
topmost.getBoundingClientRect().top < 0.9 * tocHeight)
|
||||
top = topmost.offsetTop - 32;
|
||||
else
|
||||
top = bottommost.offsetTop - tocHeight * 0.8;
|
||||
|
||||
this.tocEl.scrollTo({
|
||||
top,
|
||||
left: 0,
|
||||
behavior: "smooth",
|
||||
});
|
||||
};
|
||||
|
||||
update = () => {
|
||||
requestAnimationFrame(() => {
|
||||
this.toggleActiveHeading();
|
||||
// requestAnimationFrame(() => {
|
||||
this.scrollToActiveHeading();
|
||||
// });
|
||||
});
|
||||
};
|
||||
|
||||
fallback = () => {
|
||||
if (!this.sections.length) return;
|
||||
|
||||
for (let i = 0; i < this.sections.length; i++) {
|
||||
let offsetTop = this.sections[i].getBoundingClientRect().top;
|
||||
let offsetBottom = this.sections[i].getBoundingClientRect().bottom;
|
||||
|
||||
if (this.isInRange(offsetTop, 0, window.innerHeight)
|
||||
|| this.isInRange(offsetBottom, 0, window.innerHeight)
|
||||
|| (offsetTop < 0 && offsetBottom > window.innerHeight)) {
|
||||
this.markActiveHeading(i);
|
||||
}
|
||||
else if (offsetTop > window.innerHeight) break;
|
||||
}
|
||||
};
|
||||
|
||||
markActiveHeading = (idx: number)=> {
|
||||
this.active[idx] = true;
|
||||
};
|
||||
|
||||
handleAnchorClick = (event: Event) => {
|
||||
const anchor = event
|
||||
.composedPath()
|
||||
.find((element) => element instanceof HTMLAnchorElement);
|
||||
|
||||
if (anchor) {
|
||||
const id = decodeURIComponent(anchor.hash?.substring(1));
|
||||
const idx = this.headingIdxMap.get(id);
|
||||
if (idx !== undefined) {
|
||||
this.anchorNavTarget = this.headings[idx];
|
||||
} else {
|
||||
this.anchorNavTarget = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
isInRange(value: number, min: number, max: number) {
|
||||
return min < value && value < max;
|
||||
};
|
||||
|
||||
connectedCallback() {
|
||||
// wait for the onload animation to finish, which makes the `getBoundingClientRect` return correct values
|
||||
const element = document.querySelector('.prose');
|
||||
if (element) {
|
||||
element.addEventListener('animationend', () => {
|
||||
this.init();
|
||||
}, { once: true });
|
||||
} else {
|
||||
console.warn('Animation element not found');
|
||||
}
|
||||
};
|
||||
|
||||
init() {
|
||||
this.tocEl = document.getElementById(
|
||||
"toc-inner-wrapper"
|
||||
);
|
||||
|
||||
if (!this.tocEl) return;
|
||||
|
||||
this.tocEl.addEventListener("click", this.handleAnchorClick, {
|
||||
capture: true,
|
||||
});
|
||||
|
||||
this.activeIndicator = document.getElementById("active-indicator");
|
||||
|
||||
this.tocEntries = Array.from(
|
||||
document.querySelectorAll<HTMLAnchorElement>("#toc a[href^='#']")
|
||||
);
|
||||
|
||||
if (this.tocEntries.length === 0) return;
|
||||
|
||||
this.sections = new Array(this.tocEntries.length);
|
||||
this.headings = new Array(this.tocEntries.length);
|
||||
for (let i = 0; i < this.tocEntries.length; i++) {
|
||||
const id = decodeURIComponent(this.tocEntries[i].hash?.substring(1));
|
||||
const heading = document.getElementById(id);
|
||||
const section = heading?.parentElement;
|
||||
if (heading instanceof HTMLElement && section instanceof HTMLElement) {
|
||||
this.headings[i] = heading;
|
||||
this.sections[i] = section;
|
||||
this.headingIdxMap.set(id, i);
|
||||
}
|
||||
}
|
||||
this.active = new Array(this.tocEntries.length).fill(false);
|
||||
|
||||
this.sections.forEach((section) =>
|
||||
this.observer.observe(section)
|
||||
);
|
||||
|
||||
this.fallback();
|
||||
this.update();
|
||||
};
|
||||
|
||||
disconnectedCallback() {
|
||||
this.sections.forEach((section) =>
|
||||
this.observer.unobserve(section)
|
||||
);
|
||||
this.observer.disconnect();
|
||||
this.tocEl?.removeEventListener("click", this.handleAnchorClick);
|
||||
};
|
||||
}
|
||||
|
||||
customElements.define("table-of-contents", TableOfContents);
|
||||
|
||||
</script>
|
|
@ -1,32 +0,0 @@
|
|||
---
|
||||
|
||||
import WidgetLayout from "./WidgetLayout.astro";
|
||||
import ButtonTag from "../control/ButtonTag.astro";
|
||||
import {getTagList} from "../../utils/content-utils";
|
||||
import {i18n} from "../../i18n/translation";
|
||||
import I18nKey from "../../i18n/i18nKey";
|
||||
import {url} from "../../utils/url-utils";
|
||||
|
||||
const tags = await getTagList();
|
||||
|
||||
const COLLAPSED_HEIGHT = "7.5rem";
|
||||
|
||||
const isCollapsed = tags.length >= 20;
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
style?: string;
|
||||
}
|
||||
const className = Astro.props.class
|
||||
const style = Astro.props.style
|
||||
|
||||
---
|
||||
<WidgetLayout name={i18n(I18nKey.tags)} id="tags" isCollapsed={isCollapsed} collapsedHeight={COLLAPSED_HEIGHT} class={className} style={style}>
|
||||
<div class="flex gap-2 flex-wrap">
|
||||
{tags.map(t => (
|
||||
<ButtonTag href={url(`/archive/tag/${t.name}/`)} label={`View all posts with the ${t.name} tag`}>
|
||||
{t.name}
|
||||
</ButtonTag>
|
||||
))}
|
||||
</div>
|
||||
</WidgetLayout>
|