diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 954c0c0ac44..6d9db65e94a 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -144,6 +144,7 @@ module = R.module ? R.module.name : "No Module Detected", synchronization = R.connected_ai, is_hacked = R.connected_ai && R.emagged, + emagged = R.emagged, hackable = can_hack(user, R), ) data["cyborgs"] += list(cyborg_data) diff --git a/code/game/machinery/doors/door_vr.dm b/code/game/machinery/doors/door_vr.dm index 7a2ba190cd3..4455a6c99d0 100644 --- a/code/game/machinery/doors/door_vr.dm +++ b/code/game/machinery/doors/door_vr.dm @@ -54,6 +54,7 @@ var/obj/item/stack/stack = I var/amount_given = amount_needed - reinforcing var/mats_given = stack.get_amount() + var/singular_name = stack.singular_name if(reinforcing && amount_given <= 0) to_chat(user, "You must weld or remove \the plasteel from \the [src] before you can add anything else.") else @@ -65,7 +66,7 @@ reinforcing += mats_given amount_given = mats_given if(amount_given) - to_chat(user, "You fit [amount_given] [stack.singular_name]\s on \the [src].") + to_chat(user, "You fit [amount_given] [singular_name]\s on \the [src].") return TRUE @@ -141,4 +142,4 @@ if(D.icon_tinted && (D.id_tint == src.id || !D.id_tint)) spawn(0) D.toggle() - return \ No newline at end of file + return diff --git a/code/modules/pda/cart_apps.dm b/code/modules/pda/cart_apps.dm index eaf0db739de..0b93f261a46 100644 --- a/code/modules/pda/cart_apps.dm +++ b/code/modules/pda/cart_apps.dm @@ -138,7 +138,7 @@ else for(var/datum/data/record/R as anything in sortRecord(data_core.general)) if(R) - records += list(list(Name = R.fields["name"], "ref" = "\ref[R]")) + records += list(list(name = R.fields["name"], "ref" = "\ref[R]")) data["recordsList"] = records data["records"] = null return null diff --git a/code/modules/resleeving/designer.dm b/code/modules/resleeving/designer.dm index b597fd5733d..da166a18bc8 100644 --- a/code/modules/resleeving/designer.dm +++ b/code/modules/resleeving/designer.dm @@ -196,6 +196,7 @@ var/datum/preferences/designer/P = new() apply_markings_to_prefs(mannequin, P) data["activeBodyRecord"]["markings"] = P.body_markings + data["activeBodyRecord"]["digitigrade"] = mannequin.digitigrade data["menu"] = menu data["temp"] = temp @@ -283,7 +284,6 @@ /obj/machinery/computer/transhuman/designer/proc/update_preview_icon() if(!mannequin) mannequin = new () - mannequin.delete_inventory(TRUE) update_preview_mob(mannequin) mannequin.ImmediateOverlayUpdate() @@ -357,6 +357,14 @@ H.sync_organ_dna() // Do this because sprites depend on DNA-gender of organs (chest etc) H.resize(active_br.sizemult, FALSE) + // Emissiive... + if(H.ear_style) + H.ear_style.em_block = FALSE + if(H.tail_style) + H.tail_style.em_block = FALSE + if(H.wing_style) + H.wing_style.em_block = FALSE + // And as for clothing... // We don't actually dress them! This is a medical machine, handle the nakedness DOCTOR! diff --git a/code/modules/vore/persist/persist_vr.dm b/code/modules/vore/persist/persist_vr.dm index 67bb1103c02..60311e9889b 100644 --- a/code/modules/vore/persist/persist_vr.dm +++ b/code/modules/vore/persist/persist_vr.dm @@ -130,15 +130,41 @@ prefs.f_style = character.f_style prefs.b_type = character.b_type -// Saves mob's current custom species, ears, and tail state to prefs +// Saves mob's current custom species, ears, tail, wings and digitigrade legs state to prefs // This basically needs to be the reverse of /datum/category_item/player_setup_item/vore/ears/copy_to_mob() ~Leshana /proc/apply_ears_to_prefs(var/mob/living/carbon/human/character, var/datum/preferences/prefs) - if(character.ear_style) prefs.ear_style = character.ear_style.type - if(character.tail_style) prefs.tail_style = character.tail_style.type + if(character.ear_style) prefs.ear_style = character.ear_style.name + if(character.tail_style) prefs.tail_style = character.tail_style.name + if(character.wing_style) prefs.wing_style = character.wing_style.name + prefs.r_ears = character.r_ears + prefs.g_ears = character.g_ears + prefs.b_ears = character.b_ears + prefs.r_ears2 = character.r_ears2 + prefs.g_ears2 = character.g_ears2 + prefs.b_ears2 = character.b_ears2 + prefs.r_ears3 = character.r_ears3 + prefs.g_ears3 = character.g_ears3 + prefs.b_ears3 = character.b_ears3 prefs.r_tail = character.r_tail prefs.b_tail = character.b_tail prefs.g_tail = character.g_tail + prefs.r_tail2 = character.r_tail2 + prefs.b_tail2 = character.b_tail2 + prefs.g_tail2 = character.g_tail2 + prefs.r_tail3 = character.r_tail3 + prefs.b_tail3 = character.b_tail3 + prefs.g_tail3 = character.g_tail3 + prefs.r_wing = character.r_wing + prefs.b_wing = character.b_wing + prefs.g_wing = character.g_wing + prefs.r_wing2 = character.r_wing2 + prefs.b_wing2 = character.b_wing2 + prefs.g_wing2 = character.g_wing2 + prefs.r_wing3 = character.r_wing3 + prefs.b_wing3 = character.b_wing3 + prefs.g_wing3 = character.g_wing3 prefs.custom_species = character.custom_species + prefs.digitigrade = character.digitigrade // Saves mob's current organ state to prefs. // This basically needs to be the reverse of /datum/category_item/player_setup_item/general/body/copy_to_mob() ~Leshana diff --git a/tgui/packages/tgui/components/Box.tsx b/tgui/packages/tgui/components/Box.tsx index 2ee476fddd9..4891624d59d 100644 --- a/tgui/packages/tgui/components/Box.tsx +++ b/tgui/packages/tgui/components/Box.tsx @@ -203,6 +203,7 @@ const booleanStyleMap = { }, inline: mapBooleanPropTo('display', 'inline-block'), italic: mapBooleanPropTo('fontStyle', 'italic'), + underline: mapBooleanPropTo('textDecorationLine', 'underline'), // Vorestation Add nowrap: mapBooleanPropTo('whiteSpace', 'nowrap'), preserveWhitespace: mapBooleanPropTo('whiteSpace', 'pre-wrap'), } as const; diff --git a/tgui/packages/tgui/interfaces/Autolathe.tsx b/tgui/packages/tgui/interfaces/Autolathe.tsx index 97c00ad02ee..cf27ce81d60 100644 --- a/tgui/packages/tgui/interfaces/Autolathe.tsx +++ b/tgui/packages/tgui/interfaces/Autolathe.tsx @@ -7,7 +7,7 @@ import { useBackend, useSharedState } from '../backend'; import { Box, Button, Dropdown, Flex, Input, Section } from '../components'; import { Window } from '../layouts'; import { mat } from './common/CommonTypes'; -import { Materials } from './ExosuitFabricator'; +import { Materials } from './ExosuitFabricator/Material'; const canBeMade = (recipe, materials, mult: number = 1) => { if (recipe.requirements === null) { @@ -53,7 +53,7 @@ export const Autolathe = (props) => { const [category, setCategory] = useSharedState('category', 0); const [searchText, setSearchText] = useSharedState('search_text', ''); - const testSearch = createSearch(searchText, (recipe) => recipe.name); + const testSearch = createSearch(searchText, (recipe: recipe) => recipe.name); const recipesToShow = flow([ filter((recipe: recipe) => recipe.category === categories[category]), diff --git a/tgui/packages/tgui/interfaces/BodyDesigner/BodyDesignerSpecificRecord.tsx b/tgui/packages/tgui/interfaces/BodyDesigner/BodyDesignerSpecificRecord.tsx index b6fd5e67f44..8b22f1be3b6 100644 --- a/tgui/packages/tgui/interfaces/BodyDesigner/BodyDesignerSpecificRecord.tsx +++ b/tgui/packages/tgui/interfaces/BodyDesigner/BodyDesignerSpecificRecord.tsx @@ -113,7 +113,9 @@ export const BodyDesignerSpecificRecord = (props: { > {style.style} - ) : null} + ) : ( + '' + )} {style.colorHref ? ( - ) : null} + ) : ( + '' + )} {style.colorHref2 ? ( - ) : null} + ) : ( + '' + )} ); })} + + + act('href_conversion', { + target_href: 'digitigrade', + target_value: 1, + }) + } + > + {activeBodyRecord.digitigrade ? 'Yes' : 'No'} + + { const { act } = useBackend(); diff --git a/tgui/packages/tgui/interfaces/ChemMaster/index.tsx b/tgui/packages/tgui/interfaces/ChemMaster/index.tsx index 658ffc8f3c0..ad27d1a5147 100644 --- a/tgui/packages/tgui/interfaces/ChemMaster/index.tsx +++ b/tgui/packages/tgui/interfaces/ChemMaster/index.tsx @@ -3,7 +3,7 @@ import { Window } from '../../layouts'; import { ComplexModal, modalRegisterBodyOverride, -} from '.././common/ComplexModal'; +} from '../common/ComplexModal'; import { analyzeModalBodyOverride } from './ChemMasterAnalyzeModalBodyOverride'; import { ChemMasterBeaker } from './ChemMasterBeaker'; import { ChemMasterBuffer } from './ChemMasterBuffer'; diff --git a/tgui/packages/tgui/interfaces/Communicator/CommunicatorNewsTab.tsx b/tgui/packages/tgui/interfaces/Communicator/CommunicatorNewsTab.tsx index 5ed6049bfd9..e274cc5f6f8 100644 --- a/tgui/packages/tgui/interfaces/Communicator/CommunicatorNewsTab.tsx +++ b/tgui/packages/tgui/interfaces/Communicator/CommunicatorNewsTab.tsx @@ -1,7 +1,7 @@ import { decodeHtmlEntities } from 'common/string'; import { useBackend } from '../../backend'; -import { Box, Button, Section } from '../../components'; +import { Box, Button, Image, Section } from '../../components'; import { Data } from './types'; export const CommunicatorNewsTab = (props) => { @@ -37,7 +37,7 @@ export const CommunicatorNewsTab = (props) => { - {decodeHtmlEntities(message.body)} {!!message.img && ( - + {decodeHtmlEntities(message.caption) || null} )} diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator.jsx b/tgui/packages/tgui/interfaces/ExosuitFabricator.jsx deleted file mode 100644 index d0c3459bade..00000000000 --- a/tgui/packages/tgui/interfaces/ExosuitFabricator.jsx +++ /dev/null @@ -1,768 +0,0 @@ -import { uniqBy } from 'common/collections'; -import { toFixed } from 'common/math'; -import { classes } from 'common/react'; -import { createSearch, toTitleCase } from 'common/string'; -import { Fragment } from 'react'; - -import { useBackend, useSharedState } from '../backend'; -import { - Box, - Button, - Flex, - Icon, - Input, - NumberInput, - ProgressBar, - Section, - Tabs, - Tooltip, -} from '../components'; -import { formatMoney, formatSiUnit } from '../format'; -import { Window } from '../layouts'; - -const MATERIAL_KEYS = { - steel: 'sheet-metal_3', - glass: 'sheet-glass_3', - silver: 'sheet-silver_3', - graphite: 'sheet-puck_3', - plasteel: 'sheet-plasteel_3', - durasteel: 'sheet-durasteel_3', - verdantium: 'sheet-wavy_3', - morphium: 'sheet-wavy_3', - mhydrogen: 'sheet-mythril_3', - gold: 'sheet-gold_3', - diamond: 'sheet-diamond', - supermatter: 'sheet-super_3', - osmium: 'sheet-silver_3', - phoron: 'sheet-phoron_3', - uranium: 'sheet-uranium_3', - titanium: 'sheet-titanium_3', - lead: 'sheet-adamantine_3', - platinum: 'sheet-adamantine_3', - plastic: 'sheet-plastic_3', -}; - -const COLOR_NONE = 0; -const COLOR_AVERAGE = 1; -const COLOR_BAD = 2; - -const COLOR_KEYS = { - [COLOR_NONE]: false, - [COLOR_AVERAGE]: 'average', - [COLOR_BAD]: 'bad', -}; - -const materialArrayToObj = (materials) => { - let materialObj = {}; - - materials.forEach((m) => { - materialObj[m.name] = m.amount; - }); - - return materialObj; -}; - -const partBuildColor = (cost, tally, material) => { - if (cost > material) { - return { color: COLOR_BAD, deficit: cost - material }; - } - - if (tally > material) { - return { color: COLOR_AVERAGE, deficit: cost }; - } - - if (cost + tally > material) { - return { color: COLOR_AVERAGE, deficit: cost + tally - material }; - } - - return { color: COLOR_NONE, deficit: 0 }; -}; - -const partCondFormat = (materials, tally, part) => { - let format = { textColor: COLOR_NONE }; - - Object.keys(part.cost).forEach((mat) => { - format[mat] = partBuildColor(part.cost[mat], tally[mat], materials[mat]); - - if (format[mat].color > format['textColor']) { - format['textColor'] = format[mat].color; - } - }); - - return format; -}; - -const queueCondFormat = (materials, queue) => { - let materialTally = {}; - let matFormat = {}; - let missingMatTally = {}; - let textColors = {}; - - queue.forEach((part, i) => { - textColors[i] = COLOR_NONE; - Object.keys(part.cost).forEach((mat) => { - materialTally[mat] = materialTally[mat] || 0; - missingMatTally[mat] = missingMatTally[mat] || 0; - - matFormat[mat] = partBuildColor( - part.cost[mat], - materialTally[mat], - materials[mat], - ); - - if (matFormat[mat].color !== COLOR_NONE) { - if (textColors[i] < matFormat[mat].color) { - textColors[i] = matFormat[mat].color; - } - } else { - materialTally[mat] += part.cost[mat]; - } - - missingMatTally[mat] += matFormat[mat].deficit; - }); - }); - return { materialTally, missingMatTally, textColors, matFormat }; -}; - -const searchFilter = (search, allparts) => { - let searchResults = []; - - if (!search.length) { - return; - } - - const resultFilter = createSearch( - search, - (part) => (part.name || '') + (part.desc || '') + (part.searchMeta || ''), - ); - - Object.keys(allparts).forEach((category) => { - allparts[category].filter(resultFilter).forEach((e) => { - searchResults.push(e); - }); - }); - - searchResults = uniqBy((part) => part.name)(searchResults); - - return searchResults; -}; - -export const ExosuitFabricator = (props) => { - const { act, data } = useBackend(); - - const queue = data.queue || []; - const materialAsObj = materialArrayToObj(data.materials || []); - - const { materialTally, missingMatTally, textColors } = queueCondFormat( - materialAsObj, - queue, - ); - - const [displayMatCost, setDisplayMatCost] = useSharedState( - 'display_mats', - false, - ); - - const [displayAllMat, setDisplayAllMat] = useSharedState( - 'display_all_mats', - false, - ); - - return ( - - - - - - - - - - - - setDisplayMatCost(!displayMatCost)} - checked={displayMatCost} - > - Display Material Costs - - setDisplayAllMat(!displayAllMat)} - checked={displayAllMat} - > - Display All Materials - - {(data.species_types && ( - - Species: - act('species')}> - {data.species} - - - )) || - null} - {(data.manufacturers && ( - - Manufacturer: - act('manufacturer')}> - {data.manufacturer} - - - )) || - null} - - - - - - - act('sync_rnd')}>R&D Sync - } - > - - - - - - - - - - - - - - - - - ); -}; - -const EjectMaterial = (props) => { - const { act } = useBackend(); - - const { material } = props; - - const { name, removable, sheets } = material; - - const [removeMaterials, setRemoveMaterials] = useSharedState( - 'remove_mats_' + name, - 1, - ); - - if (removeMaterials > 1 && sheets < removeMaterials) { - setRemoveMaterials(sheets || 1); - } - - return ( - <> - { - const newVal = parseInt(val, 10); - if (Number.isInteger(newVal)) { - setRemoveMaterials(newVal); - } - }} - /> - - act('remove_mat', { - id: name, - amount: removeMaterials, - }) - } - /> - > - ); -}; - -export const Materials = (props) => { - const { data } = useBackend(); - - const { displayAllMat, disableEject = false } = props; - - const materials = data.materials || []; - - let display_materials = materials.filter( - (mat) => displayAllMat || mat.amount > 0, - ); - - if (display_materials.length === 0) { - return ( - - - - No Materials Loaded. - - ); - } - - return ( - - {display_materials.map( - (material) => - ( - - - {!disableEject && ( - - - - )} - - ) || null, - )} - - ); -}; - -const MaterialAmount = (props) => { - const { name, amount, formatsi, formatmoney, color, style } = props; - - let amountDisplay = '0'; - if (amount < 1 && amount > 0) { - amountDisplay = toFixed(amount, 2); - } else if (formatsi) { - amountDisplay = formatSiUnit(amount, 0); - } else if (formatmoney) { - amountDisplay = formatMoney(amount); - } else { - amountDisplay = amount; - } - - return ( - - - - - - - - - {amountDisplay} - - - - ); -}; - -const PartSets = (props) => { - const { data } = useBackend(); - - const partSets = data.partSets || []; - const buildableParts = data.buildableParts || {}; - - const [selectedPartTab, setSelectedPartTab] = useSharedState( - 'part_tab', - partSets.length ? buildableParts[0] : '', - ); - - return ( - - {partSets.map( - (set) => - !!buildableParts[set] && ( - setSelectedPartTab(set)} - > - {set} - - ), - )} - - ); -}; - -const PartLists = (props) => { - const { data } = useBackend(); - - const getFirstValidPartSet = (sets) => { - for (let set of sets) { - if (buildableParts[set]) { - return set; - } - } - return null; - }; - - const partSets = data.partSets || []; - const buildableParts = data.buildableParts || []; - - const { queueMaterials, materials } = props; - - const [selectedPartTab, setSelectedPartTab] = useSharedState( - 'part_tab', - getFirstValidPartSet(partSets), - ); - - const [searchText, setSearchText] = useSharedState('search_text', ''); - - if (!selectedPartTab || !buildableParts[selectedPartTab]) { - const validSet = getFirstValidPartSet(partSets); - if (validSet) { - setSelectedPartTab(validSet); - } else { - return; - } - } - - let partsList; - // Build list of sub-categories if not using a search filter. - if (!searchText) { - partsList = { Parts: [] }; - buildableParts[selectedPartTab].forEach((part) => { - part['format'] = partCondFormat(materials, queueMaterials, part); - if (!part.subCategory) { - partsList['Parts'].push(part); - return; - } - if (!(part.subCategory in partsList)) { - partsList[part.subCategory] = []; - } - partsList[part.subCategory].push(part); - }); - } else { - partsList = []; - searchFilter(searchText, buildableParts).forEach((part) => { - part['format'] = partCondFormat(materials, queueMaterials, part); - partsList.push(part); - }); - } - - return ( - <> - - - - - - - setSearchText(v)} - /> - - - - {(!!searchText && ( - - )) || - Object.keys(partsList).map((category) => ( - - ))} - > - ); -}; - -const PartCategory = (props) => { - const { act, data } = useBackend(); - - const { buildingPart } = data; - - const { parts, name, forceShow, placeholder } = props; - - const [displayMatCost] = useSharedState('display_mats', false); - - return ( - (!!parts.length || forceShow) && ( - - act('add_queue_set', { - part_list: parts.map((part) => part.id), - }) - } - > - Queue All - - } - > - {!parts.length && placeholder} - {parts.map((part) => ( - - - - act('build_part', { id: part.id })} - /> - - - act('add_queue_part', { id: part.id })} - /> - - - - {part.name} - - - - - - - - {displayMatCost && ( - - {Object.keys(part.cost).map((material) => ( - - - - ))} - - )} - - ))} - - ) - ); -}; - -const Queue = (props) => { - const { act, data } = useBackend(); - - const { isProcessingQueue } = data; - - const queue = data.queue || []; - - const { queueMaterials, missingMaterials, textColors } = props; - - return ( - - - - act('clear_queue')} - > - Clear Queue - - {(!!isProcessingQueue && ( - act('stop_queue')} - > - Stop - - )) || ( - act('build_queue')} - > - Build Queue - - )} - > - } - > - - - - - - - - - - - {!!queue.length && ( - - - - - - )} - - ); -}; - -const QueueMaterials = (props) => { - const { queueMaterials, missingMaterials } = props; - - return ( - - {Object.keys(queueMaterials).map((material) => ( - - - {!!missingMaterials[material] && ( - - {formatMoney(missingMaterials[material])} - - )} - - ))} - - ); -}; - -const QueueList = (props) => { - const { act, data } = useBackend(); - - const { textColors } = props; - - const queue = data.queue || []; - - if (!queue.length) { - return <>No parts in queue.>; - } - - return queue.map((part, index) => ( - - - - act('del_queue_part', { index: index + 1 })} - /> - - - - {part.name} - - - - - )); -}; - -const BeingBuilt = (props) => { - const { data } = useBackend(); - - const { buildingPart, storedPart } = data; - - if (storedPart) { - const { name } = storedPart; - - return ( - - - - {name} - - {'Fabricator outlet obstructed...'} - - - - ); - } - - if (buildingPart) { - const { name, duration, printTime } = buildingPart; - - const timeLeft = Math.ceil(duration / 10); - - return ( - - - - {name} - - - {(timeLeft >= 0 && timeLeft + 's') || 'Dispensing...'} - - - - - ); - } -}; diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator/Material.tsx b/tgui/packages/tgui/interfaces/ExosuitFabricator/Material.tsx new file mode 100644 index 00000000000..6c4e1c28b2d --- /dev/null +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator/Material.tsx @@ -0,0 +1,150 @@ +import { toFixed } from 'common/math'; +import { classes } from 'common/react'; +import { toTitleCase } from 'common/string'; + +import { useBackend, useSharedState } from '../../backend'; +import { + Box, + Button, + Flex, + Icon, + NumberInput, + Tooltip, +} from '../../components'; +import { formatMoney, formatSiUnit } from '../../format'; +import { MATERIAL_KEYS } from './constants'; +import { Data, material } from './types'; + +const EjectMaterial = (props: { material: material }) => { + const { act } = useBackend(); + + const { material } = props; + + const { name, removable, sheets } = material; + + const [removeMaterials, setRemoveMaterials] = useSharedState( + 'remove_mats_' + name, + 1, + ); + + if (removeMaterials > 1 && sheets < removeMaterials) { + setRemoveMaterials(sheets || 1); + } + + return ( + <> + { + const newVal = parseInt(val, 10); + if (Number.isInteger(newVal)) { + setRemoveMaterials(newVal); + } + }} + /> + + act('remove_mat', { + id: name, + amount: removeMaterials, + }) + } + /> + > + ); +}; + +export const Materials = (props: { + displayAllMat?: boolean; + disableEject?: boolean; +}) => { + const { data } = useBackend(); + + const { displayAllMat, disableEject = false } = props; + + const { materials = [] } = data; + + let display_materials = materials.filter( + (mat) => displayAllMat || mat.amount > 0, + ); + + if (display_materials.length === 0) { + return ( + + + + No Materials Loaded. + + ); + } + + return ( + + {display_materials.map( + (material) => + ( + + + {!disableEject && ( + + + + )} + + ) || '', + )} + + ); +}; + +export const MaterialAmount = (props: { + name: string; + amount: number; + formatsi?: boolean; + formatmoney?: boolean; + color?: string; + style?: {}; +}) => { + const { name, amount, formatsi, formatmoney, color, style } = props; + + let amountDisplay: string = '0'; + if (amount < 1 && amount > 0) { + amountDisplay = toFixed(amount, 2); + } else if (formatsi) { + amountDisplay = formatSiUnit(amount, 0); + } else if (formatmoney) { + amountDisplay = formatMoney(amount); + } else { + amountDisplay = amount.toString(); + } + + return ( + + + + + + + + + {amountDisplay} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator/Parts.tsx b/tgui/packages/tgui/interfaces/ExosuitFabricator/Parts.tsx new file mode 100644 index 00000000000..30b03ab16b2 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator/Parts.tsx @@ -0,0 +1,238 @@ +import { Fragment } from 'react'; + +import { useBackend, useSharedState } from '../../backend'; +import { + Box, + Button, + Flex, + Icon, + Input, + Section, + Tabs, +} from '../../components'; +import { COLOR_BAD, COLOR_KEYS } from './constants'; +import { + getFirstValidPartSet, + partCondFormat, + searchFilter, +} from './functions'; +import { MaterialAmount } from './Material'; +import { Data, internalPart } from './types'; + +export const PartSets = (props) => { + const { data } = useBackend(); + + const { partSets = [], buildableParts = [] } = data; + + const [selectedPartTab, setSelectedPartTab] = useSharedState( + 'part_tab', + partSets.length ? buildableParts[0] : '', + ); + + return ( + + {partSets.map( + (set) => + !!buildableParts[set] && ( + setSelectedPartTab(set)} + > + {set} + + ), + )} + + ); +}; + +export const PartLists = (props: { + queueMaterials: Record; + materials: Record; +}) => { + const { data } = useBackend(); + + const { partSets = [], buildableParts = [] } = data; + + const { queueMaterials, materials } = props; + + const [selectedPartTab, setSelectedPartTab] = useSharedState( + 'part_tab', + getFirstValidPartSet(partSets, buildableParts), + ); + + const [searchText, setSearchText] = useSharedState('search_text', ''); + + if (!selectedPartTab || !buildableParts[selectedPartTab]) { + const validSet = getFirstValidPartSet(partSets, buildableParts); + if (validSet) { + setSelectedPartTab(validSet); + } else { + return; + } + } + + let partsObj: { Parts: internalPart[] } = { + Parts: [], + }; + let partsList: internalPart[] = []; + // Build list of sub-categories if not using a search filter. + if (!searchText) { + partsObj = { Parts: [] }; + buildableParts[selectedPartTab!].forEach((part) => { + part['format'] = partCondFormat(materials, queueMaterials, part); + if (!part.subCategory) { + partsObj['Parts'].push(part); + return; + } + if (!(part.subCategory in partsObj)) { + partsObj[part.subCategory] = []; + } + partsObj[part.subCategory].push(part); + }); + } else { + searchFilter(searchText, buildableParts).forEach((part: internalPart) => { + part['format'] = partCondFormat(materials, queueMaterials, part); + partsList.push(part); + }); + } + + return ( + <> + + + + + + + setSearchText(v)} + /> + + + + {(!!searchText && ( + + )) || + Object.keys(partsObj).map((category) => ( + + ))} + > + ); +}; + +const PartCategory = (props: { + parts: internalPart[]; + name: string; + forceShow?: boolean; + placeholder?: string; +}) => { + const { act, data } = useBackend(); + + const { buildingPart } = data; + + const { parts, name, forceShow, placeholder } = props; + + const [displayMatCost] = useSharedState('display_mats', false); + + return ( + (!!parts.length || forceShow) && ( + + act('add_queue_set', { + part_list: parts.map((part) => part.id), + }) + } + > + Queue All + + } + > + {!parts.length && placeholder} + {parts.map((part) => ( + + + + act('build_part', { id: part.id })} + /> + + + act('add_queue_part', { id: part.id })} + /> + + + + {part.name} + + + + + + + + {displayMatCost && ( + + {Object.keys(part.cost).map((material) => ( + + + + ))} + + )} + + ))} + + ) + ); +}; diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator/Queue.tsx b/tgui/packages/tgui/interfaces/ExosuitFabricator/Queue.tsx new file mode 100644 index 00000000000..9791f96c2e4 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator/Queue.tsx @@ -0,0 +1,184 @@ +import { useBackend } from '../../backend'; +import { Box, Button, Flex, ProgressBar, Section } from '../../components'; +import { formatMoney } from '../../format'; +import { COLOR_KEYS } from './constants'; +import { MaterialAmount } from './Material'; +import { Data } from './types'; + +export const Queue = (props: { + queueMaterials: Record; + missingMaterials: Record; + textColors: Record; +}) => { + const { act, data } = useBackend(); + + const { isProcessingQueue, queue = [] } = data; + + const { queueMaterials, missingMaterials, textColors } = props; + + return ( + + + + act('clear_queue')} + > + Clear Queue + + {(!!isProcessingQueue && ( + act('stop_queue')} + > + Stop + + )) || ( + act('build_queue')} + > + Build Queue + + )} + > + } + > + + + + + + + + + + + {!!length && ( + + + + + + )} + + ); +}; + +const QueueMaterials = (props: { + queueMaterials: Record; + missingMaterials: Record; +}) => { + const { queueMaterials, missingMaterials } = props; + + return ( + + {Object.keys(queueMaterials).map((material) => ( + + + {!!missingMaterials[material] && ( + + {formatMoney(missingMaterials[material])} + + )} + + ))} + + ); +}; + +const QueueList = (props: { textColors: Record }) => { + const { act, data } = useBackend(); + + const { textColors } = props; + + const { queue = [] } = data; + + if (!queue || !queue.length) { + return <>No parts in queue.>; + } + + return queue.map((part, index) => ( + + + + act('del_queue_part', { index: index + 1 })} + /> + + + + {part.name} + + + + + )); +}; + +const BeingBuilt = (props) => { + const { data } = useBackend(); + + const { buildingPart, storedPart } = data; + + if (storedPart) { + return ( + + + + {storedPart} + + {'Fabricator outlet obstructed...'} + + + + ); + } + + if (buildingPart) { + const { name, duration, printTime } = buildingPart; + + const timeLeft = Math.ceil(duration / 10); + + return ( + + + + {name} + + + {(timeLeft >= 0 && timeLeft + 's') || 'Dispensing...'} + + + + + ); + } +}; diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator/constants.ts b/tgui/packages/tgui/interfaces/ExosuitFabricator/constants.ts new file mode 100644 index 00000000000..be394d852c0 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator/constants.ts @@ -0,0 +1,31 @@ +export const MATERIAL_KEYS = { + steel: 'sheet-metal_3', + glass: 'sheet-glass_3', + silver: 'sheet-silver_3', + graphite: 'sheet-puck_3', + plasteel: 'sheet-plasteel_3', + durasteel: 'sheet-durasteel_3', + verdantium: 'sheet-wavy_3', + morphium: 'sheet-wavy_3', + mhydrogen: 'sheet-mythril_3', + gold: 'sheet-gold_3', + diamond: 'sheet-diamond', + supermatter: 'sheet-super_3', + osmium: 'sheet-silver_3', + phoron: 'sheet-phoron_3', + uranium: 'sheet-uranium_3', + titanium: 'sheet-titanium_3', + lead: 'sheet-adamantine_3', + platinum: 'sheet-adamantine_3', + plastic: 'sheet-plastic_3', +}; + +export const COLOR_NONE = 0; +export const COLOR_AVERAGE = 1; +export const COLOR_BAD = 2; + +export const COLOR_KEYS = { + [COLOR_NONE]: undefined, + [COLOR_AVERAGE]: 'average', + [COLOR_BAD]: 'bad', +}; diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator/functions.ts b/tgui/packages/tgui/interfaces/ExosuitFabricator/functions.ts new file mode 100644 index 00000000000..0462c6c1bb9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator/functions.ts @@ -0,0 +1,130 @@ +import { uniqBy } from 'common/collections'; +import { createSearch } from 'common/string'; + +import { COLOR_AVERAGE, COLOR_BAD, COLOR_NONE } from './constants'; +import { material, part, queueFormat } from './types'; + +export function materialArrayToObj( + materials: material[], +): Record { + let materialObj = {}; + + materials.forEach((m) => { + materialObj[m.name] = m.amount; + }); + + return materialObj; +} + +export function partBuildColor( + cost: number, + tally: number, + material: number, +): { color: number; deficit: number } { + if (cost > material) { + return { color: COLOR_BAD, deficit: cost - material }; + } + + if (tally > material) { + return { color: COLOR_AVERAGE, deficit: cost }; + } + + if (cost + tally > material) { + return { color: COLOR_AVERAGE, deficit: cost + tally - material }; + } + + return { color: COLOR_NONE, deficit: 0 }; +} + +export function partCondFormat( + materials: Record, + tally: Record, + part: part, +) { + let format = { textColor: COLOR_NONE }; + + Object.keys(part.cost).forEach((mat) => { + format[mat] = partBuildColor(part.cost[mat], tally[mat], materials[mat]); + + if (format[mat].color > format['textColor']) { + format['textColor'] = format[mat].color; + } + }); + + return format; +} + +export function queueCondFormat( + materials: material | {}, + queue: part[] | null, +): queueFormat { + let materialTally = {}; + let matFormat = {}; + let missingMatTally = {}; + let textColors = {}; + + queue && + queue.forEach((part, i) => { + textColors[i] = COLOR_NONE; + Object.keys(part.cost).forEach((mat) => { + materialTally[mat] = materialTally[mat] || 0; + missingMatTally[mat] = missingMatTally[mat] || 0; + + matFormat[mat] = partBuildColor( + part.cost[mat], + materialTally[mat], + materials[mat], + ); + + if (matFormat[mat].color !== COLOR_NONE) { + if (textColors[i] < matFormat[mat].color) { + textColors[i] = matFormat[mat].color; + } + } else { + materialTally[mat] += part.cost[mat]; + } + + missingMatTally[mat] += matFormat[mat].deficit; + }); + }); + return { materialTally, missingMatTally, textColors, matFormat }; +} + +export function searchFilter( + search: string, + allparts: Record | [], +) { + let searchResults: part[] = []; + + if (!search.length) { + return []; + } + + const resultFilter = createSearch( + search, + (part: part) => + (part.name || '') + (part.desc || '') + (part.searchMeta || ''), + ); + + Object.keys(allparts).forEach((category) => { + allparts[category].filter(resultFilter).forEach((e: part) => { + searchResults.push(e); + }); + }); + + searchResults = uniqBy((part: part) => part.name)(searchResults); + + return searchResults; +} + +export function getFirstValidPartSet( + sets: string[], + buildableParts: Record | [], +) { + for (let set of sets) { + if (buildableParts[set]) { + return set; + } + } + return null; +} diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator/index.tsx b/tgui/packages/tgui/interfaces/ExosuitFabricator/index.tsx new file mode 100644 index 00000000000..8195c6674b5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator/index.tsx @@ -0,0 +1,117 @@ +import { useBackend, useSharedState } from '../../backend'; +import { Box, Button, Flex, Section } from '../../components'; +import { Window } from '../../layouts'; +import { materialArrayToObj, queueCondFormat } from './functions'; +import { Materials } from './Material'; +import { PartLists, PartSets } from './Parts'; +import { Queue } from './Queue'; +import { Data } from './types'; + +export const ExosuitFabricator = (props) => { + const { act, data } = useBackend(); + + const { + species_types, + species, + manufacturers, + manufacturer, + queue = [], + materials = [], + } = data; + + const materialAsObj = materialArrayToObj(materials); + + const { materialTally, missingMatTally, textColors } = queueCondFormat( + materialAsObj, + queue, + ); + + const [displayMatCost, setDisplayMatCost] = useSharedState( + 'display_mats', + false, + ); + + const [displayAllMat, setDisplayAllMat] = useSharedState( + 'display_all_mats', + false, + ); + + return ( + + + + + + + + + + + + setDisplayMatCost(!displayMatCost)} + checked={displayMatCost} + > + Display Material Costs + + setDisplayAllMat(!displayAllMat)} + checked={displayAllMat} + > + Display All Materials + + {(species_types && ( + + Species: + act('species')}>{species} + + )) || + null} + {(manufacturers && ( + + Manufacturer: + act('manufacturer')}> + {manufacturer} + + + )) || + null} + + + + + + + act('sync_rnd')}>R&D Sync + } + > + + + + + + + + + + + + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator/types.ts b/tgui/packages/tgui/interfaces/ExosuitFabricator/types.ts new file mode 100644 index 00000000000..2a7b85710a6 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator/types.ts @@ -0,0 +1,42 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + partSets: string[]; + buildableParts: Record | []; + materials: material[]; + buildingPart: { name: string; duration: number; printTime: number } | null; + queue: part[] | null; + storedPart: string | null; + isProcessingQueue: BooleanLike; + species_types: string[]; + species: string; + manufacturers: { id: string; company: string }; + manufacturer: string; +}; + +export type part = { + name: string; + desc: string; + printTime: number; + cost: number; + id: string; + subCategory: string[]; + categoryOverride: string[]; + searchMeta: string | null; +}; + +export type material = { + name: string; + amount: number; + sheets: number; + removable: BooleanLike; +}; + +export type queueFormat = { + materialTally: Record; + missingMatTally: Record; + matFormat: { color: number; deficit: number } | {}; + textColors: Record; +}; + +export type internalPart = Required; diff --git a/tgui/packages/tgui/interfaces/GeneralAtmoControl.jsx b/tgui/packages/tgui/interfaces/GeneralAtmoControl.jsx deleted file mode 100644 index 0ec31e6a0a3..00000000000 --- a/tgui/packages/tgui/interfaces/GeneralAtmoControl.jsx +++ /dev/null @@ -1,310 +0,0 @@ -import { useBackend } from '../backend'; -import { Box, Button, Flex, LabeledList, Section, Slider } from '../components'; -import { Window } from '../layouts'; - -export const GeneralAtmoControl = (props) => { - const { act, data } = useBackend(); - - // While many of these variables are unused, it's helpful to have a consistent - // list of all possible parameters in the core component of this UI. - // So, keep them here and update them as necessary, pretty please. - const { - // All - sensors, - // Tanks /obj/machinery/computer/general_air_control - tanks, - // Tanks+Core /obj/machinery/computer/general_air_control/large_tank_control - input_info, - output_info, - input_flow_setting, - pressure_setting, - max_pressure, - max_flowrate, - // Core /obj/machinery/computer/general_air_control/supermatter_core - core, - // Fuel /obj/machinery/computer/general_air_control/fuel_injection - fuel, - automation, - device_info, - } = data; - - return ( - - - - {(core || tanks) && } - {fuel && } - - - ); -}; - -const AtmoControlSensors = (props) => { - const { act } = useBackend(); - - const { sensors } = props; - - if (!sensors) { - return ( - - No Sensors Connected. - - ); - } else { - return ( - - {sensors.map((sensor) => ( - - - - ))} - - ); - } -}; - -const AtmoSensor = (props) => { - const { sensor } = props; - - if (!sensor.sensor_data) { - return UNABLE TO FIND SENSOR; - } - - const { pressure, temperature, oxygen, nitrogen, carbon_dioxide, phoron } = - sensor.sensor_data; - - let labeledListContents = []; - if (pressure) { - labeledListContents.push( - {pressure} kPa, - ); - } - - if (temperature) { - labeledListContents.push( - {temperature} K, - ); - } - - if (oxygen || nitrogen || carbon_dioxide || phoron) { - labeledListContents.push( - - - {oxygen ? ({oxygen}% O²) : null} - {nitrogen ? ({nitrogen}% N²) : null} - {carbon_dioxide ? ( - ({carbon_dioxide}% CO²) - ) : null} - {phoron ? ({phoron}% TX) : null} - - , - ); - } - - return {labeledListContents.map((item) => item)}; -}; - -const AtmoControlTankCore = (props) => { - const { act, data } = useBackend(); - - const { - // Tanks /obj/machinery/computer/general_air_control - tanks, - // Tanks+Core /obj/machinery/computer/general_air_control/large_tank_control - input_info, - output_info, - input_flow_setting, - pressure_setting, - max_pressure, - max_flowrate, - // Core /obj/machinery/computer/general_air_control/supermatter_core - core, - } = data; - - let sectionName = 'Unknown Control System'; - if (tanks) { - sectionName = 'Tank Control System'; - } else if (core) { - sectionName = 'Core Cooling Control System'; - } - - const inputActions = { - power: () => act('in_toggle_injector'), - apply: () => act('in_set_flowrate'), - refresh: () => act('in_refresh_status'), - slider: (e, val) => - act('adj_input_flow_rate', { - adj_input_flow_rate: val, - }), - }; - - const outputActions = { - power: () => act('out_toggle_power'), - apply: () => act('out_set_pressure'), - refresh: () => act('out_refresh_status'), - slider: (e, val) => act('adj_pressure', { adj_pressure: val }), - }; - - return ( - - - - - ); -}; - -const AtmoControlTankCoreControl = (props) => { - const { - info, - maxSliderValue, - sliderControl, - sliderFill, - unit, - name, - limitName, - actions, - } = props; - - return ( - - actions.refresh()} - > - Refresh - - actions.power()} - > - Power - - > - } - > - - {(info && ( - - {info.power ? 'Injecting' : 'On Hold'} - - )) || ( - - ERROR: Cannot Find {name} Port - actions.refresh()}> - Search - - - )} - actions.apply()} - > - Apply - - } - > - actions.slider(e, val)} - > - {sliderFill ? sliderFill : 'UNK'} {unit} / {sliderControl} {unit} - - - - - ); -}; - -const AtmoControlFuel = (props) => { - const { act, data } = useBackend(); - - const { fuel, automation, device_info } = data; - return ( - - act('injection')} - disabled={automation || !device_info} - > - Inject - - act('refresh_status')}> - Refresh - - act('toggle_injector')} - selected={device_info ? device_info.power : false} - disabled={automation || !device_info} - > - Injector Power - - > - } - > - {device_info ? ( - - - {device_info.power ? 'Injecting' : 'On Hold'} - - - {device_info.volume_rate} - - - act('toggle_automation')} - > - {automation ? 'Engaged' : 'Disengaged'} - - - - ) : ( - <> - ERROR: Cannot Find Device - act('refresh_status')}> - Search - - > - )} - - ); -}; diff --git a/tgui/packages/tgui/interfaces/GeneralAtmoControl/FuelControls.tsx b/tgui/packages/tgui/interfaces/GeneralAtmoControl/FuelControls.tsx new file mode 100644 index 00000000000..1a1796428c6 --- /dev/null +++ b/tgui/packages/tgui/interfaces/GeneralAtmoControl/FuelControls.tsx @@ -0,0 +1,63 @@ +import { useBackend } from '../../backend'; +import { Box, Button, LabeledList, Section } from '../../components'; +import { Data } from './types'; + +export const AtmoControlFuel = (props) => { + const { act, data } = useBackend(); + + const { automation, device_info } = data; + return ( + + act('injection')} + disabled={automation || !device_info} + > + Inject + + act('refresh_status')}> + Refresh + + act('toggle_injector')} + selected={device_info ? device_info.power : false} + disabled={automation || !device_info} + > + Injector Power + + > + } + > + {device_info ? ( + + + {device_info.power ? 'Injecting' : 'On Hold'} + + + {device_info.volume_rate} + + + act('toggle_automation')} + > + {automation ? 'Engaged' : 'Disengaged'} + + + + ) : ( + <> + ERROR: Cannot Find Device + act('refresh_status')}> + Search + + > + )} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/GeneralAtmoControl/Sensors.tsx b/tgui/packages/tgui/interfaces/GeneralAtmoControl/Sensors.tsx new file mode 100644 index 00000000000..b1024b08fc8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/GeneralAtmoControl/Sensors.tsx @@ -0,0 +1,65 @@ +import { Box, Flex, LabeledList, Section } from '../../components'; +import { sensor } from './types'; + +export const AtmoControlSensors = (props: { sensors: sensor[] }) => { + const { sensors } = props; + + if (!sensors) { + return ( + + No Sensors Connected. + + ); + } else { + return ( + + {sensors.map((sensor) => ( + + + + ))} + + ); + } +}; + +const AtmoSensor = (props: { sensor: sensor }) => { + const { sensor } = props; + + if (!sensor.sensor_data) { + return UNABLE TO FIND SENSOR; + } + + const { pressure, temperature, oxygen, nitrogen, carbon_dioxide, phoron } = + sensor.sensor_data; + + let labeledListContents: React.JSX.Element[] = []; + if (pressure) { + labeledListContents.push( + {pressure} kPa, + ); + } + + if (temperature) { + labeledListContents.push( + {temperature} K, + ); + } + + if (oxygen || nitrogen || carbon_dioxide || phoron) { + labeledListContents.push( + + + {oxygen ? ({oxygen}% O²) : null} + {nitrogen ? ({nitrogen}% N²) : null} + {carbon_dioxide ? ( + ({carbon_dioxide}% CO²) + ) : null} + {phoron ? ({phoron}% TX) : null} + + , + ); + } + + return {labeledListContents.map((item) => item)}; +}; diff --git a/tgui/packages/tgui/interfaces/GeneralAtmoControl/TankControls.tsx b/tgui/packages/tgui/interfaces/GeneralAtmoControl/TankControls.tsx new file mode 100644 index 00000000000..bd11ac243ee --- /dev/null +++ b/tgui/packages/tgui/interfaces/GeneralAtmoControl/TankControls.tsx @@ -0,0 +1,148 @@ +import { useBackend } from '../../backend'; +import { Box, Button, LabeledList, Section, Slider } from '../../components'; +import { Data } from './types'; + +export const AtmoControlTankCore = (props) => { + const { act, data } = useBackend(); + + const { + // Tanks /obj/machinery/computer/general_air_control + tanks, + // Tanks+Core /obj/machinery/computer/general_air_control/large_tank_control + input_info, + output_info, + input_flow_setting, + pressure_setting, + max_pressure, + max_flowrate, + // Core /obj/machinery/computer/general_air_control/supermatter_core + core, + } = data; + + let sectionName = 'Unknown Control System'; + if (tanks) { + sectionName = 'Tank Control System'; + } else if (core) { + sectionName = 'Core Cooling Control System'; + } + + const inputActions = { + power: () => act('in_toggle_injector'), + apply: () => act('in_set_flowrate'), + refresh: () => act('in_refresh_status'), + slider: (e, val: number) => + act('adj_input_flow_rate', { + adj_input_flow_rate: val, + }), + }; + + const outputActions = { + power: () => act('out_toggle_power'), + apply: () => act('out_set_pressure'), + refresh: () => act('out_refresh_status'), + slider: (e, val: number) => act('adj_pressure', { adj_pressure: val }), + }; + + return ( + + + + + ); +}; + +const AtmoControlTankCoreControl = (props) => { + const { + info, + maxSliderValue, + sliderControl, + sliderFill, + unit, + name, + limitName, + actions, + } = props; + + return ( + + actions.refresh()} + > + Refresh + + actions.power()} + > + Power + + > + } + > + + {(info && ( + + {info.power ? 'Injecting' : 'On Hold'} + + )) || ( + + ERROR: Cannot Find {name} Port + actions.refresh()}> + Search + + + )} + actions.apply()} + > + Apply + + } + > + actions.slider(e, val)} + > + {sliderFill ? sliderFill : 'UNK'} {unit} / {sliderControl} {unit} + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/GeneralAtmoControl/index.tsx b/tgui/packages/tgui/interfaces/GeneralAtmoControl/index.tsx new file mode 100644 index 00000000000..22d8ac79efe --- /dev/null +++ b/tgui/packages/tgui/interfaces/GeneralAtmoControl/index.tsx @@ -0,0 +1,34 @@ +import { useBackend } from '../../backend'; +import { Window } from '../../layouts'; +import { AtmoControlFuel } from './FuelControls'; +import { AtmoControlSensors } from './Sensors'; +import { AtmoControlTankCore } from './TankControls'; +import { Data } from './types'; + +export const GeneralAtmoControl = (props) => { + const { data } = useBackend(); + + // While many of these variables are unused, it's helpful to have a consistent + // list of all possible parameters in the core component of this UI. + // So, keep them here and update them as necessary, pretty please. + const { + // All + sensors, + // Tanks /obj/machinery/computer/general_air_control + tanks, + // Core /obj/machinery/computer/general_air_control/supermatter_core + core, + // Fuel /obj/machinery/computer/general_air_control/fuel_injection + fuel, + } = data; + + return ( + + + + {(core || tanks) && } + {fuel && } + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/GeneralAtmoControl/types.ts b/tgui/packages/tgui/interfaces/GeneralAtmoControl/types.ts new file mode 100644 index 00000000000..f430e495dee --- /dev/null +++ b/tgui/packages/tgui/interfaces/GeneralAtmoControl/types.ts @@ -0,0 +1,29 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + sensors: sensor[]; + tanks: BooleanLike; + core: BooleanLike; + fuel: BooleanLike; + automation: BooleanLike; + input_info: { power: number; volume_rate: number } | null | undefined; + output_info: { power: number; output_pressure: number } | null | undefined; + device_info: { power: number; volume_rate: number } | null | undefined; + input_flow_setting: number | undefined; + pressure_setting: number | undefined; + max_pressure: number | undefined; + max_flowrate: number | undefined; +}; + +export type sensor = { + long_name: string; + sensor_data: { + pressure: number; + temperature: number; + oxygen: number; + nitrogen: number; + carbon_dioxide: number; + phoron: number; + other: number; + }; +}; diff --git a/tgui/packages/tgui/interfaces/GeneralRecords.jsx b/tgui/packages/tgui/interfaces/GeneralRecords.jsx deleted file mode 100644 index 958b3de10c7..00000000000 --- a/tgui/packages/tgui/interfaces/GeneralRecords.jsx +++ /dev/null @@ -1,280 +0,0 @@ -import { filter } from 'common/collections'; -import { flow } from 'common/fp'; -import { createSearch } from 'common/string'; -import { useState } from 'react'; - -import { useBackend } from '../backend'; -import { - Box, - Button, - Icon, - Input, - LabeledList, - Section, - Tabs, -} from '../components'; -import { Window } from '../layouts'; -import { ComplexModal, modalOpen } from './common/ComplexModal'; -import { LoginInfo } from './common/LoginInfo'; -import { LoginScreen } from './common/LoginScreen'; -import { TemporaryNotice } from './common/TemporaryNotice'; - -const doEdit = (field) => { - modalOpen('edit', { - field: field.edit, - value: field.value, - }); -}; - -export const GeneralRecords = (_properties) => { - const { data } = useBackend(); - const { authenticated, screen } = data; - if (!authenticated) { - return ( - - - - - - ); - } - - let body; - if (screen === 2) { - // List Records - body = ; - } else if (screen === 3) { - // Record Maintenance - body = ; - } else if (screen === 4) { - // View Records - body = ; - } - - return ( - - - - - - - - {body} - - - - ); -}; - -/** - * Record selector. - * - * Filters records, applies search terms and sorts the alphabetically. - */ -const selectRecords = (records, searchText = '') => { - const nameSearch = createSearch(searchText, (record) => record.name); - const idSearch = createSearch(searchText, (record) => record.id); - const dnaSearch = createSearch(searchText, (record) => record.b_dna); - let fl = flow([ - // Optional search term - searchText && - filter((record) => { - return nameSearch(record) || idSearch(record) || dnaSearch(record); - }), - ])(records); - return fl; -}; - -const GeneralRecordsList = (_properties) => { - const { act, data } = useBackend(); - - const [searchText, setSearchText] = useState(''); - - const records = selectRecords(data.records, searchText); - return ( - <> - - act('new')}> - New Record - - - setSearchText(value)} - /> - - {records.map((record, i) => ( - act('d_rec', { d_rec: record.ref })} - > - {record.id + ': ' + record.name} - - ))} - - > - ); -}; - -const GeneralRecordsMaintenance = (_properties) => { - const { act } = useBackend(); - return ( - act('del_all')}> - Delete All Employment Records - - ); -}; - -const GeneralRecordsView = (_properties) => { - const { act, data } = useBackend(); - const { general, printing } = data; - return ( - <> - - - - - act('del_r')} - > - Delete Employment Record - - act('print_p')} - > - Print Entry - - - act('screen', { screen: 2 })} - > - Back - - - > - ); -}; - -const GeneralRecordsViewGeneral = (_properties) => { - const { act, data } = useBackend(); - const { general } = data; - if (!general || !general.fields) { - return ( - - General record lost! - act('new')}> - New Record - - - ); - } - return ( - <> - - - {general.fields.map((field, i) => ( - - - {field.value} - - {!!field.edit && ( - doEdit(field)} /> - )} - - ))} - - - {general.skills || 'No data found.'} - - - {general.comments.length === 0 ? ( - No comments found. - ) : ( - general.comments.map((comment, i) => ( - - - {comment.header} - - - {comment.text} - act('del_c', { del_c: i + 1 })} - /> - - )) - )} - - modalOpen('add_c')} - > - Add Entry - - - - - {!!general.has_photos && - general.photos.map((p, i) => ( - - - - Photo #{i + 1} - - ))} - - > - ); -}; - -const GeneralRecordsNavigation = (_properties) => { - const { act, data } = useBackend(); - const { screen } = data; - return ( - - act('screen', { screen: 2 })} - > - - List Records - - act('screen', { screen: 3 })} - > - - Record Maintenance - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/GeneralRecords/GeneralRecordsList.tsx b/tgui/packages/tgui/interfaces/GeneralRecords/GeneralRecordsList.tsx new file mode 100644 index 00000000000..99ea8a12476 --- /dev/null +++ b/tgui/packages/tgui/interfaces/GeneralRecords/GeneralRecordsList.tsx @@ -0,0 +1,40 @@ +import { useState } from 'react'; + +import { useBackend } from '../../backend'; +import { Box, Button, Input } from '../../components'; +import { selectRecords } from './functions'; +import { Data, record } from './types'; + +export const GeneralRecordsList = (props) => { + const { act, data } = useBackend(); + + const [searchText, setSearchText] = useState(''); + + const records: record[] = selectRecords(data.records!, searchText); + return ( + <> + + act('new')}> + New Record + + + setSearchText(value)} + /> + + {records.map((record, i) => ( + act('d_rec', { d_rec: record.ref })} + > + {record.id + ': ' + record.name} + + ))} + + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/GeneralRecords/GeneralRecordsOptions.tsx b/tgui/packages/tgui/interfaces/GeneralRecords/GeneralRecordsOptions.tsx new file mode 100644 index 00000000000..5db9a5c321d --- /dev/null +++ b/tgui/packages/tgui/interfaces/GeneralRecords/GeneralRecordsOptions.tsx @@ -0,0 +1,75 @@ +import { useBackend } from '../../backend'; +import { Button, Icon, Section, Tabs } from '../../components'; +import { GeneralRecordsViewGeneral } from './GeneralRecordsViewGeneral'; +import { Data } from './types'; + +export const GeneralRecordsMaintenance = (props) => { + const { act } = useBackend(); + return ( + act('del_all')}> + Delete All Employment Records + + ); +}; + +export const GeneralRecordsView = (props) => { + const { act, data } = useBackend(); + const { general, printing } = data; + return ( + <> + + + + + act('del_r')} + > + Delete Employment Record + + act('print_p')} + > + Print Entry + + + act('screen', { screen: 2 })} + > + Back + + + > + ); +}; + +export const GeneralRecordsNavigation = (props) => { + const { act, data } = useBackend(); + const { screen } = data; + return ( + + act('screen', { screen: 2 })} + > + + List Records + + act('screen', { screen: 3 })} + > + + Record Maintenance + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/GeneralRecords/GeneralRecordsViewGeneral.tsx b/tgui/packages/tgui/interfaces/GeneralRecords/GeneralRecordsViewGeneral.tsx new file mode 100644 index 00000000000..5d762469830 --- /dev/null +++ b/tgui/packages/tgui/interfaces/GeneralRecords/GeneralRecordsViewGeneral.tsx @@ -0,0 +1,104 @@ +import { useBackend } from '../../backend'; +import { Box, Button, Image, LabeledList, Section } from '../../components'; +import { modalOpen } from '../common/ComplexModal'; +import { doEdit } from './functions'; +import { Data } from './types'; + +export const GeneralRecordsViewGeneral = (props) => { + const { act, data } = useBackend(); + const { general } = data; + if (!general || !general.fields) { + return ( + + General record lost! + act('new')}> + New Record + + + ); + } + return ( + <> + + + {general.fields.map((field, i) => ( + + + {field.value} + {!!field.edit && ( + doEdit(field)} + /> + )} + + + ))} + + + {general.skills || 'No data found.'} + + + {general.comments && general.comments.length === 0 ? ( + No comments found. + ) : ( + general.comments && + general.comments.map((comment, i) => ( + + + {comment.header} + + + {comment.text} + act('del_c', { del_c: i + 1 })} + /> + + )) + )} + + modalOpen('add_c')} + > + Add Entry + + + + + {!!general.has_photos && + general.photos!.map((p, i) => ( + + + + Photo #{i + 1} + + ))} + + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/GeneralRecords/functions.ts b/tgui/packages/tgui/interfaces/GeneralRecords/functions.ts new file mode 100644 index 00000000000..f546f955dc9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/GeneralRecords/functions.ts @@ -0,0 +1,32 @@ +import { filter } from 'common/collections'; +import { flow } from 'common/fp'; +import { createSearch } from 'common/string'; + +import { modalOpen } from '../common/ComplexModal'; +import { field, record } from './types'; + +export function doEdit(field: field) { + modalOpen('edit', { + field: field.edit, + value: field.value, + }); +} + +/** + * Record selector. + * + * Filters records, applies search terms and sorts the alphabetically. + */ +export function selectRecords(records: record[], searchText = ''): record[] { + const nameSearch = createSearch(searchText, (record: record) => record.name); + const idSearch = createSearch(searchText, (record: record) => record.id); + const dnaSearch = createSearch(searchText, (record: record) => record.b_dna); + const fl: record[] = flow([ + // Optional search term + searchText && + filter((record: record) => { + return nameSearch(record) || idSearch(record) || dnaSearch(record); + }), + ])(records); + return fl; +} diff --git a/tgui/packages/tgui/interfaces/GeneralRecords/index.tsx b/tgui/packages/tgui/interfaces/GeneralRecords/index.tsx new file mode 100644 index 00000000000..e752cc59106 --- /dev/null +++ b/tgui/packages/tgui/interfaces/GeneralRecords/index.tsx @@ -0,0 +1,47 @@ +import { useBackend } from '../../backend'; +import { Section } from '../../components'; +import { Window } from '../../layouts'; +import { ComplexModal } from '../common/ComplexModal'; +import { LoginInfo } from '../common/LoginInfo'; +import { LoginScreen } from '../common/LoginScreen'; +import { TemporaryNotice } from '../common/TemporaryNotice'; +import { GeneralRecordsList } from './GeneralRecordsList'; +import { + GeneralRecordsMaintenance, + GeneralRecordsNavigation, + GeneralRecordsView, +} from './GeneralRecordsOptions'; +import { Data } from './types'; + +export const GeneralRecords = (props) => { + const { data } = useBackend(); + const { authenticated, screen } = data; + if (!authenticated) { + return ( + + + + + + ); + } + + const body: React.JSX.Element[] = []; + body[2] = ; + body[3] = ; + body[4] = ; + + return ( + + + + + + + + {(screen && body[screen]) || ''} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/GeneralRecords/types.ts b/tgui/packages/tgui/interfaces/GeneralRecords/types.ts new file mode 100644 index 00000000000..d2990bfdb6f --- /dev/null +++ b/tgui/packages/tgui/interfaces/GeneralRecords/types.ts @@ -0,0 +1,31 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + temp: { color: string; text: string } | null; + scan: string | null; + authenticated: BooleanLike; + rank: string | null; + screen: number | null; + printing: BooleanLike; + isAI: BooleanLike; + isRobot: BooleanLike; + records: record[] | undefined; + general: + | { + fields: field[] | undefined; + photos: string[] | undefined; + has_photos: BooleanLike; + skills: string[] | undefined; + comments: { header: string; text: string }[] | undefined; + empty: BooleanLike; + } + | undefined; +}; + +export type record = { ref: string; id: string; name: string; b_dna: string }; + +export type field = { + field: string; + value: string | number; + edit: string | null; +}; diff --git a/tgui/packages/tgui/interfaces/MedicalRecords.jsx b/tgui/packages/tgui/interfaces/MedicalRecords.jsx deleted file mode 100644 index e7df9755313..00000000000 --- a/tgui/packages/tgui/interfaces/MedicalRecords.jsx +++ /dev/null @@ -1,427 +0,0 @@ -import { Fragment } from 'react'; - -import { useBackend } from '../backend'; -import { - Box, - Button, - Collapsible, - Icon, - Input, - LabeledList, - Section, - Tabs, -} from '../components'; -import { - ComplexModal, - modalOpen, - modalRegisterBodyOverride, -} from '../interfaces/common/ComplexModal'; -import { Window } from '../layouts'; -import { LoginInfo } from './common/LoginInfo'; -import { LoginScreen } from './common/LoginScreen'; -import { TemporaryNotice } from './common/TemporaryNotice'; - -const severities = { - Minor: 'good', - Medium: 'average', - 'Dangerous!': 'bad', - Harmful: 'bad', - 'BIOHAZARD THREAT!': 'bad', -}; - -const doEdit = (field) => { - modalOpen('edit', { - field: field.edit, - value: field.value, - }); -}; - -const virusModalBodyOverride = (modal) => { - const { act } = useBackend(); - const virus = modal.args; - return ( - act('modal_close')} /> - } - > - - - - {virus.spread_text} Transmission - - - {virus.antigen} - - - {virus.rate} - - - {virus.resistance}% - - - {virus.species} - - - - {virus.symptoms.map((s) => ( - - - Strength: - {' '} - {s.strength} - - Aggressiveness: - {' '} - {s.aggressiveness} - - ))} - - - - - - ); -}; - -export const MedicalRecords = (_properties) => { - const { data } = useBackend(); - const { authenticated, screen } = data; - if (!authenticated) { - return ( - - - - - - ); - } - - let body; - if (screen === 2) { - // List Records - body = ; - } else if (screen === 3) { - // Record Maintenance - body = ; - } else if (screen === 4) { - // View Records - body = ; - } else if (screen === 5) { - // Virus Database - body = ; - } else if (screen === 6) { - // Medbot Tracking - body = ; - } - - return ( - - - - - - - - {body} - - - - ); -}; - -const MedicalRecordsList = (_properties) => { - const { act, data } = useBackend(); - const { records } = data; - return ( - <> - act('search', { t1: value })} - /> - - {records.map((record, i) => ( - act('d_rec', { d_rec: record.ref })} - > - {record.id + ': ' + record.name} - - ))} - - > - ); -}; - -const MedicalRecordsMaintenance = (_properties) => { - const { act } = useBackend(); - return ( - <> - - Backup to Disk - - - - Upload from Disk - - - act('del_all')}> - Delete All Medical Records - - > - ); -}; - -const MedicalRecordsView = (_properties) => { - const { act, data } = useBackend(); - const { medical, printing } = data; - return ( - <> - - - - - - - - act('del_r')} - > - Delete Medical Record - - act('print_p')} - > - Print Entry - - - act('screen', { screen: 2 })} - > - Back - - - > - ); -}; - -const MedicalRecordsViewGeneral = (_properties) => { - const { data } = useBackend(); - const { general } = data; - if (!general || !general.fields) { - return General records lost!; - } - return ( - <> - - - {general.fields.map((field, i) => ( - - - {field.value} - - {!!field.edit && ( - doEdit(field)} /> - )} - - ))} - - - - {!!general.has_photos && - general.photos.map((p, i) => ( - - - - Photo #{i + 1} - - ))} - - > - ); -}; - -const MedicalRecordsViewMedical = (_properties) => { - const { act, data } = useBackend(); - const { medical } = data; - if (!medical || !medical.fields) { - return ( - - Medical records lost! - act('new')}> - New Record - - - ); - } - return ( - <> - - {medical.fields.map((field, i) => ( - - - {field.value} - doEdit(field)} - /> - - - ))} - - - {medical.comments.length === 0 ? ( - No comments found. - ) : ( - medical.comments.map((comment, i) => ( - - - {comment.header} - - - {comment.text} - act('del_c', { del_c: i + 1 })} - /> - - )) - )} - - modalOpen('add_c')} - > - Add Entry - - - > - ); -}; - -const MedicalRecordsViruses = (_properties) => { - const { act, data } = useBackend(); - const { virus } = data; - virus.sort((a, b) => (a.name > b.name ? 1 : -1)); - return virus.map((vir, i) => ( - - act('vir', { vir: vir.D })} - > - {vir.name} - - - - )); -}; - -const MedicalRecordsMedbots = (_properties) => { - const { data } = useBackend(); - const { medbots } = data; - if (medbots.length === 0) { - return There are no Medbots.; - } - return medbots.map((medbot, i) => ( - - - - - {medbot.area || 'Unknown'} ({medbot.x}, {medbot.y}) - - - {medbot.on ? ( - <> - Online - - {medbot.use_beaker - ? 'Reservoir: ' + - medbot.total_volume + - '/' + - medbot.maximum_volume - : 'Using internal synthesizer.'} - - > - ) : ( - Offline - )} - - - - - )); -}; - -const MedicalRecordsNavigation = (_properties) => { - const { act, data } = useBackend(); - const { screen } = data; - return ( - - act('screen', { screen: 2 })} - > - - List Records - - act('screen', { screen: 5 })} - > - - Virus Database - - act('screen', { screen: 6 })} - > - - Medbot Tracking - - act('screen', { screen: 3 })} - > - - Record Maintenance - - - ); -}; - -modalRegisterBodyOverride('virus', virusModalBodyOverride); diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsList.tsx b/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsList.tsx new file mode 100644 index 00000000000..ae0fc26729d --- /dev/null +++ b/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsList.tsx @@ -0,0 +1,29 @@ +import { useBackend } from '../../backend'; +import { Box, Button, Input } from '../../components'; +import { Data } from './types'; + +export const MedicalRecordsList = (props) => { + const { act, data } = useBackend(); + const { records } = data; + return ( + <> + act('search', { t1: value })} + /> + + {records.map((record, i) => ( + act('d_rec', { d_rec: record.ref })} + > + {record.id + ': ' + record.name} + + ))} + + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsMedbots.tsx b/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsMedbots.tsx new file mode 100644 index 00000000000..f0389b1c483 --- /dev/null +++ b/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsMedbots.tsx @@ -0,0 +1,39 @@ +import { useBackend } from '../../backend'; +import { Box, Collapsible, LabeledList } from '../../components'; +import { Data } from './types'; + +export const MedicalRecordsMedbots = (props) => { + const { data } = useBackend(); + const { medbots } = data; + if (!medbots || medbots.length === 0) { + return There are no Medbots.; + } + return medbots.map((medbot, i) => ( + + + + + {medbot.area || 'Unknown'} ({medbot.x}, {medbot.y}) + + + {medbot.on ? ( + <> + Online + + {medbot.use_beaker + ? 'Reservoir: ' + + medbot.total_volume + + '/' + + medbot.maximum_volume + : 'Using internal synthesizer.'} + + > + ) : ( + Offline + )} + + + + + )); +}; diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsOptions.tsx b/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsOptions.tsx new file mode 100644 index 00000000000..037fa47dda5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsOptions.tsx @@ -0,0 +1,103 @@ +import { useBackend } from '../../backend'; +import { Button, Icon, Section, Tabs } from '../../components'; +import { MedicalRecordsViewGeneral } from './MedicalRecordsViewGeneral'; +import { MedicalRecordsViewMedical } from './MedicalRecordsViewMedical'; +import { Data } from './types'; + +export const MedicalRecordsMaintenance = (props) => { + const { act } = useBackend(); + return ( + <> + + Backup to Disk + + + + Upload from Disk + + + act('del_all')}> + Delete All Medical Records + + > + ); +}; + +export const MedicalRecordsView = (props) => { + const { act, data } = useBackend(); + const { medical, printing } = data; + return ( + <> + + + + + + + + act('del_r')} + > + Delete Medical Record + + act('print_p')} + > + Print Entry + + + act('screen', { screen: 2 })} + > + Back + + + > + ); +}; + +export const MedicalRecordsNavigation = (props) => { + const { act, data } = useBackend(); + const { screen } = data; + return ( + + act('screen', { screen: 2 })} + > + + List Records + + act('screen', { screen: 5 })} + > + + Virus Database + + act('screen', { screen: 6 })} + > + + Medbot Tracking + + act('screen', { screen: 3 })} + > + + Record Maintenance + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsViewGeneral.tsx b/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsViewGeneral.tsx new file mode 100644 index 00000000000..01ca768df89 --- /dev/null +++ b/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsViewGeneral.tsx @@ -0,0 +1,61 @@ +import { useBackend } from '../../backend'; +import { Box, Button, Image, LabeledList } from '../../components'; +import { doEdit } from '../GeneralRecords/functions'; +import { Data } from './types'; + +export const MedicalRecordsViewGeneral = (props) => { + const { data } = useBackend(); + const { general } = data; + if (!general || !general.fields) { + return General records lost!; + } + return ( + <> + + + {general.fields.map((field, i) => ( + + + {field.value} + {!!field.edit && ( + doEdit(field)} + /> + )} + + + ))} + + + + {!!general.has_photos && + general.photos!.map((p, i) => ( + + + + Photo #{i + 1} + + ))} + + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsViewMedical.tsx b/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsViewMedical.tsx new file mode 100644 index 00000000000..dc3b07c08b2 --- /dev/null +++ b/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsViewMedical.tsx @@ -0,0 +1,66 @@ +import { useBackend } from '../../backend'; +import { Box, Button, LabeledList, Section } from '../../components'; +import { modalOpen } from '../../interfaces/common/ComplexModal'; +import { doEdit } from '../GeneralRecords/functions'; +import { Data } from './types'; + +export const MedicalRecordsViewMedical = (props) => { + const { act, data } = useBackend(); + const { medical } = data; + if (!medical || !medical.fields) { + return ( + + Medical records lost! + act('new')}> + New Record + + + ); + } + return ( + <> + + {medical.fields.map((field, i) => ( + + + {field.value} + doEdit(field)} /> + + + ))} + + + {medical.comments && medical.comments.length === 0 ? ( + No comments found. + ) : ( + medical.comments && + medical.comments.map((comment, i) => ( + + + {comment.header} + + + {comment.text} + act('del_c', { del_c: i + 1 })} + /> + + )) + )} + + modalOpen('add_c')} + > + Add Entry + + + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsViruses.tsx b/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsViruses.tsx new file mode 100644 index 00000000000..eb7ea731b9d --- /dev/null +++ b/tgui/packages/tgui/interfaces/MedicalRecords/MedicalRecordsViruses.tsx @@ -0,0 +1,26 @@ +import { Fragment } from 'react'; + +import { useBackend } from '../../backend'; +import { Button } from '../../components'; +import { Data } from './types'; + +export const MedicalRecordsViruses = (props) => { + const { act, data } = useBackend(); + const { virus } = data; + virus && virus.sort((a, b) => (a.name > b.name ? 1 : -1)); + return ( + virus && + virus.map((vir, i) => ( + + act('vir', { vir: vir.D })} + > + {vir.name} + + + + )) + ); +}; diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/constants.ts b/tgui/packages/tgui/interfaces/MedicalRecords/constants.ts new file mode 100644 index 00000000000..08b21c0b9f5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/MedicalRecords/constants.ts @@ -0,0 +1,7 @@ +export const severities = { + Minor: 'good', + Medium: 'average', + 'Dangerous!': 'bad', + Harmful: 'bad', + 'BIOHAZARD THREAT!': 'bad', +}; diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/index.tsx b/tgui/packages/tgui/interfaces/MedicalRecords/index.tsx new file mode 100644 index 00000000000..61fd434ab91 --- /dev/null +++ b/tgui/packages/tgui/interfaces/MedicalRecords/index.tsx @@ -0,0 +1,62 @@ +import { useBackend } from '../../backend'; +import { Section } from '../../components'; +import { + ComplexModal, + modalRegisterBodyOverride, +} from '../../interfaces/common/ComplexModal'; +import { Window } from '../../layouts'; +import { LoginInfo } from '../common/LoginInfo'; +import { LoginScreen } from '../common/LoginScreen'; +import { TemporaryNotice } from '../common/TemporaryNotice'; +import { MedicalRecordsList } from './MedicalRecordsList'; +import { MedicalRecordsMedbots } from './MedicalRecordsMedbots'; +import { + MedicalRecordsMaintenance, + MedicalRecordsNavigation, + MedicalRecordsView, +} from './MedicalRecordsOptions'; +import { MedicalRecordsViruses } from './MedicalRecordsViruses'; +import { Data } from './types'; +import { virusModalBodyOverride } from './virusModalBodyOverride'; + +export const MedicalRecords = (props) => { + const { data } = useBackend(); + const { authenticated, screen } = data; + if (!authenticated) { + return ( + + + + + + ); + } + + const body: React.JSX.Element[] = []; + // List Records + body[2] = ; + // Record Maintenance + body[3] = ; + // View Records + body[4] = ; + // Virus Database + body[5] = ; + // Medbot Tracking + body[6] = ; + + return ( + + + + + + + + {(screen && body[screen]) || ''} + + + + ); +}; + +modalRegisterBodyOverride('virus', virusModalBodyOverride); diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/types.ts b/tgui/packages/tgui/interfaces/MedicalRecords/types.ts new file mode 100644 index 00000000000..2f8e1e0a61c --- /dev/null +++ b/tgui/packages/tgui/interfaces/MedicalRecords/types.ts @@ -0,0 +1,73 @@ +import { BooleanLike } from 'common/react'; + +import { field } from '../GeneralRecords/types'; + +export type Data = { + temp: { color: string; text: string } | null; + scan: string | null; + authenticated: BooleanLike; + rank: string | null; + screen: number | null; + printing: BooleanLike; + isAI: BooleanLike; + isRobot: BooleanLike; + records: record[]; + general: + | { + fields: field[] | undefined; + photos: string[] | undefined; + has_photos: BooleanLike; + empty: BooleanLike; + } + | undefined; + medical: + | { + fields: field[] | undefined; + comments: { header: string; text: string }[] | undefined; + empty: BooleanLike; + } + | undefined; + virus: { name: string; D: string }[] | undefined; + medbots: + | { + name: string; + area: string; + x: number; + y: number; + z: number; + on: BooleanLike; + use_beaker: BooleanLike; + total_volume: number | undefined; + maximum_volume: number | undefined; + }[] + | undefined; + modal: modalData; +}; + +export type modalData = { + id: string; + text: string; + args: { + name: string; + spreadtype: string; + antigen: string; + rate: number; + resistance: number; + species: string; + ref: string; + symptoms: { + stage: number; + name: string; + strength: string; + aggressiveness: string; + }[]; + record: string; + }; + modal_type: string; +}; + +type record = { + ref: string; + id: string; + name: string; +}; diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/virusModalBodyOverride.tsx b/tgui/packages/tgui/interfaces/MedicalRecords/virusModalBodyOverride.tsx new file mode 100644 index 00000000000..06f0af5a868 --- /dev/null +++ b/tgui/packages/tgui/interfaces/MedicalRecords/virusModalBodyOverride.tsx @@ -0,0 +1,53 @@ +import { useBackend } from '../../backend'; +import { Box, Button, LabeledList, Section } from '../../components'; +import { modalData } from './types'; + +export const virusModalBodyOverride = (modal: modalData) => { + const { act } = useBackend(); + const virus = modal.args; + return ( + act('modal_close')} /> + } + > + + + + {virus.spreadtype} Transmission + + + {virus.antigen} + + + {virus.rate} + + + {virus.resistance}% + + + {virus.species} + + + + {virus.symptoms.map((s) => ( + + + Strength: + {' '} + {s.strength} + + Aggressiveness: + {' '} + {s.aggressiveness} + + ))} + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/MessageMonitor/types.ts b/tgui/packages/tgui/interfaces/MessageMonitor/types.ts index 9ec9d76c239..c38fb0b2ee8 100644 --- a/tgui/packages/tgui/interfaces/MessageMonitor/types.ts +++ b/tgui/packages/tgui/interfaces/MessageMonitor/types.ts @@ -5,7 +5,7 @@ export type Data = { customrecepient: string; customjob: string; custommessage: string; - temp: string | null; + temp: { color: string; text: string } | null; hacking: BooleanLike; emag: BooleanLike; auth: BooleanLike; diff --git a/tgui/packages/tgui/interfaces/NIF.jsx b/tgui/packages/tgui/interfaces/NIF.jsx deleted file mode 100644 index f3e8d77b335..00000000000 --- a/tgui/packages/tgui/interfaces/NIF.jsx +++ /dev/null @@ -1,289 +0,0 @@ -import { useState } from 'react'; - -import { useBackend } from '../backend'; -import { - AnimatedNumber, - Box, - Button, - Dropdown, - Flex, - LabeledList, - Modal, - NoticeBox, - ProgressBar, - Section, - Table, -} from '../components'; -import { Window } from '../layouts'; - -const NIF_WORKING = 0; -const NIF_POWFAIL = 1; -const NIF_TEMPFAIL = 2; -const NIF_INSTALLING = 3; -const NIF_PREINSTALL = 4; - -export const NIF = (props) => { - const { act, config, data } = useBackend(); - - const { theme, last_notification } = data; - - const [settingsOpen, setSettingsOpen] = useState(false); - const [viewingModule, setViewing] = useState(null); - - return ( - - - {!!last_notification && ( - - - - - {last_notification} - - - act('dismissNotification')} - /> - - - - - )} - {!!viewingModule && ( - - - { - act('uninstall', { module: viewingModule.ref }); - setViewing(null); - }} - > - Uninstall - - setViewing(null)} - /> - > - } - > - {viewingModule.desc} - - It consumes - - {viewingModule.p_drain} - - energy units while installed, and - - {viewingModule.a_drain} - - additionally while active. - - - It is {viewingModule.illegal ? 'NOT ' : ''}a legal software - package. - - - The MSRP of the package is - - {viewingModule.cost}â‚®. - - - - The difficulty to construct the associated implant is - - Rating {viewingModule.wear} - - . - - - - )} - setSettingsOpen(!settingsOpen)} - /> - } - > - {(settingsOpen && ) || ( - - )} - - - - ); -}; - -const getNifCondition = (nif_stat, nif_percent) => { - switch (nif_stat) { - case NIF_WORKING: - if (nif_percent < 25) { - return 'Service Needed Soon'; - } else { - return 'Operating Normally'; - } - case NIF_POWFAIL: - return 'Insufficient Energy!'; - case NIF_TEMPFAIL: - return 'System Failure!'; - case NIF_INSTALLING: - return 'Adapting To User'; - } - return 'Unknown'; -}; - -const getNutritionText = (nutrition, isSynthetic) => { - if (isSynthetic) { - if (nutrition >= 450) { - return 'Overcharged'; - } else if (nutrition >= 250) { - return 'Good Charge'; - } - return 'Low Charge'; - } - - if (nutrition >= 250) { - return 'NIF Power Requirement met.'; - } else if (nutrition >= 150) { - return 'Fluctuations in available power.'; - } - return 'Power failure imminent.'; -}; - -const NIFMain = (props) => { - const { act, config, data } = useBackend(); - - const { nif_percent, nif_stat, nutrition, isSynthetic, modules } = data; - - const { setViewing } = props; - - return ( - - - - - {getNifCondition(nif_stat, nif_percent)} ( - - %) - - - - - {getNutritionText(nutrition, isSynthetic)} - - - - - - {modules.map((module) => ( - - act('uninstall', { module: module.ref })} - /> - setViewing(module)} - tooltip="View Information" - tooltipPosition="left" - /> - > - } - > - {(module.activates && ( - act('toggle_module', { module: module.ref })} - /> - )) || {module.stat_text}} - - ))} - - - - ); -}; - -const NIFSettings = (props) => { - const { act, data } = useBackend(); - - const { valid_themes, theme } = data; - - return ( - - - - - act('setTheme', { theme: val })} - /> - - {theme ? ( - - { - act('setTheme', { theme: null }); - }} - /> - - ) : ( - '' - )} - - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/NIF/NIFMain.tsx b/tgui/packages/tgui/interfaces/NIF/NIFMain.tsx new file mode 100644 index 00000000000..0d64ac8ab2c --- /dev/null +++ b/tgui/packages/tgui/interfaces/NIF/NIFMain.tsx @@ -0,0 +1,94 @@ +import { useBackend } from '../../backend'; +import { + AnimatedNumber, + Box, + Button, + LabeledList, + ProgressBar, + Section, +} from '../../components'; +import { getNifCondition, getNutritionText } from './functions'; +import { Data } from './types'; + +export const NIFMain = (props) => { + const { act, data } = useBackend(); + + const { nif_percent, nif_stat, nutrition, isSynthetic, modules } = data; + + const { setViewing } = props; + + return ( + + + + + {getNifCondition(nif_stat, nif_percent)} ( + + %) + + + + + {getNutritionText(nutrition, isSynthetic)} + + + + + + {modules.map((module) => ( + + act('uninstall', { module: module.ref })} + /> + setViewing(module)} + tooltip="View Information" + tooltipPosition="left" + /> + > + } + > + {(module.activates && ( + act('toggle_module', { module: module.ref })} + /> + )) || {module.stat_text}} + + ))} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/NIF/NIFSettings.tsx b/tgui/packages/tgui/interfaces/NIF/NIFSettings.tsx new file mode 100644 index 00000000000..108e800680d --- /dev/null +++ b/tgui/packages/tgui/interfaces/NIF/NIFSettings.tsx @@ -0,0 +1,40 @@ +import { useBackend } from '../../backend'; +import { Button, Dropdown, Flex, LabeledList } from '../../components'; +import { Data } from './types'; + +export const NIFSettings = (props) => { + const { act, data } = useBackend(); + + const { valid_themes, theme } = data; + + return ( + + + + + act('setTheme', { theme: val })} + /> + + {theme ? ( + + { + act('setTheme', { theme: null }); + }} + /> + + ) : ( + '' + )} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/NIF/constants.ts b/tgui/packages/tgui/interfaces/NIF/constants.ts new file mode 100644 index 00000000000..1ff36cb5b35 --- /dev/null +++ b/tgui/packages/tgui/interfaces/NIF/constants.ts @@ -0,0 +1,5 @@ +export const NIF_WORKING = 0; +export const NIF_POWFAIL = 1; +export const NIF_TEMPFAIL = 2; +export const NIF_INSTALLING = 3; +export const NIF_PREINSTALL = 4; diff --git a/tgui/packages/tgui/interfaces/NIF/functions.ts b/tgui/packages/tgui/interfaces/NIF/functions.ts new file mode 100644 index 00000000000..2be3f36c6e5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/NIF/functions.ts @@ -0,0 +1,47 @@ +import { BooleanLike } from 'common/react'; + +import { + NIF_INSTALLING, + NIF_POWFAIL, + NIF_TEMPFAIL, + NIF_WORKING, +} from './constants'; + +export function getNifCondition(nif_stat: number, nif_percent: number): string { + switch (nif_stat) { + case NIF_WORKING: + if (nif_percent < 25) { + return 'Service Needed Soon'; + } else { + return 'Operating Normally'; + } + case NIF_POWFAIL: + return 'Insufficient Energy!'; + case NIF_TEMPFAIL: + return 'System Failure!'; + case NIF_INSTALLING: + return 'Adapting To User'; + } + return 'Unknown'; +} + +export function getNutritionText( + nutrition: number, + isSynthetic: BooleanLike, +): string { + if (isSynthetic) { + if (nutrition >= 450) { + return 'Overcharged'; + } else if (nutrition >= 250) { + return 'Good Charge'; + } + return 'Low Charge'; + } + + if (nutrition >= 250) { + return 'NIF Power Requirement met.'; + } else if (nutrition >= 150) { + return 'Fluctuations in available power.'; + } + return 'Power failure imminent.'; +} diff --git a/tgui/packages/tgui/interfaces/NIF/index.tsx b/tgui/packages/tgui/interfaces/NIF/index.tsx new file mode 100644 index 00000000000..4118ee0de1b --- /dev/null +++ b/tgui/packages/tgui/interfaces/NIF/index.tsx @@ -0,0 +1,125 @@ +import { useState } from 'react'; + +import { useBackend } from '../../backend'; +import { + Box, + Button, + Modal, + NoticeBox, + Section, + Table, +} from '../../components'; +import { Window } from '../../layouts'; +import { NIFMain } from './NIFMain'; +import { NIFSettings } from './NIFSettings'; +import { Data, module } from './types'; + +export const NIF = (props) => { + const { act, config, data } = useBackend(); + + const { theme, last_notification } = data; + + const [settingsOpen, setSettingsOpen] = useState(false); + const [viewingModule, setViewing] = useState(null); + + return ( + + + {!!last_notification && ( + + + + + {last_notification} + + + act('dismissNotification')} + /> + + + + + )} + {!!viewingModule && ( + + + { + act('uninstall', { module: viewingModule.ref }); + setViewing(null); + }} + > + Uninstall + + setViewing(null)} + /> + > + } + > + {viewingModule.desc} + + It consumes + + {viewingModule.p_drain} + + energy units while installed, and + + {viewingModule.a_drain} + + additionally while active. + + + It is {viewingModule.illegal ? 'NOT ' : ''}a legal software + package. + + + The MSRP of the package is + + {viewingModule.cost}â‚®. + + + + The difficulty to construct the associated implant is + + Rating {viewingModule.wear} + + . + + + + )} + setSettingsOpen(!settingsOpen)} + /> + } + > + {(settingsOpen && ) || ( + + )} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/NIF/types.ts b/tgui/packages/tgui/interfaces/NIF/types.ts new file mode 100644 index 00000000000..7c769858eb3 --- /dev/null +++ b/tgui/packages/tgui/interfaces/NIF/types.ts @@ -0,0 +1,26 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + valid_themes: string[]; + theme: string; + last_notification: string | null; + nutrition: number; + isSynthetic: BooleanLike; + nif_percent: number; + nif_stat: number; + modules: module[]; +}; + +export type module = { + name: string; + desc: string; + p_drain: number; + a_drain: number; + illegal: BooleanLike; + wear: BooleanLike; + cost: number; + activates: BooleanLike; + active: BooleanLike; + stat_text: string; + ref: string; +}; diff --git a/tgui/packages/tgui/interfaces/Newscaster.jsx b/tgui/packages/tgui/interfaces/Newscaster.jsx deleted file mode 100644 index 05e5dff8086..00000000000 --- a/tgui/packages/tgui/interfaces/Newscaster.jsx +++ /dev/null @@ -1,599 +0,0 @@ -import { decodeHtmlEntities } from 'common/string'; - -import { useBackend, useSharedState } from '../backend'; -import { Box, Button, Flex, Input, LabeledList, Section } from '../components'; -import { Window } from '../layouts'; -import { TemporaryNotice } from './common/TemporaryNotice'; - -const NEWSCASTER_SCREEN_MAIN = 'Main Menu'; -const NEWSCASTER_SCREEN_NEWCHANNEL = 'New Channel'; -const NEWSCASTER_SCREEN_VIEWLIST = 'View List'; -const NEWSCASTER_SCREEN_NEWSTORY = 'New Story'; -const NEWSCASTER_SCREEN_PRINT = 'Print'; -const NEWSCASTER_SCREEN_NEWWANTED = 'New Wanted'; -const NEWSCASTER_SCREEN_VIEWWANTED = 'View Wanted'; -const NEWSCASTER_SCREEN_SELECTEDCHANNEL = 'View Selected Channel'; - -export const Newscaster = (props) => { - const { act, data } = useBackend(); - - const { screen, user } = data; - - return ( - - - - - - - ); -}; - -const NewscasterContent = (props) => { - const { act, data } = useBackend(); - - const { user } = data; - - const [screen, setScreen] = useSharedState('screen', NEWSCASTER_SCREEN_MAIN); - let Template = screenToTemplate[screen]; - - return ( - - - - ); -}; - -const NewscasterMainMenu = (props) => { - const { act, data } = useBackend(); - - const { securityCaster, wanted_issue } = data; - - const { setScreen } = props; - - return ( - <> - - {wanted_issue && ( - setScreen(NEWSCASTER_SCREEN_VIEWWANTED)} - color="bad" - > - Read WANTED Issue - - )} - setScreen(NEWSCASTER_SCREEN_VIEWLIST)} - > - View Feed Channels - - setScreen(NEWSCASTER_SCREEN_NEWCHANNEL)} - > - Create Feed Channel - - setScreen(NEWSCASTER_SCREEN_NEWSTORY)} - > - Create Feed Message - - setScreen(NEWSCASTER_SCREEN_PRINT)} - > - Print Newspaper - - - {!!securityCaster && ( - - setScreen(NEWSCASTER_SCREEN_NEWWANTED)} - > - Manage "Wanted" Issue - - - )} - > - ); -}; - -const NewscasterNewChannel = (props) => { - const { act, data } = useBackend(); - - const { channel_name, c_locked, user } = data; - - const { setScreen } = props; - - return ( - setScreen(NEWSCASTER_SCREEN_MAIN)}> - Back - - } - > - - - act('set_channel_name', { val: val })} - /> - - - {user} - - - act('set_channel_lock')} - > - {c_locked ? 'No' : 'Yes'} - - - - act('submit_new_channel')} - > - Submit Channel - - setScreen(NEWSCASTER_SCREEN_MAIN)} - > - Cancel - - - ); -}; - -const NewscasterViewList = (props) => { - const { act, data } = useBackend(); - - const { channels } = data; - - const { setScreen } = props; - - return ( - setScreen(NEWSCASTER_SCREEN_MAIN)}> - Back - - } - > - {channels.map((channel) => ( - { - act('show_channel', { show_channel: channel.ref }); - setScreen(NEWSCASTER_SCREEN_SELECTEDCHANNEL); - }} - > - {decodeHtmlEntities(channel.name)} - - ))} - - ); -}; - -const NewscasterNewStory = (props) => { - const { act, data } = useBackend(); - - const { channel_name, user, title, msg, photo_data } = data; - - const { setScreen } = props; - - return ( - setScreen(NEWSCASTER_SCREEN_MAIN)}> - Back - - } - > - - - act('set_channel_receiving')}> - {channel_name || 'Unset'} - - - - {user} - - - - - - {title || '(no title yet)'} - - - - act('set_new_title')} - icon="pen" - tooltip="Edit Title" - tooltipPosition="left" - /> - - - - - - - - {msg || '(no message yet)'} - - - - act('set_new_message')} - icon="pen" - tooltip="Edit Message" - tooltipPosition="left" - /> - - - - - act('set_attachment')}> - {photo_data ? 'Photo Attached' : 'No Photo'} - - - - act('submit_new_message')} - > - Submit Message - - setScreen(NEWSCASTER_SCREEN_MAIN)} - > - Cancel - - - ); -}; - -const NewscasterPrint = (props) => { - const { act, data } = useBackend(); - - const { total_num, active_num, message_num, paper_remaining } = data; - - const { setScreen } = props; - - return ( - setScreen(NEWSCASTER_SCREEN_MAIN)}> - Back - - } - > - - Newscaster currently serves a total of {total_num} Feed channels,{' '} - {active_num} of which are active, and a total of {message_num} Feed - stories. - - - - {paper_remaining * 100} cm³ - - - act('print_paper')} - > - Print Paper - - setScreen(NEWSCASTER_SCREEN_MAIN)} - > - Cancel - - - ); -}; - -const NewscasterNewWanted = (props) => { - const { act, data } = useBackend(); - - const { channel_name, msg, photo_data, user, wanted_issue } = data; - - const { setScreen } = props; - - return ( - setScreen(NEWSCASTER_SCREEN_MAIN)}> - Back - - } - > - - {!!wanted_issue && ( - - A wanted issue is already in circulation. You can edit or cancel it - below. - - )} - - act('set_channel_name', { val: val })} - /> - - - act('set_wanted_desc', { val: val })} - /> - - - act('set_attachment')}> - {photo_data ? 'Photo Attached' : 'No Photo'} - - - - {user} - - - act('submit_wanted')} - > - Submit Wanted Issue - - {!!wanted_issue && ( - act('cancel_wanted')} - > - Take Down Issue - - )} - setScreen(NEWSCASTER_SCREEN_MAIN)} - > - Cancel - - - ); -}; - -const NewscasterViewWanted = (props) => { - const { act, data } = useBackend(); - - const { wanted_issue } = data; - - const { setScreen } = props; - - if (!wanted_issue) { - return ( - setScreen(NEWSCASTER_SCREEN_MAIN)}> - Back - - } - > - There are no wanted issues currently outstanding. - - ); - } - - return ( - setScreen(NEWSCASTER_SCREEN_MAIN)}> - Back - - } - > - - - - {decodeHtmlEntities(wanted_issue.author)} - - - - {decodeHtmlEntities(wanted_issue.criminal)} - - - {decodeHtmlEntities(wanted_issue.desc)} - - - {(wanted_issue.img && ) || 'None'} - - - - - ); -}; - -const NewscasterViewSelected = (props) => { - const { act, data } = useBackend(); - - const { viewing_channel, securityCaster, company } = data; - - const { setScreen } = props; - - if (!viewing_channel) { - return ( - setScreen(NEWSCASTER_SCREEN_VIEWLIST)} - > - Back - - } - > - The channel you were looking for no longer exists. - - ); - } - - return ( - - {!!securityCaster && ( - - act('toggle_d_notice', { ref: viewing_channel.ref }) - } - > - Issue D-Notice - - )} - setScreen(NEWSCASTER_SCREEN_VIEWLIST)} - > - Back - - > - } - > - - - {(securityCaster && ( - - act('censor_channel_author', { ref: viewing_channel.ref }) - } - > - {decodeHtmlEntities(viewing_channel.author)} - - )) || {decodeHtmlEntities(viewing_channel.author)}} - - - {!!viewing_channel.censored && ( - - ATTENTION: This channel has been deemed as threatening to the welfare - of the station, and marked with a {company} D-Notice. No further feed - story additions are allowed while the D-Notice is in effect. - - )} - {(!!viewing_channel.messages.length && - viewing_channel.messages.map((message) => ( - - - {decodeHtmlEntities(message.body)} - {!!message.img && ( - - - {decodeHtmlEntities(message.caption) || null} - - )} - - [Story by {decodeHtmlEntities(message.author)} -{' '} - {message.timestamp}] - - {!!securityCaster && ( - <> - - act('censor_channel_story_body', { ref: message.ref }) - } - > - Censor Story - - - act('censor_channel_story_author', { ref: message.ref }) - } - > - Censor Author - - > - )} - - ))) || - (!viewing_channel.censored && ( - No feed messages found in channel. - ))} - - ); -}; - -/* Must be at the bottom because of how the const lifting rules work */ -let screenToTemplate = {}; -screenToTemplate[NEWSCASTER_SCREEN_MAIN] = NewscasterMainMenu; -screenToTemplate[NEWSCASTER_SCREEN_NEWCHANNEL] = NewscasterNewChannel; -screenToTemplate[NEWSCASTER_SCREEN_VIEWLIST] = NewscasterViewList; -screenToTemplate[NEWSCASTER_SCREEN_NEWSTORY] = NewscasterNewStory; -screenToTemplate[NEWSCASTER_SCREEN_PRINT] = NewscasterPrint; -screenToTemplate[NEWSCASTER_SCREEN_NEWWANTED] = NewscasterNewWanted; -screenToTemplate[NEWSCASTER_SCREEN_VIEWWANTED] = NewscasterViewWanted; -screenToTemplate[NEWSCASTER_SCREEN_SELECTEDCHANNEL] = NewscasterViewSelected; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterMainMenu.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterMainMenu.tsx new file mode 100644 index 00000000000..aa0e819deed --- /dev/null +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterMainMenu.tsx @@ -0,0 +1,75 @@ +import { useBackend } from '../../backend'; +import { Button, Section } from '../../components'; +import { + NEWSCASTER_SCREEN_NEWCHANNEL, + NEWSCASTER_SCREEN_NEWSTORY, + NEWSCASTER_SCREEN_NEWWANTED, + NEWSCASTER_SCREEN_PRINT, + NEWSCASTER_SCREEN_VIEWLIST, + NEWSCASTER_SCREEN_VIEWWANTED, +} from './constants'; +import { Data } from './types'; + +export const NewscasterMainMenu = (props: { setScreen: Function }) => { + const { data } = useBackend(); + + const { securityCaster, wanted_issue } = data; + + const { setScreen } = props; + + return ( + <> + + {wanted_issue && ( + setScreen(NEWSCASTER_SCREEN_VIEWWANTED)} + color="bad" + > + Read WANTED Issue + + )} + setScreen(NEWSCASTER_SCREEN_VIEWLIST)} + > + View Feed Channels + + setScreen(NEWSCASTER_SCREEN_NEWCHANNEL)} + > + Create Feed Channel + + setScreen(NEWSCASTER_SCREEN_NEWSTORY)} + > + Create Feed Message + + setScreen(NEWSCASTER_SCREEN_PRINT)} + > + Print Newspaper + + + {!!securityCaster && ( + + setScreen(NEWSCASTER_SCREEN_NEWWANTED)} + > + Manage "Wanted" Issue + + + )} + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewChannel.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewChannel.tsx new file mode 100644 index 00000000000..5e0230fe8e9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewChannel.tsx @@ -0,0 +1,63 @@ +import { decodeHtmlEntities } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Button, Input, LabeledList, Section } from '../../components'; +import { NEWSCASTER_SCREEN_MAIN } from './constants'; +import { Data } from './types'; + +export const NewscasterNewChannel = (props: { setScreen: Function }) => { + const { act, data } = useBackend(); + + const { channel_name, c_locked, user } = data; + + const { setScreen } = props; + + return ( + setScreen(NEWSCASTER_SCREEN_MAIN)}> + Back + + } + > + + + act('set_channel_name', { val: val })} + /> + + + {user} + + + act('set_channel_lock')} + > + {c_locked ? 'No' : 'Yes'} + + + + act('submit_new_channel')} + > + Submit Channel + + setScreen(NEWSCASTER_SCREEN_MAIN)} + > + Cancel + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewStory.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewStory.tsx new file mode 100644 index 00000000000..859e80a366f --- /dev/null +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewStory.tsx @@ -0,0 +1,91 @@ +import { useBackend } from '../../backend'; +import { Button, Flex, LabeledList, Section } from '../../components'; +import { NEWSCASTER_SCREEN_MAIN } from './constants'; +import { Data } from './types'; + +export const NewscasterNewStory = (props: { setScreen: Function }) => { + const { act, data } = useBackend(); + + const { channel_name, user, title, msg, photo_data } = data; + + const { setScreen } = props; + + return ( + setScreen(NEWSCASTER_SCREEN_MAIN)}> + Back + + } + > + + + act('set_channel_receiving')}> + {channel_name || 'Unset'} + + + + {user} + + + + + + {title || '(no title yet)'} + + + + act('set_new_title')} + icon="pen" + tooltip="Edit Title" + tooltipPosition="left" + /> + + + + + + + + {msg || '(no message yet)'} + + + + act('set_new_message')} + icon="pen" + tooltip="Edit Message" + tooltipPosition="left" + /> + + + + + act('set_attachment')}> + {photo_data ? 'Photo Attached' : 'No Photo'} + + + + act('submit_new_message')} + > + Submit Message + + setScreen(NEWSCASTER_SCREEN_MAIN)} + > + Cancel + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewWanted.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewWanted.tsx new file mode 100644 index 00000000000..e21b79913b8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewWanted.tsx @@ -0,0 +1,83 @@ +import { decodeHtmlEntities } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Button, Input, LabeledList, Section } from '../../components'; +import { NEWSCASTER_SCREEN_MAIN } from './constants'; +import { Data } from './types'; + +export const NewscasterNewWanted = (props: { setScreen: Function }) => { + const { act, data } = useBackend(); + + const { channel_name, msg, photo_data, user, wanted_issue } = data; + + const { setScreen } = props; + + return ( + setScreen(NEWSCASTER_SCREEN_MAIN)}> + Back + + } + > + + {!!wanted_issue && ( + + A wanted issue is already in circulation. You can edit or cancel it + below. + + )} + + act('set_channel_name', { val: val })} + /> + + + act('set_wanted_desc', { val: val })} + /> + + + act('set_attachment')}> + {photo_data ? 'Photo Attached' : 'No Photo'} + + + + {user} + + + act('submit_wanted')} + > + Submit Wanted Issue + + {!!wanted_issue && ( + act('cancel_wanted')} + > + Take Down Issue + + )} + setScreen(NEWSCASTER_SCREEN_MAIN)} + > + Cancel + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterPrint.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterPrint.tsx new file mode 100644 index 00000000000..2bfe10342e4 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterPrint.tsx @@ -0,0 +1,51 @@ +import { useBackend } from '../../backend'; +import { Box, Button, LabeledList, Section } from '../../components'; +import { NEWSCASTER_SCREEN_MAIN } from './constants'; +import { Data } from './types'; + +export const NewscasterPrint = (props: { setScreen: Function }) => { + const { act, data } = useBackend(); + + const { total_num, active_num, message_num, paper_remaining } = data; + + const { setScreen } = props; + + return ( + setScreen(NEWSCASTER_SCREEN_MAIN)}> + Back + + } + > + + Newscaster currently serves a total of {total_num} Feed channels,{' '} + {active_num} of which are active, and a total of {message_num} Feed + stories. + + + + {paper_remaining * 100} cm³ + + + act('print_paper')} + > + Print Paper + + setScreen(NEWSCASTER_SCREEN_MAIN)} + > + Cancel + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewList.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewList.tsx new file mode 100644 index 00000000000..a576202f19b --- /dev/null +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewList.tsx @@ -0,0 +1,43 @@ +import { decodeHtmlEntities } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Button, Section } from '../../components'; +import { + NEWSCASTER_SCREEN_MAIN, + NEWSCASTER_SCREEN_SELECTEDCHANNEL, +} from './constants'; +import { Data } from './types'; + +export const NewscasterViewList = (props: { setScreen: Function }) => { + const { act, data } = useBackend(); + + const { channels } = data; + + const { setScreen } = props; + + return ( + setScreen(NEWSCASTER_SCREEN_MAIN)}> + Back + + } + > + {channels.map((channel) => ( + { + act('show_channel', { show_channel: channel.ref }); + setScreen(NEWSCASTER_SCREEN_SELECTEDCHANNEL); + }} + > + {decodeHtmlEntities(channel.name)} + + ))} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewSelected.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewSelected.tsx new file mode 100644 index 00000000000..dcb999f8d72 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewSelected.tsx @@ -0,0 +1,130 @@ +import { decodeHtmlEntities } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Box, Button, Image, LabeledList, Section } from '../../components'; +import { NEWSCASTER_SCREEN_VIEWLIST } from './constants'; +import { Data } from './types'; + +export const NewscasterViewSelected = (props: { setScreen: Function }) => { + const { act, data } = useBackend(); + + const { viewing_channel, securityCaster, company } = data; + + const { setScreen } = props; + + if (!viewing_channel) { + return ( + setScreen(NEWSCASTER_SCREEN_VIEWLIST)} + > + Back + + } + > + The channel you were looking for no longer exists. + + ); + } + + return ( + + {!!securityCaster && ( + + act('toggle_d_notice', { ref: viewing_channel.ref }) + } + > + Issue D-Notice + + )} + setScreen(NEWSCASTER_SCREEN_VIEWLIST)} + > + Back + + > + } + > + + + {(securityCaster && ( + + act('censor_channel_author', { ref: viewing_channel.ref }) + } + > + {decodeHtmlEntities(viewing_channel.author)} + + )) || {decodeHtmlEntities(viewing_channel.author)}} + + + {!!viewing_channel.censored && ( + + ATTENTION: This channel has been deemed as threatening to the welfare + of the station, and marked with a {company} D-Notice. No further feed + story additions are allowed while the D-Notice is in effect. + + )} + {(!!viewing_channel.messages.length && + viewing_channel.messages.map((message) => ( + + - {decodeHtmlEntities(message.body)} + {!!message.img && ( + + + {decodeHtmlEntities(message.caption) || null} + + )} + + [Story by {decodeHtmlEntities(message.author)} -{' '} + {message.timestamp}] + + {!!securityCaster && ( + <> + + act('censor_channel_story_body', { ref: message.ref }) + } + > + Censor Story + + + act('censor_channel_story_author', { ref: message.ref }) + } + > + Censor Author + + > + )} + + ))) || + (!viewing_channel.censored && ( + No feed messages found in channel. + ))} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewWanted.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewWanted.tsx new file mode 100644 index 00000000000..73192f65328 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewWanted.tsx @@ -0,0 +1,59 @@ +import { decodeHtmlEntities } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Box, Button, Image, LabeledList, Section } from '../../components'; +import { NEWSCASTER_SCREEN_MAIN } from './constants'; +import { Data } from './types'; + +export const NewscasterViewWanted = (props: { setScreen: Function }) => { + const { data } = useBackend(); + + const { wanted_issue } = data; + + const { setScreen } = props; + + if (!wanted_issue) { + return ( + setScreen(NEWSCASTER_SCREEN_MAIN)}> + Back + + } + > + There are no wanted issues currently outstanding. + + ); + } + + return ( + setScreen(NEWSCASTER_SCREEN_MAIN)}> + Back + + } + > + + + + {decodeHtmlEntities(wanted_issue.author)} + + + + {decodeHtmlEntities(wanted_issue.criminal)} + + + {decodeHtmlEntities(wanted_issue.desc)} + + + {(wanted_issue.img && ) || 'None'} + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Newscaster/constants.ts b/tgui/packages/tgui/interfaces/Newscaster/constants.ts new file mode 100644 index 00000000000..e4419a58f59 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Newscaster/constants.ts @@ -0,0 +1,8 @@ +export const NEWSCASTER_SCREEN_MAIN = 'Main Menu'; +export const NEWSCASTER_SCREEN_NEWCHANNEL = 'New Channel'; +export const NEWSCASTER_SCREEN_VIEWLIST = 'View List'; +export const NEWSCASTER_SCREEN_NEWSTORY = 'New Story'; +export const NEWSCASTER_SCREEN_PRINT = 'Print'; +export const NEWSCASTER_SCREEN_NEWWANTED = 'New Wanted'; +export const NEWSCASTER_SCREEN_VIEWWANTED = 'View Wanted'; +export const NEWSCASTER_SCREEN_SELECTEDCHANNEL = 'View Selected Channel'; diff --git a/tgui/packages/tgui/interfaces/Newscaster/index.tsx b/tgui/packages/tgui/interfaces/Newscaster/index.tsx new file mode 100644 index 00000000000..da86f815165 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Newscaster/index.tsx @@ -0,0 +1,66 @@ +import { useSharedState } from '../../backend'; +import { Box } from '../../components'; +import { Window } from '../../layouts'; +import { TemporaryNotice } from '../common/TemporaryNotice'; +import { + NEWSCASTER_SCREEN_MAIN, + NEWSCASTER_SCREEN_NEWCHANNEL, + NEWSCASTER_SCREEN_NEWSTORY, + NEWSCASTER_SCREEN_NEWWANTED, + NEWSCASTER_SCREEN_PRINT, + NEWSCASTER_SCREEN_SELECTEDCHANNEL, + NEWSCASTER_SCREEN_VIEWLIST, + NEWSCASTER_SCREEN_VIEWWANTED, +} from './constants'; +import { NewscasterMainMenu } from './NewscasterMainMenu'; +import { NewscasterNewChannel } from './NewscasterNewChannel'; +import { NewscasterNewStory } from './NewscasterNewStory'; +import { NewscasterNewWanted } from './NewscasterNewWanted'; +import { NewscasterPrint } from './NewscasterPrint'; +import { NewscasterViewList } from './NewscasterViewList'; +import { NewscasterViewSelected } from './NewscasterViewSelected'; +import { NewscasterViewWanted } from './NewscasterViewWanted'; + +export const Newscaster = (props) => { + return ( + + + + + + + ); +}; + +const NewscasterContent = (props) => { + const [screen, setScreen] = useSharedState('screen', NEWSCASTER_SCREEN_MAIN); + + const screenToTemplate: React.JSX.Element[] = []; + + screenToTemplate[NEWSCASTER_SCREEN_MAIN] = ( + + ); + screenToTemplate[NEWSCASTER_SCREEN_NEWCHANNEL] = ( + + ); + screenToTemplate[NEWSCASTER_SCREEN_VIEWLIST] = ( + + ); + screenToTemplate[NEWSCASTER_SCREEN_NEWSTORY] = ( + + ); + screenToTemplate[NEWSCASTER_SCREEN_PRINT] = ( + + ); + screenToTemplate[NEWSCASTER_SCREEN_NEWWANTED] = ( + + ); + screenToTemplate[NEWSCASTER_SCREEN_VIEWWANTED] = ( + + ); + screenToTemplate[NEWSCASTER_SCREEN_SELECTEDCHANNEL] = ( + + ); + + return {screenToTemplate[screen]}; +}; diff --git a/tgui/packages/tgui/interfaces/Newscaster/types.ts b/tgui/packages/tgui/interfaces/Newscaster/types.ts new file mode 100644 index 00000000000..c1932c3006f --- /dev/null +++ b/tgui/packages/tgui/interfaces/Newscaster/types.ts @@ -0,0 +1,45 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + temp: { text: string; style: string } | null; + user: string; + unit_no: number; + wanted_issue: { + author: string; + criminal: string; + desc: string; + img: string | null; + }; + securityCaster: BooleanLike; + channels: { + admin: BooleanLike; + ref: string; + name: string; + censored: BooleanLike; + }[]; + channel_name: string; + c_locked: BooleanLike; + msg: string; + title: string; + photo_data: BooleanLike; + total_num: number; + active_num: number; + message_num: number; + paper_remaining: number; + viewing_channel: { + name: string; + author: string; + censored: BooleanLike; + messages: { + body: string; + img: string | null; + type: string; + caption: string | null; + author: string; + timestamp: string; + ref: string; + }[]; + ref: string; + }; + company: string; +}; diff --git a/tgui/packages/tgui/interfaces/NtosAccessDecrypter.tsx b/tgui/packages/tgui/interfaces/NtosAccessDecrypter.tsx index a6ccf8a55b3..18b37732d83 100644 --- a/tgui/packages/tgui/interfaces/NtosAccessDecrypter.tsx +++ b/tgui/packages/tgui/interfaces/NtosAccessDecrypter.tsx @@ -10,7 +10,7 @@ type Data = { running: BooleanLike; rate: number; factor: number; - regions: []; + regions: string[]; }; export const NtosAccessDecrypter = (props) => { diff --git a/tgui/packages/tgui/interfaces/NtosArcade.tsx b/tgui/packages/tgui/interfaces/NtosArcade.tsx index 99590e5ec2c..754fe475736 100644 --- a/tgui/packages/tgui/interfaces/NtosArcade.tsx +++ b/tgui/packages/tgui/interfaces/NtosArcade.tsx @@ -6,6 +6,7 @@ import { AnimatedNumber, Box, Button, + Image, LabeledList, ProgressBar, Section, @@ -101,7 +102,7 @@ export const NtosArcade = (props) => { - + diff --git a/tgui/packages/tgui/interfaces/NtosCameraConsole.tsx b/tgui/packages/tgui/interfaces/NtosCameraConsole.tsx index b5ce8e7c6e7..7be395bfc08 100644 --- a/tgui/packages/tgui/interfaces/NtosCameraConsole.tsx +++ b/tgui/packages/tgui/interfaces/NtosCameraConsole.tsx @@ -2,6 +2,7 @@ import { useBackend } from '../backend'; import { Button, ByondUi } from '../components'; import { NtosWindow } from '../layouts'; import { + camera, CameraConsoleContent, Data, prevNextCamera, @@ -11,7 +12,7 @@ import { export const NtosCameraConsole = (props) => { const { act, data } = useBackend(); const { mapRef, activeCamera, cameras } = data; - const selected_cameras = selectCameras(cameras); + const selected_cameras: camera[] = selectCameras(cameras); const [prevCameraName, nextCameraName] = prevNextCamera( selected_cameras, activeCamera, diff --git a/tgui/packages/tgui/interfaces/NtosConfiguration.jsx b/tgui/packages/tgui/interfaces/NtosConfiguration.tsx similarity index 80% rename from tgui/packages/tgui/interfaces/NtosConfiguration.jsx rename to tgui/packages/tgui/interfaces/NtosConfiguration.tsx index 590a6c6b272..bdf93c2840c 100644 --- a/tgui/packages/tgui/interfaces/NtosConfiguration.jsx +++ b/tgui/packages/tgui/interfaces/NtosConfiguration.tsx @@ -1,14 +1,38 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, LabeledList, ProgressBar, Section } from '../components'; import { NtosWindow } from '../layouts'; +type Data = { + PC_device_theme: string; + power_usage: number; + battery_exists: BooleanLike; + battery_rating: number | undefined; + battery_percent: number | undefined; + battery: battery | undefined; + hardware: + | { + name: string; + desc: string; + enabled: BooleanLike; + critical: BooleanLike; + powerusage: number; + }[] + | []; + disk_size: number; + disk_used: number; +}; + +type battery = { max: number; charge: number }; + export const NtosConfiguration = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { PC_device_theme, power_usage, battery_exists, - battery = {}, + battery = {} as battery, disk_size, disk_used, hardware = [], @@ -27,7 +51,7 @@ export const NtosConfiguration = (props) => { {battery_exists ? ( { {!component.critical && ( diff --git a/tgui/packages/tgui/interfaces/NtosCrewMonitor.tsx b/tgui/packages/tgui/interfaces/NtosCrewMonitor.tsx index a0d356c09ac..5be08337499 100644 --- a/tgui/packages/tgui/interfaces/NtosCrewMonitor.tsx +++ b/tgui/packages/tgui/interfaces/NtosCrewMonitor.tsx @@ -4,8 +4,8 @@ import { NtosWindow } from '../layouts'; import { CrewMonitorContent } from './CrewMonitor'; export const NtosCrewMonitor = () => { - const [tabIndex, setTabIndex] = useState(0); - const [zoom, setZoom] = useState(1); + const [tabIndex, setTabIndex] = useState(0); + const [zoom, setZoom] = useState(1); function handleTabIndex(value) { setTabIndex(value); diff --git a/tgui/packages/tgui/interfaces/NtosDigitalWarrant.jsx b/tgui/packages/tgui/interfaces/NtosDigitalWarrant.tsx similarity index 82% rename from tgui/packages/tgui/interfaces/NtosDigitalWarrant.jsx rename to tgui/packages/tgui/interfaces/NtosDigitalWarrant.tsx index 030f83056db..d418171a16a 100644 --- a/tgui/packages/tgui/interfaces/NtosDigitalWarrant.jsx +++ b/tgui/packages/tgui/interfaces/NtosDigitalWarrant.tsx @@ -1,15 +1,32 @@ import { filter } from 'common/collections'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { Button, LabeledList, Section, Table } from '../components'; import { NtosWindow } from '../layouts'; +type Data = { + warrantname: string | null; + warrantcharges: string | null; + warrantauth: BooleanLike; + type: string | null; + allwarrants: warrant[] | []; +}; + +type warrant = { + warrantname: string; + charges: string; + auth: BooleanLike; + id: number; + arrestsearch: string; +}; + export const NtosDigitalWarrant = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); - const { warrantname, warrantcharges, warrantauth, type, allwarrants } = data; + const { warrantauth } = data; - let body = ; + let body: React.JSX.Element = ; if (warrantauth) { body = ; @@ -23,19 +40,17 @@ export const NtosDigitalWarrant = (props) => { }; const AllWarrants = (props) => { - const { act, data } = useBackend(); - - const { allwarrants } = data; + const { act } = useBackend(); return ( act('addwarrant')}> Create New Warrant - + - + @@ -43,13 +58,15 @@ const AllWarrants = (props) => { }; const WarrantList = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { type } = props; - const { allwarrants } = data; + const { allwarrants = [] } = data; - const ourWarrants = filter((w) => w.arrestsearch === type)(allwarrants); + const ourWarrants = filter((w: warrant) => w.arrestsearch === type)( + allwarrants, + ); return ( @@ -84,7 +101,7 @@ const WarrantList = (props) => { }; const ActiveWarrant = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { warrantname, warrantcharges, warrantauth, type } = data; diff --git a/tgui/packages/tgui/interfaces/NtosEmailAdministration.jsx b/tgui/packages/tgui/interfaces/NtosEmailAdministration.tsx similarity index 74% rename from tgui/packages/tgui/interfaces/NtosEmailAdministration.jsx rename to tgui/packages/tgui/interfaces/NtosEmailAdministration.tsx index ef2cf328e5d..5ddecfdf278 100644 --- a/tgui/packages/tgui/interfaces/NtosEmailAdministration.jsx +++ b/tgui/packages/tgui/interfaces/NtosEmailAdministration.tsx @@ -1,17 +1,40 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, LabeledList, Section, Table } from '../components'; import { NtosWindow } from '../layouts'; import { NtosEmailClientViewMessage } from './NtosEmailClient'; +type Data = { + error: string; + cur_title: string | null; + cur_body: string | null; + cur_timestamp: string | null; + cur_source: string | null; + current_account: string | null; + cur_suspended: BooleanLike; + messages: message[] | null; + accounts: account[] | []; +}; + +type message = { + title: string; + source: string; + timestamp: string; + uid: number; +}; + +type account = { login: string; uid: number }; + export const NtosEmailAdministration = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); - const { error, cur_title, current_account } = data; + const { error, cur_title, current_account, accounts } = data; - let body = ; + let body: React.JSX.Element = ; if (error) { - body = ; + body = ; } else if (cur_title) { body = ; } else if (current_account) { @@ -25,9 +48,9 @@ export const NtosEmailAdministration = (props) => { ); }; -const MainMenu = (props) => { - const { act, data } = useBackend(); - const { accounts } = data; +const MainMenu = (props: { accounts: account[] }) => { + const { act } = useBackend(); + const { accounts } = props; return ( @@ -53,9 +76,9 @@ const MainMenu = (props) => { ); }; -const EmailError = (props) => { - const { act, data } = useBackend(); - const { error } = data; +const EmailError = (props: { error: string }) => { + const { act } = useBackend(); + const { error } = props; return ( { }; const ViewEmail = (props) => { - const { act, data } = useBackend(); return ( @@ -80,18 +102,8 @@ const ViewEmail = (props) => { }; const ViewAccount = (props) => { - const { act, data } = useBackend(); - const { - error, - msg_title, - msg_body, - msg_timestamp, - msg_source, - current_account, - cur_suspended, - messages, - accounts, - } = data; + const { act, data } = useBackend(); + const { current_account, cur_suspended, messages = [] } = data; return ( { - - {(messages.length && ( + + {(messages!.length && ( Source @@ -127,7 +139,7 @@ const ViewAccount = (props) => { Received at Actions - {messages.map((message) => ( + {messages!.map((message) => ( {message.source} {message.title} diff --git a/tgui/packages/tgui/interfaces/NtosEmailClient.jsx b/tgui/packages/tgui/interfaces/NtosEmailClient.tsx similarity index 79% rename from tgui/packages/tgui/interfaces/NtosEmailClient.jsx rename to tgui/packages/tgui/interfaces/NtosEmailClient.tsx index 6ca82c3caf6..14151088eb3 100644 --- a/tgui/packages/tgui/interfaces/NtosEmailClient.jsx +++ b/tgui/packages/tgui/interfaces/NtosEmailClient.tsx @@ -1,5 +1,6 @@ /* eslint react/no-danger: "off" */ import { toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { @@ -16,8 +17,54 @@ import { } from '../components'; import { NtosWindow } from '../layouts'; +type Data = { + PC_device_theme: string; + accounts: account[] | null; + addressbook: BooleanLike; + cur_attachment_filename: string | null; + cur_attachment_size: number | null; + cur_body: string | null; + cur_hasattachment: BooleanLike; + cur_source: string | null; + cur_timestamp: string | null; + cur_title: string | null; + cur_uid: number | null; + current_account: account | null; + down_filename: string | null; + down_progress: number | null; + down_size: number | null; + down_speed: number | null; + downloading: BooleanLike; + error: string | null; + folder: string | null; + label_deleted: string | null; + label_inbox: string | null; + label_spam: string | null; + messagecount: number | null; + messages: message[] | null; + msg_attachment_filename: string | null; + msg_attachment_size: number | null; + msg_body: string | null; + msg_hasattachment: BooleanLike; + msg_recipient: string | null; + msg_title: string | null; + new_message: BooleanLike; + stored_login: string | null; + stored_password: string | null; +}; + +type message = { + title: string; + body: string; + source: string; + timestamp: string; + uid: number; +}; + +type account = { login: string }; + export const NtosEmailClient = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { PC_device_theme, error, downloading, current_account } = data; @@ -39,7 +86,7 @@ export const NtosEmailClient = (props) => { }; const NtosEmailClientDownloading = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { down_filename, down_progress, down_size, down_speed } = data; @@ -50,15 +97,19 @@ const NtosEmailClientDownloading = (props) => { {down_filename} ({down_size} GQ) - GQ/s + GQ/s - + {down_progress + '/' + down_size + ' (' + - toFixed((down_progress / down_size) * 100, 1) + + toFixed((down_progress! / down_size!) * 100, 1) + '%)'} @@ -68,14 +119,15 @@ const NtosEmailClientDownloading = (props) => { }; const NtosEmailClientContent = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); - const { current_account, addressbook, new_message, cur_title } = data; + const { current_account, addressbook, new_message, cur_title, accounts } = + data; let content = ; if (addressbook) { - content = ; + content = ; } else if (new_message) { content = ; } else if (cur_title) { @@ -114,12 +166,12 @@ const NtosEmailClientContent = (props) => { }; const NtosEmailClientInbox = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); - const { current_account, folder, messagecount, messages } = data; + const { folder, messagecount, messages } = data; return ( - + { Received At Actions - {messages.map((msg) => ( + {messages!.map((msg) => ( {msg.source} {msg.title} @@ -181,8 +233,10 @@ const NtosEmailClientInbox = (props) => { ); }; -export const NtosEmailClientViewMessage = (props) => { - const { act, data } = useBackend(); +export const NtosEmailClientViewMessage = (props: { + administrator?: BooleanLike; +}) => { + const { act, data } = useBackend(); // This is used to let NtosEmailAdministration use the same code for spying on emails // Administrators don't have access to attachments or the message UID, so we need to avoid @@ -254,13 +308,13 @@ export const NtosEmailClientViewMessage = (props) => { {cur_attachment_filename} ({cur_attachment_size}GQ) )) || - null} + ''} {/* This dangerouslySetInnerHTML is only ever passed data that has passed through pencode2html * It should be safe enough to support pencode in this way. */} - + @@ -268,15 +322,14 @@ export const NtosEmailClientViewMessage = (props) => { ); }; -const NtosEmailClientAddressBook = (props) => { - const { act, data } = useBackend(); +const NtosEmailClientAddressBook = (props: { accounts: account[] }) => { + const { act } = useBackend(); - const { accounts } = data; + const { accounts } = props; return ( { }; const NtosEmailClientNewMessage = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { - current_account, msg_title, msg_recipient, msg_body, @@ -314,7 +366,6 @@ const NtosEmailClientNewMessage = (props) => { return ( act('send')}> @@ -329,7 +380,7 @@ const NtosEmailClientNewMessage = (props) => { act('edit_title', { val: val })} + onInput={(e, val: string) => act('edit_title', { val: val })} /> @@ -338,7 +389,9 @@ const NtosEmailClientNewMessage = (props) => { act('edit_recipient', { val: val })} + onInput={(e, val: string) => + act('edit_recipient', { val: val }) + } /> @@ -380,7 +433,7 @@ const NtosEmailClientNewMessage = (props) => { - + @@ -399,7 +452,7 @@ const NtosEmailClientNewMessage = (props) => { ); }; -const NtosEmailClientError = (props) => { +const NtosEmailClientError = (props: { error: string }) => { const { act } = useBackend(); const { error } = props; return ( @@ -417,7 +470,7 @@ const NtosEmailClientError = (props) => { }; const NtosEmailClientLogin = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { stored_login, stored_password } = data; @@ -428,14 +481,14 @@ const NtosEmailClientLogin = (props) => { act('edit_login', { val: val })} + onInput={(e, val: string) => act('edit_login', { val: val })} /> act('edit_password', { val: val })} + onInput={(e, val: string) => act('edit_password', { val: val })} /> diff --git a/tgui/packages/tgui/interfaces/NtosFileManager.jsx b/tgui/packages/tgui/interfaces/NtosFileManager.tsx similarity index 76% rename from tgui/packages/tgui/interfaces/NtosFileManager.jsx rename to tgui/packages/tgui/interfaces/NtosFileManager.tsx index 32314b42f3f..176cda35545 100644 --- a/tgui/packages/tgui/interfaces/NtosFileManager.jsx +++ b/tgui/packages/tgui/interfaces/NtosFileManager.tsx @@ -1,11 +1,31 @@ /* eslint react/no-danger: "off" */ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Button, Flex, Section, Table } from '../components'; import { NtosWindow } from '../layouts'; +type Data = { + PC_device_theme: string; + error: string | null; + filedata: string | null; + filename: string | null; + files: file[]; + usbconnected: BooleanLike; + usbfiles: file[]; +}; + +export type file = { + name: string; + type: string; + uid: number; + size: number; + undeletable: BooleanLike; +}; + export const NtosFileManager = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { PC_device_theme, usbconnected, @@ -46,16 +66,16 @@ export const NtosFileManager = (props) => { act('PRG_copytousb', { uid: file })} - onDelete={(file) => act('PRG_deletefile', { uid: file })} - onOpen={(file) => act('PRG_openfile', { uid: file })} - onRename={(file, newName) => + onUpload={(file: file) => act('PRG_copytousb', { uid: file })} + onDelete={(file: file) => act('PRG_deletefile', { uid: file })} + onOpen={(file: file) => act('PRG_openfile', { uid: file })} + onRename={(file: file, newName: string) => act('PRG_rename', { uid: file, new_name: newName, }) } - onDuplicate={(file) => act('PRG_clone', { uid: file })} + onDuplicate={(file: file) => act('PRG_clone', { uid: file })} /> {(usbconnected && ( @@ -64,16 +84,20 @@ export const NtosFileManager = (props) => { usbmode files={usbfiles} usbconnected={usbconnected} - onUpload={(file) => act('PRG_copyfromusb', { uid: file })} - onDelete={(file) => act('PRG_deletefile', { uid: file })} - onOpen={(file) => act('PRG_openfile', { uid: file })} - onRename={(file, newName) => + onUpload={(file: file) => + act('PRG_copyfromusb', { uid: file }) + } + onDelete={(file: file) => + act('PRG_deletefile', { uid: file }) + } + onOpen={(file: file) => act('PRG_openfile', { uid: file })} + onRename={(file: file, newName: string) => act('PRG_rename', { uid: file, new_name: newName, }) } - onDuplicate={(file) => act('PRG_clone', { uid: file })} + onDuplicate={(file: file) => act('PRG_clone', { uid: file })} /> )) || @@ -107,7 +131,16 @@ export const NtosFileManager = (props) => { ); }; -const FileTable = (props) => { +const FileTable = (props: { + files: file[]; + usbconnected: BooleanLike; + usbmode?: boolean; + onUpload: Function; + onDelete: Function; + onRename: Function; + onOpen: Function; + onDuplicate: Function; +}) => { const { files = [], usbconnected, @@ -116,6 +149,7 @@ const FileTable = (props) => { onDelete, onRename, onOpen, + onDuplicate, } = props; return ( diff --git a/tgui/packages/tgui/interfaces/NtosMain.jsx b/tgui/packages/tgui/interfaces/NtosMain.tsx similarity index 90% rename from tgui/packages/tgui/interfaces/NtosMain.jsx rename to tgui/packages/tgui/interfaces/NtosMain.tsx index 4e8729d8ed0..a9e5d3a4430 100644 --- a/tgui/packages/tgui/interfaces/NtosMain.jsx +++ b/tgui/packages/tgui/interfaces/NtosMain.tsx @@ -1,3 +1,5 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Button, ColorBox, Section, Table } from '../components'; import { NtosWindow } from '../layouts'; @@ -20,8 +22,26 @@ const PROGRAM_ICONS = { shipping: 'tags', }; +type Data = { + device_theme: string; + login: user; + removable_media: string[]; + programs: { + name: string; + desc: string; + icon: string; + running: BooleanLike; + autorun: BooleanLike; + }[]; + has_light: BooleanLike; + light_on: BooleanLike; + comp_light_color: BooleanLike; +}; + +type user = { IDName: string | undefined; IDJob: string | undefined }; + export const NtosMain = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { device_theme, programs = [], @@ -29,7 +49,7 @@ export const NtosMain = (props) => { light_on, comp_light_color, removable_media = [], - login = [], + login = {} as user, } = data; return ( { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { can_admin, adminmode, @@ -15,8 +33,8 @@ export const NtosNetChat = (props) => { clients = [], messages = [], } = data; - const in_channel = active_channel !== null; - const authorized = authed || adminmode; + const in_channel: boolean = active_channel !== null; + const authorized: BooleanLike = authed || adminmode; return ( diff --git a/tgui/packages/tgui/interfaces/NtosNetDos.jsx b/tgui/packages/tgui/interfaces/NtosNetDos.tsx similarity index 87% rename from tgui/packages/tgui/interfaces/NtosNetDos.jsx rename to tgui/packages/tgui/interfaces/NtosNetDos.tsx index d6c94e07d77..2b0fbff5e5a 100644 --- a/tgui/packages/tgui/interfaces/NtosNetDos.jsx +++ b/tgui/packages/tgui/interfaces/NtosNetDos.tsx @@ -1,7 +1,19 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, LabeledList, NoticeBox, Section } from '../components'; import { NtosWindow } from '../layouts'; +type Data = { + error: string; + target: BooleanLike; + speed: number; + overload: number; + capacity: number; + relays: { id: number }[]; + focus: number | null; +}; + export const NtosNetDos = () => { return ( @@ -13,7 +25,7 @@ export const NtosNetDos = () => { }; export const NtosNetDosContent = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { relays = [], focus, target, speed, overload, capacity, error } = data; @@ -28,7 +40,7 @@ export const NtosNetDosContent = (props) => { ); } - const generate10String = (length) => { + const generate10String = (length: number): string => { let outString = ''; const factor = overload / capacity; while (outString.length < length) { diff --git a/tgui/packages/tgui/interfaces/NtosNetDownloader.jsx b/tgui/packages/tgui/interfaces/NtosNetDownloader.tsx similarity index 81% rename from tgui/packages/tgui/interfaces/NtosNetDownloader.jsx rename to tgui/packages/tgui/interfaces/NtosNetDownloader.tsx index 632029c0b81..d819153d05a 100644 --- a/tgui/packages/tgui/interfaces/NtosNetDownloader.jsx +++ b/tgui/packages/tgui/interfaces/NtosNetDownloader.tsx @@ -1,4 +1,5 @@ import { toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { @@ -13,8 +14,34 @@ import { } from '../components'; import { NtosWindow } from '../layouts'; +type Data = { + PC_device_theme: string; + downloading: BooleanLike; + error: string | BooleanLike; + downloadname: string | undefined; + downloaddesc: string | undefined; + downloadsize: number | undefined; + downloadspeed: number | undefined; + downloadcompletion: number | undefined; + disk_size: number; + disk_used: number; + hackedavailable: BooleanLike; + hacked_programs: program[]; + downloadable_programs: program[]; + downloads_queue: string[]; +}; + +type program = { + filename: string; + filedesc: string; + fileinfo: string; + compatibility: string; + size: number; + icon: string; +}; + export const NtosNetDownloader = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { PC_device_theme, disk_size, @@ -63,14 +90,13 @@ export const NtosNetDownloader = (props) => { ); }; -const Program = (props) => { +const Program = (props: { program: program }) => { const { program } = props; - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { disk_size, disk_used, downloadcompletion, - downloading, downloadname, downloadsize, downloadspeed, @@ -92,9 +118,9 @@ const Program = (props) => { color="green" minValue={0} maxValue={downloadsize} - value={downloadcompletion} + value={downloadcompletion!} > - {toFixed((downloadcompletion / downloadsize) * 100, 1)}% + {toFixed((downloadcompletion! / downloadsize!) * 100, 1)}% {'(' + downloadspeed + 'GQ/s)'} )) || diff --git a/tgui/packages/tgui/interfaces/NtosNetMonitor.jsx b/tgui/packages/tgui/interfaces/NtosNetMonitor.tsx similarity index 91% rename from tgui/packages/tgui/interfaces/NtosNetMonitor.jsx rename to tgui/packages/tgui/interfaces/NtosNetMonitor.tsx index 31aeaee48ad..b8bed80289a 100644 --- a/tgui/packages/tgui/interfaces/NtosNetMonitor.jsx +++ b/tgui/packages/tgui/interfaces/NtosNetMonitor.tsx @@ -1,3 +1,5 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, @@ -9,8 +11,24 @@ import { } from '../components'; import { NtosWindow } from '../layouts'; +type Data = { + ntnetstatus: BooleanLike; + ntnetrelays: number; + idsstatus: BooleanLike; + idsalarm: BooleanLike; + config_softwaredownload: BooleanLike; + config_peertopeer: BooleanLike; + config_communication: BooleanLike; + config_systemcontrol: BooleanLike; + ntnetlogs: { entry: string }[] | []; + minlogs: number; + maxlogs: number; + banned_nids: number[]; + ntnetmaxlogs: number; +}; + export const NtosNetMonitor = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { ntnetrelays, ntnetstatus, @@ -111,7 +129,7 @@ export const NtosNetMonitor = (props) => { {!!idsalarm && ( <> NETWORK INCURSION DETECTED - + Abnormal activity has been detected in the network. Check system logs for more information @@ -162,7 +180,7 @@ export const NtosNetMonitor = (props) => { minValue={minlogs} maxValue={maxlogs} width="39px" - onChange={(e, value) => + onChange={(e, value: number) => act('updatemaxlogs', { new_number: value, }) @@ -173,7 +191,6 @@ export const NtosNetMonitor = (props) => { act('purgelogs')}> Clear Logs diff --git a/tgui/packages/tgui/interfaces/NtosNetTransfer.jsx b/tgui/packages/tgui/interfaces/NtosNetTransfer.tsx similarity index 78% rename from tgui/packages/tgui/interfaces/NtosNetTransfer.jsx rename to tgui/packages/tgui/interfaces/NtosNetTransfer.tsx index 154e380b79e..9bb6ba01fad 100644 --- a/tgui/packages/tgui/interfaces/NtosNetTransfer.jsx +++ b/tgui/packages/tgui/interfaces/NtosNetTransfer.tsx @@ -1,3 +1,5 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, @@ -9,8 +11,33 @@ import { } from '../components'; import { NtosWindow } from '../layouts'; +type Data = { + error: string; + downloading: BooleanLike; + download_size: number | undefined; + download_progress: number | undefined; + download_netspeed: number | undefined; + download_name: string | undefined; + uploading: BooleanLike; + upload_uid: number | undefined; + upload_clients: number | undefined; + upload_haspassword: BooleanLike; + upload_filename: string | undefined; + upload_filelist: uploadFile[] | []; + servers: server[] | []; +}; + +type server = { + uid: number; + filename: string; + size: number; + haspassword: BooleanLike; +}; + +type uploadFile = { uid: number; filename: string; size: number }; + export const NtosNetTransfer = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { error, downloading, uploading, upload_filelist } = data; @@ -34,7 +61,7 @@ export const NtosNetTransfer = (props) => { }; const P2PError = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { error } = data; return ( { }; const P2PDownload = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { download_name, download_progress, download_size, download_netspeed } = data; return ( @@ -61,7 +88,7 @@ const P2PDownload = (props) => { {download_name} - + {download_progress} / {download_size} GQ @@ -79,7 +106,7 @@ const P2PDownload = (props) => { }; const P2PUpload = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { upload_clients, upload_filename, upload_haspassword } = data; return ( @@ -107,7 +134,7 @@ const P2PUpload = (props) => { }; const P2PUploadServer = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { upload_filelist } = data; return ( { act('PRG_setpassword')}> Set Password - - {upload_filelist.map((file) => ( + + {upload_filelist.map((file: uploadFile) => ( { }; const P2PAvailable = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { servers } = data; return ( { > {(servers.length && ( - {servers.map((server) => ( + {servers.map((server: server) => ( {!!server.haspassword && } {server.filename} ({server.size}GQ) diff --git a/tgui/packages/tgui/interfaces/NtosNewsBrowser.jsx b/tgui/packages/tgui/interfaces/NtosNewsBrowser.tsx similarity index 83% rename from tgui/packages/tgui/interfaces/NtosNewsBrowser.jsx rename to tgui/packages/tgui/interfaces/NtosNewsBrowser.tsx index 5bf28f45f2f..7591b6cd5e3 100644 --- a/tgui/packages/tgui/interfaces/NtosNewsBrowser.jsx +++ b/tgui/packages/tgui/interfaces/NtosNewsBrowser.tsx @@ -1,8 +1,11 @@ /* eslint react/no-danger: "off" */ +import { BooleanLike } from 'common/react'; + import { resolveAsset } from '../assets'; import { useBackend } from '../backend'; import { Button, + Image, LabeledList, NoticeBox, ProgressBar, @@ -10,8 +13,25 @@ import { } from '../components'; import { NtosWindow } from '../layouts'; +type Data = { + message: string; + showing_archived: BooleanLike; + download: { + download_progress: number; + download_maxprogress: number; + download_rate: number; + } | null; + article: { title: string; cover: string; content: string } | null; + all_articles: { + name: string; + size: number; + uid: number; + archived: BooleanLike; + }[]; +}; + export const NtosNewsBrowser = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { article, download, message } = data; @@ -39,7 +59,7 @@ export const NtosNewsBrowser = (props) => { }; const SelectedArticle = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { article } = data; @@ -63,7 +83,7 @@ const SelectedArticle = (props) => { > } > - {!!cover && } + {!!cover && } {/* News articles are written in premade .html files and cannot be edited by players, so it should be * safe enough to use dangerouslySetInnerHTML here. */} @@ -73,7 +93,7 @@ const SelectedArticle = (props) => { }; const ViewArticles = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { showing_archived, all_articles } = data; @@ -115,10 +135,10 @@ const ViewArticles = (props) => { }; const ArticleDownloading = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { download_progress, download_maxprogress, download_rate } = - data.download; + data.download!; return ( diff --git a/tgui/packages/tgui/interfaces/NtosPowerMonitor.tsx b/tgui/packages/tgui/interfaces/NtosPowerMonitor.tsx index 39b36f03b72..de7274cb9cd 100644 --- a/tgui/packages/tgui/interfaces/NtosPowerMonitor.tsx +++ b/tgui/packages/tgui/interfaces/NtosPowerMonitor.tsx @@ -1,5 +1,5 @@ import { NtosWindow } from '../layouts'; -import { PowerMonitorContent } from './PowerMonitor'; +import { PowerMonitorContent } from './PowerMonitor/PowerMonitorContent'; export const NtosPowerMonitor = () => { return ( diff --git a/tgui/packages/tgui/interfaces/NtosRCON.tsx b/tgui/packages/tgui/interfaces/NtosRCON.tsx index d0728330e7b..476680892ce 100644 --- a/tgui/packages/tgui/interfaces/NtosRCON.tsx +++ b/tgui/packages/tgui/interfaces/NtosRCON.tsx @@ -1,5 +1,5 @@ import { NtosWindow } from '../layouts'; -import { RCONContent } from './RCON'; +import { RCONContent } from './RCON/RCONContent'; export const NtosRCON = () => { return ( diff --git a/tgui/packages/tgui/interfaces/NtosUAV.jsx b/tgui/packages/tgui/interfaces/NtosUAV.tsx similarity index 90% rename from tgui/packages/tgui/interfaces/NtosUAV.jsx rename to tgui/packages/tgui/interfaces/NtosUAV.tsx index 04c234923b2..c1036bda86d 100644 --- a/tgui/packages/tgui/interfaces/NtosUAV.jsx +++ b/tgui/packages/tgui/interfaces/NtosUAV.tsx @@ -1,9 +1,18 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, Flex, LabeledList, Section } from '../components'; import { NtosWindow } from '../layouts'; +type Data = { + current_uav: { status: string; power: BooleanLike } | null; + signal_strength: string; + in_use: number; + paired_uavs: { name: string; uavref: string }[]; +}; + export const NtosUAV = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { current_uav, signal_strength, in_use, paired_uavs } = data; diff --git a/tgui/packages/tgui/interfaces/NtosWordProcessor.jsx b/tgui/packages/tgui/interfaces/NtosWordProcessor.tsx similarity index 87% rename from tgui/packages/tgui/interfaces/NtosWordProcessor.jsx rename to tgui/packages/tgui/interfaces/NtosWordProcessor.tsx index 2914c2078df..d7c105da78e 100644 --- a/tgui/packages/tgui/interfaces/NtosWordProcessor.jsx +++ b/tgui/packages/tgui/interfaces/NtosWordProcessor.tsx @@ -1,21 +1,26 @@ /* eslint react/no-danger: "off" */ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, Section, Table } from '../components'; import { NtosWindow } from '../layouts'; +import { file } from './NtosFileManager'; + +type Data = { + PC_device_theme: string; + error: string | null; + browsing: BooleanLike; + files: file[]; + usbconnected: BooleanLike; + usbfiles: file[]; + filedata: string | null; + filename: string | null; +}; export const NtosWordProcessor = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); - const { - PC_device_theme, - error, - browsing, - files, - usbconnected, - usbfiles, - filename, - filedata, - } = data; + const { PC_device_theme, error, browsing, files, filename, filedata } = data; return ( @@ -43,7 +48,7 @@ export const NtosWordProcessor = (props) => { } > - + Name @@ -94,7 +99,7 @@ export const NtosWordProcessor = (props) => { * It should be safe enough to support pencode in this way. */} - + )} diff --git a/tgui/packages/tgui/interfaces/OperatingComputer.jsx b/tgui/packages/tgui/interfaces/OperatingComputer.jsx deleted file mode 100644 index 2271d65f905..00000000000 --- a/tgui/packages/tgui/interfaces/OperatingComputer.jsx +++ /dev/null @@ -1,265 +0,0 @@ -import { toFixed } from 'common/math'; - -import { useBackend } from '../backend'; -import { - Box, - Button, - Flex, - Icon, - Knob, - LabeledList, - ProgressBar, - Section, - Tabs, -} from '../components'; -import { Window } from '../layouts'; - -const stats = [ - ['good', 'Conscious'], - ['average', 'Unconscious'], - ['bad', 'DEAD'], -]; - -const damages = [ - ['Resp.', 'oxyLoss'], - ['Toxin', 'toxLoss'], - ['Brute', 'bruteLoss'], - ['Burn', 'fireLoss'], -]; - -const damageRange = { - average: [0.25, 0.5], - bad: [0.5, Infinity], -}; - -const tempColors = [ - 'bad', - 'average', - 'average', - 'good', - 'average', - 'average', - 'bad', -]; - -export const OperatingComputer = (props) => { - const { act, data } = useBackend(); - const { hasOccupant, choice } = data; - let body; - if (!choice) { - body = hasOccupant ? ( - - ) : ( - - ); - } else { - body = ; - } - return ( - - - - act('choiceOff')} - > - Patient - - act('choiceOn')} - > - Options - - - {body} - - - ); -}; - -const OperatingComputerPatient = (props) => { - const { data } = useBackend(); - const { occupant } = data; - return ( - <> - - - {occupant.name} - - {stats[occupant.stat][1]} - - - - - {damages.map((d, i) => ( - - - {toFixed(occupant[d[1]])} - - - ))} - - - {toFixed(occupant.btCelsius)}°C, {toFixed(occupant.btFaren)} - °F - - - {!!occupant.hasBlood && ( - <> - - - {occupant.bloodPercent}%, {occupant.bloodLevel}cl - - - - {occupant.pulse} BPM - - > - )} - - - - {occupant.surgery && occupant.surgery.length ? ( - - {occupant.surgery.map((limb) => ( - - - - {limb.currentStage} - - - {limb.nextSteps.map((step) => ( - {step} - ))} - - - - ))} - - ) : ( - No procedure ongoing. - )} - - > - ); -}; - -const OperatingComputerUnoccupied = () => { - return ( - - - - - No patient detected. - - - ); -}; - -const OperatingComputerOptions = (props) => { - const { act, data } = useBackend(); - const { verbose, health, healthAlarm, oxy, oxyAlarm, crit } = data; - return ( - - - act(verbose ? 'verboseOff' : 'verboseOn')} - > - {verbose ? 'On' : 'Off'} - - - - act(health ? 'healthOff' : 'healthOn')} - > - {health ? 'On' : 'Off'} - - - - val + '%'} - onChange={(e, val) => - act('health_adj', { - new: val, - }) - } - /> - - - act(oxy ? 'oxyOff' : 'oxyOn')} - > - {oxy ? 'On' : 'Off'} - - - - - act('oxy_adj', { - new: val, - }) - } - /> - - - act(crit ? 'critOff' : 'critOn')} - > - {crit ? 'On' : 'Off'} - - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/OperatingComputer/OperatingComputerOptions.tsx b/tgui/packages/tgui/interfaces/OperatingComputer/OperatingComputerOptions.tsx new file mode 100644 index 00000000000..18e4c52161c --- /dev/null +++ b/tgui/packages/tgui/interfaces/OperatingComputer/OperatingComputerOptions.tsx @@ -0,0 +1,79 @@ +import { useBackend } from '../../backend'; +import { Button, Knob, LabeledList } from '../../components'; +import { Data } from './types'; + +export const OperatingComputerOptions = (props) => { + const { act, data } = useBackend(); + const { verbose, health, healthAlarm, oxy, oxyAlarm, crit } = data; + return ( + + + act(verbose ? 'verboseOff' : 'verboseOn')} + > + {verbose ? 'On' : 'Off'} + + + + act(health ? 'healthOff' : 'healthOn')} + > + {health ? 'On' : 'Off'} + + + + val + '%'} + onChange={(e, val: number) => + act('health_adj', { + new: val, + }) + } + /> + + + act(oxy ? 'oxyOff' : 'oxyOn')} + > + {oxy ? 'On' : 'Off'} + + + + + act('oxy_adj', { + new: val, + }) + } + /> + + + act(crit ? 'critOff' : 'critOn')} + > + {crit ? 'On' : 'Off'} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/OperatingComputer/OperatingComputerPatient.tsx b/tgui/packages/tgui/interfaces/OperatingComputer/OperatingComputerPatient.tsx new file mode 100644 index 00000000000..3b1ec80fa4e --- /dev/null +++ b/tgui/packages/tgui/interfaces/OperatingComputer/OperatingComputerPatient.tsx @@ -0,0 +1,100 @@ +import { toFixed } from 'common/math'; + +import { Box, LabeledList, ProgressBar, Section } from '../../components'; +import { damageRange, damages, stats, tempColors } from './constants'; +import { occupant } from './types'; + +export const OperatingComputerPatient = (props: { occupant: occupant }) => { + const { occupant } = props; + return ( + <> + + + {occupant.name} + + {stats[occupant.stat][1]} + + + + + {damages.map((d, i) => ( + + + {toFixed(occupant[d[1]])} + + + ))} + + + {toFixed(occupant.btCelsius)}°C, {toFixed(occupant.btFaren)} + °F + + + {!!occupant.hasBlood && ( + <> + + + {occupant.bloodPercent}%, {occupant.bloodLevel}cl + + + + {occupant.pulse} BPM + + > + )} + + + + {occupant.surgery && occupant.surgery.length ? ( + + {occupant.surgery.map((limb) => ( + + + + {limb.currentStage} + + + {limb.nextSteps.map((step) => ( + {step} + ))} + + + + ))} + + ) : ( + No procedure ongoing. + )} + + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/OperatingComputer/OperatingComputerUnoccupied.tsx b/tgui/packages/tgui/interfaces/OperatingComputer/OperatingComputerUnoccupied.tsx new file mode 100644 index 00000000000..0c386f28fd8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/OperatingComputer/OperatingComputerUnoccupied.tsx @@ -0,0 +1,13 @@ +import { Flex, Icon } from '../../components'; + +export const OperatingComputerUnoccupied = (props) => { + return ( + + + + + No patient detected. + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/OperatingComputer/constants.ts b/tgui/packages/tgui/interfaces/OperatingComputer/constants.ts new file mode 100644 index 00000000000..621033849ca --- /dev/null +++ b/tgui/packages/tgui/interfaces/OperatingComputer/constants.ts @@ -0,0 +1,27 @@ +export const stats: string[][] = [ + ['good', 'Conscious'], + ['average', 'Unconscious'], + ['bad', 'DEAD'], +]; + +export const damages: string[][] = [ + ['Resp.', 'oxyLoss'], + ['Toxin', 'toxLoss'], + ['Brute', 'bruteLoss'], + ['Burn', 'fireLoss'], +]; + +export const damageRange: Record = { + average: [0.25, 0.5], + bad: [0.5, Infinity], +}; + +export const tempColors: string[] = [ + 'bad', + 'average', + 'average', + 'good', + 'average', + 'average', + 'bad', +]; diff --git a/tgui/packages/tgui/interfaces/OperatingComputer/index.tsx b/tgui/packages/tgui/interfaces/OperatingComputer/index.tsx new file mode 100644 index 00000000000..cf293d98786 --- /dev/null +++ b/tgui/packages/tgui/interfaces/OperatingComputer/index.tsx @@ -0,0 +1,45 @@ +import { useBackend } from '../../backend'; +import { Section, Tabs } from '../../components'; +import { Window } from '../../layouts'; +import { OperatingComputerOptions } from './OperatingComputerOptions'; +import { OperatingComputerPatient } from './OperatingComputerPatient'; +import { OperatingComputerUnoccupied } from './OperatingComputerUnoccupied'; +import { Data } from './types'; + +export const OperatingComputer = (props) => { + const { act, data } = useBackend(); + const { hasOccupant, choice, occupant } = data; + let body; + if (!choice) { + body = hasOccupant ? ( + + ) : ( + + ); + } else { + body = ; + } + return ( + + + + act('choiceOff')} + > + Patient + + act('choiceOn')} + > + Options + + + {body} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/OperatingComputer/types.ts b/tgui/packages/tgui/interfaces/OperatingComputer/types.ts new file mode 100644 index 00000000000..677edf0e88e --- /dev/null +++ b/tgui/packages/tgui/interfaces/OperatingComputer/types.ts @@ -0,0 +1,38 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + hasOccupant: BooleanLike; + occupant: occupant; + verbose: BooleanLike; + oxyAlarm: number; + choice: BooleanLike; + health: BooleanLike; + crit: BooleanLike; + healthAlarm: BooleanLike; + oxy: BooleanLike; +}; + +export type occupant = { + name: string; + stat: number; + health: number; + maxHealth: number; + minHealth: number; + bruteLoss: number; + oxyLoss: number; + toxLoss: number; + fireLoss: number; + paralysis: number; + hasBlood: BooleanLike; + bodyTemperature: number; + maxTemp: number; + temperatureSuitability: number; + btCelsius: number; + btFaren: number; + pulse: number | undefined; + bloodLevel: number | undefined; + bloodMax: number | undefined; + bloodPercent: number | undefined; + bloodType: string | undefined; + surgery: { name: string; currentStage: string; nextSteps: string[] }[] | null; +}; diff --git a/tgui/packages/tgui/interfaces/OvermapDisperser.jsx b/tgui/packages/tgui/interfaces/OvermapDisperser.tsx similarity index 89% rename from tgui/packages/tgui/interfaces/OvermapDisperser.jsx rename to tgui/packages/tgui/interfaces/OvermapDisperser.tsx index 640b15e4c87..7a2ec522edf 100644 --- a/tgui/packages/tgui/interfaces/OvermapDisperser.jsx +++ b/tgui/packages/tgui/interfaces/OvermapDisperser.tsx @@ -1,3 +1,5 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { AnimatedNumber, @@ -10,6 +12,19 @@ import { import { Window } from '../layouts'; import { OvermapPanControls } from './common/Overmap'; +type Data = { + faillink: BooleanLike; + calibration: number[] | null; + overmapdir: number | null; + cal_accuracy: number; + strength: number; + range: number; + next_shot: number; + nopower: BooleanLike; + skill: BooleanLike; + chargeload: string | null; +}; + export const OvermapDisperser = (props) => { return ( @@ -21,7 +36,7 @@ export const OvermapDisperser = (props) => { }; const OvermapDisperserContent = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { faillink, calibration, @@ -31,7 +46,6 @@ const OvermapDisperserContent = (props) => { range, next_shot, nopower, - skill, chargeload, } = data; @@ -61,7 +75,7 @@ const OvermapDisperserContent = (props) => { At least one part of the machine is unpowered. )) || - null} + ''} {chargeload} @@ -73,7 +87,7 @@ const OvermapDisperserContent = (props) => { Warning: Do not fire during cooldown. )) || - null} + ''} @@ -89,7 +103,7 @@ const OvermapDisperserContent = (props) => { Pre-Calibration - {calibration.map((cal, i) => ( + {calibration!.map((cal, i) => ( Cal #{i}: { return ( @@ -21,7 +37,7 @@ export const OvermapEngines = (props) => { }; export const OvermapEnginesContent = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { global_state, // This indicates all engines being powered up or not global_limit, // Global Thrust limit @@ -59,7 +75,7 @@ export const OvermapEnginesContent = (props) => { - + {engines_info.map((engine, i) => ( @@ -149,7 +165,7 @@ export const OvermapEnginesContent = (props) => { diff --git a/tgui/packages/tgui/interfaces/OvermapFull.tsx b/tgui/packages/tgui/interfaces/OvermapFull.tsx index 77736dcbc8b..37f1d96b5ad 100644 --- a/tgui/packages/tgui/interfaces/OvermapFull.tsx +++ b/tgui/packages/tgui/interfaces/OvermapFull.tsx @@ -7,7 +7,7 @@ import { OvermapHelmContent } from './OvermapHelm'; import { OvermapShipSensorsContent } from './OvermapShipSensors'; export const OvermapFull = (props) => { - const [tab, setTab] = useState(0); + const [tab, setTab] = useState(0); return ( diff --git a/tgui/packages/tgui/interfaces/OvermapHelm.jsx b/tgui/packages/tgui/interfaces/OvermapHelm.tsx similarity index 90% rename from tgui/packages/tgui/interfaces/OvermapHelm.jsx rename to tgui/packages/tgui/interfaces/OvermapHelm.tsx index 8e78e6ea078..e74a3654589 100644 --- a/tgui/packages/tgui/interfaces/OvermapHelm.jsx +++ b/tgui/packages/tgui/interfaces/OvermapHelm.tsx @@ -1,8 +1,33 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, Flex, LabeledList, Section, Table } from '../components'; import { Window } from '../layouts'; import { OvermapFlightData, OvermapPanControls } from './common/Overmap'; +type Data = { + sector: string; + sector_info: string; + landed: string; + s_x: number; + s_y: number; + dest: BooleanLike; + d_x: number; + d_y: number; + speedlimit: string | number; + accel: number; + heading: number; + autopilot_disabled: BooleanLike; + autopilot: number; + manual_control: BooleanLike; + canburn: BooleanLike; + accellimit: number; + speed: number; + speed_color: string | null; + ETAnext: string; + locations: { name: string; x: number; y: number; reference: string }[]; +}; + export const OvermapHelm = (props) => { return ( @@ -33,8 +58,6 @@ export const OvermapHelmContent = (props) => { }; export const OvermapFlightDataWrap = (props) => { - const { act, data } = useBackend(); - // While, yes, this is a strange choice to use fieldset over Section // just look at how pretty the legend is, sticking partially through the border ;///; return ( @@ -49,7 +72,7 @@ export const OvermapFlightDataWrap = (props) => { }; const OvermapManualControl = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { canburn, manual_control } = data; @@ -81,7 +104,7 @@ const OvermapManualControl = (props) => { }; const OvermapAutopilot = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { dest, d_x, d_y, speedlimit, autopilot, autopilot_disabled } = data; if (autopilot_disabled) { @@ -170,7 +193,7 @@ const OvermapAutopilot = (props) => { }; const OvermapNavComputer = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { sector, s_x, s_y, sector_info, landed, locations } = data; diff --git a/tgui/packages/tgui/interfaces/OvermapShieldGenerator.jsx b/tgui/packages/tgui/interfaces/OvermapShieldGenerator.tsx similarity index 80% rename from tgui/packages/tgui/interfaces/OvermapShieldGenerator.jsx rename to tgui/packages/tgui/interfaces/OvermapShieldGenerator.tsx index ef628d534f7..89c71442a90 100644 --- a/tgui/packages/tgui/interfaces/OvermapShieldGenerator.jsx +++ b/tgui/packages/tgui/interfaces/OvermapShieldGenerator.tsx @@ -1,3 +1,5 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { AnimatedNumber, @@ -9,6 +11,39 @@ import { } from '../components'; import { Window } from '../layouts'; +type Data = { + running: number; + modes: { + name: string; + desc: string; + flag: number; + status: BooleanLike; + hacked: BooleanLike; + multiplier: number; + }[]; + overloaded: BooleanLike; + mitigation_max: number; + mitigation_physical: number; + mitigation_em: number; + mitigation_heat: number; + field_integrity: number; + max_energy: number; + current_energy: number; + percentage_energy: number; + total_segments: number; + functional_segments: number; + field_radius: number; + target_radius: number; + input_cap_kw: number; + upkeep_power_usage: number; + power_usage: number; + hacked: BooleanLike; + offline_for: number; + idle_multiplier: number; + idle_valid_values: number[]; + spinup_counter: number; +}; + export const OvermapShieldGenerator = (props) => { return ( @@ -20,7 +55,7 @@ export const OvermapShieldGenerator = (props) => { }; const OvermapShieldGeneratorContent = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { modes, offline_for } = data; if (offline_for) { @@ -41,7 +76,6 @@ const OvermapShieldGeneratorContent = (props) => { {modes.map((mode) => ( { }; const OvermapShieldGeneratorStatus = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { running, overloaded, @@ -85,24 +119,24 @@ const OvermapShieldGeneratorStatus = (props) => { spinup_counter, } = data; + const tab: React.JSX.Element[] = []; + tab[1] = Shutting Down; + tab[2] = Overloaded; + tab[3] = Inactive; + tab[4] = ( + + Spinning Up + {(target_radius !== field_radius && ( + (Adjusting Radius) + )) || {spinup_counter * 2}s} + + ); + return ( - {(running === 1 && Shutting Down) || - (running === 2 && - ((overloaded && Overloaded) || ( - Running - ))) || - (running === 3 && Inactive) || - (running === 4 && ( - - Spinning Up - {(target_radius !== field_radius && ( - (Adjusting Radius) - )) || {spinup_counter * 2}s} - - )) || Offline} + {tab[running] || Offline} @@ -145,7 +179,7 @@ const OvermapShieldGeneratorStatus = (props) => { }; const OvermapShieldGeneratorControls = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { running, hacked, idle_multiplier, idle_valid_values } = data; return ( @@ -193,7 +227,7 @@ const OvermapShieldGeneratorControls = (props) => { EMERGENCY SHUTDOWN )) || - null} + ''} > } > diff --git a/tgui/packages/tgui/interfaces/OvermapShipSensors.jsx b/tgui/packages/tgui/interfaces/OvermapShipSensors.tsx similarity index 90% rename from tgui/packages/tgui/interfaces/OvermapShipSensors.jsx rename to tgui/packages/tgui/interfaces/OvermapShipSensors.tsx index 556ceab2a8b..4ed6d8cc09d 100644 --- a/tgui/packages/tgui/interfaces/OvermapShipSensors.jsx +++ b/tgui/packages/tgui/interfaces/OvermapShipSensors.tsx @@ -1,7 +1,21 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, LabeledList, ProgressBar, Section } from '../components'; import { Window } from '../layouts'; +type Data = { + viewing: BooleanLike; + on: BooleanLike; + range: string | number; + health: number; + max_health: number; + heat: number; + critical_heat: number; + status: string; + contacts: { name: string; ref: string; bearing: number }[]; +}; + export const OvermapShipSensors = (props) => { return ( @@ -13,7 +27,7 @@ export const OvermapShipSensors = (props) => { }; export const OvermapShipSensorsContent = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { viewing, on, @@ -114,7 +128,7 @@ export const OvermapShipSensorsContent = (props) => { )) || - null} + ''} > ); }; diff --git a/tgui/packages/tgui/interfaces/PartsLathe.jsx b/tgui/packages/tgui/interfaces/PartsLathe.tsx similarity index 81% rename from tgui/packages/tgui/interfaces/PartsLathe.jsx rename to tgui/packages/tgui/interfaces/PartsLathe.tsx index 71166a3accd..8b697f0a0ad 100644 --- a/tgui/packages/tgui/interfaces/PartsLathe.jsx +++ b/tgui/packages/tgui/interfaces/PartsLathe.tsx @@ -1,3 +1,4 @@ +import { BooleanLike } from 'common/react'; import { toTitleCase } from 'common/string'; import { useBackend } from '../backend'; @@ -10,12 +11,24 @@ import { Section, } from '../components'; import { Window } from '../layouts'; -import { Materials } from './ExosuitFabricator'; +import { Materials } from './ExosuitFabricator/Material'; +import { material } from './ExosuitFabricator/types'; + +type Data = { + panelOpen: BooleanLike; + materials: material[]; + copyBoard: string | null; + copyBoardReqComponents: { name: string; qty: number }[] | null; + queue: string[]; + building: string | null; + buildPercent: number | null; + error: string | null; + recipies: { name: string; type: string }[]; +}; export const PartsLathe = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { - panelOpen, copyBoard, copyBoardReqComponents, queue, @@ -28,7 +41,7 @@ export const PartsLathe = (props) => { {(error && Missing Materials: {error}) || - null} + ''} @@ -39,12 +52,16 @@ export const PartsLathe = (props) => { {toTitleCase(building)} - + )) || - null} + ''} {copyBoard && ( @@ -87,7 +104,7 @@ export const PartsLathe = (props) => { Cancel )) || - null} + ''} ))) || Queue Empty} diff --git a/tgui/packages/tgui/interfaces/PathogenicIsolator.jsx b/tgui/packages/tgui/interfaces/PathogenicIsolator.tsx similarity index 84% rename from tgui/packages/tgui/interfaces/PathogenicIsolator.jsx rename to tgui/packages/tgui/interfaces/PathogenicIsolator.tsx index 3521e0acdbe..7e88065a448 100644 --- a/tgui/packages/tgui/interfaces/PathogenicIsolator.jsx +++ b/tgui/packages/tgui/interfaces/PathogenicIsolator.tsx @@ -1,3 +1,4 @@ +import { BooleanLike } from 'common/react'; import { useState } from 'react'; import { useBackend } from '../backend'; @@ -10,19 +11,37 @@ import { Section, Tabs, } from '../components'; -import { - ComplexModal, - modalRegisterBodyOverride, -} from '../interfaces/common/ComplexModal'; import { Window } from '../layouts'; +import { ComplexModal, modalRegisterBodyOverride } from './common/ComplexModal'; +import { modalData } from './MedicalRecords/types'; -const virusModalBodyOverride = (modal) => { - const { act, data } = useBackend(); +type Data = { + syringe_inserted: BooleanLike; + isolating: BooleanLike; + pathogen_pool: + | { + name: string; + dna: string; + unique_id: number; + reference: string; + is_in_database: BooleanLike; + record: string; + }[] + | []; + can_print: BooleanLike; + database: { + name: string; + record: string; + }[]; + modal: modalData; +}; + +const virusModalBodyOverride = (modal: modalData) => { + const { act, data } = useBackend(); const { can_print } = data; const virus = modal.args; return ( { - {virus.spread_text} Transmission + {virus.spreadtype} Transmission {virus.antigen} @@ -84,18 +103,15 @@ const virusModalBodyOverride = (modal) => { }; export const PathogenicIsolator = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { isolating } = data; const [tabIndex, setTabIndex] = useState(0); - let tab = null; - if (tabIndex === 0) { - tab = ; - } else if (tabIndex === 1) { - tab = ; - } + const tab: React.JSX.Element[] = []; + tab[0] = ; + tab[1] = ; modalRegisterBodyOverride('virus', virusModalBodyOverride); return ( @@ -105,7 +121,7 @@ export const PathogenicIsolator = (props) => { {(isolating && ( The Isolator is currently isolating... )) || - null} + ''} setTabIndex(0)}> Home @@ -114,14 +130,14 @@ export const PathogenicIsolator = (props) => { Database - {tab} + {tab[tabIndex] || ''} ); }; const PathogenicIsolatorTabHome = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { syringe_inserted, pathogen_pool, can_print } = data; return ( { }; const PathogenicIsolatorTabDatabase = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { database, can_print } = data; return ( { - let appModule; +function getPdaApp(name: string) { + let appModule: __WebpackModuleApi.RequireContext; try { appModule = requirePdaInterface(`./${name}.tsx`); } catch (err) { @@ -18,15 +37,15 @@ const getPdaApp = (name) => { } throw err; } - const Component = appModule[name]; + const Component: () => React.JSX.Element = appModule[name]; if (!Component) { return routingError('missingExport', name); } return Component; -}; +} export const Pda = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { app, owner, useRetro } = data; @@ -44,14 +63,14 @@ export const Pda = (props) => { let App = getPdaApp(app.template); - const [settingsMode, setSettingsMode] = useState(false); + const [settingsMode, setSettingsMode] = useState(false); - function handleSettingsMode(value) { + function handleSettingsMode(value: BooleanLike) { setSettingsMode(value); } return ( - + { ); }; -const PDAHeader = (props) => { - const { act, data } = useBackend(); +const PDAHeader = (props: { + settingsMode: BooleanLike; + onSettingsMode: Function; +}) => { + const { act, data } = useBackend(); - const { idInserted, idLink, cartridge_name, stationTime } = data; + const { idInserted, idLink, stationTime } = data; return ( @@ -113,7 +135,7 @@ const PDAHeader = (props) => { }; const PDASettings = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { idInserted, idLink, cartridge_name, touch_silent } = data; @@ -153,8 +175,8 @@ const PDASettings = (props) => { ); }; -const PDAFooter = (props) => { - const { act, data } = useBackend(); +const PDAFooter = (props: { onSettingsMode: Function }) => { + const { act, data } = useBackend(); const { app, useRetro } = data; diff --git a/tgui/packages/tgui/interfaces/PersonalCrafting.jsx b/tgui/packages/tgui/interfaces/PersonalCrafting.tsx similarity index 87% rename from tgui/packages/tgui/interfaces/PersonalCrafting.jsx rename to tgui/packages/tgui/interfaces/PersonalCrafting.tsx index 874df9ff9d7..e7621b33918 100644 --- a/tgui/packages/tgui/interfaces/PersonalCrafting.jsx +++ b/tgui/packages/tgui/interfaces/PersonalCrafting.tsx @@ -1,3 +1,4 @@ +import { BooleanLike } from 'common/react'; import { useState } from 'react'; import { useBackend } from '../backend'; @@ -12,13 +13,35 @@ import { } from '../components'; import { Window } from '../layouts'; +type Data = { + busy: BooleanLike; + category: string; + subcategory: string; + display_craftable_only: BooleanLike; + display_compact: BooleanLike; + craftability: Record; + crafting_recipes: Record; +}; + +type recipe = { + name: string; + ref: string; + req_text: string; + catalyst_text: string; + tool_text: string; + has_subcats: BooleanLike; +}; + +type uiRecipe = Required; + export const PersonalCrafting = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { busy, display_craftable_only, display_compact } = data; const crafting_recipes = data.crafting_recipes || {}; // Sort everything into flat categories - const categories = []; - const recipes = []; + const categories: { name: string; category: string; subcategory?: string }[] = + []; + const recipes: uiRecipe[] = []; for (let category of Object.keys(crafting_recipes)) { const subcategories = crafting_recipes[category]; if ('has_subcats' in subcategories) { @@ -118,9 +141,9 @@ export const PersonalCrafting = (props) => { ); }; -const CraftingList = (props) => { +const CraftingList = (props: { craftables: uiRecipe[] }) => { const { craftables = [] } = props; - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { craftability = {}, display_compact, display_craftable_only } = data; return craftables.map((craftable) => { if (display_craftable_only && !craftability[craftable.ref]) { @@ -160,7 +183,6 @@ const CraftingList = (props) => { { - const { data } = useBackend(); + const { data } = useBackend(); const { isAI, has_toner, has_item } = data; return ( @@ -37,11 +50,11 @@ export const Photocopier = (props) => { }; const Toner = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { max_toner, current_toner } = data; - const average_toner = max_toner * 0.66; - const bad_toner = max_toner * 0.33; + const average_toner: number = max_toner * 0.66; + const bad_toner: number = max_toner * 0.33; return ( @@ -60,8 +73,8 @@ const Toner = (props) => { }; const Options = (props) => { - const { act, data } = useBackend(); - const { num_copies, has_enough_toner } = data; + const { act, data } = useBackend(); + const { num_copies } = data; return ( @@ -111,7 +124,7 @@ const Options = (props) => { }; const AIOptions = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { can_AI_print } = data; return ( diff --git a/tgui/packages/tgui/interfaces/PipeDispenser.tsx b/tgui/packages/tgui/interfaces/PipeDispenser.tsx index 7553fecf703..005d226542a 100644 --- a/tgui/packages/tgui/interfaces/PipeDispenser.tsx +++ b/tgui/packages/tgui/interfaces/PipeDispenser.tsx @@ -4,7 +4,7 @@ import { useState } from 'react'; import { useBackend } from '../backend'; import { Box, Button, Section, Tabs } from '../components'; import { Window } from '../layouts'; -import { ICON_BY_CATEGORY_NAME } from './RapidPipeDispenser'; +import { ICON_BY_CATEGORY_NAME } from './RapidPipeDispenser/constants'; type Data = { disposals: BooleanLike; diff --git a/tgui/packages/tgui/interfaces/PowerMonitor/PowerMonitorContent.tsx b/tgui/packages/tgui/interfaces/PowerMonitor/PowerMonitorContent.tsx new file mode 100644 index 00000000000..8a7486f42ad --- /dev/null +++ b/tgui/packages/tgui/interfaces/PowerMonitor/PowerMonitorContent.tsx @@ -0,0 +1,48 @@ +import { useBackend } from '../../backend'; +import { Box, Button, Section, Table } from '../../components'; +import { PowerMonitorFocus } from './PowerMonitorFocus'; +import { Data } from './types'; + +export const PowerMonitorContent = (props) => { + const { act, data } = useBackend(); + + const { all_sensors, focus } = data; + + if (focus) { + return ; + } + + let body: React.JSX.Element = No sensors detected; + + if (all_sensors) { + body = ( + + {all_sensors.map((sensor) => ( + + + act('setsensor', { id: sensor.name })} + > + {sensor.name} + + + + ))} + + ); + } + + return ( + act('refresh')}> + Scan For Sensors + + } + > + {body} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/PowerMonitor.jsx b/tgui/packages/tgui/interfaces/PowerMonitor/PowerMonitorFocus.tsx similarity index 54% rename from tgui/packages/tgui/interfaces/PowerMonitor.jsx rename to tgui/packages/tgui/interfaces/PowerMonitor/PowerMonitorFocus.tsx index a713e0fd7d9..1c23f026165 100644 --- a/tgui/packages/tgui/interfaces/PowerMonitor.jsx +++ b/tgui/packages/tgui/interfaces/PowerMonitor/PowerMonitorFocus.tsx @@ -3,113 +3,57 @@ import { flow } from 'common/fp'; import { toFixed } from 'common/math'; import { useState } from 'react'; -import { useBackend } from '../backend'; +import { useBackend } from '../../backend'; import { Box, Button, Chart, - ColorBox, Flex, - Icon, LabeledList, ProgressBar, Section, Table, -} from '../components'; -import { Window } from '../layouts'; +} from '../../components'; +import { PEAK_DRAW } from './constants'; +import { powerRank } from './functions'; +import { AreaCharge, AreaStatusColorBox } from './PowerMonitorHelpers'; +import { area, sensor } from './types'; -const PEAK_DRAW = 500000; - -export const powerRank = (str) => { - const unit = String(str.split(' ')[1]).toLowerCase(); - return ['w', 'kw', 'mw', 'gw'].indexOf(unit); -}; - -export const PowerMonitor = () => { - return ( - - - - - - ); -}; - -export const PowerMonitorContent = (props) => { - const { act, data } = useBackend(); - - const { map_levels, all_sensors, focus } = data; - - if (focus) { - return ; - } - - let body = No sensors detected; - - if (all_sensors) { - body = ( - - {all_sensors.map((sensor) => ( - - - act('setsensor', { id: sensor.name })} - > - {sensor.name} - - - - ))} - - ); - } - - return ( - act('refresh')}> - Scan For Sensors - - } - > - {body} - - ); -}; - -export const PowerMonitorFocus = (props) => { - const { act, data } = useBackend(); +export const PowerMonitorFocus = (props: { focus: sensor }) => { + const { act } = useBackend(); const { focus } = props; const { history } = focus; - const [sortByField, setSortByField] = useState(null); - const supply = history.supply[history.supply.length - 1] || 0; - const demand = history.demand[history.demand.length - 1] || 0; - const supplyData = history.supply.map((value, i) => [i, value]); - const demandData = history.demand.map((value, i) => [i, value]); - const maxValue = Math.max(PEAK_DRAW, ...history.supply, ...history.demand); + const [sortByField, setSortByField] = useState(null); + const supply: number = history.supply[history.supply.length - 1] || 0; + const demand: number = history.demand[history.demand.length - 1] || 0; + const supplyData: number[][] = history.supply.map((value, i) => [i, value]); + const demandData: number[][] = history.demand.map((value, i) => [i, value]); + const maxValue: number = Math.max( + PEAK_DRAW, + ...history.supply, + ...history.demand, + ); // Process area data - const areas = flow([ - map((area, i) => ({ + const areas: area[] = flow([ + map((area: area, i) => ({ ...area, // Generate a unique id id: area.name + i, })), - sortByField === 'name' && sortBy((area) => area.name), - sortByField === 'charge' && sortBy((area) => -area.charge), + sortByField === 'name' && sortBy((area: area) => area.name), + sortByField === 'charge' && sortBy((area: area) => -area.charge), sortByField === 'draw' && sortBy( - (area) => -powerRank(area.load), - (area) => -parseFloat(area.load), + (area: area) => -powerRank(area.load), + (area: area) => -parseFloat(area.load), ), sortByField === 'problems' && sortBy( - (area) => area.eqp, - (area) => area.lgt, - (area) => area.env, - (area) => area.charge, - (area) => area.name, + (area: area) => area.eqp, + (area: area) => area.lgt, + (area: area) => area.env, + (area: area) => area.charge, + (area: area) => area.name, ), ])(focus.areas); return ( @@ -177,26 +121,32 @@ export const PowerMonitorFocus = (props) => { setSortByField(sortByField !== 'name' && 'name')} + onClick={() => + setSortByField((sortByField !== 'name' && 'name') || null) + } > Name setSortByField(sortByField !== 'charge' && 'charge')} + onClick={() => + setSortByField((sortByField !== 'charge' && 'charge') || null) + } > Charge setSortByField(sortByField !== 'draw' && 'draw')} + onClick={() => + setSortByField((sortByField !== 'draw' && 'draw') || null) + } > Draw - setSortByField(sortByField !== 'problems' && 'problems') + setSortByField((sortByField !== 'problems' && 'problems') || null) } > Problems @@ -218,7 +168,7 @@ export const PowerMonitorFocus = (props) => { {areas.map((area, i) => ( - + {area.name} @@ -242,43 +192,3 @@ export const PowerMonitorFocus = (props) => { > ); }; - -export const AreaCharge = (props) => { - const { charging, charge } = props; - return ( - <> - 50 ? 'battery-half' : 'battery-quarter')) || - (charging === 1 && 'bolt') || - (charging === 2 && 'battery-full') - } - color={ - (charging === 0 && (charge > 50 ? 'yellow' : 'red')) || - (charging === 1 && 'yellow') || - (charging === 2 && 'green') - } - /> - - {toFixed(charge) + '%'} - - > - ); -}; - -const AreaStatusColorBox = (props) => { - const { status } = props; - const power = Boolean(status & 2); - const mode = Boolean(status & 1); - const tooltipText = (power ? 'On' : 'Off') + ` [${mode ? 'auto' : 'manual'}]`; - return ( - - ); -}; diff --git a/tgui/packages/tgui/interfaces/PowerMonitor/PowerMonitorHelpers.tsx b/tgui/packages/tgui/interfaces/PowerMonitor/PowerMonitorHelpers.tsx new file mode 100644 index 00000000000..faa6922035c --- /dev/null +++ b/tgui/packages/tgui/interfaces/PowerMonitor/PowerMonitorHelpers.tsx @@ -0,0 +1,46 @@ +import { toFixed } from 'common/math'; + +import { Box, ColorBox, Icon, Tooltip } from '../../components'; + +export const AreaCharge = (props: { charging: number; charge: number }) => { + const { charging, charge } = props; + return ( + <> + 50 ? 'battery-half' : 'battery-quarter')) || + (charging === 1 && 'bolt') || + (charging === 2 && 'battery-full') || + '' + } + color={ + (charging === 0 && (charge > 50 ? 'yellow' : 'red')) || + (charging === 1 && 'yellow') || + (charging === 2 && 'green') + } + /> + + {toFixed(charge) + '%'} + + > + ); +}; + +export const AreaStatusColorBox = (props: { status: number }) => { + const { status } = props; + const power: boolean = Boolean(status & 2); + const mode: boolean = Boolean(status & 1); + const tooltipText: string = + (power ? 'On' : 'Off') + ` [${mode ? 'auto' : 'manual'}]`; + return ( + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/PowerMonitor/constants.ts b/tgui/packages/tgui/interfaces/PowerMonitor/constants.ts new file mode 100644 index 00000000000..e557920e2e5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PowerMonitor/constants.ts @@ -0,0 +1 @@ +export const PEAK_DRAW: number = 500000; diff --git a/tgui/packages/tgui/interfaces/PowerMonitor/functions.ts b/tgui/packages/tgui/interfaces/PowerMonitor/functions.ts new file mode 100644 index 00000000000..ce8c24fe3cf --- /dev/null +++ b/tgui/packages/tgui/interfaces/PowerMonitor/functions.ts @@ -0,0 +1,4 @@ +export function powerRank(str: string): number { + const unit: string = String(str.split(' ')[1]).toLowerCase(); + return ['w', 'kw', 'mw', 'gw'].indexOf(unit); +} diff --git a/tgui/packages/tgui/interfaces/PowerMonitor/index.tsx b/tgui/packages/tgui/interfaces/PowerMonitor/index.tsx new file mode 100644 index 00000000000..3cadcabfe20 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PowerMonitor/index.tsx @@ -0,0 +1,12 @@ +import { Window } from '../../layouts'; +import { PowerMonitorContent } from './PowerMonitorContent'; + +export const PowerMonitor = () => { + return ( + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/PowerMonitor/types.ts b/tgui/packages/tgui/interfaces/PowerMonitor/types.ts new file mode 100644 index 00000000000..320979c9986 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PowerMonitor/types.ts @@ -0,0 +1,25 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + all_sensors: { name: string; alarm: BooleanLike }[]; + focus: sensor | null; +}; + +export type sensor = { + name: string; + stored: number; + interval: number; + attached: BooleanLike; + history: { supply: number[]; demand: number[] }; + areas: area[]; +}; + +export type area = { + name: string; + charge: number; + load: string; + charging: number; + eqp: number; + lgt: number; + env: number; +}; diff --git a/tgui/packages/tgui/interfaces/PressureRegulator.jsx b/tgui/packages/tgui/interfaces/PressureRegulator.tsx similarity index 93% rename from tgui/packages/tgui/interfaces/PressureRegulator.jsx rename to tgui/packages/tgui/interfaces/PressureRegulator.tsx index 390f56c5fa9..ee929824e4c 100644 --- a/tgui/packages/tgui/interfaces/PressureRegulator.jsx +++ b/tgui/packages/tgui/interfaces/PressureRegulator.tsx @@ -1,9 +1,22 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { AnimatedNumber, Button, LabeledList, Section } from '../components'; import { Window } from '../layouts'; +type Data = { + on: BooleanLike; + pressure_set: number; + max_pressure: number; + input_pressure: number; + output_pressure: number; + regulate_mode: number; + set_flow_rate: number; + last_flow_rate: number; +}; + export const PressureRegulator = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { on, diff --git a/tgui/packages/tgui/interfaces/PrisonerManagement.jsx b/tgui/packages/tgui/interfaces/PrisonerManagement.tsx similarity index 93% rename from tgui/packages/tgui/interfaces/PrisonerManagement.jsx rename to tgui/packages/tgui/interfaces/PrisonerManagement.tsx index 3fc24cdec04..b1888d41615 100644 --- a/tgui/packages/tgui/interfaces/PrisonerManagement.jsx +++ b/tgui/packages/tgui/interfaces/PrisonerManagement.tsx @@ -1,9 +1,17 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, Section, Table } from '../components'; import { Window } from '../layouts'; +type Data = { + locked: BooleanLike; + chemImplants: { host: string; units: string; ref: string }[]; + trackImplants: { host: string; ref: string; id: string; loc: string }[]; +}; + export const PrisonerManagement = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { locked, chemImplants, trackImplants } = data; return ( diff --git a/tgui/packages/tgui/interfaces/RCON.jsx b/tgui/packages/tgui/interfaces/RCON.jsx deleted file mode 100644 index e598f6f753b..00000000000 --- a/tgui/packages/tgui/interfaces/RCON.jsx +++ /dev/null @@ -1,351 +0,0 @@ -import { toFixed } from 'common/math'; -import { capitalize } from 'common/string'; -import { useState } from 'react'; - -import { useBackend } from '../backend'; -import { - Box, - Button, - Icon, - LabeledList, - ProgressBar, - Section, - Slider, - Stack, - Tabs, -} from '../components'; -import { formatPower } from '../format'; -import { Window } from '../layouts'; - -// Common power multiplier -const POWER_MUL = 1e3; - -export const RCON = (props) => { - return ( - - - - - - ); -}; - -export const RCONContent = (props) => { - const [tabIndex, setTabIndex] = useState(0); - - let body; - if (tabIndex === 0) { - body = ; - } else if (tabIndex === 1) { - body = ; - } - - return ( - <> - - setTabIndex(0)} - > - SMESs - - setTabIndex(1)} - > - Breakers - - - {body} - > - ); -}; - -const RCONSmesList = (props) => { - const { act, data } = useBackend(); - - const { smes_info, pages, current_page } = data; - - const runCallback = (cb) => { - return cb(); - }; - - return ( - - - {smes_info.map((smes) => ( - - - - ))} - - Page Selection: - - {runCallback(() => { - const row = []; - for (let i = 1; i < pages; i++) { - row.push( - - act('set_smes_page', { - index: i, - }) - } - > - {i} - , - ); - } - return row; - })} - - ); -}; - -const SMESItem = (props) => { - const { act } = useBackend(); - const { - capacityPercent, - capacity, - charge, - inputAttempt, - inputting, - inputLevel, - inputLevelMax, - inputAvailable, - outputAttempt, - outputting, - outputLevel, - outputLevelMax, - outputUsed, - RCON_tag, - } = props.smes; - - return ( - - - - - {RCON_tag} - - - - {toFixed(charge / (1000 * 60), 1) + - 'kWh / ' + - toFixed(capacity / (1000 * 60)) + - 'kWh (' + - capacityPercent + - '%)'} - - - - - - - - - - - - - ); -}; - -const SMESControls = (props) => { - const { act } = useBackend(); - const { way, smes } = props; - const { - capacityPercent, - capacity, - charge, - inputAttempt, - inputting, - inputLevel, - inputLevelMax, - inputAvailable, - outputAttempt, - outputting, - outputLevel, - outputLevelMax, - outputUsed, - RCON_tag, - } = smes; - - let level; - let levelMax; - let available; - let direction; - let changeStatusAct; - let changeAmountAct; - let enabled; - let powerColor; - let powerTooltip; - - switch (way) { - case 'input': - level = inputLevel; - levelMax = inputLevelMax; - available = inputAvailable; - direction = 'IN'; - changeStatusAct = 'smes_in_toggle'; - changeAmountAct = 'smes_in_set'; - enabled = inputAttempt; - powerColor = !inputAttempt ? null : inputting ? 'green' : 'yellow'; - powerTooltip = !inputAttempt - ? 'The SMES input is off.' - : inputting - ? 'The SMES is drawing power.' - : 'The SMES lacks power.'; - break; - case 'output': - level = outputLevel; - levelMax = outputLevelMax; - available = outputUsed; - direction = 'OUT'; - changeStatusAct = 'smes_out_toggle'; - changeAmountAct = 'smes_out_set'; - enabled = outputAttempt; - powerColor = !outputAttempt ? null : outputting ? 'green' : 'yellow'; - powerTooltip = !outputAttempt - ? 'The SMES output is off.' - : outputting - ? 'The SMES is outputting power.' - : 'The SMES lacks any draw.'; - break; - } - - return ( - - {capitalize(way)} - - - - - act(changeStatusAct, { - smes: RCON_tag, - }) - } - /> - - - - act(changeAmountAct, { - target: 'min', - smes: RCON_tag, - }) - } - /> - - act(changeAmountAct, { - adjust: -10000, - smes: RCON_tag, - }) - } - /> - - - - formatPower(available, 1) + - '/' + - formatPower(value * POWER_MUL, 1) - } - onDrag={(e, value) => - act(changeAmountAct, { - target: value * POWER_MUL, - smes: RCON_tag, - }) - } - /> - - - - act(changeAmountAct, { - adjust: 10000, - smes: RCON_tag, - }) - } - /> - - act(changeAmountAct, { - target: 'max', - smes: RCON_tag, - }) - } - /> - - - - - ); -}; - -const RCONBreakerList = (props) => { - const { act, data } = useBackend(); - - const { breaker_info } = data; - - return ( - - - {breaker_info ? ( - breaker_info.map((breaker) => ( - - act('toggle_breaker', { - breaker: breaker.RCON_tag, - }) - } - > - {breaker.enabled ? 'Enabled' : 'Disabled'} - - } - /> - )) - ) : ( - No breakers detected. - )} - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/RCON/RCONBreakerList.tsx b/tgui/packages/tgui/interfaces/RCON/RCONBreakerList.tsx new file mode 100644 index 00000000000..399d4980e9e --- /dev/null +++ b/tgui/packages/tgui/interfaces/RCON/RCONBreakerList.tsx @@ -0,0 +1,40 @@ +import { useBackend } from '../../backend'; +import { Button, LabeledList, Section } from '../../components'; +import { Data } from './types'; + +export const RCONBreakerList = (props) => { + const { act, data } = useBackend(); + + const { breaker_info } = data; + + return ( + + + {breaker_info ? ( + breaker_info.map((breaker) => ( + + act('toggle_breaker', { + breaker: breaker.RCON_tag, + }) + } + > + {breaker.enabled ? 'Enabled' : 'Disabled'} + + } + /> + )) + ) : ( + No breakers detected. + )} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RCON/RCONContent.tsx b/tgui/packages/tgui/interfaces/RCON/RCONContent.tsx new file mode 100644 index 00000000000..07f11410840 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RCON/RCONContent.tsx @@ -0,0 +1,36 @@ +import { useState } from 'react'; + +import { Box, Icon, Tabs } from '../../components'; +import { RCONBreakerList } from './RCONBreakerList'; +import { RCONSmesList } from './RCONSmesList'; + +export const RCONContent = (props) => { + const [tabIndex, setTabIndex] = useState(0); + + const body: React.JSX.Element[] = []; + + body[0] = ; + body[1] = ; + + return ( + <> + + setTabIndex(0)} + > + SMESs + + setTabIndex(1)} + > + Breakers + + + {body[tabIndex] || ''} + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/RCON/RCONSMESControls.tsx b/tgui/packages/tgui/interfaces/RCON/RCONSMESControls.tsx new file mode 100644 index 00000000000..9ef2608c791 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RCON/RCONSMESControls.tsx @@ -0,0 +1,156 @@ +import { BooleanLike } from 'common/react'; +import { capitalize } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Button, Slider, Stack } from '../../components'; +import { formatPower } from '../../format'; +import { POWER_MUL } from './constants'; +import { rconSmes } from './types'; + +export const SMESControls = (props: { way: string; smes: rconSmes }) => { + const { act } = useBackend(); + const { way, smes } = props; + const { + inputAttempt, + inputting, + inputLevel, + inputLevelMax, + inputAvailable, + outputAttempt, + outputting, + outputLevel, + outputLevelMax, + outputUsed, + RCON_tag, + } = smes; + + let level: number = 0; + let levelMax: number = 0; + let available: number = 0; + let direction: string; + let changeStatusAct: string; + let changeAmountAct: string; + let enabled: BooleanLike; + let powerColor: string | undefined; + let powerTooltip: string = ''; + + switch (way) { + case 'input': + level = inputLevel; + levelMax = inputLevelMax; + available = inputAvailable; + direction = 'IN'; + changeStatusAct = 'smes_in_toggle'; + changeAmountAct = 'smes_in_set'; + enabled = inputAttempt; + powerColor = !inputAttempt ? undefined : inputting ? 'green' : 'yellow'; + powerTooltip = !inputAttempt + ? 'The SMES input is off.' + : inputting + ? 'The SMES is drawing power.' + : 'The SMES lacks power.'; + break; + case 'output': + level = outputLevel; + levelMax = outputLevelMax; + available = outputUsed; + direction = 'OUT'; + changeStatusAct = 'smes_out_toggle'; + changeAmountAct = 'smes_out_set'; + enabled = outputAttempt; + powerColor = !outputAttempt ? undefined : outputting ? 'green' : 'yellow'; + powerTooltip = !outputAttempt + ? 'The SMES output is off.' + : outputting + ? 'The SMES is outputting power.' + : 'The SMES lacks any draw.'; + break; + } + + return ( + + {capitalize(way)} + + + + + act(changeStatusAct, { + smes: RCON_tag, + }) + } + /> + + + + act(changeAmountAct, { + target: 'min', + smes: RCON_tag, + }) + } + /> + + act(changeAmountAct, { + adjust: -10000, + smes: RCON_tag, + }) + } + /> + + + + formatPower(available, 1) + + '/' + + formatPower(value * POWER_MUL, 1) + } + onDrag={(e, value: number) => + act(changeAmountAct, { + target: value * POWER_MUL, + smes: RCON_tag, + }) + } + /> + + + + act(changeAmountAct, { + adjust: 10000, + smes: RCON_tag, + }) + } + /> + + act(changeAmountAct, { + target: 'max', + smes: RCON_tag, + }) + } + /> + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RCON/RCONSMESItem.tsx b/tgui/packages/tgui/interfaces/RCON/RCONSMESItem.tsx new file mode 100644 index 00000000000..93122d580e3 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RCON/RCONSMESItem.tsx @@ -0,0 +1,45 @@ +import { toFixed } from 'common/math'; + +import { ProgressBar, Stack } from '../../components'; +import { SMESControls } from './RCONSMESControls'; +import { rconSmes } from './types'; + +export const SMESItem = (props: { smes: rconSmes }) => { + const { capacityPercent, capacity, charge, RCON_tag } = props.smes; + + return ( + + + + + {RCON_tag} + + + + {toFixed(charge / (1000 * 60), 1) + + 'kWh / ' + + toFixed(capacity / (1000 * 60)) + + 'kWh (' + + capacityPercent + + '%)'} + + + + + + + + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RCON/RCONSmesList.tsx b/tgui/packages/tgui/interfaces/RCON/RCONSmesList.tsx new file mode 100644 index 00000000000..3bde7c21031 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RCON/RCONSmesList.tsx @@ -0,0 +1,47 @@ +import { useBackend } from '../../backend'; +import { Button, Section, Stack } from '../../components'; +import { SMESItem } from './RCONSMESItem'; +import { Data } from './types'; + +export const RCONSmesList = (props) => { + const { act, data } = useBackend(); + + const { smes_info, pages, current_page } = data; + + const runCallback = (cb: Function) => { + return cb(); + }; + + return ( + + + {smes_info.map((smes) => ( + + + + ))} + + Page Selection: + + {runCallback(() => { + const row: React.JSX.Element[] = []; + for (let i: number = 1; i < pages; i++) { + row.push( + + act('set_smes_page', { + index: i, + }) + } + > + {i} + , + ); + } + return row; + })} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RCON/constants.ts b/tgui/packages/tgui/interfaces/RCON/constants.ts new file mode 100644 index 00000000000..26b2f0f4a21 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RCON/constants.ts @@ -0,0 +1,2 @@ +// Common power multiplier +export const POWER_MUL: number = 1e3; diff --git a/tgui/packages/tgui/interfaces/RCON/index.tsx b/tgui/packages/tgui/interfaces/RCON/index.tsx new file mode 100644 index 00000000000..139403fe0ba --- /dev/null +++ b/tgui/packages/tgui/interfaces/RCON/index.tsx @@ -0,0 +1,12 @@ +import { Window } from '../../layouts'; +import { RCONContent } from './RCONContent'; + +export const RCON = (props) => { + return ( + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RCON/types.ts b/tgui/packages/tgui/interfaces/RCON/types.ts new file mode 100644 index 00000000000..80d2934ea65 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RCON/types.ts @@ -0,0 +1,12 @@ +import { BooleanLike } from 'common/react'; + +import { smes } from '../Smes'; + +export type Data = { + pages: number; + current_page: number; + smes_info: rconSmes[]; + breaker_info: { RCON_tag: string; enabled: BooleanLike }[]; +}; + +export type rconSmes = Required; diff --git a/tgui/packages/tgui/interfaces/RIGSuit.jsx b/tgui/packages/tgui/interfaces/RIGSuit.jsx deleted file mode 100644 index b37927d2cab..00000000000 --- a/tgui/packages/tgui/interfaces/RIGSuit.jsx +++ /dev/null @@ -1,353 +0,0 @@ -import { capitalize, toTitleCase } from 'common/string'; - -import { useBackend } from '../backend'; -import { - Box, - Button, - Flex, - LabeledList, - ProgressBar, - Section, -} from '../components'; -import { Window } from '../layouts'; - -export const RIGSuit = (props) => { - const { act, data } = useBackend(); - - const { interfacelock, malf, aicontrol, ai } = data; - - let override = null; - - if (interfacelock || malf) { - // Interface is offline, or a malf AI took over, either way, the user is - // no longer permitted to view this interface. - override = --HARDSUIT INTERFACE OFFLINE--; - } else if (!ai && aicontrol) { - // Non-AI trying to control the hardsuit while it's AI control overridden - override = -- HARDSUIT CONTROL OVERRIDDEN BY AI --; - } - - return ( - - - {override || ( - <> - - - - > - )} - - - ); -}; - -const RIGSuitStatus = (props) => { - const { act, data } = useBackend(); - - const { - // Power Bar - chargestatus, - charge, - maxcharge, - // AI Control Toggle - aioverride, - // Suit Status - sealing, - sealed, - cooling, - // Cover Locks - emagged, - securitycheck, - coverlock, - } = data; - - const SealButton = ( - act('toggle_seals')} - > - {'Suit ' + - (sealing ? 'seals working...' : sealed ? 'is Active' : 'is Inactive')} - - ); - - const CoolingButton = ( - act('toggle_cooling')} - > - {'Suit Cooling ' + (cooling ? 'is Active' : 'is Inactive')} - - ); - - const AIButton = ( - act('toggle_ai_control')} - > - {'AI Control ' + (aioverride ? 'Enabled' : 'Disabled')} - - ); - - return ( - - {SealButton} - {AIButton} - {CoolingButton} - > - } - > - - - - {charge} / {maxcharge} - - - - {emagged || !securitycheck ? ( - Error - Maintenance Lock Control Offline - ) : ( - act('toggle_suit_lock')} - > - {coverlock ? 'Locked' : 'Unlocked'} - - )} - - - - ); -}; - -const RIGSuitHardware = (props) => { - const { act, data } = useBackend(); - - const { - // Disables buttons while the suit is busy - sealing, - // Each piece - helmet, - helmetDeployed, - gauntlets, - gauntletsDeployed, - boots, - bootsDeployed, - chest, - chestDeployed, - } = data; - - return ( - - - act('toggle_piece', { piece: 'helmet' })} - > - {helmetDeployed ? 'Deployed' : 'Deploy'} - - } - > - {helmet ? capitalize(helmet) : 'ERROR'} - - act('toggle_piece', { piece: 'gauntlets' })} - > - {gauntletsDeployed ? 'Deployed' : 'Deploy'} - - } - > - {gauntlets ? capitalize(gauntlets) : 'ERROR'} - - act('toggle_piece', { piece: 'boots' })} - > - {bootsDeployed ? 'Deployed' : 'Deploy'} - - } - > - {boots ? capitalize(boots) : 'ERROR'} - - act('toggle_piece', { piece: 'chest' })} - > - {chestDeployed ? 'Deployed' : 'Deploy'} - - } - > - {chest ? capitalize(chest) : 'ERROR'} - - - - ); -}; - -const RIGSuitModules = (props) => { - const { act, data } = useBackend(); - - const { - // Seals disable Modules - sealed, - sealing, - // Currently Selected system - primarysystem, - // The actual modules. - modules, - } = data; - - if (!sealed || sealing) { - return ( - - HARDSUIT SYSTEMS OFFLINE - - ); - } - - return ( - - - Selected Primary: {capitalize(primarysystem || 'None')} - - {modules && - modules.map((module, i) => ( - - {module.can_select ? ( - - act('interact_module', { - module: module.index, - module_mode: 'select', - }) - } - > - {module.name === primarysystem ? 'Selected' : 'Select'} - - ) : null} - {module.can_use ? ( - - act('interact_module', { - module: module.index, - module_mode: 'engage', - }) - } - > - {module.engagestring} - - ) : null} - {module.can_toggle ? ( - - act('interact_module', { - module: module.index, - module_mode: 'toggle', - }) - } - > - {module.is_active - ? module.deactivatestring - : module.activatestring} - - ) : null} - > - } - > - {module.damage >= 2 ? ( - -- MODULE DESTROYED -- - ) : ( - - - Engage: {module.engagecost} - Active: {module.activecost} - Passive: {module.passivecost} - - {module.desc} - - )} - {module.charges ? ( - - - - - {capitalize(module.chargetype)} - - {module.charges.map((charge, i) => ( - - - act('interact_module', { - module: module.index, - module_mode: 'select_charge_type', - charge_type: charge.index, - }) - } - /> - - ))} - - - - ) : null} - - ))} - - ); -}; diff --git a/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitHardware.tsx b/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitHardware.tsx new file mode 100644 index 00000000000..22e1d23724e --- /dev/null +++ b/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitHardware.tsx @@ -0,0 +1,90 @@ +import { capitalize } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Button, LabeledList, Section } from '../../components'; +import { Data } from './types'; + +export const RIGSuitHardware = (props) => { + const { act, data } = useBackend(); + + const { + // Disables buttons while the suit is busy + sealing, + // Each piece + helmet, + helmetDeployed, + gauntlets, + gauntletsDeployed, + boots, + bootsDeployed, + chest, + chestDeployed, + } = data; + + return ( + + + act('toggle_piece', { piece: 'helmet' })} + > + {helmetDeployed ? 'Deployed' : 'Deploy'} + + } + > + {helmet ? capitalize(helmet) : 'ERROR'} + + act('toggle_piece', { piece: 'gauntlets' })} + > + {gauntletsDeployed ? 'Deployed' : 'Deploy'} + + } + > + {gauntlets ? capitalize(gauntlets) : 'ERROR'} + + act('toggle_piece', { piece: 'boots' })} + > + {bootsDeployed ? 'Deployed' : 'Deploy'} + + } + > + {boots ? capitalize(boots) : 'ERROR'} + + act('toggle_piece', { piece: 'chest' })} + > + {chestDeployed ? 'Deployed' : 'Deploy'} + + } + > + {chest ? capitalize(chest) : 'ERROR'} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitModules.tsx b/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitModules.tsx new file mode 100644 index 00000000000..d04bc9c9695 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitModules.tsx @@ -0,0 +1,141 @@ +import { capitalize, toTitleCase } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Box, Button, Flex, LabeledList, Section } from '../../components'; +import { Data } from './types'; + +export const RIGSuitModules = (props) => { + const { act, data } = useBackend(); + + const { + // Seals disable Modules + sealed, + sealing, + // Currently Selected system + primarysystem, + // The actual modules. + modules, + } = data; + + if (!sealed || sealing) { + return ( + + HARDSUIT SYSTEMS OFFLINE + + ); + } + + return ( + + + Selected Primary: {capitalize(primarysystem || 'None')} + + {modules && + modules.map((module, i) => ( + + {module.can_select ? ( + + act('interact_module', { + module: module.index, + module_mode: 'select', + }) + } + > + {module.name === primarysystem ? 'Selected' : 'Select'} + + ) : ( + '' + )} + {module.can_use ? ( + + act('interact_module', { + module: module.index, + module_mode: 'engage', + }) + } + > + {module.engagestring} + + ) : ( + '' + )} + {module.can_toggle ? ( + + act('interact_module', { + module: module.index, + module_mode: 'toggle', + }) + } + > + {module.is_active + ? module.deactivatestring + : module.activatestring} + + ) : ( + '' + )} + > + } + > + {module.damage >= 2 ? ( + -- MODULE DESTROYED -- + ) : ( + + + Engage: {module.engagecost} + Active: {module.activecost} + Passive: {module.passivecost} + + {module.desc} + + )} + {module.charges ? ( + + + + + {capitalize(module.chargetype)} + + {module.charges.map((charge, i) => ( + + + act('interact_module', { + module: module.index, + module_mode: 'select_charge_type', + charge_type: charge.index, + }) + } + /> + + ))} + + + + ) : ( + '' + )} + + ))} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitStatus.tsx b/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitStatus.tsx new file mode 100644 index 00000000000..eac883b7ab7 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitStatus.tsx @@ -0,0 +1,105 @@ +import { useBackend } from '../../backend'; +import { + Box, + Button, + LabeledList, + ProgressBar, + Section, +} from '../../components'; +import { Data } from './types'; + +export const RIGSuitStatus = (props) => { + const { act, data } = useBackend(); + + const { + // Power Bar + chargestatus, + charge, + maxcharge, + // AI Control Toggle + aioverride, + // Suit Status + sealing, + sealed, + cooling, + // Cover Locks + emagged, + securitycheck, + coverlock, + } = data; + + const SealButton = ( + act('toggle_seals')} + > + {'Suit ' + + (sealing ? 'seals working...' : sealed ? 'is Active' : 'is Inactive')} + + ); + + const CoolingButton = ( + act('toggle_cooling')} + > + {'Suit Cooling ' + (cooling ? 'is Active' : 'is Inactive')} + + ); + + const AIButton = ( + act('toggle_ai_control')} + > + {'AI Control ' + (aioverride ? 'Enabled' : 'Disabled')} + + ); + + return ( + + {SealButton} + {AIButton} + {CoolingButton} + > + } + > + + + + {charge} / {maxcharge} + + + + {emagged || !securitycheck ? ( + Error - Maintenance Lock Control Offline + ) : ( + act('toggle_suit_lock')} + > + {coverlock ? 'Locked' : 'Unlocked'} + + )} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RIGSuit/index.tsx b/tgui/packages/tgui/interfaces/RIGSuit/index.tsx new file mode 100644 index 00000000000..8138c407848 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RIGSuit/index.tsx @@ -0,0 +1,38 @@ +import { useBackend } from '../../backend'; +import { Box } from '../../components'; +import { Window } from '../../layouts'; +import { RIGSuitHardware } from './RIGSuitHardware'; +import { RIGSuitModules } from './RIGSuitModules'; +import { RIGSuitStatus } from './RIGSuitStatus'; +import { Data } from './types'; + +export const RIGSuit = (props) => { + const { data } = useBackend(); + + const { interfacelock, malf, aicontrol, ai } = data; + + let override: React.JSX.Element | null = null; + + if (interfacelock || malf) { + // Interface is offline, or a malf AI took over, either way, the user is + // no longer permitted to view this interface. + override = --HARDSUIT INTERFACE OFFLINE--; + } else if (!ai && aicontrol) { + // Non-AI trying to control the hardsuit while it's AI control overridden + override = -- HARDSUIT CONTROL OVERRIDDEN BY AI --; + } + + return ( + + + {override || ( + <> + + + + > + )} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RIGSuit/types.ts b/tgui/packages/tgui/interfaces/RIGSuit/types.ts new file mode 100644 index 00000000000..b1f110a832b --- /dev/null +++ b/tgui/packages/tgui/interfaces/RIGSuit/types.ts @@ -0,0 +1,46 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + primarysystem: string | null; + ai: BooleanLike; + cooling: BooleanLike; + sealed: BooleanLike; + sealing: BooleanLike; + helmet: string; + gauntlets: string; + boots: string; + chest: string; + helmetDeployed: BooleanLike; + gauntletsDeployed: BooleanLike; + bootsDeployed: BooleanLike; + chestDeployed: BooleanLike; + charge: number; + maxcharge: number; + chargestatus: number; + emagged: BooleanLike; + coverlock: BooleanLike; + interfacelock: BooleanLike; + aicontrol: BooleanLike; + aioverride: BooleanLike; + securitycheck: BooleanLike; + malf: BooleanLike; + modules: { + index: number; + name: string; + desc: string; + can_use: BooleanLike; + can_select: BooleanLike; + can_toggle: BooleanLike; + is_active: BooleanLike; + engagecost: number; + activecost: number; + passivecost: number; + engagestring: string; + activatestring: string; + deactivatestring: string; + damage: number; + charges: { caption: string; index: string }[]; + realchargetype: string; + chargetype: string; + }[]; +}; diff --git a/tgui/packages/tgui/interfaces/Radio.jsx b/tgui/packages/tgui/interfaces/Radio.tsx similarity index 85% rename from tgui/packages/tgui/interfaces/Radio.jsx rename to tgui/packages/tgui/interfaces/Radio.tsx index d281fcbfbde..50d399ca666 100644 --- a/tgui/packages/tgui/interfaces/Radio.jsx +++ b/tgui/packages/tgui/interfaces/Radio.tsx @@ -1,12 +1,36 @@ import { round, toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { Box, Button, LabeledList, NumberInput, Section } from '../components'; import { RADIO_CHANNELS } from '../constants'; import { Window } from '../layouts'; +type Data = { + rawfreq: number; + listening: BooleanLike; + broadcasting: BooleanLike; + subspace: BooleanLike; + subspaceSwitchable: BooleanLike; + loudspeaker: BooleanLike; + mic_cut: BooleanLike; + spk_cut: BooleanLike; + chan_list: + | { + chan: number; + display_name: string; + secure_channel: BooleanLike; + sec_channel_listen: BooleanLike; + freq: number; + }[] + | null; + useSyndMode: BooleanLike; + minFrequency: number; + maxFrequency: number; +}; + export const Radio = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { rawfreq, minFrequency, @@ -27,7 +51,7 @@ export const Radio = (props) => { ); // Calculate window height - let height = 156; + let height: number = 156; if (chan_list && chan_list.length > 0) { height += chan_list.length * 28 + 6; } else { @@ -37,12 +61,7 @@ export const Radio = (props) => { height += 38; } return ( - + @@ -55,10 +74,10 @@ export const Radio = (props) => { minValue={minFrequency / 10} maxValue={maxFrequency / 10} value={rawfreq / 10} - format={(value) => toFixed(value, 1)} - onDrag={(e, value) => + format={(value: number) => toFixed(value, 1)} + onDrag={(e, value: number) => act('setFrequency', { - freq: round(value * 10), + freq: round(value * 10, 0), }) } /> diff --git a/tgui/packages/tgui/interfaces/RapidPipeDispenser.jsx b/tgui/packages/tgui/interfaces/RapidPipeDispenser.jsx deleted file mode 100644 index 959a59bd0e2..00000000000 --- a/tgui/packages/tgui/interfaces/RapidPipeDispenser.jsx +++ /dev/null @@ -1,244 +0,0 @@ -import { classes } from 'common/react'; -import { capitalize } from 'common/string'; -import { useState } from 'react'; - -import { useBackend } from '../backend'; -import { - Box, - Button, - ColorBox, - LabeledList, - Section, - Stack, - Tabs, -} from '../components'; -import { Window } from '../layouts'; - -const ROOT_CATEGORIES = [ - 'Atmospherics', - 'Disposals', - // 'Transit Tubes', -]; - -export const ICON_BY_CATEGORY_NAME = { - Atmospherics: 'wrench', - Disposals: 'trash-alt', - 'Transit Tubes': 'bus', - Pipes: 'grip-lines', - 'Disposal Pipes': 'grip-lines', - Devices: 'microchip', - 'Heat Exchange': 'thermometer-half', - 'Insulated pipes': 'snowflake', - 'Station Equipment': 'microchip', -}; - -const TOOLS = [ - { - name: 'Dispense', - bitmask: 1, - }, - { - name: 'Connect', - bitmask: 2, - }, - { - name: 'Destroy', - bitmask: 4, - }, - { - name: 'Paint', - bitmask: 8, - }, -]; - -const SelectionSection = (props) => { - const { act, data } = useBackend(); - const { category: rootCategoryIndex, selected_color, mode } = data; - return ( - - - - {ROOT_CATEGORIES.map((categoryName, i) => ( - act('category', { category: i })} - > - {categoryName} - - ))} - - - - {TOOLS.map((tool) => ( - - - act('mode', { - mode: tool.bitmask, - }) - } - > - {tool.name} - - - ))} - - - - - {capitalize(selected_color)} - - {Object.keys(data.paint_colors).map((colorName) => ( - - act('color', { - paint_color: colorName, - }) - } - /> - ))} - - - - ); -}; - -const LayerSection = (props) => { - const { act, data } = useBackend(); - const { category: rootCategoryIndex, piping_layer, pipe_layers } = data; - const previews = data.preview_rows.flatMap((row) => row.previews); - return ( - - {rootCategoryIndex === 0 && ( - - {Object.keys(pipe_layers).map((layer) => ( - - - act('piping_layer', { - piping_layer: pipe_layers[layer], - }) - } - > - {layer} - - - ))} - - )} - - {previews.map((preview) => ( - - act('setdir', { - dir: preview.dir, - flipped: preview.flipped, - }) - } - > - - - ))} - - - ); -}; - -const PipeTypeSection = (props) => { - const { act, data } = useBackend(); - const { categories = [] } = data; - const [categoryName, setCategoryName] = useState('categoryName'); - const shownCategory = - categories.find((category) => category.cat_name === categoryName) || - categories[0]; - return ( - - - {categories.map((category, i) => ( - setCategoryName(category.cat_name)} - > - {category.cat_name} - - ))} - - {shownCategory?.recipes.map((recipe) => ( - - act('pipe_type', { - pipe_type: recipe.pipe_index, - category: shownCategory.cat_name, - }) - } - > - {recipe.pipe_name} - - ))} - - ); -}; - -export const RapidPipeDispenser = (props) => { - const { act, data } = useBackend(); - const { category: rootCategoryIndex } = data; - return ( - - - - - - - - - - - - - - - - - - - - - - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/RapidPipeDispenser/LayerSection.tsx b/tgui/packages/tgui/interfaces/RapidPipeDispenser/LayerSection.tsx new file mode 100644 index 00000000000..33f032f725e --- /dev/null +++ b/tgui/packages/tgui/interfaces/RapidPipeDispenser/LayerSection.tsx @@ -0,0 +1,64 @@ +import { classes } from 'common/react'; + +import { useBackend } from '../../backend'; +import { Box, Button, Section, Stack } from '../../components'; +import { Data } from './types'; + +export const LayerSection = (props) => { + const { act, data } = useBackend(); + const { category: rootCategoryIndex, piping_layer, pipe_layers } = data; + const previews = data.preview_rows.flatMap((row) => row.previews); + return ( + + {rootCategoryIndex === 0 && ( + + {Object.keys(pipe_layers).map((layer) => ( + + + act('piping_layer', { + piping_layer: pipe_layers[layer], + }) + } + > + {layer} + + + ))} + + )} + + {previews.map((preview) => ( + + act('setdir', { + dir: preview.dir, + flipped: preview.flipped, + }) + } + > + + + ))} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RapidPipeDispenser/PipeTypeSection.tsx b/tgui/packages/tgui/interfaces/RapidPipeDispenser/PipeTypeSection.tsx new file mode 100644 index 00000000000..c55ff8e0fcf --- /dev/null +++ b/tgui/packages/tgui/interfaces/RapidPipeDispenser/PipeTypeSection.tsx @@ -0,0 +1,48 @@ +import { useState } from 'react'; + +import { useBackend } from '../../backend'; +import { Button, Section, Tabs } from '../../components'; +import { ICON_BY_CATEGORY_NAME } from './constants'; +import { Data } from './types'; + +export const PipeTypeSection = (props) => { + const { act, data } = useBackend(); + const { categories = [] } = data; + const [categoryName, setCategoryName] = useState('categoryName'); + const shownCategory = + categories.find((category) => category.cat_name === categoryName) || + categories[0]; + return ( + + + {categories.map((category, i) => ( + setCategoryName(category.cat_name)} + > + {category.cat_name} + + ))} + + {shownCategory?.recipes.map((recipe) => ( + + act('pipe_type', { + pipe_type: recipe.pipe_index, + category: shownCategory.cat_name, + }) + } + > + {recipe.pipe_name} + + ))} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RapidPipeDispenser/SelectionSection.tsx b/tgui/packages/tgui/interfaces/RapidPipeDispenser/SelectionSection.tsx new file mode 100644 index 00000000000..c9962695404 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RapidPipeDispenser/SelectionSection.tsx @@ -0,0 +1,78 @@ +import { capitalize } from 'common/string'; + +import { useBackend } from '../../backend'; +import { + Box, + Button, + ColorBox, + LabeledList, + Section, + Stack, +} from '../../components'; +import { ICON_BY_CATEGORY_NAME, ROOT_CATEGORIES, TOOLS } from './constants'; +import { Data } from './types'; + +export const SelectionSection = (props) => { + const { act, data } = useBackend(); + const { + category: rootCategoryIndex, + selected_color, + mode, + paint_colors, + } = data; + return ( + + + + {ROOT_CATEGORIES.map((categoryName, i) => ( + act('category', { category: i })} + > + {categoryName} + + ))} + + + + {TOOLS.map((tool) => ( + + + act('mode', { + mode: tool.bitmask, + }) + } + > + {tool.name} + + + ))} + + + + + {capitalize(selected_color)} + + {Object.keys(paint_colors).map((colorName) => ( + + act('color', { + paint_color: colorName, + }) + } + /> + ))} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RapidPipeDispenser/constants.ts b/tgui/packages/tgui/interfaces/RapidPipeDispenser/constants.ts new file mode 100644 index 00000000000..f4cad4b32a4 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RapidPipeDispenser/constants.ts @@ -0,0 +1,36 @@ +export const ROOT_CATEGORIES: string[] = [ + 'Atmospherics', + 'Disposals', + // 'Transit Tubes', +]; + +export const ICON_BY_CATEGORY_NAME = { + Atmospherics: 'wrench', + Disposals: 'trash-alt', + 'Transit Tubes': 'bus', + Pipes: 'grip-lines', + 'Disposal Pipes': 'grip-lines', + Devices: 'microchip', + 'Heat Exchange': 'thermometer-half', + 'Insulated pipes': 'snowflake', + 'Station Equipment': 'microchip', +}; + +export const TOOLS = [ + { + name: 'Dispense', + bitmask: 1, + }, + { + name: 'Connect', + bitmask: 2, + }, + { + name: 'Destroy', + bitmask: 4, + }, + { + name: 'Paint', + bitmask: 8, + }, +]; diff --git a/tgui/packages/tgui/interfaces/RapidPipeDispenser/index.tsx b/tgui/packages/tgui/interfaces/RapidPipeDispenser/index.tsx new file mode 100644 index 00000000000..f8783ba0705 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RapidPipeDispenser/index.tsx @@ -0,0 +1,33 @@ +import { Stack } from '../../components'; +import { Window } from '../../layouts'; +import { LayerSection } from './LayerSection'; +import { PipeTypeSection } from './PipeTypeSection'; +import { SelectionSection } from './SelectionSection'; + +export const RapidPipeDispenser = (props) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RapidPipeDispenser/types.ts b/tgui/packages/tgui/interfaces/RapidPipeDispenser/types.ts new file mode 100644 index 00000000000..7bcab750c07 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RapidPipeDispenser/types.ts @@ -0,0 +1,28 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + category: number; + piping_layer: number; + pipe_layers: { + Regular: number; + Supply: number; + Scrubber: number; + Fuel: number; + Aux: number; + }; + preview_rows: { + previews: { + selected: BooleanLike; + dir: string; + dir_name: string; + icon_state: string; + flipped: BooleanLike; + }; + }[]; + categories: { cat_name: string; recipes: recipe[] }[]; + selected_color: string; + paint_colors: Record; + mode: number; +}; + +type recipe = { pipe_name: string; pipe_index: number; selected: BooleanLike }; diff --git a/tgui/packages/tgui/interfaces/RequestConsole.jsx b/tgui/packages/tgui/interfaces/RequestConsole.jsx deleted file mode 100644 index 43e2f56eb10..00000000000 --- a/tgui/packages/tgui/interfaces/RequestConsole.jsx +++ /dev/null @@ -1,354 +0,0 @@ -import { decodeHtmlEntities } from 'common/string'; - -import { useBackend } from '../backend'; -import { Box, Button, LabeledList, Section, Tabs } from '../components'; -import { Window } from '../layouts'; - -const RCS_MAINMENU = 0; // Settings menu -const RCS_RQASSIST = 1; // Request supplies -const RCS_RQSUPPLY = 2; // Request assistance -const RCS_SENDINFO = 3; // Relay information -const RCS_SENTPASS = 4; // Message sent successfully -const RCS_SENTFAIL = 5; // Message sent unsuccessfully -const RCS_VIEWMSGS = 6; // View messages -const RCS_MESSAUTH = 7; // Authentication before sending -const RCS_ANNOUNCE = 8; // Send announcement - -const RequestConsoleSettings = (props) => { - const { act, data } = useBackend(); - const { silent } = data; - return ( - - act('toggleSilent')} - > - Speaker {silent ? 'OFF' : 'ON'} - - - ); -}; - -const RequestConsoleSupplies = (props) => { - const { act, data } = useBackend(); - const { department, supply_dept } = data; - return ( - - - - ); -}; - -const RequestConsoleAssistance = (props) => { - const { act, data } = useBackend(); - const { department, assist_dept } = data; - return ( - - - - ); -}; - -const RequestConsoleRelay = (props) => { - const { act, data } = useBackend(); - const { department, info_dept } = data; - return ( - - - - ); -}; - -const RequestConsoleSendMenu = (props) => { - const { act } = useBackend(); - const { dept_list, department } = props; - return ( - - {dept_list.sort().map( - (dept) => - (dept !== department && ( - - act('write', { write: dept, priority: 1 })} - > - Message - - act('write', { write: dept, priority: 2 })} - > - High Priority - - > - } - /> - )) || - null, - )} - - ); -}; - -const RequestConsoleSendPass = (props) => { - const { act, data } = useBackend(); - return ( - - - Message Sent Successfully - - - act('setScreen', { setScreen: RCS_MAINMENU })} - > - Continue - - - - ); -}; - -const RequestConsoleSendFail = (props) => { - const { act, data } = useBackend(); - return ( - - - An error occured. Message Not Sent. - - - act('setScreen', { setScreen: RCS_MAINMENU })} - > - Continue - - - - ); -}; - -const RequestConsoleViewMessages = (props) => { - const { act, data } = useBackend(); - const { message_log } = data; - return ( - - {(message_log.length && - message_log.map((msg, i) => ( - act('print', { print: i + 1 })} - > - Print - - } - > - {decodeHtmlEntities(msg[1])} - - ))) || No messages.} - - ); -}; - -const RequestConsoleMessageAuth = (props) => { - const { act, data } = useBackend(); - const { message, recipient, priority, msgStamped, msgVerified } = data; - return ( - - - - {message} - - - {priority === 2 - ? 'High Priority' - : priority === 1 - ? 'Normal Priority' - : 'Unknown'} - - - {decodeHtmlEntities(msgVerified) || 'No Validation'} - - - {decodeHtmlEntities(msgStamped) || 'No Stamp'} - - - act('department', { department: recipient })} - > - Send Message - - act('setScreen', { setScreen: RCS_MAINMENU })} - > - Back - - - ); -}; - -const RequestConsoleAnnounce = (props) => { - const { act, data } = useBackend(); - const { - department, - screen, - message_log, - newmessagepriority, - silent, - announcementConsole, - assist_dept, - supply_dept, - info_dept, - message, - recipient, - priority, - msgStamped, - msgVerified, - announceAuth, - } = data; - return ( - - {(announceAuth && ( - <> - - ID Verified. Authentication Accepted. - - act('writeAnnouncement')} - > - Edit - - } - > - {message || 'No Message'} - - > - )) || ( - - Swipe your ID card to authenticate yourself. - - )} - act('sendAnnouncement')} - > - Announce - - act('setScreen', { setScreen: RCS_MAINMENU })} - > - Back - - - ); -}; - -let screenToTemplate = {}; -screenToTemplate[RCS_MAINMENU] = RequestConsoleSettings; -screenToTemplate[RCS_RQASSIST] = RequestConsoleAssistance; -screenToTemplate[RCS_RQSUPPLY] = RequestConsoleSupplies; -screenToTemplate[RCS_SENDINFO] = RequestConsoleRelay; -screenToTemplate[RCS_SENTPASS] = RequestConsoleSendPass; -screenToTemplate[RCS_SENTFAIL] = RequestConsoleSendFail; -screenToTemplate[RCS_VIEWMSGS] = RequestConsoleViewMessages; -screenToTemplate[RCS_MESSAUTH] = RequestConsoleMessageAuth; -screenToTemplate[RCS_ANNOUNCE] = RequestConsoleAnnounce; - -export const RequestConsole = (props) => { - const { act, data } = useBackend(); - const { screen, newmessagepriority, announcementConsole } = data; - - let BodyElement = screenToTemplate[screen]; - - return ( - - - - act('setScreen', { setScreen: RCS_VIEWMSGS })} - icon="envelope-open-text" - > - Messages - - act('setScreen', { setScreen: RCS_RQASSIST })} - icon="share-square" - > - Assistance - - act('setScreen', { setScreen: RCS_RQSUPPLY })} - icon="share-square" - > - Supplies - - act('setScreen', { setScreen: RCS_SENDINFO })} - icon="share-square-o" - > - Report - - {(announcementConsole && ( - act('setScreen', { setScreen: RCS_ANNOUNCE })} - icon="volume-up" - > - Announce - - )) || - null} - act('setScreen', { setScreen: RCS_MAINMENU })} - icon="cog" - /> - - {(newmessagepriority && ( - 1 - ? 'NEW PRIORITY MESSAGES' - : 'There are new messages!' - } - color={newmessagepriority > 1 ? 'bad' : 'average'} - bold={newmessagepriority > 1} - /> - )) || - null} - - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/RequestConsole/RequestConsolTypes.tsx b/tgui/packages/tgui/interfaces/RequestConsole/RequestConsolTypes.tsx new file mode 100644 index 00000000000..671f275a2f1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RequestConsole/RequestConsolTypes.tsx @@ -0,0 +1,34 @@ +import { useBackend } from '../../backend'; +import { Section } from '../../components'; +import { RequestConsoleSendMenu } from './RequestConsoleSend'; +import { Data } from './types'; + +export const RequestConsoleSupplies = (props) => { + const { data } = useBackend(); + const { department, supply_dept } = data; + return ( + + + + ); +}; + +export const RequestConsoleAssistance = (props) => { + const { data } = useBackend(); + const { department, assist_dept } = data; + return ( + + + + ); +}; + +export const RequestConsoleRelay = (props) => { + const { data } = useBackend(); + const { department, info_dept } = data; + return ( + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RequestConsole/RequestConsoleMessage.tsx b/tgui/packages/tgui/interfaces/RequestConsole/RequestConsoleMessage.tsx new file mode 100644 index 00000000000..29321d06098 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RequestConsole/RequestConsoleMessage.tsx @@ -0,0 +1,128 @@ +import { decodeHtmlEntities } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Box, Button, LabeledList, Section } from '../../components'; +import { RCS_MAINMENU } from './constants'; +import { Data } from './types'; + +export const RequestConsoleViewMessages = (props) => { + const { act, data } = useBackend(); + const { message_log } = data; + return ( + + {(message_log.length && + message_log.map((msg, i) => ( + act('print', { print: i + 1 })} + > + Print + + } + > + {decodeHtmlEntities(msg[1])} + + ))) || No messages.} + + ); +}; + +export const RequestConsoleMessageAuth = (props) => { + const { act, data } = useBackend(); + const { message, recipient, priority, msgStamped, msgVerified } = data; + return ( + + + + {message} + + + {priority === 2 + ? 'High Priority' + : priority === 1 + ? 'Normal Priority' + : 'Unknown'} + + + {decodeHtmlEntities(msgVerified) || 'No Validation'} + + + {decodeHtmlEntities(msgStamped) || 'No Stamp'} + + + act('department', { department: recipient })} + > + Send Message + + act('setScreen', { setScreen: RCS_MAINMENU })} + > + Back + + + ); +}; + +export const RequestConsoleAnnounce = (props) => { + const { act, data } = useBackend(); + const { message, announceAuth } = data; + return ( + + {(announceAuth && ( + <> + + ID Verified. Authentication Accepted. + + act('writeAnnouncement')} + > + Edit + + } + > + {message || 'No Message'} + + > + )) || ( + + Swipe your ID card to authenticate yourself. + + )} + act('sendAnnouncement')} + > + Announce + + act('setScreen', { setScreen: RCS_MAINMENU })} + > + Back + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RequestConsole/RequestConsoleSend.tsx b/tgui/packages/tgui/interfaces/RequestConsole/RequestConsoleSend.tsx new file mode 100644 index 00000000000..1f40cfd6dc3 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RequestConsole/RequestConsoleSend.tsx @@ -0,0 +1,78 @@ +import { useBackend } from '../../backend'; +import { Box, Button, LabeledList, Section } from '../../components'; +import { RCS_MAINMENU } from './constants'; + +export const RequestConsoleSendMenu = (props: { + dept_list: string[]; + department: string; +}) => { + const { act } = useBackend(); + const { dept_list, department } = props; + return ( + + {dept_list.sort().map( + (dept) => + (dept !== department && ( + + act('write', { write: dept, priority: 1 })} + > + Message + + act('write', { write: dept, priority: 2 })} + > + High Priority + + > + } + /> + )) || + null, + )} + + ); +}; + +export const RequestConsoleSendPass = (props) => { + const { act, data } = useBackend(); + return ( + + + Message Sent Successfully + + + act('setScreen', { setScreen: RCS_MAINMENU })} + > + Continue + + + + ); +}; + +export const RequestConsoleSendFail = (props) => { + const { act, data } = useBackend(); + return ( + + + An error occured. Message Not Sent. + + + act('setScreen', { setScreen: RCS_MAINMENU })} + > + Continue + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RequestConsole/RequestConsoleSettings.tsx b/tgui/packages/tgui/interfaces/RequestConsole/RequestConsoleSettings.tsx new file mode 100644 index 00000000000..0246736d36f --- /dev/null +++ b/tgui/packages/tgui/interfaces/RequestConsole/RequestConsoleSettings.tsx @@ -0,0 +1,19 @@ +import { useBackend } from '../../backend'; +import { Button, Section } from '../../components'; +import { Data } from './types'; + +export const RequestConsoleSettings = (props) => { + const { act, data } = useBackend(); + const { silent } = data; + return ( + + act('toggleSilent')} + > + Speaker {silent ? 'OFF' : 'ON'} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RequestConsole/constants.ts b/tgui/packages/tgui/interfaces/RequestConsole/constants.ts new file mode 100644 index 00000000000..e2d6917075c --- /dev/null +++ b/tgui/packages/tgui/interfaces/RequestConsole/constants.ts @@ -0,0 +1,9 @@ +export const RCS_MAINMENU = 0; // Settings menu +export const RCS_RQASSIST = 1; // Request supplies +export const RCS_RQSUPPLY = 2; // Request assistance +export const RCS_SENDINFO = 3; // Relay information +export const RCS_SENTPASS = 4; // Message sent successfully +export const RCS_SENTFAIL = 5; // Message sent unsuccessfully +export const RCS_VIEWMSGS = 6; // View messages +export const RCS_MESSAUTH = 7; // Authentication before sending +export const RCS_ANNOUNCE = 8; // Send announcement diff --git a/tgui/packages/tgui/interfaces/RequestConsole/index.tsx b/tgui/packages/tgui/interfaces/RequestConsole/index.tsx new file mode 100644 index 00000000000..822d8f12ff9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RequestConsole/index.tsx @@ -0,0 +1,112 @@ +import { useBackend } from '../../backend'; +import { Section, Tabs } from '../../components'; +import { Window } from '../../layouts'; +import { + RCS_ANNOUNCE, + RCS_MAINMENU, + RCS_MESSAUTH, + RCS_RQASSIST, + RCS_RQSUPPLY, + RCS_SENDINFO, + RCS_SENTFAIL, + RCS_SENTPASS, + RCS_VIEWMSGS, +} from './constants'; +import { + RequestConsoleAnnounce, + RequestConsoleMessageAuth, + RequestConsoleViewMessages, +} from './RequestConsoleMessage'; +import { + RequestConsoleSendFail, + RequestConsoleSendPass, +} from './RequestConsoleSend'; +import { RequestConsoleSettings } from './RequestConsoleSettings'; +import { + RequestConsoleAssistance, + RequestConsoleRelay, + RequestConsoleSupplies, +} from './RequestConsolTypes'; +import { Data } from './types'; + +export const RequestConsole = (props) => { + const { act, data } = useBackend(); + const { screen, newmessagepriority, announcementConsole } = data; + + const body: React.JSX.Element[] = []; + + body[RCS_MAINMENU] = ; + body[RCS_RQASSIST] = ; + body[RCS_RQSUPPLY] = ; + body[RCS_SENDINFO] = ; + body[RCS_SENTPASS] = ; + body[RCS_SENTFAIL] = ; + body[RCS_VIEWMSGS] = ; + body[RCS_MESSAUTH] = ; + body[RCS_ANNOUNCE] = ; + + return ( + + + + act('setScreen', { setScreen: RCS_VIEWMSGS })} + icon="envelope-open-text" + > + Messages + + act('setScreen', { setScreen: RCS_RQASSIST })} + icon="share-square" + > + Assistance + + act('setScreen', { setScreen: RCS_RQSUPPLY })} + icon="share-square" + > + Supplies + + act('setScreen', { setScreen: RCS_SENDINFO })} + icon="share-square-o" + > + Report + + {(announcementConsole && ( + act('setScreen', { setScreen: RCS_ANNOUNCE })} + icon="volume-up" + > + Announce + + )) || + null} + act('setScreen', { setScreen: RCS_MAINMENU })} + icon="cog" + /> + + {(newmessagepriority && ( + 1 + ? 'NEW PRIORITY MESSAGES' + : 'There are new messages!' + } + color={newmessagepriority > 1 ? 'bad' : 'average'} + bold={newmessagepriority > 1} + /> + )) || + null} + {body[screen] || ''} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RequestConsole/types.ts b/tgui/packages/tgui/interfaces/RequestConsole/types.ts new file mode 100644 index 00000000000..d61cabc091e --- /dev/null +++ b/tgui/packages/tgui/interfaces/RequestConsole/types.ts @@ -0,0 +1,19 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + department: string; + screen: number; + message_log: string[][]; + newmessagepriority: number; + silent: BooleanLike; + announcementConsole: BooleanLike; + assist_dept: string[]; + supply_dept: string[]; + info_dept: string[]; + message: string; + recipient: string; + priority: number; + msgStamped: string; + msgVerified: string; + announceAuth: BooleanLike; +}; diff --git a/tgui/packages/tgui/interfaces/ResearchServerController.jsx b/tgui/packages/tgui/interfaces/ResearchServerController.tsx similarity index 71% rename from tgui/packages/tgui/interfaces/ResearchServerController.jsx rename to tgui/packages/tgui/interfaces/ResearchServerController.tsx index e38d3906caf..d685ab2f5fb 100644 --- a/tgui/packages/tgui/interfaces/ResearchServerController.jsx +++ b/tgui/packages/tgui/interfaces/ResearchServerController.tsx @@ -1,11 +1,27 @@ import { filter } from 'common/collections'; +import { BooleanLike } from 'common/react'; import { useBackend, useSharedState } from '../backend'; import { Box, Button, LabeledList, Section, Tabs } from '../components'; import { Window } from '../layouts'; +type Data = { badmin: BooleanLike; servers: server[]; consoles: console[] }; + +type server = { + name: string; + ref: string; + id: number; + id_with_upload: string[]; + id_with_download: string[]; + tech: techDes[]; + designs: techDes[]; +}; + +type techDes = { name: string; id: string }; + +type console = { name: string; ref: string; loc: string; id: number }; + export const ResearchServerController = (props) => { - const { act, data } = useBackend(); return ( @@ -16,11 +32,11 @@ export const ResearchServerController = (props) => { }; const ResearchControllerContent = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); - const { badmin, servers, consoles } = data; + const { servers } = data; - const [selectedServer, setSelectedServer] = useSharedState( + const [selectedServer, setSelectedServer] = useSharedState( 'selectedServer', null, ); @@ -31,7 +47,7 @@ const ResearchControllerContent = (props) => { return ( ); } @@ -49,12 +65,15 @@ const ResearchControllerContent = (props) => { ); }; -const ResearchServer = (props) => { - const { act, data } = useBackend(); +const ResearchServer = (props: { + server: server; + setSelectedServer: Function; +}) => { + const { data } = useBackend(); const { badmin } = data; const { server, setSelectedServer } = props; - const [tab, setTab] = useSharedState('tab', 0); + const [tab, setTab] = useSharedState('tab', 0); return ( { ); }; -const ResearchServerAccess = (props) => { - const { act, data } = useBackend(); +const ResearchServerAccess = (props: { server: server }) => { + const { act, data } = useBackend(); const { server } = props; const { consoles } = data; @@ -108,7 +127,7 @@ const ResearchServerAccess = (props) => { }; return ( - + {consoles.length && consoles.map((console) => ( @@ -149,13 +168,13 @@ const ResearchServerAccess = (props) => { ); }; -const ResearchServerData = (props) => { - const { act, data } = useBackend(); +const ResearchServerData = (props: { server: server }) => { + const { act } = useBackend(); const { server } = props; return ( <> - + {server.tech.map((tech) => ( { /> ))} - - {filter((design) => !!design.name)(server.designs).map((design) => ( - - act('reset_design', { server: server.ref, design: design.id }) - } - > - Delete - - } - /> - ))} + + {filter((design: techDes) => !!design.name)(server.designs).map( + (design) => ( + + act('reset_design', { + server: server.ref, + design: design.id, + }) + } + > + Delete + + } + /> + ), + )} > ); }; -const ResearchServerTransfer = (props) => { - const { act, data } = useBackend(); +const ResearchServerTransfer = (props: { server: server }) => { + const { act, data } = useBackend(); const { server } = props; @@ -211,7 +235,7 @@ const ResearchServerTransfer = (props) => { } return ( - + {servers.map((newserver) => ( { - const { act, data } = useBackend(); - const { - activerecord, - realname, - obviously_dead, - oocnotes, - can_sleeve_active, - } = modal.args; - return ( - act('modal_close')} /> - } - > - - {realname} - {obviously_dead} - - - act('sleeve', { - ref: activerecord, - mode: 1, - }) - } - > - Sleeve - - - act('sleeve', { - ref: activerecord, - mode: 2, - }) - } - > - Card - - - - - {oocnotes} - - - - - ); -}; - -const viewBodyRecordModalBodyOverride = (modal) => { - const { act, data } = useBackend(); - const { - activerecord, - realname, - species, - sex, - mind_compat, - synthetic, - oocnotes, - can_grow_active, - } = modal.args; - return ( - act('modal_close')} /> - } - > - - {realname} - {species} - {sex} - {mind_compat} - - {synthetic ? 'Yes' : 'No'} - - - - {oocnotes} - - - - - act('create', { - ref: activerecord, - }) - } - > - {synthetic ? 'Build' : 'Grow'} - - - - - ); -}; - -export const ResleevingConsole = (props) => { - const { act, data } = useBackend(); - const { menu, coredumped, emergency } = data; - let body = ( - <> - - - - - - - > - ); - if (coredumped) { - body = ; - } - if (emergency) { - body = ; - } - modalRegisterBodyOverride('view_b_rec', viewBodyRecordModalBodyOverride); - modalRegisterBodyOverride('view_m_rec', viewMindRecordModalBodyOverride); - return ( - - - - {body} - - - ); -}; - -const ResleevingConsoleNavigation = (props) => { - const { act, data } = useBackend(); - const { menu } = data; - return ( - - - act('menu', { - num: MENU_MAIN, - }) - } - > - Main - - - act('menu', { - num: MENU_BODY, - }) - } - > - Body Records - - - act('menu', { - num: MENU_MIND, - }) - } - > - Mind Records - - - ); -}; - -const ResleevingConsoleBody = (props) => { - const { data } = useBackend(); - const { menu, bodyrecords, mindrecords } = data; - let body; - if (menu === MENU_MAIN) { - body = ; - } else if (menu === MENU_BODY) { - body = ( - - ); - } else if (menu === MENU_MIND) { - body = ( - - ); - } - return body; -}; - -const ResleevingConsoleCoreDump = (props) => { - return ( - - - - - - - TransCore dump completed. Resleeving offline. - - - - ); -}; - -const ResleevingConsoleDiskPrep = (props) => { - const { act } = useBackend(); - return ( - - - TRANSCORE DUMP - - - !!WARNING!! - - - This will transfer all minds to the dump disk, and the TransCore will be - made unusable until post-shift maintenance! This should only be used in - emergencies! - - - act('ejectdisk')}> - Eject Disk - - - - act('coredump')} - > - Core Dump - - - - ); -}; - -const ResleevingConsoleMain = (props) => { - const { act, data } = useBackend(); - const { - loading, - scantemp, - occupant, - locked, - can_brainscan, - scan_mode, - pods, - selected_pod, - } = data; - const isLocked = locked && !!occupant; - return ( - - - - - - ); -}; - -const ResleevingConsolePodGrowers = (props) => { - const { act, data } = useBackend(); - const { pods, spods, selected_pod } = data; - - if (pods && pods.length) { - return pods.map((pod, i) => { - let podAction; - if (pod.status === 'cloning') { - podAction = ( - - {toFixed(pod.progress) + '%'} - - ); - } else if (pod.status === 'mess') { - podAction = ( - - ERROR - - ); - } else { - podAction = ( - - act('selectpod', { - ref: pod.pod, - }) - } - > - Select - - ); - } - - return ( - - - {pod.name} - = 150 ? 'good' : 'bad'} inline> - = 150 ? 'circle' : 'circle-o'} /> - - {pod.biomass} - - {podAction} - - ); - }); - } - - return null; -}; - -const ResleevingConsolePodSleevers = (props) => { - const { act, data } = useBackend(); - const { sleevers, spods, selected_sleever } = data; - - if (sleevers && sleevers.length) { - return sleevers.map((pod, i) => { - return ( - - - {pod.name} - - act('selectsleever', { - ref: pod.sleever, - }) - } - > - Select - - - ); - }); - } - - return null; -}; - -const ResleevingConsolePodSpods = (props) => { - const { act, data } = useBackend(); - const { spods, selected_printer } = data; - - if (spods && spods.length) { - return spods.map((pod, i) => { - let podAction; - if (pod.status === 'cloning') { - podAction = ( - - {toFixed(pod.progress) + '%'} - - ); - } else if (pod.status === 'mess') { - podAction = ( - - ERROR - - ); - } else { - podAction = ( - - act('selectprinter', { - ref: pod.spod, - }) - } - > - Select - - ); - } - - return ( - - - {pod.name} - = 15000 ? 'good' : 'bad'} inline> - = 15000 ? 'circle' : 'circle-o'} /> - - {pod.steel} - - = 15000 ? 'good' : 'bad'} inline> - = 15000 ? 'circle' : 'circle-o'} /> - - {pod.glass} - - {podAction} - - ); - }); - } - - return null; -}; - -const ResleevingConsoleRecords = (props) => { - const { act } = useBackend(); - const { records, actToDo } = props; - if (!records.length) { - return ( - - - - - No records found. - - - ); - } - return ( - - {records.map((record, i) => ( - - act(actToDo, { - ref: record.recref, - }) - } - > - {record.name} - - ))} - - ); -}; - -const ResleevingConsoleTemp = (props) => { - const { act, data } = useBackend(); - const { temp } = data; - if (!temp || !temp.text || temp.text.length <= 0) { - return; - } - - const tempProp = { [temp.style]: true }; - return ( - - - {temp.text} - - act('cleartemp')} - /> - - - ); -}; - -const ResleevingConsoleStatus = (props) => { - const { act, data } = useBackend(); - const { pods, spods, sleevers, autoallowed, autoprocess, disk } = data; - return ( - - - - {pods && pods.length ? ( - {pods.length} connected - ) : ( - None connected! - )} - - - {spods && spods.length ? ( - {spods.length} connected - ) : ( - None connected! - )} - - - {sleevers && sleevers.length ? ( - {sleevers.length} Connected - ) : ( - None connected! - )} - - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsoleElements.tsx b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsoleElements.tsx new file mode 100644 index 00000000000..1eb7e8d069e --- /dev/null +++ b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsoleElements.tsx @@ -0,0 +1,105 @@ +import { useBackend } from '../../backend'; +import { Box, Button, NoticeBox, Section, Tabs } from '../../components'; +import { MENU_BODY, MENU_MAIN, MENU_MIND } from './constants'; +import { ResleevingConsolePodGrowers } from './ResleevingConsolePodGrowers'; +import { ResleevingConsolePodSleevers } from './ResleevingConsolePodSleevers'; +import { ResleevingConsolePodSpods } from './ResleevingConsolePodSpods'; +import { ResleevingConsoleRecords } from './ResleevingConsoleRecords'; +import { Data } from './types'; + +export const ResleevingConsoleBody = (props) => { + const { data } = useBackend(); + const { menu, bodyrecords, mindrecords } = data; + + const body: React.JSX.Element[] = []; + + body[MENU_MAIN] = ; + body[MENU_BODY] = ( + + ); + body[MENU_MIND] = ( + + ); + return body[menu]; +}; + +const ResleevingConsoleMain = (props) => { + return ( + + + + + + ); +}; + +export const ResleevingConsoleNavigation = (props) => { + const { act, data } = useBackend(); + const { menu } = data; + return ( + + + act('menu', { + num: MENU_MAIN, + }) + } + > + Main + + + act('menu', { + num: MENU_BODY, + }) + } + > + Body Records + + + act('menu', { + num: MENU_MIND, + }) + } + > + Mind Records + + + ); +}; + +export const ResleevingConsoleTemp = (props) => { + const { act, data } = useBackend(); + const { temp } = data; + if (!temp || !temp.text || temp.text.length <= 0) { + return; + } + + const tempProp = { [temp.style]: true }; + return ( + + + {temp.text} + + act('cleartemp')} + /> + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsolePodGrowers.tsx b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsolePodGrowers.tsx new file mode 100644 index 00000000000..2bd4bd8d5bd --- /dev/null +++ b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsolePodGrowers.tsx @@ -0,0 +1,75 @@ +import { toFixed } from 'common/math'; + +import { resolveAsset } from '../../assets'; +import { useBackend } from '../../backend'; +import { Box, Button, Icon, Image, ProgressBar } from '../../components'; +import { Data } from './types'; + +export const ResleevingConsolePodGrowers = (props) => { + const { act, data } = useBackend(); + const { pods, spods, selected_pod } = data; + + if (pods && pods.length) { + return pods.map((pod, i) => { + let podAction; + if (pod.status === 'cloning') { + podAction = ( + + {toFixed(pod.progress) + '%'} + + ); + } else if (pod.status === 'mess') { + podAction = ( + + ERROR + + ); + } else { + podAction = ( + + act('selectpod', { + ref: pod.pod, + }) + } + > + Select + + ); + } + + return ( + + + {pod.name} + = 150 ? 'good' : 'bad'} inline> + = 150 ? 'circle' : 'circle-o'} /> + + {pod.biomass} + + {podAction} + + ); + }); + } + + return ''; +}; diff --git a/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsolePodSleevers.tsx b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsolePodSleevers.tsx new file mode 100644 index 00000000000..34a9976ebb5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsolePodSleevers.tsx @@ -0,0 +1,41 @@ +import { resolveAsset } from '../../assets'; +import { useBackend } from '../../backend'; +import { Box, Button, Image } from '../../components'; +import { Data } from './types'; + +export const ResleevingConsolePodSleevers = (props) => { + const { act, data } = useBackend(); + const { sleevers, spods, selected_sleever } = data; + + if (sleevers && sleevers.length) { + return sleevers.map((pod, i) => { + return ( + + + {pod.name} + + act('selectsleever', { + ref: pod.sleever, + }) + } + > + Select + + + ); + }); + } + + return ''; +}; diff --git a/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsolePodSpods.tsx b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsolePodSpods.tsx new file mode 100644 index 00000000000..87fde7a5d59 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsolePodSpods.tsx @@ -0,0 +1,82 @@ +import { toFixed } from 'common/math'; + +import { resolveAsset } from '../../assets'; +import { useBackend } from '../../backend'; +import { Box, Button, Icon, Image, ProgressBar } from '../../components'; +import { Data } from './types'; + +export const ResleevingConsolePodSpods = (props) => { + const { act, data } = useBackend(); + const { spods, selected_printer } = data; + + if (spods && spods.length) { + return spods.map((pod, i) => { + let podAction: React.JSX.Element; + if (pod.status === 'cloning') { + podAction = ( + + {toFixed(pod.progress) + '%'} + + ); + } else if (pod.status === 'mess') { + podAction = ( + + ERROR + + ); + } else { + podAction = ( + + act('selectprinter', { + ref: pod.spod, + }) + } + > + Select + + ); + } + + return ( + + + {pod.name} + = 15000 ? 'good' : 'bad'} inline> + = 15000 ? 'circle' : 'circle-o'} /> + + {pod.steel} + + = 15000 ? 'good' : 'bad'} inline> + = 15000 ? 'circle' : 'circle-o'} /> + + {pod.glass} + + {podAction} + + ); + }); + } + + return ''; +}; diff --git a/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsoleRecords.tsx b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsoleRecords.tsx new file mode 100644 index 00000000000..58153d9917b --- /dev/null +++ b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsoleRecords.tsx @@ -0,0 +1,40 @@ +import { useBackend } from '../../backend'; +import { Box, Button, Flex, Icon } from '../../components'; +import { record } from './types'; + +export const ResleevingConsoleRecords = (props: { + records: record[]; + actToDo: string; +}) => { + const { act } = useBackend(); + const { records, actToDo } = props; + if (!records.length) { + return ( + + + + + No records found. + + + ); + } + return ( + + {records.map((record, i) => ( + + act(actToDo, { + ref: record.recref, + }) + } + > + {record.name} + + ))} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsoleStatus.tsx b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsoleStatus.tsx new file mode 100644 index 00000000000..ac7ff47a523 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsoleStatus.tsx @@ -0,0 +1,35 @@ +import { useBackend } from '../../backend'; +import { Box, LabeledList, Section } from '../../components'; +import { Data } from './types'; + +export const ResleevingConsoleStatus = (props) => { + const { data } = useBackend(); + const { pods, spods, sleevers } = data; + return ( + + + + {pods && pods.length ? ( + {pods.length} connected + ) : ( + None connected! + )} + + + {spods && spods.length ? ( + {spods.length} connected + ) : ( + None connected! + )} + + + {sleevers && sleevers.length ? ( + {sleevers.length} Connected + ) : ( + None connected! + )} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsoleTexts.tsx b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsoleTexts.tsx new file mode 100644 index 00000000000..f350fc85325 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ResleevingConsole/ResleevingConsoleTexts.tsx @@ -0,0 +1,52 @@ +import { useBackend } from '../../backend'; +import { Box, Button, Dimmer, Flex, Icon } from '../../components'; + +export const ResleevingConsoleCoreDump = (props) => { + return ( + + + + + + + TransCore dump completed. Resleeving offline. + + + + ); +}; + +export const ResleevingConsoleDiskPrep = (props) => { + const { act } = useBackend(); + return ( + + + TRANSCORE DUMP + + + !!WARNING!! + + + This will transfer all minds to the dump disk, and the TransCore will be + made unusable until post-shift maintenance! This should only be used in + emergencies! + + + act('ejectdisk')}> + Eject Disk + + + + act('coredump')} + > + Core Dump + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ResleevingConsole/constants.ts b/tgui/packages/tgui/interfaces/ResleevingConsole/constants.ts new file mode 100644 index 00000000000..e0461d4bb7c --- /dev/null +++ b/tgui/packages/tgui/interfaces/ResleevingConsole/constants.ts @@ -0,0 +1,3 @@ +export const MENU_MAIN = 1; +export const MENU_BODY = 2; +export const MENU_MIND = 3; diff --git a/tgui/packages/tgui/interfaces/ResleevingConsole/index.tsx b/tgui/packages/tgui/interfaces/ResleevingConsole/index.tsx new file mode 100644 index 00000000000..286582fc59e --- /dev/null +++ b/tgui/packages/tgui/interfaces/ResleevingConsole/index.tsx @@ -0,0 +1,51 @@ +import { useBackend } from '../../backend'; +import { Section } from '../../components'; +import { + ComplexModal, + modalRegisterBodyOverride, +} from '../../interfaces/common/ComplexModal'; +import { Window } from '../../layouts'; +import { + ResleevingConsoleBody, + ResleevingConsoleNavigation, + ResleevingConsoleTemp, +} from './ResleevingConsoleElements'; +import { ResleevingConsoleStatus } from './ResleevingConsoleStatus'; +import { + ResleevingConsoleCoreDump, + ResleevingConsoleDiskPrep, +} from './ResleevingConsoleTexts'; +import { Data } from './types'; +import { viewBodyRecordModalBodyOverride } from './viewBodyRecordModalBodyOverride'; +import { viewMindRecordModalBodyOverride } from './viewMindRecordModalBodyOverride'; + +export const ResleevingConsole = (props) => { + const { data } = useBackend(); + const { coredumped, emergency } = data; + let body: React.JSX.Element = ( + <> + + + + + + + > + ); + if (coredumped) { + body = ; + } + if (emergency) { + body = ; + } + modalRegisterBodyOverride('view_b_rec', viewBodyRecordModalBodyOverride); + modalRegisterBodyOverride('view_m_rec', viewMindRecordModalBodyOverride); + return ( + + + + {body} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ResleevingConsole/types.ts b/tgui/packages/tgui/interfaces/ResleevingConsole/types.ts new file mode 100644 index 00000000000..8802231afbc --- /dev/null +++ b/tgui/packages/tgui/interfaces/ResleevingConsole/types.ts @@ -0,0 +1,69 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + menu: number; + pods: pod[]; + spods: Required< + pod & { + spod: string; + name: string; + busy: BooleanLike; + steel: number; + glass: number; + } + >[]; + sleevers: { + sleever: string; + name: string; + occupied: BooleanLike; + occupant: string; + }[]; + coredumped: BooleanLike; + emergency: BooleanLike; + temp: { text: string; style: string } | null; + selected_pod: string; + selected_printer: string; + selected_sleever: string; + bodyrecords: record[]; + mindrecords: record[]; + modal: Partial; +}; + +type pod = { + pod: string; + name: string; + biomass: number; + status: string; + progress: number; +}; + +export type modalBBodyData = { + id: string; + text: string; + args: { + activerecord: string; + realname: string; + species: string; + sex: string; + mind_compat: string; + synthetic: BooleanLike; + oocnotes: string; + can_grow_active: BooleanLike; + }; + modal_type: string; +}; + +export type modalMindData = { + id: string; + text: string; + args: { + activerecord: string; + realname: string; + obviously_dead: string; + oocnotes: string; + can_sleeve_active: BooleanLike; + }; + modal_type: string; +}; + +export type record = { name: string; recref: string }; diff --git a/tgui/packages/tgui/interfaces/ResleevingConsole/viewBodyRecordModalBodyOverride.tsx b/tgui/packages/tgui/interfaces/ResleevingConsole/viewBodyRecordModalBodyOverride.tsx new file mode 100644 index 00000000000..58b20b8a976 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ResleevingConsole/viewBodyRecordModalBodyOverride.tsx @@ -0,0 +1,58 @@ +import { useBackend } from '../../backend'; +import { Button, LabeledList, Section } from '../../components'; +import { modalBBodyData } from './types'; + +export const viewBodyRecordModalBodyOverride = (modal: modalBBodyData) => { + const { act } = useBackend(); + const { + activerecord, + realname, + species, + sex, + mind_compat, + synthetic, + oocnotes, + can_grow_active, + } = modal.args; + return ( + act('modal_close')} /> + } + > + + {realname} + {species} + {sex} + {mind_compat} + + {synthetic ? 'Yes' : 'No'} + + + + {oocnotes} + + + + + act('create', { + ref: activerecord, + }) + } + > + {synthetic ? 'Build' : 'Grow'} + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ResleevingConsole/viewMindRecordModalBodyOverride.tsx b/tgui/packages/tgui/interfaces/ResleevingConsole/viewMindRecordModalBodyOverride.tsx new file mode 100644 index 00000000000..18cfccb73a1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ResleevingConsole/viewMindRecordModalBodyOverride.tsx @@ -0,0 +1,62 @@ +import { useBackend } from '../../backend'; +import { Button, LabeledList, Section } from '../../components'; +import { modalMindData } from './types'; + +export const viewMindRecordModalBodyOverride = (modal: modalMindData) => { + const { act } = useBackend(); + const { + activerecord, + realname, + obviously_dead, + oocnotes, + can_sleeve_active, + } = modal.args; + return ( + act('modal_close')} /> + } + > + + {realname} + {obviously_dead} + + + act('sleeve', { + ref: activerecord, + mode: 1, + }) + } + > + Sleeve + + + act('sleeve', { + ref: activerecord, + mode: 2, + }) + } + > + Card + + + + + {oocnotes} + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ResleevingPod.jsx b/tgui/packages/tgui/interfaces/ResleevingPod.tsx similarity index 87% rename from tgui/packages/tgui/interfaces/ResleevingPod.jsx rename to tgui/packages/tgui/interfaces/ResleevingPod.tsx index 1b0027b484e..455cca49e79 100644 --- a/tgui/packages/tgui/interfaces/ResleevingPod.jsx +++ b/tgui/packages/tgui/interfaces/ResleevingPod.tsx @@ -1,9 +1,23 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, LabeledList, ProgressBar, Section } from '../components'; import { Window } from '../layouts'; +type Data = { + occupied: BooleanLike; + name: string; + health: number; + maxHealth: number; + stat: number; + mindStatus: BooleanLike; + mindName: string; + resleeveSick: BooleanLike; + initialSick: BooleanLike; +}; + export const ResleevingPod = (model) => { - const { data } = useBackend(); + const { data } = useBackend(); const { occupied, name, @@ -17,7 +31,7 @@ export const ResleevingPod = (model) => { } = data; return ( - + {occupied ? ( diff --git a/tgui/packages/tgui/interfaces/RoboticsControlConsole.jsx b/tgui/packages/tgui/interfaces/RoboticsControlConsole.tsx similarity index 80% rename from tgui/packages/tgui/interfaces/RoboticsControlConsole.jsx rename to tgui/packages/tgui/interfaces/RoboticsControlConsole.tsx index c775ff5a420..87ea39cf6f4 100644 --- a/tgui/packages/tgui/interfaces/RoboticsControlConsole.jsx +++ b/tgui/packages/tgui/interfaces/RoboticsControlConsole.tsx @@ -1,3 +1,5 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, @@ -9,9 +11,33 @@ import { } from '../components'; import { Window } from '../layouts'; +type Data = { + auth: BooleanLike; + can_hack: BooleanLike; + cyborgs: cyborg[]; + safety: BooleanLike; + show_detonate_all: BooleanLike; +}; + +type cyborg = { + name: string; + ref: string; + locked_down: BooleanLike; + locstring: string; + status: number; + health: number; + charge: number | null; + cell_capacity: number | null; + module: string; + synchronization: BooleanLike; + is_hacked: BooleanLike; + emagged: BooleanLike; + hackable: BooleanLike; +}; + export const RoboticsControlConsole = (props) => { - const { act, data } = useBackend(); - const { can_hack, safety, show_detonate_all, cyborgs = [] } = data; + const { act, data } = useBackend(); + const { can_hack, safety, show_detonate_all, cyborgs = [], auth } = data; return ( @@ -30,15 +56,19 @@ export const RoboticsControlConsole = (props) => { )} - + ); }; -const Cyborgs = (props) => { - const { cyborgs, can_hack } = props; - const { act, data } = useBackend(); +const Cyborgs = (props: { + cyborgs: cyborg[]; + can_hack: BooleanLike; + auth: BooleanLike; +}) => { + const { cyborgs, can_hack, auth } = props; + const { act } = useBackend(); if (!cyborgs.length) { return ( No cyborg units detected within access parameters. @@ -67,7 +97,7 @@ const Cyborgs = (props) => { act('stopbot', { ref: cyborg.ref, @@ -78,7 +108,7 @@ const Cyborgs = (props) => { act('killbot', { @@ -123,7 +153,7 @@ const Cyborgs = (props) => { /> - + {cyborg.cell_capacity} diff --git a/tgui/packages/tgui/interfaces/RogueZones.jsx b/tgui/packages/tgui/interfaces/RogueZones.tsx similarity index 89% rename from tgui/packages/tgui/interfaces/RogueZones.jsx rename to tgui/packages/tgui/interfaces/RogueZones.tsx index edbedcca52a..a6b365b9f43 100644 --- a/tgui/packages/tgui/interfaces/RogueZones.jsx +++ b/tgui/packages/tgui/interfaces/RogueZones.tsx @@ -1,9 +1,25 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, LabeledList, ProgressBar, Section } from '../components'; import { Window } from '../layouts'; +type Data = { + timeout_percent: number; + diffstep: number; + difficulty: string; + occupied: BooleanLike; + scanning: BooleanLike; + updated: BooleanLike; + debug: BooleanLike; + shuttle_location: string; + shuttle_at_station: BooleanLike; + scan_ready: BooleanLike; + can_recall_shuttle: BooleanLike; +}; + export const RogueZones = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { timeout_percent, diffstep, diff --git a/tgui/packages/tgui/interfaces/Secbot.jsx b/tgui/packages/tgui/interfaces/Secbot.tsx similarity index 90% rename from tgui/packages/tgui/interfaces/Secbot.jsx rename to tgui/packages/tgui/interfaces/Secbot.tsx index 756ae9a3b36..5c631e6cc50 100644 --- a/tgui/packages/tgui/interfaces/Secbot.jsx +++ b/tgui/packages/tgui/interfaces/Secbot.tsx @@ -1,9 +1,24 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Button, LabeledList, Section } from '../components'; import { Window } from '../layouts'; +type Data = { + on: BooleanLike; + open: BooleanLike; + locked: BooleanLike; + idcheck: BooleanLike; + check_records: BooleanLike; + check_arrest: BooleanLike; + arrest_type: BooleanLike; + declare_arrests: BooleanLike; + bot_patrolling: BooleanLike; + patrol: BooleanLike; +}; + export const Secbot = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { on, diff --git a/tgui/packages/tgui/interfaces/SecureSafe.jsx b/tgui/packages/tgui/interfaces/SecureSafe.tsx similarity index 81% rename from tgui/packages/tgui/interfaces/SecureSafe.jsx rename to tgui/packages/tgui/interfaces/SecureSafe.tsx index ff01ba5093b..79561b3cbfa 100644 --- a/tgui/packages/tgui/interfaces/SecureSafe.jsx +++ b/tgui/packages/tgui/interfaces/SecureSafe.tsx @@ -1,14 +1,26 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, Flex, NoticeBox, Section, Table } from '../components'; import { Window } from '../layouts'; +type Data = { + locked: BooleanLike; + code: string; + emagged: BooleanLike; + l_setshort: BooleanLike; + l_set: BooleanLike; +}; + const NukeKeypad = (props) => { - const { act, data } = useBackend(); - const keypadKeys = [ + const { act, data } = useBackend(); + + const keypadKeys: string[][] = [ ['1', '4', '7', 'R'], ['2', '5', '8', '0'], ['3', '6', '9', 'E'], ]; + const { locked, l_setshort, code, emagged } = data; return ( @@ -44,27 +56,27 @@ const NukeKeypad = (props) => { }; export const SecureSafe = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { code, l_setshort, l_set, emagged, locked } = data; - let new_code = !(!!l_set || !!l_setshort); + let new_code: boolean = !(!!l_set || !!l_setshort); return ( {new_code && ( - + ENTER NEW 5-DIGIT PASSCODE. )} {!!emagged && ( - + LOCKING SYSTEM ERROR - 1701 )} {!!l_setshort && ( - + ALERT: MEMORY SYSTEM ERROR - 6040 201 )} diff --git a/tgui/packages/tgui/interfaces/SecurityRecords.jsx b/tgui/packages/tgui/interfaces/SecurityRecords.jsx deleted file mode 100644 index f71551c1a0a..00000000000 --- a/tgui/packages/tgui/interfaces/SecurityRecords.jsx +++ /dev/null @@ -1,301 +0,0 @@ -import { useBackend } from '../backend'; -import { - Box, - Button, - Flex, - Input, - LabeledList, - Section, - Tabs, -} from '../components'; -import { ComplexModal, modalOpen } from '../interfaces/common/ComplexModal'; -import { Window } from '../layouts'; -import { LoginInfo } from './common/LoginInfo'; -import { LoginScreen } from './common/LoginScreen'; -import { TemporaryNotice } from './common/TemporaryNotice'; - -const doEdit = (field) => { - modalOpen('edit', { - field: field.edit, - value: field.value, - }); -}; - -export const SecurityRecords = (_properties) => { - const { data } = useBackend(); - const { authenticated, screen } = data; - if (!authenticated) { - return ( - - - - - - ); - } - - let body; - if (screen === 2) { - // List Records - body = ; - } else if (screen === 3) { - // Record Maintenance - body = ; - } else if (screen === 4) { - // View Records - body = ; - } - - return ( - - - - - - - {body} - - - ); -}; - -const SecurityRecordsList = (_properties) => { - const { act, data } = useBackend(); - const { records } = data; - return ( - <> - act('search', { t1: value })} - /> - - {records.map((record, i) => ( - act('d_rec', { d_rec: record.ref })} - > - {record.id + - ': ' + - record.name + - ' (Criminal Status: ' + - record.criminal + - ')'} - - ))} - - > - ); -}; - -const SecurityRecordsMaintenance = (_properties) => { - const { act } = useBackend(); - return ( - <> - - Backup to Disk - - - - Upload from Disk - - - act('del_all')}> - Delete All Security Records - - > - ); -}; - -const SecurityRecordsView = (_properties) => { - const { act, data } = useBackend(); - const { security, printing } = data; - return ( - <> - - - - - - - - act('del_r')} - > - Delete Security Record - - act('del_r_2')} - > - Delete Record (All) - - act('print_p')} - > - Print Entry - - - act('screen', { screen: 2 })} - > - Back - - - > - ); -}; - -const SecurityRecordsViewGeneral = (_properties) => { - const { act, data } = useBackend(); - const { general } = data; - if (!general || !general.fields) { - return General records lost!; - } - return ( - - - - {general.fields.map((field, i) => ( - - - {field.value} - - {!!field.edit && ( - doEdit(field)} /> - )} - - ))} - - - - {!!general.has_photos && - general.photos.map((p, i) => ( - - - - Photo #{i + 1} - - ))} - - act('photo_front')}>Update Front Photo - act('photo_side')}>Update Side Photo - - - - ); -}; - -const SecurityRecordsViewSecurity = (_properties) => { - const { act, data } = useBackend(); - const { security } = data; - if (!security || !security.fields) { - return ( - - Security records lost! - act('new')}> - New Record - - - ); - } - return ( - <> - - {security.fields.map((field, i) => ( - - - {field.value} - doEdit(field)} - /> - - - ))} - - - {security.comments.length === 0 ? ( - No comments found. - ) : ( - security.comments.map((comment, i) => ( - - - {comment.header} - - - {comment.text} - act('del_c', { del_c: i + 1 })} - /> - - )) - )} - - modalOpen('add_c')} - > - Add Entry - - - > - ); -}; - -const SecurityRecordsNavigation = (_properties) => { - const { act, data } = useBackend(); - const { screen } = data; - return ( - - act('screen', { screen: 2 })} - > - List Records - - act('screen', { screen: 3 })} - > - Record Maintenance - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/SecurityRecordsList.tsx b/tgui/packages/tgui/interfaces/SecurityRecords/SecurityRecordsList.tsx new file mode 100644 index 00000000000..8ddfdded920 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SecurityRecords/SecurityRecordsList.tsx @@ -0,0 +1,35 @@ +import { useBackend } from '../../backend'; +import { Box, Button, Input } from '../../components'; +import { Data } from './types'; + +export const SecurityRecordsList = (props) => { + const { act, data } = useBackend(); + const { records } = data; + return ( + <> + act('search', { t1: value })} + /> + + {records!.map((record, i) => ( + act('d_rec', { d_rec: record.ref })} + > + {record.id + + ': ' + + record.name + + ' (Criminal Status: ' + + record.criminal + + ')'} + + ))} + + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/SecurityRecordsOptions.tsx b/tgui/packages/tgui/interfaces/SecurityRecords/SecurityRecordsOptions.tsx new file mode 100644 index 00000000000..276ad42d1a9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SecurityRecords/SecurityRecordsOptions.tsx @@ -0,0 +1,97 @@ +import { useBackend } from '../../backend'; +import { Button, Section, Tabs } from '../../components'; +import { SecurityRecordsViewGeneral } from './SecurityRecordsViewGeneral'; +import { SecurityRecordsViewSecurity } from './SecurityRecordsViewSecurity'; +import { Data } from './types'; + +export const SecurityRecordsMaintenance = (props) => { + const { act } = useBackend(); + return ( + <> + + Backup to Disk + + + + Upload from Disk + + + act('del_all')}> + Delete All Security Records + + > + ); +}; + +export const SecurityRecordsView = (props) => { + const { act, data } = useBackend(); + const { security, printing } = data; + return ( + <> + + + + + + + + act('del_r')} + > + Delete Security Record + + act('del_r_2')} + > + Delete Record (All) + + act('print_p')} + > + Print Entry + + + act('screen', { screen: 2 })} + > + Back + + + > + ); +}; + +export const SecurityRecordsNavigation = (props) => { + const { act, data } = useBackend(); + const { screen } = data; + return ( + + act('screen', { screen: 2 })} + > + List Records + + act('screen', { screen: 3 })} + > + Record Maintenance + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/SecurityRecordsViewGeneral.tsx b/tgui/packages/tgui/interfaces/SecurityRecords/SecurityRecordsViewGeneral.tsx new file mode 100644 index 00000000000..a25e9b0628a --- /dev/null +++ b/tgui/packages/tgui/interfaces/SecurityRecords/SecurityRecordsViewGeneral.tsx @@ -0,0 +1,54 @@ +import { useBackend } from '../../backend'; +import { Box, Button, Flex, Image, LabeledList } from '../../components'; +import { doEdit } from '../GeneralRecords/functions'; +import { Data } from './types'; + +export const SecurityRecordsViewGeneral = (props) => { + const { act, data } = useBackend(); + const { general } = data; + if (!general || !general.fields) { + return General records lost!; + } + return ( + + + + {general.fields.map((field, i) => ( + + + {field.value} + {!!field.edit && ( + doEdit(field)} + /> + )} + + + ))} + + + + {!!general.has_photos && + general.photos!.map((p, i) => ( + + + + Photo #{i + 1} + + ))} + + act('photo_front')}>Update Front Photo + act('photo_side')}>Update Side Photo + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/SecurityRecordsViewSecurity.tsx b/tgui/packages/tgui/interfaces/SecurityRecords/SecurityRecordsViewSecurity.tsx new file mode 100644 index 00000000000..7c5686555ac --- /dev/null +++ b/tgui/packages/tgui/interfaces/SecurityRecords/SecurityRecordsViewSecurity.tsx @@ -0,0 +1,71 @@ +import { useBackend } from '../../backend'; +import { Box, Button, LabeledList, Section } from '../../components'; +import { modalOpen } from '../../interfaces/common/ComplexModal'; +import { doEdit } from '../GeneralRecords/functions'; +import { Data } from './types'; + +export const SecurityRecordsViewSecurity = (props) => { + const { act, data } = useBackend(); + const { security } = data; + if (!security || !security.fields) { + return ( + + Security records lost! + act('new')}> + New Record + + + ); + } + return ( + <> + + {security.fields.map((field, i) => ( + + + {field.value} + doEdit(field)} + /> + + + ))} + + + {security.comments && security.comments.length === 0 ? ( + No comments found. + ) : ( + security.comments && + security.comments.map((comment, i) => ( + + + {comment.header} + + + {comment.text} + act('del_c', { del_c: i + 1 })} + /> + + )) + )} + + modalOpen('add_c')} + > + Add Entry + + + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/index.tsx b/tgui/packages/tgui/interfaces/SecurityRecords/index.tsx new file mode 100644 index 00000000000..1b7478d4400 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SecurityRecords/index.tsx @@ -0,0 +1,48 @@ +import { useBackend } from '../../backend'; +import { Section } from '../../components'; +import { ComplexModal } from '../../interfaces/common/ComplexModal'; +import { Window } from '../../layouts'; +import { LoginInfo } from '../common/LoginInfo'; +import { LoginScreen } from '../common/LoginScreen'; +import { TemporaryNotice } from '../common/TemporaryNotice'; +import { SecurityRecordsList } from './SecurityRecordsList'; +import { + SecurityRecordsMaintenance, + SecurityRecordsNavigation, + SecurityRecordsView, +} from './SecurityRecordsOptions'; +import { Data } from './types'; + +export const SecurityRecords = (props) => { + const { data } = useBackend(); + const { authenticated, screen } = data; + if (!authenticated) { + return ( + + + + + + ); + } + + const body: React.JSX.Element[] = []; + // List Records + body[2] = ; + // Record Maintenance + body[3] = ; + // View Records + body[4] = ; + + return ( + + + + + + + {(screen && body[screen]) || ''} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/types.ts b/tgui/packages/tgui/interfaces/SecurityRecords/types.ts new file mode 100644 index 00000000000..e93daddae45 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SecurityRecords/types.ts @@ -0,0 +1,46 @@ +import { BooleanLike } from 'common/react'; + +import { field } from '../GeneralRecords/types'; + +export type Data = { + temp: { color: string; text: string } | null; + scan: string | null; + authenticated: BooleanLike; + rank: string | null; + screen: number | null; + printing: BooleanLike; + isAI: BooleanLike; + isRobot: BooleanLike; + records: record[] | undefined; + general: + | { + fields: field[] | undefined; + photos: string[] | undefined; + has_photos: BooleanLike; + empty: BooleanLike; + } + | undefined; + security: + | { + fields: field[] | undefined; + comments: { header: string; text: string }[] | undefined; + empty: BooleanLike; + } + | undefined; + modal: modalData; +}; + +type record = { + ref: string; + id: string; + name: string; + color: string; + criminal: string; +}; + +export type modalData = { + id: string; + text: string; + args: {}; + modal_type: string; +}; diff --git a/tgui/packages/tgui/interfaces/SeedStorage.jsx b/tgui/packages/tgui/interfaces/SeedStorage.tsx similarity index 76% rename from tgui/packages/tgui/interfaces/SeedStorage.jsx rename to tgui/packages/tgui/interfaces/SeedStorage.tsx index e1408fe4ce3..01d035c301a 100644 --- a/tgui/packages/tgui/interfaces/SeedStorage.jsx +++ b/tgui/packages/tgui/interfaces/SeedStorage.tsx @@ -5,12 +5,36 @@ import { useBackend } from '../backend'; import { Button, Collapsible, Flex, LabeledList, Section } from '../components'; import { Window } from '../layouts'; +type Data = { + scanner: string[]; + seeds: seed[]; +}; + +type seed = { + name: string; + uid: string; + amount: number; + id: number; + traits: { + Endurance: string; + Yield: string; + Production: string; + Potency: string; + 'Repeat Harvest': string; + 'Ideal Heat': string; + 'Ideal Light': string; + 'Nutrient Consumption': string; + 'Water Consumption': string; + notes: string; + }; +}; + export const SeedStorage = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); - const { scanner, seeds } = data; + const { seeds } = data; - const sortedSeeds = sortBy((seed) => seed.name.toLowerCase())(seeds); + const sortedSeeds = sortBy((seed: seed) => seed.name.toLowerCase())(seeds); return ( diff --git a/tgui/packages/tgui/interfaces/ShieldCapacitor.jsx b/tgui/packages/tgui/interfaces/ShieldCapacitor.tsx similarity index 83% rename from tgui/packages/tgui/interfaces/ShieldCapacitor.jsx rename to tgui/packages/tgui/interfaces/ShieldCapacitor.tsx index 16c0e53e82b..c34795a65ef 100644 --- a/tgui/packages/tgui/interfaces/ShieldCapacitor.jsx +++ b/tgui/packages/tgui/interfaces/ShieldCapacitor.tsx @@ -1,4 +1,5 @@ import { round, toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { @@ -12,8 +13,17 @@ import { import { formatPower, formatSiUnit } from '../format'; import { Window } from '../layouts'; +type Data = { + active: BooleanLike; + time_since_fail: number; + stored_charge: number; + max_charge: number; + charge_rate: number; + max_charge_rate: number; +}; + export const ShieldCapacitor = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { active, @@ -64,8 +74,8 @@ export const ShieldCapacitor = (props) => { stepPixelSize={0.2} minValue={10000} maxValue={max_charge_rate} - format={(val) => formatPower(val)} - onDrag={(e, val) => act('charge_rate', { rate: val })} + format={(val: number) => formatPower(val)} + onDrag={(e, val: number) => act('charge_rate', { rate: val })} /> diff --git a/tgui/packages/tgui/interfaces/ShieldGenerator.jsx b/tgui/packages/tgui/interfaces/ShieldGenerator.tsx similarity index 83% rename from tgui/packages/tgui/interfaces/ShieldGenerator.jsx rename to tgui/packages/tgui/interfaces/ShieldGenerator.tsx index e19c25b12b6..baff85f2ff1 100644 --- a/tgui/packages/tgui/interfaces/ShieldGenerator.jsx +++ b/tgui/packages/tgui/interfaces/ShieldGenerator.tsx @@ -1,4 +1,5 @@ import { toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { @@ -13,8 +14,36 @@ import { formatPower, formatSiUnit } from '../format'; import { Window } from '../layouts'; import { FullscreenNotice } from './common/FullscreenNotice'; +type Data = { + locked: BooleanLike; + lockedData: { + capacitors: capacitor[]; + active: BooleanLike; + failing: BooleanLike; + radius: number; + max_radius: number; + z_range: number; + max_z_range: number; + average_field_strength: number; + target_field_strength: number; + max_field_strength: number; + shields: number; + upkeep: number; + strengthen_rate: number; + max_strengthen_rate: number; + gen_power: number; + }; +}; + +type capacitor = { + active: BooleanLike; + stored_charge: number; + max_charge: number; + failing: BooleanLike; +}; + export const ShieldGenerator = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { locked } = data; @@ -44,7 +73,7 @@ const ShieldGeneratorLocked = (props) => ( ); const ShieldGeneratorContent = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { capacitors, @@ -154,7 +183,7 @@ const ShieldGeneratorContent = (props) => { maxValue={max_radius} value={radius} unit="m" - onDrag={(e, val) => act('change_radius', { val: val })} + onDrag={(e, val: number) => act('change_radius', { val: val })} /> @@ -165,7 +194,7 @@ const ShieldGeneratorContent = (props) => { maxValue={max_z_range} value={z_range} unit="vertical range" - onDrag={(e, val) => act('z_range', { val: val })} + onDrag={(e, val: number) => act('z_range', { val: val })} /> @@ -176,9 +205,9 @@ const ShieldGeneratorContent = (props) => { step={0.1} maxValue={max_strengthen_rate} value={strengthen_rate} - format={(val) => toFixed(val, 1)} + format={(val: number) => toFixed(val, 1)} unit="Renwick/s" - onDrag={(e, val) => act('strengthen_rate', { val: val })} + onDrag={(e, val: number) => act('strengthen_rate', { val: val })} /> @@ -189,7 +218,9 @@ const ShieldGeneratorContent = (props) => { maxValue={max_field_strength} value={target_field_strength} unit="Renwick" - onDrag={(e, val) => act('target_field_strength', { val: val })} + onDrag={(e, val: number) => + act('target_field_strength', { val: val }) + } /> diff --git a/tgui/packages/tgui/interfaces/ShutoffMonitor.jsx b/tgui/packages/tgui/interfaces/ShutoffMonitor.tsx similarity index 88% rename from tgui/packages/tgui/interfaces/ShutoffMonitor.jsx rename to tgui/packages/tgui/interfaces/ShutoffMonitor.tsx index a61b7521138..e83e3ee8dab 100644 --- a/tgui/packages/tgui/interfaces/ShutoffMonitor.jsx +++ b/tgui/packages/tgui/interfaces/ShutoffMonitor.tsx @@ -1,7 +1,21 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Button, Section, Table } from '../components'; import { Window } from '../layouts'; +type Data = { + valves: { + name: string; + enabled: BooleanLike; + open: BooleanLike; + x: number; + y: number; + z: number; + ref: string; + }[]; +}; + export const ShutoffMonitor = (props) => ( @@ -11,7 +25,7 @@ export const ShutoffMonitor = (props) => ( ); export const ShutoffMonitorContent = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { valves } = data; diff --git a/tgui/packages/tgui/interfaces/ShuttleControl/ShuttleControlConsoleTypes.tsx b/tgui/packages/tgui/interfaces/ShuttleControl/ShuttleControlConsoleTypes.tsx new file mode 100644 index 00000000000..26a3c917a3f --- /dev/null +++ b/tgui/packages/tgui/interfaces/ShuttleControl/ShuttleControlConsoleTypes.tsx @@ -0,0 +1,88 @@ +import { useBackend } from '../../backend'; +import { Button, LabeledList, Section } from '../../components'; +import { ShuttleControlSharedShuttleControls } from './ShuttleControlSharedShuttleControls'; +import { ShuttleControlSharedShuttleStatus } from './ShuttleControlSharedShuttleStatus'; +import { Data } from './types'; + +export const ShuttleControlConsoleDefault = (props) => { + return ( + <> + + + > + ); +}; + +export const ShuttleControlConsoleMulti = (props: { + destination_name: string; +}) => { + const { act, data } = useBackend(); + const { can_cloak, can_pick, legit, cloaked } = data; + return ( + <> + + + + {(can_cloak && ( + + act('toggle_cloaked')} + > + {cloaked ? 'Enabled' : 'Disabled'} + + + )) || + ''} + + act('pick')} + > + {props.destination_name} + + + + + + > + ); +}; + +export const ShuttleControlConsoleExploration = (props) => { + const { act, data } = useBackend(); + const { can_pick, destination_name, fuel_usage, fuel_span, remaining_fuel } = + data; + return ( + <> + + + + + act('pick')} + > + {destination_name} + + + {(fuel_usage && ( + <> + + {remaining_fuel} m/s + + + {fuel_usage} m/s + + > + )) || + ''} + + + + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/ShuttleControl.jsx b/tgui/packages/tgui/interfaces/ShuttleControl/ShuttleControlConsoleWeb.tsx similarity index 51% rename from tgui/packages/tgui/interfaces/ShuttleControl.jsx rename to tgui/packages/tgui/interfaces/ShuttleControl/ShuttleControlConsoleWeb.tsx index 652c38b1ffb..d3c6d9130c7 100644 --- a/tgui/packages/tgui/interfaces/ShuttleControl.jsx +++ b/tgui/packages/tgui/interfaces/ShuttleControl/ShuttleControlConsoleWeb.tsx @@ -1,222 +1,19 @@ import { toTitleCase } from 'common/string'; -import { useBackend } from '../backend'; +import { useBackend } from '../../backend'; import { Box, Button, - Flex, LabeledList, ProgressBar, Section, -} from '../components'; -import { Window } from '../layouts'; - -/* Helpers */ -const getDockingStatus = (docking_status, docking_override) => { - let main = 'ERROR'; - let color = 'bad'; - let showsOverride = false; - if (docking_status === 'docked') { - main = 'DOCKED'; - color = 'good'; - } else if (docking_status === 'docking') { - main = 'DOCKING'; - color = 'average'; - showsOverride = true; - } else if (docking_status === 'undocking') { - main = 'UNDOCKING'; - color = 'average'; - showsOverride = true; - } else if (docking_status === 'undocked') { - main = 'UNDOCKED'; - color = '#676767'; - } - - if (showsOverride && docking_override) { - main = main + '-MANUAL'; - } - - return {main}; -}; - -/* Templates */ -const ShuttleControlSharedShuttleStatus = (props) => { - const { act, data } = useBackend(); - const { engineName = 'Bluespace Drive' } = props; - const { - shuttle_status, - shuttle_state, - has_docking, - docking_status, - docking_override, - docking_codes, - } = data; - return ( - - - {shuttle_status} - - - - {(shuttle_state === 'idle' && ( - - IDLE - - )) || - (shuttle_state === 'warmup' && ( - SPINNING UP - )) || - (shuttle_state === 'in_transit' && ( - ENGAGED - )) || ERROR} - - {(has_docking && ( - <> - - {getDockingStatus(docking_status, docking_override)} - - - act('set_codes')}> - {docking_codes || 'Not Set'} - - - > - )) || - null} - - - ); -}; - -const ShuttleControlSharedShuttleControls = (props) => { - const { act, data } = useBackend(); - - const { can_launch, can_cancel, can_force } = data; - - return ( - - - - act('move')} - disabled={!can_launch} - icon="rocket" - fluid - > - Launch Shuttle - - - - act('cancel')} - disabled={!can_cancel} - icon="ban" - fluid - > - Cancel Launch - - - - act('force')} - color="bad" - disabled={!can_force} - icon="exclamation-triangle" - fluid - > - Force Launch - - - - - ); -}; - -const ShuttleControlConsoleDefault = (props) => { - const { act, data } = useBackend(); - return ( - <> - - - > - ); -}; - -const ShuttleControlConsoleMulti = (props) => { - const { act, data } = useBackend(); - const { can_cloak, can_pick, legit, cloaked } = data; - return ( - <> - - - - {(can_cloak && ( - - act('toggle_cloaked')} - > - {cloaked ? 'Enabled' : 'Disabled'} - - - )) || - null} - - act('pick')} - > - {props.destination_name} - - - - - - > - ); -}; - -const ShuttleControlConsoleExploration = (props) => { - const { act, data } = useBackend(); - const { can_pick, destination_name, fuel_usage, fuel_span, remaining_fuel } = - data; - return ( - <> - - - - - act('pick')} - > - {destination_name} - - - {(fuel_usage && ( - <> - - {remaining_fuel} m/s - - - {fuel_usage} m/s - - > - )) || - null} - - - - > - ); -}; +} from '../../components'; +import { getDockingStatus } from './functions'; +import { Data } from './types'; /* Ugh. Just ugh. */ -const ShuttleControlConsoleWeb = (props) => { - const { act, data } = useBackend(); +export const ShuttleControlConsoleWeb = (props) => { + const { act, data } = useBackend(); const { autopilot, @@ -250,7 +47,7 @@ const ShuttleControlConsoleWeb = (props) => { )) || - null} + ''} { Rename )) || - null + '' } > @@ -314,7 +111,7 @@ const ShuttleControlConsoleWeb = (props) => { )) || - null} + ''} {(can_cloak && ( { )) || - null} + ''} {(can_autopilot && ( { )) || - null} + ''} > )) || - null} + ''} {(!is_moving && ( - + - {(routes.length && - routes.map((route) => ( + {(routes!.length && + routes!.map((route) => ( { )) || - null} + ''} {(is_in_transit && ( @@ -374,7 +171,7 @@ const ShuttleControlConsoleWeb = (props) => { color="good" minValue={0} maxValue={100} - value={travel_progress} + value={travel_progress!} > {time_left}s @@ -382,12 +179,12 @@ const ShuttleControlConsoleWeb = (props) => { )) || - null} - {(Object.keys(doors).length && ( + ''} + {(Object.keys(doors!).length && ( - {Object.keys(doors).map((key) => { - let door = doors[key]; + {Object.keys(doors!).map((key) => { + const door = doors![key]; return ( {(door.open && ( @@ -415,12 +212,12 @@ const ShuttleControlConsoleWeb = (props) => { )) || - null} - {(Object.keys(sensors).length && ( + ''} + {(Object.keys(sensors!).length && ( - {Object.keys(sensors).map((key, index) => { - let sensor = sensors[key]; + {Object.keys(sensors!).map((key, index) => { + const sensor = sensors![key]; if (sensor.reading !== -1) { return ( @@ -454,7 +251,7 @@ const ShuttleControlConsoleWeb = (props) => { {sensor.other}% )) || - null} + ''} ); @@ -462,33 +259,7 @@ const ShuttleControlConsoleWeb = (props) => { )) || - null} + ''} > ); }; - -export const ShuttleControl = (props) => { - const { act, data } = useBackend(); - const { subtemplate, destination_name } = data; - return ( - - - {(subtemplate === 'ShuttleControlConsoleDefault' && ( - - )) || - (subtemplate === 'ShuttleControlConsoleMulti' && ( - - )) || - (subtemplate === 'ShuttleControlConsoleExploration' && ( - - )) || - (subtemplate === 'ShuttleControlConsoleWeb' && ( - - ))} - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/ShuttleControl/ShuttleControlSharedShuttleControls.tsx b/tgui/packages/tgui/interfaces/ShuttleControl/ShuttleControlSharedShuttleControls.tsx new file mode 100644 index 00000000000..8b351ff3e3a --- /dev/null +++ b/tgui/packages/tgui/interfaces/ShuttleControl/ShuttleControlSharedShuttleControls.tsx @@ -0,0 +1,47 @@ +import { useBackend } from '../../backend'; +import { Button, Flex, Section } from '../../components'; +import { Data } from './types'; + +export const ShuttleControlSharedShuttleControls = (props) => { + const { act, data } = useBackend(); + + const { can_launch, can_cancel, can_force } = data; + + return ( + + + + act('move')} + disabled={!can_launch} + icon="rocket" + fluid + > + Launch Shuttle + + + + act('cancel')} + disabled={!can_cancel} + icon="ban" + fluid + > + Cancel Launch + + + + act('force')} + color="bad" + disabled={!can_force} + icon="exclamation-triangle" + fluid + > + Force Launch + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ShuttleControl/ShuttleControlSharedShuttleStatus.tsx b/tgui/packages/tgui/interfaces/ShuttleControl/ShuttleControlSharedShuttleStatus.tsx new file mode 100644 index 00000000000..a91599325d7 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ShuttleControl/ShuttleControlSharedShuttleStatus.tsx @@ -0,0 +1,54 @@ +import { useBackend } from '../../backend'; +import { Box, Button, LabeledList, Section } from '../../components'; +import { getDockingStatus } from './functions'; +import { Data } from './types'; + +export const ShuttleControlSharedShuttleStatus = (props: { + engineName?: string; +}) => { + const { act, data } = useBackend(); + const { engineName = 'Bluespace Drive' } = props; + const { + shuttle_status, + shuttle_state, + has_docking, + docking_status, + docking_override, + docking_codes, + } = data; + return ( + + + {shuttle_status} + + + + {(shuttle_state === 'idle' && ( + + IDLE + + )) || + (shuttle_state === 'warmup' && ( + SPINNING UP + )) || + (shuttle_state === 'in_transit' && ( + ENGAGED + )) || ERROR} + + {(has_docking && ( + <> + + {getDockingStatus(docking_status, docking_override)} + + + act('set_codes')}> + {docking_codes || 'Not Set'} + + + > + )) || + ''} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ShuttleControl/functions.tsx b/tgui/packages/tgui/interfaces/ShuttleControl/functions.tsx new file mode 100644 index 00000000000..fbed5118fad --- /dev/null +++ b/tgui/packages/tgui/interfaces/ShuttleControl/functions.tsx @@ -0,0 +1,33 @@ +import { BooleanLike } from 'common/react'; + +import { Box } from '../../components'; + +export function getDockingStatus( + docking_status: string | null | undefined, + docking_override: BooleanLike, +): React.JSX.Element { + let main: string = 'ERROR'; + let color: string = 'bad'; + let showsOverride: Boolean = false; + if (docking_status === 'docked') { + main = 'DOCKED'; + color = 'good'; + } else if (docking_status === 'docking') { + main = 'DOCKING'; + color = 'average'; + showsOverride = true; + } else if (docking_status === 'undocking') { + main = 'UNDOCKING'; + color = 'average'; + showsOverride = true; + } else if (docking_status === 'undocked') { + main = 'UNDOCKED'; + color = '#676767'; + } + + if (showsOverride && docking_override) { + main = main + '-MANUAL'; + } + + return {main}; +} diff --git a/tgui/packages/tgui/interfaces/ShuttleControl/index.tsx b/tgui/packages/tgui/interfaces/ShuttleControl/index.tsx new file mode 100644 index 00000000000..f1bd8658e36 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ShuttleControl/index.tsx @@ -0,0 +1,35 @@ +import { useBackend } from '../../backend'; +import { Window } from '../../layouts'; +import { + ShuttleControlConsoleDefault, + ShuttleControlConsoleExploration, + ShuttleControlConsoleMulti, +} from './ShuttleControlConsoleTypes'; +import { ShuttleControlConsoleWeb } from './ShuttleControlConsoleWeb'; +import { Data } from './types'; + +export const ShuttleControl = (props) => { + const { data } = useBackend(); + const { subtemplate, destination_name } = data; + return ( + + + {(subtemplate === 'ShuttleControlConsoleDefault' && ( + + )) || + (subtemplate === 'ShuttleControlConsoleMulti' && ( + + )) || + (subtemplate === 'ShuttleControlConsoleExploration' && ( + + )) || + (subtemplate === 'ShuttleControlConsoleWeb' && ( + + ))} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ShuttleControl/types.ts b/tgui/packages/tgui/interfaces/ShuttleControl/types.ts new file mode 100644 index 00000000000..2134143cad8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ShuttleControl/types.ts @@ -0,0 +1,69 @@ +import { BooleanLike } from 'common/react'; + +export type Data = Partial< + MultiData & + ExploData & + WebData & { + shuttle_status: string; + shuttle_state: string; + has_docking: BooleanLike; + docking_status: string | null; + docking_override: BooleanLike; + can_launch: BooleanLike; + can_cancel: BooleanLike; + can_force: BooleanLike; + docking_codes: string; + subtemplate: string; + } +>; + +type MultiData = { + destination_name: string; + can_pick: BooleanLike; + can_cloak: BooleanLike; + cloaked: BooleanLike; + legit: BooleanLike; +}; + +type ExploData = { + destination_name: string; + can_pick: BooleanLike; + fuel_usage: number; + remaining_fuel: number; + fuel_span: string; +}; + +type WebData = { + shuttle_location: string; + future_location: string; + shuttle_state: string; + routes: { name: string; index: number; travel_time: number }[]; + has_docking: BooleanLike; + skip_docking: BooleanLike; + is_moving: BooleanLike; + docking_status: string | null; + docking_override: BooleanLike; + is_in_transit: BooleanLike; + travel_progress: number; + time_left: number; + can_cloak: BooleanLike; + cloaked: BooleanLike; + can_autopilot: BooleanLike; + autopilot: BooleanLike; + can_rename: BooleanLike; + doors: Record; + sensors: Record; +}; + +export type sensor = { + pressure: string; + nitrogen: string; + oxygen: string; + carbon_dioxide: string; + phoron: string; + other: string; + temp: string; + reading: BooleanLike; +}; + +export type door = { bolted: BooleanLike; open: BooleanLike }; diff --git a/tgui/packages/tgui/interfaces/Sleeper.jsx b/tgui/packages/tgui/interfaces/Sleeper.jsx deleted file mode 100644 index 8a042ad78e2..00000000000 --- a/tgui/packages/tgui/interfaces/Sleeper.jsx +++ /dev/null @@ -1,333 +0,0 @@ -import { toFixed } from 'common/math'; - -import { useBackend } from '../backend'; -import { - Box, - Button, - Flex, - Icon, - LabeledList, - ProgressBar, - Section, -} from '../components'; -import { Window } from '../layouts'; - -const stats = [ - ['good', 'Alive'], - ['average', 'Unconscious'], - ['bad', 'DEAD'], -]; - -const damages = [ - ['Resp', 'oxyLoss'], - ['Toxin', 'toxLoss'], - ['Brute', 'bruteLoss'], - ['Burn', 'fireLoss'], -]; - -const damageRange = { - average: [0.25, 0.5], - bad: [0.5, Infinity], -}; - -const tempColors = [ - 'bad', - 'average', - 'average', - 'good', - 'average', - 'average', - 'bad', -]; - -export const Sleeper = (props) => { - const { act, data } = useBackend(); - const { hasOccupant } = data; - const body = hasOccupant ? : ; - return ( - - - {body} - - - ); -}; - -const SleeperMain = (props) => { - const { act, data } = useBackend(); - const { occupant, dialysis, stomachpumping } = data; - return ( - <> - - - - - - > - ); -}; - -const SleeperOccupant = (props) => { - const { act, data } = useBackend(); - const { occupant, auto_eject_dead, stasis } = data; - return ( - - - Auto-eject if dead: - - - act('auto_eject_dead_' + (auto_eject_dead ? 'off' : 'on')) - } - > - {auto_eject_dead ? 'On' : 'Off'} - - act('ejectify')}> - Eject - - act('changestasis')}>{stasis} - > - } - > - - {occupant.name} - - - {toFixed(occupant.health)} - - - - {stats[occupant.stat][1]} - - - - {toFixed(occupant.btCelsius)}°C, - {toFixed(occupant.btFaren)}°F - - - {!!occupant.hasBlood && ( - <> - - - {occupant.bloodPercent}%, {occupant.bloodLevel}cl - - - - {occupant.pulse} BPM - - > - )} - - - ); -}; - -const SleeperDamage = (props) => { - const { data } = useBackend(); - const { occupant } = data; - return ( - - - {damages.map((d, i) => ( - - - {toFixed(occupant[d[1]])} - - - ))} - - - ); -}; - -const SleeperDialysisPump = (props) => { - const { act, data } = useBackend(); - const { isBeakerLoaded, beakerMaxSpace, beakerFreeSpace } = data; - const { active, actToDo, title } = props; - const canDialysis = active && beakerFreeSpace > 0; - return ( - - act(actToDo)} - > - {canDialysis ? 'Active' : 'Inactive'} - - act('removebeaker')} - > - Eject - - > - } - > - {isBeakerLoaded ? ( - - - - {beakerFreeSpace}u - - - - ) : ( - No beaker loaded. - )} - - ); -}; - -const SleeperChemicals = (props) => { - const { act, data } = useBackend(); - const { occupant, chemicals, maxchem, amounts } = data; - return ( - - {chemicals.map((chem, i) => { - let barColor = ''; - let odWarning; - if (chem.overdosing) { - barColor = 'bad'; - odWarning = ( - - - Overdosing! - - ); - } else if (chem.od_warning) { - barColor = 'average'; - odWarning = ( - - - Close to overdosing - - ); - } - return ( - - - - - {chem.pretty_amount}/{maxchem}u - - {amounts.map((a, i) => ( - maxchem || - occupant.stat === 2 - } - icon="syringe" - mb="0" - height="19px" - onClick={() => - act('chemical', { - chemid: chem.id, - amount: a, - }) - } - > - {a} - - ))} - - - - ); - })} - - ); -}; - -const SleeperEmpty = (props) => { - const { act, data } = useBackend(); - const { isBeakerLoaded } = data; - return ( - - - - - - No occupant detected. - {(isBeakerLoaded && ( - - act('removebeaker')}> - Remove Beaker - - - )) || - null} - - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/Sleeper/SleeperChemicals.tsx b/tgui/packages/tgui/interfaces/Sleeper/SleeperChemicals.tsx new file mode 100644 index 00000000000..6ede5639bac --- /dev/null +++ b/tgui/packages/tgui/interfaces/Sleeper/SleeperChemicals.tsx @@ -0,0 +1,83 @@ +import { useBackend } from '../../backend'; +import { + Box, + Button, + Flex, + Icon, + ProgressBar, + Section, +} from '../../components'; +import { Data } from './types'; + +export const SleeperChemicals = (props) => { + const { act, data } = useBackend(); + const { occupant, chemicals, maxchem, amounts } = data; + return ( + + {chemicals.map((chem, i) => { + let barColor = ''; + let odWarning; + if (chem.overdosing) { + barColor = 'bad'; + odWarning = ( + + + Overdosing! + + ); + } else if (chem.od_warning) { + barColor = 'average'; + odWarning = ( + + + Close to overdosing + + ); + } + return ( + + + + + {chem.pretty_amount}/{maxchem}u + + {amounts.map((a, i) => ( + maxchem || + occupant.stat === 2 + } + icon="syringe" + mb="0" + height="19px" + onClick={() => + act('chemical', { + chemid: chem.id, + amount: a, + }) + } + > + {a} + + ))} + + + + ); + })} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Sleeper/SleeperDamage.tsx b/tgui/packages/tgui/interfaces/Sleeper/SleeperDamage.tsx new file mode 100644 index 00000000000..5b97fb55bfa --- /dev/null +++ b/tgui/packages/tgui/interfaces/Sleeper/SleeperDamage.tsx @@ -0,0 +1,30 @@ +import { toFixed } from 'common/math'; + +import { useBackend } from '../../backend'; +import { LabeledList, ProgressBar, Section } from '../../components'; +import { damageRange, damages } from './constants'; +import { Data } from './types'; + +export const SleeperDamage = (props) => { + const { data } = useBackend(); + const { occupant } = data; + return ( + + + {damages.map((d, i) => ( + + + {toFixed(occupant[d[1]])} + + + ))} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Sleeper/SleeperDialysisPump.tsx b/tgui/packages/tgui/interfaces/Sleeper/SleeperDialysisPump.tsx new file mode 100644 index 00000000000..09bea62b011 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Sleeper/SleeperDialysisPump.tsx @@ -0,0 +1,70 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../../backend'; +import { + Box, + Button, + LabeledList, + ProgressBar, + Section, +} from '../../components'; +import { Data } from './types'; + +export const SleeperDialysisPump = (props: { + active: BooleanLike; + actToDo: string; + title: string; +}) => { + const { act, data } = useBackend(); + + const { active, actToDo, title } = props; + + const { isBeakerLoaded, beakerMaxSpace, beakerFreeSpace } = data; + + const canDialysis = active && beakerFreeSpace > 0; + return ( + + act(actToDo)} + > + {canDialysis ? 'Active' : 'Inactive'} + + act('removebeaker')} + > + Eject + + > + } + > + {isBeakerLoaded ? ( + + + + {beakerFreeSpace}u + + + + ) : ( + No beaker loaded. + )} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Sleeper/SleeperEmpty.tsx b/tgui/packages/tgui/interfaces/Sleeper/SleeperEmpty.tsx new file mode 100644 index 00000000000..b70f6a6c0c8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Sleeper/SleeperEmpty.tsx @@ -0,0 +1,27 @@ +import { useBackend } from '../../backend'; +import { Box, Button, Flex, Icon, Section } from '../../components'; +import { Data } from './types'; + +export const SleeperEmpty = (props) => { + const { act, data } = useBackend(); + const { isBeakerLoaded } = data; + return ( + + + + + + No occupant detected. + {(isBeakerLoaded && ( + + act('removebeaker')}> + Remove Beaker + + + )) || + null} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Sleeper/SleeperMain.tsx b/tgui/packages/tgui/interfaces/Sleeper/SleeperMain.tsx new file mode 100644 index 00000000000..8e69b83e5ab --- /dev/null +++ b/tgui/packages/tgui/interfaces/Sleeper/SleeperMain.tsx @@ -0,0 +1,28 @@ +import { useBackend } from '../../backend'; +import { SleeperChemicals } from './SleeperChemicals'; +import { SleeperDamage } from './SleeperDamage'; +import { SleeperDialysisPump } from './SleeperDialysisPump'; +import { SleeperOccupant } from './SleeperOccupant'; +import { Data } from './types'; + +export const SleeperMain = (props) => { + const { data } = useBackend(); + const { dialysis, stomachpumping } = data; + return ( + <> + + + + + + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/Sleeper/SleeperOccupant.tsx b/tgui/packages/tgui/interfaces/Sleeper/SleeperOccupant.tsx new file mode 100644 index 00000000000..efcc3217923 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Sleeper/SleeperOccupant.tsx @@ -0,0 +1,95 @@ +import { toFixed } from 'common/math'; + +import { useBackend } from '../../backend'; +import { + Box, + Button, + LabeledList, + ProgressBar, + Section, +} from '../../components'; +import { stats, tempColors } from './constants'; +import { Data } from './types'; + +export const SleeperOccupant = (props) => { + const { act, data } = useBackend(); + const { occupant, auto_eject_dead, stasis } = data; + return ( + + + Auto-eject if dead: + + + act('auto_eject_dead_' + (auto_eject_dead ? 'off' : 'on')) + } + > + {auto_eject_dead ? 'On' : 'Off'} + + act('ejectify')}> + Eject + + act('changestasis')}>{stasis} + > + } + > + + {occupant.name} + + + {toFixed(occupant.health)} + + + + {stats[occupant.stat][1]} + + + + {toFixed(occupant.btCelsius)}°C, + {toFixed(occupant.btFaren)}°F + + + {!!occupant.hasBlood && ( + <> + + + {occupant.bloodPercent}%, {occupant.bloodLevel}cl + + + + {occupant.pulse} BPM + + > + )} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Sleeper/constants.ts b/tgui/packages/tgui/interfaces/Sleeper/constants.ts new file mode 100644 index 00000000000..47de4eeeaa7 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Sleeper/constants.ts @@ -0,0 +1,27 @@ +export const stats: string[][] = [ + ['good', 'Alive'], + ['average', 'Unconscious'], + ['bad', 'DEAD'], +]; + +export const damages: string[][] = [ + ['Resp', 'oxyLoss'], + ['Toxin', 'toxLoss'], + ['Brute', 'bruteLoss'], + ['Burn', 'fireLoss'], +]; + +export const damageRange: Record = { + average: [0.25, 0.5], + bad: [0.5, Infinity], +}; + +export const tempColors: string[] = [ + 'bad', + 'average', + 'average', + 'good', + 'average', + 'average', + 'bad', +]; diff --git a/tgui/packages/tgui/interfaces/Sleeper/index.tsx b/tgui/packages/tgui/interfaces/Sleeper/index.tsx new file mode 100644 index 00000000000..afc87c8d85c --- /dev/null +++ b/tgui/packages/tgui/interfaces/Sleeper/index.tsx @@ -0,0 +1,18 @@ +import { useBackend } from '../../backend'; +import { Window } from '../../layouts'; +import { SleeperEmpty } from './SleeperEmpty'; +import { SleeperMain } from './SleeperMain'; +import { Data } from './types'; + +export const Sleeper = (props) => { + const { data } = useBackend(); + const { hasOccupant } = data; + const body = hasOccupant ? : ; + return ( + + + {body} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Sleeper/types.ts b/tgui/packages/tgui/interfaces/Sleeper/types.ts new file mode 100644 index 00000000000..5097c3813ea --- /dev/null +++ b/tgui/packages/tgui/interfaces/Sleeper/types.ts @@ -0,0 +1,52 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + amounts: number[]; + hasOccupant: BooleanLike; + occupant: occupant; + maxchem: number; + minhealth: number; + dialysis: BooleanLike; + stomachpumping: BooleanLike; + auto_eject_dead: BooleanLike; + isBeakerLoaded: BooleanLike; + beakerMaxSpace: number; + beakerFreeSpace: number; + stasis: string; + chemicals: chemical[]; +}; + +type chemical = { + title: string; + id: number; + commands: { chemical: number }; + occ_amount: number; + pretty_amount: number; + injectable: BooleanLike; + overdosing: BooleanLike; + od_warning: BooleanLike; +}; + +export type occupant = { + name: string; + stat: number; + health: number; + maxHealth: number; + minHealth: number; + bruteLoss: number; + oxyLoss: number; + toxLoss: number; + fireLoss: number; + paralysis: number; + hasBlood: BooleanLike; + bodyTemperature: number; + maxTemp: number; + temperatureSuitability: number; + btCelsius: number; + btFaren: number; + pulse: number | undefined; + bloodLevel: number | undefined; + bloodMax: number | undefined; + bloodPercent: number | undefined; + bloodType: string | undefined; +}; diff --git a/tgui/packages/tgui/interfaces/SmartVend.jsx b/tgui/packages/tgui/interfaces/SmartVend.tsx similarity index 82% rename from tgui/packages/tgui/interfaces/SmartVend.jsx rename to tgui/packages/tgui/interfaces/SmartVend.tsx index beb4679f3f6..7fbc58932d5 100644 --- a/tgui/packages/tgui/interfaces/SmartVend.jsx +++ b/tgui/packages/tgui/interfaces/SmartVend.tsx @@ -1,29 +1,42 @@ import { map } from 'common/collections'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { Box, Button, NoticeBox, Section, Table } from '../components'; import { Window } from '../layouts'; +type Data = { + contents: content[]; + name: string; + locked: BooleanLike; + secure: BooleanLike; +}; + +type content = { name: string; index: number; amount: number }; + export const SmartVend = (props) => { - const { act, config, data } = useBackend(); + const { act, config, data } = useBackend(); + + const { secure, locked, contents } = data; + return ( - {(data.secure && ( - - {data.locked === -1 ? ( - - Sec.re ACC_** //):securi_nt.diag=>##'or - 1=1'%($... - - ) : ( - Secure Access: Please have your identification ready. - )} + {(secure && locked === -1 && ( + + + Sec.re ACC_** //):securi_nt.diag=>##'or 1=1'%($... + )) || - null} - {(data.contents.length === 0 && ( + (secure && locked !== -1 && ( + + Secure Access: Please have your identification ready. + + )) || + ''} + {(contents.length === 0 && ( Unfortunately, this {config.title} is empty. )) || ( @@ -36,7 +49,7 @@ export const SmartVend = (props) => { Dispense - {map((value, key) => ( + {map((value: content, key) => ( {value.name} @@ -110,7 +123,7 @@ export const SmartVend = (props) => { - ))(data.contents)} + ))(contents)} )} diff --git a/tgui/packages/tgui/interfaces/Smes.jsx b/tgui/packages/tgui/interfaces/Smes.tsx similarity index 88% rename from tgui/packages/tgui/interfaces/Smes.jsx rename to tgui/packages/tgui/interfaces/Smes.tsx index 686e49a1c00..4d6654441d0 100644 --- a/tgui/packages/tgui/interfaces/Smes.jsx +++ b/tgui/packages/tgui/interfaces/Smes.tsx @@ -1,4 +1,5 @@ import { toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { @@ -14,10 +15,30 @@ import { formatPower } from '../format'; import { Window } from '../layouts'; // Common power multiplier -const POWER_MUL = 1e3; +const POWER_MUL: number = 1e3; + +export type smes = { + capacity: number; + capacityPercent: number; + charge: number; + inputAttempt: BooleanLike; + inputting: number; + inputLevel: number; + inputLevel_text: string; + inputLevelMax: number; + inputAvailable: number; + outputAttempt: BooleanLike; + outputting: number; + outputLevel: number; + outputLevel_text: string; + outputLevelMax: number; + outputUsed: number; +}; + +type Data = smes; export const Smes = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { capacityPercent, capacity, @@ -107,8 +128,10 @@ export const Smes = (props) => { maxValue={inputLevelMax / POWER_MUL} step={5} stepPixelSize={4} - format={(value) => formatPower(value * POWER_MUL, 1)} - onDrag={(e, value) => + format={(value: number) => + formatPower(value * POWER_MUL, 1) + } + onDrag={(e, value: number) => act('input', { target: value * POWER_MUL, }) @@ -193,8 +216,10 @@ export const Smes = (props) => { maxValue={outputLevelMax / POWER_MUL} step={5} stepPixelSize={4} - format={(value) => formatPower(value * POWER_MUL, 1)} - onDrag={(e, value) => + format={(value: number) => + formatPower(value * POWER_MUL, 1) + } + onDrag={(e, value: number) => act('output', { target: value * POWER_MUL, }) diff --git a/tgui/packages/tgui/interfaces/SolarControl.jsx b/tgui/packages/tgui/interfaces/SolarControl.tsx similarity index 93% rename from tgui/packages/tgui/interfaces/SolarControl.jsx rename to tgui/packages/tgui/interfaces/SolarControl.tsx index 54a7ce2c594..9ceae183677 100644 --- a/tgui/packages/tgui/interfaces/SolarControl.jsx +++ b/tgui/packages/tgui/interfaces/SolarControl.tsx @@ -1,4 +1,5 @@ import { toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { @@ -12,8 +13,20 @@ import { } from '../components'; import { Window } from '../layouts'; +type Data = { + generated: number; + generated_ratio: number; + sun_angle: number; + array_angle: number; + rotation_rate: number; + max_rotation_rate: number; + tracking_state: number; + connected_panels: number; + connected_tracker: BooleanLike; +}; + export const SolarControl = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { generated, generated_ratio, diff --git a/tgui/packages/tgui/interfaces/Stack.jsx b/tgui/packages/tgui/interfaces/Stack.tsx similarity index 86% rename from tgui/packages/tgui/interfaces/Stack.jsx rename to tgui/packages/tgui/interfaces/Stack.tsx index d87dbf7787a..d6605dc28e5 100644 --- a/tgui/packages/tgui/interfaces/Stack.jsx +++ b/tgui/packages/tgui/interfaces/Stack.tsx @@ -2,8 +2,17 @@ import { useBackend } from '../backend'; import { Box, Button, Collapsible, Section, Table } from '../components'; import { Window } from '../layouts'; +type Data = { amount: number; recipes: recipe[] }; + +type recipe = { + res_amount: number; + max_res_amount: number; + req_amount: number; + ref: string; +}; + export const Stack = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { amount, recipes } = data; @@ -18,12 +27,10 @@ export const Stack = (props) => { ); }; -const RecipeList = (props) => { - const { act, data } = useBackend(); - +const RecipeList = (props: { recipes: recipe[] }) => { const { recipes } = props; - let sortedKeys = Object.keys(recipes).sort(); + const sortedKeys = Object.keys(recipes).sort(); // Shunt all categories to the top. // We're not using this for now, keeping it here in case someone really hates color coding later. @@ -57,7 +64,7 @@ const RecipeList = (props) => { }); }; -const buildMultiplier = (recipe, amount) => { +const buildMultiplier = (recipe: recipe, amount: number) => { if (recipe.req_amount > amount) { return 0; } @@ -75,9 +82,9 @@ const Multipliers = (props) => { Math.floor(recipe.max_res_amount / recipe.res_amount), ); - let multipliers = [5, 10, 25]; + const multipliers = [5, 10, 25]; - let finalResult = []; + const finalResult: React.JSX.Element[] = []; for (let multiplier of multipliers) { if (maxM >= multiplier) { @@ -114,8 +121,8 @@ const Multipliers = (props) => { return finalResult; }; -const Recipe = (props) => { - const { act, data } = useBackend(); +const Recipe = (props: { recipe: recipe; title: string }) => { + const { act, data } = useBackend(); const { amount } = data; diff --git a/tgui/packages/tgui/interfaces/StationAlertConsole.jsx b/tgui/packages/tgui/interfaces/StationAlertConsole.tsx similarity index 78% rename from tgui/packages/tgui/interfaces/StationAlertConsole.jsx rename to tgui/packages/tgui/interfaces/StationAlertConsole.tsx index 24ac77fa9a2..562645f2a21 100644 --- a/tgui/packages/tgui/interfaces/StationAlertConsole.jsx +++ b/tgui/packages/tgui/interfaces/StationAlertConsole.tsx @@ -1,7 +1,30 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, Section } from '../components'; import { Window } from '../layouts'; +type Data = { + categories: { + category: string; + alarms: { + name: string; + origin_lost: BooleanLike; + has_cameras: number; + cameras: { + name: string; + deact: BooleanLike; + camera: string; + omni: BooleanLike; + x: number; + y: number; + z: number; + }[]; + lost_sources: string; + }[]; + }[]; +}; + export const StationAlertConsole = () => { return ( @@ -13,7 +36,7 @@ export const StationAlertConsole = () => { }; export const StationAlertConsoleContent = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { categories = [] } = data; return categories.map((category) => ( @@ -22,7 +45,7 @@ export const StationAlertConsoleContent = (props) => { Systems Nominal )} {category.alarms.map((alarm) => { - let footer = ''; + let footer: React.JSX.Element | string = ''; // To be clear, this is never the case unless the user is an AI. if (alarm.has_cameras) { diff --git a/tgui/packages/tgui/interfaces/StationBlueprints.jsx b/tgui/packages/tgui/interfaces/StationBlueprints.tsx similarity index 85% rename from tgui/packages/tgui/interfaces/StationBlueprints.jsx rename to tgui/packages/tgui/interfaces/StationBlueprints.tsx index 53bae488de5..b3f863ebebc 100644 --- a/tgui/packages/tgui/interfaces/StationBlueprints.jsx +++ b/tgui/packages/tgui/interfaces/StationBlueprints.tsx @@ -2,6 +2,8 @@ import { useBackend } from '../backend'; import { ByondUi } from '../components'; import { Window } from '../layouts'; +type Data = { mapRef: string }; + export const StationBlueprints = (props) => { return ( @@ -11,9 +13,9 @@ export const StationBlueprints = (props) => { }; export const StationBlueprintsContent = (props) => { - const { act, data, config } = useBackend(); + const { data } = useBackend(); - const { mapRef, areas, turfs } = data; + const { mapRef /* areas, turfs */ } = data; return ( <> diff --git a/tgui/packages/tgui/interfaces/StockExchange.jsx b/tgui/packages/tgui/interfaces/StockExchange.tsx similarity index 85% rename from tgui/packages/tgui/interfaces/StockExchange.jsx rename to tgui/packages/tgui/interfaces/StockExchange.tsx index 15b71e81587..f25499b6ae1 100644 --- a/tgui/packages/tgui/interfaces/StockExchange.jsx +++ b/tgui/packages/tgui/interfaces/StockExchange.tsx @@ -1,9 +1,57 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, Chart, Divider, Section, Table } from '../components'; import { Window } from '../layouts'; +type Data = { + stationName: string; + balance: number; + screen: string; + viewMode: string | undefined; + stocks: + | { + REF: string; + valueChange: number; + bankrupt: BooleanLike; + ID: string; + Name: string; + Value: number; + Owned: number; + Avail: number; + Unification: string; + Products: string[]; + }[] + | []; + logs: + | { + type: string; + time: number; + user_name: string; + stocks: string[]; + shareprice: number; + money: number; + company_name: string; + }[] + | []; + name: string | undefined; + events: { current_title: string; current_desc: string }[] | undefined; + articles: + | { + headline: string; + subtitle: string; + article: string; + author: string; + spacetime: string; + outlet: string; + }[] + | undefined; + maxValue: number | undefined; + values: number[][] | undefined; +}; + export const StockExchange = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { screen, stationName } = data; @@ -28,7 +76,7 @@ export const StockExchange = (props) => { }; const StockExchangeStockList = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { balance, stationName, viewMode } = data; @@ -66,7 +114,7 @@ const StockExchangeStockList = (props) => { }; const StockExchangeFullView = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { stocks = [] } = data; @@ -125,7 +173,7 @@ const StockExchangeFullView = (props) => { }; const StockExchangeCompactView = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { stocks = [] } = data; @@ -133,7 +181,7 @@ const StockExchangeCompactView = (props) => { {stocks.map((stock) => ( - {stock.name} {stock.ID} + {stock.Name} {stock.ID} {stock.bankrupt === 1 && BANKRUPT} Unified shares {stock.Unification} ago. @@ -178,7 +226,7 @@ const StockExchangeCompactView = (props) => { // "Refresh" const StockExchangeLogs = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { logs = [] } = data; @@ -225,7 +273,7 @@ const StockExchangeLogs = (props) => { }; const StockExchangeArchive = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { name, events = [], articles = [] } = data; @@ -270,7 +318,7 @@ const StockExchangeArchive = (props) => { }; const StockExchangeGraph = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { name, maxValue, values = [] } = data; @@ -283,7 +331,7 @@ const StockExchangeGraph = (props) => { fillPositionedParent data={values} rangeX={[0, values.length - 1]} - rangeY={[0, maxValue]} + rangeY={[0, maxValue!]} strokeColor="rgba(0, 181, 173, 1)" fillColor="rgba(0, 181, 173, 0.25)" /> diff --git a/tgui/packages/tgui/interfaces/SuitCycler.jsx b/tgui/packages/tgui/interfaces/SuitCycler.tsx similarity index 81% rename from tgui/packages/tgui/interfaces/SuitCycler.jsx rename to tgui/packages/tgui/interfaces/SuitCycler.tsx index e5758ce0aa1..347a65e1b77 100644 --- a/tgui/packages/tgui/interfaces/SuitCycler.jsx +++ b/tgui/packages/tgui/interfaces/SuitCycler.tsx @@ -1,3 +1,4 @@ +import { BooleanLike } from 'common/react'; import { useState } from 'react'; import { useBackend } from '../backend'; @@ -12,23 +13,41 @@ import { } from '../components'; import { Window } from '../layouts'; +type Data = { + model_text: string; + can_repair: BooleanLike; + userHasAccess: BooleanLike; + locked: BooleanLike; + active: BooleanLike; + safeties: BooleanLike; + uv_active: BooleanLike; + uv_level: number; + max_uv_level: number; + helmet: string | null; + suit: string | null; + damage: number | null; + occupied: BooleanLike; + departments: string[]; + species: string[]; +}; + export const SuitCycler = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { active, locked, uv_active, species, departments } = data; - const [selectedDepartment, setSelectedDepartment] = useState( - (!!departments && departments[0]) || null, + const [selectedDepartment, setSelectedDepartment] = useState< + string | undefined + >((!!departments && departments[0]) || undefined); + + const [selectedSpecies, setSelectedSpecies] = useState( + (!!species && species[0]) || undefined, ); - const [selectedSpecies, setSelectedSpecies] = useState( - (!!species && species[0]) || null, - ); - - function handleSelectedDepartment(value) { + function handleSelectedDepartment(value: string | undefined) { setSelectedDepartment(value); } - function handleSelectedSpecies(value) { + function handleSelectedSpecies(value: string | undefined) { setSelectedSpecies(value); } @@ -56,8 +75,13 @@ export const SuitCycler = (props) => { ); }; -const SuitCyclerContent = (props) => { - const { act, data } = useBackend(); +const SuitCyclerContent = (props: { + selectedDepartment: string | undefined; + selectedSpecies: string | undefined; + onSelectedDepartment: Function; + onSelectedSpecies: Function; +}) => { + const { act, data } = useBackend(); const { safeties, occupied, @@ -136,7 +160,6 @@ const SuitCyclerContent = (props) => { { minValue={1} maxValue={max_uv_level} stepPixelSize={30} - onChange={(e, val) => act('radlevel', { radlevel: val })} + onChange={(e, val: number) => act('radlevel', { radlevel: val })} /> @@ -199,7 +222,7 @@ const SuitCyclerUV = (props) => { }; const SuitCyclerLocked = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { model_text, userHasAccess } = data; diff --git a/tgui/packages/tgui/interfaces/SuitStorageUnit.jsx b/tgui/packages/tgui/interfaces/SuitStorageUnit.tsx similarity index 90% rename from tgui/packages/tgui/interfaces/SuitStorageUnit.jsx rename to tgui/packages/tgui/interfaces/SuitStorageUnit.tsx index 4bfcbf0bea1..1970d29059d 100644 --- a/tgui/packages/tgui/interfaces/SuitStorageUnit.jsx +++ b/tgui/packages/tgui/interfaces/SuitStorageUnit.tsx @@ -1,3 +1,5 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, @@ -11,8 +13,23 @@ import { } from '../components'; import { Window } from '../layouts'; +type Data = { + broken: BooleanLike; + panelopen: BooleanLike; + locked: BooleanLike; + open: BooleanLike; + safeties: BooleanLike; + uv_active: BooleanLike; + uv_super: BooleanLike; + helmet: string | null; + suit: string | null; + mask: string | null; + storage: null; + occupied: BooleanLike; +}; + export const SuitStorageUnit = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { panelopen, uv_active, broken } = data; let subTemplate = ; @@ -33,7 +50,7 @@ export const SuitStorageUnit = (props) => { }; const SuitStorageUnitContent = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { locked, open, safeties, occupied, suit, helmet, mask } = data; return ( @@ -139,7 +156,7 @@ const SuitStorageUnitContent = (props) => { }; const SuitStorageUnitPanel = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { safeties, uv_super } = data; return ( @@ -178,9 +195,9 @@ const SuitStorageUnitPanel = (props) => { A thick old-style button, with 2 grimy LED lights next to it. The{' '} {safeties ? ( - GREEN + GREEN ) : ( - RED + RED )}{' '} LED is on. @@ -192,7 +209,7 @@ const SuitStorageUnitPanel = (props) => { icon="caret-square-right" style={{ border: '4px solid #777', - 'border-style': 'outset', + borderStyle: 'outset', }} onClick={() => act('togglesafeties')} /> diff --git a/tgui/packages/tgui/interfaces/SupermatterMonitor.jsx b/tgui/packages/tgui/interfaces/SupermatterMonitor.tsx similarity index 90% rename from tgui/packages/tgui/interfaces/SupermatterMonitor.jsx rename to tgui/packages/tgui/interfaces/SupermatterMonitor.tsx index 61af33d3e20..3391c30aadc 100644 --- a/tgui/packages/tgui/interfaces/SupermatterMonitor.jsx +++ b/tgui/packages/tgui/interfaces/SupermatterMonitor.tsx @@ -1,4 +1,5 @@ import { toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; import { toTitleCase } from 'common/string'; import { useBackend } from '../backend'; @@ -13,6 +14,22 @@ import { } from '../components'; import { Window } from '../layouts'; +type Data = { + active: BooleanLike; + SM_area: string; + SM_integrity: number; + SM_power: number; + SM_ambienttemp: number; + SM_ambientpressure: number; + SM_EPR: number; + SM_gas_O2: number; + SM_gas_CO2: number; + SM_gas_N2: number; + SM_gas_PH: number; + SM_gas_N2O: number; + supermatters: { area_name: string; integrity: number; uid: number }[]; +}; + // As of 2020-08-06 this isn't actually ever used, but it needs to exist because that's what tgui_modules expect export const SupermatterMonitor = (props) => ( @@ -23,7 +40,7 @@ export const SupermatterMonitor = (props) => ( ); export const SupermatterMonitorContent = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { active } = data; @@ -35,7 +52,7 @@ export const SupermatterMonitorContent = (props) => { }; const SupermatterMonitorList = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { supermatters } = data; @@ -74,7 +91,7 @@ const SupermatterMonitorList = (props) => { }; const SupermatterMonitorActive = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { SM_area, @@ -102,7 +119,6 @@ const SupermatterMonitorActive = (props) => { { - const { act, data } = useBackend(); - const { supply_points } = data; - const { name, cost, manifest, ref, random } = modal.args; - return ( - supply_points} - onClick={() => act('request_crate', { ref: ref })} - > - {'Buy - ' + cost + ' points'} - - } - > - - {manifest.map((m) => ( - {m} - ))} - - - ); -}; - -export const SupplyConsole = (props) => { - const { act, data } = useBackend(); - modalRegisterBodyOverride('view_crate', viewCrateContents); - return ( - - - - - - - - - - ); -}; - -const SupplyConsoleShuttleStatus = (props) => { - const { act, data } = useBackend(); - - const { supply_points, shuttle, shuttle_auth } = data; - - let shuttle_buttons = null; - let showShuttleForce = false; - - if (shuttle_auth) { - if (shuttle.launch === 1 && shuttle.mode === 0) { - shuttle_buttons = ( - act('send_shuttle', { mode: 'send_away' })} - > - Send Away - - ); - } else if ( - shuttle.launch === 2 && - (shuttle.mode === 3 || shuttle.mode === 1) - ) { - shuttle_buttons = ( - act('send_shuttle', { mode: 'cancel_shuttle' })} - > - Cancel Launch - - ); - } else if (shuttle.launch === 1 && shuttle.mode === 5) { - shuttle_buttons = ( - act('send_shuttle', { mode: 'send_to_station' })} - > - Send Shuttle - - ); - } - if (shuttle.force) { - showShuttleForce = true; - } - } - - return ( - - - - - - - - - - {shuttle_buttons} - {showShuttleForce ? ( - - act('send_shuttle', { mode: 'force_shuttle' }) - } - > - Force Launch - - ) : null} - > - } - > - {shuttle.location} - - {shuttle.engine} - {shuttle.mode === 4 ? ( - - {shuttle.time > 1 ? formatTime(shuttle.time) : 'LATE'} - - ) : null} - - - - ); -}; - -const SupplyConsoleMenu = (props) => { - const { act, data } = useBackend(); - - const { order_auth } = data; - - const [tabIndex, setTabIndex] = useState(0); - - return ( - - - setTabIndex(0)} - > - Request - - setTabIndex(1)} - > - Accepted - - setTabIndex(2)} - > - Requests - - setTabIndex(3)} - > - Order history - - setTabIndex(4)} - > - Export history - - - {tabIndex === 0 ? : null} - {tabIndex === 1 ? : null} - {tabIndex === 2 ? : null} - {tabIndex === 3 ? : null} - {tabIndex === 4 ? : null} - - ); -}; - -const SupplyConsoleMenuOrder = (props) => { - const { act, data } = useBackend(); - - const { categories, supply_packs, contraband, supply_points } = data; - - const [activeCategory, setActiveCategory] = useState(null); - - const viewingPacks = flow([ - filter((val) => val.group === activeCategory), - filter((val) => !val.contraband || contraband), - sortBy((val) => val.name), - sortBy((val) => val.cost > supply_points), - ])(supply_packs); - - // const viewingPacks = sortBy(val => val.name)(supply_packs).filter(val => val.group === activeCategory); - - return ( - - - - - {categories.map((category) => ( - setActiveCategory(category)} - > - {category} - - ))} - - - - - {viewingPacks.map((pack) => ( - - - - supply_points ? 'red' : null} - onClick={() => act('request_crate', { ref: pack.ref })} - > - {pack.name} - - - - supply_points ? 'red' : null} - onClick={() => - act('request_crate_multi', { ref: pack.ref }) - } - > - # - - - - supply_points ? 'red' : null} - onClick={() => act('view_crate', { crate: pack.ref })} - > - C - - - {pack.cost} points - - - ))} - {/* Alternative collapsible style folders */} - {/* {viewingPacks.map(pack => ( - - - {pack.manifest.map(item => ( - - {item} - - ))} - - {"Buy - " + pack.cost + " points"} - - - - ))} */} - - - - - ); -}; - -const SupplyConsoleMenuOrderList = (props) => { - const { act, data } = useBackend(); - const { mode } = props; - const { orders, order_auth, supply_points } = data; - - const displayedOrders = orders.filter( - (val) => val.status === mode || mode === 'All', - ); - - if (!displayedOrders.length) { - return No orders found.; - } - - return ( - - {mode === 'Requested' && order_auth ? ( - act('clear_all_requests')} - > - Clear all requests - - ) : null} - {displayedOrders.map((order, i) => ( - act('delete_order', { ref: order.ref })} - > - Delete Record - - ) : null - } - > - - {order.entries.map((field, i) => - field.entry ? ( - { - act('edit_order_value', { - ref: order.ref, - edit: field.field, - default: field.entry, - }); - }} - > - Edit - - ) : null - } - > - {field.entry} - - ) : null, - )} - {mode === 'All' ? ( - {order.status} - ) : null} - - {order_auth && mode === 'Requested' ? ( - <> - supply_points} - onClick={() => act('approve_order', { ref: order.ref })} - > - Approve - - act('deny_order', { ref: order.ref })} - > - Deny - - > - ) : null} - - ))} - - ); -}; - -const SupplyConsoleMenuHistoryExport = (props) => { - const { act, data } = useBackend(); - const { receipts, order_auth } = data; - - if (!receipts.length) { - return No receipts found.; - } - - return ( - - {receipts.map((r, ri) => ( - - - {r.title.map((title) => ( - - act('export_edit', { - ref: r.ref, - edit: title.field, - default: title.entry, - }) - } - > - Edit - - ) : null - } - > - {title.entry} - - ))} - {r.error ? ( - - {r.error} - - ) : ( - r.contents.map((item, i) => ( - - - act('export_edit_field', { - ref: r.ref, - index: i + 1, - edit: 'meow', - default: item.object, - }) - } - > - Edit - - - act('export_delete_field', { - ref: r.ref, - index: i + 1, - }) - } - > - Delete - - > - ) : null - } - > - {item.quantity}x -> {item.value} points - - )) - )} - - {order_auth ? ( - <> - act('export_add_field', { ref: r.ref })} - > - Add Item To Record - - act('export_delete', { ref: r.ref })} - > - Delete Record - - > - ) : null} - - ))} - - ); -}; diff --git a/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleMenu.tsx b/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleMenu.tsx new file mode 100644 index 00000000000..7a844408261 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleMenu.tsx @@ -0,0 +1,61 @@ +import { useState } from 'react'; + +import { Section, Tabs } from '../../components'; +import { SupplyConsoleMenuHistoryExport } from './SupplyConsoleMenuHistoryExport'; +import { SupplyConsoleMenuOrder } from './SupplyConsoleMenuOrder'; +import { SupplyConsoleMenuOrderList } from './SupplyConsoleMenuOrderList'; + +export const SupplyConsoleMenu = (props) => { + const [tabIndex, setTabIndex] = useState(0); + + const tab: React.JSX.Element[] = []; + + tab[0] = ; + tab[1] = ; + tab[2] = ; + tab[3] = ; + tab[4] = ; + + return ( + + + setTabIndex(0)} + > + Request + + setTabIndex(1)} + > + Accepted + + setTabIndex(2)} + > + Requests + + setTabIndex(3)} + > + Order history + + setTabIndex(4)} + > + Export history + + + {tab[tabIndex] || ''} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleMenuHistoryExport.tsx b/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleMenuHistoryExport.tsx new file mode 100644 index 00000000000..0b127bc2172 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleMenuHistoryExport.tsx @@ -0,0 +1,115 @@ +import { useBackend } from '../../backend'; +import { Button, LabeledList, Section } from '../../components'; +import { Data } from './types'; + +export const SupplyConsoleMenuHistoryExport = (props) => { + const { act, data } = useBackend(); + const { receipts, order_auth } = data; + + if (!receipts.length) { + return No receipts found.; + } + + return ( + + {receipts.map((r, ri) => ( + + + {r.title.map((title) => ( + + act('export_edit', { + ref: r.ref, + edit: title.field, + default: title.entry, + }) + } + > + Edit + + ) : ( + '' + ) + } + > + {title.entry} + + ))} + {r.error ? ( + + {r.error} + + ) : ( + r.contents.map((item, i) => ( + + + act('export_edit_field', { + ref: r.ref, + index: i + 1, + edit: 'meow', + default: item.object, + }) + } + > + Edit + + + act('export_delete_field', { + ref: r.ref, + index: i + 1, + }) + } + > + Delete + + > + ) : ( + '' + ) + } + > + {item.quantity}x -> {item.value} points + + )) + )} + + {order_auth ? ( + <> + act('export_add_field', { ref: r.ref })} + > + Add Item To Record + + act('export_delete', { ref: r.ref })} + > + Delete Record + + > + ) : ( + '' + )} + + ))} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleMenuOrder.tsx b/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleMenuOrder.tsx new file mode 100644 index 00000000000..2e253c7fdb5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleMenuOrder.tsx @@ -0,0 +1,103 @@ +import { filter, sortBy } from 'common/collections'; +import { flow } from 'common/fp'; +import { useState } from 'react'; + +import { useBackend } from '../../backend'; +import { Box, Button, Section, Stack } from '../../components'; +import { Data, supplyPack } from './types'; + +export const SupplyConsoleMenuOrder = (props) => { + const { act, data } = useBackend(); + + const { categories, supply_packs, contraband, supply_points } = data; + + const [activeCategory, setActiveCategory] = useState(null); + + const viewingPacks = flow([ + filter((val: supplyPack) => val.group === activeCategory), + filter((val: supplyPack) => !val.contraband || !!contraband), + sortBy((val: supplyPack) => val.name), + sortBy((val: supplyPack) => val.cost > supply_points), + ])(supply_packs); + + // const viewingPacks = sortBy(val => val.name)(supply_packs).filter(val => val.group === activeCategory); + + return ( + + + + + {categories.map((category) => ( + setActiveCategory(category)} + > + {category} + + ))} + + + + + {viewingPacks.map((pack) => ( + + + + supply_points ? 'red' : undefined} + onClick={() => act('request_crate', { ref: pack.ref })} + > + {pack.name} + + + + supply_points ? 'red' : undefined} + onClick={() => + act('request_crate_multi', { ref: pack.ref }) + } + > + # + + + + supply_points ? 'red' : undefined} + onClick={() => act('view_crate', { crate: pack.ref })} + > + C + + + {pack.cost} points + + + ))} + {/* Alternative collapsible style folders */} + {/* {viewingPacks.map(pack => ( + + + {pack.manifest.map(item => ( + + {item} + + ))} + + {"Buy - " + pack.cost + " points"} + + + + ))} */} + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleMenuOrderList.tsx b/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleMenuOrderList.tsx new file mode 100644 index 00000000000..7c2fe705910 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleMenuOrderList.tsx @@ -0,0 +1,112 @@ +import { useBackend } from '../../backend'; +import { Button, LabeledList, Section } from '../../components'; +import { Data } from './types'; + +export const SupplyConsoleMenuOrderList = (props) => { + const { act, data } = useBackend(); + const { mode } = props; + const { orders, order_auth, supply_points } = data; + + const displayedOrders = orders.filter( + (val) => val.status === mode || mode === 'All', + ); + + if (!displayedOrders.length) { + return No orders found.; + } + + return ( + + {mode === 'Requested' && order_auth ? ( + act('clear_all_requests')} + > + Clear all requests + + ) : ( + '' + )} + {displayedOrders.map((order, i) => ( + act('delete_order', { ref: order.ref })} + > + Delete Record + + ) : ( + '' + ) + } + > + + {order.entries.map((field, i) => + field.entry ? ( + { + act('edit_order_value', { + ref: order.ref, + edit: field.field, + default: field.entry, + }); + }} + > + Edit + + ) : ( + '' + ) + } + > + {field.entry} + + ) : ( + '' + ), + )} + {mode === 'All' ? ( + {order.status} + ) : ( + '' + )} + + {order_auth && mode === 'Requested' ? ( + <> + supply_points} + onClick={() => act('approve_order', { ref: order.ref })} + > + Approve + + act('deny_order', { ref: order.ref })} + > + Deny + + > + ) : ( + '' + )} + + ))} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleShuttleStatus.tsx b/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleShuttleStatus.tsx new file mode 100644 index 00000000000..3afc92fcbf9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SupplyConsole/SupplyConsoleShuttleStatus.tsx @@ -0,0 +1,94 @@ +import { useBackend } from '../../backend'; +import { AnimatedNumber, Button, LabeledList, Section } from '../../components'; +import { formatTime } from '../../format'; +import { Data } from './types'; + +export const SupplyConsoleShuttleStatus = (props) => { + const { act, data } = useBackend(); + + const { supply_points, shuttle, shuttle_auth } = data; + + let shuttle_buttons: React.JSX.Element | string = ''; + let showShuttleForce = false; + + if (shuttle_auth) { + if (shuttle.launch === 1 && shuttle.mode === 0) { + shuttle_buttons = ( + act('send_shuttle', { mode: 'send_away' })} + > + Send Away + + ); + } else if ( + shuttle.launch === 2 && + (shuttle.mode === 3 || shuttle.mode === 1) + ) { + shuttle_buttons = ( + act('send_shuttle', { mode: 'cancel_shuttle' })} + > + Cancel Launch + + ); + } else if (shuttle.launch === 1 && shuttle.mode === 5) { + shuttle_buttons = ( + act('send_shuttle', { mode: 'send_to_station' })} + > + Send Shuttle + + ); + } + if (shuttle.force) { + showShuttleForce = true; + } + } + + return ( + + + + + + + + + + {shuttle_buttons} + {showShuttleForce ? ( + + act('send_shuttle', { mode: 'force_shuttle' }) + } + > + Force Launch + + ) : ( + '' + )} + > + } + > + {shuttle.location} + + {shuttle.engine} + {shuttle.mode === 4 ? ( + + {shuttle.time > 1 ? formatTime(shuttle.time) : 'LATE'} + + ) : ( + '' + )} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/SupplyConsole/index.tsx b/tgui/packages/tgui/interfaces/SupplyConsole/index.tsx new file mode 100644 index 00000000000..f237ba15e84 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SupplyConsole/index.tsx @@ -0,0 +1,24 @@ +import { Section } from '../../components'; +import { + ComplexModal, + modalRegisterBodyOverride, +} from '../../interfaces/common/ComplexModal'; +import { Window } from '../../layouts'; +import { SupplyConsoleMenu } from './SupplyConsoleMenu'; +import { SupplyConsoleShuttleStatus } from './SupplyConsoleShuttleStatus'; +import { viewCrateContents } from './viewCrateContents'; + +export const SupplyConsole = (props) => { + modalRegisterBodyOverride('view_crate', viewCrateContents); + return ( + + + + + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/SupplyConsole/types.ts b/tgui/packages/tgui/interfaces/SupplyConsole/types.ts new file mode 100644 index 00000000000..2d4f26c7eb4 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SupplyConsole/types.ts @@ -0,0 +1,65 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + shuttle_auth: BooleanLike; + order_auth: BooleanLike; + shuttle: shuttleStatus; + supply_points: number; + orders: order[]; + receipts: receipt[]; + contraband: BooleanLike; + modal: modalData; + supply_packs: supplyPack[]; + categories: string[]; +}; + +export type modalData = { + id: string; + text: string; + args: { + name: string; + cost: number; + manifest: string[]; + ref: string; + random: number; + }; + modal_type: string; +}; + +export type supplyPack = { + name: string; + cost: number; + group: string; + contraband: BooleanLike; + manifest: string[]; + random: number; + ref: string; +}; + +type shuttleStatus = { + location: string; + mode: number; + time: number; + launch: number; + engine: string; + force: BooleanLike; +}; + +type order = { + ref: string; + status: string; + cost: number; + entries: { field: string; entry: string }[]; +}; + +type receipt = { + ref: string; + contents: { + object: string; + quantity: number; + value: number; + error: string | undefined; + }[]; + error: string | undefined; + title: { field: string; entry: string }[]; +}; diff --git a/tgui/packages/tgui/interfaces/SupplyConsole/viewCrateContents.tsx b/tgui/packages/tgui/interfaces/SupplyConsole/viewCrateContents.tsx new file mode 100644 index 00000000000..368cc9d37d0 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SupplyConsole/viewCrateContents.tsx @@ -0,0 +1,36 @@ +import { useBackend } from '../../backend'; +import { Box, Button, Section } from '../../components'; +import { Data, modalData } from './types'; + +export const viewCrateContents = (modal: modalData) => { + const { act, data } = useBackend(); + const { supply_points } = data; + const { name, cost, manifest, ref, random } = modal.args; + return ( + supply_points} + onClick={() => act('request_crate', { ref: ref })} + > + {'Buy - ' + cost + ' points'} + + } + > + + {manifest.map((m) => ( + {m} + ))} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/TelecommsLogBrowser.jsx b/tgui/packages/tgui/interfaces/TelecommsLogBrowser.tsx similarity index 78% rename from tgui/packages/tgui/interfaces/TelecommsLogBrowser.jsx rename to tgui/packages/tgui/interfaces/TelecommsLogBrowser.tsx index 23061efb988..f344e009b2e 100644 --- a/tgui/packages/tgui/interfaces/TelecommsLogBrowser.jsx +++ b/tgui/packages/tgui/interfaces/TelecommsLogBrowser.tsx @@ -1,4 +1,5 @@ import { toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { @@ -11,30 +12,76 @@ import { } from '../components'; import { Window } from '../layouts'; +type Data = { + universal_translate: BooleanLike; + network: string; + temp: { color: string; text: string } | null; + servers: server[]; + selectedServer: selectedServer | null; +}; + +type server = { id: string; name: string }; + +type selectedServer = { + id: string; + totalTraffic: number; + logs: log[] | []; +}; + +type log = { + name: string; + input_type: string; + id: number; + parameters: Record; +}; + export const TelecommsLogBrowser = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { universal_translate, network, temp, servers, selectedServer } = data; return ( - {temp ? ( - - + {(temp && temp.color === 'bad' && ( + + {temp.text} act('cleartemp')} /> - + - ) : null} + )) || + (temp && temp.color !== 'bad' && ( + + + {temp.text} + + act('cleartemp')} + /> + + + )) || + ''} { ); }; -const TelecommsServerSelection = (props) => { - const { act, data } = useBackend(); +const TelecommsServerSelection = (props: { + network: string; + servers: server[]; +}) => { + const { act } = useBackend(); const { network, servers } = props; if (!servers || !servers.length) { @@ -108,8 +158,12 @@ const TelecommsServerSelection = (props) => { ); }; -const TelecommsSelectedServer = (props) => { - const { act, data } = useBackend(); +const TelecommsSelectedServer = (props: { + network: string; + server: selectedServer; + universal_translate: BooleanLike; +}) => { + const { act } = useBackend(); const { network, server, universal_translate } = props; return ( @@ -184,8 +238,7 @@ const TelecommsSelectedServer = (props) => { ); }; -const TelecommsLog = (props) => { - const { act, data } = useBackend(); +const TelecommsLog = (props: { log?: log; error?: BooleanLike }) => { const { log, error } = props; const { timecode, name, race, job, message } = (log && log.parameters) || { diff --git a/tgui/packages/tgui/interfaces/TelecommsMachineBrowser.jsx b/tgui/packages/tgui/interfaces/TelecommsMachineBrowser.tsx similarity index 72% rename from tgui/packages/tgui/interfaces/TelecommsMachineBrowser.jsx rename to tgui/packages/tgui/interfaces/TelecommsMachineBrowser.tsx index 4c923d8d129..e2e69a38315 100644 --- a/tgui/packages/tgui/interfaces/TelecommsMachineBrowser.jsx +++ b/tgui/packages/tgui/interfaces/TelecommsMachineBrowser.tsx @@ -2,30 +2,66 @@ import { useBackend } from '../backend'; import { Box, Button, LabeledList, NoticeBox, Section } from '../components'; import { Window } from '../layouts'; +type Data = { + network: string; + temp: { color: string; text: string } | null; + machinelist: machine[] | []; + selectedMachine: Required< + machine & { + links: machine[] | undefined; + } + > | null; +}; + +type machine = { id: string; name: string }; + export const TelecommsMachineBrowser = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { network, temp, machinelist, selectedMachine } = data; return ( - {temp ? ( - - + {(temp && temp.color === 'bad' && ( + + {temp.text} act('cleartemp')} /> - + - ) : null} + )) || + (temp && temp.color !== 'bad' && ( + + + {temp.text} + + act('cleartemp')} + /> + + + )) || + ''} { - const { act, data } = useBackend(); +type Data = { + temp: { color: string; text: string } | null; + on: BooleanLike; + id: string | null; + network: string | null; + autolinkers: BooleanLike; + shadowlink: BooleanLike; + options: options; + linked: { ref: string; name: string; id: string; index: number }[]; + filter: { name: string; freq: string }[]; + multitool: BooleanLike; + multitool_buffer: { name: string; id: string } | null; +}; - const { - // All - temp, - on, - id, - network, - autolinkers, - shadowlink, - options, - linked, - filter, - multitool, - multitool_buffer, - } = data; +type options = { + use_listening_level: BooleanLike; + use_broadcasting: BooleanLike; + use_receiving: BooleanLike; + listening_level: BooleanLike; + broadcasting: BooleanLike; + receiving: BooleanLike; + use_change_freq: BooleanLike; + change_freq: number | undefined; + use_broadcast_range: BooleanLike; + range: number | undefined; + minRange: number | undefined; + maxRange: number | undefined; + use_receive_range: BooleanLike; +}; + +export const TelecommsMultitoolMenu = (props) => { + const { data } = useBackend(); + + const { options } = data; return ( @@ -33,17 +52,15 @@ export const TelecommsMultitoolMenu = (props) => { }; const TelecommsMultitoolMenuStatus = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { // All - temp, on, id, network, autolinkers, shadowlink, - options, linked, filter, multitool, @@ -75,16 +92,20 @@ const TelecommsMultitoolMenuStatus = (props) => { {shadowlink ? ( Active. - ) : null} + ) : ( + '' + )} {multitool ? ( {multitool_buffer ? ( <> {multitool_buffer.name} ({multitool_buffer.id}) > - ) : null} + ) : ( + '' + )} act('link') : () => act('buffer') @@ -98,9 +119,13 @@ const TelecommsMultitoolMenuStatus = (props) => { act('flush')}> Flush - ) : null} + ) : ( + '' + )} - ) : null} + ) : ( + '' + )} @@ -128,9 +153,9 @@ const TelecommsMultitoolMenuStatus = (props) => { } > - {filter.map((f) => ( + {filter.map((f, i) => ( { ))} {!filter || filter.length === 0 ? ( No filters. - ) : null} + ) : ( + '' + )} ); }; -const TelecommsMultitoolMenuPolymorphicOptions = (props) => { - const { act, data } = useBackend(); +const TelecommsMultitoolMenuPolymorphicOptions = (props: { + options: options; +}) => { + const { act } = useBackend(); const { // Relay @@ -193,7 +222,9 @@ const TelecommsMultitoolMenuPolymorphicOptions = (props) => { {listening_level ? 'Yes' : 'No'} - ) : null} + ) : ( + '' + )} {use_broadcasting ? ( { {broadcasting ? 'Yes' : 'No'} - ) : null} + ) : ( + '' + )} {use_receiving ? ( { {receiving ? 'Yes' : 'No'} - ) : null} + ) : ( + '' + )} {use_change_freq ? ( { {change_freq ? 'Yes (' + change_freq + ')' : 'No'} - ) : null} + ) : ( + '' + )} {use_broadcast_range || use_receive_range ? ( { onDrag={(e, val) => act('range', { range: val })} /> - ) : null} + ) : ( + '' + )} ); diff --git a/tgui/packages/tgui/interfaces/TelesciConsole.jsx b/tgui/packages/tgui/interfaces/TelesciConsole.tsx similarity index 76% rename from tgui/packages/tgui/interfaces/TelesciConsole.jsx rename to tgui/packages/tgui/interfaces/TelesciConsole.tsx index 624878b641a..fb8d2d9c994 100644 --- a/tgui/packages/tgui/interfaces/TelesciConsole.jsx +++ b/tgui/packages/tgui/interfaces/TelesciConsole.tsx @@ -1,4 +1,5 @@ import { sortBy } from 'common/collections'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { @@ -12,8 +13,27 @@ import { } from '../components'; import { Window } from '../layouts'; +type Data = { + noTelepad: BooleanLike; + insertedGps: string | undefined; + rotation: number | undefined; + currentZ: number | undefined; + cooldown: number | undefined; + crystalCount: number | undefined; + maxCrystals: number | undefined; + maxPossibleDistance: number | undefined; + maxAllowedDistance: number | undefined; + distance: number | undefined; + tempMsg: string | undefined; + sectorOptions: string[] | undefined; + lastTeleData: + | { src_x: number; src_y: number; distance: number; time: number } + | undefined + | null; +}; + export const TelesciConsole = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { noTelepad } = data; @@ -37,7 +57,7 @@ const TelesciNoTelepadError = (props) => { }; export const TelesciConsoleContent = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { insertedGps, @@ -100,16 +120,17 @@ export const TelesciConsoleContent = (props) => { /> - {sortBy((v) => Number(v))(sectorOptions).map((z) => ( - act('setz', { setz: z })} - > - {z} - - ))} + {sectorOptions && + sortBy((v) => Number(v))(sectorOptions).map((z: number) => ( + act('setz', { setz: z })} + > + {z} + + ))} act('send')}> diff --git a/tgui/packages/tgui/interfaces/TimeClock.jsx b/tgui/packages/tgui/interfaces/TimeClock.tsx similarity index 69% rename from tgui/packages/tgui/interfaces/TimeClock.jsx rename to tgui/packages/tgui/interfaces/TimeClock.tsx index eaed24b90d0..71271c8aa5b 100644 --- a/tgui/packages/tgui/interfaces/TimeClock.jsx +++ b/tgui/packages/tgui/interfaces/TimeClock.tsx @@ -1,4 +1,5 @@ import { toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { @@ -12,8 +13,25 @@ import { import { Window } from '../layouts'; import { RankIcon } from './common/RankIcon'; +type Data = { + card: string | null; + department_hours: Record | undefined; + user_name: string; + assignment: string | null; + job_datum: { + title: string; + departments: string; + selection_color: string; + economic_modifier: number; + timeoff_factor: number; + pto_department: string; + } | null; + allow_change_job: BooleanLike; + job_choices: Record | null; +}; + export const TimeClock = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { department_hours, @@ -33,24 +51,25 @@ export const TimeClock = (props) => { OOC Note: PTO acquired is account-wide and shared across all characters. Info listed below is not IC information. - + - {Object.keys(department_hours).map((key) => ( - 6 - ? 'good' - : department_hours[key] > 1 - ? 'average' - : 'bad' - } - > - {toFixed(department_hours[key], 1)}{' '} - {department_hours[key] === 1 ? 'hour' : 'hours'} - - ))} + {!!department_hours && + Object.keys(department_hours).map((key) => ( + 6 + ? 'good' + : department_hours[key] > 1 + ? 'average' + : 'bad' + } + > + {toFixed(department_hours[key], 1)}{' '} + {department_hours[key] === 1 ? 'hour' : 'hours'} + + ))} @@ -105,21 +124,23 @@ export const TimeClock = (props) => { ) && ( {(job_datum.timeoff_factor > 0 && - ((department_hours[job_datum.pto_department] > 0 && ( - act('switch-to-offduty')} - > - Go Off-Duty - - )) || ( + ((!!department_hours && + department_hours[job_datum.pto_department] > 0 && ( + act('switch-to-offduty')} + > + Go Off-Duty + + )) || ( Warning: You do not have enough accrued time off to go off-duty. ))) || - (Object.keys(job_choices).length && + (!!job_choices && + Object.keys(job_choices).length && Object.keys(job_choices).map((job) => { let alt_titles = job_choices[job]; diff --git a/tgui/packages/tgui/interfaces/Turbolift.jsx b/tgui/packages/tgui/interfaces/Turbolift.tsx similarity index 86% rename from tgui/packages/tgui/interfaces/Turbolift.jsx rename to tgui/packages/tgui/interfaces/Turbolift.tsx index 778f152c7d1..ecf48110b61 100644 --- a/tgui/packages/tgui/interfaces/Turbolift.jsx +++ b/tgui/packages/tgui/interfaces/Turbolift.tsx @@ -1,14 +1,32 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Button, Flex, Section } from '../components'; import { Window } from '../layouts'; +type Data = { + doors_open: BooleanLike; + fire_mode: BooleanLike; + floors: floor[]; +}; + +type floor = { + id: number; + ref: string; + queued: BooleanLike; + target: BooleanLike; + current: BooleanLike; + label: string; + name: string; +}; + export const Turbolift = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { floors, doors_open, fire_mode } = data; return ( - + { - const { data } = useBackend(); - - const [screen, setScreen] = useState(0); - - const { telecrystals } = data; - return ( - - - - {(screen === 0 && ( - - )) || - (screen === 1 && ) || ( - Error - )} - - - ); -}; - -const UplinkHeader = (props) => { - const { act, data } = useBackend(); - - const { screen, setScreen } = props; - - const { discount_name, discount_amount, offer_expiry } = data; - - return ( - - - setScreen(0)}> - Request Items - - setScreen(1)}> - Exploitable Information - - - - {(discount_amount < 100 && ( - - {discount_name} - {discount_amount}% off. Offer expires at:{' '} - {offer_expiry} - - )) || No items currently discounted.} - - - ); -}; - -const ExploitableInformation = (props) => { - const { act, data } = useBackend(); - - const { exploit, locked_records } = data; - - return ( - act('view_exploits', { id: 0 })}> - Back - - ) - } - > - {(exploit && ( - - - {exploit.name} - {exploit.sex} - - {exploit.species} - - {exploit.age} - {exploit.rank} - - {exploit.home_system} - - - {exploit.birthplace} - - - {exploit.citizenship} - - - {exploit.faction} - - - {exploit.religion} - - - {exploit.fingerprint} - - - {exploit.antagfaction} - - - Acquired Information - - {exploit.nanoui_exploit_record.split('').map((m) => ( - {m} - ))} - - - - )) || - locked_records.map((record) => ( - act('view_exploits', { id: record.id })} - > - {record.name} - - ))} - - ); -}; - -export const GenericUplink = (props) => { - const { currencyAmount = 0, currencySymbol = 'â‚®' } = props; - const { act, data } = useBackend(); - const { compactMode, lockable, categories = [] } = data; - const [searchText, setSearchText] = useState(''); - const [selectedCategory, setSelectedCategory] = useState(categories[0]?.name); - const testSearch = createSearch(searchText, (item) => { - return item.name + item.desc; - }); - 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(currencyAmount)} {currencySymbol} - - } - buttons={ - <> - Search - setSearchText(value)} - mx={1} - /> - act('compact_toggle')} - > - {compactMode ? 'Compact' : 'Detailed'} - - {!!lockable && ( - act('lock')}> - Lock - - )} - > - } - > - - {searchText.length === 0 && ( - - - {categories.map((category) => ( - setSelectedCategory(category.name)} - > - {category.name} ({category.items?.length || 0}) - - ))} - - - )} - - {items.length === 0 && ( - - {searchText.length === 0 - ? 'No items in this category.' - : 'No results found.'} - - )} - 0 || compactMode} - currencyAmount={currencyAmount} - currencySymbol={currencySymbol} - items={items} - /> - - - - ); -}; - -const ItemList = (props) => { - const { compactMode, currencyAmount, currencySymbol } = props; - const { act } = useBackend(); - const [hoveredItem, setHoveredItem] = useState({}); - const hoveredCost = (hoveredItem && hoveredItem.cost) || 0; - // Append extra hover data to items - const items = props.items.map((item) => { - const notSameItem = hoveredItem && hoveredItem.name !== item.name; - const notEnoughHovered = currencyAmount - hoveredCost < item.cost; - const disabledDueToHovered = notSameItem && notEnoughHovered; - const disabled = currencyAmount < item.cost || disabledDueToHovered; - return { - ...item, - disabled, - }; - }); - if (compactMode) { - return ( - - {items.map((item) => ( - - {decodeHtmlEntities(item.name)} - - setHoveredItem(item)} - onmouseout={() => setHoveredItem({})} - onClick={() => - act('buy', { - ref: item.ref, - }) - } - > - {formatMoney(item.cost) + ' ' + currencySymbol} - - - - ))} - - ); - } - return items.map((item) => ( - setHoveredItem(item)} - onmouseout={() => setHoveredItem({})} - onClick={() => - act('buy', { - ref: item.ref, - }) - } - > - {item.cost + ' ' + currencySymbol} - - } - > - {decodeHtmlEntities(item.desc)} - - )); -}; diff --git a/tgui/packages/tgui/interfaces/Uplink/ExploitableInformation.tsx b/tgui/packages/tgui/interfaces/Uplink/ExploitableInformation.tsx new file mode 100644 index 00000000000..842e58b0719 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Uplink/ExploitableInformation.tsx @@ -0,0 +1,75 @@ +import { useBackend } from '../../backend'; +import { Box, Button, LabeledList, Section } from '../../components'; +import { Data } from './types'; + +export const ExploitableInformation = (props) => { + const { act, data } = useBackend(); + + const { exploit, locked_records } = data; + + return ( + act('view_exploits', { id: 0 })}> + Back + + ) + } + > + {(exploit && ( + + + {exploit.name} + {exploit.sex} + + {exploit.species} + + {exploit.age} + {exploit.rank} + + {exploit.home_system} + + + {exploit.birthplace} + + + {exploit.citizenship} + + + {exploit.faction} + + + {exploit.religion} + + + {exploit.fingerprint} + + + {exploit.antagfaction} + + + Acquired Information + + {exploit.nanoui_exploit_record.split('').map((m) => ( + {m} + ))} + + + + )) || + (locked_records && + locked_records.map((record) => ( + act('view_exploits', { id: record.id })} + > + {record.name} + + )))} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Uplink/GenericUplink.tsx b/tgui/packages/tgui/interfaces/Uplink/GenericUplink.tsx new file mode 100644 index 00000000000..0965bf2f0e0 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Uplink/GenericUplink.tsx @@ -0,0 +1,109 @@ +import { createSearch } from 'common/string'; +import { useState } from 'react'; + +import { useBackend } from '../../backend'; +import { + Box, + Button, + Flex, + Input, + NoticeBox, + Section, + Tabs, +} from '../../components'; +import { formatMoney } from '../../format'; +import { MAX_SEARCH_RESULTS } from './constants'; +import { ItemList } from './ItemList'; +import { Data } from './types'; + +export const GenericUplink = (props: { + currencyAmount: number; + currencySymbol: string; +}) => { + const { act, data } = useBackend(); + + const { currencyAmount = 0, currencySymbol = 'â‚®' } = props; + + const { compactMode, lockable, categories = [] } = data; + + const [searchText, setSearchText] = useState(''); + const [selectedCategory, setSelectedCategory] = useState(categories[0]?.name); + const testSearch = createSearch(searchText, (item) => { + return item.name + item.desc; + }); + 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(currencyAmount)} {currencySymbol} + + } + buttons={ + <> + Search + setSearchText(value)} + mx={1} + /> + act('compact_toggle')} + > + {compactMode ? 'Compact' : 'Detailed'} + + {!!lockable && ( + act('lock')}> + Lock + + )} + > + } + > + + {searchText.length === 0 && ( + + + {categories.map((category) => ( + setSelectedCategory(category.name)} + > + {category.name} ({category.items?.length || 0}) + + ))} + + + )} + + {items.length === 0 && ( + + {searchText.length === 0 + ? 'No items in this category.' + : 'No results found.'} + + )} + 0 || compactMode} + currencyAmount={currencyAmount} + currencySymbol={currencySymbol} + items={items} + /> + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Uplink/ItemList.tsx b/tgui/packages/tgui/interfaces/Uplink/ItemList.tsx new file mode 100644 index 00000000000..967ed27189d --- /dev/null +++ b/tgui/packages/tgui/interfaces/Uplink/ItemList.tsx @@ -0,0 +1,65 @@ +import { BooleanLike } from 'common/react'; +import { decodeHtmlEntities } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Button, Section, Table } from '../../components'; +import { formatMoney } from '../../format'; +import { item } from './types'; + +export const ItemList = (props: { + compactMode: BooleanLike; + currencyAmount: number; + currencySymbol: string; + items: item[]; +}) => { + const { act } = useBackend(); + + const { compactMode, currencyAmount, currencySymbol, items } = props; + + if (compactMode) { + return ( + + {items.map((item) => ( + + {decodeHtmlEntities(item.name)} + + + act('buy', { + ref: item.ref, + }) + } + > + {formatMoney(item.cost) + ' ' + currencySymbol} + + + + ))} + + ); + } + return items.map((item) => ( + + act('buy', { + ref: item.ref, + }) + } + > + {item.cost + ' ' + currencySymbol} + + } + > + {decodeHtmlEntities(item.desc)} + + )); +}; diff --git a/tgui/packages/tgui/interfaces/Uplink/UplinkHeader.tsx b/tgui/packages/tgui/interfaces/Uplink/UplinkHeader.tsx new file mode 100644 index 00000000000..74877faaf38 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Uplink/UplinkHeader.tsx @@ -0,0 +1,40 @@ +import { useBackend } from '../../backend'; +import { Box, Section, Tabs } from '../../components'; +import { Data } from './types'; + +export const UplinkHeader = (props: { + screen: number; + setScreen: Function; +}) => { + const { data } = useBackend(); + + const { screen, setScreen } = props; + + const { discount_name, discount_amount, offer_expiry } = data; + + return ( + + + setScreen(0)}> + Request Items + + setScreen(1)}> + Exploitable Information + + + + {(discount_amount < 100 && ( + + {discount_name} - {discount_amount}% off. Offer expires at:{' '} + {offer_expiry} + + )) || No items currently discounted.} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Uplink/constants.ts b/tgui/packages/tgui/interfaces/Uplink/constants.ts new file mode 100644 index 00000000000..01c2c8d98f9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Uplink/constants.ts @@ -0,0 +1 @@ +export const MAX_SEARCH_RESULTS = 25; diff --git a/tgui/packages/tgui/interfaces/Uplink/index.tsx b/tgui/packages/tgui/interfaces/Uplink/index.tsx new file mode 100644 index 00000000000..f7ee3f9b57f --- /dev/null +++ b/tgui/packages/tgui/interfaces/Uplink/index.tsx @@ -0,0 +1,30 @@ +import { useState } from 'react'; + +import { useBackend } from '../../backend'; +import { Section } from '../../components'; +import { Window } from '../../layouts'; +import { ExploitableInformation } from './ExploitableInformation'; +import { GenericUplink } from './GenericUplink'; +import { Data } from './types'; +import { UplinkHeader } from './UplinkHeader'; + +export const Uplink = (props) => { + const { data } = useBackend(); + + const [screen, setScreen] = useState(0); + + const { telecrystals } = data; + return ( + + + + {(screen === 0 && ( + + )) || + (screen === 1 && ) || ( + Error + )} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Uplink/types.ts b/tgui/packages/tgui/interfaces/Uplink/types.ts new file mode 100644 index 00000000000..8b870ae2350 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Uplink/types.ts @@ -0,0 +1,31 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + telecrystals: number; + lockable: BooleanLike; + compactMode: BooleanLike; + discount_name: string; + discount_amount: number; + offer_expiry: string; + exploit: exploit | null; + locked_records: { name: string; id: number }[] | null; + categories: { name: string; items: item[] | null }[]; +}; + +type exploit = { + nanoui_exploit_record: string; + name: string; + sex: string; + age: string; + species: string; + rank: string; + home_system: string; + birthplace: string; + citizenship: string; + faction: string; + religion: string; + fingerprint: string; + antagfaction: string; +}; + +export type item = { name: string; cost: number; desc: string; ref: string }; diff --git a/tgui/packages/tgui/interfaces/Vending.jsx b/tgui/packages/tgui/interfaces/Vending.tsx similarity index 75% rename from tgui/packages/tgui/interfaces/Vending.jsx rename to tgui/packages/tgui/interfaces/Vending.tsx index 34bd7a19a99..420e72e5959 100644 --- a/tgui/packages/tgui/interfaces/Vending.jsx +++ b/tgui/packages/tgui/interfaces/Vending.tsx @@ -1,6 +1,6 @@ import { filter } from 'common/collections'; import { flow } from 'common/fp'; -import { classes } from 'common/react'; +import { BooleanLike, classes } from 'common/react'; import { createSearch } from 'common/string'; import { useState } from 'react'; @@ -16,8 +16,32 @@ import { } from '../components'; import { Window } from '../layouts'; -const VendingRow = (props) => { - const { act, data } = useBackend(); +type Data = { + chargesMoney: BooleanLike; + products: product[]; + coin: string | BooleanLike; + actively_vending: string | null; + panel: BooleanLike; + speaker: BooleanLike; + guestNotice: string; + userMoney: number; + user: { name: string; job: string }; +}; + +type product = { + key: number; + name: string; + desc: string; + price: number; + color: string; + isatom: BooleanLike; + path: string; + amount: number; + max_amount: number; // Not used? +}; + +const VendingRow = (props: { product: product }) => { + const { act, data } = useBackend(); const { actively_vending } = data; const { product } = props; return ( @@ -27,8 +51,7 @@ const VendingRow = (props) => { )) || @@ -73,11 +96,11 @@ const VendingRow = (props) => { }; export const Vending = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { panel } = data; - const [searchText, setSearchText] = useState(''); + const [searchText, setSearchText] = useState(''); - function handleSearchText(value) { + function handleSearchText(value: string) { setSearchText(value); } @@ -91,8 +114,11 @@ export const Vending = (props) => { ); }; -export const VendingProducts = (props) => { - const { act, data } = useBackend(); +export const VendingProducts = (props: { + searchText: string; + onSearch: Function; +}) => { + const { act, data } = useBackend(); const { coin, chargesMoney, user, userMoney, guestNotice, products } = data; // Just in case we still have undefined values in the list @@ -120,13 +146,13 @@ export const VendingProducts = (props) => { props.onSearch(value)} + onInput={(e, value: string) => props.onSearch(value)} /> - {myproducts.map((product) => ( - + {myproducts.map((product, i) => ( + ))} @@ -145,7 +171,7 @@ export const VendingProducts = (props) => { }; export const VendingMaintenance = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { speaker } = data; return ( @@ -169,9 +195,11 @@ export const VendingMaintenance = (props) => { /** * Search box */ -export const prepareSearch = (products, searchText = '') => { - const testSearch = - createSearch < ProductRecord > (searchText, (product) => product.name); +export const prepareSearch = (products: product[], searchText: string = '') => { + const testSearch = createSearch( + searchText, + (product: product) => product.name, + ); return flow([ // Optional search term searchText && filter(testSearch), diff --git a/tgui/packages/tgui/interfaces/VorePanel.jsx b/tgui/packages/tgui/interfaces/VorePanel.jsx deleted file mode 100644 index bd5106c6001..00000000000 --- a/tgui/packages/tgui/interfaces/VorePanel.jsx +++ /dev/null @@ -1,2498 +0,0 @@ -import { classes } from 'common/react'; -import { capitalize } from 'common/string'; -import { useState } from 'react'; - -import { useBackend } from '../backend'; -import { - Box, - Button, - Collapsible, - Divider, - Flex, - Icon, - LabeledList, - NoticeBox, - Section, - Tabs, -} from '../components'; -import { Window } from '../layouts'; - -const stats = [null, 'average', 'bad']; - -const digestModeToColor = { - Hold: null, - Digest: 'red', - Absorb: 'purple', - Unabsorb: 'purple', - Drain: 'orange', - Selective: 'orange', - Shrink: 'teal', - Grow: 'teal', - 'Size Steal': 'teal', - Heal: 'green', - 'Encase In Egg': 'blue', -}; - -const digestModeToPreyMode = { - Hold: 'being held.', - Digest: 'being digested.', - Absorb: 'being absorbed.', - Unabsorb: 'being unabsorbed.', - Drain: 'being drained.', - Selective: 'being processed.', - Shrink: 'being shrunken.', - Grow: 'being grown.', - 'Size Steal': 'having your size stolen.', - Heal: 'being healed.', - 'Encase In Egg': 'being encased in an egg.', -}; - -/** - * There are three main sections to this UI. - * - The Inside Panel, where all relevant data for interacting with a belly you're in is located. - * - The Belly Selection Panel, where you can select what belly people will go into and customize the active one. - * - User Preferences, where you can adjust all of your vore preferences on the fly. - */ -export const VorePanel = (props) => { - const { act, data } = useBackend(); - - const [tabIndex, setTabIndex] = useState(0); - - const tabs = []; - - tabs[0] = ; - - tabs[1] = ; - - return ( - - - {(data.unsaved_changes && ( - - - Warning: Unsaved Changes! - - act('saveprefs')}> - Save Prefs - - - - { - act('saveprefs'); - act('exportpanel'); - }} - > - Save Prefs & Export Selected Belly - - - - - )) || - null} - - - setTabIndex(0)}> - Bellies - - - setTabIndex(1)}> - Preferences - - - - {tabs[tabIndex] || 'Error'} - - - ); -}; - -const VoreInsidePanel = (props) => { - const { act, data } = useBackend(); - - const { absorbed, belly_name, belly_mode, desc, pred, contents, ref } = - data.inside; - - if (!belly_name) { - return You aren't inside anyone.; - } - - return ( - - - You are currently {absorbed ? 'absorbed into' : 'inside'} - - - - {pred}'s - - - - {belly_name} - - - - and you are - - - - {digestModeToPreyMode[belly_mode]} - - - {desc} - {(contents.length && ( - - - - )) || - 'There is nothing else around you.'} - - ); -}; - -const VoreBellySelectionAndCustomization = (props) => { - const { act, data } = useBackend(); - - const { our_bellies, selected } = data; - - return ( - - - - - act('newbelly')}> - New - - - act('exportpanel')}> - Export - - - - {our_bellies.map((belly) => ( - act('bellypick', { bellypick: belly.ref })} - > - - {belly.name} ({belly.contents}) - - - ))} - - - - - {selected && ( - - - - )} - - - ); -}; - -/** - * Subtemplate of VoreBellySelectionAndCustomization - */ -const VoreSelectedBelly = (props) => { - const { act } = useBackend(); - - const { belly } = props; - const { contents } = belly; - - const [tabIndex, setTabIndex] = useState(0); - - const tabs = []; - - tabs[0] = ; - - tabs[1] = ; - - tabs[2] = ; - - tabs[3] = ; - - tabs[4] = ; - - tabs[5] = ; - - tabs[6] = ; - - return ( - <> - - setTabIndex(0)}> - Controls - - setTabIndex(1)}> - Descriptions - - setTabIndex(2)}> - Options - - setTabIndex(3)}> - Sounds - - setTabIndex(4)}> - Visuals - - setTabIndex(5)}> - Interactions - - setTabIndex(6)}> - Contents ({contents.length}) - - - {tabs[tabIndex] || 'Error'} - > - ); -}; - -const VoreSelectedBellyControls = (props) => { - const { act } = useBackend(); - - const { belly } = props; - const { belly_name, mode, item_mode, addons } = belly; - - return ( - - - act('move_belly', { dir: -1 })} - /> - act('move_belly', { dir: 1 })} - /> - > - } - > - act('set_attribute', { attribute: 'b_name' })}> - {belly_name} - - - - act('set_attribute', { attribute: 'b_mode' })} - > - {mode} - - - - {(addons.length && addons.join(', ')) || 'None'} - act('set_attribute', { attribute: 'b_addons' })} - ml={1} - icon="plus" - /> - - - act('set_attribute', { attribute: 'b_item_mode' })} - > - {item_mode} - - - - act('set_attribute', { attribute: 'b_del' })} - > - Delete Belly - - - - ); -}; - -const VoreSelectedBellyDescriptions = (props) => { - const { act } = useBackend(); - - const { belly } = props; - const { - verb, - release_verb, - desc, - absorbed_desc, - mode, - message_mode, - escapable, - interacts, - emote_active, - } = belly; - - return ( - - act('set_attribute', { attribute: 'b_desc' })} - icon="pen" - /> - } - > - {desc} - - - act('set_attribute', { attribute: 'b_absorbed_desc' }) - } - icon="pen" - /> - } - > - {absorbed_desc} - - - act('set_attribute', { attribute: 'b_verb' })}> - {verb} - - - - act('set_attribute', { attribute: 'b_release_verb' })} - > - {release_verb} - - - - - act('set_attribute', { - attribute: 'b_message_mode', - }) - } - icon={message_mode ? 'toggle-on' : 'toggle-off'} - selected={message_mode} - > - {message_mode ? 'True' : 'False'} - - - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'em' }) - } - > - Examine Message (when full) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'ema' }) - } - > - Examine Message (with absorbed victims) - - - {message_mode || escapable ? ( - <> - - - {(message_mode || - !!interacts.transferlocation || - !!interacts.transferlocation_secondary) && ( - - )} - {(message_mode || - interacts.digestchance > 0 || - interacts.absorbchance > 0) && ( - - )} - > - ) : ( - '' - )} - {(message_mode || - mode === 'Digest' || - mode === 'Selective' || - mode === 'Absorb' || - mode === 'Unabsorb') && ( - - )} - {emote_active ? ( - - ) : ( - '' - )} - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'reset' }) - } - > - Reset Messages - - - - ); -}; - -const VoreSelectedBellyDescriptionsStruggle = (props) => { - const { act } = useBackend(); - - return ( - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'smo' }) - } - > - Struggle Message (outside) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'smi' }) - } - > - Struggle Message (inside) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'asmo' }) - } - > - Absorbed Struggle Message (outside) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'asmi' }) - } - > - Absorbed Struggle Message (inside) - - - ); -}; - -const VoreSelectedBellyDescriptionsEscape = (props) => { - const { act } = useBackend(); - - const { message_mode, interacts } = props; - - return ( - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'escap' }) - } - > - Escape Attempt Message (to prey) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'escao' }) - } - > - Escape Attempt Message (to you) - - {(message_mode || interacts.escapechance > 0) && ( - <> - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'escp', - }) - } - > - Escape Message (to prey) - - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'esco', - }) - } - > - Escape Message (to you) - - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'escout', - }) - } - > - Escape Message (outside) - - > - )} - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'escip' }) - } - > - Escape Item Message (to prey) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'escio' }) - } - > - Escape Item Message (to you) - - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'esciout', - }) - } - > - Escape Item Message (outside) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'escfp' }) - } - > - Escape Fail Message (to prey) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'escfo' }) - } - > - Escape Fail Message (to you) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'aescap' }) - } - > - Absorbed Escape Attempt Message (to prey) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'aescao' }) - } - > - Absorbed Escape Attempt Message (to you) - - {(message_mode || interacts.escapechance_absorbed > 0) && ( - <> - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'aescp', - }) - } - > - Absorbed Escape Message (to prey) - - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'aesco', - }) - } - > - Absorbed Escape Message (to you) - - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'aescout', - }) - } - > - Absorbed Escape Message (outside) - - > - )} - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'aescfp' }) - } - > - Absorbed Escape Fail Message (to prey) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'aescfo' }) - } - > - Absorbed Escape Fail Message (to you) - - - ); -}; - -const VoreSelectedBellyDescriptionsTransfer = (props) => { - const { act } = useBackend(); - - const { message_mode, interacts } = props; - - return ( - - {(message_mode || !!interacts.transferlocation) && ( - <> - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'trnspp', - }) - } - > - Primary Transfer Message (to prey) - - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'trnspo', - }) - } - > - Primary Transfer Message (to you) - - > - )} - {(message_mode || !!interacts.transferlocation_secondary) && ( - <> - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'trnssp', - }) - } - > - Secondary Transfer Message (to prey) - - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'trnsso', - }) - } - > - Secondary Transfer Message (to you) - - > - )} - - ); -}; - -const VoreSelectedBellyDescriptionsInteractionChance = (props) => { - const { act } = useBackend(); - - const { message_mode, interacts } = props; - - return ( - - {(message_mode || interacts.digestchance > 0) && ( - <> - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'stmodp', - }) - } - > - Interaction Chance Digest Message (to prey) - - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'stmodo', - }) - } - > - Interaction Chance Digest Message (to you) - - > - )} - {(message_mode || interacts.absorbchance > 0) && ( - <> - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'stmoap', - }) - } - > - Interaction Chance Absorb Message (to prey) - - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'stmoao', - }) - } - > - Interaction Chance Absorb Message (to you) - - > - )} - - ); -}; - -const VoreSelectedBellyDescriptionsBellymode = (props) => { - const { act } = useBackend(); - - const { message_mode, mode } = props; - - return ( - - {(message_mode || mode === 'Digest' || mode === 'Selective') && ( - <> - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'dmp' }) - } - > - Digest Message (to prey) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'dmo' }) - } - > - Digest Message (to you) - - > - )} - {(message_mode || mode === 'Absorb' || mode === 'Selective') && ( - <> - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'amp' }) - } - > - Absorb Message (to prey) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'amo' }) - } - > - Absorb Message (to you) - - > - )} - {(message_mode || mode === 'Unabsorb') && ( - <> - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'uamp' }) - } - > - Unabsorb Message (to prey) - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'uamo' }) - } - > - Unabsorb Message (to you) - - > - )} - - ); -}; - -const VoreSelectedBellyDescriptionsIdle = (props) => { - const { act } = useBackend(); - - const { message_mode, mode } = props; - - return ( - - {(message_mode || mode === 'Hold' || mode === 'Selective') && ( - <> - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'im_hold', - }) - } - > - Idle Messages (Hold) - - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'im_holdabsorbed', - }) - } - > - Idle Messages (Hold Absorbed) - - > - )} - {(message_mode || mode === 'Digest' || mode === 'Selective') && ( - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'im_digest', - }) - } - > - Idle Messages (Digest) - - )} - {(message_mode || mode === 'Absorb' || mode === 'Selective') && ( - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'im_absorb', - }) - } - > - Idle Messages (Absorb) - - )} - {(message_mode || mode === 'Unabsorb') && ( - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'im_unabsorb', - }) - } - > - Idle Messages (Unabsorb) - - )} - {(message_mode || mode === 'Drain' || mode === 'Selective') && ( - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'im_drain' }) - } - > - Idle Messages (Drain) - - )} - {(message_mode || mode === 'Heal') && ( - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'im_heal' }) - } - > - Idle Messages (Heal) - - )} - {(message_mode || mode === 'Size Steal') && ( - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'im_steal' }) - } - > - Idle Messages (Size Steal) - - )} - {(message_mode || mode === 'Shrink') && ( - - act('set_attribute', { - attribute: 'b_msgs', - msgtype: 'im_shrink', - }) - } - > - Idle Messages (Shrink) - - )} - {(message_mode || mode === 'Grow') && ( - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'im_grow' }) - } - > - Idle Messages (Grow) - - )} - {(message_mode || mode === 'Encase In Egg') && ( - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'im_egg' }) - } - > - Idle Messages (Encase In Egg) - - )} - - ); -}; - -const VoreSelectedBellyOptions = (props) => { - const { act, data } = useBackend(); - - const { host_mobtype } = data; - const { is_cyborg, is_vore_simple_mob } = host_mobtype; - const { belly } = props; - const { - can_taste, - nutrition_percent, - digest_brute, - digest_burn, - digest_oxy, - digest_tox, - digest_clone, - bulge_size, - display_absorbed_examine, - shrink_grow_size, - emote_time, - emote_active, - contaminates, - contaminate_flavor, - contaminate_color, - egg_type, - selective_preference, - save_digest_mode, - eating_privacy_local, - silicon_belly_overlay_preference, - belly_mob_mult, - belly_item_mult, - belly_overall_mult, - drainmode, - } = belly; - - return ( - - - - - act('set_attribute', { attribute: 'b_tastes' })} - icon={can_taste ? 'toggle-on' : 'toggle-off'} - selected={can_taste} - > - {can_taste ? 'Yes' : 'No'} - - - - - act('set_attribute', { attribute: 'b_contaminate' }) - } - icon={contaminates ? 'toggle-on' : 'toggle-off'} - selected={contaminates} - > - {contaminates ? 'Yes' : 'No'} - - - {(contaminates && ( - <> - - - act('set_attribute', { - attribute: 'b_contamination_flavor', - }) - } - icon="pen" - > - {contaminate_flavor} - - - - - act('set_attribute', { attribute: 'b_contamination_color' }) - } - icon="pen" - > - {capitalize(contaminate_color)} - - - > - )) || - null} - - - act('set_attribute', { attribute: 'b_nutritionpercent' }) - } - > - {nutrition_percent + '%'} - - - - - act('set_attribute', { attribute: 'b_bulge_size' }) - } - > - {bulge_size * 100 + '%'} - - - - - act('set_attribute', { - attribute: 'b_display_absorbed_examine', - }) - } - icon={display_absorbed_examine ? 'toggle-on' : 'toggle-off'} - selected={display_absorbed_examine} - > - {display_absorbed_examine ? 'True' : 'False'} - - - - - act('set_attribute', { attribute: 'b_eating_privacy' }) - } - > - {capitalize(eating_privacy_local)} - - - - - - act('set_attribute', { attribute: 'b_save_digest_mode' }) - } - icon={save_digest_mode ? 'toggle-on' : 'toggle-off'} - selected={save_digest_mode} - > - {save_digest_mode ? 'True' : 'False'} - - - - - - - - - - act('set_attribute', { attribute: 'b_emoteactive' }) - } - icon={emote_active ? 'toggle-on' : 'toggle-off'} - selected={emote_active} - > - {emote_active ? 'Active' : 'Inactive'} - - - - act('set_attribute', { attribute: 'b_emotetime' })} - > - {emote_time + ' seconds'} - - - - act('set_attribute', { attribute: 'b_brute_dmg' })} - > - {digest_brute} - - - - act('set_attribute', { attribute: 'b_burn_dmg' })} - > - {digest_burn} - - - - act('set_attribute', { attribute: 'b_oxy_dmg' })} - > - {digest_oxy} - - - - act('set_attribute', { attribute: 'b_tox_dmg' })} - > - {digest_tox} - - - - act('set_attribute', { attribute: 'b_clone_dmg' })} - > - {digest_clone} - - - - act('set_attribute', { attribute: 'b_drainmode' })} - > - {drainmode} - - - - - act('set_attribute', { attribute: 'b_grow_shrink' }) - } - > - {shrink_grow_size * 100 + '%'} - - - - act('set_attribute', { attribute: 'b_egg_type' })} - icon="pen" - > - {capitalize(egg_type)} - - - - - act('set_attribute', { - attribute: 'b_selective_mode_pref_toggle', - }) - } - > - {capitalize(selective_preference)} - - - - - - ); -}; - -const VoreSelectedMobTypeBellyButtons = (props) => { - const { act, data } = useBackend(); - const { host_mobtype } = data; - const { is_cyborg, is_vore_simple_mob } = host_mobtype; - const { belly } = props; - const { - silicon_belly_overlay_preference, - belly_mob_mult, - belly_item_mult, - belly_overall_mult, - } = belly; - - if (is_cyborg) { - return ( - - - - - act('set_attribute', { attribute: 'b_silicon_belly' }) - } - > - {capitalize(silicon_belly_overlay_preference)} - - - - - act('set_attribute', { attribute: 'b_belly_mob_mult' }) - } - > - {belly_mob_mult} - - - - - act('set_attribute', { attribute: 'b_belly_item_mult' }) - } - > - {belly_item_mult} - - - - - act('set_attribute', { - attribute: 'b_belly_overall_mult', - }) - } - > - {belly_overall_mult} - - - - - ); - } else if (is_vore_simple_mob) { - return ( - // For now, we're only returning empty. TODO: Simple mob belly controls - - - - ); - } else { - return ( - // Returning Empty element - - - - ); - } -}; - -const VoreSelectedBellySounds = (props) => { - const { act } = useBackend(); - - const { belly } = props; - const { is_wet, wet_loop, fancy, sound, release_sound } = belly; - - return ( - - - - - act('set_attribute', { attribute: 'b_wetness' })} - icon={is_wet ? 'toggle-on' : 'toggle-off'} - selected={is_wet} - > - {is_wet ? 'Yes' : 'No'} - - - - act('set_attribute', { attribute: 'b_wetloop' })} - icon={wet_loop ? 'toggle-on' : 'toggle-off'} - selected={wet_loop} - > - {wet_loop ? 'Yes' : 'No'} - - - - - act('set_attribute', { attribute: 'b_fancy_sound' }) - } - icon={fancy ? 'toggle-on' : 'toggle-off'} - selected={fancy} - > - {fancy ? 'Yes' : 'No'} - - - - act('set_attribute', { attribute: 'b_sound' })} - > - {sound} - - act('set_attribute', { attribute: 'b_soundtest' })} - icon="volume-up" - /> - - - act('set_attribute', { attribute: 'b_release' })} - > - {release_sound} - - - act('set_attribute', { attribute: 'b_releasesoundtest' }) - } - icon="volume-up" - /> - - - - - ); -}; - -const VoreSelectedBellyVisuals = (props) => { - const { act } = useBackend(); - - const { belly } = props; - const { - belly_fullscreen, - possible_fullscreens, - disable_hud, - belly_fullscreen_color, - belly_fullscreen_color_secondary, - belly_fullscreen_color_trinary, - mapRef, - colorization_enabled, - vore_sprite_flags, - affects_voresprite, - absorbed_voresprite, - absorbed_multiplier, - item_voresprite, - item_multiplier, - health_voresprite, - resist_animation, - voresprite_size_factor, - belly_sprite_option_shown, - belly_sprite_to_affect, - undergarment_chosen, - undergarment_if_none, - undergarment_color, - tail_option_shown, - tail_to_change_to, - tail_colouration, - tail_extra_overlay, - tail_extra_overlay2, - } = belly; - - return ( - <> - - - - - - act('set_attribute', { attribute: 'b_affects_vore_sprites' }) - } - icon={affects_voresprite ? 'toggle-on' : 'toggle-off'} - selected={affects_voresprite} - > - {affects_voresprite ? 'Yes' : 'No'} - - - {affects_voresprite ? ( - - - {(vore_sprite_flags.length && vore_sprite_flags.join(', ')) || - 'None'} - - act('set_attribute', { attribute: 'b_vore_sprite_flags' }) - } - ml={1} - icon="plus" - /> - - - - act('set_attribute', { - attribute: 'b_count_absorbed_prey_for_sprites', - }) - } - icon={absorbed_voresprite ? 'toggle-on' : 'toggle-off'} - selected={absorbed_voresprite} - > - {absorbed_voresprite ? 'Yes' : 'No'} - - - - - act('set_attribute', { - attribute: 'b_absorbed_multiplier', - }) - } - > - {absorbed_multiplier} - - - - - act('set_attribute', { - attribute: 'b_count_items_for_sprites', - }) - } - icon={item_voresprite ? 'toggle-on' : 'toggle-off'} - selected={item_voresprite} - > - {item_voresprite ? 'Yes' : 'No'} - - - - - act('set_attribute', { attribute: 'b_item_multiplier' }) - } - > - {item_multiplier} - - - - - act('set_attribute', { - attribute: 'b_health_impacts_size', - }) - } - icon={health_voresprite ? 'toggle-on' : 'toggle-off'} - selected={health_voresprite} - > - {health_voresprite ? 'Yes' : 'No'} - - - - - act('set_attribute', { attribute: 'b_resist_animation' }) - } - icon={resist_animation ? 'toggle-on' : 'toggle-off'} - selected={resist_animation} - > - {resist_animation ? 'Yes' : 'No'} - - - - - act('set_attribute', { - attribute: 'b_size_factor_sprites', - }) - } - > - {voresprite_size_factor} - - - {belly_sprite_option_shown ? ( - - - act('set_attribute', { - attribute: 'b_belly_sprite_to_affect', - }) - } - > - {belly_sprite_to_affect} - - - ) : ( - '' - )} - {tail_option_shown && - vore_sprite_flags.includes('Undergarment addition') ? ( - - - - act('set_attribute', { - attribute: 'b_undergarment_choice', - }) - } - > - {undergarment_chosen} - - - - - act('set_attribute', { - attribute: 'b_undergarment_if_none', - }) - } - > - {undergarment_if_none} - - - - ) : ( - '' - )} - {tail_option_shown && - vore_sprite_flags.includes('Tail adjustment') ? ( - - - act('set_attribute', { - attribute: 'b_tail_to_change_to', - }) - } - > - {tail_to_change_to} - - - ) : ( - '' - )} - - ) : ( - '' - )} - - - - - - - - act('set_attribute', { - attribute: 'b_fullscreen_color', - val: null, - }) - } - > - Select Primary Color - - - - act('set_attribute', { - attribute: 'b_fullscreen_color_secondary', - val: null, - }) - } - > - Select Secondary Color - - - - act('set_attribute', { - attribute: 'b_fullscreen_color_trinary', - val: null, - }) - } - > - Select Trinary Color - - - - act('set_attribute', { attribute: 'b_colorization_enabled' }) - } - icon={colorization_enabled ? 'toggle-on' : 'toggle-off'} - selected={colorization_enabled} - > - {colorization_enabled ? 'Yes' : 'No'} - - - - - act('set_attribute', { attribute: 'b_preview_belly' }) - } - > - Preview - - - - - act('set_attribute', { attribute: 'b_clear_preview' }) - } - > - Clear - - - - - - - - - - act('set_attribute', { attribute: 'b_disable_hud' }) - } - icon={disable_hud ? 'toggle-on' : 'toggle-off'} - selected={disable_hud} - > - {disable_hud ? 'Yes' : 'No'} - - - - - - Belly styles: - - act('set_attribute', { attribute: 'b_fullscreen', val: null }) - } - > - Disabled - - {Object.keys(possible_fullscreens).map((key, index) => ( - - - act('set_attribute', { attribute: 'b_fullscreen', val: key }) - } - > - - - - ))} - - - > - ); -}; - -const VoreSelectedBellyInteractions = (props) => { - const { act } = useBackend(); - - const { belly } = props; - const { escapable, interacts } = belly; - - return ( - act('set_attribute', { attribute: 'b_escapable' })} - icon={escapable ? 'toggle-on' : 'toggle-off'} - selected={escapable} - > - {escapable ? 'Interactions On' : 'Interactions Off'} - - } - > - {escapable ? ( - - - - act('set_attribute', { attribute: 'b_escapechance' }) - } - > - {interacts.escapechance + '%'} - - - - - act('set_attribute', { attribute: 'b_escapechance_absorbed' }) - } - > - {interacts.escapechance_absorbed + '%'} - - - - - act('set_attribute', { attribute: 'b_escapetime' }) - } - > - {interacts.escapetime / 10 + 's'} - - - - - - act('set_attribute', { attribute: 'b_transferchance' }) - } - > - {interacts.transferchance + '%'} - - - - - act('set_attribute', { attribute: 'b_transferlocation' }) - } - > - {interacts.transferlocation - ? interacts.transferlocation - : 'Disabled'} - - - - - - act('set_attribute', { - attribute: 'b_transferchance_secondary', - }) - } - > - {interacts.transferchance_secondary + '%'} - - - - - act('set_attribute', { - attribute: 'b_transferlocation_secondary', - }) - } - > - {interacts.transferlocation_secondary - ? interacts.transferlocation_secondary - : 'Disabled'} - - - - - - act('set_attribute', { attribute: 'b_absorbchance' }) - } - > - {interacts.absorbchance + '%'} - - - - - act('set_attribute', { attribute: 'b_digestchance' }) - } - > - {interacts.digestchance + '%'} - - - - ) : ( - 'These options only display while interactions are turned on.' - )} - - ); -}; - -const VoreContentsPanel = (props) => { - const { act, data } = useBackend(); - const { show_pictures } = data; - const { contents, belly, outside = false } = props; - - return ( - <> - {(outside && ( - act('pick_from_outside', { pickall: true })} - > - All - - )) || - null} - {(show_pictures && ( - - {contents.map((thing) => ( - - - act( - thing.outside ? 'pick_from_outside' : 'pick_from_inside', - { - pick: thing.ref, - belly: belly, - }, - ) - } - > - - - {thing.name} - - ))} - - )) || ( - - {contents.map((thing) => ( - - - act( - thing.outside ? 'pick_from_outside' : 'pick_from_inside', - { - pick: thing.ref, - belly: belly, - }, - ) - } - > - Interact - - - ))} - - )} - > - ); -}; - -const VoreUserPreferences = (props) => { - const { act, data } = useBackend(); - - const { - digestable, - devourable, - resizable, - feeding, - absorbable, - digest_leave_remains, - allowmobvore, - permit_healbelly, - show_vore_fx, - can_be_drop_prey, - can_be_drop_pred, - allow_inbelly_spawning, - allow_spontaneous_tf, - step_mechanics_active, - pickup_mechanics_active, - noisy, - drop_vore, - stumble_vore, - slip_vore, - throw_vore, - food_vore, - digest_pain, - nutrition_message_visible, - weight_message_visible, - eating_privacy_global, - } = data.prefs; - - const { show_pictures } = data; - - const preferences = { - digestion: { - action: 'toggle_digest', - test: digestable, - tooltip: { - main: "This button is for those who don't like being digested. It can make you undigestable.", - enable: 'Click here to allow digestion.', - disable: 'Click here to prevent digestion.', - }, - content: { - enabled: 'Digestion Allowed', - disabled: 'No Digestion', - }, - }, - absorbable: { - action: 'toggle_absorbable', - test: absorbable, - tooltip: { - main: "This button allows preds to know whether you prefer or don't prefer to be absorbed.", - enable: 'Click here to allow being absorbed.', - disable: 'Click here to disallow being absorbed.', - }, - content: { - enabled: 'Absorption Allowed', - disabled: 'No Absorption', - }, - }, - devour: { - action: 'toggle_devour', - test: devourable, - tooltip: { - main: 'This button is to toggle your ability to be devoured by others.', - enable: 'Click here to allow being devoured.', - disable: 'Click here to prevent being devoured.', - }, - content: { - enabled: 'Devouring Allowed', - disabled: 'No Devouring', - }, - }, - mobvore: { - action: 'toggle_mobvore', - test: allowmobvore, - tooltip: { - main: "This button is for those who don't like being eaten by mobs.", - enable: 'Click here to allow being eaten by mobs.', - disable: 'Click here to prevent being eaten by mobs.', - }, - content: { - enabled: 'Mobs eating you allowed', - disabled: 'No Mobs eating you', - }, - }, - feed: { - action: 'toggle_feed', - test: feeding, - tooltip: { - main: 'This button is to toggle your ability to be fed to or by others vorishly.', - enable: 'Click here to allow being fed to/by other people.', - disable: 'Click here to prevent being fed to/by other people.', - }, - content: { - enabled: 'Feeding Allowed', - disabled: 'No Feeding', - }, - }, - healbelly: { - action: 'toggle_healbelly', - test: permit_healbelly, - tooltip: { - main: - "This button is for those who don't like healbelly used on them as a mechanic." + - ' It does not affect anything, but is displayed under mechanical prefs for ease of quick checks.', - enable: 'Click here to allow being heal-bellied.', - disable: 'Click here to prevent being heal-bellied.', - }, - content: { - enabled: 'Heal-bellies Allowed', - disabled: 'No Heal-bellies', - }, - }, - dropnom_prey: { - action: 'toggle_dropnom_prey', - test: can_be_drop_prey, - tooltip: { - main: - 'This toggle is for spontaneous, environment related vore' + - ' as prey, including drop-noms, teleporters, etc.', - enable: 'Click here to allow being spontaneous prey.', - disable: 'Click here to prevent being spontaneous prey.', - }, - content: { - enabled: 'Spontaneous Prey Enabled', - disabled: 'Spontaneous Prey Disabled', - }, - }, - dropnom_pred: { - action: 'toggle_dropnom_pred', - test: can_be_drop_pred, - tooltip: { - main: - 'This toggle is for spontaneous, environment related vore' + - ' as a predator, including drop-noms, teleporters, etc.', - enable: 'Click here to allow being spontaneous pred.', - disable: 'Click here to prevent being spontaneous pred.', - }, - content: { - enabled: 'Spontaneous Pred Enabled', - disabled: 'Spontaneous Pred Disabled', - }, - }, - toggle_drop_vore: { - action: 'toggle_drop_vore', - test: drop_vore, - tooltip: { - main: - 'Allows for dropnom spontaneous vore to occur. ' + - 'Note, you still need spontaneous vore pred and/or prey enabled.', - enable: 'Click here to allow for dropnoms.', - disable: 'Click here to disable dropnoms.', - }, - content: { - enabled: 'Drop Noms Enabled', - disabled: 'Drop Noms Disabled', - }, - }, - toggle_slip_vore: { - action: 'toggle_slip_vore', - test: slip_vore, - tooltip: { - main: - 'Allows for slip related spontaneous vore to occur. ' + - 'Note, you still need spontaneous vore pred and/or prey enabled.', - enable: 'Click here to allow for slip vore.', - disable: 'Click here to disable slip vore.', - }, - content: { - enabled: 'Slip Vore Enabled', - disabled: 'Slip Vore Disabled', - }, - }, - toggle_stumble_vore: { - action: 'toggle_stumble_vore', - test: stumble_vore, - tooltip: { - main: - 'Allows for stumble related spontaneous vore to occur. ' + - ' Note, you still need spontaneous vore pred and/or prey enabled.', - enable: 'Click here to allow for stumble vore.', - disable: 'Click here to disable stumble vore.', - }, - content: { - enabled: 'Stumble Vore Enabled', - disabled: 'Stumble Vore Disabled', - }, - }, - toggle_throw_vore: { - action: 'toggle_throw_vore', - test: throw_vore, - tooltip: { - main: - 'Allows for throw related spontaneous vore to occur. ' + - ' Note, you still need spontaneous vore pred and/or prey enabled.', - enable: 'Click here to allow for throw vore.', - disable: 'Click here to disable throw vore.', - }, - content: { - enabled: 'Throw Vore Enabled', - disabled: 'Throw Vore Disabled', - }, - }, - toggle_food_vore: { - action: 'toggle_food_vore', - test: food_vore, - tooltip: { - main: - 'Allows for food related spontaneous vore to occur. ' + - ' Note, you still need spontaneous vore pred and/or prey enabled.', - enable: 'Click here to allow for food vore.', - disable: 'Click here to disable food vore.', - }, - content: { - enabled: 'Food Vore Enabled', - disabled: 'Food Vore Disabled', - }, - }, - toggle_digest_pain: { - action: 'toggle_digest_pain', - test: digest_pain, - tooltip: { - main: - 'Allows for pain messages to show when being digested. ' + - ' Can be toggled off to disable pain messages.', - enable: 'Click here to allow for digestion pain.', - disable: 'Click here to disable digestion pain.', - }, - content: { - enabled: 'Digestion Pain Enabled', - disabled: 'Digestion Pain Disabled', - }, - }, - inbelly_spawning: { - action: 'toggle_allow_inbelly_spawning', - test: allow_inbelly_spawning, - tooltip: { - main: - 'This toggle is ghosts being able to spawn in one of your bellies.' + - ' You will have to confirm again when they attempt to.', - enable: 'Click here to allow prey to spawn in you.', - disable: 'Click here to prevent prey from spawning in you.', - }, - content: { - enabled: 'Inbelly Spawning Allowed', - disabled: 'Inbelly Spawning Forbidden', - }, - }, - noisy: { - action: 'toggle_noisy', - test: noisy, - tooltip: { - main: 'Toggle audible hunger noises.', - enable: 'Click here to turn on hunger noises.', - disable: 'Click here to turn off hunger noises.', - }, - content: { - enabled: 'Hunger Noises Enabled', - disabled: 'Hunger Noises Disabled', - }, - }, - resize: { - action: 'toggle_resize', - test: resizable, - tooltip: { - main: 'This button is to toggle your ability to be resized by others.', - enable: 'Click here to allow being resized.', - disable: 'Click here to prevent being resized.', - }, - content: { - enabled: 'Resizing Allowed', - disabled: 'No Resizing', - }, - }, - steppref: { - action: 'toggle_steppref', - test: step_mechanics_active, - tooltip: { - main: '', - enable: - 'You will not participate in step mechanics.' + - ' Click to enable step mechanics.', - disable: - 'This setting controls whether or not you participate in size-based step mechanics.' + - ' Includes both stepping on others, as well as getting stepped on. Click to disable step mechanics.', - }, - content: { - enabled: 'Step Mechanics Enabled', - disabled: 'Step Mechanics Disabled', - }, - }, - vore_fx: { - action: 'toggle_fx', - test: show_vore_fx, - tooltip: { - main: '', - enable: - 'Regardless of Predator Setting, you will not see their FX settings.' + - ' Click this to enable showing FX.', - disable: - 'This setting controls whether or not a pred is allowed to mess with your HUD and fullscreen overlays.' + - ' Click to disable all FX.', - }, - content: { - enabled: 'Show Vore FX', - disabled: 'Do Not Show Vore FX', - }, - }, - remains: { - action: 'toggle_leaveremains', - test: digest_leave_remains, - tooltip: { - main: '', - enable: - 'Regardless of Predator Setting, you will not leave remains behind.' + - ' Click this to allow leaving remains.', - disable: - 'Your Predator must have this setting enabled in their belly modes to allow remains to show up,' + - ' if they do not, they will not leave your remains behind, even with this on. Click to disable remains.', - }, - content: { - enabled: 'Allow Leaving Remains', - disabled: 'Do Not Allow Leaving Remains', - }, - }, - pickuppref: { - action: 'toggle_pickuppref', - test: pickup_mechanics_active, - tooltip: { - main: '', - enable: - 'You will not participate in pick-up mechanics.' + - ' Click this to allow picking up/being picked up.', - disable: - 'Allows macros to pick you up into their hands, and you to pick up micros.' + - ' Click to disable pick-up mechanics.', - }, - content: { - enabled: 'Pick-up Mechanics Enabled', - disabled: 'Pick-up Mechanics Disabled', - }, - }, - spontaneous_tf: { - action: 'toggle_allow_spontaneous_tf', - test: allow_spontaneous_tf, - tooltip: { - main: - 'This toggle is for spontaneous or environment related transformation' + - ' as a victim, such as via chemicals.', - enable: 'Click here to allow being spontaneously transformed.', - disable: 'Click here to disable being spontaneously transformed.', - }, - content: { - enabled: 'Spontaneous TF Enabled', - disabled: 'Spontaneous TF Disabled', - }, - }, - examine_nutrition: { - action: 'toggle_nutrition_ex', - test: nutrition_message_visible, - tooltip: { - main: '', - enable: 'Click here to enable nutrition messages.', - disable: 'Click here to disable nutrition messages.', - }, - content: { - enabled: 'Examine Nutrition Messages Active', - disabled: 'Examine Nutrition Messages Inactive', - }, - }, - examine_weight: { - action: 'toggle_weight_ex', - test: weight_message_visible, - tooltip: { - main: '', - enable: 'Click here to enable weight messages.', - disable: 'Click here to disable weight messages.', - }, - content: { - enabled: 'Examine Weight Messages Active', - disabled: 'Examine Weight Messages Inactive', - }, - }, - eating_privacy_global: { - action: 'toggle_global_privacy', - test: eating_privacy_global, - tooltip: { - main: - 'Sets default belly behaviour for vorebellies for announcing' + - ' ingesting or expelling prey' + - ' Overwritten by belly-specific preferences if set.', - enable: ' Click here to turn your messages subtle', - disable: ' Click here to turn your messages loud', - }, - content: { - enabled: 'Global Vore Privacy: Subtle', - disabled: 'Global Vore Privacy: Loud', - }, - }, - }; - - return ( - act('show_pictures')} - > - Contents Preference: {show_pictures ? 'Show Pictures' : 'Show List'} - - } - > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - act('switch_selective_mode_pref')}> - Selective Mode Preference - - - - - - - - - - act('setflavor')}> - Set Taste - - - - act('setsmell')}> - Set Smell - - - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'en' }) - } - icon="flask" - fluid - > - Set Nutrition Examine Message - - - - - act('set_attribute', { attribute: 'b_msgs', msgtype: 'ew' }) - } - icon="weight-hanging" - fluid - > - Set Weight Examine Message - - - - - - - - - - act('set_vs_color')}> - Vore Sprite Color - - - - - - - - - act('saveprefs')}> - Save Prefs - - - - act('reloadprefs')}> - Reload Prefs - - - - - - ); -}; - -const VoreUserPreferenceItem = (props) => { - const { act } = useBackend(); - - const { spec, ...rest } = props; - const { action, test, tooltip, content } = spec; - - return ( - act(action)} - icon={test ? 'toggle-on' : 'toggle-off'} - selected={test} - fluid - tooltip={tooltip.main + ' ' + (test ? tooltip.disable : tooltip.enable)} - {...rest} - > - {test ? content.enabled : content.disabled} - - ); -}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreBellySelectionAndCustomization.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreBellySelectionAndCustomization.tsx new file mode 100644 index 00000000000..f3c4b4eb710 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreBellySelectionAndCustomization.tsx @@ -0,0 +1,67 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../../backend'; +import { Box, Divider, Flex, Icon, Section, Tabs } from '../../components'; +import { digestModeToColor } from './constants'; +import { bellyData, hostMob, selectedData } from './types'; +import { VoreSelectedBelly } from './VoreSelectedBelly'; + +export const VoreBellySelectionAndCustomization = (props: { + our_bellies: bellyData[]; + selected: selectedData; + host_mobtype: hostMob; + show_pictures: BooleanLike; +}) => { + const { act } = useBackend(); + + const { our_bellies, selected, show_pictures, host_mobtype } = props; + + return ( + + + + + act('newbelly')}> + New + + + act('exportpanel')}> + Export + + + + {our_bellies.map((belly) => ( + act('bellypick', { bellypick: belly.ref })} + > + + {belly.name} ({belly.contents}) + + + ))} + + + + + {selected && ( + + + + )} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreContentsPanel.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreContentsPanel.tsx new file mode 100644 index 00000000000..4c991c6f178 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreContentsPanel.tsx @@ -0,0 +1,92 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../../backend'; +import { Button, Flex, Image, LabeledList } from '../../components'; +import { stats } from './constants'; +import { contentData } from './types'; + +export const VoreContentsPanel = (props: { + contents: contentData[]; + belly?: string; + outside?: BooleanLike; + show_pictures: BooleanLike; +}) => { + const { act } = useBackend(); + const { contents, belly, outside = false, show_pictures } = props; + + return ( + <> + {(outside && ( + act('pick_from_outside', { pickall: true })} + > + All + + )) || + null} + {(show_pictures && ( + + {contents.map((thing) => ( + + + act( + thing.outside ? 'pick_from_outside' : 'pick_from_inside', + { + pick: thing.ref, + belly: belly, + }, + ) + } + > + + + {thing.name} + + ))} + + )) || ( + + {contents.map((thing) => ( + + + act( + thing.outside ? 'pick_from_outside' : 'pick_from_inside', + { + pick: thing.ref, + belly: belly, + }, + ) + } + > + Interact + + + ))} + + )} + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreInsidePanel.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreInsidePanel.tsx new file mode 100644 index 00000000000..538ed71c137 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreInsidePanel.tsx @@ -0,0 +1,56 @@ +import { BooleanLike } from 'common/react'; + +import { Box, Collapsible, Section } from '../../components'; +import { digestModeToColor, digestModeToPreyMode } from './constants'; +import { insideData } from './types'; +import { VoreContentsPanel } from './VoreContentsPanel'; + +export const VoreInsidePanel = (props: { + inside: insideData; + show_pictures: BooleanLike; +}) => { + const { inside, show_pictures } = props; + + const { absorbed, belly_name, belly_mode, desc, pred, contents, ref } = + inside; + + if (!belly_name) { + return You aren't inside anyone.; + } + + return ( + + + You are currently {absorbed ? 'absorbed into' : 'inside'} + + + + {pred}'s + + + + {belly_name} + + + + and you are + + + + {digestModeToPreyMode[belly_mode]} + + + {desc} + {(contents.length && ( + + + + )) || + 'There is nothing else around you.'} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBelly.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBelly.tsx new file mode 100644 index 00000000000..5a571302073 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBelly.tsx @@ -0,0 +1,79 @@ +import { BooleanLike } from 'common/react'; +import { useState } from 'react'; + +import { Tabs } from '../../components'; +import { hostMob, selectedData } from './types'; +import { VoreContentsPanel } from './VoreContentsPanel'; +import { VoreSelectedBellyControls } from './VoreSelectedBellyTabs/VoreSelectedBellyControls'; +import { VoreSelectedBellyDescriptions } from './VoreSelectedBellyTabs/VoreSelectedBellyDescriptions'; +import { VoreSelectedBellyInteractions } from './VoreSelectedBellyTabs/VoreSelectedBellyInteractions'; +import { VoreSelectedBellyOptions } from './VoreSelectedBellyTabs/VoreSelectedBellyOptions'; +import { VoreSelectedBellySounds } from './VoreSelectedBellyTabs/VoreSelectedBellySounds'; +import { VoreSelectedBellyVisuals } from './VoreSelectedBellyTabs/VoreSelectedBellyVisuals'; + +/** + * Subtemplate of VoreBellySelectionAndCustomization + */ +export const VoreSelectedBelly = (props: { + belly: selectedData; + host_mobtype: hostMob; + show_pictures: BooleanLike; +}) => { + const { belly, show_pictures, host_mobtype } = props; + const { contents } = belly; + + const [tabIndex, setTabIndex] = useState(0); + + const tabs: React.JSX.Element[] = []; + + tabs[0] = ; + + tabs[1] = ; + + tabs[2] = ( + + ); + + tabs[3] = ; + + tabs[4] = ; + + tabs[5] = ; + + tabs[6] = ( + + ); + + return ( + <> + + setTabIndex(0)}> + Controls + + setTabIndex(1)}> + Descriptions + + setTabIndex(2)}> + Options + + setTabIndex(3)}> + Sounds + + setTabIndex(4)}> + Visuals + + setTabIndex(5)}> + Interactions + + setTabIndex(6)}> + Contents ({contents.length}) + + + {tabs[tabIndex] || 'Error'} + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsBellymode.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsBellymode.tsx new file mode 100644 index 00000000000..67425867e70 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsBellymode.tsx @@ -0,0 +1,72 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../../../backend'; +import { Button, LabeledList } from '../../../components'; + +export const VoreSelectedBellyDescriptionsBellymode = (props: { + message_mode: BooleanLike; + mode: string; +}) => { + const { act } = useBackend(); + + const { message_mode, mode } = props; + + return ( + + {(message_mode || mode === 'Digest' || mode === 'Selective') && ( + <> + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'dmp' }) + } + > + Digest Message (to prey) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'dmo' }) + } + > + Digest Message (to you) + + > + )} + {(message_mode || mode === 'Absorb' || mode === 'Selective') && ( + <> + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'amp' }) + } + > + Absorb Message (to prey) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'amo' }) + } + > + Absorb Message (to you) + + > + )} + {(message_mode || mode === 'Unabsorb') && ( + <> + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'uamp' }) + } + > + Unabsorb Message (to prey) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'uamo' }) + } + > + Unabsorb Message (to you) + + > + )} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsEscape.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsEscape.tsx new file mode 100644 index 00000000000..d0c15fda26d --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsEscape.tsx @@ -0,0 +1,167 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../../../backend'; +import { Button, LabeledList } from '../../../components'; +import { interactData } from '../types'; + +export const VoreSelectedBellyDescriptionsEscape = (props: { + message_mode: BooleanLike; + interacts: interactData; +}) => { + const { act } = useBackend(); + + const { message_mode, interacts } = props; + + return ( + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'escap' }) + } + > + Escape Attempt Message (to prey) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'escao' }) + } + > + Escape Attempt Message (to you) + + {(message_mode || interacts.escapechance > 0) && ( + <> + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'escp', + }) + } + > + Escape Message (to prey) + + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'esco', + }) + } + > + Escape Message (to you) + + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'escout', + }) + } + > + Escape Message (outside) + + > + )} + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'escip' }) + } + > + Escape Item Message (to prey) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'escio' }) + } + > + Escape Item Message (to you) + + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'esciout', + }) + } + > + Escape Item Message (outside) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'escfp' }) + } + > + Escape Fail Message (to prey) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'escfo' }) + } + > + Escape Fail Message (to you) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'aescap' }) + } + > + Absorbed Escape Attempt Message (to prey) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'aescao' }) + } + > + Absorbed Escape Attempt Message (to you) + + {(message_mode || interacts.escapechance_absorbed > 0) && ( + <> + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'aescp', + }) + } + > + Absorbed Escape Message (to prey) + + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'aesco', + }) + } + > + Absorbed Escape Message (to you) + + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'aescout', + }) + } + > + Absorbed Escape Message (outside) + + > + )} + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'aescfp' }) + } + > + Absorbed Escape Fail Message (to prey) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'aescfo' }) + } + > + Absorbed Escape Fail Message (to you) + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsIdle.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsIdle.tsx new file mode 100644 index 00000000000..cf8a078c199 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsIdle.tsx @@ -0,0 +1,135 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../../../backend'; +import { Button, LabeledList } from '../../../components'; + +export const VoreSelectedBellyDescriptionsIdle = (props: { + message_mode: BooleanLike; + mode: string; +}) => { + const { act } = useBackend(); + + const { message_mode, mode } = props; + + return ( + + {(message_mode || mode === 'Hold' || mode === 'Selective') && ( + <> + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'im_hold', + }) + } + > + Idle Messages (Hold) + + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'im_holdabsorbed', + }) + } + > + Idle Messages (Hold Absorbed) + + > + )} + {(message_mode || mode === 'Digest' || mode === 'Selective') && ( + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'im_digest', + }) + } + > + Idle Messages (Digest) + + )} + {(message_mode || mode === 'Absorb' || mode === 'Selective') && ( + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'im_absorb', + }) + } + > + Idle Messages (Absorb) + + )} + {(message_mode || mode === 'Unabsorb') && ( + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'im_unabsorb', + }) + } + > + Idle Messages (Unabsorb) + + )} + {(message_mode || mode === 'Drain' || mode === 'Selective') && ( + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'im_drain' }) + } + > + Idle Messages (Drain) + + )} + {(message_mode || mode === 'Heal') && ( + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'im_heal' }) + } + > + Idle Messages (Heal) + + )} + {(message_mode || mode === 'Size Steal') && ( + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'im_steal' }) + } + > + Idle Messages (Size Steal) + + )} + {(message_mode || mode === 'Shrink') && ( + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'im_shrink', + }) + } + > + Idle Messages (Shrink) + + )} + {(message_mode || mode === 'Grow') && ( + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'im_grow' }) + } + > + Idle Messages (Grow) + + )} + {(message_mode || mode === 'Encase In Egg') && ( + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'im_egg' }) + } + > + Idle Messages (Encase In Egg) + + )} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsInteractionChance.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsInteractionChance.tsx new file mode 100644 index 00000000000..c65b5728763 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsInteractionChance.tsx @@ -0,0 +1,67 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../../../backend'; +import { Button, LabeledList } from '../../../components'; +import { interactData } from '../types'; + +export const VoreSelectedBellyDescriptionsInteractionChance = (props: { + message_mode: BooleanLike; + interacts: interactData; +}) => { + const { act } = useBackend(); + + const { message_mode, interacts } = props; + + return ( + + {(message_mode || interacts.digestchance > 0) && ( + <> + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'stmodp', + }) + } + > + Interaction Chance Digest Message (to prey) + + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'stmodo', + }) + } + > + Interaction Chance Digest Message (to you) + + > + )} + {(message_mode || interacts.absorbchance > 0) && ( + <> + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'stmoap', + }) + } + > + Interaction Chance Absorb Message (to prey) + + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'stmoao', + }) + } + > + Interaction Chance Absorb Message (to you) + + > + )} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsStruggle.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsStruggle.tsx new file mode 100644 index 00000000000..69d43467c46 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsStruggle.tsx @@ -0,0 +1,39 @@ +import { useBackend } from '../../../backend'; +import { Button, LabeledList } from '../../../components'; + +export const VoreSelectedBellyDescriptionsStruggle = (props) => { + const { act } = useBackend(); + + return ( + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'smo' }) + } + > + Struggle Message (outside) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'smi' }) + } + > + Struggle Message (inside) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'asmo' }) + } + > + Absorbed Struggle Message (outside) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'asmi' }) + } + > + Absorbed Struggle Message (inside) + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsTransfer.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsTransfer.tsx new file mode 100644 index 00000000000..d061b1bb33b --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsTransfer.tsx @@ -0,0 +1,67 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../../../backend'; +import { Button, LabeledList } from '../../../components'; +import { interactData } from '../types'; + +export const VoreSelectedBellyDescriptionsTransfer = (props: { + message_mode: BooleanLike; + interacts: interactData; +}) => { + const { act } = useBackend(); + + const { message_mode, interacts } = props; + + return ( + + {(message_mode || !!interacts.transferlocation) && ( + <> + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'trnspp', + }) + } + > + Primary Transfer Message (to prey) + + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'trnspo', + }) + } + > + Primary Transfer Message (to you) + + > + )} + {(message_mode || !!interacts.transferlocation_secondary) && ( + <> + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'trnssp', + }) + } + > + Secondary Transfer Message (to prey) + + + act('set_attribute', { + attribute: 'b_msgs', + msgtype: 'trnsso', + }) + } + > + Secondary Transfer Message (to you) + + > + )} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyControls.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyControls.tsx new file mode 100644 index 00000000000..b078a13c19b --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyControls.tsx @@ -0,0 +1,74 @@ +import { useBackend } from '../../../backend'; +import { Button, LabeledList } from '../../../components'; +import { digestModeToColor } from '../constants'; +import { selectedData } from '../types'; + +export const VoreSelectedBellyControls = (props: { belly: selectedData }) => { + const { act } = useBackend(); + + const { belly } = props; + const { belly_name, mode, item_mode, addons } = belly; + + return ( + + + act('move_belly', { dir: -1 })} + /> + act('move_belly', { dir: 1 })} + /> + > + } + > + act('set_attribute', { attribute: 'b_name' })}> + {belly_name} + + + + act('set_attribute', { attribute: 'b_mode' })} + > + {mode} + + + + {(addons.length && addons.join(', ')) || 'None'} + act('set_attribute', { attribute: 'b_addons' })} + ml={1} + icon="plus" + /> + + + act('set_attribute', { attribute: 'b_item_mode' })} + > + {item_mode} + + + + act('set_attribute', { attribute: 'b_del' })} + > + Delete Belly + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyDescriptions.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyDescriptions.tsx new file mode 100644 index 00000000000..1ebd89c4957 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyDescriptions.tsx @@ -0,0 +1,153 @@ +import { useBackend } from '../../../backend'; +import { Button, LabeledList } from '../../../components'; +import { selectedData } from '../types'; +import { VoreSelectedBellyDescriptionsBellymode } from '../VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsBellymode'; +import { VoreSelectedBellyDescriptionsEscape } from '../VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsEscape'; +import { VoreSelectedBellyDescriptionsIdle } from '../VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsIdle'; +import { VoreSelectedBellyDescriptionsInteractionChance } from '../VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsInteractionChance'; +import { VoreSelectedBellyDescriptionsStruggle } from '../VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsStruggle'; +import { VoreSelectedBellyDescriptionsTransfer } from '../VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsTransfer'; + +export const VoreSelectedBellyDescriptions = (props: { + belly: selectedData; +}) => { + const { act } = useBackend(); + + const { belly } = props; + const { + verb, + release_verb, + desc, + absorbed_desc, + mode, + message_mode, + escapable, + interacts, + emote_active, + } = belly; + + return ( + + act('set_attribute', { attribute: 'b_desc' })} + icon="pen" + /> + } + > + {desc} + + + act('set_attribute', { attribute: 'b_absorbed_desc' }) + } + icon="pen" + /> + } + > + {absorbed_desc} + + + act('set_attribute', { attribute: 'b_verb' })}> + {verb} + + + + act('set_attribute', { attribute: 'b_release_verb' })} + > + {release_verb} + + + + + act('set_attribute', { + attribute: 'b_message_mode', + }) + } + icon={message_mode ? 'toggle-on' : 'toggle-off'} + selected={message_mode} + > + {message_mode ? 'True' : 'False'} + + + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'em' }) + } + > + Examine Message (when full) + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'ema' }) + } + > + Examine Message (with absorbed victims) + + + {message_mode || escapable ? ( + <> + + + {(message_mode || + !!interacts.transferlocation || + !!interacts.transferlocation_secondary) && ( + + )} + {(message_mode || + interacts.digestchance > 0 || + interacts.absorbchance > 0) && ( + + )} + > + ) : ( + '' + )} + {(message_mode || + mode === 'Digest' || + mode === 'Selective' || + mode === 'Absorb' || + mode === 'Unabsorb') && ( + + )} + {emote_active ? ( + + ) : ( + '' + )} + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'reset' }) + } + > + Reset Messages + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyInteractions.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyInteractions.tsx new file mode 100644 index 00000000000..815530b714b --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyInteractions.tsx @@ -0,0 +1,123 @@ +import { useBackend } from '../../../backend'; +import { Button, LabeledList, Section } from '../../../components'; + +export const VoreSelectedBellyInteractions = (props) => { + const { act } = useBackend(); + + const { belly } = props; + const { escapable, interacts } = belly; + + return ( + act('set_attribute', { attribute: 'b_escapable' })} + icon={escapable ? 'toggle-on' : 'toggle-off'} + selected={escapable} + > + {escapable ? 'Interactions On' : 'Interactions Off'} + + } + > + {escapable ? ( + + + + act('set_attribute', { attribute: 'b_escapechance' }) + } + > + {interacts.escapechance + '%'} + + + + + act('set_attribute', { attribute: 'b_escapechance_absorbed' }) + } + > + {interacts.escapechance_absorbed + '%'} + + + + + act('set_attribute', { attribute: 'b_escapetime' }) + } + > + {interacts.escapetime / 10 + 's'} + + + + + + act('set_attribute', { attribute: 'b_transferchance' }) + } + > + {interacts.transferchance + '%'} + + + + + act('set_attribute', { attribute: 'b_transferlocation' }) + } + > + {interacts.transferlocation + ? interacts.transferlocation + : 'Disabled'} + + + + + + act('set_attribute', { + attribute: 'b_transferchance_secondary', + }) + } + > + {interacts.transferchance_secondary + '%'} + + + + + act('set_attribute', { + attribute: 'b_transferlocation_secondary', + }) + } + > + {interacts.transferlocation_secondary + ? interacts.transferlocation_secondary + : 'Disabled'} + + + + + + act('set_attribute', { attribute: 'b_absorbchance' }) + } + > + {interacts.absorbchance + '%'} + + + + + act('set_attribute', { attribute: 'b_digestchance' }) + } + > + {interacts.digestchance + '%'} + + + + ) : ( + 'These options only display while interactions are turned on.' + )} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyOptions.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyOptions.tsx new file mode 100644 index 00000000000..d14aafc68b6 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyOptions.tsx @@ -0,0 +1,241 @@ +import { capitalize } from 'common/string'; + +import { useBackend } from '../../../backend'; +import { Button, Flex, LabeledList } from '../../../components'; +import { hostMob, selectedData } from '../types'; +import { VoreSelectedMobTypeBellyButtons } from './VoreSelectedMobTypeBellyButtons'; + +export const VoreSelectedBellyOptions = (props: { + belly: selectedData; + host_mobtype: hostMob; +}) => { + const { act } = useBackend(); + + const { belly, host_mobtype } = props; + const { + can_taste, + nutrition_percent, + digest_brute, + digest_burn, + digest_oxy, + digest_tox, + digest_clone, + bulge_size, + display_absorbed_examine, + shrink_grow_size, + emote_time, + emote_active, + contaminates, + contaminate_flavor, + contaminate_color, + egg_type, + selective_preference, + save_digest_mode, + eating_privacy_local, + drainmode, + } = belly; + + return ( + + + + + act('set_attribute', { attribute: 'b_tastes' })} + icon={can_taste ? 'toggle-on' : 'toggle-off'} + selected={can_taste} + > + {can_taste ? 'Yes' : 'No'} + + + + + act('set_attribute', { attribute: 'b_contaminate' }) + } + icon={contaminates ? 'toggle-on' : 'toggle-off'} + selected={contaminates} + > + {contaminates ? 'Yes' : 'No'} + + + {(contaminates && ( + <> + + + act('set_attribute', { + attribute: 'b_contamination_flavor', + }) + } + icon="pen" + > + {contaminate_flavor} + + + + + act('set_attribute', { attribute: 'b_contamination_color' }) + } + icon="pen" + > + {capitalize(contaminate_color)} + + + > + )) || + null} + + + act('set_attribute', { attribute: 'b_nutritionpercent' }) + } + > + {nutrition_percent + '%'} + + + + + act('set_attribute', { attribute: 'b_bulge_size' }) + } + > + {bulge_size * 100 + '%'} + + + + + act('set_attribute', { + attribute: 'b_display_absorbed_examine', + }) + } + icon={display_absorbed_examine ? 'toggle-on' : 'toggle-off'} + selected={display_absorbed_examine} + > + {display_absorbed_examine ? 'True' : 'False'} + + + + + act('set_attribute', { attribute: 'b_eating_privacy' }) + } + > + {capitalize(eating_privacy_local)} + + + + + + act('set_attribute', { attribute: 'b_save_digest_mode' }) + } + icon={save_digest_mode ? 'toggle-on' : 'toggle-off'} + selected={save_digest_mode} + > + {save_digest_mode ? 'True' : 'False'} + + + + + + + + + + act('set_attribute', { attribute: 'b_emoteactive' }) + } + icon={emote_active ? 'toggle-on' : 'toggle-off'} + selected={emote_active} + > + {emote_active ? 'Active' : 'Inactive'} + + + + act('set_attribute', { attribute: 'b_emotetime' })} + > + {emote_time + ' seconds'} + + + + act('set_attribute', { attribute: 'b_brute_dmg' })} + > + {digest_brute} + + + + act('set_attribute', { attribute: 'b_burn_dmg' })} + > + {digest_burn} + + + + act('set_attribute', { attribute: 'b_oxy_dmg' })} + > + {digest_oxy} + + + + act('set_attribute', { attribute: 'b_tox_dmg' })} + > + {digest_tox} + + + + act('set_attribute', { attribute: 'b_clone_dmg' })} + > + {digest_clone} + + + + act('set_attribute', { attribute: 'b_drainmode' })} + > + {drainmode} + + + + + act('set_attribute', { attribute: 'b_grow_shrink' }) + } + > + {shrink_grow_size * 100 + '%'} + + + + act('set_attribute', { attribute: 'b_egg_type' })} + icon="pen" + > + {capitalize(egg_type)} + + + + + act('set_attribute', { + attribute: 'b_selective_mode_pref_toggle', + }) + } + > + {capitalize(selective_preference)} + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellySounds.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellySounds.tsx new file mode 100644 index 00000000000..8847e090f4d --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellySounds.tsx @@ -0,0 +1,72 @@ +import { useBackend } from '../../../backend'; +import { Button, Flex, LabeledList } from '../../../components'; +import { selectedData } from '../types'; + +export const VoreSelectedBellySounds = (props: { belly: selectedData }) => { + const { act } = useBackend(); + + const { belly } = props; + const { is_wet, wet_loop, fancy, sound, release_sound } = belly; + + return ( + + + + + act('set_attribute', { attribute: 'b_wetness' })} + icon={is_wet ? 'toggle-on' : 'toggle-off'} + selected={is_wet} + > + {is_wet ? 'Yes' : 'No'} + + + + act('set_attribute', { attribute: 'b_wetloop' })} + icon={wet_loop ? 'toggle-on' : 'toggle-off'} + selected={wet_loop} + > + {wet_loop ? 'Yes' : 'No'} + + + + + act('set_attribute', { attribute: 'b_fancy_sound' }) + } + icon={fancy ? 'toggle-on' : 'toggle-off'} + selected={fancy} + > + {fancy ? 'Yes' : 'No'} + + + + act('set_attribute', { attribute: 'b_sound' })} + > + {sound} + + act('set_attribute', { attribute: 'b_soundtest' })} + icon="volume-up" + /> + + + act('set_attribute', { attribute: 'b_release' })} + > + {release_sound} + + + act('set_attribute', { attribute: 'b_releasesoundtest' }) + } + icon="volume-up" + /> + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyVisuals.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyVisuals.tsx new file mode 100644 index 00000000000..763daa2e0d2 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyVisuals.tsx @@ -0,0 +1,345 @@ +import { classes } from 'common/react'; + +import { useBackend } from '../../../backend'; +import { Box, Button, Flex, LabeledList, Section } from '../../../components'; +import { selectedData } from '../types'; + +export const VoreSelectedBellyVisuals = (props: { belly: selectedData }) => { + const { act } = useBackend(); + + const { belly } = props; + const { + belly_fullscreen, + possible_fullscreens, + disable_hud, + belly_fullscreen_color, + belly_fullscreen_color_secondary, + belly_fullscreen_color_trinary, + colorization_enabled, + vore_sprite_flags, + affects_voresprite, + absorbed_voresprite, + absorbed_multiplier, + item_voresprite, + item_multiplier, + health_voresprite, + resist_animation, + voresprite_size_factor, + belly_sprite_option_shown, + belly_sprite_to_affect, + undergarment_chosen, + undergarment_if_none, + tail_option_shown, + tail_to_change_to, + } = belly; + + return ( + <> + + + + + + act('set_attribute', { attribute: 'b_affects_vore_sprites' }) + } + icon={affects_voresprite ? 'toggle-on' : 'toggle-off'} + selected={affects_voresprite} + > + {affects_voresprite ? 'Yes' : 'No'} + + + {affects_voresprite ? ( + + + {(vore_sprite_flags.length && vore_sprite_flags.join(', ')) || + 'None'} + + act('set_attribute', { attribute: 'b_vore_sprite_flags' }) + } + ml={1} + icon="plus" + /> + + + + act('set_attribute', { + attribute: 'b_count_absorbed_prey_for_sprites', + }) + } + icon={absorbed_voresprite ? 'toggle-on' : 'toggle-off'} + selected={absorbed_voresprite} + > + {absorbed_voresprite ? 'Yes' : 'No'} + + + + + act('set_attribute', { + attribute: 'b_absorbed_multiplier', + }) + } + > + {absorbed_multiplier} + + + + + act('set_attribute', { + attribute: 'b_count_items_for_sprites', + }) + } + icon={item_voresprite ? 'toggle-on' : 'toggle-off'} + selected={item_voresprite} + > + {item_voresprite ? 'Yes' : 'No'} + + + + + act('set_attribute', { attribute: 'b_item_multiplier' }) + } + > + {item_multiplier} + + + + + act('set_attribute', { + attribute: 'b_health_impacts_size', + }) + } + icon={health_voresprite ? 'toggle-on' : 'toggle-off'} + selected={health_voresprite} + > + {health_voresprite ? 'Yes' : 'No'} + + + + + act('set_attribute', { attribute: 'b_resist_animation' }) + } + icon={resist_animation ? 'toggle-on' : 'toggle-off'} + selected={resist_animation} + > + {resist_animation ? 'Yes' : 'No'} + + + + + act('set_attribute', { + attribute: 'b_size_factor_sprites', + }) + } + > + {voresprite_size_factor} + + + {belly_sprite_option_shown ? ( + + + act('set_attribute', { + attribute: 'b_belly_sprite_to_affect', + }) + } + > + {belly_sprite_to_affect} + + + ) : ( + '' + )} + {tail_option_shown && + vore_sprite_flags.includes('Undergarment addition') ? ( + + + + act('set_attribute', { + attribute: 'b_undergarment_choice', + }) + } + > + {undergarment_chosen} + + + + + act('set_attribute', { + attribute: 'b_undergarment_if_none', + }) + } + > + {undergarment_if_none} + + + + ) : ( + '' + )} + {tail_option_shown && + vore_sprite_flags.includes('Tail adjustment') ? ( + + + act('set_attribute', { + attribute: 'b_tail_to_change_to', + }) + } + > + {tail_to_change_to} + + + ) : ( + '' + )} + + ) : ( + '' + )} + + + + + + + + act('set_attribute', { + attribute: 'b_fullscreen_color', + val: null, + }) + } + > + Select Primary Color + + + + act('set_attribute', { + attribute: 'b_fullscreen_color_secondary', + val: null, + }) + } + > + Select Secondary Color + + + + act('set_attribute', { + attribute: 'b_fullscreen_color_trinary', + val: null, + }) + } + > + Select Trinary Color + + + + act('set_attribute', { attribute: 'b_colorization_enabled' }) + } + icon={colorization_enabled ? 'toggle-on' : 'toggle-off'} + selected={colorization_enabled} + > + {colorization_enabled ? 'Yes' : 'No'} + + + + + act('set_attribute', { attribute: 'b_preview_belly' }) + } + > + Preview + + + + + act('set_attribute', { attribute: 'b_clear_preview' }) + } + > + Clear + + + + + + + + + + act('set_attribute', { attribute: 'b_disable_hud' }) + } + icon={disable_hud ? 'toggle-on' : 'toggle-off'} + selected={disable_hud} + > + {disable_hud ? 'Yes' : 'No'} + + + + + + Belly styles: + + act('set_attribute', { attribute: 'b_fullscreen', val: null }) + } + > + Disabled + + {Object.keys(possible_fullscreens).map((key, index) => ( + + + act('set_attribute', { attribute: 'b_fullscreen', val: key }) + } + > + + + + ))} + + + > + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedMobTypeBellyButtons.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedMobTypeBellyButtons.tsx new file mode 100644 index 00000000000..15bf0c2b0f1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedMobTypeBellyButtons.tsx @@ -0,0 +1,83 @@ +import { capitalize } from 'common/string'; + +import { useBackend } from '../../../backend'; +import { Button, LabeledList, Section } from '../../../components'; +import { hostMob, selectedData } from '../types'; + +export const VoreSelectedMobTypeBellyButtons = (props: { + belly: selectedData; + host_mobtype: hostMob; +}) => { + const { act } = useBackend(); + + const { belly, host_mobtype } = props; + const { + silicon_belly_overlay_preference, + belly_mob_mult, + belly_item_mult, + belly_overall_mult, + } = belly; + + const { is_cyborg, is_vore_simple_mob } = host_mobtype; + + if (is_cyborg) { + return ( + + + + + act('set_attribute', { attribute: 'b_silicon_belly' }) + } + > + {capitalize(silicon_belly_overlay_preference)} + + + + + act('set_attribute', { attribute: 'b_belly_mob_mult' }) + } + > + {belly_mob_mult} + + + + + act('set_attribute', { attribute: 'b_belly_item_mult' }) + } + > + {belly_item_mult} + + + + + act('set_attribute', { + attribute: 'b_belly_overall_mult', + }) + } + > + {belly_overall_mult} + + + + + ); + } else if (is_vore_simple_mob) { + return ( + // For now, we're only returning empty. TODO: Simple mob belly controls + + + + ); + } else { + return ( + // Returning Empty element + + + + ); + } +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferenceItem.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferenceItem.tsx new file mode 100644 index 00000000000..c2f7ac3eb07 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferenceItem.tsx @@ -0,0 +1,26 @@ +import { useBackend } from '../../backend'; +import { Button } from '../../components'; +import { preferenceData } from './types'; + +export const VoreUserPreferenceItem = (props: { + spec: preferenceData; + [rest: string]: any; +}) => { + const { act } = useBackend(); + + const { spec, ...rest } = props; + const { action, test, tooltip, content } = spec; + + return ( + act(action)} + icon={test ? 'toggle-on' : 'toggle-off'} + selected={test} + fluid + tooltip={tooltip.main + ' ' + (test ? tooltip.disable : tooltip.enable)} + {...rest} + > + {test ? content.enabled : content.disabled} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferences.tsx.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferences.tsx.tsx new file mode 100644 index 00000000000..0913c9fb294 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferences.tsx.tsx @@ -0,0 +1,438 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../../backend'; +import { Box, Button, Divider, Flex, Section } from '../../components'; +import { prefData } from './types'; +import { VoreUserPreferencesAesthetic } from './VoreUserPreferencesTabs/VoreUserPreferencesAesthetic '; +import { VoreUserPreferencesMechanical } from './VoreUserPreferencesTabs/VoreUserPreferencesMechanical '; + +export const VoreUserPreferences = (props: { + prefs: prefData; + show_pictures: BooleanLike; +}) => { + const { act } = useBackend(); + + const { prefs, show_pictures } = props; + + const { + digestable, + devourable, + resizable, + feeding, + absorbable, + digest_leave_remains, + allowmobvore, + permit_healbelly, + show_vore_fx, + can_be_drop_prey, + can_be_drop_pred, + allow_inbelly_spawning, + allow_spontaneous_tf, + step_mechanics_active, + pickup_mechanics_active, + noisy, + drop_vore, + stumble_vore, + slip_vore, + throw_vore, + food_vore, + digest_pain, + nutrition_message_visible, + weight_message_visible, + eating_privacy_global, + } = prefs; + + const preferences = { + digestion: { + action: 'toggle_digest', + test: digestable, + tooltip: { + main: "This button is for those who don't like being digested. It can make you undigestable.", + enable: 'Click here to allow digestion.', + disable: 'Click here to prevent digestion.', + }, + content: { + enabled: 'Digestion Allowed', + disabled: 'No Digestion', + }, + }, + absorbable: { + action: 'toggle_absorbable', + test: absorbable, + tooltip: { + main: "This button allows preds to know whether you prefer or don't prefer to be absorbed.", + enable: 'Click here to allow being absorbed.', + disable: 'Click here to disallow being absorbed.', + }, + content: { + enabled: 'Absorption Allowed', + disabled: 'No Absorption', + }, + }, + devour: { + action: 'toggle_devour', + test: devourable, + tooltip: { + main: 'This button is to toggle your ability to be devoured by others.', + enable: 'Click here to allow being devoured.', + disable: 'Click here to prevent being devoured.', + }, + content: { + enabled: 'Devouring Allowed', + disabled: 'No Devouring', + }, + }, + mobvore: { + action: 'toggle_mobvore', + test: allowmobvore, + tooltip: { + main: "This button is for those who don't like being eaten by mobs.", + enable: 'Click here to allow being eaten by mobs.', + disable: 'Click here to prevent being eaten by mobs.', + }, + content: { + enabled: 'Mobs eating you allowed', + disabled: 'No Mobs eating you', + }, + }, + feed: { + action: 'toggle_feed', + test: feeding, + tooltip: { + main: 'This button is to toggle your ability to be fed to or by others vorishly.', + enable: 'Click here to allow being fed to/by other people.', + disable: 'Click here to prevent being fed to/by other people.', + }, + content: { + enabled: 'Feeding Allowed', + disabled: 'No Feeding', + }, + }, + healbelly: { + action: 'toggle_healbelly', + test: permit_healbelly, + tooltip: { + main: + "This button is for those who don't like healbelly used on them as a mechanic." + + ' It does not affect anything, but is displayed under mechanical prefs for ease of quick checks.', + enable: 'Click here to allow being heal-bellied.', + disable: 'Click here to prevent being heal-bellied.', + }, + content: { + enabled: 'Heal-bellies Allowed', + disabled: 'No Heal-bellies', + }, + }, + dropnom_prey: { + action: 'toggle_dropnom_prey', + test: can_be_drop_prey, + tooltip: { + main: + 'This toggle is for spontaneous, environment related vore' + + ' as prey, including drop-noms, teleporters, etc.', + enable: 'Click here to allow being spontaneous prey.', + disable: 'Click here to prevent being spontaneous prey.', + }, + content: { + enabled: 'Spontaneous Prey Enabled', + disabled: 'Spontaneous Prey Disabled', + }, + }, + dropnom_pred: { + action: 'toggle_dropnom_pred', + test: can_be_drop_pred, + tooltip: { + main: + 'This toggle is for spontaneous, environment related vore' + + ' as a predator, including drop-noms, teleporters, etc.', + enable: 'Click here to allow being spontaneous pred.', + disable: 'Click here to prevent being spontaneous pred.', + }, + content: { + enabled: 'Spontaneous Pred Enabled', + disabled: 'Spontaneous Pred Disabled', + }, + }, + toggle_drop_vore: { + action: 'toggle_drop_vore', + test: drop_vore, + tooltip: { + main: + 'Allows for dropnom spontaneous vore to occur. ' + + 'Note, you still need spontaneous vore pred and/or prey enabled.', + enable: 'Click here to allow for dropnoms.', + disable: 'Click here to disable dropnoms.', + }, + content: { + enabled: 'Drop Noms Enabled', + disabled: 'Drop Noms Disabled', + }, + }, + toggle_slip_vore: { + action: 'toggle_slip_vore', + test: slip_vore, + tooltip: { + main: + 'Allows for slip related spontaneous vore to occur. ' + + 'Note, you still need spontaneous vore pred and/or prey enabled.', + enable: 'Click here to allow for slip vore.', + disable: 'Click here to disable slip vore.', + }, + content: { + enabled: 'Slip Vore Enabled', + disabled: 'Slip Vore Disabled', + }, + }, + toggle_stumble_vore: { + action: 'toggle_stumble_vore', + test: stumble_vore, + tooltip: { + main: + 'Allows for stumble related spontaneous vore to occur. ' + + ' Note, you still need spontaneous vore pred and/or prey enabled.', + enable: 'Click here to allow for stumble vore.', + disable: 'Click here to disable stumble vore.', + }, + content: { + enabled: 'Stumble Vore Enabled', + disabled: 'Stumble Vore Disabled', + }, + }, + toggle_throw_vore: { + action: 'toggle_throw_vore', + test: throw_vore, + tooltip: { + main: + 'Allows for throw related spontaneous vore to occur. ' + + ' Note, you still need spontaneous vore pred and/or prey enabled.', + enable: 'Click here to allow for throw vore.', + disable: 'Click here to disable throw vore.', + }, + content: { + enabled: 'Throw Vore Enabled', + disabled: 'Throw Vore Disabled', + }, + }, + toggle_food_vore: { + action: 'toggle_food_vore', + test: food_vore, + tooltip: { + main: + 'Allows for food related spontaneous vore to occur. ' + + ' Note, you still need spontaneous vore pred and/or prey enabled.', + enable: 'Click here to allow for food vore.', + disable: 'Click here to disable food vore.', + }, + content: { + enabled: 'Food Vore Enabled', + disabled: 'Food Vore Disabled', + }, + }, + toggle_digest_pain: { + action: 'toggle_digest_pain', + test: digest_pain, + tooltip: { + main: + 'Allows for pain messages to show when being digested. ' + + ' Can be toggled off to disable pain messages.', + enable: 'Click here to allow for digestion pain.', + disable: 'Click here to disable digestion pain.', + }, + content: { + enabled: 'Digestion Pain Enabled', + disabled: 'Digestion Pain Disabled', + }, + }, + inbelly_spawning: { + action: 'toggle_allow_inbelly_spawning', + test: allow_inbelly_spawning, + tooltip: { + main: + 'This toggle is ghosts being able to spawn in one of your bellies.' + + ' You will have to confirm again when they attempt to.', + enable: 'Click here to allow prey to spawn in you.', + disable: 'Click here to prevent prey from spawning in you.', + }, + content: { + enabled: 'Inbelly Spawning Allowed', + disabled: 'Inbelly Spawning Forbidden', + }, + }, + noisy: { + action: 'toggle_noisy', + test: noisy, + tooltip: { + main: 'Toggle audible hunger noises.', + enable: 'Click here to turn on hunger noises.', + disable: 'Click here to turn off hunger noises.', + }, + content: { + enabled: 'Hunger Noises Enabled', + disabled: 'Hunger Noises Disabled', + }, + }, + resize: { + action: 'toggle_resize', + test: resizable, + tooltip: { + main: 'This button is to toggle your ability to be resized by others.', + enable: 'Click here to allow being resized.', + disable: 'Click here to prevent being resized.', + }, + content: { + enabled: 'Resizing Allowed', + disabled: 'No Resizing', + }, + }, + steppref: { + action: 'toggle_steppref', + test: step_mechanics_active, + tooltip: { + main: '', + enable: + 'You will not participate in step mechanics.' + + ' Click to enable step mechanics.', + disable: + 'This setting controls whether or not you participate in size-based step mechanics.' + + ' Includes both stepping on others, as well as getting stepped on. Click to disable step mechanics.', + }, + content: { + enabled: 'Step Mechanics Enabled', + disabled: 'Step Mechanics Disabled', + }, + }, + vore_fx: { + action: 'toggle_fx', + test: show_vore_fx, + tooltip: { + main: '', + enable: + 'Regardless of Predator Setting, you will not see their FX settings.' + + ' Click this to enable showing FX.', + disable: + 'This setting controls whether or not a pred is allowed to mess with your HUD and fullscreen overlays.' + + ' Click to disable all FX.', + }, + content: { + enabled: 'Show Vore FX', + disabled: 'Do Not Show Vore FX', + }, + }, + remains: { + action: 'toggle_leaveremains', + test: digest_leave_remains, + tooltip: { + main: '', + enable: + 'Regardless of Predator Setting, you will not leave remains behind.' + + ' Click this to allow leaving remains.', + disable: + 'Your Predator must have this setting enabled in their belly modes to allow remains to show up,' + + ' if they do not, they will not leave your remains behind, even with this on. Click to disable remains.', + }, + content: { + enabled: 'Allow Leaving Remains', + disabled: 'Do Not Allow Leaving Remains', + }, + }, + pickuppref: { + action: 'toggle_pickuppref', + test: pickup_mechanics_active, + tooltip: { + main: '', + enable: + 'You will not participate in pick-up mechanics.' + + ' Click this to allow picking up/being picked up.', + disable: + 'Allows macros to pick you up into their hands, and you to pick up micros.' + + ' Click to disable pick-up mechanics.', + }, + content: { + enabled: 'Pick-up Mechanics Enabled', + disabled: 'Pick-up Mechanics Disabled', + }, + }, + spontaneous_tf: { + action: 'toggle_allow_spontaneous_tf', + test: allow_spontaneous_tf, + tooltip: { + main: + 'This toggle is for spontaneous or environment related transformation' + + ' as a victim, such as via chemicals.', + enable: 'Click here to allow being spontaneously transformed.', + disable: 'Click here to disable being spontaneously transformed.', + }, + content: { + enabled: 'Spontaneous TF Enabled', + disabled: 'Spontaneous TF Disabled', + }, + }, + examine_nutrition: { + action: 'toggle_nutrition_ex', + test: nutrition_message_visible, + tooltip: { + main: '', + enable: 'Click here to enable nutrition messages.', + disable: 'Click here to disable nutrition messages.', + }, + content: { + enabled: 'Examine Nutrition Messages Active', + disabled: 'Examine Nutrition Messages Inactive', + }, + }, + examine_weight: { + action: 'toggle_weight_ex', + test: weight_message_visible, + tooltip: { + main: '', + enable: 'Click here to enable weight messages.', + disable: 'Click here to disable weight messages.', + }, + content: { + enabled: 'Examine Weight Messages Active', + disabled: 'Examine Weight Messages Inactive', + }, + }, + eating_privacy_global: { + action: 'toggle_global_privacy', + test: eating_privacy_global, + tooltip: { + main: + 'Sets default belly behaviour for vorebellies for announcing' + + ' ingesting or expelling prey' + + ' Overwritten by belly-specific preferences if set.', + enable: ' Click here to turn your messages subtle', + disable: ' Click here to turn your messages loud', + }, + content: { + enabled: 'Global Vore Privacy: Subtle', + disabled: 'Global Vore Privacy: Loud', + }, + }, + }; + + return ( + + + + + + + + act('saveprefs')}> + Save Prefs + + + + act('reloadprefs')}> + Reload Prefs + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferencesTabs.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferencesTabs.tsx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferencesTabs/VoreUserPreferencesAesthetic .tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferencesTabs/VoreUserPreferencesAesthetic .tsx new file mode 100644 index 00000000000..cc5c7036eab --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferencesTabs/VoreUserPreferencesAesthetic .tsx @@ -0,0 +1,61 @@ +import { useBackend } from '../../../backend'; +import { Button, Flex, Section } from '../../../components'; +import { localPrefs } from '../types'; +import { VoreUserPreferenceItem } from '../VoreUserPreferenceItem'; + +export const VoreUserPreferencesAesthetic = (props: { + preferences: localPrefs; +}) => { + const { act } = useBackend(); + const { preferences } = props; + + return ( + + + + act('setflavor')}> + Set Taste + + + + act('setsmell')}> + Set Smell + + + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'en' }) + } + icon="flask" + fluid + > + Set Nutrition Examine Message + + + + + act('set_attribute', { attribute: 'b_msgs', msgtype: 'ew' }) + } + icon="weight-hanging" + fluid + > + Set Weight Examine Message + + + + + + + + + + act('set_vs_color')} icon="palette"> + Vore Sprite Color + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferencesTabs/VoreUserPreferencesMechanical .tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferencesTabs/VoreUserPreferencesMechanical .tsx new file mode 100644 index 00000000000..21d32e32fdb --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreUserPreferencesTabs/VoreUserPreferencesMechanical .tsx @@ -0,0 +1,121 @@ +import { BooleanLike } from 'common/react'; + +import { useBackend } from '../../../backend'; +import { Button, Flex, Section } from '../../../components'; +import { localPrefs } from '../types'; +import { VoreUserPreferenceItem } from '../VoreUserPreferenceItem'; + +export const VoreUserPreferencesMechanical = (props: { + show_pictures: BooleanLike; + preferences: localPrefs; +}) => { + const { act } = useBackend(); + const { show_pictures, preferences } = props; + + return ( + act('show_pictures')} + > + Contents Preference: {show_pictures ? 'Show Pictures' : 'Show List'} + + } + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + act('switch_selective_mode_pref')}> + Selective Mode Preference + + + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/constants.ts b/tgui/packages/tgui/interfaces/VorePanel/constants.ts new file mode 100644 index 00000000000..b87bf1be2e1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/constants.ts @@ -0,0 +1,29 @@ +export const stats: (string | undefined)[] = [undefined, 'average', 'bad']; + +export const digestModeToColor = { + Hold: null, + Digest: 'red', + Absorb: 'purple', + Unabsorb: 'purple', + Drain: 'orange', + Selective: 'orange', + Shrink: 'teal', + Grow: 'teal', + 'Size Steal': 'teal', + Heal: 'green', + 'Encase In Egg': 'blue', +}; + +export const digestModeToPreyMode = { + Hold: 'being held.', + Digest: 'being digested.', + Absorb: 'being absorbed.', + Unabsorb: 'being unabsorbed.', + Drain: 'being drained.', + Selective: 'being processed.', + Shrink: 'being shrunken.', + Grow: 'being grown.', + 'Size Steal': 'having your size stolen.', + Heal: 'being healed.', + 'Encase In Egg': 'being encased in an egg.', +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/index.tsx b/tgui/packages/tgui/interfaces/VorePanel/index.tsx new file mode 100644 index 00000000000..e285075fa3d --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/index.tsx @@ -0,0 +1,80 @@ +import { useState } from 'react'; + +import { useBackend } from '../../backend'; +import { Button, Flex, Icon, NoticeBox, Tabs } from '../../components'; +import { Window } from '../../layouts'; +import { Data } from './types'; +import { VoreBellySelectionAndCustomization } from './VoreBellySelectionAndCustomization'; +import { VoreInsidePanel } from './VoreInsidePanel'; +import { VoreUserPreferences } from './VoreUserPreferences.tsx'; + +/** + * There are three main sections to this UI. + * - The Inside Panel, where all relevant data for interacting with a belly you're in is located. + * - The Belly Selection Panel, where you can select what belly people will go into and customize the active one. + * - User Preferences, where you can adjust all of your vore preferences on the fly. + */ +export const VorePanel = (props) => { + const { act, data } = useBackend(); + + const { inside, our_bellies, selected, prefs, show_pictures, host_mobtype } = + data; + + const [tabIndex, setTabIndex] = useState(0); + + const tabs: React.JSX.Element[] = []; + + tabs[0] = ( + + ); + + tabs[1] = ; + + return ( + + + {(data.unsaved_changes && ( + + + Warning: Unsaved Changes! + + act('saveprefs')}> + Save Prefs + + + + { + act('saveprefs'); + act('exportpanel'); + }} + > + Save Prefs & Export Selected Belly + + + + + )) || + ''} + + + setTabIndex(0)}> + Bellies + + + setTabIndex(1)}> + Preferences + + + + {tabs[tabIndex] || 'Error'} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/types.ts b/tgui/packages/tgui/interfaces/VorePanel/types.ts new file mode 100644 index 00000000000..9d62b52dcb8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel/types.ts @@ -0,0 +1,213 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + unsaved_changes: BooleanLike; + show_pictures: BooleanLike; + inside: insideData; + host_mobtype: hostMob; + our_bellies: bellyData[]; + selected: selectedData; + prefs: prefData; + abilities: { + nutrition: number; + current_size: number; + minimum_size: number; + maximum_size: number; + resize_cost: number; + }; +}; + +export type hostMob = { + is_cyborg: BooleanLike; + is_vore_simple_mob: BooleanLike; +}; + +export type insideData = { + absorbed: BooleanLike; + belly_name: string; + belly_mode: string; + desc: string; + pred: string; + ref: string; + contents: contentData[]; +}; + +export type contentData = { + name: string; + absorbed: BooleanLike; + stat: number; + ref: string; + outside: BooleanLike; + icon: string; +}; + +export type bellyData = { + selected: BooleanLike; + name: string; + ref: string; + digest_mode: string; + contents: number; +}; + +export type selectedData = { + belly_name: string; + message_mode: BooleanLike; + is_wet: BooleanLike; + wet_loop: BooleanLike; + mode: string; + item_mode: string; + verb: string; + release_verb: string; + desc: string; + absorbed_desc: string; + fancy: BooleanLike; + sound: string; + release_sound: string; + can_taste: BooleanLike; + egg_type: string; + nutrition_percent: number; + digest_brute: number; + digest_burn: number; + digest_oxy: number; + digest_tox: number; + digest_clone: number; + bulge_size: number; + save_digest_mode: BooleanLike; + display_absorbed_examine: BooleanLike; + shrink_grow_size: number; + emote_time: number; + emote_active: BooleanLike; + selective_preference: string; + nutrition_ex: BooleanLike; + weight_ex: BooleanLike; + belly_fullscreen: string; + eating_privacy_local: string; + silicon_belly_overlay_preference: string; + belly_mob_mult: number; + belly_item_mult: number; + belly_overall_mult: number; + drainmode: string; + belly_fullscreen_color: string; + belly_fullscreen_color_secondary: string; + belly_fullscreen_color_trinary: string; + colorization_enabled: BooleanLike; + private_struggle: BooleanLike; + addons: string[]; + vore_sprite_flags: string[]; + contaminates: BooleanLike; + contaminate_flavor: string | null; + contaminate_color: string | null; + escapable: BooleanLike; + interacts: interactData; + autotransfer_enabled: BooleanLike; + autotransfer: autotransferData; + disable_hud: BooleanLike; + possible_fullscreens: string[]; + contents: contentData[]; + affects_voresprite: BooleanLike; + absorbed_voresprite: BooleanLike; + absorbed_multiplier: number; + liquid_voresprite: BooleanLike; + liquid_multiplier: number; + item_voresprite: BooleanLike; + item_multiplier: number; + health_voresprite: BooleanLike; + resist_animation: BooleanLike; + voresprite_size_factor: number; + belly_sprite_to_affect: string; + belly_sprite_option_shown: BooleanLike; + tail_option_shown: BooleanLike; + tail_to_change_to: BooleanLike | string; + tail_colouration: BooleanLike; + tail_extra_overlay: BooleanLike; + tail_extra_overlay2: BooleanLike; + undergarment_chosen: undefined; // NOT IMPLEMENTED!!! + undergarment_if_none: undefined; // NOT IMPLEMENTED!!! +}; + +export type interactData = { + escapechance: number; + escapechance_absorbed: number; + escapetime: number; + transferchance: number; + transferlocation: string; + transferchance_secondary: number; + transferlocation_secondary: string; + absorbchance: number; + digestchance: number; +}; + +type autotransferData = { + autotransferchance: number; + autotransferwait: number; + autotransferlocation: string; +}; + +export type prefData = { + digestable: BooleanLike; + devourable: BooleanLike; + resizable: BooleanLike; + feeding: BooleanLike; + absorbable: BooleanLike; + digest_leave_remains: BooleanLike; + allowmobvore: BooleanLike; + permit_healbelly: BooleanLike; + show_vore_fx: BooleanLike; + can_be_drop_prey: BooleanLike; + can_be_drop_pred: BooleanLike; + allow_spontaneous_tf: BooleanLike; + allow_inbelly_spawning: BooleanLike; + step_mechanics_active: BooleanLike; + pickup_mechanics_active: BooleanLike; + noisy: BooleanLike; + drop_vore: BooleanLike; + slip_vore: BooleanLike; + stumble_vore: BooleanLike; + throw_vore: BooleanLike; + food_vore: BooleanLike; + digest_pain: BooleanLike; + nutrition_message_visible: BooleanLike; + nutrition_messages: string[]; + weight_message_visible: BooleanLike; + weight_messages: string[]; + eating_privacy_global: BooleanLike; + vore_sprite_color: { stomach: string; 'taur belly': string }; + vore_sprite_multiply: { stomach: BooleanLike; 'taur belly': BooleanLike }; +}; + +export type localPrefs = { + digestion: preferenceData; + absorbable: preferenceData; + devour: preferenceData; + mobvore: preferenceData; + feed: preferenceData; + healbelly: preferenceData; + dropnom_prey: preferenceData; + dropnom_pred: preferenceData; + toggle_drop_vore: preferenceData; + toggle_slip_vore: preferenceData; + toggle_stumble_vore: preferenceData; + toggle_throw_vore: preferenceData; + toggle_food_vore: preferenceData; + toggle_digest_pain: preferenceData; + inbelly_spawning: preferenceData; + noisy: preferenceData; + resize: preferenceData; + steppref: preferenceData; + vore_fx: preferenceData; + remains: preferenceData; + pickuppref: preferenceData; + spontaneous_tf: preferenceData; + examine_nutrition: preferenceData; + examine_weight: preferenceData; + eating_privacy_global: preferenceData; +}; + +export type preferenceData = { + action: string; + test: BooleanLike; + tooltip: { main: string; enable: string; disable: string }; + content: { enabled: string; disabled: string }; + fluid?: boolean; + back_color?: { enabled: string; disabled: string }; +}; diff --git a/tgui/packages/tgui/interfaces/VorePanelExport.tsx b/tgui/packages/tgui/interfaces/VorePanelExport/VorePanelExportBellyString.tsx similarity index 76% rename from tgui/packages/tgui/interfaces/VorePanelExport.tsx rename to tgui/packages/tgui/interfaces/VorePanelExport/VorePanelExportBellyString.tsx index edba067fe92..421508355d9 100644 --- a/tgui/packages/tgui/interfaces/VorePanelExport.tsx +++ b/tgui/packages/tgui/interfaces/VorePanelExport/VorePanelExportBellyString.tsx @@ -1,183 +1,9 @@ -import { BooleanLike } from 'common/react'; - -import { useBackend } from '../backend'; -import { Button, Section } from '../components'; -import { Window } from '../layouts'; - -const ModeSpan = { - Hold: 'Hold', - Digest: 'Digest', - Absorb: 'Absorb', - Drain: 'Drain', - Selective: 'Selective', - Unabsorb: 'Unabsorb', - Heal: 'Heal', - Shrink: 'Shrink', - Grow: 'Grow', - 'Size Steal': 'Size Steal', - 'Encase In Egg': 'Encase In Egg', -}; - -const ItemModeSpan = { - Hold: 'Item: Hold', - 'Digest (Food Only)': - 'Item: Digest (Food Only)', - Digest: 'Item: Digest', -}; - -const AddonIcon = { - Numbing: '', - Stripping: '', - 'Leave Remains': '', - Muffles: 'bi-volume-mute', - 'Affect Worn Items': '', - 'Jams Sensors': 'bi-wifi-off', - 'Complete Absorb': '', -}; - -const GetAddons = (addons: string[]) => { - let result: string[] = []; - - addons?.forEach((addon) => { - result.push( - '' + - addon + - '', - ); - }); - - if (result.length === 0) { - result.push('No Addons Set'); - } - - return result; -}; - -type Data = { - db_version: string; - db_repo: string; - mob_name: string; - bellies: Belly[]; -}; - -type Belly = { - // General Information - name: string; - desc: string; - message_mode: BooleanLike; - absorbed_desc: string; - vore_verb: string; - release_verb: string; - - // Controls - mode: string; - addons: string[]; - item_mode: string; - - // Options - digest_brute: number; - digest_burn: number; - digest_oxy: number; - digest_tox: number; - digest_clone: number; - - can_taste: BooleanLike; - contaminates: BooleanLike; - contamination_flavor: string; - contamination_color: string; - nutrition_percent: number; - bulge_size: number; - display_absorbed_examine: BooleanLike; - save_digest_mode: BooleanLike; - emote_active: BooleanLike; - emote_time: number; - shrink_grow_size: number; - egg_type: string; - selective_preference: string; - - // Messages - struggle_messages_outside: string[]; - struggle_messages_inside: string[]; - absorbed_struggle_messages_outside: string[]; - absorbed_struggle_messages_inside: string[]; - escape_attempt_messages_owner: string[]; - escape_attempt_messages_prey: string[]; - escape_messages_owner: string[]; - escape_messages_prey: string[]; - escape_messages_outside: string[]; - escape_item_messages_owner: string[]; - escape_item_messages_prey: string[]; - escape_item_messages_outside: string[]; - escape_fail_messages_owner: string[]; - escape_fail_messages_prey: string[]; - escape_attempt_absorbed_messages_owner: string[]; - escape_attempt_absorbed_messages_prey: string[]; - escape_absorbed_messages_owner: string[]; - escape_absorbed_messages_prey: string[]; - escape_absorbed_messages_outside: string[]; - escape_fail_absorbed_messages_owner: string[]; - escape_fail_absorbed_messages_prey: string[]; - primary_transfer_messages_owner: string[]; - primary_transfer_messages_prey: string[]; - secondary_transfer_messages_owner: string[]; - secondary_transfer_messages_prey: string[]; - digest_chance_messages_owner: string[]; - digest_chance_messages_prey: string[]; - absorb_chance_messages_owner: string[]; - absorb_chance_messages_prey: string[]; - digest_messages_owner: string[]; - digest_messages_prey: string[]; - absorb_messages_owner: string[]; - absorb_messages_prey: string[]; - unabsorb_messages_owner: string[]; - unabsorb_messages_prey: string[]; - examine_messages: string[]; - examine_messages_absorbed: string[]; - - // emote_list: any[]; - emotes_digest; - emotes_hold; - emotes_holdabsorbed; - emotes_absorb; - emotes_heal; - emotes_drain; - emotes_steal; - emotes_egg; - emotes_shrink; - emotes_grow; - emotes_unabsorb; - - // Sounds - is_wet: BooleanLike; - wet_loop: BooleanLike; - fancy_vore: BooleanLike; - vore_sound: string; - release_sound: string; - - // Visuals (Vore FX) - disable_hud: BooleanLike; - - // Interactions - escapable: BooleanLike; - - escapechance: number; - escapechance_absorbed: number; - escapetime: number; - - transferchance: number; - transferlocation: string; - - transferchance_secondary: number; - transferlocation_secondary: string; - - absorbchance: number; - digestchance: number; -}; +import { ItemModeSpan, ModeSpan } from './constants'; +import { Belly } from './types'; +import { GetAddons } from './VorePanelExportBellyStringHelpers'; // prettier-ignore -const generateBellyString = (belly: Belly, index: number) => { +export const generateBellyString = (belly: Belly, index: number) => { const { // General Information name, @@ -769,128 +595,3 @@ const generateBellyString = (belly: Belly, index: number) => { return result; }; - -const getCurrentTimestamp = (): string => { - let now = new Date(); - let hours = String(now.getHours()); - if (hours.length < 2) { - hours = '0' + hours; - } - let minutes = String(now.getMinutes()); - if (minutes.length < 2) { - minutes = '0' + minutes; - } - let dayofmonth = String(now.getDate()); - if (dayofmonth.length < 2) { - dayofmonth = '0' + dayofmonth; - } - let month = String(now.getMonth() + 1); // 0-11 - if (month.length < 2) { - month = '0' + month; - } - let year = String(now.getFullYear()); - - return ( - ' ' + - year + - '-' + - month + - '-' + - dayofmonth + - ' (' + - hours + - ' ' + - minutes + - ')' - ); -}; - -const downloadPrefs = (extension: string) => { - const { act, data } = useBackend(); - - const { db_version, db_repo, mob_name, bellies } = data; - - let datesegment = getCurrentTimestamp(); - - let filename = mob_name + datesegment + extension; - let blob; - - if (extension === '.html') { - let style = ''; - - blob = new Blob( - [ - '' + - '' + - '' + - '' + - bellies.length + - ' Exported Bellies (DB_VER: ' + - db_repo + - '-' + - db_version + - ')' + - '' + - '' + - style + - 'Bellies of ' + - mob_name + - 'Generated on: ' + - datesegment + - '', - ], - { - type: 'text/html;charset=utf8', - }, - ); - bellies.forEach((belly, i) => { - blob = new Blob([blob, generateBellyString(belly, i)], { - type: 'text/html;charset=utf8', - }); - }); - blob = new Blob( - [ - blob, - '', - '', - '', - ], - { type: 'text/html;charset=utf8' }, - ); - } - - if (extension === '.vrdb') { - blob = new Blob([JSON.stringify(bellies)], { type: 'application/json' }); - } - - (window.navigator as any).msSaveOrOpenBlob(blob, filename); -}; - -export const VorePanelExport = () => { - return ( - - - - - - ); -}; - -const VorePanelExportContent = (props) => { - const { act, data } = useBackend(); - - const { bellies } = data; - - return ( - - - downloadPrefs('.html')}> - Export (HTML) - - downloadPrefs('.vrdb')}> - Export (VRDB) - - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/VorePanelExport/VorePanelExportBellyStringHelpers.tsx b/tgui/packages/tgui/interfaces/VorePanelExport/VorePanelExportBellyStringHelpers.tsx new file mode 100644 index 00000000000..54b40cf5109 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanelExport/VorePanelExportBellyStringHelpers.tsx @@ -0,0 +1,21 @@ +import { AddonIcon } from './constants'; + +export const GetAddons = (addons: string[]) => { + let result: string[] = []; + + addons?.forEach((addon) => { + result.push( + '' + + addon + + '', + ); + }); + + if (result.length === 0) { + result.push('No Addons Set'); + } + + return result; +}; diff --git a/tgui/packages/tgui/interfaces/VorePanelExport/VorePanelExportDownload.tsx b/tgui/packages/tgui/interfaces/VorePanelExport/VorePanelExportDownload.tsx new file mode 100644 index 00000000000..bcc6125e72c --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanelExport/VorePanelExportDownload.tsx @@ -0,0 +1,65 @@ +import { useBackend } from '../../backend'; +import { Data } from './types'; +import { generateBellyString } from './VorePanelExportBellyString'; +import { getCurrentTimestamp } from './VorePanelExportTimestamp'; + +export const downloadPrefs = (extension: string) => { + const { act, data } = useBackend(); + + const { db_version, db_repo, mob_name, bellies } = data; + + let datesegment = getCurrentTimestamp(); + + let filename = mob_name + datesegment + extension; + let blob; + + if (extension === '.html') { + let style = ''; + + blob = new Blob( + [ + '' + + '' + + '' + + '' + + bellies.length + + ' Exported Bellies (DB_VER: ' + + db_repo + + '-' + + db_version + + ')' + + '' + + '' + + style + + 'Bellies of ' + + mob_name + + 'Generated on: ' + + datesegment + + '', + ], + { + type: 'text/html;charset=utf8', + }, + ); + bellies.forEach((belly, i) => { + blob = new Blob([blob, generateBellyString(belly, i)], { + type: 'text/html;charset=utf8', + }); + }); + blob = new Blob( + [ + blob, + '', + '', + '', + ], + { type: 'text/html;charset=utf8' }, + ); + } + + if (extension === '.vrdb') { + blob = new Blob([JSON.stringify(bellies)], { type: 'application/json' }); + } + + (window.navigator as any).msSaveOrOpenBlob(blob, filename); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanelExport/VorePanelExportTimestamp.tsx b/tgui/packages/tgui/interfaces/VorePanelExport/VorePanelExportTimestamp.tsx new file mode 100644 index 00000000000..84ec6c5269f --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanelExport/VorePanelExportTimestamp.tsx @@ -0,0 +1,34 @@ +export const getCurrentTimestamp = (): string => { + let now = new Date(); + let hours = String(now.getHours()); + if (hours.length < 2) { + hours = '0' + hours; + } + let minutes = String(now.getMinutes()); + if (minutes.length < 2) { + minutes = '0' + minutes; + } + let dayofmonth = String(now.getDate()); + if (dayofmonth.length < 2) { + dayofmonth = '0' + dayofmonth; + } + let month = String(now.getMonth() + 1); // 0-11 + if (month.length < 2) { + month = '0' + month; + } + let year = String(now.getFullYear()); + + return ( + ' ' + + year + + '-' + + month + + '-' + + dayofmonth + + ' (' + + hours + + ' ' + + minutes + + ')' + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanelExport/constants.ts b/tgui/packages/tgui/interfaces/VorePanelExport/constants.ts new file mode 100644 index 00000000000..5b07412443a --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanelExport/constants.ts @@ -0,0 +1,30 @@ +export const ModeSpan = { + Hold: 'Hold', + Digest: 'Digest', + Absorb: 'Absorb', + Drain: 'Drain', + Selective: 'Selective', + Unabsorb: 'Unabsorb', + Heal: 'Heal', + Shrink: 'Shrink', + Grow: 'Grow', + 'Size Steal': 'Size Steal', + 'Encase In Egg': 'Encase In Egg', +}; + +export const ItemModeSpan = { + Hold: 'Item: Hold', + 'Digest (Food Only)': + 'Item: Digest (Food Only)', + Digest: 'Item: Digest', +}; + +export const AddonIcon = { + Numbing: '', + Stripping: '', + 'Leave Remains': '', + Muffles: 'bi-volume-mute', + 'Affect Worn Items': '', + 'Jams Sensors': 'bi-wifi-off', + 'Complete Absorb': '', +}; diff --git a/tgui/packages/tgui/interfaces/VorePanelExport/index.tsx b/tgui/packages/tgui/interfaces/VorePanelExport/index.tsx new file mode 100644 index 00000000000..630b066cbf3 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanelExport/index.tsx @@ -0,0 +1,34 @@ +import { useBackend } from '../../backend'; +import { Button, Section } from '../../components'; +import { Window } from '../../layouts'; +import { Data } from './types'; +import { downloadPrefs } from './VorePanelExportDownload'; + +export const VorePanelExport = () => { + return ( + + + + + + ); +}; + +const VorePanelExportContent = (props) => { + const { act, data } = useBackend(); + + const { bellies } = data; + + return ( + + + downloadPrefs('.html')}> + Export (HTML) + + downloadPrefs('.vrdb')}> + Export (VRDB) + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanelExport/types.ts b/tgui/packages/tgui/interfaces/VorePanelExport/types.ts new file mode 100644 index 00000000000..720a3a7287a --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanelExport/types.ts @@ -0,0 +1,122 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + db_version: string; + db_repo: string; + mob_name: string; + bellies: Belly[]; +}; + +export type Belly = { + // General Information + name: string; + desc: string; + message_mode: BooleanLike; + absorbed_desc: string; + vore_verb: string; + release_verb: string; + + // Controls + mode: string; + addons: string[]; + item_mode: string; + + // Options + digest_brute: number; + digest_burn: number; + digest_oxy: number; + digest_tox: number; + digest_clone: number; + + can_taste: BooleanLike; + contaminates: BooleanLike; + contamination_flavor: string; + contamination_color: string; + nutrition_percent: number; + bulge_size: number; + display_absorbed_examine: BooleanLike; + save_digest_mode: BooleanLike; + emote_active: BooleanLike; + emote_time: number; + shrink_grow_size: number; + egg_type: string; + selective_preference: string; + + // Messages + struggle_messages_outside: string[]; + struggle_messages_inside: string[]; + absorbed_struggle_messages_outside: string[]; + absorbed_struggle_messages_inside: string[]; + escape_attempt_messages_owner: string[]; + escape_attempt_messages_prey: string[]; + escape_messages_owner: string[]; + escape_messages_prey: string[]; + escape_messages_outside: string[]; + escape_item_messages_owner: string[]; + escape_item_messages_prey: string[]; + escape_item_messages_outside: string[]; + escape_fail_messages_owner: string[]; + escape_fail_messages_prey: string[]; + escape_attempt_absorbed_messages_owner: string[]; + escape_attempt_absorbed_messages_prey: string[]; + escape_absorbed_messages_owner: string[]; + escape_absorbed_messages_prey: string[]; + escape_absorbed_messages_outside: string[]; + escape_fail_absorbed_messages_owner: string[]; + escape_fail_absorbed_messages_prey: string[]; + primary_transfer_messages_owner: string[]; + primary_transfer_messages_prey: string[]; + secondary_transfer_messages_owner: string[]; + secondary_transfer_messages_prey: string[]; + digest_chance_messages_owner: string[]; + digest_chance_messages_prey: string[]; + absorb_chance_messages_owner: string[]; + absorb_chance_messages_prey: string[]; + digest_messages_owner: string[]; + digest_messages_prey: string[]; + absorb_messages_owner: string[]; + absorb_messages_prey: string[]; + unabsorb_messages_owner: string[]; + unabsorb_messages_prey: string[]; + examine_messages: string[]; + examine_messages_absorbed: string[]; + + // emote_list: string[]; + emotes_digest: string[]; + emotes_hold: string[]; + emotes_holdabsorbed: string[]; + emotes_absorb: string[]; + emotes_heal: string[]; + emotes_drain: string[]; + emotes_steal: string[]; + emotes_egg: string[]; + emotes_shrink: string[]; + emotes_grow: string[]; + emotes_unabsorb: string[]; + + // Sounds + is_wet: BooleanLike; + wet_loop: BooleanLike; + fancy_vore: BooleanLike; + vore_sound: string; + release_sound: string; + + // Visuals (Vore FX) + disable_hud: BooleanLike; + + // Interactions + escapable: BooleanLike; + + escapechance: number; + escapechance_absorbed: number; + escapetime: number; + + transferchance: number; + transferlocation: string; + + transferchance_secondary: number; + transferlocation_secondary: string; + + absorbchance: number; + digestchance: number; +}; diff --git a/tgui/packages/tgui/interfaces/XenoarchSpectrometer.jsx b/tgui/packages/tgui/interfaces/XenoarchSpectrometer.tsx similarity index 86% rename from tgui/packages/tgui/interfaces/XenoarchSpectrometer.jsx rename to tgui/packages/tgui/interfaces/XenoarchSpectrometer.tsx index 73e7f607424..8a7ae92de81 100644 --- a/tgui/packages/tgui/interfaces/XenoarchSpectrometer.jsx +++ b/tgui/packages/tgui/interfaces/XenoarchSpectrometer.tsx @@ -1,3 +1,4 @@ +import { BooleanLike } from 'common/react'; import { decodeHtmlEntities } from 'common/string'; import { useBackend } from '../backend'; @@ -12,8 +13,31 @@ import { } from '../components'; import { Window } from '../layouts'; +type Data = { + scanned_item: string; + scanned_item_desc: string; + last_scan_data: string; + scan_progress: number; + scanning: BooleanLike; + scanner_seal_integrity: number; + scanner_rpm: number; + scanner_temperature: number; + coolant_usage_rate: number; + coolant_usage_max: number; + unused_coolant_abs: number; + unused_coolant_per: number; + coolant_purity: number; + optimal_wavelength: number; + maser_wavelength: number; + maser_wavelength_max: number; + maser_efficiency: number; + radiation: number; + t_left_radspike: number; + rad_shield_on: BooleanLike; +}; + export const XenoarchSpectrometer = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { scanned_item, @@ -121,9 +145,11 @@ export const XenoarchSpectrometer = (props) => { fillValue={optimal_wavelength} minValue={1} maxValue={maser_wavelength_max} - format={(val) => val + ' MHz'} + format={(val: number) => val + ' MHz'} step={10} - onDrag={(e, val) => act('maserWavelength', { wavelength: val })} + onDrag={(e, val: number) => + act('maserWavelength', { wavelength: val }) + } /> @@ -209,8 +235,10 @@ export const XenoarchSpectrometer = (props) => { value={coolant_usage_rate} maxValue={coolant_usage_max} stepPixelSize={50} - format={(val) => val + ' u/s'} - onDrag={(e, val) => act('coolantRate', { coolant: val })} + format={(val: number) => val + ' u/s'} + onDrag={(e, val: number) => + act('coolantRate', { coolant: val }) + } /> diff --git a/tgui/packages/tgui/interfaces/common/ComplexModal.tsx b/tgui/packages/tgui/interfaces/common/ComplexModal.tsx index 31931bdfb23..8efd96fe2fa 100644 --- a/tgui/packages/tgui/interfaces/common/ComplexModal.tsx +++ b/tgui/packages/tgui/interfaces/common/ComplexModal.tsx @@ -1,7 +1,15 @@ import React from 'react'; import { useBackend } from '../../backend'; -import { Box, Button, Dropdown, Flex, Input, Modal } from '../../components'; +import { + Box, + Button, + Dropdown, + Flex, + Image, + Input, + Modal, +} from '../../components'; type Data = { modal: { id: string; args: {}; text: string; type: string } }; let bodyOverrides = {}; @@ -171,7 +179,7 @@ export const ComplexModal = (props) => { selected={i + 1 === parseInt(modal.value, 10)} onClick={() => modalAnswer(id, (i + 1).toString(), {})} > - + ))} diff --git a/tgui/packages/tgui/interfaces/common/LoginInfo.tsx b/tgui/packages/tgui/interfaces/common/LoginInfo.tsx index a25c1f5d1ff..f9da3169a08 100644 --- a/tgui/packages/tgui/interfaces/common/LoginInfo.tsx +++ b/tgui/packages/tgui/interfaces/common/LoginInfo.tsx @@ -8,9 +8,9 @@ type Data = { authenticated: string; rank: string }; * `authenticated` and `rank` data fields if they exist. * * Also gives an option to log off (calls `logout` TGUI action) - * @param {object} _properties + * @param {object} props */ -export const LoginInfo = (_properties) => { +export const LoginInfo = (props) => { const { act, data } = useBackend(); const { authenticated, rank } = data; if (!data) { diff --git a/tgui/packages/tgui/interfaces/common/LoginScreen.tsx b/tgui/packages/tgui/interfaces/common/LoginScreen.tsx index c97c47614a7..b34826f5416 100644 --- a/tgui/packages/tgui/interfaces/common/LoginScreen.tsx +++ b/tgui/packages/tgui/interfaces/common/LoginScreen.tsx @@ -4,7 +4,7 @@ import { useBackend } from '../../backend'; import { Box, Button, Icon } from '../../components'; import { FullscreenNotice } from './FullscreenNotice'; -type machine = { machineType: string }; +type machine = { machineType?: string }; type Data = { scan: BooleanLike; isAI: BooleanLike; isRobot: BooleanLike }; /** @@ -28,12 +28,12 @@ type Data = { scan: BooleanLike; isAI: BooleanLike; isRobot: BooleanLike }; * You will have to handle the AI login case in the same action. * The normal login button is only available when `scan` is not null. * The AI and robot login buttons are only visible if the user is one - * @param {object} _properties + * @param {object} props */ -export const LoginScreen = (_properties: machine) => { +export const LoginScreen = (props: machine) => { const { act, data } = useBackend(); const { scan, isAI, isRobot } = data; - const { machineType } = _properties; + const { machineType } = props; return ( @@ -95,9 +95,9 @@ export const LoginScreen = (_properties: machine) => { * specialType definitions are defined in LoginScreen.js SpecialMachineInteraction * currently supported: "Fax" */ -export const SpecialMachineInteraction = (_properties: machine) => { +export const SpecialMachineInteraction = (props: machine) => { const { act } = useBackend(); - const { machineType } = _properties; + const { machineType } = props; if (!machineType) { return null; } else if (machineType === 'Fax') { diff --git a/tgui/packages/tgui/interfaces/common/Overmap.tsx b/tgui/packages/tgui/interfaces/common/Overmap.tsx index f875bb7211e..f6056985471 100644 --- a/tgui/packages/tgui/interfaces/common/Overmap.tsx +++ b/tgui/packages/tgui/interfaces/common/Overmap.tsx @@ -1,4 +1,5 @@ import { toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; import { useBackend } from '../../backend'; import { Box, Button, LabeledList } from '../../components'; @@ -38,7 +39,11 @@ export const OvermapFlightData = (props) => { ); }; -export const OvermapPanControls = (props) => { +export const OvermapPanControls = (props: { + disabled?: BooleanLike; + actToDo: string; + selected?: (val: number) => boolean; +}) => { const { act } = useBackend(); const { disabled, actToDo, selected = (val) => false } = props; diff --git a/tgui/packages/tgui/interfaces/common/TemporaryNotice.tsx b/tgui/packages/tgui/interfaces/common/TemporaryNotice.tsx index a94816416b0..69102be5e79 100644 --- a/tgui/packages/tgui/interfaces/common/TemporaryNotice.tsx +++ b/tgui/packages/tgui/interfaces/common/TemporaryNotice.tsx @@ -1,3 +1,4 @@ +import { BooleanLike } from 'common/react'; import { decodeHtmlEntities } from 'common/string'; import { useBackend } from '../../backend'; @@ -15,10 +16,10 @@ type Data = { temp: { style: string; text: string } }; * - `text` — The text to display * * Allows clearing the notice through the `cleartemp` TGUI act - * @param {object} _properties + * @param {object} props */ -export const TemporaryNotice = (_properties) => { - const { decode } = _properties; +export const TemporaryNotice = (props: { decode?: BooleanLike }) => { + const { decode } = props; const { act, data } = useBackend(); const { temp } = data; if (!temp) { diff --git a/tgui/packages/tgui/interfaces/pAIAtmos.jsx b/tgui/packages/tgui/interfaces/pAIAtmos.tsx similarity index 72% rename from tgui/packages/tgui/interfaces/pAIAtmos.jsx rename to tgui/packages/tgui/interfaces/pAIAtmos.tsx index ec2edb7f40f..048f58a2589 100644 --- a/tgui/packages/tgui/interfaces/pAIAtmos.jsx +++ b/tgui/packages/tgui/interfaces/pAIAtmos.tsx @@ -5,7 +5,27 @@ import { useBackend } from '../backend'; import { LabeledList, Section } from '../components'; import { Window } from '../layouts'; -const getItemColor = (value, min2, min1, max1, max2) => { +type Data = { + aircontents: aircontent[]; +}; + +type aircontent = { + entry: string; + units: string; + val: string; + bad_high: number; + poor_high: number; + poor_low: number; + bad_low: number; +}; + +const getItemColor = ( + value: number, + min2: number, + min1: number, + max1: number, + max2: number, +): string => { if (value < min2) { return 'bad'; } else if (value < min1) { @@ -19,7 +39,7 @@ const getItemColor = (value, min2, min1, max1, max2) => { }; export const pAIAtmos = (props) => { - const { act, data } = useBackend(); + const { data } = useBackend(); const { aircontents } = data; @@ -29,16 +49,16 @@ export const pAIAtmos = (props) => { {filter( - (i) => + (i: aircontent) => i.val !== '0' || i.entry === 'Pressure' || i.entry === 'Temperature', - )(aircontents).map((item) => ( + )(aircontents).map((item: aircontent) => ( { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { cable, machine, inprogress, progress_a, progress_b, aborted } = data; @@ -59,9 +70,7 @@ export const pAIDoorjack = (props) => { )) || (!!aborted && ( - - Hack aborted. - + Hack aborted. ))} diff --git a/tgui/packages/tgui/interfaces/pAIMedrecords.jsx b/tgui/packages/tgui/interfaces/pAIMedrecords.tsx similarity index 91% rename from tgui/packages/tgui/interfaces/pAIMedrecords.jsx rename to tgui/packages/tgui/interfaces/pAIMedrecords.tsx index 17662f31d2d..f9306fca50a 100644 --- a/tgui/packages/tgui/interfaces/pAIMedrecords.jsx +++ b/tgui/packages/tgui/interfaces/pAIMedrecords.tsx @@ -1,9 +1,19 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, LabeledList, Section } from '../components'; import { Window } from '../layouts'; +import { GeneralRecord, MedicalRecord, RecordList } from './pda/pda_types'; + +type Data = { + records: RecordList; + general: GeneralRecord; + medical: MedicalRecord; + could_not_find: BooleanLike; +}; export const pAIMedrecords = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { records, general, medical, could_not_find } = data; diff --git a/tgui/packages/tgui/interfaces/pAISecrecords.jsx b/tgui/packages/tgui/interfaces/pAISecrecords.tsx similarity index 90% rename from tgui/packages/tgui/interfaces/pAISecrecords.jsx rename to tgui/packages/tgui/interfaces/pAISecrecords.tsx index 6c19aae0acd..12eae31246a 100644 --- a/tgui/packages/tgui/interfaces/pAISecrecords.jsx +++ b/tgui/packages/tgui/interfaces/pAISecrecords.tsx @@ -1,9 +1,19 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, LabeledList, Section } from '../components'; import { Window } from '../layouts'; +import { GeneralRecord, RecordList, SecurityRecord } from './pda/pda_types'; + +type Data = { + records: RecordList; + general: GeneralRecord; + security: SecurityRecord; + could_not_find: BooleanLike; +}; export const pAISecrecords = (props) => { - const { act, data } = useBackend(); + const { act, data } = useBackend(); const { records, general, security, could_not_find } = data; diff --git a/tgui/packages/tgui/interfaces/pda/pda_medical.tsx b/tgui/packages/tgui/interfaces/pda/pda_medical.tsx index 97acc11040a..c2826c2d2f9 100644 --- a/tgui/packages/tgui/interfaces/pda/pda_medical.tsx +++ b/tgui/packages/tgui/interfaces/pda/pda_medical.tsx @@ -1,28 +1,11 @@ import { useBackend } from '../../backend'; import { Box, Button, LabeledList, Section } from '../../components'; -import { GeneralRecord, RecordList } from './pda_types'; +import { GeneralRecord, MedicalRecord, RecordList } from './pda_types'; type Data = { records: { general: GeneralRecord; - medical: { - id: string; - name: string; - species: string; - b_type: string; - b_dna: string; - id_gender: string; - brain_type: string; - mi_dis: string; - mi_dis_d: string; - ma_dis: string; - ma_dis_d: string; - alg: string; - alg_d: string; - cdi: string; - cdi_d: string; - notes: string; - }; + medical: MedicalRecord; }; recordsList: RecordList; }; @@ -108,7 +91,7 @@ export const pda_medical = (props) => { fluid onClick={() => act('Records', { target: record.ref })} > - {record.Name} + {record.name} ))} diff --git a/tgui/packages/tgui/interfaces/pda/pda_news.tsx b/tgui/packages/tgui/interfaces/pda/pda_news.tsx index 98626eba5d6..73aead963c8 100644 --- a/tgui/packages/tgui/interfaces/pda/pda_news.tsx +++ b/tgui/packages/tgui/interfaces/pda/pda_news.tsx @@ -2,7 +2,7 @@ import { BooleanLike } from 'common/react'; import { decodeHtmlEntities } from 'common/string'; import { useBackend } from '../../backend'; -import { Box, Button, Section } from '../../components'; +import { Box, Button, Image, Section } from '../../components'; type Data = { feeds: feed[]; @@ -84,7 +84,7 @@ const NewsTargetFeed = (props: { target_feed: feed }) => { - {decodeHtmlEntities(message.body)} {!!message.img && ( - + {decodeHtmlEntities(message.caption) || null} )} diff --git a/tgui/packages/tgui/interfaces/pda/pda_power.tsx b/tgui/packages/tgui/interfaces/pda/pda_power.tsx index c2b199acb7a..431c96a4975 100644 --- a/tgui/packages/tgui/interfaces/pda/pda_power.tsx +++ b/tgui/packages/tgui/interfaces/pda/pda_power.tsx @@ -1,8 +1,5 @@ -import { useBackend } from '../../backend'; -import { PowerMonitorContent } from '../PowerMonitor'; +import { PowerMonitorContent } from '../PowerMonitor/PowerMonitorContent'; export const pda_power = (props) => { - const { act, data } = useBackend(); - return ; }; diff --git a/tgui/packages/tgui/interfaces/pda/pda_security.tsx b/tgui/packages/tgui/interfaces/pda/pda_security.tsx index 041f84eb586..dbceb364db7 100644 --- a/tgui/packages/tgui/interfaces/pda/pda_security.tsx +++ b/tgui/packages/tgui/interfaces/pda/pda_security.tsx @@ -1,22 +1,11 @@ import { useBackend } from '../../backend'; import { Box, Button, LabeledList, Section } from '../../components'; -import { GeneralRecord, RecordList } from './pda_types'; +import { GeneralRecord, RecordList, SecurityRecord } from './pda_types'; type Data = { records: { general: GeneralRecord; - security: { - name: string; - species: string; - id: string; - brain_type: string; - criminal: string; - mi_crim: string; - mi_crim_d: string; - ma_crim: string; - ma_crim_d: string; - notes: string; - }; + security: SecurityRecord; }; recordsList: RecordList; }; @@ -92,7 +81,7 @@ export const pda_security = (props) => { fluid onClick={() => act('Records', { target: record.ref })} > - {record.Name} + {record.name} ))} diff --git a/tgui/packages/tgui/interfaces/pda/pda_types.ts b/tgui/packages/tgui/interfaces/pda/pda_types.ts index f7a1bac39b1..6d22b018102 100644 --- a/tgui/packages/tgui/interfaces/pda/pda_types.ts +++ b/tgui/packages/tgui/interfaces/pda/pda_types.ts @@ -27,4 +27,36 @@ export type GeneralRecord = { notes: string; }; -export type RecordList = { Name: string; ref: string }[]; +export type MedicalRecord = { + id: string; + name: string; + species: string; + b_type: string; + b_dna: string; + id_gender: string; + brain_type: string; + mi_dis: string; + mi_dis_d: string; + ma_dis: string; + ma_dis_d: string; + alg: string; + alg_d: string; + cdi: string; + cdi_d: string; + notes: string; +}; + +export type SecurityRecord = { + name: string; + species: string; + id: string; + brain_type: string; + criminal: string; + mi_crim: string; + mi_crim_d: string; + ma_crim: string; + ma_crim_d: string; + notes: string; +}; + +export type RecordList = { name: string; ref: string }[]; diff --git a/tgui/packages/tgui/layouts/NtosWindow.jsx b/tgui/packages/tgui/layouts/NtosWindow.jsx index 884a1a6a793..c00f9f2de0b 100644 --- a/tgui/packages/tgui/layouts/NtosWindow.jsx +++ b/tgui/packages/tgui/layouts/NtosWindow.jsx @@ -6,7 +6,7 @@ import { resolveAsset } from '../assets'; import { useBackend } from '../backend'; -import { Box, Button } from '../components'; +import { Box, Button, Image } from '../components'; import { Window } from './Window'; export const NtosWindow = (props) => { @@ -47,7 +47,7 @@ export const NtosWindow = (props) => { {PC_programheaders.map((header) => ( - @@ -55,7 +55,7 @@ export const NtosWindow = (props) => { ))} {PC_ntneticon && ( - @@ -63,7 +63,7 @@ export const NtosWindow = (props) => { {!!(PC_showbatteryicon && PC_batteryicon) && ( - diff --git a/tgui/public/tgui-panel.bundle.js b/tgui/public/tgui-panel.bundle.js index f82b58f5734..0393b8c76c9 100644 --- a/tgui/public/tgui-panel.bundle.js +++ b/tgui/public/tgui-panel.bundle.js @@ -6,7 +6,7 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */function i(o,e){return e!=null&&typeof Symbol!="undefined"&&e[Symbol.hasInstance]?!!e[Symbol.hasInstance](o):o instanceof e}function u(o){"@swc/helpers - typeof";return o&&typeof Symbol!="undefined"&&o.constructor===Symbol?"symbol":typeof o}var s=n(28277),d=n(9359);function f(o){for(var e="https://reactjs.org/docs/error-decoder.html?invariant="+o,t=1;te}return!1}function M(o,e,t,r,a,l,v){this.acceptsBooleans=e===2||e===3||e===4,this.attributeName=r,this.attributeNamespace=a,this.mustUseProperty=t,this.propertyName=o,this.type=e,this.sanitizeURL=l,this.removeEmptyString=v}var U={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(o){U[o]=new M(o,0,!1,o,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(o){var e=o[0];U[e]=new M(e,1,!1,o[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(o){U[o]=new M(o,2,!1,o.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(o){U[o]=new M(o,2,!1,o,null,!1,!1)}),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(o){U[o]=new M(o,3,!1,o.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(o){U[o]=new M(o,3,!0,o,null,!1,!1)}),["capture","download"].forEach(function(o){U[o]=new M(o,4,!1,o,null,!1,!1)}),["cols","rows","size","span"].forEach(function(o){U[o]=new M(o,6,!1,o,null,!1,!1)}),["rowSpan","start"].forEach(function(o){U[o]=new M(o,5,!1,o.toLowerCase(),null,!1,!1)});var z=/[\-:]([a-z])/g;function D(o){return o[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(o){var e=o.replace(z,D);U[e]=new M(e,1,!1,o,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(o){var e=o.replace(z,D);U[e]=new M(e,1,!1,o,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(o){var e=o.replace(z,D);U[e]=new M(e,1,!1,o,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(o){U[o]=new M(o,1,!1,o.toLowerCase(),null,!1,!1)}),U.xlinkHref=new M("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(o){U[o]=new M(o,1,!1,o.toLowerCase(),null,!0,!0)});function b(o,e,t,r){var a=U.hasOwnProperty(e)?U[e]:null;(a!==null?a.type!==0:r||!(2P||a[v]!==l[P]){var k="\n"+a[v].replace(" at new "," at ");return o.displayName&&k.includes("")&&(k=k.replace("",o.displayName)),k}while(1<=v&&0<=P);break}}}finally{ye=!1,Error.prepareStackTrace=t}return(o=o?o.displayName||o.name:"")?Te(o):""}function Ae(o){switch(o.tag){case 5:return Te(o.type);case 16:return Te("Lazy");case 13:return Te("Suspense");case 19:return Te("SuspenseList");case 0:case 2:case 15:return o=xe(o.type,!1),o;case 11:return o=xe(o.type.render,!1),o;case 1:return o=xe(o.type,!0),o;default:return""}}function Pe(o){if(o==null)return null;if(typeof o=="function")return o.displayName||o.name||null;if(typeof o=="string")return o;switch(o){case G:return"Fragment";case V:return"Portal";case oe:return"Profiler";case J:return"StrictMode";case pe:return"Suspense";case ce:return"SuspenseList"}if(typeof o=="object")switch(o.$$typeof){case ne:return(o.displayName||"Context")+".Consumer";case Z:return(o._context.displayName||"Context")+".Provider";case te:var e=o.render;return o=o.displayName,o||(o=e.displayName||e.name||"",o=o!==""?"ForwardRef("+o+")":"ForwardRef"),o;case q:return e=o.displayName||null,e!==null?e:Pe(o.type)||"Memo";case K:e=o._payload,o=o._init;try{return Pe(o(e))}catch(t){}}return null}function me(o){var e=o.type;switch(o.tag){case 24:return"Cache";case 9:return(e.displayName||"Context")+".Consumer";case 10:return(e._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return o=e.render,o=o.displayName||o.name||"",e.displayName||(o!==""?"ForwardRef("+o+")":"ForwardRef");case 7:return"Fragment";case 5:return e;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Pe(e);case 8:return e===J?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e}return null}function Ye(o){switch(typeof o=="undefined"?"undefined":u(o)){case"boolean":case"number":case"string":case"undefined":return o;case"object":return o;default:return""}}function Qe(o){var e=o.type;return(o=o.nodeName)&&o.toLowerCase()==="input"&&(e==="checkbox"||e==="radio")}function yt(o){var e=Qe(o)?"checked":"value",t=Object.getOwnPropertyDescriptor(o.constructor.prototype,e),r=""+o[e];if(!o.hasOwnProperty(e)&&typeof t!="undefined"&&typeof t.get=="function"&&typeof t.set=="function"){var a=t.get,l=t.set;return Object.defineProperty(o,e,{configurable:!0,get:function(){return a.call(this)},set:function(P){r=""+P,l.call(this,P)}}),Object.defineProperty(o,e,{enumerable:t.enumerable}),{getValue:function(){return r},setValue:function(P){r=""+P},stopTracking:function(){o._valueTracker=null,delete o[e]}}}}function ut(o){o._valueTracker||(o._valueTracker=yt(o))}function Ie(o){if(!o)return!1;var e=o._valueTracker;if(!e)return!0;var t=e.getValue(),r="";return o&&(r=Qe(o)?o.checked?"true":"false":o.value),o=r,o!==t?(e.setValue(o),!0):!1}function De(o){if(o=o||(typeof document!="undefined"?document:void 0),typeof o=="undefined")return null;try{return o.activeElement||o.body}catch(e){return o.body}}function be(o,e){var t=e.checked;return ae({},e,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:t!=null?t:o._wrapperState.initialChecked})}function Xe(o,e){var t=e.defaultValue==null?"":e.defaultValue,r=e.checked!=null?e.checked:e.defaultChecked;t=Ye(e.value!=null?e.value:t),o._wrapperState={initialChecked:r,initialValue:t,controlled:e.type==="checkbox"||e.type==="radio"?e.checked!=null:e.value!=null}}function lt(o,e){e=e.checked,e!=null&&b(o,"checked",e,!1)}function tt(o,e){lt(o,e);var t=Ye(e.value),r=e.type;if(t!=null)r==="number"?(t===0&&o.value===""||o.value!=t)&&(o.value=""+t):o.value!==""+t&&(o.value=""+t);else if(r==="submit"||r==="reset"){o.removeAttribute("value");return}e.hasOwnProperty("value")?qe(o,e.type,t):e.hasOwnProperty("defaultValue")&&qe(o,e.type,Ye(e.defaultValue)),e.checked==null&&e.defaultChecked!=null&&(o.defaultChecked=!!e.defaultChecked)}function ct(o,e,t){if(e.hasOwnProperty("value")||e.hasOwnProperty("defaultValue")){var r=e.type;if(!(r!=="submit"&&r!=="reset"||e.value!==void 0&&e.value!==null))return;e=""+o._wrapperState.initialValue,t||e===o.value||(o.value=e),o.defaultValue=e}t=o.name,t!==""&&(o.name=""),o.defaultChecked=!!o._wrapperState.initialChecked,t!==""&&(o.name=t)}function qe(o,e,t){(e!=="number"||De(o.ownerDocument)!==o)&&(t==null?o.defaultValue=""+o._wrapperState.initialValue:o.defaultValue!==""+t&&(o.defaultValue=""+t))}var Ue=Array.isArray;function Ge(o,e,t,r){if(o=o.options,e){e={};for(var a=0;a"+e.valueOf().toString()+"",e=bt.firstChild;o.firstChild;)o.removeChild(o.firstChild);for(;e.firstChild;)o.appendChild(e.firstChild)}});function St(o,e){if(e){var t=o.firstChild;if(t&&t===o.lastChild&&t.nodeType===3){t.nodeValue=e;return}}o.textContent=e}var et={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},He=["Webkit","ms","Moz","O"];Object.keys(et).forEach(function(o){He.forEach(function(e){e=e+o.charAt(0).toUpperCase()+o.substring(1),et[e]=et[o]})});function Ft(o,e,t){return e==null||typeof e=="boolean"||e===""?"":t||typeof e!="number"||e===0||et.hasOwnProperty(o)&&et[o]?(""+e).trim():e+"px"}function Ut(o,e){o=o.style;for(var t in e)if(e.hasOwnProperty(t)){var r=t.indexOf("--")===0,a=Ft(t,e[t],r);t==="float"&&(t="cssFloat"),r?o.setProperty(t,a):o[t]=a}}var fn=ae({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function gn(o,e){if(e){if(fn[o]&&(e.children!=null||e.dangerouslySetInnerHTML!=null))throw Error(f(137,o));if(e.dangerouslySetInnerHTML!=null){if(e.children!=null)throw Error(f(60));if(typeof e.dangerouslySetInnerHTML!="object"||!("__html"in e.dangerouslySetInnerHTML))throw Error(f(61))}if(e.style!=null&&typeof e.style!="object")throw Error(f(62))}}function kn(o,e){if(o.indexOf("-")===-1)return typeof e.is=="string";switch(o){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Xn=null;function Lr(o){return o=o.target||o.srcElement||window,o.correspondingUseElement&&(o=o.correspondingUseElement),o.nodeType===3?o.parentNode:o}var le=null,we=null,ge=null;function Oe(o){if(o=ii(o)){if(typeof le!="function")throw Error(f(280));var e=o.stateNode;e&&(e=Go(e),le(o.stateNode,o.type,e))}}function Fe(o){we?ge?ge.push(o):ge=[o]:we=o}function Ve(){if(we){var o=we,e=ge;if(ge=we=null,Oe(o),e)for(o=0;o>>=0,o===0?32:31-(cr(o)/Co|0)|0}var Tr=64,wn=4194304;function Pr(o){switch(o&-o){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return o&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return o&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return o}}function mr(o,e){var t=o.pendingLanes;if(t===0)return 0;var r=0,a=o.suspendedLanes,l=o.pingedLanes,v=t&268435455;if(v!==0){var P=v&~a;P!==0?r=Pr(P):(l&=v,l!==0&&(r=Pr(l)))}else v=t&~a,v!==0?r=Pr(v):l!==0&&(r=Pr(l));if(r===0)return 0;if(e!==0&&e!==r&&!(e&a)&&(a=r&-r,l=e&-e,a>=l||a===16&&(l&4194240)!==0))return e;if(r&4&&(r|=t&16),e=o.entangledLanes,e!==0)for(o=o.entanglements,e&=r;0t;t++)e.push(o);return e}function tr(o,e,t){o.pendingLanes|=e,e!==536870912&&(o.suspendedLanes=0,o.pingedLanes=0),o=o.eventTimes,e=31-On(e),o[e]=t}function Ar(o,e){var t=o.pendingLanes&~e;o.pendingLanes=e,o.suspendedLanes=0,o.pingedLanes=0,o.expiredLanes&=e,o.mutableReadLanes&=e,o.entangledLanes&=e,e=o.entanglements;var r=o.eventTimes;for(o=o.expirationTimes;0=ni),hl=" ",ts=!1;function ju(o,e){switch(o){case"keyup":return Ys.indexOf(e.keyCode)!==-1;case"keydown":return e.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function ns(o){return o=o.detail,typeof o=="object"&&"data"in o?o.data:null}var xi=!1;function iu(o,e){switch(o){case"compositionend":return ns(e);case"keypress":return e.which!==32?null:(ts=!0,hl);case"textInput":return o=e.data,o===hl&&ts?null:o;default:return null}}function $c(o,e){if(xi)return o==="compositionend"||!pl&&ju(o,e)?(o=Hn(),Kn=xn=Yt=null,xi=!1,o):null;switch(o){case"paste":return null;case"keypress":if(!(e.ctrlKey||e.altKey||e.metaKey)||e.ctrlKey&&e.altKey){if(e.char&&1=e)return{node:t,offset:e-o};o=r}e:{for(;t;){if(t.nextSibling){t=t.nextSibling;break e}t=t.parentNode}t=void 0}t=Bi(t)}}function gl(o,e){return o&&e?o===e?!0:o&&o.nodeType===3?!1:e&&e.nodeType===3?gl(o,e.parentNode):"contains"in o?o.contains(e):o.compareDocumentPosition?!!(o.compareDocumentPosition(e)&16):!1:!1}function yl(){for(var o=window,e=De();i(e,o.HTMLIFrameElement);){try{var t=typeof e.contentWindow.location.href=="string"}catch(r){t=!1}if(t)o=e.contentWindow;else break;e=De(o.document)}return e}function xl(o){var e=o&&o.nodeName&&o.nodeName.toLowerCase();return e&&(e==="input"&&(o.type==="text"||o.type==="search"||o.type==="tel"||o.type==="url"||o.type==="password")||e==="textarea"||o.contentEditable==="true")}function zu(o){var e=yl(),t=o.focusedElem,r=o.selectionRange;if(e!==t&&t&&t.ownerDocument&&gl(t.ownerDocument.documentElement,t)){if(r!==null&&xl(t)){if(e=r.start,o=r.end,o===void 0&&(o=e),"selectionStart"in t)t.selectionStart=e,t.selectionEnd=Math.min(o,t.value.length);else if(o=(e=t.ownerDocument||document)&&e.defaultView||window,o.getSelection){o=o.getSelection();var a=t.textContent.length,l=Math.min(r.start,a);r=r.end===void 0?l:Math.min(r.end,a),!o.extend&&l>r&&(a=r,r=l,l=a),a=uu(t,l);var v=uu(t,r);a&&v&&(o.rangeCount!==1||o.anchorNode!==a.node||o.anchorOffset!==a.offset||o.focusNode!==v.node||o.focusOffset!==v.offset)&&(e=e.createRange(),e.setStart(a.node,a.offset),o.removeAllRanges(),l>r?(o.addRange(e),o.extend(v.node,v.offset)):(e.setEnd(v.node,v.offset),o.addRange(e)))}}for(e=[],o=t;o=o.parentNode;)o.nodeType===1&&e.push({element:o,left:o.scrollLeft,top:o.scrollTop});for(typeof t.focus=="function"&&t.focus(),t=0;t=document.documentMode,lu=null,ri=null,Ba=null,ba=!1;function Sl(o,e,t){var r=t.window===t?t.document:t.nodeType===9?t:t.ownerDocument;ba||lu==null||lu!==De(r)||(r=lu,"selectionStart"in r&&xl(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Ba&&dr(Ba,r)||(Ba=r,r=$i(ri,"onSelect"),0Oi||(o.current=va[Oi],va[Oi]=null,Oi--)}function zt(o,e){Oi++,va[Oi]=o.current,o.current=e}var vn={},bn=No(vn),Tn=No(!1),xr=vn;function Ur(o,e){var t=o.type.contextTypes;if(!t)return vn;var r=o.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===e)return r.__reactInternalMemoizedMaskedChildContext;var a={},l;for(l in t)a[l]=e[l];return r&&(o=o.stateNode,o.__reactInternalMemoizedUnmaskedChildContext=e,o.__reactInternalMemoizedMaskedChildContext=a),a}function Sr(o){return o=o.childContextTypes,o!=null}function kr(){mn(Tn),mn(bn)}function Wa(o,e,t){if(bn.current!==vn)throw Error(f(168));zt(bn,e),zt(Tn,t)}function hu(o,e,t){var r=o.stateNode;if(e=e.childContextTypes,typeof r.getChildContext!="function")return t;r=r.getChildContext();for(var a in r)if(!(a in e))throw Error(f(108,me(o)||"Unknown",a));return ae({},t,r)}function mu(o){return o=(o=o.stateNode)&&o.__reactInternalMemoizedMergedChildContext||vn,xr=bn.current,zt(bn,o),zt(Tn,Tn.current),!0}function gu(o,e,t){var r=o.stateNode;if(!r)throw Error(f(169));t?(o=hu(o,e,xr),r.__reactInternalMemoizedMergedChildContext=o,mn(Tn),mn(bn),zt(bn,o)):mn(Tn),zt(Tn,t)}var Mo=null,jo=!1,pa=!1;function Cl(o){Mo===null?Mo=[o]:Mo.push(o)}function yu(o){jo=!0,Cl(o)}function Ti(){if(!pa&&Mo!==null){pa=!0;var o=0,e=tn;try{var t=Mo;for(tn=1;o>=v,a-=v,ro=1<<32-On(e)+a|t<it?(Nt=nt,nt=null):Nt=nt.sibling;var Ht=Se(Ce,nt,X[it],se);if(Ht===null){nt===null&&(nt=Nt);break}o&&nt&&Ht.alternate===null&&e(Ce,nt),Y=l(Ht,Y,it),Je===null?Le=Ht:Je.sibling=Ht,Je=Ht,nt=Nt}if(it===X.length)return t(Ce,nt),nn&&Nr(Ce,it),Le;if(nt===null){for(;itit?(Nt=nt,nt=null):Nt=nt.sibling;var on=Se(Ce,nt,Ht.value,se);if(on===null){nt===null&&(nt=Nt);break}o&&nt&&on.alternate===null&&e(Ce,nt),Y=l(on,Y,it),Je===null?Le=on:Je.sibling=on,Je=on,nt=Nt}if(Ht.done)return t(Ce,nt),nn&&Nr(Ce,it),Le;if(nt===null){for(;!Ht.done;it++,Ht=X.next())Ht=fe(Ce,Ht.value,se),Ht!==null&&(Y=l(Ht,Y,it),Je===null?Le=Ht:Je.sibling=Ht,Je=Ht);return nn&&Nr(Ce,it),Le}for(nt=r(Ce,nt);!Ht.done;it++,Ht=X.next())Ht=Re(nt,Ce,it,Ht.value,se),Ht!==null&&(o&&Ht.alternate!==null&&nt.delete(Ht.key===null?it:Ht.key),Y=l(Ht,Y,it),Je===null?Le=Ht:Je.sibling=Ht,Je=Ht);return o&&nt.forEach(function(eu){return e(Ce,eu)}),nn&&Nr(Ce,it),Le}function gt(Ce,Y,X,se){if(typeof X=="object"&&X!==null&&X.type===G&&X.key===null&&(X=X.props.children),typeof X=="object"&&X!==null){switch(X.$$typeof){case F:e:{for(var Le=X.key,Je=Y;Je!==null;){if(Je.key===Le){if(Le=X.type,Le===G){if(Je.tag===7){t(Ce,Je.sibling),Y=a(Je,X.props.children),Y.return=Ce,Ce=Y;break e}}else if(Je.elementType===Le||typeof Le=="object"&&Le!==null&&Le.$$typeof===K&&Lo(Le)===Je.type){t(Ce,Je.sibling),Y=a(Je,X.props),Y.ref=ai(Ce,Je,X),Y.return=Ce,Ce=Y;break e}t(Ce,Je);break}else e(Ce,Je);Je=Je.sibling}X.type===G?(Y=Ji(X.props.children,Ce.mode,se,X.key),Y.return=Ce,Ce=Y):(se=Mi(X.type,X.key,X.props,null,Ce.mode,se),se.ref=ai(Ce,Y,X),se.return=Ce,Ce=se)}return v(Ce);case V:e:{for(Je=X.key;Y!==null;){if(Y.key===Je)if(Y.tag===4&&Y.stateNode.containerInfo===X.containerInfo&&Y.stateNode.implementation===X.implementation){t(Ce,Y.sibling),Y=a(Y,X.children||[]),Y.return=Ce,Ce=Y;break e}else{t(Ce,Y);break}else e(Ce,Y);Y=Y.sibling}Y=$l(X,Ce.mode,se),Y.return=Ce,Ce=Y}return v(Ce);case K:return Je=X._init,gt(Ce,Y,Je(X._payload),se)}if(Ue(X))return ke(Ce,Y,X,se);if(H(X))return Ke(Ce,Y,X,se);To(Ce,X)}return typeof X=="string"&&X!==""||typeof X=="number"?(X=""+X,Y!==null&&Y.tag===6?(t(Ce,Y.sibling),Y=a(Y,X),Y.return=Ce,Ce=Y):(t(Ce,Y),Y=nl(X,Ce.mode,se),Y.return=Ce,Ce=Y),v(Ce)):t(Ce,Y)}return gt}var ui=ga(!0),Io=ga(!1),Ki={},io=No(Ki),Vr=No(Ki),Ii=No(Ki);function Do(o){if(o===Ki)throw Error(f(174));return o}function wi(o,e){switch(zt(Ii,e),zt(Vr,o),zt(io,Ki),o=e.nodeType,o){case 9:case 11:e=(e=e.documentElement)?e.namespaceURI:xt(null,"");break;default:o=o===8?e.parentNode:e,e=o.namespaceURI||null,o=o.tagName,e=xt(e,o)}mn(io),zt(io,e)}function Hi(){mn(io),mn(Vr),mn(Ii)}function Gi(o){Do(Ii.current);var e=Do(io.current),t=xt(e,o.type);e!==t&&(zt(Vr,o),zt(io,t))}function Su(o){Vr.current===o&&(mn(io),mn(Vr))}var Dn=No(0);function Nn(o){for(var e=o;e!==null;){if(e.tag===13){var t=e.memoizedState;if(t!==null&&(t=t.dehydrated,t===null||t.data==="$?"||t.data==="$!"))return e}else if(e.tag===19&&e.memoizedProps.revealOrder!==void 0){if(e.flags&128)return e}else if(e.child!==null){e.child.return=e,e=e.child;continue}if(e===o)break;for(;e.sibling===null;){if(e.return===null||e.return===o)return null;e=e.return}e.sibling.return=e.return,e=e.sibling}return null}var Fo=[];function Yi(){for(var o=0;ot?t:4,o(!0);var r=xa.transition;xa.transition={};try{o(!1),e()}finally{tn=t,xa.transition=r}}function Hc(){return Er().memoizedState}function Gc(o,e,t){var r=vr(o);if(t={lane:r,action:t,hasEagerState:!1,eagerState:null,next:null},Yc(o))sc(e,t);else if(t=Lt(o,e,t,r),t!==null){var a=Xr();Qr(t,o,r,a),cc(t,e,r)}}function cf(o,e,t){var r=vr(o),a={lane:r,action:t,hasEagerState:!1,eagerState:null,next:null};if(Yc(o))sc(e,a);else{var l=o.alternate;if(o.lanes===0&&(l===null||l.lanes===0)&&(l=e.lastRenderedReducer,l!==null))try{var v=e.lastRenderedState,P=l(v,t);if(a.hasEagerState=!0,a.eagerState=P,Vo(P,v)){var k=e.interleaved;k===null?(a.next=a,ht(e)):(a.next=k.next,k.next=a),e.interleaved=a;return}}catch(Q){}finally{}t=Lt(o,e,a,r),t!==null&&(a=Xr(),Qr(t,o,r,a),cc(t,e,r))}}function Yc(o){var e=o.alternate;return o===Sn||e!==null&&e===Sn}function sc(o,e){Ka=Jn=!0;var t=o.pending;t===null?e.next=e:(e.next=t.next,t.next=e),o.pending=e}function cc(o,e,t){if(t&4194240){var r=e.lanes;r&=o.pendingLanes,t|=r,e.lanes=t,Jr(o,t)}}var Dl={readContext:vt,useCallback:ao,useContext:ao,useEffect:ao,useImperativeHandle:ao,useInsertionEffect:ao,useLayoutEffect:ao,useMemo:ao,useReducer:ao,useRef:ao,useState:ao,useDebugValue:ao,useDeferredValue:ao,useTransition:ao,useMutableSource:ao,useSyncExternalStore:ao,useId:ao,unstable_isNewReconciler:!1},ms={readContext:vt,useCallback:function(e,t){return li().memoizedState=[e,t===void 0?null:t],e},useContext:vt,useEffect:Ll,useImperativeHandle:function(e,t,r){return r=r!=null?r.concat([e]):null,jl(4194308,4,ic.bind(null,t,e),r)},useLayoutEffect:function(e,t){return jl(4194308,4,e,t)},useInsertionEffect:function(e,t){return jl(4,2,e,t)},useMemo:function(e,t){var r=li();return t=t===void 0?null:t,e=e(),r.memoizedState=[e,t],e},useReducer:function(e,t,r){var a=li();return t=r!==void 0?r(t):t,a.memoizedState=a.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},a.queue=e,e=e.dispatch=Gc.bind(null,Sn,e),[a.memoizedState,e]},useRef:function(e){var t=li();return e={current:e},t.memoizedState=e},useState:rc,useDebugValue:ps,useDeferredValue:function(e){return li().memoizedState=e},useTransition:function(){var e=rc(!1),t=e[0];return e=Kc.bind(null,e[1]),li().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,r){var a=Sn,l=li();if(nn){if(r===void 0)throw Error(f(407));r=r()}else{if(r=t(),$t===null)throw Error(f(349));Jo&30||qs(a,t,r)}l.memoizedState=r;var v={value:r,getSnapshot:t};return l.queue=v,Ll(ec.bind(null,a,v,e),[e]),a.flags|=2048,Ku(9,_s.bind(null,a,v,r,t),void 0,null),r},useId:function(){var e=li(),t=$t.identifierPrefix;if(nn){var r=Wr,a=ro;r=(a&~(1<<32-On(a)-1)).toString(32)+r,t=":"+t+"R"+r,r=Sa++,0<\/script>",o=o.removeChild(o.firstChild)):typeof r.is=="string"?o=v.createElement(t,{is:r.is}):(o=v.createElement(t),t==="select"&&(v=o,r.multiple?v.multiple=!0:r.size&&(v.size=r.size))):o=v.createElementNS(o,t),o[_r]=e,o[zr]=r,Jc(o,e,!1,!1),e.stateNode=o;e:{switch(v=kn(t,r),t){case"dialog":Rn("cancel",o),Rn("close",o),a=r;break;case"iframe":case"object":case"embed":Rn("load",o),a=r;break;case"video":case"audio":for(a=0;aXa&&(e.flags|=128,r=!0,Xu(l,!1),e.lanes=4194304)}else{if(!r)if(o=Nn(v),o!==null){if(e.flags|=128,r=!0,t=o.updateQueue,t!==null&&(e.updateQueue=t,e.flags|=4),Xu(l,!0),l.tail===null&&l.tailMode==="hidden"&&!v.alternate&&!nn)return Cr(e),null}else 2*ln()-l.renderingStartTime>Xa&&t!==1073741824&&(e.flags|=128,r=!0,Xu(l,!1),e.lanes=4194304);l.isBackwards?(v.sibling=e.child,e.child=v):(t=l.last,t!==null?t.sibling=v:e.child=v,l.last=v)}return l.tail!==null?(e=l.tail,l.rendering=e,l.tail=e.sibling,l.renderingStartTime=ln(),e.sibling=null,t=Dn.current,zt(Dn,r?t&1|2:t&1),e):(Cr(e),null);case 22:case 23:return wa(),r=e.memoizedState!==null,o!==null&&o.memoizedState!==null!==r&&(e.flags|=8192),r&&e.mode&1?Pn&1073741824&&(Cr(e),e.subtreeFlags&6&&(e.flags|=8192)):Cr(e),null;case 24:return null;case 25:return null}throw Error(f(156,e.tag))}function vf(o,e){switch(Vu(e),e.tag){case 1:return Sr(e.type)&&kr(),o=e.flags,o&65536?(e.flags=o&-65537|128,e):null;case 3:return Hi(),mn(Tn),mn(bn),Yi(),o=e.flags,o&65536&&!(o&128)?(e.flags=o&-65537|128,e):null;case 5:return Su(e),null;case 13:if(mn(Dn),o=e.memoizedState,o!==null&&o.dehydrated!==null){if(e.alternate===null)throw Error(f(340));re()}return o=e.flags,o&65536?(e.flags=o&-65537|128,e):null;case 19:return mn(Dn),null;case 4:return Hi(),null;case 10:return ot(e.type._context),null;case 22:case 23:return wa(),null;case 24:return null;default:return null}}var Rs=!1,Mr=!1,co=typeof WeakSet=="function"?WeakSet:Set,Ct=null;function Et(o,e){var t=o.ref;if(t!==null)if(typeof t=="function")try{t(null)}catch(r){ir(o,e,r)}else t.current=null}function Ga(o,e,t){try{t()}catch(r){ir(o,e,r)}}var Ns=!1;function qc(o,e){if(du=Wo,o=yl(),xl(o)){if("selectionStart"in o)var t={start:o.selectionStart,end:o.selectionEnd};else e:{t=(t=o.ownerDocument)&&t.defaultView||window;var r=t.getSelection&&t.getSelection();if(r&&r.rangeCount!==0){t=r.anchorNode;var a=r.anchorOffset,l=r.focusNode;r=r.focusOffset;try{t.nodeType,l.nodeType}catch(se){t=null;break e}var v=0,P=-1,k=-1,Q=0,ie=0,fe=o,Se=null;t:for(;;){for(var Re;fe!==t||a!==0&&fe.nodeType!==3||(P=v+a),fe!==l||r!==0&&fe.nodeType!==3||(k=v+r),fe.nodeType===3&&(v+=fe.nodeValue.length),(Re=fe.firstChild)!==null;)Se=fe,fe=Re;for(;;){if(fe===o)break t;if(Se===t&&++Q===a&&(P=v),Se===l&&++ie===r&&(k=v),(Re=fe.nextSibling)!==null)break;fe=Se,Se=fe.parentNode}fe=Re}t=P===-1||k===-1?null:{start:P,end:k}}else t=null}t=t||{start:0,end:0}}else t=null;for(vu={focusedElem:o,selectionRange:t},Wo=!1,Ct=e;Ct!==null;)if(e=Ct,o=e.child,(e.subtreeFlags&1028)!==0&&o!==null)o.return=e,Ct=o;else for(;Ct!==null;){e=Ct;try{var ke=e.alternate;if(e.flags&1024)switch(e.tag){case 0:case 11:case 15:break;case 1:if(ke!==null){var Ke=ke.memoizedProps,gt=ke.memoizedState,Ce=e.stateNode,Y=Ce.getSnapshotBeforeUpdate(e.elementType===e.type?Ke:ue(e.type,Ke),gt);Ce.__reactInternalSnapshotBeforeUpdate=Y}break;case 3:var X=e.stateNode.containerInfo;X.nodeType===1?X.textContent="":X.nodeType===9&&X.documentElement&&X.removeChild(X.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(f(163))}}catch(se){ir(e,e.return,se)}if(o=e.sibling,o!==null){o.return=e.return,Ct=o;break}Ct=e.return}return ke=Ns,Ns=!1,ke}function zl(o,e,t){var r=e.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var a=r=r.next;do{if((a.tag&o)===o){var l=a.destroy;a.destroy=void 0,l!==void 0&&Ga(e,t,l)}a=a.next}while(a!==r)}}function Ya(o,e){if(e=e.updateQueue,e=e!==null?e.lastEffect:null,e!==null){var t=e=e.next;do{if((t.tag&o)===o){var r=t.create;t.destroy=r()}t=t.next}while(t!==e)}}function Qu(o){var e=o.ref;if(e!==null){var t=o.stateNode;switch(o.tag){case 5:o=t;break;default:o=t}typeof e=="function"?e(o):e.current=o}}function Ms(o){var e=o.alternate;e!==null&&(o.alternate=null,Ms(e)),o.child=null,o.deletions=null,o.sibling=null,o.tag===5&&(e=o.stateNode,e!==null&&(delete e[_r],delete e[zr],delete e[Eo],delete e[wl],delete e[cs])),o.stateNode=null,o.return=null,o.dependencies=null,o.memoizedProps=null,o.memoizedState=null,o.pendingProps=null,o.stateNode=null,o.updateQueue=null}function Oc(o){return o.tag===5||o.tag===3||o.tag===4}function Tc(o){e:for(;;){for(;o.sibling===null;){if(o.return===null||Oc(o.return))return null;o=o.return}for(o.sibling.return=o.return,o=o.sibling;o.tag!==5&&o.tag!==6&&o.tag!==18;){if(o.flags&2||o.child===null||o.tag===4)continue e;o.child.return=o,o=o.child}if(!(o.flags&2))return o.stateNode}}function js(o,e,t){var r=o.tag;if(r===5||r===6)o=o.stateNode,e?t.nodeType===8?t.parentNode.insertBefore(o,e):t.insertBefore(o,e):(t.nodeType===8?(e=t.parentNode,e.insertBefore(o,t)):(e=t,e.appendChild(o)),t=t._reactRootContainer,t!=null||e.onclick!==null||(e.onclick=ca));else if(r!==4&&(o=o.child,o!==null))for(js(o,e,t),o=o.sibling;o!==null;)js(o,e,t),o=o.sibling}function Ul(o,e,t){var r=o.tag;if(r===5||r===6)o=o.stateNode,e?t.insertBefore(o,e):t.appendChild(o);else if(r!==4&&(o=o.child,o!==null))for(Ul(o,e,t),o=o.sibling;o!==null;)Ul(o,e,t),o=o.sibling}var jr=null,Fn=!1;function Hr(o,e,t){for(t=t.child;t!==null;)Oa(o,e,t),t=t.sibling}function Oa(o,e,t){if(Wn&&typeof Wn.onCommitFiberUnmount=="function")try{Wn.onCommitFiberUnmount(hn,t)}catch(P){}switch(t.tag){case 5:Mr||Et(t,e);case 6:var r=jr,a=Fn;jr=null,Hr(o,e,t),jr=r,Fn=a,jr!==null&&(Fn?(o=jr,t=t.stateNode,o.nodeType===8?o.parentNode.removeChild(t):o.removeChild(t)):jr.removeChild(t.stateNode));break;case 18:jr!==null&&(Fn?(o=jr,t=t.stateNode,o.nodeType===8?Il(o.parentNode,t):o.nodeType===1&&Il(o,t),Ao(o)):Il(jr,t.stateNode));break;case 4:r=jr,a=Fn,jr=t.stateNode.containerInfo,Fn=!0,Hr(o,e,t),jr=r,Fn=a;break;case 0:case 11:case 14:case 15:if(!Mr&&(r=t.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){a=r=r.next;do{var l=a,v=l.destroy;l=l.tag,v!==void 0&&(l&2||l&4)&&Ga(t,e,v),a=a.next}while(a!==r)}Hr(o,e,t);break;case 1:if(!Mr&&(Et(t,e),r=t.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=t.memoizedProps,r.state=t.memoizedState,r.componentWillUnmount()}catch(P){ir(t,e,P)}Hr(o,e,t);break;case 21:Hr(o,e,t);break;case 22:t.mode&1?(Mr=(r=Mr)||t.memoizedState!==null,Hr(o,e,t),Mr=r):Hr(o,e,t);break;default:Hr(o,e,t)}}function Ic(o){var e=o.updateQueue;if(e!==null){o.updateQueue=null;var t=o.stateNode;t===null&&(t=o.stateNode=new co),e.forEach(function(r){var a=hf.bind(null,o,r);t.has(r)||(t.add(r),r.then(a,a))})}}function ci(o,e){var t=e.deletions;if(t!==null)for(var r=0;ra&&(a=v),r&=~l}if(r=a,r=ln()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*ef(r/1960))-r,10o?16:o,Ri===null)var r=!1;else{if(o=Ri,Ri=null,Ni=0,Zt&6)throw Error(f(331));var a=Zt;for(Zt|=4,Ct=o.current;Ct!==null;){var l=Ct,v=l.child;if(Ct.flags&16){var P=l.deletions;if(P!==null){for(var k=0;kln()-fo?Ca(o,0):Ju|=t),_n(o,e)}function nf(o,e){e===0&&(o.mode&1?(e=wn,wn<<=1,!(wn&130023424)&&(wn=4194304)):e=1);var t=Xr();o=At(o,e),o!==null&&(tr(o,e,t),_n(o,t))}function rf(o){var e=o.memoizedState,t=0;e!==null&&(t=e.retryLane),nf(o,t)}function hf(o,e){var t=0;switch(o.tag){case 13:var r=o.stateNode,a=o.memoizedState;a!==null&&(t=a.retryLane);break;case 19:r=o.stateNode;break;default:throw Error(f(314))}r!==null&&r.delete(e),nf(o,t)}var of;of=function(e,t,r){if(e!==null)if(e.memoizedProps!==t.pendingProps||Tn.current)Bo=!0;else{if(!(e.lanes&r)&&!(t.flags&128))return Bo=!1,Ea(e,t,r);Bo=!!(e.flags&131072)}else Bo=!1,nn&&t.flags&1048576&&ma(t,ha,t.index);switch(t.lanes=0,t.tag){case 2:var a=t.type;bl(e,t),e=t.pendingProps;var l=Ur(t,bn.current);ft(t,r),l=Rl(null,t,a,e,l,r);var v=Nl();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Sr(a)?(v=!0,mu(t)):v=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,Dt(t),l.updater=Zo,t.stateNode=l,l._reactInternals=t,Vi(t,a,e,r),t=xs(null,t,a,!0,v,r)):(t.tag=0,nn&&v&&Pl(t),Mn(null,t,l,r),t=t.child),t;case 16:a=t.elementType;e:{switch(bl(e,t),e=t.pendingProps,l=a._init,a=l(a._payload),t.type=a,l=t.tag=jc(a),e=ue(a,e),l){case 0:t=gs(null,t,a,e,r);break e;case 1:t=ys(null,t,a,e,r);break e;case 11:t=lo(null,t,a,e,r);break e;case 14:t=mc(null,t,a,ue(a.type,e),r);break e}throw Error(f(306,a,""))}return t;case 0:return a=t.type,l=t.pendingProps,l=t.elementType===a?l:ue(a,l),gs(e,t,a,l,r);case 1:return a=t.type,l=t.pendingProps,l=t.elementType===a?l:ue(a,l),ys(e,t,a,l,r);case 3:e:{if(Ss(t),e===null)throw Error(f(387));a=t.pendingProps,v=t.memoizedState,l=v.element,Xt(e,t),Gn(t,a,null,r);var P=t.memoizedState;if(a=P.element,v.isDehydrated)if(v={element:a,isDehydrated:!1,cache:P.cache,pendingSuspenseBoundaries:P.pendingSuspenseBoundaries,transitions:P.transitions},t.updateQueue.baseState=v,t.memoizedState=v,t.flags&256){l=Gu(Error(f(423)),t),t=Sc(e,t,a,r,l);break e}else if(a!==l){l=Gu(Error(f(424)),t),t=Sc(e,t,a,r,l);break e}else for(zn=Ko(t.stateNode.containerInfo.firstChild),oo=t,nn=!0,pn=null,r=Io(t,null,a,r),t.child=r;r;)r.flags=r.flags&-3|4096,r=r.sibling;else{if(re(),a===l){t=si(e,t,r);break e}Mn(e,t,a,r)}t=t.child}return t;case 5:return Gi(t),e===null&&A(t),a=t.type,l=t.pendingProps,v=e!==null?e.memoizedProps:null,P=l.children,$a(a,l)?P=null:v!==null&&$a(a,v)&&(t.flags|=32),xc(e,t),Mn(e,t,P,r),t.child;case 6:return e===null&&A(t),null;case 13:return Os(e,t,r);case 4:return wi(t,t.stateNode.containerInfo),a=t.pendingProps,e===null?t.child=ui(t,null,a,r):Mn(e,t,a,r),t.child;case 11:return a=t.type,l=t.pendingProps,l=t.elementType===a?l:ue(a,l),lo(e,t,a,l,r);case 7:return Mn(e,t,t.pendingProps,r),t.child;case 8:return Mn(e,t,t.pendingProps.children,r),t.child;case 12:return Mn(e,t,t.pendingProps.children,r),t.child;case 10:e:{if(a=t.type._context,l=t.pendingProps,v=t.memoizedProps,P=l.value,zt(ve,a._currentValue),a._currentValue=P,v!==null)if(Vo(v.value,P)){if(v.children===l.children&&!Tn.current){t=si(e,t,r);break e}}else for(v=t.child,v!==null&&(v.return=t);v!==null;){var k=v.dependencies;if(k!==null){P=v.child;for(var Q=k.firstContext;Q!==null;){if(Q.context===a){if(v.tag===1){Q=Mt(-1,r&-r),Q.tag=2;var ie=v.updateQueue;if(ie!==null){ie=ie.shared;var fe=ie.pending;fe===null?Q.next=Q:(Q.next=fe.next,fe.next=Q),ie.pending=Q}}v.lanes|=r,Q=v.alternate,Q!==null&&(Q.lanes|=r),st(v.return,r,t),k.lanes|=r;break}Q=Q.next}}else if(v.tag===10)P=v.type===t.type?null:v.child;else if(v.tag===18){if(P=v.return,P===null)throw Error(f(341));P.lanes|=r,k=P.alternate,k!==null&&(k.lanes|=r),st(P,r,t),P=v.sibling}else P=v.child;if(P!==null)P.return=v;else for(P=v;P!==null;){if(P===t){P=null;break}if(v=P.sibling,v!==null){v.return=P.return,P=v;break}P=P.return}v=P}Mn(e,t,l.children,r),t=t.child}return t;case 9:return l=t.type,a=t.pendingProps.children,ft(t,r),l=vt(l),a=a(l),t.flags|=1,Mn(e,t,a,r),t.child;case 14:return a=t.type,l=ue(a,t.pendingProps),l=ue(a.type,l),mc(e,t,a,l,r);case 15:return gc(e,t,t.type,t.pendingProps,r);case 17:return a=t.type,l=t.pendingProps,l=t.elementType===a?l:ue(a,l),bl(e,t),t.tag=1,Sr(a)?(e=!0,mu(t)):e=!1,ft(t,r),Va(t,a,l),Vi(t,a,l,r),xs(null,t,a,!0,e,r);case 19:return Cs(e,t,r);case 22:return yc(e,t,r)}throw Error(f(156,t.tag))};function Mc(o,e){return Or(o,e)}function af(o,e,t,r){this.tag=o,this.key=t,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=e,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function vi(o,e,t,r){return new af(o,e,t,r)}function Uo(o){return o=o.prototype,!(!o||!o.isReactComponent)}function jc(o){if(typeof o=="function")return Uo(o)?1:0;if(o!=null){if(o=o.$$typeof,o===te)return 11;if(o===q)return 14}return 2}function _a(o,e){var t=o.alternate;return t===null?(t=vi(o.tag,e,o.key,o.mode),t.elementType=o.elementType,t.type=o.type,t.stateNode=o.stateNode,t.alternate=o,o.alternate=t):(t.pendingProps=e,t.type=o.type,t.flags=0,t.subtreeFlags=0,t.deletions=null),t.flags=o.flags&14680064,t.childLanes=o.childLanes,t.lanes=o.lanes,t.child=o.child,t.memoizedProps=o.memoizedProps,t.memoizedState=o.memoizedState,t.updateQueue=o.updateQueue,e=o.dependencies,t.dependencies=e===null?null:{lanes:e.lanes,firstContext:e.firstContext},t.sibling=o.sibling,t.index=o.index,t.ref=o.ref,t}function Mi(o,e,t,r,a,l){var v=2;if(r=o,typeof o=="function")Uo(o)&&(v=1);else if(typeof o=="string")v=5;else e:switch(o){case G:return Ji(t.children,a,l,e);case J:v=8,a|=8;break;case oe:return o=vi(12,t,e,a|2),o.elementType=oe,o.lanes=l,o;case pe:return o=vi(13,t,e,a),o.elementType=pe,o.lanes=l,o;case ce:return o=vi(19,t,e,a),o.elementType=ce,o.lanes=l,o;case _:return qi(t,a,l,e);default:if(typeof o=="object"&&o!==null)switch(o.$$typeof){case Z:v=10;break e;case ne:v=9;break e;case te:v=11;break e;case q:v=14;break e;case K:v=16,r=null;break e}throw Error(f(130,o==null?o:typeof o=="undefined"?"undefined":u(o),""))}return e=vi(v,t,e,a),e.elementType=o,e.type=r,e.lanes=l,e}function Ji(o,e,t,r){return o=vi(7,o,r,e),o.lanes=t,o}function qi(o,e,t,r){return o=vi(22,o,r,e),o.elementType=_,o.lanes=t,o.stateNode={isHidden:!1},o}function nl(o,e,t){return o=vi(6,o,null,e),o.lanes=t,o}function $l(o,e,t){return e=vi(4,o.children!==null?o.children:[],o.key,e),e.lanes=t,e.stateNode={containerInfo:o.containerInfo,pendingChildren:null,implementation:o.implementation},e}function Lc(o,e,t,r,a){this.tag=e,this.containerInfo=o,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=ko(0),this.expirationTimes=ko(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=ko(0),this.identifierPrefix=r,this.onRecoverableError=a,this.mutableSourceEagerHydrationData=null}function Dc(o,e,t,r,a,l,v,P,k){return o=new Lc(o,e,t,P,k),e===1?(e=1,l===!0&&(e|=8)):e=0,l=vi(3,null,null,e),o.current=l,l.stateNode=o,l.memoizedState={element:r,isDehydrated:t,cache:null,transitions:null,pendingSuspenseBoundaries:null},Dt(l),o}function Fc(o,e,t){var r=3e}return!1}function M(o,e,t,r,a,l,v){this.acceptsBooleans=e===2||e===3||e===4,this.attributeName=r,this.attributeNamespace=a,this.mustUseProperty=t,this.propertyName=o,this.type=e,this.sanitizeURL=l,this.removeEmptyString=v}var U={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(o){U[o]=new M(o,0,!1,o,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(o){var e=o[0];U[e]=new M(e,1,!1,o[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(o){U[o]=new M(o,2,!1,o.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(o){U[o]=new M(o,2,!1,o,null,!1,!1)}),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(o){U[o]=new M(o,3,!1,o.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(o){U[o]=new M(o,3,!0,o,null,!1,!1)}),["capture","download"].forEach(function(o){U[o]=new M(o,4,!1,o,null,!1,!1)}),["cols","rows","size","span"].forEach(function(o){U[o]=new M(o,6,!1,o,null,!1,!1)}),["rowSpan","start"].forEach(function(o){U[o]=new M(o,5,!1,o.toLowerCase(),null,!1,!1)});var z=/[\-:]([a-z])/g;function D(o){return o[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(o){var e=o.replace(z,D);U[e]=new M(e,1,!1,o,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(o){var e=o.replace(z,D);U[e]=new M(e,1,!1,o,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(o){var e=o.replace(z,D);U[e]=new M(e,1,!1,o,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(o){U[o]=new M(o,1,!1,o.toLowerCase(),null,!1,!1)}),U.xlinkHref=new M("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(o){U[o]=new M(o,1,!1,o.toLowerCase(),null,!0,!0)});function b(o,e,t,r){var a=U.hasOwnProperty(e)?U[e]:null;(a!==null?a.type!==0:r||!(2P||a[v]!==l[P]){var k="\n"+a[v].replace(" at new "," at ");return o.displayName&&k.includes("")&&(k=k.replace("",o.displayName)),k}while(1<=v&&0<=P);break}}}finally{ye=!1,Error.prepareStackTrace=t}return(o=o?o.displayName||o.name:"")?Te(o):""}function Ae(o){switch(o.tag){case 5:return Te(o.type);case 16:return Te("Lazy");case 13:return Te("Suspense");case 19:return Te("SuspenseList");case 0:case 2:case 15:return o=xe(o.type,!1),o;case 11:return o=xe(o.type.render,!1),o;case 1:return o=xe(o.type,!0),o;default:return""}}function Pe(o){if(o==null)return null;if(typeof o=="function")return o.displayName||o.name||null;if(typeof o=="string")return o;switch(o){case G:return"Fragment";case V:return"Portal";case oe:return"Profiler";case J:return"StrictMode";case pe:return"Suspense";case ce:return"SuspenseList"}if(typeof o=="object")switch(o.$$typeof){case ne:return(o.displayName||"Context")+".Consumer";case Z:return(o._context.displayName||"Context")+".Provider";case te:var e=o.render;return o=o.displayName,o||(o=e.displayName||e.name||"",o=o!==""?"ForwardRef("+o+")":"ForwardRef"),o;case q:return e=o.displayName||null,e!==null?e:Pe(o.type)||"Memo";case K:e=o._payload,o=o._init;try{return Pe(o(e))}catch(t){}}return null}function me(o){var e=o.type;switch(o.tag){case 24:return"Cache";case 9:return(e.displayName||"Context")+".Consumer";case 10:return(e._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return o=e.render,o=o.displayName||o.name||"",e.displayName||(o!==""?"ForwardRef("+o+")":"ForwardRef");case 7:return"Fragment";case 5:return e;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Pe(e);case 8:return e===J?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e}return null}function Ye(o){switch(typeof o=="undefined"?"undefined":u(o)){case"boolean":case"number":case"string":case"undefined":return o;case"object":return o;default:return""}}function Qe(o){var e=o.type;return(o=o.nodeName)&&o.toLowerCase()==="input"&&(e==="checkbox"||e==="radio")}function yt(o){var e=Qe(o)?"checked":"value",t=Object.getOwnPropertyDescriptor(o.constructor.prototype,e),r=""+o[e];if(!o.hasOwnProperty(e)&&typeof t!="undefined"&&typeof t.get=="function"&&typeof t.set=="function"){var a=t.get,l=t.set;return Object.defineProperty(o,e,{configurable:!0,get:function(){return a.call(this)},set:function(P){r=""+P,l.call(this,P)}}),Object.defineProperty(o,e,{enumerable:t.enumerable}),{getValue:function(){return r},setValue:function(P){r=""+P},stopTracking:function(){o._valueTracker=null,delete o[e]}}}}function ut(o){o._valueTracker||(o._valueTracker=yt(o))}function Ie(o){if(!o)return!1;var e=o._valueTracker;if(!e)return!0;var t=e.getValue(),r="";return o&&(r=Qe(o)?o.checked?"true":"false":o.value),o=r,o!==t?(e.setValue(o),!0):!1}function De(o){if(o=o||(typeof document!="undefined"?document:void 0),typeof o=="undefined")return null;try{return o.activeElement||o.body}catch(e){return o.body}}function be(o,e){var t=e.checked;return ae({},e,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:t!=null?t:o._wrapperState.initialChecked})}function Xe(o,e){var t=e.defaultValue==null?"":e.defaultValue,r=e.checked!=null?e.checked:e.defaultChecked;t=Ye(e.value!=null?e.value:t),o._wrapperState={initialChecked:r,initialValue:t,controlled:e.type==="checkbox"||e.type==="radio"?e.checked!=null:e.value!=null}}function lt(o,e){e=e.checked,e!=null&&b(o,"checked",e,!1)}function tt(o,e){lt(o,e);var t=Ye(e.value),r=e.type;if(t!=null)r==="number"?(t===0&&o.value===""||o.value!=t)&&(o.value=""+t):o.value!==""+t&&(o.value=""+t);else if(r==="submit"||r==="reset"){o.removeAttribute("value");return}e.hasOwnProperty("value")?qe(o,e.type,t):e.hasOwnProperty("defaultValue")&&qe(o,e.type,Ye(e.defaultValue)),e.checked==null&&e.defaultChecked!=null&&(o.defaultChecked=!!e.defaultChecked)}function ct(o,e,t){if(e.hasOwnProperty("value")||e.hasOwnProperty("defaultValue")){var r=e.type;if(!(r!=="submit"&&r!=="reset"||e.value!==void 0&&e.value!==null))return;e=""+o._wrapperState.initialValue,t||e===o.value||(o.value=e),o.defaultValue=e}t=o.name,t!==""&&(o.name=""),o.defaultChecked=!!o._wrapperState.initialChecked,t!==""&&(o.name=t)}function qe(o,e,t){(e!=="number"||De(o.ownerDocument)!==o)&&(t==null?o.defaultValue=""+o._wrapperState.initialValue:o.defaultValue!==""+t&&(o.defaultValue=""+t))}var Ue=Array.isArray;function Ge(o,e,t,r){if(o=o.options,e){e={};for(var a=0;a"+e.valueOf().toString()+"",e=bt.firstChild;o.firstChild;)o.removeChild(o.firstChild);for(;e.firstChild;)o.appendChild(e.firstChild)}});function St(o,e){if(e){var t=o.firstChild;if(t&&t===o.lastChild&&t.nodeType===3){t.nodeValue=e;return}}o.textContent=e}var et={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},He=["Webkit","ms","Moz","O"];Object.keys(et).forEach(function(o){He.forEach(function(e){e=e+o.charAt(0).toUpperCase()+o.substring(1),et[e]=et[o]})});function Ft(o,e,t){return e==null||typeof e=="boolean"||e===""?"":t||typeof e!="number"||e===0||et.hasOwnProperty(o)&&et[o]?(""+e).trim():e+"px"}function Ut(o,e){o=o.style;for(var t in e)if(e.hasOwnProperty(t)){var r=t.indexOf("--")===0,a=Ft(t,e[t],r);t==="float"&&(t="cssFloat"),r?o.setProperty(t,a):o[t]=a}}var fn=ae({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function gn(o,e){if(e){if(fn[o]&&(e.children!=null||e.dangerouslySetInnerHTML!=null))throw Error(f(137,o));if(e.dangerouslySetInnerHTML!=null){if(e.children!=null)throw Error(f(60));if(typeof e.dangerouslySetInnerHTML!="object"||!("__html"in e.dangerouslySetInnerHTML))throw Error(f(61))}if(e.style!=null&&typeof e.style!="object")throw Error(f(62))}}function $n(o,e){if(o.indexOf("-")===-1)return typeof e.is=="string";switch(o){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Xn=null;function Lr(o){return o=o.target||o.srcElement||window,o.correspondingUseElement&&(o=o.correspondingUseElement),o.nodeType===3?o.parentNode:o}var le=null,we=null,ge=null;function Oe(o){if(o=ii(o)){if(typeof le!="function")throw Error(f(280));var e=o.stateNode;e&&(e=Go(e),le(o.stateNode,o.type,e))}}function Fe(o){we?ge?ge.push(o):ge=[o]:we=o}function Ve(){if(we){var o=we,e=ge;if(ge=we=null,Oe(o),e)for(o=0;o>>=0,o===0?32:31-(cr(o)/Co|0)|0}var Tr=64,wn=4194304;function Pr(o){switch(o&-o){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return o&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return o&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return o}}function mr(o,e){var t=o.pendingLanes;if(t===0)return 0;var r=0,a=o.suspendedLanes,l=o.pingedLanes,v=t&268435455;if(v!==0){var P=v&~a;P!==0?r=Pr(P):(l&=v,l!==0&&(r=Pr(l)))}else v=t&~a,v!==0?r=Pr(v):l!==0&&(r=Pr(l));if(r===0)return 0;if(e!==0&&e!==r&&!(e&a)&&(a=r&-r,l=e&-e,a>=l||a===16&&(l&4194240)!==0))return e;if(r&4&&(r|=t&16),e=o.entangledLanes,e!==0)for(o=o.entanglements,e&=r;0t;t++)e.push(o);return e}function tr(o,e,t){o.pendingLanes|=e,e!==536870912&&(o.suspendedLanes=0,o.pingedLanes=0),o=o.eventTimes,e=31-On(e),o[e]=t}function Ar(o,e){var t=o.pendingLanes&~e;o.pendingLanes=e,o.suspendedLanes=0,o.pingedLanes=0,o.expiredLanes&=e,o.mutableReadLanes&=e,o.entangledLanes&=e,e=o.entanglements;var r=o.eventTimes;for(o=o.expirationTimes;0=ni),hl=" ",ts=!1;function ju(o,e){switch(o){case"keyup":return Ys.indexOf(e.keyCode)!==-1;case"keydown":return e.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function ns(o){return o=o.detail,typeof o=="object"&&"data"in o?o.data:null}var xi=!1;function iu(o,e){switch(o){case"compositionend":return ns(e);case"keypress":return e.which!==32?null:(ts=!0,hl);case"textInput":return o=e.data,o===hl&&ts?null:o;default:return null}}function Wc(o,e){if(xi)return o==="compositionend"||!pl&&ju(o,e)?(o=Hn(),Kn=xn=Yt=null,xi=!1,o):null;switch(o){case"paste":return null;case"keypress":if(!(e.ctrlKey||e.altKey||e.metaKey)||e.ctrlKey&&e.altKey){if(e.char&&1=e)return{node:t,offset:e-o};o=r}e:{for(;t;){if(t.nextSibling){t=t.nextSibling;break e}t=t.parentNode}t=void 0}t=Bi(t)}}function gl(o,e){return o&&e?o===e?!0:o&&o.nodeType===3?!1:e&&e.nodeType===3?gl(o,e.parentNode):"contains"in o?o.contains(e):o.compareDocumentPosition?!!(o.compareDocumentPosition(e)&16):!1:!1}function yl(){for(var o=window,e=De();i(e,o.HTMLIFrameElement);){try{var t=typeof e.contentWindow.location.href=="string"}catch(r){t=!1}if(t)o=e.contentWindow;else break;e=De(o.document)}return e}function xl(o){var e=o&&o.nodeName&&o.nodeName.toLowerCase();return e&&(e==="input"&&(o.type==="text"||o.type==="search"||o.type==="tel"||o.type==="url"||o.type==="password")||e==="textarea"||o.contentEditable==="true")}function zu(o){var e=yl(),t=o.focusedElem,r=o.selectionRange;if(e!==t&&t&&t.ownerDocument&&gl(t.ownerDocument.documentElement,t)){if(r!==null&&xl(t)){if(e=r.start,o=r.end,o===void 0&&(o=e),"selectionStart"in t)t.selectionStart=e,t.selectionEnd=Math.min(o,t.value.length);else if(o=(e=t.ownerDocument||document)&&e.defaultView||window,o.getSelection){o=o.getSelection();var a=t.textContent.length,l=Math.min(r.start,a);r=r.end===void 0?l:Math.min(r.end,a),!o.extend&&l>r&&(a=r,r=l,l=a),a=uu(t,l);var v=uu(t,r);a&&v&&(o.rangeCount!==1||o.anchorNode!==a.node||o.anchorOffset!==a.offset||o.focusNode!==v.node||o.focusOffset!==v.offset)&&(e=e.createRange(),e.setStart(a.node,a.offset),o.removeAllRanges(),l>r?(o.addRange(e),o.extend(v.node,v.offset)):(e.setEnd(v.node,v.offset),o.addRange(e)))}}for(e=[],o=t;o=o.parentNode;)o.nodeType===1&&e.push({element:o,left:o.scrollLeft,top:o.scrollTop});for(typeof t.focus=="function"&&t.focus(),t=0;t=document.documentMode,lu=null,ri=null,Ba=null,ba=!1;function Sl(o,e,t){var r=t.window===t?t.document:t.nodeType===9?t:t.ownerDocument;ba||lu==null||lu!==De(r)||(r=lu,"selectionStart"in r&&xl(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Ba&&dr(Ba,r)||(Ba=r,r=$i(ri,"onSelect"),0Oi||(o.current=va[Oi],va[Oi]=null,Oi--)}function zt(o,e){Oi++,va[Oi]=o.current,o.current=e}var vn={},zn=No(vn),Tn=No(!1),xr=vn;function Ur(o,e){var t=o.type.contextTypes;if(!t)return vn;var r=o.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===e)return r.__reactInternalMemoizedMaskedChildContext;var a={},l;for(l in t)a[l]=e[l];return r&&(o=o.stateNode,o.__reactInternalMemoizedUnmaskedChildContext=e,o.__reactInternalMemoizedMaskedChildContext=a),a}function Sr(o){return o=o.childContextTypes,o!=null}function kr(){mn(Tn),mn(zn)}function Wa(o,e,t){if(zn.current!==vn)throw Error(f(168));zt(zn,e),zt(Tn,t)}function hu(o,e,t){var r=o.stateNode;if(e=e.childContextTypes,typeof r.getChildContext!="function")return t;r=r.getChildContext();for(var a in r)if(!(a in e))throw Error(f(108,me(o)||"Unknown",a));return ae({},t,r)}function mu(o){return o=(o=o.stateNode)&&o.__reactInternalMemoizedMergedChildContext||vn,xr=zn.current,zt(zn,o),zt(Tn,Tn.current),!0}function gu(o,e,t){var r=o.stateNode;if(!r)throw Error(f(169));t?(o=hu(o,e,xr),r.__reactInternalMemoizedMergedChildContext=o,mn(Tn),mn(zn),zt(zn,o)):mn(Tn),zt(Tn,t)}var Mo=null,jo=!1,pa=!1;function Cl(o){Mo===null?Mo=[o]:Mo.push(o)}function yu(o){jo=!0,Cl(o)}function Ti(){if(!pa&&Mo!==null){pa=!0;var o=0,e=tn;try{var t=Mo;for(tn=1;o>=v,a-=v,ro=1<<32-On(e)+a|t<it?(Nt=nt,nt=null):Nt=nt.sibling;var Ht=Se(Ce,nt,X[it],se);if(Ht===null){nt===null&&(nt=Nt);break}o&&nt&&Ht.alternate===null&&e(Ce,nt),Y=l(Ht,Y,it),Je===null?Le=Ht:Je.sibling=Ht,Je=Ht,nt=Nt}if(it===X.length)return t(Ce,nt),nn&&Nr(Ce,it),Le;if(nt===null){for(;itit?(Nt=nt,nt=null):Nt=nt.sibling;var on=Se(Ce,nt,Ht.value,se);if(on===null){nt===null&&(nt=Nt);break}o&&nt&&on.alternate===null&&e(Ce,nt),Y=l(on,Y,it),Je===null?Le=on:Je.sibling=on,Je=on,nt=Nt}if(Ht.done)return t(Ce,nt),nn&&Nr(Ce,it),Le;if(nt===null){for(;!Ht.done;it++,Ht=X.next())Ht=fe(Ce,Ht.value,se),Ht!==null&&(Y=l(Ht,Y,it),Je===null?Le=Ht:Je.sibling=Ht,Je=Ht);return nn&&Nr(Ce,it),Le}for(nt=r(Ce,nt);!Ht.done;it++,Ht=X.next())Ht=Re(nt,Ce,it,Ht.value,se),Ht!==null&&(o&&Ht.alternate!==null&&nt.delete(Ht.key===null?it:Ht.key),Y=l(Ht,Y,it),Je===null?Le=Ht:Je.sibling=Ht,Je=Ht);return o&&nt.forEach(function(eu){return e(Ce,eu)}),nn&&Nr(Ce,it),Le}function gt(Ce,Y,X,se){if(typeof X=="object"&&X!==null&&X.type===G&&X.key===null&&(X=X.props.children),typeof X=="object"&&X!==null){switch(X.$$typeof){case F:e:{for(var Le=X.key,Je=Y;Je!==null;){if(Je.key===Le){if(Le=X.type,Le===G){if(Je.tag===7){t(Ce,Je.sibling),Y=a(Je,X.props.children),Y.return=Ce,Ce=Y;break e}}else if(Je.elementType===Le||typeof Le=="object"&&Le!==null&&Le.$$typeof===K&&Lo(Le)===Je.type){t(Ce,Je.sibling),Y=a(Je,X.props),Y.ref=ai(Ce,Je,X),Y.return=Ce,Ce=Y;break e}t(Ce,Je);break}else e(Ce,Je);Je=Je.sibling}X.type===G?(Y=Ji(X.props.children,Ce.mode,se,X.key),Y.return=Ce,Ce=Y):(se=Mi(X.type,X.key,X.props,null,Ce.mode,se),se.ref=ai(Ce,Y,X),se.return=Ce,Ce=se)}return v(Ce);case V:e:{for(Je=X.key;Y!==null;){if(Y.key===Je)if(Y.tag===4&&Y.stateNode.containerInfo===X.containerInfo&&Y.stateNode.implementation===X.implementation){t(Ce,Y.sibling),Y=a(Y,X.children||[]),Y.return=Ce,Ce=Y;break e}else{t(Ce,Y);break}else e(Ce,Y);Y=Y.sibling}Y=$l(X,Ce.mode,se),Y.return=Ce,Ce=Y}return v(Ce);case K:return Je=X._init,gt(Ce,Y,Je(X._payload),se)}if(Ue(X))return ke(Ce,Y,X,se);if(H(X))return Ke(Ce,Y,X,se);To(Ce,X)}return typeof X=="string"&&X!==""||typeof X=="number"?(X=""+X,Y!==null&&Y.tag===6?(t(Ce,Y.sibling),Y=a(Y,X),Y.return=Ce,Ce=Y):(t(Ce,Y),Y=nl(X,Ce.mode,se),Y.return=Ce,Ce=Y),v(Ce)):t(Ce,Y)}return gt}var ui=ga(!0),Io=ga(!1),Ki={},io=No(Ki),Vr=No(Ki),Ii=No(Ki);function Do(o){if(o===Ki)throw Error(f(174));return o}function wi(o,e){switch(zt(Ii,e),zt(Vr,o),zt(io,Ki),o=e.nodeType,o){case 9:case 11:e=(e=e.documentElement)?e.namespaceURI:xt(null,"");break;default:o=o===8?e.parentNode:e,e=o.namespaceURI||null,o=o.tagName,e=xt(e,o)}mn(io),zt(io,e)}function Hi(){mn(io),mn(Vr),mn(Ii)}function Gi(o){Do(Ii.current);var e=Do(io.current),t=xt(e,o.type);e!==t&&(zt(Vr,o),zt(io,t))}function Su(o){Vr.current===o&&(mn(io),mn(Vr))}var Dn=No(0);function Nn(o){for(var e=o;e!==null;){if(e.tag===13){var t=e.memoizedState;if(t!==null&&(t=t.dehydrated,t===null||t.data==="$?"||t.data==="$!"))return e}else if(e.tag===19&&e.memoizedProps.revealOrder!==void 0){if(e.flags&128)return e}else if(e.child!==null){e.child.return=e,e=e.child;continue}if(e===o)break;for(;e.sibling===null;){if(e.return===null||e.return===o)return null;e=e.return}e.sibling.return=e.return,e=e.sibling}return null}var Fo=[];function Yi(){for(var o=0;ot?t:4,o(!0);var r=xa.transition;xa.transition={};try{o(!1),e()}finally{tn=t,xa.transition=r}}function Hc(){return Er().memoizedState}function Gc(o,e,t){var r=vr(o);if(t={lane:r,action:t,hasEagerState:!1,eagerState:null,next:null},Yc(o))cc(e,t);else if(t=Lt(o,e,t,r),t!==null){var a=Xr();Qr(t,o,r,a),fc(t,e,r)}}function cf(o,e,t){var r=vr(o),a={lane:r,action:t,hasEagerState:!1,eagerState:null,next:null};if(Yc(o))cc(e,a);else{var l=o.alternate;if(o.lanes===0&&(l===null||l.lanes===0)&&(l=e.lastRenderedReducer,l!==null))try{var v=e.lastRenderedState,P=l(v,t);if(a.hasEagerState=!0,a.eagerState=P,Vo(P,v)){var k=e.interleaved;k===null?(a.next=a,ht(e)):(a.next=k.next,k.next=a),e.interleaved=a;return}}catch(Q){}finally{}t=Lt(o,e,a,r),t!==null&&(a=Xr(),Qr(t,o,r,a),fc(t,e,r))}}function Yc(o){var e=o.alternate;return o===Sn||e!==null&&e===Sn}function cc(o,e){Ka=Jn=!0;var t=o.pending;t===null?e.next=e:(e.next=t.next,t.next=e),o.pending=e}function fc(o,e,t){if(t&4194240){var r=e.lanes;r&=o.pendingLanes,t|=r,e.lanes=t,Jr(o,t)}}var Dl={readContext:vt,useCallback:ao,useContext:ao,useEffect:ao,useImperativeHandle:ao,useInsertionEffect:ao,useLayoutEffect:ao,useMemo:ao,useReducer:ao,useRef:ao,useState:ao,useDebugValue:ao,useDeferredValue:ao,useTransition:ao,useMutableSource:ao,useSyncExternalStore:ao,useId:ao,unstable_isNewReconciler:!1},ms={readContext:vt,useCallback:function(e,t){return li().memoizedState=[e,t===void 0?null:t],e},useContext:vt,useEffect:Ll,useImperativeHandle:function(e,t,r){return r=r!=null?r.concat([e]):null,jl(4194308,4,ac.bind(null,t,e),r)},useLayoutEffect:function(e,t){return jl(4194308,4,e,t)},useInsertionEffect:function(e,t){return jl(4,2,e,t)},useMemo:function(e,t){var r=li();return t=t===void 0?null:t,e=e(),r.memoizedState=[e,t],e},useReducer:function(e,t,r){var a=li();return t=r!==void 0?r(t):t,a.memoizedState=a.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},a.queue=e,e=e.dispatch=Gc.bind(null,Sn,e),[a.memoizedState,e]},useRef:function(e){var t=li();return e={current:e},t.memoizedState=e},useState:oc,useDebugValue:ps,useDeferredValue:function(e){return li().memoizedState=e},useTransition:function(){var e=oc(!1),t=e[0];return e=Kc.bind(null,e[1]),li().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,r){var a=Sn,l=li();if(nn){if(r===void 0)throw Error(f(407));r=r()}else{if(r=t(),$t===null)throw Error(f(349));Jo&30||_s(a,t,r)}l.memoizedState=r;var v={value:r,getSnapshot:t};return l.queue=v,Ll(tc.bind(null,a,v,e),[e]),a.flags|=2048,Ku(9,ec.bind(null,a,v,r,t),void 0,null),r},useId:function(){var e=li(),t=$t.identifierPrefix;if(nn){var r=Wr,a=ro;r=(a&~(1<<32-On(a)-1)).toString(32)+r,t=":"+t+"R"+r,r=Sa++,0<\/script>",o=o.removeChild(o.firstChild)):typeof r.is=="string"?o=v.createElement(t,{is:r.is}):(o=v.createElement(t),t==="select"&&(v=o,r.multiple?v.multiple=!0:r.size&&(v.size=r.size))):o=v.createElementNS(o,t),o[_r]=e,o[zr]=r,Jc(o,e,!1,!1),e.stateNode=o;e:{switch(v=$n(t,r),t){case"dialog":Rn("cancel",o),Rn("close",o),a=r;break;case"iframe":case"object":case"embed":Rn("load",o),a=r;break;case"video":case"audio":for(a=0;aXa&&(e.flags|=128,r=!0,Xu(l,!1),e.lanes=4194304)}else{if(!r)if(o=Nn(v),o!==null){if(e.flags|=128,r=!0,t=o.updateQueue,t!==null&&(e.updateQueue=t,e.flags|=4),Xu(l,!0),l.tail===null&&l.tailMode==="hidden"&&!v.alternate&&!nn)return Cr(e),null}else 2*ln()-l.renderingStartTime>Xa&&t!==1073741824&&(e.flags|=128,r=!0,Xu(l,!1),e.lanes=4194304);l.isBackwards?(v.sibling=e.child,e.child=v):(t=l.last,t!==null?t.sibling=v:e.child=v,l.last=v)}return l.tail!==null?(e=l.tail,l.rendering=e,l.tail=e.sibling,l.renderingStartTime=ln(),e.sibling=null,t=Dn.current,zt(Dn,r?t&1|2:t&1),e):(Cr(e),null);case 22:case 23:return wa(),r=e.memoizedState!==null,o!==null&&o.memoizedState!==null!==r&&(e.flags|=8192),r&&e.mode&1?Pn&1073741824&&(Cr(e),e.subtreeFlags&6&&(e.flags|=8192)):Cr(e),null;case 24:return null;case 25:return null}throw Error(f(156,e.tag))}function vf(o,e){switch(Vu(e),e.tag){case 1:return Sr(e.type)&&kr(),o=e.flags,o&65536?(e.flags=o&-65537|128,e):null;case 3:return Hi(),mn(Tn),mn(zn),Yi(),o=e.flags,o&65536&&!(o&128)?(e.flags=o&-65537|128,e):null;case 5:return Su(e),null;case 13:if(mn(Dn),o=e.memoizedState,o!==null&&o.dehydrated!==null){if(e.alternate===null)throw Error(f(340));re()}return o=e.flags,o&65536?(e.flags=o&-65537|128,e):null;case 19:return mn(Dn),null;case 4:return Hi(),null;case 10:return ot(e.type._context),null;case 22:case 23:return wa(),null;case 24:return null;default:return null}}var Rs=!1,Mr=!1,co=typeof WeakSet=="function"?WeakSet:Set,Ct=null;function Et(o,e){var t=o.ref;if(t!==null)if(typeof t=="function")try{t(null)}catch(r){ir(o,e,r)}else t.current=null}function Ga(o,e,t){try{t()}catch(r){ir(o,e,r)}}var Ns=!1;function qc(o,e){if(du=Wo,o=yl(),xl(o)){if("selectionStart"in o)var t={start:o.selectionStart,end:o.selectionEnd};else e:{t=(t=o.ownerDocument)&&t.defaultView||window;var r=t.getSelection&&t.getSelection();if(r&&r.rangeCount!==0){t=r.anchorNode;var a=r.anchorOffset,l=r.focusNode;r=r.focusOffset;try{t.nodeType,l.nodeType}catch(se){t=null;break e}var v=0,P=-1,k=-1,Q=0,ie=0,fe=o,Se=null;t:for(;;){for(var Re;fe!==t||a!==0&&fe.nodeType!==3||(P=v+a),fe!==l||r!==0&&fe.nodeType!==3||(k=v+r),fe.nodeType===3&&(v+=fe.nodeValue.length),(Re=fe.firstChild)!==null;)Se=fe,fe=Re;for(;;){if(fe===o)break t;if(Se===t&&++Q===a&&(P=v),Se===l&&++ie===r&&(k=v),(Re=fe.nextSibling)!==null)break;fe=Se,Se=fe.parentNode}fe=Re}t=P===-1||k===-1?null:{start:P,end:k}}else t=null}t=t||{start:0,end:0}}else t=null;for(vu={focusedElem:o,selectionRange:t},Wo=!1,Ct=e;Ct!==null;)if(e=Ct,o=e.child,(e.subtreeFlags&1028)!==0&&o!==null)o.return=e,Ct=o;else for(;Ct!==null;){e=Ct;try{var ke=e.alternate;if(e.flags&1024)switch(e.tag){case 0:case 11:case 15:break;case 1:if(ke!==null){var Ke=ke.memoizedProps,gt=ke.memoizedState,Ce=e.stateNode,Y=Ce.getSnapshotBeforeUpdate(e.elementType===e.type?Ke:ue(e.type,Ke),gt);Ce.__reactInternalSnapshotBeforeUpdate=Y}break;case 3:var X=e.stateNode.containerInfo;X.nodeType===1?X.textContent="":X.nodeType===9&&X.documentElement&&X.removeChild(X.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(f(163))}}catch(se){ir(e,e.return,se)}if(o=e.sibling,o!==null){o.return=e.return,Ct=o;break}Ct=e.return}return ke=Ns,Ns=!1,ke}function zl(o,e,t){var r=e.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var a=r=r.next;do{if((a.tag&o)===o){var l=a.destroy;a.destroy=void 0,l!==void 0&&Ga(e,t,l)}a=a.next}while(a!==r)}}function Ya(o,e){if(e=e.updateQueue,e=e!==null?e.lastEffect:null,e!==null){var t=e=e.next;do{if((t.tag&o)===o){var r=t.create;t.destroy=r()}t=t.next}while(t!==e)}}function Qu(o){var e=o.ref;if(e!==null){var t=o.stateNode;switch(o.tag){case 5:o=t;break;default:o=t}typeof e=="function"?e(o):e.current=o}}function Ms(o){var e=o.alternate;e!==null&&(o.alternate=null,Ms(e)),o.child=null,o.deletions=null,o.sibling=null,o.tag===5&&(e=o.stateNode,e!==null&&(delete e[_r],delete e[zr],delete e[Eo],delete e[wl],delete e[cs])),o.stateNode=null,o.return=null,o.dependencies=null,o.memoizedProps=null,o.memoizedState=null,o.pendingProps=null,o.stateNode=null,o.updateQueue=null}function Tc(o){return o.tag===5||o.tag===3||o.tag===4}function Ic(o){e:for(;;){for(;o.sibling===null;){if(o.return===null||Tc(o.return))return null;o=o.return}for(o.sibling.return=o.return,o=o.sibling;o.tag!==5&&o.tag!==6&&o.tag!==18;){if(o.flags&2||o.child===null||o.tag===4)continue e;o.child.return=o,o=o.child}if(!(o.flags&2))return o.stateNode}}function js(o,e,t){var r=o.tag;if(r===5||r===6)o=o.stateNode,e?t.nodeType===8?t.parentNode.insertBefore(o,e):t.insertBefore(o,e):(t.nodeType===8?(e=t.parentNode,e.insertBefore(o,t)):(e=t,e.appendChild(o)),t=t._reactRootContainer,t!=null||e.onclick!==null||(e.onclick=ca));else if(r!==4&&(o=o.child,o!==null))for(js(o,e,t),o=o.sibling;o!==null;)js(o,e,t),o=o.sibling}function Ul(o,e,t){var r=o.tag;if(r===5||r===6)o=o.stateNode,e?t.insertBefore(o,e):t.appendChild(o);else if(r!==4&&(o=o.child,o!==null))for(Ul(o,e,t),o=o.sibling;o!==null;)Ul(o,e,t),o=o.sibling}var jr=null,Fn=!1;function Hr(o,e,t){for(t=t.child;t!==null;)Oa(o,e,t),t=t.sibling}function Oa(o,e,t){if(Vn&&typeof Vn.onCommitFiberUnmount=="function")try{Vn.onCommitFiberUnmount(hn,t)}catch(P){}switch(t.tag){case 5:Mr||Et(t,e);case 6:var r=jr,a=Fn;jr=null,Hr(o,e,t),jr=r,Fn=a,jr!==null&&(Fn?(o=jr,t=t.stateNode,o.nodeType===8?o.parentNode.removeChild(t):o.removeChild(t)):jr.removeChild(t.stateNode));break;case 18:jr!==null&&(Fn?(o=jr,t=t.stateNode,o.nodeType===8?Il(o.parentNode,t):o.nodeType===1&&Il(o,t),Ao(o)):Il(jr,t.stateNode));break;case 4:r=jr,a=Fn,jr=t.stateNode.containerInfo,Fn=!0,Hr(o,e,t),jr=r,Fn=a;break;case 0:case 11:case 14:case 15:if(!Mr&&(r=t.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){a=r=r.next;do{var l=a,v=l.destroy;l=l.tag,v!==void 0&&(l&2||l&4)&&Ga(t,e,v),a=a.next}while(a!==r)}Hr(o,e,t);break;case 1:if(!Mr&&(Et(t,e),r=t.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=t.memoizedProps,r.state=t.memoizedState,r.componentWillUnmount()}catch(P){ir(t,e,P)}Hr(o,e,t);break;case 21:Hr(o,e,t);break;case 22:t.mode&1?(Mr=(r=Mr)||t.memoizedState!==null,Hr(o,e,t),Mr=r):Hr(o,e,t);break;default:Hr(o,e,t)}}function wc(o){var e=o.updateQueue;if(e!==null){o.updateQueue=null;var t=o.stateNode;t===null&&(t=o.stateNode=new co),e.forEach(function(r){var a=hf.bind(null,o,r);t.has(r)||(t.add(r),r.then(a,a))})}}function ci(o,e){var t=e.deletions;if(t!==null)for(var r=0;ra&&(a=v),r&=~l}if(r=a,r=ln()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*ef(r/1960))-r,10o?16:o,Ri===null)var r=!1;else{if(o=Ri,Ri=null,Ni=0,Zt&6)throw Error(f(331));var a=Zt;for(Zt|=4,Ct=o.current;Ct!==null;){var l=Ct,v=l.child;if(Ct.flags&16){var P=l.deletions;if(P!==null){for(var k=0;kln()-fo?Ca(o,0):Ju|=t),_n(o,e)}function nf(o,e){e===0&&(o.mode&1?(e=wn,wn<<=1,!(wn&130023424)&&(wn=4194304)):e=1);var t=Xr();o=At(o,e),o!==null&&(tr(o,e,t),_n(o,t))}function rf(o){var e=o.memoizedState,t=0;e!==null&&(t=e.retryLane),nf(o,t)}function hf(o,e){var t=0;switch(o.tag){case 13:var r=o.stateNode,a=o.memoizedState;a!==null&&(t=a.retryLane);break;case 19:r=o.stateNode;break;default:throw Error(f(314))}r!==null&&r.delete(e),nf(o,t)}var of;of=function(e,t,r){if(e!==null)if(e.memoizedProps!==t.pendingProps||Tn.current)Bo=!0;else{if(!(e.lanes&r)&&!(t.flags&128))return Bo=!1,Ea(e,t,r);Bo=!!(e.flags&131072)}else Bo=!1,nn&&t.flags&1048576&&ma(t,ha,t.index);switch(t.lanes=0,t.tag){case 2:var a=t.type;bl(e,t),e=t.pendingProps;var l=Ur(t,zn.current);ft(t,r),l=Rl(null,t,a,e,l,r);var v=Nl();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Sr(a)?(v=!0,mu(t)):v=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,Dt(t),l.updater=Zo,t.stateNode=l,l._reactInternals=t,Vi(t,a,e,r),t=xs(null,t,a,!0,v,r)):(t.tag=0,nn&&v&&Pl(t),Mn(null,t,l,r),t=t.child),t;case 16:a=t.elementType;e:{switch(bl(e,t),e=t.pendingProps,l=a._init,a=l(a._payload),t.type=a,l=t.tag=Lc(a),e=ue(a,e),l){case 0:t=gs(null,t,a,e,r);break e;case 1:t=ys(null,t,a,e,r);break e;case 11:t=lo(null,t,a,e,r);break e;case 14:t=gc(null,t,a,ue(a.type,e),r);break e}throw Error(f(306,a,""))}return t;case 0:return a=t.type,l=t.pendingProps,l=t.elementType===a?l:ue(a,l),gs(e,t,a,l,r);case 1:return a=t.type,l=t.pendingProps,l=t.elementType===a?l:ue(a,l),ys(e,t,a,l,r);case 3:e:{if(Ss(t),e===null)throw Error(f(387));a=t.pendingProps,v=t.memoizedState,l=v.element,Xt(e,t),Gn(t,a,null,r);var P=t.memoizedState;if(a=P.element,v.isDehydrated)if(v={element:a,isDehydrated:!1,cache:P.cache,pendingSuspenseBoundaries:P.pendingSuspenseBoundaries,transitions:P.transitions},t.updateQueue.baseState=v,t.memoizedState=v,t.flags&256){l=Gu(Error(f(423)),t),t=Ec(e,t,a,r,l);break e}else if(a!==l){l=Gu(Error(f(424)),t),t=Ec(e,t,a,r,l);break e}else for(Un=Ko(t.stateNode.containerInfo.firstChild),oo=t,nn=!0,pn=null,r=Io(t,null,a,r),t.child=r;r;)r.flags=r.flags&-3|4096,r=r.sibling;else{if(re(),a===l){t=si(e,t,r);break e}Mn(e,t,a,r)}t=t.child}return t;case 5:return Gi(t),e===null&&A(t),a=t.type,l=t.pendingProps,v=e!==null?e.memoizedProps:null,P=l.children,$a(a,l)?P=null:v!==null&&$a(a,v)&&(t.flags|=32),Sc(e,t),Mn(e,t,P,r),t.child;case 6:return e===null&&A(t),null;case 13:return Os(e,t,r);case 4:return wi(t,t.stateNode.containerInfo),a=t.pendingProps,e===null?t.child=ui(t,null,a,r):Mn(e,t,a,r),t.child;case 11:return a=t.type,l=t.pendingProps,l=t.elementType===a?l:ue(a,l),lo(e,t,a,l,r);case 7:return Mn(e,t,t.pendingProps,r),t.child;case 8:return Mn(e,t,t.pendingProps.children,r),t.child;case 12:return Mn(e,t,t.pendingProps.children,r),t.child;case 10:e:{if(a=t.type._context,l=t.pendingProps,v=t.memoizedProps,P=l.value,zt(ve,a._currentValue),a._currentValue=P,v!==null)if(Vo(v.value,P)){if(v.children===l.children&&!Tn.current){t=si(e,t,r);break e}}else for(v=t.child,v!==null&&(v.return=t);v!==null;){var k=v.dependencies;if(k!==null){P=v.child;for(var Q=k.firstContext;Q!==null;){if(Q.context===a){if(v.tag===1){Q=Mt(-1,r&-r),Q.tag=2;var ie=v.updateQueue;if(ie!==null){ie=ie.shared;var fe=ie.pending;fe===null?Q.next=Q:(Q.next=fe.next,fe.next=Q),ie.pending=Q}}v.lanes|=r,Q=v.alternate,Q!==null&&(Q.lanes|=r),st(v.return,r,t),k.lanes|=r;break}Q=Q.next}}else if(v.tag===10)P=v.type===t.type?null:v.child;else if(v.tag===18){if(P=v.return,P===null)throw Error(f(341));P.lanes|=r,k=P.alternate,k!==null&&(k.lanes|=r),st(P,r,t),P=v.sibling}else P=v.child;if(P!==null)P.return=v;else for(P=v;P!==null;){if(P===t){P=null;break}if(v=P.sibling,v!==null){v.return=P.return,P=v;break}P=P.return}v=P}Mn(e,t,l.children,r),t=t.child}return t;case 9:return l=t.type,a=t.pendingProps.children,ft(t,r),l=vt(l),a=a(l),t.flags|=1,Mn(e,t,a,r),t.child;case 14:return a=t.type,l=ue(a,t.pendingProps),l=ue(a.type,l),gc(e,t,a,l,r);case 15:return yc(e,t,t.type,t.pendingProps,r);case 17:return a=t.type,l=t.pendingProps,l=t.elementType===a?l:ue(a,l),bl(e,t),t.tag=1,Sr(a)?(e=!0,mu(t)):e=!1,ft(t,r),Va(t,a,l),Vi(t,a,l,r),xs(null,t,a,!0,e,r);case 19:return Cs(e,t,r);case 22:return xc(e,t,r)}throw Error(f(156,t.tag))};function jc(o,e){return Or(o,e)}function af(o,e,t,r){this.tag=o,this.key=t,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=e,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function vi(o,e,t,r){return new af(o,e,t,r)}function Uo(o){return o=o.prototype,!(!o||!o.isReactComponent)}function Lc(o){if(typeof o=="function")return Uo(o)?1:0;if(o!=null){if(o=o.$$typeof,o===te)return 11;if(o===q)return 14}return 2}function _a(o,e){var t=o.alternate;return t===null?(t=vi(o.tag,e,o.key,o.mode),t.elementType=o.elementType,t.type=o.type,t.stateNode=o.stateNode,t.alternate=o,o.alternate=t):(t.pendingProps=e,t.type=o.type,t.flags=0,t.subtreeFlags=0,t.deletions=null),t.flags=o.flags&14680064,t.childLanes=o.childLanes,t.lanes=o.lanes,t.child=o.child,t.memoizedProps=o.memoizedProps,t.memoizedState=o.memoizedState,t.updateQueue=o.updateQueue,e=o.dependencies,t.dependencies=e===null?null:{lanes:e.lanes,firstContext:e.firstContext},t.sibling=o.sibling,t.index=o.index,t.ref=o.ref,t}function Mi(o,e,t,r,a,l){var v=2;if(r=o,typeof o=="function")Uo(o)&&(v=1);else if(typeof o=="string")v=5;else e:switch(o){case G:return Ji(t.children,a,l,e);case J:v=8,a|=8;break;case oe:return o=vi(12,t,e,a|2),o.elementType=oe,o.lanes=l,o;case pe:return o=vi(13,t,e,a),o.elementType=pe,o.lanes=l,o;case ce:return o=vi(19,t,e,a),o.elementType=ce,o.lanes=l,o;case _:return qi(t,a,l,e);default:if(typeof o=="object"&&o!==null)switch(o.$$typeof){case Z:v=10;break e;case ne:v=9;break e;case te:v=11;break e;case q:v=14;break e;case K:v=16,r=null;break e}throw Error(f(130,o==null?o:typeof o=="undefined"?"undefined":u(o),""))}return e=vi(v,t,e,a),e.elementType=o,e.type=r,e.lanes=l,e}function Ji(o,e,t,r){return o=vi(7,o,r,e),o.lanes=t,o}function qi(o,e,t,r){return o=vi(22,o,r,e),o.elementType=_,o.lanes=t,o.stateNode={isHidden:!1},o}function nl(o,e,t){return o=vi(6,o,null,e),o.lanes=t,o}function $l(o,e,t){return e=vi(4,o.children!==null?o.children:[],o.key,e),e.lanes=t,e.stateNode={containerInfo:o.containerInfo,pendingChildren:null,implementation:o.implementation},e}function Dc(o,e,t,r,a){this.tag=e,this.containerInfo=o,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=ko(0),this.expirationTimes=ko(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=ko(0),this.identifierPrefix=r,this.onRecoverableError=a,this.mutableSourceEagerHydrationData=null}function Fc(o,e,t,r,a,l,v,P,k){return o=new Dc(o,e,t,P,k),e===1?(e=1,l===!0&&(e|=8)):e=0,l=vi(3,null,null,e),o.current=l,l.stateNode=o,l.memoizedState={element:r,isDehydrated:t,cache:null,transitions:null,pendingSuspenseBoundaries:null},Dt(l),o}function Bc(o,e,t){var r=3t}return!1}function U(e,t,r,a,l,v,P){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=a,this.attributeNamespace=l,this.mustUseProperty=r,this.propertyName=e,this.type=t,this.sanitizeURL=v,this.removeEmptyString=P}var z={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){z[e]=new U(e,0,!1,e,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];z[t]=new U(t,1,!1,e[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){z[e]=new U(e,2,!1,e.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){z[e]=new U(e,2,!1,e,null,!1,!1)}),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){z[e]=new U(e,3,!1,e.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(e){z[e]=new U(e,3,!0,e,null,!1,!1)}),["capture","download"].forEach(function(e){z[e]=new U(e,4,!1,e,null,!1,!1)}),["cols","rows","size","span"].forEach(function(e){z[e]=new U(e,6,!1,e,null,!1,!1)}),["rowSpan","start"].forEach(function(e){z[e]=new U(e,5,!1,e.toLowerCase(),null,!1,!1)});var D=/[\-:]([a-z])/g;function b(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(D,b);z[t]=new U(t,1,!1,e,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(D,b);z[t]=new U(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(D,b);z[t]=new U(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(e){z[e]=new U(e,1,!1,e.toLowerCase(),null,!1,!1)}),z.xlinkHref=new U("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(e){z[e]=new U(e,1,!1,e.toLowerCase(),null,!0,!0)});function L(e,t,r,a){var l=z.hasOwnProperty(t)?z[t]:null;(l!==null?l.type!==0:a||!(2k||l[P]!==v[k]){var Q="\n"+l[P].replace(" at new "," at ");return e.displayName&&Q.includes("")&&(Q=Q.replace("",e.displayName)),Q}while(1<=P&&0<=k);break}}}finally{xe=!1,Error.prepareStackTrace=r}return(e=e?e.displayName||e.name:"")?ye(e):""}function Pe(e){switch(e.tag){case 5:return ye(e.type);case 16:return ye("Lazy");case 13:return ye("Suspense");case 19:return ye("SuspenseList");case 0:case 2:case 15:return e=Ae(e.type,!1),e;case 11:return e=Ae(e.type.render,!1),e;case 1:return e=Ae(e.type,!0),e;default:return""}}function me(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case J:return"Fragment";case G:return"Portal";case Z:return"Profiler";case oe:return"StrictMode";case ce:return"Suspense";case q:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case te:return(e.displayName||"Context")+".Consumer";case ne:return(e._context.displayName||"Context")+".Provider";case pe:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case K:return t=e.displayName||null,t!==null?t:me(e.type)||"Memo";case _:t=e._payload,e=e._init;try{return me(e(t))}catch(r){}}return null}function Ye(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return me(t);case 8:return t===oe?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Qe(e){switch(typeof e=="undefined"?"undefined":s(e)){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function yt(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function ut(e){var t=yt(e)?"checked":"value",r=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),a=""+e[t];if(!e.hasOwnProperty(t)&&typeof r!="undefined"&&typeof r.get=="function"&&typeof r.set=="function"){var l=r.get,v=r.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(k){a=""+k,v.call(this,k)}}),Object.defineProperty(e,t,{enumerable:r.enumerable}),{getValue:function(){return a},setValue:function(k){a=""+k},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Ie(e){e._valueTracker||(e._valueTracker=ut(e))}function De(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var r=t.getValue(),a="";return e&&(a=yt(e)?e.checked?"true":"false":e.value),e=a,e!==r?(t.setValue(e),!0):!1}function be(e){if(e=e||(typeof document!="undefined"?document:void 0),typeof e=="undefined")return null;try{return e.activeElement||e.body}catch(t){return e.body}}function Xe(e,t){var r=t.checked;return he({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:r!=null?r:e._wrapperState.initialChecked})}function lt(e,t){var r=t.defaultValue==null?"":t.defaultValue,a=t.checked!=null?t.checked:t.defaultChecked;r=Qe(t.value!=null?t.value:r),e._wrapperState={initialChecked:a,initialValue:r,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function tt(e,t){t=t.checked,t!=null&&L(e,"checked",t,!1)}function ct(e,t){tt(e,t);var r=Qe(t.value),a=t.type;if(r!=null)a==="number"?(r===0&&e.value===""||e.value!=r)&&(e.value=""+r):e.value!==""+r&&(e.value=""+r);else if(a==="submit"||a==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Ue(e,t.type,r):t.hasOwnProperty("defaultValue")&&Ue(e,t.type,Qe(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function qe(e,t,r){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var a=t.type;if(!(a!=="submit"&&a!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,r||t===e.value||(e.value=t),e.defaultValue=t}r=e.name,r!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,r!==""&&(e.name=r)}function Ue(e,t,r){(t!=="number"||be(e.ownerDocument)!==e)&&(r==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+r&&(e.defaultValue=""+r))}var Ge=Array.isArray;function $e(e,t,r,a){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=Wt.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function et(e,t){if(t){var r=e.firstChild;if(r&&r===e.lastChild&&r.nodeType===3){r.nodeValue=t;return}}e.textContent=t}var He={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Ft=["Webkit","ms","Moz","O"];Object.keys(He).forEach(function(e){Ft.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),He[t]=He[e]})});function Ut(e,t,r){return t==null||typeof t=="boolean"||t===""?"":r||typeof t!="number"||t===0||He.hasOwnProperty(e)&&He[e]?(""+t).trim():t+"px"}function fn(e,t){e=e.style;for(var r in t)if(t.hasOwnProperty(r)){var a=r.indexOf("--")===0,l=Ut(r,t[r],a);r==="float"&&(r="cssFloat"),a?e.setProperty(r,l):e[r]=l}}var gn=he({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function kn(e,t){if(t){if(gn[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(p(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(p(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(p(61))}if(t.style!=null&&typeof t.style!="object")throw Error(p(62))}}function Xn(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Lr=null;function le(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var we=null,ge=null,Oe=null;function Fe(e){if(e=Ei(e)){if(typeof we!="function")throw Error(p(280));var t=e.stateNode;t&&(t=va(t),we(e.stateNode,e.type,t))}}function Ve(e){ge?Oe?Oe.push(e):Oe=[e]:ge=e}function pt(){if(ge){var e=ge,t=Oe;if(Oe=ge=null,Fe(e),t)for(e=0;e>>=0,e===0?32:31-(Co(e)/qo|0)|0}var wn=64,Pr=4194304;function mr(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function pi(e,t){var r=e.pendingLanes;if(r===0)return 0;var a=0,l=e.suspendedLanes,v=e.pingedLanes,P=r&268435455;if(P!==0){var k=P&~l;k!==0?a=mr(k):(v&=P,v!==0&&(a=mr(v)))}else P=r&~l,P!==0?a=mr(P):v!==0&&(a=mr(v));if(a===0)return 0;if(t!==0&&t!==a&&!(t&l)&&(l=a&-a,v=t&-t,l>=v||l===16&&(v&4194240)!==0))return t;if(a&4&&(a|=r&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=a;0r;r++)t.push(e);return t}function Ar(e,t,r){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-cr(t),e[t]=r}function Jr(e,t){var r=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var a=e.eventTimes;for(e=e.expirationTimes;0=ja),ts=" ",ju=!1;function ns(e,t){switch(e){case"keyup":return pl.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function xi(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var iu=!1;function $c(e,t){switch(e){case"compositionend":return xi(t);case"keypress":return t.which!==32?null:(ju=!0,ts);case"textInput":return e=t.data,e===ts&&ju?null:e;default:return null}}function Di(e,t){if(iu)return e==="compositionend"||!ni&&ns(e,t)?(e=ti(),Hn=Kn=xn=null,iu=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:r,offset:t-e};e=a}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=uu(r)}}function yl(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?yl(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function xl(){for(var e=window,t=be();u(t,e.HTMLIFrameElement);){try{var r=typeof t.contentWindow.location.href=="string"}catch(a){r=!1}if(r)e=t.contentWindow;else break;t=be(e.document)}return t}function zu(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Vc(e){var t=xl(),r=e.focusedElem,a=e.selectionRange;if(t!==r&&r&&r.ownerDocument&&yl(r.ownerDocument.documentElement,r)){if(a!==null&&zu(r)){if(t=a.start,e=a.end,e===void 0&&(e=t),"selectionStart"in r)r.selectionStart=t,r.selectionEnd=Math.min(e,r.value.length);else if(e=(t=r.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=r.textContent.length,v=Math.min(a.start,l);a=a.end===void 0?v:Math.min(a.end,l),!e.extend&&v>a&&(l=a,a=v,v=l),l=gl(r,v);var P=gl(r,a);l&&P&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==P.node||e.focusOffset!==P.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),v>a?(e.addRange(t),e.extend(P.node,P.offset)):(t.setEnd(P.node,P.offset),e.addRange(t)))}}for(t=[],e=r;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof r.focus=="function"&&r.focus(),r=0;r=document.documentMode,ri=null,Ba=null,ba=null,Sl=!1;function Uu(e,t,r){var a=r.window===r?r.document:r.nodeType===9?r:r.ownerDocument;Sl||ri==null||ri!==be(a)||(a=ri,"selectionStart"in a&&zu(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),ba&&Bi(ba,a)||(ba=a,a=Ro(Ba,"onSelect"),0No||(e.current=Oi[No],Oi[No]=null,No--)}function vn(e,t){No++,Oi[No]=e.current,e.current=t}var bn={},Tn=mn(bn),xr=mn(!1),Ur=bn;function Sr(e,t){var r=e.type.contextTypes;if(!r)return bn;var a=e.stateNode;if(a&&a.__reactInternalMemoizedUnmaskedChildContext===t)return a.__reactInternalMemoizedMaskedChildContext;var l={},v;for(v in r)l[v]=t[v];return a&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function kr(e){return e=e.childContextTypes,e!=null}function Wa(){zt(xr),zt(Tn)}function hu(e,t,r){if(Tn.current!==bn)throw Error(p(168));vn(Tn,t),vn(xr,r)}function mu(e,t,r){var a=e.stateNode;if(t=t.childContextTypes,typeof a.getChildContext!="function")return r;a=a.getChildContext();for(var l in a)if(!(l in t))throw Error(p(108,Ye(e)||"Unknown",l));return he({},r,a)}function gu(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||bn,Ur=Tn.current,vn(Tn,e),vn(xr,xr.current),!0}function Mo(e,t,r){var a=e.stateNode;if(!a)throw Error(p(169));r?(e=mu(e,t,Ur),a.__reactInternalMemoizedMergedChildContext=e,zt(xr),zt(Tn),vn(Tn,e)):zt(xr),vn(xr,r)}var jo=null,pa=!1,Cl=!1;function yu(e){jo===null?jo=[e]:jo.push(e)}function Ti(e){pa=!0,yu(e)}function no(){if(!Cl&&jo!==null){Cl=!0;var e=0,t=un;try{var r=jo;for(un=1;e>=P,l-=P,Wr=1<<32-cr(t)+l|r<Nt?(Ht=it,it=null):Ht=it.sibling;var on=Re(Y,it,se[Nt],Le);if(on===null){it===null&&(it=Ht);break}e&&it&&on.alternate===null&&t(Y,it),X=v(on,X,Nt),nt===null?Je=on:nt.sibling=on,nt=on,it=Ht}if(Nt===se.length)return r(Y,it),pn&&ma(Y,Nt),Je;if(it===null){for(;NtNt?(Ht=it,it=null):Ht=it.sibling;var eu=Re(Y,it,on.value,Le);if(eu===null){it===null&&(it=Ht);break}e&&it&&eu.alternate===null&&t(Y,it),X=v(eu,X,Nt),nt===null?Je=eu:nt.sibling=eu,nt=eu,it=Ht}if(on.done)return r(Y,it),pn&&ma(Y,Nt),Je;if(it===null){for(;!on.done;Nt++,on=se.next())on=Se(Y,on.value,Le),on!==null&&(X=v(on,X,Nt),nt===null?Je=on:nt.sibling=on,nt=on);return pn&&ma(Y,Nt),Je}for(it=a(Y,it);!on.done;Nt++,on=se.next())on=ke(it,Y,Nt,on.value,Le),on!==null&&(e&&on.alternate!==null&&it.delete(on.key===null?Nt:on.key),X=v(on,X,Nt),nt===null?Je=on:nt.sibling=on,nt=on);return e&&it.forEach(function(yf){return t(Y,yf)}),pn&&ma(Y,Nt),Je}function Ce(Y,X,se,Le){if(typeof se=="object"&&se!==null&&se.type===J&&se.key===null&&(se=se.props.children),typeof se=="object"&&se!==null){switch(se.$$typeof){case V:e:{for(var Je=se.key,nt=X;nt!==null;){if(nt.key===Je){if(Je=se.type,Je===J){if(nt.tag===7){r(Y,nt.sibling),X=l(nt,se.props.children),X.return=Y,Y=X;break e}}else if(nt.elementType===Je||typeof Je=="object"&&Je!==null&&Je.$$typeof===_&&ga(Je)===nt.type){r(Y,nt.sibling),X=l(nt,se.props),X.ref=To(Y,nt,se),X.return=Y,Y=X;break e}r(Y,nt);break}else t(Y,nt);nt=nt.sibling}se.type===J?(X=qi(se.props.children,Y.mode,Le,se.key),X.return=Y,Y=X):(Le=Ji(se.type,se.key,se.props,null,Y.mode,Le),Le.ref=To(Y,X,se),Le.return=Y,Y=Le)}return P(Y);case G:e:{for(nt=se.key;X!==null;){if(X.key===nt)if(X.tag===4&&X.stateNode.containerInfo===se.containerInfo&&X.stateNode.implementation===se.implementation){r(Y,X.sibling),X=l(X,se.children||[]),X.return=Y,Y=X;break e}else{r(Y,X);break}else t(Y,X);X=X.sibling}X=Lc(se,Y.mode,Le),X.return=Y,Y=X}return P(Y);case _:return nt=se._init,Ce(Y,X,nt(se._payload),Le)}if(Ge(se))return Ke(Y,X,se,Le);if(ae(se))return gt(Y,X,se,Le);Lo(Y,se)}return typeof se=="string"&&se!==""||typeof se=="number"?(se=""+se,X!==null&&X.tag===6?(r(Y,X.sibling),X=l(X,se),X.return=Y,Y=X):(r(Y,X),X=$l(se,Y.mode,Le),X.return=Y,Y=X),P(Y)):r(Y,X)}return Ce}var Io=ui(!0),Ki=ui(!1),io={},Vr=mn(io),Ii=mn(io),Do=mn(io);function wi(e){if(e===io)throw Error(p(174));return e}function Hi(e,t){switch(vn(Do,t),vn(Ii,e),vn(Vr,io),e=t.nodeType,e){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:bt(null,"");break;default:e=e===8?t.parentNode:t,t=e.namespaceURI||null,e=e.tagName,t=bt(t,e)}zt(Vr),vn(Vr,t)}function Gi(){zt(Vr),zt(Ii),zt(Do)}function Su(e){wi(Do.current);var t=wi(Vr.current),r=bt(t,e.type);t!==r&&(vn(Ii,e),vn(Vr,r))}function Dn(e){Ii.current===e&&(zt(Vr),zt(Ii))}var Nn=mn(0);function Fo(e){for(var t=e;t!==null;){if(t.tag===13){var r=t.memoizedState;if(r!==null&&(r=r.dehydrated,r===null||r.data==="$?"||r.data==="$!"))return t}else if(t.tag===19&&t.memoizedProps.revealOrder!==void 0){if(t.flags&128)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var Yi=[];function ya(){for(var e=0;er?r:4,e(!0);var a=Jo.transition;Jo.transition={};try{e(!1),t()}finally{un=r,Jo.transition=a}}function Gc(){return uo().memoizedState}function cf(e,t,r){var a=Qr(e);if(r={lane:a,action:r,hasEagerState:!1,eagerState:null,next:null},sc(e))cc(t,r);else if(r=At(e,t,r,a),r!==null){var l=vr();_n(r,e,a,l),Dl(r,t,a)}}function Yc(e,t,r){var a=Qr(e),l={lane:a,action:r,hasEagerState:!1,eagerState:null,next:null};if(sc(e))cc(t,l);else{var v=e.alternate;if(e.lanes===0&&(v===null||v.lanes===0)&&(v=t.lastRenderedReducer,v!==null))try{var P=t.lastRenderedState,k=v(P,r);if(l.hasEagerState=!0,l.eagerState=k,dr(k,P)){var Q=t.interleaved;Q===null?(l.next=l,Lt(t)):(l.next=Q.next,Q.next=l),t.interleaved=l;return}}catch(ie){}finally{}r=At(e,t,l,a),r!==null&&(l=vr(),_n(r,e,a,l),Dl(r,t,a))}}function sc(e){var t=e.alternate;return e===Qt||t!==null&&t===Qt}function cc(e,t){Sa=Ka=!0;var r=e.pending;r===null?t.next=t:(t.next=r.next,r.next=t),e.pending=t}function Dl(e,t,r){if(r&4194240){var a=t.lanes;a&=e.pendingLanes,r|=a,t.lanes=r,tn(e,r)}}var ms={readContext:Ot,useCallback:Kr,useContext:Kr,useEffect:Kr,useImperativeHandle:Kr,useInsertionEffect:Kr,useLayoutEffect:Kr,useMemo:Kr,useReducer:Kr,useRef:Kr,useState:Kr,useDebugValue:Kr,useDeferredValue:Kr,useTransition:Kr,useMutableSource:Kr,useSyncExternalStore:Kr,useId:Kr,unstable_isNewReconciler:!1},ff={readContext:Ot,useCallback:function(t,r){return Er().memoizedState=[t,r===void 0?null:r],t},useContext:Ot,useEffect:ds,useImperativeHandle:function(t,r,a){return a=a!=null?a.concat([t]):null,Ou(4194308,4,ac.bind(null,r,t),a)},useLayoutEffect:function(t,r){return Ou(4194308,4,t,r)},useInsertionEffect:function(t,r){return Ou(4,2,t,r)},useMemo:function(t,r){var a=Er();return r=r===void 0?null:r,t=t(),a.memoizedState=[t,r],t},useReducer:function(t,r,a){var l=Er();return r=a!==void 0?a(r):r,l.memoizedState=l.baseState=r,t={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:t,lastRenderedState:r},l.queue=t,t=t.dispatch=cf.bind(null,Qt,t),[l.memoizedState,t]},useRef:function(t){var r=Er();return t={current:t},r.memoizedState=t},useState:Ku,useDebugValue:hs,useDeferredValue:function(t){return Er().memoizedState=t},useTransition:function(){var t=Ku(!1),r=t[0];return t=Hc.bind(null,t[1]),Er().memoizedState=t,[r,t]},useMutableSource:function(){},useSyncExternalStore:function(t,r,a){var l=Qt,v=Er();if(pn){if(a===void 0)throw Error(p(407));a=a()}else{if(a=r(),cn===null)throw Error(p(349));Sn&30||_s(l,r,a)}v.memoizedState=a;var P={value:a,getSnapshot:r};return v.queue=P,ds(tc.bind(null,l,P,t),[t]),l.flags|=2048,Hu(9,ec.bind(null,l,P,a,r),void 0,null),a},useId:function(){var t=Er(),r=cn.identifierPrefix;if(pn){var a=Nr,l=Wr;a=(l&~(1<<32-cr(l)-1)).toString(32)+a,r=":"+r+"R"+a,a=Al++,0<\/script>",e=e.removeChild(e.firstChild)):typeof a.is=="string"?e=P.createElement(r,{is:a.is}):(e=P.createElement(r),r==="select"&&(P=e,a.multiple?P.multiple=!0:a.size&&(P.size=a.size))):e=P.createElementNS(e,r),e[zr]=t,e[So]=a,Ps(e,t,!1,!1),t.stateNode=e;e:{switch(P=Xn(r,a),r){case"dialog":Cn("cancel",e),Cn("close",e),l=a;break;case"iframe":case"object":case"embed":Cn("load",e),l=a;break;case"video":case"audio":for(l=0;lzo&&(t.flags|=128,a=!0,Cr(v,!1),t.lanes=4194304)}else{if(!a)if(e=Fo(P),e!==null){if(t.flags|=128,a=!0,r=e.updateQueue,r!==null&&(t.updateQueue=r,t.flags|=4),Cr(v,!0),v.tail===null&&v.tailMode==="hidden"&&!P.alternate&&!pn)return so(t),null}else 2*sn()-v.renderingStartTime>zo&&r!==1073741824&&(t.flags|=128,a=!0,Cr(v,!1),t.lanes=4194304);v.isBackwards?(P.sibling=t.child,t.child=P):(r=v.last,r!==null?r.sibling=P:t.child=P,v.last=P)}return v.tail!==null?(t=v.tail,v.rendering=t,v.tail=t.sibling,v.renderingStartTime=sn(),t.sibling=null,r=Nn.current,vn(Nn,a?r&1|2:r&1),t):(so(t),null);case 22:case 23:return Ca(),a=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==a&&(t.flags|=8192),a&&t.mode&1?Gr&1073741824&&(so(t),t.subtreeFlags&6&&(t.flags|=8192)):so(t),null;case 24:return null;case 25:return null}throw Error(p(156,t.tag))}function Rs(e,t){switch(oo(t),t.tag){case 1:return kr(t.type)&&Wa(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Gi(),zt(xr),zt(Tn),ya(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return Dn(t),null;case 13:if(zt(Nn),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(p(340));ee()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return zt(Nn),null;case 4:return Gi(),null;case 10:return st(t.type._context),null;case 22:case 23:return Ca(),null;case 24:return null;default:return null}}var Mr=!1,co=!1,Ct=typeof WeakSet=="function"?WeakSet:Set,Et=null;function Ga(e,t){var r=e.ref;if(r!==null)if(typeof r=="function")try{r(null)}catch(a){pr(e,t,a)}else r.current=null}function Ns(e,t,r){try{r()}catch(a){pr(e,t,a)}}var qc=!1;function zl(e,t){if(vu=Ra,e=xl(),zu(e)){if("selectionStart"in e)var r={start:e.selectionStart,end:e.selectionEnd};else e:{r=(r=e.ownerDocument)&&r.defaultView||window;var a=r.getSelection&&r.getSelection();if(a&&a.rangeCount!==0){r=a.anchorNode;var l=a.anchorOffset,v=a.focusNode;a=a.focusOffset;try{r.nodeType,v.nodeType}catch(Le){r=null;break e}var P=0,k=-1,Q=-1,ie=0,fe=0,Se=e,Re=null;t:for(;;){for(var ke;Se!==r||l!==0&&Se.nodeType!==3||(k=P+l),Se!==v||a!==0&&Se.nodeType!==3||(Q=P+a),Se.nodeType===3&&(P+=Se.nodeValue.length),(ke=Se.firstChild)!==null;)Re=Se,Se=ke;for(;;){if(Se===e)break t;if(Re===r&&++ie===l&&(k=P),Re===v&&++fe===a&&(Q=P),(ke=Se.nextSibling)!==null)break;Se=Re,Re=Se.parentNode}Se=ke}r=k===-1||Q===-1?null:{start:k,end:Q}}else r=null}r=r||{start:0,end:0}}else r=null;for($a={focusedElem:e,selectionRange:r},Ra=!1,Et=t;Et!==null;)if(t=Et,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,Et=e;else for(;Et!==null;){t=Et;try{var Ke=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(Ke!==null){var gt=Ke.memoizedProps,Ce=Ke.memoizedState,Y=t.stateNode,X=Y.getSnapshotBeforeUpdate(t.elementType===t.type?gt:ve(t.type,gt),Ce);Y.__reactInternalSnapshotBeforeUpdate=X}break;case 3:var se=t.stateNode.containerInfo;se.nodeType===1?se.textContent="":se.nodeType===9&&se.documentElement&&se.removeChild(se.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(p(163))}}catch(Le){pr(t,t.return,Le)}if(e=t.sibling,e!==null){e.return=t.return,Et=e;break}Et=t.return}return Ke=qc,qc=!1,Ke}function Ya(e,t,r){var a=t.updateQueue;if(a=a!==null?a.lastEffect:null,a!==null){var l=a=a.next;do{if((l.tag&e)===e){var v=l.destroy;l.destroy=void 0,v!==void 0&&Ns(t,r,v)}l=l.next}while(l!==a)}}function Qu(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var r=t=t.next;do{if((r.tag&e)===e){var a=r.create;r.destroy=a()}r=r.next}while(r!==t)}}function Ms(e){var t=e.ref;if(t!==null){var r=e.stateNode;switch(e.tag){case 5:e=r;break;default:e=r}typeof t=="function"?t(e):t.current=e}}function Oc(e){var t=e.alternate;t!==null&&(e.alternate=null,Oc(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[zr],delete t[So],delete t[wl],delete t[cs],delete t[Wi])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Tc(e){return e.tag===5||e.tag===3||e.tag===4}function js(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Tc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Ul(e,t,r){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?r.nodeType===8?r.parentNode.insertBefore(e,t):r.insertBefore(e,t):(r.nodeType===8?(t=r.parentNode,t.insertBefore(e,r)):(t=r,t.appendChild(e)),r=r._reactRootContainer,r!=null||t.onclick!==null||(t.onclick=du));else if(a!==4&&(e=e.child,e!==null))for(Ul(e,t,r),e=e.sibling;e!==null;)Ul(e,t,r),e=e.sibling}function jr(e,t,r){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?r.insertBefore(e,t):r.appendChild(e);else if(a!==4&&(e=e.child,e!==null))for(jr(e,t,r),e=e.sibling;e!==null;)jr(e,t,r),e=e.sibling}var Fn=null,Hr=!1;function Oa(e,t,r){for(r=r.child;r!==null;)Ic(e,t,r),r=r.sibling}function Ic(e,t,r){if(Qn&&typeof Qn.onCommitFiberUnmount=="function")try{Qn.onCommitFiberUnmount(Wn,r)}catch(k){}switch(r.tag){case 5:co||Ga(r,t);case 6:var a=Fn,l=Hr;Fn=null,Oa(e,t,r),Fn=a,Hr=l,Fn!==null&&(Hr?(e=Fn,r=r.stateNode,e.nodeType===8?e.parentNode.removeChild(r):e.removeChild(r)):Fn.removeChild(r.stateNode));break;case 18:Fn!==null&&(Hr?(e=Fn,r=r.stateNode,e.nodeType===8?Ko(e.parentNode,r):e.nodeType===1&&Ko(e,r),yo(e)):Ko(Fn,r.stateNode));break;case 4:a=Fn,l=Hr,Fn=r.stateNode.containerInfo,Hr=!0,Oa(e,t,r),Fn=a,Hr=l;break;case 0:case 11:case 14:case 15:if(!co&&(a=r.updateQueue,a!==null&&(a=a.lastEffect,a!==null))){l=a=a.next;do{var v=l,P=v.destroy;v=v.tag,P!==void 0&&(v&2||v&4)&&Ns(r,t,P),l=l.next}while(l!==a)}Oa(e,t,r);break;case 1:if(!co&&(Ga(r,t),a=r.stateNode,typeof a.componentWillUnmount=="function"))try{a.props=r.memoizedProps,a.state=r.memoizedState,a.componentWillUnmount()}catch(k){pr(r,t,k)}Oa(e,t,r);break;case 21:Oa(e,t,r);break;case 22:r.mode&1?(co=(a=co)||r.memoizedState!==null,Oa(e,t,r),co=a):Oa(e,t,r);break;default:Oa(e,t,r)}}function ci(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var r=e.stateNode;r===null&&(r=e.stateNode=new Ct),t.forEach(function(a){var l=of.bind(null,e,a);r.has(a)||(r.add(a),a.then(l,l))})}}function fi(e,t){var r=t.deletions;if(r!==null)for(var a=0;al&&(l=P),a&=~v}if(a=l,a=sn()-a,a=(120>a?120:480>a?480:1080>a?1080:1920>a?1920:3e3>a?3e3:4320>a?4320:1960*Ls(a/1960))-a,10e?16:e,Ni===null)var a=!1;else{if(e=Ni,Ni=null,Qa=0,$t&6)throw Error(p(331));var l=$t;for($t|=4,Et=e.current;Et!==null;){var v=Et,P=v.child;if(Et.flags&16){var k=v.deletions;if(k!==null){for(var Q=0;Qsn()-Xa?Ja(e,0):Tu|=r),wo(e,t)}function rf(e,t){t===0&&(e.mode&1?(t=Pr,Pr<<=1,!(Pr&130023424)&&(Pr=4194304)):t=1);var r=vr();e=Tt(e,t),e!==null&&(Ar(e,t,r),wo(e,r))}function hf(e){var t=e.memoizedState,r=0;t!==null&&(r=t.retryLane),rf(e,r)}function of(e,t){var r=0;switch(e.tag){case 13:var a=e.stateNode,l=e.memoizedState;l!==null&&(r=l.retryLane);break;case 19:a=e.stateNode;break;default:throw Error(p(314))}a!==null&&a.delete(t),rf(e,r)}var Mc;Mc=function(t,r,a){if(t!==null)if(t.memoizedProps!==r.pendingProps||xr.current)Mn=!0;else{if(!(t.lanes&a)&&!(r.flags&128))return Mn=!1,Jc(t,r,a);Mn=!!(t.flags&131072)}else Mn=!1,pn&&r.flags&1048576&&Pl(r,$r,r.index);switch(r.lanes=0,r.tag){case 2:var l=r.type;si(t,r),t=r.pendingProps;var v=Sr(r,Tn.current);vt(r,a),v=Nl(null,r,l,t,v,a);var P=li();return r.flags|=1,typeof v=="object"&&v!==null&&typeof v.render=="function"&&v.$$typeof===void 0?(r.tag=1,r.memoizedState=null,r.updateQueue=null,kr(l)?(P=!0,gu(r)):P=!1,r.memoizedState=v.state!==null&&v.state!==void 0?v.state:null,Xt(r),v.updater=Oo,r.stateNode=v,v._reactInternals=r,ai(r,l,t,a),r=Ss(null,r,l,!0,P,a)):(r.tag=0,pn&&P&&Vu(r),lo(null,r,v,a),r=r.child),r;case 16:l=r.elementType;e:{switch(si(t,r),t=r.pendingProps,v=l._init,l=v(l._payload),r.type=l,v=r.tag=_a(l),t=ve(l,t),v){case 0:r=ys(null,r,l,t,a);break e;case 1:r=xs(null,r,l,t,a);break e;case 11:r=mc(null,r,l,t,a);break e;case 14:r=gc(null,r,l,ve(l.type,t),a);break e}throw Error(p(306,l,""))}return r;case 0:return l=r.type,v=r.pendingProps,v=r.elementType===l?v:ve(l,v),ys(t,r,l,v,a);case 1:return l=r.type,v=r.pendingProps,v=r.elementType===l?v:ve(l,v),xs(t,r,l,v,a);case 3:e:{if(Sc(r),t===null)throw Error(p(387));l=r.pendingProps,P=r.memoizedState,v=P.element,Mt(t,r),Un(r,l,null,a);var k=r.memoizedState;if(l=k.element,P.isDehydrated)if(P={element:l,isDehydrated:!1,cache:k.cache,pendingSuspenseBoundaries:k.pendingSuspenseBoundaries,transitions:k.transitions},r.updateQueue.baseState=P,r.memoizedState=P,r.flags&256){v=Ha(Error(p(423)),r),r=Es(t,r,l,a,v);break e}else if(l!==v){v=Ha(Error(p(424)),r),r=Es(t,r,l,a,v);break e}else for(nn=Ho(r.stateNode.containerInfo.firstChild),zn=r,pn=!0,Qo=null,a=Ki(r,null,l,a),r.child=a;a;)a.flags=a.flags&-3|4096,a=a.sibling;else{if(ee(),l===v){r=Ea(t,r,a);break e}lo(t,r,l,a)}r=r.child}return r;case 5:return Su(r),t===null&&N(r),l=r.type,v=r.pendingProps,P=t!==null?t.memoizedProps:null,k=v.children,fa(l,v)?k=null:P!==null&&fa(l,P)&&(r.flags|=32),gs(t,r),lo(t,r,k,a),r.child;case 6:return t===null&&N(r),null;case 13:return Ts(t,r,a);case 4:return Hi(r,r.stateNode.containerInfo),l=r.pendingProps,t===null?r.child=Io(r,null,l,a):lo(t,r,l,a),r.child;case 11:return l=r.type,v=r.pendingProps,v=r.elementType===l?v:ve(l,v),mc(t,r,l,v,a);case 7:return lo(t,r,r.pendingProps,a),r.child;case 8:return lo(t,r,r.pendingProps.children,a),r.child;case 12:return lo(t,r,r.pendingProps.children,a),r.child;case 10:e:{if(l=r.type._context,v=r.pendingProps,P=r.memoizedProps,k=v.value,vn(Be,l._currentValue),l._currentValue=k,P!==null)if(dr(P.value,k)){if(P.children===v.children&&!xr.current){r=Ea(t,r,a);break e}}else for(P=r.child,P!==null&&(P.return=r);P!==null;){var Q=P.dependencies;if(Q!==null){k=P.child;for(var ie=Q.firstContext;ie!==null;){if(ie.context===l){if(P.tag===1){ie=It(-1,a&-a),ie.tag=2;var fe=P.updateQueue;if(fe!==null){fe=fe.shared;var Se=fe.pending;Se===null?ie.next=ie:(ie.next=Se.next,Se.next=ie),fe.pending=ie}}P.lanes|=a,ie=P.alternate,ie!==null&&(ie.lanes|=a),ft(P.return,a,r),Q.lanes|=a;break}ie=ie.next}}else if(P.tag===10)k=P.type===r.type?null:P.child;else if(P.tag===18){if(k=P.return,k===null)throw Error(p(341));k.lanes|=a,Q=k.alternate,Q!==null&&(Q.lanes|=a),ft(k,a,r),k=P.sibling}else k=P.child;if(k!==null)k.return=P;else for(k=P;k!==null;){if(k===r){k=null;break}if(P=k.sibling,P!==null){P.return=k.return,k=P;break}k=k.return}P=k}lo(t,r,v.children,a),r=r.child}return r;case 9:return v=r.type,l=r.pendingProps.children,vt(r,a),v=Ot(v),l=l(v),r.flags|=1,lo(t,r,l,a),r.child;case 14:return l=r.type,v=ve(l,r.pendingProps),v=ve(l.type,v),gc(t,r,l,v,a);case 15:return yc(t,r,r.type,r.pendingProps,a);case 17:return l=r.type,v=r.pendingProps,v=r.elementType===l?v:ve(l,v),si(t,r),r.tag=1,kr(l)?(t=!0,gu(r)):t=!1,vt(r,a),xu(r,l,v),ai(r,l,v,a),Ss(null,r,l,!0,t,a);case 19:return bl(t,r,a);case 22:return xc(t,r,a)}throw Error(p(156,r.tag))};function af(e,t){return lr(e,t)}function vi(e,t,r,a){this.tag=e,this.key=r,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=a,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Uo(e,t,r,a){return new vi(e,t,r,a)}function jc(e){return e=e.prototype,!(!e||!e.isReactComponent)}function _a(e){if(typeof e=="function")return jc(e)?1:0;if(e!=null){if(e=e.$$typeof,e===pe)return 11;if(e===K)return 14}return 2}function Mi(e,t){var r=e.alternate;return r===null?(r=Uo(e.tag,t,e.key,e.mode),r.elementType=e.elementType,r.type=e.type,r.stateNode=e.stateNode,r.alternate=e,e.alternate=r):(r.pendingProps=t,r.type=e.type,r.flags=0,r.subtreeFlags=0,r.deletions=null),r.flags=e.flags&14680064,r.childLanes=e.childLanes,r.lanes=e.lanes,r.child=e.child,r.memoizedProps=e.memoizedProps,r.memoizedState=e.memoizedState,r.updateQueue=e.updateQueue,t=e.dependencies,r.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},r.sibling=e.sibling,r.index=e.index,r.ref=e.ref,r}function Ji(e,t,r,a,l,v){var P=2;if(a=e,typeof e=="function")jc(e)&&(P=1);else if(typeof e=="string")P=5;else e:switch(e){case J:return qi(r.children,l,v,t);case oe:P=8,l|=8;break;case Z:return e=Uo(12,r,t,l|2),e.elementType=Z,e.lanes=v,e;case ce:return e=Uo(13,r,t,l),e.elementType=ce,e.lanes=v,e;case q:return e=Uo(19,r,t,l),e.elementType=q,e.lanes=v,e;case W:return nl(r,l,v,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case ne:P=10;break e;case te:P=9;break e;case pe:P=11;break e;case K:P=14;break e;case _:P=16,a=null;break e}throw Error(p(130,e==null?e:typeof e=="undefined"?"undefined":s(e),""))}return t=Uo(P,r,t,l),t.elementType=e,t.type=a,t.lanes=v,t}function qi(e,t,r,a){return e=Uo(7,e,a,t),e.lanes=r,e}function nl(e,t,r,a){return e=Uo(22,e,a,t),e.elementType=W,e.lanes=r,e.stateNode={isHidden:!1},e}function $l(e,t,r){return e=Uo(6,e,null,t),e.lanes=r,e}function Lc(e,t,r){return t=Uo(4,e.children!==null?e.children:[],e.key,t),t.lanes=r,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Dc(e,t,r,a,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=tr(0),this.expirationTimes=tr(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=tr(0),this.identifierPrefix=a,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Fc(e,t,r,a,l,v,P,k,Q){return e=new Dc(e,t,r,k,Q),t===1?(t=1,v===!0&&(t|=8)):t=0,v=Uo(3,null,null,t),e.current=v,v.stateNode=e,v.memoizedState={element:a,isDehydrated:r,cache:null,transitions:null,pendingSuspenseBoundaries:null},Xt(v),e}function uf(e,t,r){var a=3Me.length)&&(Ne=Me.length);for(var We=0,_e=new Array(Ne);We1?We-1:0),xt=1;xt/gm),ut=j(/\${[\w\W]*}/gm),Ie=j(/^data-[\-\w.\u00B7-\uFFFF]/),De=j(/^aria-[\-\w]+$/),be=j(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Xe=j(/^(?:\w+script|data):/i),lt=j(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),tt=j(/^html$/i),ct=j(/^[a-z][.\w]*(-[.\w]+)+$/i),qe=function(){return typeof window=="undefined"?null:window},Ue=function(Ne,We){if(n(Ne)!=="object"||typeof Ne.createPolicy!="function")return null;var _e=null,xt="data-tt-policy-suffix";We.currentScript&&We.currentScript.hasAttribute(xt)&&(_e=We.currentScript.getAttribute(xt));var bt="dompurify"+(_e?"#"+_e:"");try{return Ne.createPolicy(bt,{createHTML:function(St){return St},createScriptURL:function(St){return St}})}catch(Wt){return console.warn("TrustedTypes policy "+bt+" could not be created."),null}};function Ge(){var Me=arguments.length>0&&arguments[0]!==void 0?arguments[0]:qe(),Ne=function(Ee){return Ge(Ee)};if(Ne.version="2.5.0",Ne.removed=[],!Me||!Me.document||Me.document.nodeType!==9)return Ne.isSupported=!1,Ne;var We=Me.document,_e=Me.document,xt=Me.DocumentFragment,bt=Me.HTMLTemplateElement,Wt=Me.Node,St=Me.Element,et=Me.NodeFilter,He=Me.NamedNodeMap,Ft=He===void 0?Me.NamedNodeMap||Me.MozNamedAttrMap:He,Ut=Me.HTMLFormElement,fn=Me.DOMParser,gn=Me.trustedTypes,kn=St.prototype,Xn=_(kn,"cloneNode"),Lr=_(kn,"nextSibling"),le=_(kn,"childNodes"),we=_(kn,"parentNode");if(typeof bt=="function"){var ge=_e.createElement("template");ge.content&&ge.content.ownerDocument&&(_e=ge.content.ownerDocument)}var Oe=Ue(gn,We),Fe=Oe?Oe.createHTML(""):"",Ve=_e,pt=Ve.implementation,dt=Ve.createNodeIterator,Rt=Ve.createDocumentFragment,at=Ve.getElementsByTagName,Gt=We.importNode,Vt={};try{Vt=K(_e).documentMode?_e.documentMode:{}}catch(Pt){}var Bt={};Ne.isSupported=typeof we=="function"&&pt&&pt.createHTMLDocument!==void 0&&Vt!==9;var Kt=Qe,qt=yt,Jt=ut,kt=Ie,$n=De,jn=Xe,ar=lt,vo=ct,jt=be,_t=null,po=q({},[].concat(d(W),d(H),d(ae),d(Te),d(xe))),yn=null,ur=q({},[].concat(d(Ae),d(Pe),d(me),d(Ye))),en=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Or=null,lr=null,eo=!0,hr=!0,ln=!1,sn=!0,An=!1,Dr=!0,er=!1,sr=!1,Fr=!1,hn=!1,Wn=!1,Qn=!1,On=!0,cr=!1,Co="user-content-",qo=!0,Tr=!1,wn={},Pr=null,mr=q({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),pi=null,hi=q({},["audio","video","img","source","image","track"]),Zr=null,mi=q({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),ko="http://www.w3.org/1998/Math/MathML",tr="http://www.w3.org/2000/svg",Ar="http://www.w3.org/1999/xhtml",Jr=Ar,tn=!1,un=null,_o=q({},[ko,tr,Ar],V),ho,Pa=["application/xhtml+xml","text/html"],tu="text/html",Zn,Po=null,ei=_e.createElement("form"),Rr=function(Ee){return y(Ee,RegExp)||y(Ee,Function)},gr=function(Ee){Po&&Po===Ee||((!Ee||n(Ee)!=="object")&&(Ee={}),Ee=K(Ee),ho=Pa.indexOf(Ee.PARSER_MEDIA_TYPE)===-1?ho=tu:ho=Ee.PARSER_MEDIA_TYPE,Zn=ho==="application/xhtml+xml"?V:F,_t="ALLOWED_TAGS"in Ee?q({},Ee.ALLOWED_TAGS,Zn):po,yn="ALLOWED_ATTR"in Ee?q({},Ee.ALLOWED_ATTR,Zn):ur,un="ALLOWED_NAMESPACES"in Ee?q({},Ee.ALLOWED_NAMESPACES,V):_o,Zr="ADD_URI_SAFE_ATTR"in Ee?q(K(mi),Ee.ADD_URI_SAFE_ATTR,Zn):mi,pi="ADD_DATA_URI_TAGS"in Ee?q(K(hi),Ee.ADD_DATA_URI_TAGS,Zn):hi,Pr="FORBID_CONTENTS"in Ee?q({},Ee.FORBID_CONTENTS,Zn):mr,Or="FORBID_TAGS"in Ee?q({},Ee.FORBID_TAGS,Zn):{},lr="FORBID_ATTR"in Ee?q({},Ee.FORBID_ATTR,Zn):{},wn="USE_PROFILES"in Ee?Ee.USE_PROFILES:!1,eo=Ee.ALLOW_ARIA_ATTR!==!1,hr=Ee.ALLOW_DATA_ATTR!==!1,ln=Ee.ALLOW_UNKNOWN_PROTOCOLS||!1,sn=Ee.ALLOW_SELF_CLOSE_IN_ATTR!==!1,An=Ee.SAFE_FOR_TEMPLATES||!1,Dr=Ee.SAFE_FOR_XML!==!1,er=Ee.WHOLE_DOCUMENT||!1,hn=Ee.RETURN_DOM||!1,Wn=Ee.RETURN_DOM_FRAGMENT||!1,Qn=Ee.RETURN_TRUSTED_TYPE||!1,Fr=Ee.FORCE_BODY||!1,On=Ee.SANITIZE_DOM!==!1,cr=Ee.SANITIZE_NAMED_PROPS||!1,qo=Ee.KEEP_CONTENT!==!1,Tr=Ee.IN_PLACE||!1,jt=Ee.ALLOWED_URI_REGEXP||jt,Jr=Ee.NAMESPACE||Ar,en=Ee.CUSTOM_ELEMENT_HANDLING||{},Ee.CUSTOM_ELEMENT_HANDLING&&Rr(Ee.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(en.tagNameCheck=Ee.CUSTOM_ELEMENT_HANDLING.tagNameCheck),Ee.CUSTOM_ELEMENT_HANDLING&&Rr(Ee.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(en.attributeNameCheck=Ee.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),Ee.CUSTOM_ELEMENT_HANDLING&&typeof Ee.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements=="boolean"&&(en.allowCustomizedBuiltInElements=Ee.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),An&&(hr=!1),Wn&&(hn=!0),wn&&(_t=q({},d(xe)),yn=[],wn.html===!0&&(q(_t,W),q(yn,Ae)),wn.svg===!0&&(q(_t,H),q(yn,Pe),q(yn,Ye)),wn.svgFilters===!0&&(q(_t,ae),q(yn,Pe),q(yn,Ye)),wn.mathMl===!0&&(q(_t,Te),q(yn,me),q(yn,Ye))),Ee.ADD_TAGS&&(_t===po&&(_t=K(_t)),q(_t,Ee.ADD_TAGS,Zn)),Ee.ADD_ATTR&&(yn===ur&&(yn=K(yn)),q(yn,Ee.ADD_ATTR,Zn)),Ee.ADD_URI_SAFE_ATTR&&q(Zr,Ee.ADD_URI_SAFE_ATTR,Zn),Ee.FORBID_CONTENTS&&(Pr===mr&&(Pr=K(Pr)),q(Pr,Ee.FORBID_CONTENTS,Zn)),qo&&(_t["#text"]=!0),er&&q(_t,["html","head","body"]),_t.table&&(q(_t,["tbody"]),delete Or.tbody),R&&R(Ee),Po=Ee)},fr=q({},["mi","mo","mn","ms","mtext"]),Br=q({},["foreignobject","desc","title","annotation-xml"]),$o=q({},["title","style","font","a","script"]),Vn=q({},H);q(Vn,ae),q(Vn,he);var mo=q({},Te);q(mo,ye);var nu=function(Ee){var rt=we(Ee);(!rt||!rt.tagName)&&(rt={namespaceURI:Jr,tagName:"template"});var mt=F(Ee.tagName),Yt=F(rt.tagName);return un[Ee.namespaceURI]?Ee.namespaceURI===tr?rt.namespaceURI===Ar?mt==="svg":rt.namespaceURI===ko?mt==="svg"&&(Yt==="annotation-xml"||fr[Yt]):!!Vn[mt]:Ee.namespaceURI===ko?rt.namespaceURI===Ar?mt==="math":rt.namespaceURI===tr?mt==="math"&&Br[Yt]:!!mo[mt]:Ee.namespaceURI===Ar?rt.namespaceURI===tr&&!Br[Yt]||rt.namespaceURI===ko&&!fr[Yt]?!1:!mo[mt]&&($o[mt]||!Vn[mt]):!!(ho==="application/xhtml+xml"&&un[Ee.namespaceURI]):!1},Bn=function(Ee){L(Ne.removed,{element:Ee});try{Ee.parentNode.removeChild(Ee)}catch(rt){try{Ee.outerHTML=Fe}catch(mt){Ee.remove()}}},go=function(Ee,rt){try{L(Ne.removed,{attribute:rt.getAttributeNode(Ee),from:rt})}catch(mt){L(Ne.removed,{attribute:null,from:rt})}if(rt.removeAttribute(Ee),Ee==="is"&&!yn[Ee])if(hn||Wn)try{Bn(rt)}catch(mt){}else try{rt.setAttribute(Ee,"")}catch(mt){}},Aa=function(Ee){var rt,mt;if(Fr)Ee=""+Ee;else{var Yt=G(Ee,/^[\r\n\t ]+/);mt=Yt&&Yt[0]}ho==="application/xhtml+xml"&&Jr===Ar&&(Ee=''+Ee+"");var xn=Oe?Oe.createHTML(Ee):Ee;if(Jr===Ar)try{rt=new fn().parseFromString(xn,ho)}catch(Hn){}if(!rt||!rt.documentElement){rt=pt.createDocument(Jr,"template",null);try{rt.documentElement.innerHTML=tn?Fe:xn}catch(Hn){}}var Kn=rt.body||rt.documentElement;return Ee&&mt&&Kn.insertBefore(_e.createTextNode(mt),Kn.childNodes[0]||null),Jr===Ar?at.call(rt,er?"html":"body")[0]:er?rt.documentElement:Kn},nr=function(Ee){return dt.call(Ee.ownerDocument||Ee,Ee,et.SHOW_ELEMENT|et.SHOW_COMMENT|et.SHOW_TEXT|et.SHOW_PROCESSING_INSTRUCTION|et.SHOW_CDATA_SECTION,null,!1)},_i=function(Ee){return y(Ee,Ut)&&(typeof Ee.nodeName!="string"||typeof Ee.textContent!="string"||typeof Ee.removeChild!="function"||!y(Ee.attributes,Ft)||typeof Ee.removeAttribute!="function"||typeof Ee.setAttribute!="function"||typeof Ee.namespaceURI!="string"||typeof Ee.insertBefore!="function"||typeof Ee.hasChildNodes!="function")},ji=function(Ee){return n(Wt)==="object"?y(Ee,Wt):Ee&&n(Ee)==="object"&&typeof Ee.nodeType=="number"&&typeof Ee.nodeName=="string"},qr=function(Ee,rt,mt){Bt[Ee]&&D(Bt[Ee],function(Yt){Yt.call(Ne,rt,mt,Po)})},Ao=function(Ee){var rt;if(qr("beforeSanitizeElements",Ee,null),_i(Ee)||ne(/[\u0080-\uFFFF]/,Ee.nodeName))return Bn(Ee),!0;var mt=Zn(Ee.nodeName);if(qr("uponSanitizeElement",Ee,{tagName:mt,allowedTags:_t}),Ee.hasChildNodes()&&!ji(Ee.firstElementChild)&&(!ji(Ee.content)||!ji(Ee.content.firstElementChild))&&ne(/<[/\w]/g,Ee.innerHTML)&&ne(/<[/\w]/g,Ee.textContent)||mt==="select"&&ne(/=0;--Hn)Yt.insertBefore(Xn(xn[Hn],!0),Lr(Ee))}return Bn(Ee),!0}return y(Ee,St)&&!nu(Ee)||(mt==="noscript"||mt==="noembed"||mt==="noframes")&&ne(/<\/no(script|embed|frames)/i,Ee.innerHTML)?(Bn(Ee),!0):(An&&Ee.nodeType===3&&(rt=Ee.textContent,rt=J(rt,Kt," "),rt=J(rt,qt," "),rt=J(rt,Jt," "),Ee.textContent!==rt&&(L(Ne.removed,{element:Ee.cloneNode()}),Ee.textContent=rt)),qr("afterSanitizeElements",Ee,null),!1)},yo=function(Ee,rt,mt){if(On&&(rt==="id"||rt==="name")&&(mt in _e||mt in ei))return!1;if(!(hr&&!lr[rt]&&ne(kt,rt))){if(!(eo&&ne($n,rt))){if(!yn[rt]||lr[rt]){if(!(Wo(Ee)&&(y(en.tagNameCheck,RegExp)&&ne(en.tagNameCheck,Ee)||y(en.tagNameCheck,Function)&&en.tagNameCheck(Ee))&&(y(en.attributeNameCheck,RegExp)&&ne(en.attributeNameCheck,rt)||y(en.attributeNameCheck,Function)&&en.attributeNameCheck(rt))||rt==="is"&&en.allowCustomizedBuiltInElements&&(y(en.tagNameCheck,RegExp)&&ne(en.tagNameCheck,mt)||y(en.tagNameCheck,Function)&&en.tagNameCheck(mt))))return!1}else if(!Zr[rt]){if(!ne(jt,J(mt,ar,""))){if(!((rt==="src"||rt==="xlink:href"||rt==="href")&&Ee!=="script"&&oe(mt,"data:")===0&&pi[Ee])){if(!(ln&&!ne(jn,J(mt,ar,"")))){if(mt)return!1}}}}}}return!0},Wo=function(Ee){return Ee!=="annotation-xml"&&G(Ee,vo)},Ra=function(Ee){var rt,mt,Yt,xn;qr("beforeSanitizeAttributes",Ee,null);var Kn=Ee.attributes;if(Kn){var Hn={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:yn};for(xn=Kn.length;xn--;){rt=Kn[xn];var ti=rt,En=ti.name,gi=ti.namespaceURI;if(mt=En==="value"?rt.value:Z(rt.value),Yt=Zn(En),Hn.attrName=Yt,Hn.attrValue=mt,Hn.keepAttr=!0,Hn.forceKeepAttr=void 0,qr("uponSanitizeAttribute",Ee,Hn),mt=Hn.attrValue,!Hn.forceKeepAttr&&(go(En,Ee),!!Hn.keepAttr)){if(!sn&&ne(/\/>/i,mt)){go(En,Ee);continue}An&&(mt=J(mt,Kt," "),mt=J(mt,qt," "),mt=J(mt,Jt," "));var rr=Zn(Ee.nodeName);if(yo(rr,Yt,mt)){if(cr&&(Yt==="id"||Yt==="name")&&(go(En,Ee),mt=Co+mt),Oe&&n(gn)==="object"&&typeof gn.getAttributeType=="function"&&!gi)switch(gn.getAttributeType(rr,Yt)){case"TrustedHTML":{mt=Oe.createHTML(mt);break}case"TrustedScriptURL":{mt=Oe.createScriptURL(mt);break}}try{gi?Ee.setAttributeNS(gi,En,mt):Ee.setAttribute(En,mt),b(Ne.removed)}catch(yr){}}}}qr("afterSanitizeAttributes",Ee,null)}},Na=function Pt(Ee){var rt,mt=nr(Ee);for(qr("beforeSanitizeShadowDOM",Ee,null);rt=mt.nextNode();)qr("uponSanitizeShadowNode",rt,null),!Ao(rt)&&(y(rt.content,xt)&&Pt(rt.content),Ra(rt));qr("afterSanitizeShadowDOM",Ee,null)};return Ne.sanitize=function(Pt){var Ee=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},rt,mt,Yt,xn,Kn;if(tn=!Pt,tn&&(Pt=""),typeof Pt!="string"&&!ji(Pt))if(typeof Pt.toString=="function"){if(Pt=Pt.toString(),typeof Pt!="string")throw te("dirty is not a string, aborting")}else throw te("toString is not a function");if(!Ne.isSupported){if(n(Me.toStaticHTML)==="object"||typeof Me.toStaticHTML=="function"){if(typeof Pt=="string")return Me.toStaticHTML(Pt);if(ji(Pt))return Me.toStaticHTML(Pt.outerHTML)}return Pt}if(sr||gr(Ee),Ne.removed=[],typeof Pt=="string"&&(Tr=!1),Tr){if(Pt.nodeName){var Hn=Zn(Pt.nodeName);if(!_t[Hn]||Or[Hn])throw te("root node is forbidden and cannot be sanitized in-place")}}else if(y(Pt,Wt))rt=Aa(""),mt=rt.ownerDocument.importNode(Pt,!0),mt.nodeType===1&&mt.nodeName==="BODY"||mt.nodeName==="HTML"?rt=mt:rt.appendChild(mt);else{if(!hn&&!An&&!er&&Pt.indexOf("<")===-1)return Oe&&Qn?Oe.createHTML(Pt):Pt;if(rt=Aa(Pt),!rt)return hn?null:Qn?Fe:""}rt&&Fr&&Bn(rt.firstChild);for(var ti=nr(Tr?Pt:rt);Yt=ti.nextNode();)Yt.nodeType===3&&Yt===xn||Ao(Yt)||(y(Yt.content,xt)&&Na(Yt.content),Ra(Yt),xn=Yt);if(xn=null,Tr)return Pt;if(hn){if(Wn)for(Kn=Rt.call(rt.ownerDocument);rt.firstChild;)Kn.appendChild(rt.firstChild);else Kn=rt;return(yn.shadowroot||yn.shadowrootmod)&&(Kn=Gt.call(We,Kn,!0)),Kn}var En=er?rt.outerHTML:rt.innerHTML;return er&&_t["!doctype"]&&rt.ownerDocument&&rt.ownerDocument.doctype&&rt.ownerDocument.doctype.name&&ne(tt,rt.ownerDocument.doctype.name)&&(En="\n"+En),An&&(En=J(En,Kt," "),En=J(En,qt," "),En=J(En,Jt," ")),Oe&&Qn?Oe.createHTML(En):En},Ne.setConfig=function(Pt){gr(Pt),sr=!0},Ne.clearConfig=function(){Po=null,sr=!1},Ne.isValidAttribute=function(Pt,Ee,rt){Po||gr({});var mt=Zn(Pt),Yt=Zn(Ee);return yo(mt,Yt,rt)},Ne.addHook=function(Pt,Ee){typeof Ee=="function"&&(Bt[Pt]=Bt[Pt]||[],L(Bt[Pt],Ee))},Ne.removeHook=function(Pt){if(Bt[Pt])return b(Bt[Pt])},Ne.removeHooks=function(Pt){Bt[Pt]&&(Bt[Pt]=[])},Ne.removeAllHooks=function(){Bt={}},Ne}var $e=Ge();return $e})},20878:function(m){function y(f,p){return p!=null&&typeof Symbol!="undefined"&&p[Symbol.hasInstance]?!!p[Symbol.hasInstance](f):f instanceof p}var n=typeof Element!="undefined",i=typeof Map=="function",u=typeof Set=="function",s=typeof ArrayBuffer=="function"&&!!ArrayBuffer.isView;function d(f,p){if(f===p)return!0;if(f&&p&&typeof f=="object"&&typeof p=="object"){if(f.constructor!==p.constructor)return!1;var x,g,S;if(Array.isArray(f)){if(x=f.length,x!=p.length)return!1;for(g=x;g--!==0;)if(!d(f[g],p[g]))return!1;return!0}var E;if(i&&y(f,Map)&&y(p,Map)){if(f.size!==p.size)return!1;for(E=f.entries();!(g=E.next()).done;)if(!p.has(g.value[0]))return!1;for(E=f.entries();!(g=E.next()).done;)if(!d(g.value[1],p.get(g.value[0])))return!1;return!0}if(u&&y(f,Set)&&y(p,Set)){if(f.size!==p.size)return!1;for(E=f.entries();!(g=E.next()).done;)if(!p.has(g.value[0]))return!1;return!0}if(s&&ArrayBuffer.isView(f)&&ArrayBuffer.isView(p)){if(x=f.length,x!=p.length)return!1;for(g=x;g--!==0;)if(f[g]!==p[g])return!1;return!0}if(f.constructor===RegExp)return f.source===p.source&&f.flags===p.flags;if(f.valueOf!==Object.prototype.valueOf&&typeof f.valueOf=="function"&&typeof p.valueOf=="function")return f.valueOf()===p.valueOf();if(f.toString!==Object.prototype.toString&&typeof f.toString=="function"&&typeof p.toString=="function")return f.toString()===p.toString();if(S=Object.keys(f),x=S.length,x!==Object.keys(p).length)return!1;for(g=x;g--!==0;)if(!Object.prototype.hasOwnProperty.call(p,S[g]))return!1;if(n&&y(f,Element))return!1;for(g=x;g--!==0;)if(!((S[g]==="_owner"||S[g]==="__v"||S[g]==="__o")&&f.$$typeof)&&!d(f[S[g]],p[S[g]]))return!1;return!0}return f!==f&&p!==p}m.exports=function(p,x){try{return d(p,x)}catch(g){if((g.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw g}}},5139:function(m,y,n){"use strict";/** + */function u(e,t){return t!=null&&typeof Symbol!="undefined"&&t[Symbol.hasInstance]?!!t[Symbol.hasInstance](e):e instanceof t}function s(e){"@swc/helpers - typeof";return e&&typeof Symbol!="undefined"&&e.constructor===Symbol?"symbol":typeof e}var d=n(28277),f=n(9359);function p(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,r=1;rt}return!1}function U(e,t,r,a,l,v,P){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=a,this.attributeNamespace=l,this.mustUseProperty=r,this.propertyName=e,this.type=t,this.sanitizeURL=v,this.removeEmptyString=P}var z={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){z[e]=new U(e,0,!1,e,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];z[t]=new U(t,1,!1,e[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){z[e]=new U(e,2,!1,e.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){z[e]=new U(e,2,!1,e,null,!1,!1)}),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){z[e]=new U(e,3,!1,e.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(e){z[e]=new U(e,3,!0,e,null,!1,!1)}),["capture","download"].forEach(function(e){z[e]=new U(e,4,!1,e,null,!1,!1)}),["cols","rows","size","span"].forEach(function(e){z[e]=new U(e,6,!1,e,null,!1,!1)}),["rowSpan","start"].forEach(function(e){z[e]=new U(e,5,!1,e.toLowerCase(),null,!1,!1)});var D=/[\-:]([a-z])/g;function b(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(D,b);z[t]=new U(t,1,!1,e,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(D,b);z[t]=new U(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(D,b);z[t]=new U(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(e){z[e]=new U(e,1,!1,e.toLowerCase(),null,!1,!1)}),z.xlinkHref=new U("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(e){z[e]=new U(e,1,!1,e.toLowerCase(),null,!0,!0)});function L(e,t,r,a){var l=z.hasOwnProperty(t)?z[t]:null;(l!==null?l.type!==0:a||!(2k||l[P]!==v[k]){var Q="\n"+l[P].replace(" at new "," at ");return e.displayName&&Q.includes("")&&(Q=Q.replace("",e.displayName)),Q}while(1<=P&&0<=k);break}}}finally{xe=!1,Error.prepareStackTrace=r}return(e=e?e.displayName||e.name:"")?ye(e):""}function Pe(e){switch(e.tag){case 5:return ye(e.type);case 16:return ye("Lazy");case 13:return ye("Suspense");case 19:return ye("SuspenseList");case 0:case 2:case 15:return e=Ae(e.type,!1),e;case 11:return e=Ae(e.type.render,!1),e;case 1:return e=Ae(e.type,!0),e;default:return""}}function me(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case J:return"Fragment";case G:return"Portal";case Z:return"Profiler";case oe:return"StrictMode";case ce:return"Suspense";case q:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case te:return(e.displayName||"Context")+".Consumer";case ne:return(e._context.displayName||"Context")+".Provider";case pe:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case K:return t=e.displayName||null,t!==null?t:me(e.type)||"Memo";case _:t=e._payload,e=e._init;try{return me(e(t))}catch(r){}}return null}function Ye(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return me(t);case 8:return t===oe?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Qe(e){switch(typeof e=="undefined"?"undefined":s(e)){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function yt(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function ut(e){var t=yt(e)?"checked":"value",r=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),a=""+e[t];if(!e.hasOwnProperty(t)&&typeof r!="undefined"&&typeof r.get=="function"&&typeof r.set=="function"){var l=r.get,v=r.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(k){a=""+k,v.call(this,k)}}),Object.defineProperty(e,t,{enumerable:r.enumerable}),{getValue:function(){return a},setValue:function(k){a=""+k},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Ie(e){e._valueTracker||(e._valueTracker=ut(e))}function De(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var r=t.getValue(),a="";return e&&(a=yt(e)?e.checked?"true":"false":e.value),e=a,e!==r?(t.setValue(e),!0):!1}function be(e){if(e=e||(typeof document!="undefined"?document:void 0),typeof e=="undefined")return null;try{return e.activeElement||e.body}catch(t){return e.body}}function Xe(e,t){var r=t.checked;return he({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:r!=null?r:e._wrapperState.initialChecked})}function lt(e,t){var r=t.defaultValue==null?"":t.defaultValue,a=t.checked!=null?t.checked:t.defaultChecked;r=Qe(t.value!=null?t.value:r),e._wrapperState={initialChecked:a,initialValue:r,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function tt(e,t){t=t.checked,t!=null&&L(e,"checked",t,!1)}function ct(e,t){tt(e,t);var r=Qe(t.value),a=t.type;if(r!=null)a==="number"?(r===0&&e.value===""||e.value!=r)&&(e.value=""+r):e.value!==""+r&&(e.value=""+r);else if(a==="submit"||a==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Ue(e,t.type,r):t.hasOwnProperty("defaultValue")&&Ue(e,t.type,Qe(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function qe(e,t,r){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var a=t.type;if(!(a!=="submit"&&a!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,r||t===e.value||(e.value=t),e.defaultValue=t}r=e.name,r!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,r!==""&&(e.name=r)}function Ue(e,t,r){(t!=="number"||be(e.ownerDocument)!==e)&&(r==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+r&&(e.defaultValue=""+r))}var Ge=Array.isArray;function $e(e,t,r,a){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=Wt.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function et(e,t){if(t){var r=e.firstChild;if(r&&r===e.lastChild&&r.nodeType===3){r.nodeValue=t;return}}e.textContent=t}var He={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Ft=["Webkit","ms","Moz","O"];Object.keys(He).forEach(function(e){Ft.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),He[t]=He[e]})});function Ut(e,t,r){return t==null||typeof t=="boolean"||t===""?"":r||typeof t!="number"||t===0||He.hasOwnProperty(e)&&He[e]?(""+t).trim():t+"px"}function fn(e,t){e=e.style;for(var r in t)if(t.hasOwnProperty(r)){var a=r.indexOf("--")===0,l=Ut(r,t[r],a);r==="float"&&(r="cssFloat"),a?e.setProperty(r,l):e[r]=l}}var gn=he({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function $n(e,t){if(t){if(gn[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(p(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(p(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(p(61))}if(t.style!=null&&typeof t.style!="object")throw Error(p(62))}}function Xn(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Lr=null;function le(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var we=null,ge=null,Oe=null;function Fe(e){if(e=Ei(e)){if(typeof we!="function")throw Error(p(280));var t=e.stateNode;t&&(t=va(t),we(e.stateNode,e.type,t))}}function Ve(e){ge?Oe?Oe.push(e):Oe=[e]:ge=e}function pt(){if(ge){var e=ge,t=Oe;if(Oe=ge=null,Fe(e),t)for(e=0;e>>=0,e===0?32:31-(Co(e)/qo|0)|0}var wn=64,Pr=4194304;function mr(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function pi(e,t){var r=e.pendingLanes;if(r===0)return 0;var a=0,l=e.suspendedLanes,v=e.pingedLanes,P=r&268435455;if(P!==0){var k=P&~l;k!==0?a=mr(k):(v&=P,v!==0&&(a=mr(v)))}else P=r&~l,P!==0?a=mr(P):v!==0&&(a=mr(v));if(a===0)return 0;if(t!==0&&t!==a&&!(t&l)&&(l=a&-a,v=t&-t,l>=v||l===16&&(v&4194240)!==0))return t;if(a&4&&(a|=r&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=a;0r;r++)t.push(e);return t}function Ar(e,t,r){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-cr(t),e[t]=r}function Jr(e,t){var r=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var a=e.eventTimes;for(e=e.expirationTimes;0=ja),ts=" ",ju=!1;function ns(e,t){switch(e){case"keyup":return pl.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function xi(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var iu=!1;function Wc(e,t){switch(e){case"compositionend":return xi(t);case"keypress":return t.which!==32?null:(ju=!0,ts);case"textInput":return e=t.data,e===ts&&ju?null:e;default:return null}}function Di(e,t){if(iu)return e==="compositionend"||!ni&&ns(e,t)?(e=ti(),Hn=Kn=xn=null,iu=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:r,offset:t-e};e=a}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=uu(r)}}function yl(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?yl(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function xl(){for(var e=window,t=be();u(t,e.HTMLIFrameElement);){try{var r=typeof t.contentWindow.location.href=="string"}catch(a){r=!1}if(r)e=t.contentWindow;else break;t=be(e.document)}return t}function zu(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Vc(e){var t=xl(),r=e.focusedElem,a=e.selectionRange;if(t!==r&&r&&r.ownerDocument&&yl(r.ownerDocument.documentElement,r)){if(a!==null&&zu(r)){if(t=a.start,e=a.end,e===void 0&&(e=t),"selectionStart"in r)r.selectionStart=t,r.selectionEnd=Math.min(e,r.value.length);else if(e=(t=r.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=r.textContent.length,v=Math.min(a.start,l);a=a.end===void 0?v:Math.min(a.end,l),!e.extend&&v>a&&(l=a,a=v,v=l),l=gl(r,v);var P=gl(r,a);l&&P&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==P.node||e.focusOffset!==P.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),v>a?(e.addRange(t),e.extend(P.node,P.offset)):(t.setEnd(P.node,P.offset),e.addRange(t)))}}for(t=[],e=r;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof r.focus=="function"&&r.focus(),r=0;r=document.documentMode,ri=null,Ba=null,ba=null,Sl=!1;function Uu(e,t,r){var a=r.window===r?r.document:r.nodeType===9?r:r.ownerDocument;Sl||ri==null||ri!==be(a)||(a=ri,"selectionStart"in a&&zu(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),ba&&Bi(ba,a)||(ba=a,a=Ro(Ba,"onSelect"),0No||(e.current=Oi[No],Oi[No]=null,No--)}function vn(e,t){No++,Oi[No]=e.current,e.current=t}var zn={},Tn=mn(zn),xr=mn(!1),Ur=zn;function Sr(e,t){var r=e.type.contextTypes;if(!r)return zn;var a=e.stateNode;if(a&&a.__reactInternalMemoizedUnmaskedChildContext===t)return a.__reactInternalMemoizedMaskedChildContext;var l={},v;for(v in r)l[v]=t[v];return a&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function kr(e){return e=e.childContextTypes,e!=null}function Wa(){zt(xr),zt(Tn)}function hu(e,t,r){if(Tn.current!==zn)throw Error(p(168));vn(Tn,t),vn(xr,r)}function mu(e,t,r){var a=e.stateNode;if(t=t.childContextTypes,typeof a.getChildContext!="function")return r;a=a.getChildContext();for(var l in a)if(!(l in t))throw Error(p(108,Ye(e)||"Unknown",l));return he({},r,a)}function gu(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||zn,Ur=Tn.current,vn(Tn,e),vn(xr,xr.current),!0}function Mo(e,t,r){var a=e.stateNode;if(!a)throw Error(p(169));r?(e=mu(e,t,Ur),a.__reactInternalMemoizedMergedChildContext=e,zt(xr),zt(Tn),vn(Tn,e)):zt(xr),vn(xr,r)}var jo=null,pa=!1,Cl=!1;function yu(e){jo===null?jo=[e]:jo.push(e)}function Ti(e){pa=!0,yu(e)}function no(){if(!Cl&&jo!==null){Cl=!0;var e=0,t=un;try{var r=jo;for(un=1;e>=P,l-=P,Wr=1<<32-cr(t)+l|r<Nt?(Ht=it,it=null):Ht=it.sibling;var on=Re(Y,it,se[Nt],Le);if(on===null){it===null&&(it=Ht);break}e&&it&&on.alternate===null&&t(Y,it),X=v(on,X,Nt),nt===null?Je=on:nt.sibling=on,nt=on,it=Ht}if(Nt===se.length)return r(Y,it),pn&&ma(Y,Nt),Je;if(it===null){for(;NtNt?(Ht=it,it=null):Ht=it.sibling;var eu=Re(Y,it,on.value,Le);if(eu===null){it===null&&(it=Ht);break}e&&it&&eu.alternate===null&&t(Y,it),X=v(eu,X,Nt),nt===null?Je=eu:nt.sibling=eu,nt=eu,it=Ht}if(on.done)return r(Y,it),pn&&ma(Y,Nt),Je;if(it===null){for(;!on.done;Nt++,on=se.next())on=Se(Y,on.value,Le),on!==null&&(X=v(on,X,Nt),nt===null?Je=on:nt.sibling=on,nt=on);return pn&&ma(Y,Nt),Je}for(it=a(Y,it);!on.done;Nt++,on=se.next())on=ke(it,Y,Nt,on.value,Le),on!==null&&(e&&on.alternate!==null&&it.delete(on.key===null?Nt:on.key),X=v(on,X,Nt),nt===null?Je=on:nt.sibling=on,nt=on);return e&&it.forEach(function(yf){return t(Y,yf)}),pn&&ma(Y,Nt),Je}function Ce(Y,X,se,Le){if(typeof se=="object"&&se!==null&&se.type===J&&se.key===null&&(se=se.props.children),typeof se=="object"&&se!==null){switch(se.$$typeof){case V:e:{for(var Je=se.key,nt=X;nt!==null;){if(nt.key===Je){if(Je=se.type,Je===J){if(nt.tag===7){r(Y,nt.sibling),X=l(nt,se.props.children),X.return=Y,Y=X;break e}}else if(nt.elementType===Je||typeof Je=="object"&&Je!==null&&Je.$$typeof===_&&ga(Je)===nt.type){r(Y,nt.sibling),X=l(nt,se.props),X.ref=To(Y,nt,se),X.return=Y,Y=X;break e}r(Y,nt);break}else t(Y,nt);nt=nt.sibling}se.type===J?(X=qi(se.props.children,Y.mode,Le,se.key),X.return=Y,Y=X):(Le=Ji(se.type,se.key,se.props,null,Y.mode,Le),Le.ref=To(Y,X,se),Le.return=Y,Y=Le)}return P(Y);case G:e:{for(nt=se.key;X!==null;){if(X.key===nt)if(X.tag===4&&X.stateNode.containerInfo===se.containerInfo&&X.stateNode.implementation===se.implementation){r(Y,X.sibling),X=l(X,se.children||[]),X.return=Y,Y=X;break e}else{r(Y,X);break}else t(Y,X);X=X.sibling}X=Dc(se,Y.mode,Le),X.return=Y,Y=X}return P(Y);case _:return nt=se._init,Ce(Y,X,nt(se._payload),Le)}if(Ge(se))return Ke(Y,X,se,Le);if(ae(se))return gt(Y,X,se,Le);Lo(Y,se)}return typeof se=="string"&&se!==""||typeof se=="number"?(se=""+se,X!==null&&X.tag===6?(r(Y,X.sibling),X=l(X,se),X.return=Y,Y=X):(r(Y,X),X=$l(se,Y.mode,Le),X.return=Y,Y=X),P(Y)):r(Y,X)}return Ce}var Io=ui(!0),Ki=ui(!1),io={},Vr=mn(io),Ii=mn(io),Do=mn(io);function wi(e){if(e===io)throw Error(p(174));return e}function Hi(e,t){switch(vn(Do,t),vn(Ii,e),vn(Vr,io),e=t.nodeType,e){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:bt(null,"");break;default:e=e===8?t.parentNode:t,t=e.namespaceURI||null,e=e.tagName,t=bt(t,e)}zt(Vr),vn(Vr,t)}function Gi(){zt(Vr),zt(Ii),zt(Do)}function Su(e){wi(Do.current);var t=wi(Vr.current),r=bt(t,e.type);t!==r&&(vn(Ii,e),vn(Vr,r))}function Dn(e){Ii.current===e&&(zt(Vr),zt(Ii))}var Nn=mn(0);function Fo(e){for(var t=e;t!==null;){if(t.tag===13){var r=t.memoizedState;if(r!==null&&(r=r.dehydrated,r===null||r.data==="$?"||r.data==="$!"))return t}else if(t.tag===19&&t.memoizedProps.revealOrder!==void 0){if(t.flags&128)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var Yi=[];function ya(){for(var e=0;er?r:4,e(!0);var a=Jo.transition;Jo.transition={};try{e(!1),t()}finally{un=r,Jo.transition=a}}function Gc(){return uo().memoizedState}function cf(e,t,r){var a=Qr(e);if(r={lane:a,action:r,hasEagerState:!1,eagerState:null,next:null},cc(e))fc(t,r);else if(r=At(e,t,r,a),r!==null){var l=vr();_n(r,e,a,l),Dl(r,t,a)}}function Yc(e,t,r){var a=Qr(e),l={lane:a,action:r,hasEagerState:!1,eagerState:null,next:null};if(cc(e))fc(t,l);else{var v=e.alternate;if(e.lanes===0&&(v===null||v.lanes===0)&&(v=t.lastRenderedReducer,v!==null))try{var P=t.lastRenderedState,k=v(P,r);if(l.hasEagerState=!0,l.eagerState=k,dr(k,P)){var Q=t.interleaved;Q===null?(l.next=l,Lt(t)):(l.next=Q.next,Q.next=l),t.interleaved=l;return}}catch(ie){}finally{}r=At(e,t,l,a),r!==null&&(l=vr(),_n(r,e,a,l),Dl(r,t,a))}}function cc(e){var t=e.alternate;return e===Qt||t!==null&&t===Qt}function fc(e,t){Sa=Ka=!0;var r=e.pending;r===null?t.next=t:(t.next=r.next,r.next=t),e.pending=t}function Dl(e,t,r){if(r&4194240){var a=t.lanes;a&=e.pendingLanes,r|=a,t.lanes=r,tn(e,r)}}var ms={readContext:Ot,useCallback:Kr,useContext:Kr,useEffect:Kr,useImperativeHandle:Kr,useInsertionEffect:Kr,useLayoutEffect:Kr,useMemo:Kr,useReducer:Kr,useRef:Kr,useState:Kr,useDebugValue:Kr,useDeferredValue:Kr,useTransition:Kr,useMutableSource:Kr,useSyncExternalStore:Kr,useId:Kr,unstable_isNewReconciler:!1},ff={readContext:Ot,useCallback:function(t,r){return Er().memoizedState=[t,r===void 0?null:r],t},useContext:Ot,useEffect:ds,useImperativeHandle:function(t,r,a){return a=a!=null?a.concat([t]):null,Ou(4194308,4,uc.bind(null,r,t),a)},useLayoutEffect:function(t,r){return Ou(4194308,4,t,r)},useInsertionEffect:function(t,r){return Ou(4,2,t,r)},useMemo:function(t,r){var a=Er();return r=r===void 0?null:r,t=t(),a.memoizedState=[t,r],t},useReducer:function(t,r,a){var l=Er();return r=a!==void 0?a(r):r,l.memoizedState=l.baseState=r,t={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:t,lastRenderedState:r},l.queue=t,t=t.dispatch=cf.bind(null,Qt,t),[l.memoizedState,t]},useRef:function(t){var r=Er();return t={current:t},r.memoizedState=t},useState:Ku,useDebugValue:hs,useDeferredValue:function(t){return Er().memoizedState=t},useTransition:function(){var t=Ku(!1),r=t[0];return t=Hc.bind(null,t[1]),Er().memoizedState=t,[r,t]},useMutableSource:function(){},useSyncExternalStore:function(t,r,a){var l=Qt,v=Er();if(pn){if(a===void 0)throw Error(p(407));a=a()}else{if(a=r(),cn===null)throw Error(p(349));Sn&30||ec(l,r,a)}v.memoizedState=a;var P={value:a,getSnapshot:r};return v.queue=P,ds(nc.bind(null,l,P,t),[t]),l.flags|=2048,Hu(9,tc.bind(null,l,P,a,r),void 0,null),a},useId:function(){var t=Er(),r=cn.identifierPrefix;if(pn){var a=Nr,l=Wr;a=(l&~(1<<32-cr(l)-1)).toString(32)+a,r=":"+r+"R"+a,a=Al++,0<\/script>",e=e.removeChild(e.firstChild)):typeof a.is=="string"?e=P.createElement(r,{is:a.is}):(e=P.createElement(r),r==="select"&&(P=e,a.multiple?P.multiple=!0:a.size&&(P.size=a.size))):e=P.createElementNS(e,r),e[zr]=t,e[So]=a,Ps(e,t,!1,!1),t.stateNode=e;e:{switch(P=Xn(r,a),r){case"dialog":Cn("cancel",e),Cn("close",e),l=a;break;case"iframe":case"object":case"embed":Cn("load",e),l=a;break;case"video":case"audio":for(l=0;lzo&&(t.flags|=128,a=!0,Cr(v,!1),t.lanes=4194304)}else{if(!a)if(e=Fo(P),e!==null){if(t.flags|=128,a=!0,r=e.updateQueue,r!==null&&(t.updateQueue=r,t.flags|=4),Cr(v,!0),v.tail===null&&v.tailMode==="hidden"&&!P.alternate&&!pn)return so(t),null}else 2*sn()-v.renderingStartTime>zo&&r!==1073741824&&(t.flags|=128,a=!0,Cr(v,!1),t.lanes=4194304);v.isBackwards?(P.sibling=t.child,t.child=P):(r=v.last,r!==null?r.sibling=P:t.child=P,v.last=P)}return v.tail!==null?(t=v.tail,v.rendering=t,v.tail=t.sibling,v.renderingStartTime=sn(),t.sibling=null,r=Nn.current,vn(Nn,a?r&1|2:r&1),t):(so(t),null);case 22:case 23:return Ca(),a=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==a&&(t.flags|=8192),a&&t.mode&1?Gr&1073741824&&(so(t),t.subtreeFlags&6&&(t.flags|=8192)):so(t),null;case 24:return null;case 25:return null}throw Error(p(156,t.tag))}function Rs(e,t){switch(oo(t),t.tag){case 1:return kr(t.type)&&Wa(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Gi(),zt(xr),zt(Tn),ya(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return Dn(t),null;case 13:if(zt(Nn),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(p(340));ee()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return zt(Nn),null;case 4:return Gi(),null;case 10:return st(t.type._context),null;case 22:case 23:return Ca(),null;case 24:return null;default:return null}}var Mr=!1,co=!1,Ct=typeof WeakSet=="function"?WeakSet:Set,Et=null;function Ga(e,t){var r=e.ref;if(r!==null)if(typeof r=="function")try{r(null)}catch(a){pr(e,t,a)}else r.current=null}function Ns(e,t,r){try{r()}catch(a){pr(e,t,a)}}var qc=!1;function zl(e,t){if(vu=Ra,e=xl(),zu(e)){if("selectionStart"in e)var r={start:e.selectionStart,end:e.selectionEnd};else e:{r=(r=e.ownerDocument)&&r.defaultView||window;var a=r.getSelection&&r.getSelection();if(a&&a.rangeCount!==0){r=a.anchorNode;var l=a.anchorOffset,v=a.focusNode;a=a.focusOffset;try{r.nodeType,v.nodeType}catch(Le){r=null;break e}var P=0,k=-1,Q=-1,ie=0,fe=0,Se=e,Re=null;t:for(;;){for(var ke;Se!==r||l!==0&&Se.nodeType!==3||(k=P+l),Se!==v||a!==0&&Se.nodeType!==3||(Q=P+a),Se.nodeType===3&&(P+=Se.nodeValue.length),(ke=Se.firstChild)!==null;)Re=Se,Se=ke;for(;;){if(Se===e)break t;if(Re===r&&++ie===l&&(k=P),Re===v&&++fe===a&&(Q=P),(ke=Se.nextSibling)!==null)break;Se=Re,Re=Se.parentNode}Se=ke}r=k===-1||Q===-1?null:{start:k,end:Q}}else r=null}r=r||{start:0,end:0}}else r=null;for($a={focusedElem:e,selectionRange:r},Ra=!1,Et=t;Et!==null;)if(t=Et,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,Et=e;else for(;Et!==null;){t=Et;try{var Ke=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(Ke!==null){var gt=Ke.memoizedProps,Ce=Ke.memoizedState,Y=t.stateNode,X=Y.getSnapshotBeforeUpdate(t.elementType===t.type?gt:ve(t.type,gt),Ce);Y.__reactInternalSnapshotBeforeUpdate=X}break;case 3:var se=t.stateNode.containerInfo;se.nodeType===1?se.textContent="":se.nodeType===9&&se.documentElement&&se.removeChild(se.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(p(163))}}catch(Le){pr(t,t.return,Le)}if(e=t.sibling,e!==null){e.return=t.return,Et=e;break}Et=t.return}return Ke=qc,qc=!1,Ke}function Ya(e,t,r){var a=t.updateQueue;if(a=a!==null?a.lastEffect:null,a!==null){var l=a=a.next;do{if((l.tag&e)===e){var v=l.destroy;l.destroy=void 0,v!==void 0&&Ns(t,r,v)}l=l.next}while(l!==a)}}function Qu(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var r=t=t.next;do{if((r.tag&e)===e){var a=r.create;r.destroy=a()}r=r.next}while(r!==t)}}function Ms(e){var t=e.ref;if(t!==null){var r=e.stateNode;switch(e.tag){case 5:e=r;break;default:e=r}typeof t=="function"?t(e):t.current=e}}function Tc(e){var t=e.alternate;t!==null&&(e.alternate=null,Tc(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[zr],delete t[So],delete t[wl],delete t[cs],delete t[Wi])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Ic(e){return e.tag===5||e.tag===3||e.tag===4}function js(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Ic(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Ul(e,t,r){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?r.nodeType===8?r.parentNode.insertBefore(e,t):r.insertBefore(e,t):(r.nodeType===8?(t=r.parentNode,t.insertBefore(e,r)):(t=r,t.appendChild(e)),r=r._reactRootContainer,r!=null||t.onclick!==null||(t.onclick=du));else if(a!==4&&(e=e.child,e!==null))for(Ul(e,t,r),e=e.sibling;e!==null;)Ul(e,t,r),e=e.sibling}function jr(e,t,r){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?r.insertBefore(e,t):r.appendChild(e);else if(a!==4&&(e=e.child,e!==null))for(jr(e,t,r),e=e.sibling;e!==null;)jr(e,t,r),e=e.sibling}var Fn=null,Hr=!1;function Oa(e,t,r){for(r=r.child;r!==null;)wc(e,t,r),r=r.sibling}function wc(e,t,r){if(Qn&&typeof Qn.onCommitFiberUnmount=="function")try{Qn.onCommitFiberUnmount(Vn,r)}catch(k){}switch(r.tag){case 5:co||Ga(r,t);case 6:var a=Fn,l=Hr;Fn=null,Oa(e,t,r),Fn=a,Hr=l,Fn!==null&&(Hr?(e=Fn,r=r.stateNode,e.nodeType===8?e.parentNode.removeChild(r):e.removeChild(r)):Fn.removeChild(r.stateNode));break;case 18:Fn!==null&&(Hr?(e=Fn,r=r.stateNode,e.nodeType===8?Ko(e.parentNode,r):e.nodeType===1&&Ko(e,r),yo(e)):Ko(Fn,r.stateNode));break;case 4:a=Fn,l=Hr,Fn=r.stateNode.containerInfo,Hr=!0,Oa(e,t,r),Fn=a,Hr=l;break;case 0:case 11:case 14:case 15:if(!co&&(a=r.updateQueue,a!==null&&(a=a.lastEffect,a!==null))){l=a=a.next;do{var v=l,P=v.destroy;v=v.tag,P!==void 0&&(v&2||v&4)&&Ns(r,t,P),l=l.next}while(l!==a)}Oa(e,t,r);break;case 1:if(!co&&(Ga(r,t),a=r.stateNode,typeof a.componentWillUnmount=="function"))try{a.props=r.memoizedProps,a.state=r.memoizedState,a.componentWillUnmount()}catch(k){pr(r,t,k)}Oa(e,t,r);break;case 21:Oa(e,t,r);break;case 22:r.mode&1?(co=(a=co)||r.memoizedState!==null,Oa(e,t,r),co=a):Oa(e,t,r);break;default:Oa(e,t,r)}}function ci(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var r=e.stateNode;r===null&&(r=e.stateNode=new Ct),t.forEach(function(a){var l=of.bind(null,e,a);r.has(a)||(r.add(a),a.then(l,l))})}}function fi(e,t){var r=t.deletions;if(r!==null)for(var a=0;al&&(l=P),a&=~v}if(a=l,a=sn()-a,a=(120>a?120:480>a?480:1080>a?1080:1920>a?1920:3e3>a?3e3:4320>a?4320:1960*Ls(a/1960))-a,10e?16:e,Ni===null)var a=!1;else{if(e=Ni,Ni=null,Qa=0,$t&6)throw Error(p(331));var l=$t;for($t|=4,Et=e.current;Et!==null;){var v=Et,P=v.child;if(Et.flags&16){var k=v.deletions;if(k!==null){for(var Q=0;Qsn()-Xa?Ja(e,0):Tu|=r),wo(e,t)}function rf(e,t){t===0&&(e.mode&1?(t=Pr,Pr<<=1,!(Pr&130023424)&&(Pr=4194304)):t=1);var r=vr();e=Tt(e,t),e!==null&&(Ar(e,t,r),wo(e,r))}function hf(e){var t=e.memoizedState,r=0;t!==null&&(r=t.retryLane),rf(e,r)}function of(e,t){var r=0;switch(e.tag){case 13:var a=e.stateNode,l=e.memoizedState;l!==null&&(r=l.retryLane);break;case 19:a=e.stateNode;break;default:throw Error(p(314))}a!==null&&a.delete(t),rf(e,r)}var jc;jc=function(t,r,a){if(t!==null)if(t.memoizedProps!==r.pendingProps||xr.current)Mn=!0;else{if(!(t.lanes&a)&&!(r.flags&128))return Mn=!1,Jc(t,r,a);Mn=!!(t.flags&131072)}else Mn=!1,pn&&r.flags&1048576&&Pl(r,$r,r.index);switch(r.lanes=0,r.tag){case 2:var l=r.type;si(t,r),t=r.pendingProps;var v=Sr(r,Tn.current);vt(r,a),v=Nl(null,r,l,t,v,a);var P=li();return r.flags|=1,typeof v=="object"&&v!==null&&typeof v.render=="function"&&v.$$typeof===void 0?(r.tag=1,r.memoizedState=null,r.updateQueue=null,kr(l)?(P=!0,gu(r)):P=!1,r.memoizedState=v.state!==null&&v.state!==void 0?v.state:null,Xt(r),v.updater=Oo,r.stateNode=v,v._reactInternals=r,ai(r,l,t,a),r=Ss(null,r,l,!0,P,a)):(r.tag=0,pn&&P&&Vu(r),lo(null,r,v,a),r=r.child),r;case 16:l=r.elementType;e:{switch(si(t,r),t=r.pendingProps,v=l._init,l=v(l._payload),r.type=l,v=r.tag=_a(l),t=ve(l,t),v){case 0:r=ys(null,r,l,t,a);break e;case 1:r=xs(null,r,l,t,a);break e;case 11:r=gc(null,r,l,t,a);break e;case 14:r=yc(null,r,l,ve(l.type,t),a);break e}throw Error(p(306,l,""))}return r;case 0:return l=r.type,v=r.pendingProps,v=r.elementType===l?v:ve(l,v),ys(t,r,l,v,a);case 1:return l=r.type,v=r.pendingProps,v=r.elementType===l?v:ve(l,v),xs(t,r,l,v,a);case 3:e:{if(Ec(r),t===null)throw Error(p(387));l=r.pendingProps,P=r.memoizedState,v=P.element,Mt(t,r),kn(r,l,null,a);var k=r.memoizedState;if(l=k.element,P.isDehydrated)if(P={element:l,isDehydrated:!1,cache:k.cache,pendingSuspenseBoundaries:k.pendingSuspenseBoundaries,transitions:k.transitions},r.updateQueue.baseState=P,r.memoizedState=P,r.flags&256){v=Ha(Error(p(423)),r),r=Es(t,r,l,a,v);break e}else if(l!==v){v=Ha(Error(p(424)),r),r=Es(t,r,l,a,v);break e}else for(nn=Ho(r.stateNode.containerInfo.firstChild),Un=r,pn=!0,Qo=null,a=Ki(r,null,l,a),r.child=a;a;)a.flags=a.flags&-3|4096,a=a.sibling;else{if(ee(),l===v){r=Ea(t,r,a);break e}lo(t,r,l,a)}r=r.child}return r;case 5:return Su(r),t===null&&N(r),l=r.type,v=r.pendingProps,P=t!==null?t.memoizedProps:null,k=v.children,fa(l,v)?k=null:P!==null&&fa(l,P)&&(r.flags|=32),gs(t,r),lo(t,r,k,a),r.child;case 6:return t===null&&N(r),null;case 13:return Ts(t,r,a);case 4:return Hi(r,r.stateNode.containerInfo),l=r.pendingProps,t===null?r.child=Io(r,null,l,a):lo(t,r,l,a),r.child;case 11:return l=r.type,v=r.pendingProps,v=r.elementType===l?v:ve(l,v),gc(t,r,l,v,a);case 7:return lo(t,r,r.pendingProps,a),r.child;case 8:return lo(t,r,r.pendingProps.children,a),r.child;case 12:return lo(t,r,r.pendingProps.children,a),r.child;case 10:e:{if(l=r.type._context,v=r.pendingProps,P=r.memoizedProps,k=v.value,vn(Be,l._currentValue),l._currentValue=k,P!==null)if(dr(P.value,k)){if(P.children===v.children&&!xr.current){r=Ea(t,r,a);break e}}else for(P=r.child,P!==null&&(P.return=r);P!==null;){var Q=P.dependencies;if(Q!==null){k=P.child;for(var ie=Q.firstContext;ie!==null;){if(ie.context===l){if(P.tag===1){ie=It(-1,a&-a),ie.tag=2;var fe=P.updateQueue;if(fe!==null){fe=fe.shared;var Se=fe.pending;Se===null?ie.next=ie:(ie.next=Se.next,Se.next=ie),fe.pending=ie}}P.lanes|=a,ie=P.alternate,ie!==null&&(ie.lanes|=a),ft(P.return,a,r),Q.lanes|=a;break}ie=ie.next}}else if(P.tag===10)k=P.type===r.type?null:P.child;else if(P.tag===18){if(k=P.return,k===null)throw Error(p(341));k.lanes|=a,Q=k.alternate,Q!==null&&(Q.lanes|=a),ft(k,a,r),k=P.sibling}else k=P.child;if(k!==null)k.return=P;else for(k=P;k!==null;){if(k===r){k=null;break}if(P=k.sibling,P!==null){P.return=k.return,k=P;break}k=k.return}P=k}lo(t,r,v.children,a),r=r.child}return r;case 9:return v=r.type,l=r.pendingProps.children,vt(r,a),v=Ot(v),l=l(v),r.flags|=1,lo(t,r,l,a),r.child;case 14:return l=r.type,v=ve(l,r.pendingProps),v=ve(l.type,v),yc(t,r,l,v,a);case 15:return xc(t,r,r.type,r.pendingProps,a);case 17:return l=r.type,v=r.pendingProps,v=r.elementType===l?v:ve(l,v),si(t,r),r.tag=1,kr(l)?(t=!0,gu(r)):t=!1,vt(r,a),xu(r,l,v),ai(r,l,v,a),Ss(null,r,l,!0,t,a);case 19:return bl(t,r,a);case 22:return Sc(t,r,a)}throw Error(p(156,r.tag))};function af(e,t){return lr(e,t)}function vi(e,t,r,a){this.tag=e,this.key=r,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=a,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Uo(e,t,r,a){return new vi(e,t,r,a)}function Lc(e){return e=e.prototype,!(!e||!e.isReactComponent)}function _a(e){if(typeof e=="function")return Lc(e)?1:0;if(e!=null){if(e=e.$$typeof,e===pe)return 11;if(e===K)return 14}return 2}function Mi(e,t){var r=e.alternate;return r===null?(r=Uo(e.tag,t,e.key,e.mode),r.elementType=e.elementType,r.type=e.type,r.stateNode=e.stateNode,r.alternate=e,e.alternate=r):(r.pendingProps=t,r.type=e.type,r.flags=0,r.subtreeFlags=0,r.deletions=null),r.flags=e.flags&14680064,r.childLanes=e.childLanes,r.lanes=e.lanes,r.child=e.child,r.memoizedProps=e.memoizedProps,r.memoizedState=e.memoizedState,r.updateQueue=e.updateQueue,t=e.dependencies,r.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},r.sibling=e.sibling,r.index=e.index,r.ref=e.ref,r}function Ji(e,t,r,a,l,v){var P=2;if(a=e,typeof e=="function")Lc(e)&&(P=1);else if(typeof e=="string")P=5;else e:switch(e){case J:return qi(r.children,l,v,t);case oe:P=8,l|=8;break;case Z:return e=Uo(12,r,t,l|2),e.elementType=Z,e.lanes=v,e;case ce:return e=Uo(13,r,t,l),e.elementType=ce,e.lanes=v,e;case q:return e=Uo(19,r,t,l),e.elementType=q,e.lanes=v,e;case W:return nl(r,l,v,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case ne:P=10;break e;case te:P=9;break e;case pe:P=11;break e;case K:P=14;break e;case _:P=16,a=null;break e}throw Error(p(130,e==null?e:typeof e=="undefined"?"undefined":s(e),""))}return t=Uo(P,r,t,l),t.elementType=e,t.type=a,t.lanes=v,t}function qi(e,t,r,a){return e=Uo(7,e,a,t),e.lanes=r,e}function nl(e,t,r,a){return e=Uo(22,e,a,t),e.elementType=W,e.lanes=r,e.stateNode={isHidden:!1},e}function $l(e,t,r){return e=Uo(6,e,null,t),e.lanes=r,e}function Dc(e,t,r){return t=Uo(4,e.children!==null?e.children:[],e.key,t),t.lanes=r,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Fc(e,t,r,a,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=tr(0),this.expirationTimes=tr(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=tr(0),this.identifierPrefix=a,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Bc(e,t,r,a,l,v,P,k,Q){return e=new Fc(e,t,r,k,Q),t===1?(t=1,v===!0&&(t|=8)):t=0,v=Uo(3,null,null,t),e.current=v,v.stateNode=e,v.memoizedState={element:a,isDehydrated:r,cache:null,transitions:null,pendingSuspenseBoundaries:null},Xt(v),e}function uf(e,t,r){var a=3Me.length)&&(Ne=Me.length);for(var We=0,_e=new Array(Ne);We1?We-1:0),xt=1;xt/gm),ut=j(/\${[\w\W]*}/gm),Ie=j(/^data-[\-\w.\u00B7-\uFFFF]/),De=j(/^aria-[\-\w]+$/),be=j(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Xe=j(/^(?:\w+script|data):/i),lt=j(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),tt=j(/^html$/i),ct=j(/^[a-z][.\w]*(-[.\w]+)+$/i),qe=function(){return typeof window=="undefined"?null:window},Ue=function(Ne,We){if(n(Ne)!=="object"||typeof Ne.createPolicy!="function")return null;var _e=null,xt="data-tt-policy-suffix";We.currentScript&&We.currentScript.hasAttribute(xt)&&(_e=We.currentScript.getAttribute(xt));var bt="dompurify"+(_e?"#"+_e:"");try{return Ne.createPolicy(bt,{createHTML:function(St){return St},createScriptURL:function(St){return St}})}catch(Wt){return console.warn("TrustedTypes policy "+bt+" could not be created."),null}};function Ge(){var Me=arguments.length>0&&arguments[0]!==void 0?arguments[0]:qe(),Ne=function(Ee){return Ge(Ee)};if(Ne.version="2.5.0",Ne.removed=[],!Me||!Me.document||Me.document.nodeType!==9)return Ne.isSupported=!1,Ne;var We=Me.document,_e=Me.document,xt=Me.DocumentFragment,bt=Me.HTMLTemplateElement,Wt=Me.Node,St=Me.Element,et=Me.NodeFilter,He=Me.NamedNodeMap,Ft=He===void 0?Me.NamedNodeMap||Me.MozNamedAttrMap:He,Ut=Me.HTMLFormElement,fn=Me.DOMParser,gn=Me.trustedTypes,$n=St.prototype,Xn=_($n,"cloneNode"),Lr=_($n,"nextSibling"),le=_($n,"childNodes"),we=_($n,"parentNode");if(typeof bt=="function"){var ge=_e.createElement("template");ge.content&&ge.content.ownerDocument&&(_e=ge.content.ownerDocument)}var Oe=Ue(gn,We),Fe=Oe?Oe.createHTML(""):"",Ve=_e,pt=Ve.implementation,dt=Ve.createNodeIterator,Rt=Ve.createDocumentFragment,at=Ve.getElementsByTagName,Gt=We.importNode,Vt={};try{Vt=K(_e).documentMode?_e.documentMode:{}}catch(Pt){}var Bt={};Ne.isSupported=typeof we=="function"&&pt&&pt.createHTMLDocument!==void 0&&Vt!==9;var Kt=Qe,qt=yt,Jt=ut,kt=Ie,Wn=De,jn=Xe,ar=lt,vo=ct,jt=be,_t=null,po=q({},[].concat(d(W),d(H),d(ae),d(Te),d(xe))),yn=null,ur=q({},[].concat(d(Ae),d(Pe),d(me),d(Ye))),en=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Or=null,lr=null,eo=!0,hr=!0,ln=!1,sn=!0,An=!1,Dr=!0,er=!1,sr=!1,Fr=!1,hn=!1,Vn=!1,Qn=!1,On=!0,cr=!1,Co="user-content-",qo=!0,Tr=!1,wn={},Pr=null,mr=q({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),pi=null,hi=q({},["audio","video","img","source","image","track"]),Zr=null,mi=q({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),ko="http://www.w3.org/1998/Math/MathML",tr="http://www.w3.org/2000/svg",Ar="http://www.w3.org/1999/xhtml",Jr=Ar,tn=!1,un=null,_o=q({},[ko,tr,Ar],V),ho,Pa=["application/xhtml+xml","text/html"],tu="text/html",Zn,Po=null,ei=_e.createElement("form"),Rr=function(Ee){return y(Ee,RegExp)||y(Ee,Function)},gr=function(Ee){Po&&Po===Ee||((!Ee||n(Ee)!=="object")&&(Ee={}),Ee=K(Ee),ho=Pa.indexOf(Ee.PARSER_MEDIA_TYPE)===-1?ho=tu:ho=Ee.PARSER_MEDIA_TYPE,Zn=ho==="application/xhtml+xml"?V:F,_t="ALLOWED_TAGS"in Ee?q({},Ee.ALLOWED_TAGS,Zn):po,yn="ALLOWED_ATTR"in Ee?q({},Ee.ALLOWED_ATTR,Zn):ur,un="ALLOWED_NAMESPACES"in Ee?q({},Ee.ALLOWED_NAMESPACES,V):_o,Zr="ADD_URI_SAFE_ATTR"in Ee?q(K(mi),Ee.ADD_URI_SAFE_ATTR,Zn):mi,pi="ADD_DATA_URI_TAGS"in Ee?q(K(hi),Ee.ADD_DATA_URI_TAGS,Zn):hi,Pr="FORBID_CONTENTS"in Ee?q({},Ee.FORBID_CONTENTS,Zn):mr,Or="FORBID_TAGS"in Ee?q({},Ee.FORBID_TAGS,Zn):{},lr="FORBID_ATTR"in Ee?q({},Ee.FORBID_ATTR,Zn):{},wn="USE_PROFILES"in Ee?Ee.USE_PROFILES:!1,eo=Ee.ALLOW_ARIA_ATTR!==!1,hr=Ee.ALLOW_DATA_ATTR!==!1,ln=Ee.ALLOW_UNKNOWN_PROTOCOLS||!1,sn=Ee.ALLOW_SELF_CLOSE_IN_ATTR!==!1,An=Ee.SAFE_FOR_TEMPLATES||!1,Dr=Ee.SAFE_FOR_XML!==!1,er=Ee.WHOLE_DOCUMENT||!1,hn=Ee.RETURN_DOM||!1,Vn=Ee.RETURN_DOM_FRAGMENT||!1,Qn=Ee.RETURN_TRUSTED_TYPE||!1,Fr=Ee.FORCE_BODY||!1,On=Ee.SANITIZE_DOM!==!1,cr=Ee.SANITIZE_NAMED_PROPS||!1,qo=Ee.KEEP_CONTENT!==!1,Tr=Ee.IN_PLACE||!1,jt=Ee.ALLOWED_URI_REGEXP||jt,Jr=Ee.NAMESPACE||Ar,en=Ee.CUSTOM_ELEMENT_HANDLING||{},Ee.CUSTOM_ELEMENT_HANDLING&&Rr(Ee.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(en.tagNameCheck=Ee.CUSTOM_ELEMENT_HANDLING.tagNameCheck),Ee.CUSTOM_ELEMENT_HANDLING&&Rr(Ee.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(en.attributeNameCheck=Ee.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),Ee.CUSTOM_ELEMENT_HANDLING&&typeof Ee.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements=="boolean"&&(en.allowCustomizedBuiltInElements=Ee.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),An&&(hr=!1),Vn&&(hn=!0),wn&&(_t=q({},d(xe)),yn=[],wn.html===!0&&(q(_t,W),q(yn,Ae)),wn.svg===!0&&(q(_t,H),q(yn,Pe),q(yn,Ye)),wn.svgFilters===!0&&(q(_t,ae),q(yn,Pe),q(yn,Ye)),wn.mathMl===!0&&(q(_t,Te),q(yn,me),q(yn,Ye))),Ee.ADD_TAGS&&(_t===po&&(_t=K(_t)),q(_t,Ee.ADD_TAGS,Zn)),Ee.ADD_ATTR&&(yn===ur&&(yn=K(yn)),q(yn,Ee.ADD_ATTR,Zn)),Ee.ADD_URI_SAFE_ATTR&&q(Zr,Ee.ADD_URI_SAFE_ATTR,Zn),Ee.FORBID_CONTENTS&&(Pr===mr&&(Pr=K(Pr)),q(Pr,Ee.FORBID_CONTENTS,Zn)),qo&&(_t["#text"]=!0),er&&q(_t,["html","head","body"]),_t.table&&(q(_t,["tbody"]),delete Or.tbody),R&&R(Ee),Po=Ee)},fr=q({},["mi","mo","mn","ms","mtext"]),Br=q({},["foreignobject","desc","title","annotation-xml"]),$o=q({},["title","style","font","a","script"]),Bn=q({},H);q(Bn,ae),q(Bn,he);var mo=q({},Te);q(mo,ye);var nu=function(Ee){var rt=we(Ee);(!rt||!rt.tagName)&&(rt={namespaceURI:Jr,tagName:"template"});var mt=F(Ee.tagName),Yt=F(rt.tagName);return un[Ee.namespaceURI]?Ee.namespaceURI===tr?rt.namespaceURI===Ar?mt==="svg":rt.namespaceURI===ko?mt==="svg"&&(Yt==="annotation-xml"||fr[Yt]):!!Bn[mt]:Ee.namespaceURI===ko?rt.namespaceURI===Ar?mt==="math":rt.namespaceURI===tr?mt==="math"&&Br[Yt]:!!mo[mt]:Ee.namespaceURI===Ar?rt.namespaceURI===tr&&!Br[Yt]||rt.namespaceURI===ko&&!fr[Yt]?!1:!mo[mt]&&($o[mt]||!Bn[mt]):!!(ho==="application/xhtml+xml"&&un[Ee.namespaceURI]):!1},bn=function(Ee){L(Ne.removed,{element:Ee});try{Ee.parentNode.removeChild(Ee)}catch(rt){try{Ee.outerHTML=Fe}catch(mt){Ee.remove()}}},go=function(Ee,rt){try{L(Ne.removed,{attribute:rt.getAttributeNode(Ee),from:rt})}catch(mt){L(Ne.removed,{attribute:null,from:rt})}if(rt.removeAttribute(Ee),Ee==="is"&&!yn[Ee])if(hn||Vn)try{bn(rt)}catch(mt){}else try{rt.setAttribute(Ee,"")}catch(mt){}},Aa=function(Ee){var rt,mt;if(Fr)Ee=""+Ee;else{var Yt=G(Ee,/^[\r\n\t ]+/);mt=Yt&&Yt[0]}ho==="application/xhtml+xml"&&Jr===Ar&&(Ee=''+Ee+"");var xn=Oe?Oe.createHTML(Ee):Ee;if(Jr===Ar)try{rt=new fn().parseFromString(xn,ho)}catch(Hn){}if(!rt||!rt.documentElement){rt=pt.createDocument(Jr,"template",null);try{rt.documentElement.innerHTML=tn?Fe:xn}catch(Hn){}}var Kn=rt.body||rt.documentElement;return Ee&&mt&&Kn.insertBefore(_e.createTextNode(mt),Kn.childNodes[0]||null),Jr===Ar?at.call(rt,er?"html":"body")[0]:er?rt.documentElement:Kn},nr=function(Ee){return dt.call(Ee.ownerDocument||Ee,Ee,et.SHOW_ELEMENT|et.SHOW_COMMENT|et.SHOW_TEXT|et.SHOW_PROCESSING_INSTRUCTION|et.SHOW_CDATA_SECTION,null,!1)},_i=function(Ee){return y(Ee,Ut)&&(typeof Ee.nodeName!="string"||typeof Ee.textContent!="string"||typeof Ee.removeChild!="function"||!y(Ee.attributes,Ft)||typeof Ee.removeAttribute!="function"||typeof Ee.setAttribute!="function"||typeof Ee.namespaceURI!="string"||typeof Ee.insertBefore!="function"||typeof Ee.hasChildNodes!="function")},ji=function(Ee){return n(Wt)==="object"?y(Ee,Wt):Ee&&n(Ee)==="object"&&typeof Ee.nodeType=="number"&&typeof Ee.nodeName=="string"},qr=function(Ee,rt,mt){Bt[Ee]&&D(Bt[Ee],function(Yt){Yt.call(Ne,rt,mt,Po)})},Ao=function(Ee){var rt;if(qr("beforeSanitizeElements",Ee,null),_i(Ee)||ne(/[\u0080-\uFFFF]/,Ee.nodeName))return bn(Ee),!0;var mt=Zn(Ee.nodeName);if(qr("uponSanitizeElement",Ee,{tagName:mt,allowedTags:_t}),Ee.hasChildNodes()&&!ji(Ee.firstElementChild)&&(!ji(Ee.content)||!ji(Ee.content.firstElementChild))&&ne(/<[/\w]/g,Ee.innerHTML)&&ne(/<[/\w]/g,Ee.textContent)||mt==="select"&&ne(/=0;--Hn)Yt.insertBefore(Xn(xn[Hn],!0),Lr(Ee))}return bn(Ee),!0}return y(Ee,St)&&!nu(Ee)||(mt==="noscript"||mt==="noembed"||mt==="noframes")&&ne(/<\/no(script|embed|frames)/i,Ee.innerHTML)?(bn(Ee),!0):(An&&Ee.nodeType===3&&(rt=Ee.textContent,rt=J(rt,Kt," "),rt=J(rt,qt," "),rt=J(rt,Jt," "),Ee.textContent!==rt&&(L(Ne.removed,{element:Ee.cloneNode()}),Ee.textContent=rt)),qr("afterSanitizeElements",Ee,null),!1)},yo=function(Ee,rt,mt){if(On&&(rt==="id"||rt==="name")&&(mt in _e||mt in ei))return!1;if(!(hr&&!lr[rt]&&ne(kt,rt))){if(!(eo&&ne(Wn,rt))){if(!yn[rt]||lr[rt]){if(!(Wo(Ee)&&(y(en.tagNameCheck,RegExp)&&ne(en.tagNameCheck,Ee)||y(en.tagNameCheck,Function)&&en.tagNameCheck(Ee))&&(y(en.attributeNameCheck,RegExp)&&ne(en.attributeNameCheck,rt)||y(en.attributeNameCheck,Function)&&en.attributeNameCheck(rt))||rt==="is"&&en.allowCustomizedBuiltInElements&&(y(en.tagNameCheck,RegExp)&&ne(en.tagNameCheck,mt)||y(en.tagNameCheck,Function)&&en.tagNameCheck(mt))))return!1}else if(!Zr[rt]){if(!ne(jt,J(mt,ar,""))){if(!((rt==="src"||rt==="xlink:href"||rt==="href")&&Ee!=="script"&&oe(mt,"data:")===0&&pi[Ee])){if(!(ln&&!ne(jn,J(mt,ar,"")))){if(mt)return!1}}}}}}return!0},Wo=function(Ee){return Ee!=="annotation-xml"&&G(Ee,vo)},Ra=function(Ee){var rt,mt,Yt,xn;qr("beforeSanitizeAttributes",Ee,null);var Kn=Ee.attributes;if(Kn){var Hn={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:yn};for(xn=Kn.length;xn--;){rt=Kn[xn];var ti=rt,En=ti.name,gi=ti.namespaceURI;if(mt=En==="value"?rt.value:Z(rt.value),Yt=Zn(En),Hn.attrName=Yt,Hn.attrValue=mt,Hn.keepAttr=!0,Hn.forceKeepAttr=void 0,qr("uponSanitizeAttribute",Ee,Hn),mt=Hn.attrValue,!Hn.forceKeepAttr&&(go(En,Ee),!!Hn.keepAttr)){if(!sn&&ne(/\/>/i,mt)){go(En,Ee);continue}An&&(mt=J(mt,Kt," "),mt=J(mt,qt," "),mt=J(mt,Jt," "));var rr=Zn(Ee.nodeName);if(yo(rr,Yt,mt)){if(cr&&(Yt==="id"||Yt==="name")&&(go(En,Ee),mt=Co+mt),Oe&&n(gn)==="object"&&typeof gn.getAttributeType=="function"&&!gi)switch(gn.getAttributeType(rr,Yt)){case"TrustedHTML":{mt=Oe.createHTML(mt);break}case"TrustedScriptURL":{mt=Oe.createScriptURL(mt);break}}try{gi?Ee.setAttributeNS(gi,En,mt):Ee.setAttribute(En,mt),b(Ne.removed)}catch(yr){}}}}qr("afterSanitizeAttributes",Ee,null)}},Na=function Pt(Ee){var rt,mt=nr(Ee);for(qr("beforeSanitizeShadowDOM",Ee,null);rt=mt.nextNode();)qr("uponSanitizeShadowNode",rt,null),!Ao(rt)&&(y(rt.content,xt)&&Pt(rt.content),Ra(rt));qr("afterSanitizeShadowDOM",Ee,null)};return Ne.sanitize=function(Pt){var Ee=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},rt,mt,Yt,xn,Kn;if(tn=!Pt,tn&&(Pt=""),typeof Pt!="string"&&!ji(Pt))if(typeof Pt.toString=="function"){if(Pt=Pt.toString(),typeof Pt!="string")throw te("dirty is not a string, aborting")}else throw te("toString is not a function");if(!Ne.isSupported){if(n(Me.toStaticHTML)==="object"||typeof Me.toStaticHTML=="function"){if(typeof Pt=="string")return Me.toStaticHTML(Pt);if(ji(Pt))return Me.toStaticHTML(Pt.outerHTML)}return Pt}if(sr||gr(Ee),Ne.removed=[],typeof Pt=="string"&&(Tr=!1),Tr){if(Pt.nodeName){var Hn=Zn(Pt.nodeName);if(!_t[Hn]||Or[Hn])throw te("root node is forbidden and cannot be sanitized in-place")}}else if(y(Pt,Wt))rt=Aa(""),mt=rt.ownerDocument.importNode(Pt,!0),mt.nodeType===1&&mt.nodeName==="BODY"||mt.nodeName==="HTML"?rt=mt:rt.appendChild(mt);else{if(!hn&&!An&&!er&&Pt.indexOf("<")===-1)return Oe&&Qn?Oe.createHTML(Pt):Pt;if(rt=Aa(Pt),!rt)return hn?null:Qn?Fe:""}rt&&Fr&&bn(rt.firstChild);for(var ti=nr(Tr?Pt:rt);Yt=ti.nextNode();)Yt.nodeType===3&&Yt===xn||Ao(Yt)||(y(Yt.content,xt)&&Na(Yt.content),Ra(Yt),xn=Yt);if(xn=null,Tr)return Pt;if(hn){if(Vn)for(Kn=Rt.call(rt.ownerDocument);rt.firstChild;)Kn.appendChild(rt.firstChild);else Kn=rt;return(yn.shadowroot||yn.shadowrootmod)&&(Kn=Gt.call(We,Kn,!0)),Kn}var En=er?rt.outerHTML:rt.innerHTML;return er&&_t["!doctype"]&&rt.ownerDocument&&rt.ownerDocument.doctype&&rt.ownerDocument.doctype.name&&ne(tt,rt.ownerDocument.doctype.name)&&(En="\n"+En),An&&(En=J(En,Kt," "),En=J(En,qt," "),En=J(En,Jt," ")),Oe&&Qn?Oe.createHTML(En):En},Ne.setConfig=function(Pt){gr(Pt),sr=!0},Ne.clearConfig=function(){Po=null,sr=!1},Ne.isValidAttribute=function(Pt,Ee,rt){Po||gr({});var mt=Zn(Pt),Yt=Zn(Ee);return yo(mt,Yt,rt)},Ne.addHook=function(Pt,Ee){typeof Ee=="function"&&(Bt[Pt]=Bt[Pt]||[],L(Bt[Pt],Ee))},Ne.removeHook=function(Pt){if(Bt[Pt])return b(Bt[Pt])},Ne.removeHooks=function(Pt){Bt[Pt]&&(Bt[Pt]=[])},Ne.removeAllHooks=function(){Bt={}},Ne}var $e=Ge();return $e})},20878:function(m){function y(f,p){return p!=null&&typeof Symbol!="undefined"&&p[Symbol.hasInstance]?!!p[Symbol.hasInstance](f):f instanceof p}var n=typeof Element!="undefined",i=typeof Map=="function",u=typeof Set=="function",s=typeof ArrayBuffer=="function"&&!!ArrayBuffer.isView;function d(f,p){if(f===p)return!0;if(f&&p&&typeof f=="object"&&typeof p=="object"){if(f.constructor!==p.constructor)return!1;var x,g,S;if(Array.isArray(f)){if(x=f.length,x!=p.length)return!1;for(g=x;g--!==0;)if(!d(f[g],p[g]))return!1;return!0}var E;if(i&&y(f,Map)&&y(p,Map)){if(f.size!==p.size)return!1;for(E=f.entries();!(g=E.next()).done;)if(!p.has(g.value[0]))return!1;for(E=f.entries();!(g=E.next()).done;)if(!d(g.value[1],p.get(g.value[0])))return!1;return!0}if(u&&y(f,Set)&&y(p,Set)){if(f.size!==p.size)return!1;for(E=f.entries();!(g=E.next()).done;)if(!p.has(g.value[0]))return!1;return!0}if(s&&ArrayBuffer.isView(f)&&ArrayBuffer.isView(p)){if(x=f.length,x!=p.length)return!1;for(g=x;g--!==0;)if(f[g]!==p[g])return!1;return!0}if(f.constructor===RegExp)return f.source===p.source&&f.flags===p.flags;if(f.valueOf!==Object.prototype.valueOf&&typeof f.valueOf=="function"&&typeof p.valueOf=="function")return f.valueOf()===p.valueOf();if(f.toString!==Object.prototype.toString&&typeof f.toString=="function"&&typeof p.toString=="function")return f.toString()===p.toString();if(S=Object.keys(f),x=S.length,x!==Object.keys(p).length)return!1;for(g=x;g--!==0;)if(!Object.prototype.hasOwnProperty.call(p,S[g]))return!1;if(n&&y(f,Element))return!1;for(g=x;g--!==0;)if(!((S[g]==="_owner"||S[g]==="__v"||S[g]==="__o")&&f.$$typeof)&&!d(f[S[g]],p[S[g]]))return!1;return!0}return f!==f&&p!==p}m.exports=function(p,x){try{return d(p,x)}catch(g){if((g.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw g}}},5139:function(m,y,n){"use strict";/** * @license React * react-jsx-runtime.production.min.js * @@ -52,7 +52,7 @@ * @file * @copyright 2020 Aleksej Komarov * @license MIT - */var i=8,u=9,s=13,d=16,f=17,p=18,x=19,g=20,S=27,E=32,T=33,C=34,w=35,I=36,R=37,j=38,B=39,M=40,U=45,z=46,D=48,b=49,L=50,F=51,V=52,G=53,J=54,oe=55,Z=56,ne=57,te=65,pe=66,ce=67,q=68,K=69,_=70,W=71,H=72,ae=73,he=74,Te=75,ye=76,xe=77,Ae=78,Pe=79,me=80,Ye=81,Qe=82,yt=83,ut=84,Ie=85,De=86,be=87,Xe=88,lt=89,tt=90,ct=112,qe=113,Ue=114,Ge=115,$e=116,Me=117,Ne=118,We=119,_e=120,xt=121,bt=122,Wt=123,St=186,et=187,He=188,Ft=189,Ut=190,fn=191,gn=219,kn=220,Xn=221,Lr=222},87239:function(m,y,n){"use strict";n.d(y,{_:function(){return i}});var i;(function(u){u.Alt="Alt",u.Backspace="Backspace",u.Control="Control",u.Delete="Delete",u.Down="ArrowDown",u.End="End",u.Enter="Enter",u.Escape="Escape",u.Home="Home",u.Insert="Insert",u.Left="ArrowLeft",u.PageDown="PageDown",u.PageUp="PageUp",u.Right="ArrowRight",u.Shift="Shift",u.Space=" ",u.Tab="Tab",u.Up="ArrowUp"})(i||(i={}))},4089:function(m,y,n){"use strict";n.d(y,{J$:function(){return f},Mg:function(){return g},TG:function(){return E},hs:function(){return p},qE:function(){return d}});/** + */var i=8,u=9,s=13,d=16,f=17,p=18,x=19,g=20,S=27,E=32,T=33,C=34,w=35,I=36,R=37,j=38,B=39,M=40,U=45,z=46,D=48,b=49,L=50,F=51,V=52,G=53,J=54,oe=55,Z=56,ne=57,te=65,pe=66,ce=67,q=68,K=69,_=70,W=71,H=72,ae=73,he=74,Te=75,ye=76,xe=77,Ae=78,Pe=79,me=80,Ye=81,Qe=82,yt=83,ut=84,Ie=85,De=86,be=87,Xe=88,lt=89,tt=90,ct=112,qe=113,Ue=114,Ge=115,$e=116,Me=117,Ne=118,We=119,_e=120,xt=121,bt=122,Wt=123,St=186,et=187,He=188,Ft=189,Ut=190,fn=191,gn=219,$n=220,Xn=221,Lr=222},87239:function(m,y,n){"use strict";n.d(y,{_:function(){return i}});var i;(function(u){u.Alt="Alt",u.Backspace="Backspace",u.Control="Control",u.Delete="Delete",u.Down="ArrowDown",u.End="End",u.Enter="Enter",u.Escape="Escape",u.Home="Home",u.Insert="Insert",u.Left="ArrowLeft",u.PageDown="PageDown",u.PageUp="PageUp",u.Right="ArrowRight",u.Shift="Shift",u.Space=" ",u.Tab="Tab",u.Up="ArrowUp"})(i||(i={}))},4089:function(m,y,n){"use strict";n.d(y,{J$:function(){return f},Mg:function(){return g},TG:function(){return E},hs:function(){return p},qE:function(){return d}});/** * @file * @copyright 2020 Aleksej Komarov * @license MIT @@ -154,7 +154,7 @@ * @file * @copyright 2020 Aleksej Komarov * @license MIT - */function oe(le,we){(we==null||we>le.length)&&(we=le.length);for(var ge=0,Oe=new Array(we);ge=le.length?{done:!0}:{done:!1,value:le[Oe++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var pe=(0,j.h)("chatRenderer"),ce=24,q={Tooltip:s.m_},K={position:"position",content:"content"},_=function(le){for(var we=document.body,ge=le;ge&&ge!==we;){if(ge.scrollWidth=f.HC){pe.error("failed to load an image after "+ge+" attempts");return}var Oe=we.src;we.src=null,we.src=Oe+"#"+ge,we.setAttribute("data-reload-n",ge+1)},f.xr)},Ae=function(le){var we=le.node,ge=le.times;if(!(!we||!ge)){var Oe=we.querySelector(".Chat__badge"),Fe=Oe||document.createElement("div");Fe.textContent=ge,Fe.className=(0,C.Ly)(["Chat__badge","Chat__badge--animate"]),requestAnimationFrame(function(){Fe.className="Chat__badge"}),Oe||we.appendChild(Fe)}},Pe=function(){"use strict";function le(){var ge=this;this.loaded=!1,this.rootNode=null,this.queue=[],this.messages=[],this.archivedMessages=[],this.visibleMessages=[],this.page=null,this.events=new I.b,this.prependTimestamps=!1,this.visibleMessageLimit=2500,this.combineMessageLimit=5,this.combineIntervalLimit=5,this.logLimit=0,this.logEnable=!0,this.roundId=null,this.storedTypes={},this.interleave=!1,this.interleaveEnabled=!1,this.interleaveColor="#909090",this.hideImportantInAdminTab=!1,this.scrollNode=null,this.scrollTracking=!0,this.handleScroll=function(Oe){var Fe=ge.scrollNode,Ve=Fe.scrollHeight,pt=Fe.scrollTop+Fe.offsetHeight,dt=Math.abs(Ve-pt)0&&(this.processBatch(this.queue,{doArchive:Oe}),this.queue=[])},we.assignStyle=function(Oe){Oe===void 0&&(Oe={});for(var Fe=te(Object.keys(Oe)),Ve;!(Ve=Fe()).done;){var pt=Ve.value;this.rootNode.style.setProperty(pt,Oe[pt])}},we.setHighlight=function(Oe,Fe){var Ve=this;this.highlightParsers=null,Oe&&Oe.map(function(pt){var dt=Fe[pt],Rt=dt.highlightText,at=dt.blacklistText,Gt=dt.highlightColor,Vt=dt.highlightBlacklist,Bt=dt.highlightWholeMessage,Kt=dt.matchWord,qt=dt.matchCase,Jt=/^[a-z0-9_\-$/^[\s\]\\]+$/gi,kt=/[!#$%^&*)(+=.<>{}[\]:;'"|~`_\-\\/]/g,$n=String(Rt).split(",").map(function(hn){return hn.trim()}).filter(function(hn){return hn&&hn.length>1&&Jt.test(hn)&&((Jt.lastIndex=0)||!0)}),jn,ar;if($n.length!==0){var vo=String(at).split(",").map(function(hn){return hn.trim()}).filter(function(hn){return hn&&hn.length>1&&Jt.test(hn)&&((Jt.lastIndex=0)||!0)}),jt,_t;if(Vt&&vo.length>0){for(var po=[],yn=te(vo),ur;!(ur=yn()).done;){var en=ur.value;if(en.charAt(0)==="/"&&en.charAt(en.length-1)==="/"){var Or=en.substring(1,en.length-1);if(/^(\[.*\]|\\.|.)$/.test(Or))continue;po.push(Or)}else jt||(jt=[]),en=en.replace(kt,"\\$&"),jt.push("^\\s*"+en),jt.push("^\\[\\d+:\\d+\\]\\s*"+en)}var lr=jt.join("|"),eo="i";try{_t=new RegExp("("+lr+")",eo)}catch(hn){_t=null}}for(var hr=[],ln=te($n),sn;!(sn=ln()).done;){var An=sn.value;if(An.charAt(0)==="/"&&An.charAt(An.length-1)==="/"){var Dr=An.substring(1,An.length-1);if(/^(\[.*\]|\\.|.)$/.test(Dr))continue;hr.push(Dr)}else jn||(jn=[]),An=An.replace(kt,"\\$&"),jn.push(An)}var er=hr.join("|"),sr="g"+(qt?"":"i");try{if(er)ar=new RegExp("("+er+")",sr);else{var Fr=(Kt?"\\b":"")+"("+jn.join("|")+")"+(Kt?"\\b":"");ar=new RegExp(Fr,sr)}}catch(hn){ar=null}Ve.highlightParsers||(Ve.highlightParsers=[]),Ve.highlightParsers.push({highlightWords:jn,highlightRegex:ar,highlightColor:Gt,highlightWholeMessage:Bt,highlightBlacklist:Vt,blacklistregex:_t})}})},we.scrollToBottom=function(){this.scrollNode.scrollTop=this.scrollNode.scrollHeight},we.setVisualChatLimits=function(Oe,Fe,Ve,pt,dt,Rt,at,Gt,Vt,Bt,Kt){this.visibleMessageLimit=Oe,this.combineMessageLimit=Fe,this.combineIntervalLimit=Ve,this.logEnable=pt,this.logLimit=dt,this.storedTypes=Rt,this.roundId=at,this.prependTimestamps=Gt,this.hideImportantInAdminTab=Vt,this.interleaveEnabled=Bt,this.interleaveColor=Kt},we.changePage=function(Oe){if(!this.isReady()){this.page=Oe,this.tryFlushQueue();return}this.page=Oe,this.rootNode.textContent="",this.visibleMessages=[];for(var Fe=document.createDocumentFragment(),Ve,pt=te(this.messages),dt;!(dt=pt()).done;){var Rt=dt.value;(0,B.CH)(Oe,Rt.type)&&!((0,B.Db)(Oe)&&(0,B.Dx)(Rt.type)&&this.hideImportantInAdminTab)&&(Ve=Rt.node,Ve=ae(Ve,this.interleaveEnabled&&this.interleave,this.interleaveColor),this.interleave=!this.interleave,Fe.appendChild(Ve),this.visibleMessages.push(Rt))}Ve&&(this.rootNode.appendChild(Fe),Ve.scrollIntoView())},we.getCombinableMessage=function(Oe){for(var Fe=Date.now(),Ve=this.visibleMessages.length,pt=Ve-1,dt=Math.max(0,Ve-this.combineMessageLimit),Rt=pt;Rt>=dt;Rt--){var at=this.visibleMessages[Rt],Gt=!at.type.startsWith(f.PM)&&(0,B.mh)(at,Oe)&&Fe0&&Ve.archivedMessages.length>=Ve.logLimit+1?Ve.archivedMessages=Ve.archivedMessages.slice(-(Ve.logLimit-1)):Ve.logLimit>0&&Ve.archivedMessages.length>=Ve.logLimit&&Ve.archivedMessages.shift(),Ve.archivedMessages.push((0,B.Ex)(jt,!0))),(0,B.CH)(Ve.page,jt.type)&&!((0,B.Db)(Ve.page)&&(0,B.Dx)(jt.type)&&Ve.hideImportantInAdminTab)&&(kt=ae(kt,Ve.interleaveEnabled&&Ve.interleave,Ve.interleaveColor),Ve.interleave=!Ve.interleave,qt.appendChild(kt),Ve.visibleMessages.push(jt))},dt=this;Fe===void 0&&(Fe={});var Rt=Fe.prepend,at=Fe.notifyListeners,Gt=at===void 0?!0:at,Vt=Fe.doArchive,Bt=Vt===void 0?!1:Vt,Kt=Date.now();if(!this.isReady()){Rt?this.queue=[].concat(Oe,this.queue):this.queue=[].concat(this.queue,Oe);return}for(var qt=document.createDocumentFragment(),Jt={},kt,$n=te(Oe),jn;!(jn=$n()).done;)Ve=this,pt();if(kt){var ar=this.rootNode.childNodes[0];Rt&&ar?this.rootNode.insertBefore(qt,ar):this.rootNode.appendChild(qt),this.scrollTracking&&setImmediate(function(){return dt.scrollToBottom()})}Gt&&this.events.emit("batchProcessed",Jt)},we.pruneMessages=function(){if(this.isReady()){if(!this.scrollTracking){pe.debug("pruning delayed");return}{var Oe=this.visibleMessages,Fe=Math.max(0,Oe.length-this.visibleMessageLimit);if(Fe>0){this.visibleMessages=Oe.slice(Fe);for(var Ve=0;Ve0&&(this.messages=this.messages.slice(dt),pe.log("pruned "+dt+" stored messages"))}}},we.rebuildChat=function(Oe){if(this.isReady()){for(var Fe=Math.max(0,this.messages.length-Oe),Ve=this.messages.slice(Fe),pt=te(Ve),dt;!(dt=pt()).done;){var Rt=dt.value;Rt.node=void 0}this.rootNode.textContent="",this.messages=[],this.visibleMessages=[],this.processBatch(Ve,{notifyListeners:!1})}},we.saveToDisk=function(Oe,Fe,Ve){if(Fe===void 0&&(Fe=0),Ve===void 0&&(Ve=0),!Byond.IS_LTE_IE10){for(var pt="",dt=document.styleSheets,Rt=0;Rt0&&(Kt=Kt.slice(-Oe))):Oe>0?Kt=this.archivedMessages.slice(-Oe):Kt=this.archivedMessages;for(var qt=te(Kt),Jt;!(Jt=qt()).done;){var kt=Jt.value;(0,B.CH)(this.page,kt.type)&&(Bt+=kt.html+"\n")}var $n="\n\n\nSS13 Chat Log\n\n\n\n\n'+Bt+"\n\n\n",jn=new Blob([$n]),ar=new Date().toISOString().substring(0,19).replace(/[-:]/g,"").replace("T","-");window.navigator.msSaveBlob(jn,"ss13-chatlog-"+ar+".html")}},we.purgeMessageArchive=function(){this.archivedMessages=[]},we.getStoredMessages=function(){return this.archivedMessages.length},le}();window.__chatRenderer__||(window.__chatRenderer__=new Pe);var me=window.__chatRenderer__;/** + */function oe(le,we){(we==null||we>le.length)&&(we=le.length);for(var ge=0,Oe=new Array(we);ge=le.length?{done:!0}:{done:!1,value:le[Oe++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var pe=(0,j.h)("chatRenderer"),ce=24,q={Tooltip:s.m_},K={position:"position",content:"content"},_=function(le){for(var we=document.body,ge=le;ge&&ge!==we;){if(ge.scrollWidth=f.HC){pe.error("failed to load an image after "+ge+" attempts");return}var Oe=we.src;we.src=null,we.src=Oe+"#"+ge,we.setAttribute("data-reload-n",ge+1)},f.xr)},Ae=function(le){var we=le.node,ge=le.times;if(!(!we||!ge)){var Oe=we.querySelector(".Chat__badge"),Fe=Oe||document.createElement("div");Fe.textContent=ge,Fe.className=(0,C.Ly)(["Chat__badge","Chat__badge--animate"]),requestAnimationFrame(function(){Fe.className="Chat__badge"}),Oe||we.appendChild(Fe)}},Pe=function(){"use strict";function le(){var ge=this;this.loaded=!1,this.rootNode=null,this.queue=[],this.messages=[],this.archivedMessages=[],this.visibleMessages=[],this.page=null,this.events=new I.b,this.prependTimestamps=!1,this.visibleMessageLimit=2500,this.combineMessageLimit=5,this.combineIntervalLimit=5,this.logLimit=0,this.logEnable=!0,this.roundId=null,this.storedTypes={},this.interleave=!1,this.interleaveEnabled=!1,this.interleaveColor="#909090",this.hideImportantInAdminTab=!1,this.scrollNode=null,this.scrollTracking=!0,this.handleScroll=function(Oe){var Fe=ge.scrollNode,Ve=Fe.scrollHeight,pt=Fe.scrollTop+Fe.offsetHeight,dt=Math.abs(Ve-pt)0&&(this.processBatch(this.queue,{doArchive:Oe}),this.queue=[])},we.assignStyle=function(Oe){Oe===void 0&&(Oe={});for(var Fe=te(Object.keys(Oe)),Ve;!(Ve=Fe()).done;){var pt=Ve.value;this.rootNode.style.setProperty(pt,Oe[pt])}},we.setHighlight=function(Oe,Fe){var Ve=this;this.highlightParsers=null,Oe&&Oe.map(function(pt){var dt=Fe[pt],Rt=dt.highlightText,at=dt.blacklistText,Gt=dt.highlightColor,Vt=dt.highlightBlacklist,Bt=dt.highlightWholeMessage,Kt=dt.matchWord,qt=dt.matchCase,Jt=/^[a-z0-9_\-$/^[\s\]\\]+$/gi,kt=/[!#$%^&*)(+=.<>{}[\]:;'"|~`_\-\\/]/g,Wn=String(Rt).split(",").map(function(hn){return hn.trim()}).filter(function(hn){return hn&&hn.length>1&&Jt.test(hn)&&((Jt.lastIndex=0)||!0)}),jn,ar;if(Wn.length!==0){var vo=String(at).split(",").map(function(hn){return hn.trim()}).filter(function(hn){return hn&&hn.length>1&&Jt.test(hn)&&((Jt.lastIndex=0)||!0)}),jt,_t;if(Vt&&vo.length>0){for(var po=[],yn=te(vo),ur;!(ur=yn()).done;){var en=ur.value;if(en.charAt(0)==="/"&&en.charAt(en.length-1)==="/"){var Or=en.substring(1,en.length-1);if(/^(\[.*\]|\\.|.)$/.test(Or))continue;po.push(Or)}else jt||(jt=[]),en=en.replace(kt,"\\$&"),jt.push("^\\s*"+en),jt.push("^\\[\\d+:\\d+\\]\\s*"+en)}var lr=jt.join("|"),eo="i";try{_t=new RegExp("("+lr+")",eo)}catch(hn){_t=null}}for(var hr=[],ln=te(Wn),sn;!(sn=ln()).done;){var An=sn.value;if(An.charAt(0)==="/"&&An.charAt(An.length-1)==="/"){var Dr=An.substring(1,An.length-1);if(/^(\[.*\]|\\.|.)$/.test(Dr))continue;hr.push(Dr)}else jn||(jn=[]),An=An.replace(kt,"\\$&"),jn.push(An)}var er=hr.join("|"),sr="g"+(qt?"":"i");try{if(er)ar=new RegExp("("+er+")",sr);else{var Fr=(Kt?"\\b":"")+"("+jn.join("|")+")"+(Kt?"\\b":"");ar=new RegExp(Fr,sr)}}catch(hn){ar=null}Ve.highlightParsers||(Ve.highlightParsers=[]),Ve.highlightParsers.push({highlightWords:jn,highlightRegex:ar,highlightColor:Gt,highlightWholeMessage:Bt,highlightBlacklist:Vt,blacklistregex:_t})}})},we.scrollToBottom=function(){this.scrollNode.scrollTop=this.scrollNode.scrollHeight},we.setVisualChatLimits=function(Oe,Fe,Ve,pt,dt,Rt,at,Gt,Vt,Bt,Kt){this.visibleMessageLimit=Oe,this.combineMessageLimit=Fe,this.combineIntervalLimit=Ve,this.logEnable=pt,this.logLimit=dt,this.storedTypes=Rt,this.roundId=at,this.prependTimestamps=Gt,this.hideImportantInAdminTab=Vt,this.interleaveEnabled=Bt,this.interleaveColor=Kt},we.changePage=function(Oe){if(!this.isReady()){this.page=Oe,this.tryFlushQueue();return}this.page=Oe,this.rootNode.textContent="",this.visibleMessages=[];for(var Fe=document.createDocumentFragment(),Ve,pt=te(this.messages),dt;!(dt=pt()).done;){var Rt=dt.value;(0,B.CH)(Oe,Rt.type)&&!((0,B.Db)(Oe)&&(0,B.Dx)(Rt.type)&&this.hideImportantInAdminTab)&&(Ve=Rt.node,Ve=ae(Ve,this.interleaveEnabled&&this.interleave,this.interleaveColor),this.interleave=!this.interleave,Fe.appendChild(Ve),this.visibleMessages.push(Rt))}Ve&&(this.rootNode.appendChild(Fe),Ve.scrollIntoView())},we.getCombinableMessage=function(Oe){for(var Fe=Date.now(),Ve=this.visibleMessages.length,pt=Ve-1,dt=Math.max(0,Ve-this.combineMessageLimit),Rt=pt;Rt>=dt;Rt--){var at=this.visibleMessages[Rt],Gt=!at.type.startsWith(f.PM)&&(0,B.mh)(at,Oe)&&Fe0&&Ve.archivedMessages.length>=Ve.logLimit+1?Ve.archivedMessages=Ve.archivedMessages.slice(-(Ve.logLimit-1)):Ve.logLimit>0&&Ve.archivedMessages.length>=Ve.logLimit&&Ve.archivedMessages.shift(),Ve.archivedMessages.push((0,B.Ex)(jt,!0))),(0,B.CH)(Ve.page,jt.type)&&!((0,B.Db)(Ve.page)&&(0,B.Dx)(jt.type)&&Ve.hideImportantInAdminTab)&&(kt=ae(kt,Ve.interleaveEnabled&&Ve.interleave,Ve.interleaveColor),Ve.interleave=!Ve.interleave,qt.appendChild(kt),Ve.visibleMessages.push(jt))},dt=this;Fe===void 0&&(Fe={});var Rt=Fe.prepend,at=Fe.notifyListeners,Gt=at===void 0?!0:at,Vt=Fe.doArchive,Bt=Vt===void 0?!1:Vt,Kt=Date.now();if(!this.isReady()){Rt?this.queue=[].concat(Oe,this.queue):this.queue=[].concat(this.queue,Oe);return}for(var qt=document.createDocumentFragment(),Jt={},kt,Wn=te(Oe),jn;!(jn=Wn()).done;)Ve=this,pt();if(kt){var ar=this.rootNode.childNodes[0];Rt&&ar?this.rootNode.insertBefore(qt,ar):this.rootNode.appendChild(qt),this.scrollTracking&&setImmediate(function(){return dt.scrollToBottom()})}Gt&&this.events.emit("batchProcessed",Jt)},we.pruneMessages=function(){if(this.isReady()){if(!this.scrollTracking){pe.debug("pruning delayed");return}{var Oe=this.visibleMessages,Fe=Math.max(0,Oe.length-this.visibleMessageLimit);if(Fe>0){this.visibleMessages=Oe.slice(Fe);for(var Ve=0;Ve0&&(this.messages=this.messages.slice(dt),pe.log("pruned "+dt+" stored messages"))}}},we.rebuildChat=function(Oe){if(this.isReady()){for(var Fe=Math.max(0,this.messages.length-Oe),Ve=this.messages.slice(Fe),pt=te(Ve),dt;!(dt=pt()).done;){var Rt=dt.value;Rt.node=void 0}this.rootNode.textContent="",this.messages=[],this.visibleMessages=[],this.processBatch(Ve,{notifyListeners:!1})}},we.saveToDisk=function(Oe,Fe,Ve){if(Fe===void 0&&(Fe=0),Ve===void 0&&(Ve=0),!Byond.IS_LTE_IE10){for(var pt="",dt=document.styleSheets,Rt=0;Rt0&&(Kt=Kt.slice(-Oe))):Oe>0?Kt=this.archivedMessages.slice(-Oe):Kt=this.archivedMessages;for(var qt=te(Kt),Jt;!(Jt=qt()).done;){var kt=Jt.value;(0,B.CH)(this.page,kt.type)&&(Bt+=kt.html+"\n")}var Wn="\n\n\nSS13 Chat Log\n\n\n\n\n'+Bt+"\n\n\n",jn=new Blob([Wn]),ar=new Date().toISOString().substring(0,19).replace(/[-:]/g,"").replace("T","-");window.navigator.msSaveBlob(jn,"ss13-chatlog-"+ar+".html")}},we.purgeMessageArchive=function(){this.archivedMessages=[]},we.getStoredMessages=function(){return this.archivedMessages.length},le}();window.__chatRenderer__||(window.__chatRenderer__=new Pe);var me=window.__chatRenderer__;/** * @file * @copyright 2020 Aleksej Komarov * @license MIT @@ -166,11 +166,11 @@ * @file * @copyright 2020 Aleksej Komarov * @license MIT - */function qe(le,we){(we==null||we>le.length)&&(we=le.length);for(var ge=0,Oe=new Array(we);ge=le.length?{done:!0}:{done:!1,value:le[Oe++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function Ne(le,we){var ge,Oe,Fe,Ve,pt={label:0,sent:function(){if(Fe[0]&1)throw Fe[1];return Fe[1]},trys:[],ops:[]};return Ve={next:dt(0),throw:dt(1),return:dt(2)},typeof Symbol=="function"&&(Ve[Symbol.iterator]=function(){return this}),Ve;function dt(at){return function(Gt){return Rt([at,Gt])}}function Rt(at){if(ge)throw new TypeError("Generator is already executing.");for(;pt;)try{if(ge=1,Oe&&(Fe=at[0]&2?Oe.return:at[0]?Oe.throw||((Fe=Oe.return)&&Fe.call(Oe),0):Oe.next)&&!(Fe=Fe.call(Oe,at[1])).done)return Fe;switch(Oe=0,Fe&&(at=[at[0]&2,Fe.value]),at[0]){case 0:case 1:Fe=at;break;case 4:return pt.label++,{value:at[1],done:!1};case 5:pt.label++,Oe=at[1],at=[0];continue;case 7:at=pt.ops.pop(),pt.trys.pop();continue;default:if(Fe=pt.trys,!(Fe=Fe.length>0&&Fe[Fe.length-1])&&(at[0]===6||at[0]===2)){pt=0;continue}if(at[0]===3&&(!Fe||at[1]>Fe[0]&&at[1]Bt.logRetainRounds?(me.archivedMessages=Fe.slice(xt[_e.length-Bt.logRetainRounds]),Bt.storedRounds=Bt.logRetainRounds):me.archivedMessages=Fe,Bt.lastId=Kt}else me.archivedMessages=Fe}return le.dispatch((0,d.Hg)(ge)),[2]}})}),St=function(le){var we=!1,ge=!1,Oe=[],Fe=[];return me.events.on("batchProcessed",function(Ve){ge&&le.dispatch((0,d.Y_)(Ve))}),me.events.on("scrollTrackingChanged",function(Ve){le.dispatch((0,d.$l)(Ve))}),function(Ve){return function(pt){var dt=pt.type,Rt=pt.payload,at=(0,ct.i0)(le.getState()),Gt=(0,tt.V)(le.getState());if(at.totalStoredMessages=me.getStoredMessages(),at.storedRounds=_e.length,me.setVisualChatLimits(at.visibleMessageLimit,at.combineMessageLimit,at.combineIntervalLimit,at.logEnable,at.logLimit,at.storedTypes,Gt.roundId,at.prependTimestamps,at.hideImportantInAdminTab,at.interleave,at.interleaveColor),!we&&(at.initialized||at.firstLoad)&&(we=!0,setInterval(function(){bt(le)},at.saveInterval*1e3),Wt(le)),dt==="chat/message"){var Vt;try{Vt=JSON.parse(Rt)}catch(jn){return}var Bt=Vt.sequence;if(Oe.includes(Bt))return;var Kt=Oe.length;e:if(Kt>0){if(Fe.includes(Bt)){Fe.splice(Fe.indexOf(Bt),1);break e}var qt=Oe[Kt-1]+1;if(Bt!==qt)for(var Jt=qt;Jtle.length)&&(we=le.length);for(var ge=0,Oe=new Array(we);ge=le.length?{done:!0}:{done:!1,value:le[Oe++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function Ne(le,we){var ge,Oe,Fe,Ve,pt={label:0,sent:function(){if(Fe[0]&1)throw Fe[1];return Fe[1]},trys:[],ops:[]};return Ve={next:dt(0),throw:dt(1),return:dt(2)},typeof Symbol=="function"&&(Ve[Symbol.iterator]=function(){return this}),Ve;function dt(at){return function(Gt){return Rt([at,Gt])}}function Rt(at){if(ge)throw new TypeError("Generator is already executing.");for(;pt;)try{if(ge=1,Oe&&(Fe=at[0]&2?Oe.return:at[0]?Oe.throw||((Fe=Oe.return)&&Fe.call(Oe),0):Oe.next)&&!(Fe=Fe.call(Oe,at[1])).done)return Fe;switch(Oe=0,Fe&&(at=[at[0]&2,Fe.value]),at[0]){case 0:case 1:Fe=at;break;case 4:return pt.label++,{value:at[1],done:!1};case 5:pt.label++,Oe=at[1],at=[0];continue;case 7:at=pt.ops.pop(),pt.trys.pop();continue;default:if(Fe=pt.trys,!(Fe=Fe.length>0&&Fe[Fe.length-1])&&(at[0]===6||at[0]===2)){pt=0;continue}if(at[0]===3&&(!Fe||at[1]>Fe[0]&&at[1]Bt.logRetainRounds?(me.archivedMessages=Fe.slice(xt[_e.length-Bt.logRetainRounds]),Bt.storedRounds=Bt.logRetainRounds):me.archivedMessages=Fe,Bt.lastId=Kt}else me.archivedMessages=Fe}return le.dispatch((0,d.Hg)(ge)),[2]}})}),St=function(le){var we=!1,ge=!1,Oe=[],Fe=[];return me.events.on("batchProcessed",function(Ve){ge&&le.dispatch((0,d.Y_)(Ve))}),me.events.on("scrollTrackingChanged",function(Ve){le.dispatch((0,d.$l)(Ve))}),function(Ve){return function(pt){var dt=pt.type,Rt=pt.payload,at=(0,ct.i0)(le.getState()),Gt=(0,tt.V)(le.getState());if(at.totalStoredMessages=me.getStoredMessages(),at.storedRounds=_e.length,me.setVisualChatLimits(at.visibleMessageLimit,at.combineMessageLimit,at.combineIntervalLimit,at.logEnable,at.logLimit,at.storedTypes,Gt.roundId,at.prependTimestamps,at.hideImportantInAdminTab,at.interleave,at.interleaveColor),!we&&(at.initialized||at.firstLoad)&&(we=!0,setInterval(function(){bt(le)},at.saveInterval*1e3),Wt(le)),dt==="chat/message"){var Vt;try{Vt=JSON.parse(Rt)}catch(jn){return}var Bt=Vt.sequence;if(Oe.includes(Bt))return;var Kt=Oe.length;e:if(Kt>0){if(Fe.includes(Bt)){Fe.splice(Fe.indexOf(Bt),1);break e}var qt=Oe[Kt-1]+1;if(Bt!==qt)for(var Jt=qt;Jtle.length)&&(we=le.length);for(var ge=0,Oe=new Array(we);ge=0)&&(ge[Fe]=le[Fe]);return ge}function Ut(le,we){if(le){if(typeof le=="string")return et(le,we);var ge=Object.prototype.toString.call(le).slice(8,-1);if(ge==="Object"&&le.constructor&&(ge=le.constructor.name),ge==="Map"||ge==="Set")return Array.from(ge);if(ge==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(ge))return et(le,we)}}function fn(le,we){var ge=typeof Symbol!="undefined"&&le[Symbol.iterator]||le["@@iterator"];if(ge)return(ge=ge.call(le)).next.bind(ge);if(Array.isArray(le)||(ge=Ut(le))||we&&le&&typeof le.length=="number"){ge&&(le=ge);var Oe=0;return function(){return Oe>=le.length?{done:!0}:{done:!1,value:le[Oe++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var gn=(0,B.pJ)(),kn,Xn={version:5,currentPageId:gn.id,scrollTracking:!0,pages:[gn.id],pageById:(kn={},kn[gn.id]=gn,kn)},Lr=function(le,we){le===void 0&&(le=Xn);var ge=we.type,Oe=we.payload;if(ge===d.Hg.type){if((Oe==null?void 0:Oe.version)!==le.version)return le;for(var Fe=fn(Object.keys(Oe.pageById)),Ve;!(Ve=Fe()).done;)for(var pt=Ve.value,dt=Oe.pageById[pt],Rt=dt.acceptedTypes,at=gn.acceptedTypes,Gt=fn(Object.keys(at)),Vt;!(Vt=Gt()).done;){var Bt=Vt.value;Rt[Bt]===void 0&&(Rt[Bt]=at[Bt])}for(var Kt=fn(Object.keys(Oe.pageById)),qt;!(qt=Kt()).done;){var Jt=qt.value,kt=Oe.pageById[Jt];kt.unreadCount=0}return He({},le,Oe)}if(ge===d.$l.type){var $n=Oe,jn=He({},le,{scrollTracking:$n});if($n){var ar=le.currentPageId,vo=He({},le.pageById[ar],{unreadCount:0}),jt;jn.pageById=He({},le.pageById,(jt={},jt[ar]=vo,jt))}return jn}if(ge===d.Y_.type){for(var _t=Oe,po=le.pages.map(function(_o){return le.pageById[_o]}),yn=le.pageById[le.currentPageId],ur=He({},le.pageById),en=fn(po),Or;!(Or=en()).done;){for(var lr=Or.value,eo=0,hr=fn(Object.keys(_t)),ln;!(ln=hr()).done;){var sn=ln.value;(0,B.CH)(lr,sn)&&(lr===yn&&le.scrollTracking||lr!==yn&&(0,B.CH)(yn,sn)||(eo+=_t[sn]))}eo>0&&(ur[lr.id]=He({},lr,{unreadCount:lr.unreadCount+eo}))}return He({},le,{pageById:ur})}if(ge===d.Pd.type){var An;return He({},le,{currentPageId:Oe.id,pages:[].concat(le.pages,[Oe.id]),pageById:He({},le.pageById,(An={},An[Oe.id]=Oe,An))})}if(ge===d.Qn.type){var Dr=Oe.pageId,er=He({},le.pageById[Dr],{unreadCount:0}),sr;return He({},le,{currentPageId:Dr,pageById:He({},le.pageById,(sr={},sr[Dr]=er,sr))})}if(ge===d.Hp.type){var Fr=Oe.pageId,hn=Ft(Oe,["pageId"]),Wn=He({},le.pageById[Fr],hn),Qn;return He({},le,{pageById:He({},le.pageById,(Qn={},Qn[Fr]=Wn,Qn))})}if(ge===d._E.type){var On=Oe.pageId,cr=Oe.type,Co=He({},le.pageById[On]);Co.acceptedTypes=He({},Co.acceptedTypes),Co.acceptedTypes[cr]=!Co.acceptedTypes[cr];var qo;return He({},le,{pageById:He({},le.pageById,(qo={},qo[On]=Co,qo))})}if(ge===d.YH.type){var Tr=Oe.pageId,wn=He({},le,{pages:[].concat(le.pages),pageById:He({},le.pageById)});return delete wn.pageById[Tr],wn.pages=wn.pages.filter(function(_o){return _o!==Tr}),wn.pages.length===0&&(wn.pages.push(gn.id),wn.pageById[gn.id]=gn,wn.currentPageId=gn.id),(!wn.currentPageId||wn.currentPageId===Tr)&&(wn.currentPageId=wn.pages[0]),wn}if(ge===d.AB.type){var Pr=Oe.pageId,mr=He({},le,{pages:[].concat(le.pages),pageById:He({},le.pageById)}),pi=mr.pageById[Pr],hi=mr.pages.indexOf(pi.id),Zr=hi-1;if(hi>0&&Zr>0){var mi=mr.pages[hi];mr.pages[hi]=mr.pages[Zr],mr.pages[Zr]=mi}return mr}if(ge===d.Xl.type){var ko=Oe.pageId,tr=He({},le,{pages:[].concat(le.pages),pageById:He({},le.pageById)}),Ar=tr.pageById[ko],Jr=tr.pages.indexOf(Ar.id),tn=Jr+1;if(Jr>0&&tnle.length)&&(we=le.length);for(var ge=0,Oe=new Array(we);ge=0)&&(ge[Fe]=le[Fe]);return ge}function Ut(le,we){if(le){if(typeof le=="string")return et(le,we);var ge=Object.prototype.toString.call(le).slice(8,-1);if(ge==="Object"&&le.constructor&&(ge=le.constructor.name),ge==="Map"||ge==="Set")return Array.from(ge);if(ge==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(ge))return et(le,we)}}function fn(le,we){var ge=typeof Symbol!="undefined"&&le[Symbol.iterator]||le["@@iterator"];if(ge)return(ge=ge.call(le)).next.bind(ge);if(Array.isArray(le)||(ge=Ut(le))||we&&le&&typeof le.length=="number"){ge&&(le=ge);var Oe=0;return function(){return Oe>=le.length?{done:!0}:{done:!1,value:le[Oe++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var gn=(0,B.pJ)(),$n,Xn={version:5,currentPageId:gn.id,scrollTracking:!0,pages:[gn.id],pageById:($n={},$n[gn.id]=gn,$n)},Lr=function(le,we){le===void 0&&(le=Xn);var ge=we.type,Oe=we.payload;if(ge===d.Hg.type){if((Oe==null?void 0:Oe.version)!==le.version)return le;for(var Fe=fn(Object.keys(Oe.pageById)),Ve;!(Ve=Fe()).done;)for(var pt=Ve.value,dt=Oe.pageById[pt],Rt=dt.acceptedTypes,at=gn.acceptedTypes,Gt=fn(Object.keys(at)),Vt;!(Vt=Gt()).done;){var Bt=Vt.value;Rt[Bt]===void 0&&(Rt[Bt]=at[Bt])}for(var Kt=fn(Object.keys(Oe.pageById)),qt;!(qt=Kt()).done;){var Jt=qt.value,kt=Oe.pageById[Jt];kt.unreadCount=0}return He({},le,Oe)}if(ge===d.$l.type){var Wn=Oe,jn=He({},le,{scrollTracking:Wn});if(Wn){var ar=le.currentPageId,vo=He({},le.pageById[ar],{unreadCount:0}),jt;jn.pageById=He({},le.pageById,(jt={},jt[ar]=vo,jt))}return jn}if(ge===d.Y_.type){for(var _t=Oe,po=le.pages.map(function(_o){return le.pageById[_o]}),yn=le.pageById[le.currentPageId],ur=He({},le.pageById),en=fn(po),Or;!(Or=en()).done;){for(var lr=Or.value,eo=0,hr=fn(Object.keys(_t)),ln;!(ln=hr()).done;){var sn=ln.value;(0,B.CH)(lr,sn)&&(lr===yn&&le.scrollTracking||lr!==yn&&(0,B.CH)(yn,sn)||(eo+=_t[sn]))}eo>0&&(ur[lr.id]=He({},lr,{unreadCount:lr.unreadCount+eo}))}return He({},le,{pageById:ur})}if(ge===d.Pd.type){var An;return He({},le,{currentPageId:Oe.id,pages:[].concat(le.pages,[Oe.id]),pageById:He({},le.pageById,(An={},An[Oe.id]=Oe,An))})}if(ge===d.Qn.type){var Dr=Oe.pageId,er=He({},le.pageById[Dr],{unreadCount:0}),sr;return He({},le,{currentPageId:Dr,pageById:He({},le.pageById,(sr={},sr[Dr]=er,sr))})}if(ge===d.Hp.type){var Fr=Oe.pageId,hn=Ft(Oe,["pageId"]),Vn=He({},le.pageById[Fr],hn),Qn;return He({},le,{pageById:He({},le.pageById,(Qn={},Qn[Fr]=Vn,Qn))})}if(ge===d._E.type){var On=Oe.pageId,cr=Oe.type,Co=He({},le.pageById[On]);Co.acceptedTypes=He({},Co.acceptedTypes),Co.acceptedTypes[cr]=!Co.acceptedTypes[cr];var qo;return He({},le,{pageById:He({},le.pageById,(qo={},qo[On]=Co,qo))})}if(ge===d.YH.type){var Tr=Oe.pageId,wn=He({},le,{pages:[].concat(le.pages),pageById:He({},le.pageById)});return delete wn.pageById[Tr],wn.pages=wn.pages.filter(function(_o){return _o!==Tr}),wn.pages.length===0&&(wn.pages.push(gn.id),wn.pageById[gn.id]=gn,wn.currentPageId=gn.id),(!wn.currentPageId||wn.currentPageId===Tr)&&(wn.currentPageId=wn.pages[0]),wn}if(ge===d.AB.type){var Pr=Oe.pageId,mr=He({},le,{pages:[].concat(le.pages),pageById:He({},le.pageById)}),pi=mr.pageById[Pr],hi=mr.pages.indexOf(pi.id),Zr=hi-1;if(hi>0&&Zr>0){var mi=mr.pages[hi];mr.pages[hi]=mr.pages[Zr],mr.pages[Zr]=mi}return mr}if(ge===d.Xl.type){var ko=Oe.pageId,tr=He({},le,{pages:[].concat(le.pages),pageById:He({},le.pageById)}),Ar=tr.pageById[ko],Jr=tr.pages.indexOf(Ar.id),tn=Jr+1;if(Jr>0&&tnF.length)&&(V=F.length);for(var G=0,J=new Array(V);G=0)&&(G[oe]=F[oe]);return G}function g(F,V){if(F){if(typeof F=="string")return f(F,V);var G=Object.prototype.toString.call(F).slice(8,-1);if(G==="Object"&&F.constructor&&(G=F.constructor.name),G==="Map"||G==="Set")return Array.from(G);if(G==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(G))return f(F,V)}}function S(F,V){var G=typeof Symbol!="undefined"&&F[Symbol.iterator]||F["@@iterator"];if(G)return(G=G.call(F)).next.bind(G);if(Array.isArray(F)||(G=g(F))||V&&F&&typeof F.length=="number"){G&&(F=G);var J=0;return function(){return J>=F.length?{done:!0}:{done:!1,value:F[J++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var E=function(F){if(typeof F=="string")return F.endsWith("px")?parseFloat(F)/12+"rem":F;if(typeof F=="number")return F+"rem"},T=function(F){if(typeof F=="string")return E(F);if(typeof F=="number")return E(F*.5)},C=function(F){return!w(F)},w=function(F){return typeof F=="string"&&s.NE.includes(F)},I=function(F){return function(V,G){(typeof G=="number"||typeof G=="string")&&(V[F]=G)}},R=function(F,V){return function(G,J){(typeof J=="number"||typeof J=="string")&&(G[F]=V(J))}},j=function(F,V){return function(G,J){J&&(G[F]=V)}},B=function(F,V,G){return function(J,oe){if(typeof oe=="number"||typeof oe=="string")for(var Z=0;ZF.length)&&(V=F.length);for(var G=0,J=new Array(V);G=0)&&(G[oe]=F[oe]);return G}function g(F,V){if(F){if(typeof F=="string")return f(F,V);var G=Object.prototype.toString.call(F).slice(8,-1);if(G==="Object"&&F.constructor&&(G=F.constructor.name),G==="Map"||G==="Set")return Array.from(G);if(G==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(G))return f(F,V)}}function S(F,V){var G=typeof Symbol!="undefined"&&F[Symbol.iterator]||F["@@iterator"];if(G)return(G=G.call(F)).next.bind(G);if(Array.isArray(F)||(G=g(F))||V&&F&&typeof F.length=="number"){G&&(F=G);var J=0;return function(){return J>=F.length?{done:!0}:{done:!1,value:F[J++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var E=function(F){if(typeof F=="string")return F.endsWith("px")?parseFloat(F)/12+"rem":F;if(typeof F=="number")return F+"rem"},T=function(F){if(typeof F=="string")return E(F);if(typeof F=="number")return E(F*.5)},C=function(F){return!w(F)},w=function(F){return typeof F=="string"&&s.NE.includes(F)},I=function(F){return function(V,G){(typeof G=="number"||typeof G=="string")&&(V[F]=G)}},R=function(F,V){return function(G,J){(typeof J=="number"||typeof J=="string")&&(G[F]=V(J))}},j=function(F,V){return function(G,J){J&&(G[F]=V)}},B=function(F,V,G){return function(J,oe){if(typeof oe=="number"||typeof oe=="string")for(var Z=0;Z=0)&&(T[w]=S[w]);return T}var p=function(S){var E=S.className,T=S.collapsing,C=S.children,w=f(S,["className","collapsing","children"]);return(0,i.jsx)("table",d({className:(0,u.Ly)(["Table",T&&"Table--collapsing",E,(0,s.WP)(w)])},(0,s.Fl)(w),{children:(0,i.jsx)("tbody",{children:C})}))},x=function(S){var E=S.className,T=S.header,C=f(S,["className","header"]);return(0,i.jsx)("tr",d({className:(0,u.Ly)(["Table__row",T&&"Table__row--header",E,(0,s.WP)(S)])},(0,s.Fl)(C)))},g=function(S){var E=S.className,T=S.collapsing,C=S.header,w=f(S,["className","collapsing","header"]);return(0,i.jsx)("td",d({className:(0,u.Ly)(["Table__cell",T&&"Table__cell--collapsing",C&&"Table__cell--header",E,(0,s.WP)(S)])},(0,s.Fl)(w)))};p.Row=x,p.Cell=g},16754:function(m,y,n){"use strict";n.d(y,{Z8:function(){return j},Y0:function(){return D},az:function(){return M.az},$n:function(){return nr},D1:function(){return ti},Nt:function(){return Vs},BK:function(){return sl},cG:function(){return Zl},Hx:function(){return Nu},ms:function(){return hl},so:function(){return br},In:function(){return G},pd:function(){return El},N6:function(){return Ol},Ki:function(){return Ui},IC:function(){return _r},Q7:function(){return cs},ND:function(){return ja},z2:function(){return Vo},wn:function(){return gu},Ap:function(){return pa},BJ:function(){return uu},tU:function(){return no},fs:function(){return Ir},m_:function(){return Vn}});var i=n(62161),u=n(4089),s=n(28277);/** + */function d(){return d=Object.assign||function(S){for(var E=1;E=0)&&(T[w]=S[w]);return T}var p=function(S){var E=S.className,T=S.collapsing,C=S.children,w=f(S,["className","collapsing","children"]);return(0,i.jsx)("table",d({className:(0,u.Ly)(["Table",T&&"Table--collapsing",E,(0,s.WP)(w)])},(0,s.Fl)(w),{children:(0,i.jsx)("tbody",{children:C})}))},x=function(S){var E=S.className,T=S.header,C=f(S,["className","header"]);return(0,i.jsx)("tr",d({className:(0,u.Ly)(["Table__row",T&&"Table__row--header",E,(0,s.WP)(S)])},(0,s.Fl)(C)))},g=function(S){var E=S.className,T=S.collapsing,C=S.header,w=f(S,["className","collapsing","header"]);return(0,i.jsx)("td",d({className:(0,u.Ly)(["Table__cell",T&&"Table__cell--collapsing",C&&"Table__cell--header",E,(0,s.WP)(S)])},(0,s.Fl)(w)))};p.Row=x,p.Cell=g},16754:function(m,y,n){"use strict";n.d(y,{Z8:function(){return j},Y0:function(){return D},az:function(){return M.az},$n:function(){return nr},D1:function(){return ti},Nt:function(){return Vs},BK:function(){return sl},cG:function(){return Zl},Hx:function(){return Nu},ms:function(){return hl},so:function(){return br},In:function(){return G},_V:function(){return Xs},pd:function(){return El},N6:function(){return Ol},Ki:function(){return Ui},IC:function(){return _r},Q7:function(){return cs},ND:function(){return ja},z2:function(){return Vo},wn:function(){return gu},Ap:function(){return pa},BJ:function(){return uu},tU:function(){return no},fs:function(){return Ir},m_:function(){return Bn}});var i=n(62161),u=n(4089),s=n(28277);/** * @file * @copyright 2020 Aleksej Komarov * @license MIT @@ -311,11 +311,11 @@ * @author Original Aleksej Komarov * @author Changes ThePotato97 * @license MIT - */function L(){return L=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}var V=/-o$/,G=function(c){var h=c.name,A=c.size,N=c.spin,O=c.className,$=c.rotation,re=F(c,["name","size","spin","className","rotation"]),ee=re.style||{};A&&(ee.fontSize=A*100+"%"),$&&(ee.transform="rotate("+$+"deg)"),re.style=ee;var de=(0,M.Fl)(re),ue="";if(h.startsWith("tg-"))ue=h;else{var ve=V.test(h),Be=h.replace(V,""),ze=!Be.startsWith("fa-");ue=ve?"far ":"fas ",ze&&(ue+="fa-"),ue+=Be,N&&(ue+=" fa-spin")}return(0,i.jsx)("i",L({className:(0,B.Ly)(["Icon",ue,O,(0,M.WP)(re)])},de))},J=function(c){var h=c.className,A=c.children,N=F(c,["className","children"]);return(0,i.jsx)("span",L({className:(0,B.Ly)(["IconStack",h,(0,M.WP)(N)])},(0,M.Fl)(N),{children:A}))};G.Stack=J;function oe(c){if(c==null)return window;if(c.toString()!=="[object Window]"){var h=c.ownerDocument;return h&&h.defaultView||window}return c}function Z(c,h){return h!=null&&typeof Symbol!="undefined"&&h[Symbol.hasInstance]?!!h[Symbol.hasInstance](c):c instanceof h}function ne(c){var h=oe(c).Element;return Z(c,h)||Z(c,Element)}function te(c){var h=oe(c).HTMLElement;return Z(c,h)||Z(c,HTMLElement)}function pe(c){if(typeof ShadowRoot=="undefined")return!1;var h=oe(c).ShadowRoot;return Z(c,h)||Z(c,ShadowRoot)}var ce=Math.max,q=Math.min,K=Math.round;function _(){var c=navigator.userAgentData;return c!=null&&c.brands&&Array.isArray(c.brands)?c.brands.map(function(h){return h.brand+"/"+h.version}).join(" "):navigator.userAgent}function W(){return!/^((?!chrome|android).)*safari/i.test(_())}function H(c,h,A){h===void 0&&(h=!1),A===void 0&&(A=!1);var N=c.getBoundingClientRect(),O=1,$=1;h&&te(c)&&(O=c.offsetWidth>0&&K(N.width)/c.offsetWidth||1,$=c.offsetHeight>0&&K(N.height)/c.offsetHeight||1);var re=ne(c)?oe(c):window,ee=re.visualViewport,de=!W()&&A,ue=(N.left+(de&&ee?ee.offsetLeft:0))/O,ve=(N.top+(de&&ee?ee.offsetTop:0))/$,Be=N.width/O,ze=N.height/$;return{width:Be,height:ze,top:ve,right:ue+Be,bottom:ve+ze,left:ue,x:ue,y:ve}}function ae(c){var h=oe(c),A=h.pageXOffset,N=h.pageYOffset;return{scrollLeft:A,scrollTop:N}}function he(c){return{scrollLeft:c.scrollLeft,scrollTop:c.scrollTop}}function Te(c){return c===oe(c)||!te(c)?ae(c):he(c)}function ye(c){return c?(c.nodeName||"").toLowerCase():null}function xe(c){return((ne(c)?c.ownerDocument:c.document)||window.document).documentElement}function Ae(c){return H(xe(c)).left+ae(c).scrollLeft}function Pe(c){return oe(c).getComputedStyle(c)}function me(c){var h=Pe(c),A=h.overflow,N=h.overflowX,O=h.overflowY;return/auto|scroll|overlay|hidden/.test(A+O+N)}function Ye(c){var h=c.getBoundingClientRect(),A=K(h.width)/c.offsetWidth||1,N=K(h.height)/c.offsetHeight||1;return A!==1||N!==1}function Qe(c,h,A){A===void 0&&(A=!1);var N=te(h),O=te(h)&&Ye(h),$=xe(h),re=H(c,O,A),ee={scrollLeft:0,scrollTop:0},de={x:0,y:0};return(N||!N&&!A)&&((ye(h)!=="body"||me($))&&(ee=Te(h)),te(h)?(de=H(h,!0),de.x+=h.clientLeft,de.y+=h.clientTop):$&&(de.x=Ae($))),{x:re.left+ee.scrollLeft-de.x,y:re.top+ee.scrollTop-de.y,width:re.width,height:re.height}}function yt(c){var h=H(c),A=c.offsetWidth,N=c.offsetHeight;return Math.abs(h.width-A)<=1&&(A=h.width),Math.abs(h.height-N)<=1&&(N=h.height),{x:c.offsetLeft,y:c.offsetTop,width:A,height:N}}function ut(c){return ye(c)==="html"?c:c.assignedSlot||c.parentNode||(pe(c)?c.host:null)||xe(c)}function Ie(c){return["html","body","#document"].indexOf(ye(c))>=0?c.ownerDocument.body:te(c)&&me(c)?c:Ie(ut(c))}function De(c,h){var A;h===void 0&&(h=[]);var N=Ie(c),O=N===((A=c.ownerDocument)==null?void 0:A.body),$=oe(N),re=O?[$].concat($.visualViewport||[],me(N)?N:[]):N,ee=h.concat(re);return O?ee:ee.concat(De(ut(re)))}function be(c){return["table","td","th"].indexOf(ye(c))>=0}function Xe(c){return!te(c)||Pe(c).position==="fixed"?null:c.offsetParent}function lt(c){var h=/firefox/i.test(_()),A=/Trident/i.test(_());if(A&&te(c)){var N=Pe(c);if(N.position==="fixed")return null}var O=ut(c);for(pe(O)&&(O=O.host);te(O)&&["html","body"].indexOf(ye(O))<0;){var $=Pe(O);if($.transform!=="none"||$.perspective!=="none"||$.contain==="paint"||["transform","perspective"].indexOf($.willChange)!==-1||h&&$.willChange==="filter"||h&&$.filter&&$.filter!=="none")return O;O=O.parentNode}return null}function tt(c){for(var h=oe(c),A=Xe(c);A&&be(A)&&Pe(A).position==="static";)A=Xe(A);return A&&(ye(A)==="html"||ye(A)==="body"&&Pe(A).position==="static")?h:A||lt(c)||h}var ct="top",qe="bottom",Ue="right",Ge="left",$e="auto",Me=[ct,qe,Ue,Ge],Ne="start",We="end",_e="clippingParents",xt="viewport",bt="popper",Wt="reference",St=Me.reduce(function(c,h){return c.concat([h+"-"+Ne,h+"-"+We])},[]),et=[].concat(Me,[$e]).reduce(function(c,h){return c.concat([h,h+"-"+Ne,h+"-"+We])},[]),He="beforeRead",Ft="read",Ut="afterRead",fn="beforeMain",gn="main",kn="afterMain",Xn="beforeWrite",Lr="write",le="afterWrite",we=[He,Ft,Ut,fn,gn,kn,Xn,Lr,le];function ge(c){var h=new Map,A=new Set,N=[];c.forEach(function($){h.set($.name,$)});function O($){A.add($.name);var re=[].concat($.requires||[],$.requiresIfExists||[]);re.forEach(function(ee){if(!A.has(ee)){var de=h.get(ee);de&&O(de)}}),N.push($)}return c.forEach(function($){A.has($.name)||O($)}),N}function Oe(c){var h=ge(c);return we.reduce(function(A,N){return A.concat(h.filter(function(O){return O.phase===N}))},[])}function Fe(c){var h;return function(){return h||(h=new Promise(function(A){Promise.resolve().then(function(){h=void 0,A(c())})})),h}}function Ve(c){var h=c.reduce(function(A,N){var O=A[N.name];return A[N.name]=O?Object.assign({},O,N,{options:Object.assign({},O.options,N.options),data:Object.assign({},O.data,N.data)}):N,A},{});return Object.keys(h).map(function(A){return h[A]})}var pt={placement:"bottom",modifiers:[],strategy:"absolute"};function dt(){for(var c=arguments.length,h=new Array(c),A=0;A=0?"x":"y"}function kt(c){var h=c.reference,A=c.element,N=c.placement,O=N?Kt(N):null,$=N?qt(N):null,re=h.x+h.width/2-A.width/2,ee=h.y+h.height/2-A.height/2,de;switch(O){case ct:de={x:re,y:h.y-A.height};break;case qe:de={x:re,y:h.y+h.height};break;case Ue:de={x:h.x+h.width,y:ee};break;case Ge:de={x:h.x-A.width,y:ee};break;default:de={x:h.x,y:h.y}}var ue=O?Jt(O):null;if(ue!=null){var ve=ue==="y"?"height":"width";switch($){case Ne:de[ue]=de[ue]-(h[ve]/2-A[ve]/2);break;case We:de[ue]=de[ue]+(h[ve]/2-A[ve]/2);break;default:}}return de}function $n(c){var h=c.state,A=c.name;h.modifiersData[A]=kt({reference:h.rects.reference,element:h.rects.popper,strategy:"absolute",placement:h.placement})}var jn={name:"popperOffsets",enabled:!0,phase:"read",fn:$n,data:{}},ar={top:"auto",right:"auto",bottom:"auto",left:"auto"};function vo(c,h){var A=c.x,N=c.y,O=h.devicePixelRatio||1;return{x:K(A*O)/O||0,y:K(N*O)/O||0}}function jt(c){var h,A=c.popper,N=c.popperRect,O=c.placement,$=c.variation,re=c.offsets,ee=c.position,de=c.gpuAcceleration,ue=c.adaptive,ve=c.roundOffsets,Be=c.isFixed,ze=re.x,je=ze===void 0?0:ze,Ze=re.y,ot=Ze===void 0?0:Ze,st=typeof ve=="function"?ve({x:je,y:ot}):{x:je,y:ot};je=st.x,ot=st.y;var ft=re.hasOwnProperty("x"),vt=re.hasOwnProperty("y"),Ot=Ge,ht=ct,Lt=window;if(ue){var At=tt(A),Tt="clientHeight",Dt="clientWidth";if(At===oe(A)&&(At=xe(A),Pe(At).position!=="static"&&ee==="absolute"&&(Tt="scrollHeight",Dt="scrollWidth")),At=At,O===ct||(O===Ge||O===Ue)&&$===We){ht=qe;var Xt=Be&&At===Lt&&Lt.visualViewport?Lt.visualViewport.height:At[Tt];ot-=Xt-N.height,ot*=de?1:-1}if(O===Ge||(O===ct||O===qe)&&$===We){Ot=Ue;var Mt=Be&&At===Lt&&Lt.visualViewport?Lt.visualViewport.width:At[Dt];je-=Mt-N.width,je*=de?1:-1}}var It=Object.assign({position:ee},ue&&ar),wt=ve===!0?vo({x:je,y:ot},oe(A)):{x:je,y:ot};if(je=wt.x,ot=wt.y,de){var In;return Object.assign({},It,(In={},In[ht]=vt?"0":"",In[Ot]=ft?"0":"",In.transform=(Lt.devicePixelRatio||1)<=1?"translate("+je+"px, "+ot+"px)":"translate3d("+je+"px, "+ot+"px, 0)",In))}return Object.assign({},It,(h={},h[ht]=vt?ot+"px":"",h[Ot]=ft?je+"px":"",h.transform="",h))}function _t(c){var h=c.state,A=c.options,N=A.gpuAcceleration,O=N===void 0?!0:N,$=A.adaptive,re=$===void 0?!0:$,ee=A.roundOffsets,de=ee===void 0?!0:ee,ue={placement:Kt(h.placement),variation:qt(h.placement),popper:h.elements.popper,popperRect:h.rects.popper,gpuAcceleration:O,isFixed:h.options.strategy==="fixed"};h.modifiersData.popperOffsets!=null&&(h.styles.popper=Object.assign({},h.styles.popper,jt(Object.assign({},ue,{offsets:h.modifiersData.popperOffsets,position:h.options.strategy,adaptive:re,roundOffsets:de})))),h.modifiersData.arrow!=null&&(h.styles.arrow=Object.assign({},h.styles.arrow,jt(Object.assign({},ue,{offsets:h.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:de})))),h.attributes.popper=Object.assign({},h.attributes.popper,{"data-popper-placement":h.placement})}var po={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:_t,data:{}};function yn(c){var h=c.state;Object.keys(h.elements).forEach(function(A){var N=h.styles[A]||{},O=h.attributes[A]||{},$=h.elements[A];!te($)||!ye($)||(Object.assign($.style,N),Object.keys(O).forEach(function(re){var ee=O[re];ee===!1?$.removeAttribute(re):$.setAttribute(re,ee===!0?"":ee)}))})}function ur(c){var h=c.state,A={popper:{position:h.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(h.elements.popper.style,A.popper),h.styles=A,h.elements.arrow&&Object.assign(h.elements.arrow.style,A.arrow),function(){Object.keys(h.elements).forEach(function(N){var O=h.elements[N],$=h.attributes[N]||{},re=Object.keys(h.styles.hasOwnProperty(N)?h.styles[N]:A[N]),ee=re.reduce(function(de,ue){return de[ue]="",de},{});!te(O)||!ye(O)||(Object.assign(O.style,ee),Object.keys($).forEach(function(de){O.removeAttribute(de)}))})}}var en={name:"applyStyles",enabled:!0,phase:"write",fn:yn,effect:ur,requires:["computeStyles"]};function Or(c,h,A){var N=Kt(c),O=[Ge,ct].indexOf(N)>=0?-1:1,$=typeof A=="function"?A(Object.assign({},h,{placement:c})):A,re=$[0],ee=$[1];return re=re||0,ee=(ee||0)*O,[Ge,Ue].indexOf(N)>=0?{x:ee,y:re}:{x:re,y:ee}}function lr(c){var h=c.state,A=c.options,N=c.name,O=A.offset,$=O===void 0?[0,0]:O,re=et.reduce(function(ve,Be){return ve[Be]=Or(Be,h.rects,$),ve},{}),ee=re[h.placement],de=ee.x,ue=ee.y;h.modifiersData.popperOffsets!=null&&(h.modifiersData.popperOffsets.x+=de,h.modifiersData.popperOffsets.y+=ue),h.modifiersData[N]=re}var eo={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:lr},hr={left:"right",right:"left",bottom:"top",top:"bottom"};function ln(c){return c.replace(/left|right|bottom|top/g,function(h){return hr[h]})}var sn={start:"end",end:"start"};function An(c){return c.replace(/start|end/g,function(h){return sn[h]})}function Dr(c,h){var A=oe(c),N=xe(c),O=A.visualViewport,$=N.clientWidth,re=N.clientHeight,ee=0,de=0;if(O){$=O.width,re=O.height;var ue=W();(ue||!ue&&h==="fixed")&&(ee=O.offsetLeft,de=O.offsetTop)}return{width:$,height:re,x:ee+Ae(c),y:de}}function er(c){var h,A=xe(c),N=ae(c),O=(h=c.ownerDocument)==null?void 0:h.body,$=ce(A.scrollWidth,A.clientWidth,O?O.scrollWidth:0,O?O.clientWidth:0),re=ce(A.scrollHeight,A.clientHeight,O?O.scrollHeight:0,O?O.clientHeight:0),ee=-N.scrollLeft+Ae(c),de=-N.scrollTop;return Pe(O||A).direction==="rtl"&&(ee+=ce(A.clientWidth,O?O.clientWidth:0)-$),{width:$,height:re,x:ee,y:de}}function sr(c,h){var A=h.getRootNode&&h.getRootNode();if(c.contains(h))return!0;if(A&&pe(A)){var N=h;do{if(N&&c.isSameNode(N))return!0;N=N.parentNode||N.host}while(N)}return!1}function Fr(c){return Object.assign({},c,{left:c.x,top:c.y,right:c.x+c.width,bottom:c.y+c.height})}function hn(c,h){var A=H(c,!1,h==="fixed");return A.top=A.top+c.clientTop,A.left=A.left+c.clientLeft,A.bottom=A.top+c.clientHeight,A.right=A.left+c.clientWidth,A.width=c.clientWidth,A.height=c.clientHeight,A.x=A.left,A.y=A.top,A}function Wn(c,h,A){return h===xt?Fr(Dr(c,A)):ne(h)?hn(h,A):Fr(er(xe(c)))}function Qn(c){var h=De(ut(c)),A=["absolute","fixed"].indexOf(Pe(c).position)>=0,N=A&&te(c)?tt(c):c;return ne(N)?h.filter(function(O){return ne(O)&&sr(O,N)&&ye(O)!=="body"}):[]}function On(c,h,A,N){var O=h==="clippingParents"?Qn(c):[].concat(h),$=[].concat(O,[A]),re=$[0],ee=$.reduce(function(de,ue){var ve=Wn(c,ue,N);return de.top=ce(ve.top,de.top),de.right=q(ve.right,de.right),de.bottom=q(ve.bottom,de.bottom),de.left=ce(ve.left,de.left),de},Wn(c,re,N));return ee.width=ee.right-ee.left,ee.height=ee.bottom-ee.top,ee.x=ee.left,ee.y=ee.top,ee}function cr(){return{top:0,right:0,bottom:0,left:0}}function Co(c){return Object.assign({},cr(),c)}function qo(c,h){return h.reduce(function(A,N){return A[N]=c,A},{})}function Tr(c,h){h===void 0&&(h={});var A=h,N=A.placement,O=N===void 0?c.placement:N,$=A.strategy,re=$===void 0?c.strategy:$,ee=A.boundary,de=ee===void 0?_e:ee,ue=A.rootBoundary,ve=ue===void 0?xt:ue,Be=A.elementContext,ze=Be===void 0?bt:Be,je=A.altBoundary,Ze=je===void 0?!1:je,ot=A.padding,st=ot===void 0?0:ot,ft=Co(typeof st!="number"?st:qo(st,Me)),vt=ze===bt?Wt:bt,Ot=c.rects.popper,ht=c.elements[Ze?vt:ze],Lt=On(ne(ht)?ht:ht.contextElement||xe(c.elements.popper),de,ve,re),At=H(c.elements.reference),Tt=kt({reference:At,element:Ot,strategy:"absolute",placement:O}),Dt=Fr(Object.assign({},Ot,Tt)),Xt=ze===bt?Dt:At,Mt={top:Lt.top-Xt.top+ft.top,bottom:Xt.bottom-Lt.bottom+ft.bottom,left:Lt.left-Xt.left+ft.left,right:Xt.right-Lt.right+ft.right},It=c.modifiersData.offset;if(ze===bt&&It){var wt=It[O];Object.keys(Mt).forEach(function(In){var Gn=[Ue,qe].indexOf(In)>=0?1:-1,Un=[ct,qe].indexOf(In)>=0?"y":"x";Mt[In]+=wt[Un]*Gn})}return Mt}function wn(c,h){h===void 0&&(h={});var A=h,N=A.placement,O=A.boundary,$=A.rootBoundary,re=A.padding,ee=A.flipVariations,de=A.allowedAutoPlacements,ue=de===void 0?et:de,ve=qt(N),Be=ve?ee?St:St.filter(function(Ze){return qt(Ze)===ve}):Me,ze=Be.filter(function(Ze){return ue.indexOf(Ze)>=0});ze.length===0&&(ze=Be);var je=ze.reduce(function(Ze,ot){return Ze[ot]=Tr(c,{placement:ot,boundary:O,rootBoundary:$,padding:re})[Kt(ot)],Ze},{});return Object.keys(je).sort(function(Ze,ot){return je[Ze]-je[ot]})}function Pr(c){if(Kt(c)===$e)return[];var h=ln(c);return[An(c),h,An(h)]}function mr(c){var h=c.state,A=c.options,N=c.name;if(!h.modifiersData[N]._skip){for(var O=A.mainAxis,$=O===void 0?!0:O,re=A.altAxis,ee=re===void 0?!0:re,de=A.fallbackPlacements,ue=A.padding,ve=A.boundary,Be=A.rootBoundary,ze=A.altBoundary,je=A.flipVariations,Ze=je===void 0?!0:je,ot=A.allowedAutoPlacements,st=h.options.placement,ft=Kt(st),vt=ft===st,Ot=de||(vt||!Ze?[ln(st)]:Pr(st)),ht=[st].concat(Ot).reduce(function(To,Lo){return To.concat(Kt(Lo)===$e?wn(h,{placement:Lo,boundary:ve,rootBoundary:Be,padding:ue,flipVariations:Ze,allowedAutoPlacements:ot}):Lo)},[]),Lt=h.rects.reference,At=h.rects.popper,Tt=new Map,Dt=!0,Xt=ht[0],Mt=0;Mt=0,Un=Gn?"width":"height",Yn=Tr(h,{placement:It,boundary:ve,rootBoundary:Be,altBoundary:ze,padding:ue}),wr=Gn?In?Ue:Ge:In?qe:ct;Lt[Un]>At[Un]&&(wr=ln(wr));var Zo=ln(wr),Oo=[];if($&&Oo.push(Yn[wt]<=0),ee&&Oo.push(Yn[wr]<=0,Yn[Zo]<=0),Oo.every(function(To){return To})){Xt=It,Dt=!1;break}Tt.set(It,Oo)}if(Dt)for(var Va=Ze?3:1,xu=function(Lo){var ga=ht.find(function(ui){var Io=Tt.get(ui);if(Io)return Io.slice(0,Lo).every(function(Ki){return Ki})});if(ga)return Xt=ga,"break"},Vi=Va;Vi>0;Vi--){var ai=xu(Vi);if(ai==="break")break}h.placement!==Xt&&(h.modifiersData[N]._skip=!0,h.placement=Xt,h.reset=!0)}}var pi={name:"flip",enabled:!0,phase:"main",fn:mr,requiresIfExists:["offset"],data:{_skip:!1}};function hi(c){return c==="x"?"y":"x"}function Zr(c,h,A){return ce(c,q(h,A))}function mi(c,h,A){var N=Zr(c,h,A);return N>A?A:N}function ko(c){var h=c.state,A=c.options,N=c.name,O=A.mainAxis,$=O===void 0?!0:O,re=A.altAxis,ee=re===void 0?!1:re,de=A.boundary,ue=A.rootBoundary,ve=A.altBoundary,Be=A.padding,ze=A.tether,je=ze===void 0?!0:ze,Ze=A.tetherOffset,ot=Ze===void 0?0:Ze,st=Tr(h,{boundary:de,rootBoundary:ue,padding:Be,altBoundary:ve}),ft=Kt(h.placement),vt=qt(h.placement),Ot=!vt,ht=Jt(ft),Lt=hi(ht),At=h.modifiersData.popperOffsets,Tt=h.rects.reference,Dt=h.rects.popper,Xt=typeof ot=="function"?ot(Object.assign({},h.rects,{placement:h.placement})):ot,Mt=typeof Xt=="number"?{mainAxis:Xt,altAxis:Xt}:Object.assign({mainAxis:0,altAxis:0},Xt),It=h.modifiersData.offset?h.modifiersData.offset[h.placement]:null,wt={x:0,y:0};if(At){if($){var In,Gn=ht==="y"?ct:Ge,Un=ht==="y"?qe:Ue,Yn=ht==="y"?"height":"width",wr=At[ht],Zo=wr+st[Gn],Oo=wr-st[Un],Va=je?-Dt[Yn]/2:0,xu=vt===Ne?Tt[Yn]:Dt[Yn],Vi=vt===Ne?-Dt[Yn]:-Tt[Yn],ai=h.elements.arrow,To=je&&ai?yt(ai):{width:0,height:0},Lo=h.modifiersData["arrow#persistent"]?h.modifiersData["arrow#persistent"].padding:cr(),ga=Lo[Gn],ui=Lo[Un],Io=Zr(0,Tt[Yn],To[Yn]),Ki=Ot?Tt[Yn]/2-Va-Io-ga-Mt.mainAxis:xu-Io-ga-Mt.mainAxis,io=Ot?-Tt[Yn]/2+Va+Io+ui+Mt.mainAxis:Vi+Io+ui+Mt.mainAxis,Vr=h.elements.arrow&&tt(h.elements.arrow),Ii=Vr?ht==="y"?Vr.clientTop||0:Vr.clientLeft||0:0,Do=(In=It==null?void 0:It[ht])!=null?In:0,wi=wr+Ki-Do-Ii,Hi=wr+io-Do,Gi=Zr(je?q(Zo,wi):Zo,wr,je?ce(Oo,Hi):Oo);At[ht]=Gi,wt[ht]=Gi-wr}if(ee){var Su,Dn=ht==="x"?ct:Ge,Nn=ht==="x"?qe:Ue,Fo=At[Lt],Yi=Lt==="y"?"height":"width",ya=Fo+st[Dn],xa=Fo-st[Nn],Jo=[ct,Ge].indexOf(ft)!==-1,Sn=(Su=It==null?void 0:It[Lt])!=null?Su:0,Qt=Jo?ya:Fo-Tt[Yi]-Dt[Yi]-Sn+Mt.altAxis,rn=Jo?Fo+Tt[Yi]+Dt[Yi]-Sn-Mt.altAxis:xa,Jn=je&&Jo?mi(Qt,Fo,rn):Zr(je?Qt:ya,Fo,je?rn:xa);At[Lt]=Jn,wt[Lt]=Jn-Fo}h.modifiersData[N]=wt}}var tr={name:"preventOverflow",enabled:!0,phase:"main",fn:ko,requiresIfExists:["offset"]},Ar=function(h,A){return h=typeof h=="function"?h(Object.assign({},A.rects,{placement:A.placement})):h,Co(typeof h!="number"?h:qo(h,Me))};function Jr(c){var h,A=c.state,N=c.name,O=c.options,$=A.elements.arrow,re=A.modifiersData.popperOffsets,ee=Kt(A.placement),de=Jt(ee),ue=[Ge,Ue].indexOf(ee)>=0,ve=ue?"height":"width";if(!(!$||!re)){var Be=Ar(O.padding,A),ze=yt($),je=de==="y"?ct:Ge,Ze=de==="y"?qe:Ue,ot=A.rects.reference[ve]+A.rects.reference[de]-re[de]-A.rects.popper[ve],st=re[de]-A.rects.reference[de],ft=tt($),vt=ft?de==="y"?ft.clientHeight||0:ft.clientWidth||0:0,Ot=ot/2-st/2,ht=Be[je],Lt=vt-ze[ve]-Be[Ze],At=vt/2-ze[ve]/2+Ot,Tt=Zr(ht,At,Lt),Dt=de;A.modifiersData[N]=(h={},h[Dt]=Tt,h.centerOffset=Tt-At,h)}}function tn(c){var h=c.state,A=c.options,N=A.element,O=N===void 0?"[data-popper-arrow]":N;O!=null&&(typeof O=="string"&&(O=h.elements.popper.querySelector(O),!O)||sr(h.elements.popper,O)&&(h.elements.arrow=O))}var un={name:"arrow",enabled:!0,phase:"main",fn:Jr,effect:tn,requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function _o(c,h,A){return A===void 0&&(A={x:0,y:0}),{top:c.top-h.height-A.y,right:c.right-h.width+A.x,bottom:c.bottom-h.height+A.y,left:c.left-h.width-A.x}}function ho(c){return[ct,Ue,qe,Ge].some(function(h){return c[h]>=0})}function Pa(c){var h=c.state,A=c.name,N=h.rects.reference,O=h.rects.popper,$=h.modifiersData.preventOverflow,re=Tr(h,{elementContext:"reference"}),ee=Tr(h,{altBoundary:!0}),de=_o(re,N),ue=_o(ee,O,$),ve=ho(de),Be=ho(ue);h.modifiersData[A]={referenceClippingOffsets:de,popperEscapeOffsets:ue,isReferenceHidden:ve,hasPopperEscaped:Be},h.attributes.popper=Object.assign({},h.attributes.popper,{"data-popper-reference-hidden":ve,"data-popper-escaped":Be})}var tu={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:Pa},Zn=[Bt,jn,po,en,eo,pi,tr,un,tu],Po=Rt({defaultModifiers:Zn}),ei=n(53833);function Rr(){return Rr=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}var V=/-o$/,G=function(c){var h=c.name,A=c.size,N=c.spin,O=c.className,$=c.rotation,re=F(c,["name","size","spin","className","rotation"]),ee=re.style||{};A&&(ee.fontSize=A*100+"%"),$&&(ee.transform="rotate("+$+"deg)"),re.style=ee;var de=(0,M.Fl)(re),ue="";if(h.startsWith("tg-"))ue=h;else{var ve=V.test(h),Be=h.replace(V,""),ze=!Be.startsWith("fa-");ue=ve?"far ":"fas ",ze&&(ue+="fa-"),ue+=Be,N&&(ue+=" fa-spin")}return(0,i.jsx)("i",L({className:(0,B.Ly)(["Icon",ue,O,(0,M.WP)(re)])},de))},J=function(c){var h=c.className,A=c.children,N=F(c,["className","children"]);return(0,i.jsx)("span",L({className:(0,B.Ly)(["IconStack",h,(0,M.WP)(N)])},(0,M.Fl)(N),{children:A}))};G.Stack=J;function oe(c){if(c==null)return window;if(c.toString()!=="[object Window]"){var h=c.ownerDocument;return h&&h.defaultView||window}return c}function Z(c,h){return h!=null&&typeof Symbol!="undefined"&&h[Symbol.hasInstance]?!!h[Symbol.hasInstance](c):c instanceof h}function ne(c){var h=oe(c).Element;return Z(c,h)||Z(c,Element)}function te(c){var h=oe(c).HTMLElement;return Z(c,h)||Z(c,HTMLElement)}function pe(c){if(typeof ShadowRoot=="undefined")return!1;var h=oe(c).ShadowRoot;return Z(c,h)||Z(c,ShadowRoot)}var ce=Math.max,q=Math.min,K=Math.round;function _(){var c=navigator.userAgentData;return c!=null&&c.brands&&Array.isArray(c.brands)?c.brands.map(function(h){return h.brand+"/"+h.version}).join(" "):navigator.userAgent}function W(){return!/^((?!chrome|android).)*safari/i.test(_())}function H(c,h,A){h===void 0&&(h=!1),A===void 0&&(A=!1);var N=c.getBoundingClientRect(),O=1,$=1;h&&te(c)&&(O=c.offsetWidth>0&&K(N.width)/c.offsetWidth||1,$=c.offsetHeight>0&&K(N.height)/c.offsetHeight||1);var re=ne(c)?oe(c):window,ee=re.visualViewport,de=!W()&&A,ue=(N.left+(de&&ee?ee.offsetLeft:0))/O,ve=(N.top+(de&&ee?ee.offsetTop:0))/$,Be=N.width/O,ze=N.height/$;return{width:Be,height:ze,top:ve,right:ue+Be,bottom:ve+ze,left:ue,x:ue,y:ve}}function ae(c){var h=oe(c),A=h.pageXOffset,N=h.pageYOffset;return{scrollLeft:A,scrollTop:N}}function he(c){return{scrollLeft:c.scrollLeft,scrollTop:c.scrollTop}}function Te(c){return c===oe(c)||!te(c)?ae(c):he(c)}function ye(c){return c?(c.nodeName||"").toLowerCase():null}function xe(c){return((ne(c)?c.ownerDocument:c.document)||window.document).documentElement}function Ae(c){return H(xe(c)).left+ae(c).scrollLeft}function Pe(c){return oe(c).getComputedStyle(c)}function me(c){var h=Pe(c),A=h.overflow,N=h.overflowX,O=h.overflowY;return/auto|scroll|overlay|hidden/.test(A+O+N)}function Ye(c){var h=c.getBoundingClientRect(),A=K(h.width)/c.offsetWidth||1,N=K(h.height)/c.offsetHeight||1;return A!==1||N!==1}function Qe(c,h,A){A===void 0&&(A=!1);var N=te(h),O=te(h)&&Ye(h),$=xe(h),re=H(c,O,A),ee={scrollLeft:0,scrollTop:0},de={x:0,y:0};return(N||!N&&!A)&&((ye(h)!=="body"||me($))&&(ee=Te(h)),te(h)?(de=H(h,!0),de.x+=h.clientLeft,de.y+=h.clientTop):$&&(de.x=Ae($))),{x:re.left+ee.scrollLeft-de.x,y:re.top+ee.scrollTop-de.y,width:re.width,height:re.height}}function yt(c){var h=H(c),A=c.offsetWidth,N=c.offsetHeight;return Math.abs(h.width-A)<=1&&(A=h.width),Math.abs(h.height-N)<=1&&(N=h.height),{x:c.offsetLeft,y:c.offsetTop,width:A,height:N}}function ut(c){return ye(c)==="html"?c:c.assignedSlot||c.parentNode||(pe(c)?c.host:null)||xe(c)}function Ie(c){return["html","body","#document"].indexOf(ye(c))>=0?c.ownerDocument.body:te(c)&&me(c)?c:Ie(ut(c))}function De(c,h){var A;h===void 0&&(h=[]);var N=Ie(c),O=N===((A=c.ownerDocument)==null?void 0:A.body),$=oe(N),re=O?[$].concat($.visualViewport||[],me(N)?N:[]):N,ee=h.concat(re);return O?ee:ee.concat(De(ut(re)))}function be(c){return["table","td","th"].indexOf(ye(c))>=0}function Xe(c){return!te(c)||Pe(c).position==="fixed"?null:c.offsetParent}function lt(c){var h=/firefox/i.test(_()),A=/Trident/i.test(_());if(A&&te(c)){var N=Pe(c);if(N.position==="fixed")return null}var O=ut(c);for(pe(O)&&(O=O.host);te(O)&&["html","body"].indexOf(ye(O))<0;){var $=Pe(O);if($.transform!=="none"||$.perspective!=="none"||$.contain==="paint"||["transform","perspective"].indexOf($.willChange)!==-1||h&&$.willChange==="filter"||h&&$.filter&&$.filter!=="none")return O;O=O.parentNode}return null}function tt(c){for(var h=oe(c),A=Xe(c);A&&be(A)&&Pe(A).position==="static";)A=Xe(A);return A&&(ye(A)==="html"||ye(A)==="body"&&Pe(A).position==="static")?h:A||lt(c)||h}var ct="top",qe="bottom",Ue="right",Ge="left",$e="auto",Me=[ct,qe,Ue,Ge],Ne="start",We="end",_e="clippingParents",xt="viewport",bt="popper",Wt="reference",St=Me.reduce(function(c,h){return c.concat([h+"-"+Ne,h+"-"+We])},[]),et=[].concat(Me,[$e]).reduce(function(c,h){return c.concat([h,h+"-"+Ne,h+"-"+We])},[]),He="beforeRead",Ft="read",Ut="afterRead",fn="beforeMain",gn="main",$n="afterMain",Xn="beforeWrite",Lr="write",le="afterWrite",we=[He,Ft,Ut,fn,gn,$n,Xn,Lr,le];function ge(c){var h=new Map,A=new Set,N=[];c.forEach(function($){h.set($.name,$)});function O($){A.add($.name);var re=[].concat($.requires||[],$.requiresIfExists||[]);re.forEach(function(ee){if(!A.has(ee)){var de=h.get(ee);de&&O(de)}}),N.push($)}return c.forEach(function($){A.has($.name)||O($)}),N}function Oe(c){var h=ge(c);return we.reduce(function(A,N){return A.concat(h.filter(function(O){return O.phase===N}))},[])}function Fe(c){var h;return function(){return h||(h=new Promise(function(A){Promise.resolve().then(function(){h=void 0,A(c())})})),h}}function Ve(c){var h=c.reduce(function(A,N){var O=A[N.name];return A[N.name]=O?Object.assign({},O,N,{options:Object.assign({},O.options,N.options),data:Object.assign({},O.data,N.data)}):N,A},{});return Object.keys(h).map(function(A){return h[A]})}var pt={placement:"bottom",modifiers:[],strategy:"absolute"};function dt(){for(var c=arguments.length,h=new Array(c),A=0;A=0?"x":"y"}function kt(c){var h=c.reference,A=c.element,N=c.placement,O=N?Kt(N):null,$=N?qt(N):null,re=h.x+h.width/2-A.width/2,ee=h.y+h.height/2-A.height/2,de;switch(O){case ct:de={x:re,y:h.y-A.height};break;case qe:de={x:re,y:h.y+h.height};break;case Ue:de={x:h.x+h.width,y:ee};break;case Ge:de={x:h.x-A.width,y:ee};break;default:de={x:h.x,y:h.y}}var ue=O?Jt(O):null;if(ue!=null){var ve=ue==="y"?"height":"width";switch($){case Ne:de[ue]=de[ue]-(h[ve]/2-A[ve]/2);break;case We:de[ue]=de[ue]+(h[ve]/2-A[ve]/2);break;default:}}return de}function Wn(c){var h=c.state,A=c.name;h.modifiersData[A]=kt({reference:h.rects.reference,element:h.rects.popper,strategy:"absolute",placement:h.placement})}var jn={name:"popperOffsets",enabled:!0,phase:"read",fn:Wn,data:{}},ar={top:"auto",right:"auto",bottom:"auto",left:"auto"};function vo(c,h){var A=c.x,N=c.y,O=h.devicePixelRatio||1;return{x:K(A*O)/O||0,y:K(N*O)/O||0}}function jt(c){var h,A=c.popper,N=c.popperRect,O=c.placement,$=c.variation,re=c.offsets,ee=c.position,de=c.gpuAcceleration,ue=c.adaptive,ve=c.roundOffsets,Be=c.isFixed,ze=re.x,je=ze===void 0?0:ze,Ze=re.y,ot=Ze===void 0?0:Ze,st=typeof ve=="function"?ve({x:je,y:ot}):{x:je,y:ot};je=st.x,ot=st.y;var ft=re.hasOwnProperty("x"),vt=re.hasOwnProperty("y"),Ot=Ge,ht=ct,Lt=window;if(ue){var At=tt(A),Tt="clientHeight",Dt="clientWidth";if(At===oe(A)&&(At=xe(A),Pe(At).position!=="static"&&ee==="absolute"&&(Tt="scrollHeight",Dt="scrollWidth")),At=At,O===ct||(O===Ge||O===Ue)&&$===We){ht=qe;var Xt=Be&&At===Lt&&Lt.visualViewport?Lt.visualViewport.height:At[Tt];ot-=Xt-N.height,ot*=de?1:-1}if(O===Ge||(O===ct||O===qe)&&$===We){Ot=Ue;var Mt=Be&&At===Lt&&Lt.visualViewport?Lt.visualViewport.width:At[Dt];je-=Mt-N.width,je*=de?1:-1}}var It=Object.assign({position:ee},ue&&ar),wt=ve===!0?vo({x:je,y:ot},oe(A)):{x:je,y:ot};if(je=wt.x,ot=wt.y,de){var In;return Object.assign({},It,(In={},In[ht]=vt?"0":"",In[Ot]=ft?"0":"",In.transform=(Lt.devicePixelRatio||1)<=1?"translate("+je+"px, "+ot+"px)":"translate3d("+je+"px, "+ot+"px, 0)",In))}return Object.assign({},It,(h={},h[ht]=vt?ot+"px":"",h[Ot]=ft?je+"px":"",h.transform="",h))}function _t(c){var h=c.state,A=c.options,N=A.gpuAcceleration,O=N===void 0?!0:N,$=A.adaptive,re=$===void 0?!0:$,ee=A.roundOffsets,de=ee===void 0?!0:ee,ue={placement:Kt(h.placement),variation:qt(h.placement),popper:h.elements.popper,popperRect:h.rects.popper,gpuAcceleration:O,isFixed:h.options.strategy==="fixed"};h.modifiersData.popperOffsets!=null&&(h.styles.popper=Object.assign({},h.styles.popper,jt(Object.assign({},ue,{offsets:h.modifiersData.popperOffsets,position:h.options.strategy,adaptive:re,roundOffsets:de})))),h.modifiersData.arrow!=null&&(h.styles.arrow=Object.assign({},h.styles.arrow,jt(Object.assign({},ue,{offsets:h.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:de})))),h.attributes.popper=Object.assign({},h.attributes.popper,{"data-popper-placement":h.placement})}var po={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:_t,data:{}};function yn(c){var h=c.state;Object.keys(h.elements).forEach(function(A){var N=h.styles[A]||{},O=h.attributes[A]||{},$=h.elements[A];!te($)||!ye($)||(Object.assign($.style,N),Object.keys(O).forEach(function(re){var ee=O[re];ee===!1?$.removeAttribute(re):$.setAttribute(re,ee===!0?"":ee)}))})}function ur(c){var h=c.state,A={popper:{position:h.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(h.elements.popper.style,A.popper),h.styles=A,h.elements.arrow&&Object.assign(h.elements.arrow.style,A.arrow),function(){Object.keys(h.elements).forEach(function(N){var O=h.elements[N],$=h.attributes[N]||{},re=Object.keys(h.styles.hasOwnProperty(N)?h.styles[N]:A[N]),ee=re.reduce(function(de,ue){return de[ue]="",de},{});!te(O)||!ye(O)||(Object.assign(O.style,ee),Object.keys($).forEach(function(de){O.removeAttribute(de)}))})}}var en={name:"applyStyles",enabled:!0,phase:"write",fn:yn,effect:ur,requires:["computeStyles"]};function Or(c,h,A){var N=Kt(c),O=[Ge,ct].indexOf(N)>=0?-1:1,$=typeof A=="function"?A(Object.assign({},h,{placement:c})):A,re=$[0],ee=$[1];return re=re||0,ee=(ee||0)*O,[Ge,Ue].indexOf(N)>=0?{x:ee,y:re}:{x:re,y:ee}}function lr(c){var h=c.state,A=c.options,N=c.name,O=A.offset,$=O===void 0?[0,0]:O,re=et.reduce(function(ve,Be){return ve[Be]=Or(Be,h.rects,$),ve},{}),ee=re[h.placement],de=ee.x,ue=ee.y;h.modifiersData.popperOffsets!=null&&(h.modifiersData.popperOffsets.x+=de,h.modifiersData.popperOffsets.y+=ue),h.modifiersData[N]=re}var eo={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:lr},hr={left:"right",right:"left",bottom:"top",top:"bottom"};function ln(c){return c.replace(/left|right|bottom|top/g,function(h){return hr[h]})}var sn={start:"end",end:"start"};function An(c){return c.replace(/start|end/g,function(h){return sn[h]})}function Dr(c,h){var A=oe(c),N=xe(c),O=A.visualViewport,$=N.clientWidth,re=N.clientHeight,ee=0,de=0;if(O){$=O.width,re=O.height;var ue=W();(ue||!ue&&h==="fixed")&&(ee=O.offsetLeft,de=O.offsetTop)}return{width:$,height:re,x:ee+Ae(c),y:de}}function er(c){var h,A=xe(c),N=ae(c),O=(h=c.ownerDocument)==null?void 0:h.body,$=ce(A.scrollWidth,A.clientWidth,O?O.scrollWidth:0,O?O.clientWidth:0),re=ce(A.scrollHeight,A.clientHeight,O?O.scrollHeight:0,O?O.clientHeight:0),ee=-N.scrollLeft+Ae(c),de=-N.scrollTop;return Pe(O||A).direction==="rtl"&&(ee+=ce(A.clientWidth,O?O.clientWidth:0)-$),{width:$,height:re,x:ee,y:de}}function sr(c,h){var A=h.getRootNode&&h.getRootNode();if(c.contains(h))return!0;if(A&&pe(A)){var N=h;do{if(N&&c.isSameNode(N))return!0;N=N.parentNode||N.host}while(N)}return!1}function Fr(c){return Object.assign({},c,{left:c.x,top:c.y,right:c.x+c.width,bottom:c.y+c.height})}function hn(c,h){var A=H(c,!1,h==="fixed");return A.top=A.top+c.clientTop,A.left=A.left+c.clientLeft,A.bottom=A.top+c.clientHeight,A.right=A.left+c.clientWidth,A.width=c.clientWidth,A.height=c.clientHeight,A.x=A.left,A.y=A.top,A}function Vn(c,h,A){return h===xt?Fr(Dr(c,A)):ne(h)?hn(h,A):Fr(er(xe(c)))}function Qn(c){var h=De(ut(c)),A=["absolute","fixed"].indexOf(Pe(c).position)>=0,N=A&&te(c)?tt(c):c;return ne(N)?h.filter(function(O){return ne(O)&&sr(O,N)&&ye(O)!=="body"}):[]}function On(c,h,A,N){var O=h==="clippingParents"?Qn(c):[].concat(h),$=[].concat(O,[A]),re=$[0],ee=$.reduce(function(de,ue){var ve=Vn(c,ue,N);return de.top=ce(ve.top,de.top),de.right=q(ve.right,de.right),de.bottom=q(ve.bottom,de.bottom),de.left=ce(ve.left,de.left),de},Vn(c,re,N));return ee.width=ee.right-ee.left,ee.height=ee.bottom-ee.top,ee.x=ee.left,ee.y=ee.top,ee}function cr(){return{top:0,right:0,bottom:0,left:0}}function Co(c){return Object.assign({},cr(),c)}function qo(c,h){return h.reduce(function(A,N){return A[N]=c,A},{})}function Tr(c,h){h===void 0&&(h={});var A=h,N=A.placement,O=N===void 0?c.placement:N,$=A.strategy,re=$===void 0?c.strategy:$,ee=A.boundary,de=ee===void 0?_e:ee,ue=A.rootBoundary,ve=ue===void 0?xt:ue,Be=A.elementContext,ze=Be===void 0?bt:Be,je=A.altBoundary,Ze=je===void 0?!1:je,ot=A.padding,st=ot===void 0?0:ot,ft=Co(typeof st!="number"?st:qo(st,Me)),vt=ze===bt?Wt:bt,Ot=c.rects.popper,ht=c.elements[Ze?vt:ze],Lt=On(ne(ht)?ht:ht.contextElement||xe(c.elements.popper),de,ve,re),At=H(c.elements.reference),Tt=kt({reference:At,element:Ot,strategy:"absolute",placement:O}),Dt=Fr(Object.assign({},Ot,Tt)),Xt=ze===bt?Dt:At,Mt={top:Lt.top-Xt.top+ft.top,bottom:Xt.bottom-Lt.bottom+ft.bottom,left:Lt.left-Xt.left+ft.left,right:Xt.right-Lt.right+ft.right},It=c.modifiersData.offset;if(ze===bt&&It){var wt=It[O];Object.keys(Mt).forEach(function(In){var Gn=[Ue,qe].indexOf(In)>=0?1:-1,kn=[ct,qe].indexOf(In)>=0?"y":"x";Mt[In]+=wt[kn]*Gn})}return Mt}function wn(c,h){h===void 0&&(h={});var A=h,N=A.placement,O=A.boundary,$=A.rootBoundary,re=A.padding,ee=A.flipVariations,de=A.allowedAutoPlacements,ue=de===void 0?et:de,ve=qt(N),Be=ve?ee?St:St.filter(function(Ze){return qt(Ze)===ve}):Me,ze=Be.filter(function(Ze){return ue.indexOf(Ze)>=0});ze.length===0&&(ze=Be);var je=ze.reduce(function(Ze,ot){return Ze[ot]=Tr(c,{placement:ot,boundary:O,rootBoundary:$,padding:re})[Kt(ot)],Ze},{});return Object.keys(je).sort(function(Ze,ot){return je[Ze]-je[ot]})}function Pr(c){if(Kt(c)===$e)return[];var h=ln(c);return[An(c),h,An(h)]}function mr(c){var h=c.state,A=c.options,N=c.name;if(!h.modifiersData[N]._skip){for(var O=A.mainAxis,$=O===void 0?!0:O,re=A.altAxis,ee=re===void 0?!0:re,de=A.fallbackPlacements,ue=A.padding,ve=A.boundary,Be=A.rootBoundary,ze=A.altBoundary,je=A.flipVariations,Ze=je===void 0?!0:je,ot=A.allowedAutoPlacements,st=h.options.placement,ft=Kt(st),vt=ft===st,Ot=de||(vt||!Ze?[ln(st)]:Pr(st)),ht=[st].concat(Ot).reduce(function(To,Lo){return To.concat(Kt(Lo)===$e?wn(h,{placement:Lo,boundary:ve,rootBoundary:Be,padding:ue,flipVariations:Ze,allowedAutoPlacements:ot}):Lo)},[]),Lt=h.rects.reference,At=h.rects.popper,Tt=new Map,Dt=!0,Xt=ht[0],Mt=0;Mt=0,kn=Gn?"width":"height",Yn=Tr(h,{placement:It,boundary:ve,rootBoundary:Be,altBoundary:ze,padding:ue}),wr=Gn?In?Ue:Ge:In?qe:ct;Lt[kn]>At[kn]&&(wr=ln(wr));var Zo=ln(wr),Oo=[];if($&&Oo.push(Yn[wt]<=0),ee&&Oo.push(Yn[wr]<=0,Yn[Zo]<=0),Oo.every(function(To){return To})){Xt=It,Dt=!1;break}Tt.set(It,Oo)}if(Dt)for(var Va=Ze?3:1,xu=function(Lo){var ga=ht.find(function(ui){var Io=Tt.get(ui);if(Io)return Io.slice(0,Lo).every(function(Ki){return Ki})});if(ga)return Xt=ga,"break"},Vi=Va;Vi>0;Vi--){var ai=xu(Vi);if(ai==="break")break}h.placement!==Xt&&(h.modifiersData[N]._skip=!0,h.placement=Xt,h.reset=!0)}}var pi={name:"flip",enabled:!0,phase:"main",fn:mr,requiresIfExists:["offset"],data:{_skip:!1}};function hi(c){return c==="x"?"y":"x"}function Zr(c,h,A){return ce(c,q(h,A))}function mi(c,h,A){var N=Zr(c,h,A);return N>A?A:N}function ko(c){var h=c.state,A=c.options,N=c.name,O=A.mainAxis,$=O===void 0?!0:O,re=A.altAxis,ee=re===void 0?!1:re,de=A.boundary,ue=A.rootBoundary,ve=A.altBoundary,Be=A.padding,ze=A.tether,je=ze===void 0?!0:ze,Ze=A.tetherOffset,ot=Ze===void 0?0:Ze,st=Tr(h,{boundary:de,rootBoundary:ue,padding:Be,altBoundary:ve}),ft=Kt(h.placement),vt=qt(h.placement),Ot=!vt,ht=Jt(ft),Lt=hi(ht),At=h.modifiersData.popperOffsets,Tt=h.rects.reference,Dt=h.rects.popper,Xt=typeof ot=="function"?ot(Object.assign({},h.rects,{placement:h.placement})):ot,Mt=typeof Xt=="number"?{mainAxis:Xt,altAxis:Xt}:Object.assign({mainAxis:0,altAxis:0},Xt),It=h.modifiersData.offset?h.modifiersData.offset[h.placement]:null,wt={x:0,y:0};if(At){if($){var In,Gn=ht==="y"?ct:Ge,kn=ht==="y"?qe:Ue,Yn=ht==="y"?"height":"width",wr=At[ht],Zo=wr+st[Gn],Oo=wr-st[kn],Va=je?-Dt[Yn]/2:0,xu=vt===Ne?Tt[Yn]:Dt[Yn],Vi=vt===Ne?-Dt[Yn]:-Tt[Yn],ai=h.elements.arrow,To=je&&ai?yt(ai):{width:0,height:0},Lo=h.modifiersData["arrow#persistent"]?h.modifiersData["arrow#persistent"].padding:cr(),ga=Lo[Gn],ui=Lo[kn],Io=Zr(0,Tt[Yn],To[Yn]),Ki=Ot?Tt[Yn]/2-Va-Io-ga-Mt.mainAxis:xu-Io-ga-Mt.mainAxis,io=Ot?-Tt[Yn]/2+Va+Io+ui+Mt.mainAxis:Vi+Io+ui+Mt.mainAxis,Vr=h.elements.arrow&&tt(h.elements.arrow),Ii=Vr?ht==="y"?Vr.clientTop||0:Vr.clientLeft||0:0,Do=(In=It==null?void 0:It[ht])!=null?In:0,wi=wr+Ki-Do-Ii,Hi=wr+io-Do,Gi=Zr(je?q(Zo,wi):Zo,wr,je?ce(Oo,Hi):Oo);At[ht]=Gi,wt[ht]=Gi-wr}if(ee){var Su,Dn=ht==="x"?ct:Ge,Nn=ht==="x"?qe:Ue,Fo=At[Lt],Yi=Lt==="y"?"height":"width",ya=Fo+st[Dn],xa=Fo-st[Nn],Jo=[ct,Ge].indexOf(ft)!==-1,Sn=(Su=It==null?void 0:It[Lt])!=null?Su:0,Qt=Jo?ya:Fo-Tt[Yi]-Dt[Yi]-Sn+Mt.altAxis,rn=Jo?Fo+Tt[Yi]+Dt[Yi]-Sn-Mt.altAxis:xa,Jn=je&&Jo?mi(Qt,Fo,rn):Zr(je?Qt:ya,Fo,je?rn:xa);At[Lt]=Jn,wt[Lt]=Jn-Fo}h.modifiersData[N]=wt}}var tr={name:"preventOverflow",enabled:!0,phase:"main",fn:ko,requiresIfExists:["offset"]},Ar=function(h,A){return h=typeof h=="function"?h(Object.assign({},A.rects,{placement:A.placement})):h,Co(typeof h!="number"?h:qo(h,Me))};function Jr(c){var h,A=c.state,N=c.name,O=c.options,$=A.elements.arrow,re=A.modifiersData.popperOffsets,ee=Kt(A.placement),de=Jt(ee),ue=[Ge,Ue].indexOf(ee)>=0,ve=ue?"height":"width";if(!(!$||!re)){var Be=Ar(O.padding,A),ze=yt($),je=de==="y"?ct:Ge,Ze=de==="y"?qe:Ue,ot=A.rects.reference[ve]+A.rects.reference[de]-re[de]-A.rects.popper[ve],st=re[de]-A.rects.reference[de],ft=tt($),vt=ft?de==="y"?ft.clientHeight||0:ft.clientWidth||0:0,Ot=ot/2-st/2,ht=Be[je],Lt=vt-ze[ve]-Be[Ze],At=vt/2-ze[ve]/2+Ot,Tt=Zr(ht,At,Lt),Dt=de;A.modifiersData[N]=(h={},h[Dt]=Tt,h.centerOffset=Tt-At,h)}}function tn(c){var h=c.state,A=c.options,N=A.element,O=N===void 0?"[data-popper-arrow]":N;O!=null&&(typeof O=="string"&&(O=h.elements.popper.querySelector(O),!O)||sr(h.elements.popper,O)&&(h.elements.arrow=O))}var un={name:"arrow",enabled:!0,phase:"main",fn:Jr,effect:tn,requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function _o(c,h,A){return A===void 0&&(A={x:0,y:0}),{top:c.top-h.height-A.y,right:c.right-h.width+A.x,bottom:c.bottom-h.height+A.y,left:c.left-h.width-A.x}}function ho(c){return[ct,Ue,qe,Ge].some(function(h){return c[h]>=0})}function Pa(c){var h=c.state,A=c.name,N=h.rects.reference,O=h.rects.popper,$=h.modifiersData.preventOverflow,re=Tr(h,{elementContext:"reference"}),ee=Tr(h,{altBoundary:!0}),de=_o(re,N),ue=_o(ee,O,$),ve=ho(de),Be=ho(ue);h.modifiersData[A]={referenceClippingOffsets:de,popperEscapeOffsets:ue,isReferenceHidden:ve,hasPopperEscaped:Be},h.attributes.popper=Object.assign({},h.attributes.popper,{"data-popper-reference-hidden":ve,"data-popper-escaped":Be})}var tu={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:Pa},Zn=[Bt,jn,po,en,eo,pi,tr,un,tu],Po=Rt({defaultModifiers:Zn}),ei=n(53833);function Rr(){return Rr=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}function Aa(c,h){var A,N,O,$,re={label:0,sent:function(){if(O[0]&1)throw O[1];return O[1]},trys:[],ops:[]};return $={next:ee(0),throw:ee(1),return:ee(2)},typeof Symbol=="function"&&($[Symbol.iterator]=function(){return this}),$;function ee(ue){return function(ve){return de([ue,ve])}}function de(ue){if(A)throw new TypeError("Generator is already executing.");for(;re;)try{if(A=1,N&&(O=ue[0]&2?N.return:ue[0]?N.throw||((O=N.return)&&O.call(N),0):N.next)&&!(O=O.call(N,ue[1])).done)return O;switch(N=0,O&&(ue=[ue[0]&2,O.value]),ue[0]){case 0:case 1:O=ue;break;case 4:return re.label++,{value:ue[1],done:!1};case 5:re.label++,N=ue[1],ue=[0];continue;case 7:ue=re.ops.pop(),re.trys.pop();continue;default:if(O=re.trys,!(O=O.length>0&&O[O.length-1])&&(ue[0]===6||ue[0]===2)){re=0;continue}if(ue[0]===3&&(!O||ue[1]>O[0]&&ue[1]=0)&&(A[O]=c[O]);return A}function Aa(c,h){var A,N,O,$,re={label:0,sent:function(){if(O[0]&1)throw O[1];return O[1]},trys:[],ops:[]};return $={next:ee(0),throw:ee(1),return:ee(2)},typeof Symbol=="function"&&($[Symbol.iterator]=function(){return this}),$;function ee(ue){return function(ve){return de([ue,ve])}}function de(ue){if(A)throw new TypeError("Generator is already executing.");for(;re;)try{if(A=1,N&&(O=ue[0]&2?N.return:ue[0]?N.throw||((O=N.return)&&O.call(N),0):N.next)&&!(O=O.call(N,ue[1])).done)return O;switch(N=0,O&&(ue=[ue[0]&2,O.value]),ue[0]){case 0:case 1:O=ue;break;case 4:return re.label++,{value:ue[1],done:!1};case 5:re.label++,N=ue[1],ue=[0];continue;case 7:ue=re.ops.pop(),re.trys.pop();continue;default:if(O=re.trys,!(O=O.length>0&&O[O.length-1])&&(ue[0]===6||ue[0]===2)){re=0;continue}if(ue[0]===3&&(!O||ue[1]>O[0]&&ue[1]0&&(O.setState({suppressingFlicker:!0}),clearTimeout(O.flickerTimer),O.flickerTimer=setTimeout(function(){O.setState({suppressingFlicker:!1})},$))},O.handleDragStart=function($){var re=O.props,ee=re.value,de=re.dragMatrix,ue=O.state.editing;ue||(document.body.style["pointer-events"]="none",O.ref=$.target,O.setState({dragging:!1,origin:vl($,de),value:ee,internalValue:ee}),O.timer=setTimeout(function(){O.setState({dragging:!0})},250),O.dragInterval=setInterval(function(){var ve=O.state,Be=ve.dragging,ze=ve.value,je=O.props.onDrag;Be&&je&&je($,ze)},O.props.updateRate||dl),document.addEventListener("mousemove",O.handleDragMove),document.addEventListener("mouseup",O.handleDragEnd))},O.handleDragMove=function($){var re=O.props,ee=re.minValue,de=re.maxValue,ue=re.step,ve=re.stepPixelSize,Be=re.dragMatrix;O.setState(function(ze){var je=fl({},ze),Ze=vl($,Be)-je.origin;if(ze.dragging){var ot=Number.isFinite(ee)?ee%ue:0;je.internalValue=(0,u.qE)(je.internalValue+Ze*ue/ve,ee-ue,de+ue),je.value=(0,u.qE)(je.internalValue-je.internalValue%ue+ot,ee,de),je.origin=vl($,Be)}else Math.abs(Ze)>4&&(je.dragging=!0);return je})},O.handleDragEnd=function($){var re=O.props,ee=re.onChange,de=re.onDrag,ue=O.state,ve=ue.dragging,Be=ue.value,ze=ue.internalValue;if(document.body.style["pointer-events"]="auto",clearTimeout(O.timer),clearInterval(O.dragInterval),O.setState({dragging:!1,editing:!ve,origin:null}),document.removeEventListener("mousemove",O.handleDragMove),document.removeEventListener("mouseup",O.handleDragEnd),ve)O.suppressFlicker(),ee&&ee($,Be),de&&de($,Be);else if(O.inputRef){var je=O.inputRef.current;je.value=ze;try{je.focus(),je.select()}catch(Ze){}}},O}var A=h.prototype;return A.render=function(){var O=this,$=this.state,re=$.dragging,ee=$.editing,de=$.value,ue=$.suppressingFlicker,ve=this.props,Be=ve.animated,ze=ve.value,je=ve.unit,Ze=ve.minValue,ot=ve.maxValue,st=ve.unclamped,ft=ve.format,vt=ve.onChange,Ot=ve.onDrag,ht=ve.children,Lt=ve.height,At=ve.lineHeight,Tt=ve.fontSize,Dt=ze;(re||ue)&&(Dt=de);var Xt=(0,i.jsxs)(i.Fragment,{children:[Be&&!re&&!ue?(0,i.jsx)(E,{value:Dt,format:ft}):ft?ft(Dt):Dt,je?" "+je:""]}),Mt=(0,i.jsx)("input",{ref:this.inputRef,className:"NumberInput__input",style:{display:ee?void 0:"none",height:Lt,lineHeight:At,fontsize:Tt},onBlur:function(It){if(ee){var wt;if(st?wt=parseFloat(It.target.value):wt=(0,u.qE)(parseFloat(It.target.value),Ze,ot),Number.isNaN(wt)){O.setState({editing:!1});return}O.setState({editing:!1,value:wt}),O.suppressFlicker(),vt&&vt(It,wt),Ot&&Ot(It,wt)}},onKeyDown:function(It){if(It.keyCode===13){var wt;if(st?wt=parseFloat(It.target.value):wt=(0,u.qE)(parseFloat(It.target.value),Ze,ot),Number.isNaN(wt)){O.setState({editing:!1});return}O.setState({editing:!1,value:wt}),O.suppressFlicker(),vt&&vt(It,wt),Ot&&Ot(It,wt);return}if(It.keyCode===27){O.setState({editing:!1});return}}});return ht({dragging:re,editing:ee,value:ze,displayValue:Dt,displayElement:Xt,inputElement:Mt,handleDragStart:this.handleDragStart})},h}(s.Component);Nu.defaultProps={minValue:-1/0,maxValue:1/0,step:1,stepPixelSize:1,suppressFlicker:50,dragMatrix:[1,0]};var Jl=n(20878),ql=n.n(Jl),Uc=function(h){return Array.isArray(h)?h[0]:h},Gs=function(h){if(typeof h=="function"){for(var A=arguments.length,N=new Array(A>1?A-1:0),O=1;O0&&(O.setState({suppressingFlicker:!0}),clearTimeout(O.flickerTimer),O.flickerTimer=setTimeout(function(){O.setState({suppressingFlicker:!1})},$))},O.handleDragStart=function($){var re=O.props,ee=re.value,de=re.dragMatrix,ue=O.state.editing;ue||(document.body.style["pointer-events"]="none",O.ref=$.target,O.setState({dragging:!1,origin:vl($,de),value:ee,internalValue:ee}),O.timer=setTimeout(function(){O.setState({dragging:!0})},250),O.dragInterval=setInterval(function(){var ve=O.state,Be=ve.dragging,ze=ve.value,je=O.props.onDrag;Be&&je&&je($,ze)},O.props.updateRate||dl),document.addEventListener("mousemove",O.handleDragMove),document.addEventListener("mouseup",O.handleDragEnd))},O.handleDragMove=function($){var re=O.props,ee=re.minValue,de=re.maxValue,ue=re.step,ve=re.stepPixelSize,Be=re.dragMatrix;O.setState(function(ze){var je=fl({},ze),Ze=vl($,Be)-je.origin;if(ze.dragging){var ot=Number.isFinite(ee)?ee%ue:0;je.internalValue=(0,u.qE)(je.internalValue+Ze*ue/ve,ee-ue,de+ue),je.value=(0,u.qE)(je.internalValue-je.internalValue%ue+ot,ee,de),je.origin=vl($,Be)}else Math.abs(Ze)>4&&(je.dragging=!0);return je})},O.handleDragEnd=function($){var re=O.props,ee=re.onChange,de=re.onDrag,ue=O.state,ve=ue.dragging,Be=ue.value,ze=ue.internalValue;if(document.body.style["pointer-events"]="auto",clearTimeout(O.timer),clearInterval(O.dragInterval),O.setState({dragging:!1,editing:!ve,origin:null}),document.removeEventListener("mousemove",O.handleDragMove),document.removeEventListener("mouseup",O.handleDragEnd),ve)O.suppressFlicker(),ee&&ee($,Be),de&&de($,Be);else if(O.inputRef){var je=O.inputRef.current;je.value=ze;try{je.focus(),je.select()}catch(Ze){}}},O}var A=h.prototype;return A.render=function(){var O=this,$=this.state,re=$.dragging,ee=$.editing,de=$.value,ue=$.suppressingFlicker,ve=this.props,Be=ve.animated,ze=ve.value,je=ve.unit,Ze=ve.minValue,ot=ve.maxValue,st=ve.unclamped,ft=ve.format,vt=ve.onChange,Ot=ve.onDrag,ht=ve.children,Lt=ve.height,At=ve.lineHeight,Tt=ve.fontSize,Dt=ze;(re||ue)&&(Dt=de);var Xt=(0,i.jsxs)(i.Fragment,{children:[Be&&!re&&!ue?(0,i.jsx)(E,{value:Dt,format:ft}):ft?ft(Dt):Dt,je?" "+je:""]}),Mt=(0,i.jsx)("input",{ref:this.inputRef,className:"NumberInput__input",style:{display:ee?void 0:"none",height:Lt,lineHeight:At,fontsize:Tt},onBlur:function(It){if(ee){var wt;if(st?wt=parseFloat(It.target.value):wt=(0,u.qE)(parseFloat(It.target.value),Ze,ot),Number.isNaN(wt)){O.setState({editing:!1});return}O.setState({editing:!1,value:wt}),O.suppressFlicker(),vt&&vt(It,wt),Ot&&Ot(It,wt)}},onKeyDown:function(It){if(It.keyCode===13){var wt;if(st?wt=parseFloat(It.target.value):wt=(0,u.qE)(parseFloat(It.target.value),Ze,ot),Number.isNaN(wt)){O.setState({editing:!1});return}O.setState({editing:!1,value:wt}),O.suppressFlicker(),vt&&vt(It,wt),Ot&&Ot(It,wt);return}if(It.keyCode===27){O.setState({editing:!1});return}}});return ht({dragging:re,editing:ee,value:ze,displayValue:Dt,displayElement:Xt,inputElement:Mt,handleDragStart:this.handleDragStart})},h}(s.Component);Nu.defaultProps={minValue:-1/0,maxValue:1/0,step:1,stepPixelSize:1,suppressFlicker:50,dragMatrix:[1,0]};var Jl=n(20878),ql=n.n(Jl),kc=function(h){return Array.isArray(h)?h[0]:h},Gs=function(h){if(typeof h=="function"){for(var A=arguments.length,N=new Array(A>1?A-1:0),O=1;O=0)&&(A[O]=c[O]);return A}var Bu=function(c){var h=c.children,A=Da(c,["children"]);return(0,i.jsx)(Fu.XI,Fi({},A,{children:(0,i.jsx)(Fu.XI.Row,{children:h})}))},ml=function(c){var h=c.size,A=h===void 0?1:h,N=c.style,O=Da(c,["size","style"]);return(0,i.jsx)(Fu.XI.Cell,Fi({style:Fi({width:A+"%"},N)},O))};Bu.Column=ml;function Fa(){return Fa=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}var Wc=function(c){var h=c.className,A=c.fixBlur,N=A===void 0?!0:A,O=c.objectFit,$=O===void 0?"fill":O,re=c.src,ee=c.tooltip,de=rs(c,["className","fixBlur","objectFit","src","tooltip"]),ue=computeBoxProps(de);ue.style=Fa({},ue.style,{"-ms-interpolation-mode":N?"nearest-neighbor":"auto",objectFit:$});var ve=_jsx("img",Fa({className:h,src:re},ue));return ee&&(ve=_jsx(Tooltip,{content:ee,children:ve})),ve},Xs=n(79500);/** + */function Fi(){return Fi=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}var Bu=function(c){var h=c.children,A=Da(c,["children"]);return(0,i.jsx)(Fu.XI,Fi({},A,{children:(0,i.jsx)(Fu.XI.Row,{children:h})}))},ml=function(c){var h=c.size,A=h===void 0?1:h,N=c.style,O=Da(c,["size","style"]);return(0,i.jsx)(Fu.XI.Cell,Fi({style:Fi({width:A+"%"},N)},O))};Bu.Column=ml;function Fa(){return Fa=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}var Xs=function(c){var h=c.className,A=c.fixBlur,N=A===void 0?!0:A,O=c.objectFit,$=O===void 0?"fill":O,re=c.src,ee=c.tooltip,de=rs(c,["className","fixBlur","objectFit","src","tooltip"]),ue=(0,M.Fl)(de);ue.style=Fa({},ue.style,{"-ms-interpolation-mode":N?"nearest-neighbor":"auto",objectFit:$});var ve=(0,i.jsx)("img",Fa({className:h,src:re},ue));return ee&&(ve=(0,i.jsx)(Bn,{content:ee,children:ve})),ve},Qs=n(79500);/** * @file * @copyright 2020 Aleksej Komarov * @license MIT - */function bu(){return bu=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}var Vo=function(c){var h=c.className,A=c.value,N=c.minValue,O=N===void 0?0:N,$=c.maxValue,re=$===void 0?1:$,ee=c.color,de=c.ranges,ue=de===void 0?{}:de,ve=c.children,Be=Qs(c,["className","value","minValue","maxValue","color","ranges","children"]),ze=(0,u.hs)(A,O,re),je=ve!==void 0,Ze=ee||(0,u.TG)(A,ue)||"default",ot=(0,M.Fl)(Be),st=["ProgressBar",h,(0,M.WP)(Be)],ft={width:(0,u.J$)(ze)*100+"%"};return Xs.NE.includes(Ze)||Ze==="default"?st.push("ProgressBar--color--"+Ze):(ot.style=bu({},ot.style,{borderColor:Ze}),ft.backgroundColor=Ze),(0,i.jsxs)("div",bu({className:(0,B.Ly)(st)},ot,{children:[(0,i.jsx)("div",{className:"ProgressBar__fill ProgressBar__fill--animated",style:ft}),(0,i.jsx)("div",{className:"ProgressBar__content",children:je?ve:(0,u.Mg)(ze*100)+"%"})]}))};/** + */function bu(){return bu=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}var Vo=function(c){var h=c.className,A=c.value,N=c.minValue,O=N===void 0?0:N,$=c.maxValue,re=$===void 0?1:$,ee=c.color,de=c.ranges,ue=de===void 0?{}:de,ve=c.children,Be=Zs(c,["className","value","minValue","maxValue","color","ranges","children"]),ze=(0,u.hs)(A,O,re),je=ve!==void 0,Ze=ee||(0,u.TG)(A,ue)||"default",ot=(0,M.Fl)(Be),st=["ProgressBar",h,(0,M.WP)(Be)],ft={width:(0,u.J$)(ze)*100+"%"};return Qs.NE.includes(Ze)||Ze==="default"?st.push("ProgressBar--color--"+Ze):(ot.style=bu({},ot.style,{borderColor:Ze}),ft.backgroundColor=Ze),(0,i.jsxs)("div",bu({className:(0,B.Ly)(st)},ot,{children:[(0,i.jsx)("div",{className:"ProgressBar__fill ProgressBar__fill--animated",style:ft}),(0,i.jsx)("div",{className:"ProgressBar__content",children:je?ve:(0,u.Mg)(ze*100)+"%"})]}))};/** * @file * @copyright 2021 Aleksej Komarov * @license MIT @@ -375,7 +375,7 @@ * @file * @copyright 2020 Aleksej Komarov * @license MIT - */function to(){return to=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}var Ol=function(c){var h=c.animated,A=c.format,N=c.maxValue,O=c.minValue,$=c.unclamped,re=c.onChange,ee=c.onDrag,de=c.step,ue=c.stepPixelSize,ve=c.suppressFlicker,Be=c.unit,ze=c.value,je=c.className,Ze=c.style,ot=c.fillValue,st=c.color,ft=c.ranges,vt=ft===void 0?{}:ft,Ot=c.size,ht=Ot===void 0?1:Ot,Lt=c.bipolar,At=c.children,Tt=cu(c,["animated","format","maxValue","minValue","unclamped","onChange","onDrag","step","stepPixelSize","suppressFlicker","unit","value","className","style","fillValue","color","ranges","size","bipolar","children"]);return(0,i.jsx)(Nu,{dragMatrix:[0,-1],animated:h,format:A,maxValue:N,minValue:O,unclamped:$,onChange:re,onDrag:ee,step:de,stepPixelSize:ue,suppressFlicker:ve,unit:Be,value:ze,children:function(Dt){var Xt=Dt.dragging,Mt=Dt.editing,It=Dt.value,wt=Dt.displayValue,In=Dt.displayElement,Gn=Dt.inputElement,Un=Dt.handleDragStart,Yn=(0,u.hs)(ot!=null?ot:wt,O,N),wr=(0,u.hs)(wt,O,N),Zo=st||(0,u.TG)(ot!=null?ot:It,vt)||"default",Oo=Math.min((wr-.5)*270,225);return(0,i.jsxs)("div",to({className:(0,B.Ly)(["Knob","Knob--color--"+Zo,Lt&&"Knob--bipolar",je,(0,M.WP)(Tt)])},(0,M.Fl)(to({style:to({fontSize:ht+"em"},Ze)},Tt)),{onMouseDown:Un,children:[(0,i.jsx)("div",{className:"Knob__circle",children:(0,i.jsx)("div",{className:"Knob__cursorBox",style:{transform:"rotate("+Oo+"deg)"},children:(0,i.jsx)("div",{className:"Knob__cursor"})})}),Xt&&(0,i.jsx)("div",{className:"Knob__popupValue",children:In}),(0,i.jsx)("svg",{className:"Knob__ring Knob__ringTrackPivot",viewBox:"0 0 100 100",children:(0,i.jsx)("circle",{className:"Knob__ringTrack",cx:"50",cy:"50",r:"50"})}),(0,i.jsx)("svg",{className:"Knob__ring Knob__ringFillPivot",viewBox:"0 0 100 100",children:(0,i.jsx)("circle",{className:"Knob__ringFill",style:{strokeDashoffset:Math.max(((Lt?2.75:2)-Yn*1.5)*Math.PI*50,0)},cx:"50",cy:"50",r:"50"})}),Gn]}))}})};/** + */function to(){return to=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}var Ol=function(c){var h=c.animated,A=c.format,N=c.maxValue,O=c.minValue,$=c.unclamped,re=c.onChange,ee=c.onDrag,de=c.step,ue=c.stepPixelSize,ve=c.suppressFlicker,Be=c.unit,ze=c.value,je=c.className,Ze=c.style,ot=c.fillValue,st=c.color,ft=c.ranges,vt=ft===void 0?{}:ft,Ot=c.size,ht=Ot===void 0?1:Ot,Lt=c.bipolar,At=c.children,Tt=cu(c,["animated","format","maxValue","minValue","unclamped","onChange","onDrag","step","stepPixelSize","suppressFlicker","unit","value","className","style","fillValue","color","ranges","size","bipolar","children"]);return(0,i.jsx)(Nu,{dragMatrix:[0,-1],animated:h,format:A,maxValue:N,minValue:O,unclamped:$,onChange:re,onDrag:ee,step:de,stepPixelSize:ue,suppressFlicker:ve,unit:Be,value:ze,children:function(Dt){var Xt=Dt.dragging,Mt=Dt.editing,It=Dt.value,wt=Dt.displayValue,In=Dt.displayElement,Gn=Dt.inputElement,kn=Dt.handleDragStart,Yn=(0,u.hs)(ot!=null?ot:wt,O,N),wr=(0,u.hs)(wt,O,N),Zo=st||(0,u.TG)(ot!=null?ot:It,vt)||"default",Oo=Math.min((wr-.5)*270,225);return(0,i.jsxs)("div",to({className:(0,B.Ly)(["Knob","Knob--color--"+Zo,Lt&&"Knob--bipolar",je,(0,M.WP)(Tt)])},(0,M.Fl)(to({style:to({fontSize:ht+"em"},Ze)},Tt)),{onMouseDown:kn,children:[(0,i.jsx)("div",{className:"Knob__circle",children:(0,i.jsx)("div",{className:"Knob__cursorBox",style:{transform:"rotate("+Oo+"deg)"},children:(0,i.jsx)("div",{className:"Knob__cursor"})})}),Xt&&(0,i.jsx)("div",{className:"Knob__popupValue",children:In}),(0,i.jsx)("svg",{className:"Knob__ring Knob__ringTrackPivot",viewBox:"0 0 100 100",children:(0,i.jsx)("circle",{className:"Knob__ringTrack",cx:"50",cy:"50",r:"50"})}),(0,i.jsx)("svg",{className:"Knob__ring Knob__ringFillPivot",viewBox:"0 0 100 100",children:(0,i.jsx)("circle",{className:"Knob__ringFill",style:{strokeDashoffset:Math.max(((Lt?2.75:2)-Yn*1.5)*Math.PI*50,0)},cx:"50",cy:"50",r:"50"})}),Gn]}))}})};/** * @file * @copyright 2020 Aleksej Komarov * @license MIT @@ -383,15 +383,15 @@ * @file * @copyright 2020 Aleksej Komarov * @license MIT - */var Ui=function(c){var h=c.children;return(0,i.jsx)("table",{className:"LabeledList",children:h})},Rn=function(c){var h=c.className,A=c.label,N=c.labelColor,O=N===void 0?"label":N,$=c.labelWrap,re=c.color,ee=c.textAlign,de=c.buttons,ue=c.content,ve=c.children,Be=c.verticalAlign,ze=Be===void 0?"baseline":Be,je=c.tooltip,Ze;A&&(Ze=A,typeof A=="string"&&(Ze+=":")),je!==void 0&&(Ze=(0,i.jsx)(Vn,{content:je,children:(0,i.jsx)(M.az,{as:"span",style:{borderBottom:"2px dotted rgba(255, 255, 255, 0.8)"},children:Ze})}));var ot=(0,i.jsx)(M.az,{as:"td",color:O,className:(0,B.Ly)(["LabeledList__cell",!$&&"LabeledList__label--nowrap"]),verticalAlign:ze,children:Ze});return(0,i.jsxs)("tr",{className:(0,B.Ly)(["LabeledList__row",h]),children:[ot,(0,i.jsxs)(M.az,{as:"td",color:re,textAlign:ee,className:(0,B.Ly)(["LabeledList__cell","LabeledList__content"]),colSpan:de?void 0:2,verticalAlign:ze,children:[ue,ve]}),de&&(0,i.jsx)("td",{className:"LabeledList__cell LabeledList__buttons",children:de})]})},Cn=function(c){var h=c.size?(0,M.zA)(Math.max(0,c.size-1)):0;return(0,i.jsx)("tr",{className:"LabeledList__row",children:(0,i.jsx)("td",{colSpan:3,style:{paddingTop:h,paddingBottom:h},children:(0,i.jsx)(Zl,{})})})};Ui.Item=Rn,Ui.Divider=Cn;/** + */var Ui=function(c){var h=c.children;return(0,i.jsx)("table",{className:"LabeledList",children:h})},Rn=function(c){var h=c.className,A=c.label,N=c.labelColor,O=N===void 0?"label":N,$=c.labelWrap,re=c.color,ee=c.textAlign,de=c.buttons,ue=c.content,ve=c.children,Be=c.verticalAlign,ze=Be===void 0?"baseline":Be,je=c.tooltip,Ze;A&&(Ze=A,typeof A=="string"&&(Ze+=":")),je!==void 0&&(Ze=(0,i.jsx)(Bn,{content:je,children:(0,i.jsx)(M.az,{as:"span",style:{borderBottom:"2px dotted rgba(255, 255, 255, 0.8)"},children:Ze})}));var ot=(0,i.jsx)(M.az,{as:"td",color:O,className:(0,B.Ly)(["LabeledList__cell",!$&&"LabeledList__label--nowrap"]),verticalAlign:ze,children:Ze});return(0,i.jsxs)("tr",{className:(0,B.Ly)(["LabeledList__row",h]),children:[ot,(0,i.jsxs)(M.az,{as:"td",color:re,textAlign:ee,className:(0,B.Ly)(["LabeledList__cell","LabeledList__content"]),colSpan:de?void 0:2,verticalAlign:ze,children:[ue,ve]}),de&&(0,i.jsx)("td",{className:"LabeledList__cell LabeledList__buttons",children:de})]})},Cn=function(c){var h=c.size?(0,M.zA)(Math.max(0,c.size-1)):0;return(0,i.jsx)("tr",{className:"LabeledList__row",children:(0,i.jsx)("td",{colSpan:3,style:{paddingTop:h,paddingBottom:h},children:(0,i.jsx)(Zl,{})})})};Ui.Item=Rn,Ui.Divider=Cn;/** * @file * @copyright 2022 Aleksej Komarov * @license MIT - */function ki(){return ki=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}function ka(c,h){return ka=Object.setPrototypeOf||function(N,O){return N.__proto__=O,N},ka(c,h)}var ua=function(c){"use strict";Si(h,c);function h(N){var O;return O=c.call(this,N)||this,O.handleClick=function($){if(!O.props.menuRef.current){Na.v.log("Menu.handleClick(): No ref");return}O.props.menuRef.current.contains($.target)?Na.v.log("Menu.handleClick(): Inside"):(Na.v.log("Menu.handleClick(): Outside"),O.props.onOutsideClick())},O}var A=h.prototype;return A.componentWillMount=function(){window.addEventListener("click",this.handleClick)},A.componentWillUnmount=function(){window.removeEventListener("click",this.handleClick)},A.render=function(){var O=this.props,$=O.width,re=O.children;return(0,i.jsx)("div",{className:"MenuBar__menu",style:{width:$},children:re})},h}(s.Component),$i=function(c){"use strict";Si(h,c);function h(N){var O;return O=c.call(this,N)||this,O.menuRef=(0,s.createRef)(),O}var A=h.prototype;return A.render=function(){var O=this.props,$=O.open,re=O.openWidth,ee=O.children,de=O.disabled,ue=O.display,ve=O.onMouseOver,Be=O.onClick,ze=O.onOutsideClick,je=aa(O,["open","openWidth","children","disabled","display","onMouseOver","onClick","onOutsideClick"]),Ze=je.className,ot=aa(je,["className"]);return(0,i.jsxs)("div",{ref:this.menuRef,children:[(0,i.jsx)(M.az,ki({className:(0,B.Ly)(["MenuBar__MenuBarButton","MenuBar__font","MenuBar__hover",Ze])},ot,{onClick:de?function(){return null}:Be,onMouseOver:ve,children:(0,i.jsx)("span",{className:"MenuBar__MenuBarButton-text",children:ue})})),$&&(0,i.jsx)(ua,{width:re,menuRef:this.menuRef,onOutsideClick:ze,children:ee})]})},h}(s.Component),Ro=function(c){var h=c.entry,A=c.children,N=c.openWidth,O=c.display,$=c.setOpenMenuBar,re=c.openMenuBar,ee=c.setOpenOnHover,de=c.openOnHover,ue=c.disabled,ve=c.className;return(0,i.jsx)($i,{openWidth:N,display:O,disabled:ue,open:re===h,className:ve,onClick:function(){var Be=re===h?null:h;$(Be),ee(!de)},onOutsideClick:function(){$(null),ee(!1)},onMouseOver:function(){de&&$(h)},children:A})},la=function(c){var h=c.value,A=c.displayText,N=c.onClick,O=c.checked;return(0,i.jsxs)(M.az,{className:(0,B.Ly)(["MenuBar__font","MenuBar__MenuItem","MenuBar__MenuItemToggle","MenuBar__hover"]),onClick:function(){return N(h)},children:[(0,i.jsx)("div",{className:"MenuBar__MenuItemToggle__check",children:O&&(0,i.jsx)(G,{size:1.3,name:"check"})}),A]})};Ro.MenuItemToggle=la;var us=function(c){var h=c.value,A=c.displayText,N=c.onClick;return(0,i.jsx)(M.az,{className:(0,B.Ly)(["MenuBar__font","MenuBar__MenuItem","MenuBar__hover"]),onClick:function(){return N(h)},children:A})};Ro.MenuItem=us;var Zs=function(){return(0,i.jsx)("div",{className:"MenuBar__Separator"})};Ro.Separator=Zs;var ls=function(c){var h=c.children;return(0,i.jsx)(M.az,{className:"MenuBar",children:h})};ls.Dropdown=Ro;/** + */function ki(){return ki=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}function ka(c,h){return ka=Object.setPrototypeOf||function(N,O){return N.__proto__=O,N},ka(c,h)}var ua=function(c){"use strict";Si(h,c);function h(N){var O;return O=c.call(this,N)||this,O.handleClick=function($){if(!O.props.menuRef.current){Na.v.log("Menu.handleClick(): No ref");return}O.props.menuRef.current.contains($.target)?Na.v.log("Menu.handleClick(): Inside"):(Na.v.log("Menu.handleClick(): Outside"),O.props.onOutsideClick())},O}var A=h.prototype;return A.componentWillMount=function(){window.addEventListener("click",this.handleClick)},A.componentWillUnmount=function(){window.removeEventListener("click",this.handleClick)},A.render=function(){var O=this.props,$=O.width,re=O.children;return(0,i.jsx)("div",{className:"MenuBar__menu",style:{width:$},children:re})},h}(s.Component),$i=function(c){"use strict";Si(h,c);function h(N){var O;return O=c.call(this,N)||this,O.menuRef=(0,s.createRef)(),O}var A=h.prototype;return A.render=function(){var O=this.props,$=O.open,re=O.openWidth,ee=O.children,de=O.disabled,ue=O.display,ve=O.onMouseOver,Be=O.onClick,ze=O.onOutsideClick,je=aa(O,["open","openWidth","children","disabled","display","onMouseOver","onClick","onOutsideClick"]),Ze=je.className,ot=aa(je,["className"]);return(0,i.jsxs)("div",{ref:this.menuRef,children:[(0,i.jsx)(M.az,ki({className:(0,B.Ly)(["MenuBar__MenuBarButton","MenuBar__font","MenuBar__hover",Ze])},ot,{onClick:de?function(){return null}:Be,onMouseOver:ve,children:(0,i.jsx)("span",{className:"MenuBar__MenuBarButton-text",children:ue})})),$&&(0,i.jsx)(ua,{width:re,menuRef:this.menuRef,onOutsideClick:ze,children:ee})]})},h}(s.Component),Ro=function(c){var h=c.entry,A=c.children,N=c.openWidth,O=c.display,$=c.setOpenMenuBar,re=c.openMenuBar,ee=c.setOpenOnHover,de=c.openOnHover,ue=c.disabled,ve=c.className;return(0,i.jsx)($i,{openWidth:N,display:O,disabled:ue,open:re===h,className:ve,onClick:function(){var Be=re===h?null:h;$(Be),ee(!de)},onOutsideClick:function(){$(null),ee(!1)},onMouseOver:function(){de&&$(h)},children:A})},la=function(c){var h=c.value,A=c.displayText,N=c.onClick,O=c.checked;return(0,i.jsxs)(M.az,{className:(0,B.Ly)(["MenuBar__font","MenuBar__MenuItem","MenuBar__MenuItemToggle","MenuBar__hover"]),onClick:function(){return N(h)},children:[(0,i.jsx)("div",{className:"MenuBar__MenuItemToggle__check",children:O&&(0,i.jsx)(G,{size:1.3,name:"check"})}),A]})};Ro.MenuItemToggle=la;var us=function(c){var h=c.value,A=c.displayText,N=c.onClick;return(0,i.jsx)(M.az,{className:(0,B.Ly)(["MenuBar__font","MenuBar__MenuItem","MenuBar__hover"]),onClick:function(){return N(h)},children:A})};Ro.MenuItem=us;var Js=function(){return(0,i.jsx)("div",{className:"MenuBar__Separator"})};Ro.Separator=Js;var ls=function(c){var h=c.children;return(0,i.jsx)(M.az,{className:"MenuBar",children:h})};ls.Dropdown=Ro;/** * @file * @copyright 2020 Aleksej Komarov * @license MIT - */function sa(){return sa=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}var du=function(c){var h=c.className,A=c.children,N=c.onEnter,O=ca(c,["className","children","onEnter"]),$;return N&&($=function(re){var ee=re.which||re.keyCode;ee===13&&N(re)}),_jsx(Dimmer,{onKeyDown:$,children:_jsx("div",sa({className:classes(["Modal",h,computeBoxClassName(O)])},computeBoxProps(O),{children:A}))})},vu=n(31200),$a=n(7081);function fa(){return fa=Object.assign||function(c){for(var h=1;h500&&(ze=500);var je=ue.offsetY-256*Be;return je<-200&&(je=-200),je>200&&(je=200),ue.offsetX=ze,ue.offsetY=je,N.onZoom&&N.onZoom(ue.zoom),ue})},O}var A=h.prototype;return A.render=function(){var O=(0,$a.Oc)().config,$=this.state,re=$.dragging,ee=$.offsetX,de=$.offsetY,ue=$.zoom,ve=ue===void 0?1:ue,Be=this.props.children,ze=(0,vu.l)(O.map+"_nanomap_z"+O.mapZLevel+".png"),je=this.props.zoomScale*ve+"px",Ze={width:je,height:je,"margin-top":de+"px","margin-left":ee+"px",overflow:"hidden",position:"relative","background-image":"url("+ze+")","background-size":"cover","background-repeat":"no-repeat","text-align":"center",cursor:re?"move":"auto"};return(0,i.jsxs)(M.az,{className:"NanoMap__container",children:[(0,i.jsx)(M.az,{style:Ze,textAlign:"center",onMouseDown:this.handleDragStart,onClick:this.handleOnClick,children:(0,i.jsx)(M.az,{children:Be})}),(0,i.jsx)(Ko,{zoom:ve,onZoom:this.handleZoom})]})},h}(s.Component),Il=function(c){var h=c.x,A=c.y,N=c.zoom,O=N===void 0?1:N,$=c.icon,re=c.tooltip,ee=c.color,de=c.onClick,ue=function(ze){pu(ze),de&&de(ze)},ve=h*2*O-O-3,Be=A*2*O-O-3;return(0,i.jsx)("div",{children:(0,i.jsxs)(M.az,{position:"absolute",className:"NanoMap__marker",lineHeight:"0",bottom:Be+"px",left:ve+"px",onMouseDown:ue,children:[(0,i.jsx)(G,{name:$,color:ee,fontSize:"6px"}),(0,i.jsx)(Vn,{content:re})]})})};ss.Marker=Il;var Ko=function(c){var h=(0,$a.Oc)(),A=h.act,N=h.config,O=h.data;return(0,i.jsx)(M.az,{className:"NanoMap__zoomer",children:(0,i.jsxs)(Ui,{children:[(0,i.jsx)(Ui.Item,{label:"Zoom",children:(0,i.jsx)(pa,{minValue:"1",maxValue:"8",stepPixelSize:"10",format:function($){return $+"x"},value:c.zoom,onDrag:function($,re){return c.onZoom($,re)}})}),(0,i.jsx)(Ui.Item,{label:"Z-Level",children:O.map_levels.sort(function($,re){return Number($)-Number(re)}).map(function($){return(0,i.jsx)(nr,{selected:~~$===~~N.mapZLevel,onClick:function(){A("setZLevel",{mapZLevel:$})},children:$},$)})})]})})};ss.Zoomer=Ko;/** + */function sa(){return sa=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}var du=function(c){var h=c.className,A=c.children,N=c.onEnter,O=ca(c,["className","children","onEnter"]),$;return N&&($=function(re){var ee=re.which||re.keyCode;ee===13&&N(re)}),_jsx(Dimmer,{onKeyDown:$,children:_jsx("div",sa({className:classes(["Modal",h,computeBoxClassName(O)])},computeBoxProps(O),{children:A}))})},vu=n(31200),$a=n(7081);function fa(){return fa=Object.assign||function(c){for(var h=1;h500&&(ze=500);var je=ue.offsetY-256*Be;return je<-200&&(je=-200),je>200&&(je=200),ue.offsetX=ze,ue.offsetY=je,N.onZoom&&N.onZoom(ue.zoom),ue})},O}var A=h.prototype;return A.render=function(){var O=(0,$a.Oc)().config,$=this.state,re=$.dragging,ee=$.offsetX,de=$.offsetY,ue=$.zoom,ve=ue===void 0?1:ue,Be=this.props.children,ze=(0,vu.l)(O.map+"_nanomap_z"+O.mapZLevel+".png"),je=this.props.zoomScale*ve+"px",Ze={width:je,height:je,"margin-top":de+"px","margin-left":ee+"px",overflow:"hidden",position:"relative","background-image":"url("+ze+")","background-size":"cover","background-repeat":"no-repeat","text-align":"center",cursor:re?"move":"auto"};return(0,i.jsxs)(M.az,{className:"NanoMap__container",children:[(0,i.jsx)(M.az,{style:Ze,textAlign:"center",onMouseDown:this.handleDragStart,onClick:this.handleOnClick,children:(0,i.jsx)(M.az,{children:Be})}),(0,i.jsx)(Ko,{zoom:ve,onZoom:this.handleZoom})]})},h}(s.Component),Il=function(c){var h=c.x,A=c.y,N=c.zoom,O=N===void 0?1:N,$=c.icon,re=c.tooltip,ee=c.color,de=c.onClick,ue=function(ze){pu(ze),de&&de(ze)},ve=h*2*O-O-3,Be=A*2*O-O-3;return(0,i.jsx)("div",{children:(0,i.jsxs)(M.az,{position:"absolute",className:"NanoMap__marker",lineHeight:"0",bottom:Be+"px",left:ve+"px",onMouseDown:ue,children:[(0,i.jsx)(G,{name:$,color:ee,fontSize:"6px"}),(0,i.jsx)(Bn,{content:re})]})})};ss.Marker=Il;var Ko=function(c){var h=(0,$a.Oc)(),A=h.act,N=h.config,O=h.data;return(0,i.jsx)(M.az,{className:"NanoMap__zoomer",children:(0,i.jsxs)(Ui,{children:[(0,i.jsx)(Ui.Item,{label:"Zoom",children:(0,i.jsx)(pa,{minValue:"1",maxValue:"8",stepPixelSize:"10",format:function($){return $+"x"},value:c.zoom,onDrag:function($,re){return c.onZoom($,re)}})}),(0,i.jsx)(Ui.Item,{label:"Z-Level",children:O.map_levels.sort(function($,re){return Number($)-Number(re)}).map(function($){return(0,i.jsx)(nr,{selected:~~$===~~N.mapZLevel,onClick:function(){A("setZLevel",{mapZLevel:$})},children:$},$)})})]})})};ss.Zoomer=Ko;/** * @file * @copyright 2020 Aleksej Komarov * @license MIT @@ -399,7 +399,7 @@ * @file * @copyright 2020 Aleksej Komarov * @license MIT - */function zr(){return zr=Object.assign||function(c){for(var h=1;h0&&(O.setState({suppressingFlicker:!0}),clearTimeout(O.flickerTimer),O.flickerTimer=setTimeout(function(){return O.setState({suppressingFlicker:!1})},re))},O.handleDragStart=function(re){var ee=O.props.value,de=O.state.editing;de||(document.body.style["pointer-events"]="none",O.ref=re.target,O.setState({dragging:!1,origin:re.screenY,value:ee,internalValue:ee}),O.timer=setTimeout(function(){O.setState({dragging:!0})},250),O.dragInterval=setInterval(function(){var ue=O.state,ve=ue.dragging,Be=ue.value,ze=O.props.onDrag;ve&&ze&&ze(re,Be)},O.props.updateRate||wl),document.addEventListener("mousemove",O.handleDragMove),document.addEventListener("mouseup",O.handleDragEnd))},O.handleDragMove=function(re){var ee=O.props,de=ee.minValue,ue=ee.maxValue,ve=ee.step,Be=ee.stepPixelSize;O.setState(function(ze){var je=zr({},ze),Ze=je.origin-re.screenY;if(ze.dragging){var ot=Number.isFinite(de)?de%ve:0;je.internalValue=(0,u.qE)(je.internalValue+Ze*ve/Be,de-ve,ue+ve),je.value=(0,u.qE)(je.internalValue-je.internalValue%ve+ot,de,ue),je.origin=re.screenY}else Math.abs(Ze)>4&&(je.dragging=!0);return je})},O.handleDragEnd=function(re){var ee=O.props,de=ee.onChange,ue=ee.onDrag,ve=O.state,Be=ve.dragging,ze=ve.value,je=ve.internalValue;if(document.body.style["pointer-events"]="auto",clearTimeout(O.timer),clearInterval(O.dragInterval),O.setState({dragging:!1,editing:!Be,origin:null}),document.removeEventListener("mousemove",O.handleDragMove),document.removeEventListener("mouseup",O.handleDragEnd),Be)O.suppressFlicker(),de&&de(re,ze),ue&&ue(re,ze);else if(O.inputRef){var Ze=O.inputRef.current;Ze.value=je;try{Ze.focus(),Ze.select()}catch(ot){}}},O}var A=h.prototype;return A.render=function(){var O=this,$=this.state,re=$.dragging,ee=$.editing,de=$.value,ue=$.suppressingFlicker,ve=this.props,Be=ve.className,ze=ve.fluid,je=ve.animated,Ze=ve.value,ot=ve.unit,st=ve.minValue,ft=ve.maxValue,vt=ve.height,Ot=ve.width,ht=ve.lineHeight,Lt=ve.fontSize,At=ve.format,Tt=ve.onChange,Dt=ve.onDrag,Xt=Ze;(re||ue)&&(Xt=de);var Mt=(0,i.jsxs)("div",{className:"NumberInput__content",children:[je&&!re&&!ue?(0,i.jsx)(E,{value:Xt,format:At}):At?At(Xt):Xt,ot?" "+ot:""]});return(0,i.jsxs)(M.az,{className:(0,B.Ly)(["NumberInput",ze&&"NumberInput--fluid",Be]),minWidth:Ot,minHeight:vt,lineHeight:ht,fontSize:Lt,onMouseDown:this.handleDragStart,children:[(0,i.jsx)("div",{className:"NumberInput__barContainer",children:(0,i.jsx)("div",{className:"NumberInput__bar",style:{height:(0,u.qE)((Xt-st)/(ft-st)*100,0,100)+"%"}})}),Mt,(0,i.jsx)("input",{ref:this.inputRef,className:"NumberInput__input",style:{display:ee?void 0:"none",height:vt,lineHeight:ht,fontSize:Lt},onBlur:function(It){if(ee){var wt=(0,u.qE)(parseFloat(It.target.value),st,ft);if(Number.isNaN(wt)){O.setState({editing:!1});return}O.setState({editing:!1,value:wt}),O.suppressFlicker(),Tt&&Tt(It,wt),Dt&&Dt(It,wt)}},onKeyDown:function(It){if(It.keyCode===13){var wt=(0,u.qE)(parseFloat(It.target.value),st,ft);if(Number.isNaN(wt)){O.setState({editing:!1});return}O.setState({editing:!1,value:wt}),O.suppressFlicker(),Tt&&Tt(It,wt),Dt&&Dt(It,wt);return}if(It.keyCode===27){O.setState({editing:!1});return}}})]})},h}(s.Component);cs.defaultProps={minValue:-1/0,maxValue:1/0,step:1,stepPixelSize:1,suppressFlicker:50};function Wi(){return Wi=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}function Go(c,h){return Go=Object.setPrototypeOf||function(N,O){return N.__proto__=O,N},Go(c,h)}var va=0,Oi=1e4,No=function(c,h,A,N){var O=h||va,$=A||A===0?A:Oi,re=N?c.replace(/[^\-\d.]/g,""):c.replace(/[^\-\d]/g,"");return N&&(re=vn(re,O),re=bn(".",re)),h<0?(re=zt(re),re=bn("-",re)):re=re.replaceAll("-",""),O<=1&&$>=0?mn(re,O,$,N):re},mn=function(c,h,A,N){var O=N?parseFloat(c):parseInt(c,10);if(!isNaN(O)&&(c.slice(-1)!=="."||O0?(c=c.replace("-",""),h="-".concat(c)):A===0&&c.indexOf("-",A+1)>0&&(h=c.replaceAll("-","")),h},vn=function(c,h){var A=c,N=Math.sign(h)*Math.floor(Math.abs(h));return c.indexOf(".")===0?A=String(N).concat(c):c.indexOf("-")===0&&c.indexOf(".")===1&&(A=N+".".concat(c.slice(2))),A},bn=function(c,h){var A=h.indexOf(c),N=h.length,O=h;if(A!==-1&&A0&&(O.setState({suppressingFlicker:!0}),clearTimeout(O.flickerTimer),O.flickerTimer=setTimeout(function(){return O.setState({suppressingFlicker:!1})},re))},O.handleDragStart=function(re){var ee=O.props.value,de=O.state.editing;de||(document.body.style["pointer-events"]="none",O.ref=re.target,O.setState({dragging:!1,origin:re.screenY,value:ee,internalValue:ee}),O.timer=setTimeout(function(){O.setState({dragging:!0})},250),O.dragInterval=setInterval(function(){var ue=O.state,ve=ue.dragging,Be=ue.value,ze=O.props.onDrag;ve&&ze&&ze(re,Be)},O.props.updateRate||wl),document.addEventListener("mousemove",O.handleDragMove),document.addEventListener("mouseup",O.handleDragEnd))},O.handleDragMove=function(re){var ee=O.props,de=ee.minValue,ue=ee.maxValue,ve=ee.step,Be=ee.stepPixelSize;O.setState(function(ze){var je=zr({},ze),Ze=je.origin-re.screenY;if(ze.dragging){var ot=Number.isFinite(de)?de%ve:0;je.internalValue=(0,u.qE)(je.internalValue+Ze*ve/Be,de-ve,ue+ve),je.value=(0,u.qE)(je.internalValue-je.internalValue%ve+ot,de,ue),je.origin=re.screenY}else Math.abs(Ze)>4&&(je.dragging=!0);return je})},O.handleDragEnd=function(re){var ee=O.props,de=ee.onChange,ue=ee.onDrag,ve=O.state,Be=ve.dragging,ze=ve.value,je=ve.internalValue;if(document.body.style["pointer-events"]="auto",clearTimeout(O.timer),clearInterval(O.dragInterval),O.setState({dragging:!1,editing:!Be,origin:null}),document.removeEventListener("mousemove",O.handleDragMove),document.removeEventListener("mouseup",O.handleDragEnd),Be)O.suppressFlicker(),de&&de(re,ze),ue&&ue(re,ze);else if(O.inputRef){var Ze=O.inputRef.current;Ze.value=je;try{Ze.focus(),Ze.select()}catch(ot){}}},O}var A=h.prototype;return A.render=function(){var O=this,$=this.state,re=$.dragging,ee=$.editing,de=$.value,ue=$.suppressingFlicker,ve=this.props,Be=ve.className,ze=ve.fluid,je=ve.animated,Ze=ve.value,ot=ve.unit,st=ve.minValue,ft=ve.maxValue,vt=ve.height,Ot=ve.width,ht=ve.lineHeight,Lt=ve.fontSize,At=ve.format,Tt=ve.onChange,Dt=ve.onDrag,Xt=Ze;(re||ue)&&(Xt=de);var Mt=(0,i.jsxs)("div",{className:"NumberInput__content",children:[je&&!re&&!ue?(0,i.jsx)(E,{value:Xt,format:At}):At?At(Xt):Xt,ot?" "+ot:""]});return(0,i.jsxs)(M.az,{className:(0,B.Ly)(["NumberInput",ze&&"NumberInput--fluid",Be]),minWidth:Ot,minHeight:vt,lineHeight:ht,fontSize:Lt,onMouseDown:this.handleDragStart,children:[(0,i.jsx)("div",{className:"NumberInput__barContainer",children:(0,i.jsx)("div",{className:"NumberInput__bar",style:{height:(0,u.qE)((Xt-st)/(ft-st)*100,0,100)+"%"}})}),Mt,(0,i.jsx)("input",{ref:this.inputRef,className:"NumberInput__input",style:{display:ee?void 0:"none",height:vt,lineHeight:ht,fontSize:Lt},onBlur:function(It){if(ee){var wt=(0,u.qE)(parseFloat(It.target.value),st,ft);if(Number.isNaN(wt)){O.setState({editing:!1});return}O.setState({editing:!1,value:wt}),O.suppressFlicker(),Tt&&Tt(It,wt),Dt&&Dt(It,wt)}},onKeyDown:function(It){if(It.keyCode===13){var wt=(0,u.qE)(parseFloat(It.target.value),st,ft);if(Number.isNaN(wt)){O.setState({editing:!1});return}O.setState({editing:!1,value:wt}),O.suppressFlicker(),Tt&&Tt(It,wt),Dt&&Dt(It,wt);return}if(It.keyCode===27){O.setState({editing:!1});return}}})]})},h}(s.Component);cs.defaultProps={minValue:-1/0,maxValue:1/0,step:1,stepPixelSize:1,suppressFlicker:50};function Wi(){return Wi=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}function Go(c,h){return Go=Object.setPrototypeOf||function(N,O){return N.__proto__=O,N},Go(c,h)}var va=0,Oi=1e4,No=function(c,h,A,N){var O=h||va,$=A||A===0?A:Oi,re=N?c.replace(/[^\-\d.]/g,""):c.replace(/[^\-\d]/g,"");return N&&(re=vn(re,O),re=zn(".",re)),h<0?(re=zt(re),re=zn("-",re)):re=re.replaceAll("-",""),O<=1&&$>=0?mn(re,O,$,N):re},mn=function(c,h,A,N){var O=N?parseFloat(c):parseInt(c,10);if(!isNaN(O)&&(c.slice(-1)!=="."||O0?(c=c.replace("-",""),h="-".concat(c)):A===0&&c.indexOf("-",A+1)>0&&(h=c.replaceAll("-","")),h},vn=function(c,h){var A=c,N=Math.sign(h)*Math.floor(Math.abs(h));return c.indexOf(".")===0?A=String(N).concat(c):c.indexOf("-")===0&&c.indexOf(".")===1&&(A=N+".".concat(c.slice(2))),A},zn=function(c,h){var A=h.indexOf(c),N=h.length,O=h;if(A!==-1&&A=0)&&(A[O]=c[O]);return A}var pa=function(c){var h=c.animated,A=c.format,N=c.maxValue,O=c.minValue,$=c.onChange,re=c.onDrag,ee=c.step,de=c.stepPixelSize,ue=c.suppressFlicker,ve=c.unit,Be=c.value,ze=c.className,je=c.fillValue,Ze=c.color,ot=c.ranges,st=ot===void 0?{}:ot,ft=c.children,vt=jo(c,["animated","format","maxValue","minValue","onChange","onDrag","step","stepPixelSize","suppressFlicker","unit","value","className","fillValue","color","ranges","children"]),Ot=ft!==void 0;return(0,i.jsx)(Nu,{dragMatrix:[1,0],animated:h,format:A,maxValue:N,minValue:O,onChange:$,onDrag:re,step:ee,stepPixelSize:de,suppressFlicker:ue,unit:ve,value:Be,children:function(ht){var Lt=ht.dragging,At=ht.editing,Tt=ht.value,Dt=ht.displayValue,Xt=ht.displayElement,Mt=ht.inputElement,It=ht.handleDragStart,wt=je!=null,In=(0,u.hs)(Tt,O,N),Gn=(0,u.hs)(je!=null?je:Dt,O,N),Un=(0,u.hs)(Dt,O,N),Yn=Ze||(0,u.TG)(je!=null?je:Tt,st)||"default";return(0,i.jsxs)("div",Mo({className:(0,B.Ly)(["Slider","ProgressBar","ProgressBar--color--"+Yn,ze,(0,M.WP)(vt)])},(0,M.Fl)(vt),{onMouseDown:It,children:[(0,i.jsx)("div",{className:(0,B.Ly)(["ProgressBar__fill",wt&&"ProgressBar__fill--animated"]),style:{width:(0,u.J$)(Gn)*100+"%",opacity:.4}}),(0,i.jsx)("div",{className:"ProgressBar__fill",style:{width:(0,u.J$)(Math.min(Gn,Un))*100+"%"}}),(0,i.jsxs)("div",{className:"Slider__cursorOffset",style:{width:(0,u.J$)(Un)*100+"%"},children:[(0,i.jsx)("div",{className:"Slider__cursor"}),(0,i.jsx)("div",{className:"Slider__pointer"}),Lt&&(0,i.jsx)("div",{className:"Slider__popupValue",children:Xt})]}),(0,i.jsx)("div",{className:"ProgressBar__content",children:Ot?ft:Xt}),Mt]}))}})},Cl=function(c){return _jsxs(Box,{style:c.style,children:[_jsxs(Box,{className:"Section__title",style:c.titleStyle,children:[_jsx(Box,{className:"Section__titleText",style:c.textStyle,children:c.title}),_jsx("div",{className:"Section__buttons",children:c.titleSubtext})]}),_jsx(Box,{className:"Section__rest",children:_jsx(Box,{className:"Section__content",children:c.children})})]})};/** + */function Mo(){return Mo=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}var pa=function(c){var h=c.animated,A=c.format,N=c.maxValue,O=c.minValue,$=c.onChange,re=c.onDrag,ee=c.step,de=c.stepPixelSize,ue=c.suppressFlicker,ve=c.unit,Be=c.value,ze=c.className,je=c.fillValue,Ze=c.color,ot=c.ranges,st=ot===void 0?{}:ot,ft=c.children,vt=jo(c,["animated","format","maxValue","minValue","onChange","onDrag","step","stepPixelSize","suppressFlicker","unit","value","className","fillValue","color","ranges","children"]),Ot=ft!==void 0;return(0,i.jsx)(Nu,{dragMatrix:[1,0],animated:h,format:A,maxValue:N,minValue:O,onChange:$,onDrag:re,step:ee,stepPixelSize:de,suppressFlicker:ue,unit:ve,value:Be,children:function(ht){var Lt=ht.dragging,At=ht.editing,Tt=ht.value,Dt=ht.displayValue,Xt=ht.displayElement,Mt=ht.inputElement,It=ht.handleDragStart,wt=je!=null,In=(0,u.hs)(Tt,O,N),Gn=(0,u.hs)(je!=null?je:Dt,O,N),kn=(0,u.hs)(Dt,O,N),Yn=Ze||(0,u.TG)(je!=null?je:Tt,st)||"default";return(0,i.jsxs)("div",Mo({className:(0,B.Ly)(["Slider","ProgressBar","ProgressBar--color--"+Yn,ze,(0,M.WP)(vt)])},(0,M.Fl)(vt),{onMouseDown:It,children:[(0,i.jsx)("div",{className:(0,B.Ly)(["ProgressBar__fill",wt&&"ProgressBar__fill--animated"]),style:{width:(0,u.J$)(Gn)*100+"%",opacity:.4}}),(0,i.jsx)("div",{className:"ProgressBar__fill",style:{width:(0,u.J$)(Math.min(Gn,kn))*100+"%"}}),(0,i.jsxs)("div",{className:"Slider__cursorOffset",style:{width:(0,u.J$)(kn)*100+"%"},children:[(0,i.jsx)("div",{className:"Slider__cursor"}),(0,i.jsx)("div",{className:"Slider__pointer"}),Lt&&(0,i.jsx)("div",{className:"Slider__popupValue",children:Xt})]}),(0,i.jsx)("div",{className:"ProgressBar__content",children:Ot?ft:Xt}),Mt]}))}})},Cl=function(c){return _jsxs(Box,{style:c.style,children:[_jsxs(Box,{className:"Section__title",style:c.titleStyle,children:[_jsx(Box,{className:"Section__titleText",style:c.textStyle,children:c.title}),_jsx("div",{className:"Section__buttons",children:c.titleSubtext})]}),_jsx(Box,{className:"Section__rest",children:_jsx(Box,{className:"Section__content",children:c.children})})]})};/** * @file * @copyright 2020 Aleksej Komarov * @license MIT @@ -420,7 +420,7 @@ * @copyright 2020 Aleksej Komarov * @author Warlockd * @license MIT - */function Xo(){return Xo=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}function Ln(c,h){return Ln=Object.setPrototypeOf||function(N,O){return N.__proto__=O,N},Ln(c,h)}var Ir=function(c){"use strict";ha(h,c);function h(N){var O;O=c.call(this,N)||this,O.textareaRef=N.innerRef||(0,s.createRef)(),O.state={editing:!1,scrolledAmount:0};var $=N.dontUseTabForIndent,re=$===void 0?!1:$;return O.handleOnInput=function(ee){var de=O.state.editing,ue=O.props.onInput;de||O.setEditing(!0),ue&&ue(ee,ee.target.value)},O.handleOnChange=function(ee){var de=O.state.editing,ue=O.props.onChange;de&&O.setEditing(!1),ue&&ue(ee,ee.target.value)},O.handleKeyPress=function(ee){var de=O.state.editing,ue=O.props.onKeyPress;de||O.setEditing(!0),ue&&ue(ee,ee.target.value)},O.handleKeyDown=function(ee){var de=O.state.editing,ue=O.props,ve=ue.onChange,Be=ue.onInput,ze=ue.onEnter,je=ue.onKey;if(ee.keyCode===xo.Ri){O.setEditing(!1),ve&&ve(ee,ee.target.value),Be&&Be(ee,ee.target.value),ze&&ze(ee,ee.target.value),O.props.selfClear&&(ee.target.value="",ee.target.blur());return}if(ee.keyCode===xo.s6){O.props.onEscape&&O.props.onEscape(ee),O.setEditing(!1),O.props.selfClear?ee.target.value="":(ee.target.value=bi(O.props.value),ee.target.blur());return}if(de||O.setEditing(!0),je&&je(ee,ee.target.value),!re){var Ze=ee.keyCode||ee.which;if(Ze===xo.aW){ee.preventDefault();var ot=ee.target,st=ot.value,ft=ot.selectionStart,vt=ot.selectionEnd;ee.target.value=st.substring(0,ft)+" "+st.substring(vt),ee.target.selectionEnd=ft+1,Be&&Be(ee,ee.target.value)}}},O.handleFocus=function(ee){var de=O.state.editing;de||O.setEditing(!0)},O.handleBlur=function(ee){var de=O.state.editing,ue=O.props.onChange;de&&(O.setEditing(!1),ue&&ue(ee,ee.target.value))},O.handleScroll=function(ee){var de=O.props.displayedValue,ue=O.textareaRef.current;de&&ue&&O.setState({scrolledAmount:ue.scrollTop})},O}var A=h.prototype;return A.componentDidMount=function(){var O=this,$=this.props.value,re=this.textareaRef.current;re&&(re.value=bi($)),(this.props.autoFocus||this.props.autoSelect)&&setTimeout(function(){re.focus(),O.props.autoSelect&&re.select()},1)},A.componentDidUpdate=function(O,$){var re=O.value,ee=this.props.value,de=this.textareaRef.current;de&&typeof ee=="string"&&re!==ee&&(de.value=bi(ee))},A.setEditing=function(O){this.setState({editing:O})},A.getValue=function(){return this.textareaRef.current&&this.textareaRef.current.value},A.render=function(){var O=this.props,$=O.onChange,re=O.onKeyDown,ee=O.onKeyPress,de=O.onInput,ue=O.onFocus,ve=O.onBlur,Be=O.onEnter,ze=O.value,je=O.maxLength,Ze=O.placeholder,ot=O.scrollbar,st=O.noborder,ft=O.displayedValue,vt=$r(O,["onChange","onKeyDown","onKeyPress","onInput","onFocus","onBlur","onEnter","value","maxLength","placeholder","scrollbar","noborder","displayedValue"]),Ot=vt.className,ht=vt.fluid,Lt=vt.nowrap,At=$r(vt,["className","fluid","nowrap"]),Tt=this.state.scrolledAmount;return(0,i.jsxs)(M.az,Xo({className:(0,B.Ly)(["TextArea",ht&&"TextArea--fluid",st&&"TextArea--noborder",Ot])},At,{children:[!!ft&&(0,i.jsx)(M.az,{position:"absolute",width:"100%",height:"100%",overflow:"hidden",children:(0,i.jsx)("div",{className:(0,B.Ly)(["TextArea__textarea","TextArea__textarea_custom"]),style:{transform:"translateY(-"+Tt+"px)"},children:ft})}),(0,i.jsx)("textarea",{ref:this.textareaRef,className:(0,B.Ly)(["TextArea__textarea",ot&&"TextArea__textarea--scrollable",Lt&&"TextArea__nowrap"]),placeholder:Ze,onChange:this.handleOnChange,onKeyDown:this.handleKeyDown,onKeyPress:this.handleKeyPress,onInput:this.handleOnInput,onFocus:this.handleFocus,onBlur:this.handleBlur,onScroll:this.handleScroll,maxLength:je,style:{color:ft?"rgba(0, 0, 0, 0)":"inherit"}})]}))},h}(s.Component),ro=n(41242);function Wr(c,h){if(typeof h!="function"&&h!==null)throw new TypeError("Super expression must either be null or a function");c.prototype=Object.create(h&&h.prototype,{constructor:{value:c,writable:!0,configurable:!0}}),h&&Nr(c,h)}function Nr(c,h){return Nr=Object.setPrototypeOf||function(N,O){return N.__proto__=O,N},Nr(c,h)}var ma=function(c){return typeof c=="number"&&Number.isFinite(c)&&!Number.isNaN(c)},Pl=null;function Vu(c){if(c===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return c}function oo(c,h){if(typeof h!="function"&&h!==null)throw new TypeError("Super expression must either be null or a function");c.prototype=Object.create(h&&h.prototype,{constructor:{value:c,writable:!0,configurable:!0}}),h&&nn(c,h)}function zn(c,h){return h!=null&&typeof Symbol!="undefined"&&h[Symbol.hasInstance]?!!h[Symbol.hasInstance](c):c instanceof h}function nn(c,h){return nn=Object.setPrototypeOf||function(N,O){return N.__proto__=O,N},nn(c,h)}var pn=null,Qo=function(c){var h=c.children,A=useRef(null),N=useState(1),O=N[0],$=N[1],re=useState(0),ee=re[0],de=re[1],ue=useCallback(function(){var ve=A.current;if(!(!h||!Array.isArray(h)||!ve||O>=h.length)){var Be=document.body.offsetHeight-ve.getBoundingClientRect().bottom,ze=Math.ceil(ve.offsetHeight/O);if(Be>0){var je=Math.min(h.length,O+Math.max(1,Math.ceil(Be/ze)));$(je),de((h.length-je)*ze)}}},[A,O,$,de]);return useEffect(function(){ue();var ve=setInterval(ue,100);return function(){return clearInterval(ve)}},[ue]),_jsxs("div",{className:"VirtualList",children:[_jsx("div",{className:"VirtualList__Container",ref:A,children:Array.isArray(h)?h.slice(0,O):null}),_jsx("div",{className:"VirtualList__Padding",style:{paddingBottom:""+ee+"px"}})]})};/** + */function Xo(){return Xo=Object.assign||function(c){for(var h=1;h=0)&&(A[O]=c[O]);return A}function Ln(c,h){return Ln=Object.setPrototypeOf||function(N,O){return N.__proto__=O,N},Ln(c,h)}var Ir=function(c){"use strict";ha(h,c);function h(N){var O;O=c.call(this,N)||this,O.textareaRef=N.innerRef||(0,s.createRef)(),O.state={editing:!1,scrolledAmount:0};var $=N.dontUseTabForIndent,re=$===void 0?!1:$;return O.handleOnInput=function(ee){var de=O.state.editing,ue=O.props.onInput;de||O.setEditing(!0),ue&&ue(ee,ee.target.value)},O.handleOnChange=function(ee){var de=O.state.editing,ue=O.props.onChange;de&&O.setEditing(!1),ue&&ue(ee,ee.target.value)},O.handleKeyPress=function(ee){var de=O.state.editing,ue=O.props.onKeyPress;de||O.setEditing(!0),ue&&ue(ee,ee.target.value)},O.handleKeyDown=function(ee){var de=O.state.editing,ue=O.props,ve=ue.onChange,Be=ue.onInput,ze=ue.onEnter,je=ue.onKey;if(ee.keyCode===xo.Ri){O.setEditing(!1),ve&&ve(ee,ee.target.value),Be&&Be(ee,ee.target.value),ze&&ze(ee,ee.target.value),O.props.selfClear&&(ee.target.value="",ee.target.blur());return}if(ee.keyCode===xo.s6){O.props.onEscape&&O.props.onEscape(ee),O.setEditing(!1),O.props.selfClear?ee.target.value="":(ee.target.value=bi(O.props.value),ee.target.blur());return}if(de||O.setEditing(!0),je&&je(ee,ee.target.value),!re){var Ze=ee.keyCode||ee.which;if(Ze===xo.aW){ee.preventDefault();var ot=ee.target,st=ot.value,ft=ot.selectionStart,vt=ot.selectionEnd;ee.target.value=st.substring(0,ft)+" "+st.substring(vt),ee.target.selectionEnd=ft+1,Be&&Be(ee,ee.target.value)}}},O.handleFocus=function(ee){var de=O.state.editing;de||O.setEditing(!0)},O.handleBlur=function(ee){var de=O.state.editing,ue=O.props.onChange;de&&(O.setEditing(!1),ue&&ue(ee,ee.target.value))},O.handleScroll=function(ee){var de=O.props.displayedValue,ue=O.textareaRef.current;de&&ue&&O.setState({scrolledAmount:ue.scrollTop})},O}var A=h.prototype;return A.componentDidMount=function(){var O=this,$=this.props.value,re=this.textareaRef.current;re&&(re.value=bi($)),(this.props.autoFocus||this.props.autoSelect)&&setTimeout(function(){re.focus(),O.props.autoSelect&&re.select()},1)},A.componentDidUpdate=function(O,$){var re=O.value,ee=this.props.value,de=this.textareaRef.current;de&&typeof ee=="string"&&re!==ee&&(de.value=bi(ee))},A.setEditing=function(O){this.setState({editing:O})},A.getValue=function(){return this.textareaRef.current&&this.textareaRef.current.value},A.render=function(){var O=this.props,$=O.onChange,re=O.onKeyDown,ee=O.onKeyPress,de=O.onInput,ue=O.onFocus,ve=O.onBlur,Be=O.onEnter,ze=O.value,je=O.maxLength,Ze=O.placeholder,ot=O.scrollbar,st=O.noborder,ft=O.displayedValue,vt=$r(O,["onChange","onKeyDown","onKeyPress","onInput","onFocus","onBlur","onEnter","value","maxLength","placeholder","scrollbar","noborder","displayedValue"]),Ot=vt.className,ht=vt.fluid,Lt=vt.nowrap,At=$r(vt,["className","fluid","nowrap"]),Tt=this.state.scrolledAmount;return(0,i.jsxs)(M.az,Xo({className:(0,B.Ly)(["TextArea",ht&&"TextArea--fluid",st&&"TextArea--noborder",Ot])},At,{children:[!!ft&&(0,i.jsx)(M.az,{position:"absolute",width:"100%",height:"100%",overflow:"hidden",children:(0,i.jsx)("div",{className:(0,B.Ly)(["TextArea__textarea","TextArea__textarea_custom"]),style:{transform:"translateY(-"+Tt+"px)"},children:ft})}),(0,i.jsx)("textarea",{ref:this.textareaRef,className:(0,B.Ly)(["TextArea__textarea",ot&&"TextArea__textarea--scrollable",Lt&&"TextArea__nowrap"]),placeholder:Ze,onChange:this.handleOnChange,onKeyDown:this.handleKeyDown,onKeyPress:this.handleKeyPress,onInput:this.handleOnInput,onFocus:this.handleFocus,onBlur:this.handleBlur,onScroll:this.handleScroll,maxLength:je,style:{color:ft?"rgba(0, 0, 0, 0)":"inherit"}})]}))},h}(s.Component),ro=n(41242);function Wr(c,h){if(typeof h!="function"&&h!==null)throw new TypeError("Super expression must either be null or a function");c.prototype=Object.create(h&&h.prototype,{constructor:{value:c,writable:!0,configurable:!0}}),h&&Nr(c,h)}function Nr(c,h){return Nr=Object.setPrototypeOf||function(N,O){return N.__proto__=O,N},Nr(c,h)}var ma=function(c){return typeof c=="number"&&Number.isFinite(c)&&!Number.isNaN(c)},Pl=null;function Vu(c){if(c===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return c}function oo(c,h){if(typeof h!="function"&&h!==null)throw new TypeError("Super expression must either be null or a function");c.prototype=Object.create(h&&h.prototype,{constructor:{value:c,writable:!0,configurable:!0}}),h&&nn(c,h)}function Un(c,h){return h!=null&&typeof Symbol!="undefined"&&h[Symbol.hasInstance]?!!h[Symbol.hasInstance](c):c instanceof h}function nn(c,h){return nn=Object.setPrototypeOf||function(N,O){return N.__proto__=O,N},nn(c,h)}var pn=null,Qo=function(c){var h=c.children,A=useRef(null),N=useState(1),O=N[0],$=N[1],re=useState(0),ee=re[0],de=re[1],ue=useCallback(function(){var ve=A.current;if(!(!h||!Array.isArray(h)||!ve||O>=h.length)){var Be=document.body.offsetHeight-ve.getBoundingClientRect().bottom,ze=Math.ceil(ve.offsetHeight/O);if(Be>0){var je=Math.min(h.length,O+Math.max(1,Math.ceil(Be/ze)));$(je),de((h.length-je)*ze)}}},[A,O,$,de]);return useEffect(function(){ue();var ve=setInterval(ue,100);return function(){return clearInterval(ve)}},[ue]),_jsxs("div",{className:"VirtualList",children:[_jsx("div",{className:"VirtualList__Container",ref:A,children:Array.isArray(h)?h.slice(0,O):null}),_jsx("div",{className:"VirtualList__Padding",style:{paddingBottom:""+ee+"px"}})]})};/** * @file * @copyright 2020 Aleksej Komarov * @license MIT @@ -492,7 +492,7 @@ * @file * @copyright 2020 Aleksej Komarov * @license MIT - */function G(){return G=Object.assign||function(q){for(var K=1;K=V&&(!L||G))J=j(D,0,V);else{var oe=L&&!G&&M?{maxByteLength:M(D)}:void 0;J=new E(V,oe);for(var Z=new T(D),ne=new T(J),te=w(V,F),pe=0;pe
Generated on: ' + - datesegment + - '
Generated on: ' + + datesegment + + '