Files
SkinbaseNova/resources/js/components/upload/UploadSidebar.jsx
Gregor Klevze a875203482 feat: Nova UI component library + Studio dropdown/picker polish
- Add Nova UI library: Button, TextInput, Textarea, FormField, Select,
  NovaSelect, Checkbox, Radio/RadioGroup, Toggle, DatePicker,
  DateRangePicker, Modal + barrel index.js
- Replace all native <select> in Studio with NovaSelect (StudioFilters,
  StudioToolbar, BulkActionsBar) including frosted-glass portal and
  category group headers
- Replace native checkboxes in StudioGridCard, StudioTable, UploadSidebar,
  UploadWizard, Upload/Index with custom Checkbox component
- Add nova-scrollbar CSS utility (thin 4px, semi-transparent)
- Fix portal position drift: use viewport-relative coords (no scrollY offset)
  for NovaSelect, DatePicker and DateRangePicker
- Close portals on external scroll instead of remeasuring
- Improve hover highlight visibility in NovaSelect (bg-white/[0.13])
- Move search icon to right side in NovaSelect dropdown
- Reduce Studio layout top spacing (py-6 -> pt-4 pb-8)
- Add StudioCheckbox and SquareCheckbox backward-compat shims
- Add sync.sh rsync deploy script
2026-03-01 10:41:43 +01:00

95 lines
3.9 KiB
JavaScript

import React from 'react'
import TagInput from '../tags/TagInput'
import Checkbox from '../../Components/ui/Checkbox'
export default function UploadSidebar({
title = 'Artwork details',
description = 'Complete metadata before publishing',
showHeader = true,
metadata,
suggestedTags = [],
errors = {},
onChangeTitle,
onChangeTags,
onChangeDescription,
onToggleRights,
}) {
return (
<aside className="rounded-2xl border border-white/7 bg-gradient-to-br from-slate-900/55 to-slate-900/35 p-6 shadow-[0_10px_24px_rgba(0,0,0,0.22)] sm:p-7">
{showHeader && (
<div className="mb-5 rounded-xl border border-white/8 bg-white/[0.04] p-4">
<h3 className="text-lg font-semibold text-white">{title}</h3>
<p className="mt-1 text-sm text-white/65">{description}</p>
</div>
)}
<div className="space-y-5">
<section className="rounded-xl border border-white/10 bg-white/[0.03] p-4">
<div className="mb-3">
<h4 className="text-sm font-semibold text-white">Basics</h4>
<p className="mt-1 text-xs text-white/60">Add a clear title and short description.</p>
</div>
<div className="space-y-4">
<label className="block">
<span className="text-sm font-medium text-white/90">Title <span className="text-red-300">*</span></span>
<input
id="upload-sidebar-title"
value={metadata.title}
onChange={(event) => onChangeTitle?.(event.target.value)}
className={`mt-2 w-full rounded-xl border bg-white/10 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 ${errors.title ? 'border-red-300/60 focus:ring-red-300/70' : 'border-white/15 focus:ring-sky-300/70'}`}
placeholder="Give your artwork a clear title"
/>
{errors.title && <p className="mt-1 text-xs text-red-200">{errors.title}</p>}
</label>
<label className="block">
<span className="text-sm font-medium text-white/90">Description</span>
<textarea
id="upload-sidebar-description"
value={metadata.description}
onChange={(event) => onChangeDescription?.(event.target.value)}
rows={5}
className="mt-2 w-full rounded-xl border border-white/15 bg-white/10 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-sky-300/70"
placeholder="Describe your artwork (Markdown supported)."
/>
</label>
</div>
</section>
<section className="rounded-xl border border-white/10 bg-white/[0.03] p-4">
<div className="mb-3">
<h4 className="text-sm font-semibold text-white">Tags</h4>
<p className="mt-1 text-xs text-white/60">Use keywords people would search for. Press Enter, comma, or Tab to add a tag.</p>
</div>
<TagInput
value={metadata.tags}
onChange={(nextTags) => onChangeTags?.(nextTags)}
suggestedTags={suggestedTags}
maxTags={15}
minLength={2}
maxLength={32}
searchEndpoint="/api/tags/search"
popularEndpoint="/api/tags/popular"
placeholder="Type tags (e.g. cyberpunk, city)"
/>
</section>
<section className="rounded-xl border border-white/10 bg-white/[0.03] p-4">
<Checkbox
id="upload-sidebar-rights"
checked={Boolean(metadata.rightsAccepted)}
onChange={(event) => onToggleRights?.(event.target.checked)}
variant="emerald"
size={20}
label="I confirm I own the rights to this content."
hint="Required before publishing."
error={errors.rights}
required
/>
</section>
</div>
</aside>
)
}