Skip to content

Commit 9d2f03e

Browse files
authored
Merge pull request #6344 from WoltLab/6.2-content-interaction-tabs
Content interaction tabs
2 parents dfc34ba + 5b277bc commit 9d2f03e

4 files changed

Lines changed: 139 additions & 8 deletions

File tree

com.woltlab.wcf/templates/contentInteraction.tpl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
{/capture}
2727
{assign var='__contentInteractionShareButton' value=$__contentInteractionShareButton|trim}
2828

29-
{if $__contentInteractionPagination || $__contentInteractionButtons || $__contentInteractionDropdownItems || $__contentInteractionShareButton}
30-
<div class="contentInteraction">
31-
{if $__contentInteractionPagination}
29+
{if $contentInteractionTabsComponent|isset || $__contentInteractionPagination || $__contentInteractionButtons || $__contentInteractionDropdownItems || $__contentInteractionShareButton}
30+
<div class="contentInteraction{if $contentInteractionTabsComponent|isset} contentInteraction--withTabs{/if}">
31+
{if $contentInteractionTabsComponent|isset}
32+
{unsafe:$contentInteractionTabsComponent->render()}
33+
{elseif $__contentInteractionPagination}
3234
<div class="contentInteractionPagination paginationTop">
3335
{@$__contentInteractionPagination}
3436
</div>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<ul class="contentInteractionTabs">
2+
{foreach from=$tabs item='tab'}
3+
<li class="contentInteractionTab{if $tab->active} contentInteractionTab--active{/if}">
4+
<a
5+
href="{$tab->link}"
6+
class="contentInteractionTab__link"
7+
{if $tab->active} aria-current="page"{/if}
8+
>
9+
{lang}{$tab->title}{/lang}
10+
</a>
11+
</li>
12+
{/foreach}
13+
</ul>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
namespace wcf\system\view\component;
4+
5+
use wcf\system\WCF;
6+
7+
/**
8+
* Represents the component of the tabs shown in the content interaction section.
9+
*
10+
* @author Marcel Werk
11+
* @copyright 2001-2025 WoltLab GmbH
12+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
13+
* @since 6.2
14+
*/
15+
final class ContentInteractionTabsComponent
16+
{
17+
/**
18+
* @var list<ContentInteractionTab>
19+
*/
20+
private array $tabs = [];
21+
22+
public function addTab(string $title, string $link, bool $active = false): void
23+
{
24+
if ($active && $this->getActiveTab() !== null) {
25+
throw new \BadMethodCallException("The tab '{$this->getActiveTab()->link}' is already marked as active");
26+
}
27+
28+
$this->tabs[] = new ContentInteractionTab($title, $link, $active);
29+
}
30+
31+
private function getActiveTab(): ?ContentInteractionTab
32+
{
33+
return \array_find($this->tabs, static fn($tab) => $tab->active);
34+
}
35+
36+
public function render(): string
37+
{
38+
if (!$this->tabs === []) {
39+
return '';
40+
}
41+
42+
return WCF::getTPL()->render(
43+
'wcf',
44+
'shared_contentInteractionTabs',
45+
[
46+
'tabs' => $this->tabs,
47+
],
48+
);
49+
}
50+
}
51+
52+
/** @internal */
53+
final class ContentInteractionTab
54+
{
55+
public function __construct(
56+
public readonly string $title,
57+
public readonly string $link,
58+
public readonly bool $active,
59+
) {}
60+
}

wcfsetup/install/files/style/layout/content.scss

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -424,12 +424,7 @@ fieldset {
424424

425425
.contentInteraction {
426426
display: flex;
427-
justify-content: space-between;
428427
margin-top: 20px;
429-
430-
@include screen-xs {
431-
flex-wrap: wrap;
432-
}
433428
}
434429

435430
.contentInteractionPagination {
@@ -520,6 +515,9 @@ fieldset {
520515
}
521516

522517
.content {
518+
container-type: inline-size;
519+
container-name: content;
520+
523521
.contentInteraction + .section,
524522
.contentInteraction + form {
525523
margin-top: 20px;
@@ -571,3 +569,61 @@ fieldset {
571569
}
572570
}
573571
}
572+
573+
.contentInteraction--withTabs {
574+
border-bottom: solid 1px var(--wcfContentBorderInner);
575+
}
576+
577+
.contentInteractionTabs {
578+
display: flex;
579+
gap: 10px;
580+
}
581+
582+
.contentInteractionTab {
583+
display: flex;
584+
white-space: nowrap;
585+
}
586+
587+
.contentInteractionTab__link {
588+
display: flex;
589+
padding: 5px 10px;
590+
color: var(--wcfContentDimmedText);
591+
font-size: var(--wcfFontSizeSection);
592+
font-weight: 600;
593+
position: relative;
594+
}
595+
596+
.contentInteractionTab__link::after {
597+
content: "";
598+
left: 0;
599+
right: 0;
600+
bottom: -1px;
601+
position: absolute;
602+
height: 3px;
603+
}
604+
605+
.contentInteractionTab--active .contentInteractionTab__link {
606+
color: var(--wcfContentText);
607+
}
608+
609+
.contentInteractionTab__link:hover {
610+
color: var(--wcfContentText);
611+
}
612+
613+
.contentInteractionTab__link:hover::after {
614+
background-color: var(--wcfContentBorderInner);
615+
}
616+
617+
.contentInteractionTab--active .contentInteractionTab__link::after {
618+
background-color: var(--wcfTabularBoxHeadline);
619+
}
620+
621+
@container content (width < 800px) {
622+
.contentInteraction {
623+
flex-direction: column;
624+
}
625+
626+
.contentInteractionButtonContainer {
627+
order: -1;
628+
}
629+
}

0 commit comments

Comments
 (0)