mirror of
https://github.com/ajurna/cbwebreader.git
synced 2025-12-06 06:17:17 +00:00
Remove coreui (#76)
* adding typing and flake8 * removing coreui. ComicCard.vue finished * removing coreui. ConfirmButton.vue finished * removing coreui. more pages finished. * removing coreui. all pages finished * removing coreui. all pages finished * version bump and update python deps. * Update frontend/src/components/ComicPaginate.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/src/components/ComicPaginate.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/src/components/ComicPaginate.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/src/components/ComicPaginate.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/src/components/ComicPaginate.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/src/components/InitialSetup.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/src/components/TheAccountForm.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/src/components/TheAccountForm.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/src/components/ComicPaginate.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/src/components/ConfirmButton.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/vue.config.js Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/src/components/ComicPaginate.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/src/components/ComicPaginate.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update frontend/src/components/TheNavbar.vue Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com> * Update TheNavbar.vue Co-authored-by: Peter Dwyer <peter.dwyer@clanwilliamhealth.com> Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com>
This commit is contained in:
1924
frontend/package-lock.json
generated
1924
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,34 +4,26 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "webpack-dev-server --config webpack.dev.js",
|
||||
"build": "npx webpack --config webpack.prod.js",
|
||||
"build": "webpack --config webpack.prod.js",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coreui/coreui": "^4.2.0",
|
||||
"@coreui/vue": "^4.3.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.1.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.1.2",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.1",
|
||||
"axios": "^0.27.2",
|
||||
"axios-jwt": "^1.8.0",
|
||||
"bootstrap": "^4.6.2",
|
||||
"core-js": "^3.8.3",
|
||||
"bootstrap": "^5.2.0",
|
||||
"hammerjs": "^2.0.8",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"pdfvuer": "^2.0.1",
|
||||
"reveal.js": "^4.3.1",
|
||||
"reveal.js-menu": "^2.1.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"timeago.js": "^4.0.2",
|
||||
"vue": "^3.2.13",
|
||||
"vue-loader": "^17.0.0",
|
||||
"vue-router": "^4.0.3",
|
||||
"vue-toast-notification": "3.0",
|
||||
"vuejs-paginate-next": "^1.0.2",
|
||||
"vuex": "^4.0.0",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-bundle-tracker": "^1.6.0"
|
||||
"webpack": "^5.74.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.16",
|
||||
@@ -45,7 +37,12 @@
|
||||
"eslint-plugin-vue": "^8.0.3",
|
||||
"jshint": "^2.13.5",
|
||||
"mini-css-extract-plugin": "^2.6.1",
|
||||
"webpack-cli": "^4.10.0"
|
||||
"terser-webpack-plugin": "^5.3.6",
|
||||
"webpack-bundle-analyzer": "^4.6.1",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-bundle-tracker": "^1.6.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"vue-loader": "^17.0.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
@@ -62,9 +59,6 @@
|
||||
"rules": {}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead",
|
||||
"not ie 11"
|
||||
"defaults"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,41 +1,43 @@
|
||||
<template>
|
||||
<CButton color="secondary" @click="visible = true">Add User</CButton>
|
||||
<CModal :visible="visible" @close="visible = false">
|
||||
<CModalHeader>
|
||||
<CModalTitle>Add user</CModalTitle>
|
||||
</CModalHeader>
|
||||
<CForm @submit="addUser">
|
||||
<CModalBody>
|
||||
<CFormInput
|
||||
type="text"
|
||||
label="Username"
|
||||
v-model="username"
|
||||
/>
|
||||
<CFormInput
|
||||
type="email"
|
||||
label="Email address"
|
||||
text="Must be 8-20 characters long."
|
||||
v-model="email"
|
||||
feedback-invalid="Email address invalid."
|
||||
/>
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<CButton color="secondary" @click="visible = false">
|
||||
Close
|
||||
</CButton>
|
||||
<CButton color="primary" type="submit">Submit</CButton>
|
||||
</CModalFooter>
|
||||
</CForm>
|
||||
</CModal>
|
||||
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#addUserModal">Add User</button>
|
||||
|
||||
<div class="modal fade" id="addUserModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true" >
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Add user</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form @submit="addUser">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label for="usernameInput" class="form-label">Username</label>
|
||||
<input type="text" class="form-control" id="usernameInput" aria-describedby="usernameHelp" v-model="username">
|
||||
<div id="usernameHelp" class="form-text">Please enter a unique username</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="emailInput" class="form-label">Email address</label>
|
||||
<input type="email" class="form-control" id="emailInput" aria-describedby="emailHelp" v-model="email">
|
||||
<div id="emailHelp" class="form-text">Must be 8-20 characters long.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary" data-bs-dismiss="modal">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from "@/api";
|
||||
import 'bootstrap/js/dist/modal'
|
||||
export default {
|
||||
name: "AddUser",
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
username: '',
|
||||
email: ''
|
||||
}
|
||||
@@ -58,7 +60,6 @@ export default {
|
||||
color: 'success',
|
||||
text: 'New user "' + response.data.username + '" created with password "' + response2.data.password + '".'
|
||||
})
|
||||
this.visible=false
|
||||
this.$emit('user-added')
|
||||
})
|
||||
}).catch(err => {
|
||||
@@ -66,7 +67,6 @@ export default {
|
||||
color: 'danger',
|
||||
text: 'Cannot create user "' + this.username + '" with error "' + (err.response.data.username? err.response.data.username: err.response.data.email) + '".'
|
||||
})
|
||||
this.visible = false
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -76,4 +76,4 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<CAlert :color="message.color" dismissible v-for="message in messages" :key="message.text">
|
||||
<div class="alert alert-dismissible fade show" :class="'alert-'+message.color" role="alert" v-for="message in messages" :key="message.text">
|
||||
{{message.text}}
|
||||
</CAlert>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -20,4 +21,4 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,66 +1,77 @@
|
||||
<template>
|
||||
<CCol>
|
||||
<CCard class="">
|
||||
<CCardImage orientation="top" :src="thumbnail"/>
|
||||
<CCardBody class="pb-0 pt-0 pl-1 pr-1 card-img-overlay d-flex" @click="$router.push((data.type === 'Directory' ? {'name': 'browse', params: { selector: data.selector }} : {'name': 'read', params: { selector: data.selector }}))">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card card-body p-0" @click="$router.push((data.type === 'Directory' ? {'name': 'browse', params: { selector: data.selector }} : {'name': 'read', params: { selector: data.selector }}))">
|
||||
<img :src="thumbnail" class="card-img-top" :alt="data.title">
|
||||
<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 text-break" style="">
|
||||
<h5 class="card-title text-break mb-0">
|
||||
<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" />
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-footer px-0 pb-0">
|
||||
<div class="progress position-relative">
|
||||
<div class="progress-bar" role="progressbar" aria-label="Basic example" :style="'width: '+ progressPercentCalc +'%;'" :aria-valuenow="progressPercentCalc" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
<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>
|
||||
</CCol>
|
||||
</div>
|
||||
<div class="btn-group w-100 pt-1" role="group" aria-label="Basic example">
|
||||
<button type="button" class="btn btn-primary" @click="updateComic('mark_unread')"><font-awesome-icon icon='book' /></button>
|
||||
<button type="button" class="btn btn-primary" @click="updateComic('mark_read')" ><font-awesome-icon icon='book-open' /></button>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<font-awesome-icon icon='edit' />
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" @click="updateComic('mark_unread')"><font-awesome-icon icon='book' /> Mark Un-read</a></li>
|
||||
<li><a class="dropdown-item" @click="updateComic('mark_read')"><font-awesome-icon icon='book-open' /> Mark read</a></li>
|
||||
<li><a class="dropdown-item" 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</a></li>
|
||||
<li><a class="dropdown-item" v-if="data.type === 'Directory'" data-bs-toggle="modal" :data-bs-target="'#'+data.selector"><font-awesome-icon icon='edit' />Edit comic</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" :id="data.selector" tabindex="-1" :aria-labelledby="data.selector+'-label'" aria-hidden="true" >
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" :id="data.selector+'-label'">{{ data.title }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form @submit="updateDirectory">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-check-label mb-1" :for="data.selector+'-classification'" >
|
||||
Classification
|
||||
</label>
|
||||
<select class="form-select" :id="data.selector+'-classification'" v-model="new_classification">
|
||||
<option v-for="class_options in [...this.$store.state.classifications]" :key="class_options.value" :value="class_options.value">{{class_options.label}}</option>
|
||||
</select>
|
||||
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<input class="form-check-input" type="checkbox" value="" :id="data.selector+'-recursive'" v-model="recursive">
|
||||
<label class="form-check-label px-1" :for="data.selector+'-recursive'" >
|
||||
Recursive
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary" data-bs-dismiss="modal">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {useToast} from "vue-toast-notification";
|
||||
import api from "@/api";
|
||||
import 'bootstrap/js/dist/modal'
|
||||
|
||||
export default {
|
||||
name: "ComicCard",
|
||||
@@ -160,15 +171,12 @@ export default {
|
||||
.card-title a {
|
||||
color: white;
|
||||
text-shadow: .2rem .2rem .3rem black ;
|
||||
}
|
||||
|
||||
h5.card-title {
|
||||
margin-bottom: 75px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
text-decoration: none;
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.85), transparent);
|
||||
}
|
||||
|
||||
h5.card-title::before {
|
||||
filter: blur(12px);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card .unread-badge {
|
||||
@@ -188,4 +196,4 @@ h5.card-title::before {
|
||||
padding:5px;
|
||||
color:black;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
73
frontend/src/components/ComicPaginate.vue
Normal file
73
frontend/src/components/ComicPaginate.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<ul class="list-group list-group-horizontal">
|
||||
<li class="list-group-item" @click="this.$emit('prevComic')">Prev Comic</li>
|
||||
<li class="list-group-item" @click="prevPage">Prev</li>
|
||||
<template v-for="ind in visible_pages" :key="ind">
|
||||
<li class="list-group-item" :class="(ind===modelValue ? 'list-group-item-primary': '')" @click="setPage(ind)">{{ ind }}</li>
|
||||
</template>
|
||||
<li class="list-group-item" @click="nextPage">Next</li>
|
||||
<li class="list-group-item" @click="this.$emit('nextComic')">Next Comic</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ComicPaginate",
|
||||
props: {
|
||||
page_count: Number,
|
||||
modelValue: Number,
|
||||
},
|
||||
emits: ['update:modelValue', 'setPage', 'prevComic', 'nextComic'],
|
||||
methods: {
|
||||
setPage(evt) {
|
||||
if (evt !== '...'){
|
||||
this.$emit("setPage", evt)
|
||||
}
|
||||
},
|
||||
nextPage(){
|
||||
if (this.modelValue === this.page_count){
|
||||
this.$emit('nextComic')
|
||||
} else {
|
||||
this.setPage(this.modelValue + 1)
|
||||
}
|
||||
},
|
||||
prevPage(){
|
||||
if (this.modelValue === 1) {
|
||||
this.$emit('prevComic')
|
||||
} else {
|
||||
this.setPage(this.modelValue - 1)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visible_pages(){
|
||||
let out = []
|
||||
if (this.page_count <= 5) {
|
||||
for (let i = 1; i <= this.page_count; i++){
|
||||
out.push(i)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
let min = Math.max(1, this.modelValue - 2)
|
||||
let max = Math.min(this.page_count, this.modelValue + 2)
|
||||
|
||||
for (let i = min; i <= max; i++){
|
||||
out.push(i)
|
||||
}
|
||||
|
||||
if (out[0] !== 1) {
|
||||
out.splice(0, 1, ...[1, "..."])
|
||||
}
|
||||
if (out[out.length - 1] !==this.page_count){
|
||||
out.splice(out.length - 1, 1, ...["...", this.page_count])
|
||||
}
|
||||
return out
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,16 +1,13 @@
|
||||
<template>
|
||||
<CButtonGroup>
|
||||
<CButton :color="color" v-if="!confirm" @click="confirm = !confirm">{{ label }}</CButton>
|
||||
<CButton color="success" class="text-nowrap" v-if="confirm" variant="outline" @click="performAction">
|
||||
<font-awesome-icon icon='check' class=""/>
|
||||
Yes
|
||||
</CButton>
|
||||
<CButton color="danger" class="text-nowrap" v-if="confirm" variant="outline"
|
||||
@click="confirm = !confirm">
|
||||
<font-awesome-icon icon='times' class=""/>
|
||||
No
|
||||
</CButton>
|
||||
</CButtonGroup>
|
||||
<div class="btn-group" role="group" aria-label="Basic example">
|
||||
<button type="button" class="btn" :class="'btn-'+color" v-if="!confirm" @click="confirm = !confirm">{{ label }}</button>
|
||||
<button type="button" class="btn btn-outline-success text-nowrap" v-if="confirm" @click="performAction">
|
||||
<font-awesome-icon icon="check" class="" />Yes
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-danger text-nowrap" v-if="confirm" @click="confirm = !confirm">
|
||||
<font-awesome-icon icon='times' class=""/>No
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
<template>
|
||||
<div class="hello">
|
||||
<h1>{{ msg }}</h1>
|
||||
<p>
|
||||
For a guide and recipes on how to configure / customize this project,<br>
|
||||
check out the
|
||||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
|
||||
</p>
|
||||
<h3>Installed CLI Plugins</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
|
||||
</ul>
|
||||
<h3>Essential Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
|
||||
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
|
||||
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
|
||||
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
|
||||
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
|
||||
</ul>
|
||||
<h3>Ecosystem</h3>
|
||||
<ul>
|
||||
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
|
||||
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
|
||||
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
|
||||
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'HelloWorld',
|
||||
props: {
|
||||
msg: String
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
h3 {
|
||||
margin: 40px 0 0;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
li {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
a {
|
||||
color: #42b983;
|
||||
}
|
||||
</style>
|
||||
@@ -1,30 +1,20 @@
|
||||
<template>
|
||||
<h1>Create your admin account.</h1>
|
||||
<CForm @submit="saveForm">
|
||||
<CFormInput
|
||||
type="text"
|
||||
label="Username"
|
||||
v-model="username"
|
||||
/>
|
||||
<CFormInput
|
||||
type="email"
|
||||
label="Email address"
|
||||
text="Must be 8-20 characters long."
|
||||
v-model="email"
|
||||
feedback-invalid="Email address invalid."
|
||||
/>
|
||||
<CFormInput
|
||||
type="password"
|
||||
label="Password"
|
||||
v-model="password"
|
||||
/>
|
||||
<CFormInput
|
||||
type="password"
|
||||
label="Confirm Password"
|
||||
v-model="confirm_password"
|
||||
/>
|
||||
<CButton color="primary" type="submit" class="mr-5 mt-2">Save</CButton>
|
||||
</CForm>
|
||||
<form @submit="saveForm">
|
||||
<label class="form-label">Username</label>
|
||||
<input class="form-control" type="text" v-model="username" />
|
||||
|
||||
<label class="form-label">Email address</label>
|
||||
<input class="form-control" type="email" v-model="email">
|
||||
|
||||
<label class="form-label">Password</label>
|
||||
<input class="form-control" type="password" v-model="password">
|
||||
|
||||
<label class="form-label">Confirm Password</label>
|
||||
<input class="form-control" type="password" v-model="confirm_password">
|
||||
|
||||
<button class="btn btn-primary mr-5 mt-2" type="submit">Save</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -60,4 +50,4 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,66 +1,35 @@
|
||||
<template>
|
||||
<CContainer>
|
||||
<CForm @submit="updateAccount">
|
||||
<CFormInput
|
||||
type="text"
|
||||
label="Username"
|
||||
readonly
|
||||
v-model="username"
|
||||
/>
|
||||
<CFormInput
|
||||
type="email"
|
||||
label="Email address"
|
||||
:placeholder="email"
|
||||
text="Must be 8-20 characters long."
|
||||
v-model="email"
|
||||
feedback-invalid="Email address invalid."
|
||||
:valid="validateEmail(email)"
|
||||
/>
|
||||
<CFormInput
|
||||
type="password"
|
||||
label="Current Password"
|
||||
placeholder="Enter Current Password"
|
||||
text="Must enter current password to change settings."
|
||||
v-model="current_password"
|
||||
feedback-invalid="Wrong Password."
|
||||
:valid="current_password.length > 0"
|
||||
/>
|
||||
<CFormInput
|
||||
type="password"
|
||||
label="New Password"
|
||||
placeholder="Enter New Password"
|
||||
text="Must be at least 9 characters long."
|
||||
v-model="new_password"
|
||||
feedback-invalid="Password is not complex enough."
|
||||
:valid="checkNewPassword(new_password)"
|
||||
/>
|
||||
<CFormInput
|
||||
type="password"
|
||||
label="New Password Confirm"
|
||||
placeholder="Enter New Password"
|
||||
text="Must be at least 9 characters long."
|
||||
v-model="new_password_confirm"
|
||||
feedback-invalid="New passwords should match."
|
||||
:valid="new_password === new_password_confirm && new_password.length > 8"
|
||||
/>
|
||||
<CButton color="primary" type="submit">Save</CButton>
|
||||
</CForm>
|
||||
</CContainer>
|
||||
<div class="container">
|
||||
<form @submit="updateAccount">
|
||||
<label class="form-label">Username</label>
|
||||
<input class="form-control" readonly type="text" v-model="username" />
|
||||
|
||||
<label class="form-label">Email address</label>
|
||||
<input placeholder="" class="form-control" type="email" v-model="email" />
|
||||
|
||||
<label class="form-label">Current Password</label>
|
||||
<input placeholder="Enter Current Password" class="form-control" type="password" v-model="current_password"/>
|
||||
<div class="form-text">Must enter current password to change settings.</div>
|
||||
|
||||
<label class="form-label">New Password</label><input placeholder="Enter New Password" class="form-control" type="password" v-model="new_password"/>
|
||||
<div class="form-text">Must be at least 9 characters long.</div>
|
||||
|
||||
<label class="form-label">New Password Confirm</label><input placeholder="Enter New Password" class="form-control" type="password" v-model="new_password_confirm"/>
|
||||
<div class="form-text">Must be at least 9 characters long.</div>
|
||||
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {CForm, CFormInput, CContainer, CButton} from "@coreui/vue";
|
||||
import api from "@/api";
|
||||
import {useToast} from "vue-toast-notification";
|
||||
const toast = useToast();
|
||||
export default {
|
||||
name: "TheAccountForm",
|
||||
components: {
|
||||
CForm,
|
||||
CFormInput,
|
||||
CContainer,
|
||||
CButton
|
||||
},
|
||||
components: {},
|
||||
data () {
|
||||
return {
|
||||
username: '',
|
||||
@@ -87,7 +56,10 @@ export default {
|
||||
updateAccount () {
|
||||
if (!this.current_password) {
|
||||
toast.error('Please enter your current password.', {position:'top'});
|
||||
} else if (this.email === this.$store.state.user.email && this.new_password.length === 0){
|
||||
toast.error('No changes detected', {position:'top'});
|
||||
} else {
|
||||
console.log(this.email === this.$store.state.user.email)
|
||||
if (this.email !== this.$store.state.user.email) {
|
||||
let payload = {
|
||||
username: this.username,
|
||||
@@ -101,7 +73,7 @@ export default {
|
||||
toast.error(error.response.data.errors)
|
||||
})
|
||||
}
|
||||
if (this.new_password === this.new_password_confirm) {
|
||||
if (this.new_password === this.new_password_confirm && this.new_password.length > 0) {
|
||||
let payload = {
|
||||
username: this.username,
|
||||
old_password: this.current_password,
|
||||
@@ -119,16 +91,10 @@ export default {
|
||||
|
||||
}
|
||||
},
|
||||
validateEmail(mail){
|
||||
return (/\S+@\S+\.\S+/.test(mail))
|
||||
},
|
||||
checkNewPassword(pass){
|
||||
return (pass.length >= 9)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,32 +1,30 @@
|
||||
<template>
|
||||
<CBreadcrumb>
|
||||
<nav aria-label="breadcrumb" class="px-5">
|
||||
<ol class="breadcrumb " >
|
||||
<template v-for="(item, index) in crumbs" :key="item.id">
|
||||
<template v-if="index !== crumbs.length - 1">
|
||||
<CBreadcrumbItem v-if="item.selector">
|
||||
<li class="breadcrumb-item" v-if="item.selector">
|
||||
<router-link :to="{'name': 'browse', params: { selector: item.selector }}">{{ item.name }}</router-link>
|
||||
</CBreadcrumbItem>
|
||||
<CBreadcrumbItem v-else-if="item.route">
|
||||
</li>
|
||||
<li class="breadcrumb-item" v-else-if="item.route">
|
||||
<router-link :to="item.route">{{ item.name }}</router-link>
|
||||
</CBreadcrumbItem>
|
||||
<CBreadcrumbItem v-else>
|
||||
</li>
|
||||
<li class="breadcrumb-item" v-else>
|
||||
<router-link :to="{'name': 'browse'}">{{ item.name }}</router-link>
|
||||
</CBreadcrumbItem>
|
||||
</li>
|
||||
</template>
|
||||
<CBreadcrumbItem v-else active>{{ item.name }}</CBreadcrumbItem>
|
||||
<li class="breadcrumb-item active" aria-current="page" v-else>{{ item.name }}</li>
|
||||
</template>
|
||||
</CBreadcrumb>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { CBreadcrumbItem, CBreadcrumb } from '@coreui/vue'
|
||||
import api from "@/api";
|
||||
export default {
|
||||
name: "TheBreadcrumbs",
|
||||
components: {
|
||||
CBreadcrumb,
|
||||
CBreadcrumbItem,
|
||||
},
|
||||
components: { },
|
||||
data () {
|
||||
return {
|
||||
crumbs: []
|
||||
@@ -68,5 +66,10 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
.breadcrumb-item a {
|
||||
text-decoration: none;
|
||||
}
|
||||
nav {
|
||||
background: lightgrey;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
<template>
|
||||
<CContainer fluid>
|
||||
<CRow>
|
||||
<CInputGroup>
|
||||
<CFormInput placeholder="Search" aria-label="Filter comics by name" v-model="this.filters.search_string"/>
|
||||
<CButton type="button" :color="(!filters.filter_read && !filters.filter_unread? 'primary' : 'secondary')" variant="outline" @click="filters.filter_read=false; filters.filter_unread=false">All</CButton>
|
||||
<CButton type="button" :color="(filters.filter_read && !filters.filter_unread? 'primary' : 'secondary')" variant="outline" @click="filters.filter_read=true; filters.filter_unread=false">Read</CButton>
|
||||
<CButton type="button" :color="(!filters.filter_read && filters.filter_unread? 'primary' : 'secondary')" variant="outline" @click="filters.filter_read=false; filters.filter_unread=true">Un-read</CButton>
|
||||
<CDropdown variant="input-group">
|
||||
<CDropdownToggle color="secondary" variant="outline">Action</CDropdownToggle>
|
||||
<CDropdownMenu>
|
||||
<CDropdownItem @click="markAll('mark_unread')"><font-awesome-icon icon='book' />Mark Un-read</CDropdownItem>
|
||||
<CDropdownItem @click="markAll('mark_read')"><font-awesome-icon icon='book-open' />Mark read</CDropdownItem>
|
||||
</CDropdownMenu>
|
||||
</CDropdown>
|
||||
</CInputGroup>
|
||||
</CRow>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="input-group">
|
||||
<input class="form-control" aria-label="Filter comics by name" placeholder="Search" v-model="this.filters.search_string">
|
||||
<button type="button" class="btn" :class="(!filters.filter_read && !filters.filter_unread? 'btn-outline-primary' : 'btn-outline-secondary')" @click="filters.filter_read=false; filters.filter_unread=false">All</button>
|
||||
<button type="button" class="btn" :class="(filters.filter_read && !filters.filter_unread? 'btn-outline-primary' : 'btn-outline-secondary')" @click="filters.filter_read=true; filters.filter_unread=false">Read</button>
|
||||
<button type="button" class="btn" :class="(!filters.filter_read && filters.filter_unread? 'btn-outline-primary' : 'btn-outline-secondary')" @click="filters.filter_read=false; filters.filter_unread=true">Un-read</button>
|
||||
<button type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Action</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" @click="markAll('mark_unread')"><font-awesome-icon icon='book' />Mark Un-read</a></li>
|
||||
<li><a class="dropdown-item" @click="markAll('mark_read')"><font-awesome-icon icon='book-open' />Mark read</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row row-cols-2 row-cols-sm-3 row-cols-md-4 row-cols-lg-6 row-cols-xl-auto mt-1" >
|
||||
<template v-if="loading">
|
||||
<div class="col-12 col-xl-12 col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<CProgress class="mt-3" >
|
||||
<CProgressBar color="success" variant="striped" animated :value="100"/>
|
||||
</CProgress>
|
||||
<div class="progress mt-3">
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated bg-success" role="progressbar" aria-label="Loading data" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
@@ -29,7 +27,7 @@
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</CContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -145,4 +143,4 @@ export default {
|
||||
.dropdown-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -6,34 +6,27 @@
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<CRow class="navButtons pb-2">
|
||||
<CListGroup :layout="'horizontal'">
|
||||
<CListGroupItem class="p-1 pt-2 page-link pl-2 pr-2" @click="prevComic">Prev Comic</CListGroupItem>
|
||||
<paginate
|
||||
v-model="paginate_page"
|
||||
:page-count="pages.length"
|
||||
:click-handler="this.setPage"
|
||||
:prev-text="'Prev'"
|
||||
:next-text="'Next'"
|
||||
:container-class="'pagination'"
|
||||
>
|
||||
</paginate>
|
||||
<CListGroupItem class="p-1 pt-2 page-link pl-2 pr-2" @click="nextComic">Next Comic</CListGroupItem>
|
||||
</CListGroup>
|
||||
</CRow>
|
||||
<div class="row navButtons pb-2">
|
||||
<comic-paginate
|
||||
v-model="paginate_page"
|
||||
:page_count="pages.length"
|
||||
@setPage="this.setPage"
|
||||
@prevComic="prevComic"
|
||||
@nextComic="nextComic"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Reveal from "reveal.js";
|
||||
import api from "@/api";
|
||||
import 'reveal.js-menu/menu.css'
|
||||
import Paginate from "vuejs-paginate-next";
|
||||
import * as Hammer from 'hammerjs'
|
||||
import ComicPaginate from "@/components/ComicPaginate";
|
||||
|
||||
export default {
|
||||
name: "TheComicReader",
|
||||
components: {Paginate},
|
||||
components: {ComicPaginate},
|
||||
data () {
|
||||
return {
|
||||
current_page: 0,
|
||||
@@ -185,7 +178,4 @@ export default {
|
||||
section {
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
.list-group-item {
|
||||
/*padding: 0;*/
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,46 +1,39 @@
|
||||
<template>
|
||||
<CNavbar expand="lg" color-scheme="light" class="bg-light">
|
||||
<CContainer fluid>
|
||||
<CNavbarBrand href="#"><img src="/static/img/logo.svg" width="35" class="d-inline-block align-top" alt="CB"> Web Reader</CNavbarBrand>
|
||||
<CNavbarToggler @click="visible = !visible"/>
|
||||
<CCollapse class="navbar-collapse" :visible="visible">
|
||||
<CNavbarNav>
|
||||
<CNavItem>
|
||||
<nav class="navbar navbar-expand-lg bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#"><img src="/static/img/logo.svg" width="35" class="d-inline-block align-top" alt="CB"> Web Reader</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<router-link :to="{name: 'browse'}" class="nav-link" >Browse</router-link>
|
||||
</CNavItem>
|
||||
<CNavItem>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<router-link :to="{name: 'recent'}" class="nav-link" >Recent</router-link>
|
||||
</CNavItem>
|
||||
<CNavItem>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<router-link :to="{name: 'account'}" class="nav-link" >Account</router-link>
|
||||
</CNavItem>
|
||||
<CNavItem>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<router-link :to="{name: 'user'}" class="nav-link" v-if="this.$store.getters.is_superuser">Users</router-link>
|
||||
</CNavItem>
|
||||
<CNavItem>
|
||||
<CNavLink @click="logout">Log Out</CNavLink>
|
||||
</CNavItem>
|
||||
</CNavbarNav>
|
||||
</CCollapse>
|
||||
</CContainer>
|
||||
</CNavbar>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" @click="logout">Log Out</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
<script>
|
||||
import { CNavbar, CNavbarNav, CContainer, CNavbarBrand, CNavbarToggler, CCollapse, CNavItem, CNavLink } from '@coreui/vue'
|
||||
import store from "@/store";
|
||||
import router from "@/router";
|
||||
import 'bootstrap/js/dist/collapse'
|
||||
export default {
|
||||
name: "TheNavbar",
|
||||
components: {
|
||||
CNavbar,
|
||||
CNavbarNav,
|
||||
CContainer,
|
||||
CNavbarBrand,
|
||||
CNavbarToggler,
|
||||
CCollapse,
|
||||
CNavItem,
|
||||
CNavLink
|
||||
},
|
||||
components: { },
|
||||
data() {
|
||||
return {
|
||||
visible: false
|
||||
@@ -59,4 +52,4 @@ export default {
|
||||
.nav-link {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,41 +1,35 @@
|
||||
<template>
|
||||
<CContainer ref="pdfContainer">
|
||||
<CRow class="w-100 pb-5 mb-5" v-if="loaded" >
|
||||
<pdf :src="pdfdata" :page="page" ref="pdfWindow" :resize="true">
|
||||
<template v-slot:loading>
|
||||
loading content here...
|
||||
</template>
|
||||
</pdf>
|
||||
</CRow>
|
||||
</CContainer>
|
||||
<CRow class="navButtons pb-2">
|
||||
<CListGroup :layout="'horizontal'">
|
||||
<CListGroupItem class="p-1 pt-2 page-link pl-2 pr-2" @click="prevComic">Prev Comic</CListGroupItem>
|
||||
<paginate
|
||||
v-model="page"
|
||||
:page-count="numPages"
|
||||
:click-handler="this.setPage"
|
||||
:prev-text="'Prev'"
|
||||
:next-text="'Next'"
|
||||
:container-class="'pagination'"
|
||||
>
|
||||
</paginate>
|
||||
<CListGroupItem class="p-1 pt-2 page-link pl-2 pr-2" @click="nextComic">Next Comic</CListGroupItem>
|
||||
</CListGroup>
|
||||
</CRow>
|
||||
<div class="container" ref="pdfContainer">
|
||||
<div class="row w-100 pb-5 mb-5" v-if="loaded">
|
||||
<pdf :src="pdfdata" :page="page" ref="pdfWindow" :resize="true">
|
||||
<template v-slot:loading>
|
||||
loading content here...
|
||||
</template>
|
||||
</pdf>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row navButtons pb-2">
|
||||
<comic-paginate
|
||||
v-model="page"
|
||||
:page_count="numPages"
|
||||
@setPage="setPage"
|
||||
@prevComic="prevComic"
|
||||
@nextComic="nextComic"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pdfvuer from 'pdfvuer'
|
||||
import api from "@/api";
|
||||
import Paginate from "vuejs-paginate-next";
|
||||
import * as Hammer from 'hammerjs'
|
||||
|
||||
import ComicPaginate from "@/components/ComicPaginate";
|
||||
|
||||
export default {
|
||||
name: "ThePdfReader",
|
||||
components: {
|
||||
pdf: pdfvuer, Paginate
|
||||
ComicPaginate,
|
||||
pdf: pdfvuer
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -83,7 +77,7 @@ export default {
|
||||
this.setReadPage(this.page)
|
||||
this.next_comic = response.data.next_comic
|
||||
this.prev_comic = response.data.prev_comic
|
||||
this.hammertime = new Hammer(this.$refs.pdfContainer.$el, {})
|
||||
this.hammertime = new Hammer(this.$refs.pdfContainer, {})
|
||||
this.hammertime.on('swipeleft', (_e, self=this) => {
|
||||
self.nextPage()
|
||||
})
|
||||
@@ -130,7 +124,7 @@ export default {
|
||||
this.setReadPage(this.page)
|
||||
},
|
||||
setReadPage(num){
|
||||
this.$refs.pdfContainer.$el.scrollIntoView()
|
||||
this.$refs.pdfContainer.scrollIntoView()
|
||||
let payload = {
|
||||
page: num-1
|
||||
}
|
||||
@@ -173,4 +167,4 @@ export default {
|
||||
width: auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,65 +1,68 @@
|
||||
<template>
|
||||
<CContainer>
|
||||
<CRow>
|
||||
<CCol>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col d-flex align-items-center">
|
||||
<form class="form-inline ">
|
||||
<label class="my-1 mr-2" for="selectChoices">Show</label>
|
||||
<label class="my-1 px-1" for="selectChoices">Show</label>
|
||||
<select class="custom-select my-1 mr-sm-2 " id="selectChoices" v-model="this.page_size" @change="this.setPage(this.page)">
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
<label class="my-1 mr-2" for="selectChoices">entries</label>
|
||||
<label class="my-1 px-1" for="selectChoices">entries</label>
|
||||
</form>
|
||||
</CCol>
|
||||
<CCol class="d-flex justify-content-end">
|
||||
</div>
|
||||
<div class="col d-flex justify-content-end">
|
||||
<form class="form-inline">
|
||||
<label for="searchText" class="my-1 mr-2">Search</label>
|
||||
<input type="text" id="searchText" class="form-control my-1 mr-sm-2" v-model="search_text" @keyup="this.debounceInput()">
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control" id="floatingInput" placeholder="name@example.com" v-model="search_text" @keyup="this.debounceInput()">
|
||||
<label for="floatingInput">Search</label>
|
||||
</div>
|
||||
</form>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<caption>
|
||||
<h2>Recent Comics - <a :href="'/feed/' + this.feed_id + '/'">Feed</a></h2>
|
||||
Mark selected issues as:
|
||||
<select name="func" id="func_selector" @change="this.performFunction()" v-model="func_selected">
|
||||
<select class="form-select-sm" name="func" id="func_selector" @change="this.performFunction()" v-model="func_selected">
|
||||
<option value="choose">Choose...</option>
|
||||
<option value="mark_read">Read</option>
|
||||
<option value="mark_unread">Un-Read</option>
|
||||
</select>
|
||||
</caption>
|
||||
</CRow>
|
||||
<CRow>
|
||||
<CTable striped bordered>
|
||||
<CTableHead>
|
||||
<CTableRow>
|
||||
<CTableHeaderCell scope="col"><input class="form-check-input m-0 position-relative mt-1" type="checkbox" value="" ref="select-all"></CTableHeaderCell>
|
||||
<CTableHeaderCell scope="col"></CTableHeaderCell>
|
||||
<CTableHeaderCell scope="col">Comic</CTableHeaderCell>
|
||||
<CTableHeaderCell scope="col">Date Added</CTableHeaderCell>
|
||||
<CTableHeaderCell scope="col">status</CTableHeaderCell>
|
||||
</CTableRow>
|
||||
</CTableHead>
|
||||
<CTableBody>
|
||||
</div>
|
||||
<div class="row">
|
||||
<table class="table table-striped table-bordered">
|
||||
<caption>Recent Comics</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"><input class="form-check-input m-0 position-relative mt-1" type="checkbox" value="" ref="select-all"></th>
|
||||
<th scope="col"></th>
|
||||
<th scope="col">Comic</th>
|
||||
<th scope="col">Date Added</th>
|
||||
<th scope="col">status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="item in comics" :key="item.id">
|
||||
<CTableRow>
|
||||
<CTableHeaderCell scope="row"><input ref="comic_selector" class="form-check-input m-0 position-relative mt-1" type="checkbox" :value="item.selector"></CTableHeaderCell>
|
||||
<CTableDataCell class=""><font-awesome-icon icon='book' class="" /></CTableDataCell>
|
||||
<CTableDataCell><router-link :to="{name: 'read', params: { selector: item.selector }}" class="" >{{ item.file_name }}</router-link></CTableDataCell>
|
||||
<CTableDataCell>{{ timeago(item.date_added) }}</CTableDataCell>
|
||||
<CTableDataCell>{{ get_status(item) }}</CTableDataCell>
|
||||
</CTableRow>
|
||||
<tr>
|
||||
<th scope="row"><input ref="comic_selector" class="form-check-input m-0 position-relative mt-1" type="checkbox" :value="item.selector"></th>
|
||||
<td class=""><font-awesome-icon icon='book' class="" /></td>
|
||||
<td><router-link :to="{name: 'read', params: { selector: item.selector }}" class="" >{{ item.file_name }}</router-link></td>
|
||||
<td>{{ timeago(item.date_added) }}</td>
|
||||
<td>{{ get_status(item) }}</td>
|
||||
</tr>
|
||||
</template>
|
||||
</CTableBody>
|
||||
</CTable>
|
||||
</CRow>
|
||||
<CRow>
|
||||
<CCol>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
Showing page {{ this.page }} of {{ this.page_count }} pages.
|
||||
</CCol>
|
||||
<CCol class="d-flex justify-content-end">
|
||||
</div>
|
||||
<div class="col d-flex justify-content-end">
|
||||
<paginate
|
||||
v-model="this.page"
|
||||
:page-count="this.page_count"
|
||||
@@ -69,9 +72,9 @@
|
||||
:container-class="'pagination '"
|
||||
>
|
||||
</paginate>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</CContainer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -181,4 +184,4 @@ export default {
|
||||
.pagination {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,35 +1,26 @@
|
||||
<template>
|
||||
<CContainer>
|
||||
<CForm @submit="saveForm">
|
||||
<CFormInput
|
||||
type="text"
|
||||
label="Username"
|
||||
readonly
|
||||
v-model="username"
|
||||
/>
|
||||
<CFormInput
|
||||
type="email"
|
||||
label="Email address"
|
||||
:placeholder="user.email"
|
||||
text="Must be 8-20 characters long."
|
||||
v-model="email"
|
||||
feedback-invalid="Email address invalid."
|
||||
/>
|
||||
<CFormSelect
|
||||
aria-label="Default select example"
|
||||
v-model="classification"
|
||||
:options="[...this.$store.state.classifications]">
|
||||
</CFormSelect>
|
||||
<CRow class="mt-2">
|
||||
<CCol>
|
||||
<CButton color="primary" type="submit" class="mr-5">Save</CButton>
|
||||
<confirm-button class="mr-5" label="Reset Password" :action="resetPassword" />
|
||||
<confirm-button label="Delete User" :action="deleteUser" />
|
||||
</CCol>
|
||||
</CRow>
|
||||
<div class="container">
|
||||
<form @submit="saveForm">
|
||||
<label class="form-label">Username</label>
|
||||
<input class="form-control" readonly="" type="text" v-model="username" />
|
||||
|
||||
</CForm>
|
||||
</CContainer>
|
||||
<label class="form-label">Email address</label>
|
||||
<input placeholder="" class="form-control" type="email" v-model="email"/>
|
||||
|
||||
<label class="form-label">Classification</label>
|
||||
<select aria-label="Default select example" class="form-select" v-model="classification">
|
||||
<option v-for="class_opt in [...this.$store.state.classifications]" :key="class_opt.value" :value="class_opt.value">{{class_opt.label}}</option>
|
||||
</select>
|
||||
|
||||
<div class="row mt-2">
|
||||
<div class="col">
|
||||
<button type="submit" class="btn btn-primary me-5">Save</button>
|
||||
<confirm-button class="me-5" label="Reset Password" :action="resetPassword" />
|
||||
<confirm-button label="Delete User" :action="deleteUser" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -111,4 +102,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
<template>
|
||||
<CTable striped bordered>
|
||||
<CTableHead>
|
||||
<CTableRow>
|
||||
<CTableHeaderCell scope="col">#</CTableHeaderCell>
|
||||
<CTableHeaderCell scope="col">Username</CTableHeaderCell>
|
||||
<CTableHeaderCell scope="col">Email</CTableHeaderCell>
|
||||
<CTableHeaderCell scope="col">Superuser</CTableHeaderCell>
|
||||
<CTableHeaderCell scope="col">Classification</CTableHeaderCell>
|
||||
</CTableRow>
|
||||
</CTableHead>
|
||||
<CTableBody>
|
||||
<table class="table table-striped table-bordered">
|
||||
<caption>User list</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Username</th>
|
||||
<th scope="col">Email</th>
|
||||
<th scope="col">Superuser</th>
|
||||
<th scope="col">Classification</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="item in users" :key="item.id">
|
||||
<CTableRow>
|
||||
<CTableHeaderCell scope="row">{{ item.id }}</CTableHeaderCell>
|
||||
<CTableDataCell class="">
|
||||
<tr>
|
||||
<th scope="row">{{ item.id }}</th>
|
||||
<td class="">
|
||||
<router-link :to="{'name': 'user', params: { userid: item.id }}">{{ item.username }}</router-link>
|
||||
</CTableDataCell>
|
||||
<CTableDataCell>{{ item.email }}</CTableDataCell>
|
||||
<CTableDataCell>{{ item.is_superuser }}</CTableDataCell>
|
||||
<CTableDataCell>{{ this.$store.state.classifications.find(i => i.value === item.classification.toString()).label }}</CTableDataCell>
|
||||
</CTableRow>
|
||||
</td>
|
||||
<td>{{ item.email }}</td>
|
||||
<td>{{ item.is_superuser }}</td>
|
||||
<td>{{ this.$store.state.classifications.find(i => i.value === item.classification.toString()).label }}</td>
|
||||
</tr>
|
||||
</template>
|
||||
</CTableBody>
|
||||
</CTable>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -36,4 +37,4 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import * as Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import ToastPlugin from 'vue-toast-notification';
|
||||
|
||||
import CoreuiVue from '@coreui/vue';
|
||||
import '@coreui/coreui/dist/css/coreui.min.css'
|
||||
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||
import 'vue-toast-notification/dist/theme-default.css';
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||
import 'bootstrap/js/dist/dropdown'
|
||||
|
||||
|
||||
|
||||
/* import the fontawesome core */
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
|
||||
@@ -14,14 +15,13 @@ import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||
|
||||
/* import specific icons */
|
||||
import {faBook, faBookOpen, faEdit, faTurnUp} from '@fortawesome/free-solid-svg-icons'
|
||||
library.add(faBook, faBookOpen, faEdit, faTurnUp)
|
||||
import {faBook, faBookOpen, faEdit, faTurnUp, faTimes, faCheck} from '@fortawesome/free-solid-svg-icons'
|
||||
library.add(faBook, faBookOpen, faEdit, faTurnUp, faTimes, faCheck)
|
||||
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
|
||||
Vue.createApp(App)
|
||||
.use(CoreuiVue)
|
||||
.use(ToastPlugin)
|
||||
.use(store)
|
||||
.use(router)
|
||||
|
||||
@@ -1,36 +1,25 @@
|
||||
<template>
|
||||
<CContainer>
|
||||
<CRow v-if="!initialSetupRequired">
|
||||
<CCol lg="4"/>
|
||||
<CCol lg="4" id="login-col">
|
||||
<CForm @submit="login">
|
||||
<CFormInput
|
||||
type="username"
|
||||
id="username"
|
||||
label="Username"
|
||||
placeholder="username"
|
||||
text="Please enter your username"
|
||||
aria-describedby="loginFormControlInputHelpInline"
|
||||
v-model="username"
|
||||
/>
|
||||
<CFormInput
|
||||
type="password"
|
||||
id="password"
|
||||
label="password"
|
||||
placeholder="password"
|
||||
text="Please enter your password"
|
||||
aria-describedby="loginFormControlInputHelpInline"
|
||||
v-model="password"
|
||||
@keyup.enter="login"
|
||||
/>
|
||||
<CButton color="primary" class="mb-3">Login</CButton>
|
||||
</CForm>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow>
|
||||
<div class="container">
|
||||
<div class="row" v-if="!initialSetupRequired">
|
||||
<div class="col col-lg-4" />
|
||||
<div class="col col-lg-4" id="login-col">
|
||||
<form @submit="login">
|
||||
<label class="form-label" for="username">Username</label>
|
||||
<input id="username" placeholder="username" aria-describedby="loginFormControlInputHelpInline" class="form-control" type="text" v-model="username" />
|
||||
<div class="form-text" id="loginFormControlInputHelpInline">Please enter your username</div>
|
||||
|
||||
<label class="form-label" for="password">password</label>
|
||||
<input id="password" placeholder="password" aria-describedby="loginFormControlInputHelpInline" class="form-control" type="password" v-model="password"/>
|
||||
<div class="form-text" id="loginFormControlInputHelpInline">Please enter your password</div>
|
||||
|
||||
<button class="btn btn-primary mb-3" type="submit">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<initial-setup v-if="initialSetupRequired" />
|
||||
</CRow>
|
||||
</CContainer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -65,4 +54,4 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<the-breadcrumbs :manual_crumbs="this.crumbs" />
|
||||
<CContainer>
|
||||
<div class="container">
|
||||
<alert-messages :messages="messages" />
|
||||
<user-list :users="users" v-if="!userid"/>
|
||||
<user-edit v-if="user_data" :user="user_data" @add-message="addMessage"/>
|
||||
<add-user v-if="!userid" @user-added="updateUsers" @add-message="addMessage"/>
|
||||
</CContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -78,4 +78,4 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
const { defineConfig } = require('@vue/cli-service')
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
|
||||
.BundleAnalyzerPlugin;
|
||||
|
||||
module.exports = defineConfig({
|
||||
transpileDependencies: true
|
||||
transpileDependencies: true,
|
||||
configureWebpack: {
|
||||
plugins: [new BundleAnalyzerPlugin()]
|
||||
},
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ const path = require('path')
|
||||
const { VueLoaderPlugin } = require('vue-loader')
|
||||
const BundleTracker = require('webpack-bundle-tracker');
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
|
||||
const webpack = require('webpack')
|
||||
|
||||
@@ -12,7 +12,7 @@ module.exports = (env = {}) => {
|
||||
return {
|
||||
|
||||
mode: 'production',
|
||||
devtool: false,
|
||||
devtool: 'hidden-source-map',
|
||||
entry: path.resolve(__dirname, './src/main.js'),
|
||||
output: {
|
||||
path: path.resolve(__dirname, './dist/bundles/'),
|
||||
@@ -56,6 +56,8 @@ module.exports = (env = {}) => {
|
||||
}),
|
||||
new webpack.DefinePlugin({ __VUE_OPTIONS_API__: true, __VUE_PROD_DEVTOOLS__: false }),
|
||||
new MiniCssExtractPlugin(),
|
||||
|
||||
// new BundleAnalyzerPlugin(),
|
||||
],
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
@@ -63,4 +65,4 @@ module.exports = (env = {}) => {
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user