diff --git a/app/src/components/icons/SimulationIcons.tsx b/app/src/components/icons/SimulationIcons.tsx index 29b8de4..4d9657a 100644 --- a/app/src/components/icons/SimulationIcons.tsx +++ b/app/src/components/icons/SimulationIcons.tsx @@ -330,3 +330,59 @@ export function CartBagIcon() { </svg> ); } + +export function StorageCapacityIcon() { + return ( + <svg + width="21" + height="20" + viewBox="0 0 21 20" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <g clipPath="url(#clip0_4582_10883)"> + <g filter="url(#filter0_f_4582_10883)"> + <path + d="M5.31653 6.41406H15.35C16.495 6.41406 17.431 7.30913 17.4964 8.43776L17.5 8.56409V11.4308C17.5 12.5758 16.605 13.5118 15.4763 13.5772L15.35 13.5808H5.31653C4.17151 13.5808 3.23555 12.6858 3.17015 11.5571L3.1665 11.4308V8.56409C3.1665 7.41907 4.06158 6.48311 5.1902 6.41771L5.31653 6.41406ZM14.6333 8.56409C14.2375 8.56409 13.9166 8.88494 13.9166 9.28076C13.9166 9.67658 14.2375 9.99744 14.6333 9.99744C15.0291 9.99744 15.35 9.67658 15.35 9.28076C15.35 8.88494 15.0291 8.56409 14.6333 8.56409ZM11.7666 8.56409C11.3708 8.56409 11.0499 8.88494 11.0499 9.28076C11.0499 9.67658 11.3708 9.99744 11.7666 9.99744C12.1624 9.99744 12.4833 9.67658 12.4833 9.28076C12.4833 8.88494 12.1624 8.56409 11.7666 8.56409Z" + fill="#6F42C1" + /> + </g> + <path + d="M5.31653 6.41406H15.35C16.495 6.41406 17.431 7.30913 17.4964 8.43776L17.5 8.56409V11.4308C17.5 12.5758 16.605 13.5118 15.4763 13.5772L15.35 13.5808H5.31653C4.17151 13.5808 3.23555 12.6858 3.17015 11.5571L3.1665 11.4308V8.56409C3.1665 7.41907 4.06158 6.48311 5.1902 6.41771L5.31653 6.41406ZM14.6333 8.56409C14.2375 8.56409 13.9166 8.88494 13.9166 9.28076C13.9166 9.67658 14.2375 9.99744 14.6333 9.99744C15.0291 9.99744 15.35 9.67658 15.35 9.28076C15.35 8.88494 15.0291 8.56409 14.6333 8.56409ZM11.7666 8.56409C11.3708 8.56409 11.0499 8.88494 11.0499 9.28076C11.0499 9.67658 11.3708 9.99744 11.7666 9.99744C12.1624 9.99744 12.4833 9.67658 12.4833 9.28076C12.4833 8.88494 12.1624 8.56409 11.7666 8.56409Z" + fill="#CCACFF" + /> + </g> + <defs> + <filter + id="filter0_f_4582_10883" + x="-0.833496" + y="2.41406" + width="22.3335" + height="15.1641" + filterUnits="userSpaceOnUse" + colorInterpolationFilters="sRGB" + > + <feFlood floodOpacity="0" result="BackgroundImageFix" /> + <feBlend + mode="normal" + in="SourceGraphic" + in2="BackgroundImageFix" + result="shape" + /> + <feGaussianBlur + stdDeviation="2" + result="effect1_foregroundBlur_4582_10883" + /> + </filter> + <clipPath id="clip0_4582_10883"> + <rect + width="20" + height="20" + fill="white" + transform="translate(0.5)" + /> + </clipPath> + </defs> + </svg> + ); +} diff --git a/app/src/components/ui/simulation/AssetDetailsCard.tsx b/app/src/components/ui/simulation/AssetDetailsCard.tsx index ff7accd..08eb280 100644 --- a/app/src/components/ui/simulation/AssetDetailsCard.tsx +++ b/app/src/components/ui/simulation/AssetDetailsCard.tsx @@ -4,12 +4,14 @@ import { ExpandIcon, IndicationArrow, SimulationStatusIcon, + StorageCapacityIcon, } from "../../icons/SimulationIcons"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; interface AssetDetailsCardInterface { name: string; status: string; + enableStatue?: boolean; count?: number; totalCapacity?: number; assetDetails?: { @@ -54,6 +56,7 @@ const GetStatus = (status: string) => { const AssetDetailsCard: React.FC<AssetDetailsCardInterface> = ({ name, + enableStatue = true, status, count, totalCapacity, @@ -72,7 +75,12 @@ const AssetDetailsCard: React.FC<AssetDetailsCardInterface> = ({ <div className="asset-details-header"> <div className="content"> <div className="name">{name}</div> - <div className="status-container">{GetStatus(status)}</div> + {enableStatue && ( + <div className="status-container">{GetStatus(status)}</div> + )} + {!enableStatue && totalCapacity && ( + <div className="storage-container">Storage/Inventory</div> + )} </div> <button className="expand-button" @@ -87,10 +95,48 @@ const AssetDetailsCard: React.FC<AssetDetailsCardInterface> = ({ {totalCapacity && ( <div className="count-ui-wrapper"> <div className="count-ui-container"> - <div className="icon"> - <CartBagIcon /> + <div className="content"> + <div className="icon"> + <StorageCapacityIcon /> + </div> + <div className="display"> + {count?.toString()}/{totalCapacity} + </div> + </div> + {/* progress ui */} + <div className="value-container"> + <div className="progress-bar"> + {[...Array(5)].map((_, i) => { + const percentage = (count ?? 0 / totalCapacity) * 100; + const start = i * 20; + const end = (i + 1) * 20; + // fill amount: 0 to 100 + let fillPercent = 0; + if (percentage >= end) { + fillPercent = 100; + } else if (percentage <= start) { + fillPercent = 1; + } else { + fillPercent = ((percentage - start) / 20) * 100; + } + return ( + <div key={i} className="block"> + <div + className="fill" + style={ + { + "--process-fill-percentage": `${fillPercent}%`, + } as React.CSSProperties + } + ></div> + </div> + ); + })} + </div> + <div className="value"> + {Math.round((count ?? 0 / totalCapacity) * 100).toString()}% + </div> </div> - <div className="value">{count?.toString()}</div> </div> </div> )} diff --git a/app/src/modules/simulation/ui3d/StorageContentUi.tsx b/app/src/modules/simulation/ui3d/StorageContentUi.tsx index dbda5b3..38f62dc 100644 --- a/app/src/modules/simulation/ui3d/StorageContentUi.tsx +++ b/app/src/modules/simulation/ui3d/StorageContentUi.tsx @@ -30,6 +30,8 @@ const StorageContentUi: React.FC<StorageContentUiProps> = ({ storageUnit }) => { name={storageUnit.modelName} status={storageUnit.state} count={storageUnit.currentLoad} + enableStatue={false} + totalCapacity={storageUnit.point.action.storageCapacity} /> </Html> ); diff --git a/app/src/styles/components/simulation/simulation.scss b/app/src/styles/components/simulation/simulation.scss index b98c23f..c57bfb0 100644 --- a/app/src/styles/components/simulation/simulation.scss +++ b/app/src/styles/components/simulation/simulation.scss @@ -425,8 +425,7 @@ animation: borderAnimation 5s linear infinite; -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); - mask: linear-gradient(#fff 0 0) content-box, - linear-gradient(#fff 0 0); + mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; z-index: -1; @@ -455,6 +454,10 @@ } } } + .storage-container{ + font-size: var(--font-size-tiny); + color: var(--highlight-text-color); + } } } @@ -485,32 +488,61 @@ .count-ui-wrapper { position: absolute; - right: -42px; - top: 5px; + right: -16px; + top: -2px; padding: 4px; padding-right: 8px; .count-ui-container { - @include flex-center; - gap: 6px; - .icon{ + background: var(--background-color-solid); + padding: 8px; + outline: 1px solid var(--border-color); + border-radius: #{$border-radius-large}; + box-shadow: inset 0px 10px 50px #8080803a; + max-width: 80px; + position: absolute; + left: 0; + .content { @include flex-center; - padding: 3px; - border-radius: #{$border-radius-circle}; - background: var(--background-color-accent); - svg { - scale: 0.6; + gap: 2px; + .icon { + @include flex-center; + } + .display { + font-size: var(--font-size-small); } } - .value{ - position: absolute; - width: 48px; - background: var(--background-color-solid-gradient); - border-radius: #{$border-radius-large}; - outline: 1px solid var(--border-color); - padding: 4px 10px; - padding-left: 16px; - transform: translateX(28px); - z-index: -1; + .value-container { + @include flex-center; + gap: 4px; + .progress-bar { + display: flex; + align-items: center; + gap: 1px; + height: 10px; + } + + .block { + width: 5px; + height: 100%; + border-radius: 2px; + transition: background-color 0.3s; + background: var(--background-color); + overflow: hidden; + position: relative; + .fill { + height: 100%; + background: linear-gradient( + to top, + var(--background-color-accent) var(--process-fill-percentage), + transparent var(--process-fill-percentage) + ); + } + } + + .value { + font-size: var(--font-size-tiny); + color: var(--input-text-color); + } } } }