feat: add dedicated model photo separate from avatar
Adds a `photo` field to the users table (and a migration) that serves as a dedicated profile/card image for models. This is now used in model cards and on the model single page, while `avatar` is reserved for comments, article authors, and the user profile page. - DB: `photo` column on `users` with FK to `files` - GraphQL: exposed on ModelType, UserType, AdminUserDetailType; photoId arg on adminUpdateUser - Services: photo field in MODELS_QUERY, MODEL_BY_SLUG_QUERY, ADMIN_GET/UPDATE_USER - Frontend: model cards and single page use `photo ?? avatar` fallback - Admin: model photo upload section in user edit page Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
let artistName = $state(data.user.artist_name ?? "");
|
||||
let avatarId = $state<string | null>(data.user.avatar ?? null);
|
||||
let bannerId = $state<string | null>(data.user.banner ?? null);
|
||||
let photoId = $state<string | null>(data.user.photo ?? null);
|
||||
let isAdmin = $state(data.user.is_admin ?? false);
|
||||
let saving = $state(false);
|
||||
|
||||
@@ -52,6 +53,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function handlePhotoUpload2(files: File[]) {
|
||||
const file = files[0];
|
||||
if (!file) return;
|
||||
const fd = new FormData();
|
||||
fd.append("file", file);
|
||||
try {
|
||||
const res = await uploadFile(fd);
|
||||
photoId = res.id;
|
||||
toast.success($_("admin.user_edit.model_photo_uploaded"));
|
||||
} catch {
|
||||
toast.error($_("admin.user_edit.model_photo_failed"));
|
||||
}
|
||||
}
|
||||
|
||||
async function handlePhotoUpload(files: File[]) {
|
||||
for (const file of files) {
|
||||
const fd = new FormData();
|
||||
@@ -88,6 +103,7 @@
|
||||
artistName: artistName || undefined,
|
||||
avatarId: avatarId || undefined,
|
||||
bannerId: bannerId || undefined,
|
||||
photoId: photoId || undefined,
|
||||
isAdmin,
|
||||
});
|
||||
toast.success($_("admin.user_edit.save_success"));
|
||||
@@ -158,6 +174,20 @@
|
||||
<FileDropZone accept="image/*" maxFileSize={10 * MEGABYTE} onUpload={handleBannerUpload} />
|
||||
</div>
|
||||
|
||||
<!-- Model photo (used in cards & model page, not for avatar/comments) -->
|
||||
<div class="space-y-1.5">
|
||||
<Label>{$_("admin.user_edit.model_photo")}</Label>
|
||||
<p class="text-xs text-muted-foreground">{$_("admin.user_edit.model_photo_hint")}</p>
|
||||
{#if photoId}
|
||||
<img
|
||||
src={getAssetUrl(photoId, "preview")}
|
||||
alt=""
|
||||
class="w-full h-48 rounded object-cover mb-2"
|
||||
/>
|
||||
{/if}
|
||||
<FileDropZone accept="image/*" maxFileSize={10 * MEGABYTE} onUpload={handlePhotoUpload2} />
|
||||
</div>
|
||||
|
||||
<!-- Admin flag -->
|
||||
<label
|
||||
class="flex items-center gap-3 rounded-lg border border-border/40 px-4 py-3 cursor-pointer hover:bg-muted/20 transition-colors"
|
||||
|
||||
Reference in New Issue
Block a user