Files
discourse/app/assets/javascripts/select-kit/addon/components/selected-name.js
David Battersby d06c60ca7c FEATURE: add icons and emojis to category (#31795)
This feature allow admins to personalize their communities by
associating emojis or icons with their site categories.

There are now 3 style types for categories:
- Square (the default)
- Emoji
- Icon

### How it looks 🎨 

Adding an icon:

<img width="502" alt="Category with an icon"
src="https://github.com/user-attachments/assets/8f711340-166e-4781-a7b7-7267469dbabd"
/>

Adding an emoji:

<img width="651" alt="Category with an emoji"
src="https://github.com/user-attachments/assets/588c38ce-c719-4ed5-83f9-f1e1cb52c929"
/>

Sidebar:

<img width="248" alt="Sidebar with emojis"
src="https://github.com/user-attachments/assets/cd03d591-6170-4515-998c-0cec20118568"
/>

Category menus:

<img width="621" alt="Screenshot 2025-03-13 at 10 32 30 AM"
src="https://github.com/user-attachments/assets/7d89797a-f69f-45e5-bf64-a92d4cff8753"
/>

Within posts/topics:

<img width="382" alt="Screenshot 2025-03-13 at 10 33 41 AM"
src="https://github.com/user-attachments/assets/b7b1a951-44c6-4a4f-82ad-8ee31ddd6061"
/>

Chat messages:

<img width="392" alt="Screenshot 2025-03-13 at 10 30 20 AM"
src="https://github.com/user-attachments/assets/126f8076-0ea3-4f19-8452-1041fd2af29f"
/>

Autocomplete:

<img width="390" alt="Screenshot 2025-03-13 at 10 29 53 AM"
src="https://github.com/user-attachments/assets/cad75669-225f-4b8e-a7b5-ae5aa8f1bcad"
/>

---------

Co-authored-by: Martin Brennan <martin@discourse.org>
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
2025-03-26 09:46:17 +04:00

93 lines
2.3 KiB
JavaScript

import Component from "@ember/component";
import { computed, get } from "@ember/object";
import { reads } from "@ember/object/computed";
import { guidFor } from "@ember/object/internals";
import { tagName } from "@ember-decorators/component";
import { makeArray } from "discourse/lib/helpers";
import UtilsMixin from "select-kit/mixins/utils";
@tagName("")
export default class SelectedName extends Component.extend(UtilsMixin) {
name = null;
value = null;
headerTitle = null;
headerLang = null;
headerLabel = null;
id = null;
@reads("headerLang") lang;
init() {
super.init(...arguments);
this.set("id", guidFor(this));
}
didReceiveAttrs() {
super.didReceiveAttrs(...arguments);
// we can't listen on `item.nameProperty` given it's variable
this.setProperties({
headerLabel: this.getProperty(this.item, "labelProperty"),
headerTitle: this.getProperty(this.item, "titleProperty"),
headerLang: this.getProperty(this.item, "langProperty"),
name: this.getName(this.item),
renderIcon: this.canDisplayIcon,
value:
this.item === this.selectKit.noneItem ? null : this.getValue(this.item),
});
}
@computed("selectKit.options.shouldDisplayIcon")
get canDisplayIcon() {
return this.selectKit.options.shouldDisplayIcon ?? true;
}
@computed("item", "sanitizedTitle")
get ariaLabel() {
return this._safeProperty("ariaLabel", this.item) || this.sanitizedTitle;
}
// this might need a more advanced solution
// but atm it's the only case we have to handle
@computed("title")
get sanitizedTitle() {
return String(this.title).replace("&hellip;", "");
}
@computed("headerTitle", "item")
get title() {
return (
this.headerTitle ||
this._safeProperty("title", this.item) ||
this.name ||
""
);
}
@computed("headerLabel", "title", "name")
get label() {
return (
this.headerLabel ||
this._safeProperty("label", this.item) ||
this.title ||
this.name
);
}
@computed("item.{icon,icons}")
get icons() {
const icon = makeArray(this._safeProperty("icon", this.item));
const icons = makeArray(this._safeProperty("icons", this.item));
return icon.concat(icons).filter(Boolean);
}
_safeProperty(name, content) {
if (!content) {
return null;
}
return get(content, name);
}
}