feat: integrate Kirby CMS data with Vue print editor

- Add JSON content representation template (recit.json.php)
- Create virtual /print page plugin for recit pages
- Add recit.php base template for content representation
- Create Pinia store for recit data management
- Add block components (text, heading, image, list, quote, video, map)
- Update PagedJsWrapper for dynamic content rendering with data-page-type
- Modify header.php to pass recit JSON URL via data attribute
- Update App.vue to load recit data on mount

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
isUnknown 2025-12-08 18:01:01 +01:00
parent 446b6cd9e7
commit 790eb7414e
17 changed files with 807 additions and 56 deletions

127
src/stores/recit.js Normal file
View file

@ -0,0 +1,127 @@
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useRecitStore = defineStore('recit', () => {
const data = ref(null);
const loading = ref(false);
const error = ref(null);
// Computed properties
const title = computed(() => data.value?.title ?? '');
const author = computed(() => data.value?.author ?? '');
const cover = computed(() => data.value?.cover ?? null);
const introduction = computed(() => data.value?.introduction ?? '');
const children = computed(() => data.value?.children ?? []);
// Flatten all content for PagedJS rendering
const flattenedContent = computed(() => {
if (!data.value) return [];
const items = [];
// Add recit intro as first section
items.push({
id: data.value.id,
template: 'recit',
title: data.value.title,
author: data.value.author,
cover: data.value.cover,
introduction: data.value.introduction
});
// Recursively flatten children
const flattenChildren = (children, depth = 0) => {
for (const child of children) {
if (child.template === 'geoformat') {
// Add geoformat header
items.push({
id: child.id,
template: 'geoformat',
title: child.title,
subtitle: child.subtitle,
tags: child.tags,
cover: child.cover,
text: child.text
});
// Add geoformat chapters
if (child.children && child.children.length > 0) {
flattenChildren(child.children, depth + 1);
}
} else if (child.template === 'chapitre') {
items.push({
id: child.id,
template: 'chapitre',
title: child.title,
blocks: child.blocks
});
} else if (child.template === 'carte') {
items.push({
id: child.id,
template: 'carte',
title: child.title,
tags: child.tags,
text: child.text
});
}
}
};
flattenChildren(data.value.children);
return items;
});
// Load recit data from URL
const loadRecit = async (url) => {
if (!url) {
error.value = 'No recit URL provided';
return;
}
loading.value = true;
error.value = null;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
data.value = await response.json();
} catch (e) {
console.error('Error loading recit:', e);
error.value = e.message;
data.value = null;
} finally {
loading.value = false;
}
};
// Reset store
const reset = () => {
data.value = null;
loading.value = false;
error.value = null;
};
return {
// State
data,
loading,
error,
// Computed
title,
author,
cover,
introduction,
children,
flattenedContent,
// Actions
loadRecit,
reset
};
});