diff --git a/adev/shared-docs/styles/_colors.scss b/adev/shared-docs/styles/_colors.scss index 3009a53e184..23c5334b831 100644 --- a/adev/shared-docs/styles/_colors.scss +++ b/adev/shared-docs/styles/_colors.scss @@ -13,6 +13,7 @@ --electric-violet: oklch(53.18% 0.28 296.97); // #8514f5 --french-violet: oklch(47.66% 0.246 305.88); // #8001c6 --vivid-pink: oklch(69.02% 0.277 332.77); // #f637e3 + --always-pink: oklch(69.02% 0.277 332.77); // #f637e3 --hot-pink: oklch(59.91% 0.239 8.14); // #e90464 --hot-red: oklch(61.42% 0.238 15.34); // #f11653 --orange-red: oklch(63.32% 0.24 31.68); // #fa2c04 @@ -22,7 +23,7 @@ --deprecated-docs-bg: var(--deprecated-light); // Alias specifically for deprecated docs // subtle-purple is used for inline-code bg, docs-card hover bg & docs-code header bg - --subtle-purple: color-mix(in srgb, var(--bright-blue) 5%, white 10%); + --subtle-purple: color-mix(in srgb, var(--bright-blue) 8%, white 92%); --light-blue: color-mix(in srgb, var(--bright-blue), white 50%); --light-violet: color-mix(in srgb, var(--electric-violet), white 65%); --light-orange: color-mix(in srgb, var(--orange-red), white 50%); @@ -211,6 +212,7 @@ --electric-violet: color-mix(in srgb, oklch(53.18% 0.28 296.97), var(--full-contrast) 70%); --french-violet: color-mix(in srgb, oklch(47.66% 0.246 305.88), var(--full-contrast) 70%); --vivid-pink: color-mix(in srgb, oklch(69.02% 0.277 332.77), var(--full-contrast) 70%); + // --always-pink we keep the same in light mode --hot-pink: color-mix(in srgb, oklch(59.91% 0.239 8.14), var(--full-contrast) 70%); --hot-red: color-mix(in srgb, oklch(61.42% 0.238 15.34), var(--full-contrast) 70%); --orange-red: color-mix(in srgb, oklch(63.32% 0.24 31.68), var(--full-contrast) 60%); @@ -220,6 +222,7 @@ --deprecated-docs-bg: var(--deprecated-dark); // Alias specifically for deprecated docs --light-pink: color-mix(in srgb, var(--vivid-pink) 5%, var(--page-background) 75%); + --subtle-purple: color-mix(in srgb, var(--bright-blue) 5%, var(--page-background) 85%); --symbolic-purple: color-mix(in srgb, oklch(42.86% 0.29 266.4), var(--full-contrast) 65%); --symbolic-gray: color-mix(in srgb, oklch(66.98% 0 0), var(--full-contrast) 65%); diff --git a/adev/shared-docs/styles/docs/_card.scss b/adev/shared-docs/styles/docs/_card.scss index 3ee5aeaae01..52cf9300aca 100644 --- a/adev/shared-docs/styles/docs/_card.scss +++ b/adev/shared-docs/styles/docs/_card.scss @@ -16,6 +16,7 @@ display: flex; flex-direction: column; justify-content: space-between; + background: var(--page-background); color: var(--primary-contrast); padding: 1.5rem; border: 1px solid var(--senary-contrast); @@ -40,7 +41,7 @@ position: relative; } - * + *:not(a):not(code):not(span) { + * + *:not(a):not(code):not(span):not(div) { margin-block: 1.5rem; } diff --git a/adev/src/app/features/home/home.component.html b/adev/src/app/features/home/home.component.html index 77e44585fc2..3ac5daf7e96 100644 --- a/adev/src/app/features/home/home.component.html +++ b/adev/src/app/features/home/home.component.html @@ -1,17 +1,477 @@ - +
+ @if (!isUwu) { + +
+ + + + + + + + + + + + + + + +

The framework for building scalable web apps with confidence

+
+ } @else { + +
+ Angular logo +
+ } - -@if (!animationReady()) { -
-} - -
-
- @defer (when showEditor(); prefetch when prefetchEditor()) { - - } @loading { - Code editor - } + -
+
+ +
+

Productivity meets scalability

+
+
+ + + + + + + + + + +

AI-forward

+

Resources and integrations to supercharge your development with AI

+
+
+ + + +

Opinionated & versatile

+

Organized yet modular thanks to Angular components and dependency injection

+
+
+ + + +

Reactive

+

Fast state updates with fine-gained reactivity based on Angular Signals

+
+
+ + + +

Fully featured

+

+ Everything works together with Angular's first-party modules for forms, routing, and more +

+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + +
+ +
diff --git a/adev/src/app/features/home/home.component.scss b/adev/src/app/features/home/home.component.scss index 8029cb3c70e..507775d3e1b 100644 --- a/adev/src/app/features/home/home.component.scss +++ b/adev/src/app/features/home/home.component.scss @@ -3,74 +3,282 @@ :host { width: 100%; position: relative; +} - // While editor is loading, display an svg of the editor - .docs-dark-mode & { - .adev-editor-scroll-container img { - content: url('../../../assets/images/editor-dark-horizontal.svg'); - @include mq.for-tablet-down { - content: url('../../../assets/images/editor-dark-vertical.svg'); - } +.logo-section { + text-align: center; + background-image: + linear-gradient( + 63deg, + transparent 66%, + var(--page-background) 69%, + var(--page-background) 70%, + transparent 70% + ), + linear-gradient(162deg, var(--page-background) 50%, #9337f58a 100%); + background-size: + 27px 27px, + auto; + background-repeat: repeat; + background-color: transparent; + padding-bottom: 36px; + + button { + font-size: 1.2rem; + + @include mq.for-tablet-down { + font-size: 1rem; } - } - .docs-light-mode & { - .adev-editor-scroll-container img { - content: url('../../../assets/images/editor-light-horizontal.svg'); - @include mq.for-tablet-down { - content: url('../../../assets/images/editor-light-vertical.svg'); - } + + @include mq.for-phone-only { + font-size: 0.8rem; } } - .spacer { - height: 100vh; + $transition: 200ms linear; + margin-top: 5rem; + + .svg { + fill-rule: evenodd; + clip-rule: evenodd; + stroke-linejoin: round; + stroke-miterlimit: 2; + color: var(--primary-contrast); + + max-width: 680px; } - .adev-editor-scroll-container { - position: relative; - height: 300vh; - background-color: var(--page-background); + h2 { + margin-top: 0; + font-size: 1.2rem; - .adev-code-editor { - background-color: var(--page-background); - padding-bottom: 60px; - position: sticky; - top: calc((100vh - (100vh - 110px)) / 2); - - @include mq.for-tablet { - top: calc(((100vh - (100vh - 110px)) / 2) + 36px); + @include mq.for-tablet-down { + & { + font-size: 1rem; } - @include mq.for-phone-only { - top: calc(((100vh - (100vh - 110px)) / 2) + 25px); - } - - // stylelint-disable-next-line - ::ng-deep { - embedded-editor { - margin: 0 auto; - display: flex; - width: 75vw; - height: calc(100vh - 110px); - - @include mq.for-phone-only { - width: 95vw; - } - - .adev-editor-container { - width: 100%; - } - } - } - } - - img { - margin: 0 auto; - display: flex; - justify-content: center; - align-items: center; - height: auto; - min-height: 60vh; - width: 75vw; + } + } +} + +section { + padding-left: 2rem; + padding-right: 2rem; + + h2 { + font-size: 2.5rem; + margin-bottom: 3rem; + } + + svg { + fill: var(--always-pink); + color: var(--always-pink); + } + + .section-content { + max-width: 1200px; + margin: 0 auto; + } +} + +.features { + padding: 2rem; + text-align: center; + + h2 { + font-size: 2.2rem; + } + + .features-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + max-width: 1200px; + margin: 0 auto; + + @include mq.for-tablet-down { + grid-template-columns: repeat(2, 1fr); + } + + @include mq.for-phone-only { + grid-template-columns: 1fr; + } + } + + .feature { + padding: 2rem; + border-left: 1px solid var(--senary-contrast); + + &:first-child { + border-left: none; + } + + @include mq.for-tablet-down { + border-top: 1px solid var(--senary-contrast); + + &:first { + border-top: none; + } + + &:nth-child(odd) { + border-left: none; + } + } + + @include mq.for-phone-only { + &:nth-child(n) { + border-left: none; + } + + &:nth-child(-n + 1) { + border-top: none; + } + } + + svg { + width: 3rem; + } + + h3 { + font-size: 1.5rem; + margin-bottom: 1rem; + } + + p { + font-size: 1rem; + color: var(--quaternary-contrast); + font-weight: 300; + } + } +} + +.performance { + background-image: + linear-gradient( + 63deg, + transparent 66%, + var(--page-background) 69%, + var(--page-background) 70%, + transparent 70% + ), + linear-gradient(350deg, var(--page-background) 50%, #9337f58a 100%); + background-size: + 27px 27px, + auto; + background-repeat: repeat; + background-color: transparent; + + .section-content { + display: flex; + flex-wrap: wrap; + gap: 1.5rem; + } + + .performance-half { + flex: 1 0 200px; + padding: 3rem 0; + + &:nth-child(2) { + display: flex; + justify-content: center; + align-items: center; + + @include mq.for-desktop-down { + display: none; + } + + svg { + width: 80%; + max-width: 365px; + } + } + } + + p { + &.secondary { + font-size: 1.2rem; + } + } + + .docs-card-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1.5rem; + + @include mq.for-tablet-down { + grid-template-columns: 1fr; + } + } +} + +.learn-more { + background-image: + linear-gradient( + 63deg, + transparent 66%, + var(--page-background) 69%, + var(--page-background) 70%, + transparent 70% + ), + linear-gradient(162deg, var(--page-background) 50%, #9337f58a 100%); + background-size: + 27px 27px, + auto; + background-repeat: repeat; + background-color: transparent; + + padding: 5rem 2rem; + text-align: left; + + h2 { + font-size: 2.5rem; + margin-bottom: 3rem; + } + + h3 { + margin-top: 0; + } + + svg { + max-width: 64px; + margin: 0 1rem; + } + + p { + font-size: 1rem; + font-weight: 300; + + &.secondary { + color: var(--quaternary-contrast); + } + } + + .card-content { + flex: 1; + display: flex; + flex-direction: column; + justify-content: space-between; + height: 100%; + } + + .docs-card { + display: flex; + flex-direction: row; + align-items: flex-start; + gap: 1.5rem; + + @include mq.for-tablet-down { + & { + flex-direction: column; + } + } + } + + .docs-card-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1.5rem; + + @include mq.for-tablet-down { + grid-template-columns: 1fr; } } } diff --git a/adev/src/app/features/home/home.component.ts b/adev/src/app/features/home/home.component.ts index 8ca5fd1429f..5c7c61c0774 100644 --- a/adev/src/app/features/home/home.component.ts +++ b/adev/src/app/features/home/home.component.ts @@ -6,58 +6,17 @@ * found in the LICENSE file at https://angular.dev/license */ -import { - ChangeDetectionStrategy, - Component, - computed, - DestroyRef, - inject, - Renderer2, - signal, -} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; -import {DOCUMENT} from '@angular/common'; -import {WINDOW} from '@angular/docs'; - -import {HomeAnimationComponent} from './components/home-animation/home-animation.component'; -import {CodeEditorComponent} from './components/home-editor.component'; - -export const TUTORIALS_HOMEPAGE_DIRECTORY = 'homepage'; +import {ChangeDetectionStrategy, Component, inject} from '@angular/core'; +import {ActivatedRoute, RouterLink} from '@angular/router'; @Component({ selector: 'adev-home', - imports: [HomeAnimationComponent, CodeEditorComponent], + imports: [RouterLink], templateUrl: './home.component.html', styleUrls: ['./home.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export default class Home { private readonly activatedRoute = inject(ActivatedRoute); - private readonly renderer = inject(Renderer2); - private readonly win = inject(WINDOW); - private readonly doc = inject(DOCUMENT); - private readonly destroyRef = inject(DestroyRef); - - protected readonly tutorialFiles = TUTORIALS_HOMEPAGE_DIRECTORY; protected readonly isUwu = 'uwu' in this.activatedRoute.snapshot.queryParams; - - private scrollProgress = signal(0); - - readonly prefetchEditor = computed(() => this.scrollProgress() > 0.25); - readonly showEditor = computed(() => this.scrollProgress() > 0.35); - - animationReady = signal(false); - - constructor() { - const scrollListenerCleanupFn = this.renderer.listen(this.win, 'scroll', () => - // Keep track of the scroll progress since the home animation uses - // different mechanics for the standard and reduced-motion animations. - this.scrollProgress.set(this.win.scrollY / this.doc.body.scrollHeight), - ); - this.destroyRef.onDestroy(() => scrollListenerCleanupFn()); - } - - onAnimationReady(ready: boolean) { - this.animationReady.set(ready); - } }