docs | sidebar
@ -23,7 +23,7 @@
|
||||
"format": "unix-time"
|
||||
}
|
||||
],
|
||||
"default": "2025-12-29T22:44:15.028Z"
|
||||
"default": "2025-12-29T23:12:02.959Z"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
|
||||
export default new Map([
|
||||
["src/content/resources/astro-development.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fresources%2Fastro-development.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/resources/collections.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fresources%2Fcollections.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/resources/FileTree.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fresources%2FFileTree.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/resources/Masonry.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fresources%2FMasonry.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/resources/sidebar.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fresources%2Fsidebar.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/resources/test.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fresources%2Ftest.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/resources/workflow.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fresources%2Fworkflow.mdx&astroContentModuleFlag=true")]]);
|
||||
|
||||
21
app.log
@ -199,3 +199,24 @@
|
||||
{"level":"INFO","time":"2025-12-29T22:44:14.393Z","pid":27608,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:44:14.403Z","pid":27608,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from ./app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:45:26.156Z","pid":27608,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale es"}
|
||||
{"level":"INFO","time":"2025-12-29T22:50:59.233Z","pid":18260,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:50:59.811Z","pid":18260,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from ./app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:51:10.198Z","pid":22516,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:51:12.520Z","pid":22516,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:51:13.551Z","pid":22516,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:51:13.563Z","pid":22516,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from ./app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:51:30.288Z","pid":22516,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale es"}
|
||||
{"level":"INFO","time":"2025-12-29T22:53:59.973Z","pid":24864,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:54:00.942Z","pid":24864,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from ./app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:54:16.178Z","pid":27916,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:54:20.530Z","pid":27916,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:54:22.605Z","pid":27916,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:54:22.627Z","pid":27916,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from ./app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T22:56:14.003Z","pid":27916,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale es"}
|
||||
{"level":"INFO","time":"2025-12-29T23:03:57.474Z","pid":27916,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T23:11:40.022Z","pid":18684,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T23:11:40.915Z","pid":18684,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from ./app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T23:11:55.964Z","pid":28160,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T23:11:59.947Z","pid":28160,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T23:12:01.708Z","pid":28160,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\app-config.json for locale en"}
|
||||
{"level":"INFO","time":"2025-12-29T23:12:01.728Z","pid":28160,"hostname":"DESKTOP-OL563U1","msg":"Loading library config from ./app-config.json for locale en"}
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
{
|
||||
"main": [
|
||||
{
|
||||
"name": "facebook",
|
||||
"icon": "FaFacebookF",
|
||||
"link": "https://www.facebook.com/themefisher"
|
||||
},
|
||||
{
|
||||
"name": "twitter",
|
||||
"icon": "FaXTwitter",
|
||||
"link": "https://x.com/themefisher"
|
||||
},
|
||||
{
|
||||
"name": "linkedin",
|
||||
"icon": "FaLinkedinIn",
|
||||
"link": "https://bd.linkedin.com/company/themefisher"
|
||||
},
|
||||
{
|
||||
"name": "github",
|
||||
"icon": "FaGithub",
|
||||
"link": "https://github.com/themefisher/astrofront"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
{
|
||||
"colors": {
|
||||
"default": {
|
||||
"theme_color": {
|
||||
"primary": "#121212",
|
||||
"body": "#fff",
|
||||
"border": "#eaeaea",
|
||||
"theme_light": "#f2f2f2",
|
||||
"theme_dark": "#000"
|
||||
},
|
||||
"text_color": {
|
||||
"default": "#444",
|
||||
"dark": "#000",
|
||||
"light": "#666"
|
||||
}
|
||||
},
|
||||
"darkmode": {
|
||||
"theme_color": {
|
||||
"primary": "#fff",
|
||||
"body": "#252525",
|
||||
"border": "#3E3E3E",
|
||||
"theme_light": "#222222",
|
||||
"theme_dark": "#000"
|
||||
},
|
||||
"text_color": {
|
||||
"default": "#DDD",
|
||||
"dark": "#fff",
|
||||
"light": "#DDD"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fonts": {
|
||||
"font_family": {
|
||||
"primary": "Karla:wght@400;500;700",
|
||||
"primary_type": "sans-serif",
|
||||
"secondary": "",
|
||||
"secondary_type": ""
|
||||
},
|
||||
"font_size": {
|
||||
"base": "16",
|
||||
"scale": "1.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
552
src/content/resources/FileTree.mdx
Normal file
@ -0,0 +1,552 @@
|
||||
---
|
||||
pubDate: 2024-12-19
|
||||
title: FileTree Component
|
||||
author: PolyMech Team
|
||||
description: "Complete documentation for the FileTree component with glob patterns and clickable file links"
|
||||
image:
|
||||
url: "https://fastly.picsum.photos/id/972/200/300.jpg?hmac=UMf5f6BV9GkLiz0Xz9kMwm1riiTtlpIG2jt0WrxZ51Q?grayscale"
|
||||
alt: "FileTree component documentation"
|
||||
tags: ["component", "filetree", "documentation", "glob", "navigation"]
|
||||
sidebar:
|
||||
label: "FileTree Guide"
|
||||
items:
|
||||
- label: "Overview"
|
||||
href: "#filetree-component"
|
||||
- label: "Basic Usage"
|
||||
href: "#basic-usage"
|
||||
- label: "Glob Patterns"
|
||||
href: "#glob-pattern-support"
|
||||
- label: "Clickable Links"
|
||||
href: "#clickable-file-links"
|
||||
- label: "Configuration"
|
||||
href: "#configuration-options"
|
||||
- label: "Examples"
|
||||
href: "#comprehensive-examples"
|
||||
- label: "Integration"
|
||||
href: "#integration-examples"
|
||||
---
|
||||
|
||||
import FileTree from "@polymech/astro-base/components/FileTree.astro";
|
||||
|
||||
# FileTree Component
|
||||
|
||||
The FileTree component displays hierarchical file and directory structures with automatic discovery via glob patterns and clickable file links. It's perfect for documentation, code exploration, and project navigation.
|
||||
|
||||
## Key Features
|
||||
|
||||
- 🔍 **Auto-Discovery**: Use glob patterns to automatically generate file trees
|
||||
- 🔗 **Clickable Links**: Files link to editors, repositories, or file system
|
||||
- 🖼️ **Thumbnail View**: Windows Explorer-style grid with image previews
|
||||
- 🎯 **Smart Filtering**: Control depth, hidden files, and exclusions
|
||||
- 🎨 **Icon Support**: Automatic file type icons
|
||||
- 📱 **Responsive**: Works on all screen sizes
|
||||
- ⚡ **Fast**: Efficient file system scanning
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### Manual File Tree
|
||||
|
||||
The traditional way to create file trees by manually typing the structure:
|
||||
|
||||
<FileTree>
|
||||
|
||||
- src/
|
||||
- components/
|
||||
- **Header.astro** Main header component
|
||||
- Footer.astro
|
||||
- Navigation.astro
|
||||
- layouts/
|
||||
- Layout.astro
|
||||
- pages/
|
||||
- index.astro
|
||||
- about.astro
|
||||
- package.json
|
||||
- README.md
|
||||
|
||||
</FileTree>
|
||||
|
||||
```jsx
|
||||
<FileTree>
|
||||
- src/
|
||||
- components/
|
||||
- **Header.astro** Main header component
|
||||
- Footer.astro
|
||||
- layouts/
|
||||
- Layout.astro
|
||||
- package.json
|
||||
</FileTree>
|
||||
```
|
||||
|
||||
## Glob Pattern Support
|
||||
|
||||
### Auto-Generated Trees
|
||||
|
||||
Instead of manually typing file structures, use glob patterns to automatically discover and display files:
|
||||
|
||||
<FileTree glob="../**/*.{md,mdx}" maxDepth={2} />
|
||||
|
||||
```jsx
|
||||
<FileTree glob="../**/*.{md,mdx}" maxDepth={2} />
|
||||
```
|
||||
|
||||
### Current Directory Files
|
||||
|
||||
<FileTree glob="./*" />
|
||||
|
||||
```jsx
|
||||
<FileTree glob="./*" />
|
||||
```
|
||||
|
||||
### TypeScript Files Only
|
||||
|
||||
<FileTree glob="../**/*.ts" maxDepth={3} exclude={["node_modules", "dist"]} />
|
||||
|
||||
```jsx
|
||||
<FileTree glob="../**/*.ts" maxDepth={3} exclude={["node_modules", "dist"]} />
|
||||
```
|
||||
|
||||
## Thumbnail View
|
||||
|
||||
### Windows Explorer Style
|
||||
|
||||
Perfect for browsing images and visual content:
|
||||
|
||||
<FileTree
|
||||
glob="../public/images/**/*.{jpg,jpeg,png,gif,webp,svg}"
|
||||
view="thumbs"
|
||||
thumbSize="medium"
|
||||
maxDepth={2}
|
||||
/>
|
||||
|
||||
```jsx
|
||||
<FileTree
|
||||
glob="../public/images/**/*.{jpg,jpeg,png,gif,webp,svg}"
|
||||
view="thumbs"
|
||||
thumbSize="medium"
|
||||
maxDepth={2}
|
||||
/>
|
||||
```
|
||||
|
||||
### Different Thumbnail Sizes
|
||||
|
||||
Small thumbnails with mixed file types:
|
||||
|
||||
<FileTree
|
||||
glob="../src/**/*.{ts,astro,json}"
|
||||
view="thumbs"
|
||||
thumbSize="small"
|
||||
maxDepth={2}
|
||||
/>
|
||||
|
||||
Large thumbnails for detailed preview:
|
||||
|
||||
<FileTree
|
||||
glob="../public/images/**/*.{jpg,jpeg,png}"
|
||||
view="thumbs"
|
||||
thumbSize="large"
|
||||
maxDepth={1}
|
||||
/>
|
||||
|
||||
### File Type Icons in Thumbnails
|
||||
|
||||
Shows different icons for different file types with **imagetools integration**:
|
||||
|
||||
<FileTree
|
||||
glob="../**/*.{md,ts,js,json,astro,vue,jsx}"
|
||||
view="thumbs"
|
||||
thumbSize="medium"
|
||||
maxDepth={1}
|
||||
/>
|
||||
|
||||
### Image Optimization Features
|
||||
|
||||
Thanks to imagetools integration, thumbnails include:
|
||||
- **AVIF Format**: Modern, efficient image format
|
||||
- **Blurred Placeholders**: Smooth loading experience
|
||||
- **Responsive Sizing**: Automatic width generation
|
||||
- **Lazy Loading**: Performance optimization
|
||||
- **Aspect Ratio**: Consistent square thumbnails
|
||||
|
||||
```jsx
|
||||
// Small thumbnails (80px)
|
||||
<FileTree view="thumbs" thumbSize="small" />
|
||||
|
||||
// Medium thumbnails (120px) - default
|
||||
<FileTree view="thumbs" thumbSize="medium" />
|
||||
|
||||
// Large thumbnails (160px)
|
||||
<FileTree view="thumbs" thumbSize="large" />
|
||||
```
|
||||
|
||||
## Clickable File Links
|
||||
|
||||
Files in auto-generated trees are clickable by default, supporting multiple link types:
|
||||
|
||||
### Default (File System)
|
||||
|
||||
<FileTree glob="../src/components/polymech/**/*.{ts,astro}" maxDepth={2} />
|
||||
|
||||
### VS Code Integration
|
||||
|
||||
Click files to open directly in VS Code:
|
||||
|
||||
<FileTree
|
||||
glob="../src/components/polymech/**/*.astro"
|
||||
maxDepth={1}
|
||||
urlPrefix="vscode://file"
|
||||
/>
|
||||
|
||||
```jsx
|
||||
<FileTree
|
||||
glob="../src/components/polymech/**/*.astro"
|
||||
urlPrefix="vscode://file"
|
||||
/>
|
||||
```
|
||||
|
||||
### GitHub Repository Links
|
||||
|
||||
<FileTree
|
||||
glob="../**/*.json"
|
||||
maxDepth={1}
|
||||
urlPrefix="https://github.com/username/repo/blob/main"
|
||||
/>
|
||||
|
||||
```jsx
|
||||
<FileTree
|
||||
glob="../**/*.json"
|
||||
urlPrefix="https://github.com/username/repo/blob/main"
|
||||
/>
|
||||
```
|
||||
|
||||
### Links Disabled
|
||||
|
||||
<FileTree
|
||||
glob="../src/components/polymech/**/*.ts"
|
||||
maxDepth={1}
|
||||
linkFiles={false}
|
||||
/>
|
||||
|
||||
```jsx
|
||||
<FileTree
|
||||
glob="../src/components/polymech/**/*.ts"
|
||||
linkFiles={false}
|
||||
/>
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Props Interface
|
||||
|
||||
```typescript
|
||||
interface Props {
|
||||
glob?: string; // Glob pattern to auto-generate file tree
|
||||
maxDepth?: number; // Maximum directory depth (default: 5)
|
||||
showHidden?: boolean; // Show hidden files starting with . (default: false)
|
||||
exclude?: string[]; // Patterns to exclude (default: [])
|
||||
urlPrefix?: string; // URL prefix for file links (auto-detected)
|
||||
linkFiles?: boolean; // Whether to make files clickable (default: true)
|
||||
view?: 'tree' | 'thumbs'; // Display mode (default: 'tree')
|
||||
thumbSize?: 'small' | 'medium' | 'large'; // Thumbnail size (default: 'medium')
|
||||
}
|
||||
```
|
||||
|
||||
### Glob Patterns
|
||||
|
||||
| Pattern | Description | Example |
|
||||
|---------|-------------|---------|
|
||||
| `**/*` | All files recursively | `../src/**/*` |
|
||||
| `*.ext` | Files with specific extension | `../**/*.ts` |
|
||||
| `{a,b}` | Multiple extensions | `../**/*.{js,ts}` |
|
||||
| `**/dir/**` | Files in specific directory | `**/components/**/*` |
|
||||
| `!pattern` | Exclude pattern | Use `exclude` prop instead |
|
||||
|
||||
### URL Prefix Types
|
||||
|
||||
| Type | Prefix | Description |
|
||||
|------|--------|-------------|
|
||||
| **VS Code** | `vscode://file` | Opens files in VS Code editor |
|
||||
| **GitHub** | `https://github.com/user/repo/blob/main` | Links to GitHub repository |
|
||||
| **GitLab** | `https://gitlab.com/user/repo/-/blob/main` | Links to GitLab repository |
|
||||
| **File System** | `file://` | Opens local files in system |
|
||||
| **Custom** | `https://your-viewer.com` | Custom file viewer |
|
||||
| **Default** | Auto-detected | Uses current dev server |
|
||||
|
||||
## Comprehensive Examples
|
||||
|
||||
### Development Workflow
|
||||
|
||||
Show project structure with VS Code integration:
|
||||
|
||||
<FileTree
|
||||
glob="../src/**/*.{astro,ts,js}"
|
||||
maxDepth={3}
|
||||
exclude={["node_modules", ".git", "dist", "build"]}
|
||||
urlPrefix="vscode://file"
|
||||
/>
|
||||
|
||||
```jsx
|
||||
<FileTree
|
||||
glob="../src/**/*.{astro,ts,js}"
|
||||
maxDepth={3}
|
||||
exclude={["node_modules", ".git", "dist", "build"]}
|
||||
urlPrefix="vscode://file"
|
||||
/>
|
||||
```
|
||||
|
||||
### Documentation Files
|
||||
|
||||
<FileTree
|
||||
glob="../**/*.{md,mdx}"
|
||||
maxDepth={2}
|
||||
urlPrefix="https://github.com/yourorg/yourrepo/blob/main"
|
||||
/>
|
||||
|
||||
```jsx
|
||||
<FileTree
|
||||
glob="../**/*.{md,mdx}"
|
||||
maxDepth={2}
|
||||
urlPrefix="https://github.com/yourorg/yourrepo/blob/main"
|
||||
/>
|
||||
```
|
||||
|
||||
### Configuration Files
|
||||
|
||||
<FileTree
|
||||
glob="../**/*.{json,yaml,yml,toml,config.js,config.ts}"
|
||||
maxDepth={2}
|
||||
/>
|
||||
|
||||
```jsx
|
||||
<FileTree
|
||||
glob="../**/*.{json,yaml,yml,toml,config.js,config.ts}"
|
||||
maxDepth={2}
|
||||
/>
|
||||
```
|
||||
|
||||
### Show Hidden Files
|
||||
|
||||
<FileTree
|
||||
glob="../**/*"
|
||||
maxDepth={2}
|
||||
showHidden={true}
|
||||
exclude={["node_modules"]}
|
||||
/>
|
||||
|
||||
```jsx
|
||||
<FileTree
|
||||
glob="../**/*"
|
||||
maxDepth={2}
|
||||
showHidden={true}
|
||||
exclude={["node_modules"]}
|
||||
/>
|
||||
```
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### With Astro Projects
|
||||
|
||||
```jsx
|
||||
// Show Astro project structure
|
||||
<FileTree
|
||||
glob="../src/**/*.astro"
|
||||
maxDepth={3}
|
||||
urlPrefix="vscode://file"
|
||||
/>
|
||||
|
||||
// Show content collections
|
||||
<FileTree
|
||||
glob="../src/content/**/*.{md,mdx}"
|
||||
maxDepth={2}
|
||||
/>
|
||||
```
|
||||
|
||||
### With React/Vue Projects
|
||||
|
||||
```jsx
|
||||
// Show component files
|
||||
<FileTree
|
||||
glob="../src/**/*.{jsx,tsx,vue}"
|
||||
maxDepth={3}
|
||||
exclude={["node_modules", "dist"]}
|
||||
/>
|
||||
```
|
||||
|
||||
### With Documentation Sites
|
||||
|
||||
```jsx
|
||||
// Link to GitHub for editing
|
||||
<FileTree
|
||||
glob="../docs/**/*.md"
|
||||
urlPrefix="https://github.com/yourorg/docs/edit/main"
|
||||
maxDepth={2}
|
||||
/>
|
||||
```
|
||||
|
||||
### Custom File Viewer
|
||||
|
||||
```jsx
|
||||
// Link to custom file viewer API
|
||||
<FileTree
|
||||
glob="../**/*.log"
|
||||
urlPrefix="https://yourapp.com/file-viewer"
|
||||
maxDepth={1}
|
||||
/>
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### File Type Icons & Modern Link Styling
|
||||
|
||||
The FileTree automatically displays appropriate icons and uses subtle, modern link styling:
|
||||
|
||||
**File Icons:**
|
||||
- 📄 `.md`, `.mdx` - Markdown files
|
||||
- 🟦 `.ts`, `.tsx` - TypeScript files
|
||||
- 🟨 `.js`, `.jsx` - JavaScript files
|
||||
- 🎨 `.astro` - Astro components
|
||||
- ⚙️ `.json`, `.yaml` - Configuration files
|
||||
- 📁 Directories with gold folder icons
|
||||
|
||||
**Link Styling Best Practices:**
|
||||
- **Subtle Colors**: No aggressive blue links - uses content text color
|
||||
- **Background Hover**: Gentle background highlight on hover instead of color change
|
||||
- **Subtle Underline**: Thin, muted underline appears on hover
|
||||
- **Clickable Indicators**: Small dots on thumbnails indicate clickable items
|
||||
- **Accessibility**: Proper focus states and keyboard navigation
|
||||
- **Consistent**: Same styling approach across tree and thumbnail views
|
||||
|
||||
### Responsive Design
|
||||
|
||||
The FileTree adapts to different screen sizes:
|
||||
- Desktop: Full tree with hover effects
|
||||
- Mobile: Collapsible directories
|
||||
- Touch-friendly click targets
|
||||
|
||||
### Performance Optimized
|
||||
|
||||
- Efficient file system scanning
|
||||
- Lazy directory expansion
|
||||
- Cached glob results
|
||||
- Minimal DOM updates
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Use Appropriate Depth Limits
|
||||
|
||||
```jsx
|
||||
// Good - reasonable depth
|
||||
<FileTree glob="../src/**/*" maxDepth={3} />
|
||||
|
||||
// Avoid - too deep, slow performance
|
||||
<FileTree glob="../**/*" maxDepth={10} />
|
||||
```
|
||||
|
||||
### 2. Exclude Unnecessary Directories
|
||||
|
||||
```jsx
|
||||
// Good - exclude build artifacts
|
||||
<FileTree
|
||||
glob="../**/*"
|
||||
exclude={["node_modules", ".git", "dist", "build", ".cache"]}
|
||||
/>
|
||||
```
|
||||
|
||||
### 3. Use Specific Patterns
|
||||
|
||||
```jsx
|
||||
// Good - specific file types
|
||||
<FileTree glob="../src/**/*.{astro,ts}" />
|
||||
|
||||
// Less efficient - too broad
|
||||
<FileTree glob="../**/*" />
|
||||
```
|
||||
|
||||
### 4. Choose Appropriate URL Prefixes
|
||||
|
||||
```jsx
|
||||
// Development - VS Code
|
||||
<FileTree urlPrefix="vscode://file" />
|
||||
|
||||
// Documentation - GitHub
|
||||
<FileTree urlPrefix="https://github.com/user/repo/blob/main" />
|
||||
|
||||
// Local browsing - file system
|
||||
<FileTree urlPrefix="file://" />
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No Files Found
|
||||
|
||||
If your FileTree shows "No files found", the error message now includes debugging information:
|
||||
|
||||
```
|
||||
No files found matching pattern: ./gallery/*.jpg
|
||||
Searched in: /full/path/to/src/content/resources
|
||||
```
|
||||
|
||||
This helps you verify:
|
||||
|
||||
1. **Pattern Syntax**: Check if your glob pattern is correct
|
||||
2. **Search Location**: Verify the absolute path is where you expect
|
||||
3. **File Existence**: Confirm files actually exist in the searched directory
|
||||
4. **Exclude Patterns**: Check if exclude patterns aren't too broad
|
||||
|
||||
### Debug Examples
|
||||
|
||||
<FileTree
|
||||
glob="./non-existent/*.jpg"
|
||||
view="thumbs"
|
||||
thumbSize="small"
|
||||
/>
|
||||
|
||||
<FileTree
|
||||
glob="./missing-dir/**/*.png"
|
||||
view="tree"
|
||||
maxDepth={2}
|
||||
/>
|
||||
|
||||
### Links Not Working
|
||||
|
||||
If file links don't work:
|
||||
|
||||
1. Check the `urlPrefix` is correct for your environment
|
||||
2. Verify the protocol is supported by your system
|
||||
3. For VS Code links, ensure VS Code is installed
|
||||
4. For repository links, check the URL format
|
||||
|
||||
### Performance Issues
|
||||
|
||||
If FileTree is slow:
|
||||
|
||||
1. Reduce `maxDepth` value
|
||||
2. Use more specific glob patterns
|
||||
3. Add more items to `exclude` array
|
||||
4. Consider using `linkFiles={false}` for display-only trees
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### From Manual Trees
|
||||
|
||||
Replace manual file listings:
|
||||
|
||||
```jsx
|
||||
// Old way
|
||||
<FileTree>
|
||||
- src/
|
||||
- components/
|
||||
- Header.astro
|
||||
- Footer.astro
|
||||
</FileTree>
|
||||
|
||||
// New way
|
||||
<FileTree glob="../src/components/**/*.astro" />
|
||||
```
|
||||
|
||||
### From Other File Tree Components
|
||||
|
||||
The FileTree component is compatible with standard markdown file tree syntax, making migration straightforward.
|
||||
|
||||
---
|
||||
|
||||
The FileTree component transforms static file documentation into interactive, always-up-to-date navigation tools. Perfect for project documentation, code exploration, and development workflows!
|
||||
492
src/content/resources/Masonry.mdx
Normal file
@ -0,0 +1,492 @@
|
||||
---
|
||||
pubDate: 2024-12-19
|
||||
title: MasonryGallery Component
|
||||
author: Development Team
|
||||
description: "Complete guide to the MasonryGallery component - a Pinterest-style masonry layout with lightbox functionality, glob support, and responsive design."
|
||||
image:
|
||||
url: "https://fastly.picsum.photos/id/972/200/300.jpg?hmac=UMf5f6BV9GkLiz0Xz9kMwm1riiTtlpIG2jt0WrxZ51Q?nature"
|
||||
alt: "Masonry gallery preview"
|
||||
tags: ["masonry", "gallery", "images", "component", "responsive"]
|
||||
sidebar:
|
||||
label: "Navigation"
|
||||
items:
|
||||
- label: "Overview"
|
||||
href: "#masonrygallery-component"
|
||||
- label: "Live Examples"
|
||||
href: "#live-examples"
|
||||
- label: "Basic Usage"
|
||||
href: "#basic-usage"
|
||||
- label: "Advanced Features"
|
||||
href: "#advanced-configuration"
|
||||
- label: "API Reference"
|
||||
href: "#api-reference"
|
||||
- label: "Best Practices"
|
||||
href: "#best-practices"
|
||||
---
|
||||
|
||||
import MasonryGallery from "@polymech/astro-base/components/MasonryGallery.astro";
|
||||
|
||||
|
||||
# MasonryGallery Component
|
||||
|
||||
A beautiful Pinterest-style masonry gallery component with lightbox functionality, glob pattern support, and configurable constraints. Perfect for showcasing image collections with natural, flowing layouts.
|
||||
|
||||
## Key Features
|
||||
|
||||
- **📐 Masonry Layout**: CSS Grid-based masonry with no fixed height - images flow naturally
|
||||
- **🖼️ Lightbox**: Full lightbox with swipe support and keyboard navigation
|
||||
- **🔍 Glob Support**: Auto-load images using patterns like `*.jpg`, `**/*.{jpg,png}`
|
||||
- **📏 Size Constraints**: Configure `maxItems`, `maxWidth`, and `maxHeight`
|
||||
- **📱 Responsive**: Adapts seamlessly to mobile, tablet, and desktop screens
|
||||
- **🏷️ Metadata Support**: Companion `.json` and `.md` files for rich image metadata
|
||||
- **⚡ Performance**: Lazy loading and optimized image formats (AVIF, WebP)
|
||||
- **🎨 Customizable**: Full control over gallery and lightbox settings
|
||||
- **📅 Flexible Grouping**: Optional grouping by year, month, or custom functions with EXIF date extraction
|
||||
|
||||
## Live Examples
|
||||
|
||||
### Default Masonry Layout
|
||||
|
||||
Auto-loads images from the gallery directory with balanced sizing:
|
||||
|
||||
<MasonryGallery
|
||||
glob="./gallery/*.jpg"
|
||||
maxItems={10}
|
||||
maxWidth="150px"
|
||||
maxHeight="500px"
|
||||
groupBy="groupByYear"
|
||||
gallerySettings={{
|
||||
SHOW_TITLE: false,
|
||||
SHOW_DESCRIPTION: false,
|
||||
SIZES_REGULAR: "(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
|
||||
}}
|
||||
lightboxSettings={{
|
||||
SHOW_TITLE: true,
|
||||
SHOW_DESCRIPTION: true,
|
||||
SIZES_LARGE: "90vw"
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
### Compact Grid
|
||||
|
||||
Perfect for thumbnails and preview galleries:
|
||||
|
||||
<MasonryGallery
|
||||
glob="./gallery/*.jpg"
|
||||
maxItems={10}
|
||||
maxWidth="250px"
|
||||
maxHeight="300px"
|
||||
gallerySettings={{
|
||||
SHOW_TITLE: false,
|
||||
SHOW_DESCRIPTION: false
|
||||
}}
|
||||
/>
|
||||
|
||||
### Large Format Display
|
||||
|
||||
Ideal for portfolio and showcase galleries:
|
||||
|
||||
<MasonryGallery
|
||||
glob="./gallery/*.jpg"
|
||||
maxItems={10}
|
||||
maxWidth="450px"
|
||||
maxHeight="600px"
|
||||
gallerySettings={{
|
||||
SHOW_TITLE: true,
|
||||
SHOW_DESCRIPTION: true
|
||||
}}
|
||||
/>
|
||||
|
||||
### Mobile-Optimized
|
||||
|
||||
Responsive design that works beautifully on all devices:
|
||||
|
||||
<MasonryGallery
|
||||
glob="./gallery/*.jpg"
|
||||
maxItems={10}
|
||||
maxWidth="280px"
|
||||
maxHeight="350px"
|
||||
gallerySettings={{
|
||||
SHOW_TITLE: false,
|
||||
SHOW_DESCRIPTION: false,
|
||||
SIZES_REGULAR: "(max-width: 480px) 100vw, (max-width: 768px) 50vw, 33vw"
|
||||
}}
|
||||
/>
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### Simple Glob Pattern
|
||||
|
||||
```jsx
|
||||
// Auto-load all JPG images with default settings
|
||||
<MasonryGallery
|
||||
glob="./gallery/*.jpg"
|
||||
maxItems={10}
|
||||
/>
|
||||
```
|
||||
|
||||
### With Size Constraints
|
||||
|
||||
```jsx
|
||||
// Control maximum dimensions and item count
|
||||
<MasonryGallery
|
||||
glob="./images/*.{jpg,png,webp}"
|
||||
maxItems={10}
|
||||
maxWidth="300px"
|
||||
maxHeight="400px"
|
||||
/>
|
||||
```
|
||||
|
||||
### No Grouping (Default)
|
||||
|
||||
```jsx
|
||||
// Simple masonry layout without any grouping
|
||||
<MasonryGallery
|
||||
glob="./gallery/*.jpg"
|
||||
maxItems={10}
|
||||
maxWidth="280px"
|
||||
maxHeight="350px"
|
||||
/>
|
||||
```
|
||||
|
||||
### Group by Year
|
||||
|
||||
```jsx
|
||||
// Group images by year with year headers
|
||||
<MasonryGallery
|
||||
glob="./gallery/*.jpg"
|
||||
maxItems={10}
|
||||
groupBy="groupByYear"
|
||||
maxWidth="280px"
|
||||
maxHeight="350px"
|
||||
/>
|
||||
```
|
||||
|
||||
### Group by Month
|
||||
|
||||
```jsx
|
||||
// Group images by month with month/year headers
|
||||
<MasonryGallery
|
||||
glob="./gallery/*.jpg"
|
||||
maxItems={10}
|
||||
groupBy="groupByMonth"
|
||||
maxWidth="280px"
|
||||
maxHeight="350px"
|
||||
/>
|
||||
```
|
||||
|
||||
### Subdirectory Patterns
|
||||
|
||||
```jsx
|
||||
// Load from nested directories
|
||||
<MasonryGallery
|
||||
glob="./portfolio/**/*.jpg"
|
||||
maxItems={10}
|
||||
maxWidth="350px"
|
||||
maxHeight="500px"
|
||||
/>
|
||||
```
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Custom Gallery Settings
|
||||
|
||||
```jsx
|
||||
<MasonryGallery
|
||||
glob="./showcase/*.jpg"
|
||||
maxItems={10}
|
||||
maxWidth="400px"
|
||||
maxHeight="600px"
|
||||
gallerySettings={{
|
||||
SHOW_TITLE: true,
|
||||
SHOW_DESCRIPTION: true,
|
||||
SIZES_REGULAR: "(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw",
|
||||
SIZES_THUMB: "200px",
|
||||
SIZES_LARGE: "800px"
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### Lightbox Customization
|
||||
|
||||
```jsx
|
||||
<MasonryGallery
|
||||
glob="./photos/*.jpg"
|
||||
maxItems={10}
|
||||
lightboxSettings={{
|
||||
SHOW_TITLE: true,
|
||||
SHOW_DESCRIPTION: false,
|
||||
SIZES_LARGE: "95vw"
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### Custom Grouping Function
|
||||
|
||||
```jsx
|
||||
// Create a custom grouping function
|
||||
const groupByFileSize = (image) => {
|
||||
// This would need to be implemented to get actual file size
|
||||
// For demonstration purposes, we'll group by a mock size category
|
||||
const mockSize = Math.random() > 0.5 ? 'large' : 'small';
|
||||
return {
|
||||
key: mockSize,
|
||||
label: mockSize === 'large' ? 'Large Images' : 'Small Images',
|
||||
sortOrder: mockSize === 'large' ? 1 : 0
|
||||
};
|
||||
};
|
||||
|
||||
<MasonryGallery
|
||||
glob="./portfolio/*.jpg"
|
||||
maxItems={10}
|
||||
groupBy={groupByFileSize}
|
||||
maxWidth="320px"
|
||||
maxHeight="400px"
|
||||
gallerySettings={{
|
||||
SHOW_TITLE: true,
|
||||
SHOW_DESCRIPTION: false
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### No Grouping for Clean Layout
|
||||
|
||||
```jsx
|
||||
// For a clean, simple layout without any organization headers
|
||||
<MasonryGallery
|
||||
glob="./portfolio/*.jpg"
|
||||
maxItems={10}
|
||||
maxWidth="320px"
|
||||
maxHeight="400px"
|
||||
gallerySettings={{
|
||||
SHOW_TITLE: true,
|
||||
SHOW_DESCRIPTION: false
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### Manual Images with Glob
|
||||
|
||||
```jsx
|
||||
// Combine manual images with auto-loaded ones
|
||||
const featuredImages = [
|
||||
{
|
||||
src: "./featured/hero.jpg",
|
||||
alt: "Hero image",
|
||||
title: "Featured Photo",
|
||||
description: "Our most popular image"
|
||||
}
|
||||
];
|
||||
|
||||
<MasonryGallery
|
||||
images={featuredImages}
|
||||
glob="./gallery/*.jpg"
|
||||
maxItems={10}
|
||||
maxWidth="350px"
|
||||
maxHeight="500px"
|
||||
/>
|
||||
```
|
||||
|
||||
## Grouping Options
|
||||
|
||||
The `groupBy` prop provides flexible ways to organize your images:
|
||||
|
||||
### Predefined Grouping Functions
|
||||
|
||||
- **`null` (default)**: No grouping - displays images in a simple masonry layout
|
||||
- **`"groupByYear"`**: Groups images by year based on EXIF date or file modification time
|
||||
- **`"groupByMonth"`**: Groups images by month and year (e.g., "January 2024", "February 2024")
|
||||
|
||||
### Custom Grouping Functions
|
||||
|
||||
You can also provide a custom function that takes an image and returns a `GroupInfo` object:
|
||||
|
||||
```jsx
|
||||
const customGroupFunction = (image) => ({
|
||||
key: 'unique-group-key', // Used for internal grouping
|
||||
label: 'Display Label', // Shown as the group header
|
||||
sortOrder: 123 // Numeric value for sorting (higher = shown first)
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Props
|
||||
|
||||
```typescript
|
||||
type GroupByFunction = (image: Image) => GroupInfo;
|
||||
|
||||
interface Props {
|
||||
images?: Image[]; // Manual image array
|
||||
glob?: string; // Glob pattern for auto-loading
|
||||
maxItems?: number; // Maximum number of images (default: 50)
|
||||
maxWidth?: string; // Max width per image (default: "300px")
|
||||
maxHeight?: string; // Max height per image (default: "400px")
|
||||
entryPath?: string; // Content entry path for resolving relative images
|
||||
groupBy?: GroupByFunction | 'groupByYear' | 'groupByMonth' | null; // Grouping strategy (default: null = no grouping)
|
||||
gallerySettings?: {
|
||||
SIZES_REGULAR?: string; // Responsive sizes for main images
|
||||
SIZES_THUMB?: string; // Responsive sizes for thumbnails
|
||||
SIZES_LARGE?: string; // Responsive sizes for lightbox
|
||||
SHOW_TITLE?: boolean; // Show image titles
|
||||
SHOW_DESCRIPTION?: boolean; // Show image descriptions
|
||||
};
|
||||
lightboxSettings?: {
|
||||
SIZES_REGULAR?: string;
|
||||
SIZES_THUMB?: string;
|
||||
SIZES_LARGE?: string;
|
||||
SHOW_TITLE?: boolean;
|
||||
SHOW_DESCRIPTION?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface GroupInfo {
|
||||
key: string; // Unique identifier for the group
|
||||
label: string; // Display label for the group
|
||||
sortOrder: number; // Numeric value for sorting groups
|
||||
}
|
||||
```
|
||||
|
||||
### Image Interface
|
||||
|
||||
```typescript
|
||||
interface Image {
|
||||
src: string; // Image source URL
|
||||
alt: string; // Alt text for accessibility
|
||||
title?: string; // Optional title
|
||||
description?: string; // Optional description
|
||||
}
|
||||
```
|
||||
|
||||
## Metadata Support
|
||||
|
||||
Enhance your images with companion metadata files:
|
||||
|
||||
### JSON Metadata (`image.json`)
|
||||
|
||||
```json
|
||||
{
|
||||
"alt": "Beautiful mountain landscape at sunset",
|
||||
"title": "Mountain Sunset",
|
||||
"description": "A breathtaking view of mountains during golden hour"
|
||||
}
|
||||
```
|
||||
|
||||
### Markdown Metadata (`image.md`)
|
||||
|
||||
```markdown
|
||||
A detailed description of the image that can include **markdown formatting**.
|
||||
|
||||
This will be used as the description if no JSON description is provided.
|
||||
```
|
||||
|
||||
## Responsive Behavior
|
||||
|
||||
The MasonryGallery automatically adapts to different screen sizes:
|
||||
|
||||
- **Desktop (1024px+)**: Minimum 250px columns with auto-fill
|
||||
- **Tablet (768px-1023px)**: Minimum 200px columns
|
||||
- **Mobile (480px-767px)**: Minimum 150px columns
|
||||
- **Small Mobile (<480px)**: Single column layout
|
||||
|
||||
## Interactive Controls
|
||||
|
||||
### Keyboard Navigation (Lightbox)
|
||||
|
||||
- **Escape**: Close lightbox
|
||||
- **Arrow Left**: Previous image
|
||||
- **Arrow Right**: Next image
|
||||
|
||||
### Touch Controls (Lightbox)
|
||||
|
||||
- **Swipe Left**: Next image
|
||||
- **Swipe Right**: Previous image
|
||||
- **Tap**: Close lightbox (outside image)
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Performance Optimization
|
||||
|
||||
```jsx
|
||||
// Use appropriate sizing for your use case
|
||||
<MasonryGallery
|
||||
glob="./thumbnails/*.jpg"
|
||||
maxItems={10} // Limit items for performance
|
||||
maxWidth="250px" // Smaller for faster loading
|
||||
maxHeight="300px"
|
||||
gallerySettings={{
|
||||
SIZES_REGULAR: "(max-width: 640px) 250px, (max-width: 1024px) 300px, 350px"
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### Accessibility
|
||||
|
||||
```jsx
|
||||
// Always provide meaningful alt text
|
||||
const images = [
|
||||
{
|
||||
src: "./photo.jpg",
|
||||
alt: "Person hiking on mountain trail during sunrise",
|
||||
title: "Morning Hike"
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
### Content Organization
|
||||
|
||||
```jsx
|
||||
// Organize images in logical directories
|
||||
<MasonryGallery glob="./projects/web-design/*.jpg" /> // Web projects
|
||||
<MasonryGallery glob="./projects/photography/*.jpg" /> // Photography
|
||||
<MasonryGallery glob="./projects/illustrations/*.jpg" /> // Illustrations
|
||||
```
|
||||
|
||||
### Loading Strategy
|
||||
|
||||
```jsx
|
||||
// For above-the-fold galleries, consider smaller maxItems
|
||||
<MasonryGallery
|
||||
glob="./hero-gallery/*.jpg"
|
||||
maxItems={10} // Load fewer images initially
|
||||
maxWidth="400px"
|
||||
maxHeight="500px"
|
||||
/>
|
||||
```
|
||||
|
||||
## CSS Classes
|
||||
|
||||
The component uses these CSS classes for styling customization:
|
||||
|
||||
- `.masonry-gallery`: Main container
|
||||
- `.masonry-container`: Grid container
|
||||
- `.masonry-item`: Individual image container
|
||||
- `.line-clamp-2`: Text truncation utility
|
||||
|
||||
## Browser Support
|
||||
|
||||
- **Modern browsers**: Full CSS Grid masonry support
|
||||
- **Fallback**: Graceful degradation for older browsers
|
||||
- **Progressive enhancement**: Touch and swipe support where available
|
||||
- **Accessibility**: Full ARIA support and keyboard navigation
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Images Not Loading
|
||||
|
||||
1. Check that your glob pattern matches actual files
|
||||
2. Ensure images are in the correct directory relative to the MDX file
|
||||
3. Verify file extensions match your glob pattern
|
||||
|
||||
### Performance Issues
|
||||
|
||||
1. Reduce `maxItems` for better initial load times
|
||||
2. Use appropriate `maxWidth` and `maxHeight` values
|
||||
3. Consider using smaller image formats (WebP, AVIF)
|
||||
|
||||
### Layout Issues
|
||||
|
||||
1. Ensure your images have reasonable aspect ratios
|
||||
2. Check that `maxWidth` and `maxHeight` values work well together
|
||||
3. Test on different screen sizes for responsive behavior
|
||||
148
src/content/resources/astro-development.mdx
Normal file
@ -0,0 +1,148 @@
|
||||
---
|
||||
pubDate: 2024-12-18
|
||||
title: Building Modern Websites with Astro
|
||||
author: Jane Developer
|
||||
description: "Learn how to create fast, content-focused websites using Astro's innovative approach to web development."
|
||||
url_0: "https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=800&h=400&fit=crop"
|
||||
image:
|
||||
url: "https://fastly.picsum.photos/id/972/200/300.jpg?hmac=UMf5f6BV9GkLiz0Xz9kMwm1riiTtlpIG2jt0WrxZ51Q?grayscale"
|
||||
alt: "Astro development workspace"
|
||||
tags: ["astro", "javascript", "ssr", "web-development"]
|
||||
---
|
||||
|
||||
import { Code } from 'astro:components';
|
||||
|
||||
# Building Modern Websites with Astro
|
||||
|
||||
Astro is revolutionizing how we build websites by combining the best of static site generation with modern web development practices. Let's explore what makes Astro special and how you can leverage it for your next project.
|
||||
|
||||
## What Makes Astro Different?
|
||||
|
||||
### Zero JS by Default
|
||||
Astro ships **zero JavaScript** to the browser by default. Components are rendered to HTML at build time, resulting in incredibly fast loading pages.
|
||||
|
||||
```astro
|
||||
---
|
||||
// This JavaScript runs at build time
|
||||
const greeting = "Hello, Astro!"
|
||||
const items = ['Fast', 'Flexible', 'Developer-friendly']
|
||||
---
|
||||
|
||||
<h1>{greeting}</h1>
|
||||
<ul>
|
||||
{items.map(item => <li>{item}</li>)}
|
||||
</ul>
|
||||
```
|
||||
|
||||
### Component Islands
|
||||
When you do need interactivity, Astro's "Islands Architecture" lets you selectively hydrate components:
|
||||
|
||||
<Code code={`---
|
||||
// ButtonCounter.tsx (React component)
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function ButtonCounter() {
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
return (
|
||||
<button onClick={() => setCount(count + 1)}>
|
||||
Count: {count}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
---
|
||||
|
||||
<!-- In your .astro file -->
|
||||
<ButtonCounter client:load />
|
||||
`} lang="astro" title="Interactive Component" />
|
||||
|
||||
## Key Features
|
||||
|
||||
### 🚀 Performance First
|
||||
- **Partial Hydration**: Only interactive components load JavaScript
|
||||
- **Optimized Builds**: Tree-shaking, bundling, and minification out of the box
|
||||
- **Image Optimization**: Built-in image processing and optimization
|
||||
|
||||
### 🧩 Framework Agnostic
|
||||
Use your favorite framework - or mix and match:
|
||||
|
||||
```astro
|
||||
---
|
||||
import ReactComponent from './ReactComponent.tsx';
|
||||
import VueComponent from './VueComponent.vue';
|
||||
import SvelteComponent from './SvelteComponent.svelte';
|
||||
---
|
||||
|
||||
<div>
|
||||
<ReactComponent client:visible />
|
||||
<VueComponent client:idle />
|
||||
<SvelteComponent client:media="(max-width: 768px)" />
|
||||
</div>
|
||||
```
|
||||
|
||||
### 📝 Content Collections
|
||||
Organize your content with type-safe collections:
|
||||
|
||||
```typescript
|
||||
// content.config.ts
|
||||
import { defineCollection, z } from 'astro:content';
|
||||
|
||||
const blog = defineCollection({
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
pubDate: z.date(),
|
||||
author: z.string(),
|
||||
tags: z.array(z.string()),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = { blog };
|
||||
```
|
||||
|
||||
## Advanced Patterns
|
||||
|
||||
### Dynamic Routing
|
||||
Create dynamic pages with ease:
|
||||
|
||||
```astro
|
||||
---
|
||||
// pages/blog/[...slug].astro
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection('blog');
|
||||
return posts.map(post => ({
|
||||
params: { slug: post.slug },
|
||||
props: { post },
|
||||
}));
|
||||
}
|
||||
---
|
||||
```
|
||||
|
||||
### API Routes
|
||||
Build full-stack applications:
|
||||
|
||||
```typescript
|
||||
// pages/api/posts.ts
|
||||
export async function GET() {
|
||||
const posts = await getCollection('blog');
|
||||
return new Response(JSON.stringify(posts), {
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Start Static**: Begin with static content and add interactivity where needed
|
||||
2. **Use Content Collections**: Organize your content with schemas for type safety
|
||||
3. **Optimize Images**: Leverage Astro's built-in image optimization
|
||||
4. **Progressive Enhancement**: Add JavaScript only when necessary
|
||||
|
||||
## Conclusion
|
||||
|
||||
Astro represents a paradigm shift towards **content-first web development**. By shipping less JavaScript and focusing on performance, it enables developers to create fast, accessible websites without sacrificing developer experience.
|
||||
|
||||
Whether you're building a blog, documentation site, or e-commerce platform, Astro provides the tools and performance you need to succeed in the modern web landscape.
|
||||
|
||||
---
|
||||
|
||||
**Ready to get started?** Check out the [official Astro documentation](https://docs.astro.build) and start building today!
|
||||
468
src/content/resources/collections.mdx
Normal file
@ -0,0 +1,468 @@
|
||||
---
|
||||
title: "Collection Filter System"
|
||||
description: "Complete guide to the generic collection filtering system for Astro content collections"
|
||||
author: "Polymech Team"
|
||||
pubDate: 2024-01-15
|
||||
tags: ["internal", "documentation", "astro", "collections", "filters"]
|
||||
---
|
||||
|
||||
# Collection Filter System
|
||||
|
||||
This document describes the generic collection filtering system implemented for Astro content collections. The system provides a unified way to filter collection entries across the application, ensuring consistency between pages and sidebar generation.
|
||||
|
||||
## Overview
|
||||
|
||||
The collection filter system replaces manual filtering in `getStaticPaths` functions with a configurable, reusable approach. It automatically excludes invalid entries like those with "Untitled" titles, draft content, folders, and other unwanted items.
|
||||
|
||||
## Core Components
|
||||
|
||||
### 1. Filter Functions (`polymech/src/base/collections.ts`)
|
||||
|
||||
#### Basic Filters
|
||||
|
||||
```typescript
|
||||
// Default filters applied automatically
|
||||
export const hasValidFrontMatter: CollectionFilter
|
||||
export const isNotFolder: CollectionFilter
|
||||
export const isNotDraft: CollectionFilter
|
||||
export const hasTitle: CollectionFilter // Excludes "Untitled" entries
|
||||
|
||||
// Content validation filters
|
||||
export const hasBody: CollectionFilter
|
||||
export const hasDescription: CollectionFilter
|
||||
export const hasImage: CollectionFilter
|
||||
export const hasAuthor: CollectionFilter // Excludes "Unknown" authors
|
||||
export const hasPubDate: CollectionFilter
|
||||
export const hasTags: CollectionFilter
|
||||
export const hasValidFileExtension: CollectionFilter // .md/.mdx only
|
||||
```
|
||||
|
||||
#### Advanced Filters
|
||||
|
||||
```typescript
|
||||
// Date-based filtering
|
||||
export const isNotFuture: CollectionFilter
|
||||
export const createDateFilter(beforeDate?: Date, afterDate?: Date): CollectionFilter
|
||||
export const createOldPostFilter(cutoffDays: number): CollectionFilter
|
||||
|
||||
// Tag-based filtering
|
||||
export const createTagFilter(requiredTags: string[], matchAll?: boolean): CollectionFilter
|
||||
export const createExcludeTagsFilter(excludeTags: string[]): CollectionFilter
|
||||
|
||||
// Field validation
|
||||
export const createRequiredFieldsFilter(requiredFields: string[]): CollectionFilter
|
||||
export const createFrontmatterValidator(validator: (data: any) => boolean): CollectionFilter
|
||||
```
|
||||
|
||||
### 2. Main Filter Functions
|
||||
|
||||
```typescript
|
||||
// Apply filters to a collection
|
||||
export function filterCollection<T>(
|
||||
collection: CollectionEntry<T>[],
|
||||
filters: CollectionFilter<T>[] = defaultFilters,
|
||||
astroConfig?: any
|
||||
): CollectionEntry<T>[]
|
||||
|
||||
// Apply filters based on configuration
|
||||
export function filterCollectionWithConfig<T>(
|
||||
collection: CollectionEntry<T>[],
|
||||
config: CollectionFilterConfig,
|
||||
astroConfig?: any
|
||||
): CollectionEntry<T>[]
|
||||
```
|
||||
|
||||
### 3. Central Configuration (`site2/src/app/config.ts`)
|
||||
|
||||
The collection filter system is centrally configured in `site2/src/app/config.ts`. This is the main configuration file where you control all filtering behavior across your application.
|
||||
|
||||
**Key Configuration Location: `site2/src/app/config.ts`**
|
||||
|
||||
```typescript
|
||||
/////////////////////////////////////////////
|
||||
//
|
||||
// Collection Filters
|
||||
|
||||
// Collection filter configuration
|
||||
export const COLLECTION_FILTERS = {
|
||||
// Core filters (enabled by default)
|
||||
ENABLE_VALID_FRONTMATTER_CHECK: true,
|
||||
ENABLE_FOLDER_FILTER: true,
|
||||
ENABLE_DRAFT_FILTER: true,
|
||||
ENABLE_TITLE_FILTER: true, // Filters out "Untitled" entries
|
||||
|
||||
// Content validation filters (disabled by default)
|
||||
ENABLE_BODY_FILTER: false, // Require entries to have body content
|
||||
ENABLE_DESCRIPTION_FILTER: false, // Require entries to have descriptions
|
||||
ENABLE_IMAGE_FILTER: false, // Require entries to have images
|
||||
ENABLE_AUTHOR_FILTER: false, // Require entries to have real authors (not "Unknown")
|
||||
ENABLE_PUBDATE_FILTER: false, // Require entries to have valid publication dates
|
||||
ENABLE_TAGS_FILTER: false, // Require entries to have tags
|
||||
ENABLE_FILE_EXTENSION_FILTER: true, // Require valid .md/.mdx extensions
|
||||
|
||||
// Advanced filtering
|
||||
REQUIRED_FIELDS: [], // Array of required frontmatter fields
|
||||
REQUIRED_TAGS: [], // Array of required tags
|
||||
EXCLUDE_TAGS: [], // Array of tags to exclude
|
||||
|
||||
// Date filtering
|
||||
FILTER_FUTURE_POSTS: false, // Filter out posts with future publication dates
|
||||
FILTER_OLD_POSTS: false, // Filter out posts older than a certain date
|
||||
OLD_POST_CUTOFF_DAYS: 365, // Days to consider a post "old"
|
||||
}
|
||||
```
|
||||
|
||||
**Why config.ts?**
|
||||
- **Centralized Control**: All filter settings in one place
|
||||
- **Environment Consistency**: Same filtering rules across all pages and sidebar
|
||||
- **Easy Maintenance**: Change behavior without touching individual page files
|
||||
- **Type Safety**: Imported with full TypeScript support
|
||||
|
||||
## Configuring Filters in config.ts
|
||||
|
||||
### Modifying Collection Filters
|
||||
|
||||
To change filtering behavior across your entire application, edit the `COLLECTION_FILTERS` object in `site2/src/app/config.ts`:
|
||||
|
||||
```typescript
|
||||
// site2/src/app/config.ts
|
||||
|
||||
// Example: Enable stricter content validation
|
||||
export const COLLECTION_FILTERS = {
|
||||
// Core filters (keep these enabled)
|
||||
ENABLE_VALID_FRONTMATTER_CHECK: true,
|
||||
ENABLE_FOLDER_FILTER: true,
|
||||
ENABLE_DRAFT_FILTER: true,
|
||||
ENABLE_TITLE_FILTER: true,
|
||||
|
||||
// Enable content validation
|
||||
ENABLE_BODY_FILTER: true, // Require body content
|
||||
ENABLE_DESCRIPTION_FILTER: true, // Require descriptions
|
||||
ENABLE_AUTHOR_FILTER: true, // Require real authors
|
||||
ENABLE_TAGS_FILTER: true, // Require tags
|
||||
|
||||
// Require specific fields
|
||||
REQUIRED_FIELDS: ['title', 'description', 'pubDate'],
|
||||
|
||||
// Exclude test content
|
||||
EXCLUDE_TAGS: ['draft', 'test', 'internal'],
|
||||
|
||||
// Filter future posts in production
|
||||
FILTER_FUTURE_POSTS: true,
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Import
|
||||
|
||||
The configuration is imported in pages and components like this:
|
||||
|
||||
```typescript
|
||||
import { COLLECTION_FILTERS } from "config/config.js"
|
||||
import { filterCollectionWithConfig } from '@polymech/astro-base/base/collections';
|
||||
|
||||
// Apply the configured filters
|
||||
const entries = filterCollectionWithConfig(allEntries, COLLECTION_FILTERS);
|
||||
```
|
||||
|
||||
**Note**: The import path `"config/config.js"` refers to `site2/src/app/config.ts` due to Astro's import resolution.
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### 1. Basic Usage in Pages
|
||||
|
||||
Replace manual filtering in `getStaticPaths`:
|
||||
|
||||
```typescript
|
||||
// Before
|
||||
export async function getStaticPaths() {
|
||||
const resourceEntries = (await getCollection("resources")).filter(entry => {
|
||||
const entryPath = `src/content/resources/${entry.id}`;
|
||||
return !isFolder(entryPath);
|
||||
});
|
||||
}
|
||||
|
||||
// After
|
||||
import { filterCollectionWithConfig } from '@polymech/astro-base/base/collections';
|
||||
import { COLLECTION_FILTERS } from 'config/config.js';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const allResourceEntries = await getCollection("resources");
|
||||
const resourceEntries = filterCollectionWithConfig(allResourceEntries, COLLECTION_FILTERS);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Custom Filtering
|
||||
|
||||
```typescript
|
||||
import { filterCollection, hasTitle, isNotDraft, createTagFilter } from '@polymech/astro-base/base/collections';
|
||||
|
||||
// Custom filter combination
|
||||
const customFilters = [
|
||||
hasTitle,
|
||||
isNotDraft,
|
||||
createTagFilter(['published'], true), // Must have 'published' tag
|
||||
];
|
||||
|
||||
const filteredEntries = filterCollection(allEntries, customFilters);
|
||||
```
|
||||
|
||||
### 3. Configuration-Based Filtering
|
||||
|
||||
```typescript
|
||||
// Enable stricter content validation
|
||||
const strictConfig = {
|
||||
...COLLECTION_FILTERS,
|
||||
ENABLE_DESCRIPTION_FILTER: true,
|
||||
ENABLE_AUTHOR_FILTER: true,
|
||||
ENABLE_TAGS_FILTER: true,
|
||||
REQUIRED_FIELDS: ['title', 'description', 'pubDate'],
|
||||
EXCLUDE_TAGS: ['draft', 'internal', 'test']
|
||||
};
|
||||
|
||||
const entries = filterCollectionWithConfig(allEntries, strictConfig);
|
||||
```
|
||||
|
||||
### 4. Sidebar Integration
|
||||
|
||||
The sidebar automatically uses the filter system:
|
||||
|
||||
```typescript
|
||||
// Sidebar configuration in polymech/src/config/sidebar.ts
|
||||
export const sidebarConfig: SidebarGroup[] = [
|
||||
{
|
||||
label: 'Resources',
|
||||
autogenerate: {
|
||||
directory: 'resources',
|
||||
collapsed: true,
|
||||
sortBy: 'alphabetical'
|
||||
},
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
#### Advanced Sidebar Options
|
||||
|
||||
```typescript
|
||||
import { generateLinksFromDirectoryWithConfig, createSidebarOptions } from '@polymech/astro-base/components/sidebar/utils';
|
||||
|
||||
// Using the new options object API
|
||||
const links = await generateLinksFromDirectoryWithConfig('resources', {
|
||||
maxDepth: 3,
|
||||
collapsedByDefault: true,
|
||||
sortBy: 'date',
|
||||
filters: [hasTitle, isNotDraft, hasDescription]
|
||||
});
|
||||
|
||||
// Using the helper function
|
||||
const options = createSidebarOptions({
|
||||
maxDepth: 4,
|
||||
sortBy: 'custom',
|
||||
customSort: (a, b) => a.label.localeCompare(b.label),
|
||||
filters: customFilters
|
||||
});
|
||||
|
||||
const links = await generateLinksFromDirectoryWithConfig('resources', options);
|
||||
```
|
||||
|
||||
## Filter Details
|
||||
|
||||
### Default Filters
|
||||
|
||||
These filters are applied automatically unless disabled:
|
||||
|
||||
1. **`hasValidFrontMatter`** - Ensures entries have valid frontmatter data
|
||||
2. **`isNotFolder`** - Excludes directory entries using `entry.filePath`
|
||||
3. **`isNotDraft`** - Excludes entries with `draft: true`
|
||||
4. **`hasTitle`** - Excludes entries with empty titles or "Untitled"
|
||||
|
||||
### Content Validation Filters
|
||||
|
||||
Enable these for stricter content requirements:
|
||||
|
||||
- **`hasBody`** - Requires non-empty body content
|
||||
- **`hasDescription`** - Requires non-empty descriptions
|
||||
- **`hasImage`** - Requires `image.url` in frontmatter
|
||||
- **`hasAuthor`** - Requires real authors (not "Unknown")
|
||||
- **`hasPubDate`** - Requires valid publication dates
|
||||
- **`hasTags`** - Requires non-empty tags array
|
||||
- **`hasValidFileExtension`** - Ensures `.md` or `.mdx` extensions
|
||||
|
||||
### Advanced Filtering
|
||||
|
||||
#### Date Filtering
|
||||
|
||||
```typescript
|
||||
// Filter future posts
|
||||
FILTER_FUTURE_POSTS: true
|
||||
|
||||
// Filter old posts
|
||||
FILTER_OLD_POSTS: true,
|
||||
OLD_POST_CUTOFF_DAYS: 365
|
||||
|
||||
// Custom date ranges
|
||||
const recentFilter = createDateFilter(
|
||||
new Date('2024-12-31'), // Before this date
|
||||
new Date('2024-01-01') // After this date
|
||||
);
|
||||
```
|
||||
|
||||
#### Tag Filtering
|
||||
|
||||
```typescript
|
||||
// Require specific tags (all must be present)
|
||||
REQUIRED_TAGS: ['published', 'reviewed']
|
||||
|
||||
// Exclude specific tags
|
||||
EXCLUDE_TAGS: ['draft', 'internal', 'test']
|
||||
|
||||
// Custom tag filtering
|
||||
const tutorialFilter = createTagFilter(['tutorial', 'guide'], false); // At least one
|
||||
const excludeTestFilter = createExcludeTagsFilter(['test', 'draft']);
|
||||
```
|
||||
|
||||
#### Field Validation
|
||||
|
||||
```typescript
|
||||
// Require specific frontmatter fields
|
||||
REQUIRED_FIELDS: ['title', 'description', 'pubDate', 'author']
|
||||
|
||||
// Custom field validation
|
||||
const customValidator = createFrontmatterValidator((data) => {
|
||||
return data.title &&
|
||||
data.description &&
|
||||
data.description.length > 50 && // Min description length
|
||||
Array.isArray(data.tags) &&
|
||||
data.tags.length > 0;
|
||||
});
|
||||
```
|
||||
|
||||
## Frontmatter Validation
|
||||
|
||||
The system includes advanced frontmatter validation using Astro's `parseFrontmatter`:
|
||||
|
||||
```typescript
|
||||
import { parseFrontmatter } from '@astrojs/markdown-remark';
|
||||
|
||||
// Advanced validation for raw markdown content
|
||||
const rawValidator = createRawFrontmatterValidator(
|
||||
(entry) => fs.readFileSync(entry.filePath, 'utf-8'),
|
||||
(frontmatter) => frontmatter.published === true
|
||||
);
|
||||
|
||||
// File-based validation using entry.filePath
|
||||
const fileValidator = createFileBasedFrontmatterValidator(
|
||||
(data) => data.status === 'published'
|
||||
);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
The filter system includes comprehensive error handling:
|
||||
|
||||
```typescript
|
||||
// Individual filter errors are logged but don't break the entire filtering
|
||||
try {
|
||||
return filter(entry, astroConfig);
|
||||
} catch (error) {
|
||||
console.warn(`Filter failed for entry ${entry.id}:`, error);
|
||||
return false; // Exclude entry on filter error
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- **Caching**: Collection entries are cached by Astro in production
|
||||
- **Early Filtering**: Apply filters as early as possible in `getStaticPaths`
|
||||
- **Filter Order**: More selective filters should come first
|
||||
- **Lazy Evaluation**: Filters use short-circuit evaluation
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### From Manual Filtering
|
||||
|
||||
```typescript
|
||||
// Old approach
|
||||
const entries = (await getCollection("resources")).filter(entry => {
|
||||
const entryPath = `src/content/resources/${entry.id}`;
|
||||
return !isFolder(entryPath) && !entry.data?.draft && entry.data?.title !== 'Untitled';
|
||||
});
|
||||
|
||||
// New approach
|
||||
const entries = filterCollectionWithConfig(
|
||||
await getCollection("resources"),
|
||||
COLLECTION_FILTERS
|
||||
);
|
||||
```
|
||||
|
||||
### Sidebar Updates
|
||||
|
||||
The sidebar automatically uses the new filter system. No migration needed for basic usage.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use Configuration**: Prefer `COLLECTION_FILTERS` over custom filter arrays
|
||||
2. **Test Thoroughly**: Verify filtering works across all content types
|
||||
3. **Document Custom Filters**: Add JSDoc comments to custom filter functions
|
||||
4. **Handle Errors**: Always wrap filter logic in try-catch blocks
|
||||
5. **Performance**: Use selective filters first to reduce processing
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Entries Still Showing in Sidebar**
|
||||
- Ensure sidebar is using the updated `generateLinksFromDirectoryWithConfig`
|
||||
- Check that filters are properly imported and configured
|
||||
|
||||
**Filter Not Working**
|
||||
- Verify the filter function returns a boolean
|
||||
- Check that the entry structure matches expected format
|
||||
- Look for console warnings about filter failures
|
||||
|
||||
**Type Errors**
|
||||
- Ensure proper imports from `@polymech/astro-base/base/collections`
|
||||
- Check that custom filters match the `CollectionFilter<T>` type
|
||||
|
||||
### Debugging
|
||||
|
||||
Enable debug logging by adding console logs to custom filters:
|
||||
|
||||
```typescript
|
||||
const debugFilter: CollectionFilter = (entry) => {
|
||||
const result = hasTitle(entry);
|
||||
console.log(`Filter result for ${entry.id}:`, result, entry.data?.title);
|
||||
return result;
|
||||
};
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Types
|
||||
|
||||
```typescript
|
||||
export type CollectionFilter<T = any> = (entry: CollectionEntry<T>, astroConfig?: any) => boolean;
|
||||
|
||||
export interface CollectionFilterConfig {
|
||||
ENABLE_VALID_FRONTMATTER_CHECK?: boolean;
|
||||
ENABLE_FOLDER_FILTER?: boolean;
|
||||
ENABLE_DRAFT_FILTER?: boolean;
|
||||
ENABLE_TITLE_FILTER?: boolean;
|
||||
// ... additional options
|
||||
}
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
```typescript
|
||||
export function filterCollection<T>(collection, filters?, astroConfig?): CollectionEntry<T>[]
|
||||
export function filterCollectionWithConfig<T>(collection, config, astroConfig?): CollectionEntry<T>[]
|
||||
export function buildFiltersFromConfig<T>(config): CollectionFilter<T>[]
|
||||
export function combineFilters<T>(baseFilters?, additionalFilters?): CollectionFilter<T>[]
|
||||
```
|
||||
|
||||
## Examples Repository
|
||||
|
||||
For more examples and use cases, see:
|
||||
- `site2/src/pages/[locale]/resources/[...slug].astro`
|
||||
- `site2/src/pages/resources/[...slug].astro`
|
||||
- `polymech/src/components/sidebar/utils.ts`
|
||||
BIN
src/content/resources/gallery/DSC03470.jpg
Normal file
|
After Width: | Height: | Size: 322 KiB |
2
src/content/resources/gallery/DSC03470.md
Normal file
@ -0,0 +1,2 @@
|
||||
boops
|
||||
|
||||
BIN
src/content/resources/gallery/DSC03481.jpg
Normal file
|
After Width: | Height: | Size: 347 KiB |
BIN
src/content/resources/gallery/DSC03770.jpg
Normal file
|
After Width: | Height: | Size: 332 KiB |
BIN
src/content/resources/gallery/DSC03876.jpg
Normal file
|
After Width: | Height: | Size: 377 KiB |
BIN
src/content/resources/gallery/DSC04389.jpg
Normal file
|
After Width: | Height: | Size: 320 KiB |
BIN
src/content/resources/gallery/DSC04648.jpg
Normal file
|
After Width: | Height: | Size: 332 KiB |
BIN
src/content/resources/gallery/DSC04700.jpg
Normal file
|
After Width: | Height: | Size: 320 KiB |
BIN
src/content/resources/gallery/DSC04881.jpg
Normal file
|
After Width: | Height: | Size: 480 KiB |
BIN
src/content/resources/gallery/DSC05173.jpg
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
src/content/resources/gallery/DSC05198.jpg
Normal file
|
After Width: | Height: | Size: 295 KiB |
BIN
src/content/resources/gallery/DSC05815.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
src/content/resources/gallery/IMG_20201219_172830_671.jpg
Normal file
|
After Width: | Height: | Size: 441 KiB |
4
src/content/resources/gallery/IMG_20201219_172830_671.md
Normal file
@ -0,0 +1,4 @@
|
||||
boops md
|
||||
|
||||
|
||||
|
||||
BIN
src/content/resources/gallery/IMG_20210224_110541_721.jpg
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
src/content/resources/gallery/IMG_20210224_110541_725.jpg
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
src/content/resources/gallery/IMG_20210611_185222_023.jpg
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
src/content/resources/gallery/IMG_20210611_185222_078.jpg
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
src/content/resources/gallery/IMG_20210711_210122_345.jpg
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
src/content/resources/gallery/IMG_20210711_210122_387.jpg
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
src/content/resources/gallery/IMG_20210731_003002_242.jpg
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
src/content/resources/gallery/edc-450-mould-45.jpg
Normal file
|
After Width: | Height: | Size: 116 KiB |
561
src/content/resources/sidebar.mdx
Normal file
@ -0,0 +1,561 @@
|
||||
---
|
||||
pubDate: 2024-12-19
|
||||
title: Sidebar Navigation System
|
||||
author: System Documentation
|
||||
description: "Complete guide to the custom sidebar navigation system with autogeneration, nested menus, page-level navigation, and hiding functionality."
|
||||
tags: ["documentation", "sidebar", "navigation", "astro"]
|
||||
sidebar:
|
||||
label: "Sidebar Guide"
|
||||
items:
|
||||
- label: "Quick Start"
|
||||
href: "#quick-start"
|
||||
- label: "Configuration"
|
||||
href: "#configuration"
|
||||
- label: "Features"
|
||||
href: "#features"
|
||||
- label: "Examples"
|
||||
href: "#examples"
|
||||
- label: "Troubleshooting"
|
||||
href: "#troubleshooting"
|
||||
---
|
||||
|
||||
# Sidebar Navigation System
|
||||
|
||||
A comprehensive, lightweight sidebar navigation system built for Astro with support for autogeneration from content collections, nested menus, page-level navigation, and visibility controls.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Basic Setup
|
||||
|
||||
The sidebar is automatically configured in `astro.config.mjs`:
|
||||
|
||||
```javascript
|
||||
export default defineConfig({
|
||||
// ... other config
|
||||
sidebar: [
|
||||
{
|
||||
label: 'Resources',
|
||||
autogenerate: { directory: 'resources' },
|
||||
}
|
||||
],
|
||||
// ... rest of config
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Using in Layouts
|
||||
|
||||
Apply the sidebar to any layout:
|
||||
|
||||
```astro
|
||||
---
|
||||
import Sidebar from '@/components/sidebar/Sidebar.astro';
|
||||
import { getSidebarConfig } from '@/config/sidebar';
|
||||
|
||||
const sidebarConfig = getSidebarConfig();
|
||||
const pageNavigation = frontmatter.sidebar ? [frontmatter.sidebar].flat() : [];
|
||||
---
|
||||
|
||||
<div class="layout-with-sidebar">
|
||||
<div class="sidebar-wrapper">
|
||||
<Sidebar
|
||||
config={sidebarConfig}
|
||||
currentUrl={Astro.url}
|
||||
headings={headings}
|
||||
pageNavigation={pageNavigation}
|
||||
/>
|
||||
</div>
|
||||
<main class="main-content-with-sidebar">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Global Sidebar Configuration
|
||||
|
||||
Configure the main navigation structure in `astro.config.mjs`:
|
||||
|
||||
```javascript
|
||||
sidebar: [
|
||||
// Manual navigation group
|
||||
{
|
||||
label: 'Guides',
|
||||
items: [
|
||||
{ label: 'Getting Started', slug: 'guides/getting-started' },
|
||||
{ label: 'Advanced Topics', slug: 'guides/advanced' },
|
||||
],
|
||||
},
|
||||
|
||||
// Autogenerated navigation group
|
||||
{
|
||||
label: 'Resources',
|
||||
autogenerate: {
|
||||
directory: 'resources',
|
||||
collapsed: false, // Subgroups open by default
|
||||
maxDepth: 2 // Maximum nesting levels
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
### Autogeneration Options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `directory` | `string` | - | Content collection directory to scan |
|
||||
| `collapsed` | `boolean` | `false` | Whether subgroups are collapsed by default |
|
||||
| `maxDepth` | `number` | `2` | Maximum nesting levels (1-2 supported) |
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Multilingual Support (i18n)
|
||||
|
||||
The sidebar now supports internationalization using the same i18n system as other components:
|
||||
|
||||
**Features:**
|
||||
- All sidebar labels are translatable
|
||||
- Uses the existing `Translate` component
|
||||
- Supports translation keys in configuration
|
||||
- Automatically adapts to current locale
|
||||
|
||||
**Usage:**
|
||||
```javascript
|
||||
// Configuration with i18n keys
|
||||
export const sidebarConfig = [
|
||||
{
|
||||
label: 'sidebar.guides', // Translation key instead of hardcoded text
|
||||
items: [
|
||||
{ label: 'sidebar.example-guide', slug: 'guides/example' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'sidebar.resources',
|
||||
autogenerate: { directory: 'resources' },
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
**Components automatically wrap labels with `<Translate>`:**
|
||||
- Group titles: `<Translate>{group.label}</Translate>`
|
||||
- Link labels: `<Translate>{item.label}</Translate>`
|
||||
- Table of Contents: `<Translate>{title}</Translate>`
|
||||
|
||||
**TOC Translation Examples:**
|
||||
```astro
|
||||
<!-- Using default translatable title -->
|
||||
<TableOfContentsWithScroll headings={headings} />
|
||||
|
||||
<!-- Using custom translation key -->
|
||||
<TableOfContentsWithScroll
|
||||
headings={headings}
|
||||
title="toc.custom-title"
|
||||
/>
|
||||
|
||||
<!-- Using hardcoded text (still works but not recommended) -->
|
||||
<TableOfContentsWithScroll
|
||||
headings={headings}
|
||||
title="Page Contents"
|
||||
/>
|
||||
```
|
||||
|
||||
### 2. Autogenerated Navigation
|
||||
|
||||
Automatically creates navigation from your content collections:
|
||||
|
||||
```
|
||||
src/content/resources/
|
||||
├── getting-started.md → /resources/getting-started/
|
||||
├── advanced/
|
||||
│ ├── deployment.md → /resources/advanced/deployment/
|
||||
│ └── optimization.md → /resources/advanced/optimization/
|
||||
└── tutorials/
|
||||
├── basic.mdx → /resources/tutorials/basic/
|
||||
└── advanced.mdx → /resources/tutorials/advanced/
|
||||
```
|
||||
|
||||
**Result in sidebar:**
|
||||
- Resources
|
||||
- Getting Started
|
||||
- Advanced (collapsible group)
|
||||
- Deployment
|
||||
- Optimization
|
||||
- Tutorials (collapsible group)
|
||||
- Basic
|
||||
- Advanced
|
||||
|
||||
### 2. Page-Level Navigation
|
||||
|
||||
Add custom navigation to specific pages via frontmatter:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: My Page
|
||||
sidebar:
|
||||
label: "Page Navigation"
|
||||
items:
|
||||
- label: "Quick Start"
|
||||
href: "#quick-start"
|
||||
- label: "Configuration"
|
||||
href: "#configuration"
|
||||
- label: "Examples"
|
||||
href: "#examples"
|
||||
---
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Appears first in the sidebar
|
||||
- Visually distinguished with blue styling
|
||||
- Perfect for page-specific jump links
|
||||
- Supports internal anchors and external URLs
|
||||
- Page-level labels are also translatable when using translation keys
|
||||
|
||||
### 3. Hide Pages from Navigation
|
||||
|
||||
Hide specific pages from autogenerated navigation:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Hidden Page
|
||||
sidebar:
|
||||
hide: true
|
||||
---
|
||||
```
|
||||
|
||||
**Use cases:**
|
||||
- Draft pages under development
|
||||
- Landing pages accessed via specific links
|
||||
- Admin or utility pages
|
||||
- Pages not ready for public navigation
|
||||
|
||||
### 4. Table of Contents (TOC)
|
||||
|
||||
Automatic TOC generation with scroll-based active highlighting:
|
||||
|
||||
**Features:**
|
||||
- Auto-generated from markdown headings
|
||||
- Scroll-based active state indication
|
||||
- Nested heading support
|
||||
- Sticky positioning
|
||||
- Mobile responsive
|
||||
- Fully translatable title using translation keys
|
||||
- Default title: `"toc.on-this-page"` (translatable)
|
||||
- Title wrapped with `<Translate>{title}</Translate>`
|
||||
|
||||
### 5. Nested Directory Support
|
||||
|
||||
Supports up to 2 levels of nesting:
|
||||
|
||||
```
|
||||
content/
|
||||
├── page1.md → Level 1 (root)
|
||||
└── category/
|
||||
├── page2.md → Level 2 (in collapsible group)
|
||||
└── subcategory/
|
||||
└── page3.md → Level 2 (flattened with category)
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- Maximum 2 levels supported for UI clarity
|
||||
- Subdirectories become collapsible groups
|
||||
- Files deeper than 2 levels are flattened to level 2
|
||||
- Directory names are automatically formatted and translatable
|
||||
|
||||
### 6. Responsive Design
|
||||
|
||||
**Desktop (768px+):**
|
||||
- Sticky positioning
|
||||
- 288px width (`w-72`)
|
||||
- Always visible
|
||||
|
||||
**Mobile:**
|
||||
- Slide-out overlay
|
||||
- Backdrop blur effect
|
||||
- Touch-friendly toggle button
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Autogenerated Section
|
||||
|
||||
```javascript
|
||||
// astro.config.mjs
|
||||
{
|
||||
label: 'Documentation',
|
||||
autogenerate: { directory: 'docs' }
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Collapsed Subgroups by Default
|
||||
|
||||
```javascript
|
||||
// astro.config.mjs
|
||||
{
|
||||
label: 'API Reference',
|
||||
autogenerate: {
|
||||
directory: 'api',
|
||||
collapsed: true,
|
||||
maxDepth: 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example 3: Mixed Manual and Auto Navigation
|
||||
|
||||
```javascript
|
||||
// astro.config.mjs
|
||||
sidebar: [
|
||||
// Manual section
|
||||
{
|
||||
label: 'Getting Started',
|
||||
items: [
|
||||
{ label: 'Installation', slug: 'install' },
|
||||
{ label: 'Quick Start', slug: 'quickstart' },
|
||||
]
|
||||
},
|
||||
// Auto section
|
||||
{
|
||||
label: 'Guides',
|
||||
autogenerate: { directory: 'guides' }
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Example 4: Page with Custom Navigation
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Complete Tutorial
|
||||
description: Step-by-step guide
|
||||
sidebar:
|
||||
label: "Tutorial Steps"
|
||||
items:
|
||||
- label: "1. Setup"
|
||||
href: "#setup"
|
||||
- label: "2. Configuration"
|
||||
href: "#configuration"
|
||||
- label: "3. Deployment"
|
||||
href: "#deployment"
|
||||
- label: "4. Troubleshooting"
|
||||
href: "#troubleshooting"
|
||||
---
|
||||
|
||||
# Complete Tutorial
|
||||
|
||||
Your tutorial content here...
|
||||
```
|
||||
|
||||
### Example 5: Hidden Development Page
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Work in Progress
|
||||
description: This page is still being written
|
||||
sidebar:
|
||||
hide: true
|
||||
---
|
||||
|
||||
# Work in Progress
|
||||
|
||||
This page won't appear in navigation but is accessible via direct URL.
|
||||
```
|
||||
|
||||
## File Naming and URL Generation
|
||||
|
||||
### Clean URLs
|
||||
|
||||
The system automatically generates clean URLs:
|
||||
|
||||
| File | Generated URL |
|
||||
|------|---------------|
|
||||
| `getting-started.md` | `/resources/getting-started/` |
|
||||
| `api/endpoints.mdx` | `/resources/api/endpoints/` |
|
||||
| `tutorials/basic.md` | `/resources/tutorials/basic/` |
|
||||
|
||||
### Label Generation Priority
|
||||
|
||||
For link labels, the system checks (in order):
|
||||
|
||||
1. `frontmatter.title`
|
||||
2. `frontmatter.page`
|
||||
3. `frontmatter.name`
|
||||
4. Filename (as fallback)
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "This Will Be Used" # ← Highest priority
|
||||
page: "This Is Ignored"
|
||||
name: "This Is Also Ignored"
|
||||
---
|
||||
```
|
||||
|
||||
## Styling and Theming
|
||||
|
||||
### Light Theme Design
|
||||
|
||||
The sidebar uses a light theme optimized for readability:
|
||||
|
||||
**Colors:**
|
||||
- Background: `bg-gray-50`
|
||||
- Borders: `border-gray-200`
|
||||
- Text: `text-gray-800`
|
||||
- Active links: `text-blue-700` with `bg-blue-50`
|
||||
- Hover states: `hover:bg-gray-100`
|
||||
|
||||
### Page-Level Navigation Styling
|
||||
|
||||
Page-level navigation has distinct styling:
|
||||
|
||||
```css
|
||||
.page-level {
|
||||
border-bottom: 2px solid #e5e7eb;
|
||||
padding-bottom: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.page-level .sidebar-link {
|
||||
color: #1e40af;
|
||||
font-weight: 500;
|
||||
background-color: #f0f9ff;
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
```
|
||||
|
||||
### Customization
|
||||
|
||||
All styles are in `src/styles/global.css` under the `@layer components` section. Key classes:
|
||||
|
||||
- `.sidebar-wrapper` - Main container
|
||||
- `.sidebar-nav` - Navigation wrapper
|
||||
- `.sidebar-group` - Group containers
|
||||
- `.sidebar-link` - Individual links
|
||||
- `.sidebar-link.current` - Active page styling
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**1. Pages not appearing in sidebar**
|
||||
- Check if the content collection exists
|
||||
- Verify the directory name matches the config
|
||||
- Ensure frontmatter doesn't have `sidebar.hide: true`
|
||||
|
||||
**2. URLs not working**
|
||||
- Verify the content collection is properly configured in `src/content/config.ts`
|
||||
- Check that the dynamic route file exists (e.g., `[...slug].astro`)
|
||||
- Ensure clean URLs are being generated correctly
|
||||
|
||||
**3. Sidebar not showing**
|
||||
- Check that the layout includes the sidebar components
|
||||
- Verify the `getSidebarConfig()` function is imported
|
||||
- Ensure proper CSS classes are applied
|
||||
|
||||
**4. Mobile sidebar not working**
|
||||
- Check that `MobileToggle` component is included
|
||||
- Verify JavaScript for mobile toggle is working
|
||||
- Ensure proper z-index stacking
|
||||
|
||||
**5. TOC not highlighting correctly**
|
||||
- Verify headings have proper `id` attributes
|
||||
- Check that the `IntersectionObserver` script is loaded
|
||||
- Ensure headings are being passed to the component
|
||||
|
||||
### Debug Tips
|
||||
|
||||
**1. Check console for errors:**
|
||||
```javascript
|
||||
// Browser dev tools console
|
||||
console.log('Sidebar config:', sidebarConfig);
|
||||
```
|
||||
|
||||
**2. Verify content collection:**
|
||||
```javascript
|
||||
// In Astro component
|
||||
const entries = await getCollection('resources');
|
||||
console.log('Found entries:', entries.length);
|
||||
```
|
||||
|
||||
**3. Check CSS loading:**
|
||||
```css
|
||||
/* Add temporary styles to verify CSS is loading */
|
||||
.sidebar-wrapper {
|
||||
border: 2px solid red !important;
|
||||
}
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### File Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── components/sidebar/
|
||||
│ ├── Sidebar.astro # Main sidebar component
|
||||
│ ├── SidebarGroup.astro # Group/section component
|
||||
│ ├── MobileToggle.astro # Mobile hamburger menu
|
||||
│ ├── TableOfContents.astro # TOC component
|
||||
│ ├── TableOfContentsWithScroll.astro # TOC with scroll tracking
|
||||
│ ├── types.ts # TypeScript interfaces
|
||||
│ └── utils.ts # Core logic and utilities
|
||||
├── config/
|
||||
│ └── sidebar.ts # Configuration management
|
||||
├── layouts/
|
||||
│ └── Resources.astro # Example layout using sidebar
|
||||
└── styles/
|
||||
└── global.css # All sidebar styles
|
||||
```
|
||||
|
||||
### Key Components
|
||||
|
||||
**`utils.ts`** - Core functionality:
|
||||
- `generateLinksFromDirectoryWithConfig()` - Autogeneration logic
|
||||
- `processSidebarGroup()` - Configuration processing
|
||||
- `isPageHidden()` - Hide functionality
|
||||
- `createSidebarLink()` - URL and label generation
|
||||
|
||||
**`types.ts`** - Type definitions:
|
||||
- `SidebarLink` - Individual navigation links
|
||||
- `SidebarGroup` - Navigation groups/sections
|
||||
- `SidebarConfig` - Overall configuration structure
|
||||
|
||||
**`Sidebar.astro`** - Main component orchestrating:
|
||||
- Global navigation rendering
|
||||
- Page-level navigation integration
|
||||
- Table of contents inclusion
|
||||
- Mobile responsiveness
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Build Time
|
||||
- Autogeneration happens at build time
|
||||
- Content collections are cached by Astro
|
||||
- Minimal impact on build performance
|
||||
|
||||
### Runtime
|
||||
- Static navigation structure
|
||||
- No client-side JavaScript for basic navigation
|
||||
- TOC scroll tracking uses efficient `IntersectionObserver`
|
||||
- Mobile toggle uses minimal JavaScript
|
||||
|
||||
### Memory Usage
|
||||
- Sidebar configuration loaded once per page
|
||||
- Content collection entries processed efficiently
|
||||
- No large client-side bundles
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features
|
||||
- [ ] Search functionality within sidebar
|
||||
- [ ] Collapsible state persistence
|
||||
- [ ] Custom ordering for autogenerated items
|
||||
- [ ] Multi-language support
|
||||
- [ ] Custom icons for navigation items
|
||||
|
||||
### Extension Points
|
||||
- Custom link processors in `utils.ts`
|
||||
- Additional styling hooks in `global.css`
|
||||
- Plugin system for custom autogeneration logic
|
||||
- Integration with external navigation systems
|
||||
|
||||
---
|
||||
|
||||
*This documentation covers version 1.0 of the sidebar system. For updates and additional features, check the latest codebase.*
|
||||
587
src/content/resources/test.mdx
Normal file
@ -0,0 +1,587 @@
|
||||
---
|
||||
pubDate: 2024-12-19
|
||||
title: Test MDX File
|
||||
author: Test Author
|
||||
description: "This is a test MDX file to verify the resources collection is working properly."
|
||||
image:
|
||||
url: "https://fastly.picsum.photos/id/972/200/300.jpg?hmac=UMf5f6BV9GkLiz0Xz9kMwm1riiTtlpIG2jt0WrxZ51Q?grayscale"
|
||||
alt: "Test placeholder image"
|
||||
tags: ["test", "mdx", "resources"]
|
||||
# breadcrumb: false # Uncomment to disable breadcrumb navigation
|
||||
sidebar:
|
||||
label: "Page Navigation"
|
||||
items:
|
||||
- label: "Quick Start"
|
||||
href: "#test-mdx-content"
|
||||
- label: "Image Solutions"
|
||||
href: "#🎯-relative-path-solution-for-imagetools"
|
||||
- label: "Gallery Examples"
|
||||
href: "#interactive-image-gallery"
|
||||
|
||||
- label: "Code Examples"
|
||||
href: "#manual-usage"
|
||||
- label: "Breadcrumb Info"
|
||||
href: "#breadcrumb-navigation"
|
||||
---
|
||||
|
||||
import { Img, Picture } from "imagetools/components";
|
||||
import LGallery from "@polymech/astro-base/components/GalleryK.astro";
|
||||
import RelativeImage from "@polymech/astro-base/components/RelativeImage.astro";
|
||||
import RelativePicture from "@polymech/astro-base/components/RelativePicture.astro";
|
||||
import RelativeGallery from "@polymech/astro-base/components/RelativeGallery.astro";
|
||||
|
||||
import FileTree from "@polymech/astro-base/components/FileTree.astro";
|
||||
|
||||
# Test MDX Content
|
||||
|
||||
This is a test MDX file with proper frontmatter. It should now appear in your resources collection.
|
||||
|
||||
## 🎯 Relative Path Solution for Imagetools
|
||||
|
||||
### ✅ NEW: Relative Paths with Custom Wrappers
|
||||
|
||||
<RelativeImage src="./test.jpg" alt="Test image with relative path" width={300} />
|
||||
|
||||
<RelativePicture src="./test.jpg" alt="Responsive relative image" widths={[600]} />
|
||||
|
||||
### 🔄 Two Images Side by Side (50% each)
|
||||
|
||||
<div class="image-row">
|
||||
<RelativeImage src="./test.jpg" alt="First image" class="floating-image" />
|
||||
<RelativeImage src="./test.jpg" alt="Second image" class="floating-image" />
|
||||
</div>
|
||||
|
||||
### 🔄 Original: Public Paths (Still Work)
|
||||
|
||||
<Img src="/images/test.jpg" alt="Test Image from Public" width={300} />
|
||||
|
||||
<Picture src="/images/test.jpg" alt="Responsive Test Image" widths={[600]} />
|
||||
|
||||
### Different Format Generation
|
||||
<Picture src="/images/test.jpg" alt="Multi-format Test Image" width={400} format={["avif", "webp", "jpg"]} />
|
||||
|
||||
### Quality Optimization
|
||||
<Img src="/images/test.jpg" alt="Optimized Test Image" width={350} quality={85} />
|
||||
|
||||
## Interactive Image Gallery
|
||||
|
||||
### 🆕 Glob Pattern Gallery - Auto-load from Directory!
|
||||
|
||||
<RelativeGallery
|
||||
glob="./gallery/*.jpg"
|
||||
gallerySettings={{
|
||||
SHOW_TITLE: true,
|
||||
SHOW_DESCRIPTION: true
|
||||
}}
|
||||
/>
|
||||
|
||||
### Manual Images (Original Method)
|
||||
|
||||
export const galleryImages = [
|
||||
{
|
||||
src: "./test.jpg",
|
||||
alt: "First test image",
|
||||
title: "Test Image 1 (Relative)",
|
||||
description: "This image uses relative path ./test.jpg"
|
||||
},
|
||||
{
|
||||
src: "./test.jpg",
|
||||
alt: "Second test image",
|
||||
title: "Test Image 2 (Relative)",
|
||||
description: "This image uses relative path ./test.jpg"
|
||||
}
|
||||
];
|
||||
|
||||
<RelativeGallery
|
||||
images={galleryImages}
|
||||
gallerySettings={{
|
||||
SHOW_TITLE: true,
|
||||
SHOW_DESCRIPTION: true,
|
||||
SIZES_REGULAR: "w-full h-auto",
|
||||
SIZES_THUMB: "w-32 h-32"
|
||||
}}
|
||||
lightboxSettings={{
|
||||
SHOW_TITLE: true,
|
||||
SHOW_DESCRIPTION: true,
|
||||
SIZES_LARGE: "w-auto h-auto"
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
### 🆕 Glob Pattern Support:
|
||||
|
||||
<RelativeGallery
|
||||
glob="./gallery/*.jpg"
|
||||
gallerySettings={{ SHOW_TITLE: true }}
|
||||
/>
|
||||
|
||||
### Manual Usage:
|
||||
```jsx
|
||||
import RelativeImage from "@polymech/astro-base/components/RelativeImage.astro";
|
||||
<RelativeImage src="./my-image.jpg" alt="My image" width={400} />
|
||||
```
|
||||
|
||||
## FileTree Component Example
|
||||
|
||||
### 🆕 Auto-Generated FileTree with Glob Patterns!
|
||||
|
||||
No more manually typing out file structures! Just like RelativeGallery, FileTree now supports glob patterns with **clickable file links**:
|
||||
|
||||
<FileTree glob="../**/*.{md,mdx,astro,ts,js,json}" maxDepth={3} />
|
||||
|
||||
### Specific Directory Structure (with custom URL prefix)
|
||||
|
||||
<FileTree
|
||||
glob="../components/**/*"
|
||||
maxDepth={2}
|
||||
exclude={["node_modules", ".git"]}
|
||||
urlPrefix="https://github.com/yourrepo/blob/main"
|
||||
/>
|
||||
|
||||
### VS Code Integration Example
|
||||
|
||||
<FileTree
|
||||
glob="../src/components/polymech/**/*.{ts,astro}"
|
||||
maxDepth={2}
|
||||
urlPrefix="vscode://file"
|
||||
/>
|
||||
|
||||
### 🆕 Thumbnail View (Windows Explorer Style)
|
||||
|
||||
Perfect for browsing images and visual files with **modern, subtle link styling** (no more aggressive blue!):
|
||||
|
||||
<FileTree
|
||||
glob="../public/images/**/*.{jpg,jpeg,png,gif,webp,svg}"
|
||||
view="thumbs"
|
||||
thumbSize="medium"
|
||||
maxDepth={2}
|
||||
/>
|
||||
|
||||
### Large Thumbnails for Detailed Preview
|
||||
|
||||
<FileTree
|
||||
glob="../public/products/**/*.{jpg,jpeg,png}"
|
||||
view="thumbs"
|
||||
thumbSize="large"
|
||||
maxDepth={1}
|
||||
/>
|
||||
|
||||
### Small Thumbnails for Compact View
|
||||
|
||||
Debug example with current directory images and proper icons:
|
||||
|
||||
<FileTree
|
||||
glob="./gallery/*"
|
||||
view="thumbs"
|
||||
thumbSize="medium"
|
||||
linkFiles={true}
|
||||
/>
|
||||
|
||||
Mixed content with folders and files:
|
||||
|
||||
<FileTree
|
||||
glob="../**/*.{md,ts,json}"
|
||||
view="thumbs"
|
||||
thumbSize="small"
|
||||
maxDepth={2}
|
||||
/>
|
||||
|
||||
For comparison, here's a tree view of the same files:
|
||||
|
||||
<FileTree
|
||||
glob="./*.jpg"
|
||||
view="tree"
|
||||
linkFiles={true}
|
||||
/>
|
||||
|
||||
### Debug Example - Non-existent Path
|
||||
|
||||
This will show the "No files found" message with absolute path:
|
||||
|
||||
<FileTree
|
||||
glob="./non-existent/*.jpg"
|
||||
view="thumbs"
|
||||
thumbSize="small"
|
||||
/>
|
||||
|
||||
<FileTree
|
||||
glob="./another-missing-dir/**/*.png"
|
||||
view="tree"
|
||||
maxDepth={2}
|
||||
/>
|
||||
|
||||
### Manual FileTree (Original Method)
|
||||
|
||||
Here's an example of the FileTree component with manual structure:
|
||||
|
||||
<FileTree>
|
||||
|
||||
- public/
|
||||
- images/
|
||||
- logo.svg
|
||||
- hero.jpg
|
||||
- favicon.ico
|
||||
- src/
|
||||
- components/
|
||||
- **Header.astro** Important component
|
||||
- Footer.astro
|
||||
- Navigation.astro
|
||||
- layouts/
|
||||
- Layout.astro
|
||||
- pages/
|
||||
- index.astro
|
||||
- about.astro
|
||||
- blog/
|
||||
- [...slug].astro
|
||||
- styles/
|
||||
- global.css
|
||||
- astro.config.mjs
|
||||
- package.json
|
||||
- README.md
|
||||
|
||||
</FileTree>
|
||||
|
||||
### Advanced FileTree Features
|
||||
|
||||
<FileTree>
|
||||
|
||||
- src/
|
||||
- components/
|
||||
- ui/
|
||||
- Button.tsx React component
|
||||
- Input.vue Vue component
|
||||
- Modal.svelte Svelte component
|
||||
- **layouts/**
|
||||
- BaseLayout.astro
|
||||
- BlogLayout.astro
|
||||
- utils/
|
||||
- helpers.ts
|
||||
- constants.js
|
||||
- types/
|
||||
- index.d.ts TypeScript definitions
|
||||
- ...
|
||||
- tests/
|
||||
- unit/
|
||||
- components.test.ts
|
||||
- e2e/
|
||||
- homepage.spec.ts
|
||||
- docs/
|
||||
- **getting-started.md** Start here!
|
||||
- api-reference.md
|
||||
- .github/
|
||||
- workflows/
|
||||
- ci.yml
|
||||
- package.json
|
||||
- tsconfig.json
|
||||
|
||||
</FileTree>
|
||||
|
||||
### More Glob Examples
|
||||
|
||||
Show just the current directory:
|
||||
<FileTree glob="./*" />
|
||||
|
||||
Show all TypeScript files in the project:
|
||||
<FileTree glob="../**/*.ts" maxDepth={4} />
|
||||
|
||||
Show configuration files only:
|
||||
<FileTree glob="../**/*.{json,yaml,yml,toml,config.js,config.ts}" maxDepth={2} />
|
||||
|
||||
### FileTree Usage Examples
|
||||
|
||||
```jsx
|
||||
// Tree view (default) - hierarchical structure
|
||||
<FileTree glob="../src/**/*.astro" maxDepth={3} />
|
||||
|
||||
// Thumbnail view - Windows Explorer style grid
|
||||
<FileTree
|
||||
glob="../public/images/**/*.{jpg,png,gif}"
|
||||
view="thumbs"
|
||||
thumbSize="medium"
|
||||
/>
|
||||
|
||||
// Large thumbnails for detailed preview
|
||||
<FileTree
|
||||
glob="../assets/**/*.{jpg,png}"
|
||||
view="thumbs"
|
||||
thumbSize="large"
|
||||
maxDepth={2}
|
||||
/>
|
||||
|
||||
// Small thumbnails for compact display
|
||||
<FileTree
|
||||
glob="../gallery/**/*"
|
||||
view="thumbs"
|
||||
thumbSize="small"
|
||||
linkFiles={false}
|
||||
/>
|
||||
|
||||
// Custom URL prefix for GitHub integration
|
||||
<FileTree
|
||||
glob="../**/*.ts"
|
||||
urlPrefix="https://github.com/username/repo/blob/main"
|
||||
maxDepth={3}
|
||||
/>
|
||||
|
||||
// VS Code integration - files open in editor
|
||||
<FileTree
|
||||
glob="../**/*.astro"
|
||||
urlPrefix="vscode://file"
|
||||
maxDepth={2}
|
||||
/>
|
||||
|
||||
// Disable links if you just want display
|
||||
<FileTree
|
||||
glob="../**/*"
|
||||
linkFiles={false}
|
||||
maxDepth={2}
|
||||
/>
|
||||
|
||||
// Show hidden files with custom dev server URL
|
||||
<FileTree
|
||||
glob="../**/*"
|
||||
showHidden={true}
|
||||
urlPrefix="http://localhost:3000"
|
||||
maxDepth={2}
|
||||
/>
|
||||
|
||||
// Manual structure (original way - no links)
|
||||
<FileTree>
|
||||
- src/
|
||||
- components/
|
||||
- Header.astro
|
||||
</FileTree>
|
||||
```
|
||||
|
||||
### View Modes:
|
||||
|
||||
- **Tree View** (`view="tree"`): Traditional hierarchical file tree with folders and files
|
||||
- **Thumbnail View** (`view="thumbs"`): Grid layout like Windows Explorer with image previews
|
||||
|
||||
### Thumbnail Sizes:
|
||||
|
||||
- **Small** (`thumbSize="small"`): 80px thumbnails for compact display
|
||||
- **Medium** (`thumbSize="medium"`): 120px thumbnails (default)
|
||||
- **Large** (`thumbSize="large"`): 160px thumbnails for detailed preview
|
||||
|
||||
### Link Types Supported:
|
||||
|
||||
- **Default**: `file://` protocol for local file system
|
||||
- **VS Code**: `vscode://file/` for opening in VS Code
|
||||
- **GitHub**: `https://github.com/user/repo/blob/main/` for web viewing
|
||||
- **Custom**: Any URL prefix you provide
|
||||
- **Disabled**: Set `linkFiles={false}` for display only
|
||||
|
||||
## Breadcrumb Navigation
|
||||
|
||||
The Resources collection now includes automatic breadcrumb navigation!
|
||||
|
||||
### Features:
|
||||
- **Auto-generated**: Breadcrumbs are automatically created based on your URL path
|
||||
- **Smart labeling**: Uses your page title for the current page, formatted directory names for paths
|
||||
- **Accessible**: Full ARIA support with proper labels and navigation structure
|
||||
- **Responsive**: Mobile-friendly design that adapts to smaller screens
|
||||
- **Customizable**: Easy to disable per page or customize styling
|
||||
|
||||
### Usage:
|
||||
|
||||
**Enable breadcrumbs (default behavior):**
|
||||
```yaml
|
||||
---
|
||||
title: "My Page Title"
|
||||
# Breadcrumbs will show automatically
|
||||
---
|
||||
```
|
||||
|
||||
**Disable breadcrumbs for a specific page:**
|
||||
```yaml
|
||||
---
|
||||
title: "My Page Title"
|
||||
breadcrumb: false
|
||||
---
|
||||
```
|
||||
|
||||
### Example Breadcrumb Path:
|
||||
For a page at `/resources/guides/getting-started/`, the breadcrumb would show:
|
||||
```
|
||||
Home / Resources / Guides / Getting Started
|
||||
```
|
||||
|
||||
The breadcrumb component is reusable and can be easily integrated into other collection layouts as needed.
|
||||
|
||||
## 🆕 Sidebar Autogenerated Nodes with Sorting
|
||||
|
||||
The sidebar now supports configurable sorting for autogenerated nodes! By default, all autogenerated sidebar sections use **alphabetical sorting**.
|
||||
|
||||
### Available Sort Functions:
|
||||
|
||||
1. **`'alphabetical'`** (Default): Sorts items alphabetically by label, with files before groups
|
||||
2. **`'date'`**: Sorts by `pubDate` frontmatter field (newest first), fallback to alphabetical
|
||||
3. **`'custom'`**: Use your own custom sorting function
|
||||
|
||||
### Configuration Examples:
|
||||
|
||||
#### Basic Alphabetical Sorting (Default)
|
||||
```typescript
|
||||
// src/config/sidebar.ts
|
||||
export const sidebarConfig: SidebarGroup[] = [
|
||||
{
|
||||
label: 'Resources',
|
||||
autogenerate: {
|
||||
directory: 'resources',
|
||||
collapsed: false,
|
||||
sortBy: 'alphabetical' // This is the default
|
||||
},
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
#### Date-based Sorting (Newest First)
|
||||
```typescript
|
||||
{
|
||||
label: 'Blog Posts',
|
||||
autogenerate: {
|
||||
directory: 'blog',
|
||||
collapsed: false,
|
||||
sortBy: 'date' // Requires pubDate in frontmatter
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
#### Custom Sorting Function
|
||||
```typescript
|
||||
{
|
||||
label: 'Custom Sorted',
|
||||
autogenerate: {
|
||||
directory: 'docs',
|
||||
collapsed: false,
|
||||
sortBy: 'custom',
|
||||
customSort: (a, b) => {
|
||||
// Custom logic here - example: prioritize certain files
|
||||
if (a.label.startsWith('Getting Started')) return -1;
|
||||
if (b.label.startsWith('Getting Started')) return 1;
|
||||
return a.label.localeCompare(b.label);
|
||||
}
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Features:
|
||||
|
||||
- **Hierarchical sorting**: Applies to both files and subdirectories
|
||||
- **Files before groups**: Files always appear before subdirectory groups in alphabetical mode
|
||||
- **Fallback support**: Date sorting falls back to alphabetical when no dates are available
|
||||
- **Deep nesting**: Sorting applies recursively to all nested levels
|
||||
- **Type safety**: Full TypeScript support with proper type definitions
|
||||
|
||||
### Migration:
|
||||
|
||||
Existing configurations will continue to work unchanged - alphabetical sorting is now the explicit default instead of being hardcoded.
|
||||
|
||||
## Mermaid Diagrams
|
||||
|
||||
Now we have full support for Mermaid diagrams in MDX! Here are some examples:
|
||||
|
||||
### Flowchart Example
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Start] --> B{Is it working?}
|
||||
B -->|Yes| C[Great!]
|
||||
B -->|No| D[Debug]
|
||||
D --> B
|
||||
C --> E[Deploy to Production]
|
||||
```
|
||||
|
||||
### Sequence Diagram
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant Browser
|
||||
participant Server
|
||||
participant Database
|
||||
|
||||
User->>Browser: Open website
|
||||
Browser->>Server: Request page
|
||||
Server->>Database: Query data
|
||||
Database-->>Server: Return data
|
||||
Server-->>Browser: Send HTML
|
||||
Browser-->>User: Display page
|
||||
```
|
||||
|
||||
### Git Flow Diagram
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[main branch] --> B[develop branch]
|
||||
B --> C[feature branch]
|
||||
C --> D[commit 1]
|
||||
D --> E[commit 2]
|
||||
E --> F[merge to develop]
|
||||
F --> B
|
||||
B --> G[merge to main]
|
||||
G --> A
|
||||
|
||||
style A fill:#e1f5fe
|
||||
style B fill:#f3e5f5
|
||||
style C fill:#e8f5e8
|
||||
```
|
||||
|
||||
### Class Diagram
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class FileTree {
|
||||
+String glob
|
||||
+Number maxDepth
|
||||
+Boolean showHidden
|
||||
+String[] exclude
|
||||
+String urlPrefix
|
||||
+Boolean linkFiles
|
||||
+generateFileUrl()
|
||||
+buildFileTreeFromPaths()
|
||||
}
|
||||
|
||||
class RelativeGallery {
|
||||
+String glob
|
||||
+Object[] images
|
||||
+Object gallerySettings
|
||||
+Object lightboxSettings
|
||||
+renderGallery()
|
||||
}
|
||||
|
||||
FileTree --> RelativeGallery : uses similar patterns
|
||||
```
|
||||
|
||||
### State Diagram
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Loading
|
||||
Loading --> Success: Data loaded
|
||||
Loading --> Error: Failed to load
|
||||
Success --> [*]
|
||||
Error --> Retry: User clicks retry
|
||||
Retry --> Loading
|
||||
Error --> [*]: User gives up
|
||||
```
|
||||
|
||||
### Project Timeline
|
||||
|
||||
```mermaid
|
||||
gantt
|
||||
title Development Timeline
|
||||
dateFormat YYYY-MM-DD
|
||||
section Setup
|
||||
Project Start :2024-01-01, 2024-01-31
|
||||
Astro Setup :2024-01-15, 2024-01-31
|
||||
section Features
|
||||
ImageTools :2024-02-01, 2024-02-15
|
||||
FileTree :2024-02-10, 2024-02-28
|
||||
RelativeGallery :2024-03-01, 2024-03-15
|
||||
Breadcrumbs :2024-03-10, 2024-03-20
|
||||
section Recent
|
||||
Mermaid Support :2024-12-01, 2024-12-19
|
||||
Enhanced Links :2024-12-15, 2024-12-19
|
||||
```
|
||||
BIN
src/content/resources/test2.jpg
Normal file
|
After Width: | Height: | Size: 293 KiB |
69
src/content/resources/web-performance.md
Normal file
@ -0,0 +1,69 @@
|
||||
---
|
||||
pubDate: 2024-12-15
|
||||
title: Web Performance Optimization Guide
|
||||
author: Sarah Johnson
|
||||
description: "Learn how to optimize your website's performance with these proven techniques and best practices."
|
||||
image0:
|
||||
url: "https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800&h=400&fit=crop"
|
||||
alt: "Performance optimization dashboard"
|
||||
tags: ["performance", "optimization", "web-development", "speed"]
|
||||
---
|
||||
|
||||
# Web Performance Optimization Guide
|
||||
|
||||
In today's fast-paced digital world, website performance is crucial for user experience and SEO rankings. This comprehensive guide will walk you through the essential techniques to optimize your website's performance.
|
||||
|
||||
## Key Performance Metrics
|
||||
|
||||
### Core Web Vitals
|
||||
- **Largest Contentful Paint (LCP)**: Measures loading performance
|
||||
- **First Input Delay (FID)**: Measures interactivity
|
||||
- **Cumulative Layout Shift (CLS)**: Measures visual stability
|
||||
|
||||
### Additional Metrics
|
||||
- **First Contentful Paint (FCP)**
|
||||
- **Time to Interactive (TTI)**
|
||||
- **Total Blocking Time (TBT)**
|
||||
|
||||
## Optimization Techniques
|
||||
|
||||
### 1. Image Optimization
|
||||
```html
|
||||
<!-- Use modern image formats -->
|
||||
<picture>
|
||||
<source srcset="image.webp" type="image/webp">
|
||||
<source srcset="image.avif" type="image/avif">
|
||||
<img src="image.jpg" alt="Optimized image" loading="lazy">
|
||||
</picture>
|
||||
```
|
||||
|
||||
### 2. Code Splitting
|
||||
```javascript
|
||||
// Dynamic imports for better performance
|
||||
const LazyComponent = React.lazy(() => import('./LazyComponent'));
|
||||
|
||||
// Webpack code splitting
|
||||
import('./module').then(module => {
|
||||
// Use the module
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Resource Preloading
|
||||
```html
|
||||
<!-- Preload critical resources -->
|
||||
<link rel="preload" href="critical.css" as="style">
|
||||
<link rel="preload" href="hero-image.jpg" as="image">
|
||||
<link rel="prefetch" href="next-page.html">
|
||||
```
|
||||
|
||||
## Performance Monitoring
|
||||
|
||||
Use tools like:
|
||||
- Google PageSpeed Insights
|
||||
- Lighthouse
|
||||
- WebPageTest
|
||||
- Core Web Vitals extension
|
||||
|
||||
## Conclusion
|
||||
|
||||
Web performance optimization is an ongoing process. Regular monitoring and continuous improvement are key to maintaining a fast, user-friendly website.
|
||||
@ -16,7 +16,6 @@ import Translate from "@polymech/astro-base/components/i18n.astro";
|
||||
import { getSidebarConfig } from "@polymech/astro-base/config/sidebar";
|
||||
import { generateToC } from "@polymech/astro-base/components/sidebar/utils/generateToC.js";
|
||||
|
||||
import RelativeImage from "@polymech/astro-base/components/RelativeImage.astro";
|
||||
import type { MarkdownHeading } from "astro";
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
|
||||