albums sidebar in dashboard is now collapsible

they'll also be collapsed on initial page load

this uses a new client-side dependency, bulma-collapsible
https://github.com/creativebulma/bulma-collapsible

/api/albums to fetch albums list now support simple reply, where only
their ids and names will be returned.
this simple reply will also return all of the user's albums, instead of
being limited to only 9 or 25 entires like before.

fixed add to album in dashboard, and album selector in homepage uploader
being limited to only 25 albums.
This commit is contained in:
Bobby Wibowo 2020-12-26 18:49:51 +07:00
parent 98080204da
commit c5647cb8bf
No known key found for this signature in database
GPG Key ID: 51C3A1E1E22D26CF
9 changed files with 83 additions and 30 deletions

View File

@ -73,7 +73,7 @@ self.list = async (req, res, next) => {
if (!user) return if (!user) return
const all = req.headers.all === '1' const all = req.headers.all === '1'
const sidebar = req.headers.sidebar const simple = req.headers.simple
const ismoderator = perms.is(user, 'moderator') const ismoderator = perms.is(user, 'moderator')
if (all && !ismoderator) return res.status(403).end() if (all && !ismoderator) return res.status(403).end()
@ -97,10 +97,9 @@ self.list = async (req, res, next) => {
const fields = ['id', 'name'] const fields = ['id', 'name']
let albums let albums
if (sidebar) { if (simple) {
albums = await db.table('albums') albums = await db.table('albums')
.where(filter) .where(filter)
.limit(9)
.select(fields) .select(fields)
return res.json({ success: true, albums, count }) return res.json({ success: true, albums, count })

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Wikiki
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1 @@
@-webkit-keyframes spinAround{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes spinAround{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.is-collapsible{height:0;overflow-y:hidden;transition:height .2s ease}.is-collapsible.is-active{transition:height .2s ease}.is-collapsible.message-body{padding:0!important}.is-collapsible.message-body .message-body-content{padding:1.25em 1.5em}

File diff suppressed because one or more lines are too long

View File

@ -20,7 +20,6 @@ body {
a { a {
color: $link; color: $link;
border: 1px solid transparent; border: 1px solid transparent;
margin-top: -1px;
&.is-active { &.is-active {
color: $white; color: $white;
@ -53,6 +52,16 @@ body {
top: calc(50% - (1em / 2)); top: calc(50% - (1em / 2));
position: absolute !important position: absolute !important
} }
&.is-active[data-action="collapse"] {
color: $link !important;
background: none !important;
border-color: transparent !important;
&:hover {
border-color: $link !important
}
}
} }
li ul { li ul {

View File

@ -1,4 +1,4 @@
/* global swal, axios, ClipboardJS, LazyLoad */ /* global swal, axios, ClipboardJS, LazyLoad, bulmaCollapsible */
const lsKeys = { const lsKeys = {
token: 'token', token: 'token',
@ -90,6 +90,8 @@ const page = {
clipboardJS: null, clipboardJS: null,
lazyLoad: null, lazyLoad: null,
albumsSidebarCollapse: null,
albumsSidebarCollapsible: null,
imageExts: ['.gif', '.jpeg', '.jpg', '.png', '.svg', '.tif', '.tiff', '.webp'], imageExts: ['.gif', '.jpeg', '.jpg', '.png', '.svg', '.tif', '.tiff', '.webp'],
videoExts: ['.3g2', '.3gp', '.asf', '.avchd', '.avi', '.divx', '.evo', '.flv', '.h264', '.h265', '.hevc', '.m2p', '.m2ts', '.m4v', '.mk3d', '.mkv', '.mov', '.mp4', '.mpeg', '.mpg', '.mxf', '.ogg', '.ogv', '.ps', '.qt', '.rmvb', '.ts', '.vob', '.webm', '.wmv'], videoExts: ['.3g2', '.3gp', '.asf', '.avchd', '.avi', '.divx', '.evo', '.flv', '.h264', '.h265', '.hevc', '.m2p', '.m2ts', '.m4v', '.mk3d', '.mkv', '.mov', '.mp4', '.mpeg', '.mpg', '.mxf', '.ogg', '.ogv', '.ps', '.qt', '.rmvb', '.ts', '.vob', '.webm', '.wmv'],
@ -1540,7 +1542,7 @@ page.addUploadsToAlbum = (ids, callback) => {
}) })
// Get albums list then update content of swal // Get albums list then update content of swal
axios.get('api/albums').then(list => { axios.get('api/albums', { headers: { simple: '1' } }).then(list => {
if (list.data.success === false) { if (list.data.success === false) {
if (list.data.description === 'No token provided') { if (list.data.description === 'No token provided') {
page.verifyToken(page.token) page.verifyToken(page.token)
@ -2040,7 +2042,7 @@ page.submitAlbum = element => {
} }
page.getAlbumsSidebar = () => { page.getAlbumsSidebar = () => {
axios.get('api/albums', { headers: { sidebar: '1' } }).then(response => { axios.get('api/albums', { headers: { simple: '1' } }).then(response => {
if (!response) return if (!response) return
if (response.data.success === false) { if (response.data.success === false) {
@ -2053,18 +2055,27 @@ page.getAlbumsSidebar = () => {
const albums = response.data.albums const albums = response.data.albums
const count = response.data.count const count = response.data.count
const albumsContainer = document.querySelector('#albumsContainer') const albumsSidebar = document.querySelector('#albumsSidebar')
// Clear albums sidebar if necessary // Clear albums sidebar if necessary
const oldAlbums = albumsContainer.querySelectorAll('li > a') const oldAlbums = albumsSidebar.querySelectorAll('li > a')
const diffCount = oldAlbums.length !== count
if (oldAlbums.length) { if (oldAlbums.length) {
for (let i = 0; i < oldAlbums.length; i++) { for (let i = 0; i < oldAlbums.length; i++) {
page.menus.splice(page.menus.indexOf(oldAlbums[i]), 1) page.menus.splice(page.menus.indexOf(oldAlbums[i]), 1)
} }
albumsContainer.innerHTML = '' albumsSidebar.innerHTML = ''
} }
if (albums === undefined) return page.albumsSidebarCollapse.innerText = page.albumsSidebarCollapsible.collapsed()
? page.albumsSidebarCollapse.dataset.textExpand
: page.albumsSidebarCollapse.dataset.textCollapse
if (!albums || !albums.length) {
page.albumsSidebarCollapsible.collapse()
page.albumsSidebarCollapse.setAttribute('disabled', 'disabled')
return
}
for (let i = 0; i < albums.length; i++) { for (let i = 0; i < albums.length; i++) {
const album = albums[i] const album = albums[i]
@ -2083,24 +2094,14 @@ page.getAlbumsSidebar = () => {
page.menus.push(a) page.menus.push(a)
li.appendChild(a) li.appendChild(a)
albumsContainer.appendChild(li) albumsSidebar.appendChild(li)
} }
if (count > albums.length) { page.albumsSidebarCollapse.removeAttribute('disabled')
const li = document.createElement('li') if (!page.albumsSidebarCollapsible.collapsed() && diffCount) {
const a = document.createElement('a') // Since it's not possible to refresh collapsible's height with bulmaCollapsible APIs,
a.className = 'is-relative' // forcefully collapse albums sidebar if albums count is different with the previous iteration.
a.innerHTML = '...' page.albumsSidebarCollapsible.collapse()
a.title = `You have ${count} albums, but the sidebar can only list your first ${albums.length} albums.`
a.addEventListener('click', event => {
page.getAlbums({
trigger: document.querySelector('#itemManageYourAlbums')
})
})
li.appendChild(a)
albumsContainer.appendChild(li)
} }
}).catch(page.onAxiosError) }).catch(page.onAxiosError)
} }
@ -3010,4 +3011,15 @@ window.addEventListener('DOMContentLoaded', () => {
page.clipboardJS.on('error', page.onError) page.clipboardJS.on('error', page.onError)
page.lazyLoad = new LazyLoad() page.lazyLoad = new LazyLoad()
page.albumsSidebarCollapse = document.querySelector('#albumsSidebarCollapse')
/* eslint-disable-next-line new-cap */
page.albumsSidebarCollapsible = new bulmaCollapsible(document.querySelector('#albumsSidebar'))
page.albumsSidebarCollapsible.on('before:expand', event => {
page.albumsSidebarCollapse.innerText = page.albumsSidebarCollapse.dataset.textCollapse
})
page.albumsSidebarCollapsible.on('before:collapse', event => {
page.albumsSidebarCollapse.innerText = page.albumsSidebarCollapse.dataset.textExpand
})
}) })

View File

@ -314,7 +314,12 @@ page.setActiveTab = index => {
} }
page.fetchAlbums = () => { page.fetchAlbums = () => {
return axios.get('api/albums', { headers: { token: page.token } }).then(response => { return axios.get('api/albums', {
headers: {
simple: '1',
token: page.token
}
}).then(response => {
if (response.data.success === false) { if (response.data.success === false) {
return swal('An error occurred!', response.data.description, 'error') return swal('An error occurred!', response.data.description, 'error')
} }

View File

@ -66,7 +66,7 @@ page.toggleReloadBtn = enabled => {
page.reloadBtn.removeAttribute('disabled') page.reloadBtn.removeAttribute('disabled')
} else { } else {
page.reloadBtn.classList.add('is-loading') page.reloadBtn.classList.add('is-loading')
page.reloadBtn.setAttribute('disabled', true) page.reloadBtn.setAttribute('disabled', 'disabled')
} }
} }

View File

@ -6,6 +6,7 @@
{% block stylesheets %} {% block stylesheets %}
<!-- Libs stylesheets --> <!-- Libs stylesheets -->
<link rel="stylesheet" href="libs/fontello/fontello.css{{ versions[1] }}"> <link rel="stylesheet" href="libs/fontello/fontello.css{{ versions[1] }}">
<link rel="stylesheet" href="libs/bulma-collapsible/bulma-collapsible.min.css{{ versions[3] }}">
{{ super() }} {{ super() }}
<link rel="stylesheet" href="css/sweetalert.css{{ versions[1] }}"> <link rel="stylesheet" href="css/sweetalert.css{{ versions[1] }}">
<link rel="stylesheet" href="css/thumbs.css{{ versions[1] }}"> <link rel="stylesheet" href="css/thumbs.css{{ versions[1] }}">
@ -21,6 +22,7 @@
<script src="libs/lazyload/lazyload.min.js{{ versions[3] }}"></script> <script src="libs/lazyload/lazyload.min.js{{ versions[3] }}"></script>
{# Polyfill smooth scroll for older browsers #} {# Polyfill smooth scroll for older browsers #}
<script src="libs/smoothscroll/smoothscroll.min.js{{ versions[3] }}"></script> <script src="libs/smoothscroll/smoothscroll.min.js{{ versions[3] }}"></script>
<script src="libs/bulma-collapsible/bulma-collapsible.min.js{{ versions[3] }}"></script>
<!-- Scripts --> <!-- Scripts -->
{# We assign an ID for this so that the script can find out its own version #} {# We assign an ID for this so that the script can find out its own version #}
<script id="mainScript" src="js/dashboard.js{{ versions[1] }}"></script> <script id="mainScript" src="js/dashboard.js{{ versions[1] }}"></script>
@ -64,7 +66,10 @@
<a id="itemManageYourAlbums" class="is-relative">Manage your albums</a> <a id="itemManageYourAlbums" class="is-relative">Manage your albums</a>
</li> </li>
<li> <li>
<ul id="albumsContainer"></ul> <a id="albumsSidebarCollapse" href="#albumsSidebar" data-action="collapse" data-text-collapse="Collapse albums sidebar" data-text-expand="Expand albums sidebar" disabled>Fetching albums sidebar…</a>
</li>
<li>
<ul id="albumsSidebar" class="is-collapsible"></ul>
</li> </li>
</ul> </ul>
<p id="itemLabelAdmin" class="menu-label is-hidden">Administration</p> <p id="itemLabelAdmin" class="menu-label is-hidden">Administration</p>