Add Soft UI

master
sundayenglish 4 weeks ago
parent 1a138e86dc
commit 1f0c97794e
  1. 5
      README.md
  2. 40
      app/Http/Controllers/Auth/LoginController.php
  3. 2
      app/Livewire/Auth/Login.php
  4. 13
      app/Livewire/Dashboard.php
  5. 58
      resources/views/auth/login.blade.php
  6. 48
      resources/views/layouts/app.blade.php
  7. 38
      resources/views/layouts/auth.blade.php
  8. 22
      resources/views/layouts/partials/navbar.blade.php
  9. 20
      resources/views/layouts/partials/sidebar.blade.php
  10. 45
      resources/views/livewire/auth/login.blade.php
  11. 5
      resources/views/livewire/dashboard.blade.php
  12. 20
      routes/web.php
  13. 13
      vite.config.js

@ -1,6 +1,9 @@
# Laravel 12 - Content Management Project (Dockerized)
This project is a content management system (CMS) built with **Laravel 12**, running in a development environment powered by **Docker + Docker Compose**.
This project is a content management system (CMS) built with **Laravel 12**, running in a development environment powered by **Docker + Docker Compose** It integrates modern Laravel tools including:
- **Livewire** – For building reactive components using Blade.
- **Passport** – Provides API authentication using OAuth2.
- **Vite** – Bundles and hot-reloads frontend assets efficiently.
---
---

@ -0,0 +1,40 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
public function showLoginForm()
{
return view('auth.login');
}
public function login(Request $request)
{
$data = $request->validate([
'email' => ['required','email'],
'password' => ['required','string'],
]);
if (Auth::attempt($data, $request->boolean('remember'))) {
$request->session()->regenerate();
return redirect()->intended(route('dashboard'));
}
return back()
->withErrors(['email' => 'Email hoặc mật khẩu không đúng.'])
->withInput(['email' => $request->email]);
}
public function logout(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->route('login');
}
}

@ -30,6 +30,6 @@ class Login extends Component
public function render()
{
return view('livewire.auth.login')->layout('layouts.app');
return view('auth.login')->layout('layouts.auth');
}
}

@ -0,0 +1,13 @@
<?php
namespace App\Livewire;
use Livewire\Component;
class Dashboard extends Component
{
public function render()
{
return view('livewire.dashboard')->layout('layouts.app', ['title' => 'Dashboard']);
}
}

@ -0,0 +1,58 @@
@extends('layouts.auth')
@section('title','Đăng nhập hệ thống')
@section('content')
<div class="row">
<div class="col-lg-4 col-md-6 col-sm-8 mx-auto">
<div class="card card-body mt-4 shadow-lg">
<h4 class="text-center mb-4">Đăng nhập</h4>
<form method="POST" action="{{ route('login') }}">
@csrf
{{-- Email --}}
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input id="email" type="email" name="email"
class="form-control @error('email') is-invalid @enderror"
value="{{ old('email') }}" required autofocus>
@error('email')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
{{-- Password --}}
<div class="mb-3">
<label for="password" class="form-label">Mật khẩu</label>
<input id="password" type="password" name="password"
class="form-control @error('password') is-invalid @enderror"
required>
@error('password')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
{{-- Remember --}}
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" name="remember" id="remember">
<label class="form-check-label" for="remember">Ghi nhớ đăng nhập</label>
</div>
{{-- Submit --}}
<div class="d-grid">
<button type="submit" class="btn btn-primary">
Đăng nhập
</button>
</div>
{{-- Forgot Password --}}
@if(Route::has('password.request'))
<p class="text-center text-sm mt-3">
<a href="{{ route('password.request') }}">Quên mật khẩu?</a>
</p>
@endif
</form>
</div>
</div>
</div>
@endsection

@ -1,21 +1,51 @@
{{-- resources/views/layouts/soft-ui.blade.php --}}
<!DOCTYPE html>
<html lang="vi">
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Đăng nhập hệ thống</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet" />
@vite('resources/css/app.css')
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>@yield('title', 'Dashboard')</title>
{{-- 1. Soft UI CSS --}}
<link rel="stylesheet" href="{{ asset('soft-ui/assets/css/soft-ui-dashboard.css') }}" />
{{-- 2. Google fonts / Icons (nếu cần) --}}
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Round" rel="stylesheet" />
{{-- 3. Livewire --}}
@livewireStyles
{{-- 4. CSS bổ sung --}}
@stack('css')
</head>
<body class="font-sans antialiased bg-cover bg-center" style="background-image: url('{{ asset('images/logo.png') }}')">
<div class="min-h-screen flex items-center justify-center bg-gray-900 bg-opacity-50">
{{ $slot }}
<body class="g-sidenav-show bg-gray-100">
{{-- Ảnh nền header (tùy chọn) --}}
<div class="min-height-300 bg-primary position-absolute w-100"></div>
{{-- Sidebar --}}
@include('layouts.partials.sidebar')
<main class="main-content position-relative max-height-vh-100 h-100 border-radius-lg">
{{-- Navbar --}}
@include('layouts.partials.navbar')
{{-- Nội dung chính --}}
<div class="container-fluid py-4">
@yield('content')
</div>
</main>
{{-- 5. Core JS bundle (đã gồm Popper & Bootstrap) --}}
<script src="{{ asset('soft-ui/assets/js/soft-ui-dashboard.min.js') }}"></script>
{{-- 6. Livewire --}}
@livewireScripts
{{-- 7. JS bổ sung --}}
@stack('js')
</body>
</html>

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>@yield('title','Auth')</title>
{{-- Soft UI CSS --}}
<link rel="stylesheet" href="{{ asset('soft-ui/assets/css/soft-ui-dashboard.css') }}"/>
{{-- Livewire Styles --}}
@livewireStyles
{{-- CSS bổ sung --}}
@stack('css')
</head>
<body class="bg-gray-100">
<section class="min-vh-100 d-flex align-items-center justify-content-center">
<div class="container">
@yield('content')
</div>
</section>
{{-- Core JS --}}
<script src="{{ asset('soft-ui/assets/js/core/popper.min.js') }}"></script>
<script src="{{ asset('soft-ui/assets/js/core/bootstrap.min.js') }}"></script>
<script src="{{ asset('soft-ui/assets/js/plugins/perfect-scrollbar.min.js') }}"></script>
<script src="{{ asset('soft-ui/assets/js/plugins/smooth-scrollbar.min.js') }}"></script>
<script src="{{ asset('soft-ui/assets/js/soft-ui-dashboard.min.js') }}"></script>
{{-- Livewire Scripts --}}
@livewireScripts
{{-- JS bổ sung --}}
@stack('js')
</body>
</html>

@ -0,0 +1,22 @@
{{-- resources/views/layouts/partials/navbar-soft-ui.blade.php --}}
<nav class="navbar navbar-main navbar-expand-lg px-0 mx-4 shadow-none border-radius-xl">
<div class="container-fluid py-1 px-3">
<nav aria-label="breadcrumb">
<ol class="breadcrumb bg-transparent mb-0 pb-0 pt-1 px-0 me-sm-6 me-5">
<li class="breadcrumb-item text-sm"><a class="opacity-5 text-dark" href="#">Pages</a></li>
<li class="breadcrumb-item text-sm text-dark active" aria-current="page">@yield('title')</li>
</ol>
<h6 class="font-weight-bolder mb-0">@yield('title')</h6>
</nav>
<ul class="navbar-nav justify-content-end ms-auto">
<li class="nav-item d-flex align-items-center">
<form method="POST" action="{{ route('logout') }}">
@csrf
<button type="submit" class="btn btn-link text-dark">
<i class="material-icons-round">logout</i> Đăng xuất
</button>
</form>
</li>
</ul>
</div>
</nav>

@ -0,0 +1,20 @@
{{-- resources/views/layouts/partials/sidebar-soft-ui.blade.php --}}
<aside class="sidenav navbar navbar-vertical navbar-expand-xs border-0 border-radius-xl my-3 fixed-start ms-3">
<div class="sidenav-header">
<a class="navbar-brand" href="{{ route('dashboard') }}">
<img src="{{ asset('images/logo.png') }}" class="navbar-brand-img" alt="logo">
<span class="ms-1 font-weight-bold">My App</span>
</a>
</div>
<hr class="horizontal dark mt-0 mb-2">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link {{ request()->routeIs('dashboard') ? 'active' : '' }}"
href="{{ route('dashboard') }}">
<i class="material-icons-round">dashboard</i>
<span class="nav-link-text ms-2">Dashboard</span>
</a>
</li>
{{-- các mục khác… --}}
</ul>
</aside>

@ -1,45 +0,0 @@
<div class="max-w-md w-full bg-white shadow-xl rounded-lg p-8 relative z-10">
<div class="flex justify-center mb-4">
<img src="{{ asset('images/logo.png') }}" alt="Logo" class="h-16 w-auto">
</div>
<h2 class="text-2xl font-semibold text-center text-gray-900 mb-6">Đăng nhập hệ thống</h2>
<form wire:submit.prevent="login" class="space-y-4">
<!-- Email -->
<div>
<label class="block text-sm font-medium text-gray-700">Email:</label>
<input type="email" wire:model="email" required
class="mt-1 block w-full rounded-md border border-gray-300 shadow-sm py-2 px-3
focus:ring-indigo-500 focus:border-indigo-500">
@error('email')
<div class="text-red-500 text-sm">{{ $message }}</div>
@enderror
</div>
<!-- Password -->
<div>
<label class="block text-sm font-medium text-gray-700">Mật khẩu:</label>
<input type="password" wire:model="password" required
class="mt-1 block w-full rounded-md border border-gray-300 shadow-sm py-2 px-3
focus:ring-indigo-500 focus:border-indigo-500">
@error('password')
<div class="text-red-500 text-sm">{{ $message }}</div>
@enderror
</div>
<!-- Remember -->
<div class="flex items-center">
<input type="checkbox" wire:model="remember" id="remember"
class="h-4 w-4 bg-red-500 border-gray-300 rounded">
<label for="remember" class="ml-2 text-sm text-gray-900">Ghi nhớ đăng nhập</label>
</div>
<!-- Button -->
<button type="submit"
class="block w-full py-3 bg-indigo-600 text-white font-medium rounded hover:bg-indigo-700
transition duration-200">
Đăng nhập
</button>
</form>
</div>

@ -0,0 +1,5 @@
<div class="row">
<div class="col-12">
<h3>Xin chào, {{ auth()->user()->name }}!</h3>
</div>
</div>

@ -1,9 +1,19 @@
<?php
use App\Http\Controllers\Auth\LoginController;
use Illuminate\Support\Facades\Route;
use App\Livewire\Auth\Login;
use App\Livewire\Dashboard;
Route::get('/', function () {
return view('welcome');
});
Route::get('/login', Login::class)->name('login')->middleware('guest');
// Form đăng nhập, chỉ cho guest
Route::get('login', [LoginController::class, 'showLoginForm'])
->middleware('guest')
->name('login');
Route::post('login', [LoginController::class, 'login'])
->middleware('guest');
Route::post('logout', [LoginController::class, 'logout'])
->middleware('auth')
->name('logout');
Route::get('dashboard', Dashboard::class)
->name('dashboard')
->middleware(['auth']);

@ -1,13 +1,18 @@
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import tailwindcss from '@tailwindcss/vite';
import { defineConfig } from "vite";
import laravel from "laravel-vite-plugin";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
input: ["resources/css/app.css", "resources/js/app.js"],
refresh: true,
}),
tailwindcss(),
],
server: {
fs: {
allow: [".", "public/soft-ui/assets"],
},
},
});

Loading…
Cancel
Save