first commit

This commit is contained in:
2025-08-02 16:30:27 +02:00
commit 23646bfcee
14851 changed files with 1750626 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\Admin;
class ArticlesRelatedTypes extends \Window
{
protected $tableName = 'articles_related_types';
protected $nameField = 'name';
}
return ArticlesRelatedTypes::class;

View File

@@ -0,0 +1,7 @@
{
"name": "ArticlesRSS",
"row": {
"type": "articleConfigurable",
"template": "{\"beginning\":\"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n<rss version=\\\"2.0\\\">\\n<channel>\\n <title>{print_url} - Články</title>\\n <link>{url}clanky/</link>\\n <description>Články</description>\\n <language>cs-CZ</language>\",\"end\":\"</channel>\\n</rss>\",\"nodes\":[{\"type\":\"element\",\"value\":\"item\",\"nodes\":[{\"type\":\"element\",\"value\":\"title\",\"nodes\":[{\"type\":\"expression\",\"value\":\"title\",\"nodes\":[]}]},{\"type\":\"element\",\"value\":\"link\",\"nodes\":[{\"type\":\"expression\",\"value\":\"link\",\"nodes\":[]}]},{\"type\":\"element\",\"value\":\"description\",\"nodes\":[{\"type\":\"expression\",\"value\":\"lead_in\",\"nodes\":[]}]},{\"type\":\"element\",\"value\":\"pubDate\",\"nodes\":[{\"type\":\"expression\",\"value\":\"utils.formatDate(date, 'D, d M Y H:i:s O')\",\"nodes\":[]}]},{\"type\":\"element\",\"value\":\"guid\",\"nodes\":[{\"type\":\"expression\",\"value\":\"link\",\"nodes\":[]}]},{\"type\":\"condition\",\"value\":\"tags\",\"nodes\":[{\"type\":\"element\",\"value\":\"tags\",\"nodes\":[{\"type\":\"cycle\",\"value\":\"tags\",\"indexAccessName\":\"key\",\"valueAccessName\":\"tag\",\"nodes\":[{\"type\":\"element\",\"value\":\"tag\",\"nodes\":[{\"type\":\"expression\",\"value\":\"tag\",\"nodes\":[]}]}]}]}]},{\"type\":\"condition\",\"value\":\"main_photo\",\"nodes\":[{\"type\":\"element\",\"value\":\"enclosure\",\"nodes\":[{\"type\":\"attribute\",\"value\":\"url\",\"nodes\":[{\"type\":\"expression\",\"value\":\"main_photo.original_url\",\"nodes\":[]}]},{\"type\":\"attribute\",\"value\":\"type\",\"nodes\":[{\"type\":\"value\",\"value\":\"image/jpeg\",\"nodes\":[]}]},{\"type\":\"attribute\",\"value\":\"length\",\"nodes\":[{\"type\":\"value\",\"value\":\"123456\",\"nodes\":[]}]}]}]}]}]}"
}
}

View File

@@ -0,0 +1,10 @@
<?php
$txt_str['ArticlesRelatedTypes'] = [
'toolbar_list' => 'Seznam souvisejících typů',
'toolbar_add' => 'Přidat související typ',
'tabType' => 'Související typ',
'name' => 'Název',
];

View File

@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace KupShop\CatalogBundle\Admin\lists;
use KupShop\AdminBundle\AdminList\BaseList;
use KupShop\KupShopBundle\Util\HtmlBuilder\HTML;
use Query\Operator;
use Query\QueryBuilder;
class ArticlesProductsList extends BaseList
{
protected $tableDef = [
'id' => 'pia.id_product',
'fields' => [
'photo' => ['translate' => true, 'field' => 'p.title', 'spec' => [], 'type' => 'products', 'render' => 'renderImage', 'visible' => 'N', 'size' => '140px'],
'title' => ['translate' => true, 'field' => 'p.title', 'spec' => 'p.title', 'type' => 'products', 'fieldType' => BaseList::TYPE_STRING],
'productNumber' => ['translate' => true, 'field' => 'p.id', 'spec' => 'p.id', 'fieldType' => BaseList::TYPE_FLOAT],
'code' => ['translate' => true, 'field' => 'p.code', 'spec' => 'p.code', 'fieldType' => BaseList::TYPE_STRING],
'piecesInStore' => ['translate' => true, 'field' => 'p.in_store', 'spec' => 'p.in_store', 'fieldType' => BaseList::TYPE_FLOAT],
'Odebrat' => ['field' => 'p.id', 'render' => 'renderDelete', 'size' => '100px'],
],
'translation_section' => 'products',
];
protected $tableName = 'products_in_articles';
protected ?string $tableAlias = 'pia';
public function customizeTableDef($tableDef)
{
$tableDef = parent::customizeTableDef($tableDef);
$tableDef['fields']['photo']['spec'] = function ($qb) {
$qb->addSelect('ppr.id_photo as id_image, ph.image_2, ph.source as image_source, "product_gallery" as image_type')
->leftJoin('p', 'photos_products_relation', 'ppr', 'ppr.id_product = p.id AND ppr.show_in_lead = "Y"')
->leftJoin('ppr', 'photos', 'ph', 'ph.id = ppr.id_photo');
};
return $tableDef;
}
public function getQuery(): QueryBuilder
{
$qb = parent::getQuery();
$qb->leftJoin('pia', 'products', 'p', 'p.id = pia.id_product');
return $qb;
}
public function getFilterQuery(): QueryBuilder
{
$qb = parent::getFilterQuery();
$qb->leftJoin('pia', 'products', 'p', 'p.id = pia.id_product');
$qb->andWhere(Operator::equals(['id_article' => getVal('id_article')]));
return $qb;
}
public function renderDelete($values, $column): HTML
{
$id_article = getVal('id_article');
return HTML::create('a')
->attr('class', 'btn-sm btn btn-danger')
->attr('data-form-delete', '')
->attr('href', "?s=list.php&type=articlesProducts&id_article={$id_article}&acn=deleteValue&delete={$values['id']}")
->tag('input')
->attr('name', "data[products][{$values['id']}][delete]")
->attr('value', '')
->attr('data-form-delete-input', (string) $values['id'])
->attr('type', 'hidden')
->end()
->tag('span')
->attr('class', 'glyphicon glyphicon-remove')
->end();
}
public function handleDeleteValue(): void
{
if (($id_article = getVal('id_article')) && ($id_product = getVal('delete'))) {
sqlQueryBuilder()
->delete('products_in_articles')
->where(Operator::equals(['id_article' => $id_article, 'id_product' => $id_product]))
->execute();
}
redirect($_SERVER['HTTP_REFERER']);
}
}
return ArticlesProductsList::class;

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace KupShop\CatalogBundle\Admin\lists;
use KupShop\AdminBundle\AdminList\BaseList;
class ArticlesRelatedTypesList extends BaseList
{
protected $tableName = 'articles_related_types';
protected ?string $tableAlias = 'art';
protected $tableDef = [
'id' => 'id',
'fields' => [
'ID' => ['field' => 'id', 'fieldType' => self::TYPE_INT, 'size' => 0.1],
'name' => ['field' => 'name', 'translate' => true, 'fieldType' => self::TYPE_STRING],
],
];
}
return ArticlesRelatedTypesList::class;

View File

@@ -0,0 +1,18 @@
{extends "[shared]/window.tpl"}
{block tabs}
{windowTab id='flapArticlesRelatedTypes' label="{'tabType'|translate}"}
{/block}
{block tabsContent}
<div id="flapArticlesRelatedTypes" class="tab-pane fade active in boxFlex box">
<div class="form-group">
<div class="col-md-2 control-label">
<label>{'name'|translate}</label>
</div>
<div class="col-md-10">
<input type="text" class="form-control" name="data[name]" maxlength="255" value="{$body.data.name}" />
</div>
</div>
</div>
{/block}

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\AdminRegister;
use KupShop\AdminBundle\AdminRegister\IAdminRegisterDynamic;
use KupShop\AdminBundle\AdminRegister\IAdminRegisterStatic;
use KupShop\POSBundle\AdminRegister\AdminRegister;
class ArticlesRegister extends AdminRegister implements IAdminRegisterDynamic, IAdminRegisterStatic
{
public static function getMenu(): array
{
return [
static::createMenuItem('contentMenu/articlesMenu', [
'name' => 'ArticlesRelatedTypes',
'left' => 's=menu.php&type=ArticlesRelatedTypes',
'right' => 's=list.php&type=ArticlesRelatedTypes',
]),
];
}
public static function getPermissions(): array
{
return [
static::createPermissions('ArticlesRelatedTypes', [\Modules::ARTICLES_RELATED_TYPES], superuser: true),
];
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace KupShop\ArticlesBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ArticlesBundle extends Bundle
{
}

View File

@@ -0,0 +1,93 @@
<?php
namespace KupShop\ArticlesBundle\Feed;
use Doctrine\Common\Collections\ArrayCollection;
use KupShop\ArticlesBundle\Wrapper\ArticleWrapper;
use KupShop\FeedGeneratorBundle\Feed\ConfigurableFeedTrait;
use KupShop\FeedGeneratorBundle\Feed\IConfigurableFeed;
use KupShop\FeedsBundle\Feed\IFeed;
use KupShop\I18nBundle\Translations\ArticlesTranslation;
use Query\Translation;
class ArticleConfigurableFeed implements IFeed, IConfigurableFeed
{
use \DatabaseCommunication;
use ConfigurableFeedTrait;
/** @var string */
public static $type = 'articleConfigurable';
/** @var string */
public static $alias = 'Články';
/** @var string */
public static $objectType = 'article';
/** @var \Query\QueryBuilder */
protected $query;
public static function isAllowed(): bool
{
return (bool) findModule(\Modules::ARTICLES);
}
public function __construct(ArticleWrapper $articleWrapper)
{
$this->objectWrapper = $articleWrapper;
}
public function getQuery(int $feedID, $feedRow): \Query\QueryBuilder
{
$qb = sqlQueryBuilder()->select('a.*')->from('articles', 'a')
->andWhere(Translation::coalesceTranslatedFields(ArticlesTranslation::class))
->orderBy('a.id');
if (($feedRow['settings']['filter']['includeHidden'] ?? null) != 'Y') {
$qb->andWhere("a.figure='Y'"); // default: select only visible articles (when includeHidden is NOT set to 'Y')
}
foreach ($this->specs as $spec) {
$qb->andWhere($spec);
}
$this->query = $qb;
return $qb;
}
public function filterByObjectID($objectID): void
{
$this->specs[] = function (\Query\QueryBuilder $qb) use ($objectID) {
$qb->andWhere('a.id=:article_id')->setParameter('article_id', $objectID);
return '';
};
}
public function getData(array $feedRow, ?int $limit = null): \Generator
{
$settingsJson = ($feedRow['settings'] ?? null);
if ($settingsJson) {
$feedRow['settings'] = json_decode_strict($settingsJson, true);
}
$qb = $this->query ?? $this->getQuery($feedRow['id'], $feedRow);
$countQuery = (clone $qb)
->select('count(a.id) AS c')
->resetQueryPart('groupBy');
$count = (int) $countQuery->execute()->fetch()['c'];
// use batching only if limit is NOT set
$iterationLimit = isset($limit) ? 1 : ($count / (float) static::$batchSize);
for ($i = 0; $i < $iterationLimit; $i++) {
$qb->setFirstResult($i * static::$batchSize);
$qb->setMaxResults($limit ?? static::$batchSize);
$articles = new ArrayCollection();
foreach ($qb->execute() as $row) {
$articles->set($row['id'], (object) $row); // cast to (object) to force reference
}
$this->objectWrapper->setArticles($articles);
foreach ($articles as $article) {
yield $this->prepareSingleObject($article);
}
}
}
}

View File

@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\GTM\PageViews;
use KupShop\ComponentsBundle\Interfaces\GTMComponentInterface;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use KupShop\GTMBundle\PageType\ArticlePageType;
class Article extends ArticlePageType implements GTMComponentInterface
{
/**
* @param \KupShop\ArticlesBundle\Twig\Components\Articles\Detail\View $component
*/
public function getPushData($component): object
{
$a = new \stdClass();
$article = $component->articleForGTM();
$a->category = $article['section']['name'] ?? '';
$a->name = $article['title'];
$a->tags = array_values($article['tags'] ?? []);
$a->authors = array_values(array_map(function ($author) {
return [
'name' => $author['name'],
'email' => $author['email'],
'id' => $author['id'],
];
}, $article['authors'] ?? []));
$a->date_created = date_create($article['date'])->format('Y-m-d');
$a->read_time = $article['data']['readTime'] ?? false;
return (object) ['article' => $a];
}
protected function getFirstRelatedBranch($aID)
{
return sqlQueryBuilder()
->select('ab.name')
->from('articles_relation', 'ar')
->leftJoin('ar', 'articles_branches', 'ab', 'ar.id_branch = ab.id')
->where('ar.id_art=:aID')
->setParameter('aID', $aID)
->setMaxResults(1)
->execute()
->fetchOne();
}
public function getPageTypeString(BaseComponent $component): ?string
{
return 'article';
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace KupShop\ArticlesBundle\GTM\PageViews;
use KupShop\ArticlesBundle\Twig\Components\Articles\View;
use KupShop\ComponentsBundle\Interfaces\GTMComponentInterface;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use KupShop\GTMBundle\PageType\ArticlesViewType;
class Articles extends ArticlesViewType implements GTMComponentInterface
{
/** @param View $component */
public function getPushData($component): object
{
return (object) [
'articles' => [
'artPath' => $this->getBreadcrumbsWithoutCurrent(),
],
];
}
public function getPageTypeString(BaseComponent $component): ?string
{
return 'blog';
}
}

View File

@@ -0,0 +1,11 @@
twig_component:
defaults:
KupShop\ArticlesBundle\Twig\Components\: '@Articles/components/'
services:
_defaults:
autowire: true
autoconfigure: true
KupShop\ArticlesBundle\:
resource: ../../{Twig,GTM}

View File

@@ -0,0 +1,7 @@
services:
_defaults:
autowire: true
autoconfigure: true
KupShop\ArticlesBundle\:
resource: ../../{AdminRegister,Feed,Wrapper}

View File

@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="cs">
<file id="articles.cs">
<unit id="wlCCiMH" name="articles.read.count">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ArticleInfo/ArticleInfo.1.html.twig:12</note>
</notes>
<segment>
<source>articles.read.count</source>
<target>x přečteno</target>
</segment>
</unit>
<unit id="Ctbyciv" name="author.article">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/AuthorSmall/AuthorSmall.1.html.twig:6</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/AuthorSmall/AuthorSmall.1.html.twig:6</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/AuthorSmall/AuthorSmall.1.html.twig:6</note>
</notes>
<segment>
<source>author.article</source>
<target>Autor článku</target>
</segment>
</unit>
<unit id="cBgSDGs" name="articles.share.facebook">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:10</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:10</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:8</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:8</note>
</notes>
<segment>
<source>articles.share.facebook</source>
<target>Sdílet článek na Facebooku</target>
</segment>
</unit>
<unit id="jnYl6lu" name="articles.share">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:11</note>
</notes>
<segment>
<source>articles.share</source>
<target>Sdílet</target>
</segment>
</unit>
<unit id="m4sdXJb" name="articles.comments">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:14</note>
</notes>
<segment>
<source>articles.comments</source>
<target>Komentáře</target>
</segment>
</unit>
<unit id="13LrtFk" name="labels">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Labels/Labels.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Labels/Labels.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Labels/Labels.1.html.twig:4</note>
</notes>
<segment>
<source>labels</source>
<target>Štítky</target>
</segment>
</unit>
<unit id="zjh9Xgo" name="gallery">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:5</note>
</notes>
<segment>
<source>gallery</source>
<target>Galerie</target>
</segment>
</unit>
<unit id="gfzu7du" name="registerMessage">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:9</note>
</notes>
<segment>
<source>registerMessage</source>
<target>Chcete-li stáhnout fotografie v plném rozlišení, je nutné se</target>
</segment>
</unit>
<unit id="h3gPpd5" name="register">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:9</note>
</notes>
<segment>
<source>register</source>
<target>zaregistrovat.</target>
</segment>
</unit>
<unit id="IG4i0Ur" name="pressroomMessage">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:17</note>
</notes>
<segment>
<source>pressroomMessage</source>
<target>Nelze stáhnout: Nejste v Pressroom skupině.</target>
</segment>
</unit>
<unit id="aP9j_4L" name="download">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:28</note>
</notes>
<segment>
<source>download</source>
<target>stáhnout</target>
</segment>
</unit>
<unit id="RpfvMi0" name="sections">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:4</note>
</notes>
<segment>
<source>sections</source>
<target>Sekce</target>
</segment>
</unit>
<unit id="ZrwWsR3" name="articles.all">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:10</note>
</notes>
<segment>
<source>articles.all</source>
<target>Vše</target>
</segment>
</unit>
<unit id="vg.6KZO" name="liked.article">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:3</note>
</notes>
<segment>
<source>liked.article</source>
<target>Líbil se vám tento příspěvek? Pošlete ho dál…</target>
</segment>
</unit>
<unit id="UGPQZdU" name="articles.share.x">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:15</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:15</note>
</notes>
<segment>
<source>articles.share.x</source>
<target>Sdílet článek na X</target>
</segment>
</unit>
<unit id="CnHh9m_" name="articles.share.pinterest">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:22</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:22</note>
</notes>
<segment>
<source>articles.share.pinterest</source>
<target>Sdílet článek na Pinterestu</target>
</segment>
</unit>
<unit id="WgTr1MI" name="articles.read">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/ArticleSmall/ArticleSmall.1.html.twig:11</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/LineItem/LineItem.1.html.twig:14</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/SquareBasicItem/SquareBasicItem.1.html.twig:12</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/TopArticle/TopArticle.1.html.twig:13</note>
</notes>
<segment>
<source>articles.read</source>
<target>Přečíst</target>
</segment>
</unit>
<unit id="H00mvj1" name="related.articles">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Product/Articles/Articles.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Product/Articles/Articles.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Product/Articles/Articles.1.html.twig:4</note>
</notes>
<segment>
<source>related.articles</source>
<target>Související články</target>
</segment>
</unit>
</file>
</xliff>

View File

@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="de">
<file id="articles.de">
<unit id="wlCCiMH" name="articles.read.count">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ArticleInfo/ArticleInfo.1.html.twig:12</note>
</notes>
<segment>
<source>articles.read.count</source>
<target>x Abgerufen</target>
</segment>
</unit>
<unit id="Ctbyciv" name="author.article">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/AuthorSmall/AuthorSmall.1.html.twig:6</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/AuthorSmall/AuthorSmall.1.html.twig:6</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/AuthorSmall/AuthorSmall.1.html.twig:6</note>
</notes>
<segment>
<source>author.article</source>
<target>Autor des Artikels</target>
</segment>
</unit>
<unit id="cBgSDGs" name="articles.share.facebook">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:10</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:10</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:8</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:8</note>
</notes>
<segment>
<source>articles.share.facebook</source>
<target>Artikel auf Facebook teilen</target>
</segment>
</unit>
<unit id="jnYl6lu" name="articles.share">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:11</note>
</notes>
<segment>
<source>articles.share</source>
<target>Aktie</target>
</segment>
</unit>
<unit id="m4sdXJb" name="articles.comments">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:14</note>
</notes>
<segment>
<source>articles.comments</source>
<target>Kommentare</target>
</segment>
</unit>
<unit id="13LrtFk" name="labels">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Labels/Labels.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Labels/Labels.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Labels/Labels.1.html.twig:4</note>
</notes>
<segment>
<source>labels</source>
<target>Stichworte</target>
</segment>
</unit>
<unit id="zjh9Xgo" name="gallery">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:5</note>
</notes>
<segment>
<source>gallery</source>
<target>Galerie</target>
</segment>
</unit>
<unit id="gfzu7du" name="registerMessage">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:9</note>
</notes>
<segment>
<source>registerMessage</source>
<target>Um Fotos in voller Auflösung herunterzuladen, müssen Sie</target>
</segment>
</unit>
<unit id="h3gPpd5" name="register">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:9</note>
</notes>
<segment>
<source>register</source>
<target>sich registrieren.</target>
</segment>
</unit>
<unit id="IG4i0Ur" name="pressroomMessage">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:17</note>
</notes>
<segment>
<source>pressroomMessage</source>
<target>Download nicht möglich: Sie sind nicht in der Pressroom-Gruppe.</target>
</segment>
</unit>
<unit id="aP9j_4L" name="download">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:28</note>
</notes>
<segment>
<source>download</source>
<target>herunterladen</target>
</segment>
</unit>
<unit id="RpfvMi0" name="sections">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:4</note>
</notes>
<segment>
<source>sections</source>
<target>Abschnitt</target>
</segment>
</unit>
<unit id="ZrwWsR3" name="articles.all">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:10</note>
</notes>
<segment>
<source>articles.all</source>
<target>Blog</target>
</segment>
</unit>
<unit id="vg.6KZO" name="liked.article">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:3</note>
</notes>
<segment>
<source>liked.article</source>
<target>Hat Ihnen dieser Beitrag gefallen? Gib ihn weiter…</target>
</segment>
</unit>
<unit id="UGPQZdU" name="articles.share.x">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:15</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:15</note>
</notes>
<segment>
<source>articles.share.x</source>
<target>Artikel auf X teilen</target>
</segment>
</unit>
<unit id="CnHh9m_" name="articles.share.pinterest">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:22</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:22</note>
</notes>
<segment>
<source>articles.share.pinterest</source>
<target>Artikel auf Pinterest teilen</target>
</segment>
</unit>
<unit id="WgTr1MI" name="articles.read">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/ArticleSmall/ArticleSmall.1.html.twig:11</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/LineItem/LineItem.1.html.twig:14</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/SquareBasicItem/SquareBasicItem.1.html.twig:12</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/TopArticle/TopArticle.1.html.twig:13</note>
</notes>
<segment>
<source>articles.read</source>
<target>Lesen</target>
</segment>
</unit>
<unit id="H00mvj1" name="related.articles">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Product/Articles/Articles.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Product/Articles/Articles.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Product/Articles/Articles.1.html.twig:4</note>
</notes>
<segment>
<source>related.articles</source>
<target>Ähnliche Artikel</target>
</segment>
</unit>
</file>
</xliff>

View File

@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="en">
<file id="articles.en">
<unit id="wlCCiMH" name="articles.read.count">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ArticleInfo/ArticleInfo.1.html.twig:12</note>
</notes>
<segment>
<source>articles.read.count</source>
<target>x seen</target>
</segment>
</unit>
<unit id="Ctbyciv" name="author.article">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/AuthorSmall/AuthorSmall.1.html.twig:6</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/AuthorSmall/AuthorSmall.1.html.twig:6</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/AuthorSmall/AuthorSmall.1.html.twig:6</note>
</notes>
<segment>
<source>author.article</source>
<target>Author of the article</target>
</segment>
</unit>
<unit id="cBgSDGs" name="articles.share.facebook">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:10</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:10</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:8</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:8</note>
</notes>
<segment>
<source>articles.share.facebook</source>
<target>Share article on Facebook</target>
</segment>
</unit>
<unit id="jnYl6lu" name="articles.share">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:11</note>
</notes>
<segment>
<source>articles.share</source>
<target>Share</target>
</segment>
</unit>
<unit id="m4sdXJb" name="articles.comments">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:14</note>
</notes>
<segment>
<source>articles.comments</source>
<target>comments</target>
</segment>
</unit>
<unit id="13LrtFk" name="labels">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Labels/Labels.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Labels/Labels.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Labels/Labels.1.html.twig:4</note>
</notes>
<segment>
<source>labels</source>
<target>Labels</target>
</segment>
</unit>
<unit id="zjh9Xgo" name="gallery">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:5</note>
</notes>
<segment>
<source>gallery</source>
<target>Gallery</target>
</segment>
</unit>
<unit id="gfzu7du" name="registerMessage">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:9</note>
</notes>
<segment>
<source>registerMessage</source>
<target>To download full resolution photos, you must</target>
</segment>
</unit>
<unit id="h3gPpd5" name="register">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:9</note>
</notes>
<segment>
<source>register</source>
<target>register first.</target>
</segment>
</unit>
<unit id="IG4i0Ur" name="pressroomMessage">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:17</note>
</notes>
<segment>
<source>pressroomMessage</source>
<target>Unable to download: You are not in the Pressroom group.</target>
</segment>
</unit>
<unit id="aP9j_4L" name="download">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:28</note>
</notes>
<segment>
<source>download</source>
<target>download</target>
</segment>
</unit>
<unit id="RpfvMi0" name="sections">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:4</note>
</notes>
<segment>
<source>sections</source>
<target>Sections</target>
</segment>
</unit>
<unit id="ZrwWsR3" name="articles.all">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:10</note>
</notes>
<segment>
<source>articles.all</source>
<target>Blog</target>
</segment>
</unit>
<unit id="vg.6KZO" name="liked.article">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:3</note>
</notes>
<segment>
<source>liked.article</source>
<target>Did you like this post? Pass it on…</target>
</segment>
</unit>
<unit id="UGPQZdU" name="articles.share.x">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:15</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:15</note>
</notes>
<segment>
<source>articles.share.x</source>
<target>Share article on X</target>
</segment>
</unit>
<unit id="CnHh9m_" name="articles.share.pinterest">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:22</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:22</note>
</notes>
<segment>
<source>articles.share.pinterest</source>
<target>Share article on Pinterest</target>
</segment>
</unit>
<unit id="WgTr1MI" name="articles.read">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/ArticleSmall/ArticleSmall.1.html.twig:11</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/LineItem/LineItem.1.html.twig:14</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/SquareBasicItem/SquareBasicItem.1.html.twig:12</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/TopArticle/TopArticle.1.html.twig:13</note>
</notes>
<segment>
<source>articles.read</source>
<target>Read</target>
</segment>
</unit>
<unit id="H00mvj1" name="related.articles">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Product/Articles/Articles.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Product/Articles/Articles.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Product/Articles/Articles.1.html.twig:4</note>
</notes>
<segment>
<source>related.articles</source>
<target>Related articles</target>
</segment>
</unit>
</file>
</xliff>

View File

@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="sk">
<file id="articles.sk">
<unit id="wlCCiMH" name="articles.read.count">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ArticleInfo/ArticleInfo.1.html.twig:12</note>
</notes>
<segment>
<source>articles.read.count</source>
<target>x prečítané</target>
</segment>
</unit>
<unit id="Ctbyciv" name="author.article">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/AuthorSmall/AuthorSmall.1.html.twig:6</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/AuthorSmall/AuthorSmall.1.html.twig:6</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/AuthorSmall/AuthorSmall.1.html.twig:6</note>
</notes>
<segment>
<source>author.article</source>
<target>Autor článku</target>
</segment>
</unit>
<unit id="cBgSDGs" name="articles.share.facebook">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:10</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:10</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:8</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:8</note>
</notes>
<segment>
<source>articles.share.facebook</source>
<target>Zdieľať článok na Facebooku</target>
</segment>
</unit>
<unit id="jnYl6lu" name="articles.share">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:11</note>
</notes>
<segment>
<source>articles.share</source>
<target>Zdieľať</target>
</segment>
</unit>
<unit id="m4sdXJb" name="articles.comments">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Detail/Header/Header.1.html.twig:14</note>
</notes>
<segment>
<source>articles.comments</source>
<target>Komentáre</target>
</segment>
</unit>
<unit id="13LrtFk" name="labels">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Labels/Labels.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Labels/Labels.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Labels/Labels.1.html.twig:4</note>
</notes>
<segment>
<source>labels</source>
<target>Štítky</target>
</segment>
</unit>
<unit id="zjh9Xgo" name="gallery">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:5</note>
</notes>
<segment>
<source>gallery</source>
<target>Galéria</target>
</segment>
</unit>
<unit id="gfzu7du" name="registerMessage">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:9</note>
</notes>
<segment>
<source>registerMessage</source>
<target>Ak chcete stiahnuť fotografie v plnom rozlíšení, je nutné sa</target>
</segment>
</unit>
<unit id="h3gPpd5" name="register">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:9</note>
</notes>
<segment>
<source>register</source>
<target>zaregistrovať</target>
</segment>
</unit>
<unit id="IG4i0Ur" name="pressroomMessage">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:17</note>
</notes>
<segment>
<source>pressroomMessage</source>
<target>Nedá sa stiahnuť: Nie ste v Pressroom skupine.</target>
</segment>
</unit>
<unit id="aP9j_4L" name="download">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/PressroomGallery/PressroomGallery.1.html.twig:28</note>
</notes>
<segment>
<source>download</source>
<target>stiahnuť</target>
</segment>
</unit>
<unit id="RpfvMi0" name="sections">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:4</note>
</notes>
<segment>
<source>sections</source>
<target>Sekcie</target>
</segment>
</unit>
<unit id="ZrwWsR3" name="articles.all">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/Sections/Sections.1.html.twig:10</note>
</notes>
<segment>
<source>articles.all</source>
<target>Všetko</target>
</segment>
</unit>
<unit id="vg.6KZO" name="liked.article">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:3</note>
</notes>
<segment>
<source>liked.article</source>
<target>Páčil sa vám tento príspevok? Pošlite ho ďalej…</target>
</segment>
</unit>
<unit id="UGPQZdU" name="articles.share.x">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:15</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:15</note>
</notes>
<segment>
<source>articles.share.x</source>
<target>Zdieľať článok na X</target>
</segment>
</unit>
<unit id="CnHh9m_" name="articles.share.pinterest">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:22</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Articles/ShareButtons/ShareButtons.1.html.twig:22</note>
</notes>
<segment>
<source>articles.share.pinterest</source>
<target>Zdieľať článok na Pintereste</target>
</segment>
</unit>
<unit id="WgTr1MI" name="articles.read">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/ArticleSmall/ArticleSmall.1.html.twig:11</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/LineItem/LineItem.1.html.twig:14</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/SquareBasicItem/SquareBasicItem.1.html.twig:12</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/ArticlesList/TopArticle/TopArticle.1.html.twig:13</note>
</notes>
<segment>
<source>articles.read</source>
<target>Prečítať</target>
</segment>
</unit>
<unit id="H00mvj1" name="related.articles">
<notes>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Product/Articles/Articles.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Product/Articles/Articles.1.html.twig:4</note>
<note category="file-source" priority="1">engine/bundles/KupShop/ArticlesBundle/Resources/views/components/Product/Articles/Articles.1.html.twig:4</note>
</notes>
<segment>
<source>related.articles</source>
<target>Súvisiace články</target>
</segment>
</unit>
</file>
</xliff>

View File

@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\Resources\upgrade;
class ArticlesUpgrade extends \UpgradeNew
{
public function check_ShowInSearch(): bool
{
return $this->checkColumnExists('articles', 'show_in_search');
}
/** Add articles.show_in_search column */
public function upgrade_ShowInSearch(): void
{
sqlQuery('ALTER TABLE articles ADD COLUMN show_in_search enum (\'Y\', \'N\') default \'Y\' NULL AFTER figure');
$this->upgradeOK();
}
public function check_dateCreated(): bool
{
return $this->checkColumnExists('articles', 'date_created');
}
/** Add articles.date_created column */
public function upgrade_dateCreated(): void
{
sqlQuery('ALTER TABLE articles ADD COLUMN date_created datetime NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER date');
sqlQuery('UPDATE articles SET date_created = date WHERE 1');
$this->upgradeOK();
}
public function check_ArticlesRelatedTypes(): bool
{
return findModule(\Modules::ARTICLES_RELATED_TYPES) && $this->checkTableExists('articles_related_types');
}
/** Create `articles_related_types` table */
public function upgrade_ArticlesRelatedTypes(): void
{
sqlQuery('
CREATE TABLE articles_related_types (
`id` int auto_increment PRIMARY KEY ,
`name` VARCHAR(50) NOT NULL
);
');
$this->insertSQL('articles_related_types', ['name' => 'Související']);
$this->upgradeOK();
}
public function check_ArticlesRelatedTypeColumn(): bool
{
return findModule(\Modules::ARTICLES_RELATED_TYPES) && $this->checkColumnExists('articles_related', 'type');
}
/** Add `type` column into `articles_related_types` */
public function upgrade_ArticlesRelatedTypeColumn(): void
{
sqlQuery('ALTER TABLE articles_related ADD COLUMN `type` INT NOT NULL');
// pokud neexistuje zadnej type, tak ho pridam
if (!($typeId = sqlQuery('SELECT id FROM articles_related_types ORDER BY id ASC')->fetchOne())) {
$this->insertSQL('articles_related_types', ['name' => 'Související']);
$typeId = sqlInsertId();
}
sqlQuery('UPDATE articles_related SET type = :type WHERE type IS NULL OR type = 0', ['type' => $typeId]);
sqlQuery('ALTER TABLE articles_related ADD FOREIGN KEY (`type`) REFERENCES `articles_related_types`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;');
sqlQuery('ALTER TABLE articles_related DROP PRIMARY KEY, ADD PRIMARY KEY (id_article, id_article_related, type);');
$this->upgradeOK();
}
public function check_idBlockColumn()
{
return findModule(\Modules::ARTICLES_AUTHORS) && $this->checkColumnExists('articles_authors', 'id_block');
}
/** add id_block column into articles_authors table */
public function upgrade_idBlockColumn()
{
sqlQuery('ALTER TABLE articles_authors ADD COLUMN id_block INT(11) UNSIGNED DEFAULT NULL AFTER id');
sqlQuery('ALTER TABLE articles_authors ADD FOREIGN KEY (id_block) REFERENCES blocks(id)');
$this->upgradeOK();
}
}

View File

@@ -0,0 +1,7 @@
<div {{ attributes }}>
{% for flag in this.articleFlags %}
<a href="{{ this.sectionUrl(flag.id) }}">
<span class="flag flag-{{ this.flagClass(flag.flag_name) }} flag-{{ flag.id }}">{{ flag.name }}</span>
</a>
{% endfor %}
</div>

View File

@@ -0,0 +1,52 @@
@use "sass:map";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"padding": 5px,
"border-radius":global.$border-radius-base,
"background-color": global.$brand-primary,
"color": global.$white,
"font-weight": global.$font-weight-bold,
"font-size": global.$font-size-smaller,
"gap": global.$gap-width,
"margin-bottom": 0,
);
@if global-variable-exists(c-articles-articleflag, components) {
$keys: map.keys(components.$c-articles-articleflag);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:ArticleFlag", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-articleflag);
}
.#{component("Articles:ArticleFlag", "class")} {
display: flex;
margin-bottom: map.get($params, "margin-bottom");
gap: map.get($params, "gap");
a {
text-decoration: none;
}
.flag {
padding: map.get($params, "padding");
border-radius: map.get($params, "border-radius");
font-size: map.get($params, "font-size");
font-weight: map.get($params, "font-weight");
background-color: map.get($params, "background-color");
color: map.get($params, "color");
}
@each $name, $props in global.$article-flags {
.flag-#{$name} {
@each $prop, $val in $props {
#{$prop}: $val;
}
}
}
}

View File

@@ -0,0 +1,35 @@
{% trans_default_domain 'articles' %}
<div {{ attributes }}>
{% set separatorShown = false %}
{% if this.showDate %}
{{ this.date|date(this.dateFormat) }}
{% set separatorShown = true %}
{% endif %}
{% if this.showSeen %}
{% if separatorShown and this.showSeparator %}| {% endif %}
{{ this.seen }}{{ 'articles.read.count'|trans }}
{% set separatorShown = true %}
{% endif %}
{% if this.tags and this.showTags %}
{% if separatorShown and this.showSeparator %}|&nbsp;{% endif %}
{% for tag in this.tags %}
<a class="link" href="{{ this.tagUrl(tag.id) }}">{{ tag.tag }}</a>
{{ loop.last ? '&#8291;' : ',&nbsp;' }}
{% endfor %}
{% set separatorShown = true %}
{% endif %}
{% if this.showSection %}
{% if separatorShown and this.showSeparator %}|&nbsp;{% endif %}
<a class="link" href="{{ this.sectionUrl }}">{{ this.sectionName }}</a>
{% set separatorShown = true %}
{% endif %}
{% if this.author and this.showAuthor %}
{% if separatorShown and this.showSeparator %}|&nbsp;{% endif %}
<a class="link" href="{{ this.authorUrl }}">{{ this.author }}</a>
{% endif %}
</div>

View File

@@ -0,0 +1,42 @@
@use "sass:map";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"info-color": global.$text-muted,
"info-font-size": global.$font-size-smaller,
"link-font-weight": global.$font-weight-base,
"link-color": global.$text-dark,
"link-padding": unset,
"link-first-padding": unset,
);
@if global-variable-exists(c-articles-articleinfo, components) {
$keys: map.keys(components.$c-articles-articleinfo);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:ArticleInfo", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-articleinfo);
}
.#{component("Articles:ArticleInfo", "class")} {
display: flex;
flex-wrap: wrap;
color: map.get($params, "info-color");
font-size: map.get($params, "info-font-size");
.link {
display: inline-block;
padding: map.get($params, "link-padding");
color: map.get($params, "link-color");
font-weight: map.get($params, "link-font-weight");
&:first-of-type {
padding: map.get($params, "link-first-padding");
}
}
}

View File

@@ -0,0 +1,9 @@
{% trans_default_domain 'articles' %}
<div {{ attributes }}>
{% if this.thumbnail %}
<twig:Picture class="img-responsive" thumbnail="{{ this.thumbnail }}" type="articles_authors"/>
{% endif %}
<p class="title">{{ this.title|default('author.article'|trans) }}</p>
<a href="{{ this.authorUrl }}" class="name">{{ this.authorName }}</a>
<p class="note">{{ this.note }}</p>
</div>

View File

@@ -0,0 +1,75 @@
@use "sass:map";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"margin": global.$spacer 0,
"background": global.$body-bg-alt,
"border-radius": global.$border-radius-lg,
"padding": 30px 20px,
"img-border-radius": 50%,
"title-font-size": global.$font-size-base,
"title-color": global.$text-muted,
"title-margin": global.$spacer 0 0 0,
"note-font-size": global.$font-size-smaller,
"note-color": global.$text-dark,
"note-margin": 0,
"name-font-size": global.$font-size-larger,
"name-color": global.$text-dark,
"name-margin": 0,
);
@if global-variable-exists(c-articles-authorsmall, components) {
$keys: map.keys(components.$c-articles-authorsmall);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:AuthorSmall", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-authorsmall);
}
.#{component("Articles:AuthorSmall", "class")} {
background: map.get($params, "background");
border-radius: map.get($params, "border-radius");
padding: map.get($params, "padding");
margin: map.get($params, "margin");
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
p {
margin: 0;
}
.title {
font-size: map.get($params, "title-font-size");
color: map.get($params, "title-color");
margin: map.get($params, "title-margin");
}
.note {
font-size: map.get($params, "note-font-size");
color: map.get($params, "note-color");
margin: map.get($params, "note-margin");
}
.name {
font-size: map.get($params, "name-font-size");
color: map.get($params, "name-color");
margin: map.get($params, "name-margin");
}
.#{component("Picture", "class")} {
img {
border-radius: map.get($params, "img-border-radius");
}
}
}

View File

@@ -0,0 +1,27 @@
{% trans_default_domain 'articles' %}
<div {{ attributes }}>
<twig:Articles:ArticleFlag id_article="{{ this.article.id }}"/>
<h1 class="title">{{ this.title }}</h1>
<div class="info-wrapper">
<twig:block name="content">
<twig:Articles:ArticleInfo article="{{ this.article }}" showSection="{{ false }}"></twig:Articles:ArticleInfo>
<div class="links">
<a href="https://www.facebook.com/sharer/sharer.php?u={{ this.url }}&title={{ this.title }}" target="_blank"
rel="noopener noreferrer" aria-label="{{ 'articles.share.facebook'|trans }}" title="{{ 'articles.share.facebook'|trans }}">
<twig:ux:icon name="share" class="c-icon"/>{{ 'articles.share'|trans }}</a>
{% if module.COMMENTS %}
<a href="#comments">
<twig:ux:icon name="comment" class="c-icon"/>{{ 'articles.comments'|trans }}</a>
{% endif %}
</div>
</twig:block>
</div>
{% if this.lead %}
<p class="lead">{{ this.lead }}</p>
{% endif %}
{% if this.thumbnail %}
<twig:Picture class="img-responsive" thumbnail="{{ this.thumbnail }}" type="article_thumb_detail" alt="{{ this.title }}"/>
{% endif %}
</div>

View File

@@ -0,0 +1,96 @@
@use "sass:map";
@use "sass:math";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"margin": global.$spacer 0 global.$spacer 0,
"info-gap": 5px 10px,
"info-padding": 20px 0 0,
"info-margin": 0 0 30px,
"info-border-top": global.$border-width solid global.$border-color,
"info-border-bottom": none,
"title-margin": global.$spacer 0 20px,
"title-color": global.$headings-color,
"title-font-size": global.$font-size-h1,
"title-font-weight": global.$font-weight-bold,
"image-border": 0,
"image-border-radius": global.$border-radius-lg,
"lead-margin": 30px 0 40px,
"lead-font-size": global.$font-size-h4,
"lead-font-weight": global.$font-weight-bold,
"section-label-background-color": global.$orange,
"section-label-color": global.$white,
"links-gap": global.$spacer,
"links-display": flex,
"icons-gap": global.$gap-width,
);
@if global-variable-exists(c-articles-detail-header, components) {
$keys: map.keys(components.$c-articles-detail-header);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:Detail:Header", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-detail-header);
}
.#{component("Articles:Detail:Header", "class")} {
margin: map.get($params, "margin");
.info-wrapper {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: map.get($params, "info-gap");
border-top: map.get($params, "info-border-top");
border-bottom: map.get($params, "info-border-bottom");
padding: map.get($params, "info-padding");
margin: map.get($params, "info-margin");
}
.links {
display: map.get($params,"links-display");
gap: map.get($params, "links-gap");
}
a {
display: flex;
align-items: center;
gap: map.get($params, "icons-gap");
}
.#{component("Picture", "class")} {
border: map.get($params, "image-border");
img {
border-radius: map.get($params, "image-border-radius");
}
}
.lead {
font-size: map.get($params, "lead-font-size");
font-weight: map.get($params, "lead-font-weight");
margin: map.get($params, "lead-margin");
}
p {
margin: 0;
}
.title {
margin: map.get($params, "title-margin");
color: map.get($params, "title-color");
font-size: map.get($params, "title-font-size");
font-weight: map.get($params, "title-font-weight");
}
}

View File

@@ -0,0 +1,15 @@
{% trans_default_domain 'articles' %}
<div {{ attributes }}>
<div class="content">
<div>
<h1 class="title">{{ this.title }}</h1>
<twig:Articles:ArticleInfo article="{{ this.article }}"></twig:Articles:ArticleInfo>
<p class="lead">{{ this.lead }}</p>
</div>
<twig:Articles:ShareVertical id="{{ this.article.id }}" title="{{ this.article.title }}" image="{{ this.article.image }}"/>
</div>
{% if this.thumbnail %}
<twig:Picture class="img-responsive" thumbnail="{{ this.thumbnail }}" type="article_thumb_detail"/>
{% endif %}
</div>

View File

@@ -0,0 +1,68 @@
@use "sass:map";
@use "sass:math";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"margin": global.$spacer 0 global.$spacer 0,
"gap": 80px,
"title-margin": 0 0 20px,
"title-color": global.$headings-color,
"title-font-size": global.$font-size-h1,
"title-font-weight": global.$font-weight-bold,
"image-border": 0,
"image-border-radius": global.$border-radius-lg,
"lead-margin": 30px 0 40px 0,
"lead-font-size": global.$font-size-h4,
"lead-font-weight": global.$font-weight-base,
);
@if global-variable-exists(c-articles-detail-header-simple, components) {
$keys: map.keys(components.$c-articles-detail-header-simple);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:Detail:Header:Simple", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-detail-header-simple);
}
.#{component("Articles:Detail:Header:Simple", "class")} {
position: relative;
margin: map.get($params, "margin");
.content {
display: flex;
justify-content: space-between;
gap: map.get($params, "gap");
}
.#{component("Picture", "class")} {
border: map.get($params, "image-border");
img {
border-radius: map.get($params, "image-border-radius");
}
}
.lead {
font-size: map.get($params, "lead-font-size");
font-weight: map.get($params, "lead-font-weight");
margin: map.get($params, "lead-margin");
}
p {
margin: 0;
}
.title {
margin: map.get($params, "title-margin");
color: map.get($params, "title-color");
font-size: map.get($params, "title-font-size");
font-weight: map.get($params, "title-font-weight");
}
}

View File

@@ -0,0 +1,3 @@
<div {{ attributes }}>
<twig:block name="content"></twig:block>
</div>

View File

@@ -0,0 +1,23 @@
@use "sass:map";
@use "sass:math";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"margin":global.$spacer 0 global.$spacer 0,
);
@if global-variable-exists(c-articles-detail-panelbottom, components) {
$keys: map.keys(components.$c-articles-detail-panelbottom);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:Detail:PanelBottom", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-detail-panelbottom);
}
.#{component("Articles:Detail:PanelBottom", "class")} {
margin: map.get($params, "margin");
}

View File

@@ -0,0 +1,24 @@
<main {{ attributes }}>
<twig:block name="content">
<article class="container">
<div class="article-top">
<twig:block name="top">
</twig:block>
</div>
<div class="article-content">
<div class="article-left-side">
<twig:block name="left_side">
</twig:block>
</div>
<div class="article-right-side">
<twig:block name="right_side">
</twig:block>
</div>
</div>
<div class="article-bottom">
<twig:block name="bottom">
</twig:block>
</div>
</article>
</twig:block>
</main>

View File

@@ -0,0 +1,62 @@
@use "sass:map";
@use "sass:math";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"container-size": true,
"container-max-width": 1000px,
"breakpoint": global.$lg,
"left-side-width": percentage(math.div(3, 12)),
"right-side-width": percentage(math.div(9, 12)),
"gap": 30px,
"margin": 0 0 global.$spacer 0,
"padding-bottom": 0,
"content-margin": 40px 0,
);
@if global-variable-exists(c-articles-detail-view, components) {
$keys: map.keys(components.$c-articles-detail-view);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:Detail:View", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-detail-view);
}
.#{component("Articles:Detail:View", "class")} {
margin: map.get($params, "margin");
container-type: inline-size;
gap: map.get($params, "gap");
> .container {
@if not (map.get($params, "container-size")) {
max-width: unset;
} @else if map.get($params, "container-max-width") {
max-width: map.get($params, "container-max-width");
}
}
.article-content {
margin: map.get($params, "content-margin");
}
@container (inline-size > #{map.get($params, "breakpoint")}) {
@include global.container-query-selector(".article-content") {
display: flex;
justify-content: space-between;
}
@include global.container-query-selector(".article-right-side") {
width: calc(map.get($params, "left-side-width") - map.get($params, "gap"));
}
@include global.container-query-selector(".article-left-side") {
width: map.get($params, "right-side-width");
}
}
}

View File

@@ -0,0 +1,11 @@
{% trans_default_domain 'articles' %}
{% if this.tags|length > 0 %}
<div {{ attributes }}>
<p class="title">{{ this.title|default('labels'|trans) }}</p>
<ul>
{% for tag in this.tags %}
<li><a href="{{ this.url(tag.id, tag.tag, 'articles_tags') }}">{{ tag.tag }}</a></li>
{% endfor %}
</ul>
</div>
{% endif %}

View File

@@ -0,0 +1,131 @@
@use "sass:map";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"breakpoint": 310px,
"border-top": global.$border-width solid global.$border-color,
"gap": 5px,
"color": global.$text-dark,
"font-size": global.$font-size-base,
"font-weight": global.$font-weight-base,
"line-height": global.$line-height-sm,
"background": global.$body-bg-alt,
"padding": 5px 10px,
"border-radius": global.$border-radius-base,
"border": global.$border-width solid global.$body-bg-alt,
"hover-background": global.$body-bg-alt,
"hover-border": global.$border-width solid global.$brand-primary,
"hover-color": global.$text-dark,
"title-font-size": global.$font-size-h4,
"title-font-weight": global.$font-weight-bold,
"title-color": global.$text-dark,
"title-margin": global.$gap-width 0 global.$gap-width 0,
"lg-margin": global.$spacer 0 global.$spacer 0,
"lg-padding": 15px 20px,
"lg-gap": global.$spacer,
"lg-background": global.$body-bg-alt,
"lg-border-radius": global.$border-radius-base,
"lg-tags-gap": global.$spacer,
"lg-title-font-size": global.$font-size-base,
"lg-title-font-weight": global.$font-weight-base,
"lg-title-color": global.$text-muted,
"lg-title-margin": 0,
);
@if global-variable-exists(c-articles-labels, components) {
$keys: map.keys(components.$c-articles-labels);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:Labels", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-labels);
}
.#{component("Articles:Labels", "class")} {
border-top: map.get($params, "border-top");
ul {
@include global.list-inline;
display: flex;
gap: map.get($params, "gap");
flex-wrap: wrap;
}
li {
a {
@include global.underline-never;
display: inline-flex;
align-items: center;
justify-content: center;
padding: map.get($params, "padding");
background: map.get($params, "background");
border: map.get($params, "border");
border-radius: map.get($params, "border-radius");
color: map.get($params, "color");
font-size: map.get($params, "font-size");
font-weight: map.get($params, "font-weight");
line-height: map.get($params, "line-height");
transition:
background global.$transition-speed,
border global.$transition-speed,
color global.$transition-speed;
@include global.haf {
background: map.get($params, "hover-background");
border: map.get($params, "hover-border");
color: map.get($params, "hover-color");
}
}
}
.title {
font-size: map.get($params, "title-font-size");
font-weight: map.get($params, "title-font-weight");
color: map.get($params, "title-color");
margin: map.get($params, "title-margin");
}
@container (inline-size > #{map.get($params, "breakpoint")}) {
@include global.container-query-selector("&") {
display: flex;
border-top: none;
margin: map.get($params, "lg-margin");
gap: map.get($params, "lg-tags-gap");
padding: map.get($params, "lg-padding");
background: map.get($params, "lg-background");
border-radius: map.get($params, "lg-border-radius");
}
@include global.container-query-selector(".title") {
font-size: map.get($params, "lg-title-font-size");
font-weight: map.get($params, "lg-title-font-weight");
color: map.get($params, "lg-title-color");
margin: map.get($params, "lg-title-margin");
}
@include global.container-query-selector("ul") {
gap: map.get($params, "lg-gap");
}
@include global.container-query-selector("a") {
text-decoration: underline;
background: none;
border: none;
padding: 0;
@include global.haf {
border: none;
}
}
}
}

View File

@@ -0,0 +1,36 @@
{% trans_default_domain 'articles' %}
{% if this.photos is not empty %}
<div {{ attributes }}>
<p class="h4">
{{ 'gallery'|trans }}
</p>
{% if not this.isUserLoggedIn %}
<div class="photo-download-register">
{{ 'registerMessage'|trans }} <a href="{{ path('register') }}">{{ 'register'|trans }}</a>
</div>
{% endif %}
<div class="photo-list">
{% for photo in this.photos|slice(1) %}
<div class="photo">
<twig:Picture thumbnail="{{ this.createThumbnailFromPhoto(photo) }}" type="articles_pressroom" />
{% if this.isUserLoggedIn and not this.isPressroomUser %}
<p class="not-pressroom-user">{{ 'pressroomMessage'|trans }}</p>
{% else %}
<div class="photo-details">
{{ this.getPhotoFilesize(photo)|formatFilesize }}
<a
{% if this.isPressroomUser %}
href="{{ this.photoOriginalPath(photo) }}" download
{% else %}
role="button" data-wpj-modal="{{ path('kupshop_components_modal_modal', {template: 'login'}) }}"
{% endif %}
>
<twig:ux:icon name="arrow-down-to-line" class="c-icon" />{{ 'download'|trans }}
</a>
</div>
{% endif %}
</div>
{% endfor %}
</div>
</div>
{% endif %}

View File

@@ -0,0 +1,77 @@
@use "sass:map";
@use "sass:math";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"register-note-color": global.$brand-ctr,
"register-note-radius": global.$border-radius-sm,
"register-note-padding": 15px,
"photo-spacing": 20px,
"details-margin-top": 15px,
"details-padding": 0 15px,
"photo-warning-margin-top": 5px,
"photo-warning-margin-bottom": 0,
"photo-warning-color": global.$red,
"photo-warning-font-size": global.$font-size-smaller,
"photo-warning-line-height": global.$line-height-sm,
);
@if global-variable-exists(c-articles-pressroomgallery, components) {
$keys: map.keys(components.$c-articles-pressroomgallery);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:PressroomGallery", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-pressroomgallery);
}
.#{component("Articles:PressroomGallery", "class")} {
.photo-download-register {
padding: map.get($params, "register-note-padding");
margin-bottom: map.get($params, "register-note-padding");
border: 1px solid map.get($params, "register-note-color");
border-radius: map.get($params, "register-note-radius");
color: map.get($params, "register-note-color");
text-align: justify;
a {
font-weight: global.$font-weight-bold;
}
}
.not-pressroom-user {
margin-top: map.get($params, "photo-warning-margin-top");
margin-bottom: map.get($params, "photo-warning-margin-bottom");
color: map.get($params, "photo-warning-color");
font-size: map.get($params, "photo-warning-font-size");
line-height: map.get($params, "photo-warning-line-height");
}
.photo {
+ .photo {
margin-top: map.get($params, "photo-spacing");
}
}
.photo-details {
margin-top: map.get($params, "details-margin-top");
padding: map.get($params, "details-padding");
display: flex;
a {
margin-left: auto;
font-weight: global.$font-weight-bold;
svg {
margin-right: 10px;
vertical-align: middle;
}
}
}
}

View File

@@ -0,0 +1,20 @@
{% trans_default_domain 'articles' %}
<div {{ attributes }}>
{% if this.title %}
<p class="title">{{ this.title|default('sections'|trans) }}</p>
{% endif %}
<ul>
{% if this.id_top_branch and this.articleSections|length %}
<li>
<a href="{{ path('kupshop_content_articles_articles_1', {IDb: this.id_top_branch}) }}"
class="{% if this.id_branch == this.id_top_branch %} active{% endif %}">{{ 'articles.all'|trans }}</a>
</li>
{% endif %}
{% for section in this.articleSections %}
<li>
<a href="{{ path('kupshop_content_articles_articles_1', {IDb: section.id}) }}"
class="{% if section.id == this.id_branch %} active{% endif %}">{{ section.name|trim }}</a>
</li>
{% endfor %}
</ul>
</div>

View File

@@ -0,0 +1,118 @@
@use "sass:map";
@use "sass:math";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"margin": 0 0 global.$spacer 0,
"justify-content": flex-start,
"item-gap": global.$spacer,
"item-padding": 0 10px,
"item-text-decoration-mixin": "never",
"item-border-radius": unset,
"item-background-color": none,
"item-background-color-active": transparent,
"item-color-active": global.$text-dark,
"background-color": global.$body-bg,
"font-size": global.$font-size-larger,
"font-weight": global.$font-weight-bold,
"color": global.$text-dark,
"hover-line": true,
"hover-line-color": global.$blue,
"hover-line-size": 3px,
"title-margin": 0 0 20px 0,
"title-color": global.$headings-color,
"title-font-size": global.$font-size-h4,
"title-font-weight": global.$font-weight-bold,
);
@if global-variable-exists(c-articles-sections, components) {
$keys: map.keys(components.$c-articles-sections);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:Sections", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-sections);
}
.#{component("Articles:Sections", "class")} {
display: flex;
justify-content: map.get($params, "justify-content");
background-color: map.get($params, "background-color");
container-type: inline-size;
margin: map.get($params, "margin");
ul {
@include global.list-inline;
display: flex;
flex-wrap: wrap;
gap: map.get($params, "item-gap");
}
.title {
margin: map.get($params, "title-margin");
color: map.get($params, "title-color");
font-size: map.get($params, "title-font-size");
font-weight: map.get($params, "title-font-weight");
}
a {
@if (map.get($params, "item-text-decoration-mixin") == "never") {
@include global.underline-never;
} @else if (map.get($params, "item-text-decoration-mixin") == "hover") {
@include global.underline-hover;
} @else if (map.get($params, "item-text-decoration-mixin") == "default") {
@include global.underline-default;
}
display: block;
font-size: map.get($params, "font-size");
font-weight: map.get($params, "font-weight");
color: map.get($params, "color");
padding: map.get($params, "item-padding");
background: map.get($params, "item-background-color");
border-radius: map.get($params, "item-border-radius");
position: relative;
@if (map.get($params, "hover-line") == true) {
&::after {
content: "";
display: block;
position: absolute;
border-bottom: map.get($params, "hover-line-size") solid map.get($params, "hover-line-color");
bottom: calc(#{math.ceil(math.div(map.get($params, "hover-line-size"), 2))} * -1);
left: 50%;
width: 100%;
max-width: 0;
transition: all global.$transition-speed;
}
}
&.active {
background-color: map.get($params, "item-background-color-active");
color: map.get($params, "item-color-active");
text-decoration: none;
}
@include global.haf {
&::after {
max-width: 100%;
left: 0;
}
}
}
@container (inline-size > 500px) {
@include global.container-query-selector('ul') {
flex-direction: row;
align-items: center;
justify-content: map.get($params, "justify-content");
}
}
}

View File

@@ -0,0 +1,27 @@
{% trans_default_domain 'articles' %}
<div {{ attributes }}>
<p>{{ 'liked.article'|trans }}</p>
<div class="links">
{% if not this.hideFacebook %}
<a href="https://www.facebook.com/sharer/sharer.php?u={{ this.url }}&title={{ this.title }}"
target="_blank" rel="noopener noreferrer"
aria-label="{{ 'articles.share.facebook'|trans }}" title="{{ 'articles.share.facebook'|trans }}">
<twig:ux:icon name="fb" class="c-icon"/>
</a>
{% endif %}
{% if not this.hideX %}
<a href="https://twitter.com/intent/tweet?status={{ this.title }}&url={{ this.url }}"
target="_blank" rel="noopener noreferrer"
aria-label="{{ 'articles.share.x'|trans }}" title="{{ 'articles.share.x'|trans }}">
<twig:ux:icon name="x" class="c-icon"/>
</a>
{% endif %}
{% if not this.hidePinterest %}
<a href="https://pinterest.com/pin/create/bookmarklet/?media={{ this.shareImage }}&url={{ this.url }}&is_video=false&description={{ this.title }}"
target="_blank" rel="noopener noreferrer"
aria-label="{{ 'articles.share.pinterest'|trans }}" title="{{ 'articles.share.pinterest'|trans }}">
<twig:ux:icon name="pinterest" class="c-icon"/>
</a>
{% endif %}
</div>
</div>

View File

@@ -0,0 +1,80 @@
@use "sass:map";
@use "sass:math";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"gap": 70px,
"padding": 30px 40px,
"margin": global.$spacer-lg 0 global.$spacer-lg 0,
"text-align-sm": center,
"border-top": global.$border-width solid global.$border-color,
"border-bottom": global.$border-width solid global.$border-color,
"justify-content": center,
"title-font-size": global.$font-size-h4,
"title-font-weight": global.$font-weight-base,
"title-color": global.$text-dark,
"title-margin": 0,
"links-gap": 20px,
"links-font-size": 20px,
"links-color": global.$brand-primary,
"links-margin-sm": 10px 0 0 0,
"links-margin": 0,
"links-display": flex,
"display-sm": flex,
);
@if global-variable-exists(c-articles-sharebuttons, components) {
$keys: map.keys(components.$c-articles-sharebuttons);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:ShareButtons", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-sharebuttons);
}
.#{component("Articles:ShareButtons", "class")} {
display: map.get($params, "display-sm");
justify-content: map.get($params, "justify-content");
gap: map.get($params, "gap");
padding: map.get($params, "padding");
border-top: map.get($params, "border-top");
border-bottom: map.get($params, "border-bottom");
margin: map.get($params, "margin");
p {
font-size: map.get($params, "title-font-size");
font-weight: map.get($params, "title-font-weight");
color: map.get($params, "title-color");
margin: map.get($params, "title-margin");
text-align: map.get($params, "text-align-sm");
}
.links {
display: map.get($params, "links-display");
gap: map.get($params, "links-gap");
justify-content: center;
align-items: center;
margin: map.get($params, "links-margin-sm");
svg {
font-size: map.get($params, "links-font-size");
color: map.get($params, "links-color");
}
}
}
@container (inline-size > 600px) {
.#{component("Articles:ShareButtons", "class")} {
display: flex;
.links {
margin: map.get($params, "links-margin");
}
}
}

View File

@@ -0,0 +1,19 @@
{% trans_default_domain 'articles' %}
<div {{ attributes }}>
{#<p>{{ 'liked.article'|trans }}</p>#}
<p>Sdílet</p>
<div class="links">
{% if not this.hideFacebook %}
<a href="https://www.facebook.com/sharer/sharer.php?u={{ this.url }}&title={{ this.title }}" target="_blank" rel="noopener noreferrer">
<twig:ux:icon name="fb" class="c-icon"/></a>
{% endif %}
{% if not this.hideX %}
<a href="https://twitter.com/intent/tweet?status={{ this.title }}&url={{ this.url }}" target="_blank" rel="noopener noreferrer">
<twig:ux:icon name="x" class="c-icon"/></a>
{% endif %}
{% if not this.hidePinterest %}
<a href="https://pinterest.com/pin/create/bookmarklet/?media={{ this.shareImage }}&url={{ this.url }}&is_video=false&description={{ this.title }}" target="_blank" rel="noopener noreferrer">
<twig:ux:icon name="pinterest" class="c-icon"/></a>
{% endif %}
</div>
</div>

View File

@@ -0,0 +1,46 @@
@use "sass:map";
@use "sass:math";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"title-margin-bottom": 20px,
"title-font-size": global.$font-size-base,
"title-color": global.$text-muted,
"links-gap": 20px,
"links-font-size": 20px,
"links-color": global.$brand-primary,
);
@if global-variable-exists(c-articles-sharevertical, components) {
$keys: map.keys(components.$c-articles-sharevertical);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:ShareVertical", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-sharevertical);
}
.#{component("Articles:ShareVertical", "class")} {
p {
margin-bottom: map.get($params, "title-margin-bottom");
font-size: map.get($params, "title-font-size");
color: map.get($params, "title-color");
text-align: center;
}
.links {
display: flex;
flex-direction: column;
gap: map.get($params, "links-gap");
align-items: center;
svg {
font-size: map.get($params, "links-font-size");
color: map.get($params, "links-color");
}
}
}

View File

@@ -0,0 +1,3 @@
<div {{ attributes }}>
<twig:block name="content"></twig:block>
</div>

View File

@@ -0,0 +1,22 @@
@use "sass:map";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
);
@if global-variable-exists(c-articleslist-sidepanel, components) {
$keys: map.keys(components.$c-articleslist-sidepanel);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:SidePanel", "class")}'.";
}
}
$params: map.merge($params, components.$c-articleslist-sidepanel);
}
.#{component("Articles:SidePanel", "class")} {
container-type: inline-size;
}

View File

@@ -0,0 +1,24 @@
<main {{ attributes }}>
<twig:block name="content">
<div class="container">
<div class="articles-top">
<twig:block name="top">
</twig:block>
</div>
<div class="articles-content">
<div class="articles-left-side">
<twig:block name="left_side">
</twig:block>
</div>
<div class="articles-right-side">
<twig:block name="right_side">
</twig:block>
</div>
</div>
<div class="articles-bottom">
<twig:block name="bottom">
</twig:block>
</div>
</div>
</twig:block>
</main>

View File

@@ -0,0 +1,50 @@
@use "sass:map";
@use "sass:math";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"breakpoint": global.$lg,
"left-side-width": percentage(math.div(3, 12)),
"right-side-width": percentage(math.div(9, 12)),
"gap": 60px,
"margin": 0 0 global.$spacer 0,
"padding-bottom": 0,
"title-text-align": left,
);
@if global-variable-exists(c-articles-view, components) {
$keys: map.keys(components.$c-articles-view);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Articles:View", "class")}'.";
}
}
$params: map.merge($params, components.$c-articles-view);
}
.#{component("Articles:View", "class")} {
margin: map.get($params, "margin");
container-type: inline-size;
gap: map.get($params, "gap");
h1 {
text-align: map.get($params, "title-text-align");
}
@container (inline-size > #{map.get($params, "breakpoint")}) {
@include global.container-query-selector(".articles-content") {
display: flex;
justify-content: space-between;
}
@include global.container-query-selector(".articles-right-side") {
width: calc(map.get($params, "left-side-width") - map.get($params, "gap"));
}
@include global.container-query-selector(".articles-left-side") {
width: map.get($params, "right-side-width");
}
}
}

View File

@@ -0,0 +1,13 @@
{% trans_default_domain 'articles' %}
<div {{ attributes }}>
<a href="{{ this.url }}">
<twig:Picture class="img-responsive" thumbnail="{{ this.thumbnail|default(null) }}" type="article_thumb" alt="{{ this.title }}"/>
</a>
<div class="content">
<p class="title"><a href="{{ this.url }}">{{ this.title }}</a></p>
{% if this.showArticleInfo %}
<twig:Articles:ArticleInfo article="{{ this.article }}" showDate="{{ false }}" showTags="{{ false }}"></twig:Articles:ArticleInfo>
{% endif %}
<a href="{{ this.url }}" title="{{ this.title }}" class="btn-link">{{ 'articles.read'|trans }}</a>
</div>
</div>

View File

@@ -0,0 +1,103 @@
@use "sass:map";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"margin": 0 0 global.$spacer,
"item-background": global.$body-bg,
"item-border": 0,
"item-border-radius": global.$border-radius-base,
"gap": 0,
"btn-link-font-weight": global.$btn-font-weight,
"btn-link-underline-default": "false",
"btn-link-color": inherit,
"image-border": 0,
"image-border-radius": global.$border-radius-lg,
"image-margin": 0,
"content-padding": 0,
"title-font-size": global.$font-size-base,
"title-font-weight": global.$font-weight-bold,
"title-color": global.$text-dark,
"title-margin": global.$gap-width 0 global.$gap-width 0,
"title-line-clamp": 1,
"title-line-height": global.$headings-line-height,
"info-padding": 0 0 global.$gap-width 0,
);
@if global-variable-exists(c-articleslist-articleSmall, components) {
$keys: map.keys(components.$c-articleslist-articleSmall);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("ArticlesList:ArticleSmall", "class")}'.";
}
}
$params: map.merge($params, components.$c-articleslist-articleSmall);
}
.#{component("ArticlesList:ArticleSmall", "class")} {
flex: 1 0 100%;
display: flex;
flex-direction: column;
gap: map.get($params, "gap");
margin: map.get($params, "margin");
background: map.get($params, "item-background");
border: map.get($params, "item-border");
border-radius: map.get($params, "item-border-radius");
a:not(.link) {
@include global.underline-hover;
}
a.btn-link {
font-weight: map.get($params, "btn-link-font-weight");
color: map.get($params, "btn-link-color");
@if (map.get($params, "btn-link-underline-default") == "true") {
@include global.underline-default;
}
}
p {
margin: 0;
}
.content {
flex: 1 0 50%;
padding: map.get($params, "content-padding");
}
.title {
font-size: map.get($params, "title-font-size");
font-weight: map.get($params, "title-font-weight");
color: map.get($params, "title-color");
margin: map.get($params, "title-margin");
line-height: map.get($params, "title-line-height");
height: calc(map.get($params, "title-line-clamp") * map.get($params, "title-line-height") * map.get($params, "title-font-size"));
overflow: hidden;
-webkit-line-clamp: map.get($params, "title-line-clamp");
display: -webkit-box;
-webkit-box-orient: vertical;
}
.#{component("Articles:ArticleInfo", "class")} {
padding: map.get($params, "info-padding");
}
.#{component("Picture", "class")} {
border: map.get($params, "image-border");
border-radius: map.get($params, "image-border-radius");
overflow: hidden;
margin: map.get($params, "image-margin");
img {
margin: auto;
border-radius: map.get($params, "image-border-radius");
}
}
}

View File

@@ -0,0 +1,14 @@
{% if this.articles %}
<div {{ attributes }}>
{% if this.title %}
<p class="{{ this.title_class }}">{{ this.title }}</p>
{% endif %}
<div class="articles">
{% for item in this.articles %}
<twig:block name="content">
<twig:ArticlesList:SquareItem article="{{ item }}"/>
</twig:block>
{% endfor %}
</div>
</div>
{% endif %}

View File

@@ -0,0 +1,41 @@
@use "sass:map";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"margin": 0 0 global.$spacer 0,
"articles-gap": 30px,
"articles-gap-sm": 20px,
);
@if global-variable-exists(c-articleslist, components) {
$keys: map.keys(components.$c-articleslist);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("ArticlesList", "class")}'.";
}
}
$params: map.merge($params, components.$c-articleslist);
}
.#{component("ArticlesList", "class")} {
display: flex;
flex-direction: column;
width: 100%;
margin: map.get($params, "margin");
container-type: inline-size;
.articles {
display: flex;
flex-wrap: wrap;
gap: map.get($params, "articles-gap");
}
@media screen and (max-width: global.$sm - 1) {
.articles {
gap: map.get($params, "articles-gap-sm");
}
}
}

View File

@@ -0,0 +1,18 @@
export default {
title: "Article/ArticlesList",
args: {
title: "Blog",
limit: 4,
offset: 0,
list_show: 1,
}
};
export const ArticlesList = {
parameters: {
server: {
id: "ArticlesList"
}
}
};

View File

@@ -0,0 +1,18 @@
{% trans_default_domain 'articles' %}
<div {{ attributes }}>
<a href="{{ this.url }}" title="{{ this.title }}">
{% if this.thumbnail %}
<twig:Picture class="img-responsive" thumbnail="{{ this.thumbnail }}" type="article_thumb" is_lazy="{{ this.lazyImg }}"/>
{% endif %}
</a>
<div class="content">
<twig:Articles:ArticleFlag id_article="{{ this.article.id }}"/>
<p class="title"><a href="{{ this.url }}" title="{{ this.title }}">{{ this.title }}</a></p>
<twig:Articles:ArticleInfo article="{{ this.article }}" showSection="{{ false }}"></twig:Articles:ArticleInfo>
<p class="lead">{{ this.lead }}</p>
<a href="{{ this.url }}" title="{{ this.title }}" class="btn-link">{{ 'articles.read'|trans }}
<twig:ux:icon name="caret-right" class="c-icon arrow-icon"/>
</a>
</div>
</div>

View File

@@ -0,0 +1,107 @@
@use "sass:map";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"item-background": global.$body-bg,
"item-border": 0,
"item-border-radius": global.$border-radius-base,
"gap": 60px,
"image-border": 0,
"image-border-radius": global.$border-radius-lg,
"image-margin": 0 0 global.$spacer 0,
"content-padding": 30px 0,
"title-font-size": global.$font-size-h4,
"title-font-weight": global.$font-weight-bold,
"title-color": global.$text-dark,
"title-margin": global.$spacer 0 global.$gap-width 0,
"title-line-clamp":2,
"title-line-height": global.$headings-line-height,
"lead-line-clamp": 3,
"lead-line-height": global.$line-height-base,
"lead-font-size": global.$font-size-base,
"lead-margin": 12px 0 global.$spacer 0,
);
@if global-variable-exists(c-articleslist-lineitem, components) {
$keys: map.keys(components.$c-articleslist-lineitem);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("ArticlesList:LineItem", "class")}'.";
}
}
$params: map.merge($params, components.$c-articleslist-lineitem);
}
.#{component("ArticlesList:LineItem", "class")} {
display: flex;
flex: 1 0 100%;
gap: calc(map.get($params, "gap") / 2);
flex-direction: column;
background: map.get($params, "item-background");
border: map.get($params, "item-border");
border-radius: map.get($params, "item-border-radius");
a:not(.link) {
text-decoration: none;
}
.#{component("Picture", "class")} {
border: map.get($params, "image-border");
border-radius: map.get($params, "image-border-radius");
overflow: hidden;
margin: map.get($params, "image-margin");
img {
margin: auto;
border-radius: map.get($params, "image-border-radius");
}
}
.content {
flex: 1 0 50%;
padding: 0;
}
.title {
font-size: map.get($params, "title-font-size");
font-weight: map.get($params, "title-font-weight");
color: map.get($params, "title-color");
margin: map.get($params, "title-margin");
line-height: map.get($params, "title-line-height");
height: calc(map.get($params, "title-line-clamp") * map.get($params, "title-line-height") * map.get($params, "title-font-size"));
overflow: hidden;
-webkit-line-clamp: map.get($params, "title-line-clamp");
display: -webkit-box;
-webkit-box-orient: vertical;
}
p {
margin: 0;
}
.lead {
overflow: hidden;
-webkit-line-clamp: map.get($params, "lead-line-clamp");
display: -webkit-box;
-webkit-box-orient: vertical;
margin: map.get($params, "lead-margin");
height: calc(map.get($params, "lead-line-clamp") * map.get($params, "lead-line-height") * map.get($params, "lead-font-size"));
}
@container (inline-size > #{global.$lg}) {
@include global.container-query-selector("&") {
flex-direction: row;
gap: map.get($params, "gap");
}
@include global.container-query-selector(".content") {
padding: map.get($params, "content-padding");
}
}
}

View File

@@ -0,0 +1,15 @@
{% trans_default_domain 'articles' %}
<div {{ attributes }}>
<a href="{{ this.url }}" title="{{ this.title }}" class="article-link">
{% if this.thumbnail %}
<twig:Picture img_class="img-fluid" thumbnail="{{ this.thumbnail }}" type="article_thumb" is_lazy="{{ this.lazyImg }}"/>
{% endif %}
<div class="content">
<h3 class="heading-reset title">{{ this.title }}</h3>
{% if this.show_date %}
<p class="date">{{ this.date|date('d. m.') }}</p>
{% endif %}
<span href="{{ this.url }}" class="read-more">{{ 'articles.read'|trans }}</span>
</div>
</a>
</div>

View File

@@ -0,0 +1,123 @@
@use "sass:map";
@use "sass:math";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"breakpoint-sm": global.$sm,
"item-background": global.$body-bg,
"item-border": 0,
"item-line-height": global.$line-height-sm,
"item-margin": 0 0 calc(#{global.$spacer} * 1.5),
"image-overlay": true,
"image-border": 0,
"image-border-radius": global.$border-radius-base,
"image-margin": 0 0 global.$spacer 0,
"image-padding": 0px,
"title-font-size": global.$font-size-h4,
"title-font-weight": global.$font-weight-bold,
"title-color": global.$text-dark,
"title-margin": 0 0 8px 0,
"title-line-height": global.$headings-line-height,
"date-color": global.$text-muted,
"date-font-size": global.$font-size-smaller,
"date-margin": 0 0 12px 0,
"readmore-color": global.$text-dark,
"readmore-font-size": global.$font-size-base,
"num-of-lines": 2,
);
@if global-variable-exists(c-articleslist-squarebasicitem, components) {
$keys: map.keys(components.$c-articleslist-squarebasicitem);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("ArticlesList:SquareBasicItem", "class")}'.";
}
}
$params: map.merge($params, components.$c-articleslist-squarebasicitem);
}
.#{component("ArticlesList:SquareBasicItem", "class")} {
position: relative;
background: map.get($params, "item-background");
border: map.get($params, "item-border");
line-height: map.get($params, "item-line-height");
margin: map.get($params, "item-margin");
flex: 1 0 100%;
.article-link {
text-decoration: none;
display: block;
}
.#{component("Picture", "class")} {
@if (map.get($params, "image-overlay") == true) {
@include global.image-overlay;
}
border: map.get($params, "image-border");
border-radius: map.get($params, "image-border-radius");
overflow: hidden;
margin: map.get($params, "image-margin");
padding: map.get($params, "image-padding");
}
.title {
font-size: map.get($params, "title-font-size");
font-weight: map.get($params, "title-font-weight");
line-height: map.get($params, "title-line-height");
color: map.get($params, "title-color");
height: calc(#{map.get($params, "num-of-lines")} * #{map.get($params, "title-font-size")} * #{map.get($params, "title-line-height")});
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: map.get($params, "num-of-lines");
-webkit-box-orient: vertical;
}
.date {
color: map.get($params, "date-color");
font-size: map.get($params, "date-font-size");
margin: map.get($params, "date-margin");
}
.read-more {
display: inline-block;
font-size: map.get($params, "readmore-font-size");
color: map.get($params, "readmore-color");
text-decoration: underline;
&:hover {
text-decoration: none;
color: lighten(map.get($params, "readmore-color"), 10%);
}
}
@container (inline-size > #{map.get($params, "breakpoint-sm")}) {
@include global.container-query-selector("&") {
flex-basis: 45%;
max-width: 50%;
}
}
}
// modifikace pro bloček
// šířka podle počtu prvků (2 - 4)
.#{component("EditableContent", "class")} {
.#{component("ArticlesList:SquareBasicItem", "class")} {
@container (inline-size > #{map.get($params, "breakpoint-sm")}) {
@for $i from 2 through 4 {
@include global.container-query-selector("&:first-child:nth-last-child(#{$i}), &:first-child:nth-last-child(#{$i}) ~ .#{component("ArticlesList:SquareBasicItem", "class")}") {
flex-basis: (math.div(100, $i) - 3%);
max-width: calc(percentage(math.div(100, $i)) - #{global.$gap-width});
}
}
}
}
}

View File

@@ -0,0 +1 @@
{{ include('componentOverrides/articles.SquareItem.html.twig') }}

View File

@@ -0,0 +1 @@
@import "@twig/scss/base/componentOverrides/_articles.SquareItem";

View File

@@ -0,0 +1,18 @@
{% trans_default_domain 'articles' %}
<div {{ attributes }}>
<a href="{{ this.url }}">
<twig:Picture class="img-responsive" thumbnail="{{ this.thumbnail|default(null) }}" type="article_thumb_lg" alt="{{ this.title }}"/>
</a>
<twig:block name="content">
<div class="content">
<twig:Articles:ArticleFlag id_article="{{ this.article.id }}"/>
<p class="title"><a href="{{ this.url }}">{{ this.title }}</a></p>
<twig:Articles:ArticleInfo article="{{ this.article }}" showSection="{{ false }}"></twig:Articles:ArticleInfo>
<p class="lead">{{ this.lead }}</p>
<a href="{{ this.url }}" title="{{ this.title }}" class="btn-link">{{ 'articles.read'|trans }}
<twig:ux:icon name="caret-right" class="c-icon arrow-icon"/>
</a>
</div>
</twig:block>
</div>

View File

@@ -0,0 +1,143 @@
@use "sass:map";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"item-background": global.$body-bg,
"item-border": 0,
"item-border-radius": global.$border-radius-base,
"gap": 60px,
"align-items": stretch,
"image-border": 0,
"image-border-radius": global.$border-radius-lg,
"image-margin": 0 0 global.$spacer 0,
"content-flex": 1 0 50%,
"content-padding-sm": 0,
"content-padding": 30px 0,
"btn-link-margin": unset,
"btn-link-underline-default": "false",
"title-font-size": global.$font-size-h1,
"title-font-size-sm": global.$font-size-h3-sm,
"title-font-weight": global.$font-weight-bold,
"title-color": global.$text-dark,
"title-margin": global.$spacer 0 global.$gap-width 0,
"title-line-clamp": 2,
"title-line-height": global.$headings-line-height,
"title-underline-hover": "false",
"lead-is-clamp": "true",
"lead-line-clamp": 3,
"lead-line-height": global.$line-height-base,
"lead-font-size": global.$font-size-base,
"lead-margin": 12px 0 global.$spacer 0,
"lead-display": -webkit-box,
"lead-display-sm": none,
);
@if global-variable-exists(c-articleslist-toparticle, components) {
$keys: map.keys(components.$c-articleslist-toparticle);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("ArticlesList:TopArticle", "class")}'.";
}
}
$params: map.merge($params, components.$c-articleslist-toparticle);
}
.#{component("ArticlesList:TopArticle", "class")} {
flex: 1 0 100%;
display: flex;
align-items: map.get($params, "align-items");
gap: calc(map.get($params, "gap") / 2);
flex-direction: column;
background: map.get($params, "item-background");
border: map.get($params, "item-border");
border-radius: map.get($params, "item-border-radius");
a:not(.link) {
text-decoration: none;
}
a.btn-link {
margin: map.get($params, "btn-link-margin");
@if (map.get($params, "btn-link-underline-default") == "true") {
@include global.underline-default;
}
}
.#{component("Picture", "class")} {
border: map.get($params, "image-border");
border-radius: map.get($params, "image-border-radius");
overflow: hidden;
margin: map.get($params, "image-margin");
img {
margin: auto;
border-radius: map.get($params, "image-border-radius");
}
}
.content {
flex: map.get($params, "content-flex");
padding: map.get($params, "content-padding-sm");
}
.title {
font-size: map.get($params, "title-font-size-sm");
font-weight: map.get($params, "title-font-weight");
color: map.get($params, "title-color");
margin: map.get($params, "title-margin");
line-height: map.get($params, "title-line-height");
height: calc(map.get($params, "title-line-clamp") * map.get($params, "title-line-height") * map.get($params, "title-font-size-sm"));
overflow: hidden;
-webkit-line-clamp: map.get($params, "title-line-clamp");
display: -webkit-box;
-webkit-box-orient: vertical;
@if (map.get($params, "title-underline-hover") == "true") {
@include global.underline-hover;
}
}
p {
margin: 0;
}
.lead {
display: map.get($params, "lead-display-sm");
@if (map.get($params, "lead-is-clamp") == "true") {
overflow: hidden;
-webkit-line-clamp: map.get($params, "lead-line-clamp");
-webkit-box-orient: vertical;
margin: map.get($params, "lead-margin");
height: calc(map.get($params, "lead-line-clamp") * map.get($params, "lead-line-height") * map.get($params, "lead-font-size"));
}
}
@container (inline-size > #{global.$lg}) {
@include global.container-query-selector("&") {
flex-direction: row;
gap: map.get($params, "gap");
}
@include global.container-query-selector(".content") {
padding: map.get($params, "content-padding");
}
@include global.container-query-selector(".title") {
font-size: map.get($params, "title-font-size");
height: calc(map.get($params, "title-line-clamp") * map.get($params, "title-line-height") * map.get($params, "title-font-size"));
}
@include global.container-query-selector(".lead") {
display: map.get($params, "lead-display");
}
}
}

View File

@@ -0,0 +1,23 @@
{% if this.articles %}
<div {{ attributes }}>
<div class="articles">
{% for item in this.articles %}
<twig:block name="content">
{% if this.innerComponent == 'SquareBasicItem' %}
<twig:block name="SquareBasicItem">
<twig:ArticlesList:SquareBasicItem article="{{ item }}" lazyImg="{{ this.lazyImg }}" />
</twig:block>
{% elseif this.innerComponent == 'LineItem' %}
<twig:block name="LineItem">
<twig:ArticlesList:LineItem article="{{ item }}" lazyImg="{{ this.lazyImg }}" />
</twig:block>
{% else %}
<twig:block name="SquareItem">
<twig:ArticlesList:SquareItem article="{{ item }}" lazyImg="{{ this.lazyImg }}" />
</twig:block>
{% endif %}
</twig:block>
{% endfor %}
</div>
</div>
{% endif %}

View File

@@ -0,0 +1,79 @@
@use "sass:map";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"margin": 0 0 global.$spacer 0,
"articles-scroll": "true",
"articles-margin-lg": 0 -20px,
"articles-margin-sm": 0 -10px,
"articles-padding-x-lg": 20px,
"articles-padding-x-sm": 10px,
"articles-gap": 30px,
"articles-gap-lg": 20px,
"articles-gap-sm": 10px,
"articles-width-sm": 80%,
);
@if global-variable-exists(c-editablecontent-articleslist, components) {
$keys: map.keys(components.$c-editablecontent-articleslist);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("EditableContent:ArticlesList", "class")}'.";
}
}
$params: map.merge($params, components.$c-editablecontent-articleslist);
}
.#{component("EditableContent:ArticlesList", "class")} {
display: flex;
flex-direction: column;
width: 100%;
margin: map.get($params, "margin");
container-type: inline-size;
.articles {
display: flex;
flex-wrap: wrap;
gap: map.get($params, "articles-gap");
}
@container (inline-size < 1001px) {
@include global.container-query-selector(".articles") {
gap: map.get($params, "articles-gap-lg");
margin: map.get($params, "articles-margin-lg");
padding: 0 map.get($params, "articles-padding-x-lg");
scroll-padding-left: map.get($params, "articles-padding-x-lg");
@if (map.get($params, "articles-scroll") == "true") {
flex-wrap: nowrap;
overflow: auto hidden;
scroll-snap-type: x mandatory;
&::-webkit-scrollbar {
display: none;
}
.#{component("ArticlesList:SquareItem", "class")} {
scroll-snap-align: start;
}
}
}
}
@media screen and (max-width: global.$sm - 1) {
@include global.container-query-selector(".articles") {
margin: map.get($params, "articles-margin-sm");
padding: 0 map.get($params, "articles-padding-x-sm");
gap: map.get($params, "articles-gap-sm");
scroll-padding-left: map.get($params, "articles-padding-x-sm");
.#{component("ArticlesList:SquareItem", "class")} {
flex-basis: map.get($params, "articles-width-sm");
max-width: map.get($params, "articles-width-sm");
}
}
}
}

View File

@@ -0,0 +1,19 @@
{% trans_default_domain 'articles' %}
{% if this.articles %}
<div {{ attributes }} >
<p class="title-default">{{ this.title|default('related.articles'|trans) }}</p>
<div class="product-articles-list">
{% for item in this.articles %}
<twig:block name="content">
<twig:ArticlesList:SquareBasicItem article="{{ item }}"/>
</twig:block>
{% endfor %}
</div>
</div>
{% elseif outerScope.this.identifier is defined and this.useOuterscopeIdentifier %}
<style>
[data-target="#tabs-{{ outerScope.this.identifier }}"] {
display: none;
}
</style>
{% endif %}

View File

@@ -0,0 +1,49 @@
@use "sass:map";
@use "@twig/scss/_global" as global;
@use "@twig/scss/variables/_variables-components" as components;
$params: (
"breakpoint-sm": global.$sm,
"list-gap": global.$gap-width,
"title-margin": 0 0 global.$headings-margin-bottom,
"title-text-align": start,
"title-color": global.$text-dark,
"title-font-size": global.$font-size-h3,
"title-font-weight": global.$headings-font-weight,
);
@if global-variable-exists(c-product-articles, components) {
$keys: map.keys(components.$c-product-articles);
@each $name in $keys {
@if not map.get($params, $name) {
@warn "Neexistující proměnná '#{$name}' v komponentě '$#{component("Product:Articles", "class")}'.";
}
}
$params: map.merge($params, components.$c-product-articles);
}
.#{component("Product:Articles", "class")} {
.product-articles-list {
display: flex;
flex-wrap: wrap;
gap: map.get($params, "list-gap");
container-type: inline-size;
}
.title-default {
margin: map.get($params, "title-margin");
color: map.get($params, "title-color");
font-size: map.get($params, "title-font-size");
font-weight: map.get($params, "title-font-weight");
text-align: map.get($params, "title-text-align");
}
@container (inline-size < #{map.get($params, "breakpoint-sm")}) {
.product-articles-list {
display: block;
}
}
}

View File

@@ -0,0 +1,18 @@
import { productComponent } from '@components/Product/stories.utils';
export default {
...productComponent,
title: "Product/Articles",
};
export const Articles = {
parameters: {
server: {
id: "Product:Articles"
}
},
args: {
title: "Chcete vědět víc?",
}
};

View File

@@ -0,0 +1,53 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use KupShop\I18nBundle\Translations\ArticlesSectionsTranslation;
use KupShop\KupShopBundle\Util\StringUtil;
use Query\Operator;
use Query\Translation;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PostMount;
#[AsTwigComponent(template: '@Articles/components/Articles/ArticleFlag/ArticleFlag.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class ArticleFlag extends BaseComponent
{
public int $id_article;
private ?array $articleFlags = null;
#[PostMount]
public function loadArticleFlags(): void
{
if (empty($this->articleFlags)) {
$this->articleFlags = sqlQueryBuilder()
->select('ab.id, ab.name, ab.name as flag_name')
->from('articles_relation', 'ar')
->leftJoin('ar', 'articles_branches', 'ab', 'ar.id_branch = ab.id')
->andWhere(Operator::equals(['ar.id_art' => $this->id_article]))
->andWhere(Translation::coalesceTranslatedFields(ArticlesSectionsTranslation::class))
->execute()
->fetchAllAssociative();
}
}
public function getArticleFlags(): array
{
return $this->articleFlags ?? [];
}
public function getSectionUrl(int $id): string
{
return path('kupshop_content_articles_articles_1', ['IDb' => $id]);
}
public function getFlagClass(string $sectionName): string
{
return StringUtil::slugify($sectionName);
}
}

View File

@@ -0,0 +1,103 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Articles/ArticleInfo/ArticleInfo.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class ArticleInfo extends BaseComponent
{
public array $article;
private ?array $sections = null;
public bool $showDate = true;
public bool $showSeen = true;
public bool $showTags = true;
public bool $showSeparator = true;
public bool $showAuthor = true;
public bool $showSection = true;
public string $dateFormat = 'd. m.';
public function getSectionName(): string
{
return $this->article['section']['name'] ?? '';
}
public function getSectionUrl(): string
{
return path('kupshop_content_articles_articles_1', ['IDb' => $this->article['section']['id']]);
}
public function getDate(): string
{
$date = $this->article['date'];
if ($date instanceof \DateTime) {
return $date->format(\Settings::getDateFormat());
} else {
return $date;
}
}
public function getSeen(): int
{
return $this->article['seen'] ?? 0;
}
public function getAuthor(): ?string
{
if (empty($this->article['authors'])) {
return null;
}
$firstAuthor = reset($this->article['authors']);
if (!empty($firstAuthor['nick'])) {
return $firstAuthor['nick'];
}
return $firstAuthor['name'].' '.$firstAuthor['surname'];
}
public function getAuthorUrl(): ?string
{
if (!empty($this->article['authors'])) {
$firstAuthor = reset($this->article['authors']);
return path('kupshop_content_articles_articlesauthor', [
'authorId' => $firstAuthor['id'],
]);
}
return null;
}
public function getTags(): ?array
{
if (!empty($this->article['tags'])) {
return $this->article['tags'];
}
return null;
}
public function getTagUrl(int $id, $idKey = 'ID', $absolute = null): ?string
{
$params = [
's' => 'articles_tags',
$idKey => $id,
'TITLE' => $this->article['tags'][$id]['tag'],
];
if ($absolute) {
$params['absolute'] = 1;
}
return htmlspecialchars(createScriptURL($params), ENT_QUOTES);
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Entity\Thumbnail;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Articles/AuthorSmall/AuthorSmall.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class AuthorSmall extends BaseComponent
{
public array $author;
public ?string $title = null;
public function getAuthorName(): ?string
{
if (empty($this->author)) {
return null;
}
if (!empty($this->author['nick'])) {
return $this->author['nick'];
}
return $this->author['name'].' '.$this->author['surname'];
}
public function getAuthorUrl(): ?string
{
if (!empty($this->author)) {
return path('kupshop_content_articles_articlesauthor', [
'authorId' => $this->author['id'],
]);
}
return null;
}
public function getNote(): ?string
{
if (!empty($this->author && !empty($this->author['note']))) {
return $this->author['note'];
}
return null;
}
public function getThumbnail(): ?Thumbnail
{
if (!empty($this->author['photo'])) {
return new Thumbnail((string) $this->author['photo']['id'], $this->author['photo']['descr'], (string) $this->author['photo']['date_update']);
}
return null;
}
}

View File

@@ -0,0 +1,193 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles\Detail;
use KupShop\ArticlesBundle\Twig\Components\Articles\Utils\ArticleTrait;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Entity\Thumbnail;
use KupShop\ComponentsBundle\Interfaces\Microdata;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use KupShop\ComponentsBundle\Twig\DataProvider\MicrodataProvider;
use KupShop\KupShopBundle\Util\Compat\CtrlLoader;
use KupShop\KupShopBundle\Util\System\UrlFinder;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Articles/Detail/Header/Header.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class Header extends BaseComponent implements Microdata
{
use ArticleTrait {
getUrl as getBaseUrl;
}
public array $article;
public function __construct(
private readonly UrlFinder $urlFinder,
private readonly CtrlLoader $ctrlLoader,
) {
}
public function getUrl(): string
{
return $this->getBaseUrl($this->article['id'], null, 'article', 'IDa', 1);
}
public function getImage(): ?array
{
return $this->article['image'] ?? null;
}
public function getId(): int
{
return $this->article['id'];
}
public function getTitle(): string
{
return $this->article['title'];
}
public function getSeen(): string
{
return $this->article['seen'];
}
public function getSectionID(): string
{
return $this->article['id_branch'];
}
public function getAuthor(): ?string
{
if (empty($this->article['authors'])) {
echo 'nevim';
return null;
}
$firstAuthor = reset($this->article['authors']);
if (!empty($firstAuthor['nick'])) {
return $firstAuthor['nick'];
}
return $firstAuthor['name'].' '.$firstAuthor['surname'];
}
public function getAuthorUrl(): ?string
{
if (!empty($this->article['authors'])) {
$firstAuthor = reset($this->article['authors']);
return path('kupshop_content_articles_articlesauthor', [
'authorId' => $firstAuthor['id'],
]);
}
return null;
}
public function getDate(): string
{
return $this->article['date'];
}
public function getLead(): string
{
return $this->article['lead'];
}
public function setArticle(array $article): void
{
$this->article = $article;
}
public function initMicrodata(): array
{
$author = ['@type' => 'Person'];
if (count($_authors = $this->getAuthor()) > 1) {
foreach ($_authors as $_author) {
$author['authors']['name'] = $_author['name'].' '.$_author['surname'];
break;
}
}
$dbcfg = \Settings::getDefault();
if (empty($author['authors']['name'])) {
$author['authors']['name'] = $dbcfg['shop_firm_name'];
}
$articleMicrodata = [
'@context' => 'http://schema.org',
'@type' => 'NewsArticle',
'headline' => $this->getTitle(),
'author' => $author,
'url' => $this->urlFinder->shopUrlAbsolute($this->ctrlLoader['currUrl']['Abs']),
'publisher' => [
'@type' => 'Organization',
'name' => $dbcfg['shop_firm_name'],
'logo' => [
'@type' => 'ImageObject',
'url' => $this->urlFinder->staticUrlAbsolute('/templates/images/logo.png'),
],
],
];
if ($this->getImage()) {
$articleMicrodata['image'] = $this->urlFinder->shopUrlAbsolute($this->getImage()['src']);
}
if ($this->getDate()) {
$articleMicrodata['datePublished'] = $this->getDate();
}
if ($this->getLead()) {
$articleMicrodata['description'] = $this->getLead();
}
return [MicrodataProvider::ARTICLE => $articleMicrodata];
}
public function getTag(): ?string
{
if (!empty($this->article['tags'])) {
$firstTag = reset($this->article['tags']);
return $firstTag['tag'] ?? '';
}
return null;
}
public function getTagUrl($idKey = 'ID', $absolute = null): ?string
{
if (!empty($this->article['tags'])) {
$tag = reset($this->article['tags']);
$params = [
's' => 'articles_tags',
$idKey => $tag['id'],
'TITLE' => $tag['tag'],
];
if ($absolute) {
$params['absolute'] = 1;
}
return htmlspecialchars(createScriptURL($params), ENT_QUOTES);
}
return null;
}
public function getThumbnail(): ?Thumbnail
{
if (!empty($this->article['image'])) {
return new Thumbnail((string) $this->article['image']['id'], $this->article['image']['descr'], (string) $this->article['image']['date_update']);
}
return null;
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles\Detail\Header;
use KupShop\ArticlesBundle\Twig\Components\Articles\Detail\Header;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Articles/Detail/Header/Simple/Simple.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class Simple extends Header
{
}

View File

@@ -0,0 +1,16 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles\Detail;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Articles/Detail/PanelBottom/PanelBottom.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class PanelBottom extends BaseComponent
{
}

View File

@@ -0,0 +1,63 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles\Detail;
use KupShop\ArticlesBundle\GTM\PageViews\Article;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Entity\EditableContent;
use KupShop\ComponentsBundle\Entity\ObjectInfo;
use KupShop\ComponentsBundle\GTM\PostMount\GTMViewData;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use Symfony\Contracts\Service\Attribute\Required;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Articles/Detail/View/View.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class View extends BaseComponent
{
use GTMViewData;
private array $article;
#[Required]
public Article $gtmClass;
public function getBlockId(): ?int
{
return $this->article['id_block'] ?? null;
}
protected function getObjectInfo(): ObjectInfo
{
return new ObjectInfo(
type: 'article',
id: $this->article['id'] ?? null,
name: (translate('objects', 'blocks', true, true)['article'] ?? 'article').': '.$this->article['title'] ?? ''
);
}
public function getContent(): EditableContent
{
return new EditableContent(
blockId: $this->getBlockId(),
objectInfo: $this->getObjectInfo()
);
}
public function setArticle(array $article): void
{
$this->article = $article;
}
/**
* Je to takhle idiotsky pojmenovany abych se k tomu dostal ale zaroven se to moc nenapovidalo v twig šabloně
* Pokud existuje lepsi reseni, sem s nim pls.
*
* @deprecated
*/
public function articleForGTM(): array
{
return $this->article;
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles;
use KupShop\ArticlesBundle\Twig\Components\Articles\Utils\ArticleTrait;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Articles/Labels/Labels.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class Labels extends BaseComponent
{
use ArticleTrait;
private ?array $tags = null;
public ?string $title = null;
public function getTags(): ?array
{
if (!$this->tags) {
return $this->tags = $this->articlesUtil->getArticleTags(null, 1);
}
return $this->tags;
}
public function getUrl($id, $title, $type, $idKey = 'ID', $absolute = null): string
{
$params = [
's' => $type,
$idKey => $id,
'TITLE' => $title,
];
if ($absolute) {
$params['absolute'] = 1;
}
return htmlspecialchars(createScriptURL($params), ENT_QUOTES);
}
}

View File

@@ -0,0 +1,84 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Entity\Thumbnail;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use KupShop\ContentBundle\Util\ImageLocator;
use KupShop\KupShopBundle\Context\UserContext;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\KupShopBundle\Util\Functional\Mapping;
use KupShop\KupShopBundle\Util\System\PathFinder;
use Query\Operator;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Articles/PressroomGallery/PressroomGallery.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class PressroomGallery extends BaseComponent
{
public array $photos;
private ?array $photosHash = null;
public function __construct(
private readonly PathFinder $pathFinder,
private readonly ImageLocator $imageLocator,
) {
}
public function getIsUserLoggedIn()
{
return Contexts::get(UserContext::class)->isActive();
}
public function getIsPressroomUser()
{
return Contexts::get(UserContext::class)->isType('pressroom');
}
public function createThumbnailFromPhoto(array $photo): Thumbnail
{
return new Thumbnail($photo['id'], $photo['descr'], $photo['date_update']);
}
public function getPhotoOriginalPath(array $photo): string
{
// use special route to handle download of the original, unprocessed image
return path('kupshop_catalog_image_photosoriginal', ['photoId' => $photo['id'], 'hash' => $this->getPhotoHash($photo)]);
}
public function getPhotoFilesize(array $photo): int
{
$path = $this->pathFinder->dataPath('photos/'.$photo['source'].$photo['image_2']);
if (file_exists($path) && ($filesize = filesize($path))) {
return $filesize;
}
return 0;
}
private function getPhotoHash(array $photo): ?string
{
if ($this->photosHash === null) {
$this->photosHash = Mapping::mapKeys(
sqlQueryBuilder()
->select('*')
->from('photos')
->where(Operator::inIntArray(array_map(fn ($x) => $x['id'], $this->photos), 'id'))
->execute(),
function ($k, $v) {
$image = $this->imageLocator->getImage($v);
return [$image->getId(), $image->getHash()];
}
);
}
return $this->photosHash[$photo['id']] ?? null;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles;
use KupShop\ArticlesBundle\Twig\Components\Articles\Utils\ArticleTrait;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Articles/Sections/Sections.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class Sections extends BaseComponent
{
use ArticleTrait;
public ?int $id_branch;
public ?int $id_top_branch = null;
public ?string $title = null;
public function getArticleSections()
{
return $this->articlesUtil->getArticleSections($this->id_top_branch);
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles;
use KupShop\ArticlesBundle\Twig\Components\Articles\Utils\ArticleTrait;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use KupShop\KupShopBundle\Context\DomainContext;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Articles/ShareButtons/ShareButtons.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class ShareButtons extends BaseComponent
{
use ArticleTrait {
getUrl as getBaseUrl;
}
public int $id;
public ?array $image = null;
public string $title;
public bool $hideFacebook = false;
public bool $hideX = false;
public bool $hidePinterest = false;
public function __construct(private readonly DomainContext $domainContext)
{
}
public function getUrl(): string
{
return $this->getBaseUrl($this->id, null, 'article', 'IDa', 1);
}
public function getShareImage()
{
if (!$this->image) {
return '';
}
return "{$this->domainContext->getActiveId()}{$this->image['src']}";
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles;
use KupShop\ArticlesBundle\Twig\Components\Articles\Utils\ArticleTrait;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use KupShop\KupShopBundle\Context\DomainContext;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Articles/ShareVertical/ShareVertical.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class ShareVertical extends BaseComponent
{
use ArticleTrait {
getUrl as getBaseUrl;
}
public int $id;
public ?array $image = null;
public string $title;
public bool $hideFacebook = false;
public bool $hideX = false;
public bool $hidePinterest = false;
public function __construct(private readonly DomainContext $domainContext)
{
}
public function getUrl(): string
{
return $this->getBaseUrl($this->id, null, 'article', 'IDa', 1);
}
public function getShareImage()
{
if (!$this->image) {
return '';
}
return "{$this->domainContext->getActiveId()}{$this->image['src']}";
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Articles/SidePanel/SidePanel.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class SidePanel extends BaseComponent
{
}

View File

@@ -0,0 +1,86 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles\Utils;
use KupShop\ContentBundle\Util\ArticlesUtil;
trait ArticleTrait
{
protected ?string $url = null;
private ?array $topArticles = null;
public function __construct(private readonly ArticlesUtil $articlesUtil)
{
}
public function getUrl($id, $title, $type, $idKey = 'ID', $absolute = null): string
{
if (!$this->url) {
$params = [
's' => $type,
$idKey => $id,
'TITLE' => $title,
];
if ($absolute) {
$params['absolute'] = 1;
}
return $this->url = htmlspecialchars(createScriptURL($params), ENT_QUOTES);
}
return $this->url;
}
public function getTopArticles($count, $order_by = null, $order = 'DESC', $section = null, $section_id = null, $exclude_articles_ids = []): ?array
{
if (!$this->topArticles) {
$params = [
'count' => $count,
];
if ($order) {
$params['order'] = $order;
}
if ($order_by) {
$params['order_by'] = $order_by;
}
if ($section) {
$params['section'] = $section;
}
if ($exclude_articles_ids) {
$params['exclude_articles'] = $exclude_articles_ids;
}
if ($section_id) {
$params['section_id'] = $section_id;
}
return $this->topArticles = $this->articlesUtil->getArticles($params);
}
return $this->topArticles;
}
public function from_cat($CatID, $return = [])
{
$return[] = $CatID;
$qb = sqlQueryBuilder()
->select('id')
->from('articles_branches')
->andWhere('figure="Y" AND top_branch=:catID')
->setParameter('catID', $CatID)
->orderBy('id', 'ASC')
->execute();
foreach ($qb as $row) {
$return = $this->from_cat($row['id'], $return);
}
return $return;
}
}

View File

@@ -0,0 +1,87 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\Articles;
use KupShop\ArticlesBundle\GTM\PageViews\Articles;
use KupShop\ArticlesBundle\Twig\DataProvider\ArticleAuthorDataProvider;
use KupShop\CatalogBundle\Entity\Wrapper\ArticleAuthorWrapper;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Entity\EditableContent;
use KupShop\ComponentsBundle\Entity\ObjectInfo;
use KupShop\ComponentsBundle\GTM\PostMount\GTMViewData;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use KupShop\ContentBundle\Entity\Placeholder;
use Symfony\Contracts\Service\Attribute\Required;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PostMount;
#[AsTwigComponent(template: '@Articles/components/Articles/View/View.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class View extends BaseComponent
{
use GTMViewData;
#[Required]
public Articles $gtmClass;
private ?int $idListAuthor = null;
public ArticleAuthorWrapper $author;
#[Required]
public ArticleAuthorDataProvider $articleAuthorDataProvider;
#[PostMount]
public function postMount(): void
{
if ($this->idListAuthor) {
$this->articleAuthorDataProvider->setAuthor($this->idListAuthor);
$this->author = $this->articleAuthorDataProvider->getAuthor();
}
}
protected function getObjectInfo(): ObjectInfo
{
return new ObjectInfo(
type: 'article',
id: $this->author->getObject()->id,
name: (translate('objects', 'blocks', true, true)['articles_author'] ?? 'articles_author').': '.$this->author->getObject()->name ?? '',
placeholders: $this->getPlaceholders()
);
}
protected function getBlockId(): ?int
{
return $this->author->getObject()->id_block ?? null;
}
public function getAuthorContent(): EditableContent
{
return new EditableContent(
blockId: $this->getBlockId(),
objectInfo: $this->getObjectInfo()
);
}
public function getIsListAuthor(): bool
{
return !empty($this->idListAuthor);
}
public function setIdListAuthor(?int $idListAuthor): void
{
$this->idListAuthor = $idListAuthor;
}
/** @return Placeholder[] */
private function getPlaceholders(): array
{
return [
new Placeholder('NAME', 'Jméno autora.', fn () => $this->author->getObject()->name ?? ''),
new Placeholder('SURNAME', 'Přijmení autora.', fn () => $this->author->getObject()->surname ?? ''),
new Placeholder('NOTE', 'Popis autora.', fn () => $this->author->getObject()->note ?? ''),
new Placeholder('NICK', 'Přezdívka autora.', fn () => $this->author->getObject()->nick ?? ''),
];
}
}

View File

@@ -0,0 +1,186 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\Twig\Components;
use KupShop\ArticlesBundle\Twig\Components\Articles\Utils\ArticleTrait;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use KupShop\ContentBundle\Util\ArticleList;
use KupShop\ContentBundle\Util\ArticlesUtil;
use Query\Operator;
use Query\QueryBuilder;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PostMount;
#[AsTwigComponent(template: '@Articles/components/ArticlesList/ArticlesList.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class ArticlesList extends BaseComponent
{
use ArticleTrait {
getTopArticles as getBaseTopArticles;
}
public ?string $title = null;
public int $limit = 0;
public int $offset = 0;
public bool $loadTopArticles = false;
public bool $loadRelatedArticles = false;
public ?int $idArticleSection = null;
public ?int $idArticle = null;
public ?string $title_class = 'h2';
public ?int $id_branch = null;
public ?int $id_tag = null;
public ?\Pager $pager = null;
protected array $specs;
protected array $articles;
protected ?array $settings_branch = null;
public function __construct(protected ArticleList $articleList, private readonly ArticlesUtil $articlesUtil)
{
}
public function getArticles(): array
{
if (!isset($this->articles)) {
if ($this->loadTopArticles) {
$this->articles = $this->getTopArticles()['articles'];
} else {
$this->articleList->setImage('photo');
$this->articles = $this->articleList->getArticles(Operator::andX($this->getSpecs()));
}
}
return $this->articles;
}
public function addSpec($spec): void
{
$this->specs[] = $spec;
}
public function getSpecs(): array
{
if (!isset($this->specs)) {
$this->specs = [];
$this->addLimitOffsetSpec();
$this->addOrderSpec();
$this->addBehaviourSpecs();
$this->addTagSpec();
$this->addFilterRelatedSpec();
}
return $this->specs;
}
public function addFilterRelatedSpec(): array
{
if ($this->loadRelatedArticles) {
$this->addSpec(function (QueryBuilder $qb) {
$relatedArticlesIds = sqlQueryBuilder()
->select('id_article_related, position')
->from('articles_related')
->andWhere(Operator::equals(['id_article' => $this->idArticle]))
->orderBy('position', 'ASC');
$qb->leftJoinSubQuery('a', $relatedArticlesIds, 'arel', 'arel.id_article_related = a.id')
->andWhere('arel.id_article_related IS NOT NULL')
->orderBy('arel.position', 'ASC')
->setMaxResults($this->limit);
});
}
return $this->specs;
}
protected function addOrderSpec(): array
{
$this->addSpec(function (QueryBuilder $qb) {
$qb->orderBy('date', 'DESC');
});
return $this->specs;
}
private function addSectionSpec(): array
{
if (!empty($this->id_branch)) {
$this->addSpec(function (QueryBuilder $qb) {
$qb->andWhere('ar.id_branch = :idBranch');
$qb->setParameter('idBranch', $this->id_branch);
});
}
return $this->specs;
}
private function addTagSpec(): array
{
if (!empty($this->id_tag)) {
$this->addSpec(function (QueryBuilder $qb) {
$qb->andWhere('atr.id_tag = :idTag');
$qb->setParameter('idTag', $this->id_tag);
});
}
return $this->specs;
}
private function addBehaviourSpecs(): void
{
if (empty($this->settings_branch)) {
$this->addSectionSpec();
return;
}
switch ($this->settings_branch['behaviour'] ?? false) {
case '1': // ZOBRAZENÍ Z KONKRÉTNÍ SEKCE
$this->addSectionSpec();
break;
case '2': // ZOBRAZOVANI CLANKU V TETO SEKCI A JEJICH DCERINYCH SEKCICH
$this->addSpec(function (QueryBuilder $qb) {
$cats = $this->from_cat($this->id_branch);
$qb->andWhere(Operator::inIntArray($cats, 'ar.id_branch'));
});
break;
case '3': // ZOBRAZENÍ VŠECH ČLÁNKŮ
$this->addSpec(function (QueryBuilder $qb) {
$qb->andWhere(1);
});
break;
}
}
protected function addLimitOffsetSpec(): array
{
if ($this->pager) {
$this->addSpec($this->pager->getSpec());
}
return $this->specs;
}
public function getTopArticles(): ?array
{
if (empty($this->idArticle)) {
return $this->getBaseTopArticles($this->limit, 'date', 'DESC', 'all', $this->idArticleSection);
}
return $this->getBaseTopArticles($this->limit, 'date', 'DESC', 'all', $this->idArticleSection, [$this->idArticle]);
}
#[PostMount]
public function loadBranchSettings(): void
{
if (!empty($this->id_branch)) {
$this->settings_branch = $this->articleList->getSection(function (QueryBuilder $qb) {
$qb->andWhere(Operator::equals(['ab.id' => $this->id_branch]));
});
}
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace KupShop\ArticlesBundle\Twig\Components\ArticlesList;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/ArticlesList/ArticleSmall/ArticleSmall.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class ArticleSmall extends Item
{
public $showArticleInfo = true;
}

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\Twig\Components\ArticlesList;
use KupShop\ComponentsBundle\Entity\Thumbnail;
use KupShop\ComponentsBundle\Twig\BaseComponent;
class Item extends BaseComponent
{
public array $article;
public bool $lazyImg = false;
public function getTitle(): string
{
return $this->article['title'] ?? '';
}
public function getUrl(): string
{
return path('kupshop_content_articles_article_1', [
'IDa' => $this->article['id'],
'slug' => $this->article['seo_url'],
]);
}
public function getThumbnail(): ?Thumbnail
{
if (!empty($this->article['photoId'])) {
return new Thumbnail((string) $this->article['photoId'], $this->article['photoDescr'], (string) $this->article['photoDateUpdate']);
}
if (!empty($this->article['image'])) {
return new Thumbnail((string) $this->article['image']['id'], $this->article['image']['descr'], (string) $this->article['image']['date_update']);
}
return null;
}
public function getLead(): string
{
return $this->article['lead_in'] ?? '';
}
public function getDate(): string
{
return $this->article['date']?->format(\Settings::getDateFormat());
}
}

View File

@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\Twig\Components\ArticlesList;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/ArticlesList/LineItem/LineItem.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class LineItem extends Item
{
}

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\Twig\Components\ArticlesList;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/ArticlesList/SquareBasicItem/SquareBasicItem.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class SquareBasicItem extends Item
{
public bool $show_date = false;
}

View File

@@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\Twig\Components\ArticlesList;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/ArticlesList/SquareItem/SquareItem.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class SquareItem extends Item
{
public bool $show_flags = false;
public bool $show_lead = true;
}

View File

@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\Twig\Components\ArticlesList;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/ArticlesList/TopArticle/TopArticle.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class TopArticle extends Item
{
}

View File

@@ -0,0 +1,164 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\Twig\Components\EditableContent;
use KupShop\ComponentsBundle\Attributes\Blocek;
use KupShop\ComponentsBundle\Attributes\BlocekAttribute;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Twig\BaseComponent;
use KupShop\ComponentsBundle\Twig\Components\Utils\EditableContent\BlocekDataResult;
use KupShop\ComponentsBundle\Twig\Components\Utils\EditableContent\BlocekDataTrait;
use KupShop\ContentBundle\Util\ArticleList;
use KupShop\ContentBundle\Util\BlocekTypes;
use Query\Operator;
use Query\QueryBuilder;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PostMount;
#[AsTwigComponent(template: '@Articles/components/EditableContent/ArticlesList/ArticlesList.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
#[Blocek(lazy: true, title: 'Výpis článků')]
class ArticlesList extends BaseComponent
{
use BlocekDataTrait;
private array $articles;
#[BlocekAttribute(title: 'Počet článků')]
public int $limit = 3;
#[BlocekAttribute(title: 'Řazení', type: BlocekTypes::SELECT, options: [
'Datum' => 'date',
'Název' => 'title',
])]
public ?string $orderBy = 'date';
#[BlocekAttribute(title: 'Směr řazení', type: BlocekTypes::SELECT, options: [
'Vzestupně' => 'ASC',
'Sestupně' => 'DESC',
])]
public ?string $order = 'DESC';
#[BlocekAttribute(
title: 'Sekce',
type: BlocekTypes::AUTOCOMPLETE,
autocompleteType: 'articles_sections',
autocompleteMulti: true,
autocompletePreload: 'articlesSections'
)]
private ?BlocekDataResult $sectionsConfig = null;
#[BlocekAttribute(
title: 'Štítky',
type: BlocekTypes::AUTOCOMPLETE,
autocompleteType: 'articles_tags',
autocompleteMulti: false,
autocompletePreload: 'articles_tags'
)]
private ?BlocekDataResult $tagsConfig = null;
#[BlocekAttribute(
title: 'Autoři',
type: BlocekTypes::AUTOCOMPLETE,
autocompleteType: 'articlesAuthors',
autocompleteMulti: true,
autocompletePreload: 'articlesAuthors'
)]
public ?BlocekDataResult $authorsConfig = null;
#[BlocekAttribute(
title: 'Články',
type: BlocekTypes::AUTOCOMPLETE,
autocompleteType: 'articles',
autocompleteMulti: true,
autocompletePreload: 'articles'
)]
private ?BlocekDataResult $articlesConfig = null;
#[BlocekAttribute(title: 'Vynechání prvních')]
public int $offset = 0;
#[BlocekAttribute(
title: 'Vzhled článku',
type: BlocekTypes::SELECT,
options: [
'Výchozí' => 'SquareItem',
'Základní' => 'SquareBasicItem',
'Seznam' => 'LineItem',
]
)]
public string $innerComponent = 'SquareItem';
#[BlocekAttribute(title: 'Lazy-loading obrázků')]
public bool $lazyImg = false;
public function __construct(protected ArticleList $articleList)
{
}
public function getArticles(): array
{
if (!isset($this->articles)) {
$this->articleList->setImage('photo');
$this->articles = $this->articleList->getArticles(Operator::andX($this->getSpecs()));
}
return $this->articles;
}
#[PostMount]
public function prepareSpecs(): void
{
$this->clearSpecs();
// Limit spec
if ($this->limit > 0) {
$this->addSpec(function (QueryBuilder $qb) {
$qb->setMaxResults($this->limit);
});
}
// Offset spec
if ($this->offset > 0) {
$this->addSpec(function (QueryBuilder $qb) {
$qb->setFirstResult($this->offset);
});
}
// Order spec
if ($this->orderBy != 'undefined' && $this->order != 'undefined') {
$this->addSpec(function (QueryBuilder $qb) {
$qb->orderBy($this->orderBy, $this->order);
});
}
// All autocomplete specs
$this->buildAutocompleteSpecs([
'ar.id_branch' => $this->sectionsConfig,
'ar.id_tag' => $this->tagsConfig,
'a.id_author' => $this->authorsConfig,
'a.id' => $this->articlesConfig,
]);
}
public function setSectionsConfig(?array $sectionsConfig): void
{
$this->sectionsConfig = new BlocekDataResult($sectionsConfig);
}
public function setTagsConfig(?array $tagsConfig): void
{
$this->tagsConfig = new BlocekDataResult($tagsConfig);
}
public function setArticlesConfig(?array $articlesConfig): void
{
$this->articlesConfig = new BlocekDataResult($articlesConfig);
}
public function setAuthorsConfig(?array $authorsConfig): void
{
$this->authorsConfig = new BlocekDataResult($authorsConfig);
}
}

View File

@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\Twig\Components\Product;
use KupShop\ArticlesBundle\Twig\Components\ArticlesList;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use KupShop\ComponentsBundle\Twig\DataProvider\ProductDataTrait;
use Query\Operator;
use Query\QueryBuilder;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
#[AsTwigComponent(template: '@Articles/components/Product/Articles/Articles.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class Articles extends ArticlesList
{
use ProductDataTrait;
public ?string $title = null;
public int $limit = 4;
public bool $useOuterscopeIdentifier = true;
public function getSpecs(): array
{
parent::getSpecs();
$this->addSpec(function (QueryBuilder $qb) {
$qb->join('a', 'products_in_articles', 'pia', 'pia.id_article = a.id')
->andWhere(Operator::equals(['pia.id_product' => $this->id_product]))
->setMaxResults($this->limit);
});
return $this->specs;
}
}

View File

@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace KupShop\ArticlesBundle\Twig\Components\Search;
use KupShop\ComponentsBundle\Attributes\Component;
use KupShop\ComponentsBundle\Attributes\Version;
use Query\Operator;
use Query\QueryBuilder;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PreMount;
#[AsTwigComponent(template: '@Articles/components/ArticlesList/ArticlesList.1.html.twig')]
#[Component(1, [
new Version(1, newJs: null),
])]
class ArticlesList extends \KupShop\ArticlesBundle\Twig\Components\ArticlesList
{
public array $articleIds;
#[PreMount]
public function filterByIds(): void
{
$this->addSpec(function (QueryBuilder $qb) {
$qb->andWhere(Operator::inIntArray($this->articleIds, 'a.id'));
});
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace KupShop\ArticlesBundle\Twig\DataProvider;
use KupShop\CatalogBundle\Entity\ArticleAuthor;
use KupShop\CatalogBundle\Entity\Wrapper\ArticleAuthorWrapper;
use KupShop\I18nBundle\Translations\ArticlesAuthorsTranslation;
use KupShop\KupShopBundle\Util\Entity\EntityUtil;
use PHPUnit\Runner\Exception;
use Query\Operator;
use Query\Translation;
class ArticleAuthorDataProvider
{
protected ?ArticleAuthorWrapper $author = null;
public function __construct(
private readonly ArticleAuthorWrapper $articleAuthorWrapper,
private readonly EntityUtil $entityUtil,
) {
}
public function setAuthor(int $idAuthor): void
{
if (empty($idAuthor)) {
throw new Exception('ID author is null.');
}
$rawAuthorData = sqlQueryBuilder()
->select('au.id, au.id_block, au.name, au.surname, au.nick, au.note, au.photo')
->from('articles_authors', 'au')
->andWhere(Operator::equals(['au.id' => $idAuthor]))
->andWhere(Translation::coalesceTranslatedFields(ArticlesAuthorsTranslation::class))
->execute()
->fetchAssociative();
$author = $this->entityUtil->createEntity($rawAuthorData, ArticleAuthor::class);
$this->author = (clone $this->articleAuthorWrapper)->setObject($author);
}
public function getAuthor(): ?ArticleAuthorWrapper
{
return $this->author ?? null;
}
}

View File

@@ -0,0 +1,223 @@
<?php
namespace KupShop\ArticlesBundle\Wrapper;
use Doctrine\Common\Collections\ArrayCollection;
use KupShop\FeedsBundle\Utils\FeedUtils;
use KupShop\FeedsBundle\Wrapper\BaseWrapper;
use KupShop\FeedsBundle\Wrapper\BlockWrapper;
use KupShop\FeedsBundle\Wrapper\BlockWrapperFactory;
use KupShop\FeedsBundle\Wrapper\MultiWrapper;
use KupShop\FeedsBundle\Wrapper\PhotoWrapper;
use KupShop\FeedsBundle\Wrapper\PhotoWrapperFactory;
use KupShop\I18nBundle\Translations\ArticlesSectionsTranslation;
use KupShop\I18nBundle\Translations\ArticlesTagsTranslation;
use KupShop\KupShopBundle\Util\StringUtil;
use Query\Operator;
use Query\Translation;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Service\Attribute\Required;
class ArticleWrapper extends BaseWrapper
{
/** @var ArrayCollection */
protected $articles;
/** @var array */
protected $feedRow;
/** @var MultiWrapper */
protected $blocksWrapper;
/** @var PhotoWrapper */
protected $photoWrapper;
/** @var MultiWrapper */
protected $photosWrapper;
protected FeedUtils $feedUtils;
public function __construct(
BlockWrapper $blockWrapper,
BlockWrapperFactory $blockWrapperFactory,
PhotoWrapper $photoWrapper,
PhotoWrapperFactory $photoWrapperFactory,
FeedUtils $feedUtils,
) {
$this->blocksWrapper = new MultiWrapper($blockWrapper, $blockWrapperFactory);
$this->photoWrapper = $photoWrapper;
$this->photosWrapper = new MultiWrapper($photoWrapper, $photoWrapperFactory);
$this->feedUtils = $feedUtils;
}
#[Required]
public function setBlockWrapper(BlockWrapper $blockWrapper): void
{
$this->blockWrapper = $blockWrapper;
}
/**
* @param array|null $feedRow
*
* @private
*/
public function setFeedRow($feedRow)
{
$this->feedRow = $feedRow;
}
/**
* @private
*/
public function setArticles(ArrayCollection $articles)
{
$this->articles = $articles;
}
/** @var array */
protected $object;
/** ID článku */
public function field_id()
{
return $this->object->id ?? null;
}
/** URL odkaz */
public function field_link()
{
return path('kupshop_content_articles_article_1', [
'IDa' => $this->object->id,
'slug' => StringUtil::slugify($this->object->title),
], UrlGeneratorInterface::ABSOLUTE_URL);
}
/** Štítky */
public function field_tags()
{
if (!isset($this->articles->_tags_fetched)) {
$qb = sqlQueryBuilder()->select('atr.id_article, at.id, at.tag')->from('articles_tags_relation', 'atr')
->innerJoin('atr', 'articles_tags', 'at', 'at.id=atr.id_tag')
->where(Operator::inIntArray($this->articles->getKeys(), 'atr.id_article'))
->andWhere(Translation::coalesceTranslatedFields(ArticlesTagsTranslation::class))
->groupBy('atr.id_article, at.tag')
->orderBy('atr.id_article, at.tag');
foreach ($qb->execute() as $row) {
if (isset($this->articles[$row['id_article']])) {
$this->articles[$row['id_article']]->_tags = $this->articles[$row['id_article']]->_tags ?? [];
$this->articles[$row['id_article']]->_tags[$row['id']] = $row['tag'];
}
}
$this->articles->_tags_fetched = true;
}
return $this->object->_tags ?? [];
}
/** Sekce článků */
public function field_sections()
{
if (!isset($this->articles->_sections_fetched)) {
$qb = sqlQueryBuilder()->select('ar.id_art AS id_article, ab.id, ab.name, ab.descr')->from('articles_relation', 'ar')
->innerJoin('ar', 'articles_branches', 'ab', 'ab.id=ar.id_branch')
->where(Operator::inIntArray($this->articles->getKeys(), 'ar.id_art'))
->andWhere(Translation::coalesceTranslatedFields(ArticlesSectionsTranslation::class))
->groupBy('ar.id_art, ab.id')
->orderBy('ar.id_art, ab.id');
foreach ($qb->execute() as $row) {
if (isset($this->articles[$row['id_article']])) {
$this->articles[$row['id_article']]->_sections = $this->articles[$row['id_article']]->_sections ?? [];
$this->articles[$row['id_article']]->_sections[$row['id']] = $row['name'];
}
}
$this->articles->_sections_fetched = true;
}
return $this->object->_sections ?? [];
}
/** @private */
protected function fetchPhotos()
{
$this->feedUtils->fetchPhotos($this->articles, 'photos_articles_relation', 'id_art', 'article_thumb');
}
/** Hlavní obrázek */
public function field_main_photo()
{
$this->fetchPhotos();
return ($this->object->_main_photo['src'] ?? false) ? $this->photoWrapper->setObject($this->object->_main_photo) : null;
}
/** Ostatní obrázky */
public function field_photos()
{
$this->fetchPhotos();
return $this->photosWrapper->setObject($this->object->_photos ?? []);
}
/** Název článku */
public function field_title()
{
return $this->object->title ?? null;
}
/** Klíčová slova */
public function field_keywords()
{
return $this->object->keywords ?? null;
}
/** Anotace */
public function field_lead_in()
{
return $this->object->lead_in ?? null;
}
/** Publikováno.
*
* Y - Viditelné
* N - Skryté
*/
public function field_visibility()
{
return $this->object->figure ?? null;
}
/** Datum publikace */
public function field_date()
{
return $this->object->date ?? '';
}
/** Datum poslední úpravy */
public function field_last_change_date()
{
if (!isset($this->articles->_last_change_date_fetched)) {
$qb = sqlQueryBuilder()->select('a.id AS id_article, MAX(bh.date) AS last_change_date')
->from('articles', 'a')
->innerJoin('a', 'blocks_history', 'bh', 'bh.id_root_block=a.id_block')
->where(Operator::inIntArray($this->articles->getKeys(), 'a.id'))
->groupBy('a.id')
->orderBy('a.id');
foreach ($qb->execute() as $row) {
if (isset($this->articles[$row['id_article']])) {
$this->articles[$row['id_article']]->_last_change_date = $row['last_change_date'];
}
}
$this->articles->_last_change_date_fetched = true;
}
return $this->object->_last_change_date ?? '';
}
/** Bloky (obsah) */
public function field_blocks()
{
$this->feedUtils->fetchCollectionBlocks($this->articles);
return !empty($this->object->_raw_blocks) ? $this->blocksWrapper->setObject($this->object->_raw_blocks) : [];
}
}