diff --git a/.gitignore b/.gitignore index 7804505..86c47f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /custom* /content* +/docs* diff --git a/app/config.ini b/app/config.ini index fd603b4..d38a320 100644 --- a/app/config.ini +++ b/app/config.ini @@ -1,3 +1,8 @@ +; PnP Framework Configuration + [languages] +; Default language (used when no language prefix in URL) default = "no" + +; Available languages (comma-separated language codes) available = "no,en" diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 292e66b..0000000 --- a/docs/README.md +++ /dev/null @@ -1,211 +0,0 @@ -# FolderWeb Documentation - -Welcome to the FolderWeb documentation! This comprehensive guide covers everything you need to know about building and maintaining websites with FolderWeb. - -## π Documentation Organization - -This documentation follows the [Diataxis framework](https://diataxis.fr/), organizing content into four distinct types to help you find exactly what you need: - -### π Tutorial (Learning-Oriented) - -**Purpose**: Learn by doing -**For**: Newcomers to FolderWeb - -- **[Getting Started](tutorial/00-getting-started.md)** - Build your first FolderWeb site from scratch in 10 minutes - -Start here if you're new to FolderWeb. This hands-on tutorial walks you through creating a complete website with pages, blog posts, and custom styling. - -### π How-To Guides (Task-Oriented) - -**Purpose**: Solve specific problems -**For**: Users with a specific goal - -- **[Custom Templates](how-to/custom-templates.md)** - Override default templates with your own designs -- **[Custom Styles](how-to/custom-styles.md)** - Customize appearance using CSS -- **[Multi-Language Sites](how-to/multi-language.md)** - Set up and manage multiple languages -- **[Working with Metadata](how-to/working-with-metadata.md)** - Control content with metadata.ini files - -Use these guides when you know what you want to accomplish and need step-by-step instructions. - -### π Reference (Information-Oriented) - -**Purpose**: Look up technical details -**For**: Users who need precise information - -- **[File Structure](reference/file-structure.md)** - Complete directory layout and file conventions -- **[Metadata](reference/metadata.md)** - All available metadata fields and their usage -- **[Templates](reference/templates.md)** - Template types and available variables -- **[Configuration](reference/configuration.md)** - Configuration options and format -- **[CSS Variables](reference/css-variables.md)** - All CSS custom properties for styling - -Consult these documents when you need to look up specific technical details or API information. - -### π‘ Explanation (Understanding-Oriented) - -**Purpose**: Understand concepts and design decisions -**For**: Users who want to understand the "why" - -- **[Philosophy](explanation/philosophy.md)** - Design principles and thinking behind FolderWeb -- **[Architecture](explanation/architecture.md)** - How FolderWeb works under the hood - -Read these to gain deeper understanding of FolderWeb's design and architecture. - -## π Quick Start - -```bash -# 1. Create project directory -mkdir my-website && cd my-website - -# 2. Copy framework files -cp -r /path/to/folderweb/app ./app - -# 3. Create your first page -mkdir content -echo "# Welcome" > content/index.md - -# 4. Start development server -php -S localhost:8000 -t . app/router.php - -# 5. Open http://localhost:8000 -``` - -**Next**: Follow the complete [Getting Started Tutorial](tutorial/00-getting-started.md) - -## π― Common Tasks - -Quick links to frequently needed guides: - -| Task | Guide | -|------|-------| -| Create a custom template | [Custom Templates](how-to/custom-templates.md) | -| Change colors and fonts | [Custom Styles](how-to/custom-styles.md) | -| Add multiple languages | [Multi-Language Sites](how-to/multi-language.md) | -| Configure page metadata | [Working with Metadata](how-to/working-with-metadata.md) | -| Look up all metadata fields | [Metadata Reference](reference/metadata.md) | -| Find template variables | [Templates Reference](reference/templates.md) | -| Understand file organization | [File Structure Reference](reference/file-structure.md) | - -## π‘ Key Concepts - -- **File-based routing**: Your folder structure defines your URL structure -- **Template fallback**: Custom templates automatically override defaults -- **Content types**: Single-file pages, multi-file pages, or list views -- **Language support**: Built-in multi-language with URL prefixes -- **Metadata control**: Configure behavior with simple INI files -- **No build process**: Save and refresh - see changes immediately - -## π Requirements - -- **PHP**: 8.4 or higher -- **Web server**: Apache, Nginx, or PHP's built-in server -- **Extensions**: Standard PHP (no special extensions required) - -## ποΈ Documentation Files - -### Complete File List - -``` -docs/ -βββ README.md # This file -βββ index.md # Documentation homepage -β -βββ tutorial/ -β βββ 00-getting-started.md # Step-by-step tutorial -β -βββ how-to/ -β βββ custom-templates.md # Override templates -β βββ custom-styles.md # Customize CSS -β βββ multi-language.md # Multi-language setup -β βββ working-with-metadata.md # Metadata usage -β -βββ reference/ -β βββ file-structure.md # Directory layout -β βββ metadata.md # Metadata fields -β βββ templates.md # Template reference -β βββ configuration.md # Config options -β βββ css-variables.md # CSS customization -β -βββ explanation/ - βββ philosophy.md # Design principles - βββ architecture.md # Technical architecture -``` - -## π Reading Paths - -Choose your path based on your needs: - -### Path 1: Complete Beginner - -1. [Getting Started Tutorial](tutorial/00-getting-started.md) -2. [Custom Styles](how-to/custom-styles.md) -3. [Working with Metadata](how-to/working-with-metadata.md) -4. [Philosophy](explanation/philosophy.md) - -### Path 2: Experienced Developer - -1. [Philosophy](explanation/philosophy.md) -2. [Architecture](explanation/architecture.md) -3. [File Structure Reference](reference/file-structure.md) -4. Browse How-To Guides as needed - -### Path 3: Specific Task - -1. Find your task in [How-To Guides](how-to/) -2. Consult [Reference](reference/) for details -3. Return to task completion - -## π€ Getting Help - -### Documentation Not Enough? - -1. **Check the code**: FolderWeb is deliberately simple - reading the source is encouraged -2. **Review examples**: Look at the demo content in `/app/default/content/` -3. **Test locally**: Experiment with a test site to understand behavior - -### Common Issues - -| Problem | Solution | -|---------|----------| -| Styles not loading | Hard refresh browser (Ctrl+Shift+R) | -| 404 errors | Verify folder exists with content files | -| Language not working | Check `available` in config.ini | -| Metadata not showing | Validate INI syntax with PHP parser | -| Custom template ignored | Ensure file is in `/custom/templates/` | - -## π Philosophy Highlights - -FolderWeb embraces: - -- **Simplicity**: Just enough, nothing more -- **Longevity**: Works today, works in 2035 -- **Transparency**: Readable code, clear behavior -- **Files**: Your content, fully portable -- **No build**: Save and refresh workflow - -Read the complete [Philosophy](explanation/philosophy.md) to understand FolderWeb's design principles. - -## π Contributing to Documentation - -Documentation improvements are welcome: - -- Fix typos or unclear explanations -- Add missing examples -- Improve existing guides -- Suggest new how-to guides - -Keep documentation: -- Clear and concise -- Accurate and tested -- Organized according to Diataxis principles - -## π External Resources - -- [Diataxis Framework](https://diataxis.fr/) - Documentation organization system -- [PHP 8.4 Documentation](https://www.php.net/manual/en/) - PHP reference -- [Markdown Guide](https://www.markdownguide.org/) - Markdown syntax -- [MDN Web Docs](https://developer.mozilla.org/) - HTML and CSS reference - ---- - -**Start here**: [Getting Started Tutorial](tutorial/00-getting-started.md) -**Main index**: [Documentation Index](index.md) diff --git a/docs/explanation/architecture.md b/docs/explanation/architecture.md deleted file mode 100644 index 08809d8..0000000 --- a/docs/explanation/architecture.md +++ /dev/null @@ -1,739 +0,0 @@ -# Architecture - -Understanding how FolderWeb works under the hood. - -## High-Level Overview - -FolderWeb follows a simple request-response flow: - -``` -HTTP Request - β -router.php (entry point) - β -Parse request path - β -Find content files - β -Determine content type (page/list/file) - β -Render content - β -Wrap in templates - β -HTTP Response -``` - -## Core Components - -### 1. Router (`app/router.php`) - -**Purpose**: Entry point for all requests, determines what to serve - -**Responsibilities**: -- Receive HTTP requests -- Check for root-level assets (`/custom/assets/`) -- Parse request path -- Dispatch to appropriate renderer -- Handle redirects (trailing slashes) -- Serve 404 for missing content - -**Key Flow**: -```php -// 1. Check for root-level assets -if (file_exists("/custom/assets/$path")) { - serve_static_file(); -} - -// 2. Empty path = home page (render all root content files) -if (empty($path)) { - render_all_files_in_root(); -} - -// 3. Parse request path -$result = parseRequestPath($ctx); - -// 4. Handle based on type -match($result['type']) { - 'page' => renderMultipleFiles(...), - 'file' => renderFile(...), - 'directory' => renderListView(...), - 'not_found' => show_404() -}; -``` - -**Location**: `/app/router.php` (lines 1-100+) - -### 2. Content Discovery (`app/content.php`) - -**Purpose**: Find and parse content files and directories - -**Key Functions**: - -#### `parseRequestPath($ctx)` -Analyzes request path and determines content type. - -**Returns**: -```php -[ - 'type' => 'page' | 'file' | 'directory' | 'not_found', - 'path' => '/full/system/path', - 'files' => [...], // For page type - // ... other data -] -``` - -**Logic**: -1. Resolve translated slugs to real paths -2. Check if path exists -3. If directory: - - Has subdirectories? β `type: 'directory'` (list view) - - Has content files only? β `type: 'page'` (multi-file) -4. If matches file? β `type: 'file'` -5. Otherwise β `type: 'not_found'` - -#### `findAllContentFiles($dir, $lang, $defaultLang, $availableLangs)` -Scans directory for content files. - -**Process**: -1. Read directory contents -2. Filter for valid extensions (`.md`, `.html`, `.php`) -3. Parse filenames for language suffix -4. Filter by current language: - - Show `.{lang}.ext` files for that language - - Show default files (no suffix) only if no language variant -5. Sort alphanumerically -6. Return array of file paths - -**Example**: -```php -// Directory contains: -// - index.md -// - index.no.md -// - about.md - -// English request (lang=en, default=en): -findAllContentFiles() β ['index.md', 'about.md'] - -// Norwegian request (lang=no): -findAllContentFiles() β ['index.no.md', 'about.md'] -``` - -#### `loadMetadata($dirPath, $lang, $defaultLang)` -Loads and merges metadata for a directory. - -**Process**: -1. Check for `metadata.ini` in directory -2. Parse INI file with sections -3. Start with base values -4. Override with language-specific section if exists -5. Return merged array - -**Example**: -```ini -title = "About" -summary = "Learn about us" - -[no] -title = "Om" -summary = "LΓ¦r om oss" -``` - -For Norwegian request: -```php -loadMetadata(..., 'no', 'en') β [ - 'title' => 'Om', // Overridden - 'summary' => 'LΓ¦r om oss' // Overridden -] -``` - -#### `resolveTranslatedPath($ctx, $requestPath)` -Maps translated slugs back to real directory names. - -**Example**: -```ini -; In content/about/metadata.ini: -[no] -slug = "om-oss" -``` - -Request to `/no/om-oss/` resolves to `content/about/`. - -**Process**: -1. Split path into segments -2. For each segment: - - Load metadata of parent directory - - Check if any subdirectory has matching translated slug - - Replace segment with real directory name -3. Return resolved path - -### 3. Rendering Engine (`app/rendering.php`) - -**Purpose**: Convert content to HTML and wrap in templates - -**Key Functions**: - -#### `renderContentFile($filePath)` -Converts a single content file to HTML. - -**Process**: -```php -switch (extension) { - case 'md': - return Parsedown->text(file_contents); - case 'html': - return file_contents; - case 'php': - ob_start(); - include $filePath; // $ctx available - return ob_get_clean(); -} -``` - -#### `renderFile($ctx, $filePath)` -Renders single file wrapped in templates. - -**Process**: -1. Convert file to HTML -2. Load metadata -3. Wrap in page template -4. Wrap in base template -5. Return HTML - -#### `renderMultipleFiles($ctx, $filePaths, $pageDir)` -Renders multiple files as single page. - -**Process**: -1. Convert each file to HTML -2. Concatenate HTML (in order) -3. Load metadata -4. Wrap in page template -5. Wrap in base template -6. Return HTML - -**Used for**: Multi-file pages (documentation, long articles) - -#### `renderTemplate($ctx, $content, $statusCode = 200)` -Wraps content in base template. - -**Process**: -1. Extract variables for template -2. Set HTTP status code -3. Include base template -4. Return HTML - -**Variables provided**: -- `$content` - Rendered HTML -- `$ctx` - Context object -- `$currentLang`, `$navigation`, `$homeLabel`, etc. - -### 4. Context Object (`app/context.php`) - -**Purpose**: Immutable request context with computed properties - -**Implementation**: -```php -readonly class Context { - public function __construct( - public private(set) string $contentDir, - public private(set) string $currentLang, - // ... other properties - ) {} - - // Computed property (PHP 8.4 hook) - public string $langPrefix { - get => $this->currentLang !== $this->defaultLang - ? "/{$this->currentLang}" - : ''; - } - - // Lazy-loaded computed property - public array $navigation { - get => buildNavigation($this); - } -} -``` - -**Benefits**: -- **Immutability**: Cannot be changed after creation -- **Type safety**: All properties typed -- **Computed values**: Calculated on-demand -- **No globals**: Passed explicitly - -**Creation**: -```php -$ctx = createContext(); -``` - -This function: -1. Loads configuration -2. Extracts language from URL -3. Determines content directory -4. Resolves template paths -5. Returns readonly Context object - -### 5. Configuration (`app/config.php`) - -**Purpose**: Load and merge configuration - -**Process**: -1. Parse `/app/config.ini` (defaults) -2. Parse `/custom/config.ini` if exists -3. Merge arrays (custom overrides defaults) -4. Extract language settings -5. Validate configuration - -**Configuration Used**: -```ini -[languages] -default = "en" -available = "en,no,fr" -``` - -### 6. Helper Functions (`app/helpers.php`) - -**Purpose**: Utility functions used throughout - -**Key Helpers**: - -| Function | Purpose | -|----------|---------| -| `resolveTemplate($name, $type)` | Find custom or default template | -| `getSubdirectories($dir)` | List subdirectories only | -| `extractTitle($filePath, $lang, $defaultLang)` | Extract H1 from content | -| `formatNorwegianDate($date)` | Format date as "2. november 2025" | -| `extractDateFromFolder($name)` | Parse date from folder name | -| `findCoverImage($dir)` | Locate cover image | -| `findPdfFile($dir)` | Find first PDF | - -### 7. Static File Server (`app/static.php`) - -**Purpose**: Serve CSS, fonts, and other static assets - -**Process**: -1. Validate path (prevent directory traversal) -2. Resolve real path -3. Check file exists and is readable -4. Determine MIME type -5. Set headers -6. Output file contents - -**Routes**: -- `/app/styles/base.css` β Custom or default CSS -- `/app/default-styles/base.css` β Default CSS -- `/custom/fonts/*` β Custom fonts - -## Data Flow - -### Request Flow Diagram - -``` -1. HTTP Request: /blog/2025-11-02-post/ - β -2. router.php receives request - β -3. createContext() - ββ Load config - ββ Extract language from URL - ββ Determine content directory - ββ Return Context object - β -4. parseRequestPath($ctx) - ββ resolveTranslatedPath() - map slug to real path - ββ Check path exists - ββ findAllContentFiles() - scan for content - ββ Return ['type' => 'file', 'path' => '...'] - β -5. renderFile($ctx, $filePath) - ββ renderContentFile() - convert to HTML - ββ loadMetadata() - get metadata - ββ Apply page template - ββ Apply base template - β -6. HTTP Response: HTML -``` - -### List View Flow - -``` -1. Request: /blog/ - β -2. parseRequestPath() β type: 'directory' - β -3. Load directory metadata - ββ Get page_template setting - ββ Get other directory metadata - β -4. getSubdirectories() - find all subdirs - β -5. For each subdirectory: - ββ loadMetadata() - get title, date, summary - ββ findCoverImage() - locate cover - ββ findPdfFile() - locate PDF - ββ Build item array - β -6. Render list template with $items - β -7. Wrap in base template - β -8. Return HTML -``` - -## File Organization - -### Separation of Concerns - -``` -app/ -βββ router.php # Entry point, request handling -βββ content.php # Content discovery, parsing -βββ rendering.php # HTML generation, templates -βββ context.php # Request context -βββ config.php # Configuration loading -βββ helpers.php # Utility functions -βββ constants.php # Constants (extensions) -βββ static.php # Static file serving -``` - -Each file has a single responsibility. - -### Template Resolution - -Templates use fallback chain: - -``` -1. /custom/templates/{name}.php - β (if not found) -2. /app/default/templates/{name}.php -``` - -**Implementation**: -```php -function resolveTemplate($name, $type = 'templates') { - $custom = __DIR__ . "/../custom/$type/$name"; - $default = __DIR__ . "/default/$type/$name"; - return file_exists($custom) ? $custom : $default; -} -``` - -This pattern applies to: -- Templates -- Styles -- Languages -- Any overridable resource - -## Language Handling - -### URL Structure - -``` -/ β Default language -/no/ β Norwegian -/fr/page/ β French page -``` - -### Language Extraction - -From URL path: -```php -// Request: /no/blog/post/ -$segments = explode('/', trim($path, '/')); -$firstSegment = $segments[0] ?? ''; - -if (in_array($firstSegment, $availableLangs)) { - $currentLang = $firstSegment; - $pathWithoutLang = implode('/', array_slice($segments, 1)); -} else { - $currentLang = $defaultLang; - $pathWithoutLang = $path; -} -``` - -### Content Filtering - -Files with language suffixes (`.{lang}.ext`) are filtered: - -```php -// Parse filename -$parts = explode('.', $filename); -$lastPart = $parts[count($parts) - 2] ?? null; - -// Check if second-to-last part is a language -if (in_array($lastPart, $availableLangs)) { - $fileLang = $lastPart; -} else { - $fileLang = $defaultLang; -} - -// Include file if: -// - It matches current language, OR -// - It's default language AND no specific variant exists -``` - -## Navigation Building - -### Process - -```php -function buildNavigation($ctx) { - $items = []; - - // 1. Scan content root for directories - $dirs = getSubdirectories($ctx->contentDir); - - // 2. For each directory - foreach ($dirs as $dir) { - // Load metadata - $metadata = loadMetadata($dir, $ctx->currentLang, $ctx->defaultLang); - - // Skip if menu = false - if (!($metadata['menu'] ?? false)) continue; - - // Build item - $items[] = [ - 'title' => $metadata['title'] ?? basename($dir), - 'url' => $ctx->langPrefix . '/' . basename($dir) . '/', - 'order' => $metadata['menu_order'] ?? 999 - ]; - } - - // 3. Sort by menu_order - usort($items, fn($a, $b) => $a['order'] <=> $b['order']); - - return $items; -} -``` - -### Caching - -Navigation is a computed property, calculated once per request: - -```php -public array $navigation { - get => buildNavigation($this); -} -``` - -PHP memoizes the result automatically. - -## Performance Characteristics - -### Time Complexity - -| Operation | Complexity | Notes | -|-----------|------------|-------| -| Route resolution | O(1) | Direct file checks | -| Content file scan | O(n) | n = files in directory | -| Metadata loading | O(1) | Single file read | -| Template rendering | O(m) | m = content size | -| Navigation build | O(d) | d = top-level directories | - -### Space Complexity - -- **Memory**: O(c) where c = content size -- **No caching**: Each request independent -- **Stateless**: No session storage - -### Optimization Points - -1. **OPcache**: PHP bytecode caching (biggest impact) -2. **Web server cache**: Serve cached HTML -3. **Reverse proxy**: Varnish, Cloudflare -4. **Minimize file reads**: Context created once per request - -## Security Architecture - -### Path Validation - -Multiple layers prevent directory traversal: - -```php -// 1. Remove .. segments -$path = str_replace('..', '', $path); - -// 2. Resolve to real path -$realPath = realpath($path); - -// 3. Ensure within content directory -if (!str_starts_with($realPath, $contentDir)) { - return 404; -} - -// 4. Check readable -if (!is_readable($realPath)) { - return 404; -} -``` - -### Output Escaping - -All user-generated content escaped: - -```php -= htmlspecialchars($metadata['title']) ?> -``` - -This prevents XSS attacks. - -### MIME Type Validation - -Static files served with correct MIME types: - -```php -$mimeTypes = [ - 'css' => 'text/css', - 'woff2' => 'font/woff2', - 'jpg' => 'image/jpeg', - // ... -]; - -header('Content-Type: ' . $mimeTypes[$extension]); -``` - -## Error Handling - -### HTTP Status Codes - -- **200 OK**: Successful content render -- **301 Moved Permanently**: Missing trailing slash -- **404 Not Found**: Content doesn't exist - -### 404 Handling - -When content not found: - -```php -renderTemplate($ctx, '
= htmlspecialchars($item['summary']) ?>
- -= $translations['footer_text'] ?>
-``` - -### In Custom Templates - -Access translations the same way: - -```php - -``` - -### Access Current Language - -```php -currentLang === 'no'): ?> -Dette er norsk innhold.
- -This is English content.
- -``` - -## Language Switcher - -Create a language switcher in your custom base template: - -```php - -``` - -Style it: - -```css -.language-switcher { - display: flex; - gap: 0.5rem; -} - -.language-switcher a { - padding: 0.25rem 0.75rem; - border-radius: var(--border-radius); - text-decoration: none; -} - -.language-switcher a.active { - background: var(--color-primary); - color: white; -} -``` - -## List Views with Multiple Languages - -When displaying blog listings, FolderWeb automatically filters items by language: - -``` -content/blog/ -βββ 2025-11-01-english-article/ -β βββ index.md # Shows in English -βββ 2025-11-02-norsk-artikkel/ -β βββ index.no.md # Shows only in Norwegian -βββ 2025-11-03-universal/ - βββ index.md # Shows in English - βββ index.no.md # Shows in Norwegian - βββ index.fr.md # Shows in French -``` - -When viewing `/blog/`: -- Shows "english-article" and "universal" - -When viewing `/no/blog/`: -- Shows "norsk-artikkel" and "universal" - -When viewing `/fr/blog/`: -- Shows only "universal" - -## Handling Missing Translations - -### Default Fallback - -If a translation is missing, FolderWeb uses the default language automatically. - -### Show Different Content - -You can use PHP in your content files: - -```php -currentLang === 'en'): ?> -# Welcome -This page is only in English. - -# Under Construction -This page is not yet translated. - -``` - -## SEO Considerations - -### Add hreflang Tags - -In your custom base template: - -```php - - - - availableLangs as $lang): ?> - defaultLang - ? 'https://yoursite.com/' . trim($ctx->requestPath, '/') - : 'https://yoursite.com/' . $lang . '/' . trim($ctx->requestPath, '/'); - ?> - - - - - -``` - -### Language-Specific Metadata - -Add language attributes: - -```php - -``` - -## Testing Your Multi-Language Site - -1. **Visit default language**: `http://localhost:8000/about/` -2. **Visit Norwegian**: `http://localhost:8000/no/about/` -3. **Visit French**: `http://localhost:8000/fr/about/` -4. **Check navigation**: Ensure links include language prefix -5. **Test translation strings**: Verify UI text changes per language -6. **Check blog listings**: Confirm language-specific posts appear correctly - -## Common Patterns - -### Blog in Multiple Languages - -Structure: -``` -content/blog/ -βββ metadata.ini # List template config -βββ [date]-[slug]/ - βββ index.{lang}.md # One file per language - βββ cover.jpg # Shared assets - βββ metadata.ini # Translated metadata -``` - -### Documentation in Multiple Languages - -Structure: -``` -content/docs/ -βββ metadata.ini # Template config -βββ 00-intro.md # Default language -βββ 00-intro.no.md # Norwegian -βββ 01-setup.md -βββ 01-setup.no.md -βββ ... -``` - -### Mixed Content Strategy - -Not everything needs translation. You can have: -- English-only blog posts (no language suffix) -- Multi-language main pages (with language suffixes) -- Shared images and assets - -## Related - -- [Metadata Reference](../reference/metadata.md) -- [Configuration Reference](../reference/configuration.md) -- [Template Variables Reference](../reference/templates.md) diff --git a/docs/how-to/working-with-metadata.md b/docs/how-to/working-with-metadata.md deleted file mode 100644 index ad224b5..0000000 --- a/docs/how-to/working-with-metadata.md +++ /dev/null @@ -1,481 +0,0 @@ -# How to Work with Metadata - -This guide shows you how to use `metadata.ini` files to control page behavior, appearance, and content. - -## What is Metadata? - -Metadata provides structured information about your content directories without cluttering your content files. It's stored in `metadata.ini` files using the INI format. - -## Basic Metadata File - -Create `metadata.ini` in any content directory: - -```ini -title = "My Page Title" -date = "2025-11-02" -summary = "A brief description of this page." -``` - -## Common Metadata Fields - -### Title - -Controls the displayed title (overrides automatic title extraction): - -```ini -title = "Custom Page Title" -``` - -If not provided, FolderWeb extracts the title from: -1. First H1 heading in content (`# Title` in Markdown) -2. Folder name (as fallback) - -### Date - -Set an explicit date (overrides folder name date extraction): - -```ini -date = "2025-11-02" -``` - -Format: `YYYY-MM-DD` - -FolderWeb automatically formats this in Norwegian style: "2. november 2025" - -### Summary - -Add a summary for list views: - -```ini -summary = "This appears in blog listings and card grids." -``` - -Summaries are displayed in: -- List views -- Grid layouts -- Card grids - -## Navigation Control - -### Adding to Menu - -```ini -menu = true -menu_order = 1 -``` - -- **menu**: Set to `true` to include in site navigation -- **menu_order**: Controls order (lower numbers appear first) - -**Example** - Setting up main navigation: - -**content/blog/metadata.ini**: -```ini -menu = true -menu_order = 1 -title = "Blog" -``` - -**content/about/metadata.ini**: -```ini -menu = true -menu_order = 2 -title = "About" -``` - -**content/contact/metadata.ini**: -```ini -menu = true -menu_order = 3 -title = "Contact" -``` - -Result: Navigation shows "Blog", "About", "Contact" in that order. - -## Template Control - -### Choosing List Template - -For directories with subdirectories, control which list template is used: - -```ini -page_template = "list-grid" -``` - -Available templates: -- `list` - Simple list (default) -- `list-grid` - Grid with cover images -- `list-card-grid` - Card-style grid (supports PDFs, external links) -- `list-faq` - Expandable FAQ format - -**Example** - Blog with grid layout: - -**content/blog/metadata.ini**: -```ini -title = "Blog" -page_template = "list-grid" -``` - -## External Redirects - -Make a directory item link externally (used with `list-card-grid`): - -```ini -redirect = "https://example.com" -``` - -**Example** - Portfolio with external links: - -**content/portfolio/project-live-site/metadata.ini**: -```ini -title = "Visit Live Site" -summary = "Check out the deployed project." -redirect = "https://myproject.com" -``` - -When using the `list-card-grid` template, this creates a card that links to the external URL instead of an internal page. - -## Multi-Language Metadata - -Use sections for language-specific overrides: - -```ini -; Default language values -title = "About Us" -summary = "Learn more about our company." - -[no] -title = "Om Oss" -summary = "LΓ¦r mer om vΓ₯rt selskap." -slug = "om-oss" - -[fr] -title = "Γ Propos" -summary = "DΓ©couvrez notre entreprise." -slug = "a-propos" -``` - -Language sections override base values for that language. - -### Translated Slugs - -The `slug` field in language sections changes the URL: - -```ini -[no] -slug = "om-oss" -``` - -Now the Norwegian version is accessible at `/no/om-oss/` instead of `/no/about/`. - -## Custom Metadata Fields - -You can add any custom fields you need: - -```ini -title = "Article Title" -author = "Jane Doe" -reading_time = "5 min" -difficulty = "intermediate" -featured = true -``` - -Access these in custom templates: - -```php - - - - - - = htmlspecialchars($metadata['reading_time']) ?> - -``` - -## Arrays in Metadata - -INI format supports arrays using repeated keys: - -```ini -tags[] = "PHP" -tags[] = "Web Development" -tags[] = "Tutorial" - -categories[] = "Programming" -categories[] = "Backend" -``` - -Access in templates: - -```php - - - -``` - -## Boolean Values - -Use `true`, `false`, `1`, `0`, `yes`, `no`, `on`, `off`: - -```ini -menu = true -featured = yes -draft = false -``` - -## Comments - -Add comments with `;` or `#`: - -```ini -; This is a comment -title = "My Page" - -# This is also a comment -date = "2025-11-02" -``` - -## Metadata Inheritance - -Metadata does **not** inherit from parent directories. Each directory needs its own `metadata.ini`. - -## Metadata for List Items - -When a directory is displayed in a list view, FolderWeb loads its metadata: - -**content/blog/2025-11-01-first-post/metadata.ini**: -```ini -title = "My First Blog Post" -date = "2025-11-01" -summary = "An introduction to blogging with FolderWeb." -``` - -This metadata appears in the blog listing at `/blog/`. - -## Complete Example: Blog Setup - -### Blog Directory Metadata - -**content/blog/metadata.ini**: -```ini -title = "Blog" -menu = true -menu_order = 1 -page_template = "list-grid" - -[no] -title = "Blogg" -slug = "blogg" -``` - -### Individual Post Metadata - -**content/blog/2025-11-02-web-performance/metadata.ini**: -```ini -title = "Optimizing Web Performance" -date = "2025-11-02" -summary = "Learn techniques to make your website faster." -author = "Jane Developer" -reading_time = "8 min" - -tags[] = "Performance" -tags[] = "Web Development" -tags[] = "Optimization" - -categories[] = "Technical" -categories[] = "Tutorial" - -[no] -title = "Optimalisering av Nettsideytelse" -summary = "LΓ¦r teknikker for Γ₯ gjΓΈre nettsiden din raskere." -``` - -## Accessing Metadata in Templates - -### In Page Templates - -```php - - -= htmlspecialchars($item['summary']) ?>
- - - -Viewing in default language
- - - -About -``` - -## Best Practices - -### Keep It Simple - -Only configure what's necessary. FolderWeb embraces sensible defaults. - -### Match Translation Files - -Ensure translation files exist for all languages: - -```ini -[languages] -available = "en,no,fr" -``` - -Requires: -- `custom/languages/en.ini` -- `custom/languages/no.ini` -- `custom/languages/fr.ini` - -### Choose Appropriate Default - -Your default language should be: -- Your primary audience's language -- The language with most content -- The language you'll maintain long-term - -### Document Your Choices - -Add comments to explain configuration: - -```ini -; Site uses English as primary language (most content) -; Norwegian and French are secondary translations -[languages] -default = "en" -available = "en,no,fr" -``` - -## Testing Configuration Changes - -After changing configuration: - -1. **Clear browser cache** (Ctrl+Shift+R or Cmd+Shift+R) -2. **Test default language**: Visit `/` -3. **Test other languages**: Visit `/no/`, `/fr/`, etc. -4. **Check navigation**: Ensure menu links include language prefix -5. **Verify translations**: Check UI strings change per language -6. **Test language switcher**: Confirm switching works - -## Related - -- [Multi-Language Guide](../how-to/multi-language.md) -- [Translation Reference](translations.md) -- [Metadata Reference](metadata.md) -- [Context Object Reference](templates.md#context-object) diff --git a/docs/reference/css-variables.md b/docs/reference/css-variables.md deleted file mode 100644 index 135978d..0000000 --- a/docs/reference/css-variables.md +++ /dev/null @@ -1,538 +0,0 @@ -# CSS Variables Reference - -Complete reference for all CSS custom properties available in FolderWeb. - -## Overview - -FolderWeb uses CSS custom properties (variables) for theming. Override these in `/custom/styles/base.css` to customize your site's appearance. - -## Color Variables - -### Primary Colors - -```css -:root { - --color-primary: oklch(0.65 0.15 250); - --color-secondary: oklch(0.50 0.12 250); - --color-light: oklch(0.97 0.01 250); - --color-grey: oklch(0.37 0 0); -} -``` - -| Variable | Default | Description | -|----------|---------|-------------| -| `--color-primary` | Blue (OKLCH) | Primary brand color, links, buttons | -| `--color-secondary` | Dark blue (OKLCH) | Secondary accents, hover states | -| `--color-light` | Off-white (OKLCH) | Background, light sections | -| `--color-grey` | Dark grey | Body text, headings | - -### OKLCH Color Space - -FolderWeb uses OKLCH for perceptually uniform colors: - -```css -oklch(lightness chroma hue) -``` - -- **Lightness**: 0 (black) to 1 (white) -- **Chroma**: 0 (grey) to ~0.4 (vibrant) -- **Hue**: 0-360 degrees - -**Examples**: -```css -/* Blue hues (250Β°) */ ---color-primary: oklch(0.65 0.15 250); - -/* Orange hues (30Β°) */ ---color-primary: oklch(0.65 0.20 30); - -/* Green hues (150Β°) */ ---color-primary: oklch(0.60 0.15 150); - -/* Red hues (0Β°) */ ---color-primary: oklch(0.60 0.20 0); - -/* Purple hues (300Β°) */ ---color-primary: oklch(0.60 0.18 300); -``` - -### Alternative Color Formats - -You can use hex, rgb, or hsl instead: - -```css -:root { - /* Hex */ - --color-primary: #4169E1; - --color-secondary: #1E3A8A; - - /* RGB */ - --color-primary: rgb(65, 105, 225); - --color-secondary: rgb(30, 58, 138); - - /* HSL */ - --color-primary: hsl(225, 73%, 57%); - --color-secondary: hsl(225, 64%, 33%); -} -``` - -## Typography Variables - -### Font Families - -```css -:root { - --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; - --font-heading: Georgia, "Times New Roman", serif; -} -``` - -| Variable | Default | Description | -|----------|---------|-------------| -| `--font-body` | System sans-serif stack | Body text, paragraphs | -| `--font-heading` | Serif stack | Headings (h1-h6) | - -**Custom Fonts**: -```css -@font-face { - font-family: 'MyFont'; - src: url('/custom/fonts/MyFont.woff2') format('woff2'); - font-weight: 400; - font-style: normal; - font-display: swap; -} - -:root { - --font-body: 'MyFont', sans-serif; -} -``` - -### Font Sizes - -```css -:root { - --font-size-base: 1.125rem; /* 18px */ - --font-size-small: 0.875rem; /* 14px */ -} -``` - -| Variable | Default | Description | -|----------|---------|-------------| -| `--font-size-base` | 1.125rem (18px) | Body text size | -| `--font-size-small` | 0.875rem (14px) | Small text, metadata | - -**Responsive Sizing**: -```css -:root { - /* Fluid typography */ - --font-size-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem); -} - -h1 { - font-size: clamp(2rem, 1.5rem + 2vw, 3.5rem); -} -``` - -### Line Heights - -```css -:root { - --line-height-base: 1.6; - --line-height-heading: 1.2; -} -``` - -| Variable | Default | Description | -|----------|---------|-------------| -| `--line-height-base` | 1.6 | Body text line height | -| `--line-height-heading` | 1.2 | Heading line height | - -## Spacing Variables - -```css -:root { - --spacing-unit: 1.5rem; /* 24px */ - --spacing-small: 0.75rem; /* 12px */ - --spacing-large: 3rem; /* 48px */ -} -``` - -| Variable | Default | Description | -|----------|---------|-------------| -| `--spacing-unit` | 1.5rem (24px) | Base spacing unit | -| `--spacing-small` | 0.75rem (12px) | Small gaps | -| `--spacing-large` | 3rem (48px) | Large gaps, section spacing | - -**Usage**: -```css -.card { - padding: var(--spacing-unit); - margin-block-end: var(--spacing-large); -} - -.tag { - padding: var(--spacing-small); -} -``` - -**Responsive Spacing**: -```css -:root { - --spacing-unit: clamp(1rem, 0.8rem + 1vw, 2rem); -} -``` - -## Layout Variables - -```css -:root { - --max-width: 70rem; /* 1120px */ - --border-radius: 4px; -} -``` - -| Variable | Default | Description | -|----------|---------|-------------| -| `--max-width` | 70rem (1120px) | Content max-width | -| `--border-radius` | 4px | Corner rounding | - -**Usage**: -```css -.contain { - max-inline-size: var(--max-width); - margin-inline: auto; -} - -.card { - border-radius: var(--border-radius); -} -``` - -## Complete Variable List - -```css -:root { - /* Colors */ - --color-primary: oklch(0.65 0.15 250); - --color-secondary: oklch(0.50 0.12 250); - --color-light: oklch(0.97 0.01 250); - --color-grey: oklch(0.37 0 0); - - /* Typography */ - --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; - --font-heading: Georgia, "Times New Roman", serif; - --font-size-base: 1.125rem; - --font-size-small: 0.875rem; - --line-height-base: 1.6; - --line-height-heading: 1.2; - - /* Spacing */ - --spacing-unit: 1.5rem; - --spacing-small: 0.75rem; - --spacing-large: 3rem; - - /* Layout */ - --max-width: 70rem; - --border-radius: 4px; -} -``` - -## Customization Examples - -### Orange Theme - -```css -:root { - --color-primary: oklch(0.65 0.20 30); - --color-secondary: oklch(0.50 0.18 30); - --color-light: oklch(0.97 0.01 30); -} -``` - -### Dark Mode - -```css -@media (prefers-color-scheme: dark) { - :root { - --color-primary: oklch(0.70 0.15 250); - --color-secondary: oklch(0.80 0.12 250); - --color-light: oklch(0.25 0 0); - --color-grey: oklch(0.90 0 0); - } -} -``` - -### Large Text - -```css -:root { - --font-size-base: 1.25rem; /* 20px */ - --line-height-base: 1.7; - --spacing-unit: 2rem; -} -``` - -### Tight Layout - -```css -:root { - --max-width: 50rem; /* 800px */ - --spacing-unit: 1rem; /* 16px */ - --spacing-large: 2rem; /* 32px */ -} -``` - -### Rounded Design - -```css -:root { - --border-radius: 12px; -} -``` - -## Using Variables - -### In Your Styles - -```css -.card { - background: var(--color-light); - color: var(--color-grey); - padding: var(--spacing-unit); - border-radius: var(--border-radius); -} - -.button { - background: var(--color-primary); - color: white; - padding: var(--spacing-small) var(--spacing-unit); - border-radius: var(--border-radius); -} - -.button:hover { - background: var(--color-secondary); -} -``` - -### With Fallbacks - -Provide fallbacks for older browsers: - -```css -.card { - background: #F5F5F5; /* Fallback */ - background: var(--color-light); /* Variable */ -} -``` - -### With calc() - -Combine with calculations: - -```css -.card { - padding: calc(var(--spacing-unit) * 2); - margin-block-end: calc(var(--spacing-large) - 1rem); -} -``` - -### With color-mix() - -Create variations: - -```css -.button { - background: var(--color-primary); -} - -.button:hover { - background: color-mix(in oklch, var(--color-primary), black 10%); -} - -.button-light { - background: color-mix(in oklch, var(--color-primary), white 80%); -} -``` - -## Adding Custom Variables - -Define your own variables: - -```css -:root { - /* Custom color palette */ - --color-accent: oklch(0.70 0.15 180); - --color-warning: oklch(0.70 0.20 60); - --color-danger: oklch(0.60 0.20 10); - --color-success: oklch(0.65 0.15 140); - - /* Custom spacing */ - --spacing-xs: 0.25rem; - --spacing-xl: 4rem; - --spacing-2xl: 6rem; - - /* Custom typography */ - --font-mono: 'Monaco', 'Courier New', monospace; - --font-size-large: 1.5rem; - --font-size-xlarge: 2rem; - - /* Custom layout */ - --sidebar-width: 20rem; - --header-height: 4rem; - --content-gap: 2rem; -} -``` - -Use them: - -```css -.sidebar { - width: var(--sidebar-width); - background: var(--color-light); -} - -code { - font-family: var(--font-mono); - background: var(--color-accent); - padding: var(--spacing-xs); -} -``` - -## Scoped Variables - -Override variables for specific sections: - -```css -/* Global defaults */ -:root { - --color-primary: oklch(0.65 0.15 250); -} - -/* Blog section uses green */ -.section-blog { - --color-primary: oklch(0.60 0.15 150); -} - -/* About page uses orange */ -.page-about { - --color-primary: oklch(0.65 0.20 30); -} - -/* Variables cascade to children */ -.section-blog .button { - background: var(--color-primary); /* Green in blog */ -} -``` - -## Responsive Variables - -Change variables at breakpoints: - -```css -:root { - --spacing-unit: 1rem; - --font-size-base: 1rem; - --max-width: 60rem; -} - -@media (min-width: 768px) { - :root { - --spacing-unit: 1.5rem; - --font-size-base: 1.125rem; - --max-width: 70rem; - } -} - -@media (min-width: 1200px) { - :root { - --spacing-unit: 2rem; - --font-size-base: 1.25rem; - --max-width: 80rem; - } -} -``` - -## Browser Support - -CSS custom properties are supported in all modern browsers: -- Chrome 49+ -- Firefox 31+ -- Safari 9.1+ -- Edge 15+ - -For older browsers, provide fallbacks or use PostCSS with custom properties plugin. - -## Debugging Variables - -Inspect variables in browser DevTools: - -1. Right-click element β Inspect -2. Check "Computed" tab -3. Scroll to custom properties section -4. See resolved values - -Or log in console: - -```javascript -getComputedStyle(document.documentElement).getPropertyValue('--color-primary') -``` - -## Best Practices - -### Use Semantic Names - -```css -/* Good - semantic */ ---color-primary ---color-text ---color-background - -/* Avoid - non-semantic */ ---color-blue ---color-444 -``` - -### Group Related Variables - -```css -:root { - /* Colors */ - --color-primary: ...; - --color-secondary: ...; - - /* Typography */ - --font-body: ...; - --font-heading: ...; - - /* Spacing */ - --spacing-unit: ...; -} -``` - -### Document Your Variables - -```css -:root { - /* Brand colors from design system */ - --color-primary: oklch(0.65 0.15 250); /* Blue - primary CTA */ - --color-secondary: oklch(0.50 0.12 250); /* Dark blue - accents */ - - /* Layout constraints */ - --max-width: 70rem; /* 1120px - content max width */ -} -``` - -### Provide Fallbacks - -```css -.card { - background: #F5F5F5; - background: var(--color-light); -} -``` - -## Related - -- [Custom Styles Guide](../how-to/custom-styles.md) -- [Template Reference](templates.md) -- [File Structure Reference](file-structure.md) diff --git a/docs/reference/file-structure.md b/docs/reference/file-structure.md deleted file mode 100644 index 9e86833..0000000 --- a/docs/reference/file-structure.md +++ /dev/null @@ -1,394 +0,0 @@ -# File Structure Reference - -Complete reference for FolderWeb's file and directory structure. - -## Root Structure - -``` -project/ -βββ app/ # Framework core (never modify) -βββ content/ # Your website content -βββ custom/ # Your customizations -βββ .htaccess # Web server configuration (optional) -``` - -## App Directory (Framework Core) - -``` -app/ -βββ router.php # Main entry point and request router -βββ content.php # Content discovery and parsing functions -βββ rendering.php # Template rendering engine -βββ context.php # Context object (readonly class) -βββ config.php # Configuration loader -βββ helpers.php # Utility functions -βββ constants.php # File extension constants -βββ static.php # Static file server -βββ config.ini # Default configuration -βββ default/ # Default files (fallback) -β βββ templates/ # Default templates -β β βββ base.php # HTML wrapper -β β βββ page.php # Page wrapper -β β βββ list.php # Simple list -β β βββ list-grid.php # Grid layout -β β βββ list-card-grid.php # Card grid -β β βββ list-faq.php # FAQ layout -β βββ styles/ # Default CSS -β β βββ base.css # Main stylesheet -β βββ languages/ # Default translations -β β βββ en.ini # English -β β βββ no.ini # Norwegian -β βββ content/ # Demo content (fallback) -βββ vendor/ # Third-party libraries - βββ Parsedown.php # Markdown parser -``` - -**Important**: Never modify files in `/app/`. All customization goes in `/custom/`. - -## Custom Directory - -``` -custom/ -βββ templates/ # Override templates -β βββ base.php # Custom base template -β βββ page.php # Custom page template -β βββ list-*.php # Custom list templates -β βββ [custom].php # Your custom templates -βββ styles/ # Override styles -β βββ base.css # Custom stylesheet -βββ languages/ # Override translations -β βββ en.ini # English translations -β βββ no.ini # Norwegian translations -β βββ [lang].ini # Other languages -βββ fonts/ # Custom web fonts -β βββ *.woff2 # Font files -βββ assets/ # Root-level assets -β βββ favicon.ico # Site favicon -β βββ robots.txt # Robots file -β βββ logo.svg # Logo -β βββ [any file] # Served at root level -βββ config.ini # Configuration overrides -``` - -## Content Directory - -Your content directory contains all your website pages and assets. - -### Basic Structure - -``` -content/ -βββ index.md # Home page -βββ about/ # About page -β βββ index.md # Page content -β βββ metadata.ini # Page metadata -β βββ team-photo.jpg # Page asset -βββ blog/ # Blog (list view) -β βββ metadata.ini # Blog configuration -β βββ 2025-11-01-first-post/ -β β βββ index.md # Post content -β β βββ cover.jpg # Cover image -β β βββ metadata.ini # Post metadata -β βββ 2025-11-02-second-post/ -β βββ index.md -β βββ cover.webp -β βββ metadata.ini -βββ docs/ # Multi-file page - βββ 00-intro.md # Section 1 - βββ 01-setup.md # Section 2 - βββ 02-usage.md # Section 3 - βββ metadata.ini # Page metadata -``` - -### Content Types - -#### Single-File Page - -``` -content/about/ -βββ index.md -``` - -URL: `/about/` - -#### Multi-File Page - -``` -content/docs/ -βββ 00-intro.md -βββ 01-setup.md -βββ 02-usage.md -``` - -URL: `/docs/` (all files render as one page) - -#### List View (Directory with Subdirectories) - -``` -content/blog/ -βββ metadata.ini -βββ 2025-11-01-post/ -β βββ index.md -βββ 2025-11-02-post/ - βββ index.md -``` - -URL: `/blog/` (shows list of posts) - -## File Naming Conventions - -### Content Files - -Supported extensions: -- `.md` - Markdown (parsed with Parsedown) -- `.html` - HTML (included as-is) -- `.php` - PHP (executed with access to `$ctx`) - -### Language-Specific Files - -Format: `filename.{lang}.ext` - -Examples: -- `index.md` - Default language -- `index.no.md` - Norwegian -- `index.fr.md` - French -- `about.en.md` - English - -### Date Prefixes - -Format: `YYYY-MM-DD-slug` - -Examples: -- `2025-11-01-my-post` -- `2025-11-02-another-post` - -Dates are automatically extracted and formatted. - -### Cover Images - -Filename: `cover.{ext}` - -Supported formats: -- `cover.jpg` -- `cover.jpeg` -- `cover.png` -- `cover.webp` -- `cover.gif` - -Automatically detected in list views. - -### PDF Files - -Any `.pdf` file in a directory is automatically linked in grid layouts. - -### Metadata Files - -Filename: `metadata.ini` - -Format: INI with optional language sections. - -## File Discovery Order - -### Content File Priority - -For multi-file pages, files are rendered in alphanumerical order: - -``` -content/docs/ -βββ 00-intro.md # First -βββ 01-setup.md # Second -βββ 02-usage.md # Third -βββ 99-appendix.md # Last -``` - -Use numerical prefixes to control order. - -### Template Resolution - -Templates are resolved with custom fallback: - -1. `/custom/templates/{name}.php` -2. `/app/default/templates/{name}.php` - -### CSS Resolution - -Stylesheets are resolved with custom fallback: - -1. `/custom/styles/base.css` -2. `/app/default/styles/base.css` - -### Translation Resolution - -Translations are resolved with custom fallback: - -1. `/custom/languages/{lang}.ini` -2. `/app/default/languages/{lang}.ini` - -### Configuration Resolution - -Configuration is merged: - -1. Load `/app/config.ini` -2. Merge with `/custom/config.ini` if exists - -Custom values override defaults. - -## URL Mapping - -### Basic Mapping - -``` -/content/about/index.md β /about/ -/content/blog/ β /blog/ -/content/docs/ β /docs/ -``` - -### Language Prefixes - -Default language (no prefix): -``` -/content/about/index.md β /about/ -``` - -Other languages (with prefix): -``` -/content/about/index.no.md β /no/about/ -/content/about/index.fr.md β /fr/about/ -``` - -### Translated Slugs - -With metadata slug overrides: -``` -content/about/metadata.ini: - [no] - slug = "om-oss" - - [fr] - slug = "a-propos" -``` - -URLs become: -- `/about/` (English) -- `/no/om-oss/` (Norwegian) -- `/fr/a-propos/` (French) - -### Trailing Slashes - -FolderWeb requires trailing slashes for directories. Missing slashes trigger 301 redirects: - -``` -/blog β 301 redirect to β /blog/ -``` - -## Special Files and Directories - -### System Files (Ignored) - -These files are automatically ignored: -- `.htaccess` -- `.git/` -- `.DS_Store` -- `node_modules/` -- Hidden files/directories (starting with `.`) - -### Index Files - -`index.md`, `index.html`, `index.php` are treated as directory content, not separate routes. - -### Metadata Files - -`metadata.ini` files are configuration, never rendered as content. - -## Asset Serving - -### Root-Level Assets - -Files in `/custom/assets/` are served at site root: - -``` -/custom/assets/robots.txt β yoursite.com/robots.txt -/custom/assets/favicon.ico β yoursite.com/favicon.ico -/custom/assets/logo.svg β yoursite.com/logo.svg -``` - -### Content Assets - -Files in content directories are accessible at their directory URL: - -``` -/content/blog/2025-11-01-post/cover.jpg - β yoursite.com/blog/2025-11-01-post/cover.jpg - -/content/about/team-photo.jpg - β yoursite.com/about/team-photo.jpg -``` - -### CSS Files - -CSS is served with version hashing: - -``` -/custom/styles/base.css - β yoursite.com/app/styles/base.css?v=abc123def456 -``` - -### Font Files - -Fonts in `/custom/fonts/` are accessible: - -``` -/custom/fonts/MyFont.woff2 - β yoursite.com/custom/fonts/MyFont.woff2 -``` - -## File Permissions - -### Readable Files - -The web server must have read access to: -- All files in `/app/` -- All files in `/content/` -- All files in `/custom/` - -### Writable Files - -FolderWeb is read-only. No files require write access. - -### Security - -- Path validation prevents directory traversal -- Files must be within document root -- Realpath checks ensure proper resolution - -## Size Limits - -- **Read Tool**: Files larger than 50KB are truncated -- **No upload limits**: FolderWeb doesn't handle uploads -- **No execution limits**: Standard PHP limits apply - -## Caching - -### CSS Versioning - -CSS files are versioned with MD5 hash: - -```html - -``` - -Hash updates when file content changes. - -### No Built-in Cache - -FolderWeb doesn't implement content caching. Use: -- Web server caching (Apache, Nginx) -- Reverse proxy (Varnish, Cloudflare) -- PHP OPcache for code - -## Related - -- [Metadata Reference](metadata.md) -- [Configuration Reference](configuration.md) -- [How to Customize Templates](../how-to/custom-templates.md) -- [How to Customize Styles](../how-to/custom-styles.md) diff --git a/docs/reference/metadata.md b/docs/reference/metadata.md deleted file mode 100644 index 3bbb381..0000000 --- a/docs/reference/metadata.md +++ /dev/null @@ -1,610 +0,0 @@ -# Metadata Reference - -Complete reference for all metadata fields and their usage in `metadata.ini` files. - -## File Format - -Metadata files use INI format: - -```ini -; Comments start with semicolon -key = "value" -array[] = "value1" -array[] = "value2" - -[section] -key = "section value" -``` - -## Standard Fields - -### title - -**Type**: String -**Used in**: All content types -**Purpose**: Override automatic title extraction - -```ini -title = "Custom Page Title" -``` - -If not provided, FolderWeb extracts title from: -1. First H1 heading (`# Title` in Markdown) -2. Folder name (as fallback) - -**Multi-language**: -```ini -title = "English Title" - -[no] -title = "Norsk Tittel" - -[fr] -title = "Titre FranΓ§ais" -``` - -### date - -**Type**: Date string (YYYY-MM-DD) -**Used in**: Blog posts, articles -**Purpose**: Override automatic date extraction - -```ini -date = "2025-11-02" -``` - -If not provided, FolderWeb extracts date from folder names like `2025-11-02-post-title`. - -Dates are automatically formatted in Norwegian style: "2. november 2025" - -### summary - -**Type**: String -**Used in**: List views -**Purpose**: Brief description for cards and listings - -```ini -summary = "A concise description that appears in blog listings." -``` - -**Multi-language**: -```ini -summary = "English summary" - -[no] -summary = "Norsk sammendrag" -``` - -### menu - -**Type**: Boolean -**Used in**: Top-level directories -**Purpose**: Include in site navigation - -```ini -menu = true -``` - -Accepted values: `true`, `false`, `1`, `0`, `yes`, `no`, `on`, `off` - -### menu_order - -**Type**: Integer -**Used in**: Navigation items -**Purpose**: Control navigation order (lower numbers first) - -```ini -menu = true -menu_order = 1 -``` - -### page_template - -**Type**: String -**Used in**: Directories with subdirectories -**Purpose**: Choose list template - -```ini -page_template = "list-grid" -``` - -Available values: -- `list` - Simple list (default) -- `list-grid` - Grid with cover images -- `list-card-grid` - Card-style grid -- `list-faq` - Expandable FAQ format -- Any custom template name (without `.php` extension) - -### slug - -**Type**: String -**Used in**: Language sections -**Purpose**: Translate URL segments - -```ini -[no] -slug = "om-oss" - -[fr] -slug = "a-propos" -``` - -The actual folder is `about/`, but URLs become: -- `/about/` (English) -- `/no/om-oss/` (Norwegian) -- `/fr/a-propos/` (French) - -### redirect - -**Type**: URL string -**Used in**: List items (with `list-card-grid` template) -**Purpose**: Link to external site instead of internal page - -```ini -redirect = "https://example.com" -``` - -Creates an external link card in card grid layouts. - -## Custom Fields - -You can add any custom fields for use in your templates: - -### Common Custom Fields - -```ini -; Author information -author = "Jane Doe" -author_email = "jane@example.com" -author_url = "https://janedoe.com" - -; Content metadata -reading_time = "5 min" -difficulty = "intermediate" -featured = true - -; Categorization -tags[] = "PHP" -tags[] = "Tutorial" -tags[] = "Web Development" - -categories[] = "Programming" -categories[] = "Backend" - -; SEO -meta_description = "Complete guide to FolderWeb metadata" -meta_keywords = "metadata, ini, folderweb" - -; Social sharing -og_image = "/blog/post/social-card.jpg" -twitter_card = "summary_large_image" - -; Version tracking -version = "1.2.0" -last_updated = "2025-11-02" - -; Display options -hide_date = true -hide_author = false -show_toc = true - -; External references -github_url = "https://github.com/user/repo" -demo_url = "https://demo.example.com" -download_url = "/files/document.pdf" -``` - -## Array Fields - -Use `[]` syntax for array values: - -```ini -tags[] = "PHP" -tags[] = "Web Development" -tags[] = "Tutorial" - -authors[] = "Jane Doe" -authors[] = "John Smith" - -related_posts[] = "/blog/post-1/" -related_posts[] = "/blog/post-2/" -``` - -Access in templates: - -```php - - = htmlspecialchars($tag) ?> - -``` - -## Boolean Values - -Accepted boolean formats: - -```ini -; True values -featured = true -featured = 1 -featured = yes -featured = on - -; False values -draft = false -draft = 0 -draft = no -draft = off -``` - -## Language Sections - -Use `[lang]` sections for multi-language overrides: - -```ini -; Base values (default language) -title = "About Us" -summary = "Learn about our company" -slug = "about" - -; Norwegian overrides -[no] -title = "Om Oss" -summary = "LΓ¦r om vΓ₯rt selskap" -slug = "om-oss" - -; French overrides -[fr] -title = "Γ Propos" -summary = "DΓ©couvrez notre entreprise" -slug = "a-propos" - -; Fields not overridden inherit base values -``` - -Language-specific fields override base fields for that language. - -## Comments - -Use `;` or `#` for comments: - -```ini -; This is a comment -title = "My Page" - -# This is also a comment -date = "2025-11-02" - -; Comments can be on same line as values -menu = true ; Include in navigation -``` - -## Special Characters - -### Quotes - -Use quotes for values with special characters: - -```ini -; Optional for simple values -title = Simple Title -title = "Simple Title" - -; Required for values with spaces at start/end -title = " Padded Title " - -; Required for values with special characters -summary = "Use \"quotes\" for nested quotes" -summary = 'Single quotes work too' -``` - -### Escape Sequences - -Standard INI escape sequences: - -```ini -; Newline -text = "First line\nSecond line" - -; Tab -text = "Indented\ttext" - -; Quote -text = "He said \"Hello\"" -``` - -## Metadata Location - -### Directory Metadata - -Place `metadata.ini` in the directory it describes: - -``` -content/blog/metadata.ini # Blog configuration -content/about/metadata.ini # About page metadata -``` - -### Item Metadata - -Place `metadata.ini` in each subdirectory: - -``` -content/blog/2025-11-01-post/metadata.ini # Post metadata -content/blog/2025-11-02-post/metadata.ini # Post metadata -``` - -## Metadata Scope - -Metadata applies only to its directory. **No inheritance** from parent directories. - -## Complete Examples - -### Blog Configuration - -**content/blog/metadata.ini**: -```ini -; Display settings -title = "Blog" -page_template = "list-grid" - -; Navigation -menu = true -menu_order = 1 - -; Multi-language -[no] -title = "Blogg" -slug = "blogg" - -[fr] -title = "Blog" -slug = "blog" -``` - -### Blog Post - -**content/blog/2025-11-02-web-performance/metadata.ini**: -```ini -; Basic information -title = "Optimizing Web Performance" -date = "2025-11-02" -summary = "Learn techniques to make your website faster." - -; Author information -author = "Jane Developer" -author_url = "https://jane.dev" - -; Content metadata -reading_time = "8 min" -difficulty = "intermediate" -featured = true - -; Categorization -tags[] = "Performance" -tags[] = "Web Development" -tags[] = "Optimization" - -categories[] = "Technical" -categories[] = "Tutorial" - -; SEO -meta_description = "Complete guide to web performance optimization" - -; Multi-language versions -[no] -title = "Optimalisering av Nettsideytelse" -summary = "LΓ¦r teknikker for Γ₯ gjΓΈre nettsiden din raskere." - -[fr] -title = "Optimisation des Performances Web" -summary = "Apprenez Γ accΓ©lΓ©rer votre site web." -``` - -### Documentation Page - -**content/docs/metadata.ini**: -```ini -title = "Documentation" -menu = true -menu_order = 2 -page_template = "list" - -; Custom fields -show_toc = true -github_url = "https://github.com/user/repo" - -[no] -title = "Dokumentasjon" -slug = "dokumentasjon" -``` - -### Portfolio Project - -**content/portfolio/project-name/metadata.ini**: -```ini -title = "Project Name" -date = "2025-11-02" -summary = "Brief project description" - -; External links -redirect = "https://project-demo.com" -github_url = "https://github.com/user/project" - -; Project details -client = "Company Name" -role = "Lead Developer" -technologies[] = "PHP" -technologies[] = "HTML" -technologies[] = "CSS" - -[no] -title = "Prosjektnavn" -summary = "Kort prosjektbeskrivelse" -``` - -### FAQ Section - -**content/faq/metadata.ini**: -```ini -title = "Frequently Asked Questions" -menu = true -menu_order = 4 -page_template = "list-faq" - -[no] -title = "Ofte Stilte SpΓΈrsmΓ₯l" -slug = "oss" - -[fr] -title = "Questions FrΓ©quemment PosΓ©es" -slug = "faq" -``` - -## Accessing Metadata in Templates - -### In Page Templates - -Variable: `$pageMetadata` - -```php - - -= htmlspecialchars($item['summary']) ?>
- -By = htmlspecialchars($metadata['author']) ?>
- -``` - -### Use Consistent Field Names - -Stick to standard names across your site: -- `author` not `writer` or `by` -- `tags` not `keywords` or `topics` -- `summary` not `description` or `excerpt` - -### Document Custom Fields - -Add comments explaining non-obvious fields: - -```ini -; Featured articles appear at top of homepage -featured = true - -; External demo link (overrides internal page) -demo_url = "https://demo.example.com" -``` - -## Related - -- [Multi-Language Guide](../how-to/multi-language.md) -- [Working with Metadata](../how-to/working-with-metadata.md) -- [Template Variables Reference](templates.md) -- [Configuration Reference](configuration.md) diff --git a/docs/reference/templates.md b/docs/reference/templates.md deleted file mode 100644 index 0fe7beb..0000000 --- a/docs/reference/templates.md +++ /dev/null @@ -1,608 +0,0 @@ -# Template Reference - -Complete reference for all templates and available variables in FolderWeb. - -## Template System Overview - -FolderWeb uses a fallback template system: -1. Check `/custom/templates/{name}.php` -2. Fall back to `/app/default/templates/{name}.php` - -Templates are plain PHP files with access to specific variables and the context object. - -## Core Templates - -### base.php - -**Purpose**: HTML wrapper for all pages (header, navigation, footer) -**Used**: On every page render -**Customizable**: Yes - -**Available Variables**: - -| Variable | Type | Description | -|----------|------|-------------| -| `$content` | string | Rendered page content (HTML) | -| `$ctx` | Context | Full context object | -| `$currentLang` | string | Current language code (e.g., "en", "no") | -| `$navigation` | array | Navigation menu items | -| `$homeLabel` | string | Site title | -| `$translations` | array | UI translation strings | -| `$pageTitle` | string | Current page title | -| `$dirName` | string | Parent directory name | -| `$pageName` | string | Current page filename | - -**Example**: -```php - - - - -= htmlspecialchars($item['summary']) ?>
- -= htmlspecialchars($item['summary']) ?>
- - -= htmlspecialchars($item['summary']) ?>
- - - - - Visit Site - - - - Download PDF - - - - View Details - - -= htmlspecialchars($item['summary']) ?>
- - - - = $translations['read_more'] ?> - -