From 405bfba3c0dbc6c7b5718ea49b889326564e201f Mon Sep 17 00:00:00 2001 From: Isaac Janzen <50783505+janzenisaac@users.noreply.github.com> Date: Mon, 4 Mar 2024 10:02:23 -0700 Subject: [PATCH] DEV: Convert `home-logo` widget to a glimmer component (#25989) Part of the larger effort to upgrade the header from widgets to glimmer components: https://github.com/discourse/discourse/pull/25214 --- .../components/glimmer-header/contents.gjs | 7 +- .../components/glimmer-header/home-logo.gjs | 118 ++++++++++++ .../app/components/glimmer-header/logo.gjs | 29 +++ .../discourse/app/lib/plugin-api.js | 1 + .../discourse/app/widgets/home-logo.js | 1 + .../integration/components/home-logo-test.gjs | 175 ++++++++++++++++++ .../components/widgets/home-logo-test.gjs | 1 + 7 files changed, 327 insertions(+), 5 deletions(-) create mode 100644 app/assets/javascripts/discourse/app/components/glimmer-header/home-logo.gjs create mode 100644 app/assets/javascripts/discourse/app/components/glimmer-header/logo.gjs create mode 100644 app/assets/javascripts/discourse/tests/integration/components/home-logo-test.gjs diff --git a/app/assets/javascripts/discourse/app/components/glimmer-header/contents.gjs b/app/assets/javascripts/discourse/app/components/glimmer-header/contents.gjs index 429af099f2d..328f2187ff3 100644 --- a/app/assets/javascripts/discourse/app/components/glimmer-header/contents.gjs +++ b/app/assets/javascripts/discourse/app/components/glimmer-header/contents.gjs @@ -3,8 +3,8 @@ import { hash } from "@ember/helper"; import { inject as service } from "@ember/service"; import and from "truth-helpers/helpers/and"; import BootstrapModeNotice from "../bootstrap-mode-notice"; -import MountWidget from "../mount-widget"; import PluginOutlet from "../plugin-outlet"; +import HomeLogo from "./home-logo"; import SidebarToggle from "./sidebar-toggle"; import TopicInfo from "./topic/info"; @@ -28,10 +28,7 @@ export default class Contents extends Component {
- +
diff --git a/app/assets/javascripts/discourse/app/components/glimmer-header/home-logo.gjs b/app/assets/javascripts/discourse/app/components/glimmer-header/home-logo.gjs new file mode 100644 index 00000000000..dcd7fc5e71f --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/glimmer-header/home-logo.gjs @@ -0,0 +1,118 @@ +import Component from "@glimmer/component"; +import { on } from "@ember/modifier"; +import { action } from "@ember/object"; +import { inject as service } from "@ember/service"; +import concatClass from "discourse/helpers/concat-class"; +import { wantsNewWindow } from "discourse/lib/intercept-click"; +import DiscourseURL from "discourse/lib/url"; +import icon from "discourse-common/helpers/d-icon"; +import getURL from "discourse-common/lib/get-url"; +import Logo from "./logo"; + +export default class HomeLogo extends Component { + @service session; + @service site; + @service siteSettings; + + href = getURL("/"); + darkModeAvailable = this.session.darkModeAvailable; + + get showMobileLogo() { + return this.site.mobileView && this.logoResolver("mobile_logo").length > 0; + } + + get logoUrl() { + return this.logoResolver("logo"); + } + + get logoUrlDark() { + return this.logoResolver("logo", { dark: this.darkModeAvailable }); + } + + get logoSmallUrl() { + return this.logoResolver("logo_small"); + } + + get logoSmallUrlDark() { + return this.logoResolver("logo_small", { dark: this.darkModeAvailable }); + } + + get mobileLogoUrl() { + return this.logoResolver("mobile_logo"); + } + + get mobileLogoUrlDark() { + return this.logoResolver("mobile_logo", { dark: this.darkModeAvailable }); + } + + logoResolver(name, opts = {}) { + // get alternative logos for browser dark dark mode switching + if (opts.dark) { + return this.siteSettings[`site_${name}_dark_url`]; + } + + // try dark logos first when color scheme is dark + // this is independent of browser dark mode + // hence the fallback to normal logos + if (this.session.defaultColorSchemeIsDark) { + return ( + this.siteSettings[`site_${name}_dark_url`] || + this.siteSettings[`site_${name}_url`] || + "" + ); + } + + return this.siteSettings[`site_${name}_url`] || ""; + } + + @action + click(e) { + if (wantsNewWindow(e)) { + return false; + } + + e.preventDefault(); + DiscourseURL.routeToTag(e.target.closest("a")); + } + + +} diff --git a/app/assets/javascripts/discourse/app/components/glimmer-header/logo.gjs b/app/assets/javascripts/discourse/app/components/glimmer-header/logo.gjs new file mode 100644 index 00000000000..d9bc6771a46 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/glimmer-header/logo.gjs @@ -0,0 +1,29 @@ +import getURL from "discourse-common/lib/get-url"; +import and from "truth-helpers/helpers/and"; +import eq from "truth-helpers/helpers/eq"; +import notEq from "truth-helpers/helpers/not-eq"; + +const Logo = ; + +export default Logo; diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.js b/app/assets/javascripts/discourse/app/lib/plugin-api.js index adb83e97bb5..fd1ea432c81 100644 --- a/app/assets/javascripts/discourse/app/lib/plugin-api.js +++ b/app/assets/javascripts/discourse/app/lib/plugin-api.js @@ -156,6 +156,7 @@ const DEPRECATED_HEADER_WIDGETS = [ "header-icons", "header-topic-info", "header-notifications", + "home-logo", ]; // This helper prevents us from applying the same `modifyClass` over and over in test mode. diff --git a/app/assets/javascripts/discourse/app/widgets/home-logo.js b/app/assets/javascripts/discourse/app/widgets/home-logo.js index d236b380737..2ace90d8366 100644 --- a/app/assets/javascripts/discourse/app/widgets/home-logo.js +++ b/app/assets/javascripts/discourse/app/widgets/home-logo.js @@ -1,3 +1,4 @@ +// deprecated in favor of components/glimmer-header/home-logo.gjs import { h } from "virtual-dom"; import { wantsNewWindow } from "discourse/lib/intercept-click"; import DiscourseURL from "discourse/lib/url"; diff --git a/app/assets/javascripts/discourse/tests/integration/components/home-logo-test.gjs b/app/assets/javascripts/discourse/tests/integration/components/home-logo-test.gjs new file mode 100644 index 00000000000..9ebe59acd7a --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/home-logo-test.gjs @@ -0,0 +1,175 @@ +import { getOwner } from "@ember/application"; +import { render } from "@ember/test-helpers"; +import { module, test } from "qunit"; +import HomeLogo from "discourse/components/glimmer-header/home-logo"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; + +const bigLogo = "/images/d-logo-sketch.png?test"; +const smallLogo = "/images/d-logo-sketch-small.png?test"; +const mobileLogo = "/images/d-logo-sketch.png?mobile"; +const darkLogo = "/images/d-logo-sketch.png?dark"; +const title = "Cool Forum"; +const prefersDark = "(prefers-color-scheme: dark)"; + +module("Integration | Component | home-logo", function (hooks) { + setupRenderingTest(hooks); + + hooks.afterEach(function () { + this.session = getOwner(this).lookup("service:session"); + this.session.set("darkModeAvailable", null); + this.session.set("defaultColorSchemeIsDark", null); + }); + + test("basics", async function (assert) { + this.siteSettings.site_logo_url = bigLogo; + this.siteSettings.site_logo_small_url = smallLogo; + this.siteSettings.title = title; + + await render(); + assert.dom(".title").exists({ count: 1 }); + assert.dom("img#site-logo.logo-big").exists({ count: 1 }); + assert.dom("#site-logo").hasAttribute("src", bigLogo); + assert.dom("#site-logo").hasAttribute("alt", title); + }); + + test("basics - minimized", async function (assert) { + this.siteSettings.site_logo_url = bigLogo; + this.siteSettings.site_logo_small_url = smallLogo; + this.siteSettings.title = title; + + await render(); + assert.dom("img.logo-small").exists({ count: 1 }); + assert.dom("img.logo-small").hasAttribute("src", smallLogo); + assert.dom("img.logo-small").hasAttribute("alt", title); + assert.dom("img.logo-small").hasAttribute("width", "36"); + }); + + test("no logo", async function (assert) { + this.siteSettings.site_logo_url = ""; + this.siteSettings.site_logo_small_url = ""; + this.siteSettings.title = title; + + await render(); + assert.dom("h1#site-text-logo.text-logo").exists({ count: 1 }); + assert.dom("#site-text-logo").hasText(title, "has title as text logo"); + }); + + test("no logo - minimized", async function (assert) { + this.siteSettings.site_logo_url = ""; + this.siteSettings.site_logo_small_url = ""; + this.siteSettings.title = title; + + await render(); + assert.dom(".d-icon-home").exists({ count: 1 }); + }); + + test("mobile logo", async function (assert) { + this.siteSettings.site_mobile_logo_url = mobileLogo; + this.siteSettings.site_logo_small_url = smallLogo; + this.site.mobileView = true; + + await render(); + assert.dom("img#site-logo.logo-mobile").exists({ count: 1 }); + assert.dom("#site-logo").hasAttribute("src", mobileLogo); + }); + + test("mobile without logo", async function (assert) { + this.siteSettings.site_logo_url = bigLogo; + this.site.mobileView = true; + + await render(); + assert.dom("img#site-logo.logo-big").exists({ count: 1 }); + assert.dom("#site-logo").hasAttribute("src", bigLogo); + }); + + test("logo with dark mode alternative", async function (assert) { + this.siteSettings.site_logo_url = bigLogo; + this.siteSettings.site_logo_dark_url = darkLogo; + this.session.set("darkModeAvailable", true); + + await render(); + assert.dom("img#site-logo.logo-big").exists({ count: 1 }); + assert.dom("#site-logo").hasAttribute("src", bigLogo); + assert + .dom("picture source") + .hasAttribute("media", prefersDark, "includes dark mode media attribute"); + assert + .dom("picture source") + .hasAttribute( + "srcset", + darkLogo, + "includes dark mode alternative logo source" + ); + }); + + test("mobile logo with dark mode alternative", async function (assert) { + this.siteSettings.site_logo_url = bigLogo; + this.siteSettings.site_mobile_logo_url = mobileLogo; + this.siteSettings.site_mobile_logo_dark_url = darkLogo; + this.session.set("darkModeAvailable", true); + + this.site.mobileView = true; + + await render(); + + assert.dom("#site-logo").hasAttribute("src", mobileLogo); + assert + .dom("picture source") + .hasAttribute("media", prefersDark, "includes dark mode media attribute"); + assert + .dom("picture source") + .hasAttribute( + "srcset", + darkLogo, + "includes dark mode alternative logo source" + ); + }); + + test("dark mode enabled but no dark logo set", async function (assert) { + this.siteSettings.site_logo_url = bigLogo; + this.siteSettings.site_logo_dark_url = ""; + this.session.set("darkModeAvailable", true); + + await render(); + assert.dom("img#site-logo.logo-big").exists({ count: 1 }); + assert.dom("#site-logo").hasAttribute("src", bigLogo); + assert.dom("picture").doesNotExist("does not include alternative logo"); + }); + + test("dark logo set but no dark mode", async function (assert) { + this.siteSettings.site_logo_url = bigLogo; + this.siteSettings.site_logo_dark_url = darkLogo; + + await render(); + assert.dom("img#site-logo.logo-big").exists({ count: 1 }); + assert.dom("#site-logo").hasAttribute("src", bigLogo); + assert.dom("picture").doesNotExist("does not include alternative logo"); + }); + + test("dark color scheme and dark logo set", async function (assert) { + this.siteSettings.site_logo_url = bigLogo; + this.siteSettings.site_logo_dark_url = darkLogo; + this.session.set("defaultColorSchemeIsDark", true); + + await render(); + assert.dom("img#site-logo.logo-big").exists({ count: 1 }); + assert.dom("#site-logo").hasAttribute("src", darkLogo, "uses dark logo"); + assert.dom("picture").doesNotExist("does not add dark mode alternative"); + }); + + test("dark color scheme and dark logo not set", async function (assert) { + this.siteSettings.site_logo_url = bigLogo; + this.siteSettings.site_logo_dark_url = ""; + this.session.set("defaultColorSchemeIsDark", true); + + await render(); + assert.dom("img#site-logo.logo-big").exists({ count: 1 }); + assert + .dom("#site-logo") + .hasAttribute( + "src", + bigLogo, + "uses regular logo on dark scheme if no dark logo" + ); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/integration/components/widgets/home-logo-test.gjs b/app/assets/javascripts/discourse/tests/integration/components/widgets/home-logo-test.gjs index dbfdab95ff2..31458483b88 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/widgets/home-logo-test.gjs +++ b/app/assets/javascripts/discourse/tests/integration/components/widgets/home-logo-test.gjs @@ -1,3 +1,4 @@ +// deprecated in favor of discourse/tests/integration/components/home-logo-test.gjs import { getOwner } from "@ember/application"; import { render } from "@ember/test-helpers"; import { module, test } from "qunit";