@contentrain/astro-kit 0.46.2 → 0.46.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/catalog.json +4 -0
- package/components/_shared/card-image.ts +13 -0
- package/components/band/Band.astro +2 -1
- package/components/band/meta.json +1 -0
- package/components/card-grid/CardGrid.astro +3 -2
- package/components/card-grid/meta.json +1 -0
- package/components/post-card/PostCard.astro +2 -1
- package/components/post-card/meta.json +1 -1
- package/components/team/Team.astro +2 -1
- package/components/team/meta.json +1 -0
- package/package.json +1 -1
package/catalog.json
CHANGED
|
@@ -105,6 +105,7 @@
|
|
|
105
105
|
"KitImage.astro",
|
|
106
106
|
"Lines.astro",
|
|
107
107
|
"Section.astro",
|
|
108
|
+
"card-image.ts",
|
|
108
109
|
"image-widths.ts",
|
|
109
110
|
"instance-id.ts",
|
|
110
111
|
"measured.ts",
|
|
@@ -790,6 +791,7 @@
|
|
|
790
791
|
"shared": [
|
|
791
792
|
"KitImage.astro",
|
|
792
793
|
"Section.astro",
|
|
794
|
+
"card-image.ts",
|
|
793
795
|
"image-widths.ts",
|
|
794
796
|
"image.ts",
|
|
795
797
|
"instance-id.ts",
|
|
@@ -5015,6 +5017,7 @@
|
|
|
5015
5017
|
"uses": [],
|
|
5016
5018
|
"shared": [
|
|
5017
5019
|
"KitImage.astro",
|
|
5020
|
+
"card-image.ts",
|
|
5018
5021
|
"image-widths.ts",
|
|
5019
5022
|
"safe-url.ts",
|
|
5020
5023
|
"types.ts"
|
|
@@ -7824,6 +7827,7 @@
|
|
|
7824
7827
|
"shared": [
|
|
7825
7828
|
"KitImage.astro",
|
|
7826
7829
|
"Section.astro",
|
|
7830
|
+
"card-image.ts",
|
|
7827
7831
|
"image-widths.ts",
|
|
7828
7832
|
"image.ts",
|
|
7829
7833
|
"instance-id.ts",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ImageInput } from './types'
|
|
2
|
+
|
|
3
|
+
const spoken = (text: string): string => text.replace(/\s+/g, ' ').trim().replace(/[.:;!]+$/, '').toLowerCase()
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A card's image beside its title link: when the title's link covers the card (a stretched link) and the image's text
|
|
7
|
+
* only repeats the title, the image is drawn with an empty text, so a screen reader says the title once. The content
|
|
8
|
+
* keeps its text (Studio, image search); an image outside such a card, or with words of its own, is drawn as written.
|
|
9
|
+
*/
|
|
10
|
+
export function cardImage(image: ImageInput | undefined, title: string | undefined, linked: boolean): ImageInput | undefined {
|
|
11
|
+
if (!image || !linked || !image.alt || !title || spoken(image.alt) !== spoken(title)) return image
|
|
12
|
+
return { ...image, alt: '' }
|
|
13
|
+
}
|
|
@@ -12,6 +12,7 @@ import type { ActionInput, ImageInput, MeasuredStyle } from '../_shared/types'
|
|
|
12
12
|
import { safeHref } from '../_shared/safe-url'
|
|
13
13
|
import { instanceId } from '../_shared/instance-id'
|
|
14
14
|
import { muted } from '../_shared/muted'
|
|
15
|
+
import { cardImage } from '../_shared/card-image'
|
|
15
16
|
|
|
16
17
|
const band = tv({
|
|
17
18
|
slots: {
|
|
@@ -134,7 +135,7 @@ const hasCopy = Boolean(heading || eyebrow || lead || actions.length)
|
|
|
134
135
|
<ul class={s.list({ class: measuredGrid(measured) })}>
|
|
135
136
|
{items.map(item => (
|
|
136
137
|
<li class={s.item()}>
|
|
137
|
-
{item.media && <div class={s.itemMedia()}><KitImage image={{ src: item.media, alt: item.mediaAlt ?? '' }} sizes="(min-width: 1024px) 33vw, (min-width: 640px) 50vw, 100vw" class="aspect-[3/2] w-full object-cover" /></div>}
|
|
138
|
+
{item.media && <div class={s.itemMedia()}><KitImage image={cardImage({ src: item.media, alt: item.mediaAlt ?? '' }, item.title, !!item.href && !item.linkLabel)!} sizes="(min-width: 1024px) 33vw, (min-width: 640px) 50vw, 100vw" class="aspect-[3/2] w-full object-cover" /></div>}
|
|
138
139
|
{item.icon && <KitImage image={{ src: item.icon, alt: '' }} class="h-10 w-10 object-contain" />}
|
|
139
140
|
{item.value && <p class={s.itemValue()}>{item.value}</p>}
|
|
140
141
|
{item.title && (
|
|
@@ -7,6 +7,7 @@ import Section, { type Tone } from '../_shared/Section.astro'
|
|
|
7
7
|
import { instanceId } from '../_shared/instance-id'
|
|
8
8
|
import { measuredGrid } from '../_shared/measured'
|
|
9
9
|
import type { MeasuredStyle } from '../_shared/types'
|
|
10
|
+
import { cardImage } from '../_shared/card-image'
|
|
10
11
|
import { imageOf, type ImageSource } from '../_shared/image'
|
|
11
12
|
import { safeHref } from '../_shared/safe-url'
|
|
12
13
|
import { muted, mutedReset } from '../_shared/muted'
|
|
@@ -130,7 +131,7 @@ const number = (i: number) => String(i + 1).padStart(2, '0')
|
|
|
130
131
|
{item.text ? <p class={r.text()} data-kit-text>{item.text}</p> : <span aria-hidden="true" />}
|
|
131
132
|
{(imageOf(item.image, item.imageAlt) || (item.href && item.linkLabel)) && (
|
|
132
133
|
<div class={r.end({ class: imageOf(item.image, item.imageAlt) ? 'md:self-start' : undefined })}>
|
|
133
|
-
{imageOf(item.image, item.imageAlt) && <div class={r.media()}><KitImage image={imageOf(item.image, item.imageAlt)!} sizes="(min-width: 768px) 12rem, 100vw" class="aspect-[3/2] w-full object-cover" /></div>}
|
|
134
|
+
{imageOf(item.image, item.imageAlt) && <div class={r.media()}><KitImage image={cardImage(imageOf(item.image, item.imageAlt), item.title, !!item.href && !item.linkLabel)!} sizes="(min-width: 768px) 12rem, 100vw" class="aspect-[3/2] w-full object-cover" /></div>}
|
|
134
135
|
{item.href && item.linkLabel && <a href={safeHref(item.href)} class={r.link()}>{item.linkLabel}</a>}
|
|
135
136
|
</div>
|
|
136
137
|
)}
|
|
@@ -141,7 +142,7 @@ const number = (i: number) => String(i + 1).padStart(2, '0')
|
|
|
141
142
|
<ul class={list({ class: measuredGrid(measured) })}>
|
|
142
143
|
{items.map(item => (
|
|
143
144
|
<li class={card()}>
|
|
144
|
-
{imageOf(item.image, item.imageAlt) && <div class={media()}><KitImage image={imageOf(item.image, item.imageAlt)!} sizes="(min-width: 1024px) 33vw, (min-width: 640px) 50vw, 100vw" class="aspect-[3/2] w-full object-cover transition duration-300 group-hover:scale-[1.02]" /></div>}
|
|
145
|
+
{imageOf(item.image, item.imageAlt) && <div class={media()}><KitImage image={cardImage(imageOf(item.image, item.imageAlt), item.title, !!item.href && !item.linkLabel)!} sizes="(min-width: 1024px) 33vw, (min-width: 640px) 50vw, 100vw" class="aspect-[3/2] w-full object-cover transition duration-300 group-hover:scale-[1.02]" /></div>}
|
|
145
146
|
{item.icon && <KitImage image={{ src: item.icon, alt: '' }} class="h-10 w-10 object-contain" />}
|
|
146
147
|
{item.eyebrow && <p class="text-sm font-medium text-accent-text">{item.eyebrow}</p>}
|
|
147
148
|
<CardHeading class={cardTitle()}>
|
|
@@ -8,6 +8,7 @@ import { tv } from 'tailwind-variants'
|
|
|
8
8
|
import KitImage from '../_shared/KitImage.astro'
|
|
9
9
|
import type { ImageInput, LinkInput } from '../_shared/types'
|
|
10
10
|
import { safeHref } from '../_shared/safe-url'
|
|
11
|
+
import { cardImage } from '../_shared/card-image'
|
|
11
12
|
|
|
12
13
|
const card = tv({
|
|
13
14
|
slots: {
|
|
@@ -82,7 +83,7 @@ const Heading = `h${headingLevel}` as 'h2' | 'h3'
|
|
|
82
83
|
<article class={slots.root()}>
|
|
83
84
|
{image && layout !== 'minimal' && (
|
|
84
85
|
<div class={slots.media()}>
|
|
85
|
-
<KitImage image={image} sizes={sizes ?? (layout === 'horizontal' ? '256px' : '(min-width: 1024px) 360px, 100vw')} class:list={['w-full object-cover transition duration-300 group-hover:scale-[1.02]', !imageStyle && 'aspect-[16/9]']} style={imageStyle} />
|
|
86
|
+
<KitImage image={cardImage(image, title, !!href)!} sizes={sizes ?? (layout === 'horizontal' ? '256px' : '(min-width: 1024px) 360px, 100vw')} class:list={['w-full object-cover transition duration-300 group-hover:scale-[1.02]', !imageStyle && 'aspect-[16/9]']} style={imageStyle} />
|
|
86
87
|
</div>
|
|
87
88
|
)}
|
|
88
89
|
<div class={slots.body()}>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"description": "One post in a list (index, archive, related posts): image, category, date, title, excerpt, author. The whole card links to the post.",
|
|
5
5
|
"category": "content",
|
|
6
6
|
"uses": [],
|
|
7
|
-
"shared": ["KitImage.astro", "image-widths.ts", "safe-url.ts", "types.ts"],
|
|
7
|
+
"shared": ["KitImage.astro", "card-image.ts", "image-widths.ts", "safe-url.ts", "types.ts"],
|
|
8
8
|
"variants": {
|
|
9
9
|
"layout": { "options": ["vertical", "horizontal", "minimal"], "default": "vertical", "description": "Image on top, image beside the text, or text only with a divider." },
|
|
10
10
|
"surface": { "options": ["plain", "card"], "default": "plain", "description": "plain: no surface. card: its own background (--color-card), radius and shadow (--shadow-card), the text padded (--spacing-card) and the image flush at the edge, as theme cards are drawn on a tinted page." },
|
|
@@ -7,6 +7,7 @@ import Section from '../_shared/Section.astro'
|
|
|
7
7
|
import { instanceId } from '../_shared/instance-id'
|
|
8
8
|
import { measuredGrid } from '../_shared/measured'
|
|
9
9
|
import type { MeasuredStyle } from '../_shared/types'
|
|
10
|
+
import { cardImage } from '../_shared/card-image'
|
|
10
11
|
import { imageOf, type ImageSource } from '../_shared/image'
|
|
11
12
|
import { profile } from './team'
|
|
12
13
|
import { safeHref } from '../_shared/safe-url'
|
|
@@ -109,7 +110,7 @@ const NameHeading = heading ? 'h3' : 'h2'
|
|
|
109
110
|
{items.map(member => (
|
|
110
111
|
<li class={s.member()}>
|
|
111
112
|
{/* The portrait's text defaults to the name: a photo of a named person is not decoration. */}
|
|
112
|
-
{imageOf(member.image, member.imageAlt ?? member.name) && <div class={`${s.portrait()} kit-portrait`}><KitImage image={imageOf(member.image, member.imageAlt ?? member.name)!} sizes="(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw" class="aspect-square w-full object-cover" /></div>}
|
|
113
|
+
{imageOf(member.image, member.imageAlt ?? member.name) && <div class={`${s.portrait()} kit-portrait`}><KitImage image={cardImage(imageOf(member.image, member.imageAlt ?? member.name), member.name, !!member.href)!} sizes="(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw" class="aspect-square w-full object-cover" /></div>}
|
|
113
114
|
<NameHeading class={s.name()}>
|
|
114
115
|
{member.href
|
|
115
116
|
? <a href={safeHref(member.href)} class="text-current no-underline after:absolute after:inset-0 after:content-[''] hover:text-accent-text">{member.name}</a>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentrain/astro-kit",
|
|
3
|
-
"version": "0.46.
|
|
3
|
+
"version": "0.46.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Copy-in Astro components for Contentrain sites (shadcn model): typed props, tailwind-variants, zero JavaScript by default — with a machine-readable catalog",
|
|
6
6
|
"type": "module",
|