Started landing page

This commit is contained in:
2023-02-16 21:57:02 +01:00
parent 266a7cd21d
commit 69d6686995
15 changed files with 427 additions and 19 deletions

View File

@@ -1,6 +1,6 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import {HomeComponent} from "./home/home.component"; import {HomeComponent} from "./sites/home/home.component";
const routes: Routes = [ const routes: Routes = [
{path: "", component: HomeComponent}, {path: "", component: HomeComponent},

View File

@@ -4,17 +4,19 @@ import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NavigationComponent } from './navigation/navigation.component'; import { NavigationComponent } from './components/navigation/navigation.component';
import {MatSidenavModule} from "@angular/material/sidenav"; import {MatSidenavModule} from "@angular/material/sidenav";
import {MatIconModule} from "@angular/material/icon"; import {MatIconModule} from "@angular/material/icon";
import {MatButtonModule} from "@angular/material/button"; import {MatButtonModule} from "@angular/material/button";
import { HomeComponent } from './home/home.component'; import { HomeComponent } from './sites/home/home.component';
import { FeaturedProjectsPipe } from './pipes/featured-projects.pipe';
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
NavigationComponent, NavigationComponent,
HomeComponent HomeComponent,
FeaturedProjectsPipe
], ],
imports: [ imports: [
BrowserModule.withServerTransition({appId: 'serverApp'}), BrowserModule.withServerTransition({appId: 'serverApp'}),

View File

@@ -1,9 +1,9 @@
<nav class="header"> <nav class="header">
<img src="favicon.ico" alt="logo" class="logo" draggable="false"> <img src="../../../favicon.ico" alt="logo" class="logo" draggable="false">
<span class="name">Leon Hoppe</span> <span class="name">Leon Hoppe</span>
<div id="header-links" *ngIf="!deviceService.isMobile()"> <div id="header-links" *ngIf="!deviceService.isMobile()">
<a class="header-link" *ngFor="let link of navLinks" [routerLink]="link.href" [ngClass]="{'active': router.url == link.href}">{{link.label}}</a> <a class="header-link" *ngFor="let link of navLinks" [routerLink]="link.href" [ngClass]="{'active': cleanUrl(router.url) == link.href}">{{link.label}}</a>
</div> </div>
<div id="social-media" [ngStyle]="{'margin-left': deviceService.isMobile() ? 'auto' : ''}"> <div id="social-media" [ngStyle]="{'margin-left': deviceService.isMobile() ? 'auto' : ''}">
@@ -18,7 +18,7 @@
</section> </section>
<nav *ngIf="deviceService.isMobile()" class="footer"> <nav *ngIf="deviceService.isMobile()" class="footer">
<button mat-button class="footer-link" *ngFor="let link of navLinks" [routerLink]="link.href" [ngClass]="{'active': router.url == link.href}"> <button mat-button class="footer-link" *ngFor="let link of navLinks" [routerLink]="link.href" [ngClass]="{'active': cleanUrl(router.url) == link.href}">
<mat-icon>{{link.icon}}</mat-icon> <mat-icon>{{link.icon}}</mat-icon>
</button> </button>
</nav> </nav>

View File

@@ -1,4 +1,4 @@
$border-color: black; $border-color: #2d2d2d;
.header { .header {
width: 100vw; width: 100vw;

View File

@@ -25,4 +25,18 @@ export class NavigationComponent {
{href: 'mailto://leon@ladenbau-hoppe.de', image: 'https://webmail.strato.de/favicon.ico'} {href: 'mailto://leon@ladenbau-hoppe.de', image: 'https://webmail.strato.de/favicon.ico'}
] ]
public cleanUrl(url: string): string {
try {
url = location.origin + url;
const urlObj = new URL(url);
urlObj.search = '';
urlObj.hash = '';
return urlObj.toString().replace(location.origin, "");
} catch {
return "";
}
}
} }

View File

@@ -1 +0,0 @@
<p>home works!</p>

View File

@@ -1,10 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent {
}

View File

@@ -0,0 +1,7 @@
export interface Project {
cover: string;
name: string;
description: string;
buttons?: {text: string; link: string}[];
featured?: boolean;
}

View File

@@ -0,0 +1,18 @@
import { Pipe, PipeTransform } from '@angular/core';
import {Project} from "../models/project";
@Pipe({
name: 'featuredProjects'
})
export class FeaturedProjectsPipe implements PipeTransform {
transform(objects: Project[]): Project[] {
const newObjects: Project[] = [];
objects?.forEach(obj => {
if (obj?.featured)
newObjects.push(obj);
})
return newObjects;
}
}

View File

@@ -0,0 +1,31 @@
<section id="hero" [ngClass]="{'mobile': deviceService.isMobile()}">
<div class="artwork">
<div class="circle big-circle"></div>
<div class="circle small-circle"></div>
<div class="circle image"></div>
</div>
<h1>
<span>Hallo, ich bin Leon Hoppe,</span><br>
full stack developer
</h1>
<p>
Auf dieser Seite erfahren Sie, an welchen Projekten ich bereits gearbeitet habe,<br>
was meine Programmierkenntnisse sind und welche Pläne ich für die Zukunft habe.
</p>
<a href="#projects">Mehr erfahren</a>
</section>
<section id="projects" [ngClass]="{'mobile': deviceService.isMobile()}">
<h1>Projekte</h1>
<a routerLink="/projects">alle ansehen</a>
<div id="project-wrapper">
<div class="project" *ngFor="let project of projects | featuredProjects">
<img src="{{project.cover}}" alt="{{project.name}}">
<h2>{{project.name}}</h2>
<span>{{project.description}}</span>
<div class="project-buttons">
<a class="project-button" *ngFor="let button of project.buttons" href="{{button.link}}">{{button.text}}</a>
</div>
</div>
</div>
</section>

View File

@@ -0,0 +1,233 @@
@use "../../../theme";
@use "src/styles" as s;
@use 'sass:map';
$gradient: linear-gradient(90deg, theme.$primary, theme.$secondary);
$gradient-angled: linear-gradient(135deg, theme.$primary, theme.$secondary);
$gradient-straight: linear-gradient(theme.$primary, theme.$secondary);
$padding: 12.5vw;
$padding-small: 5vw;
$desc-color: #7c8393;
#hero {
height: 100vh;
padding-left: $padding;
user-select: none;
position: relative;
overflow-x: hidden;
box-sizing: border-box;
h1 {
margin-top: 20vh;
font-size: 45px;
line-height:70px;
span {
background: $gradient;
background-clip: text;
color: transparent;
}
}
p {
font-size: 18px;
color: $desc-color;
}
a {
display: block;
margin-top: 40px;
height: 60px;
width: 150px;
background: $gradient;
border-radius: 30px;
font-size: 15px;
text-align: center;
line-height: 60px;
text-decoration: none;
box-shadow: 0 0 40px -5px theme.$primary;
}
.artwork {
position: absolute;
left: 55%;
top: 19vh;
.circle {
position: absolute;
aspect-ratio: 1 / 1;
z-index: -1;
background: $gradient-angled;
border-radius: 50%;
&:after {
content: '';
position: absolute;
inset: 1px;
background-color: map.get(theme.$background, 'background');
border-radius: 50%;
}
}
.big-circle {
left: 0;
top: 0;
width: 400px;
}
.small-circle {
top: 100px;
left: 350px;
width: 150px;
&:after {
content: none;
}
}
.image {
top: -50px;
left: 170px;
width: 250px;
&:after {
background-image: url("/favicon.ico");
background-size: 112%;
background-position: -15px -15px;
}
}
}
&.mobile {
padding-left: $padding-small;
h1 {
margin-top: 10vh;
font-size: 30px;
line-height: 50px;
}
p {
font-size: 15px;
margin-right: 20px;
}
.artwork > .small-circle, .artwork > .image {
display: none;
}
}
}
#projects {
padding-inline: $padding;
user-select: none;
margin-bottom: 100px;
h1 {
font-size: 35px;
display: inline;
margin-right: 10px;
}
#project-wrapper {
display: flex;
flex-wrap: wrap;
margin-top: 70px;
justify-content: space-between;
gap: 70px;
.project {
width: 400px;
height: 500px;
padding: 25px;
box-sizing: border-box;
background: map.get(theme.$background, 'background');
border-radius: 30px;
position: relative;
display: flex;
flex-direction: column;
box-shadow: 0 0 40px -10px theme.$primary;
&:before {
position: absolute;
inset: -1px;
content: '';
background: $gradient-straight;
border-radius: 30px;
z-index: -1;
}
img {
width: 350px;
height: 170px;
object-fit: cover;
border-radius: 12px;
}
h2 {
margin-block: 10px 5px;
font-size: 20px;
}
span {
color: $desc-color;
}
.project-buttons {
display: flex;
justify-content: space-evenly;
margin-top: auto;
flex-wrap: wrap;
gap: 5px;
.project-button {
display: block;
text-align: center;
line-height: 40px;
width: max-content;
height: 40px;
padding-inline: 15px;
border: 1px solid #FFF;
border-radius: 20px;
text-decoration: none;
font-size: 13px;
&:hover {
text-decoration: underline;
}
}
}
}
}
&.mobile {
padding-inline: $padding-small;
h1 {
font-size: 25px;
}
#project-wrapper {
margin-top: 30px;
gap: 30px;
.project {
width: 100%;
height: 450px;
box-shadow: none;
img {
width: 100%;
height: auto;
}
}
}
}
}

View File

@@ -0,0 +1,53 @@
import { Component } from '@angular/core';
import {DeviceDetectorService} from "ngx-device-detector";
import {Project} from "../../models/project";
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent {
public constructor(public deviceService: DeviceDetectorService) {}
public projects: Project[] = [
{
name: "Test Project",
description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur excepturi facere, fuga maxime nulla qui voluptas voluptates? Adipisci asperiores dolor error iste sunt tempore. Blanditiis illum mollitia nostrum quae vero?",
cover: "https://cdn.leon-hoppe.de/portfolio/projects/manager.jpeg",
featured: true,
buttons: [{
text: "Source Code",
link: "#hero"
}]
},
{
name: "Test Project",
description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur excepturi facere, fuga maxime nulla qui voluptas voluptates? Adipisci asperiores dolor error iste sunt tempore. Blanditiis illum mollitia nostrum quae vero?",
cover: "https://cdn.leon-hoppe.de/portfolio/projects/manager.jpeg",
featured: true,
buttons: [{
text: "Source Code",
link: ""
},
{
text: "gskjghjshfkafsdgs",
link: "#hero"
},]
},
{
name: "Test Project",
description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur excepturi facere, fuga maxime nulla qui voluptas voluptates? Adipisci asperiores dolor error iste sunt tempore. Blanditiis illum mollitia nostrum quae vero?",
cover: "https://cdn.leon-hoppe.de/portfolio/projects/manager.jpeg",
featured: true
},
{
name: "Test Project",
description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur excepturi facere, fuga maxime nulla qui voluptas voluptates? Adipisci asperiores dolor error iste sunt tempore. Blanditiis illum mollitia nostrum quae vero?",
cover: "https://cdn.leon-hoppe.de/portfolio/projects/manager.jpeg",
featured: true
},
]
}

View File

@@ -2,8 +2,44 @@
html, body { height: 100vh; } html, body { height: 100vh; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
*, html {scroll-behavior: smooth !important;}
mat-drawer > div { mat-drawer > div {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
::-webkit-scrollbar {
width: 5px;
}
::-webkit-scrollbar-track {
display: none;
}
::-webkit-scrollbar-thumb {
background: #484c52;
border-radius: 2.5px;
}
::-webkit-scrollbar-thumb:hover {
background: #5b6067;
}
@function css-function( $function, $values... ) {
@return
$function
+ unquote( '(' )
+ $values
+ unquote( ')' )
;
}
@function css-min( $values... ) {
@return css-function( min, $values );
}
@function css-max( $values... ) {
@return css-function( max, $values );
}
@function css-clamp( $values... ) {
@return css-function( clamp, $values );
}

View File

@@ -3,6 +3,26 @@
@import "/node_modules/@angular/material/theming"; @import "/node_modules/@angular/material/theming";
@include mat.core(); @include mat.core();
@function modify-background($theme, $background-color) {
// Replace the background in the color object's background palette.
$theme-color: map-get($theme, color);
$color-background-palette: map-get($theme-color, background);
$color-background-palette: map-merge($color-background-palette, (background: $background-color));
$color-background-palette: map-merge($color-background-palette, (raised-button: $background-color));
// Replace the background in the background palette.
$background-palette: map-get($theme, background);
$background-palette: map-merge($background-palette, (background: $background-color));
$background-palette: map-merge($background-palette, (raised-button: $background-color));
// Merge the changes into a new theme.
$modified-theme-color: map-merge($theme-color, (background: $color-background-palette));
$modified-theme: map-merge($theme, (color: $modified-theme-color));
$modified-theme: map-merge($modified-theme, (background: $background-palette));
@return $modified-theme;
}
$angular-primary: mat.define-palette(mat.$blue-palette, 500, 100, 900); $angular-primary: mat.define-palette(mat.$blue-palette, 500, 100, 900);
$angular-accent: mat.define-palette(mat.$green-palette, A200, A100, A400); $angular-accent: mat.define-palette(mat.$green-palette, A200, A100, A400);
$angular-warn: mat.define-palette(mat.$red-palette); $angular-warn: mat.define-palette(mat.$red-palette);
@@ -17,8 +37,13 @@ $angular-theme: mat.define-dark-theme(
) )
); );
$angular-theme: modify-background($angular-theme, #0f1724);
@include mat.all-component-themes($angular-theme); @include mat.all-component-themes($angular-theme);
$primary: #8e5bd2;
$secondary: #11a8bd;
$color-config: mat.get-color-config($angular-theme); $color-config: mat.get-color-config($angular-theme);
$background: map.get($color-config, 'background'); $background: map.get($color-config, 'background');
$text: map.get($color-config, 'foreground'); $text: map.get($color-config, 'foreground');