1122 lines
52 KiB
Markdown
1122 lines
52 KiB
Markdown
# Dark Crime Theme Implementation Plan
|
|||
|
|
|
||
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||
|
|
|
||
|
|
**Goal:** Apply a dark, crime-themed UI to the full Laravel/Blade/Tailwind game — sidebar layout, blood-red accents, near-black backgrounds — across all game and auth pages.
|
||
|
|
|
||
|
|
**Architecture:** All styling is done via Tailwind utility classes directly in Blade templates. A custom color palette (`syndicate`, `crime`, `gold`) is registered in `tailwind.config.js`. No new CSS files are created — the existing `resources/css/app.css` (`@tailwind base/components/utilities`) is sufficient.
|
||
|
|
|
||
|
|
**Tech Stack:** Laravel 11, Blade templates, Tailwind CSS v3, `@tailwindcss/forms`, Alpine.js (already present via `x-data`), Bunny Fonts.
|
||
|
|
|
||
|
|
## Global Constraints
|
||
|
|
|
||
|
|
- Never add new PHP files — only modify Blade templates and `tailwind.config.js`
|
||
|
|
- Keep all existing route names and form actions unchanged
|
||
|
|
- Preserve Alpine.js `x-data` / `@click` attributes on the navigation
|
||
|
|
- Use exact color token names: `syndicate-{950,900,800,700,600}`, `crime-{600,500,400}`, `gold-{500,400}`
|
||
|
|
- Font families: `font-sans` = Inter, `font-display` = Rajdhani
|
||
|
|
- Bunny Fonts URL format: `https://fonts.bunny.net/css?family=inter:400,500,600|rajdhani:600,700&display=swap`
|
||
|
|
- No mobile sidebar collapse — out of scope
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## File Map
|
||
|
|
|
||
|
|
| File | Action | Responsibility |
|
||
|
|
|---|---|---|
|
||
|
|
| `tailwind.config.js` | Modify | Register color palette + font-display |
|
||
|
|
| `resources/views/layouts/app.blade.php` | Modify | Dark body bg, new font link |
|
||
|
|
| `resources/views/layouts/guest.blade.php` | Modify | Dark auth wrapper + card |
|
||
|
|
| `resources/views/layouts/game.blade.php` | Rewrite | Sidebar + top bar shell |
|
||
|
|
| `resources/views/layouts/navigation.blade.php` | Rewrite | Sidebar nav links (replaces top-nav) |
|
||
|
|
| `resources/views/game/partials/stats-bar.blade.php` | Rewrite | Compact HP/Energy/Cash pills |
|
||
|
|
| `resources/views/components/primary-button.blade.php` | Modify | Crime-red button |
|
||
|
|
| `resources/views/components/secondary-button.blade.php` | Modify | Syndicate-dark button |
|
||
|
|
| `resources/views/components/text-input.blade.php` | Modify | Dark input field |
|
||
|
|
| `resources/views/components/input-label.blade.php` | Modify | Light label text |
|
||
|
|
| `resources/views/game/dashboard.blade.php` | Modify | Dark card classes throughout |
|
||
|
|
| `resources/views/game/crimes/index.blade.php` | Modify | Dark card/button classes |
|
||
|
|
| `resources/views/game/inventory/index.blade.php` | Modify | Dark card/button classes |
|
||
|
|
| `resources/views/game/hospital.blade.php` | Modify | Dark card classes |
|
||
|
|
| `resources/views/game/jail.blade.php` | Modify | Dark card classes |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 1: Register color palette and fonts in Tailwind config
|
||
|
|
|
||
|
|
**Files:**
|
||
|
|
- Modify: `tailwind.config.js`
|
||
|
|
- Modify: `resources/views/layouts/app.blade.php`
|
||
|
|
- Modify: `resources/views/layouts/guest.blade.php`
|
||
|
|
|
||
|
|
**Interfaces:**
|
||
|
|
- Produces: color tokens `syndicate-{950,900,800,700,600}`, `crime-{600,500,400}`, `gold-{500,400}`, font family `font-display` — used by every subsequent task
|
||
|
|
|
||
|
|
- [ ] **Step 1: Update tailwind.config.js**
|
||
|
|
|
||
|
|
Replace the entire file content with:
|
||
|
|
|
||
|
|
```js
|
||
|
|
import defaultTheme from 'tailwindcss/defaultTheme';
|
||
|
|
import forms from '@tailwindcss/forms';
|
||
|
|
|
||
|
|
/** @type {import('tailwindcss').Config} */
|
||
|
|
export default {
|
||
|
|
content: [
|
||
|
|
'./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
|
||
|
|
'./storage/framework/views/*.php',
|
||
|
|
'./resources/views/**/*.blade.php',
|
||
|
|
],
|
||
|
|
|
||
|
|
theme: {
|
||
|
|
extend: {
|
||
|
|
fontFamily: {
|
||
|
|
sans: ['Inter', ...defaultTheme.fontFamily.sans],
|
||
|
|
display: ['Rajdhani', ...defaultTheme.fontFamily.sans],
|
||
|
|
},
|
||
|
|
colors: {
|
||
|
|
syndicate: {
|
||
|
|
950: '#0a0a0c',
|
||
|
|
900: '#111114',
|
||
|
|
800: '#1a1a1f',
|
||
|
|
700: '#242429',
|
||
|
|
600: '#2e2e35',
|
||
|
|
},
|
||
|
|
crime: {
|
||
|
|
600: '#dc2626',
|
||
|
|
500: '#ef4444',
|
||
|
|
400: '#f87171',
|
||
|
|
},
|
||
|
|
gold: {
|
||
|
|
500: '#d97706',
|
||
|
|
400: '#fbbf24',
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
|
||
|
|
plugins: [forms],
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 2: Update app.blade.php font link and body class**
|
||
|
|
|
||
|
|
Replace `resources/views/layouts/app.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
<!DOCTYPE html>
|
||
|
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||
|
|
<head>
|
||
|
|
<meta charset="utf-8">
|
||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
|
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||
|
|
|
||
|
|
<title>@yield('title', config('app.name', 'Laravel'))</title>
|
||
|
|
|
||
|
|
<!-- Fonts -->
|
||
|
|
<link rel="preconnect" href="https://fonts.bunny.net">
|
||
|
|
<link href="https://fonts.bunny.net/css?family=inter:400,500,600|rajdhani:600,700&display=swap" rel="stylesheet" />
|
||
|
|
|
||
|
|
<!-- Scripts -->
|
||
|
|
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||
|
|
</head>
|
||
|
|
<body class="font-sans antialiased bg-syndicate-950 text-gray-100 min-h-screen">
|
||
|
|
@yield('content')
|
||
|
|
</body>
|
||
|
|
</html>
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 3: Update guest.blade.php for dark auth layout**
|
||
|
|
|
||
|
|
Replace `resources/views/layouts/guest.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
<!DOCTYPE html>
|
||
|
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||
|
|
<head>
|
||
|
|
<meta charset="utf-8">
|
||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
|
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||
|
|
|
||
|
|
<title>{{ config('app.name', 'Laravel') }}</title>
|
||
|
|
|
||
|
|
<!-- Fonts -->
|
||
|
|
<link rel="preconnect" href="https://fonts.bunny.net">
|
||
|
|
<link href="https://fonts.bunny.net/css?family=inter:400,500,600|rajdhani:600,700&display=swap" rel="stylesheet" />
|
||
|
|
|
||
|
|
<!-- Scripts -->
|
||
|
|
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||
|
|
</head>
|
||
|
|
<body class="font-sans antialiased bg-syndicate-950 text-gray-100 min-h-screen">
|
||
|
|
<div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0">
|
||
|
|
<div class="mb-6">
|
||
|
|
<a href="/" class="font-display text-3xl font-bold text-crime-400 tracking-wide uppercase">
|
||
|
|
{{ config('app.name', 'The Crime Syndicate') }}
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="w-full sm:max-w-md px-8 py-8 bg-syndicate-800 border border-syndicate-700 shadow-xl overflow-hidden sm:rounded-lg">
|
||
|
|
{{ $slot }}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</body>
|
||
|
|
</html>
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 4: Build assets and verify no Tailwind errors**
|
||
|
|
|
||
|
|
Run:
|
||
|
|
```bash
|
||
|
|
cd /home/liquidsky/Projects/thecrimesyndicate && npm run build 2>&1 | tail -20
|
||
|
|
```
|
||
|
|
|
||
|
|
Expected: build completes with no errors. The output should mention `app.css` and `app.js`.
|
||
|
|
|
||
|
|
- [ ] **Step 5: Commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /home/liquidsky/Projects/thecrimesyndicate
|
||
|
|
git add tailwind.config.js resources/views/layouts/app.blade.php resources/views/layouts/guest.blade.php
|
||
|
|
git commit -m "feat: register syndicate/crime/gold color palette and Inter/Rajdhani fonts"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 2: Rewrite game layout with sidebar + top bar
|
||
|
|
|
||
|
|
**Files:**
|
||
|
|
- Rewrite: `resources/views/layouts/game.blade.php`
|
||
|
|
- Rewrite: `resources/views/layouts/navigation.blade.php`
|
||
|
|
- Rewrite: `resources/views/game/partials/stats-bar.blade.php`
|
||
|
|
|
||
|
|
**Interfaces:**
|
||
|
|
- Consumes: color tokens from Task 1
|
||
|
|
- Produces: `@yield('game-content')` content slot consumed by all game pages; `$character` variable (already passed by game controllers)
|
||
|
|
|
||
|
|
- [ ] **Step 1: Rewrite game.blade.php**
|
||
|
|
|
||
|
|
Replace `resources/views/layouts/game.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
@extends('layouts.app')
|
||
|
|
|
||
|
|
@section('title', config('game.name', 'The Crime Syndicate') . ' - ' . ($title ?? 'Game'))
|
||
|
|
|
||
|
|
@section('content')
|
||
|
|
<div class="flex flex-col min-h-screen">
|
||
|
|
|
||
|
|
{{-- TOP BAR --}}
|
||
|
|
<header class="bg-syndicate-900 border-b border-syndicate-700 h-14 flex items-center px-6 flex-shrink-0 z-10">
|
||
|
|
{{-- Logo --}}
|
||
|
|
<a href="{{ route('game.dashboard') }}" class="font-display font-bold text-xl text-crime-400 uppercase tracking-widest mr-8 flex-shrink-0">
|
||
|
|
{{ config('game.name', 'The Crime Syndicate') }}
|
||
|
|
</a>
|
||
|
|
|
||
|
|
{{-- Stats bar --}}
|
||
|
|
<div class="flex-1 flex items-center justify-center space-x-4">
|
||
|
|
@if(auth()->check() && auth()->user()->character)
|
||
|
|
@include('game.partials.stats-bar')
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{{-- User menu --}}
|
||
|
|
<div class="flex items-center space-x-3 flex-shrink-0">
|
||
|
|
<span class="text-sm text-gray-400">{{ auth()->user()->name ?? '' }}</span>
|
||
|
|
<div x-data="{ open: false }" class="relative">
|
||
|
|
<button @click="open = !open" class="flex items-center text-gray-400 hover:text-gray-100 transition">
|
||
|
|
<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="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
|
||
|
|
</svg>
|
||
|
|
</button>
|
||
|
|
<div x-show="open" @click.away="open = false"
|
||
|
|
class="absolute right-0 mt-2 w-48 bg-syndicate-800 border border-syndicate-700 rounded-lg shadow-xl z-50">
|
||
|
|
<a href="{{ route('profile.edit') }}" class="block px-4 py-2 text-sm text-gray-300 hover:bg-syndicate-700 hover:text-gray-100 rounded-t-lg transition">
|
||
|
|
Settings
|
||
|
|
</a>
|
||
|
|
<form method="POST" action="{{ route('logout') }}">
|
||
|
|
@csrf
|
||
|
|
<button type="submit" class="w-full text-left px-4 py-2 text-sm text-gray-300 hover:bg-syndicate-700 hover:text-gray-100 rounded-b-lg transition">
|
||
|
|
Log Out
|
||
|
|
</button>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</header>
|
||
|
|
|
||
|
|
{{-- BODY: sidebar + content --}}
|
||
|
|
<div class="flex flex-1">
|
||
|
|
|
||
|
|
{{-- SIDEBAR --}}
|
||
|
|
@include('layouts.navigation')
|
||
|
|
|
||
|
|
{{-- CONTENT --}}
|
||
|
|
<main class="flex-1 bg-syndicate-950 p-6 overflow-auto">
|
||
|
|
|
||
|
|
{{-- Flash messages --}}
|
||
|
|
@if(session('success'))
|
||
|
|
<div class="mb-4 px-4 py-3 bg-green-900/40 border border-green-700 text-green-400 rounded-lg text-sm">
|
||
|
|
{{ session('success') }}
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
@if(session('error'))
|
||
|
|
<div class="mb-4 px-4 py-3 bg-red-900/40 border border-red-800 text-red-400 rounded-lg text-sm">
|
||
|
|
{{ session('error') }}
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
|
||
|
|
@yield('game-content')
|
||
|
|
</main>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{{-- FOOTER --}}
|
||
|
|
<footer class="bg-syndicate-900 border-t border-syndicate-700 py-3 text-center text-xs text-gray-600">
|
||
|
|
© {{ date('Y') }} {{ config('game.name', 'The Crime Syndicate') }} — v{{ config('game.version', '1.0.0') }}
|
||
|
|
</footer>
|
||
|
|
|
||
|
|
</div>
|
||
|
|
@endsection
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 2: Rewrite navigation.blade.php as sidebar**
|
||
|
|
|
||
|
|
Replace `resources/views/layouts/navigation.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
<aside class="bg-syndicate-900 border-r border-syndicate-700 w-56 flex-shrink-0 flex flex-col">
|
||
|
|
<nav class="flex-1 py-4">
|
||
|
|
<ul class="space-y-1 px-2">
|
||
|
|
<li>
|
||
|
|
<a href="{{ route('game.dashboard') }}"
|
||
|
|
class="flex items-center space-x-3 px-3 py-2 rounded-lg text-sm transition
|
||
|
|
{{ request()->routeIs('game.dashboard') ? 'border-l-2 border-crime-500 bg-syndicate-800 text-gray-100 pl-[10px]' : 'text-gray-400 hover:bg-syndicate-800 hover:text-gray-100' }}">
|
||
|
|
<span class="text-base">🏠</span>
|
||
|
|
<span>Dashboard</span>
|
||
|
|
</a>
|
||
|
|
</li>
|
||
|
|
<li>
|
||
|
|
<a href="{{ route('game.crimes.index') }}"
|
||
|
|
class="flex items-center space-x-3 px-3 py-2 rounded-lg text-sm transition
|
||
|
|
{{ request()->routeIs('game.crimes.*') ? 'border-l-2 border-crime-500 bg-syndicate-800 text-gray-100 pl-[10px]' : 'text-gray-400 hover:bg-syndicate-800 hover:text-gray-100' }}">
|
||
|
|
<span class="text-base">🎯</span>
|
||
|
|
<span>Crimes</span>
|
||
|
|
</a>
|
||
|
|
</li>
|
||
|
|
<li>
|
||
|
|
<a href="{{ route('game.inventory.index') }}"
|
||
|
|
class="flex items-center space-x-3 px-3 py-2 rounded-lg text-sm transition
|
||
|
|
{{ request()->routeIs('game.inventory.*') ? 'border-l-2 border-crime-500 bg-syndicate-800 text-gray-100 pl-[10px]' : 'text-gray-400 hover:bg-syndicate-800 hover:text-gray-100' }}">
|
||
|
|
<span class="text-base">🎒</span>
|
||
|
|
<span>Inventory</span>
|
||
|
|
</a>
|
||
|
|
</li>
|
||
|
|
<li>
|
||
|
|
<a href="{{ route('game.character.show') }}"
|
||
|
|
class="flex items-center space-x-3 px-3 py-2 rounded-lg text-sm transition
|
||
|
|
{{ request()->routeIs('game.character.show') ? 'border-l-2 border-crime-500 bg-syndicate-800 text-gray-100 pl-[10px]' : 'text-gray-400 hover:bg-syndicate-800 hover:text-gray-100' }}">
|
||
|
|
<span class="text-base">👤</span>
|
||
|
|
<span>Profile</span>
|
||
|
|
</a>
|
||
|
|
</li>
|
||
|
|
|
||
|
|
@if(auth()->check() && auth()->user()->character)
|
||
|
|
@php $charStatus = auth()->user()->character->status; @endphp
|
||
|
|
|
||
|
|
@if($charStatus === \App\Enums\CharacterStatus::IN_HOSPITAL)
|
||
|
|
<li class="pt-2 border-t border-syndicate-700 mt-2">
|
||
|
|
<a href="{{ route('game.hospital') }}"
|
||
|
|
class="flex items-center space-x-3 px-3 py-2 rounded-lg text-sm transition border-l-2 border-red-500 bg-syndicate-800 text-red-400 pl-[10px]">
|
||
|
|
<span class="text-base">🏥</span>
|
||
|
|
<span>Hospital</span>
|
||
|
|
</a>
|
||
|
|
</li>
|
||
|
|
@endif
|
||
|
|
|
||
|
|
@if($charStatus === \App\Enums\CharacterStatus::IN_JAIL)
|
||
|
|
<li class="pt-2 border-t border-syndicate-700 mt-2">
|
||
|
|
<a href="{{ route('game.jail') }}"
|
||
|
|
class="flex items-center space-x-3 px-3 py-2 rounded-lg text-sm transition border-l-2 border-yellow-500 bg-syndicate-800 text-yellow-400 pl-[10px]">
|
||
|
|
<span class="text-base">🚔</span>
|
||
|
|
<span>Jail</span>
|
||
|
|
</a>
|
||
|
|
</li>
|
||
|
|
@endif
|
||
|
|
@endif
|
||
|
|
</ul>
|
||
|
|
</nav>
|
||
|
|
</aside>
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 3: Rewrite stats-bar.blade.php as compact pills**
|
||
|
|
|
||
|
|
Replace `resources/views/game/partials/stats-bar.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
@php $character = auth()->user()->character; @endphp
|
||
|
|
<div class="flex items-center space-x-3 text-sm">
|
||
|
|
{{-- HP --}}
|
||
|
|
<div class="flex items-center space-x-1 bg-syndicate-800 border border-syndicate-700 rounded px-2 py-1">
|
||
|
|
<span class="text-red-400">❤</span>
|
||
|
|
<span class="text-gray-300">{{ $character->health }}<span class="text-gray-600">/{{ $character->max_health }}</span></span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{{-- Energy --}}
|
||
|
|
<div class="flex items-center space-x-1 bg-syndicate-800 border border-syndicate-700 rounded px-2 py-1">
|
||
|
|
<span class="text-yellow-400">⚡</span>
|
||
|
|
<span class="text-gray-300">{{ $character->energy }}<span class="text-gray-600">/{{ $character->max_energy }}</span></span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{{-- Cash --}}
|
||
|
|
<div class="flex items-center space-x-1 bg-syndicate-800 border border-syndicate-700 rounded px-2 py-1">
|
||
|
|
<span class="text-gold-400">$</span>
|
||
|
|
<span class="text-gray-300">{{ number_format($character->money) }}</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{{-- Level --}}
|
||
|
|
<div class="bg-syndicate-700 text-gray-300 rounded px-2 py-1 text-xs font-medium">
|
||
|
|
Lv.{{ $character->level }}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{{-- Non-active status badge --}}
|
||
|
|
@if($character->status !== \App\Enums\CharacterStatus::ACTIVE)
|
||
|
|
<span class="px-2 py-1 text-xs rounded {{ $character->status->color() }}">
|
||
|
|
{{ $character->status->label() }}
|
||
|
|
</span>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 4: Build assets**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /home/liquidsky/Projects/thecrimesyndicate && npm run build 2>&1 | tail -20
|
||
|
|
```
|
||
|
|
|
||
|
|
Expected: build succeeds with no errors.
|
||
|
|
|
||
|
|
- [ ] **Step 5: Commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /home/liquidsky/Projects/thecrimesyndicate
|
||
|
|
git add resources/views/layouts/game.blade.php resources/views/layouts/navigation.blade.php resources/views/game/partials/stats-bar.blade.php
|
||
|
|
git commit -m "feat: sidebar + top bar game layout with dark crime theme"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 3: Restyle Blade components (buttons + form inputs)
|
||
|
|
|
||
|
|
**Files:**
|
||
|
|
- Modify: `resources/views/components/primary-button.blade.php`
|
||
|
|
- Modify: `resources/views/components/secondary-button.blade.php`
|
||
|
|
- Modify: `resources/views/components/text-input.blade.php`
|
||
|
|
- Modify: `resources/views/components/input-label.blade.php`
|
||
|
|
|
||
|
|
**Interfaces:**
|
||
|
|
- Consumes: color tokens from Task 1
|
||
|
|
- Produces: restyled `<x-primary-button>`, `<x-secondary-button>`, `<x-text-input>`, `<x-input-label>` used by auth pages and game pages
|
||
|
|
|
||
|
|
- [ ] **Step 1: Restyle primary-button**
|
||
|
|
|
||
|
|
Replace `resources/views/components/primary-button.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-crime-600 border border-transparent rounded-md font-semibold text-sm text-white uppercase tracking-widest hover:bg-crime-500 focus:outline-none focus:ring-2 focus:ring-crime-500 focus:ring-offset-2 focus:ring-offset-syndicate-800 transition ease-in-out duration-150']) }}>
|
||
|
|
{{ $slot }}
|
||
|
|
</button>
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 2: Restyle secondary-button**
|
||
|
|
|
||
|
|
Replace `resources/views/components/secondary-button.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
<button {{ $attributes->merge(['type' => 'button', 'class' => 'inline-flex items-center px-4 py-2 bg-syndicate-700 border border-syndicate-600 rounded-md font-semibold text-sm text-gray-300 uppercase tracking-widest hover:bg-syndicate-600 hover:text-gray-100 focus:outline-none focus:ring-2 focus:ring-syndicate-600 focus:ring-offset-2 focus:ring-offset-syndicate-800 disabled:opacity-25 transition ease-in-out duration-150']) }}>
|
||
|
|
{{ $slot }}
|
||
|
|
</button>
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 3: Restyle text-input**
|
||
|
|
|
||
|
|
Replace `resources/views/components/text-input.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
@props(['disabled' => false])
|
||
|
|
|
||
|
|
<input @disabled($disabled) {{ $attributes->merge(['class' => 'bg-syndicate-700 border-syndicate-600 text-gray-100 placeholder-gray-500 focus:border-crime-500 focus:ring-crime-500 rounded-md shadow-sm']) }}>
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 4: Restyle input-label**
|
||
|
|
|
||
|
|
Replace `resources/views/components/input-label.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
@props(['value'])
|
||
|
|
|
||
|
|
<label {{ $attributes->merge(['class' => 'block font-medium text-sm text-gray-300']) }}>
|
||
|
|
{{ $value ?? $slot }}
|
||
|
|
</label>
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 5: Build assets**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /home/liquidsky/Projects/thecrimesyndicate && npm run build 2>&1 | tail -20
|
||
|
|
```
|
||
|
|
|
||
|
|
Expected: build succeeds with no errors.
|
||
|
|
|
||
|
|
- [ ] **Step 6: Commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /home/liquidsky/Projects/thecrimesyndicate
|
||
|
|
git add resources/views/components/primary-button.blade.php resources/views/components/secondary-button.blade.php resources/views/components/text-input.blade.php resources/views/components/input-label.blade.php
|
||
|
|
git commit -m "feat: restyle form components for dark crime theme"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 4: Restyle game dashboard
|
||
|
|
|
||
|
|
**Files:**
|
||
|
|
- Modify: `resources/views/game/dashboard.blade.php`
|
||
|
|
|
||
|
|
**Interfaces:**
|
||
|
|
- Consumes: color tokens from Task 1, game layout from Task 2
|
||
|
|
- Consumes: `$character`, `$recentActivity` variables (passed by `GameController`)
|
||
|
|
|
||
|
|
- [ ] **Step 1: Replace dashboard.blade.php**
|
||
|
|
|
||
|
|
Replace `resources/views/game/dashboard.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
@extends('layouts.game')
|
||
|
|
|
||
|
|
@section('title', 'Dashboard')
|
||
|
|
|
||
|
|
@section('game-content')
|
||
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||
|
|
|
||
|
|
{{-- Welcome Card --}}
|
||
|
|
<div class="bg-syndicate-800 border border-syndicate-700 rounded-lg p-6">
|
||
|
|
<h2 class="font-display text-xl font-semibold text-gray-100 mb-4">
|
||
|
|
Welcome, {{ $character->name }}!
|
||
|
|
</h2>
|
||
|
|
<p class="text-gray-400 text-sm">
|
||
|
|
You are in <strong class="text-gray-200">{{ $character->location->name ?? 'Unknown Location' }}</strong>.
|
||
|
|
</p>
|
||
|
|
<p class="text-gray-400 text-sm mt-2">
|
||
|
|
Level {{ $character->level }} — {{ number_format($character->experience) }} / {{ number_format($character->experience_for_next_level) }} EXP
|
||
|
|
</p>
|
||
|
|
<div class="w-full bg-syndicate-700 rounded-full h-1.5 mt-3">
|
||
|
|
<div class="bg-crime-600 h-1.5 rounded-full" style="width: {{ $character->experience_progress }}%"></div>
|
||
|
|
</div>
|
||
|
|
<p class="text-xs text-gray-600 mt-1">{{ number_format($character->experience_progress, 1) }}% to next level</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{{-- Quick Stats --}}
|
||
|
|
<div class="bg-syndicate-800 border border-syndicate-700 rounded-lg p-6">
|
||
|
|
<h3 class="font-display text-lg font-semibold text-gray-100 mb-4">Quick Stats</h3>
|
||
|
|
<div class="space-y-2 text-sm">
|
||
|
|
<div class="flex justify-between">
|
||
|
|
<span class="text-gray-400">Strength</span>
|
||
|
|
<span class="text-gray-200 font-medium">{{ $character->strength }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="flex justify-between">
|
||
|
|
<span class="text-gray-400">Defense</span>
|
||
|
|
<span class="text-gray-200 font-medium">{{ $character->defense }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="flex justify-between">
|
||
|
|
<span class="text-gray-400">Speed</span>
|
||
|
|
<span class="text-gray-200 font-medium">{{ $character->speed }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="flex justify-between">
|
||
|
|
<span class="text-gray-400">Dexterity</span>
|
||
|
|
<span class="text-gray-200 font-medium">{{ $character->dexterity }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="flex justify-between pt-2 border-t border-syndicate-700">
|
||
|
|
<span class="text-gray-400">Attack Power</span>
|
||
|
|
<span class="text-crime-400 font-medium">{{ $character->attack_power }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="flex justify-between">
|
||
|
|
<span class="text-gray-400">Total Defense</span>
|
||
|
|
<span class="text-blue-400 font-medium">{{ $character->defense }}</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{{-- Finances --}}
|
||
|
|
<div class="bg-syndicate-800 border border-syndicate-700 rounded-lg p-6">
|
||
|
|
<h3 class="font-display text-lg font-semibold text-gray-100 mb-4">Finances</h3>
|
||
|
|
<div class="space-y-3 text-sm">
|
||
|
|
<div class="flex items-center justify-between">
|
||
|
|
<div class="flex items-center space-x-2">
|
||
|
|
<span class="text-gold-400">💰</span>
|
||
|
|
<span class="text-gray-400">Cash</span>
|
||
|
|
</div>
|
||
|
|
<span class="text-gold-400 font-medium">${{ number_format($character->money) }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="flex items-center justify-between">
|
||
|
|
<div class="flex items-center space-x-2">
|
||
|
|
<span class="text-blue-400">🏦</span>
|
||
|
|
<span class="text-gray-400">Bank</span>
|
||
|
|
</div>
|
||
|
|
<span class="text-gray-200 font-medium">${{ number_format($character->bank) }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="pt-2 border-t border-syndicate-700 space-y-2">
|
||
|
|
<a href="#" onclick="event.preventDefault(); document.getElementById('deposit-form').submit();"
|
||
|
|
class="block w-full text-center bg-crime-600 hover:bg-crime-500 text-white py-2 px-4 rounded text-sm transition">
|
||
|
|
Deposit to Bank
|
||
|
|
</a>
|
||
|
|
<form id="deposit-form" action="{{ route('game.character.deposit') }}" method="POST" class="hidden">
|
||
|
|
@csrf
|
||
|
|
<input type="number" name="amount" value="1000" min="1" max="{{ $character->money }}">
|
||
|
|
</form>
|
||
|
|
|
||
|
|
<a href="#" onclick="event.preventDefault(); document.getElementById('withdraw-form').submit();"
|
||
|
|
class="block w-full text-center bg-syndicate-700 hover:bg-syndicate-600 text-gray-300 py-2 px-4 rounded text-sm transition">
|
||
|
|
Withdraw from Bank
|
||
|
|
</a>
|
||
|
|
<form id="withdraw-form" action="{{ route('game.character.withdraw') }}" method="POST" class="hidden">
|
||
|
|
@csrf
|
||
|
|
<input type="number" name="amount" value="1000" min="1" max="{{ $character->bank }}">
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{{-- Quick Actions --}}
|
||
|
|
<div class="bg-syndicate-800 border border-syndicate-700 rounded-lg p-6 lg:col-span-2">
|
||
|
|
<h3 class="font-display text-lg font-semibold text-gray-100 mb-4">Quick Actions</h3>
|
||
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||
|
|
<a href="{{ route('game.crimes.index') }}"
|
||
|
|
class="flex flex-col items-center justify-center bg-syndicate-700 border border-syndicate-600 hover:border-crime-600 text-gray-300 hover:text-gray-100 py-4 px-2 rounded-lg transition">
|
||
|
|
<span class="text-2xl mb-1">🎯</span>
|
||
|
|
<span class="text-sm font-medium">Crimes</span>
|
||
|
|
<span class="text-xs text-gray-500">Commit crimes</span>
|
||
|
|
</a>
|
||
|
|
<a href="{{ route('game.inventory.index') }}"
|
||
|
|
class="flex flex-col items-center justify-center bg-syndicate-700 border border-syndicate-600 hover:border-crime-600 text-gray-300 hover:text-gray-100 py-4 px-2 rounded-lg transition">
|
||
|
|
<span class="text-2xl mb-1">🎒</span>
|
||
|
|
<span class="text-sm font-medium">Inventory</span>
|
||
|
|
<span class="text-xs text-gray-500">Manage items</span>
|
||
|
|
</a>
|
||
|
|
<a href="{{ route('game.character.show') }}"
|
||
|
|
class="flex flex-col items-center justify-center bg-syndicate-700 border border-syndicate-600 hover:border-crime-600 text-gray-300 hover:text-gray-100 py-4 px-2 rounded-lg transition">
|
||
|
|
<span class="text-2xl mb-1">👤</span>
|
||
|
|
<span class="text-sm font-medium">Profile</span>
|
||
|
|
<span class="text-xs text-gray-500">View profile</span>
|
||
|
|
</a>
|
||
|
|
<a href="{{ route('profile.edit') }}"
|
||
|
|
class="flex flex-col items-center justify-center bg-syndicate-700 border border-syndicate-600 hover:border-crime-600 text-gray-300 hover:text-gray-100 py-4 px-2 rounded-lg transition">
|
||
|
|
<span class="text-2xl mb-1">⚙️</span>
|
||
|
|
<span class="text-sm font-medium">Settings</span>
|
||
|
|
<span class="text-xs text-gray-500">Account settings</span>
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{{-- Recent Activity --}}
|
||
|
|
<div class="bg-syndicate-800 border border-syndicate-700 rounded-lg p-6 lg:col-span-3">
|
||
|
|
<h3 class="font-display text-lg font-semibold text-gray-100 mb-4">Recent Activity</h3>
|
||
|
|
|
||
|
|
@if($recentActivity->isEmpty())
|
||
|
|
<p class="text-gray-500 text-center py-4 text-sm">No recent activity.</p>
|
||
|
|
@else
|
||
|
|
<div class="space-y-2">
|
||
|
|
@foreach($recentActivity as $activity)
|
||
|
|
<div class="flex items-start space-x-3 p-3 bg-syndicate-700 rounded-lg">
|
||
|
|
<span class="text-gray-500 text-base">
|
||
|
|
@switch($activity->action)
|
||
|
|
@case('crime_attempt')
|
||
|
|
@if(str_contains($activity->description, 'success')) ✅ @else ❌ @endif
|
||
|
|
@break
|
||
|
|
@case('money_earned') 💰 @break
|
||
|
|
@case('money_spent') 💸 @break
|
||
|
|
@case('character_created') 🎉 @break
|
||
|
|
@default 📝
|
||
|
|
@endswitch
|
||
|
|
</span>
|
||
|
|
<div class="flex-1">
|
||
|
|
<p class="text-sm font-medium text-gray-200">
|
||
|
|
{{ ucfirst(str_replace('_', ' ', $activity->action)) }}
|
||
|
|
</p>
|
||
|
|
<p class="text-xs text-gray-500">{{ $activity->description }}</p>
|
||
|
|
<p class="text-xs text-gray-600 mt-1">{{ $activity->created_at->diffForHumans() }}</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
@endforeach
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
|
||
|
|
</div>
|
||
|
|
@endsection
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 2: Build assets**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /home/liquidsky/Projects/thecrimesyndicate && npm run build 2>&1 | tail -20
|
||
|
|
```
|
||
|
|
|
||
|
|
Expected: build succeeds.
|
||
|
|
|
||
|
|
- [ ] **Step 3: Commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /home/liquidsky/Projects/thecrimesyndicate
|
||
|
|
git add resources/views/game/dashboard.blade.php
|
||
|
|
git commit -m "feat: restyle game dashboard with dark crime theme"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 5: Restyle crimes page
|
||
|
|
|
||
|
|
**Files:**
|
||
|
|
- Modify: `resources/views/game/crimes/index.blade.php`
|
||
|
|
|
||
|
|
**Interfaces:**
|
||
|
|
- Consumes: color tokens from Task 1, game layout from Task 2
|
||
|
|
- Consumes: `$character`, `$availableCrimes`, `$recentAttempts`, `$crimeService` (passed by `CrimeController`)
|
||
|
|
|
||
|
|
- [ ] **Step 1: Replace crimes/index.blade.php**
|
||
|
|
|
||
|
|
Replace `resources/views/game/crimes/index.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
@extends('layouts.game')
|
||
|
|
|
||
|
|
@section('title', 'Crimes')
|
||
|
|
|
||
|
|
@section('game-content')
|
||
|
|
<div class="max-w-4xl mx-auto space-y-6">
|
||
|
|
|
||
|
|
{{-- Header card --}}
|
||
|
|
<div class="bg-syndicate-800 border border-syndicate-700 rounded-lg">
|
||
|
|
<div class="px-6 py-4 border-b border-syndicate-700 flex justify-between items-center">
|
||
|
|
<h1 class="font-display text-xl font-semibold text-gray-100">Available Crimes</h1>
|
||
|
|
<div class="text-sm text-gray-400">
|
||
|
|
Energy: <span class="text-yellow-400 font-medium">{{ $character->energy }}/{{ $character->max_energy }}</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="p-6">
|
||
|
|
@if($availableCrimes->isEmpty())
|
||
|
|
<p class="text-center text-gray-500 py-8 text-sm">No crimes available. Try leveling up or restoring your energy.</p>
|
||
|
|
@else
|
||
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
|
|
@foreach($availableCrimes as $crime)
|
||
|
|
@php
|
||
|
|
$onCooldown = $crimeService->isOnCooldown($character, $crime);
|
||
|
|
$cooldownRemaining = $onCooldown ? $crimeService->getCooldownRemaining($character, $crime) : 0;
|
||
|
|
$successRate = $crime->calculateSuccessRate($character);
|
||
|
|
@endphp
|
||
|
|
|
||
|
|
<div class="bg-syndicate-700 border border-syndicate-600 hover:border-crime-600 rounded-lg p-4 transition">
|
||
|
|
<div class="flex justify-between items-start mb-2">
|
||
|
|
<div>
|
||
|
|
<h3 class="font-medium text-gray-100">{{ $crime->name }}</h3>
|
||
|
|
<p class="text-xs text-gray-500 mt-1">{{ $crime->difficulty_label }} Difficulty</p>
|
||
|
|
</div>
|
||
|
|
<span class="text-xs px-2 py-1 rounded-full {{ $crime->difficulty_color }} text-white flex-shrink-0">
|
||
|
|
{{ number_format($successRate * 100, 1) }}% Success
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<p class="text-sm text-gray-400 mb-3">{{ Str::limit($crime->description, 100) }}</p>
|
||
|
|
|
||
|
|
<div class="grid grid-cols-2 gap-2 text-xs text-gray-400 mb-3">
|
||
|
|
<div class="flex items-center space-x-1">
|
||
|
|
<span class="text-yellow-400">⚡</span>
|
||
|
|
<span>{{ $crime->energy_cost }} Energy</span>
|
||
|
|
</div>
|
||
|
|
<div class="flex items-center space-x-1">
|
||
|
|
<span class="text-gold-400">💰</span>
|
||
|
|
<span>${{ $crime->reward_min }}-{{ $crime->reward_max }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="flex items-center space-x-1">
|
||
|
|
<span class="text-blue-400">📈</span>
|
||
|
|
<span>{{ $crime->experience }} EXP</span>
|
||
|
|
</div>
|
||
|
|
<div class="flex items-center space-x-1">
|
||
|
|
<span class="text-gray-500">⏱</span>
|
||
|
|
<span>{{ $crime->cooldown }}s Cooldown</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
@if($onCooldown)
|
||
|
|
<button disabled
|
||
|
|
class="w-full py-2 px-4 text-sm text-center bg-syndicate-600 text-gray-600 rounded-lg cursor-not-allowed">
|
||
|
|
On Cooldown ({{ ceil($cooldownRemaining / 60) }}m)
|
||
|
|
</button>
|
||
|
|
@else
|
||
|
|
<form action="{{ route('game.crimes.attempt', $crime) }}" method="POST">
|
||
|
|
@csrf
|
||
|
|
<button type="submit"
|
||
|
|
class="w-full py-2 px-4 text-sm text-center bg-crime-600 hover:bg-crime-500 text-white rounded-lg transition">
|
||
|
|
Attempt Crime
|
||
|
|
</button>
|
||
|
|
</form>
|
||
|
|
@endif
|
||
|
|
|
||
|
|
@if($crime->requires_level)
|
||
|
|
<p class="text-xs text-gray-600 mt-2">Requires Level {{ $crime->requires_level }}+</p>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
@endforeach
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{{-- Recent Attempts --}}
|
||
|
|
<div class="bg-syndicate-800 border border-syndicate-700 rounded-lg">
|
||
|
|
<div class="px-6 py-4 border-b border-syndicate-700">
|
||
|
|
<h3 class="font-display text-lg font-semibold text-gray-100">Recent Attempts</h3>
|
||
|
|
</div>
|
||
|
|
<div class="p-6">
|
||
|
|
@if($recentAttempts->isEmpty())
|
||
|
|
<p class="text-center text-gray-500 py-4 text-sm">No recent crime attempts.</p>
|
||
|
|
@else
|
||
|
|
<div class="space-y-2">
|
||
|
|
@foreach($recentAttempts as $attempt)
|
||
|
|
<div class="flex items-center justify-between p-3 bg-syndicate-700 rounded-lg">
|
||
|
|
<div class="flex items-center space-x-3">
|
||
|
|
<span>
|
||
|
|
@if($attempt->success)
|
||
|
|
<span class="text-green-400">✅</span>
|
||
|
|
@else
|
||
|
|
<span class="text-red-400">❌</span>
|
||
|
|
@endif
|
||
|
|
</span>
|
||
|
|
<div>
|
||
|
|
<p class="font-medium text-gray-200 text-sm">{{ $attempt->crime->name }}</p>
|
||
|
|
<p class="text-xs text-gray-500">{{ $attempt->attempted_at->diffForHumans() }}</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="text-right">
|
||
|
|
@if($attempt->success)
|
||
|
|
<p class="text-sm text-gold-400">+${{ number_format($attempt->reward) }}</p>
|
||
|
|
<p class="text-xs text-gray-500">+{{ $attempt->experience_gained }} EXP</p>
|
||
|
|
@else
|
||
|
|
<p class="text-sm text-red-400">Failed</p>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
@endforeach
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
</div>
|
||
|
|
@endsection
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 2: Build and commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /home/liquidsky/Projects/thecrimesyndicate && npm run build 2>&1 | tail -5
|
||
|
|
git add resources/views/game/crimes/index.blade.php
|
||
|
|
git commit -m "feat: restyle crimes page with dark crime theme"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 6: Restyle inventory, hospital, and jail pages
|
||
|
|
|
||
|
|
**Files:**
|
||
|
|
- Modify: `resources/views/game/inventory/index.blade.php`
|
||
|
|
- Modify: `resources/views/game/hospital.blade.php`
|
||
|
|
- Modify: `resources/views/game/jail.blade.php`
|
||
|
|
|
||
|
|
**Interfaces:**
|
||
|
|
- Consumes: color tokens from Task 1, game layout from Task 2
|
||
|
|
- Consumes: `$inventory` (inventory page), `$character` + `$releaseTime` + `$reviveCost` (hospital), `$character` + `$releaseTime` (jail)
|
||
|
|
|
||
|
|
- [ ] **Step 1: Replace inventory/index.blade.php**
|
||
|
|
|
||
|
|
Replace `resources/views/game/inventory/index.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
@extends('layouts.game')
|
||
|
|
|
||
|
|
@section('title', 'Inventory')
|
||
|
|
|
||
|
|
@section('game-content')
|
||
|
|
<div class="max-w-4xl mx-auto">
|
||
|
|
<div class="bg-syndicate-800 border border-syndicate-700 rounded-lg">
|
||
|
|
<div class="px-6 py-4 border-b border-syndicate-700">
|
||
|
|
<h1 class="font-display text-xl font-semibold text-gray-100">Inventory</h1>
|
||
|
|
<p class="mt-1 text-sm text-gray-400">Equip weapons and armor, or use consumables.</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="p-6">
|
||
|
|
@if($inventory->isEmpty())
|
||
|
|
<p class="text-center text-gray-500 py-8 text-sm">Your inventory is empty.</p>
|
||
|
|
@else
|
||
|
|
<div class="space-y-6">
|
||
|
|
@foreach($inventory->groupBy('item.type') as $type => $items)
|
||
|
|
<div>
|
||
|
|
<h3 class="font-display text-base font-semibold text-gray-300 capitalize mb-3">
|
||
|
|
{{ ucfirst($type) }}s ({{ $items->sum('quantity') }})
|
||
|
|
</h3>
|
||
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
|
|
@foreach($items as $item)
|
||
|
|
<div class="bg-syndicate-700 border border-syndicate-600 rounded-lg p-4">
|
||
|
|
<div class="flex justify-between items-start mb-2">
|
||
|
|
<div>
|
||
|
|
<h4 class="font-medium text-gray-100">{{ $item->item->name }}</h4>
|
||
|
|
<p class="text-xs text-gray-500">x{{ $item->quantity }}</p>
|
||
|
|
</div>
|
||
|
|
@if($item->equipped)
|
||
|
|
<span class="text-xs px-2 py-1 bg-green-800/60 border border-green-700 text-green-400 rounded-full">Equipped</span>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
|
||
|
|
@if($item->item->description)
|
||
|
|
<p class="text-sm text-gray-400 mb-3">{{ Str::limit($item->item->description, 80) }}</p>
|
||
|
|
@endif
|
||
|
|
|
||
|
|
<div class="grid grid-cols-2 gap-2 text-xs text-gray-400 mb-3">
|
||
|
|
@if($item->item->attack_bonus > 0)
|
||
|
|
<div class="flex items-center space-x-1">
|
||
|
|
<span class="text-crime-400">⚔️</span>
|
||
|
|
<span>+{{ $item->item->attack_bonus }} Attack</span>
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
@if($item->item->defense_bonus > 0)
|
||
|
|
<div class="flex items-center space-x-1">
|
||
|
|
<span class="text-blue-400">🛡️</span>
|
||
|
|
<span>+{{ $item->item->defense_bonus }} Defense</span>
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
@if($item->item->health_bonus > 0)
|
||
|
|
<div class="flex items-center space-x-1">
|
||
|
|
<span class="text-green-400">❤️</span>
|
||
|
|
<span>+{{ $item->item->health_bonus }} Health</span>
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
@if($item->item->energy_bonus > 0)
|
||
|
|
<div class="flex items-center space-x-1">
|
||
|
|
<span class="text-yellow-400">⚡</span>
|
||
|
|
<span>+{{ $item->item->energy_bonus }} Energy</span>
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="flex space-x-2">
|
||
|
|
@if($item->item->canEquip())
|
||
|
|
@if($item->equipped)
|
||
|
|
<form action="{{ route('game.inventory.unequip', $item) }}" method="POST">
|
||
|
|
@csrf
|
||
|
|
<button type="submit"
|
||
|
|
class="px-3 py-1 text-xs bg-syndicate-600 hover:bg-syndicate-500 text-gray-300 rounded transition">
|
||
|
|
Unequip
|
||
|
|
</button>
|
||
|
|
</form>
|
||
|
|
@else
|
||
|
|
<form action="{{ route('game.inventory.equip', $item) }}" method="POST">
|
||
|
|
@csrf
|
||
|
|
<button type="submit"
|
||
|
|
class="px-3 py-1 text-xs bg-crime-600 hover:bg-crime-500 text-white rounded transition">
|
||
|
|
Equip
|
||
|
|
</button>
|
||
|
|
</form>
|
||
|
|
@endif
|
||
|
|
@endif
|
||
|
|
|
||
|
|
@if($item->item->canUse())
|
||
|
|
<form action="{{ route('game.inventory.use', $item) }}" method="POST">
|
||
|
|
@csrf
|
||
|
|
<button type="submit"
|
||
|
|
class="px-3 py-1 text-xs bg-green-700 hover:bg-green-600 text-white rounded transition">
|
||
|
|
Use
|
||
|
|
</button>
|
||
|
|
</form>
|
||
|
|
@endif
|
||
|
|
|
||
|
|
<form action="{{ route('game.inventory.drop', $item) }}" method="POST">
|
||
|
|
@csrf
|
||
|
|
<input type="number" name="quantity" value="1" min="1" max="{{ $item->quantity }}" class="hidden">
|
||
|
|
<button type="submit"
|
||
|
|
class="px-3 py-1 text-xs bg-red-900/60 hover:bg-red-800/80 border border-red-800 text-red-400 rounded transition">
|
||
|
|
Drop
|
||
|
|
</button>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
@endforeach
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
@endforeach
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
@endsection
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 2: Replace hospital.blade.php**
|
||
|
|
|
||
|
|
Replace `resources/views/game/hospital.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
@extends('layouts.game')
|
||
|
|
|
||
|
|
@section('title', 'Hospital')
|
||
|
|
|
||
|
|
@section('game-content')
|
||
|
|
<div class="max-w-2xl mx-auto">
|
||
|
|
<div class="bg-syndicate-800 border border-syndicate-700 rounded-lg">
|
||
|
|
<div class="p-8 text-center">
|
||
|
|
<div class="mb-6">
|
||
|
|
<span class="text-6xl">🏥</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<h1 class="font-display text-2xl font-bold text-gray-100 mb-4">You're in the Hospital</h1>
|
||
|
|
<p class="text-gray-400 mb-6 text-sm">Your character has been injured and is currently recovering.</p>
|
||
|
|
|
||
|
|
<div class="bg-red-900/20 border border-red-800 rounded-lg p-6 mb-6 text-left">
|
||
|
|
<h3 class="font-display text-base font-semibold text-red-300 mb-3">Your Status</h3>
|
||
|
|
<div class="space-y-2 text-sm">
|
||
|
|
<div class="flex justify-between">
|
||
|
|
<span class="text-gray-400">Health</span>
|
||
|
|
<span class="text-gray-200 font-medium">{{ $character->health }}/{{ $character->max_health }}</span>
|
||
|
|
</div>
|
||
|
|
<div class="flex justify-between">
|
||
|
|
<span class="text-gray-400">Status</span>
|
||
|
|
<span class="text-red-400 font-medium">
|
||
|
|
@if($character->health <= 0) Dead @else In Hospital @endif
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div class="flex justify-between">
|
||
|
|
<span class="text-gray-400">Release Time</span>
|
||
|
|
<span class="text-gray-200 font-medium">{{ $releaseTime }}</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="space-y-4">
|
||
|
|
<form action="{{ route('game.character.revive') }}" method="POST">
|
||
|
|
@csrf
|
||
|
|
<button type="submit"
|
||
|
|
class="w-full flex items-center justify-center px-6 py-4 bg-green-700 hover:bg-green-600 text-white font-medium rounded-lg transition">
|
||
|
|
<span class="mr-2">💵</span>
|
||
|
|
Revive Now for ${{ number_format($reviveCost) }}
|
||
|
|
</button>
|
||
|
|
</form>
|
||
|
|
|
||
|
|
<p class="text-sm text-gray-600">Or wait to be automatically released when your health regenerates.</p>
|
||
|
|
|
||
|
|
<a href="{{ route('game.dashboard') }}"
|
||
|
|
class="inline-flex items-center text-gray-500 hover:text-gray-300 transition text-sm">
|
||
|
|
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||
|
|
</svg>
|
||
|
|
Back to Dashboard
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
@endsection
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 3: Replace jail.blade.php**
|
||
|
|
|
||
|
|
Replace `resources/views/game/jail.blade.php` with:
|
||
|
|
|
||
|
|
```blade
|
||
|
|
@extends('layouts.game')
|
||
|
|
|
||
|
|
@section('title', 'Jail')
|
||
|
|
|
||
|
|
@section('game-content')
|
||
|
|
<div class="max-w-2xl mx-auto">
|
||
|
|
<div class="bg-syndicate-800 border border-syndicate-700 rounded-lg">
|
||
|
|
<div class="p-8 text-center">
|
||
|
|
<div class="mb-6">
|
||
|
|
<span class="text-6xl">🚔</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<h1 class="font-display text-2xl font-bold text-gray-100 mb-4">You're in Jail</h1>
|
||
|
|
<p class="text-gray-400 mb-6 text-sm">Your character has been arrested and is currently serving time.</p>
|
||
|
|
|
||
|
|
<div class="bg-yellow-900/20 border border-yellow-800 rounded-lg p-6 mb-6 text-left">
|
||
|
|
<h3 class="font-display text-base font-semibold text-yellow-300 mb-3">Your Status</h3>
|
||
|
|
<div class="space-y-2 text-sm">
|
||
|
|
<div class="flex justify-between">
|
||
|
|
<span class="text-gray-400">Status</span>
|
||
|
|
<span class="text-yellow-400 font-medium">In Jail</span>
|
||
|
|
</div>
|
||
|
|
<div class="flex justify-between">
|
||
|
|
<span class="text-gray-400">Release Time</span>
|
||
|
|
<span class="text-gray-200 font-medium">{{ $releaseTime }}</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="space-y-4">
|
||
|
|
<p class="text-sm text-gray-600">You must wait for your sentence to complete.</p>
|
||
|
|
|
||
|
|
<a href="{{ route('game.dashboard') }}"
|
||
|
|
class="inline-flex items-center text-gray-500 hover:text-gray-300 transition text-sm">
|
||
|
|
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||
|
|
</svg>
|
||
|
|
Back to Dashboard
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
@endsection
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 4: Build assets**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /home/liquidsky/Projects/thecrimesyndicate && npm run build 2>&1 | tail -5
|
||
|
|
```
|
||
|
|
|
||
|
|
Expected: build succeeds.
|
||
|
|
|
||
|
|
- [ ] **Step 5: Commit**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /home/liquidsky/Projects/thecrimesyndicate
|
||
|
|
git add resources/views/game/inventory/index.blade.php resources/views/game/hospital.blade.php resources/views/game/jail.blade.php
|
||
|
|
git commit -m "feat: restyle inventory, hospital, and jail pages with dark crime theme"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Self-Review Checklist
|
||
|
|
|
||
|
|
**Spec coverage:**
|
||
|
|
- ✅ Color system (syndicate/crime/gold) — Task 1
|
||
|
|
- ✅ Typography (Inter + Rajdhani) — Task 1
|
||
|
|
- ✅ `app.blade.php` dark body — Task 1
|
||
|
|
- ✅ `guest.blade.php` dark auth layout — Task 1
|
||
|
|
- ✅ Game layout (sidebar + top bar) — Task 2
|
||
|
|
- ✅ Sidebar nav links with conditional Hospital/Jail — Task 2
|
||
|
|
- ✅ Stats bar compact pills (HP/Energy/Cash/Level) — Task 2
|
||
|
|
- ✅ Flash messages dark variant — Task 2 (inside game.blade.php)
|
||
|
|
- ✅ Primary/Secondary/Ghost buttons — Task 3
|
||
|
|
- ✅ Dark text-input and input-label — Task 3
|
||
|
|
- ✅ Dashboard restyled — Task 4
|
||
|
|
- ✅ Crimes page restyled — Task 5
|
||
|
|
- ✅ Inventory page restyled — Task 6
|
||
|
|
- ✅ Hospital page restyled — Task 6
|
||
|
|
- ✅ Jail page restyled — Task 6
|
||
|
|
|
||
|
|
**No placeholders found.**
|
||
|
|
|
||
|
|
**Type/name consistency:**
|
||
|
|
- `CharacterStatus::ACTIVE`, `CharacterStatus::IN_HOSPITAL`, `CharacterStatus::IN_JAIL` — consistent across Tasks 2 and 4
|
||
|
|
- `$character->status->color()` / `->label()` — consistent with the enum definition
|
||
|
|
- Color tokens identical across all tasks (no drift)
|