Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions
@@ -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)">,&nbsp;</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">,&#32;</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>
@@ -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
}
};