Merge pull request #5587 from aignatov-bio/ai-sci-8540-update-top-navigation
Refactor top navigation [SCI-8540]
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 991 B After Width: | Height: | Size: 843 B |
|
@ -1,3 +1,5 @@
|
|||
@import "tailwind/inputs";
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
|
|
@ -11,7 +11,7 @@ body.navigator-collapsed {
|
|||
--left-navigation-width: 192px;
|
||||
--navbar-height: calc(var(--top-navigation-height) + var(--breadcrumbs-navigation-height));
|
||||
--navigator-navigation-width: 240px;
|
||||
--top-navigation-height: 52px;
|
||||
--top-navigation-height: 72px;
|
||||
display: grid;
|
||||
grid-template-areas: "left top top"
|
||||
"left breadcrumbs breadcrumbs"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 2rem 1rem;
|
||||
padding: 1.5rem 1rem;
|
||||
width: 100%;
|
||||
|
||||
.sci--layout--menu-item {
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
.sci--navigation--top-menu-container {
|
||||
align-items: center;
|
||||
background-color: $color-white;
|
||||
box-shadow: $flyout-shadow;
|
||||
border-bottom: 1px solid var(--sn-sleepy-grey);
|
||||
display: flex;
|
||||
gap: .5em;
|
||||
gap: 1rem;
|
||||
height: 100%;
|
||||
padding: 0 2em;
|
||||
padding: 0 1rem;
|
||||
|
||||
.sci--navigation--top-menu-logo {
|
||||
a {
|
||||
|
@ -28,40 +28,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
.sci--navigation--top-menu-teams {
|
||||
height: 36px;
|
||||
margin-left: 2em;
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.sci--navigation--top-menu-search {
|
||||
margin-left: auto;
|
||||
margin-right: 1em;
|
||||
width: 240px;
|
||||
|
||||
input {
|
||||
border-color: $color-alto;
|
||||
}
|
||||
|
||||
.sn-icon {
|
||||
color: $color-silver-chalice;
|
||||
}
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.sci--navigation--top-menu-user {
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
margin-left: .75em;
|
||||
|
||||
span {
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
.sn-select {
|
||||
border: 1px solid;
|
||||
border-color: var(--sn-grey);
|
||||
border-radius: 4px;
|
||||
align-items: center;
|
||||
border: $border-default;
|
||||
border-color: var(--sn-light-grey);
|
||||
border-radius: $border-radius-default;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
padding: .5em;
|
||||
display: flex;
|
||||
padding: .5rem .625rem .5rem 1rem;
|
||||
position: relative;
|
||||
|
||||
&.sn-select--blank {
|
||||
.sn-select__value {
|
||||
color: var(--sn-grey);
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,11 +28,11 @@
|
|||
.sn-select__value {
|
||||
all: unset;
|
||||
display: inline-block;
|
||||
flex-grow: 1;
|
||||
line-height: 1.625rem;
|
||||
overflow: hidden;
|
||||
padding-right: 1.5em;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: calc(100% - 1.5em);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
@ -51,12 +53,6 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.sn-select__caret {
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
top: 1.1em;
|
||||
}
|
||||
|
||||
.sn-select__search-input {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
|
@ -75,10 +71,6 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
.sn-select__caret {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.sn-select__options {
|
||||
background: var(--sn-white);
|
||||
border-bottom-left-radius: 4px;
|
||||
|
@ -88,15 +80,15 @@
|
|||
left: 0;
|
||||
max-height: 300px;
|
||||
overflow: hidden;
|
||||
overflow-y: scroll;
|
||||
top: 2.5em;
|
||||
top: 2.5rem;
|
||||
width: 100%;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.sn-select__option {
|
||||
padding: .5em;
|
||||
line-height: 1.75rem;
|
||||
overflow: hidden;
|
||||
padding: .5rem 1rem;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: calc(100%);
|
||||
|
@ -108,8 +100,7 @@
|
|||
}
|
||||
|
||||
.sn-select__option:hover {
|
||||
background: var(--sn-blue);
|
||||
color: var(--sn-white);
|
||||
background: var(--sn-super-light-grey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,6 @@
|
|||
transition: .3s;
|
||||
user-select: none;
|
||||
|
||||
img {
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
|
27
app/assets/stylesheets/tailwind/inputs.css
Normal file
|
@ -0,0 +1,27 @@
|
|||
@layer components {
|
||||
.sci-input-container-v2 {
|
||||
@apply relative h-[2.75rem] flex items-center;
|
||||
}
|
||||
|
||||
.sci-input-container-v2 input {
|
||||
@apply w-full h-full bg-transparent p-0.5 border rounded outline-none absolute top-0;
|
||||
border-color: var(--sn-sleepy-grey);
|
||||
}
|
||||
|
||||
.sci-input-container-v2 input::placeholder {
|
||||
color: var(--sn-sleepy-grey);
|
||||
}
|
||||
|
||||
.sci-input-container-v2 input:focus {
|
||||
border-color: var(--sn-science-blue);
|
||||
}
|
||||
|
||||
.sci-input-container-v2 .sn-icon {
|
||||
@apply m-2;
|
||||
color: var(--sn-black)
|
||||
}
|
||||
|
||||
.sci-input-container-v2.left-icon input {
|
||||
@apply pl-10;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ class NavigationsController < ApplicationController
|
|||
def top_menu
|
||||
render json: {
|
||||
root_url: root_path,
|
||||
team_switch_url: switch_users_settings_teams_path,
|
||||
current_team: current_team&.id,
|
||||
search_url: search_path,
|
||||
teams: teams,
|
||||
|
@ -25,11 +26,10 @@ class NavigationsController < ApplicationController
|
|||
|
||||
def teams
|
||||
current_user.teams.order(:name).map do |t|
|
||||
{
|
||||
label: t.name,
|
||||
value: t.id,
|
||||
params: { switch_url: switch_users_settings_team_path(t) }
|
||||
}
|
||||
[
|
||||
t.id,
|
||||
t.name
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ module Users
|
|||
end
|
||||
|
||||
def switch
|
||||
team = current_user.teams.find_by(id: params[:id])
|
||||
team = current_user.teams.find_by(id: params[:team_id])
|
||||
|
||||
if team && current_user.update(current_team_id: team.id)
|
||||
flash[:success] = t('users.settings.changed_team_flash',
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<template>
|
||||
<div class="sci--navigation--top-menu-container">
|
||||
<div v-if="currentTeam" class="sci--navigation--top-menu-teams">
|
||||
<DropdownSelector
|
||||
:selectedValue="currentTeam"
|
||||
:options="teams"
|
||||
:disableSearch="true"
|
||||
:selectorId="`sciNavigationTeamSelector`"
|
||||
:labelHTML="true"
|
||||
@dropdown:changed="switchTeam"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="user" class="sci--navigation--top-menu-search left-icon sci-input-container" :class="{'disabled' : !currentTeam}">
|
||||
<input type="text" class="sci-input-field" :placeholder="i18n.t('nav.search')" @change="searchValue"/>
|
||||
<div v-if="user" class="sci--navigation--top-menu-search left-icon sci-input-container-v2" :class="{'disabled' : !currentTeam}">
|
||||
<input type="text" :placeholder="i18n.t('nav.search')" @change="searchValue"/>
|
||||
<i class="sn-icon sn-icon-search"></i>
|
||||
</div>
|
||||
<div v-if="currentTeam" class="mr-auto w-64">
|
||||
<Select
|
||||
:value="currentTeam"
|
||||
:options="teams"
|
||||
:placeholder="'test'"
|
||||
:noOptionsPlaceholder="'test'"
|
||||
v-bind:disabled="false"
|
||||
@change="switchTeam"
|
||||
></Select>
|
||||
</div>
|
||||
<div v-if="user" class="dropdown">
|
||||
<button class="btn btn-light icon-btn" data-toggle="dropdown">
|
||||
<i class="sn-icon sn-icon-help"></i>
|
||||
|
@ -60,9 +60,8 @@
|
|||
@close="notificationsOpened = false" />
|
||||
</div>
|
||||
<div v-if="user" class="dropdown">
|
||||
<div class="sci--navigation--top-menu-user" data-toggle="dropdown">
|
||||
<span>{{ i18n.t('nav.user_greeting', { full_name: user.name })}}</span>
|
||||
<img class="avatar" :src="user.avatar_url">
|
||||
<div class="sci--navigation--top-menu-user btn btn-light icon-btn" data-toggle="dropdown">
|
||||
<img class="avatar w-6 h-6" :src="user.avatar_url">
|
||||
</div>
|
||||
<div class="dropdown-menu dropdown-menu-right top-menu-user-dropdown">
|
||||
<li v-for="(item, i) in userMenu" :key="i">
|
||||
|
@ -83,12 +82,14 @@
|
|||
<script>
|
||||
import NotificationsFlyout from './notifications/notifications_flyout.vue'
|
||||
import DropdownSelector from '../shared/dropdown_selector.vue'
|
||||
import Select from "../shared/select.vue";
|
||||
|
||||
export default {
|
||||
name: 'TopMenuContainer',
|
||||
components: {
|
||||
DropdownSelector,
|
||||
NotificationsFlyout
|
||||
NotificationsFlyout,
|
||||
Select
|
||||
},
|
||||
props: {
|
||||
url: String,
|
||||
|
@ -98,6 +99,7 @@
|
|||
data() {
|
||||
return {
|
||||
rootUrl: null,
|
||||
teamSwitchUrl: null,
|
||||
currentTeam: null,
|
||||
teams: null,
|
||||
searchUrl: null,
|
||||
|
@ -127,6 +129,7 @@
|
|||
fetchData() {
|
||||
$.get(this.url, (result) => {
|
||||
this.rootUrl = result.root_url;
|
||||
this.teamSwitchUrl = result.team_switch_url;
|
||||
this.currentTeam = result.current_team;
|
||||
this.teams = result.teams;
|
||||
this.searchUrl = result.search_url;
|
||||
|
@ -139,11 +142,11 @@
|
|||
switchTeam(team) {
|
||||
if (this.currentTeam == team) return;
|
||||
|
||||
let newTeam = this.teams.find(e => e.value == team);
|
||||
let newTeam = this.teams.find(e => e[0] == team);
|
||||
|
||||
if (!newTeam) return;
|
||||
|
||||
$.post(newTeam.params.switch_url, (result) => {
|
||||
$.post(this.teamSwitchUrl, {team_id: team}, (result) => {
|
||||
this.currentTeam = result.currentTeam
|
||||
dropdownSelector.selectValues('#sciNavigationTeamSelector', this.currentTeam);
|
||||
$('body').attr('data-current-team-id', this.currentTeam);
|
||||
|
|
|
@ -4,9 +4,13 @@
|
|||
<button ref="focusElement" class="sn-select__value">
|
||||
<span>{{ valueLabel || (placeholder || i18n.t('general.select')) }}</span>
|
||||
</button>
|
||||
<span class="sn-select__caret caret"></span>
|
||||
<i class="sn-icon" :class="{ 'sn-icon-down': !isOpen, 'sn-icon-up': isOpen}"></i>
|
||||
</slot>
|
||||
<div ref="optionsContainer" class="sn-select__options" :style="optionPositionStyle">
|
||||
<perfect-scrollbar
|
||||
ref="optionsContainer"
|
||||
:style="optionPositionStyle"
|
||||
class="sn-select__options scroll-container"
|
||||
>
|
||||
<template v-if="options.length">
|
||||
<div
|
||||
v-for="option in options"
|
||||
|
@ -22,12 +26,13 @@
|
|||
>
|
||||
{{ this.noOptionsPlaceholder }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</perfect-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PerfectScrollbar from 'vue2-perfect-scrollbar';
|
||||
|
||||
export default {
|
||||
name: 'Select',
|
||||
props: {
|
||||
|
@ -38,6 +43,7 @@
|
|||
noOptionsPlaceholder: { type: String },
|
||||
disabled: { type: Boolean, default: false }
|
||||
},
|
||||
comments: { PerfectScrollbar },
|
||||
data() {
|
||||
return {
|
||||
isOpen: false,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
>
|
||||
<input ref="focusElement" v-model="query" type="text" class="sn-select__search-input" :placeholder="searchPlaceholder" />
|
||||
<span class="sn-select__value">{{ valueLabel || (placeholder || i18n.t('general.select')) }}</span>
|
||||
<span class="sn-select__caret caret"></span>
|
||||
<i class="sn-icon" :class="{ 'sn-icon-down': !isOpen, 'sn-icon-up': isOpen}"></i>
|
||||
</Select>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ Rails.application.routes.draw do
|
|||
namespace :users do
|
||||
namespace :settings do
|
||||
resources :teams, only: [] do
|
||||
member do
|
||||
collection do
|
||||
post :switch
|
||||
end
|
||||
end
|
||||
|
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 991 B After Width: | Height: | Size: 1.4 KiB |