Chore: Remove Sidebar from Blaze (#27571)
Co-authored-by: Guilherme Gazzo <guilherme@gazzo.xyz> Co-authored-by: Guilherme Gazzo <guilhermegazzo@gmail.com>pull/27600/head
parent
acb4cd3046
commit
86ea45e992
@ -1,71 +0,0 @@ |
||||
.rooms-list { |
||||
position: relative; |
||||
|
||||
display: flex; |
||||
|
||||
overflow-x: hidden; |
||||
overflow-y: hidden; |
||||
|
||||
flex: 1 1 auto; |
||||
|
||||
height: 100%; |
||||
|
||||
&--embedded { |
||||
margin-top: 2rem; |
||||
} |
||||
|
||||
&__list:not(:last-child) { |
||||
margin-bottom: 22px; |
||||
} |
||||
|
||||
&__type { |
||||
display: flex; |
||||
|
||||
flex-direction: row; |
||||
|
||||
padding: 0 var(--sidebar-default-padding) 1rem var(--sidebar-default-padding); |
||||
|
||||
color: var(--rooms-list-title-color); |
||||
|
||||
font-size: var(--rooms-list-title-text-size); |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
|
||||
&-text--livechat { |
||||
flex: 1; |
||||
} |
||||
} |
||||
|
||||
&__empty-room { |
||||
padding: 0 var(--sidebar-default-padding); |
||||
|
||||
color: var(--rooms-list-empty-text-color); |
||||
|
||||
font-size: var(--rooms-list-empty-text-size); |
||||
} |
||||
|
||||
&__toolbar-search { |
||||
position: absolute; |
||||
z-index: 10; |
||||
left: 0; |
||||
|
||||
overflow-y: scroll; |
||||
|
||||
height: 100%; |
||||
|
||||
background-color: var(--sidebar-background); |
||||
|
||||
padding-block-start: 12px; |
||||
} |
||||
} |
||||
|
||||
@media (width <= 400px) { |
||||
padding: 0 calc(var(--sidebar-small-default-padding) - 4px); |
||||
|
||||
.rooms-list { |
||||
&__type, |
||||
&__empty-room { |
||||
padding: 0 calc(var(--sidebar-small-default-padding) - 4px) 0.5rem calc(var(--sidebar-small-default-padding) - 4px); |
||||
} |
||||
} |
||||
} |
||||
@ -1,51 +0,0 @@ |
||||
.sidebar-flex { |
||||
&__header { |
||||
display: flex; |
||||
|
||||
padding: var(--sidebar-default-padding); |
||||
} |
||||
|
||||
&__title { |
||||
flex: 1; |
||||
|
||||
font-size: 1rem; |
||||
font-weight: 400; |
||||
} |
||||
|
||||
&__close-button { |
||||
font-size: 18px; |
||||
} |
||||
|
||||
&__search { |
||||
padding: 0 1rem; |
||||
|
||||
& .rc-input { |
||||
&__wrapper { |
||||
color: var(--sidebar-flex-search-placeholder-color); |
||||
} |
||||
|
||||
&__icon { |
||||
left: 0.5rem; |
||||
} |
||||
|
||||
&__element { |
||||
padding-left: 2.25rem; |
||||
|
||||
border: 0; |
||||
background-color: var(--sidebar-flex-search-background); |
||||
|
||||
&::placeholder { |
||||
color: var(--sidebar-flex-search-placeholder-color); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
@media (width <= 400px) { |
||||
.sidebar-flex { |
||||
&__back-button { |
||||
padding: 1rem calc(var(--sidebar-small-default-padding) - 8px) 1.5rem; |
||||
} |
||||
} |
||||
} |
||||
@ -1,130 +0,0 @@ |
||||
.sidebar { |
||||
position: relative; |
||||
|
||||
z-index: 2; |
||||
|
||||
display: flex; |
||||
flex-direction: column; |
||||
flex: 0 0 var(--sidebar-width); |
||||
|
||||
width: var(--sidebar-width); |
||||
max-width: var(--sidebar-width); |
||||
|
||||
height: 100%; |
||||
|
||||
user-select: none; |
||||
|
||||
transition: transform 0.3s; |
||||
|
||||
background-color: var(--sidebar-background); |
||||
|
||||
&-wrap { |
||||
position: absolute; |
||||
z-index: 1; |
||||
top: 0; |
||||
left: 0; |
||||
|
||||
height: 100%; |
||||
|
||||
user-select: none; |
||||
transition: opacity 0.3s; |
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); |
||||
touch-action: pan-y; |
||||
-webkit-user-drag: none; |
||||
} |
||||
|
||||
& .wrapper-unread { |
||||
position: relative; |
||||
z-index: 2; |
||||
|
||||
& .unread-rooms { |
||||
position: absolute; |
||||
left: 50%; |
||||
|
||||
overflow: hidden; |
||||
|
||||
min-width: 120px; |
||||
max-width: 100%; |
||||
|
||||
padding: 8px var(--sidebar-small-default-padding); |
||||
|
||||
-webkit-transform: translateX(-50%); |
||||
transform: translateX(-50%); |
||||
|
||||
animation: fade 0.3s; |
||||
|
||||
text-align: center; |
||||
|
||||
white-space: nowrap; |
||||
|
||||
text-overflow: ellipsis; |
||||
|
||||
border-radius: 25px; |
||||
|
||||
&.bottom-unread-rooms { |
||||
bottom: 0; |
||||
} |
||||
|
||||
&.top-unread-rooms { |
||||
top: 0; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
@keyframes fade { |
||||
from { |
||||
opacity: 0; |
||||
} |
||||
|
||||
to { |
||||
opacity: 1; |
||||
} |
||||
} |
||||
|
||||
@media (width < 768px) { |
||||
.sidebar { |
||||
position: absolute; |
||||
|
||||
user-select: none; |
||||
transform: translate3d(-100%, 0, 0); |
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); |
||||
touch-action: pan-y; |
||||
-webkit-user-drag: none; |
||||
will-change: transform; |
||||
} |
||||
|
||||
.rtl .sidebar { |
||||
transform: translate3d(200%, 0, 0); |
||||
} |
||||
} |
||||
|
||||
@media (width <= 400px) { |
||||
.sidebar { |
||||
flex: 0 0 var(--sidebar-small-width); |
||||
|
||||
width: var(--sidebar-small-width); |
||||
max-width: var(--sidebar-small-width); |
||||
|
||||
&__footer { |
||||
display: none; |
||||
} |
||||
|
||||
&:not(&--light) { |
||||
transform: translate3d(-100%, 0, 0); |
||||
} |
||||
} |
||||
|
||||
.rtl .sidebar { |
||||
transform: translate3d(200%, 0, 0); |
||||
} |
||||
} |
||||
|
||||
@media (min-width: 1372px) { /* 1440px -68px (eletron menu) */ |
||||
.sidebar { |
||||
flex: 0 0 20%; |
||||
|
||||
width: 20%; |
||||
max-width: 20%; |
||||
} |
||||
} |
||||
@ -1,3 +0,0 @@ |
||||
import './sideNav.html'; |
||||
import './sideNav'; |
||||
import './userPresence'; |
||||
@ -1,23 +0,0 @@ |
||||
<template name="sideNav"> |
||||
<aside class="rcx-sidebar sidebar sidebar--main sidebar--{{sidebarViewMode}} {{#if sidebarHideAvatar}}sidebar--hide-avatar{{/if}}" role="navigation" data-qa-opened="{{dataQa}}"> |
||||
{{> sidebarHeader }} |
||||
<div class="wrapper-unread"> |
||||
<div class="unread-rooms background-primary-action-color color-primary-action-contrast top-unread-rooms hidden"> |
||||
<i class="icon-up-big"></i> {{_ "More_unreads"}} |
||||
</div> |
||||
</div> |
||||
<div class="rooms-list sidebar--custom-colors" aria-label="{{_ "Channels"}}" role="region"> |
||||
{{> sidebarChats }} |
||||
</div> |
||||
<div class="wrapper-unread"> |
||||
<div class="unread-rooms background-primary-action-color color-primary-action-contrast bottom-unread-rooms hidden"> |
||||
<i class="icon-down-big"></i> {{_ "More_unreads"}} |
||||
</div> |
||||
</div> |
||||
<div class="flex-nav rcx-sidebar animated-hidden"> |
||||
{{> Template.dynamic template=flexTemplate data=flexData }} |
||||
</div> |
||||
{{> sidebarFooter}} |
||||
</aside> |
||||
<div class="sidebar-wrap"></div> |
||||
</template> |
||||
@ -1,126 +0,0 @@ |
||||
import { Meteor } from 'meteor/meteor'; |
||||
import { Tracker } from 'meteor/tracker'; |
||||
import { ReactiveVar } from 'meteor/reactive-var'; |
||||
import { FlowRouter } from 'meteor/kadira:flow-router'; |
||||
import { Template } from 'meteor/templating'; |
||||
|
||||
import { SideNav, menu } from '../../ui-utils'; |
||||
import { settings } from '../../settings'; |
||||
import { getUserPreference } from '../../utils'; |
||||
import { Users } from '../../models/client'; |
||||
import { roomCoordinator } from '../../../client/lib/rooms/roomCoordinator'; |
||||
|
||||
Template.sideNav.helpers({ |
||||
dataQa() { |
||||
return Template.instance().menuState.get() === 'opened'; |
||||
}, |
||||
|
||||
flexTemplate() { |
||||
return SideNav.getFlex().template; |
||||
}, |
||||
|
||||
flexData() { |
||||
return SideNav.getFlex().data; |
||||
}, |
||||
|
||||
roomType() { |
||||
return roomCoordinator.getSortedTypes().map(({ config }) => ({ |
||||
template: config.customTemplate || 'roomList', |
||||
data: { |
||||
header: config.header, |
||||
identifier: config.identifier, |
||||
label: config.label, |
||||
}, |
||||
})); |
||||
}, |
||||
|
||||
loggedInUser() { |
||||
return !!Meteor.userId(); |
||||
}, |
||||
|
||||
sidebarViewMode() { |
||||
const viewMode = getUserPreference(Meteor.userId(), 'sidebarViewMode'); |
||||
return viewMode || 'condensed'; |
||||
}, |
||||
|
||||
sidebarHideAvatar() { |
||||
return !getUserPreference(Meteor.userId(), 'sidebarDisplayAvatar'); |
||||
}, |
||||
}); |
||||
|
||||
Template.sideNav.events({ |
||||
'click .close-flex'() { |
||||
return SideNav.closeFlex(); |
||||
}, |
||||
|
||||
'dropped .sidebar'(e) { |
||||
return e.preventDefault(); |
||||
}, |
||||
'mouseenter .sidebar-item__link'(e) { |
||||
const element = e.currentTarget; |
||||
setTimeout(() => { |
||||
const ellipsedElement = element.querySelector('.sidebar-item__ellipsis'); |
||||
const isTextEllipsed = ellipsedElement.offsetWidth < ellipsedElement.scrollWidth; |
||||
|
||||
if (isTextEllipsed) { |
||||
element.setAttribute('title', element.getAttribute('aria-label')); |
||||
} else { |
||||
element.removeAttribute('title'); |
||||
} |
||||
}, 0); |
||||
}, |
||||
}); |
||||
|
||||
const redirectToDefaultChannelIfNeeded = () => { |
||||
const needToBeRedirect = () => ['/', '/home'].includes(FlowRouter.current().path); |
||||
|
||||
Tracker.autorun((c) => { |
||||
const firstChannelAfterLogin = settings.get('First_Channel_After_Login'); |
||||
|
||||
if (!needToBeRedirect()) { |
||||
return c.stop(); |
||||
} |
||||
|
||||
if (!firstChannelAfterLogin) { |
||||
return c.stop(); |
||||
} |
||||
|
||||
const room = roomCoordinator.getRoomDirectives('c')?.findRoom(firstChannelAfterLogin); |
||||
|
||||
if (!room) { |
||||
return; |
||||
} |
||||
|
||||
c.stop(); |
||||
FlowRouter.go(`/channel/${firstChannelAfterLogin}`); |
||||
}); |
||||
}; |
||||
|
||||
Template.sideNav.onRendered(function () { |
||||
SideNav.init(); |
||||
menu.init(); |
||||
|
||||
this.stopMenuListener = menu.on('change', () => { |
||||
this.menuState.set(menu.isOpen() ? 'opened' : 'closed'); |
||||
}); |
||||
redirectToDefaultChannelIfNeeded(); |
||||
}); |
||||
|
||||
Template.sideNav.onDestroyed(function () { |
||||
this.stopMenuListener(); |
||||
}); |
||||
Template.sideNav.onCreated(function () { |
||||
this.groupedByType = new ReactiveVar(false); |
||||
|
||||
this.menuState = new ReactiveVar(menu.isOpen() ? 'opened' : 'closed'); |
||||
|
||||
this.autorun(() => { |
||||
const user = Users.findOne(Meteor.userId(), { |
||||
fields: { |
||||
'settings.preferences.sidebarGroupByType': 1, |
||||
}, |
||||
}); |
||||
const userPref = getUserPreference(user, 'sidebarGroupByType'); |
||||
this.groupedByType.set(userPref || settings.get('UI_Group_Channels_By_Type')); |
||||
}); |
||||
}); |
||||
@ -1 +0,0 @@ |
||||
<template name="userPresence">{{> Template.contentBlock}}</template> |
||||
@ -1,59 +0,0 @@ |
||||
import { Meteor } from 'meteor/meteor'; |
||||
import { Accounts } from 'meteor/accounts-base'; |
||||
import { Template } from 'meteor/templating'; |
||||
import { Tracker } from 'meteor/tracker'; |
||||
|
||||
import { Presence } from '../../../client/lib/presence'; |
||||
|
||||
import './userPresence.html'; |
||||
|
||||
const data = new Map(); |
||||
const options = { |
||||
threshold: 0.1, |
||||
}; |
||||
|
||||
let lastEntries = []; |
||||
const handleEntries = function (entries) { |
||||
lastEntries = entries.filter(({ isIntersecting }) => isIntersecting); |
||||
lastEntries.forEach(async (entry) => { |
||||
const { uid } = data.get(entry.target); |
||||
Presence.get(uid); |
||||
}); |
||||
}; |
||||
|
||||
const featureExists = !!window.IntersectionObserver; |
||||
|
||||
const observer = featureExists && new IntersectionObserver(handleEntries, options); |
||||
|
||||
Tracker.autorun(() => { |
||||
// Only clear statuses on disconnect, prevent process it on reconnect again
|
||||
const isConnected = Meteor.status().connected; |
||||
if (!Meteor.userId() || !isConnected) { |
||||
Presence.reset(); |
||||
return Meteor.users.update({ status: { $exists: true } }, { $unset: { status: true } }, { multi: true }); |
||||
} |
||||
|
||||
Presence.restart(); |
||||
|
||||
if (featureExists) { |
||||
for (const node of data.keys()) { |
||||
observer.unobserve(node); |
||||
observer.observe(node); |
||||
} |
||||
return; |
||||
} |
||||
|
||||
Accounts.onLogout(() => { |
||||
Presence.reset(); |
||||
}); |
||||
}); |
||||
|
||||
Template.userPresence.onRendered(function () { |
||||
if (!this.data || !this.data.uid) { |
||||
return; |
||||
} |
||||
data.set(this.firstNode, this.data); |
||||
if (featureExists) { |
||||
return observer.observe(this.firstNode); |
||||
} |
||||
}); |
||||
@ -1 +0,0 @@ |
||||
export * from './client/index'; |
||||
@ -1,114 +0,0 @@ |
||||
import { FlowRouter } from 'meteor/kadira:flow-router'; |
||||
import { Session } from 'meteor/session'; |
||||
import { Emitter } from '@rocket.chat/emitter'; |
||||
|
||||
import { Subscriptions } from '../../../models/client'; |
||||
import { RoomManager } from '../../../../client/lib/RoomManager'; |
||||
import { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator'; |
||||
|
||||
export const SideNav = new (class extends Emitter<{ |
||||
changed: undefined; |
||||
}> { |
||||
private opened = false; |
||||
|
||||
private initiated = false; |
||||
|
||||
private openQueue: { |
||||
config: { |
||||
template?: string; |
||||
data: Record<string, unknown>; |
||||
}; |
||||
callback: () => void; |
||||
}[] = []; |
||||
|
||||
private animating = false; |
||||
|
||||
private sideNav: JQuery<HTMLElement>; |
||||
|
||||
private flexNav: JQuery<HTMLElement>; |
||||
|
||||
toggleFlex(status: 1 | -1, callback?: () => void): void { |
||||
if (this.animating === true) { |
||||
return; |
||||
} |
||||
|
||||
this.animating = true; |
||||
|
||||
if (status === -1 || (status !== 1 && this.opened)) { |
||||
this.opened = false; |
||||
this.flexNav.addClass('animated-hidden'); |
||||
} else { |
||||
this.opened = true; |
||||
this.flexNav.removeClass('animated-hidden'); |
||||
} |
||||
|
||||
this.emit('changed'); |
||||
|
||||
!this.opened && this.setFlex(); |
||||
this.animating = false; |
||||
typeof callback === 'function' && callback(); |
||||
} |
||||
|
||||
closeFlex(callback: () => void = (): void => undefined): void { |
||||
const routeName = FlowRouter.current().route?.name; |
||||
if (!routeName || !roomCoordinator.isRouteNameKnown(routeName)) { |
||||
const subscription = Subscriptions.findOne({ rid: RoomManager.lastRid }); |
||||
if (subscription) { |
||||
roomCoordinator.openRouteLink(subscription.t, subscription, FlowRouter.current().queryParams); |
||||
} else { |
||||
FlowRouter.go('home'); |
||||
} |
||||
} |
||||
if (this.animating === true) { |
||||
return; |
||||
} |
||||
this.toggleFlex(-1, callback); |
||||
} |
||||
|
||||
flexStatus(): boolean { |
||||
return this.opened; |
||||
} |
||||
|
||||
setFlex(template?: string, data = {}): void { |
||||
Session.set('flex-nav-template', template); |
||||
return Session.set('flex-nav-data', data); |
||||
} |
||||
|
||||
getFlex(): { |
||||
template?: string; |
||||
data: Record<string, unknown>; |
||||
} { |
||||
return { |
||||
template: Session.get('flex-nav-template'), |
||||
data: Session.get('flex-nav-data'), |
||||
}; |
||||
} |
||||
|
||||
openFlex(callback = (): void => undefined): void { |
||||
if (!this.initiated) { |
||||
this.openQueue.push({ |
||||
config: this.getFlex(), |
||||
callback, |
||||
}); |
||||
return; |
||||
} |
||||
if (this.animating === true) { |
||||
return; |
||||
} |
||||
this.toggleFlex(1, callback); |
||||
} |
||||
|
||||
init(): void { |
||||
this.sideNav = $('.sidebar'); |
||||
this.flexNav = this.sideNav.find('.flex-nav'); |
||||
this.setFlex(''); |
||||
this.initiated = true; |
||||
if (this.openQueue.length > 0) { |
||||
this.openQueue.forEach((item) => { |
||||
this.setFlex(item.config.template, item.config.data); |
||||
return this.openFlex(item.callback); |
||||
}); |
||||
this.openQueue = []; |
||||
} |
||||
} |
||||
})(); |
||||
@ -1,121 +0,0 @@ |
||||
import { Session } from 'meteor/session'; |
||||
import { Meteor } from 'meteor/meteor'; |
||||
import { Emitter } from '@rocket.chat/emitter'; |
||||
|
||||
import { isRTLScriptLanguage } from '../../../../client/lib/utils/isRTLScriptLanguage'; |
||||
|
||||
const sideNavW = 280; |
||||
const map = (x, in_min, in_max, out_min, out_max) => ((x - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min; |
||||
|
||||
export const menu = new (class extends Emitter { |
||||
constructor() { |
||||
super(); |
||||
this._open = false; |
||||
|
||||
this.sideNavW = sideNavW; |
||||
} |
||||
|
||||
get isRtl() { |
||||
return isRTLScriptLanguage(Meteor._localStorage.getItem('userLanguage')); |
||||
} |
||||
|
||||
translate(diff, width = sideNavW) { |
||||
if (diff === undefined) { |
||||
diff = this.isRtl ? -1 * sideNavW : sideNavW; |
||||
} |
||||
this.sidebarWrap.css('width', '100%'); |
||||
this.wrapper.css('overflow', 'hidden'); |
||||
this.sidebarWrap.css('background-color', '#000'); |
||||
this.sidebarWrap.css('opacity', map(Math.abs(diff) / width, 0, 1, -0.1, 0.8).toFixed(2)); |
||||
this.isRtl |
||||
? this.sidebar.css('transform', `translate3d(${(sideNavW + diff).toFixed(3)}px, 0 , 0)`) |
||||
: this.sidebar.css('transform', `translate3d(${(diff - sideNavW).toFixed(3)}px, 0 , 0)`); |
||||
} |
||||
|
||||
init() { |
||||
this.menu = $('.sidebar'); |
||||
this.sidebar = this.menu; |
||||
this.sidebarWrap = $('.sidebar-wrap'); |
||||
this.wrapper = $('.messages-box > .wrapper'); |
||||
const ignore = (fn) => (event) => document.body.clientWidth <= 780 && fn(event); |
||||
|
||||
this.sidebarWrap.on( |
||||
'click', |
||||
ignore((e) => { |
||||
e.target === this.sidebarWrap[0] && this.isOpen() && this.emit('clickOut', e); |
||||
}), |
||||
); |
||||
this.on('close', () => { |
||||
this.sidebarWrap.css('width', ''); |
||||
// this.sidebarWrap.css('z-index', '');
|
||||
this.sidebarWrap.css('background-color', ''); |
||||
this.sidebar.css('transform', ''); |
||||
this.sidebar.css('box-shadow', ''); |
||||
this.sidebar.css('transition', ''); |
||||
this.sidebarWrap.css('transition', ''); |
||||
this.wrapper && this.wrapper.css('overflow', ''); |
||||
}); |
||||
this.on( |
||||
'open', |
||||
ignore(() => { |
||||
this.sidebar.css('box-shadow', '0 0 15px 1px rgba(0,0,0,.3)'); |
||||
// this.sidebarWrap.css('z-index', '9998');
|
||||
this.translate(); |
||||
}), |
||||
); |
||||
this.mainContent = $('.main-content'); |
||||
|
||||
this.list = $('.rooms-list'); |
||||
this._open = false; |
||||
Session.set('isMenuOpen', this._open); |
||||
} |
||||
|
||||
closePopover() { |
||||
return this.menu.find('[data-popover="anchor"]:checked').prop('checked', false).length > 0; |
||||
} |
||||
|
||||
isOpen() { |
||||
return Session.get('isMenuOpen'); |
||||
} |
||||
|
||||
open() { |
||||
this._open = true; |
||||
Session.set('isMenuOpen', this._open); |
||||
this.emit('change'); |
||||
this.emit('open'); |
||||
} |
||||
|
||||
close() { |
||||
this._open = false; |
||||
Session.set('isMenuOpen', this._open); |
||||
this.emit('change'); |
||||
this.emit('close'); |
||||
} |
||||
|
||||
toggle() { |
||||
return this.isOpen() ? this.close() : this.open(); |
||||
} |
||||
})(); |
||||
|
||||
let passClosePopover = false; |
||||
|
||||
menu.on('clickOut', function () { |
||||
if (!menu.closePopover()) { |
||||
passClosePopover = true; |
||||
menu.close(); |
||||
} |
||||
}); |
||||
|
||||
menu.on('close', function () { |
||||
if (!menu.sidebar) { |
||||
return; |
||||
} |
||||
|
||||
menu.sidebar.css('transition', ''); |
||||
menu.sidebarWrap.css('transition', ''); |
||||
if (passClosePopover) { |
||||
passClosePopover = false; |
||||
return; |
||||
} |
||||
menu.closePopover(); |
||||
}); |
||||
@ -1,21 +0,0 @@ |
||||
import _ from 'underscore'; |
||||
|
||||
import { menu } from '../../../ui-utils'; |
||||
|
||||
window.addEventListener( |
||||
'resize', |
||||
_.debounce( |
||||
(() => { |
||||
let lastState = window.matchMedia('(min-width: 780px)').matches ? 'mini' : 'large'; |
||||
menu.close(); |
||||
return () => { |
||||
const futureState = window.matchMedia('(min-width: 780px)').matches ? 'mini' : 'large'; |
||||
if (lastState !== futureState) { |
||||
lastState = futureState; |
||||
menu.close(); |
||||
} |
||||
}; |
||||
})(), |
||||
100, |
||||
), |
||||
); |
||||
@ -0,0 +1,127 @@ |
||||
import { css } from '@rocket.chat/css-in-js'; |
||||
import { Box } from '@rocket.chat/fuselage'; |
||||
import { useLayout, useUserPreference } from '@rocket.chat/ui-contexts'; |
||||
import React from 'react'; |
||||
|
||||
import SidebarRoomList from './RoomList'; |
||||
import SidebarFooter from './footer'; |
||||
import SidebarHeader from './header'; |
||||
|
||||
const Sidebar = () => { |
||||
const sidebarViewMode = useUserPreference('sidebarViewMode'); |
||||
const sidebarHideAvatar = !useUserPreference('sidebarDisplayAvatar'); |
||||
const { isMobile, sidebar } = useLayout(); |
||||
|
||||
const sideBarStyle = css` |
||||
position: relative; |
||||
z-index: 2; |
||||
display: flex; |
||||
flex-direction: column; |
||||
flex: 0 0 var(--sidebar-width); |
||||
width: var(--sidebar-width); |
||||
max-width: var(--sidebar-width); |
||||
height: 100%; |
||||
user-select: none; |
||||
transition: transform 0.3s; |
||||
background-color: var(--sidebar-background); |
||||
|
||||
&.opened { |
||||
box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 15px 1px; |
||||
transform: translate3d(0px, 0px, 0px); |
||||
} |
||||
|
||||
@media (width < 768px) { |
||||
position: absolute; |
||||
user-select: none; |
||||
transform: translate3d(-100%, 0, 0); |
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); |
||||
touch-action: pan-y; |
||||
-webkit-user-drag: none; |
||||
will-change: transform; |
||||
|
||||
.rtl & { |
||||
transform: translate3d(200%, 0, 0); |
||||
} |
||||
} |
||||
|
||||
@media (width <= 400px) { |
||||
flex: 0 0 var(--sidebar-small-width); |
||||
width: var(--sidebar-small-width); |
||||
max-width: var(--sidebar-small-width); |
||||
|
||||
&__footer { |
||||
display: none; |
||||
} |
||||
|
||||
&:not(&--light) { |
||||
transform: translate3d(-100%, 0, 0); |
||||
} |
||||
|
||||
.rtl & { |
||||
transform: translate3d(200%, 0, 0); |
||||
} |
||||
} |
||||
|
||||
@media (min-width: 1372px) { |
||||
/* 1440px -68px (eletron menu) */ |
||||
flex: 0 0 20%; |
||||
|
||||
width: 20%; |
||||
max-width: 20%; |
||||
} |
||||
`;
|
||||
|
||||
const sidebarWrapStyle = css` |
||||
position: absolute; |
||||
z-index: 1; |
||||
top: 0; |
||||
left: 0; |
||||
height: 100%; |
||||
user-select: none; |
||||
transition: opacity 0.3s; |
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); |
||||
touch-action: pan-y; |
||||
-webkit-user-drag: none; |
||||
|
||||
&.opened { |
||||
width: 100%; |
||||
background-color: rgb(0, 0, 0); |
||||
opacity: 0.8; |
||||
} |
||||
`;
|
||||
|
||||
return ( |
||||
<> |
||||
<Box |
||||
id='sidebar-region' |
||||
className={[ |
||||
'rcx-sidebar', |
||||
'sidebar--main', |
||||
`sidebar--${sidebarViewMode}`, |
||||
sidebarHideAvatar && 'sidebar--hide-avatar', |
||||
!sidebar.isCollapsed && isMobile && 'opened', |
||||
sideBarStyle, |
||||
].filter(Boolean)} |
||||
> |
||||
<Box |
||||
display='flex' |
||||
flexDirection='column' |
||||
height='100%' |
||||
is='nav' |
||||
className='rcx-sidebar--template' |
||||
role='navigation' |
||||
data-qa-opened={sidebar.isCollapsed ? 'false' : 'true'} |
||||
> |
||||
<SidebarHeader /> |
||||
<SidebarRoomList /> |
||||
<SidebarFooter /> |
||||
</Box> |
||||
</Box> |
||||
{isMobile && ( |
||||
<Box className={[sidebarWrapStyle, !sidebar.isCollapsed && 'opened'].filter(Boolean)} onClick={() => sidebar.toggle()}></Box> |
||||
)} |
||||
</> |
||||
); |
||||
}; |
||||
|
||||
export default Sidebar; |
||||
@ -0,0 +1,16 @@ |
||||
import { Box } from '@rocket.chat/fuselage'; |
||||
import type { FC } from 'react'; |
||||
import React, { memo } from 'react'; |
||||
import { createPortal } from 'react-dom'; |
||||
|
||||
const SidebarPortal: FC = ({ children }) => { |
||||
const sidebarRoot = document.getElementById('sidebar-region'); |
||||
|
||||
if (!sidebarRoot) { |
||||
return null; |
||||
} |
||||
|
||||
return createPortal(<Box className='rcx-sidebar flex-nav'>{children}</Box>, sidebarRoot); |
||||
}; |
||||
|
||||
export default memo<typeof SidebarPortal>(SidebarPortal); |
||||
@ -0,0 +1 @@ |
||||
export { default } from './Sidebar'; |
||||
@ -1,15 +1,18 @@ |
||||
import type { FC } from 'react'; |
||||
import React, { useEffect } from 'react'; |
||||
import React from 'react'; |
||||
|
||||
import { SideNav } from '../../../app/ui-utils/client'; |
||||
import SidebarPortal from '../../sidebar/SidebarPortal'; |
||||
import AdminSidebar from './sidebar/AdminSidebar'; |
||||
|
||||
const AdministrationLayout: FC = ({ children }) => { |
||||
useEffect(() => { |
||||
SideNav.setFlex('adminFlex'); |
||||
SideNav.openFlex(); |
||||
}, []); |
||||
|
||||
return <>{children}</>; |
||||
return ( |
||||
<> |
||||
<SidebarPortal> |
||||
<AdminSidebar /> |
||||
</SidebarPortal> |
||||
{children} |
||||
</> |
||||
); |
||||
}; |
||||
|
||||
export default AdministrationLayout; |
||||
|
||||
Loading…
Reference in new issue