download fixes
This commit is contained in:
@@ -8,18 +8,23 @@ 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:512000','is_published'=>'sometimes|boolean']);
|
||||
$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']);
|
||||
$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:512000','is_published'=>'sometimes|boolean']);
|
||||
$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']);
|
||||
$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);
|
||||
return back()->with('status','Product updated.');
|
||||
}
|
||||
public function publication(Request $request, DownloadProduct $product) {
|
||||
$data = $request->validate(['is_published' => 'required|boolean']);
|
||||
$product->update(['is_published' => (bool) $data['is_published']]);
|
||||
return back()->with('status', $product->is_published ? 'Product published.' : 'Product unpublished.');
|
||||
}
|
||||
public function destroy(DownloadProduct $product) { if($product->file_path) Storage::disk('local')->delete($product->file_path); $product->delete(); return back()->with('status','Product deleted.'); }
|
||||
}
|
||||
|
||||
@@ -15,9 +15,13 @@ final class ReleaseController extends Controller
|
||||
{
|
||||
$latest = SonarDeskRelease::published()->where('is_featured', true)->orderByDesc('published_at')->first()
|
||||
?? SonarDeskRelease::published()->where('channel', 'stable')->orderByDesc('published_at')->orderByDesc('id')->first();
|
||||
$releases = SonarDeskRelease::published()->orderByDesc('published_at')->paginate(12);
|
||||
$releases = SonarDeskRelease::published()
|
||||
->when($latest, fn ($query) => $query->whereKeyNot($latest->getKey()))
|
||||
->orderByDesc('published_at')->paginate(12);
|
||||
$settings = $this->settings();
|
||||
$products = DownloadProduct::where('is_published', true)->whereNotNull('file_path')->orderBy('name')->get();
|
||||
$products = DownloadProduct::where('is_published', true)->whereNotNull('file_path')
|
||||
->when($latest, fn ($query) => $query->whereRaw('LOWER(name) <> ?', ['sonardesk']))
|
||||
->orderBy('name')->get();
|
||||
|
||||
return view('downloads.index', compact('latest', 'releases', 'settings', 'products'));
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
@extends('layouts.app', ['title' => 'Download products — Admin'])
|
||||
@section('content')
|
||||
<section class="portal-header"><div><span class="eyebrow">Distribution</span><h1>Other download products</h1><p class="lead compact">Add named products and files to the public downloads area.</p></div><a class="btn btn-secondary" href="{{ route('admin.releases.index') }}">Back to releases</a></section>
|
||||
@if(session('status'))<div class="card"><p>{{ session('status') }}</p></div>@endif
|
||||
@if($errors->any())<div class="card"><ul>@foreach($errors->all() as $error)<li>{{ $error }}</li>@endforeach</ul></div>@endif
|
||||
<div class="editor-card"><h2>Add product</h2><form method="post" action="{{ route('admin.download-products.store') }}" enctype="multipart/form-data">@csrf
|
||||
<label>Product name<input name="name" required maxlength="150"></label><label>Description<textarea name="description" rows="3"></textarea></label><label>Version<input name="version"></label><label>Platform<input name="platform" placeholder="macOS, Windows, Linux…"></label><label>Download file<input type="file" name="package" required></label><label><input type="checkbox" name="is_published" value="1"> Publish immediately</label><p><button class="btn btn-primary">Add product</button></p></form></div>
|
||||
@foreach($products as $product)
|
||||
<div class="editor-card" style="margin-top:20px"><h2>{{ $product->name }}</h2><p>{{ $product->download_count }} downloads · {{ $product->formatted_size }} · {{ $product->is_published ? 'Published' : 'Draft' }}</p><form method="post" action="{{ route('admin.download-products.update',$product) }}" enctype="multipart/form-data">@csrf @method('PUT')
|
||||
<label>Product name<input name="name" value="{{ $product->name }}" required></label><label>Description<textarea name="description" rows="3">{{ $product->description }}</textarea></label><label>Version<input name="version" value="{{ $product->version }}"></label><label>Platform<input name="platform" value="{{ $product->platform }}"></label><label>Replace file (optional)<input type="file" name="package"></label><label><input type="checkbox" name="is_published" value="1" @checked($product->is_published)> Published</label><p><button class="btn btn-primary">Save changes</button></p></form><form method="post" action="{{ route('admin.download-products.destroy',$product) }}" onsubmit="return confirm('Delete this product and its file?')">@csrf @method('DELETE')<button class="danger-outline">Delete product</button></form></div>
|
||||
@endforeach
|
||||
<div class="distribution-admin">
|
||||
<section class="portal-header distribution-header"><div><span class="eyebrow">Distribution / Product management</span><h1>Download products</h1><p class="lead compact">Manage installers, releases and publication status in one place.</p></div><div class="distribution-header-actions"><a class="btn btn-secondary" href="{{ route('release') }}" target="_blank" rel="noopener">View public downloads ↗</a><a class="btn btn-secondary" href="{{ route('admin.releases.index') }}">Releases</a></div></section>
|
||||
@if(session('status'))<div class="distribution-notice" role="status">{{ session('status') }}</div>@endif
|
||||
@if($errors->any())<div class="distribution-errors" role="alert"><strong>Please correct the following:</strong><ul>@foreach($errors->all() as $error)<li>{{ $error }}</li>@endforeach</ul></div>@endif
|
||||
<div class="distribution-summary"><div><span>Total products</span><strong>{{ $products->count() }}</strong></div><div><span>Published</span><strong>{{ $products->where('is_published', true)->count() }}</strong></div><div><span>Drafts</span><strong>{{ $products->where('is_published', false)->count() }}</strong></div><div><span>Total downloads</span><strong>{{ number_format($products->sum('download_count')) }}</strong></div></div>
|
||||
<section class="admin-table-card distribution-table"><div class="admin-table-title"><div><h2>Product catalogue</h2><p>Publish or unpublish products instantly, or edit their details.</p></div><a class="btn btn-primary" href="#new-product">+ Add product</a></div><div class="table-scroll"><table class="pro-table"><thead><tr><th>Product</th><th>Version / Platform</th><th>Downloads</th><th>Status</th><th style="text-align:right">Actions</th></tr></thead><tbody>
|
||||
@forelse($products as $product)<tr><td><strong>{{ $product->name }}</strong><small>{{ \Illuminate\Support\Str::limit($product->description ?: $product->original_filename, 70) }}</small></td><td><strong>{{ $product->version ?: '—' }}</strong><small>{{ $product->platform ?: 'Unspecified' }} · {{ $product->formatted_size }}</small></td><td>{{ number_format($product->download_count) }}</td><td><span class="status-chip {{ $product->is_published ? 'success' : 'muted' }}">{{ $product->is_published ? 'Published' : 'Draft' }}</span></td><td><div class="distribution-row-actions"><a href="#edit-product-{{ $product->id }}" class="dist-action">Edit</a><form method="post" action="{{ route('admin.download-products.publication', $product) }}">@csrf @method('PATCH')<input type="hidden" name="is_published" value="{{ $product->is_published ? '0' : '1' }}"><button type="submit" class="dist-action {{ $product->is_published ? 'dist-unpublish' : 'dist-publish' }}">{{ $product->is_published ? 'Unpublish' : 'Publish' }}</button></form></div></td></tr>
|
||||
@empty<tr><td colspan="5" class="empty-cell">No additional products yet. Add your first installer below.</td></tr>@endforelse
|
||||
</tbody></table></div></section>
|
||||
<details class="distribution-panel" id="new-product" @if($errors->any() && !old('_method')) open @endif><summary><span><strong>Add a new product</strong><small>Upload an installer and choose whether to publish it.</small></span><span class="dist-chevron">+</span></summary><form class="distribution-form" method="post" action="{{ route('admin.download-products.store') }}" enctype="multipart/form-data">@csrf<div class="form-grid"><label>Product name<input name="name" value="{{ old('name') }}" required maxlength="150" placeholder="e.g. SonarDesk CLI"></label><label>Version<input name="version" value="{{ old('version') }}" maxlength="80" placeholder="e.g. 2.1.0"></label><label>Platform<input name="platform" value="{{ old('platform') }}" maxlength="120" placeholder="macOS, Windows, Linux…"></label></div><label>Description<textarea name="description" rows="3" maxlength="3000" placeholder="Describe what this product does">{{ old('description') }}</textarea></label><label class="distribution-file">Installer / package <small>Maximum 1 GB</small><input type="file" name="package" required></label><label class="distribution-check"><input type="checkbox" name="is_published" value="1" @checked(old('is_published'))><span><strong>Publish immediately</strong><small>Make this download available on the public page.</small></span></label><button class="btn btn-primary" type="submit">Add product</button></form></details>
|
||||
@foreach($products as $product)<details class="distribution-panel" id="edit-product-{{ $product->id }}"><summary><span><strong>Edit {{ $product->name }}</strong><small>{{ $product->original_filename }} · {{ $product->formatted_size }}</small></span><span class="dist-chevron">+</span></summary><form class="distribution-form" method="post" action="{{ route('admin.download-products.update',$product) }}" enctype="multipart/form-data">@csrf @method('PUT')<div class="form-grid"><label>Product name<input name="name" value="{{ $product->name }}" required maxlength="150"></label><label>Version<input name="version" value="{{ $product->version }}" maxlength="80"></label><label>Platform<input name="platform" value="{{ $product->platform }}" maxlength="120"></label></div><label>Description<textarea name="description" rows="3" maxlength="3000">{{ $product->description }}</textarea></label><label class="distribution-file">Replace package (optional)<small>Current: {{ $product->original_filename }} · Maximum 1 GB</small><input type="file" name="package"></label><label class="distribution-check"><input type="checkbox" name="is_published" value="1" @checked($product->is_published)><span><strong>Published</strong><small>Untick to save this product as a draft.</small></span></label><button class="btn btn-primary" type="submit">Save changes</button></form><form class="distribution-delete" method="post" action="{{ route('admin.download-products.destroy',$product) }}" onsubmit="return confirm('Permanently delete this product and its installer?')">@csrf @method('DELETE')<button type="submit" class="danger-outline">Delete product</button></form></details>@endforeach
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
@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"><section id="release-notes" class="release-notes-panel">@if($latest)<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><div class="checksum-box"><span>SHA-256</span><code>{{ $latest->sha256 }}</code></div>@endif</section><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>
|
||||
<div class="download-shell download-content"><section id="release-notes" class="release-notes-panel">@if($latest)<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>@endif</section><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><div class="distribution-product-icon" aria-hidden="true">↓</div><h3>{{ $product->name }}</h3><p>{{ $product->description ?: 'Download the latest available package.' }}</p><div class="distribution-product-footer"><span>{{ $product->formatted_size }}</span><a class="btn btn-primary" href="{{ route('download.product',$product) }}" aria-label="Download {{ $product->name }}">Download →</a></div></article>@endforeach</div></div></section>
|
||||
@endif
|
||||
<section class="release-history"><div class="download-shell"><div class="section-heading"><span class="eyebrow">More downloads</span><h2>Other products</h2><p>Explore our other available software and downloads.</p></div><div class="release-history-list">@foreach($products as $product)<article><div><strong>{{ $product->name }}@if($product->version) {{ $product->version }}@endif</strong><span>{{ $product->description }}</span>@if($product->platform)<span>{{ $product->platform }}</span>@endif</div><div><span>{{ $product->formatted_size }}</span><a href="{{ route('download.product',$product) }}">Download</a></div></article>@endforeach</div></div></section>
|
||||
@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>
|
||||
|
||||
@@ -198,6 +198,10 @@
|
||||
.home-download-showcase{display:grid;grid-template-columns:1.25fr .75fr;gap:36px;align-items:center;margin:0 0 64px;padding:38px;background:linear-gradient(135deg,#f8fafc,#eff6ff);border:1px solid #dbeafe;border-radius:22px}.home-download-copy h2{font-size:38px;letter-spacing:-.035em;margin:7px 0 10px}.home-download-copy p{color:#667085;font-size:16px;max-width:680px}.home-download-meta{background:#0b1220;color:#fff;border-radius:16px;padding:24px;box-shadow:0 18px 40px rgba(15,23,42,.16)}.home-download-meta>span{display:block;color:#93c5fd;text-transform:uppercase;font-size:9px;font-weight:900;letter-spacing:.12em}.home-download-meta>strong{display:block;font-size:24px;margin:7px 0 3px}.home-download-meta>small{color:#94a3b8}.home-download-meta>div{margin-top:20px;padding-top:16px;border-top:1px solid rgba(255,255,255,.1)}.home-download-meta b,.home-download-meta code{display:block}.home-download-meta b{font-size:9px;color:#64748b;letter-spacing:.1em}.home-download-meta code{font-size:10px;color:#cbd5e1;margin-top:5px}@media(max-width:760px){.home-download-showcase{grid-template-columns:1fr;padding:24px}}
|
||||
|
||||
.seo-admin-form{display:grid;gap:18px}.seo-section{padding:28px}.seo-section h2{margin:4px 0 4px;font-size:22px;letter-spacing:-.02em}.seo-section-head{display:flex;justify-content:space-between;align-items:flex-start;gap:20px;padding-bottom:20px;margin-bottom:22px;border-bottom:1px solid var(--line)}.seo-section-head p{margin:0;color:var(--muted);max-width:680px}.seo-badge{display:inline-flex;align-items:center;padding:6px 10px;border-radius:999px;background:var(--blue-soft);color:var(--blue-dark);font-size:11px;font-weight:850;text-transform:uppercase;letter-spacing:.08em;white-space:nowrap}.seo-badge.success{background:var(--green-soft);color:var(--green)}.seo-dns-callout{display:grid;gap:5px;margin-bottom:22px;padding:16px 18px;border:1px solid #bfdbfe;border-radius:12px;background:#eff6ff;color:#1e3a8a}.seo-dns-callout span{color:#475569}.seo-dns-callout code{font-weight:800}.seo-savebar{position:sticky;bottom:18px;z-index:20;display:flex;align-items:center;justify-content:space-between;gap:18px;padding:15px 18px;border:1px solid var(--line);border-radius:14px;background:rgba(255,255,255,.96);backdrop-filter:blur(14px);box-shadow:0 14px 38px rgba(15,23,42,.14)}.seo-savebar strong,.seo-savebar span{display:block}.seo-savebar span{font-size:12px;color:var(--muted);margin-top:2px}.seo-preview{border:1px solid var(--line);border-radius:12px;padding:18px;background:#fff}.seo-preview-label{font-size:10px;font-weight:850;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);margin-bottom:10px}.seo-preview-title{color:#1a0dab;font-size:19px;line-height:1.3}.seo-preview-url{color:#188038;font-size:12px;margin:4px 0}.seo-preview-description{color:#4d5156;font-size:13px;line-height:1.45}@media(max-width:700px){.seo-section-head,.seo-savebar{align-items:stretch;flex-direction:column}.seo-savebar .btn{width:100%}}
|
||||
|
||||
/* Download catalogue and distribution admin */
|
||||
.distribution-admin{max-width:1200px;margin:auto;padding-bottom:55px}.distribution-header{display:flex;justify-content:space-between;align-items:end;gap:24px}.distribution-header-actions{display:flex;gap:10px;flex-wrap:wrap}.distribution-summary{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin:25px 0}.distribution-summary>div{background:#fff;border:1px solid #e4e7ec;border-radius:14px;padding:18px 20px}.distribution-summary span,.distribution-summary strong{display:block}.distribution-summary span{font-size:12px;color:#667085}.distribution-summary strong{font-size:28px;color:#101828;margin-top:5px}.distribution-notice,.distribution-errors{padding:14px 18px;border-radius:10px;margin:16px 0;background:#ecfdf3;border:1px solid #a6f4c5;color:#067647}.distribution-errors{background:#fef3f2;border-color:#fecdca;color:#b42318}.distribution-table{margin-bottom:22px}.distribution-row-actions{display:flex;gap:14px;justify-content:flex-end;align-items:center;white-space:nowrap}.distribution-row-actions form{margin:0}.dist-action{background:none;border:0;padding:4px 0;color:#245bc6;font-weight:750;font-size:13px;cursor:pointer;text-decoration:none}.dist-unpublish{color:#b54708}.dist-publish{color:#067647}.distribution-panel{background:#fff;border:1px solid #e4e7ec;border-radius:14px;margin:12px 0;overflow:hidden}.distribution-panel>summary{list-style:none;display:flex;justify-content:space-between;align-items:center;gap:12px;cursor:pointer;padding:19px 24px}.distribution-panel>summary::-webkit-details-marker{display:none}.distribution-panel>summary strong,.distribution-panel>summary small{display:block}.distribution-panel>summary strong{font-size:16px;color:#101828}.distribution-panel>summary small{font-size:12px;color:#667085;margin-top:4px}.dist-chevron{font-size:22px;color:#667085}.distribution-panel[open] .dist-chevron{transform:rotate(45deg)}.distribution-form{padding:24px;border-top:1px solid #eef2f6;display:grid;gap:16px}.distribution-form label{display:grid;gap:6px;font-size:13px;font-weight:750;color:#344054}.distribution-form input:not([type=checkbox]),.distribution-form textarea{width:100%;border:1px solid #d0d5dd;border-radius:9px;padding:11px 12px;background:#fff;color:#101828;font:inherit}.distribution-form .form-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.distribution-file{border:1px dashed #cbd5e1;border-radius:12px;padding:16px;background:#f8fafc}.distribution-file small{color:#667085;font-weight:400}.distribution-file input{background:transparent!important;border:0!important;padding-left:0!important}.distribution-check{display:flex!important;align-items:center;gap:12px!important;padding:12px 0}.distribution-check input{width:18px;height:18px;flex:none}.distribution-check strong,.distribution-check small{display:block}.distribution-check small{font-weight:400;color:#667085;margin-top:3px}.distribution-form>.btn{justify-self:start}.distribution-delete{padding:0 24px 22px}.distribution-catalogue{background:#f6f8fc;padding:76px 0;border-top:1px solid #e4e7ec}.distribution-product-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px;margin-top:28px}.distribution-product-card{background:#fff;border:1px solid #e4e7ec;border-radius:18px;padding:26px;display:flex;flex-direction:column;box-shadow:0 8px 30px rgba(16,24,40,.04)}.distribution-product-top,.distribution-product-footer{display:flex;justify-content:space-between;align-items:center;gap:12px}.distribution-platform{background:#eff6ff;color:#175cd3;border-radius:20px;padding:5px 10px;font-size:11px;font-weight:800}.distribution-version{font-size:12px;color:#667085}.distribution-product-icon{display:grid;place-items:center;width:48px;height:48px;background:#0b1730;color:#e8bc66;border-radius:12px;font-size:23px;margin:26px 0 12px}.distribution-product-card h3{font-size:22px;letter-spacing:-.03em;margin:0 0 8px;color:#101828}.distribution-product-card p{font-size:14px;line-height:1.6;color:#667085;flex:1;margin:0 0 28px}.distribution-product-footer{border-top:1px solid #eef2f6;padding-top:20px}.distribution-product-footer>span{font-size:12px;color:#667085}.checksum-box summary{cursor:pointer;font-size:12px;font-weight:750;color:#475467}.checksum-box code{display:block;margin-top:12px}.download-primary{background:#e8bc66!important;color:#101828!important}.download-icon{background:#101828!important;color:#e8bc66!important}
|
||||
@media(max-width:900px){.distribution-product-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.distribution-header{align-items:start;flex-direction:column}}@media(max-width:640px){.distribution-product-grid,.distribution-summary{grid-template-columns:1fr}.distribution-form .form-grid{grid-template-columns:1fr}.distribution-row-actions{flex-wrap:wrap}.distribution-header-actions{width:100%}.distribution-table .pro-table{min-width:730px}}
|
||||
</style>
|
||||
@stack('head')
|
||||
</head>
|
||||
|
||||
@@ -79,6 +79,7 @@ Route::middleware(['auth', 'verified', AdminOnly::class])->prefix('admin')->name
|
||||
Route::get('/download-products', [DownloadProductController::class, 'index'])->name('download-products.index');
|
||||
Route::post('/download-products', [DownloadProductController::class, 'store'])->name('download-products.store');
|
||||
Route::put('/download-products/{product}', [DownloadProductController::class, 'update'])->name('download-products.update');
|
||||
Route::patch('/download-products/{product}/publication', [DownloadProductController::class, 'publication'])->name('download-products.publication');
|
||||
Route::delete('/download-products/{product}', [DownloadProductController::class, 'destroy'])->name('download-products.destroy');
|
||||
Route::get('/releases', [AdminReleaseController::class, 'index'])->name('releases.index');
|
||||
Route::get('/releases/create', [AdminReleaseController::class, 'create'])->name('releases.create');
|
||||
|
||||
Reference in New Issue
Block a user