Personal website boilerplate made in astro with brutalism UI style
---
name: astro
description: Skill for building with the Astro web framework. Helps create Astro components and pages, configure SSR adapters, set up content collections, deploy static sites, and manage project structure and CLI commands. Use when the user needs to work with Astro, mentions .astro files, asks about static site generation (SSG), islands architecture, content collections, or deploying an Astro project.
license: MIT
metadata:
authors: "Astro Team"
version: "0.0.1"
---
# Astro Usage Guide
**Always consult [docs.astro.build](https://docs.astro.build) for code examples and latest API.**
Astro is the web framework for content-driven websites.
---
## Quick Reference
### File Location
CLI looks for `astro.config.js`, `astro.config.mjs`, `astro.config.cjs`, and `astro.config.ts` in: `./`. Use `--config` for custom path.
### CLI Commands
- `npx astro dev` - Start the development server.
- `npx astro build` - Build your project and write it to disk.
- `npx astro check` - Check your project for errors.
- `npx astro add` - Add an integration.
- `npx astro sync` - Generate TypeScript types for all Astro modules.
**Re-run after adding/changing plugins.**
### Project Structure
Reference [project structure docs](https://docs.astro.build/en/basics/project-structure).
- `src/*` - Project source code (components, pages, styles, images, etc.)
- `src/pages` - **Required.** Defines all pages and routes.
- `src/components` - Components (convention, not required).
- `src/layouts` - Layout components (convention, not required).
- `src/styles` - CSS/Sass files (convention, not required).
- `public/*` - Non-code, unprocessed assets (fonts, icons, etc.); copied as-is to build output.
- `package.json` - Project manifest.
- `astro.config.{js,mjs,cjs,ts}` - Astro configuration file. (recommended)
- `tsconfig.json` - TypeScript configuration file. (recommended)
---
## Core Config Options
| Option | Notes |
|--------|-------|
| `site` | Your final, deployed URL. Used to generate sitemaps and canonical URLs. |
### Example `astro.config.ts`
```ts
import { defineConfig } from 'astro/config';
export default defineConfig({
site: 'https://example.com',
});
```
---
## Common Workflows
### Creating a Basic Page
Add a file to `src/pages/` — the filename becomes the route:
```astro
---
// src/pages/index.astro
const title = 'Hello, Astro!';
---
<html>
<head><title>{title}</title></head>
<body>
<h1>{title}</h1>
</body>
</html>
```
### Creating a Component
```astro
---
// src/components/Card.astro
const { title, body } = Astro.props;
---
<div class="card">
<h2>{title}</h2>
<p>{body}</p>
</div>
```
### Deploying with an Adapter
1. Add the adapter: `npx astro add vercel --yes` (or `node`, `cloudflare`, `netlify`)
2. Run `npx astro check` to catch type and configuration errors before building.
3. Run `npx astro build` to produce the deployment artifact.
4. Verify the build output directory (e.g. `dist/`) exists and is non-empty before proceeding.
5. Deploy the output per the adapter's documentation.
---
## Adapters
Deploy to your favorite server, serverless, or edge host with build adapters. Use an adapter to enable on-demand rendering in your Astro project.
**Add [Node.js](https://docs.astro.build/en/guides/integrations-guide/node) adapter using astro add:**
```
npx astro add node --yes
```
**Add [Cloudflare](https://docs.astro.build/en/guides/integrations-guide/cloudflare) adapter using astro add:**
```
npx astro add cloudflare --yes
```
**Add [Netlify](https://docs.astro.build/en/guides/integrations-guide/netlify) adapter using astro add:**
```
npx astro add netlify --yes
```
**Add [Vercel](https://docs.astro.build/en/guides/integrations-guide/vercel) adapter using astro add:**
```
npx astro add vercel --yes
```
[Other Community adapters](https://astro.build/integrations/2/?search=&categories%5B%5D=adapters)
## Resources
- [Docs](https://docs.astro.build)
- [Config Reference](https://docs.astro.build/en/reference/configuration-reference/)
- [llms.txt](https://docs.astro.build/llms.txt)
- [GitHub](https://github.com/withastro/astro)
{
"mcpServers": {
"Astro docs": {
"type": "http",
"url": "https://mcp.docs.astro.build/mcp"
}
}
}
node_modules/
coverage/
.pnpm-store/
pnpm-lock.yaml
package-lock.json
yarn.lock
{
"endOfLine": "lf",
"semi": false,
"singleQuote": false,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 80,
"plugins": ["prettier-plugin-astro", "prettier-plugin-tailwindcss"],
"tailwindStylesheet": "src/styles/global.css",
"tailwindFunctions": ["cn", "cva"],
"overrides": [
{
"files": "*.astro",
"options": {
"parser": "astro"
}
}
]
}
# Personal Website
A personal website boilerplate — brutalism style. Built with
[Astro](https://astro.build) + React + Tailwind CSS v4 + shadcn/ui, deployed to
[Cloudflare Workers](https://developers.cloudflare.com/workers/).
> Scaffolded by the `astro-personal-website` powerup.
## Getting started
```sh
npm install
npm run setup # authenticate with Cloudflare (runs `wrangler login`)
npm run dev # dev server at http://localhost:4321
```
## Production site URL
The sitemap integration requires a `site` URL at build time. Set `SITE_URL`
once your Cloudflare domain (or `*.workers.dev` URL) is known, then build:
```sh
SITE_URL=https://your-domain.example npm run build
```
Dev builds fall back to `http://localhost:4321`, so no setup is needed locally.
## Deploying
Deploying uses [wrangler](https://developers.cloudflare.com/workers/), which is
authenticated by `npm run setup`. Create your own `wrangler.jsonc` (or
`wrangler.toml`) in the project root for your Worker, then:
```sh
npm run deploy # astro build && wrangler deploy
```
## Make it yours
Personal bits are applied at powerup-apply time via variables. To change them
afterwards:
| What | Where |
| ----------------------------- | ---------------------------------- |
| Site title & description | `src/consts.ts` |
| Name, profile image, socials | `src/pages/index.astro` |
| Home content page | `src/content/pages/home.mdx` |
| Analytics (Umami) | `src/components/BaseHead.astro` |
| Favicons | `public/favicon.svg`, `public/favicon.ico` |
Social buttons only render for handles you provided; add more like:
```astro
<SocialButton type="github" handle="your-handle">Github @your-handle</SocialButton>
```
To use your own profile picture, drop an image into `public/` and pass it to
the `Heading` component: `image={{ src: "/your-photo.png", alt: "Profile Picture" }}`.
Without it, a generic placeholder is shown.
## Project structure
```text
├── public/ # static assets (favicons, webmanifest)
├── src/
│ ├── components/ # Astro + React + shadcn/ui components
│ ├── content/pages/ # MDX content pages (home)
│ ├── layouts/ # main layout, incl. <BaseHead /> meta tags
│ ├── pages/ # routes (index.astro)
│ ├── styles/ # Tailwind + global styles
│ └── consts.ts # site title & description
└── wrangler.jsonc # your own Cloudflare config (create after `npm run setup`)
```
## Commands
| Command | Action |
| :-------------------------- | :------------------------------------------------ |
| `npm run setup` | Authenticate with Cloudflare (`wrangler login`) |
| `npm run dev` | Start local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run deploy` | Build and deploy to Cloudflare Workers |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run lint` / `format` | ESLint / Prettier |
| `npm run typecheck` | `astro check` |
| `npm run cf-typegen` | Generate Cloudflare types (`wrangler types`) |
## Learn more
- [Astro docs](https://docs.astro.build)
- [Cloudflare Workers docs](https://developers.cloudflare.com/workers/)
- [Tailwind CSS docs](https://tailwindcss.com/docs)// @ts-check
import tailwindcss from "@tailwindcss/vite"
import { defineConfig } from "astro/config"
import react from "@astrojs/react"
import mdx from '@astrojs/mdx';
import sitemap from '@astrojs/sitemap';
import cloudflare from "@astrojs/cloudflare";
// Set SITE_URL in your production build environment once your Cloudflare
// domain is set up (run `npm run setup` first to authenticate with wrangler).
const site = process.env.SITE_URL || "http://localhost:4321"
// https://astro.build/config
export default defineConfig({
site,
vite: {
plugins: [tailwindcss()],
},
integrations: [react(), mdx(), sitemap()],
adapter: cloudflare(),
}){
"$schema": "https://ui.shadcn.com/schema.json",
"style": "base-sera",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/styles/global.css",
"baseColor": "zinc",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "phosphor",
"rtl": false,
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"menuColor": "default",
"menuAccent": "subtle",
"registries": {}
}
import js from "@eslint/js"
import globals from "globals"
import reactHooks from "eslint-plugin-react-hooks"
import reactRefresh from "eslint-plugin-react-refresh"
import tseslint from "typescript-eslint"
import { defineConfig, globalIgnores } from "eslint/config"
export default defineConfig([
globalIgnores(["dist", ".astro"]),
{
files: ["**/*.{ts,tsx}"],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
globals: globals.browser,
},
},
])
{
"name": "{{projectName}}",
"type": "module",
"version": "0.0.1",
"private": true,
"engines": {
"node": ">=22.12.0"
},
"scripts": {
"setup": "wrangler login",
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro",
"lint": "eslint .",
"format": "prettier --write \"**/*.{ts,tsx,astro}\"",
"typecheck": "astro check",
"generate-types": "wrangler types",
"deploy": "astro build && wrangler deploy",
"cf-typegen": "wrangler types"
},
"dependencies": {
"@astrojs/cloudflare": "^14.2.5",
"@astrojs/mdx": "^7.0.8",
"@astrojs/react": "^6.0.4",
"@astrojs/sitemap": "^3.7.3",
"@base-ui/react": "^1.7.0",
"@fontsource-variable/dm-sans": "^5.3.0",
"@fontsource-variable/inter": "^5.3.0",
"@phosphor-icons/react": "^2.1.10",
"@radix-ui/react-dropdown-menu": "^2.1.24",
"@radix-ui/react-slot": "^1.3.3",
"@shadcn/react": "^0.3.0",
"@tailwindcss/typography": "^0.5.20",
"@tailwindcss/vite": "^4",
"@types/react": "^19",
"@types/react-dom": "^19",
"astro": "^7.2.6",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"date-fns": "^4.4.0",
"embla-carousel-react": "^8.6.0",
"input-otp": "^1.5.0",
"react": "^19.2.6",
"react-day-picker": "^10.0.1",
"react-dom": "^19.2.6",
"react-resizable-panels": "^4.12.3",
"recharts": "3.8.0",
"shadcn": "^4.19.0",
"tailwind-merge": "^3.6.0",
"tailwindcss": "^4",
"tw-animate-css": "^1.4.0"
},
"devDependencies": {
"@astrojs/check": "^0.9.10",
"@eslint/js": "^10",
"eslint": "^10",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17",
"prettier": "^3.8.3",
"prettier-plugin-astro": "^0.14.1",
"prettier-plugin-tailwindcss": "^0.8.0",
"typescript": "~6",
"typescript-eslint": "^8",
"wrangler": "^4.127.0"
}
}
�PNG