Repository: tgstation/tgstation
Pull request #89883: Adds several new decals to the Tile Sprayer
Author: login: ghost
Labels: name: Feature
description: Exposes new bugs in interesting ways
Created: 2025-03-07T08:02:55Z | Merged: 2025-03-17T07:50:25Z


## About The Pull Request
Continuing my conquest against irrepairable features.
Today, adding a lot of the missing decals to the Tile Sprayer.
This doesn't include sidings or the likes, only the paints. ~~And it's technically missing like, 3, but if they were added then the UI would use the multiple-of-5 thats holding it together.~~

Also a tiny thing but I moved the 1-dir tiles to be the first of their cluster, so it flows kind of like subsections (Primary, Filled Trims, Thin Trims, so on so on)

> **Thank you @RealWinterFrost for showing me how easy it was to add more decals to this list.**
> **Thank you @jlsnow301 for helping me with the UI when I decided that I couldn't accept it being easy.**

<details><summary>A few preview tiles to prove that it works</summary>

![image](https://github.com/user-attachments/assets/086318f0-488b-4290-a7c4-7077774f20dd)

</details>
<details><summary>The UI now includes a scrollbar! Wow! This took me hours!</summary>

![image](https://github.com/user-attachments/assets/10f769f9-51a5-4df6-9855-adbefdcd4357)

</details>
<details><summary>The full list of newly-available tile decals</summary>

![image](https://github.com/user-attachments/assets/0de41fe0-80a5-4288-8117-5f1d325cfa22)

</details>

> _The current way the spritesheets are set up, all tiles use the same base floortile for the preview icon - this makes the Diagonal Centre/Edge, Full Tile, Full Half, and Full Anticorner decals look a bit odd in the UI. Technically functional, but- well, you can see it in the 3rd dropdown._
> _If anybody knows anything about spritesheets that might fix this then I'd appreciate it._

> _~~Also if any really cool coders want to redo this UI with Categories ala the RPD so we can cram the Tile Sprayer and Decal Painter into one item that would be cool. I sadly cannot because I lack talent.~~_
## Why It's Good For The Game
One of the banes of SS13 is items or details players can use/see, but cannot recreate. Giving players tools to rebuild what mappers place makes the game world feel a lot more natural.

Now, our floors shall truly be beautiful.
## Changelog
:cl:
add: the Tile Sprayer now includes quite a few more tile decals! Warning lines, guide arrows, diagonals and filled tiles! Wow!
/:cl:



Diff:
diff --git a/code/game/objects/items/airlock_painter.dm b/code/game/objects/items/airlock_painter.dm
index 52962c0684e34e..939d5c5a0589d0 100644
--- a/code/game/objects/items/airlock_painter.dm
+++ b/code/game/objects/items/airlock_painter.dm
@@ -399,20 +399,48 @@
 		list("R&D Purple", "#D381C9"),
 	)
 	decal_list = list(
+		//Primary Category
+		list("4 Corners", "tile_fourcorners"),
 		list("Corner", "tile_corner"),
 		list("Half", "tile_half_contrasted"),
 		list("Opposing Corners", "tile_opposing_corners"),
 		list("3 Corners", "tile_anticorner_contrasted"),
-		list("4 Corners", "tile_fourcorners"),
-		list("Trimline Corner", "trimline_corner_fill"),
-		list("Trimline Fill", "trimline_fill"),
-		list("Trimline Fill L", "trimline_fill__8"), // This is a hack that lives in the spritesheet builder and paint_floor
-		list("Trimline End", "trimline_end_fill"),
-		list("Trimline Box", "trimline_box_fill"),
+		//Trimlines Category
+		list("Trimline Filled Box", "trimline_box_fill"),
+		list("Trimline Filled Corner", "trimline_corner_fill"),
+		list("Trimline Filled", "trimline_fill"),
+		list("Trimline Filled L ", "trimline_fill__8"), // This is a hack that lives in the spritesheet builder and paint_floor
+		list("Trimline Filled End", "trimline_end_fill"),
+		list("Trimline Box", "trimline_box"),
+		list("Trimline Corner", "trimline_corner"),
+		list("Trimline", "trimline"),
+		list("Trimline L ", "trimline__8"),
+		list("Trimline End", "trimline_end"),
+		//A few misc decals to break up the UI a touch
+		list("Diagonal Centre", "diagonal_centre"),
+		list("Diagonal Edge", "diagonal_edge"),
+		list("Full Tile", "tile_full"),
+		list("Full Half", "tile_half"),
+		list("Full Anticorner", "tile_anticorner"),
+		//Decorative Trimlines Category
+		list("Trimline Connector L", "trimline_shrink_cw"),
+		list("Trimline Connector R", "trimline_shrink_ccw"),
+		list("Trimline Arrow L Filled", "trimline_arrow_cw_fill"),
+		list("Trimline Arrow R Filled", "trimline_arrow_ccw_fill"),
+		list("Trimline Warn Filled", "trimline_warn_fill"),
+		list("Trimline Warn Filled L", "trimline_warn_fill__8"),
+		list("Trimline Warn", "trimline_warn"),
+		list("Trimline Warn L", "trimline_warn__8"),
+		list("Trimline Arrow L", "trimline_arrow_cw"),
+		list("Trimline Arrow R", "trimline_arrow_ccw"),
 	)
 	nondirectional_decals = list(
 		"tile_fourcorners",
 		"trimline_box_fill",
+		"trimline_box",
+		"diagonal_centre",
+		"diagonal_edge",
+		"tile_full",
 	)
 
 	/// Regex to split alpha out.
diff --git a/tgui/packages/tgui/interfaces/DecalPainter.tsx b/tgui/packages/tgui/interfaces/DecalPainter.tsx
index 5b45db3a4ddadd..b60ea31a27d456 100644
--- a/tgui/packages/tgui/interfaces/DecalPainter.tsx
+++ b/tgui/packages/tgui/interfaces/DecalPainter.tsx
@@ -1,4 +1,4 @@
-import { Button, ColorBox, Flex, Section } from 'tgui-core/components';
+import { Button, ColorBox, Flex, Section, Stack } from 'tgui-core/components';
 
 import { useBackend } from '../backend';
 import { Window } from '../layouts';
@@ -51,83 +51,93 @@ export const DecalPainter = (props) => {
   // Handle custom color icon correctly
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
+  const {
+    color_list,
+    current_custom_color,
+    current_color,
+    current_decal,
+    current_dir,
+    decal_list,
+    dir_list,
+  } = data;
+
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === current_color}
+                    onClick={() =>
+                      act('select color', {
+                        color: color.color,
+                      })
+                    }
+                  >
+                    <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
+                    {color.name}
+                  </Button>
+                );
+              })}
+              {supports_custom_color && (
+                <Button
+                  selected={custom_color_selected}
+                  onClick={() => act('pick custom color')}
                 >
-                  {data.dir_list.map((dir) => {
-                    const selected =
-                      decal.decal === data.current_decal &&
-                      dir.dir === data.current_dir;
-
-                    return (
-                      <IconButton
-                        key={dir.dir}
-                        decal={decal.decal}
-                        dir={dir.dir}
-                        color={preview_color}
-                        label={`${dir.name} ${decal.name}`}
-                        selected={selected}
-                      />
-                    );
-                  })}
-                </Flex>
-              );
-            })}
-          </Flex>
-        </Section>
+                  <ColorBox color={current_custom_color} mr={0.5} />
+                  Custom
+                </Button>
+              )}
+            </Section>
+          </Stack.Item>
+          <Stack.Item grow>
+            <Section title="Decal Style" fill scrollable>
+              <Flex wrap="wrap">
+                {decal_list.map((decal) => {
+                  const nondirectional = data.nondirectional_decals.includes(
+                    decal.decal,
+                  );
+
+                  return nondirectional ? (
+                    // Tallll button for nondirectional
+                    <IconButton
+                      key={decal.decal}
+                      decal={decal.decal}
+                      dir={2}
+                      color={preview_color}
+                      label={decal.name}
+                      selected={decal.decal === current_decal}
+                    />
+                  ) : (
+                    // 4 buttons for directional
+                    <Flex key={decal.decal} direction="column">
+                      {dir_list.map((dir) => {
+                        const selected =
+                          decal.decal === current_decal &&
+                          dir.dir === current_dir;
+
+                        return (
+                          <IconButton
+                            key={dir.dir}
+                            decal={decal.decal}
+                            dir={dir.dir}
+                            color={preview_color}
+                            label={`${dir.name} ${decal.name}`}
+                            selected={selected}
+                          />
+                        );
+                      })}
+                    </Flex>
+                  );
+                })}
+              </Flex>
+            </Section>
+          </Stack.Item>
+        </Stack>
       </Window.Content>
     </Window>
   );


Reviews:
user: login: jlsnow301
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T20:19:01Z
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-08T05:14:21Z
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-08T05:15:03Z
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-08T05:15:49Z
user: login: jlsnow301
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-08T06:42:53Z
user: login: jlsnow301
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-08T06:47:22Z
user: login: jlsnow301
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-08T06:49:54Z
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-10T09:22:57Z
user: login: jlsnow301
body: `scrollable` on section is just overflowY behind the curtain. pls use the intended props before resorting to using `style`
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-10T16:01:31Z
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-11T05:52:58Z
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-13T07:17:05Z
user: login: jlsnow301
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-13T20:03:31Z
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-14T06:04:11Z

Review comments:
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
+                    onClick={() =>
+                      act('select color', {
+                        color: color.color,
+                      })
+                    }
+                  >
+                    <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
+                    {color.name}
+                  </Button>
+                );
+              })}
+              {supports_custom_color && (
+                <Button
+                  selected={custom_color_selected}
+                  onClick={() => act('pick custom color')}
                 >
-                  {data.dir_list.map((dir) => {
-                    const selected =
-                      decal.decal === data.current_decal &&
-                      dir.dir === data.current_dir;
-
-                    return (
-                      <IconButton
-                        key={dir.dir}
-                        decal={decal.decal}
-                        dir={dir.dir}
-                        color={preview_color}
-                        label={`${dir.name} ${decal.name}`}
-                        selected={selected}
-                      />
-                    );
-                  })}
-                </Flex>
-              );
-            })}
-          </Flex>
-        </Section>
+                  <ColorBox color={data.current_custom_color} mr={0.5} />
+                  Custom
+                </Button>
+              )}
+            </Section>
+          </Stack.Item>
+          <Stack.Item grow style={{ overflowY: 'auto', overflowX: 'hidden' }}>
+            <Section title="Decal Style" scrollable fill>
+              <Flex direction="row" wrap="wrap" align="fill" justify="fill">
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
user: login: jlsnow301
body: this is kinda confusing. 
1. what's supposed to scroll here? both the stack item and the section are getting scrollbars bc `overflow`
2. what does flex do here? is fill even an option on `align` or `justify`? direction is also row by default. what does it look like without this?

created_at: 2025-03-07T20:16:12Z
author_association: MEMBER
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
+                    onClick={() =>
+                      act('select color', {
+                        color: color.color,
+                      })
+                    }
+                  >
+                    <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
+                    {color.name}
+                  </Button>
+                );
+              })}
+              {supports_custom_color && (
+                <Button
+                  selected={custom_color_selected}
+                  onClick={() => act('pick custom color')}
                 >
-                  {data.dir_list.map((dir) => {
-                    const selected =
-                      decal.decal === data.current_decal &&
-                      dir.dir === data.current_dir;
-
-                    return (
-                      <IconButton
-                        key={dir.dir}
-                        decal={decal.decal}
-                        dir={dir.dir}
-                        color={preview_color}
-                        label={`${dir.name} ${decal.name}`}
-                        selected={selected}
-                      />
-                    );
-                  })}
-                </Flex>
-              );
-            })}
-          </Flex>
-        </Section>
+                  <ColorBox color={data.current_custom_color} mr={0.5} />
+                  Custom
+                </Button>
+              )}
+            </Section>
+          </Stack.Item>
+          <Stack.Item grow style={{ overflowY: 'auto', overflowX: 'hidden' }}>
+            <Section title="Decal Style" scrollable fill>
+              <Flex direction="row" wrap="wrap" align="fill" justify="fill">
+                {data.decal_list.map((decal) => {
+                  const nondirectional = data.nondirectional_decals.includes(
+                    decal.decal,
+                  );
+
+                  return nondirectional ? (
+                    // Tallll button for nondirectional
+                    <IconButton
+                      key={decal.decal}
+                      decal={decal.decal}
+                      dir={2}
+                      color={preview_color}
+                      label={decal.name}
+                      selected={decal.decal === data.current_decal}
+                    />
+                  ) : (
+                    // 4 buttons for directional
+                    <Flex
+                      key={decal.decal}
+                      direction="column"
+                      wrap="nowrap"
+                      align="fill"
+                      justify="fill"
+                    >
+                      {data.dir_list.map((dir) => {
+                        const selected =
+                          decal.decal === data.current_decal &&
+                          dir.dir === data.current_dir;
+
+                        return (
+                          <IconButton
+                            key={dir.dir}
+                            decal={decal.decal}
+                            dir={dir.dir}
+                            color={preview_color}
+                            label={`${dir.name} ${decal.name}`}
+                            selected={selected}
+                          />
+                        );
+                      })}
+                    </Flex>
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
user: login: jlsnow301
body: 1. probably valid to break into its own component
2. more weird flex props. 
3. why not use stack?
created_at: 2025-03-07T20:17:43Z
author_association: MEMBER
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
user: login: jlsnow301
body: everything `data.x` should be deconstructed before the return block, it's free
created_at: 2025-03-07T20:18:54Z
author_association: MEMBER
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
+                    onClick={() =>
+                      act('select color', {
+                        color: color.color,
+                      })
+                    }
+                  >
+                    <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
+                    {color.name}
+                  </Button>
+                );
+              })}
+              {supports_custom_color && (
+                <Button
+                  selected={custom_color_selected}
+                  onClick={() => act('pick custom color')}
                 >
-                  {data.dir_list.map((dir) => {
-                    const selected =
-                      decal.decal === data.current_decal &&
-                      dir.dir === data.current_dir;
-
-                    return (
-                      <IconButton
-                        key={dir.dir}
-                        decal={decal.decal}
-                        dir={dir.dir}
-                        color={preview_color}
-                        label={`${dir.name} ${decal.name}`}
-                        selected={selected}
-                      />
-                    );
-                  })}
-                </Flex>
-              );
-            })}
-          </Flex>
-        </Section>
+                  <ColorBox color={data.current_custom_color} mr={0.5} />
+                  Custom
+                </Button>
+              )}
+            </Section>
+          </Stack.Item>
+          <Stack.Item grow style={{ overflowY: 'auto', overflowX: 'hidden' }}>
+            <Section title="Decal Style" scrollable fill>
+              <Flex direction="row" wrap="wrap" align="fill" justify="fill">
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
body: Does overflow give it a scrollbar? If so that's nifty

And the flex was pre-existing code. I'll see how it looks without the extra stuff
created_at: 2025-03-08T05:14:21Z
author_association: NONE
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
+                    onClick={() =>
+                      act('select color', {
+                        color: color.color,
+                      })
+                    }
+                  >
+                    <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
+                    {color.name}
+                  </Button>
+                );
+              })}
+              {supports_custom_color && (
+                <Button
+                  selected={custom_color_selected}
+                  onClick={() => act('pick custom color')}
                 >
-                  {data.dir_list.map((dir) => {
-                    const selected =
-                      decal.decal === data.current_decal &&
-                      dir.dir === data.current_dir;
-
-                    return (
-                      <IconButton
-                        key={dir.dir}
-                        decal={decal.decal}
-                        dir={dir.dir}
-                        color={preview_color}
-                        label={`${dir.name} ${decal.name}`}
-                        selected={selected}
-                      />
-                    );
-                  })}
-                </Flex>
-              );
-            })}
-          </Flex>
-        </Section>
+                  <ColorBox color={data.current_custom_color} mr={0.5} />
+                  Custom
+                </Button>
+              )}
+            </Section>
+          </Stack.Item>
+          <Stack.Item grow style={{ overflowY: 'auto', overflowX: 'hidden' }}>
+            <Section title="Decal Style" scrollable fill>
+              <Flex direction="row" wrap="wrap" align="fill" justify="fill">
+                {data.decal_list.map((decal) => {
+                  const nondirectional = data.nondirectional_decals.includes(
+                    decal.decal,
+                  );
+
+                  return nondirectional ? (
+                    // Tallll button for nondirectional
+                    <IconButton
+                      key={decal.decal}
+                      decal={decal.decal}
+                      dir={2}
+                      color={preview_color}
+                      label={decal.name}
+                      selected={decal.decal === data.current_decal}
+                    />
+                  ) : (
+                    // 4 buttons for directional
+                    <Flex
+                      key={decal.decal}
+                      direction="column"
+                      wrap="nowrap"
+                      align="fill"
+                      justify="fill"
+                    >
+                      {data.dir_list.map((dir) => {
+                        const selected =
+                          decal.decal === data.current_decal &&
+                          dir.dir === data.current_dir;
+
+                        return (
+                          <IconButton
+                            key={dir.dir}
+                            decal={decal.decal}
+                            dir={dir.dir}
+                            color={preview_color}
+                            label={`${dir.name} ${decal.name}`}
+                            selected={selected}
+                          />
+                        );
+                      })}
+                    </Flex>
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
body: I'll be honest on this, no clue what any of that means. I didn't change any code in here, this is how the UI already worked.

I understand the flex thing though I can see if removing those breaks it
created_at: 2025-03-08T05:15:03Z
author_association: NONE
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
body: Same as the other comment, I don't know what this means (I can vaguely READ UI code but have no clue about terms or how to make it work from scratch)
created_at: 2025-03-08T05:15:49Z
author_association: NONE
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
+                    onClick={() =>
+                      act('select color', {
+                        color: color.color,
+                      })
+                    }
+                  >
+                    <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
+                    {color.name}
+                  </Button>
+                );
+              })}
+              {supports_custom_color && (
+                <Button
+                  selected={custom_color_selected}
+                  onClick={() => act('pick custom color')}
                 >
-                  {data.dir_list.map((dir) => {
-                    const selected =
-                      decal.decal === data.current_decal &&
-                      dir.dir === data.current_dir;
-
-                    return (
-                      <IconButton
-                        key={dir.dir}
-                        decal={decal.decal}
-                        dir={dir.dir}
-                        color={preview_color}
-                        label={`${dir.name} ${decal.name}`}
-                        selected={selected}
-                      />
-                    );
-                  })}
-                </Flex>
-              );
-            })}
-          </Flex>
-        </Section>
+                  <ColorBox color={data.current_custom_color} mr={0.5} />
+                  Custom
+                </Button>
+              )}
+            </Section>
+          </Stack.Item>
+          <Stack.Item grow style={{ overflowY: 'auto', overflowX: 'hidden' }}>
+            <Section title="Decal Style" scrollable fill>
+              <Flex direction="row" wrap="wrap" align="fill" justify="fill">
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
user: login: jlsnow301
body: https://www.w3schools.com/css/css_overflow.asp
created_at: 2025-03-08T06:42:53Z
author_association: MEMBER
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
+                    onClick={() =>
+                      act('select color', {
+                        color: color.color,
+                      })
+                    }
+                  >
+                    <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
+                    {color.name}
+                  </Button>
+                );
+              })}
+              {supports_custom_color && (
+                <Button
+                  selected={custom_color_selected}
+                  onClick={() => act('pick custom color')}
                 >
-                  {data.dir_list.map((dir) => {
-                    const selected =
-                      decal.decal === data.current_decal &&
-                      dir.dir === data.current_dir;
-
-                    return (
-                      <IconButton
-                        key={dir.dir}
-                        decal={decal.decal}
-                        dir={dir.dir}
-                        color={preview_color}
-                        label={`${dir.name} ${decal.name}`}
-                        selected={selected}
-                      />
-                    );
-                  })}
-                </Flex>
-              );
-            })}
-          </Flex>
-        </Section>
+                  <ColorBox color={data.current_custom_color} mr={0.5} />
+                  Custom
+                </Button>
+              )}
+            </Section>
+          </Stack.Item>
+          <Stack.Item grow style={{ overflowY: 'auto', overflowX: 'hidden' }}>
+            <Section title="Decal Style" scrollable fill>
+              <Flex direction="row" wrap="wrap" align="fill" justify="fill">
+                {data.decal_list.map((decal) => {
+                  const nondirectional = data.nondirectional_decals.includes(
+                    decal.decal,
+                  );
+
+                  return nondirectional ? (
+                    // Tallll button for nondirectional
+                    <IconButton
+                      key={decal.decal}
+                      decal={decal.decal}
+                      dir={2}
+                      color={preview_color}
+                      label={decal.name}
+                      selected={decal.decal === data.current_decal}
+                    />
+                  ) : (
+                    // 4 buttons for directional
+                    <Flex
+                      key={decal.decal}
+                      direction="column"
+                      wrap="nowrap"
+                      align="fill"
+                      justify="fill"
+                    >
+                      {data.dir_list.map((dir) => {
+                        const selected =
+                          decal.decal === data.current_decal &&
+                          dir.dir === data.current_dir;
+
+                        return (
+                          <IconButton
+                            key={dir.dir}
+                            decal={decal.decal}
+                            dir={dir.dir}
+                            color={preview_color}
+                            label={`${dir.name} ${decal.name}`}
+                            selected={selected}
+                          />
+                        );
+                      })}
+                    </Flex>
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
user: login: jlsnow301
body: you can (and should) abstract chunks of react code when it makes it more readable to do so - in this case, you can pull this entire block into its own subcomponent. the size of a react component should be 30-100 lines ish
created_at: 2025-03-08T06:47:22Z
author_association: MEMBER
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
user: login: jlsnow301
body: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring
created_at: 2025-03-08T06:49:54Z
author_association: MEMBER
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
+                    onClick={() =>
+                      act('select color', {
+                        color: color.color,
+                      })
+                    }
+                  >
+                    <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
+                    {color.name}
+                  </Button>
+                );
+              })}
+              {supports_custom_color && (
+                <Button
+                  selected={custom_color_selected}
+                  onClick={() => act('pick custom color')}
                 >
-                  {data.dir_list.map((dir) => {
-                    const selected =
-                      decal.decal === data.current_decal &&
-                      dir.dir === data.current_dir;
-
-                    return (
-                      <IconButton
-                        key={dir.dir}
-                        decal={decal.decal}
-                        dir={dir.dir}
-                        color={preview_color}
-                        label={`${dir.name} ${decal.name}`}
-                        selected={selected}
-                      />
-                    );
-                  })}
-                </Flex>
-              );
-            })}
-          </Flex>
-        </Section>
+                  <ColorBox color={data.current_custom_color} mr={0.5} />
+                  Custom
+                </Button>
+              )}
+            </Section>
+          </Stack.Item>
+          <Stack.Item grow style={{ overflowY: 'auto', overflowX: 'hidden' }}>
+            <Section title="Decal Style" scrollable fill>
+              <Flex direction="row" wrap="wrap" align="fill" justify="fill">
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
body: > 1. what's supposed to scroll here? both the stack item and the section are getting scrollbars bc `overflow`


This one came out just fine removing the scrollbar, neat to know overflow does that

>  2. what does flex do here? is fill even an option on `align` or `justify`? direction is also row by default. what does it look like without this?

<details><summary>I think I found what the flex does</summary>

![image](https://github.com/user-attachments/assets/d9ede190-f288-4cd8-b748-98c5e3f7d971)

</details>

The align/justify within the flex are useless though, functions the same without those. 
Lots of default values in the flexes in the file, cleared them all out
created_at: 2025-03-10T09:22:57Z
author_association: NONE
diff_hunk: @@ -85,8 +85,8 @@ export const DecalPainter = (props) => {
             </Section>
           </Stack.Item>
           <Stack.Item grow style={{ overflowY: 'auto', overflowX: 'hidden' }}>
-            <Section title="Decal Style" scrollable fill>
-              <Flex direction="row" wrap="wrap" align="fill" justify="fill">
+            <Section title="Decal Style" fill>
+              <Flex wrap="wrap">
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
user: login: jlsnow301
body: ```
<Stack.Item grow>
  <Section title="Decal Style" fill scrollable>
    <Flex wrap="wrap">
```

created_at: 2025-03-10T16:00:40Z
author_association: MEMBER
diff_hunk: @@ -85,8 +85,8 @@ export const DecalPainter = (props) => {
             </Section>
           </Stack.Item>
           <Stack.Item grow style={{ overflowY: 'auto', overflowX: 'hidden' }}>
-            <Section title="Decal Style" scrollable fill>
-              <Flex direction="row" wrap="wrap" align="fill" justify="fill">
+            <Section title="Decal Style" fill>
+              <Flex wrap="wrap">
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
body: Odd, could have sworn during testing this wasn't working until I did the overflow. Now scrollable is working though.
created_at: 2025-03-11T05:52:58Z
author_association: NONE
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
body: Before I commit, does this look right?
![image](https://github.com/user-attachments/assets/9f374231-fd8e-4618-af34-f41e126b76a0)

created_at: 2025-03-13T07:17:05Z
author_association: NONE
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
user: login: jlsnow301
body: it does, but it's not the ask. you're only using that var once, so it's not really beneficial to make an abstraction.

i meant that, before the jsx block, you unpack the contents of `data` into their own vars. the result would look something like this:

```tsx
const { color_list, current_custom_color, dir_list, decal_list, // etc } = data;

return (
<Section ... >
{color_list.map((color) => { // no longer need to write data. prefix
```

keep in mind that this is an opinion/style nit that you don't /have/ to do, but it's free (performance wise) and easy
created_at: 2025-03-13T20:03:31Z
author_association: MEMBER
diff_hunk: @@ -52,82 +52,88 @@ export const DecalPainter = (props) => {
   const preview_color = custom_color_selected ? 'custom' : data.current_color;
 
   return (
-    <Window width={550} height={400}>
+    <Window width={525} height={400}>
       <Window.Content>
-        <Section title="Decal Color">
-          {data.color_list.map((color) => {
-            return (
-              <Button
-                key={color.color}
-                selected={color.color === data.current_color}
-                onClick={() =>
-                  act('select color', {
-                    color: color.color,
-                  })
-                }
-              >
-                <ColorBox color={filterBoxColor(color.color)} mr={0.5} />
-                {color.name}
-              </Button>
-            );
-          })}
-          {supports_custom_color && (
-            <Button
-              selected={custom_color_selected}
-              onClick={() => act('pick custom color')}
-            >
-              <ColorBox color={data.current_custom_color} mr={0.5} />
-              Custom
-            </Button>
-          )}
-        </Section>
-        <Section title="Decal Style">
-          <Flex direction="row" wrap="nowrap" align="fill" justify="fill">
-            {data.decal_list.map((decal) => {
-              const nondirectional = data.nondirectional_decals.includes(
-                decal.decal,
-              );
-
-              return nondirectional ? (
-                // Tallll button for nondirectional
-                <IconButton
-                  key={decal.decal}
-                  decal={decal.decal}
-                  dir={2}
-                  color={preview_color}
-                  label={decal.name}
-                  selected={decal.decal === data.current_decal}
-                />
-              ) : (
-                // 4 buttons for directional
-                <Flex
-                  key={decal.decal}
-                  direction="column"
-                  wrap="nowrap"
-                  align="fill"
-                  justify="fill"
+        <Stack fill vertical>
+          <Stack.Item>
+            <Section title="Decal Color">
+              {data.color_list.map((color) => {
+                return (
+                  <Button
+                    key={color.color}
+                    selected={color.color === data.current_color}
path: tgui/packages/tgui/interfaces/DecalPainter.tsx
body: ohhhh I get it, should be right now with https://github.com/tgstation/tgstation/pull/89883/commits/6ccd285311c359a05aa80c146cbbee5acb4901cf
created_at: 2025-03-14T06:04:11Z
author_association: NONE

PR comments:
user: login: EmptyLullaby
created_at: 2025-03-08T05:18:47Z
body: ive been wanting this for years. 
author_association: CONTRIBUTOR
user: login: ghost
created_at: 2025-03-14T10:16:19Z
body: I'm excited for this PR!
author_association: NONE