[web] marketing/testimonials: add Tyler Holdren

This commit is contained in:
Yangshun 2025-09-04 11:31:50 +08:00
parent 05e40bf6f0
commit 5cfb117809
5 changed files with 130 additions and 51 deletions

View File

@ -1 +1,3 @@
<svg viewBox="0 0 384 512" xmlns="http://www.w3.org/2000/svg"><path fill="#808080" d="m318.7 268.7c-.2-36.7 16.4-64.4 50-84.8-18.8-26.9-47.2-41.7-84.7-44.6-35.5-2.8-74.3 20.7-88.5 20.7-15 0-49.4-19.7-76.4-19.7-55.8.9-115.1 44.5-115.1 133.2q0 39.3 14.4 81.2c12.8 36.7 59 126.7 107.2 125.2 25.2-.6 43-17.9 75.8-17.9 31.8 0 48.3 17.9 76.4 17.9 48.6-.7 90.4-82.5 102.6-119.3-65.2-30.7-61.7-90-61.7-91.9zm-56.6-164.2c27.3-32.4 24.8-61.9 24-72.5-24.1 1.4-52 16.4-67.9 34.9-17.5 19.8-27.8 44.3-25.6 71.9 26.1 2 49.9-11.4 69.5-34.3z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="814" height="1000">
<path d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z"/>
</svg>

Before

Width:  |  Height:  |  Size: 534 B

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -9,6 +9,7 @@ import Anchor from '~/components/ui/Anchor';
import Avatar from '~/components/ui/Avatar';
import Divider from '~/components/ui/Divider';
import { headingCVA } from '~/components/ui/Heading';
import Img from '~/components/ui/Img';
import Text, { textVariants } from '~/components/ui/Text';
import { themeTextSubtitleColor } from '~/components/ui/theme';
@ -20,6 +21,9 @@ type TestimonialCardProps = Readonly<{
anonymous: boolean;
authorThumbnailUrl?: string | null;
authorUrl?: string | null;
companyLogoUrl?: string | null;
createdAt: string;
featuredOffer?: string | null;
id: string;
location?: string | null;
name?: string | null;
@ -28,15 +32,33 @@ type TestimonialCardProps = Readonly<{
variant?: 'compact' | 'full';
}>;
function TestimonialCard({
function formatDate(
inputDate: string, // YYYY-MM-DD format
) {
const date = new Date(inputDate);
const options: Intl.DateTimeFormatOptions = {
month: 'short',
year: 'numeric',
};
const formatter = new Intl.DateTimeFormat('en-US', options);
return formatter.format(date);
}
function AuthTestimonialSliderCard({
authorThumbnailUrl,
authorUrl,
companyLogoUrl,
createdAt,
featuredOffer,
location,
name,
testimonial,
title,
variant = 'full',
}: TestimonialCardProps) {
const intl = useIntl();
return (
<div className={clsx('flex flex-col justify-between gap-6')}>
<div className={clsx('flex items-center gap-4', themeTextSubtitleColor)}>
@ -66,50 +88,78 @@ function TestimonialCard({
{testimonial}
</blockquote>
<figcaption
className={clsx('flex flex-col gap-4 sm:flex-row sm:items-center')}>
className={clsx('flex flex-col gap-5 sm:flex-row sm:items-center')}>
{authorThumbnailUrl && (
<Avatar
alt={name ?? ''}
decoding="async"
loading="lazy"
size="lg"
src={authorThumbnailUrl}
/>
<div className="relative">
<Avatar
alt={name ?? ''}
decoding="async"
loading="lazy"
size="lg"
src={authorThumbnailUrl}
/>
{featuredOffer && companyLogoUrl && (
<div
className={clsx(
'grid place-items-center rounded-full p-1',
'absolute -bottom-0 -right-2',
'bg-white',
)}>
<Img
alt={featuredOffer}
className={clsx('size-4', 'object-contain')}
src={companyLogoUrl}
/>
</div>
)}
</div>
)}
<div
className={clsx(
'flex gap-x-2 gap-y-0.5',
variant === 'full' ? 'flex-row flex-wrap' : 'flex-col',
)}>
{name &&
(() => {
if (!authorUrl) {
return (
<Text size="body1" weight="medium">
{name}
</Text>
);
}
<div className="flex flex-col">
<div>
{name &&
(() => {
if (!authorUrl) {
return (
<Text size="body1" weight="medium">
{name}
</Text>
);
}
return (
<Anchor
className={textVariants({
size: 'body1',
weight: 'medium',
})}
href={authorUrl}
variant="flat">
{name}
</Anchor>
);
})()}
<Text
className="block"
color="secondary"
size="body1"
weight="medium">
{[title, location].filter(Boolean).join(', ')}
</Text>
return (
<Anchor
className={textVariants({
size: 'body1',
weight: 'medium',
})}
href={authorUrl}
variant="flat">
{name}
</Anchor>
);
})()}
<Text color="secondary" size="body1" weight="medium">
, {[title, location].filter(Boolean).join(', ')}
</Text>
</div>
<div>
{featuredOffer && (
<Text color="secondary" size="body2">
{intl.formatMessage({
defaultMessage: 'Offer from',
description: 'Offer from companies',
id: '9R/+sv',
})}{' '}
<Text color="subtitle" weight="medium">
{featuredOffer}
</Text>
,{' '}
</Text>
)}
<Text color="secondary" size="body2">
{formatDate(createdAt)}
</Text>
</div>
</div>
</figcaption>
</div>
@ -122,15 +172,20 @@ type Props = Readonly<{
export default function AuthTestimonialSlider({ variant = 'full' }: Props) {
const intl = useIntl();
const testimonials = InterviewsMarketingTestimonialsDict(intl);
const marketingTestimonials = InterviewsMarketingTestimonialsDict(intl);
const [authTestimonials, setAuthTestimonials] = useState(() =>
shuffle([
testimonials.cliffordFung,
testimonials.yugantJoshi,
testimonials.deannaTran,
testimonials.locChuong,
testimonials.edWang,
testimonials.lunghaoLee,
marketingTestimonials.tylerHoldren,
marketingTestimonials.jessieShen,
marketingTestimonials.praveenKumar,
marketingTestimonials.faithMorante,
marketingTestimonials.anubhavKhanna,
marketingTestimonials.lamTran,
marketingTestimonials.cliffordFung,
marketingTestimonials.yugantJoshi,
marketingTestimonials.deannaTran,
marketingTestimonials.locChuong,
marketingTestimonials.edWang,
]),
);
const [currentIndex, setCurrentIndex] = useState(0);
@ -166,7 +221,7 @@ export default function AuthTestimonialSlider({ variant = 'full' }: Props) {
exit={{ opacity: 0 }}
initial={{ opacity: 0 }}
transition={{ duration: 1, ease: 'easeInOut' }}>
<TestimonialCard
<AuthTestimonialSliderCard
{...authTestimonials[currentIndex]}
variant={variant}
/>

View File

@ -45,6 +45,7 @@ export default function InterviewsMarketingHero() {
});
const testimonials = [
marketingTestimonials.tylerHoldren,
marketingTestimonials.jessieShen,
marketingTestimonials.praveenKumar,
marketingTestimonials.faithMorante,

View File

@ -1171,6 +1171,26 @@ export function InterviewsMarketingTestimonialsDict(intl: IntlShape) {
}),
title: 'Frontend Engineer',
};
const tylerHoldren: InterviewsMarketingTestimonial = {
anonymous: false,
authorThumbnailUrl: '/img/testimonials/users/tyler-holdren.webp',
authorUrl: 'https://www.linkedin.com/in/tyler-holdren/',
companyLogoUrl: '/img/testimonials/company/apple.svg',
createdAt: '2025-09-04',
featured: true,
featuredOffer: 'Apple',
id: 'tyler-holdren',
location: 'New York, US',
name: 'Tyler Holdren',
offers: [],
testimonial: intl.formatMessage({
defaultMessage:
"GreatFrontEnd completely transformed my interview prep. I went from feeling uncertain in my JS fundamentals to being able to impress my interviewers with my depth of knowledge and understanding. The coding solutions are official, optimal, and explained by the authors with unmatched clarity, rigor, and evidence. The system design docs are also next-level, breaking down front-end architecture in a way that's clear and approachable, which enabled me to speak confidently in my interviews. I directly attribute my success in navigating the interview landscape to consistent, focused effort and the quality of the content on this platform.",
description: 'User testimonial for GreatFrontEnd Interviews',
id: 'PMSHEJ',
}),
title: 'Software Engineer',
};
// Const template: InterviewsMarketingTestimonial = {
// anonymous: false,
// authorThumbnailUrl: 'TO_BE_FILLED',
@ -1242,6 +1262,7 @@ export function InterviewsMarketingTestimonialsDict(intl: IntlShape) {
skarKing,
skykillz,
t4d95,
tylerHoldren,
uncleTito,
vali,
vietnam,