Create standalone browser port of LTX Athena with authenticated native API transport
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
import type { Asset } from '../types/project-model'
|
||||
|
||||
export type GenSpaceTypeFilter = 'all' | 'video' | 'image'
|
||||
export type GenSpaceSortKey = 'createdAt' | 'type' | 'duration' | 'resolution' | 'ratio'
|
||||
export type GenSpaceSortDir = 'asc' | 'desc'
|
||||
|
||||
export const GENSPACE_TYPE_FILTER_OPTIONS: { value: GenSpaceTypeFilter; label: string }[] = [
|
||||
{ value: 'all', label: 'All' },
|
||||
{ value: 'video', label: 'Videos' },
|
||||
{ value: 'image', label: 'Images' },
|
||||
]
|
||||
|
||||
export const GENSPACE_SORT_OPTIONS: { value: GenSpaceSortKey; label: string }[] = [
|
||||
{ value: 'createdAt', label: 'Date' },
|
||||
{ value: 'type', label: 'Type' },
|
||||
{ value: 'duration', label: 'Duration' },
|
||||
{ value: 'resolution', label: 'Resolution' },
|
||||
{ value: 'ratio', label: 'Ratio' },
|
||||
]
|
||||
|
||||
const VISUAL_TYPES = new Set(['video', 'image'])
|
||||
|
||||
export function defaultSortDir(key: GenSpaceSortKey): GenSpaceSortDir {
|
||||
switch (key) {
|
||||
case 'createdAt':
|
||||
case 'duration':
|
||||
case 'resolution':
|
||||
case 'ratio':
|
||||
case 'type':
|
||||
return 'desc'
|
||||
}
|
||||
}
|
||||
|
||||
export function filterGenSpaceAssets(
|
||||
assets: Asset[],
|
||||
typeFilter: GenSpaceTypeFilter,
|
||||
favoritesOnly: boolean,
|
||||
): Asset[] {
|
||||
let result = assets.filter(asset => VISUAL_TYPES.has(asset.type))
|
||||
if (typeFilter !== 'all') {
|
||||
result = result.filter(asset => asset.type === typeFilter)
|
||||
}
|
||||
if (favoritesOnly) {
|
||||
result = result.filter(asset => asset.favorite)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function resolutionRank(asset: Asset): number {
|
||||
if (asset.width && asset.height) return Math.min(asset.width, asset.height)
|
||||
const match = asset.resolution?.match(/(\d+)/)
|
||||
return match ? parseInt(match[1], 10) : 0
|
||||
}
|
||||
|
||||
function durationRank(asset: Asset): number {
|
||||
return asset.duration ?? 0
|
||||
}
|
||||
|
||||
function parseAspectRatioString(value?: string): number {
|
||||
if (!value) return 0
|
||||
const match = value.match(/^(\d+(?:\.\d+)?)\s*:\s*(\d+(?:\.\d+)?)$/)
|
||||
if (!match) return 0
|
||||
const height = Number(match[2])
|
||||
return height === 0 ? 0 : Number(match[1]) / height
|
||||
}
|
||||
|
||||
function ratioRank(asset: Asset): number {
|
||||
if (asset.width && asset.height) return asset.width / asset.height
|
||||
return parseAspectRatioString(asset.generationParams?.imageAspectRatio)
|
||||
}
|
||||
|
||||
function compareTieBreak(a: Asset, b: Asset): number {
|
||||
if (a.createdAt !== b.createdAt) return b.createdAt - a.createdAt
|
||||
return a.id.localeCompare(b.id)
|
||||
}
|
||||
|
||||
function comparePrimary(a: Asset, b: Asset, key: GenSpaceSortKey): number {
|
||||
switch (key) {
|
||||
case 'type':
|
||||
return a.type.localeCompare(b.type)
|
||||
case 'duration':
|
||||
return durationRank(a) - durationRank(b)
|
||||
case 'resolution':
|
||||
return resolutionRank(a) - resolutionRank(b)
|
||||
case 'ratio':
|
||||
return ratioRank(a) - ratioRank(b)
|
||||
case 'createdAt':
|
||||
default:
|
||||
return a.createdAt - b.createdAt
|
||||
}
|
||||
}
|
||||
|
||||
export function sortGenSpaceAssets(
|
||||
assets: Asset[],
|
||||
key: GenSpaceSortKey,
|
||||
direction: GenSpaceSortDir,
|
||||
): Asset[] {
|
||||
const dir = direction === 'desc' ? -1 : 1
|
||||
return [...assets].sort((a, b) => {
|
||||
const primary = comparePrimary(a, b, key)
|
||||
if (primary !== 0) return dir * primary
|
||||
return compareTieBreak(a, b)
|
||||
})
|
||||
}
|
||||
|
||||
export function shouldShowGeneratingTile(
|
||||
typeFilter: GenSpaceTypeFilter,
|
||||
mode: 'image' | 'video',
|
||||
): boolean {
|
||||
if (typeFilter === 'all') return true
|
||||
return typeFilter === mode
|
||||
}
|
||||
Reference in New Issue
Block a user