VITEC headless v14: 5-bug fix unifies plugin renderers + cleanup
Resolves a cascade of TYPO3 v14 breaking changes that left every VITEC plugin's JSON output silently empty: 1. `list_type` column dropped — all renderer page-discovery queries now filter by `CType = 'vitec_X'`. 2. `#[AsAllowedCallable]` attribute added to every public render() — without it v14 throws AllowedCallableException, which headless silently filters via its "Oops, an error occurred!" guard. 3. `$GLOBALS['TSFE']->id` is null inside JSON cObj context — page id now read from the `frontend.page.information` request attribute (TSFE fallback kept for legacy entry points). 4. page.tsconfig wizard items migrated to `CType = vitec_X` directly (legacy `CType=list, list_type=...` no longer exists in v14). 5. ContainerChildrenProcessor + ContentElementResolver dispatch the PLUGIN_RENDERERS map by CType (primary) with list_type fallback. Beyond the bug fix this commit also contains: - Datasheets renderer rewritten to "products with newest datasheet" semantics (filtered via Download.hideondatasheets). - New vitec/card content block — multi-purpose card with backend preview and layout/background/aspect/alignment/border/shadow options. - New vitec_container CType (b13 single-column container, FlexForm cssClass propagated into the JSON envelope). - ContentElementResolver service for contentelement/contentelementcta link resolution; ContainerChildrenProcessor for nested plugin resolution inside b13 containers. - Vitecset setup.typoscript: ContentElement import moved to top so lib.contentElement is defined before VITEC's tt_content blocks. - Cleanup: 98 .bak.<timestamp> debugging backups removed; *.bak.* and /public/_assets_install/ added to .gitignore. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
|
||||
<rect x="1.5" y="2.5" width="13" height="11" rx="1.4" fill="none" stroke="#000" stroke-width="1.2"/>
|
||||
<rect x="3" y="4" width="10" height="3.6" rx="0.4" fill="#000" opacity="0.55"/>
|
||||
<rect x="3" y="8.3" width="7.5" height="1.2" rx="0.2" fill="#000" opacity="0.45"/>
|
||||
<rect x="3" y="10" width="9" height="1" rx="0.2" fill="#000" opacity="0.3"/>
|
||||
<rect x="3" y="11.4" width="4.2" height="1" rx="0.2" fill="#000" opacity="0.25"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 524 B |
186
packages/vitec/ContentBlocks/ContentElements/card/config.yaml
Normal file
186
packages/vitec/ContentBlocks/ContentElements/card/config.yaml
Normal file
@@ -0,0 +1,186 @@
|
||||
name: vitec/card
|
||||
group: vitec
|
||||
prefixFields: true
|
||||
prefixType: vendor
|
||||
|
||||
fields:
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
- identifier: tab_content
|
||||
type: Tab
|
||||
label: Content
|
||||
|
||||
- identifier: eyebrow
|
||||
type: Text
|
||||
max: 50
|
||||
|
||||
- identifier: header
|
||||
useExistingField: true
|
||||
required: true
|
||||
|
||||
- identifier: subheader
|
||||
useExistingField: true
|
||||
|
||||
- identifier: bodytext
|
||||
useExistingField: true
|
||||
enableRichtext: true
|
||||
|
||||
- identifier: image
|
||||
type: File
|
||||
minitems: 0
|
||||
maxitems: 1
|
||||
allowed: common-image-types
|
||||
|
||||
- identifier: icon
|
||||
type: File
|
||||
minitems: 0
|
||||
maxitems: 1
|
||||
allowed: svg,png
|
||||
|
||||
- identifier: primary_cta
|
||||
type: Link
|
||||
allowedTypes:
|
||||
- page
|
||||
- url
|
||||
- file
|
||||
- email
|
||||
|
||||
- identifier: primary_cta_label
|
||||
type: Text
|
||||
max: 30
|
||||
default: 'Learn more'
|
||||
|
||||
- identifier: secondary_cta
|
||||
type: Link
|
||||
allowedTypes:
|
||||
- page
|
||||
- url
|
||||
- file
|
||||
- email
|
||||
|
||||
- identifier: secondary_cta_label
|
||||
type: Text
|
||||
max: 30
|
||||
|
||||
- identifier: card_link
|
||||
type: Link
|
||||
allowedTypes:
|
||||
- page
|
||||
- url
|
||||
- file
|
||||
- email
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
- identifier: tab_layout
|
||||
type: Tab
|
||||
label: Layout
|
||||
|
||||
- identifier: layout_variant
|
||||
type: Select
|
||||
renderType: selectSingle
|
||||
default: vertical
|
||||
items:
|
||||
- label: Vertical (image top, content below)
|
||||
value: vertical
|
||||
- label: Horizontal (image left, content right)
|
||||
value: horizontal
|
||||
- label: Horizontal Reverse (content left, image right)
|
||||
value: horizontal_reverse
|
||||
- label: Image Overlay (text over image)
|
||||
value: image_overlay
|
||||
- label: Text Only (no image)
|
||||
value: text_only
|
||||
- label: Icon Card (icon focused, text below)
|
||||
value: icon_card
|
||||
- label: Feature (large highlighted card)
|
||||
value: feature
|
||||
- label: Compact (small card, tight spacing)
|
||||
value: compact
|
||||
|
||||
- identifier: background_variant
|
||||
type: Select
|
||||
renderType: selectSingle
|
||||
default: none
|
||||
items:
|
||||
- label: None
|
||||
value: none
|
||||
- label: Orange
|
||||
value: orange
|
||||
- label: Blue
|
||||
value: blue
|
||||
- label: Graphite
|
||||
value: graphite
|
||||
- label: Midnight
|
||||
value: midnight
|
||||
- label: Light (neutral)
|
||||
value: light
|
||||
- label: Dark (neutral)
|
||||
value: dark
|
||||
|
||||
- identifier: image_aspect_ratio
|
||||
type: Select
|
||||
renderType: selectSingle
|
||||
default: auto
|
||||
items:
|
||||
- label: Auto (original)
|
||||
value: auto
|
||||
- label: Square (1:1)
|
||||
value: '1_1'
|
||||
- label: Landscape (4:3)
|
||||
value: '4_3'
|
||||
- label: Widescreen (16:9)
|
||||
value: '16_9'
|
||||
- label: Portrait (3:4)
|
||||
value: '3_4'
|
||||
|
||||
- identifier: text_alignment
|
||||
type: Select
|
||||
renderType: selectSingle
|
||||
default: left
|
||||
items:
|
||||
- label: Left
|
||||
value: left
|
||||
- label: Center
|
||||
value: center
|
||||
- label: Right
|
||||
value: right
|
||||
|
||||
- identifier: border_style
|
||||
type: Select
|
||||
renderType: selectSingle
|
||||
default: none
|
||||
items:
|
||||
- label: None
|
||||
value: none
|
||||
- label: Soft (subtle line)
|
||||
value: soft
|
||||
- label: Hard (thick line)
|
||||
value: hard
|
||||
- label: Dashed
|
||||
value: dashed
|
||||
|
||||
- identifier: shadow
|
||||
type: Select
|
||||
renderType: selectSingle
|
||||
default: none
|
||||
items:
|
||||
- label: None
|
||||
value: none
|
||||
- label: Soft
|
||||
value: soft
|
||||
- label: Medium
|
||||
value: medium
|
||||
- label: Strong
|
||||
value: strong
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
- identifier: tab_advanced
|
||||
type: Tab
|
||||
label: Advanced
|
||||
|
||||
- identifier: cssClass
|
||||
type: Text
|
||||
max: 100
|
||||
|
||||
- identifier: debug
|
||||
type: Checkbox
|
||||
default: 0
|
||||
@@ -0,0 +1,206 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff version="1.2">
|
||||
<file source-language="en" datatype="plaintext" original="messages">
|
||||
<body>
|
||||
<trans-unit id="title">
|
||||
<source>VITEC · Card</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="description">
|
||||
<source>Multi-purpose card with image / icon, body, two CTAs, layout/background/aspect-ratio/alignment/border/shadow options.</source>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="tab_content.label">
|
||||
<source>Content</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="tab_layout.label">
|
||||
<source>Layout</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="tab_advanced.label">
|
||||
<source>Advanced</source>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="eyebrow.label">
|
||||
<source>Eyebrow (small pre-title)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="image.label">
|
||||
<source>Image</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="image.description">
|
||||
<source>Primary card image. Optional — leave empty for text-only / icon-only layouts.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="icon.label">
|
||||
<source>Icon (SVG or PNG)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="icon.description">
|
||||
<source>Small icon used as fallback when no image is set, or as a visual indicator in icon-focused layouts.</source>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="primary_cta.label">
|
||||
<source>Primary CTA Link</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="primary_cta_label.label">
|
||||
<source>Primary CTA Button Text</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="secondary_cta.label">
|
||||
<source>Secondary CTA Link (optional)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="secondary_cta_label.label">
|
||||
<source>Secondary CTA Button Text (optional)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="card_link.label">
|
||||
<source>Whole-card link (optional)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="card_link.description">
|
||||
<source>If set, the whole card becomes clickable. Overrides individual CTAs visually in the frontend.</source>
|
||||
</trans-unit>
|
||||
|
||||
<!-- ============================================================== -->
|
||||
<!-- layout_variant -->
|
||||
<!-- ============================================================== -->
|
||||
<trans-unit id="layout_variant.label">
|
||||
<source>Layout Variant</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="layout_variant.items.vertical.label">
|
||||
<source>Vertical (image top, content below)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="layout_variant.items.horizontal.label">
|
||||
<source>Horizontal (image left, content right)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="layout_variant.items.horizontal_reverse.label">
|
||||
<source>Horizontal Reverse (content left, image right)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="layout_variant.items.image_overlay.label">
|
||||
<source>Image Overlay (text over image)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="layout_variant.items.text_only.label">
|
||||
<source>Text Only (no image)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="layout_variant.items.icon_card.label">
|
||||
<source>Icon Card (icon focused, text below)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="layout_variant.items.feature.label">
|
||||
<source>Feature (large highlighted card)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="layout_variant.items.compact.label">
|
||||
<source>Compact (small card, tight spacing)</source>
|
||||
</trans-unit>
|
||||
|
||||
<!-- ============================================================== -->
|
||||
<!-- background_variant -->
|
||||
<!-- ============================================================== -->
|
||||
<trans-unit id="background_variant.label">
|
||||
<source>Background Variant</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="background_variant.items.none.label">
|
||||
<source>None</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="background_variant.items.orange.label">
|
||||
<source>Orange</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="background_variant.items.blue.label">
|
||||
<source>Blue</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="background_variant.items.graphite.label">
|
||||
<source>Graphite</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="background_variant.items.midnight.label">
|
||||
<source>Midnight</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="background_variant.items.light.label">
|
||||
<source>Light (neutral)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="background_variant.items.dark.label">
|
||||
<source>Dark (neutral)</source>
|
||||
</trans-unit>
|
||||
|
||||
<!-- ============================================================== -->
|
||||
<!-- image_aspect_ratio -->
|
||||
<!-- ============================================================== -->
|
||||
<trans-unit id="image_aspect_ratio.label">
|
||||
<source>Image Aspect Ratio</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="image_aspect_ratio.items.auto.label">
|
||||
<source>Auto (original)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="image_aspect_ratio.items.1_1.label">
|
||||
<source>Square (1:1)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="image_aspect_ratio.items.4_3.label">
|
||||
<source>Landscape (4:3)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="image_aspect_ratio.items.16_9.label">
|
||||
<source>Widescreen (16:9)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="image_aspect_ratio.items.3_4.label">
|
||||
<source>Portrait (3:4)</source>
|
||||
</trans-unit>
|
||||
|
||||
<!-- ============================================================== -->
|
||||
<!-- text_alignment -->
|
||||
<!-- ============================================================== -->
|
||||
<trans-unit id="text_alignment.label">
|
||||
<source>Text Alignment</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="text_alignment.items.left.label">
|
||||
<source>Left</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="text_alignment.items.center.label">
|
||||
<source>Center</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="text_alignment.items.right.label">
|
||||
<source>Right</source>
|
||||
</trans-unit>
|
||||
|
||||
<!-- ============================================================== -->
|
||||
<!-- border_style -->
|
||||
<!-- ============================================================== -->
|
||||
<trans-unit id="border_style.label">
|
||||
<source>Border Style</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="border_style.items.none.label">
|
||||
<source>None</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="border_style.items.soft.label">
|
||||
<source>Soft (subtle line)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="border_style.items.hard.label">
|
||||
<source>Hard (thick line)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="border_style.items.dashed.label">
|
||||
<source>Dashed</source>
|
||||
</trans-unit>
|
||||
|
||||
<!-- ============================================================== -->
|
||||
<!-- shadow -->
|
||||
<!-- ============================================================== -->
|
||||
<trans-unit id="shadow.label">
|
||||
<source>Shadow</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="shadow.items.none.label">
|
||||
<source>None</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="shadow.items.soft.label">
|
||||
<source>Soft</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="shadow.items.medium.label">
|
||||
<source>Medium</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="shadow.items.strong.label">
|
||||
<source>Strong</source>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="cssClass.label">
|
||||
<source>Additional CSS Class</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="cssClass.description">
|
||||
<source>Custom CSS class rendered on the card root element in the frontend.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="debug.label">
|
||||
<source>Allow Debug Output</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="debug.description">
|
||||
<source>When enabled, extra debug fields may be included in the JSON output for this element.</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
@@ -0,0 +1,150 @@
|
||||
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
|
||||
<f:layout name="Preview"/>
|
||||
<f:section name="Content">
|
||||
|
||||
<f:asset.css identifier="vitec-backend-preview" href="EXT:vitec/Resources/Public/Css/backend-preview.css"/>
|
||||
|
||||
<div class="vitec-preview vitec-preview--{data.background_variant}">
|
||||
|
||||
<f:comment>Thumbnail: image > icon > placeholder</f:comment>
|
||||
<f:if condition="{data.image.0}">
|
||||
<f:then>
|
||||
<f:image image="{data.image.0}"
|
||||
class="vitec-preview__thumb"
|
||||
width="120c"
|
||||
height="80c"
|
||||
alt="Card image preview"/>
|
||||
</f:then>
|
||||
<f:else>
|
||||
<f:if condition="{data.icon.0}">
|
||||
<f:then>
|
||||
<f:image image="{data.icon.0}"
|
||||
class="vitec-preview__thumb"
|
||||
width="120c"
|
||||
height="80"
|
||||
alt="Card icon preview"/>
|
||||
</f:then>
|
||||
<f:else>
|
||||
<div class="vitec-preview__thumb-placeholder">
|
||||
<f:switch expression="{data.layout_variant}">
|
||||
<f:case value="text_only">📝</f:case>
|
||||
<f:case value="icon_card">✦</f:case>
|
||||
<f:case value="feature">⭐</f:case>
|
||||
<f:case value="compact">▫</f:case>
|
||||
<f:defaultCase>▢</f:defaultCase>
|
||||
</f:switch>
|
||||
</div>
|
||||
</f:else>
|
||||
</f:if>
|
||||
</f:else>
|
||||
</f:if>
|
||||
|
||||
<div class="vitec-preview__body">
|
||||
<div class="vitec-preview__label">VITEC · Card</div>
|
||||
|
||||
<f:if condition="{data.eyebrow}">
|
||||
<div class="vitec-preview__eyebrow">{data.eyebrow}</div>
|
||||
</f:if>
|
||||
|
||||
<h3 class="vitec-preview__headline">
|
||||
<f:if condition="{data.header}">
|
||||
<f:then>{data.header}</f:then>
|
||||
<f:else>
|
||||
<em style="color:#c00;">⚠ Headline fehlt</em>
|
||||
</f:else>
|
||||
</f:if>
|
||||
</h3>
|
||||
|
||||
<f:if condition="{data.subheader}">
|
||||
<div class="vitec-preview__subline">{data.subheader}</div>
|
||||
</f:if>
|
||||
|
||||
<f:if condition="{data.bodytext}">
|
||||
<div class="vitec-preview__body-text">
|
||||
<f:format.stripTags>{data.bodytext}</f:format.stripTags>
|
||||
</div>
|
||||
</f:if>
|
||||
|
||||
<div class="vitec-preview__ctas">
|
||||
<f:if condition="{data.primary_cta_label}">
|
||||
<span class="vitec-preview__cta-btn">{data.primary_cta_label} →</span>
|
||||
</f:if>
|
||||
<f:if condition="{data.secondary_cta_label}">
|
||||
<span class="vitec-preview__cta-btn vitec-preview__cta-btn--secondary">
|
||||
{data.secondary_cta_label}
|
||||
</span>
|
||||
</f:if>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:comment>Settings sidebar with badges</f:comment>
|
||||
<div class="vitec-preview__settings">
|
||||
|
||||
<span class="vitec-badge">
|
||||
<f:switch expression="{data.layout_variant}">
|
||||
<f:case value="vertical">▤ Vertical</f:case>
|
||||
<f:case value="horizontal">▥ Horizontal</f:case>
|
||||
<f:case value="horizontal_reverse">▤ Horizontal-Rev</f:case>
|
||||
<f:case value="image_overlay">▣ Image Overlay</f:case>
|
||||
<f:case value="text_only">📝 Text Only</f:case>
|
||||
<f:case value="icon_card">✦ Icon Card</f:case>
|
||||
<f:case value="feature">⭐ Feature</f:case>
|
||||
<f:case value="compact">▫ Compact</f:case>
|
||||
<f:defaultCase>{data.layout_variant}</f:defaultCase>
|
||||
</f:switch>
|
||||
</span>
|
||||
|
||||
<span class="vitec-badge">
|
||||
<span class="vitec-badge__dot vitec-badge__dot--{data.background_variant}"></span>
|
||||
<f:switch expression="{data.background_variant}">
|
||||
<f:case value="none">No BG</f:case>
|
||||
<f:case value="orange">Orange</f:case>
|
||||
<f:case value="blue">Blue</f:case>
|
||||
<f:case value="graphite">Graphite</f:case>
|
||||
<f:case value="midnight">Midnight</f:case>
|
||||
<f:case value="light">Light</f:case>
|
||||
<f:case value="dark">Dark</f:case>
|
||||
<f:defaultCase>{data.background_variant}</f:defaultCase>
|
||||
</f:switch>
|
||||
</span>
|
||||
|
||||
<f:if condition="{data.image_aspect_ratio} != 'auto'">
|
||||
<span class="vitec-badge">⛶ {data.image_aspect_ratio -> f:format.raw()}</span>
|
||||
</f:if>
|
||||
|
||||
<f:if condition="{data.text_alignment} != 'left'">
|
||||
<span class="vitec-badge">
|
||||
<f:switch expression="{data.text_alignment}">
|
||||
<f:case value="center">↔ Center</f:case>
|
||||
<f:case value="right">→ Right</f:case>
|
||||
<f:defaultCase>{data.text_alignment}</f:defaultCase>
|
||||
</f:switch>
|
||||
</span>
|
||||
</f:if>
|
||||
|
||||
<f:if condition="{data.border_style} != 'none'">
|
||||
<span class="vitec-badge">▭ Border: {data.border_style}</span>
|
||||
</f:if>
|
||||
|
||||
<f:if condition="{data.shadow} != 'none'">
|
||||
<span class="vitec-badge">☁ Shadow: {data.shadow}</span>
|
||||
</f:if>
|
||||
|
||||
<f:if condition="{data.card_link.url}">
|
||||
<span class="vitec-badge">🔗 Whole-card link</span>
|
||||
</f:if>
|
||||
|
||||
<f:if condition="{data.cssClass}">
|
||||
<span class="vitec-badge">⌗ .{data.cssClass}</span>
|
||||
</f:if>
|
||||
|
||||
<f:if condition="{data.debug}">
|
||||
<span class="vitec-badge vitec-badge--warning">⚙ Debug ON</span>
|
||||
</f:if>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</f:section>
|
||||
</html>
|
||||
@@ -0,0 +1,3 @@
|
||||
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
|
||||
<!-- Headless mode: JSON is built by nb-headless-content-blocks -->
|
||||
</html>
|
||||
Reference in New Issue
Block a user