Skip to content

Commit

Permalink
tab visual indicators and minor css fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
rayzhou-bit committed Feb 25, 2024
1 parent 799b746 commit 690d55d
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 83 deletions.
4 changes: 2 additions & 2 deletions src/components/Card/Content.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ const Content = ({
});

return (
<div className="content">
<div className='content'>
<textarea
className='text'
onBlur={endContentEdit}
onChange={(e) => changeContentValue(e.target.value)}
onClick={beginContentEdit}
onDragOver={(e) => e.preventDefault()}
onWheel={(e) => e.stopPropagation()}
placeholder="Fill me in!"
placeholder='Fill me in!'
readOnly={readOnly}
ref={contentRef}
value={contentValue}
Expand Down
3 changes: 1 addition & 2 deletions src/components/Card/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ $title-height: 32px;

.color-btn {
background-color: transparent;
img { padding-top: 2px; }
&:hover > img { content: url('../../assets/icons/rounded-square-hover.svg'); }
}

Expand All @@ -88,7 +87,7 @@ $title-height: 32px;
box-sizing: border-box;
height: 100%;
width: 100%;
padding: 18px 24px;
padding: 7px 14px;
margin: 0;
border: 0;
border-radius: inherit;
Expand Down
9 changes: 6 additions & 3 deletions src/components/TabBar/Tab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@ import React from 'react';
import { Rnd } from "react-rnd";

import "./index.scss";
import { TAB_WIDTH, useTabHooks } from './hooks';
import { TAB_HEIGHT, TAB_WIDTH, useTabHooks } from './hooks';
import ActionDropdown from '../../components-shared/Dropdowns/ActionDropdown';

import './index.scss';
import DropdownArrowIcon from '../../assets/icons/dropdown-arrow.svg';

const Tab = ({
id,
setDropIndicatorIndex,
}) => {
const {
setRndRef,
isActiveTab,
switchTab,
isDragging,
onDrag,
onDragStart,
onDragStop,

Expand All @@ -33,7 +35,7 @@ const Tab = ({
openTabMenuDropup,
closeTabMenuDropup,
dropUpOptions,
} = useTabHooks({ id });
} = useTabHooks({ id, setDropIndicatorIndex });

return (
<Rnd
Expand All @@ -42,11 +44,12 @@ const Tab = ({
dragAxis='x'
dragHandleClassName='input-div'
enableResizing={false}
onDrag={onDrag}
onDragStart={onDragStart}
onDragStop={onDragStop}
onClick={switchTab}
ref={node => setRndRef(node)}
size={{ width: TAB_WIDTH, height: 32 }}
size={{ width: TAB_WIDTH, height: TAB_HEIGHT }}
style={{ zIndex: isDragging ? 100 : 0 }}
>
<div
Expand Down
49 changes: 49 additions & 0 deletions src/components/TabBar/TabIndicators.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';

import { TAB_HEIGHT, TAB_WIDTH, POSITION_INCREMENT } from './hooks';

import './index.scss';

const GAP = 1;
const DROP_INDICATOR_WIDTH = POSITION_INCREMENT - TAB_WIDTH - (2 * GAP);

const TabIndicators = ({
dropIndicatorIndex,
tabCount,
}) => {
const tabShadow = () => (
<div className='tab-shadow' style={{ width: TAB_WIDTH, height: TAB_HEIGHT }} />
);
const dropIndicator = (highlight) => (
<div
className='drop-indicator'
style={{ width: DROP_INDICATOR_WIDTH, height: TAB_HEIGHT, background: highlight ? '#5BC5FF' : 'transparent' }}
/>
);

let tabIndicators = [];
for (let i = 0; i < tabCount; i++) {
tabIndicators = [
...tabIndicators,
dropIndicator(i === dropIndicatorIndex),
tabShadow(),
];
if (i === tabCount - 1) {
tabIndicators = [
...tabIndicators,
dropIndicator(i === dropIndicatorIndex),
];
}
}

return (
<div
className='tab-indicator-container'
style={{ left: -DROP_INDICATOR_WIDTH - GAP, gap: GAP }}
>
{tabIndicators}
</div>
);
};

export default TabIndicators;
40 changes: 28 additions & 12 deletions src/components/TabBar/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@ import useOutsideClick from '../../utils/useOutsideClick';

import * as actions from '../../store/actionIndex';

import RedTrashIcon from '../../assets/icons/red-trash.png';
import { PopupKeys } from '../Popup/PopupKey';

// TAB_WIDTH handles both the styling and drag movement for tabs.
export const TAB_HEIGHT = 32;
export const TAB_WIDTH = 200;
export const POSITION_INCREMENT = TAB_WIDTH + 6;
export const SCROLL_RATIO = 1.75;

export const useTabBarHooks = () => {
const tabs = useSelector(state => state.campaignData.present.viewOrder || []);
const [ position, setPosition ] = useState(0);
const [ dropIndicatorIndex, setDropIndicatorIndex ] = useState(null);
const [ lockScroll, setLockScroll ] = useState(false);
const containerRef = useRef();
const totalTabWidth = tabs.length * (TAB_WIDTH + 1);
const rightBoundary = 3*(TAB_WIDTH + 1) - totalTabWidth;
const totalTabWidth = tabs.length * POSITION_INCREMENT;
const rightBoundary = (3 * POSITION_INCREMENT) - totalTabWidth;
const containerWidth = () => containerRef.current.getBoundingClientRect().width;

const checkLock = () => {
Expand Down Expand Up @@ -46,30 +48,30 @@ export const useTabBarHooks = () => {

const scrollLeft = () => {
if (!lockScroll) {
const newPosition = position + (TAB_WIDTH + 1)*SCROLL_RATIO;
const newPosition = position + POSITION_INCREMENT * SCROLL_RATIO;
if (newPosition < 0) {
setPosition(position + (TAB_WIDTH + 1)*SCROLL_RATIO);
setPosition(position + POSITION_INCREMENT * SCROLL_RATIO);
} else {
setPosition(0);
}
}
};
const scrollRight = () => {
if (!lockScroll) {
const newPosition = position - (TAB_WIDTH + 1)*SCROLL_RATIO;
const newPosition = position - POSITION_INCREMENT * SCROLL_RATIO;
if (newPosition > rightBoundary) {
setPosition(position - (TAB_WIDTH + 1)*SCROLL_RATIO);
setPosition(position - POSITION_INCREMENT * SCROLL_RATIO);
} else {
setPosition(rightBoundary);
}
}
};
const scrollTo = (tabId) => {
if (!lockScroll) {
const tabPosition = tabs.indexOf(tabId) * (TAB_WIDTH + 1);
const tabPosition = tabs.indexOf(tabId) * POSITION_INCREMENT;
const [ leftBound, rightBound ] = [
-tabPosition,
containerWidth() - (TAB_WIDTH + 1) - tabPosition,
containerWidth() - POSITION_INCREMENT - tabPosition,
];
if (position < leftBound) {
setPosition(leftBound);
Expand All @@ -83,6 +85,8 @@ export const useTabBarHooks = () => {
tabs,
containerRef,
position,
dropIndicatorIndex,
setDropIndicatorIndex,
scrollLeft,
scrollRight,
scrollTo,
Expand Down Expand Up @@ -144,6 +148,7 @@ export const useTabControlsHooks = ({

export const useTabHooks = ({
id,
setDropIndicatorIndex,
}) => {
const dispatch = useDispatch();
const [ isDragging, setIsDragging ] = useState(false);
Expand All @@ -168,7 +173,7 @@ export const useTabHooks = ({
// Set visual position of tab when tabOrder changes
useEffect(() => {
rndRef.updatePosition({
x: tabIndex * (TAB_WIDTH + 1),
x: tabIndex * POSITION_INCREMENT,
y: 0,
});
}, [tabOrder]);
Expand Down Expand Up @@ -241,10 +246,20 @@ export const useTabHooks = ({
isActiveTab,
switchTab: () => dispatch(actions.updActiveViewId(id)),
isDragging,
onDrag: (event, data) => {
const initialX = tabIndex * POSITION_INCREMENT;
if (initialX - data.x > POSITION_INCREMENT / 2) {
setDropIndicatorIndex(Math.round(data.x / POSITION_INCREMENT));
} else if (initialX - data.x < -POSITION_INCREMENT / 2) {
setDropIndicatorIndex(Math.round(data.x / POSITION_INCREMENT) + 1);
} else {
setDropIndicatorIndex(null);
}
},
onDragStart: () => setIsDragging(true),
onDragStop: (event, data) => {
const initialX = tabIndex * (TAB_WIDTH + 1);
const deltaIndex = Math.round((data.x - initialX) / TAB_WIDTH);
const initialX = tabIndex * POSITION_INCREMENT;
const deltaIndex = Math.round((data.x - initialX) / POSITION_INCREMENT);
if (deltaIndex !== 0) {
dispatch(actions.shiftViewInViewOrder(id, deltaIndex));
} else {
Expand All @@ -254,6 +269,7 @@ export const useTabHooks = ({
});
}
setIsDragging(false);
setDropIndicatorIndex(null);
},

titleRef,
Expand Down
10 changes: 7 additions & 3 deletions src/components/TabBar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import { useTabBarHooks } from './hooks';
import TabControls from './TabControls';
import Tab from './Tab';
import TabIndicators from './TabIndicators';

import './index.scss';
import ScrollLeftIcon from '../../assets/icons/scroll-left.svg';
Expand All @@ -13,6 +14,8 @@ const TabBar = () => {
tabs,
containerRef,
position,
dropIndicatorIndex,
setDropIndicatorIndex,
scrollLeft,
scrollRight,
scrollTo,
Expand All @@ -21,21 +24,22 @@ const TabBar = () => {
isInactiveRight,
} = useTabBarHooks();

const tabList = tabs.map(tab => <Tab id={tab} />);
const tabList = tabs.map(tab => <Tab id={tab} setDropIndicatorIndex={setDropIndicatorIndex} />);

return (
<div className="tab-bar">
<div className='tab-bar'>
<TabControls scrollTo={scrollTo} />
<div
className='tab-container'
onWheel={(event) => onWheel(event)}
ref={containerRef}
>
<div
className='tab-scroll-container'
className='tab-list-container'
style={{ left: position }}
>
{tabList}
<TabIndicators dropIndicatorIndex={dropIndicatorIndex} tabCount={tabs.length} />
</div>
</div>
<div className='tab-scroll'>
Expand Down
Loading

0 comments on commit 690d55d

Please sign in to comment.