このコミットが含まれているのは:
2026-07-15 20:25:51 +09:00
コミット d2f1b1ed48
13個のファイルの変更85行の追加196行の削除
+6 -23
ファイルの表示
@@ -3,12 +3,8 @@ import { cn } from '@/lib/utils'
import type { FC, ReactNode } from 'react'
export type StatusBadgeTone =
'danger'
| 'default'
| 'info'
| 'manual'
| 'ready'
| 'skipped'
'success'
| 'neutral'
| 'warning'
type Props = {
@@ -16,35 +12,22 @@ type Props = {
tone: StatusBadgeTone }
const TONES: Record<StatusBadgeTone, string[]> = {
default: [
'border-slate-300 bg-slate-50 text-slate-700',
'dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200'],
ready: [
success: [
'border-emerald-300 bg-emerald-50 text-emerald-700',
'dark:border-emerald-900 dark:bg-emerald-950 dark:text-emerald-200'],
warning: [
'border-amber-300 bg-amber-50 text-amber-700',
'dark:border-amber-900 dark:bg-amber-950 dark:text-amber-200'],
danger: [
'border-rose-300 bg-rose-50 text-rose-700',
'dark:border-rose-900 dark:bg-rose-950 dark:text-rose-200'],
info: [
'border-sky-300 bg-sky-50 text-sky-700',
'dark:border-sky-900 dark:bg-sky-950 dark:text-sky-200'],
skipped: [
neutral: [
'border-stone-300 bg-stone-50 text-stone-700',
'dark:border-stone-700 dark:bg-stone-900 dark:text-stone-200'],
manual: [
'border-purple-300 bg-purple-50 text-purple-700',
'dark:border-purple-900 dark:bg-purple-950 dark:text-purple-200'] }
'dark:border-stone-700 dark:bg-stone-900 dark:text-stone-200'] }
const StatusBadge: FC<Props> = ({ children, tone }) => (
<span
className={cn (
'inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium',
TONES[tone],
)}>
TONES[tone])}>
{children}
</span>)
+16 -23
ファイルの表示
@@ -70,10 +70,14 @@ const PostImportRowDialog: FC<Props> = (
{ open, row, messageRow, saving, onOpenChange, onSave },
) => {
const [draft, setDraft] = useState<Draft | null> (null)
const [resetRequested, setResetRequested] = useState (false)
useEffect (() => {
if (open && row)
setDraft (buildDraft (row))
{
setDraft (buildDraft (row))
setResetRequested (false)
}
}, [open, row])
if (row == null || draft == null)
@@ -90,12 +94,10 @@ const PostImportRowDialog: FC<Props> = (
}
const save = async () => {
if (
await onSave ({
draft,
resetRequested: false,
resetSnapshot: row.resetSnapshot })
)
if (await onSave ({
draft,
resetRequested,
resetSnapshot: row.resetSnapshot }))
onOpenChange (false)
}
@@ -139,8 +141,7 @@ const PostImportRowDialog: FC<Props> = (
warnings={displayRow.fieldWarnings.thumbnailBase}
errors={groupedMessages (
displayRow.validationErrors.thumbnailBase,
displayRow.importErrors?.thumbnailBase,
)}
displayRow.importErrors?.thumbnailBase)}
onChange={value => update ('thumbnailBase', value)}/>
<PostOriginalCreatedTimeField
originalCreatedFrom={draft.originalCreatedFrom || null}
@@ -153,8 +154,7 @@ const PostImportRowDialog: FC<Props> = (
displayRow.validationErrors.originalCreatedBefore,
displayRow.importErrors?.originalCreatedAt,
displayRow.importErrors?.originalCreatedFrom,
displayRow.importErrors?.originalCreatedBefore,
)}/>
displayRow.importErrors?.originalCreatedBefore)}/>
<DialogTextField
label="動画時間"
value={draft.duration}
@@ -162,8 +162,7 @@ const PostImportRowDialog: FC<Props> = (
displayRow.validationErrors.duration,
displayRow.validationErrors.videoMs,
displayRow.importErrors?.duration,
displayRow.importErrors?.videoMs,
)}
displayRow.importErrors?.videoMs)}
onChange={value => update ('duration', value)}/>
<DialogAreaField
label="タグ"
@@ -177,8 +176,7 @@ const PostImportRowDialog: FC<Props> = (
value={draft.parentPostIds}
errors={groupedMessages (
displayRow.validationErrors.parentPostIds,
displayRow.importErrors?.parentPostIds,
)}
displayRow.importErrors?.parentPostIds)}
onChange={value => update ('parentPostIds', value)}/>
<FieldWarning messages={displayRow.baseWarnings}/>
<FieldError messages={displayRow.validationErrors.base}/>
@@ -191,14 +189,9 @@ const PostImportRowDialog: FC<Props> = (
<Button
type="button"
variant="outline"
onClick={async () => {
const resetDraft = buildResetDraft (row)
setDraft (resetDraft)
if (await onSave ({
draft: resetDraft,
resetRequested: true,
resetSnapshot: row.resetSnapshot }))
onOpenChange (false)
onClick={() => {
setDraft (buildResetDraft (row))
setResetRequested (true)
}}>
</Button>
+2 -6
ファイルの表示
@@ -4,7 +4,6 @@ import { cn } from '@/lib/utils'
import PostImportStatusBadge from '@/components/posts/import/PostImportStatusBadge'
import ThumbnailPreview from '@/components/posts/import/ThumbnailPreview'
import { displayPostImportStatus } from '@/components/posts/import/postImportRowStatus'
import { importPanelToneForRow } from '@/components/posts/import/postImportTone'
import type { FC } from 'react'
@@ -35,9 +34,7 @@ const PostImportRowSummary: FC<Props> = ({ row, onEdit }) => {
className={cn (
'hidden items-center gap-4 rounded-lg border p-4 md:grid',
'md:grid-cols-[4rem_5rem_minmax(0,1fr)_auto_auto]',
importPanelToneForRow (row),
'transition-shadow hover:shadow-sm',
)}>
'transition-shadow hover:shadow-sm')}>
<div className="space-y-1">
<div className="text-sm font-medium">#{row.sourceRow}</div>
</div>
@@ -80,8 +77,7 @@ const PostImportRowSummary: FC<Props> = ({ row, onEdit }) => {
<div
className={cn (
'space-y-3 rounded-lg border p-4 md:hidden',
importPanelToneForRow (row),
)}>
'transition-shadow hover:shadow-sm')}>
<div className="flex items-start gap-3">
<ThumbnailPreview
url={String (row.attributes.thumbnailBase ?? '')}
+2 -2
ファイルの表示
@@ -14,9 +14,9 @@ const LABELS: Record<PostImportBadgeValue, string> = {
skipped: 'スキップ' }
const TONES: Record<PostImportBadgeValue, StatusBadgeTone> = {
ready: 'ready',
ready: 'success',
warning: 'warning',
skipped: 'skipped' }
skipped: 'neutral' }
const PostImportStatusBadge: FC<Props> = ({ value }) => (
-19
ファイルの表示
@@ -1,19 +0,0 @@
import PostImportStatusBadge from '@/components/posts/import/PostImportStatusBadge'
import type { FC } from 'react'
import type { PostImportBadgeValue } from '@/components/posts/import/postImportRowStatus'
type Props = {
label: string
value: number
badge?: PostImportBadgeValue }
const PostImportSummaryChip: FC<Props> = ({ label, value, badge }) => (
<div className="flex items-center gap-2 rounded-full border border-border
bg-background px-3 py-1 text-sm">
{badge != null && <PostImportStatusBadge value={badge}/>}
<span>{label} {value}</span>
</div>)
export default PostImportSummaryChip
+9 -16
ファイルの表示
@@ -10,20 +10,13 @@ const hasWarnings = (row: PostImportRow): boolean =>
export const displayPostImportStatus = (
row: PostImportRow,
): PostImportDisplayStatus | null => {
const skipped =
row.skipReason === 'existing'
|| row.importStatus === 'skipped'
const hidden =
Object.keys (row.validationErrors ?? { }).length > 0
): PostImportDisplayStatus | null =>
(row.skipReason === 'existing' || row.importStatus === 'skipped')
? 'skipped'
: ((Object.keys (row.validationErrors ?? { }).length > 0
|| row.importStatus === 'failed'
|| row.importStatus === 'created'
if (skipped)
return 'skipped'
if (hidden)
return null
return hasWarnings (row) || row.status === 'warning'
? 'warning'
: 'ready'
}
|| row.importStatus === 'created')
? null
: ((hasWarnings (row) || row.status === 'warning')
? 'warning'
: 'ready'))
-36
ファイルの表示
@@ -1,36 +0,0 @@
import { displayPostImportStatus } from '@/components/posts/import/postImportRowStatus'
import type { PostImportRow } from '@/lib/postImportSession'
export const importPanelToneClass = (
status: 'created' | 'error' | 'failed' | 'invalid' | 'skipped' | 'warning' | 'ready',
): string[] => {
switch (status)
{
case 'created':
return [
'border-sky-200 bg-sky-50',
'dark:border-sky-900 dark:bg-sky-950/30']
case 'error':
case 'failed':
case 'invalid':
return [
'border-rose-200 bg-rose-50',
'dark:border-rose-900 dark:bg-rose-950/30']
case 'skipped':
return [
'border-stone-200 bg-stone-50',
'dark:border-stone-800 dark:bg-stone-900/60']
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']
}
}
export const importPanelToneForRow = (row: PostImportRow): string[] =>
importPanelToneClass (displayPostImportStatus (row) ?? 'ready')