diff --git a/app/Http/Controllers/Admin/DownloadProductController.php b/app/Http/Controllers/Admin/DownloadProductController.php
index 9e5a45b..8bc4a21 100644
--- a/app/Http/Controllers/Admin/DownloadProductController.php
+++ b/app/Http/Controllers/Admin/DownloadProductController.php
@@ -8,14 +8,14 @@ use Illuminate\Support\Facades\Storage;
final class DownloadProductController extends Controller {
public function index() { return view('admin.download-products.index', ['products'=>DownloadProduct::latest()->get()]); }
public function store(Request $request) {
- $data=$request->validate(['name'=>'required|string|max:150','description'=>'nullable|string|max:3000','version'=>'nullable|string|max:80','platform'=>'nullable|string|max:120','package'=>'required|file|max:1048576','is_published'=>'sometimes|boolean']);
+ $data=$request->validate(['name'=>'required|string|max:150','description'=>'nullable|string|max:12000','version'=>'nullable|string|max:80','platform'=>'nullable|string|max:120','package'=>'required|file|max:1048576','is_published'=>'sometimes|boolean']);
$file=$request->file('package');
$path=$file->store('download-products','local');
DownloadProduct::create(['name'=>$data['name'],'description'=>$data['description']??null,'version'=>$data['version']??null,'platform'=>$data['platform']??null,'file_path'=>$path,'original_filename'=>$file->getClientOriginalName(),'file_size'=>$file->getSize(),'is_published'=>$request->boolean('is_published')]);
return back()->with('status','Product added.');
}
public function update(Request $request, DownloadProduct $product) {
- $data=$request->validate(['name'=>'required|string|max:150','description'=>'nullable|string|max:3000','version'=>'nullable|string|max:80','platform'=>'nullable|string|max:120','package'=>'nullable|file|max:1048576','is_published'=>'sometimes|boolean']);
+ $data=$request->validate(['name'=>'required|string|max:150','description'=>'nullable|string|max:12000','version'=>'nullable|string|max:80','platform'=>'nullable|string|max:120','package'=>'nullable|file|max:1048576','is_published'=>'sometimes|boolean']);
$changes=['name'=>$data['name'],'description'=>$data['description']??null,'version'=>$data['version']??null,'platform'=>$data['platform']??null,'is_published'=>$request->boolean('is_published')];
if ($request->hasFile('package')) { $file=$request->file('package'); $path=$file->store('download-products','local'); $old=$product->file_path; $changes+=['file_path'=>$path,'original_filename'=>$file->getClientOriginalName(),'file_size'=>$file->getSize()]; $product->update($changes); if($old) Storage::disk('local')->delete($old); }
else $product->update($changes);
diff --git a/resources/views/admin/download-products/index.blade.php b/resources/views/admin/download-products/index.blade.php
index 70ffdf7..6740f7f 100644
--- a/resources/views/admin/download-products/index.blade.php
+++ b/resources/views/admin/download-products/index.blade.php
@@ -9,7 +9,7 @@
@forelse($products as $product)
| {{ $product->name }}{{ \Illuminate\Support\Str::limit($product->description ?: $product->original_filename, 70) }} | {{ $product->version ?: '—' }}{{ $product->platform ?: 'Unspecified' }} · {{ $product->formatted_size }} | {{ number_format($product->download_count) }} | {{ $product->is_published ? 'Published' : 'Draft' }} | |
@empty| No additional products yet. Add your first installer below. |
@endforelse
- any() && !old('_method')) open @endif>Add a new productUpload an installer and choose whether to publish it.+
- @foreach($products as $product)Edit {{ $product->name }}{{ $product->original_filename }} · {{ $product->formatted_size }}+
@endforeach
+ any() && !old('_method')) open @endif>Add a new productUpload an installer and choose whether to publish it.+
+ @foreach($products as $product)Edit {{ $product->name }}{{ $product->original_filename }} · {{ $product->formatted_size }}+
@endforeach
@endsection
diff --git a/resources/views/downloads/index.blade.php b/resources/views/downloads/index.blade.php
index 92f1917..fe9892e 100644
--- a/resources/views/downloads/index.blade.php
+++ b/resources/views/downloads/index.blade.php
@@ -4,7 +4,7 @@
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 releaseSonarDesk {{ $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 catalogueMore downloads
Additional tools and installers available from our team.
@foreach($products as $product)
{{ $product->platform ?: 'Software' }}{{ $product->version ? 'v'.$product->version : 'Latest' }}
↓
{{ $product->name }}
{{ $product->description ?: 'Download the latest available package.' }}
@endforeach
+Software catalogueMore 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
@endif
Release archivePrevious 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') }}
@empty
No published releases are available yet.
@endforelse
{{ $releases->links() }}
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php
index 1a000fd..af145f2 100644
--- a/resources/views/layouts/app.blade.php
+++ b/resources/views/layouts/app.blade.php
@@ -258,6 +258,26 @@
margin-bottom: 14px;
}
+/* Markdown product descriptions: readable headings, paragraphs and lists. */
+.download-page .distribution-product-description { color:#475467; font-size:14px; line-height:1.75; margin:0 0 20px; overflow-wrap:anywhere; }
+.download-page .distribution-product-description > :first-child { margin-top:0; }
+.download-page .distribution-product-description > :last-child { margin-bottom:0; }
+.download-page .distribution-product-description h1,
+.download-page .distribution-product-description h2,
+.download-page .distribution-product-description h3 { color:#101828; font-weight:750; line-height:1.35; margin:22px 0 8px; letter-spacing:-.015em; }
+.download-page .distribution-product-description h1 { font-size:20px; }
+.download-page .distribution-product-description h2 { font-size:17px; }
+.download-page .distribution-product-description h3 { font-size:15px; }
+.download-page .distribution-product-description p { margin:0 0 12px; color:inherit; font-size:inherit; line-height:inherit; }
+.download-page .distribution-product-description ul { list-style:disc outside; margin:0 0 16px; padding-left:22px; }
+.download-page .distribution-product-description ol { list-style:decimal outside; margin:0 0 16px; padding-left:22px; }
+.download-page .distribution-product-description li { display:list-item; margin:5px 0; padding:0; }
+.download-page .distribution-product-description strong { color:#1d2939; font-weight:700; }
+.download-page .distribution-product-description a { color:#175cd3; text-decoration:underline; }
+.download-page .distribution-product-description code { background:#f2f4f7; border-radius:4px; padding:2px 4px; }
+.download-page .distribution-product-description pre { overflow-x:auto; background:#f2f4f7; padding:12px; border-radius:8px; }
+.download-page .distribution-product-description blockquote { border-left:3px solid #e8bc66; padding-left:12px; margin:12px 0; }
+
.download-page .distribution-product-footer {
padding-top: 12px;
}