CoolFace
Apppublic

lerobot/robot-learning-tutorial

sourceHugging Faceupdated 1y agoView on Hugging Face
508likes
MultiImage.astro234 linesDownload Raw Back to components
1---2// @ts-ignore - types provided by Astro at runtime3import ResponsiveImage from "./ResponsiveImage.astro";4 5interface ImageItem {6    /** Source image imported via astro:assets */7    src: any;8    /** Alt text for accessibility */9    alt: string;10    /** Individual caption for this image */11    caption?: string;12    /** Optional individual image ID for referencing */13    id?: string;14    /** Enable zoom on this specific image (defaults to parent zoomable setting) */15    zoomable?: boolean;16    /** Enable download on this specific image (defaults to parent downloadable setting) */17    downloadable?: boolean;18}19 20interface Props {21    /** Array of images to display */22    images: ImageItem[];23    /** Global caption for the entire figure */24    caption?: string;25    /** Layout mode: number of columns or 'auto' for responsive */26    layout?: "2-column" | "3-column" | "4-column" | "auto";27    /** Enable medium-zoom behavior on all images (can be overridden per image) */28    zoomable?: boolean;29    /** Show download buttons on all images (can be overridden per image) */30    downloadable?: boolean;31    /** Optional class to apply on the wrapper */32    class?: string;33    /** Optional global ID for the multi-image figure */34    id?: string;35}36 37const {38    images,39    caption,40    layout = "3-column",41    zoomable = false,42    downloadable = false,43    class: className,44    id,45} = Astro.props as Props;46 47const hasCaptionSlot = Astro.slots.has("caption");48const hasCaption =49    hasCaptionSlot || (typeof caption === "string" && caption.length > 0);50const uid = `mi_${Math.random().toString(36).slice(2)}`;51 52// Generate CSS grid columns based on layout53const getGridColumns = () => {54    switch (layout) {55        case "2-column":56            return "repeat(2, 1fr)";57        case "3-column":58            return "repeat(3, 1fr)";59        case "4-column":60            return "repeat(4, 1fr)";61        case "auto":62            return "repeat(auto-fit, minmax(200px, 1fr))";63        default:64            return "repeat(3, 1fr)";65    }66};67 68const gridColumns = getGridColumns();69---70 71<div72    class={`multi-image ${className || ""}`}73    data-mi-root={uid}74    data-layout={layout}75    {id}76>77    {78        hasCaption ? (79            <figure class="multi-image-figure">80                <div81                    class="multi-image-grid"82                    style={`grid-template-columns: ${gridColumns}`}83                >84                    {images.map((image, index) => (85                        <div class="multi-image-item">86                            <ResponsiveImage87                                src={image.src}88                                alt={image.alt}89                                zoomable={image.zoomable ?? zoomable}90                                downloadable={91                                    image.downloadable ?? downloadable92                                }93                                class="multi-image-img"94                            />95                            {image.caption && (96                                <div class="multi-image-subcaption">97                                    {image.caption}98                                </div>99                            )}100                            {image.id && (101                                <span102                                    id={image.id}103                                    style="position: absolute;"104                                />105                            )}106                        </div>107                    ))}108                </div>109                <figcaption class="multi-image-caption">110                    {hasCaptionSlot ? (111                        <slot name="caption" />112                    ) : (113                        caption && <span set:html={caption} />114                    )}115                </figcaption>116            </figure>117        ) : (118            <div119                class="multi-image-grid"120                style={`grid-template-columns: ${gridColumns}`}121            >122                {images.map((image, index) => (123                    <div class="multi-image-item">124                        <ResponsiveImage125                            src={image.src}126                            alt={image.alt}127                            zoomable={image.zoomable ?? zoomable}128                            downloadable={image.downloadable ?? downloadable}129                            class="multi-image-img"130                        />131                        {image.caption && (132                            <div class="multi-image-subcaption">133                                {image.caption}134                            </div>135                        )}136                        {image.id && (137                            <span id={image.id} style="position: absolute;" />138                        )}139                    </div>140                ))}141            </div>142        )143    }144</div>145 146<style>147    .multi-image {148        margin: var(--block-spacing-y) 0;149    }150 151    .multi-image-figure {152        margin: 0;153    }154 155    .multi-image-grid {156        display: grid;157        gap: 1rem;158        align-items: start;159    }160 161    .multi-image-item {162        display: flex;163        flex-direction: column;164        text-align: center;165    }166 167    .multi-image-item :global(.ri-root) {168        margin: 0;169    }170 171    .multi-image-item :global(figure) {172        margin: 0;173    }174 175    .multi-image-img {176        width: 100%;177        height: auto;178        object-fit: contain;179    }180 181    .multi-image-subcaption {182        font-size: 0.85rem;183        color: var(--muted-color);184        margin-top: 0.5rem;185        line-height: 1.4;186    }187 188    .multi-image-caption {189        text-align: left;190        font-size: 0.9rem;191        color: var(--muted-color);192        margin-top: 1rem;193        line-height: 1.4;194    }195 196    /* Responsive behavior */197    @media (max-width: 768px) {198        .multi-image-grid[style*="repeat(3, 1fr)"],199        .multi-image-grid[style*="repeat(4, 1fr)"] {200            grid-template-columns: 1fr !important;201            gap: 1.5rem;202        }203 204        .multi-image-grid[style*="repeat(2, 1fr)"] {205            grid-template-columns: 1fr !important;206            gap: 1.5rem;207        }208    }209 210    @media (min-width: 769px) and (max-width: 1024px) {211        .multi-image-grid[style*="repeat(4, 1fr)"] {212            grid-template-columns: repeat(2, 1fr) !important;213        }214    }215 216    /* Equal height images when desired */217    .multi-image[data-layout*="column"] .multi-image-item :global(img) {218        height: 200px;219        object-fit: contain;220    }221 222    /* Auto layout gets flexible heights */223    .multi-image[data-layout="auto"] .multi-image-item :global(img) {224        height: auto;225    }226 227    /* Ensure images maintain aspect ratio */228    .multi-image-item :global(img) {229        max-width: 100%;230        display: block;231        margin: 0 auto;232    }233</style>234