### Install Frontend Skills Plugin Source: https://github.com/discourse/skills/blob/main/README.md Command to install the frontend-skills plugin. ```bash /plugin install frontend-skills@discourse-agent-skills ``` -------------------------------- ### Real Example Source: https://github.com/discourse/skills/blob/main/skills/css/SKILL.md An example of CSS from the Discourse chat plugin loading skeleton. ```scss .chat-skeleton { &__body { display: flex; &.--with-avatar { padding-left: 50px; } } &__message { &.is-loading { animation: pulse 1.5s infinite; } } } ``` -------------------------------- ### Handling Legacy Code Source: https://github.com/discourse/skills/blob/main/skills/css/SKILL.md Example of how to add new CSS correctly when existing code uses incorrect syntax. ```scss // ❌ WRONG - existing legacy code .d-button.-cancel { } .d-button.-primary { } // ✅ CORRECT - your addition .d-button.--success { } ``` -------------------------------- ### jQuery vs Native DOM Source: https://github.com/discourse/skills/blob/main/skills/javascript/SKILL.md Examples demonstrating the replacement of jQuery methods with native DOM equivalents. ```javascript // ❌ NEVER - jQuery $(".submit-btn").on("click", function () { $(".success").fadeIn(); }); // ✅ ALWAYS - Native DOM const btn = document.querySelector(".submit-btn"); btn.addEventListener("click", () => { document.querySelector(".success").classList.add("visible"); }); ``` -------------------------------- ### Singleton Imports vs Dependency Injection Source: https://github.com/discourse/skills/blob/main/skills/javascript/SKILL.md Examples showing the incorrect use of singleton imports and the correct use of dependency injection for accessing site properties. ```javascript // ❌ NEVER - Singleton import import Site from "discourse/models/site"; console.log(Site.currentProp("top_menu_items")); // ✅ ALWAYS - Dependency injection // In components, routes, controllers - site is auto-injected: console.log(this.site.top_menu_items); // In initializers: let site = container.lookup("site:main"); console.log(site.top_menu_items); ``` -------------------------------- ### Cleanup: Event Listeners and Timers Source: https://github.com/discourse/skills/blob/main/skills/javascript/SKILL.md Example demonstrating how to properly remove event listeners and cancel timers in the willDestroyElement hook to prevent memory leaks. ```javascript export default Component.extend({ didInsertElement() { this._super(...arguments); this.clickHandler = () => this.handleClick(); document.addEventListener("click", this.clickHandler); this.timerId = setTimeout(() => { this.doSomething(); }, 5000); }, willDestroyElement() { this._super(...arguments); // Clean up listener document.removeEventListener("click", this.clickHandler); // Cancel timer clearTimeout(this.timerId); }, }); ``` -------------------------------- ### Binding Context with @bind Decorator Source: https://github.com/discourse/skills/blob/main/skills/javascript/SKILL.md Example of using the @bind decorator when arrow functions cannot be used, to ensure correct context preservation. ```javascript import { bind } from "discourse-common/utils/decorators"; @bind myMethod() { console.log(this.property); } // Pass bound method reference library.setup({ callback: this.myMethod }); ``` -------------------------------- ### Service Injection with @service Decorator Source: https://github.com/discourse/skills/blob/main/skills/javascript/SKILL.md Example of using the @service decorator to inject common Discourse services into a component. ```javascript import { service } from "@ember/service"; export default class extends Component { @service router; @service currentUser; @service store; navigateToProfile() { this.router.transitionTo("user", this.currentUser.username); } } ``` -------------------------------- ### Default Objects/Arrays vs. Initialization in init() Source: https://github.com/discourse/skills/blob/main/skills/javascript/SKILL.md Demonstrates the incorrect way of using default objects/arrays which leads to shared references, and the correct way of initializing them within the init() method for EmberObjects. ```javascript // ❌ NEVER - Default objects/arrays export default EmberObject.extend({ items: [], // SHARED REFERENCE config: {} // SHARED REFERENCE }); // ✅ ALWAYS - Initialize in init() (EmberObject) export default EmberObject.extend({ items: null, config: null, init() { this._super(...arguments); this.items = []; this.config = {}; } }); // ✅ OR - Use native classes (no issue) export default class { items = []; // Each instance gets own array config = {}; // Each instance gets own object } ``` -------------------------------- ### State Classes Source: https://github.com/discourse/skills/blob/main/skills/css/SKILL.md States use `is-` or `has-` prefixes. ```scss .modal { display: none; &.is-open { display: block; } } .form { &.has-errors { .form__input { border-color: var(--danger); } } } ``` -------------------------------- ### Register Discourse Skills as a Claude Code Plugin Marketplace Source: https://github.com/discourse/skills/blob/main/README.md Command to register the discourse/skills repository as a Claude Code Plugin marketplace. ```bash /plugin marketplace add discourse/skills ``` -------------------------------- ### Visual Nesting Source: https://github.com/discourse/skills/blob/main/skills/css/SKILL.md Always nest related elements under block. ```scss .chat-message { // block styling display: flex; &__avatar { // element styling width: 40px; height: 40px; } &__content { flex: 1; } &__username { font-weight: bold; } &.--highlighted { // direct modifier background: var(--highlight-bg); } } ``` -------------------------------- ### Lifecycle Hooks: Explicit Methods vs @on Decorators Source: https://github.com/discourse/skills/blob/main/skills/javascript/SKILL.md Illustrates the correct use of explicit lifecycle methods over the deprecated @on decorators. ```javascript // ❌ NEVER - @on decorator @on("init") setupComponent() { this.set("data", []); } @on("init") setupOther() { this.loadData(); } // ✅ ALWAYS - Explicit lifecycle method init() { this._super(...arguments); this.data = []; this.loadData(); } ``` -------------------------------- ### Array Prototype Extensions vs. Native Methods Source: https://github.com/discourse/skills/blob/main/skills/javascript/SKILL.md Shows the deprecated usage of Ember's array prototype extensions and the recommended approach using native Array methods. ```javascript const items = [{ name: "foo" }, { name: "bar" }]; // ❌ NEVER - Ember prototype extension items.findBy("name", "foo"); // ✅ ALWAYS - Native method items.find((item) => item.name === "foo"); ``` -------------------------------- ### Private Fields using # Syntax Source: https://github.com/discourse/skills/blob/main/skills/javascript/SKILL.md Illustrates the use of the '#' syntax for true private fields in JavaScript classes, contrasting it with public fields and fields requiring decorators. ```javascript export default class extends Component { // Public - used in template @tracked count = 0; // Public - decorator doesn't work on private @action increment() { this.#updateCount(); } // Private - not used in template #internalState = null; #updateCount() { this.count++; } } ``` -------------------------------- ### Observers vs. Action Handlers and Getters Source: https://github.com/discourse/skills/blob/main/skills/javascript/SKILL.md Contrasts the outdated use of observers with modern approaches using action handlers for user events and native getters for derived data. ```javascript // ❌ NEVER - Observer @observes('userInput') inputChanged() { this.processInput(); } // ✅ ALWAYS - Action handler for user events ``` ```javascript // ✅ Native getter for computed values get fullName() { return `${this.firstName} ${this.lastName}`; } ``` -------------------------------- ### self = this vs Arrow Functions Source: https://github.com/discourse/skills/blob/main/skills/javascript/SKILL.md Demonstrates the outdated 'self = this' pattern and the preferred arrow function syntax for preserving context. ```javascript // ❌ NEVER - self = this pattern let self = this; setTimeout(function () { self.doSomething(); }, 1000); // ✅ ALWAYS - Arrow function setTimeout(() => { this.doSomething(); }, 1000); ``` -------------------------------- ### Direct Modifier (on element itself) Source: https://github.com/discourse/skills/blob/main/skills/css/SKILL.md Applies a modifier directly to the element it modifies. ```scss .d-button { background: var(--primary); &.--cancel { background: var(--secondary); } &.--danger { background: var(--danger); } } ``` ```html ``` -------------------------------- ### Indirect Modifier (on parent) Source: https://github.com/discourse/skills/blob/main/skills/css/SKILL.md Applies a modifier to child elements based on a state of the parent element. Use indirect when styling multiple child elements based on parent state. ```scss .user-form { &__input { border: 1px solid var(--primary-low); // Indirect modifier - applies when parent has --error .--error & { border-color: var(--danger); } } &__label { color: var(--primary); .--error & { color: var(--danger); } } } ``` ```html
...
``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.