diff options
author | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2019-11-07 21:45:14 +0300 |
---|---|---|
committer | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2019-11-07 21:45:14 +0300 |
commit | ae28cc9b2d79568ae069e3f25ed29791986791d0 (patch) | |
tree | 64142d5c99b2b0c392bc8e22a4ea536fd5c9f816 /src | |
parent | 9c94a3e10fb3345ed57df27f44d51dde2f7ff733 (diff) |
Added navigation, albums, init tags
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/Photos.vue (renamed from src/Gallery.vue) | 20 | ||||
-rw-r--r-- | src/components/Folder.vue | 27 | ||||
-rw-r--r-- | src/components/Grid.vue | 87 | ||||
-rw-r--r-- | src/components/Navigation.vue | 16 | ||||
-rw-r--r-- | src/main.js | 6 | ||||
-rw-r--r-- | src/router/index.js | 68 | ||||
-rw-r--r-- | src/services/DavClient.js | 3 | ||||
-rw-r--r-- | src/services/FileList.js | 24 | ||||
-rw-r--r-- | src/services/FolderInfo.js | 14 | ||||
-rw-r--r-- | src/services/PhotoSearch.js | 6 | ||||
-rw-r--r-- | src/services/SystemTags.js | 56 | ||||
-rw-r--r-- | src/store/index.js | 2 | ||||
-rw-r--r-- | src/store/systemtags.js | 99 | ||||
-rw-r--r-- | src/utils/ParseFile.js | 37 | ||||
-rw-r--r-- | src/views/Albums.vue (renamed from src/views/Grid.vue) | 60 | ||||
-rw-r--r-- | src/views/Tags.vue | 111 |
16 files changed, 545 insertions, 91 deletions
diff --git a/src/Gallery.vue b/src/Photos.vue index cb9a8882..ec26f323 100644 --- a/src/Gallery.vue +++ b/src/Photos.vue @@ -22,6 +22,17 @@ <template> <Content app-name="photos"> + <AppNavigation> + <AppNavigationItem :to="{name: 'root'}" + class="app-navigation__photos" + :title="t('photos', 'Your photos')" + icon="icon-photos" /> + <AppNavigationItem to="/favorites" :title="t('photos', 'Favorites')" icon="icon-favorite" /> + <AppNavigationItem :to="{name: 'albums'}" :title="t('photos', 'Your albums')" icon="icon-files-dark" /> + <AppNavigationItem :to="{name: 'shared'}" :title="t('photos', 'Shared albums')" icon="icon-share" /> + <AppNavigationItem :to="{name: 'tags'}" :title="t('photos', 'Tags')" icon="icon-tag" /> + <AppNavigationItem :to="{name: 'maps'}" :title="t('photos', 'Locations')" icon="icon-address" /> + </AppNavigation> <AppContent :class="{ 'icon-loading': loading }"> <router-view v-show="!loading" :loading.sync="loading" /> @@ -34,6 +45,8 @@ <script> import Content from '@nextcloud/vue/dist/Components/Content' import AppContent from '@nextcloud/vue/dist/Components/AppContent' +import AppNavigation from '@nextcloud/vue/dist/Components/AppNavigation' +import AppNavigationItem from '@nextcloud/vue/dist/Components/AppNavigationItem' import svgplaceholder from './assets/img-placeholder.svg' export default { @@ -41,6 +54,8 @@ export default { components: { Content, AppContent, + AppNavigation, + AppNavigationItem, }, data: function() { return { @@ -50,3 +65,8 @@ export default { }, } </script> +<style lang="scss" scoped> +.app-navigation__photos::v-deep .app-navigation-entry-icon.icon-photos { + background-size: 20px; +} +</style> diff --git a/src/components/Folder.vue b/src/components/Folder.vue index 5dec6b5a..de2db5a6 100644 --- a/src/components/Folder.vue +++ b/src/components/Folder.vue @@ -23,7 +23,7 @@ <template> <router-link :class="{'folder--clear': isEmpty}" class="folder" - :to="folder.filename" + :to="to" :aria-label="ariaLabel"> <transition name="fade"> <div v-show="loaded" @@ -39,8 +39,8 @@ </transition> <div class="folder-name"> - <span :class="{'icon-white': !isEmpty}" - class="folder-name__icon icon-folder" + <span :class="[!isEmpty ? 'icon-white' : 'icon-dark', icon]" + class="folder-name__icon" role="img" /> <p :id="ariaUuid" class="folder-name__name"> {{ folder.basename }} @@ -66,6 +66,10 @@ export default { type: Object, required: true, }, + icon: { + type: String, + default: 'icon-folder', + }, }, data() { @@ -106,6 +110,20 @@ export default { ariaLabel() { return t('photos', 'Open the "{name}" sub-directory', { name: this.folder.basename }) }, + + /** + * We do not want encoded slashes when browsing by folder + * so we generate a new valid route object, get the final url back + * decode it and use it as a direct string, which vue-router + * does not encode afterwards + */ + to() { + const route = Object.assign({}, this.$route, { + // always remove first slash + params: { path: this.folder.filename.substr(1) } + }); + return decodeURIComponent(this.$router.resolve(route).resolved.path) + }, }, async created() { @@ -215,6 +233,9 @@ $name-height: 1.2rem; .folder { // if no img, let's display the folder icon as default black &--clear { + .folder-name__icon { + opacity: .3; + } .folder-name__name { color: var(--color-main-text); text-shadow: 0 0 8px var(--color-main-background); diff --git a/src/components/Grid.vue b/src/components/Grid.vue new file mode 100644 index 00000000..85023f5a --- /dev/null +++ b/src/components/Grid.vue @@ -0,0 +1,87 @@ +<!-- + - @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com> + - + - @author John Molakvoæ <skjnldsv@protonmail.com> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <!-- Folder content --> + <transition-group + class="photos-grid" + role="grid" + name="list" + tag="div"> + <slot /> + <div key="footer" role="none" class="photos-grid__footer-spacer" /> + </transition-group> +</template> + +<script> +export default { + name: 'Grid', +} +</script> + +<style scoped lang="scss"> +.photos-grid { + display: grid; + align-items: center; + justify-content: center; + gap: 8px; + grid-template-columns: repeat(10, 1fr); + position: relative; + + // always put one more row of grid for the spacer + &__footer-spacer { + // always add one row, so placing it on the first + // column will always add one more + grid-column: 1; + // same height as the width + padding-bottom: 100%; + } +} + +.list-move { + transition: transform var(--animation-quick); +} + +// TODO: use mixins/GridSizes as soon as node-sass supports it +// needs node-sass 5.0 (with libsass 3.6) +// https://github.com/sass/node-sass/pull/2312 +$previous: 0; +@each $size, $config in get('sizes') { + $count: map-get($config, 'count'); + $marginTop: map-get($config, 'marginTop'); + $marginW: map-get($config, 'marginW'); + + // if this is the last entry, only use min-width + $rule: '(min-width: #{$previous}px) and (max-width: #{$size}px)'; + @if $size == 'max' { + $rule: '(min-width: #{$previous}px)'; + } + + @media #{$rule} { + .photos-grid { + padding: #{$marginTop}px #{$marginW}px #{$marginW}px #{$marginW}px; + grid-template-columns: repeat($count, 1fr); + } + } + $previous: $size; +} +</style> diff --git a/src/components/Navigation.vue b/src/components/Navigation.vue index facbdf10..df1c3f0f 100644 --- a/src/components/Navigation.vue +++ b/src/components/Navigation.vue @@ -89,11 +89,25 @@ export default { } return t('photos', 'Back to {folder}', { folder: this.parentName }) }, + + /** + * We do not want encoded slashes when browsing by folder + * so we generate a new valid route object, get the final url back + * decode it and use it as a direct string, which vue-router + * does not encode afterwards + */ + to() { + const route = Object.assign({}, this.$route, { + // always remove first slash + params: { path: this.parentPath.substr(1) } + }); + return decodeURIComponent(this.$router.resolve(route).resolved.path) + }, }, methods: { folderUp() { - this.$router.push(this.parentPath) + this.$router.push(this.to) }, }, } diff --git a/src/main.js b/src/main.js index 595ecb95..5e4a96d3 100644 --- a/src/main.js +++ b/src/main.js @@ -26,7 +26,7 @@ import { sync } from 'vuex-router-sync' import { translate, translatePlural } from '@nextcloud/l10n' import Vue from 'vue' -import Gallery from './Gallery' +import Photos from './Photos' import router from './router' import store from './store' @@ -49,8 +49,8 @@ Vue.prototype.n = translatePlural export default new Vue({ el: '#content', // eslint-disable-next-line vue/match-component-file-name - name: 'GalleryRoot', + name: 'PhotosRoot', router, store, - render: h => h(Gallery), + render: h => h(Photos), }) diff --git a/src/router/index.js b/src/router/index.js index 80dcdd5e..df464138 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -24,10 +24,17 @@ import { generateUrl } from '@nextcloud/router' import Router from 'vue-router' import Vue from 'vue' -import Grid from '../views/Grid' +import Albums from '../views/Albums' +import Tags from '../views/Tags' Vue.use(Router) +// shortcut to properly format the path prop +const props = route => ({ + // always lead current path with a slash + path: `/${route.params.path ? route.params.path : ''}`, +}) + export default new Router({ mode: 'history', // if index.php is in the url AND we got this far, then it's working: @@ -37,20 +44,65 @@ export default new Router({ routes: [ { path: '/', - component: Grid, - props: route => ({ - // always lead current path with a slash - path: `/${route.params.path ? route.params.path : ''}`, - }), + component: Albums, name: 'root', + }, + { + path: '/albums', + component: Albums, + name: 'albums', + props, + children: [ + { + path: ':path*', + name: 'path', + component: Albums, + }, + ], + }, + { + path: '/shared', + component: Albums, + name: 'shared', + props, + children: [ + { + path: ':path*', + name: 'path', + component: Albums, + }, + ], + }, + { + path: '/favorites', + component: Tags, + name: 'favorites', + props, children: [ { path: ':path*', name: 'path', - component: Grid, + component: Tags, }, ], }, - { path: '*', redirect: { name: 'root' } }, + { + path: '/tags', + component: Tags, + name: 'tags', + props, + children: [ + { + path: ':path*', + name: 'path', + component: Tags, + }, + ], + }, + { + path: '/maps', + name: 'maps', + redirect: '', + }, ], }) diff --git a/src/services/DavClient.js b/src/services/DavClient.js index acdfdf1b..c91b57e8 100644 --- a/src/services/DavClient.js +++ b/src/services/DavClient.js @@ -24,14 +24,13 @@ import webdav from 'webdav' import axios from '@nextcloud/axios' import parseUrl from 'url-parse' import { generateRemoteUrl } from '@nextcloud/router' -import { getCurrentUser } from '@nextcloud/auth' // force our axios const patcher = webdav.getPatcher() patcher.patch('request', axios) // init webdav client -const remote = generateRemoteUrl(`dav/files/${getCurrentUser().uid}`) +const remote = generateRemoteUrl(`dav`) const client = webdav.createClient(remote) export const remotePath = parseUrl(remote).pathname diff --git a/src/services/FileList.js b/src/services/FileList.js index 2ee84328..80e9df6d 100644 --- a/src/services/FileList.js +++ b/src/services/FileList.js @@ -20,12 +20,14 @@ * */ +import { getCurrentUser } from '@nextcloud/auth' import { getSingleValue, getValueForKey, parseXML, propsToStat } from 'webdav/dist/interface/dav' import { handleResponseCode, processResponsePayload } from 'webdav/dist/response' import { normaliseHREF, normalisePath } from 'webdav/dist/url' import client, { remotePath } from './DavClient' import pathPosix from 'path-posix' import request from './DavRequest' +import parseFile from '../utils/ParseFile' /** * List files from a folder and filter out unwanted mimes @@ -46,6 +48,8 @@ export default async function(path, options) { details: true, }, options) + const prefixPath = `/files/${getCurrentUser().uid}` + /** * Fetch listing * @@ -54,7 +58,7 @@ export default async function(path, options) { * see https://github.com/perry-mitchell/webdav-client/blob/baf858a4856d44ae19ac12cb10c469b3e6c41ae4/source/interface/directoryContents.js#L11 */ let response = null - const { data } = await client.customRequest(path, options) + const { data } = await client.customRequest(prefixPath + path, options) .then(handleResponseCode) .then(res => { response = res @@ -64,14 +68,7 @@ export default async function(path, options) { .then(result => getDirectoryFiles(result, remotePath, options.details)) .then(files => processResponsePayload(response, files, options.details)) - const list = data - .map(entry => { - return Object.assign({ - id: parseInt(entry.props.fileid), - isFavorite: entry.props.favorite !== '0', - hasPreview: entry.props['has-preview'] !== 'false', - }, entry) - }) + const list = data.map(data => parseFile(data, prefixPath)) // filter all the files and folders let folder = {} @@ -91,6 +88,15 @@ export default async function(path, options) { return { folder, folders, files } } +/** + * Modified function to include the root requested folder + * Into the returned data + * + * @param {Object} result the request result + * @param {string} serverBasePath server base path + * @param {boolean} isDetailed detailed request + * @returns {Array} + */ function getDirectoryFiles(result, serverBasePath, isDetailed = false) { const serverBase = pathPosix.join(serverBasePath, '/') // Extract the response items (directory contents) diff --git a/src/services/FolderInfo.js b/src/services/FolderInfo.js index b95d7c67..6d65b57a 100644 --- a/src/services/FolderInfo.js +++ b/src/services/FolderInfo.js @@ -20,8 +20,10 @@ * */ +import { getCurrentUser } from '@nextcloud/auth' import client from './DavClient' import request from './DavRequest' +import parseFile from '../utils/ParseFile' /** * List files from a folder and filter out unwanted mimes @@ -33,17 +35,13 @@ export default async function(path) { // getDirectoryContents doesn't accept / for root const fixedPath = path === '/' ? '' : path + const prefixPath = `/files/${getCurrentUser().uid}` + // fetch listing - const response = await client.stat(fixedPath, { + const response = await client.stat(prefixPath + fixedPath, { data: request, details: true, }) - const entry = response.data - return Object.assign({ - id: parseInt(entry.props.fileid), - isFavorite: entry.props.favorite !== '0', - hasPreview: entry.props['has-preview'] !== 'false', - }, entry) - + return parseFile(response.data, prefixPath) } diff --git a/src/services/PhotoSearch.js b/src/services/PhotoSearch.js index b780ba2c..e4546bb4 100644 --- a/src/services/PhotoSearch.js +++ b/src/services/PhotoSearch.js @@ -20,8 +20,10 @@ * */ -import client from './DavClient' +import { generateRemoteUrl } from '@nextcloud/router' import { getCurrentUser } from '@nextcloud/auth' +import client from './DavClient' +import parseFile from '../utils/ParseFile' /** * List files from a folder and filter out unwanted mimes @@ -35,7 +37,7 @@ export default async function() { headers: { 'content-Type': 'text/xml', }, - url: '/remote.php/dav/', + url: generateRemoteUrl(`dav`), data: `<?xml version="1.0" encoding="UTF-8"?> <d:searchrequest xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" diff --git a/src/services/SystemTags.js b/src/services/SystemTags.js new file mode 100644 index 00000000..a8ce55eb --- /dev/null +++ b/src/services/SystemTags.js @@ -0,0 +1,56 @@ +/** + * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +import client from './DavClient' +import { generateRemoteUrl } from '@nextcloud/router' + +/** + * List files from a folder and filter out unwanted mimes + * + * @returns {Array} the file list + */ +export default async function() { + const response = await client.getDirectoryContents('/systemtags/', { + data: `<?xml version="1.0"?> + <d:propfind xmlns:d="DAV:" + xmlns:oc="http://owncloud.org/ns"> + <d:prop> + <oc:id /> + <oc:display-name /> + <oc:user-visible /> + <oc:user-assignable /> + <oc:can-assign /> + </d:prop> + </d:propfind>`, + details: true, + }) + + console.info(response) + + const entry = response.data + return Object.assign({ + id: parseInt(entry.props.fileid), + isFavorite: entry.props.favorite !== '0', + hasPreview: entry.props['has-preview'] !== 'false', + }, entry) + +} diff --git a/src/store/index.js b/src/store/index.js index d7593570..e48270b7 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -25,12 +25,14 @@ import Vuex, { Store } from 'vuex' import files from './files' import folders from './folders' +import systemtags from './systemtags' Vue.use(Vuex) export default new Store({ modules: { files, folders, + systemtags, }, strict: process.env.NODE_ENV !== 'production', diff --git a/src/store/systemtags.js b/src/store/systemtags.js new file mode 100644 index 00000000..8f213e9e --- /dev/null +++ b/src/store/systemtags.js @@ -0,0 +1,99 @@ +/** + * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +import Vue from 'vue' + +const state = { + paths: {}, + tags: {}, +} + +const mutations = { + /** + * Index folders paths and ids + * + * @param {Object} state vuex state + * @param {Object} data destructuring object + * @param {number} data.id current folder id + * @param {Array} data.files list of files + */ + updateTags(state, { id, files }) { + if (files.length > 0) { + // sort by last modified + const list = files.sort((a, b) => { + return new Date(b.lastmod).getTime() - new Date(a.lastmod).getTime() + }) + + // Set folder list + Vue.set(state.tags, id, list.map(file => file.id)) + } + }, + + /** + * Index folders paths and ids + * + * @param {Object} state vuex state + * @param {Object} data destructuring object + * @param {string} data.path path of this folder + * @param {number} data.id id of this folder + */ + addPath(state, { path, id }) { + Vue.set(state.paths, path, id) + }, +} + +const getters = { + tags: state => state.tags, + tag: state => id => state.tags[id], + tagId: state => path => state.paths[path], +} + +const actions = { + /** + * Update files and folders + * + * @param {Object} context vuex context + * @param {Object} data destructuring object + * @param {number} data.id current folder id + * @param {Array} data.files list of files + * @param {Array} data.folders list of folders + */ + updateTags(context, { id, files, folders }) { + context.commit('updateTags', { id, files }) + + // then add each folders path indexes + folders.forEach(folder => context.commit('addPath', { path: folder.filename, id: folder.id })) + }, + + /** + * Index folders paths and ids + * + * @param {Object} context vuex context + * @param {Object} data destructuring object + * @param {string} data.path path of this folder + * @param {number} data.id id of this folder + */ + addPath(context, { path, id }) { + context.commit('addPath', { path, id }) + }, +} + +export default { state, mutations, getters, actions } diff --git a/src/utils/ParseFile.js b/src/utils/ParseFile.js new file mode 100644 index 00000000..8d9d9baf --- /dev/null +++ b/src/utils/ParseFile.js @@ -0,0 +1,37 @@ +/** + * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/** + * Format a file into a usable fileinfo object + * + * @param {Object} fileData file data returned by the webdav lib + * @param {String} prefixPath path to substract from the files + * @returns {Object} + */ +export default function(fileData, prefixPath = '') { + const filename = fileData.filename.replace(prefixPath, '/').replace(/^\/\//, '/') + return Object.assign({ + id: parseInt(fileData.props.fileid), + isFavorite: fileData.props.favorite !== '0', + hasPreview: fileData.props['has-preview'] !== 'false', + }, fileData, { filename }) +} diff --git a/src/views/Grid.vue b/src/views/Albums.vue index 849fd99b..98642e3d 100644 --- a/src/views/Grid.vue +++ b/src/views/Albums.vue @@ -33,16 +33,11 @@ </EmptyContent> <!-- Folder content --> - <transition-group v-else - class="photos-grid" - role="grid" - name="list" - tag="div"> + <Grid v-else> <Navigation v-if="folder" key="navigation" v-bind="folder" /> <Folder v-for="dir in folderList" :key="dir.id" :folder="dir" /> <File v-for="file in fileList" :key="file.id" v-bind="file" /> - <div key="footer" role="none" class="photos-grid__footer-spacer" /> - </transition-group> + </Grid> </template> <script> @@ -55,16 +50,18 @@ import getPictures from '../services/FileList' import EmptyContent from './EmptyContent' import Folder from '../components/Folder' import File from '../components/File' +import Grid from '../components/Grid' import Navigation from '../components/Navigation' import cancelableRequest from '../utils/CancelableRequest' export default { - name: 'Grid', + name: 'Albums', components: { EmptyContent, File, Folder, + Grid, Navigation, }, props: { @@ -205,50 +202,3 @@ export default { } </script> - -<style lang="scss"> -.photos-grid { - display: grid; - align-items: center; - justify-content: center; - gap: 8px; - grid-template-columns: repeat(10, 1fr); - position: relative; - // always put one more row of grid for the spacer - &__footer-spacer { - // always add one row, so placing it on the first - // column will always add one more - grid-column: 1; - // same height as the width - padding-bottom: 100%; - } -} - -.list-move { - transition: transform var(--animation-quick); -} - -// TODO: use mixins/GridSizes as soon as node-sass supports it -// needs node-sass 5.0 (with libsass 3.6) -// https://github.com/sass/node-sass/pull/2312 -$previous: 0; -@each $size, $config in get('sizes') { - $count: map-get($config, 'count'); - $marginTop: map-get($config, 'marginTop'); - $marginW: map-get($config, 'marginW'); - - // if this is the last entry, only use min-width - $rule: '(min-width: #{$previous}px) and (max-width: #{$size}px)'; - @if $size == 'max' { - $rule: '(min-width: #{$previous}px)'; - } - - @media #{$rule} { - .photos-grid { - padding: #{$marginTop}px #{$marginW}px #{$marginW}px #{$marginW}px; - grid-template-columns: repeat($count, 1fr); - } - } - $previous: $size; -} -</style> diff --git a/src/views/Tags.vue b/src/views/Tags.vue new file mode 100644 index 00000000..8180b2bc --- /dev/null +++ b/src/views/Tags.vue @@ -0,0 +1,111 @@ +<!-- + - @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com> + - + - @author John Molakvoæ <skjnldsv@protonmail.com> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <!-- Errors handlers--> + <!-- <EmptyContent v-if="error === 404" illustration-name="folder"> + {{ t('photos', 'This folder does not exists') }} + </EmptyContent> + <EmptyContent v-else-if="error"> + {{ t('photos', 'An error occurred') }} + </EmptyContent> + <EmptyContent v-else-if="!loading && isEmpty" illustration-name="empty"> + {{ t('photos', 'This folder does not contain pictures') }} + </EmptyContent> --> + + <!-- Folder content --> + <!-- <Grid v-else> + <Navigation v-if="folder" key="navigation" v-bind="folder" /> + <Folder v-for="dir in folderList" :key="dir.id" :folder="dir" /> + <File v-for="file in fileList" :key="file.id" v-bind="file" /> + </Grid> --> + <span>Test</span> +</template> + +<script> +import { mapGetters } from 'vuex' + +import getSystemTags from '../services/SystemTags' + +import EmptyContent from './EmptyContent' +import Folder from '../components/Folder' +import File from '../components/File' +import Grid from '../components/Grid' +import Navigation from '../components/Navigation' + +import cancelableRequest from '../utils/CancelableRequest' + +export default { + name: 'Tags', + components: { + EmptyContent, + File, + Folder, + Grid, + Navigation, + }, + props: { + path: { + type: String, + default: '/', + }, + loading: { + type: Boolean, + required: true, + }, + }, + + data() { + return { + error: null, + cancelRequest: () => {}, + } + }, + + computed: { + // global lists + ...mapGetters([ + 'files', + 'tags', + ]), + }, + + watch: { + path(path) { + console.debug('changed:', path) + this.fetchFolderContent() + }, + }, + + async beforeMount() { + console.debug('beforemount: GRID') + this.fetchFolderContent() + }, + + methods: { + async fetchFolderContent() { + await getSystemTags() + }, + }, + +} +</script> |