Added Escape key handler to close ElementPopup or PagePopup when open. The handler checks which popup is visible and calls its close method. Works in all contexts (main document and iframe) using the existing handleKeyboardShortcut function. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| .vscode | ||
| public | ||
| src | ||
| .gitignore | ||
| claude.md | ||
| Dockerfile.ci | ||
| index.html | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| vite.config.js | ||
GeoProject - Web-to-Print Interface
A web-to-print application for creating printable narratives with real-time layout editing.
Overview
GeoProject is a sophisticated web-to-print platform that combines:
- Kirby CMS for content management
- Vue 3 for interactive editing interface
- PagedJS for print-ready rendering
The application allows users to create and edit multi-page narratives with dynamic layouts, supporting various content blocks (text, images, videos, maps) and custom page templates.
Tech Stack
- Frontend: Vue 3 (Composition API) + Vite
- Print Engine: PagedJS (CSS Paged Media)
- CMS: Kirby 5 (headless, flat-file)
- Backend: PHP 8.1+
- State Management: Pinia
- Styling: CSS with CSS Variables
Project Structure
/src # Vue 3 SPA
├── main.js # Vue bootstrap
├── App.vue # Root component + PagedJS init
├── components/
│ ├── blocks/ # Content block components (HeadingBlock, TextBlock, etc.)
│ ├── editor/ # Editor panels (PageSettings, TextSettings, etc.)
│ ├── ui/ # Reusable UI components (InputWithUnit, MarginEditor, etc.)
│ └── *.vue # Core components (PagedJsWrapper, ElementPopup, etc.)
├── composables/ # Vue composables (useCssSync, useCssUpdater, etc.)
├── stores/ # Pinia stores (narrative.js, stylesheet.js)
└── utils/ # JavaScript utilities
/public # Kirby CMS + static assets
├── site/
│ ├── blueprints/ # Content schemas
│ ├── templates/ # PHP templates
│ ├── snippets/ # PHP snippets
│ └── plugins/ # Kirby plugins
├── content/ # Markdown content files
└── assets/ # Static assets (CSS, fonts, SVG)
/.forgejo/workflows # CI/CD pipeline
Key Features
Content Types
- Narratives: Main story containers with cover, author, introduction
- Geoformats: Structured content sections with chapters
- Chapters: Individual chapters with rich content blocks
- Maps: Special map-based content pages
Content Blocks
- Text blocks with rich formatting
- Headings with customizable levels
- Images with captions and positioning
- Lists (ordered and unordered)
- Blockquotes with citations
- Video embeds
- Interactive maps
Print Features
- Real-time preview with PagedJS rendering
- Custom @page rules for different templates
- Interactive element and page editing
- CSS variable-based theming
- Print-optimized output
Getting Started
Development
# Install dependencies
npm install
# Start Vite dev server
npm run dev
# Start PHP server for Kirby (separate terminal)
php -S localhost:8000 -t public
The Vue app will be served at http://localhost:5173 and Kirby at http://localhost:8000.
Production Build
# Build for production
npm run build
Builds are output to /public/assets/dist/.
Data Flow
- Kirby CMS stores and manages content as flat files
- PHP Templates render the HTML structure and inject Vue
- Vue App provides the interactive editing interface
- PagedJS transforms content into print-ready pages
API
Narrative JSON Endpoint
GET /projet/{narrative-slug}.json
Returns the complete narrative data structure including all child pages, blocks, and metadata.
Naming Conventions
- Vue Components: PascalCase (e.g.,
PagedJsWrapper.vue) - Composables: Prefixed with
use(e.g.,useCssSync) - Stores: camelCase files, PascalCase store names (e.g.,
useNarrativeStore) - Code Language: English preferred for all code, comments, and identifiers
English-French Dictionary
The codebase uses English naming conventions, but some French terms remain in content and templates for compatibility. Here's a reference guide:
Core Concepts
| English | French | Context |
|---|---|---|
| narrative | récit | Main content container type |
| chapter | chapitre | Chapter/section within a geoformat |
| map | carte | Map-based content page |
| cover | couverture | Cover page/image |
| author | auteur | Narrative author(s) |
| introduction | introduction | Introductory text |
| impression | Print/output functionality |
Template Types
| English | French | File/Template Name |
|---|---|---|
| narrative | recit | narrative.php, narrative.json.php |
| chapter | chapitre | chapitre.php |
| map | carte | carte.php |
| geoformat | geoformat | geoformat.php |
UI Elements
| English | French | Notes |
|---|---|---|
| settings | paramètres | Editor panel settings |
| page | page | Page template/type |
| block | bloc | Content block |
| edit | éditer | Edit action |
| preview | aperçu | Preview mode |
Technical Terms
| English | French | Notes |
|---|---|---|
| store | magasin | Pinia store (use English 'store') |
| template | template/modèle | Page template |
| blueprint | schéma | Kirby content schema |
| field | champ | Form/content field |
Code Examples
Store naming:
// Correct
import { useNarrativeStore } from './stores/narrative';
// Old (deprecated)
import { useRecitStore } from './stores/recit';
Template references:
// Check for narrative template
if (item.template === 'narrative') { /* ... */ }
// Check for chapter template
if (item.template === 'chapitre') { /* ... */ }
CSS classes:
/* Narrative cover page */
.narrative-cover { /* ... */ }
/* Chapter content */
.chapitre { /* ... */ }
CI/CD
The project uses Forgejo Actions for continuous deployment:
- Code is pushed to Forgejo repository
- Workflow builds the Vue app
- Files are deployed via FTP to production server
See .forgejo/workflows/deploy.yml for details.
Contributing
For detailed development guidelines, see CLAUDE.md.