feat: render full map content (image, intro, markers) in PagedJS
- Fix template check 'carte' → 'map' so map subpages are served by API - Add parseMarker() and enrich parseCarte() with static image, intro, markers - Include map children in parseGeoformat() alongside chapters - Resolve map block references in chapters to full carte data - Update narrative store flattening with new carte fields - Replace MapBlock placeholder with full carte rendering (title, image, tags, intro, markers with icons and blocks) - Add default marker-pin.svg for markers without custom icon Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9d80845335
commit
41fbe71a1f
5 changed files with 171 additions and 22 deletions
|
|
@ -63,11 +63,41 @@
|
|||
class="carte"
|
||||
:data-page-type="item.template"
|
||||
>
|
||||
<h2>{{ item.title }}</h2>
|
||||
<h4>{{ item.title }}</h4>
|
||||
<img v-if="item.image" :src="item.image" class="carte-image" alt="" />
|
||||
<div v-if="item.tags && item.tags.length" class="tags">
|
||||
<span v-for="tag in item.tags" :key="tag" class="tag">{{ tag }}</span>
|
||||
</div>
|
||||
<div v-if="item.text" class="carte-content" v-html="item.text"></div>
|
||||
<div v-if="item.intro" class="intro" v-html="item.intro"></div>
|
||||
<div v-if="item.markers && item.markers.length" class="markers">
|
||||
<div v-for="(marker, idx) in item.markers" :key="idx" class="marker">
|
||||
<h5 class="marker-title">
|
||||
<img
|
||||
v-if="marker.icon"
|
||||
:src="marker.icon"
|
||||
class="marker-icon"
|
||||
:style="{ width: marker.iconSize + 'px', height: marker.iconSize + 'px' }"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
src="/assets/svg/marker-pin.svg"
|
||||
class="marker-icon marker-icon--default"
|
||||
alt=""
|
||||
/>
|
||||
{{ marker.title }}
|
||||
</h5>
|
||||
<img v-if="marker.cover" :src="marker.cover" class="marker-cover" alt="" />
|
||||
<template v-if="marker.blocks">
|
||||
<component
|
||||
v-for="block in visibleBlocks(marker.blocks)"
|
||||
:key="block.id"
|
||||
:is="getBlockComponent(block.type)"
|
||||
:content="block.content"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
</template>
|
||||
|
|
@ -186,9 +216,37 @@ const getBlockComponent = (type) => {
|
|||
}
|
||||
|
||||
.block-map {
|
||||
background: #f5f5f5;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
border: 1px dashed #ccc;
|
||||
break-before: page;
|
||||
}
|
||||
|
||||
.carte-image {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.marker {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.marker-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.marker-icon {
|
||||
flex-shrink: 0;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.marker-icon--default {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.marker-cover {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,72 @@
|
|||
<template>
|
||||
<div class="block-map">
|
||||
<div v-if="content.template === 'carte'" class="block-map">
|
||||
<h4>{{ content.title }}</h4>
|
||||
<img v-if="content.image" :src="content.image" class="carte-image" alt="" />
|
||||
<div v-if="content.tags && content.tags.length" class="tags">
|
||||
<span v-for="tag in content.tags" :key="tag" class="tag">{{ tag }}</span>
|
||||
</div>
|
||||
<div v-if="content.intro" class="intro" v-html="content.intro"></div>
|
||||
<div v-if="content.markers && content.markers.length" class="markers">
|
||||
<div v-for="(marker, idx) in content.markers" :key="idx" class="marker">
|
||||
<h5 class="marker-title">
|
||||
<img
|
||||
v-if="marker.icon"
|
||||
:src="marker.icon"
|
||||
class="marker-icon"
|
||||
:style="{ width: marker.iconSize + 'px', height: marker.iconSize + 'px' }"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
src="/assets/svg/marker-pin.svg"
|
||||
class="marker-icon marker-icon--default"
|
||||
alt=""
|
||||
/>
|
||||
{{ marker.title }}
|
||||
</h5>
|
||||
<img v-if="marker.cover" :src="marker.cover" class="marker-cover" alt="" />
|
||||
<template v-if="marker.blocks">
|
||||
<component
|
||||
v-for="block in visibleBlocks(marker.blocks)"
|
||||
:key="block.id"
|
||||
:is="getBlockComponent(block.type)"
|
||||
:content="block.content"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="block-map">
|
||||
<p class="map-placeholder">[Carte: {{ content.map }}]</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import TextBlock from './TextBlock.vue';
|
||||
import HeadingBlock from './HeadingBlock.vue';
|
||||
import ImageBlock from './ImageBlock.vue';
|
||||
import ListBlock from './ListBlock.vue';
|
||||
import QuoteBlock from './QuoteBlock.vue';
|
||||
|
||||
defineProps({
|
||||
content: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const visibleBlocks = (blocks) => {
|
||||
return blocks.filter((block) => !block.isHidden);
|
||||
};
|
||||
|
||||
const getBlockComponent = (type) => {
|
||||
const components = {
|
||||
text: TextBlock,
|
||||
heading: HeadingBlock,
|
||||
image: ImageBlock,
|
||||
list: ListBlock,
|
||||
quote: QuoteBlock,
|
||||
};
|
||||
return components[type] || TextBlock;
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,9 @@ export const useNarrativeStore = defineStore('narrative', () => {
|
|||
template: 'carte',
|
||||
title: child.title,
|
||||
tags: child.tags,
|
||||
text: child.text,
|
||||
image: child.image,
|
||||
intro: child.intro,
|
||||
markers: child.markers,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue