Initial commit
This commit is contained in:
@@ -0,0 +1,325 @@
|
||||
<template>
|
||||
<a :href="vizUrl"
|
||||
target="_blank"
|
||||
class="row"
|
||||
:class="{
|
||||
'row--selected': isSelected,
|
||||
'row--quick-actions-open': areQuickActionsOpen,
|
||||
'row--no-hover': !activeHover,
|
||||
'row--can-hover': canHover
|
||||
}"
|
||||
@click="onClick">
|
||||
|
||||
<div class="viz-column--main-info">
|
||||
<div class="cell cell--thumbnail cell--first">
|
||||
<div class="cell__media" :class="{'has-error': isThumbnailErrored}">
|
||||
<img class="cell__map-thumbnail" :src="mapThumbnailUrl" @error="onThumbnailError" v-if="!isThumbnailErrored"/>
|
||||
|
||||
<div class="MapCard-error" v-if="isThumbnailErrored"></div>
|
||||
</div>
|
||||
|
||||
<span class="checkbox cell__checkbox" @mouseover="mouseOverChildElement" @mouseleave="mouseOutChildElement">
|
||||
<input class="checkbox-input" :class="{'is-selected': isSelected }" @click.stop.prevent="toggleSelection($event)" type="checkbox">
|
||||
<span class="checkbox-decoration">
|
||||
<img svg-inline src="../../assets/icons/common/checkbox.svg">
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="cell cell--map-name cell--main">
|
||||
<div class="cell__title">
|
||||
<h3 class="text is-caption is-txtGrey u-ellipsis cell--map-name__text">
|
||||
{{ visualization.name }}
|
||||
</h3>
|
||||
|
||||
<span v-if="showInteractiveElements" class="cell__favorite" :class="{ 'is-favorite': visualization.liked }" @click.prevent="toggleFavorite" @mouseover="mouseOverChildElement" @mouseleave="mouseOutChildElement">
|
||||
<img svg-inline src="../../assets/icons/common/favorite.svg">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="metadata" v-if="hasTags || isSharedWithMe || isSharedWithColleagues">
|
||||
<div class="metadata__element" v-if="hasTags" @mouseover="mouseOverChildElement" @mouseleave="mouseOutChildElement">
|
||||
<img class="metadata__icon" src="../../assets/icons/common/tag.svg" width="14" height="14">
|
||||
|
||||
<ul class="metadata__tags" v-if="tagsChars <= maxTagsChars">
|
||||
<li v-for="(tag, index) in visualization.tags" :key="tag">
|
||||
<router-link :to="{ name: 'tagSearch', params: { tag } }" class="text is-small is-txtSoftGrey metadata__tag">{{ tag }}</router-link><span class="text is-small is-txtSoftGrey" v-if="!isLastTag(index)">, </span>
|
||||
</li>
|
||||
</ul>
|
||||
<FeaturesDropdown v-if="tagsChars > maxTagsChars" :list=visualization.tags linkRoute="tagSearch" feature="tag">
|
||||
<span class="metadata__tags-count text is-small is-txtSoftGrey">{{tagsLength}} {{$t(`DatasetCard.tags`)}}</span>
|
||||
</FeaturesDropdown>
|
||||
</div>
|
||||
|
||||
<div class="metadata__element" v-if="isSharedWithMe">
|
||||
<img class="metadata__icon" svg-inline src="../../assets/icons/common/user.svg">
|
||||
<span class="text is-small is-txtSoftGrey">{{visualization.permission.owner.username}}</span>
|
||||
</div>
|
||||
|
||||
<SharedBrief class="metadata__element u-ellipsis" v-if="isSharedWithColleagues && !isSharedWithMe" :colleagues="colleaguesSharedList" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="viz-column--extra-info">
|
||||
<div class="viz-column--status">
|
||||
<div class="cell cell--large">
|
||||
<span class="text is-small is-txtSoftGrey">{{ lastUpdated }}</span>
|
||||
</div>
|
||||
<div class="cell cell--large u-txt-right u-p--0 ">
|
||||
<span class="text is-small is-txtSoftGrey">{{ numberViews }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="viz-column--share">
|
||||
<div class="cell cell--small">
|
||||
<p class="text is-small is-txtSoftGrey">
|
||||
{{ $t(`MapCard.shared.${visualization.privacy}`) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="cell quick-actions cell--last" @mouseover="mouseOverChildElement" @mouseleave="mouseOutChildElement">
|
||||
<div class="quick-actions__placeholder" v-if="!showInteractiveElements || isSharedWithMe"></div>
|
||||
<MapQuickActions class="quick-actions__element" v-if="showInteractiveElements" :map="visualization" @open="openQuickActions" @close="closeQuickActions" @contentChanged="onContentChanged" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import computed from './shared/computed';
|
||||
import data from './shared/data';
|
||||
import FeaturesDropdown from 'new-dashboard/components/Dropdowns/FeaturesDropdown';
|
||||
import MapQuickActions from 'new-dashboard/components/QuickActions/MapQuickActions';
|
||||
import SharedBrief from 'new-dashboard/components/SharedBrief';
|
||||
import methods from './shared/methods';
|
||||
import props from './shared/props';
|
||||
|
||||
export default {
|
||||
name: 'CondensedMapCard',
|
||||
components: {
|
||||
MapQuickActions,
|
||||
FeaturesDropdown,
|
||||
SharedBrief
|
||||
},
|
||||
props,
|
||||
data () {
|
||||
return {
|
||||
...data(),
|
||||
thumbnailWidth: 144,
|
||||
thumbnailHeight: 144
|
||||
};
|
||||
},
|
||||
computed,
|
||||
methods: {
|
||||
...methods,
|
||||
onContentChanged (type) {
|
||||
this.$emit('contentChanged', type);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import 'new-dashboard/styles/variables';
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
padding: 0 14px;
|
||||
background-color: #FFF;
|
||||
|
||||
.cell--thumbnail {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-self: flex-start;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cell__map-thumbnail {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.cell__media {
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
overflow: hidden;
|
||||
transition: all 0.25s cubic-bezier(0.4, 0.01, 0.165, 0.99);
|
||||
border-radius: 2px;
|
||||
background: url($assetsDir + '/images/layout/default-map-bkg.png') no-repeat center 0;
|
||||
background-size: cover;
|
||||
|
||||
&.has-error {
|
||||
.MapCard-error {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cell__checkbox {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
transform: translateY(250%);
|
||||
transition: all 0.25s cubic-bezier(0.4, 0.01, 0.165, 0.99);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $softblue;
|
||||
text-decoration: none;
|
||||
|
||||
&:not(.row--no-hover) {
|
||||
.cell--map-name .cell--map-name__text {
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
.cell__title {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.cell__favorite {
|
||||
opacity: 1;
|
||||
|
||||
.favorite-icon {
|
||||
stroke: $text__color--secondary;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.favorite-icon {
|
||||
stroke: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.metadata__tags-count,
|
||||
.metadata__tag {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.cell__favorite {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
transform: translate3d(0, 2px, 0);
|
||||
opacity: 0;
|
||||
vertical-align: middle;
|
||||
|
||||
&.is-favorite {
|
||||
opacity: 1;
|
||||
|
||||
.favorite-icon {
|
||||
stroke: #FFC300;
|
||||
fill: #FFC300;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.favorite-icon {
|
||||
stroke: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cell--last {
|
||||
width: 38px;
|
||||
}
|
||||
|
||||
.quick-actions-placeholder {
|
||||
display: block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
&.row--selected {
|
||||
box-shadow: 0 0 0 1px $primary-color;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.row--selected {
|
||||
&.row--can-hover {
|
||||
.cell__media {
|
||||
transform: translateY(-100%);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.cell__checkbox {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.row--quick-actions-open,
|
||||
&:hover {
|
||||
.quick-actions {
|
||||
.quick-actions__element {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cell__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:hover + .metadata .metadata__tag {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.quick-actions {
|
||||
.quick-actions__placeholder {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.quick-actions__element {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.metadata {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 4px;
|
||||
|
||||
.metadata__element {
|
||||
margin-left: 16px;
|
||||
|
||||
&:first-of-type {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.metadata__icon,
|
||||
.features-dropdown,
|
||||
ul,
|
||||
li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.metadata__icon {
|
||||
margin-right: 4px;
|
||||
transform: translate(0, 2px);
|
||||
}
|
||||
|
||||
li {
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<div class="map-list-row">
|
||||
<div class="viz-column--main-info">
|
||||
<div class="cell cell--start">
|
||||
</div>
|
||||
<div class="cell cell--main" @click="changeOrder('name')">
|
||||
<span class="text is-small is-txtSoftGrey"
|
||||
:class="{
|
||||
'is-active': isOrderApplied('name'),
|
||||
'is-reversed': isReverseOrderApplied('name'),
|
||||
'element-sort': isSortable
|
||||
}">
|
||||
{{ $t(`MapListHeader.name`) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="viz-column--extra-info">
|
||||
<div class="viz-column--status">
|
||||
<div class="cell cell--large" @click="changeOrder('updated_at')">
|
||||
<span class="text is-small is-txtSoftGrey"
|
||||
:class="{
|
||||
'is-active': isOrderApplied('updated_at'),
|
||||
'is-reversed': isReverseOrderApplied('updated_at'),
|
||||
'element-sort': isSortable
|
||||
}">
|
||||
{{ $t(`MapListHeader.lastModified`) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="cell cell--large u-txt-right u-p--0 " @click="changeOrder('mapviews')">
|
||||
<span class="text is-small is-txtSoftGrey"
|
||||
:class="{
|
||||
'is-active': isOrderApplied('mapviews'),
|
||||
'is-reversed': isReverseOrderApplied('mapviews'),
|
||||
'element-sort': isSortable
|
||||
}">
|
||||
{{ $t(`MapListHeader.views`) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="viz-column--share">
|
||||
<div class="cell cell--small" @click="changeOrder('privacy')">
|
||||
<span class="text is-small is-txtSoftGrey"
|
||||
:class="{
|
||||
'is-active': isOrderApplied('privacy'),
|
||||
'is-reversed': isReverseOrderApplied('privacy'),
|
||||
'element-sort': isSortable
|
||||
}">
|
||||
{{ $t(`MapListHeader.privacy`) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="cell cell--end"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CondensedMapHeader',
|
||||
props: {
|
||||
order: String,
|
||||
orderDirection: String,
|
||||
isSortable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeOrder (order) {
|
||||
if (this.order === order) {
|
||||
return this.setOrder(
|
||||
order,
|
||||
this.getOppositeOrderDirection(this.orderDirection)
|
||||
);
|
||||
}
|
||||
|
||||
this.setOrder(order);
|
||||
},
|
||||
|
||||
getOppositeOrderDirection (order) {
|
||||
if (order === 'desc') {
|
||||
return 'asc';
|
||||
}
|
||||
|
||||
if (order === 'asc') {
|
||||
return 'desc';
|
||||
}
|
||||
},
|
||||
|
||||
isOrderApplied (order) {
|
||||
return order === this.order;
|
||||
},
|
||||
|
||||
isReverseOrderApplied (order) {
|
||||
return order === this.order && this.orderDirection === 'asc';
|
||||
},
|
||||
|
||||
setOrder (order, direction = 'desc') {
|
||||
this.$emit('orderChanged', { order, direction });
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import 'new-dashboard/styles/variables';
|
||||
|
||||
.map-list-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin-bottom: 1px;
|
||||
padding: 14px;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid $softblue;
|
||||
background-color: $white;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.cell--start {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-self: flex-start;
|
||||
width: 58px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.cell--end {
|
||||
width: 38px;
|
||||
}
|
||||
|
||||
.element-sort {
|
||||
&.is-active,
|
||||
&:hover {
|
||||
color: $text__color;
|
||||
cursor: pointer;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 14px;
|
||||
height: 100%;
|
||||
margin-left: 4px;
|
||||
transition: all 0.25s cubic-bezier(0.4, 0.01, 0.165, 0.99);
|
||||
background-image: url('../../assets/icons/datasets/chevron.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
&.is-reversed {
|
||||
&::after {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<component
|
||||
:is="componentType"
|
||||
:visualization="visualization"
|
||||
:isSelected="isSelected"
|
||||
:canHover="canHover"
|
||||
:selectMode="selectMode"
|
||||
:storeActionType="storeActionType"
|
||||
@toggleSelection="toggleSelection"
|
||||
@contentChanged="onContentChanged" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CondensedMapCard from './CondensedMapCard';
|
||||
import SimpleMapCard from './SimpleMapCard';
|
||||
import props from './shared/props';
|
||||
|
||||
export default {
|
||||
name: 'MapCard',
|
||||
props: {
|
||||
...props,
|
||||
condensed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
SimpleMapCard,
|
||||
CondensedMapCard
|
||||
},
|
||||
computed: {
|
||||
componentType () {
|
||||
return this.condensed ? 'CondensedMapCard' : 'SimpleMapCard';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleSelection ($event) {
|
||||
this.$emit('toggleSelection', $event);
|
||||
},
|
||||
onContentChanged (type) {
|
||||
this.$emit('contentChanged', type);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,476 @@
|
||||
<template>
|
||||
<a :href="vizUrl"
|
||||
target="_blank"
|
||||
class="card map-card"
|
||||
:class="{
|
||||
'card--selected': isSelected,
|
||||
'card--child-hover': !activeHover,
|
||||
'card--quick-actions-open': areQuickActionsOpen,
|
||||
'card--can-hover': canHover
|
||||
}"
|
||||
@click="onClick">
|
||||
<div class="card-media" :class="{'has-error': isThumbnailErrored}">
|
||||
<img :src="mapThumbnailUrl" @error="onThumbnailError" v-if="isMap && !isThumbnailErrored"/>
|
||||
|
||||
<div class="media-dataset" v-if="!isMap">
|
||||
<img svg-inline src="../../assets/icons/datasets/dataset-icon.svg" />
|
||||
</div>
|
||||
|
||||
<div class="MapCard-error" v-if="isThumbnailErrored"></div>
|
||||
</div>
|
||||
|
||||
<span class="checkbox card-select" @mouseover="mouseOverChildElement" @mouseleave="mouseOutChildElement">
|
||||
<input class="checkbox-input" :class="{'is-selected': isSelected }" @click.stop.prevent="toggleSelection($event)" type="checkbox">
|
||||
<span class="checkbox-decoration">
|
||||
<img svg-inline src="../../assets/icons/common/checkbox.svg">
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<div class="card-actions" v-if="showInteractiveElements" @mouseover="mouseOverChildElement" @mouseleave="mouseOutChildElement">
|
||||
<component
|
||||
:is="quickActionsComponent"
|
||||
|
||||
:map="visualization"
|
||||
:dataset="visualization"
|
||||
:storeActionType="storeActionType"
|
||||
|
||||
@open="openQuickActions"
|
||||
@close="closeQuickActions"
|
||||
@contentChanged="onContentChanged"></component>
|
||||
</div>
|
||||
|
||||
<div class="card-text">
|
||||
<div class="card-header" :class="{ 'card-header__no-description': !sectionsToShow.description}">
|
||||
<h2 :title="visualization.name" class="card-title title is-caption" :class="{'title-overflow': (titleOverflow || isStarInNewLine) && !singleLineTitle, 'single-line': singleLineTitle}">
|
||||
<span :class="{ 'title-element': singleLineTitle }">{{ visualization.name }}</span>
|
||||
<span
|
||||
v-if="showInteractiveElements"
|
||||
class="card-favorite"
|
||||
:class="{'is-favorite': visualization.liked, 'favorite-overflow': titleOverflow}"
|
||||
@click.prevent="toggleFavorite"
|
||||
@mouseover="mouseOverChildElement"
|
||||
@mouseleave="mouseOutChildElement">
|
||||
<img svg-inline src="../../assets/icons/common/favorite.svg">
|
||||
</span>
|
||||
</h2>
|
||||
<template v-if="sectionsToShow.description">
|
||||
<p class="card-description text is-caption" :title="visualization.description" v-if="visualization.description" :class="{'single-line': multilineTitle}">{{ visualization.description }}</p>
|
||||
<p class="card-description text is-caption is-txtSoftGrey" v-else>{{ $t(`MapCard.noDescription`) }}</p>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<ul class="card-metadata">
|
||||
<li class="card-metadataItem text is-caption" v-if="sectionsToShow.privacy && !isSharedWithMe">
|
||||
<span class="icon icon--privacy" :class="privacyIcon"></span>
|
||||
<p>{{ $t(`MapCard.shared.${visualization.privacy}`) }} <span v-if="showViews">| {{ $t(`MapCard.views`, { views: numberViews })}}</span></p>
|
||||
</li>
|
||||
|
||||
<li class="card-metadataItem text is-caption" v-if="sectionsToShow.privacy && isSharedWithMe">
|
||||
<span class="icon icon--privacy icon--sharedBy" :style="{ backgroundImage: `url('${visualization.permission.owner.avatar_url}')` }"></span>
|
||||
<p>{{ $t(`MapCard.sharedBy`, { owner: visualization.permission.owner.username })}}</p>
|
||||
</li>
|
||||
|
||||
<li class="card-metadataItem text is-caption" v-if="sectionsToShow.lastModification">
|
||||
<span class="icon"><img inline-svg src="../../assets/icons/maps/calendar.svg"></span>
|
||||
<p>{{ lastUpdated }}</p>
|
||||
</li>
|
||||
|
||||
<li class="card-metadataItem text is-caption" v-if="sectionsToShow.tags">
|
||||
<span class="icon"><img class="icon__tags" svg-inline src="../../assets/icons/common/tag.svg"></span>
|
||||
|
||||
<ul class="card-tags" v-if="tagsChars <= maxTagsChars">
|
||||
<li v-for="(tag, index) in visualization.tags" :key="tag">
|
||||
<router-link class="card-tags__tag" :to="{ name: 'tagSearch', params: { tag } }" @mouseover="mouseOverChildElement" @mouseleave="mouseOutChildElement">{{ tag }}</router-link><span v-if="index < visualization.tags.length - 1">, </span>
|
||||
</li>
|
||||
|
||||
<li v-if="!tagsLength">
|
||||
<span>{{ $t(`MapCard.noTags`) }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<FeaturesDropdown v-if="tagsChars > maxTagsChars" :list=visualization.tags linkRoute="tagSearch" feature="tag">
|
||||
<span class="feature-text text is-caption is-txtGrey">{{tagsLength}} {{$t(`MapCard.tags`)}}</span>
|
||||
</FeaturesDropdown>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FeaturesDropdown from 'new-dashboard/components/Dropdowns/FeaturesDropdown';
|
||||
import MapQuickActions from 'new-dashboard/components/QuickActions/MapQuickActions';
|
||||
import DatasetQuickActions from 'new-dashboard/components/QuickActions/DatasetQuickActions';
|
||||
import props from './shared/props';
|
||||
import methods from './shared/methods';
|
||||
import data from './shared/data';
|
||||
import computed from './shared/computed';
|
||||
|
||||
export default {
|
||||
name: 'SimpleMapCard',
|
||||
components: {
|
||||
MapQuickActions,
|
||||
DatasetQuickActions,
|
||||
FeaturesDropdown
|
||||
},
|
||||
props: {
|
||||
...props,
|
||||
visibleSections: Array,
|
||||
singleLineTitle: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
...data(),
|
||||
thumbnailWidth: 600,
|
||||
thumbnailHeight: 280
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...computed,
|
||||
quickActionsComponent () {
|
||||
const visualizationType = this.$props.visualization.type;
|
||||
|
||||
if (visualizationType === 'table') {
|
||||
return 'DatasetQuickActions';
|
||||
}
|
||||
|
||||
if (visualizationType === 'derived') {
|
||||
return 'MapQuickActions';
|
||||
}
|
||||
},
|
||||
sectionsToShow () {
|
||||
const defaultSections = ['description', 'privacy', 'lastModification', 'tags'];
|
||||
const visibleSections = this.$props.visibleSections || defaultSections;
|
||||
|
||||
return visibleSections.reduce((allSections, section) => {
|
||||
allSections[section] = true;
|
||||
return allSections;
|
||||
}, {});
|
||||
},
|
||||
isMap () {
|
||||
return this.$props.visualization.type === 'derived';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...methods,
|
||||
onContentChanged (type) {
|
||||
this.$emit('contentChanged', type);
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
function isStarUnderText (textNode, starNode) {
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(textNode.firstChild);
|
||||
const textBottomPosition = range.getClientRects()[0].bottom;
|
||||
const starBottomPosition = starNode.getBoundingClientRect().bottom;
|
||||
return textBottomPosition !== starBottomPosition;
|
||||
}
|
||||
|
||||
this.$nextTick(function () {
|
||||
var title = this.$el.querySelector('.card-title');
|
||||
this.multilineTitle = title.offsetHeight > 30;
|
||||
this.titleOverflow = title.scrollHeight > title.clientHeight;
|
||||
this.isStarInNewLine = isStarUnderText(this.$el.querySelector('.card-title'), this.$el.querySelector('.card-favorite'));
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import 'new-dashboard/styles/variables';
|
||||
|
||||
.map-card {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.card {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 2px;
|
||||
background-clip: padding-box;
|
||||
background-color: $white;
|
||||
|
||||
&:hover {
|
||||
border-color: transparent;
|
||||
box-shadow: $card__shadow;
|
||||
cursor: pointer;
|
||||
|
||||
&:not(.card--child-hover) {
|
||||
.card-title {
|
||||
color: $primary-color;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
&.card--child-hover {
|
||||
.card-title {
|
||||
color: $text__color;
|
||||
}
|
||||
|
||||
.card-tags {
|
||||
.card-tags__tag {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-actions,
|
||||
.card-favorite {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.card-tags {
|
||||
.card-tags__tag {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.card--selected {
|
||||
border: 1px solid $primary-color;
|
||||
|
||||
.card-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.card--quick-actions-open {
|
||||
.card-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.card--can-hover {
|
||||
&.card--selected,
|
||||
&.card--quick-actions-open,
|
||||
&:hover {
|
||||
.card-select {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-text {
|
||||
padding: 24px 16px;
|
||||
color: $text__color;
|
||||
}
|
||||
|
||||
.card-media {
|
||||
display: flex;
|
||||
position: relative;
|
||||
height: 140px;
|
||||
overflow: hidden;
|
||||
background: url($assetsDir + '/images/layout/default-map-bkg.png') no-repeat center 0;
|
||||
background-size: cover;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
&.has-error {
|
||||
.MapCard-error {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.media-dataset {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 88px;
|
||||
|
||||
&.card-header__no-description {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.card-title {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
max-height: 48px;
|
||||
margin-bottom: 8px;
|
||||
overflow: hidden;
|
||||
transition: color 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
&.title-overflow {
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
.title-element {
|
||||
max-height: 24px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&.single-line {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.card-description {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
position: relative;
|
||||
max-height: 48px;
|
||||
margin-bottom: 8px;
|
||||
overflow: hidden;
|
||||
|
||||
&.single-line {
|
||||
-webkit-line-clamp: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.card-metadataItem {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
|
||||
a {
|
||||
color: $text__color;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: $text__color;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-top: 4px;
|
||||
margin-right: 8px;
|
||||
|
||||
&.icon--privacy {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
&.icon--private {
|
||||
background-image: url("../../assets/icons/maps/privacy/lock.svg");
|
||||
}
|
||||
|
||||
&.icon--public {
|
||||
background-image: url("../../assets/icons/maps/privacy/public.svg");
|
||||
}
|
||||
|
||||
&.icon--link {
|
||||
background-image: url("../../assets/icons/maps/privacy/link.svg");
|
||||
}
|
||||
|
||||
&.icon--password {
|
||||
background-image: url("../../assets/icons/maps/privacy/password.svg");
|
||||
}
|
||||
|
||||
&.icon--sharedBy {
|
||||
border-radius: 2px;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.icon__tags {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
g {
|
||||
fill: $text__color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-select {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
transition: opacity 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border-radius: 4px;
|
||||
opacity: 0;
|
||||
background: $white;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:checked {
|
||||
opacity: 1;
|
||||
background: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
transition: opacity 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.card-favorite {
|
||||
margin-left: 8px;
|
||||
opacity: 0;
|
||||
|
||||
svg {
|
||||
transform: translateY(2px);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.favorite-icon {
|
||||
stroke: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-favorite {
|
||||
opacity: 1;
|
||||
|
||||
.favorite-icon {
|
||||
stroke: #FFC300;
|
||||
fill: #FFC300;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.favorite-icon {
|
||||
stroke: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.favorite-overflow {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: -4px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-tags > li {
|
||||
display: inline;
|
||||
}
|
||||
</style>
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div class="condensed-fake-row">
|
||||
<div class="viz-column--main-info">
|
||||
<div class="cell-placeholder cell--icon">
|
||||
<div class="icon-placeholder"/>
|
||||
</div>
|
||||
<div class="cell-placeholder cell--main">
|
||||
<div class="text-placeholder"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="viz-column--extra-info">
|
||||
<div class="viz-column--status u-flex__justify--between">
|
||||
<div class="cell-placeholder cell--large">
|
||||
<div class="text-placeholder"/>
|
||||
</div>
|
||||
<div class="cell-placeholder cell--xsmall">
|
||||
<div class="text-placeholder"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="viz-column--share">
|
||||
<div class="cell-placeholder cell--small">
|
||||
<div class="text-placeholder"/>
|
||||
</div>
|
||||
<div class="cell-placeholder cell--quick-actions">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CondensedMapCardFake'
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import 'new-dashboard/styles/variables';
|
||||
|
||||
.condensed-fake-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
padding: 0 14px;
|
||||
background-color: $white;
|
||||
}
|
||||
|
||||
.icon-placeholder {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 2px;
|
||||
background-color: $softblue;
|
||||
}
|
||||
|
||||
.text-placeholder {
|
||||
height: 24px;
|
||||
background-color: $softblue;
|
||||
}
|
||||
|
||||
.cell-placeholder {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.cell--icon {
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
|
||||
.cell--quick-actions {
|
||||
padding: 0 18px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<div>
|
||||
<CondensedMapCardFake v-if="condensed"></CondensedMapCardFake>
|
||||
<SimpleMapCardFake v-else></SimpleMapCardFake>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SimpleMapCardFake from 'new-dashboard/components/MapCard/fakes/SimpleMapCardFake';
|
||||
import CondensedMapCardFake from 'new-dashboard/components/MapCard/fakes/CondensedMapCardFake';
|
||||
|
||||
export default {
|
||||
name: 'MapCardFake',
|
||||
components: {
|
||||
SimpleMapCardFake,
|
||||
CondensedMapCardFake
|
||||
},
|
||||
props: {
|
||||
condensed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div class="map-fake-card">
|
||||
<div class="image-placeholder"></div>
|
||||
<div class="text-container-placeholder">
|
||||
<div class="text-placeholder"></div>
|
||||
<div class="text-placeholder text-placeholder--double" v-if="sectionsToShow.description"></div>
|
||||
<div class="text-placeholder" v-if="sectionsToShow.privacy"></div>
|
||||
<div class="text-placeholder" v-if="sectionsToShow.lastModification"></div>
|
||||
<div class="text-placeholder" v-if="sectionsToShow.tags"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SimpleMapCardFake',
|
||||
props: {
|
||||
visibleSections: {
|
||||
type: Array,
|
||||
default: () => ['description', 'privacy', 'lastModification', 'tags']
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
sectionsToShow () {
|
||||
const visibleSections = this.$props.visibleSections || [];
|
||||
|
||||
return visibleSections.reduce((allSections, section) => {
|
||||
allSections[section] = true;
|
||||
return allSections;
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import 'new-dashboard/styles/variables';
|
||||
|
||||
.map-fake-card {
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 2px;
|
||||
background-color: $white;
|
||||
}
|
||||
|
||||
.image-placeholder {
|
||||
width: 100%;
|
||||
height: 140px;
|
||||
background-color: $softblue;
|
||||
}
|
||||
|
||||
.text-container-placeholder {
|
||||
padding: 24px 16px;
|
||||
}
|
||||
|
||||
.text-placeholder {
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
margin-bottom: 8px;
|
||||
background-color: $softblue;
|
||||
|
||||
&.text-placeholder--double {
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,55 @@
|
||||
import * as Visualization from 'new-dashboard/core/models/visualization';
|
||||
import countCharsArray from 'new-dashboard/utils/count-chars-array';
|
||||
import distanceInWordsStrict from 'date-fns/distance_in_words_strict';
|
||||
import zhCN from 'date-fns/locale/zh_cn';
|
||||
|
||||
|
||||
export default {
|
||||
privacyIcon () {
|
||||
return `icon--${this.$props.visualization.privacy}`.toLowerCase();
|
||||
},
|
||||
lastUpdated () {
|
||||
return this.$t(`MapCard.lastUpdate`, {
|
||||
date: distanceInWordsStrict(this.$props.visualization.updated_at, new Date(),{ locale: zhCN })
|
||||
});
|
||||
},
|
||||
mapThumbnailUrl () {
|
||||
return Visualization.getThumbnailUrl(this.$props.visualization, this.$cartoModels, {
|
||||
width: this.thumbnailWidth,
|
||||
height: this.thumbnailHeight
|
||||
});
|
||||
},
|
||||
tagsLength () {
|
||||
return this.$props.visualization.tags ? this.$props.visualization.tags.length : 0;
|
||||
},
|
||||
hasTags () {
|
||||
return this.$props.visualization.tags && this.$props.visualization.tags.length;
|
||||
},
|
||||
vizUrl () {
|
||||
return Visualization.getURL(this.$props.visualization, this.$cartoModels);
|
||||
},
|
||||
tagsChars () {
|
||||
return countCharsArray(this.$props.visualization.tags, ', ');
|
||||
},
|
||||
isSharedWithMe () {
|
||||
return Visualization.isSharedWithMe(this.$props.visualization, this.$cartoModels);
|
||||
},
|
||||
showViews () {
|
||||
const privacy = this.$props.visualization.privacy;
|
||||
return ['public', 'password', 'link'].includes(privacy.toLowerCase());
|
||||
},
|
||||
numberViews () {
|
||||
const stats = this.$props.visualization.stats;
|
||||
const totalViews = Object.keys(stats).reduce((total, date) => total + stats[date], 0);
|
||||
return totalViews;
|
||||
},
|
||||
showInteractiveElements () {
|
||||
return !this.$props.selectMode;
|
||||
},
|
||||
colleaguesSharedList () {
|
||||
return this.$props.visualization.permission.acl;
|
||||
},
|
||||
isSharedWithColleagues () {
|
||||
return this.$props.visualization.permission.acl.length > 0;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
export default function data () {
|
||||
return {
|
||||
isThumbnailErrored: false,
|
||||
activeHover: true,
|
||||
titleOverflow: false,
|
||||
multilineTitle: false,
|
||||
areQuickActionsOpen: false,
|
||||
isStarInNewLine: false,
|
||||
maxTagsChars: 30
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
export default {
|
||||
toggleSelection ($event) {
|
||||
this.$emit('toggleSelection', {
|
||||
map: this.$props.visualization,
|
||||
isSelected: !this.$props.isSelected,
|
||||
event: $event
|
||||
});
|
||||
},
|
||||
toggleFavorite () {
|
||||
if (this.$props.visualization.liked) {
|
||||
this.$store.dispatch(`${this.$props.storeActionType}/deleteLike`, this.$props.visualization);
|
||||
} else {
|
||||
this.$store.dispatch(`${this.$props.storeActionType}/like`, this.$props.visualization);
|
||||
}
|
||||
},
|
||||
openQuickActions () {
|
||||
this.areQuickActionsOpen = true;
|
||||
},
|
||||
closeQuickActions () {
|
||||
this.areQuickActionsOpen = false;
|
||||
},
|
||||
mouseOverChildElement () {
|
||||
this.activeHover = false;
|
||||
},
|
||||
mouseOutChildElement () {
|
||||
this.activeHover = true;
|
||||
},
|
||||
onThumbnailError () {
|
||||
this.isThumbnailErrored = true;
|
||||
},
|
||||
onDataChanged () {
|
||||
this.$emit('dataChanged');
|
||||
},
|
||||
onClick (event) {
|
||||
if (this.$props.selectMode) {
|
||||
event.preventDefault();
|
||||
this.toggleSelection(event);
|
||||
}
|
||||
},
|
||||
isLastTag (index) {
|
||||
return index === this.tagsLength - 1;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
export default {
|
||||
visualization: Object,
|
||||
storeActionType: {
|
||||
type: String,
|
||||
default: 'maps'
|
||||
},
|
||||
isSelected: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
canHover: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
selectMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user