diff --git a/tgui/packages/tgui/interfaces/Biogenerator.js b/tgui/packages/tgui/interfaces/Biogenerator.js new file mode 100644 index 0000000000..7142cb045b --- /dev/null +++ b/tgui/packages/tgui/interfaces/Biogenerator.js @@ -0,0 +1,188 @@ +import { classes } from 'common/react'; +import { createSearch } from 'common/string'; +import { Fragment } from 'inferno'; +import { useBackend, useLocalState } from '../backend'; +import { Box, Button, Dimmer, Flex, Icon, Input, Section, Table, Tabs, NoticeBox, NumberInput } from '../components'; +import { formatMoney } from '../format'; +import { Window } from '../layouts'; + +const MAX_SEARCH_RESULTS = 25; + +export const Biogenerator = (props, context) => { + const { data } = useBackend(context); + const { + beaker, + processing, + } = data; + return ( + + {!!processing && ( + + + {' Processing...'} + + )} + + {!beaker && ( + No Container + )} + {!!beaker && ( + + )} + + + ); +}; + +export const BiogeneratorContent = (props, context) => { + const { act, data } = useBackend(context); + const { + biomass, + can_process, + categories = [], + } = data; + const [ + searchText, + setSearchText, + ] = useLocalState(context, 'searchText', ''); + const [ + selectedCategory, + setSelectedCategory, + ] = useLocalState(context, 'category', categories[0]?.name); + const testSearch = createSearch(searchText, item => { + return item.name; + }); + const items = searchText.length > 0 + // Flatten all categories and apply search to it + && categories + .flatMap(category => category.items || []) + .filter(testSearch) + .filter((item, i) => i < MAX_SEARCH_RESULTS) + // Select a category and show all items in it + || categories + .find(category => category.name === selectedCategory) + ?.items + // If none of that results in a list, return an empty list + || []; + return ( +
0 ? 'good' : 'bad'}> + {formatMoney(biomass)} Biomass + + )} + buttons={( + + Search + setSearchText(value)} + mx={1} /> +
+ ); +}; + +const ItemList = (props, context) => { + const { act } = useBackend(context); + const [ + hoveredItem, + setHoveredItem, + ] = useLocalState(context, 'hoveredItem', {}); + const hoveredCost = hoveredItem && hoveredItem.cost || 0; + // Append extra hover data to items + const items = props.items.map(item => { + const [ + amount, + setAmount, + ] = useLocalState(context, "amount" + item.name, 1); + const notSameItem = hoveredItem && hoveredItem.name !== item.name; + const notEnoughHovered = props.biomass - hoveredCost + * hoveredItem.amount < item.cost * amount; + const disabledDueToHovered = notSameItem && notEnoughHovered; + const disabled = props.biomass < item.cost * amount || disabledDueToHovered; + return { + ...item, + disabled, + amount, + setAmount, + }; + }); + return items.map(item => ( + + + + {' '}{item.name} + + + item.setAmount(value)} /> + + + + ); + })} + { !!admin_controls && ( + + + + + + + + )} + +
+ + {!!players && players.map(player => { return ( + + {player.votes !== undefined + && (Votes : {player.votes} )} + { + !!player.actions && player.actions.map(action => { + return ( + ); }) + } + ); + })} + +
+
+ + {!!all_roles && all_roles.map(r => ( + + + {r} + + + ))} +
+
+ + + ); +}; diff --git a/tgui/packages/tgui/interfaces/NtosCyborgRemoteMonitorSyndicate.js b/tgui/packages/tgui/interfaces/NtosCyborgRemoteMonitorSyndicate.js new file mode 100644 index 0000000000..07a0038544 --- /dev/null +++ b/tgui/packages/tgui/interfaces/NtosCyborgRemoteMonitorSyndicate.js @@ -0,0 +1,15 @@ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Box, Button, LabeledList, NoticeBox, Section } from '../components'; +import { NtosWindow } from '../layouts'; +import { NtosCyborgRemoteMonitorContent } from './NtosCyborgRemoteMonitor'; + +export const NtosCyborgRemoteMonitorSyndicate = (props, context) => { + return ( + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/SeedExtractor.js b/tgui/packages/tgui/interfaces/SeedExtractor.js new file mode 100644 index 0000000000..3dbdd6da06 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SeedExtractor.js @@ -0,0 +1,89 @@ +import { sortBy } from 'common/collections'; +import { flow } from 'common/fp'; +import { toTitleCase } from 'common/string'; +import { useBackend } from '../backend'; +import { Button, Section, Table } from '../components'; +import { Window } from '../layouts'; + +/** + * This method takes a seed string and splits the values + * into an object + */ +const splitSeedString = text => { + const re = /([^;=]+)=([^;]+)/g; + const ret = {}; + let m; + do { + m = re.exec(text); + if (m) { + ret[m[1]] = m[2] + ''; + } + } while (m); + return ret; +}; + +/** + * This method splits up the string "name" we get for the seeds + * and creates an object from it include the value that is the + * ammount + * + * @returns {any[]} + */ +const createSeeds = seedStrings => { + const objs = Object.keys(seedStrings).map(key => { + const obj = splitSeedString(key); + obj.amount = seedStrings[key]; + obj.key = key; + obj.name = toTitleCase(obj.name.replace('pack of ', '')); + return obj; + }); + return flow([ + sortBy(item => item.name), + ])(objs); +}; + +export const SeedExtractor = (props, context) => { + const { act, data } = useBackend(context); + const seeds = createSeeds(data.seeds); + return ( + + +
+ + + Name + Lifespan + Endurance + Maturation + Production + Yield + Potency + Instability + Stock + + {seeds.map(item => ( + + {item.name} + {item.lifespan} + {item.endurance} + {item.maturation} + {item.production} + {item.yield} + {item.potency} + {item.instability} + +
+
+
+
+ ); +};