diff --git a/extensions/tags/js/src/forum/addTagFilter.tsx b/extensions/tags/js/src/forum/addTagFilter.tsx index 13875b15e6..98430ce3f0 100644 --- a/extensions/tags/js/src/forum/addTagFilter.tsx +++ b/extensions/tags/js/src/forum/addTagFilter.tsx @@ -87,6 +87,16 @@ export default function addTagFilter() { } }); + // Name the current tag in the index title control. The nav dropdown only falls + // back to this label when none of its items is active, so it surfaces exactly + // when the current tag has no item in the sidebar nav, which is the case for + // any secondary tag outside the 3 most discussed ones. + extend(IndexPage.prototype, 'view', function () { + const tag = app.currentTag(); + + if (tag) app.current.set('titleControlLabel', tag.name()); + }); + // If currently viewing a tag, restyle the 'new discussion' button to use // the tag's color, and disable if the user isn't allowed to edit. extend(IndexSidebar.prototype, 'items', function (items) { diff --git a/framework/core/js/src/forum/components/IndexSidebar.tsx b/framework/core/js/src/forum/components/IndexSidebar.tsx index e89badd0dc..a1f383377f 100644 --- a/framework/core/js/src/forum/components/IndexSidebar.tsx +++ b/framework/core/js/src/forum/components/IndexSidebar.tsx @@ -47,12 +47,18 @@ export default class IndexSidebar ); + // `SelectDropdown` labels its button with the active child, and falls back to + // `defaultLabel` when none of them is active. That happens whenever a page + // filters the discussion list without contributing a nav item of its own, so + // such a page can name itself here by setting `titleControlLabel` on + // `app.current`. Otherwise we are on the unfiltered index. items.add( 'nav', {this.navItems().toArray()} diff --git a/framework/core/js/tests/integration/forum/components/IndexSidebar.test.ts b/framework/core/js/tests/integration/forum/components/IndexSidebar.test.ts new file mode 100644 index 0000000000..6d56c94f9b --- /dev/null +++ b/framework/core/js/tests/integration/forum/components/IndexSidebar.test.ts @@ -0,0 +1,58 @@ +import bootstrapForum from '@flarum/jest-config/src/bootstrap/forum'; +import IndexSidebar from '../../../../src/forum/components/IndexSidebar'; +import { app } from '../../../../src/forum'; +import mq from 'mithril-query'; +import m from 'mithril'; + +beforeAll(() => bootstrapForum()); + +const titleControlLabel = (sidebar: any): string | undefined => + sidebar.rootEl.querySelector('.App-titleControl > .Dropdown-toggle .Button-labelText')?.textContent; + +const navItemLabel = (sidebar: any, item: string): string | undefined => + sidebar.rootEl.querySelector(`.Dropdown-menu .item-${item} .Button-labelText`)?.textContent; + +describe('IndexSidebar', () => { + beforeAll(() => app.boot()); + + afterEach(() => app.current.set('titleControlLabel', undefined)); + + test('renders', () => { + const sidebar = mq(IndexSidebar, {}); + + expect(sidebar).toHaveElement('.App-titleControl'); + }); + + test('labels the title control with the index link when no nav item is active', () => { + const sidebar = mq(IndexSidebar, {}); + + expect(titleControlLabel(sidebar)).toBeTruthy(); + expect(titleControlLabel(sidebar)).toBe(navItemLabel(sidebar, 'allDiscussions')); + }); + + test('labels the title control from app.current when a page provides a label', () => { + app.current.set('titleControlLabel', 'Support'); + + const sidebar = mq(IndexSidebar, {}); + + expect(titleControlLabel(sidebar)).toBe('Support'); + }); + + test('prefers an active nav item over the label from app.current', () => { + class SidebarWithActiveItem extends IndexSidebar { + navItems() { + const items = super.navItems(); + + items.add('active', m('button', { active: true }, 'Active item'), 200); + + return items; + } + } + + app.current.set('titleControlLabel', 'Support'); + + const sidebar = mq(SidebarWithActiveItem, {}); + + expect(titleControlLabel(sidebar)).toBe('Active item'); + }); +});