From 5c4d7ca909a66d18b39d98c8efe48e74a1cf7cb0 Mon Sep 17 00:00:00 2001 From: fadeltd Date: Thu, 24 Sep 2026 15:55:36 +0700 Subject: [PATCH] Fix ID generator note, dropdown styling and preset display; polish sidebar Four things, three of which were my bugs. The security note in the ID generator rendered as overlapping fragments. The paragraph had `display: flex`, which promotes every inline child to a flex item -- so "Generated with", the inline , and the remaining sentence were laid out as three siblings in a row rather than as flowing text. It is a plain block again, with the icon inline. Dropdowns had cramped padding and the native arrow sat outside the padding box, colliding with the border at a 28px control height. The native arrow cannot be styled, so it is suppressed with appearance-none and replaced by a chevron drawn as a background image, with padding reserved for it. The preset dropdown always read "Preset..." because its value was hardcoded empty -- it worked as an action menu but read as broken, which is the same thing from the user's side. It now shows whichever preset the current options match. That is derived from the options rather than stored, so it survives a reload and falls back to "Custom" the moment any field changes, with no state to keep in sync. The sidebar collapse control moves from the bottom of the tool list to the top, where it is visible without scrolling, and the width now animates with the labels fading in behind it. Both are disabled under prefers-reduced-motion. --- CHANGELOG.md | 17 +++++++- src/components/layout/Sidebar.tsx | 55 +++++++++++++++----------- src/components/ui/Select.tsx | 20 ++++++++-- src/styles/global.css | 18 +++++++++ src/tools/id-gen/IdGenTool.tsx | 23 ++++++++--- src/tools/id-gen/core/generate.test.ts | 25 ++++++++++++ src/tools/id-gen/core/generate.ts | 15 +++++++ 7 files changed, 139 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2acfc81..cc113d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,22 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] -Nothing yet. +### Fixed +- The security note in the ID generator rendered as overlapping fragments. It + was a paragraph with `display: flex`, which makes every inline child — both + text runs and the inline `` — a separate flex item laid out in a row. +- Dropdowns had cramped padding and the native arrow overlapped the border at + our control height. The native arrow is now suppressed and replaced with a + chevron drawn inside the padding box, with room reserved for it. +- The preset dropdown always displayed "Preset…" regardless of the settings in + use. It now shows whichever preset the current options match, derived from + those options rather than stored, so it survives a reload and falls back to + "Custom" as soon as any field changes. + +### Changed +- The sidebar collapse control moved from the bottom of the tool list to the + top, where it is visible without scrolling, and the collapse now animates. + Both respect `prefers-reduced-motion`. ## [0.2.2] — 2026-09-24 diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index ff2cdce..64d9c3d 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -54,7 +54,11 @@ function ToolLinks({ } > - {!collapsed && {tool.title}} + {!collapsed && ( + + {tool.title} + + )} ))} @@ -70,35 +74,40 @@ export function Sidebar() { return ( ) } diff --git a/src/components/ui/Select.tsx b/src/components/ui/Select.tsx index c8aabc2..35ae8d3 100644 --- a/src/components/ui/Select.tsx +++ b/src/components/ui/Select.tsx @@ -1,12 +1,25 @@ import type { ReactNode, SelectHTMLAttributes } from 'react' import { cn } from '@/lib/util/cn' -export function Select({ className, ...rest }: SelectHTMLAttributes) { +/** + * The native arrow sits outside the padding box and cannot be styled, so it + * collides with the border at our control height. We suppress it with + * appearance-none and draw our own chevron as a background image, leaving + * explicit room for it on the right. + */ +const CHEVRON = + "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%238b8d98' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E\")" + +export function Select({ className, style, ...rest }: SelectHTMLAttributes) { return ( { const preset = PRESETS.find((p) => p.name === e.target.value) if (preset) applyOptions((p) => ({ ...p, ...preset.options })) }} title="Load a preset" > - + {PRESETS.map((p) => (