fix(picker): Pi family component cards — full illustrations + PRO badge
The registry's Pi Zero/1/2/3/4/5 component entries rendered the live velxio-raspberry-pi-* element clipped to a sliver and carried no PRO marker. Reuse the board illustrations keyed by tagName (Zero/1/2 intentionally share the Pi 3 art) and show the shared gold PRO pill on any component whose id is a pro board kind (Pi Linux family + STM32).
This commit is contained in:
parent
1ce0bad5c8
commit
a000fba154
|
|
@ -343,17 +343,53 @@ const PASSIVE_TAGS = new Set([
|
||||||
'wokwi-inductor',
|
'wokwi-inductor',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Static illustrations for the Pi Linux family. A live velxio-raspberry-pi-*
|
||||||
|
// custom element at natural size + CSS scale keeps its unscaled layout box,
|
||||||
|
// so the 100px thumbnail clips it to a sliver — images render fully instead.
|
||||||
|
// Keyed by tagName because the registry's Pi Zero/1/2 entries deliberately
|
||||||
|
// reuse the Pi 3 board art.
|
||||||
|
const PI_BOARD_ART: Record<string, string> = {
|
||||||
|
'velxio-raspberry-pi-3': raspberryPi3Svg,
|
||||||
|
'velxio-raspberry-pi-4': raspberryPi4Png,
|
||||||
|
'velxio-raspberry-pi-5': raspberryPi5Png,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Gold PRO pill shown on cards for paid-gated boards (Pi Linux + STM32). */
|
||||||
|
const ProBadge: React.FC = () => (
|
||||||
|
<span
|
||||||
|
title="Pro feature — paid plan or Velxio Desktop"
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 8,
|
||||||
|
right: 8,
|
||||||
|
zIndex: 1,
|
||||||
|
padding: '3px 10px',
|
||||||
|
borderRadius: 999,
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: 700,
|
||||||
|
letterSpacing: 0.6,
|
||||||
|
color: '#1a1205',
|
||||||
|
background: 'linear-gradient(180deg,#ffd566,#f5a623)',
|
||||||
|
boxShadow: '0 1px 4px rgba(0,0,0,0.35)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
PRO
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
const ComponentCard: React.FC<ComponentCardProps> = ({ component, onSelect }) => {
|
const ComponentCard: React.FC<ComponentCardProps> = ({ component, onSelect }) => {
|
||||||
const thumbnailRef = React.useRef<HTMLDivElement>(null);
|
const thumbnailRef = React.useRef<HTMLDivElement>(null);
|
||||||
const usePresetSvg =
|
const usePresetSvg =
|
||||||
PASSIVE_TAGS.has(component.tagName) &&
|
PASSIVE_TAGS.has(component.tagName) &&
|
||||||
typeof component.thumbnail === 'string' &&
|
typeof component.thumbnail === 'string' &&
|
||||||
component.thumbnail.trim().startsWith('<svg');
|
component.thumbnail.trim().startsWith('<svg');
|
||||||
|
const boardArt = PI_BOARD_ART[component.tagName];
|
||||||
|
|
||||||
// Render actual web component as thumbnail
|
// Render actual web component as thumbnail
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!thumbnailRef.current) return;
|
if (!thumbnailRef.current) return;
|
||||||
if (usePresetSvg) return; // SVG is rendered via dangerouslySetInnerHTML below
|
if (usePresetSvg) return; // SVG is rendered via dangerouslySetInnerHTML below
|
||||||
|
if (boardArt) return; // static illustration rendered below
|
||||||
|
|
||||||
// Create the actual wokwi element
|
// Create the actual wokwi element
|
||||||
const element = document.createElement(component.tagName);
|
const element = document.createElement(component.tagName);
|
||||||
|
|
@ -397,12 +433,19 @@ const ComponentCard: React.FC<ComponentCardProps> = ({ component, onSelect }) =>
|
||||||
thumbnailRef.current.innerHTML = '';
|
thumbnailRef.current.innerHTML = '';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [component.tagName, component.defaultValues, usePresetSvg]);
|
}, [component.tagName, component.defaultValues, usePresetSvg, boardArt]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className="component-card" onClick={onSelect}>
|
<button className="component-card" onClick={onSelect} style={{ position: 'relative' }}>
|
||||||
|
{isProBoardKind(component.id) && <ProBadge />}
|
||||||
<div className="card-thumbnail">
|
<div className="card-thumbnail">
|
||||||
{usePresetSvg ? (
|
{boardArt ? (
|
||||||
|
<img
|
||||||
|
src={boardArt}
|
||||||
|
alt={component.name}
|
||||||
|
style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }}
|
||||||
|
/>
|
||||||
|
) : usePresetSvg ? (
|
||||||
<div
|
<div
|
||||||
className="component-preview"
|
className="component-preview"
|
||||||
dangerouslySetInnerHTML={{ __html: component.thumbnail }}
|
dangerouslySetInnerHTML={{ __html: component.thumbnail }}
|
||||||
|
|
@ -517,27 +560,7 @@ const BoardCard: React.FC<BoardCardProps> = ({ kind, onSelect }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className="component-card" onClick={onSelect} style={{ position: 'relative' }}>
|
<button className="component-card" onClick={onSelect} style={{ position: 'relative' }}>
|
||||||
{isProBoardKind(kind) && (
|
{isProBoardKind(kind) && <ProBadge />}
|
||||||
<span
|
|
||||||
title="Pro feature — paid plan or Velxio Desktop"
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: 8,
|
|
||||||
right: 8,
|
|
||||||
zIndex: 1,
|
|
||||||
padding: '3px 10px',
|
|
||||||
borderRadius: 999,
|
|
||||||
fontSize: 11,
|
|
||||||
fontWeight: 700,
|
|
||||||
letterSpacing: 0.6,
|
|
||||||
color: '#1a1205',
|
|
||||||
background: 'linear-gradient(180deg,#ffd566,#f5a623)',
|
|
||||||
boxShadow: '0 1px 4px rgba(0,0,0,0.35)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
PRO
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
<div className="card-thumbnail">
|
<div className="card-thumbnail">
|
||||||
{reactThumbnail ? reactThumbnail : <div ref={thumbnailRef} className="component-preview" />}
|
{reactThumbnail ? reactThumbnail : <div ref={thumbnailRef} className="component-preview" />}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue