Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Mission5/이종길] Project_Notion_VanillaJS 과제 #38

Open
wants to merge 42 commits into
base: 4/#5_jgjgill
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
bc9b44a
feat: 기본 폴더 및 파일 세팅
jgjgill Jun 30, 2023
f60c9cb
feat: 문서 추가 기능 구현
jgjgill Jul 1, 2023
4edc593
feat: 모든 문서 불러오기 기능 구현
jgjgill Jul 1, 2023
78870f8
feat: 특정 문서 읽기 기능 구현
jgjgill Jul 1, 2023
d0db2fd
feat: 문서 수정 기능 구현
jgjgill Jul 1, 2023
7d7660f
feat: 문서 트리 형태로 불러오기 기능 구현
jgjgill Jul 1, 2023
134fb2c
fix: 중복 이벤트 발생 에러 수정
jgjgill Jul 1, 2023
5f3005e
feat: 문서 삭제 기능 구현
jgjgill Jul 2, 2023
1357324
fix: 문서 추가 방식 변경
jgjgill Jul 2, 2023
64a6d5c
refactor: 라우팅 방식 변경
jgjgill Jul 2, 2023
6d490c6
feat: 문서 수정 기능 변경
jgjgill Jul 2, 2023
502b74d
refactor: 코드 중복 제거 및 추상화 작업
jgjgill Jul 2, 2023
5e81344
chore: Edit 파일 Document로 이름 변경
jgjgill Jul 2, 2023
ac3e47b
feat: 재귀 관련 템플릿 작업
jgjgill Jul 2, 2023
66716bc
feat: 자식 문서로 이동 기능 구현
jgjgill Jul 2, 2023
b989893
chore: Document 관련 이름 변경
jgjgill Jul 3, 2023
7e5e929
feat: api 요청에 따른 상태 업데이트하도록 임시 구현
jgjgill Jul 3, 2023
c51e413
feat: 상태 관리 방식으로 변경 작업
jgjgill Jul 4, 2023
a522eb2
feat: 자식 문서 추가시 상태 최신화 구현
jgjgill Jul 4, 2023
7809c08
fix: 수정 및 제거 관련 자식 문서 최신화하도록 변경
jgjgill Jul 4, 2023
9d47d3a
refactor: 현재 문서 삭제시 홈으로 이동하는 방식으로 변경
jgjgill Jul 4, 2023
3c38e75
fix: 라우팅 관련 작업
jgjgill Jul 4, 2023
0778f63
feat: 자동 완성 및 최근 검색 기능 구현
jgjgill Jul 4, 2023
6918089
chore: 개행 및 안쓰는 코드 정리
jgjgill Jul 5, 2023
97c35be
style: 스타일 관련 작업
jgjgill Jul 5, 2023
f619831
fix: 문서 삭제 관련 로직 변경
jgjgill Jul 5, 2023
0ba048e
fix: 타이틀 변경시 에디터 상태로 변경하도록 로직 변경
jgjgill Jul 5, 2023
931b895
style: Home, Editor 관련 스타일 작업
jgjgill Jul 5, 2023
8872665
feat: NotFound 관련 작업
jgjgill Jul 5, 2023
13cb534
refactor: 자잘한 리팩토링 진행
jgjgill Jul 5, 2023
0979e02
feat: 검색 관련 포커스 기능 추가
jgjgill Jul 5, 2023
6428239
fix: 자식 문서 여백 문제 관련 작업
jgjgill Jul 5, 2023
6bc441b
feat: 토글 기능 구현
jgjgill Jul 5, 2023
f281d38
refactor: 디바운스 함수 분리
jgjgill Jul 6, 2023
d5f507a
feat: 툴팁 기능 구현
jgjgill Jul 6, 2023
c1870b6
refactor: 파일 구조 변경 및 코드 수정
jgjgill Jul 6, 2023
f29f3a1
style: 에디터에서의 자식 문서 스타일 작업
jgjgill Jul 6, 2023
6100dc0
chore: 오타 수정
jgjgill Jul 6, 2023
00d57ac
fix: 스크롤 초기화되는 문제 관련 작업
jgjgill Jul 6, 2023
f229c64
refactor: 변수명 변경
jgjgill Jul 17, 2023
b93a98a
fix: 에러 관련 작업
jgjgill Jul 17, 2023
6c2a351
style: 토글 디폴트값 변경
jgjgill Jul 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import { PATH } from "./constants/path.js";
import { initRouter, push } from "./utils/route.js";
import RecurDocumentList from "./components/template/RecurDocumentList.js";
import {
TrieDocument,
addChildDocument,
editTitleDocument,
findAllDocument,
removeDocument,
} from "./utils/document.js";

Expand All @@ -25,21 +27,26 @@ export default function App({ appElement }) {
leftContainerElement.className = "left-container";
rightContainerEleement.className = "right-container";

const trie = new TrieDocument();

let timer = null;

this.state = [];

this.setState = (nextState) => {
this.state = nextState;
findAllDocument(this.state, (title, id) => trie.insert(title, id));

documentListComponent.render();
};

this.tempSetState = (nextState) => {
this.editorSetState = (nextState) => {
this.state = nextState;
documentEditorComponent.render();
};

const layoutComponent = new Layout({ appElement });

const documentListComponent = new DocumentList({
parentElement: leftContainerElement,
renderItemComponent: (parentElement) => {
Expand All @@ -53,7 +60,7 @@ export default function App({ appElement }) {
(documentId) => {
const newState = removeDocument(documentId, this.state);
if (Number(window.location.pathname.split("/")[2]) !== documentId) {
this.tempSetState(newState);
this.editorSetState(newState);
}

push(PATH.HOME);
Expand All @@ -67,7 +74,12 @@ export default function App({ appElement }) {
this.setState(nextState);
},
});
const homeComponent = new Home({ parentElement: rightContainerEleement });

const homeComponent = new Home({
parentElement: rightContainerEleement,
search: (text) => trie.search(text),
});

const documentEditorComponent = new DocumentEditor({
parentElement: rightContainerEleement,
onEditing: (document) => {
Expand Down
70 changes: 69 additions & 1 deletion src/components/domain/Home.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,80 @@
export default function Home({ parentElement }) {
import { PATH } from "../../constants/path.js";
import { push } from "../../utils/route.js";
import { getItem, setItem } from "../../utils/storage.js";

export default function Home({ parentElement, search }) {
if (!new.target) return new Home(...arguments);

const containerElement = document.createElement("div");

let timer = null;

this.state = {
text: "",
list: [],
};

this.setState = (nextState) => {
this.state = nextState;
this.render();
};

containerElement.addEventListener("input", (e) => {
if (!e.target.closest(".search-input")) return;

if (timer !== null) {
clearTimeout(timer);
}

timer = setTimeout(() => {
if (e.target.value === "") {
this.setState({ text: e.target.value, list: [] });
return;
}

const searchList = search(e.target.value);
this.setState({ text: e.target.value, list: searchList });
}, 1000);
});

containerElement.addEventListener("click", (e) => {
if (!e.target.closest("li")) return;

push(`${PATH.DOCUMENTS}/${e.target.dataset.id}`);
setItem("recent-search-list", [
...getItem("recent-search-list", []),
{ id: e.target.dataset.id, title: e.target.innerText },
]);
});

this.render = () => {
parentElement.append(containerElement);
containerElement.innerHTML = `
<h1>Home 입니다.</h1>
<input placeholder="종션 전체 문서 검색" autofocus class="search-input" value="${
this.state.text
}" />
${
this.state.list.length === 0 && this.state.text !== ""
? `<p>${this.state.text}와(과) 일치하는 검색결과가 없습니다.</p>`
: `<ul>${this.state.list
.map(
(item) =>
`<li data-id=${item.id}>${
item.title === "" ? "제목 없음" : item.title
}</li>`
)
.join("")}
</ul>`
}
<div>
<h3>최근 검색어 목록</h3>
<ul>
${getItem("recent-search-list", [])
.map((item) => `<li data-id="${item.id}">${item.title}</li>`)
.join("")}
</ul>
</div>
`;
};

Expand Down
78 changes: 78 additions & 0 deletions src/utils/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,81 @@ export function editTitleDocument(documentId, state, documentTitle) {

return tempState;
}

export function findAllDocument(state, temp) {
const stack = [];
const tempState = structuredClone(state);

for (const temp of tempState) {
stack.push(temp);
}

while (stack.length !== 0) {
const current = stack.pop();

temp(current.title ?? "", current.id);

for (const document of current.documents) {
stack.push(document);
}
}
}

function Node(value = "") {
this.value = value;
this.children = new Map();
this.isWord = false;
this.list = [];
}

export function TrieDocument() {
this.root = new Node();

this.insert = (string, id) => {
let currentNode = this.root;

for (const char of string) {
if (!currentNode.children.has(char)) {
currentNode.children.set(char, new Node(currentNode.value + char));
}
currentNode = currentNode.children.get(char);
}

currentNode.isWord = true;
currentNode.list.push({ title: string, id });
};

this.search = (value) => {
const queue = [];
const searchList = [];
let index = 0;
let currentNode = this.root;

for (const char of value) {
if (!currentNode.children.has(char)) {
return [];
}

currentNode = currentNode.children.get(char);
}

queue.push(currentNode);

while (index < queue.length) {
const currentNode = queue[index];
index += 1;

if (currentNode.isWord) {
for (const item of currentNode.list) {
searchList.push(item);
}
}

for (const [key, child] of currentNode.children) {
queue.push(child);
}
}

return searchList;
};
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trie 실습 했던걸 활용해서 검색 기능 만드신게 정말 인상 깊습니다... 👍👍