download fixes

This commit is contained in:
Mark Gregory
2026-10-12 10:56:55 +01:00
parent f9123813fb
commit 1409d19e3d
5 changed files with 45 additions and 14 deletions
@@ -26,6 +26,14 @@ final class ReleaseController extends Controller
return view('downloads.index', compact('latest', 'releases', 'settings', 'products'));
}
public function sonarDeskDetails()
{
$latest = SonarDeskRelease::published()->where('is_featured', true)->orderByDesc('published_at')->first()
?? SonarDeskRelease::published()->where('channel', 'stable')->orderByDesc('published_at')->orderByDesc('id')->firstOrFail();
$settings = $this->settings();
return view('downloads.sonardesk', compact('latest', 'settings'));
}
public function latest(): BinaryFileResponse
{
$release = SonarDeskRelease::published()->where('channel', 'stable')->orderByDesc('published_at')->firstOrFail();
+15 -14
View File
@@ -1,17 +1,18 @@
@extends('layouts.app', ['title' => 'Download SonarDesk — Native SonarQube monitoring for macOS', 'description' => 'Download the latest signed SonarDesk release for macOS, review release notes and system requirements.'])
@extends('layouts.app', ['title' => 'Downloads — SonarDesk and developer tools', 'description' => 'Browse SonarDesk and other macOS developer utilities. View release details or download installers.'])
@section('fullbleed')
<main class="download-page"><section class="download-hero"><div class="download-shell"><div class="download-copy"><span class="eyebrow">{{ $settings['eyebrow'] }}</span><h1>{{ $settings['title'] }}</h1><p>{{ $settings['intro'] }}</p>@if($latest)<div class="download-actions"><a class="btn download-primary" href="{{ route('download.latest') }}"><span class="download-icon">↓</span><span><strong>Download SonarDesk {{ $latest->version }}</strong><small>{{ $latest->formatted_size }} · macOS {{ $latest->minimum_macos ?: 'supported versions' }}</small></span></a><a class="btn download-secondary" href="#release-notes">View release notes</a></div><div class="release-verification"><span>✓ Signed distribution</span><span>✓ SHA-256 verified</span><span>✓ Secure licence activation</span></div>@else<div class="no-release"><strong>The next SonarDesk release is being prepared.</strong><span>Check back shortly or contact support.</span></div>@endif</div><div class="product-visual"><div class="mac-window"><div class="mac-titlebar"><i></i><i></i><i></i><span>SonarDesk</span></div><div class="mac-content"><div class="mini-sidebar"><img src="{{ asset('icons/sonardesk-icon-64.png') }}" alt=""><b>SonarDesk</b><span class="active"></span><span></span><span></span><span></span><span></span></div><div class="mini-dashboard"><div class="mini-head"><b>Project health</b><em>All systems monitored</em></div><div class="mini-stats"><i></i><i></i><i></i><i></i></div><div class="mini-chart"><span></span><span></span><span></span><span></span><span></span><span></span></div></div></div></div><div class="visual-badge"><span>Native</span><strong>Built for macOS</strong></div></div></div></section>
<section class="download-confidence"><div class="download-shell confidence-grid"><div><span>Native macOS</span><strong>Fast, focused desktop workflow</strong></div><div><span>SonarQube</span><strong>Your server remains the source of truth</strong></div><div><span>Security</span><strong>Tokens protected by macOS Keychain</strong></div><div><span>Updates</span><strong>Professional in-app release delivery</strong></div></div></section>
<div class="download-shell download-content">@if($latest)<section id="release-notes" class="release-notes-panel"><div class="release-heading"><div><span class="eyebrow">Latest stable release</span><h2>SonarDesk {{ $latest->version }}</h2><p>Build {{ $latest->build_number }} · Released {{ $latest->published_at?->format('j F Y') }}</p></div><a class="btn btn-primary" href="{{ route('download.release',$latest) }}">Download {{ $latest->version }}</a></div><div class="release-note-copy">{!! nl2br(e($latest->release_notes ?: 'This release contains the latest SonarDesk improvements and maintenance updates.')) !!}</div><details class="checksum-box"><summary>SHA-256 checksum · Verify download</summary><code>{{ $latest->sha256 }}</code></details></section>@endif<aside class="requirements-panel"><span class="eyebrow">Before you install</span><h2>System requirements</h2><p>{{ $settings['requirements'] }}</p><ol><li><span>1</span><div><strong>Download</strong><small>Get the latest signed SonarDesk package.</small></div></li><li><span>2</span><div><strong>Install</strong><small>Open the DMG and move SonarDesk to Applications.</small></div></li><li><span>3</span><div><strong>Activate</strong><small>Enter the licence key delivered after purchase.</small></div></li></ol><a href="{{ route('buy') }}">Need a licence? View pricing →</a></aside></div>
@if($products->isNotEmpty())
<section class="distribution-catalogue"><div class="download-shell"><div class="section-heading"><span class="eyebrow">Software catalogue</span><h2>More downloads</h2><p>Additional tools and installers available from our team.</p></div><div class="distribution-product-grid">@foreach($products as $product)
<article class="distribution-product-card">
<div class="distribution-product-top"><span class="distribution-platform">{{ $product->platform ?: 'Software' }}</span><span class="distribution-version">{{ $product->version ? 'v'.$product->version : 'Latest' }}</span></div>
<h3><a href="{{ route('download.product.details', $product) }}" style="color:inherit;text-decoration:none">{{ $product->name }}</a></h3>
<p class="distribution-product-description">{{ \Illuminate\Support\Str::limit(trim(preg_replace('/\s+/', ' ', strip_tags(\Illuminate\Support\Str::markdown($product->description ?: 'Download the latest available package.', ['html_input' => 'strip', 'allow_unsafe_links' => false])))), 190) }}</p>
<div class="distribution-product-footer"><span>{{ $product->formatted_size }}</span><div class="distribution-product-links"><a class="product-details-link" href="{{ route('download.product.details', $product) }}">View details →</a><a class="btn btn-primary" href="{{ route('download.product',$product) }}" aria-label="Download {{ $product->name }}">Download ↓</a></div></div>
</article>@endforeach</div></div></section>
<main class="download-page catalogue-page">
<section class="catalogue-header"><div class="download-shell"><span class="eyebrow">Software downloads</span><h1>Downloads</h1><p>Find the latest releases of SonarDesk and our developer tools. View details, check requirements or download directly.</p></div></section>
<section class="distribution-catalogue"><div class="download-shell"><div class="section-heading"><span class="eyebrow">Available software</span><h2>Product catalogue</h2><p>All downloads in one place.</p></div>
<div class="distribution-product-grid">
@if($latest)
<article class="distribution-product-card"><div class="distribution-product-top"><span class="distribution-platform">macOS</span><span class="distribution-version">v{{ $latest->version }}</span></div><h3><a href="{{ route('download.sonardesk.details') }}">SonarDesk</a></h3><p class="distribution-product-description">{{ \Illuminate\Support\Str::limit(trim(preg_replace('/\s+/', ' ', strip_tags(\Illuminate\Support\Str::markdown($latest->release_notes ?: $settings['intro'], ['html_input'=>'strip','allow_unsafe_links'=>false])))), 175) }}</p><div class="distribution-product-footer"><span>{{ $latest->formatted_size }}</span><div class="distribution-product-links"><a class="product-details-link" href="{{ route('download.sonardesk.details') }}">View details →</a><a class="btn btn-primary" href="{{ route('download.latest') }}">Download ↓</a></div></div></article>
@endif
<section class="release-history"><div class="download-shell"><div class="section-heading"><span class="eyebrow">Release archive</span><h2>Previous versions</h2><p>Published SonarDesk builds remain available here for customers who need a previous release.</p></div><div class="release-history-list">@forelse($releases as $release)<article><div><strong>SonarDesk {{ $release->version }}</strong><span>Build {{ $release->build_number }} · {{ ucfirst($release->channel) }} · {{ $release->published_at?->format('j M Y') }}</span></div><div><span>{{ $release->formatted_size }}</span><a href="{{ route('download.release',$release) }}">Download</a></div></article>@empty<p>No published releases are available yet.</p>@endforelse</div>{{ $releases->links() }}</div></section>
<section class="download-support"><div class="download-shell"><div><span class="eyebrow">Support</span><h2>Installation or activation help?</h2><p>{{ $settings['support_text'] }}</p></div><a class="btn btn-secondary" href="{{ route('support') }}">Contact SonarDesk support</a></div></section></main>
@foreach($products as $product)
<article class="distribution-product-card"><div class="distribution-product-top"><span class="distribution-platform">{{ $product->platform ?: 'Software' }}</span><span class="distribution-version">{{ $product->version ? 'v'.$product->version : 'Latest' }}</span></div><h3><a href="{{ route('download.product.details', $product) }}">{{ $product->name }}</a></h3><p class="distribution-product-description">{{ \Illuminate\Support\Str::limit(trim(preg_replace('/\s+/', ' ', strip_tags(\Illuminate\Support\Str::markdown($product->description ?: 'Download the latest available package.', ['html_input'=>'strip','allow_unsafe_links'=>false])))), 175) }}</p><div class="distribution-product-footer"><span>{{ $product->formatted_size }}</span><div class="distribution-product-links"><a class="product-details-link" href="{{ route('download.product.details', $product) }}">View details →</a><a class="btn btn-primary" href="{{ route('download.product', $product) }}">Download ↓</a></div></div></article>
@endforeach
</div>
@if(!$latest && $products->isEmpty())<p>No published downloads are available yet.</p>@endif
</div></section>
@if($releases->isNotEmpty())<section class="release-history"><div class="download-shell"><div class="section-heading"><span class="eyebrow">SonarDesk archive</span><h2>Previous SonarDesk versions</h2><p>Older published installers, grouped separately from current products.</p></div><div class="release-history-list">@foreach($releases as $release)<article><div><strong>SonarDesk {{ $release->version }}</strong><span>Build {{ $release->build_number }} · {{ ucfirst($release->channel) }} · {{ $release->published_at?->format('j M Y') }}</span></div><div><span>{{ $release->formatted_size }}</span><a href="{{ route('download.release', $release) }}">Download</a></div></article>@endforeach</div>{{ $releases->links() }}</div></section>@endif
</main>
@endsection
@@ -0,0 +1,4 @@
@extends('layouts.app', ['title' => 'SonarDesk — Details and download', 'description' => 'SonarDesk release notes, system requirements and macOS installer.'])
@section('fullbleed')
<main class="download-page"><div class="download-shell"><article class="product-detail-panel"><a class="product-details-link" href="{{ route('release') }}">← All downloads</a><div class="distribution-product-top" style="margin-top:26px"><span class="distribution-platform">macOS</span><span class="distribution-version">v{{ $latest->version }}</span></div><h1>SonarDesk</h1><p>{{ $settings['intro'] }}</p><p class="detail-meta">Version {{ $latest->version }} · Build {{ $latest->build_number }} · {{ $latest->formatted_size }} · Released {{ $latest->published_at?->format('j F Y') }}</p><a class="btn btn-primary" href="{{ route('download.latest') }}">Download SonarDesk ↓</a><section class="detail-section"><h2>Release notes</h2><div class="distribution-product-description">{!! \Illuminate\Support\Str::markdown($latest->release_notes ?: 'Latest maintenance and improvements.', ['html_input'=>'strip','allow_unsafe_links'=>false]) !!}</div></section><section class="detail-section"><h2>System requirements</h2><p>{{ $settings['requirements'] }}</p>@if($latest->minimum_macos)<p><strong>Minimum macOS version:</strong> {{ $latest->minimum_macos }}</p>@endif</section><section class="detail-section"><h2>Installation</h2><ol><li>Download the signed installer.</li><li>Open the DMG and move SonarDesk to Applications.</li><li>Launch SonarDesk and activate with your licence.</li></ol></section>@if($latest->sha256)<details class="checksum-box"><summary>SHA-256 checksum</summary><code>{{ $latest->sha256 }}</code></details>@endif</article></div></main>
@endsection
+17
View File
@@ -353,6 +353,23 @@
.download-page .product-detail-panel .distribution-product-description li {margin:6px 0;}
@media(max-width:700px){.download-page .distribution-product-grid{grid-template-columns:1fr;}}
/* Compact, unified software catalogue */
.download-page.catalogue-page .catalogue-header {padding:64px 0 32px;background:#f5f7fb;}
.download-page.catalogue-page .catalogue-header h1 {font-size:clamp(36px,4vw,54px);letter-spacing:-.045em;color:#101828;margin:10px 0;}
.download-page.catalogue-page .catalogue-header p {font-size:18px;color:#667085;max-width:720px;}
.download-page.catalogue-page .distribution-catalogue {padding-top:28px;}
.download-page .distribution-product-card h3 a {color:inherit;text-decoration:none;}
.download-page .distribution-product-card h3 a:hover {color:#175cd3;}
.download-page.catalogue-page .distribution-product-card {padding:24px;}
.download-page.catalogue-page .distribution-product-card h3 {margin:14px 0 10px;font-size:28px;}
.download-page.catalogue-page .distribution-product-description {margin-bottom:18px;}
.download-page .detail-section {margin-top:36px;border-top:1px solid #eaecf0;padding-top:26px;}
.download-page .detail-section h2 {font-size:24px;font-weight:800;margin-bottom:14px;color:#101828;}
.download-page .detail-section ol {padding-left:24px;list-style:decimal;}
.download-page .detail-section li {margin:8px 0;}
.download-page .detail-meta {color:#667085;margin:12px 0 22px;}
</style>
@stack('head')
</head>
+1
View File
@@ -25,6 +25,7 @@ Route::get('/robots.txt', [SeoController::class, 'robots'])->name('robots');
Route::get('/', fn () => view('portal.welcome', ['latestRelease' => \App\Models\SonarDeskRelease::published()->where('channel', 'stable')->latest('published_at')->first()]))->name('home');
Route::view('/features', 'features')->name('features');
Route::get('/release', [ReleaseController::class, 'index'])->name('release');
Route::get('/downloads/sonardesk/details', [ReleaseController::class, 'sonarDeskDetails'])->name('download.sonardesk.details');
Route::get('/download', [ReleaseController::class, 'latest'])->name('download.latest');
Route::get('/downloads/products/{product}/details', [ReleaseController::class, 'productDetails'])->name('download.product.details');
Route::get('/downloads/products/{product}', [ReleaseController::class, 'productDownload'])->name('download.product');