Merge pull request #1 from xodivorce/dev

feat(core): restructure auth, routing, and role-based dashboards
This commit is contained in:
2025-12-29 12:45:39 +05:30
committed by GitHub
Unverified
40 changed files with 4664 additions and 1887 deletions

View File

@@ -6,7 +6,7 @@
#### A real-time map-based reporting system for campus infrastructure issues, built to improve visibility, accountability, and resolution efficiency. #### A real-time map-based reporting system for campus infrastructure issues, built to improve visibility, accountability, and resolution efficiency.
[![status](https://img.shields.io/badge/status-active-brightgreen.svg?style=flat)](https://github.com/xodivorce/infra-xodivorce-in/) [![status](https://img.shields.io/badge/status-active-brightgreen.svg?style=flat)](https://github.com/xodivorce/infra-xodivorce-in/)
[![version](https://img.shields.io/badge/version-v1.0.1-yellow.svg?style=flat)](https://github.com/xodivorce/infra-xodivorce-in/) [![version](https://img.shields.io/badge/version-v1.1.1-yellow.svg?style=flat)](https://github.com/xodivorce/infra-xodivorce-in/)
[![PRs](https://img.shields.io/badge/PRs-welcome-blue.svg?style=flat)](https://github.com/xodivorce/infra-xodivorce-in/) [![PRs](https://img.shields.io/badge/PRs-welcome-blue.svg?style=flat)](https://github.com/xodivorce/infra-xodivorce-in/)
> **🥰 Like this project? Please consider giving it a Star (🌟) on GitHub to show us your appreciation. Thank you!** > **🥰 Like this project? Please consider giving it a Star (🌟) on GitHub to show us your appreciation. Thank you!**

View File

@@ -3,7 +3,6 @@ SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS DROP TABLE IF EXISTS
`translations`, `translations`,
`password_resets`, `password_resets`,
`videos`,
`contributors`, `contributors`,
`users`, `users`,
`languages`; `languages`;

View File

@@ -3,7 +3,7 @@
-- https://www.phpmyadmin.net/ -- https://www.phpmyadmin.net/
-- --
-- Host: localhost -- Host: localhost
-- Generation Time: Dec 25, 2025 at 02:30 PM -- Generation Time: Dec 29, 2025 at 07:20 AM
-- Server version: 10.4.28-MariaDB -- Server version: 10.4.28-MariaDB
-- PHP Version: 8.2.4 -- PHP Version: 8.2.4
@@ -135,10 +135,17 @@ CREATE TABLE `password_resets` (
-- --
INSERT INTO `password_resets` (`id`, `user_id`, `email`, `token_hash`, `token_salt`, `expires_at`, `attempts`, `ip_address`, `user_agent`, `used`, `created_at`) VALUES INSERT INTO `password_resets` (`id`, `user_id`, `email`, `token_hash`, `token_salt`, `expires_at`, `attempts`, `ip_address`, `user_agent`, `used`, `created_at`) VALUES
(77, 59, 'chutkasekari@gmail.com', '28ca5a1bb5683e2a2fad65e1650c80c55962710455243876578b4fa7cd446497', 'ebc01675ab917ffa0aba525097db21bb', '2025-12-25 13:37:31', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 0, '2025-12-25 18:04:31'), (77, NULL, 'chutkasekari@gmail.com', '28ca5a1bb5683e2a2fad65e1650c80c55962710455243876578b4fa7cd446497', 'ebc01675ab917ffa0aba525097db21bb', '2025-12-25 13:37:31', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 0, '2025-12-25 18:04:31'),
(78, 59, 'chutkasekari@gmail.com', '70b759995118115ff5ea12a340705b4e65fc42a3210007e293bc5fdfaf3b82af', 'c346f11fea127900487ecb050e0f97c0', '2025-12-25 13:39:18', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 0, '2025-12-25 18:06:18'), (78, NULL, 'chutkasekari@gmail.com', '70b759995118115ff5ea12a340705b4e65fc42a3210007e293bc5fdfaf3b82af', 'c346f11fea127900487ecb050e0f97c0', '2025-12-25 13:39:18', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 0, '2025-12-25 18:06:18'),
(79, 59, 'chutkasekari@gmail.com', '30d40f81acea6d52d241ebd3e4a634eaf775c0b9be4ffed6d31d9d2c2d568cdf', '92ce928e6056112bf5929c4d2cf539ed', '2025-12-25 13:39:58', 1, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 0, '2025-12-25 18:06:58'), (79, NULL, 'chutkasekari@gmail.com', '30d40f81acea6d52d241ebd3e4a634eaf775c0b9be4ffed6d31d9d2c2d568cdf', '92ce928e6056112bf5929c4d2cf539ed', '2025-12-25 13:39:58', 1, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 0, '2025-12-25 18:06:58'),
(80, 59, 'chutkasekari@gmail.com', '2e4d690b2c931843336e171e472064a4fc0e9eeb709bf8940a89856823278617', '87adce2403c4d95a30646d8f3818d0c0', '2025-12-25 13:44:47', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 0, '2025-12-25 18:11:47'); (80, NULL, 'chutkasekari@gmail.com', '2e4d690b2c931843336e171e472064a4fc0e9eeb709bf8940a89856823278617', '87adce2403c4d95a30646d8f3818d0c0', '2025-12-25 13:44:47', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 0, '2025-12-25 18:11:47'),
(81, NULL, 'chutkasekari@gmail.com', '08150475e5a01b56682158d7245448f6784732d4c02bcde71228a11dfdeea220', '86e1b3f761ac4a2c5f4f09b9a8a5a7b1', '2025-12-25 15:17:10', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 1, '2025-12-25 19:44:10'),
(82, NULL, 'chutkasekari@gmail.com', 'aca6fa6001c57ef6415fb9ee6e2777072d829f8fee751172f3de75325dbaece6', '3b6d0bf0cc84fbd4f15d2c341bd3711b', '2025-12-25 15:29:45', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 0, '2025-12-25 19:56:45'),
(83, NULL, 'chutkasekari@gmail.com', '687bb06e12c95dc4d960c45c4aed67f3bd3cf4126de49f6a2940043ceca1fc05', 'a8986c4b4ae94027076a6275696cfc50', '2025-12-25 15:30:22', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 0, '2025-12-25 19:57:22'),
(84, NULL, 'chutkasekari@gmail.com', '7295280b048f2a55857391a401888be44c360c886992aa5a28ea3ac77aff00d7', 'ca070cc644d5188dfa48a23e01550dca', '2025-12-25 15:34:43', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 1, '2025-12-25 20:01:43'),
(85, 63, 'prasidmandal79@gmail.com', '13bba949aa87cdce6d004a83a4e12d8fad3908493c676f9938f92fe18d495cb0', 'cb7282236e04acef46f4f94014b42894', '2025-12-29 07:10:57', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 1, '2025-12-29 11:37:57'),
(86, 63, 'prasidmandal79@gmail.com', '5ffb85b8ad6b37321a5fa80c3e31f0c2d13865493b66e819a231409f76497706', 'c225eb18cd7a316efac7db40bfcc97c5', '2025-12-29 07:11:35', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 0, '2025-12-29 11:38:35'),
(87, 63, 'prasidmandal79@gmail.com', 'cf0d32fb8d22c62dc077ba82960ec696c5c7b2cc2b37b3d7c7187219f9820b57', 'da591eaf4b7de7a6e065ce677df6ae0b', '2025-12-29 07:11:44', 0, 0x00000000000000000000000000000001, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', 0, '2025-12-29 11:38:44');
-- -------------------------------------------------------- -- --------------------------------------------------------
@@ -3296,15 +3303,17 @@ CREATE TABLE `users` (
`age` tinyint(3) UNSIGNED NOT NULL, `age` tinyint(3) UNSIGNED NOT NULL,
`gender` enum('male','female','prefer_not') NOT NULL, `gender` enum('male','female','prefer_not') NOT NULL,
`password_hash` varchar(255) NOT NULL CHECK (char_length(`password_hash`) >= 60), `password_hash` varchar(255) NOT NULL CHECK (char_length(`password_hash`) >= 60),
`is_admin` tinyint(1) NOT NULL DEFAULT 0,
`created_at` timestamp NOT NULL DEFAULT current_timestamp() `created_at` timestamp NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ;
-- --
-- Dumping data for table `users` -- Dumping data for table `users`
-- --
INSERT INTO `users` (`id`, `username`, `email`, `age`, `gender`, `password_hash`, `created_at`) VALUES INSERT INTO `users` (`id`, `username`, `email`, `age`, `gender`, `password_hash`, `is_admin`, `created_at`) VALUES
(59, '23/v/kpc-cst/36', 'chutkasekari@gmail.com', 19, 'male', '$2y$10$1qTZLhchbeN9KITqwwdjnuN9OhX7/n.se5zdoc31zAZ89qiSv8z9W', '2025-12-25 12:31:52'); (63, '23/v/kpc-cst/36', 'prasidmandal79@gmail.com', 19, 'male', '$2y$10$VpgmeJOMAK72yYHNM.yXQ.F9ZnsQf8v9INGovs7fXjr9wh.euMGki', 1, '2025-12-28 20:20:52'),
(65, '23/v/kpc-cst/35', 'dipalimandal257@gmail.com', 36, 'female', '$2y$10$CW4itEj.dMuFszYJ/jmAnu49qGr2rZUENEkLnWBzRk0CY9.dJSxNu', 0, '2025-12-29 06:18:30');
-- --
-- Indexes for dumped tables -- Indexes for dumped tables
@@ -3370,7 +3379,7 @@ ALTER TABLE `languages`
-- AUTO_INCREMENT for table `password_resets` -- AUTO_INCREMENT for table `password_resets`
-- --
ALTER TABLE `password_resets` ALTER TABLE `password_resets`
MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=81; MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=88;
-- --
-- AUTO_INCREMENT for table `translations` -- AUTO_INCREMENT for table `translations`
@@ -3382,7 +3391,7 @@ ALTER TABLE `translations`
-- AUTO_INCREMENT for table `users` -- AUTO_INCREMENT for table `users`
-- --
ALTER TABLE `users` ALTER TABLE `users`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=60; MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
-- --
-- Constraints for dumped tables -- Constraints for dumped tables

View File

@@ -1,9 +1,7 @@
#This is an example of secret environmental variables #This is an example of secret environmental variables
#original environmental variable should be created with .env filename #original environmental variable should be created with .env filename
DOMAIN = "Your Domain Name Here" DOMAIN = "Your Domain Name Here"
DEBUG_MODE = "false" # Set to "false" in production DEBUG_MODE = "false" # Set to falsein production
BETA = "true" #Is this in the beta version? or not.
DB_HOST = "Your Database Host Name Here" DB_HOST = "Your Database Host Name Here"
DB_USER = "Your Database Username Here" DB_USER = "Your Database Username Here"
DB_PASS = "Your Database Password Here" DB_PASS = "Your Database Password Here"
@@ -18,3 +16,15 @@ MAIL_FROM_NAME = "Your Mail From Name Here"
MAIL_TO = "Your Mail To Address Here" MAIL_TO = "Your Mail To Address Here"
MAX_VISIBLE_CONTRIBUTORS = "Your Maximum Visible Contributors Here. Use: 11(default)" MAX_VISIBLE_CONTRIBUTORS = "Your Maximum Visible Contributors Here. Use: 11(default)"
PROJECT_START_YEAR = "Your Project Start Year Here. Use: 2025(default)" PROJECT_START_YEAR = "Your Project Start Year Here. Use: 2025(default)"
# Contact Information of various departments
HELPDESK_EMAIL= "Your Helpdesk Email Here"
HELPDESK_PHONE= "Your Helpdesk Phone Here"
MANAGEMENT_EMAIL= "Your Management Email Here"
MANAGEMENT_PHONE= "Your Management Phone Here"
HEALTH_EMAIL= "Your Health Email Here"
HEALTH_PHONE= "Your Health Phone Here"
LIBRARY_EMAIL= "Your Library Email Here"
LIBRARY_PHONE= "Your Library Phone Here"
SECURITY_EMAIL= "Your Security Email Here"
SECURITY_PHONE= "Your Security Phone Here"

View File

@@ -1,83 +1,39 @@
<nav class="fixed top-0 left-0 right-0 px-7 pb-1 bg-black z-10 flex justify-between items-center h-[3.8em]"> <?php
$current_email = $_SESSION['user_email'];
$user_initial = strtoupper($current_email[0]);
?>
<div class="flex items-center"> <header class="w-full bg-neutral-900/95 border-b border-neutral-800 px-6 py-4 flex items-center justify-between backdrop-blur-sm sticky top-0 z-20">
<img src="./assets/images/icons/menu.svg" class="h-[1.1rem] -mr-1 w-auto cursor-pointer" id="menu-icon"
alt="menu-icon">
<img src="./assets/images/logos/steamstube-logo.svg" class="h-8 ml-7 cursor-pointer" alt="steamstube-logo"
id="domain-logo">
<span class="text-[1.3rem] font-youtube ml-0.5 text-gray-200 cursor-pointer" id="domain-name">
<?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?>
</span>
<?php if (!empty($_ENV['BETA']) && filter_var($_ENV['BETA'], FILTER_VALIDATE_BOOLEAN)): ?>
<span
class="text-[0.6rem] font-youtube uppercase ml-[0.1rem] -mt-2 px-1 py-0.5 rounded text-pink-700 pointer-events-none">beta</span>
<?php endif; ?>
</div>
<div <div class="flex items-center gap-5">
class="flex flex-1 justify-center items-center px-8 mt-1 ml-auto mr-auto max-[1100px]:justify-start max-[750px]:hidden">
<div class="flex items-center w-full max-w-[41rem] border-2 border-neutral-900 rounded-full px-5 py-[0.5rem]"> <div class="flex items-center gap-3">
<img src="./assets/images/icons/search.svg" class="h-[1.2rem] mr-2" alt="search-icon"> <div class="w-8 h-8 rounded-lg bg-blue-500/10 flex items-center justify-center border border-blue-500/20 shadow-[0_0_15px_rgba(59,130,246,0.1)]">
<input type="text" <svg class="w-5 h-5 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
placeholder="Search <?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?> or paste your code..." <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
class="flex-1 placeholder:text-gray-400 font-light text-gray-200 bg-transparent border-none outline-none text-sm tracking-wide truncate min-w-0"> </svg>
<button class="ml-2 cursor-pointer"> </div>
<img src="./assets/images/icons/search-filter-icon.svg" class="h-5" alt="search-filter-icon"> <h2 class="text-xl font-bold text-white tracking-tight"> <?php echo htmlspecialchars($_ENV['DOMAIN']); ?> Dashboard</h2>
</button>
</div> </div>
</div> </div>
<div class="flex items-center mt-0 relative"> <div class="flex items-center gap-4">
<button class="hidden max-[750px]:inline-flex items-center justify-center cursor-pointer" id="mobileSearchBtn">
<img src="./assets/images/icons/mobile-search-icon.svg" class="h-5 w-auto pl-5" alt="mobile-search-icon"> <div class="text-right">
</button> <div class="text-sm font-semibold text-white">
<div id="mobileSearchOverlay" <?php echo htmlspecialchars($current_email); ?>
class="hidden fixed top-0 left-0 right-0 bg-black px-5 py-3 items-center z-50 transition-transform duration-300 transform -translate-y-full"> </div>
<div class="flex items-center w-full border-2 border-neutral-900 rounded-full px-4 py-2 bg-black"> <div class="text-xs text-neutral-500 font-medium uppercase tracking-wide">
<input type="text" id="mobileSearchInput" <?php echo ($is_admin ?? false) ? 'Administrator' : 'User'; ?>
placeholder="Search <?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?> or paste your code..."
class="flex-1 text-[1rem] text-gray-200 bg-transparent border-none outline-none tracking-wide placeholder:text-gray-400 placeholder:font-light text-sm placeholder:tracking-normal truncate">
</div> </div>
</div> </div>
<button class="hidden max-[750px]:inline-flex items-center justify-center -ml-2 relative left-7 cursor-pointer"
id="moreOptionsBtn"> <button
<img src="./assets/images/icons/more-options-icon.svg" class="h-5 w-auto" alt="more-options-icon"> onclick="window.location.href='./pages/account.php'"
class="w-10 h-10 rounded-full bg-neutral-800 border border-neutral-700 hover:border-blue-500/50 hover:shadow-[0_0_15px_rgba(59,130,246,0.3)] transition-all duration-300 flex items-center justify-center text-neutral-300 hover:text-white font-bold text-sm"
>
<?php echo $user_initial; ?>
</button> </button>
<div class="hidden absolute top-[1.4rem] left-[-4.2rem] bg-black text-gray-200 rounded-xl shadow-2xl shadow-black/40 w-36 py-2 z-50 opacity-0 transform scale-95 transition-all duration-200 ease-out"
id="moreOptionsMenu">
<button
class="flex items-center w-full px-4 py-2 text-base font-light text-gray-200 no-underline cursor-pointer hover:bg-[#332631] hover:rounded-lg max-[56.25rem]:text-sm"><img
src="./assets/images/icons/upload.svg" class="h-5 mr-2" alt="upload-icon">
<span>Uploads</span>
</button>
<button
class="flex items-center w-full px-4 py-2 text-base font-light text-gray-200 no-underline cursor-pointer hover:bg-[#332631] hover:rounded-lg max-[56.25rem]:text-sm">
<img src="./assets/images/icons/reminders.svg" class="h-5 mr-2" alt="reminders-icon">
<span>Reminders</span>
</button>
<button
class="flex items-center w-full px-4 py-2 text-base font-light text-gray-200 no-underline cursor-pointer hover:bg-[#332631] hover:rounded-lg max-[56.25rem]:text-sm">
<img src="./assets/images/icons/settings.svg" class="h-5 mr-2" alt="settings-icon">
<span>Settings</span>
</button>
<button onclick="window.location.href='./core/auth/auth_check.php'"
class="flex items-center w-full px-4 py-2 text-base font-light text-gray-200 no-underline cursor-pointer hover:bg-[#332631] hover:rounded-lg max-[56.25rem]:text-sm">
<img src="./assets/images/icons/default-user.png" class="h-5 mr-2" alt="default-user-icon">
<span>Account</span>
</button>
</div>
<div class="flex items-center max-[750px]:hidden">
<button class="ml-2 cursor-pointer"><img src="./assets/images/icons/upload.svg" class="h-5 w-auto"
alt="upload-icon"></button>
<button class="ml-8 cursor-pointer"><img src="./assets/images/icons/reminders.svg" class="h-5 w-auto"
alt="reminders-icon"></button>
<button class="ml-8 cursor-pointer"><img src="./assets/images/icons/settings.svg" class="h-5 w-auto"
alt="settings-icon"></button>
<button onclick="window.location.href='./core/auth/auth_check.php'" class="ml-8 cursor-pointer"><img
src="./assets/images/icons/default-user.png" class="h-5 w-auto" alt="default-user-icon"></button>
</div>
</div> </div>
</header>
</nav>

View File

@@ -1,302 +1,71 @@
<div <?php
class="sidebar group fixed top-[3.6rem] left-0 z-[9999] h-[calc(100vh-3.6rem)] w-[14.375rem] overflow-y-auto overflow-x-hidden bg-black pb-[25%] pr-[0.9375rem] pl-[0.9375rem] pt-[0.3125rem] group-[.small-sidebar]:w-[4.375rem] group-[.small-sidebar]:overflow-y-hidden max-[31.25rem]:group-[.small-sidebar]:hidden"> $activeClass = 'bg-blue-500/10 text-blue-400 shadow-[0_0_15px_rgba(59,130,246,0.1)] border border-blue-500/20';
$inactiveClass = 'text-neutral-400 hover:text-white hover:bg-neutral-800/60 border border-transparent transition-all duration-200';
?>
<div class="shortcut-links"> <aside class="w-64 bg-neutral-900/95 border-r border-neutral-800 flex flex-col h-screen">
<button id="home-btn"
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.526rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/home-icon.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/home-fill-icon.svg">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Home</p>
</button>
<button id="trending-btn"
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/trending-icon.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/trending-fill-icon.svg">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Trending</p>
</button>
<hr
class="sidebar-hr my-[0.3125rem] ml-[1%] h-[0.0625rem] w-[99%] border-0 bg-neutral-700 transition-width duration-300 ease-in-out group-[.small-sidebar]:w-full max-[56.25rem]:w-[99%]">
</div>
<div class="shortcut-links"> <nav class="flex-1 px-4 py-6 space-y-2 overflow-y-auto" id="sidebar-nav">
<button id="watched-btn"
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/watched-icon.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/watched-fill-icon.svg">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Watched</p>
</button>
<button id="favourites-btn"
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/favourites-icon.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/favourites-fill-icon.svg">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Favourites</p>
</button>
<button id="followings-btn"
class="icon-btn categories-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/followings-icon.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/followings-fill-icon.svg">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Followings</p>
<div
class="right-side absolute right-0 mr-[0.375rem] flex items-center bg-transparent ml-auto group-[.small-sidebar]:hidden">
<div class="divider mx-[0.625rem] h-[1.3rem] w-[0.0625rem] bg-neutral-700"></div>
<img src="./assets/images/icons/arrow-down.svg" class="arrow-icon h-[1.3rem] w-auto">
</div>
</button>
<div class="dropdown hidden flex-col">
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 active:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/users/apple.jpg"
class="icon block h-[1.5rem] w-[1.5rem] rounded-full object-cover max-[56.25rem]:h-[1.3rem] max-[56.25rem]:w-[1.3rem]">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
@apple</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 active:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/users/cumatozz.jpg"
class="icon block h-[1.5rem] w-[1.5rem] rounded-full object-cover max-[56.25rem]:h-[1.3rem] max-[56.25rem]:w-[1.3rem]">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
@cumatozz</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 active:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/users/johnny-sins.jpg"
class="icon block h-[1.5rem] w-[1.5rem] rounded-full object-cover max-[56.25rem]:h-[1.3rem] max-[56.25rem]:w-[1.3rem]">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
@johnny_sins</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 active:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/users/sweetie-fox.jpg"
class="icon block h-[1.5rem] w-[1.5rem] rounded-full object-cover max-[56.25rem]:h-[1.3rem] max-[56.25rem]:w-[1.3rem]">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
@sweetie_fox</p>
</button>
</div>
<hr
class="sidebar-hr my-[0.3125rem] ml-[1%] h-[0.0625rem] w-[99%] border-0 bg-neutral-700 transition-width duration-300 ease-in-out group-[.small-sidebar]:w-full max-[56.25rem]:w-[99%]">
</div>
<div class="shortcut-links"> <?php if (!$is_admin): ?>
<button id="categories-btn"
class="icon-btn categories-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/categories-icon.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/categories-fill-icon.svg" alt="Categories icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Categories</p>
<div
class="right-side absolute right-0 mr-[0.375rem] flex items-center bg-transparent ml-auto group-[.small-sidebar]:hidden">
<div class="divider mx-[0.625rem] h-[1.3rem] w-[0.0625rem] bg-neutral-700"></div>
<img src="./assets/images/icons/arrow-down.svg" class="arrow-icon h-[1.3rem] w-auto">
</div>
</button>
<div class="dropdown hidden flex-col">
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/straight-gender-icon.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/straight-gender-fill-icon.svg" alt="Male icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Straight</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/gay-gender-icon.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/gay-gender-fill-icon.svg" alt="Male icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Gay</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/trans-gender-icon.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/trans-gender-fill-icon.svg" alt="Female icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Trans</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/lesbian-gender-icon.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/lesbian-gender-fill-icon.svg" alt="Female icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Lesbian</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/bisexual-gender-icon.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/bisexual-gender-fill-icon.svg" alt="Female icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Bisexual</p>
</button>
</div>
<button id="fan-picks-btn"
class="icon-btn categories-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/fan-pick's-icon.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/fan-pick's-fill-icon.svg" alt="Fan Pick's icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Fan Picks</p>
<div
class="right-side absolute right-0 mr-[0.375rem] flex items-center bg-transparent ml-auto group-[.small-sidebar]:hidden">
<div class="divider mx-[0.625rem] h-[1.3rem] w-[0.0625rem] bg-neutral-700"></div>
<img src="./assets/images/icons/arrow-down.svg" class="arrow-icon h-[1.3rem] w-auto">
</div>
</button>
<div class="dropdown fan-picks-dropdown hidden flex-col group-[.small-sidebar]:!hidden">
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/fan-pick's-sub-con.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/fan-pick's-sub-fill-icon.svg" alt="Male icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Teen (18+)</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/fan-pick's-sub-con.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/fan-pick's-sub-fill-icon.svg" alt="Female icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
MILF</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/fan-pick's-sub-con.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/fan-pick's-sub-fill-icon.svg" alt="Male icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Anal</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/fan-pick's-sub-con.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/fan-pick's-sub-fill-icon.svg" alt="Female icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Hardcore BDSM</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/fan-pick's-sub-con.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/fan-pick's-sub-fill-icon.svg" alt="Female icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Threesome</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/fan-pick's-sub-con.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/fan-pick's-sub-fill-icon.svg" alt="Female icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Hentai</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/fan-pick's-sub-con.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/fan-pick's-sub-fill-icon.svg" alt="Female icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
JAV</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/fan-pick's-sub-con.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/fan-pick's-sub-fill-icon.svg" alt="Female icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Russian</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/fan-pick's-sub-con.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/fan-pick's-sub-fill-icon.svg" alt="Female icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Korean</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/fan-pick's-sub-con.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/fan-pick's-sub-fill-icon.svg" alt="Female icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Chinese</p>
</button>
<button
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm">
<img src="./assets/images/icons/fan-pick's-sub-con.svg"
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]"
data-hover="./assets/images/icons/fan-pick's-sub-fill-icon.svg" alt="Female icon">
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Indian</p>
</button>
</div>
<hr
class="sidebar-hr my-[0.3125rem] ml-[1%] h-[0.0625rem] w-[99%] border-0 bg-neutral-700 transition-width duration-300 ease-in-out group-[.small-sidebar]:w-full max-[56.25rem]:w-[99%]">
</div>
<div class="shortcut-links"> <a href="?page=overview"
<p class="group flex items-center px-4 py-3 text-sm font-medium rounded-xl <?php echo $page === 'overview' ? $activeClass : $inactiveClass; ?>">
class="sidebar-title my-1 ml-[0.625rem] whitespace-nowrap text-gray-200 text-base max-[56.25rem]:text-sm group-[.small-sidebar]:hidden"> <svg class="w-5 h-5 mr-3 <?php echo $page === 'overview' ? 'text-blue-400' : 'text-neutral-500 group-hover:text-white'; ?> transition-colors"
More from <?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></p> fill="none" stroke="currentColor" viewBox="0 0 24 24">
<button id="the-originals-btn" <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm"> d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
<img src="./assets/images/icons/the-st-originals-icon.svg" </svg>
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]" Overview
data-hover="./assets/images/icons/the-st-originals-fill-icon.svg"> </a>
<p
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden"> <a href="?page=reports"
The ST Originals</p> class="group flex items-center px-4 py-3 text-sm font-medium rounded-xl <?php echo $page === 'reports' ? $activeClass : $inactiveClass; ?>">
</button> <svg class="w-5 h-5 mr-3 <?php echo $page === 'reports' ? 'text-blue-400' : 'text-neutral-500 group-hover:text-white'; ?> transition-colors"
<button id="trust-support-btn" fill="none" stroke="currentColor" viewBox="0 0 24 24">
class="icon-btn relative flex w-full cursor-pointer items-center justify-start gap-[0.9375rem] border-none bg-transparent py-[0.525rem] pr-[0.25rem] pl-[0.75rem] text-base font-light text-gray-200 no-underline hover:rounded-[0.625rem] hover:bg-neutral-900 [&.active]:rounded-[0.625rem] [&.active]:bg-neutral-900 group-[.small-sidebar]:w-full group-[.small-sidebar]:justify-center group-[.small-sidebar]:p-[0.75rem] max-[56.25rem]: max-[56.25rem]:text-sm"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
<img src="./assets/images/icons/trust-icon.svg" d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 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" />
class="icon block h-[1.3rem] w-auto bg-transparent max-[56.25rem]:h-[1.125rem]" </svg>
data-hover="./assets/images/icons/trust-fill-icon.svg"> Reports
<p </a>
class="label m-0 block min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap bg-transparent group-[.small-sidebar]:hidden">
Trust & Support</p> <?php endif; ?>
</button>
</div> <?php if ($is_admin): ?>
</div>
<a href="?page=status-board"
class="group flex items-center px-4 py-3 text-sm font-medium rounded-xl <?php echo $page === 'status-board' ? $activeClass : $inactiveClass; ?>">
<svg class="w-5 h-5 mr-3 <?php echo $page === 'status-board' ? 'text-blue-400' : 'text-neutral-500 group-hover:text-white'; ?> transition-colors"
fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
</svg>
Status Board
</a>
<a href="?page=activity-logs"
class="group flex items-center px-4 py-3 text-sm font-medium rounded-xl <?php echo $page === 'activity-logs' ? $activeClass : $inactiveClass; ?>">
<svg class="w-5 h-5 mr-3 <?php echo $page === 'activity-logs' ? 'text-blue-400' : 'text-neutral-500 group-hover:text-white'; ?> transition-colors"
fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
Activity Logs
</a>
<a href="?page=admin"
class="group flex items-center px-4 py-3 text-sm font-medium rounded-xl <?php echo $page === 'admin' ? $activeClass : $inactiveClass; ?>">
<svg class="w-5 h-5 mr-3 <?php echo $page === 'admin' ? 'text-blue-400' : 'text-neutral-500 group-hover:text-white'; ?> transition-colors"
fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
System Admin
</a>
<?php endif; ?>
</nav>
</aside>

View File

@@ -0,0 +1,244 @@
<section class="space-y-6">
<header>
<h1 class="text-2xl font-semibold text-white">Activity Logs</h1>
<p class="mt-1 text-sm text-neutral-400">Recent system and user activities</p>
</header>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4">
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
<div>
<label class="block text-xs font-medium text-neutral-400 mb-1.5">Event Type</label>
<select class="w-full bg-neutral-900 border border-neutral-700 text-white text-sm rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
<option>All</option>
<option>Reports</option>
<option>Status Changes</option>
<option>Admin Actions</option>
</select>
</div>
<div>
<label class="block text-xs font-medium text-neutral-400 mb-1.5">Severity</label>
<select class="w-full bg-neutral-900 border border-neutral-700 text-white text-sm rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
<option>All</option>
<option>Info</option>
<option>Warning</option>
<option>Critical</option>
</select>
</div>
<div>
<label class="block text-xs font-medium text-neutral-400 mb-1.5">Date Range</label>
<select class="w-full bg-neutral-900 border border-neutral-700 text-white text-sm rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
<option>Today</option>
<option>Last 7 days</option>
<option>Last 30 days</option>
</select>
</div>
<div>
<label class="block text-xs font-medium text-neutral-400 mb-1.5">Search</label>
<input type="text" placeholder="Search activity…" class="w-full bg-neutral-900 border border-neutral-700 text-white placeholder-neutral-500 text-sm rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
</div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-neutral-900 border-b border-neutral-700">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">Timestamp</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">Actor</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">Action</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">Related Entity</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">Severity</th>
</tr>
</thead>
<tbody class="divide-y divide-neutral-700">
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">2025-12-27 14:32:15</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">admin@system</td>
<td class="px-6 py-4 text-sm text-neutral-300">Updated service configuration</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">API Gateway - US-East</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-900 text-blue-200">Info</span>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">2025-12-27 14:28:43</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">System</td>
<td class="px-6 py-4 text-sm text-neutral-300">Service health check failed</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">Database - EU-West</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-900 text-yellow-200">Warning</span>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">2025-12-27 14:15:22</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">john.doe@company.com</td>
<td class="px-6 py-4 text-sm text-neutral-300">Generated monthly report</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">Report #1247</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-900 text-blue-200">Info</span>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">2025-12-27 13:58:09</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">System</td>
<td class="px-6 py-4 text-sm text-neutral-300">Critical alert triggered</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">Load Balancer - APAC</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-900 text-red-200">Critical</span>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">2025-12-27 13:45:31</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">admin@system</td>
<td class="px-6 py-4 text-sm text-neutral-300">Modified user permissions</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">User: jane.smith@company.com</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-900 text-blue-200">Info</span>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">2025-12-27 13:22:17</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">System</td>
<td class="px-6 py-4 text-sm text-neutral-300">Backup completed successfully</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">All Services</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-900 text-blue-200">Info</span>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">2025-12-27 12:58:44</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">mark.wilson@company.com</td>
<td class="px-6 py-4 text-sm text-neutral-300">Updated service status</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">CDN - US-West</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-900 text-blue-200">Info</span>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">2025-12-27 12:31:05</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">System</td>
<td class="px-6 py-4 text-sm text-neutral-300">High memory usage detected</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">Cache Server - EU-Central</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-900 text-yellow-200">Warning</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="hidden bg-neutral-800 rounded-lg border border-neutral-700 p-12">
<div class="flex flex-col items-center justify-center text-center">
<svg class="w-16 h-16 text-neutral-600 mb-4" 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>
<h3 class="text-lg font-medium text-white mb-1">No activity logs available</h3>
<p class="text-sm text-neutral-400">System and user actions will appear here</p>
</div>
</div>
<div class="hidden bg-neutral-800 rounded-lg border border-neutral-700 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-neutral-900 border-b border-neutral-700">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">Timestamp</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">Actor</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">Action</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">Related Entity</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">Severity</th>
</tr>
</thead>
<tbody class="divide-y divide-neutral-700">
<tr class="animate-pulse">
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-32"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-28"></div>
</td>
<td class="px-6 py-4">
<div class="h-4 bg-neutral-700 rounded w-48"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-36"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-5 bg-neutral-700 rounded-full w-16"></div>
</td>
</tr>
<tr class="animate-pulse">
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-32"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-24"></div>
</td>
<td class="px-6 py-4">
<div class="h-4 bg-neutral-700 rounded w-56"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-40"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-5 bg-neutral-700 rounded-full w-16"></div>
</td>
</tr>
<tr class="animate-pulse">
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-32"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-36"></div>
</td>
<td class="px-6 py-4">
<div class="h-4 bg-neutral-700 rounded w-44"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-32"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-5 bg-neutral-700 rounded-full w-16"></div>
</td>
</tr>
<tr class="animate-pulse">
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-32"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-20"></div>
</td>
<td class="px-6 py-4">
<div class="h-4 bg-neutral-700 rounded w-52"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-44"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-5 bg-neutral-700 rounded-full w-16"></div>
</td>
</tr>
<tr class="animate-pulse">
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-32"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-28"></div>
</td>
<td class="px-6 py-4">
<div class="h-4 bg-neutral-700 rounded w-48"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-40"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-5 bg-neutral-700 rounded-full w-16"></div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>

438
src/assets/admin/_admin.php Normal file
View File

@@ -0,0 +1,438 @@
<section class="space-y-6">
<header>
<h1 class="text-2xl font-semibold text-white">Admin Panel</h1>
<p class="mt-1 text-sm text-neutral-400">System management and administrative controls</p>
</header>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-medium text-neutral-400">Total Users</p>
<p class="mt-2 text-3xl font-semibold text-white">1,247</p>
</div>
<div class="w-12 h-12 bg-blue-900 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-blue-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z">
</path>
</svg>
</div>
</div>
<p class="mt-4 text-xs text-neutral-500">Active: 1,189 | Suspended: 58</p>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-medium text-neutral-400">Pending Reports</p>
<p class="mt-2 text-3xl font-semibold text-white">34</p>
</div>
<div class="w-12 h-12 bg-yellow-900 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-yellow-200" 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>
</div>
</div>
<p class="mt-4 text-xs text-neutral-500">High: 8 | Medium: 15 | Low: 11</p>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-medium text-neutral-400">Active Incidents</p>
<p class="mt-2 text-3xl font-semibold text-white">7</p>
</div>
<div class="w-12 h-12 bg-red-900 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-red-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z">
</path>
</svg>
</div>
</div>
<p class="mt-4 text-xs text-neutral-500">Critical: 2 | Warning: 5</p>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-medium text-neutral-400">System Health</p>
<p class="mt-2 text-3xl font-semibold text-green-400">98.5%</p>
</div>
<div class="w-12 h-12 bg-green-900 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-green-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
</div>
</div>
<p class="mt-4 text-xs text-neutral-500">All services operational</p>
</div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700">
<div class="px-6 py-4 border-b border-neutral-700">
<h2 class="text-lg font-semibold text-white">User Management</h2>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-neutral-900 border-b border-neutral-700">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
User ID</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Name</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Email</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Role</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Status</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-neutral-700">
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">#1001</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">John Anderson</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">john.anderson@company.com</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-purple-900 text-purple-200">Admin</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-900 text-green-200">Active</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<button class="text-blue-400 hover:text-blue-300 mr-3">View</button>
<button class="text-red-400 hover:text-red-300">Disable</button>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">#1002</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">Sarah Mitchell</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">sarah.mitchell@company.com</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-900 text-blue-200">Moderator</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-900 text-green-200">Active</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<button class="text-blue-400 hover:text-blue-300 mr-3">View</button>
<button class="text-red-400 hover:text-red-300">Disable</button>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">#1003</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">Michael Chen</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">michael.chen@company.com</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-neutral-700 text-neutral-300">User</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-900 text-green-200">Active</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<button class="text-blue-400 hover:text-blue-300 mr-3">View</button>
<button class="text-red-400 hover:text-red-300">Disable</button>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">#1004</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">Emily Rodriguez</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">emily.rodriguez@company.com
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-neutral-700 text-neutral-300">User</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-900 text-red-200">Suspended</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<button class="text-blue-400 hover:text-blue-300 mr-3">View</button>
<button class="text-green-400 hover:text-green-300">Enable</button>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">#1005</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-white">David Thompson</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">david.thompson@company.com</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-900 text-blue-200">Moderator</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-900 text-green-200">Active</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<button class="text-blue-400 hover:text-blue-300 mr-3">View</button>
<button class="text-red-400 hover:text-red-300">Disable</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700">
<div class="px-6 py-4 border-b border-neutral-700">
<h2 class="text-lg font-semibold text-white">Report Moderation</h2>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-neutral-900 border-b border-neutral-700">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Report ID</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Title</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Submitted By</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Priority</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Status</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-neutral-700">
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">#2045</td>
<td class="px-6 py-4 text-sm text-white">Database Connection Issues</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">alex.kim@company.com</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-900 text-red-200">High</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-900 text-yellow-200">Pending</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<button class="text-green-400 hover:text-green-300 mr-2">Approve</button>
<button class="text-orange-400 hover:text-orange-300 mr-2">Escalate</button>
<button class="text-red-400 hover:text-red-300">Delete</button>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">#2044</td>
<td class="px-6 py-4 text-sm text-white">API Response Time Degradation</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">maria.santos@company.com</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-900 text-yellow-200">Medium</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-900 text-yellow-200">Pending</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<button class="text-green-400 hover:text-green-300 mr-2">Approve</button>
<button class="text-orange-400 hover:text-orange-300 mr-2">Escalate</button>
<button class="text-red-400 hover:text-red-300">Delete</button>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">#2043</td>
<td class="px-6 py-4 text-sm text-white">UI Rendering Bug</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">james.wilson@company.com</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-900 text-blue-200">Low</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-900 text-yellow-200">Pending</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<button class="text-green-400 hover:text-green-300 mr-2">Approve</button>
<button class="text-orange-400 hover:text-orange-300 mr-2">Escalate</button>
<button class="text-red-400 hover:text-red-300">Delete</button>
</td>
</tr>
<tr class="hover:bg-neutral-750">
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-300">#2042</td>
<td class="px-6 py-4 text-sm text-white">Memory Leak in Production</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-neutral-400">lisa.park@company.com</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-900 text-red-200">High</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-900 text-yellow-200">Pending</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<button class="text-green-400 hover:text-green-300 mr-2">Approve</button>
<button class="text-orange-400 hover:text-orange-300 mr-2">Escalate</button>
<button class="text-red-400 hover:text-red-300">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700">
<div class="px-6 py-4 border-b border-neutral-700">
<h2 class="text-lg font-semibold text-white">System Controls</h2>
</div>
<div class="p-6 space-y-4">
<div class="flex items-center justify-between p-4 bg-neutral-900 rounded-lg border border-neutral-700">
<div>
<h3 class="text-sm font-medium text-white">Maintenance Mode</h3>
<p class="mt-1 text-xs text-neutral-400">Enable maintenance mode to perform system updates</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" class="sr-only peer">
<div
class="w-11 h-6 bg-neutral-700 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-blue-500 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-neutral-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600">
</div>
</label>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<button
class="flex items-center justify-center px-4 py-3 bg-neutral-900 border border-neutral-700 rounded-lg text-sm font-medium text-white hover:bg-neutral-750 transition-colors">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16">
</path>
</svg>
Clear Cache
</button>
<button
class="flex items-center justify-center px-4 py-3 bg-neutral-900 border border-neutral-700 rounded-lg text-sm font-medium text-white hover:bg-neutral-750 transition-colors">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15">
</path>
</svg>
Force Status Refresh
</button>
<button
class="flex items-center justify-center px-4 py-3 bg-yellow-900 border border-yellow-700 rounded-lg text-sm font-medium text-yellow-200 hover:bg-yellow-800 transition-colors">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15">
</path>
</svg>
Restart Services
</button>
</div>
</div>
</div>
<div class="hidden bg-neutral-800 rounded-lg border border-neutral-700 p-12">
<div class="flex flex-col items-center justify-center text-center">
<svg class="w-16 h-16 text-neutral-600 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4">
</path>
</svg>
<h3 class="text-lg font-medium text-white mb-1">No data available</h3>
<p class="text-sm text-neutral-400">Administrative data will appear here when available</p>
</div>
</div>
<div class="hidden bg-neutral-800 rounded-lg border border-neutral-700 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-neutral-900 border-b border-neutral-700">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
User ID</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Name</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Email</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Role</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Status</th>
<th class="px-6 py-3 text-left text-xs font-medium text-neutral-400 uppercase tracking-wider">
Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-neutral-700">
<tr class="animate-pulse">
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-16"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-32"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-48"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-5 bg-neutral-700 rounded-full w-16"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-5 bg-neutral-700 rounded-full w-16"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-24"></div>
</td>
</tr>
<tr class="animate-pulse">
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-16"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-28"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-44"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-5 bg-neutral-700 rounded-full w-16"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-5 bg-neutral-700 rounded-full w-16"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-24"></div>
</td>
</tr>
<tr class="animate-pulse">
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-16"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-36"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-52"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-5 bg-neutral-700 rounded-full w-16"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-5 bg-neutral-700 rounded-full w-16"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="h-4 bg-neutral-700 rounded w-24"></div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>

View File

@@ -0,0 +1,296 @@
<div class="space-y-6">
<!-- Header -->
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 pb-4 border-b border-neutral-800">
<div>
<h1 class="text-2xl font-bold text-white">Status Board</h1>
<p class="text-sm text-neutral-400 mt-1">Live infrastructure and service health</p>
</div>
<div class="flex items-center gap-4 text-xs">
<div class="flex items-center gap-2">
<div class="w-2 h-2 rounded-full bg-green-500"></div>
<span class="text-neutral-300">Operational</span>
</div>
<div class="flex items-center gap-2">
<div class="w-2 h-2 rounded-full bg-yellow-500"></div>
<span class="text-neutral-300">Degraded</span>
</div>
<div class="flex items-center gap-2">
<div class="w-2 h-2 rounded-full bg-red-500"></div>
<span class="text-neutral-300">Outage</span>
</div>
</div>
</div>
<!-- Global Status Summary -->
<section>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4">
<div class="flex items-center justify-between mb-2">
<span class="text-sm text-neutral-400">Overall System</span>
<div class="w-2 h-2 rounded-full bg-green-500"></div>
</div>
<div class="text-2xl font-bold text-white">Operational</div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4">
<div class="flex items-center justify-between mb-2">
<span class="text-sm text-neutral-400">Services Operational</span>
<div class="w-2 h-2 rounded-full bg-green-500"></div>
</div>
<div class="text-2xl font-bold text-white">12/14</div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4">
<div class="flex items-center justify-between mb-2">
<span class="text-sm text-neutral-400">Active Incidents</span>
<div class="w-2 h-2 rounded-full bg-yellow-500"></div>
</div>
<div class="text-2xl font-bold text-white">2</div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4">
<div class="flex items-center justify-between mb-2">
<span class="text-sm text-neutral-400">Regions Affected</span>
<div class="w-2 h-2 rounded-full bg-green-500"></div>
</div>
<div class="text-2xl font-bold text-white">0/8</div>
</div>
</div>
</section>
<!-- Services Status Grid -->
<section>
<h2 class="text-lg font-semibold text-white mb-4">Services Status</h2>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4">
<div class="flex items-start justify-between mb-2">
<div class="flex items-center gap-3">
<div class="w-3 h-3 rounded-full bg-green-500"></div>
<h3 class="font-semibold text-white">Power Grid</h3>
</div>
<span class="px-2 py-1 text-xs font-medium rounded bg-green-500/10 text-green-400 border border-green-500/20">Operational</span>
</div>
<p class="text-sm text-neutral-400 mb-2">Running normally</p>
<p class="text-xs text-neutral-500">Last updated: 2 minutes ago</p>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4">
<div class="flex items-start justify-between mb-2">
<div class="flex items-center gap-3">
<div class="w-3 h-3 rounded-full bg-green-500"></div>
<h3 class="font-semibold text-white">Water Supply</h3>
</div>
<span class="px-2 py-1 text-xs font-medium rounded bg-green-500/10 text-green-400 border border-green-500/20">Operational</span>
</div>
<p class="text-sm text-neutral-400 mb-2">Running normally</p>
<p class="text-xs text-neutral-500">Last updated: 5 minutes ago</p>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4">
<div class="flex items-start justify-between mb-2">
<div class="flex items-center gap-3">
<div class="w-3 h-3 rounded-full bg-yellow-500"></div>
<h3 class="font-semibold text-white">Network Infrastructure</h3>
</div>
<span class="px-2 py-1 text-xs font-medium rounded bg-yellow-500/10 text-yellow-400 border border-yellow-500/20">Degraded</span>
</div>
<p class="text-sm text-neutral-400 mb-2">Partial outage in Zone C</p>
<p class="text-xs text-neutral-500">Last updated: 1 minute ago</p>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4">
<div class="flex items-start justify-between mb-2">
<div class="flex items-center gap-3">
<div class="w-3 h-3 rounded-full bg-green-500"></div>
<h3 class="font-semibold text-white">Road Network</h3>
</div>
<span class="px-2 py-1 text-xs font-medium rounded bg-green-500/10 text-green-400 border border-green-500/20">Operational</span>
</div>
<p class="text-sm text-neutral-400 mb-2">All routes clear</p>
<p class="text-xs text-neutral-500">Last updated: 3 minutes ago</p>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4">
<div class="flex items-start justify-between mb-2">
<div class="flex items-center gap-3">
<div class="w-3 h-3 rounded-full bg-red-500"></div>
<h3 class="font-semibold text-white">Public Transit</h3>
</div>
<span class="px-2 py-1 text-xs font-medium rounded bg-red-500/10 text-red-400 border border-red-500/20">Outage</span>
</div>
<p class="text-sm text-neutral-400 mb-2">Service suspended on Line 5</p>
<p class="text-xs text-neutral-500">Last updated: 8 minutes ago</p>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4">
<div class="flex items-start justify-between mb-2">
<div class="flex items-center gap-3">
<div class="w-3 h-3 rounded-full bg-green-500"></div>
<h3 class="font-semibold text-white">Emergency Services</h3>
</div>
<span class="px-2 py-1 text-xs font-medium rounded bg-green-500/10 text-green-400 border border-green-500/20">Operational</span>
</div>
<p class="text-sm text-neutral-400 mb-2">All systems nominal</p>
<p class="text-xs text-neutral-500">Last updated: 1 minute ago</p>
</div>
</div>
</section>
<!-- Location / Region Status -->
<section>
<h2 class="text-lg font-semibold text-white mb-4">Regional Status</h2>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-neutral-900 border-b border-neutral-700">
<tr>
<th class="text-left px-4 py-3 text-xs font-semibold text-neutral-300 uppercase tracking-wider">Region / Area</th>
<th class="text-left px-4 py-3 text-xs font-semibold text-neutral-300 uppercase tracking-wider">Affected Services</th>
<th class="text-left px-4 py-3 text-xs font-semibold text-neutral-300 uppercase tracking-wider">Status</th>
<th class="text-left px-4 py-3 text-xs font-semibold text-neutral-300 uppercase tracking-wider">Last Update</th>
</tr>
</thead>
<tbody class="divide-y divide-neutral-700">
<tr>
<td class="px-4 py-3 text-sm text-white whitespace-nowrap">North District</td>
<td class="px-4 py-3 text-sm text-neutral-400">None</td>
<td class="px-4 py-3">
<span class="inline-flex items-center gap-2 px-2 py-1 text-xs font-medium rounded bg-green-500/10 text-green-400 border border-green-500/20">
<div class="w-2 h-2 rounded-full bg-green-500"></div>
Operational
</span>
</td>
<td class="px-4 py-3 text-sm text-neutral-500 whitespace-nowrap">2 minutes ago</td>
</tr>
<tr>
<td class="px-4 py-3 text-sm text-white whitespace-nowrap">South District</td>
<td class="px-4 py-3 text-sm text-neutral-400">None</td>
<td class="px-4 py-3">
<span class="inline-flex items-center gap-2 px-2 py-1 text-xs font-medium rounded bg-green-500/10 text-green-400 border border-green-500/20">
<div class="w-2 h-2 rounded-full bg-green-500"></div>
Operational
</span>
</td>
<td class="px-4 py-3 text-sm text-neutral-500 whitespace-nowrap">4 minutes ago</td>
</tr>
<tr>
<td class="px-4 py-3 text-sm text-white whitespace-nowrap">East District</td>
<td class="px-4 py-3 text-sm text-neutral-400">Network, Transit</td>
<td class="px-4 py-3">
<span class="inline-flex items-center gap-2 px-2 py-1 text-xs font-medium rounded bg-yellow-500/10 text-yellow-400 border border-yellow-500/20">
<div class="w-2 h-2 rounded-full bg-yellow-500"></div>
Degraded
</span>
</td>
<td class="px-4 py-3 text-sm text-neutral-500 whitespace-nowrap">1 minute ago</td>
</tr>
<tr>
<td class="px-4 py-3 text-sm text-white whitespace-nowrap">West District</td>
<td class="px-4 py-3 text-sm text-neutral-400">None</td>
<td class="px-4 py-3">
<span class="inline-flex items-center gap-2 px-2 py-1 text-xs font-medium rounded bg-green-500/10 text-green-400 border border-green-500/20">
<div class="w-2 h-2 rounded-full bg-green-500"></div>
Operational
</span>
</td>
<td class="px-4 py-3 text-sm text-neutral-500 whitespace-nowrap">3 minutes ago</td>
</tr>
<tr>
<td class="px-4 py-3 text-sm text-white whitespace-nowrap">Central District</td>
<td class="px-4 py-3 text-sm text-neutral-400">None</td>
<td class="px-4 py-3">
<span class="inline-flex items-center gap-2 px-2 py-1 text-xs font-medium rounded bg-green-500/10 text-green-400 border border-green-500/20">
<div class="w-2 h-2 rounded-full bg-green-500"></div>
Operational
</span>
</td>
<td class="px-4 py-3 text-sm text-neutral-500 whitespace-nowrap">5 minutes ago</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<!-- Incident Snapshot -->
<section>
<h2 class="text-lg font-semibold text-white mb-4">Active Incidents</h2>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 divide-y divide-neutral-700">
<div class="p-4">
<div class="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3 mb-2">
<h3 class="font-semibold text-white">Network connectivity issues in Zone C</h3>
<span class="px-2 py-1 text-xs font-medium rounded bg-yellow-500/10 text-yellow-400 border border-yellow-500/20 self-start">High</span>
</div>
<div class="flex items-center gap-3 text-sm">
<span class="px-2 py-1 text-xs font-medium rounded bg-blue-500/10 text-blue-400 border border-blue-500/20">Investigating</span>
<span class="text-neutral-500">15 minutes ago</span>
</div>
</div>
<div class="p-4">
<div class="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3 mb-2">
<h3 class="font-semibold text-white">Transit Line 5 service disruption</h3>
<span class="px-2 py-1 text-xs font-medium rounded bg-red-500/10 text-red-400 border border-red-500/20 self-start">Critical</span>
</div>
<div class="flex items-center gap-3 text-sm">
<span class="px-2 py-1 text-xs font-medium rounded bg-orange-500/10 text-orange-400 border border-orange-500/20">Identified</span>
<span class="text-neutral-500">32 minutes ago</span>
</div>
</div>
</div>
</section>
<!-- Loading State (Hidden by default) -->
<div class="space-y-6 hidden" data-loading-state>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4 animate-pulse">
<div class="h-4 bg-neutral-700 rounded w-1/2 mb-3"></div>
<div class="h-8 bg-neutral-700 rounded w-3/4"></div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4 animate-pulse">
<div class="h-4 bg-neutral-700 rounded w-1/2 mb-3"></div>
<div class="h-8 bg-neutral-700 rounded w-3/4"></div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4 animate-pulse">
<div class="h-4 bg-neutral-700 rounded w-1/2 mb-3"></div>
<div class="h-8 bg-neutral-700 rounded w-3/4"></div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4 animate-pulse">
<div class="h-4 bg-neutral-700 rounded w-1/2 mb-3"></div>
<div class="h-8 bg-neutral-700 rounded w-3/4"></div>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4 animate-pulse">
<div class="h-5 bg-neutral-700 rounded w-1/3 mb-3"></div>
<div class="h-4 bg-neutral-700 rounded w-full mb-2"></div>
<div class="h-3 bg-neutral-700 rounded w-1/4"></div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4 animate-pulse">
<div class="h-5 bg-neutral-700 rounded w-1/3 mb-3"></div>
<div class="h-4 bg-neutral-700 rounded w-full mb-2"></div>
<div class="h-3 bg-neutral-700 rounded w-1/4"></div>
</div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-4">
<div class="space-y-3">
<div class="h-10 bg-neutral-700 rounded animate-pulse"></div>
<div class="h-10 bg-neutral-700 rounded animate-pulse"></div>
<div class="h-10 bg-neutral-700 rounded animate-pulse"></div>
</div>
</div>
</div>
<!-- Empty State for Incidents -->
<div class="bg-neutral-800 rounded-lg border border-neutral-700 p-12 text-center hidden" data-empty-incidents>
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-green-500/10 mb-4">
<svg class="w-8 h-8 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
</div>
<p class="text-lg font-semibold text-white mb-1">No active incidents</p>
<p class="text-sm text-neutral-400">All systems are operating normally</p>
</div>
</div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -1,6 +1,6 @@
{ {
"name": "SteamsTube", "name": "Infra-UNI",
"short_name": "SteamsTube", "short_name": "Infra-UNI",
"icons": [ "icons": [
{ {
"src": "/web-app-manifest-192x192.png", "src": "/web-app-manifest-192x192.png",
@@ -15,7 +15,7 @@
"purpose": "maskable" "purpose": "maskable"
} }
], ],
"theme_color": "#171717", "theme_color": "#ffffff",
"background_color": "#171717", "background_color": "#ffffff",
"display": "standalone" "display": "standalone"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 KiB

View File

@@ -0,0 +1,18 @@
function copyToClipboard(text, btnId) {
navigator.clipboard.writeText(text).then(() => {
const btn = document.getElementById(btnId);
const icon = btn.querySelector('svg');
// Success State
btn.classList.add('bg-green-500/20', 'text-green-400', 'border-green-500/50');
btn.classList.remove('text-neutral-400');
icon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>';
// Revert
setTimeout(() => {
btn.classList.remove('bg-green-500/20', 'text-green-400', 'border-green-500/50');
btn.classList.add('text-neutral-400');
icon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/>';
}, 2000);
});
}

View File

@@ -0,0 +1,100 @@
async function loadDashboardMetrics() {
// TODO: Replace with actual API call
// const response = await fetch('/api/dashboard/metrics');
// const data = await response.json();
// Placeholder for future implementation
const metricsData = {
totalReports: null,
activeIssues: null,
resolvedIssues: null,
criticalAlerts: null,
};
// Update DOM with API data
document.querySelector('[data-value="total-reports"]').textContent =
metricsData.totalReports !== null ? metricsData.totalReports : "—";
document.querySelector('[data-value="active-issues"]').textContent =
metricsData.activeIssues !== null ? metricsData.activeIssues : "—";
document.querySelector('[data-value="resolved-issues"]').textContent =
metricsData.resolvedIssues !== null ? metricsData.resolvedIssues : "—";
document.querySelector('[data-value="critical-alerts"]').textContent =
metricsData.criticalAlerts !== null ? metricsData.criticalAlerts : "—";
}
async function loadRecentActivity() {
// TODO: Replace with actual API call
// const response = await fetch('/api/activity/recent');
// const activities = await response.json();
const activities = [];
const listContainer = document.getElementById("activity-list");
const skeleton = document.getElementById("activity-skeleton");
const empty = document.getElementById("activity-empty");
const items = document.getElementById("activity-items");
skeleton.classList.add("hidden");
if (activities.length === 0) {
listContainer.setAttribute("data-status", "empty");
empty.classList.remove("hidden");
} else {
listContainer.setAttribute("data-status", "loaded");
items.classList.remove("hidden");
// Render activity items
activities.forEach((activity) => {
const item = createActivityItem(activity);
items.appendChild(item);
});
}
}
function createActivityItem(activity) {
const div = document.createElement("div");
div.className = "px-6 py-4 flex items-start space-x-4";
div.setAttribute("data-activity-id", activity.id);
const statusColors = {
critical: "bg-red-400",
warning: "bg-yellow-400",
info: "bg-blue-400",
success: "bg-green-400",
};
div.innerHTML = `
<div class="w-2 h-2 mt-2 rounded-full ${
statusColors[activity.severity] || "bg-gray-600"
}"></div>
<div class="flex-1 min-w-0">
<p class="text-sm text-gray-200">${activity.message}</p>
<div class="mt-1 flex items-center space-x-3">
<span class="text-xs text-gray-500">${
activity.timestamp
}</span>
<span class="px-2 py-0.5 text-xs font-medium rounded ${getBadgeClass(
activity.status
)}">${activity.status}</span>
</div>
</div>
`;
return div;
}
function getBadgeClass(status) {
const classes = {
new: "bg-blue-900/40 text-blue-400",
"in-progress": "bg-yellow-900/40 text-yellow-400",
resolved: "bg-green-900/40 text-green-400",
closed: "bg-gray-800 text-gray-400",
};
return classes[status] || "bg-gray-800 text-gray-400";
}
// Initialize dashboard on page load
document.addEventListener("DOMContentLoaded", () => {
loadDashboardMetrics();
setTimeout(() => loadRecentActivity(), 500);
});

View File

@@ -0,0 +1,96 @@
<div class="max-w-6xl mx-auto w-full">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
<div class="group bg-neutral-800 rounded-lg border border-neutral-700/50 p-4 shadow-sm hover:border-blue-500/30 transition-all duration-300 flex items-center justify-between">
<div>
<h3 class="text-xs font-semibold text-neutral-400 uppercase tracking-wider group-hover:text-blue-400 transition-colors">Total Reports</h3>
<p class="text-2xl font-bold text-white mt-1">128</p>
<p class="text-[10px] text-neutral-500 mt-1">All submissions overview</p>
</div>
<div class="p-3 bg-blue-500/10 rounded-lg group-hover:bg-blue-500/20 transition-colors">
<svg class="w-6 h-6 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 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" />
</svg>
</div>
</div>
<div class="group bg-neutral-800 rounded-lg border border-neutral-700/50 p-4 shadow-sm hover:border-yellow-500/30 transition-all duration-300 flex items-center justify-between">
<div>
<h3 class="text-xs font-semibold text-neutral-400 uppercase tracking-wider group-hover:text-yellow-400 transition-colors">Active Issues</h3>
<p class="text-2xl font-bold text-white mt-1">42</p>
<p class="text-[10px] text-neutral-500 mt-1">In progress / Open</p>
</div>
<div class="p-3 bg-yellow-500/10 rounded-lg group-hover:bg-yellow-500/20 transition-colors">
<svg class="w-6 h-6 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
</div>
<div class="group bg-neutral-800 rounded-lg border border-neutral-700/50 p-4 shadow-sm hover:border-green-500/30 transition-all duration-300 flex items-center justify-between">
<div>
<h3 class="text-xs font-semibold text-neutral-400 uppercase tracking-wider group-hover:text-green-400 transition-colors">Resolved</h3>
<p class="text-2xl font-bold text-white mt-1">86</p>
<p class="text-[10px] text-neutral-500 mt-1">Successfully closed</p>
</div>
<div class="p-3 bg-green-500/10 rounded-lg group-hover:bg-green-500/20 transition-colors">
<svg class="w-6 h-6 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
</div>
</div>
<div class="bg-neutral-800 rounded-lg border border-neutral-700 overflow-hidden shadow-sm">
<div class="px-4 py-3 border-b border-neutral-700 flex items-center justify-between bg-neutral-900/30">
<h3 class="text-sm font-semibold text-white">Recent Activity</h3>
<button class="text-xs text-blue-400 hover:text-blue-300 font-medium transition-colors">View All</button>
</div>
<div class="divide-y divide-neutral-700/50">
<div class="px-4 py-3 hover:bg-neutral-700/30 transition-colors flex items-center gap-3">
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-green-500/10 border border-green-500/20 flex items-center justify-center">
<svg class="w-4 h-4 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
</div>
<div class="flex-1 min-w-0 grid gap-0.5">
<div class="flex items-center justify-between">
<p class="text-sm font-medium text-neutral-200 truncate">
Issue <span class="text-white hover:underline cursor-pointer">#1231</span> Resolved
</p>
<span class="text-[10px] text-neutral-500 whitespace-nowrap">2h ago</span>
</div>
<p class="text-xs text-neutral-500 truncate">Water leakage in park <span>23/v/kpc-cst/33</span></p>
</div>
</div>
<div class="px-4 py-3 hover:bg-neutral-700/30 transition-colors flex items-center gap-3">
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-blue-500/10 border border-blue-500/20 flex items-center justify-center">
<svg class="w-4 h-4 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/></svg>
</div>
<div class="flex-1 min-w-0 grid gap-0.5">
<div class="flex items-center justify-between">
<p class="text-sm font-medium text-neutral-200 truncate">Issue 1234 submitted</p>
<span class="text-[10px] text-neutral-500 whitespace-nowrap">5h ago</span>
</div>
<p class="text-xs text-neutral-500 truncate">Pothole on Main Street <span>23/v/kpc-cst/36</span></p>
</div>
</div>
<div class="px-4 py-3 hover:bg-neutral-700/30 transition-colors flex items-center gap-3">
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-yellow-500/10 border border-yellow-500/20 flex items-center justify-center">
<svg class="w-4 h-4 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
</div>
<div class="flex-1 min-w-0 grid gap-0.5">
<div class="flex items-center justify-between">
<p class="text-sm font-medium text-neutral-200 truncate">Status: In Progress</p>
<span class="text-[10px] text-neutral-500 whitespace-nowrap">1d ago</span>
</div>
<p class="text-xs text-neutral-500 truncate">Broken Street Light <span>23/v/kpc-cst/37</span></p>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,511 @@
<?php
function words($text, $limit = 4) {
$w = preg_split('/\s+/', trim($text));
return count($w) > $limit
? implode(' ', array_slice($w, 0, $limit)) . '…'
: $text;
}
?>
<div class="max-w-7xl mx-auto space-y-6">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div>
<h1 class="text-2xl md:text-3xl font-bold text-white tracking-tight">Campus Reports</h1>
<p class="mt-1 text-sm text-neutral-400">Manage facility and infrastructure issues</p>
</div>
<button onclick="document.getElementById('createModal').classList.remove('hidden')"
class="w-full sm:w-auto px-5 py-2.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-semibold rounded-lg shadow-lg shadow-blue-900/20 transition-all flex items-center justify-center gap-2 group">
<svg class="w-4 h-4 transition-transform group-hover:rotate-90" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
</svg>
Create Report
</button>
</div>
<div class="bg-neutral-800 rounded-xl border border-neutral-700 p-4 shadow-sm">
<div class="flex flex-col lg:flex-row gap-4 justify-between">
<div class="flex overflow-x-auto pb-2 lg:pb-0 gap-2 no-scrollbar">
<button
class="px-4 py-2 bg-blue-600/10 text-blue-400 border border-blue-600/20 text-sm font-medium rounded-lg whitespace-nowrap">All
Reports</button>
<button
class="px-4 py-2 hover:bg-neutral-700 text-neutral-400 hover:text-white text-sm font-medium rounded-lg transition-colors whitespace-nowrap">Open</button>
<button
class="px-4 py-2 hover:bg-neutral-700 text-neutral-400 hover:text-white text-sm font-medium rounded-lg transition-colors whitespace-nowrap">In
Progress</button>
<button
class="px-4 py-2 hover:bg-neutral-700 text-neutral-400 hover:text-white text-sm font-medium rounded-lg transition-colors whitespace-nowrap">Resolved</button>
</div>
<div class="flex flex-col sm:flex-row gap-3">
<div class="relative min-w-[200px]">
<select
class="w-full appearance-none px-4 py-2 bg-neutral-900 border border-neutral-700 rounded-lg text-sm text-neutral-300 focus:outline-none focus:ring-2 focus:ring-blue-500/50 focus:border-blue-500 transition-all cursor-pointer">
<option>Last 7 days</option>
<option>Last 30 days</option>
<option>Last 90 days</option>
<option>All time</option>
</select>
<svg class="absolute right-3 top-2.5 h-4 w-4 text-neutral-500 pointer-events-none" fill="none"
stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</div>
<div class="relative w-full sm:w-64">
<input type="text" placeholder="Search reports..."
class="w-full pl-10 pr-4 py-2 bg-neutral-900 border border-neutral-700 rounded-lg text-sm text-white placeholder-neutral-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 focus:border-blue-500 transition-all">
<svg class="absolute left-3 top-2.5 h-4 w-4 text-neutral-500" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 md:hidden">
<div
class="bg-neutral-800 hover:bg-neutral-750 transition-colors duration-200 rounded-xl border border-neutral-700 p-4 space-y-3 group cursor-default">
<div class="flex justify-between items-start">
<div>
<span
class="text-xs font-mono text-neutral-500 hover:text-blue-400 hover:underline cursor-pointer transition-colors">#1234</span>
<h3 class="font-semibold text-white mt-1">Pothole on Main Street</h3>
</div>
<span
class="inline-flex px-2.5 py-1 text-xs font-medium rounded-full bg-blue-900/30 text-blue-400 border border-blue-700/50">Open</span>
</div>
<div class="flex items-center gap-2 text-sm text-neutral-400">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Main St. & 4th Ave
</div>
<div class="grid grid-cols-2 gap-2 py-2 border-t border-b border-neutral-700/50">
<div>
<p class="text-xs text-neutral-500">Category</p>
<p class="text-sm text-neutral-300">Road Damage</p>
</div>
<div>
<p class="text-xs text-neutral-500">Priority</p>
<p class="text-sm text-red-400 font-medium">High</p>
</div>
</div>
<div class="flex items-center justify-between pt-1">
<div class="flex items-center gap-2 text-xs text-neutral-500">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
Dec 15, 2024
</div>
<button class="text-blue-400 text-sm font-medium hover:text-blue-300 transition-colors">View Details
&rarr;</button>
</div>
</div>
<div
class="bg-neutral-800 hover:bg-neutral-750 transition-colors duration-200 rounded-xl border border-neutral-700 p-4 space-y-3 group cursor-default">
<div class="flex justify-between items-start">
<div>
<span
class="text-xs font-mono text-neutral-500 hover:text-blue-400 hover:underline cursor-pointer transition-colors">#1233</span>
<h3 class="font-semibold text-white mt-1">Broken street light</h3>
</div>
<span
class="inline-flex px-2.5 py-1 text-xs font-medium rounded-full bg-yellow-900/30 text-yellow-500 border border-yellow-700/50">In
Progress</span>
</div>
<div class="flex items-center gap-2 text-sm text-neutral-400">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Sector 7 Park
</div>
<div class="grid grid-cols-2 gap-2 py-2 border-t border-b border-neutral-700/50">
<div>
<p class="text-xs text-neutral-500">Category</p>
<p class="text-sm text-neutral-300">Street Lighting</p>
</div>
<div>
<p class="text-xs text-neutral-500">Priority</p>
<p class="text-sm text-orange-400 font-medium">Medium</p>
</div>
</div>
<div class="flex items-center justify-between pt-1">
<div class="flex items-center gap-2 text-xs text-neutral-500">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
Dec 14, 2024
</div>
<button class="text-blue-400 text-sm font-medium hover:text-blue-300 transition-colors">View Details
&rarr;</button>
</div>
</div>
<div
class="bg-neutral-800 hover:bg-neutral-750 transition-colors duration-200 rounded-xl border border-neutral-700 p-4 space-y-3 group cursor-default">
<div class="flex justify-between items-start">
<div>
<span
class="text-xs font-mono text-neutral-500 hover:text-blue-400 hover:underline cursor-pointer transition-colors">#1232</span>
<h3 class="font-semibold text-white mt-1">Water leakage in park</h3>
</div>
<span
class="inline-flex px-2.5 py-1 text-xs font-medium rounded-full bg-green-900/30 text-green-400 border border-green-700/50">Resolved</span>
</div>
<div class="flex items-center gap-2 text-sm text-neutral-400">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Central Park Zone B
</div>
<div class="grid grid-cols-2 gap-2 py-2 border-t border-b border-neutral-700/50">
<div>
<p class="text-xs text-neutral-500">Category</p>
<p class="text-sm text-neutral-300">Water Supply</p>
</div>
<div>
<p class="text-xs text-neutral-500">Priority</p>
<p class="text-sm text-green-400 font-medium">Low</p>
</div>
</div>
<div class="flex items-center justify-between pt-1">
<div class="flex items-center gap-2 text-xs text-neutral-500">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
Dec 12, 2024
</div>
<button class="text-blue-400 text-sm font-medium hover:text-blue-300 transition-colors">View Details
&rarr;</button>
</div>
</div>
</div>
<div class="hidden md:block bg-neutral-800 rounded-xl border border-neutral-700 overflow-hidden shadow-sm">
<div class="overflow-x-auto custom-scrollbar">
<table class="w-full">
<thead class="bg-neutral-900/50 border-b border-neutral-700">
<tr>
<th class="px-6 py-4 text-left text-xs font-semibold text-neutral-400 uppercase tracking-wider">
ID</th>
<th class="px-6 py-4 text-left text-xs font-semibold text-neutral-400 uppercase tracking-wider">
Title</th>
<th class="px-6 py-4 text-left text-xs font-semibold text-neutral-400 uppercase tracking-wider">
Category</th>
<th class="px-6 py-4 text-left text-xs font-semibold text-neutral-400 uppercase tracking-wider">
Status</th>
<th class="px-6 py-4 text-left text-xs font-semibold text-neutral-400 uppercase tracking-wider">
Priority</th>
<th
class="px-6 py-4 text-center text-xs font-semibold text-neutral-400 uppercase tracking-wider">
Image</th>
<th
class="px-6 py-4 text-center text-xs font-semibold text-neutral-400 uppercase tracking-wider">
G-Map</th>
<th class="px-6 py-4 text-left text-xs font-semibold text-neutral-400 uppercase tracking-wider">
Date</th>
</tr>
</thead>
<tbody class="divide-y divide-neutral-700/50">
<tr class="hover:bg-neutral-700/30 transition-colors duration-200 group">
<td
class="px-6 py-4 text-sm font-mono text-neutral-500 group-hover:text-neutral-300 hover:text-blue-400 hover:underline cursor-pointer transition-colors">
#1234</td>
<td class="px-6 py-4">
<div class="text-sm font-medium text-white ">Pothole on Main Street</div>
<div class="text-xs text-neutral-500 mt-0.5">Reported by <span>23/v/kpc-cst/36</span></div>
</td>
<td class="px-6 py-4 text-sm text-neutral-300">Road Damage</td>
<td class="px-6 py-4">
<span
class="inline-flex items-center px-2.5 py-0.5 text-xs font-medium rounded-full bg-blue-900/30 text-blue-400 border border-blue-700/50">
<span class="w-1.5 h-1.5 mr-1.5 bg-blue-400 rounded-full"></span>
Open
</span>
</td>
<td class="px-6 py-4 text-sm text-red-400 font-medium">High</td>
<td class="px-6 py-4 text-center">
<button class="p-2 hover:bg-neutral-700 rounded-lg text-neutral-400 hover:text-white transition-colors"
title="View Image">
<svg class="h-5 w-5 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
</button>
</td>
<td class="px-6 py-4 text-center">
<button class="p-2 hover:bg-neutral-700 rounded-lg text-blue-500 hover:text-blue-400 transition-colors"
title="View Map">
<svg class="h-5 w-5 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
</button>
</td>
<td class="px-6 py-4 text-sm text-neutral-400">Dec 15, 2024</td>
</tr>
<tr class="hover:bg-neutral-700/30 transition-colors duration-200 group">
<td
class="px-6 py-4 text-sm font-mono text-neutral-500 group-hover:text-neutral-300 hover:text-blue-400 hover:underline cursor-pointer transition-colors">
#1233</td>
<td class="px-6 py-4">
<div class="text-sm font-medium text-white">Broken street light</div>
<div class="text-xs text-neutral-500 mt-0.5">Reported by <span>23/v/kpc-cst/37</span></div>
</td>
<td class="px-6 py-4 text-sm text-neutral-300">Street Lighting</td>
<td class="px-6 py-4">
<span
class="inline-flex items-center px-2.5 py-0.5 text-xs font-medium rounded-full bg-yellow-900/30 text-yellow-500 border border-yellow-700/50">
<span class="w-1.5 h-1.5 mr-1.5 bg-yellow-500 rounded-full animate-pulse"></span>
In Progress
</span>
</td>
<td class="px-6 py-4 text-sm text-orange-400 font-medium">Medium</td>
<td class="px-6 py-4 text-center">
<button class="p-2 hover:bg-neutral-700 rounded-lg text-neutral-400 hover:text-white transition-colors"
title="View Image">
<svg class="h-5 w-5 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
</button>
</td>
<td class="px-6 py-4 text-center">
<button class="p-2 hover:bg-neutral-700 rounded-lg text-blue-500 hover:text-blue-400 transition-colors"
title="View Map">
<svg class="h-5 w-5 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
</button>
</td>
<td class="px-6 py-4 text-sm text-neutral-400">Dec 14, 2024</td>
</tr>
<tr class="hover:bg-neutral-700/30 transition-colors duration-200 group">
<td
class="px-6 py-4 text-sm font-mono text-neutral-500 group-hover:text-neutral-300 hover:text-blue-400 hover:underline cursor-pointer transition-colors">
#1232</td>
<td class="px-6 py-4">
<div class="text-sm font-medium text-white">Water leakage in park</div>
<div class="text-xs text-neutral-500 mt-0.5">Reported by <span>23/v/kpc-cst/33</span></div>
</td>
<td class="px-6 py-4 text-sm text-neutral-300">Water Supply</td>
<td class="px-6 py-4">
<span
class="inline-flex items-center px-2.5 py-0.5 text-xs font-medium rounded-full bg-green-900/30 text-green-400 border border-green-700/50">
<span class="w-1.5 h-1.5 mr-1.5 bg-green-400 rounded-full"></span>
Resolved
</span>
</td>
<td class="px-6 py-4 text-sm text-green-400 font-medium">Low</td>
<td class="px-6 py-4 text-center">
<button class="p-2 hover:bg-neutral-700 rounded-lg text-neutral-400 hover:text-white transition-colors"
title="View Image">
<svg class="h-5 w-5 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
</button>
</td>
<td class="px-6 py-4 text-center">
<button class="p-2 hover:bg-neutral-700 rounded-lg text-blue-500 hover:text-blue-400 transition-colors"
title="View Map">
<svg class="h-5 w-5 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
</button>
</td>
<td class="px-6 py-4 text-sm text-neutral-400">Dec 12, 2024</td>
</tr>
</tbody>
</table>
</div>
<div class="bg-neutral-900 border-t border-neutral-700 px-6 py-4 flex items-center justify-between">
<span class="text-sm text-neutral-400">Showing <span class="text-white font-medium">1-3</span> of <span
class="text-white font-medium">128</span></span>
<div class="flex gap-2">
<button
class="px-3 py-1 bg-neutral-800 hover:bg-neutral-700 border border-neutral-700 rounded-lg text-sm transition-colors disabled:opacity-50"
disabled>Previous</button>
<button
class="px-3 py-1 bg-neutral-800 hover:bg-neutral-700 border border-neutral-700 rounded-lg text-sm transition-colors">Next</button>
</div>
</div>
</div>
</div>
<div id="createModal" class="hidden fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-title" role="dialog"
aria-modal="true">
<div class="flex items-end sm:items-center justify-center min-h-full p-4 text-center sm:p-0">
<div class="fixed inset-0 bg-neutral-900/80 backdrop-blur-sm transition-opacity" aria-hidden="true"
onclick="document.getElementById('createModal').classList.add('hidden')"></div>
<div
class="relative bg-neutral-800 rounded-2xl border border-neutral-700 text-left shadow-2xl transform transition-all sm:my-8 sm:w-full sm:max-w-2xl">
<div class="px-6 py-4 border-b border-neutral-700 flex justify-between items-center">
<h2 class="text-xl font-semibold text-white">Create Report</h2>
<button onclick="document.getElementById('createModal').classList.add('hidden')"
class="text-neutral-400 hover:text-white transition-colors">
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="px-6 py-6 space-y-6">
<form>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="col-span-1 md:col-span-2">
<label class="block text-sm font-medium text-neutral-300 mb-2">Report Title <span class="text-red-500">*</span></label>
<input type="text" required
class="w-full px-4 py-2.5 bg-neutral-900 border border-neutral-700 rounded-lg text-white placeholder-neutral-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 focus:border-blue-500 transition-all"
placeholder="E.g., Large pothole near school">
</div>
<div>
<label class="block text-sm font-medium text-neutral-300 mb-2">Category <span class="text-red-500">*</span></label>
<div class="relative">
<select required
class="w-full px-4 py-2.5 bg-neutral-900 border border-neutral-700 rounded-lg text-white appearance-none focus:outline-none focus:ring-2 focus:ring-blue-500/50 transition-all cursor-pointer">
<option value="" disabled selected>Select a category...</option>
<option>WiFi & Network Issue</option>
<option>Electrical Issue</option>
<option>Water & Plumbing</option>
<option>HVAC (AC/Heating)</option>
<option>Furniture & Fixtures</option>
<option>Cleaning & Janitorial</option>
<option>Security & Safety</option>
<option>Road & Pathway Damage</option>
<option>Other</option>
</select>
<svg class="absolute right-3 top-3 h-4 w-4 text-neutral-500 pointer-events-none"
fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7" />
</svg>
</div>
</div>
<div>
<label class="block text-sm font-medium text-neutral-300 mb-2">Priority <span class="text-red-500">*</span></label>
<div class="flex bg-neutral-900 rounded-lg p-1 border border-neutral-700">
<label class="flex-1 text-center cursor-pointer">
<input type="radio" name="priority" class="sr-only peer">
<span
class="block px-2 py-1.5 rounded-md text-sm text-neutral-400 peer-checked:bg-neutral-800 peer-checked:text-green-400 peer-checked:shadow-sm transition-all">Low</span>
</label>
<label class="flex-1 text-center cursor-pointer">
<input type="radio" name="priority" class="sr-only peer">
<span
class="block px-2 py-1.5 rounded-md text-sm text-neutral-400 peer-checked:bg-neutral-800 peer-checked:text-white peer-checked:shadow-sm transition-all">Med</span>
</label>
<label class="flex-1 text-center cursor-pointer">
<input type="radio" name="priority" class="sr-only peer" checked>
<span
class="block px-2 py-1.5 rounded-md text-sm text-neutral-400 peer-checked:bg-neutral-800 peer-checked:text-white peer-checked:shadow-sm transition-all">High</span>
</label>
</div>
</div>
</div>
<div class="mt-6">
<div class="flex justify-between items-center mb-2">
<label class="block text-sm font-medium text-neutral-300">Location <span class="text-red-500">*</span></label>
<button type="button" class="text-xs text-blue-400 hover:text-blue-300 flex items-center gap-1">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Use Current Location
</button>
</div>
<div class="relative mb-3">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="h-4 w-4 text-neutral-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
</svg>
</div>
<input type="text" required
class="w-full pl-10 pr-4 py-2.5 bg-neutral-900 border border-neutral-700 rounded-lg text-white placeholder-neutral-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 focus:border-blue-500 transition-all text-sm"
placeholder="Paste Google Maps link or enter address...">
</div>
</div>
<div class="mt-6">
<label class="block text-sm font-medium text-neutral-300 mb-2">Evidence <span class="text-red-500">*</span></label>
<div class="relative">
<input type="file" required id="file-upload" class="hidden">
<label for="file-upload"
class="block border-2 border-dashed border-neutral-700 rounded-xl p-8 text-center hover:border-blue-500/50 hover:bg-neutral-900/50 transition-all cursor-pointer group">
<div
class="w-12 h-12 bg-neutral-800 rounded-full flex items-center justify-center mx-auto mb-3 group-hover:scale-110 transition-transform">
<svg class="h-6 w-6 text-neutral-400 group-hover:text-blue-400" fill="none"
stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
</div>
<p class="text-sm text-neutral-300 font-medium">Click to upload or drag and drop</p>
<p class="text-xs text-neutral-500 mt-1"> PNG, JPG, JPEG (max. 2MB)</p>
</label>
</div>
</div>
</div>
<div class="px-6 py-4 border-t border-neutral-700 bg-neutral-800/50 flex flex-col sm:flex-row sm:items-center justify-between gap-4 rounded-b-2xl">
<span class="text-xs text-neutral-500 order-2 sm:order-1 text-center sm:text-left">
<span class="text-red-500">*</span> All fields marked above are required
</span>
<div class="flex gap-3 order-1 sm:order-2 w-full sm:w-auto justify-end">
<button type="button" onclick="document.getElementById('createModal').classList.add('hidden')"
class="px-5 py-2 text-neutral-300 hover:text-white text-sm font-medium transition-colors">Cancel</button>
<button type="submit"
class="px-5 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg shadow-lg shadow-blue-900/20 transition-all">Submit
Report</button>
</div>
</div>
</form>
</div>
</div>
</div>

View File

@@ -1,94 +0,0 @@
<?php
function numberToWords($num)
{
$words = [
0 => 'Zero',
1 => 'One',
2 => 'Two',
3 => 'Three',
4 => 'Four',
5 => 'Five',
6 => 'Six',
7 => 'Seven',
8 => 'Eight',
9 => 'Nine',
10 => 'Ten',
11 => 'Eleven',
12 => 'Twelve',
13 => 'Thirteen',
14 => 'Fourteen',
15 => 'Fifteen',
16 => 'Sixteen',
17 => 'Seventeen',
18 => 'Eighteen',
19 => 'Nineteen',
20 => 'Twenty',
30 => 'Thirty',
40 => 'Forty',
50 => 'Fifty',
60 => 'Sixty',
70 => 'Seventy',
80 => 'Eighty',
90 => 'Ninety'
];
if ($num <= 20) return $words[$num];
if ($num < 100) {
$tens = intval($num / 10) * 10;
$ones = $num % 10;
return $words[$tens] . ($ones ? ' ' . $words[$ones] : '');
}
return strval($num);
}
function timeAgo($datetime)
{
$now = new DateTime();
$time = new DateTime($datetime);
$diff = $now->diff($time);
$isFuture = $time > $now;
if ($diff->y >= 10) return 'A decade ago';
if ($diff->y > 0) return ($diff->y == 1 ? 'A' : numberToWords($diff->y)) . ' year' . ($diff->y > 1 ? 's' : '') . ' ago';
if ($diff->m > 0) return ($diff->m == 1 ? 'A' : numberToWords($diff->m)) . ' month' . ($diff->m > 1 ? 's' : '') . ' ago';
if ($diff->d >= 7) {
$weeks = floor($diff->d / 7);
return ($weeks == 1 ? 'A' : numberToWords($weeks)) . ' week' . ($weeks > 1 ? 's' : '') . ' ago';
}
if ($diff->d > 1) return numberToWords($diff->d) . ' days ago';
if ($diff->d == 1) return $isFuture ? 'The next day' : 'The previous day';
if ($diff->h > 0) return numberToWords($diff->h) . ' hour' . ($diff->h > 1 ? 's' : '') . ' ago';
if ($diff->i > 0) return numberToWords($diff->i) . ' minute' . ($diff->i > 1 ? 's' : '') . ' ago';
if ($diff->s > 0) return numberToWords($diff->s) . ' second' . ($diff->s > 1 ? 's' : '') . ' ago';
return 'Just now';
}
function formatDuration($duration)
{
$parts = explode(':', $duration);
if (count($parts) == 2) {
$minutes = intval($parts[0]);
$seconds = intval($parts[1]);
if ($minutes > 0 && $seconds > 0) return $minutes . 'm ' . $seconds . 's';
if ($minutes > 0) return $minutes . 'm';
return $seconds . ' s';
} elseif (count($parts) == 3) {
$hours = intval($parts[0]);
$minutes = intval($parts[1]);
$seconds = intval($parts[2]);
$result = '';
if ($hours > 0) $result .= $hours . 'h';
if ($minutes > 0) $result .= ($result ? ' ' : '') . $minutes . 'm';
if ($seconds > 0) $result .= ($result ? ' ' : '') . $seconds . 's';
return $result;
}
return $duration;
}
function formatViews($num)
{
if ($num >= 1000000000) return round($num / 1000000000, 1) . 'B';
if ($num >= 1000000) return round($num / 1000000, 1) . 'M';
if ($num >= 1000) return round($num / 1000, 1) . 'k';
return $num;
}

View File

@@ -1,6 +1,7 @@
<?php <?php
require __DIR__ . '/vendor/autoload.php'; require dirname(__DIR__) . '/core/vendor/autoload.php';
use Dotenv\Dotenv; use Dotenv\Dotenv;
$dotenv = Dotenv::createImmutable(dirname(__DIR__)); $dotenv = Dotenv::createImmutable(dirname(__DIR__));
$dotenv->load(); $dotenv->load();
?>

View File

@@ -1,726 +0,0 @@
<?php
// A raw translation file
// Array of translations per language
$texts = [
'English (United Kingdom)' => [
'sign_in' => 'Sign in',
'continue_to' => 'to continue to',
'email_placeholder' => 'Email or username',
'forgot_email' => 'Forgot the email?',
'guest_mode' => 'Not your desktop? Use Private Browsing windows to sign in.',
'learn_more' => 'Learn more about the Guest mode',
'create_account' => 'Create an account',
'next' => 'Confirm',
'help' => 'Support',
'privacy' => 'Privacy Policy',
'terms' => 'Terms of Service',
'bug' => 'Found a bug? Help us fix it'
],
'English (United States)' => [
'sign_in' => 'Log in',
'continue_to' => 'to continue to',
'email_placeholder' => 'Email or username',
'forgot_email' => 'Forgot your email?',
'guest_mode' => 'Not your personal computer? Use Incognito mode to sign in.',
'learn_more' => 'Learn more about using Guest mode',
'create_account' => 'Create account',
'next' => 'Continue',
'help' => 'Help',
'privacy' => 'Privacy',
'terms' => 'Terms',
'bug' => 'Spotted a bug? Help us fix it'
],
'Español (España)' => [
'sign_in' => 'Iniciar sesión',
'continue_to' => 'para continuar a',
'email_placeholder' => 'Correo electrónico o usuario',
'forgot_email' => '¿Olvidaste el correo?',
'guest_mode' => '¿No es tu escritorio? Usa ventanas de navegación privada para iniciar sesión.',
'learn_more' => 'Más información sobre el modo invitado',
'create_account' => 'Crear una cuenta',
'next' => 'Confirmar',
'help' => 'Soporte',
'privacy' => 'Política de privacidad',
'terms' => 'Términos de servicio',
'bug' => "¿Encontraste un error?\nAyúdanos a solucionarlo"
],
'Español (Latinoamérica)' => [
'sign_in' => 'Iniciar sesión',
'continue_to' => 'para continuar a',
'email_placeholder' => 'Correo electrónico o usuario',
'forgot_email' => '¿Olvidaste tu correo?',
'guest_mode' => '¿No es tu computadora? Usa ventanas de navegación privada para iniciar sesión.',
'learn_more' => 'Más información sobre el modo invitado',
'create_account' => 'Crear una cuenta',
'next' => 'Confirmar',
'help' => 'Soporte',
'privacy' => 'Política de privacidad',
'terms' => 'Términos de servicio',
'bug' => "¿Encontraste un error?\nAyúdanos a solucionarlo"
],
'Français (Canada)' => [
'sign_in' => 'Se connecter',
'continue_to' => 'pour continuer vers',
'email_placeholder' => 'Courriel ou nom dutilisateur',
'forgot_email' => 'Courriel oublié?',
'guest_mode' => 'Ce nest pas votre bureau? Utilisez des fenêtres de navigation privée pour vous connecter.',
'learn_more' => 'En savoir plus sur le mode invité',
'create_account' => 'Créer un compte',
'next' => 'Confirmer',
'help' => 'Support',
'privacy' => 'Politique de confidentialité',
'terms' => 'Conditions dutilisation',
'bug' => "Vous avez trouvé un bogue?\nAidez-nous à le corriger"
],
'Français (France)' => [
'sign_in' => 'Se connecter',
'continue_to' => 'pour continuer vers',
'email_placeholder' => 'Courriel ou nom dutilisateur',
'forgot_email' => 'Courriel oublié?',
'guest_mode' => 'Ce nest pas votre bureau? Utilisez des fenêtres de navigation privée pour vous connecter.',
'learn_more' => 'En savoir plus sur le mode invité',
'create_account' => 'Créer un compte',
'next' => 'Confirmer',
'help' => 'Support',
'privacy' => 'Politique de confidentialité',
'terms' => 'Conditions dutilisation',
'bug' => "Vous avez trouvé un bogue?\nAidez-nous à le corriger"
],
'Deutsch' => [
'sign_in' => 'Anmelden',
'continue_to' => 'um fortzufahren zu',
'email_placeholder' => 'E-Mail oder Benutzername',
'forgot_email' => 'E-Mail vergessen?',
'guest_mode' => 'Nicht dein Desktop? Verwende Privatfenster zum Anmelden.',
'learn_more' => 'Mehr über den Gastmodus erfahren',
'create_account' => 'Ein Konto erstellen',
'next' => 'Bestätigen',
'help' => 'Support',
'privacy' => 'Datenschutzrichtlinie',
'terms' => 'Nutzungsbedingungen',
'bug' => "Fehler gefunden?\nHelfen Sie uns, ihn zu beheben"
],
'Gaeilge' => [
'sign_in' => 'Sínigh isteach',
'continue_to' => 'chun leanúint ar aghaidh chuig',
'email_placeholder' => 'Ríomhphost nó ainm úsáideora',
'forgot_email' => 'Ar dhearmad tú do ríomhphost?',
'guest_mode' => 'Ní do dheasc é seo? Úsáid fuinneoga brabhsála príobháideacha chun síniú isteach.',
'learn_more' => 'Foghlaim níos mó faoi mhodh an aíochtaí',
'create_account' => 'Cuir cuntas ar bun',
'next' => 'Dearbhaigh',
'help' => 'Tacaíocht',
'privacy' => 'Polasaí Príobháideachta',
'terms' => 'Téarmaí Seirbhíse',
'bug' => "Ar aimsigh tú fabht?\nCabhraigh linn é a cheartú"
],
'Indonesian' => [
'sign_in' => 'Masuk',
'continue_to' => 'untuk melanjutkan ke',
'email_placeholder' => 'Email atau nama pengguna',
'forgot_email' => 'Lupa email?',
'guest_mode' => 'Bukan desktop Anda? Gunakan jendela Penjelajahan Pribadi untuk masuk.',
'learn_more' => 'Pelajari lebih lanjut tentang mode Tamu',
'create_account' => 'Buat akun',
'next' => 'Konfirmasi',
'help' => 'Bantuan',
'privacy' => 'Kebijakan Privasi',
'terms' => 'Syarat Layanan',
'bug' => "Menemukan bug? Bantu kami memperbaikinya"
],
'Italiano' => [
'sign_in' => 'Accedi',
'continue_to' => 'per continuare a',
'email_placeholder' => 'Email o nome utente',
'forgot_email' => 'Hai dimenticato lemail?',
'guest_mode' => 'Non è il tuo desktop? Usa finestre di navigazione privata per accedere.',
'learn_more' => 'Ulteriori informazioni sulla modalità ospite',
'create_account' => 'Crea un account',
'next' => 'Conferma',
'help' => 'Supporto',
'privacy' => 'Informativa sulla privacy',
'terms' => 'Termini di servizio',
'bug' => "Hai trovato un bug? Aiutaci a risolverlo"
],
'Melayu' => [
'sign_in' => 'Log masuk',
'continue_to' => 'untuk terus ke',
'email_placeholder' => 'Emel atau nama pengguna',
'forgot_email' => 'Lupa emel?',
'guest_mode' => 'Bukan desktop anda? Gunakan tetingkap Penyemakan Imbas Peribadi untuk log masuk.',
'learn_more' => 'Ketahui lebih lanjut mengenai mod Tetamu',
'create_account' => 'Buat akaun',
'next' => 'Sahkan',
'help' => 'Sokongan',
'privacy' => 'Dasar Privasi',
'terms' => 'Terma Perkhidmatan',
'bug' => "Jumpa pepijat? Bantu kami membetulkannya"
],
'Nederlands' => [
'sign_in' => 'Inloggen',
'continue_to' => 'om door te gaan naar',
'email_placeholder' => 'E-mail of gebruikersnaam',
'forgot_email' => 'E-mail vergeten?',
'guest_mode' => 'Niet jouw desktop? Gebruik privévensters om in te loggen.',
'learn_more' => 'Meer informatie over de gastmodus',
'create_account' => 'Maak een account aan',
'next' => 'Bevestigen',
'help' => 'Ondersteuning',
'privacy' => 'Privacybeleid',
'terms' => 'Gebruiksvoorwaarden',
'bug' => "Bug gevonden? Help ons dit op te lossen"
],
'Norsk' => [
'sign_in' => 'Logg inn',
'continue_to' => 'for å fortsette til',
'email_placeholder' => 'E-post eller brukernavn',
'forgot_email' => 'Glemt e-post?',
'guest_mode' => 'Ikke din desktop? Bruk privat vindu for å logge inn.',
'learn_more' => 'Lær mer om gjestemodus',
'create_account' => 'Opprett en konto',
'next' => 'Bekreft',
'help' => 'Støtte',
'privacy' => 'Personvern',
'terms' => 'Vilkår for bruk',
'bug' => "Fant du en feil? Hjelp oss å fikse den",
],
"Ozbek" => [
'sign_in' => 'Kirish',
'continue_to' => 'davom ettirish uchun',
'email_placeholder' => 'Email yoki foydalanuvchi nomi',
'forgot_email' => 'Emailni unutdingizmi?',
'guest_mode' => 'Sizning desktopingiz emasmi? Maxfiy brauzer oynasidan foydalaning.',
'learn_more' => 'Mehmon rejimi haqida batafsil malumot',
'create_account' => 'Hisob yaratish',
'next' => 'Tasdiqlash',
'help' => 'Yordam',
'privacy' => 'Maxfiylik siyosati',
'terms' => 'Xizmat shartlari',
'bug' => "Xato topdingizmi? Uni tuzatishda yordam bering",
],
'Português (Brasil)' => [
'sign_in' => 'Entrar',
'continue_to' => 'para continuar para',
'email_placeholder' => 'Email ou nome de usuário',
'forgot_email' => 'Esqueceu o email?',
'guest_mode' => 'Não é seu desktop? Use janelas de navegação privada para entrar.',
'learn_more' => 'Saiba mais sobre o modo convidado',
'create_account' => 'Criar uma conta',
'next' => 'Confirmar',
'help' => 'Suporte',
'privacy' => 'Política de Privacidade',
'terms' => 'Termos de Serviço',
'bug' => "Encontrou um bug? Ajude-nos a corrigi-lo",
],
'Português (Portugal)' => [
'sign_in' => 'Iniciar sessão',
'continue_to' => 'para continuar para',
'email_placeholder' => 'Email ou nome de utilizador',
'forgot_email' => 'Esqueceu o email?',
'guest_mode' => 'Não é o seu desktop? Utilize janelas de navegação privada para iniciar sessão.',
'learn_more' => 'Saiba mais sobre o modo convidado',
'create_account' => 'Criar uma conta',
'next' => 'Confirmar',
'help' => 'Suporte',
'privacy' => 'Política de Privacidade',
'terms' => 'Termos de Serviço',
'bug' => "Encontrou um bug? Ajude-nos a corrigi-lo",
],
'Română' => [
'sign_in' => 'Conectare',
'continue_to' => 'pentru a continua către',
'email_placeholder' => 'Email sau nume de utilizator',
'forgot_email' => 'Ai uitat emailul?',
'guest_mode' => 'Nu este desktopul tău? Folosește ferestre private pentru a te conecta.',
'learn_more' => 'Aflați mai multe despre modul oaspete',
'create_account' => 'Creează un cont',
'next' => 'Confirmă',
'help' => 'Suport',
'privacy' => 'Politica de confidențialitate',
'terms' => 'Termeni de serviciu',
'bug' => "Ai găsit un bug? Ajută-ne să îl reparăm",
],
'Svenska' => [
'sign_in' => 'Logga in',
'continue_to' => 'för att fortsätta till',
'email_placeholder' => 'E-post eller användarnamn',
'forgot_email' => 'Glömt e-post?',
'guest_mode' => 'Inte din desktop? Använd privata fönster för att logga in.',
'learn_more' => 'Läs mer om gästläget',
'create_account' => 'Skapa ett konto',
'next' => 'Bekräfta',
'help' => 'Support',
'privacy' => 'Sekretesspolicy',
'terms' => 'Användarvillkor',
'bug' => "Hittade du en bugg? Hjälp oss att åtgärda den",
],
'Tiếng Việt' => [
'sign_in' => 'Đăng nhập',
'continue_to' => 'để tiếp tục tới',
'email_placeholder' => 'Email hoặc tên người dùng',
'forgot_email' => 'Quên email?',
'guest_mode' => 'Không phải desktop của bạn? Sử dụng cửa sổ ẩn danh để đăng nhập.',
'learn_more' => 'Tìm hiểu thêm về chế độ khách',
'create_account' => 'Tạo tài khoản',
'next' => 'Xác nhận',
'help' => 'Hỗ trợ',
'privacy' => 'Chính sách bảo mật',
'terms' => 'Điều khoản dịch vụ',
'bug' => "Bạn phát hiện lỗi? Giúp chúng tôi sửa nó"
],
'Türkçe' => [
'sign_in' => 'Oturum aç',
'continue_to' => 'devam etmek için',
'email_placeholder' => 'E-posta veya kullanıcı adı',
'forgot_email' => 'E-postayı unuttunuz mu?',
'guest_mode' => 'Masaüstünüz mü değil? Özel tarama pencerelerini kullanarak oturum açın.',
'learn_more' => 'Misafir modu hakkında daha fazla bilgi edinin',
'create_account' => 'Hesap oluştur',
'next' => 'Onayla',
'help' => 'Destek',
'privacy' => 'Gizlilik Politikası',
'terms' => 'Hizmet Şartları',
'bug' => "Bir hata mı buldunuz? Düzeltmemize yardımcı olun",
],
'Ελληνικά' => [
'sign_in' => 'Σύνδεση',
'continue_to' => 'για να συνεχίσετε στο',
'email_placeholder' => 'Email ή όνομα χρήστη',
'forgot_email' => 'Ξεχάσατε το email;',
'guest_mode' => 'Δεν είναι ο υπολογιστής σας; Χρησιμοποιήστε παράθυρα ιδιωτικής περιήγησης για σύνδεση.',
'learn_more' => 'Μάθετε περισσότερα για τη λειτουργία επισκέπτη',
'create_account' => 'Δημιουργία λογαριασμού',
'next' => 'Επιβεβαίωση',
'help' => 'Υποστήριξη',
'privacy' => 'Πολιτική Απορρήτου',
'terms' => 'Όροι Υπηρεσίας',
'bug' => "Βρήκατε σφάλμα; Βοηθήστε μας να το διορθώσουμε"
],
'қазақ тілі' => [
'sign_in' => 'Кіру',
'continue_to' => 'жалғастыру үшін',
'email_placeholder' => 'Электрондық пошта немесе пайдаланушы аты',
'forgot_email' => 'Электрондық поштаны ұмыттыңыз ба?',
'guest_mode' => 'Сіздің жұмыс үстеліңіз емес пе? Жеке терезелерді қолданып кіріңіз.',
'learn_more' => 'Қонақ режимі туралы көбірек біліңіз',
'create_account' => 'Тіркелгі жасау',
'next' => 'Растау',
'help' => 'Қолдау',
'privacy' => 'Құпиялылық саясаты',
'terms' => 'Қызмет көрсету шарттары',
'bug' => "Қате таптыңыз ба? Оны түзетуге көмектесіңіз"
],
'монгол' => [
'sign_in' => 'Нэвтрэх',
'continue_to' => 'үргэлжлүүлэх',
'email_placeholder' => 'Имэйл эсвэл хэрэглэгчийн нэр',
'forgot_email' => 'Имэйл мартсан уу?',
'guest_mode' => 'Таны ширээний компьютер биш үү? Хувийн цонх ашиглан нэвтэрнэ үү.',
'learn_more' => 'Зочны горимын талаар дэлгэрэнгүй',
'create_account' => 'Данс үүсгэх',
'next' => 'Баталгаажуулах',
'help' => 'Тусламж',
'privacy' => 'Нууцлалын бодлого',
'terms' => 'Үйлчилгээний нөхцөл',
'bug' => "Алдаа илэрсэн үү? Үүнийг засахад туслаач",
],
'Русский' => [
'sign_in' => 'Войти',
'continue_to' => 'чтобы продолжить на',
'email_placeholder' => 'Электронная почта или имя пользователя',
'forgot_email' => 'Забыли электронную почту?',
'guest_mode' => 'Это не ваш рабочий стол? Используйте приватные окна для входа.',
'learn_more' => 'Подробнее о режиме гостя',
'create_account' => 'Создать аккаунт',
'next' => 'Подтвердить',
'help' => 'Поддержка',
'privacy' => 'Политика конфиденциальности',
'terms' => 'Условия обслуживания',
'bug' => "Нашли ошибку?\nПомогите нам её исправить",
],
'Українська' => [
'sign_in' => 'Увійти',
'continue_to' => 'щоб продовжити на',
'email_placeholder' => 'Електронна пошта або ім’я користувача',
'forgot_email' => 'Забули електронну пошту?',
'guest_mode' => 'Це не ваш робочий стіл? Використовуйте приватні вікна для входу.',
'learn_more' => 'Дізнатися більше про режим гостя',
'create_account' => 'Створити обліковий запис',
'next' => 'Підтвердити',
'help' => 'Підтримка',
'privacy' => 'Політика конфіденційності',
'terms' => 'Умови обслуговування',
'bug' => "Знайшли помилку?\nДопоможіть нам її виправити"
],
'ქართული' => [
'sign_in' => 'შესვლა',
'continue_to' => 'საგრძელებლად',
'email_placeholder' => 'ელ.ფოსტა ან მომხმარებლის სახელი',
'forgot_email' => 'ელ.ფოსტა დაგავიწყდა?',
'guest_mode' => 'ეს შენი დესკტოპი არ არის? გამოიყენეთ კერძო ბრაუზერის ფანჯრები შესასვლელად.',
'learn_more' => 'გაიგე მეტი სტუმრის რეჟიმის შესახებ',
'create_account' => 'ანგარიშის შექმნა',
'next' => 'დადასტურება',
'help' => 'მხარდაჭერა',
'privacy' => "კონფიდენციალურობის\nპოლიტიკა",
'terms' => 'სერვისის პირობები',
'bug' => "იპოვნეთ შეცდომა?\nდაგვეხმარეთ მისი გამოსწორებაში"
],
'հայերեն' => [
'sign_in' => 'Մուտք գործել',
'continue_to' => 'շարունակելու համար դեպի',
'email_placeholder' => 'Էլ.փոստ կամ օգտվողի անուն',
'forgot_email' => 'Մոռացե՞լ եք էլ.փոստը',
'guest_mode' => 'ԴՁեր աշխատասեղանի մոտ չե՞ք: Օգտագործեք մասնավոր զննարկիչ մուտք գործելու համար:',
'learn_more' => 'Իմանալ ավելին «Հյուրի» ռեժիմի մասին',
'create_account' => 'Ստեղծել հաշիվ',
'next' => 'Հաստատել',
'help' => 'Աջակցություն',
'privacy' => "Գաղտնիության\nքաղաքականություն",
'terms' => "Ծառայության\nպայմաններ",
'bug' => "Սխալ գտա՞ք։\nՕգնեք մեզ այն շտկել"
],
'اردو‎' => [
'sign_in' => 'لاگ ان',
'continue_to' => 'جاری رکھنے کے لیے',
'email_placeholder' => 'ای میل یا صارف نام',
'forgot_email' => 'ای میل بھول گئے؟',
'guest_mode' => 'یہ آپ کا ڈیسک ٹاپ نہیں ہے؟ سائن ان کرنے کے لیے پرائیویٹ براؤزنگ ونڈوز استعمال کریں۔',
'learn_more' => 'مہمان موڈ کے بارے میں مزید جانیں',
'create_account' => 'اکاؤنٹ بنائیں',
'next' => 'تصدیق کریں',
'help' => 'مدد',
'privacy' => 'پرائیویسی پالیسی',
'terms' => 'سروس کی شرائط',
'bug' => "کیا آپ نے کوئی خرابی دیکھی؟ ہماری مدد کریں اسے درست کرنے میں"
],
'العربية‎' => [
'sign_in' => 'تسجيل الدخول',
'continue_to' => 'للإستمرار إلى',
'email_placeholder' => 'البريد الإلكتروني أو اسم المستخدم',
'forgot_email' => 'نسيت البريد الإلكتروني؟',
'guest_mode' => 'ليس سطح المكتب الخاص بك؟ استخدم نوافذ التصفح الخاصة لتسجيل الدخول.',
'learn_more' => 'تعرف على المزيد حول وضع الضيف',
'create_account' => 'إنشاء حساب',
'next' => 'تأكيد',
'help' => 'الدعم',
'privacy' => 'سياسة الخصوصية',
'terms' => 'شروط الخدمة',
'bug' => "هل وجدت خطأً؟ ساعدنا في إصلاحه"
],
'हिन्दी' => [
'sign_in' => 'साइन इन',
'continue_to' => 'जारी रखने के लिए',
'email_placeholder' => 'ईमेल या उपयोगकर्ता नाम',
'forgot_email' => 'ईमेल भूल गए?',
'guest_mode' => 'यह आपका डेस्कटॉप नहीं है? साइन इन करने के लिए प्राइवेट ब्राउज़िंग विंडो का उपयोग करें।',
'learn_more' => 'गेस्ट मोड के बारे में और जानें',
'create_account' => 'खाता बनाएं',
'next' => 'पुष्टि करें',
'help' => 'सहायता',
'privacy' => 'गोपनीयता नीति',
'terms' => 'सेवा की शर्तें',
'bug' => "क्या आपको कोई बग मिला? हमारी मदद करें इसे ठीक करने में"
],
'অসমীয়া' => [
'sign_in' => 'সাইন ইন',
'continue_to' => 'অগ্ৰগতি কৰিবলৈ',
'email_placeholder' => 'ইমেইল বা ব্যৱহাৰকাৰীৰ নাম',
'forgot_email' => 'ইমেইল পাহৰি গ’ল?',
'guest_mode' => 'এয়া আপোনাৰ ডেস্কটপ নহয়? সাইন ইন কৰিবলৈ ব্যক্তিগত ব্ৰাউজিং উইণ্ডো ব্যৱহাৰ কৰক।',
'learn_more' => 'গেষ্ট মোডৰ বিষয়ে বেছি জানক',
'create_account' => 'একাউণ্ট বনাওক',
'next' => 'নিশ্চিত কৰক',
'help' => 'সহায়',
'privacy' => 'গোপনীয়তা নীতি',
'terms' => 'সেৱাৰ চৰ্তাৱলী',
'bug' => "আপুনি কোনো ত্ৰুটি পাইলেনে? আমাক ইয়াক ঠিক কৰিবলৈ সহায় কৰক"
],
'বাংলা (India)' => [
'sign_in' => 'সাইন ইন',
'continue_to' => 'চালিয়ে যেতে',
'email_placeholder' => 'ইমেল বা ব্যবহারকারীর নাম',
'forgot_email' => 'ইমেল ভুলে গেছেন?',
'guest_mode' => 'এটি আপনার ডেস্কটপ নয়? সাইন ইন করার জন্য প্রাইভেট ব্রাউজিং উইন্ডো ব্যবহার করুন।',
'learn_more' => 'গেস্ট মোড সম্পর্কে আরও জানুন',
'create_account' => 'একাউন্ট তৈরি করুন',
'next' => 'নিশ্চিত করুন',
'help' => 'সাহায্য',
'privacy' => 'গোপনীয়তা নীতি',
'terms' => 'সার্ভিসের শর্তাবলী',
'bug' => "কোনও ত্ৰুটি দেখেছেন? আমাদের সেটি ঠিক করতে সাহায্য করুন"
],
'বাংলা (Bangladesh)' => [
'sign_in' => 'সাইন ইন',
'continue_to' => 'চালিয়ে যেতে',
'email_placeholder' => 'ইমেল বা ব্যবহারকারীর নাম',
'forgot_email' => 'ইমেল ভুলে গেছেন?',
'guest_mode' => 'এটি আপনার ডেস্কটপ নয়? সাইন ইন করার জন্য প্রাইভেট ব্রাউজিং উইন্ডো ব্যবহার করুন।',
'learn_more' => 'গেস্ট মোড সম্পর্কে আরও জানুন',
'create_account' => 'একাউন্ট তৈরি করুন',
'next' => 'নিশ্চিত করুন',
'help' => 'সাহায্য',
'privacy' => 'গোপনীয়তা নীতি',
'terms' => 'সার্ভিসের শর্তাবলী',
'bug' => "কোনও ত্ৰুটি দেখেছেন? আমাদের সেটি ঠিক করতে সাহায্য করুন"
],
'ਪੰਜਾਬੀ' => [
'sign_in' => 'ਸਾਈਨ ਇਨ',
'continue_to' => 'ਜਾਰੀ ਰੱਖਣ ਲਈ',
'email_placeholder' => 'ਈਮੇਲ ਜਾਂ ਉਪਭੋਗਤਾ ਨਾਮ',
'forgot_email' => 'ਈਮੇਲ ਭੁੱਲ ਗਏ?',
'guest_mode' => 'ਇਹ ਤੁਹਾਡਾ ਡੈਸਕਟਾਪ ਨਹੀਂ ਹੈ? ਸਾਈਨ ਇਨ ਕਰਨ ਲਈ ਪ੍ਰਾਈਵੇਟ ਬ੍ਰਾਉਜ਼ਿੰਗ ਵਰਤੋਂ।',
'learn_more' => 'ਗੈਸਟ ਮੋਡ ਬਾਰੇ ਹੋਰ ਜਾਣੋ',
'create_account' => 'ਖਾਤਾ ਬਣਾਓ',
'next' => 'ਪੁਸ਼ਟੀ ਕਰੋ',
'help' => 'ਮਦਦ',
'privacy' => 'ਪ੍ਰਾਈਵੇਸੀ',
'terms' => 'ਸ਼ਰਤਾਂ',
'bug' => "ਕੀ ਤੁਸੀਂ ਕੋਈ ਬੱਗ ਲੱਭਿਆ? ਸਾਡੇ ਨੂੰ ਇਸਨੂੰ ਠੀਕ ਕਰਨ ਵਿੱਚ ਮਦਦ ਕਰੋ"
],
'ગુજરાતી' => [
'sign_in' => 'સાઇન ઇન',
'continue_to' => 'ચાલુ રાખવા માટે',
'email_placeholder' => 'ઇમેલ અથવા વપરાશકર્તા નામ',
'forgot_email' => 'ઇમેલ ભૂલી ગયા?',
'guest_mode' => 'આ તમારું ડેસ્કટોપ નથી? સાઇન ઇન કરવા માટે પ્રાઇવેટ બ્રાઉઝિંગ વાપરો.',
'learn_more' => 'ગેસ્ટ મોડ વિશે વધુ જાણો',
'create_account' => 'એકાઉન્ટ બનાવો',
'next' => 'સંદેશની પુષ્ટિ કરો',
'help' => 'મદદ',
'privacy' => 'ગોપનીયતા',
'terms' => 'શરતો',
'bug' => "શું તમને કોઈ ભૂલ મળી? અમને તેને સુધારવામાં મદદ કરો"
],
'ଓଡ଼ିଆ' => [
'sign_in' => 'ସାଇନ୍ ଇନ୍',
'continue_to' => 'ଚାଲୁ ରଖିବା ପାଇଁ',
'email_placeholder' => 'ଇମେଲ୍ କିମ୍ବା ବ୍ୟବହାରକାରୀ ନାମ',
'forgot_email' => 'ଇମେଲ୍ ଭୁଲିଗଲେ?',
'guest_mode' => 'ଏହା ଆପଣଙ୍କର ଡେସ୍କଟପ୍ ନୁହେଁ? ସାଇନ୍ ଇନ୍ କରିବା ପାଇଁ ପ୍ରାଇଭେଟ୍ ବ୍ରାଉଜିଂ ୱିଣ୍ଡୋ ବ୍ୟବହାର କରନ୍ତୁ।',
'learn_more' => 'ଗେଷ୍ଟ୍ ମୋଡ୍ ବିଷୟରେ ଅଧିକ ଜାଣନ୍ତୁ',
'create_account' => 'ଏକ ଖାତା ତିଆରି କରନ୍ତୁ',
'next' => 'ନିଶ୍ଚିତ କରନ୍ତୁ',
'help' => 'ସହାୟତା',
'privacy' => 'ଗୋପନୀୟତା',
'terms' => 'ସେବା ନୀତି',
'bug' => "ଆପଣ କିଛି ତ୍ରୁଟି ଦେଖିଛନ୍ତି? ଆମକୁ ଏହା ଠିକ କରିବାରେ ସାହାଯ୍ୟ କରନ୍ତୁ"
],
'தமிழ்' => [
'sign_in' => 'சைன் இன்',
'continue_to' => 'தொடர திரும்ப',
'email_placeholder' => 'மின்னஞ்சல் அல்லது பயனர் பெயர்',
'forgot_email' => 'மின்னஞ்சல் மறந்துவிட்டீர்களா?',
'guest_mode' => 'இது உங்கள் டெஸ்க்டாப் அல்லவா? சைன் இன் செய்ய தனிப்பட்ட பிரௌசிங் பயன்படுத்தவும்.',
'learn_more' => 'கெஸ்ட் மோடு பற்றி மேலும் அறிக',
'create_account' => 'கணக்கு உருவாக்கவும்',
'next' => 'தொடரவும்',
'help' => 'உதவி',
'privacy' => 'தனியுரிமை',
'terms' => 'சேவை நிபந்தனைகள்',
'bug' => "பிழை கண்டறிந்தீர்களா? அதை சரி செய்ய எங்களுக்கு உதவுங்கள்"
],
'తెలుగు' => [
'sign_in' => 'సైన్ ఇన్',
'continue_to' => 'కొనసాగడానికి',
'email_placeholder' => 'ఇమెయిల్ లేదా యూజర్ పేరు',
'forgot_email' => 'ఇమెయిల్ మర్చిపోయారా?',
'guest_mode' => 'ఇది మీ డెస్క్‌టాప్ కాదు? సైన్ ఇన్ చేసేందుకు ప్రైవేట్ బ్రౌజింగ్ విండో ఉపయోగించండి.',
'learn_more' => 'అతిథి మోడ్ గురించి మరింత తెలుసుకోండి',
'create_account' => 'ఖాతా సృష్టించండి',
'next' => 'తదుపరి',
'help' => 'సహాయం',
'privacy' => 'గోప్యతా విధానం',
'terms' => 'సేవా నిబంధనలు',
'bug' => "దోషం కనపడిందా? దాన్ని సరిచేయడంలో మాకు సహాయపడండి"
],
'ಕನ್ನಡ' => [
'sign_in' => 'ಸೈನ್ ಇನ್',
'continue_to' => 'ಮುಂದುವರಿಸಲು',
'email_placeholder' => 'ಇಮೇಲ್ ಅಥವಾ ಬಳಕೆದಾರ ಹೆಸರು',
'forgot_email' => 'ಇಮೇಲ್ ಮರೆತಿದ್ದೀರಾ?',
'guest_mode' => 'ಇದು ನಿಮ್ಮ ಡೆಸ್ಕ್‌ಟಾಪ್ ಅಲ್ಲವೇ? ಸೈನ್ ಇನ್ ಮಾಡಲು ಪ್ರೈವೇಟ್ ಬ್ರೌಸಿಂಗ್ ಬಳಸಿ.',
'learn_more' => 'ಅತಿಥಿ ಮೋಡ್ ಬಗ್ಗೆ ಹೆಚ್ಚು ತಿಳಿಯಿರಿ',
'create_account' => 'ಖಾತೆ ರಚಿಸಿ',
'next' => 'ಮುಂದುವರಿಸಿ',
'help' => 'ಸಹಾಯ',
'privacy' => 'ಗೊಪ್ಯತೆ',
'terms' => 'ಸೇವೆ ನಿಯಮಗಳು',
'bug' => "ನೀವು ಒಂದು ದೋಷ ಕಂಡಿದ್ದೀರಾ? ಇದನ್ನು ಸರಿಪಡಿಸಲು ನಮಗೆ ಸಹಾಯ ಮಾಡಿ"
],
'മലയാളം' => [
'sign_in' => 'സൈൻ ഇൻ',
'continue_to' => 'തുടരാൻ',
'email_placeholder' => 'ഇമെയിൽ അല്ലെങ്കിൽ ഉപയോക്തൃനാമം',
'forgot_email' => 'ഇമെയിൽ മറന്നോ?',
'guest_mode' => 'ഇത് നിങ്ങളുടെ ഡെസ്ക്ടോപ്പ് അല്ലേ? സൈൻ ഇൻ ചെയ്യാൻ പ്രൈവറ്റ് ബ്രൗസിംഗ് ഉപയോഗിക്കുക.',
'learn_more' => 'ഗസ്റ്റ് മോഡ് ഉപയോഗത്തെ കുറിച്ച് കൂടുതൽ അറിയുക',
'create_account' => 'അക്കൗണ്ട് സൃഷ്‌ടിക്കുക',
'next' => 'തുടരുക',
'help' => 'സഹായം',
'privacy' => 'സ്വകാര്യത',
'terms' => 'നിയമങ്ങൾ',
'bug' => "ഒരു പിശക് കണ്ടോ? ദയവായി അത് ശരിയാക്കാൻ ഞങ്ങളെ സഹായിക്കുക"
],
'سنڌي' => [
'sign_in' => 'سائن ان',
'continue_to' => 'جاري رکڻ لاءِ',
'email_placeholder' => 'ايميل يا يوزر نالو',
'forgot_email' => 'ايميل وساري وياسين؟',
'guest_mode' => 'ڇا هي توهان جو ڪمپيوٽر ناهي؟ سائن ان ڪرڻ لاءِ پرائيويٽ برائوزنگ استعمال ڪريو.',
'learn_more' => 'گيسٽ موڊ بابت وڌيڪ ڄاڻو',
'create_account' => 'اڪائونٽ ٺاهيو',
'next' => 'اڳتي وڌو',
'help' => 'مدد',
'privacy' => 'رازداري',
'terms' => 'شرطن',
'bug' => 'ڇا توهان کي ڪو بگ مليو؟ ان کي درست ڪرڻ ۾ اسان جي مدد ڪريو'
],
'मराठी' => [
'sign_in' => 'साइन इन',
'continue_to' => 'सुरू ठेवण्यासाठी',
'email_placeholder' => 'ईमेल किंवा वापरकर्तानाव',
'forgot_email' => 'ईमेल विसरलात?',
'guest_mode' => 'हे तुमचे डेस्कटॉप नाही? साइन इन करण्यासाठी प्रायव्हेट ब्राउझिंग वापरा.',
'learn_more' => 'गेस्ट मोडबद्दल अधिक जाणून घ्या',
'create_account' => 'खाते तयार करा',
'next' => 'सुरू ठेवा',
'help' => 'सहाय्य',
'privacy' => 'गोपनीयता',
'terms' => 'अटी',
'bug' => 'तुम्हाला एखादी बग सापडली का? ती दुरुस्त करण्यात आमची मदत करा'
],
'नेपाली' => [
'sign_in' => 'साइन इन',
'continue_to' => 'जारी राख्न',
'email_placeholder' => 'इमेल वा प्रयोगकर्ता नाम',
'forgot_email' => 'इमेल बिर्सनुभयो?',
'guest_mode' => 'यो तपाईंको डेस्कटप होइन? साइन इन गर्न प्राइभेट ब्राउजिङ प्रयोग गर्नुहोस्।',
'learn_more' => 'गेस्ट मोडको बारेमा जान्नुहोस्',
'create_account' => 'खाता सिर्जना गर्नुहोस्',
'next' => 'जारी राख्नुहोस्',
'help' => 'सहायता',
'privacy' => 'गोपनीयता',
'terms' => 'सर्तहरू',
'bug' => 'के तपाईँले कुनै बग फेला पार्नुभयो? कृपया यसलाई सच्याउन हामीलाई मद्दत गर्नुहोस्'
],
'ไทย' => [
'sign_in' => 'เข้าสู่ระบบ',
'continue_to' => 'ดำเนินการต่อไปยัง',
'email_placeholder' => 'อีเมลหรือชื่อผู้ใช้',
'forgot_email' => 'ลืมอีเมลใช่ไหม?',
'guest_mode' => 'นี่ไม่ใช่เดสก์ท็อปของคุณ? ใช้หน้าต่างการท่องเว็บส่วนตัวเพื่อลงชื่อเข้าใช้',
'learn_more' => 'เรียนรู้เพิ่มเติมเกี่ยวกับโหมดผู้เยี่ยมชม',
'create_account' => 'สร้างบัญชี',
'next' => 'ดำเนินการต่อ',
'help' => 'ช่วยเหลือ',
'privacy' => 'ความเป็นส่วนตัว',
'terms' => 'ข้อกำหนด',
'bug' => 'พบข้อผิดพลาด? โปรดช่วยเราแก้ไข'
],
'한국어' => [
'sign_in' => '로그인',
'continue_to' => '계속 진행',
'email_placeholder' => '이메일 또는 사용자 이름',
'forgot_email' => '이메일을 잊으셨나요?',
'guest_mode' => '데스크톱이 아닌가요? 개인 정보 보호 브라우징 창을 사용하여 로그인하세요.',
'learn_more' => '게스트 모드에 대해 자세히 알아보기',
'create_account' => '계정 만들기',
'next' => '계속',
'help' => '도움말',
'privacy' => '개인정보',
'terms' => '약관',
'bug' => '버그를 발견하셨나요? 수정하는 데 도움을 주세요'
],
'日本語' => [
'sign_in' => 'サインイン',
'continue_to' => '次へ進む',
'email_placeholder' => 'メールアドレスまたはユーザー名',
'forgot_email' => 'メールアドレスをお忘れですか?',
'guest_mode' => 'デスクトップではありませんか?プライベートブラウジングウィンドウでサインインしてください。',
'learn_more' => 'ゲストモードについて詳しく',
'create_account' => 'アカウント作成',
'next' => '続行',
'help' => 'ヘルプ',
'privacy' => 'プライバシー',
'terms' => '利用規約',
'bug' => 'バグを見つけましたか?修正にご協力ください'
],
'简体中文' => [
'sign_in' => '登录',
'continue_to' => '继续至',
'email_placeholder' => '邮箱或用户名',
'forgot_email' => '忘记邮箱?',
'guest_mode' => '不是您的桌面?请使用隐私浏览窗口登录。',
'learn_more' => '了解更多访客模式信息',
'create_account' => '创建账户',
'next' => '继续',
'help' => '帮助',
'privacy' => '隐私',
'terms' => '条款',
'bug' => '发现错误了吗?请帮助我们修复它'
],
'繁體中文' => [
'sign_in' => '登入',
'continue_to' => '繼續至',
'email_placeholder' => '電子郵件或用戶名',
'forgot_email' => '忘記電子郵件?',
'guest_mode' => '不是您的桌面?請使用隱私瀏覽視窗登入。',
'learn_more' => '了解更多訪客模式資訊',
'create_account' => '建立帳號',
'next' => '繼續',
'help' => '幫助',
'privacy' => '隱私',
'terms' => '條款',
'bug' => '發現錯誤了嗎?請幫助我們修復它'
],
];

64
src/core/router.php Normal file
View File

@@ -0,0 +1,64 @@
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header('Location: ./pages/sign_in_email.php');
exit;
}
$is_admin = $_SESSION['is_admin'] ?? false;
$page = $_GET['page'] ?? 'overview';
$routes = [
'overview' => [
'role' => 'user',
'label' => 'Overview',
'icon' => 'home',
'file' => './assets/users/_overview.php',
'nav' => true,
],
'reports' => [
'role' => 'user',
'label' => 'Reports',
'icon' => 'file-text',
'file' => './assets/users/_reports.php',
'nav' => true,
],
'status-board' => [
'role' => 'admin',
'label' => 'Status Board',
'icon' => 'activity',
'file' => './assets/admin/_status_board.php',
'nav' => true,
],
'activity-logs' => [
'role' => 'admin',
'label' => 'Activity Logs',
'icon' => 'clock',
'file' => './assets/admin/_activity_logs.php',
'nav' => true,
],
'admin' => [
'role' => 'admin',
'label' => 'Admin',
'icon' => 'settings',
'file' => './assets/admin/_admin.php',
'nav' => true,
],
];
if (!isset($routes[$page])) {
$page = $is_admin ? 'status-board' : 'overview';
}
$routeRole = $routes[$page]['role'];
if (
($routeRole === 'admin' && !$is_admin) ||
($routeRole === 'user' && $is_admin)
) {
$page = $is_admin ? 'status-board' : 'overview';
}
$current_route = $routes[$page];
?>

View File

@@ -1,168 +0,0 @@
<?php
session_start();
// Initialize the application
include '../init.php';
include '../connection.php';
// Suppress all PHP errors in production environment
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
if (isset($_GET['action']) && $_GET['action'] === 'logout') {
session_unset();
session_destroy();
header("Location: " . $_SERVER['PHP_SELF']);
exit;
}
$is_logged_in = isset($_SESSION['user_id']) && !empty($_SESSION['user_id']);
$user_id = $_SESSION['user_id'] ?? null;
$username = 'Unknown';
$email = 'Unknown';
$password_hash = '';
$password_plain = $_SESSION['user_password_plain'] ?? null;
if ($user_id) {
$stmt = $conn->prepare("SELECT username, email, password_hash FROM users WHERE id = ? LIMIT 1");
if ($stmt) {
$stmt->bind_param("i", $user_id);
$stmt->execute();
$stmt->bind_result($db_username, $db_email, $db_password_hash);
$stmt->fetch();
if (!empty($db_username))
$username = $db_username;
if (!empty($db_email))
$email = $db_email;
$password_hash = $db_password_hash;
$stmt->close();
} else {
die("Database error: " . htmlspecialchars($conn->error));
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Account Test Page</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" href="../../src/output.css">
<style>
.kv {
min-width: 160px;
font-weight: 500;
}
.card-row {
flex-wrap: wrap;
}
.card-item {
word-break: break-word;
}
</style>
</head>
<body class="bg-neutral-900 text-gray-200 min-h-screen flex items-center justify-center p-6">
<div class="w-full max-w-4xl">
<div class="bg-black border border-neutral-800 rounded-3xl p-8 shadow-2xl">
<div class="flex flex-col md:flex-row md:items-center md:justify-between mb-8 gap-4">
<h1 class="text-3xl font-bold text-white">Account Info — Test</h1>
<div class="text-lg text-gray-400">
Status:
<span class="<?php echo $is_logged_in ? 'text-green-400' : 'text-red-400'; ?>">
<?php echo $is_logged_in ? 'Logged in ✅' : 'Not logged in ❌'; ?>
</span>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="p-6 bg-neutral-900 rounded-2xl flex items-center gap-4 card-row">
<div class="kv text-gray-400">Username</div>
<div class="flex-1 text-lg card-item"><?php echo htmlspecialchars($username); ?></div>
</div>
<div class="p-6 bg-neutral-900 rounded-2xl flex items-center gap-4 card-row">
<div class="kv text-gray-400">Email</div>
<div class="flex-1 text-lg card-item"><?php echo htmlspecialchars($email); ?></div>
</div>
<div class="p-6 bg-neutral-900 rounded-2xl flex items-center gap-4 card-row">
<div class="kv text-gray-400">Password</div>
<div class="flex-1 card-item">
<?php if ($password_plain !== null): ?>
<div class="relative">
<input id="plainPwd" type="password" readonly
value="<?php echo htmlspecialchars($password_plain); ?>"
class="w-full bg-transparent border border-neutral-700 rounded-md px-4 py-3 text-lg text-gray-200 focus:outline-none" />
<button id="togglePwd" type="button"
class="absolute right-2 top-1/2 -translate-y-1/2 bg-neutral-800 px-3 py-1 rounded text-sm hover:bg-neutral-700">
Show
</button>
</div>
<p class="mt-2 text-sm text-yellow-300">Plaintext available from session for testing purposes
only.</p>
<?php else: ?>
<div class="text-gray-400 text-sm">Plaintext not stored, password hashed(secure).</div>
<?php endif; ?>
</div>
</div>
<div class="p-6 bg-neutral-900 rounded-2xl flex items-center gap-4 card-row">
<div class="kv text-gray-400">Password Hash</div>
<div class="flex-1 text-sm break-all card-item"><?php echo htmlspecialchars($password_hash); ?>
</div>
</div>
<div class="p-6 bg-neutral-900 rounded-2xl flex items-center gap-4 card-row">
<div class="kv text-gray-400">User ID</div>
<div class="flex-1 text-lg card-item"><?php echo htmlspecialchars($user_id ?? '—'); ?></div>
</div>
<div class="p-6 bg-neutral-900 rounded-2xl flex items-center gap-4 card-row">
<div class="kv text-gray-400">Session Data</div>
<div class="flex-1 text-sm text-gray-400 card-item">
<?php echo htmlspecialchars(json_encode(array_intersect_key($_SESSION, array_flip(['user_id', 'user_name', 'user_email'])))); ?>
</div>
</div>
</div>
<div class="mt-8 flex gap-4 justify-start flex-wrap">
<form method="get" action="" class="inline">
<button type="submit" name="action" value="logout"
class="px-6 py-3 rounded-full bg-red-600 hover:bg-red-700 text-white text-lg font-medium">
Logout
</button>
</form>
<button type="button" onclick="window.location.href='../../home.php';"
class="px-6 py-3 rounded-full bg-neutral-800 hover:bg-neutral-700 text-gray-200 text-lg font-medium">
Back
</button>
</div>
</div>
</div>
<script>
(function () {
const btn = document.getElementById('togglePwd');
const input = document.getElementById('plainPwd');
if (!btn || !input) return;
btn.addEventListener('click', function () {
if (input.type === 'password') {
input.type = 'text';
btn.textContent = 'Hide';
} else {
input.type = 'password';
btn.textContent = 'Show';
}
});
})();
</script>
</body>
</html>

View File

@@ -1,101 +0,0 @@
<?php
// Initialize the application
include './core/init.php';
// Suppress all PHP errors in production environment
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
error_reporting(0);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Meta & Viewport Configuration -->
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Favicon & PWA Assets -->
<link rel="icon" type="image/png" href="./assets/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./assets/favicon/favicon.svg" />
<link rel="shortcut icon" href="./assets/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="./assets/favicon/site.webmanifest" />
<meta name="apple-mobile-web-app-title" content="SteamsTube" />
<!-- Main Stylesheet (Tailwind CSS) -->
<link rel="stylesheet" href="./src/output.css">
<!-- Google Fonts: Lexend Deca -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@100..900&display=swap" rel="stylesheet">
<!-- Dynamic Page Title (from .env DOMAIN variable) -->
<title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title>
<!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) -->
<?php include 'assets/_debug_kit.php'; ?>
</head>
<body class="bg-black">
<!-- Includes -->
<?php include 'assets/_navbar.php'; ?>
<?php include 'assets/_sidebar.php'; ?>
<?php include 'core/connection.php'; ?>
<?php include 'core/home/home_config.php'; ?>
<main class="mt-8 p-7">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<?php
$sql = "SELECT thumbnail, duration, channel_image, title, channel_name, views, uploaded_at FROM videos ORDER BY uploaded_at DESC";
$result = $conn->query($sql);
if ($result->num_rows > 0):
while ($row = $result->fetch_assoc()):
?>
<div class="cursor-pointer">
<!-- Thumbnail -->
<div class="relative">
<img src="<?php echo htmlspecialchars($row['thumbnail']); ?>" alt="video thumbnail"
class="w-full h-auto rounded-2xl opacity-90" loading="lazy">
<span class="absolute bottom-2 right-2 text-gray-200 text-xs px-1 py-[0.15rem] rounded-md bg-black/50">
<?php echo htmlspecialchars(formatDuration($row['duration'])); ?>
</span>
</div>
<!-- Info -->
<div class="flex mt-2 gap-3">
<img src="<?php echo htmlspecialchars($row['channel_image']); ?>" alt="channel"
class="w-auto h-10 rounded-full opacity-90" loading="lazy">
<div>
<h3 class="text-md text-gray-200"><?php echo htmlspecialchars($row['title']); ?></h3>
<p class="text-sm text-gray-400"><?php echo htmlspecialchars($row['channel_name']); ?></p>
<p class="text-sm text-gray-400">
<?php echo htmlspecialchars(formatViews($row['views'])); ?> views •
<?php echo htmlspecialchars(timeAgo($row['uploaded_at'])); ?>
</p>
</div>
</div>
</div>
<?php
endwhile;
else:
echo "<p class='text-gray-400'>No videos found.</p>";
endif;
?>
</div>
</main>
</body>
<!-- Scripts -->
<script src="assets/js/navbar_config.js"></script>
<script src="assets/js/sidebar_config.js"></script>
</html>

View File

@@ -1,9 +1,7 @@
<?php <?php
// Error reporting
ini_set('display_errors', 1); ini_set('display_errors', 1);
ini_set('display_startup_errors', 1); ini_set('display_startup_errors', 1);
error_reporting(E_ALL); error_reporting(E_ALL);
// Application includes include './pages/dashboard.php';
include 'home.php';
?> ?>

393
src/pages/account.php Normal file
View File

@@ -0,0 +1,393 @@
<?php
session_start();
include './../core/init.php';
include './../core/connection.php';
ini_set('display_errors', 0);
error_reporting(0);
if (isset($_GET['action']) && $_GET['action'] === 'logout') {
session_unset();
session_destroy();
header("Location: ./../index.php");
exit;
}
$user_id = $_SESSION['user_id'] ?? null;
if (!$user_id) {
header("Location: ./../index.php");
exit;
}
$username = 'Unknown';
$email = 'Unknown';
$is_admin = false;
$stmt = $conn->prepare("SELECT username, email, is_admin FROM users WHERE id = ? LIMIT 1");
if ($stmt) {
$stmt->bind_param("i", $user_id);
$stmt->execute();
$stmt->bind_result($db_username, $db_email, $db_is_admin);
if ($stmt->fetch()) {
$username = $db_username;
$email = $db_email;
$is_admin = ((int) $db_is_admin === 1);
}
$stmt->close();
}
$email_initial = strtoupper(substr($email, 0, 1));
$helpdesk_email = $_ENV['HELPDESK_EMAIL'];
$helpdesk_phone = $_ENV['HELPDESK_PHONE'];
$management_email = $_ENV['MANAGEMENT_EMAIL'];
$management_phone = $_ENV['MANAGEMENT_PHONE'];
$health_email = $_ENV['HEALTH_EMAIL'];
$health_phone = $_ENV['HEALTH_PHONE'];
$library_email = $_ENV['LIBRARY_EMAIL'];
$library_phone = $_ENV['LIBRARY_PHONE'];
$security_email = $_ENV['SECURITY_EMAIL'];
$security_phone = $_ENV['SECURITY_PHONE'];
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="./../assets/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./../assets/favicon/favicon.svg" />
<link rel="shortcut icon" href="./../assets/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./../assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="./../assets/favicon/site.webmanifest" />
<meta name="apple-mobile-web-app-title" content="<?php echo htmlspecialchars($_ENV['DOMAIN']); ?>" />
<link rel="stylesheet" href="./../src/output.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@100..900&display=swap" rel="stylesheet">
<title><?php echo htmlspecialchars(($_ENV['DOMAIN']) . ' - Account'); ?></title>
<?php include './../assets/_debug_kit.php'; ?>
</head>
<body class="bg-neutral-900 text-gray-200 min-h-screen flex flex-col antialiased selection:bg-blue-500/30"
style="font-family: 'Lexend Deca', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;">
<div class="h-[140px] md:h-[150px] w-full bg-neutral-900 relative overflow-hidden border-b border-neutral-800">
<div class="absolute top-4 left-4 md:top-6 md:left-6 z-20">
<button onclick="window.location.href='./../index.php';" class="group flex items-center gap-2 px-4 py-2 bg-blue-500/10 backdrop-blur-xl
border border-blue-500/40 rounded-xl text-sm text-neutral-300
hover:text-white hover:bg-blue-500/20
transition-all duration-300 active:scale-95">
<svg class="w-4 h-4 transition-transform group-hover:-translate-x-1" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
Dashboard
</button>
</div>
</div>
<div class="flex-1 w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 -mt-12 md:-mt-20 relative z-10 pb-12">
<div class="flex flex-col md:flex-row items-center md:items-end gap-4 md:gap-8 mb-8 md:mb-12">
<div class="relative shrink-0 group">
<div
class="w-28 h-28 md:w-44 md:h-44 rounded-full bg-neutral-900 border-4 md:border-[6px] border-neutral-900 shadow-2xl flex items-center justify-center relative overflow-hidden">
<div
class="absolute inset-0 bg-gradient-to-tr from-neutral-800 via-neutral-700 to-neutral-600 group-hover:scale-110 transition-transform duration-700">
</div>
<span class="relative z-10 text-4xl md:text-6xl font-bold text-white drop-shadow-lg">
<?php echo $email_initial; ?>
</span>
</div>
<div class="absolute bottom-1 right-1 md:bottom-3 md:right-3 bg-neutral-900 rounded-full p-1 md:p-1.5">
<div
class="w-4 h-4 md:w-6 md:h-6 bg-green-500 rounded-full border-2 md:border-[3px] border-neutral-900 flex items-center justify-center shadow-lg shadow-green-500/50">
<div class="w-1.5 h-1.5 md:w-2 md:h-2 bg-white rounded-full opacity-70 animate-pulse"></div>
</div>
</div>
</div>
<div class="flex-1 w-full text-center md:text-left pb-0 md:pb-4">
<h1 class="text-2xl md:text-5xl font-bold text-white tracking-tight mb-3 break-all md:break-normal">
<?php echo htmlspecialchars($email); ?>
</h1>
<div class="flex flex-wrap items-center justify-center md:justify-start gap-2 md:gap-3">
<span
class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full border bg-green-500/10 border-green-500/20 text-green-400 text-[10px] md:text-xs font-bold uppercase tracking-wider backdrop-blur-md">
<svg class="w-3 h-3 md:w-3.5 md:h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
Verified
</span>
</div>
</div>
<div class="w-full md:w-auto pb-0 md:pb-4 mt-2 md:mt-0">
<form method="get" action="">
<button type="submit" name="action" value="logout"
class="w-full md:w-auto flex items-center justify-center gap-2 px-6 py-3 rounded-xl bg-red-500/10 text-red-400 border border-red-500/20 hover:bg-red-500/80 hover:text-white hover:shadow-lg hover:shadow-red-500/20 transition-all duration-300 font-medium text-sm active:scale-95">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
</svg>
Sign Out
</button>
</form>
</div>
</div>
<div class="grid grid-cols-1 xl:grid-cols-3 gap-6 md:gap-8">
<div class="xl:col-span-2 space-y-6">
<div
class="bg-neutral-900/60 backdrop-blur-xl border border-neutral-800 rounded-2xl p-5 md:p-8 shadow-xl relative overflow-hidden h-full">
<div
class="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-blue-500 via-neutral-600 to-transparent">
</div>
<div class="flex items-center justify-between mb-6">
<div>
<h2 class="text-lg md:text-xl font-bold text-white">Your Identification</h2>
<p class="text-xs text-neutral-400 mt-1">View the University credentials & access details
</p>
</div>
<div class="p-2 bg-neutral-800/50 rounded-lg border border-neutral-700/50">
<svg class="w-5 h-5 md:w-6 md:h-6 text-blue-400" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10 6H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V8a2 2 0 00-2-2h-5m-4 0V5a2 2 0 114 0v1m-4 0c0 .6.4 1 1 1 1 1 0 0 1 1 1v3" />
</svg>
</div>
</div>
<div class="grid grid-cols-1 gap-5">
<div class="group">
<label
class="block text-[10px] font-bold text-neutral-500 uppercase tracking-widest mb-1.5 ml-1">Username/
University ID/ Student ID</label>
<div class="flex items-center gap-2">
<div class="relative flex-1 min-w-0">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="w-4 h-4 text-blue-400 transition-colors" fill="none"
stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M5.121 17.804A13.937 13.937 0 0112 16c2.5 0 4.847.655 6.879 1.804M15 10a3 3 0 11-6 0 3 3 0 016 0zm6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div
class="w-full bg-black/40 border border-neutral-800 text-neutral-200 text-sm rounded-xl py-3.5 pl-9 pr-4 font-mono truncate group-hover:border-neutral-700 transition-colors">
<?php echo htmlspecialchars($username); ?>
</div>
</div>
<button id="btn-user"
onclick="copyToClipboard('<?php echo htmlspecialchars($username, ENT_QUOTES); ?>', 'btn-user')"
class="shrink-0 p-3.5 bg-neutral-800 border border-neutral-700 rounded-xl text-neutral-400 hover:text-white hover:bg-neutral-700 hover:border-neutral-600 transition-all shadow-sm active:scale-95"
title="Copy ID">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
</button>
</div>
</div>
<div class="group">
<label
class="block text-[10px] font-bold text-neutral-500 uppercase tracking-widest mb-1.5 ml-1">Authenticated
Email Address</label>
<div class="flex items-center gap-2">
<div class="relative flex-1 min-w-0">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="w-4 h-4 text-blue-400 transition-colors" fill="none"
stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</div>
<div
class="w-full bg-black/40 border border-neutral-800 text-neutral-200 text-sm rounded-xl py-3.5 pl-9 pr-4 font-mono truncate group-hover:border-neutral-700 transition-colors">
<?php echo htmlspecialchars($email); ?>
</div>
</div>
<button id="btn-email"
onclick="copyToClipboard('<?php echo htmlspecialchars($email, ENT_QUOTES); ?>', 'btn-email')"
class="shrink-0 p-3.5 bg-neutral-800 border border-neutral-700 rounded-xl text-neutral-400 hover:text-white hover:bg-neutral-700 hover:border-neutral-600 transition-all shadow-sm active:scale-95"
title="Copy Email">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
</button>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2">
<div
class="p-4 rounded-xl bg-neutral-800/30 border border-neutral-800 flex items-center justify-between group hover:border-green-500/20 transition-colors">
<div>
<p class="text-[10px] text-neutral-500 uppercase font-bold">Account Status</p>
<p class="text-xs font-semibold text-neutral-200 mt-1">
Activated
</p>
</div>
<svg class="w-5 h-5 text-green-400 drop-shadow-[0_0_6px_rgba(34,197,94,0.45)]"
fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div
class="p-4 rounded-xl bg-neutral-800/30 border border-neutral-800 flex items-center justify-between group hover:border-blue-500/20 transition-colors">
<div>
<p class="text-[10px] text-neutral-500 uppercase font-bold">CAMPUS ROLE</p>
<p class="text-xs font-semibold text-white mt-1">
<?php echo $is_admin ? 'Administrator' : 'Student'; ?>
</p>
</div>
<svg class="w-5 h-5 text-blue-400 opacity-90 transition-colors" fill="none"
stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
</div>
</div>
</div>
</div>
</div>
<div class="space-y-3">
<a
class="group flex items-center gap-4 p-4 rounded-xl bg-neutral-800/30 border border-neutral-800 hover:border-blue-500/30 hover:bg-neutral-800/50 transition-all duration-300">
<div
class="p-2.5 bg-blue-500/10 rounded-lg text-blue-400 group-hover:scale-110 transition-transform">
<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.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</div>
<div class="flex-1 min-w-0">
<p
class="text-xs font-bold text-white uppercase tracking-wide group-hover:text-blue-400 transition-colors">
IT Helpdesk Support</p>
<div class="text-[10px] text-neutral-400 mt-0.5">
<p><?php echo htmlspecialchars($helpdesk_email); ?></p>
<p><?php echo htmlspecialchars($helpdesk_phone); ?></p>
</div>
</div>
</a>
<div
class="group flex items-center gap-4 p-4 rounded-xl bg-neutral-800/30 border border-neutral-800 hover:border-purple-500/30 hover:bg-neutral-800/50 transition-all duration-300">
<div
class="p-2.5 bg-purple-500/10 rounded-lg text-purple-400 group-hover:scale-110 transition-transform">
<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" />
</svg>
</div>
<div class="flex-1 min-w-0">
<p
class="text-xs font-bold text-white uppercase tracking-wide group-hover:text-purple-400 transition-colors">
Management Support</p>
<div class="text-[10px] text-neutral-400 mt-0.5">
<p><?php echo htmlspecialchars($management_email); ?></p>
<p><?php echo htmlspecialchars($management_phone); ?></p>
</div>
</div>
</div>
<div
class="group flex items-center gap-4 p-4 rounded-xl bg-neutral-800/30 border border-neutral-800 hover:border-emerald-500/30 hover:bg-neutral-800/50 transition-all duration-300">
<div
class="p-2.5 bg-emerald-500/10 rounded-lg text-emerald-400 group-hover:scale-110 transition-transform">
<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="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
</svg>
</div>
<div class="flex-1 min-w-0">
<p
class="text-xs font-bold text-white uppercase tracking-wide group-hover:text-emerald-400 transition-colors">
Health & Food Support</p>
<div class="text-[10px] text-neutral-400 mt-0.5">
<p><?php echo htmlspecialchars($health_email); ?></p>
<p><?php echo htmlspecialchars($health_phone); ?></p>
</div>
</div>
</div>
<div
class="group flex items-center gap-4 p-4 rounded-xl bg-neutral-800/30 border border-neutral-800 hover:border-amber-500/30 hover:bg-neutral-800/50 transition-all duration-300">
<div
class="p-2.5 bg-amber-500/10 rounded-lg text-amber-400 group-hover:scale-110 transition-transform">
<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 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
</svg>
</div>
<div class="flex-1 min-w-0">
<p
class="text-xs font-bold text-white uppercase tracking-wide group-hover:text-amber-400 transition-colors">
Library & Books Support</p>
<div class="text-[10px] text-neutral-400 mt-0.5">
<p><?php echo htmlspecialchars($library_email); ?></p>
<p><?php echo htmlspecialchars($library_phone); ?></p>
</div>
</div>
</div>
<div
class="group flex items-center gap-4 p-4 rounded-xl bg-neutral-800/30 border border-neutral-800 hover:border-red-500/30 hover:bg-neutral-800/50 transition-all duration-300">
<div class="p-2.5 bg-red-500/10 rounded-lg text-red-400 group-hover:scale-110 transition-transform">
<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 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
</div>
<div class="flex-1 min-w-0">
<p
class="text-xs font-bold text-white uppercase tracking-wide group-hover:text-red-400 transition-colors">
Campus Security Support</p>
<div class="text-[10px] text-neutral-400 mt-0.5">
<p><?php echo htmlspecialchars($security_email); ?></p>
<p><?php echo htmlspecialchars($security_phone); ?></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script src="./../assets/js/account_config.js"></script>
</html>

View File

@@ -2,9 +2,9 @@
session_start(); session_start();
// Initialize the application // Initialize the application
include './core/init.php'; include './../core/init.php';
include './core/connection.php'; include './../core/connection.php';
include './core/languages/language_config.php'; include './../core/languages/language_config.php';
// Suppress all PHP errors in production environment // Suppress all PHP errors in production environment
ini_set('display_errors', 0); ini_set('display_errors', 0);
@@ -54,15 +54,15 @@ if (empty($current_texts) && !empty($languages)) {
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Favicon & PWA Assets --> <!-- Favicon & PWA Assets -->
<link rel="icon" type="image/png" href="./assets/favicon/favicon-96x96.png" sizes="96x96" /> <link rel="icon" type="image/png" href="./../assets/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./assets/favicon/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="./../assets/favicon/favicon.svg" />
<link rel="shortcut icon" href="./assets/favicon/favicon.ico" /> <link rel="shortcut icon" href="./../assets/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./assets/favicon/apple-touch-icon.png" /> <link rel="apple-touch-icon" sizes="180x180" href="./../assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="./assets/favicon/site.webmanifest" /> <link rel="manifest" href="./../assets/favicon/site.webmanifest" />
<meta name="apple-mobile-web-app-title" content="SteamsTube" /> <meta name="apple-mobile-web-app-title" content="<?php echo htmlspecialchars($_ENV['DOMAIN']); ?>" />
<!-- Main Stylesheet (Tailwind CSS) --> <!-- Main Stylesheet (Tailwind CSS) -->
<link rel="stylesheet" href="./src/output.css"> <link rel="stylesheet" href="./../src/output.css">
<!-- Google Fonts: Lexend Deca --> <!-- Google Fonts: Lexend Deca -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
@@ -73,7 +73,7 @@ if (empty($current_texts) && !empty($languages)) {
<title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title> <title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title>
<!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) --> <!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) -->
<?php include 'assets/_debug_kit.php'; ?> <?php include './../assets/_debug_kit.php'; ?>
</head> </head>
<body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4"> <body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4">
@@ -84,7 +84,7 @@ if (empty($current_texts) && !empty($languages)) {
<!-- Left Section --> <!-- Left Section -->
<div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start"> <div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start">
<div class="flex items-center mb-6"> <div class="flex items-center mb-6">
<img src="./assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900" <img src="./../assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900"
alt="xovae-logo" /> alt="xovae-logo" />
</div> </div>
<h1 class="text-3xl font-normal text-gray-200 mb-2"><?php echo t('create_an_account'); ?></h1> <h1 class="text-3xl font-normal text-gray-200 mb-2"><?php echo t('create_an_account'); ?></h1>
@@ -195,6 +195,6 @@ if (empty($current_texts) && !empty($languages)) {
</body> </body>
<!-- Scripts --> <!-- Scripts -->
<script src="assets/js/create_account_config.js"></script> <script src="./../assets/js/create_account_config.js"></script>
</html> </html>

View File

@@ -2,9 +2,9 @@
session_start(); session_start();
// Initialize the application // Initialize the application
include './core/init.php'; include './../core/init.php';
include './core/connection.php'; include './../core/connection.php';
include './core/languages/language_config.php'; include './../core/languages/language_config.php';
// Suppress all PHP errors in production environment // Suppress all PHP errors in production environment
ini_set('display_errors', 0); ini_set('display_errors', 0);
@@ -69,7 +69,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty($error) && isset($_POST['pass
if ($stmt) { if ($stmt) {
$stmt->bind_param("ssiss", $username, $email, $age, $gender, $password_hash); $stmt->bind_param("ssiss", $username, $email, $age, $gender, $password_hash);
if ($stmt->execute()) { if ($stmt->execute()) {
include './core/auth/mail/create_account_config.php'; include './../core/auth/mail/create_account_config.php';
sendAccountCreationMail($email, $username); sendAccountCreationMail($email, $username);
unset($_SESSION['signup']); unset($_SESSION['signup']);
@@ -99,15 +99,15 @@ if (empty($current_texts) && !empty($languages)) {
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Favicon & PWA --> <!-- Favicon & PWA -->
<link rel="icon" type="image/png" href="./assets/favicon/favicon-96x96.png" sizes="96x96" /> <link rel="icon" type="image/png" href="./../assets/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./assets/favicon/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="./../assets/favicon/favicon.svg" />
<link rel="shortcut icon" href="./assets/favicon/favicon.ico" /> <link rel="shortcut icon" href="./../assets/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./assets/favicon/apple-touch-icon.png" /> <link rel="apple-touch-icon" sizes="180x180" href="./../assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="./assets/favicon/site.webmanifest" /> <link rel="manifest" href="./../assets/favicon/site.webmanifest" />
<meta name="apple-mobile-web-app-title" content="SteamsTube" /> <meta name="apple-mobile-web-app-title" content="<?php echo htmlspecialchars($_ENV['DOMAIN']); ?>" />
<!-- TailwindCSS --> <!-- TailwindCSS -->
<link rel="stylesheet" href="./src/output.css"> <link rel="stylesheet" href="./../src/output.css">
<!-- Google Fonts --> <!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
@@ -118,7 +118,7 @@ if (empty($current_texts) && !empty($languages)) {
<title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title> <title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title>
<!-- Debug Kit --> <!-- Debug Kit -->
<?php include 'assets/_debug_kit.php'; ?> <?php include './../assets/_debug_kit.php'; ?>
</head> </head>
<body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4"> <body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4">
@@ -128,7 +128,7 @@ if (empty($current_texts) && !empty($languages)) {
<!-- Left --> <!-- Left -->
<div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start"> <div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start">
<div class="flex items-center mb-6"> <div class="flex items-center mb-6">
<img src="./assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900" <img src="./../assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900"
alt="xovae-logo" /> alt="xovae-logo" />
</div> </div>
<h1 class="text-3xl font-normal text-gray-200 mb-2"><?php echo t('create_password_title'); ?></h1> <h1 class="text-3xl font-normal text-gray-200 mb-2"><?php echo t('create_password_title'); ?></h1>
@@ -218,6 +218,6 @@ if (empty($current_texts) && !empty($languages)) {
</body> </body>
<!-- Scripts --> <!-- Scripts -->
<script src="assets/js/create_account_config.js"></script> <script src="./../assets/js/create_account_config.js"></script>
</html> </html>

65
src/pages/dashboard.php Normal file
View File

@@ -0,0 +1,65 @@
<?php
// Initialize the application
include './core/init.php';
include './core/router.php';
// Suppress all PHP errors in production environment
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
error_reporting(0);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Meta & Viewport Configuration -->
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Favicon & PWA Assets -->
<link rel="icon" type="image/png" href="./assets/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./assets/favicon/favicon.svg" />
<link rel="shortcut icon" href="./assets/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="./assets/favicon/site.webmanifest" />
<meta name="apple-mobile-web-app-title" content="<?php echo htmlspecialchars($_ENV['DOMAIN']); ?>" />
<!-- Main Stylesheet (Tailwind CSS) -->
<link rel="stylesheet" href="./src/output.css">
<!-- Google Fonts: Lexend Deca -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@100..900&display=swap" rel="stylesheet">
<!-- Dynamic Page Title (from .env DOMAIN variable) -->
<title><?php echo htmlspecialchars($_ENV['DOMAIN'] . ' - Dashboard'); ?></title>
<!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) -->
<?php include './assets/_debug_kit.php'; ?>
</head>
<body class="bg-neutral-900 text-gray-200 antialiased">
<?php include './assets/_navbar.php'; ?>
<div class="flex h-screen overflow-hidden">
<?php include './assets/_sidebar.php'; ?>
<main class="flex-1 overflow-y-auto p-6">
<div class="max-w-7xl mx-auto space-y-6">
<?php include $current_route['file']; ?>
</div>
</main>
</div>
<script src="./assets/js/dashboard_config.js"></script>
</body>
</html>

406
src/pages/error/404.php Normal file
View File

@@ -0,0 +1,406 @@
<?php
include './../../core/init.php';
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Service Paused - <?php echo htmlspecialchars($_ENV['DOMAIN']); ?></title>
<link rel="icon" type="image/png" href="./../../assets/favicon/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/svg+xml" href="./../../assets/favicon/favicon.svg">
<link rel="shortcut icon" href="./../../assets/favicon/favicon.ico">
<link rel="apple-touch-icon" sizes="180x180" href="./../../assets/favicon/apple-touch-icon.png">
<link rel="manifest" href="./../../assets/favicon/site.webmanifest">
<link rel="stylesheet" href="./../../assets/css/error_config.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@300;400;600;700&display=swap" rel="stylesheet">
<style>
:root{
--eerie-black:#060b14;
--pure-white:#ffffff;
--neon-sky:#37bbf9;
--neon-sky-translucent:rgba(55,187,249,0.2745098039);
--neon-sky-glow-weak:rgba(55,187,249,0.18);
--neon-sky-glow-mid:rgba(55,187,249,0.28);
--neon-sky-pressed:rgba(55,187,249,0.2745098039);
--transparent-dark:rgba(6,11,20,0);
}
*,*:before,*:after{box-sizing:border-box;}
*{-webkit-tap-highlight-color:rgba(0,0,0,0);transform-style:preserve-3d;}
*:focus{outline:none!important;}
body,html{height:100%;margin:0;}
body{
display:flex;
align-items:center;
align-content:center;
justify-content:center;
padding:12px;
background:var(--eerie-black);
color:var(--pure-white);
font-family:"Lexend Deca", sans-serif;
font-feature-settings:"liga","ss05" on,"ss07" on;
font-size:24px;
text-rendering:optimizeLegibility;
-webkit-font-smoothing:antialiased;
overflow-x:hidden;
}
::selection{background:none;}
.return-btn{
font:inherit;
background:none;
border:none;
color:var(--pure-white);
text-align:left;
cursor:pointer;
padding:0;
transition:color 150ms ease,text-shadow 150ms ease,opacity 120ms ease;
animation:return-blink 2.4s ease-in-out infinite;
animation-play-state:running;
}
.return-btn:hover,
.return-btn:focus,
.return-btn:focus-visible{
color:var(--neon-sky);
animation:none!important;
animation-play-state:paused!important;
opacity:1!important;
text-shadow:0 0 10px var(--neon-sky-glow-mid);
outline:none;
}
svg{width:70px;height:auto;}
.crack{position:relative;z-index:4;margin-left:-46px;}
.crack polyline{
fill:none;
stroke:var(--neon-sky);
stroke-width:10px;
stroke-linecap:round;
stroke-linejoin:round;
stroke-dasharray:1649.099;
stroke-dashoffset:1649.099;
animation:drawStroke 1500ms ease-out 500ms forwards;
}
main{
display:flex;
align-items:center;
align-content:center;
justify-content:center;
width:100%;
max-width:100vw;
}
main>div{
display:flex;
align-items:center;
align-content:center;
position:relative;
overflow:hidden;
}
main>div svg{position:relative;z-index:1;}
main>div svg polygon{fill:var(--eerie-black);}
main>div span{
display:block;
position:relative;
z-index:0;
padding:0 12px;
line-height:1.4;
}
main>div:first-child{text-align:right;z-index:1;}
main>div:first-child span:first-child{
opacity:0;
transform:translateX(100%);
animation:translateLeft 1000ms linear 1250ms forwards;
}
main>div:first-child span:last-child{
opacity:0;
transform:translateX(100%);
animation:translateLeft 1000ms linear 1450ms forwards;
}
main>div:first-child svg polygon{
animation:removeFill 10ms ease-out 1600ms forwards;
}
main>div:last-child{
z-index:0;
margin-left:-50px;
}
main>div:last-child span:first-child{
opacity:0;
transform:translateX(-100%);
animation:translateRight 1000ms linear 1650ms forwards;
}
main>div:last-child span:last-child{
opacity:0;
transform:translateX(-100%);
animation:translateRight 1000ms linear 1850ms forwards;
}
@keyframes drawStroke{
0%{stroke-dashoffset:1649.099;}
100%{stroke-dashoffset:0;}
}
@keyframes removeFill{
0%{fill:var(--eerie-black);}
100%{fill:var(--transparent-dark);}
}
@keyframes pulseColor{
0%{color:var(--pure-white);}
25%{color:var(--neon-sky-translucent);}
50%{color:var(--pure-white);}
75%{color:var(--neon-sky-translucent);}
100%{color:var(--pure-white);}
}
@keyframes translateLeft{
0%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,150,0,0,1);opacity:1;}
7.61%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,69.561,0,0,1);}
11.41%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,39.355,0,0,1);}
15.12%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,17.801,0,0,1);}
18.92%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,3.02,0,0,1);}
22.72%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,-5.661,0,0,1);}
30.23%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,-10.852,0,0,1);}
50.25%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,-2.282,0,0,1);}
70.27%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0.519,0,0,1);}
100%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);opacity:1;}
}
@keyframes translateRight{
0%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,-150,0,0,1);opacity:1;}
7.61%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,-69.561,0,0,1);}
11.41%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,-39.355,0,0,1);}
15.12%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,-17.801,0,0,1);}
18.92%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,-3.02,0,0,1);}
22.72%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,5.661,0,0,1);}
30.23%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,10.852,0,0,1);}
50.25%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,2.282,0,0,1);}
70.27%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,-0.519,0,0,1);}
100%{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);opacity:1;}
}
@keyframes return-blink{
0%{opacity:1;text-shadow:none;}
40%{opacity:.62;text-shadow:0 0 6px #37bbf949;}
60%{opacity:.92;text-shadow:0 0 10px #37bbf949;}
100%{opacity:1;text-shadow:none;}
}
@media (max-width:1024px){
body{
font-size:22px;
padding:10px;
}
svg{
width:64px;
}
.crack{
margin-left:-44px;
}
main>div:last-child{
margin-left:-46px;
}
main>div span{
padding:0 12px;
}
.return-btn{
font-size:22px;
padding:4px 0;
line-height:1.2;
}
}
@media (max-width:768px){
body{
font-size:20px;
padding:10px;
}
svg{
width:58px;
}
.crack{
margin-left:-40px;
}
main>div:last-child{
margin-left:-42px;
}
main>div span{
padding:0 10px;
line-height:1.35;
}
.return-btn{
font-size:20px;
}
}
@media (max-width:600px){
body{
font-size:18px;
padding:10px;
}
main{
transform:scale(1.1);
}
svg{
width:54px;
}
.crack{
margin-left:-38px;
}
main>div:last-child{
margin-left:-40px;
}
main>div span{
padding:0 10px;
line-height:1.3;
}
.return-btn{
font-size:18px;
}
}
@media (max-width:480px){
body{
font-size:17px;
padding:8px;
}
main{
transform:scale(1.05);
}
svg{
width:50px;
}
.crack{
margin-left:-36px;
}
main>div:last-child{
margin-left:-38px;
}
main>div span{
padding:0 8px;
line-height:1.3;
}
.return-btn{
font-size:17px;
}
}
@media (max-width:400px){
body{
font-size:16px;
padding:8px;
}
main{
transform:scale(1.0);
}
svg{
width:46px;
}
.crack{
margin-left:-34px;
}
main>div:last-child{
margin-left:-36px;
}
main>div span{
padding:0 8px;
line-height:1.25;
}
.return-btn{
font-size:16px;
}
}
@media (max-width:360px){
body{
font-size:15px;
padding:6px;
}
main{
transform:scale(0.95);
}
svg{
width:42px;
}
.crack{
margin-left:-32px;
}
main>div:last-child{
margin-left:-34px;
}
main>div span{
padding:0 6px;
line-height:1.25;
}
.return-btn{
font-size:15px;
}
}
@media (max-height:500px) and (orientation:landscape){
body{
font-size:14px;
padding:6px;
}
main{
transform:scale(0.85);
}
svg{
width:38px;
}
.crack{
margin-left:-28px;
}
main>div:last-child{
margin-left:-30px;
}
}
</style>
</head>
<body class="body-font">
<main>
<div>
<div><span>404 error</span><span>page not found</span></div>
<svg viewBox="0 0 200 600">
<polygon
points="118.302698 8 59.5369448 66.7657528 186.487016 193.715824 14 366.202839 153.491505 505.694344 68.1413353 591.044514 200 591.044514 200 8">
</polygon>
</svg>
</div>
<svg class="crack" viewBox="0 0 200 600">
<polyline
points="118.302698 8 59.5369448 66.7657528 186.487016 193.715824 14 366.202839 153.491505 505.694344 68.1413353 591.044514">
</polyline>
</svg>
<div>
<svg viewBox="0 0 200 600">
<polygon
points="118.302698 8 59.5369448 66.7657528 186.487016 193.715824 14 366.202839 153.491505 505.694344 68.1413353 591.044514 0 591.044514 0 8">
</polygon>
</svg>
<div><span>sorry&nbsp;about&nbsp;that!</span>
<span>
<button class="return-btn" onclick="window.location.href='./../../index.php'">
return home?
</button>
</span>
</div>
</main>
</body>
</html>

View File

@@ -16,15 +16,15 @@ include './core/init.php';
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Favicon & PWA Assets --> <!-- Favicon & PWA Assets -->
<link rel="icon" type="image/png" href="./assets/favicon/favicon-96x96.png" sizes="96x96" /> <link rel="icon" type="image/png" href="./../assets/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./assets/favicon/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="./../assets/favicon/favicon.svg" />
<link rel="shortcut icon" href="./assets/favicon/favicon.ico" /> <link rel="shortcut icon" href="./../assets/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./assets/favicon/apple-touch-icon.png" /> <link rel="apple-touch-icon" sizes="180x180" href="./../assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="./assets/favicon/site.webmanifest" /> <link rel="manifest" href="./../assets/favicon/site.webmanifest" />
<meta name="apple-mobile-web-app-title" content="SteamsTube" /> <meta name="apple-mobile-web-app-title" content="<?php echo htmlspecialchars($_ENV['DOMAIN']); ?>" />
<!-- Main Stylesheet (Tailwind CSS) --> <!-- Main Stylesheet (Tailwind CSS) -->
<link rel="stylesheet" href="./src/output.css"> <link rel="stylesheet" href="./../src/output.css">
<!-- Google Fonts: Lexend Deca --> <!-- Google Fonts: Lexend Deca -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
@@ -35,14 +35,14 @@ include './core/init.php';
<title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title> <title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title>
<!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) --> <!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) -->
<?php include 'assets/_debug_kit.php'; ?> <?php include './../assets/_debug_kit.php'; ?>
</head> </head>
<body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4"> <body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4">
<!-- Includes --> <!-- Includes -->
<?php include './core/connection.php'; ?> <?php include './../core/connection.php'; ?>
<?php include './core/languages/language_config.php';?> <?php include './../core/languages/language_config.php';?>
<?php include './core/feedback/mail/feedback_config.php';?> <?php include './../core/feedback/mail/feedback_config.php';?>
<?php <?php
// Handles the language selection // Handles the language selection
@@ -79,7 +79,7 @@ include './core/init.php';
<!-- Left --> <!-- Left -->
<div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start"> <div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start">
<div class="flex items-center mb-6"> <div class="flex items-center mb-6">
<img src="./assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900" alt="xovae-logo" /> <img src="./../assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900" alt="xovae-logo" />
</div> </div>
<h1 class="text-3xl font-normal text-gray-200 mb-2">Language Support</h1> <h1 class="text-3xl font-normal text-gray-200 mb-2">Language Support</h1>
<p class="text-gray-400"> <p class="text-gray-400">

View File

@@ -3,16 +3,16 @@
session_start(); session_start();
// Initialize the application // Initialize the application
include './core/init.php'; include './../core/init.php';
// Suppress all PHP errors in production environment // Suppress all PHP errors in production environment
ini_set('display_errors', 0); ini_set('display_errors', 0);
ini_set('display_startup_errors', 0); ini_set('display_startup_errors', 0);
error_reporting(0); error_reporting(0);
include './core/connection.php'; include './../core/connection.php';
include './core/languages/language_config.php'; include './../core/languages/language_config.php';
include './core/forgot/mail/forgot_email_config.php'; include './../core/forgot/mail/forgot_email_config.php';
// Handle language selection // Handle language selection
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['language']) && in_array($_POST['language'], $languages, true)) { if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['language']) && in_array($_POST['language'], $languages, true)) {
@@ -89,15 +89,15 @@ if (!empty($_SESSION['forgot_success'])) {
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Favicon & PWA Assets --> <!-- Favicon & PWA Assets -->
<link rel="icon" type="image/png" href="./assets/favicon/favicon-96x96.png" sizes="96x96" /> <link rel="icon" type="image/png" href="./../assets/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./assets/favicon/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="./../assets/favicon/favicon.svg" />
<link rel="shortcut icon" href="./assets/favicon/favicon.ico" /> <link rel="shortcut icon" href="./../assets/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./assets/favicon/apple-touch-icon.png" /> <link rel="apple-touch-icon" sizes="180x180" href="./../assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="./assets/favicon/site.webmanifest" /> <link rel="manifest" href="./../assets/favicon/site.webmanifest" />
<meta name="apple-mobile-web-app-title" content="SteamsTube" /> <meta name="apple-mobile-web-app-title" content="<?php echo htmlspecialchars($_ENV['DOMAIN']); ?>" />
<!-- Main Stylesheet (Tailwind CSS) --> <!-- Main Stylesheet (Tailwind CSS) -->
<link rel="stylesheet" href="./src/output.css"> <link rel="stylesheet" href="./../src/output.css">
<!-- Google Fonts: Lexend Deca --> <!-- Google Fonts: Lexend Deca -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
@@ -108,7 +108,7 @@ if (!empty($_SESSION['forgot_success'])) {
<title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title> <title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title>
<!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) --> <!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) -->
<?php include 'assets/_debug_kit.php'; ?> <?php include './../assets/_debug_kit.php'; ?>
</head> </head>
<body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4"> <body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4">
@@ -118,7 +118,7 @@ if (!empty($_SESSION['forgot_success'])) {
<!-- Left --> <!-- Left -->
<div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start"> <div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start">
<div class="flex items-center mb-6"> <div class="flex items-center mb-6">
<img src="./assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900" <img src="./../assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900"
alt="xovae-logo" /> alt="xovae-logo" />
</div> </div>
<h1 class="text-3xl font-normal text-gray-200 mb-2"><?php echo t('find_email_title'); ?></h1> <h1 class="text-3xl font-normal text-gray-200 mb-2"><?php echo t('find_email_title'); ?></h1>
@@ -208,6 +208,7 @@ if (!empty($_SESSION['forgot_success'])) {
</body> </body>
<!-- Scripts --> <!-- Scripts -->
<script src="./assets/js/forgot_email_config.js"></script> <script src="./../assets/js/forgot_email_config.js"></script>
</html> </html>

View File

@@ -3,10 +3,10 @@
session_start(); session_start();
// Initialize the application // Initialize the application
include './core/init.php'; include './../core/init.php';
include './core/connection.php'; include './../core/connection.php';
include './core/languages/language_config.php'; include './../core/languages/language_config.php';
include './core/auth/mail/forgot_password_config.php'; // sendPasswordResetSuccessMail() - success mail include './../core/auth/mail/forgot_password_config.php'; // sendPasswordResetSuccessMail() - success mail
// Suppress all PHP errors in production environment // Suppress all PHP errors in production environment
ini_set('display_errors', 0); ini_set('display_errors', 0);
@@ -297,15 +297,15 @@ if (
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Favicon & PWA Assets --> <!-- Favicon & PWA Assets -->
<link rel="icon" type="image/png" href="./assets/favicon/favicon-96x96.png" sizes="96x96" /> <link rel="icon" type="image/png" href="./../assets/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./assets/favicon/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="./../assets/favicon/favicon.svg" />
<link rel="shortcut icon" href="./assets/favicon/favicon.ico" /> <link rel="shortcut icon" href="./../assets/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./assets/favicon/apple-touch-icon.png" /> <link rel="apple-touch-icon" sizes="180x180" href="./../assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="./assets/favicon/site.webmanifest" /> <link rel="manifest" href="./../assets/favicon/site.webmanifest" />
<meta name="apple-mobile-web-app-title" content="SteamsTube" /> <meta name="apple-mobile-web-app-title" content="<?php echo htmlspecialchars($_ENV['DOMAIN']); ?>" />
<!-- Main Stylesheet (Tailwind CSS) --> <!-- Main Stylesheet (Tailwind CSS) -->
<link rel="stylesheet" href="./src/output.css"> <link rel="stylesheet" href="./../src/output.css">
<!-- Google Fonts: Lexend Deca --> <!-- Google Fonts: Lexend Deca -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
@@ -316,7 +316,7 @@ if (
<title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title> <title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title>
<!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) --> <!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) -->
<?php include 'assets/_debug_kit.php'; ?> <?php include './../assets/_debug_kit.php'; ?>
</head> </head>
<body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4"> <body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4">
@@ -326,7 +326,7 @@ if (
<!-- Left Side Content --> <!-- Left Side Content -->
<div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start"> <div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start">
<div class="flex items-center mb-6"> <div class="flex items-center mb-6">
<img src="./assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900" <img src="./../assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900"
alt="xovae-logo" /> alt="xovae-logo" />
</div> </div>
<h1 class="text-3xl font-normal text-gray-200 mb-2"><?php echo t('reset_password_title'); ?></h1> <h1 class="text-3xl font-normal text-gray-200 mb-2"><?php echo t('reset_password_title'); ?></h1>
@@ -436,6 +436,6 @@ if (
</body> </body>
<!-- Scripts --> <!-- Scripts -->
<script src="assets/js/forgot_password_config.js"></script> <script src="./../assets/js/forgot_password_config.js"></script>
</html> </html>

View File

@@ -2,9 +2,9 @@
session_start(); session_start();
// Initialize the application // Initialize the application
include './core/init.php'; include './../core/init.php';
include './core/connection.php'; include './../core/connection.php';
include './core/languages/language_config.php'; include './../core/languages/language_config.php';
// Suppress all PHP errors in production environment // Suppress all PHP errors in production environment
ini_set('display_errors', 0); ini_set('display_errors', 0);
@@ -34,7 +34,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['input'])) {
$stmt->fetch(); $stmt->fetch();
$_SESSION['signin_email'] = $email; $_SESSION['signin_email'] = $email;
header('Location: sign_in_password.php'); header('Location: ./sign_in_password.php');
exit; exit;
} else { } else {
$error = t('account_not_found'); $error = t('account_not_found');
@@ -69,15 +69,15 @@ if (empty($current_texts) && !empty($languages)) {
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Favicon & PWA Assets --> <!-- Favicon & PWA Assets -->
<link rel="icon" type="image/png" href="./assets/favicon/favicon-96x96.png" sizes="96x96" /> <link rel="icon" type="image/png" href="./../assets/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./assets/favicon/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="./../assets/favicon/favicon.svg" />
<link rel="shortcut icon" href="./assets/favicon/favicon.ico" /> <link rel="shortcut icon" href="./../assets/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./assets/favicon/apple-touch-icon.png" /> <link rel="apple-touch-icon" sizes="180x180" href="./../assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="./assets/favicon/site.webmanifest" /> <link rel="manifest" href="./../assets/favicon/site.webmanifest" />
<meta name="apple-mobile-web-app-title" content="SteamsTube" /> <meta name="apple-mobile-web-app-title" content="<?php echo htmlspecialchars($_ENV['DOMAIN']); ?>" />
<!-- Main Stylesheet (Tailwind CSS) --> <!-- Main Stylesheet (Tailwind CSS) -->
<link rel="stylesheet" href="./src/output.css"> <link rel="stylesheet" href="./../src/output.css">
<!-- Google Fonts: Lexend Deca --> <!-- Google Fonts: Lexend Deca -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
@@ -88,7 +88,7 @@ if (empty($current_texts) && !empty($languages)) {
<title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title> <title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title>
<!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) --> <!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) -->
<?php include 'assets/_debug_kit.php'; ?> <?php include './../assets/_debug_kit.php'; ?>
</head> </head>
<body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4"> <body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4">
@@ -99,7 +99,7 @@ if (empty($current_texts) && !empty($languages)) {
<!-- Left Side --> <!-- Left Side -->
<div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start"> <div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start">
<div class="flex items-center mb-6"> <div class="flex items-center mb-6">
<img src="./assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900" <img src="./../assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900"
alt="xovae-logo" /> alt="xovae-logo" />
</div> </div>
<h1 class="text-3xl font-normal text-gray-200 mb-2"><?php echo t('sign_in'); ?></h1> <h1 class="text-3xl font-normal text-gray-200 mb-2"><?php echo t('sign_in'); ?></h1>
@@ -189,6 +189,6 @@ if (empty($current_texts) && !empty($languages)) {
</body> </body>
<!-- Scripts --> <!-- Scripts -->
<script src="assets/js/sign_in_config.js"></script> <script src="./../assets/js/sign_in_config.js"></script>
</html> </html>

View File

@@ -2,11 +2,10 @@
session_start(); session_start();
// Initialize the application // Initialize the application
include './core/init.php'; include './../core/init.php';
include './core/connection.php'; include './../core/connection.php';
include './core/languages/language_config.php'; include './../core/languages/language_config.php';
include './core/auth/mail/forgot_password_config.php'; include './../core/auth/mail/forgot_password_config.php';
// Suppress all PHP errors in production environment // Suppress all PHP errors in production environment
ini_set('display_errors', 0); ini_set('display_errors', 0);
ini_set('display_startup_errors', 0); ini_set('display_startup_errors', 0);
@@ -124,7 +123,7 @@ if (
if (empty($password)) { if (empty($password)) {
$error = t('empty_password_error'); $error = t('empty_password_error');
} else { } else {
$stmt = $conn->prepare("SELECT id, password_hash FROM users WHERE email = ? LIMIT 1"); $stmt = $conn->prepare(" SELECT id, password_hash, is_admin FROM users WHERE email = ? LIMIT 1 ");
if (!$stmt) { if (!$stmt) {
$error = t('database_prepare_failed'); $error = t('database_prepare_failed');
@@ -134,13 +133,14 @@ if (
$stmt->store_result(); $stmt->store_result();
if ($stmt->num_rows > 0) { if ($stmt->num_rows > 0) {
$stmt->bind_result($user_id, $hashed_password); $stmt->bind_result($user_id, $hashed_password, $is_admin);
$stmt->fetch(); $stmt->fetch();
if (password_verify($password, $hashed_password)) { if (password_verify($password, $hashed_password)) {
$_SESSION['user_id'] = $user_id; $_SESSION['user_id'] = $user_id;
$_SESSION['logged_in'] = true; $_SESSION['logged_in'] = true;
$_SESSION['user_email'] = $email; $_SESSION['user_email'] = $email;
$_SESSION['is_admin'] = (bool) $is_admin;
// Fetch username for display // Fetch username for display
$user_stmt = $conn->prepare("SELECT username FROM users WHERE id = ? LIMIT 1"); $user_stmt = $conn->prepare("SELECT username FROM users WHERE id = ? LIMIT 1");
@@ -152,7 +152,7 @@ if (
$user_stmt->close(); $user_stmt->close();
unset($_SESSION['signin_email']); unset($_SESSION['signin_email']);
header('Location: home.php'); header('Location: ./../index.php');
exit; exit;
} else { } else {
$error = t('incorrect_password'); $error = t('incorrect_password');
@@ -184,16 +184,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['language']) && in_arr
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Favicon & PWA Assets --> <!-- Favicon & PWA Assets -->
<link rel="icon" type="image/png" href="./assets/favicon/favicon-96x96.png" sizes="96x96" /> <link rel="icon" type="image/png" href="./../assets/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./assets/favicon/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="./../assets/favicon/favicon.svg" />
<link rel="shortcut icon" href="./assets/favicon/favicon.ico" /> <link rel="shortcut icon" href="./../assets/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./assets/favicon/apple-touch-icon.png" /> <link rel="apple-touch-icon" sizes="180x180" href="./../assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="./assets/favicon/site.webmanifest" /> <link rel="manifest" href="./../assets/favicon/site.webmanifest" />
<meta name="apple-mobile-web-app-title" content="SteamsTube" /> <meta name="apple-mobile-web-app-title" content="<?php echo htmlspecialchars($_ENV['DOMAIN']); ?>" />
<!-- Main Stylesheet (Tailwind CSS) --> <!-- Main Stylesheet (Tailwind CSS) -->
<link rel="stylesheet" href="./src/output.css"> <link rel="stylesheet" href="./../src/output.css">
<!-- Google Fonts: Lexend Deca --> <!-- Google Fonts: Lexend Deca -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -203,7 +202,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['language']) && in_arr
<title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title> <title><?php echo htmlspecialchars(!empty($_ENV['DOMAIN']) ? $_ENV['DOMAIN'] : 'UNKNOWN DOMAIN'); ?></title>
<!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) --> <!-- Debug Kit: Optional outline borders (toggled via .env DEBUG_MODE) -->
<?php include 'assets/_debug_kit.php'; ?> <?php include './../assets/_debug_kit.php'; ?>
</head> </head>
<body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4"> <body class="bg-neutral-900 text-gray-200 flex items-center justify-center min-h-screen p-4">
@@ -214,7 +213,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['language']) && in_arr
<!-- Left Side --> <!-- Left Side -->
<div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start"> <div class="p-8 md:p-12 flex flex-col self-start text-center md:text-left items-center md:items-start">
<div class="flex items-center mb-6"> <div class="flex items-center mb-6">
<img src="./assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900" <img src="./../assets/images/logos/xovae.svg" class="h-14 w-auto rounded-full bg-neutral-900"
alt="xovae-logo" /> alt="xovae-logo" />
</div> </div>
<h1 class="text-3xl font-normal text-gray-200 mb-2"><?php echo t('sign_in'); ?></h1> <h1 class="text-3xl font-normal text-gray-200 mb-2"><?php echo t('sign_in'); ?></h1>
@@ -312,6 +311,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['language']) && in_arr
</body> </body>
<!-- Scripts --> <!-- Scripts -->
<script src="assets/js/sign_in_config.js"></script> <script src="./../assets/js/sign_in_config.js"></script>
</html> </html>

File diff suppressed because it is too large Load Diff