fix: tour init on All tab + 11" Latex card; fix modal title truncation

- Tour now switches to the All tab and clears search on start, ensuring
  the 11" Latex product is always visible and the exit overlay works
- data-tour="first-card" now targets the 11" Latex item by name instead
  of whichever card happens to be first in the filtered list
- Modal header title now truncates with ellipsis so the X close button
  is never pushed off screen by a long product name

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chris 2026-04-15 14:39:45 -04:00
parent 6fea1f2be1
commit c6d5a0265f
3 changed files with 21 additions and 8 deletions

View File

@ -151,9 +151,9 @@ export default function ColorPicker({ product, maxColors, onClose, editingEntry
<div className="modal is-active" onClick={onClose}> <div className="modal is-active" onClick={onClose}>
<div className="modal-card" style={{ maxWidth: '780px', width: '95vw' }} onClick={(e) => e.stopPropagation()}> <div className="modal-card" style={{ maxWidth: '780px', width: '95vw' }} onClick={(e) => e.stopPropagation()}>
<header className="modal-card-head" style={{ background: '#11b3be' }}> <header className="modal-card-head" style={{ background: '#11b3be', gap: '0.75rem' }}>
<p className="modal-card-title has-text-white">{product.name}</p> <p className="modal-card-title has-text-white" style={{ flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{product.name}</p>
<button className="delete" aria-label="close" onClick={onClose} /> <button className="delete" aria-label="close" onClick={onClose} style={{ flexShrink: 0 }} />
</header> </header>
<section className="modal-card-body" style={{ maxHeight: '70vh', overflowY: 'auto', padding: '1.25rem 1.5rem' }}> <section className="modal-card-body" style={{ maxHeight: '70vh', overflowY: 'auto', padding: '1.25rem 1.5rem' }}>

View File

@ -48,6 +48,12 @@ export default function FeaturedProducts() {
setShowTour(true) setShowTour(true)
} }
const tourInit = () => {
setCategory('all')
setSearch('')
setSearchOpen(false)
}
const endTour = () => { const endTour = () => {
setShowTour(false) setShowTour(false)
// Close any customization modal that may have been opened during the tour // Close any customization modal that may have been opened during the tour
@ -224,7 +230,7 @@ export default function FeaturedProducts() {
{/* Welcome modal + guided tour */} {/* Welcome modal + guided tour */}
{showWelcome && <WelcomeModal onTour={startTour} onDismiss={dismissWelcome} />} {showWelcome && <WelcomeModal onTour={startTour} onDismiss={dismissWelcome} />}
{showTour && <GuidedTour onDone={endTour} />} {showTour && <GuidedTour onDone={endTour} onStart={tourInit} />}
{/* Product grid */} {/* Product grid */}
{loading ? ( {loading ? (
@ -244,11 +250,11 @@ export default function FeaturedProducts() {
</p> </p>
) : ( ) : (
<div className="columns is-multiline is-centered"> <div className="columns is-multiline is-centered">
{filtered.map((item, index) => ( {filtered.map((item) => (
<div <div
key={item.id} key={item.id}
className="column is-3-desktop is-6-tablet is-12-mobile" className="column is-3-desktop is-6-tablet is-12-mobile"
{...(index === 0 ? { 'data-tour': 'first-card' } : {})} {...(/\b11["''″]|\b11[- ]?inch/i.test(item.name) && /latex/i.test(item.name) ? { 'data-tour': 'first-card' } : {})}
> >
<ProductCard item={item} /> <ProductCard item={item} />
</div> </div>

View File

@ -57,10 +57,11 @@ const PAD = 10 // px padding around spotlight
const TIP_WIDTH = 300 // tooltip width in px const TIP_WIDTH = 300 // tooltip width in px
interface Props { interface Props {
onDone: () => void onDone: () => void
onStart?: () => void
} }
export default function GuidedTour({ onDone }: Props) { export default function GuidedTour({ onDone, onStart }: Props) {
const [step, setStep] = useState(0) const [step, setStep] = useState(0)
const [targetRect, setTargetRect] = useState<DOMRect | null>(null) const [targetRect, setTargetRect] = useState<DOMRect | null>(null)
@ -72,6 +73,12 @@ export default function GuidedTour({ onDone }: Props) {
if (el) setTargetRect(el.getBoundingClientRect()) if (el) setTargetRect(el.getBoundingClientRect())
}, [current.target]) }, [current.target])
// Switch to All tab and pick the 11" Latex card as the tour example on mount
useEffect(() => {
onStart?.()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
// On step change: fire onEnter, poll until target appears, then scroll + measure. // On step change: fire onEnter, poll until target appears, then scroll + measure.
useEffect(() => { useEffect(() => {
setTargetRect(null) // clear stale rect immediately setTargetRect(null) // clear stale rect immediately