Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
Title,
} from "@storybook/blocks";
import { TEDI_TRANSLATION_DEFAULT_TOKEN } from "../tedi/tokens/translation.token";
import { TEDI_THEME_DEFAULT_TOKEN } from "../tedi/tokens/theme.token";
import { THEME_FALLBACK_VALUE } from "../tedi/services/theme/theme.service";

export const globalTypes = {
theme: {
Expand Down Expand Up @@ -62,7 +64,10 @@ const preview: Preview = {
decorators: [
themeDecorator,
applicationConfig({
providers: [{ provide: TEDI_TRANSLATION_DEFAULT_TOKEN, useValue: "et" }],
providers: [
{ provide: TEDI_TRANSLATION_DEFAULT_TOKEN, useValue: "et" },
{ provide: TEDI_THEME_DEFAULT_TOKEN, useValue: THEME_FALLBACK_VALUE },
],
}),
],
parameters: {
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"ngx-float-ui": "^19.0.1 || ^20.0.0 || ^21.0.0"
},
"dependencies": {
"@tedi-design-system/core": "^6.0.1"
"@tedi-design-system/core": "^6.1.2"
},
"devDependencies": {
"@angular-devkit/core": "19.2.15",
Expand Down
5 changes: 5 additions & 0 deletions public/header-logo-white.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 4 additions & 3 deletions tedi/components/base/text/text.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type TextModifiers =
| "h6"
| "normal"
| "small"
| "extra-small"
| "bold"
| "thin"
| "italic"
Expand Down Expand Up @@ -45,15 +46,16 @@ export type TextColor =
| "warning"
| "danger"
| "info"
| "neutral";
| "neutral"
| "inherit";

@Component({
selector: "[tedi-text]",
standalone: true,
templateUrl: "./text.component.html",
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
"[class]": "classes()"
"[class]": "classes()",
},
})
export class TextComponent {
Expand Down Expand Up @@ -81,7 +83,6 @@ export class TextComponent {
: modifiersValue
? [modifiersValue]
: [];


modifierClasses.forEach((modifier) => {
if (this.isHeadingModifier(modifier)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,23 @@

.tedi-header-actions {
display: flex;
gap: var(--layout-header-items-right-gutter-x);
align-items: center;
height: 100%;
margin-left: auto;

> * {
display: flex;
align-items: center;
height: 100%;

&:not(:first-child) {
padding-left: var(--layout-header-items-right-gutter-x);
border-left: var(--tedi-borders-01) solid var(--general-border-primary);
}

&:not(:last-child) {
padding-right: var(--layout-header-items-right-gutter-x);
}

&:has(.tedi-header-login__button--mobile),
&:has(.tedi-header-profile--mobile) {
padding-left: 0;
}

@include breakpoints.media-breakpoint-only(md) {
max-height: 2.75rem;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@use "@tedi-design-system/core/bootstrap-utility/breakpoints";

.tedi-header-bottom {
display: block;
padding: var(--layout-grid-gutters-12) var(--layout-page-spacing-x);
background: var(--general-surface-primary);
border-top: var(--tedi-borders-01) solid var(--general-border-primary);
border-bottom: var(--tedi-borders-01) solid var(--general-border-primary);

@include breakpoints.media-breakpoint-up(md) {
display: none;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { Component } from "@angular/core";
import { HeaderBottomComponent } from "./header-bottom.component";

describe("HeaderBottomComponent", () => {
let fixture: ComponentFixture<HeaderBottomComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HeaderBottomComponent],
}).compileComponents();

fixture = TestBed.createComponent(HeaderBottomComponent);
fixture.detectChanges();
});

it("should create the component", () => {
expect(fixture.componentInstance).toBeTruthy();
});

it("should apply the host class", () => {
expect(fixture.nativeElement.classList).toContain("tedi-header-bottom");
});

it("should project children content", () => {
@Component({
standalone: true,
imports: [HeaderBottomComponent],
template: `
<tedi-header-bottom>
<span data-testid="projected">hello</span>
</tedi-header-bottom>
`,
})
class HostComponent {}

const hostFixture = TestBed.createComponent(HostComponent);
hostFixture.detectChanges();

const projected = hostFixture.nativeElement.querySelector(
"[data-testid='projected']",
);
expect(projected).toBeTruthy();
expect(projected.textContent).toBe("hello");
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
ChangeDetectionStrategy,
Component,
ViewEncapsulation,
} from "@angular/core";

/**
* Mobile-only secondary row rendered below the main header bar.
*
* Typical use: a compact search bar or mobile-specific navigation that only
* appears below the `md` breakpoint. Above `md` the component is hidden via
* CSS, so consumers can include it unconditionally — desktop users won't see it.
*
* @example
* <header tedi-header>
* <!-- main content -->
* <tedi-header-bottom>
* <tedi-header-search mobileVariant="inline">
* <tedi-search inputId="search" placeholder="Search..." />
* </tedi-header-search>
* </tedi-header-bottom>
* </header>
*/
@Component({
selector: "tedi-header-bottom",
standalone: true,
template: "<ng-content />",
styleUrl: "./header-bottom.component.scss",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
"class": "tedi-header-bottom",
},
})
export class HeaderBottomComponent {}
1 change: 1 addition & 0 deletions tedi/components/layout/header/header-bottom/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./header-bottom.component";
Original file line number Diff line number Diff line change
@@ -1,23 +1,41 @@
tedi-header-content {
.tedi-header-content {
display: flex;
flex: 1 0 0;
gap: var(--layout-header-items-center-gutter-x);
align-items: center;

&--flex-start {
justify-content: flex-start;
}

&--center {
justify-content: center;
}

&--space-between {
justify-content: space-between;
}

a,
.tedi-link {
color: var(--general-text-primary);
color: var(--header-link-default);

&:hover {
color: var(--general-text-secondary);
&:hover:not(:disabled, [aria-disabled="true"]) {
color: var(--header-link-hover);
}

&:active {
color: var(--general-text-tertiary);
&:active:not(:disabled, [aria-disabled="true"]) {
color: var(--header-link-active);
}

&:focus-visible {
outline: var(--tedi-borders-02) solid var(--tedi-primary-500);
&:focus-visible:not(:disabled) {
outline: var(--tedi-borders-02) solid var(--header-link-focus);
outline-offset: var(--tedi-borders-01);
}
}

> * {
display: flex;
gap: var(--layout-header-items-center-gutter-x);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { HeaderContentAlignment, HeaderContentComponent } from "./header-content.component";

describe("HeaderContentComponent", () => {
let fixture: ComponentFixture<HeaderContentComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HeaderContentComponent],
}).compileComponents();

fixture = TestBed.createComponent(HeaderContentComponent);
fixture.detectChanges();
});

it("should create the component", () => {
expect(fixture.componentInstance).toBeTruthy();
});

it("should apply the base host class", () => {
expect(fixture.nativeElement.classList).toContain("tedi-header-content");
});

it("should default to the center alignment modifier", () => {
expect(fixture.nativeElement.classList).toContain(
"tedi-header-content--center",
);
});

it.each<HeaderContentAlignment>(["flex-start", "center", "space-between"])(
"should apply the %s alignment modifier when set",
(alignment) => {
fixture.componentRef.setInput("alignment", alignment);
fixture.detectChanges();

expect(fixture.nativeElement.classList).toContain(
`tedi-header-content--${alignment}`,
);
},
);

it("should swap the modifier class when alignment changes", () => {
fixture.componentRef.setInput("alignment", "space-between");
fixture.detectChanges();
expect(fixture.nativeElement.classList).toContain(
"tedi-header-content--space-between",
);
expect(fixture.nativeElement.classList).not.toContain(
"tedi-header-content--center",
);

fixture.componentRef.setInput("alignment", "flex-start");
fixture.detectChanges();
expect(fixture.nativeElement.classList).toContain(
"tedi-header-content--flex-start",
);
expect(fixture.nativeElement.classList).not.toContain(
"tedi-header-content--space-between",
);
});
});
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import {
ChangeDetectionStrategy,
Component,
ViewEncapsulation,
computed,
input,
} from "@angular/core";

export type HeaderContentAlignment = "flex-start" | "center" | "space-between";

@Component({
selector: 'tedi-header-content',
selector: "tedi-header-content",
standalone: true,
template: "<ng-content />",
styleUrl: './header-content.component.scss',
styleUrl: "./header-content.component.scss",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
"[class]": "classes()",
},
})
export class HeaderContentComponent {}
export class HeaderContentComponent {
/**
* Controls the horizontal alignment of the projected content (`justify-content`).
* Useful when the center area mixes nav links with another component (e.g. a
* `<tedi-header-search>`) and you want to push them apart or align them to one edge.
* @default "center"
*/
readonly alignment = input<HeaderContentAlignment>("center");

protected readonly classes = computed(
() => `tedi-header-content tedi-header-content--${this.alignment()}`,
);
}
Loading
Loading