refactor(todo): 移除 Todo 前端示例
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { orpc } from '@/client/orpc'
|
||||
|
||||
export const useInvalidateTodos = () => {
|
||||
const queryClient = useQueryClient()
|
||||
return () => queryClient.invalidateQueries({ queryKey: orpc.todo.list.key() })
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import type { SubmitEventHandler } from 'react'
|
||||
import { useState } from 'react'
|
||||
|
||||
interface TodoFormProps {
|
||||
onSubmit: (title: string) => void
|
||||
isPending: boolean
|
||||
}
|
||||
|
||||
export const TodoForm = ({ onSubmit, isPending }: TodoFormProps) => {
|
||||
const [title, setTitle] = useState('')
|
||||
|
||||
const handleSubmit: SubmitEventHandler<HTMLFormElement> = (e) => {
|
||||
e.preventDefault()
|
||||
if (title.trim()) {
|
||||
onSubmit(title.trim())
|
||||
setTitle('')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className="relative group z-10">
|
||||
<div className="relative transform transition-all duration-200 focus-within:-translate-y-1">
|
||||
<input
|
||||
type="text"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
placeholder="添加新任务..."
|
||||
className="w-full pl-6 pr-32 py-5 bg-white rounded-2xl shadow-[0_8px_30px_rgb(0,0,0,0.04)] border-0 ring-1 ring-slate-100 focus:ring-2 focus:ring-indigo-500/50 outline-none transition-all placeholder:text-slate-400 text-lg text-slate-700"
|
||||
disabled={isPending}
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isPending || !title.trim()}
|
||||
className="absolute right-3 top-3 bottom-3 px-6 bg-indigo-600 hover:bg-indigo-700 text-white rounded-xl font-medium transition-all shadow-md shadow-indigo-200 disabled:opacity-50 disabled:shadow-none hover:shadow-lg hover:shadow-indigo-300 active:scale-95"
|
||||
>
|
||||
{isPending ? '添加中' : '添加'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import type { RouterOutputs } from '@/server/api/types'
|
||||
|
||||
type Todo = RouterOutputs['todo']['list'][number]
|
||||
|
||||
interface TodoItemProps {
|
||||
todo: Todo
|
||||
onToggle: (id: string, completed: boolean) => void
|
||||
onDelete: (id: string) => void
|
||||
}
|
||||
|
||||
export const TodoItem = ({ todo, onToggle, onDelete }: TodoItemProps) => {
|
||||
return (
|
||||
<div
|
||||
className={`group relative flex items-center p-4 bg-white rounded-xl border border-slate-100 shadow-sm transition-all duration-200 hover:shadow-md hover:border-slate-200 ${
|
||||
todo.completed ? 'bg-slate-50/50' : ''
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onToggle(todo.id, todo.completed)}
|
||||
className={`shrink-0 w-6 h-6 rounded-full border-2 transition-all duration-200 flex items-center justify-center mr-4 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 ${
|
||||
todo.completed ? 'bg-indigo-500 border-indigo-500' : 'border-slate-300 hover:border-indigo-500 bg-white'
|
||||
}`}
|
||||
>
|
||||
{todo.completed && (
|
||||
<svg
|
||||
className="w-3.5 h-3.5 text-white"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={3}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
|
||||
<div className="flex-1 min-w-0">
|
||||
<p
|
||||
className={`text-lg transition-all duration-200 truncate ${
|
||||
todo.completed ? 'text-slate-400 line-through decoration-slate-300 decoration-2' : 'text-slate-700'
|
||||
}`}
|
||||
>
|
||||
{todo.title}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center opacity-0 group-hover:opacity-100 transition-opacity duration-200 absolute right-4 pl-4 bg-linear-to-l from-white via-white to-transparent sm:static sm:bg-none">
|
||||
<span className="text-xs text-slate-400 mr-3 hidden sm:inline-block">
|
||||
{new Date(todo.createdAt).toLocaleDateString('zh-CN')}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onDelete(todo.id)}
|
||||
className="p-2 text-slate-400 hover:text-red-500 hover:bg-red-50 rounded-lg transition-colors focus:outline-none"
|
||||
title="删除"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.5}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user