feat: initial release v0.3.0

This commit is contained in:
saturn
2026-03-08 03:15:27 +08:00
commit 881ed44996
1311 changed files with 225407 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import {
getImageGenerationCountConfig,
getImageGenerationCountOptions,
normalizeImageGenerationCount,
} from '@/lib/image-generation/count'
import {
getImageGenerationCount,
setImageGenerationCount,
} from '@/lib/image-generation/count-preference'
describe('image generation count helpers', () => {
afterEach(() => {
vi.unstubAllGlobals()
})
it('normalizes values within each scope range', () => {
expect(normalizeImageGenerationCount('character', 0)).toBe(1)
expect(normalizeImageGenerationCount('character', 8)).toBe(6)
expect(normalizeImageGenerationCount('storyboard-candidates', 0)).toBe(1)
expect(normalizeImageGenerationCount('storyboard-candidates', 9)).toBe(4)
})
it('returns ordered options for each scope', () => {
expect(getImageGenerationCountOptions('character')).toEqual([1, 2, 3, 4, 5, 6])
expect(getImageGenerationCountOptions('storyboard-candidates')).toEqual([1, 2, 3, 4])
})
it('reads and writes client preference with scope isolation', () => {
const localStorageMock = {
getItem: vi.fn((key: string) => {
if (key === getImageGenerationCountConfig('character').storageKey) return '5'
if (key === getImageGenerationCountConfig('location').storageKey) return '2'
return null
}),
setItem: vi.fn(),
}
vi.stubGlobal('window', { localStorage: localStorageMock })
expect(getImageGenerationCount('character')).toBe(5)
expect(getImageGenerationCount('location')).toBe(2)
expect(setImageGenerationCount('storyboard-candidates', 8)).toBe(4)
expect(localStorageMock.setItem).toHaveBeenCalledWith(
getImageGenerationCountConfig('storyboard-candidates').storageKey,
'4',
)
})
})

View File

@@ -0,0 +1,101 @@
import { describe, expect, it } from 'vitest'
import {
countGeneratedImageSlots,
resolveDisplayImageSlots,
resolveGroupedImageSlotPhase,
resolveImageSlotPhase,
shouldShowImageSlotGrid,
} from '@/lib/image-generation/slot-state'
describe('image slot state', () => {
it('counts only slots with image urls', () => {
expect(countGeneratedImageSlots([
{ imageUrl: 'a.png' },
{ imageUrl: null },
{ imageUrl: 'b.png' },
])).toBe(2)
})
it('distinguishes generate and regenerate phases', () => {
expect(resolveImageSlotPhase({ imageUrl: null }, true)).toBe('generating')
expect(resolveImageSlotPhase({ imageUrl: 'a.png' }, true)).toBe('regenerating')
expect(resolveImageSlotPhase({ imageUrl: null }, false)).toBe('idle-empty')
expect(resolveImageSlotPhase({ imageUrl: 'a.png' }, false)).toBe('idle-filled')
})
it('keeps completed filled slots idle while the group still has empty pending slots', () => {
expect(resolveGroupedImageSlotPhase(
{ imageUrl: 'a.png' },
{ isGroupRunning: true, isSlotRunning: false, hasPendingEmptySlots: true },
)).toBe('idle-filled')
expect(resolveGroupedImageSlotPhase(
{ imageUrl: null },
{ isGroupRunning: true, isSlotRunning: true, hasPendingEmptySlots: true },
)).toBe('generating')
})
it('hides legacy empty slots when the location is idle', () => {
const displaySlots = resolveDisplayImageSlots([
{ imageUrl: 'a.png' },
{ imageUrl: null },
{ imageUrl: null },
], {
hasRunningTask: false,
requestedCount: 1,
})
expect(displaySlots).toHaveLength(1)
expect(displaySlots[0]?.imageUrl).toBe('a.png')
})
it('shows only one slot while running a single-image location generation', () => {
const displaySlots = resolveDisplayImageSlots([
{ imageUrl: null },
{ imageUrl: null },
{ imageUrl: null },
], {
hasRunningTask: true,
requestedCount: 1,
})
expect(displaySlots).toHaveLength(1)
})
it('shows requested placeholders while running a multi-image location generation', () => {
const displaySlots = resolveDisplayImageSlots([
{ imageUrl: 'a.png' },
{ imageUrl: null },
{ imageUrl: null },
{ imageUrl: null },
], {
hasRunningTask: true,
requestedCount: 4,
})
expect(displaySlots).toHaveLength(4)
})
it('shows slot grid only after generation is active or meaningful', () => {
expect(shouldShowImageSlotGrid({
totalSlotCount: 3,
generatedCount: 0,
hasRunningTask: false,
hasAnyError: false,
})).toBe(false)
expect(shouldShowImageSlotGrid({
totalSlotCount: 3,
generatedCount: 0,
hasRunningTask: true,
hasAnyError: false,
})).toBe(true)
expect(shouldShowImageSlotGrid({
totalSlotCount: 3,
generatedCount: 1,
hasRunningTask: false,
hasAnyError: false,
})).toBe(true)
})
})