디자인디테일

This commit is contained in:
koreacomp5
2025-11-01 23:16:22 +09:00
parent f84111b9cc
commit 27cf98eef2
20 changed files with 735 additions and 384 deletions

View File

@@ -14,6 +14,7 @@ export default function NewPostPage() {
const initialBoardId = sp.get("boardId") ?? "";
const boardSlug = sp.get("boardSlug") ?? undefined;
const [form, setForm] = useState({ boardId: initialBoardId, title: "", content: "" });
const [isSecret, setIsSecret] = useState(false);
const [loading, setLoading] = useState(false);
async function submit() {
try {
@@ -49,56 +50,90 @@ export default function NewPostPage() {
setLoading(false);
}
}
const plainLength = (form.content || "").replace(/<[^>]*>/g, "").length;
const MAX_LEN = 10000;
return (
<div className="space-y-6">
{/* 상단 배너 */}
<section>
<HeroBanner />
</section>
{/* 작성 카드 */}
<section className="rounded-xl overflow-hidden bg-white">
<header className="px-4 py-3 border-b border-neutral-200">
<h1 className="text-xl md:text-2xl font-bold text-neutral-900"> </h1>
</header>
<div className="p-4 md:p-6 space-y-3">
<section className="mx-auto max-w-5xl bg-white rounded-2xl border border-neutral-300 px-6 sm:px-8 pt-6 pb-8">
<div className="flex items-center justify-between">
<h1 className="text-[22px] md:text-[26px] font-semibold text-neutral-900 leading-none"> </h1>
<button
aria-label="닫기"
onClick={() => router.back()}
className="inline-flex items-center justify-center rounded-xl p-2 hover:bg-neutral-100"
>
</button>
</div>
<div className="mt-5 grid grid-cols-1 sm:grid-cols-[1fr_162px] gap-3">
<input
className="h-10 w-full rounded-md border border-neutral-300 px-3 text-sm focus:outline-none focus:ring-2 focus:ring-neutral-400"
placeholder="boardId"
value={form.boardId}
onChange={(e) => setForm({ ...form, boardId: e.target.value })}
/>
<input
className="h-10 w-full rounded-md border border-neutral-300 px-3 text-sm focus:outline-none focus:ring-2 focus:ring-neutral-400"
placeholder="제목"
className="h-16 w-full rounded-2xl border border-neutral-300 px-6 text-lg placeholder:text-neutral-500 focus:outline-none focus:ring-2 focus:ring-neutral-400"
placeholder="제목을 작성해주세요"
value={form.title}
onChange={(e) => setForm({ ...form, title: e.target.value })}
/>
<Editor value={form.content} onChange={(v) => setForm({ ...form, content: v })} placeholder="내용을 입력하세요" />
<div className="pt-1">
<UploadButton
multiple
onUploaded={(url) => setForm((f) => ({ ...f, content: `${f.content}\n![image](${url})` }))}
{...(boardSlug ? require("@/lib/photoPresets").getPhotoPresetBySlug(boardSlug) : {})}
/>
</div>
</div>
<footer className="px-4 py-3 border-t border-neutral-200 flex items-center justify-end gap-2">
<button
type="button"
className="h-9 px-4 rounded-md border border-neutral-300 bg-white text-sm hover:bg-neutral-100"
onClick={() => router.back()}
className="h-16 rounded-2xl border border-neutral-300 px-6 text-base text-neutral-900 bg-white hover:bg-neutral-50"
onClick={() => {/* 태그 선택 자리표시 */}}
>
</button>
</div>
<div className="mt-3 rounded-2xl border border-neutral-300">
<div className="p-5">
<Editor value={form.content} onChange={(v) => setForm({ ...form, content: v })} placeholder="내용을 작성해주세요" />
</div>
<div className="px-4 py-3 flex items-center justify-between bg-neutral-100 rounded-b-2xl">
<label className="inline-flex items-center gap-2 bg-white px-2.5 py-1.5 rounded-lg border border-red-300">
<input
type="checkbox"
className="size-4 accent-[#f94b37]"
checked={isSecret}
onChange={(e) => setIsSecret(e.target.checked)}
/>
<span className="text-sm text-[#f94b37]"></span>
</label>
<div className="flex items-center gap-3 text-[13px]">
<span className="text-orange-600">{plainLength}</span>
<span className="text-neutral-900">/ {MAX_LEN.toLocaleString()}</span>
<span aria-hidden>🙂</span>
<UploadButton
multiple
onUploaded={(url) => setForm((f) => ({ ...f, content: `${f.content}\n![image](${url})` }))}
{...(boardSlug ? require("@/lib/photoPresets").getPhotoPresetBySlug(boardSlug) : {})}
/>
</div>
</div>
</div>
<div className="mt-4">
<button
disabled={loading}
onClick={submit}
className="h-9 px-4 rounded-md bg-neutral-900 text-white text-sm hover:bg-neutral-800 disabled:opacity-60"
className="w-full h-14 rounded-2xl bg-[#f94b37] text-white text-[20px] font-semibold hover:opacity-95 disabled:opacity-60 border border-[#d73b29]"
>
{loading ? "저장 중..." : "등록"}
{loading ? "저장 중..." : "게시하기"}
</button>
</footer>
</div>
<div className="sr-only">
<input
className="hidden"
placeholder="boardId"
value={form.boardId}
onChange={(e) => setForm({ ...form, boardId: e.target.value })}
aria-hidden
readOnly
/>
</div>
</section>
</div>
);