Skip to content

Commit

Permalink
feat: editor 페이지 기능 작업 중
Browse files Browse the repository at this point in the history
  • Loading branch information
JaeHyup0504 committed May 9, 2024
1 parent 2b55c5e commit 6a57429
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 88 deletions.
10 changes: 0 additions & 10 deletions public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,6 @@
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
Expand Down
4 changes: 1 addition & 3 deletions src/components/Editor/Components/Auto.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import React, { useState } from "react";
// import EditSections from "./EditSections";
// import SelectSections from "./SelectSections";
import AutoForm from "./AutoForm";
import EditSections from "./EditSections";
import SelectSections from "./SelectSections";
Expand All @@ -14,7 +12,7 @@ const Auto = () => {
{create ? (
<>
<div className="w-full h-auto">
<EditSections keyName="auto-sections-list" />
<EditSections type="auto" />
</div>
<div className="w-full h-auto">
<SelectSections />
Expand Down
2 changes: 1 addition & 1 deletion src/components/Editor/Components/Builder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const Builder = () => {
return (
<div className="w-full h-full flex flex-col gap-[20px]">
<div className="w-full h-auto">
<EditSections keyName="builder-sections-list" />
<EditSections type="builder" />
</div>
<div className="w-full h-auto">
<SelectSections />
Expand Down
46 changes: 36 additions & 10 deletions src/components/Editor/Components/EditSection.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { List, Reset, TrashCan } from "@carbon/icons-react";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import clsx from "clsx";
import { useSection } from "context/SectionContext";
import { SectionsType } from "../types";

interface Props {
id: number;
title: string | undefined;
markdown: string | undefined;
interface Props extends SectionsType {
focusSection: number;
setFocusSection: React.Dispatch<React.SetStateAction<number | null>>;
onDeleteSection: (e: React.MouseEvent<HTMLElement, MouseEvent>, targetId: number) => void;
onResetSection: (e: React.MouseEvent<HTMLElement, MouseEvent>, targetId: number) => void;
}

const EditSection = ({ id, title, markdown, onDeleteSection }: Props) => {
const EditSection = ({
id,
title,
markdown,
focusSection,
setFocusSection,
onDeleteSection,
onResetSection,
}: Props) => {
const { state, actions } = useSection();

const [hover, setHover] = useState<boolean>(false);
const onMouseEnter = () => setHover(true);
const onMouseLeave = () => setHover(false);
Expand All @@ -23,11 +35,21 @@ const EditSection = ({ id, title, markdown, onDeleteSection }: Props) => {
transform: CSS.Transform.toString(transform),
};

const onClickSection = () => {
actions.setEditorMarkDown(prev => ({ ...prev, id, title, markdown }));
setFocusSection(id);
};

useEffect(() => {
localStorage.setItem("select-section", JSON.stringify(state.editorMarkDown));
}, [onClickSection]);

return (
<div
ref={setNodeRef}
{...attributes}
style={style}
onClick={onClickSection}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
className={clsx(
Expand All @@ -36,16 +58,20 @@ const EditSection = ({ id, title, markdown, onDeleteSection }: Props) => {
"rounded-[8px] border-solid border bg-white border-[#F1F3F5] drop-shadow-[0_1px_1px_rgba(173,181,189,0.25)]",
"cursor-pointer",
{
"focus:outline-none focus:ring-2 focus:ring-textBlue": true,
"ring-2 ring-textBlue": focusSection === id,
},
)}
>
<List {...listeners} size={25} className="fill-textSecondary min-w-[25px]" />
<p className="text-textPrimary mb-0 truncate">{title}</p>
{hover && (
{focusSection === id && (
<div className="flex flex-row gap-[10px] ml-auto">
<button>
<Reset size={20} className="fill-[#ADB5BD]" onClick={() => alert("rest")} />
<button
onClick={e => {
onResetSection(e, id);
}}
>
<Reset size={20} className="fill-[#ADB5BD]" />
</button>
<button
onClick={e => {
Expand Down
32 changes: 24 additions & 8 deletions src/components/Editor/Components/EditSections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ import {
} from "@dnd-kit/sortable";
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
import { useSection } from "context/SectionContext";
import { KeyNameType, SectionsType } from "../types";
import { KeyType, SectionsType } from "../types";

const EditSections = ({ keyName }: KeyNameType) => {
const { value, setValue } = useSection();
const EditSections = ({ type }: KeyType) => {
const { actions } = useSection();
const [sections, setSections] = useState<SectionsType[]>([]);
const [focusSection, setFocusSection] = useState<number | null>(null);

const getIndex = (id: number) => sections.findIndex(el => el.id === id);

Expand All @@ -48,24 +49,36 @@ const EditSections = ({ keyName }: KeyNameType) => {
const onDeleteSection = (e: React.MouseEvent<HTMLElement, MouseEvent>, targetId: number) => {
e.stopPropagation();
setSections(prev => prev.filter(el => el.id !== targetId));
if (sections.length > 1) {
let index;
const deleteSection = sections.findIndex(el => el.id === targetId);
if (deleteSection === 0) {
index = 1;
} else {
index = deleteSection - 1;
}
actions.setEditorMarkDown(sections[index]);
setFocusSection(sections[index].id);
}
};

const onResetSection = (e: React.MouseEvent<HTMLElement, MouseEvent>, targetId: number) => {
e.stopPropagation();
};

useEffect(() => {
const sectionsList = JSON.parse(localStorage.getItem(`${keyName}`) || "[]");
const sectionsList = JSON.parse(localStorage.getItem(`${type}-sections-list`) || "[]");
if (sectionsList.length > 0) {
setSections(sectionsList);
actions.setEditorMarkDown(sectionsList[0]);
setFocusSection(sectionsList[0]?.id);
}
}, []);

useEffect(() => {
localStorage.setItem(`${keyName}`, JSON.stringify(sections));
const sectionsList = JSON.parse(localStorage.getItem(`${keyName}`) || "[]");
const markdownList = sectionsList.map((el: SectionsType) => el.markdown).join("");
setValue(markdownList);
localStorage.setItem(`${type}-sections-list`, JSON.stringify(sections));
const sectionsList = JSON.parse(localStorage.getItem(`${type}-sections-list`) || "[]");
actions.setMarkDowns(sectionsList);
}, [sections]);

return (
Expand All @@ -87,7 +100,10 @@ const EditSections = ({ keyName }: KeyNameType) => {
title={section.title}
id={section.id}
markdown={section.markdown}
focusSection={focusSection!}
setFocusSection={setFocusSection}
onDeleteSection={onDeleteSection}
onResetSection={onResetSection}
/>
))}
</SortableContext>
Expand Down
64 changes: 47 additions & 17 deletions src/components/Editor/Components/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,61 @@
import React from "react";
import React, { useEffect, useState } from "react";
import { useSection } from "context/SectionContext";
import MDEditor, { commands } from "@uiw/react-md-editor";
import { KeyType } from "../types";

const Editor = () => {
const { value: markdown, setValue } = useSection();
const { state, actions } = useSection();
const commandsList = [...commands.getCommands()].slice(0, 17);

const [markdownValue, setMarkdownValue] = useState<string>("");

const onEditEditor = (value: string) => {
setMarkdownValue(value);
actions.setMarkDowns(prev =>
prev.map(markdown => {
if (markdown.id === state.editorMarkDown.id) {
return { ...markdown, markdown: value };
} else {
return markdown;
}
}),
);
localStorage.setItem("builder-sections-list", JSON.stringify(state.markDowns));
};

useEffect(() => {
const markdown = state.editorMarkDown.markdown;
if (markdown) {
setMarkdownValue(markdown);
}
}, [state.editorMarkDown]);

return (
<div
className="w-full h-full rounded-[8px] border-solid border border-textTertiary overflow-y-auto"
data-color-mode="dark"
>
<MDEditor
className="editor"
value={markdown}
onChange={value => setValue(value!)}
preview="edit"
height="100%"
commands={commandsList}
extraCommands={[]}
visibleDragbar={false}
style={{
height: "100%",
overflow: "scroll",
border: "none",
}}
/>
{state.markDowns.length > 0 ? (
<MDEditor
className="editor"
value={markdownValue}
onChange={value => {
onEditEditor(value!);
}}
preview="edit"
height="100%"
commands={commandsList}
extraCommands={[]}
visibleDragbar={false}
style={{
height: "100%",
overflow: "scroll",
border: "none",
}}
/>
) : (
<EmptySections />
)}
</div>
);
};
Expand Down
9 changes: 0 additions & 9 deletions src/components/Editor/Components/SelectSections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,6 @@ const SelectSections = () => {
<div className="h-full max-h-auto flex flex-col gap-[10px]">
<SearchSection />
<SelectSection />
<SelectSection />
<SelectSection />
<SelectSection />
<SelectSection />
<SelectSection />
<SelectSection />
<SelectSection />
<SelectSection />
<SelectSection />
</div>
{openModal && (
<AddSectionModal
Expand Down
21 changes: 12 additions & 9 deletions src/components/Editor/EditorPreviewContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import Preview from "./Components/Preview";
import Raw from "./Components/Raw";
import { Tab, Tabs } from "../Common/Tabs";
import { useSection } from "../../context/SectionContext";
import Editor from "./Components/Editor";
import { Download } from "@carbon/icons-react";
import clsx from "clsx";
import { SectionsType } from "./types";

const EditorPreviewContainer = () => {
const { value } = useSection();
const { state } = useSection();
const markDownsData = state.markDowns.map(el => el.markdown).join("");
const [selectedTab, setSelectedTab] = useState<string | undefined>("Preview");

const handleTabClick = (value?: string | undefined) => {
Expand All @@ -18,11 +20,12 @@ const EditorPreviewContainer = () => {
const onDownloadMarkdown = () => {
try {
const element = document.createElement("a");
const file = new Blob([value], { type: "text/plain" });
const file = new Blob([markDownsData], { type: "text/plain" });
element.href = URL.createObjectURL(file);
element.download = "README.md";
document.body.appendChild(element);
element.click();
element.remove();
alert("Download is complete");
} catch (error) {
alert("Download failed.");
Expand Down Expand Up @@ -57,21 +60,21 @@ const EditorPreviewContainer = () => {
"bg-textBlue text-white ",
"rounded-[8px]",
{
"hover:bg-[#6E9EFF]": value.length > 0,
"cursor-pointer": value.length > 0,
"hover:bg-[#6E9EFF]": state.markDowns.length > 0,
"cursor-pointer": state.markDowns.length > 0,
},
{
"bg-textTertiary": value.length === 0,
"bg-textTertiary": state.markDowns.length === 0,
},
)}
disabled={value.length > 0 ? false : true}
disabled={state.markDowns.length > 0 ? false : true}
>
<Download size={16} />
<p className="mb-0 text-sm">Download</p>
</button>
</div>
{selectedTab === "Preview" && <Preview value={value} />}
{selectedTab === "Raw" && <Raw value={value} />}
{selectedTab === "Preview" && <Preview value={markDownsData} />}
{selectedTab === "Raw" && <Raw value={markDownsData} />}
</div>
</div>
</>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Editor/Modal/AddSectionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const AddSectionModal = ({ modalRef, modalOutSideClick, onClose, openModal }: Pr
if (openModal) {
inputRef.current?.focus();
}
}, []);
}, [openModal]);

return (
<div
Expand Down
11 changes: 5 additions & 6 deletions src/components/Editor/types.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
export interface ValueType {
value: string | undefined;
}

export interface SectionsType {
id: number;
title: string | undefined;
markdown: string | undefined;
}
export interface ValueType {
value: string | undefined;
}

export interface KeyNameType {
keyName: string;
export interface KeyType {
type: string;
}
Loading

0 comments on commit 6a57429

Please sign in to comment.