Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into changelogs-tgui
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { Button, LabeledList, Section, ProgressBar, Flex, Box, Table, Collapsible, Input, Dimmer, Icon } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { capitalize } from "common/string";
|
||||
|
||||
export const Autolathe = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
// Extract `health` and `color` variables from the `data` object.
|
||||
const {
|
||||
materialtotal,
|
||||
materialsmax,
|
||||
materials = [],
|
||||
categories = [],
|
||||
designs = [],
|
||||
active,
|
||||
} = data;
|
||||
const [
|
||||
current_category,
|
||||
setCategory,
|
||||
] = useLocalState(context, 'current_category', "None");
|
||||
const filteredmaterials = materials.filter(material =>
|
||||
material.mineral_amount > 0);
|
||||
return (
|
||||
<Window
|
||||
width={600}
|
||||
height={600}>
|
||||
<Window.Content scrollable>
|
||||
<Section title="Total Materials">
|
||||
<LabeledList>
|
||||
<LabeledList.Item
|
||||
label="Total Materials">
|
||||
<ProgressBar
|
||||
value={materialtotal}
|
||||
minValue={0}
|
||||
maxValue={materialsmax}
|
||||
ranges={{
|
||||
"good": [materialsmax * 0.85, materialsmax],
|
||||
"average": [materialsmax * 0.25, materialsmax * 0.85],
|
||||
"bad": [0, materialsmax * 0.25],
|
||||
}}>
|
||||
{materialtotal + '/' + materialsmax + ' cm³'}
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item>
|
||||
{filteredmaterials.length > 0 && (
|
||||
<Collapsible title="Materials">
|
||||
<LabeledList>
|
||||
{filteredmaterials.map(filteredmaterial => (
|
||||
<LabeledList.Item
|
||||
key={filteredmaterial.id}
|
||||
label={capitalize(filteredmaterial.name)}>
|
||||
<ProgressBar
|
||||
style={{
|
||||
transform: 'scaleX(-1) scaleY(1)',
|
||||
}}
|
||||
value={materialsmax - filteredmaterial.mineral_amount}
|
||||
maxValue={materialsmax}
|
||||
color="black"
|
||||
backgroundColor={filteredmaterial.matcolour}>
|
||||
<div style={{ transform: 'scaleX(-1)' }}>{filteredmaterial.mineral_amount + ' cm³'}</div>
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
</Collapsible>)}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
<Section
|
||||
title="Search">
|
||||
<Input fluid
|
||||
placeholder="Search Recipes..."
|
||||
selfClear
|
||||
onChange={(e, value) => {
|
||||
if (value.length) {
|
||||
act('search', {
|
||||
to_search: value,
|
||||
});
|
||||
setCategory('results for "' + value + '"');
|
||||
}
|
||||
}} />
|
||||
</Section>
|
||||
<Section title="Categories">
|
||||
<Box>
|
||||
{categories.map(category => (
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<Button
|
||||
selected={current_category === category}
|
||||
content={category}
|
||||
onClick={() => {
|
||||
act('category', {
|
||||
selectedCategory: category,
|
||||
});
|
||||
setCategory(category);
|
||||
}} />
|
||||
))}
|
||||
</Box>
|
||||
</Section>
|
||||
{current_category.toString() !== "None" && (
|
||||
<Section
|
||||
title={'Displaying ' + current_category.toString()}
|
||||
buttons={(
|
||||
<Button
|
||||
icon="times"
|
||||
content="Close Category"
|
||||
onClick={() => {
|
||||
act('menu');
|
||||
setCategory("None");
|
||||
}} />
|
||||
)}>
|
||||
{active === 1 && (
|
||||
<Dimmer fontSize="32px">
|
||||
<Icon name="cog" spin />
|
||||
{'Building items...'}
|
||||
</Dimmer>
|
||||
)}
|
||||
<Flex direction="row" wrap="nowrap">
|
||||
<Table>
|
||||
{designs.length
|
||||
&& (designs.map(design => (
|
||||
<Table.Row
|
||||
key={design.id}>
|
||||
<Flex.Item>
|
||||
<Button
|
||||
content={design.name}
|
||||
disabled={design.buildable}
|
||||
onClick={() => act('make', {
|
||||
id: design.id,
|
||||
multiplier: '1',
|
||||
})} />
|
||||
</Flex.Item>
|
||||
{design.sheet ? (
|
||||
<Table.Cell>
|
||||
<Flex.Item grow={1}>
|
||||
<Button
|
||||
icon="hammer"
|
||||
content="10"
|
||||
disabled={!design.mult10}
|
||||
onClick={() => act('make', {
|
||||
id: design.id,
|
||||
multiplier: '10',
|
||||
})} />
|
||||
<Button
|
||||
icon="hammer"
|
||||
content="25"
|
||||
disabled={!design.mult25}
|
||||
onClick={() => act('make', {
|
||||
id: design.id,
|
||||
multiplier: '25',
|
||||
})} />
|
||||
</Flex.Item>
|
||||
</Table.Cell>
|
||||
) : (
|
||||
<Table.Cell>
|
||||
<Flex.Item grow={3}>
|
||||
<Button
|
||||
icon="hammer"
|
||||
content="5"
|
||||
disabled={!design.mult5}
|
||||
onClick={() => act('make', {
|
||||
id: design.id,
|
||||
multiplier: '5',
|
||||
})} />
|
||||
<Button
|
||||
icon="hammer"
|
||||
content="10"
|
||||
disabled={!design.mult10}
|
||||
onClick={() => act('make', {
|
||||
id: design.id,
|
||||
multiplier: '10',
|
||||
})} />
|
||||
</Flex.Item>
|
||||
</Table.Cell>
|
||||
)}
|
||||
<Table.Cell>
|
||||
<Button.Input
|
||||
content={"[Max:" + design.maxmult + ']'}
|
||||
maxValue={design.maxmult}
|
||||
disabled={design.buildable}
|
||||
backgroundColor={design.buildable ? '#999999' : 'default'}
|
||||
onCommit={(e, value) => act('make', {
|
||||
id: design.id,
|
||||
multiplier: value,
|
||||
})} />
|
||||
</Table.Cell>
|
||||
{design.cost}
|
||||
</Table.Row>
|
||||
))) || (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
{"No designs found."}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)}
|
||||
</Table>
|
||||
</Flex>
|
||||
</Section>
|
||||
)}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,136 @@
|
||||
/* eslint-disable react/jsx-closing-tag-location */
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, Flex, Icon, LabeledList, Modal, Section, Table, Tooltip } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
export const CustomShuttleConsole = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
docked_location,
|
||||
ship_name = "ERROR",
|
||||
shuttle_mass = 0,
|
||||
engine_force = 0,
|
||||
engines = 0,
|
||||
calculated_speed = 0,
|
||||
calculated_non_operational_thrusters = 0,
|
||||
calculated_consumption = 0,
|
||||
calculated_cooldown = 0,
|
||||
locations = [],
|
||||
destination = null,
|
||||
} = data;
|
||||
return (
|
||||
<Window
|
||||
width={385}
|
||||
height={475}>
|
||||
<Window.Content overflow="auto">
|
||||
<Section fluid fill grow={1}>
|
||||
{!docked_location ? (
|
||||
<Modal
|
||||
ml={1}
|
||||
mt={1}
|
||||
width={26}
|
||||
height={12}
|
||||
fontSize="28px"
|
||||
fontFamily="monospace"
|
||||
textAlign="center">
|
||||
<Flex>
|
||||
<Flex.Item mt={8} ml={3}>
|
||||
<Icon
|
||||
name="minus-circle" />
|
||||
</Flex.Item>
|
||||
<Flex.Item
|
||||
mt={5}
|
||||
ml={2}
|
||||
color="yellow">
|
||||
{"Shuttle Link Required."}
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Modal>
|
||||
) : (
|
||||
<>
|
||||
<font size="+3"><center>{ship_name}</center></font>
|
||||
<Section title="Info">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Current Location">
|
||||
{docked_location}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Shuttle Mass">
|
||||
{shuttle_mass / 10}ton{shuttle_mass !== 1 ? "s" : null}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Engine Force">
|
||||
{engine_force}Kn ({engines} engine{engines !== 1 ? "s" : null})
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Sublight speed">
|
||||
{calculated_speed}ms{<sup>-1</sup>} {calculated_speed < 1 ? <Tooltip content="INSUFFICIENT ENGINE POWER"><Icon name="exclamation-triangle" color="yellow" /></Tooltip> : null}
|
||||
</LabeledList.Item>
|
||||
{calculated_non_operational_thrusters.len
|
||||
? <LabeledList.Item label="Warning">
|
||||
{calculated_non_operational_thrusters} thruster{calculated_non_operational_thrusters !== 1 ? "s are" : " is"} not operational.
|
||||
</LabeledList.Item>
|
||||
: null}
|
||||
<LabeledList.Item label="Fuel Consumption">
|
||||
{calculated_consumption} unit{calculated_consumption !== 1 ? "s" : null} per travel
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Engine Cooldown">
|
||||
{calculated_cooldown}s
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
<Section title="Destinations">
|
||||
{locations.length===0 && (
|
||||
<Box
|
||||
mb={1.7}
|
||||
color="bad">
|
||||
No valid destinations
|
||||
</Box>
|
||||
) || (
|
||||
<Table>
|
||||
{locations.map(location => (
|
||||
<tr class="Table__row candystripe" key={location.id}>
|
||||
{location.name} <td>({location.dist}m)</td>
|
||||
<td>
|
||||
<Button
|
||||
icon="crosshairs"
|
||||
selected={location.id === destination}
|
||||
onClick={() => act("setloc", {
|
||||
setloc: location.id,
|
||||
})} />
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</Table>
|
||||
)}
|
||||
</Section>
|
||||
<Section>
|
||||
<Button
|
||||
content="Initiate Flight"
|
||||
icon="rocket"
|
||||
disabled={calculated_speed < 1 || !destination}
|
||||
onClick={() => act('fly')}
|
||||
fluid />
|
||||
</Section>
|
||||
</>
|
||||
)}
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const getLocationNameById = (locations, id) => {
|
||||
return locations?.find(location => location.id === id)?.name;
|
||||
};
|
||||
|
||||
const getLocationIdByName = (locations, name) => {
|
||||
return locations?.find(location => location.name === name)?.id;
|
||||
};
|
||||
|
||||
const STATUS_COLOR_KEYS = {
|
||||
"In Transit": "good",
|
||||
"Idle": "average",
|
||||
"Igniting": "average",
|
||||
"Recharging": "average",
|
||||
"Missing": "bad",
|
||||
"Unauthorized Access": "bad",
|
||||
"Locked": "bad",
|
||||
};
|
||||
@@ -0,0 +1,351 @@
|
||||
import { multiline } from '../../common/string';
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Icon, LabeledControls, NoticeBox, Section, Slider, Stack, Tooltip } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type SimpleBotContext = {
|
||||
can_hack: number;
|
||||
locked: number;
|
||||
emagged: number;
|
||||
pai: Pai;
|
||||
settings: Settings;
|
||||
custom_controls: Controls;
|
||||
};
|
||||
|
||||
type Pai = {
|
||||
allow_pai: number;
|
||||
card_inserted: number;
|
||||
};
|
||||
|
||||
type Settings = {
|
||||
power: number;
|
||||
airplane_mode: number;
|
||||
maintenance_lock: number;
|
||||
patrol_station: number;
|
||||
};
|
||||
|
||||
type Controls = {
|
||||
[Control: string]: [Value: number];
|
||||
};
|
||||
|
||||
export const SimpleBot = (_, context) => {
|
||||
const { data } = useBackend<SimpleBotContext>(context);
|
||||
const { can_hack, locked } = data;
|
||||
const access = (!locked || can_hack);
|
||||
|
||||
return (
|
||||
<Window width={450} height={300}>
|
||||
<Window.Content>
|
||||
<Stack fill vertical>
|
||||
<Stack.Item>
|
||||
<Section title="Settings" buttons={<TabDisplay />}>
|
||||
{!access
|
||||
? (<NoticeBox>Locked!</NoticeBox>)
|
||||
: (<SettingsDisplay />)}
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
{access && (
|
||||
<Stack.Item grow>
|
||||
<Section fill scrollable title="Controls">
|
||||
<ControlsDisplay />
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
)}
|
||||
</Stack>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
/** Creates a lock button at the top of the controls */
|
||||
const TabDisplay = (_, context) => {
|
||||
const { act, data } = useBackend<SimpleBotContext>(context);
|
||||
const { can_hack, locked, pai } = data;
|
||||
const { allow_pai } = pai;
|
||||
|
||||
return (
|
||||
<>
|
||||
{!!can_hack && <HackButton />}
|
||||
{!!allow_pai && <PaiButton />}
|
||||
<Button
|
||||
color="transparent"
|
||||
icon={locked ? 'lock' : 'lock-open'}
|
||||
onClick={() => act('lock')}
|
||||
selected={locked}
|
||||
tooltip={`${locked ? 'Unlock' : 'Lock'} the control panel.`}>
|
||||
Controls Lock
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
/** If user is a bad silicon, they can press this button to hack the bot */
|
||||
const HackButton = (_, context) => {
|
||||
const { act, data } = useBackend<SimpleBotContext>(context);
|
||||
const { can_hack, emagged } = data;
|
||||
|
||||
return (
|
||||
<Button
|
||||
color="danger"
|
||||
disabled={!can_hack}
|
||||
icon={emagged ? 'bug' : 'lock'}
|
||||
onClick={() => act('hack')}
|
||||
selected={!emagged}
|
||||
tooltip={
|
||||
!emagged
|
||||
? 'Unlocks the safety protocols.'
|
||||
: 'Resets the bot operating system.'
|
||||
}>
|
||||
{emagged ? 'Malfunctional' : 'Safety Lock'}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
/** Creates a button indicating PAI status and offers the eject action */
|
||||
const PaiButton = (_, context) => {
|
||||
const { act, data } = useBackend<SimpleBotContext>(context);
|
||||
const { card_inserted } = data.pai;
|
||||
|
||||
if (!card_inserted) {
|
||||
return (
|
||||
<Button
|
||||
color="transparent"
|
||||
icon="robot"
|
||||
tooltip={multiline`Insert an active PAI card to control this device.`}>
|
||||
No PAI Inserted
|
||||
</Button>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Button
|
||||
disabled={!card_inserted}
|
||||
icon="eject"
|
||||
onClick={() => act('eject_pai')}
|
||||
tooltip={multiline`Ejects the current PAI.`}>
|
||||
Eject PAI
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/** Displays the bot's standard settings: Power, patrol, etc. */
|
||||
const SettingsDisplay = (_, context) => {
|
||||
const { act, data } = useBackend<SimpleBotContext>(context);
|
||||
const { settings } = data;
|
||||
const { airplane_mode, patrol_station, power, maintenance_lock } = settings;
|
||||
|
||||
return (
|
||||
<LabeledControls>
|
||||
<LabeledControls.Item label="Power">
|
||||
<Tooltip content={`Powers ${power ? 'off' : 'on'} the bot.`}>
|
||||
<Icon
|
||||
size={2}
|
||||
name="power-off"
|
||||
color={power ? 'good' : 'gray'}
|
||||
onClick={() => act('power')}
|
||||
/>
|
||||
</Tooltip>
|
||||
</LabeledControls.Item>
|
||||
<LabeledControls.Item label="Airplane Mode">
|
||||
<Tooltip
|
||||
content={`${
|
||||
!airplane_mode ? 'Disables' : 'Enables'
|
||||
} remote access via console.`}>
|
||||
<Icon
|
||||
size={2}
|
||||
name="plane"
|
||||
color={airplane_mode ? 'yellow' : 'gray'}
|
||||
onClick={() => act('airplane')}
|
||||
/>
|
||||
</Tooltip>
|
||||
</LabeledControls.Item>
|
||||
<LabeledControls.Item label="Patrol Station">
|
||||
<Tooltip
|
||||
content={`${
|
||||
patrol_station ? 'Disables' : 'Enables'
|
||||
} automatic station patrol.`}>
|
||||
<Icon
|
||||
size={2}
|
||||
name="map-signs"
|
||||
color={patrol_station ? 'good' : 'gray'}
|
||||
onClick={() => act('patrol')}
|
||||
/>
|
||||
</Tooltip>
|
||||
</LabeledControls.Item>
|
||||
<LabeledControls.Item label="Maintenance Lock">
|
||||
<Tooltip
|
||||
content={
|
||||
maintenance_lock
|
||||
? 'Opens the maintenance hatch for repairs.'
|
||||
: 'Closes the maintenance hatch.'
|
||||
}>
|
||||
<Icon
|
||||
size={2}
|
||||
name="toolbox"
|
||||
color={maintenance_lock ? 'yellow' : 'gray'}
|
||||
onClick={() => act('maintenance')}
|
||||
/>
|
||||
</Tooltip>
|
||||
</LabeledControls.Item>
|
||||
</LabeledControls>
|
||||
);
|
||||
};
|
||||
|
||||
/** Iterates over custom controls.
|
||||
* Calls the helper to identify which button to use.
|
||||
*/
|
||||
const ControlsDisplay = (_, context) => {
|
||||
const { data } = useBackend<SimpleBotContext>(context);
|
||||
const { custom_controls } = data;
|
||||
|
||||
return (
|
||||
<LabeledControls wrap>
|
||||
{Object.entries(custom_controls).map((control) => {
|
||||
return (
|
||||
<LabeledControls.Item
|
||||
pb={2}
|
||||
key={control[0]}
|
||||
label={control[0]
|
||||
.replace('_', ' ')
|
||||
.replace(/(^\w{1})|(\s+\w{1})/g, (letter) =>
|
||||
letter.toUpperCase())}>
|
||||
<ControlHelper control={control} />
|
||||
</LabeledControls.Item>
|
||||
);
|
||||
})}
|
||||
</LabeledControls>
|
||||
);
|
||||
};
|
||||
|
||||
/** Helper function which identifies which button to create.
|
||||
* Might need some fine tuning if you are using more advanced controls.
|
||||
*/
|
||||
const ControlHelper = (props, context) => {
|
||||
const { act } = useBackend<SimpleBotContext>(context);
|
||||
const { control } = props;
|
||||
if (control[0] === 'sync_tech') {
|
||||
/** Control is for sync - this is medbot specific */
|
||||
return <MedbotSync />;
|
||||
} else if (control[0] === 'heal_threshold') {
|
||||
/** Control is a threshold - this is medbot specific */
|
||||
return <MedbotThreshold control={control} />;
|
||||
} else if (control[0] === 'injection_amount') {
|
||||
/** Control is for injection - this is medbot specific */
|
||||
return <InjectionThreshold control={control} />;
|
||||
} else if (control[0] === 'tile_stack') {
|
||||
return <FloorbotTiles control={control} />;
|
||||
} else if (control[0] === 'line_mode') {
|
||||
return <FloorbotLine control={control} />;
|
||||
} else {
|
||||
/** Control is a boolean of some type */
|
||||
return (
|
||||
<Icon
|
||||
color={control[1] ? 'good' : 'gray'}
|
||||
name={control[1] ? 'toggle-on' : 'toggle-off'}
|
||||
size={2}
|
||||
onClick={() => act(control[0])}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/** Small button to sync medbots with research. */
|
||||
const MedbotSync = (_, context) => {
|
||||
const { act } = useBackend<SimpleBotContext>(context);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content={multiline`Synchronize surgical data with research network.
|
||||
Improves Tending Efficiency.`}>
|
||||
<Icon
|
||||
color="purple"
|
||||
name="cloud-download-alt"
|
||||
size={2}
|
||||
onClick={() => act('sync_tech')}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
/** Slider button for medbot injection thresholds */
|
||||
const InjectionThreshold = (props, context) => {
|
||||
const { act } = useBackend<SimpleBotContext>(context);
|
||||
const { control } = props;
|
||||
|
||||
return (
|
||||
<Tooltip content="Adjusts the amount for using when injecting.">
|
||||
<Slider
|
||||
minValue={1}
|
||||
maxValue={15}
|
||||
ranges={{
|
||||
bad: [-Infinity, 5],
|
||||
average: [6, 10],
|
||||
good: [11, Infinity],
|
||||
}}
|
||||
step={2}
|
||||
unit="u"
|
||||
value={control[1]}
|
||||
onChange={(_, value) => act(control[0], { amount: value })}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
/** Slider button for medbot healing thresholds */
|
||||
const MedbotThreshold = (props, context) => {
|
||||
const { act } = useBackend<SimpleBotContext>(context);
|
||||
const { control } = props;
|
||||
|
||||
return (
|
||||
<Tooltip content="Adjusts the sensitivity for damage treatment.">
|
||||
<Slider
|
||||
minValue={5}
|
||||
maxValue={75}
|
||||
ranges={{
|
||||
good: [-Infinity, 15],
|
||||
average: [15, 55],
|
||||
bad: [55, Infinity],
|
||||
}}
|
||||
step={5}
|
||||
unit="%"
|
||||
value={control[1]}
|
||||
onChange={(_, value) => act(control[0], { threshold: value })}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
/** Tile stacks for floorbots - shows number and eject button */
|
||||
const FloorbotTiles = (props, context) => {
|
||||
const { act } = useBackend<SimpleBotContext>(context);
|
||||
const { control } = props;
|
||||
|
||||
return (
|
||||
<Button
|
||||
disabled={!control[1]}
|
||||
icon={control[1] ? 'eject' : ''}
|
||||
onClick={() => act('eject_tiles')}
|
||||
tooltip="Number of floor tiles contained in the bot.">
|
||||
{control[1] ? `${control[1]}` : 'Empty'}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
/** Direction indicator for floorbot when line mode is chosen. */
|
||||
const FloorbotLine = (props, context) => {
|
||||
const { act } = useBackend<SimpleBotContext>(context);
|
||||
const { control } = props;
|
||||
|
||||
return (
|
||||
<Tooltip content="Enables straight line tiling mode.">
|
||||
<Icon
|
||||
color={control[1] ? 'good' : 'gray'}
|
||||
name={control[1] ? 'compass' : 'toggle-off'}
|
||||
onClick={() => act('line_mode')}
|
||||
size={!control[1] ? 2 : 1.5}>
|
||||
{' '}
|
||||
{control[1] ? control[1].toString().charAt(0).toUpperCase() : ''}
|
||||
</Icon>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user