Skip to content

Commit

Permalink
feat: add editor config to support multi mode and better feature
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronConlon committed Aug 19, 2024
1 parent c09fdbf commit ae1132f
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 102 deletions.
20 changes: 12 additions & 8 deletions src/components/Blog/Editor/RecentIssues.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ export default function RecentIssues({

return (
<div className="border h-screen overflow-auto">
<h1 className="p-4 text-primary font-semibold text-2xl mb-2 sticky top-0 w-full bg-white z-10 flex justify-between">
<span className="bg-primary text-white px-2 rounded-md min-w-8 text-center">
{issues.length}
</span>
<h1 className="p-4 text-primary font-semibold text-2xl mb-2 sticky top-0 w-full bg-white z-10 flex gap-4">
<span>{isLocal ? "Local Issues" : "Online issues"}</span>
<span className="text-center font-thin text-sm underline underline-offset-8 mt-1">
{issues.length}
</span>
</h1>

<ul className="flex flex-col gap-4 font-thin text-sm p-4">
Expand All @@ -38,15 +38,19 @@ export default function RecentIssues({
: issues.map(({ number, title, updated_at, id, ...rest }) => (
<li
key={number}
className="grid grid-cols-[168px_auto_48px] gap-1 group hover:bg-primary/10 p-1"
className="grid grid-cols-[190px_auto_48px] gap-1 group hover:bg-primary/10 p-1"
>
<span className="flex items-center gap-1 text-primary">
<Calendar size={16} className="opacity-60" />
Updated: {formatTimeFromNow(updated_at!)}
</span>
<Link href={`/blog/post/${id}`} className="truncate">
{title}
</Link>
{isLocal ? (
<div className="truncate">{title}</div>
) : (
<Link href={`/blog/post/${id}`} className="truncate">
{title}
</Link>
)}
<div className="flex items-center justify-end">
<Edit2Icon
className="opacity-0 group-hover:opacity-100 transition-opacity cursor-pointer mr-2"
Expand Down
207 changes: 113 additions & 94 deletions src/components/Blog/Editor/VditorComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ export default function VditorComponent({
const { data, content } = resolveIssueBody(body);
if (vd === undefined) {
const vditor = new Vditor("vditor", {
outline: {
enable: true,
position: "left",
},
mode: "wysiwyg",
preview: {
hljs: {
lineNumber: true,
defaultLang: "javascript",
},
},
after: () => {
// 仅初始化时设置
if (!vd) {
Expand All @@ -59,6 +70,12 @@ export default function VditorComponent({
setVd(vditor);
},
height: "100%",
cache: {
enable: false,
},
counter: {
enable: true,
},
input: () => {
if (isLocalIssue) {
// 每次都同步数据到 storage
Expand All @@ -78,6 +95,10 @@ export default function VditorComponent({
});
} else {
vd.setValue(content);
setTitle(issue?.title ?? "");
setDescription(data?.description ?? "");
setNewLabels(issue?.labels ?? []);
setCover(data?.cover ?? "");
}
}, [issue, isLocalIssue]);

Expand Down Expand Up @@ -145,116 +166,114 @@ export default function VditorComponent({
};

return (
<div className="h-screen flex">
<div className="max-w-[760px] bg-gray-50">
<div>
<div className="relative grid grid-cols-[48px_auto_160px] items-center m-2">
<span className="px-2 py-1 rounded-md text-center text-md text-primary font-semibold mt-1">
标题
</span>
<input
className="block p-1 mb-1 !border-b outline-none shadow-sm m-2"
value={title}
onChange={(e) => {
const value = e.target.value;
setTitle(value);
}}
/>
<div className="h-screen max-w-[1260px]">
<div>
<div className="relative grid grid-cols-[48px_auto_160px] items-center m-2">
<span className="px-2 py-1 rounded-md text-center text-md text-primary font-semibold mt-1">
标题
</span>
<input
className="block p-1 mb-1 !border-b outline-none shadow-sm m-2"
value={title}
onChange={(e) => {
const value = e.target.value;
setTitle(value);
}}
/>

<div className="flex items-center gap-2 absolute translate-y-[-50%] right-2 top-[50%]">
{!isLocalIssue && (
<button
onClick={async (e) => {
e.stopPropagation();
e.preventDefault();
setState(state === "open" ? "closed" : "open");
const newIssue = await updateIssue(
{
state: state === "open" ? "closed" : "open",
},
issue?.number!,
token!
);
setIssues((prev) =>
prev.map((i) => {
if (i.number === issue?.number) {
return newIssue;
}
return i;
})
);
}}
className="border-primary/60 border text-primary px-2 py-1 rounded-md font-thin text-sm"
>
{state === "open" ? "⚠️ 关闭" : "🚄 打开"}
</button>
)}
<div className="flex items-center gap-2 absolute translate-y-[-50%] right-2 top-[50%]">
{!isLocalIssue && (
<button
onClick={(e) => {
onClick={async (e) => {
e.stopPropagation();
e.preventDefault();
onPublish();
setState(state === "open" ? "closed" : "open");
const newIssue = await updateIssue(
{
state: state === "open" ? "closed" : "open",
},
issue?.number!,
token!
);
setIssues((prev) =>
prev.map((i) => {
if (i.number === issue?.number) {
return newIssue;
}
return i;
})
);
}}
className="border-primary/60 border text-primary px-2 py-1 rounded-md font-thin text-sm"
>
🚀 发布
{state === "open" ? "⚠️ 关闭" : "🚄 打开"}
</button>
</div>
</div>
<div className="flex">
<div className="m-2 w-[600px]">
<SelectLabels
labels={labels}
onChange={(e: string[]) => {
console.log("change...", e);
setNewLabels(
e.map((i) => labels.find((label) => label.name === i)!)
);
}}
defaultLabels={issue?.labels ?? []}
/>
</div>
<div className="flex items-center gap-1 ml-auto mr-2 font-thin text-sm">
<Calendar size={16} className="opacity-60" />
<span>{formatTimeFromNow(issue?.updated_at!)}</span>
</div>
)}
<button
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
onPublish();
}}
className="border-primary/60 border text-primary px-2 py-1 rounded-md font-thin text-sm"
>
🚀 发布
</button>
</div>
</div>
<div className="h-[calc(100vh-300px)] p-2">
<div id="vditor" className="vditor "></div>
</div>
<div className="p-2">
<div className="relative">
<span className="absolute -top-4 left-4 bg-white p-1 py-0.5 text-primary font-thin">
Cover Image
</span>
<input
type="text"
value={cover}
onChange={(e) => {
const value = e.target.value;
setCover(value);
<div className="flex">
<div className="m-2 w-[600px]">
<SelectLabels
labels={labels}
onChange={(e: string[]) => {
console.log("change...", e);
setNewLabels(
e.map((i) => labels.find((label) => label.name === i)!)
);
}}
className="w-full p-2 border border-gray-200 outline-none mb-6"
defaultLabels={issue?.labels ?? []}
/>
</div>
<div className="relative">
<span className="absolute -top-4 left-4 bg-white p-1 py-0.5 text-primary font-thin">
Description
</span>
<textarea
value={description}
onChange={(e) => {
const value = e.target.value;
setDescription(value);
}}
className="w-full p-2 border-gray-200 outline-none border"
role="textbox"
rows={3}
/>
<div className="flex items-center gap-1 ml-auto mr-2 font-thin text-sm">
<Calendar size={16} className="opacity-60" />
<span>{formatTimeFromNow(issue?.updated_at!)}</span>
</div>
</div>
</div>
<div className="h-[calc(100vh-300px)] p-2">
<div id="vditor" className="vditor "></div>
</div>
<div className="p-2">
<div className="relative">
<span className="absolute -top-4 left-4 bg-white p-1 py-0.5 text-primary font-thin">
Cover Image
</span>
<input
type="text"
value={cover}
onChange={(e) => {
const value = e.target.value;
setCover(value);
}}
className="w-full p-2 border border-gray-200 outline-none mb-6"
/>
</div>
<div className="relative">
<span className="absolute -top-4 left-4 bg-white p-1 py-0.5 text-primary font-thin">
Description
</span>
<textarea
value={description}
onChange={(e) => {
const value = e.target.value;
setDescription(value);
}}
className="w-full p-2 border-gray-200 outline-none border"
role="textbox"
rows={3}
/>
</div>
</div>
</div>
);
}

0 comments on commit ae1132f

Please sign in to comment.