summaryrefslogtreecommitdiff
path: root/resources/views/admin.blade.php
diff options
context:
space:
mode:
Diffstat (limited to 'resources/views/admin.blade.php')
-rw-r--r--resources/views/admin.blade.php268
1 files changed, 268 insertions, 0 deletions
diff --git a/resources/views/admin.blade.php b/resources/views/admin.blade.php
new file mode 100644
index 0000000..bf8db6f
--- /dev/null
+++ b/resources/views/admin.blade.php
@@ -0,0 +1,268 @@
+@extends('template')
+
+@section('head')
+@endsection
+
+@section('content')
+<h1>Admin</h1>
+
+@if(session('success'))
+ <div class="flash-success">{{ session('success') }}</div>
+@endif
+
+<div class="admin-layout">
+ <nav class="admin-sidebar">
+ <a href="#visitors" class="admin-nav active" data-section="visitors">Visitors</a>
+ <a href="#files" class="admin-nav" data-section="files">Files</a>
+ <a href="#links" class="admin-nav" data-section="links">Links</a>
+ </nav>
+
+ <div class="admin-content">
+ {{-- ==================== VISITORS ==================== --}}
+ <div id="section-visitors" class="admin-section active">
+ <h2>Visitor Logs</h2>
+
+ <div class="summary-row">
+ <div class="summary-stat">
+ <div class="num">{{ $visitorSummary['unique_ips'] }}</div>
+ <div class="lbl">Unique IPs</div>
+ </div>
+ <div class="summary-stat">
+ <div class="num">{{ number_format($visitorSummary['total_requests']) }}</div>
+ <div class="lbl">Total Requests</div>
+ </div>
+ <div class="summary-stat">
+ <div class="num">{{ number_format($visitorSummary['total_200']) }}</div>
+ <div class="lbl">200</div>
+ </div>
+ <div class="summary-stat">
+ <div class="num">{{ number_format($visitorSummary['total_404']) }}</div>
+ <div class="lbl">404</div>
+ </div>
+ <div class="summary-stat">
+ <div class="num">{{ number_format($visitorSummary['total_405']) }}</div>
+ <div class="lbl">405</div>
+ </div>
+ <div class="summary-stat">
+ <div class="num">{{ number_format($visitorSummary['total_500']) }}</div>
+ <div class="lbl">500</div>
+ </div>
+ </div>
+
+ <table class="admin-table">
+ <thead>
+ <tr>
+ <th>IP Address</th>
+ <th>Requests</th>
+ <th>200</th>
+ <th>404</th>
+ <th>405</th>
+ <th>500</th>
+ <th>First Seen</th>
+ <th>Last Seen</th>
+ </tr>
+ </thead>
+ <tbody>
+ @forelse($visitors as $v)
+ <tr>
+ <td>{{ $v->ip_address }}</td>
+ <td>{{ number_format($v->total_requests) }}</td>
+ <td>{{ $v->status_200_count }}</td>
+ <td>{{ $v->status_404_count }}</td>
+ <td>{{ $v->status_405_count }}</td>
+ <td>{{ $v->status_500_count }}</td>
+ <td>{{ $v->first_seen_at?->format('Y-m-d H:i') }}</td>
+ <td>{{ $v->last_seen_at?->diffForHumans() }}</td>
+ </tr>
+ @empty
+ <tr><td colspan="8" style="text-align:center;color:#999;">No visitor data yet</td></tr>
+ @endforelse
+ </tbody>
+ </table>
+ </div>
+
+ {{-- ==================== FILES ==================== --}}
+ <div id="section-files" class="admin-section">
+ <h2>Files</h2>
+
+ <div class="admin-form">
+ <h3>Upload Files</h3>
+ <form action="/f" method="POST" enctype="multipart/form-data">
+ @csrf
+ <input type="hidden" name="response_format" value="html">
+ <input type="hidden" name="_redirect" value="/admin#files">
+ <div class="form-row">
+ <div class="form-group">
+ <label for="f">Select files</label>
+ <input type="file" name="f[]" id="f" multiple>
+ </div>
+ <div class="form-group">
+ <label for="upload-tags">Tags (comma-separated)</label>
+ <input type="text" name="tags" id="upload-tags" placeholder="e.g. photo, doc">
+ </div>
+ <button type="submit" class="btn btn-primary">Upload</button>
+ </div>
+ </form>
+ </div>
+
+ <table class="admin-table">
+ <thead>
+ <tr>
+ <th>Filename</th>
+ <th>Path</th>
+ <th>Size</th>
+ <th>Uploaded</th>
+ <th>Actions</th>
+ </tr>
+ </thead>
+ <tbody>
+ @forelse($files as $file)
+ <tr>
+ <td>{{ $file->filename }}</td>
+ <td>{{ $file->path }}</td>
+ <td>{{ $file->size ? round($file->size / 1024, 1) . ' KB' : '—' }}</td>
+ <td>{{ $file->created_at?->format('Y-m-d') }}</td>
+ <td>
+ <form action="/f/{{ $file->id }}" method="POST" style="display:inline"
+ onsubmit="return confirm('Delete this file?')">
+ @csrf
+ @method('DELETE')
+ <input type="hidden" name="_redirect" value="/admin#files">
+ <button type="submit" class="btn btn-danger btn-sm">Delete</button>
+ </form>
+ </td>
+ </tr>
+ @empty
+ <tr><td colspan="5" style="text-align:center;color:#999;">No files</td></tr>
+ @endforelse
+ </tbody>
+ </table>
+ </div>
+
+ {{-- ==================== LINKS ==================== --}}
+ <div id="section-links" class="admin-section">
+ <h2>Links</h2>
+
+ <div class="admin-form">
+ <h3>Add Link</h3>
+ <form action="/l" method="POST">
+ @csrf
+ <input type="hidden" name="_redirect" value="/admin#links">
+ <div class="form-row">
+ <div class="form-group">
+ <label for="link-label">Label</label>
+ <input type="text" name="label" id="link-label" required>
+ </div>
+ <div class="form-group">
+ <label for="link-url">URL</label>
+ <input type="text" name="url" id="link-url" required>
+ </div>
+ <div class="form-group">
+ <label for="link-desc">Description</label>
+ <input type="text" name="description" id="link-desc">
+ </div>
+ <button type="submit" class="btn btn-primary">Add</button>
+ </div>
+ </form>
+ </div>
+
+ <table class="admin-table">
+ <thead>
+ <tr>
+ <th>Label</th>
+ <th>URL</th>
+ <th>Description</th>
+ <th>Actions</th>
+ </tr>
+ </thead>
+ <tbody>
+ @forelse($links as $link)
+ <tr id="link-row-{{ $link->id }}">
+ <td class="link-display">{{ $link->label }}</td>
+ <td class="link-display"><a href="{{ $link->url }}" target="_blank">{{ Str::limit($link->url, 50) }}</a></td>
+ <td class="link-display">{{ $link->description }}</td>
+ <td>
+ <button class="btn btn-primary btn-sm" onclick="editLink({{ $link->id }}, this)">Edit</button>
+ <form action="/l/{{ $link->id }}" method="POST" style="display:inline"
+ onsubmit="return confirm('Delete this link?')">
+ @csrf
+ @method('DELETE')
+ <input type="hidden" name="_redirect" value="/admin#links">
+ <button type="submit" class="btn btn-danger btn-sm">Delete</button>
+ </form>
+ </td>
+ </tr>
+ @empty
+ <tr><td colspan="4" style="text-align:center;color:#999;">No links</td></tr>
+ @endforelse
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
+@endsection
+
+@section('scripts')
+<script>
+// Tab navigation
+document.querySelectorAll('.admin-nav').forEach(link => {
+ link.addEventListener('click', function(e) {
+ e.preventDefault();
+ const section = this.dataset.section;
+
+ document.querySelectorAll('.admin-nav').forEach(n => n.classList.remove('active'));
+ document.querySelectorAll('.admin-section').forEach(s => s.classList.remove('active'));
+
+ this.classList.add('active');
+ document.getElementById('section-' + section).classList.add('active');
+
+ history.replaceState(null, '', '#' + section);
+ });
+});
+
+// Restore tab from hash
+window.addEventListener('DOMContentLoaded', function() {
+ const hash = window.location.hash.replace('#', '');
+ if (hash) {
+ const navLink = document.querySelector(`.admin-nav[data-section="${hash}"]`);
+ if (navLink) navLink.click();
+ }
+});
+
+// Inline link editing
+function editLink(id, btn) {
+ const row = document.getElementById('link-row-' + id);
+ const cells = row.querySelectorAll('.link-display');
+ const label = cells[0].textContent.trim();
+ const url = cells[1].textContent.trim();
+ const desc = cells[2].textContent.trim();
+
+ cells[0].innerHTML = `<input name="label" value="${label}">`;
+ cells[1].innerHTML = `<input name="url" value="${url}">`;
+ cells[2].innerHTML = `<input name="description" value="${desc}">`;
+
+ btn.textContent = 'Save';
+ btn.onclick = function() { saveLink(id, row, btn); };
+}
+
+function saveLink(id, row, btn) {
+ const data = {
+ label: row.querySelector('input[name="label"]').value,
+ url: row.querySelector('input[name="url"]').value,
+ description: row.querySelector('input[name="description"]').value,
+ _token: '{{ csrf_token() }}',
+ _method: 'PUT',
+ _redirect: '/admin#links'
+ };
+
+ axios.post('/l/' + id, data)
+ .then(function() {
+ window.location.href = '/admin#links';
+ window.location.reload();
+ })
+ .catch(function(err) {
+ alert('Error saving link: ' + (err.response?.data?.message || err.message));
+ });
+}
+</script>
+@endsection