{"id":45294453,"url":"https://github.com/rokde/laravel-pergament","last_synced_at":"2026-02-22T04:01:13.232Z","repository":{"id":338611964,"uuid":"1158433453","full_name":"rokde/laravel-pergament","owner":"rokde","description":"A file-based CMS package for Laravel. Renders documentation, blog posts, standalone pages from markdown files with YAML front matter.","archived":false,"fork":false,"pushed_at":"2026-02-20T22:18:33.000Z","size":145,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-21T07:38:11.986Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rokde.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":"https://www.paypal.me/rok","buy_me_a_coffee":"robertkummer"}},"created_at":"2026-02-15T11:14:30.000Z","updated_at":"2026-02-20T22:18:37.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rokde/laravel-pergament","commit_stats":null,"previous_names":["rokde/laravel-pergament"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rokde/laravel-pergament","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rokde%2Flaravel-pergament","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rokde%2Flaravel-pergament/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rokde%2Flaravel-pergament/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rokde%2Flaravel-pergament/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rokde","download_url":"https://codeload.github.com/rokde/laravel-pergament/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rokde%2Flaravel-pergament/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29704420,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-22T03:17:42.375Z","status":"ssl_error","status_checked_at":"2026-02-22T03:17:31.622Z","response_time":110,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-21T03:35:24.880Z","updated_at":"2026-02-22T04:01:13.211Z","avatar_url":"https://github.com/rokde.png","language":"PHP","funding_links":["https://www.paypal.me/rok","https://buymeacoffee.com/robertkummer"],"categories":[],"sub_categories":[],"readme":"# Laravel Pergament\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/rokde/laravel-pergament.svg?style=flat-square)](https://packagist.org/packages/rokde/laravel-pergament)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/rokde/laravel-pergament/tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/rokde/laravel-pergament/actions/workflows/tests.yml?query=branch%3Amain)\n[![Total Downloads](https://img.shields.io/packagist/dt/rokde/laravel-pergament.svg?style=flat-square)](https://packagist.org/packages/rokde/laravel-pergament)\n\nA file-based CMS package for Laravel. Renders documentation, blog posts, and standalone pages from Markdown files with YAML front matter. Blade templates, Tailwind CSS, dark mode, server-side syntax highlighting — no database required.\n\n## Installation\n\nAdd the package via Composer:\n\n```bash\ncomposer require rokde/laravel-pergament\n```\n\nPublish the configuration:\n\n```bash\nphp artisan vendor:publish --tag=pergament-config\n```\n\nPublish the views (optional, for customization):\n\n```bash\nphp artisan vendor:publish --tag=pergament-views\n```\n\n## Configuration\n\nThe main config file is `config/pergament.php`. Key options:\n\n### Base URL Prefix\n\nControl where Pergament listens. All routes are nested under this prefix:\n\n```php\n'prefix' =\u003e '/',                    // Pergament owns the root\n'prefix' =\u003e 'docs',                 // Pergament lives at /docs/*\n'prefix' =\u003e 'landing-page/hello',   // Pergament lives at /landing-page/hello/*\n```\n\n### Content Path\n\nWhere your Markdown content lives on disk:\n\n```php\n'content_path' =\u003e base_path('content'),\n```\n\n### Homepage\n\nConfigure what shows at the base URL:\n\n```php\n'homepage' =\u003e [\n    'type' =\u003e 'page',        // \"page\", \"blog-index\", \"doc-page\", or \"redirect\"\n    'source' =\u003e 'home',      // page slug, \"chapter/page\", or redirect target\n],\n```\n\n### Documentation\n\n```php\n'docs' =\u003e [\n    'enabled' =\u003e true,\n    'path' =\u003e 'docs',            // subfolder under content_path\n    'url_prefix' =\u003e 'docs',      // URL segment: /prefix/docs/chapter/page\n    'title' =\u003e 'Documentation',\n],\n```\n\n### Blog\n\n```php\n'blog' =\u003e [\n    'enabled' =\u003e true,\n    'path' =\u003e 'blog',\n    'url_prefix' =\u003e 'blog',\n    'title' =\u003e 'Blog',\n    'per_page' =\u003e 12,\n    'default_authors' =\u003e [],\n    'feed' =\u003e [\n        'enabled' =\u003e true,\n        'type' =\u003e 'atom',        // \"atom\" or \"rss\"\n        'title' =\u003e null,\n        'description' =\u003e '',\n        'limit' =\u003e 20,\n    ],\n],\n```\n\n### Colors \u0026 Theming\n\nConfigure your brand color and page background. Both values propagate as CSS custom properties (`--p-primary`, `--p-bg`) that drive the entire UI — navigation highlights, badges, links, scrollbars, focus rings, text selection, and more:\n\n```php\n'colors' =\u003e [\n    'primary'    =\u003e '#3b82f6',   // any CSS color: hex, oklch, named…\n    'background' =\u003e '#ffffff',\n],\n```\n\nDark mode is handled automatically: the background switches to a dark slate (`#111827`) and tints derived from `--p-primary` re-resolve against it without any extra configuration.\n\n### Site \u0026 SEO\n\n```php\n'site' =\u003e [\n    'name' =\u003e env('APP_NAME', 'Pergament'),\n    'url' =\u003e env('APP_URL', 'http://localhost'),\n    'locale' =\u003e 'en',\n    'seo' =\u003e [\n        'title' =\u003e env('APP_NAME', 'Pergament'),\n        'description' =\u003e '',\n        'keywords' =\u003e '',\n        'og_image' =\u003e '',\n        'twitter_card' =\u003e 'summary_large_image',\n        'robots' =\u003e 'index, follow',\n    ],\n],\n```\n\n## Content Structure\n\n```\ncontent/\n├── docs/\n│   ├── 0-getting-started/\n│   │   ├── 01-introduction.md\n│   │   └── 02-installation.md\n│   └── 1-configuration/\n│       └── 01-basic-setup.md\n├── blog/\n│   ├── 2024-01-15-hello-world/\n│   │   ├── post.md\n│   │   └── hero.png\n│   └── 2024-03-20-new-feature/\n│       └── post.md\n└── pages/\n    ├── home.md\n    ├── about.md\n    └── pricing.md\n```\n\n### Documentation\n\nDocumentation lives in numbered chapter directories. Each chapter contains numbered Markdown files:\n\n- Directory format: `{order}-{chapter-slug}/` (e.g. `0-getting-started/`)\n- File format: `{order}-{page-slug}.md` (e.g. `01-introduction.md`)\n- The numeric prefixes control sort order and are stripped from URLs\n\n### Blog Posts\n\nBlog posts live in date-prefixed directories:\n\n- Directory format: `{YYYY-MM-DD}-{slug}/` (e.g. `2024-01-15-hello-world/`)\n- Each directory contains a `post.md` file and any associated media files\n- The date is extracted from the directory name\n\n### Standalone Pages\n\nSimple Markdown files in the `pages/` directory. The filename (without `.md`) becomes the URL slug.\n\n## Front Matter\n\nAll content files use YAML front matter delimited by `---`:\n\n```markdown\n---\ntitle: My Page Title\nexcerpt: A brief description shown on index pages\n---\n\n# My Page Title\n\nContent goes here.\n```\n\n### Documentation Front Matter\n\n```yaml\n---\ntitle: Introduction\nexcerpt: Getting started with Pergament\n---\n```\n\n### Blog Post Front Matter\n\n```yaml\n---\ntitle: \"Hello World\"\nexcerpt: \"Our very first blog post\"\ncategory: \"Announcements\"\ntags:\n  - \"laravel\"\n  - \"pergament\"\nauthor: \"Jane Doe\"\n---\n```\n\nYou can also define multiple authors with details:\n\n```yaml\nauthors:\n  - name: \"Jane Doe\"\n    email: \"jane@example.com\"\n    url: \"https://janedoe.com\"\n    avatar: \"https://example.com/avatar.jpg\"\n  - name: \"John Smith\"\n```\n\n### Page Front Matter\n\n```yaml\n---\ntitle: About Us\nexcerpt: Learn more about our company\nlayout: landing\n---\n```\n\nSet `layout: landing` to use the full-width landing page layout instead of the default centered content layout.\n\n### SEO Overrides\n\nAny page can override global SEO settings using dot notation in its front matter:\n\n```yaml\n---\ntitle: My Page\nseo.title: \"Custom SEO Title - My Site\"\nseo.description: \"A custom meta description for this specific page\"\nseo.og_image: \"https://example.com/special-og.png\"\nseo.robots: \"noindex, nofollow\"\n---\n```\n\nThese override the corresponding values from `config('pergament.site.seo.*')`.\n\n## Block-Based Landing Pages\n\nFor landing pages and homepages, you can use block directives in Markdown to create structured sections. Block directives wrap content in `\u003cdiv\u003e` elements with CSS classes for styling.\n\n### Syntax\n\n```markdown\n:::hero\n\n# Welcome to Our Product\n\nThe best solution for your needs.\n\n[Get Started](/docs/getting-started/introduction)\n\n:::\n\n:::features\n\n## Why Choose Us\n\n- **Fast** — Built for speed\n- **Reliable** — 99.9% uptime\n- **Simple** — Easy to use\n\n:::\n\n:::cta\n\n## Ready to Get Started?\n\nSign up today and see the difference.\n\n[Sign Up Free](/register)\n\n:::\n```\n\nEach `:::{name}` block becomes a `\u003cdiv class=\"pergament-block pergament-block-{name}\"\u003e` in the rendered HTML. The closing `:::` ends the block.\n\n### Built-in Block Types\n\nThe default views include basic styles for these block types:\n\n| Directive | CSS Class | Purpose |\n|-----------|-----------|---------|\n| `:::hero` | `pergament-block-hero` | Hero sections with centered text |\n| `:::features` | `pergament-block-features` | Feature grids and lists |\n| `:::cta` | `pergament-block-cta` | Call-to-action sections |\n\nYou can use any name — it maps directly to a CSS class. Custom blocks like `:::pricing`, `:::testimonials`, or `:::team` will generate `pergament-block-pricing`, `pergament-block-testimonials`, and `pergament-block-team` classes respectively.\n\n### Styling Blocks\n\nOverride the default styles by publishing the views and editing the CSS, or add your own styles targeting the generated classes:\n\n```css\n.pergament-block-hero {\n    padding: 6rem 2rem;\n    text-align: center;\n    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n    color: white;\n}\n\n.pergament-block-features {\n    display: grid;\n    grid-template-columns: repeat(3, 1fr);\n    gap: 2rem;\n    padding: 4rem 2rem;\n}\n\n.pergament-block-pricing {\n    /* your custom block styles */\n}\n```\n\n### Full Landing Page Example\n\nCreate `content/pages/home.md`:\n\n```markdown\n---\ntitle: \"My Product\"\nlayout: landing\nseo.title: \"My Product - The Best Solution\"\nseo.description: \"Discover the best solution for your needs\"\n---\n\n:::hero\n\n# My Product\n\nBuild something amazing with our platform.\n\n[Get Started](/docs/getting-started/introduction) [Learn More](#features)\n\n:::\n\n:::features\n\n## Features\n\n### Lightning Fast\nOur platform is optimized for performance at every level.\n\n### Fully Extensible\nPlugin system lets you customize everything.\n\n### Dark Mode\nBeautiful light and dark themes out of the box.\n\n:::\n\n:::cta\n\n## Start Building Today\n\nJoin thousands of developers who trust our platform.\n\n[Sign Up Free](/register)\n\n:::\n```\n\nThen set the homepage config to use it:\n\n```php\n'homepage' =\u003e [\n    'type' =\u003e 'page',\n    'source' =\u003e 'home',\n],\n```\n\n## Dark Mode\n\nThe package supports class-based dark mode. Add the `dark` class to your `\u003chtml\u003e` element to activate dark mode. All views include `dark:` Tailwind variants.\n\n### Themed Images\n\nDocumentation images can have dark/light variants that automatically switch based on the active theme. Place variant files alongside the original:\n\n```\ncontent/docs/0-getting-started/\n├── 01-introduction.md\n├── dashboard.png           # referenced in markdown\n├── dashboard.dark.png      # shown in dark mode\n└── dashboard.light.png     # shown in light mode (optional)\n```\n\nThe variant resolution works as follows:\n\n| Dark variant exists | Light variant exists | Light mode shows | Dark mode shows |\n|---|---|---|---|\n| No | No | `dashboard.png` | `dashboard.png` |\n| Yes | No | `dashboard.png` | `dashboard.dark.png` |\n| No | Yes | `dashboard.light.png` | `dashboard.png` |\n| Yes | Yes | `dashboard.light.png` | `dashboard.dark.png` |\n\n## Command Palette Search\n\nWhen search is enabled, a command palette is available on every page. Open it with `Cmd+K` (macOS) or `Ctrl+K` (other platforms), or by clicking the search input in the navigation bar.\n\n- **Real-time results** — results appear as you type, fetched from the search endpoint as JSON (no page reload)\n- **Type badges** — each result is labelled **Doc**, **Post**, or **Page**\n- **Keyboard navigation** — `↑`/`↓` to move between results, `Enter` to open, `Escape` to close\n- **Mouse navigation** — click any result to navigate\n- **Excerpt preview** — a short excerpt is shown below each title; falls back to the first 160 characters of content when no explicit excerpt is set in front matter\n- **No-JS fallback** — the nav search form submits to `/search?q=…` as before when JavaScript is unavailable\n\nSearch covers all three content types:\n\n| Type | Source |\n|------|--------|\n| Doc | Documentation pages |\n| Post | Blog posts |\n| Page | Standalone pages |\n\n## Artisan Commands\n\n### Create a documentation page\n\nWe have an interactive docs creation command. All arguments are optional, you will be guided through all necessary things.\n\n```bash\nphp artisan pergament:make:doc\n\n# Or with arguments\nphp artisan pergament:make:doc --chapter=getting-started --title=\"Installation Guide\" --order=02\n```\n\n### Create a blog post\n\n```bash\nphp artisan pergament:make:post\n\n# Or with arguments\nphp artisan pergament:make:post \\\n    --title=\"My First Post\" \\\n    --category=\"Tutorials\" \\\n    --tags=\"laravel, php\" \\\n    --author=\"Jane Doe\" \\\n    --date=2024-06-15\n```\n\nBoth commands prompt for any missing arguments interactively.\n\n## Routes\n\nAll routes are nested under the configured `prefix`. With the default `/` prefix:\n\n| Route | Description |\n|-------|-------------|\n| `/` | Homepage |\n| `/docs` | Documentation index (redirects to first page) |\n| `/docs/{chapter}/{page}` | Documentation page |\n| `/blog` | Blog index |\n| `/blog/{slug}` | Blog post |\n| `/blog/category/{category}` | Posts by category |\n| `/blog/tag/{tag}` | Posts by tag |\n| `/blog/author/{author}` | Posts by author |\n| `/blog/feed` | RSS/Atom feed |\n| `/search?q=query` | Search |\n| `/{slug}` | Standalone page |\n| `/sitemap.xml` | XML sitemap |\n| `/robots.txt` | Robots.txt |\n| `/llms.txt` | LLMs.txt |\n\nWith `prefix` set to `docs`, all routes become `/docs/...`, `/docs/blog/...`, etc.\n\n## Markdown Responses for AI \u0026 LLMs\n\nAll content pages (documentation, blog posts, standalone pages, and the homepage) can be served as plain Markdown instead of HTML. This is configurable in the exports section of the configuration.\n\nA markdown response is returned when any of the following is true:\n\n| Trigger | Example |\n|---------|---------|\n| `Accept: text/markdown` request header | `curl -H \"Accept: text/markdown\" /docs/getting-started/installation` |\n| Known AI / LLM user-agent | Requests from ChatGPT, Claude, Perplexity, etc. |\n| `.md` URL suffix | `/blog/my-post.md` |\n\nMedia files, feeds, sitemaps, and search results are excluded — only rendered HTML content pages are converted.\n\n## Features\n\n- **File-based content** — Markdown + YAML front matter, no database\n- **Documentation** — Numbered chapters/pages, sidebar navigation, TOC scrollspy, heading anchor links, themed images\n- **Blog** — Categories, tags, multiple authors, date-prefixed directories, pagination\n- **RSS/Atom feeds** — Configurable feed type and limits\n- **SEO** — Meta tags, Open Graph, Twitter Cards, per-page overrides via dot notation\n- **Sitemap** — Auto-generated XML sitemap\n- **robots.txt / llms.txt** — Auto-generated or custom content\n- **Markdown responses** — All content pages served as plain Markdown via `Accept: text/markdown`, `.md` suffix, or known AI user-agents (powered by spatie/laravel-markdown-response)\n- **Command palette search** — `Cmd+K`/`Ctrl+K` opens a live search dialog across docs, posts, and pages; keyboard navigable; no-JS form fallback\n- **PWA** — Optional manifest.json and service worker\n- **Landing pages** — Block-based content with `:::directive` syntax\n- **Dark mode** — Class-based toggle with system preference detection; dark-mode syntax highlighting\n- **Syntax highlighting** — Server-side via tempest/highlight, light and dark themes included\n- **Theming** — Configure `colors.primary` and `colors.background`; the entire UI (nav, links, badges, scrollbars, focus rings, text selection) derives from these two values via CSS custom properties\n- **Zoomable images** — Click any image to enlarge it in a lightbox; Escape or click outside to close\n- **Copy code** — Hover a code block to reveal a Copy button; switches to \"Copied\" on success\n- **Configurable prefix** — Mount the CMS at any URL path\n\n## Testing\n\n```bash\ncomposer test\n```\n\n## Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.\n\n## Contributing\n\nPlease see [CONTRIBUTING](./.github/CONTRIBUTING.md) for details.\n\n## Security Vulnerabilities\n\nPlease review [our security policy](../../security/policy) on how to report security vulnerabilities.\n\n## Credits\n\n- [Robert Kummer](https://github.com/rokde)\n- [All Contributors](../../contributors)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frokde%2Flaravel-pergament","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frokde%2Flaravel-pergament","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frokde%2Flaravel-pergament/lists"}