이제 글 추가하는 어드민 화면을 만들어보자.
총 3가지가 필요하다.
뭐 유명한 웹 에디터는 summernote
가 있고, 마침 svelte 용으로 wrapping 된 버전이 존재하는 것이 확인된다. (https://github.com/easylogic/svelte-summernote)
근데 사용법을 보니 명시적으로 jQuery 를 넣어야 하는 듯...
import 'jquery'
import SvelteSummernoteLite from '@easylogic/svelte-summernote'
import '@easylogic/svelte-summernote/index.css'
......
jQuery
는 훌륭한 라이브러리지만 지금은 왠지 명시적으로 쓰기 싫다.
그래서 먼저 Toast UI
의 에디터를 사용해보기로 헸다. (https://github.com/nhn/tui.editor/tree/master/apps/editor)
뭐 이전 회사에서도 써보기도 했고, Toast UI
를 써보고 안되면 summernote
써보지 뭐...
다만 웹 에디터를 적용하기 전에 먼저 소스 정리가 필요하다.
Article 추가 화면은 여기다가 만들고, 웹 에디터 부분을 제외한 나머지 부분들을 넣어보자.
근데 생각해보니 메뉴 선택하는 화면은 사실상 AdminMenu.svelte
화면과 동일하다.
코드를 그대로 복사해도 되긴 하지만... 중복이므로 별도의 컴포넌트로 빼고 적용하자.
AdminMenuSelectContainer.svelte
AdminMenu.svelte
내에 있던 UI & 로직들을 여기로 옮김<Content>
<div class="card-content-container">
{#each parents as parent, i}
<div>
<MenuSelect menus={parent.list} depth={i} on:change={changeParent} initTime={parents.initTime}></MenuSelect>
</div>
{/each}
</div>
<pre><h2>선택된 부모 메뉴 : { selectedParents() }</h2></pre>
</Content>
<Actions>
<Button on:click={ init } variant="raised"><Label>초기화</Label></Button>
</Actions>
<script>
import { Content, Actions } from '@smui/card';
import Button, { Label } from '@smui/button';
import { createEventDispatcher } from 'svelte';
import MenuSelect from '../child/MenuSelect.svelte';
import menu from '../../store/menu.js';
const dispatch = createEventDispatcher();
let parents = [];
$: selectedParents = () => {
let str = '';
parents.map(parent => {
if (!parent.select || !parent.select.name) {
return;
}
if (str) {
str += ' > ';
}
str += parent.select.name;
});
if (!str) {
str = '없음';
}
return str;
};
$: {
let parent = null;
for (let i = parents.length - 1; i >= 0; i--) {
if (parents[i].select !== '선택 안함' && !!parents[i].select?._id) {
parent = parents[i].select._id;
break;
}
}
dispatch('change', { parent });
}
const changeParent = (event) => {
const { value, depth } = event.detail;
if (!value) {
return;
}
const initTime = parents.initTime;
parents = parents.slice(0, depth + 1);
parents.initTime = initTime;
parents[depth].select = value;
if (value.children && value.children.length > 0) {
parents.push({list: [...value.children], select: null});
}
};
const init = () => {
parents = [{list: $menu, select: null}];
parents.initTime = (new Date()).getTime();
};
menu.subscribe(value => {
init();
});
</script>
<style>
.card-content-container {
display: flex;
flex-wrap: wrap;
}
.card-content-container > div {
flex-basis: 0px;
min-width: 245px;
margin-right: 12px;
}
pre h2 {
color: orange;
}
</style>
추가로createEventDispatcher
로 선택된 메뉴에 대한 정보를 부모 컴포넌트 - AdminMenu.svelte
, AdminArticle.svelte
에 전달하는 부분도 구현하고, 하는 김에 style 부분도 정리하고 전반적으로 코드 정리도 같이 했다.
이제 AdminMenu.svelte
, AdminArticle.svelte
안에 새로 만든 컴포넌트를 적용하자.
AdminMenuSelectContainer.svelte
를 적용한 코드
<div class="card-container">
<h3>부모 메뉴 선택</h3>
<Card variant="outlined">
<AdminMenuSelectContainer on:change={chageParent}></AdminMenuSelectContainer>
</Card>
</div>
...
<script>
import AdminMenuSelectContainer from '../child/AdminMenuSelectContainer.svelte';
let parent = null;
const chageParent = e => {
parent = e.detail.parent;
};
....
</script>
구현된 화면은 아래와 같다.
의도대로 잘 동작하는 중 ㅎㅎ 이제 웹 에디터만 추가하면 됨~.