Skip to content

Commit

Permalink
feat: unstick topbar with limited vertical space
Browse files Browse the repository at this point in the history
Unsticks the top bar above tables as well as the table headers with limited vertical screen space. This way, we prevent those elements from overflowing content below.
  • Loading branch information
Jannik Stehle committed Aug 12, 2024
1 parent 5dd54df commit e96da17
Show file tree
Hide file tree
Showing 14 changed files with 96 additions and 25 deletions.
6 changes: 6 additions & 0 deletions changelog/unreleased/enhancement-unstick-top-bar
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Unstick top bar

The top bar above tables as well as the table headers now lose their "stickiness" with limited vertical screen space. This way, we prevent those elements from overflowing content below.

https://github.com/owncloud/web/pull/11344
https://github.com/owncloud/web/issues/10728
21 changes: 17 additions & 4 deletions packages/web-app-admin-settings/src/components/AppTemplate.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
<app-loading-spinner v-if="loading" />
<template v-else>
<div id="admin-settings-wrapper" class="oc-width-expand oc-height-1-1 oc-position-relative">
<div id="admin-settings-app-bar" ref="appBarRef" class="oc-app-bar oc-py-s">
<div
id="admin-settings-app-bar"
ref="appBarRef"
class="oc-app-bar oc-py-s"
:class="{ 'admin-settings-app-bar-sticky': isSticky }"
>
<div class="admin-settings-app-bar-controls oc-flex oc-flex-between oc-flex-middle">
<oc-breadcrumb
v-if="!isMobileWidth"
Expand Down Expand Up @@ -68,7 +73,8 @@ import {
SideBar,
BatchActions,
SideBarPanelContext,
Action
Action,
useIsTopBarSticky
} from '@ownclouders/web-pkg'
import {
defineComponent,
Expand Down Expand Up @@ -159,6 +165,8 @@ export default defineComponent({
setup(props) {
const appBarRef = ref<VNodeRef>()
const limitedScreenSpace = ref(false)
const { isSticky } = useIsTopBarSticky()
const onResize = () => {
limitedScreenSpace.value = props.isSideBarOpen
? window.innerWidth <= 1600
Expand Down Expand Up @@ -199,7 +207,8 @@ export default defineComponent({
applicationId: 'admin-settings'
}),
perPageDefault,
paginationOptions
paginationOptions,
isSticky
}
}
})
Expand All @@ -215,9 +224,13 @@ export default defineComponent({
border-top-right-radius: 15px;
box-sizing: border-box;
z-index: 2;
position: sticky;
position: inherit;
padding: 0 var(--oc-space-medium);
top: 0;
&.admin-settings-app-bar-sticky {
position: sticky;
}
}
.admin-settings-app-bar-controls {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
:fields="fields"
:data="paginatedItems"
:highlighted="highlighted"
:sticky="true"
:sticky="isSticky"
:header-position="fileListHeaderY"
:hover="true"
@sort="handleSort"
Expand Down Expand Up @@ -125,6 +125,7 @@ import {
displayPositionedDropdown,
eventBus,
SortDir,
useIsTopBarSticky,
useKeyboardActions,
useRoute,
useRouter
Expand Down Expand Up @@ -157,6 +158,7 @@ export default defineComponent({
const filterTerm = ref('')
const router = useRouter()
const route = useRoute()
const { isSticky } = useIsTopBarSticky()
const lastSelectedGroupIndex = ref(0)
const lastSelectedGroupId = ref(null)
Expand Down Expand Up @@ -351,7 +353,8 @@ export default defineComponent({
unselectAllGroups,
selectGroups,
selectGroup,
groups
groups,
isSticky
}
},
computed: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
:fields="fields"
:data="paginatedItems"
:highlighted="highlighted"
:sticky="true"
:sticky="isSticky"
:header-position="fileListHeaderY"
:hover="true"
@sort="handleSort"
Expand Down Expand Up @@ -124,7 +124,8 @@ import {
formatFileSize,
defaultFuseOptions,
useKeyboardActions,
ContextMenuBtnClickEventData
ContextMenuBtnClickEventData,
useIsTopBarSticky
} from '@ownclouders/web-pkg'
import {
ComponentPublicInstance,
Expand Down Expand Up @@ -163,6 +164,7 @@ export default defineComponent({
const route = useRoute()
const language = useGettext()
const { $gettext } = language
const { isSticky } = useIsTopBarSticky()
const { y: fileListHeaderY } = useFileListHeaderPosition('#admin-settings-app-bar')
const contextMenuButtonRef = ref(undefined)
Expand Down Expand Up @@ -535,7 +537,8 @@ export default defineComponent({
totalPages,
selectSpace,
selectSpaces,
unselectAllSpaces
unselectAllSpaces,
isSticky
}
},
methods: { $gettext }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
:fields="fields"
:data="paginatedItems"
:highlighted="highlighted"
:sticky="true"
:sticky="isSticky"
:header-position="fileListHeaderY"
:hover="true"
@sort="handleSort"
Expand Down Expand Up @@ -124,6 +124,7 @@ import {
eventBus,
queryItemAsString,
SortDir,
useIsTopBarSticky,
useKeyboardActions,
useRouteQuery
} from '@ownclouders/web-pkg'
Expand Down Expand Up @@ -157,6 +158,7 @@ export default defineComponent({
},
setup(props) {
const { $gettext } = useGettext()
const { isSticky } = useIsTopBarSticky()
const contextMenuButtonRef = ref(undefined)
const sortBy = ref('onPremisesSamAccountName')
Expand Down Expand Up @@ -366,7 +368,8 @@ export default defineComponent({
selectUser,
selectUsers,
unselectAllUsers,
users
users,
isSticky
}
},
computed: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
RouteLocation,
shallowMount
} from 'web-test-helpers'
import { eventBus, SideBar } from '@ownclouders/web-pkg'
import { eventBus, SideBar, useIsTopBarSticky } from '@ownclouders/web-pkg'
import { SideBarEventTopics } from '@ownclouders/web-pkg'
import { mock } from 'vitest-mock-extended'
import { OcBreadcrumb } from 'design-system/src/components'
Expand Down Expand Up @@ -111,6 +111,8 @@ describe('AppTemplate', () => {
})

function getWrapper({ props = {}, isMobileWidth = false } = {}) {
vi.mocked(useIsTopBarSticky).mockReturnValue({ isSticky: ref(true) })

return {
wrapper: shallowMount(AppTemplate, {
props: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exports[`Spaces view > loading states > should render spaces list after loading
"<div>
<main class="oc-flex oc-height-1-1 app-content oc-width-1-1">
<div id="admin-settings-wrapper" class="oc-width-expand oc-height-1-1 oc-position-relative">
<div id="admin-settings-app-bar" class="oc-app-bar oc-py-s">
<div id="admin-settings-app-bar" class="oc-app-bar oc-py-s admin-settings-app-bar-sticky">
<div class="admin-settings-app-bar-controls oc-flex oc-flex-between oc-flex-middle">
<oc-breadcrumb-stub items="[object Object],[object Object]" id="admin-settings-breadcrumb" variation="default" contextmenupadding="medium" maxwidth="-1" truncationoffset="2" showcontextactions="false" class="oc-flex oc-flex-middle"></oc-breadcrumb-stub>
<portal-target name="app.runtime.mobile.nav"></portal-target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exports[`Users view > list view > renders initially warning if filters are manda
"<div data-v-32efd9c6="">
<main data-v-32efd9c6="" class="oc-flex oc-height-1-1 app-content oc-width-1-1">
<div id="admin-settings-wrapper" class="oc-width-expand oc-height-1-1 oc-position-relative">
<div id="admin-settings-app-bar" class="oc-app-bar oc-py-s">
<div id="admin-settings-app-bar" class="oc-app-bar oc-py-s admin-settings-app-bar-sticky">
<div class="admin-settings-app-bar-controls oc-flex oc-flex-between oc-flex-middle">
<oc-breadcrumb-stub items="[object Object],[object Object]" id="admin-settings-breadcrumb" variation="default" contextmenupadding="medium" maxwidth="-1" truncationoffset="2" showcontextactions="false" class="oc-flex oc-flex-middle"></oc-breadcrumb-stub>
<portal-target name="app.runtime.mobile.nav"></portal-target>
Expand Down Expand Up @@ -52,7 +52,7 @@ exports[`Users view > list view > renders list initially 1`] = `
"<div data-v-32efd9c6="">
<main data-v-32efd9c6="" class="oc-flex oc-height-1-1 app-content oc-width-1-1">
<div id="admin-settings-wrapper" class="oc-width-expand oc-height-1-1 oc-position-relative">
<div id="admin-settings-app-bar" class="oc-app-bar oc-py-s">
<div id="admin-settings-app-bar" class="oc-app-bar oc-py-s admin-settings-app-bar-sticky">
<div class="admin-settings-app-bar-controls oc-flex oc-flex-between oc-flex-middle">
<oc-breadcrumb-stub items="[object Object],[object Object]" id="admin-settings-breadcrumb" variation="default" contextmenupadding="medium" maxwidth="-1" truncationoffset="2" showcontextactions="false" class="oc-flex oc-flex-middle"></oc-breadcrumb-stub>
<portal-target name="app.runtime.mobile.nav"></portal-target>
Expand Down
19 changes: 15 additions & 4 deletions packages/web-pkg/src/components/AppBar/AppBar.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<template>
<div id="files-app-bar" ref="filesAppBar" :class="{ 'files-app-bar-squashed': isSideBarOpen }">
<div
id="files-app-bar"
ref="filesAppBar"
:class="{ 'files-app-bar-squashed': isSideBarOpen, 'files-app-bar-sticky': isSticky }"
>
<div class="files-topbar oc-py-s">
<h1 class="oc-invisible-sr" v-text="pageTitle" />
<oc-hidden-announcer :announcement="selectedResourcesAnnouncement" level="polite" />
Expand Down Expand Up @@ -93,7 +97,8 @@ import {
useRouter,
FolderViewModeConstants,
useExtensionRegistry,
ActionExtension
ActionExtension,
useIsTopBarSticky
} from '../../composables'
import { BreadcrumbItem } from 'design-system/src/components/OcBreadcrumb/types'
import { useActiveLocation } from '../../composables'
Expand Down Expand Up @@ -154,6 +159,7 @@ export default defineComponent({
const { can } = useAbility()
const router = useRouter()
const { requestExtensions } = useExtensionRegistry()
const { isSticky } = useIsTopBarSticky()
const resourcesStore = useResourcesStore()
const { selectedResources } = storeToRefs(resourcesStore)
Expand Down Expand Up @@ -275,7 +281,8 @@ export default defineComponent({
breadcrumbTruncationOffset,
fileDroppedBreadcrumb,
pageTitle,
selectedResources
selectedResources,
isSticky
}
},
data: function () {
Expand Down Expand Up @@ -346,10 +353,14 @@ export default defineComponent({
border-top-right-radius: 15px;
box-sizing: border-box;
z-index: 2;
position: sticky;
position: inherit;
padding: 0 var(--oc-space-medium);
top: 0;
&.files-app-bar-sticky {
position: sticky;
}
.files-app-bar-controls {
min-height: 52px;
Expand Down
9 changes: 6 additions & 3 deletions packages/web-pkg/src/components/FilesList/ResourceTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
:fields="fields"
:highlighted="selectedIds"
:disabled="disabledResources"
:sticky="true"
:sticky="isSticky"
:header-position="headerPosition"
:drag-drop="dragDrop"
:hover="hover"
Expand Down Expand Up @@ -274,7 +274,8 @@ import {
useResourcesStore,
useRouter,
useCanBeOpenedWithSecureView,
useFileActions
useFileActions,
useIsTopBarSticky
} from '../../composables'
import ResourceListItem from './ResourceListItem.vue'
import ResourceGhostElement from './ResourceGhostElement.vue'
Expand Down Expand Up @@ -529,6 +530,7 @@ export default defineComponent({
const { getMatchingSpace } = useGetMatchingSpace()
const { canBeOpenedWithSecureView } = useCanBeOpenedWithSecureView()
const { getFolderLink } = useFolderLink()
const { isSticky } = useIsTopBarSticky()
const {
isLocationPicker,
isFilePicker,
Expand Down Expand Up @@ -670,7 +672,8 @@ export default defineComponent({
areFileExtensionsShown,
latestSelectedId,
isResourceClickable,
getResourceLink
getResourceLink,
isSticky
}
},
data() {
Expand Down
1 change: 1 addition & 0 deletions packages/web-pkg/src/composables/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from './eventBus'
export * from './fileListHeaderPosition'
export * from './filesList'
export * from './folderLink'
export * from './isTopBarSticky'
export * from './keyboardActions'
export * from './links'
export * from './loadingService'
Expand Down
1 change: 1 addition & 0 deletions packages/web-pkg/src/composables/isTopBarSticky/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useIsTopBarSticky'
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ref, onMounted, onBeforeUnmount } from 'vue'

/**
* Determines if the topbar (including table headers) should be sticky or not.
* With a vertical height less than 500px, the topbar should not be sticky because
* it takes up too much space and overflows content.
*/
export const useIsTopBarSticky = () => {
const isSticky = ref(true)

const setIsSticky = () => {
isSticky.value = window.innerHeight > 500
}

onMounted(() => {
setIsSticky()
window.addEventListener('resize', setIsSticky)
})

onBeforeUnmount(() => {
window.removeEventListener('resize', setIsSticky)
})

return { isSticky }
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`AppBar component > renders > by default no breadcrumbs, no bulkactions, no sharesnavigation but viewoptions and sidebartoggle 1`] = `
"<div data-v-aba8ddeb="" id="files-app-bar" class="">
"<div data-v-aba8ddeb="" id="files-app-bar" class="files-app-bar-sticky">
<div data-v-aba8ddeb="" class="files-topbar oc-py-s">
<h1 data-v-aba8ddeb="" class="oc-invisible-sr">ExampleTitle</h1>
<oc-hidden-announcer-stub data-v-aba8ddeb="" announcement="No items selected." level="polite"></oc-hidden-announcer-stub>
Expand All @@ -23,7 +23,7 @@ exports[`AppBar component > renders > by default no breadcrumbs, no bulkactions,
`;

exports[`AppBar component > renders > if given, with content in the actions slot 1`] = `
"<div data-v-aba8ddeb="" id="files-app-bar" class="">
"<div data-v-aba8ddeb="" id="files-app-bar" class="files-app-bar-sticky">
<div data-v-aba8ddeb="" class="files-topbar oc-py-s">
<h1 data-v-aba8ddeb="" class="oc-invisible-sr">ExampleTitle</h1>
<oc-hidden-announcer-stub data-v-aba8ddeb="" announcement="No items selected." level="polite"></oc-hidden-announcer-stub>
Expand All @@ -45,7 +45,7 @@ exports[`AppBar component > renders > if given, with content in the actions slot
`;

exports[`AppBar component > renders > if given, with content in the content slot 1`] = `
"<div data-v-aba8ddeb="" id="files-app-bar" class="">
"<div data-v-aba8ddeb="" id="files-app-bar" class="files-app-bar-sticky">
<div data-v-aba8ddeb="" class="files-topbar oc-py-s">
<h1 data-v-aba8ddeb="" class="oc-invisible-sr">ExampleTitle</h1>
<oc-hidden-announcer-stub data-v-aba8ddeb="" announcement="No items selected." level="polite"></oc-hidden-announcer-stub>
Expand Down

0 comments on commit e96da17

Please sign in to comment.