diff --git a/docs/features/project-brief.md b/docs/features/project-brief.md index e6fcbb16f7..a19e368fec 100644 --- a/docs/features/project-brief.md +++ b/docs/features/project-brief.md @@ -2,7 +2,7 @@ ## Overview -The Project Brief feature displays team project information to users on the home page. When a user's team has a project brief configured, a "Project Brief" button appears next to the experience name. Clicking this button opens a modal that displays structured project details. +The Project Brief feature displays team project information to users on the home page. When a user's team has a project brief configured, a "Project Brief" button appears next to the experience name. Clicking this button opens a modal that displays structured project details. When the Project Hub feature is enabled, a visible "Go to Project Hub" button opens the external Project Hub application. ## Data Flow @@ -17,7 +17,7 @@ HomePage.updateDashboard() ↓ reads from storage this.projectBrief = this.storageService.getUser().projectBrief ↓ -Template: *ngIf="projectBrief" shows button +Template: *ngIf="projectBrief" shows Project Brief button; *ngIf="showProjectHub" shows Project Hub button ↓ showProjectBrief() → opens ProjectBriefModalComponent ``` @@ -34,10 +34,11 @@ showProjectBrief() → opens ProjectBriefModalComponent - `project-brief-modal.component.scss` - Component-specific styles - `project-brief-modal.component.spec.ts` - Unit tests -**Input:** +**Modal property:** ```typescript -@Input() projectBrief: ProjectBrief = {}; +projectBrief: ProjectBrief = {}; ``` +Ionic sets this public property through `componentProps` when the modal is created. **Interface:** ```typescript @@ -62,6 +63,10 @@ interface ProjectBrief { - Professional Skills (as chips) - Deliverables +**Color treatment:** +- Modal section header icons and chips use the primary brand color. +- Do not use the secondary brand color for Technical Skills accents; customer secondary colors can be too light to remain visible on the light modal background. + **Empty Field Handling:** - All sections show "None specified" when the field is empty or undefined - Uses `hasValue()` for string fields and `hasItems()` for array fields @@ -124,17 +129,28 @@ Button placement - next to experience name: ```html

- - - Project Brief - +
+ + + Project Brief + + + + Go to Project Hub + +
``` @@ -177,11 +193,11 @@ Button placement - next to experience name: ## Accessibility -- Button includes `aria-label="View project brief"` with i18n support +- Buttons include descriptive aria labels with i18n support - Keyboard navigation with `(keydown.enter)` and `(keydown.space)` handlers - Modal has proper semantic structure with `
`, `
`, and heading hierarchy - Close button includes `aria-label="Close project brief"` -- Ion-chips for industry/skills are visually distinct with color coding +- Ion-chips for industry/skills use the primary brand color so labels and outlines remain visible when secondary branding is faint ## Sample Data @@ -219,6 +235,7 @@ After parsing: - Template renders title when provided - Template shows "None specified" for empty fields - Template renders chips for industry and skills +- Template keeps section accents on the primary brand color **HomePage tests (additions needed):** - Button visible when `projectBrief` is set diff --git a/projects/v3/src/app/components/project-brief-modal/project-brief-modal.component.html b/projects/v3/src/app/components/project-brief-modal/project-brief-modal.component.html index c4ca51db22..8c53bcb1c0 100644 --- a/projects/v3/src/app/components/project-brief-modal/project-brief-modal.component.html +++ b/projects/v3/src/app/components/project-brief-modal/project-brief-modal.component.html @@ -59,13 +59,13 @@

{{ projectBrief.title }}

- + Technical Skills
{{ skill }} @@ -78,13 +78,13 @@

{{ projectBrief.title }}

- + Professional Skills
{{ skill }} @@ -97,7 +97,7 @@

{{ projectBrief.title }}

- + Deliverables
diff --git a/projects/v3/src/app/components/project-brief-modal/project-brief-modal.component.spec.ts b/projects/v3/src/app/components/project-brief-modal/project-brief-modal.component.spec.ts index 7a32b8f106..d3f3f6c30c 100644 --- a/projects/v3/src/app/components/project-brief-modal/project-brief-modal.component.spec.ts +++ b/projects/v3/src/app/components/project-brief-modal/project-brief-modal.component.spec.ts @@ -124,5 +124,30 @@ describe('ProjectBriefModalComponent', () => { const chips = fixture.nativeElement.querySelectorAll('ion-chip'); expect(chips.length).toBe(4); }); + + it('should use the primary brand color for section accents', () => { + component.projectBrief = { + industry: ['Health'], + technicalSkills: ['Python'], + professionalSkills: ['Leadership'], + deliverables: 'Prototype' + }; + fixture.detectChanges(); + + const accentSelectors = [ + 'ion-icon[name="document-text-outline"]', + 'ion-icon[name="business-outline"]', + 'ion-icon[name="code-slash-outline"]', + 'ion-icon[name="people-outline"]', + 'ion-icon[name="checkbox-outline"]', + 'ion-chip' + ]; + + accentSelectors.forEach((selector) => { + fixture.nativeElement.querySelectorAll(selector).forEach((element: Element) => { + expect(element.getAttribute('color')).toBe('primary'); + }); + }); + }); }); }); diff --git a/projects/v3/src/app/pages/experiences/experiences.page.html b/projects/v3/src/app/pages/experiences/experiences.page.html index dd4ab7c50e..debc62c9df 100644 --- a/projects/v3/src/app/pages/experiences/experiences.page.html +++ b/projects/v3/src/app/pages/experiences/experiences.page.html @@ -46,7 +46,7 @@

Experiences

}
+ [class.exp-grid--center]="isCompactLayout(experiences.length)"> @for (experience of experiences; track experience) {
diff --git a/projects/v3/src/app/pages/home/home.page.scss b/projects/v3/src/app/pages/home/home.page.scss index 7c8b31b4e9..bbe4bac59e 100644 --- a/projects/v3/src/app/pages/home/home.page.scss +++ b/projects/v3/src/app/pages/home/home.page.scss @@ -77,7 +77,6 @@ ion-content.scrollable-desktop { min-width: 0; overflow-wrap: anywhere; word-break: break-word; - flex-shrink: 0; } } diff --git a/projects/v3/src/app/pages/home/home.page.spec.ts b/projects/v3/src/app/pages/home/home.page.spec.ts index f3236ba232..21c9faaa16 100644 --- a/projects/v3/src/app/pages/home/home.page.spec.ts +++ b/projects/v3/src/app/pages/home/home.page.spec.ts @@ -176,6 +176,25 @@ describe('HomePage', () => { expect(component).toBeTruthy(); }); + it('should show a visible Project Hub label when project brief and project hub are available', () => { + component.experience = { id: 1, name: 'Test Experience', cardUrl: 'test-card-url' } as any; + component.isExpert = false; + component.projectBrief = { id: 'brief-1', title: 'Project Brief' }; + component.showProjectHub = true; + + fixture.detectChanges(); + + const buttons = Array.from( + fixture.nativeElement.querySelectorAll('ion-button') + ) as HTMLElement[]; + const projectHubButton = buttons.find(button => + button.getAttribute('aria-label') === 'Go to Project Hub' + ); + + expect(projectHubButton).toBeTruthy(); + expect(projectHubButton?.textContent).toContain('Go to Project Hub'); + }); + describe('updateDashboard', () => { beforeEach(() => { sharedService.refreshJWT.and.returnValue(Promise.resolve());