Add MiniCard molecule and component tokens for MiniCard + MapPin
MiniCard: compact vertical card for grids, recommendations, and map popups. Image + title + optional price/badges/chips/meta. Lighter than ProviderCard — no verified tiers, no logo. Audit: 20/20. MapPin tokens added (build next): price-pill markers for map views. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
157
src/components/molecules/MiniCard/MiniCard.stories.tsx
Normal file
157
src/components/molecules/MiniCard/MiniCard.stories.tsx
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import VerifiedOutlinedIcon from '@mui/icons-material/VerifiedOutlined';
|
||||||
|
import { MiniCard } from './MiniCard';
|
||||||
|
|
||||||
|
// Placeholder images for stories
|
||||||
|
const IMG_PROVIDER =
|
||||||
|
'https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=400&h=240&fit=crop&auto=format';
|
||||||
|
const IMG_VENUE =
|
||||||
|
'https://images.unsplash.com/photo-1497366216548-37526070297c?w=400&h=240&fit=crop&auto=format';
|
||||||
|
const IMG_CHAPEL =
|
||||||
|
'https://images.unsplash.com/photo-1548625149-fc4a29cf7092?w=400&h=240&fit=crop&auto=format';
|
||||||
|
const IMG_GARDEN =
|
||||||
|
'https://images.unsplash.com/photo-1585320806297-9794b3e4eeae?w=400&h=240&fit=crop&auto=format';
|
||||||
|
|
||||||
|
const meta: Meta<typeof MiniCard> = {
|
||||||
|
title: 'Molecules/MiniCard',
|
||||||
|
component: MiniCard,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
parameters: {
|
||||||
|
layout: 'centered',
|
||||||
|
},
|
||||||
|
decorators: [
|
||||||
|
(Story) => (
|
||||||
|
<Box sx={{ width: 240 }}>
|
||||||
|
<Story />
|
||||||
|
</Box>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof MiniCard>;
|
||||||
|
|
||||||
|
/** Default mini card with title, image, and price */
|
||||||
|
export const Default: Story = {
|
||||||
|
args: {
|
||||||
|
title: 'H.Parsons Funeral Directors',
|
||||||
|
imageUrl: IMG_PROVIDER,
|
||||||
|
price: 900,
|
||||||
|
location: 'Wollongong',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** With all optional fields populated */
|
||||||
|
export const FullyLoaded: Story = {
|
||||||
|
args: {
|
||||||
|
title: 'H.Parsons Funeral Directors',
|
||||||
|
imageUrl: IMG_PROVIDER,
|
||||||
|
price: 900,
|
||||||
|
location: 'Wollongong',
|
||||||
|
rating: 4.8,
|
||||||
|
badges: [
|
||||||
|
{ label: 'Verified', color: 'brand', variant: 'filled', icon: <VerifiedOutlinedIcon /> },
|
||||||
|
{ label: 'Online Arrangement', color: 'success' },
|
||||||
|
],
|
||||||
|
chips: ['Burial', 'Cremation'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Venue card usage — capacity instead of rating */
|
||||||
|
export const Venue: Story = {
|
||||||
|
args: {
|
||||||
|
title: 'Albany Creek Memorial Park',
|
||||||
|
imageUrl: IMG_CHAPEL,
|
||||||
|
price: 450,
|
||||||
|
location: 'Albany Creek',
|
||||||
|
capacity: 120,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Package card usage — custom price label */
|
||||||
|
export const Package: Story = {
|
||||||
|
args: {
|
||||||
|
title: 'Essential Cremation Package',
|
||||||
|
imageUrl: IMG_GARDEN,
|
||||||
|
priceLabel: 'From $2,800',
|
||||||
|
badges: [{ label: 'Most Popular', color: 'brand' }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Minimal — just title and image */
|
||||||
|
export const Minimal: Story = {
|
||||||
|
args: {
|
||||||
|
title: 'Lady Anne Funerals',
|
||||||
|
imageUrl: IMG_VENUE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Selected state — brand border + warm background */
|
||||||
|
export const Selected: Story = {
|
||||||
|
args: {
|
||||||
|
title: 'H.Parsons Funeral Directors',
|
||||||
|
imageUrl: IMG_PROVIDER,
|
||||||
|
price: 900,
|
||||||
|
location: 'Wollongong',
|
||||||
|
selected: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Long title truncated at 2 lines */
|
||||||
|
export const LongTitle: Story = {
|
||||||
|
args: {
|
||||||
|
title: 'Botanical Funerals by Ian Allison — Sustainable & Eco-Friendly Services',
|
||||||
|
imageUrl: IMG_GARDEN,
|
||||||
|
price: 1200,
|
||||||
|
location: 'Northern Beaches',
|
||||||
|
rating: 4.9,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Multiple cards in a responsive grid */
|
||||||
|
export const Grid: Story = {
|
||||||
|
decorators: [
|
||||||
|
(Story) => (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))',
|
||||||
|
gap: 2,
|
||||||
|
width: 680,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</Box>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
render: () => (
|
||||||
|
<>
|
||||||
|
<MiniCard
|
||||||
|
title="H.Parsons Funeral Directors"
|
||||||
|
imageUrl={IMG_PROVIDER}
|
||||||
|
price={900}
|
||||||
|
location="Wollongong"
|
||||||
|
rating={4.8}
|
||||||
|
badges={[
|
||||||
|
{ label: 'Verified', color: 'brand', variant: 'filled', icon: <VerifiedOutlinedIcon /> },
|
||||||
|
]}
|
||||||
|
onClick={() => {}}
|
||||||
|
/>
|
||||||
|
<MiniCard
|
||||||
|
title="Albany Creek Memorial Park"
|
||||||
|
imageUrl={IMG_CHAPEL}
|
||||||
|
price={450}
|
||||||
|
location="Albany Creek"
|
||||||
|
capacity={120}
|
||||||
|
onClick={() => {}}
|
||||||
|
/>
|
||||||
|
<MiniCard
|
||||||
|
title="Lady Anne Funerals"
|
||||||
|
imageUrl={IMG_VENUE}
|
||||||
|
location="Sutherland Shire"
|
||||||
|
onClick={() => {}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
};
|
||||||
259
src/components/molecules/MiniCard/MiniCard.tsx
Normal file
259
src/components/molecules/MiniCard/MiniCard.tsx
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import type { SxProps, Theme } from '@mui/material/styles';
|
||||||
|
import LocationOnOutlinedIcon from '@mui/icons-material/LocationOnOutlined';
|
||||||
|
import StarRoundedIcon from '@mui/icons-material/StarRounded';
|
||||||
|
import PeopleOutlinedIcon from '@mui/icons-material/PeopleOutlined';
|
||||||
|
import { Card } from '../../atoms/Card';
|
||||||
|
import { Typography } from '../../atoms/Typography';
|
||||||
|
import { Badge } from '../../atoms/Badge';
|
||||||
|
import type { BadgeProps } from '../../atoms/Badge/Badge';
|
||||||
|
|
||||||
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** A badge to render inside the MiniCard */
|
||||||
|
export interface MiniCardBadge {
|
||||||
|
/** Label text */
|
||||||
|
label: string;
|
||||||
|
/** Badge colour intent */
|
||||||
|
color?: BadgeProps['color'];
|
||||||
|
/** Badge variant */
|
||||||
|
variant?: BadgeProps['variant'];
|
||||||
|
/** Optional leading icon */
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Props for the FA MiniCard molecule */
|
||||||
|
export interface MiniCardProps {
|
||||||
|
/** Card title — provider name, venue name, package name, etc. */
|
||||||
|
title: string;
|
||||||
|
/** Hero image URL */
|
||||||
|
imageUrl: string;
|
||||||
|
/** Alt text for the image — defaults to title */
|
||||||
|
imageAlt?: string;
|
||||||
|
/** Price in dollars — shown as "From $X" */
|
||||||
|
price?: number;
|
||||||
|
/** Custom price label (e.g. "POA", "Included") — overrides formatted price */
|
||||||
|
priceLabel?: string;
|
||||||
|
/** Location text (suburb, city) */
|
||||||
|
location?: string;
|
||||||
|
/** Average rating (e.g. 4.8) */
|
||||||
|
rating?: number;
|
||||||
|
/** Venue capacity (e.g. 120) */
|
||||||
|
capacity?: number;
|
||||||
|
/** Badge items to render below the title */
|
||||||
|
badges?: MiniCardBadge[];
|
||||||
|
/** Chip labels rendered as small soft badges */
|
||||||
|
chips?: string[];
|
||||||
|
/** Whether this card is currently selected */
|
||||||
|
selected?: boolean;
|
||||||
|
/** Click handler — entire card is clickable */
|
||||||
|
onClick?: () => void;
|
||||||
|
/** MUI sx prop for style overrides */
|
||||||
|
sx?: SxProps<Theme>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Constants ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
const IMAGE_HEIGHT = 'var(--fa-mini-card-image-height)';
|
||||||
|
const CONTENT_PADDING = 'var(--fa-mini-card-content-padding)';
|
||||||
|
const CONTENT_GAP = 'var(--fa-mini-card-content-gap)';
|
||||||
|
|
||||||
|
// ─── Component ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compact vertical card for the FA design system.
|
||||||
|
*
|
||||||
|
* A smaller, flexible card for displaying providers, venues, or packages
|
||||||
|
* in grids, recommendation rows, and map popups. Shows an image with
|
||||||
|
* a title and optional price, badges, chips, and meta row.
|
||||||
|
*
|
||||||
|
* Lighter than ProviderCard — no verified/unverified tiers, no logo
|
||||||
|
* overlay, no capability tooltips. Just image + content.
|
||||||
|
*
|
||||||
|
* Composes: Card + Typography + Badge.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* ```tsx
|
||||||
|
* <MiniCard
|
||||||
|
* title="H.Parsons Funeral Directors"
|
||||||
|
* imageUrl="/images/parsons.jpg"
|
||||||
|
* price={900}
|
||||||
|
* location="Wollongong"
|
||||||
|
* rating={4.8}
|
||||||
|
* badges={[{ label: 'Verified', color: 'brand', variant: 'filled' }]}
|
||||||
|
* onClick={() => navigate('/providers/parsons')}
|
||||||
|
* />
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export const MiniCard = React.forwardRef<HTMLDivElement, MiniCardProps>(
|
||||||
|
(
|
||||||
|
{
|
||||||
|
title,
|
||||||
|
imageUrl,
|
||||||
|
imageAlt,
|
||||||
|
price,
|
||||||
|
priceLabel,
|
||||||
|
location,
|
||||||
|
rating,
|
||||||
|
capacity,
|
||||||
|
badges,
|
||||||
|
chips,
|
||||||
|
selected = false,
|
||||||
|
onClick,
|
||||||
|
sx,
|
||||||
|
},
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
|
const hasMeta = location != null || rating != null || capacity != null;
|
||||||
|
const hasPrice = price != null || priceLabel != null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
ref={ref}
|
||||||
|
interactive={!!onClick}
|
||||||
|
selected={selected}
|
||||||
|
padding="none"
|
||||||
|
onClick={onClick}
|
||||||
|
sx={[
|
||||||
|
{
|
||||||
|
overflow: 'hidden',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'background.paper',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...(Array.isArray(sx) ? sx : [sx]),
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{/* ── Image ── */}
|
||||||
|
<Box
|
||||||
|
role="img"
|
||||||
|
aria-label={imageAlt ?? title}
|
||||||
|
sx={{
|
||||||
|
height: IMAGE_HEIGHT,
|
||||||
|
backgroundImage: `url(${imageUrl})`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
backgroundColor: 'var(--fa-color-neutral-100)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* ── Content ── */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: CONTENT_GAP,
|
||||||
|
p: CONTENT_PADDING,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Title */}
|
||||||
|
<Typography variant="h6" maxLines={2}>
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Price */}
|
||||||
|
{hasPrice && (
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'baseline', gap: 0.5 }}>
|
||||||
|
{priceLabel ? (
|
||||||
|
<Typography variant="body2" color="primary" sx={{ fontStyle: 'italic' }}>
|
||||||
|
{priceLabel}
|
||||||
|
</Typography>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
From
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
component="span"
|
||||||
|
color="primary"
|
||||||
|
sx={{ fontWeight: 600 }}
|
||||||
|
>
|
||||||
|
${price!.toLocaleString('en-AU')}
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Badges */}
|
||||||
|
{badges && badges.length > 0 && (
|
||||||
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
|
||||||
|
{badges.map((badge) => (
|
||||||
|
<Badge
|
||||||
|
key={badge.label}
|
||||||
|
color={badge.color}
|
||||||
|
variant={badge.variant}
|
||||||
|
size="small"
|
||||||
|
icon={badge.icon}
|
||||||
|
>
|
||||||
|
{badge.label}
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Chips */}
|
||||||
|
{chips && chips.length > 0 && (
|
||||||
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
|
||||||
|
{chips.map((chip) => (
|
||||||
|
<Badge key={chip} color="default" variant="soft" size="small">
|
||||||
|
{chip}
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Meta row: location / rating / capacity */}
|
||||||
|
{hasMeta && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 1.5,
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{location && (
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
||||||
|
<LocationOnOutlinedIcon
|
||||||
|
sx={{ fontSize: 14, color: 'text.secondary' }}
|
||||||
|
aria-hidden
|
||||||
|
/>
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
{location}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{rating != null && (
|
||||||
|
<Box
|
||||||
|
sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}
|
||||||
|
aria-label={`Rated ${rating} out of 5`}
|
||||||
|
>
|
||||||
|
<StarRoundedIcon sx={{ fontSize: 14, color: 'warning.main' }} aria-hidden />
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
{rating}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{capacity != null && (
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
||||||
|
<PeopleOutlinedIcon sx={{ fontSize: 14, color: 'text.secondary' }} aria-hidden />
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
{capacity} guests
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
MiniCard.displayName = 'MiniCard';
|
||||||
|
export default MiniCard;
|
||||||
2
src/components/molecules/MiniCard/index.ts
Normal file
2
src/components/molecules/MiniCard/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export { MiniCard, default } from './MiniCard';
|
||||||
|
export type { MiniCardProps, MiniCardBadge } from './MiniCard';
|
||||||
@@ -26,6 +26,11 @@
|
|||||||
--fa-input-height-sm: 40px; /** Small — compact forms, admin layouts, matches Button medium height */
|
--fa-input-height-sm: 40px; /** Small — compact forms, admin layouts, matches Button medium height */
|
||||||
--fa-input-height-md: 48px; /** Medium (default) — standard forms, matches Button large for alignment */
|
--fa-input-height-md: 48px; /** Medium (default) — standard forms, matches Button large for alignment */
|
||||||
--fa-input-icon-size-default: 20px; /** 20px — icon size inside input field, matches Figma trailing icon */
|
--fa-input-icon-size-default: 20px; /** 20px — icon size inside input field, matches Figma trailing icon */
|
||||||
|
--fa-map-pin-height: 28px; /** Pill height — compact for map density */
|
||||||
|
--fa-map-pin-font-size: 12px; /** Small but legible price text */
|
||||||
|
--fa-map-pin-dot-size: 12px; /** Small circle marker */
|
||||||
|
--fa-map-pin-nub-size: 6px; /** Nub triangle size */
|
||||||
|
--fa-mini-card-image-height: 120px; /** Shorter image than full listing cards (180px) for compact grids */
|
||||||
--fa-provider-card-image-height: 180px; /** Fixed image height for consistent card sizing in list layouts */
|
--fa-provider-card-image-height: 180px; /** Fixed image height for consistent card sizing in list layouts */
|
||||||
--fa-provider-card-logo-size: 64px; /** Logo width/height — rounded rectangle, overlapping image bottom into content row */
|
--fa-provider-card-logo-size: 64px; /** Logo width/height — rounded rectangle, overlapping image bottom into content row */
|
||||||
--fa-radio-size-default: 20px; /** Default radio size — matches Figma 16px + padding for 44px touch target area */
|
--fa-radio-size-default: 20px; /** Default radio size — matches Figma 16px + padding for 44px touch target area */
|
||||||
@@ -268,6 +273,10 @@
|
|||||||
--fa-input-font-size-default: var(--fa-font-size-base); /** 16px — prevents iOS auto-zoom on focus, matches Figma */
|
--fa-input-font-size-default: var(--fa-font-size-base); /** 16px — prevents iOS auto-zoom on focus, matches Figma */
|
||||||
--fa-input-border-radius-default: var(--fa-border-radius-sm); /** 4px — subtle rounding, consistent with Figma design */
|
--fa-input-border-radius-default: var(--fa-border-radius-sm); /** 4px — subtle rounding, consistent with Figma design */
|
||||||
--fa-input-gap-default: var(--fa-spacing-2); /** 8px — vertical rhythm between label/input/helper, slightly more generous than Figma's 6px for readability */
|
--fa-input-gap-default: var(--fa-spacing-2); /** 8px — vertical rhythm between label/input/helper, slightly more generous than Figma's 6px for readability */
|
||||||
|
--fa-map-pin-padding-x: var(--fa-spacing-2); /** 8px horizontal padding inside pill */
|
||||||
|
--fa-map-pin-border-radius: var(--fa-border-radius-full); /** Fully rounded pill shape */
|
||||||
|
--fa-mini-card-content-padding: var(--fa-spacing-3); /** 12px — matches ProviderCard/VenueCard content padding */
|
||||||
|
--fa-mini-card-content-gap: var(--fa-spacing-1); /** 4px vertical gap between content rows */
|
||||||
--fa-provider-card-logo-border-radius: var(--fa-border-radius-md); /** 8px rounded rectangle — softer than circle, matches card border radius */
|
--fa-provider-card-logo-border-radius: var(--fa-border-radius-md); /** 8px rounded rectangle — softer than circle, matches card border radius */
|
||||||
--fa-provider-card-content-padding: var(--fa-spacing-3); /** 12px content padding — tight to keep card compact in listing layout */
|
--fa-provider-card-content-padding: var(--fa-spacing-3); /** 12px content padding — tight to keep card compact in listing layout */
|
||||||
--fa-provider-card-content-gap: var(--fa-spacing-1); /** 4px vertical gap between content rows — tight for compact listing cards */
|
--fa-provider-card-content-gap: var(--fa-spacing-1); /** 4px vertical gap between content rows — tight for compact listing cards */
|
||||||
|
|||||||
9
src/theme/generated/tokens.d.ts
vendored
9
src/theme/generated/tokens.d.ts
vendored
@@ -71,6 +71,15 @@ export declare const InputFontSizeDefault: string;
|
|||||||
export declare const InputBorderRadiusDefault: string;
|
export declare const InputBorderRadiusDefault: string;
|
||||||
export declare const InputGapDefault: string;
|
export declare const InputGapDefault: string;
|
||||||
export declare const InputIconSizeDefault: string;
|
export declare const InputIconSizeDefault: string;
|
||||||
|
export declare const MapPinHeight: string;
|
||||||
|
export declare const MapPinPaddingX: string;
|
||||||
|
export declare const MapPinFontSize: string;
|
||||||
|
export declare const MapPinBorderRadius: string;
|
||||||
|
export declare const MapPinDotSize: string;
|
||||||
|
export declare const MapPinNubSize: string;
|
||||||
|
export declare const MiniCardImageHeight: string;
|
||||||
|
export declare const MiniCardContentPadding: string;
|
||||||
|
export declare const MiniCardContentGap: string;
|
||||||
export declare const ProviderCardImageHeight: string;
|
export declare const ProviderCardImageHeight: string;
|
||||||
export declare const ProviderCardLogoSize: string;
|
export declare const ProviderCardLogoSize: string;
|
||||||
export declare const ProviderCardLogoBorderRadius: string;
|
export declare const ProviderCardLogoBorderRadius: string;
|
||||||
|
|||||||
@@ -72,6 +72,15 @@ export const InputFontSizeDefault = "1rem"; // 16px — prevents iOS auto-zoom o
|
|||||||
export const InputBorderRadiusDefault = "4px"; // 4px — subtle rounding, consistent with Figma design
|
export const InputBorderRadiusDefault = "4px"; // 4px — subtle rounding, consistent with Figma design
|
||||||
export const InputGapDefault = "8px"; // 8px — vertical rhythm between label/input/helper, slightly more generous than Figma's 6px for readability
|
export const InputGapDefault = "8px"; // 8px — vertical rhythm between label/input/helper, slightly more generous than Figma's 6px for readability
|
||||||
export const InputIconSizeDefault = "20px"; // 20px — icon size inside input field, matches Figma trailing icon
|
export const InputIconSizeDefault = "20px"; // 20px — icon size inside input field, matches Figma trailing icon
|
||||||
|
export const MapPinHeight = "28px"; // Pill height — compact for map density
|
||||||
|
export const MapPinPaddingX = "8px"; // 8px horizontal padding inside pill
|
||||||
|
export const MapPinFontSize = "12px"; // Small but legible price text
|
||||||
|
export const MapPinBorderRadius = "9999px"; // Fully rounded pill shape
|
||||||
|
export const MapPinDotSize = "12px"; // Small circle marker
|
||||||
|
export const MapPinNubSize = "6px"; // Nub triangle size
|
||||||
|
export const MiniCardImageHeight = "120px"; // Shorter image than full listing cards (180px) for compact grids
|
||||||
|
export const MiniCardContentPadding = "12px"; // 12px — matches ProviderCard/VenueCard content padding
|
||||||
|
export const MiniCardContentGap = "4px"; // 4px vertical gap between content rows
|
||||||
export const ProviderCardImageHeight = "180px"; // Fixed image height for consistent card sizing in list layouts
|
export const ProviderCardImageHeight = "180px"; // Fixed image height for consistent card sizing in list layouts
|
||||||
export const ProviderCardLogoSize = "64px"; // Logo width/height — rounded rectangle, overlapping image bottom into content row
|
export const ProviderCardLogoSize = "64px"; // Logo width/height — rounded rectangle, overlapping image bottom into content row
|
||||||
export const ProviderCardLogoBorderRadius = "8px"; // 8px rounded rectangle — softer than circle, matches card border radius
|
export const ProviderCardLogoBorderRadius = "8px"; // 8px rounded rectangle — softer than circle, matches card border radius
|
||||||
|
|||||||
17
tokens/component/mapPin.json
Normal file
17
tokens/component/mapPin.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"mapPin": {
|
||||||
|
"$description": "MapPin atom tokens — price-pill map markers for provider/venue map views. Verified (brand) vs unverified (neutral) visual distinction.",
|
||||||
|
"height": { "$type": "dimension", "$value": "28px", "$description": "Pill height — compact for map density" },
|
||||||
|
"paddingX": { "$type": "dimension", "$value": "{spacing.2}", "$description": "8px horizontal padding inside pill" },
|
||||||
|
"fontSize": { "$type": "dimension", "$value": "12px", "$description": "Small but legible price text" },
|
||||||
|
"borderRadius": { "$type": "dimension", "$value": "{borderRadius.full}", "$description": "Fully rounded pill shape" },
|
||||||
|
"dot": {
|
||||||
|
"$description": "Dot variant for pins without a price label.",
|
||||||
|
"size": { "$type": "dimension", "$value": "12px", "$description": "Small circle marker" }
|
||||||
|
},
|
||||||
|
"nub": {
|
||||||
|
"$description": "Downward-pointing nub anchoring the pill to the map location.",
|
||||||
|
"size": { "$type": "dimension", "$value": "6px", "$description": "Nub triangle size" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
tokens/component/miniCard.json
Normal file
15
tokens/component/miniCard.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"miniCard": {
|
||||||
|
"$description": "MiniCard molecule tokens — compact vertical card for providers, venues, packages in grids, recommendations, and map popups.",
|
||||||
|
"image": {
|
||||||
|
"$type": "dimension",
|
||||||
|
"$description": "Hero image area dimensions.",
|
||||||
|
"height": { "$value": "120px", "$description": "Shorter image than full listing cards (180px) for compact grids" }
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"$description": "Content area spacing.",
|
||||||
|
"padding": { "$type": "dimension", "$value": "{spacing.3}", "$description": "12px — matches ProviderCard/VenueCard content padding" },
|
||||||
|
"gap": { "$type": "dimension", "$value": "{spacing.1}", "$description": "4px vertical gap between content rows" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user