diff --git a/src/routes/(app)/database/characters/[id]/+page.svelte b/src/routes/(app)/database/characters/[id]/+page.svelte index 77daaaef..abed119c 100644 --- a/src/routes/(app)/database/characters/[id]/+page.svelte +++ b/src/routes/(app)/database/characters/[id]/+page.svelte @@ -17,10 +17,10 @@ import CharacterUncapSection from '$lib/features/database/characters/sections/CharacterUncapSection.svelte' import CharacterTaxonomySection from '$lib/features/database/characters/sections/CharacterTaxonomySection.svelte' import CharacterStatsSection from '$lib/features/database/characters/sections/CharacterStatsSection.svelte' - import CharacterImagesSection from '$lib/features/database/characters/sections/CharacterImagesSection.svelte' import EntityImagesTab from '$lib/features/database/detail/tabs/EntityImagesTab.svelte' import EntityRawDataTab from '$lib/features/database/detail/tabs/EntityRawDataTab.svelte' import DetailsContainer from '$lib/components/ui/DetailsContainer.svelte' + import DetailItem from '$lib/components/ui/DetailItem.svelte' import { getCharacterImage } from '$lib/utils/images' // Types @@ -81,6 +81,9 @@ return getCharacterImage(character?.granblueId, 'grid', '01') } + // Available image sizes for characters + const characterSizes = ['detail', 'grid', 'main', 'square'] + // Generate image items for character (variants and poses based on uncap level) const characterImages = $derived.by((): ImageItem[] => { if (!character?.granblueId) return [] @@ -88,8 +91,7 @@ const variants = ['detail', 'grid', 'main', 'square'] as const const images: ImageItem[] = [] - // Determine available poses based on uncap level - // _01 = Base, _02 = MLB (3*), _03 = FLB (5*), _04 = Transcendence + // Only include poses that are available - _01 = Base, _02 = MLB (3*), _03 = FLB (5*), _04 = Transcendence const poses: { id: string; label: string }[] = [ { id: '01', label: 'Base' }, { id: '02', label: 'MLB' } @@ -103,19 +105,51 @@ poses.push({ id: '04', label: 'Transcendence' }) } - for (const variant of variants) { - for (const pose of poses) { + for (const pose of poses) { + for (const variant of variants) { images.push({ url: getCharacterImage(character.granblueId, variant, pose.id), label: `${variant} (${pose.label})`, variant, - pose: pose.id + pose: pose.id, + poseLabel: pose.label }) } } return images }) + + // Image download handlers + async function handleDownloadImage(size: string, transformation: string | undefined, force: boolean) { + if (!character?.id) return + await entityAdapter.downloadCharacterImage(character.id, size, transformation, force) + } + + async function handleDownloadAllPose(pose: string, force: boolean) { + if (!character?.id) return + // Download all sizes for this pose + for (const size of characterSizes) { + await entityAdapter.downloadCharacterImage(character.id, size, pose, force) + } + } + + async function handleDownloadAllImages(force: boolean) { + if (!character?.id) return + await entityAdapter.downloadCharacterImages(character.id, { force }) + } + + async function handleDownloadSize(size: string) { + if (!character?.id) return + // Download this size for all available poses + const poses = ['01', '02'] + if (character.uncap?.flb) poses.push('03') + if (character.uncap?.transcendence) poses.push('04') + + for (const pose of poses) { + await entityAdapter.downloadCharacterImage(character.id, size, pose, false) + } + }
@@ -128,6 +162,9 @@ editUrl={canEdit ? editUrl : undefined} {currentTab} onTabChange={handleTabChange} + onDownloadAllImages={canEdit ? handleDownloadAllImages : undefined} + onDownloadSize={canEdit ? handleDownloadSize : undefined} + availableSizes={characterSizes} > {#if currentTab === 'info'}
@@ -136,12 +173,18 @@ - {#if character?.id && character?.granblueId} - + {#if character.releaseDate || character.flbDate || character.ulbDate} + + {#if character.releaseDate} + + {/if} + {#if character.flbDate} + + {/if} + {#if character.ulbDate} + + {/if} + {/if} {#if relatedQuery.data?.length} @@ -162,13 +205,26 @@ {/if}
{:else if currentTab === 'images'} - + {:else if currentTab === 'raw'} { + const result = await entityAdapter.fetchCharacterWiki(character.id) + rawDataQuery.refetch() + return result + } + : undefined} /> {/if} diff --git a/src/routes/(app)/database/summons/[id]/+page.svelte b/src/routes/(app)/database/summons/[id]/+page.svelte index ae1b9167..e1ab1c57 100644 --- a/src/routes/(app)/database/summons/[id]/+page.svelte +++ b/src/routes/(app)/database/summons/[id]/+page.svelte @@ -19,6 +19,8 @@ import SummonStatsSection from '$lib/features/database/summons/sections/SummonStatsSection.svelte' import EntityImagesTab from '$lib/features/database/detail/tabs/EntityImagesTab.svelte' import EntityRawDataTab from '$lib/features/database/detail/tabs/EntityRawDataTab.svelte' + import DetailsContainer from '$lib/components/ui/DetailsContainer.svelte' + import DetailItem from '$lib/components/ui/DetailItem.svelte' import { getSummonImage } from '$lib/utils/images' // Types @@ -69,23 +71,85 @@ return getSummonImage(summon?.granblueId, 'grid') } + // Available image sizes for summons + const summonSizes = ['detail', 'grid', 'main', 'square', 'wide'] + // Generate image items for summon (detail, grid, main, square, wide variants) + // Summons have transformations: Base (no suffix), ULB (_02), Transcendence Stage 1 (_03), Transcendence Stage 5 (_04) const summonImages = $derived.by((): ImageItem[] => { if (!summon?.granblueId) return [] const variants = ['detail', 'grid', 'main', 'square', 'wide'] as const const images: ImageItem[] = [] - for (const variant of variants) { - images.push({ - url: getSummonImage(summon.granblueId, variant), - label: variant, - variant - }) + // Only include transformations that are available + const transformations: { id: string; label: string; suffix?: string }[] = [ + { id: '01', label: 'Base', suffix: undefined } + ] + + if (summon.uncap?.ulb) { + transformations.push({ id: '02', label: 'ULB', suffix: '02' }) + } + + if (summon.uncap?.transcendence) { + transformations.push( + { id: '03', label: 'Transcendence (1)', suffix: '03' }, + { id: '04', label: 'Transcendence (5)', suffix: '04' } + ) + } + + for (const transformation of transformations) { + for (const variant of variants) { + images.push({ + url: getSummonImage(summon.granblueId, variant, transformation.suffix), + label: `${variant} (${transformation.label})`, + variant, + pose: transformation.id, + poseLabel: transformation.label + }) + } } return images }) + + // Image download handlers + async function handleDownloadImage(size: string, transformation: string | undefined, force: boolean) { + if (!summon?.id) return + // For summons, '01' means base (no transformation suffix) + const trans = transformation === '01' ? undefined : transformation + await entityAdapter.downloadSummonImage(summon.id, size, trans, force) + } + + async function handleDownloadAllPose(pose: string, force: boolean) { + if (!summon?.id) return + const trans = pose === '01' ? undefined : pose + // Download all sizes for this pose + for (const size of summonSizes) { + await entityAdapter.downloadSummonImage(summon.id, size, trans, force) + } + } + + async function handleDownloadAllImages(force: boolean) { + if (!summon?.id) return + await entityAdapter.downloadSummonImages(summon.id, { force }) + } + + async function handleDownloadSize(size: string) { + if (!summon?.id) return + // Download this size for all available transformations + const transformations: (string | undefined)[] = [undefined] + if (summon.uncap?.ulb) { + transformations.push('02') + } + if (summon.uncap?.transcendence) { + transformations.push('03', '04') + } + + for (const trans of transformations) { + await entityAdapter.downloadSummonImage(summon.id, size, trans, false) + } + }
@@ -98,6 +162,9 @@ editUrl={canEdit ? editUrl : undefined} {currentTab} onTabChange={handleTabChange} + onDownloadAllImages={canEdit ? handleDownloadAllImages : undefined} + onDownloadSize={canEdit ? handleDownloadSize : undefined} + availableSizes={summonSizes} > {#if currentTab === 'info'}
@@ -147,15 +214,45 @@
{/if}
+ + {#if summon.releaseDate || summon.flbDate || summon.ulbDate || summon.transcendenceDate} + + {#if summon.releaseDate} + + {/if} + {#if summon.flbDate} + + {/if} + {#if summon.ulbDate} + + {/if} + {#if summon.transcendenceDate} + + {/if} + + {/if} {:else if currentTab === 'images'} - + {:else if currentTab === 'raw'} { + const result = await entityAdapter.fetchSummonWiki(summon.id) + rawDataQuery.refetch() + return result + } + : undefined} /> {/if} diff --git a/src/routes/(app)/database/weapons/[id]/+page.svelte b/src/routes/(app)/database/weapons/[id]/+page.svelte index a94737fc..311537b2 100644 --- a/src/routes/(app)/database/weapons/[id]/+page.svelte +++ b/src/routes/(app)/database/weapons/[id]/+page.svelte @@ -19,6 +19,8 @@ import WeaponStatsSection from '$lib/features/database/weapons/sections/WeaponStatsSection.svelte' import EntityImagesTab from '$lib/features/database/detail/tabs/EntityImagesTab.svelte' import EntityRawDataTab from '$lib/features/database/detail/tabs/EntityRawDataTab.svelte' + import DetailsContainer from '$lib/components/ui/DetailsContainer.svelte' + import DetailItem from '$lib/components/ui/DetailItem.svelte' import { getWeaponGridImage, getWeaponImage as getWeaponImageUrl } from '$lib/utils/images' // Types @@ -69,23 +71,78 @@ return getWeaponGridImage(weapon?.granblueId, weapon?.element, weapon?.instanceElement) } + // Available image sizes for weapons + const weaponSizes = ['base', 'grid', 'main', 'square'] + // Generate image items for weapon (base, grid, main, square variants) + // Weapons have transformations: Base (no suffix), Transcendence Stage 1 (_02), Transcendence Stage 5 (_03) const weaponImages = $derived.by((): ImageItem[] => { if (!weapon?.granblueId) return [] const variants = ['base', 'grid', 'main', 'square'] as const const images: ImageItem[] = [] - for (const variant of variants) { - images.push({ - url: getWeaponImageUrl(weapon.granblueId, variant), - label: variant, - variant - }) + // Only include transformations that are available + const transformations: { id: string; label: string; suffix?: string }[] = [ + { id: '01', label: 'Base', suffix: undefined } + ] + + if (weapon.uncap?.transcendence) { + transformations.push( + { id: '02', label: 'Transcendence (1)', suffix: '02' }, + { id: '03', label: 'Transcendence (5)', suffix: '03' } + ) + } + + for (const transformation of transformations) { + for (const variant of variants) { + images.push({ + url: getWeaponImageUrl(weapon.granblueId, variant, undefined, transformation.suffix), + label: `${variant} (${transformation.label})`, + variant, + pose: transformation.id, + poseLabel: transformation.label + }) + } } return images }) + + // Image download handlers + async function handleDownloadImage(size: string, transformation: string | undefined, force: boolean) { + if (!weapon?.id) return + // For weapons, '01' means base (no transformation suffix) + const trans = transformation === '01' ? undefined : transformation + await entityAdapter.downloadWeaponImage(weapon.id, size, trans, force) + } + + async function handleDownloadAllPose(pose: string, force: boolean) { + if (!weapon?.id) return + const trans = pose === '01' ? undefined : pose + // Download all sizes for this pose + for (const size of weaponSizes) { + await entityAdapter.downloadWeaponImage(weapon.id, size, trans, force) + } + } + + async function handleDownloadAllImages(force: boolean) { + if (!weapon?.id) return + await entityAdapter.downloadWeaponImages(weapon.id, { force }) + } + + async function handleDownloadSize(size: string) { + if (!weapon?.id) return + // Download this size for all available transformations + const transformations: (string | undefined)[] = [undefined] + if (weapon.uncap?.transcendence) { + transformations.push('02', '03') + } + + for (const trans of transformations) { + await entityAdapter.downloadWeaponImage(weapon.id, size, trans, false) + } + }
@@ -98,6 +155,9 @@ editUrl={canEdit ? editUrl : undefined} {currentTab} onTabChange={handleTabChange} + onDownloadAllImages={canEdit ? handleDownloadAllImages : undefined} + onDownloadSize={canEdit ? handleDownloadSize : undefined} + availableSizes={weaponSizes} > {#if currentTab === 'info'}
@@ -123,15 +183,45 @@ {/if}
+ + {#if weapon.releaseDate || weapon.flbDate || weapon.ulbDate || weapon.transcendenceDate} + + {#if weapon.releaseDate} + + {/if} + {#if weapon.flbDate} + + {/if} + {#if weapon.ulbDate} + + {/if} + {#if weapon.transcendenceDate} + + {/if} + + {/if} {:else if currentTab === 'images'} - + {:else if currentTab === 'raw'} { + const result = await entityAdapter.fetchWeaponWiki(weapon.id) + rawDataQuery.refetch() + return result + } + : undefined} /> {/if}