diff --git a/com.woltlab.wcf/templates/contentInteraction.tpl b/com.woltlab.wcf/templates/contentInteraction.tpl index c851535757e..9d3732ab944 100644 --- a/com.woltlab.wcf/templates/contentInteraction.tpl +++ b/com.woltlab.wcf/templates/contentInteraction.tpl @@ -26,9 +26,11 @@ {/capture} {assign var='__contentInteractionShareButton' value=$__contentInteractionShareButton|trim} -{if $__contentInteractionPagination || $__contentInteractionButtons || $__contentInteractionDropdownItems || $__contentInteractionShareButton} -
- {if $__contentInteractionPagination} +{if $contentInteractionTabsComponent|isset || $__contentInteractionPagination || $__contentInteractionButtons || $__contentInteractionDropdownItems || $__contentInteractionShareButton} +
+ {if $contentInteractionTabsComponent|isset} + {unsafe:$contentInteractionTabsComponent->render()} + {elseif $__contentInteractionPagination}
{@$__contentInteractionPagination}
diff --git a/com.woltlab.wcf/templates/shared_contentInteractionTabs.tpl b/com.woltlab.wcf/templates/shared_contentInteractionTabs.tpl new file mode 100644 index 00000000000..334857099fd --- /dev/null +++ b/com.woltlab.wcf/templates/shared_contentInteractionTabs.tpl @@ -0,0 +1,13 @@ + diff --git a/wcfsetup/install/files/lib/system/view/component/ContentInteractionTabsComponent.class.php b/wcfsetup/install/files/lib/system/view/component/ContentInteractionTabsComponent.class.php new file mode 100644 index 00000000000..a5b91adc510 --- /dev/null +++ b/wcfsetup/install/files/lib/system/view/component/ContentInteractionTabsComponent.class.php @@ -0,0 +1,60 @@ + + * @since 6.2 + */ +final class ContentInteractionTabsComponent +{ + /** + * @var list + */ + private array $tabs = []; + + public function addTab(string $title, string $link, bool $active = false): void + { + if ($active && $this->getActiveTab() !== null) { + throw new \BadMethodCallException("The tab '{$this->getActiveTab()->link}' is already marked as active"); + } + + $this->tabs[] = new ContentInteractionTab($title, $link, $active); + } + + private function getActiveTab(): ?ContentInteractionTab + { + return \array_find($this->tabs, static fn($tab) => $tab->active); + } + + public function render(): string + { + if (!$this->tabs === []) { + return ''; + } + + return WCF::getTPL()->render( + 'wcf', + 'shared_contentInteractionTabs', + [ + 'tabs' => $this->tabs, + ], + ); + } +} + +/** @internal */ +final class ContentInteractionTab +{ + public function __construct( + public readonly string $title, + public readonly string $link, + public readonly bool $active, + ) {} +} diff --git a/wcfsetup/install/files/style/layout/content.scss b/wcfsetup/install/files/style/layout/content.scss index b2c81fe6146..bf81fe134b2 100644 --- a/wcfsetup/install/files/style/layout/content.scss +++ b/wcfsetup/install/files/style/layout/content.scss @@ -424,12 +424,7 @@ fieldset { .contentInteraction { display: flex; - justify-content: space-between; margin-top: 20px; - - @include screen-xs { - flex-wrap: wrap; - } } .contentInteractionPagination { @@ -520,6 +515,9 @@ fieldset { } .content { + container-type: inline-size; + container-name: content; + .contentInteraction + .section, .contentInteraction + form { margin-top: 20px; @@ -571,3 +569,61 @@ fieldset { } } } + +.contentInteraction--withTabs { + border-bottom: solid 1px var(--wcfContentBorderInner); +} + +.contentInteractionTabs { + display: flex; + gap: 10px; +} + +.contentInteractionTab { + display: flex; + white-space: nowrap; +} + +.contentInteractionTab__link { + display: flex; + padding: 5px 10px; + color: var(--wcfContentDimmedText); + font-size: var(--wcfFontSizeSection); + font-weight: 600; + position: relative; +} + +.contentInteractionTab__link::after { + content: ""; + left: 0; + right: 0; + bottom: -1px; + position: absolute; + height: 3px; +} + +.contentInteractionTab--active .contentInteractionTab__link { + color: var(--wcfContentText); +} + +.contentInteractionTab__link:hover { + color: var(--wcfContentText); +} + +.contentInteractionTab__link:hover::after { + background-color: var(--wcfContentBorderInner); +} + +.contentInteractionTab--active .contentInteractionTab__link::after { + background-color: var(--wcfTabularBoxHeadline); +} + +@container content (width < 800px) { + .contentInteraction { + flex-direction: column; + } + + .contentInteractionButtonContainer { + order: -1; + } +}