Update new UI for mobile

This commit is contained in:
lethemanh
2024-12-19 14:17:25 +07:00
parent 57dfbaff84
commit f87d85a9e2
18 changed files with 336 additions and 99 deletions
+2 -1
View File
@@ -35,7 +35,7 @@
"components.add_mails_workspace.text_area_placeholder": "Enter emails of your users*", "components.add_mails_workspace.text_area_placeholder": "Enter emails of your users*",
"components.alert.confirm": "Confirm your action", "components.alert.confirm": "Confirm your action",
"components.alert.confirm_click": "Confirm your action by clicking on OK.", "components.alert.confirm_click": "Confirm your action by clicking on OK.",
"components.create_folder_modal.hint": "Choose a name for the new folder.", "components.create_folder_modal.hint": "Create a folder",
"components.create_folder_modal.placeholder": "Folder name", "components.create_folder_modal.placeholder": "Folder name",
"components.create_link_modal.button": "Create link", "components.create_link_modal.button": "Create link",
"components.create_link_modal.hint": "Link name", "components.create_link_modal.hint": "Link name",
@@ -48,6 +48,7 @@
"components.disk_usage.in_trash": "in trash", "components.disk_usage.in_trash": "in trash",
"components.disk_usage.of": "of", "components.disk_usage.of": "of",
"components.disk_usage.used": "used", "components.disk_usage.used": "used",
"components.disk_usage.title": "Storage",
"components.dragndrop_info_move_to": "move to", "components.dragndrop_info_move_to": "move to",
"components.drive_dropzone.uploading": "Uploading...", "components.drive_dropzone.uploading": "Uploading...",
"components.header_path.my_trash": "My Trash", "components.header_path.my_trash": "My Trash",
+1
View File
@@ -48,6 +48,7 @@
"components.disk_usage.in_trash": "dans la corbeille", "components.disk_usage.in_trash": "dans la corbeille",
"components.disk_usage.of": "sur", "components.disk_usage.of": "sur",
"components.disk_usage.used": "utilisé(s)", "components.disk_usage.used": "utilisé(s)",
"components.disk_usage.title": "Stockage",
"components.dragndrop_info_move_to": "déplacé vers", "components.dragndrop_info_move_to": "déplacé vers",
"components.drive_dropzone.uploading": "Téléchargement...", "components.drive_dropzone.uploading": "Téléchargement...",
"components.header_path.my_trash": "Ma corbeille", "components.header_path.my_trash": "Ma corbeille",
+1
View File
@@ -48,6 +48,7 @@
"components.disk_usage.in_trash": "в корзине", "components.disk_usage.in_trash": "в корзине",
"components.disk_usage.of": "из", "components.disk_usage.of": "из",
"components.disk_usage.used": "использовано", "components.disk_usage.used": "использовано",
"components.disk_usage.title": "хранилище",
"components.dragndrop_info_move_to": "move to", "components.dragndrop_info_move_to": "move to",
"components.drive_dropzone.uploading": "Загрузка...", "components.drive_dropzone.uploading": "Загрузка...",
"components.header_path.my_trash": "Корзина \"Моего диска\"", "components.header_path.my_trash": "Корзина \"Моего диска\"",
+2 -1
View File
@@ -35,7 +35,7 @@
"components.add_mails_workspace.text_area_placeholder": "Nhập email của người dùng của bạn*", "components.add_mails_workspace.text_area_placeholder": "Nhập email của người dùng của bạn*",
"components.alert.confirm": "Xác nhận hành động của bạn", "components.alert.confirm": "Xác nhận hành động của bạn",
"components.alert.confirm_click": "Xác nhận hành động của bạn bằng cách nhấp vào OK.", "components.alert.confirm_click": "Xác nhận hành động của bạn bằng cách nhấp vào OK.",
"components.create_folder_modal.hint": "Chọn tên cho thư mục mới.", "components.create_folder_modal.hint": "Tạo folder",
"components.create_folder_modal.placeholder": "Tên thư mục", "components.create_folder_modal.placeholder": "Tên thư mục",
"components.create_link_modal.button": "Tạo liên kết", "components.create_link_modal.button": "Tạo liên kết",
"components.create_link_modal.hint": "Tên liên kết", "components.create_link_modal.hint": "Tên liên kết",
@@ -46,6 +46,7 @@
"components.create_modal.upload_folders": "Tải lên thư mục từ thiết bị", "components.create_modal.upload_folders": "Tải lên thư mục từ thiết bị",
"components.disk_usage.in_trash": "trong thùng rác", "components.disk_usage.in_trash": "trong thùng rác",
"components.disk_usage.used": "đã sử dụng", "components.disk_usage.used": "đã sử dụng",
"components.disk_usage.title": "Lưu trữ",
"components.dragndrop_info_move_to": "di chuyển đến", "components.dragndrop_info_move_to": "di chuyển đến",
"components.drive_dropzone.uploading": "Đang tải lên...", "components.drive_dropzone.uploading": "Đang tải lên...",
"components.header_path.my_trash": "Thùng rác của tôi", "components.header_path.my_trash": "Thùng rác của tôi",
@@ -64,7 +64,8 @@ export default class Menu extends React.Component {
elementRect, elementRect,
this.props.position, this.props.position,
undefined, undefined,
this.props.testClassId this.props.testClassId,
this.props.enableMobileMenu,
); );
this.setState({ isMenuOpen: true }, () => this.open = true); this.setState({ isMenuOpen: true }, () => this.open = true);
this.open = true; this.open = true;
@@ -1,9 +1,10 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import MenusManager from '@components/menus/menus-manager.jsx'; import MenusManager from '@components/menus/menus-manager';
import MenuComponent from './menu-component.jsx'; import MenuComponent from './menu-component';
import OutsideClickHandler from 'react-outside-click-handler'; import OutsideClickHandler from 'react-outside-click-handler';
import MobileMenu from './mobile-menu';
/* /*
Where the menu will be displayed, this component should be in app.js (menus should be over all elements of the page) Where the menu will be displayed, this component should be in app.js (menus should be over all elements of the page)
@@ -194,24 +195,45 @@ export default class MenusBodyLayer extends React.Component {
marginLeft: item.position.marginLeft, marginLeft: item.position.marginLeft,
}} }}
> >
<MenuComponent {item.enableMobileMenu ? (
withFrame <MobileMenu
menu={item.menu} withFrame
openAt={item.openAt} menu={item.menu}
level={item.level} openAt={item.openAt}
animationClass={ level={item.level}
this.state.menus_manager.willClose || item.willClose animationClass={
? 'fade_out' this.state.menus_manager.willClose || item.willClose
: item.level === 0 || item.positionType ? 'fade_out'
? item.positionType === 'bottom' : item.level === 0 || item.positionType
? 'skew_in_bottom_nobounce' ? item.positionType === 'bottom'
: item.left ? 'skew_in_bottom_nobounce'
? 'skew_in_left_nobounce' : item.left
: 'skew_in_right_nobounce' ? 'skew_in_left_nobounce'
: 'fade_in' : 'skew_in_right_nobounce'
} : 'fade_in'
testClassId={item.menuTestClassId} }
/> testClassId={item.menuTestClassId}
/>
) : (
<MenuComponent
withFrame
menu={item.menu}
openAt={item.openAt}
level={item.level}
animationClass={
this.state.menus_manager.willClose || item.willClose
? 'fade_out'
: item.level === 0 || item.positionType
? item.positionType === 'bottom'
? 'skew_in_bottom_nobounce'
: item.left
? 'skew_in_left_nobounce'
: 'skew_in_right_nobounce'
: 'fade_in'
}
testClassId={item.menuTestClassId}
/>
)}
</div> </div>
</OutsideClickHandler> </OutsideClickHandler>
); );
@@ -57,7 +57,7 @@ class MenusManager extends Observable {
this.notify(); this.notify();
} }
async openMenu(menu, domRect, positionType, options, menuTestClassId) { async openMenu(menu, domRect, positionType, options, menuTestClassId, enableMobileMenu) {
this.isOpen = 1; this.isOpen = 1;
if(typeof menu === 'function') { if(typeof menu === 'function') {
menu = await menu(); menu = await menu();
@@ -86,6 +86,7 @@ class MenusManager extends Observable {
id: Number.unid(), id: Number.unid(),
allowClickOut: options.allowClickOut !== undefined ? options.allowClickOut : true, allowClickOut: options.allowClickOut !== undefined ? options.allowClickOut : true,
menuTestClassId, menuTestClassId,
enableMobileMenu,
}); });
this.last_opened_id = Number.unid(); this.last_opened_id = Number.unid();
this.notify(); this.notify();
@@ -0,0 +1,161 @@
import React, { Component } from 'react';
import Icon from '@components/icon/icon.jsx';
import { Modal, ModalContent } from '@atoms/modal';
import Emojione from 'components/emojione/emojione';
import MenusManager from '@components/menus/menus-manager.jsx';
import './menu.scss';
/*
One menu
*/
export default class MobileMenu extends React.Component {
constructor(props) {
super();
this.state = {
menus_manager: MenusManager,
};
MenusManager.addListener(this);
}
componentWillUnmount() {
MenusManager.removeListener(this);
}
openSubMenu(dom_element, menu, level) {
var elementRect = window.getBoundingClientRect(dom_element);
elementRect.x = elementRect.x || elementRect.left;
elementRect.y = elementRect.y || elementRect.top;
MenusManager.openSubMenu(menu, elementRect, level);
}
closeSubMenu(level) {
MenusManager.closeSubMenu(level);
}
hoverMenu(dom_element, item) {
if (item.submenu && !item.submenu_replace) {
this.last_hovered = item;
this.openSubMenu(dom_element, item.submenu, this.props.level || 0);
} else {
this.closeSubMenu(this.props.level || 0);
}
}
clickMenu(dom_element, item, evt) {
if(Date.now() - this.props.openAt < 200 ){
// When a menu is open and another one opens above it, you have to block the buttons for a while. Otherwise, the hovered option of the new menu will be clicked
return;
}
if (item.submenu_replace) {
this.state.menus_manager.openMenu(item.submenu, { x: evt.clientX, y: evt.clientY }, 'center');
return;
}
if (item.onClick) {
var res = item.onClick(evt);
if (res !== false) {
this.state.menus_manager.closeMenu();
}
}
}
render() {
return (
<Modal
open={this.state.menus_manager.isOpen === 1}
closable={true}
onClose={() => this.state.menus_manager.closeMenu()}
className={`md:!max-w-sm testid:${this.props.testClassId}`}
disableCountVisibleModals={true}
>
<ModalContent title="">
<div
ref={node => (this.original_menu = node)}
className={
'menu-list sm:py-0 ' + (this.props.withFrame ? 'text-black bg-white dark:bg-zinc-900 dark:text-white rounded-lg ' : '') + this.props.animationClass
}>
{(this.props.menu || [])
.filter(item => item && !item.hide)
.map((item, index) => {
if (item.type == 'separator') {
return <div key={'menu_' + index} className="menu-separator" />;
} else if (item.type == 'title') {
return (
<div key={'menu_' + index} className={'menu-title ' + item.className}>
{item.text}
</div>
);
} else if (item.type == 'text') {
return (
<div
key={'menu_' + index}
ref={node => (item.ref = node)}
className={'menu-text ' + item.className + ' testid:menu-item'}
onMouseEnter={evt => {
this.hoverMenu(item.ref, item);
}}
>
{item.icon && (
<div className="icon">
{typeof item.icon === 'string' ? <Icon type={item.icon} /> : item.icon}
</div>
)}
<div className={`text testid:menu-item-${item.testClassId}`}>{item.text}</div>
</div>
);
} else if (item.type == 'react-element') {
return (
<div
key={'menu_' + index}
className={'menu-custom ' + item.className + ' testid:menu-item'}
onClick={item.onClick}
>
{typeof item.reactElement == 'function'
? item.reactElement(this.props.level)
: item.reactElement}
</div>
);
} else {
return (
<div
key={'menu_' + index}
ref={node => (item.ref = node)}
className={
'menu ' +
item.className +
' ' +
(this.state.menus_manager.max_level > this.props.level &&
this.last_hovered == item
? 'hovered '
: '') +
(item.selected ? 'selected ' : '') +
' testid:menu-item'
}
onMouseEnter={evt => {
this.hoverMenu(item.ref, item);
}}
onClick={evt => {
this.clickMenu(item.ref, item, evt);
}}
>
{item.icon && (
<div className="icon">
{typeof item.icon === 'string' ? <Icon type={item.icon} /> : item.icon}
</div>
)}
{item.emoji && (
<div className="icon">
<Emojione type={item.emoji} />
</div>
)}
<div className={`text testid:menu-item-${item.testClassId}`}>{item.text}</div>
<div className="more">
{item.rightIcon && <Icon type={item.rightIcon} />}
{item.submenu && !item.submenu_replace && <Icon type="angle-right" />}
</div>
</div>
);
}
})
}
</div>
</ModalContent>
</Modal>
);
}
}
@@ -224,7 +224,8 @@ export default memo(
key: index, key: index,
className: className:
(index === 0 ? 'rounded-t-md ' : '-mt-px ') + (index === 0 ? 'rounded-t-md ' : '-mt-px ') +
(index === items.length - 1 ? 'rounded-b-md ' : ''), (index === items.length - 1 ? 'rounded-b-md ' : '') +
'border-0 md:border',
item: child, item: child,
checked: checked[child.id] || false, checked: checked[child.id] || false,
onCheck: (v: boolean) => setChecked(_.pickBy({ ...checked, [child.id]: v }, _.identity)), onCheck: (v: boolean) => setChecked(_.pickBy({ ...checked, [child.id]: v }, _.identity)),
@@ -358,7 +359,7 @@ export default memo(
(loading && (!items?.length || loadingParentChange) ? 'opacity-50 ' : '') (loading && (!items?.length || loadingParentChange) ? 'opacity-50 ' : '')
} }
> >
<div className={`flex flex-row shrink-0 items-center mb-4 ${!sharedWithMe ? 'flex-wrap' : ''}`}> <div className={`flex flex-row shrink-0 items-center mb-4 ${!sharedWithMe ? 'flex-wrap' : ''} border-b md:border-b-0 px-4 py-2 md:px-0 md:py-0`}>
{sharedWithMe ? ( {sharedWithMe ? (
<div> <div>
<Title className="mb-4 block"> <Title className="mb-4 block">
@@ -445,14 +446,14 @@ export default memo(
<div className="grow" /> <div className="grow" />
{access !== 'read' && ( {access !== 'read' && (
<BaseSmall> <BaseSmall className="hidden md:block">
{formatBytes(item?.size || 0)} {Languages.t('scenes.app.drive.used')} {formatBytes(item?.size || 0)} {Languages.t('scenes.app.drive.used')}
</BaseSmall> </BaseSmall>
)} )}
<Menu menu={() => onBuildSortContextMenu()} sortData={sortLabel} testClassId="browser-menu-sorting"> <Menu menu={() => onBuildSortContextMenu()} sortData={sortLabel} testClassId="browser-menu-sorting">
{' '} {' '}
<Button theme="outline" className="ml-4 flex flex-row items-center" testClassId="button-sorting"> <Button theme="outline" className="ml-4 flex flex-row items-center border-0 md:border !text-gray-500 md:!text-blue-500 px-0 md:px-4" testClassId="button-sorting">
<SortIcon <SortIcon
className={`h-4 w-4 mr-2 -ml-1 ${ className={`h-4 w-4 mr-2 -ml-1 ${
sortLabel.order === 'asc' ? 'transform rotate-180' : '' sortLabel.order === 'asc' ? 'transform rotate-180' : ''
@@ -467,7 +468,7 @@ export default memo(
{viewId !== 'shared_with_me' && ( {viewId !== 'shared_with_me' && (
<Menu menu={() => onBuildContextMenu(details)} testClassId="browser-menu-more"> <Menu menu={() => onBuildContextMenu(details)} testClassId="browser-menu-more">
{' '} {' '}
<Button theme="secondary" className="ml-4 flex flex-row items-center" testClassId="button-more"> <Button theme="secondary" className="ml-4 flex flex-row items-center bg-transparent md:bg-blue-500 md:bg-opacity-25 !text-gray-500 md:!text-blue-500 px-0 md:px-4" testClassId="button-more">
<span> <span>
{selectedCount > 1 {selectedCount > 1
? `${selectedCount} items` ? `${selectedCount} items`
@@ -510,7 +511,8 @@ export default memo(
key={index} key={index}
className={ className={
(index === 0 ? 'rounded-t-md ' : '-mt-px ') + (index === 0 ? 'rounded-t-md ' : '-mt-px ') +
(index === items.length - 1 ? 'rounded-b-md ' : '') (index === items.length - 1 ? 'rounded-b-md ' : '') +
'border-0 md:border'
} }
item={child} item={child}
onClick={() => { onClick={() => {
@@ -44,6 +44,8 @@ export const DocumentRow = ({
// history.push(RouterServices.generateRouteFromState({ companyId: company, itemId: item.id })); // history.push(RouterServices.generateRouteFromState({ companyId: company, itemId: item.id }));
}; };
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
return ( return (
<div <div
className={ className={
@@ -78,17 +80,17 @@ export const DocumentRow = ({
fallback={<DocumentIcon item={item} />} fallback={<DocumentIcon item={item} />}
/> />
</div> </div>
<div className="md:grow text-ellipsis whitespace-nowrap"> <div className="grow text-ellipsis whitespace-nowrap overflow-hidden">
<Base className={`block text-ellipsis whitespace-nowrap overflow-hidden ${hasAnyPublicLinkAccess(item) ? 'w-[38px]' : 'w-[74px]'} md:w-full`}>{item.name}</Base> <Base className={`block text-ellipsis whitespace-nowrap overflow-hidden max-w-full`}>{item.name}</Base>
</div> </div>
<div className="shrink-0 md:ml-4"> <div className="shrink-0 md:ml-4">
{hasAnyPublicLinkAccess(item) && <PublicIcon className="h-5 w-5 text-blue-500 ml-4" />} {hasAnyPublicLinkAccess(item) && <PublicIcon className="h-5 w-5 ml-4 text-gray-500 md:text-blue-500" />}
</div> </div>
<div className="shrink-0 ml-4 md:mr-12"> <div className="shrink-0 ml-4 md:mr-12 hidden md:block">
<BaseSmall>{formatDateShort(item?.last_version_cache?.date_added)}</BaseSmall> <BaseSmall>{formatDateShort(item?.last_version_cache?.date_added)}</BaseSmall>
</div> </div>
<div className="shrink-0 ml-4 mr-4 md:mr-none text-right lg:w-24 sm:w-20 "> <div className="shrink-0 ml-4 mr-4 md:mr-none text-right lg:w-24 sm:w-20 ">
<BaseSmall>{formatBytes(item.size)}</BaseSmall> <BaseSmall className="text-gray-500 dark:md:text-white md:text-black">{formatBytes(item.size)}</BaseSmall>
</div> </div>
{FeatureTogglesService.isActiveFeatureName(FeatureNames.COMPANY_AV_ENABLED) && ( {FeatureTogglesService.isActiveFeatureName(FeatureNames.COMPANY_AV_ENABLED) && (
<div className="shrink-0 ml-4 text-right lg:w-24 sm:w-20 "> <div className="shrink-0 ml-4 text-right lg:w-24 sm:w-20 ">
@@ -102,11 +104,11 @@ export const DocumentRow = ({
</div> </div>
)} )}
<div className="shrink-0 ml-auto md:ml-4"> <div className="shrink-0 ml-auto md:ml-4">
<Menu menu={onBuildContextMenu} testClassId="document-row-menu"> <Menu menu={onBuildContextMenu} enableMobileMenu={isMobile} testClassId="document-row-menu">
<Button <Button
theme={'secondary'} theme={'secondary'}
size="sm" size="sm"
className={'!rounded-full '} className={'!rounded-full !text-gray-500 md:!text-blue-500 bg-transparent md:bg-blue-500 md:bg-opacity-25 '}
icon={DotsHorizontalIcon} icon={DotsHorizontalIcon}
testClassId="document-row-button-open-menu" testClassId="document-row-button-open-menu"
/> />
@@ -20,6 +20,8 @@ export const FolderRow = ({
}: DriveItemProps) => { }: DriveItemProps) => {
const [hover, setHover] = useState(false); const [hover, setHover] = useState(false);
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
return ( return (
<div <div
className={ className={
@@ -48,22 +50,22 @@ export const FolderRow = ({
/> />
</div> </div>
<div className="grow whitespace-nowrap overflow-hidden"> <div className="grow whitespace-nowrap overflow-hidden">
<Base className="!font-semibold text-ellipsis overflow-hidden block max-w-full">{item.name}</Base> <Base className="text-ellipsis overflow-hidden block max-w-full">{item.name}</Base>
</div> </div>
<div className="shrink-0 ml-4"> <div className="shrink-0 ml-4">
{hasAnyPublicLinkAccess(item) && ( {hasAnyPublicLinkAccess(item) && (
<PublicIcon className="h-5 w-5 text-blue-500" /> <PublicIcon className="h-5 w-5 text-gray-500 md:text-blue-500" />
)} )}
</div> </div>
<div className="shrink-0 ml-4 text-right minWidth80"> <div className="shrink-0 ml-4 text-right minWidth80">
<BaseSmall>{formatBytes(item.size)}</BaseSmall> <BaseSmall className="text-gray-500 dark:md:text-white md:text-black">{formatBytes(item.size)}</BaseSmall>
</div> </div>
<div className="shrink-0 ml-4"> <div className="shrink-0 ml-4">
<Menu menu={onBuildContextMenu} testClassId="folder-row-menu"> <Menu menu={onBuildContextMenu} enableMobileMenu={isMobile} testClassId="folder-row-menu">
<Button <Button
theme={'secondary'} theme={'secondary'}
size="sm" size="sm"
className={'!rounded-full '} className={'!rounded-full !text-gray-500 md:!text-blue-500 bg-transparent md:bg-blue-500 md:bg-opacity-25 '}
icon={DotsHorizontalIcon} icon={DotsHorizontalIcon}
testClassId="folder-row-button-open-menu" testClassId="folder-row-button-open-menu"
/> />
@@ -1,6 +1,6 @@
import { Title } from '@atoms/text'; import { Title } from '@atoms/text';
import { DriveItem } from '@features/drive/types'; import { DriveItem } from '@features/drive/types';
import { ChevronDownIcon } from '@heroicons/react/solid'; import { ChevronDownIcon, ChevronLeftIcon } from '@heroicons/react/solid';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { PublicIcon } from './components/public-icon'; import { PublicIcon } from './components/public-icon';
import MenusManager from '@components/menus/menus-manager.jsx'; import MenusManager from '@components/menus/menus-manager.jsx';
@@ -74,46 +74,65 @@ export const PathRender = ({
const pathLength = (pathToRender || []).reduce((acc, curr) => acc + curr.name.length, 0); const pathLength = (pathToRender || []).reduce((acc, curr) => acc + curr.name.length, 0);
return ( return (
<nav className="overflow-hidden whitespace-nowrap mr-2 pl-px inline-flex md:max-w-[50%] sm:max-w-[20%] testid:header-path"> <>
{pathLength < 70 ? ( <nav className="overflow-hidden whitespace-nowrap mr-2 pl-px hidden md:inline-flex max-w-[50%] testid:header-path">
(pathToRender || [])?.map((a, i) => ( {pathLength < 70 ? (
<PathItem (pathToRender || [])?.map((a, i) => (
key={a.id} <PathItem
item={a} key={a.id}
first={i === 0} item={a}
last={i + 1 === pathToRender?.length} first={i === 0}
onClick={onClick} last={i + 1 === pathToRender?.length}
/> onClick={onClick}
)) />
) : ( ))
<> ) : (
<PathItem <>
key={pathToRender[pathToRender.length - 3]?.id} <PathItem
item={{ key={pathToRender[pathToRender.length - 3]?.id}
...pathToRender[pathToRender?.length - 3], item={{
name: '...', ...pathToRender[pathToRender?.length - 3],
}} name: '...',
first={true} }}
last={false} first={true}
onClick={onClick} last={false}
/> onClick={onClick}
<PathItem />
key={pathToRender[pathToRender.length - 2]?.id} <PathItem
item={pathToRender[pathToRender?.length - 2]} key={pathToRender[pathToRender.length - 2]?.id}
first={false} item={pathToRender[pathToRender?.length - 2]}
last={false} first={false}
onClick={onClick} last={false}
/> onClick={onClick}
<PathItem />
key={pathToRender[pathToRender.length - 1]?.id} <PathItem
item={pathToRender[pathToRender?.length - 1]} key={pathToRender[pathToRender.length - 1]?.id}
first={false} item={pathToRender[pathToRender?.length - 1]}
last={true} first={false}
onClick={onClick} last={true}
/> onClick={onClick}
</> />
)} </>
</nav> )}
</nav>
<nav className="overflow-hidden whitespace-nowrap mr-2 pl-px inline-flex md:hidden max-w-[50%] testid:header-path">
<PathItem
key={pathToRender[pathToRender.length - 2]?.id}
item={pathToRender[pathToRender?.length - 2]}
first={false}
last={false}
isPreviousItemInMobile={true}
onClick={onClick}
/>
<PathItem
key={pathToRender[pathToRender.length - 1]?.id}
item={pathToRender[pathToRender?.length - 1]}
first={false}
last={true}
onClick={onClick}
/>
</nav>
</>
); );
}; };
@@ -121,11 +140,13 @@ const PathItem = ({
item, item,
first, first,
last, last,
isPreviousItemInMobile,
onClick, onClick,
}: { }: {
item: Partial<DriveItem>; item: Partial<DriveItem>;
last?: boolean; last?: boolean;
first?: boolean; first?: boolean;
isPreviousItemInMobile?: boolean;
onClick: (viewId: string, dirId: string) => void; onClick: (viewId: string, dirId: string) => void;
}) => { }) => {
const { user } = useCurrentUser(); const { user } = useCurrentUser();
@@ -181,11 +202,15 @@ const PathItem = ({
} }
}} }}
> >
<Title noColor={last} className={!first ? 'text-blue-500 inline-block overflow-hidden text-ellipsis max-w-36' : ''}> <Title noColor={last} className={!first ? 'text-black dark:text-white md:text-blue-500 inline-block overflow-hidden text-ellipsis max-w-full' : ''}>
{(() => { {(() => {
const isTrash = viewId?.includes('trash_') || viewId === 'trash'; const isTrash = viewId?.includes('trash_') || viewId === 'trash';
const fileName = cutFileName(item?.name) || ''; const fileName = cutFileName(item?.name) || '';
if (isPreviousItemInMobile && fileName) {
return <ChevronLeftIcon className="w-6 h-6 mr-2 ml-[-6px]" />
}
if (first) { if (first) {
if (isTrash) { if (isTrash) {
return viewId?.includes('trash_') return viewId?.includes('trash_')
@@ -202,15 +227,15 @@ const PathItem = ({
})()} })()}
</Title> </Title>
</a> </a>
{hasAnyPublicLinkAccess(item) && ( {hasAnyPublicLinkAccess(item) && !isPreviousItemInMobile && (
<PublicIcon className="h-5 w-5 ml-2" /> <PublicIcon className="h-5 w-5 ml-2" />
)} )}
{first && !!user?.id && viewId?.includes('trash') && ( {first && !!user?.id && viewId?.includes('trash') && !isPreviousItemInMobile && (
<span className="ml-2 -mr-1 text-gray-700"> <span className="ml-2 -mr-1 text-gray-700">
<ChevronDownIcon className="w-4 h-4" /> <ChevronDownIcon className="w-4 h-4" />
</span> </span>
)} )}
{!last && ( {!last && !isPreviousItemInMobile && (
<svg <svg
aria-hidden="true" aria-hidden="true"
className="w-6 h-6 text-gray-400 mx-1" className="w-6 h-6 text-gray-400 mx-1"
@@ -3,7 +3,7 @@ import { useRecoilState } from 'recoil';
import { CreateModalAtom } from '.'; import { CreateModalAtom } from '.';
import { Button } from '@atoms/button/button'; import { Button } from '@atoms/button/button';
import { Input } from '@atoms/input/input-text'; import { Input } from '@atoms/input/input-text';
import { Info } from '@atoms/text'; import { Base } from '@atoms/text';
import { useDriveActions } from '@features/drive/hooks/use-drive-actions'; import { useDriveActions } from '@features/drive/hooks/use-drive-actions';
import Languages from "features/global/services/languages-service"; import Languages from "features/global/services/languages-service";
@@ -29,7 +29,7 @@ export const CreateFolder = () => {
return ( return (
<> <>
<Info>{ Languages.t('components.create_folder_modal.hint')}</Info> <Base className="!font-medium">{ Languages.t('components.create_folder_modal.hint')}</Base>
<div ref={inputRef}> <div ref={inputRef}>
<Input <Input
disabled={loading} disabled={loading}
@@ -45,12 +45,13 @@ export const CreateModal = ({
return ( return (
<Modal <Modal
open={state.open} open={state.open}
closable={true}
onClose={() => setState({ ...state, open: false })} onClose={() => setState({ ...state, open: false })}
className="!max-w-sm testid:create-modal" className="md:!max-w-sm testid:create-modal"
> >
<ModalContent <ModalContent
title={ title={
<div className="flex flex-row items-center justify-start"> <div className="hidden md:flex flex-row items-center justify-start">
{!!state.type && ( {!!state.type && (
<A onClick={() => setState({ ...state, type: '' })}> <A onClick={() => setState({ ...state, type: '' })}>
<ChevronLeftIcon className="w-6 h-6" /> <ChevronLeftIcon className="w-6 h-6" />
@@ -183,7 +184,7 @@ const CreateModalOption = (props: { testClassId?: string; icon: ReactNode; text:
return ( return (
<div <div
onClick={props.onClick} onClick={props.onClick}
className={`flex flex-row p-4 dark:bg-zinc-900 dark:text-white bg-zinc-100 hover:bg-opacity-75 cursor-pointer rounded-md m-2 focus:bg-zinc-800 dark:focus:bg-zinc-800 outline-none focus:border-none ${testId}`} className={`flex flex-row py-2 md:p-4 md:dark:bg-zinc-900 dark:text-white md:bg-zinc-100 md:hover:bg-opacity-75 cursor-pointer rounded-md m-2 focus:bg-zinc-800 dark:focus:bg-zinc-800 outline-none focus:border-none ${testId}`}
tabIndex={0} tabIndex={0}
onKeyUp={handleKeyPress} onKeyUp={handleKeyPress}
> >
@@ -39,12 +39,13 @@ export const UploadModal = ({
return ( return (
<Modal <Modal
open={state.open} open={state.open}
closable={true}
onClose={() => setState({ ...state, open: false })} onClose={() => setState({ ...state, open: false })}
className="!max-w-sm testid:upload-modal" className="md:!max-w-sm testid:upload-modal"
> >
<ModalContent <ModalContent
title={ title={
<div className="flex flex-row items-center justify-start"> <div className="hidden md:flex flex-row items-center justify-start">
{!!state.type && ( {!!state.type && (
<A onClick={() => setState({ ...state, type: '' })}> <A onClick={() => setState({ ...state, type: '' })}>
<ChevronLeftIcon className="w-6 h-6" /> <ChevronLeftIcon className="w-6 h-6" />
@@ -106,7 +107,7 @@ const CreateModalOption = (props: {
return ( return (
<div <div
onClick={props.onClick} onClick={props.onClick}
className={`flex flex-row p-4 dark:bg-zinc-900 dark:text-white bg-zinc-100 hover:bg-opacity-75 cursor-pointer rounded-md m-2 focus:bg-zinc-800 dark:focus:bg-zinc-800 outline-none focus:border-none testid:${props.testClassId}`} className={`flex flex-row py-2 md:p-4 md:dark:bg-zinc-900 dark:text-white md:bg-zinc-100 md:hover:bg-opacity-75 cursor-pointer rounded-md m-2 focus:bg-zinc-800 dark:focus:bg-zinc-800 outline-none focus:border-none testid:${props.testClassId}`}
tabIndex={0} tabIndex={0}
onKeyUp={handleKeyPress} onKeyUp={handleKeyPress}
> >
@@ -67,7 +67,8 @@ const DiskUsage = () => {
</div> </div>
)} )}
{!FeatureTogglesService.isActiveFeatureName(FeatureNames.COMPANY_USER_QUOTA) && ( {!FeatureTogglesService.isActiveFeatureName(FeatureNames.COMPANY_USER_QUOTA) && (
<div className="bg-zinc-500 dark:bg-zinc-900 bg-opacity-10 rounded-md p-4 w-auto max-w-md"> <div className="md:bg-zinc-500 md:dark:bg-zinc-900 md:bg-opacity-10 rounded-md p-4 w-auto max-w-md">
<Base className="!font-medium md:hidden">{Languages.t('components.disk_usage.title')}</Base>
<div className="w-full"> <div className="w-full">
<Base className="testid:disk-usage-text"> <Base className="testid:disk-usage-text">
{formatBytesToInt(usedBytes)} {formatBytesToInt(usedBytes)}
@@ -73,7 +73,7 @@ export default React.memo((): JSX.Element => {
onClick={() => setMenuIsOpen(false)} onClick={() => setMenuIsOpen(false)}
className="absolute left-0 top-0 h-full w-full bg-black bg-opacity-50 transition-all z-40 opacity-0" className="absolute left-0 top-0 h-full w-full bg-black bg-opacity-50 transition-all z-40 opacity-0"
></div> ></div>
<div className="bg-white dark:bg-zinc-900 flex grow sm:rounded-lg p-4 sm:w-2/3 overflow-x-hidden"> <div className="bg-white dark:bg-zinc-900 flex grow sm:rounded-lg sm:w-2/3 overflow-x-hidden p-0 md:p-4">
<Suspense fallback={<></>}> <Suspense fallback={<></>}>
<MainView className={classNames({ collapsed: menuIsOpen })} /> <MainView className={classNames({ collapsed: menuIsOpen })} />
</Suspense> </Suspense>
@@ -52,10 +52,24 @@ export default () => {
<div className="grow"> <div className="grow">
<div className="sm:hidden block mb-2"> <div className="sm:hidden block mb-2">
<div className="flex flex-row space-between w-full"> <div className="flex flex-row space-between w-full">
<div className="grow"> <div className="flex items-center order-1 grow">
<img
src="/public/img/logo/logo-text-black.svg"
className="h-6 ml-1 dark:hidden block"
alt="Tdrive"
/>
<img
src="/public/img/logo/logo-text-white.svg"
className="h-6 ml-1 dark:block hidden"
alt="Tdrive"
/>
</div>
<div className="md:grow order-3 md:order-2">
<Account /> <Account />
</div> </div>
<AppGrid /> <div className="order-2 md:order-3 mr-2 md:mr-0">
<AppGrid />
</div>
</div> </div>
<div className="mt-6" /> <div className="mt-6" />