diff --git a/demo-shell/src/app/components/app-layout/app-layout.component.html b/demo-shell/src/app/components/app-layout/app-layout.component.html
index 30b7d1de977..31c840191d1 100644
--- a/demo-shell/src/app/components/app-layout/app-layout.component.html
+++ b/demo-shell/src/app/components/app-layout/app-layout.component.html
@@ -18,6 +18,18 @@
+
+
+
+ Item 1
+ Item 2
+
diff --git a/docs/README.md b/docs/README.md
index 73ff140a4e9..1241ad9631f 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -30,10 +30,8 @@ A few other pages of information are also available:
- The [Release notes](release-notes/README.md) section has details of all
the features introduced and bugs fixed with each release.
- The [Version compatibility](compatibility.md) page shows which versions
- of Alfresco's backend servies (ACS and APS) are compatible with each released
+ of Alfresco backend services (ACS and APS) are compatible with each released
version of ADF.
-- The [Roadmap](roadmap.md)
- contains a preview of features we hope to release in future versions of ADF.
- The [License info](license-info/README.md) section lists the third-party libraries used by ADF along with links to their Open Source licenses.
- The [Vulnerability](vulnerability/README.md) section lists the third-party
libraries known vulnerability.
@@ -79,6 +77,15 @@ for more information about installing and using the source code.
+### Primitives
+
+A collection of Angular components for generic use.
+
+| Name | Description |
+|-----------------------------------------------|------------------------------|
+| [Avatar](core/components/avatar.component.md) | Displays user avatars. |
+| [Button](core/components/button.component.md) | A standard button component. |
+
### Components
| Name | Description | Source link |
diff --git a/docs/core/components/avatar.component.md b/docs/core/components/avatar.component.md
new file mode 120000
index 00000000000..732acc2e390
--- /dev/null
+++ b/docs/core/components/avatar.component.md
@@ -0,0 +1 @@
+../../../lib/core/src/lib/avatar/avatar.component.md
\ No newline at end of file
diff --git a/docs/core/components/button.component.md b/docs/core/components/button.component.md
new file mode 120000
index 00000000000..f5978fde61e
--- /dev/null
+++ b/docs/core/components/button.component.md
@@ -0,0 +1 @@
+../../../lib/core/src/lib/button/button.component.md
\ No newline at end of file
diff --git a/lib/core/src/lib/avatar/avatar.component.html b/lib/core/src/lib/avatar/avatar.component.html
new file mode 100644
index 00000000000..88e79302303
--- /dev/null
+++ b/lib/core/src/lib/avatar/avatar.component.html
@@ -0,0 +1,7 @@
+
+
+
+
+
+ {{ initials }}
+
diff --git a/lib/core/src/lib/avatar/avatar.component.md b/lib/core/src/lib/avatar/avatar.component.md
new file mode 100644
index 00000000000..473626f80f4
--- /dev/null
+++ b/lib/core/src/lib/avatar/avatar.component.md
@@ -0,0 +1,78 @@
+# Avatar Component
+
+`standalone`, `component`
+
+The Avatar component is a simple component that can be used to display user avatars.
+
+## Usage
+
+Displaying an avatar with an image and initials fallback:
+
+```html
+
+
+```
+
+Integrating with context menu:
+
+```html
+
+
+
+
+ Item 1
+ Item 2
+
+```
+
+## API
+
+Import the following standalone components:
+
+```typescript
+import { AvatarComponent } from '@alfresco/adf-core';
+```
+
+## Properties
+
+| Name | Type | Default | Description |
+|------------|--------|---------|--------------------------------------------------------|
+| `size` | string | `32px` | The size of the avatar. |
+| `src` | string | | The URL of the image to display. |
+| `initials` | string | | The initials to display if the image is not available. |
+| `tooltip` | string | | The tooltip to display when hovering over the avatar. |
+| `cursor` | string | `auto` | The cursor style. |
+
+## Theming
+
+The following CSS classes are available for theming:
+
+| Name | Description |
+|------------------------|-----------------------|
+| `adf-avatar` | The host element. |
+| `adf-avatar__image` | The image element. |
+| `adf-avatar__initials` | The initials element. |
+
+### CSS Variables
+
+| Name | Default | Description |
+|---------------------------------|-----------|-------------------------------------|
+| `--adf-avatar-size` | `32px` | The size of the avatar. |
+| `--adf-avatar-border-radius` | `50%` | The border radius of the avatar. |
+| `--adf-avatar-background-color` | `#f3f3f3` | The background color of the avatar. |
+| `--adf-avatar-color` | `#333` | The text color of the initials. |
+| `--adf-avatar-font-size` | `14px` | The font size of the initials. |
+| `--adf-avatar-font-weight` | `500` | The font weight of the initials. |
+| `--adf-avatar-cursor` | `auto` | The cursor style. |
+```
diff --git a/lib/core/src/lib/avatar/avatar.component.scss b/lib/core/src/lib/avatar/avatar.component.scss
new file mode 100644
index 00000000000..67e69728c52
--- /dev/null
+++ b/lib/core/src/lib/avatar/avatar.component.scss
@@ -0,0 +1,20 @@
+.adf-avatar {
+ display: flex;
+}
+
+.adf-avatar__image {
+ cursor: var(--adf-avatar-cursor, auto);
+ display: inline-block;
+ overflow: hidden;
+ line-height: 1;
+ border-radius: var(--adf-avatar-border-radius, 50%);
+ width: var(--adf-avatar-size, 32px);
+ height: var(--adf-avatar-size, 32px);
+ color: var(--adf-avatar-color, #333);
+ background-color: var(--adf-avatar-background-color, #f3f3f3);
+ box-shadow: 0 0 0 1px var(--adf-avatar-border-color, rgba(31, 35, 40, 0.15));
+ font-size: var(--adf-avatar-font-size, 14px);
+ font-weight: var(--adf-avatar-font-weight, 500);
+ text-align: center;
+ align-content: center;
+}
diff --git a/lib/core/src/lib/avatar/avatar.component.spec.ts b/lib/core/src/lib/avatar/avatar.component.spec.ts
new file mode 100644
index 00000000000..07bd1623f5b
--- /dev/null
+++ b/lib/core/src/lib/avatar/avatar.component.spec.ts
@@ -0,0 +1,89 @@
+/*!
+ * @license
+ * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { AvatarComponent } from '@alfresco/adf-core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+describe('AvatarComponent', () => {
+ let component: AvatarComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [AvatarComponent]
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(AvatarComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should display initials when src is not provided', () => {
+ component.src = '';
+ fixture.detectChanges();
+ const avatarElement: HTMLElement = fixture.nativeElement.querySelector('.adf-avatar__initials');
+ expect(avatarElement.textContent).toContain(component.initials);
+ });
+
+ it('should display image when src is provided', () => {
+ component.src = 'path/to/image.jpg';
+ fixture.detectChanges();
+ const imgElement: HTMLImageElement = fixture.nativeElement.querySelector('.adf-avatar__image');
+ expect(imgElement.src).toContain(component.src);
+ });
+
+ it('should use default initials when not provided', () => {
+ fixture.detectChanges();
+ const avatarElement: HTMLElement = fixture.nativeElement.querySelector('.adf-avatar__initials');
+ expect(avatarElement.textContent).toContain('U');
+ });
+
+ it('should use custom initials', () => {
+ component.initials = 'DV';
+ fixture.detectChanges();
+ const avatarElement: HTMLElement = fixture.nativeElement.querySelector('.adf-avatar__initials');
+ expect(avatarElement.textContent).toContain('DV');
+ });
+
+ it('should apply custom size style when size is provided', () => {
+ component.size = '48px';
+ fixture.detectChanges();
+
+ const style = getComputedStyle(fixture.nativeElement.querySelector('.adf-avatar__image'));
+ expect(style.width).toBe('48px');
+ expect(style.height).toBe('48px');
+ });
+
+ it('should apply custom cursor style when cursor is provided', () => {
+ component.cursor = 'pointer';
+ fixture.detectChanges();
+
+ const style = getComputedStyle(fixture.nativeElement.querySelector('.adf-avatar__image'));
+ expect(style.cursor).toBe('pointer');
+ });
+
+ it('should display tooltip when provided', () => {
+ component.tooltip = 'User Tooltip';
+ fixture.detectChanges();
+ const avatarElement: HTMLElement = fixture.nativeElement.querySelector('.adf-avatar__image');
+ expect(avatarElement.getAttribute('title')).toBe('User Tooltip');
+ });
+});
diff --git a/lib/core/src/lib/avatar/avatar.component.ts b/lib/core/src/lib/avatar/avatar.component.ts
new file mode 100644
index 00000000000..9a868c769ae
--- /dev/null
+++ b/lib/core/src/lib/avatar/avatar.component.ts
@@ -0,0 +1,46 @@
+/*!
+ * @license
+ * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Component, HostBinding, Input, ViewEncapsulation } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+@Component({
+ selector: 'adf-avatar',
+ standalone: true,
+ imports: [CommonModule],
+ templateUrl: './avatar.component.html',
+ styleUrls: ['./avatar.component.scss'],
+ encapsulation: ViewEncapsulation.None
+})
+export class AvatarComponent {
+ @Input()
+ src: string;
+
+ @Input()
+ initials: string = 'U';
+
+ @Input()
+ tooltip: string = '';
+
+ @HostBinding('style.--adf-avatar-size')
+ @Input()
+ size = getComputedStyle(document.documentElement).getPropertyValue('--adf-avatar-size');
+
+ @HostBinding('style.--adf-avatar-cursor')
+ @Input()
+ cursor = getComputedStyle(document.documentElement).getPropertyValue('--adf-avatar-cursor');
+}
diff --git a/lib/core/src/public-api.ts b/lib/core/src/public-api.ts
index 7105f0fdd68..84ce1ca93f9 100644
--- a/lib/core/src/public-api.ts
+++ b/lib/core/src/public-api.ts
@@ -16,6 +16,7 @@
*/
export * from './lib/about/index';
+export * from './lib/avatar/avatar.component';
export * from './lib/button/button.component';
export * from './lib/viewer/index';
export * from './lib/toolbar/index';