Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 1 addition & 41 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,7 @@
>
<NcAppNavigation :class="{loading: loading.notes, 'icon-error': error}">
<template #list>
<NcAppNavigationNew
v-show="!loading.notes && !error"
:text="t('notes', 'New category')"
@click="onNewCategory"
@dragover="onNewCategoryDragOver"
@drop="onNewCategoryDrop"
>
<template #icon>
<FolderPlusIcon :size="20" />
</template>
</NcAppNavigationNew>
<CategoriesList :loading="loading.notes" />
<CategoriesList :loading="loading.notes" :hideNewCategoryAction="!!error" />
</template>

<template #footer>
Expand Down Expand Up @@ -92,11 +81,9 @@ import { useIsMobile } from '@nextcloud/vue/composables/useIsMobile'
import NcAppContent from '@nextcloud/vue/components/NcAppContent'
import NcAppNavigation from '@nextcloud/vue/components/NcAppNavigation'
import NcAppNavigationItem from '@nextcloud/vue/components/NcAppNavigationItem'
import NcAppNavigationNew from '@nextcloud/vue/components/NcAppNavigationNew'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcContent from '@nextcloud/vue/components/NcContent'
import CogIcon from 'vue-material-design-icons/CogOutline.vue'
import FolderPlusIcon from 'vue-material-design-icons/FolderPlusOutline.vue'
import FocusIcon from 'vue-material-design-icons/ImageFilterCenterFocusStrongOutline.vue'
import ShareVariantOutlineIcon from 'vue-material-design-icons/ShareVariantOutline.vue'
import AppSettings from './components/AppSettings.vue'
Expand All @@ -107,7 +94,6 @@ import { config } from './config.js'
import logger from './Logger.js'
import { fetchNotes, noteExists, undoDeleteNote } from './NotesService.js'
import store from './store.js'
import { getDraggedNoteId, isNoteDrag } from './Util.js'

import '@nextcloud/dialogs/style.css'

Expand All @@ -126,13 +112,11 @@ export default {
EditorHint,
NcAppContent,
NcAppNavigation,
NcAppNavigationNew,
NcAppNavigationItem,
NcButton,
NcContent,
FocusIcon,
NoteShareSidebar,
FolderPlusIcon,
ShareVariantOutlineIcon,
},

Expand Down Expand Up @@ -358,30 +342,6 @@ export default {
}
},

onNewCategory() {
emit('notes:category:new')
},

onNewCategoryDragOver(event) {
if (!isNoteDrag(event)) {
return
}
event.preventDefault()
if (event.dataTransfer) {
event.dataTransfer.dropEffect = 'move'
}
},

onNewCategoryDrop(event) {
const noteId = getDraggedNoteId(event, (noteId) => store.notes.getNote(noteId))
if (noteId === null) {
return
}
event.preventDefault()
event.stopPropagation()
emit('notes:category:new', { noteId })
},

onNoteDeleted(note) {
this.deletedNotes.push(note)
this.clearUndoTimer()
Expand Down
94 changes: 89 additions & 5 deletions src/components/CategoriesList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,23 @@
</template>
</NcAppNavigationItem>

<NcAppNavigationCaption v-show="!loading" :name="t('notes', 'Categories')" />
<NcAppNavigationCaption v-show="!loading"
:name="t('notes', 'Categories')"
:inline="1"
:class="{ 'drop-over-caption': dragOverNewCategory }"
@dragover="onNewCategoryDragOver($event)"
@dragleave="onNewCategoryDragLeave($event)"
@drop="onNewCategoryDrop($event)"
>
<template #actions>
<NcActionButton v-if="!hideNewCategoryAction" @click="startNewCategory()">
<template #icon>
<FolderPlusIcon :size="20" />
</template>
{{ t('notes', 'New category') }}
</NcActionButton>
</template>
</NcAppNavigationCaption>

<NcAppNavigationItem
v-if="newCategoryDraft"
Expand Down Expand Up @@ -63,7 +79,6 @@
:editLabel="t('notes', 'Rename category')"
:editPlaceholder="category.name"
:forceMenu="category.name !== ''"
:forceDisplayActions="category.name !== ''"
:class="{
'drop-over': category.name === dragOverCategory,
'category-no-actions': category.name === '',
Expand Down Expand Up @@ -106,6 +121,7 @@ import NcCounterBubble from '@nextcloud/vue/components/NcCounterBubble'
import DeleteIcon from 'vue-material-design-icons/Delete.vue'
import FolderIcon from 'vue-material-design-icons/Folder.vue'
import FolderOutlineIcon from 'vue-material-design-icons/FolderOutline.vue'
import FolderPlusIcon from 'vue-material-design-icons/FolderPlusOutline.vue'
import HistoryIcon from 'vue-material-design-icons/History.vue'
import { deleteCategory as deleteCategoryRequest, getCategories, renameCategory as renameCategoryRequest, setCategory } from '../NotesService.js'
import store from '../store.js'
Expand All @@ -122,16 +138,19 @@ export default {
NcCounterBubble,
FolderIcon,
FolderOutlineIcon,
FolderPlusIcon,
HistoryIcon,
},

props: {
loading: Boolean,
hideNewCategoryAction: Boolean,
},
Comment on lines 145 to 148

data() {
return {
dragOverCategory: null,
dragOverNewCategory: false,
dragOverAllNotes: false,
newCategoryDraft: false,
newCategoryMonitor: null,
Expand Down Expand Up @@ -179,6 +198,40 @@ export default {
})
},

onNewCategoryDragOver(event) {
if (this.hideNewCategoryAction || !isNoteDrag(event)) {
return
}
event.preventDefault()
if (event.dataTransfer) {
event.dataTransfer.dropEffect = 'move'
}
this.dragOverNewCategory = true
},

onNewCategoryDragLeave(event) {
// dragleave also fires when moving onto a child element, so ignore
// events that are still inside the caption row
if (event.currentTarget?.contains(event.relatedTarget)) {
return
}
this.dragOverNewCategory = false
},

onNewCategoryDrop(event) {
if (this.hideNewCategoryAction) {
return
}
this.dragOverNewCategory = false
const noteId = getDraggedNoteId(event, (noteId) => store.notes.getNote(noteId))
if (noteId === null) {
return
}
event.preventDefault()
event.stopPropagation()
this.startNewCategory({ noteId })
},

stopNewCategoryMonitor() {
if (this.newCategoryMonitor) {
cancelAnimationFrame(this.newCategoryMonitor)
Expand Down Expand Up @@ -453,13 +506,44 @@ export default {
</script>

<style lang="scss" scoped>
.app-navigation-entry-wrapper.drop-over:deep(.app-navigation-entry) {
/* The caption is not an .app-navigation-entry, so it opts into the same drop
hint by its own class. */
.app-navigation-entry-wrapper.drop-over:deep(.app-navigation-entry),
.app-navigation-caption.drop-over-caption {
background-color: var(--color-primary-element-light) !important;
outline: 2px dashed var(--color-primary-element);
outline-offset: -2px;
border-radius: var(--border-radius-element, var(--border-radius-large));
}

/* 22px is the counter bubble's diameter, so this centres a single-digit
bubble under the caption's icon. */
.app-navigation-entry-wrapper:deep(.app-navigation-entry__utils) {
--counter-inset: calc((var(--default-clickable-area) - 22px) / 2);
position: relative;
}

.app-navigation-entry-wrapper:deep(.app-navigation-entry__utils .app-navigation-entry__counter-wrapper) {
margin-inline-end: var(--counter-inset);
transition: margin-inline-end var(--animation-quick) ease-in-out;
}

/* Out of the flow, so revealing it lets the counter animate aside instead of
being displaced instantly. */
.app-navigation-entry-wrapper:deep(.app-navigation-entry__utils .action-item.app-navigation-entry__actions) {
position: absolute;
inset-inline-end: 0;
}

.app-navigation-entry-wrapper:not(.category-no-actions):deep(.app-navigation-entry:hover .app-navigation-entry__counter-wrapper),
.app-navigation-entry-wrapper:not(.category-no-actions):deep(.app-navigation-entry:focus-within .app-navigation-entry__counter-wrapper),
.app-navigation-entry-wrapper:not(.category-no-actions):deep(.app-navigation-entry.active .app-navigation-entry__counter-wrapper) {
margin-inline-end: calc(var(--counter-inset) + var(--default-clickable-area));
}

.app-navigation-entry-wrapper.category-no-actions:deep(.app-navigation-entry__counter-wrapper) {
margin-inline-end: calc(var(--default-grid-baseline) * 2 + var(--default-clickable-area));
@media (prefers-reduced-motion: reduce) {
.app-navigation-entry-wrapper:deep(.app-navigation-entry__utils .app-navigation-entry__counter-wrapper) {
transition: none;
}
}
</style>
Loading