2021-02-04 07:02:36 +00:00
|
|
|
import React, { useRef, useEffect, useState, useCallback } from "react";
|
|
|
|
|
import styled from "styled-components";
|
|
|
|
|
import {
|
2022-03-17 10:28:54 +00:00
|
|
|
ApplicationPayload,
|
2021-02-04 07:02:36 +00:00
|
|
|
PageListPayload,
|
2022-04-12 10:50:01 +00:00
|
|
|
} from "@appsmith/constants/ReduxActionConstants";
|
2021-11-08 05:41:42 +00:00
|
|
|
import Icon, { IconSize } from "components/ads/Icon";
|
2021-02-04 07:02:36 +00:00
|
|
|
import PageTabs from "./PageTabs";
|
|
|
|
|
import useThrottledRAF from "utils/hooks/useThrottledRAF";
|
2021-11-08 05:41:42 +00:00
|
|
|
import { Colors } from "constants/Colors";
|
2021-02-04 07:02:36 +00:00
|
|
|
|
|
|
|
|
const Container = styled.div`
|
|
|
|
|
width: 100%;
|
|
|
|
|
align-items: center;
|
2022-05-04 09:45:57 +00:00
|
|
|
|
2021-02-04 07:02:36 +00:00
|
|
|
& {
|
|
|
|
|
svg path,
|
|
|
|
|
svg:hover path {
|
2021-11-08 05:41:42 +00:00
|
|
|
fill: ${Colors.BLACK};
|
2021-02-04 07:02:36 +00:00
|
|
|
stroke: ${(props) => props.theme.colors.header.tabText};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
border-bottom: 1px solid
|
|
|
|
|
${(props) => props.theme.colors.header.tabsHorizontalSeparator};
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const ScrollBtnContainer = styled.div<{ visible: boolean }>`
|
|
|
|
|
cursor: pointer;
|
2022-05-04 09:45:57 +00:00
|
|
|
display: flex;
|
|
|
|
|
position: absolute;
|
|
|
|
|
height: 100%;
|
|
|
|
|
padding: 0 10px;
|
|
|
|
|
|
|
|
|
|
& > span {
|
|
|
|
|
background: white;
|
|
|
|
|
position: relative;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-04 07:02:36 +00:00
|
|
|
${(props) =>
|
|
|
|
|
props.visible
|
|
|
|
|
? `
|
|
|
|
|
visibility: visible;
|
|
|
|
|
opacity: 1;
|
2022-05-04 09:45:57 +00:00
|
|
|
z-index: 1;
|
2021-02-04 07:02:36 +00:00
|
|
|
transition: visibility 0s linear 0s, opacity 300ms;
|
|
|
|
|
`
|
|
|
|
|
: `
|
|
|
|
|
visibility: hidden;
|
|
|
|
|
opacity: 0;
|
|
|
|
|
transition: visibility 0s linear 300ms, opacity 300ms;
|
|
|
|
|
`}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
type AppViewerHeaderProps = {
|
2022-03-17 10:28:54 +00:00
|
|
|
currentApplicationDetails?: ApplicationPayload;
|
2021-02-04 07:02:36 +00:00
|
|
|
pages: PageListPayload;
|
|
|
|
|
};
|
|
|
|
|
|
2021-04-28 10:28:39 +00:00
|
|
|
export function PageTabsContainer(props: AppViewerHeaderProps) {
|
2021-02-04 07:02:36 +00:00
|
|
|
const { currentApplicationDetails, pages } = props;
|
|
|
|
|
|
|
|
|
|
// Mark default page as first page
|
|
|
|
|
const appPages = pages;
|
|
|
|
|
if (appPages.length > 1) {
|
|
|
|
|
appPages.forEach((item, i) => {
|
|
|
|
|
if (item.isDefault) {
|
|
|
|
|
appPages.splice(i, 1);
|
|
|
|
|
appPages.unshift(item);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const tabsRef = useRef<HTMLElement | null>(null);
|
|
|
|
|
const [tabsScrollable, setTabsScrollable] = useState(false);
|
|
|
|
|
const [shouldShowLeftArrow, setShouldShowLeftArrow] = useState(false);
|
|
|
|
|
const [shouldShowRightArrow, setShouldShowRightArrow] = useState(true);
|
|
|
|
|
|
|
|
|
|
const setShowScrollArrows = useCallback(() => {
|
|
|
|
|
if (tabsRef.current) {
|
2021-05-13 08:35:39 +00:00
|
|
|
const { offsetWidth, scrollLeft, scrollWidth } = tabsRef.current;
|
2021-02-04 07:02:36 +00:00
|
|
|
setShouldShowLeftArrow(scrollLeft > 0);
|
|
|
|
|
setShouldShowRightArrow(scrollLeft + offsetWidth < scrollWidth);
|
|
|
|
|
}
|
|
|
|
|
}, [tabsRef.current]);
|
|
|
|
|
|
|
|
|
|
const measuredTabsRef = useCallback((node) => {
|
|
|
|
|
tabsRef.current = node;
|
|
|
|
|
if (node !== null) {
|
2021-05-13 08:35:39 +00:00
|
|
|
const { offsetWidth, scrollWidth } = node;
|
2021-02-04 07:02:36 +00:00
|
|
|
setTabsScrollable(scrollWidth > offsetWidth);
|
|
|
|
|
setShowScrollArrows();
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const [isScrolling, setIsScrolling] = useState(false);
|
|
|
|
|
const [isScrollingLeft, setIsScrollingLeft] = useState(false);
|
|
|
|
|
|
|
|
|
|
const scroll = useCallback(() => {
|
|
|
|
|
const currentOffset = tabsRef.current?.scrollLeft || 0;
|
|
|
|
|
|
|
|
|
|
if (tabsRef.current) {
|
|
|
|
|
tabsRef.current.scrollLeft = isScrollingLeft
|
|
|
|
|
? currentOffset - 5
|
|
|
|
|
: currentOffset + 5;
|
|
|
|
|
setShowScrollArrows();
|
|
|
|
|
}
|
|
|
|
|
}, [tabsRef.current, isScrollingLeft]);
|
|
|
|
|
// eslint-disable-next-line
|
|
|
|
|
const [_intervalRef, _rafRef, requestAF] = useThrottledRAF(scroll, 10);
|
|
|
|
|
|
|
|
|
|
const stopScrolling = () => {
|
|
|
|
|
setIsScrolling(false);
|
|
|
|
|
setIsScrollingLeft(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const startScrolling = (isLeft: boolean) => {
|
|
|
|
|
setIsScrolling(true);
|
|
|
|
|
setIsScrollingLeft(isLeft);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
let clear;
|
|
|
|
|
if (isScrolling) {
|
|
|
|
|
clear = requestAF();
|
|
|
|
|
}
|
|
|
|
|
return clear;
|
|
|
|
|
}, [isScrolling, isScrollingLeft]);
|
|
|
|
|
|
|
|
|
|
return appPages.length > 1 ? (
|
2022-05-04 09:45:57 +00:00
|
|
|
<Container className="relative hidden px-6 h-9 md:flex">
|
2021-02-04 07:02:36 +00:00
|
|
|
<ScrollBtnContainer
|
2022-05-04 09:45:57 +00:00
|
|
|
className="left-0"
|
2021-02-04 07:02:36 +00:00
|
|
|
onMouseDown={() => startScrolling(true)}
|
|
|
|
|
onMouseLeave={stopScrolling}
|
2021-04-28 10:28:39 +00:00
|
|
|
onMouseUp={stopScrolling}
|
2021-02-09 05:35:06 +00:00
|
|
|
onTouchEnd={stopScrolling}
|
2021-04-28 10:28:39 +00:00
|
|
|
onTouchStart={() => startScrolling(true)}
|
2021-02-04 07:02:36 +00:00
|
|
|
visible={shouldShowLeftArrow}
|
|
|
|
|
>
|
2021-11-08 05:41:42 +00:00
|
|
|
<Icon name="left-arrow-2" size={IconSize.MEDIUM} />
|
2021-02-04 07:02:36 +00:00
|
|
|
</ScrollBtnContainer>
|
|
|
|
|
<PageTabs
|
|
|
|
|
appPages={appPages}
|
|
|
|
|
currentApplicationDetails={currentApplicationDetails}
|
2021-04-28 10:28:39 +00:00
|
|
|
measuredTabsRef={measuredTabsRef}
|
2021-02-04 07:02:36 +00:00
|
|
|
setShowScrollArrows={setShowScrollArrows}
|
2021-04-28 10:28:39 +00:00
|
|
|
tabsScrollable={tabsScrollable}
|
2021-02-04 07:02:36 +00:00
|
|
|
/>
|
|
|
|
|
<ScrollBtnContainer
|
2022-05-04 09:45:57 +00:00
|
|
|
className="right-0"
|
2021-02-04 07:02:36 +00:00
|
|
|
onMouseDown={() => startScrolling(false)}
|
|
|
|
|
onMouseLeave={stopScrolling}
|
2021-04-28 10:28:39 +00:00
|
|
|
onMouseUp={stopScrolling}
|
2021-02-09 05:35:06 +00:00
|
|
|
onTouchEnd={stopScrolling}
|
2021-04-28 10:28:39 +00:00
|
|
|
onTouchStart={() => startScrolling(false)}
|
2021-02-04 07:02:36 +00:00
|
|
|
visible={shouldShowRightArrow}
|
|
|
|
|
>
|
2021-11-08 05:41:42 +00:00
|
|
|
<Icon name="right-arrow-2" size={IconSize.MEDIUM} />
|
2021-02-04 07:02:36 +00:00
|
|
|
</ScrollBtnContainer>
|
|
|
|
|
</Container>
|
|
|
|
|
) : null;
|
2021-04-28 10:28:39 +00:00
|
|
|
}
|
2021-02-04 07:02:36 +00:00
|
|
|
|
|
|
|
|
export default PageTabsContainer;
|