edit css
This commit is contained in:
parent
b61998b9e3
commit
868b5e1c36
6 changed files with 126 additions and 61 deletions
|
@ -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>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -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>)
|
||||
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
|
|
32
src/Post.tsx
32
src/Post.tsx
|
@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
82
src/Zone.tsx
82
src/Zone.tsx
|
@ -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>
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue