From aad92bad89d8a8205b04c1c78171f1e4472475b6 Mon Sep 17 00:00:00 2001 From: Aylong <69762909+AyIong@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:10:25 +0200 Subject: [PATCH] Remove blue buttons from loadout (#832) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## About The Pull Request Это максимум который я сделаю Делать ТГУИ на ТГ **МАКСИМАЛЬНО** неприятно, всё сука лагает, всё блять разбросано как говно по туалету Я блять ненавижу то что ТГшеры сделали с ТГУИ ![image](https://github.com/user-attachments/assets/0fafe0bc-85cc-4fa8-8593-bfeea1fd2c79) --- .../tgui/bandastation/ImageButton.scss | 276 ++++++++++++++++++ .../tgui/bandastation/ImageButton.tsx | 245 ++++++++++++++++ .../tgui/bandastation/ItemDisplay220.tsx | 86 ++++++ .../PreferencesMenu/loadout/ItemDisplay.tsx | 21 +- .../PreferencesMenu/loadout/base.ts | 2 +- 5 files changed, 616 insertions(+), 14 deletions(-) create mode 100644 tgui/packages/tgui/bandastation/ImageButton.scss create mode 100644 tgui/packages/tgui/bandastation/ImageButton.tsx create mode 100644 tgui/packages/tgui/bandastation/ItemDisplay220.tsx diff --git a/tgui/packages/tgui/bandastation/ImageButton.scss b/tgui/packages/tgui/bandastation/ImageButton.scss new file mode 100644 index 0000000000000..cddf4d48c1e15 --- /dev/null +++ b/tgui/packages/tgui/bandastation/ImageButton.scss @@ -0,0 +1,276 @@ +/** + * Copyright (c) 2024 Aylong (https://github.com/AyIong) + * SPDX-License-Identifier: MIT + */ +@use '~tgui/styles/base.scss'; +@use '~tgui/styles/colors.scss'; +@use '../styles/functions.scss' as *; + +$color-default: colors.bg(base.$color-bg-section) !default; +$color-disabled: hsl(0, 55%, 25%) !default; +$color-selected: colors.bg(colors.$green) !default; +$bg-map: colors.$bg-map !default; + +@function round-color($color, $opacity: null) { + $r: round(red($color)); + $g: round(green($color)); + $b: round(blue($color)); + @if $opacity != null { + @return rgba($r, $g, $b, $opacity); + } + @return rgb($r, $g, $b); +} + +@mixin button-style( + $color, + $border-color: round-color(lighten($color, 50%), 0.2), + $border-width: 1px 0 0 0, + $opacity: 0.2, + $hoverable: true, + $transition-duration: 0.2s +) { + $text-color: if(luminance($color) > 0.3, black, white); + background-color: round-color($color, $opacity); + color: $text-color; + border: solid $border-color; + border-width: $border-width; + transition: + background-color $transition-duration, + border-color $transition-duration; + + @if $hoverable { + &:hover { + background-color: round-color(lighten($color, 50%), $opacity); + } + } +} + +@each $color-name, $color-value in $bg-map { + .color__#{$color-name} { + @include button-style($color-value, $border-width: 1px); + } + + .contentColor__#{$color-name} { + @include button-style( + $color-value, + $border-color: lighten($color-value, 25%), + $opacity: 1, + $hoverable: false + ); + } + + .buttonsContainerColor__#{$color-name} { + @include button-style( + $color-value, + $border-width: 1px 1px 1px 0, + $opacity: 0.33, + $hoverable: false, + $transition-duration: 0 + ); + } +} + +.color__default { + @include button-style(lighten($color-default, 85%), $border-width: 1px); +} + +.disabled { + background-color: rgba($color-disabled, 0.25) !important; + border-color: rgba($color-disabled, 0.25) !important; +} + +.selected { + @include button-style( + $color-selected, + $border-color: rgba($color-selected, 0.25), + $border-width: 1px + ); +} + +.contentColor__default { + @include button-style( + lighten($color-default, 80%), + $border-color: lighten($color-default, 100%), + $opacity: 1, + $hoverable: false + ); +} + +.contentDisabled { + background-color: $color-disabled !important; + border-top: 1px solid lighten($color-disabled, 25%) !important; +} + +.contentSelected { + @include button-style( + $color-selected, + $border-color: lighten($color-selected, 25%), + $opacity: 1, + $hoverable: false + ); +} + +.buttonsContainerColor__default { + @include button-style( + lighten($color-default, 85%), + $border-width: 1px 1px 1px 0, + $hoverable: false, + $transition-duration: 0 + ); +} + +.ImageButton { + display: inline-table; + position: relative; + text-align: center; + margin: 0.25em; + user-select: none; + -ms-user-select: none; + + .noAction { + pointer-events: none; + } + + .container { + display: flex; + flex-direction: column; + border-radius: 0.33em; + } + + .image { + position: relative; + align-self: center; + pointer-events: none; + overflow: hidden; + line-height: 0; + padding: 0.25em; + border-radius: 0.33em; + } + + .buttonsContainer { + display: flex; + position: absolute; + overflow: hidden; + left: 1px; + bottom: 1.8em; + max-width: 100%; + z-index: 1; + + &.buttonsAltContainer { + overflow: visible; + flex-direction: column; + pointer-events: none; + top: 1px; + bottom: inherit !important; + } + + &.buttonsEmpty { + bottom: 1px; + } + + & > * { + /* I know !important is bad, but here's no other way */ + margin: 0 !important; + padding: 0 0.2em !important; + border-radius: 0 !important; + } + } + + .content { + -ms-user-select: none; + user-select: none; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding: 0.25em 0.5em; + margin: -1px; + border-radius: 0 0 0.33em 0.33em; + z-index: 2; + } +} + +.fluid { + display: flex; + flex-direction: row; + position: relative; + text-align: center; + margin: 0 0 0.5em 0; + user-select: none; + -ms-user-select: none; + + &:last-of-type { + margin-bottom: 0; + } + + .info { + display: flex; + flex-direction: column; + justify-content: center; + flex: 1; + } + + .title { + font-weight: bold; + padding: 0.5em; + + &.divider { + margin: 0 0.5em; + border-bottom: base.em(2px) solid rgba(255, 255, 255, 0.1); + } + } + + .contentFluid { + padding: 0.5em; + color: white; + } + + .container { + flex-direction: row; + flex: 1; + + &.hasButtons { + border-radius: 0.33em 0 0 0.33em; + border-width: 1px 0 1px 1px; + } + } + + .image { + padding: 0; + } + + .buttonsContainer { + position: relative; + left: inherit; + bottom: inherit; + border-radius: 0 0.33em 0.33em 0; + + &.buttonsEmpty { + bottom: inherit; + } + + &.buttonsAltContainer { + overflow: hidden; + pointer-events: auto; + top: inherit; + + & > * { + border-top: 1px solid rgba(255, 255, 255, 0.075); + + &:first-child { + border-top: 0; + } + } + } + + & > * { + display: inline-flex; + flex-direction: column; + justify-content: center; + text-align: center; + white-space: pre-wrap; + line-height: base.em(14px); + height: 100%; + border-left: 1px solid rgba(255, 255, 255, 0.075); + } + } +} diff --git a/tgui/packages/tgui/bandastation/ImageButton.tsx b/tgui/packages/tgui/bandastation/ImageButton.tsx new file mode 100644 index 0000000000000..785b98ed0d267 --- /dev/null +++ b/tgui/packages/tgui/bandastation/ImageButton.tsx @@ -0,0 +1,245 @@ +/** + * @file + * @copyright 2024 Aylong (https://github.com/AyIong) + * @license MIT + */ + +import './ImageButton.scss'; + +import { Placement } from '@popperjs/core'; +import { BooleanLike, classes } from 'common/react'; +import { ReactNode } from 'react'; + +import { BoxProps, computeBoxProps } from '../components/Box'; +import { DmIcon } from '../components/DmIcon'; +import { Icon } from '../components/Icon'; +import { Image } from '../components/Image'; +import { Stack } from '../components/Stack'; +import { Tooltip } from '../components/Tooltip'; + +type Props = Partial<{ + /** Asset cache. Example: `asset={`assetname32x32, ${thing.key}`}` */ + asset: string[]; + /** Classic way to put images. Example: `base64={thing.image}` */ + base64: string; + /** + * Special container for buttons. + * You can put any other component here. + * Has some special stylings! + * Example: `buttons={}` + */ + buttons: ReactNode; + /** + * Same as buttons, but. Have disabled pointer-events on content inside if non-fluid. + * Fluid version have humburger layout. + */ + buttonsAlt: ReactNode; + /** Content under image. Or on the right if fluid. */ + children: ReactNode; + /** Applies a CSS class to the element. */ + className: string; + /** Color of the button. See [Button](#button) but without `transparent`. */ + color: string; + /** Makes button disabled and dark red if true. Also disables onClick. */ + disabled: BooleanLike; + /** Optional. Adds a "stub" when loading DmIcon. */ + dmFallback: ReactNode; + /** Parameter `icon` of component `DmIcon`. */ + dmIcon: string | null; + /** Parameter `icon_state` of component `DmIcon`. */ + dmIconState: string | null; + /** Parameter `direction` of component `DmIcon`. */ + dmDirection: any; + /** + * Changes the layout of the button, making it fill the entire horizontally available space. + * Allows the use of `title` + */ + fluid: boolean; + /** Parameter responsible for the size of the image, component and standard "stubs". */ + imageSize: number; + /** Prop `src` of . Example: `imageSrc={resolveAsset(thing.image}` */ + imageSrc: string; + /** Called when button is clicked with LMB. */ + onClick: (e: any) => void; + /** Called when button is clicked with RMB. */ + onRightClick: (e: any) => void; + /** Makes button selected and green if true. */ + selected: BooleanLike; + /** Requires `fluid` for work. Bold text with divider betwen content. */ + title: string; + /** A fancy, boxy tooltip, which appears when hovering over the button */ + tooltip: ReactNode; + /** Position of the tooltip. See [`Popper`](#Popper) for valid options. */ + tooltipPosition: Placement; +}> & + BoxProps; + +export const ImageButton = (props: Props) => { + const { + asset, + base64, + buttons, + buttonsAlt, + children, + className, + color, + disabled, + dmFallback, + dmDirection, + dmIcon, + dmIconState, + fluid, + imageSize = 64, + imageSrc, + onClick, + onRightClick, + selected, + title, + tooltip, + tooltipPosition, + ...rest + } = props; + + const getFallback = (iconName: string, iconSpin: boolean) => { + return ( + + + + + + ); + }; + + let buttonContent = ( +
{ + if (!disabled && onClick) { + onClick(event); + } + }} + onContextMenu={(event) => { + event.preventDefault(); + if (!disabled && onRightClick) { + onRightClick(event); + } + }} + style={{ width: !fluid ? `calc(${imageSize}px + 0.5em + 2px)` : 'auto' }} + > +
+ {base64 || asset || imageSrc ? ( + + ) : dmIcon && dmIconState ? ( + + ) : ( + getFallback('question', false) + )} +
+ {fluid ? ( +
+ {title && ( + + {title} + + )} + {children && ( + {children} + )} +
+ ) : ( + children && ( + + {children} + + ) + )} +
+ ); + + if (tooltip) { + buttonContent = ( + + {buttonContent} + + ); + } + + return ( +
+ {buttonContent} + {buttons && ( +
+ {buttons} +
+ )} + {buttonsAlt && ( +
+ {buttonsAlt} +
+ )} +
+ ); +}; diff --git a/tgui/packages/tgui/bandastation/ItemDisplay220.tsx b/tgui/packages/tgui/bandastation/ItemDisplay220.tsx new file mode 100644 index 0000000000000..b3847d85117fe --- /dev/null +++ b/tgui/packages/tgui/bandastation/ItemDisplay220.tsx @@ -0,0 +1,86 @@ +import { Box, Button } from 'tgui-core/components'; + +import { useBackend } from '../backend'; +import { LoadoutItem } from '../interfaces/PreferencesMenu/loadout/base'; +import { ImageButton } from './ImageButton'; + +export const ItemDisplay220 = (props: { + active: boolean; + item: LoadoutItem; +}) => { + const { act } = useBackend(); + const { active, item } = props; + const icon = item.icon; + const iconState = item.icon_state; + const costText = + item.cost === 1 + ? `${item.cost} Очко` + : item.cost < 4 + ? `${item.cost} Очка` + : `${item.cost} Очков`; + + const textInfo = ( + + + {/* gear.gear_tier > 0 && `Tier ${gear.gear_tier}` */} + + + {costText} + + + ); + + const getIcon = (info: string) => { + switch (info) { + case 'Recolorable': + return 'palette'; + case 'Renamable': + return 'font'; + case 'Reskinnable': + return 'paint-brush'; + case 'Prescription': + return 'prescription'; + default: + return 'question'; + } + }; + + return ( + ( + ); @@ -100,16 +96,15 @@ const ItemListDisplay = (props: { items: LoadoutItem[] }) => { const { data } = useBackend(); const { loadout_list } = data.character_preferences.misc; return ( - +
{props.items.map((item) => ( - - - + ))} - +
); }; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/base.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/base.ts index 139c73b112bac..575de19ba342a 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/base.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/loadout/base.ts @@ -31,7 +31,7 @@ export type LoadoutItem = { buttons: LoadoutButton[]; reskins: ReskinOption[] | null; information: string[]; - cost: string; + cost: number; }; // Category of items in the loadout