Files
www/components/tabs/LibraryTab.vue
T
2021-10-25 05:19:13 +07:00

286 lines
6.6 KiB
Vue

<template>
<section>
<div class="LibraryPage">
<form @submit.prevent="q = q0">
<label for="q" class="label">
Search
<b-tooltip label="How to?" position="is-right">
<a
href="https://github.com/zhquiz/zhquiz/wiki/How-to-search-or-filter"
target="_blank"
rel="noopener noreferrer"
>
<b-icon icon="info-circle"></b-icon>
</a>
</b-tooltip>
</label>
<div class="field has-addons">
<p class="control is-expanded">
<input
v-model="q0"
class="input"
type="search"
name="q"
placeholder="Type here to search"
aria-label="search"
/>
</p>
<p class="control">
<button
class="button is-success"
type="button"
@click="openEditModal()"
>
Add new item
</button>
</p>
</div>
</form>
<div class="columns mt-4">
<div class="column">
<section class="card">
<div class="card-content">
<LibraryCard
v-for="(it, i) in local.result"
:id="it.id"
:key="i"
:title="it.title"
:entries="it.entries"
:type="it.type"
:description="it.description"
:additional="additionalContext(it)"
/>
<b-pagination
v-if="local.count > local.perPage"
v-model="local.page"
:total="local.count"
:per-page="local.perPage"
icon-prev="angle-left"
icon-next="angle-right"
@change="(p) => (local.page = p)"
/>
</div>
</section>
</div>
</div>
</div>
<b-modal v-model="isEditModal">
<div class="card">
<header class="card-header">
<div v-if="!edited.id" class="card-header-title">New list</div>
<div v-else class="card-header-title">Edit list</div>
</header>
<div class="card-content">
<b-field label="Title">
<b-input
v-model="edited.title"
placeholder="Must not be empty"
></b-input>
</b-field>
<b-field label="Entries">
<template slot="label">
Entries
<b-tooltip type="is-dark" label="Space or new-line separated">
<b-icon size="is-small" icon="info-circle"></b-icon>
</b-tooltip>
</template>
<b-input
v-model="entryString"
type="textarea"
placeholder="Space or new-line separated, must not be empty"
></b-input>
</b-field>
<b-field label="Description">
<b-input v-model="edited.description" type="textarea"></b-input>
</b-field>
<b-field label="Tag">
<b-taginput v-model="edited.tag"></b-taginput>
</b-field>
<b-field label="Additional options">
<b-checkbox
:value="edited.isShared"
@input="(ev) => $set(edited, 'isShared', ev)"
>
Make it availble for others (shared library)
</b-checkbox>
</b-field>
</div>
<footer class="card-footer">
<div class="card-footer-item">
<button
class="button is-success"
type="button"
@click="edited.id ? doUpdate() : doCreate()"
>
Save
</button>
<button
class="button is-cancel"
type="button"
@click="isEditModal = false"
>
Cancel
</button>
</div>
</footer>
</div>
</b-modal>
</section>
</template>
<script lang="ts">
import { Component, Vue, Watch } from 'nuxt-property-decorator'
import { api, ILibrary } from '~/assets/api'
import LibraryCard from '../cards/LibraryCard.vue'
@Component<LibraryTab>({
components: {
LibraryCard,
},
created() {
this.$emit('title', 'Library')
this.updateLocal()
},
})
export default class LibraryTab extends Vue {
q = ''
q0 = ''
isEditModal = false
local: {
result: ILibrary[]
count: number
page: number
perPage: number
} = {
result: [],
count: 0,
page: 1,
perPage: 10,
}
edited: ILibrary = {
id: '',
title: '',
list: [],
type: 'vocabulary',
description: '',
tag: [],
}
get entryString() {
return this.edited.list.join('\n')
}
set entryString(s) {
this.edited.list = s
.split('\n')
.filter((s) => s.trim())
.filter((a, i, r) => r.indexOf(a) === i)
}
additionalContext(it: ILibrary) {
if (!it.id) {
return []
}
return [
{
name: 'Edit list',
handler: () => {
this.openEditModal()
},
},
{
name: 'Delete list',
handler: () => {
if (it.id) {
this.doDelete(it.id)
}
},
},
]
}
openEditModal(it?: ILibrary) {
this.edited = it || {
id: '',
title: '',
list: [],
type: 'vocabulary',
description: '',
tag: [],
}
this.isEditModal = true
}
@Watch('q')
@Watch('local.page')
async updateLocal() {
const r = await api.library_getQuery({
q: this.q,
offset: this.local.page * this.local.perPage,
limit: this.local.perPage,
})
this.local = {
...this.local,
...r,
result: r.result,
}
}
async doCreate() {
await api.library_create(this.edited)
this.$buefy.snackbar.open(`Created list: ${this.edited.title}`)
this.isEditModal = false
this.local.page = 1
await this.updateLocal()
}
async doUpdate() {
const { id } = this.edited
if (id) {
await api.library_update(this.edited)
this.$buefy.snackbar.open(`Updated list: ${this.edited.title}`)
}
this.isEditModal = false
this.local.page = 1
await this.updateLocal()
}
async doDelete(id: string) {
await api.library_delete({ id })
this.$buefy.snackbar.open(`Deleted list: ${this.edited.title}`)
this.local.page = 1
await this.updateLocal()
}
}
</script>
<style scoped>
nav.pagination {
margin-top: 1rem;
}
.button + .button {
margin-left: 1rem;
}
.button.is-cancel {
background-color: rgb(215, 217, 219);
}
</style>