10 changed files with 189 additions and 82 deletions
@ -0,0 +1,78 @@ |
|||||
|
import type React from "react"; |
||||
|
import { useState } from "react"; |
||||
|
|
||||
|
import { |
||||
|
Heading, |
||||
|
IconComponent, |
||||
|
majorScale, |
||||
|
Pane, |
||||
|
Paragraph, |
||||
|
Tab, |
||||
|
Tablist, |
||||
|
} from "evergreen-ui"; |
||||
|
import type { IconType } from "react-icons"; |
||||
|
|
||||
|
export interface TabType { |
||||
|
name: string; |
||||
|
icon: IconComponent | IconType; |
||||
|
element: () => JSX.Element; |
||||
|
disabled?: boolean; |
||||
|
} |
||||
|
|
||||
|
export interface SlideSheetTabbedContentProps { |
||||
|
heading: string; |
||||
|
description: string; |
||||
|
tabs: TabType[]; |
||||
|
} |
||||
|
|
||||
|
export const SlideSheetTabbedContent = ({ |
||||
|
heading, |
||||
|
description, |
||||
|
tabs, |
||||
|
}: SlideSheetTabbedContentProps): JSX.Element => { |
||||
|
const [selectedTab, setSelectedTab] = useState(0); |
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
<Pane zIndex={1} flexShrink={0} elevation={1} backgroundColor="white"> |
||||
|
<Pane padding={16} borderBottom="muted"> |
||||
|
<Heading size={600}>{heading}</Heading> |
||||
|
<Paragraph size={400} color="muted"> |
||||
|
{description} |
||||
|
</Paragraph> |
||||
|
</Pane> |
||||
|
<Pane display="flex" padding={8}> |
||||
|
<Tablist> |
||||
|
{tabs.map((Entry, index) => ( |
||||
|
<Tab |
||||
|
key={index} |
||||
|
userSelect="none" |
||||
|
disabled={Entry.disabled} |
||||
|
gap={5} |
||||
|
onSelect={() => setSelectedTab(index)} |
||||
|
isSelected={selectedTab === index} |
||||
|
> |
||||
|
<Entry.icon /> |
||||
|
{Entry.name} |
||||
|
</Tab> |
||||
|
))} |
||||
|
</Tablist> |
||||
|
</Pane> |
||||
|
</Pane> |
||||
|
<Pane display="flex" overflowY="scroll" background="tint1" padding={16}> |
||||
|
{tabs.map((Entry, index) => ( |
||||
|
<Pane |
||||
|
key={index} |
||||
|
borderRadius={majorScale(1)} |
||||
|
backgroundColor="white" |
||||
|
elevation={1} |
||||
|
flexGrow={1} |
||||
|
display={selectedTab === index ? "block" : "none"} |
||||
|
> |
||||
|
{!Entry.disabled && <Entry.element />} |
||||
|
</Pane> |
||||
|
))} |
||||
|
</Pane> |
||||
|
</> |
||||
|
); |
||||
|
}; |
||||
@ -0,0 +1,56 @@ |
|||||
|
import type React from "react"; |
||||
|
import { useState } from "react"; |
||||
|
|
||||
|
import { Pane, Tab, Tablist } from "evergreen-ui"; |
||||
|
|
||||
|
import { ExternalNotification } from "@app/components/PageComponents/ModuleConfig/ExternalNotification.js"; |
||||
|
import { MQTT } from "@components/PageComponents/ModuleConfig/MQTT.js"; |
||||
|
import { Serial } from "@components/PageComponents/ModuleConfig/Serial.js"; |
||||
|
|
||||
|
export const AppConfig = (): JSX.Element => { |
||||
|
const [selectedIndex, setSelectedIndex] = useState(0); |
||||
|
|
||||
|
const configSections = [ |
||||
|
{ |
||||
|
label: "Interface", |
||||
|
element: MQTT, |
||||
|
}, |
||||
|
{ |
||||
|
label: "Logging", |
||||
|
element: Serial, |
||||
|
}, |
||||
|
{ |
||||
|
label: "Language", |
||||
|
element: ExternalNotification, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
return ( |
||||
|
<Pane display="flex"> |
||||
|
<Pane flexBasis={150} marginRight={24}> |
||||
|
<Tablist> |
||||
|
{configSections.map((Config, index) => ( |
||||
|
<Tab |
||||
|
key={index} |
||||
|
direction="vertical" |
||||
|
isSelected={index === selectedIndex} |
||||
|
onSelect={() => setSelectedIndex(index)} |
||||
|
> |
||||
|
{Config.label} |
||||
|
</Tab> |
||||
|
))} |
||||
|
</Tablist> |
||||
|
</Pane> |
||||
|
<Pane flex="1"> |
||||
|
{configSections.map((Config, index) => ( |
||||
|
<Pane |
||||
|
key={index} |
||||
|
display={index === selectedIndex ? "block" : "none"} |
||||
|
> |
||||
|
<Config.element /> |
||||
|
</Pane> |
||||
|
))} |
||||
|
</Pane> |
||||
|
</Pane> |
||||
|
); |
||||
|
}; |
||||
@ -1,36 +1,31 @@ |
|||||
import type React from "react"; |
import type React from "react"; |
||||
import { useState } from "react"; |
|
||||
|
|
||||
import { CogIcon, CubeIcon } from "evergreen-ui"; |
import { ApplicationsIcon, CogIcon, CubeIcon } from "evergreen-ui"; |
||||
|
|
||||
import { Tab, TabbedContent } from "@components/layout/page/TabbedContent"; |
import { TabbedContent, TabType } from "@components/layout/page/TabbedContent"; |
||||
|
|
||||
|
import { AppConfig } from "./AppConfig.js"; |
||||
import { DeviceConfig } from "./DeviceConfig.js"; |
import { DeviceConfig } from "./DeviceConfig.js"; |
||||
import { ModuleConfig } from "./ModuleConfig.js"; |
import { ModuleConfig } from "./ModuleConfig.js"; |
||||
|
|
||||
export const ConfigPage = (): JSX.Element => { |
export const ConfigPage = (): JSX.Element => { |
||||
const [activeConfig, setActiveConfig] = useState(0); |
const tabs: TabType[] = [ |
||||
|
|
||||
const tabs: Tab[] = [ |
|
||||
{ |
{ |
||||
key: 0, |
|
||||
name: "Device Config", |
name: "Device Config", |
||||
icon: CogIcon, |
icon: CogIcon, |
||||
element: DeviceConfig, |
element: DeviceConfig, |
||||
}, |
}, |
||||
{ |
{ |
||||
key: 1, |
|
||||
name: "Module Config", |
name: "Module Config", |
||||
icon: CubeIcon, |
icon: CubeIcon, |
||||
element: ModuleConfig, |
element: ModuleConfig, |
||||
}, |
}, |
||||
|
{ |
||||
|
name: "App Config", |
||||
|
icon: ApplicationsIcon, |
||||
|
element: AppConfig, |
||||
|
}, |
||||
]; |
]; |
||||
|
|
||||
return ( |
return <TabbedContent tabs={tabs} />; |
||||
<TabbedContent |
|
||||
active={activeConfig} |
|
||||
setActive={setActiveConfig} |
|
||||
tabs={tabs} |
|
||||
/> |
|
||||
); |
|
||||
}; |
}; |
||||
|
|||||
@ -1,46 +1,35 @@ |
|||||
import type React from "react"; |
import type React from "react"; |
||||
import { useState } from "react"; |
|
||||
|
|
||||
import { DocumentIcon, GanttChartIcon, RainIcon } from "evergreen-ui"; |
import { DocumentIcon, GanttChartIcon, RainIcon } from "evergreen-ui"; |
||||
|
|
||||
import { useDevice } from "@app/core/stores/deviceStore.js"; |
import { useDevice } from "@app/core/stores/deviceStore.js"; |
||||
import { Tab, TabbedContent } from "@components/layout/page/TabbedContent"; |
import { TabbedContent, TabType } from "@components/layout/page/TabbedContent"; |
||||
import { FileBrowser } from "@pages/Extensions/FileBrowser"; |
import { FileBrowser } from "@pages/Extensions/FileBrowser"; |
||||
|
|
||||
import { Environment } from "./Environment.js"; |
import { Environment } from "./Environment.js"; |
||||
|
|
||||
export const ExtensionsPage = (): JSX.Element => { |
export const ExtensionsPage = (): JSX.Element => { |
||||
const [activeExtension, setActiveExtension] = useState(0); |
|
||||
const { hardware } = useDevice(); |
const { hardware } = useDevice(); |
||||
|
|
||||
const tabs: Tab[] = [ |
const tabs: TabType[] = [ |
||||
{ |
{ |
||||
key: 0, |
|
||||
name: "File Browser", |
name: "File Browser", |
||||
icon: DocumentIcon, |
icon: DocumentIcon, |
||||
element: FileBrowser, |
element: FileBrowser, |
||||
disabled: !hardware.hasWifi, |
disabled: !hardware.hasWifi, |
||||
}, |
}, |
||||
{ |
{ |
||||
key: 1, |
|
||||
name: "Range Test", |
name: "Range Test", |
||||
icon: GanttChartIcon, |
icon: GanttChartIcon, |
||||
element: FileBrowser, |
element: FileBrowser, |
||||
disabled: !hardware.hasWifi, |
disabled: !hardware.hasWifi, |
||||
}, |
}, |
||||
{ |
{ |
||||
key: 2, |
|
||||
name: "Environment", |
name: "Environment", |
||||
icon: RainIcon, |
icon: RainIcon, |
||||
element: Environment, |
element: Environment, |
||||
}, |
}, |
||||
]; |
]; |
||||
|
|
||||
return ( |
return <TabbedContent tabs={tabs} />; |
||||
<TabbedContent |
|
||||
active={activeExtension} |
|
||||
setActive={setActiveExtension} |
|
||||
tabs={tabs} |
|
||||
/> |
|
||||
); |
|
||||
}; |
}; |
||||
|
|||||
Loading…
Reference in new issue