diff --git a/libs/ui/components/src/lib/content-hero/content-hero.component.html b/libs/ui/components/src/lib/content-hero/content-hero.component.html index cd5899744..3ac415115 100644 --- a/libs/ui/components/src/lib/content-hero/content-hero.component.html +++ b/libs/ui/components/src/lib/content-hero/content-hero.component.html @@ -142,9 +142,37 @@ @if (description()) { -
+
{{ description() }}
+ @if (hasDescriptionOverflow() || isDescriptionExpanded()) { + + } } diff --git a/libs/ui/components/src/lib/content-hero/content-hero.component.scss b/libs/ui/components/src/lib/content-hero/content-hero.component.scss index 48dedce1e..20ec01b63 100644 --- a/libs/ui/components/src/lib/content-hero/content-hero.component.scss +++ b/libs/ui/components/src/lib/content-hero/content-hero.component.scss @@ -322,7 +322,7 @@ font-size: 0.9375rem; line-height: 1.6; color: var(--text-secondary); - margin-bottom: 20px; + margin-bottom: 6px; max-width: 600px; // Truncate long descriptions @@ -330,6 +330,58 @@ -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; + + &--expanded { + display: block; + -webkit-line-clamp: unset; + overflow: visible; + } + } + + &__description-toggle { + display: inline-flex; + align-items: center; + gap: 4px; + margin: 0 0 20px 0; + padding: 4px 0; + background: transparent; + border: 0; + cursor: pointer; + color: var(--text-secondary); + font: inherit; + font-size: 0.8125rem; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + transition: + color 180ms ease, + transform 180ms ease; + + mat-icon { + font-size: 16px; + width: 16px; + height: 16px; + line-height: 16px; + transition: transform 180ms ease; + } + + &:hover { + color: var(--text-primary); + + mat-icon { + transform: translateY(2px); + } + } + + &[aria-expanded='true']:hover mat-icon { + transform: translateY(-2px); + } + + &:focus-visible { + outline: 2px solid var(--accent-color); + outline-offset: 2px; + border-radius: 2px; + } } &__meta { @@ -483,6 +535,10 @@ &__description { -webkit-line-clamp: 3; + + &--expanded { + -webkit-line-clamp: unset; + } } &__meta { diff --git a/libs/ui/components/src/lib/content-hero/content-hero.component.ts b/libs/ui/components/src/lib/content-hero/content-hero.component.ts index a04f8610b..8703858ec 100644 --- a/libs/ui/components/src/lib/content-hero/content-hero.component.ts +++ b/libs/ui/components/src/lib/content-hero/content-hero.component.ts @@ -1,16 +1,35 @@ -import { Component, computed, input, output, signal } from '@angular/core'; +import { + Component, + DestroyRef, + computed, + effect, + inject, + input, + output, + signal, + viewChild, + ElementRef, +} from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; +import { TranslateModule } from '@ngx-translate/core'; import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader'; @Component({ selector: 'app-content-hero', standalone: true, - imports: [MatIconModule, MatButtonModule, NgxSkeletonLoaderComponent], + imports: [ + MatIconModule, + MatButtonModule, + NgxSkeletonLoaderComponent, + TranslateModule, + ], templateUrl: './content-hero.component.html', styleUrls: ['./content-hero.component.scss'], }) export class ContentHeroComponent { + private readonly destroyRef = inject(DestroyRef); + readonly title = input