Type the illustration name in Illustration and Empty (#2944)

This commit is contained in:
Paweł Kuna authored and GitHub committed 2026-09-02 23:42:00 +02:00
1 parent 369322a834
commit 53f5244153
6 files changed
+36 -8

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
---
"@tabler/preview": patch
"@tabler/docs": patch
---
Updated the `Illustration` and `Empty` components to accept only the bundled illustration names, checked at build time.
+2 -1
View File
@@ -3,6 +3,7 @@
import BaseLayout from './BaseLayout.astro'
import Empty from '@ui/Empty.astro'
import errors from '@data/errors.json'
import type { IllustrationImage } from '@shared/lib/svg'
interface Props {
title?: string
@@ -13,7 +14,7 @@ interface Props {
const { title, pageError } = Astro.props
type ErrorEntry = {
illustration?: string
illustration?: IllustrationImage
title?: string | number
header?: string
description?: string
+11 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { iconSvg, iconSourceComment, illustrationSvg } from './svg'
import { freeIllustrationSource, iconSvg, iconSourceComment, illustrationSvg } from './svg'
describe('iconSvg', () => {
it('returns the processed outline svg with a11y attributes and the given classes', () => {
@@ -34,6 +34,16 @@ describe('iconSourceComment', () => {
})
})
describe('freeIllustrationSource', () => {
it('returns the same svg with and without the ".svg" suffix', () => {
expect(freeIllustrationSource('boy-girl.svg')).toBe(freeIllustrationSource('boy-girl'))
})
it('returns the auto-dark source of a bundled illustration', () => {
expect(freeIllustrationSource('not-found')).toContain('<svg ')
})
})
describe('illustrationSvg', () => {
const source = '<svg width="800" height="600" viewBox="0 0 800 600"><path /></svg>'
+12
View File
@@ -1,6 +1,18 @@
// Inline-SVG preparation helpers: filler-path strip, a11y attribute/class swap
// and the illustration attribute rewrites.
import icons from '../data/icons.json'
import freeIllustrations from '../data/free-illustrations.json'
/** Names of the illustrations bundled in @data/free-illustrations.json. */
export type FreeIllustration = keyof typeof freeIllustrations.autodark
/** How an illustration is named in markup — with or without the ".svg" suffix. */
export type IllustrationImage = FreeIllustration | `${FreeIllustration}.svg`
/** Source SVG of a bundled illustration, in its auto-dark variant. */
export function freeIllustrationSource(image: IllustrationImage): string {
return freeIllustrations.autodark[image.replaceAll('.svg', '') as FreeIllustration] ?? ''
}
type IconRecord = { svg: Record<string, string | null | undefined> }
+2 -1
View File
@@ -2,6 +2,7 @@
import Icon from './Icon.astro'
import Button from './Button.astro'
import Illustration from './Illustration.astro'
import type { IllustrationImage } from '@shared/lib/svg'
type PolymorphicProps = { as?: 'p' | 'h1' | 'h2' }
@@ -10,7 +11,7 @@ interface Props extends PolymorphicProps {
height?: number | string
class?: string
/** illustration file name, e.g. "computer-fix.svg" */
illustration?: string | undefined
illustration?: IllustrationImage | undefined
/** big text rendered instead of an icon/illustration */
iconText?: string | undefined
title?: string
+3 -5
View File
@@ -1,18 +1,16 @@
---
import freeIllustrations from '@data/free-illustrations.json'
import { illustrationSvg } from '@shared/lib/svg'
import { freeIllustrationSource, illustrationSvg, type IllustrationImage } from '@shared/lib/svg'
interface Props {
/** file name of the illustration, e.g. "boy-girl.svg" (the ".svg" suffix is stripped) */
image: string
image: IllustrationImage
height?: number | string
class?: string
}
const { image, height = 128, class: className } = Astro.props
const key = image.replaceAll('.svg', '')
const source = (freeIllustrations as { autodark: Record<string, string> }).autodark[key] ?? ''
const source = freeIllustrationSource(image)
const illustration = illustrationSvg(source, { ...(className ? { classes: className } : {}), height })
---