Skip to content

Commit 322253c

Browse files
committed
first commit
0 parents  commit 322253c

File tree

247 files changed

+72725
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

247 files changed

+72725
-0
lines changed

.env.sample

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# ========================================
2+
# 🔐 Environment Variables Configuration
3+
# ========================================
4+
# Copy this file to `.env` and fill in your actual values.
5+
# Variables prefixed with PUBLIC_ are exposed to client-side code.
6+
# ========================================
7+
8+
# 🔖 Raindrop.io Integration
9+
# Used for bookmarks and reading list features
10+
# Get your access token from: https://app.raindrop.io/settings/integrations
11+
RAINDROP_ACCESS_TOKEN=your_raindrop_access_token_here
12+
13+
# 🎵 Last.fm Integration
14+
# Powers the "Now Playing" music features throughout the site
15+
# Get your API credentials from: https://www.last.fm/api/account/create
16+
17+
# PUBLIC: API key for Last.fm requests (exposed to client)
18+
PUBLIC_LASTFM_API_KEY=
19+
20+
# PUBLIC: Your app name registered with Last.fm
21+
PUBLIC_LASTFM_APPNAME=ansango.dev
22+
23+
# PUBLIC: Last.fm API base URL (usually no need to change)
24+
PUBLIC_LASTFM_API_BASE_URL=https://ws.audioscrobbler.com/2.0
25+
26+
# PRIVATE: Shared secret for authenticated Last.fm requests
27+
LASTFM_SHARED_SECRET=
28+
29+
# 📊 GoatCounter Analytics (Optional)
30+
# Privacy-friendly web analytics
31+
# Sign up at: https://www.goatcounter.com/
32+
# PUBLIC: Your site code (e.g., "my-site" from my-site.goatcounter.com)
33+
PUBLIC_GOATCOUNTER_CODE=
34+
35+
# ========================================
36+
# 🚀 Deployment Secrets (CI/CD Only)
37+
# ========================================
38+
# Only needed if deploying via GitHub Actions to Cloudflare Pages
39+
# These should be set as GitHub repository secrets, not in .env
40+
41+
# Cloudflare account ID (found in Cloudflare dashboard)
42+
CLOUDFLARE_ACCOUNT_ID=
43+
44+
# Cloudflare API token with Pages:Edit permissions
45+
# Create at: https://dash.cloudflare.com/profile/api-tokens
46+
CLOUDFLARE_API_TOKEN=

.github/copilot-instructions.md

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# Copilot Instructions for ansango.dev
2+
3+
This guide helps AI coding agents work productively in the `ansango.dev` codebase. It covers architecture, workflows, conventions, and integration points unique to this project.
4+
5+
## 🏗️ Architecture Overview
6+
7+
- **Framework:** Built with [Astro](https://astro.build), [Svelte 5](https://svelte.dev), and [Tailwind CSS v4](https://tailwindcss.com).
8+
- **Content Collections:** Defined in `src/content.config.ts` and managed in `src/content/`. Types: blog, wiki, projects, about, uses, now, blogroll.
9+
- **Dynamic Pages:** Bookmarks and Reading pages powered by Raindrop.io API.
10+
- **Music Integration:** Live Last.fm integration with Svelte 5 components and TanStack Query.
11+
- **Site Metadata:** Centralized in `src/site.json` and `src/constants.ts`.
12+
- **Layouts:** Modular layouts in `src/layout/` with reusable elements (head, header, footer, theme).
13+
- **Components:** Organized by atomic design (atoms, molecules, organisms, templates). Mix of Astro and Svelte 5 components.
14+
## 🚦 Developer Workflows
15+
16+
- **Install:** `npm install`
17+
- **Dev Server:** `npm run dev` (http://localhost:4321)
18+
- **Build:** `npm run build`
19+
- **Preview:** `npm run preview`
20+
- **Astro CLI:** `npm run astro`
21+
- **Format:** `npm run format` (Prettier with Astro and Tailwind plugins)
22+
- **Environment:** Copy `.env.sample` to `.env` and configure API keys:
23+
- `RAINDROP_ACCESS_TOKEN` for bookmarks/reading
24+
- `PUBLIC_LASTFM_API_KEY` and `LASTFM_SHARED_SECRET` for music
25+
- **Content:** Add markdown files to `src/content/` with required frontmatter. Set `published: true` to publish.
26+
- **Add Collection:**
27+
1. Define schema in `src/content.config.ts` with glob loader
28+
2. Add metadata in `src/constants.ts` (contentCollections object)
29+
## 📝 Project Conventions
30+
31+
- **Frontmatter:** Each content type has strict frontmatter requirements using Zod schemas (see `src/content.config.ts`).
32+
- **Wiki:** Supports nested folders; navigation auto-generated from structure using `src/lib/tree-node.ts`.
33+
- **Styling:** Use Tailwind CSS v4 classes; styles in `src/styles/` (global.css, content.css, headings.css, tables.css, theme.css).
34+
- **Theme:** Dark/light mode via class strategy; theme logic in `src/layout/elements/theme.script.astro`.
35+
- **Pagination:** Controlled in `src/constants.ts` per collection via `entriesPerPage`. Set to 0 for no pagination.
36+
- **Tagging:** Tags are slugified and aggregated automatically.
37+
- **Component Organization:** Atomic design (atoms → molecules → organisms → templates).
38+
## 🔌 Integrations & Plugins
39+
40+
- **Astro Integrations:**
41+
- `@astrojs/sitemap` for XML sitemap generation
42+
- `astro-pagefind` for full-text search
43+
- `@astrojs/svelte` for Svelte 5 components
44+
- `@astrojs/rss` for RSS feed
45+
- **Svelte & Data:**
46+
## 🛠️ Key Files & Directories
47+
48+
- `src/content.config.ts`: Collection schemas with Zod and glob loaders
49+
- `src/constants.ts`: Site/collection metadata, navigation tree, pagination settings
50+
- `src/site.json`: Global site info (url, name, author, description, etc.)
51+
- `.env.sample`: Environment variables template
52+
- `src/layout/`: Page layouts and elements (head, header, footer, theme)
53+
- `src/components/`: Organized by atomic design
54+
- `atoms/`: Container, Link, Tag, Image, etc.
55+
- `molecules/`: Pagination, Searcher, PlayNow, Tree-node
56+
- `organisms/`: Archive, Bookmarks, Music, Reading, Wiki, Tags
57+
## 🧩 Patterns & Examples
58+
59+
- **Layout Usage:**
60+
- `src/layout/default.astro` is the base layout wrapper
61+
- Import layout elements from `src/layout/elements/`
62+
- Pass metadata props for SEO (title, description, etc.)
63+
64+
- **Content Example:**
65+
66+
```markdown
67+
---
68+
title: "My First Post"
69+
description: "Intro to my blog"
70+
date: 2025-10-11
71+
mod: 2025-10-11
72+
published: true
73+
tags: [astro, web-development]
74+
---
75+
76+
Your content here...
77+
```
78+
79+
## ⚡ Productivity Tips
80+
81+
- Reference `README.md` for full architecture, deployment, and integration details.
82+
- Follow existing folder and naming conventions for new features.
83+
- Use modular layouts and components for consistency.
84+
- Validate frontmatter and content structure before publishing.
85+
- Use `npm run format` before committing to ensure code style consistency.
86+
- For interactive features, prefer Svelte 5 components with TanStack Query.
87+
- Test API integrations locally with proper environment variables set.
88+
- Check browser console for client-side errors and server logs for build-time issues.
89+
90+
## 🔐 Environment Variables
91+
92+
Required for full functionality (copy from `.env.sample`):
93+
94+
```env
95+
# Raindrop.io (for bookmarks and reading)
96+
RAINDROP_ACCESS_TOKEN=your_token_here
97+
98+
# Last.fm (for music integration)
99+
PUBLIC_LASTFM_API_KEY=your_api_key_here
100+
PUBLIC_LASTFM_APPNAME=ansango.dev
101+
PUBLIC_LASTFM_API_BASE_URL=https://ws.audioscrobbler.com/2.0
102+
LASTFM_SHARED_SECRET=your_secret_here
103+
```
104+
105+
**Note:** Variables with `PUBLIC_` prefix are exposed to client-side code.
106+
107+
## 🎯 Common Tasks
108+
109+
- **Add a blog post:** Create MD file in `src/content/blog/` with proper frontmatter
110+
- **Update music username:** Change "ansango" in `src/lib/music.ts` and `src/lib/queries/current-track.ts`
111+
- **Customize Raindrop collections:** Follow naming convention in Raindrop (e.g., `ansango.work`)
112+
- **Add search:** Already integrated; works automatically for published content
113+
- **Customize theme colors:** Edit CSS custom properties in `src/styles/theme.css`
114+
- **Add new page:** Create file in `src/pages/` following Astro's file-based routing
115+
116+
---
117+
118+
If any section is unclear or missing, please provide feedback to improve these instructions.
119+
newCollection,
120+
};
121+
122+
// 2. In src/constants.ts
123+
const contentCollections: Record<CollectionName, Meta> = {
124+
// ...existing
125+
newCollection: {
126+
title: "New Collection",
127+
description: "Description here",
128+
entriesPerPage: 10,
129+
url: "/new-collection",
130+
published: true,
131+
},
132+
};
133+
134+
// 3. Create folder
135+
// mkdir src/content/new-collection
136+
```
137+
138+
- **Svelte Component Example:**
139+
```svelte
140+
<script lang="ts">
141+
import { useQuery } from '@tanstack/svelte-query';
142+
143+
let { data } = $props();
144+
let count = $state(0);
145+
let doubled = $derived(count * 2);
146+
</script>
147+
```
148+
149+
- **API Client Usage:**
150+
```typescript
151+
// Server-side (build time)
152+
import { getRaindropData } from '@/lib/raindrop';
153+
import { getLastfmData } from '@/lib/music';
154+
155+
const { bookmarks, collections } = await getRaindropData();
156+
const { tracks, artists, albums } = await getLastfmData();
157+
158+
// Client-side (runtime)
159+
import { useGetCurrentTrack } from '@/lib/queries';
160+
const query = useGetCurrentTrack();
161+
```
162+
## 🛠️ Key Files & Directories
163+
164+
- `src/content.config.ts`: Collection schemas
165+
- `src/constants.ts`: Site/collection metadata
166+
- `src/site.json`: Global site info
167+
- `src/layout/`: Page layouts
168+
- `src/components/`: UI and layout components
169+
- `src/lib/`: Utilities and plugins
170+
- `src/styles/`: CSS
171+
- `public/`: Static assets
172+
173+
## 🧩 Patterns & Examples
174+
175+
- **Layout Usage:**
176+
- `src/layout/default.astro` wraps pages with `<Head>`, `<Header>`, `<Container>`, `<Footer>`.
177+
- **Content Example:**
178+
179+
```markdown
180+
---
181+
title: "My First Post"
182+
description: "Intro to my blog"
183+
date: 2025-10-11
184+
mod: 2025-10-11
185+
published: true
186+
tags: [astro, web-development]
187+
---
188+
189+
...
190+
```
191+
192+
- **Add New Collection:**
193+
- Update schema, metadata, and create folder as above.
194+
195+
## ⚡ Productivity Tips
196+
197+
- Reference `README.md` for full architecture and workflow details.
198+
- Follow existing folder and naming conventions for new features.
199+
- Use modular layouts and components for consistency.
200+
- Validate frontmatter and content structure before publishing.
201+
202+
---
203+
204+
If any section is unclear or missing, please provide feedback to improve these instructions.

.github/workflows/deploy.yml

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
name: ansango.com
2+
env:
3+
CONTENT_DIR: src/content
4+
ASSETS_DIR: public/assets
5+
6+
on:
7+
workflow_dispatch:
8+
push:
9+
branches: [main]
10+
paths:
11+
- "src/content/**"
12+
schedule:
13+
- cron: "0 9 */2 * *" # Every 2 days at 9 AM UTC
14+
15+
# Cancel in-progress runs if new push
16+
concurrency:
17+
group: ${{ github.workflow }}-${{ github.ref }}
18+
cancel-in-progress: true
19+
20+
jobs:
21+
publish:
22+
runs-on: ubuntu-latest
23+
timeout-minutes: 15
24+
25+
steps:
26+
# ==========================================
27+
# CHECKOUT REPOSITORY
28+
# ==========================================
29+
30+
- name: 📥 Checkout repository
31+
uses: actions/checkout@v4
32+
33+
# ==========================================
34+
# PREPARE CONTENT FOR CONVERSION
35+
# ==========================================
36+
37+
- name: 📝 Prepare content and assets for export
38+
run: |
39+
mkdir -p obsidian_input
40+
cp -r ${{ env.CONTENT_DIR }} obsidian_input/
41+
if [ -d "${{ env.ASSETS_DIR }}" ]; then
42+
mkdir -p obsidian_input/assets
43+
cp -r ${{ env.ASSETS_DIR }}/* obsidian_input/assets/
44+
fi
45+
46+
# ==========================================
47+
# OBSIDIAN TO MARKDOWN CONVERSION
48+
# ==========================================
49+
50+
- name: 💾 Cache obsidian-export binary
51+
uses: actions/cache@v4
52+
id: obsidian-cache
53+
with:
54+
path: obsidian-export_Linux-x86_64.bin
55+
key: obsidian-export-v22.11.0
56+
57+
- name: 📥 Download obsidian-export
58+
if: steps.obsidian-cache.outputs.cache-hit != 'true'
59+
run: |
60+
wget https://github.com/zoni/obsidian-export/releases/download/v22.11.0/obsidian-export_Linux-x86_64.bin
61+
chmod +x obsidian-export_Linux-x86_64.bin
62+
63+
- name: 🔄 Convert Obsidian to Markdown
64+
run: |
65+
mkdir -p obsidian_output
66+
./obsidian-export_Linux-x86_64.bin ./obsidian_input ./obsidian_output
67+
68+
- name: 📦 Replace content with converted files
69+
run: |
70+
rm -rf ${{ env.CONTENT_DIR }}
71+
rm -rf src/assets
72+
cp -r obsidian_output/content ./src/
73+
if [ -d "obsidian_output/assets" ]; then
74+
cp -r obsidian_output/assets ./src/
75+
fi
76+
rm -rf obsidian_input obsidian_output
77+
78+
# ==========================================
79+
# BUILD SITE
80+
# ==========================================
81+
82+
- name: 🥟 Setup Bun
83+
uses: oven-sh/setup-bun@v2
84+
with:
85+
bun-version: 'latest'
86+
87+
- name: 💾 Cache Bun dependencies
88+
uses: actions/cache@v4
89+
with:
90+
path: ~/.bun/install/cache
91+
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
92+
restore-keys: |
93+
${{ runner.os }}-bun-
94+
95+
- name: 🔨 Build site
96+
env:
97+
# API credentials
98+
RAINDROP_ACCESS_TOKEN: ${{ secrets.RAINDROP_ACCESS_TOKEN }}
99+
LASTFM_SHARED_SECRET: ${{ secrets.LASTFM_SHARED_SECRET }}
100+
101+
# Public environment variables
102+
PUBLIC_LASTFM_API_KEY: ${{ secrets.PUBLIC_LASTFM_API_KEY }}
103+
PUBLIC_LASTFM_APPNAME: ansango.dev
104+
PUBLIC_LASTFM_API_BASE_URL: https://ws.audioscrobbler.com/2.0
105+
PUBLIC_GOATCOUNTER_CODE: ${{ secrets.PUBLIC_GOATCOUNTER_CODE }}
106+
run: bun install && bun run build
107+
108+
# ==========================================
109+
# DEPLOY TO CLOUDFLARE PAGES
110+
# ==========================================
111+
112+
- name: 🚀 Deploy to Cloudflare Pages
113+
uses: cloudflare/wrangler-action@v3
114+
with:
115+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
116+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
117+
command: pages deploy dist --project-name=ansango-dev --commit-dirty=true
118+
119+
# ==========================================
120+
# NOTIFICATIONS
121+
# ==========================================
122+
123+
- name: 📊 Build summary (success)
124+
if: success()
125+
run: |
126+
echo "### ✅ Deployment Successful! 🎉" >> $GITHUB_STEP_SUMMARY
127+
echo "" >> $GITHUB_STEP_SUMMARY
128+
echo "**Triggered by:** ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
129+
echo "**Branch:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
130+
echo "**Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
131+
echo "**Deployed at:** $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
132+
133+
- name: 💬 Build summary (failure)
134+
if: failure()
135+
run: |
136+
echo "### ❌ Deployment Failed" >> $GITHUB_STEP_SUMMARY
137+
echo "" >> $GITHUB_STEP_SUMMARY
138+
echo "Check the logs above for details." >> $GITHUB_STEP_SUMMARY
139+
echo "**Failed at:** $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY

0 commit comments

Comments
 (0)