Skip to content

Commit a4754c4

Browse files
committed
Changes to Testimonials component to allow single card without carousel, and encapsulate styles used with it on home page
1 parent 6542355 commit a4754c4

12 files changed

Lines changed: 273 additions & 180 deletions

File tree

‎@types/speech-recognition.d.ts‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Minimal Web Speech API typings used by SearchBar voice input.
2+
// The project restricts global `types` in tsconfig, so we declare what we use here.
3+
4+
declare global {
5+
interface SpeechRecognitionErrorEvent extends Event {
6+
error: string
7+
}
8+
9+
interface SpeechRecognitionEvent extends Event {
10+
resultIndex: number
11+
results: ArrayLike<ArrayLike<{ transcript: string; confidence: number }> & { isFinal: boolean }>
12+
}
13+
14+
interface SpeechRecognition extends EventTarget {
15+
continuous: boolean
16+
interimResults: boolean
17+
lang: string
18+
19+
onstart: (() => void) | null
20+
onend: (() => void) | null
21+
onerror: ((event: SpeechRecognitionErrorEvent) => void) | null
22+
onresult: ((event: SpeechRecognitionEvent) => void) | null
23+
24+
start(): void
25+
stop(): void
26+
}
27+
28+
// Constructor globals
29+
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
30+
var SpeechRecognition: {
31+
prototype: SpeechRecognition
32+
new (): SpeechRecognition
33+
}
34+
35+
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
36+
var webkitSpeechRecognition: {
37+
prototype: SpeechRecognition
38+
new (): SpeechRecognition
39+
}
40+
}
41+
42+
export {}

‎package-lock.json‎

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@
100100
"@types/confusing-browser-globals": "1.0.3",
101101
"@types/cross-spawn": "6.0.6",
102102
"@types/dedent": "^0.7.2",
103-
"@types/dom-speech-recognition": "^0.0.7",
104103
"@types/eslint": "^9.6.1",
105104
"@types/eslint-plugin-security": "3.0.0",
106105
"@types/glidejs__glide": "^3.6.6",

‎src/components/Breadcrumbs/__tests__/index.spec.ts‎

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,15 @@ describe('Breadcrumbs (Astro)', () => {
2424
const renderedHtml = await response.text()
2525

2626
await withJsdomEnvironment(async ({ window }) => {
27-
// Prefer document.write here so any hoisted tags (e.g., JSON-LD scripts) are also available.
28-
window.document.open()
29-
window.document.write(renderedHtml)
30-
window.document.close()
27+
const doc = new window.DOMParser().parseFromString(renderedHtml, 'text/html')
3128

32-
const nav = window.document.querySelector('nav[aria-label="Breadcrumbs"]')
29+
const nav = doc.querySelector('nav[aria-label="Breadcrumbs"]')
3330
expect(nav).toBeTruthy()
3431

35-
const current = window.document.querySelector('[aria-current="page"]')
32+
const current = doc.querySelector('[aria-current="page"]')
3633
expect(current?.textContent).toContain('My Post Title')
3734

38-
const links = window.document.querySelectorAll('nav[aria-label="Breadcrumbs"] a[href]')
35+
const links = doc.querySelectorAll<HTMLAnchorElement>('nav[aria-label="Breadcrumbs"] a[href]')
3936
expect(links.length).toBeGreaterThan(0)
4037
links.forEach(link => {
4138
expect(link.getAttribute('href')?.trim().length).toBeGreaterThan(0)
@@ -46,7 +43,7 @@ describe('Breadcrumbs (Astro)', () => {
4643
expect(link.tabIndex).toBeGreaterThanOrEqual(0)
4744
})
4845

49-
const jsonLdScripts = window.document.querySelectorAll('script[type="application/ld+json"]')
46+
const jsonLdScripts = doc.querySelectorAll('script[type="application/ld+json"]')
5047
expect(jsonLdScripts.length).toBe(1)
5148

5249
const jsonLdScript = jsonLdScripts.item(0)

‎src/components/Search/SearchBar/client/__tests__/index.spec.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ describe('SearchBar web component', () => {
5757
container = await AstroContainer.create()
5858
searchQueryMock.mockReset()
5959

60-
delete (globalThis as unknown as Record<string, unknown>).SpeechRecognition
61-
delete (globalThis as unknown as Record<string, unknown>).webkitSpeechRecognition
60+
delete (globalThis as unknown as Record<string, unknown>)['SpeechRecognition']
61+
delete (globalThis as unknown as Record<string, unknown>)['webkitSpeechRecognition']
6262
})
6363

6464
const runComponentRender = async (

‎src/components/Search/SearchBar/index.module.css‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.searchBar[data-search-variant='header'] button[data-search-toggle][data-state='open'] .icon--search {
1+
.searchBar button[data-search-toggle][data-state='open'] .icon--search {
22
color: var(--color-primary);
33
fill: var(--color-primary);
44
}
@@ -9,25 +9,25 @@
99
display: none;
1010
}
1111

12-
.searchBar[data-search-variant='header'] button[data-search-clear] svg {
12+
.searchBar button[data-search-clear] svg {
1313
display: block;
14+
fill: currentcolor;
1415
height: calc(var(--header-icon-svg-size) * 0.75);
1516
width: calc(var(--header-icon-svg-size) * 0.75);
16-
fill: currentColor;
1717
}
1818

19-
.searchBar[data-search-variant='header'] button[data-search-mic] svg {
19+
.searchBar button[data-search-mic] svg {
2020
display: block;
21+
fill: currentcolor;
2122
height: calc(var(--header-icon-svg-size) * 0.75);
2223
width: calc(var(--header-icon-svg-size) * 0.75);
23-
fill: currentColor;
2424
}
2525

26-
.searchBar[data-search-variant='header'] button[data-search-mic]:not([hidden]) + button[data-search-clear] {
26+
.searchBar button:not([hidden]) + button[data-search-clear] {
2727
margin-left: -12px;
2828
}
2929

30-
.searchBar[data-search-variant='header'] form[data-search-form][data-state='open'] {
30+
.searchBar form[data-search-form][data-state='open'] {
3131
box-shadow:
3232
var(--shadow-elevated, 0 0 0 0 transparent),
3333
inset 0 0 0 2px var(--color-spotlight);
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
import type { CollectionEntry } from 'astro:content'
3+
import Avatar from '@components/Avatar/index.astro'
4+
5+
export interface Props {
6+
testimonial: CollectionEntry<'testimonials'>
7+
}
8+
9+
const { testimonial } = Astro.props
10+
---
11+
12+
<article class="bg-page-base-offset rounded-xl p-8 shadow-lg border border-trim h-full flex flex-col">
13+
<div class="text-primary mb-4">
14+
<svg
15+
class="w-8 h-8"
16+
fill="currentColor"
17+
viewBox="0 0 24 24"
18+
aria-hidden="true"
19+
focusable="false"
20+
>
21+
<path d="M14.017 21v-7.391c0-5.704 3.731-9.57 8.983-10.609l.995 2.151c-2.432.917-3.995 3.638-3.995 5.849h4v10h-9.983zm-14.017 0v-7.391c0-5.704 3.748-9.57 9-10.609l.996 2.151c-2.433.917-3.996 3.638-3.996 5.849h4v10h-10z" />
22+
</svg>
23+
</div>
24+
25+
<div class="flex-1 mb-6">
26+
<blockquote class="text-lg leading-relaxed italic">
27+
{testimonial.body}
28+
</blockquote>
29+
</div>
30+
31+
<div class="flex items-center gap-4">
32+
<Avatar name={testimonial.data.name} class="shrink-0" />
33+
<div>
34+
<div class="font-semibold">{testimonial.data.name}</div>
35+
<div class="text-sm text-content-active capitalize">{testimonial.data.organization}</div>
36+
</div>
37+
</div>
38+
</article>

0 commit comments

Comments
 (0)