Move to snowpack
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import React from 'react';
|
||||
|
||||
import { FaCheckCircle, FaCircle, FaUser } from 'react-icons/fa';
|
||||
|
||||
import type { Types } from '@meshtastic/meshtasticjs';
|
||||
|
||||
interface ChatMessageProps {
|
||||
message: { message: Types.TextPacket; ack: boolean };
|
||||
myId: number;
|
||||
nodes: Types.NodeInfoPacket[];
|
||||
}
|
||||
|
||||
const ChatMessage = (props: ChatMessageProps) => {
|
||||
return (
|
||||
<div className="flex items-end">
|
||||
<div
|
||||
className={`flex p-3 rounded-full shadow-md ${
|
||||
props.message.message.packet.from !== props.myId
|
||||
? 'bg-gray-300'
|
||||
: 'bg-green-200'
|
||||
}`}
|
||||
>
|
||||
<FaUser className="m-auto" />
|
||||
</div>
|
||||
<div className="flex flex-col container px-2 items-start">
|
||||
<div
|
||||
className={`px-4 py-2 rounded-md shadow-md ${
|
||||
props.message.message.packet.from !== props.myId
|
||||
? 'bg-gray-300'
|
||||
: 'bg-green-200'
|
||||
}`}
|
||||
>
|
||||
<div className="flex text-xs text-gray-500 space-x-1">
|
||||
<div className="font-medium">
|
||||
{/* {
|
||||
props.nodes.find(
|
||||
(node) => node.data.num === props.message.message.packet.from,
|
||||
).data.user.longName
|
||||
} */}
|
||||
</div>
|
||||
<p>-</p>
|
||||
<div className="underline">
|
||||
{new Date(
|
||||
props.message.message.packet.rxTime > 0
|
||||
? props.message.message.packet.rxTime
|
||||
: Date.now(),
|
||||
).toLocaleString()}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between text-gray-600">
|
||||
<span className="inline-block">{props.message.message.data}</span>
|
||||
{props.message.ack ? (
|
||||
<FaCheckCircle className="my-auto" />
|
||||
) : (
|
||||
<FaCircle className=" text-lg my-auto animate-pulse" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatMessage;
|
||||
@@ -0,0 +1,56 @@
|
||||
import React from 'react';
|
||||
|
||||
import { FaBroadcastTower, FaMobileAlt } from 'react-icons/fa';
|
||||
|
||||
import { Types } from '@meshtastic/meshtasticjs';
|
||||
|
||||
interface HeaderProps {
|
||||
status: Types.DeviceStatusEnum;
|
||||
IsReady: boolean;
|
||||
LastMeshInterraction: number;
|
||||
}
|
||||
|
||||
const Header = (props: HeaderProps) => {
|
||||
return (
|
||||
<nav className="w-full shadow-md">
|
||||
<div className="flex w-full container mx-auto justify-between px-6 py-4">
|
||||
<img src="/design/typelogo/typelogo.svg" height="30" width="200" />
|
||||
|
||||
<div className="flex items-center">
|
||||
<div className="flex pl-4">
|
||||
<div
|
||||
className={`w-5 h-5 rounded-full ${
|
||||
new Date(props.LastMeshInterraction) <
|
||||
new Date(Date.now() - 40000)
|
||||
? 'bg-red-400'
|
||||
: new Date(props.LastMeshInterraction) <
|
||||
new Date(Date.now() - 20000)
|
||||
? 'bg-yellow-400'
|
||||
: 'bg-green-400'
|
||||
}`}
|
||||
></div>
|
||||
<FaBroadcastTower className="m-auto ml-1 text-xl" />
|
||||
</div>
|
||||
|
||||
<div className="flex pl-4">
|
||||
<div
|
||||
className={`w-5 h-5 rounded-full ${
|
||||
props.status <= Types.DeviceStatusEnum.DEVICE_DISCONNECTED
|
||||
? 'bg-red-400'
|
||||
: props.status <= Types.DeviceStatusEnum.DEVICE_CONFIGURING &&
|
||||
!props.IsReady
|
||||
? 'bg-yellow-400'
|
||||
: props.IsReady
|
||||
? 'bg-green-400'
|
||||
: 'bg-gray-400'
|
||||
}`}
|
||||
></div>
|
||||
<FaMobileAlt className="m-auto ml-1 text-xl" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
@@ -0,0 +1,66 @@
|
||||
import React, { ReactNode, useEffect, useState } from 'react';
|
||||
|
||||
import { FaCaretDown, FaCaretRight, FaSpinner } from 'react-icons/fa';
|
||||
|
||||
interface NavItemProps {
|
||||
isDropdown: boolean;
|
||||
open?: boolean;
|
||||
isNested: boolean;
|
||||
titleContent: ReactNode;
|
||||
dropdownContent?: ReactNode;
|
||||
onClick?: Function;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
const NavItem = (props: NavItemProps) => {
|
||||
useEffect(() => {
|
||||
if (props.open) {
|
||||
setNavItemOpen(props.open);
|
||||
}
|
||||
}, []);
|
||||
const [navItemOpen, setNavItemOpen] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`flex w-full text-lg font-medium justify-between ${
|
||||
navItemOpen && props.isNested ? 'bg-gray-100' : null
|
||||
} ${props.isNested ? 'border-b px-3 py-1' : 'p-3'} ${
|
||||
props.isDropdown && navItemOpen ? 'shadow-md' : 'border-b'
|
||||
} ${
|
||||
props.isDropdown || props.isNested
|
||||
? 'hover:bg-gray-200 cursor-pointer'
|
||||
: null
|
||||
}`}
|
||||
onClick={() => {
|
||||
if (props.isDropdown) setNavItemOpen(!navItemOpen);
|
||||
if (props.onClick) {
|
||||
props.onClick();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{props.titleContent}
|
||||
{props.isDropdown && !props.isLoading ? (
|
||||
navItemOpen ? (
|
||||
<FaCaretDown className="my-auto group-hover:text-gray-700" />
|
||||
) : (
|
||||
<FaCaretRight className="my-auto group-hover:text-gray-700" />
|
||||
)
|
||||
) : null}
|
||||
{props.isLoading ? (
|
||||
<FaSpinner className="animate-spin my-auto" />
|
||||
) : null}
|
||||
</div>
|
||||
{props.isDropdown ? (
|
||||
<div
|
||||
className={`duration-200 ease-in-out transition-all overflow-hidden max-h-0 border-l-8 ${
|
||||
props.isNested ? 'border-gray-500' : 'border-gray-300'
|
||||
} ${navItemOpen ? 'max-h-full' : null}`}
|
||||
>
|
||||
{props.dropdownContent}
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavItem;
|
||||
@@ -0,0 +1,62 @@
|
||||
import React from 'react';
|
||||
|
||||
import type {
|
||||
IHTTPConnection,
|
||||
Protobuf,
|
||||
Types,
|
||||
} from '@meshtastic/meshtasticjs';
|
||||
|
||||
import type { LanguageEnum, languageTemplate } from '../App';
|
||||
import SidebarChannels from './Sidebar/SidebarChannels';
|
||||
import SidebarDeviceSettings from './Sidebar/SidebarDeviceSettings';
|
||||
import SidebarNodes from './Sidebar/SidebarNodes';
|
||||
import SidebarUISettings from './Sidebar/SidebarUISettings';
|
||||
|
||||
interface SidebarProps {
|
||||
IsReady: boolean;
|
||||
Nodes: Types.NodeInfoPacket[];
|
||||
Channels: Protobuf.Channel[];
|
||||
Preferences: Protobuf.RadioConfig_UserPreferences;
|
||||
Connection: IHTTPConnection;
|
||||
MobileNavOpen: boolean;
|
||||
Language: LanguageEnum;
|
||||
SetLanguage: Function;
|
||||
Translations: languageTemplate;
|
||||
}
|
||||
|
||||
const Sidebar = (props: SidebarProps) => {
|
||||
const updatePreferences = () => {};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex flex-col rounded-md m-3 md:ml-0 shadow-md w-full max-w-sm ${
|
||||
!props.MobileNavOpen ? 'hidden' : 'visible'
|
||||
}`}
|
||||
>
|
||||
<SidebarNodes
|
||||
IsReady={props.IsReady}
|
||||
Nodes={props.Nodes}
|
||||
Translations={props.Translations}
|
||||
/>
|
||||
<SidebarDeviceSettings
|
||||
IsReady={props.IsReady}
|
||||
Preferences={props.Preferences}
|
||||
Connection={props.Connection}
|
||||
Translations={props.Translations}
|
||||
/>
|
||||
<SidebarChannels
|
||||
IsReady={props.IsReady}
|
||||
Channels={props.Channels}
|
||||
Translations={props.Translations}
|
||||
/>
|
||||
<div className="flex-grow border-b"></div>
|
||||
<SidebarUISettings
|
||||
Language={props.Language}
|
||||
SetLanguage={props.SetLanguage}
|
||||
Translations={props.Translations}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
@@ -0,0 +1,145 @@
|
||||
import React from 'react';
|
||||
|
||||
import { FaStream } from 'react-icons/fa';
|
||||
|
||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||
|
||||
import type { languageTemplate } from '../../App';
|
||||
import NavItem from '../NavItem';
|
||||
|
||||
interface SidebarChannelsProps {
|
||||
IsReady: boolean;
|
||||
Channels: Protobuf.Channel[];
|
||||
Translations: languageTemplate;
|
||||
}
|
||||
|
||||
const SidebarChannels = (props: SidebarChannelsProps) => {
|
||||
return (
|
||||
<NavItem
|
||||
isDropdown={true}
|
||||
open={false}
|
||||
isNested={false}
|
||||
titleContent={
|
||||
<div className="flex">
|
||||
<FaStream className="my-auto mr-2" />
|
||||
{props.Translations.device_channels_title}
|
||||
</div>
|
||||
}
|
||||
isLoading={!props.IsReady}
|
||||
dropdownContent={
|
||||
<>
|
||||
{props.Channels.map((channel, index) => {
|
||||
if (channel.role !== Protobuf.Channel_Role.DISABLED)
|
||||
return (
|
||||
<NavItem
|
||||
key={index}
|
||||
isDropdown={true}
|
||||
isNested={true}
|
||||
titleContent={
|
||||
<div className="flex">
|
||||
{channel.index} - {Protobuf.Channel_Role[channel.role]}
|
||||
</div>
|
||||
}
|
||||
dropdownContent={
|
||||
<NavItem
|
||||
isDropdown={false}
|
||||
isNested={false}
|
||||
titleContent={
|
||||
<div className="w-full">
|
||||
<div className="flex justify-between border-b hover:bg-gray-200">
|
||||
<p>Bandwidth:</p>
|
||||
<code className="bg-gray-200 rounded-full px-2">
|
||||
{channel.settings?.bandwidth}
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between border-b hover:bg-gray-200">
|
||||
<p>Channel Number:</p>
|
||||
<code className="bg-gray-200 rounded-full px-2">
|
||||
{channel.settings?.channelNum}
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between border-b hover:bg-gray-200">
|
||||
<p>Coding Rate:</p>
|
||||
<code className="bg-gray-200 rounded-full px-2">
|
||||
{channel.settings?.codingRate}
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between border-b hover:bg-gray-200">
|
||||
<p>ID:</p>
|
||||
<code className="bg-gray-200 rounded-full px-2">
|
||||
{channel.settings?.id}
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between border-b hover:bg-gray-200">
|
||||
<p>Modem Config:</p>
|
||||
<code className="bg-gray-200 rounded-full px-2">
|
||||
{channel.settings?.modemConfig
|
||||
? Protobuf.ChannelSettings_ModemConfig[
|
||||
channel.settings.modemConfig
|
||||
]
|
||||
: null}
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between border-b hover:bg-gray-200">
|
||||
<p>Name:</p>
|
||||
<code className="bg-gray-200 rounded-full px-2">
|
||||
{channel.settings?.name}
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between border-b hover:bg-gray-200">
|
||||
<p>PSK:</p>
|
||||
<code className="bg-gray-200 rounded-full px-2">
|
||||
{channel.settings?.psk.toLocaleString()}
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between border-b hover:bg-gray-200">
|
||||
<p>Spread Factor:</p>
|
||||
<code className="bg-gray-200 rounded-full px-2">
|
||||
{channel.settings?.spreadFactor}
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between border-b hover:bg-gray-200">
|
||||
<p>Tx Power:</p>
|
||||
<code className="bg-gray-200 rounded-full px-2">
|
||||
{channel.settings?.txPower}
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between border-b hover:bg-gray-200">
|
||||
<p>Uplink:</p>
|
||||
<code className="bg-gray-200 rounded-full px-2">
|
||||
{channel.settings?.uplinkEnabled
|
||||
? 'true'
|
||||
: 'false'}
|
||||
</code>
|
||||
</div>
|
||||
<div className="flex justify-between border-b hover:bg-gray-200">
|
||||
<p>Downlink:</p>
|
||||
<code className="bg-gray-200 rounded-full px-2">
|
||||
{channel.settings?.downlinkEnabled
|
||||
? 'true'
|
||||
: 'false'}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SidebarChannels;
|
||||
@@ -0,0 +1,106 @@
|
||||
import React from 'react';
|
||||
|
||||
import { FaSave, FaUserCog } from 'react-icons/fa';
|
||||
|
||||
import { IHTTPConnection, Protobuf } from '@meshtastic/meshtasticjs';
|
||||
|
||||
import type { languageTemplate } from '../../App';
|
||||
import NavItem from '../NavItem';
|
||||
|
||||
interface SidebarDeviceSettingsProps {
|
||||
IsReady: boolean;
|
||||
Preferences: Protobuf.RadioConfig_UserPreferences;
|
||||
Connection: IHTTPConnection;
|
||||
Translations: languageTemplate;
|
||||
}
|
||||
|
||||
const SidebarDeviceSettings = (props: SidebarDeviceSettingsProps) => {
|
||||
return (
|
||||
<NavItem
|
||||
isDropdown={true}
|
||||
open={false}
|
||||
isNested={false}
|
||||
titleContent={
|
||||
<div className="flex">
|
||||
<FaUserCog className="my-auto mr-2" />
|
||||
{props.Translations.device_settings_title}
|
||||
</div>
|
||||
}
|
||||
isLoading={!props.IsReady}
|
||||
dropdownContent={
|
||||
<>
|
||||
<div className="flex whitespace-nowrap p-3 justify-between border-b">
|
||||
<div className="my-auto">
|
||||
{props.Translations.device_region_title}
|
||||
</div>
|
||||
<div className="flex shadow-md rounded-md ml-2">
|
||||
<select
|
||||
value={props.Preferences?.region ?? Protobuf.RegionCode.Unset}
|
||||
onChange={(e) => {
|
||||
props.Preferences.region = parseInt(e.target.value);
|
||||
}}
|
||||
>
|
||||
<option value={Protobuf.RegionCode.ANZ}>
|
||||
{Protobuf.RegionCode[Protobuf.RegionCode.ANZ]}
|
||||
</option>
|
||||
<option value={Protobuf.RegionCode.CN}>
|
||||
{Protobuf.RegionCode[Protobuf.RegionCode.CN]}
|
||||
</option>
|
||||
<option value={Protobuf.RegionCode.EU433}>
|
||||
{Protobuf.RegionCode[Protobuf.RegionCode.EU433]}
|
||||
</option>
|
||||
<option value={Protobuf.RegionCode.EU865}>
|
||||
{Protobuf.RegionCode[Protobuf.RegionCode.EU865]}
|
||||
</option>
|
||||
<option value={Protobuf.RegionCode.JP}>
|
||||
{Protobuf.RegionCode[Protobuf.RegionCode.JP]}
|
||||
</option>
|
||||
<option value={Protobuf.RegionCode.KR}>
|
||||
{Protobuf.RegionCode[Protobuf.RegionCode.KR]}
|
||||
</option>
|
||||
<option value={Protobuf.RegionCode.TW}>
|
||||
{Protobuf.RegionCode[Protobuf.RegionCode.TW]}
|
||||
</option>
|
||||
<option value={Protobuf.RegionCode.US}>
|
||||
{Protobuf.RegionCode[Protobuf.RegionCode.US]}
|
||||
</option>
|
||||
<option value={Protobuf.RegionCode.Unset}>
|
||||
{Protobuf.RegionCode[Protobuf.RegionCode.Unset]}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex whitespace-nowrap p-3 justify-between border-b">
|
||||
<div className="my-auto">{props.Translations.device_wifi_ssid}</div>
|
||||
<div className="flex shadow-md rounded-md ml-2">
|
||||
<input
|
||||
onChange={() => {}}
|
||||
type="text"
|
||||
value={props.Preferences.wifiSsid}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex whitespace-nowrap p-3 justify-between border-b">
|
||||
<div className="my-auto">{props.Translations.device_wifi_psk}</div>
|
||||
<div className="flex shadow-md rounded-md ml-2">
|
||||
<input type="password" value={props.Preferences.wifiPassword} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex group p-1 bg-gray-100 cursor-pointer hover:bg-gray-200 border-b">
|
||||
<div
|
||||
className="flex m-auto font-medium group-hover:text-gray-700"
|
||||
onClick={() => {
|
||||
props.Connection.setPreferences(props.Preferences);
|
||||
}}
|
||||
>
|
||||
<FaSave className="m-auto mr-2 group-hover:text-gray-700" />
|
||||
{props.Translations.save_changes_button}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SidebarDeviceSettings;
|
||||
@@ -0,0 +1,88 @@
|
||||
import React from 'react';
|
||||
|
||||
import { FaDesktop, FaUsers } from 'react-icons/fa';
|
||||
|
||||
import type { Types } from '@meshtastic/meshtasticjs';
|
||||
|
||||
import type { languageTemplate } from '../../App';
|
||||
import NavItem from '../NavItem';
|
||||
|
||||
interface sidebarNodesProps {
|
||||
IsReady: boolean;
|
||||
Nodes: Types.NodeInfoPacket[];
|
||||
Translations: languageTemplate;
|
||||
}
|
||||
|
||||
const SidebarNodes = (props: sidebarNodesProps) => {
|
||||
return (
|
||||
<NavItem
|
||||
isDropdown={true}
|
||||
open={false}
|
||||
isNested={false}
|
||||
titleContent={
|
||||
<div className="flex">
|
||||
<FaUsers className="my-auto mr-2" />
|
||||
{props.Translations.nodes_title}
|
||||
<div className="flex m-auto rounded-full bg-gray-300 w-6 h-6 text-sm ml-2">
|
||||
<div className="m-auto">{props.Nodes.length ?? 0}</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
isLoading={!props.IsReady}
|
||||
dropdownContent={
|
||||
props.Nodes.length ? (
|
||||
props.Nodes.map((node, index) => (
|
||||
<NavItem
|
||||
key={index}
|
||||
isDropdown={true}
|
||||
isNested={true}
|
||||
open={false}
|
||||
titleContent={
|
||||
<div key={index} className="flex">
|
||||
<FaDesktop className="my-auto mr-2" />
|
||||
<div className="m-auto">{node.data.user?.longName}</div>
|
||||
</div>
|
||||
}
|
||||
dropdownContent={
|
||||
<NavItem
|
||||
isDropdown={false}
|
||||
isNested={true}
|
||||
titleContent={
|
||||
<div>
|
||||
<p>
|
||||
SNR:{' '}
|
||||
{node.packet?.rxSnr ? node.packet.rxSnr : 'Unknown'}
|
||||
</p>
|
||||
<p>
|
||||
RSSI:{' '}
|
||||
{node.packet?.rxRssi ? node.packet.rxRssi : 'Unknown'}
|
||||
</p>
|
||||
<p>
|
||||
Last heard:{' '}
|
||||
{node.data?.lastHeard ? node.data.lastHeard : 'Unknown'}
|
||||
</p>
|
||||
<p>
|
||||
Loc:{' '}
|
||||
{node.data?.position
|
||||
? `alt: ${node.data?.position.altitude}, lat: ${node.data?.position.latitudeI}, lng: ${node.data?.position.longitudeI}, time: ${node.data?.position.time}, batt: ${node.data?.position.batteryLevel}`
|
||||
: 'Unknown'}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<div className="flex border-b border-gray-300">
|
||||
<div className="m-auto p-3 text-gray-500">
|
||||
{props.Translations.no_nodes_message}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SidebarNodes;
|
||||
@@ -0,0 +1,110 @@
|
||||
import React from 'react';
|
||||
|
||||
// import Flags from 'country-flag-icons/react/3x2';
|
||||
import { FaCog, FaLaptop, FaMoon, FaSun } from 'react-icons/fa';
|
||||
|
||||
import type { languageTemplate } from '../../App';
|
||||
import { LanguageEnum } from '../../App';
|
||||
import ToggleSwitch from '../basic/ToggleSwitch';
|
||||
import NavItem from '../NavItem';
|
||||
|
||||
interface SidebarUISettingsProps {
|
||||
Language: LanguageEnum;
|
||||
SetLanguage: Function;
|
||||
Translations: languageTemplate;
|
||||
}
|
||||
|
||||
const SidebarUISettings = (props: SidebarUISettingsProps) => {
|
||||
return (
|
||||
<NavItem
|
||||
isDropdown={true}
|
||||
isNested={false}
|
||||
titleContent={
|
||||
<div className="flex">
|
||||
<FaCog className="my-auto mr-2" />
|
||||
{props.Translations.ui_settings_title}
|
||||
</div>
|
||||
}
|
||||
dropdownContent={
|
||||
<>
|
||||
<NavItem
|
||||
isDropdown={false}
|
||||
isNested={true}
|
||||
titleContent={
|
||||
<>
|
||||
<div className="my-auto">
|
||||
{props.Translations.color_scheme_title}
|
||||
</div>
|
||||
<div className="flex shadow-md rounded-md ml-2">
|
||||
<div className="bg-gray-200 flex group p-2 rounded-l-md border border-gray-300 hover:bg-gray-200 cursor-pointer">
|
||||
<FaSun className="m-auto group-hover:text-gray-700" />
|
||||
</div>
|
||||
<div className="flex group p-2 border border-gray-300 hover:bg-gray-200 cursor-pointer">
|
||||
<FaMoon className="m-auto group-hover:text-gray-700" />
|
||||
</div>
|
||||
<div className="flex group p-2 rounded-r-md border border-gray-300 hover:bg-gray-200 cursor-pointer">
|
||||
<FaLaptop className="m-auto group-hover:text-gray-700" />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<NavItem
|
||||
isDropdown={true}
|
||||
isNested={true}
|
||||
open={false}
|
||||
titleContent={
|
||||
<div className="flex my-auto">
|
||||
{/* {props.Translations.language_title}
|
||||
{props.Language === LanguageEnum.ENGLISH ? (
|
||||
<Flags.US className="ml-2 w-8 shadow-md" />
|
||||
) : props.Language === LanguageEnum.JAPANESE ? (
|
||||
<Flags.JP className="ml-2 w-8 shadow-md" />
|
||||
) : (
|
||||
''
|
||||
)} */}
|
||||
</div>
|
||||
}
|
||||
dropdownContent={
|
||||
<>
|
||||
<NavItem
|
||||
onClick={() => {
|
||||
props.SetLanguage(LanguageEnum.ENGLISH);
|
||||
}}
|
||||
isDropdown={false}
|
||||
isNested={true}
|
||||
titleContent={
|
||||
<>{/* English <Flags.US className="w-8 shadow-md" /> */}</>
|
||||
}
|
||||
/>
|
||||
<NavItem
|
||||
onClick={() => {
|
||||
props.SetLanguage(LanguageEnum.JAPANESE);
|
||||
}}
|
||||
isDropdown={false}
|
||||
isNested={true}
|
||||
titleContent={
|
||||
<>{/* 日本語 <Flags.JP className="w-8 shadow-md" /> */}</>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<NavItem
|
||||
isDropdown={false}
|
||||
isNested={true}
|
||||
open={false}
|
||||
titleContent={
|
||||
<>
|
||||
<div className="">Test</div>
|
||||
<ToggleSwitch active={true} />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SidebarUISettings;
|
||||
@@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
interface TimelineProps {}
|
||||
|
||||
const Timeline = (props: TimelineProps) => {
|
||||
return <div></div>;
|
||||
};
|
||||
|
||||
export default Timeline;
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
interface TimelineItemProps {
|
||||
time: number;
|
||||
color: string;
|
||||
}
|
||||
|
||||
const TimelineItem = (props: TimelineItemProps) => {
|
||||
return <div className={`rounded-full h-6 w-6 bg-${props.color}`}>Test</div>;
|
||||
};
|
||||
|
||||
export default TimelineItem;
|
||||
@@ -0,0 +1,33 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
interface ToggleSwitchProps {
|
||||
active: boolean;
|
||||
toggle?: Function;
|
||||
}
|
||||
|
||||
const ToggleSwitch = (props: ToggleSwitchProps) => {
|
||||
const [active, setActive] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setActive(props.active);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={() => {
|
||||
setActive(!active);
|
||||
}}
|
||||
className={`w-12 h-6 flex items-center bg-gray-300 rounded-full p-1 duration-300 ease-in-out my-auto ${
|
||||
active ? 'bg-green-400' : null
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`bg-white w-4 h-4 rounded-full shadow-md transform duration-300 ease-in-out ${
|
||||
active ? 'translate-x-6' : null
|
||||
}`}
|
||||
></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ToggleSwitch;
|
||||
Reference in New Issue
Block a user