This commit is contained in:
Letter N
2020-07-21 15:02:32 +08:00
parent f7f35c47b9
commit ba1d3eef8c
4 changed files with 399 additions and 0 deletions

View File

@@ -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 (
<Window resizable>
{!!processing && (
<Dimmer fontSize="32px">
<Icon name="cog" spin={1} />
{' Processing...'}
</Dimmer>
)}
<Window.Content scrollable>
{!beaker && (
<NoticeBox>No Container</NoticeBox>
)}
{!!beaker && (
<BiogeneratorContent />
)}
</Window.Content>
</Window>
);
};
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 (
<Section
title={(
<Box
inline
color={biomass > 0 ? 'good' : 'bad'}>
{formatMoney(biomass)} Biomass
</Box>
)}
buttons={(
<Fragment>
Search
<Input
value={searchText}
onInput={(e, value) => setSearchText(value)}
mx={1} />
<Button
icon="eject"
content="Eject"
onClick={() => act('detach')} />
<Button
icon="cog"
content="Activate"
disabled={!can_process}
onClick={() => act('activate')} />
</Fragment>
)}>
<Flex>
{searchText.length === 0 && (
<Flex.Item>
<Tabs vertical>
{categories.map(category => (
<Tabs.Tab
key={category.name}
selected={category.name === selectedCategory}
onClick={() => setSelectedCategory(category.name)}>
{category.name} ({category.items?.length || 0})
</Tabs.Tab>
))}
</Tabs>
</Flex.Item>
)}
<Flex.Item grow={1} basis={0}>
{items.length === 0 && (
<NoticeBox>
{searchText.length === 0
? 'No items in this category.'
: 'No results found.'}
</NoticeBox>
)}
<Table>
<ItemList
biomass={biomass}
items={items} />
</Table>
</Flex.Item>
</Flex>
</Section>
);
};
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 => (
<Table.Row key={item.id}>
<Table.Cell>
<span
className={classes(['design32x32', item.id])}
style={{
'vertical-align': 'middle',
}} />
{' '}<b>{item.name}</b>
</Table.Cell>
<Table.Cell collapsing>
<NumberInput
value={Math.round(item.amount)}
width="35px"
minValue={1}
maxValue={10}
onChange={(e, value) => item.setAmount(value)} />
</Table.Cell>
<Table.Cell collapsing>
<Button
style={{
'text-align': 'right',
}}
fluid
content={item.cost * item.amount + ' ' + "BIO"}
disabled={item.disabled}
onmouseover={() => setHoveredItem(item)}
onmouseout={() => setHoveredItem({})}
onClick={() => act('create', {
id: item.id,
amount: item.amount,
})} />
</Table.Cell>
</Table.Row>
));
};

View File

@@ -0,0 +1,107 @@
import { useBackend } from '../backend';
import { Flex, Button, LabeledList, Section, Box, Table, TimeDisplay } from '../components';
import { Fragment } from 'inferno';
import { Window } from '../layouts';
import { FlexItem } from '../components/Flex';
export const MafiaPanel = (props, context) => {
const { act, data } = useBackend(context);
const {
players,
actions,
phase,
role_info,
admin_controls,
timeleft,
all_roles } = data;
return (
<Window resizable>
<Window.Content>
<Section title={phase}>
{!!role_info && (
<Table>
<Table.Row>
<Table.Cell>
<TimeDisplay auto="down" value={timeleft} />
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell bold>
You are a {role_info.role}
</Table.Cell>
</Table.Row>
<Table.Row bold>
<Table.Cell>
{role_info.desc}
</Table.Cell>
</Table.Row>
{!!role_info.action_log && role_info.action_log.map(log_line => (
<Table.Row key={log_line}>
<Table.Cell>
{role_info.action_log}
</Table.Cell>
</Table.Row>
))}
</Table>
)}
</Section>
<Flex>
{!!actions && actions.map(action => {
return (
<Flex.Item key={action}>
<Button
onClick={() => act("mf_action", { atype: action })}>
{action}
</Button>
</Flex.Item>);
})}
{ !!admin_controls && (
<Fragment>
<Flex.Item>
<Button onClick={() => act("next_phase")}>Next Phase</Button>
</Flex.Item>
<FlexItem>
<Button onClick={() => act("new_game")}>New Game</Button>
</FlexItem>
</Fragment>)}
</Flex>
<Section title="Players">
<LabeledList>
{!!players && players.map(player => { return (
<LabeledList.Item
className="candystripe"
key={player.ref}
label={player.name}>
{player.votes !== undefined
&& (<Fragment>Votes : {player.votes} </Fragment>)}
{
!!player.actions && player.actions.map(action => {
return (
<Button
key={action}
onClick={
// eslint-disable-next-line indent
() => act("mf_targ_action", { atype: action, target: player.ref })
}>
{action}
</Button>); })
}
</LabeledList.Item>);
})}
</LabeledList>
</Section>
<Section title="Roles">
<Table>
{!!all_roles && all_roles.map(r => (
<Table.Row key={r}>
<Table.Cell bold>
{r}
</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
</Window.Content>
</Window>
);
};

View File

@@ -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 (
<NtosWindow theme="syndicate">
<NtosWindow.Content scrollable>
<NtosCyborgRemoteMonitorContent />
</NtosWindow.Content>
</NtosWindow>
);
};

View File

@@ -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 (
<Window resizable>
<Window.Content scrollable>
<Section title="Stored seeds:">
<Table cellpadding="3" textAlign="center">
<Table.Row>
<Table.Cell>Name</Table.Cell>
<Table.Cell>Lifespan</Table.Cell>
<Table.Cell>Endurance</Table.Cell>
<Table.Cell>Maturation</Table.Cell>
<Table.Cell>Production</Table.Cell>
<Table.Cell>Yield</Table.Cell>
<Table.Cell>Potency</Table.Cell>
<Table.Cell>Instability</Table.Cell>
<Table.Cell>Stock</Table.Cell>
</Table.Row>
{seeds.map(item => (
<Table.Row key={item.key}>
<Table.Cell bold>{item.name}</Table.Cell>
<Table.Cell>{item.lifespan}</Table.Cell>
<Table.Cell>{item.endurance}</Table.Cell>
<Table.Cell>{item.maturation}</Table.Cell>
<Table.Cell>{item.production}</Table.Cell>
<Table.Cell>{item.yield}</Table.Cell>
<Table.Cell>{item.potency}</Table.Cell>
<Table.Cell>{item.instability}</Table.Cell>
<Table.Cell>
<Button
content="Vend"
onClick={() => act('select', {
item: item.key,
})} />
({item.amount} left)
</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
</Window.Content>
</Window>
);
};