Skip to content

Commit dd84b9a

Browse files
authored
Make icons path configurable instead of hardcoded (#455)
1 parent 7f20116 commit dd84b9a

File tree

3 files changed

+111
-2
lines changed

3 files changed

+111
-2
lines changed

.github/copilot-instructions.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
You are an expert in TypeScript, Angular, and scalable web application development. You write functional, maintainable, performant, and accessible code following Angular and TypeScript best practices.
2+
3+
## TypeScript Best Practices
4+
5+
- Use strict type checking
6+
- Prefer type inference when the type is obvious
7+
- Avoid the `any` type; use `unknown` when type is uncertain
8+
9+
## Angular Best Practices
10+
11+
- Always use standalone components over NgModules
12+
- Must NOT set `standalone: true` inside Angular decorators. It's the default in Angular v20+.
13+
- Use signals for state management
14+
- Implement lazy loading for feature routes
15+
- Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead
16+
- Use `NgOptimizedImage` for all static images.
17+
- `NgOptimizedImage` does not work for inline base64 images.
18+
19+
## Accessibility Requirements
20+
21+
- It MUST pass all AXE checks.
22+
- It MUST follow all WCAG AA minimums, including focus management, color contrast, and ARIA attributes.
23+
24+
### Components
25+
26+
- Keep components small and focused on a single responsibility
27+
- Use `input()` and `output()` functions instead of decorators
28+
- Use `computed()` for derived state
29+
- Set `changeDetection: ChangeDetectionStrategy.OnPush` in `@Component` decorator
30+
- Prefer inline templates for small components
31+
- Prefer Reactive forms instead of Template-driven ones
32+
- Do NOT use `ngClass`, use `class` bindings instead
33+
- Do NOT use `ngStyle`, use `style` bindings instead
34+
- When using external templates/styles, use paths relative to the component TS file.
35+
36+
## State Management
37+
38+
- Use signals for local component state
39+
- Use `computed()` for derived state
40+
- Keep state transformations pure and predictable
41+
- Do NOT use `mutate` on signals, use `update` or `set` instead
42+
43+
## Templates
44+
45+
- Keep templates simple and avoid complex logic
46+
- Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch`
47+
- Use the async pipe to handle observables
48+
- Do not assume globals like (`new Date()`) are available.
49+
- Do not write arrow functions in templates (they are not supported).
50+
51+
## Services
52+
53+
- Design services around a single responsibility
54+
- Use the `providedIn: 'root'` option for singleton services
55+
- Use the `inject()` function instead of constructor injection
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { CpsIconComponent, ICONS_PATH } from './cps-icon.component';
3+
import { CommonModule } from '@angular/common';
4+
5+
describe('CpsIconComponent', () => {
6+
const createComponent = () => {
7+
fixture = TestBed.createComponent(CpsIconComponent);
8+
component = fixture.componentInstance;
9+
fixture.detectChanges();
10+
};
11+
12+
let component: CpsIconComponent;
13+
let fixture: ComponentFixture<CpsIconComponent>;
14+
15+
beforeEach(async () => {
16+
await TestBed.configureTestingModule({
17+
imports: [CommonModule, CpsIconComponent]
18+
}).compileComponents();
19+
});
20+
21+
it('should create', () => {
22+
createComponent();
23+
expect(component).toBeTruthy();
24+
});
25+
26+
describe('Test assets path injection', () => {
27+
it('should use default path when no ICONS_PATH is provided', () => {
28+
createComponent();
29+
expect(component.url).toBe('assets/');
30+
});
31+
32+
it('should use injected ICONS_PATH value', () => {
33+
TestBed.overrideProvider(ICONS_PATH, {
34+
useValue: 'test-assets/'
35+
});
36+
createComponent();
37+
expect(component.url).toBe('test-assets/');
38+
});
39+
});
40+
});

projects/cps-ui-kit/src/lib/components/cps-icon/cps-icon.component.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
11
import { CommonModule, DOCUMENT } from '@angular/common';
2-
import { Component, Inject, Input, OnChanges } from '@angular/core';
2+
import {
3+
Component,
4+
inject,
5+
Inject,
6+
InjectionToken,
7+
Input,
8+
OnChanges
9+
} from '@angular/core';
310
import { convertSize } from '../../utils/internal/size-utils';
411
import { getCSSColor } from '../../utils/colors-utils';
512

13+
/**
14+
* Injection token that is used to provide the path to the icons.
15+
*/
16+
export const ICONS_PATH = new InjectionToken<string>(
17+
'Icons path for CpsIconComponent'
18+
);
19+
620
export const iconNames = [
721
'access',
822
'access-denied',
@@ -176,7 +190,7 @@ export class CpsIconComponent implements OnChanges {
176190
@Input() color = 'currentColor';
177191

178192
iconColor = 'currentColor';
179-
url = 'assets/';
193+
url = inject(ICONS_PATH, { optional: true }) ?? 'assets/';
180194
cvtSize = '';
181195

182196
classesList: string[] = ['cps-icon'];

0 commit comments

Comments
 (0)