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"));
+ }
+
+
+ {{! template-lint-disable no-invalid-interactive }}
+
+
+}
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 =
+ {{#if (and @darkUrl (notEq @url @darkUrl))}}
+
+ {{else}}
+
+ {{/if}}
+;
+
+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";