diff --git a/src/builder/components/Inspector.tsx b/src/builder/components/Inspector.tsx index 529fa282..90c13297 100644 --- a/src/builder/components/Inspector.tsx +++ b/src/builder/components/Inspector.tsx @@ -1,6 +1,6 @@ import React, { memo } from 'react'; import { useEditor } from '../EditorContext'; -import { BadgesPanel, SelectionPanel } from './panels'; +import { BadgesPanel, SelectionPanel } from './Panels'; import type { PosterConfig } from '../types'; import { Badge, MousePointer2 } from 'lucide-react'; import SidebarLayout from './SidebarLayout'; diff --git a/src/builder/components/ui/SourceTabContent.tsx b/src/builder/components/ui/SourceTabContent.tsx index acb544ba..8686349c 100644 --- a/src/builder/components/ui/SourceTabContent.tsx +++ b/src/builder/components/ui/SourceTabContent.tsx @@ -270,108 +270,112 @@ const SourceTabContent: React.FC = ({ - {/* Media type + ID */} -
-
-

- Media Type -

- updateConfig('mediaType', v as PosterConfig['mediaType'])} - options={[ - { id: 'movie', label: '🎬 Movie' }, - { id: 'tv', label: '📺 TV Series' }, - { id: 'anime', label: '🎌 Anime' }, - ]} - /> -
-
-

- IMDb ID -

- { - const val = e.target.value.trim(); - if (val.startsWith('tt')) { - setConfig((prev) => ({ ...prev, imdbId: val })); - } else { - setConfig((prev) => ({ ...prev, tmdbId: val, imdbId: undefined })); - } - }} - className="w-full h-9 px-2 rounded-lg mono-font text-center focus:outline-none transition-colors" - style={{ - background: 'rgba(255,255,255,0.04)', - border: '1px solid rgba(255,255,255,0.1)', - fontSize: 11, - color: 'var(--film-pale)', - }} - onMouseEnter={(e) => { - (e.currentTarget as HTMLElement).style.borderColor = 'rgba(196,124,46,0.4)'; - }} - onMouseLeave={(e) => { - if (document.activeElement !== e.currentTarget) { - (e.currentTarget as HTMLElement).style.borderColor = 'rgba(255,255,255,0.1)'; - } - }} - onFocus={(e) => { - (e.currentTarget as HTMLElement).style.borderColor = 'rgba(196,124,46,0.4)'; - }} - onBlur={(e) => { - (e.currentTarget as HTMLElement).style.borderColor = 'rgba(255,255,255,0.1)'; - }} - /> -
-
+ {isAdvanced && ( + <> + {/* Media type + ID */} +
+
+

+ Media Type +

+ updateConfig('mediaType', v as PosterConfig['mediaType'])} + options={[ + { id: 'movie', label: '🎬 Movie' }, + { id: 'tv', label: '📺 TV Series' }, + { id: 'anime', label: '🎌 Anime' }, + ]} + /> +
+
+

+ IMDb ID +

+ { + const val = e.target.value.trim(); + if (val.startsWith('tt')) { + setConfig((prev) => ({ ...prev, imdbId: val })); + } else { + setConfig((prev) => ({ ...prev, tmdbId: val, imdbId: undefined })); + } + }} + className="w-full h-9 px-2 rounded-lg mono-font text-center focus:outline-none transition-colors" + style={{ + background: 'rgba(255,255,255,0.04)', + border: '1px solid rgba(255,255,255,0.1)', + fontSize: 11, + color: 'var(--film-pale)', + }} + onMouseEnter={(e) => { + (e.currentTarget as HTMLElement).style.borderColor = 'rgba(196,124,46,0.4)'; + }} + onMouseLeave={(e) => { + if (document.activeElement !== e.currentTarget) { + (e.currentTarget as HTMLElement).style.borderColor = 'rgba(255,255,255,0.1)'; + } + }} + onFocus={(e) => { + (e.currentTarget as HTMLElement).style.borderColor = 'rgba(196,124,46,0.4)'; + }} + onBlur={(e) => { + (e.currentTarget as HTMLElement).style.borderColor = 'rgba(255,255,255,0.1)'; + }} + /> +
+
- {/* Source + ptype */} -
-
-

- Poster Source -

- updateConfig('source', v as PosterConfig['source'])} - options={sourceOptions} - /> -
- {['fanart', 'tmdb', 'imdb'].includes(config.source) && ( -
-

- Poster Type -

- updateConfig('ptype', v)} - options={ptypeOptions} - /> + {/* Source + ptype */} +
+
+

+ Poster Source +

+ updateConfig('source', v as PosterConfig['source'])} + options={sourceOptions} + /> +
+ {['fanart', 'tmdb', 'imdb'].includes(config.source) && ( +
+

+ Poster Type +

+ updateConfig('ptype', v)} + options={ptypeOptions} + /> +
+ )}
- )} -
- {/* Textless toggle */} - updateConfig('textless', v)} - disabled={['metahub', 'imdb'].includes(config.source)} - /> + {/* Textless toggle */} + updateConfig('textless', v)} + disabled={['metahub', 'imdb'].includes(config.source)} + /> + + )}
= ({ />
-
- - updateConfig( - 'logoSource', - v === 'auto' ? null : (v as PosterConfig['logoSource']) - ) - } - options={logoSourceOptions} - /> -
+ {isAdvanced && ( +
+ + updateConfig( + 'logoSource', + v === 'auto' ? null : (v as PosterConfig['logoSource']) + ) + } + options={logoSourceOptions} + /> +
+ )}
(null); const [leftPanelOpen, setLeftPanelOpen] = useState(false); const [rightPanelOpen, setRightPanelOpen] = useState(false); - const [bottomPanelTab, setBottomPanelTab] = useState<'source' | 'canvas' | 'badges'>('source'); + const [bottomPanelTab, setBottomPanelTab] = useState<'source' | 'badges'>('source'); const { bottomPanelOpen, @@ -163,7 +162,7 @@ const StudioLayout: React.FC<{ } = useMobileBottomSheet(mobileRootRef); const openBottomPanel = useCallback( - (tab: 'source' | 'canvas' | 'badges') => { + (tab: 'source' | 'badges') => { setBottomPanelTab(tab); openBottomPanelSheet(); }, @@ -1230,9 +1229,7 @@ const StudioLayout: React.FC<{ : bottomPanelOpen ? bottomPanelTab === 'source' ? 'Source' - : bottomPanelTab === 'canvas' - ? 'Canvas' - : 'Badges' + : 'Badges' : 'Builder'}
@@ -1970,7 +1967,6 @@ const StudioLayout: React.FC<{ {( [ { id: 'source', label: 'Source' }, - { id: 'canvas', label: 'Canvas' }, { id: 'badges', label: 'Badges' }, ] as const ).map(({ id, label }) => { @@ -2007,7 +2003,7 @@ const StudioLayout: React.FC<{
{/* CONTENT AREA */} - {/* All three panels are mounted simultaneously. Only one is visible via display. */} + {/* Both panels are mounted simultaneously. Only one is visible via display. */} {/* This eliminates remounting, re-running effects, and scroll position loss on tab switch. */} {/* Each content div has its own overflow-y:auto with touch scrolling. */}
- {/* CANVAS TAB CONTENT */} -
- -
- {/* BADGES TAB CONTENT */}
{/* Active indicator bar — 28px wide, 2px tall, translates X based on active tab */} - {/* Tab indices: source=0, canvas=1, badges=2. Each tab is 1/3 of nav width. */} - {/* Indicator centered within its tab: left = (tabIndex * 33.333%) + (33.333% - 28px) / 2 */} + {/* Tab indices: source=0, badges=1. Each tab is 1/2 of nav width. */} + {/* Indicator centered within its tab: left = (tabIndex * 50%) + (50% - 28px) / 2 */} {/* Use transform: translateX for GPU-accelerated animation instead of left: */}