feat: add create & edit article page

This commit is contained in:
mutoe 2020-10-20 22:33:50 +08:00
parent f7c4dbb3d5
commit 125c23d55a
No known key found for this signature in database
GPG Key ID: ABE5E78D073FC208
5 changed files with 159 additions and 23 deletions

View File

@ -26,20 +26,18 @@
</button>
<AppLink
v-if="displayEditButton"
class="btn btn-outline-secondary btn-sm space"
name="editor"
name="edit-article"
:params="{slug: article.slug}"
>
<i class="ion-edit space" /> Edit Article
</AppLink>
<button class="btn btn-outline-danger btn-sm">
<i class="ion-trash-a" /> Delete Article
</button>
//
<button
class="btn btn-outline-danger btn-sm disabled"
disabled
v-if="displayEditButton"
class="btn btn-outline-danger btn-sm"
@click="onDelete"
>
<i class="ion-trash-a" /> Delete Article
</button>
@ -47,13 +45,31 @@
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue'
import { computed, defineComponent, PropType } from 'vue'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex'
import { deleteArticle } from '../services/article/deleteArticle'
import { Store } from '../store'
export default defineComponent({
name: 'ArticleMeta',
props: {
article: { type: Object as PropType<Article>, required: true },
},
setup (props) {
const router = useRouter()
const store = useStore<Store>()
const user = computed<Store['user']>(() => store.state.user)
const displayEditButton = computed(() => user.value.username === props.article.author?.username)
const onDelete = async () => {
await deleteArticle(props.article.slug)
return router.push({ name: 'global-feed' })
}
return { displayEditButton, onDelete }
},
})
</script>

View File

@ -35,7 +35,7 @@ export function useNavigationLinks ({ user }: UseLinksProps) {
display: 'anonym',
},
{
name: 'editor',
name: 'create-article',
title: 'New Post',
display: 'authorized',
icon: 'ion-compose',

109
src/pages/EditArticle.vue Normal file
View File

@ -0,0 +1,109 @@
<template>
<div class="editor-page">
<div class="container page">
<div class="row">
<div class="col-md-10 offset-md-1 col-xs-12">
<form @submit.prevent="onSubmit">
<fieldset class="form-group">
<input
v-model="form.title"
type="text"
class="form-control form-control-lg"
placeholder="Article Title"
>
</fieldset>
<fieldset class="form-group">
<input
v-model="form.description"
type="text"
class="form-control form-control-lg"
placeholder="What's this article about?"
>
</fieldset>
<fieldset class="form-group">
<textarea
v-model="form.body"
:rows="8"
class="form-control"
placeholder="Write your article (in markdown)"
/>
</fieldset>
<fieldset class="form-group">
<input
:value="form.tagList.join(' ')"
type="text"
class="form-control"
placeholder="Enter tags"
@input="value => (form.tagList = value.split(' '))"
>
<div class="tag-list" />
</fieldset>
<button
class="btn btn-lg pull-xs-right btn-primary"
type="submit"
:disabled="!(form.title && form.description && form.body)"
>
Publish Article
</button>
</form>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, onMounted, reactive } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { getArticle } from '../services/article/getArticle'
import { postArticle, putArticle } from '../services/article/postArticle'
interface FormState {
title: string;
description: string;
body: string;
tagList: string[];
}
export default defineComponent({
name: 'EditArticle',
setup () {
const route = useRoute()
const router = useRouter()
const slug = computed<string>(() => route.params.slug as string)
const form = reactive<FormState>({
title: '',
description: '',
body: '',
tagList: [],
})
async function fetchArticle (slug: string) {
const article = await getArticle(slug)
// FIXME: I always feel a little wordy here
form.title = article.title
form.description = article.description
form.body = article.body
form.tagList = article.tagList
}
onMounted(() => {
if (slug.value) fetchArticle(slug.value)
})
const onSubmit = async () => {
let article: Article
if (slug.value) {
article = await putArticle(slug.value, form)
} else {
article = await postArticle(form)
}
return router.push({ name: 'article', params: { slug: article.slug } })
}
return { form, onSubmit }
},
})
</script>

View File

@ -2,15 +2,16 @@ import { createRouter, createWebHashHistory } from 'vue-router'
import Home from './pages/Home.vue'
export type AppRouteNames = 'global-feed'
|'my-feed'
|'tag'
|'article'
|'login'
|'register'
|'profile'
|'profile-favorites'
|'editor'
|'settings'
| 'my-feed'
| 'tag'
| 'article'
| 'create-article'
| 'edit-article'
| 'login'
| 'register'
| 'profile'
| 'profile-favorites'
| 'settings'
const router = createRouter({
history: createWebHashHistory(),
@ -35,6 +36,16 @@ const router = createRouter({
path: '/article/:slug',
component: () => import('./pages/Article.vue'),
},
{
name: 'edit-article',
path: '/article/:slug/edit',
component: () => import('./pages/EditArticle.vue'),
},
{
name: 'create-article',
path: '/article/create',
component: () => import('./pages/EditArticle.vue'),
},
{
name: 'login',
path: '/login',
@ -55,11 +66,6 @@ const router = createRouter({
path: '/profile/:username/favorites',
component: () => import('./pages/Profile.vue'),
},
{
name: 'editor',
path: '/editor',
redirect: '/',
},
{
name: 'settings',
path: '/settings',

View File

@ -0,0 +1,5 @@
import { request } from '../index'
export async function deleteArticle (slug: string): Promise<void> {
return request.delete(`/articles/${slug}`)
}