Initial baseline: LaraBlog core with plugin commerce surface.
Captures the current working tree after theme slots, ArticleAccess, and the payment / paid-content plugins so subsequent work has a reviewable git history.
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
<x-filament-panels::page>
|
||||
<style>
|
||||
.lb-admin-card-grid {
|
||||
display: grid;
|
||||
gap: 1.25rem;
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
align-items: stretch;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.lb-admin-card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
}
|
||||
@media (min-width: 1280px) {
|
||||
.lb-admin-card-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
||||
}
|
||||
.lb-admin-card-grid > .lb-admin-card {
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.lb-admin-card-grid .fi-section {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@if (count($plugins) === 0)
|
||||
<x-filament::section>
|
||||
<x-filament::empty-state
|
||||
:heading="__('admin.pages.no_plugins')"
|
||||
icon="heroicon-o-puzzle-piece"
|
||||
/>
|
||||
</x-filament::section>
|
||||
@else
|
||||
<div class="lb-admin-card-grid">
|
||||
@foreach ($plugins as $plugin)
|
||||
<div class="lb-admin-card">
|
||||
<x-filament::section
|
||||
:heading="$plugin['title']"
|
||||
:description="$plugin['name'].' · '.__('admin.pages.version').' '.$plugin['version']"
|
||||
:icon="$plugin['enabled'] ? 'heroicon-o-check-circle' : 'heroicon-o-puzzle-piece'"
|
||||
:icon-color="$plugin['enabled'] ? 'success' : 'gray'"
|
||||
>
|
||||
<x-slot name="afterHeader">
|
||||
@if ($plugin['enabled'])
|
||||
<x-filament::badge color="success">{{ __('admin.pages.enabled') }}</x-filament::badge>
|
||||
@else
|
||||
<x-filament::badge color="gray">{{ __('admin.pages.disabled') }}</x-filament::badge>
|
||||
@endif
|
||||
</x-slot>
|
||||
|
||||
<p class="text-sm leading-6 text-gray-600 dark:text-gray-300">
|
||||
{{ $plugin['description'] }}
|
||||
</p>
|
||||
@if (! empty($plugin['requires']))
|
||||
<p class="mt-2 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ __('admin.pages.plugin_requires') }}:
|
||||
{{ implode(', ', $plugin['requires']) }}
|
||||
</p>
|
||||
@endif
|
||||
|
||||
<x-slot name="footer">
|
||||
<div class="flex flex-wrap justify-end gap-2">
|
||||
@if ($plugin['has_docs'] ?? false)
|
||||
<x-filament::button color="gray" size="sm" outlined wire:click="showDocs('{{ $plugin['name'] }}')">
|
||||
{{ __('admin.pages.plugin_docs') }}
|
||||
</x-filament::button>
|
||||
@endif
|
||||
@if ($plugin['enabled'])
|
||||
<x-filament::button color="gray" size="sm" wire:click="disable('{{ $plugin['name'] }}')">
|
||||
{{ __('admin.pages.disable') }}
|
||||
</x-filament::button>
|
||||
@else
|
||||
<x-filament::button size="sm" wire:click="enable('{{ $plugin['name'] }}')">
|
||||
{{ __('admin.pages.enable') }}
|
||||
</x-filament::button>
|
||||
@endif
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-filament::section>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</x-filament-panels::page>
|
||||
@@ -0,0 +1,130 @@
|
||||
<x-filament-panels::page>
|
||||
<style>
|
||||
.lb-admin-card-grid {
|
||||
display: grid;
|
||||
gap: 1.25rem;
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
align-items: stretch;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.lb-admin-card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
}
|
||||
@media (min-width: 1280px) {
|
||||
.lb-admin-card-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
||||
}
|
||||
.lb-admin-card-grid > .lb-admin-card {
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.lb-admin-card-grid .fi-section {
|
||||
height: 100%;
|
||||
}
|
||||
.lb-admin-card-preview {
|
||||
overflow: hidden;
|
||||
border-radius: 0.75rem;
|
||||
background: rgba(128, 128, 128, 0.08);
|
||||
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.lb-admin-card-preview__frame {
|
||||
aspect-ratio: 16 / 10;
|
||||
}
|
||||
.lb-admin-card-preview__frame img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.lb-admin-card-preview__empty {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.875rem;
|
||||
color: rgba(128, 128, 128, 0.9);
|
||||
}
|
||||
</style>
|
||||
|
||||
@if (count($themes) === 0)
|
||||
<x-filament::section>
|
||||
<x-filament::empty-state
|
||||
:heading="__('admin.pages.no_themes')"
|
||||
icon="heroicon-o-swatch"
|
||||
/>
|
||||
</x-filament::section>
|
||||
@else
|
||||
<div class="lb-admin-card-grid">
|
||||
@foreach ($themes as $theme)
|
||||
@php
|
||||
$isActive = $theme['slug'] === $activeTheme;
|
||||
$slotColor = match ($theme['slots_status'] ?? 'undeclared') {
|
||||
'full' => 'success',
|
||||
'partial', 'mismatch' => 'warning',
|
||||
default => 'danger',
|
||||
};
|
||||
@endphp
|
||||
<div class="lb-admin-card">
|
||||
<x-filament::section
|
||||
:heading="$theme['title']"
|
||||
:description="$theme['slug'].' · '.__('admin.pages.version').' '.$theme['version']"
|
||||
:icon="$isActive ? 'heroicon-o-check-badge' : 'heroicon-o-swatch'"
|
||||
:icon-color="$isActive ? 'primary' : 'gray'"
|
||||
>
|
||||
<x-slot name="afterHeader">
|
||||
@if ($isActive)
|
||||
<x-filament::badge color="primary">{{ __('admin.pages.current') }}</x-filament::badge>
|
||||
@endif
|
||||
<x-filament::badge :color="$slotColor">
|
||||
{{ $theme['slots_label'] ?? __('admin.slots.status_undeclared') }}
|
||||
@if (($theme['slots_declared_count'] ?? 0) > 0)
|
||||
· {{ $theme['slots_declared_count'] }}
|
||||
@endif
|
||||
</x-filament::badge>
|
||||
</x-slot>
|
||||
|
||||
<div style="display:grid;gap:0.75rem">
|
||||
<div class="lb-admin-card-preview">
|
||||
<div class="lb-admin-card-preview__frame">
|
||||
@if (! empty($theme['preview']))
|
||||
<img
|
||||
src="{{ $theme['preview'] }}"
|
||||
alt="{{ $theme['title'] }} {{ __('admin.pages.preview') }}"
|
||||
>
|
||||
@else
|
||||
<div class="lb-admin-card-preview__empty">
|
||||
{{ __('admin.pages.preview') }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-sm leading-6 text-gray-600 dark:text-gray-300">
|
||||
{{ $theme['description'] }}
|
||||
</p>
|
||||
|
||||
@if (! empty($theme['slots_missing']))
|
||||
<p class="text-xs text-warning-600 dark:text-warning-400">
|
||||
{{ __('admin.messages.slots_missing_prefix') }}{{ implode(', ', array_slice($theme['slots_missing'], 0, 6)) }}{{ count($theme['slots_missing']) > 6 ? '…' : '' }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<x-slot name="footer">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<x-filament::link href="{{ url('/') }}" target="_blank" size="sm">
|
||||
{{ __('admin.pages.preview') }}
|
||||
</x-filament::link>
|
||||
@if ($isActive)
|
||||
<x-filament::badge color="success">{{ __('admin.pages.current') }}</x-filament::badge>
|
||||
@else
|
||||
<x-filament::button size="sm" wire:click="activate('{{ $theme['slug'] }}')">
|
||||
{{ __('admin.pages.activate') }}
|
||||
</x-filament::button>
|
||||
@endif
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-filament::section>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</x-filament-panels::page>
|
||||
@@ -0,0 +1,20 @@
|
||||
<x-filament-panels::page>
|
||||
<x-filament::section
|
||||
:heading="$pluginTitle"
|
||||
:description="$pluginName"
|
||||
icon="heroicon-o-puzzle-piece"
|
||||
>
|
||||
<x-slot name="afterHeader">
|
||||
@if ($enabled)
|
||||
<x-filament::badge color="success">{{ __('admin.pages.enabled') }}</x-filament::badge>
|
||||
@else
|
||||
<x-filament::badge color="gray">{{ __('admin.pages.disabled') }}</x-filament::badge>
|
||||
@endif
|
||||
</x-slot>
|
||||
|
||||
<div class="space-y-3 text-sm leading-6 text-gray-600 dark:text-gray-300">
|
||||
<p>{{ $pluginDescription }}</p>
|
||||
<p class="text-gray-500 dark:text-gray-400">{{ __('admin.pages.skeleton_note') }}</p>
|
||||
</div>
|
||||
</x-filament::section>
|
||||
</x-filament-panels::page>
|
||||
@@ -0,0 +1,4 @@
|
||||
<x-filament-panels::page>
|
||||
{{-- SiteSettings renders via Page::content() schema; this view is unused fallback. --}}
|
||||
{{ $this->content }}
|
||||
</x-filament-panels::page>
|
||||
@@ -0,0 +1,5 @@
|
||||
<div class="fi-clear-cache-button">
|
||||
{{ $this->clearCacheAction }}
|
||||
|
||||
<x-filament-actions::modals />
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/** @var \Illuminate\Support\Collection|\App\Models\Article[] $articles */
|
||||
$access = app(\App\Domain\Blog\ArticleAccess::class);
|
||||
?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>{{ $settings->site_name ?? config('app.name') }}</title>
|
||||
<link>{{ url('/') }}</link>
|
||||
<description>{{ $settings->site_description ?? '' }}</description>
|
||||
<language>{{ app()->getLocale() }}</language>
|
||||
@foreach($articles as $article)
|
||||
@php
|
||||
$decision = $access->resolve($article, null, []);
|
||||
$body = $access->publicHtml($article, $decision);
|
||||
@endphp
|
||||
<item>
|
||||
<title>{{ $article->title }}</title>
|
||||
<link>{{ url('/show-'.$article->id.'.shtml') }}</link>
|
||||
<guid isPermaLink="true">{{ url('/show-'.$article->id.'.shtml') }}</guid>
|
||||
<pubDate>{{ optional($article->published_at)->toRfc2822String() }}</pubDate>
|
||||
<description><![CDATA[{!! $body !!}]]></description>
|
||||
</item>
|
||||
@endforeach
|
||||
</channel>
|
||||
</rss>
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user