* Test color palette extraction * Fix import * Add hex <> oklch conversions * Add 'hue' storage to photos * Consolidate color modules * Add chromatic config, track missing color data * Bump deps * Fix lens text test * Finalize color storage * Refactor color imports * Hide form color data when disabled * Store all average oklch color components * Finalize color-config language * Optimize photo syncing for color data * Only update color data when syncing if possible * Build out all color sorts * Debug image colors * Improve color debugging * Improve color logging * Simplify color sorting * Bump deps * Fix color sync logic * Switch to sort params: ascending, descending * Fix commandk sort menu * Update tr-tr sorting language * Add color capture to all photo extractions * Add color visualization to photo form * Standardize photo update language * Create global debug color update function * Improve color data capture logging * Update maximum function duration for admin photos * Add note to remove maxDuration * Use AI to generate sorting color * Conditionally use AI to analyze colors * Manage AI color analysis batched requests * Fix color reporting in admin photo table * Only update color where AI fields are missing * Temporarily upgrade admin/photos timeout * Fix pro-based max duration * Standardize color sorting foundations * Update color sorting language * Refactor color calculations * Restore max duration time * Update color-based sort menu labels * Finalize color documentation * Clean up color test actions * Round color sort values before submitting to db * Consolidate color server actions
131 lines
4.5 KiB
TypeScript
131 lines
4.5 KiB
TypeScript
'use client';
|
|
|
|
import { clsx } from 'clsx/lite';
|
|
import AppGrid from '@/components/AppGrid';
|
|
import AdminPhotosTable from '@/admin/AdminPhotosTable';
|
|
import AdminPhotosTableInfinite from '@/admin/AdminPhotosTableInfinite';
|
|
import PathLoaderButton from '@/components/primitives/PathLoaderButton';
|
|
import { PATH_ADMIN_PHOTOS_UPDATES } from '@/app/path';
|
|
import { Photo } from '@/photo';
|
|
import { StorageListResponse } from '@/platforms/storage';
|
|
import AdminUploadsTable from './AdminUploadsTable';
|
|
import { Timezone } from '@/utility/timezone';
|
|
import { useAppState } from '@/app/AppState';
|
|
import PhotoUploadWithStatus from '@/photo/PhotoUploadWithStatus';
|
|
import { pluralize } from '@/utility/string';
|
|
import IconBroom from '@/components/icons/IconBroom';
|
|
import ResponsiveText from '@/components/primitives/ResponsiveText';
|
|
import { useAppText } from '@/i18n/state/client';
|
|
import SyncColorButton from '@/photo/color/SyncColorButton';
|
|
|
|
export default function AdminPhotosClient({
|
|
photos,
|
|
photosCount,
|
|
photosCountNeedsSync,
|
|
blobPhotoUrls,
|
|
shouldResize,
|
|
hasAiTextGeneration,
|
|
onLastUpload,
|
|
infiniteScrollInitial,
|
|
infiniteScrollMultiple,
|
|
timezone,
|
|
debugColorData,
|
|
}: {
|
|
photos: Photo[]
|
|
photosCount: number
|
|
photosCountNeedsSync: number
|
|
blobPhotoUrls: StorageListResponse
|
|
shouldResize: boolean
|
|
hasAiTextGeneration: boolean
|
|
onLastUpload: () => Promise<void>
|
|
infiniteScrollInitial: number
|
|
infiniteScrollMultiple: number
|
|
timezone: Timezone
|
|
debugColorData?: boolean
|
|
}) {
|
|
const { uploadState: { isUploading } } = useAppState();
|
|
|
|
const appText = useAppText();
|
|
|
|
return (
|
|
<AppGrid
|
|
contentMain={
|
|
<div className="space-y-4">
|
|
<div className="flex gap-4">
|
|
<div className="grow min-w-0">
|
|
<PhotoUploadWithStatus
|
|
inputId="admin-photos"
|
|
shouldResize={shouldResize}
|
|
onLastUpload={onLastUpload}
|
|
/>
|
|
</div>
|
|
{debugColorData &&
|
|
<SyncColorButton />}
|
|
{photosCountNeedsSync > 0 &&
|
|
<PathLoaderButton
|
|
path={PATH_ADMIN_PHOTOS_UPDATES}
|
|
icon={<IconBroom
|
|
size={18}
|
|
className="translate-x-[-1px]"
|
|
/>}
|
|
tooltip={(
|
|
pluralize(
|
|
photosCountNeedsSync,
|
|
appText.photo.photo,
|
|
appText.photo.photoPlural.toLocaleLowerCase(),
|
|
) +
|
|
' missing data or AI-generated text'
|
|
)}
|
|
className={clsx(
|
|
'text-blue-600 dark:text-blue-400',
|
|
'border border-blue-200 dark:border-blue-800/60',
|
|
'active:bg-blue-50 dark:active:bg-blue-950/50',
|
|
'disabled:bg-blue-50 dark:disabled:bg-blue-950/50',
|
|
isUploading && 'hidden md:inline-flex',
|
|
)}
|
|
spinnerColor="text"
|
|
spinnerClassName="text-blue-200 dark:text-blue-600/40"
|
|
hideText="never"
|
|
>
|
|
<ResponsiveText shortText={photosCountNeedsSync}>
|
|
{pluralize(
|
|
photosCountNeedsSync,
|
|
appText.admin.update,
|
|
appText.admin.updatePlural,
|
|
)}
|
|
</ResponsiveText>
|
|
</PathLoaderButton>}
|
|
</div>
|
|
{blobPhotoUrls.length > 0 &&
|
|
<div className={clsx(
|
|
'border-b pb-6',
|
|
'border-gray-200 dark:border-gray-700',
|
|
'space-y-4',
|
|
)}>
|
|
<div className="font-bold">
|
|
Photo Blobs ({blobPhotoUrls.length})
|
|
</div>
|
|
<AdminUploadsTable urlAddStatuses={blobPhotoUrls} />
|
|
</div>}
|
|
{/* Use custom spacing to address gap/space-y compatibility quirks */}
|
|
<div className="space-y-[6px] sm:space-y-[10px]">
|
|
<AdminPhotosTable
|
|
photos={photos}
|
|
hasAiTextGeneration={hasAiTextGeneration}
|
|
timezone={timezone}
|
|
debugColorData={debugColorData}
|
|
/>
|
|
{photosCount > photos.length &&
|
|
<AdminPhotosTableInfinite
|
|
initialOffset={infiniteScrollInitial}
|
|
itemsPerPage={infiniteScrollMultiple}
|
|
hasAiTextGeneration={hasAiTextGeneration}
|
|
timezone={timezone}
|
|
debugColorData={debugColorData}
|
|
/>}
|
|
</div>
|
|
</div>}
|
|
/>
|
|
);
|
|
}
|