rail.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import { ReactElement, useCallback, useState } from 'react'
  2. import { Nav, NavLink, Tab, TabContainer } from 'react-bootstrap-5'
  3. import MaterialIcon, {
  4. AvailableUnfilledIcon,
  5. } from '@/shared/components/material-icon'
  6. import { Panel } from 'react-resizable-panels'
  7. type RailElement = {
  8. icon: AvailableUnfilledIcon
  9. key: string
  10. component: ReactElement
  11. }
  12. const RAIL_TABS: RailElement[] = [
  13. // NOTE: The file tree **MUST** be the first (i.e. default) tab in the list
  14. // since the file tree is responsible for opening the initial document.
  15. {
  16. key: 'file-tree',
  17. icon: 'description',
  18. component: <>File tree</>,
  19. },
  20. {
  21. key: 'integrations',
  22. icon: 'integration_instructions',
  23. component: <>Integrations</>,
  24. },
  25. {
  26. key: 'review-panel',
  27. icon: 'rate_review',
  28. component: <>Review panel</>,
  29. },
  30. {
  31. key: 'chat',
  32. icon: 'forum',
  33. component: <>Chat</>,
  34. },
  35. {
  36. key: 'errors',
  37. icon: 'report',
  38. component: <>Errors</>,
  39. },
  40. ]
  41. export const RailLayout = () => {
  42. const [selectedTab, setSelectedTab] = useState<string | undefined>(
  43. RAIL_TABS[0]?.key
  44. )
  45. return (
  46. <TabContainer
  47. mountOnEnter // Only render when necessary (so that we can lazy load tab content)
  48. unmountOnExit={false} // TODO: Should we unmount the tabs when they're not used?
  49. transition={false}
  50. defaultActiveKey={selectedTab}
  51. onSelect={useCallback(key => setSelectedTab(key ?? undefined), [])}
  52. id="ide-rail-tabs"
  53. >
  54. <div className="ide-rail">
  55. <Nav defaultActiveKey={RAIL_TABS[0]?.key} className="flex-column">
  56. {RAIL_TABS.map(({ icon, key }) => (
  57. <RailTab
  58. active={selectedTab === key}
  59. key={key}
  60. eventKey={key}
  61. icon={icon}
  62. />
  63. ))}
  64. </Nav>
  65. </div>
  66. <Panel
  67. id="ide-redesign-sidebar-panel"
  68. order={1}
  69. defaultSize={15}
  70. minSize={5}
  71. maxSize={80}
  72. >
  73. <div className="ide-rail-content">
  74. <Tab.Content>
  75. {RAIL_TABS.map(({ key, component }) => (
  76. <Tab.Pane eventKey={key} key={key}>
  77. {component}
  78. </Tab.Pane>
  79. ))}
  80. </Tab.Content>
  81. </div>
  82. </Panel>
  83. </TabContainer>
  84. )
  85. }
  86. const RailTab = ({
  87. icon,
  88. eventKey,
  89. active,
  90. }: {
  91. icon: AvailableUnfilledIcon
  92. eventKey: string
  93. active: boolean
  94. }) => {
  95. return (
  96. <NavLink eventKey={eventKey} className="ide-rail-tab-link">
  97. <MaterialIcon
  98. className="ide-rail-tab-link-icon"
  99. type={icon}
  100. unfilled={!active}
  101. />
  102. </NavLink>
  103. )
  104. }