diff --git a/app/Http/Controllers/ReleaseController.php b/app/Http/Controllers/ReleaseController.php index b51954b..bce87b6 100644 --- a/app/Http/Controllers/ReleaseController.php +++ b/app/Http/Controllers/ReleaseController.php @@ -38,6 +38,12 @@ final class ReleaseController extends Controller return $this->send($release); } + public function productDetails(DownloadProduct $product) + { + abort_unless($product->is_published && $product->file_path, 404); + return view('downloads.product', compact('product')); + } + public function productDownload(DownloadProduct $product): BinaryFileResponse { abort_unless($product->is_published && $product->file_path && Storage::disk('local')->exists($product->file_path), 404); diff --git a/resources/views/downloads/index.blade.php b/resources/views/downloads/index.blade.php index fe9892e..70b60b7 100644 --- a/resources/views/downloads/index.blade.php +++ b/resources/views/downloads/index.blade.php @@ -4,7 +4,13 @@
Native macOSFast, focused desktop workflow
SonarQubeYour server remains the source of truth
SecurityTokens protected by macOS Keychain
UpdatesProfessional in-app release delivery
@if($latest)
Latest stable release

SonarDesk {{ $latest->version }}

Build {{ $latest->build_number }} · Released {{ $latest->published_at?->format('j F Y') }}

Download {{ $latest->version }}
{!! nl2br(e($latest->release_notes ?: 'This release contains the latest SonarDesk improvements and maintenance updates.')) !!}
SHA-256 checksum · Verify download{{ $latest->sha256 }}
@endif
@if($products->isNotEmpty()) -
Software catalogue

More downloads

Additional tools and installers available from our team.

@foreach($products as $product)
{{ $product->platform ?: 'Software' }}{{ $product->version ? 'v'.$product->version : 'Latest' }}

{{ $product->name }}

{!! \Illuminate\Support\Str::markdown($product->description ?: 'Download the latest available package.', ['html_input' => 'strip', 'allow_unsafe_links' => false]) !!}
@endforeach
+
Software catalogue

More downloads

Additional tools and installers available from our team.

@foreach($products as $product) +
+
{{ $product->platform ?: 'Software' }}{{ $product->version ? 'v'.$product->version : 'Latest' }}
+

{{ $product->name }}

+

{{ \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) }}

+ +
@endforeach
@endif
Release archive

Previous versions

Published SonarDesk builds remain available here for customers who need a previous release.

@forelse($releases as $release)
SonarDesk {{ $release->version }}Build {{ $release->build_number }} · {{ ucfirst($release->channel) }} · {{ $release->published_at?->format('j M Y') }}
{{ $release->formatted_size }}Download
@empty

No published releases are available yet.

@endforelse
{{ $releases->links() }}
Support

Installation or activation help?

{{ $settings['support_text'] }}

Contact SonarDesk support
diff --git a/resources/views/downloads/product.blade.php b/resources/views/downloads/product.blade.php new file mode 100644 index 0000000..11903d4 --- /dev/null +++ b/resources/views/downloads/product.blade.php @@ -0,0 +1,13 @@ +@extends('layouts.app', ['title' => $product->name.' — Downloads', 'description' => 'Download '.$product->name.' and read product information and release notes.']) +@section('fullbleed') +
+
+← All downloads +
{{ $product->platform ?: 'Software' }}{{ $product->version ? 'v'.$product->version : 'Latest' }}
+

{{ $product->name }}

+

{{ $product->formatted_size }} · {{ $product->platform ?: 'Software' }}

+Download {{ $product->name }} ↓ +
{!! \Illuminate\Support\Str::markdown($product->description ?: 'Download the latest available package.', ['html_input' => 'strip', 'allow_unsafe_links' => false]) !!}
+Download ↓ +
+@endsection diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index dd26830..4efb8b8 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -332,6 +332,27 @@ @media (max-width: 640px) { .download-page .distribution-catalogue > .download-shell { width: calc(100% - 28px); } } + +/* Compact product catalogue */ +.download-page .distribution-catalogue > .download-shell { width:min(100% - 40px,1200px);max-width:1200px;margin-inline:auto; } +.download-page .distribution-product-grid { display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,330px),1fr));gap:20px;align-items:stretch; } +.download-page .distribution-product-card { display:flex;flex-direction:column;width:auto;min-width:0;padding:26px;border-radius:18px; } +.download-page .distribution-product-card h3 {font-size:clamp(25px,2vw,30px);font-weight:800;letter-spacing:-.035em;line-height:1.15;margin:20px 0 12px;color:#101828;} +.download-page .distribution-product-description {font-size:15px;line-height:1.6;margin:0 0 20px;color:#475467;} +.download-page .distribution-product-footer {margin-top:auto;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;} +.download-page .distribution-product-links {display:flex;align-items:center;gap:12px;flex-wrap:wrap;} +.download-page .distribution-product-links .product-details-link {color:#175cd3;font-weight:700;text-decoration:none;} +.download-page .distribution-product-links .product-details-link:hover {text-decoration:underline;} +.download-page .product-detail-panel {background:white;border:1px solid #e3e8ef;border-radius:18px;padding:clamp(24px,4vw,52px);margin:40px auto 70px;max-width:960px;} +.download-page .product-detail-panel h1 {font-size:clamp(32px,4vw,48px);font-weight:800;letter-spacing:-.04em;line-height:1.1;margin:14px 0;} +.download-page .product-detail-panel .distribution-product-description {margin-top:30px;font-size:16px;} +.download-page .product-detail-panel .distribution-product-description h2 {font-size:24px;margin:30px 0 12px;} +.download-page .product-detail-panel .distribution-product-description h3 {font-size:19px;margin:24px 0 10px;} +.download-page .product-detail-panel .distribution-product-description ul {list-style:disc;padding-left:25px;} +.download-page .product-detail-panel .distribution-product-description ol {list-style:decimal;padding-left:25px;} +.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;}} + @stack('head') diff --git a/routes/web.php b/routes/web.php index a25dd50..7793c3c 100644 --- a/routes/web.php +++ b/routes/web.php @@ -26,6 +26,7 @@ Route::get('/', fn () => view('portal.welcome', ['latestRelease' => \App\Models\ Route::view('/features', 'features')->name('features'); Route::get('/release', [ReleaseController::class, 'index'])->name('release'); 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'); Route::get('/downloads/{release}', [ReleaseController::class, 'download'])->name('download.release'); Route::get('/updates/appcast.xml', [ReleaseController::class, 'appcast'])->name('updates.appcast');