diff --git a/app/assets/stylesheets/components/_onboarding.scss b/app/assets/stylesheets/components/_onboarding.scss index 5fa6ddc4d..86030cb40 100644 --- a/app/assets/stylesheets/components/_onboarding.scss +++ b/app/assets/stylesheets/components/_onboarding.scss @@ -195,7 +195,7 @@ $onboarding-card-border: rgba(255, 255, 255, 0.5); justify-content: center; padding: 0.6rem 1rem; position: sticky; - top: 0; + top: var(--top-banner-height, 0px); z-index: 50; body.signed-in:not(.app-layout-page) & { margin-left: calc(-1 * var(--sidebar-reserved)); diff --git a/app/assets/stylesheets/components/_sidebar.scss b/app/assets/stylesheets/components/_sidebar.scss index 9a2f8af79..ed42873f5 100644 --- a/app/assets/stylesheets/components/_sidebar.scss +++ b/app/assets/stylesheets/components/_sidebar.scss @@ -4,7 +4,7 @@ --sidebar-inset-y: var(--space-s); // tiny top + bottom edges position: fixed; - top: var(--sidebar-inset-y); + top: calc(var(--sidebar-inset-y) + var(--top-banner-height, 0px)); bottom: var(--sidebar-inset-y); left: var(--sidebar-inset); width: var(--sidebar-width); diff --git a/app/assets/stylesheets/components/_top_banner.scss b/app/assets/stylesheets/components/_top_banner.scss index db5605b10..891df5a24 100644 --- a/app/assets/stylesheets/components/_top_banner.scss +++ b/app/assets/stylesheets/components/_top_banner.scss @@ -18,8 +18,14 @@ border-bottom: 2px solid #92400e; } +// Pinned above everything, including the fixed sidebar. top_banner_controller +// publishes its height so the page and sidebar start below it. .top-banner--announcement { - position: relative; + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; padding-inline: 2.5rem; text-align: center; background: var(--color-brand-yellow); diff --git a/app/assets/stylesheets/layout/_base.scss b/app/assets/stylesheets/layout/_base.scss index d107da4d6..5565a0cad 100644 --- a/app/assets/stylesheets/layout/_base.scss +++ b/app/assets/stylesheets/layout/_base.scss @@ -16,6 +16,7 @@ body { display: flex; flex-direction: column; min-height: 100vh; + padding-top: var(--top-banner-height, 0px); } main { diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index a09e44ab2..38d179927 100644 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -202,6 +202,9 @@ application.register("discover-rail-panel", DiscoverRailPanelController); import DismissableController from "./dismissable_controller"; application.register("dismissable", DismissableController); +import TopBannerController from "./top_banner_controller"; +application.register("top-banner", TopBannerController); + import EmojiPickerController from "./emoji_picker_controller"; application.register("emoji-picker", EmojiPickerController); diff --git a/app/javascript/controllers/top_banner_controller.js b/app/javascript/controllers/top_banner_controller.js new file mode 100644 index 000000000..60d6d3ce5 --- /dev/null +++ b/app/javascript/controllers/top_banner_controller.js @@ -0,0 +1,23 @@ +import { Controller } from "@hotwired/stimulus"; + +// Publishes a fixed top banner's height as --top-banner-height so the page, +// sidebar and sticky headers can sit below it. Cleared when the banner leaves. +export default class extends Controller { + connect() { + this.observer = new ResizeObserver(() => this.publish()); + this.observer.observe(this.element); + this.publish(); + } + + disconnect() { + this.observer?.disconnect(); + document.documentElement.style.removeProperty("--top-banner-height"); + } + + publish() { + document.documentElement.style.setProperty( + "--top-banner-height", + `${this.element.offsetHeight}px`, + ); + } +} diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 93fa6db2d..c02f62da5 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -91,7 +91,7 @@