Initial commit
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
<template>
|
||||
<nav class="navbar" :class="{ 'is-search-open': isSearchOpen, 'has-user-notification': isNotificationVisible }">
|
||||
<ul class="navbar-elementsContainer">
|
||||
<router-link :to="{ name: 'home' }" class="navbar-elementItem" :class="{'is-active': isHomePage()}" staticRoute="/dashboard">
|
||||
<span class="navbar-icon">
|
||||
<img svg-inline class="navbar-iconFill" src="../../assets/icons/navbar/home.svg" />
|
||||
</span>
|
||||
<span class="title is-caption is-txtWhite u-hideTablet">主页</span>
|
||||
</router-link>
|
||||
<router-link :to="{ name: 'maps' }" class="navbar-elementItem" active-class="is-active" staticRoute="/dashboard/maps">
|
||||
<span class="navbar-icon">
|
||||
<img svg-inline class="navbar-iconFill" src="../../assets/icons/navbar/maps.svg" />
|
||||
</span>
|
||||
<span class="title is-caption is-txtWhite u-hideTablet">地图</span>
|
||||
</router-link>
|
||||
<!-- <router-link :to="{ name: 'solutions' }" class="navbar-elementItem" active-class="is-active">
|
||||
<span class="navbar-icon">
|
||||
<img svg-inline class="navbar-iconFill" src="../../assets/icons/navbar/solutions.svg" />
|
||||
</span>
|
||||
<span class="title is-caption is-txtWhite u-hideTablet">Solutions</span>
|
||||
</router-link> -->
|
||||
<router-link :to="{ name: 'datasets' }" class="navbar-elementItem" active-class="is-active" staticRoute="/dashboard/datasets">
|
||||
<span class="navbar-icon">
|
||||
<img svg-inline class="navbar-iconFill" src="../../assets/icons/navbar/data.svg" />
|
||||
</span>
|
||||
<span class="title is-caption is-txtWhite u-hideTablet">数据</span>
|
||||
</router-link>
|
||||
<span class="navbar-elementItem navbar-icon navbar-searchIcon u-showMobile" @click="toggleSearch">
|
||||
<img svg-inline src="../../assets/icons/navbar/loupe_white.svg" />
|
||||
</span>
|
||||
</ul>
|
||||
<div class="navbar-imagotype u-hideMobile">
|
||||
<img src="../../assets/icons/navbar/imagotype.svg" />
|
||||
</div>
|
||||
<div class="navbar-elementsContainer navbar-searchContainer">
|
||||
<Search />
|
||||
<div class="navbar-user">
|
||||
<div class="navbar-avatar" :class="{'has-notification': notificationsCount}" :style="{ backgroundImage: `url('${user.avatar_url}')` }" @click.stop.prevent="toggleDropdown"></div>
|
||||
<UserDropdown :userModel="user" :notificationsCount="notificationsCount" :open="isDropdownOpen" :baseUrl="baseUrl" v-click-outside="closeDropdown" @linkClick="closeDropdown" />
|
||||
</div>
|
||||
<span class="navbar-searchClose" @click="toggleSearch">
|
||||
<img svg-inline src="../../assets/icons/navbar/close.svg" />
|
||||
</span>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Search from '../Search/Search';
|
||||
import UserDropdown from './UserDropdown';
|
||||
import FeedbackPopup from '../FeedbackPopup';
|
||||
import storageAvailable from 'new-dashboard/utils/is-storage-available';
|
||||
|
||||
export default {
|
||||
name: 'NavigationBar',
|
||||
components: {
|
||||
Search,
|
||||
UserDropdown,
|
||||
FeedbackPopup
|
||||
},
|
||||
props: {
|
||||
user: Object,
|
||||
baseUrl: String,
|
||||
notificationsCount: Number,
|
||||
isNotificationVisible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isFirstTimeInDashboard: Boolean,
|
||||
bundleType: {
|
||||
type: String,
|
||||
default: 'other'
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isDropdownOpen: false,
|
||||
isSearchOpen: false,
|
||||
hasDropdownOpenedForFirstTime: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isDashboardBundle () {
|
||||
return this.$props.bundleType === 'dashboard';
|
||||
},
|
||||
popupWasShown () {
|
||||
if (!storageAvailable('localStorage')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return JSON.parse(window.localStorage.getItem('carto.feedback.popupWasShown'));
|
||||
},
|
||||
shouldShowFeedbackPopup () {
|
||||
return this.isDashboardBundle &&
|
||||
!this.isFirstTimeInDashboard &&
|
||||
!this.hasDropdownOpenedForFirstTime &&
|
||||
!this.popupWasShown;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleDropdown () {
|
||||
this.hasDropdownOpenedForFirstTime = true;
|
||||
this.isDropdownOpen = !this.isDropdownOpen;
|
||||
},
|
||||
closeDropdown () {
|
||||
this.isDropdownOpen = false;
|
||||
},
|
||||
toggleSearch () {
|
||||
this.isSearchOpen = !this.isSearchOpen;
|
||||
},
|
||||
isHomePage () {
|
||||
return (this.$route || {}).name === 'home';
|
||||
},
|
||||
onFeedbackClicked () {
|
||||
this.toggleDropdown();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import 'new-dashboard/styles/variables';
|
||||
|
||||
.navbar {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
z-index: $z-index__navbar;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 0 64px;
|
||||
border-bottom: 1px solid $white;
|
||||
background-color: $primary-color;
|
||||
|
||||
@media (max-width: $layout-tablet) {
|
||||
padding: 0 24px 0 40px;
|
||||
}
|
||||
|
||||
@media (max-width: $layout-mobile) {
|
||||
padding: 0 16px 0 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-elementsContainer {
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
a:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
@media (max-width: $layout-mobile) {
|
||||
a:last-of-type {
|
||||
margin-right: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-elementItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 54px;
|
||||
padding: 20px 2px 16px;
|
||||
border-bottom: 4px solid transparent;
|
||||
|
||||
@media (max-width: $layout-tablet) {
|
||||
margin-right: 48px;
|
||||
}
|
||||
|
||||
@media (max-width: $layout-mobile) {
|
||||
margin-right: 36px;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
border-color: $white;
|
||||
|
||||
.navbar-iconFill {
|
||||
fill: #FFF;
|
||||
}
|
||||
|
||||
.navbar-iconNegativeFill {
|
||||
fill: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-searchIcon {
|
||||
padding-top: 21px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.navbar-searchClose {
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.navbar-icon {
|
||||
margin-right: 12px;
|
||||
|
||||
@media (max-width: $layout-tablet) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-imagotype {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
transform: translate3d(-50%, 0, 0);
|
||||
}
|
||||
|
||||
.navbar-user {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.navbar-avatar {
|
||||
display: flex;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin-left: 24px;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
background-color: $navbar-avatar__bg-color;
|
||||
background-size: cover;
|
||||
|
||||
&.has-notification {
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: -4px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border: 2px solid $primary-color;
|
||||
border-radius: 50%;
|
||||
background-color: $notification__bg-color;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar.is-search-open {
|
||||
padding: 0;
|
||||
|
||||
.navbar-elementsContainer {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.navbar-elementsContainer,
|
||||
.navbar-imagotype,
|
||||
.navbar-user {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.navbar-searchContainer {
|
||||
visibility: visible;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.navbar-searchClose {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar.has-user-notification {
|
||||
top: $notification-warning__height;
|
||||
}
|
||||
|
||||
.feedback-popup {
|
||||
position: absolute;
|
||||
top: calc(100% + 18px);
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<div class="navbar-dropdown" :class="{ 'is-open': open }">
|
||||
<ul class="navbar-dropdown-container">
|
||||
<li class="navbar-dropdown-profile">
|
||||
<div class="avatar-container">
|
||||
<img :src="userModel.avatar_url">
|
||||
</div>
|
||||
<div class="navbar-dropdown-userInfo">
|
||||
<p class="text is-semibold is-caption">{{userModel.username}}</p>
|
||||
<p class="text is-small">{{userModel.email}}</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="navbar-dropdown-iconLink">
|
||||
<div class="icon-container">
|
||||
<img svg-inline src="../../assets/icons/navbar/dropdown/settings.svg"/>
|
||||
</div>
|
||||
<a :href="`${ baseUrl }/profile`" class="text is-semibold is-caption is-txtGrey" @click="linkClicked">{{ $t('UserDropdown.settings') }}</a>
|
||||
</li>
|
||||
<li class="navbar-dropdown-iconLink" v-if="isOrganizationAdmin">
|
||||
<div class="icon-container">
|
||||
<img svg-inline src="../../assets/icons/navbar/dropdown/organization.svg"/>
|
||||
</div>
|
||||
<a :href="`${ baseUrl }/organization`" class="text is-semibold is-caption is-txtGrey" @click="linkClicked">{{ $t('UserDropdown.organizationSettings') }}</a>
|
||||
</li>
|
||||
<li @click="linkClicked" class="navbar-dropdown-iconLink">
|
||||
<div class="icon-container">
|
||||
<img svg-inline src="../../assets/icons/navbar/dropdown/api-keys.svg"/>
|
||||
</div>
|
||||
<a :href="`${ baseUrl }/your_apps`" class="text is-semibold is-caption is-txtGrey" @click="linkClicked">{{ $t('UserDropdown.apiKeys') }}</a>
|
||||
</li>
|
||||
<li class="navbar-dropdown-iconLink">
|
||||
<div class="icon-container">
|
||||
<img svg-inline src="../../assets/icons/navbar/dropdown/profile.svg"/>
|
||||
</div>
|
||||
<a :href="`${ baseUrl }/me`" class="text is-semibold is-caption is-txtGrey" target="_blank" @click="linkClicked">{{ $t('UserDropdown.publicProfile') }}</a>
|
||||
</li>
|
||||
<li class="navbar-dropdown-iconLink">
|
||||
<div class="icon-container">
|
||||
<img svg-inline src="../../assets/icons/navbar/dropdown/notifications.svg"/>
|
||||
</div>
|
||||
<router-link :to="{ name: 'notifications' }" class="text is-semibold is-caption is-txtGrey" @click.native="linkClicked" :staticRoute="'/dashboard/notifications'">
|
||||
{{ $t('UserDropdown.notifications') }}
|
||||
</router-link>
|
||||
<span v-if="notificationsCount > 0" class="notification-number text is-semibold is-small is-txtGrey">{{notificationsCount}}</span>
|
||||
</li>
|
||||
<!--
|
||||
<li class="navbar-dropdown-iconLink">
|
||||
<div class="icon-container">
|
||||
<img svg-inline src="../../assets/icons/navbar/dropdown/feedback.svg"/>
|
||||
</div>
|
||||
<a href="https://docs.google.com/forms/d/e/1FAIpQLScBQUWd-TP3Qy514DOCNg-KoLrViHijUR5giLAMS-3jmDnrPg/viewform" class="text is-semibold is-caption is-txtGrey" target="_blank" @click="linkClicked">
|
||||
{{ $t('UserDropdown.feedback') }}
|
||||
</a>
|
||||
</li>
|
||||
-->
|
||||
</ul>
|
||||
<a :href="`${ baseUrl }/logout`" class="navbar-dropdown-bottom" @click="linkClicked">
|
||||
<div class="arrow"><img src="../../assets/icons/navbar/dropdown/arrow-right.svg" /></div>
|
||||
<div class="title is-small is-txtAlert">{{ $t('UserDropdown.logout') }}</div>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UserDropdown',
|
||||
props: {
|
||||
baseUrl: { type: String, default: '' },
|
||||
open: { type: Boolean, default: false },
|
||||
userModel: Object,
|
||||
notificationsCount: Number
|
||||
},
|
||||
computed: {
|
||||
isOrganizationAdmin () {
|
||||
return this.userModel.org_admin;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
linkClicked () {
|
||||
this.$emit('linkClick');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import 'new-dashboard/styles/variables';
|
||||
|
||||
.navbar-dropdown {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 360px;
|
||||
margin-top: 18px;
|
||||
transition: all 0.25s linear;
|
||||
border-radius: 4px;
|
||||
opacity: 0;
|
||||
box-shadow: $dropdown__shadow;
|
||||
pointer-events: none;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
transform: rotate(45deg) translateX(-50%);
|
||||
transform-origin: center center;
|
||||
border-radius: 4px;
|
||||
background-color: $white;
|
||||
box-shadow: $dropdown__shadow;
|
||||
}
|
||||
|
||||
&.is-open {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
pointer-events: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-dropdown-profile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 36px;
|
||||
|
||||
.avatar-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin-right: 12px;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-dropdown-container {
|
||||
position: relative;
|
||||
padding: 28px 24px 36px;
|
||||
border-radius: 4px 4px 0 0;
|
||||
background-color: $white;
|
||||
}
|
||||
|
||||
.navbar-dropdown-iconLink {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.icon-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-dropdown-bottom {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
padding: 24px 30px;
|
||||
border-radius: 0 0 4px 4px;
|
||||
background-color: $softblue;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
& .arrow {
|
||||
margin-right: 8px;
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-number {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-top: 2px;
|
||||
margin-left: 24px;
|
||||
border-radius: 50%;
|
||||
background-color: $notification__bg-color;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user