This commit is contained in:
x1ulan 2025-06-10 22:10:01 +08:00
parent b61998b9e3
commit 868b5e1c36
6 changed files with 126 additions and 61 deletions

View file

@ -49,30 +49,32 @@ export const Delete = () => {
<form
onSubmit={handleSubmit(onSubmit)}
className=
'flex flex-col m-auto w-10/12 h-[80dvh] px-10 gap-3 pb-3 md:w-[50dvw]'
'flex flex-col m-auto w-10/12 px-6 py-8 gap-6 rounded-lg shadow-xl bg-white md:w-[50dvw]'
>
{/* register your input into the hook by invoking the "register" function */}
<h1 className="text-3xl my-3"></h1>
<label htmlFor='id' className='text-left'>
<h1 className="text-4xl font-bold text-gray-800 mb-4 text-center"></h1>
<label htmlFor='id' className='text-lg font-medium text-gray-700'>
ID:
</label>
<input id="id" type="search" {...register("id", { required: true })} className='border-b-4 border-zinc-500 w-full text-end outline-none focus:border-zinc-200' list="saved_id" />
<input id="id" type="search" {...register("id", { required: true })} className='border-b-4 border-zinc-500 w-full text-end outline-none focus:border-gray-600 text-black' list="saved_id" />
<datalist id="saved_id">
{saved.map((e, it) => <option value={e.id} key={it}></option>)}
</datalist>
<label htmlFor='hash'>
<label htmlFor='hash' className='text-lg font-medium text-gray-700'>
Hash:
</label>
<input id="hash" type="text" {...register("hash", { required: true })} className='border-b-4 border-zinc-500 w-full text-end outline-none focus:border-zinc-200' />
<input id="hash" type="text" {...register("hash", { required: true })} className='border-b-4 border-zinc-500 w-full text-end outline-none focus:border-gray-600 text-black' />
{/* errors will return when field validation fails */}
{errors.id && <span>This field is required</span>}
{errors.hash && <span>This field is required</span>}
<button type="submit" className="ring-3 w-full mx-auto rounded-md ">
</button>
<button
type="submit"
className="mt-6 w-full py-3 bg-gray-800 text-white font-semibold rounded-lg hover:bg-gray-700 transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed" // Consistent button styling
>
</button>
</form>
</>
)

View file

@ -12,29 +12,30 @@ export const Fetch = () => {
setFetched(e)
}
}
)
)
}, [])
return (<div className="h-dvh w-dvw flex flex-col justify-items-center overflow-scroll gap-10 pt-10 pb-10">
{fetched.map(post => <div className="w-[87%] h-fit mx-auto border-1 border-slate-700 rounded">
<p className="text-left mx-2 mt-2">{post.content}</p>
{post.enclosure.length > 0 && post.enclosure[0] != null && <div className="flex flex-row overflow-scroll w-full h-30 mx-2">
{post.enclosure.map(enc => {
return (<div className="min-h-dvh w-dvw flex flex-col items-center gap-6 py-8 px-4">
{fetched.map(post => <div className="w-full max-w-2xl bg-gray-200 rounded-lg shadow-md p-6 flex flex-col gap-4">
<p className="text-gray-800 text-base leading-relaxed">{post.content}</p>
{post.enclosure.length > 0 && post.enclosure[0] != null && <div className="flex flex-row overflow-x-auto gap-3 py-2 -mx-2 px-2 border-t border-gray-200 pt-4">
{post.enclosure.map((enc, index) => {
if (enc) {
return <img src={MediaPathTrc(enc)} className="rounded h-full w-auto" />
return <img
key={index}
src={MediaPathTrc(enc)}
alt={`Post media ${post.id}-${index}`}
className="rounded-md h-32 object-cover aspect-video flex-shrink-0"
/>
} else {
return ""
}
})}
</div>}
{post.signing && <p className="text-right mr-3">by: {post.signing}</p>}
<div className="h-fit flex flex-row text-sm mx-3">
{post.signing && <p className="text-right text-sm text-gray-600 italic mt-2">by: {post.signing}</p>}
<div className="flex justify-between items-center text-xs text-gray-500 border-t border-gray-100 pt-3">
<p className="self-start">PID: {post.id}</p>
<p className="self-end ml-auto">: {post.post_at.toLocaleTimeString()}</p>
<p className="self-end">: {post.post_at.toLocaleTimeString()}</p>
</div>
</div>)}
</div>)
}

View file

@ -12,7 +12,7 @@ const ImageWithPreview = ({
<>
<img
src={src}
alt="kkk"
alt="tyts"
onClick={() => {
setShow(true)
}}
@ -25,15 +25,15 @@ const ImageWithPreview = ({
}
onClick={() => setShow(false)}
>
<div className="z-20 w-full fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 md:w-[50dvw]">
<img src={src} className="w-[90dvw] h-auto m-auto" />
<button
type="button"
className="border w-full"
onClick={() => remove()}
>
</button>
<div className="z-20 w-full md:w-fit fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 md:w-[50dvw]">
<img src={src} className="w-[90dvw] h-auto m-auto md:w-auto md:max-h-[80dvh]" />
<button
type="button"
className="mt-6 w-full py-3 bg-gray-800 text-white font-semibold rounded-lg hover:bg-gray-700 transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed" // Consistent button styling
onClick={() => remove()}
>
</button>
</div>
</div>
</>

View file

@ -1,4 +1,4 @@
import { useState, type ReactElement, } from 'react'
import { useState, type ReactElement } from 'react'
import { useForm, type SubmitHandler } from 'react-hook-form'
import ImageWithPreview from './ImageWithPrview'
import { Post } from './api'
@ -77,20 +77,20 @@ export default function PostForm() {
<form
onSubmit={handleSubmit(onSubmit)}
className={
'flex flex-col m-auto w-10/12 h-[80dvh] px-10 gap-3 pb-3 md:w-[50dvw]' +
'flex flex-col m-auto w-10/12 h-[80dvh] px-6 py-8 gap-6 rounded-lg shadow-xl bg-white ' + // Added background, padding, shadow, rounded corners
(cred !== undefined ? ' hidden' : '')
}
>
{/* register your input into the hook by invoking the "register" function */}
<h1 className="text-3xl my-3"></h1>
<h1 className="text-4xl font-bold text-gray-800 mb-4 text-center"></h1> {/* Larger, bolder title, centered */}
<textarea
className="ring-3 ring-zinc-500 focus:ring-zinc-200 outline-none rounded-xl h-5/12 px-3 w-full"
className="p-4 border border-gray-300 rounded-lg h-5/12 w-full resize-y focus:outline-none focus:border-gray-500 transition-colors duration-200 text-black" // Modernized textarea
placeholder="匿名文章"
{...register('content', { required: true })}
/>
<div>
<label htmlFor="files" className="text-xl">
<label htmlFor="files" className="block text-lg font-medium text-gray-700 mb-2 cursor-pointer"> {/* Styled label */}
<span className="ml-2 px-3 py-1 bg-gray-100 text-gray-700 rounded-full text-sm hover:bg-gray-200 transition-colors duration-200"></span>
</label>
<input
multiple
@ -102,7 +102,7 @@ export default function PostForm() {
/>
<div
className={
'h-20 w-full gap-3 overflow-scroll flex flex-row ' +
'h-24 w-full gap-3 overflow-x-auto flex flex-row items-center border border-gray-200 rounded-lg p-2 ' + // Adjusted image preview container
(files_list && files_list.length > 0 ? '' : 'hidden')
}
>
@ -110,23 +110,25 @@ export default function PostForm() {
</div>
</div>
{/* include validation with required or other standard HTML validation rules */}
<div className="ml-auto flex gap-3">
<label className="w-fit break-keep"></label>
<div className="ml-auto flex items-center gap-3"> {/* Aligned items, added items-center */}
<label className="w-fit text-lg font-medium text-gray-700 break-keep"></label>
<input
className="border-b-4 border-zinc-500 w-full text-end outline-none focus:border-zinc-200"
className="border-b-2 border-gray-400 w-full text-right outline-none focus:border-gray-600 transition-colors duration-200 p-1" // Modernized signing input
{...register('signing', {
maxLength: 20,
})}
/>
</div>
{/* errors will return when field validation fails */}
{errors.content && <span>This field is required</span>}
{errors.content && <span className="text-red-500 text-sm"></span>} {/* Styled error message */}
<button type="submit" className="ring-3 w-full mx-auto rounded-md " disabled={posting}>
<button
type="submit"
className="mt-6 w-full py-3 bg-gray-800 text-white font-semibold rounded-lg hover:bg-gray-700 transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed" // Modernized button
disabled={posting}
>
</button>
</form>
</>
)
}
}

View file

@ -2,21 +2,81 @@ import { useState } from 'react'
export const Zone = ({ setZone }: { setZone: (zone_name: string) => void }) => {
const [toggle, setToggle] = useState(false)
return (
<>
{/* Backdrop with fade animation */}
<div
className={`fixed inset-0 z-10 backdrop-blur-sm transition-all duration-300 ${
toggle
? 'bg-black/50 opacity-100 pointer-events-auto'
: 'bg-black/0 opacity-0 pointer-events-none'
}`}
onClick={() => setToggle(false)}
/>
{toggle && <div className="w-full fixed h-dvh top-0 left-0 z-10 backdrop-brightness-50" >
</div>}
{/* Main drawer */}
<div className={`
fixed bottom-0 left-1/2 -translate-x-1/2 z-20
w-[min(80dvw,400px)] bg-zinc-800
rounded-t-3xl shadow-2xl border-t border-zinc-600
transition-all duration-500 ease-out
${toggle ? 'h-[45dvh]' : 'h-16'}
`}>
{/* Drawer handle/button */}
<div className="relative">
{/* Visual handle indicator */}
<div className="w-12 h-1 bg-zinc-500 rounded-full mx-auto mt-3 mb-2" />
<button
onClick={() => setToggle(!toggle)}
className="w-full py-3 px-6 text-white font-medium text-lg
hover:bg-zinc-700 transition-colors duration-200
flex items-center justify-center gap-2"
>
<span></span>
<span className={`transition-transform duration-300 ${toggle ? 'rotate-180' : ''}`}>
</span>
</button>
</div>
<div className={"fixed bottom-0 left-1/2 -translate-x-1/2 z-20 w-[80dvw] bg-zinc-700 rounded transition-all duration-300" + (toggle ? " h-[40dvh]" : "h-fit")}>
<button onClick={() => setToggle(!toggle)}>Drawer</button>
{toggle && <div className="h-[40dvh] w-full flex flex-col pt-10 gap-8 text-xl">
<button onClick={() => { setZone("post"); setToggle(false) }}>PO文</button>
<button onClick={() => { setZone("delete"); setToggle(false) }}></button>
<button onClick={() => { setZone("view"); setToggle(false) }}></button>
</div>}
{/* Menu content with staggered animations */}
<div className={`
px-6 pb-6 overflow-hidden
transition-all duration-500 ease-out
${toggle ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4 pointer-events-none'}
`}>
<div className="grid gap-4 pt-4">
{[
{ key: 'post', label: 'PO文', icon: '✏️', delay: '100ms' },
{ key: 'delete', label: '刪文', icon: '🗑️', delay: '200ms' },
{ key: 'view', label: '查看', icon: '👁️', delay: '300ms' }
].map(({ key, label, icon, delay }) => (
<button
key={key}
onClick={() => { setZone(key); setToggle(false) }}
className={`
w-full py-4 px-6 bg-zinc-700 hover:bg-zinc-600
rounded-xl text-white text-lg font-medium
flex items-center gap-4
transform transition-all duration-300 ease-out
hover:scale-105 hover:shadow-lg
active:scale-95
${toggle ? 'translate-y-0 opacity-100' : 'translate-y-4 opacity-0'}
`}
style={{
transitionDelay: toggle ? delay : '0ms'
}}
>
<span className="text-2xl">{icon}</span>
<span>{label}</span>
</button>
))}
</div>
</div>
</div>
</>
)
}
}

View file

@ -1,5 +1,5 @@
import { z } from 'zod/v4'
let rooturl = 'http://10.16.20.19:3000'
let rooturl = 'http://172.16.20.145:3000'
type Inputs = {
content: string