From 197e246c45ab094ea3ca69bfa34811260ba27c3c Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Mon, 19 Oct 2026 14:53:50 +0200 Subject: [PATCH 01/10] Add the page footer layout style option and move the classic footer CSS into its own stylesheet --- com.woltlab.wcf/defaultStyle.tar | Bin 20480 -> 20480 bytes .../templates/system_pageFooter.tpl | 21 ++ defaultStyle/variables.xml | 1 + .../__styleOptionPreview_pageFooterLayout.tpl | 27 ++ ...ate_com.woltlab.wcf_6.3_styleVariables.php | 15 +- .../files/lib/data/style/Style.class.php | 16 ++ .../lib/system/style/StyleCompiler.class.php | 6 +- .../style/option/PageFooterLayout.class.php | 88 +++++++ wcfsetup/install/files/style/layout/box.scss | 174 +----------- .../files/style/layout/pageFooter.scss | 28 -- .../style/layout/pageFooter/classic.scss | 247 ++++++++++++++++++ .../style/layout/pageFooter/compact.scss | 0 wcfsetup/install/lang/de.xml | 5 + wcfsetup/install/lang/en.xml | 5 + wcfsetup/setup/db/install.sql | 1 + 15 files changed, 426 insertions(+), 208 deletions(-) create mode 100644 com.woltlab.wcf/templates/system_pageFooter.tpl create mode 100644 wcfsetup/install/files/acp/templates/__styleOptionPreview_pageFooterLayout.tpl create mode 100644 wcfsetup/install/files/lib/system/style/option/PageFooterLayout.class.php delete mode 100644 wcfsetup/install/files/style/layout/pageFooter.scss create mode 100644 wcfsetup/install/files/style/layout/pageFooter/classic.scss create mode 100644 wcfsetup/install/files/style/layout/pageFooter/compact.scss diff --git a/com.woltlab.wcf/defaultStyle.tar b/com.woltlab.wcf/defaultStyle.tar index 268e6e1bc065fb11cf4f5bf721f91da2e4ba9ffc..401f31bb388406c4c72a6faa8a400c02423b008d 100644 GIT binary patch delta 99 zcmZozz}T>WaYF{%#0+UE15-0|218RLGgA{oLla{o1_MI_Q$s@r1%t_gj47KL*?%!= zyXEJXq!#%kR_2$MDB0O4MmxJWhB!ti=jRqACYQv<+S%xrB^G5SCgr3~e!_8U5tkbP DWGfzx delta 62 zcmZozz}T>WaYF_hv$?tX + {if ENABLE_DEBUG_MODE} + + {/if} +{/if} + +
+ {include file='pageFooterCopyright'} +
diff --git a/defaultStyle/variables.xml b/defaultStyle/variables.xml index 1b04934cf4e..b5ef577f567 100644 --- a/defaultStyle/variables.xml +++ b/defaultStyle/variables.xml @@ -1,4 +1,5 @@ + diff --git a/wcfsetup/install/files/acp/templates/__styleOptionPreview_pageFooterLayout.tpl b/wcfsetup/install/files/acp/templates/__styleOptionPreview_pageFooterLayout.tpl new file mode 100644 index 00000000000..6ae926f37f3 --- /dev/null +++ b/wcfsetup/install/files/acp/templates/__styleOptionPreview_pageFooterLayout.tpl @@ -0,0 +1,27 @@ + diff --git a/wcfsetup/install/files/acp/update_com.woltlab.wcf_6.3_styleVariables.php b/wcfsetup/install/files/acp/update_com.woltlab.wcf_6.3_styleVariables.php index 033edd30479..23edf35005e 100644 --- a/wcfsetup/install/files/acp/update_com.woltlab.wcf_6.3_styleVariables.php +++ b/wcfsetup/install/files/acp/update_com.woltlab.wcf_6.3_styleVariables.php @@ -3,6 +3,7 @@ use wcf\system\WCF; $styleVariables = [ + ['pageFooterLayout', 'compact', null], ['pageHeaderLayout', 'logoTop', null], ['wcfHeaderMenuLinkBackgroundActive', 'rgba(36, 66, 95, 1)', 'rgba(54, 72, 96, 1)'], ['wcfHeaderMenuDropdownBackgroundActive', 'rgba(65, 121, 173, 1)', 'rgba(63, 82, 112, 1)'], @@ -28,8 +29,8 @@ ]); } -// Existing styles keep the classic page header, only an explicit value switches -// them to the new one. `IFNULL()` preserves values that are already set. +// Existing styles keep the classic page header and footer, only an explicit value +// switches them to the new one. `IFNULL()` preserves values that are already set. $sql = "INSERT INTO wcf1_style_variable_value (styleID, variableID, variableValue) SELECT style.styleID, variable.variableID, ? @@ -38,7 +39,9 @@ WHERE variable.variableName = ? ON DUPLICATE KEY UPDATE variableValue = IFNULL(variableValue, VALUES(variableValue))"; $statement = WCF::getDB()->prepare($sql); -$statement->execute([ - 'classic', - 'pageHeaderLayout', -]); +foreach (['pageFooterLayout', 'pageHeaderLayout'] as $variableName) { + $statement->execute([ + 'classic', + $variableName, + ]); +} diff --git a/wcfsetup/install/files/lib/data/style/Style.class.php b/wcfsetup/install/files/lib/data/style/Style.class.php index cf8c56ebcf9..bca3526e7f1 100644 --- a/wcfsetup/install/files/lib/data/style/Style.class.php +++ b/wcfsetup/install/files/lib/data/style/Style.class.php @@ -5,6 +5,7 @@ use wcf\data\DatabaseObject; use wcf\data\ITitledObject; use wcf\system\style\option\IStyleOption; +use wcf\system\style\option\PageFooterLayout; use wcf\system\style\option\PageHeaderLayout; use wcf\system\style\StyleCompiler; use wcf\system\WCF; @@ -94,6 +95,7 @@ class Style extends DatabaseObject implements ITitledObject, \Stringable */ private const OPTIONS = [ PageHeaderLayout::class, + PageFooterLayout::class, ]; /** @@ -226,6 +228,20 @@ public function usesClassicPageHeader(): bool return PageHeaderLayout::fromString($variables[PageHeaderLayout::getVariableName()]) === PageHeaderLayout::Classic; } + /** + * Returns true if this style renders the classic page footer. Templates outside + * the footer, such as the language controls of both headers, use this to adapt + * their markup without relying on the template variants. + * + * @since 6.3 + */ + public function usesClassicPageFooter(): bool + { + $variables = $this->getVariables(); + + return PageFooterLayout::fromString($variables[PageFooterLayout::getVariableName()]) === PageFooterLayout::Classic; + } + /** * Returns the per-style options. * diff --git a/wcfsetup/install/files/lib/system/style/StyleCompiler.class.php b/wcfsetup/install/files/lib/system/style/StyleCompiler.class.php index bcace2b3b0c..ed7ad93083c 100644 --- a/wcfsetup/install/files/lib/system/style/StyleCompiler.class.php +++ b/wcfsetup/install/files/lib/system/style/StyleCompiler.class.php @@ -15,6 +15,7 @@ use wcf\system\exception\SystemException; use wcf\system\SingletonFactory; use wcf\system\style\option\IStyleOption; +use wcf\system\style\option\PageFooterLayout; use wcf\system\style\option\PageHeaderLayout; use wcf\command\style\CreateManifest; use wcf\system\WCF; @@ -427,7 +428,10 @@ private function extractPreloadRequests(string $css): iterable */ public function compileACP(): void { - $files = $this->getCoreFiles([PageHeaderLayout::Classic->getStylesheet()]); + $files = $this->getCoreFiles([ + PageHeaderLayout::Classic->getStylesheet(), + PageFooterLayout::Classic->getStylesheet(), + ]); // ACP uses a slightly different layout $files[] = \WCF_DIR . 'acp/style/layout.scss'; diff --git a/wcfsetup/install/files/lib/system/style/option/PageFooterLayout.class.php b/wcfsetup/install/files/lib/system/style/option/PageFooterLayout.class.php new file mode 100644 index 00000000000..796139c9d6e --- /dev/null +++ b/wcfsetup/install/files/lib/system/style/option/PageFooterLayout.class.php @@ -0,0 +1,88 @@ + + * @since 6.3 + */ +enum PageFooterLayout implements IStyleOption +{ + case Compact; + case Classic; + + #[\Override] + public static function getVariableName(): string + { + return 'pageFooterLayout'; + } + + #[\Override] + public static function getFallback(): static + { + return self::Classic; + } + + #[\Override] + public static function fromString(string $value): static + { + $variant = self::tryFromString($value); + if ($variant === null) { + throw new \ValueError("Unknown value '{$value}' for '" . self::getVariableName() . "'."); + } + + return $variant; + } + + #[\Override] + public static function tryFromString(string $value): ?static + { + foreach (self::cases() as $case) { + if ($case->toString() === $value) { + return $case; + } + } + + return null; + } + + #[\Override] + public function toString(): string + { + return match ($this) { + self::Classic => 'classic', + self::Compact => 'compact', + }; + } + + #[\Override] + public function isDeprecated(): bool + { + return match ($this) { + self::Classic => true, + self::Compact => false, + }; + } + + #[\Override] + public function getTemplateVariant(): ?string + { + return match ($this) { + self::Classic => null, + self::Compact => 'pageFooter', + }; + } + + #[\Override] + public function getStylesheet(): string + { + return match ($this) { + self::Classic => 'layout/pageFooter/classic.scss', + self::Compact => 'layout/pageFooter/compact.scss', + }; + } +} diff --git a/wcfsetup/install/files/style/layout/box.scss b/wcfsetup/install/files/style/layout/box.scss index ebaf633eef7..9e05008006e 100644 --- a/wcfsetup/install/files/style/layout/box.scss +++ b/wcfsetup/install/files/style/layout/box.scss @@ -777,180 +777,8 @@ margin-top: 40px; } -/* styling for boxes in position */ -.boxesFooterBoxes { - background-color: var(--wcfFooterBoxBackground); - color: var(--wcfFooterBoxText); - - a { - color: var(--wcfFooterBoxLink); - - &:hover { - color: var(--wcfFooterBoxLinkActive); - } - } - - .boxContainer { - @include screen-sm-down { - display: flex; - flex-direction: column; - padding: 40px 0; - row-gap: 40px; - } - - @include screen-md-up { - column-gap: 30px; - display: grid; - grid-template-columns: 1fr 1fr; - padding: 60px 0; - row-gap: 60px; - } - } - - @include screen-md-up { - .box.boxFullWidth { - grid-column: span 2; - } - } - - .boxTitle { - color: var(--wcfFooterBoxHeadlineText); - - a { - color: var(--wcfFooterBoxHeadlineLink); - - &:hover { - color: var(--wcfFooterBoxHeadlineLinkActive); - } - } - } - - .boxImage { - align-items: center; - display: flex; - justify-content: center; - margin-bottom: 20px; - max-height: 100px; - overflow: hidden; - } -} - -/* styling for boxes in