Success-story migration + new plugins + JSON/UX polish
- Success Stories: full migration from old site (48/48, audited), markets n:n, quotation content block, columns content block, pretty SEO detail URLs via SuccessStoryPathRewrite middleware, list/detail split (list page 4 / story page), detailUrl/backUrl - New plugins: VITEC Locations (grid/list/map + RTE map text), VITEC Customer Logos (color/bw logic, only-show-selected), VITEC Card (one plugin for product/story/market/solution with reloading FlexForm + custom backend preview renderer) - Eventlist: layout dropdown (list/grid/teaserbar) in settings - Hero section CB: Images/Video tabs, background video + overlay - Product JSON: full category rootline (parents), fixed missing ConnectionPool import (all-products crash), category tree map - Backend preview CSS: container-query responsive (narrow columns) - Docs: ISO architecture spec, root + extension READMEs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -168,3 +168,7 @@ bash fix-asset-perms.sh # fix asset permission
|
|||||||
[GPL‑2.0‑or‑later](LICENSE) — © evomedien.
|
[GPL‑2.0‑or‑later](LICENSE) — © evomedien.
|
||||||
|
|
||||||
<div align="center"><sub>VITEC · TYPO3 headless backend + React front end</sub></div>
|
<div align="center"><sub>VITEC · TYPO3 headless backend + React front end</sub></div>
|
||||||
|
|
||||||
|
|
||||||
|
vitecdev
|
||||||
|
17ZJfy75sJoU68J6
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
"friendsoftypo3/headless": "^5.0@rc",
|
"friendsoftypo3/headless": "^5.0@rc",
|
||||||
"georgringer/news": "^14.0",
|
"georgringer/news": "^14.0",
|
||||||
"netzbewegung/nb-headless-content-blocks": "^0.0.23",
|
"netzbewegung/nb-headless-content-blocks": "^0.0.23",
|
||||||
|
"plan2net/backend-category-hierarchy": "^14.0",
|
||||||
"typo3/cms-backend": "^14.3",
|
"typo3/cms-backend": "^14.3",
|
||||||
"typo3/cms-belog": "^14.3",
|
"typo3/cms-belog": "^14.3",
|
||||||
"typo3/cms-beuser": "^14.3",
|
"typo3/cms-beuser": "^14.3",
|
||||||
|
|||||||
68
composer.lock
generated
68
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "894f07b60885efbdf0a5979a6879e631",
|
"content-hash": "09c5be5fca6a03ab5f0ed81662f20f36",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "b13/container",
|
"name": "b13/container",
|
||||||
@@ -2834,6 +2834,66 @@
|
|||||||
},
|
},
|
||||||
"time": "2026-07-08T07:01:06+00:00"
|
"time": "2026-07-08T07:01:06+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "plan2net/backend-category-hierarchy",
|
||||||
|
"version": "14.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/plan2net/backend-category-hierarchy.git",
|
||||||
|
"reference": "ee40a998fadba5545401425a0bc224482d0f643a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/plan2net/backend-category-hierarchy/zipball/ee40a998fadba5545401425a0bc224482d0f643a",
|
||||||
|
"reference": "ee40a998fadba5545401425a0bc224482d0f643a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^8.2",
|
||||||
|
"typo3/cms-backend": "^13.4 || ^14.0",
|
||||||
|
"typo3/cms-core": "^13.4 || ^14.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.64",
|
||||||
|
"phpstan/extension-installer": "^1.4",
|
||||||
|
"phpstan/phpstan": "^2.0",
|
||||||
|
"phpstan/phpstan-phpunit": "^2.0",
|
||||||
|
"phpstan/phpstan-strict-rules": "^2.0",
|
||||||
|
"phpunit/phpunit": "^11.5",
|
||||||
|
"typo3/testing-framework": "^9.3 || ^10.0",
|
||||||
|
"vimeo/psalm": "^6.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"georgringer/news": "*"
|
||||||
|
},
|
||||||
|
"type": "typo3-cms-extension",
|
||||||
|
"extra": {
|
||||||
|
"typo3/cms": {
|
||||||
|
"extension-key": "backend_category_hierarchy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Plan2net\\BackendCategoryHierarchy\\": "Classes/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"GPL-2.0-or-later"
|
||||||
|
],
|
||||||
|
"description": "Show category hierarchy information in list view",
|
||||||
|
"homepage": "https://plan2.net",
|
||||||
|
"keywords": [
|
||||||
|
"TYPO3 CMS",
|
||||||
|
"backend",
|
||||||
|
"category"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/plan2net/backend-category-hierarchy/issues",
|
||||||
|
"source": "https://github.com/plan2net/backend-category-hierarchy/tree/14.0.0"
|
||||||
|
},
|
||||||
|
"time": "2026-05-17T07:58:49+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/cache",
|
"name": "psr/cache",
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
@@ -9411,10 +9471,10 @@
|
|||||||
},
|
},
|
||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": {},
|
"platform": [],
|
||||||
"platform-dev": {},
|
"platform-dev": [],
|
||||||
"platform-overrides": {
|
"platform-overrides": {
|
||||||
"php": "8.4.0"
|
"php": "8.4.0"
|
||||||
},
|
},
|
||||||
"plugin-api-version": "2.9.0"
|
"plugin-api-version": "2.3.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,4 +69,26 @@ routeEnhancers:
|
|||||||
aspects:
|
aspects:
|
||||||
news-title:
|
news-title:
|
||||||
type: NewsTitle
|
type: NewsTitle
|
||||||
|
UsecaseDetail:
|
||||||
|
type: Extbase
|
||||||
|
limitToPages:
|
||||||
|
- 4
|
||||||
|
- 26
|
||||||
|
- 25
|
||||||
|
extension: Vitec
|
||||||
|
plugin: Usecaseshow
|
||||||
|
routes:
|
||||||
|
-
|
||||||
|
routePath: '/{usecase_slug}'
|
||||||
|
_controller: 'Usecase::show'
|
||||||
|
_arguments:
|
||||||
|
usecase_slug: usecase
|
||||||
|
defaultController: 'Usecase::show'
|
||||||
|
requirements:
|
||||||
|
usecase_slug: '[a-zA-Z0-9\-]+'
|
||||||
|
aspects:
|
||||||
|
usecase_slug:
|
||||||
|
type: PersistedAliasMapper
|
||||||
|
tableName: tx_vitec_domain_model_usecase
|
||||||
|
routeFieldName: slug
|
||||||
websiteTitle: ''
|
websiteTitle: ''
|
||||||
|
|||||||
708
packages/vitec/Classes/Command/ImportSuccessStoriesCommand.php
Executable file
708
packages/vitec/Classes/Command/ImportSuccessStoriesCommand.php
Executable file
@@ -0,0 +1,708 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use TYPO3\CMS\Core\Core\Bootstrap;
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use TYPO3\CMS\Core\DataHandling\DataHandler;
|
||||||
|
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One-time (idempotent) migration of the old vitec.com Success Stories into
|
||||||
|
* the new tx_vitec_domain_model_usecase model.
|
||||||
|
*
|
||||||
|
* Source: migrations JSON produced on the OLD site by
|
||||||
|
* migrations/export_success_stories.php, plus the staged original files under
|
||||||
|
* fileadmin/success_stories_import/ (same relative identifiers as on the old
|
||||||
|
* site).
|
||||||
|
*
|
||||||
|
* Mapping (see analysis in the session / architecture spec):
|
||||||
|
* pages(title,slug,SEO) -> usecase base + seo_*
|
||||||
|
* mask_web__markets_card -> subtitle, card_image, customer_logo
|
||||||
|
* mask_web__success_story__promo -> hero (bgimage, overlay color, theme)
|
||||||
|
* use_case element (APP) -> industries (sys_category) -> markets MM
|
||||||
|
* page content (flux tree) -> inline content_elements:
|
||||||
|
* text -> text CE (blockquote quotes -> vitec_quotation)
|
||||||
|
* image/textmedia -> image/textmedia CE + FAL
|
||||||
|
* html -> html CE
|
||||||
|
* 2-column flux rows -> vitec_columns content block
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* vendor/bin/typo3 vitec:import-success-stories --dry-run
|
||||||
|
* vendor/bin/typo3 vitec:import-success-stories --only=meydan-racecourse
|
||||||
|
* vendor/bin/typo3 vitec:import-success-stories --force (reimport existing)
|
||||||
|
*/
|
||||||
|
#[AsCommand(
|
||||||
|
name: 'vitec:import-success-stories',
|
||||||
|
description: 'Import success stories from the old-website export JSON into the usecase model'
|
||||||
|
)]
|
||||||
|
final class ImportSuccessStoriesCommand extends Command
|
||||||
|
{
|
||||||
|
private const TABLE = 'tx_vitec_domain_model_usecase';
|
||||||
|
private const FILES_BASE = '/success_stories_import';
|
||||||
|
|
||||||
|
/** Old market2 token -> canonical industry title. */
|
||||||
|
private const INDUSTRY_TOKENS = [
|
||||||
|
'sports' => 'Sports', 'venues' => 'Venues', 'government' => 'Government',
|
||||||
|
'military' => 'Military', 'corporate' => 'Corporate', 'broadcast' => 'Broadcast',
|
||||||
|
'education' => 'Education', 'healthcare' => 'Healthcare',
|
||||||
|
'hospitality' => 'Hospitality & Leisure', 'leisure' => 'Hospitality & Leisure',
|
||||||
|
'accomodation' => 'Accommodation', 'accommodation' => 'Accommodation',
|
||||||
|
];
|
||||||
|
|
||||||
|
/** CTypes that never become content elements. */
|
||||||
|
private const SKIP_CTYPES = [
|
||||||
|
'shortcut', 'div', 'fluxbs5templates_buttonlink', 'mask_web__jumpmenu',
|
||||||
|
'mask_web__markets_card', 'mask_web__success_story__full_width_promo',
|
||||||
|
'mask_web__success_top_story', 'mask_use_case', 'header',
|
||||||
|
];
|
||||||
|
|
||||||
|
private const CONTAINER_CTYPES = ['fluxbs5templates_fluidrow', 'fluxbs5templates_container'];
|
||||||
|
|
||||||
|
private array $export = [];
|
||||||
|
private array $pagesByUid = [];
|
||||||
|
private array $contentByUid = [];
|
||||||
|
private array $childrenByParent = []; // parentCeUid => list of child CEs
|
||||||
|
private array $rootsByPid = []; // pageUid => list of colPos-0/5 CEs
|
||||||
|
private array $cardByPageUid = [];
|
||||||
|
private array $useCaseByKey = [];
|
||||||
|
private array $fileRefs = []; // "table:uid:field" => refs[]
|
||||||
|
private array $catTitleByUid = [];
|
||||||
|
private array $catsByCeUid = [];
|
||||||
|
private array $marketUidByTitle = [];
|
||||||
|
private array $fileUidCache = [];
|
||||||
|
private string $collectionTable = '';
|
||||||
|
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this->addOption('file', null, InputOption::VALUE_REQUIRED, 'Path to success_stories_export.json', 'var/transient/success_stories_export.json');
|
||||||
|
$this->addOption('pid', null, InputOption::VALUE_REQUIRED, 'Storage pid for new usecase records (default: pid of existing records)');
|
||||||
|
$this->addOption('only', null, InputOption::VALUE_REQUIRED, 'Import only the story whose slug tail matches');
|
||||||
|
$this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Analyse and report only, write nothing');
|
||||||
|
$this->addOption('force', null, InputOption::VALUE_NONE, 'Delete + recreate stories that already exist (matched by slug)');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
Bootstrap::initializeBackendAuthentication();
|
||||||
|
|
||||||
|
$file = (string)$input->getOption('file');
|
||||||
|
if (!is_file($file)) {
|
||||||
|
$output->writeln("<error>Export file not found: $file</error>");
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
$this->export = json_decode((string)file_get_contents($file), true) ?? [];
|
||||||
|
if (!isset($this->export['pages'])) {
|
||||||
|
$output->writeln('<error>Export JSON malformed (no pages key)</error>');
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dryRun = (bool)$input->getOption('dry-run');
|
||||||
|
$force = (bool)$input->getOption('force');
|
||||||
|
$only = (string)($input->getOption('only') ?? '');
|
||||||
|
|
||||||
|
$this->buildIndexes();
|
||||||
|
|
||||||
|
$storagePid = $this->resolveStoragePid($input->getOption('pid'));
|
||||||
|
if ($storagePid <= 0) {
|
||||||
|
$output->writeln('<error>No storage pid — pass --pid or create one usecase record manually first.</error>');
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
$this->collectionTable = (string)($GLOBALS['TCA']['tt_content']['columns']['vitec_items']['config']['foreign_table'] ?? '');
|
||||||
|
|
||||||
|
$rootUids = array_map(static fn(array $r): int => (int)$r['uid'], $this->export['storyRoots']);
|
||||||
|
$stories = array_values(array_filter(
|
||||||
|
$this->export['pages'],
|
||||||
|
static fn(array $p): bool => (int)($p['sys_language_uid'] ?? 0) === 0 && in_array((int)$p['pid'], $rootUids, true)
|
||||||
|
));
|
||||||
|
|
||||||
|
$output->writeln(sprintf(
|
||||||
|
'<info>%d stories in export · storage pid %d · %s</info>',
|
||||||
|
count($stories),
|
||||||
|
$storagePid,
|
||||||
|
$dryRun ? 'DRY-RUN' : 'LIVE'
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!$dryRun) {
|
||||||
|
$this->ensureMarkets($output, $storagePid);
|
||||||
|
}
|
||||||
|
|
||||||
|
$summary = [];
|
||||||
|
foreach ($stories as $page) {
|
||||||
|
$slugTail = basename((string)$page['slug']);
|
||||||
|
if ($only !== '' && $slugTail !== $only) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$summary[] = $this->importStory($page, $storagePid, $dryRun, $force, $output);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$summary[] = [$slugTail, 'ERROR: ' . $e->getMessage(), 0, 0, 0];
|
||||||
|
$output->writeln("<error> $slugTail: {$e->getMessage()}</error>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$output->writeln('');
|
||||||
|
$output->writeln(str_pad('story', 55) . str_pad('action', 12) . str_pad('CEs', 5) . str_pad('imgs', 6) . 'markets');
|
||||||
|
foreach ($summary as [$slug, $action, $ces, $imgs, $mk]) {
|
||||||
|
$output->writeln(str_pad(substr($slug, 0, 53), 55) . str_pad($action, 12) . str_pad((string)$ces, 5) . str_pad((string)$imgs, 6) . $mk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================== index building
|
||||||
|
|
||||||
|
private function buildIndexes(): void
|
||||||
|
{
|
||||||
|
foreach ($this->export['pages'] as $p) {
|
||||||
|
$this->pagesByUid[(int)$p['uid']] = $p;
|
||||||
|
}
|
||||||
|
$allCes = array_merge($this->export['content'], $this->export['storyElementsElsewhere']);
|
||||||
|
foreach ($allCes as $c) {
|
||||||
|
$this->contentByUid[(int)$c['uid']] = $c;
|
||||||
|
}
|
||||||
|
// flux tree: colPos >= 100 encodes parentUid*100 + column
|
||||||
|
foreach ($this->export['content'] as $c) {
|
||||||
|
$colPos = (int)($c['colPos'] ?? 0);
|
||||||
|
if ($colPos >= 100 && isset($this->contentByUid[intdiv($colPos, 100)])) {
|
||||||
|
$this->childrenByParent[intdiv($colPos, 100)][] = $c;
|
||||||
|
} else {
|
||||||
|
$this->rootsByPid[(int)$c['pid']][] = $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($this->childrenByParent as &$list) {
|
||||||
|
usort($list, static fn($a, $b) => [($a['colPos'] % 100), $a['sorting']] <=> [($b['colPos'] % 100), $b['sorting']]);
|
||||||
|
}
|
||||||
|
unset($list);
|
||||||
|
foreach ($this->rootsByPid as &$list) {
|
||||||
|
usort($list, static fn($a, $b) => $a['sorting'] <=> $b['sorting']);
|
||||||
|
}
|
||||||
|
unset($list);
|
||||||
|
|
||||||
|
// story card by target page uid (tx_mask_web__markets_card_link = "427" | "t3://page?uid=427")
|
||||||
|
foreach ($allCes as $c) {
|
||||||
|
if (($c['CType'] ?? '') !== 'mask_web__markets_card') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$link = (string)($c['tx_mask_web__markets_card_link'] ?? '');
|
||||||
|
if (preg_match('/uid=(\d+)/', $link, $m)) {
|
||||||
|
$target = (int)$m[1];
|
||||||
|
} elseif (ctype_digit(trim($link))) {
|
||||||
|
$target = (int)trim($link);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// prefer the newest non-hidden card per target
|
||||||
|
$known = $this->cardByPageUid[$target] ?? null;
|
||||||
|
if ($known === null || ((int)$c['tstamp'] > (int)$known['tstamp'] && empty($c['hidden']))) {
|
||||||
|
$this->cardByPageUid[$target] = $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use_case (APP) elements by normalised title
|
||||||
|
foreach ($allCes as $c) {
|
||||||
|
if (($c['CType'] ?? '') !== 'mask_use_case') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach ([(string)($c['header'] ?? ''), (string)($c['tx_mask_tile_customer'] ?? '')] as $t) {
|
||||||
|
$k = $this->normTitle($t);
|
||||||
|
if ($k !== '' && !isset($this->useCaseByKey[$k])) {
|
||||||
|
$this->useCaseByKey[$k] = $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->export['fileReferences'] as $r) {
|
||||||
|
if (!empty($r['hidden'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->fileRefs[$r['tablenames'] . ':' . $r['uid_foreign'] . ':' . $r['fieldname']][] = $r;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->export['categories'] as $c) {
|
||||||
|
$this->catTitleByUid[(int)$c['uid']] = (string)$c['title'];
|
||||||
|
}
|
||||||
|
foreach ($this->export['categoryAssignments'] as $a) {
|
||||||
|
if ($a['tablenames'] === 'tt_content') {
|
||||||
|
$this->catsByCeUid[(int)$a['uid_foreign']][] = $this->catTitleByUid[(int)$a['category_uid']] ?? '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Resolve a content-blocks column name: prefixed variant if it exists in TCA. */
|
||||||
|
private function cbCol(string $table, string $name): string
|
||||||
|
{
|
||||||
|
return isset($GLOBALS['TCA'][$table]['columns']['vitec_' . $name]) ? 'vitec_' . $name : $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normTitle(string $t): string
|
||||||
|
{
|
||||||
|
return preg_replace('/[^a-z0-9]/', '', strtolower($t)) ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function refs(string $table, int $uid, string $field): array
|
||||||
|
{
|
||||||
|
return $this->fileRefs[$table . ':' . $uid . ':' . $field] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================== market setup
|
||||||
|
|
||||||
|
private function resolveStoragePid(mixed $option): int
|
||||||
|
{
|
||||||
|
if ($option !== null && (int)$option > 0) {
|
||||||
|
return (int)$option;
|
||||||
|
}
|
||||||
|
$row = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getConnectionForTable(self::TABLE)
|
||||||
|
->select(['pid'], self::TABLE, ['deleted' => 0], [], [], 1)
|
||||||
|
->fetchAssociative();
|
||||||
|
return (int)($row['pid'] ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ensure one market record per canonical industry; fill title->uid map. */
|
||||||
|
private function ensureMarkets(OutputInterface $output, int $fallbackPid): void
|
||||||
|
{
|
||||||
|
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_vitec_domain_model_market');
|
||||||
|
$rows = $conn->select(['uid', 'title', 'pid'], 'tx_vitec_domain_model_market', ['deleted' => 0])->fetchAllAssociative();
|
||||||
|
$marketPid = $fallbackPid;
|
||||||
|
foreach ($rows as $r) {
|
||||||
|
$this->marketUidByTitle[$this->normTitle((string)$r['title'])] = (int)$r['uid'];
|
||||||
|
$marketPid = (int)$r['pid'];
|
||||||
|
}
|
||||||
|
$canonical = array_unique(array_values(self::INDUSTRY_TOKENS));
|
||||||
|
$datamap = [];
|
||||||
|
foreach ($canonical as $i => $title) {
|
||||||
|
if (!isset($this->marketUidByTitle[$this->normTitle($title)])) {
|
||||||
|
$datamap['tx_vitec_domain_model_market']['NEWMARKET' . $i] = ['pid' => $marketPid, 'title' => $title];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($datamap !== []) {
|
||||||
|
$dh = GeneralUtility::makeInstance(DataHandler::class);
|
||||||
|
$dh->start($datamap, []);
|
||||||
|
$dh->process_datamap();
|
||||||
|
foreach ($datamap['tx_vitec_domain_model_market'] as $key => $fields) {
|
||||||
|
$uid = (int)($dh->substNEWwithIDs[$key] ?? 0);
|
||||||
|
if ($uid > 0) {
|
||||||
|
$this->marketUidByTitle[$this->normTitle($fields['title'])] = $uid;
|
||||||
|
$output->writeln(" <info>created market: {$fields['title']} ($uid)</info>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string[] canonical industry titles for one story */
|
||||||
|
private function industriesForStory(array $page, ?array $card, ?array $useCase): array
|
||||||
|
{
|
||||||
|
$out = [];
|
||||||
|
if ($useCase !== null) {
|
||||||
|
foreach ($this->catsByCeUid[(int)$useCase['uid']] ?? [] as $t) {
|
||||||
|
if ($t !== '') {
|
||||||
|
$out[] = $t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($out === [] && $card !== null) {
|
||||||
|
$tokens = preg_split('/\s+/', strtolower((string)($card['tx_mask_markets_card_market2'] ?? ''))) ?: [];
|
||||||
|
foreach ($tokens as $tok) {
|
||||||
|
if (isset(self::INDUSTRY_TOKENS[$tok])) {
|
||||||
|
$out[] = self::INDUSTRY_TOKENS[$tok];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array_values(array_unique($out));
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================== story import
|
||||||
|
|
||||||
|
/** @return array{0:string,1:string,2:int,3:int,4:string} */
|
||||||
|
private function importStory(array $page, int $storagePid, bool $dryRun, bool $force, OutputInterface $output): array
|
||||||
|
{
|
||||||
|
$pageUid = (int)$page['uid'];
|
||||||
|
$slugTail = basename((string)$page['slug']);
|
||||||
|
$slug = '/' . $slugTail;
|
||||||
|
|
||||||
|
$card = $this->cardByPageUid[$pageUid] ?? null;
|
||||||
|
$useCase = $this->useCaseByKey[$this->normTitle((string)$page['title'])] ?? null;
|
||||||
|
$promo = null;
|
||||||
|
foreach ($this->rootsByPid[$pageUid] ?? [] as $ce) {
|
||||||
|
if ($ce['CType'] === 'mask_web__success_story__full_width_promo') {
|
||||||
|
$promo = $ce;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$industries = $this->industriesForStory($page, $card, $useCase);
|
||||||
|
$ceSpecs = $this->transformContent($pageUid);
|
||||||
|
|
||||||
|
// ---- existing?
|
||||||
|
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable(self::TABLE);
|
||||||
|
$existing = $conn->select(['uid'], self::TABLE, ['slug' => $slug, 'deleted' => 0])->fetchAssociative()
|
||||||
|
?: $conn->select(['uid'], self::TABLE, ['slug' => $slugTail, 'deleted' => 0])->fetchAssociative();
|
||||||
|
|
||||||
|
$imgCount = 0;
|
||||||
|
foreach ($ceSpecs as $s) {
|
||||||
|
$imgCount += count($s['files'] ?? []);
|
||||||
|
foreach ($s['items'] ?? [] as $it) {
|
||||||
|
$imgCount += count($it['files'] ?? []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dryRun) {
|
||||||
|
$output->writeln(sprintf(
|
||||||
|
' <comment>%s</comment> ces=%d quotes=%d cols=%d imgs=%d markets=[%s] card=%s uc=%s hero=%s%s',
|
||||||
|
$slugTail,
|
||||||
|
count($ceSpecs),
|
||||||
|
count(array_filter($ceSpecs, fn($s) => $s['CType'] === 'vitec_quotation')),
|
||||||
|
count(array_filter($ceSpecs, fn($s) => $s['CType'] === 'vitec_columns')),
|
||||||
|
$imgCount,
|
||||||
|
implode(',', $industries),
|
||||||
|
$card ? 'y' : 'MISSING',
|
||||||
|
$useCase ? 'y' : '-',
|
||||||
|
$promo ? 'y' : 'MISSING',
|
||||||
|
$existing ? ' EXISTS(uid=' . $existing['uid'] . ')' : ''
|
||||||
|
));
|
||||||
|
return [$slugTail, $existing ? 'dry(exists)' : 'dry', count($ceSpecs), $imgCount, implode(',', $industries)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($existing) {
|
||||||
|
if (!$force) {
|
||||||
|
return [$slugTail, 'skipped', 0, 0, ''];
|
||||||
|
}
|
||||||
|
$dh = GeneralUtility::makeInstance(DataHandler::class);
|
||||||
|
$dh->start([], [self::TABLE => [(int)$existing['uid'] => ['delete' => 1]]]);
|
||||||
|
$dh->process_cmdmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- assemble datamap
|
||||||
|
$datamap = [];
|
||||||
|
$storyKey = 'NEWSTORY1';
|
||||||
|
$refCounter = 0;
|
||||||
|
$newRef = function (string $identifier, string $table, string $key, string $field, array $meta = []) use (&$datamap, &$refCounter, $storagePid): ?string {
|
||||||
|
$fileUid = $this->fileUidFor($identifier);
|
||||||
|
if ($fileUid === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$refKey = 'NEWREF' . (++$refCounter);
|
||||||
|
$datamap['sys_file_reference'][$refKey] = array_filter([
|
||||||
|
'pid' => $storagePid,
|
||||||
|
'uid_local' => 'sys_file_' . $fileUid,
|
||||||
|
'tablenames' => $table,
|
||||||
|
'uid_foreign' => $key,
|
||||||
|
'fieldname' => $field,
|
||||||
|
'title' => $meta['title'] ?? null,
|
||||||
|
'alternative' => $meta['alternative'] ?? null,
|
||||||
|
'description' => $meta['description'] ?? null,
|
||||||
|
'crop' => $meta['crop'] ?? null,
|
||||||
|
], static fn($v) => $v !== null && $v !== '');
|
||||||
|
return $refKey;
|
||||||
|
};
|
||||||
|
$attach = function (array $refs, string $table, string $key, string $newField) use ($newRef): string {
|
||||||
|
$ids = [];
|
||||||
|
foreach ($refs as $r) {
|
||||||
|
$id = $newRef((string)$r['identifier'], $table, $key, $newField, $r);
|
||||||
|
if ($id !== null) {
|
||||||
|
$ids[] = $id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return implode(',', $ids);
|
||||||
|
};
|
||||||
|
|
||||||
|
// story base fields
|
||||||
|
$subtitle = trim(strip_tags((string)($card['tx_mask_web__markets_card_frontttext'] ?? '')));
|
||||||
|
if ($subtitle === '' && $useCase !== null) {
|
||||||
|
$subtitle = (string)($useCase['tx_mask_tile_teaser'] ?? '');
|
||||||
|
}
|
||||||
|
$textColor = strtolower((string)($promo['tx_mask_web__success_story__full_width_promo_textcolor'] ?? ''));
|
||||||
|
$overlay = (string)($promo['tx_mask_web__success_story__full_width_promo_color'] ?? '');
|
||||||
|
|
||||||
|
$story = [
|
||||||
|
'pid' => $storagePid,
|
||||||
|
'title' => (string)$page['title'],
|
||||||
|
'slug' => $slug,
|
||||||
|
'subtitle' => $subtitle,
|
||||||
|
'teaser' => (string)($page['abstract'] ?? '') !== '' ? (string)$page['abstract'] : (string)($page['description'] ?? ''),
|
||||||
|
'seo_title' => (string)($page['seo_title'] ?? ''),
|
||||||
|
'seo_description' => (string)($page['description'] ?? ''),
|
||||||
|
'og_title' => (string)($page['og_title'] ?? ''),
|
||||||
|
'og_description' => (string)($page['og_description'] ?? ''),
|
||||||
|
'twitter_title' => (string)($page['twitter_title'] ?? ''),
|
||||||
|
'twitter_description' => (string)($page['twitter_description'] ?? ''),
|
||||||
|
'no_index' => (int)($page['no_index'] ?? 0),
|
||||||
|
'no_follow' => (int)($page['no_follow'] ?? 0),
|
||||||
|
'hero_overlay_color' => $overlay,
|
||||||
|
'hero_overlay_opacity' => $overlay !== '' ? 0.4 : 0,
|
||||||
|
'text_theme' => in_array($textColor, ['#fff', '#ffffff', 'white'], true) ? 'light' : 'dark',
|
||||||
|
'markets' => implode(',', array_filter(array_map(
|
||||||
|
fn(string $t): int => $this->marketUidByTitle[$this->normTitle($t)] ?? 0,
|
||||||
|
$industries
|
||||||
|
))),
|
||||||
|
];
|
||||||
|
|
||||||
|
// FAL: card image, logo, hero, og/twitter
|
||||||
|
if ($card !== null) {
|
||||||
|
$story['card_image'] = $attach(
|
||||||
|
array_slice($this->refs('tt_content', (int)$card['uid'], 'tx_mask_web__markets_card_frontimage'), 0, 1),
|
||||||
|
self::TABLE, $storyKey, 'card_image'
|
||||||
|
);
|
||||||
|
$story['customer_logo'] = $attach(
|
||||||
|
array_slice($this->refs('tt_content', (int)$card['uid'], 'tx_mask_web__markets_card_customerlogo'), 0, 1),
|
||||||
|
self::TABLE, $storyKey, 'customer_logo'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$heroRefs = $promo !== null
|
||||||
|
? $this->refs('tt_content', (int)$promo['uid'], 'tx_mask_web__success_story__full_width_promo_image')
|
||||||
|
: [];
|
||||||
|
if ($heroRefs === []) {
|
||||||
|
$heroRefs = $this->refs('pages', $pageUid, 'heroimage_big');
|
||||||
|
}
|
||||||
|
$story['hero_bgimage'] = $attach(array_slice($heroRefs, 0, 1), self::TABLE, $storyKey, 'hero_bgimage');
|
||||||
|
$story['og_image'] = $attach(array_slice($this->refs('pages', $pageUid, 'og_image'), 0, 1), self::TABLE, $storyKey, 'og_image');
|
||||||
|
$story['twitter_image'] = $attach(array_slice($this->refs('pages', $pageUid, 'twitter_image'), 0, 1), self::TABLE, $storyKey, 'twitter_image');
|
||||||
|
|
||||||
|
// content elements
|
||||||
|
$ceKeys = [];
|
||||||
|
$ceCounter = 0;
|
||||||
|
$itemCounter = 0;
|
||||||
|
foreach ($ceSpecs as $spec) {
|
||||||
|
$ceKey = 'NEWCE' . (++$ceCounter);
|
||||||
|
$fields = $spec['fields'];
|
||||||
|
$fields['pid'] = $storagePid;
|
||||||
|
$fields['CType'] = $spec['CType'];
|
||||||
|
$fields['colPos'] = 999;
|
||||||
|
foreach ($spec['files'] ?? [] as $f) {
|
||||||
|
$fields[$f['field']] = $attach($f['refs'], 'tt_content', $ceKey, $f['field']);
|
||||||
|
}
|
||||||
|
if (($spec['CType'] === 'vitec_columns') && $this->collectionTable !== '' && !empty($spec['items'])) {
|
||||||
|
$itemKeys = [];
|
||||||
|
foreach ($spec['items'] as $item) {
|
||||||
|
$itemKey = 'NEWITEM' . (++$itemCounter);
|
||||||
|
$itemFields = $item['fields'];
|
||||||
|
$itemFields['pid'] = $storagePid;
|
||||||
|
foreach ($item['files'] ?? [] as $f) {
|
||||||
|
$itemFields[$f['field']] = $attach($f['refs'], $this->collectionTable, $itemKey, $f['field']);
|
||||||
|
}
|
||||||
|
$datamap[$this->collectionTable][$itemKey] = $itemFields;
|
||||||
|
$itemKeys[] = $itemKey;
|
||||||
|
}
|
||||||
|
$fields[$this->cbCol('tt_content', 'items')] = implode(',', $itemKeys);
|
||||||
|
}
|
||||||
|
$datamap['tt_content'][$ceKey] = $fields;
|
||||||
|
$ceKeys[] = $ceKey;
|
||||||
|
}
|
||||||
|
$story['content_elements'] = implode(',', $ceKeys);
|
||||||
|
$datamap[self::TABLE][$storyKey] = $story;
|
||||||
|
|
||||||
|
$dh = GeneralUtility::makeInstance(DataHandler::class);
|
||||||
|
$dh->start($datamap, []);
|
||||||
|
$dh->process_datamap();
|
||||||
|
if ($dh->errorLog !== []) {
|
||||||
|
throw new \RuntimeException('DataHandler: ' . implode(' | ', array_slice($dh->errorLog, 0, 3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$slugTail, $existing ? 'reimported' : 'created', count($ceSpecs), $imgCount, implode(',', $industries)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================== content transform
|
||||||
|
|
||||||
|
/** @return array<int,array<string,mixed>> ordered CE specs */
|
||||||
|
private function transformContent(int $pageUid): array
|
||||||
|
{
|
||||||
|
$specs = [];
|
||||||
|
$roots = $this->rootsByPid[$pageUid] ?? [];
|
||||||
|
|
||||||
|
// intro (colPos 5): hero subline — first element, CTA buttons stripped
|
||||||
|
foreach ($roots as $ce) {
|
||||||
|
if ((int)$ce['colPos'] === 5 && $ce['CType'] === 'text' && !empty($ce['bodytext'])) {
|
||||||
|
$body = preg_replace('/<p[^>]*>(?:(?!<\/p>).)*btn(?:(?!<\/p>).)*<\/p>/is', '', (string)$ce['bodytext']) ?? '';
|
||||||
|
if (trim(strip_tags($body)) !== '') {
|
||||||
|
$specs[] = ['CType' => 'text', 'fields' => ['header' => '', 'bodytext' => trim($body)], 'files' => []];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($roots as $ce) {
|
||||||
|
if ((int)$ce['colPos'] === 0) {
|
||||||
|
$this->transformCe($ce, $specs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $specs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function transformCe(array $ce, array &$specs): void
|
||||||
|
{
|
||||||
|
$ctype = (string)$ce['CType'];
|
||||||
|
if (in_array($ctype, self::SKIP_CTYPES, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (in_array($ctype, self::CONTAINER_CTYPES, true)) {
|
||||||
|
$this->transformContainer($ce, $specs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch ($ctype) {
|
||||||
|
case 'text':
|
||||||
|
$specs[] = $this->textOrQuoteSpec($ce);
|
||||||
|
break;
|
||||||
|
case 'image':
|
||||||
|
case 'textmedia':
|
||||||
|
$field = $ctype === 'image' ? 'image' : 'assets';
|
||||||
|
$spec = [
|
||||||
|
'CType' => $ctype,
|
||||||
|
'fields' => array_filter([
|
||||||
|
'header' => (string)($ce['header'] ?? ''),
|
||||||
|
'header_layout' => (int)($ce['header_layout'] ?? 0),
|
||||||
|
'bodytext' => (string)($ce['bodytext'] ?? ''),
|
||||||
|
], static fn($v) => $v !== '' && $v !== 0),
|
||||||
|
'files' => [],
|
||||||
|
];
|
||||||
|
$refs = $this->refs('tt_content', (int)$ce['uid'], $field);
|
||||||
|
if ($refs !== []) {
|
||||||
|
$spec['files'][] = ['field' => $field, 'refs' => $refs];
|
||||||
|
}
|
||||||
|
if ($spec['files'] !== [] || ($spec['fields']['bodytext'] ?? '') !== '') {
|
||||||
|
$specs[] = $spec;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'html':
|
||||||
|
if (!empty($ce['bodytext'])) {
|
||||||
|
$specs[] = ['CType' => 'html', 'fields' => ['bodytext' => (string)$ce['bodytext']], 'files' => []];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// unknown → keep text-ish content if any
|
||||||
|
if (!empty($ce['bodytext']) || !empty($ce['header'])) {
|
||||||
|
$specs[] = ['CType' => 'text', 'fields' => [
|
||||||
|
'header' => (string)($ce['header'] ?? ''),
|
||||||
|
'bodytext' => (string)($ce['bodytext'] ?? ''),
|
||||||
|
], 'files' => []];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Two clean columns -> vitec_columns; everything else flattens in order. */
|
||||||
|
private function transformContainer(array $ce, array &$specs): void
|
||||||
|
{
|
||||||
|
$children = $this->childrenByParent[(int)$ce['uid']] ?? [];
|
||||||
|
if ($children === []) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$byCol = [];
|
||||||
|
foreach ($children as $child) {
|
||||||
|
$byCol[(int)$child['colPos'] % 100][] = $child;
|
||||||
|
}
|
||||||
|
ksort($byCol);
|
||||||
|
|
||||||
|
$isSimple = static fn(array $c): bool => in_array($c['CType'], ['text', 'image'], true)
|
||||||
|
&& stripos((string)($c['bodytext'] ?? ''), '<blockquote') === false;
|
||||||
|
$cols = array_keys($byCol);
|
||||||
|
$allSimple = count($cols) === 2 && count($children) <= 4
|
||||||
|
&& array_reduce($children, static fn($ok, $c) => $ok && $isSimple($c), true);
|
||||||
|
|
||||||
|
if ($allSimple) {
|
||||||
|
$items = [];
|
||||||
|
foreach ($byCol as $colIdx => $colCes) {
|
||||||
|
$side = $colIdx === $cols[0] ? 'left' : 'right';
|
||||||
|
foreach ($colCes as $c) {
|
||||||
|
$t = $this->collectionTable;
|
||||||
|
if ($c['CType'] === 'text') {
|
||||||
|
$items[] = ['fields' => [
|
||||||
|
$this->cbCol($t, 'column') => $side, $this->cbCol($t, 'item_type') => 'text',
|
||||||
|
$this->cbCol($t, 'headline') => (string)($c['header'] ?? ''),
|
||||||
|
$this->cbCol($t, 'text') => (string)($c['bodytext'] ?? ''),
|
||||||
|
], 'files' => []];
|
||||||
|
} else {
|
||||||
|
$refs = $this->refs('tt_content', (int)$c['uid'], 'image');
|
||||||
|
$items[] = ['fields' => [
|
||||||
|
$this->cbCol($t, 'column') => $side, $this->cbCol($t, 'item_type') => 'image',
|
||||||
|
$this->cbCol($t, 'headline') => (string)($c['header'] ?? ''),
|
||||||
|
], 'files' => $refs !== [] ? [['field' => $this->cbCol($t, 'image'), 'refs' => array_slice($refs, 0, 1)]] : []];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$specs[] = [
|
||||||
|
'CType' => 'vitec_columns',
|
||||||
|
'fields' => ['header' => (string)($ce['header'] ?? ''), $this->cbCol('tt_content', 'layout') => 'cols_50_50'],
|
||||||
|
'files' => [],
|
||||||
|
'items' => $items,
|
||||||
|
];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// flatten: children first; the container header only becomes a heading
|
||||||
|
// when the container actually contributed content (skips e.g. the old
|
||||||
|
// "Related Success Stories" section whose children are all shortcuts).
|
||||||
|
$childSpecs = [];
|
||||||
|
foreach ($byCol as $colCes) {
|
||||||
|
foreach ($colCes as $child) {
|
||||||
|
$this->transformCe($child, $childSpecs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$header = trim((string)($ce['header'] ?? ''));
|
||||||
|
if ($childSpecs !== [] && $header !== '' && !str_starts_with($header, '///')) {
|
||||||
|
$specs[] = ['CType' => 'text', 'fields' => ['header' => $header], 'files' => []];
|
||||||
|
}
|
||||||
|
foreach ($childSpecs as $cs) {
|
||||||
|
$specs[] = $cs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** blockquote text CEs become vitec_quotation; the rest stay text. */
|
||||||
|
private function textOrQuoteSpec(array $ce): array
|
||||||
|
{
|
||||||
|
$body = (string)($ce['bodytext'] ?? '');
|
||||||
|
$header = (string)($ce['header'] ?? '');
|
||||||
|
|
||||||
|
if (stripos($body, '<blockquote') !== false) {
|
||||||
|
$quote = $body;
|
||||||
|
$name = '';
|
||||||
|
$position = '';
|
||||||
|
if (preg_match('/<blockquote[^>]*>(.*)<\/blockquote>/is', $body, $m)) {
|
||||||
|
$inner = $m[1];
|
||||||
|
// attribution paragraph: <p><strong>— Name</strong><br/>Position</p>
|
||||||
|
if (preg_match('/<p>\s*<strong>\s*(?:—|—|-)?\s*(.*?)<\/strong>\s*(?:<br\s*\/?>)?\s*(.*?)<\/p>\s*$/is', $inner, $a)) {
|
||||||
|
$name = trim(strip_tags($a[1]));
|
||||||
|
$position = trim(strip_tags($a[2]));
|
||||||
|
$inner = (string)preg_replace('/<p>\s*<strong>\s*(?:—|—|-)?.*?<\/p>\s*$/is', '', $inner);
|
||||||
|
}
|
||||||
|
$quote = trim(strip_tags($inner));
|
||||||
|
$quote = trim($quote, "“”\"' \u{201C}\u{201D}");
|
||||||
|
}
|
||||||
|
return ['CType' => 'vitec_quotation', 'fields' => [
|
||||||
|
$this->cbCol('tt_content', 'quote') => $quote,
|
||||||
|
$this->cbCol('tt_content', 'quote_name') => $name,
|
||||||
|
$this->cbCol('tt_content', 'quote_position') => $position,
|
||||||
|
], 'files' => []];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['CType' => 'text', 'fields' => array_filter([
|
||||||
|
'header' => strcasecmp($header, 'Quote') === 0 ? '' : $header,
|
||||||
|
'header_layout' => (int)($ce['header_layout'] ?? 0),
|
||||||
|
'bodytext' => $body,
|
||||||
|
], static fn($v) => $v !== '' && $v !== 0), 'files' => []];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================================================================== files
|
||||||
|
|
||||||
|
/** Old-site identifier -> new-site sys_file uid (staged under FILES_BASE). */
|
||||||
|
private function fileUidFor(string $identifier): ?int
|
||||||
|
{
|
||||||
|
if (isset($this->fileUidCache[$identifier])) {
|
||||||
|
return $this->fileUidCache[$identifier] ?: null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$file = GeneralUtility::makeInstance(ResourceFactory::class)
|
||||||
|
->getFileObjectFromCombinedIdentifier('1:' . self::FILES_BASE . $identifier);
|
||||||
|
$uid = $file !== null ? (int)$file->getUid() : 0;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$uid = 0;
|
||||||
|
}
|
||||||
|
$this->fileUidCache[$identifier] = $uid;
|
||||||
|
return $uid ?: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
packages/vitec/Classes/Controller/CustomerController.php
Executable file
21
packages/vitec/Classes/Controller/CustomerController.php
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\Controller;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomerController — Extbase registration target for the Customerlogos
|
||||||
|
* plugin. In headless mode the JSON output is produced by
|
||||||
|
* CustomerlogosJsonRenderer, not by this controller.
|
||||||
|
*/
|
||||||
|
class CustomerController extends ActionController
|
||||||
|
{
|
||||||
|
public function listAction(): ResponseInterface
|
||||||
|
{
|
||||||
|
return $this->htmlResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
21
packages/vitec/Classes/Controller/LocationController.php
Executable file
21
packages/vitec/Classes/Controller/LocationController.php
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\Controller;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LocationController — Extbase registration target for the Locationlist
|
||||||
|
* plugin. In headless mode the JSON output is produced by
|
||||||
|
* LocationsJsonRenderer, not by this controller.
|
||||||
|
*/
|
||||||
|
class LocationController extends ActionController
|
||||||
|
{
|
||||||
|
public function listAction(): ResponseInterface
|
||||||
|
{
|
||||||
|
return $this->htmlResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
21
packages/vitec/Classes/Controller/ModelcardController.php
Executable file
21
packages/vitec/Classes/Controller/ModelcardController.php
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\Controller;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModelcardController — Extbase registration target for the VITEC Card
|
||||||
|
* plugin. In headless mode the JSON output is produced by
|
||||||
|
* ModelcardJsonRenderer, not by this controller.
|
||||||
|
*/
|
||||||
|
class ModelcardController extends ActionController
|
||||||
|
{
|
||||||
|
public function listAction(): ResponseInterface
|
||||||
|
{
|
||||||
|
return $this->htmlResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,9 @@ use Evomedien\Vitec\UserFunc\DownloadcardJsonRenderer;
|
|||||||
use Evomedien\Vitec\UserFunc\DownloadcardcollectionJsonRenderer;
|
use Evomedien\Vitec\UserFunc\DownloadcardcollectionJsonRenderer;
|
||||||
use Evomedien\Vitec\UserFunc\DatasheetsJsonRenderer;
|
use Evomedien\Vitec\UserFunc\DatasheetsJsonRenderer;
|
||||||
use Evomedien\Vitec\UserFunc\EventlistJsonRenderer;
|
use Evomedien\Vitec\UserFunc\EventlistJsonRenderer;
|
||||||
|
use Evomedien\Vitec\UserFunc\LocationsJsonRenderer;
|
||||||
|
use Evomedien\Vitec\UserFunc\CustomerlogosJsonRenderer;
|
||||||
|
use Evomedien\Vitec\UserFunc\ModelcardJsonRenderer;
|
||||||
use Evomedien\Vitec\UserFunc\NewsJsonRenderer;
|
use Evomedien\Vitec\UserFunc\NewsJsonRenderer;
|
||||||
use TYPO3\CMS\Core\Database\Connection;
|
use TYPO3\CMS\Core\Database\Connection;
|
||||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
@@ -111,6 +114,9 @@ final class ContainerChildrenProcessor implements DataProcessorInterface
|
|||||||
'vitec_downloadcardcollection' => [DownloadcardcollectionJsonRenderer::class, 'downloadcardcollection'],
|
'vitec_downloadcardcollection' => [DownloadcardcollectionJsonRenderer::class, 'downloadcardcollection'],
|
||||||
'vitec_datasheets' => [DatasheetsJsonRenderer::class, 'datasheets'],
|
'vitec_datasheets' => [DatasheetsJsonRenderer::class, 'datasheets'],
|
||||||
'vitec_eventlist' => [EventlistJsonRenderer::class, 'eventlist'],
|
'vitec_eventlist' => [EventlistJsonRenderer::class, 'eventlist'],
|
||||||
|
'vitec_locationlist' => [LocationsJsonRenderer::class, 'locations'],
|
||||||
|
'vitec_customerlogos' => [CustomerlogosJsonRenderer::class, 'customerlogos'],
|
||||||
|
'vitec_modelcard' => [ModelcardJsonRenderer::class, 'card'],
|
||||||
'news_pi1' => [NewsJsonRenderer::class, 'news'],
|
'news_pi1' => [NewsJsonRenderer::class, 'news'],
|
||||||
'news_newsliststicky' => [NewsJsonRenderer::class, 'news'],
|
'news_newsliststicky' => [NewsJsonRenderer::class, 'news'],
|
||||||
'news_newsselectedlist' => [NewsJsonRenderer::class, 'news'],
|
'news_newsselectedlist' => [NewsJsonRenderer::class, 'news'],
|
||||||
|
|||||||
79
packages/vitec/Classes/Middleware/SuccessStoryPathRewrite.php
Executable file
79
packages/vitec/Classes/Middleware/SuccessStoryPathRewrite.php
Executable file
@@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\Middleware;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pretty detail URLs for Success Stories.
|
||||||
|
*
|
||||||
|
* Public URL: /success-stories/<slug> (old-site SEO URLs)
|
||||||
|
* Real page: /success-stories/story/<slug> (subpage holding ONLY the
|
||||||
|
* usecaseshow plugin)
|
||||||
|
*
|
||||||
|
* TYPO3's page router always resolves /success-stories/<slug> to the LIST
|
||||||
|
* page (longest page-slug prefix), so the detail subpage could never answer
|
||||||
|
* that URL. This middleware rewrites the request path internally — before
|
||||||
|
* page resolution — whenever <slug> matches an existing (visible) success
|
||||||
|
* story. Real subpages of /success-stories are unaffected: no story match,
|
||||||
|
* no rewrite. The browser URL never changes.
|
||||||
|
*
|
||||||
|
* Exception-safe: any failure leaves the request untouched.
|
||||||
|
*/
|
||||||
|
final class SuccessStoryPathRewrite implements MiddlewareInterface
|
||||||
|
{
|
||||||
|
private const LIST_PATH = '/success-stories';
|
||||||
|
private const DETAIL_SEGMENT = 'story';
|
||||||
|
|
||||||
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||||
|
{
|
||||||
|
$debug = 'no-match';
|
||||||
|
try {
|
||||||
|
$path = $request->getUri()->getPath();
|
||||||
|
if (preg_match('#^' . self::LIST_PATH . '/([a-zA-Z0-9\-]+)/?$#', $path, $m) === 1
|
||||||
|
&& $m[1] !== self::DETAIL_SEGMENT
|
||||||
|
) {
|
||||||
|
if ($this->isStorySlug($m[1])) {
|
||||||
|
$uri = $request->getUri()->withPath(
|
||||||
|
self::LIST_PATH . '/' . self::DETAIL_SEGMENT . '/' . $m[1]
|
||||||
|
);
|
||||||
|
$request = $request->withUri($uri);
|
||||||
|
$debug = 'rewritten';
|
||||||
|
} else {
|
||||||
|
$debug = 'slug-not-found:' . $m[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$debug = 'exception:' . substr($e->getMessage(), 0, 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEMP-DIAG header (remove after verification)
|
||||||
|
return $handler->handle($request)->withHeader('X-Vitec-Story-Rewrite', $debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isStorySlug(string $slug): bool
|
||||||
|
{
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('tx_vitec_domain_model_usecase');
|
||||||
|
$row = $qb
|
||||||
|
->select('uid')
|
||||||
|
->from('tx_vitec_domain_model_usecase')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('slug', $qb->createNamedParameter($slug)),
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
return $row !== false;
|
||||||
|
}
|
||||||
|
}
|
||||||
127
packages/vitec/Classes/Preview/ModelcardPreviewRenderer.php
Executable file
127
packages/vitec/Classes/Preview/ModelcardPreviewRenderer.php
Executable file
@@ -0,0 +1,127 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\Preview;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
use TYPO3\CMS\Backend\Preview\StandardContentPreviewRenderer;
|
||||||
|
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem;
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||||
|
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page-module preview for the VITEC Card plugin (vitec_modelcard):
|
||||||
|
* type badge, selected record title, thumbnail and layout badge.
|
||||||
|
* Registered via TCA types.vitec_modelcard.previewRenderer.
|
||||||
|
*/
|
||||||
|
class ModelcardPreviewRenderer extends StandardContentPreviewRenderer
|
||||||
|
{
|
||||||
|
private const MODEL_TABLES = [
|
||||||
|
'product' => 'tx_vitec_domain_model_product',
|
||||||
|
'story' => 'tx_vitec_domain_model_usecase',
|
||||||
|
'market' => 'tx_vitec_domain_model_market',
|
||||||
|
'solution' => 'tx_vitec_domain_model_solution',
|
||||||
|
];
|
||||||
|
|
||||||
|
private const TYPE_LABELS = [
|
||||||
|
'product' => 'Product',
|
||||||
|
'story' => 'Success Story',
|
||||||
|
'market' => 'Market',
|
||||||
|
'solution' => 'Solution',
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Card-image FAL field per model type (first hit wins). */
|
||||||
|
private const IMAGE_FIELDS = [
|
||||||
|
'product' => ['image', 'productimage'],
|
||||||
|
'story' => ['card_image', 'hero_bgimage'],
|
||||||
|
'market' => ['image'],
|
||||||
|
'solution' => ['image'],
|
||||||
|
];
|
||||||
|
|
||||||
|
public function renderPageModulePreviewContent(GridColumnItem $item): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$record = $item->getRecord();
|
||||||
|
|
||||||
|
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
||||||
|
$flexFormData = $flexFormService->convertFlexFormContentToArray($record['pi_flexform'] ?? '');
|
||||||
|
$settings = $flexFormData['settings'] ?? [];
|
||||||
|
|
||||||
|
$modelType = (string)($settings['modelType'] ?? 'product');
|
||||||
|
$layout = (string)($settings['layout'] ?? 'vertical');
|
||||||
|
$recordUid = (int)($settings[$modelType === 'story' ? 'story' : $modelType] ?? 0);
|
||||||
|
|
||||||
|
$title = '';
|
||||||
|
$subtitle = '';
|
||||||
|
$imageUrl = '';
|
||||||
|
if ($recordUid > 0 && isset(self::MODEL_TABLES[$modelType])) {
|
||||||
|
$table = self::MODEL_TABLES[$modelType];
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
|
||||||
|
$row = $qb
|
||||||
|
->select('*')
|
||||||
|
->from($table)
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('uid', $qb->createNamedParameter($recordUid, ParameterType::INTEGER)),
|
||||||
|
$qb->expr()->eq('deleted', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
if ($row) {
|
||||||
|
$title = (string)($row['title'] ?? '');
|
||||||
|
$subtitle = (string)($row['subtitle'] ?? ($row['teaser'] ?? ''));
|
||||||
|
$imageUrl = $this->firstImageUrl($table, $recordUid, self::IMAGE_FIELDS[$modelType]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||||
|
$view->setTemplatePathAndFilename('EXT:vitec/Resources/Private/Templates/Preview/Modelcard.html');
|
||||||
|
$view->assignMultiple([
|
||||||
|
'typeLabel' => self::TYPE_LABELS[$modelType] ?? $modelType,
|
||||||
|
'layout' => $layout,
|
||||||
|
'recordUid' => $recordUid,
|
||||||
|
'title' => $title,
|
||||||
|
'subtitle' => $subtitle,
|
||||||
|
'imageUrl' => $imageUrl,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $view->render();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return parent::renderPageModulePreviewContent($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param string[] $fieldNames */
|
||||||
|
private function firstImageUrl(string $table, int $uid, array $fieldNames): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
foreach ($fieldNames as $fieldName) {
|
||||||
|
$ref = $qb
|
||||||
|
->select('uid')
|
||||||
|
->from('sys_file_reference')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('tablenames', $qb->createNamedParameter($table, ParameterType::STRING)),
|
||||||
|
$qb->expr()->eq('fieldname', $qb->createNamedParameter($fieldName, ParameterType::STRING)),
|
||||||
|
$qb->expr()->eq('uid_foreign', $qb->createNamedParameter($uid, ParameterType::INTEGER)),
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
if ($ref) {
|
||||||
|
$file = GeneralUtility::makeInstance(ResourceFactory::class)
|
||||||
|
->getFileReferenceObject((int)$ref['uid']);
|
||||||
|
return (string)$file->getPublicUrl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// no thumb
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,9 @@ use Evomedien\Vitec\UserFunc\DownloadcardJsonRenderer;
|
|||||||
use Evomedien\Vitec\UserFunc\DownloadcardcollectionJsonRenderer;
|
use Evomedien\Vitec\UserFunc\DownloadcardcollectionJsonRenderer;
|
||||||
use Evomedien\Vitec\UserFunc\DatasheetsJsonRenderer;
|
use Evomedien\Vitec\UserFunc\DatasheetsJsonRenderer;
|
||||||
use Evomedien\Vitec\UserFunc\EventlistJsonRenderer;
|
use Evomedien\Vitec\UserFunc\EventlistJsonRenderer;
|
||||||
|
use Evomedien\Vitec\UserFunc\LocationsJsonRenderer;
|
||||||
|
use Evomedien\Vitec\UserFunc\CustomerlogosJsonRenderer;
|
||||||
|
use Evomedien\Vitec\UserFunc\ModelcardJsonRenderer;
|
||||||
use Evomedien\Vitec\UserFunc\NewsJsonRenderer;
|
use Evomedien\Vitec\UserFunc\NewsJsonRenderer;
|
||||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
@@ -76,6 +79,9 @@ final class ContentElementResolver
|
|||||||
'vitec_downloadcardcollection' => [DownloadcardcollectionJsonRenderer::class, 'downloadcardcollection'],
|
'vitec_downloadcardcollection' => [DownloadcardcollectionJsonRenderer::class, 'downloadcardcollection'],
|
||||||
'vitec_datasheets' => [DatasheetsJsonRenderer::class, 'datasheets'],
|
'vitec_datasheets' => [DatasheetsJsonRenderer::class, 'datasheets'],
|
||||||
'vitec_eventlist' => [EventlistJsonRenderer::class, 'eventlist'],
|
'vitec_eventlist' => [EventlistJsonRenderer::class, 'eventlist'],
|
||||||
|
'vitec_locationlist' => [LocationsJsonRenderer::class, 'locations'],
|
||||||
|
'vitec_customerlogos' => [CustomerlogosJsonRenderer::class, 'customerlogos'],
|
||||||
|
'vitec_modelcard' => [ModelcardJsonRenderer::class, 'card'],
|
||||||
'news_pi1' => [NewsJsonRenderer::class, 'news'],
|
'news_pi1' => [NewsJsonRenderer::class, 'news'],
|
||||||
'news_newsliststicky' => [NewsJsonRenderer::class, 'news'],
|
'news_newsliststicky' => [NewsJsonRenderer::class, 'news'],
|
||||||
'news_newsselectedlist' => [NewsJsonRenderer::class, 'news'],
|
'news_newsselectedlist' => [NewsJsonRenderer::class, 'news'],
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ final class UsecaseSerializer
|
|||||||
'teaser' => (string)($u['teaser'] ?? ''),
|
'teaser' => (string)($u['teaser'] ?? ''),
|
||||||
'cardImage' => $this->image($uid, 'card_image'),
|
'cardImage' => $this->image($uid, 'card_image'),
|
||||||
'customerLogo' => $this->image($uid, 'customer_logo'),
|
'customerLogo' => $this->image($uid, 'customer_logo'),
|
||||||
'market' => $this->market((int)($u['market'] ?? 0)),
|
'markets' => $this->relationMulti('tx_vitec_usecase_market_mm', 'tx_vitec_domain_model_market', $uid),
|
||||||
'categories' => $this->categories($uid),
|
'categories' => $this->categories($uid),
|
||||||
'featured' => (bool)($u['featured'] ?? false),
|
'featured' => (bool)($u['featured'] ?? false),
|
||||||
'layoutVariant' => (string)($u['layout_variant'] ?? 'standard'),
|
'layoutVariant' => (string)($u['layout_variant'] ?? 'standard'),
|
||||||
@@ -75,7 +75,7 @@ final class UsecaseSerializer
|
|||||||
'contentElements' => $this->contentElements($uid),
|
'contentElements' => $this->contentElements($uid),
|
||||||
'related' => [
|
'related' => [
|
||||||
'show' => (bool)($u['show_related'] ?? true),
|
'show' => (bool)($u['show_related'] ?? true),
|
||||||
'market' => $base['market'],
|
'markets' => $base['markets'],
|
||||||
'solutions' => $this->relationMulti('tx_vitec_usecase_solution_mm', 'tx_vitec_domain_model_solution', $uid),
|
'solutions' => $this->relationMulti('tx_vitec_usecase_solution_mm', 'tx_vitec_domain_model_solution', $uid),
|
||||||
'products' => $this->relationMulti('tx_vitec_usecase_product_mm', 'tx_vitec_domain_model_product', $uid),
|
'products' => $this->relationMulti('tx_vitec_usecase_product_mm', 'tx_vitec_domain_model_product', $uid),
|
||||||
'categories' => $base['categories'],
|
'categories' => $base['categories'],
|
||||||
@@ -129,6 +129,20 @@ final class UsecaseSerializer
|
|||||||
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
$fileReference = $resourceFactory->getFileReferenceObject((int)$ref['uid']);
|
$fileReference = $resourceFactory->getFileReferenceObject((int)$ref['uid']);
|
||||||
|
|
||||||
|
if (str_contains((string)$fileReference->getMimeType(), 'svg')) {
|
||||||
|
// SVG: no processing/srcset — deliver the file as-is.
|
||||||
|
return [
|
||||||
|
'uid' => (int)$ref['uid'],
|
||||||
|
'url' => (string)$fileReference->getPublicUrl(),
|
||||||
|
'title' => (string)($ref['title'] ?? ''),
|
||||||
|
'alternative' => (string)($ref['alternative'] ?? ''),
|
||||||
|
'description' => (string)($ref['description'] ?? ''),
|
||||||
|
'srcset' => [],
|
||||||
|
'properties' => ['mimeType' => $fileReference->getMimeType()],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$srcset = [];
|
$srcset = [];
|
||||||
foreach (self::IMAGE_WIDTHS as $width) {
|
foreach (self::IMAGE_WIDTHS as $width) {
|
||||||
$variant = $imageService->applyProcessingInstructions(
|
$variant = $imageService->applyProcessingInstructions(
|
||||||
@@ -165,6 +179,114 @@ final class UsecaseSerializer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All FAL images of one field (multi-reference), same shape as image().
|
||||||
|
*
|
||||||
|
* @return array<int,array<string,mixed>>
|
||||||
|
*/
|
||||||
|
public function images(int $recordUid, string $fieldName, ?string $table = null): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$table = $table ?? self::TABLE;
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
$refs = $qb
|
||||||
|
->select('sfr.uid')
|
||||||
|
->from('sys_file_reference', 'sfr')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('sfr.tablenames', $qb->createNamedParameter($table, ParameterType::STRING)),
|
||||||
|
$qb->expr()->eq('sfr.fieldname', $qb->createNamedParameter($fieldName, ParameterType::STRING)),
|
||||||
|
$qb->expr()->eq('sfr.uid_foreign', $qb->createNamedParameter($recordUid, ParameterType::INTEGER)),
|
||||||
|
$qb->expr()->eq('sfr.deleted', 0),
|
||||||
|
$qb->expr()->eq('sfr.hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sfr.sorting_foreign')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$out = [];
|
||||||
|
foreach ($refs as $i => $r) {
|
||||||
|
// reuse the single-image resolver per reference position
|
||||||
|
$img = $this->imageByReferenceUid((int)$r['uid']);
|
||||||
|
if ($img !== null) {
|
||||||
|
$out[] = $img;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve one sys_file_reference uid to the standard image shape.
|
||||||
|
*
|
||||||
|
* @return array<string,mixed>|null
|
||||||
|
*/
|
||||||
|
private function imageByReferenceUid(int $refUid): ?array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
$ref = $qb
|
||||||
|
->select('uid', 'title', 'description', 'alternative', 'crop')
|
||||||
|
->from('sys_file_reference')
|
||||||
|
->where($qb->expr()->eq('uid', $qb->createNamedParameter($refUid, ParameterType::INTEGER)))
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
if (!$ref) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject((int)$ref['uid']);
|
||||||
|
|
||||||
|
if (str_contains((string)$fileReference->getMimeType(), 'svg')) {
|
||||||
|
// SVG: no processing/srcset — deliver the file as-is.
|
||||||
|
return [
|
||||||
|
'uid' => (int)$ref['uid'],
|
||||||
|
'url' => (string)$fileReference->getPublicUrl(),
|
||||||
|
'title' => (string)($ref['title'] ?? ''),
|
||||||
|
'alternative' => (string)($ref['alternative'] ?? ''),
|
||||||
|
'description' => (string)($ref['description'] ?? ''),
|
||||||
|
'srcset' => [],
|
||||||
|
'properties' => ['mimeType' => $fileReference->getMimeType()],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$srcset = [];
|
||||||
|
foreach (self::IMAGE_WIDTHS as $width) {
|
||||||
|
$variant = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => $width, 'crop' => $ref['crop'] ?? null]
|
||||||
|
);
|
||||||
|
$srcset[] = ['url' => $imageService->getImageUri($variant), 'width' => $width, 'descriptor' => $width . 'w'];
|
||||||
|
}
|
||||||
|
$default = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => 800, 'crop' => $ref['crop'] ?? null]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => (int)$ref['uid'],
|
||||||
|
'url' => $imageService->getImageUri($default),
|
||||||
|
'title' => (string)($ref['title'] ?? ''),
|
||||||
|
'alternative' => (string)($ref['alternative'] ?? ''),
|
||||||
|
'description' => (string)($ref['description'] ?? ''),
|
||||||
|
'srcset' => $srcset,
|
||||||
|
'properties' => [
|
||||||
|
'width' => $fileReference->getProperty('width'),
|
||||||
|
'height' => $fileReference->getProperty('height'),
|
||||||
|
'mimeType' => $fileReference->getProperty('mime_type'),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FAL video (public URL only). $table as in image().
|
* FAL video (public URL only). $table as in image().
|
||||||
*
|
*
|
||||||
@@ -367,10 +489,39 @@ final class UsecaseSerializer
|
|||||||
*/
|
*/
|
||||||
private function resolveInlineElement(array $row): ?array
|
private function resolveInlineElement(array $row): ?array
|
||||||
{
|
{
|
||||||
if ((string)($row['CType'] ?? '') === self::COLUMNS_CTYPE) {
|
$ctype = (string)($row['CType'] ?? '');
|
||||||
|
if ($ctype === self::COLUMNS_CTYPE) {
|
||||||
return $this->resolveColumnsElement($row);
|
return $this->resolveColumnsElement($row);
|
||||||
}
|
}
|
||||||
return ContentElementResolver::normaliseRecord($row);
|
if ($ctype === 'vitec_quotation') {
|
||||||
|
$uid = (int)$row['uid'];
|
||||||
|
$logoField = array_key_exists('vitec_quote_logo', $row) ? 'vitec_quote_logo' : 'quote_logo';
|
||||||
|
return [
|
||||||
|
'id' => $uid,
|
||||||
|
'type' => 'vitec_quotation',
|
||||||
|
'colPos' => (int)($row['colPos'] ?? 0),
|
||||||
|
'sorting' => (int)($row['sorting'] ?? 0),
|
||||||
|
'header' => (string)($row['header'] ?? ''),
|
||||||
|
'quote' => (string)($row['vitec_quote'] ?? $row['quote'] ?? ''),
|
||||||
|
'name' => (string)($row['vitec_quote_name'] ?? $row['quote_name'] ?? ''),
|
||||||
|
'position' => (string)($row['vitec_quote_position'] ?? $row['quote_position'] ?? ''),
|
||||||
|
'logo' => $this->image($uid, $logoField, 'tt_content'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$el = ContentElementResolver::normaliseRecord($row);
|
||||||
|
if (is_array($el)) {
|
||||||
|
$uid = (int)$row['uid'];
|
||||||
|
$media = [];
|
||||||
|
foreach (['image', 'assets', 'media'] as $f) {
|
||||||
|
foreach ($this->images($uid, $f, 'tt_content') as $img) {
|
||||||
|
$media[] = $img;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($media !== []) {
|
||||||
|
$el['images'] = $media;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $el;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -445,15 +596,12 @@ final class UsecaseSerializer
|
|||||||
$uid = (int)$it['uid'];
|
$uid = (int)$it['uid'];
|
||||||
$get = static fn (string $k): string => (string)($it['vitec_' . $k] ?? $it[$k] ?? '');
|
$get = static fn (string $k): string => (string)($it['vitec_' . $k] ?? $it[$k] ?? '');
|
||||||
|
|
||||||
$imageField = array_key_exists('vitec_image', $it) ? 'vitec_image' : 'image';
|
|
||||||
$videoField = array_key_exists('vitec_video', $it) ? 'vitec_video' : 'video';
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'type' => $get('item_type') !== '' ? $get('item_type') : 'text',
|
'type' => $get('item_type') !== '' ? $get('item_type') : 'text',
|
||||||
'headline' => $get('headline'),
|
'headline' => $get('headline'),
|
||||||
'text' => $get('text'),
|
'text' => $get('text'),
|
||||||
'image' => $this->image($uid, $imageField, $table),
|
'image' => $this->image($uid, 'vitec_image', $table) ?? $this->image($uid, 'image', $table),
|
||||||
'video' => $this->video($uid, $videoField, $table),
|
'video' => $this->video($uid, 'vitec_video', $table) ?? $this->video($uid, 'video', $table),
|
||||||
'link' => $get('link'),
|
'link' => $get('link'),
|
||||||
'linkLabel' => $get('link_label'),
|
'linkLabel' => $get('link_label'),
|
||||||
];
|
];
|
||||||
|
|||||||
232
packages/vitec/Classes/UserFunc/CustomerlogosJsonRenderer.php
Executable file
232
packages/vitec/Classes/UserFunc/CustomerlogosJsonRenderer.php
Executable file
@@ -0,0 +1,232 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\UserFunc;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
use TYPO3\CMS\Core\Attribute\AsAllowedCallable;
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||||
|
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
use TYPO3\CMS\Extbase\Service\ImageService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserFunc: render the VITEC customer logos as JSON (headless).
|
||||||
|
*
|
||||||
|
* Output under content.customerlogos:
|
||||||
|
* { "layout": "list|grid|carousel|marquee", "logos": [ … ] }
|
||||||
|
*
|
||||||
|
* Selection logic:
|
||||||
|
* - no customers selected -> ALL logos, each with color:false (b/w)
|
||||||
|
* - customers selected -> the selected ones FIRST (selection order,
|
||||||
|
* color:true), followed by all remaining logos (color:false)
|
||||||
|
*
|
||||||
|
* `render()` = top-level plugin / page discovery. `renderForRecord()` = one
|
||||||
|
* specific tt_content row (reused by ContainerChildrenProcessor for nested
|
||||||
|
* plugins). Exception-safe.
|
||||||
|
*/
|
||||||
|
class CustomerlogosJsonRenderer
|
||||||
|
{
|
||||||
|
private const TABLE = 'tx_vitec_domain_model_customer';
|
||||||
|
private const IMAGE_WIDTHS = [200, 400];
|
||||||
|
|
||||||
|
#[AsAllowedCallable]
|
||||||
|
public function render(string $content, array $conf): string
|
||||||
|
{
|
||||||
|
$row = is_array($this->cObj->data ?? null) ? $this->cObj->data : null;
|
||||||
|
if ($row && (string)($row['CType'] ?? '') === 'vitec_customerlogos') {
|
||||||
|
return $this->renderForRecord($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageId = 0;
|
||||||
|
$request = $GLOBALS['TYPO3_REQUEST'] ?? null;
|
||||||
|
if ($request !== null) {
|
||||||
|
$pageInfo = $request->getAttribute('frontend.page.information');
|
||||||
|
if ($pageInfo !== null) {
|
||||||
|
$pageId = (int)$pageInfo->getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($pageId <= 0) {
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
}
|
||||||
|
if ($pageId <= 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
|
||||||
|
$ces = $qb
|
||||||
|
->select('*')
|
||||||
|
->from('tt_content')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('pid', $qb->createNamedParameter($pageId, ParameterType::INTEGER)),
|
||||||
|
$qb->expr()->eq('CType', $qb->createNamedParameter('vitec_customerlogos', ParameterType::STRING)),
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($ces)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->renderForRecord($ces[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string,mixed> $contentElement
|
||||||
|
*/
|
||||||
|
public function renderForRecord(array $contentElement): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
||||||
|
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
||||||
|
$settings = $flexFormData['settings'] ?? [];
|
||||||
|
|
||||||
|
$layout = (string)($settings['layout'] ?? 'grid');
|
||||||
|
$debugMode = (bool)($settings['debug'] ?? false);
|
||||||
|
$selectedUids = GeneralUtility::intExplode(',', (string)($settings['customers'] ?? ''), true);
|
||||||
|
$onlySelected = (bool)($settings['onlySelected'] ?? false);
|
||||||
|
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::TABLE);
|
||||||
|
$rows = $qb
|
||||||
|
->select('*')
|
||||||
|
->from(self::TABLE)
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$byUid = [];
|
||||||
|
foreach ($rows as $r) {
|
||||||
|
$byUid[(int)$r['uid']] = $r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Selected customers first (selection order, in color), then the rest (b/w).
|
||||||
|
$logos = [];
|
||||||
|
foreach ($selectedUids as $uid) {
|
||||||
|
if (isset($byUid[$uid])) {
|
||||||
|
$logos[] = $this->serializeCustomer($byUid[$uid], true);
|
||||||
|
unset($byUid[$uid]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!($onlySelected && $selectedUids !== [])) {
|
||||||
|
foreach ($byUid as $r) {
|
||||||
|
$logos[] = $this->serializeCustomer($r, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = [
|
||||||
|
'layout' => $layout,
|
||||||
|
'logos' => $logos,
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($debugMode) {
|
||||||
|
$response['debug'] = [
|
||||||
|
'count' => count($logos),
|
||||||
|
'selected' => $selectedUids,
|
||||||
|
'settings' => $settings,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string)json_encode($response);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string,mixed> $r
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
private function serializeCustomer(array $r, bool $color): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => (int)$r['uid'],
|
||||||
|
'name' => (string)($r['title'] ?? ''),
|
||||||
|
'emphasized' => (bool)($r['emphasize_logo'] ?? false),
|
||||||
|
'color' => $color,
|
||||||
|
'logo' => $this->logo((int)$r['uid']),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FAL logo with small srcset; SVGs are delivered unprocessed.
|
||||||
|
*
|
||||||
|
* @return array<string,mixed>|null
|
||||||
|
*/
|
||||||
|
private function logo(int $customerUid): ?array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_file_reference');
|
||||||
|
$ref = $qb
|
||||||
|
->select('uid', 'title', 'alternative', 'crop')
|
||||||
|
->from('sys_file_reference')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('tablenames', $qb->createNamedParameter(self::TABLE, ParameterType::STRING)),
|
||||||
|
$qb->expr()->eq('fieldname', $qb->createNamedParameter('logo', ParameterType::STRING)),
|
||||||
|
$qb->expr()->eq('uid_foreign', $qb->createNamedParameter($customerUid, ParameterType::INTEGER)),
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sorting_foreign')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
if (!$ref) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||||
|
$imageService = GeneralUtility::makeInstance(ImageService::class);
|
||||||
|
$fileReference = $resourceFactory->getFileReferenceObject((int)$ref['uid']);
|
||||||
|
|
||||||
|
if (str_contains((string)$fileReference->getMimeType(), 'svg')) {
|
||||||
|
// SVG: no processing/srcset — deliver the file as-is.
|
||||||
|
return [
|
||||||
|
'uid' => (int)$ref['uid'],
|
||||||
|
'url' => (string)$fileReference->getPublicUrl(),
|
||||||
|
'title' => (string)($ref['title'] ?? ''),
|
||||||
|
'alternative' => (string)($ref['alternative'] ?? ''),
|
||||||
|
'srcset' => [],
|
||||||
|
'properties' => ['mimeType' => $fileReference->getMimeType()],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$srcset = [];
|
||||||
|
foreach (self::IMAGE_WIDTHS as $width) {
|
||||||
|
$variant = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => $width, 'crop' => $ref['crop'] ?? null]
|
||||||
|
);
|
||||||
|
$srcset[] = ['url' => $imageService->getImageUri($variant), 'width' => $width, 'descriptor' => $width . 'w'];
|
||||||
|
}
|
||||||
|
$default = $imageService->applyProcessingInstructions(
|
||||||
|
$fileReference,
|
||||||
|
['width' => 400, 'crop' => $ref['crop'] ?? null]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'uid' => (int)$ref['uid'],
|
||||||
|
'url' => $imageService->getImageUri($default),
|
||||||
|
'title' => (string)($ref['title'] ?? ''),
|
||||||
|
'alternative' => (string)($ref['alternative'] ?? ''),
|
||||||
|
'srcset' => $srcset,
|
||||||
|
'properties' => [
|
||||||
|
'width' => $fileReference->getProperty('width'),
|
||||||
|
'height' => $fileReference->getProperty('height'),
|
||||||
|
'mimeType' => $fileReference->getProperty('mime_type'),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -86,12 +86,14 @@ class EventlistJsonRenderer
|
|||||||
$daysInAdvance = (int)($settings['daysinadvance'] ?? 0);
|
$daysInAdvance = (int)($settings['daysinadvance'] ?? 0);
|
||||||
$limit = (int)($settings['limit'] ?? 0);
|
$limit = (int)($settings['limit'] ?? 0);
|
||||||
$debugMode = (bool)($settings['debug'] ?? false);
|
$debugMode = (bool)($settings['debug'] ?? false);
|
||||||
|
$layout = (string)($settings['layout'] ?? 'list');
|
||||||
|
|
||||||
$upcoming = $this->fetchEvents(true, $limit, $daysInAdvance);
|
$upcoming = $this->fetchEvents(true, $limit, $daysInAdvance);
|
||||||
|
|
||||||
$response = [
|
$response = [
|
||||||
'events' => array_map(fn($e) => $this->serializeEvent($e), $upcoming),
|
'events' => array_map(fn($e) => $this->serializeEvent($e), $upcoming),
|
||||||
'settings' => [
|
'settings' => [
|
||||||
|
'layout' => $layout,
|
||||||
'showpast' => $showPast,
|
'showpast' => $showPast,
|
||||||
'daysinadvance' => $daysInAdvance,
|
'daysinadvance' => $daysInAdvance,
|
||||||
'limit' => $limit,
|
'limit' => $limit,
|
||||||
|
|||||||
197
packages/vitec/Classes/UserFunc/LocationsJsonRenderer.php
Executable file
197
packages/vitec/Classes/UserFunc/LocationsJsonRenderer.php
Executable file
@@ -0,0 +1,197 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\UserFunc;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
use TYPO3\CMS\Core\Attribute\AsAllowedCallable;
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserFunc: render the VITEC locations as JSON (headless).
|
||||||
|
*
|
||||||
|
* Output under content.locations:
|
||||||
|
* { "variant": "grid|list|map", "mapText": "<p>…</p>"|null, "locations": [ … ] }
|
||||||
|
*
|
||||||
|
* Each location follows the frontend contract (id, slug, name, countryCode,
|
||||||
|
* coordinates, address, contact, links, marker, sorting, active).
|
||||||
|
*
|
||||||
|
* `render()` = top-level plugin / page discovery. `renderForRecord()` = one
|
||||||
|
* specific tt_content row (reused by ContainerChildrenProcessor for nested
|
||||||
|
* plugins). Exception-safe.
|
||||||
|
*/
|
||||||
|
class LocationsJsonRenderer
|
||||||
|
{
|
||||||
|
private const TABLE = 'tx_vitec_domain_model_location';
|
||||||
|
|
||||||
|
#[AsAllowedCallable]
|
||||||
|
public function render(string $content, array $conf): string
|
||||||
|
{
|
||||||
|
$row = is_array($this->cObj->data ?? null) ? $this->cObj->data : null;
|
||||||
|
if ($row && (string)($row['CType'] ?? '') === 'vitec_locationlist') {
|
||||||
|
return $this->renderForRecord($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageId = 0;
|
||||||
|
$request = $GLOBALS['TYPO3_REQUEST'] ?? null;
|
||||||
|
if ($request !== null) {
|
||||||
|
$pageInfo = $request->getAttribute('frontend.page.information');
|
||||||
|
if ($pageInfo !== null) {
|
||||||
|
$pageId = (int)$pageInfo->getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($pageId <= 0) {
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
}
|
||||||
|
if ($pageId <= 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
|
||||||
|
$ces = $qb
|
||||||
|
->select('*')
|
||||||
|
->from('tt_content')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('pid', $qb->createNamedParameter($pageId, ParameterType::INTEGER)),
|
||||||
|
$qb->expr()->eq('CType', $qb->createNamedParameter('vitec_locationlist', ParameterType::STRING)),
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($ces)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->renderForRecord($ces[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string,mixed> $contentElement
|
||||||
|
*/
|
||||||
|
public function renderForRecord(array $contentElement): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
||||||
|
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
||||||
|
$settings = $flexFormData['settings'] ?? [];
|
||||||
|
|
||||||
|
$variant = (string)($settings['variant'] ?? 'grid');
|
||||||
|
$mapText = trim((string)($settings['maptext'] ?? ''));
|
||||||
|
$debugMode = (bool)($settings['debug'] ?? false);
|
||||||
|
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::TABLE);
|
||||||
|
$rows = $qb
|
||||||
|
->select('*')
|
||||||
|
->from(self::TABLE)
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->orderBy('sorting', 'ASC')
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
$locations = array_map(fn(array $r): array => $this->serializeLocation($r), $rows);
|
||||||
|
|
||||||
|
$response = [
|
||||||
|
'variant' => $variant,
|
||||||
|
'mapText' => $variant === 'map' && $mapText !== '' ? $mapText : null,
|
||||||
|
'locations' => $locations,
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($debugMode) {
|
||||||
|
$response['debug'] = ['count' => count($locations), 'settings' => $settings];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string)json_encode($response);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string,mixed> $r
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
private function serializeLocation(array $r): array
|
||||||
|
{
|
||||||
|
$name = (string)($r['title'] ?? '');
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => (int)$r['uid'],
|
||||||
|
'slug' => (string)($r['slug'] ?? ''),
|
||||||
|
'name' => $name,
|
||||||
|
'countryCode' => (string)($r['country_code'] ?? ''),
|
||||||
|
'coordinates' => [
|
||||||
|
'latitude' => (float)($r['latitude'] ?? 0),
|
||||||
|
'longitude' => (float)($r['longitude'] ?? 0),
|
||||||
|
],
|
||||||
|
'address' => [
|
||||||
|
'company' => $this->nullIfEmpty($r['address_company'] ?? ''),
|
||||||
|
'street' => $this->nullIfEmpty($r['street'] ?? ''),
|
||||||
|
'additional' => $this->nullIfEmpty($r['address_additional'] ?? ''),
|
||||||
|
'postalCode' => $this->nullIfEmpty($r['postal_code'] ?? ''),
|
||||||
|
'city' => $this->nullIfEmpty($r['city'] ?? ''),
|
||||||
|
'region' => $this->nullIfEmpty($r['region'] ?? ''),
|
||||||
|
'country' => $this->nullIfEmpty($r['country'] ?? ''),
|
||||||
|
],
|
||||||
|
'contact' => [
|
||||||
|
'phone' => $this->nullIfEmpty($r['phone'] ?? ''),
|
||||||
|
'fax' => $this->nullIfEmpty($r['fax'] ?? ''),
|
||||||
|
'email' => $this->nullIfEmpty($r['email'] ?? ''),
|
||||||
|
],
|
||||||
|
'links' => [
|
||||||
|
'contact' => $this->resolveLink((string)($r['contact_link'] ?? '')),
|
||||||
|
'legal' => $this->resolveLinkLines((string)($r['legal_links'] ?? '')),
|
||||||
|
],
|
||||||
|
'marker' => [
|
||||||
|
'label' => (string)($r['marker_label'] ?? '') !== '' ? (string)$r['marker_label'] : $name,
|
||||||
|
'color' => (string)($r['marker_color'] ?? '#ff6633'),
|
||||||
|
'size' => (float)($r['marker_size'] ?? 0.5),
|
||||||
|
],
|
||||||
|
'sorting' => (int)($r['sorting'] ?? 0),
|
||||||
|
'active' => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function nullIfEmpty(mixed $value): ?string
|
||||||
|
{
|
||||||
|
$value = trim((string)$value);
|
||||||
|
return $value === '' ? null : $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Resolve a typolink parameter (t3://…, page uid, URL) to a URL/path. */
|
||||||
|
private function resolveLink(string $parameter): ?string
|
||||||
|
{
|
||||||
|
$parameter = trim($parameter);
|
||||||
|
if ($parameter === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
|
||||||
|
$url = $cObj->typoLink_URL(['parameter' => $parameter]);
|
||||||
|
return $url !== '' ? $url : $parameter;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return $parameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return array<int,string> */
|
||||||
|
private function resolveLinkLines(string $lines): array
|
||||||
|
{
|
||||||
|
$out = [];
|
||||||
|
foreach (preg_split('/\r\n|\r|\n/', $lines) ?: [] as $line) {
|
||||||
|
$resolved = $this->resolveLink($line);
|
||||||
|
if ($resolved !== null) {
|
||||||
|
$out[] = $resolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
}
|
||||||
175
packages/vitec/Classes/UserFunc/ModelcardJsonRenderer.php
Executable file
175
packages/vitec/Classes/UserFunc/ModelcardJsonRenderer.php
Executable file
@@ -0,0 +1,175 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Evomedien\Vitec\UserFunc;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
use Evomedien\Vitec\Service\UsecaseSerializer;
|
||||||
|
use TYPO3\CMS\Core\Attribute\AsAllowedCallable;
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use TYPO3\CMS\Core\Service\FlexFormService;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserFunc: render the VITEC Card plugin as JSON (headless).
|
||||||
|
*
|
||||||
|
* ONE plugin for four card types — the FlexForm picks the model type
|
||||||
|
* (product | story | market | solution) plus one record; ALL card data
|
||||||
|
* comes from the model. Output under content.card:
|
||||||
|
*
|
||||||
|
* { "modelType": "product", "layout": "vertical", "item": { … } }
|
||||||
|
*
|
||||||
|
* Image resolution is delegated to UsecaseSerializer::image() (generic,
|
||||||
|
* srcset + SVG-safe). `render()` = top-level plugin / page discovery,
|
||||||
|
* `renderForRecord()` = one tt_content row (container-nestable).
|
||||||
|
* Exception-safe.
|
||||||
|
*/
|
||||||
|
class ModelcardJsonRenderer
|
||||||
|
{
|
||||||
|
private const MODEL_TABLES = [
|
||||||
|
'product' => 'tx_vitec_domain_model_product',
|
||||||
|
'story' => 'tx_vitec_domain_model_usecase',
|
||||||
|
'market' => 'tx_vitec_domain_model_market',
|
||||||
|
'solution' => 'tx_vitec_domain_model_solution',
|
||||||
|
];
|
||||||
|
|
||||||
|
#[AsAllowedCallable]
|
||||||
|
public function render(string $content, array $conf): string
|
||||||
|
{
|
||||||
|
$row = is_array($this->cObj->data ?? null) ? $this->cObj->data : null;
|
||||||
|
if ($row && (string)($row['CType'] ?? '') === 'vitec_modelcard') {
|
||||||
|
return $this->renderForRecord($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageId = 0;
|
||||||
|
$request = $GLOBALS['TYPO3_REQUEST'] ?? null;
|
||||||
|
if ($request !== null) {
|
||||||
|
$pageInfo = $request->getAttribute('frontend.page.information');
|
||||||
|
if ($pageInfo !== null) {
|
||||||
|
$pageId = (int)$pageInfo->getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($pageId <= 0) {
|
||||||
|
$pageId = (int)($GLOBALS['TSFE']->id ?? 0);
|
||||||
|
}
|
||||||
|
if ($pageId <= 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
|
||||||
|
$ces = $qb
|
||||||
|
->select('*')
|
||||||
|
->from('tt_content')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('pid', $qb->createNamedParameter($pageId, ParameterType::INTEGER)),
|
||||||
|
$qb->expr()->eq('CType', $qb->createNamedParameter('vitec_modelcard', ParameterType::STRING)),
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
|
||||||
|
if (empty($ces)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->renderForRecord($ces[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string,mixed> $contentElement
|
||||||
|
*/
|
||||||
|
public function renderForRecord(array $contentElement): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
||||||
|
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
||||||
|
$settings = $flexFormData['settings'] ?? [];
|
||||||
|
|
||||||
|
$modelType = (string)($settings['modelType'] ?? 'product');
|
||||||
|
$layout = (string)($settings['layout'] ?? 'vertical');
|
||||||
|
$debugMode = (bool)($settings['debug'] ?? false);
|
||||||
|
$recordUid = (int)($settings[$modelType === 'story' ? 'story' : $modelType] ?? 0);
|
||||||
|
|
||||||
|
$item = null;
|
||||||
|
if ($recordUid > 0 && isset(self::MODEL_TABLES[$modelType])) {
|
||||||
|
$row = $this->fetchRecord(self::MODEL_TABLES[$modelType], $recordUid);
|
||||||
|
if ($row !== null) {
|
||||||
|
$item = $this->serializeItem($modelType, $row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = [
|
||||||
|
'modelType' => $modelType,
|
||||||
|
'layout' => $layout,
|
||||||
|
'item' => $item,
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($debugMode) {
|
||||||
|
$response['debug'] = ['recordUid' => $recordUid, 'settings' => $settings];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string)json_encode($response);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string,mixed>|null
|
||||||
|
*/
|
||||||
|
private function fetchRecord(string $table, int $uid): ?array
|
||||||
|
{
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
|
||||||
|
$row = $qb
|
||||||
|
->select('*')
|
||||||
|
->from($table)
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('uid', $qb->createNamedParameter($uid, ParameterType::INTEGER)),
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAssociative();
|
||||||
|
|
||||||
|
return $row ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string,mixed> $row
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
private function serializeItem(string $modelType, array $row): array
|
||||||
|
{
|
||||||
|
$serializer = GeneralUtility::makeInstance(UsecaseSerializer::class);
|
||||||
|
$uid = (int)$row['uid'];
|
||||||
|
|
||||||
|
if ($modelType === 'story') {
|
||||||
|
// Success stories already have the canonical card serialisation.
|
||||||
|
return $serializer->serializeListItem($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($modelType === 'product') {
|
||||||
|
return [
|
||||||
|
'uid' => $uid,
|
||||||
|
'title' => (string)($row['title'] ?? ''),
|
||||||
|
'slug' => (string)($row['slug'] ?? ''),
|
||||||
|
'subtitle' => (string)($row['subtitle'] ?? ''),
|
||||||
|
'teaser' => (string)($row['teaser'] ?? ''),
|
||||||
|
'image' => $serializer->image($uid, 'image', 'tx_vitec_domain_model_product')
|
||||||
|
?? $serializer->image($uid, 'productimage', 'tx_vitec_domain_model_product'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// market | solution — identical field set.
|
||||||
|
return [
|
||||||
|
'uid' => $uid,
|
||||||
|
'title' => (string)($row['title'] ?? ''),
|
||||||
|
'subtitle' => (string)($row['subtitle'] ?? ''),
|
||||||
|
'teaser' => (string)($row['teaser'] ?? ''),
|
||||||
|
'description' => (string)($row['description'] ?? ''),
|
||||||
|
'image' => $serializer->image($uid, 'image', self::MODEL_TABLES[$modelType]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ use Evomedien\Vitec\Domain\Repository\ProductRepository;
|
|||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use TYPO3\CMS\Core\Core\Environment;
|
use TYPO3\CMS\Core\Core\Environment;
|
||||||
use TYPO3\CMS\Core\Database\Connection;
|
use TYPO3\CMS\Core\Database\Connection;
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
||||||
use TYPO3\CMS\Core\Resource\FileReference;
|
use TYPO3\CMS\Core\Resource\FileReference;
|
||||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||||
@@ -406,15 +407,61 @@ class ProductListJsonRenderer
|
|||||||
->executeQuery()
|
->executeQuery()
|
||||||
->fetchAllAssociative();
|
->fetchAllAssociative();
|
||||||
|
|
||||||
return array_map(static function ($cat) {
|
return array_map(function ($cat) {
|
||||||
return [
|
return [
|
||||||
'uid' => (int)$cat['uid'],
|
'uid' => (int)$cat['uid'],
|
||||||
'title' => $cat['title'] ?? '',
|
'title' => $cat['title'] ?? '',
|
||||||
'description' => $cat['description'] ?? '',
|
'description' => $cat['description'] ?? '',
|
||||||
|
'parents' => $this->getCategoryParents((int)$cat['uid']),
|
||||||
];
|
];
|
||||||
}, $categories);
|
}, $categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var array<int,array{parent:int,title:string}>|null Lazy uid => [parent,title] map of all categories. */
|
||||||
|
private ?array $categoryTreeMap = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All ancestor categories of one category, ROOT FIRST (excluding itself).
|
||||||
|
* Backed by a once-per-request map of sys_category — cheap for any number
|
||||||
|
* of products. Cycle-safe.
|
||||||
|
*
|
||||||
|
* @return array<int,array{uid:int,title:string}>
|
||||||
|
*/
|
||||||
|
private function getCategoryParents(int $categoryUid): array
|
||||||
|
{
|
||||||
|
if ($this->categoryTreeMap === null) {
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_category');
|
||||||
|
$rows = $qb
|
||||||
|
->select('uid', 'parent', 'title')
|
||||||
|
->from('sys_category')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
$this->categoryTreeMap = [];
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$this->categoryTreeMap[(int)$row['uid']] = [
|
||||||
|
'parent' => (int)$row['parent'],
|
||||||
|
'title' => (string)$row['title'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$parents = [];
|
||||||
|
$seen = [$categoryUid => true];
|
||||||
|
$current = $this->categoryTreeMap[$categoryUid]['parent'] ?? 0;
|
||||||
|
while ($current > 0 && isset($this->categoryTreeMap[$current]) && !isset($seen[$current])) {
|
||||||
|
$seen[$current] = true;
|
||||||
|
array_unshift($parents, ['uid' => $current, 'title' => $this->categoryTreeMap[$current]['title']]);
|
||||||
|
$current = $this->categoryTreeMap[$current]['parent'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parents;
|
||||||
|
}
|
||||||
|
|
||||||
private function getDownloadFileType(int $downloadUid): string
|
private function getDownloadFileType(int $downloadUid): string
|
||||||
{
|
{
|
||||||
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
|||||||
@@ -493,10 +493,56 @@ class ProductShowJsonRenderer
|
|||||||
'uid' => (int)$cat['uid'],
|
'uid' => (int)$cat['uid'],
|
||||||
'title' => $cat['title'],
|
'title' => $cat['title'],
|
||||||
'description' => $cat['description'] ?? '',
|
'description' => $cat['description'] ?? '',
|
||||||
|
'parents' => $this->getCategoryParents((int)$cat['uid']),
|
||||||
];
|
];
|
||||||
}, $categories);
|
}, $categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var array<int,array{parent:int,title:string}>|null Lazy uid => [parent,title] map of all categories. */
|
||||||
|
private ?array $categoryTreeMap = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All ancestor categories of one category, ROOT FIRST (excluding itself).
|
||||||
|
* Backed by a once-per-request map of sys_category — cheap for any number
|
||||||
|
* of products. Cycle-safe.
|
||||||
|
*
|
||||||
|
* @return array<int,array{uid:int,title:string}>
|
||||||
|
*/
|
||||||
|
private function getCategoryParents(int $categoryUid): array
|
||||||
|
{
|
||||||
|
if ($this->categoryTreeMap === null) {
|
||||||
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_category');
|
||||||
|
$rows = $qb
|
||||||
|
->select('uid', 'parent', 'title')
|
||||||
|
->from('sys_category')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->eq('deleted', 0),
|
||||||
|
$qb->expr()->eq('hidden', 0)
|
||||||
|
)
|
||||||
|
->executeQuery()
|
||||||
|
->fetchAllAssociative();
|
||||||
|
$this->categoryTreeMap = [];
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$this->categoryTreeMap[(int)$row['uid']] = [
|
||||||
|
'parent' => (int)$row['parent'],
|
||||||
|
'title' => (string)$row['title'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$parents = [];
|
||||||
|
$seen = [$categoryUid => true];
|
||||||
|
$current = $this->categoryTreeMap[$categoryUid]['parent'] ?? 0;
|
||||||
|
while ($current > 0 && isset($this->categoryTreeMap[$current]) && !isset($seen[$current])) {
|
||||||
|
$seen[$current] = true;
|
||||||
|
array_unshift($parents, ['uid' => $current, 'title' => $this->categoryTreeMap[$current]['title']]);
|
||||||
|
$current = $this->categoryTreeMap[$current]['parent'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parents;
|
||||||
|
}
|
||||||
|
|
||||||
private function getDownloadFileType(int $downloadUid): string
|
private function getDownloadFileType(int $downloadUid): string
|
||||||
{
|
{
|
||||||
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||||
|
|||||||
@@ -72,6 +72,22 @@ class UsecaseListJsonRenderer
|
|||||||
public function renderForRecord(array $contentElement): string
|
public function renderForRecord(array $contentElement): string
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
// Detail context: when the request carries a story argument the
|
||||||
|
// list stays silent — the usecaseshow plugin on the same page
|
||||||
|
// renders the story. Keeps old SEO URLs on one page.
|
||||||
|
$request = $GLOBALS['TYPO3_REQUEST'] ?? null;
|
||||||
|
$routing = $request?->getAttribute('routing');
|
||||||
|
$detailParam = null;
|
||||||
|
if ($routing instanceof \TYPO3\CMS\Core\Routing\PageArguments) {
|
||||||
|
$detailParam = $routing->getRouteArguments()['tx_vitec_usecaseshow']['usecase'] ?? null;
|
||||||
|
}
|
||||||
|
if ($detailParam === null || $detailParam === '') {
|
||||||
|
$detailParam = ($request?->getQueryParams() ?? [])['tx_vitec_usecaseshow']['usecase'] ?? null;
|
||||||
|
}
|
||||||
|
if ($detailParam !== null && $detailParam !== '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
|
||||||
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
||||||
$settings = $flexFormData['settings'] ?? [];
|
$settings = $flexFormData['settings'] ?? [];
|
||||||
@@ -92,8 +108,28 @@ class UsecaseListJsonRenderer
|
|||||||
->fetchAllAssociative();
|
->fetchAllAssociative();
|
||||||
|
|
||||||
$serializer = GeneralUtility::makeInstance(UsecaseSerializer::class);
|
$serializer = GeneralUtility::makeInstance(UsecaseSerializer::class);
|
||||||
|
|
||||||
|
// Detail links: the PUBLIC URL is the PARENT path of the
|
||||||
|
// FlexForm-selected "Single PID" page plus the story slug —
|
||||||
|
// /success-stories/<slug>, not /success-stories/story/<slug>.
|
||||||
|
// The SuccessStoryPathRewrite middleware maps it back to the
|
||||||
|
// detail subpage at request time.
|
||||||
|
$singlePid = (int)($settings['singlePid'] ?? 0);
|
||||||
|
$detailBase = '';
|
||||||
|
if ($singlePid > 0) {
|
||||||
|
$detailPath = rtrim($this->resolvePageUrl($singlePid), '/');
|
||||||
|
$parent = str_contains($detailPath, '/') ? substr($detailPath, 0, (int)strrpos($detailPath, '/')) : '';
|
||||||
|
$detailBase = $parent !== '' ? $parent : $detailPath;
|
||||||
|
}
|
||||||
|
|
||||||
$usecases = array_map(
|
$usecases = array_map(
|
||||||
static fn (array $u): array => $serializer->serializeListItem($u),
|
static function (array $u) use ($serializer, $detailBase): array {
|
||||||
|
$item = $serializer->serializeListItem($u);
|
||||||
|
$item['detailUrl'] = ($detailBase !== '' && ($item['slug'] ?? '') !== '')
|
||||||
|
? $detailBase . '/' . ltrim((string)$item['slug'], '/')
|
||||||
|
: null;
|
||||||
|
return $item;
|
||||||
|
},
|
||||||
$rows
|
$rows
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -109,4 +145,15 @@ class UsecaseListJsonRenderer
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Resolve a page uid to its frontend path (route enhancer aware). */
|
||||||
|
private function resolvePageUrl(int $pageUid): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$cObj = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class);
|
||||||
|
return (string)$cObj->typoLink_URL(['parameter' => (string)$pageUid]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,16 +77,21 @@ class UsecaseShowJsonRenderer
|
|||||||
|
|
||||||
$layout = (string)($settings['layout'] ?? 'default');
|
$layout = (string)($settings['layout'] ?? 'default');
|
||||||
$debugMode = (bool)($settings['debug'] ?? false);
|
$debugMode = (bool)($settings['debug'] ?? false);
|
||||||
$usecaseUid = (int)($settings['usecase'] ?? 0);
|
// The story is resolved from the request ONLY (detail route from the
|
||||||
|
// list plugin's detailUrl): route-enhancer arguments live in the
|
||||||
// Fallback: uid/slug from the request (React detail route).
|
// `routing` PageArguments, plain GET in query params.
|
||||||
if (!$usecaseUid) {
|
$request = $GLOBALS['TYPO3_REQUEST'] ?? null;
|
||||||
$params = $GLOBALS['TYPO3_REQUEST']?->getQueryParams() ?? [];
|
$param = null;
|
||||||
$param = $params['tx_vitec_usecaseshow']['usecase'] ?? null;
|
$routing = $request?->getAttribute('routing');
|
||||||
if ($param !== null && $param !== '') {
|
if ($routing instanceof \TYPO3\CMS\Core\Routing\PageArguments) {
|
||||||
$usecaseUid = is_numeric($param) ? (int)$param : $this->resolveSlug((string)$param);
|
$param = $routing->getRouteArguments()['tx_vitec_usecaseshow']['usecase'] ?? null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if ($param === null || $param === '') {
|
||||||
|
$param = ($request?->getQueryParams() ?? [])['tx_vitec_usecaseshow']['usecase'] ?? null;
|
||||||
|
}
|
||||||
|
$usecaseUid = ($param !== null && $param !== '')
|
||||||
|
? (is_numeric($param) ? (int)$param : $this->resolveSlug((string)$param))
|
||||||
|
: 0;
|
||||||
|
|
||||||
if (!$usecaseUid) {
|
if (!$usecaseUid) {
|
||||||
return $debugMode
|
return $debugMode
|
||||||
@@ -114,9 +119,11 @@ class UsecaseShowJsonRenderer
|
|||||||
|
|
||||||
$serializer = GeneralUtility::makeInstance(UsecaseSerializer::class);
|
$serializer = GeneralUtility::makeInstance(UsecaseSerializer::class);
|
||||||
|
|
||||||
|
$backPid = (int)($settings['backPid'] ?? 0);
|
||||||
$response = [
|
$response = [
|
||||||
'usecase' => $serializer->serializeDetail($usecase),
|
'usecase' => $serializer->serializeDetail($usecase),
|
||||||
'layout' => $layout,
|
'layout' => $layout,
|
||||||
|
'backUrl' => $backPid > 0 ? ($this->resolvePageUrl($backPid) ?: null) : null,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($debugMode) {
|
if ($debugMode) {
|
||||||
@@ -145,4 +152,15 @@ class UsecaseShowJsonRenderer
|
|||||||
|
|
||||||
return (int)($row['uid'] ?? 0);
|
return (int)($row['uid'] ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Resolve a page uid to its frontend path (route enhancer aware). */
|
||||||
|
private function resolvePageUrl(int $pageUid): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$cObj = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class);
|
||||||
|
return (string)$cObj->typoLink_URL(['parameter' => (string)$pageUid]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
73
packages/vitec/Configuration/FlexForms/Customerlogos.xml
Executable file
73
packages/vitec/Configuration/FlexForms/Customerlogos.xml
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<T3DataStructure>
|
||||||
|
<meta>
|
||||||
|
<langDisable>1</langDisable>
|
||||||
|
</meta>
|
||||||
|
<sheets>
|
||||||
|
<sDEF>
|
||||||
|
<ROOT>
|
||||||
|
<sheetTitle>Customer Logos Settings</sheetTitle>
|
||||||
|
<type>array</type>
|
||||||
|
<el>
|
||||||
|
<settings.layout>
|
||||||
|
<label>Layout</label>
|
||||||
|
<config>
|
||||||
|
<type>select</type>
|
||||||
|
<renderType>selectSingle</renderType>
|
||||||
|
<items>
|
||||||
|
<numIndex index="0">
|
||||||
|
<label>List</label>
|
||||||
|
<value>list</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="1">
|
||||||
|
<label>Grid</label>
|
||||||
|
<value>grid</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="2">
|
||||||
|
<label>Carousel</label>
|
||||||
|
<value>carousel</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="3">
|
||||||
|
<label>Marquee (scrolling ticker)</label>
|
||||||
|
<value>marquee</value>
|
||||||
|
</numIndex>
|
||||||
|
</items>
|
||||||
|
<default>grid</default>
|
||||||
|
</config>
|
||||||
|
</settings.layout>
|
||||||
|
|
||||||
|
<settings.customers>
|
||||||
|
<label>Highlighted Customers</label>
|
||||||
|
<description>Empty = all logos black & white. Selected customers are shown in color, in front of the remaining (b/w) logos.</description>
|
||||||
|
<config>
|
||||||
|
<type>select</type>
|
||||||
|
<renderType>selectMultipleSideBySide</renderType>
|
||||||
|
<foreign_table>tx_vitec_domain_model_customer</foreign_table>
|
||||||
|
<foreign_table_where>AND tx_vitec_domain_model_customer.hidden = 0 AND tx_vitec_domain_model_customer.deleted = 0 ORDER BY tx_vitec_domain_model_customer.title</foreign_table_where>
|
||||||
|
<size>8</size>
|
||||||
|
<minitems>0</minitems>
|
||||||
|
<maxitems>999</maxitems>
|
||||||
|
</config>
|
||||||
|
</settings.customers>
|
||||||
|
|
||||||
|
<settings.onlySelected>
|
||||||
|
<label>Only show selected</label>
|
||||||
|
<description>Show only the highlighted customers — the remaining (b/w) logos are omitted entirely.</description>
|
||||||
|
<config>
|
||||||
|
<type>check</type>
|
||||||
|
<default>0</default>
|
||||||
|
</config>
|
||||||
|
</settings.onlySelected>
|
||||||
|
|
||||||
|
<settings.debug>
|
||||||
|
<label>Allow Debug Output</label>
|
||||||
|
<config>
|
||||||
|
<type>check</type>
|
||||||
|
<default>0</default>
|
||||||
|
</config>
|
||||||
|
</settings.debug>
|
||||||
|
</el>
|
||||||
|
</ROOT>
|
||||||
|
</sDEF>
|
||||||
|
</sheets>
|
||||||
|
</T3DataStructure>
|
||||||
@@ -9,6 +9,29 @@
|
|||||||
<sheetTitle>Event List Settings</sheetTitle>
|
<sheetTitle>Event List Settings</sheetTitle>
|
||||||
<type>array</type>
|
<type>array</type>
|
||||||
<el>
|
<el>
|
||||||
|
<settings.layout>
|
||||||
|
<label>Layout</label>
|
||||||
|
<config>
|
||||||
|
<type>select</type>
|
||||||
|
<renderType>selectSingle</renderType>
|
||||||
|
<items>
|
||||||
|
<numIndex index="0">
|
||||||
|
<label>List View</label>
|
||||||
|
<value>list</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="1">
|
||||||
|
<label>Grid View</label>
|
||||||
|
<value>grid</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="2">
|
||||||
|
<label>Teaser Bar</label>
|
||||||
|
<value>teaserbar</value>
|
||||||
|
</numIndex>
|
||||||
|
</items>
|
||||||
|
<default>list</default>
|
||||||
|
</config>
|
||||||
|
</settings.layout>
|
||||||
|
|
||||||
<settings.daysinadvance>
|
<settings.daysinadvance>
|
||||||
<label>Days in advance (0 = no limit)</label>
|
<label>Days in advance (0 = no limit)</label>
|
||||||
<description>Only show upcoming events starting within the next N days, e.g. 60.</description>
|
<description>Only show upcoming events starting within the next N days, e.g. 60.</description>
|
||||||
|
|||||||
57
packages/vitec/Configuration/FlexForms/Locationlist.xml
Executable file
57
packages/vitec/Configuration/FlexForms/Locationlist.xml
Executable file
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<T3DataStructure>
|
||||||
|
<meta>
|
||||||
|
<langDisable>1</langDisable>
|
||||||
|
</meta>
|
||||||
|
<sheets>
|
||||||
|
<sDEF>
|
||||||
|
<ROOT>
|
||||||
|
<sheetTitle>Locations Settings</sheetTitle>
|
||||||
|
<type>array</type>
|
||||||
|
<el>
|
||||||
|
<settings.variant>
|
||||||
|
<label>Display Variant</label>
|
||||||
|
<config>
|
||||||
|
<type>select</type>
|
||||||
|
<renderType>selectSingle</renderType>
|
||||||
|
<items>
|
||||||
|
<numIndex index="0">
|
||||||
|
<label>Grid</label>
|
||||||
|
<value>grid</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="1">
|
||||||
|
<label>List</label>
|
||||||
|
<value>list</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="2">
|
||||||
|
<label>Map</label>
|
||||||
|
<value>map</value>
|
||||||
|
</numIndex>
|
||||||
|
</items>
|
||||||
|
<default>grid</default>
|
||||||
|
</config>
|
||||||
|
</settings.variant>
|
||||||
|
|
||||||
|
<settings.maptext>
|
||||||
|
<label>Map Text</label>
|
||||||
|
<description>Rich text shown alongside the map (Map variant only).</description>
|
||||||
|
<displayCond>FIELD:settings.variant:=:map</displayCond>
|
||||||
|
<config>
|
||||||
|
<type>text</type>
|
||||||
|
<rows>8</rows>
|
||||||
|
<enableRichtext>1</enableRichtext>
|
||||||
|
</config>
|
||||||
|
</settings.maptext>
|
||||||
|
|
||||||
|
<settings.debug>
|
||||||
|
<label>Allow Debug Output</label>
|
||||||
|
<config>
|
||||||
|
<type>check</type>
|
||||||
|
<default>0</default>
|
||||||
|
</config>
|
||||||
|
</settings.debug>
|
||||||
|
</el>
|
||||||
|
</ROOT>
|
||||||
|
</sDEF>
|
||||||
|
</sheets>
|
||||||
|
</T3DataStructure>
|
||||||
146
packages/vitec/Configuration/FlexForms/Modelcard.xml
Executable file
146
packages/vitec/Configuration/FlexForms/Modelcard.xml
Executable file
@@ -0,0 +1,146 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<T3DataStructure>
|
||||||
|
<meta>
|
||||||
|
<langDisable>1</langDisable>
|
||||||
|
</meta>
|
||||||
|
<sheets>
|
||||||
|
<sDEF>
|
||||||
|
<ROOT>
|
||||||
|
<sheetTitle>Card Settings</sheetTitle>
|
||||||
|
<type>array</type>
|
||||||
|
<el>
|
||||||
|
<settings.modelType>
|
||||||
|
<label>Card Type</label>
|
||||||
|
<onChange>reload</onChange>
|
||||||
|
<config>
|
||||||
|
<type>select</type>
|
||||||
|
<renderType>selectSingle</renderType>
|
||||||
|
<items>
|
||||||
|
<numIndex index="0">
|
||||||
|
<label>Product</label>
|
||||||
|
<value>product</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="1">
|
||||||
|
<label>Success Story</label>
|
||||||
|
<value>story</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="2">
|
||||||
|
<label>Market</label>
|
||||||
|
<value>market</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="3">
|
||||||
|
<label>Solution</label>
|
||||||
|
<value>solution</value>
|
||||||
|
</numIndex>
|
||||||
|
</items>
|
||||||
|
<default>product</default>
|
||||||
|
</config>
|
||||||
|
</settings.modelType>
|
||||||
|
|
||||||
|
<settings.product>
|
||||||
|
<label>Product</label>
|
||||||
|
<displayCond>FIELD:settings.modelType:=:product</displayCond>
|
||||||
|
<config>
|
||||||
|
<type>select</type>
|
||||||
|
<renderType>selectSingle</renderType>
|
||||||
|
<items>
|
||||||
|
<numIndex index="0">
|
||||||
|
<label>— please choose —</label>
|
||||||
|
<value>0</value>
|
||||||
|
</numIndex>
|
||||||
|
</items>
|
||||||
|
<foreign_table>tx_vitec_domain_model_product</foreign_table>
|
||||||
|
<foreign_table_where>AND tx_vitec_domain_model_product.hidden = 0 AND tx_vitec_domain_model_product.deleted = 0 ORDER BY tx_vitec_domain_model_product.title</foreign_table_where>
|
||||||
|
</config>
|
||||||
|
</settings.product>
|
||||||
|
|
||||||
|
<settings.story>
|
||||||
|
<label>Success Story</label>
|
||||||
|
<displayCond>FIELD:settings.modelType:=:story</displayCond>
|
||||||
|
<config>
|
||||||
|
<type>select</type>
|
||||||
|
<renderType>selectSingle</renderType>
|
||||||
|
<items>
|
||||||
|
<numIndex index="0">
|
||||||
|
<label>— please choose —</label>
|
||||||
|
<value>0</value>
|
||||||
|
</numIndex>
|
||||||
|
</items>
|
||||||
|
<foreign_table>tx_vitec_domain_model_usecase</foreign_table>
|
||||||
|
<foreign_table_where>AND tx_vitec_domain_model_usecase.hidden = 0 AND tx_vitec_domain_model_usecase.deleted = 0 ORDER BY tx_vitec_domain_model_usecase.title</foreign_table_where>
|
||||||
|
</config>
|
||||||
|
</settings.story>
|
||||||
|
|
||||||
|
<settings.market>
|
||||||
|
<label>Market</label>
|
||||||
|
<displayCond>FIELD:settings.modelType:=:market</displayCond>
|
||||||
|
<config>
|
||||||
|
<type>select</type>
|
||||||
|
<renderType>selectSingle</renderType>
|
||||||
|
<items>
|
||||||
|
<numIndex index="0">
|
||||||
|
<label>— please choose —</label>
|
||||||
|
<value>0</value>
|
||||||
|
</numIndex>
|
||||||
|
</items>
|
||||||
|
<foreign_table>tx_vitec_domain_model_market</foreign_table>
|
||||||
|
<foreign_table_where>AND tx_vitec_domain_model_market.hidden = 0 AND tx_vitec_domain_model_market.deleted = 0 ORDER BY tx_vitec_domain_model_market.title</foreign_table_where>
|
||||||
|
</config>
|
||||||
|
</settings.market>
|
||||||
|
|
||||||
|
<settings.solution>
|
||||||
|
<label>Solution</label>
|
||||||
|
<displayCond>FIELD:settings.modelType:=:solution</displayCond>
|
||||||
|
<config>
|
||||||
|
<type>select</type>
|
||||||
|
<renderType>selectSingle</renderType>
|
||||||
|
<items>
|
||||||
|
<numIndex index="0">
|
||||||
|
<label>— please choose —</label>
|
||||||
|
<value>0</value>
|
||||||
|
</numIndex>
|
||||||
|
</items>
|
||||||
|
<foreign_table>tx_vitec_domain_model_solution</foreign_table>
|
||||||
|
<foreign_table_where>AND tx_vitec_domain_model_solution.hidden = 0 AND tx_vitec_domain_model_solution.deleted = 0 ORDER BY tx_vitec_domain_model_solution.title</foreign_table_where>
|
||||||
|
</config>
|
||||||
|
</settings.solution>
|
||||||
|
|
||||||
|
<settings.layout>
|
||||||
|
<label>Layout</label>
|
||||||
|
<config>
|
||||||
|
<type>select</type>
|
||||||
|
<renderType>selectSingle</renderType>
|
||||||
|
<items>
|
||||||
|
<numIndex index="0">
|
||||||
|
<label>Vertical (image top)</label>
|
||||||
|
<value>vertical</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="1">
|
||||||
|
<label>Horizontal (image left)</label>
|
||||||
|
<value>horizontal</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="2">
|
||||||
|
<label>Image Overlay</label>
|
||||||
|
<value>overlay</value>
|
||||||
|
</numIndex>
|
||||||
|
<numIndex index="3">
|
||||||
|
<label>Compact</label>
|
||||||
|
<value>compact</value>
|
||||||
|
</numIndex>
|
||||||
|
</items>
|
||||||
|
<default>vertical</default>
|
||||||
|
</config>
|
||||||
|
</settings.layout>
|
||||||
|
|
||||||
|
<settings.debug>
|
||||||
|
<label>Allow Debug Output</label>
|
||||||
|
<config>
|
||||||
|
<type>check</type>
|
||||||
|
<default>0</default>
|
||||||
|
</config>
|
||||||
|
</settings.debug>
|
||||||
|
</el>
|
||||||
|
</ROOT>
|
||||||
|
</sDEF>
|
||||||
|
</sheets>
|
||||||
|
</T3DataStructure>
|
||||||
@@ -8,6 +8,17 @@
|
|||||||
</sheetTitle>
|
</sheetTitle>
|
||||||
<type>array</type>
|
<type>array</type>
|
||||||
<el>
|
<el>
|
||||||
|
<settings.backPid>
|
||||||
|
<label>Back to List View (page)</label>
|
||||||
|
<description>Page that holds the Success Story list plugin. Used to build the back link in the JSON output.</description>
|
||||||
|
<config>
|
||||||
|
<type>group</type>
|
||||||
|
<allowed>pages</allowed>
|
||||||
|
<size>1</size>
|
||||||
|
<maxitems>1</maxitems>
|
||||||
|
</config>
|
||||||
|
</settings.backPid>
|
||||||
|
|
||||||
<settings.debug>
|
<settings.debug>
|
||||||
<label>Allow Debug Output.</label>
|
<label>Allow Debug Output.</label>
|
||||||
<config>
|
<config>
|
||||||
@@ -19,20 +30,6 @@
|
|||||||
</items>
|
</items>
|
||||||
</config>
|
</config>
|
||||||
</settings.debug>
|
</settings.debug>
|
||||||
<settings.usecase>
|
|
||||||
<label>
|
|
||||||
Usecase
|
|
||||||
</label>
|
|
||||||
<config>
|
|
||||||
<type>select</type>
|
|
||||||
<renderType>selectSingle</renderType>
|
|
||||||
<foreign_table>tx_vitec_domain_model_usecase</foreign_table>
|
|
||||||
<foreign_table_where>AND tx_vitec_domain_model_usecase.hidden = 0 AND tx_vitec_domain_model_usecase.deleted = 0 ORDER BY tx_vitec_domain_model_usecase.title</foreign_table_where>
|
|
||||||
<size>1</size>
|
|
||||||
<minitems>0</minitems>
|
|
||||||
<maxitems>1</maxitems>
|
|
||||||
</config>
|
|
||||||
</settings.usecase>
|
|
||||||
<settings.layout>
|
<settings.layout>
|
||||||
<label>
|
<label>
|
||||||
Layout
|
Layout
|
||||||
|
|||||||
@@ -6,6 +6,17 @@
|
|||||||
<sheetTitle>Usecase List</sheetTitle>
|
<sheetTitle>Usecase List</sheetTitle>
|
||||||
<type>array</type>
|
<type>array</type>
|
||||||
<el>
|
<el>
|
||||||
|
<settings.singlePid>
|
||||||
|
<label>Single PID (detail page)</label>
|
||||||
|
<description>Page that holds the "Show single VITEC Success Story" plugin. Used to build the detail links in the JSON output.</description>
|
||||||
|
<config>
|
||||||
|
<type>group</type>
|
||||||
|
<allowed>pages</allowed>
|
||||||
|
<size>1</size>
|
||||||
|
<maxitems>1</maxitems>
|
||||||
|
</config>
|
||||||
|
</settings.singlePid>
|
||||||
|
|
||||||
<settings.debug>
|
<settings.debug>
|
||||||
<label>Allow Debug Output.</label>
|
<label>Allow Debug Output.</label>
|
||||||
<config>
|
<config>
|
||||||
|
|||||||
@@ -76,4 +76,16 @@ return [
|
|||||||
'provider' => SvgIconProvider::class,
|
'provider' => SvgIconProvider::class,
|
||||||
'source' => 'EXT:vitec/Resources/Public/Icons/vitec-ogimage.svg',
|
'source' => 'EXT:vitec/Resources/Public/Icons/vitec-ogimage.svg',
|
||||||
],
|
],
|
||||||
|
'vitec-plugin-locationlist' => [
|
||||||
|
'provider' => SvgIconProvider::class,
|
||||||
|
'source' => 'EXT:vitec/Resources/Public/Icons/vitec-plugin-locationlist.svg',
|
||||||
|
],
|
||||||
|
'vitec-plugin-customerlogos' => [
|
||||||
|
'provider' => SvgIconProvider::class,
|
||||||
|
'source' => 'EXT:vitec/Resources/Public/Icons/vitec-plugin-customerlogos.svg',
|
||||||
|
],
|
||||||
|
'vitec-plugin-modelcard' => [
|
||||||
|
'provider' => SvgIconProvider::class,
|
||||||
|
'source' => 'EXT:vitec/Resources/Public/Icons/vitec-plugin-modelcard.svg',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
20
packages/vitec/Configuration/RequestMiddlewares.php
Executable file
20
packages/vitec/Configuration/RequestMiddlewares.php
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frontend middleware registration for EXT:vitec.
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
'frontend' => [
|
||||||
|
'vitec/success-story-path-rewrite' => [
|
||||||
|
'target' => \Evomedien\Vitec\Middleware\SuccessStoryPathRewrite::class,
|
||||||
|
'after' => [
|
||||||
|
'typo3/cms-core/normalized-params-attribute',
|
||||||
|
],
|
||||||
|
'before' => [
|
||||||
|
'typo3/cms-frontend/site',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
@@ -160,6 +160,42 @@ tt_content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vitec_modelcard < lib.contentElementWithHeader
|
||||||
|
vitec_modelcard {
|
||||||
|
fields {
|
||||||
|
content {
|
||||||
|
fields {
|
||||||
|
card = USER
|
||||||
|
card.userFunc = Evomedien\Vitec\UserFunc\ModelcardJsonRenderer->render
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vitec_customerlogos < lib.contentElementWithHeader
|
||||||
|
vitec_customerlogos {
|
||||||
|
fields {
|
||||||
|
content {
|
||||||
|
fields {
|
||||||
|
customerlogos = USER
|
||||||
|
customerlogos.userFunc = Evomedien\Vitec\UserFunc\CustomerlogosJsonRenderer->render
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vitec_locationlist < lib.contentElementWithHeader
|
||||||
|
vitec_locationlist {
|
||||||
|
fields {
|
||||||
|
content {
|
||||||
|
fields {
|
||||||
|
locations = USER
|
||||||
|
locations.userFunc = Evomedien\Vitec\UserFunc\LocationsJsonRenderer->render
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Include container (layout) rendering definitions
|
# Include container (layout) rendering definitions
|
||||||
|
|||||||
@@ -35,6 +35,41 @@ use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
|
|||||||
$registerPluginWithFlexForm('Downloadcardcollection', 'Download Card Collection', 'FILE:EXT:vitec/Configuration/FlexForms/Downloadcardcollection.xml', 'vitec-plugin-downloadcardcollection');
|
$registerPluginWithFlexForm('Downloadcardcollection', 'Download Card Collection', 'FILE:EXT:vitec/Configuration/FlexForms/Downloadcardcollection.xml', 'vitec-plugin-downloadcardcollection');
|
||||||
$registerPluginWithFlexForm('Datasheets', 'Datasheets', 'FILE:EXT:vitec/Configuration/FlexForms/Datasheets.xml');
|
$registerPluginWithFlexForm('Datasheets', 'Datasheets', 'FILE:EXT:vitec/Configuration/FlexForms/Datasheets.xml');
|
||||||
$registerPluginWithFlexForm('Eventlist', 'Event List', 'FILE:EXT:vitec/Configuration/FlexForms/Eventlist.xml', 'vitec-plugin-eventlist');
|
$registerPluginWithFlexForm('Eventlist', 'Event List', 'FILE:EXT:vitec/Configuration/FlexForms/Eventlist.xml', 'vitec-plugin-eventlist');
|
||||||
|
// Locations: lives in the "VITEC" wizard group, titled "VITEC Locations".
|
||||||
|
$GLOBALS['TCA']['tt_content']['columns']['CType']['config']['itemGroups']['vitec']
|
||||||
|
= 'LLL:EXT:vitec/Resources/Private/Language/locallang_containers.xlf:group.header';
|
||||||
|
ExtensionUtility::registerPlugin(
|
||||||
|
'Vitec',
|
||||||
|
'Modelcard',
|
||||||
|
'VITEC Card',
|
||||||
|
'vitec-plugin-modelcard',
|
||||||
|
'vitec',
|
||||||
|
'One card for a Product, Success Story, Market or Solution — all data from the model.',
|
||||||
|
'FILE:EXT:vitec/Configuration/FlexForms/Modelcard.xml'
|
||||||
|
);
|
||||||
|
$GLOBALS['TCA']['tt_content']['types']['vitec_modelcard']['previewRenderer']
|
||||||
|
= \Evomedien\Vitec\Preview\ModelcardPreviewRenderer::class;
|
||||||
|
|
||||||
|
ExtensionUtility::registerPlugin(
|
||||||
|
'Vitec',
|
||||||
|
'Customerlogos',
|
||||||
|
'VITEC Customer Logos',
|
||||||
|
'vitec-plugin-customerlogos',
|
||||||
|
'vitec',
|
||||||
|
'Customer logos in list, grid, carousel or marquee layout.',
|
||||||
|
'FILE:EXT:vitec/Configuration/FlexForms/Customerlogos.xml'
|
||||||
|
);
|
||||||
|
|
||||||
|
ExtensionUtility::registerPlugin(
|
||||||
|
'Vitec',
|
||||||
|
'Locationlist',
|
||||||
|
'VITEC Locations',
|
||||||
|
'vitec-plugin-locationlist',
|
||||||
|
'vitec',
|
||||||
|
'Locations as grid, list or interactive map.',
|
||||||
|
'FILE:EXT:vitec/Configuration/FlexForms/Locationlist.xml'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
// Change frame_class to allow multiple selections.
|
// Change frame_class to allow multiple selections.
|
||||||
$GLOBALS['TCA']['tt_content']['columns']['frame_class']['config']['renderType'] = 'selectCheckBox';
|
$GLOBALS['TCA']['tt_content']['columns']['frame_class']['config']['renderType'] = 'selectCheckBox';
|
||||||
|
|||||||
63
packages/vitec/Configuration/TCA/tx_vitec_domain_model_customer.php
Executable file
63
packages/vitec/Configuration/TCA/tx_vitec_domain_model_customer.php
Executable file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'ctrl' => [
|
||||||
|
'title' => 'VITEC Customer',
|
||||||
|
'label' => 'title',
|
||||||
|
'tstamp' => 'tstamp',
|
||||||
|
'crdate' => 'crdate',
|
||||||
|
'sortby' => 'sorting',
|
||||||
|
'delete' => 'deleted',
|
||||||
|
'enablecolumns' => [
|
||||||
|
'disabled' => 'hidden',
|
||||||
|
'starttime' => 'starttime',
|
||||||
|
'endtime' => 'endtime',
|
||||||
|
],
|
||||||
|
'searchFields' => 'title',
|
||||||
|
'iconfile' => 'EXT:vitec/Resources/Public/Icons/vitec-plugin-customerlogos.svg',
|
||||||
|
'security' => [
|
||||||
|
'ignorePageTypeRestriction' => true,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'types' => [
|
||||||
|
'1' => [
|
||||||
|
'showitem' =>
|
||||||
|
'title, logo, emphasize_logo,
|
||||||
|
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
|
||||||
|
hidden, starttime, endtime',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'columns' => [
|
||||||
|
'hidden' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [['value' => '', 'label' => '', 'invertStateDisplay' => true]],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'starttime' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
|
||||||
|
'config' => ['type' => 'datetime', 'default' => 0],
|
||||||
|
],
|
||||||
|
'endtime' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
|
||||||
|
'config' => ['type' => 'datetime', 'default' => 0, 'range' => ['upper' => mktime(0, 0, 0, 1, 1, 2038)]],
|
||||||
|
],
|
||||||
|
'title' => [
|
||||||
|
'label' => 'Customer Name',
|
||||||
|
'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim', 'required' => true, 'default' => ''],
|
||||||
|
],
|
||||||
|
'logo' => [
|
||||||
|
'label' => 'Logo',
|
||||||
|
'config' => ['type' => 'file', 'maxitems' => 1, 'allowed' => 'common-image-types'],
|
||||||
|
],
|
||||||
|
'emphasize_logo' => [
|
||||||
|
'label' => 'Emphasize Logo',
|
||||||
|
'description' => 'Highlight this logo (e.g. larger) in the frontend.',
|
||||||
|
'config' => ['type' => 'check', 'renderType' => 'checkboxToggle', 'items' => [['value' => '', 'label' => '']]],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
168
packages/vitec/Configuration/TCA/tx_vitec_domain_model_location.php
Executable file
168
packages/vitec/Configuration/TCA/tx_vitec_domain_model_location.php
Executable file
@@ -0,0 +1,168 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'ctrl' => [
|
||||||
|
'title' => 'VITEC Location',
|
||||||
|
'label' => 'title',
|
||||||
|
'tstamp' => 'tstamp',
|
||||||
|
'crdate' => 'crdate',
|
||||||
|
'sortby' => 'sorting',
|
||||||
|
'delete' => 'deleted',
|
||||||
|
'enablecolumns' => [
|
||||||
|
'disabled' => 'hidden',
|
||||||
|
'starttime' => 'starttime',
|
||||||
|
'endtime' => 'endtime',
|
||||||
|
],
|
||||||
|
'searchFields' => 'title,slug,city,country,country_code',
|
||||||
|
'iconfile' => 'EXT:vitec/Resources/Public/Icons/vitec-plugin-locationlist.svg',
|
||||||
|
'security' => [
|
||||||
|
'ignorePageTypeRestriction' => true,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'types' => [
|
||||||
|
'1' => [
|
||||||
|
'showitem' =>
|
||||||
|
'--div--;General,
|
||||||
|
title, slug, country_code,
|
||||||
|
--palette--;Coordinates;coords,
|
||||||
|
--div--;Address,
|
||||||
|
address_company, street, address_additional,
|
||||||
|
--palette--;;cityline,
|
||||||
|
region, country,
|
||||||
|
--div--;Contact & Links,
|
||||||
|
phone, fax, email, contact_link, legal_links,
|
||||||
|
--div--;Marker,
|
||||||
|
marker_label, marker_color, marker_size,
|
||||||
|
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
|
||||||
|
hidden, starttime, endtime',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'palettes' => [
|
||||||
|
'coords' => ['showitem' => 'latitude, longitude'],
|
||||||
|
'cityline' => ['showitem' => 'postal_code, city'],
|
||||||
|
],
|
||||||
|
'columns' => [
|
||||||
|
'hidden' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'check',
|
||||||
|
'renderType' => 'checkboxToggle',
|
||||||
|
'items' => [['value' => '', 'label' => '', 'invertStateDisplay' => true]],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'starttime' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
|
||||||
|
'config' => ['type' => 'datetime', 'default' => 0],
|
||||||
|
],
|
||||||
|
'endtime' => [
|
||||||
|
'exclude' => true,
|
||||||
|
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
|
||||||
|
'config' => ['type' => 'datetime', 'default' => 0, 'range' => ['upper' => mktime(0, 0, 0, 1, 1, 2038)]],
|
||||||
|
],
|
||||||
|
|
||||||
|
// ----------------------------------------------------------- General
|
||||||
|
'title' => [
|
||||||
|
'label' => 'Name',
|
||||||
|
'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim', 'required' => true, 'default' => ''],
|
||||||
|
],
|
||||||
|
'slug' => [
|
||||||
|
'label' => 'Slug',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'slug',
|
||||||
|
'size' => 50,
|
||||||
|
'generatorOptions' => ['fields' => ['title'], 'fieldSeparator' => '-', 'replacements' => ['/' => '', ',' => '']],
|
||||||
|
'fallbackCharacter' => '-',
|
||||||
|
'eval' => 'uniqueInPid',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'country_code' => [
|
||||||
|
'label' => 'Country Code (ISO 3166-1 alpha-2)',
|
||||||
|
'description' => 'e.g. US, DE, GB',
|
||||||
|
'config' => ['type' => 'input', 'size' => 6, 'max' => 5, 'eval' => 'trim,upper', 'default' => ''],
|
||||||
|
],
|
||||||
|
'latitude' => [
|
||||||
|
'label' => 'Latitude',
|
||||||
|
'config' => ['type' => 'number', 'format' => 'decimal', 'default' => 0, 'range' => ['lower' => -90, 'upper' => 90]],
|
||||||
|
],
|
||||||
|
'longitude' => [
|
||||||
|
'label' => 'Longitude',
|
||||||
|
'config' => ['type' => 'number', 'format' => 'decimal', 'default' => 0, 'range' => ['lower' => -180, 'upper' => 180]],
|
||||||
|
],
|
||||||
|
|
||||||
|
// ----------------------------------------------------------- Address
|
||||||
|
'address_company' => [
|
||||||
|
'label' => 'Company (optional)',
|
||||||
|
'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim', 'default' => ''],
|
||||||
|
],
|
||||||
|
'street' => [
|
||||||
|
'label' => 'Street',
|
||||||
|
'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim', 'default' => ''],
|
||||||
|
],
|
||||||
|
'address_additional' => [
|
||||||
|
'label' => 'Additional (optional)',
|
||||||
|
'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim', 'default' => ''],
|
||||||
|
],
|
||||||
|
'postal_code' => [
|
||||||
|
'label' => 'Postal Code',
|
||||||
|
'config' => ['type' => 'input', 'size' => 10, 'max' => 20, 'eval' => 'trim', 'default' => ''],
|
||||||
|
],
|
||||||
|
'city' => [
|
||||||
|
'label' => 'City',
|
||||||
|
'config' => ['type' => 'input', 'size' => 30, 'eval' => 'trim', 'default' => ''],
|
||||||
|
],
|
||||||
|
'region' => [
|
||||||
|
'label' => 'Region / State (optional)',
|
||||||
|
'description' => 'e.g. GA',
|
||||||
|
'config' => ['type' => 'input', 'size' => 20, 'eval' => 'trim', 'default' => ''],
|
||||||
|
],
|
||||||
|
'country' => [
|
||||||
|
'label' => 'Country (display name)',
|
||||||
|
'config' => ['type' => 'input', 'size' => 30, 'eval' => 'trim', 'default' => ''],
|
||||||
|
],
|
||||||
|
|
||||||
|
// --------------------------------------------------- Contact & Links
|
||||||
|
'phone' => [
|
||||||
|
'label' => 'Phone',
|
||||||
|
'config' => ['type' => 'input', 'size' => 30, 'max' => 100, 'eval' => 'trim', 'default' => ''],
|
||||||
|
],
|
||||||
|
'fax' => [
|
||||||
|
'label' => 'Fax',
|
||||||
|
'config' => ['type' => 'input', 'size' => 30, 'max' => 100, 'eval' => 'trim', 'default' => ''],
|
||||||
|
],
|
||||||
|
'email' => [
|
||||||
|
'label' => 'E-Mail',
|
||||||
|
'config' => ['type' => 'email', 'size' => 40, 'default' => ''],
|
||||||
|
],
|
||||||
|
'contact_link' => [
|
||||||
|
'label' => 'Contact Link',
|
||||||
|
'config' => ['type' => 'link', 'allowedTypes' => ['page', 'url', 'email']],
|
||||||
|
],
|
||||||
|
'legal_links' => [
|
||||||
|
'label' => 'Legal Links',
|
||||||
|
'description' => 'One link per line (page link or URL).',
|
||||||
|
'config' => ['type' => 'text', 'cols' => 40, 'rows' => 3, 'eval' => 'trim'],
|
||||||
|
],
|
||||||
|
|
||||||
|
// ------------------------------------------------------------ Marker
|
||||||
|
'marker_label' => [
|
||||||
|
'label' => 'Marker Label (optional)',
|
||||||
|
'description' => 'Falls back to the location name.',
|
||||||
|
'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim', 'default' => ''],
|
||||||
|
],
|
||||||
|
'marker_color' => [
|
||||||
|
'label' => 'Marker Color',
|
||||||
|
'config' => ['type' => 'color', 'default' => '#ff6633'],
|
||||||
|
],
|
||||||
|
'marker_size' => [
|
||||||
|
'label' => 'Marker Size (scale, e.g. 0.5)',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'number',
|
||||||
|
'format' => 'decimal',
|
||||||
|
'default' => 0.5,
|
||||||
|
'range' => ['lower' => 0, 'upper' => 5],
|
||||||
|
'slider' => ['step' => 0.05, 'width' => 200],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
@@ -34,7 +34,7 @@ return [
|
|||||||
--div--;Detail · Content,
|
--div--;Detail · Content,
|
||||||
content_elements,
|
content_elements,
|
||||||
--div--;Detail · Related,
|
--div--;Detail · Related,
|
||||||
market, solutions, products, categories,
|
markets, solutions, products, categories,
|
||||||
--div--;SEO,
|
--div--;SEO,
|
||||||
seo_title, seo_description, no_index, no_follow, canonical_link,
|
seo_title, seo_description, no_index, no_follow, canonical_link,
|
||||||
--palette--;Open Graph;ogPalette,
|
--palette--;Open Graph;ogPalette,
|
||||||
@@ -182,15 +182,16 @@ return [
|
|||||||
],
|
],
|
||||||
|
|
||||||
// --------------------------------------------------- Detail · Related
|
// --------------------------------------------------- Detail · Related
|
||||||
'market' => [
|
'markets' => [
|
||||||
'label' => 'Market',
|
'label' => 'Markets',
|
||||||
'config' => [
|
'config' => [
|
||||||
'type' => 'select',
|
'type' => 'select',
|
||||||
'renderType' => 'selectSingle',
|
'renderType' => 'selectMultipleSideBySide',
|
||||||
'foreign_table' => 'tx_vitec_domain_model_market',
|
'foreign_table' => 'tx_vitec_domain_model_market',
|
||||||
'items' => [['label' => '', 'value' => 0]],
|
'MM' => 'tx_vitec_usecase_market_mm',
|
||||||
'default' => 0,
|
'size' => 6,
|
||||||
'maxitems' => 1,
|
'autoSizeMax' => 20,
|
||||||
|
'maxitems' => 9999,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'solutions' => [
|
'solutions' => [
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ prefixFields: true
|
|||||||
prefixType: vendor
|
prefixType: vendor
|
||||||
|
|
||||||
fields:
|
fields:
|
||||||
|
# ──────────────────────────────────────────────────────────────────────
|
||||||
|
- identifier: tab_content
|
||||||
|
type: Tab
|
||||||
|
label: Content
|
||||||
|
|
||||||
- identifier: eyebrow
|
- identifier: eyebrow
|
||||||
type: Text
|
type: Text
|
||||||
max: 50
|
max: 50
|
||||||
@@ -29,10 +34,6 @@ fields:
|
|||||||
- identifier: subheader
|
- identifier: subheader
|
||||||
useExistingField: true
|
useExistingField: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- identifier: bodytext
|
- identifier: bodytext
|
||||||
useExistingField: true
|
useExistingField: true
|
||||||
enableRichtext: true
|
enableRichtext: true
|
||||||
@@ -53,7 +54,33 @@ fields:
|
|||||||
- identifier: Vitec/ButtonStyle
|
- identifier: Vitec/ButtonStyle
|
||||||
type: Basic
|
type: Basic
|
||||||
|
|
||||||
# --- Image ---
|
- identifier: hero_layout_variant
|
||||||
|
type: Select
|
||||||
|
renderType: selectSingle
|
||||||
|
default: fullscreen
|
||||||
|
items:
|
||||||
|
- label: Fullscreen
|
||||||
|
value: fullscreen
|
||||||
|
- label: Medium
|
||||||
|
value: md
|
||||||
|
- label: Small
|
||||||
|
value: sm
|
||||||
|
- label: Extra Small
|
||||||
|
value: xs
|
||||||
|
|
||||||
|
- identifier: show_logo_wall
|
||||||
|
type: Checkbox
|
||||||
|
default: 0
|
||||||
|
|
||||||
|
- identifier: debug
|
||||||
|
type: Checkbox
|
||||||
|
default: 0
|
||||||
|
|
||||||
|
# ──────────────────────────────────────────────────────────────────────
|
||||||
|
- identifier: tab_images
|
||||||
|
type: Tab
|
||||||
|
label: Images
|
||||||
|
|
||||||
- identifier: hero_bgimage
|
- identifier: hero_bgimage
|
||||||
type: File
|
type: File
|
||||||
minitems: 0
|
minitems: 0
|
||||||
@@ -82,7 +109,11 @@ fields:
|
|||||||
- label: Fullwidth
|
- label: Fullwidth
|
||||||
value: fullwidth
|
value: fullwidth
|
||||||
|
|
||||||
# --- Video ---
|
# ──────────────────────────────────────────────────────────────────────
|
||||||
|
- identifier: tab_video
|
||||||
|
type: Tab
|
||||||
|
label: Video
|
||||||
|
|
||||||
- identifier: hero_video
|
- identifier: hero_video
|
||||||
type: File
|
type: File
|
||||||
minitems: 0
|
minitems: 0
|
||||||
@@ -115,24 +146,28 @@ fields:
|
|||||||
type: Checkbox
|
type: Checkbox
|
||||||
default: 1
|
default: 1
|
||||||
|
|
||||||
- identifier: hero_layout_variant
|
# --- Background video with overlay layer ---
|
||||||
type: Select
|
- identifier: hero_bgvideo
|
||||||
renderType: selectSingle
|
type: File
|
||||||
default: fullscreen
|
label: Background Video
|
||||||
items:
|
description: 'Fullscreen background video behind the hero content.'
|
||||||
- label: Fullscreen
|
minitems: 0
|
||||||
value: fullscreen
|
maxitems: 1
|
||||||
- label: Medium
|
allowed: mp4,webm,ogv,mov,m4v
|
||||||
value: md
|
|
||||||
- label: Small
|
|
||||||
value: sm
|
|
||||||
- label: Extra Small
|
|
||||||
value: xs
|
|
||||||
|
|
||||||
- identifier: show_logo_wall
|
- identifier: hero_overlay_color
|
||||||
type: Checkbox
|
type: Color
|
||||||
default: 0
|
label: Overlay Color
|
||||||
|
description: 'Overlay layer on top of the background video/image.'
|
||||||
|
|
||||||
- identifier: debug
|
- identifier: hero_overlay_opacity
|
||||||
type: Checkbox
|
type: Number
|
||||||
default: 0
|
label: 'Overlay Opacity (0–1)'
|
||||||
|
format: decimal
|
||||||
|
default: 0.4
|
||||||
|
range:
|
||||||
|
lower: 0
|
||||||
|
upper: 1
|
||||||
|
slider:
|
||||||
|
step: 0.05
|
||||||
|
width: 200
|
||||||
|
|||||||
@@ -102,6 +102,28 @@
|
|||||||
<trans-unit id="hero_bgimage.description">
|
<trans-unit id="hero_bgimage.description">
|
||||||
<source>Optional background image placed behind the hero content.</source>
|
<source>Optional background image placed behind the hero content.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="tab_content.label">
|
||||||
|
<source>Content</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="tab_images.label">
|
||||||
|
<source>Images</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="tab_video.label">
|
||||||
|
<source>Video</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="hero_bgvideo.label">
|
||||||
|
<source>Background Video</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="hero_bgvideo.description">
|
||||||
|
<source>Fullscreen background video behind the hero content.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="hero_overlay_color.label">
|
||||||
|
<source>Overlay Color</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="hero_overlay_opacity.label">
|
||||||
|
<source>Overlay Opacity (0–1)</source>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
4
packages/vitec/ContentBlocks/ContentElements/quotation/assets/icon.svg
Executable file
4
packages/vitec/ContentBlocks/ContentElements/quotation/assets/icon.svg
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
||||||
|
<path d="M6 8h8v8h-6l-2 8H4l2-8V8z" fill="#ff6a00"/>
|
||||||
|
<path d="M18 8h8v8h-6l-2 8h-2l2-8V8z" fill="#0a3d62"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 203 B |
44
packages/vitec/ContentBlocks/ContentElements/quotation/config.yaml
Executable file
44
packages/vitec/ContentBlocks/ContentElements/quotation/config.yaml
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
name: vitec/quotation
|
||||||
|
group: vitec_custom_components
|
||||||
|
prefixFields: true
|
||||||
|
prefixType: vendor
|
||||||
|
|
||||||
|
fields:
|
||||||
|
- identifier: header_section
|
||||||
|
type: Palette
|
||||||
|
label: Header
|
||||||
|
fields:
|
||||||
|
- identifier: header
|
||||||
|
useExistingField: true
|
||||||
|
- type: Linebreak
|
||||||
|
- identifier: header_layout
|
||||||
|
useExistingField: true
|
||||||
|
- identifier: header_position
|
||||||
|
useExistingField: true
|
||||||
|
- identifier: date
|
||||||
|
useExistingField: true
|
||||||
|
- type: Linebreak
|
||||||
|
- identifier: header_link
|
||||||
|
useExistingField: true
|
||||||
|
- type: Linebreak
|
||||||
|
- identifier: subheader
|
||||||
|
useExistingField: true
|
||||||
|
|
||||||
|
- identifier: quote
|
||||||
|
type: Textarea
|
||||||
|
required: true
|
||||||
|
rows: 5
|
||||||
|
|
||||||
|
- identifier: quote_name
|
||||||
|
type: Text
|
||||||
|
max: 120
|
||||||
|
|
||||||
|
- identifier: quote_position
|
||||||
|
type: Text
|
||||||
|
max: 180
|
||||||
|
|
||||||
|
- identifier: quote_logo
|
||||||
|
type: File
|
||||||
|
minitems: 0
|
||||||
|
maxitems: 1
|
||||||
|
allowed: common-image-types
|
||||||
28
packages/vitec/ContentBlocks/ContentElements/quotation/language/labels.xlf
Executable file
28
packages/vitec/ContentBlocks/ContentElements/quotation/language/labels.xlf
Executable file
@@ -0,0 +1,28 @@
|
|||||||
|
<?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 · Customer Quotation</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="description">
|
||||||
|
<source>Customer quote with name, position and optional logo.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="quote.label">
|
||||||
|
<source>Quote</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="quote.description">
|
||||||
|
<source>Plain quote text without quotation marks — the frontend adds them.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="quote_name.label">
|
||||||
|
<source>Name</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="quote_position.label">
|
||||||
|
<source>Position / Company</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="quote_logo.label">
|
||||||
|
<source>Logo (optional)</source>
|
||||||
|
</trans-unit>
|
||||||
|
</body>
|
||||||
|
</file>
|
||||||
|
</xliff>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<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">
|
||||||
|
<div class="vitec-preview__thumb-placeholder">“</div>
|
||||||
|
<div class="vitec-preview__body">
|
||||||
|
<div class="vitec-preview__label">VITEC · Customer Quotation</div>
|
||||||
|
<h3 class="vitec-preview__headline">
|
||||||
|
<f:if condition="{data.quote}">
|
||||||
|
<f:then>“{data.quote -> f:format.crop(maxCharacters: 90)}”</f:then>
|
||||||
|
<f:else><em style="color:#c00;">⚠ Quote missing</em></f:else>
|
||||||
|
</f:if>
|
||||||
|
</h3>
|
||||||
|
<f:if condition="{data.quote_name}">
|
||||||
|
<div class="vitec-preview__subline">— {data.quote_name}<f:if condition="{data.quote_position}">, {data.quote_position}</f:if></div>
|
||||||
|
</f:if>
|
||||||
|
</div>
|
||||||
|
<div class="vitec-preview__settings">
|
||||||
|
<f:if condition="{data.quote_logo.0}"><span class="vitec-badge">🖼 Logo</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>
|
||||||
36
packages/vitec/Resources/Private/Templates/Preview/Modelcard.html
Executable file
36
packages/vitec/Resources/Private/Templates/Preview/Modelcard.html
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
|
||||||
|
|
||||||
|
<f:asset.css identifier="vitec-backend-preview" href="EXT:vitec/Resources/Public/Css/backend-preview.css"/>
|
||||||
|
|
||||||
|
<div class="vitec-preview">
|
||||||
|
<f:if condition="{imageUrl}">
|
||||||
|
<f:then>
|
||||||
|
<img src="{imageUrl}" class="vitec-preview__thumb" width="200" alt="Card preview"/>
|
||||||
|
</f:then>
|
||||||
|
<f:else>
|
||||||
|
<div class="vitec-preview__thumb-placeholder">▢</div>
|
||||||
|
</f:else>
|
||||||
|
</f:if>
|
||||||
|
|
||||||
|
<div class="vitec-preview__body">
|
||||||
|
<div class="vitec-preview__label">VITEC · Card — {typeLabel}</div>
|
||||||
|
<h3 class="vitec-preview__headline">
|
||||||
|
<f:if condition="{title}">
|
||||||
|
<f:then>{title}</f:then>
|
||||||
|
<f:else><em style="color:#c00;">⚠ No {typeLabel} selected</em></f:else>
|
||||||
|
</f:if>
|
||||||
|
</h3>
|
||||||
|
<f:if condition="{subtitle}">
|
||||||
|
<div class="vitec-preview__subline">{subtitle -> f:format.crop(maxCharacters: 90)}</div>
|
||||||
|
</f:if>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="vitec-preview__settings">
|
||||||
|
<span class="vitec-badge">{typeLabel}</span>
|
||||||
|
<span class="vitec-badge">Layout: {layout}</span>
|
||||||
|
<f:if condition="{recordUid} == 0">
|
||||||
|
<span class="vitec-badge vitec-badge--warning">⚠ nothing selected</span>
|
||||||
|
</f:if>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</html>
|
||||||
@@ -205,3 +205,43 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Small monitors: drop the body text — label, headline and badges stay. */
|
||||||
|
@media (max-width: 1400px) {
|
||||||
|
.vitec-preview__body-text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Real fix: react to the PREVIEW COLUMN width, not the monitor width.
|
||||||
|
The page-module body of a CE containing a vitec preview becomes a size
|
||||||
|
container (e.g. inside narrow b13 container columns). */
|
||||||
|
.t3-page-ce-body:has(.vitec-preview) {
|
||||||
|
container-type: inline-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Narrow column: stack the grid, drop the body text, badges in a row. */
|
||||||
|
@container (max-width: 700px) {
|
||||||
|
.vitec-preview {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
.vitec-preview__body-text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.vitec-preview__settings {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.vitec-preview__thumb,
|
||||||
|
.vitec-preview__thumb-placeholder {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Very narrow column: only label, headline and badges survive. */
|
||||||
|
@container (max-width: 420px) {
|
||||||
|
.vitec-preview__subline {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
6
packages/vitec/Resources/Public/Icons/vitec-plugin-customerlogos.svg
Executable file
6
packages/vitec/Resources/Public/Icons/vitec-plugin-customerlogos.svg
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
||||||
|
<rect x="3" y="7" width="12" height="8" rx="1.5" fill="#ff6a00"/>
|
||||||
|
<rect x="17" y="7" width="12" height="8" rx="1.5" fill="#9aa2ab"/>
|
||||||
|
<rect x="3" y="17" width="12" height="8" rx="1.5" fill="#9aa2ab"/>
|
||||||
|
<rect x="17" y="17" width="12" height="8" rx="1.5" fill="#9aa2ab"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 367 B |
4
packages/vitec/Resources/Public/Icons/vitec-plugin-locationlist.svg
Executable file
4
packages/vitec/Resources/Public/Icons/vitec-plugin-locationlist.svg
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
||||||
|
<path d="M16 3c-5 0-9 4-9 9 0 6.6 9 17 9 17s9-10.4 9-17c0-5-4-9-9-9z" fill="#ff6a00"/>
|
||||||
|
<circle cx="16" cy="12" r="4" fill="#fff"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 226 B |
6
packages/vitec/Resources/Public/Icons/vitec-plugin-modelcard.svg
Executable file
6
packages/vitec/Resources/Public/Icons/vitec-plugin-modelcard.svg
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
||||||
|
<rect x="5" y="4" width="22" height="24" rx="2" fill="#0a3d62"/>
|
||||||
|
<rect x="8" y="7" width="16" height="9" rx="1" fill="#ff6a00"/>
|
||||||
|
<rect x="8" y="19" width="16" height="2.5" rx="1" fill="#fff"/>
|
||||||
|
<rect x="8" y="23" width="10" height="2.5" rx="1" fill="#9aa2ab"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 359 B |
@@ -157,4 +157,40 @@ $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1750000000] = [
|
|||||||
\Evomedien\Vitec\Controller\EventController::class => 'list'
|
\Evomedien\Vitec\Controller\EventController::class => 'list'
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ExtensionUtility::configurePlugin(
|
||||||
|
'Vitec',
|
||||||
|
'Locationlist',
|
||||||
|
[
|
||||||
|
\Evomedien\Vitec\Controller\LocationController::class => 'list'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
\Evomedien\Vitec\Controller\LocationController::class => 'list'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
ExtensionUtility::configurePlugin(
|
||||||
|
'Vitec',
|
||||||
|
'Customerlogos',
|
||||||
|
[
|
||||||
|
\Evomedien\Vitec\Controller\CustomerController::class => 'list'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
\Evomedien\Vitec\Controller\CustomerController::class => 'list'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
ExtensionUtility::configurePlugin(
|
||||||
|
'Vitec',
|
||||||
|
'Modelcard',
|
||||||
|
[
|
||||||
|
\Evomedien\Vitec\Controller\ModelcardController::class => 'list'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
\Evomedien\Vitec\Controller\ModelcardController::class => 'list'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ CREATE TABLE tx_vitec_domain_model_usecase (
|
|||||||
card_image int(11) unsigned DEFAULT '0' NOT NULL,
|
card_image int(11) unsigned DEFAULT '0' NOT NULL,
|
||||||
customer_logo int(11) unsigned DEFAULT '0' NOT NULL,
|
customer_logo int(11) unsigned DEFAULT '0' NOT NULL,
|
||||||
teaser text,
|
teaser text,
|
||||||
market int(11) unsigned DEFAULT '0' NOT NULL,
|
markets int(11) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
|
||||||
hero_bgimage int(11) unsigned DEFAULT '0' NOT NULL,
|
hero_bgimage int(11) unsigned DEFAULT '0' NOT NULL,
|
||||||
hero_small_image int(11) unsigned DEFAULT '0' NOT NULL,
|
hero_small_image int(11) unsigned DEFAULT '0' NOT NULL,
|
||||||
@@ -243,3 +243,41 @@ CREATE TABLE tx_vitec_usecase_product_mm (
|
|||||||
KEY uid_local (uid_local),
|
KEY uid_local (uid_local),
|
||||||
KEY uid_foreign (uid_foreign)
|
KEY uid_foreign (uid_foreign)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_usecase_market_mm (
|
||||||
|
uid_local int(11) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
uid_foreign int(11) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
sorting int(11) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
sorting_foreign int(11) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
KEY uid_local (uid_local),
|
||||||
|
KEY uid_foreign (uid_foreign)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_domain_model_location (
|
||||||
|
title varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
slug varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
country_code varchar(5) DEFAULT '' NOT NULL,
|
||||||
|
latitude decimal(11,7) DEFAULT '0.0000000' NOT NULL,
|
||||||
|
longitude decimal(11,7) DEFAULT '0.0000000' NOT NULL,
|
||||||
|
address_company varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
street varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
address_additional varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
postal_code varchar(20) DEFAULT '' NOT NULL,
|
||||||
|
city varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
region varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
country varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
phone varchar(100) DEFAULT '' NOT NULL,
|
||||||
|
fax varchar(100) DEFAULT '' NOT NULL,
|
||||||
|
email varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
contact_link varchar(1024) DEFAULT '' NOT NULL,
|
||||||
|
legal_links text,
|
||||||
|
marker_label varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
marker_color varchar(20) DEFAULT '#ff6633' NOT NULL,
|
||||||
|
marker_size decimal(3,2) DEFAULT '0.50' NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE tx_vitec_domain_model_customer (
|
||||||
|
title varchar(255) DEFAULT '' NOT NULL,
|
||||||
|
logo int(11) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
emphasize_logo smallint(5) unsigned DEFAULT '0' NOT NULL
|
||||||
|
);
|
||||||
|
|||||||
@@ -397,7 +397,10 @@ FileETag None
|
|||||||
|
|
||||||
# Add your own rules here.
|
# Add your own rules here.
|
||||||
|
|
||||||
#AuthUserFile "/usr/www/users/vitecevo/live/public/.htpasswd"
|
AuthUserFile "/usr/www/users/vitecevo/live/public/.htpasswd"
|
||||||
#AuthName "DEV"
|
AuthName "DEV"
|
||||||
#AuthType Basic
|
AuthType Basic
|
||||||
#require valid-user
|
<RequireAny>
|
||||||
|
Require ip 217.70.192.164
|
||||||
|
Require valid-user
|
||||||
|
</RequireAny>
|
||||||
|
|||||||
1
public/_frontend/assets/VitecDebugToggle-Bp07RQC2.js
Normal file
1
public/_frontend/assets/VitecDebugToggle-Bp07RQC2.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
import{C as e,S as t,Z as n,_ as r,c as i,d as a,h as o,k as s,l as c,m as l,n as u,p as d,u as f,v as p,y as m}from"./index-7LYai_r-.js";var h=n();function g({element:n,className:g,nested:_,devInfoTags:v,uid:y,spaceBefore:b,spaceAfter:x}){let S=i(n),C=a(n),w=Number(c(n)??0),T=p(w),E=m(w),D=r(f(n)),O=D===`center`?`center`:D===`right`?`right`:`left`,k=D===`center`?`center`:D===`right`?`flex-end`:`flex-start`,A=d(n.content?.headerLink),j=o(n.content?.headerLink),M=l(n.content?.headerLink,`Mehr erfahren`);return w===100?null:(0,h.jsx)(u,{className:g,devInfoTags:v,nested:_,uid:y,spaceBefore:b,spaceAfter:x,children:(0,h.jsx)(`div`,{className:`header__inner`,children:(0,h.jsxs)(e,{spacing:.75,sx:{textAlign:O,alignItems:k},children:[S&&(0,h.jsx)(s,{variant:T,children:S}),C&&(0,h.jsx)(s,{variant:E,color:`text.secondary`,children:C}),A&&(0,h.jsx)(t,{href:A,target:j??`_self`,variant:`outlined`,size:`sm`,children:M})]})})})}export{g as VitecHeader};
|
|
||||||
1
public/_frontend/assets/header-CddkKp_g.js
Normal file
1
public/_frontend/assets/header-CddkKp_g.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,S as t,T as n,_ as r,b as i,d as a,f as o,g as s,m as c,ot as l,p as u,r as d,t as f,v as p,x as m}from"./index-CM0zIqrs.js";var h=l();function g({element:l,className:g,nested:_,devInfoTags:v,uid:y,spaceBefore:b,spaceAfter:x}){let S=a(l),C=c(l),w=Number(o(l)??0),T=m(w),E=t(w),D=i(u(l)),O=D===`center`?`center`:D===`right`?`right`:`left`,k=D===`center`?`center`:D===`right`?`flex-end`:`flex-start`,A=s(l.content?.headerLink),j=p(l.content?.headerLink),M=r(l.content?.headerLink,`Mehr erfahren`);return w===100?null:(0,h.jsx)(d,{className:g,devInfoTags:v,nested:_,uid:y,spaceBefore:b,spaceAfter:x,children:(0,h.jsx)(`div`,{className:`header__inner`,children:(0,h.jsxs)(n,{spacing:.75,sx:{textAlign:O,alignItems:k},children:[S&&(0,h.jsx)(e,{variant:T,children:S}),C&&(0,h.jsx)(e,{variant:E,sx:{opacity:.6},children:C}),A&&(0,h.jsx)(f,{href:A,target:j??`_self`,variant:`outlined`,size:`sm`,children:M})]})})})}export{g as VitecHeader};
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
148
public/_frontend/assets/index-CM0zIqrs.js
Normal file
148
public/_frontend/assets/index-CM0zIqrs.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
public/_frontend/assets/news_newsdetail-Ch4soZ5k.js
Normal file
1
public/_frontend/assets/news_newsdetail-Ch4soZ5k.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,C as t,J as n,O as r,T as i,c as a,k as o,o as s,ot as c,r as l}from"./index-CM0zIqrs.js";var u=c();function d(e){return e.split(`?`)[0].split(`.`).pop()?.toLowerCase()??``}function f(e){return decodeURIComponent(e.split(`?`)[0].split(`/`).pop()??``).replace(/^csm_/,``).replace(/_[a-f0-9]{8,}(\.[^.]+)$/,`$1`)}function p(e){return[`pdf`,`doc`,`docx`,`xls`,`xlsx`,`ppt`,`pptx`,`zip`,`txt`,`csv`].includes(e)}function m({categories:e}){return e?.length?(0,u.jsx)(u.Fragment,{children:e.map(e=>(0,u.jsx)(o,{label:e.title,size:`small`,className:`vitec_newslist__chip`},e.uid))}):null}function h(){return(0,u.jsxs)(`svg`,{width:`14`,height:`14`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2.25`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[(0,u.jsx)(`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`}),(0,u.jsx)(`polyline`,{points:`7 10 12 15 17 10`}),(0,u.jsx)(`line`,{x1:`12`,y1:`15`,x2:`12`,y2:`3`})]})}function g({file:e}){let t=d(e.url),r=f(e.url);return(0,u.jsxs)(`a`,{href:n(e.url,a.base_url,a.router_mode),download:p(t)?r:void 0,target:`_blank`,rel:`noreferrer`,className:`vitec_newsdetail__file`,children:[(0,u.jsx)(`span`,{className:`vitec_newsdetail__file-ext`,children:t.toUpperCase()}),(0,u.jsx)(`span`,{className:`vitec_newsdetail__file-name`,children:r}),(0,u.jsx)(`span`,{className:`vitec_newsdetail__file-dl`,children:(0,u.jsx)(h,{})})]})}function _({element:n,className:a,nested:o,devInfoTags:c,uid:d,spaceBefore:f,spaceAfter:p}){let h=n.content?.news?.news;if(!h)return(0,u.jsx)(l,{className:[`vitec_newsdetail`,a].filter(Boolean).join(` `),devInfoTags:c,nested:o,uid:d,spaceBefore:f,spaceAfter:p,children:(0,u.jsx)(e,{variant:`body2`,color:`text.secondary`,children:`No article found.`})});let _=h.media?.[0]?.url,v=h.datetime?s(h.datetime):null,y=h.relatedFiles??[];return(0,u.jsxs)(l,{className:[`vitec_newsdetail`,a].filter(Boolean).join(` `),devInfoTags:c,nested:o,uid:d,spaceBefore:f,spaceAfter:p,children:[_&&(0,u.jsxs)(`div`,{className:`vitec_newsdetail__hero`,children:[(0,u.jsx)(`img`,{src:_,alt:``,className:`vitec_newsdetail__hero-img`,loading:`eager`}),(0,u.jsx)(`div`,{className:`vitec_newsdetail__hero-overlay`})]}),(0,u.jsxs)(`div`,{className:`vitec_newsdetail__body`,children:[(0,u.jsxs)(i,{direction:`row`,spacing:.75,flexWrap:`wrap`,useFlexGap:!0,alignItems:`center`,className:`vitec_newsdetail__meta`,children:[(0,u.jsx)(m,{categories:h.categories}),v&&(0,u.jsx)(`span`,{className:`vitec_newsdetail__date`,children:v}),h.author&&(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`span`,{className:`vitec_newsdetail__meta-sep`,"aria-hidden":!0,children:`·`}),(0,u.jsx)(`span`,{className:`vitec_newsdetail__author`,children:h.author})]})]}),(0,u.jsx)(`h1`,{className:`vitec_newsdetail__title`,children:h.title}),h.teaser&&(0,u.jsx)(`p`,{className:`vitec_newsdetail__teaser`,children:h.teaser}),h.bodytext&&(0,u.jsx)(r,{className:`vitec_newsdetail__bodytext`,sx:t,dangerouslySetInnerHTML:{__html:h.bodytext}}),y.length>0&&(0,u.jsxs)(`div`,{className:`vitec_newsdetail__files`,children:[(0,u.jsx)(`p`,{className:`vitec_newsdetail__files-label`,children:`Downloads`}),(0,u.jsx)(`div`,{className:`vitec_newsdetail__files-list`,children:y.map(e=>(0,u.jsx)(g,{file:e},e.uid))})]})]})]})}export{_ as NewsNewsDetail};
|
||||||
1
public/_frontend/assets/news_newsliststicky-LPL7flHj.js
Normal file
1
public/_frontend/assets/news_newsliststicky-LPL7flHj.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
import{C as e,D as t,S as n,Z as r,_ as i,b as a,c as o,d as s,h as c,k as l,l as u,m as d,n as f,p,s as m,u as h,v as g,y as _}from"./index-7LYai_r-.js";var v=r();function y({element:r,className:y,nested:b,devInfoTags:x,uid:S,spaceBefore:C,spaceAfter:w}){let T=o(r),E=s(r),D=m(r),O=Number(u(r)??0),k=g(O),A=_(O),j=i(h(r)),M=j===`center`?`center`:j===`right`?`right`:`left`,N=j===`center`?`center`:j===`right`?`flex-end`:`flex-start`,P=r.appearance?.frameClass?.split(`,`).map(e=>e.trim()).includes(`vitec-full-width`)??!1,F=p(r.content?.headerLink),I=c(r.content?.headerLink),L=d(r.content?.headerLink,`Mehr erfahren`);return(0,v.jsx)(f,{className:y,devInfoTags:x,fullWidth:P,nested:b,uid:S,spaceBefore:C,spaceAfter:w,children:(0,v.jsx)(`div`,{className:`text__inner`,children:(0,v.jsxs)(e,{spacing:2,sx:{textAlign:M,alignItems:N},children:[(T||E)&&(0,v.jsxs)(e,{spacing:.5,children:[T&&(0,v.jsx)(l,{variant:k,children:T}),E&&(0,v.jsx)(l,{variant:A,color:`text.secondary`,children:E})]}),F&&(0,v.jsx)(n,{href:F,target:I??`_self`,variant:`outlined`,size:`sm`,children:L}),D&&(0,v.jsx)(t,{sx:{...a,textAlign:`left`},dangerouslySetInnerHTML:{__html:D}})]})})})}export{y as VitecText};
|
|
||||||
1
public/_frontend/assets/text-CkDHrg9f.js
Normal file
1
public/_frontend/assets/text-CkDHrg9f.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,C as t,O as n,S as r,T as i,_ as a,b as o,d as s,f as c,g as l,m as u,ot as d,p as f,r as p,t as m,u as h,v as g,x as _}from"./index-CM0zIqrs.js";var v=d();function y({element:d,className:y,nested:b,devInfoTags:x,uid:S,spaceBefore:C,spaceAfter:w}){let T=s(d),E=u(d),D=h(d),O=Number(c(d)??0),k=_(O),A=r(O),j=o(f(d)),M=j===`center`?`center`:j===`right`?`right`:`left`,N=j===`center`?`center`:j===`right`?`flex-end`:`flex-start`,P=d.appearance?.frameClass?.split(`,`).map(e=>e.trim()).includes(`vitec-full-width`)??!1,F=l(d.content?.headerLink),I=g(d.content?.headerLink),L=a(d.content?.headerLink,`Mehr erfahren`);return(0,v.jsx)(p,{className:y,devInfoTags:x,fullWidth:P,nested:b,uid:S,spaceBefore:C,spaceAfter:w,children:(0,v.jsx)(`div`,{className:`text__inner`,children:(0,v.jsxs)(i,{spacing:2,sx:{textAlign:M,alignItems:N},children:[(T||E)&&(0,v.jsxs)(i,{spacing:.5,children:[T&&(0,v.jsx)(e,{variant:k,children:T}),E&&(0,v.jsx)(e,{variant:A,color:`text.secondary`,children:E})]}),F&&(0,v.jsx)(m,{href:F,target:I??`_self`,variant:`outlined`,size:`sm`,children:L}),D&&(0,v.jsx)(n,{sx:{...t,textAlign:`left`},dangerouslySetInnerHTML:{__html:D}})]})})})}export{y as VitecText};
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{C as e,D as t,S as n,Z as r,_ as i,b as a,c as o,d as s,h as c,i as l,k as u,l as d,m as f,n as p,p as m,s as h,t as g,u as _,v,w as y,y as b}from"./index-7LYai_r-.js";var x=r();function S({element:r,className:S,nested:C,devInfoTags:w,uid:T,spaceBefore:E,spaceAfter:D}){let O=o(r),k=s(r),A=h(r),j=Number(d(r)??0),M=v(j),N=b(j),P=i(_(r)),F=P===`center`?`center`:P===`right`?`right`:`left`,I=P===`center`?`center`:P===`right`?`flex-end`:`flex-start`,L=r.appearance?.frameClass?.split(`,`).map(e=>e.trim()).includes(`vitec-full-width`)??!1,R=m(r.content?.headerLink),z=c(r.content?.headerLink),B=f(r.content?.headerLink,`Mehr erfahren`),V=l(r.content?.gallery),H=r.content?.gallery?.position?.horizontal,U=V.length>0&&(H===`right`||H===`left`),W=H!==`left`,G=(r.content?.gallery?.width??480)>=600?5:4;return(0,x.jsx)(p,{className:S,devInfoTags:w,fullWidth:L,nested:C,uid:T,spaceBefore:E,spaceAfter:D,children:(0,x.jsx)(`div`,{className:`textpic__inner`,children:(0,x.jsxs)(y,{container:!0,spacing:3,alignItems:`start`,direction:W?`row`:`row-reverse`,children:[(0,x.jsx)(y,{size:{xs:12,md:U?12-G:12},children:(0,x.jsxs)(e,{spacing:2.5,children:[(0,x.jsxs)(e,{spacing:.5,sx:{width:`100%`,textAlign:F,alignItems:I},children:[(0,x.jsx)(u,{variant:M,children:O??`Untitled content`}),k&&(0,x.jsx)(u,{variant:N,color:`text.secondary`,children:k})]}),R&&(0,x.jsx)(n,{href:R,target:z??`_self`,variant:`outlined`,size:`sm`,alignStart:!0,children:B}),A&&(0,x.jsx)(t,{sx:{...a,textAlign:`left`},dangerouslySetInnerHTML:{__html:A}})]})}),V.length>0&&(0,x.jsx)(y,{size:{xs:12,md:U?G:12},children:(0,x.jsx)(g,{images:V})})]})})})}export{S as Textpic};
|
|
||||||
1
public/_frontend/assets/textpic-CaKZ2n8y.js
Normal file
1
public/_frontend/assets/textpic-CaKZ2n8y.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,C as t,E as n,O as r,S as i,T as a,_ as o,a as s,b as c,d as l,f as u,g as d,m as f,n as p,ot as m,p as h,r as g,t as _,u as v,v as y,x as b}from"./index-CM0zIqrs.js";var x=m();function S({element:m,className:S,nested:C,devInfoTags:w,uid:T,spaceBefore:E,spaceAfter:D}){let O=l(m),k=f(m),A=v(m),j=Number(u(m)??0),M=b(j),N=i(j),P=c(h(m)),F=P===`center`?`center`:P===`right`?`right`:`left`,I=P===`center`?`center`:P===`right`?`flex-end`:`flex-start`,L=m.appearance?.frameClass?.split(`,`).map(e=>e.trim()).includes(`vitec-full-width`)??!1,R=d(m.content?.headerLink),z=y(m.content?.headerLink),B=o(m.content?.headerLink,`Mehr erfahren`),V=s(m.content?.gallery),H=m.content?.gallery?.position?.horizontal,U=V.length>0&&(H===`right`||H===`left`),W=H!==`left`,G=(m.content?.gallery?.width??480)>=600?5:4;return(0,x.jsx)(g,{className:S,devInfoTags:w,fullWidth:L,nested:C,uid:T,spaceBefore:E,spaceAfter:D,children:(0,x.jsx)(`div`,{className:`textpic__inner`,children:(0,x.jsxs)(n,{container:!0,spacing:3,alignItems:`start`,direction:W?`row`:`row-reverse`,children:[(0,x.jsx)(n,{size:{xs:12,md:U?12-G:12},children:(0,x.jsxs)(a,{spacing:2.5,children:[(0,x.jsxs)(a,{spacing:.5,sx:{width:`100%`,textAlign:F,alignItems:I},children:[(0,x.jsx)(e,{variant:M,children:O??`Untitled content`}),k&&(0,x.jsx)(e,{variant:N,color:`text.secondary`,children:k})]}),R&&(0,x.jsx)(_,{href:R,target:z??`_self`,variant:`outlined`,size:`sm`,alignStart:!0,children:B}),A&&(0,x.jsx)(r,{sx:{...t,textAlign:`left`},dangerouslySetInnerHTML:{__html:A}})]})}),V.length>0&&(0,x.jsx)(n,{size:{xs:12,md:U?G:12},children:(0,x.jsx)(p,{images:V})})]})})})}export{S as Textpic};
|
||||||
1
public/_frontend/assets/useControlled-CztbT67m.js
Normal file
1
public/_frontend/assets/useControlled-CztbT67m.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{mt as e,ut as t}from"./index-CM0zIqrs.js";var n=e(t());function r(e){let{controlled:t,default:r,name:i,state:a=`value`}=e,{current:o}=n.useRef(t!==void 0),[s,c]=n.useState(r);return[o?t:s,n.useCallback(e=>{o||c(e)},[])]}var i=r;export{i as t};
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{Q as e,tt as t}from"./index-7LYai_r-.js";var n=t(e());function r(e){let{controlled:t,default:r,name:i,state:a=`value`}=e,{current:o}=n.useRef(t!==void 0),[s,c]=n.useState(r);return[o?t:s,n.useCallback(e=>{o||c(e)},[])]}var i=r;export{i as t};
|
|
||||||
1
public/_frontend/assets/vitec_card-BzgUtAT9.js
Normal file
1
public/_frontend/assets/vitec_card-BzgUtAT9.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,C as t,O as n,T as r,_ as i,d as a,g as o,l as s,m as c,ot as l,r as u,t as d,u as f,v as p,y as m}from"./index-CM0zIqrs.js";var h=l();function g({element:l,className:g,nested:_,devInfoTags:v,uid:y,spaceBefore:b,spaceAfter:x}){let S=a(l),C=c(l),w=f(l),T=l.data?.eyebrow,E=l.data?.background_variant,D=l.data?.text_alignment??`left`,O=l.data?.layout_variant??`stacked`,k=l.data?.image_aspect_ratio??`auto`,A=l.data?.border_style??`none`,j=l.data?.shadow??`soft`,M=m(l.data?.button_style,`orange`),N=m(l.data?.secondary_button_style,`ghost`),P=(l.data?.icon?.length?l.data.icon:l.data?.image)??[],F=P[0]?.publicUrl,I=P[0]?.alt||P[0]?.title||S||``,L=o(l.data?.card_link),R=o(l.data?.primary_cta),z=p(l.data?.primary_cta),B=l.data?.primary_cta_label||i(l.data?.primary_cta,`Learn more`),V=o(l.data?.secondary_cta),H=p(l.data?.secondary_cta),U=l.data?.secondary_cta_label||i(l.data?.secondary_cta,`Learn more`),W=!!(R||V),G=O===`image_overlay`,K=O===`text_only`,q=[`graphite`,`midnight`,`orange`,`blue`,`dark`].includes(E??``),J=[`vitec_card__inner`,`vitec_card__inner--${O}`,q?`vitec_card__inner--dark-bg`:``,j===`none`?``:`vitec_card__inner--shadow-${j}`,A===`none`?``:`vitec_card__inner--border-${A}`].filter(Boolean).join(` `),Y=`vitec_card__media${k===`auto`?``:` vitec_card__media--${k}`}`,X=(0,h.jsxs)(`div`,{className:J,style:G&&F?{backgroundImage:`url(${F})`,backgroundSize:`cover`,backgroundPosition:`center`}:E&&E!==`none`?s(E):{},children:[F&&!K&&!G&&(0,h.jsx)(`div`,{className:Y,children:(0,h.jsx)(`img`,{className:`vitec_card__image`,src:F,alt:I,loading:`lazy`})}),(0,h.jsxs)(`div`,{className:`vitec_card__body`,style:{textAlign:D},children:[(0,h.jsxs)(r,{spacing:.75,children:[T&&(0,h.jsx)(e,{variant:`overline`,className:`vitec_card__eyebrow`,children:T}),S&&(0,h.jsx)(e,{variant:`h5`,className:`vitec_card__header`,children:S}),C&&(0,h.jsx)(e,{variant:`subtitle2`,color:`text.secondary`,className:`vitec_card__subheader`,children:C}),w&&(0,h.jsx)(n,{className:`vitec_card__text`,sx:t,dangerouslySetInnerHTML:{__html:w}})]}),W&&(0,h.jsx)(`div`,{className:`vitec_card__footer`,children:(0,h.jsxs)(r,{direction:`column`,spacing:.75,children:[R&&(0,h.jsx)(d,{href:R,target:z??`_self`,variant:M,children:B}),V&&(0,h.jsx)(d,{href:V,target:H??`_self`,variant:N,children:U})]})})]})]}),Z=!!L;return(0,h.jsx)(u,{className:g,devInfoTags:v,nested:_,uid:y,spaceBefore:b,spaceAfter:x,children:Z?Z&&!W?(0,h.jsx)(`a`,{className:`vitec_card__link-wrap`,href:L,"aria-label":S??void 0,children:X}):(0,h.jsx)(`div`,{className:`vitec_card__link-wrap vitec_card__link-wrap--div`,role:`link`,tabIndex:0,onClick:()=>{window.location.href=L},onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(window.location.href=L)},children:X}):X})}export{g as VitecCard};
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{C as e,D as t,S as n,Z as r,b as i,c as a,d as o,g as s,h as c,k as l,m as u,n as d,o as f,p,s as m}from"./index-7LYai_r-.js";var h=r();function g({element:r,className:g,nested:_,devInfoTags:v,uid:y,spaceBefore:b,spaceAfter:x}){let S=a(r),C=o(r),w=m(r),T=r.data?.eyebrow,E=r.data?.background_variant,D=r.data?.text_alignment??`left`,O=r.data?.layout_variant??`stacked`,k=r.data?.image_aspect_ratio??`auto`,A=r.data?.border_style??`none`,j=r.data?.shadow??`soft`,M=s(r.data?.button_style,`orange`),N=s(r.data?.secondary_button_style,`ghost`),P=(r.data?.icon?.length?r.data.icon:r.data?.image)??[],F=P[0]?.publicUrl,I=P[0]?.alt||P[0]?.title||S||``,L=p(r.data?.card_link),R=p(r.data?.primary_cta),z=c(r.data?.primary_cta),B=r.data?.primary_cta_label||u(r.data?.primary_cta,`Learn more`),V=p(r.data?.secondary_cta),H=c(r.data?.secondary_cta),U=r.data?.secondary_cta_label||u(r.data?.secondary_cta,`Learn more`),W=!!(R||V),G=O===`image_overlay`,K=O===`text_only`,q=[`graphite`,`midnight`,`orange`,`blue`,`dark`].includes(E??``),J=[`vitec_card__inner`,`vitec_card__inner--${O}`,q?`vitec_card__inner--dark-bg`:``,j===`none`?``:`vitec_card__inner--shadow-${j}`,A===`none`?``:`vitec_card__inner--border-${A}`].filter(Boolean).join(` `),Y=`vitec_card__media${k===`auto`?``:` vitec_card__media--${k}`}`,X=(0,h.jsxs)(`div`,{className:J,style:G&&F?{backgroundImage:`url(${F})`,backgroundSize:`cover`,backgroundPosition:`center`}:E&&E!==`none`?f(E):{},children:[F&&!K&&!G&&(0,h.jsx)(`div`,{className:Y,children:(0,h.jsx)(`img`,{className:`vitec_card__image`,src:F,alt:I,loading:`lazy`})}),(0,h.jsxs)(`div`,{className:`vitec_card__body`,style:{textAlign:D},children:[(0,h.jsxs)(e,{spacing:.75,children:[T&&(0,h.jsx)(l,{variant:`overline`,className:`vitec_card__eyebrow`,children:T}),S&&(0,h.jsx)(l,{variant:`h5`,className:`vitec_card__header`,children:S}),C&&(0,h.jsx)(l,{variant:`subtitle2`,color:`text.secondary`,className:`vitec_card__subheader`,children:C}),w&&(0,h.jsx)(t,{className:`vitec_card__text`,sx:i,dangerouslySetInnerHTML:{__html:w}})]}),W&&(0,h.jsx)(`div`,{className:`vitec_card__footer`,children:(0,h.jsxs)(e,{direction:`column`,spacing:.75,children:[R&&(0,h.jsx)(n,{href:R,target:z??`_self`,variant:M,children:B}),V&&(0,h.jsx)(n,{href:V,target:H??`_self`,variant:N,children:U})]})})]})]}),Z=!!L;return(0,h.jsx)(d,{className:g,devInfoTags:v,nested:_,uid:y,spaceBefore:b,spaceAfter:x,children:Z?Z&&!W?(0,h.jsx)(`a`,{className:`vitec_card__link-wrap`,href:L,"aria-label":S??void 0,children:X}):(0,h.jsx)(`div`,{className:`vitec_card__link-wrap vitec_card__link-wrap--div`,role:`link`,tabIndex:0,onClick:()=>{window.location.href=L},onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(window.location.href=L)},children:X}):X})}export{g as VitecCard};
|
|
||||||
File diff suppressed because one or more lines are too long
1
public/_frontend/assets/vitec_cards_carousel-Dt6LcIk8.js
Normal file
1
public/_frontend/assets/vitec_cards_carousel-Dt6LcIk8.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
import{C as e,O as t,Q as n,Z as r,_ as i,c as a,d as o,k as s,n as c,u as l,w as u,x as d}from"./index-7LYai_r-.js";var f=n(),p=r();function m({element:n,nested:r,devInfoTags:m,uid:h,renderElement:g,columnSpans:_,spaceBefore:v,spaceAfter:y}){let b=n.headerLayout??n.data?.header_layout??n.content?.headerLayout,x=b===100?void 0:a(n),S=b===100?void 0:o(n),C=i(l(n)),w=C===`center`?`center`:C===`right`?`right`:`left`,T=C===`center`?`center`:C===`right`?`flex-end`:`flex-start`,E=n.appearance?.frameClass?.split(`,`).map(e=>e.trim()).includes(`vitec-full-width`)??!1,D=d(),O=n.type??`vitec_cols`,k=n.data?.tx_vitec_gap??n.gap??`3`,A=`${Math.min(5,Math.max(1,parseInt(k,10)))}rem`;return(0,p.jsx)(c,{className:O,devInfoTags:m,fullWidth:E,nested:r,uid:h,spaceBefore:v,spaceAfter:y,children:(0,p.jsxs)(`div`,{className:`${O}__inner`,children:[(x||S)&&(0,p.jsxs)(e,{spacing:.5,sx:{width:`100%`,textAlign:w,alignItems:T},children:[x&&(0,p.jsx)(s,{variant:`h5`,children:x}),S&&(0,p.jsx)(s,{variant:`subtitle1`,color:`text.secondary`,children:S})]}),(0,p.jsx)(u,{container:!0,spacing:A,children:n.items?.map((r,i)=>{let a=_[i]??Math.max(1,Math.floor(12/Math.max(n.items?.length??1,1))),o=r.config?.align||`stretch`,s=r.config?.justify||`flex-start`;return(0,p.jsx)(u,{size:{xs:12,md:a},sx:{alignSelf:o},children:(0,p.jsxs)(e,{spacing:1.5,children:[D&&(0,p.jsx)(t,{label:`TYPO3 slot: colPos${r.config?.colPos??i}`,size:`small`,variant:`outlined`,sx:{width:`fit-content`,height:22,"& .MuiChip-label":{px:.75,fontSize:`0.68rem`}}}),(0,p.jsx)(e,{spacing:2,sx:{justifyContent:s},children:r.contentElements?.map(e=>{let t=`${e.id??e.type??`nested`}-${r.config?.colPos??i}`;return(0,p.jsx)(f.Fragment,{children:g(e,!0)},t)})})]})},`${n.id??n.type??`grid`}-${r.config?.colPos??i}`)})})]})})}export{m as VitecCols};
|
|
||||||
1
public/_frontend/assets/vitec_cols-DMOC1vMA.js
Normal file
1
public/_frontend/assets/vitec_cols-DMOC1vMA.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,E as t,O as n,T as r,b as i,d as a,k as o,l as s,m as c,ot as l,p as u,r as d,ut as f,w as p}from"./index-CM0zIqrs.js";var m=f(),h=l();function g({element:l,nested:f,devInfoTags:g,uid:_,className:v,renderElement:y,columnSpans:b,slotColPos:x,spaceBefore:S,spaceAfter:C}){let w=l.headerLayout??l.data?.header_layout??l.content?.headerLayout,T=w===100?void 0:a(l),E=w===100?void 0:c(l),D=i(u(l)),O=D===`center`?`center`:D===`right`?`right`:`left`,k=D===`center`?`center`:D===`right`?`flex-end`:`flex-start`,A=l.appearance?.frameClass?.split(`,`).map(e=>e.trim()).includes(`vitec-full-width`)??!1,j=p(),M=l.type??`vitec_cols`,N=l.tx_vitec_bg_variant,P=!!(N&&N!==`none`),F=P?s(N):{},I=l.data?.tx_vitec_gap??l.gap??`3`,L=`${Math.min(5,Math.max(1,parseInt(I,10)))}rem`,R=e=>({config:{colPos:e},contentElements:[]}),z=new Map((l.items??[]).map(e=>[e.config?.colPos??-1,e])),B;if(x&&x.length===b.length)B=x.map(e=>z.get(e)??R(e));else{let e=[...l.items??[]].sort((e,t)=>(e.config?.colPos??0)-(t.config?.colPos??0)),t=Math.max(0,b.length-e.length);B=[...e,...Array.from({length:t},(e,t)=>R(-(t+1)))]}return(0,h.jsx)(d,{className:v??M,devInfoTags:g,fullWidth:A,nested:f,uid:_,spaceBefore:S,spaceAfter:C,children:(0,h.jsx)(`div`,{className:`${M}__inner`,children:(0,h.jsxs)(n,{sx:{...F,...P?{borderRadius:3,px:{xs:2.5,md:4},py:{xs:3,md:3.5},"& p, & h1, & h2, & h3, & h4, & h5, & h6, & .MuiTypography-root":{color:`inherit`}}:{}},children:[(T||E)&&(0,h.jsxs)(r,{spacing:.5,sx:{width:`100%`,mb:2,textAlign:O,alignItems:k},children:[T&&(0,h.jsx)(e,{variant:`h5`,children:T}),E&&(0,h.jsx)(e,{variant:`subtitle1`,color:`text.secondary`,children:E})]}),(0,h.jsx)(t,{container:!0,spacing:L,children:B.map((e,n)=>{let i=b[n]??Math.max(1,Math.floor(12/Math.max(B.length,1))),a=e.config?.align||`stretch`,s=e.config?.justify||`flex-start`;return(0,h.jsx)(t,{size:{xs:12,md:i},sx:{alignSelf:a},children:(0,h.jsxs)(r,{spacing:1.5,children:[j&&(0,h.jsx)(o,{label:e.config?.colPos<0?`TYPO3 slot: empty`:`TYPO3 slot: colPos${e.config?.colPos??n}`,size:`small`,variant:`outlined`,sx:{width:`fit-content`,height:22,"& .MuiChip-label":{px:.75,fontSize:`0.68rem`}}}),(0,h.jsx)(r,{spacing:2,sx:{justifyContent:s},children:e.contentElements?.map(t=>{let r=`${t.id??t.type??`nested`}-${e.config?.colPos??n}`;return(0,h.jsx)(m.Fragment,{children:y(t,!0)},r)})})]})},`${l.id??l.type??`grid`}-${e.config?.colPos??n}`)})})]})})})}export{g as VitecCols};
|
||||||
1
public/_frontend/assets/vitec_columns-CdE2Ajho.js
Normal file
1
public/_frontend/assets/vitec_columns-CdE2Ajho.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{ot as e,r as t}from"./index-CM0zIqrs.js";var n=e();function r(e){if(e?.length)return e.map(e=>`${e.url} ${e.descriptor}`).join(`, `)}function i({item:e}){return e.type===`image`&&e.image?.url?(0,n.jsxs)(`div`,{className:`vitec_columns__item vitec_columns__item--image`,children:[(0,n.jsx)(`img`,{className:`vitec_columns__image`,src:e.image.url,srcSet:r(e.image.srcset),sizes:`(max-width: 899px) 100vw, 50vw`,alt:e.image.alternative||e.headline||``,loading:`lazy`}),e.headline&&(0,n.jsx)(`p`,{className:`vitec_columns__item-caption`,children:e.headline})]}):e.type===`text`?(0,n.jsxs)(`div`,{className:`vitec_columns__item vitec_columns__item--text`,children:[e.headline&&(0,n.jsx)(`h3`,{className:`vitec_columns__item-headline`,children:e.headline}),e.text&&(0,n.jsx)(`div`,{className:`vitec_columns__item-body`,dangerouslySetInnerHTML:{__html:e.text}}),e.link&&e.linkLabel&&(0,n.jsx)(`a`,{className:`vitec_columns__item-link`,href:e.link,children:e.linkLabel})]}):null}function a({element:e,className:r,nested:a,devInfoTags:o,uid:s,spaceBefore:c,spaceAfter:l}){let u=e,d=u.columns,f=u.layout??`cols_50_50`,p=d?.left??[],m=d?.right??[];return!p.length&&!m.length?null:(0,n.jsx)(t,{className:r,devInfoTags:o,nested:a,uid:s,spaceBefore:c,spaceAfter:l,children:(0,n.jsxs)(`div`,{className:`vitec_columns vitec_columns--${f.replace(/_/g,`-`)}`,children:[p.length>0&&(0,n.jsx)(`div`,{className:`vitec_columns__col vitec_columns__col--left`,children:p.map((e,t)=>(0,n.jsx)(i,{item:e},t))}),m.length>0&&(0,n.jsx)(`div`,{className:`vitec_columns__col vitec_columns__col--right`,children:m.map((e,t)=>(0,n.jsx)(i,{item:e},t))})]})})}export{a as VitecColumns};
|
||||||
1
public/_frontend/assets/vitec_container-CeBDSayn.js
Normal file
1
public/_frontend/assets/vitec_container-CeBDSayn.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,T as t,d as n,l as r,m as i,ot as a,r as o,ut as s}from"./index-CM0zIqrs.js";var c=s(),l=a();function u({element:a,nested:s,devInfoTags:u,uid:d,spaceBefore:f,spaceAfter:p,className:m,renderElement:h}){let g=n(a),_=i(a),v=a.tx_vitec_bg_variant,y=!!(v&&v!==`none`),b=r(v),x=[`vitec_container`,a.cssClass,m].filter(Boolean).join(` `),S=a.items?.flatMap(e=>e.contentElements??[])??[];return(0,l.jsx)(o,{className:x,devInfoTags:u,fullWidth:y&&!s,nested:s,uid:d,spaceBefore:f,spaceAfter:p,style:y?{background:b.background,color:b.color}:void 0,children:(0,l.jsx)(`div`,{className:`vitec_container__inner`,children:(0,l.jsxs)(`div`,{className:y?`vitec-content-box vitec_container__content`:`vitec_container__content`,children:[(g||_)&&(0,l.jsxs)(t,{spacing:.5,sx:{mb:2.5},children:[g&&(0,l.jsx)(e,{variant:`h4`,children:g}),_&&(0,l.jsx)(e,{variant:`subtitle1`,sx:y?{color:`rgba(var(--vitec-near-white), 0.65)`}:{color:`text.secondary`},children:_})]}),(0,l.jsx)(t,{spacing:2,children:S.map(e=>(0,l.jsx)(c.Fragment,{children:h(e,!0)},`${e.id??e.type}-${e.colPos}`))})]})})})}export{u as VitecContainer};
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{C as e,D as t,Q as n,Z as r,c as i,d as a,k as o,n as s,o as c}from"./index-7LYai_r-.js";var l=n(),u=r();function d({element:n,nested:r,devInfoTags:d,uid:f,spaceBefore:p,spaceAfter:m,className:h,renderElement:g}){let _=i(n),v=a(n),y=n.tx_vitec_bg_variant,b=!!(y&&y!==`none`),x=b?c(y):{},S=[`vitec_container`,n.cssClass,h].filter(Boolean).join(` `),C=n.items?.flatMap(e=>e.contentElements??[])??[];return(0,u.jsx)(s,{className:S,devInfoTags:d,nested:r,uid:f,spaceBefore:p,spaceAfter:m,children:(0,u.jsx)(`div`,{className:`vitec_container__inner`,children:(0,u.jsxs)(t,{sx:{...x,...b?{borderRadius:3,px:{xs:2.5,md:4},py:{xs:3,md:3.5}}:{},"& p, & h1, & h2, & h3, & h4, & h5, & h6, & .MuiTypography-root":{color:`inherit`}},children:[(_||v)&&(0,u.jsxs)(e,{spacing:.5,sx:{mb:2.5},children:[_&&(0,u.jsx)(o,{variant:`h4`,children:_}),v&&(0,u.jsx)(o,{variant:`subtitle1`,color:`text.secondary`,children:v})]}),(0,u.jsx)(e,{spacing:2,children:C.map(e=>(0,u.jsx)(l.Fragment,{children:g(e,!0)},`${e.id??e.type}-${e.colPos}`))})]})})})}export{d as VitecContainer};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{C as e,D as t,S as n,Z as r,b as i,c as a,f as o,g as s,h as c,k as l,m as u,n as d,o as f,p,s as m,w as h}from"./index-7LYai_r-.js";var g=r();function _({element:r,className:_,nested:v,devInfoTags:y,uid:b,spaceBefore:x,spaceAfter:S}){let C=a(r),w=m(r),T=f(r.data?.background_variant),E=o(r.data?.background_image),D=o(r.data?.icon),O=p(r.data?.primary_cta),k=c(r.data?.primary_cta),A=p(r.data?.secondary_cta),j=c(r.data?.secondary_cta),M=r.data?.layout_variant??`stacked`,N=s(r.data?.button_style,`light`),P=s(r.data?.secondary_button_style,`ghost`),F=r.appearance?.frameClass?.split(`,`).map(e=>e.trim()).includes(`vitec-full-width`)??!1,I=M===`centered`,L=M===`split`,R=M===`compact`,z=M===`feature`,B=M===`icon_card`,V=R?{px:{xs:2,md:3},py:{xs:1.5,md:2}}:z?{px:{xs:3,md:5},py:{xs:4,md:5}}:{px:{xs:2.5,md:4},py:{xs:3,md:3.5}},H=R?120:z?320:200,U=z?`h3`:R?`h5`:`h4`,W=(0,g.jsxs)(e,{direction:L?`column`:{xs:`column`,sm:`row`},spacing:1.25,alignItems:I?`center`:void 0,children:[O&&(0,g.jsx)(n,{href:O,target:k??`_self`,variant:N,children:r.data?.primary_cta_label||u(r.data?.primary_cta,`Primary CTA`)}),A&&(0,g.jsx)(n,{href:A,target:j??`_self`,variant:P,children:r.data?.secondary_cta_label||u(r.data?.secondary_cta,`Secondary CTA`)})]});return(0,g.jsx)(d,{className:_,devInfoTags:y,fullWidth:F,nested:v,uid:b,spaceBefore:x,spaceAfter:S,children:(0,g.jsx)(`div`,{className:`vitec_ctabanner__inner vitec_ctabanner--${M}`,children:(0,g.jsxs)(t,{sx:{...T,position:`relative`,overflow:`hidden`,borderRadius:3,...V,minHeight:H},children:[E&&M!==`text_only`&&(0,g.jsx)(t,{sx:{position:`absolute`,inset:0,backgroundImage:`linear-gradient(90deg, rgba(var(--vitec-surface-dark), 0.9), rgba(var(--vitec-surface-dark), 0.45)), url(${E})`,backgroundSize:`cover`,backgroundPosition:`center`,opacity:.9}}),L?(0,g.jsxs)(h,{container:!0,spacing:4,alignItems:`center`,sx:{position:`relative`,zIndex:1},children:[(0,g.jsx)(h,{size:{xs:12,md:7},children:(0,g.jsxs)(e,{spacing:1.5,children:[C&&(0,g.jsx)(l,{variant:U,children:C}),w&&(0,g.jsx)(t,{sx:i,dangerouslySetInnerHTML:{__html:w}})]})}),(0,g.jsx)(h,{size:{xs:12,md:5},children:W})]}):(0,g.jsxs)(e,{spacing:R?1.5:2,sx:{position:`relative`,zIndex:1,maxWidth:I||z?760:640,textAlign:I?`center`:`left`,alignItems:I?`center`:`flex-start`,mx:I?`auto`:void 0},children:[B&&D&&(0,g.jsx)(t,{component:`img`,src:D,alt:``,sx:{height:48,width:`auto`,objectFit:`contain`}}),C&&(0,g.jsx)(l,{variant:U,children:C}),w&&(0,g.jsx)(t,{sx:i,dangerouslySetInnerHTML:{__html:w}}),W]})]})})})}export{_ as VitecCtaBanner};
|
|
||||||
1
public/_frontend/assets/vitec_ctabanner-VXQKSyqL.js
Normal file
1
public/_frontend/assets/vitec_ctabanner-VXQKSyqL.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,C as t,E as n,O as r,T as i,_ as a,d as o,g as s,h as c,l,m as u,ot as d,r as f,t as p,u as m,v as h,y as g}from"./index-CM0zIqrs.js";var _=d();function v({element:d,className:v,nested:y,devInfoTags:b,uid:x,spaceBefore:S,spaceAfter:C}){let w=o(d),T=u(d),E=m(d),D=l(d.data?.background_variant),O=c(d.data?.background_image),k=c(d.data?.icon),A=s(d.data?.primary_cta),j=h(d.data?.primary_cta),M=s(d.data?.secondary_cta),N=h(d.data?.secondary_cta),P=d.data?.layout_variant??`stacked`,F=g(d.data?.button_style,`light`),I=g(d.data?.secondary_button_style,`ghost`),L=d.appearance?.frameClass?.split(`,`).map(e=>e.trim()).includes(`vitec-full-width`)??!1,R=P===`centered`,z=P===`split`,B=P===`compact`,V=P===`feature`,H=P===`icon_card`,U=B?{px:{xs:2,md:3},py:{xs:1.5,md:2}}:V?{px:{xs:3,md:5},py:{xs:4,md:5}}:{px:{xs:2.5,md:4},py:{xs:3,md:3.5}},W=B?120:V?320:200,G=V?`h3`:B?`h5`:`h4`,K=(0,_.jsxs)(i,{direction:z?`column`:{xs:`column`,sm:`row`},spacing:1.25,alignItems:R?`center`:void 0,children:[A&&(0,_.jsx)(p,{href:A,target:j??`_self`,variant:F,children:d.data?.primary_cta_label||a(d.data?.primary_cta,`Primary CTA`)}),M&&(0,_.jsx)(p,{href:M,target:N??`_self`,variant:I,children:d.data?.secondary_cta_label||a(d.data?.secondary_cta,`Secondary CTA`)})]});return(0,_.jsx)(f,{className:v,devInfoTags:b,fullWidth:L,nested:y,uid:x,spaceBefore:S,spaceAfter:C,children:(0,_.jsx)(`div`,{className:`vitec_ctabanner__inner vitec_ctabanner--${P}`,children:(0,_.jsxs)(r,{sx:{...D,position:`relative`,overflow:`hidden`,borderRadius:3,...U,minHeight:W},children:[O&&P!==`text_only`&&(0,_.jsx)(r,{sx:{position:`absolute`,inset:0,backgroundImage:`linear-gradient(90deg, rgba(var(--vitec-surface-dark), 0.9), rgba(var(--vitec-surface-dark), 0.45)), url(${O})`,backgroundSize:`cover`,backgroundPosition:`center`,opacity:.9}}),z?(0,_.jsxs)(n,{container:!0,spacing:4,alignItems:`center`,sx:{position:`relative`,zIndex:1},children:[(0,_.jsx)(n,{size:{xs:12,md:7},children:(0,_.jsxs)(i,{spacing:1.5,children:[w&&(0,_.jsx)(e,{variant:G,children:w}),T&&(0,_.jsx)(e,{variant:`subtitle1`,sx:{opacity:.85},children:T}),E&&(0,_.jsx)(r,{sx:t,dangerouslySetInnerHTML:{__html:E}})]})}),(0,_.jsx)(n,{size:{xs:12,md:5},children:K})]}):(0,_.jsxs)(i,{spacing:B?1.5:2,sx:{position:`relative`,zIndex:1,maxWidth:R||V?760:640,textAlign:R?`center`:`left`,alignItems:R?`center`:`flex-start`,mx:R?`auto`:void 0},children:[H&&k&&(0,_.jsx)(r,{component:`img`,src:k,alt:``,sx:{height:48,width:`auto`,objectFit:`contain`}}),w&&(0,_.jsx)(e,{variant:G,children:w}),T&&(0,_.jsx)(e,{variant:`subtitle1`,sx:{opacity:.85},children:T}),E&&(0,_.jsx)(r,{sx:t,dangerouslySetInnerHTML:{__html:E}}),K]})]})})})}export{v as VitecCtaBanner};
|
||||||
1
public/_frontend/assets/vitec_customerlogos-Dj1_aotY.js
Normal file
1
public/_frontend/assets/vitec_customerlogos-Dj1_aotY.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
public/_frontend/assets/vitec_datasheets-Cp-zTFxi.js
Normal file
1
public/_frontend/assets/vitec_datasheets-Cp-zTFxi.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
import{T as e,Z as t,n}from"./index-7LYai_r-.js";var r=t();function i({className:t,nested:i,devInfoTags:a,uid:o,spaceBefore:s,spaceAfter:c}){return(0,r.jsx)(n,{className:t,devInfoTags:a,nested:i,uid:o,spaceBefore:s,spaceAfter:c,children:(0,r.jsx)(`div`,{className:`vitec_divider__inner`,children:(0,r.jsx)(e,{})})})}export{i as VitecDivider};
|
|
||||||
1
public/_frontend/assets/vitec_divider-o_0oeIC9.js
Normal file
1
public/_frontend/assets/vitec_divider-o_0oeIC9.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{D as e,ot as t,r as n}from"./index-CM0zIqrs.js";var r=t();function i({className:t,nested:i,devInfoTags:a,uid:o,spaceBefore:s,spaceAfter:c}){return(0,r.jsx)(n,{className:t,devInfoTags:a,nested:i,uid:o,spaceBefore:s,spaceAfter:c,children:(0,r.jsx)(`div`,{className:`vitec_divider__inner`,children:(0,r.jsx)(e,{})})})}export{i as VitecDivider};
|
||||||
1
public/_frontend/assets/vitec_downloadcard-D2j-JEJt.js
Normal file
1
public/_frontend/assets/vitec_downloadcard-D2j-JEJt.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,J as t,O as n,T as r,c as i,d as a,ot as o,r as s}from"./index-CM0zIqrs.js";var c=o(),l=e=>e?e>=1024*1024?`${(e/(1024*1024)).toFixed(1)} MB`:`${Math.round(e/1024)} KB`:``,u={brochure:{background:`linear-gradient(135deg, rgba(var(--vitec-graphite), 1) 0%, rgba(var(--vitec-graphite-mid), 1) 100%)`,color:`#fff`},datasheet:{background:`linear-gradient(135deg, rgba(var(--vitec-brand), 1) 0%, rgba(var(--vitec-navy-deep), 1) 100%)`,color:`#fff`},neutral:{background:`rgba(var(--vitec-surface-light, 245 246 248), 1)`,color:`inherit`}},d={brochure:`Brochure`,datasheet:`Datasheet`,neutral:`Download`};function f(e){return e===`brochure`?`brochure`:e===`datasheet`?`datasheet`:`neutral`}function p({element:o,className:p,nested:h,devInfoTags:g,uid:_,spaceBefore:v,spaceAfter:y}){let b=o.content?.downloadcard,x=o.data?.downloadcard,S=b?.download??x?.download,C=f((x?.settings??b?.settings)?.layout),w=u[C],T=d[C],E=a(o)||S?.title,D=S?.file,O=D?.url?t(D.url,i.base_url,i.router_mode):void 0,k=D?.thumbnail?t(D.thumbnail,i.base_url,i.router_mode):void 0,A=l(D?.size),j=C!==`neutral`;return(0,c.jsx)(s,{className:p,devInfoTags:g,nested:h,uid:_,spaceBefore:v,spaceAfter:y,children:(0,c.jsxs)(n,{component:`a`,href:O??`#`,target:`_blank`,rel:`noreferrer noopener`,"aria-label":E??`Download`,className:`vitec_downloadcard vitec_downloadcard--${C}`,sx:{display:`flex`,textDecoration:`none`,color:`inherit`,borderRadius:`0.75rem`,overflow:`hidden`,boxShadow:`0 0.125rem 0.75rem rgba(0,0,0,0.08)`,minHeight:`9rem`,transition:`box-shadow 0.2s ease, transform 0.2s ease`,"&:hover":{boxShadow:`0 0.5rem 1.75rem rgba(0,0,0,0.15)`,transform:`translateY(-0.125rem)`}},children:[(0,c.jsx)(n,{sx:{width:`38%`,flexShrink:0,bgcolor:`#fff`,display:`flex`,alignItems:`center`,justifyContent:`center`,p:k?0:`1rem`,overflow:`hidden`},children:k?(0,c.jsx)(n,{component:`img`,src:k,alt:``,loading:`lazy`,sx:{width:`100%`,height:`100%`,objectFit:`contain`,objectPosition:`top center`,display:`block`,p:`0.75rem`}}):(0,c.jsx)(n,{sx:{color:`text.disabled`,opacity:.4},children:(0,c.jsxs)(`svg`,{width:`40`,height:`40`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`1.25`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[(0,c.jsx)(`path`,{d:`M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z`}),(0,c.jsx)(`polyline`,{points:`14 2 14 8 20 8`})]})})}),(0,c.jsxs)(n,{sx:{flex:1,...w,display:`flex`,flexDirection:`column`,justifyContent:`space-between`,p:`1.25rem 1.25rem 1rem`,gap:`0.5rem`},children:[(0,c.jsxs)(r,{direction:`row`,alignItems:`center`,spacing:1,children:[(0,c.jsx)(e,{component:`span`,sx:{fontSize:`0.6875rem`,fontWeight:700,letterSpacing:`0.06em`,textTransform:`uppercase`,opacity:j?.85:.6,whiteSpace:`nowrap`,color:`inherit`},children:T}),(0,c.jsx)(n,{sx:{flex:1,height:`1px`,bgcolor:j?`rgba(255,255,255,0.3)`:`rgba(0,0,0,0.15)`}})]}),E&&(0,c.jsx)(e,{variant:`h6`,sx:{fontWeight:600,lineHeight:1.25,fontSize:`clamp(0.9375rem, 2vw, 1.25rem)`,color:`inherit`,flex:1},children:E}),(0,c.jsx)(r,{direction:`row`,alignItems:`center`,spacing:.625,sx:{mt:`auto`},children:C===`neutral`?(0,c.jsxs)(n,{component:`span`,sx:{display:`inline-flex`,alignItems:`center`,gap:`0.375rem`,fontSize:`0.8125rem`,fontWeight:600,px:`0.875rem`,py:`0.4375rem`,borderRadius:`0.375rem`,border:`1.5px solid currentColor`,color:`rgba(var(--vitec-brand), 1)`},children:[(0,c.jsx)(m,{}),`Download`,A&&(0,c.jsxs)(e,{component:`span`,variant:`caption`,sx:{opacity:.6,ml:.25},children:[`(`,A,`)`]})]}):(0,c.jsxs)(n,{component:`span`,sx:{display:`inline-flex`,alignItems:`center`,gap:`0.375rem`,fontSize:`0.8125rem`,fontWeight:600,color:j?`rgba(255,255,255,0.85)`:`inherit`,"&:hover":{color:j?`#fff`:`inherit`}},children:[(0,c.jsx)(m,{}),`Download`,A&&(0,c.jsxs)(e,{component:`span`,variant:`caption`,sx:{opacity:.6,ml:.25},children:[`(`,A,`)`]})]})})]})]})})}function m(){return(0,c.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2.5`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[(0,c.jsx)(`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`}),(0,c.jsx)(`polyline`,{points:`7 10 12 15 17 10`}),(0,c.jsx)(`line`,{x1:`12`,y1:`15`,x2:`12`,y2:`3`})]})}export{p as VitecDownloadCard};
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{C as e,D as t,V as n,Z as r,a as i,c as a,k as o,n as s}from"./index-7LYai_r-.js";var c=r(),l=e=>e?e>=1024*1024?`${(e/(1024*1024)).toFixed(1)} MB`:`${Math.round(e/1024)} KB`:``,u={brochure:{background:`linear-gradient(135deg, rgba(var(--vitec-orange), 1) 0%, rgba(var(--vitec-orange-dark), 1) 100%)`,color:`#fff`},datasheet:{background:`linear-gradient(135deg, rgba(var(--vitec-brand), 1) 0%, rgba(var(--vitec-navy-deep), 1) 100%)`,color:`#fff`},neutral:{background:`rgba(var(--vitec-surface-light, 245 246 248), 1)`,color:`inherit`}},d={brochure:`Brochure`,datasheet:`Datasheet`,neutral:`Download`};function f(e){return e===`brochure`?`brochure`:e===`datasheet`?`datasheet`:`neutral`}function p({element:r,className:p,nested:h,devInfoTags:g,uid:_,spaceBefore:v,spaceAfter:y}){let b=r.content?.downloadcard,x=r.data?.downloadcard,S=b?.download??x?.download,C=f((x?.settings??b?.settings)?.layout),w=u[C],T=d[C],E=a(r)||S?.title,D=S?.file,O=D?.url?n(D.url,i.base_url,i.router_mode):void 0,k=D?.thumbnail?n(D.thumbnail,i.base_url,i.router_mode):void 0,A=l(D?.size),j=C!==`neutral`;return(0,c.jsx)(s,{className:p,devInfoTags:g,nested:h,uid:_,spaceBefore:v,spaceAfter:y,children:(0,c.jsxs)(t,{component:`a`,href:O??`#`,target:`_blank`,rel:`noreferrer noopener`,"aria-label":E??`Download`,className:`vitec_downloadcard vitec_downloadcard--${C}`,sx:{display:`flex`,textDecoration:`none`,color:`inherit`,borderRadius:`0.75rem`,overflow:`hidden`,boxShadow:`0 0.125rem 0.75rem rgba(0,0,0,0.08)`,minHeight:`9rem`,transition:`box-shadow 0.2s ease, transform 0.2s ease`,"&:hover":{boxShadow:`0 0.5rem 1.75rem rgba(0,0,0,0.15)`,transform:`translateY(-0.125rem)`}},children:[(0,c.jsx)(t,{sx:{width:`38%`,flexShrink:0,bgcolor:`#fff`,display:`flex`,alignItems:`center`,justifyContent:`center`,p:k?0:`1rem`,overflow:`hidden`},children:k?(0,c.jsx)(t,{component:`img`,src:k,alt:``,loading:`lazy`,sx:{width:`100%`,height:`100%`,objectFit:`contain`,objectPosition:`top center`,display:`block`,p:`0.75rem`}}):(0,c.jsx)(t,{sx:{color:`text.disabled`,opacity:.4},children:(0,c.jsxs)(`svg`,{width:`40`,height:`40`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`1.25`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[(0,c.jsx)(`path`,{d:`M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z`}),(0,c.jsx)(`polyline`,{points:`14 2 14 8 20 8`})]})})}),(0,c.jsxs)(t,{sx:{flex:1,...w,display:`flex`,flexDirection:`column`,justifyContent:`space-between`,p:`1.25rem 1.25rem 1rem`,gap:`0.5rem`},children:[(0,c.jsxs)(e,{direction:`row`,alignItems:`center`,spacing:1,children:[(0,c.jsx)(o,{component:`span`,sx:{fontSize:`0.6875rem`,fontWeight:700,letterSpacing:`0.06em`,textTransform:`uppercase`,opacity:j?.85:.6,whiteSpace:`nowrap`,color:`inherit`},children:T}),(0,c.jsx)(t,{sx:{flex:1,height:`1px`,bgcolor:j?`rgba(255,255,255,0.3)`:`rgba(0,0,0,0.15)`}})]}),E&&(0,c.jsx)(o,{variant:`h6`,sx:{fontWeight:600,lineHeight:1.25,fontSize:`clamp(0.9375rem, 2vw, 1.25rem)`,color:`inherit`,flex:1},children:E}),(0,c.jsx)(e,{direction:`row`,alignItems:`center`,spacing:.625,sx:{mt:`auto`},children:C===`neutral`?(0,c.jsxs)(t,{component:`span`,sx:{display:`inline-flex`,alignItems:`center`,gap:`0.375rem`,fontSize:`0.8125rem`,fontWeight:600,px:`0.875rem`,py:`0.4375rem`,borderRadius:`0.375rem`,border:`1.5px solid currentColor`,color:`rgba(var(--vitec-brand), 1)`},children:[(0,c.jsx)(m,{}),`Download`,A&&(0,c.jsxs)(o,{component:`span`,variant:`caption`,sx:{opacity:.6,ml:.25},children:[`(`,A,`)`]})]}):(0,c.jsxs)(t,{component:`span`,sx:{display:`inline-flex`,alignItems:`center`,gap:`0.375rem`,fontSize:`0.8125rem`,fontWeight:600,color:j?`rgba(255,255,255,0.85)`:`inherit`,"&:hover":{color:j?`#fff`:`inherit`}},children:[(0,c.jsx)(m,{}),`Download`,A&&(0,c.jsxs)(o,{component:`span`,variant:`caption`,sx:{opacity:.6,ml:.25},children:[`(`,A,`)`]})]})})]})]})})}function m(){return(0,c.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2.5`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[(0,c.jsx)(`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`}),(0,c.jsx)(`polyline`,{points:`7 10 12 15 17 10`}),(0,c.jsx)(`line`,{x1:`12`,y1:`15`,x2:`12`,y2:`3`})]})}export{p as VitecDownloadCard};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{A as e,C as t,D as n,Q as r,V as i,Z as a,a as o,c as s,k as c,n as l,tt as u}from"./index-7LYai_r-.js";import{t as d}from"./jszip.min-B_jfdBDa.js";var f=r(),p=u(d(),1),m=a(),h=`linear-gradient(135deg, rgba(var(--vitec-brand), 1) 0%, rgba(var(--vitec-navy-deep), 1) 100%)`;async function g(e,t){let n=new p.default;await Promise.all(e.map(async e=>{let t=e.file?.url;if(!t)return;let r=i(t,o.base_url,o.router_mode),a=await fetch(r);if(!a.ok)return;let s=await a.blob();n.file(e.file?.name??`download_${e.uid}.pdf`,s)}));let r=await n.generateAsync({type:`blob`}),a=URL.createObjectURL(r),s=document.createElement(`a`);s.href=a,s.download=t,s.click(),URL.revokeObjectURL(a)}function _({download:e}){let t=e.file,r=t?.url?i(t.url,o.base_url,o.router_mode):void 0,a=e.title??t?.name??`Download`;return(0,m.jsxs)(n,{component:`a`,href:r??`#`,target:`_blank`,rel:`noreferrer noopener`,sx:{display:`flex`,alignItems:`baseline`,gap:`0.4rem`,color:`rgba(255,255,255,0.85)`,textDecoration:`none`,fontSize:`0.8125rem`,lineHeight:1.4,"&:hover":{color:`#fff`,textDecoration:`underline`}},children:[(0,m.jsx)(n,{component:`span`,sx:{flexShrink:0,mt:`0.2em`,color:`rgba(var(--vitec-orange), 1)`,fontSize:`0.5rem`},children:`■`}),(0,m.jsx)(`span`,{children:a})]})}function v({downloads:t,zipName:r}){let[i,a]=(0,f.useState)(`idle`);return(0,m.jsxs)(n,{component:`button`,onClick:async e=>{if(e.preventDefault(),i!==`loading`){a(`loading`);try{await g(t,r),a(`idle`)}catch{a(`error`),setTimeout(()=>a(`idle`),3e3)}}},disabled:i===`loading`,sx:{display:`inline-flex`,alignItems:`center`,gap:`0.4rem`,alignSelf:`flex-start`,mt:`auto`,fontSize:`0.8125rem`,fontWeight:600,color:i===`error`?`rgba(255,180,180,1)`:`#fff`,background:`none`,border:`1.5px solid`,borderColor:i===`error`?`rgba(255,120,120,0.6)`:`rgba(255,255,255,0.5)`,borderRadius:`0.375rem`,px:`0.875rem`,py:`0.4375rem`,cursor:i===`loading`?`default`:`pointer`,transition:`border-color 0.15s, background 0.15s`,"&:hover:not(:disabled)":{borderColor:`#fff`,bgcolor:`rgba(255,255,255,0.1)`}},children:[i===`loading`?(0,m.jsx)(e,{size:12,sx:{color:`inherit`}}):(0,m.jsxs)(`svg`,{width:`12`,height:`12`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2.5`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[(0,m.jsx)(`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`}),(0,m.jsx)(`polyline`,{points:`7 10 12 15 17 10`}),(0,m.jsx)(`line`,{x1:`12`,y1:`15`,x2:`12`,y2:`3`})]}),i===`error`?`Download failed`:`Download All Documents (ZIP)`]})}function y({element:e,className:r,nested:a,devInfoTags:u,uid:d,spaceBefore:f,spaceAfter:p}){let g=e.content?.downloadcardcollection??e.data?.downloadcardcollection,y=g?.downloads??[],b=s(e),x=g?.image,S=x&&`publicUrl`in x?x.publicUrl:void 0,C=y[0]?.file?.thumbnail,w=S??(C?i(C,o.base_url,o.router_mode):void 0),T=y.filter(e=>e.file?.url),E=`${(b??`documents`).toLowerCase().replace(/\s+/g,`-`)}.zip`;return y.length===0?null:(0,m.jsx)(l,{className:r,devInfoTags:u,nested:a,uid:d,spaceBefore:f,spaceAfter:p,children:(0,m.jsxs)(n,{className:`vitec_downloadcardcollection`,sx:{display:`flex`,borderRadius:`0.75rem`,overflow:`hidden`,boxShadow:`0 0.125rem 0.75rem rgba(0,0,0,0.08)`,minHeight:`10rem`},children:[(0,m.jsx)(n,{sx:{width:`38%`,flexShrink:0,bgcolor:`#fff`,display:`flex`,alignItems:`center`,justifyContent:`center`,overflow:`hidden`,p:w?0:`1.5rem`},children:w?(0,m.jsx)(n,{component:`img`,src:w,alt:b??`Downloads`,loading:`lazy`,sx:{width:`100%`,height:`100%`,objectFit:`contain`,objectPosition:`top center`,display:`block`,p:`0.75rem`}}):(0,m.jsx)(n,{sx:{color:`text.disabled`,opacity:.3},children:(0,m.jsxs)(`svg`,{width:`48`,height:`48`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`1`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[(0,m.jsx)(`path`,{d:`M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z`}),(0,m.jsx)(`polyline`,{points:`14 2 14 8 20 8`}),(0,m.jsx)(`line`,{x1:`8`,y1:`13`,x2:`16`,y2:`13`}),(0,m.jsx)(`line`,{x1:`8`,y1:`17`,x2:`16`,y2:`17`}),(0,m.jsx)(`polyline`,{points:`10 9 9 9 8 9`})]})})}),(0,m.jsxs)(n,{sx:{flex:1,background:h,color:`#fff`,display:`flex`,flexDirection:`column`,p:`1.25rem 1.25rem 1rem`,gap:`0.75rem`},children:[(0,m.jsxs)(t,{direction:`row`,alignItems:`center`,spacing:1,children:[(0,m.jsx)(c,{component:`span`,sx:{fontSize:`0.6875rem`,fontWeight:700,letterSpacing:`0.06em`,textTransform:`uppercase`,opacity:.85,whiteSpace:`nowrap`,color:`inherit`},children:b??`Download Collection`}),(0,m.jsx)(n,{sx:{flex:1,height:`1px`,bgcolor:`rgba(255,255,255,0.3)`}})]}),(0,m.jsx)(t,{spacing:.375,sx:{flex:1},children:y.map(e=>(0,m.jsx)(_,{download:e},e.uid??e.slug??e.title))}),T.length>1&&(0,m.jsx)(v,{downloads:T,zipName:E})]})]})})}export{y as VitecDownloadCardCollection};
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,J as t,M as n,O as r,T as i,c as a,d as o,mt as s,ot as c,r as l,ut as u}from"./index-CM0zIqrs.js";import{t as d}from"./jszip.min-DxLKr7hR.js";var f=u(),p=s(d(),1),m=c(),h=`linear-gradient(135deg, rgba(var(--vitec-brand), 1) 0%, rgba(var(--vitec-navy-deep), 1) 100%)`;async function g(e,n){let r=new p.default;await Promise.all(e.map(async e=>{let n=e.file?.url;if(!n)return;let i=t(n,a.base_url,a.router_mode),o=await fetch(i);if(!o.ok)return;let s=await o.blob();r.file(e.file?.name??`download_${e.uid}.pdf`,s)}));let i=await r.generateAsync({type:`blob`}),o=URL.createObjectURL(i),s=document.createElement(`a`);s.href=o,s.download=n,s.click(),URL.revokeObjectURL(o)}function _({download:e}){let n=e.file,i=n?.url?t(n.url,a.base_url,a.router_mode):void 0,o=e.title??n?.name??`Download`;return(0,m.jsxs)(r,{component:`a`,href:i??`#`,target:`_blank`,rel:`noreferrer noopener`,sx:{display:`flex`,alignItems:`baseline`,gap:`0.4rem`,color:`rgba(255,255,255,0.85)`,textDecoration:`none`,fontSize:`0.8125rem`,lineHeight:1.4,"&:hover":{color:`#fff`,textDecoration:`underline`}},children:[(0,m.jsx)(r,{component:`span`,sx:{flexShrink:0,mt:`0.2em`,color:`rgba(var(--vitec-orange), 1)`,fontSize:`0.5rem`},children:`■`}),(0,m.jsx)(`span`,{children:o})]})}function v({downloads:e,zipName:t}){let[i,a]=(0,f.useState)(`idle`);return(0,m.jsxs)(r,{component:`button`,onClick:async n=>{if(n.preventDefault(),i!==`loading`){a(`loading`);try{await g(e,t),a(`idle`)}catch{a(`error`),setTimeout(()=>a(`idle`),3e3)}}},disabled:i===`loading`,sx:{display:`inline-flex`,alignItems:`center`,gap:`0.4rem`,alignSelf:`flex-start`,mt:`auto`,fontSize:`0.8125rem`,fontWeight:600,color:i===`error`?`rgba(255,180,180,1)`:`#fff`,background:`none`,border:`1.5px solid`,borderColor:i===`error`?`rgba(255,120,120,0.6)`:`rgba(255,255,255,0.5)`,borderRadius:`0.375rem`,px:`0.875rem`,py:`0.4375rem`,cursor:i===`loading`?`default`:`pointer`,transition:`border-color 0.15s, background 0.15s`,"&:hover:not(:disabled)":{borderColor:`#fff`,bgcolor:`rgba(255,255,255,0.1)`}},children:[i===`loading`?(0,m.jsx)(n,{size:12,sx:{color:`inherit`}}):(0,m.jsxs)(`svg`,{width:`12`,height:`12`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2.5`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[(0,m.jsx)(`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`}),(0,m.jsx)(`polyline`,{points:`7 10 12 15 17 10`}),(0,m.jsx)(`line`,{x1:`12`,y1:`15`,x2:`12`,y2:`3`})]}),i===`error`?`Download failed`:`Download All Documents (ZIP)`]})}function y({element:n,className:s,nested:c,devInfoTags:u,uid:d,spaceBefore:f,spaceAfter:p}){let g=n.content?.downloadcardcollection??n.data?.downloadcardcollection,y=g?.downloads??[],b=o(n),x=g?.image,S=x&&`publicUrl`in x?x.publicUrl:void 0,C=y[0]?.file?.thumbnail,w=S??(C?t(C,a.base_url,a.router_mode):void 0),T=y.filter(e=>e.file?.url),E=`${(b??`documents`).toLowerCase().replace(/\s+/g,`-`)}.zip`;return y.length===0?null:(0,m.jsx)(l,{className:s,devInfoTags:u,nested:c,uid:d,spaceBefore:f,spaceAfter:p,children:(0,m.jsxs)(r,{className:`vitec_downloadcardcollection`,sx:{display:`flex`,borderRadius:`0.75rem`,overflow:`hidden`,boxShadow:`0 0.125rem 0.75rem rgba(0,0,0,0.08)`,minHeight:`10rem`},children:[(0,m.jsx)(r,{sx:{width:`38%`,flexShrink:0,bgcolor:`#fff`,display:`flex`,alignItems:`center`,justifyContent:`center`,overflow:`hidden`,p:w?0:`1.5rem`},children:w?(0,m.jsx)(r,{component:`img`,src:w,alt:b??`Downloads`,loading:`lazy`,sx:{width:`100%`,height:`100%`,objectFit:`contain`,objectPosition:`top center`,display:`block`,p:`0.75rem`}}):(0,m.jsx)(r,{sx:{color:`text.disabled`,opacity:.3},children:(0,m.jsxs)(`svg`,{width:`48`,height:`48`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`1`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[(0,m.jsx)(`path`,{d:`M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z`}),(0,m.jsx)(`polyline`,{points:`14 2 14 8 20 8`}),(0,m.jsx)(`line`,{x1:`8`,y1:`13`,x2:`16`,y2:`13`}),(0,m.jsx)(`line`,{x1:`8`,y1:`17`,x2:`16`,y2:`17`}),(0,m.jsx)(`polyline`,{points:`10 9 9 9 8 9`})]})})}),(0,m.jsxs)(r,{sx:{flex:1,background:h,color:`#fff`,display:`flex`,flexDirection:`column`,p:`1.25rem 1.25rem 1rem`,gap:`0.75rem`},children:[(0,m.jsxs)(i,{direction:`row`,alignItems:`center`,spacing:1,children:[(0,m.jsx)(e,{component:`span`,sx:{fontSize:`0.6875rem`,fontWeight:700,letterSpacing:`0.06em`,textTransform:`uppercase`,opacity:.85,whiteSpace:`nowrap`,color:`inherit`},children:b??`Download Collection`}),(0,m.jsx)(r,{sx:{flex:1,height:`1px`,bgcolor:`rgba(255,255,255,0.3)`}})]}),(0,m.jsx)(i,{spacing:.375,sx:{flex:1},children:y.map(e=>(0,m.jsx)(_,{download:e},e.uid??e.slug??e.title))}),T.length>1&&(0,m.jsx)(v,{downloads:T,zipName:E})]})]})})}export{y as VitecDownloadCardCollection};
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{C as e,E as t,O as n,Z as r,_ as i,c as a,d as o,k as s,n as c,u as l}from"./index-7LYai_r-.js";var u=r();function d(e){return e?Array.isArray(e)?e[0]??null:e:null}function f(e){return e.url??e.publicUrl}function p(e,t){return e.alternative??e.alt??e.title??t}function m(e){if(e.srcset?.length)return e.srcset.map(e=>`${e.url} ${e.descriptor}`).join(`, `)}function h(e){let t=new Date(e);return{day:t.toLocaleString(`en-US`,{day:`numeric`}),month:t.toLocaleString(`en-US`,{month:`short`}).toUpperCase()}}function g(e,t){if(!e)return null;let n=new Date(e),r=n.toLocaleString(`en-US`,{month:`short`,day:`numeric`,year:`numeric`});if(!t||e===t)return r;let i=new Date(t);return n.getMonth()===i.getMonth()&&n.getFullYear()===i.getFullYear()?`${n.toLocaleString(`en-US`,{month:`short`,day:`numeric`})} – ${i.toLocaleString(`en-US`,{day:`numeric`,year:`numeric`})}`:`${r} – ${i.toLocaleString(`en-US`,{month:`short`,day:`numeric`,year:`numeric`})}`}function _(e){return e?/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e.trim()):!1}function v({element:r,className:v,nested:y,devInfoTags:b,uid:x,spaceBefore:S,spaceAfter:C}){let w=a(r),T=o(r),E=i(l(r)),D=r.content?.eventlist?.events??[];return(0,u.jsx)(c,{className:[`vitec_eventlist`,v].filter(Boolean).join(` `),devInfoTags:b,nested:y,uid:x,spaceBefore:S,spaceAfter:C,children:(0,u.jsxs)(`div`,{className:`vitec_eventlist__inner`,children:[(w||T)&&(0,u.jsxs)(e,{spacing:.5,sx:{mb:2.5,textAlign:E,alignItems:E===`center`?`center`:E===`right`?`flex-end`:`flex-start`},children:[w&&(0,u.jsx)(s,{variant:`h4`,children:w}),T&&(0,u.jsx)(s,{variant:`subtitle1`,color:`text.secondary`,children:T})]}),D.length===0?(0,u.jsx)(s,{variant:`body2`,color:`text.secondary`,children:`No upcoming events.`}):(0,u.jsx)(`div`,{className:`vitec_eventlist__items`,children:D.map(r=>{let i=r.eventstart?h(r.eventstart):null,a=r.eventend&&r.eventstart!==r.eventend,o=g(r.eventstart,r.eventend),c=[r.venue,r.city,r.country].filter(Boolean).join(`, `),l=d(r.image),v=l?f(l):void 0,y=_(r.meetinglink)?`mailto:${r.meetinglink.trim()}`:r.meetinglink?r.meetinglink:void 0;return(0,u.jsxs)(`div`,{className:`vitec_eventlist__item`,children:[i&&(0,u.jsxs)(`div`,{className:`vitec_eventlist__date-badge`,"aria-label":o??void 0,children:[(0,u.jsx)(`span`,{className:`vitec_eventlist__date-day`,children:i.day}),(0,u.jsx)(`span`,{className:`vitec_eventlist__date-month`,children:i.month}),a&&(0,u.jsx)(`span`,{className:`vitec_eventlist__date-multiday`,children:`multi-day`})]}),(0,u.jsxs)(`div`,{className:`vitec_eventlist__content`,children:[(0,u.jsx)(s,{variant:`h6`,className:`vitec_eventlist__title`,children:r.title}),r.teaser&&(0,u.jsx)(s,{variant:`body2`,className:`vitec_eventlist__teaser`,children:r.teaser}),(o||c)&&(0,u.jsxs)(`div`,{className:`vitec_eventlist__meta`,children:[o&&(0,u.jsx)(`span`,{className:`vitec_eventlist__meta-date`,children:o}),o&&c&&(0,u.jsx)(`span`,{className:`vitec_eventlist__meta-sep`,"aria-hidden":!0,children:`·`}),c&&(0,u.jsx)(`span`,{className:`vitec_eventlist__meta-location`,children:c})]}),(0,u.jsxs)(e,{direction:`row`,spacing:1,flexWrap:`wrap`,useFlexGap:!0,alignItems:`center`,sx:{mt:1},children:[r.booth&&(0,u.jsx)(n,{label:r.booth,size:`small`,variant:`outlined`,className:`vitec_eventlist__chip vitec_eventlist__chip--booth`}),r.attendancemode===`online`&&(0,u.jsx)(n,{label:`Online`,size:`small`,variant:`outlined`,className:`vitec_eventlist__chip vitec_eventlist__chip--online`}),y&&(0,u.jsx)(t,{component:`a`,href:y,size:`small`,variant:`outlined`,className:`vitec_eventlist__btn vitec_eventlist__btn--contact`,children:`Contact`}),r.eventurl&&(0,u.jsx)(t,{component:`a`,href:r.eventurl,target:`_blank`,rel:`noreferrer`,size:`small`,variant:`contained`,className:`vitec_eventlist__btn vitec_eventlist__btn--more`,children:`Learn more`})]})]}),(0,u.jsx)(`div`,{className:`vitec_eventlist__logo-box${v?``:` vitec_eventlist__logo-box--empty`}`,children:v&&(0,u.jsx)(`img`,{src:v,srcSet:l?m(l):void 0,sizes:`128px`,alt:l?p(l,r.title):r.title,className:`vitec_eventlist__logo-img`,loading:`lazy`})})]},r.uid)})})]})})}export{v as VitecEventList};
|
|
||||||
1
public/_frontend/assets/vitec_eventlist-PgRIlaon.js
Normal file
1
public/_frontend/assets/vitec_eventlist-PgRIlaon.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
public/_frontend/assets/vitec_faq-C66INAn2.js
Normal file
1
public/_frontend/assets/vitec_faq-C66INAn2.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
import{C as e,D as t,S as n,Z as r,b as i,c as a,d as o,f as s,g as c,h as l,k as u,m as d,n as f,o as p,p as m,s as h,w as g}from"./index-7LYai_r-.js";var _=r();function v({element:r,className:v,nested:y,devInfoTags:b,uid:x,spaceBefore:S,spaceAfter:C}){let w=a(r),T=o(r),E=h(r),D=p(r.data?.background_variant),O=m(r.data?.cta),k=l(r.data?.cta),A=c(r.data?.button_style,`light`),j=r.data?.hero_layout_variant??`sm`,M=r.data?.hero_video??[],N=r.data?.hero_image??[],P=M.length>0,F=N.length>0,I=(P||F)&&j!==`xs`,L=P,R=P?M[0]?.publicUrl:N[0]?.publicUrl,z=!P&&N[0]?N[0].alt||N[0].title||w||`Hero image`:``,B=(P?r.data?.hero_video_alignment:r.data?.hero_image_alignment)??`right`,V=I&&(B===`left`||B===`right`),H=I&&(B===`center`||B===`fullwidth`),U=!!r.data?.hero_video_autoplay,W=!!r.data?.hero_video_loop,G=!!r.data?.hero_video_muted||U,K=s(r.data?.hero_bgimage);return j===`xs`?(0,_.jsx)(f,{className:v,devInfoTags:b,fullWidth:!0,nested:y,uid:x,spaceBefore:S,spaceAfter:C,children:(0,_.jsx)(`div`,{className:`vitec_herosection__inner vitec_herosection__inner--xs`})}):(0,_.jsx)(f,{className:v,devInfoTags:b,fullWidth:!0,nested:y,uid:x,spaceBefore:S,spaceAfter:C,children:(0,_.jsx)(`div`,{className:`vitec_herosection__inner vitec_herosection__inner--${j}`,children:(0,_.jsxs)(t,{sx:{...D,...K?{backgroundImage:`url(${K})`,backgroundSize:`cover`,backgroundPosition:`center`}:{},borderRadius:3,px:{xs:2.5,md:4},py:{xs:3,md:4},overflow:`hidden`,display:`flex`,alignItems:`center`},children:[(0,_.jsxs)(g,{container:!0,spacing:4,alignItems:`center`,sx:{width:`100%`},children:[(0,_.jsx)(g,{size:{xs:12,md:V?7:12},sx:V&&B===`left`?{order:{md:2}}:{},children:(0,_.jsxs)(e,{spacing:2,sx:{maxWidth:V?`100%`:680},children:[r.data?.eyebrow&&j!==`sm`&&(0,_.jsx)(u,{variant:`overline`,sx:{letterSpacing:`0.14em`,opacity:.8},children:r.data.eyebrow}),w&&(0,_.jsx)(u,{variant:`h2`,children:w}),T&&(0,_.jsx)(u,{variant:`h6`,sx:{opacity:.85,fontWeight:500},children:T}),E&&(0,_.jsx)(t,{sx:{...i,"& a":{color:`inherit`},"& mark":{backgroundColor:`rgba(var(--vitec-highlight), 0.85)`}},dangerouslySetInnerHTML:{__html:E}}),O&&(0,_.jsx)(n,{href:O,target:k??`_self`,variant:A,alignStart:!0,children:r.data?.cta_label||d(r.data?.cta,`Learn more`)}),!!r.data?.show_logo_wall&&(0,_.jsx)(t,{sx:{mt:1,border:`1px dashed rgba(var(--vitec-white), 0.35)`,borderRadius:2,px:2,py:1.5,width:`fit-content`},children:(0,_.jsx)(u,{variant:`caption`,sx:{opacity:.85},children:`Logo wall placeholder enabled`})})]})}),V&&R&&(0,_.jsx)(g,{size:{xs:12,md:5},sx:B===`left`?{order:{md:1}}:{},children:L?(0,_.jsx)(`video`,{src:R,autoPlay:U,loop:W,muted:G,playsInline:!0,controls:!U,style:{width:`100%`,height:`auto`,display:`block`,borderRadius:`12px`,boxShadow:`0 20px 40px rgba(var(--vitec-surface-dark), 0.25)`}}):(0,_.jsx)(t,{component:`img`,src:R,alt:z,sx:{width:`100%`,height:`auto`,display:`block`,borderRadius:3,boxShadow:`0 20px 40px rgba(var(--vitec-surface-dark), 0.25)`}})})]}),H&&R&&(0,_.jsx)(t,{sx:{mt:3,mx:B===`center`?`auto`:void 0,maxWidth:B===`center`?720:`100%`},children:L?(0,_.jsx)(`video`,{src:R,autoPlay:U,loop:W,muted:G,playsInline:!0,controls:!U,style:{width:`100%`,height:`auto`,display:`block`,borderRadius:`12px`,boxShadow:`0 20px 40px rgba(var(--vitec-surface-dark), 0.25)`}}):(0,_.jsx)(t,{component:`img`,src:R,alt:z,sx:{width:`100%`,height:`auto`,display:`block`,borderRadius:3,boxShadow:`0 20px 40px rgba(var(--vitec-surface-dark), 0.25)`}})})]})})})}export{v as VitecHeroSection};
|
|
||||||
1
public/_frontend/assets/vitec_herosection-Dl4wV6qo.js
Normal file
1
public/_frontend/assets/vitec_herosection-Dl4wV6qo.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,E as t,O as n,T as r,_ as i,d as a,g as o,h as s,l as c,m as l,ot as u,r as d,t as f,u as p,v as m,y as h}from"./index-CM0zIqrs.js";var g=u();function _({element:u,className:_,nested:v,devInfoTags:y,uid:b,spaceBefore:x,spaceAfter:S}){let C=a(u),w=l(u),T=p(u),E=c(u.data?.background_variant),D=o(u.data?.cta),O=m(u.data?.cta),k=h(u.data?.button_style,`light`),A=u.data?.hero_layout_variant??`sm`,j=u.data?.hero_video??[],M=u.data?.hero_image??[],N=j.length>0,P=M.length>0,F=(N||P)&&A!==`xs`,I=N,L=N?j[0]?.publicUrl:M[0]?.publicUrl,R=!N&&M[0]?M[0].alt||M[0].title||C||`Hero image`:``,z=(N?u.data?.hero_video_alignment:u.data?.hero_image_alignment)??`right`,B=F&&(z===`left`||z===`right`),V=F&&(z===`center`||z===`fullwidth`),H=!!u.data?.hero_video_autoplay,U=!!u.data?.hero_video_loop,W=!!u.data?.hero_video_muted||H,G=s(u.data?.hero_bgimage),K=F&&L?I?(0,g.jsx)(`video`,{src:L,autoPlay:H,loop:U,muted:W,playsInline:!0,controls:!H,style:{width:`100%`,height:`auto`,display:`block`,borderRadius:`12px`,boxShadow:`0 20px 40px rgba(var(--vitec-surface-dark), 0.25)`}}):(0,g.jsx)(n,{component:`img`,src:L,alt:R,sx:{width:`100%`,height:`auto`,display:`block`,borderRadius:3,boxShadow:`0 20px 40px rgba(var(--vitec-surface-dark), 0.25)`}}):null;if(A===`xs`)return(0,g.jsx)(d,{className:_,devInfoTags:y,fullWidth:!0,nested:v,uid:b,spaceBefore:x,spaceAfter:S,children:(0,g.jsx)(`div`,{className:`vitec_herosection__inner vitec_herosection__inner--xs`})});let q=(u.data?.header_position??``)===`center`;return(0,g.jsx)(d,{className:_,devInfoTags:y,fullWidth:!0,nested:v,uid:b,spaceBefore:x,spaceAfter:S,children:(0,g.jsx)(`div`,{className:`vitec_herosection__inner vitec_herosection__inner--${A}`,children:(0,g.jsxs)(n,{className:`vitec_herosection__box`,sx:{...E,...G?{backgroundImage:`url(${G})`,backgroundSize:`cover`,backgroundPosition:`center`}:{}},children:[(0,g.jsxs)(t,{container:!0,spacing:4,alignItems:`center`,className:`vitec_herosection__grid`,children:[(0,g.jsx)(t,{size:{xs:12,md:B?7:12},className:B&&z===`left`?`vitec_herosection__text-col vitec_herosection__text-col--order-last`:`vitec_herosection__text-col`,children:(0,g.jsxs)(r,{spacing:2,className:[`vitec_herosection__content-stack`,B?`vitec_herosection__content-stack--side`:``,q?`vitec_herosection__content-stack--centered`:``].filter(Boolean).join(` `),children:[u.data?.eyebrow&&A!==`sm`&&(0,g.jsx)(e,{variant:`overline`,className:`vitec_herosection__eyebrow`,children:u.data.eyebrow}),C&&(0,g.jsx)(e,{variant:`h2`,children:C}),w&&(0,g.jsx)(e,{variant:`h6`,className:`vitec_herosection__subheader`,children:w}),T&&(0,g.jsx)(`div`,{className:`vitec_herosection__bodytext`,dangerouslySetInnerHTML:{__html:T}}),D&&(0,g.jsx)(f,{href:D,target:O??`_self`,variant:k,alignStart:!0,children:u.data?.cta_label||i(u.data?.cta,`Learn more`)}),!!u.data?.show_logo_wall&&(0,g.jsx)(`div`,{className:`vitec_herosection__logo-wall-placeholder`,children:(0,g.jsx)(e,{variant:`caption`,children:`Logo wall placeholder enabled`})})]})}),B&&K&&(0,g.jsx)(t,{size:{xs:12,md:5},className:z===`left`?`vitec_herosection__media-col vitec_herosection__media-col--order-first`:`vitec_herosection__media-col`,children:K})]}),V&&K&&(0,g.jsx)(`div`,{className:`vitec_herosection__stacked-media vitec_herosection__stacked-media--${z}`,children:K})]})})})}export{_ as VitecHeroSection};
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{C as e,D as t,S as n,Z as r,_ as i,b as a,c as o,d as s,g as c,h as l,k as u,n as d,p as f,s as p,w as m}from"./index-7LYai_r-.js";var h=r();function g({element:r,className:g,nested:_,devInfoTags:v,uid:y,spaceBefore:b,spaceAfter:x}){let S=o(r),C=s(r),w=p(r),T=f(r.data?.button_link),E=l(r.data?.button_link),D=r.data?.button_text,O=c(r.data?.button_style),k=r.data?.intro_layout_variant??`variant_1`,A=i(r.data?.header_position)===`center`||k===`variant_1`,j=!!r.data?.fullwidth,M=r.data?.intro_video??[],N=r.data?.intro_image??[],P=M.length>0,F=N.length>0,I=P||F,L=P,R=P?M[0]?.publicUrl:N[0]?.publicUrl,z=!P&&N[0]&&(N[0].alt||N[0].title||S)||``,B=(P?r.data?.intro_video_alignment:r.data?.intro_image_alignment)??`right`,V=I&&(B===`left`||B===`right`),H=I&&(B===`center`||B===`fullwidth`),U=!!r.data?.intro_video_autoplay,W=!!r.data?.intro_video_loop,G=!!r.data?.intro_video_muted||U,K=(0,h.jsxs)(e,{spacing:2.5,sx:{textAlign:A&&!I?`center`:`left`,alignItems:A&&!I?`center`:`flex-start`,maxWidth:I?void 0:760,mx:A&&!I?`auto`:void 0},children:[S&&(0,h.jsx)(u,{variant:`h3`,children:S}),C&&(0,h.jsx)(u,{variant:`subtitle1`,color:`text.secondary`,children:C}),w&&(0,h.jsx)(t,{sx:a,dangerouslySetInnerHTML:{__html:w}}),T&&(0,h.jsx)(n,{href:T,target:E??`_self`,variant:O,children:D??`Mehr erfahren`})]}),q=I&&R&&(L?(0,h.jsx)(`video`,{src:R,autoPlay:U,loop:W,muted:G,playsInline:!0,controls:!U,style:{width:`100%`,height:`auto`,display:`block`,borderRadius:`12px`}}):(0,h.jsx)(t,{component:`img`,src:R,alt:z,sx:{width:`100%`,height:`auto`,display:`block`,borderRadius:2}}));return(0,h.jsx)(d,{className:g,devInfoTags:v,fullWidth:j,nested:_,uid:y,spaceBefore:b,spaceAfter:x,children:(0,h.jsx)(`div`,{className:`vitec_introparagraph__inner vitec_introparagraph--${k}`,children:V?(0,h.jsxs)(m,{container:!0,spacing:4,alignItems:`center`,children:[(0,h.jsx)(m,{size:{xs:12,md:6},sx:B===`left`?{order:{md:2}}:{},children:K}),(0,h.jsx)(m,{size:{xs:12,md:6},sx:B===`left`?{order:{md:1}}:{},children:q})]}):(0,h.jsxs)(h.Fragment,{children:[K,H&&q&&(0,h.jsx)(t,{sx:{mt:3,mx:B===`center`?`auto`:void 0,maxWidth:B===`center`?720:`100%`},children:q})]})})})}export{g as VitecIntroParagraph};
|
|
||||||
1
public/_frontend/assets/vitec_introparagraph-DxC6s5bV.js
Normal file
1
public/_frontend/assets/vitec_introparagraph-DxC6s5bV.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,C as t,E as n,O as r,T as i,b as a,d as o,g as s,m as c,ot as l,r as u,t as d,u as f,v as p,y as m}from"./index-CM0zIqrs.js";var h=l();function g({element:l,className:g,nested:_,devInfoTags:v,uid:y,spaceBefore:b,spaceAfter:x}){let S=o(l),C=c(l),w=f(l),T=s(l.data?.button_link),E=p(l.data?.button_link),D=l.data?.button_text,O=m(l.data?.button_style),k=l.data?.intro_layout_variant??`variant_1`,A=a(l.data?.header_position)===`center`||k===`variant_1`,j=!!l.data?.fullwidth,M=l.data?.intro_video??[],N=l.data?.intro_image??[],P=M.length>0,F=N.length>0,I=P||F,L=P,R=P?M[0]?.publicUrl:N[0]?.publicUrl,z=!P&&N[0]&&(N[0].alt||N[0].title||S)||``,B=(P?l.data?.intro_video_alignment:l.data?.intro_image_alignment)??`right`,V=I&&(B===`left`||B===`right`),H=I&&(B===`center`||B===`fullwidth`),U=!!l.data?.intro_video_autoplay,W=!!l.data?.intro_video_loop,G=!!l.data?.intro_video_muted||U,K=(0,h.jsxs)(i,{spacing:2.5,sx:{textAlign:A&&!I?`center`:`left`,alignItems:A&&!I?`center`:`flex-start`,maxWidth:I?void 0:760,mx:A&&!I?`auto`:void 0},children:[S&&(0,h.jsx)(e,{variant:`h3`,children:S}),C&&(0,h.jsx)(e,{variant:`subtitle1`,color:`text.secondary`,children:C}),w&&(0,h.jsx)(r,{sx:t,dangerouslySetInnerHTML:{__html:w}}),T&&(0,h.jsx)(d,{href:T,target:E??`_self`,variant:O,children:D??`Mehr erfahren`})]}),q=I&&R&&(L?(0,h.jsx)(`video`,{src:R,autoPlay:U,loop:W,muted:G,playsInline:!0,controls:!U,style:{width:`100%`,height:`auto`,display:`block`,borderRadius:`12px`}}):(0,h.jsx)(r,{component:`img`,src:R,alt:z,sx:{width:`100%`,height:`auto`,display:`block`,borderRadius:2}}));return(0,h.jsx)(u,{className:g,devInfoTags:v,fullWidth:j,nested:_,uid:y,spaceBefore:b,spaceAfter:x,children:(0,h.jsx)(`div`,{className:`vitec_introparagraph__inner vitec_introparagraph--${k}`,children:V?(0,h.jsxs)(n,{container:!0,spacing:4,alignItems:`center`,children:[(0,h.jsx)(n,{size:{xs:12,md:6},sx:B===`left`?{order:{md:2}}:{},children:K}),(0,h.jsx)(n,{size:{xs:12,md:6},sx:B===`left`?{order:{md:1}}:{},children:q})]}):(0,h.jsxs)(h.Fragment,{children:[K,H&&q&&(0,h.jsx)(r,{sx:{mt:3,mx:B===`center`?`auto`:void 0,maxWidth:B===`center`?720:`100%`},children:q})]})})})}export{g as VitecIntroParagraph};
|
||||||
2
public/_frontend/assets/vitec_locationlist-BoId6hQ3.js
Normal file
2
public/_frontend/assets/vitec_locationlist-BoId6hQ3.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/vitec_locationmap-CO_jtYJV.js","assets/index-CM0zIqrs.js","assets/index-B6-rfpgz.css"])))=>i.map(i=>d[i]);
|
||||||
|
import{A as e,d as t,f as n,lt as r,ot as i,r as a,ut as o,x as s}from"./index-CM0zIqrs.js";var c=o(),l=i(),u=(0,c.lazy)(()=>r(()=>import(`./vitec_locationmap-CO_jtYJV.js`),__vite__mapDeps([0,1,2])).then(e=>({default:e.VitecGlobeMap}))),d=e=>e.toUpperCase().split(``).map(e=>String.fromCodePoint(e.charCodeAt(0)+127397)).join(``);function f(e){let t=e.address;if(!t)return[];let n=[];t.company&&n.push(t.company),t.street?n.push(t.street+(t.additional?`, `+t.additional:``)):t.additional&&n.push(t.additional);let r=[t.postalCode,t.city,t.region].filter(Boolean).join(` `);return r&&n.push(r),t.country&&n.push(t.country),n}function p(){return(0,l.jsx)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:(0,l.jsx)(`path`,{d:`M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.49 12 19.79 19.79 0 0 1 1.47 3.55 2 2 0 0 1 3.44 1.35h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L7.91 9a16 16 0 0 0 6.09 6.09l1.27-.78a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 16.92z`})})}function m(){return(0,l.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[(0,l.jsx)(`polyline`,{points:`22 17 13 17`}),(0,l.jsx)(`rect`,{x:`2`,y:`3`,width:`8`,height:`18`,rx:`1`}),(0,l.jsx)(`path`,{d:`M22 17l-5-5V7a2 2 0 0 0-2-2h-1`}),(0,l.jsx)(`line`,{x1:`6`,y1:`8`,x2:`6`,y2:`8`})]})}function h({loc:e}){let t=f(e),n=e.countryCode?d(e.countryCode):``,r=e.links?.contact??`/contact`;return(0,l.jsxs)(`div`,{className:`vitec_locationcard`,children:[(0,l.jsxs)(`div`,{className:`vitec_locationcard__header`,children:[n&&(0,l.jsx)(`span`,{className:`vitec_locationcard__flag`,"aria-hidden":`true`,children:n}),(0,l.jsx)(`span`,{className:`vitec_locationcard__name`,children:e.name})]}),(0,l.jsxs)(`div`,{className:`vitec_locationcard__body`,children:[t.length>0&&(0,l.jsx)(`address`,{className:`vitec_locationcard__address`,children:t.map((e,t)=>(0,l.jsx)(`span`,{children:e},t))}),(e.contact?.phone||e.contact?.fax)&&(0,l.jsxs)(`div`,{className:`vitec_locationcard__contact`,children:[e.contact.phone&&(0,l.jsxs)(`a`,{href:`tel:${e.contact.phone.replace(/\s/g,``)}`,className:`vitec_locationcard__contact-line`,children:[(0,l.jsx)(p,{}),e.contact.phone]}),e.contact.fax&&(0,l.jsxs)(`span`,{className:`vitec_locationcard__contact-line vitec_locationcard__contact-line--fax`,children:[(0,l.jsx)(m,{}),e.contact.fax]})]})]}),(0,l.jsx)(`div`,{className:`vitec_locationcard__footer`,children:(0,l.jsx)(`a`,{href:r,className:`vitec_locationcard__cta`,children:`Contact us`})})]})}function g({loc:e}){let t=f(e),n=e.countryCode?d(e.countryCode):``,r=e.links?.contact??`/contact`;return(0,l.jsxs)(`div`,{className:`vitec_locationrow`,children:[(0,l.jsxs)(`div`,{className:`vitec_locationrow__identity`,children:[n&&(0,l.jsx)(`span`,{className:`vitec_locationrow__flag`,"aria-hidden":`true`,children:n}),(0,l.jsx)(`span`,{className:`vitec_locationrow__name`,children:e.name})]}),t.length>0&&(0,l.jsx)(`address`,{className:`vitec_locationrow__address`,children:t.map((e,t)=>(0,l.jsx)(`span`,{children:e},t))}),(0,l.jsxs)(`div`,{className:`vitec_locationrow__right`,children:[(e.contact?.phone||e.contact?.fax)&&(0,l.jsxs)(`div`,{className:`vitec_locationrow__contact`,children:[e.contact.phone&&(0,l.jsxs)(`a`,{href:`tel:${e.contact.phone.replace(/\s/g,``)}`,className:`vitec_locationrow__contact-line`,children:[(0,l.jsx)(p,{}),e.contact.phone]}),e.contact.fax&&(0,l.jsxs)(`span`,{className:`vitec_locationrow__contact-line vitec_locationrow__contact-line--fax`,children:[(0,l.jsx)(m,{}),e.contact.fax]})]}),(0,l.jsx)(`a`,{href:r,className:`vitec_locationrow__cta`,children:`Contact →`})]})]})}function _({element:r,className:i,nested:o,devInfoTags:d,uid:f,spaceBefore:p,spaceAfter:m}){let _=t(r),v=Number(n(r)??0),y=s(v===0?2:v),b=r.content?.locations,x=b?.variant??`list`,S=(b?.locations??[]).filter(e=>e.active!==!1);return x===`map`?(0,l.jsx)(a,{className:i,devInfoTags:d,fullWidth:!0,nested:o,uid:f,spaceBefore:p,spaceAfter:m,children:(0,l.jsx)(c.Suspense,{fallback:(0,l.jsx)(`div`,{className:`vitec_locationmap__loading`}),children:(0,l.jsx)(u,{locations:S,mapText:b?.mapText})})}):(0,l.jsx)(a,{className:i,devInfoTags:d,nested:o,uid:f,spaceBefore:p,spaceAfter:m,children:(0,l.jsxs)(`div`,{className:`vitec_locationlist__inner`,children:[_&&(0,l.jsx)(e,{variant:y,className:`vitec_locationlist__heading`,children:_}),x===`grid`?(0,l.jsx)(`div`,{className:`vitec_locationlist__grid`,children:S.map(e=>(0,l.jsx)(h,{loc:e},e.id??e.slug))}):(0,l.jsx)(`div`,{className:`vitec_locationlist__list`,children:S.map(e=>(0,l.jsx)(g,{loc:e},e.id??e.slug))})]})})}export{_ as VitecLocationList};
|
||||||
5253
public/_frontend/assets/vitec_locationmap-CO_jtYJV.js
Normal file
5253
public/_frontend/assets/vitec_locationmap-CO_jtYJV.js
Normal file
File diff suppressed because one or more lines are too long
1
public/_frontend/assets/vitec_marketshow-DQPQbqWc.js
Normal file
1
public/_frontend/assets/vitec_marketshow-DQPQbqWc.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import{A as e,C as t,E as n,O as r,T as i,k as a,ot as o,r as s}from"./index-CM0zIqrs.js";var c=o();function l({element:o,className:l,nested:u,devInfoTags:d,uid:f,spaceBefore:p,spaceAfter:m}){let h=o.content?.market?.market,g=o.appearance?.frameClass?.split(`,`).map(e=>e.trim()).includes(`vitec-full-width`)??!1,_=h?.image?.url,v=h?.image?.srcset?.map(e=>`${e.url} ${e.descriptor}`).join(`, `);return(0,c.jsx)(s,{className:l,devInfoTags:d,fullWidth:g,nested:u,uid:f,spaceBefore:p,spaceAfter:m,children:(0,c.jsx)(`div`,{className:`vitec_marketshow__inner`,children:(0,c.jsxs)(n,{container:!0,spacing:3,alignItems:`start`,children:[_&&(0,c.jsx)(n,{size:{xs:12,md:5},children:(0,c.jsx)(r,{component:`img`,src:_,srcSet:v,sizes:`(max-width: 900px) 100vw, 40vw`,alt:h?.title??`Market`,sx:{width:`100%`,height:`auto`,display:`block`,borderRadius:3}})}),(0,c.jsx)(n,{size:{xs:12,md:_?7:12},children:(0,c.jsxs)(i,{spacing:2,children:[(0,c.jsx)(e,{variant:`overline`,color:`text.secondary`,children:`Market`}),h?.title&&(0,c.jsx)(e,{variant:`h4`,children:h.title}),h?.subtitle&&(0,c.jsx)(e,{variant:`subtitle1`,color:`text.secondary`,children:h.subtitle}),h?.teaser&&(0,c.jsx)(e,{variant:`body1`,children:h.teaser}),h?.description&&(0,c.jsx)(r,{sx:t,dangerouslySetInnerHTML:{__html:h.description}}),h?.categories&&h.categories.length>0&&(0,c.jsx)(i,{direction:`row`,spacing:.75,flexWrap:`wrap`,useFlexGap:!0,children:h.categories.map(e=>(0,c.jsx)(a,{label:e.title??`Category`,size:`small`},e.uid??e.title))})]})})]})})})}export{l as VitecMarketShow};
|
||||||
@@ -1 +0,0 @@
|
|||||||
import{C as e,D as t,O as n,Z as r,b as i,k as a,n as o,w as s}from"./index-7LYai_r-.js";var c=r();function l({element:r,className:l,nested:u,devInfoTags:d,uid:f,spaceBefore:p,spaceAfter:m}){let h=r.content?.market?.market,g=r.appearance?.frameClass?.split(`,`).map(e=>e.trim()).includes(`vitec-full-width`)??!1,_=h?.image?.url,v=h?.image?.srcset?.map(e=>`${e.url} ${e.descriptor}`).join(`, `);return(0,c.jsx)(o,{className:l,devInfoTags:d,fullWidth:g,nested:u,uid:f,spaceBefore:p,spaceAfter:m,children:(0,c.jsx)(`div`,{className:`vitec_marketshow__inner`,children:(0,c.jsxs)(s,{container:!0,spacing:3,alignItems:`start`,children:[_&&(0,c.jsx)(s,{size:{xs:12,md:5},children:(0,c.jsx)(t,{component:`img`,src:_,srcSet:v,sizes:`(max-width: 900px) 100vw, 40vw`,alt:h?.title??`Market`,sx:{width:`100%`,height:`auto`,display:`block`,borderRadius:3}})}),(0,c.jsx)(s,{size:{xs:12,md:_?7:12},children:(0,c.jsxs)(e,{spacing:2,children:[(0,c.jsx)(a,{variant:`overline`,color:`text.secondary`,children:`Market`}),h?.title&&(0,c.jsx)(a,{variant:`h4`,children:h.title}),h?.subtitle&&(0,c.jsx)(a,{variant:`subtitle1`,color:`text.secondary`,children:h.subtitle}),h?.teaser&&(0,c.jsx)(a,{variant:`body1`,children:h.teaser}),h?.description&&(0,c.jsx)(t,{sx:i,dangerouslySetInnerHTML:{__html:h.description}}),h?.categories&&h.categories.length>0&&(0,c.jsx)(e,{direction:`row`,spacing:.75,flexWrap:`wrap`,useFlexGap:!0,children:h.categories.map(e=>(0,c.jsx)(n,{label:e.title??`Category`,size:`small`},e.uid??e.title))})]})})]})})})}export{l as VitecMarketShow};
|
|
||||||
1
public/_frontend/assets/vitec_productlist-ANtC_tOO.js
Normal file
1
public/_frontend/assets/vitec_productlist-ANtC_tOO.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
import{C as e,D as t,N as n,O as r,S as i,V as a,Z as o,_ as s,a as c,c as l,d as u,f as d,k as f,n as p,u as m,w as h}from"./index-7LYai_r-.js";var g=o();function _({element:o,className:_,nested:v,devInfoTags:y,uid:b,spaceBefore:x,spaceAfter:S}){let C=l(o),w=u(o),T=s(m(o)),E=T===`center`?`center`:T===`right`?`right`:`left`,D=T===`center`?`center`:T===`right`?`flex-end`:`flex-start`,O=o.appearance?.frameClass?.split(`,`).map(e=>e.trim()).includes(`vitec-full-width`)??!1,k=o.content?.products?.products??[],A=o.content!=null;return(0,g.jsx)(p,{className:_,devInfoTags:y,fullWidth:O,nested:v,uid:b,spaceBefore:x,spaceAfter:S,children:(0,g.jsxs)(`div`,{className:`vitec_productlist__inner`,children:[(C||w)&&(0,g.jsxs)(e,{spacing:.5,sx:{width:`100%`,textAlign:E,alignItems:D},children:[C&&(0,g.jsx)(f,{variant:`h4`,children:C}),w&&(0,g.jsx)(f,{variant:`subtitle1`,color:`text.secondary`,children:w})]}),!A&&(0,g.jsxs)(f,{variant:`body2`,color:`text.disabled`,sx:{fontStyle:`italic`},children:[`No product data — plugin not configured or no products assigned (UID `,b??`?`,`).`]}),(0,g.jsx)(h,{container:!0,spacing:3,children:k.map(o=>{let s=d(o.images),l=a(o.link,c.base_url,c.router_mode);return(0,g.jsx)(h,{size:{xs:12,md:6,lg:4},children:(0,g.jsx)(n,{variant:`outlined`,sx:{height:`100%`,p:2.5,borderRadius:3},children:(0,g.jsxs)(e,{spacing:2,sx:{height:`100%`},children:[s&&(0,g.jsx)(t,{component:`img`,src:s,alt:o.title??`Product image`,sx:{width:`100%`,height:180,objectFit:`cover`,borderRadius:2}}),(0,g.jsxs)(e,{spacing:.75,children:[(0,g.jsx)(f,{variant:`h6`,children:o.title??`Product`}),o.subtitle&&(0,g.jsx)(f,{color:`text.secondary`,children:o.subtitle}),o.teaser&&(0,g.jsx)(f,{children:o.teaser})]}),o.categories&&o.categories.length>0&&(0,g.jsx)(e,{direction:`row`,spacing:.75,flexWrap:`wrap`,useFlexGap:!0,children:o.categories.map(e=>(0,g.jsx)(r,{label:e.title??`Category`,size:`small`},e.uid??e.title))}),(0,g.jsx)(t,{sx:{flexGrow:1}}),l&&(0,g.jsx)(i,{href:l,variant:`outlined`,size:`sm`,alignStart:!0,children:`View product`})]})})},o.uid??o.slug??o.title)})})]})})}export{_ as VitecProductList};
|
|
||||||
1
public/_frontend/assets/vitec_productshow-BpVhrdsH.js
Normal file
1
public/_frontend/assets/vitec_productshow-BpVhrdsH.js
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user