mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-19 12:05:59 +01:00
New Ore Silo UI (#80975)
 ## About The Pull Request Made a new UI for Ore Silo, tweaked `MaterialAccessBar` component a bit to properly display pop-ups over “wrapped” elements and actually wrap. ## Why It's Good For The Game Ore Silo is one of the last machines that use browser on TG, we're almost there! Also, it helps @JohnFulpWillard to bring https://hackmd.io/XLt5MoRvRxuhFbwtk4VAUA HackMD document to a closure. ## Changelog 🆑 refactor: Refactored Ore Silo Ui. /🆑
This commit is contained in:
@@ -74,7 +74,6 @@ handles linking back and forth.
|
||||
if (silo)
|
||||
silo.ore_connected_machines -= src
|
||||
silo.holds -= src
|
||||
silo.updateUsrDialog()
|
||||
silo = null
|
||||
mat_container = null
|
||||
return ..()
|
||||
@@ -170,7 +169,6 @@ handles linking back and forth.
|
||||
if (silo)
|
||||
silo.ore_connected_machines -= src
|
||||
silo.holds -= src
|
||||
silo.updateUsrDialog()
|
||||
else if (mat_container)
|
||||
//transfer all mats to silo. whatever cannot be transfered is dumped out as sheets
|
||||
if(mat_container.total_amount())
|
||||
@@ -183,7 +181,6 @@ handles linking back and forth.
|
||||
qdel(mat_container)
|
||||
silo = new_silo
|
||||
silo.ore_connected_machines += src
|
||||
silo.updateUsrDialog()
|
||||
mat_container = new_container
|
||||
if(!(mat_container_flags & MATCONTAINER_NO_INSERT))
|
||||
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, TYPE_PROC_REF(/datum/component/remote_materials, SiloAttackBy))
|
||||
|
||||
@@ -8,7 +8,7 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
|
||||
icon_state = "silo"
|
||||
density = TRUE
|
||||
circuit = /obj/item/circuitboard/machine/ore_silo
|
||||
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN|INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_OPEN_SILICON|INTERACT_MACHINE_SET_MACHINE
|
||||
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN|INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_OPEN_SILICON
|
||||
|
||||
/// The machine UI's page of logs showing ore history.
|
||||
var/log_page = 1
|
||||
@@ -77,93 +77,79 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
|
||||
/obj/machinery/ore_silo/crowbar_act(mob/living/user, obj/item/tool)
|
||||
return default_deconstruction_crowbar(tool)
|
||||
|
||||
/obj/machinery/ore_silo/ui_interact(mob/user)
|
||||
user.set_machine(src)
|
||||
var/datum/browser/popup = new(user, "ore_silo", null, 600, 550)
|
||||
popup.set_content(generate_ui())
|
||||
popup.open()
|
||||
/obj/machinery/ore_silo/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/spritesheet/sheetmaterials)
|
||||
)
|
||||
|
||||
/obj/machinery/ore_silo/proc/generate_ui()
|
||||
var/list/ui = list("<head><title>Ore Silo</title></head><body><div class='statusDisplay'><h2>Stored Material:</h2>")
|
||||
var/any = FALSE
|
||||
for(var/M in materials.materials)
|
||||
var/datum/material/mat = M
|
||||
var/amount = materials.materials[M]
|
||||
var/sheets = round(amount) / SHEET_MATERIAL_AMOUNT
|
||||
var/ref = REF(M)
|
||||
if (sheets)
|
||||
if (sheets >= 1)
|
||||
ui += "<a href='?src=[REF(src)];ejectsheet=[ref];eject_amt=1'>Eject</a>"
|
||||
else
|
||||
ui += "<span class='linkOff'>Eject</span>"
|
||||
if (sheets >= 20)
|
||||
ui += "<a href='?src=[REF(src)];ejectsheet=[ref];eject_amt=20'>20x</a>"
|
||||
else
|
||||
ui += "<span class='linkOff'>20x</span>"
|
||||
ui += "<b>[mat.name]</b>: [sheets] sheets<br>"
|
||||
any = TRUE
|
||||
if(!any)
|
||||
ui += "Nothing!"
|
||||
/obj/machinery/ore_silo/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "OreSilo")
|
||||
ui.open()
|
||||
|
||||
ui += "</div><div class='statusDisplay'><h2>Connected Machines:</h2>"
|
||||
for(var/datum/component/remote_materials/mats as anything in ore_connected_machines)
|
||||
var/atom/parent = mats.parent
|
||||
ui += "<a href='?src=[REF(src)];remove=[REF(mats)]'>Remove</a>"
|
||||
ui += "<a href='?src=[REF(src)];hold=[REF(mats)]'>[holds[mats] ? "Allow" : "Hold"]</a>"
|
||||
ui += " <b>[parent.name]</b> in [get_area_name(parent, TRUE)]<br>"
|
||||
if(!ore_connected_machines.len)
|
||||
ui += "Nothing!"
|
||||
/obj/machinery/ore_silo/ui_static_data(mob/user)
|
||||
return materials.ui_static_data()
|
||||
|
||||
ui += "</div><div class='statusDisplay'><h2>Access Logs:</h2>"
|
||||
var/list/logs = GLOB.silo_access_logs[REF(src)]
|
||||
var/len = LAZYLEN(logs)
|
||||
var/num_pages = 1 + round((len - 1) / 30)
|
||||
var/page = clamp(log_page, 1, num_pages)
|
||||
if(num_pages > 1)
|
||||
for(var/i in 1 to num_pages)
|
||||
if(i == page)
|
||||
ui += "<span class='linkOff'>[i]</span>"
|
||||
else
|
||||
ui += "<a href='?src=[REF(src)];page=[i]'>[i]</a>"
|
||||
/obj/machinery/ore_silo/ui_data(mob/user)
|
||||
var/list/data = list(
|
||||
"materials" = materials.ui_data()
|
||||
)
|
||||
|
||||
ui += "<ol>"
|
||||
any = FALSE
|
||||
for(var/i in (page - 1) * 30 + 1 to min(page * 30, len))
|
||||
var/datum/ore_silo_log/entry = logs[i]
|
||||
ui += "<li value=[len + 1 - i]>[entry.formatted]</li>"
|
||||
any = TRUE
|
||||
if (!any)
|
||||
ui += "<li>Nothing!</li>"
|
||||
var/list/connected_data
|
||||
for(var/datum/component/remote_materials/remote as anything in ore_connected_machines)
|
||||
var/atom/parent = remote.parent
|
||||
var/icon/parent_icon = icon(initial(parent.icon), initial(parent.icon_state), frame = 1)
|
||||
var/list/remote_data = list(
|
||||
"ref" = REF(remote),
|
||||
"icon" = icon2base64(parent_icon),
|
||||
"name" = parent.name,
|
||||
"onHold" = holds[remote] ? TRUE : FALSE,
|
||||
"location" = get_area_name(parent, TRUE)
|
||||
)
|
||||
LAZYADD(connected_data, list(remote_data))
|
||||
LAZYSET(data, "machines", connected_data)
|
||||
|
||||
ui += "</ol></div>"
|
||||
return ui.Join()
|
||||
var/list/logs_data
|
||||
for(var/datum/ore_silo_log/entry as anything in GLOB.silo_access_logs[REF(src)])
|
||||
var/list/log_data = list(
|
||||
"rawMaterials" = entry.get_raw_materials(""),
|
||||
"machineName" = entry.machine_name,
|
||||
"areaName" = entry.area_name,
|
||||
"action" = entry.action,
|
||||
"amount" = entry.amount,
|
||||
"time" = entry.timestamp,
|
||||
"noun" = entry.noun
|
||||
)
|
||||
LAZYADD(logs_data, list(log_data))
|
||||
LAZYSET(data, "logs", logs_data)
|
||||
|
||||
/obj/machinery/ore_silo/Topic(href, href_list)
|
||||
if(..())
|
||||
return data
|
||||
|
||||
/obj/machinery/ore_silo/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
add_fingerprint(usr)
|
||||
usr.set_machine(src)
|
||||
|
||||
if(href_list["remove"])
|
||||
var/datum/component/remote_materials/mats = locate(href_list["remove"]) in ore_connected_machines
|
||||
if (mats)
|
||||
mats.disconnect_from(src)
|
||||
updateUsrDialog()
|
||||
switch(action)
|
||||
if("remove")
|
||||
var/datum/component/remote_materials/remote = locate(params["ref"]) in ore_connected_machines
|
||||
remote?.disconnect_from(src)
|
||||
return TRUE
|
||||
|
||||
if("hold")
|
||||
var/datum/component/remote_materials/remote = locate(params["ref"]) in ore_connected_machines
|
||||
remote?.toggle_holding()
|
||||
return TRUE
|
||||
|
||||
if("eject")
|
||||
var/datum/material/ejecting = locate(params["ref"])
|
||||
var/amount = text2num(params["amount"])
|
||||
if(!isnum(amount) || !istype(ejecting))
|
||||
return TRUE
|
||||
|
||||
materials.retrieve_sheets(amount, ejecting, drop_location())
|
||||
return TRUE
|
||||
else if(href_list["hold"])
|
||||
var/datum/component/remote_materials/mats = locate(href_list["hold"]) in ore_connected_machines
|
||||
mats.toggle_holding()
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
else if(href_list["ejectsheet"])
|
||||
var/datum/material/eject_sheet = locate(href_list["ejectsheet"])
|
||||
var/amount = text2num(href_list["eject_amt"])
|
||||
materials.retrieve_sheets(amount, eject_sheet, drop_location())
|
||||
return TRUE
|
||||
else if(href_list["page"])
|
||||
log_page = text2num(href_list["page"]) || 1
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/ore_silo/multitool_act(mob/living/user, obj/item/multitool/I)
|
||||
. = ..()
|
||||
@@ -192,7 +178,6 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
|
||||
else if(!logs[1].merge(entry))
|
||||
logs.Insert(1, entry)
|
||||
|
||||
updateUsrDialog()
|
||||
flick("silo_active", src)
|
||||
|
||||
/obj/machinery/ore_silo/examine(mob/user)
|
||||
@@ -219,7 +204,6 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
|
||||
amount = _amount
|
||||
noun = _noun
|
||||
materials = mats.Copy()
|
||||
format()
|
||||
var/list/data = list(
|
||||
"machine_name" = machine_name,
|
||||
"area_name" = AREACOORD(M),
|
||||
@@ -245,13 +229,8 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
|
||||
amount += other.amount
|
||||
for(var/each in other.materials)
|
||||
materials[each] += other.materials[each]
|
||||
format()
|
||||
return TRUE
|
||||
|
||||
/datum/ore_silo_log/proc/format()
|
||||
name = "[machine_name]: [action] [amount]x [noun]"
|
||||
formatted = "([timestamp]) <b>[machine_name]</b> in [area_name]<br>[action] [abs(amount)]x [noun]<br> [get_raw_materials("")]"
|
||||
|
||||
/datum/ore_silo_log/proc/get_raw_materials(separator)
|
||||
var/list/msg = list()
|
||||
for(var/key in materials)
|
||||
|
||||
@@ -2,7 +2,7 @@ import { sortBy } from 'common/collections';
|
||||
import { classes } from 'common/react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { AnimatedNumber, Button, Flex, Stack } from '../../components';
|
||||
import { AnimatedNumber, Button, Flex } from '../../components';
|
||||
import { formatSiUnit } from '../../format';
|
||||
import { MaterialIcon } from './MaterialIcon';
|
||||
import { Material } from './Types';
|
||||
@@ -57,7 +57,7 @@ export const MaterialAccessBar = (props: MaterialAccessBarProps) => {
|
||||
<Flex wrap>
|
||||
{sortBy((m: Material) => MATERIAL_RARITY[m.name])(availableMaterials).map(
|
||||
(material) => (
|
||||
<Flex.Item key={material.name} grow={1}>
|
||||
<Flex.Item grow basis={4.5} key={material.name}>
|
||||
<MaterialCounter
|
||||
material={material}
|
||||
SHEET_MATERIAL_AMOUNT={SHEET_MATERIAL_AMOUNT}
|
||||
@@ -95,7 +95,7 @@ const MaterialCounter = (props: MaterialCounterProps) => {
|
||||
sheets < 1 && 'MaterialDock--disabled',
|
||||
])}
|
||||
>
|
||||
<Stack vertical direction="column-reverse">
|
||||
<Flex direction="column-reverse">
|
||||
<Flex
|
||||
direction="column"
|
||||
textAlign="center"
|
||||
@@ -135,7 +135,7 @@ const MaterialCounter = (props: MaterialCounterProps) => {
|
||||
</Flex>
|
||||
</div>
|
||||
)}
|
||||
</Stack>
|
||||
</Flex>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
import { classes } from 'common/react';
|
||||
import { capitalize } from 'common/string';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import {
|
||||
Box,
|
||||
Icon,
|
||||
Image,
|
||||
LabeledList,
|
||||
NoticeBox,
|
||||
Section,
|
||||
Stack,
|
||||
Tabs,
|
||||
Tooltip,
|
||||
} from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { MaterialAccessBar } from './Fabrication/MaterialAccessBar';
|
||||
import { Material } from './Fabrication/Types';
|
||||
|
||||
type Machine = {
|
||||
ref: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
onHold: boolean;
|
||||
location: string;
|
||||
};
|
||||
|
||||
type Log = {
|
||||
rawMaterials: string;
|
||||
machineName: string;
|
||||
areaName: string;
|
||||
action: string;
|
||||
amount: number;
|
||||
time: string;
|
||||
noun: string;
|
||||
};
|
||||
|
||||
type OreSiloData = {
|
||||
SHEET_MATERIAL_AMOUNT: number;
|
||||
materials: Material[];
|
||||
machines: Machine[];
|
||||
logs: Log[];
|
||||
};
|
||||
|
||||
export const OreSilo = (props: any, context: any) => {
|
||||
const { act, data } = useBackend<OreSiloData>();
|
||||
const { SHEET_MATERIAL_AMOUNT, machines, logs } = data;
|
||||
|
||||
const [currentTab, setCurrentTab] = useState(0);
|
||||
|
||||
return (
|
||||
<Window title="Ore Silo" width={380} height={600}>
|
||||
<Window.Content>
|
||||
<Stack vertical fill>
|
||||
<Stack.Item>
|
||||
<Tabs fluid>
|
||||
<Tabs.Tab
|
||||
icon="plug"
|
||||
selected={currentTab === 0}
|
||||
onClick={() => setCurrentTab(0)}
|
||||
>
|
||||
Connections
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab
|
||||
icon="book-bookmark"
|
||||
selected={currentTab === 1}
|
||||
onClick={() => setCurrentTab(1)}
|
||||
>
|
||||
Logs
|
||||
</Tabs.Tab>
|
||||
</Tabs>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
{currentTab === 0 ? (
|
||||
!!machines && machines.length > 0 ? (
|
||||
<Section fill scrollable>
|
||||
{machines.map((machine, index) => (
|
||||
<MachineDisplay
|
||||
key={machine.name}
|
||||
machine={machine}
|
||||
onPause={(machine) => act('hold', { ref: machine.ref })}
|
||||
onRemove={(machine) =>
|
||||
act('remove', { ref: machine.ref })
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Section>
|
||||
) : (
|
||||
<NoticeBox>No machines connected!</NoticeBox>
|
||||
)
|
||||
) : null}
|
||||
{currentTab === 1 ? (
|
||||
!!logs && logs.length > 0 ? (
|
||||
<Box pr={1} height="100%" overflowY="scroll">
|
||||
{logs.map((log, index) => (
|
||||
<LogEntry key={index} log={log} />
|
||||
))}
|
||||
</Box>
|
||||
) : (
|
||||
<NoticeBox>No log entries currently present!</NoticeBox>
|
||||
)
|
||||
) : null}
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Section fill>
|
||||
<MaterialAccessBar
|
||||
availableMaterials={data.materials}
|
||||
SHEET_MATERIAL_AMOUNT={SHEET_MATERIAL_AMOUNT}
|
||||
onEjectRequested={(material, amount) =>
|
||||
act('eject', { ref: material.ref, amount })
|
||||
}
|
||||
/>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
type MachineProps = {
|
||||
machine: Machine;
|
||||
onPause: (machine: Machine) => void;
|
||||
onRemove: (machine: Machine) => void;
|
||||
};
|
||||
|
||||
const MachineDisplay = (props: MachineProps) => {
|
||||
const { machine, onPause, onRemove } = props;
|
||||
|
||||
return (
|
||||
<Box className="FabricatorRecipe">
|
||||
<Box className="FabricatorRecipe__Title">
|
||||
<Box className="FabricatorRecipe__Icon">
|
||||
<Image
|
||||
width={'32px'}
|
||||
height={'32px'}
|
||||
src={`data:image/jpeg;base64,${machine.icon}`}
|
||||
/>
|
||||
</Box>
|
||||
<Box className="FabricatorRecipe__Label">{machine.name}</Box>
|
||||
</Box>
|
||||
|
||||
<Tooltip
|
||||
content={
|
||||
machine.onHold
|
||||
? `Resume ${machine.name} usage.`
|
||||
: `Put ${machine.name} on hold.`
|
||||
}
|
||||
>
|
||||
<Box
|
||||
className={classes([
|
||||
'FabricatorRecipe__Button',
|
||||
'FabricatorRecipe__Button--icon',
|
||||
])}
|
||||
onClick={(_) => {
|
||||
onPause(machine);
|
||||
}}
|
||||
>
|
||||
<Icon name={machine.onHold ? 'circle-play' : 'circle-pause'} />
|
||||
</Box>
|
||||
</Tooltip>
|
||||
<Tooltip content={`Disconnect ${machine.name}.`}>
|
||||
<Box
|
||||
className={classes([
|
||||
'FabricatorRecipe__Button',
|
||||
'FabricatorRecipe__Button--icon',
|
||||
])}
|
||||
onClick={(_) => {
|
||||
onRemove(machine);
|
||||
}}
|
||||
>
|
||||
<Icon name="trash-can" />
|
||||
</Box>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
type LogProps = {
|
||||
log: Log;
|
||||
};
|
||||
|
||||
const LogEntry = (props: LogProps) => {
|
||||
const { log } = props;
|
||||
return (
|
||||
<Section
|
||||
title={`${capitalize(log.action)}: x${Math.abs(log.amount)} ${log.noun}`}
|
||||
>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Time">{log.time}</LabeledList.Item>
|
||||
<LabeledList.Item label="Machine">
|
||||
{capitalize(log.machineName)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Location">{log.areaName}</LabeledList.Item>
|
||||
<LabeledList.Item
|
||||
label="Materials"
|
||||
color={log.amount > 0 ? 'good' : 'bad'}
|
||||
>
|
||||
{log.rawMaterials}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user