@gallop.software/studio 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/StudioUI.tsx","../src/components/StudioContext.tsx","../src/components/StudioToolbar.tsx","../src/components/StudioBreadcrumb.tsx","../src/components/StudioFileGrid.tsx","../src/components/StudioFileList.tsx","../src/components/StudioPreview.tsx","../src/components/StudioSettings.tsx"],"sourcesContent":["/** @jsxImportSource @emotion/react */\n'use client'\n\nimport { useEffect, useCallback, useState } from 'react'\nimport { css } from '@emotion/react'\nimport { StudioContext } from './StudioContext'\nimport { StudioToolbar } from './StudioToolbar'\nimport { StudioBreadcrumb } from './StudioBreadcrumb'\nimport { StudioFileGrid } from './StudioFileGrid'\nimport { StudioFileList } from './StudioFileList'\nimport { StudioPreview } from './StudioPreview'\nimport { StudioSettings } from './StudioSettings'\nimport type { FileItem, StudioMeta } from '../types'\n\ninterface StudioUIProps {\n onClose: () => void\n}\n\nconst styles = {\n container: css`\n display: flex;\n flex-direction: column;\n height: 100%;\n font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n `,\n header: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n border-bottom: 1px solid #e5e7eb;\n `,\n title: css`\n font-size: 20px;\n font-weight: 600;\n color: #111827;\n margin: 0;\n `,\n headerActions: css`\n display: flex;\n align-items: center;\n gap: 8px;\n `,\n closeBtn: css`\n padding: 8px;\n background: none;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: background-color 0.15s;\n \n &:hover {\n background-color: #f3f4f6;\n }\n `,\n closeIcon: css`\n width: 20px;\n height: 20px;\n color: #6b7280;\n `,\n content: css`\n flex: 1;\n display: flex;\n overflow: hidden;\n `,\n fileBrowser: css`\n flex: 1;\n overflow: auto;\n padding: 16px;\n `,\n}\n\n/**\n * Main Studio UI - contains all panels and manages internal state\n * Rendered inside the modal via lazy loading\n */\nexport function StudioUI({ onClose }: StudioUIProps) {\n const [currentPath, setCurrentPathInternal] = useState('public')\n const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set())\n const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid')\n const [meta, setMeta] = useState<StudioMeta | null>(null)\n const [isLoading, setIsLoading] = useState(false)\n\n const navigateUp = useCallback(() => {\n if (currentPath === 'public') return\n const parts = currentPath.split('/')\n parts.pop()\n setCurrentPathInternal(parts.join('/') || 'public')\n setSelectedItems(new Set())\n }, [currentPath])\n\n const setCurrentPath = useCallback((path: string) => {\n setCurrentPathInternal(path)\n setSelectedItems(new Set())\n }, [])\n\n const toggleSelection = useCallback((path: string) => {\n setSelectedItems((prev) => {\n const next = new Set(prev)\n if (next.has(path)) {\n next.delete(path)\n } else {\n next.add(path)\n }\n return next\n })\n }, [])\n\n const selectAll = useCallback((items: FileItem[]) => {\n setSelectedItems(new Set(items.map((item) => item.path)))\n }, [])\n\n const clearSelection = useCallback(() => {\n setSelectedItems(new Set())\n }, [])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose()\n }\n },\n [onClose]\n )\n\n useEffect(() => {\n document.addEventListener('keydown', handleKeyDown)\n document.body.style.overflow = 'hidden'\n return () => {\n document.removeEventListener('keydown', handleKeyDown)\n document.body.style.overflow = ''\n }\n }, [handleKeyDown])\n\n const contextValue = {\n isOpen: true,\n openStudio: () => {},\n closeStudio: onClose,\n toggleStudio: onClose,\n currentPath,\n setCurrentPath,\n navigateUp,\n selectedItems,\n toggleSelection,\n selectAll,\n clearSelection,\n viewMode,\n setViewMode,\n meta,\n setMeta,\n isLoading,\n setIsLoading,\n }\n\n return (\n <StudioContext.Provider value={contextValue}>\n <div css={styles.container}>\n <div css={styles.header}>\n <h1 css={styles.title}>Studio</h1>\n <div css={styles.headerActions}>\n <StudioSettings />\n <button\n css={styles.closeBtn}\n onClick={onClose}\n aria-label=\"Close Studio\"\n >\n <CloseIcon />\n </button>\n </div>\n </div>\n\n <StudioToolbar />\n <StudioBreadcrumb />\n\n <div css={styles.content}>\n <div css={styles.fileBrowser}>\n {viewMode === 'grid' ? <StudioFileGrid /> : <StudioFileList />}\n </div>\n <StudioPreview />\n </div>\n </div>\n </StudioContext.Provider>\n )\n}\n\nfunction CloseIcon() {\n return (\n <svg\n css={styles.closeIcon}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n )\n}\n\nexport default StudioUI\n","'use client'\n\nimport { createContext, useContext } from 'react'\nimport type { FileItem, StudioMeta } from '../types'\n\n/**\n * Studio state interface\n * State is managed by StudioUI and provided to all child components\n */\nexport interface StudioState {\n isOpen: boolean\n openStudio: () => void\n closeStudio: () => void\n toggleStudio: () => void\n\n // Navigation\n currentPath: string\n setCurrentPath: (path: string) => void\n navigateUp: () => void\n\n // Selection\n selectedItems: Set<string>\n toggleSelection: (path: string) => void\n selectAll: (items: FileItem[]) => void\n clearSelection: () => void\n\n // View\n viewMode: 'grid' | 'list'\n setViewMode: (mode: 'grid' | 'list') => void\n\n // Meta\n meta: StudioMeta | null\n setMeta: (meta: StudioMeta) => void\n\n // Loading\n isLoading: boolean\n setIsLoading: (loading: boolean) => void\n}\n\nconst defaultState: StudioState = {\n isOpen: false,\n openStudio: () => {},\n closeStudio: () => {},\n toggleStudio: () => {},\n currentPath: 'public',\n setCurrentPath: () => {},\n navigateUp: () => {},\n selectedItems: new Set(),\n toggleSelection: () => {},\n selectAll: () => {},\n clearSelection: () => {},\n viewMode: 'grid',\n setViewMode: () => {},\n meta: null,\n setMeta: () => {},\n isLoading: false,\n setIsLoading: () => {},\n}\n\nexport const StudioContext = createContext<StudioState>(defaultState)\n\n/**\n * Hook to access Studio state from child components\n */\nexport function useStudio() {\n return useContext(StudioContext)\n}\n","/** @jsxImportSource @emotion/react */\n'use client'\n\nimport { useCallback } from 'react'\nimport { css } from '@emotion/react'\nimport { useStudio } from './StudioContext'\n\nconst styles = {\n toolbar: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 24px;\n background-color: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n `,\n left: css`\n display: flex;\n align-items: center;\n gap: 8px;\n `,\n right: css`\n display: flex;\n align-items: center;\n gap: 16px;\n `,\n btn: css`\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n background: none;\n border: none;\n cursor: pointer;\n transition: background-color 0.15s;\n \n &:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n `,\n btnDefault: css`\n color: #374151;\n \n &:hover:not(:disabled) {\n background-color: white;\n }\n `,\n btnDanger: css`\n color: #dc2626;\n \n &:hover:not(:disabled) {\n background-color: #fef2f2;\n }\n `,\n icon: css`\n width: 16px;\n height: 16px;\n `,\n selectionCount: css`\n font-size: 14px;\n color: #4b5563;\n `,\n clearBtn: css`\n margin-left: 8px;\n color: #9333ea;\n background: none;\n border: none;\n cursor: pointer;\n font-size: 14px;\n \n &:hover {\n text-decoration: underline;\n }\n `,\n viewToggle: css`\n display: flex;\n align-items: center;\n background-color: white;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n overflow: hidden;\n `,\n viewBtn: css`\n padding: 8px;\n background: none;\n border: none;\n cursor: pointer;\n color: #6b7280;\n transition: all 0.15s;\n \n &:hover {\n background-color: #f9fafb;\n }\n `,\n viewBtnActive: css`\n background-color: #f3e8ff;\n color: #7c3aed;\n `,\n}\n\nexport function StudioToolbar() {\n const { selectedItems, viewMode, setViewMode, clearSelection } = useStudio()\n\n const handleUpload = useCallback(() => {\n console.log('Upload clicked')\n }, [])\n\n const handleReprocess = useCallback(() => {\n console.log('Reprocess clicked', selectedItems)\n }, [selectedItems])\n\n const handleDelete = useCallback(() => {\n console.log('Delete clicked', selectedItems)\n }, [selectedItems])\n\n const handleSyncCdn = useCallback(() => {\n console.log('Sync CDN clicked', selectedItems)\n }, [selectedItems])\n\n const handleScan = useCallback(() => {\n console.log('Scan clicked')\n }, [])\n\n const hasSelection = selectedItems.size > 0\n\n return (\n <div css={styles.toolbar}>\n <div css={styles.left}>\n <ToolbarButton onClick={handleUpload} icon=\"upload\" label=\"Upload\" />\n <ToolbarButton\n onClick={handleReprocess}\n icon=\"refresh\"\n label=\"Reprocess\"\n disabled={!hasSelection}\n />\n <ToolbarButton\n onClick={handleDelete}\n icon=\"trash\"\n label=\"Delete\"\n disabled={!hasSelection}\n variant=\"danger\"\n />\n <ToolbarButton\n onClick={handleSyncCdn}\n icon=\"cloud\"\n label=\"Sync CDN\"\n disabled={!hasSelection}\n />\n <ToolbarButton onClick={handleScan} icon=\"scan\" label=\"Scan\" />\n </div>\n\n <div css={styles.right}>\n {hasSelection && (\n <span css={styles.selectionCount}>\n {selectedItems.size} selected\n <button css={styles.clearBtn} onClick={clearSelection}>\n Clear\n </button>\n </span>\n )}\n\n <div css={styles.viewToggle}>\n <button\n css={[styles.viewBtn, viewMode === 'grid' && styles.viewBtnActive]}\n onClick={() => setViewMode('grid')}\n aria-label=\"Grid view\"\n >\n <GridIcon />\n </button>\n <button\n css={[styles.viewBtn, viewMode === 'list' && styles.viewBtnActive]}\n onClick={() => setViewMode('list')}\n aria-label=\"List view\"\n >\n <ListIcon />\n </button>\n </div>\n </div>\n </div>\n )\n}\n\ninterface ToolbarButtonProps {\n onClick: () => void\n icon: 'upload' | 'refresh' | 'trash' | 'cloud' | 'scan'\n label: string\n disabled?: boolean\n variant?: 'default' | 'danger'\n}\n\nfunction ToolbarButton({\n onClick,\n icon,\n label,\n disabled,\n variant = 'default',\n}: ToolbarButtonProps) {\n return (\n <button\n css={[styles.btn, variant === 'danger' ? styles.btnDanger : styles.btnDefault]}\n onClick={onClick}\n disabled={disabled}\n >\n <IconComponent icon={icon} />\n {label}\n </button>\n )\n}\n\nfunction IconComponent({ icon }: { icon: string }) {\n switch (icon) {\n case 'upload':\n return (\n <svg css={styles.icon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12\" />\n </svg>\n )\n case 'refresh':\n return (\n <svg css={styles.icon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n )\n case 'trash':\n return (\n <svg css={styles.icon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\" />\n </svg>\n )\n case 'cloud':\n return (\n <svg css={styles.icon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12\" />\n </svg>\n )\n case 'scan':\n return (\n <svg css={styles.icon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n )\n default:\n return null\n }\n}\n\nfunction GridIcon() {\n return (\n <svg css={styles.icon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z\" />\n </svg>\n )\n}\n\nfunction ListIcon() {\n return (\n <svg css={styles.icon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 6h16M4 10h16M4 14h16M4 18h16\" />\n </svg>\n )\n}\n","/** @jsxImportSource @emotion/react */\n'use client'\n\nimport { css } from '@emotion/react'\nimport { useStudio } from './StudioContext'\n\nconst styles = {\n container: css`\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 24px;\n background-color: white;\n border-bottom: 1px solid #f3f4f6;\n `,\n backBtn: css`\n padding: 4px;\n background: none;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n transition: background-color 0.15s;\n \n &:hover {\n background-color: #f3f4f6;\n }\n `,\n backIcon: css`\n width: 16px;\n height: 16px;\n color: #6b7280;\n `,\n nav: css`\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 14px;\n `,\n item: css`\n display: flex;\n align-items: center;\n gap: 4px;\n `,\n separator: css`\n color: #d1d5db;\n `,\n btn: css`\n padding: 2px 4px;\n background: none;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.15s;\n \n &:hover {\n background-color: #f3f4f6;\n }\n `,\n btnActive: css`\n color: #111827;\n font-weight: 500;\n `,\n btnInactive: css`\n color: #6b7280;\n \n &:hover {\n color: #374151;\n }\n `,\n}\n\nexport function StudioBreadcrumb() {\n const { currentPath, setCurrentPath, navigateUp } = useStudio()\n\n const parts = currentPath.split('/').filter(Boolean)\n\n const handleClick = (index: number) => {\n const newPath = parts.slice(0, index + 1).join('/')\n setCurrentPath(newPath)\n }\n\n return (\n <div css={styles.container}>\n {currentPath !== 'public' && (\n <button css={styles.backBtn} onClick={navigateUp} aria-label=\"Go back\">\n <svg css={styles.backIcon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n )}\n\n <nav css={styles.nav}>\n {parts.map((part, index) => (\n <span key={index} css={styles.item}>\n {index > 0 && <span css={styles.separator}>/</span>}\n <button\n css={[styles.btn, index === parts.length - 1 ? styles.btnActive : styles.btnInactive]}\n onClick={() => handleClick(index)}\n >\n {part}\n </button>\n </span>\n ))}\n </nav>\n </div>\n )\n}\n","/** @jsxImportSource @emotion/react */\n'use client'\n\nimport { useEffect, useState } from 'react'\nimport { css, keyframes } from '@emotion/react'\nimport { useStudio } from './StudioContext'\nimport type { FileItem } from '../types'\n\nconst spin = keyframes`\n to { transform: rotate(360deg); }\n`\n\nconst styles = {\n loading: css`\n display: flex;\n align-items: center;\n justify-content: center;\n height: 256px;\n `,\n spinner: css`\n width: 32px;\n height: 32px;\n border-radius: 50%;\n border: 2px solid transparent;\n border-bottom-color: #9333ea;\n animation: ${spin} 1s linear infinite;\n `,\n empty: css`\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 256px;\n color: #6b7280;\n `,\n emptyIcon: css`\n width: 48px;\n height: 48px;\n margin-bottom: 16px;\n `,\n emptyText: css`\n font-size: 14px;\n margin: 0;\n `,\n grid: css`\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 16px;\n \n @media (min-width: 640px) { grid-template-columns: repeat(3, 1fr); }\n @media (min-width: 768px) { grid-template-columns: repeat(4, 1fr); }\n @media (min-width: 1024px) { grid-template-columns: repeat(5, 1fr); }\n @media (min-width: 1280px) { grid-template-columns: repeat(6, 1fr); }\n `,\n item: css`\n position: relative;\n border-radius: 8px;\n border: 2px solid transparent;\n overflow: hidden;\n cursor: pointer;\n transition: all 0.15s;\n background-color: #f9fafb;\n \n &:hover {\n border-color: #e5e7eb;\n }\n `,\n itemSelected: css`\n border-color: #a855f7;\n background-color: #faf5ff;\n `,\n checkbox: css`\n position: absolute;\n top: 8px;\n left: 8px;\n z-index: 10;\n width: 16px;\n height: 16px;\n accent-color: #9333ea;\n `,\n cdnBadge: css`\n position: absolute;\n top: 8px;\n right: 8px;\n z-index: 10;\n background-color: #dcfce7;\n color: #15803d;\n font-size: 12px;\n padding: 2px 6px;\n border-radius: 9999px;\n `,\n content: css`\n aspect-ratio: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 16px;\n `,\n folderIcon: css`\n width: 64px;\n height: 64px;\n color: #facc15;\n `,\n image: css`\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n border-radius: 4px;\n `,\n label: css`\n padding: 6px 8px;\n background-color: white;\n border-top: 1px solid #e5e7eb;\n `,\n name: css`\n font-size: 12px;\n color: #374151;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin: 0;\n `,\n size: css`\n font-size: 12px;\n color: #9ca3af;\n margin: 0;\n `,\n}\n\nexport function StudioFileGrid() {\n const { currentPath, setCurrentPath, selectedItems, toggleSelection } = useStudio()\n const [items, setItems] = useState<FileItem[]>([])\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n async function loadItems() {\n setLoading(true)\n try {\n const response = await fetch(`/api/studio/list?path=${encodeURIComponent(currentPath)}`)\n if (response.ok) {\n const data = await response.json()\n setItems(data.items || [])\n }\n } catch (error) {\n console.error('Failed to load items:', error)\n }\n setLoading(false)\n }\n loadItems()\n }, [currentPath])\n\n if (loading) {\n return (\n <div css={styles.loading}>\n <div css={styles.spinner} />\n </div>\n )\n }\n\n if (items.length === 0) {\n return (\n <div css={styles.empty}>\n <svg css={styles.emptyIcon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\" />\n </svg>\n <p css={styles.emptyText}>No files in this folder</p>\n <p css={styles.emptyText}>Upload images to get started</p>\n </div>\n )\n }\n\n const sortedItems = [...items].sort((a, b) => {\n if (a.type === 'folder' && b.type !== 'folder') return -1\n if (a.type !== 'folder' && b.type === 'folder') return 1\n return a.name.localeCompare(b.name)\n })\n\n return (\n <div css={styles.grid}>\n {sortedItems.map((item) => (\n <GridItem\n key={item.path}\n item={item}\n isSelected={selectedItems.has(item.path)}\n onSelect={() => toggleSelection(item.path)}\n onOpen={() => {\n if (item.type === 'folder') {\n setCurrentPath(item.path)\n }\n }}\n />\n ))}\n </div>\n )\n}\n\ninterface GridItemProps {\n item: FileItem\n isSelected: boolean\n onSelect: () => void\n onOpen: () => void\n}\n\nfunction GridItem({ item, isSelected, onSelect, onOpen }: GridItemProps) {\n const isFolder = item.type === 'folder'\n\n return (\n <div css={[styles.item, isSelected && styles.itemSelected]} onDoubleClick={onOpen}>\n <input\n type=\"checkbox\"\n css={styles.checkbox}\n checked={isSelected}\n onChange={onSelect}\n onClick={(e) => e.stopPropagation()}\n />\n\n {item.cdnSynced && <span css={styles.cdnBadge}>CDN</span>}\n\n <div css={styles.content}>\n {isFolder ? (\n <svg css={styles.folderIcon} fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z\" />\n </svg>\n ) : (\n <img\n css={styles.image}\n src={item.path.replace('public', '')}\n alt={item.name}\n loading=\"lazy\"\n />\n )}\n </div>\n\n <div css={styles.label}>\n <p css={styles.name} title={item.name}>{item.name}</p>\n {item.size && <p css={styles.size}>{formatFileSize(item.size)}</p>}\n </div>\n </div>\n )\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n","/** @jsxImportSource @emotion/react */\n'use client'\n\nimport { useEffect, useState } from 'react'\nimport { css, keyframes } from '@emotion/react'\nimport { useStudio } from './StudioContext'\nimport type { FileItem } from '../types'\n\nconst spin = keyframes`\n to { transform: rotate(360deg); }\n`\n\nconst styles = {\n loading: css`\n display: flex;\n align-items: center;\n justify-content: center;\n height: 256px;\n `,\n spinner: css`\n width: 32px;\n height: 32px;\n border-radius: 50%;\n border: 2px solid transparent;\n border-bottom-color: #9333ea;\n animation: ${spin} 1s linear infinite;\n `,\n empty: css`\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 256px;\n color: #6b7280;\n `,\n table: css`\n width: 100%;\n border-collapse: collapse;\n `,\n th: css`\n text-align: left;\n font-size: 12px;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n padding-bottom: 8px;\n font-weight: normal;\n `,\n thCheckbox: css`\n width: 32px;\n `,\n thSize: css`\n width: 96px;\n `,\n thDimensions: css`\n width: 128px;\n `,\n thCdn: css`\n width: 96px;\n `,\n tbody: css`\n border-top: 1px solid #f3f4f6;\n `,\n row: css`\n cursor: pointer;\n transition: background-color 0.15s;\n \n &:hover {\n background-color: #f9fafb;\n }\n `,\n rowSelected: css`\n background-color: #faf5ff;\n `,\n td: css`\n padding: 8px 0;\n border-bottom: 1px solid #f3f4f6;\n `,\n checkbox: css`\n width: 16px;\n height: 16px;\n accent-color: #9333ea;\n `,\n nameCell: css`\n display: flex;\n align-items: center;\n gap: 8px;\n `,\n folderIcon: css`\n width: 20px;\n height: 20px;\n color: #facc15;\n `,\n fileIcon: css`\n width: 20px;\n height: 20px;\n color: #9ca3af;\n `,\n name: css`\n font-size: 14px;\n color: #111827;\n `,\n meta: css`\n font-size: 14px;\n color: #6b7280;\n `,\n cdnBadge: css`\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n color: #15803d;\n `,\n cdnIcon: css`\n width: 12px;\n height: 12px;\n `,\n cdnEmpty: css`\n font-size: 12px;\n color: #9ca3af;\n `,\n}\n\nexport function StudioFileList() {\n const { currentPath, setCurrentPath, selectedItems, toggleSelection } = useStudio()\n const [items, setItems] = useState<FileItem[]>([])\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n async function loadItems() {\n setLoading(true)\n try {\n const response = await fetch(`/api/studio/list?path=${encodeURIComponent(currentPath)}`)\n if (response.ok) {\n const data = await response.json()\n setItems(data.items || [])\n }\n } catch (error) {\n console.error('Failed to load items:', error)\n }\n setLoading(false)\n }\n loadItems()\n }, [currentPath])\n\n if (loading) {\n return (\n <div css={styles.loading}>\n <div css={styles.spinner} />\n </div>\n )\n }\n\n if (items.length === 0) {\n return (\n <div css={styles.empty}>\n <p>No files in this folder</p>\n </div>\n )\n }\n\n const sortedItems = [...items].sort((a, b) => {\n if (a.type === 'folder' && b.type !== 'folder') return -1\n if (a.type !== 'folder' && b.type === 'folder') return 1\n return a.name.localeCompare(b.name)\n })\n\n return (\n <table css={styles.table}>\n <thead>\n <tr>\n <th css={[styles.th, styles.thCheckbox]}></th>\n <th css={styles.th}>Name</th>\n <th css={[styles.th, styles.thSize]}>Size</th>\n <th css={[styles.th, styles.thDimensions]}>Dimensions</th>\n <th css={[styles.th, styles.thCdn]}>CDN</th>\n </tr>\n </thead>\n <tbody css={styles.tbody}>\n {sortedItems.map((item) => (\n <ListRow\n key={item.path}\n item={item}\n isSelected={selectedItems.has(item.path)}\n onSelect={() => toggleSelection(item.path)}\n onOpen={() => {\n if (item.type === 'folder') {\n setCurrentPath(item.path)\n }\n }}\n />\n ))}\n </tbody>\n </table>\n )\n}\n\ninterface ListRowProps {\n item: FileItem\n isSelected: boolean\n onSelect: () => void\n onOpen: () => void\n}\n\nfunction ListRow({ item, isSelected, onSelect, onOpen }: ListRowProps) {\n const isFolder = item.type === 'folder'\n\n return (\n <tr css={[styles.row, isSelected && styles.rowSelected]} onDoubleClick={onOpen}>\n <td css={styles.td}>\n <input\n type=\"checkbox\"\n css={styles.checkbox}\n checked={isSelected}\n onChange={onSelect}\n onClick={(e) => e.stopPropagation()}\n />\n </td>\n <td css={styles.td}>\n <div css={styles.nameCell}>\n {isFolder ? (\n <svg css={styles.folderIcon} fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z\" />\n </svg>\n ) : (\n <svg css={styles.fileIcon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\" />\n </svg>\n )}\n <span css={styles.name}>{item.name}</span>\n </div>\n </td>\n <td css={[styles.td, styles.meta]}>\n {item.size ? formatFileSize(item.size) : '--'}\n </td>\n <td css={[styles.td, styles.meta]}>\n {item.dimensions ? `${item.dimensions.width}x${item.dimensions.height}` : '--'}\n </td>\n <td css={styles.td}>\n {item.cdnSynced ? (\n <span css={styles.cdnBadge}>\n <svg css={styles.cdnIcon} fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fillRule=\"evenodd\" d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\" clipRule=\"evenodd\" />\n </svg>\n Synced\n </span>\n ) : (\n <span css={styles.cdnEmpty}>--</span>\n )}\n </td>\n </tr>\n )\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n","/** @jsxImportSource @emotion/react */\n'use client'\n\nimport { css } from '@emotion/react'\nimport { useStudio } from './StudioContext'\n\nconst styles = {\n panel: css`\n width: 320px;\n border-left: 1px solid #e5e7eb;\n background-color: #f9fafb;\n padding: 16px;\n overflow: auto;\n `,\n title: css`\n font-size: 14px;\n font-weight: 500;\n color: #111827;\n margin: 0 0 16px 0;\n `,\n imageContainer: css`\n background-color: white;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n padding: 8px;\n margin-bottom: 16px;\n `,\n image: css`\n width: 100%;\n height: auto;\n border-radius: 4px;\n `,\n info: css`\n display: flex;\n flex-direction: column;\n gap: 12px;\n `,\n row: css`\n display: flex;\n justify-content: space-between;\n font-size: 12px;\n `,\n label: css`\n color: #6b7280;\n `,\n value: css`\n color: #111827;\n `,\n valueTruncate: css`\n max-width: 128px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n `,\n section: css`\n padding-top: 8px;\n border-top: 1px solid #e5e7eb;\n `,\n sectionTitle: css`\n font-size: 12px;\n font-weight: 500;\n color: #6b7280;\n margin: 0 0 8px 0;\n `,\n cdnStatus: css`\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: #16a34a;\n `,\n cdnIcon: css`\n width: 16px;\n height: 16px;\n `,\n copyBtn: css`\n margin-top: 8px;\n font-size: 12px;\n color: #9333ea;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0;\n \n &:hover {\n text-decoration: underline;\n }\n `,\n colorSwatch: css`\n margin-top: 8px;\n height: 32px;\n border-radius: 4px;\n `,\n actions: css`\n margin-top: 16px;\n padding-top: 16px;\n border-top: 1px solid #e5e7eb;\n display: flex;\n flex-direction: column;\n gap: 8px;\n `,\n actionBtn: css`\n width: 100%;\n padding: 8px 12px;\n font-size: 14px;\n background-color: white;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n cursor: pointer;\n transition: background-color 0.15s;\n color: #374151;\n \n &:hover {\n background-color: #f9fafb;\n }\n `,\n actionBtnDanger: css`\n color: #dc2626;\n \n &:hover {\n background-color: #fef2f2;\n }\n `,\n}\n\nexport function StudioPreview() {\n const { selectedItems, meta } = useStudio()\n\n if (selectedItems.size !== 1) {\n return null\n }\n\n const selectedPath = Array.from(selectedItems)[0]\n const imageKey = selectedPath\n .replace(/^public\\/images\\//, '')\n .replace(/^public\\/originals\\//, '')\n\n const imageData = meta?.images?.[imageKey]\n\n return (\n <div css={styles.panel}>\n <h3 css={styles.title}>Preview</h3>\n\n <div css={styles.imageContainer}>\n <img\n css={styles.image}\n src={selectedPath.replace('public', '')}\n alt=\"Preview\"\n />\n </div>\n\n <div css={styles.info}>\n <InfoRow label=\"Filename\" value={selectedPath.split('/').pop() || ''} />\n\n {imageData && (\n <>\n <InfoRow\n label=\"Original\"\n value={`${imageData.original.width}x${imageData.original.height}`}\n />\n <InfoRow\n label=\"File size\"\n value={formatFileSize(imageData.original.fileSize)}\n />\n\n <div css={styles.section}>\n <p css={styles.sectionTitle}>Generated sizes</p>\n {Object.entries(imageData.sizes).map(([size, data]) => (\n <InfoRow key={size} label={size} value={`${data.width}x${data.height}`} />\n ))}\n </div>\n\n {imageData.cdn?.synced && (\n <div css={styles.section}>\n <p css={styles.sectionTitle}>CDN</p>\n <div css={styles.cdnStatus}>\n <svg css={styles.cdnIcon} fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fillRule=\"evenodd\" d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\" clipRule=\"evenodd\" />\n </svg>\n Synced to CDN\n </div>\n <button\n css={styles.copyBtn}\n onClick={() => {\n navigator.clipboard.writeText(`${imageData.cdn?.baseUrl}${imageData.sizes.full.path}`)\n }}\n >\n Copy CDN URL\n </button>\n </div>\n )}\n\n {imageData.blurhash && (\n <div css={styles.section}>\n <InfoRow label=\"Blurhash\" value={imageData.blurhash} truncate />\n <div\n css={styles.colorSwatch}\n style={{ backgroundColor: imageData.dominantColor }}\n title={`Dominant color: ${imageData.dominantColor}`}\n />\n </div>\n )}\n </>\n )}\n </div>\n\n <div css={styles.actions}>\n <button css={styles.actionBtn}>Rename</button>\n <button css={[styles.actionBtn, styles.actionBtnDanger]}>Delete</button>\n </div>\n </div>\n )\n}\n\nfunction InfoRow({ label, value, truncate }: { label: string; value: string; truncate?: boolean }) {\n return (\n <div css={styles.row}>\n <span css={styles.label}>{label}</span>\n <span css={[styles.value, truncate && styles.valueTruncate]} title={truncate ? value : undefined}>\n {value}\n </span>\n </div>\n )\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n","/** @jsxImportSource @emotion/react */\n'use client'\n\nimport { useState } from 'react'\nimport { css } from '@emotion/react'\n\nconst styles = {\n btn: css`\n padding: 8px;\n background: none;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: background-color 0.15s;\n \n &:hover {\n background-color: #f3f4f6;\n }\n `,\n icon: css`\n width: 20px;\n height: 20px;\n color: #6b7280;\n `,\n overlay: css`\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 10000;\n display: flex;\n align-items: center;\n justify-content: center;\n `,\n backdrop: css`\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n background-color: rgba(0, 0, 0, 0.3);\n `,\n panel: css`\n position: relative;\n background-color: white;\n border-radius: 12px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n width: 100%;\n max-width: 512px;\n padding: 24px;\n `,\n header: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 24px;\n `,\n title: css`\n font-size: 18px;\n font-weight: 600;\n margin: 0;\n `,\n closeBtn: css`\n padding: 4px;\n background: none;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n \n &:hover {\n background-color: #f3f4f6;\n }\n `,\n sections: css`\n display: flex;\n flex-direction: column;\n gap: 24px;\n `,\n sectionTitle: css`\n font-size: 14px;\n font-weight: 500;\n color: #111827;\n margin: 0 0 12px 0;\n `,\n description: css`\n font-size: 12px;\n color: #6b7280;\n margin: 0 0 12px 0;\n `,\n code: css`\n background-color: #f9fafb;\n border-radius: 8px;\n padding: 12px;\n font-family: monospace;\n font-size: 12px;\n color: #4b5563;\n `,\n codeLine: css`\n margin: 0 0 4px 0;\n \n &:last-child {\n margin: 0;\n }\n `,\n input: css`\n width: 100%;\n padding: 8px 12px;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 14px;\n \n &:focus {\n outline: none;\n box-shadow: 0 0 0 2px #a855f7;\n }\n `,\n grid: css`\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 12px;\n `,\n label: css`\n font-size: 12px;\n color: #6b7280;\n display: block;\n margin-bottom: 4px;\n `,\n footer: css`\n margin-top: 24px;\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n `,\n cancelBtn: css`\n padding: 8px 16px;\n font-size: 14px;\n color: #4b5563;\n background: none;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n \n &:hover {\n background-color: #f3f4f6;\n }\n `,\n saveBtn: css`\n padding: 8px 16px;\n font-size: 14px;\n color: white;\n background-color: #9333ea;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n \n &:hover {\n background-color: #7c3aed;\n }\n `,\n}\n\nexport function StudioSettings() {\n const [isOpen, setIsOpen] = useState(false)\n\n return (\n <>\n <button css={styles.btn} onClick={() => setIsOpen(true)} aria-label=\"Settings\">\n <svg\n css={styles.icon}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z\" />\n </svg>\n </button>\n\n {isOpen && <SettingsPanel onClose={() => setIsOpen(false)} />}\n </>\n )\n}\n\nfunction SettingsPanel({ onClose }: { onClose: () => void }) {\n return (\n <div css={styles.overlay}>\n <div css={styles.backdrop} onClick={onClose} />\n\n <div css={styles.panel}>\n <div css={styles.header}>\n <h2 css={styles.title}>Settings</h2>\n <button css={styles.closeBtn} onClick={onClose}>\n <svg css={styles.icon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div css={styles.sections}>\n <section>\n <h3 css={styles.sectionTitle}>Cloudflare R2</h3>\n <p css={styles.description}>Configure in .env.local file:</p>\n <div css={styles.code}>\n <p css={styles.codeLine}>CLOUDFLARE_R2_ACCOUNT_ID</p>\n <p css={styles.codeLine}>CLOUDFLARE_R2_ACCESS_KEY_ID</p>\n <p css={styles.codeLine}>CLOUDFLARE_R2_SECRET_ACCESS_KEY</p>\n <p css={styles.codeLine}>CLOUDFLARE_R2_BUCKET_NAME</p>\n <p css={styles.codeLine}>CLOUDFLARE_R2_PUBLIC_URL</p>\n </div>\n </section>\n\n <section>\n <h3 css={styles.sectionTitle}>Custom CDN URL</h3>\n <p css={styles.description}>Override the default R2 URL with a custom domain:</p>\n <input css={styles.input} type=\"text\" placeholder=\"https://cdn.yourdomain.com\" />\n </section>\n\n <section>\n <h3 css={styles.sectionTitle}>Thumbnail Sizes</h3>\n <div css={styles.grid}>\n <div>\n <label css={styles.label}>Small</label>\n <input css={styles.input} type=\"number\" defaultValue={300} />\n </div>\n <div>\n <label css={styles.label}>Medium</label>\n <input css={styles.input} type=\"number\" defaultValue={700} />\n </div>\n <div>\n <label css={styles.label}>Large</label>\n <input css={styles.input} type=\"number\" defaultValue={1400} />\n </div>\n </div>\n </section>\n </div>\n\n <div css={styles.footer}>\n <button css={styles.cancelBtn} onClick={onClose}>Cancel</button>\n <button css={styles.saveBtn}>Save Changes</button>\n </div>\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["useEffect","useCallback","useState","css","css","jsx","jsxs","styles","css","css","jsx","jsxs","styles","css","useEffect","useState","css","keyframes","jsx","jsxs","spin","keyframes","styles","css","useState","useEffect","formatFileSize","css","jsx","jsxs","styles","css","formatFileSize","useState","css","Fragment","jsx","jsxs","styles","jsx","jsxs","styles","css","useState","useCallback","useEffect"]}
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as _emotion_react_jsx_runtime from '@emotion/react/jsx-runtime';
2
2
  import { a as ImageSize, S as SizeEntry, I as ImageEntry, b as StudioMeta } from './types-BvdwylVD.mjs';
3
3
  export { C as CdnStatus, F as FileItem, c as StudioConfig } from './types-BvdwylVD.mjs';
4
4
 
@@ -6,16 +6,8 @@ export { C as CdnStatus, F as FileItem, c as StudioConfig } from './types-Bvdwyl
6
6
  * Floating button that opens the Studio modal.
7
7
  * Fixed position in bottom-right corner.
8
8
  * Only renders in development mode.
9
- *
10
- * Usage:
11
- * ```tsx
12
- * import { StudioButton } from '@gallop.software/studio'
13
- *
14
- * // In your layout
15
- * <StudioButton />
16
- * ```
17
9
  */
18
- declare function StudioButton(): react_jsx_runtime.JSX.Element | null;
10
+ declare function StudioButton(): _emotion_react_jsx_runtime.JSX.Element | null;
19
11
 
20
12
  /**
21
13
  * The meta object containing all image metadata.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as _emotion_react_jsx_runtime from '@emotion/react/jsx-runtime';
2
2
  import { a as ImageSize, S as SizeEntry, I as ImageEntry, b as StudioMeta } from './types-BvdwylVD.js';
3
3
  export { C as CdnStatus, F as FileItem, c as StudioConfig } from './types-BvdwylVD.js';
4
4
 
@@ -6,16 +6,8 @@ export { C as CdnStatus, F as FileItem, c as StudioConfig } from './types-Bvdwyl
6
6
  * Floating button that opens the Studio modal.
7
7
  * Fixed position in bottom-right corner.
8
8
  * Only renders in development mode.
9
- *
10
- * Usage:
11
- * ```tsx
12
- * import { StudioButton } from '@gallop.software/studio'
13
- *
14
- * // In your layout
15
- * <StudioButton />
16
- * ```
17
9
  */
18
- declare function StudioButton(): react_jsx_runtime.JSX.Element | null;
10
+ declare function StudioButton(): _emotion_react_jsx_runtime.JSX.Element | null;
19
11
 
20
12
  /**
21
13
  * The meta object containing all image metadata.
package/dist/index.js CHANGED
@@ -2,8 +2,98 @@
2
2
 
3
3
  // src/components/StudioButton.tsx
4
4
  var _react = require('react');
5
- var _jsxruntime = require('react/jsx-runtime');
6
- var StudioUI = _react.lazy.call(void 0, () => Promise.resolve().then(() => _interopRequireWildcard(require("./StudioUI-BH7PWCKH.js"))));
5
+ var _react3 = require('@emotion/react');
6
+ var _jsxruntime = require('@emotion/react/jsx-runtime');
7
+ var StudioUI = _react.lazy.call(void 0, () => Promise.resolve().then(() => _interopRequireWildcard(require("./StudioUI-5I3O5VF7.js"))));
8
+ var spin = _react3.keyframes`
9
+ to {
10
+ transform: rotate(360deg);
11
+ }
12
+ `;
13
+ var styles = {
14
+ button: _react3.css`
15
+ position: fixed;
16
+ bottom: 24px;
17
+ right: 24px;
18
+ z-index: 9998;
19
+ width: 48px;
20
+ height: 48px;
21
+ border-radius: 50%;
22
+ background: linear-gradient(to bottom right, #a855f7, #ec4899);
23
+ color: white;
24
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ border: none;
29
+ cursor: pointer;
30
+ transition: all 0.2s;
31
+
32
+ &:hover {
33
+ transform: scale(1.05);
34
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
35
+ }
36
+ `,
37
+ buttonIcon: _react3.css`
38
+ width: 24px;
39
+ height: 24px;
40
+ `,
41
+ overlay: _react3.css`
42
+ position: fixed;
43
+ top: 0;
44
+ right: 0;
45
+ bottom: 0;
46
+ left: 0;
47
+ z-index: 9999;
48
+ `,
49
+ backdrop: _react3.css`
50
+ position: absolute;
51
+ top: 0;
52
+ right: 0;
53
+ bottom: 0;
54
+ left: 0;
55
+ background-color: rgba(0, 0, 0, 0.5);
56
+ backdrop-filter: blur(4px);
57
+ `,
58
+ modal: _react3.css`
59
+ position: absolute;
60
+ top: 32px;
61
+ right: 32px;
62
+ bottom: 32px;
63
+ left: 32px;
64
+ background-color: white;
65
+ border-radius: 16px;
66
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
67
+ display: flex;
68
+ flex-direction: column;
69
+ overflow: hidden;
70
+ `,
71
+ loading: _react3.css`
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ height: 100%;
76
+ `,
77
+ loadingContent: _react3.css`
78
+ display: flex;
79
+ flex-direction: column;
80
+ align-items: center;
81
+ gap: 16px;
82
+ `,
83
+ spinner: _react3.css`
84
+ width: 32px;
85
+ height: 32px;
86
+ border-radius: 50%;
87
+ border: 2px solid transparent;
88
+ border-bottom-color: #9333ea;
89
+ animation: ${spin} 1s linear infinite;
90
+ `,
91
+ loadingText: _react3.css`
92
+ color: #6b7280;
93
+ font-size: 14px;
94
+ margin: 0;
95
+ `
96
+ };
7
97
  function StudioButton() {
8
98
  const [isOpen, setIsOpen] = _react.useState.call(void 0, false);
9
99
  if (process.env.NODE_ENV !== "development") {
@@ -13,85 +103,24 @@ function StudioButton() {
13
103
  !isOpen && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
14
104
  "button",
15
105
  {
106
+ css: styles.button,
16
107
  onClick: () => setIsOpen(true),
17
- style: {
18
- position: "fixed",
19
- bottom: "24px",
20
- right: "24px",
21
- zIndex: 9998,
22
- width: "48px",
23
- height: "48px",
24
- borderRadius: "50%",
25
- background: "linear-gradient(to bottom right, #a855f7, #ec4899)",
26
- color: "white",
27
- boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)",
28
- display: "flex",
29
- alignItems: "center",
30
- justifyContent: "center",
31
- border: "none",
32
- cursor: "pointer",
33
- transition: "all 0.2s"
34
- },
35
108
  title: "Open Studio",
36
109
  "aria-label": "Open Studio media manager",
37
110
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ImageIcon, {})
38
111
  }
39
112
  ),
40
- isOpen && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
41
- "div",
42
- {
43
- style: {
44
- position: "fixed",
45
- top: 0,
46
- right: 0,
47
- bottom: 0,
48
- left: 0,
49
- zIndex: 9999
50
- },
51
- children: [
52
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
53
- "div",
54
- {
55
- style: {
56
- position: "absolute",
57
- top: 0,
58
- right: 0,
59
- bottom: 0,
60
- left: 0,
61
- backgroundColor: "rgba(0, 0, 0, 0.5)",
62
- backdropFilter: "blur(4px)"
63
- },
64
- onClick: () => setIsOpen(false)
65
- }
66
- ),
67
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
68
- "div",
69
- {
70
- style: {
71
- position: "absolute",
72
- top: "32px",
73
- right: "32px",
74
- bottom: "32px",
75
- left: "32px",
76
- backgroundColor: "white",
77
- borderRadius: "16px",
78
- boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
79
- display: "flex",
80
- flexDirection: "column",
81
- overflow: "hidden"
82
- },
83
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _react.Suspense, { fallback: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LoadingState, {}), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioUI, { onClose: () => setIsOpen(false) }) })
84
- }
85
- )
86
- ]
87
- }
88
- )
113
+ isOpen && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles.overlay, children: [
114
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.backdrop, onClick: () => setIsOpen(false) }),
115
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.modal, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _react.Suspense, { fallback: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LoadingState, {}), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioUI, { onClose: () => setIsOpen(false) }) }) })
116
+ ] })
89
117
  ] });
90
118
  }
91
119
  function ImageIcon() {
92
120
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
93
121
  "svg",
94
122
  {
123
+ css: styles.buttonIcon,
95
124
  xmlns: "http://www.w3.org/2000/svg",
96
125
  viewBox: "0 0 24 24",
97
126
  fill: "none",
@@ -99,7 +128,6 @@ function ImageIcon() {
99
128
  strokeWidth: 2,
100
129
  strokeLinecap: "round",
101
130
  strokeLinejoin: "round",
102
- className: "w-6 h-6",
103
131
  children: [
104
132
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
105
133
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
@@ -109,9 +137,9 @@ function ImageIcon() {
109
137
  );
110
138
  }
111
139
  function LoadingState() {
112
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-4", children: [
113
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-purple-600" }),
114
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-gray-500", children: "Loading Studio..." })
140
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.loading, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles.loadingContent, children: [
141
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.spinner }),
142
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles.loadingText, children: "Loading Studio..." })
115
143
  ] }) });
116
144
  }
117
145
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/chrisb/Sites/studio/dist/index.js","../src/components/StudioButton.tsx","../src/lib/meta.ts"],"names":[],"mappings":"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","file":"/Users/chrisb/Sites/studio/dist/index.js","sourcesContent":[null,"'use client'\n\nimport { useState, lazy, Suspense } from 'react'\n\n// Lazy load the full Studio UI to avoid bundling in production\nconst StudioUI = lazy(() => import('./StudioUI'))\n\n/**\n * Floating button that opens the Studio modal.\n * Fixed position in bottom-right corner.\n * Only renders in development mode.\n * \n * Usage:\n * ```tsx\n * import { StudioButton } from '@gallop.software/studio'\n * \n * // In your layout\n * <StudioButton />\n * ```\n */\nexport function StudioButton() {\n const [isOpen, setIsOpen] = useState(false)\n\n // Only render in development\n if (process.env.NODE_ENV !== 'development') {\n return null\n }\n\n return (\n <>\n {/* Floating button - hidden when modal is open */}\n {!isOpen && (\n <button\n onClick={() => setIsOpen(true)}\n style={{\n position: 'fixed',\n bottom: '24px',\n right: '24px',\n zIndex: 9998,\n width: '48px',\n height: '48px',\n borderRadius: '50%',\n background: 'linear-gradient(to bottom right, #a855f7, #ec4899)',\n color: 'white',\n boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n border: 'none',\n cursor: 'pointer',\n transition: 'all 0.2s',\n }}\n title=\"Open Studio\"\n aria-label=\"Open Studio media manager\"\n >\n <ImageIcon />\n </button>\n )}\n\n {/* Modal overlay with lazy-loaded UI */}\n {isOpen && (\n <div\n style={{\n position: 'fixed',\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n zIndex: 9999,\n }}\n >\n {/* Backdrop */}\n <div\n style={{\n position: 'absolute',\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n backdropFilter: 'blur(4px)',\n }}\n onClick={() => setIsOpen(false)}\n />\n\n {/* Modal */}\n <div\n style={{\n position: 'absolute',\n top: '32px',\n right: '32px',\n bottom: '32px',\n left: '32px',\n backgroundColor: 'white',\n borderRadius: '16px',\n boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.25)',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n }}\n >\n <Suspense fallback={<LoadingState />}>\n <StudioUI onClose={() => setIsOpen(false)} />\n </Suspense>\n </div>\n </div>\n )}\n </>\n )\n}\n\nfunction ImageIcon() {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"w-6 h-6\"\n >\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n </svg>\n )\n}\n\nfunction LoadingState() {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"flex flex-col items-center gap-4\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-purple-600\" />\n <p className=\"text-gray-500\">Loading Studio...</p>\n </div>\n </div>\n )\n}\n","import type { StudioMeta, ImageEntry, ImageSize, SizeEntry } from '../types'\n\n// Default empty meta - will be populated when reading from project\nlet _meta: StudioMeta = {\n $schema: 'https://gallop.software/schemas/studio-meta.json',\n version: 1,\n generatedAt: new Date().toISOString(),\n images: {},\n}\n\n/**\n * The meta object containing all image metadata.\n * This is read from _data/_meta.json in the consuming project.\n */\nexport const meta: StudioMeta = _meta\n\n/**\n * Initialize meta from a JSON object (called during build/runtime)\n */\nexport function initializeMeta(data: StudioMeta): void {\n _meta = data\n Object.assign(meta, data)\n}\n\n/**\n * Get the resolved URL for an image, handling CDN vs local paths\n */\nexport function getImageUrl(\n imageKey: string,\n size: ImageSize = 'medium'\n): string | undefined {\n const image = meta.images[imageKey]\n if (!image) return undefined\n\n const sizeData = image.sizes[size] || image.sizes.full\n if (!sizeData) return undefined\n\n // If synced to CDN, use CDN URL\n if (image.cdn?.synced && image.cdn.baseUrl) {\n return `${image.cdn.baseUrl}${sizeData.path}`\n }\n\n // Otherwise use local path\n return sizeData.path\n}\n\n/**\n * Get the full image entry for a key\n */\nexport function getStudioMeta(imageKey: string): ImageEntry | undefined {\n return meta.images[imageKey]\n}\n\n/**\n * Get size data for an image\n */\nexport function getImageSize(\n imageKey: string,\n size: ImageSize = 'medium'\n): SizeEntry | undefined {\n const image = meta.images[imageKey]\n if (!image) return undefined\n return image.sizes[size] || image.sizes.full\n}\n"]}
1
+ {"version":3,"sources":["/Users/chrisb/Sites/studio/dist/index.js","../src/components/StudioButton.tsx","../src/lib/meta.ts"],"names":[],"mappings":"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","file":"/Users/chrisb/Sites/studio/dist/index.js","sourcesContent":[null,"/** @jsxImportSource @emotion/react */\n'use client'\n\nimport { useState, lazy, Suspense } from 'react'\nimport { css, keyframes } from '@emotion/react'\n\n// Lazy load the full Studio UI to avoid bundling in production\nconst StudioUI = lazy(() => import('./StudioUI'))\n\nconst spin = keyframes`\n to {\n transform: rotate(360deg);\n }\n`\n\nconst styles = {\n button: css`\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 9998;\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: linear-gradient(to bottom right, #a855f7, #ec4899);\n color: white;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n cursor: pointer;\n transition: all 0.2s;\n \n &:hover {\n transform: scale(1.05);\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n }\n `,\n buttonIcon: css`\n width: 24px;\n height: 24px;\n `,\n overlay: css`\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 9999;\n `,\n backdrop: css`\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n background-color: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n `,\n modal: css`\n position: absolute;\n top: 32px;\n right: 32px;\n bottom: 32px;\n left: 32px;\n background-color: white;\n border-radius: 16px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n `,\n loading: css`\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n `,\n loadingContent: css`\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n `,\n spinner: css`\n width: 32px;\n height: 32px;\n border-radius: 50%;\n border: 2px solid transparent;\n border-bottom-color: #9333ea;\n animation: ${spin} 1s linear infinite;\n `,\n loadingText: css`\n color: #6b7280;\n font-size: 14px;\n margin: 0;\n `,\n}\n\n/**\n * Floating button that opens the Studio modal.\n * Fixed position in bottom-right corner.\n * Only renders in development mode.\n */\nexport function StudioButton() {\n const [isOpen, setIsOpen] = useState(false)\n\n // Only render in development\n if (process.env.NODE_ENV !== 'development') {\n return null\n }\n\n return (\n <>\n {!isOpen && (\n <button\n css={styles.button}\n onClick={() => setIsOpen(true)}\n title=\"Open Studio\"\n aria-label=\"Open Studio media manager\"\n >\n <ImageIcon />\n </button>\n )}\n\n {isOpen && (\n <div css={styles.overlay}>\n <div css={styles.backdrop} onClick={() => setIsOpen(false)} />\n <div css={styles.modal}>\n <Suspense fallback={<LoadingState />}>\n <StudioUI onClose={() => setIsOpen(false)} />\n </Suspense>\n </div>\n </div>\n )}\n </>\n )\n}\n\nfunction ImageIcon() {\n return (\n <svg\n css={styles.buttonIcon}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n </svg>\n )\n}\n\nfunction LoadingState() {\n return (\n <div css={styles.loading}>\n <div css={styles.loadingContent}>\n <div css={styles.spinner} />\n <p css={styles.loadingText}>Loading Studio...</p>\n </div>\n </div>\n )\n}\n","import type { StudioMeta, ImageEntry, ImageSize, SizeEntry } from '../types'\n\n// Default empty meta - will be populated when reading from project\nlet _meta: StudioMeta = {\n $schema: 'https://gallop.software/schemas/studio-meta.json',\n version: 1,\n generatedAt: new Date().toISOString(),\n images: {},\n}\n\n/**\n * The meta object containing all image metadata.\n * This is read from _data/_meta.json in the consuming project.\n */\nexport const meta: StudioMeta = _meta\n\n/**\n * Initialize meta from a JSON object (called during build/runtime)\n */\nexport function initializeMeta(data: StudioMeta): void {\n _meta = data\n Object.assign(meta, data)\n}\n\n/**\n * Get the resolved URL for an image, handling CDN vs local paths\n */\nexport function getImageUrl(\n imageKey: string,\n size: ImageSize = 'medium'\n): string | undefined {\n const image = meta.images[imageKey]\n if (!image) return undefined\n\n const sizeData = image.sizes[size] || image.sizes.full\n if (!sizeData) return undefined\n\n // If synced to CDN, use CDN URL\n if (image.cdn?.synced && image.cdn.baseUrl) {\n return `${image.cdn.baseUrl}${sizeData.path}`\n }\n\n // Otherwise use local path\n return sizeData.path\n}\n\n/**\n * Get the full image entry for a key\n */\nexport function getStudioMeta(imageKey: string): ImageEntry | undefined {\n return meta.images[imageKey]\n}\n\n/**\n * Get size data for an image\n */\nexport function getImageSize(\n imageKey: string,\n size: ImageSize = 'medium'\n): SizeEntry | undefined {\n const image = meta.images[imageKey]\n if (!image) return undefined\n return image.sizes[size] || image.sizes.full\n}\n"]}