diff --git a/src/api/context.js b/src/api/context.js new file mode 100644 index 0000000..c9ed358 --- /dev/null +++ b/src/api/context.js @@ -0,0 +1,5 @@ +import { fetchJSON } from './utils' + +export async function get () { + return await fetchJSON(`/api/context`, {}) +} diff --git a/src/api/files.js b/src/api/files.js index 917e46e..0b94e15 100644 --- a/src/api/files.js +++ b/src/api/files.js @@ -112,6 +112,18 @@ export async function post (url, content = '', overwrite = false, onupload) { }) } +export function bookmark (items) { + let promises = [] + + for (let item of items) { + const path = removePrefix(item.path) + const url = `${path}?action=${item.bookmarked ? 'bookmark' : 'remove-bookmark'}` + promises.push(resourceAction(url, 'PATCH')) + } + + return Promise.all(promises) +} + function moveCopy (items, copy = false) { let promises = [] diff --git a/src/api/index.js b/src/api/index.js index 11bb49d..789204d 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -2,6 +2,7 @@ import * as files from './files' import * as share from './share' import * as users from './users' import * as settings from './settings' +import * as context from './context' import search from './search' import commands from './commands' @@ -11,5 +12,6 @@ export { users, settings, commands, - search + search, + context } diff --git a/src/components/Header.vue b/src/components/Header.vue index 0cfc4cb..48f0020 100644 --- a/src/components/Header.vue +++ b/src/components/Header.vue @@ -45,6 +45,7 @@ <switch-button v-show="isListing"></switch-button> <download-button v-show="showDownloadButton"></download-button> <upload-button v-show="showUpload"></upload-button> + <bookmark-button v-show="showBookmarkButton"></bookmark-button> <info-button v-show="isFiles"></info-button> <button v-show="isListing" @click="openSelect" :aria-label="$t('buttons.selectMultiple')" :title="$t('buttons.selectMultiple')" class="action"> @@ -71,6 +72,7 @@ import MoveButton from './buttons/Move' import CopyButton from './buttons/Copy' import ShareButton from './buttons/Share' import ShellButton from './buttons/Shell' +import BookmarkButton from './buttons/Bookmark' import {mapGetters, mapState} from 'vuex' import { logoURL } from '@/utils/constants' import * as api from '@/api' @@ -89,7 +91,8 @@ export default { UploadButton, SwitchButton, MoveButton, - ShellButton + ShellButton, + BookmarkButton }, data: function () { return { @@ -145,6 +148,9 @@ export default { ? (this.selectedCount === 1 && this.user.perm.rename) : this.user.perm.rename) }, + showBookmarkButton () { + return this.isFiles && this.isListing + }, showShareButton () { return this.isFiles && (this.isListing ? (this.selectedCount === 1 && this.user.perm.share) diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index 6ebc852..197979e 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -6,7 +6,14 @@ <span>{{ $t('sidebar.myFiles') }}</span> </router-link> - <div v-if="user.perm.create"> + <div> + <router-link v-for="(bookmark) in bookmarks" :to="'/files'+bookmark.path" class="action" :aria-label="bookmark.name" :title="bookmark.name"> + <i class="material-icons">folder</i> + <span>{{ bookmark.name }}</span> + </router-link> + </div> + + <div v-if="user.perm.create" v-show="showNew"> <button @click="$store.commit('showHover', 'newDir')" class="action" :aria-label="$t('sidebar.newFolder')" :title="$t('sidebar.newFolder')"> <i class="material-icons">create_new_folder</i> <span>{{ $t('sidebar.newFolder') }}</span> @@ -62,10 +69,18 @@ export default { name: 'sidebar', computed: { ...mapState([ 'user' ]), - ...mapGetters([ 'isLogged' ]), + ...mapGetters([ + 'isLogged', + 'bookmarks', + 'isFiles', + 'isListing' + ]), active () { return this.$store.state.show === 'sidebar' }, + showNew() { + return this.isFiles && this.isListing + }, signup: () => signup, version: () => version, disableExternal: () => disableExternal, diff --git a/src/components/buttons/Bookmark.vue b/src/components/buttons/Bookmark.vue new file mode 100644 index 0000000..cce3b8b --- /dev/null +++ b/src/components/buttons/Bookmark.vue @@ -0,0 +1,43 @@ +<template> + <button @click="toggle" :aria-label="$t('buttons.bookmark')" :title="$t('buttons.bookmark')" class="action" id="bookmark-button"> + <i class="material-icons">{{ icon }}</i> + <span>{{ $t('buttons.bookmark') }}</span> + </button> +</template> + +<script> +import { mapState, mapMutations } from 'vuex' +import { files as filesApi, context as contextApi } from '@/api' + +export default { + name: 'bookmark-button', + computed: { + ...mapState(['req']), + icon: function () { + if (this.req.bookmarked) return 'bookmark' + return 'bookmark_border' + } + }, + methods: { + ...mapMutations([ 'updateBookmark', 'closeHovers' ]), + toggle: async function () { + this.closeHovers() + + const data = { + path: this.req.path, + bookmarked: (this.icon === 'bookmark_border') + } + + try { + await filesApi.bookmark([data]) + this.updateBookmark(data) + + const ctx = await contextApi.get() + this.$store.commit('updateContext', ctx) + } catch (e) { + this.$showError(e) + } + } + } +} +</script> diff --git a/src/i18n/en.json b/src/i18n/en.json index d423ece..734a14e 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -32,7 +32,8 @@ "toggleSidebar": "Toggle sidebar", "update": "Update", "upload": "Upload", - "permalink": "Get Permanent Link" + "permalink": "Get Permanent Link", + "bookmark": "Bookmark" }, "success": { "linkCopied": "Link copied!" diff --git a/src/i18n/fr.json b/src/i18n/fr.json index f5d7d88..651bd8b 100644 --- a/src/i18n/fr.json +++ b/src/i18n/fr.json @@ -32,7 +32,8 @@ "toggleSidebar": "Afficher/Masquer la barre latérale", "update": "Mettre à jour", "upload": "Importer", - "permalink": "Obtenir un lien permanent" + "permalink": "Obtenir un lien permanent", + "bookmark": "Retenir dans les marques pages" }, "success": { "linkCopied": "Link copied!" diff --git a/src/store/getters.js b/src/store/getters.js index 9831b7b..9f4dfbd 100644 --- a/src/store/getters.js +++ b/src/store/getters.js @@ -3,7 +3,8 @@ const getters = { isFiles: state => !state.loading && state.route.name === 'Files', isListing: (state, getters) => getters.isFiles && state.req.isDir, isEditor: (state, getters) => getters.isFiles && (state.req.type === 'text' || state.req.type === 'textImmutable'), - selectedCount: state => state.selected.length + selectedCount: state => state.selected.length, + bookmarks: state => state.context.bookmarks } export default getters diff --git a/src/store/index.js b/src/store/index.js index 25c37bb..24d0d0c 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -8,6 +8,7 @@ Vue.use(Vuex) const state = { user: null, req: {}, + context: {}, oldReq: {}, clipboard: { key: '', diff --git a/src/store/mutations.js b/src/store/mutations.js index 747c91b..d48614c 100644 --- a/src/store/mutations.js +++ b/src/store/mutations.js @@ -71,10 +71,18 @@ const mutations = { state.user[field] = value[field] } }, + updateBookmark: (state, value) => { + if (value.path == state.req.path) { + state.req.bookmarked = value.bookmarked + } + }, updateRequest: (state, value) => { state.oldReq = state.req state.req = value }, + updateContext: (state, value) => { + state.context = value + }, updateClipboard: (state, value) => { state.clipboard.key = value.key state.clipboard.items = value.items diff --git a/src/views/Layout.vue b/src/views/Layout.vue index 8db58b3..b0dfc1e 100644 --- a/src/views/Layout.vue +++ b/src/views/Layout.vue @@ -19,6 +19,7 @@ import Sidebar from '@/components/Sidebar' import Prompts from '@/components/prompts/Prompts' import SiteHeader from '@/components/Header' import Shell from '@/components/Shell' +import { context as api } from '@/api' export default { name: 'layout', @@ -38,6 +39,14 @@ export default { this.$store.commit('multiple', false) if (this.$store.state.show !== 'success') this.$store.commit('closeHovers') } + }, + async created() { + try { + const res = await api.get() + this.$store.commit('updateContext', res) + } catch (e) { + this.$showError(e) + } } } </script>