diff options
Diffstat (limited to 'apps/files/src/components')
12 files changed, 101 insertions, 39 deletions
diff --git a/apps/files/src/components/DragAndDropNotice.vue b/apps/files/src/components/DragAndDropNotice.vue index 38d07c94d80..c7684d5c205 100644 --- a/apps/files/src/components/DragAndDropNotice.vue +++ b/apps/files/src/components/DragAndDropNotice.vue @@ -235,7 +235,7 @@ export default defineComponent({ justify-content: center; width: 100%; // Breadcrumbs height + row thead height - min-height: calc(58px + 55px); + min-height: calc(58px + 44px); margin: 0; user-select: none; color: var(--color-text-maxcontrast); diff --git a/apps/files/src/components/DragAndDropPreview.vue b/apps/files/src/components/DragAndDropPreview.vue index 7c9c6f4f1a7..72fd98d43fb 100644 --- a/apps/files/src/components/DragAndDropPreview.vue +++ b/apps/files/src/components/DragAndDropPreview.vue @@ -92,7 +92,7 @@ export default Vue.extend({ </script> <style lang="scss"> -$size: 32px; +$size: 28px; $stack-shift: 6px; .files-list-drag-image { @@ -102,24 +102,24 @@ $stack-shift: 6px; display: flex; overflow: hidden; align-items: center; - height: 44px; - padding: 6px 12px; + height: $size + $stack-shift; + padding: $stack-shift $stack-shift * 2; background: var(--color-main-background); &__icon, - .files-list__row-icon { + .files-list__row-icon-preview-container { display: flex; overflow: hidden; align-items: center; justify-content: center; - width: 32px; - height: 32px; + width: $size - $stack-shift; + height: $size - $stack-shift;; border-radius: var(--border-radius); } &__icon { overflow: visible; - margin-inline-end: 12px; + margin-inline-end: $stack-shift * 2; img { max-width: 100%; @@ -138,13 +138,15 @@ $stack-shift: 6px; display: flex; // Stack effect if more than one element - .files-list__row-icon + .files-list__row-icon { + // Max 3 elements + > .files-list__row-icon-preview-container + .files-list__row-icon-preview-container { margin-top: $stack-shift; - margin-inline-start: $stack-shift - $size; - & + .files-list__row-icon { + margin-inline-start: $stack-shift * 2 - $size; + & + .files-list__row-icon-preview-container { margin-top: $stack-shift * 2; } } + // If we have manually clone the preview, // let's hide any fallback icons &:not(:empty) + * { diff --git a/apps/files/src/components/FileEntry/FavoriteIcon.vue b/apps/files/src/components/FileEntry/FavoriteIcon.vue index 87684758b43..c66cb8fbd7f 100644 --- a/apps/files/src/components/FileEntry/FavoriteIcon.vue +++ b/apps/files/src/components/FileEntry/FavoriteIcon.vue @@ -56,8 +56,8 @@ export default defineComponent({ :deep() { svg { // We added a stroke for a11y so we must increase the size to include the stroke - width: 26px !important; - height: 26px !important; + width: 20px !important; + height: 20px !important; // Override NcIconSvgWrapper defaults of 20px max-width: unset !important; diff --git a/apps/files/src/components/FileEntry/FileEntryActions.vue b/apps/files/src/components/FileEntry/FileEntryActions.vue index ec111a1235d..5c537d878fe 100644 --- a/apps/files/src/components/FileEntry/FileEntryActions.vue +++ b/apps/files/src/components/FileEntry/FileEntryActions.vue @@ -25,15 +25,16 @@ :open="openedMenu" @close="onMenuClose" @closed="onMenuClosed"> - <!-- Default actions list--> - <NcActionButton v-for="action, index in enabledMenuActions" + <!-- Non-destructive actions list --> + <!-- Please keep this block in sync with the destructive actions block below --> + <NcActionButton v-for="action, index in renderedNonDestructiveActions" :key="action.id" :ref="`action-${action.id}`" class="files-list__row-action" :class="{ [`files-list__row-action-${action.id}`]: true, 'files-list__row-action--inline': index < enabledInlineActions.length, - 'files-list__row-action--menu': isValidMenu(action) + 'files-list__row-action--menu': isValidMenu(action), }" :close-after-click="!isValidMenu(action)" :data-cy-files-list-row-action="action.id" @@ -50,6 +51,35 @@ {{ actionDisplayName(action) }} </NcActionButton> + <!-- Destructive actions list --> + <template v-if="renderedDestructiveActions.length > 0"> + <NcActionSeparator /> + <NcActionButton v-for="action, index in renderedDestructiveActions" + :key="action.id" + :ref="`action-${action.id}`" + class="files-list__row-action" + :class="{ + [`files-list__row-action-${action.id}`]: true, + 'files-list__row-action--inline': index < enabledInlineActions.length, + 'files-list__row-action--menu': isValidMenu(action), + 'files-list__row-action--destructive': true, + }" + :close-after-click="!isValidMenu(action)" + :data-cy-files-list-row-action="action.id" + :is-menu="isValidMenu(action)" + :aria-label="action.title?.([source], currentView)" + :title="action.title?.([source], currentView)" + @click="onActionClick(action)"> + <template #icon> + <NcLoadingIcon v-if="isLoadingAction(action)" /> + <NcIconSvgWrapper v-else + class="files-list__row-action-icon" + :svg="action.iconSvgInline([source], currentView)" /> + </template> + {{ actionDisplayName(action) }} + </NcActionButton> + </template> + <!-- Submenu actions list--> <template v-if="openedSubmenu && enabledSubmenuActions[openedSubmenu?.id]"> <!-- Back to top-level button --> @@ -68,10 +98,11 @@ class="files-list__row-action--submenu" close-after-click :data-cy-files-list-row-action="action.id" + :aria-label="action.title?.([source], currentView)" :title="action.title?.([source], currentView)" @click="onActionClick(action)"> <template #icon> - <NcLoadingIcon v-if="isLoadingAction(action)" :size="18" /> + <NcLoadingIcon v-if="isLoadingAction(action)" /> <NcIconSvgWrapper v-else :svg="action.iconSvgInline([source], currentView)" /> </template> {{ actionDisplayName(action) }} @@ -211,6 +242,14 @@ export default defineComponent({ return actions.filter(action => !(action.parent && topActionsIds.includes(action.parent))) }, + renderedNonDestructiveActions() { + return this.enabledMenuActions.filter(action => !action.destructive) + }, + + renderedDestructiveActions() { + return this.enabledMenuActions.filter(action => action.destructive) + }, + openedMenu: { get() { return this.opened @@ -349,5 +388,12 @@ main.app-content[style*="mouse-pos-x"] .v-popper__popper { max-height: var(--max-icon-size) !important; max-width: var(--max-icon-size) !important; } + + &.files-list__row-action--destructive { + ::deep(button) { + color: var(--color-error) !important; + } + } } + </style> diff --git a/apps/files/src/components/FileEntry/FileEntryName.vue b/apps/files/src/components/FileEntry/FileEntryName.vue index 2fec9e5d556..418f9581eb6 100644 --- a/apps/files/src/components/FileEntry/FileEntryName.vue +++ b/apps/files/src/components/FileEntry/FileEntryName.vue @@ -30,7 +30,7 @@ <span class="files-list__row-name-text" dir="auto"> <!-- Keep the filename stuck to the extension to avoid whitespace rendering issues--> <span class="files-list__row-name-" v-text="basename" /> - <span class="files-list__row-name-ext" v-text="extension" /> + <span v-if="userConfigStore.userConfig.show_files_extensions" class="files-list__row-name-ext" v-text="extension" /> </span> </component> </template> @@ -46,11 +46,12 @@ import { defineComponent, inject } from 'vue' import NcTextField from '@nextcloud/vue/components/NcTextField' -import { useNavigation } from '../../composables/useNavigation' +import { getFilenameValidity } from '../../utils/filenameValidity.ts' import { useFileListWidth } from '../../composables/useFileListWidth.ts' -import { useRouteParameters } from '../../composables/useRouteParameters.ts' +import { useNavigation } from '../../composables/useNavigation.ts' import { useRenamingStore } from '../../store/renaming.ts' -import { getFilenameValidity } from '../../utils/filenameValidity.ts' +import { useRouteParameters } from '../../composables/useRouteParameters.ts' +import { useUserConfigStore } from '../../store/userconfig.ts' import logger from '../../logger.ts' export default defineComponent({ @@ -95,6 +96,7 @@ export default defineComponent({ const { directory } = useRouteParameters() const filesListWidth = useFileListWidth() const renamingStore = useRenamingStore() + const userConfigStore = useUserConfigStore() const defaultFileAction = inject<FileAction | undefined>('defaultFileAction') @@ -105,6 +107,7 @@ export default defineComponent({ filesListWidth, renamingStore, + userConfigStore, } }, diff --git a/apps/files/src/components/FileEntry/FileEntryPreview.vue b/apps/files/src/components/FileEntry/FileEntryPreview.vue index 506677b49af..3d0fffe7584 100644 --- a/apps/files/src/components/FileEntry/FileEntryPreview.vue +++ b/apps/files/src/components/FileEntry/FileEntryPreview.vue @@ -64,7 +64,7 @@ import FolderIcon from 'vue-material-design-icons/Folder.vue' import FolderOpenIcon from 'vue-material-design-icons/FolderOpen.vue' import KeyIcon from 'vue-material-design-icons/Key.vue' import LinkIcon from 'vue-material-design-icons/Link.vue' -import NetworkIcon from 'vue-material-design-icons/Network.vue' +import NetworkIcon from 'vue-material-design-icons/NetworkOutline.vue' import TagIcon from 'vue-material-design-icons/Tag.vue' import PlayCircleIcon from 'vue-material-design-icons/PlayCircle.vue' diff --git a/apps/files/src/components/FileListFilter/FileListFilterModified.vue b/apps/files/src/components/FileListFilter/FileListFilterModified.vue index f3a968dd56e..3a843b2bc3e 100644 --- a/apps/files/src/components/FileListFilter/FileListFilterModified.vue +++ b/apps/files/src/components/FileListFilter/FileListFilterModified.vue @@ -7,7 +7,7 @@ :filter-name="t('files', 'Modified')" @reset-filter="resetFilter"> <template #icon> - <NcIconSvgWrapper :path="mdiCalendarRange" /> + <NcIconSvgWrapper :path="mdiCalendarRangeOutline" /> </template> <NcActionButton v-for="preset of timePresets" :key="preset.id" @@ -25,7 +25,7 @@ import type { PropType } from 'vue' import type { ITimePreset } from '../../filters/ModifiedFilter.ts' -import { mdiCalendarRange } from '@mdi/js' +import { mdiCalendarRangeOutline } from '@mdi/js' import { translate as t } from '@nextcloud/l10n' import { defineComponent } from 'vue' @@ -50,7 +50,7 @@ export default defineComponent({ setup() { return { // icons used in template - mdiCalendarRange, + mdiCalendarRangeOutline, } }, diff --git a/apps/files/src/components/FileListFilter/FileListFilterType.vue b/apps/files/src/components/FileListFilter/FileListFilterType.vue index 53e46b48f8c..d3ad791513f 100644 --- a/apps/files/src/components/FileListFilter/FileListFilterType.vue +++ b/apps/files/src/components/FileListFilter/FileListFilterType.vue @@ -8,7 +8,7 @@ :filter-name="t('files', 'Type')" @reset-filter="resetFilter"> <template #icon> - <NcIconSvgWrapper :path="mdiFile" /> + <NcIconSvgWrapper :path="mdiFileOutline" /> </template> <NcActionButton v-for="fileType of typePresets" :key="fileType.id" @@ -27,7 +27,7 @@ import type { PropType } from 'vue' import type { ITypePreset } from '../../filters/TypeFilter.ts' -import { mdiFile } from '@mdi/js' +import { mdiFileOutline } from '@mdi/js' import { translate as t } from '@nextcloud/l10n' import { defineComponent } from 'vue' @@ -57,7 +57,7 @@ export default defineComponent({ setup() { return { - mdiFile, + mdiFileOutline, t, } }, diff --git a/apps/files/src/components/FilesListVirtual.vue b/apps/files/src/components/FilesListVirtual.vue index 04acbd302f5..47b8ef19b19 100644 --- a/apps/files/src/components/FilesListVirtual.vue +++ b/apps/files/src/components/FilesListVirtual.vue @@ -481,13 +481,13 @@ export default defineComponent({ <style scoped lang="scss"> .files-list { - --row-height: 55px; + --row-height: 44px; --cell-margin: 14px; --checkbox-padding: calc((var(--row-height) - var(--checkbox-size)) / 2); --checkbox-size: 24px; --clickable-area: var(--default-clickable-area); - --icon-preview-size: 32px; + --icon-preview-size: 24px; --fixed-block-start-position: var(--default-clickable-area); display: flex; @@ -775,8 +775,8 @@ export default defineComponent({ // File and folder overlay &-overlay { position: absolute; - max-height: calc(var(--icon-preview-size) * 0.5); - max-width: calc(var(--icon-preview-size) * 0.5); + max-height: calc(var(--icon-preview-size) * 0.6); + max-width: calc(var(--icon-preview-size) * 0.6); color: var(--color-primary-element-text); // better alignment with the folder icon margin-block-start: 2px; @@ -888,21 +888,21 @@ export default defineComponent({ } .files-list__row-size { - width: calc(var(--row-height) * 1.5); + width: calc(var(--row-height) * 2); // Right align content/text justify-content: flex-end; } .files-list__row-mtime { - width: calc(var(--row-height) * 2); + width: calc(var(--row-height) * 2.5); } .files-list__row-mime { - width: calc(var(--row-height) * 2.5); + width: calc(var(--row-height) * 3.5); } .files-list__row-column-custom { - width: calc(var(--row-height) * 2); + width: calc(var(--row-height) * 2.5); } } } diff --git a/apps/files/src/components/NavigationQuota.vue b/apps/files/src/components/NavigationQuota.vue index fd10af1c495..46c8e5c9af4 100644 --- a/apps/files/src/components/NavigationQuota.vue +++ b/apps/files/src/components/NavigationQuota.vue @@ -33,7 +33,7 @@ import { subscribe } from '@nextcloud/event-bus' import { translate } from '@nextcloud/l10n' import axios from '@nextcloud/axios' -import ChartPie from 'vue-material-design-icons/ChartPie.vue' +import ChartPie from 'vue-material-design-icons/ChartPieOutline.vue' import NcAppNavigationItem from '@nextcloud/vue/components/NcAppNavigationItem' import NcProgressBar from '@nextcloud/vue/components/NcProgressBar' diff --git a/apps/files/src/components/NewNodeDialog.vue b/apps/files/src/components/NewNodeDialog.vue index 76555db1536..ca10935940d 100644 --- a/apps/files/src/components/NewNodeDialog.vue +++ b/apps/files/src/components/NewNodeDialog.vue @@ -26,6 +26,11 @@ :helper-text="validity" :label="label" :value.sync="localDefaultName" /> + + <!-- Hidden file warning --> + <NcNoteCard v-if="isHiddenFileName" + type="warning" + :text="t('files', 'Files starting with a dot are hidden by default')" /> </form> </NcDialog> </template> @@ -35,12 +40,13 @@ import type { ComponentPublicInstance, PropType } from 'vue' import { getUniqueName } from '@nextcloud/files' import { t } from '@nextcloud/l10n' import { extname } from 'path' -import { nextTick, onMounted, ref, watch, watchEffect } from 'vue' +import { computed, nextTick, onMounted, ref, watch, watchEffect } from 'vue' import { getFilenameValidity } from '../utils/filenameValidity.ts' import NcButton from '@nextcloud/vue/components/NcButton' import NcDialog from '@nextcloud/vue/components/NcDialog' import NcTextField from '@nextcloud/vue/components/NcTextField' +import NcNoteCard from '@nextcloud/vue/components/NcNoteCard' const props = defineProps({ /** @@ -89,6 +95,11 @@ const nameInput = ref<ComponentPublicInstance>() const formElement = ref<HTMLFormElement>() const validity = ref('') +const isHiddenFileName = computed(() => { + // Check if the name starts with a dot, which indicates a hidden file + return localDefaultName.value.trim().startsWith('.') +}) + /** * Focus the filename input field */ diff --git a/apps/files/src/components/VirtualList.vue b/apps/files/src/components/VirtualList.vue index 4f9d8096580..4746fedf863 100644 --- a/apps/files/src/components/VirtualList.vue +++ b/apps/files/src/components/VirtualList.vue @@ -157,7 +157,7 @@ export default defineComponent({ itemHeight() { // Align with css in FilesListVirtual // 166px + 32px (name) + 16px (mtime) + 16px (padding top and bottom) - return this.gridMode ? (166 + 32 + 16 + 16 + 16) : 55 + return this.gridMode ? (166 + 32 + 16 + 16 + 16) : 44 }, // Grid mode only |