前端极简黑白重设计,并纳入客户端注册、站点设置与后台相关改动

- storefront 全站改为极简黑白配色:直角、细线分隔、卡片 hover 浅底、深色模式(跟随系统+手动切换)
- 抽出 storefront/partials/card 复用卡片
- 一并提交此前暂存的客户端注册 API、站点设置、后台页面与测试

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
浪子
2026-09-22 08:35:49 +08:00
parent 62cffc6f5f
commit 04a2034975
41 changed files with 3447 additions and 658 deletions
+90 -6
View File
@@ -7,6 +7,8 @@ use App\Models\Package;
use App\Models\Version;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
class AdminPackageService
{
@@ -114,6 +116,19 @@ class AdminPackageService
});
}
public function deletePackage(Package $package): void
{
$storageDir = storage_path('app/packages/' . $package->type . '/' . $package->slug);
DB::transaction(function () use ($package) {
$package->delete();
});
if (is_dir($storageDir)) {
File::deleteDirectory($storageDir);
}
}
public function refreshLatestVersion(Package $package): void
{
$latestStable = $package->versions()
@@ -141,19 +156,88 @@ class AdminPackageService
private function syncCategories(Package $package, array $categorySlugs): void
{
$categorySlugs = array_values(array_unique(array_filter(array_map('strval', $categorySlugs))));
$categorySlugs = collect($categorySlugs)
->map(fn ($item) => trim((string) $item))
->filter()
->unique(fn (string $item) => mb_strtolower($item, 'UTF-8'))
->values()
->all();
if (empty($categorySlugs)) {
$package->categories()->sync([]);
return;
}
$categoryIds = Category::query()
$categories = Category::query()
->where('type', $package->type)
->whereIn('slug', $categorySlugs)
->pluck('id')
->all();
->get(['id', 'type', 'slug', 'name']);
$package->categories()->sync($categoryIds);
$categoryIds = [];
foreach ($categorySlugs as $token) {
$normalizedToken = mb_strtolower($token, 'UTF-8');
$existing = $categories->first(function (Category $category) use ($token, $normalizedToken) {
return $category->name === $token
|| mb_strtolower($category->slug, 'UTF-8') === $normalizedToken
|| mb_strtolower($category->name, 'UTF-8') === $normalizedToken;
});
if ($existing) {
$categoryIds[] = $existing->id;
continue;
}
$slug = $this->generateCategorySlug($token, $categories);
$category = Category::query()->create([
'type' => $package->type,
'slug' => $slug,
'name' => $this->generateCategoryName($token),
'description' => '',
'sort_order' => 0,
]);
$categories->push($category);
$categoryIds[] = $category->id;
}
$package->categories()->sync(array_values(array_unique($categoryIds)));
}
private function generateCategorySlug(string $token, $categories): string
{
$base = (string) Str::of($token)
->trim()
->replace('_', '-')
->replaceMatches('/\s+/u', '-')
->replaceMatches('/[^\pL\pN-]+/u', '-')
->replaceMatches('/-+/u', '-')
->lower()
->trim('-');
if ($base === '') {
$base = 'category';
}
$slug = $base;
$suffix = 2;
while ($categories->contains(fn (Category $category) => mb_strtolower($category->slug, 'UTF-8') === mb_strtolower($slug, 'UTF-8'))) {
$slug = $base . '-' . $suffix;
$suffix++;
}
return $slug;
}
private function generateCategoryName(string $token): string
{
if (preg_match('/^[a-z0-9_-]+$/i', $token) === 1) {
return (string) Str::of($token)
->replace(['-', '_'], ' ')
->title();
}
return trim($token);
}
}