feat(phase7.1): add HelpTooltip system with contextual help icons

- New HelpTooltip component: hover-triggered floating panel, themed via
  CSS variables, supports top/right/bottom/left positioning, no deps
- New helpTexts.ts registry: 14 entries covering render settings,
  admin actions, template fields, and wizard fields
- Admin.tsx: tooltips on Cycles/EEVEE samples, smooth angle, regenerate
  thumbnails, process unprocessed
- RenderTemplateTable.tsx: tooltips on material replace, lighting only,
  shadow catcher column headers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 20:16:42 +01:00
parent 206672a858
commit 10d05bd2e7
4 changed files with 234 additions and 24 deletions
+37 -21
View File
@@ -5,6 +5,7 @@ import { UserPlus, Trash2, Pencil, ChevronDown, ChevronUp, ChevronRight, Setting
import { Link } from 'react-router-dom'
import api from '../api/client'
import ConfirmModal from '../components/ConfirmModal'
import HelpTooltip from '../components/HelpTooltip'
import TemplateEditor from '../components/admin/TemplateEditor'
import PricingTierTable from '../components/admin/PricingTierTable'
import OutputTypeTable from '../components/admin/OutputTypeTable'
@@ -388,7 +389,10 @@ export default function AdminPage() {
{/* Sample counts */}
<div className="grid grid-cols-2 gap-4 max-w-sm">
<div>
<label className="block text-xs font-medium text-content-secondary mb-1">Cycles samples</label>
<label className="flex items-center gap-1 text-xs font-medium text-content-secondary mb-1">
Cycles samples
<HelpTooltip helpKey="setting.blender_cycles_samples" position="top" size={12} />
</label>
<input
type="number"
min={1} max={4096} step={32}
@@ -400,7 +404,10 @@ export default function AdminPage() {
<p className="text-xs text-content-muted mt-0.5">Higher = better quality, slower</p>
</div>
<div>
<label className="block text-xs font-medium text-content-secondary mb-1">EEVEE samples</label>
<label className="flex items-center gap-1 text-xs font-medium text-content-secondary mb-1">
EEVEE samples
<HelpTooltip helpKey="setting.blender_eevee_samples" position="top" size={12} />
</label>
<input
type="number"
min={1} max={1024} step={16}
@@ -415,7 +422,10 @@ export default function AdminPage() {
{/* Smooth by angle */}
<div className="flex items-center gap-4 flex-wrap">
<span className="text-sm font-medium text-content-secondary w-28 shrink-0">Smooth angle</span>
<span className="flex items-center gap-1 text-sm font-medium text-content-secondary w-28 shrink-0">
Smooth angle
<HelpTooltip helpKey="setting.blender_smooth_angle" size={12} />
</span>
<input
type="number"
min={0} max={180} step={5}
@@ -674,27 +684,33 @@ export default function AdminPage() {
<p className="text-xs text-content-muted">Resets files stuck in 'processing' to 'failed'. Runs automatically every 5 min.</p>
</div>
<div className="flex flex-col gap-1">
<button
onClick={() => processUnprocessedMut.mutate()}
disabled={processUnprocessedMut.isPending}
className="btn-secondary text-sm w-full justify-start"
title="Queue all pending and failed STEP files that have never been successfully processed"
>
<RefreshCw size={14} className={processUnprocessedMut.isPending ? 'animate-spin' : ''} />
{processUnprocessedMut.isPending ? 'Queueing…' : 'Process Unprocessed'}
</button>
<div className="flex items-center gap-1.5">
<button
onClick={() => processUnprocessedMut.mutate()}
disabled={processUnprocessedMut.isPending}
className="btn-secondary text-sm flex-1 justify-start"
title="Queue all pending and failed STEP files that have never been successfully processed"
>
<RefreshCw size={14} className={processUnprocessedMut.isPending ? 'animate-spin' : ''} />
{processUnprocessedMut.isPending ? 'Queueing…' : 'Process Unprocessed'}
</button>
<HelpTooltip helpKey="action.process_unprocessed" position="left" />
</div>
<p className="text-xs text-content-muted">Queues all pending/failed STEP files for initial processing.</p>
</div>
<div className="flex flex-col gap-1">
<button
onClick={() => regenerateMut.mutate()}
disabled={regenerateMut.isPending}
className="btn-secondary text-sm w-full justify-start"
title="Re-render thumbnails for all completed CAD files using the current Blender settings"
>
<RefreshCw size={14} className={regenerateMut.isPending ? 'animate-spin' : ''} />
{regenerateMut.isPending ? 'Re-queuing…' : 'Regenerate All Thumbnails'}
</button>
<div className="flex items-center gap-1.5">
<button
onClick={() => regenerateMut.mutate()}
disabled={regenerateMut.isPending}
className="btn-secondary text-sm flex-1 justify-start"
title="Re-render thumbnails for all completed CAD files using the current Blender settings"
>
<RefreshCw size={14} className={regenerateMut.isPending ? 'animate-spin' : ''} />
{regenerateMut.isPending ? 'Re-queuing…' : 'Regenerate All Thumbnails'}
</button>
<HelpTooltip helpKey="action.regenerate_thumbnails" position="left" />
</div>
<p className="text-xs text-content-muted">Re-renders thumbnails for all completed CAD files.</p>
</div>
<div className="flex flex-col gap-1">