Skip to content

Commit e36fb69

Browse files
committed
Update callout stylings
1 parent c1199ec commit e36fb69

14 files changed

Lines changed: 131 additions & 30 deletions

File tree

_TODO.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ Need a tooltip component for consistency. List to add tooltips to:
142142
- /tags/[tag]
143143
- Bug reporter modal
144144

145+
## Text on Images
146+
147+
A scrim is an elliptical gradient from translucent black (center) to transparent black (edges), strategically placed behind white text. The scrim is probably the most subtle way of reliably overlaying text on images out there, and very few designs use this technique.
148+
149+
To overlay an article title and published date on a cover image, use CSS positioning, specifically position: relative on the container and position: absolute on the text elements, combined with design techniques to ensure readability such as a semi-transparent overlay or text shadows.
150+
145151
## Image generation models
146152

147153
- dall-e (OpenAI)

src/components/Callout/index.astro

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,29 @@ const iconMap = {
2323
action: 'warning',
2424
info: 'info',
2525
tip: 'lightbulb',
26-
note: 'question',
26+
note: 'info',
2727
success: 'check',
2828
danger: 'warning',
2929
} as const
3030
3131
// Map callout types to their background color CSS custom properties
3232
const backgroundColorMap = {
33-
warning: 'var(--color-danger-inverse)',
34-
action: 'var(--color-danger-inverse)',
33+
warning: 'var(--color-warning-inverse)',
34+
action: 'var(--color-warning-inverse)',
3535
info: 'var(--color-info-inverse)',
36-
tip: 'var(--color-page-base-offset)',
37-
note: 'var(--color-page-base-offset)',
36+
tip: 'var(--color-success-inverse)',
37+
note: 'var(--color-note-inverse)',
3838
success: 'var(--color-success-inverse)',
3939
danger: 'var(--color-danger-inverse)',
4040
} as const
4141
4242
// Map callout types to their border/icon color CSS custom properties
4343
const borderColorMap = {
44-
warning: 'var(--color-danger)',
45-
action: 'var(--color-danger)',
44+
warning: 'var(--color-warning)',
45+
action: 'var(--color-warning)',
4646
info: 'var(--color-info)',
47-
tip: 'var(--color-content)',
48-
note: 'var(--color-content)',
47+
tip: 'var(--color-success)',
48+
note: 'var(--color-note)',
4949
success: 'var(--color-success)',
5050
danger: 'var(--color-danger)',
5151
} as const
@@ -54,33 +54,59 @@ const icon = iconMap[type] ?? iconMap.info
5454
const backgroundColor = backgroundColorMap[type] ?? backgroundColorMap.info
5555
const borderColor = borderColorMap[type] ?? borderColorMap.info
5656
const typeLabel = typeLabelMap[type] ?? typeLabelMap.info
57+
const typeLabelUpper = typeLabel.toUpperCase()
5758
---
5859

5960
<style define:vars={{ backgroundColor, borderColor }}>
6061
.callout {
6162
background-color: var(--backgroundColor);
62-
border-left-color: var(--borderColor);
63+
border: 0;
64+
border-left: 6px solid var(--borderColor);
65+
border-radius: 0;
66+
display: flex;
67+
flex-direction: column;
68+
gap: 0.75rem;
69+
padding: 1rem;
70+
}
71+
72+
.callout__header {
73+
align-items: center;
74+
display: flex;
75+
gap: 0.5rem;
6376
}
6477

6578
.callout__icon {
6679
color: var(--borderColor);
80+
transform: translateY(-2px);
81+
}
82+
83+
.callout__icon :global(svg) {
84+
fill: currentcolor;
85+
}
86+
87+
.callout__label {
88+
color: var(--borderColor);
89+
font-size: 1rem;
90+
font-weight: bold;
91+
letter-spacing: 0.08em;
92+
text-transform: uppercase;
6793
}
6894

6995
/* Spacing for nested elements */
70-
/* stylelint-disable-next-line selector-max-universal */
71-
.callout__content > * + * {
96+
.callout__content > :not(.sr-only) + :not(.sr-only) {
7297
margin-top: 2rem;
7398
}
7499
</style>
75100

76-
<div class="callout border border--border border-l-0 rounded-r-lg relative pl-6" role="note">
77-
<div
78-
class="callout__icon bg-bg rounded-full absolute left-0 top-0 ml-0.5 p-1 -translate-x-1/2 -translate-y-1/2"
79-
>
80-
<Icon name={icon} size={20} />
101+
<div class="callout" role="note">
102+
<div class="callout__header">
103+
<div class="callout__icon">
104+
<Icon name={icon} size={20} variant="custom" />
105+
</div>
106+
<div class="callout__label" aria-hidden="true">{typeLabelUpper}</div>
81107
</div>
82108

83-
<div class="callout__content border-l-4 p-4 md:pl-8">
109+
<div class="callout__content">
84110
<span class="sr-only">{typeLabel} callout:</span>
85111
<slot />
86112
</div>

src/content/articles/demo/index.mdx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@ This is a danger callout. Use it for critical warnings or errors that need immed
8787
This is a danger callout. Use it for critical warnings or errors that need immediate attention.
8888
</Callout>
8989

90+
91+
```markdown
92+
<Callout type="note">
93+
This is a note callout.
94+
</Callout>
95+
```
96+
97+
<Callout type="note">
98+
This is a note callout.
99+
</Callout>
100+
90101
### Carousel Component
91102

92103
Showcase related articles using the production carousel component:

src/lib/config/markdown.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ export const rehypeAutolinkHeadingsConfig: RehypeAutolinkHeadingsOptions = {
198198
'focus-visible:no-underline',
199199
'transition-colors',
200200
],
201+
ariaLabel: 'Link to this section',
201202
},
202203
content: {
203204
type: 'element',

src/lib/markdown/__tests__/e2e/full-pipeline.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ describe('Layer 4: E2E - Full Pipeline Integration', () => {
3636
expect(html).toContain('class="c-blockquote') // Attribution
3737
expect(html).toContain('❤️') // Emoji
3838
expect(html).toContain('href="https://www.webstackbuilders.com"') // Auto-linking
39-
expect(html).toContain('class="anchor-link"') // Anchor headings
39+
expect(html).toContain('class="anchor-link') // Anchor headings
4040

4141
// Check accessibility
4242
const results = await axe(container)

src/lib/markdown/__tests__/e2e/rehype-autolink-headings.spec.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,12 @@ describe('Layer 3: E2E - rehypeAutolinkHeadings', () => {
102102
it('should add accessible attributes to anchor links', () => {
103103
const { container } = render(<MarkdownOutput html={html} />)
104104

105-
// Anchor links should have aria-hidden or similar for accessibility
106-
expect(html).toMatch(/aria-hidden=["']true["']/)
105+
// Heading anchor links should have an accessible name (axe: link-name)
106+
const headingAnchor = container.querySelector('h1 a,h2 a,h3 a,h4 a,h5 a,h6 a')
107+
expect(headingAnchor).toBeTruthy()
108+
expect(headingAnchor?.getAttribute('aria-label')).toBeTruthy()
107109

108-
const ariaHiddenLink = container.querySelector('a[aria-hidden="true"]')
109-
expect(ariaHiddenLink).toBeTruthy()
110+
// The icon itself should remain hidden from screen readers
111+
expect(html).toMatch(/class=["'][^"']*anchor-link[^"']*["'][^>]*aria-hidden=["']true["']/)
110112
})
111113
})

src/lib/markdown/__tests__/integration/rehype-tailwind-simple-elements-astro.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe('rehype-tailwind: Simple HTML Elements (Astro Pipeline)', () => {
3131
const markdown = 'This is a test paragraph.'
3232
const html = await processMarkdown(markdown)
3333

34-
expect(html).toContain('<p class="mb-8 text-lg leading-relaxed">')
34+
expect(html).toContain('<p class="mb-8 leading-relaxed">')
3535
expect(html).toContain('This is a test paragraph.')
3636
})
3737

@@ -41,7 +41,7 @@ describe('rehype-tailwind: Simple HTML Elements (Astro Pipeline)', () => {
4141
Second paragraph.`
4242
const html = await processMarkdown(markdown)
4343

44-
const paragraphMatches = html.match(/<p class="mb-8 text-lg leading-relaxed">/g)
44+
const paragraphMatches = html.match(/<p class="mb-8 leading-relaxed">/g)
4545
expect(paragraphMatches).toHaveLength(2)
4646
})
4747
})
@@ -179,7 +179,7 @@ This is a paragraph with **bold** text.
179179
const html = await processMarkdown(markdown)
180180

181181
// Verify paragraph classes
182-
expect(html).toContain('class="mb-8 text-lg leading-relaxed"')
182+
expect(html).toContain('class="mb-8 leading-relaxed"')
183183

184184
// Verify list classes
185185
expect(html).toContain('class="list-disc list-outside pl-4 mb-8"')
@@ -209,7 +209,7 @@ This paragraph has *italic* and **bold** text.
209209
expect(html).toContain('<strong>')
210210
// @TODO: there is work to improve this entire approach away from string-based in a branch
211211
//expect(html).toContain('<code>')
212-
expect(html).toContain('class="mb-8 text-lg leading-relaxed"')
212+
expect(html).toContain('class="mb-8 leading-relaxed"')
213213
expect(html).toContain('class="list-disc list-outside pl-4 mb-8"')
214214
})
215215
})

src/lib/markdown/plugins/rehype-tailwind/__tests__/index.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ describe('Paragraph (p) element', () => {
191191
test('has spacing and typography classes', () => {
192192
const config = getElementConfig('p')
193193
expect(config?.classes).toContain('mb-8')
194-
expect(config?.classes).toContain('text-lg')
195194
expect(config?.classes).toContain('leading-relaxed')
196195
})
197196
})

src/styles/print.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
html {
33
--theme-color-primary: var(--a11y-theme-color-primary);
44
--theme-color-primary-offset: var(--a11y-theme-color-primary-offset);
5+
--theme-color-primary-inverse: var(--a11y-theme-color-primary-inverse);
56
--theme-color-secondary: var(--a11y-theme-color-secondary);
67
--theme-color-secondary-offset: var(--a11y-theme-color-secondary-offset);
8+
--theme-color-secondary-inverse: var(--a11y-theme-color-secondary-inverse);
79
--theme-color-accent: var(--a11y-theme-color-accent);
810
--theme-color-accent-offset: var(--a11y-theme-color-accent-offset);
911
--theme-color-page-base: var(--a11y-theme-color-page-base);
@@ -23,6 +25,9 @@
2325
--theme-color-info: var(--a11y-theme-color-info);
2426
--theme-color-info-offset: var(--a11y-theme-color-info-offset);
2527
--theme-color-info-inverse: var(--a11y-theme-color-info-inverse);
28+
--theme-color-note: var(--a11y-theme-color-note);
29+
--theme-color-note-offset: var(--a11y-theme-color-note-offset);
30+
--theme-color-note-inverse: var(--a11y-theme-color-note-inverse);
2631
--theme-color-warning: var(--a11y-theme-color-warning);
2732
--theme-color-warning-offset: var(--a11y-theme-color-warning-offset);
2833
--theme-color-warning-inverse: var(--a11y-theme-color-warning-inverse);

src/styles/theme-inline.css

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,16 @@
103103
--color-info-offset: var(--theme-color-info-offset); /* Light theme: #38bdf8 */
104104
--color-info-inverse: var(--theme-color-info-inverse); /* Light theme: #cffafe */
105105

106+
/**
107+
* =============================================================================
108+
* Note colors
109+
* =============================================================================
110+
*/
111+
112+
--color-note: var(--theme-color-note); /* Light theme: #374151 */
113+
--color-note-offset: var(--theme-color-note-offset); /* Light theme: #6b7280 */
114+
--color-note-inverse: var(--theme-color-note-inverse); /* Light theme: #d1d5db */
115+
106116
/**
107117
* =============================================================================
108118
* Warning colors
@@ -140,8 +150,6 @@
140150
* Palette colors
141151
* =============================================================================
142152
*/
143-
--color-black: var(--theme-color-black); /* Light theme: #000 */
144-
--color-white: var(--theme-color-white); /* Light theme: #fff */
145153

146154
/** Blues */
147155
--color-blue-50: var(--theme-color-blue-50); /* Light theme: #eff6ff */

0 commit comments

Comments
 (0)