diff --git a/src/Portfolio.Api/Program.cs b/src/Portfolio.Api/Program.cs index 40be3c1..7030e00 100644 --- a/src/Portfolio.Api/Program.cs +++ b/src/Portfolio.Api/Program.cs @@ -1,5 +1,6 @@ using HopFrame.Core.Config; using HopFrame.Web; +using Microsoft.EntityFrameworkCore; using Portfolio.Api; using Portfolio.Api.Services; using Portfolio.Shared.Models; diff --git a/src/Portfolio.Shared/Models/Technology.cs b/src/Portfolio.Shared/Models/Technology.cs index f6eefae..af67be8 100644 --- a/src/Portfolio.Shared/Models/Technology.cs +++ b/src/Portfolio.Shared/Models/Technology.cs @@ -20,7 +20,8 @@ public sealed class Technology { public TechnologyLevel Level { get; set; } = TechnologyLevel.Beginner; public TechnologyType Type { get; set; } = TechnologyType.Language; - + + public bool Featured { get; set; } } public enum TechnologyLevel { diff --git a/src/Portfolio.Web/Components/App.razor b/src/Portfolio.Web/Components/App.razor index 5202003..57dfeae 100644 --- a/src/Portfolio.Web/Components/App.razor +++ b/src/Portfolio.Web/Components/App.razor @@ -22,7 +22,6 @@ - \ No newline at end of file diff --git a/src/Portfolio.Web/Components/Components/TechnologyView.razor b/src/Portfolio.Web/Components/Components/TechnologyView.razor index e2bc846..47da92a 100644 --- a/src/Portfolio.Web/Components/Components/TechnologyView.razor +++ b/src/Portfolio.Web/Components/Components/TechnologyView.razor @@ -1,22 +1,21 @@ -@rendermode InteractiveServer -@using Portfolio.Shared.Models +@using Portfolio.Shared.Models

@Technology.Name

@GetTechnologyLevelName()
-
+
-@inject IJSRuntime Runtime + @code { [Parameter] public required Technology Technology { get; set; } - - private ElementReference _element; public string GetTechnologyLevelName() { switch (Technology.Level) { @@ -31,10 +30,5 @@ return "Normal"; } } - - protected override async Task OnAfterRenderAsync(bool firstRender) { - if (!firstRender) return; - await Runtime.InvokeVoidAsync("observeElement", _element); - } } \ No newline at end of file diff --git a/src/Portfolio.Web/Components/Components/TechnologyView.razor.css b/src/Portfolio.Web/Components/Components/TechnologyView.razor.css index 620ca54..a416f7f 100644 --- a/src/Portfolio.Web/Components/Components/TechnologyView.razor.css +++ b/src/Portfolio.Web/Components/Components/TechnologyView.razor.css @@ -26,15 +26,15 @@ transition: width 200ms ease-out; width: 0; - &.level-1 { + &.level-0 { --width: 33%; } - &.level-2 { + &.level-1 { --width: 66%; } - &.level-3 { + &.level-2 { --width: 100%; } diff --git a/src/Portfolio.Web/Components/Components/TimestampView.razor b/src/Portfolio.Web/Components/Components/TimestampView.razor index 1817a85..9ed6642 100644 --- a/src/Portfolio.Web/Components/Components/TimestampView.razor +++ b/src/Portfolio.Web/Components/Components/TimestampView.razor @@ -1,9 +1,14 @@ @using Portfolio.Shared.Models +

@Entry.Date.Year

@Entry.Description
+ + @code { [Parameter] diff --git a/src/Portfolio.Web/Components/Components/TimestampView.razor.css b/src/Portfolio.Web/Components/Components/TimestampView.razor.css index 600e3b9..8e9444c 100644 --- a/src/Portfolio.Web/Components/Components/TimestampView.razor.css +++ b/src/Portfolio.Web/Components/Components/TimestampView.razor.css @@ -5,7 +5,6 @@ gap: 50px; position: relative; opacity: 0; - animation: fade-in 200ms forwards calc(var(--index) * 200ms) ease-out; h2 { font-size: 20px; @@ -40,11 +39,18 @@ top: 51px; position: absolute; display: var(--show-bar, block); + } +} + +.timestamp.in-view { + animation: fade-in 200ms forwards calc(var(--index) * 200ms) ease-out; + + &:before { animation: timestamp-in 500ms forwards calc((var(--index) + 1) * 200ms) ease-in-out; } } -@media screen and (max-width: 1200px) { +@media screen and (max-width: var(--mobile-width)) { .timestamp { gap: 15px; padding-left: 30px; diff --git a/src/Portfolio.Web/Components/Pages/AboutPage.razor.css b/src/Portfolio.Web/Components/Pages/AboutPage.razor.css index 01d7c42..6672028 100644 --- a/src/Portfolio.Web/Components/Pages/AboutPage.razor.css +++ b/src/Portfolio.Web/Components/Pages/AboutPage.razor.css @@ -17,7 +17,7 @@ margin-top: 30px; } -@media screen and (max-width: 1200px) { +@media screen and (max-width: var(--mobile-width)) { #about { grid-template-columns: unset; grid-template-rows: repeat(2, max-content); diff --git a/src/Portfolio.Web/Components/Pages/Home.razor b/src/Portfolio.Web/Components/Pages/Home.razor index 6ec3cf9..90a1267 100644 --- a/src/Portfolio.Web/Components/Pages/Home.razor +++ b/src/Portfolio.Web/Components/Pages/Home.razor @@ -1,5 +1,112 @@ @page "/" +@using Portfolio.Shared.Models +@using Portfolio.Shared.Services +@using Portfolio.Web.Components.Components -Portfolio von Leon Hoppe +
+
+
+
+
+
+

+ Hallo, ich bin Leon Hoppe,
+ +

+

+ Auf dieser Seite erfahren Sie, an welchen Projekten ich bereits gearbeitet habe,
+ was meine Programmierkenntnisse sind und welche Pläne ich für die Zukunft habe. +

+ Mehr erfahren +
-

Hello, world!

+
+

Projekte

+ alle ansehen +
+ @foreach (var (index, project) in _projects.Index()) { + + } +
+
+ +
+

Technologien

+ mehr erfahren +
+ @foreach (var technology in _technologies) { + + } +
+
+ +
+

Über mich

+ mehr erfahren +
+ @foreach (var (index, timestamp) in _timeline.Index()) { + + } +
+
+ + + +@inherits CancellableComponent + +@inject IProjectRepository ProjectRepository +@inject ITechnologyRepository TechnologyRepository +@inject ITimelineRepository TimelineRepository + +@code { + + private IEnumerable _projects = []; + private IEnumerable _technologies = []; + private IEnumerable _timeline = []; + + protected override async Task OnInitializedAsync() { + var projects = await ProjectRepository.GetProjects(TokenSource.Token); + _projects = projects.Where(p => p.Featured); + + var technologies = await TechnologyRepository.GetTechnologies(TokenSource.Token); + _technologies = technologies.Where(t => t.Featured); + + var carrierTimeline = await TimelineRepository.GetTimeline(TimelineEntryType.Carrier, TokenSource.Token); + var experienceTimeline = await TimelineRepository.GetTimeline(TimelineEntryType.Experience, TokenSource.Token); + _timeline = experienceTimeline + .Aggregate(carrierTimeline, (current, entry) => current.Append(entry)) + .Where(t => t.Featured) + .OrderBy(t => t.Date); + } + +} diff --git a/src/Portfolio.Web/Components/Pages/Home.razor.css b/src/Portfolio.Web/Components/Pages/Home.razor.css new file mode 100644 index 0000000..8b5c62f --- /dev/null +++ b/src/Portfolio.Web/Components/Pages/Home.razor.css @@ -0,0 +1,128 @@ +#hero { + height: 100vh; + box-sizing: border-box; + + h2 { + margin-top: 20vh; + font-size: 45px; + line-height:70px; + position: relative; + + #welcome { + background: var(--gradient); + background-clip: text; + color: transparent; + } + + #jobs { + position: relative; + + &:after { + content: ''; + position: absolute; + left: calc(100% + 5px); + top: 0; + width: 20px; + height: 100%; + background-color: var(--text); + animation: blink 800ms infinite; + } + } + } + + p { + font-size: 18px; + color: var(--desc-color); + position: relative; + } + + a { + display: block; + margin-top: 40px; + height: 60px; + width: 150px; + background: var(--gradient); + border-radius: 30px; + font-size: 15px; + text-align: center; + line-height: 60px; + text-decoration: none; + + box-shadow: 0 0 40px -5px var(--primary); + } +} + +.title { + font-size: 35px; + display: inline; + margin-right: 10px; +} + +#projects { + #projects-wrapper { + display: flex; + flex-wrap: wrap; + margin-top: 70px; + justify-content: space-evenly; + gap: 70px; + } +} + +#technologies { + margin-top: 300px; + + .technologies-wrapper { + margin-top: 30px; + } +} + +#about { + margin-top: 150px; +} + +.timeline ::deep .timestamp:last-of-type { + --show-bar: none; +} + +.timeline { + display: flex; + margin-top: 30px; +} + +a:not(#main-action) { + text-decoration: none; + position: relative; + + &:before { + content: ""; + position: absolute; + width: 100%; + height: 2px; + bottom: 0; + left: 0; + background-color: var(--text); + visibility: hidden; + transform: scaleX(0); + transform-origin: left; + transition: all 0.3s ease-in-out; + } +} + +a:not(#main-action):hover::before { + visibility: visible; + transform: scaleX(1); +} + +@keyframes blink { + 0% { + opacity: 1; + } + + 50% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} diff --git a/src/Portfolio.Web/Components/Pages/TechnologiesPage.razor b/src/Portfolio.Web/Components/Pages/TechnologiesPage.razor index ac9259a..8bd6d40 100644 --- a/src/Portfolio.Web/Components/Pages/TechnologiesPage.razor +++ b/src/Portfolio.Web/Components/Pages/TechnologiesPage.razor @@ -1,7 +1,5 @@ @page "/technologies" -@rendermode InteractiveServer -@using System.Collections.Immutable @using Portfolio.Shared.Models @using Portfolio.Shared.Services @using Portfolio.Web.Components.Components @@ -50,6 +48,15 @@ +
+ @foreach (var (label, count) in _projectTechnologies) { +
+ @label + @count +
+ } +
+ @inherits CancellableComponent @inject ITechnologyRepository TechnologyRepository @inject IProjectRepository ProjectRepository -@inject IJSRuntime Runtime @code { private IEnumerable _technologies = []; + private IEnumerable> _projectTechnologies = []; protected override async Task OnInitializedAsync() { _technologies = await TechnologyRepository.GetTechnologies(TokenSource.Token); - } - - protected override async Task OnAfterRenderAsync(bool firstRender) { - if (firstRender) { - var projects = await ProjectRepository.GetProjects(TokenSource.Token); - - var data = projects - .SelectMany(p => p.Languages) - .CountBy(l => l.Name) - .ToList(); - - await Runtime.InvokeVoidAsync("displayChart", - data.Select(c => c.Key), - data.Select(c => c.Value)); - } + + var projects = await ProjectRepository.GetProjects(TokenSource.Token); + _projectTechnologies = projects + .SelectMany(p => p.Languages) + .CountBy(l => l.Name); } } \ No newline at end of file diff --git a/src/Portfolio.Web/Program.cs b/src/Portfolio.Web/Program.cs index 6ab644c..7f6fec0 100644 --- a/src/Portfolio.Web/Program.cs +++ b/src/Portfolio.Web/Program.cs @@ -5,8 +5,7 @@ using Portfolio.Web.Services; var builder = WebApplication.CreateBuilder(args); // Add services to the container. -builder.Services.AddRazorComponents() - .AddInteractiveServerComponents(); +builder.Services.AddRazorComponents(); builder.AddServiceDefaults(); @@ -33,7 +32,6 @@ app.MapDefaultEndpoints(); app.UseAntiforgery(); app.MapStaticAssets(); -app.MapRazorComponents() - .AddInteractiveServerRenderMode(); +app.MapRazorComponents(); app.Run(); \ No newline at end of file diff --git a/src/Portfolio.Web/wwwroot/app.css b/src/Portfolio.Web/wwwroot/app.css index 2df0872..6dd35cb 100644 --- a/src/Portfolio.Web/wwwroot/app.css +++ b/src/Portfolio.Web/wwwroot/app.css @@ -24,6 +24,7 @@ font-family: "Ubuntu", serif; font-weight: 400; font-style: normal; + scroll-behavior: smooth; } html, body { diff --git a/src/Portfolio.Web/wwwroot/scroll-handler.js b/src/Portfolio.Web/wwwroot/scroll-handler.js index 027fc33..2f6f516 100644 --- a/src/Portfolio.Web/wwwroot/scroll-handler.js +++ b/src/Portfolio.Web/wwwroot/scroll-handler.js @@ -5,6 +5,7 @@ }); }); -function observeElement(element) { - observer?.observe(element); +function observeElements(className) { + const elements = document.querySelectorAll(`.${className}`); + elements.forEach(e => observer.observe(e)); }