feat: Complete Woles Framework v1.0 with enterprise-grade UI

- Add comprehensive error handling system with custom error pages
- Implement professional enterprise-style design with Tailwind CSS
- Create modular HMVC architecture with clean separation of concerns
- Add security features: CSRF protection, XSS filtering, Argon2ID hashing
- Include CLI tools for development workflow
- Add error reporting dashboard with system monitoring
- Implement responsive design with consistent slate color scheme
- Replace all emoji icons with professional SVG icons
- Add comprehensive test suite with PHPUnit
- Include database migrations and seeders
- Add proper exception handling with fallback pages
- Implement template engine with custom syntax support
- Add helper functions and facades for clean code
- Include proper logging and debugging capabilities
This commit is contained in:
mwpn
2025-10-11 07:08:23 +07:00
commit 0b42271bfe
90 changed files with 8315 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }}</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
'sans': ['Inter', 'system-ui', 'sans-serif'],
}
}
}
}
</script>
</head>
<body class="font-sans bg-gray-50 min-h-screen">
<!-- Header -->
<header class="bg-white shadow-sm border-b border-gray-200">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center h-16">
<div class="flex items-center">
<div class="text-2xl mr-3"></div>
<h1 class="text-xl font-bold text-gray-900">Woles Framework</h1>
</div>
<nav class="flex space-x-4">
<a href="/dashboard" class="text-gray-600 hover:text-gray-900 px-3 py-2 rounded-md text-sm font-medium transition-colors">Dashboard</a>
<a href="/users" class="text-blue-600 hover:text-blue-700 px-3 py-2 rounded-md text-sm font-medium transition-colors">Users</a>
<a href="/logout" class="text-red-600 hover:text-red-700 px-3 py-2 rounded-md text-sm font-medium transition-colors">Logout</a>
</nav>
</div>
</div>
</header>
<!-- Main Content -->
<main class="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<!-- Page Header -->
<div class="mb-8">
<h2 class="text-3xl font-bold text-gray-900 mb-2">Create New User</h2>
<p class="text-gray-600">Add a new user to the system</p>
</div>
<!-- Form Card -->
<div class="bg-white shadow-sm rounded-xl border border-gray-200 p-8">
<form method="POST" action="/users" class="space-y-6">
@csrf
<div>
<label for="name" class="block text-sm font-medium text-gray-700 mb-2">
Full Name
</label>
<input
type="text"
id="name"
name="name"
value="{{ old('name', $old['name'] ?? '') }}"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors"
placeholder="Enter full name"
required>
@if (isset($errors['name']))
<p class="mt-2 text-sm text-red-600">{{ $errors['name'] }}</p>
@endif
</div>
<div>
<label for="email" class="block text-sm font-medium text-gray-700 mb-2">
Email Address
</label>
<input
type="email"
id="email"
name="email"
value="{{ old('email', $old['email'] ?? '') }}"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors"
placeholder="Enter email address"
required>
@if (isset($errors['email']))
<p class="mt-2 text-sm text-red-600">{{ $errors['email'] }}</p>
@endif
</div>
<div>
<label for="password" class="block text-sm font-medium text-gray-700 mb-2">
Password
</label>
<input
type="password"
id="password"
name="password"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors"
placeholder="Enter password"
required>
@if (isset($errors['password']))
<p class="mt-2 text-sm text-red-600">{{ $errors['password'] }}</p>
@endif
</div>
<div class="flex space-x-4 pt-4">
<button
type="submit"
class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
Create User
</button>
<a href="/users" class="bg-gray-600 hover:bg-gray-700 text-white px-6 py-3 rounded-lg font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2">
Cancel
</a>
</div>
</form>
</div>
</main>
</body>
</html>

View File

@@ -0,0 +1,203 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }}</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f8f9fa;
color: #333;
}
.header {
background: white;
padding: 1rem 2rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
display: flex;
justify-content: space-between;
align-items: center;
}
.header h1 {
color: #667eea;
font-size: 1.5rem;
}
.nav-links {
display: flex;
gap: 1rem;
}
.nav-links a {
color: #667eea;
text-decoration: none;
padding: 0.5rem 1rem;
border-radius: 5px;
transition: background-color 0.3s ease;
}
.nav-links a:hover {
background: #f0f0f0;
}
.container {
max-width: 800px;
margin: 2rem auto;
padding: 0 2rem;
}
.page-header {
margin-bottom: 2rem;
}
.page-header h2 {
color: #333;
font-size: 1.8rem;
margin-bottom: 0.5rem;
}
.page-header p {
color: #666;
}
.card {
background: white;
padding: 2rem;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
color: #333;
font-weight: 500;
}
.form-group input {
width: 100%;
padding: 0.75rem;
border: 2px solid #e1e5e9;
border-radius: 5px;
font-size: 1rem;
transition: border-color 0.3s ease;
}
.form-group input:focus {
outline: none;
border-color: #667eea;
}
.field-error {
color: #dc3545;
font-size: 0.85rem;
margin-top: 0.25rem;
}
.btn {
background: #667eea;
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 5px;
text-decoration: none;
font-weight: 500;
transition: background-color 0.3s ease;
display: inline-block;
cursor: pointer;
}
.btn:hover {
background: #5a6fd8;
}
.btn-secondary {
background: #6c757d;
margin-left: 0.5rem;
}
.btn-secondary:hover {
background: #5a6268;
}
</style>
</head>
<body>
<div class="header">
<h1>NovaCore Framework</h1>
<div class="nav-links">
<a href="/dashboard">Dashboard</a>
<a href="/users">Users</a>
<a href="/logout">Logout</a>
</div>
</div>
<div class="container">
<div class="page-header">
<h2>Edit User</h2>
<p>Update user information</p>
</div>
<div class="card">
<form method="POST" action="/users/{{ $user['id'] }}">
@csrf
@method('PUT')
<div class="form-group">
<label for="name">Full Name</label>
<input
type="text"
id="name"
name="name"
value="{{ $user['name'] }}"
required>
@if (isset($errors['name']))
<div class="field-error">{{ $errors['name'] }}</div>
@endif
</div>
<div class="form-group">
<label for="email">Email Address</label>
<input
type="email"
id="email"
name="email"
value="{{ $user['email'] }}"
required>
@if (isset($errors['email']))
<div class="field-error">{{ $errors['email'] }}</div>
@endif
</div>
<div class="form-group">
<label for="password">New Password (leave blank to keep current)</label>
<input
type="password"
id="password"
name="password">
@if (isset($errors['password']))
<div class="field-error">{{ $errors['password'] }}</div>
@endif
</div>
<button type="submit" class="btn">Update User</button>
<a href="/users/{{ $user['id'] }}" class="btn btn-secondary">Cancel</a>
</form>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }}</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
'sans': ['Inter', 'system-ui', 'sans-serif'],
}
}
}
}
</script>
</head>
<body class="font-sans bg-gray-50 min-h-screen">
<!-- Header -->
<header class="bg-white shadow-sm border-b border-gray-200">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center h-16">
<div class="flex items-center">
<div class="text-2xl mr-3"></div>
<h1 class="text-xl font-bold text-gray-900">Woles Framework</h1>
</div>
<nav class="flex space-x-4">
<a href="/dashboard" class="text-gray-600 hover:text-gray-900 px-3 py-2 rounded-md text-sm font-medium transition-colors">Dashboard</a>
<a href="/users" class="text-blue-600 hover:text-blue-700 px-3 py-2 rounded-md text-sm font-medium transition-colors">Users</a>
<a href="/logout" class="text-red-600 hover:text-red-700 px-3 py-2 rounded-md text-sm font-medium transition-colors">Logout</a>
</nav>
</div>
</div>
</header>
<!-- Main Content -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<!-- Page Header -->
<div class="flex justify-between items-center mb-8">
<h2 class="text-3xl font-bold text-gray-900">Users Management</h2>
<a href="/users/create" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg font-medium transition-colors">
Add New User
</a>
</div>
<!-- Users Table -->
<div class="bg-white shadow-sm rounded-xl border border-gray-200 overflow-hidden">
@if (empty($users))
<div class="text-center py-12">
<div class="text-6xl mb-4">👥</div>
<h3 class="text-xl font-semibold text-gray-900 mb-2">No users found</h3>
<p class="text-gray-600 mb-6">Get started by creating your first user.</p>
<a href="/users/create" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg font-medium transition-colors">
Create User
</a>
</div>
@else
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Created At</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
@foreach ($users as $user)
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{ $user['id'] }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $user['name'] }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ $user['email'] }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ date('M j, Y', strtotime($user['created_at'])) }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<div class="flex space-x-2">
<a href="/users/{{ $user['id'] }}" class="text-blue-600 hover:text-blue-700 bg-blue-50 hover:bg-blue-100 px-3 py-1 rounded-md text-xs font-medium transition-colors">
View
</a>
<a href="/users/{{ $user['id'] }}/edit" class="text-green-600 hover:text-green-700 bg-green-50 hover:bg-green-100 px-3 py-1 rounded-md text-xs font-medium transition-colors">
Edit
</a>
<form method="POST" action="/users/{{ $user['id'] }}" class="inline">
@csrf
@method('DELETE')
<button type="submit"
class="text-red-600 hover:text-red-700 bg-red-50 hover:bg-red-100 px-3 py-1 rounded-md text-xs font-medium transition-colors"
onclick="return confirm('Are you sure you want to delete this user?')">
Delete
</button>
</form>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
</div>
</main>
</body>
</html>

View File

@@ -0,0 +1,202 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }}</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f8f9fa;
color: #333;
}
.header {
background: white;
padding: 1rem 2rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
display: flex;
justify-content: space-between;
align-items: center;
}
.header h1 {
color: #667eea;
font-size: 1.5rem;
}
.nav-links {
display: flex;
gap: 1rem;
}
.nav-links a {
color: #667eea;
text-decoration: none;
padding: 0.5rem 1rem;
border-radius: 5px;
transition: background-color 0.3s ease;
}
.nav-links a:hover {
background: #f0f0f0;
}
.container {
max-width: 800px;
margin: 2rem auto;
padding: 0 2rem;
}
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.page-header h2 {
color: #333;
font-size: 1.8rem;
}
.btn {
background: #667eea;
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 5px;
text-decoration: none;
font-weight: 500;
transition: background-color 0.3s ease;
display: inline-block;
}
.btn:hover {
background: #5a6fd8;
}
.btn-danger {
background: #dc3545;
}
.btn-danger:hover {
background: #c82333;
}
.btn-secondary {
background: #6c757d;
margin-right: 0.5rem;
}
.btn-secondary:hover {
background: #5a6268;
}
.card {
background: white;
padding: 2rem;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.user-info {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
}
.info-item {
padding: 1rem;
background: #f8f9fa;
border-radius: 5px;
}
.info-label {
font-weight: 600;
color: #495057;
margin-bottom: 0.5rem;
}
.info-value {
color: #333;
font-size: 1.1rem;
}
.actions {
margin-top: 2rem;
padding-top: 2rem;
border-top: 1px solid #e9ecef;
}
</style>
</head>
<body>
<div class="header">
<h1>NovaCore Framework</h1>
<div class="nav-links">
<a href="/dashboard">Dashboard</a>
<a href="/users">Users</a>
<a href="/logout">Logout</a>
</div>
</div>
<div class="container">
<div class="page-header">
<h2>User Details</h2>
<div>
<a href="/users/{{ $user['id'] }}/edit" class="btn btn-secondary">Edit User</a>
<a href="/users" class="btn">Back to Users</a>
</div>
</div>
<div class="card">
<div class="user-info">
<div class="info-item">
<div class="info-label">ID</div>
<div class="info-value">{{ $user['id'] }}</div>
</div>
<div class="info-item">
<div class="info-label">Name</div>
<div class="info-value">{{ $user['name'] }}</div>
</div>
<div class="info-item">
<div class="info-label">Email</div>
<div class="info-value">{{ $user['email'] }}</div>
</div>
<div class="info-item">
<div class="info-label">Created At</div>
<div class="info-value">{{ date('M j, Y g:i A', strtotime($user['created_at'])) }}</div>
</div>
<div class="info-item">
<div class="info-label">Updated At</div>
<div class="info-value">{{ date('M j, Y g:i A', strtotime($user['updated_at'])) }}</div>
</div>
</div>
<div class="actions">
<form method="POST" action="/users/{{ $user['id'] }}" style="display: inline;">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger"
onclick="return confirm('Are you sure you want to delete this user?')">
Delete User
</button>
</form>
</div>
</div>
</div>
</body>
</html>