Fix screenshot gallery layout and timeframe descriptions

- Extract both layout and timeframe information from filenames
- Group screenshots by layout (AI Layout, DIY Module)
- Sort timeframes within each layout group ascending (5m -> 4h)
- Display proper layout names and timeframes in descriptions
- Organize display as: first layout ascending, then second layout ascending
- Improve screenshot alt text with layout and timeframe info

Screenshots now properly show:
Top row: AI Layout (5m, 15m, 30m)
Bottom row: DIY Module (5m, 15m, 30m)
This commit is contained in:
mindesbunister
2025-07-17 13:09:46 +02:00
parent 01f4a9f89a
commit 8372b271cb

View File

@@ -48,11 +48,29 @@ export default function ScreenshotGallery({
return parseInt(tf) || 999 return parseInt(tf) || 999
} }
// Extract timeframe from filename // Extract layout and timeframe from filename
const extractTimeframeFromFilename = (filename: string) => { const extractInfoFromFilename = (filename: string) => {
const match = filename.match(/_(\d+|D)_/) // Pattern: SYMBOL_TIMEFRAME_LAYOUT_TIMESTAMP.png
if (!match) return 'Unknown' // e.g., SOLUSD_5_ai_1752749431435.png or SOLUSD_15_Diy module_1752749479893.png
const tf = match[1] const parts = filename.replace('.png', '').split('_')
if (parts.length >= 4) {
const timeframe = parts[1]
const layout = parts.slice(2, -1).join('_') // Handle "Diy module" with space
return { timeframe, layout }
}
// Fallback: try to extract from anywhere in filename
const timeframeMatch = filename.match(/_(\d+|D)_/)
const layoutMatch = filename.match(/_(ai|Diy module|diy)_/)
return {
timeframe: timeframeMatch ? timeframeMatch[1] : 'Unknown',
layout: layoutMatch ? layoutMatch[1] : 'Unknown'
}
}
// Format timeframe for display
const formatTimeframe = (tf: string): string => {
if (tf === 'D') return '1D' if (tf === 'D') return '1D'
if (tf === '5') return '5m' if (tf === '5') return '5m'
if (tf === '15') return '15m' if (tf === '15') return '15m'
@@ -63,26 +81,61 @@ export default function ScreenshotGallery({
return `${tf}m` return `${tf}m`
} }
// Create sorted screenshot data with timeframes // Format layout name for display
const formatLayoutName = (layout: string): string => {
if (layout === 'ai') return 'AI Layout'
if (layout === 'Diy module') return 'DIY Module'
return layout
}
// Create screenshot data with extracted info
const screenshotData = screenshots.map((screenshot, index) => { const screenshotData = screenshots.map((screenshot, index) => {
const screenshotUrl = typeof screenshot === 'string' const screenshotUrl = typeof screenshot === 'string'
? screenshot ? screenshot
: (screenshot as any)?.url || String(screenshot) : (screenshot as any)?.url || String(screenshot)
const filename = screenshotUrl.split('/').pop() || '' const filename = screenshotUrl.split('/').pop() || ''
const timeframe = timeframes[index] || extractTimeframeFromFilename(filename) const { timeframe, layout } = extractInfoFromFilename(filename)
return { return {
screenshot, screenshot,
screenshotUrl, screenshotUrl,
filename, filename,
timeframe, timeframe,
layout,
displayTimeframe: formatTimeframe(timeframe),
displayLayout: formatLayoutName(layout),
index, index,
sortOrder: timeframeToMinutes(timeframe) sortOrder: timeframeToMinutes(formatTimeframe(timeframe))
} }
}) })
// Sort by timeframe (smallest to largest) // Group by layout and sort within each group
const sortedData = screenshotData.sort((a, b) => a.sortOrder - b.sortOrder) const groupedData = screenshotData.reduce((acc: any, item) => {
if (!acc[item.layout]) {
acc[item.layout] = []
}
acc[item.layout].push(item)
return acc
}, {})
// Sort each layout group by timeframe and combine
// First layout (ai), then second layout (Diy module)
const layoutOrder = ['ai', 'Diy module']
const sortedData = layoutOrder.reduce((result: any[], layoutKey) => {
if (groupedData[layoutKey]) {
const sortedGroup = groupedData[layoutKey].sort((a: any, b: any) => a.sortOrder - b.sortOrder)
result.push(...sortedGroup)
}
return result
}, [])
// Add any remaining layouts not in the predefined order
Object.keys(groupedData).forEach(layoutKey => {
if (!layoutOrder.includes(layoutKey)) {
const sortedGroup = groupedData[layoutKey].sort((a: any, b: any) => a.sortOrder - b.sortOrder)
sortedData.push(...sortedGroup)
}
})
// Helper function to format screenshot URL // Helper function to format screenshot URL
const formatScreenshotUrl = (screenshot: string | any) => { const formatScreenshotUrl = (screenshot: string | any) => {
@@ -124,7 +177,7 @@ export default function ScreenshotGallery({
<div className="aspect-video bg-gray-800 flex items-center justify-center relative"> <div className="aspect-video bg-gray-800 flex items-center justify-center relative">
<img <img
src={imageUrl} src={imageUrl}
alt={`${symbol} - ${item.timeframe} chart`} alt={`${symbol} - ${item.displayLayout} - ${item.displayTimeframe} chart`}
className="w-full h-full object-cover" className="w-full h-full object-cover"
onError={(e: any) => { onError={(e: any) => {
const target = e.target as HTMLImageElement const target = e.target as HTMLImageElement
@@ -156,7 +209,8 @@ export default function ScreenshotGallery({
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<div className="text-sm font-medium text-white">{symbol}</div> <div className="text-sm font-medium text-white">{symbol}</div>
<div className="text-xs text-purple-300">{item.timeframe} Timeframe</div> <div className="text-xs text-purple-300">{item.displayLayout}</div>
<div className="text-xs text-gray-400">{item.displayTimeframe} Timeframe</div>
</div> </div>
<div className="text-xs text-gray-400"> <div className="text-xs text-gray-400">
Click to view Click to view