Skip to content

feat(template): Cylinders 3d#6

Merged
Aarebecca merged 5 commits into
devfrom
cylinders-3d
Nov 4, 2025
Merged

feat(template): Cylinders 3d#6
Aarebecca merged 5 commits into
devfrom
cylinders-3d

Conversation

@yvonneyx

@yvonneyx yvonneyx commented Nov 3, 2025

Copy link
Copy Markdown
Contributor
image

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @yvonneyx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the infographic library by introducing a novel 3D cylinder sequence visualization. This new structure provides a visually rich and dynamic way to represent ordered data, allowing for customizable depth, height, and item alignment. The addition of an 'alternating' item component further refines the presentation, offering a clean and organized display for associated data points. This feature expands the toolkit for creating engaging and informative infographics.

Highlights

  • New 3D Cylinder Sequence Structure: Introduced a new sequenceCylinders3d component for visualizing data as a sequence of dynamically sized and positioned 3D cylinders.
  • Alternating Item Component: Added an AlternatingItem component that displays item labels and descriptions with alternating left and right alignment, suitable for sequential layouts.
  • Advanced 3D Rendering with Gradients: Implemented detailed gradient definitions using tinycolor2 to create realistic 3D effects for cylinders, including body, top, bottom, numbered labels, and glow effects.
  • Dynamic Layout and Positioning: Developed sophisticated layout calculation functions to determine cylinder and item positions, depth offsets, and heights based on the number of items and configurable properties.
  • New Built-in Template: Integrated a new built-in template, sequence-cylinders-3d-simple, which leverages the new 3D cylinder structure and alternating item component to provide a ready-to-use visualization.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new 'Cylinders 3d' template, which includes a new AlternatingItem component and a sequence-cylinders-3d structure. The implementation is comprehensive and visually impressive. My review focuses on improving robustness, maintainability, and correctness. I've identified a critical issue that could cause a crash with empty data, a misconfiguration in the new template, and opportunities to reduce code duplication and improve clarity by removing magic numbers.

Comment on lines +618 to +620
const itemBounds = getElementBounds(
<Item indexes={[0]} data={data} datum={items[0]} positionH="center" />,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The code assumes the items array is not empty when calculating itemBounds. If data.items is empty or not provided, items[0] will be undefined, which will likely cause a runtime error inside getElementBounds or the Item component. You should add a guard to handle cases where the items array is empty.

Suggested change
const itemBounds = getElementBounds(
<Item indexes={[0]} data={data} datum={items[0]} positionH="center" />,
);
const itemBounds = items.length
? getElementBounds(
<Item indexes={[0]} data={data} datum={items[0]} positionH="center" />,
)
: { width: 0, height: 0 };

'sequence-cylinders-3d-simple': {
design: {
title: 'default',
structure: { type: 'sequence-cylinders-3d', gapY: 20 },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The sequence-cylinders-3d structure is configured with a gapY: 20 property. However, the sequenceCylinders3d component does not define or accept a gapY prop. This property will be ignored and suggests a configuration error. Please review the available props for the component and use a valid one, such as depthSpacing, or remove this property.

Comment on lines +69 to +156
if (!showIcon || !icon) {
return (
<Group {...restProps}>
<Group>
<ItemLabel
indexes={indexes}
width={width}
alignHorizontal={textAlign}
alignVertical="center"
fill={labelColor}
>
{label}
</ItemLabel>
<ItemDesc
indexes={indexes}
width={width}
y={labelBounds.height + gap}
alignHorizontal={textAlign}
alignVertical="top"
fill={themeColors.colorTextSecondary}
>
{desc}
</ItemDesc>
</Group>
</Group>
);
}

const iconBounds = getElementBounds(iconContent);
const textWidth = Math.max(width - iconBounds.width - gap, 0);

return (
<Group {...restProps}>
<FlexLayout flexDirection="row" gap={gap} alignItems="flex-start">
{isOdd ? (
<>
<Group>
<ItemLabel
indexes={indexes}
width={textWidth}
alignHorizontal="right"
alignVertical="center"
fill={labelColor}
>
{label}
</ItemLabel>
<ItemDesc
indexes={indexes}
width={textWidth}
y={labelBounds.height + gap}
alignHorizontal="right"
alignVertical="top"
fill={themeColors.colorTextSecondary}
>
{desc}
</ItemDesc>
</Group>
{iconContent}
</>
) : (
<>
{iconContent}
<Group>
<ItemLabel
indexes={indexes}
width={textWidth}
alignHorizontal="left"
alignVertical="center"
fill={labelColor}
>
{label}
</ItemLabel>
<ItemDesc
indexes={indexes}
width={textWidth}
y={labelBounds.height + gap}
alignHorizontal="left"
alignVertical="top"
fill={themeColors.colorTextSecondary}
>
{desc}
</ItemDesc>
</Group>
</>
)}
</FlexLayout>
</Group>
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is significant code duplication in rendering the text content (ItemLabel and ItemDesc). The logic is repeated for cases with and without an icon. This can be refactored by extracting the text block into a shared variable, which will make the component more maintainable and easier to read.

  const hasIcon = showIcon && icon;
  const iconBounds = hasIcon && iconContent ? getElementBounds(iconContent) : { width: 0 };
  const textWidth = hasIcon ? Math.max(width - iconBounds.width - gap, 0) : width;

  const textBlock = (
    <Group>
      <ItemLabel
        indexes={indexes}
        width={textWidth}
        alignHorizontal={textAlign}
        alignVertical="center"
        fill={labelColor}
      >
        {label}
      </ItemLabel>
      <ItemDesc
        indexes={indexes}
        width={textWidth}
        y={labelBounds.height + gap}
        alignHorizontal={textAlign}
        alignVertical="top"
        fill={themeColors.colorTextSecondary}
      >
        {desc}
      </ItemDesc>
    </Group>
  );

  if (!hasIcon) {
    return <Group {...restProps}>{textBlock}</Group>;
  }

  return (
    <Group {...restProps}>
      <FlexLayout flexDirection="row" gap={gap} alignItems="flex-start">
        {isOdd ? (
          <>
            {textBlock}
            {iconContent}
          </>
        ) : (
          <>
            {iconContent}
            {textBlock}
          </>
        )}
      </FlexLayout>
    </Group>
  );

cylinderRy?: number;
baseHeight?: number;
heightIncrement?: number;
horizontalSpacing?: number;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The prop horizontalSpacing is defined in the sequenceCylinders3dProps interface but it is never used within the component. This can be misleading for developers. Please either implement the functionality for this prop or remove it if it's not needed.

Comment on lines +402 to +404
fontFamily="Arial Black, sans-serif"
fontSize={32}
fontWeight={900}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The fontFamily, fontSize, and fontWeight for the cylinder number text are hardcoded. This prevents customization through themes and can lead to inconsistencies with the overall design. It would be better to source these values from the theme object.

Comment on lines +704 to +715
const btnNodes: JSXElement[] = [
<BtnRemove
indexes={[index]}
x={itemPos.x + itemBounds.width / 2 - btnBounds.width / 2}
y={itemPos.y + itemBounds.height + 10}
/>,
<BtnAdd
indexes={[index]}
x={itemPos.x + itemBounds.width / 2 - btnBounds.width / 2}
y={itemPos.y - btnBounds.height - 10}
/>,
];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The value 10 is used as a magic number for the vertical margin when positioning the BtnRemove and BtnAdd components. This makes the code harder to understand and maintain. It's recommended to extract this value into a named constant (e.g., BTN_VERTICAL_MARGIN) to improve readability.

Suggested change
const btnNodes: JSXElement[] = [
<BtnRemove
indexes={[index]}
x={itemPos.x + itemBounds.width / 2 - btnBounds.width / 2}
y={itemPos.y + itemBounds.height + 10}
/>,
<BtnAdd
indexes={[index]}
x={itemPos.x + itemBounds.width / 2 - btnBounds.width / 2}
y={itemPos.y - btnBounds.height - 10}
/>,
];
const BTN_VERTICAL_MARGIN = 10;
const btnNodes: JSXElement[] = [
<BtnRemove
indexes={[index]}
x={itemPos.x + itemBounds.width / 2 - btnBounds.width / 2}
y={itemPos.y + itemBounds.height + BTN_VERTICAL_MARGIN}
/>,
<BtnAdd
indexes={[index]}
x={itemPos.x + itemBounds.width / 2 - btnBounds.width / 2}
y={itemPos.y - btnBounds.height - BTN_VERTICAL_MARGIN}
/>,
];

Comment thread packages/infographic/src/designs/items/AlternatingItem.tsx Outdated
Comment thread packages/infographic/src/designs/items/AlternatingItem.tsx Outdated
Comment thread packages/infographic/src/designs/items/AlternatingItem.tsx Outdated
},
],
},
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以看看 item 和 structure 和其他设计资产组合有没有好看的~

@Aarebecca Aarebecca merged commit 04fc484 into dev Nov 4, 2025
2 checks passed
@Aarebecca Aarebecca deleted the cylinders-3d branch November 4, 2025 02:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants