snapshot before merge
This commit is contained in:
1 parent
2b3b2850f9
commit
21fc65b3ae
145 files changed
+9786
-59
No files matched your search
@@ -19,7 +19,7 @@ export default function Pagination({ page, totalPages, onPageChange }: Paginatio
|
||||
const btn = "px-2.5 py-1.5 text-[12px] rounded-md border border-line hover:bg-surface transition-colors";
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center gap-1 mt-8">
|
||||
<div className="flex items-center justify-center gap-1 mt-8 flex-wrap">
|
||||
<button type="button" onClick={() => onPageChange(page - 1)} disabled={page <= 1}
|
||||
className={`${btn} ${page <= 1 ? "opacity-25 cursor-not-allowed" : ""}`}>上一页</button>
|
||||
{start > 1 && (
|
||||
|
||||
@@ -265,7 +265,7 @@ export default function PostEditor({ initialData, isEditing }: PostEditorProps)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex gap-8">
|
||||
<div className="flex flex-col lg:flex-row lg:gap-8 gap-6">
|
||||
<div className="flex-1 min-w-0 space-y-8">
|
||||
{message && (
|
||||
<div className={`px-4 py-2.5 rounded-md text-[13px] font-medium ${
|
||||
@@ -281,7 +281,7 @@ export default function PostEditor({ initialData, isEditing }: PostEditorProps)
|
||||
<section>
|
||||
<h3 className="text-[11px] font-medium text-muted uppercase tracking-wider mb-4">文章信息</h3>
|
||||
<div className="space-y-3">
|
||||
<div className="flex gap-3">
|
||||
<div className="flex flex-col sm:flex-row gap-3">
|
||||
<div className="flex-1">
|
||||
<label className="block text-[12px] font-medium text-text/70 mb-1.5">标题</label>
|
||||
<input
|
||||
@@ -304,7 +304,7 @@ export default function PostEditor({ initialData, isEditing }: PostEditorProps)
|
||||
placeholder="文章标题"
|
||||
/>
|
||||
</div>
|
||||
<div className="w-[200px]">
|
||||
<div className="w-full sm:w-[200px]">
|
||||
<label className="block text-[12px] font-medium text-text/70 mb-1.5">
|
||||
Slug <span className="text-[10px] text-muted/50 font-normal">(自动时间戳)</span>
|
||||
</label>
|
||||
@@ -312,12 +312,12 @@ export default function PostEditor({ initialData, isEditing }: PostEditorProps)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3">
|
||||
<div className="w-[180px]">
|
||||
<div className="flex flex-col sm:flex-row gap-3">
|
||||
<div className="w-full sm:w-[180px]">
|
||||
<label className="block text-[12px] font-medium text-text/70 mb-1.5">日期</label>
|
||||
<input type="date" value={form.date} onChange={(e) => setForm({ ...form, date: e.target.value })} className={inputCls} title="日期" />
|
||||
</div>
|
||||
<div className="w-[160px]">
|
||||
<div className="w-full sm:w-[160px]">
|
||||
<label className="block text-[12px] font-medium text-text/70 mb-1.5">作者</label>
|
||||
<input type="text" value={form.author} onChange={(e) => setForm({ ...form, author: e.target.value })} className={inputCls} title="作者" />
|
||||
</div>
|
||||
@@ -327,7 +327,7 @@ export default function PostEditor({ initialData, isEditing }: PostEditorProps)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3">
|
||||
<div className="flex flex-col sm:flex-row gap-3">
|
||||
<div className="flex-1">
|
||||
<label className="block text-[12px] font-medium text-text/70 mb-1.5">标签</label>
|
||||
<input type="text" value={form.tags} onChange={(e) => setForm({ ...form, tags: e.target.value })} className={inputCls} placeholder="用顿号分隔" />
|
||||
@@ -377,7 +377,7 @@ export default function PostEditor({ initialData, isEditing }: PostEditorProps)
|
||||
</section>
|
||||
|
||||
{/* Actions: 草稿 | 保存 | 发布 */}
|
||||
<div className="flex items-center gap-3 pt-2">
|
||||
<div className="flex items-center gap-3 pt-2 flex-wrap">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleDraft}
|
||||
@@ -411,8 +411,8 @@ export default function PostEditor({ initialData, isEditing }: PostEditorProps)
|
||||
</div>
|
||||
|
||||
{/* Right: shortcuts + AI panel */}
|
||||
<div className="w-[180px] shrink-0">
|
||||
<div className="sticky top-6 space-y-6">
|
||||
<div className="w-full lg:w-[180px] lg:shrink-0">
|
||||
<div className="lg:sticky lg:top-6 space-y-6">
|
||||
<ShortcutPanel textareaRef={textareaRef} value={content} onChange={setContent} />
|
||||
<AIPanel
|
||||
selectedText={selectedText}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { FileText, PenSquare, MessageSquare, Trash2, Rss, Link2, MessageCircle, Image } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { FileText, PenSquare, MessageSquare, Trash2, Rss, Link2, MessageCircle, Image, Menu, X } from "lucide-react";
|
||||
import ThemeToggle from "./ThemeToggle";
|
||||
|
||||
const navItems = [
|
||||
@@ -18,6 +19,16 @@ const navItems = [
|
||||
|
||||
export default function Sidebar() {
|
||||
const pathname = usePathname();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
useEffect(() => { setOpen(false); }, [pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
const original = document.body.style.overflow;
|
||||
document.body.style.overflow = "hidden";
|
||||
return () => { document.body.style.overflow = original; };
|
||||
}, [open]);
|
||||
|
||||
const isActive = (href: string) => {
|
||||
if (href === "/") return pathname === "/";
|
||||
@@ -25,13 +36,28 @@ export default function Sidebar() {
|
||||
};
|
||||
|
||||
return (
|
||||
<aside className="w-1/4 min-w-[200px] max-w-[260px] bg-surface border-r border-line flex flex-col shrink-0">
|
||||
<>
|
||||
<header className="md:hidden fixed top-0 inset-x-0 z-40 h-12 bg-surface border-b border-line flex items-center px-3">
|
||||
<button type="button" onClick={() => setOpen(true)} className="p-2 -ml-1 rounded-md text-text/80 hover:bg-bg hover:text-accent transition-colors" aria-label="menu">
|
||||
<Menu size={18} />
|
||||
</button>
|
||||
<span className="ml-2 text-[13px] font-bold text-accent tracking-wider">{"\u5199\u4f5c\u540e\u53f0"}</span>
|
||||
</header>
|
||||
{open && (
|
||||
<div className="md:hidden fixed inset-0 z-40 bg-[#223d66]/30 backdrop-blur-sm" onClick={() => setOpen(false)} aria-hidden />
|
||||
)}
|
||||
<aside className={`bg-surface border-r border-line flex flex-col shrink-0 transition-transform duration-200 ease-out md:w-1/4 md:min-w-[200px] md:max-w-[260px] md:static md:translate-x-0 fixed top-0 left-0 z-50 h-full w-[78%] max-w-[280px] ${open ? "translate-x-0" : "-translate-x-full md:translate-x-0"}`}>
|
||||
{/* Logo */}
|
||||
<div className="px-5 py-5 border-b border-line">
|
||||
<div className="px-5 py-5 border-b border-line flex items-start justify-between gap-2">
|
||||
<div>
|
||||
<h1 className="text-[15px] font-bold text-accent tracking-wider">
|
||||
写作后台
|
||||
</h1>
|
||||
<p className="text-[11px] text-muted/70 mt-0.5">优世界</p>
|
||||
</div>
|
||||
<button type="button" onClick={() => setOpen(false)} className="md:hidden p-1.5 -mr-1 rounded-md text-muted hover:text-text hover:bg-bg transition-colors" aria-label="close">
|
||||
<X size={16} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Nav */}
|
||||
@@ -61,5 +87,6 @@ export default function Sidebar() {
|
||||
<p className="text-[10px] text-muted/50">localhost:8016</p>
|
||||
</div>
|
||||
</aside>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user