mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-04-23 19:37:52 +00:00
added tabs
This commit is contained in:
parent
28c2dfbb7a
commit
54b1725585
@ -3,7 +3,7 @@ import { AppViewer } from './AppViewer'
|
|||||||
import Frame from 'react-frame-component';
|
import Frame from 'react-frame-component';
|
||||||
import { MyContext } from '../../App';
|
import { MyContext } from '../../App';
|
||||||
|
|
||||||
const AppViewerContainer = ({app, isSelected}) => {
|
const AppViewerContainer = ({app, isSelected, hide}) => {
|
||||||
const { rootHeight } = useContext(MyContext);
|
const { rootHeight } = useContext(MyContext);
|
||||||
const frameRef = useRef(null);
|
const frameRef = useRef(null);
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ const AppViewerContainer = ({app, isSelected}) => {
|
|||||||
height: `calc(${rootHeight} - 60px - 45px)`,
|
height: `calc(${rootHeight} - 60px - 45px)`,
|
||||||
border: 'none',
|
border: 'none',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
display: !isSelected && 'none'
|
display: (!isSelected || hide) && 'none'
|
||||||
}} ><AppViewer app={app} /></Frame>
|
}} ><AppViewer app={app} /></Frame>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -186,9 +186,23 @@ import {
|
|||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: 'flex-start',
|
justifyContent: 'flex-start',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
flexGrow: 1
|
||||||
}));
|
}));
|
||||||
export const AppsNavBarRight = styled(Box)(({ theme }) => ({
|
export const AppsNavBarRight = styled(Box)(({ theme }) => ({
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: 'flex-end',
|
justifyContent: 'flex-end',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
export const TabParent = styled(Box)(({ theme }) => ({
|
||||||
|
height: '36px',
|
||||||
|
width: '36px',
|
||||||
|
backgroundColor: '#434343',
|
||||||
|
position: 'relative',
|
||||||
|
borderRadius: '50%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { Spacer } from '../../common/Spacer'
|
|||||||
import { MyContext, getBaseApiReact } from '../../App'
|
import { MyContext, getBaseApiReact } from '../../App'
|
||||||
import { AppsLibrary } from './AppsLibrary'
|
import { AppsLibrary } from './AppsLibrary'
|
||||||
import { AppInfo } from './AppInfo'
|
import { AppInfo } from './AppInfo'
|
||||||
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events'
|
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from '../../utils/events'
|
||||||
import { AppsNavBar } from './AppsNavBar'
|
import { AppsNavBar } from './AppsNavBar'
|
||||||
import { AppsParent } from './Apps-styles'
|
import { AppsParent } from './Apps-styles'
|
||||||
import { AppViewer } from './AppViewer'
|
import { AppViewer } from './AppViewer'
|
||||||
@ -14,13 +14,24 @@ import ShortUniqueId from "short-unique-id";
|
|||||||
const uid = new ShortUniqueId({ length: 8 });
|
const uid = new ShortUniqueId({ length: 8 });
|
||||||
|
|
||||||
|
|
||||||
export const Apps = ({mode, setMode}) => {
|
export const Apps = ({mode, setMode, show}) => {
|
||||||
const [availableQapps, setAvailableQapps] = useState([])
|
const [availableQapps, setAvailableQapps] = useState([])
|
||||||
const [downloadedQapps, setDownloadedQapps] = useState([])
|
const [downloadedQapps, setDownloadedQapps] = useState([])
|
||||||
const [selectedAppInfo, setSelectedAppInfo] = useState(null)
|
const [selectedAppInfo, setSelectedAppInfo] = useState(null)
|
||||||
const [tabs, setTabs] = useState([])
|
const [tabs, setTabs] = useState([])
|
||||||
const [selectedTab, setSelectedTab] = useState(null)
|
const [selectedTab, setSelectedTab] = useState(null)
|
||||||
|
const [isNewTabWindow, setIsNewTabWindow] = useState(false)
|
||||||
|
|
||||||
|
useEffect(()=> {
|
||||||
|
setTimeout(() => {
|
||||||
|
executeEvent('setTabsToNav', {
|
||||||
|
data: {
|
||||||
|
tabs: tabs,
|
||||||
|
selectedTab: selectedTab
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 100);
|
||||||
|
}, [show, tabs, selectedTab])
|
||||||
|
|
||||||
const getQapps = React.useCallback(
|
const getQapps = React.useCallback(
|
||||||
async () => {
|
async () => {
|
||||||
@ -85,8 +96,8 @@ export const Apps = ({mode, setMode}) => {
|
|||||||
} else if(mode === 'library'){
|
} else if(mode === 'library'){
|
||||||
setMode('home')
|
setMode('home')
|
||||||
} else {
|
} else {
|
||||||
|
const iframeId = `browser-iframe-${selectedTab?.tabId}`
|
||||||
const iframe = document.getElementById('browser-iframe2');
|
const iframe = document.getElementById(iframeId);
|
||||||
console.log('iframe', iframe)
|
console.log('iframe', iframe)
|
||||||
// Go Back in the iframe's history
|
// Go Back in the iframe's history
|
||||||
if (iframe) {
|
if (iframe) {
|
||||||
@ -108,7 +119,7 @@ if (iframe) {
|
|||||||
return () => {
|
return () => {
|
||||||
unsubscribeFromEvent("navigateBack", navigateBackFunc);
|
unsubscribeFromEvent("navigateBack", navigateBackFunc);
|
||||||
};
|
};
|
||||||
}, [mode]);
|
}, [mode, selectedTab]);
|
||||||
|
|
||||||
|
|
||||||
const addTabFunc = (e) => {
|
const addTabFunc = (e) => {
|
||||||
@ -119,6 +130,9 @@ if (iframe) {
|
|||||||
}
|
}
|
||||||
setTabs((prev)=> [...prev, newTab])
|
setTabs((prev)=> [...prev, newTab])
|
||||||
setSelectedTab(newTab)
|
setSelectedTab(newTab)
|
||||||
|
setMode('viewer')
|
||||||
|
|
||||||
|
setIsNewTabWindow(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -127,10 +141,76 @@ if (iframe) {
|
|||||||
return () => {
|
return () => {
|
||||||
unsubscribeFromEvent("addTab", addTabFunc);
|
unsubscribeFromEvent("addTab", addTabFunc);
|
||||||
};
|
};
|
||||||
}, [mode]);
|
}, [tabs]);
|
||||||
|
|
||||||
|
|
||||||
|
const setSelectedTabFunc = (e) => {
|
||||||
|
const data = e.detail?.data;
|
||||||
|
|
||||||
|
|
||||||
|
setSelectedTab(data)
|
||||||
|
setTimeout(() => {
|
||||||
|
executeEvent('setTabsToNav', {
|
||||||
|
data: {
|
||||||
|
tabs: tabs,
|
||||||
|
selectedTab: data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 100);
|
||||||
|
setIsNewTabWindow(false)
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
subscribeToEvent("setSelectedTab", setSelectedTabFunc);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribeFromEvent("setSelectedTab", setSelectedTabFunc);
|
||||||
|
};
|
||||||
|
}, [tabs]);
|
||||||
|
|
||||||
|
const removeTabFunc = (e) => {
|
||||||
|
const data = e.detail?.data;
|
||||||
|
const copyTabs = [...tabs].filter((tab)=> tab?.tabId !== data?.tabId)
|
||||||
|
if(copyTabs?.length === 0){
|
||||||
|
setMode('home')
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
setSelectedTab(copyTabs[0])
|
||||||
|
}
|
||||||
|
setTabs(copyTabs)
|
||||||
|
setSelectedTab(copyTabs[0])
|
||||||
|
setTimeout(() => {
|
||||||
|
executeEvent('setTabsToNav', {
|
||||||
|
data: {
|
||||||
|
tabs: copyTabs,
|
||||||
|
selectedTab: copyTabs[0]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 400);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
subscribeToEvent("removeTab", removeTabFunc);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribeFromEvent("removeTab", removeTabFunc);
|
||||||
|
};
|
||||||
|
}, [tabs]);
|
||||||
|
|
||||||
|
const setNewTabWindowFunc = (e) => {
|
||||||
|
setIsNewTabWindow(true)
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
subscribeToEvent("newTabWindow", setNewTabWindowFunc);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribeFromEvent("newTabWindow", setNewTabWindowFunc);
|
||||||
|
};
|
||||||
|
}, [tabs]);
|
||||||
|
|
||||||
|
if(!show) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppsParent>
|
<AppsParent>
|
||||||
@ -141,14 +221,14 @@ if (iframe) {
|
|||||||
{mode === 'home' && <AppsHome downloadedQapps={downloadedQapps} setMode={setMode} />}
|
{mode === 'home' && <AppsHome downloadedQapps={downloadedQapps} setMode={setMode} />}
|
||||||
{mode === 'library' && <AppsLibrary downloadedQapps={downloadedQapps} availableQapps={availableQapps} />}
|
{mode === 'library' && <AppsLibrary downloadedQapps={downloadedQapps} availableQapps={availableQapps} />}
|
||||||
{mode === 'appInfo' && <AppInfo app={selectedAppInfo} />}
|
{mode === 'appInfo' && <AppInfo app={selectedAppInfo} />}
|
||||||
{mode === 'viewer' && (
|
|
||||||
<>
|
|
||||||
{tabs.map((tab)=> {
|
{tabs.map((tab)=> {
|
||||||
return <AppViewerContainer isSelected={tab?.tabId === selectedTab?.tabId} app={tab} />
|
return <AppViewerContainer hide={isNewTabWindow} isSelected={tab?.tabId === selectedTab?.tabId} app={tab} />
|
||||||
})}
|
})}
|
||||||
</>
|
|
||||||
) }
|
{isNewTabWindow && (
|
||||||
|
<AppsHome downloadedQapps={downloadedQapps} setMode={setMode} />
|
||||||
|
)}
|
||||||
{mode !== 'viewer' && (
|
{mode !== 'viewer' && (
|
||||||
<Spacer height="180px" />
|
<Spacer height="180px" />
|
||||||
|
|
||||||
|
@ -1,17 +1,48 @@
|
|||||||
import React from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
AppsNavBarLeft,
|
AppsNavBarLeft,
|
||||||
AppsNavBarParent,
|
AppsNavBarParent,
|
||||||
AppsNavBarRight,
|
AppsNavBarRight,
|
||||||
} from "./Apps-styles";
|
} from "./Apps-styles";
|
||||||
import NavBack from "../../assets/svgs/NavBack.svg";
|
import NavBack from "../../assets/svgs/NavBack.svg";
|
||||||
import NavCloseTab from "../../assets/svgs/NavCloseTab.svg";
|
|
||||||
import NavAdd from "../../assets/svgs/NavAdd.svg";
|
import NavAdd from "../../assets/svgs/NavAdd.svg";
|
||||||
import NavMoreMenu from "../../assets/svgs/NavMoreMenu.svg";
|
import NavMoreMenu from "../../assets/svgs/NavMoreMenu.svg";
|
||||||
import { ButtonBase } from "@mui/material";
|
import { ButtonBase, Tab, Tabs } from "@mui/material";
|
||||||
import { executeEvent } from "../../utils/events";
|
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
|
||||||
|
import TabComponent from "./TabComponent";
|
||||||
|
|
||||||
export const AppsNavBar = () => {
|
export const AppsNavBar = () => {
|
||||||
|
const [tabs, setTabs] = useState([])
|
||||||
|
const [selectedTab, setSelectedTab] = useState([])
|
||||||
|
|
||||||
|
const tabsRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Scroll to the last tab whenever the tabs array changes (e.g., when a new tab is added)
|
||||||
|
if (tabsRef.current) {
|
||||||
|
const tabElements = tabsRef.current.querySelectorAll('.MuiTab-root');
|
||||||
|
console.log('tabElements', tabElements)
|
||||||
|
if (tabElements.length > 0) {
|
||||||
|
const lastTab = tabElements[tabElements.length - 1];
|
||||||
|
lastTab.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'end' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [tabs.length]); // Dependency on the number of tabs
|
||||||
|
|
||||||
|
const setTabsToNav = (e) => {
|
||||||
|
const {tabs, selectedTab} = e.detail?.data;
|
||||||
|
|
||||||
|
setTabs([...tabs])
|
||||||
|
setSelectedTab({...selectedTab})
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
subscribeToEvent("setTabsToNav", setTabsToNav);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribeFromEvent("setTabsToNav", setTabsToNav);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
return (
|
return (
|
||||||
<AppsNavBarParent>
|
<AppsNavBarParent>
|
||||||
<AppsNavBarLeft>
|
<AppsNavBarLeft>
|
||||||
@ -21,11 +52,43 @@ export const AppsNavBar = () => {
|
|||||||
}}>
|
}}>
|
||||||
<img src={NavBack} />
|
<img src={NavBack} />
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
<Tabs
|
||||||
|
ref={tabsRef}
|
||||||
|
aria-label="basic tabs example"
|
||||||
|
variant="scrollable" // Make tabs scrollable
|
||||||
|
scrollButtons={false}
|
||||||
|
sx={{
|
||||||
|
"& .MuiTabs-indicator": {
|
||||||
|
backgroundColor: "white",
|
||||||
|
},
|
||||||
|
maxWidth: `calc(100vw - 150px)`, // Ensure the tabs container fits within the available space
|
||||||
|
overflow: 'hidden', // Prevents overflow on small screens
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tabs?.map((tab) => (
|
||||||
|
<Tab
|
||||||
|
key={tab.tabId}
|
||||||
|
label={<TabComponent isSelected={tab?.tabId === selectedTab?.tabId} app={tab} />} // Pass custom component
|
||||||
|
sx={{
|
||||||
|
"&.Mui-selected": {
|
||||||
|
color: "white",
|
||||||
|
},
|
||||||
|
padding: '0px',
|
||||||
|
margin: '0px',
|
||||||
|
minWidth: '0px',
|
||||||
|
width: '50px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
</AppsNavBarLeft>
|
</AppsNavBarLeft>
|
||||||
<AppsNavBarRight sx={{
|
<AppsNavBarRight sx={{
|
||||||
gap: '10px'
|
gap: '10px'
|
||||||
}}>
|
}}>
|
||||||
<ButtonBase>
|
<ButtonBase onClick={()=> {
|
||||||
|
executeEvent("newTabWindow", {
|
||||||
|
});
|
||||||
|
}}>
|
||||||
<img style={{
|
<img style={{
|
||||||
height: '40px',
|
height: '40px',
|
||||||
width: '40px'
|
width: '40px'
|
||||||
|
61
src/components/Apps/TabComponent.tsx
Normal file
61
src/components/Apps/TabComponent.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { TabParent } from './Apps-styles'
|
||||||
|
import NavCloseTab from "../../assets/svgs/NavCloseTab.svg";
|
||||||
|
import { getBaseApiReact } from '../../App';
|
||||||
|
import { Avatar, ButtonBase } from '@mui/material';
|
||||||
|
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
||||||
|
import { executeEvent } from '../../utils/events';
|
||||||
|
|
||||||
|
const TabComponent = ({isSelected, app}) => {
|
||||||
|
return (
|
||||||
|
<ButtonBase onClick={()=> {
|
||||||
|
if(isSelected){
|
||||||
|
executeEvent('removeTab', {
|
||||||
|
data: app
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
executeEvent('setSelectedTab', {
|
||||||
|
data: app
|
||||||
|
})
|
||||||
|
}}>
|
||||||
|
<TabParent sx={{
|
||||||
|
border: isSelected && '1px solid #FFFFFF'
|
||||||
|
}}>
|
||||||
|
{isSelected && (
|
||||||
|
|
||||||
|
<img style={
|
||||||
|
{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '-5px',
|
||||||
|
right: '-5px',
|
||||||
|
zIndex: 1
|
||||||
|
}
|
||||||
|
} src={NavCloseTab}/>
|
||||||
|
|
||||||
|
) }
|
||||||
|
<Avatar
|
||||||
|
sx={{
|
||||||
|
height: "31px",
|
||||||
|
width: "31px",
|
||||||
|
}}
|
||||||
|
alt={app?.name}
|
||||||
|
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
|
||||||
|
app?.name
|
||||||
|
}/qortal_avatar?async=true`}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
style={{
|
||||||
|
width: "31px",
|
||||||
|
height: "auto",
|
||||||
|
}}
|
||||||
|
src={LogoSelected}
|
||||||
|
alt="center-icon"
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
</TabParent>
|
||||||
|
</ButtonBase>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TabComponent
|
@ -433,7 +433,7 @@ export const Group = ({
|
|||||||
const { clearStatesMessageQueueProvider } = useMessageQueue();
|
const { clearStatesMessageQueueProvider } = useMessageQueue();
|
||||||
const initiatedGetMembers = useRef(false);
|
const initiatedGetMembers = useRef(false);
|
||||||
const [groupChatTimestamps, setGroupChatTimestamps] = React.useState({});
|
const [groupChatTimestamps, setGroupChatTimestamps] = React.useState({});
|
||||||
const [appsMode, setAppsMode] = useState('viewer')
|
const [appsMode, setAppsMode] = useState('home')
|
||||||
|
|
||||||
useEffect(()=> {
|
useEffect(()=> {
|
||||||
timestampEnterDataRef.current = timestampEnterData
|
timestampEnterDataRef.current = timestampEnterData
|
||||||
@ -2736,8 +2736,8 @@ export const Group = ({
|
|||||||
setMobileViewMode={setMobileViewMode}
|
setMobileViewMode={setMobileViewMode}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isMobile && mobileViewMode === "apps" && (
|
{isMobile && (
|
||||||
<Apps mode={appsMode} setMode={setAppsMode} />
|
<Apps mode={appsMode} setMode={setAppsMode} show={mobileViewMode === "apps"} />
|
||||||
)}
|
)}
|
||||||
{
|
{
|
||||||
!isMobile && !selectedGroup &&
|
!isMobile && !selectedGroup &&
|
||||||
|
Loading…
x
Reference in New Issue
Block a user