Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions EstateManagementUI.BlazorServer/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
wwwroot/css/app.css
package-lock.json
22 changes: 22 additions & 0 deletions EstateManagementUI.BlazorServer/Components/App.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en" class="h-full">

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/" />
<ResourcePreloader />
<link rel="stylesheet" href="css/app.css" />
<link rel="stylesheet" href="@Assets["EstateManagementUI.BlazorServer.styles.css"]" />
<ImportMap />
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet />
</head>

<body class="h-full">
<Routes />
<ReconnectModal />
<script src="@Assets["_framework/blazor.web.js"]"></script>
</body>

</html>
88 changes: 88 additions & 0 deletions EstateManagementUI.BlazorServer/Components/Layout/MainLayout.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
@inherits LayoutComponentBase

<div class="flex h-screen bg-gray-100">
<!-- Sidebar -->
<aside class="w-64 bg-gray-900 text-white flex-shrink-0 hidden md:block">
<div class="p-4">
<div class="flex items-center space-x-2 mb-6">
<span class="text-2xl font-bold">Estate Management</span>
</div>
<NavMenu />
</div>
</aside>

<!-- Main Content -->
<div class="flex-1 flex flex-col overflow-hidden">
<!-- Top Navigation Bar -->
<header class="bg-white shadow-sm border-b border-gray-200">
<div class="px-4 py-3 flex items-center justify-between">
<div class="flex items-center space-x-4">
<button class="md:hidden text-gray-600 hover:text-gray-900">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
</button>
<h1 class="text-xl font-semibold text-gray-800">@PageTitle</h1>
</div>

<div class="flex items-center space-x-4">
<!-- Notifications -->
<button class="text-gray-600 hover:text-gray-900">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"></path>
</svg>
</button>

<!-- User Profile Dropdown -->
<AuthorizeView>
<Authorized>
<div class="flex items-center space-x-2">
<span class="text-sm text-gray-700">@context.User.Identity?.Name</span>
<button class="flex items-center space-x-1 text-gray-600 hover:text-gray-900">
<svg class="w-8 h-8 rounded-full bg-gray-300" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path>
</svg>
</button>
</div>
</Authorized>
<NotAuthorized>
<a href="/login" class="btn btn-primary btn-sm">Login</a>
</NotAuthorized>
</AuthorizeView>
</div>
</div>
</header>

<!-- Page Content -->
<main class="flex-1 overflow-x-hidden overflow-y-auto bg-gray-100">
<div class="container mx-auto px-4 py-6">
@Body
</div>
</main>
</div>
</div>

<!-- Toast Notifications Area -->
<div id="toast-container" class="fixed bottom-4 right-4 z-50">
<!-- Toast messages will appear here -->
</div>

<div id="blazor-error-ui" class="fixed bottom-0 right-0 left-0 bg-red-600 text-white p-4 shadow-lg" data-nosnippet>
<div class="container mx-auto flex items-center justify-between">
<div class="flex items-center space-x-2">
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd"></path>
</svg>
<span>An unhandled error has occurred.</span>
</div>
<div class="flex items-center space-x-4">
<a href="." class="underline hover:no-underline">Reload</a>
<button class="dismiss text-white hover:text-gray-200">✕</button>
</div>
</div>
</div>

@code {
[CascadingParameter]
public string? PageTitle { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
.page {

Check warning on line 1 in EstateManagementUI.BlazorServer/Components/Layout/MainLayout.razor.css

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Components/Layout/MainLayout.razor.css#L1

Unknown rule scss_function-disallowed-list. Did you mean function-disallowed-list?
position: relative;
display: flex;
flex-direction: column;
}

main {
flex: 1;
}

.sidebar {
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
}

.top-row {
background-color: #f7f7f7;
border-bottom: 1px solid #d6d5d5;
justify-content: flex-end;
height: 3.5rem;
display: flex;
align-items: center;
}

.top-row ::deep a, .top-row ::deep .btn-link {
white-space: nowrap;
margin-left: 1.5rem;
text-decoration: none;
}

.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
text-decoration: underline;
}

.top-row ::deep a:first-child {
overflow: hidden;
text-overflow: ellipsis;
}

@media (max-width: 640.98px) {
.top-row {
justify-content: space-between;
}

.top-row ::deep a, .top-row ::deep .btn-link {
margin-left: 0;
}
}

@media (min-width: 641px) {
.page {
flex-direction: row;
}

.sidebar {
width: 250px;
height: 100vh;
position: sticky;
top: 0;
}

.top-row {
position: sticky;
top: 0;
z-index: 1;
}

.top-row.auth ::deep a:first-child {
flex: 1;
text-align: right;
width: 0;
}

.top-row, article {
padding-left: 2rem !important;
padding-right: 1.5rem !important;
}
}

#blazor-error-ui {
color-scheme: light only;
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
box-sizing: border-box;
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
}

#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
54 changes: 54 additions & 0 deletions EstateManagementUI.BlazorServer/Components/Layout/NavMenu.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<nav class="flex flex-col space-y-1">
<NavLink class="flex items-center space-x-3 px-4 py-2 rounded-md hover:bg-gray-800 transition-colors" href="" Match="NavLinkMatch.All">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path>
</svg>
<span>Dashboard</span>
</NavLink>

<NavLink class="flex items-center space-x-3 px-4 py-2 rounded-md hover:bg-gray-800 transition-colors" href="estate">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path>
</svg>
<span>Estate Management</span>
</NavLink>

<NavLink class="flex items-center space-x-3 px-4 py-2 rounded-md hover:bg-gray-800 transition-colors" href="merchants">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"></path>
</svg>
<span>Merchant Management</span>
</NavLink>

<NavLink class="flex items-center space-x-3 px-4 py-2 rounded-md hover:bg-gray-800 transition-colors" href="contracts">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
<span>Contract Management</span>
</NavLink>

<NavLink class="flex items-center space-x-3 px-4 py-2 rounded-md hover:bg-gray-800 transition-colors" href="operators">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"></path>
</svg>
<span>Operator Management</span>
</NavLink>

<NavLink class="flex items-center space-x-3 px-4 py-2 rounded-md hover:bg-gray-800 transition-colors" href="file-processing">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
</svg>
<span>File Processing</span>
</NavLink>
</nav>

@code {
private bool collapseNavMenu = true;

private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;

private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
105 changes: 105 additions & 0 deletions EstateManagementUI.BlazorServer/Components/Layout/NavMenu.razor.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
.navbar-toggler {

Check warning on line 1 in EstateManagementUI.BlazorServer/Components/Layout/NavMenu.razor.css

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Components/Layout/NavMenu.razor.css#L1

Unknown rule scss_function-disallowed-list. Did you mean function-disallowed-list?
appearance: none;
cursor: pointer;
width: 3.5rem;
height: 2.5rem;
color: white;
position: absolute;
top: 0.5rem;
right: 1rem;
border: 1px solid rgba(255, 255, 255, 0.1);
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
}

.navbar-toggler:checked {
background-color: rgba(255, 255, 255, 0.5);
}

.top-row {
min-height: 3.5rem;
background-color: rgba(0,0,0,0.4);
}

.navbar-brand {
font-size: 1.1rem;
}

.bi {
display: inline-block;
position: relative;
width: 1.25rem;
height: 1.25rem;
margin-right: 0.75rem;
top: -1px;
background-size: cover;
}

.bi-house-door-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
}

.bi-plus-square-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
}

.bi-list-nested-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
}

.nav-item {
font-size: 0.9rem;
padding-bottom: 0.5rem;
}

.nav-item:first-of-type {
padding-top: 1rem;
}

.nav-item:last-of-type {
padding-bottom: 1rem;
}

.nav-item ::deep .nav-link {
color: #d7d7d7;
background: none;
border: none;
border-radius: 4px;
height: 3rem;
display: flex;
align-items: center;
line-height: 3rem;
width: 100%;
}

.nav-item ::deep a.active {
background-color: rgba(255,255,255,0.37);
color: white;
}

.nav-item ::deep .nav-link:hover {
background-color: rgba(255,255,255,0.1);
color: white;
}

.nav-scrollable {
display: none;
}

.navbar-toggler:checked ~ .nav-scrollable {
display: block;
}

@media (min-width: 641px) {
.navbar-toggler {
display: none;
}

.nav-scrollable {
/* Never collapse the sidebar for wide screens */
display: block;

/* Allow sidebar to scroll for tall menus */
height: calc(100vh - 3.5rem);
overflow-y: auto;
}
}
Loading