Fix: admin view extends Pterodactyl layout with proper AdminLTE styling
Rewrote view.blade.php to use @extends('layouts.admin'), @section blocks,
AdminLTE box/callout/table classes, and standard Pterodactyl admin chrome.
Replaces custom inline styles with framework components.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5775fc0cd6
commit
bd9a5fcde3
@@ -0,0 +1,50 @@
|
||||
# Chronicler Dispatch — Phase 11D UI Styling
|
||||
|
||||
**Date:** 2026-04-12
|
||||
**From:** Chronicler #84 — The Meridian
|
||||
**To:** Code
|
||||
|
||||
---
|
||||
|
||||
## UI Feedback from Michael
|
||||
|
||||
The current admin page renders as plain unstyled HTML — not integrated with Pterodactyl's admin UI. Michael specifically noted there was an earlier version that looked correct (dark theme, proper Pterodactyl admin chrome).
|
||||
|
||||
**What's needed:** `view.blade.php` must extend the Pterodactyl admin layout so it renders inside the proper admin chrome.
|
||||
|
||||
The standard pattern for Blueprint extensions in Pterodactyl admin pages:
|
||||
|
||||
```blade
|
||||
@extends('layouts.admin')
|
||||
@include('partials/admin.settings-notices')
|
||||
|
||||
@section('title')
|
||||
ModpackChecker
|
||||
@endsection
|
||||
|
||||
@section('content-header')
|
||||
<h1>ModpackChecker<small>4-Platform Modpack Version Monitoring</small></h1>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">License</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
{{-- license content here --}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
```
|
||||
|
||||
Use AdminLTE's `box`, `box-primary`, `form-group`, `btn btn-primary` classes — that's what the rest of the Pterodactyl admin uses.
|
||||
|
||||
Michael has final approval on UI before it goes to the live panel. Please push an updated view.blade.php with proper Pterodactyl admin styling.
|
||||
|
||||
*— Chronicler #84, The Meridian*
|
||||
**Fire + Frost + Foundation** 💙🔥❄️
|
||||
@@ -1,165 +1,100 @@
|
||||
<form id="config-form" action="" method="POST">
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
showSaveButton();
|
||||
});
|
||||
@extends('layouts.admin')
|
||||
@include('partials/admin.settings-notices')
|
||||
|
||||
function showSaveButton() {
|
||||
const configForm = document.getElementById("config-form");
|
||||
const saveOverlay = document.getElementById("save-overlay");
|
||||
@section('title')
|
||||
ModpackChecker
|
||||
@endsection
|
||||
|
||||
configForm.addEventListener("change", function() {
|
||||
saveOverlay.style.display = "inline";
|
||||
setTimeout(() => {
|
||||
saveOverlay.style.bottom = "10px";
|
||||
}, 100);
|
||||
});
|
||||
@section('content-header')
|
||||
<h1>ModpackChecker<small>4-Platform Modpack Version Monitoring</small></h1>
|
||||
@endsection
|
||||
|
||||
configForm.addEventListener("input", function() {
|
||||
saveOverlay.style.display = "inline";
|
||||
setTimeout(() => {
|
||||
saveOverlay.style.bottom = "10px";
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@section('content')
|
||||
|
||||
<!-- Save button overlay -->
|
||||
<div id="save-overlay">
|
||||
{{ csrf_field() }}
|
||||
<button type="submit" name="_method" value="PATCH" class="btn btn-primary btn-sm">
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
<style>
|
||||
#save-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
transition: bottom 0.3s;
|
||||
bottom: -200px;
|
||||
right: 20px;
|
||||
z-index: 500;
|
||||
padding: 15px;
|
||||
background: #1a1a2e;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Header -->
|
||||
<div class="row" style="margin-bottom: 20px;">
|
||||
<div class="col-xs-12">
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<div style="width: 50px; height: 50px; background: linear-gradient(135deg, #FF6B35, #4ECDC4); border-radius: 10px; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="fa fa-cube" style="font-size: 24px; color: white;"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h2 style="margin: 0; color: #fff;">ModpackChecker</h2>
|
||||
<p style="margin: 0; color: #888;">4-Platform Modpack Version Monitoring</p>
|
||||
</div>
|
||||
</div>
|
||||
{{-- License Status Banners --}}
|
||||
@if($license['status'] === 'expired')
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="callout callout-danger">
|
||||
<h4><i class="fa fa-exclamation-triangle"></i> License Expired</h4>
|
||||
<p>Your license could not be validated. Pro features are disabled. Please check your order ID or contact support.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- License Status Banner -->
|
||||
@if($license['status'] === 'expired')
|
||||
<div class="row" style="margin-bottom: 15px;">
|
||||
<div class="col-xs-12">
|
||||
<div style="background: #4a1a1a; border-left: 4px solid #e74c3c; border-radius: 4px; padding: 15px;">
|
||||
<h4 style="margin: 0 0 5px 0; color: #e74c3c;"><i class="fa fa-exclamation-triangle"></i> License Expired</h4>
|
||||
<p style="margin: 0; color: #ccc;">Your license could not be validated. Pro features are disabled. Please check your order ID or contact support.</p>
|
||||
</div>
|
||||
</div>
|
||||
@elseif($license['status'] === 'grace')
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="callout callout-warning">
|
||||
<h4><i class="fa fa-clock-o"></i> License Validation Warning</h4>
|
||||
<p>Could not reach license server. Grace period expires: <strong>{{ $license['grace_expires'] }}</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
@elseif($license['status'] === 'grace')
|
||||
<div class="row" style="margin-bottom: 15px;">
|
||||
<div class="col-xs-12">
|
||||
<div style="background: #4a3a1a; border-left: 4px solid #f39c12; border-radius: 4px; padding: 15px;">
|
||||
<h4 style="margin: 0 0 5px 0; color: #f39c12;"><i class="fa fa-clock-o"></i> License Validation Warning</h4>
|
||||
<p style="margin: 0; color: #ccc;">Could not reach license server. Grace period expires: <strong>{{ $license['grace_expires'] }}</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ $root }}" method="POST">
|
||||
{{ csrf_field() }}
|
||||
|
||||
<!-- License Activation -->
|
||||
<div class="row">
|
||||
{{-- License Activation --}}
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
<i class="fa fa-id-card"></i> License
|
||||
@if($license['status'] === 'active')
|
||||
<span class="label label-success" style="margin-left: 10px;">Active</span>
|
||||
@elseif($license['status'] === 'grace')
|
||||
<span class="label label-warning" style="margin-left: 10px;">Grace Period</span>
|
||||
@elseif($license['status'] === 'expired')
|
||||
<span class="label label-danger" style="margin-left: 10px;">Expired</span>
|
||||
@else
|
||||
<span class="label label-default" style="margin-left: 10px;">Not Activated</span>
|
||||
@endif
|
||||
</h3>
|
||||
<div class="box-tools pull-right">
|
||||
@if($license['status'] === 'active')
|
||||
<span class="label label-success">Active</span>
|
||||
@elseif($license['status'] === 'grace')
|
||||
<span class="label label-warning">Grace Period</span>
|
||||
@elseif($license['status'] === 'expired')
|
||||
<span class="label label-danger">Expired</span>
|
||||
@else
|
||||
<span class="label label-default">Not Activated</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label">BuiltByBit Order ID</label>
|
||||
<input
|
||||
type="text"
|
||||
name="order_id"
|
||||
id="order_id"
|
||||
value="{{ $license['order_id'] }}"
|
||||
placeholder="Enter your order ID..."
|
||||
class="form-control"
|
||||
/>
|
||||
<p class="text-muted small" style="margin-top: 8px;">
|
||||
Enter the order ID from your BuiltByBit purchase to activate.
|
||||
</p>
|
||||
<input type="text" name="order_id" value="{{ $license['order_id'] }}"
|
||||
placeholder="Enter your order ID..." class="form-control" />
|
||||
<p class="text-muted small">Enter the order ID from your BuiltByBit purchase to activate.</p>
|
||||
</div>
|
||||
@if($license['status'] === 'active' || $license['status'] === 'grace')
|
||||
<div style="margin-top: 8px; padding: 10px; background: #2a2a3e; border-radius: 4px;">
|
||||
<p style="margin: 0; color: #aaa; font-size: 12px;">
|
||||
<strong>Tier:</strong> {{ ucfirst($license['tier']) }}
|
||||
|
|
||||
<strong>Last Validated:</strong> {{ $license['last_validated'] ?: 'Never' }}
|
||||
</p>
|
||||
</div>
|
||||
@endif
|
||||
@if(!empty($license['order_id']))
|
||||
<div style="margin-top: 10px;">
|
||||
<button type="submit" name="deactivate_license" value="1" class="btn btn-danger btn-xs"
|
||||
onclick="return confirm('Are you sure you want to deactivate? This frees the activation slot.')">
|
||||
Deactivate License
|
||||
</button>
|
||||
<div class="well well-sm">
|
||||
<strong>Tier:</strong> {{ ucfirst($license['tier']) }}
|
||||
|
|
||||
<strong>Last Validated:</strong> {{ $license['last_validated'] ?: 'Never' }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@if(!empty($license['order_id']))
|
||||
<div class="box-footer">
|
||||
<button type="submit" name="deactivate_license" value="1" class="btn btn-danger btn-xs"
|
||||
onclick="return confirm('Are you sure? This frees the activation slot.')">
|
||||
Deactivate License
|
||||
</button>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CurseForge API Key -->
|
||||
{{-- CurseForge API Key --}}
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
<i class="fa fa-key"></i> CurseForge API Key
|
||||
</h3>
|
||||
<h3 class="box-title"><i class="fa fa-key"></i> CurseForge API Key</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label">API Key (BYOK)</label>
|
||||
<input
|
||||
type="password"
|
||||
name="curseforge_api_key"
|
||||
id="curseforge_api_key"
|
||||
value="{{ $curseforge_api_key }}"
|
||||
placeholder="$2a$10$..."
|
||||
class="form-control"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<p class="text-muted small" style="margin-top: 8px;">
|
||||
<input type="password" name="curseforge_api_key" value="{{ $curseforge_api_key }}"
|
||||
placeholder="$2a$10$..." class="form-control" autocomplete="off" />
|
||||
<p class="text-muted small">
|
||||
Get your free API key from
|
||||
<a href="https://console.curseforge.com/" target="_blank">console.curseforge.com</a>.
|
||||
Required for CurseForge modpack detection.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -168,29 +103,28 @@
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Check Interval (PRO TIER) -->
|
||||
{{-- Check Interval (PRO) --}}
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="box box-info">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
<i class="fa fa-clock-o"></i> Check Interval
|
||||
<span class="label label-warning" style="margin-left: 10px;">PRO TIER</span>
|
||||
<span class="label label-warning">PRO</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label">Automatic Check Frequency</label>
|
||||
<select class="form-control" name="check_interval" id="check_interval"
|
||||
<select class="form-control" name="check_interval"
|
||||
{{ $license['tier'] !== 'professional' || $license['status'] === 'expired' ? 'disabled' : '' }}>
|
||||
<option value="daily" {{ $check_interval === 'daily' ? 'selected' : '' }}>Daily (24 Hours)</option>
|
||||
<option value="12h" {{ $check_interval === '12h' ? 'selected' : '' }}>Every 12 Hours</option>
|
||||
<option value="6h" {{ $check_interval === '6h' ? 'selected' : '' }}>Every 6 Hours</option>
|
||||
</select>
|
||||
<p class="text-muted small" style="margin-top: 8px;">
|
||||
<p class="text-muted small">
|
||||
@if($license['tier'] === 'professional' && $license['status'] !== 'expired')
|
||||
Professional tier — custom check intervals enabled.
|
||||
@else
|
||||
Standard tier is locked to daily checks.
|
||||
Upgrade to Professional for more frequent automated checks.
|
||||
@endif
|
||||
</p>
|
||||
@@ -199,32 +133,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Discord Webhook (PRO TIER) -->
|
||||
{{-- Discord Webhook (PRO) --}}
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="box box-success">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
<i class="fa fa-bell"></i> Discord Notifications
|
||||
<span class="label label-warning" style="margin-left: 10px;">PRO TIER</span>
|
||||
<span class="label label-warning">PRO</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label">Webhook URL</label>
|
||||
<input
|
||||
type="url"
|
||||
name="discord_webhook_url"
|
||||
id="discord_webhook_url"
|
||||
value="{{ $discord_webhook_url }}"
|
||||
placeholder="https://discord.com/api/webhooks/..."
|
||||
class="form-control"
|
||||
{{ $license['tier'] !== 'professional' || $license['status'] === 'expired' ? 'disabled' : '' }}
|
||||
/>
|
||||
<p class="text-muted small" style="margin-top: 8px;">
|
||||
<input type="url" name="discord_webhook_url" value="{{ $discord_webhook_url }}"
|
||||
placeholder="https://discord.com/api/webhooks/..."
|
||||
class="form-control"
|
||||
{{ $license['tier'] !== 'professional' || $license['status'] === 'expired' ? 'disabled' : '' }} />
|
||||
<p class="text-muted small">
|
||||
@if($license['tier'] === 'professional' && $license['status'] !== 'expired')
|
||||
Professional tier — Discord webhook alerts enabled.
|
||||
@else
|
||||
Upgrade to Professional to receive automated update alerts in your Discord server.
|
||||
Upgrade to Professional for Discord update alerts.
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
@@ -234,58 +163,50 @@
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Supported Platforms -->
|
||||
{{-- Supported Platforms --}}
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="box box-default">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
<i class="fa fa-check-circle"></i> Supported Platforms
|
||||
</h3>
|
||||
<h3 class="box-title"><i class="fa fa-check-circle"></i> Supported Platforms</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<ul style="list-style: none; padding: 0; margin: 0;">
|
||||
<li style="padding: 8px 0; border-bottom: 1px solid #333;">
|
||||
<i class="fa fa-fire" style="color: #f16436; width: 20px;"></i>
|
||||
<strong>CurseForge</strong>
|
||||
<span class="text-muted small">(Requires API Key)</span>
|
||||
</li>
|
||||
<li style="padding: 8px 0; border-bottom: 1px solid #333;">
|
||||
<i class="fa fa-leaf" style="color: #1bd96a; width: 20px;"></i>
|
||||
<strong>Modrinth</strong>
|
||||
<span class="text-muted small">(No key required)</span>
|
||||
</li>
|
||||
<li style="padding: 8px 0; border-bottom: 1px solid #333;">
|
||||
<i class="fa fa-cogs" style="color: #4a90d9; width: 20px;"></i>
|
||||
<strong>Technic</strong>
|
||||
<span class="text-muted small">(No key required)</span>
|
||||
</li>
|
||||
<li style="padding: 8px 0;">
|
||||
<i class="fa fa-cube" style="color: #e04e39; width: 20px;"></i>
|
||||
<strong>FTB (modpacks.ch)</strong>
|
||||
<span class="text-muted small">
|
||||
<div class="box-body no-padding">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td><i class="fa fa-fire text-red"></i> <strong>CurseForge</strong></td>
|
||||
<td class="text-muted">Requires API Key</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="fa fa-leaf text-green"></i> <strong>Modrinth</strong></td>
|
||||
<td class="text-muted">No key required</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="fa fa-cogs text-blue"></i> <strong>Technic</strong></td>
|
||||
<td class="text-muted">No key required</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="fa fa-cube text-red"></i> <strong>FTB</strong></td>
|
||||
<td>
|
||||
@if($license['tier'] === 'professional')
|
||||
(Enabled — Professional)
|
||||
<span class="text-green">Enabled</span>
|
||||
@else
|
||||
(PRO TIER only)
|
||||
<span class="label label-warning">PRO</span>
|
||||
@endif
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Update Available -->
|
||||
{{-- Update Available --}}
|
||||
@if(!empty($license['latest_version']) && $license['latest_version'] !== '1.0.0')
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
<i class="fa fa-download"></i> Update Available
|
||||
</h3>
|
||||
<h3 class="box-title"><i class="fa fa-download"></i> Update Available</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<p>A new version (<strong>{{ $license['latest_version'] }}</strong>) is available.</p>
|
||||
<p>Version <strong>{{ $license['latest_version'] }}</strong> is available.</p>
|
||||
<a href="https://builtbybit.com/" target="_blank" class="btn btn-warning btn-sm">
|
||||
Download from BuiltByBit
|
||||
</a>
|
||||
@@ -295,32 +216,38 @@
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Footer Info -->
|
||||
{{-- How It Works --}}
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div style="background: #1a1a2e; border-left: 4px solid #4ECDC4; border-radius: 4px; padding: 15px; margin-bottom: 15px;">
|
||||
<h4 style="margin: 0 0 10px 0; color: #fff;"><i class="fa fa-info-circle" style="color: #4ECDC4;"></i> How It Works</h4>
|
||||
<p style="margin-bottom: 0; color: #ccc;">
|
||||
<div class="callout callout-info">
|
||||
<h4><i class="fa fa-info-circle"></i> How It Works</h4>
|
||||
<p>
|
||||
ModpackChecker automatically detects modpacks via Egg Variables or file fingerprinting.
|
||||
Set <code style="background: #2a2a3e; padding: 2px 6px; border-radius: 3px;">MODPACK_PLATFORM</code> and
|
||||
<code style="background: #2a2a3e; padding: 2px 6px; border-radius: 3px;">MODPACK_ID</code> in your server's startup variables
|
||||
for the most reliable detection, or let the extension scan for
|
||||
<code style="background: #2a2a3e; padding: 2px 6px; border-radius: 3px;">manifest.json</code> /
|
||||
<code style="background: #2a2a3e; padding: 2px 6px; border-radius: 3px;">modrinth.index.json</code> files.
|
||||
Set <code>MODPACK_PLATFORM</code> and <code>MODPACK_ID</code> in your server's startup
|
||||
variables for the most reliable detection.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Support -->
|
||||
{{-- Save Button --}}
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div style="background: #1a1a2e; border-left: 4px solid #FF6B35; border-radius: 4px; padding: 15px;">
|
||||
<h4 style="margin: 0 0 10px 0; color: #fff;"><i class="fa fa-life-ring" style="color: #FF6B35;"></i> Need Help?</h4>
|
||||
<p style="margin-bottom: 0; color: #ccc;">
|
||||
Join our Discord for support: <a href="https://firefrostgaming.com/discord" target="_blank" style="color: #4ECDC4;">firefrostgaming.com/discord</a>
|
||||
</p>
|
||||
<button type="submit" name="_method" value="PATCH" class="btn btn-primary">
|
||||
<i class="fa fa-save"></i> Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Support --}}
|
||||
<div class="row" style="margin-top: 20px;">
|
||||
<div class="col-xs-12">
|
||||
<div class="callout callout-warning">
|
||||
<h4><i class="fa fa-life-ring"></i> Need Help?</h4>
|
||||
<p>Join our Discord for support: <a href="https://firefrostgaming.com/discord" target="_blank">firefrostgaming.com/discord</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@endsection
|
||||
|
||||
Reference in New Issue
Block a user