Initial Commit

This commit is contained in:
Mark Gregory
2026-09-12 20:21:11 +01:00
commit 35d3f344c8
62 changed files with 3215 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
@import "tailwindcss";
:root{--ink:#070a19;--panel:#0d1228;--purple:#7c3aed;--pink:#ec4899;--cyan:#22d3ee;--gold:#fbbf24}*{box-sizing:border-box}body{margin:0;background:#070a19;color:#f8fafc;font-family:Inter,ui-sans-serif,system-ui,sans-serif}.shell{max-width:1280px;margin:auto;padding:0 24px}.nav{height:76px;display:flex;align-items:center;justify-content:space-between}.brand{font-size:25px;font-weight:900;color:white;text-decoration:none}.brand b{color:#ec4899}.navlinks{display:flex;gap:28px}.navlinks a{color:#dbeafe;text-decoration:none;font-size:14px}.button{display:inline-flex;padding:13px 20px;border-radius:12px;background:linear-gradient(135deg,var(--purple),var(--pink));color:white;text-decoration:none;border:0;font-weight:800}.button.ghost{background:transparent;border:1px solid #334155}.hero{min-height:610px;background:linear-gradient(90deg,rgba(7,10,25,.97) 0%,rgba(7,10,25,.72) 50%,rgba(7,10,25,.25)),url('https://images.unsplash.com/photo-1571266028243-d220c9c3b2d2?auto=format&fit=crop&w=2000&q=85') center/cover;border-bottom:1px solid #202743}.hero-copy{padding:105px 0 35px;max-width:760px}.eyebrow{color:#67e8f9;font-weight:800;letter-spacing:.18em;text-transform:uppercase}.hero h1{font-size:72px;line-height:.95;margin:14px 0 22px;letter-spacing:-.05em}.hero h1 span{background:linear-gradient(90deg,#c084fc,#f472b6,#22d3ee);background-clip:text;color:transparent}.hero p{font-size:19px;color:#cbd5e1;max-width:620px}.searchbox{margin-top:34px;padding:10px;background:white;border-radius:18px;display:grid;grid-template-columns:1.2fr 1fr 1fr auto;gap:8px;box-shadow:0 25px 80px #0008}.searchbox input,.searchbox select{border:0;padding:17px;color:#0f172a;background:#f8fafc;border-radius:10px;outline:none}.section{padding:72px 0}.section-head{display:flex;justify-content:space-between;align-items:end;margin-bottom:25px}.section h2{font-size:34px;margin:0}.muted{color:#94a3b8}.cards{display:grid;grid-template-columns:repeat(4,1fr);gap:18px}.card{background:#10162d;border:1px solid #27304d;border-radius:18px;overflow:hidden;box-shadow:0 14px 35px #0004}.card-img{height:235px;background:center/cover}.card-body{padding:18px}.card h3{margin:0 0 8px;font-size:20px}.stars{color:var(--gold)}.price{font-size:20px;font-weight:900;margin:14px 0}.chips{display:flex;gap:7px;flex-wrap:wrap}.chip{font-size:12px;padding:6px 9px;background:#1e293b;border-radius:99px;color:#cbd5e1}.profile-hero{height:350px;background:center/cover;position:relative}.profile-panel{margin:-90px auto 40px;position:relative;background:white;color:#0f172a;border-radius:22px;padding:30px;display:grid;grid-template-columns:130px 1fr 220px;gap:25px;box-shadow:0 30px 70px #0007}.avatar{width:130px;height:130px;border-radius:16px;object-fit:cover}.admin{display:grid;grid-template-columns:240px 1fr;min-height:100vh;background:#f8fafc;color:#0f172a}.sidebar{background:#0b1022;color:white;padding:28px 18px}.sidebar a{display:block;color:#cbd5e1;text-decoration:none;padding:11px;border-radius:8px}.sidebar a:hover{background:#1e293b}.admin-main{padding:35px}.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:18px}.stat{background:white;padding:24px;border-radius:14px;box-shadow:0 3px 15px #0f172a0d}.stat strong{display:block;font-size:30px;color:#7c3aed}.cookie{position:fixed;bottom:18px;left:18px;right:18px;max-width:650px;background:#fff;color:#0f172a;border-radius:16px;padding:18px;box-shadow:0 20px 60px #0008;z-index:50}@media(max-width:900px){.navlinks{display:none}.hero h1{font-size:50px}.searchbox{grid-template-columns:1fr}.cards{grid-template-columns:1fr 1fr}.profile-panel{grid-template-columns:1fr;margin:-40px 16px 30px}.admin{grid-template-columns:1fr}.sidebar{display:none}.stats{grid-template-columns:1fr 1fr}}@media(max-width:600px){.cards,.stats{grid-template-columns:1fr}.hero h1{font-size:42px}.hero-copy{padding-top:70px}}
+1
View File
@@ -0,0 +1 @@
import './bootstrap';
+1
View File
@@ -0,0 +1 @@
import axios from 'axios'; window.axios=axios; window.axios.defaults.headers.common['X-Requested-With']='XMLHttpRequest';
@@ -0,0 +1 @@
<!doctype html><html><head><meta name="viewport" content="width=device-width">@vite(['resources/css/app.css'])<title>BeatBook Admin</title></head><body><div class="admin"><aside class="sidebar"><div class="brand"><b>◉</b> BeatBook</div><p class="muted">Administration</p>@foreach(['Dashboard','Users','DJs & Businesses','Clients','Bookings','Payments','Reviews','Messages','Notifications','Support','Reports','Content','Roles & Permissions','Privacy','Settings'] as $x)<a href="#">{{ $x }}</a>@endforeach</aside><main class="admin-main"><h1>Dashboard</h1><p style="color:#64748b">Marketplace overview and moderation queue.</p><div class="stats">@foreach($stats as $k=>$v)<div class="stat"><span>{{ ucfirst($k) }}</span><strong>{{ number_format($v) }}</strong></div>@endforeach</div><div class="stat" style="margin-top:22px;min-height:330px"><h2>Operations</h2><p style="color:#64748b">Revenue charts, recent bookings, verification requests, support tickets and review moderation plug into this dashboard.</p><div style="height:180px;background:linear-gradient(180deg,#ede9fe,#fff);border-radius:12px;margin-top:30px;display:flex;align-items:end;padding:25px;gap:10px">@foreach([25,42,36,61,55,78,70,92,86,110,120] as $h)<i style="display:block;width:7%;height:{{ $h }}px;background:#7c3aed;border-radius:5px"></i>@endforeach</div></div></main></div></body></html>
@@ -0,0 +1 @@
@extends('layouts.app') @section('content')<main class="section"><div class="shell"><div class="eyebrow">Your account</div><h1>Client dashboard</h1><div class="cards"><div class="card"><div class="card-body"><h3>Enquiries</h3><p class="muted">Track quotes and conversations.</p></div></div><div class="card"><div class="card-body"><h3>Bookings</h3><p class="muted">Confirmed events and payment status.</p></div></div><div class="card"><div class="card-body"><h3>Favourites</h3><p class="muted">Your saved DJs.</p></div></div><div class="card"><div class="card-body"><h3>Reviews</h3><p class="muted">Review completed bookings.</p></div></div></div></div></main>@endsection
+1
View File
@@ -0,0 +1 @@
<article class="card"><div class="card-img" style="background-image:url('{{ $dj->profile_photo ?: 'https://images.unsplash.com/photo-1571266028243-d220c9c3b2d2?auto=format&fit=crop&w=700&q=80' }}')"></div><div class="card-body"><h3>{{ $dj->stage_name }} @if($dj->verified_at) ✓ @endif</h3><div class="stars">★★★★★ <span class="muted">{{ number_format($dj->average_rating,1) }} ({{ $dj->review_count }})</span></div><p class="muted">{{ $dj->city }} · {{ $dj->headline }}</p><div class="price">From £{{ number_format($dj->price_from,0) }}</div><a class="button" href="{{ route('djs.show',$dj) }}">View profile</a></div></article>
+1
View File
@@ -0,0 +1 @@
@extends('layouts.app') @section('title','Find DJs — BeatBook') @section('content')<main class="section"><div class="shell"><div class="eyebrow">Discover</div><h1 style="font-size:48px">Find your DJ</h1><form class="searchbox" style="margin:25px 0 35px"><input name="location" value="{{ request('location') }}" placeholder="Town or city"><input name="max_price" type="number" value="{{ request('max_price') }}" placeholder="Maximum price"><select><option>Highest rated</option></select><button class="button">Filter</button></form><div class="cards">@foreach($djs as $dj) @include('djs._card') @endforeach</div><div style="margin-top:30px">{{ $djs->links() }}</div></div></main>@endsection
+1
View File
@@ -0,0 +1 @@
@extends('layouts.app') @section('title',$dj->stage_name.' — BeatBook') @section('content')<div class="profile-hero" style="background-image:linear-gradient(#0002,#0008),url('{{ $dj->cover_photo ?: $dj->profile_photo }}')"></div><main class="shell"><section class="profile-panel"><img class="avatar" src="{{ $dj->profile_photo }}" alt="{{ $dj->stage_name }}"><div><h1 style="margin:0">{{ $dj->stage_name }} @if($dj->verified_at)<span style="color:#2563eb">✓</span>@endif</h1><div class="stars">★★★★★ <span style="color:#64748b">{{ $dj->average_rating }} · {{ $dj->review_count }} reviews</span></div><p>{{ $dj->headline }}</p><div class="chips">@foreach($dj->genres as $genre)<span class="chip">{{ $genre->name }}</span>@endforeach</div></div><aside><span>From</span><div style="font-size:34px;font-weight:900">£{{ number_format($dj->price_from,0) }}</div><span>per event</span><br><br><a class="button" href="#enquire">Request a quote</a></aside></section><section class="section" style="padding-top:15px"><div style="display:grid;grid-template-columns:2fr 1fr;gap:35px"><div><h2>About {{ $dj->stage_name }}</h2><p class="muted" style="font-size:17px;line-height:1.8">{{ $dj->bio }}</p><h2>Reviews</h2>@foreach($dj->reviews as $review)<div class="card" style="padding:20px;margin-bottom:12px"><div class="stars">{{ str_repeat('★',$review->rating) }}</div><h3>{{ $review->title }}</h3><p>{{ $review->body }}</p></div>@endforeach</div><aside id="enquire" class="card" style="padding:22px;height:max-content"><h2>Check availability</h2>@auth<form method="post" action="{{ route('enquiries.store',$dj) }}">@csrf<input name="event_type" placeholder="Event type" required style="width:100%;padding:12px;margin:5px 0"><input name="event_date" type="date" required style="width:100%;padding:12px;margin:5px 0"><input name="venue" placeholder="Venue / town" required style="width:100%;padding:12px;margin:5px 0"><input name="budget" type="number" placeholder="Budget £" style="width:100%;padding:12px;margin:5px 0"><textarea name="message" required placeholder="Tell the DJ about your event" style="width:100%;min-height:130px;padding:12px;margin:5px 0"></textarea><button class="button">Send enquiry</button></form>@else<p class="muted">Sign in to send a secure enquiry.</p><a class="button" href="/login">Sign in</a>@endauth</aside></div></section></main>@endsection
+1
View File
@@ -0,0 +1 @@
@extends('layouts.app') @section('content')<section class="hero"><div class="shell hero-copy"><div class="eyebrow">Music creates memories</div><h1>Find your <span>perfect DJ</span></h1><p>Discover trusted DJs for weddings, parties, corporate events and clubs. Compare profiles, reviews and prices, then enquire with confidence.</p><form class="searchbox" action="{{ route('djs.index') }}"><input name="location" placeholder="Town or postcode"><select name="event_type"><option value="">Event type</option><option>Wedding</option><option>Party</option><option>Corporate</option><option>Club</option></select><input type="date" name="date"><button class="button">Search DJs</button></form></div></section><section class="section"><div class="shell"><div class="section-head"><div><div class="eyebrow">Top talent</div><h2>Featured DJs</h2></div><a class="button ghost" href="{{ route('djs.index') }}">View all DJs</a></div><div class="cards">@forelse($featured as $dj) @include('djs._card',['dj'=>$dj]) @empty @foreach([['DJ Luna','London',350,'photo-1516280440614-37939bbacd81'],['DJ Maverick','Manchester',400,'photo-1571266028243-d220c9c3b2d2'],['DJ Rhythm','Birmingham',300,'photo-1524368535928-5b5e00ddc76b'],['DJ Serenity','Leeds',320,'photo-1506157786151-b8491531f063']] as $d)<article class="card"><div class="card-img" style="background-image:url('https://images.unsplash.com/{{ $d[3] }}?auto=format&fit=crop&w=700&q=80')"></div><div class="card-body"><h3>{{ $d[0] }}</h3><div class="stars">★★★★★ <span class="muted">4.9</span></div><p class="muted">{{ $d[1] }} · Weddings · Parties</p><div class="price">From £{{ $d[2] }}</div><a class="button" href="{{ route('djs.index') }}">View profile</a></div></article>@endforeach @endforelse</div></div></section><section id="how" class="section" style="background:#0d1228"><div class="shell"><div class="eyebrow">Simple & secure</div><h2>From search to dance floor</h2><div class="cards" style="margin-top:30px">@foreach(['Search'=>'Find DJs by location, date, event and budget.','Compare'=>'Review portfolios, pricing and verified feedback.','Enquire'=>'Send your event details without exposing private contact data.','Book & review'=>'Confirm securely and review after the event.'] as $a=>$b)<div class="card"><div class="card-body"><h3>{{ $a }}</h3><p class="muted">{{ $b }}</p></div></div>@endforeach</div></div></section>@endsection
+1
View File
@@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="Find and book outstanding DJs for weddings, parties, clubs and corporate events."><title>@yield('title','BeatBook — Find Your Perfect DJ')</title>@vite(['resources/css/app.css','resources/js/app.js'])</head><body><header><div class="shell nav"><a class="brand" href="{{ route('home') }}"><b>◉</b> BeatBook</a><nav class="navlinks"><a href="{{ route('djs.index') }}">Find a DJ</a><a href="/#how">How it works</a><a href="/#for-djs">For DJs</a><a href="/#pricing">Pricing</a></nav><div style="display:flex;gap:9px">@auth<a class="button ghost" href="{{ route('dashboard') }}">Dashboard</a>@else<a class="button ghost" href="/login">Sign in</a><a class="button" href="/register">Join</a>@endauth</div></div></header>@if(session('success'))<div class="shell" style="padding:14px;background:#064e3b;border-radius:12px">{{ session('success') }}</div>@endif>@yield('content')<footer class="section" style="border-top:1px solid #1e293b"><div class="shell"><b class="brand">BeatBook</b><p class="muted">DJs for every moment. Secure enquiries, bookings and verified reviews.</p><p><a href="{{ route('privacy') }}" class="muted">Privacy</a> · <a href="{{ route('cookies') }}" class="muted">Cookies</a> · <a href="{{ route('terms') }}" class="muted">Terms</a></p></div></footer><div class="cookie" id="cookie"><strong>Your privacy matters</strong><p style="margin:6px 0 12px">We use necessary cookies to run BeatBook. Analytics and marketing remain off until you choose them.</p><button class="button" onclick="localStorage.setItem('cookieChoice','necessary');document.getElementById('cookie').remove()">Necessary only</button> <button class="button ghost" style="color:#0f172a" onclick="localStorage.setItem('cookieChoice','all');document.getElementById('cookie').remove()">Accept all</button></div><script>if(localStorage.getItem('cookieChoice'))document.getElementById('cookie')?.remove()</script></body></html>
+1
View File
@@ -0,0 +1 @@
@extends('layouts.app') @section('title','Cookie Policy') @section('content')<main class="section"><div class="shell" style="max-width:850px"><h1>Cookie Policy</h1><p class="muted" style="font-size:18px;line-height:1.8">Necessary cookies operate the service. Analytics and marketing cookies require consent. Consent choices must be persisted server-side for production auditing.</p></div></main>@endsection
+1
View File
@@ -0,0 +1 @@
@extends('layouts.app') @section('title','Privacy Policy') @section('content')<main class="section"><div class="shell" style="max-width:850px"><h1>Privacy Policy</h1><p class="muted" style="font-size:18px;line-height:1.8">BeatBook is designed for UK GDPR compliance, data minimisation, access/export and deletion workflows. Replace this launch placeholder with counsel-reviewed policy text before production.</p></div></main>@endsection
+1
View File
@@ -0,0 +1 @@
@extends('layouts.app') @section('title','Terms of Service') @section('content')<main class="section"><div class="shell" style="max-width:850px"><h1>Terms of Service</h1><p class="muted" style="font-size:18px;line-height:1.8">Marketplace, DJ, client, cancellation, payment, refund and acceptable-use terms must be finalised before production launch.</p></div></main>@endsection