Zentrales Header-Thema für Benutzersymbole

Hallo, ich versuche, die Trennung des Header-Menüs mit dem Benutzer und den Benachrichtigungen ähnlich dem zentralen Thema auf Meta nachzubilden. Ich habe im Thema-Thread gefragt, aber keine Antwort erhalten.

Wenn ich dasselbe tun wollte, welche Dateien müsste ich bearbeiten und ist es besser, die Datei in meinem Thema zu platzieren oder sie mit einer Themenkomponente nachzubilden?

1 „Gefällt mir“

Wenn Sie eine Seite inspizieren und den Tab „Quellen“ aufrufen, können Sie sehen, wie sie erstellt wurde.

Im Wesentlichen:

  • Das neue Benutzermenü wird mit einem Widget erstellt, das mit api.addToHeaderIcons hinzugefügt wird.
  • Das Benachrichtigungsmenü:
    • Der Avatar wird durch ein Glockensymbol ersetzt, indem sein Inhalt aus dem Widget header-notifications ersetzt wird.
    • Das Schnelleinstiegssymbol des Benutzermenüs wird mit CSS ausgeblendet.
5 „Gefällt mir“

Vielen Dank wie immer für Ihre Hilfe. Ich werde eine Staging-Entwicklungsumgebung einrichten, um das Problem zu lösen. Nochmals vielen Dank.

1 „Gefällt mir“

Hallo @digitaldominica! Entschuldige, dass ich den Thread eine Weile nicht überprüft habe, da ich bald das nächste Update veröffentliche. Jeder hat so wertvolles Feedback, aber wenn ich nicht wegschaue, werde ich dazu neigen, es zu meiner aktuellen Liste hinzuzufügen, anstatt es für das Update danach zu speichern. :sweat_smile:

@Arkshine hat Recht. Es ist eine ziemlich provisorische Methode, die innerhalb der Einschränkungen eines Themes funktioniert (vieles von Central ist nur Prototyping, da ich zuerst, zweitens und drittens Designer und viertens Entwickler bin).

Ich werde eine Schritt-für-Schritt-Anleitung geben, wie ich den groben Prototyp in Central erstellt habe. Aber Haftungsausschluss: Diese Lösung ist möglicherweise nicht zukunftssicher, wenn wir jemals ein Kernupdate für das Benutzermenü vornehmen, und es mag einen optimaleren Weg geben, die Komponente zu erstellen.


Schritt 1: Erstellen Sie eine benutzerdefinierte Benutzermenükomponente

Erstellen Sie diese Dateien –

:page_facing_up: /javascripts/discourse/components/header-user-new.js
:page_facing_up: /javascripts/discourse/components/header-user-new.hbs

import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import { inject as service } from "@ember/service";

export default class HeaderUserNew extends Component {
  @service currentUser;
  @tracked isActive = false;

  constructor() {
    super(...arguments);
    this.handleDocumentClick = this.handleDocumentClick.bind(this);
  }

  @action
  toggleDropdown() {
    this.isActive = !this.isActive;

    if (this.isActive) {
      setTimeout(() => {
        document.addEventListener("click", this.handleDocumentClick);
      }, 0);
    } else {
      document.removeEventListener("click", this.handleDocumentClick);
    }
  }

  handleDocumentClick(event) {
    const dropdown = document.querySelector(".header-user-new__menu");
    const isClickInside = dropdown.contains(event.target);

    if (!isClickInside) {
      this.isActive = false;
      document.removeEventListener("click", this.handleDocumentClick);
    }
  }

  willDestroy() {
    super.willDestroy();
    document.removeEventListener("click", this.handleDocumentClick);
  }
}
<div class={{concatClass "header-user-new" (if isActive "active")}}>
  <button class="header-user-new__button" type="button" {{on "click" this.toggleDropdown}}>
    {{avatar currentUser}}
  </button>

  <div class="header-user-new__menu">
    <LinkTo class="header-user-new__profile" @route="user.summary" @model={{this.currentUser}}>
      {{avatar currentUser}}
      <div class="header-user-new__profile-info">
        <span class="header-user-new__profile-name">
          {{#if currentUser.name}}
            {{currentUser.name}}
          {{else}}
            {{currentUser.username}}
          {{/if}}
        </span>
        <span class="header-user-new__profile-view">
          View Profile
        </span>
      </div>
    </LinkTo>

    <ul>
      <li>
        <LinkTo @route="userActivity.bookmarks" @model={{this.currentUser}}>
          {{d-icon "bookmark"}}
          <span>
            {{i18n "js.user.bookmarks"}}
          </span>
        </LinkTo>
      </li>
      <li>
        <LinkTo @route="preferences" @model={{this.currentUser}}>
          {{d-icon "cog"}}
          <span>
            {{i18n "user.preferences"}}
          </span>
        </LinkTo>
      </li>
      <li>
        <DButton @action={{route-action "logout"}}>
          {{d-icon "sign-out-alt"}}
          <span>
            {{i18n "user.log_out"}}
          </span>
        </DButton>
      </li>
    </ul>
  </div>
</div>

Vorerst überlasse ich Ihnen das CSS-Styling, aber es ist wichtig, diesen Teil für den Toggle-Effekt einzuschließen –

.header-user-new {
  &.active {
    .header-user-new__menu {
      display: flex;
    }
  }
  .header-user-new__menu {
    display: none;
  }
}

Schritt 2: Registrieren Sie die Komponente als Widget

Erstellen Sie diese Datei –

:page_facing_up: /javascripts/discourse/widgets/header-user-new.js

import { hbs } from "ember-cli-htmlbars";
import RenderGlimmer from "discourse/widgets/render-glimmer";
import { createWidget } from "discourse/widgets/widget";

export default createWidget("header-user-new", {
  tagName: "li.header-dropdown-toggle.header-user-new",

  html() {
    return [new RenderGlimmer(this, "div", hbs`<HeaderUserNew />`)];
  },
});

Schritt 3: Fügen Sie das Widget zum Header hinzu und ersetzen Sie das vorhandene Benutzersymbol durch ein Benachrichtigungsglockensymbol

Erstellen Sie diese Datei –

:page_facing_up: /javascripts/discourse/initializers/header-edit.js

import { h } from "virtual-dom";
import { withPluginApi } from "discourse/lib/plugin-api";
import { iconNode } from "discourse-common/lib/icon-library";
import I18n from "discourse-i18n";

export default {
  initialize() {
    withPluginApi("0.8", (api) => {
      api.reopenWidget("header-notifications", {
        html(attrs) {
          const { user } = attrs;

          let avatarAttrs = {
            template: user.get("avatar_template"),
            username: user.get("username"),
          };

          if (this.siteSettings.enable_names) {
            avatarAttrs.name = user.get("name");
          }

          const contents = [h("div", iconNode("bell"))];

          if (this.currentUser.status) {
            contents.push(
              this.attach("user-status-bubble", this.currentUser.status)
            );
          }

          if (user.isInDoNotDisturb()) {
            contents.push(h("div.do-not-disturb-background", iconNode("moon")));
          } else {
            if (user.new_personal_messages_notifications_count) {
              contents.push(
                this.attach("link", {
                  action: attrs.action,
                  className: "badge-notification with-icon new-pms",
                  icon: "envelope",
                  omitSpan: true,
                  title: "notifications.tooltip.new_message_notification",
                  titleOptions: {
                    count: user.new_personal_messages_notifications_count,
                  },
                  attributes: {
                    "aria-label": I18n.t(
                      "notifications.tooltip.new_message_notification",
                      {
                        count: user.new_personal_messages_notifications_count,
                      }
                    ),
                  },
                })
              );
            } else if (user.unseen_reviewable_count) {
              contents.push(
                this.attach("link", {
                  action: attrs.action,
                  className: "badge-notification with-icon new-reviewables",
                  icon: "flag",
                  omitSpan: true,
                  title: "notifications.tooltip.new_reviewable",
                  titleOptions: { count: user.unseen_reviewable_count },
                  attributes: {
                    "aria-label": I18n.t(
                      "notifications.tooltip.new_reviewable",
                      {
                        count: user.unseen_reviewable_count,
                      }
                    ),
                  },
                })
              );
            } else if (user.all_unread_notifications_count) {
              contents.push(
                this.attach("link", {
                  action: attrs.action,
                  className: "badge-notification unread-notifications",
                  rawLabel: user.all_unread_notifications_count,
                  omitSpan: true,
                  title: "notifications.tooltip.regular",
                  titleOptions: { count: user.all_unread_notifications_count },
                  attributes: {
                    "aria-label": I18n.t("user.notifications"),
                  },
                })
              );
            }
          }
          return contents;
        },
      });

      const currentUser = api.container.lookup("service:current-user");
      if (currentUser !== null) {
        api.addToHeaderIcons("header-user-new");
      }
    });
  },
};

Die Hauptänderung bestand darin, avatarImg(...) durch iconNode zu ersetzen, um das Benachrichtigungssymbol anstelle des Benutzeravatars zu verwenden, indem das vorhandene header-notifications-Widget bearbeitet (oder „wiedereröffnet“) wurde.

Der ursprüngliche header-notifications-Code als Referenz: discourse/app/assets/javascripts/discourse/app/widgets/header.js at 9bc78625af1d54693bc4f1bad3eaa9161ae030b6 · discourse/discourse · GitHub

Und wie @Arkshine erwähnte, habe ich den Benutzerbereich im Benachrichtigungsmenü mit CSS ausgeblendet.

.d-header .panel {
  .user-menu.revamped .bottom-tabs, #user-menu-button-profile {
    display: none;
  }
}
7 „Gefällt mir“

Hallo, ich habe es geschafft, das Benutzer-AvatarImg durch das Glockensymbol zu ersetzen, aber das

api.addToHeaderIcons("new-user-icon");

entfernt den gesamten Header, anstatt den Benutzeravatar mit Dropdown anzuzeigen.

2 „Gefällt mir“

Mein Versehen, da war ein Tippfehler in diesem Code, er sollte lauten –

api.addToHeaderIcons(“header-user-new”);

Da das Widget in Schritt 2 als header-user-new registriert ist.

3 „Gefällt mir“

Danke, das hat funktioniert.

Wenn ich noch eine separate Frage stellen darf:
Wie wechselt die Vorlage für die zentrale Themenliste zwischen „vom Benutzer gepostet“ und „vom Benutzer geantwortet“?

Ich habe {{#if topic.replies}} und {{#if topic.posters.[0]}} versucht, aber das funktioniert nicht.

Kein Problem! topic.posters.1.user ist das, wonach Sie suchen (die erste Antwort). Wenn es existiert, verwenden Sie es, andernfalls verwenden Sie den OP als Standard.

So ist es derzeit in Central strukturiert:

{{#if topic.posters.1.user}}
  <span class="tli__last-reply">
    {{d-icon "reply"}}
    <a href="{{topic.lastPoster.user.userPath}}" data-user-card="{{topic.lastPoster.user.username}}">
      {{~topic.lastPoster.user.username~}}
    </a>
    {{theme-i18n "topic_list_item.replied"}}
    <a href={{topic.lastPostUrl}}>
      {{format-date topic.bumpedAt format="medium" leaveAgo="true"}}
    </a>
  </span>
{{else}}
  <span class="tli__last-reply">
    {{d-icon "m-post_add"}}
    <a href="{{topic.posters.0.user.userPath}}" data-user-card="{{topic.posters.0.user.username}}">
      {{~topic.posters.0.user.username~}}
    </a>
    posted
    <a href={{topic.lastPostUrl}}>
      {{format-date topic.bumpedAt format="medium" leaveAgo="true"}}
    </a>
  </span>
{{/if}}
1 „Gefällt mir“

Okay, topic.posters.1.user fungiert als Beitragsautor?

Oh nein, topic.posters.0.user ist der Autor, topic.posters.1.user ist der erste antwortende Benutzer (falls vorhanden). :laughing:

3 „Gefällt mir“

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.