feat: add a textimage element, add news design, add a footer
All checks were successful
Build / build (push) Successful in 2m32s
Build / deploy-stage (push) Successful in 3m0s
Build / switch-stage (push) Successful in 2m8s

This commit is contained in:
2024-12-13 01:07:46 +01:00
parent 9f410a339e
commit 52e962ae83
19 changed files with 546 additions and 22 deletions

View File

@@ -1,8 +1,8 @@
base: /
dependencies:
- georgringer/news
- cloonar-typo3/base
- typo3/redirects
- cloonar-typo3/base
languages:
-
title: German

View File

@@ -0,0 +1,13 @@
# Footer menu from a pid defined in constants: page.footerMenuPid
lib.footerMenu = HMENU
lib.footerMenu {
special = directory
special.value = {$page.footerMenuPid}
1 = TMENU
1 {
NO {
wrapItemAndSub = <li>|</li>
stdWrap.noTrimWrap = | | |
}
}
}

View File

@@ -1 +1,23 @@
@import './TypoScript/'
# Override tx_news templates
plugin.tx_news {
view {
templateRootPaths.100 = EXT:base/Resources/Private/Extensions/News/Templates/
partialRootPaths.100 = EXT:base/Resources/Private/Extensions/News/Partials/
}
}
# Define footerMenu here
lib.footerMenu = HMENU
lib.footerMenu {
special = directory
special.value = {$page.footerMenuPid}
1 = TMENU
1 {
NO {
wrapItemAndSub = <li>|</li>
stdWrap.noTrimWrap = | | |
}
}
}

View File

@@ -1,13 +1,12 @@
<?php
defined('TYPO3') or die();
// Add the new fields for the stats element to TCA if needed:
// This is only necessary if we need special configuration. By default Content Blocks handles field creation.
// Here we simply ensure that the fields appear in the backend form.
// Register the content element type in tt_content (only if needed, Content Blocks typically handle this automatically):
// $GLOBALS['TCA']['tt_content']['types']['cloonar_stats'] = [
// 'showitem' => 'header, number1, label1, number2, label2, number3, label3, number4, label4'
// ];
// The above is optional if Content Blocks extension is in use and config.yaml fields are applied automatically.
// Force imageorient to only have items 25 and 26
$GLOBALS['TCA']['tt_content']['columns']['imageorient']['config'] = [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
['LLL:EXT:base/Resources/Private/Language/locallang_db.xlf:imageorient.25', 25],
['LLL:EXT:base/Resources/Private/Language/locallang_db.xlf:imageorient.26', 26],
],
];

View File

@@ -0,0 +1,55 @@
.frame-type-cloonar_textimage {
margin: 2rem 0;
}
/* Mobile-first: column layout by default */
.textimage-container {
display: flex;
flex-direction: column;
gap: 2rem;
}
.textimage-wrapper {
width: 100%;
}
.textimage-header {
font-size: 1.5rem;
font-weight: bold;
margin-bottom: 1rem;
}
.textimage-text {
font-size: 1rem;
line-height: 1.5;
}
.textimage-image-wrapper {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.textimage-image {
max-width: 100%;
height: auto;
border-radius: 0.5rem;
}
/* Image positions: 25 = left, 26 = right
On larger screens, adjust the layout */
@media (min-width: 768px) {
.textimage-container.image-pos-25 {
flex-direction: row;
}
.textimage-container.image-pos-26 {
flex-direction: row-reverse;
}
.textimage-wrapper,
.textimage-image-wrapper {
flex: 1 1 50%;
}
}

View File

@@ -0,0 +1,19 @@
name: cloonar/textimage
typeName: cloonar_textimage
group: default
prefixFields: true
prefixType: full
fields:
- identifier: header
useExistingField: true
- identifier: bodytext
type: Textarea
enableRichtext: true
useExistingField: true
- identifier: image
type: File
properties:
allowed: [jpg, jpeg, png, gif]
useExistingField: true
- identifier: imageorient
useExistingField: true

View File

@@ -0,0 +1,14 @@
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file datatype="plaintext" original="labels.xlf" source-language="en" product-name="cloonar/textimage">
<header/>
<body>
<trans-unit id="title">
<source>Text/Image Element</source>
</trans-unit>
<trans-unit id="description">
<source>A text and image element with adjustable image position.</source>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -0,0 +1,26 @@
<html
xmlns:be="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers"
data-namespace-typo3-fluid="true"
>
<f:layout name="Preview"/>
<f:section name="Header">
<be:link.editRecord uid="{data.uid}" table="{data.mainType}">
<f:if condition="{data.header}">
<f:then>{data.header}</f:then>
<f:else>Text/Image Element</f:else>
</f:if>
</be:link.editRecord>
</f:section>
<f:section name="Content">
<f:if condition="{data.bodytext}">
<f:then>
<p>Preview: <f:format.crop maxCharacters="50">{data.bodytext}</f:format.crop></p>
</f:then>
<f:else>
<p>No text available</p>
</f:else>
</f:if>
</f:section>
</html>

View File

@@ -0,0 +1,29 @@
<f:layout name="Default" />
<f:section name="Header" />
<f:section name="Main">
<f:asset.css identifier="CBTextImage" href="{cb:assetPath()}/frontend.css" />
<div class="textimage-container image-pos-{data.imageorient}">
<div class="textimage-wrapper">
<f:if condition="{data.header}">
<h2 class="textimage-header">{data.header}</h2>
</f:if>
<f:if condition="{data.bodytext}">
<div class="textimage-text">
<f:format.html>{data.bodytext}</f:format.html>
</div>
</f:if>
</div>
<div class="textimage-image-wrapper">
<f:if condition="{data.image}">
<f:then>
<f:image image="{data.image.0}" alt="{data.header}" class="textimage-image" />
</f:then>
<f:else>
<p>No image available</p>
</f:else>
</f:if>
</div>
</div>
</f:section>

View File

@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<f:section name="Header"></f:section>
</head>
<body>
<f:section name="main"></f:section>
</body>
</html>

View File

@@ -0,0 +1,13 @@
<div class="news-item-featured">
<f:if condition="{newsItem.media}">
<f:image image="{newsItem.media.0}" class="news-item-featured-image" alt="{newsItem.title}" />
</f:if>
<div class="news-item-featured-content">
<!-- Category and Title -->
<f:if condition="{newsItem.firstCategory}">
<div class="news-item-category">{newsItem.firstCategory.title}</div>
</f:if>
<h3 class="news-item-title">{newsItem.title}</h3>
<f:link.page pageUid="{newsItem.link}" class="news-item-link"> </f:link.page>
</div>
</div>

View File

@@ -0,0 +1,12 @@
<div class="news-item-grid">
<f:if condition="{newsItem.media}">
<f:image image="{newsItem.media.0}" class="news-item-grid-image" alt="{newsItem.title}" />
</f:if>
<div class="news-item-grid-content">
<f:if condition="{newsItem.firstCategory}">
<div class="news-item-category">{newsItem.firstCategory.title}</div>
</f:if>
<h5 class="news-item-title">{newsItem.title}</h5>
<f:link.page pageUid="{newsItem.link}" class="news-item-link"> </f:link.page>
</div>
</div>

View File

@@ -0,0 +1,12 @@
<div class="news-item-side">
<f:if condition="{newsItem.media}">
<f:image image="{newsItem.media.0}" class="news-item-side-image" alt="{newsItem.title}" />
</f:if>
<div class="news-item-side-content">
<f:if condition="{newsItem.firstCategory}">
<div class="news-item-category">{newsItem.firstCategory.title}</div>
</f:if>
<h4 class="news-item-title">{newsItem.title}</h4>
<f:link.page pageUid="{newsItem.link}" class="news-item-link"> </f:link.page>
</div>
</div>

View File

@@ -0,0 +1,55 @@
<f:layout name="General" />
<f:section name="content">
<f:if condition="{news}">
<f:then>
<div class="news-list-container">
<!-- First 4 items: 1 large on the left and 3 stacked on the right -->
<f:if condition="{news -> f:count()} > 0">
<div class="news-featured-wrapper">
<div class="news-featured-item">
<f:for each="{news}" as="item" iteration="iterator">
<f:if condition="{iterator.index} == 0">
<f:then>
<f:render partial="News/ItemFeatured" arguments="{newsItem: item}" />
</f:then>
</f:if>
</f:for>
</div>
<div class="news-side-items">
<f:for each="{news}" as="item" iteration="iterator">
<f:if condition="{iterator.index} > 0 && {iterator.index} < 4">
<f:then>
<f:render partial="News/ItemSide" arguments="{newsItem: item}" />
</f:then>
</f:if>
</f:for>
</div>
</div>
</f:if>
<!-- Remaining items in a responsive grid of 3 columns -->
<f:if condition="{news -> f:count()} > 4">
<div class="news-list-grid">
<f:for each="{news}" as="item" iteration="iterator">
<f:if condition="{iterator.index} >= 4">
<f:then>
<f:render partial="News/ItemGrid" arguments="{newsItem: item}" />
</f:then>
</f:if>
</f:for>
</div>
</f:if>
<!-- "Alle anzeigen" button if listPid is set -->
<f:if condition="{settings.listPid}">
<div class="news-show-all">
<f:link.page pageUid="{settings.listPid}" class="btn-show-all">Alle anzeigen</f:link.page>
</div>
</f:if>
</div>
</f:then>
<f:else>
<p>No news available.</p>
</f:else>
</f:if>
</f:section>

View File

@@ -1,11 +1,17 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<xliff version="1.0">
<file source-language="en" datatype="plaintext" original="messages" date="2024-12-11UTC16:10:160">
<file source-language="en" datatype="plaintext" original="messages">
<header>
<authorName>Test</authorName>
<authorEmail>test@test.at</authorEmail>
</header>
<body>
<trans-unit id="imageorient.25">
<source>Image on left</source>
</trans-unit>
<trans-unit id="imageorient.26">
<source>Image on right</source>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -8,14 +8,26 @@
<f:render section="Main" />
</main>
<footer>
<f:cObject
typoscriptObjectPath="lib.dynamicContentSlide"
data="{pageUid: '{data.uid}', colPos: '90'}"
/>
<f:cObject
typoscriptObjectPath="lib.dynamicContentSlide"
data="{pageUid: '{data.uid}', colPos: '91'}"
/>
<p>&copy; {f:format.date(date: 'now', format: 'Y')} Your Company</p>
<footer class="site-footer">
<div class="site-footer__top">
<div class="container site-footer__grid">
<div class="site-footer__left">
<f:cObject typoscriptObjectPath="lib.dynamicContentSlide" data="{pageUid: '{data.uid}', colPos: '90'}" />
</div>
<div class="site-footer__right">
<f:cObject typoscriptObjectPath="lib.dynamicContentSlide" data="{pageUid: '{data.uid}', colPos: '91'}" />
</div>
</div>
</div>
<hr class="site-footer__divider" />
<div class="site-footer__bottom">
<div class="container site-footer__bottom-grid">
<ul class="site-footer__legal">
<f:cObject typoscriptObjectPath="lib.footerMenu" />
</ul>
<p class="site-footer__copyright">© All Right Reserved</p>
</div>
</div>
</footer>

View File

@@ -0,0 +1,81 @@
.site-footer {
background: #f8f8ea;
color: #4b4b4b;
font-size: 0.9rem;
padding: 2rem 0;
&__top {
padding-bottom: 2rem;
}
&__grid {
display: flex;
flex-direction: column;
gap: 2rem;
}
&__left, &__right {
flex: 1 1 100%;
}
@media (min-width: 768px) {
&__grid {
flex-direction: row;
gap: 4rem;
}
&__left, &__right {
flex: 1;
}
}
&__divider {
border: none;
border-top: 1px solid #4b4b4b;
margin: 2rem 0;
}
&__bottom-grid {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: 1rem;
}
@media (min-width: 768px) {
&__bottom-grid {
flex-direction: row;
justify-content: space-between;
text-align: left;
}
}
&__legal {
list-style: none;
display: flex;
gap: 2rem;
padding: 0;
margin: 0;
}
&__copyright {
font-size: 0.9rem;
}
}
/* Social links styling based on href */
a[href*="instagram.com"], a[href*="tiktok.com"], a[href*="linkedin.com"], a[href*="twitter.com"], a[href*="x.com"] {
display: inline-block;
text-decoration: none;
color: #4b4b4b;
transition: color 0.3s ease;
}
a[href*="instagram.com"]:hover,
a[href*="tiktok.com"]:hover,
a[href*="linkedin.com"]:hover,
a[href*="twitter.com"]:hover,
a[href*="x.com"]:hover {
color: #6B8E23;
}

View File

@@ -0,0 +1,144 @@
.news-list-container {
margin: 2rem 0;
}
/* Mobile-first: single column by default */
/* All items in a single column */
.news-featured-wrapper,
.news-side-items,
.news-list-grid {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
}
.news-item-featured,
.news-item-side,
.news-item-grid {
position: relative;
border-radius: 0.5rem;
overflow: hidden;
}
.news-item-featured-image,
.news-item-side-image,
.news-item-grid-image {
width: 100%;
height: auto;
display: block;
}
.news-item-featured-content,
.news-item-side-content,
.news-item-grid-content {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 1rem;
background: #215A2A;
color: #fff;
}
.news-item-category {
font-size: 0.9rem;
opacity: 0.9;
}
.news-item-title {
font-size: 1.2rem;
font-weight: bold;
margin-top: 0.5rem;
}
.news-item-link {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
}
.news-show-all {
margin-top: 2rem;
text-align: center;
}
.btn-show-all {
display: inline-block;
background: #6B8E23;
color: #fff;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
text-decoration: none;
font-weight: bold;
}
/* Adjust the title size for side and grid items */
.news-item-side-content .news-item-title,
.news-item-grid-content .news-item-title {
font-size: 1rem;
}
@media (min-width: 768px) and (max-width: 991px) {
/* On medium screens: switch to a 3-column grid for the first four items.
First four items are equal size and placed in a 3x grid. */
.news-featured-wrapper {
grid-template-columns: repeat(3, 1fr);
}
/* For the first four items, we treat them all equally:
The first item (featured) plus next three (side items) fill a 3-column grid equally. */
.news-side-items {
display: contents; /* Merge side items into the same grid */
}
/* Additional items still in a 3-column grid */
.news-list-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (min-width: 992px) {
/* On wide screens: special layout:
- First item bigger: takes 2 columns and 3 rows
- Next 3 items stacked in one column (3 rows) to the right of the big one
We'll create a 3-column grid for the first 4 items:
The first item (featured) will occupy the first two columns and span 3 rows.
The next 3 side items will each occupy the third column in their own row.
*/
.news-featured-wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: auto;
gap: 1rem;
}
/* The featured item (index 0) spans 2 columns and 3 rows */
.news-featured-item {
grid-column: 1 / span 2;
grid-row: 1 / span 3;
}
/* Side items should appear in the third column, one per row */
.news-side-items {
display: contents;
}
.news-side-items .news-item-side:nth-of-type(1) {
grid-column: 3;
grid-row: 1;
}
.news-side-items .news-item-side:nth-of-type(2) {
grid-column: 3;
grid-row: 2;
}
.news-side-items .news-item-side:nth-of-type(3) {
grid-column: 3;
grid-row: 3;
}
/* Additional items still in a 3-column grid below the first four */
.news-list-grid {
grid-template-columns: repeat(3, 1fr);
}
}

View File

@@ -2,3 +2,6 @@
@import 'abstracts/mixins';
@import 'base/base';
@import 'components/navigation';
@import 'components/contentElements';
@import 'components/news';
@import 'components/footer';