このコミットが含まれているのは:
2026-10-18 02:45:26 +09:00
コミット 2d1a8b4730
17個のファイルの変更、488行の追加、326行の削除
+27 -21
ファイルの表示
@@ -8,13 +8,13 @@ import TagLink from '@/components/TagLink'
import { fetchMaterialTagTree, parseMaterialFilter } from '@/lib/materials'
import { materialsKeys } from '@/lib/queryKeys'
import { cn } from '@/lib/utils'
import { useUITranslation } from '@/lib/useUITranslation'
import type { CSSProperties, Dispatch, FC, ReactNode, SetStateAction } from 'react'
import type { MaterialFilter, MaterialSidebarTag, Tag } from '@/types'
const FILTERS: MaterialFilter[] = ['missing', 'present', 'any']
const FILTER_LABELS: Record<MaterialFilter, string> = { present: '有', missing: '無', any: '全' }
const px = (value: string): number => {
@@ -96,24 +96,27 @@ const updateMaterialFilterQuery = (
const MaterialFilterButtons: FC<{ materialFilter: MaterialFilter
onChange: (materialFilter: MaterialFilter) => void }> = (
{ materialFilter, onChange },
) => (
<div className="flex flex-wrap gap-2 justify-end md:justify-start flex-center">
<label className="my-auto text-sm font-bold">素材:</label>
{FILTERS.map (value => (
<button
key={value}
type="button"
onClick={() => onChange (value)}
className={cn (
'rounded-full border px-3 py-1 text-sm',
(materialFilter === value
? ['border-sky-500 bg-sky-50 text-sky-700 dark:border-sky-400',
'dark:bg-sky-950 dark:text-sky-100']
: ['border-neutral-300 bg-white text-neutral-700 dark:border-stone-700',
'dark:bg-stone-900 dark:text-stone-200']))}>
{FILTER_LABELS[value]}
</button>))}
</div>)
) => {
const { label } = useUITranslation ('materials')
return (
<div className="flex flex-wrap gap-2 justify-end md:justify-start flex-center">
<label className="my-auto text-sm font-bold">{label ('sidebar.label')}</label>
{FILTERS.map (value => (
<button
key={value}
type="button"
onClick={() => onChange (value)}
className={cn (
'rounded-full border px-3 py-1 text-sm',
(materialFilter === value
? ['border-sky-500 bg-sky-50 text-sky-700 dark:border-sky-400',
'dark:bg-sky-950 dark:text-sky-100']
: ['border-neutral-300 bg-white text-neutral-700 dark:border-stone-700',
'dark:bg-stone-900 dark:text-stone-200']))}>
{label (`sidebar.${value}`)}
</button>))}
</div>)
}
const MaterialTreeNode: FC<{
@@ -385,6 +388,7 @@ const MobileMaterialTreeNode: FC<{ depth?: number
const MaterialSidebar: FC = () => {
const { label } = useUITranslation ('materials')
const locale = useLocale ()
const location = useLocation ()
const navigate = useLocaleNavigate ()
@@ -498,10 +502,12 @@ const MaterialSidebar: FC = () => {
materialFilter={materialFilter}
onChange={handleFilterChange}/>
{isLoading && (
<p className="text-sm text-neutral-500 dark:text-stone-400">読込中……</p>)}
<p className="text-sm text-neutral-500 dark:text-stone-400">
{label ('shared:messages.loadingEllipsis')}
</p>)}
{isError && (
<p className="text-sm text-red-600 dark:text-red-300">
タグ一覧の取得に失敗しました.
{label ('sidebar.error')}
</p>)}
{(!isLoading && !isError) && (
<ul>
+17 -11
ファイルの表示
@@ -13,6 +13,7 @@ import useDialogue from '@/lib/dialogues/useDialogue'
import { updatePost } from '@/lib/posts'
import { msToTime } from '@/lib/utils'
import { useValidationErrors } from '@/lib/useValidationErrors'
import { useUITranslation } from '@/lib/useUITranslation'
import type { FC, FormEvent } from 'react'
@@ -53,6 +54,7 @@ type Props = { post: Post
const PostEditForm: FC<Props> = ({ post, onSave }) => {
const locale = useLocale ()
const { label } = useUITranslation ('posts')
const [disabled, setDisabled] = useState (false)
const [duration, setDuration] = useState<string> (videoMsToDurationValue (post.videoMs))
const { baseErrors, fieldErrors, clearValidationErrors, applyValidationError } =
@@ -88,7 +90,7 @@ const PostEditForm: FC<Props> = ({ post, onSave }) => {
siblingPosts: data.siblingPosts,
originalCreatedFrom: data.originalCreatedFrom,
originalCreatedBefore: data.originalCreatedBefore } as Post)
toast ({ description: '更新しました.' })
toast ({ description: label ('shared:messages.updated') })
}
catch (e)
{
@@ -98,24 +100,28 @@ const PostEditForm: FC<Props> = ({ post, onSave }) => {
{
if (applyValidationError (e))
{
toast ({ description: '更新はできなかったよ……' })
toast ({ description: label ('edit.validationFailed') })
return
}
toast ({ title: '失敗……', description: '入力を確認してください.' })
toast ({ title: label ('shared:messages.failed'),
description: label ('shared:messages.checkInput') })
return
}
const action = await dialogue.choice ({
title: '競合が発生しました.',
title: label ('edit.conflictTitle'),
description: (
<div>
<p>ほかの耕作員が先に更新してゐます.</p>
<p>現在の変更をどう扱ひますか?</p>
<p>{label ('edit.conflictDescription')}</p>
<p>{label ('edit.conflictQuestion')}</p>
</div>),
choices: [...(response?.data?.mergeable ? [{ value: 'merge', label: '差分をマージ' }] : []),
{ value: 'overwrite', label: '強制上書き', variant: 'danger' }] })
cancelText: label ('shared:actions.cancel'),
closeLabel: label ('settings:actions.close'),
choices: [...(response?.data?.mergeable
? [{ value: 'merge', label: label ('edit.merge') }] : []),
{ value: 'overwrite', label: label ('edit.overwrite'), variant: 'danger' }] })
if (action === 'merge')
{
@@ -165,13 +171,13 @@ const PostEditForm: FC<Props> = ({ post, onSave }) => {
<FieldError messages={baseErrors}/>
<PostTextField
label="タイトル"
label={label ('shared:labels.title')}
value={title ?? ''}
disabled={disabled}
onChange={setTitle}/>
<PostTextField
label="親投稿"
label={label ('shared:labels.parentPosts')}
value={parentPostIds}
disabled={disabled}
errors={fieldErrors.parentPostIds}
@@ -204,7 +210,7 @@ const PostEditForm: FC<Props> = ({ post, onSave }) => {
{/* 送信 */}
<Button type="submit" disabled={disabled}>
更新
{label ('shared:actions.update')}
</Button>
</form>)
}
+1 -1
ファイルの表示
@@ -3,7 +3,7 @@ import type { FC } from 'react'
import React, { useState } from 'react'
import { cn } from '@/lib/utils'
type TabProps = { name: string
type TabProps = { name: React.ReactNode
init?: boolean
children: React.ReactNode }
+2 -1
ファイルの表示
@@ -179,7 +179,8 @@ const DialogueProvider: FC<Props> = ({ children }) => {
closeRequest (active.id, active.kind !== 'confirm' && null)
}}>
<DialogContent
closeLabel={active.kind === 'confirm' ? active.options.closeLabel : undefined}
closeLabel={(active.kind === 'confirm' || active.kind === 'choice')
? active.options.closeLabel : undefined}
className={
active.kind === 'form'
? `flex max-h-[calc(100dvh-1rem)] ${ active.options.size === 'large'