Compare commits
12 Commits
74f5d3599a
...
f6014a55e4
| Author | SHA1 | Date | |
|---|---|---|---|
| f6014a55e4 | |||
| 9fb7432694 | |||
| 9ddfe62a56 | |||
| e04b92493b | |||
| c03944faef | |||
| 219316e84c | |||
| 4247da403a | |||
| 88d4720af5 | |||
| 6b08d236a9 | |||
| a90b2931ff | |||
| e5c8080355 | |||
| 4f191c5af2 |
402
app/UsersManager.class.php
Normal file
402
app/UsersManager.class.php
Normal file
@@ -0,0 +1,402 @@
|
||||
<?php
|
||||
/**
|
||||
* UserManager - Gestione utenti e autenticazione tramite cookie
|
||||
* PHP 8+ con MariaDB
|
||||
*/
|
||||
|
||||
class UserManager {
|
||||
private PDO $db;
|
||||
private string $cookieName = 'auth_token';
|
||||
private int $cookieLifetime = 2592000; // 30 giorni in secondi
|
||||
private int $maxLoginAttempts = 5;
|
||||
private int $lockoutTime = 900; // 15 minuti in secondi
|
||||
|
||||
public function __construct(PDO $db) {
|
||||
$this->db = $db;
|
||||
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registra un nuovo utente
|
||||
*/
|
||||
public function register(string $username, string $email, string $password, string $fullName = null): bool {
|
||||
try {
|
||||
$passwordHash = password_hash($password, PASSWORD_ARGON2ID);
|
||||
|
||||
$stmt = $this->db->prepare("
|
||||
INSERT INTO users (username, email, password_hash, full_name)
|
||||
VALUES (:username, :email, :password_hash, :full_name)
|
||||
");
|
||||
|
||||
$result = $stmt->execute([
|
||||
'username' => $username,
|
||||
'email' => $email,
|
||||
'password_hash' => $passwordHash,
|
||||
'full_name' => $fullName
|
||||
]);
|
||||
|
||||
if ($result) {
|
||||
$userId = $this->db->lastInsertId();
|
||||
$this->logActivity($userId, $username, 'REGISTER', "Nuovo utente registrato: $username");
|
||||
}
|
||||
|
||||
return $result;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Errore registrazione: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Login utente con username/email e password
|
||||
*/
|
||||
public function login(string $identifier, string $password, bool $rememberMe = true): array {
|
||||
// Verifica blocco per troppi tentativi
|
||||
if ($this->isAccountLocked($identifier)) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Account temporaneamente bloccato per troppi tentativi falliti'
|
||||
];
|
||||
}
|
||||
|
||||
// Cerca utente per username o email
|
||||
$stmt = $this->db->prepare("
|
||||
SELECT id, username, email, password_hash, is_active, full_name
|
||||
FROM users
|
||||
WHERE (username = :identifier OR email = :identifier) AND is_active = 1
|
||||
");
|
||||
$stmt->execute(['identifier' => $identifier]);
|
||||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$user || !password_verify($password, $user['password_hash'])) {
|
||||
$this->logFailedAttempt($identifier);
|
||||
$this->logActivity(null, $identifier, 'LOGIN_FAILED', "Tentativo di login fallito");
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Credenziali non valide'
|
||||
];
|
||||
}
|
||||
|
||||
// Login riuscito - pulisce tentativi falliti
|
||||
$this->clearFailedAttempts($identifier);
|
||||
|
||||
// Aggiorna last_login
|
||||
$stmt = $this->db->prepare("UPDATE users SET last_login = NOW() WHERE id = :id");
|
||||
$stmt->execute(['id' => $user['id']]);
|
||||
|
||||
// Crea token di autenticazione se richiesto
|
||||
if ($rememberMe) {
|
||||
$this->createAuthToken($user['id']);
|
||||
}
|
||||
|
||||
// Salva in sessione dati base
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['full_name'] = $user['full_name'];
|
||||
|
||||
$this->logActivity($user['id'], $user['username'], 'LOGIN', "Login effettuato");
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'user' => [
|
||||
'id' => $user['id'],
|
||||
'username' => $user['username'],
|
||||
'email' => $user['email'],
|
||||
'full_name' => $user['full_name']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-autenticazione con solo password (quando cookie è scaduto ma username è memorizzato)
|
||||
*/
|
||||
public function reAuthenticate(string $username, string $password): array {
|
||||
return $this->login($username, $password, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifica validità sessione/cookie
|
||||
*/
|
||||
public function checkAuth(): ?array {
|
||||
// Prima controlla se esiste sessione attiva
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
return $this->getUserById($_SESSION['user_id']);
|
||||
}
|
||||
|
||||
// Altrimenti verifica cookie
|
||||
if (isset($_COOKIE[$this->cookieName])) {
|
||||
return $this->validateAuthToken($_COOKIE[$this->cookieName]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea token di autenticazione e imposta cookie
|
||||
*/
|
||||
private function createAuthToken(int $userId): bool {
|
||||
try {
|
||||
// Genera selector e token casuali
|
||||
$selector = bin2hex(random_bytes(16));
|
||||
$token = bin2hex(random_bytes(32));
|
||||
$tokenHash = hash('sha256', $token);
|
||||
|
||||
$expiresAt = date('Y-m-d H:i:s', time() + $this->cookieLifetime);
|
||||
|
||||
// Salva nel database
|
||||
$stmt = $this->db->prepare("
|
||||
INSERT INTO auth_tokens (user_id, token, selector, expires_at, ip_address, user_agent)
|
||||
VALUES (:user_id, :token, :selector, :expires_at, :ip, :ua)
|
||||
");
|
||||
|
||||
$stmt->execute([
|
||||
'user_id' => $userId,
|
||||
'token' => $tokenHash,
|
||||
'selector' => $selector,
|
||||
'expires_at' => $expiresAt,
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? null,
|
||||
'ua' => $_SERVER['HTTP_USER_AGENT'] ?? null
|
||||
]);
|
||||
|
||||
// Imposta cookie (selector:token)
|
||||
$cookieValue = $selector . ':' . $token;
|
||||
setcookie(
|
||||
$this->cookieName,
|
||||
$cookieValue,
|
||||
time() + $this->cookieLifetime,
|
||||
'/',
|
||||
'',
|
||||
true, // Secure (solo HTTPS in produzione)
|
||||
true // HttpOnly
|
||||
);
|
||||
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
error_log("Errore creazione token: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Valida token di autenticazione dal cookie
|
||||
*/
|
||||
private function validateAuthToken(string $cookieValue): ?array {
|
||||
try {
|
||||
$parts = explode(':', $cookieValue);
|
||||
if (count($parts) !== 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
[$selector, $token] = $parts;
|
||||
$tokenHash = hash('sha256', $token);
|
||||
|
||||
// Cerca token nel database
|
||||
$stmt = $this->db->prepare("
|
||||
SELECT at.*, u.id, u.username, u.email, u.full_name, u.is_active
|
||||
FROM auth_tokens at
|
||||
JOIN users u ON at.user_id = u.id
|
||||
WHERE at.selector = :selector AND at.expires_at > NOW() AND u.is_active = 1
|
||||
");
|
||||
$stmt->execute(['selector' => $selector]);
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$result || !hash_equals($result['token'], $tokenHash)) {
|
||||
$this->deleteAuthToken($selector);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Token valido - rigenera sessione
|
||||
$_SESSION['user_id'] = $result['id'];
|
||||
$_SESSION['username'] = $result['username'];
|
||||
$_SESSION['full_name'] = $result['full_name'];
|
||||
|
||||
// Aggiorna last_login
|
||||
$stmt = $this->db->prepare("UPDATE users SET last_login = NOW() WHERE id = :id");
|
||||
$stmt->execute(['id' => $result['id']]);
|
||||
|
||||
$this->logActivity($result['id'], $result['username'], 'AUTO_LOGIN', "Login automatico via cookie");
|
||||
|
||||
return [
|
||||
'id' => $result['id'],
|
||||
'username' => $result['username'],
|
||||
'email' => $result['email'],
|
||||
'full_name' => $result['full_name']
|
||||
];
|
||||
} catch (Exception $e) {
|
||||
error_log("Errore validazione token: " . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout - elimina sessione e cookie
|
||||
*/
|
||||
public function logout(): void {
|
||||
$userId = $_SESSION['user_id'] ?? null;
|
||||
$username = $_SESSION['username'] ?? 'unknown';
|
||||
|
||||
// Elimina token dal database se presente
|
||||
if (isset($_COOKIE[$this->cookieName])) {
|
||||
$parts = explode(':', $_COOKIE[$this->cookieName]);
|
||||
if (count($parts) === 2) {
|
||||
$this->deleteAuthToken($parts[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Elimina cookie
|
||||
setcookie($this->cookieName, '', time() - 3600, '/', '', true, true);
|
||||
|
||||
// Distrugge sessione
|
||||
session_unset();
|
||||
session_destroy();
|
||||
|
||||
if ($userId) {
|
||||
$this->logActivity($userId, $username, 'LOGOUT', "Logout effettuato");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Elimina token dal database
|
||||
*/
|
||||
private function deleteAuthToken(string $selector): void {
|
||||
try {
|
||||
$stmt = $this->db->prepare("DELETE FROM auth_tokens WHERE selector = :selector");
|
||||
$stmt->execute(['selector' => $selector]);
|
||||
} catch (Exception $e) {
|
||||
error_log("Errore eliminazione token: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottiene utente per ID
|
||||
*/
|
||||
public function getUserById(int $userId): ?array {
|
||||
$stmt = $this->db->prepare("
|
||||
SELECT id, username, email, full_name, is_active, created_at, last_login
|
||||
FROM users WHERE id = :id AND is_active = 1
|
||||
");
|
||||
$stmt->execute(['id' => $userId]);
|
||||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
return $user ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifica se account è bloccato per troppi tentativi
|
||||
*/
|
||||
private function isAccountLocked(string $identifier): bool {
|
||||
$stmt = $this->db->prepare("
|
||||
SELECT COUNT(*) as attempts
|
||||
FROM failed_login_attempts
|
||||
WHERE username = :identifier
|
||||
AND ip_address = :ip
|
||||
AND attempted_at > DATE_SUB(NOW(), INTERVAL :lockout SECOND)
|
||||
");
|
||||
$stmt->execute([
|
||||
'identifier' => $identifier,
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
|
||||
'lockout' => $this->lockoutTime
|
||||
]);
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
return $result['attempts'] >= $this->maxLoginAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registra tentativo di login fallito
|
||||
*/
|
||||
private function logFailedAttempt(string $identifier): void {
|
||||
try {
|
||||
$stmt = $this->db->prepare("
|
||||
INSERT INTO failed_login_attempts (username, ip_address)
|
||||
VALUES (:username, :ip)
|
||||
");
|
||||
$stmt->execute([
|
||||
'username' => $identifier,
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? ''
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
error_log("Errore log tentativo fallito: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulisce tentativi falliti dopo login riuscito
|
||||
*/
|
||||
private function clearFailedAttempts(string $identifier): void {
|
||||
try {
|
||||
$stmt = $this->db->prepare("
|
||||
DELETE FROM failed_login_attempts
|
||||
WHERE username = :username AND ip_address = :ip
|
||||
");
|
||||
$stmt->execute([
|
||||
'username' => $identifier,
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? ''
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
error_log("Errore pulizia tentativi: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log attività utente
|
||||
*/
|
||||
public function logActivity(?int $userId, string $username, string $action, string $description = null): void {
|
||||
try {
|
||||
$stmt = $this->db->prepare("
|
||||
INSERT INTO user_activity_log (user_id, username, action, description, ip_address, user_agent)
|
||||
VALUES (:user_id, :username, :action, :description, :ip, :ua)
|
||||
");
|
||||
$stmt->execute([
|
||||
'user_id' => $userId,
|
||||
'username' => $username,
|
||||
'action' => $action,
|
||||
'description' => $description,
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? null,
|
||||
'ua' => $_SERVER['HTTP_USER_AGENT'] ?? null
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
error_log("Errore log attività: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulizia token scaduti (da eseguire periodicamente)
|
||||
*/
|
||||
public function cleanExpiredTokens(): int {
|
||||
try {
|
||||
$stmt = $this->db->prepare("DELETE FROM auth_tokens WHERE expires_at < NOW()");
|
||||
$stmt->execute();
|
||||
return $stmt->rowCount();
|
||||
} catch (Exception $e) {
|
||||
error_log("Errore pulizia token: " . $e->getMessage());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottiene username da cookie (per form di re-autenticazione)
|
||||
*/
|
||||
public function getRememberedUsername(): ?string {
|
||||
if (!isset($_COOKIE[$this->cookieName])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$parts = explode(':', $_COOKIE[$this->cookieName]);
|
||||
if (count($parts) !== 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $this->db->prepare("
|
||||
SELECT u.username
|
||||
FROM auth_tokens at
|
||||
JOIN users u ON at.user_id = u.id
|
||||
WHERE at.selector = :selector
|
||||
");
|
||||
$stmt->execute(['selector' => $parts[0]]);
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
return $result['username'] ?? null;
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
config/.DS_Store
vendored
Normal file
BIN
config/.DS_Store
vendored
Normal file
Binary file not shown.
28
config/db.php
Normal file
28
config/db.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$dotenv = Dotenv\Dotenv::createImmutable('/var/www/html/confs/dpmy_dev/');
|
||||
$dotenv->load();
|
||||
|
||||
$DB_HOST = $_ENV['DB_HOST'];
|
||||
$DB_PORT = $_ENV['DB_PORT'];
|
||||
$DB_NAME = $_ENV['DB_DATABASE'];
|
||||
$DB_USER = $_ENV['DB_USERNAME'];
|
||||
$DB_PASS = $_ENV['DB_PASSWORD'];
|
||||
|
||||
$db = new PDO("mysql:host=$DB_HOST;dbname=$DB_NAME;charset=utf8mb4",$DB_USER,$DB_PASS,[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
||||
|
||||
|
||||
// try {
|
||||
// $pdo = new PDO(
|
||||
// "mysql:host=$DB_HOST;dbname=$DB_NAME;charset=utf8mb4",
|
||||
// $DB_USER,
|
||||
// $DB_PASS,
|
||||
// [
|
||||
// PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||
// ]
|
||||
// );
|
||||
// echo "Connessione al database riuscita!";
|
||||
// } catch (PDOException $e) {
|
||||
// echo "Errore connessione DB: " . $e->getMessage();
|
||||
// }
|
||||
6
config/init.php
Normal file
6
config/init.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/db.php';
|
||||
require_once __DIR__ . '/../app/UsesrsManager.class.php';
|
||||
$userManager = new UserManager($pdo);
|
||||
$currentUser = $userManager->checkAuth();
|
||||
8
index.php
Normal file
8
index.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/config/init.php';
|
||||
|
||||
include 'parts/head.php';
|
||||
include 'parts/sidebar.php';
|
||||
include 'parts/content.php';
|
||||
include 'parts/footer.php';
|
||||
?>
|
||||
556
parts/content.php
Normal file
556
parts/content.php
Normal file
@@ -0,0 +1,556 @@
|
||||
<!-- Content Wrapper -->
|
||||
<div id="content-wrapper" class="d-flex flex-column">
|
||||
|
||||
<!-- Main Content -->
|
||||
<div id="content">
|
||||
|
||||
<!-- Topbar -->
|
||||
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
|
||||
|
||||
<!-- Sidebar Toggle (Topbar) -->
|
||||
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
|
||||
<i class="fa fa-bars"></i>
|
||||
</button>
|
||||
|
||||
<!-- Topbar Search -->
|
||||
<form
|
||||
class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control bg-light border-0 small" placeholder="Search for..."
|
||||
aria-label="Search" aria-describedby="basic-addon2">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-primary" type="button">
|
||||
<i class="fas fa-search fa-sm"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Topbar Navbar -->
|
||||
<ul class="navbar-nav ml-auto">
|
||||
|
||||
<!-- Nav Item - Search Dropdown (Visible Only XS) -->
|
||||
<li class="nav-item dropdown no-arrow d-sm-none">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="searchDropdown" role="button"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fas fa-search fa-fw"></i>
|
||||
</a>
|
||||
<!-- Dropdown - Messages -->
|
||||
<div class="dropdown-menu dropdown-menu-right p-3 shadow animated--grow-in"
|
||||
aria-labelledby="searchDropdown">
|
||||
<form class="form-inline mr-auto w-100 navbar-search">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control bg-light border-0 small"
|
||||
placeholder="Search for..." aria-label="Search"
|
||||
aria-describedby="basic-addon2">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-primary" type="button">
|
||||
<i class="fas fa-search fa-sm"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Nav Item - Alerts -->
|
||||
<li class="nav-item dropdown no-arrow mx-1">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="alertsDropdown" role="button"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fas fa-bell fa-fw"></i>
|
||||
<!-- Counter - Alerts -->
|
||||
<span class="badge badge-danger badge-counter">3+</span>
|
||||
</a>
|
||||
<!-- Dropdown - Alerts -->
|
||||
<div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in"
|
||||
aria-labelledby="alertsDropdown">
|
||||
<h6 class="dropdown-header">
|
||||
Alerts Center
|
||||
</h6>
|
||||
<a class="dropdown-item d-flex align-items-center" href="#">
|
||||
<div class="mr-3">
|
||||
<div class="icon-circle bg-primary">
|
||||
<i class="fas fa-file-alt text-white"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="small text-gray-500">December 12, 2019</div>
|
||||
<span class="font-weight-bold">A new monthly report is ready to download!</span>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item d-flex align-items-center" href="#">
|
||||
<div class="mr-3">
|
||||
<div class="icon-circle bg-success">
|
||||
<i class="fas fa-donate text-white"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="small text-gray-500">December 7, 2019</div>
|
||||
$290.29 has been deposited into your account!
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item d-flex align-items-center" href="#">
|
||||
<div class="mr-3">
|
||||
<div class="icon-circle bg-warning">
|
||||
<i class="fas fa-exclamation-triangle text-white"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="small text-gray-500">December 2, 2019</div>
|
||||
Spending Alert: We've noticed unusually high spending for your account.
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item text-center small text-gray-500" href="#">Show All Alerts</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Nav Item - Messages -->
|
||||
<li class="nav-item dropdown no-arrow mx-1">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="messagesDropdown" role="button"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fas fa-envelope fa-fw"></i>
|
||||
<!-- Counter - Messages -->
|
||||
<span class="badge badge-danger badge-counter">7</span>
|
||||
</a>
|
||||
<!-- Dropdown - Messages -->
|
||||
<div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in"
|
||||
aria-labelledby="messagesDropdown">
|
||||
<h6 class="dropdown-header">
|
||||
Message Center
|
||||
</h6>
|
||||
<a class="dropdown-item d-flex align-items-center" href="#">
|
||||
<div class="dropdown-list-image mr-3">
|
||||
<img class="rounded-circle" src="img/undraw_profile_1.svg"
|
||||
alt="...">
|
||||
<div class="status-indicator bg-success"></div>
|
||||
</div>
|
||||
<div class="font-weight-bold">
|
||||
<div class="text-truncate">Hi there! I am wondering if you can help me with a
|
||||
problem I've been having.</div>
|
||||
<div class="small text-gray-500">Emily Fowler · 58m</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item d-flex align-items-center" href="#">
|
||||
<div class="dropdown-list-image mr-3">
|
||||
<img class="rounded-circle" src="img/undraw_profile_2.svg"
|
||||
alt="...">
|
||||
<div class="status-indicator"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-truncate">I have the photos that you ordered last month, how
|
||||
would you like them sent to you?</div>
|
||||
<div class="small text-gray-500">Jae Chun · 1d</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item d-flex align-items-center" href="#">
|
||||
<div class="dropdown-list-image mr-3">
|
||||
<img class="rounded-circle" src="img/undraw_profile_3.svg"
|
||||
alt="...">
|
||||
<div class="status-indicator bg-warning"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-truncate">Last month's report looks great, I am very happy with
|
||||
the progress so far, keep up the good work!</div>
|
||||
<div class="small text-gray-500">Morgan Alvarez · 2d</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item d-flex align-items-center" href="#">
|
||||
<div class="dropdown-list-image mr-3">
|
||||
<img class="rounded-circle" src="https://source.unsplash.com/Mv9hjnEUHR4/60x60"
|
||||
alt="...">
|
||||
<div class="status-indicator bg-success"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-truncate">Am I a good boy? The reason I ask is because someone
|
||||
told me that people say this to all dogs, even if they aren't good...</div>
|
||||
<div class="small text-gray-500">Chicken the Dog · 2w</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item text-center small text-gray-500" href="#">Read More Messages</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<div class="topbar-divider d-none d-sm-block"></div>
|
||||
|
||||
<!-- Nav Item - User Information -->
|
||||
<li class="nav-item dropdown no-arrow">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="mr-2 d-none d-lg-inline text-gray-600 small">Douglas McGee</span>
|
||||
<img class="img-profile rounded-circle"
|
||||
src="img/undraw_profile.svg">
|
||||
</a>
|
||||
<!-- Dropdown - User Information -->
|
||||
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in"
|
||||
aria-labelledby="userDropdown">
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
|
||||
Profile
|
||||
</a>
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="fas fa-cogs fa-sm fa-fw mr-2 text-gray-400"></i>
|
||||
Settings
|
||||
</a>
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="fas fa-list fa-sm fa-fw mr-2 text-gray-400"></i>
|
||||
Activity Log
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#logoutModal">
|
||||
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
|
||||
Logout
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
<!-- End of Topbar -->
|
||||
|
||||
<!-- Begin Page Content -->
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Page Heading -->
|
||||
<div class="d-sm-flex align-items-center justify-content-between mb-4">
|
||||
<h1 class="h3 mb-0 text-gray-800">Dashboard</h1>
|
||||
<a href="#" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm"><i
|
||||
class="fas fa-download fa-sm text-white-50"></i> Generate Report</a>
|
||||
</div>
|
||||
|
||||
<!-- Content Row -->
|
||||
<div class="row">
|
||||
|
||||
<!-- Earnings (Monthly) Card Example -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-primary shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
|
||||
Earnings (Monthly)</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">$40,000</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-calendar fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Earnings (Monthly) Card Example -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-success shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">
|
||||
Earnings (Annual)</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">$215,000</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-dollar-sign fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Earnings (Monthly) Card Example -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-info shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Tasks
|
||||
</div>
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-auto">
|
||||
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">50%</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="progress progress-sm mr-2">
|
||||
<div class="progress-bar bg-info" role="progressbar"
|
||||
style="width: 50%" aria-valuenow="50" aria-valuemin="0"
|
||||
aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-clipboard-list fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pending Requests Card Example -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-warning shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
|
||||
Pending Requests</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">18</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-comments fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content Row -->
|
||||
|
||||
<div class="row">
|
||||
|
||||
<!-- Area Chart -->
|
||||
<div class="col-xl-8 col-lg-7">
|
||||
<div class="card shadow mb-4">
|
||||
<!-- Card Header - Dropdown -->
|
||||
<div
|
||||
class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Earnings Overview</h6>
|
||||
<div class="dropdown no-arrow">
|
||||
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
|
||||
aria-labelledby="dropdownMenuLink">
|
||||
<div class="dropdown-header">Dropdown Header:</div>
|
||||
<a class="dropdown-item" href="#">Action</a>
|
||||
<a class="dropdown-item" href="#">Another action</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#">Something else here</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Card Body -->
|
||||
<div class="card-body">
|
||||
<div class="chart-area">
|
||||
<canvas id="myAreaChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pie Chart -->
|
||||
<div class="col-xl-4 col-lg-5">
|
||||
<div class="card shadow mb-4">
|
||||
<!-- Card Header - Dropdown -->
|
||||
<div
|
||||
class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Revenue Sources</h6>
|
||||
<div class="dropdown no-arrow">
|
||||
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
|
||||
aria-labelledby="dropdownMenuLink">
|
||||
<div class="dropdown-header">Dropdown Header:</div>
|
||||
<a class="dropdown-item" href="#">Action</a>
|
||||
<a class="dropdown-item" href="#">Another action</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#">Something else here</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Card Body -->
|
||||
<div class="card-body">
|
||||
<div class="chart-pie pt-4 pb-2">
|
||||
<canvas id="myPieChart"></canvas>
|
||||
</div>
|
||||
<div class="mt-4 text-center small">
|
||||
<span class="mr-2">
|
||||
<i class="fas fa-circle text-primary"></i> Direct
|
||||
</span>
|
||||
<span class="mr-2">
|
||||
<i class="fas fa-circle text-success"></i> Social
|
||||
</span>
|
||||
<span class="mr-2">
|
||||
<i class="fas fa-circle text-info"></i> Referral
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content Row -->
|
||||
<div class="row">
|
||||
|
||||
<!-- Content Column -->
|
||||
<div class="col-lg-6 mb-4">
|
||||
|
||||
<!-- Project Card Example -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Projects</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h4 class="small font-weight-bold">Server Migration <span
|
||||
class="float-right">20%</span></h4>
|
||||
<div class="progress mb-4">
|
||||
<div class="progress-bar bg-danger" role="progressbar" style="width: 20%"
|
||||
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<h4 class="small font-weight-bold">Sales Tracking <span
|
||||
class="float-right">40%</span></h4>
|
||||
<div class="progress mb-4">
|
||||
<div class="progress-bar bg-warning" role="progressbar" style="width: 40%"
|
||||
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<h4 class="small font-weight-bold">Customer Database <span
|
||||
class="float-right">60%</span></h4>
|
||||
<div class="progress mb-4">
|
||||
<div class="progress-bar" role="progressbar" style="width: 60%"
|
||||
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<h4 class="small font-weight-bold">Payout Details <span
|
||||
class="float-right">80%</span></h4>
|
||||
<div class="progress mb-4">
|
||||
<div class="progress-bar bg-info" role="progressbar" style="width: 80%"
|
||||
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<h4 class="small font-weight-bold">Account Setup <span
|
||||
class="float-right">Complete!</span></h4>
|
||||
<div class="progress">
|
||||
<div class="progress-bar bg-success" role="progressbar" style="width: 100%"
|
||||
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Color System -->
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card bg-primary text-white shadow">
|
||||
<div class="card-body">
|
||||
Primary
|
||||
<div class="text-white-50 small">#4e73df</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card bg-success text-white shadow">
|
||||
<div class="card-body">
|
||||
Success
|
||||
<div class="text-white-50 small">#1cc88a</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card bg-info text-white shadow">
|
||||
<div class="card-body">
|
||||
Info
|
||||
<div class="text-white-50 small">#36b9cc</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card bg-warning text-white shadow">
|
||||
<div class="card-body">
|
||||
Warning
|
||||
<div class="text-white-50 small">#f6c23e</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card bg-danger text-white shadow">
|
||||
<div class="card-body">
|
||||
Danger
|
||||
<div class="text-white-50 small">#e74a3b</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card bg-secondary text-white shadow">
|
||||
<div class="card-body">
|
||||
Secondary
|
||||
<div class="text-white-50 small">#858796</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card bg-light text-black shadow">
|
||||
<div class="card-body">
|
||||
Light
|
||||
<div class="text-black-50 small">#f8f9fc</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card bg-dark text-white shadow">
|
||||
<div class="card-body">
|
||||
Dark
|
||||
<div class="text-white-50 small">#5a5c69</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 mb-4">
|
||||
|
||||
<!-- Illustrations -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Illustrations</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="text-center">
|
||||
<img class="img-fluid px-3 px-sm-4 mt-3 mb-4" style="width: 25rem;"
|
||||
src="img/undraw_posting_photo.svg" alt="...">
|
||||
</div>
|
||||
<p>Add some quality, svg illustrations to your project courtesy of <a
|
||||
target="_blank" rel="nofollow" href="https://undraw.co/">unDraw</a>, a
|
||||
constantly updated collection of beautiful svg images that you can use
|
||||
completely free and without attribution!</p>
|
||||
<a target="_blank" rel="nofollow" href="https://undraw.co/">Browse Illustrations on
|
||||
unDraw →</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Approach -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Development Approach</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>SB Admin 2 makes extensive use of Bootstrap 4 utility classes in order to reduce
|
||||
CSS bloat and poor page performance. Custom CSS classes are used to create
|
||||
custom components and custom utility classes.</p>
|
||||
<p class="mb-0">Before working with this theme, you should become familiar with the
|
||||
Bootstrap framework, especially the utility classes.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- /.container-fluid -->
|
||||
|
||||
</div>
|
||||
<!-- End of Main Content -->
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="sticky-footer bg-white">
|
||||
<div class="container my-auto">
|
||||
<div class="copyright text-center my-auto">
|
||||
<span>Copyright © Your Website 2021</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- End of Footer -->
|
||||
|
||||
</div>
|
||||
<!-- End of Content Wrapper -->
|
||||
48
parts/footer.php
Normal file
48
parts/footer.php
Normal file
@@ -0,0 +1,48 @@
|
||||
</div>
|
||||
<!-- End of Page Wrapper -->
|
||||
|
||||
<!-- Scroll to Top Button-->
|
||||
<a class="scroll-to-top rounded" href="#page-top">
|
||||
<i class="fas fa-angle-up"></i>
|
||||
</a>
|
||||
|
||||
<!-- Logout Modal-->
|
||||
<div class="modal fade" id="logoutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Ready to Leave?</h5>
|
||||
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">Select "Logout" below if you are ready to end your current session.</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
|
||||
<a class="btn btn-primary" href="login.html">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap core JavaScript-->
|
||||
<script src="vendor/jquery/jquery.min.js"></script>
|
||||
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Core plugin JavaScript-->
|
||||
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
|
||||
|
||||
<!-- Custom scripts for all pages-->
|
||||
<script src="js/sb-admin-2.min.js"></script>
|
||||
|
||||
<!-- Page level plugins -->
|
||||
<script src="vendor/chart.js/Chart.min.js"></script>
|
||||
|
||||
<!-- Page level custom scripts -->
|
||||
<script src="js/demo/chart-area-demo.js"></script>
|
||||
<script src="js/demo/chart-pie-demo.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
19
parts/head.php
Normal file
19
parts/head.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="it">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<title>DEVVV</title>
|
||||
|
||||
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
|
||||
rel="stylesheet">
|
||||
|
||||
<link href="css/sb-admin-2.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body id="page-top">
|
||||
<div id="wrapper">
|
||||
124
parts/sidebar.php
Normal file
124
parts/sidebar.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<!-- Sidebar -->
|
||||
<ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar">
|
||||
|
||||
<!-- Sidebar - Brand -->
|
||||
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="index.html">
|
||||
<div class="sidebar-brand-icon rotate-n-15">
|
||||
<i class="fas fa-laugh-wink text-warning"></i>
|
||||
</div>
|
||||
<div class="sidebar-brand-text mx-3">GOGO DPMY.dev</div>
|
||||
</a>
|
||||
|
||||
<!-- Divider -->
|
||||
<hr class="sidebar-divider my-0">
|
||||
|
||||
<!-- Nav Item - Dashboard -->
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="index.html">
|
||||
<i class="fas fa-fw fa-tachometer-alt"></i>
|
||||
<span>Dashboard</span></a>
|
||||
</li>
|
||||
|
||||
<!-- Divider -->
|
||||
<hr class="sidebar-divider">
|
||||
|
||||
<!-- Heading -->
|
||||
<div class="sidebar-heading">
|
||||
Interface
|
||||
</div>
|
||||
|
||||
<!-- Nav Item - Pages Collapse Menu -->
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseTwo"
|
||||
aria-expanded="true" aria-controls="collapseTwo">
|
||||
<i class="fas fa-fw fa-cog"></i>
|
||||
<span>Components</span>
|
||||
</a>
|
||||
<div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionSidebar">
|
||||
<div class="bg-white py-2 collapse-inner rounded">
|
||||
<h6 class="collapse-header">Custom Components:</h6>
|
||||
<a class="collapse-item" href="buttons.html">Buttons</a>
|
||||
<a class="collapse-item" href="cards.html">Cards</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Nav Item - Utilities Collapse Menu -->
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseUtilities"
|
||||
aria-expanded="true" aria-controls="collapseUtilities">
|
||||
<i class="fas fa-fw fa-wrench"></i>
|
||||
<span>Utilities</span>
|
||||
</a>
|
||||
<div id="collapseUtilities" class="collapse" aria-labelledby="headingUtilities"
|
||||
data-parent="#accordionSidebar">
|
||||
<div class="bg-white py-2 collapse-inner rounded">
|
||||
<h6 class="collapse-header">Custom Utilities:</h6>
|
||||
<a class="collapse-item" href="utilities-color.html">Colors</a>
|
||||
<a class="collapse-item" href="utilities-border.html">Borders</a>
|
||||
<a class="collapse-item" href="utilities-animation.html">Animations</a>
|
||||
<a class="collapse-item" href="utilities-other.html">Other</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Divider -->
|
||||
<hr class="sidebar-divider">
|
||||
|
||||
<!-- Heading -->
|
||||
<div class="sidebar-heading">
|
||||
Addons
|
||||
</div>
|
||||
|
||||
<!-- Nav Item - Pages Collapse Menu -->
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapsePages"
|
||||
aria-expanded="true" aria-controls="collapsePages">
|
||||
<i class="fas fa-fw fa-folder"></i>
|
||||
<span>Pages</span>
|
||||
</a>
|
||||
<div id="collapsePages" class="collapse" aria-labelledby="headingPages" data-parent="#accordionSidebar">
|
||||
<div class="bg-white py-2 collapse-inner rounded">
|
||||
<h6 class="collapse-header">Login Screens:</h6>
|
||||
<a class="collapse-item" href="login.html">Login</a>
|
||||
<a class="collapse-item" href="register.html">Register</a>
|
||||
<a class="collapse-item" href="forgot-password.html">Forgot Password</a>
|
||||
<div class="collapse-divider"></div>
|
||||
<h6 class="collapse-header">Other Pages:</h6>
|
||||
<a class="collapse-item" href="404.html">404 Page</a>
|
||||
<a class="collapse-item" href="blank.html">Blank Page</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Nav Item - Charts -->
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="charts.html">
|
||||
<i class="fas fa-fw fa-chart-area"></i>
|
||||
<span>Charts</span></a>
|
||||
</li>
|
||||
|
||||
<!-- Nav Item - Tables -->
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="tables.html">
|
||||
<i class="fas fa-fw fa-table"></i>
|
||||
<span>Tables</span></a>
|
||||
</li>
|
||||
|
||||
<!-- Divider -->
|
||||
<hr class="sidebar-divider d-none d-md-block">
|
||||
|
||||
<!-- Sidebar Toggler (Sidebar) -->
|
||||
<div class="text-center d-none d-md-inline">
|
||||
<button class="rounded-circle border-0" id="sidebarToggle"></button>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar Message -->
|
||||
<div class="sidebar-card d-none d-lg-flex">
|
||||
<img class="sidebar-card-illustration mb-2" src="img/undraw_rocket.svg" alt="...">
|
||||
<p class="text-center mb-2"><strong>SB Admin Pro</strong> is packed with premium features, components, and more!</p>
|
||||
<a class="btn btn-success btn-sm" href="https://startbootstrap.com/theme/sb-admin-pro">Upgrade to Pro!</a>
|
||||
</div>
|
||||
|
||||
</ul>
|
||||
<!-- End of Sidebar -->
|
||||
@@ -9,7 +9,7 @@
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<title>SB Admin 2 - Dashboard</title>
|
||||
<title>DEVVV</title>
|
||||
|
||||
<!-- Custom fonts for this template-->
|
||||
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
|
||||
Reference in New Issue
Block a user