mirror of
https://github.com/discourse/discourse.git
synced 2025-10-03 17:21:20 +08:00
FEATURE: Add welcome banner to core (#31516)
This is a stripped-back version of the Search Banner component https://meta.discourse.org/t/search-banner/122939, which will be renamed to Advanced Search Banner, see https://github.com/discourse/discourse-search-banner/pull/84. This welcome banner interacts with the header search. When `search_experience` is set to `search_field`, we only show the header search after the welcome banner scrolls out of view, and vice-versa. Only new sites will get this feature turned on by default, existing sites have a migration to disable it. --------- Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com> Co-authored-by: Jordan Vidrine <jordan@jordanvidrine.com>
This commit is contained in:
parent
c5e95b419b
commit
64f1b97e0c
20 changed files with 421 additions and 13 deletions
|
@ -29,7 +29,7 @@ export default class HeaderSearch extends Component {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{#if this.shouldDisplay}}
|
{{#if this.shouldDisplay}}
|
||||||
{{bodyClass "header-search--visible"}}
|
{{bodyClass "header-search--enabled"}}
|
||||||
<div
|
<div
|
||||||
class="floating-search-input-wrapper"
|
class="floating-search-input-wrapper"
|
||||||
{{this.handleKeyboardShortcut}}
|
{{this.handleKeyboardShortcut}}
|
||||||
|
@ -46,7 +46,7 @@ export default class HeaderSearch extends Component {
|
||||||
@href={{this.advancedSearchButtonHref}}
|
@href={{this.advancedSearchButtonHref}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SearchMenu />
|
<SearchMenu @location="header" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,6 +21,7 @@ export default class SearchMenuPanel extends Component {
|
||||||
@onClose={{@closeSearchMenu}}
|
@onClose={{@closeSearchMenu}}
|
||||||
@inlineResults={{true}}
|
@inlineResults={{true}}
|
||||||
@autofocusInput={{true}}
|
@autofocusInput={{true}}
|
||||||
|
@location="header"
|
||||||
/>
|
/>
|
||||||
</MenuPanel>
|
</MenuPanel>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import { tracked } from "@glimmer/tracking";
|
import { tracked } from "@glimmer/tracking";
|
||||||
import { hash } from "@ember/helper";
|
import { concat, hash } from "@ember/helper";
|
||||||
import { on } from "@ember/modifier";
|
import { on } from "@ember/modifier";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||||
|
@ -14,6 +14,7 @@ import AdvancedButton from "discourse/components/search-menu/advanced-button";
|
||||||
import ClearButton from "discourse/components/search-menu/clear-button";
|
import ClearButton from "discourse/components/search-menu/clear-button";
|
||||||
import Results from "discourse/components/search-menu/results";
|
import Results from "discourse/components/search-menu/results";
|
||||||
import SearchTerm from "discourse/components/search-menu/search-term";
|
import SearchTerm from "discourse/components/search-menu/search-term";
|
||||||
|
import concatClass from "discourse/helpers/concat-class";
|
||||||
import loadingSpinner from "discourse/helpers/loading-spinner";
|
import loadingSpinner from "discourse/helpers/loading-spinner";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { CANCELLED_STATUS } from "discourse/lib/autocomplete";
|
import { CANCELLED_STATUS } from "discourse/lib/autocomplete";
|
||||||
|
@ -392,7 +393,9 @@ export default class SearchMenu extends Component {
|
||||||
{{! template-lint-disable no-invalid-interactive }}
|
{{! template-lint-disable no-invalid-interactive }}
|
||||||
{{on "keydown" this.onKeydown}}
|
{{on "keydown" this.onKeydown}}
|
||||||
>
|
>
|
||||||
<div class="search-input">
|
<div
|
||||||
|
class={{concatClass "search-input" (concat "search-input--" @location)}}
|
||||||
|
>
|
||||||
{{#if this.search.inTopicContext}}
|
{{#if this.search.inTopicContext}}
|
||||||
<DButton
|
<DButton
|
||||||
@icon="xmark"
|
@icon="xmark"
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { service } from "@ember/service";
|
||||||
|
import { htmlSafe } from "@ember/template";
|
||||||
|
import { modifier } from "ember-modifier";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import PluginOutlet from "discourse/components/plugin-outlet";
|
||||||
|
import SearchMenu from "discourse/components/search-menu";
|
||||||
|
import bodyClass from "discourse/helpers/body-class";
|
||||||
|
import { prioritizeNameFallback } from "discourse/lib/settings";
|
||||||
|
import { i18n } from "discourse-i18n";
|
||||||
|
|
||||||
|
export default class WelcomeBanner extends Component {
|
||||||
|
@service router;
|
||||||
|
@service siteSettings;
|
||||||
|
@service currentUser;
|
||||||
|
|
||||||
|
@tracked inViewport = true;
|
||||||
|
|
||||||
|
checkViewport = modifier((element) => {
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
([entry]) => {
|
||||||
|
this.inViewport = entry.isIntersecting;
|
||||||
|
},
|
||||||
|
{ threshold: 1.0 }
|
||||||
|
);
|
||||||
|
|
||||||
|
observer.observe(element);
|
||||||
|
|
||||||
|
return () => observer.disconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
get displayForRoute() {
|
||||||
|
return this.siteSettings.top_menu
|
||||||
|
.split("|")
|
||||||
|
.any(
|
||||||
|
(menuItem) => `discovery.${menuItem}` === this.router.currentRouteName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get headerText() {
|
||||||
|
if (!this.currentUser) {
|
||||||
|
return i18n("welcome_banner.header.anonymous_members", {
|
||||||
|
site_name: this.siteSettings.title,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return i18n("welcome_banner.header.logged_in_members", {
|
||||||
|
preferred_display_name: prioritizeNameFallback(
|
||||||
|
this.currentUser.name,
|
||||||
|
this.currentUser.username
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get shouldDisplay() {
|
||||||
|
if (!this.siteSettings.enable_welcome_banner) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.displayForRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.shouldDisplay}}
|
||||||
|
{{#if this.inViewport}}
|
||||||
|
{{bodyClass "welcome-banner--visible"}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="welcome-banner" {{this.checkViewport}}>
|
||||||
|
<div class="custom-search-banner welcome-banner__inner-wrapper">
|
||||||
|
<div class="custom-search-banner-wrap welcome-banner__wrap">
|
||||||
|
<h1 class="welcome-banner__title">{{htmlSafe this.headerText}}</h1>
|
||||||
|
<PluginOutlet @name="welcome-banner-below-headline" />
|
||||||
|
<div class="search-menu welcome-banner__search-menu">
|
||||||
|
<DButton
|
||||||
|
@icon="magnifying-glass"
|
||||||
|
@title="search.open_advanced"
|
||||||
|
@href="/search?expanded=true"
|
||||||
|
class="search-icon"
|
||||||
|
/>
|
||||||
|
<SearchMenu @location="welcome-banner" />
|
||||||
|
</div>
|
||||||
|
<PluginOutlet @name="welcome-banner-below-input" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ import RenderGlimmerContainer from "discourse/components/render-glimmer-containe
|
||||||
import Sidebar from "discourse/components/sidebar";
|
import Sidebar from "discourse/components/sidebar";
|
||||||
import SoftwareUpdatePrompt from "discourse/components/software-update-prompt";
|
import SoftwareUpdatePrompt from "discourse/components/software-update-prompt";
|
||||||
import TopicEntrance from "discourse/components/topic-entrance";
|
import TopicEntrance from "discourse/components/topic-entrance";
|
||||||
|
import WelcomeBanner from "discourse/components/welcome-banner";
|
||||||
import routeAction from "discourse/helpers/route-action";
|
import routeAction from "discourse/helpers/route-action";
|
||||||
import { i18n } from "discourse-i18n";
|
import { i18n } from "discourse-i18n";
|
||||||
import DMenus from "float-kit/components/d-menus";
|
import DMenus from "float-kit/components/d-menus";
|
||||||
|
@ -90,6 +91,9 @@ export default RouteTemplate(
|
||||||
|
|
||||||
<div id="main-outlet">
|
<div id="main-outlet">
|
||||||
<PluginOutlet @name="above-main-container" @connectorTagName="div" />
|
<PluginOutlet @name="above-main-container" @connectorTagName="div" />
|
||||||
|
|
||||||
|
<WelcomeBanner />
|
||||||
|
|
||||||
<div class="container" id="main-container">
|
<div class="container" id="main-container">
|
||||||
{{#if @controller.showTop}}
|
{{#if @controller.showTop}}
|
||||||
<CustomHtml @name="top" />
|
<CustomHtml @name="top" />
|
||||||
|
|
|
@ -98,16 +98,16 @@ acceptance("Search - Anonymous", function (needs) {
|
||||||
await visit("/");
|
await visit("/");
|
||||||
|
|
||||||
await click("#search-button");
|
await click("#search-button");
|
||||||
assert.dom(".search-menu").exists();
|
assert.dom(".search-menu-panel").exists();
|
||||||
|
|
||||||
await clickOutside();
|
await clickOutside();
|
||||||
assert.dom(".search-menu").doesNotExist();
|
assert.dom(".search-menu-panel").doesNotExist();
|
||||||
|
|
||||||
await click("#search-button");
|
await click("#search-button");
|
||||||
assert.dom(".search-menu").exists();
|
assert.dom(".search-menu-panel").exists();
|
||||||
|
|
||||||
await click("#search-button"); // toggle same button
|
await click("#search-button"); // toggle same button
|
||||||
assert.dom(".search-menu").doesNotExist();
|
assert.dom(".search-menu-panel").doesNotExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("initial options", async function (assert) {
|
test("initial options", async function (assert) {
|
||||||
|
@ -572,7 +572,9 @@ acceptance("Search - Authenticated", function (needs) {
|
||||||
assert
|
assert
|
||||||
.dom("#search-button")
|
.dom("#search-button")
|
||||||
.isFocused("Escaping search returns focus to search button");
|
.isFocused("Escaping search returns focus to search button");
|
||||||
assert.dom(".search-menu").doesNotExist("Esc removes search dropdown");
|
assert
|
||||||
|
.dom(".search-menu-panel")
|
||||||
|
.doesNotExist("Esc removes search dropdown");
|
||||||
|
|
||||||
await click("#search-button");
|
await click("#search-button");
|
||||||
await triggerKeyEvent(document.activeElement, "keyup", "ArrowDown");
|
await triggerKeyEvent(document.activeElement, "keyup", "ArrowDown");
|
||||||
|
|
|
@ -29,7 +29,7 @@ module("Integration | Component | search-menu", function (hooks) {
|
||||||
return response(searchFixtures["search/query"]);
|
return response(searchFixtures["search/query"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
await render(<template><SearchMenu /></template>);
|
await render(<template><SearchMenu @location="test" /></template>);
|
||||||
|
|
||||||
assert
|
assert
|
||||||
.dom(".show-advanced-search")
|
.dom(".show-advanced-search")
|
||||||
|
@ -73,7 +73,7 @@ module("Integration | Component | search-menu", function (hooks) {
|
||||||
test("clicking outside results hides and blurs input", async function (assert) {
|
test("clicking outside results hides and blurs input", async function (assert) {
|
||||||
await render(
|
await render(
|
||||||
<template>
|
<template>
|
||||||
<div id="click-me"><SearchMenu /></div>
|
<div id="click-me"><SearchMenu @location="test" /></div>
|
||||||
</template>
|
</template>
|
||||||
);
|
);
|
||||||
await click("#search-term");
|
await click("#search-term");
|
||||||
|
|
|
@ -62,3 +62,4 @@
|
||||||
@import "emoji-picker";
|
@import "emoji-picker";
|
||||||
@import "filter-input";
|
@import "filter-input";
|
||||||
@import "dropdown-menu";
|
@import "dropdown-menu";
|
||||||
|
@import "welcome-banner";
|
||||||
|
|
160
app/assets/stylesheets/common/components/welcome-banner.scss
Normal file
160
app/assets/stylesheets/common/components/welcome-banner.scss
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
@import "common/foundation/mixins";
|
||||||
|
|
||||||
|
.display-welcome-banner {
|
||||||
|
#main-outlet {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-banner--visible.header-search--enabled {
|
||||||
|
.floating-search-input-wrapper {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-banner {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
border-radius: var(--d-border-radius-large);
|
||||||
|
|
||||||
|
&__search-menu {
|
||||||
|
.menu-panel-results .menu-panel.search-menu-panel {
|
||||||
|
position: unset;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__wrap {
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
padding: 1.5em 0 3em;
|
||||||
|
|
||||||
|
@include breakpoint(tablet) {
|
||||||
|
padding: 1em 8px 1.25em;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
> div {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-menu {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.search-menu-container {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-icon-search {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.browser-search-tip {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
#search-term {
|
||||||
|
min-width: 0;
|
||||||
|
flex: 1 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: var(--font-up-6);
|
||||||
|
line-height: $line-height-medium;
|
||||||
|
|
||||||
|
@include breakpoint(tablet) {
|
||||||
|
font-size: var(--font-up-4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
p {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.search-icon {
|
||||||
|
z-index: 2;
|
||||||
|
background: transparent;
|
||||||
|
line-height: 1;
|
||||||
|
color: var(--primary-medium);
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
.rtl & {
|
||||||
|
right: 0;
|
||||||
|
left: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discourse-no-touch & {
|
||||||
|
&:hover {
|
||||||
|
background: transparent;
|
||||||
|
color: var(--primary);
|
||||||
|
|
||||||
|
.d-icon {
|
||||||
|
color: currentcolor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .search-menu-container .search-input {
|
||||||
|
padding-left: 1.75em;
|
||||||
|
|
||||||
|
.rtl & {
|
||||||
|
padding-left: unset;
|
||||||
|
padding-right: 1.75em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .search-menu-container .search-input .search-context {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.results {
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: var(--secondary);
|
||||||
|
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.15);
|
||||||
|
position: absolute;
|
||||||
|
z-index: 9;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
left: 0;
|
||||||
|
top: 2.75em;
|
||||||
|
right: 0;
|
||||||
|
padding: 0.5em;
|
||||||
|
|
||||||
|
@include breakpoint(mobile-extra-large) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-icon-search {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-link .d-icon {
|
||||||
|
color: var(--primary-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
span.keyword {
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hide search icon from default search menu
|
||||||
|
.search-menu.glimmer-search-menu .search-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
.header-search--visible,
|
.header-search--enabled,
|
||||||
.search-header--visible {
|
.search-header--visible {
|
||||||
.panel .header-dropdown-toggle.search-dropdown,
|
.panel .header-dropdown-toggle.search-dropdown,
|
||||||
.panel .search-menu {
|
.panel .search-menu {
|
||||||
|
|
|
@ -4,3 +4,4 @@
|
||||||
@import "welcome-header";
|
@import "welcome-header";
|
||||||
@import "more-topics";
|
@import "more-topics";
|
||||||
@import "emoji-picker";
|
@import "emoji-picker";
|
||||||
|
@import "welcome-banner";
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
.welcome-banner__search-menu {
|
||||||
|
.search-menu .search-link .badge-category {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-menu .search-input input#search-term {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
|
@ -218,6 +218,12 @@ en:
|
||||||
bootstrap_mode: "Getting started"
|
bootstrap_mode: "Getting started"
|
||||||
back_button: "Back"
|
back_button: "Back"
|
||||||
|
|
||||||
|
welcome_banner:
|
||||||
|
header:
|
||||||
|
logged_in_members: "Welcome back, %{preferred_display_name}!"
|
||||||
|
anonymous_members: "Welcome to %{site_name}!"
|
||||||
|
search: "Search"
|
||||||
|
|
||||||
themes:
|
themes:
|
||||||
default_description: "Default"
|
default_description: "Default"
|
||||||
broken_theme_alert: "Your site may not work because a theme / component has errors."
|
broken_theme_alert: "Your site may not work because a theme / component has errors."
|
||||||
|
|
|
@ -2743,6 +2743,7 @@ en:
|
||||||
suggest_weekends_in_date_pickers: "Include weekends (Saturday and Sunday) in date picker suggestions (disable this if you use Discourse only on weekdays, Monday through Friday)."
|
suggest_weekends_in_date_pickers: "Include weekends (Saturday and Sunday) in date picker suggestions (disable this if you use Discourse only on weekdays, Monday through Friday)."
|
||||||
show_bottom_topic_map: "Shows the topic map at the bottom of the topic when it has 10 replies or more."
|
show_bottom_topic_map: "Shows the topic map at the bottom of the topic when it has 10 replies or more."
|
||||||
show_topic_map_in_topics_without_replies: "Shows the topic map even if the topic has no replies."
|
show_topic_map_in_topics_without_replies: "Shows the topic map even if the topic has no replies."
|
||||||
|
enable_welcome_banner: "Display a banner on your main topic list pages to welcome members and allow them to search site content"
|
||||||
|
|
||||||
splash_screen: "Displays a temporary loading screen while site assets load"
|
splash_screen: "Displays a temporary loading screen while site assets load"
|
||||||
navigation_menu: "Specify sidebar or header dropdown as the main navigation menu for your site. Sidebar is recommended."
|
navigation_menu: "Specify sidebar or header dropdown as the main navigation menu for your site. Sidebar is recommended."
|
||||||
|
|
|
@ -3199,6 +3199,10 @@ uncategorized:
|
||||||
client: true
|
client: true
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
|
enable_welcome_banner:
|
||||||
|
client: true
|
||||||
|
default: true
|
||||||
|
|
||||||
user_preferences:
|
user_preferences:
|
||||||
default_email_digest_frequency:
|
default_email_digest_frequency:
|
||||||
enum: "DigestEmailSiteSetting"
|
enum: "DigestEmailSiteSetting"
|
||||||
|
|
15
db/migrate/20250311073009_enable_welcome_banner_new_sites.rb
Normal file
15
db/migrate/20250311073009_enable_welcome_banner_new_sites.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
#
|
||||||
|
class EnableWelcomeBannerNewSites < ActiveRecord::Migration[7.2]
|
||||||
|
def up
|
||||||
|
execute <<~SQL if Migration::Helpers.existing_site?
|
||||||
|
INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
|
||||||
|
VALUES('enable_welcome_banner', 5, 'f', NOW(), NOW())
|
||||||
|
ON CONFLICT (name) DO NOTHING
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
raise ActiveRecord::IrreversibleMigration
|
||||||
|
end
|
||||||
|
end
|
34
spec/system/page_objects/components/welcome_banner.rb
Normal file
34
spec/system/page_objects/components/welcome_banner.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module PageObjects
|
||||||
|
module Components
|
||||||
|
class WelcomeBanner < PageObjects::Components::Base
|
||||||
|
def visible?
|
||||||
|
has_css?(".welcome-banner")
|
||||||
|
end
|
||||||
|
|
||||||
|
def hidden?
|
||||||
|
has_no_css?(".welcome-banner")
|
||||||
|
end
|
||||||
|
|
||||||
|
def invisible?
|
||||||
|
has_css?(".welcome-banner", visible: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_anonymous_title?
|
||||||
|
has_css?(
|
||||||
|
".welcome-banner .welcome-banner__title",
|
||||||
|
text: I18n.t("js.welcome_banner.header.anonymous_members", site_name: SiteSetting.title),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_logged_in_title?(username)
|
||||||
|
has_css?(
|
||||||
|
".welcome-banner .welcome-banner__title",
|
||||||
|
text:
|
||||||
|
I18n.t("js.welcome_banner.header.logged_in_members", preferred_display_name: username),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,7 +9,7 @@ module PageObjects
|
||||||
end
|
end
|
||||||
|
|
||||||
def type_in_search_menu(input)
|
def type_in_search_menu(input)
|
||||||
find("input#search-term").send_keys(input)
|
find(".search-input--header input").send_keys(input)
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ describe "Search", type: :system do
|
||||||
SearchIndexer.enable
|
SearchIndexer.enable
|
||||||
SearchIndexer.index(topic, force: true)
|
SearchIndexer.index(topic, force: true)
|
||||||
SearchIndexer.index(topic2, force: true)
|
SearchIndexer.index(topic2, force: true)
|
||||||
|
SiteSetting.enable_welcome_banner = false
|
||||||
end
|
end
|
||||||
|
|
||||||
after { SearchIndexer.disable }
|
after { SearchIndexer.disable }
|
||||||
|
@ -68,6 +69,7 @@ describe "Search", type: :system do
|
||||||
SearchIndexer.index(topic, force: true)
|
SearchIndexer.index(topic, force: true)
|
||||||
SiteSetting.rate_limit_search_anon_user_per_minute = 4
|
SiteSetting.rate_limit_search_anon_user_per_minute = 4
|
||||||
RateLimiter.enable
|
RateLimiter.enable
|
||||||
|
SiteSetting.enable_welcome_banner = false
|
||||||
end
|
end
|
||||||
|
|
||||||
after { SearchIndexer.disable }
|
after { SearchIndexer.disable }
|
||||||
|
@ -93,6 +95,7 @@ describe "Search", type: :system do
|
||||||
SearchIndexer.enable
|
SearchIndexer.enable
|
||||||
SearchIndexer.index(topic, force: true)
|
SearchIndexer.index(topic, force: true)
|
||||||
SearchIndexer.index(topic2, force: true)
|
SearchIndexer.index(topic2, force: true)
|
||||||
|
SiteSetting.enable_welcome_banner = false
|
||||||
end
|
end
|
||||||
|
|
||||||
after { SearchIndexer.disable }
|
after { SearchIndexer.disable }
|
||||||
|
@ -170,6 +173,7 @@ describe "Search", type: :system do
|
||||||
SearchIndexer.enable
|
SearchIndexer.enable
|
||||||
SearchIndexer.index(topic, force: true)
|
SearchIndexer.index(topic, force: true)
|
||||||
SearchIndexer.index(topic2, force: true)
|
SearchIndexer.index(topic2, force: true)
|
||||||
|
SiteSetting.enable_welcome_banner = false
|
||||||
sign_in(admin)
|
sign_in(admin)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
73
spec/system/welcome_banner_spec.rb
Normal file
73
spec/system/welcome_banner_spec.rb
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
describe "Welcome banner", type: :system do
|
||||||
|
fab!(:current_user) { Fabricate(:user) }
|
||||||
|
let(:banner) { PageObjects::Components::WelcomeBanner.new }
|
||||||
|
let(:search_page) { PageObjects::Pages::Search.new }
|
||||||
|
|
||||||
|
context "when welcome banner is enabled" do
|
||||||
|
before { SiteSetting.enable_welcome_banner = true }
|
||||||
|
|
||||||
|
it "shows for logged in and anonymous users" do
|
||||||
|
visit "/"
|
||||||
|
expect(banner).to be_visible
|
||||||
|
expect(banner).to have_anonymous_title
|
||||||
|
sign_in(current_user)
|
||||||
|
visit "/"
|
||||||
|
expect(banner).to have_logged_in_title(current_user.username)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "only displays on top_menu routes" do
|
||||||
|
sign_in(current_user)
|
||||||
|
SiteSetting.remove_override!(:top_menu)
|
||||||
|
topic = Fabricate(:topic)
|
||||||
|
visit "/"
|
||||||
|
expect(banner).to be_visible
|
||||||
|
visit "/latest"
|
||||||
|
expect(banner).to be_visible
|
||||||
|
visit "/new"
|
||||||
|
expect(banner).to be_visible
|
||||||
|
visit "/unread"
|
||||||
|
expect(banner).to be_visible
|
||||||
|
visit "/hot"
|
||||||
|
expect(banner).to be_visible
|
||||||
|
visit "/tags"
|
||||||
|
expect(banner).to be_hidden
|
||||||
|
visit topic.relative_url
|
||||||
|
expect(banner).to be_hidden
|
||||||
|
end
|
||||||
|
|
||||||
|
it "hides welcome banner and shows header search on scroll, and vice-versa" do
|
||||||
|
SiteSetting.search_experience = "search_field"
|
||||||
|
Fabricate(:topic)
|
||||||
|
|
||||||
|
sign_in(current_user)
|
||||||
|
visit "/"
|
||||||
|
expect(banner).to be_visible
|
||||||
|
expect(search_page).to have_no_search_field
|
||||||
|
|
||||||
|
# Trick to give a huge vertical space to scroll
|
||||||
|
page.execute_script("document.querySelector('.topic-list').style.height = '10000px'")
|
||||||
|
page.scroll_to(0, 1000)
|
||||||
|
|
||||||
|
expect(banner).to be_invisible
|
||||||
|
expect(search_page).to have_search_field
|
||||||
|
|
||||||
|
page.scroll_to(0, 0)
|
||||||
|
expect(banner).to be_visible
|
||||||
|
expect(search_page).to have_no_search_field
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when welcome banner is not enabled" do
|
||||||
|
before { SiteSetting.enable_welcome_banner = false }
|
||||||
|
|
||||||
|
it "does not show the welcome banner for logged in and anonymous users" do
|
||||||
|
visit "/"
|
||||||
|
expect(banner).to be_hidden
|
||||||
|
sign_in(current_user)
|
||||||
|
visit "/"
|
||||||
|
expect(banner).to be_hidden
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Add a link
Reference in a new issue