feat(banner): add top banner (#777)

* feat: add top banner

* chore: use inside the example site

* chore: generate

* fix: banner with the burger navbar

* fix: compute the banner height to allow mutliple lines

* chore: better p style
This commit is contained in:
Ludovic Fernandez
2025-08-24 00:46:29 +02:00
committed by GitHub
parent 990d24906b
commit f297d24189
14 changed files with 96 additions and 3 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,12 @@
.hextra-banner-hidden .hextra-banner {
display: none;
}
.hextra-banner {
:where(a):not(:where([class~=not-prose],[class~=not-prose] *)) {
@apply hx:underline hx:decoration-from-font;
}
:where(p):not(:where([class~=not-prose],[class~=not-prose] *)) {
@apply hx:leading-7 hx:first:mt-0;
}
}

View File

@@ -1,6 +1,6 @@
@media (max-width: 48rem) {
.hextra-sidebar-container {
@apply hx:fixed hx:pt-[calc(var(--navbar-height))] hx:top-0 hx:w-full hx:bottom-0 hx:z-[15] hx:overscroll-contain hx:bg-white hx:dark:bg-dark;
@apply hx:fixed hx:pt-[calc(var(--navbar-height)+var(--hextra-banner-height))] hx:top-0 hx:w-full hx:bottom-0 hx:z-[15] hx:overscroll-contain hx:bg-white hx:dark:bg-dark;
transition: transform 0.4s cubic-bezier(0.52, 0.16, 0.04, 1);
will-change: transform, opacity;
contain: layout style;

View File

@@ -29,6 +29,7 @@ body {
--primary-saturation: 100%;
--primary-lightness: 50%;
--navbar-height: 4rem;
--hextra-banner-height: 2rem;
--menu-height: 3.75rem; /* 60px */
}
@@ -48,6 +49,7 @@ body {
@import "./components/steps.css";
@import "./components/search.css";
@import "./components/sidebar.css";
@import "./components/banner.css";
@import "./components/navbar.css";
@import "./components/scrollbar.css";
@import "./components/code-copy.css";

15
assets/js/banner.js Normal file
View File

@@ -0,0 +1,15 @@
// {{- if site.Params.banner }}
(function () {
const banner = document.querySelector(".hextra-banner")
document.documentElement.style.setProperty("--hextra-banner-height", banner.clientHeight+"px");
const closeBtn = banner.querySelector(".hextra-banner-close-button");
closeBtn.addEventListener("click", () => {
document.documentElement.classList.add("hextra-banner-hidden");
document.documentElement.style.setProperty("--hextra-banner-height", "0px");
localStorage.setItem('{{ site.Params.banner.key | default `banner-closed` }}', "0");
});
})();
// {{- end -}}

View File

@@ -423,3 +423,22 @@ params:
- "/img/config-image.jpg"
audio: "config-talk.mp3"
```
### Banner
To add a banner to your site, add the following to your `hugo.yaml`:
```yaml
params:
banner:
key: 'announcement-xxx'
message: |
🎉 Welcome! [Hextra](https://github.com/hextra/hextra) is a static site generator that helps you build modern websites.
```
The banner will be displayed on all pages.
The field `message` supports Markdown syntax.
If you want to use template syntax, you can define the partial in `layouts/_partials/custom/banner.html`.
In this case, the field `message` will be ignored.

View File

@@ -121,6 +121,9 @@ menu:
params:
description: Modern, responsive, batteries-included Hugo theme for creating beautiful static websites.
banner:
key: 'announcement-v0_10'
navbar:
displayTitle: true
displayLogo: true

View File

@@ -97,6 +97,8 @@
"footnotes",
"frac-line",
"hextra-badge",
"hextra-banner",
"hextra-banner-close-button",
"hextra-card",
"hextra-card-icon",
"hextra-card-image",
@@ -184,6 +186,7 @@
"hx:bg-green-100",
"hx:bg-indigo-100",
"hx:bg-neutral-50",
"hx:bg-neutral-900",
"hx:bg-orange-50",
"hx:bg-primary-100",
"hx:bg-primary-400",
@@ -321,6 +324,7 @@
"hx:dark:text-purple-200",
"hx:dark:text-red-200",
"hx:dark:text-slate-100",
"hx:dark:text-white",
"hx:dark:text-yellow-200",
"hx:dark:to-gray-400",
"hx:data-[state=closed]:hidden",
@@ -373,6 +377,7 @@
"hx:group/copybtn",
"hx:grow",
"hx:h-0",
"hx:h-10",
"hx:h-16",
"hx:h-2",
"hx:h-3.5",
@@ -457,6 +462,7 @@
"hx:max-md:[transform:translate3d(0,-100%,0)]",
"hx:max-md:hidden",
"hx:max-md:min-h-[340px]",
"hx:max-md:sticky",
"hx:max-sm:grid-cols-1",
"hx:max-w-6xl",
"hx:max-w-[50%]",
@@ -478,6 +484,7 @@
"hx:md:inline-block",
"hx:md:justify-start",
"hx:md:max-h-[min(calc(100vh-5rem-env(safe-area-inset-bottom)),400px)]",
"hx:md:mr-0",
"hx:md:pt-12",
"hx:md:px-12",
"hx:md:self-start",
@@ -542,6 +549,7 @@
"hx:pr-[calc(env(safe-area-inset-right)-1.5rem)]",
"hx:pr-[max(env(safe-area-inset-left),1.5rem)]",
"hx:pr-[max(env(safe-area-inset-right),1.5rem)]",
"hx:print:[display:none]",
"hx:print:bg-transparent",
"hx:print:hidden",
"hx:pt-4",
@@ -640,6 +648,7 @@
"hx:text-primary-800",
"hx:text-purple-900",
"hx:text-red-900",
"hx:text-slate-50",
"hx:text-slate-900",
"hx:text-sm",
"hx:text-transparent",
@@ -662,6 +671,7 @@
"hx:transition-transform",
"hx:underline",
"hx:underline-offset-2",
"hx:w-10",
"hx:w-2",
"hx:w-3.5",
"hx:w-4",

View File

@@ -0,0 +1,3 @@
<div>
<span>Hextra v0.10 is out 🎉 What <a href="{{ relref . `blog/v0.10` -}}">new</a>?</span>
</div>

View File

@@ -0,0 +1,18 @@
{{- if site.Params.banner }}
<div class="hextra-banner hx:max-md:sticky hx:top-0 hx:z-20 hx:px-6 hx:text-center hx:text-slate-50 hx:dark:text-white hx:bg-neutral-900 hx:dark:bg-neutral-800 hx:print:[display:none]">
<div class="hx:relative hx:flex hx:items-center hx:justify-center hx:font-medium hx:text-sm hx:py-2.5">
{{- with partial "custom/banner.html" . -}}
{{- . -}}
{{- else -}}
<div style="white-space: pre-wrap" class="hx:px-8">
{{- site.Params.banner.message | default "🎉 Welcome! This is a banner message." | .RenderString -}}
</div>
{{- end -}}
<button
class="hextra-banner-close-button hx:cursor-pointer hx:absolute hx:right-0 hx:text-white hx:font-bold hx:leading-none hx:hover:opacity-75 hx:transition hx:w-10 hx:h-10 hx:-mr-2 hx:md:mr-0 hx:flex hx:items-center hx:justify-center"
>
{{- partial "utils/icon.html" (dict "name" "x" "attributes" "height=16") -}}
</button>
</div>
</div>
{{- end -}}

View File

View File

@@ -77,6 +77,15 @@
</script>
<script>
// The section must not be in the banner.js file because it can create a quick flash.
if (localStorage.getItem('{{ site.Params.banner.key | default `banner-closed` }}')) {
document.documentElement.style.setProperty("--hextra-banner-height", "0px");
document.documentElement.classList.add("hextra-banner-hidden");
}
</script>
<!-- Math engine -->
{{ $noop := .WordCount -}}
{{- $engine := site.Params.math.engine | default "katex" -}}

View File

@@ -1,4 +1,5 @@
{{- $jsTheme := resources.Get "js/theme.js" | resources.ExecuteAsTemplate "theme.js" . -}}
{{- $jsBanner := resources.Get "js/banner.js" | resources.ExecuteAsTemplate "banner.js" . -}}
{{- $jsMenu := resources.Get "js/menu.js" -}}
{{- $jsTabs := resources.Get "js/tabs.js" -}}
{{- $jsLang := resources.Get "js/lang.js" -}}
@@ -10,7 +11,7 @@
{{- $jsTocScroll := resources.Get "js/toc-scroll.js" -}}
{{- $jsFavicon := resources.Get "js/favicon.js" | resources.ExecuteAsTemplate "favicon.js" . -}}
{{- $scripts := slice $jsTheme $jsMenu $jsCodeCopy $jsTabs $jsLang $jsNavMenu $jsFileTree $jsSidebar $jsBackToTop $jsTocScroll $jsFavicon | resources.Concat "js/main.js" -}}
{{- $scripts := slice $jsTheme $jsBanner $jsMenu $jsCodeCopy $jsTabs $jsLang $jsNavMenu $jsFileTree $jsSidebar $jsBackToTop $jsTocScroll $jsFavicon | resources.Concat "js/main.js" -}}
{{- if hugo.IsProduction -}}
{{- $scripts = $scripts | minify | fingerprint -}}
{{- end -}}

View File

@@ -2,6 +2,7 @@
<html lang="{{ .Site.Language.Lang }}">
{{- partial "head.html" . -}}
<body dir="{{ .Site.Language.LanguageDirection | default `ltr` }}">
{{- partial "banner.html" . -}}
{{- partial "navbar.html" . -}}
{{- block "main" . }}{{ end -}}
{{- if or (eq .Site.Params.footer.enable nil) (.Site.Params.footer.enable) }}