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.
|
||||
|
||||
<div align="center"><sub>VITEC · TYPO3 headless backend + React front end</sub></div>
|
||||
|
||||
|
||||
vitecdev
|
||||
17ZJfy75sJoU68J6
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"friendsoftypo3/headless": "^5.0@rc",
|
||||
"georgringer/news": "^14.0",
|
||||
"netzbewegung/nb-headless-content-blocks": "^0.0.23",
|
||||
"plan2net/backend-category-hierarchy": "^14.0",
|
||||
"typo3/cms-backend": "^14.3",
|
||||
"typo3/cms-belog": "^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",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "894f07b60885efbdf0a5979a6879e631",
|
||||
"content-hash": "09c5be5fca6a03ab5f0ed81662f20f36",
|
||||
"packages": [
|
||||
{
|
||||
"name": "b13/container",
|
||||
@@ -2834,6 +2834,66 @@
|
||||
},
|
||||
"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",
|
||||
"version": "3.0.0",
|
||||
@@ -9411,10 +9471,10 @@
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {},
|
||||
"platform-dev": {},
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"platform-overrides": {
|
||||
"php": "8.4.0"
|
||||
},
|
||||
"plugin-api-version": "2.9.0"
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
||||
|
||||
@@ -69,4 +69,26 @@ routeEnhancers:
|
||||
aspects:
|
||||
news-title:
|
||||
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: ''
|
||||
|
||||
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\DatasheetsJsonRenderer;
|
||||
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 TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
@@ -111,6 +114,9 @@ final class ContainerChildrenProcessor implements DataProcessorInterface
|
||||
'vitec_downloadcardcollection' => [DownloadcardcollectionJsonRenderer::class, 'downloadcardcollection'],
|
||||
'vitec_datasheets' => [DatasheetsJsonRenderer::class, 'datasheets'],
|
||||
'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_newsliststicky' => [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\DatasheetsJsonRenderer;
|
||||
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 TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
@@ -76,6 +79,9 @@ final class ContentElementResolver
|
||||
'vitec_downloadcardcollection' => [DownloadcardcollectionJsonRenderer::class, 'downloadcardcollection'],
|
||||
'vitec_datasheets' => [DatasheetsJsonRenderer::class, 'datasheets'],
|
||||
'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_newsliststicky' => [NewsJsonRenderer::class, 'news'],
|
||||
'news_newsselectedlist' => [NewsJsonRenderer::class, 'news'],
|
||||
|
||||
@@ -45,7 +45,7 @@ final class UsecaseSerializer
|
||||
'teaser' => (string)($u['teaser'] ?? ''),
|
||||
'cardImage' => $this->image($uid, 'card_image'),
|
||||
'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),
|
||||
'featured' => (bool)($u['featured'] ?? false),
|
||||
'layoutVariant' => (string)($u['layout_variant'] ?? 'standard'),
|
||||
@@ -75,7 +75,7 @@ final class UsecaseSerializer
|
||||
'contentElements' => $this->contentElements($uid),
|
||||
'related' => [
|
||||
'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),
|
||||
'products' => $this->relationMulti('tx_vitec_usecase_product_mm', 'tx_vitec_domain_model_product', $uid),
|
||||
'categories' => $base['categories'],
|
||||
@@ -129,6 +129,20 @@ final class UsecaseSerializer
|
||||
$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(
|
||||
@@ -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().
|
||||
*
|
||||
@@ -367,10 +489,39 @@ final class UsecaseSerializer
|
||||
*/
|
||||
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 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'];
|
||||
$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 [
|
||||
'type' => $get('item_type') !== '' ? $get('item_type') : 'text',
|
||||
'headline' => $get('headline'),
|
||||
'text' => $get('text'),
|
||||
'image' => $this->image($uid, $imageField, $table),
|
||||
'video' => $this->video($uid, $videoField, $table),
|
||||
'image' => $this->image($uid, 'vitec_image', $table) ?? $this->image($uid, 'image', $table),
|
||||
'video' => $this->video($uid, 'vitec_video', $table) ?? $this->video($uid, 'video', $table),
|
||||
'link' => $get('link'),
|
||||
'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);
|
||||
$limit = (int)($settings['limit'] ?? 0);
|
||||
$debugMode = (bool)($settings['debug'] ?? false);
|
||||
$layout = (string)($settings['layout'] ?? 'list');
|
||||
|
||||
$upcoming = $this->fetchEvents(true, $limit, $daysInAdvance);
|
||||
|
||||
$response = [
|
||||
'events' => array_map(fn($e) => $this->serializeEvent($e), $upcoming),
|
||||
'settings' => [
|
||||
'layout' => $layout,
|
||||
'showpast' => $showPast,
|
||||
'daysinadvance' => $daysInAdvance,
|
||||
'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 TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
||||
use TYPO3\CMS\Core\Resource\FileReference;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
@@ -406,15 +407,61 @@ class ProductListJsonRenderer
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
|
||||
return array_map(static function ($cat) {
|
||||
return array_map(function ($cat) {
|
||||
return [
|
||||
'uid' => (int)$cat['uid'],
|
||||
'title' => $cat['title'] ?? '',
|
||||
'description' => $cat['description'] ?? '',
|
||||
'parents' => $this->getCategoryParents((int)$cat['uid']),
|
||||
];
|
||||
}, $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
|
||||
{
|
||||
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
|
||||
@@ -493,10 +493,56 @@ class ProductShowJsonRenderer
|
||||
'uid' => (int)$cat['uid'],
|
||||
'title' => $cat['title'],
|
||||
'description' => $cat['description'] ?? '',
|
||||
'parents' => $this->getCategoryParents((int)$cat['uid']),
|
||||
];
|
||||
}, $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
|
||||
{
|
||||
$qb = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
|
||||
@@ -72,6 +72,22 @@ class UsecaseListJsonRenderer
|
||||
public function renderForRecord(array $contentElement): string
|
||||
{
|
||||
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);
|
||||
$flexFormData = $flexFormService->convertFlexFormContentToArray($contentElement['pi_flexform'] ?? '');
|
||||
$settings = $flexFormData['settings'] ?? [];
|
||||
@@ -92,8 +108,28 @@ class UsecaseListJsonRenderer
|
||||
->fetchAllAssociative();
|
||||
|
||||
$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(
|
||||
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
|
||||
);
|
||||
|
||||
@@ -109,4 +145,15 @@ class UsecaseListJsonRenderer
|
||||
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');
|
||||
$debugMode = (bool)($settings['debug'] ?? false);
|
||||
$usecaseUid = (int)($settings['usecase'] ?? 0);
|
||||
|
||||
// Fallback: uid/slug from the request (React detail route).
|
||||
if (!$usecaseUid) {
|
||||
$params = $GLOBALS['TYPO3_REQUEST']?->getQueryParams() ?? [];
|
||||
$param = $params['tx_vitec_usecaseshow']['usecase'] ?? null;
|
||||
if ($param !== null && $param !== '') {
|
||||
$usecaseUid = is_numeric($param) ? (int)$param : $this->resolveSlug((string)$param);
|
||||
}
|
||||
// The story is resolved from the request ONLY (detail route from the
|
||||
// list plugin's detailUrl): route-enhancer arguments live in the
|
||||
// `routing` PageArguments, plain GET in query params.
|
||||
$request = $GLOBALS['TYPO3_REQUEST'] ?? null;
|
||||
$param = null;
|
||||
$routing = $request?->getAttribute('routing');
|
||||
if ($routing instanceof \TYPO3\CMS\Core\Routing\PageArguments) {
|
||||
$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) {
|
||||
return $debugMode
|
||||
@@ -114,9 +119,11 @@ class UsecaseShowJsonRenderer
|
||||
|
||||
$serializer = GeneralUtility::makeInstance(UsecaseSerializer::class);
|
||||
|
||||
$backPid = (int)($settings['backPid'] ?? 0);
|
||||
$response = [
|
||||
'usecase' => $serializer->serializeDetail($usecase),
|
||||
'layout' => $layout,
|
||||
'backUrl' => $backPid > 0 ? ($this->resolvePageUrl($backPid) ?: null) : null,
|
||||
];
|
||||
|
||||
if ($debugMode) {
|
||||
@@ -145,4 +152,15 @@ class UsecaseShowJsonRenderer
|
||||
|
||||
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>
|
||||
<type>array</type>
|
||||
<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>
|
||||
<label>Days in advance (0 = no limit)</label>
|
||||
<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>
|
||||
<type>array</type>
|
||||
<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>
|
||||
<label>Allow Debug Output.</label>
|
||||
<config>
|
||||
@@ -19,20 +30,6 @@
|
||||
</items>
|
||||
</config>
|
||||
</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>
|
||||
<label>
|
||||
Layout
|
||||
|
||||
@@ -6,6 +6,17 @@
|
||||
<sheetTitle>Usecase List</sheetTitle>
|
||||
<type>array</type>
|
||||
<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>
|
||||
<label>Allow Debug Output.</label>
|
||||
<config>
|
||||
|
||||
@@ -76,4 +76,16 @@ return [
|
||||
'provider' => SvgIconProvider::class,
|
||||
'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
|
||||
|
||||
@@ -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('Datasheets', 'Datasheets', 'FILE:EXT:vitec/Configuration/FlexForms/Datasheets.xml');
|
||||
$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.
|
||||
$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,
|
||||
content_elements,
|
||||
--div--;Detail · Related,
|
||||
market, solutions, products, categories,
|
||||
markets, solutions, products, categories,
|
||||
--div--;SEO,
|
||||
seo_title, seo_description, no_index, no_follow, canonical_link,
|
||||
--palette--;Open Graph;ogPalette,
|
||||
@@ -182,15 +182,16 @@ return [
|
||||
],
|
||||
|
||||
// --------------------------------------------------- Detail · Related
|
||||
'market' => [
|
||||
'label' => 'Market',
|
||||
'markets' => [
|
||||
'label' => 'Markets',
|
||||
'config' => [
|
||||
'type' => 'select',
|
||||
'renderType' => 'selectSingle',
|
||||
'type' => 'select',
|
||||
'renderType' => 'selectMultipleSideBySide',
|
||||
'foreign_table' => 'tx_vitec_domain_model_market',
|
||||
'items' => [['label' => '', 'value' => 0]],
|
||||
'default' => 0,
|
||||
'maxitems' => 1,
|
||||
'MM' => 'tx_vitec_usecase_market_mm',
|
||||
'size' => 6,
|
||||
'autoSizeMax' => 20,
|
||||
'maxitems' => 9999,
|
||||
],
|
||||
],
|
||||
'solutions' => [
|
||||
|
||||
@@ -4,6 +4,11 @@ prefixFields: true
|
||||
prefixType: vendor
|
||||
|
||||
fields:
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
- identifier: tab_content
|
||||
type: Tab
|
||||
label: Content
|
||||
|
||||
- identifier: eyebrow
|
||||
type: Text
|
||||
max: 50
|
||||
@@ -29,10 +34,6 @@ fields:
|
||||
- identifier: subheader
|
||||
useExistingField: true
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- identifier: bodytext
|
||||
useExistingField: true
|
||||
enableRichtext: true
|
||||
@@ -53,7 +54,33 @@ fields:
|
||||
- identifier: Vitec/ButtonStyle
|
||||
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
|
||||
type: File
|
||||
minitems: 0
|
||||
@@ -82,7 +109,11 @@ fields:
|
||||
- label: Fullwidth
|
||||
value: fullwidth
|
||||
|
||||
# --- Video ---
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
- identifier: tab_video
|
||||
type: Tab
|
||||
label: Video
|
||||
|
||||
- identifier: hero_video
|
||||
type: File
|
||||
minitems: 0
|
||||
@@ -115,24 +146,28 @@ fields:
|
||||
type: Checkbox
|
||||
default: 1
|
||||
|
||||
- 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
|
||||
# --- Background video with overlay layer ---
|
||||
- identifier: hero_bgvideo
|
||||
type: File
|
||||
label: Background Video
|
||||
description: 'Fullscreen background video behind the hero content.'
|
||||
minitems: 0
|
||||
maxitems: 1
|
||||
allowed: mp4,webm,ogv,mov,m4v
|
||||
|
||||
- identifier: show_logo_wall
|
||||
type: Checkbox
|
||||
default: 0
|
||||
- identifier: hero_overlay_color
|
||||
type: Color
|
||||
label: Overlay Color
|
||||
description: 'Overlay layer on top of the background video/image.'
|
||||
|
||||
- identifier: debug
|
||||
type: Checkbox
|
||||
default: 0
|
||||
- identifier: hero_overlay_opacity
|
||||
type: Number
|
||||
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">
|
||||
<source>Optional background image placed behind the hero content.</source>
|
||||
</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>
|
||||
</file>
|
||||
</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;
|
||||
}
|
||||
}
|
||||
/* 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'
|
||||
]
|
||||
);
|
||||
|
||||
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,
|
||||
customer_logo int(11) unsigned DEFAULT '0' NOT NULL,
|
||||
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_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_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.
|
||||
|
||||
#AuthUserFile "/usr/www/users/vitecevo/live/public/.htpasswd"
|
||||
#AuthName "DEV"
|
||||
#AuthType Basic
|
||||
#require valid-user
|
||||
AuthUserFile "/usr/www/users/vitecevo/live/public/.htpasswd"
|
||||
AuthName "DEV"
|
||||
AuthType Basic
|
||||
<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