Skip to content

Commit 2b4c0b7

Browse files
committed
Refactor: Unify video promos with banner promo system
- Add 'type' field to PromoData (banner | video) - Add video-specific properties (placeholderImage, imageAltText, videoURL) - Add getFilteredPromos() and getTopPromos() helper functions - Migrate hardcoded videos to promo entries in promotions.ts - Update ReleaseVideo.astro to consume video promos dynamically
1 parent 252eab6 commit 2b4c0b7

File tree

2 files changed

+115
-47
lines changed

2 files changed

+115
-47
lines changed

src/assets/data/promotions.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
export type PromoType = "banner" | "video";
2+
13
export type PromoData = {
4+
type?: PromoType;
25
isActive?: boolean;
36
priority?: number;
47
osTargets?: string[];
@@ -18,10 +21,61 @@ export type PromoData = {
1821
text: string;
1922
link: string;
2023
};
24+
// Video-specific properties
25+
video?: {
26+
placeholderImage: string;
27+
imageAltText: string;
28+
videoURL: string;
29+
};
30+
};
31+
32+
export type FilterOptions = {
33+
type?: PromoType;
34+
os?: string | null;
35+
path?: string | null;
36+
};
37+
38+
/** Get all promos matching the filter criteria, sorted by priority (highest first) */
39+
export const getFilteredPromos = (
40+
promos: PromoData[],
41+
options: FilterOptions = {}
42+
): PromoData[] => {
43+
const { type, os, path } = options;
44+
45+
return promos
46+
.filter((promo) => {
47+
// Check if active
48+
if (promo.isActive === false) return false;
49+
50+
// Check type match
51+
if (type && promo.type !== type) return false;
52+
53+
// Check path suppression
54+
if (path && promo.suppressOnPaths?.includes(path)) return false;
55+
56+
// Check OS targeting
57+
if (promo.osTargets && promo.osTargets.length > 0) {
58+
if (!os || !promo.osTargets.includes(os)) return false;
59+
}
60+
61+
return true;
62+
})
63+
.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
64+
};
65+
66+
/** Get the top N promos matching the filter criteria */
67+
export const getTopPromos = (
68+
promos: PromoData[],
69+
count: number,
70+
options: FilterOptions = {}
71+
): PromoData[] => {
72+
return getFilteredPromos(promos, options).slice(0, count);
2173
};
2274

2375
const promoData: Record<string, PromoData> = {
76+
// === BANNER PROMOS ===
2477
audacity4Alpha: {
78+
type: "banner",
2579
isActive: false,
2680
priority: 50,
2781
suppressOnPaths: ["/next", "/download"],
@@ -42,6 +96,7 @@ const promoData: Record<string, PromoData> = {
4296
},
4397
},
4498
voiceByAuribus: {
99+
type: "banner",
45100
isActive: false,
46101
priority: 50,
47102
osTargets: ["Windows", "OS X"],
@@ -63,6 +118,7 @@ const promoData: Record<string, PromoData> = {
63118
},
64119
},
65120
soapVoiceCleaner: {
121+
type: "banner",
66122
isActive: true,
67123
priority: 50,
68124
osTargets: ["Windows", "OS X"],
@@ -85,6 +141,7 @@ const promoData: Record<string, PromoData> = {
85141
},
86142
},
87143
ampknob: {
144+
type: "banner",
88145
isActive: false,
89146
osTargets: ["Windows", "OS X"],
90147
message: "Heavy guitar tone in seconds. One knob, no distractions.",
@@ -105,6 +162,7 @@ const promoData: Record<string, PromoData> = {
105162
},
106163
},
107164
survey: {
165+
type: "banner",
108166
isActive: false,
109167
message: "3 minute survey:\nHelp us understand what features you want next",
110168
styles: {
@@ -123,6 +181,44 @@ const promoData: Record<string, PromoData> = {
123181
link: "https://docs.google.com/forms/d/e/1FAIpQLScxH_f64JPCWt5nwqa8MTPXfmi453mqYwy1xZFPF_mx9mYkNw/viewform",
124182
},
125183
},
184+
185+
// === VIDEO PROMOS ===
186+
audacity4Video: {
187+
type: "video",
188+
isActive: true,
189+
priority: 100,
190+
message: "How we're building Audacity 4",
191+
tracking: {
192+
category: "Video embed",
193+
action: "Watch release video",
194+
name: "How we're building Audacity 4",
195+
},
196+
video: {
197+
placeholderImage: "https://i.ytimg.com/vi/QYM3TWf_G38/maxresdefault.jpg",
198+
imageAltText: "Video thumbnail: How we're building Audacity 4",
199+
videoURL: "https://www.youtube-nocookie.com/embed/QYM3TWf_G38?autoplay=1",
200+
},
201+
},
202+
playgrndFxVideo: {
203+
type: "video",
204+
isActive: true,
205+
priority: 90,
206+
message: "Install once. Access tons of powerful plugins. Blend for infinite creativity.",
207+
cta: {
208+
text: "Get it on MuseHub",
209+
link: "https://www.musehub.com/plugin/playgrnd-fx?utm_source=au-web&utm_medium=mh-web-cta&utm_campaign=au-web-mh-web-playgrnd-fx",
210+
},
211+
tracking: {
212+
category: "Video embed",
213+
action: "Watch release video",
214+
name: "PLAYGRND FX",
215+
},
216+
video: {
217+
placeholderImage: "https://i.ytimg.com/vi/UGiJCTu67Ak/maxresdefault.jpg",
218+
imageAltText: "Video thumbnail: PLAYGRND FX",
219+
videoURL: "https://www.youtube-nocookie.com/embed/UGiJCTu67Ak?autoplay=1",
220+
},
221+
},
126222
};
127223

128224
export default promoData;
Lines changed: 19 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,29 @@
11
---
2-
import { getImage } from "astro:assets";
32
import FeaturedVideo from "../video/FeaturedVideo";
3+
import promoData, { getTopPromos } from "../../assets/data/promotions";
44
5-
const releaseVideo = {
6-
title:"How we're building Audacity 4",
7-
label:"A sneak peek at our development process and new features.",
8-
placeholderImage: "https://i.ytimg.com/vi/QYM3TWf_G38/maxresdefault.jpg",
9-
imageAltText: "Video thumbnail: How we're building Audacity 4",
10-
videoURL:"https://www.youtube-nocookie.com/embed/QYM3TWf_G38?autoplay=1",
11-
}
12-
13-
const promoVideo = {
14-
CTA: true,
15-
ctaText: "Get it on MuseHub",
16-
ctaURL:"https://www.musehub.com/plugin/playgrnd-fx?utm_source=au-web&utm_medium=mh-web-cta&utm_campaign=au-web-mh-web-playgrnd-fx",
17-
imageAltText: "Video thumbnail",
18-
label:"Install once. Access tons of powerful plugins. Blend for infinite creativity.",
19-
placeholderImage: "https://i.ytimg.com/vi/UGiJCTu67Ak/maxresdefault.jpg",
20-
title:"PLAYGRND FX",
21-
videoURL:"https://www.youtube-nocookie.com/embed/UGiJCTu67Ak?autoplay=1",
22-
}
5+
// Get top 2 active video promos, sorted by priority
6+
const videoPromos = getTopPromos(Object.values(promoData), 2, { type: "video" });
237
---
248
<section class="bg-slate-100">
259
<div class="mx-auto px-6 xs:px-12 md:px-8 py-6 md:py-8 lg:py-12 max-w-screen-lg">
2610
<div class="flex flex-col md:flex-row gap-12 md:gap-16">
27-
<!-- First Video Column -->
28-
<div class="w-full md:w-1/2">
29-
<FeaturedVideo
30-
client:load
31-
title={releaseVideo.title}
32-
label={releaseVideo.label}
33-
placeholderImage={releaseVideo.placeholderImage}
34-
imageAltText={releaseVideo.imageAltText}
35-
videoURL={releaseVideo.videoURL}
36-
matomoEventName={releaseVideo.title}
37-
/>
38-
</div>
39-
40-
<!-- Second Video Column -->
41-
<div class="w-full md:w-1/2">
42-
<FeaturedVideo
43-
client:load
44-
title={promoVideo.title}
45-
label={promoVideo.label}
46-
placeholderImage={promoVideo.placeholderImage}
47-
imageAltText={promoVideo.imageAltText}
48-
videoURL={promoVideo.videoURL}
49-
CTA={promoVideo.CTA}
50-
ctaText={promoVideo.ctaText}
51-
ctaURL={promoVideo.ctaURL}
52-
matomoEventName={promoVideo.title}
53-
/>
54-
</div>
11+
{videoPromos.map((promo) => (
12+
<div class="w-full md:w-1/2">
13+
<FeaturedVideo
14+
client:load
15+
title={promo.tracking?.name ?? promo.message}
16+
label={promo.message}
17+
placeholderImage={promo.video?.placeholderImage ?? ""}
18+
imageAltText={promo.video?.imageAltText ?? ""}
19+
videoURL={promo.video?.videoURL ?? ""}
20+
CTA={Boolean(promo.cta)}
21+
ctaText={promo.cta?.text}
22+
ctaURL={promo.cta?.link}
23+
matomoEventName={promo.tracking?.name ?? promo.message}
24+
/>
25+
</div>
26+
))}
5527
</div>
5628
</div>
5729
</section>

0 commit comments

Comments
 (0)