fix: resolve z-index layering and hero abacus visibility issues
Fix two critical issues with the trophy abacus system: 1. Hero abacus appearing on all pages: - Root cause: HomeHeroProvider now wraps all pages globally - Solution: Use pathname check to detect actual home page routes - Only show hero mode on: /, /en, /de, /ja, /hi, /es, /la 2. Z-index conflicts causing layering issues: - AppNavBar had hardcoded z-index: 1000 (DROPDOWN layer) - Should use Z_INDEX.NAV_BAR (100) for proper layering - Tooltip had z-index: 50, should use Z_INDEX.TOOLTIP (1000) This ensures: - Hero abacus only appears on home page, not all pages - Trophy abacus (z-index 30001) appears above ALL content - Nav bar and tooltips use correct z-index constants - No stacking context conflicts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -160,7 +160,8 @@
|
||||
"Bash(security find-generic-password -s 'Anthropic API Key' -w)",
|
||||
"Bash(printenv:*)",
|
||||
"Bash(typst:*)",
|
||||
"Bash(npx tsx:*)"
|
||||
"Bash(npx tsx:*)",
|
||||
"Bash(sort:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
||||
35
apps/web/scripts/generateCalendarAbacus.tsx
Normal file
35
apps/web/scripts/generateCalendarAbacus.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env tsx
|
||||
|
||||
/**
|
||||
* Generate a simple abacus SVG (no customization for now - just get it working)
|
||||
* Usage: npx tsx scripts/generateCalendarAbacus.tsx <value> <columns>
|
||||
* Example: npx tsx scripts/generateCalendarAbacus.tsx 15 2
|
||||
*
|
||||
* Pattern copied directly from working generateDayIcon.tsx
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import { AbacusReact } from '@soroban/abacus-react'
|
||||
|
||||
const value = parseInt(process.argv[2], 10)
|
||||
const columns = parseInt(process.argv[3], 10)
|
||||
|
||||
if (isNaN(value) || isNaN(columns)) {
|
||||
console.error('Usage: npx tsx scripts/generateCalendarAbacus.tsx <value> <columns>')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Use exact same pattern as generateDayIcon - inline customStyles
|
||||
const abacusMarkup = renderToStaticMarkup(
|
||||
<AbacusReact
|
||||
value={value}
|
||||
columns={columns}
|
||||
scaleFactor={1}
|
||||
animated={false}
|
||||
interactive={false}
|
||||
showNumbers={false}
|
||||
/>,
|
||||
)
|
||||
|
||||
process.stdout.write(abacusMarkup)
|
||||
@@ -1,83 +0,0 @@
|
||||
#!/usr/bin/env tsx
|
||||
|
||||
/**
|
||||
* Generate all abacus SVGs needed for a calendar
|
||||
* Usage: npx tsx scripts/generateCalendarSVGs.tsx <maxDay> <year> <customStylesJson>
|
||||
* Example: npx tsx scripts/generateCalendarSVGs.tsx 31 2025 '{}'
|
||||
*
|
||||
* This script runs as a subprocess to avoid Next.js restrictions on react-dom/server in API routes.
|
||||
* Pattern copied from generateAbacusIcons.tsx which works correctly.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import type { AbacusReact as AbacusReactType } from '@soroban/abacus-react'
|
||||
|
||||
// Use dynamic import to ensure correct module resolution
|
||||
const AbacusReactModule = require('@soroban/abacus-react')
|
||||
const AbacusReact = AbacusReactModule.AbacusReact || AbacusReactModule.default
|
||||
|
||||
// Get arguments
|
||||
const maxDay = parseInt(process.argv[2], 10)
|
||||
const year = parseInt(process.argv[3], 10)
|
||||
const customStylesJson = process.argv[4] || '{}'
|
||||
|
||||
if (!maxDay || maxDay < 1 || maxDay > 31) {
|
||||
console.error('Invalid maxDay argument')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (!year || year < 1 || year > 9999) {
|
||||
console.error('Invalid year argument')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
let customStyles: any
|
||||
try {
|
||||
customStyles = JSON.parse(customStylesJson)
|
||||
} catch (error) {
|
||||
console.error('Invalid JSON for customStyles')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
interface CalendarSVGs {
|
||||
days: Record<string, string>
|
||||
year: string
|
||||
}
|
||||
|
||||
const result: CalendarSVGs = {
|
||||
days: {},
|
||||
year: '',
|
||||
}
|
||||
|
||||
// Generate day SVGs
|
||||
for (let day = 1; day <= maxDay; day++) {
|
||||
const svg = renderToStaticMarkup(
|
||||
<AbacusReact
|
||||
value={day}
|
||||
columns={2}
|
||||
customStyles={customStyles}
|
||||
scaleFactor={1}
|
||||
animated={false}
|
||||
interactive={false}
|
||||
/>
|
||||
)
|
||||
result.days[`day-${day}`] = svg
|
||||
}
|
||||
|
||||
// Generate year SVG
|
||||
const yearColumns = Math.max(1, Math.ceil(Math.log10(year + 1)))
|
||||
const yearSvg = renderToStaticMarkup(
|
||||
<AbacusReact
|
||||
value={year}
|
||||
columns={yearColumns}
|
||||
customStyles={customStyles}
|
||||
scaleFactor={1}
|
||||
animated={false}
|
||||
interactive={false}
|
||||
/>
|
||||
)
|
||||
result.year = yearSvg
|
||||
|
||||
// Output as JSON to stdout
|
||||
process.stdout.write(JSON.stringify(result))
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/usr/bin/env tsx
|
||||
|
||||
/**
|
||||
* Generate a single abacus SVG
|
||||
* Usage: npx tsx scripts/generateSingleAbacusSVG.tsx <value> <columns> <customStylesJson>
|
||||
* Example: npx tsx scripts/generateSingleAbacusSVG.tsx 15 2 '{}'
|
||||
*
|
||||
* Pattern copied from generateDayIcon.tsx
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import { AbacusReact } from '@soroban/abacus-react'
|
||||
|
||||
// Get arguments
|
||||
const value = parseInt(process.argv[2], 10)
|
||||
const columns = parseInt(process.argv[3], 10)
|
||||
const customStylesJson = process.argv[4] || '{}'
|
||||
|
||||
if (isNaN(value) || value < 0) {
|
||||
console.error('Invalid value argument')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (isNaN(columns) || columns < 1) {
|
||||
console.error('Invalid columns argument')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
let customStyles: any
|
||||
try {
|
||||
customStyles = JSON.parse(customStylesJson)
|
||||
} catch (error) {
|
||||
console.error('Invalid JSON for customStyles')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Render abacus
|
||||
const abacusMarkup = renderToStaticMarkup(
|
||||
<AbacusReact
|
||||
value={value}
|
||||
columns={columns}
|
||||
customStyles={customStyles}
|
||||
scaleFactor={1}
|
||||
animated={false}
|
||||
interactive={false}
|
||||
/>
|
||||
)
|
||||
|
||||
// Output SVG to stdout
|
||||
process.stdout.write(abacusMarkup)
|
||||
@@ -616,7 +616,7 @@ export function AppNavBar({ variant = 'full', navSlot }: AppNavBarProps) {
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
zIndex: 1000,
|
||||
zIndex: Z_INDEX.NAV_BAR,
|
||||
transition: 'all 0.3s ease',
|
||||
})}
|
||||
>
|
||||
@@ -675,7 +675,7 @@ export function AppNavBar({ variant = 'full', navSlot }: AppNavBarProps) {
|
||||
fontSize: 'sm',
|
||||
maxW: '250px',
|
||||
shadow: 'lg',
|
||||
zIndex: 50,
|
||||
zIndex: Z_INDEX.TOOLTIP,
|
||||
})}
|
||||
>
|
||||
{subtitle.description}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { useContext, useEffect, useState } from 'react'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { AbacusReact, useAbacusConfig } from '@soroban/abacus-react'
|
||||
import { css } from '../../styled-system/css'
|
||||
import { useMyAbacus } from '@/contexts/MyAbacusContext'
|
||||
@@ -10,6 +11,7 @@ import { Z_INDEX } from '@/constants/zIndex'
|
||||
export function MyAbacus() {
|
||||
const { isOpen, close, toggle } = useMyAbacus()
|
||||
const appConfig = useAbacusConfig()
|
||||
const pathname = usePathname()
|
||||
|
||||
// Sync with hero context if on home page
|
||||
const homeHeroContext = useContext(HomeHeroContext)
|
||||
@@ -17,8 +19,15 @@ export function MyAbacus() {
|
||||
const abacusValue = homeHeroContext?.abacusValue ?? localAbacusValue
|
||||
const setAbacusValue = homeHeroContext?.setAbacusValue ?? setLocalAbacusValue
|
||||
|
||||
// Determine display mode
|
||||
const isOnHomePage = Boolean(homeHeroContext)
|
||||
// Determine display mode - only hero mode on actual home page
|
||||
const isOnHomePage =
|
||||
pathname === '/' ||
|
||||
pathname === '/en' ||
|
||||
pathname === '/de' ||
|
||||
pathname === '/ja' ||
|
||||
pathname === '/hi' ||
|
||||
pathname === '/es' ||
|
||||
pathname === '/la'
|
||||
const isHeroVisible = homeHeroContext?.isHeroVisible ?? false
|
||||
const isHeroMode = isOnHomePage && isHeroVisible && !isOpen
|
||||
|
||||
|
||||
Reference in New Issue
Block a user