vue/src/components/strand/list.vue
<script lang="js">
import StrandList from '@/components/strand/list.vue';
import NewComment from '@/components/strand/item/new_comment.vue';
import NewDiscussion from '@/components/strand/item/new_discussion.vue';
import DiscussionEdited from '@/components/strand/item/discussion_edited.vue';
import PollEdited from '@/components/strand/item/poll_edited.vue';
import PollCreated from '@/components/strand/item/poll_created.vue';
import StanceCreated from '@/components/strand/item/stance_created.vue';
import StanceUpdated from '@/components/strand/item/stance_updated.vue';
import OutcomeCreated from '@/components/strand/item/outcome_created.vue';
import StrandItemRemoved from '@/components/strand/item/removed.vue';
import StrandLoadMore from '@/components/strand/load_more.vue';
import OtherKind from '@/components/strand/item/other_kind.vue';
import ReplyForm from '@/components/strand/reply_form.vue';
import RangeSet from '@/shared/services/range_set';
import EventBus from '@/shared/services/event_bus';
import { camelCase } from 'lodash-es';
export default {
name: 'strand-list',
props: {
loader: Object,
newestFirst: Boolean,
collection: {
type: Array,
required: true
}
},
components: {
NewDiscussion,
NewComment,
PollCreated,
StanceCreated,
StanceUpdated,
OutcomeCreated,
OtherKind,
StrandLoadMore,
DiscussionEdited,
PollEdited,
StrandItemRemoved,
ReplyForm
},
computed: {
directedCollection() {
if (this.newestFirst) {
return this.collection.reverse();
} else {
return this.collection;
}
}
},
methods: {
isFocused(event) {
return ((event.depth === 1) && (event.position === this.loader.focusAttrs.position)) ||
(event.positionKey === this.loader.focusAttrs.positionKey) ||
(event.sequenceId === this.loader.focusAttrs.sequenceId) ||
((event.eventableType === 'Comment') && (event.eventableId === this.loader.focusAttrs.commentId));
},
positionKeyPrefix(event) {
if (event.depth < 1) {
return event.positionKey.split('-').slice(0, event.depth - 1);
} else {
return null;
}
},
componentForKind(kind) {
return camelCase(['stance_created', 'stance_updated', 'discussion_edited', 'new_comment', 'outcome_created', 'poll_created', 'poll_edited', 'new_discussion'].includes(kind) ?
kind
:
'other_kind'
);
},
classes(event) {
if (!event) { return []; }
return ["lmo-action-dock-wrapper",
`positionKey-${event.positionKey}`,
`sequenceId-${event.sequenceId}`,
`position-${event.position}`];
}
}
};
</script>
<template lang="pug">
.strand-list
.strand-item(
v-for="obj in directedCollection"
:key="obj.event.id"
:class="{'strand-item--deep': obj.event.depth > 1}"
)
.strand-item__row(v-if="!newestFirst && obj.missingEarlierCount")
.strand-item__gutter
.strand-item__stem-wrapper
.strand-item__stem.strand-item__stem--broken
//- | top !newestFirst && obj.missingEarlierCount
strand-load-more(
v-observe-visibility="{once: true, callback: (isVisible, entry) => isVisible && loader.autoLoadBefore(obj)}"
:label="{path: 'common.action.count_more', args: {count: obj.missingEarlierCount}}"
@click="loader.loadBefore(obj.event)"
:loading="loader.loading == 'before'+obj.event.id")
.strand-item__row(v-if="newestFirst && obj.missingAfterCount")
.strand-item__gutter
.strand-item__stem-wrapper
.strand-item__stem.strand-item__stem--broken
//- | top newestFirst && obj.missingAfterCount
strand-load-more(
v-observe-visibility="{once: true, callback: (isVisible, entry) => isVisible && loader.autoLoadAfter(obj)}"
:label="{path: 'common.action.count_more', args: {count: obj.missingAfterCount}}"
@click="loader.loadAfter(obj.event)"
:loading="loader.loading == 'after'+obj.event.id")
.strand-item__row(v-if="!loader.collapsed[obj.event.id]")
.strand-item__gutter(v-if="obj.event.depth > 0")
.d-flex.justify-center
v-checkbox.thread-item__is-forking(
v-if="loader.discussion.forkedEventIds.length"
@change="obj.event.toggleForking()"
:disabled="obj.event.forkingDisabled()"
v-model="obj.event.isForking()"
)
template(v-else)
user-avatar(
:user="obj.event.actor()"
:size="(obj.event.depth > 1) ? 28 : 32"
no-link
)
.strand-item__stem-wrapper(@click.stop="loader.collapse(obj.event)")
.strand-item__stem(:class="{'strand-item__stem--unread': obj.isUnread, 'strand-item__stem--focused': isFocused(obj.event)}")
.strand-item__main(style="overflow: hidden")
//- div {{obj.event.kind}} {{obj.event.positionKey}} {{obj.event.sequenceId}} {{isFocused(obj.event)}} childCount{{obj.event.childCount}} chdrn {{obj.children.length}}
div(:class="classes(obj.event)" v-observe-visibility="{callback: (isVisible, entry) => loader.setVisible(isVisible, obj.event)}")
strand-item-removed(v-if="obj.eventable && obj.eventable.discardedAt" :event="obj.event" :eventable="obj.eventable")
component(v-else :is="componentForKind(obj.event.kind)" :event='obj.event' :eventable="obj.eventable")
.strand-list__children(v-if="obj.event.childCount && (!obj.eventable.isA('stance') || obj.eventable.poll().showResults())")
strand-load-more(
v-if="obj.children.length == 0"
v-observe-visibility="{once: true, callback: (isVisible, entry) => isVisible && loader.loadAfter(obj.event)}"
:label="{path: 'common.action.count_more', args: {count: obj.missingChildCount}}"
@click="loader.loadAfter(obj.event)"
:loading="loader.loading == 'children'+obj.event.id")
strand-list.flex-grow-1(:loader="loader" :collection="obj.children" :newest-first="obj.event.kind == 'new_discussion' && loader.discussion.newestFirst")
reply-form(:eventId="obj.event.id")
.strand-item__row(v-if="loader.collapsed[obj.event.id]")
.d-flex.align-center
.strand-item__circle.mr-2(v-if="loader.collapsed[obj.event.id]" @click.stop="loader.expand(obj.event)")
common-icon(name="mdi-unfold-more-horizontal")
strand-item-headline.text--secondary(:event="obj.event" :eventable="obj.eventable" collapsed)
.strand-item__row(v-if="newestFirst && obj.missingEarlierCount" )
//- | bottom newestFirst && obj.missingEarlierCount
strand-load-more(
v-observe-visibility="{once: true, callback: (isVisible, entry) => isVisible && loader.autoLoadBefore(obj)}"
:label="{path: 'common.action.count_more', args: {count: obj.missingEarlierCount}}"
@click="loader.loadBefore(obj.event)"
:loading="loader.loading == 'before'+obj.event.id")
.strand-item__row(v-if="!newestFirst && obj.missingAfterCount" )
//- | bottom !newestFirst && obj.missingAfterCount
strand-load-more(
v-observe-visibility="{once: true, callback: (isVisible, entry) => isVisible && loader.autoLoadAfter(obj)}"
:label="{path: 'common.action.count_more', args: {count: obj.missingAfterCount}}"
@click="loader.loadAfter(obj.event)"
:loading="loader.loading == 'after'+obj.event.id")
</template>
<style lang="sass">
.strand-item--deep
.strand-item__gutter
width: 28px
// margin-right: 4px
.strand-item__stem
margin-left: 14px
margin-right: 14px
.strand-item__circle
// margin: 4px 0
// padding: 4px 0
width: 28px
height: 28px
.strand-item__load-more
min-height: 28px
// not working
.strand-item__branch-container
.strand-item__branch
top: -17px!important
right: -2px
// height: 36px
// width: 36px
.strand-item__row
display: flex
padding-top: 4px
.strand-item__gutter
display: flex
flex-direction: column
width: 32px
// margin-right: 8px
.strand-item__gutter:hover
.strand-item__stem
background-color: #999
.strand-item__main
flex-grow: 1
padding-left: 8px
overflow: hidden
max-width: 100%
.strand-item__stem-wrapper
width: 32px
height: 100%
padding-top: 4px
padding-bottom: 4px
.strand-item__stem
width: 0
height: 100%
padding: 0 0.5px
background-color: #dadada
margin: 0px 16px
.strand-item__stem--broken
background-image: linear-gradient(0deg, #dadada 25%, #ffffff 25%, #ffffff 50%, #dadada 50%, #dadada 75%, #ffffff 75%, #ffffff 100%)
background-size: 16.00px 16.00px
// background-size: 24.00px 24.00px
// background-size: 32.00px 32.00px
background-repeat: repeat-y
.strand-item__stem--unread
background-color: var(--v-accent-lighten1)!important
.strand-item__stem--focused
background-color: var(--v-primary-darken1)!important
.strand-item__circle
display: flex
align-items: center
justify-content: center
width: 32px
height: 32px
border: 1px solid #dadada
border-radius: 100%
margin: 4px 0
.strand-item__circle:hover
background-color: #dadada
.strand-item__stem:hover
background-color: #dadada
.strand-item__branch-container
position: absolute
overflow: hidden
margin-right: 4px
.strand-item__branch
position: relative
float: left
top: -13px
border: 2px solid #dadada
right: -2px
height: 28px
border-radius: 64px
width: 35px
margin-left: calc(50% - 1px)
border-style: solid
</style>