diff --git a/src/app/app.html b/src/app/app.html index d85eb68..dba92a9 100644 --- a/src/app/app.html +++ b/src/app/app.html @@ -1 +1,5 @@ - \ No newline at end of file + +
+ +
+ \ No newline at end of file diff --git a/src/app/app.scss b/src/app/app.scss index e40dd26..9b823de 100644 --- a/src/app/app.scss +++ b/src/app/app.scss @@ -1,2 +1,12 @@ -:host { display: block; min-height: 100dvh; } +:host { + display: flex; + flex-direction: column; + min-height: 100dvh; +} + +.app-main { + flex: 1; + display: flex; + flex-direction: column; +} diff --git a/src/app/app.ts b/src/app/app.ts index 2639d94..1a4c6b3 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -1,9 +1,11 @@ import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; +import { SiteHeader } from './site-header/site-header'; +import { SiteFooter } from './site-footer/site-footer'; @Component({ selector: 'app-root', - imports: [RouterOutlet], + imports: [RouterOutlet, SiteHeader, SiteFooter], templateUrl: './app.html', styleUrl: './app.scss' }) diff --git a/src/app/site-footer/site-footer.html b/src/app/site-footer/site-footer.html new file mode 100644 index 0000000..f8acadc --- /dev/null +++ b/src/app/site-footer/site-footer.html @@ -0,0 +1,60 @@ +
+ + + +
diff --git a/src/app/site-footer/site-footer.scss b/src/app/site-footer/site-footer.scss new file mode 100644 index 0000000..5f0beb4 --- /dev/null +++ b/src/app/site-footer/site-footer.scss @@ -0,0 +1,156 @@ +:host { display: block; } + +.site-footer { + background: #0f172a; + color: #94a3b8; + + &__inner { + max-width: 1100px; + margin: 0 auto; + padding: 48px 24px 32px; + display: grid; + grid-template-columns: 2fr 1fr 1fr; + gap: 40px; + + @media (max-width: 860px) { + grid-template-columns: 1fr 1fr; + } + + @media (max-width: 560px) { + grid-template-columns: 1fr; + gap: 32px; + padding: 36px 20px 24px; + } + } + + &__col { + &--brand { + @media (max-width: 860px) { + grid-column: 1 / -1; + } + } + } + + &__brand { + display: inline-flex; + align-items: center; + gap: 10px; + text-decoration: none; + margin-bottom: 14px; + + img { + width: 28px; + height: 28px; + object-fit: contain; + filter: brightness(0) invert(1); + opacity: 0.9; + } + } + + &__wordmark { + font-size: 18px; + letter-spacing: -0.02em; + line-height: 1; + } + + &__desc { + font-size: 13.5px; + line-height: 1.65; + color: #64748b; + max-width: 380px; + } + + &__heading { + font-size: 12px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.8px; + color: #e2e8f0; + margin-bottom: 16px; + } + + &__list { + list-style: none; + display: flex; + flex-direction: column; + gap: 10px; + margin-bottom: 18px; + + li { + display: flex; + align-items: center; + gap: 8px; + font-size: 13.5px; + + svg { flex-shrink: 0; opacity: 0.5; } + } + + a { + color: #94a3b8; + text-decoration: none; + transition: color 0.15s; + + &:hover { color: #e2e8f0; } + } + + &--legal { + li { + display: block; + font-size: 12.5px; + color: #64748b; + gap: 0; + } + } + } + + &__note { + font-size: 11px; + color: #475569; + margin-left: 4px; + } + + &__hours { + font-size: 12.5px; + color: #64748b; + line-height: 1.7; + } + + &__address { + color: #475569; + font-size: 12px !important; + line-height: 1.5; + margin-top: 4px; + } + + &__bottom { + border-top: 1px solid #1e293b; + max-width: 1100px; + margin: 0 auto; + padding: 16px 24px; + display: flex; + flex-wrap: wrap; + gap: 6px 24px; + justify-content: space-between; + font-size: 12px; + color: #475569; + + @media (max-width: 560px) { + flex-direction: column; + padding: 14px 20px; + } + } +} + +.wm-fast { + font-weight: 400; + font-size: 0.72em; + color: #64748b; + margin-right: 0.04em; +} +.wm-check { + font-weight: 700; + font-size: 1em; + color: #93c5fd; + text-transform: uppercase; + letter-spacing: 0.03em; +} diff --git a/src/app/site-footer/site-footer.ts b/src/app/site-footer/site-footer.ts new file mode 100644 index 0000000..cf8101b --- /dev/null +++ b/src/app/site-footer/site-footer.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-site-footer', + templateUrl: './site-footer.html', + styleUrl: './site-footer.scss' +}) +export class SiteFooter { + year = new Date().getFullYear(); +} diff --git a/src/app/site-header/site-header.html b/src/app/site-header/site-header.html new file mode 100644 index 0000000..bc6aa38 --- /dev/null +++ b/src/app/site-header/site-header.html @@ -0,0 +1,46 @@ + diff --git a/src/app/site-header/site-header.scss b/src/app/site-header/site-header.scss new file mode 100644 index 0000000..c977834 --- /dev/null +++ b/src/app/site-header/site-header.scss @@ -0,0 +1,131 @@ +:host { + display: block; + position: sticky; + top: 0; + z-index: 900; +} + +.site-header { + background: #fff; + border-bottom: 1px solid #e2e8f0; + box-shadow: 0 1px 8px rgba(0, 0, 0, 0.06); + + &__inner { + max-width: 1100px; + margin: 0 auto; + padding: 0 24px; + height: 60px; + display: flex; + align-items: center; + gap: 32px; + + @media (max-width: 600px) { + padding: 0 16px; + } + } + + &__brand { + display: inline-flex; + align-items: center; + gap: 10px; + text-decoration: none; + flex-shrink: 0; + + img { + width: 32px; + height: 32px; + object-fit: contain; + } + } + + &__wordmark { + font-size: 18px; + letter-spacing: -0.02em; + white-space: nowrap; + line-height: 1; + } + + &__nav { + display: flex; + align-items: center; + gap: 4px; + margin-left: auto; + + @media (max-width: 600px) { + display: none; + } + } + + &__link { + padding: 8px 14px; + border-radius: 8px; + font-size: 14px; + font-weight: 500; + color: #475569; + text-decoration: none; + transition: background 0.15s, color 0.15s; + + &:hover { + background: #f1f5f9; + color: #0f172a; + } + } + + &__burger { + display: none; + margin-left: auto; + width: 40px; + height: 40px; + border-radius: 8px; + border: none; + background: transparent; + color: #475569; + cursor: pointer; + align-items: center; + justify-content: center; + transition: background 0.15s; + -webkit-appearance: none; + font-family: inherit; + + &:hover { background: #f1f5f9; } + + @media (max-width: 600px) { + display: inline-flex; + } + } + + &__mobile-menu { + border-top: 1px solid #e2e8f0; + display: flex; + flex-direction: column; + padding: 8px 12px 12px; + background: #fff; + } + + &__mobile-link { + padding: 12px 14px; + border-radius: 10px; + font-size: 15px; + font-weight: 500; + color: #0f172a; + text-decoration: none; + transition: background 0.15s; + + &:hover { background: #f1f5f9; } + } +} + +// Wordmark colours +.wm-fast { + font-weight: 400; + font-size: 0.72em; + color: #64748b; + margin-right: 0.04em; +} +.wm-check { + font-weight: 700; + font-size: 1em; + color: #1e40af; + text-transform: uppercase; + letter-spacing: 0.03em; +} diff --git a/src/app/site-header/site-header.ts b/src/app/site-header/site-header.ts new file mode 100644 index 0000000..2152d6e --- /dev/null +++ b/src/app/site-header/site-header.ts @@ -0,0 +1,14 @@ +import { Component, signal } from '@angular/core'; +import { RouterLink } from '@angular/router'; + +@Component({ + selector: 'app-site-header', + imports: [RouterLink], + templateUrl: './site-header.html', + styleUrl: './site-header.scss' +}) +export class SiteHeader { + menuOpen = signal(false); + toggleMenu(): void { this.menuOpen.update(v => !v); } + closeMenu(): void { this.menuOpen.set(false); } +} diff --git a/src/shared.scss b/src/shared.scss index 241b99e..3fc0239 100644 --- a/src/shared.scss +++ b/src/shared.scss @@ -2,7 +2,7 @@ // Imported via @use './../../../shared' as *; .page { - min-height: 100dvh; + flex: 1; display: flex; align-items: center; justify-content: center; @@ -29,7 +29,7 @@ border-radius: 0; max-width: 100%; box-shadow: none; - min-height: 100dvh; + flex: 1; display: flex; flex-direction: column; }