mirror of
https://github.com/ajurna/cbwebreader.git
synced 2025-12-06 06:17:17 +00:00
New Frontend in Vue with drf interface (#72)
* frontend rewrite with vie initial commit * got ComicCard.vue working nice. * got TheComicList.vue working. * added router and basic config * getting jwt stuff working. * login with jwt now working. * implemented browse api call * implemented browse api recievers * jwt token is now updating automatically. * removed code for jwt testing. * enabled browsing * breadcrumbs working * adding django webpack loader * linking up navigation * fixes for ComicCard.vue stying * added thumbnail view * added thumbnail generation and handling. * detached breadcrumbs * fix breadcrumbs * added first stages of reader * reader view is working. * reader is now working with keyboard shortcuts * implemented setting read page. * implemented pagination on comic reader. * hide elements that shouldn't be shown. * fixed the ComicCard.vue to use as little space as possible. * fix navbar browse link * added RecentView.vue and added manual option for breadcrumbs * updated rest api to handle recent comics. * most functionality of recent comics done * modified comicstatus relation to use uuid relation and implemented mark read and unread for batches. * added functions to TheRecentTable.vue * added feed link to TheRecentTable.vue * fixes for comicstatus updates. * added constraints to comicstatus * update to python packages. * some changes for django 4, also removed django-recaptcha2 as it doesnt support django 4. * some fixes and updates to ComicCard.vue * cleaned up generate_directory. fixed bug where pages not visible on first call. * cleaned up generate_directory. fixed bug where pages not visible on first call. * cleaned up generate_directory. fixed bug where pages not visible on first call. * cleaned up generate_directory. * added silk stubs * fix for re-requesting thumbnail after getting it already. * fix for removing stale comics. adding leeway to access token. * mark read and unread * added filtering to comic list. * stored filtering state. * stored filtering state. * added next functionality to login. * cleanup LoginView.vue * bump font-awesome. * working on AccountView.vue * fixed form submission on LoginView.vue * account page should now be working. * hide users option if not superuser. * added pdf support * make pdf resize. * added touch controls to pdf reader * added touch controls to comic reader * beginnings of routing between issues. * fixes for navigating pages. * fixes for navigating pages. * fixes for navigating pages. * renamed HomeView.vue to BrowseView.vue * stubs for users page added. api ready * users page further functinality * fix for notification * fix for notification * moved messages to parent. * form to add users * added error handling * removed console logging * classification in base directory should be lowest * renamed usermisc to classification to be more consistent with what it does. * renamed usermisc to classification to be more consistent with what it does. * added functionality to change classification of directories. * merged rss_id api into account api. * merged breadcrumbs api into browse api. * clears some warnings from console. * fixed read/unread rendering. * added build script and starting lint * fixing lint errors * fixing lint errors * fixing lint errors * fixing lint errors * fixing lint errors * fixing lint errors * fixing lint errors * fixing lint errors * fixing navigation bugs * cleanup and fixes * fixed generated tooltips over calling. * fixed classifications. * initial setup now working * fix navbar branding * fix favicon * added beta build script. * fixes to get ready for production * optimisations for loading new comics. * added loading indicators to TheComicList.vue * lint fixes * made two methods static. may use them elsewhere. * fix for scanning files. * version updates. * fixes for production * fixes for production Co-authored-by: Peter Dwyer <peter.dwyer@clanwilliamhealth.com>
This commit is contained in:
178
frontend/src/components/ComicCard.vue
Normal file
178
frontend/src/components/ComicCard.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<CCard class="col-xl-2 col-lg-2 col-md-3 col-sm-4 p-0 m-1 ">
|
||||
<CCardImage orientation="top" :src="thumbnail"/>
|
||||
<CCardBody class="pb-0 pt-0 pl-1 pr-1 card-img-overlay d-flex">
|
||||
<span class="badge rounded-pill bg-primary unread-badge" v-if="this.unread > 0 && data.type === 'Directory'">{{ this.unread }}</span>
|
||||
<span class="badge rounded-pill bg-warning classification-badge" v-if="card_type === 'Directory'" >{{ this.$store.state.classifications.find(i => i.value === classification).label }}</span>
|
||||
<CCardTitle class="align-self-end pb-5 mb-4 text-break" style="">
|
||||
<router-link :to="(data.type === 'Directory' ? {'name': 'browse', params: { selector: data.selector }} : {'name': 'read', params: { selector: data.selector }})">{{ data.title }}</router-link>
|
||||
</CCardTitle>
|
||||
</CCardBody>
|
||||
<CCardFooter class="pl-0 pr-0 pt-0">
|
||||
<CProgress class="mb-1 position-relative" >
|
||||
<CProgressBar :value="progressPercentCalc" />
|
||||
<small class="justify-content-center d-flex position-absolute w-100 h-100" style="line-height: normal">{{ progressCalc }} / {{data.total}}</small>
|
||||
</CProgress>
|
||||
<CButtonGroup class="w-100">
|
||||
<CButton color="primary" @click="updateComic('mark_unread')" ><font-awesome-icon icon='book' /></CButton>
|
||||
<CButton color="primary" @click="updateComic('mark_read')" ><font-awesome-icon icon='book-open' /></CButton>
|
||||
<CDropdown variant="btn-group">
|
||||
<CDropdownToggle color="primary"><font-awesome-icon icon='edit' /></CDropdownToggle>
|
||||
<CDropdownMenu>
|
||||
<CDropdownItem @click="updateComic('mark_unread')"><font-awesome-icon icon='book' />Mark Un-read</CDropdownItem>
|
||||
<CDropdownItem @click="updateComic('mark_read')"><font-awesome-icon icon='book-open' />Mark read</CDropdownItem>
|
||||
<CDropdownItem v-if="data.type === 'ComicBook'" @click="$emit('markPreviousRead', data.selector)"><font-awesome-icon icon='book' /><font-awesome-icon icon='turn-up' />Mark previous comics read</CDropdownItem>
|
||||
<CDropdownItem v-if="data.type === 'Directory'" @click="editDirectoryVisible = true"><font-awesome-icon icon='edit' />Edit comic</CDropdownItem>
|
||||
</CDropdownMenu>
|
||||
</CDropdown>
|
||||
</CButtonGroup>
|
||||
</CCardFooter>
|
||||
</CCard>
|
||||
<CModal :visible="editDirectoryVisible" @close="editDirectoryVisible = false">
|
||||
<CModalHeader>
|
||||
<CModalTitle>{{ data.title }}</CModalTitle>
|
||||
</CModalHeader>
|
||||
<CForm @submit="updateDirectory">
|
||||
<CModalBody>
|
||||
<CFormSelect
|
||||
label="Classification"
|
||||
aria-label="Set Classification"
|
||||
v-model="new_classification"
|
||||
:options="[...this.$store.state.classifications]">
|
||||
</CFormSelect>
|
||||
<CFormCheck
|
||||
label="Recursive"
|
||||
class="mt-2"
|
||||
v-model="recursive"
|
||||
/>
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<CButton color="secondary" @click="editDirectoryVisible = false ">
|
||||
Close
|
||||
</CButton>
|
||||
<CButton color="primary" type="submit">Save changes</CButton>
|
||||
</CModalFooter>
|
||||
</CForm>
|
||||
</CModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {useToast} from "vue-toast-notification";
|
||||
import api from "@/api";
|
||||
|
||||
export default {
|
||||
name: "ComicCard",
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
data: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
thumbnail: '/static/img/placeholder.png',
|
||||
unread: 0,
|
||||
progress: 0,
|
||||
classification: '0',
|
||||
new_classification: '0',
|
||||
card_type: '',
|
||||
editDirectoryVisible: false,
|
||||
recursive: true
|
||||
}},
|
||||
methods: {
|
||||
updateThumbnail () {
|
||||
api.get('/api/generate_thumbnail/' + this.data.selector + '/')
|
||||
.then((response) => {
|
||||
if (response.data.thumbnail) {
|
||||
this.$emit('updateThumbnail', response.data)
|
||||
this.thumbnail = response.data.thumbnail
|
||||
}
|
||||
}).catch(() => {
|
||||
useToast().error('Error Generating Thumbnail: ' + this.data.title, {position:'top'});
|
||||
})
|
||||
},
|
||||
updateComic(action){
|
||||
let payload = { selectors: [this.data.selector] }
|
||||
api.put('/api/action/' + action +'/', payload).then(() => {
|
||||
this.$emit('updateComicList')
|
||||
}).catch(() => {
|
||||
useToast().error('action: ' + action + ' Failed', {position:'top'});
|
||||
})
|
||||
},
|
||||
updateDirectory() {
|
||||
let payload = {
|
||||
selector: this.data.selector,
|
||||
classification: ~~this.new_classification
|
||||
}
|
||||
if (this.recursive){
|
||||
api.put('/api/directory/' + this.data.selector + '/', payload).then(response => {
|
||||
this.classification = response.data[0].classification.toString()
|
||||
useToast().success('Change classification of ' + this.data.title + ' to "' + this.$store.state.classifications.find(i => i.value === this.classification).label + '"', {position:'top'});
|
||||
this.editDirectoryVisible = false
|
||||
})
|
||||
} else {
|
||||
api.patch('/api/directory/' + this.data.selector + '/', payload).then(response => {
|
||||
this.classification = response.data.classification.toString()
|
||||
useToast().success('Change classification of ' + this.data.title + ' to "' + this.$store.state.classifications.find(i => i.value === this.classification).label + '"', {position:'top'});
|
||||
this.editDirectoryVisible = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (this.data.thumbnail) {
|
||||
this.thumbnail = this.data.thumbnail
|
||||
} else {
|
||||
this.updateThumbnail()
|
||||
}
|
||||
this.unread = this.data.total - this.data.progress
|
||||
this.classification = this.data.classification.toString()
|
||||
this.new_classification = this.classification
|
||||
this.card_type = this.data.type
|
||||
},
|
||||
beforeUpdate() {
|
||||
this.unread = this.data.total - this.data.progress
|
||||
},
|
||||
emits: ['updateComicList', 'markPreviousRead', 'updateThumbnail'],
|
||||
computed: {
|
||||
progressCalc () {
|
||||
if (this.data.type === 'ComicBook'){
|
||||
return (this.data.unread ? 0 : this.data.progress)
|
||||
} else {
|
||||
return this.data.progress
|
||||
}
|
||||
},
|
||||
progressPercentCalc () {
|
||||
if (this.data.type === 'ComicBook') {
|
||||
return (this.data.unread ? 0 : this.data.progress / this.data.total * 100)
|
||||
} else {
|
||||
return this.data.progress / this.data.total * 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.card-title a {
|
||||
color: white;
|
||||
text-shadow: .2rem .2rem .3rem black ;
|
||||
}
|
||||
.card .unread-badge {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
}
|
||||
.dropdown-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
.card .classification-badge {
|
||||
position:absolute;
|
||||
top:10px;
|
||||
right: 10px;
|
||||
padding:5px;
|
||||
color:black;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user