Update blog UI and image lightbox

This commit is contained in:
2026-05-10 14:26:59 +08:00
parent 0c71229dc0
commit 7a1787a5c6
49 changed files with 3665 additions and 1221 deletions

View File

@@ -28,9 +28,10 @@ patch-package
## Tech Stack
- **Framework**: Astro 5.7.13 (SSR mode, output: 'server')
- **UI**: React 19.0.0 via @astrojs/react
- **Styling**: Tailwind CSS v4.1.7 via @tailwindcss/vite
- **Framework**: Astro 6.3.1 (SSR mode, output: 'server')
- **UI**: React 19.0.0 via @astrojs/react 5.0.4
- **Styling**: Tailwind CSS v4.3.0 via @tailwindcss/vite 4.3.0
- **Typography**: MiSans via the `misans` package, Geist Mono for code
- **TypeScript**: 5.8.3 with strict mode enabled
- **Content**: Notion API integration for blog posts
- **UI Components**: shadcn/ui (new-york style, neutral base color)
@@ -40,16 +41,19 @@ patch-package
## Code Style Guidelines
### Formatting (Prettier)
- Single quotes (`'`), no semicolons, trailing comma (es5 style)
- Plugins: `prettier-plugin-astro`, `prettier-plugin-tailwindcss`, `prettier-plugin-astro-organize-imports`
- Format with: `bun run prettier`
### TypeScript Configuration
- Strict mode enabled (`strictNullChecks: true`)
- Path aliases: `@/*``./src/*`
- JSX: `react-jsx` with React as import source
### Imports
- Use path alias `@/` for all internal imports:
- `@/components/*` → components
- `@/lib/*` → utility functions
@@ -61,12 +65,14 @@ patch-package
### Component Patterns
**Astro Components (.astro)**:
- Use for main layout and content components
- Props interface defined in frontmatter: `export interface Props { ... }`
- Use `class` prop for CSS classes (not `className`)
- Extract props: `const { class: className } = Astro.props`
**React Components (.tsx)**:
- Use for interactive UI components (shadcn/ui pattern)
- Use `className` for CSS classes
- Use `cn()` utility for conditional class merging
@@ -74,12 +80,13 @@ patch-package
- class-variance-authority (cva) for component variants
**Example:**
```tsx
import { cn } from '@/lib/utils'
import { cva } from 'class-variance-authority'
const variants = cva('base-classes', {
variants: { variant: { default: '...', outline: '...' } }
variants: { variant: { default: '...', outline: '...' } },
})
function Component({ className, variant, ...props }) {
@@ -90,6 +97,7 @@ function Component({ className, variant, ...props }) {
### Styling
**Tailwind CSS**:
- Primary styling framework (v4, no config file)
- Use `cn()` from `@/lib/utils` for merging conditional classes
- Dark mode via `data-theme` attribute (not media query)
@@ -97,35 +105,41 @@ function Component({ className, variant, ...props }) {
- OKLCH color space for all colors
**CSS Variables**:
- Light mode: `:root` selector
- Dark mode: `[data-theme='dark']` selector
- Semantic tokens: `--background`, `--foreground`, `--primary`, `--muted`, `--border`, `--ring`
- Special tokens: `--notion-surface`, `--notion-border`, `--fg`, `--anchor-border`
**Custom CSS**:
- `global.css`: Main stylesheet with Tailwind imports
- `notion-color.css`: Notion integration colors
- `typography.css`: Text styling
- `syntax-coloring.css`: Code highlighting styles
### Type Definitions
- All shared types in `src/lib/interfaces.ts`
- Notion API types: Block, Paragraph, Heading1-3, Image, Code, etc.
- Use explicit types for all props and function parameters
### Utility Functions
- `cn()` from `@/lib/utils`: Merge CSS classes (clsx + tailwind-merge)
- `formatDate()`, `readingTime()`, `calculateWordCountFromHtml()` in `@/lib/utils`
- Blog helpers in `@/lib/blog-helpers.ts`: URL parsing, slug generation, Notion image handling
- Style helpers in `@/lib/style-helpers.ts`: CSS class transformations
### Component Structure
- Layouts: `src/layouts/Layout.astro`
- Pages: `src/pages/*.astro` and `src/pages/**/*.astro`
- Components: `src/components/*.astro` and `src/components/ui/*.tsx`
- Notion block components: `src/components/notion/*.astro`
### Naming Conventions
- Components: PascalCase (`Header.astro`, `Button.tsx`)
- Files: PascalCase for components, kebab-case for utilities
- CSS classes: Tailwind utilities, custom classes in kebab-case
@@ -133,17 +147,20 @@ function Component({ className, variant, ...props }) {
- Constants: UPPER_SNAKE_CASE (`SITE`, `ENABLE_LIGHTBOX`)
### Error Handling
- Use try-catch for async operations
- Console errors for image URL parsing failures
- Graceful null/undefined checks for optional properties
- Return early for invalid data: `if (!block.Paragraph) return null`
### Inline Scripts
- Use `is:inline` for client-side scripts that need to execute immediately
- Use standard `<script>` tags for scoped client-side logic
- Listen to Astro events: `astro:after-swap` for navigation updates
### Content Pattern (Notion Integration)
- Blog posts fetched from Notion API
- Block-based rendering: `NotionBlocks.astro` recursively renders block arrays
- Each block type has a dedicated component (`Paragraph.astro`, `Heading1.astro`, etc.)
@@ -151,6 +168,7 @@ function Component({ className, variant, ...props }) {
- Children blocks supported for nested content
### Deployment
- Vercel adapter configured (`adapter: vercel()`)
- SSR output mode
- Server-side rendering for all pages