このコミットが含まれているのは:
2026-07-12 14:03:05 +09:00
コミット aa96ec95d1
10個のファイルの変更1469行の追加639行の削除
+149
ファイルの表示
@@ -0,0 +1,149 @@
import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils'
import PostImportStatusBadge from '@/components/posts/import/PostImportStatusBadge'
import ThumbnailPreview from '@/components/posts/import/ThumbnailPreview'
import type { FC } from 'react'
import type { PostImportRow } from '@/lib/postImportSession'
type Props = {
row: PostImportRow
onEdit: () => void }
const toneClass = (row: PostImportRow): string[] => {
const value = row.importStatus ?? row.status
switch (value)
{
case 'created':
return [
'border-sky-200 bg-sky-50',
'dark:border-sky-900 dark:bg-sky-950/30']
case 'skipped':
return [
'border-stone-200 bg-stone-50',
'dark:border-stone-800 dark:bg-stone-900/60']
case 'failed':
case 'error':
return [
'border-rose-200 bg-rose-50',
'dark:border-rose-900 dark:bg-rose-950/30']
case 'warning':
return [
'border-amber-200 bg-amber-50',
'dark:border-amber-900 dark:bg-amber-950/30']
default:
return [
'border-border bg-white',
'dark:border-neutral-700 dark:bg-neutral-900']
}
}
const summaryError = (row: PostImportRow): string | null => {
const validation = Object.values (row.validationErrors ?? { }).flat ()[0]
if (validation)
return validation
return Object.values (row.importErrors ?? { }).flat ()[0] ?? null
}
const summaryDate = (row: PostImportRow): string =>
[row.attributes.originalCreatedFrom, row.attributes.originalCreatedBefore]
.filter (_1 => typeof _1 === 'string' && _1 !== '')
.join (' ~ ')
const PostImportRowSummary: FC<Props> = ({ row, onEdit }) => {
const error = summaryError (row)
const importStatus = row.importStatus ?? 'pending'
return (
<>
<div
className={cn (
'hidden items-center gap-4 rounded-lg border p-4 md:grid',
'md:grid-cols-[4rem_5rem_minmax(0,1fr)_auto_auto_auto]',
toneClass (row),
'hover:bg-slate-50',
'dark:hover:bg-neutral-800',
)}>
<div className="space-y-1">
<div className="text-sm font-medium">#{row.sourceRow}</div>
<PostImportStatusBadge value={row.status}/>
</div>
<ThumbnailPreview
url={String (row.attributes.thumbnailBase ?? '')}
className="h-16 w-16"/>
<div className="min-w-0 space-y-1">
<div className="line-clamp-2 text-sm font-medium">
{String (row.attributes.title ?? '') || '(タイトル未取得)'}
</div>
<div className="truncate text-xs text-neutral-600 dark:text-neutral-300">
{row.url}
</div>
<div className="truncate text-xs text-neutral-500 dark:text-neutral-400">
{String (row.attributes.tags ?? '') || 'タグなし'}
</div>
<div className="text-xs text-neutral-500 dark:text-neutral-400">
{summaryDate (row) || '日時未取得'}
{row.attributes.duration ? ` / ${ row.attributes.duration }` : ''}
</div>
</div>
<div className="space-y-1">
<PostImportStatusBadge value={importStatus}/>
</div>
<div className="space-y-1">
{error
? <PostImportStatusBadge value="error"/>
: <PostImportStatusBadge value="ready"/>}
</div>
<div className="flex justify-end">
<Button
type="button"
variant="outline"
onClick={onEdit}
disabled={row.importStatus === 'created'}>
</Button>
</div>
</div>
<div
className={cn (
'space-y-3 rounded-lg border p-4 md:hidden',
toneClass (row),
)}>
<div className="flex items-start gap-3">
<ThumbnailPreview
url={String (row.attributes.thumbnailBase ?? '')}
className="h-20 w-20 shrink-0"/>
<div className="min-w-0 flex-1 space-y-2">
<div className="line-clamp-2 text-sm font-medium">
{String (row.attributes.title ?? '') || '(タイトル未取得)'}
</div>
<div className="truncate text-xs text-neutral-600 dark:text-neutral-300">
{row.url}
</div>
<div className="flex flex-wrap gap-2">
<PostImportStatusBadge value={row.status}/>
<PostImportStatusBadge value={importStatus}/>
</div>
{error && (
<div className="text-xs text-red-700 dark:text-red-200">
{error}
</div>)}
</div>
</div>
<Button
type="button"
variant="outline"
onClick={onEdit}
disabled={row.importStatus === 'created'}>
</Button>
</div>
</>)
}
export default PostImportRowSummary