From af5b40021d0e1f77521e17d515e140f34f7a69b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joe=20K=C3=BCng?= Date: Mon, 2 Feb 2026 20:59:50 +0100 Subject: [PATCH] feat(web): separated html and scss from ts --- .../src/app/core/layout/footer.component.html | 21 + .../src/app/core/layout/footer.component.scss | 43 ++ .../src/app/core/layout/footer.component.ts | 57 +- .../src/app/core/layout/navbar.component.html | 21 + .../src/app/core/layout/navbar.component.scss | 67 +++ .../src/app/core/layout/navbar.component.ts | 94 +--- .../src/app/features/home/home.component.html | 162 ++++++ .../src/app/features/home/home.component.scss | 337 ++++++++++++ .../src/app/features/home/home.component.ts | 493 +----------------- frontend/src/styles/_patterns.scss | 16 + 10 files changed, 673 insertions(+), 638 deletions(-) create mode 100644 frontend/src/app/core/layout/footer.component.html create mode 100644 frontend/src/app/core/layout/footer.component.scss create mode 100644 frontend/src/app/core/layout/navbar.component.html create mode 100644 frontend/src/app/core/layout/navbar.component.scss create mode 100644 frontend/src/app/features/home/home.component.html create mode 100644 frontend/src/app/features/home/home.component.scss diff --git a/frontend/src/app/core/layout/footer.component.html b/frontend/src/app/core/layout/footer.component.html new file mode 100644 index 0000000..64f9312 --- /dev/null +++ b/frontend/src/app/core/layout/footer.component.html @@ -0,0 +1,21 @@ + diff --git a/frontend/src/app/core/layout/footer.component.scss b/frontend/src/app/core/layout/footer.component.scss new file mode 100644 index 0000000..2bbcabf --- /dev/null +++ b/frontend/src/app/core/layout/footer.component.scss @@ -0,0 +1,43 @@ + @use '../../../styles/patterns'; + + .footer { + background: var(--color-neutral-900); + color: var(--color-neutral-50); + padding: var(--space-8) 0 var(--space-4); + font-size: 0.9rem; + position: relative; + margin-top: auto; /* Push to bottom if content is short */ + // Cross Hatch Pattern + &::before { + content: ''; + position: absolute; + inset: 0; + @include patterns.pattern-cross-hatch(var(--color-neutral-50), 20px, 1px); + opacity: 0.05; + pointer-events: none; + } + } + .footer-inner { + display: flex; + justify-content: space-between; + align-items: center; + } + .brand { font-weight: 700; color: white; display: block; margin-bottom: var(--space-2); } + .copyright { font-size: 0.875rem; color: var(--color-secondary-500); margin: 0; } + + .links { + display: flex; + gap: var(--space-6); + a { + color: var(--color-neutral-300); + font-size: 0.875rem; + &:hover { color: white; text-decoration: underline; } + } + } + + .social { display: flex; gap: var(--space-3); } + .social-icon { + width: 24px; height: 24px; + background-color: var(--color-neutral-800); + border-radius: 50%; + } diff --git a/frontend/src/app/core/layout/footer.component.ts b/frontend/src/app/core/layout/footer.component.ts index d0cb4ae..5f2fe89 100644 --- a/frontend/src/app/core/layout/footer.component.ts +++ b/frontend/src/app/core/layout/footer.component.ts @@ -6,60 +6,7 @@ import { RouterLink } from '@angular/router'; selector: 'app-footer', standalone: true, imports: [TranslateModule, RouterLink], - template: ` - - `, - styles: [` - .footer { - background-color: var(--color-neutral-900); - color: var(--color-neutral-300); - padding: var(--space-8) 0; - margin-top: auto; /* Push to bottom if content is short */ - } - .footer-inner { - display: flex; - justify-content: space-between; - align-items: center; - } - .brand { font-weight: 700; color: white; display: block; margin-bottom: var(--space-2); } - .copyright { font-size: 0.875rem; color: var(--color-secondary-500); margin: 0; } - - .links { - display: flex; - gap: var(--space-6); - a { - color: var(--color-neutral-300); - font-size: 0.875rem; - &:hover { color: white; text-decoration: underline; } - } - } - - .social { display: flex; gap: var(--space-3); } - .social-icon { - width: 24px; height: 24px; - background-color: var(--color-neutral-800); - border-radius: 50%; - } - `] + templateUrl: './footer.component.html', + styleUrls: ['./footer.component.scss'] }) export class FooterComponent {} diff --git a/frontend/src/app/core/layout/navbar.component.html b/frontend/src/app/core/layout/navbar.component.html new file mode 100644 index 0000000..cb0e293 --- /dev/null +++ b/frontend/src/app/core/layout/navbar.component.html @@ -0,0 +1,21 @@ + diff --git a/frontend/src/app/core/layout/navbar.component.scss b/frontend/src/app/core/layout/navbar.component.scss new file mode 100644 index 0000000..ee924fd --- /dev/null +++ b/frontend/src/app/core/layout/navbar.component.scss @@ -0,0 +1,67 @@ + .navbar { + height: 64px; + border-bottom: 1px solid var(--color-border); + background-color: var(--color-bg-card); + position: sticky; + top: 0; + z-index: 100; + display: flex; + align-items: center; + } + .navbar-inner { + display: flex; + align-items: center; + justify-content: space-between; + } + .brand { + font-size: 1.25rem; + font-weight: 700; + color: var(--color-text); + text-decoration: none; + } + .highlight { color: var(--color-brand); } + + .nav-links { + display: flex; + gap: var(--space-6); + + a { + color: var(--color-text-muted); + font-weight: 500; + text-decoration: none; + transition: color 0.2s; + + &:hover, &.active { + color: var(--color-brand); + } + } + } + + .actions { + display: flex; + align-items: center; + gap: var(--space-4); + } + + .lang-switch { + background: none; + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); + padding: 2px 6px; + cursor: pointer; + font-size: 0.875rem; + font-weight: 600; + color: var(--color-text-muted); + &:hover { color: var(--color-text); border-color: var(--color-text); } + } + + .icon-placeholder { + width: 32px; + height: 32px; + border-radius: 50%; + background-color: var(--color-neutral-100); + display: flex; + align-items: center; + justify-content: center; + color: var(--color-text-muted); + } diff --git a/frontend/src/app/core/layout/navbar.component.ts b/frontend/src/app/core/layout/navbar.component.ts index dafe005..c150856 100644 --- a/frontend/src/app/core/layout/navbar.component.ts +++ b/frontend/src/app/core/layout/navbar.component.ts @@ -8,98 +8,8 @@ import { AppButtonComponent } from '../../shared/components/app-button/app-butto selector: 'app-navbar', standalone: true, imports: [RouterLink, RouterLinkActive, TranslateModule], - template: ` - - `, - styles: [` - .navbar { - height: 64px; - border-bottom: 1px solid var(--color-border); - background-color: var(--color-bg-card); - position: sticky; - top: 0; - z-index: 100; - display: flex; - align-items: center; - } - .navbar-inner { - display: flex; - align-items: center; - justify-content: space-between; - } - .brand { - font-size: 1.25rem; - font-weight: 700; - color: var(--color-text); - text-decoration: none; - } - .highlight { color: var(--color-brand); } - - .nav-links { - display: flex; - gap: var(--space-6); - - a { - color: var(--color-text-muted); - font-weight: 500; - text-decoration: none; - transition: color 0.2s; - - &:hover, &.active { - color: var(--color-brand); - } - } - } - - .actions { - display: flex; - align-items: center; - gap: var(--space-4); - } - - .lang-switch { - background: none; - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - padding: 2px 6px; - cursor: pointer; - font-size: 0.875rem; - font-weight: 600; - color: var(--color-text-muted); - &:hover { color: var(--color-text); border-color: var(--color-text); } - } - - .icon-placeholder { - width: 32px; - height: 32px; - border-radius: 50%; - background-color: var(--color-neutral-100); - display: flex; - align-items: center; - justify-content: center; - color: var(--color-text-muted); - } - `] + templateUrl: './navbar.component.html', + styleUrls: ['./navbar.component.scss'] }) export class NavbarComponent { constructor(public langService: LanguageService) {} diff --git a/frontend/src/app/features/home/home.component.html b/frontend/src/app/features/home/home.component.html new file mode 100644 index 0000000..8380ff0 --- /dev/null +++ b/frontend/src/app/features/home/home.component.html @@ -0,0 +1,162 @@ +
+
+
+
+

Stampa 3D tecnica per aziende, freelance e maker

+

+ Prezzo e tempi in pochi secondi.
+ Dal file 3D al pezzo finito. +

+

+ Lavoriamo con trasparenza su costi, qualità e tempi. Produciamo prototipi, pezzi personalizzati + e piccole serie con supporto tecnico reale. +

+
+ Parla con noi + Vai allo shop +
+
+
+
+ +
+
+
+

Preventivo immediato

+

+ Carica il file 3D e ottieni subito costo e tempo di stampa. Nessuna registrazione. +

+
    +
  • Formati supportati: STL, 3MF, STEP, OBJ
  • +
  • Materiali disponibili: PLA, PETG, TPU
  • +
  • Qualità: bozza, standard, alta definizione
  • +
+
+ +
+
+

Calcolo automatico

+

Prezzo e tempi in un click

+
+ Senza registrazione +
+
    +
  • Carica il file 3D
  • +
  • Scegli materiale e qualità
  • +
  • Ricevi subito costo e tempo
  • +
+
+
+ Modalità + Rapida / Avanzata +
+
+ Output + Ordina o richiedi consulenza +
+
+
+ Apri calcolatore + Parla con noi +
+
+
+
+ +
+
+
+
+

Cosa puoi ottenere

+

+ Produzione su misura per prototipi, piccole serie e pezzi personalizzati. +

+
+
+ +

Prototipazione veloce

+

Valida idee e funzioni in pochi giorni con preventivo immediato.

+
+ +

Pezzi personalizzati

+

Componenti unici o in mini serie per clienti, macchine e prodotti.

+
+ +

Piccole serie

+

Produzione controllata fino a 500 pezzi con qualità costante.

+
+ +

Consulenza e CAD

+

Supporto tecnico per progettazione, modifiche e ottimizzazione.

+
+
+
+
+ +
+
+
+

Shop di soluzioni tecniche pronte

+

+ Prodotti selezionati, testati in laboratorio e pronti all'uso. Risolvono problemi reali con + funzionalità concrete. +

+
    +
  • Accessori funzionali per officine e laboratori
  • +
  • Ricambi e componenti difficili da reperire
  • +
  • Supporti e organizzatori per migliorare i flussi di lavoro
  • +
+
+ Scopri i prodotti + Richiedi una soluzione +
+
+
+ +

Best seller tecnici

+

Soluzioni provate sul campo e già pronte alla spedizione.

+
+ +

Kit pronti all'uso

+

Componenti compatibili e facili da montare senza sorprese.

+
+ +

Su richiesta

+

Non trovi quello che serve? Lo progettiamo e lo produciamo per te.

+
+
+
+
+ +
+
+
+

Su di noi

+

+ 3D fab è un laboratorio tecnico di stampa 3D. Seguiamo progetti dalla consulenza iniziale + alla produzione, con tempi chiari e supporto diretto. +

+

+ Qui puoi inserire descrizioni più dettagliate del team, del laboratorio e dei progetti in corso. +

+ Contattaci +
+
+
+
+
+

Foto laboratorio / stampanti

+
+
+
+

Dettagli qualità e finiture

+
+
+
+

Team, prototipi o casi studio

+
+
+
+
+
+
diff --git a/frontend/src/app/features/home/home.component.scss b/frontend/src/app/features/home/home.component.scss new file mode 100644 index 0000000..5e406d9 --- /dev/null +++ b/frontend/src/app/features/home/home.component.scss @@ -0,0 +1,337 @@ + @use '../../../styles/patterns'; + + .home-page { + background: var(--color-bg); + } + + .hero { + position: relative; + padding: 6rem 0 5rem; + overflow: hidden; + background: var(--color-bg); + // Enhanced Grid Pattern + &::after { + content: ''; + position: absolute; + inset: 0; + @include patterns.pattern-grid(var(--color-neutral-900), 40px, 1px); + opacity: 0.12; + z-index: 0; + pointer-events: none; + mask-image: linear-gradient(to bottom, black 40%, transparent 100%); + } + } + + // Keep the accent blob + .hero::before { + content: ''; + position: absolute; + width: 420px; + height: 420px; + right: -120px; + top: -160px; + background: radial-gradient(circle at 30% 30%, rgba(0, 0, 0, 0.03), transparent 70%); + opacity: 0.8; + z-index: 0; + animation: floatGlow 12s ease-in-out infinite; + } + + .hero-grid { + display: grid; + gap: var(--space-12); + align-items: center; + position: relative; + z-index: 1; + } + .hero-copy { animation: fadeUp 0.8s ease both; } + .hero-panel { animation: fadeUp 0.8s ease 0.15s both; } + + .eyebrow { + text-transform: uppercase; + letter-spacing: 0.12em; + font-size: 0.75rem; + color: var(--color-secondary-600); + margin-bottom: var(--space-3); + font-weight: 600; + } + .hero-title { + font-size: clamp(2.5rem, 2.4vw + 1.8rem, 4rem); + font-weight: 700; + line-height: 1.05; + letter-spacing: -0.02em; + margin-bottom: var(--space-4); + } + .hero-subtitle { + font-size: 1.2rem; + color: var(--color-text-muted); + max-width: 560px; + } + .hero-actions { + display: flex; + gap: var(--space-4); + flex-wrap: wrap; + margin: var(--space-6) 0 var(--space-4); + } + .hero-badges { + display: flex; + flex-wrap: wrap; + gap: var(--space-2); + } + .hero-badges span { + display: inline-flex; + padding: 0.35rem 0.75rem; + border-radius: 999px; + background: var(--color-neutral-100); + color: var(--color-neutral-900); + font-size: 0.85rem; + font-weight: 600; + border: 1px solid var(--color-border); + } + + .quote-card { + display: block; + } + .focus-card { + display: grid; + gap: var(--space-4); + } + .focus-list { + list-style: none; + padding: 0; + margin: 0; + display: grid; + gap: var(--space-2); + color: var(--color-text-muted); + } + .focus-list li::before { + content: '•'; + color: var(--color-brand); + margin-right: var(--space-2); + } + .focus-list li { + display: flex; + align-items: baseline; + gap: var(--space-2); + } + .quote-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: var(--space-4); + margin-bottom: var(--space-4); + } + .quote-eyebrow { + text-transform: uppercase; + font-size: 0.7rem; + letter-spacing: 0.12em; + color: var(--color-secondary-600); + margin: 0 0 var(--space-2); + } + .quote-title { margin: 0; font-size: 1.35rem; } + .quote-tag { + background: var(--color-neutral-100); + border: 1px solid var(--color-border); + border-radius: 999px; + padding: 0.35rem 0.75rem; + font-size: 0.8rem; + font-weight: 600; + } + .quote-steps { + list-style: none; + padding: 0; + margin: 0 0 var(--space-5); + display: grid; + gap: var(--space-2); + } + .quote-steps li { + position: relative; + padding-left: 1.5rem; + color: var(--color-text-muted); + } + .quote-steps li::before { + content: ''; + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--color-brand); + position: absolute; + left: 0.25rem; + top: 0.5rem; + } + .quote-meta { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--space-4); + margin-bottom: var(--space-5); + } + .meta-label { + display: block; + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--color-secondary-600); + margin-bottom: var(--space-1); + } + .meta-value { font-weight: 600; } + .quote-actions { display: grid; gap: var(--space-3); } + + .capabilities { + position: relative; + } + .capabilities-bg { + position: absolute; + inset: 0; + @include patterns.pattern-rectilinear(var(--color-neutral-900), 24px, 1px); + opacity: 0.05; + pointer-events: none; + z-index: 0; + } + + .section { padding: 5.5rem 0; position: relative; } + .section-head { margin-bottom: var(--space-8); } + .section-title { font-size: clamp(2rem, 1.8vw + 1.2rem, 2.8rem); margin-bottom: var(--space-3); } + .section-subtitle { color: var(--color-text-muted); max-width: 620px; } + .text-muted { color: var(--color-text-muted); } + + .calculator { + background: var(--color-neutral-50); + border-top: 1px solid var(--color-border); + border-bottom: 1px solid var(--color-border); + position: relative; + // Honeycomb Pattern + &::before { + content: ''; + position: absolute; + inset: 0; + @include patterns.pattern-honeycomb(var(--color-neutral-900), 24px); + opacity: 0.04; + pointer-events: none; + } + } + .calculator-grid { + display: grid; + gap: var(--space-10); + align-items: center; + position: relative; + z-index: 1; + } + .calculator-list { + padding-left: var(--space-4); + color: var(--color-text-muted); + margin: var(--space-6) 0 0; + } + .cap-cards { + display: grid; + gap: var(--space-4); + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + } + + .shop { + background: var(--color-neutral-50); + position: relative; + // Triangular/Isogrid Pattern + &::before { + content: ''; + position: absolute; + inset: 0; + @include patterns.pattern-triangular(var(--color-neutral-900), 40px); + opacity: 0.03; + pointer-events: none; + } + } + .split { + display: grid; + gap: var(--space-10); + align-items: center; + position: relative; + z-index: 1; + } + .shop-list { + padding-left: var(--space-4); + color: var(--color-text-muted); + margin-bottom: var(--space-6); + } + .shop-actions { + display: flex; + flex-wrap: wrap; + gap: var(--space-3); + } + .shop-cards { + display: grid; + gap: var(--space-4); + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + } + + .about { + background: var(--color-neutral-50); + border-top: 1px solid var(--color-border); + position: relative; + // Gyroid Pattern + &::before { + content: ''; + position: absolute; + inset: 0; + @include patterns.pattern-gyroid(var(--color-neutral-900), 40px); + opacity: 0.03; + pointer-events: none; + } + } + .about-grid { + display: grid; + gap: var(--space-10); + align-items: center; + } + .about-media { + display: grid; + gap: var(--space-4); + } + .media-grid { + display: grid; + gap: var(--space-4); + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + } + .media-tile { + display: grid; + gap: var(--space-2); + } + .media-photo { + width: 100%; + aspect-ratio: 4 / 3; + border-radius: var(--radius-lg); + background: var(--color-neutral-100); + border: 1px solid var(--color-border); + } + .media-tile p { + margin: 0; + color: var(--color-text-muted); + font-size: 0.9rem; + } + .about-note { + padding: var(--space-5); + } + + @media (min-width: 960px) { + .hero-grid { grid-template-columns: 1.1fr 0.9fr; } + .calculator-grid { grid-template-columns: 1.1fr 0.9fr; } + .split { grid-template-columns: 1.1fr 0.9fr; } + .about-grid { grid-template-columns: 1.1fr 0.9fr; } + } + + @media (max-width: 640px) { + .hero-actions { flex-direction: column; align-items: stretch; } + .quote-meta { grid-template-columns: 1fr; } + } + + @keyframes fadeUp { + from { opacity: 0; transform: translateY(18px); } + to { opacity: 1; transform: translateY(0); } + } + @keyframes floatGlow { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(20px); } + } + + @media (prefers-reduced-motion: reduce) { + .hero-copy, .hero-panel { animation: none; } + .hero::before { animation: none; } + } diff --git a/frontend/src/app/features/home/home.component.ts b/frontend/src/app/features/home/home.component.ts index b7ec019..2aec96c 100644 --- a/frontend/src/app/features/home/home.component.ts +++ b/frontend/src/app/features/home/home.component.ts @@ -9,496 +9,7 @@ import { AppCardComponent } from '../../shared/components/app-card/app-card.comp selector: 'app-home-page', standalone: true, imports: [CommonModule, RouterLink, TranslateModule, AppButtonComponent, AppCardComponent], - template: ` -
-
-
-
-

Stampa 3D tecnica per aziende, freelance e maker

-

- Prezzo e tempi in pochi secondi.
- Dal file 3D al pezzo finito. -

-

- Lavoriamo con trasparenza su costi, qualità e tempi. Produciamo prototipi, pezzi personalizzati - e piccole serie con supporto tecnico reale. -

-
- Parla con noi - Vai allo shop -
-
- Trasparenza su prezzo, qualità e tempi - Prototipi e piccole serie fino a 500 pz - Progettazione CAD e post-processing su richiesta -
-
-
-
- -
-
-
-

Preventivo immediato

-

- Carica il file 3D e ottieni subito costo e tempo di stampa. Nessuna registrazione. -

-
    -
  • Formati supportati: STL, 3MF, STEP, OBJ
  • -
  • Materiali disponibili: PLA, PETG, TPU
  • -
  • Qualità: bozza, standard, alta definizione
  • -
-
- -
-
-

Calcolo automatico

-

Prezzo e tempi in un click

-
- Senza registrazione -
-
    -
  • Carica il file 3D
  • -
  • Scegli materiale e qualità
  • -
  • Ricevi subito costo e tempo
  • -
-
-
- Modalità - Rapida / Avanzata -
-
- Output - Ordina o richiedi consulenza -
-
-
- Apri calcolatore - Parla con noi -
-
-
-
- -
-
-
-

Cosa puoi ottenere

-

- Produzione su misura per prototipi, piccole serie e pezzi personalizzati. -

-
-
- -

Prototipazione veloce

-

Valida idee e funzioni in pochi giorni con preventivo immediato.

-
- -

Pezzi personalizzati

-

Componenti unici o in mini serie per clienti, macchine e prodotti.

-
- -

Piccole serie

-

Produzione controllata fino a 500 pezzi con qualità costante.

-
- -

Consulenza e CAD

-

Supporto tecnico per progettazione, modifiche e ottimizzazione.

-
-
-
-
- -
-
-
-

Shop di soluzioni tecniche pronte

-

- Prodotti selezionati, testati in laboratorio e pronti all'uso. Risolvono problemi reali con - funzionalità concrete. -

-
    -
  • Accessori funzionali per officine e laboratori
  • -
  • Ricambi e componenti difficili da reperire
  • -
  • Supporti e organizzatori per migliorare i flussi di lavoro
  • -
-
- Scopri i prodotti - Richiedi una soluzione -
-
-
- -

Best seller tecnici

-

Soluzioni provate sul campo e già pronte alla spedizione.

-
- -

Kit pronti all'uso

-

Componenti compatibili e facili da montare senza sorprese.

-
- -

Su richiesta

-

Non trovi quello che serve? Lo progettiamo e lo produciamo per te.

-
-
-
-
- -
-
-
-

Su di noi

-

- 3D fab è un laboratorio tecnico di stampa 3D. Seguiamo progetti dalla consulenza iniziale - alla produzione, con tempi chiari e supporto diretto. -

-

- Qui puoi inserire descrizioni più dettagliate del team, del laboratorio e dei progetti in corso. -

- Contattaci -
-
-
-
-
-

Foto laboratorio / stampanti

-
-
-
-

Dettagli qualità e finiture

-
-
-
-

Team, prototipi o casi studio

-
-
- -

Spazio per descrizioni

-

- Inserisci qui testi più lunghi, riferimenti a clienti o processi interni. -

-
-
-
-
-
- `, - styles: [` - @use '../../../styles/patterns'; - - .home-page { - background: var(--color-bg); - } - - .hero { - position: relative; - padding: 6rem 0 5rem; - overflow: hidden; - background: var(--color-bg); - // Enhanced Grid Pattern - &::after { - content: ''; - position: absolute; - inset: 0; - @include patterns.pattern-grid(var(--color-neutral-900), 40px, 1px); - opacity: 0.12; - z-index: 0; - pointer-events: none; - mask-image: linear-gradient(to bottom, black 40%, transparent 100%); - } - } - - // Keep the accent blob - .hero::before { - content: ''; - position: absolute; - width: 420px; - height: 420px; - right: -120px; - top: -160px; - background: radial-gradient(circle at 30% 30%, rgba(0, 0, 0, 0.03), transparent 70%); - opacity: 0.8; - z-index: 0; - animation: floatGlow 12s ease-in-out infinite; - } - - .hero-grid { - display: grid; - gap: var(--space-12); - align-items: center; - position: relative; - z-index: 1; - } - .hero-copy { animation: fadeUp 0.8s ease both; } - .hero-panel { animation: fadeUp 0.8s ease 0.15s both; } - - .eyebrow { - text-transform: uppercase; - letter-spacing: 0.12em; - font-size: 0.75rem; - color: var(--color-secondary-600); - margin-bottom: var(--space-3); - font-weight: 600; - } - .hero-title { - font-size: clamp(2.5rem, 2.4vw + 1.8rem, 4rem); - font-weight: 700; - line-height: 1.05; - letter-spacing: -0.02em; - margin-bottom: var(--space-4); - } - .hero-subtitle { - font-size: 1.2rem; - color: var(--color-text-muted); - max-width: 560px; - } - .hero-actions { - display: flex; - gap: var(--space-4); - flex-wrap: wrap; - margin: var(--space-6) 0 var(--space-4); - } - .hero-badges { - display: flex; - flex-wrap: wrap; - gap: var(--space-2); - } - .hero-badges span { - display: inline-flex; - padding: 0.35rem 0.75rem; - border-radius: 999px; - background: var(--color-neutral-100); - color: var(--color-neutral-900); - font-size: 0.85rem; - font-weight: 600; - border: 1px solid var(--color-border); - } - - .quote-card { - display: block; - } - .focus-card { - display: grid; - gap: var(--space-4); - } - .focus-list { - list-style: none; - padding: 0; - margin: 0; - display: grid; - gap: var(--space-2); - color: var(--color-text-muted); - } - .focus-list li::before { - content: '•'; - color: var(--color-brand); - margin-right: var(--space-2); - } - .focus-list li { - display: flex; - align-items: baseline; - gap: var(--space-2); - } - .quote-header { - display: flex; - justify-content: space-between; - align-items: flex-start; - gap: var(--space-4); - margin-bottom: var(--space-4); - } - .quote-eyebrow { - text-transform: uppercase; - font-size: 0.7rem; - letter-spacing: 0.12em; - color: var(--color-secondary-600); - margin: 0 0 var(--space-2); - } - .quote-title { margin: 0; font-size: 1.35rem; } - .quote-tag { - background: var(--color-neutral-100); - border: 1px solid var(--color-border); - border-radius: 999px; - padding: 0.35rem 0.75rem; - font-size: 0.8rem; - font-weight: 600; - } - .quote-steps { - list-style: none; - padding: 0; - margin: 0 0 var(--space-5); - display: grid; - gap: var(--space-2); - } - .quote-steps li { - position: relative; - padding-left: 1.5rem; - color: var(--color-text-muted); - } - .quote-steps li::before { - content: ''; - width: 8px; - height: 8px; - border-radius: 50%; - background: var(--color-brand); - position: absolute; - left: 0.25rem; - top: 0.5rem; - } - .quote-meta { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: var(--space-4); - margin-bottom: var(--space-5); - } - .meta-label { - display: block; - font-size: 0.75rem; - text-transform: uppercase; - letter-spacing: 0.08em; - color: var(--color-secondary-600); - margin-bottom: var(--space-1); - } - .meta-value { font-weight: 600; } - .quote-actions { display: grid; gap: var(--space-3); } - - .section { padding: 5.5rem 0; position: relative; } - .section-head { margin-bottom: var(--space-8); } - .section-title { font-size: clamp(2rem, 1.8vw + 1.2rem, 2.8rem); margin-bottom: var(--space-3); } - .section-subtitle { color: var(--color-text-muted); max-width: 620px; } - .text-muted { color: var(--color-text-muted); } - - .calculator { - background: var(--color-neutral-50); - border-top: 1px solid var(--color-border); - border-bottom: 1px solid var(--color-border); - position: relative; - // Honeycomb/Gyroid Pattern - &::before { - content: ''; - position: absolute; - inset: 0; - @include patterns.pattern-gyroid(var(--color-neutral-900), 60px); - opacity: 0.03; - pointer-events: none; - } - } - .calculator-grid { - display: grid; - gap: var(--space-10); - align-items: center; - position: relative; - z-index: 1; - } - .calculator-list { - padding-left: var(--space-4); - color: var(--color-text-muted); - margin: var(--space-6) 0 0; - } - .cap-cards { - display: grid; - gap: var(--space-4); - grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); - } - - .shop { - background: var(--color-neutral-50); - position: relative; - // Triangular/Isogrid Pattern - &::before { - content: ''; - position: absolute; - inset: 0; - @include patterns.pattern-triangular(var(--color-neutral-900), 40px); - opacity: 0.03; - pointer-events: none; - } - } - .split { - display: grid; - gap: var(--space-10); - align-items: center; - position: relative; - z-index: 1; - } - .shop-list { - padding-left: var(--space-4); - color: var(--color-text-muted); - margin-bottom: var(--space-6); - } - .shop-actions { - display: flex; - flex-wrap: wrap; - gap: var(--space-3); - } - .shop-cards { - display: grid; - gap: var(--space-4); - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); - } - - .about { - background: var(--color-neutral-50); - border-top: 1px solid var(--color-border); - } - .about-grid { - display: grid; - gap: var(--space-10); - align-items: center; - } - .about-media { - display: grid; - gap: var(--space-4); - } - .media-grid { - display: grid; - gap: var(--space-4); - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - } - .media-tile { - display: grid; - gap: var(--space-2); - } - .media-photo { - width: 100%; - aspect-ratio: 4 / 3; - border-radius: var(--radius-lg); - background: var(--color-neutral-100); - border: 1px solid var(--color-border); - } - .media-tile p { - margin: 0; - color: var(--color-text-muted); - font-size: 0.9rem; - } - .about-note { - padding: var(--space-5); - } - - @media (min-width: 960px) { - .hero-grid { grid-template-columns: 1.1fr 0.9fr; } - .calculator-grid { grid-template-columns: 1.1fr 0.9fr; } - .split { grid-template-columns: 1.1fr 0.9fr; } - .about-grid { grid-template-columns: 1.1fr 0.9fr; } - } - - @media (max-width: 640px) { - .hero-actions { flex-direction: column; align-items: stretch; } - .quote-meta { grid-template-columns: 1fr; } - } - - @keyframes fadeUp { - from { opacity: 0; transform: translateY(18px); } - to { opacity: 1; transform: translateY(0); } - } - @keyframes floatGlow { - 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(20px); } - } - - @media (prefers-reduced-motion: reduce) { - .hero-copy, .hero-panel { animation: none; } - .hero::before { animation: none; } - } - `] + templateUrl: './home.component.html', + styleUrls: ['./home.component.scss'] }) export class HomeComponent {} diff --git a/frontend/src/styles/_patterns.scss b/frontend/src/styles/_patterns.scss index 4b6bf86..519a103 100644 --- a/frontend/src/styles/_patterns.scss +++ b/frontend/src/styles/_patterns.scss @@ -51,3 +51,19 @@ radial-gradient(circle at 100% 100%, transparent 47%, $color 48%, $color 50%, transparent 51%); background-size: $size $size; } + +// 6. Cross Hatch (45deg Grid) +// Intersecting diagonal lines +@mixin pattern-cross-hatch($color, $size: 24px, $weight: 1px) { + background-image: + repeating-linear-gradient(45deg, $color 0, $color $weight, transparent $weight, transparent 50%), + repeating-linear-gradient(-45deg, $color 0, $color $weight, transparent $weight, transparent 50%); + background-size: $size $size; +} + +// 7. Rectilinear (Alternating Lines) +// Simulating a raster scan path or simple linear infill +@mixin pattern-rectilinear($color, $size: 20px, $weight: 1px) { + background-image: repeating-linear-gradient(90deg, $color 0, $color $weight, transparent $weight, transparent $size); + background-size: $size $size; +}