diff --git a/frontend/public/themes/dark.css b/frontend/public/themes/dark.css index 3fba1f70..978b4f0f 100644 --- a/frontend/public/themes/dark.css +++ b/frontend/public/themes/dark.css @@ -124,6 +124,14 @@ nav > div { color: var(--textPrimary); } +#editor-container { + background: var(--background); +} + +#editor-container .bar { + background: var(--surfacePrimary); +} + @media (max-width: 736px) { #file-selection { background: var(--surfaceSecondary) !important; diff --git a/frontend/src/components/Header.vue b/frontend/src/components/Header.vue index 2ca5658d..d9542864 100644 --- a/frontend/src/components/Header.vue +++ b/frontend/src/components/Header.vue @@ -1,5 +1,5 @@ <template> - <header> + <header v-if="!isEditor"> <div> <button @click="openSidebar" :aria-label="$t('buttons.toggleSidebar')" :title="$t('buttons.toggleSidebar')" class="action"> <i class="material-icons">menu</i> @@ -13,10 +13,6 @@ <i class="material-icons">search</i> </button> - <button v-show="showSaveButton" :aria-label="$t('buttons.save')" :title="$t('buttons.save')" class="action" id="save-button"> - <i class="material-icons">save</i> - </button> - <button @click="openMore" id="more" :aria-label="$t('buttons.more')" :title="$t('buttons.more')" class="action"> <i class="material-icons">more_vert</i> </button> @@ -129,9 +125,6 @@ export default { showUpload () { return this.isListing && this.user.perm.create }, - showSaveButton () { - return this.isEditor && this.user.perm.modify - }, showDownloadButton () { return this.isFiles && this.user.perm.download }, diff --git a/frontend/src/components/files/Editor.vue b/frontend/src/components/files/Editor.vue index 8f34d48f..76ca8bd2 100644 --- a/frontend/src/components/files/Editor.vue +++ b/frontend/src/components/files/Editor.vue @@ -1,11 +1,37 @@ <template> - <form id="editor"></form> + <div id="editor-container"> + <div class="bar"> + <button @click="back" :title="$t('files.closePreview')" :aria-label="$t('files.closePreview')" id="close" class="action"> + <i class="material-icons">close</i> + </button> + + <div class="title"> + <span>{{ req.name }}</span> + </div> + + <button @click="save" v-show="user.perm.modify" :aria-label="$t('buttons.save')" :title="$t('buttons.save')" id="save-button" class="action"> + <i class="material-icons">save</i> + </button> + </div> + + <div id="breadcrumbs"> + <span><i class="material-icons">home</i></span> + + <span v-for="(link, index) in breadcrumbs" :key="index"> + <span class="chevron"><i class="material-icons">keyboard_arrow_right</i></span> + <span>{{ link.name }}</span> + </span> + </div> + + <form id="editor"></form> + </div> </template> <script> import { mapState } from 'vuex' import { files as api } from '@/api' import buttons from '@/utils/buttons' +import url from '@/utils/url' import ace from 'ace-builds/src-min-noconflict/ace.js' import modelist from 'ace-builds/src-min-noconflict/ext-modelist.js' @@ -14,27 +40,52 @@ import { theme } from '@/utils/constants' export default { name: 'editor', - computed: { - ...mapState(['req']) - }, data: function () { return {} }, + computed: { + ...mapState(['req', 'user']), + breadcrumbs () { + let parts = this.$route.path.split('/') + + if (parts[0] === '') { + parts.shift() + } + + if (parts[parts.length - 1] === '') { + parts.pop() + } + + let breadcrumbs = [] + + for (let i = 0; i < parts.length; i++) { + breadcrumbs.push({ name: decodeURIComponent(parts[i]) }) + } + + breadcrumbs.shift() + + if (breadcrumbs.length > 3) { + while (breadcrumbs.length !== 4) { + breadcrumbs.shift() + } + + breadcrumbs[0].name = '...' + } + + return breadcrumbs + } + }, created () { window.addEventListener('keydown', this.keyEvent) - document.getElementById('save-button').addEventListener('click', this.save) }, beforeDestroy () { window.removeEventListener('keydown', this.keyEvent) - document.getElementById('save-button').removeEventListener('click', this.save) this.editor.destroy(); }, - mounted: function () { + mounted: function () { const fileContent = this.req.content || ''; this.editor = ace.edit('editor', { - maxLines: 80, - minLines: 20, value: fileContent, showPrintMargin: false, readOnly: this.req.type === 'textImmutable', @@ -48,6 +99,10 @@ export default { } }, methods: { + back () { + let uri = url.removeLastDir(this.$route.path) + '/' + this.$router.push({ path: uri }) + }, keyEvent (event) { if (!event.ctrlKey && !event.metaKey) { return diff --git a/frontend/src/css/styles.css b/frontend/src/css/styles.css index e663356a..2da1d242 100644 --- a/frontend/src/css/styles.css +++ b/frontend/src/css/styles.css @@ -184,6 +184,53 @@ right: 0.5em; } +/* EDITOR */ + +#editor-container { + background-color: #fafafa; + position: fixed; + top: 0; + left: 0; + width: 100%; + z-index: 9999; + overflow: hidden; +} + +#editor-container .bar { + width: 100%; + text-align: right; + display: flex; + padding: 0.5em; + height: 3.7em; + background-color: #fff; + border-bottom: 1px solid rgba(0, 0, 0, 0.075); + box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); +} + +#editor-container .title { + margin-right: auto; + padding: 0 1em; + line-height: 2.7em; + overflow: hidden; + word-break: break-word; +} + +#previewer .title span { + font-size: 1.2em; +} + +#editor-container #editor { + height: calc(100vh - 8.2em); +} + +#editor-container #breadcrumbs { + height: 2.3em; + padding: 0 1em; +} + +#editor-container #breadcrumbs span { + font-size: 12px; +} /* * * * * * * * * * * * * * * * * PROMPT * diff --git a/frontend/src/views/Files.vue b/frontend/src/views/Files.vue index b9d4ddeb..c19709ae 100644 --- a/frontend/src/views/Files.vue +++ b/frontend/src/views/Files.vue @@ -1,6 +1,6 @@ <template> <div> - <div id="breadcrumbs"> + <div id="breadcrumbs" v-if="isListing || error"> <router-link to="/files/" :aria-label="$t('files.home')" :title="$t('files.home')"> <i class="material-icons">home</i> </router-link>