DEV: Add subsection capabilities to the sidebar API
This commit is contained in:
parent
86bb07f619
commit
97bc09b4d1
|
@ -18,43 +18,53 @@ const SidebarApiSection = <template>
|
|||
@activeLink={{@section.activeLink}}
|
||||
@expandWhenActive={{@expandWhenActive}}
|
||||
@scrollActiveLinkIntoView={{@scrollActiveLinkIntoView}}
|
||||
@level={{@section.level}}
|
||||
>
|
||||
{{#each @section.filteredLinks key="name" as |link|}}
|
||||
{{#each @section.filteredLinks key="name" as |item|}}
|
||||
{{#if item.links}}
|
||||
<SidebarApiSection
|
||||
@section={{item}}
|
||||
@collapsable={{@collapsable}}
|
||||
@expandWhenActive={{@expandActiveSection}}
|
||||
@scrollActiveLinkIntoView={{@scrollActiveLinkIntoView}}
|
||||
/>
|
||||
{{else}}
|
||||
<SectionLink
|
||||
@linkName={{link.name}}
|
||||
@linkClass={{link.classNames}}
|
||||
@route={{link.route}}
|
||||
@model={{link.model}}
|
||||
@query={{link.query}}
|
||||
@models={{link.models}}
|
||||
@currentWhen={{link.currentWhen}}
|
||||
@href={{link.href}}
|
||||
@title={{link.title}}
|
||||
@contentCSSClass={{link.contentCSSClass}}
|
||||
@prefixColor={{link.prefixColor}}
|
||||
@prefixBadge={{link.prefixBadge}}
|
||||
@prefixType={{link.prefixType}}
|
||||
@prefixValue={{link.prefixValue}}
|
||||
@prefixCSSClass={{link.prefixCSSClass}}
|
||||
@suffixType={{link.suffixType}}
|
||||
@suffixValue={{link.suffixValue}}
|
||||
@suffixCSSClass={{link.suffixCSSClass}}
|
||||
@hoverType={{link.hoverType}}
|
||||
@hoverValue={{link.hoverValue}}
|
||||
@hoverAction={{link.hoverAction}}
|
||||
@hoverTitle={{link.hoverTitle}}
|
||||
@didInsert={{link.didInsert}}
|
||||
@willDestroy={{link.willDestroy}}
|
||||
@content={{link.text}}
|
||||
@linkName={{item.name}}
|
||||
@linkClass={{item.classNames}}
|
||||
@route={{item.route}}
|
||||
@model={{item.model}}
|
||||
@query={{item.query}}
|
||||
@models={{item.models}}
|
||||
@currentWhen={{item.currentWhen}}
|
||||
@href={{item.href}}
|
||||
@title={{item.title}}
|
||||
@contentCSSClass={{item.contentCSSClass}}
|
||||
@prefixColor={{item.prefixColor}}
|
||||
@prefixBadge={{item.prefixBadge}}
|
||||
@prefixType={{item.prefixType}}
|
||||
@prefixValue={{item.prefixValue}}
|
||||
@prefixCSSClass={{item.prefixCSSClass}}
|
||||
@suffixType={{item.suffixType}}
|
||||
@suffixValue={{item.suffixValue}}
|
||||
@suffixCSSClass={{item.suffixCSSClass}}
|
||||
@hoverType={{item.hoverType}}
|
||||
@hoverValue={{item.hoverValue}}
|
||||
@hoverAction={{item.hoverAction}}
|
||||
@hoverTitle={{item.hoverTitle}}
|
||||
@didInsert={{item.didInsert}}
|
||||
@willDestroy={{item.willDestroy}}
|
||||
@content={{item.text}}
|
||||
@contentComponent={{component
|
||||
link.contentComponent
|
||||
status=link.contentComponentArgs
|
||||
item.contentComponent
|
||||
status=item.contentComponentArgs
|
||||
}}
|
||||
@scrollIntoView={{and
|
||||
@scrollActiveLinkIntoView
|
||||
(eq link.name @section.activeLink.name)
|
||||
(eq item.name @section.activeLink.name)
|
||||
}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</Section>
|
||||
{{/if}}
|
||||
|
|
|
@ -2,6 +2,8 @@ import Component from "@glimmer/component";
|
|||
import { cached } from "@glimmer/tracking";
|
||||
import { getOwner, setOwner } from "@ember/owner";
|
||||
import { service } from "@ember/service";
|
||||
import BaseCustomSidebarSection from "../../lib/sidebar/base-custom-sidebar-section";
|
||||
import BaseCustomSidebarSectionLink from "../../lib/sidebar/base-custom-sidebar-section-link";
|
||||
import ApiSection from "./api-section";
|
||||
import PanelHeader from "./panel-header";
|
||||
|
||||
|
@ -20,20 +22,13 @@ export default class SidebarApiSections extends Component {
|
|||
sectionConfigs = this.sidebarState.currentPanel.sections;
|
||||
}
|
||||
|
||||
return sectionConfigs.map((Section) => {
|
||||
const SidebarSection = prepareSidebarSectionClass(Section, this.router);
|
||||
|
||||
const sectionInstance = new SidebarSection({
|
||||
filterable:
|
||||
!this.sidebarState.combinedMode &&
|
||||
this.sidebarState.currentPanel.filterable,
|
||||
return sectionConfigs.map((SectionClass) =>
|
||||
initializeSection(SectionClass, {
|
||||
routerService: this.router,
|
||||
sidebarState: this.sidebarState,
|
||||
});
|
||||
|
||||
setOwner(sectionInstance, getOwner(this));
|
||||
|
||||
return sectionInstance;
|
||||
});
|
||||
owner: this,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
get filteredSections() {
|
||||
|
@ -54,15 +49,52 @@ export default class SidebarApiSections extends Component {
|
|||
</template>
|
||||
}
|
||||
|
||||
function initializeSection(SectionClass, opts) {
|
||||
const { sidebarState, owner } = opts;
|
||||
|
||||
const SidebarSection = prepareSidebarSectionClass(SectionClass, opts);
|
||||
|
||||
const sectionInstance = new SidebarSection({
|
||||
filterable:
|
||||
!sidebarState.combinedMode && sidebarState.currentPanel.filterable,
|
||||
sidebarState,
|
||||
});
|
||||
|
||||
setOwner(sectionInstance, getOwner(owner));
|
||||
|
||||
return sectionInstance;
|
||||
}
|
||||
|
||||
// extends the class provided for the section to add functionality we don't want to be overridable when defining custom
|
||||
// sections using the plugin API, like for example the filtering capabilities
|
||||
function prepareSidebarSectionClass(Section, routerService) {
|
||||
return class extends Section {
|
||||
function prepareSidebarSectionClass(SectionClass, opts) {
|
||||
const { routerService, level = 0 } = opts;
|
||||
|
||||
return class extends SectionClass {
|
||||
#level;
|
||||
|
||||
constructor({ filterable, sidebarState }) {
|
||||
super();
|
||||
|
||||
this.filterable = filterable;
|
||||
this.sidebarState = sidebarState;
|
||||
this.#level = level;
|
||||
}
|
||||
|
||||
get level() {
|
||||
return this.#level;
|
||||
}
|
||||
|
||||
@cached
|
||||
get links() {
|
||||
return super.links.map((item) => {
|
||||
return item instanceof BaseCustomSidebarSectionLink
|
||||
? item
|
||||
: initializeSection(item, {
|
||||
...opts,
|
||||
level: level + 1,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@cached
|
||||
|
@ -75,13 +107,19 @@ function prepareSidebarSectionClass(Section, routerService) {
|
|||
return this.links;
|
||||
}
|
||||
|
||||
return this.links.filter((link) => {
|
||||
return this.links.filter((item) => {
|
||||
// subsection
|
||||
if (item instanceof BaseCustomSidebarSection) {
|
||||
return item.filteredLinks.length > 0;
|
||||
}
|
||||
|
||||
// standard link
|
||||
return (
|
||||
link.text
|
||||
item.text
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.match(this.sidebarState.sanitizedFilter) ||
|
||||
link.keywords.navigation.some((keyword) =>
|
||||
item.keywords.navigation.some((keyword) =>
|
||||
keyword.match(this.sidebarState.sanitizedFilter)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { hash } from "@ember/helper";
|
||||
import { concat, hash } from "@ember/helper";
|
||||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||
import { service } from "@ember/service";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { gt } from "truth-helpers";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import element from "discourse/helpers/element";
|
||||
import {
|
||||
getCollapsedSidebarSectionKey,
|
||||
getSidebarSectionContentId,
|
||||
|
@ -41,6 +43,11 @@ export default class SidebarSection extends Component {
|
|||
this.args.willDestroy?.();
|
||||
}
|
||||
|
||||
get dynamicElement() {
|
||||
const tagName = this.args.level > 0 ? "li" : "div";
|
||||
return element(tagName);
|
||||
}
|
||||
|
||||
get isCollapsed() {
|
||||
if (!this.args.collapsable) {
|
||||
return false;
|
||||
|
@ -158,17 +165,19 @@ export default class SidebarSection extends Component {
|
|||
|
||||
<template>
|
||||
{{#if this.displaySection}}
|
||||
<div
|
||||
<this.dynamicElement
|
||||
{{didInsert this.setExpandedState}}
|
||||
data-section-name={{@sectionName}}
|
||||
class={{concatClass
|
||||
"sidebar-section"
|
||||
"sidebar-section-wrapper"
|
||||
(if (gt @level 0) "sidebar-subsection")
|
||||
(if
|
||||
this.displaySectionContent
|
||||
"sidebar-section--expanded"
|
||||
"sidebar-section--collapsed"
|
||||
)
|
||||
(concat "sidebar-section--level-" @level)
|
||||
}}
|
||||
...attributes
|
||||
>
|
||||
|
@ -241,7 +250,7 @@ export default class SidebarSection extends Component {
|
|||
{{yield}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
</div>
|
||||
</this.dynamicElement>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ const shortcuts = {
|
|||
a: <template><a ...attributes>{{yield}}</a></template>,
|
||||
button: <template><button ...attributes>{{yield}}</button></template>,
|
||||
td: <template><td ...attributes>{{yield}}</td></template>,
|
||||
li: <template><li ...attributes>{{yield}}</li></template>,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -160,3 +160,7 @@
|
|||
padding-right: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-subsection {
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue