minor fixes

This commit is contained in:
2026-04-09 08:50:36 +02:00
parent 23d363a50c
commit a2457f4e49
75 changed files with 3848 additions and 387 deletions

View File

@@ -7,6 +7,7 @@ import Button from '../../components/ui/Button'
import Modal from '../../components/ui/Modal'
import FormField from '../../components/ui/FormField'
import Toggle from '../../components/ui/Toggle'
import NovaSelect from '../../components/ui/NovaSelect'
import TagPicker from '../../components/tags/TagPicker'
import SchedulePublishPicker from '../../components/upload/SchedulePublishPicker'
@@ -286,6 +287,29 @@ export default function StudioArtworkEdit() {
selectedRoot?.name || 'No root category',
subCategoryId ? subCategories.find((item) => item.id === subCategoryId)?.name : null,
].filter(Boolean)
const publishingIdentityOptions = useMemo(() => {
const personalOption = {
value: '',
label: 'Personal profile',
icon: <i className="fa-solid fa-user text-[11px] text-sky-200" aria-hidden="true" />,
contextLabel: 'Publish under your own creator identity',
}
const groupItems = groupOptions.map((group) => ({
value: group.slug,
label: group.name,
icon: <i className="fa-solid fa-users text-[11px] text-violet-200" aria-hidden="true" />,
contextLabel: 'Publish under the shared group identity',
}))
return [personalOption, ...groupItems]
}, [groupOptions])
const primaryAuthorOptions = useMemo(() => currentContributorOptions.map((user) => ({
value: Number(user.id),
label: user.name || user.username,
username: user.username,
avatarUrl: user.avatar_url || null,
})), [currentContributorOptions])
// ── Handlers ───────────────────────────────────────────────────────────────
const handleContentTypeChange = (id) => {
@@ -1172,37 +1196,60 @@ export default function StudioArtworkEdit() {
</span>
</div>
<label className="block">
<span className="text-sm font-medium text-white/90">Publishing identity</span>
<select
value={groupSlug}
onChange={(event) => setGroupSlug(event.target.value)}
className="mt-2 w-full rounded-xl border border-white/15 bg-black/20 px-3 py-3 text-sm text-white outline-none transition focus:border-sky-300/40"
>
<option value="">Personal profile</option>
{groupOptions.map((group) => (
<option key={group.slug} value={group.slug}>{group.name}</option>
))}
</select>
{errors.group?.[0] ? <p className="mt-2 text-xs text-red-400">{errors.group[0]}</p> : null}
</label>
<NovaSelect
label="Publishing identity"
value={groupSlug || ''}
onChange={(nextValue) => setGroupSlug(String(nextValue || ''))}
options={publishingIdentityOptions}
searchable={false}
placeholder="Choose publishing identity"
error={errors.group?.[0]}
hint={selectedGroupOption
? 'The artwork will be publicly published under the selected group while authorship stays editable below.'
: 'Personal publishing keeps the artwork under your own creator profile.'}
className="mt-2 bg-black/20"
renderOption={(option) => (
<span className="flex min-w-0 items-center gap-3">
<span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-full border border-white/10 bg-white/[0.04]">
{option.icon}
</span>
<span className="min-w-0">
<span className="block truncate font-medium text-white">{option.label}</span>
<span className="block truncate text-[11px] text-slate-500">{option.contextLabel}</span>
</span>
</span>
)}
/>
{groupSlug ? (
<div className="grid gap-5 lg:grid-cols-[minmax(0,0.95fr)_minmax(0,1.05fr)]">
<div>
<label className="block">
<span className="text-sm font-medium text-white/90">Primary author</span>
<select
value={primaryAuthorUserId || ''}
onChange={(event) => setPrimaryAuthorUserId(event.target.value ? Number(event.target.value) : null)}
className="mt-2 w-full rounded-xl border border-white/15 bg-black/20 px-3 py-3 text-sm text-white outline-none transition focus:border-sky-300/40"
>
{currentContributorOptions.map((user) => (
<option key={user.id} value={user.id}>{user.name || user.username}</option>
))}
</select>
</label>
{errors.primary_author_user_id?.[0] ? <p className="mt-2 text-xs text-red-400">{errors.primary_author_user_id[0]}</p> : <p className="mt-2 text-xs text-slate-400">Primary author remains the lead creator shown on the public artwork page.</p>}
<NovaSelect
label="Primary author"
value={primaryAuthorUserId || null}
onChange={(nextValue) => setPrimaryAuthorUserId(nextValue ? Number(nextValue) : null)}
options={primaryAuthorOptions}
placeholder="Choose primary author"
searchable={primaryAuthorOptions.length > 6}
error={errors.primary_author_user_id?.[0]}
hint="Primary author remains the lead creator shown on the public artwork page."
className="mt-2 bg-black/20"
renderOption={(option) => (
<span className="flex min-w-0 items-center gap-3">
{option.avatarUrl ? (
<img src={option.avatarUrl} alt="" className="h-7 w-7 shrink-0 rounded-full object-cover" />
) : (
<span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-full border border-white/10 bg-white/[0.04] text-slate-400">
<i className="fa-solid fa-user text-[11px]" aria-hidden="true" />
</span>
)}
<span className="min-w-0">
<span className="block truncate font-medium text-white">{option.label}</span>
{option.username ? <span className="block truncate text-[11px] text-slate-500">@{option.username}</span> : null}
</span>
</span>
)}
/>
</div>
<div>