Merge branch 'main' of http://192.168.0.251:3000/localnet/localhost-front
This commit is contained in:
commit
51f5dfb167
19
package-lock.json
generated
19
package-lock.json
generated
@ -9,6 +9,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
|
"@tinymce/tinymce-vue": "^5.1.1",
|
||||||
"@vueup/vue-quill": "^1.2.0",
|
"@vueup/vue-quill": "^1.2.0",
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
@ -1514,6 +1515,18 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tinymce/tinymce-vue": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tinymce/tinymce-vue/-/tinymce-vue-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-iO57HOWesFOhsaqjA5Ea6sDvQBmJJH3/dq00Uvg7metlct2kLF+ctRgoDsetLt6gmeZ7COPftr814/XzqnJ/dg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tinymce": "^6.0.0 || ^5.5.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||||
@ -4312,6 +4325,12 @@
|
|||||||
"url": "https://opencollective.com/unts"
|
"url": "https://opencollective.com/unts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tinymce": {
|
||||||
|
"version": "6.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-6.8.5.tgz",
|
||||||
|
"integrity": "sha512-qAL/FxL7cwZHj4BfaF818zeJJizK9jU5IQzTcSLL4Rj5MaJdiVblEj7aDr80VCV1w9h4Lak9hlnALhq/kVtN1g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/totalist": {
|
"node_modules/totalist": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
|
"@tinymce/tinymce-vue": "^5.1.1",
|
||||||
"@vueup/vue-quill": "^1.2.0",
|
"@vueup/vue-quill": "^1.2.0",
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
|
|||||||
@ -1 +1,11 @@
|
|||||||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
{
|
||||||
|
"name": "",
|
||||||
|
"short_name": "",
|
||||||
|
"icons": [
|
||||||
|
{ "src": "/img/favicon/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" },
|
||||||
|
{ "src": "/img/favicon/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" }
|
||||||
|
],
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
||||||
|
|||||||
50
src/components/BoardDetail.vue
Normal file
50
src/components/BoardDetail.vue
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<div class="col">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex justify-content-between align-items-center flex-wrap mb-6 gap-2">
|
||||||
|
<div class="me-1">
|
||||||
|
<h5 class="mb-0">리액트 강의 추천좀</h5>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<div class="badge bg-lighter rounded d-flex align-items-center">
|
||||||
|
<img src="/img/icons/misc/pdf.png" alt="img" width="15" class="me-2">
|
||||||
|
<span class="h6 mb-0 text-body">invoices.pdf</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr class="my-6">
|
||||||
|
<div class="d-flex min-150">
|
||||||
|
<p class="mb-0">현재 뷰 사용중인데 리액트 공부가 해보고 싶습니다. 강의 추천해주십쇼! 리액트 1도 모릅니다.</p>
|
||||||
|
</div>
|
||||||
|
<div class="card shadow-none border mt-6">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex justify-content-start align-items-top">
|
||||||
|
<div class="avatar-wrapper">
|
||||||
|
<div class="avatar me-4"><img src="/img/avatars/11.png" alt="Avatar" class="rounded-circle"></div>
|
||||||
|
</div>
|
||||||
|
<div class="w-100">
|
||||||
|
<textarea class="form-control" id="exampleFormControlTextarea1" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4 text-end">
|
||||||
|
<button class="btn btn-primary my-4">답변 쓰기</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.min-150 {
|
||||||
|
min-height: 150px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
69
src/components/editor/QEditor.vue
Normal file
69
src/components/editor/QEditor.vue
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<template>
|
||||||
|
<Editor :api-key="editorKey" :init="init" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import Editor from '@tinymce/tinymce-vue';
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
|
const editorKey = '71nhna4fusscfsf8qvo9cg3ul4uydwt346izxa6ra6zwjsz7';
|
||||||
|
const init = reactive({
|
||||||
|
toolbar_mode: 'sliding',
|
||||||
|
plugins: [
|
||||||
|
// Core editing features
|
||||||
|
'anchor',
|
||||||
|
'autolink',
|
||||||
|
'charmap',
|
||||||
|
'codesample',
|
||||||
|
'emoticons',
|
||||||
|
'image',
|
||||||
|
'link',
|
||||||
|
'lists',
|
||||||
|
'media',
|
||||||
|
'searchreplace',
|
||||||
|
'table',
|
||||||
|
'visualblocks',
|
||||||
|
'wordcount',
|
||||||
|
// Your account includes a free trial of TinyMCE premium features
|
||||||
|
// Try the most popular premium features until Dec 30, 2024:
|
||||||
|
'checklist',
|
||||||
|
'mediaembed',
|
||||||
|
'casechange',
|
||||||
|
'export',
|
||||||
|
'formatpainter',
|
||||||
|
'pageembed',
|
||||||
|
'a11ychecker',
|
||||||
|
'tinymcespellchecker',
|
||||||
|
'permanentpen',
|
||||||
|
'powerpaste',
|
||||||
|
'advtable',
|
||||||
|
'advcode',
|
||||||
|
'editimage',
|
||||||
|
'advtemplate',
|
||||||
|
'ai',
|
||||||
|
'mentions',
|
||||||
|
'tinycomments',
|
||||||
|
'tableofcontents',
|
||||||
|
'footnotes',
|
||||||
|
'mergetags',
|
||||||
|
'autocorrect',
|
||||||
|
'typography',
|
||||||
|
'inlinecss',
|
||||||
|
],
|
||||||
|
toolbar:
|
||||||
|
'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | link image media table mergetags | addcomment showcomments | spellcheckdialog a11ycheck typography | align lineheight | checklist numlist bullist indent outdent | emoticons charmap | removeformat',
|
||||||
|
tinycomments_mode: 'embedded',
|
||||||
|
tinycomments_author: 'Author name',
|
||||||
|
mergetags_list: [
|
||||||
|
{ value: 'First.Name', title: 'First Name' },
|
||||||
|
{ value: 'Email', title: 'Email' },
|
||||||
|
],
|
||||||
|
ai_request: (request, respondWith) => respondWith.string(() => Promise.reject('See docs to implement AI Assistant')),
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.tox-statusbar{
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
14
src/components/input/FormFile.vue
Normal file
14
src/components/input/FormFile.vue
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-4 row">
|
||||||
|
<label for="html5-email-input" class="col-md-2 col-form-label"> 첨부파일 </label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input class="form-control" type="file" id="formFileMultiple" multiple />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
60
src/components/input/FormInput.vue
Normal file
60
src/components/input/FormInput.vue
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-4 row">
|
||||||
|
<label for="html5-text-input" class="col-md-2 col-form-label">
|
||||||
|
{{ $props.title }}
|
||||||
|
<span :class="$props.isEssential ? 'text-red' : 'none'">*</span>
|
||||||
|
</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input class="form-control" :type="$props.type" @input="updateInput" :value="$props.value" :maxLength="$props.maxlength" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const prop = defineProps({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '라벨',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
isEssential: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'text',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
require: false,
|
||||||
|
},
|
||||||
|
maxlength: {
|
||||||
|
type: Number,
|
||||||
|
default: 30,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emits = defineEmits(['inputVal'])
|
||||||
|
|
||||||
|
const updateInput = function (event) {
|
||||||
|
|
||||||
|
//Type Number 일때 maxlength 적용 안됨 방지
|
||||||
|
if (event.target.value.length > prop.maxlength) {
|
||||||
|
event.target.value = event.target.value.slice(0, prop.maxlength);
|
||||||
|
}
|
||||||
|
emits('inputVal', event.target.value);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.none {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
21
src/components/input/FormSelect.vue
Normal file
21
src/components/input/FormSelect.vue
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-4 row">
|
||||||
|
<label for="html5-email-input" class="col-md-2 col-form-label">
|
||||||
|
카테고리
|
||||||
|
<span class="text-red">*</span>
|
||||||
|
</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<select class="form-select" id="exampleFormControlSelect1" aria-label="Default select example">
|
||||||
|
<option selected value="1">자유</option>
|
||||||
|
<option value="1">임시</option>
|
||||||
|
<option value="2">공지</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
@ -38,7 +38,7 @@
|
|||||||
<div class="text-truncate" data-i18n="Analytics">Main</div>
|
<div class="text-truncate" data-i18n="Analytics">Main</div>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
<li class="menu-item" :class="$route.path == '/board' ? 'active' : '' ">
|
<li class="menu-item" :class="$route.path.includes('/board') ? 'active' : '' ">
|
||||||
<RouterLink class="menu-link" to="board" >
|
<RouterLink class="menu-link" to="board" >
|
||||||
<i class="menu-icon tf-icons bx bx-layout"></i>
|
<i class="menu-icon tf-icons bx bx-layout"></i>
|
||||||
<div class="text-truncate" data-i18n="Analytics">Board</div>
|
<div class="text-truncate" data-i18n="Analytics">Board</div>
|
||||||
|
|||||||
@ -9,4 +9,7 @@ const pinia = createPinia()
|
|||||||
pinia.use(piniaPersist)
|
pinia.use(piniaPersist)
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
app.use(router).use(pinia).use(dayjs).mount('#app')
|
app.use(router)
|
||||||
|
.use(pinia)
|
||||||
|
.use(dayjs)
|
||||||
|
.mount('#app')
|
||||||
|
|||||||
@ -5,28 +5,23 @@ import BoardWrite from '@v/board/BoardWrite.vue';
|
|||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name : 'main',
|
|
||||||
component: () => import('@v/MainView.vue'),
|
component: () => import('@v/MainView.vue'),
|
||||||
// meta: { requiresAuth: true }
|
// meta: { requiresAuth: true }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/board',
|
path: '/board',
|
||||||
name : 'board',
|
|
||||||
component: () => import('@v/board/TheBoard.vue'),
|
component: () => import('@v/board/TheBoard.vue'),
|
||||||
children : [
|
children : [
|
||||||
{
|
{
|
||||||
path : '',
|
path : '',
|
||||||
name : 'boardList',
|
|
||||||
component : () => import('@v/board/BoardList.vue')
|
component : () => import('@v/board/BoardList.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path : 'write',
|
path : 'write',
|
||||||
name : 'boardWrite',
|
|
||||||
component : () => import('@v/board/BoardWrite.vue')
|
component : () => import('@v/board/BoardWrite.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path : 'get/:id',
|
path : 'get/:id',
|
||||||
name : 'boardView',
|
|
||||||
component : () => import('@v/board/BoardView.vue')
|
component : () => import('@v/board/BoardView.vue')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,11 +1,60 @@
|
|||||||
<template>
|
<template>
|
||||||
dasdasdas
|
<div class="container-xxl flex-grow-1 container-p-y">
|
||||||
|
<div class="card">
|
||||||
|
<div class="pb-4 rounded-top">
|
||||||
|
<div class="container py-12 px-xl-10 px-4" style="padding-bottom: 0px !important">
|
||||||
|
<h3 class="text-center mb-2 mt-4">글 작성</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xl-6">
|
||||||
|
<!-- HTML5 Inputs -->
|
||||||
|
<div class="card mb-6">
|
||||||
|
<div class="card-body">
|
||||||
|
<FormInput title="제목" :is-essential="true" @input-val="title = $event"/>
|
||||||
|
|
||||||
|
<FormSelect/>
|
||||||
|
|
||||||
|
<FormInput title="비밀번호" type="password" :is-essential="true" @input-val="password = $event"/>
|
||||||
|
|
||||||
|
<FormFile />
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="html5-tel-input" class="col-md-2 col-form-label">
|
||||||
|
내용
|
||||||
|
<span class="text-red">*</span>
|
||||||
|
</label>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<QEditor />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4 d-flex justify-content-end">
|
||||||
|
<button type="button" class="btn btn-info right">목록</button>
|
||||||
|
<button type="button" class="btn btn-primary ms-1">작성</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import QEditor from '@c/editor/QEditor.vue';
|
||||||
|
import FormInput from '@c/input/FormInput.vue';
|
||||||
|
import FormSelect from '@c/input/FormSelect.vue';
|
||||||
|
import FormFile from '@c/input/FormFile.vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const title = ref('');
|
||||||
|
const password = ref('');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.text-red {
|
||||||
|
color: red;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user