Skip to content

Commit 9f81f00

Browse files
authored
Merge pull request #14 from i4Ds/Add-Home-Page
Add home page and Folder Structure
2 parents 401dce3 + 00b3ba2 commit 9f81f00

18 files changed

Lines changed: 874 additions & 536 deletions

BauMat.Client/BauMat.Client.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,8 @@
1717
<ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" />
1818
</ItemGroup>
1919

20+
<ItemGroup>
21+
<Folder Include="wwwroot\images\" />
22+
</ItemGroup>
23+
2024
</Project>

BauMat.Client/Components/Common/.gitkeep

Whitespace-only changes.

BauMat.Client/Layout/MainLayout.razor renamed to BauMat.Client/Components/Layout/MainLayout.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
<header class="app-header">
44
<div class="app-header-inner">
5-
<div class="app-brand">
5+
<a class="app-brand" href="/">
66
<div class="app-logo">
77
<div class="logo-placeholder"></div>
88
</div>
99
<div class="app-title-group">
1010
<span class="app-title">Klimamaterial</span>
1111
<span class="app-subtitle">Materialkatalog</span>
1212
</div>
13-
</div>
13+
</a>
1414
<NavMenu />
1515
</div>
1616
</header>

BauMat.Client/Layout/MainLayout.razor.css renamed to BauMat.Client/Components/Layout/MainLayout.razor.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,12 @@
6666
margin: 0 auto;
6767
padding: 2rem 1.5rem;
6868
}
69+
70+
.app-brand {
71+
color: inherit;
72+
text-decoration: none;
73+
}
74+
75+
.app-brand:hover {
76+
text-decoration: none;
77+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<nav class="app-nav">
2-
<NavLink href="/" Match="NavLinkMatch.All" class="app-nav-link">Katalog</NavLink>
2+
<NavLink href="/katalog" class="app-nav-link">Katalog</NavLink>
33
<NavLink href="/vergleich" class="app-nav-link">Vergleich</NavLink>
44
<NavLink href="/methodik" class="app-nav-link">Methodik</NavLink>
55
</nav>

BauMat.Client/Layout/NavMenu.razor.css renamed to BauMat.Client/Components/Layout/NavMenu.razor.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.app-nav {
22
display: flex;
3-
gap: 0.125rem;
3+
gap: 1rem;
44
align-items: center;
55
}
66

BauMat.Client/Data/.gitkeep

Whitespace-only changes.

BauMat.Client/Models/.gitkeep

Whitespace-only changes.

BauMat.Client/Pages/Catalog.razor

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
@page "/katalog"
2+
3+
<PageTitle>Klimamaterial – Katalog</PageTitle>
4+
5+
<div class="catalog-page">
6+
7+
<div class="catalog-header">
8+
<div class="catalog-header-left">
9+
<h2 class="catalog-title">Vergleich (@ComparedCount)</h2>
10+
<p class="catalog-subtitle">Böden · <strong>27 Materialien</strong></p>
11+
</div>
12+
<div class="catalog-header-right">
13+
<button class="btn-filter" @onclick="ToggleFilter">
14+
<svg width="15" height="15" viewBox="0 0 15 15" fill="none">
15+
<path d="M1 3h13M3 7h9M5 11h5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
16+
</svg>
17+
Filter
18+
</button>
19+
<div class="search-wrapper">
20+
<svg class="search-icon" width="15" height="15" viewBox="0 0 15 15" fill="none">
21+
<circle cx="6.5" cy="6.5" r="5" stroke="#9ca3af" stroke-width="1.4"/>
22+
<path d="M10.5 10.5 L13.5 13.5" stroke="#9ca3af" stroke-width="1.4" stroke-linecap="round"/>
23+
</svg>
24+
<input type="text"
25+
class="search-input"
26+
placeholder="Material suchen …"
27+
@bind="searchTerm"
28+
@bind:event="oninput" />
29+
</div>
30+
</div>
31+
</div>
32+
33+
@if (showFilter)
34+
{
35+
<div class="filter-panel">
36+
<p class="filter-hint">Filter-Optionen (Demonoch nicht aktiv)</p>
37+
<div class="filter-tags">
38+
<span class="filter-tag active">Alle</span>
39+
<span class="filter-tag">Unversiegelt</span>
40+
<span class="filter-tag">Begrünt</span>
41+
<span class="filter-tag">Teilversiegelt</span>
42+
<span class="filter-tag">Versiegelt</span>
43+
</div>
44+
</div>
45+
}
46+
47+
<div class="sort-bar">
48+
<span class="sort-label">Sortiert nach:</span>
49+
<span class="sort-value">Übereinstimmung mit Gewichtung</span>
50+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" class="sort-icon">
51+
<path d="M2 4l4 4 4-4" stroke="#6b7280" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
52+
</svg>
53+
</div>
54+
55+
<div class="table-wrapper">
56+
<table class="material-table">
57+
<thead>
58+
<tr>
59+
<th class="col-material">Material</th>
60+
<th class="col-rating">
61+
Kühlwirkung
62+
<small class="col-hint">1 = keine · 6 = stark</small>
63+
</th>
64+
<th class="col-rating">
65+
Albedo
66+
<small class="col-hint">1 = dunkel · 6 = hell</small>
67+
</th>
68+
<th class="col-rating">
69+
THG-Emission
70+
<small class="col-hint">1 = hoch · 6 = gering</small>
71+
</th>
72+
<th class="col-rating">
73+
Versickerung
74+
<small class="col-hint">1 = keine · 6 = hoch</small>
75+
</th>
76+
<th class="col-rating">
77+
Lebensdauer
78+
<small class="col-hint">1 = kurz · 6 = lang</small>
79+
</th>
80+
<th class="col-match">Übereinstimmung</th>
81+
<th class="col-action">Aktion</th>
82+
</tr>
83+
</thead>
84+
<tbody>
85+
@foreach (var m in FilteredMaterials)
86+
{
87+
<tr class="@(m.IsCompared ? "row-compared" : "")">
88+
<td class="cell-material">
89+
<span class="material-name">@m.Name</span>
90+
<span class="material-cat">@m.Kategorie</span>
91+
</td>
92+
<td class="cell-rating">@((MarkupString)RatingDots(m.Kuehlwirkung))</td>
93+
<td class="cell-rating">@((MarkupString)RatingDots(m.Albedo))</td>
94+
<td class="cell-rating">@((MarkupString)RatingDots(m.ThgEmission))</td>
95+
<td class="cell-rating">@((MarkupString)RatingDots(m.Versickerung))</td>
96+
<td class="cell-rating">@((MarkupString)RatingDots(m.Lebensdauer))</td>
97+
<td class="cell-match">
98+
<div class="match-score-row">
99+
<span class="match-points">@m.UebereinstimmungPunkte</span>
100+
<span class="match-max">/ @m.UebereinstimmungMax</span>
101+
</div>
102+
<div class="match-bar-track">
103+
<div class="match-bar-fill"
104+
style="width: @(m.UebereinstimmungPunkte * 100 / m.UebereinstimmungMax)%">
105+
</div>
106+
</div>
107+
</td>
108+
<td class="cell-action">
109+
<button class="compare-btn @(m.IsCompared ? "compared" : "")"
110+
@onclick="() => ToggleCompare(m)">
111+
@(m.IsCompared ? "✓ Im Vergleich" : "+ Vergleichen")
112+
</button>
113+
</td>
114+
</tr>
115+
}
116+
@if (!FilteredMaterials.Any())
117+
{
118+
<tr>
119+
<td colspan="8" class="no-results">
120+
Keine Materialien gefunden für@searchTerm"
121+
</td>
122+
</tr>
123+
}
124+
</tbody>
125+
</table>
126+
</div>
127+
128+
<div class="pagination">
129+
<button class="page-btn active">1</button>
130+
<button class="page-btn">2</button>
131+
<button class="page-btn">3</button>
132+
<span class="page-ellipsis">…</span>
133+
</div>
134+
135+
</div>
136+
137+
@code {
138+
private string searchTerm = "";
139+
private bool showFilter = false;
140+
141+
private int ComparedCount => Materials.Count(m => m.IsCompared);
142+
143+
private IEnumerable<MaterialItem> FilteredMaterials =>
144+
string.IsNullOrWhiteSpace(searchTerm)
145+
? Materials
146+
: Materials.Where(m =>
147+
m.Name.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) ||
148+
m.Kategorie.Contains(searchTerm, StringComparison.OrdinalIgnoreCase));
149+
150+
private void ToggleCompare(MaterialItem m) => m.IsCompared = !m.IsCompared;
151+
private void ToggleFilter() => showFilter = !showFilter;
152+
153+
private static string RatingDots(int value)
154+
{
155+
var sb = new System.Text.StringBuilder();
156+
sb.Append("<div class=\"rating-dots\">");
157+
for (int i = 1; i <= 6; i++)
158+
{
159+
sb.Append(i <= value
160+
? "<span class=\"dot dot-on\"></span>"
161+
: "<span class=\"dot dot-off\"></span>");
162+
}
163+
sb.Append("</div>");
164+
return sb.ToString();
165+
}
166+
167+
private readonly List<MaterialItem> Materials = new()
168+
{
169+
new() { Id = 1, Name = "Kiesbelag", Kategorie = "Boden · unversiegelt", Kuehlwirkung = 5, Albedo = 3, ThgEmission = 6, Versickerung = 6, Lebensdauer = 3, UebereinstimmungPunkte = 44, UebereinstimmungMax = 54 },
170+
new() { Id = 2, Name = "Rasen", Kategorie = "Boden · begrünt", Kuehlwirkung = 6, Albedo = 3, ThgEmission = 6, Versickerung = 3, Lebensdauer = 2, UebereinstimmungPunkte = 42, UebereinstimmungMax = 54 },
171+
new() { Id = 3, Name = "Rasengittersteinpflästerung", Kategorie = "Boden · teilversiegelt", Kuehlwirkung = 4, Albedo = 3, ThgEmission = 3, Versickerung = 5, Lebensdauer = 5, UebereinstimmungPunkte = 38, UebereinstimmungMax = 54 },
172+
new() { Id = 4, Name = "Steinplattenpflästerung", Kategorie = "Boden · versiegelt", Kuehlwirkung = 2, Albedo = 2, ThgEmission = 2, Versickerung = 1, Lebensdauer = 6, UebereinstimmungPunkte = 32, UebereinstimmungMax = 54 },
173+
new() { Id = 5, Name = "Asphalt dunkel", Kategorie = "Boden · versiegelt", Kuehlwirkung = 1, Albedo = 1, ThgEmission = 2, Versickerung = 1, Lebensdauer = 5, UebereinstimmungPunkte = 22, UebereinstimmungMax = 54 },
174+
new() { Id = 6, Name = "Betonbelag", Kategorie = "Boden · versiegelt", Kuehlwirkung = 2, Albedo = 3, ThgEmission = 2, Versickerung = 1, Lebensdauer = 6, UebereinstimmungPunkte = 28, UebereinstimmungMax = 54 },
175+
};
176+
177+
private record MaterialItem
178+
{
179+
public int Id { get; init; }
180+
public string Name { get; init; } = "";
181+
public string Kategorie { get; init; } = "";
182+
public int Kuehlwirkung { get; init; }
183+
public int Albedo { get; init; }
184+
public int ThgEmission { get; init; }
185+
public int Versickerung { get; init; }
186+
public int Lebensdauer { get; init; }
187+
public int UebereinstimmungPunkte { get; init; }
188+
public int UebereinstimmungMax { get; init; }
189+
public bool IsCompared { get; set; }
190+
}
191+
}

0 commit comments

Comments
 (0)