Skip to content
Merged
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
2 changes: 0 additions & 2 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,6 @@ onUnmounted(() => {
.app-content {
display: flex;
flex-direction: column;
padding: 0px 8px;
row-gap: 8px;

.clamped {
display: -webkit-box !important;
Expand Down
3 changes: 1 addition & 2 deletions src/components/Base/modules/HeaderBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ function toggleClamp() {
}

.header_bar {
margin-inline: -8px;
padding-inline: 56px 8px;
background-color: var(--color-main-background);
transition: all var(--animation-slow) linear;
Expand Down Expand Up @@ -88,7 +87,7 @@ function toggleClamp() {
}

.header_bar_bottom {
margin-bottom: 1rem;
padding-bottom: 1rem;
}

[class*='bar_'] {
Expand Down
28 changes: 25 additions & 3 deletions src/components/Base/modules/IntersectionObserver.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@ import { onBeforeUnmount, onMounted, ref } from 'vue'
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'

// const model = ref(false)
interface Props {
orientation?: 'horizontal' | 'vertical'
loading?: boolean
}
const { orientation = 'horizontal', loading = false } = defineProps<Props>()

const model = defineModel<boolean>()

const observer = ref<null | IntersectionObserver>(null)

const observerTarget = ref<null | Element>(null)
const emit = defineEmits(['visible', 'invisible'])

const { loading = false } = defineProps<{ loading?: boolean }>()

onMounted(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
Expand All @@ -41,8 +45,26 @@ onBeforeUnmount(() => {
</script>

<template>
<div ref="observerTarget">
<div
ref="observerTarget"
:class="{
'horizontal-fixed': orientation === 'horizontal',
'vertical-fixed': orientation === 'vertical',
}">
<NcLoadingIcon v-if="loading" :size="15" />
<slot v-else :in-viewport="model" />
</div>
</template>

<style lang="css" scoped>
.vertical-fixed {
position: sticky;
top: 0;
height: 100%;
}
.horizontal-fixed {
position: sticky;
left: 0;
width: 100%;
}
</style>
45 changes: 34 additions & 11 deletions src/components/Base/modules/StickyDiv.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,48 @@
import { computed } from 'vue'

interface Props {
stickyTop?: boolean
stickyLeft?: boolean
activateBottomShadow?: boolean
activateRightShadow?: boolean
stickyTop?: boolean
stickyLeft?: boolean
zIndex?: number
}

const {
stickyTop = false,
stickyLeft = false,
activateBottomShadow = false,
activateRightShadow = false,
stickyTop = false,
stickyLeft = false,
zIndex = undefined,
} = defineProps<Props>()

const style = computed(() => {
if (zIndex !== undefined && zIndex !== null) {
return {
'z-index': zIndex,
}
}
if (stickyTop && stickyLeft) {
return {
'z-index': 6,
}
}

if (stickyLeft) {
return {
'z-index': 5,
}
}

if (stickyTop) {
return {
'z-index': 4,
}
}

return {}
})

const stickyClass = computed(() => ({
container: true,
'sticky-top': stickyTop,
Expand All @@ -30,7 +59,7 @@ const stickyClass = computed(() => ({
</script>

<template>
<div :class="stickyClass">
<div :class="stickyClass" :style="style">
<slot name="default">
<div class="inner"></div>
</slot>
Expand All @@ -51,14 +80,12 @@ const stickyClass = computed(() => ({
.sticky-left {
position: sticky;
left: 0;
z-index: 5;
}

.sticky-top {
--shadow-height: 10px;
position: sticky;
top: 0;
z-index: 4;
padding-bottom: 0px;
padding-bottom: var(--shadow-height);

Expand Down Expand Up @@ -89,10 +116,6 @@ const stickyClass = computed(() => ({
}
}

.sticky-top.sticky-left {
z-index: 7;
}

/* TODO: Implement sticky right shadow
An Alternative could be using a grid instead of ::after
to be able to position multiple shadows in all directions */
Expand Down
4 changes: 3 additions & 1 deletion src/components/VoteTable/VoteColumn.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ import OptionItem from '../Options/OptionItem.vue'
import VoteItem from './VoteItem.vue'
import CalendarPeek from '../Calendar/CalendarPeek.vue'
import { usePollStore } from '../../stores/poll.ts'
import { useVotesStore } from '../../stores/votes.ts'
import { usePreferencesStore } from '../../stores/preferences.ts'
import { Option } from '../../stores/options.ts'
import OptionMenu from '../Options/OptionMenu.vue'

const { option } = defineProps<{ option: Option }>()

const pollStore = usePollStore()
const votesStore = useVotesStore()
const preferencesStore = usePreferencesStore()

const componentClass = computed(() => {
Expand Down Expand Up @@ -65,7 +67,7 @@ const showCalendarPeek = computed(
</div>

<VoteItem
v-for="participant in pollStore.safeParticipants"
v-for="participant in votesStore.getChunkedParticipants"
:key="participant.id"
:user="participant"
:option="option" />
Expand Down
37 changes: 23 additions & 14 deletions src/components/VoteTable/VoteTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const { downPage = false } = defineProps<{ downPage: boolean }>()
const chunksLoading = ref(false)

const tableStyle = computed(() => ({
'--participants-count': `${pollStore.safeParticipants.length}`,
'--participants-count': `${votesStore.getChunkedParticipants.length}`,
'--options-count': `${optionsStore.options.length}`,
}))

Expand Down Expand Up @@ -73,7 +73,7 @@ function isVotable(participant: User, option: Option) {
class="vote-table"
:style="tableStyle">
<StickyDiv
v-if="pollStore.viewMode === 'table-view'"
v-show="pollStore.viewMode === 'table-view'"
key="grid-info"
sticky-left
class="grid-info">
Expand All @@ -90,7 +90,7 @@ function isVotable(participant: User, option: Option) {
</StickyDiv>

<StickyDiv
v-if="pollStore.viewMode === 'table-view'"
v-show="pollStore.viewMode === 'table-view'"
:id="`option-item-spacer`"
class="option-item-spacer"
sticky-top
Expand All @@ -100,19 +100,22 @@ function isVotable(participant: User, option: Option) {

<StickyDiv
v-if="pollStore.permissions.seeResults"
v-show="pollStore.viewMode === 'table-view'"
sticky-left
class="counter-spacer" />

<StickyDiv
v-for="participant in pollStore.safeParticipants"
v-for="participant in votesStore.getChunkedParticipants"
:key="participant.id"
class="participant"
sticky-left>
<VoteParticipant :user="participant" />
</StickyDiv>

<template v-for="option in optionsStore.orderedOptions" :key="option.id">
<div v-if="pollStore.viewMode === 'table-view'" class="option-menu-grid">
<div
v-show="pollStore.viewMode === 'table-view'"
class="option-menu-grid">
<CalendarPeek
v-if="showCalendarPeek"
:id="`peek-${option.id}`"
Expand All @@ -131,7 +134,7 @@ function isVotable(participant: User, option: Option) {
<StickyDiv
:id="`option-item-${option.id}`"
class="option-item"
sticky-top
:sticky-top="pollStore.viewMode === 'table-view'"
:activate-bottom-shadow="!downPage">
<OptionItem :option="option" />
</StickyDiv>
Expand All @@ -144,7 +147,7 @@ function isVotable(participant: User, option: Option) {
:option="option" />

<div
v-for="participant in pollStore.safeParticipants"
v-for="participant in votesStore.getChunkedParticipants"
:key="participant.id"
class="vote-cell"
:class="{ 'current-user': isCurrentUser(participant) }">
Expand Down Expand Up @@ -175,6 +178,7 @@ function isVotable(participant: User, option: Option) {
grid-auto-rows: auto;
grid-auto-flow: column;
overflow: scroll;
margin: auto;

.vote-cell {
padding: 0.4rem;
Expand All @@ -192,6 +196,11 @@ function isVotable(participant: User, option: Option) {
visibility: hidden;
}

&.sticky-left {
left: -8px;
padding-left: 8px;
}

&:hover {
background: var(--color-background-hover);

Expand Down Expand Up @@ -223,7 +232,6 @@ function isVotable(participant: User, option: Option) {
overflow: visible;
min-width: min-content;
max-width: max-content;
margin: auto;
.grid-info {
grid-row: 1;
grid-column: 1;
Expand Down Expand Up @@ -295,14 +303,15 @@ function isVotable(participant: User, option: Option) {
}

&.list-view {
grid-template-columns: auto 5rem 5rem;
row-gap: 8px;
grid-template-columns:
minmax(11rem, max-content)
minmax(4rem, max-content)
minmax(4rem, max-content);
max-width: var(--cap-width);
width: fit-content;

.grid-info,
.option-spacer,
.counter-spacer,
.participant,
.option-menu-grid {
.participant {
display: none;
}

Expand Down
9 changes: 0 additions & 9 deletions src/stores/poll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,15 +263,6 @@ export const usePollStore = defineStore('poll', {
return [noString, 'yes']
},

safeParticipants(): User[] {
const sessionStore = useSessionStore()
const votesStore = useVotesStore()
if (this.viewMode === 'list-view') {
return [sessionStore.currentUser]
}
return votesStore.getChunkedParticipants
},

getProposalsOptions(): {
value: AllowProposals
label: string
Expand Down
6 changes: 6 additions & 0 deletions src/stores/votes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ export const useVotesStore = defineStore('votes', {
* @return
*/
getChunkedParticipants(state): User[] {
const sessionStore = useSessionStore()
const pollStore = usePollStore()
if (pollStore.viewMode === 'list-view') {
return [sessionStore.currentUser]
}

if (
this.participants.length > state.meta.chunks.size
&& this.participants.length
Expand Down
Loading