feat(lite): add Tabs component (#6096)
This commit is contained in:
@@ -14,6 +14,7 @@ import Checkbox from '../../components/Checkbox'
|
||||
import Icon from '../../components/Icon'
|
||||
import Input from '../../components/Input'
|
||||
import Select from '../../components/Select'
|
||||
import Tabs from '../../components/Tabs'
|
||||
import { alert, confirm } from '../../components/Modal'
|
||||
|
||||
interface ParentState {}
|
||||
@@ -231,6 +232,27 @@ const App = withState<State, Props, Effects, Computed, ParentState, ParentEffect
|
||||
]}
|
||||
value={state.value}
|
||||
valueRenderer='value'
|
||||
/>`}
|
||||
</Code>
|
||||
</Container>
|
||||
<h2>Tabs</h2>
|
||||
<Container>
|
||||
<Render>
|
||||
<Tabs
|
||||
tabs={[
|
||||
{ component: 'Hello BAR!', label: 'BAR', pathname: '/styleguide' },
|
||||
{ label: 'FOO', pathname: '/styleguide/foo' },
|
||||
]}
|
||||
useUrl
|
||||
/>
|
||||
</Render>
|
||||
<Code>
|
||||
{`<Tabs
|
||||
tabs={[
|
||||
{ component: 'Hello BAR!', label: 'BAR', pathname: '/styleguide' },
|
||||
{ label: 'FOO', pathname: '/styleguide/foo' },
|
||||
]}
|
||||
useUrl
|
||||
/>`}
|
||||
</Code>
|
||||
</Container>
|
||||
|
||||
@@ -172,6 +172,33 @@ const mdTheme = createTheme({
|
||||
main: '#ffc107',
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
fontFamily: 'inter',
|
||||
h2: {
|
||||
fontWeight: 500,
|
||||
fontSize: '2.25em',
|
||||
fontStyle: 'medium',
|
||||
lineHeight: '3em',
|
||||
},
|
||||
h3: {
|
||||
fontWeight: 500,
|
||||
fontSize: '1.5em',
|
||||
fontStyle: 'medium',
|
||||
lineHeight: '2em',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
MuiTab: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: '#E8E8E8',
|
||||
fontStyle: 'medium',
|
||||
fontSize: '1.25em',
|
||||
textAlign: 'center',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const FullPage = styledComponent.div`
|
||||
@@ -314,6 +341,9 @@ const App = withState<State, Props, Effects, Computed, ParentState, ParentEffect
|
||||
<Route exact path='/styleguide'>
|
||||
<StyleGuide />
|
||||
</Route>
|
||||
<Route exact path='/styleguide/foo'>
|
||||
<StyleGuide />
|
||||
</Route>
|
||||
<Route exact path='/pool'>
|
||||
<PoolTab />
|
||||
</Route>
|
||||
|
||||
114
@xen-orchestra/lite/src/components/Tabs.tsx
Normal file
114
@xen-orchestra/lite/src/components/Tabs.tsx
Normal file
@@ -0,0 +1,114 @@
|
||||
import Box from '@mui/material/Box'
|
||||
import React from 'react'
|
||||
import Tab from '@mui/material/Tab'
|
||||
import TabContext from '@mui/lab/TabContext'
|
||||
import TabList from '@mui/lab/TabList'
|
||||
import TabPanel from '@mui/lab/TabPanel'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import { RouteComponentProps } from 'react-router-dom'
|
||||
import { withState } from 'reaclette'
|
||||
import { withRouter } from 'react-router'
|
||||
|
||||
import IntlMessage from '../components/IntlMessage'
|
||||
|
||||
const BOX_STYLE = { borderBottom: 1, borderColor: 'divider', marginTop: '0.5em' }
|
||||
|
||||
interface ParentState {}
|
||||
|
||||
interface State {
|
||||
value: string
|
||||
}
|
||||
|
||||
interface Tab {
|
||||
component?: React.ReactNode
|
||||
disabled?: boolean
|
||||
label: React.ReactNode
|
||||
}
|
||||
|
||||
interface UrlTab extends Tab {
|
||||
pathname: string
|
||||
value?: any
|
||||
}
|
||||
|
||||
interface NoUrlTab extends Tab {
|
||||
value: any
|
||||
}
|
||||
|
||||
// For compatibility with 'withRouter'
|
||||
interface Props extends RouteComponentProps {
|
||||
indicatorColor?: 'primary' | 'secondary'
|
||||
textColor?: 'inherit' | 'primary' | 'secondary'
|
||||
// tabs = [
|
||||
// {
|
||||
// component: <span>BAR</span>,
|
||||
// pathname: '/path',
|
||||
// label: (
|
||||
// <span>
|
||||
// <Icon icon='cloud' /> {labelA}
|
||||
// </span>
|
||||
// ),
|
||||
// },
|
||||
// ]
|
||||
tabs: Array<NoUrlTab | UrlTab>
|
||||
useUrl?: boolean
|
||||
value?: any
|
||||
}
|
||||
|
||||
interface ParentEffects {}
|
||||
|
||||
interface Effects {
|
||||
onChange: (event: React.SyntheticEvent, value: string) => void
|
||||
}
|
||||
|
||||
interface Computed {}
|
||||
|
||||
// TODO: improve view as done in the model(figma).
|
||||
const pageUnderConstruction = (
|
||||
<div style={{ color: '#0085FF', textAlign: 'center' }}>
|
||||
<Typography variant='h2'>
|
||||
<IntlMessage id='xoLiteUnderConstruction' />
|
||||
</Typography>
|
||||
<Typography variant='h3'>
|
||||
<IntlMessage id='newFeaturesUnderConstruction' />
|
||||
</Typography>
|
||||
</div>
|
||||
)
|
||||
|
||||
const Tabs = withState<State, Props, Effects, Computed, ParentState, ParentEffects>(
|
||||
{
|
||||
initialState: ({ location: { pathname }, tabs, useUrl = false, value }) => ({
|
||||
value: (useUrl && pathname) || (value ?? tabs[0].value ?? tabs[0].pathname),
|
||||
}),
|
||||
effects: {
|
||||
onChange: function (_, value) {
|
||||
if (this.props.useUrl) {
|
||||
const { history, tabs } = this.props
|
||||
history.push(tabs.find(tab => (tab.value ?? tab.pathname) === value).pathname)
|
||||
}
|
||||
this.state.value = value
|
||||
},
|
||||
},
|
||||
},
|
||||
({ effects, state: { value }, indicatorColor, textColor, tabs }) => (
|
||||
<TabContext value={value}>
|
||||
<Box sx={BOX_STYLE}>
|
||||
<TabList indicatorColor={indicatorColor} onChange={effects.onChange} textColor={textColor}>
|
||||
{tabs.map((tab: UrlTab | NoUrlTab) => {
|
||||
const value = tab.value ?? tab.pathname
|
||||
return <Tab disabled={tab.disabled} key={value} label={tab.label} value={value} />
|
||||
})}
|
||||
</TabList>
|
||||
</Box>
|
||||
{tabs.map((tab: UrlTab | NoUrlTab) => {
|
||||
const value = tab.value ?? tab.pathname
|
||||
return (
|
||||
<TabPanel key={value} value={value}>
|
||||
{tab.component === undefined ? pageUnderConstruction : tab.component}
|
||||
</TabPanel>
|
||||
)
|
||||
})}
|
||||
</TabContext>
|
||||
)
|
||||
)
|
||||
|
||||
export default withRouter(Tabs)
|
||||
@@ -22,12 +22,14 @@
|
||||
"loading": "Loading…",
|
||||
"login": "Login",
|
||||
"name": "Name",
|
||||
"newFeaturesUnderConstruction": "New features are coming soon!",
|
||||
"noData": "No data",
|
||||
"noImplemented": "Not implemented",
|
||||
"noManagementPifs": "No management PIFs found",
|
||||
"none": "None",
|
||||
"notFound": "Not Found",
|
||||
"pageNotFound": "This page doesn't exist.",
|
||||
"xoLiteUnderConstruction": "XO Lite is under construction",
|
||||
"noUpdatesAvailable": "No updates available",
|
||||
"ok": "OK",
|
||||
"password": "Password",
|
||||
|
||||
Reference in New Issue
Block a user