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
This commit is contained in:
Isaac Janzen 2024-03-04 10:02:23 -07:00 committed by GitHub
parent 04b0f40db8
commit 405bfba3c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 327 additions and 5 deletions

View File

@ -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 {
<div class="home-logo-wrapper-outlet">
<PluginOutlet @name="home-logo-wrapper">
<MountWidget
@widget="home-logo"
@args={{hash minimized=this.topicPresent}}
/>
<HomeLogo @minimized={{this.topicPresent}} />
</PluginOutlet>
</div>

View File

@ -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>
{{! template-lint-disable no-invalid-interactive }}
<div
class={{concatClass (if @minimized "title--minimized") "title"}}
{{on "click" this.click}}
>
<a href={{this.href}} data-auto-route="true">
{{#if @minimized}}
{{#if this.logoSmallUrl}}
<Logo
@key="logo-small"
@url={{this.logoSmallUrl}}
@title={{this.siteSettings.title}}
@darkUrl={{this.logoSmallUrlDark}}
/>
{{else}}
{{icon "home"}}
{{/if}}
{{else if this.showMobileLogo}}
<Logo
@key="logo-mobile"
@url={{this.mobileLogoUrl}}
@title={{this.siteSettings.title}}
@darkUrl={{this.mobileLogoUrlDark}}
/>
{{else if this.logoUrl}}
<Logo
@key="logo-big"
@url={{this.logoUrl}}
@title={{this.siteSettings.title}}
@darkUrl={{this.logoUrlDark}}
/>
{{else}}
<h1 id="site-text-logo" class="text-logo">
{{this.siteSettings.title}}
</h1>
{{/if}}
</a>
</div>
</template>
}

View File

@ -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 = <template>
{{#if (and @darkUrl (notEq @url @darkUrl))}}
<picture>
<source srcset={{getURL @darkUrl}} media="(prefers-color-scheme: dark)" />
<img
id="site-logo"
class={{@key}}
src={{getURL @url}}
width={{if (eq @key "logo-small") "36"}}
alt={{@title}}
/>
</picture>
{{else}}
<img
id="site-logo"
class={{@key}}
src={{getURL @url}}
width={{if (eq @key "logo-small") "36"}}
alt={{@title}}
/>
{{/if}}
</template>;
export default Logo;

View File

@ -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.

View File

@ -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";

View File

@ -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(<template><HomeLogo @minimized={{false}} /></template>);
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(<template><HomeLogo @minimized={{true}} /></template>);
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(<template><HomeLogo @minimized={{false}} /></template>);
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(<template><HomeLogo @minimized={{true}} /></template>);
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(<template><HomeLogo /></template>);
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(<template><HomeLogo /></template>);
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(<template><HomeLogo /></template>);
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(<template><HomeLogo /></template>);
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(<template><HomeLogo /></template>);
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(<template><HomeLogo /></template>);
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(<template><HomeLogo /></template>);
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(<template><HomeLogo /></template>);
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"
);
});
});

View File

@ -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";