mirror of
https://github.com/nextcloud/server.git
synced 2026-05-28 04:32:30 -04:00
refactor(files): handle file list width break points in one central point
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
parent
3f9849d921
commit
871f037dda
14 changed files with 164 additions and 196 deletions
|
|
@ -16,7 +16,7 @@
|
|||
v-bind="section"
|
||||
dir="auto"
|
||||
:to="section.to"
|
||||
:force-icon-text="index === 0 && fileListWidth >= 486"
|
||||
:force-icon-text="index === 0 && !isNarrow"
|
||||
:title="titleForSection(index, section)"
|
||||
:aria-description="ariaForSection(section)"
|
||||
@click.native="onClick(section.to)"
|
||||
|
|
@ -76,6 +76,8 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
|
||||
emits: ['reload'],
|
||||
|
||||
setup() {
|
||||
const activeStore = useActiveStore()
|
||||
const filesStore = useFilesStore()
|
||||
|
|
@ -84,7 +86,7 @@ export default defineComponent({
|
|||
const selectionStore = useSelectionStore()
|
||||
const uploaderStore = useUploaderStore()
|
||||
|
||||
const fileListWidth = useFileListWidth()
|
||||
const { isNarrow } = useFileListWidth()
|
||||
const views = useViews()
|
||||
|
||||
return {
|
||||
|
|
@ -95,7 +97,7 @@ export default defineComponent({
|
|||
selectionStore,
|
||||
uploaderStore,
|
||||
|
||||
fileListWidth,
|
||||
isNarrow,
|
||||
views,
|
||||
}
|
||||
},
|
||||
|
|
@ -132,7 +134,7 @@ export default defineComponent({
|
|||
wrapUploadProgressBar(): boolean {
|
||||
// if an upload is ongoing, and on small screens / mobile, then
|
||||
// show the progress bar for the upload below breadcrumbs
|
||||
return this.isUploadInProgress && this.fileListWidth < 512
|
||||
return this.isUploadInProgress && this.isNarrow
|
||||
},
|
||||
|
||||
// used to show the views icon for the first breadcrumb
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ export default defineComponent({
|
|||
const filesStore = useFilesStore()
|
||||
const renamingStore = useRenamingStore()
|
||||
const selectionStore = useSelectionStore()
|
||||
const filesListWidth = useFileListWidth()
|
||||
const { isNarrow } = useFileListWidth()
|
||||
const {
|
||||
fileId: currentRouteFileId,
|
||||
} = useRouteParameters()
|
||||
|
|
@ -178,7 +178,7 @@ export default defineComponent({
|
|||
activeView,
|
||||
currentRouteFileId,
|
||||
draggingStore,
|
||||
filesListWidth,
|
||||
isNarrow,
|
||||
filesStore,
|
||||
renamingStore,
|
||||
selectionStore,
|
||||
|
|
@ -209,10 +209,10 @@ export default defineComponent({
|
|||
|
||||
columns() {
|
||||
// Hide columns if the list is too small
|
||||
if (this.filesListWidth < 512 || this.compact) {
|
||||
if (this.isNarrow || this.compact) {
|
||||
return []
|
||||
}
|
||||
return this.activeView.columns || []
|
||||
return this.activeView?.columns || []
|
||||
},
|
||||
|
||||
mime() {
|
||||
|
|
|
|||
|
|
@ -173,15 +173,17 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
|
||||
emits: ['update:opened'],
|
||||
|
||||
setup() {
|
||||
// The file list is guaranteed to be shown with active view - thus we can set the `loaded` flag
|
||||
const activeStore = useActiveStore()
|
||||
const filesListWidth = useFileListWidth()
|
||||
const { isNarrow } = useFileListWidth()
|
||||
const enabledFileActions = inject<FileAction[]>('enabledFileActions', [])
|
||||
return {
|
||||
activeStore,
|
||||
enabledFileActions,
|
||||
filesListWidth,
|
||||
isNarrow,
|
||||
t,
|
||||
}
|
||||
},
|
||||
|
|
@ -206,7 +208,7 @@ export default defineComponent({
|
|||
|
||||
// Enabled action that are displayed inline
|
||||
enabledInlineActions() {
|
||||
if (this.filesListWidth < 768 || this.gridMode) {
|
||||
if (this.isNarrow || this.gridMode) {
|
||||
return []
|
||||
}
|
||||
return this.enabledFileActions.filter((action) => {
|
||||
|
|
@ -302,7 +304,7 @@ export default defineComponent({
|
|||
methods: {
|
||||
actionDisplayName(action: FileAction) {
|
||||
try {
|
||||
if ((this.gridMode || (this.filesListWidth < 768 && action.inline)) && typeof action.title === 'function') {
|
||||
if ((this.gridMode || (this.isNarrow && action.inline)) && typeof action.title === 'function') {
|
||||
// if an inline action is rendered in the menu for
|
||||
// lack of space we use the title first if defined
|
||||
const title = action.title(this.actionContext)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { FileAction, Node } from '@nextcloud/files'
|
||||
import type { FileAction, Node, TFileType } from '@nextcloud/files'
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
|
|
@ -96,7 +96,7 @@ export default defineComponent({
|
|||
|
||||
setup() {
|
||||
// The file list is guaranteed to be only shown with active view - thus we can set the `loaded` flag
|
||||
const filesListWidth = useFileListWidth()
|
||||
const { isNarrow } = useFileListWidth()
|
||||
const renamingStore = useRenamingStore()
|
||||
const userConfigStore = useUserConfigStore()
|
||||
const { activeFolder, activeView } = useActiveStore()
|
||||
|
|
@ -107,7 +107,7 @@ export default defineComponent({
|
|||
activeFolder,
|
||||
activeView,
|
||||
defaultFileAction,
|
||||
filesListWidth,
|
||||
isNarrow,
|
||||
renamingStore,
|
||||
userConfigStore,
|
||||
}
|
||||
|
|
@ -119,7 +119,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
isRenamingSmallScreen() {
|
||||
return this.isRenaming && this.filesListWidth < 512
|
||||
return this.isRenaming && this.isNarrow
|
||||
},
|
||||
|
||||
newName: {
|
||||
|
|
@ -133,7 +133,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
renameLabel() {
|
||||
const matchLabel: Record<FileType, string> = {
|
||||
const matchLabel: Record<TFileType, string> = {
|
||||
[FileType.File]: t('files', 'Filename'),
|
||||
[FileType.Folder]: t('files', 'Folder name'),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ export default defineComponent({
|
|||
const filesStore = useFilesStore()
|
||||
const renamingStore = useRenamingStore()
|
||||
const selectionStore = useSelectionStore()
|
||||
const filesListWidth = useFileListWidth()
|
||||
const { isNarrow } = useFileListWidth()
|
||||
const {
|
||||
fileId: currentRouteFileId,
|
||||
} = useRouteParameters()
|
||||
|
|
@ -131,7 +131,7 @@ export default defineComponent({
|
|||
activeView,
|
||||
currentRouteFileId,
|
||||
draggingStore,
|
||||
filesListWidth,
|
||||
isNarrow,
|
||||
filesStore,
|
||||
renamingStore,
|
||||
selectionStore,
|
||||
|
|
|
|||
|
|
@ -36,10 +36,6 @@ export default defineComponent({
|
|||
type: Array as PropType<Node[]>,
|
||||
required: true,
|
||||
},
|
||||
filesListWidth: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
isMtimeAvailable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
|
|
@ -119,7 +115,7 @@ export default defineComponent({
|
|||
return this.renamingStore.renamingNode === this.source
|
||||
},
|
||||
isRenamingSmallScreen() {
|
||||
return this.isRenaming && this.filesListWidth < 512
|
||||
return this.isRenaming && this.isNarrow
|
||||
},
|
||||
|
||||
isActive() {
|
||||
|
|
|
|||
|
|
@ -48,111 +48,69 @@
|
|||
</tr>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { Node } from '@nextcloud/files'
|
||||
import type { PropType } from 'vue'
|
||||
<script setup lang="ts">
|
||||
import type { IColumn, INode, IView } from '@nextcloud/files'
|
||||
|
||||
import { formatFileSize, View } from '@nextcloud/files'
|
||||
import { translate } from '@nextcloud/l10n'
|
||||
import { defineComponent } from 'vue'
|
||||
import { useRouteParameters } from '../composables/useRouteParameters.ts'
|
||||
import { useFilesStore } from '../store/files.ts'
|
||||
import { usePathsStore } from '../store/paths.ts'
|
||||
import { formatFileSize } from '@nextcloud/files'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { computed } from 'vue'
|
||||
import { useFileListWidth } from '../composables/useFileListWidth.ts'
|
||||
import { useActiveStore } from '../store/active.ts'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FilesListTableFooter',
|
||||
const props = defineProps<{
|
||||
/** The current view */
|
||||
currentView: IView
|
||||
|
||||
props: {
|
||||
currentView: {
|
||||
type: View,
|
||||
required: true,
|
||||
},
|
||||
/** Whether the mime column is available */
|
||||
isMimeAvailable: boolean
|
||||
|
||||
isMimeAvailable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** Whether the mtime column is available */
|
||||
isMtimeAvailable: boolean
|
||||
|
||||
isMtimeAvailable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** Whether the size column is available */
|
||||
isSizeAvailable: boolean
|
||||
|
||||
isSizeAvailable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** The nodes to summarize */
|
||||
nodes: INode[]
|
||||
|
||||
nodes: {
|
||||
type: Array as PropType<Node[]>,
|
||||
required: true,
|
||||
},
|
||||
/** Summary text */
|
||||
summary: string
|
||||
}>()
|
||||
|
||||
summary: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
const activeStore = useActiveStore()
|
||||
const { isNarrow } = useFileListWidth()
|
||||
|
||||
filesListWidth: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
const currentFolder = computed(() => activeStore.activeFolder)
|
||||
|
||||
setup() {
|
||||
const pathsStore = usePathsStore()
|
||||
const filesStore = useFilesStore()
|
||||
const { directory } = useRouteParameters()
|
||||
return {
|
||||
filesStore,
|
||||
pathsStore,
|
||||
directory,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
currentFolder() {
|
||||
if (!this.currentView?.id) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.directory === '/') {
|
||||
return this.filesStore.getRoot(this.currentView.id)
|
||||
}
|
||||
const fileId = this.pathsStore.getPath(this.currentView.id, this.directory)!
|
||||
return this.filesStore.getNode(fileId)
|
||||
},
|
||||
|
||||
columns() {
|
||||
// Hide columns if the list is too small
|
||||
if (this.filesListWidth < 512) {
|
||||
return []
|
||||
}
|
||||
return this.currentView?.columns || []
|
||||
},
|
||||
|
||||
totalSize() {
|
||||
// If we have the size already, let's use it
|
||||
if (this.currentFolder?.size) {
|
||||
return formatFileSize(this.currentFolder.size, true)
|
||||
}
|
||||
|
||||
// Otherwise let's compute it
|
||||
return formatFileSize(this.nodes.reduce((total, node) => total + (node.size ?? 0), 0), true)
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
classForColumn(column) {
|
||||
return {
|
||||
'files-list__row-column-custom': true,
|
||||
[`files-list__row-${this.currentView.id}-${column.id}`]: true,
|
||||
}
|
||||
},
|
||||
|
||||
t: translate,
|
||||
},
|
||||
const columns = computed(() => {
|
||||
// Hide columns if the list is too small
|
||||
if (isNarrow.value) {
|
||||
return []
|
||||
}
|
||||
return props.currentView?.columns || []
|
||||
})
|
||||
|
||||
const totalSize = computed(() => {
|
||||
// If we have the size already, let's use it
|
||||
if (currentFolder.value?.size) {
|
||||
return formatFileSize(currentFolder.value.size, true)
|
||||
}
|
||||
|
||||
// Otherwise let's compute it
|
||||
return formatFileSize(props.nodes.reduce((total, node) => total + (node.size ?? 0), 0), true)
|
||||
})
|
||||
|
||||
/**
|
||||
* Get the CSS classes for a custom column
|
||||
*
|
||||
* @param column - The column
|
||||
*/
|
||||
function classForColumn(column: IColumn) {
|
||||
return {
|
||||
'files-list__row-column-custom': true,
|
||||
[`files-list__row-${props.currentView.id}-${column.id}`]: true,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<NcCheckboxRadioSwitch
|
||||
v-bind="selectAllBind"
|
||||
data-cy-files-list-selection-checkbox
|
||||
@update:modelValue="onToggleAll" />
|
||||
@update:model-value="onToggleAll" />
|
||||
</th>
|
||||
|
||||
<!-- Columns display -->
|
||||
|
|
@ -80,6 +80,7 @@ import { useHotKey } from '@nextcloud/vue/composables/useHotKey'
|
|||
import { defineComponent } from 'vue'
|
||||
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
|
||||
import FilesListTableHeaderButton from './FilesListTableHeaderButton.vue'
|
||||
import { useFileListWidth } from '../composables/useFileListWidth.ts'
|
||||
import { useRouteParameters } from '../composables/useRouteParameters.ts'
|
||||
import logger from '../logger.ts'
|
||||
import filesSortingMixin from '../mixins/filesSorting.ts'
|
||||
|
|
@ -119,11 +120,6 @@ export default defineComponent({
|
|||
type: Array as PropType<Node[]>,
|
||||
required: true,
|
||||
},
|
||||
|
||||
filesListWidth: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
|
||||
setup() {
|
||||
|
|
@ -132,19 +128,22 @@ export default defineComponent({
|
|||
const selectionStore = useSelectionStore()
|
||||
const { directory } = useRouteParameters()
|
||||
|
||||
const { isNarrow } = useFileListWidth()
|
||||
|
||||
return {
|
||||
activeStore,
|
||||
filesStore,
|
||||
selectionStore,
|
||||
|
||||
directory,
|
||||
isNarrow,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
columns() {
|
||||
// Hide columns if the list is too small
|
||||
if (this.filesListWidth < 512) {
|
||||
if (this.isNarrow) {
|
||||
return []
|
||||
}
|
||||
return this.activeStore.activeView?.columns || []
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ import type { FileSource } from '../types.ts'
|
|||
import { showError, showSuccess } from '@nextcloud/dialogs'
|
||||
import { DefaultType, getFileActions, NodeStatus } from '@nextcloud/files'
|
||||
import { translate } from '@nextcloud/l10n'
|
||||
import { defineComponent } from 'vue'
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
|
||||
import NcActions from '@nextcloud/vue/components/NcActions'
|
||||
import NcActionSeparator from '@nextcloud/vue/components/NcActionSeparator'
|
||||
|
|
@ -126,18 +126,28 @@ export default defineComponent({
|
|||
const actionsMenuStore = useActionsMenuStore()
|
||||
const filesStore = useFilesStore()
|
||||
const selectionStore = useSelectionStore()
|
||||
const fileListWidth = useFileListWidth()
|
||||
const { isMedium, isNarrow } = useFileListWidth()
|
||||
|
||||
const boundariesElement = document.getElementById('app-content-vue')
|
||||
|
||||
const inlineActions = computed(() => {
|
||||
if (isNarrow.value) {
|
||||
return 0
|
||||
}
|
||||
if (isMedium.value) {
|
||||
return 1
|
||||
}
|
||||
return 3
|
||||
})
|
||||
|
||||
return {
|
||||
actionsMenuStore,
|
||||
activeFolder,
|
||||
fileListWidth,
|
||||
filesStore,
|
||||
selectionStore,
|
||||
|
||||
boundariesElement,
|
||||
inlineActions,
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -256,19 +266,6 @@ export default defineComponent({
|
|||
this.actionsMenuStore.opened = opened ? 'global' : null
|
||||
},
|
||||
},
|
||||
|
||||
inlineActions() {
|
||||
if (this.fileListWidth < 512) {
|
||||
return 0
|
||||
}
|
||||
if (this.fileListWidth < 768) {
|
||||
return 1
|
||||
}
|
||||
if (this.fileListWidth < 1024) {
|
||||
return 2
|
||||
}
|
||||
return 3
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@
|
|||
<!-- Table header and sort buttons -->
|
||||
<FilesListTableHeader
|
||||
ref="thead"
|
||||
:files-list-width="fileListWidth"
|
||||
:is-mime-available="isMimeAvailable"
|
||||
:is-mtime-available="isMtimeAvailable"
|
||||
:is-size-available="isSizeAvailable"
|
||||
|
|
@ -61,7 +60,6 @@
|
|||
<template #footer>
|
||||
<FilesListTableFooter
|
||||
:current-view="currentView"
|
||||
:files-list-width="fileListWidth"
|
||||
:is-mime-available="isMimeAvailable"
|
||||
:is-mtime-available="isMtimeAvailable"
|
||||
:is-size-available="isSizeAvailable"
|
||||
|
|
@ -72,7 +70,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { Node as NcNode } from '@nextcloud/files'
|
||||
import type { INode } from '@nextcloud/files'
|
||||
import type { ComponentPublicInstance, PropType } from 'vue'
|
||||
import type { UserConfig } from '../types.ts'
|
||||
|
||||
|
|
@ -80,7 +78,7 @@ import { showError } from '@nextcloud/dialogs'
|
|||
import { FileType, Folder, getFileActions, getSidebar, Permission, View } from '@nextcloud/files'
|
||||
import { n, t } from '@nextcloud/l10n'
|
||||
import { useHotKey } from '@nextcloud/vue/composables/useHotKey'
|
||||
import { defineComponent } from 'vue'
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import FileEntry from './FileEntry.vue'
|
||||
import FileEntryGrid from './FileEntryGrid.vue'
|
||||
import FileListFilters from './FileListFilters.vue'
|
||||
|
|
@ -94,7 +92,7 @@ import { useFileListWidth } from '../composables/useFileListWidth.ts'
|
|||
import { useRouteParameters } from '../composables/useRouteParameters.ts'
|
||||
import logger from '../logger.ts'
|
||||
import { useActiveStore } from '../store/active.ts'
|
||||
import { useSelectionStore } from '../store/selection.js'
|
||||
import { useSelectionStore } from '../store/selection.ts'
|
||||
import { useUserConfigStore } from '../store/userconfig.ts'
|
||||
|
||||
export default defineComponent({
|
||||
|
|
@ -121,7 +119,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
nodes: {
|
||||
type: Array as PropType<NcNode[]>,
|
||||
type: Array as PropType<INode[]>,
|
||||
required: true,
|
||||
},
|
||||
|
||||
|
|
@ -131,19 +129,48 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
|
||||
setup() {
|
||||
setup(props) {
|
||||
const sidebar = getSidebar()
|
||||
const activeStore = useActiveStore()
|
||||
const selectionStore = useSelectionStore()
|
||||
const userConfigStore = useUserConfigStore()
|
||||
|
||||
const fileListWidth = useFileListWidth()
|
||||
const { isNarrow, isWide } = useFileListWidth()
|
||||
const { fileId, openDetails, openFile } = useRouteParameters()
|
||||
|
||||
const isMimeAvailable = computed(() => {
|
||||
if (!userConfigStore.userConfig.show_mime_column) {
|
||||
return false
|
||||
}
|
||||
if (!isWide.value) {
|
||||
return false // only show on wide screens
|
||||
}
|
||||
return props.nodes
|
||||
.some((node: INode) => node.mime !== undefined || node.mime !== 'application/octet-stream')
|
||||
})
|
||||
|
||||
const isMtimeAvailable = computed(() => {
|
||||
// Hide mtime column on narrow screens
|
||||
if (isNarrow.value) {
|
||||
return false // hide on narrow screens
|
||||
}
|
||||
return props.nodes.some((node: INode) => node.mtime !== undefined)
|
||||
})
|
||||
|
||||
const isSizeAvailable = computed(() => {
|
||||
// Hide size column on narrow screens
|
||||
if (isNarrow.value) {
|
||||
return false // hide on narrow screens
|
||||
}
|
||||
return props.nodes.some((node: INode) => node.size !== undefined)
|
||||
})
|
||||
|
||||
return {
|
||||
fileId,
|
||||
fileListWidth,
|
||||
headers: useFileListHeaders(),
|
||||
isSizeAvailable,
|
||||
isMtimeAvailable,
|
||||
isMimeAvailable,
|
||||
openDetails,
|
||||
openFile,
|
||||
|
||||
|
|
@ -170,33 +197,6 @@ export default defineComponent({
|
|||
return this.userConfigStore.userConfig
|
||||
},
|
||||
|
||||
isMimeAvailable() {
|
||||
if (!this.userConfig.show_mime_column) {
|
||||
return false
|
||||
}
|
||||
// Hide mime column on narrow screens
|
||||
if (this.fileListWidth < 1024) {
|
||||
return false
|
||||
}
|
||||
return this.nodes.some((node) => node.mime !== undefined || node.mime !== 'application/octet-stream')
|
||||
},
|
||||
|
||||
isMtimeAvailable() {
|
||||
// Hide mtime column on narrow screens
|
||||
if (this.fileListWidth < 768) {
|
||||
return false
|
||||
}
|
||||
return this.nodes.some((node) => node.mtime !== undefined)
|
||||
},
|
||||
|
||||
isSizeAvailable() {
|
||||
// Hide size column on narrow screens
|
||||
if (this.fileListWidth < 768) {
|
||||
return false
|
||||
}
|
||||
return this.nodes.some((node) => node.size !== undefined)
|
||||
},
|
||||
|
||||
cantUpload() {
|
||||
return this.currentFolder && (this.currentFolder.permissions & Permission.CREATE) === 0
|
||||
},
|
||||
|
|
@ -312,7 +312,7 @@ export default defineComponent({
|
|||
openSidebarForFile(fileId) {
|
||||
// Open the sidebar for the given URL fileid
|
||||
// iif we just loaded the app.
|
||||
const node = this.nodes.find((n) => n.fileid === fileId) as NcNode
|
||||
const node = this.nodes.find((n) => n.fileid === fileId) as INode
|
||||
if (node && this.sidebar.available) {
|
||||
logger.debug('Opening sidebar on file ' + node.path, { node })
|
||||
this.sidebar.open(node)
|
||||
|
|
@ -355,7 +355,7 @@ export default defineComponent({
|
|||
* @param fileId File to open
|
||||
*/
|
||||
async handleOpenFile(fileId: number) {
|
||||
const node = this.nodes.find((n) => n.fileid === fileId) as NcNode
|
||||
const node = this.nodes.find((n) => n.fileid === fileId) as INode
|
||||
if (node === undefined) {
|
||||
return
|
||||
}
|
||||
|
|
@ -445,7 +445,7 @@ export default defineComponent({
|
|||
const index = event.key === 'ArrowUp' || event.key === 'ArrowLeft'
|
||||
? this.nodes.length - 1
|
||||
: 0
|
||||
this.setActiveNode(this.nodes[index] as NcNode & { fileid: number })
|
||||
this.setActiveNode(this.nodes[index] as INode & { fileid: number })
|
||||
}
|
||||
|
||||
const index = this.nodes.findIndex((node) => node.fileid === this.fileId) ?? 0
|
||||
|
|
@ -481,7 +481,7 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
|
||||
async setActiveNode(node: NcNode & { fileid: number }) {
|
||||
async setActiveNode(node: INode & { fileid: number }) {
|
||||
logger.debug('Navigating to file ' + node.path, { node, fileid: node.fileid })
|
||||
this.scrollToFile(node.fileid)
|
||||
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
setup() {
|
||||
const fileListWidth = useFileListWidth()
|
||||
const { width: fileListWidth } = useFileListWidth()
|
||||
|
||||
return {
|
||||
fileListWidth,
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ async function getFileList() {
|
|||
template: '<div data-testid="component" style="width: 100%;background: white;">{{ fileListWidth }}</div>',
|
||||
setup() {
|
||||
return {
|
||||
fileListWidth: useFileListWidth(),
|
||||
fileListWidth: useFileListWidth().width,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,9 +2,8 @@
|
|||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
import { onMounted, readonly, ref } from 'vue'
|
||||
import { computed, onMounted, readonly, ref } from 'vue'
|
||||
|
||||
/** The element we observe */
|
||||
let element: HTMLElement | undefined
|
||||
|
|
@ -12,13 +11,22 @@ let element: HTMLElement | undefined
|
|||
/** The current width of the element */
|
||||
const width = ref(0)
|
||||
|
||||
const observer = new ResizeObserver((elements) => {
|
||||
if (elements[0].contentBoxSize) {
|
||||
const isWide = computed(() => width.value >= 1024)
|
||||
const isMedium = computed(() => width.value >= 512 && width.value < 1024)
|
||||
const isNarrow = computed(() => width.value < 512)
|
||||
|
||||
const observer = new ResizeObserver(([element]) => {
|
||||
if (!element) {
|
||||
return
|
||||
}
|
||||
|
||||
const contentBoxSize = element.contentBoxSize?.[0]
|
||||
if (contentBoxSize) {
|
||||
// use the newer `contentBoxSize` property if available
|
||||
width.value = elements[0].contentBoxSize[0].inlineSize
|
||||
width.value = contentBoxSize.inlineSize
|
||||
} else {
|
||||
// fall back to `contentRect`
|
||||
width.value = elements[0].contentRect.width
|
||||
width.value = element.contentRect.width
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -41,11 +49,17 @@ function updateObserver() {
|
|||
/**
|
||||
* Get the reactive width of the file list
|
||||
*/
|
||||
export function useFileListWidth(): Readonly<Ref<number>> {
|
||||
export function useFileListWidth() {
|
||||
// Update the observer when the component is mounted (e.g. because this is the files app)
|
||||
onMounted(updateObserver)
|
||||
// Update the observer also in setup context, so we already have an initial value
|
||||
updateObserver()
|
||||
|
||||
return readonly(width)
|
||||
return {
|
||||
width: readonly(width),
|
||||
|
||||
isWide,
|
||||
isMedium,
|
||||
isNarrow,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<template #actions>
|
||||
<!-- Sharing button -->
|
||||
<NcButton
|
||||
v-if="canShare && fileListWidth >= 512"
|
||||
v-if="canShare && !isNarrow"
|
||||
:aria-label="shareButtonLabel"
|
||||
:class="{ 'files-list__header-share-button--shared': shareButtonType }"
|
||||
:title="shareButtonLabel"
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
<UploadPicker
|
||||
v-if="canUpload && !isQuotaExceeded && currentFolder"
|
||||
allow-folders
|
||||
:no-label="fileListWidth <= 511"
|
||||
:no-label="isNarrow"
|
||||
class="files-list__header-upload-button"
|
||||
:content="getContent"
|
||||
:destination="currentFolder"
|
||||
|
|
@ -259,7 +259,7 @@ export default defineComponent({
|
|||
const userConfigStore = useUserConfigStore()
|
||||
const viewConfigStore = useViewConfigStore()
|
||||
|
||||
const fileListWidth = useFileListWidth()
|
||||
const { isNarrow } = useFileListWidth()
|
||||
const { directory, fileId } = useRouteParameters()
|
||||
|
||||
const enableGridView = (loadState('core', 'config', [])['enable_non-accessible_features'] ?? true)
|
||||
|
|
@ -271,7 +271,7 @@ export default defineComponent({
|
|||
currentView,
|
||||
directory,
|
||||
fileId,
|
||||
fileListWidth,
|
||||
isNarrow,
|
||||
t,
|
||||
|
||||
sidebar,
|
||||
|
|
@ -848,7 +848,7 @@ export default defineComponent({
|
|||
max-width: 100%;
|
||||
// Align with the navigation toggle icon
|
||||
margin-block: var(--app-navigation-padding, 4px);
|
||||
margin-inline: calc(var(--default-clickable-area, 44px) + 2 * var(--app-navigation-padding, 4px)) var(--app-navigation-padding, 4px);
|
||||
margin-inline: calc(var(--default-clickable-area) + 2 * var(--app-navigation-padding, 4px)) var(--app-navigation-padding, 4px);
|
||||
|
||||
&--public {
|
||||
// There is no navigation toggle on public shares
|
||||
|
|
|
|||
Loading…
Reference in a new issue