mirror of
https://github.com/kremalicious/blog.git
synced 2024-11-29 07:26:22 +01:00
Matthias Kretschmann
05ad0470c2
* migrate to biome * cleanup * fix * use tsx * script tweaks * fix test runs * path tweaks
272 lines
12 KiB
Markdown
272 lines
12 KiB
Markdown
<p align="center">
|
||
<a href="https://kremalicious.com"><img src="https://raw.githubusercontent.com/kremalicious/portfolio/main/public/github-header.png" alt="GitHub Header" /></a>
|
||
</p>
|
||
<p align="center">
|
||
<strong>🍭 My blog built with <a href="https://astro.build">Astro</a> + TypeScript. Neat.</strong>
|
||
</p>
|
||
<p align="center">
|
||
<a href="https://kremalicious.com">kremalicious.com</a>
|
||
</p>
|
||
<p align="center">
|
||
<a href="https://github.com/kremalicious/blog/actions"><img src="https://github.com/kremalicious/blog/workflows/CI/badge.svg" alt="CI workflow badge" /></a>
|
||
<a href="https://codeclimate.com/github/kremalicious/blog/maintainability"><img src="https://api.codeclimate.com/v1/badges/4e86c791349cd12368cd/maintainability" alt="CodeClimate maintainability badge" /></a>
|
||
<a href="https://codeclimate.com/github/kremalicious/blog/test_coverage"><img src="https://api.codeclimate.com/v1/badges/4e86c791349cd12368cd/test_coverage" alt="CodeClimate coverage badge" /></a>
|
||
</p>
|
||
|
||
---
|
||
|
||
- [🎉 Features](#-features)
|
||
- [🌅 Image handling](#-image-handling)
|
||
- [🎆 EXIF extraction](#-exif-extraction)
|
||
- [💰 Cryptocurrency donation via Web3 browser wallets](#-cryptocurrency-donation-via-web3-browser-wallets)
|
||
- [🔍 Search](#-search)
|
||
- [🕸 Related Posts](#-related-posts)
|
||
- [📝 GitHub Changelog Rendering](#-github-changelog-rendering)
|
||
- [🌗 Theme Switcher](#-theme-switcher)
|
||
- [💎 SVG assets as components](#-svg-assets-as-components)
|
||
- [astro-redirect-from](#astro-redirect-from)
|
||
- [RSS \& JSON feeds](#rss--json-feeds)
|
||
- [✨ Development](#-development)
|
||
- [🔮 Linting](#-linting)
|
||
- [🔮 Type Checking](#-type-checking)
|
||
- [👩🔬 Testing](#-testing)
|
||
- [🎈 Content creation helpers](#-content-creation-helpers)
|
||
- [Add a new post](#add-a-new-post)
|
||
- [🚚 Deployment](#-deployment)
|
||
- [S3 Deployment](#s3-deployment)
|
||
- [🏛 Licenses](#-licenses)
|
||
- [Posts](#posts)
|
||
- [Photos \& images](#photos--images)
|
||
|
||
---
|
||
|
||
## 🎉 Features
|
||
|
||
The whole [blog](https://kremalicious.com) is a statically exported site built with [Astro](https://astro.build) and TypeScript. Almost all components are Astro or native Web Components, with some React components loaded client-side.
|
||
|
||
Styling happens through a combination of basic global styles and on components level either through CSS modules or CSS in `<style>` tags within Astro components.
|
||
|
||
Content lives under `content/` and Astro creates a content collection for each subfolder, which are then queried in components. Every post is a folder with a markdown file and all respective post assets co-located inside.
|
||
|
||
Retrieving content collections will enrich every post's frontmatter metadata, like extracting date and slug from the post folder name, or exif extraction for photos.
|
||
|
||
### 🌅 Image handling
|
||
|
||
Uses Astro's native `astro:assets` feature, all required image sizes are automatically generated from source images, working in combination with my own custom `<picture>` component. Making heavy use of Astro's `getImage()` and custom markup results in full image sizing control and properly `object-fit` images with varying aspect ratios.
|
||
|
||
Teaser images are all defined in a post's frontmatter `image` key, which is then passed to the `<Picture />` component for display.
|
||
|
||
If you want to know how this works, have a look at the respective files:
|
||
|
||
- [`src/components/Picture/index.astro`](src/components/Picture/index.astro)
|
||
- [`src/components/Picture/index.module.css`](src/components/Picture/index.module.css)
|
||
|
||
### 🎆 EXIF extraction
|
||
|
||
Automatically extracts EXIF & IPTC metadata from my photos and adds it to markdown frontmatter of respective photo posts. For minimal overhead, [fast-exif](https://github.com/titarenko/fast-exif) & [node-iptc](https://github.com/derekbaron/node-iptc) is used to parse every JPG file whenever a content collection is accessed.
|
||
|
||
In the end looks like this, including location display with [pigeon-maps](https://github.com/mariusandra/pigeon-maps):
|
||
|
||
<img width="1098" alt="screen shot 2018-10-14 at 20 27 39" src="https://user-images.githubusercontent.com/90316/46920507-9d6b7a00-cfef-11e8-84c8-a1997f471cae.png">
|
||
|
||
If you want to know how this works, have a look at the respective files:
|
||
|
||
- EXIF extraction with `readOutExif()` helper in [`src/lib/exif/index.ts`](src/lib/exif/index.ts)
|
||
- the `loadAndFormatCollection()` helper in [`src/lib/astro.ts`](src/lib/astro.ts)
|
||
- output through [`src/components/Exif/`](src/components/Exif/)
|
||
|
||
### 💰 Cryptocurrency donation via Web3 browser wallets
|
||
|
||
Lets visitors say thanks with Ether, any ERC-20, or Bitcoin. The Web3 wallet integration uses [RainbowKit](https://www.rainbowkit.com) for wallet connection, my own custom web3 API to fetch wallet token balances and metadata, and [wagmi](https://wagmi.sh) for sending transactions.
|
||
|
||
<img width="502" alt="Screenshot 2023-11-05 at 20 18 50" src="https://github.com/kremalicious/blog/assets/90316/7eadf4e9-6e98-4cf6-9639-aebf42ac0d4e">
|
||
|
||
<img width="487" alt="Screenshot 2023-11-05 at 20 20 04" src="https://github.com/kremalicious/blog/assets/90316/2421e64c-2d98-4e2a-a67a-ab1b5640bfb6">
|
||
|
||
If you want to know how this works, have a look at the respective feature under
|
||
|
||
- [`src/features/Web3/`](src/features/Web3/)
|
||
|
||
### 🔍 Search
|
||
|
||
A global search is provided with fuse.js. Whenever search is opened, all posts metadata is fetched, which is then queried against when the search field is used. This prevents a huge search index from being bundled in the site build.
|
||
|
||
<img width="700" alt="screen shot 2018-11-18 at 19 44 30" src="https://user-images.githubusercontent.com/90316/48676679-634f4400-eb6a-11e8-936d-293505d5c5d9.png">
|
||
|
||
If you want to know how this works, have a look at the respective feature under
|
||
|
||
- [`src/features/Search/`](src/features/Search/)
|
||
|
||
### 🕸 Related Posts
|
||
|
||
Under each post a list of related posts is displayed which are based on the tags and other metadata of the currently viewed post, also done with fuse.js.
|
||
|
||
<img width="700" alt="screen shot 2018-10-11 at 21 03 03" src="https://user-images.githubusercontent.com/90316/46827531-14f39c00-cd99-11e8-84aa-0e851c32c89c.png" />
|
||
|
||
If you want to know how this works, have a look at the respective component under
|
||
|
||
- [`src/components/RelatedPosts/`](src/components/RelatedPosts/)
|
||
|
||
### 📝 GitHub Changelog Rendering
|
||
|
||
Adds ability to show contents of a changelog, rendered from a `CHANGELOG.md` on GitHub from the given repository. The use case is to enhance release posts about projects hosted on GitHub. Makes use of the GitHub GraphQL API.
|
||
|
||
Adding this to a post's YAML frontmatter:
|
||
|
||
```yaml
|
||
changelog: kremalicious/gatsby-plugin-matomo
|
||
```
|
||
|
||
will render this at the end of the post:
|
||
|
||
<img width="700" alt="screen shot 2018-11-21 at 23 03 38" src="https://user-images.githubusercontent.com/90316/48870593-bc74dd00-ede1-11e8-9051-df55ab7b48d1.png">
|
||
|
||
See it live e.g. on [Matomo plugin for Gatsby](https://kremalicious.com/gatsby-plugin-matomo#changelog).
|
||
|
||
If you want to know how this works, have a look at the respective component under
|
||
|
||
- [`src/components/Changelog/`](src/components/Changelog/)
|
||
- the `getRepo()` helper in [`src/lib/github/github.ts`](src/lib/github/github.ts)
|
||
|
||
### 🌗 Theme Switcher
|
||
|
||
Includes a theme switcher which allows user to toggle between a light and a dark theme. Switching between them also happens automatically based on user's system preferences.
|
||
|
||
If you want to know how, have a look at the respective components:
|
||
|
||
- [`src/components/ThemeSwitch/`](src/components/ThemeSwitch/)
|
||
|
||
### 💎 SVG assets as components
|
||
|
||
All SVG assets under `src/images/` and from select iconset dependencies are converted to Astro & React components before building the site. Compiled components are placed under `src/images/components/` and all include the cleaned SVGs as inline HTML.
|
||
|
||
All SVGs can then be imported from `@/images/components` in all Astro or React components.
|
||
|
||
If you want to know how this works, have a look at the script:
|
||
|
||
- [`scripts/create-icons/`](scripts/create-icons/)
|
||
|
||
### astro-redirect-from
|
||
|
||
Still a remnant of the old [Jekyll](https://jekyllrb.com) days, which survived in [gatsby-redirect-from](https://kremalicious.com/gatsby-redirect-from/) and now works in Astro with [astro-redirect-from](https://kremalicious.com/astro-redirect-from/).
|
||
|
||
For all post slugs defined in a `redirect_from` frontmatter key, redirects will be put in place by Astro.
|
||
|
||
### RSS & JSON feeds
|
||
|
||
Generates rss & json feeds upon build time.
|
||
|
||
If you want to know how this works, have a look at the respective files:
|
||
|
||
- [`src/pages/feed.json.ts`](src/pages/feed.json.ts)
|
||
- [`src/pages/feed.xml.ts`](src/pages/feed.xml.ts)
|
||
|
||
## ✨ Development
|
||
|
||
```bash
|
||
git clone git@github.com:kremalicious/blog.git
|
||
cd blog/
|
||
|
||
# required env vars
|
||
cp .env.sample .env
|
||
vi .env
|
||
|
||
npm i
|
||
npm start
|
||
```
|
||
|
||
### 🔮 Linting
|
||
|
||
[Biome](https://biomejs.dev) is setup for all linting and formatting purposes:
|
||
|
||
```bash
|
||
npm run lint
|
||
```
|
||
|
||
### 🔮 Type Checking
|
||
|
||
Type checking can be invoked to check all TypeScript code, including within .astro files:
|
||
|
||
```bash
|
||
npm run typecheck
|
||
```
|
||
|
||
### 👩🔬 Testing
|
||
|
||
Test suite is setup with [Vitest](https://vitest.dev), [react-testing-library](https://github.com/kentcdodds/react-testing-library), and [Playwright](https://playwright.dev).
|
||
|
||
All unit test files live beside the respective component with naming pattern `*.test.ts(x)`. Integration test files live under `./test/e2e/` exclusively, with naming pattern `*.spec.ts`.
|
||
|
||
Testing setup, fixtures, and mocks shared between unit & integration tests can be found in `./test` folder.
|
||
|
||
To run all unit tests:
|
||
|
||
```bash
|
||
npm run test:unit
|
||
|
||
# watch mode
|
||
npm run test:unit:watch
|
||
```
|
||
|
||
For End-to-End integration testing, ideally run against the production build:
|
||
|
||
```bash
|
||
npm run build && npm run preview
|
||
|
||
# mapping `playwright` command
|
||
npm run test:e2e
|
||
npm run test:e2e -- --ui
|
||
npm run test:e2e -- path/to/file.spec.ts.
|
||
npm run test:e2e -- --update-snapshots
|
||
```
|
||
|
||
## 🎈 Content creation helpers
|
||
|
||
### Add a new post
|
||
|
||
```bash
|
||
npm run new "Hello World"
|
||
npm run new "Hello World" 2017-12-27
|
||
```
|
||
|
||
Create a new photo post with date, title & description pre-filled from EXIF/IPTC data of a given image file:
|
||
|
||
```bash
|
||
npm run new photo /path/to/photo.jpg
|
||
npm run new photo /path/to/photo.jpg "Hello Photo Post"
|
||
```
|
||
|
||
- [`scripts/new/`](scripts/new/)
|
||
|
||
## 🚚 Deployment
|
||
|
||
Every branch or Pull Request is automatically deployed by [Vercel](https://vercel.com) with their GitHub integration. A link to a preview deployment will appear under each Pull Request. Vercel is not used for the production deployment.
|
||
|
||
### S3 Deployment
|
||
|
||
The latest deployment of the `main` branch is automatically deployed to S3 from the GitHub Action as the production deployment, aliased to `kremalicious.com`. The deploy command simply calls the [`scripts/deploy-s3.sh`](scripts/deploy-s3.sh) script, syncing the contents of the `dist/` folder to S3:
|
||
|
||
```bash
|
||
npm run deploy:s3
|
||
```
|
||
|
||
## 🏛 Licenses
|
||
|
||
The MIT License (MIT)
|
||
|
||
EXCEPT FOR:
|
||
|
||
### Posts
|
||
|
||
[![Creative Commons License](https://i.creativecommons.org/l/by-nc-sa/4.0/80x15.png)](http://creativecommons.org/licenses/by-nc-sa/4.0/)
|
||
|
||
All post content under `./content/articles` & `./content/links` is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-nc-sa/4.0/).
|
||
|
||
### Photos & images
|
||
|
||
All photos & image assets are plain ol' copyright.
|
||
|
||
Copyright (c) 2008–2023 Matthias Kretschmann
|
||
|
||
Don't care if you fork & play with it, but you're not allowed to publish anything from it as a whole without my written permission. Also please be aware, the combination of typography, colors & layout makes up my brand identity. So please don't just clone everything, but rather do a remix!
|