feat: add visual grab tab to resize handle with rounded corners
Added a 28px × 64px grab tab that extends to the right of the resize handle divider, providing a larger visual target when the sidebar is collapsed or near-collapsed. **Changes:** - Thin 8px divider remains the draggable area - Visual grab tab (28px × 64px) extends to right with: - Rounded corners on top-right and bottom-right (borderRadius) - Vertical knurled texture for grip appearance - Drop shadow for depth - Positioned absolutely, centered vertically - Tab is visual decoration only (pointerEvents: none) - Divider remains fully draggable **Note:** Tab is not draggable itself (library limitation - child elements outside parent bounds don't trigger drag). The 8px divider is the interactive area. Tab provides visual affordance when sidebar is collapsed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
0770bf3e1a
commit
6e55d5add7
|
|
@ -0,0 +1,31 @@
|
|||
# Resize Handle Tab Requirements
|
||||
|
||||
**CRITICAL: DO NOT MAKE THE ENTIRE HANDLE WIDE**
|
||||
|
||||
## What the user wants:
|
||||
- A **thin 8px divider** for the resize handle (full height)
|
||||
- A **small grab tab** (28px × 64px) that:
|
||||
- Is centered vertically on the divider
|
||||
- Extends to the RIGHT into the preview pane
|
||||
- Has rounded corners on the top-right and bottom-right
|
||||
- Has vertical knurled texture (ridges)
|
||||
- Is DRAGGABLE
|
||||
|
||||
## What NOT to do:
|
||||
❌ Make the entire PanelResizeHandle 36px wide
|
||||
❌ Use clip-path to make a wide handle look thin
|
||||
❌ Use pseudo-elements (_after) that extend outside the parent bounds (they don't participate in drag events)
|
||||
|
||||
## The problem:
|
||||
- PanelResizeHandle only responds to drag events on itself
|
||||
- Child elements positioned absolutely outside the parent's bounds don't trigger parent drag
|
||||
- Pseudo-elements extending outside don't work either
|
||||
|
||||
## Possible solutions to try:
|
||||
1. Check if PanelResizeHandle accepts hitAreaMargins prop (from library source)
|
||||
2. Use a custom drag overlay that forwards events to the handle
|
||||
3. Accept that the tab is visual-only and keep the 8px handle draggable
|
||||
|
||||
## User frustration level: HIGH
|
||||
- This is the **THIRD TIME** making the handle wide when asked for a small tab
|
||||
- User explicitly said "FUUUUUCK, no wide drag handles!"
|
||||
|
|
@ -1,68 +1,14 @@
|
|||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(npm run pre-commit:*)",
|
||||
"Bash(git add:*)",
|
||||
"Bash(git commit -m \"$(cat <<''EOF''\nfeat: add themed backgrounds and enhanced styling to 404 page\n\nTransform 404 page into a vibrant, playful experience with:\n\nThemed Backgrounds:\n- Each HTTP status code has custom gradient background\n- Animated radial glow effects that pulse with theme colors\n- Smooth transitions between themes (0.6s ease-in-out)\n- 14 unique color schemes matching easter egg personality\n\nEnhanced Typography:\n- Responsive font sizes (1.75rem mobile → 4rem desktop)\n- Black font weight for maximum impact\n- Dynamic text colors matching each theme\n- Glowing text shadows for easter egg modes\n- Tight letter spacing (-0.02em) for modern look\n\nNavigation Buttons:\n- Added emoji icons (🏠 🎮 ✨)\n- Lift-and-scale hover animation\n- Colored shadows matching button colors\n- Responsive sizing for mobile\n- Smooth cubic-bezier transitions\n\nResponsive Layout:\n- Increased spacing between abacus and text (2-4rem)\n- Mobile-optimized gaps and padding\n- Text pushed down to prevent overlap with large abacus\n- Smaller screens get appropriate scaling\n\nDynamic Hints:\n- Changes based on active easter egg\n- \"Try other codes...\" vs \"Click beads to discover more...\"\n- Themed text color and opacity\n- Italic, medium weight for subtle emphasis\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\nEOF\n)\")",
|
||||
"Bash(git push)",
|
||||
"Bash(git commit:*)",
|
||||
"Bash(git stash show:*)",
|
||||
"Bash(npm run type-check:*)",
|
||||
"Bash(git stash:*)",
|
||||
"Bash(git pull:*)",
|
||||
"Bash(git checkout:*)",
|
||||
"Bash(pnpm remove:*)",
|
||||
"Bash(git rm:*)",
|
||||
"WebSearch",
|
||||
"WebFetch(domain:platform.openai.com)",
|
||||
"Bash(git rev-parse:*)",
|
||||
"Bash(npx drizzle-kit:*)",
|
||||
"Bash(npm run db:migrate:*)",
|
||||
"Bash(ssh:*)",
|
||||
"Bash(git log:*)",
|
||||
"Bash(gh run list:*)",
|
||||
"Bash(gh api:*)",
|
||||
"Bash(curl:*)",
|
||||
"Bash(gh run view:*)",
|
||||
"Bash(npm install:*)",
|
||||
"Bash(pnpm add:*)",
|
||||
"WebFetch(domain:www.dynamsoft.com)",
|
||||
"Bash(npm run format:*)",
|
||||
"Bash(npm run lint:fix:*)",
|
||||
"Bash(npm run lint)",
|
||||
"Bash(find:*)",
|
||||
"Bash(for i in {0..10})",
|
||||
"Bash(do echo \"=== Checking stash@{$i} ===\")",
|
||||
"Bash(done)",
|
||||
"mcp__sqlite__list_tables",
|
||||
"mcp__sqlite__describe_table",
|
||||
"Bash(npm test:*)",
|
||||
"mcp__sqlite__read_query",
|
||||
"Bash(cat:*)",
|
||||
"Bash(npm run lint:*)",
|
||||
"Bash(git reset:*)",
|
||||
"Bash(npx tsx:*)",
|
||||
"Bash(npx tsc:*)",
|
||||
"Bash(npx @pandacss/dev)",
|
||||
"Bash(npm view:*)",
|
||||
"Bash(xargs sed:*)",
|
||||
"Bash(wc:*)",
|
||||
"Bash(git push:*)",
|
||||
"Bash(git cherry-pick:*)",
|
||||
"Bash(pnpm install)",
|
||||
"Bash(npx @biomejs/biome check:*)",
|
||||
"Bash(node -e:*)",
|
||||
"Bash(sqlite3:*)",
|
||||
"Bash(npm run format:check:*)",
|
||||
"Bash(npx biome:*)",
|
||||
"Bash(git restore:*)",
|
||||
"Bash(mcp__sqlite__describe_table:*)",
|
||||
"Bash(~45 unique available. Consider: • Reduce to 1 pages • Increase digit range)",
|
||||
"Bash(• Lower regrouping %\"\n\n**Next:** Problem space indicator in config panel showing live estimate\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\nEOF\n)\")"
|
||||
"WebFetch(domain:github.com)",
|
||||
"WebFetch(domain:react-resizable-panels.vercel.app)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
},
|
||||
"enableAllProjectMcpServers": true,
|
||||
"enabledMcpjsonServers": ["sqlite"]
|
||||
"enabledMcpjsonServers": [
|
||||
"sqlite"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,19 +77,22 @@ export function AdditionWorksheetClient({
|
|||
})
|
||||
}
|
||||
|
||||
// Resize handle styles
|
||||
// Resize handle - thin 8px divider
|
||||
const resizeHandleStyles = css({
|
||||
width: '8px',
|
||||
bg: isDark ? 'gray.700' : 'gray.200',
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
cursor: 'col-resize',
|
||||
transition: 'background 0.2s',
|
||||
zIndex: 10,
|
||||
background: isDark ? 'gray.700' : 'gray.200',
|
||||
_hover: {
|
||||
bg: isDark ? 'brand.600' : 'brand.400',
|
||||
background: isDark ? 'brand.600' : 'brand.400',
|
||||
},
|
||||
_active: {
|
||||
bg: 'brand.500',
|
||||
background: 'brand.500',
|
||||
},
|
||||
// Vertical grip dots
|
||||
_before: {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
|
|
@ -98,14 +101,45 @@ export function AdditionWorksheetClient({
|
|||
transform: 'translate(-50%, -50%)',
|
||||
width: '3px',
|
||||
height: '20px',
|
||||
bg: isDark ? 'gray.500' : 'gray.400',
|
||||
bg: isDark ? 'gray.400' : 'gray.500',
|
||||
borderRadius: 'full',
|
||||
boxShadow: isDark
|
||||
? '0 -8px 0 0 rgb(107, 114, 128), 0 8px 0 0 rgb(107, 114, 128)'
|
||||
: '0 -8px 0 0 rgb(156, 163, 175), 0 8px 0 0 rgb(156, 163, 175)',
|
||||
? '0 -8px 0 0 rgb(156, 163, 175), 0 8px 0 0 rgb(156, 163, 175)'
|
||||
: '0 -8px 0 0 rgb(107, 114, 128), 0 8px 0 0 rgb(107, 114, 128)',
|
||||
pointerEvents: 'none',
|
||||
zIndex: 2,
|
||||
},
|
||||
})
|
||||
|
||||
// Visual grab tab with rounded corners (non-interactive decoration)
|
||||
const grabTabStyles = css({
|
||||
position: 'absolute',
|
||||
top: 'calc(50% - 32px)',
|
||||
left: '8px',
|
||||
width: '28px',
|
||||
height: '64px',
|
||||
background: isDark ? 'rgb(75, 85, 99)' : 'rgb(209, 213, 219)',
|
||||
borderRadius: '0 8px 8px 0',
|
||||
boxShadow: isDark ? '2px 2px 8px rgba(0, 0, 0, 0.3)' : '2px 2px 8px rgba(0, 0, 0, 0.15)',
|
||||
pointerEvents: 'none',
|
||||
// Knurled texture
|
||||
backgroundImage: isDark
|
||||
? `repeating-linear-gradient(
|
||||
90deg,
|
||||
rgba(255, 255, 255, 0.1) 0px,
|
||||
rgba(255, 255, 255, 0.1) 1px,
|
||||
transparent 1px,
|
||||
transparent 3px
|
||||
)`
|
||||
: `repeating-linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 0, 0, 0.08) 0px,
|
||||
rgba(0, 0, 0, 0.08) 1px,
|
||||
transparent 1px,
|
||||
transparent 3px
|
||||
)`,
|
||||
})
|
||||
|
||||
return (
|
||||
<PageWithNav navTitle={t('navTitle')} navEmoji="📝">
|
||||
<WorksheetConfigProvider formState={formState} updateFormState={updateFormState}>
|
||||
|
|
@ -131,7 +165,9 @@ export function AdditionWorksheetClient({
|
|||
<ConfigSidebar isSaving={isSaving} lastSaved={lastSaved} />
|
||||
</Panel>
|
||||
|
||||
<PanelResizeHandle className={resizeHandleStyles} />
|
||||
<PanelResizeHandle className={resizeHandleStyles}>
|
||||
<div className={grabTabStyles} data-element="grab-tab" />
|
||||
</PanelResizeHandle>
|
||||
|
||||
{/* Center Panel: Preview */}
|
||||
<Panel defaultSize={75} minSize={60}>
|
||||
|
|
|
|||
Loading…
Reference in New Issue