Implement creator studio and upload updates

This commit is contained in:
2026-04-04 10:12:02 +02:00
parent 1da7d3bf88
commit 0b216b7ecd
15107 changed files with 31206 additions and 626514 deletions

View File

@@ -51,7 +51,7 @@ function SidebarContent({ isActive, onNavigate }) {
)
}
function SectionSidebar({ sections = [], activeSection, onSectionChange }) {
function SectionSidebar({ sections = [], activeSection, onSectionChange, dirtyMap = {} }) {
return (
<>
<div className="mb-6">
@@ -61,19 +61,30 @@ function SectionSidebar({ sections = [], activeSection, onSectionChange }) {
<nav className="space-y-1 flex-1">
{sections.map((section) => {
const active = section.key === activeSection
const isDirty = !!dirtyMap[section.key]
return (
<button
key={section.key}
type="button"
onClick={() => onSectionChange?.(section.key)}
className={`w-full flex items-center gap-3 px-4 py-2.5 rounded-xl text-sm font-medium transition-all duration-200 ${
className={`group relative w-full flex items-center gap-3 px-4 py-2.5 rounded-xl text-sm font-medium transition-all duration-200 ${
active
? 'bg-accent/20 text-accent shadow-sm shadow-accent/10'
: 'text-slate-400 hover:text-white hover:bg-white/5'
}`}
>
{section.icon ? <i className={`${section.icon} w-5 text-center text-base`} /> : null}
<span>{section.label}</span>
<span className="flex flex-col items-start gap-0.5">
<span className="flex items-center gap-2">
{section.label}
{isDirty && (
<span className="inline-block h-1.5 w-1.5 rounded-full bg-amber-400 animate-pulse" title="Unsaved changes" />
)}
</span>
{section.description && !active ? (
<span className="text-[11px] font-normal text-slate-500 leading-tight">{section.description}</span>
) : null}
</span>
</button>
)
})}
@@ -82,7 +93,7 @@ function SectionSidebar({ sections = [], activeSection, onSectionChange }) {
)
}
export default function SettingsLayout({ children, title, sections = null, activeSection = null, onSectionChange = null }) {
export default function SettingsLayout({ children, title, sections = null, activeSection = null, onSectionChange = null, dirtyMap = {} }) {
const { url } = usePage()
const [mobileOpen, setMobileOpen] = useState(false)
const hasSectionMode = Array.isArray(sections) && sections.length > 0 && typeof onSectionChange === 'function'
@@ -98,20 +109,27 @@ export default function SettingsLayout({ children, title, sections = null, activ
{/* Mobile top bar */}
<div className="lg:hidden px-4 py-3 border-b border-white/10 bg-nova-900/80 backdrop-blur-xl sticky top-16 z-30">
{hasSectionMode ? (
<label className="block">
<span className="sr-only">Settings section</span>
<select
className="w-full rounded-xl border border-white/10 bg-white/5 px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
value={activeSection || ''}
onChange={(e) => onSectionChange(e.target.value)}
>
{sections.map((section) => (
<option key={section.key} value={section.key} className="bg-nova-900 text-white">
{section.label}
</option>
))}
</select>
</label>
<div className="flex items-center gap-2">
<label className="block flex-1">
<span className="sr-only">Settings section</span>
<select
className="w-full rounded-xl border border-white/10 bg-white/5 px-3 py-2.5 text-sm text-white focus:outline-none focus:ring-2 focus:ring-accent/50 appearance-none"
value={activeSection || ''}
onChange={(e) => onSectionChange(e.target.value)}
>
{sections.map((section) => (
<option key={section.key} value={section.key} className="bg-nova-900 text-white">
{section.label}{dirtyMap[section.key] ? ' •' : ''}
</option>
))}
</select>
</label>
{dirtyMap[activeSection] ? (
<span className="inline-flex items-center rounded-full bg-amber-400/15 px-2 py-1 text-[10px] font-semibold text-amber-300 border border-amber-400/20">
Unsaved
</span>
) : null}
</div>
) : (
<div className="flex items-center justify-between">
<h1 className="text-lg font-bold text-white">Settings</h1>
@@ -142,7 +160,7 @@ export default function SettingsLayout({ children, title, sections = null, activ
{/* Desktop sidebar */}
<aside className="hidden lg:flex flex-col w-64 min-h-[calc(100vh-4rem)] border-r border-white/10 bg-nova-900/60 backdrop-blur-xl p-4 pt-6 sticky top-16 self-start">
{hasSectionMode ? (
<SectionSidebar sections={sections} activeSection={activeSection} onSectionChange={onSectionChange} />
<SectionSidebar sections={sections} activeSection={activeSection} onSectionChange={onSectionChange} dirtyMap={dirtyMap} />
) : (
<SidebarContent isActive={isActive} />
)}