Skip to content

Commit f23dd3d

Browse files
authored
feat: integrate CalEmbed component and update booking buttons across layouts and pages
1 parent b5cf158 commit f23dd3d

7 files changed

Lines changed: 228 additions & 25 deletions

File tree

package.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@
55
"description": "AR10Dev Github Page",
66
"author": "AR10Dev",
77
"scripts": {
8-
"dev": "astro dev",
9-
"build": "astro check && astro build",
10-
"check": "astro check",
11-
"preview": "astro preview",
12-
"lint": "biome check .",
13-
"lint:fix": "biome check --write .",
14-
"format": "biome format .",
15-
"format:fix": "biome format --write .",
16-
"setup:d2": "curl -fsSL https://d2lang.com/install.sh | sh -s --",
8+
"dev": "astro dev",
9+
"build": "astro check && astro build",
10+
"check": "astro check",
11+
"preview": "astro preview",
12+
"lint": "biome check .",
13+
"lint:fix": "biome check --write .",
14+
"format": "biome format .",
15+
"format:fix": "biome format --write .",
16+
"setup:d2": "curl -fsSL https://d2lang.com/install.sh | sh -s --",
1717

18-
"agent:lint": "biome check --write . --reporter=summary",
19-
"agent:check": "astro check 2>&1 | grep -E '(error|warning|Error|Warning)' || true",
20-
"agent:build": "astro build --silent 2>&1 | grep -E '(error|Error|warn|✗)' || true",
21-
"agent:spell": "cspell \"**\" --no-progress --no-summary 2>&1 | grep -v '^$' || true",
18+
"agent:lint": "biome check --write . --reporter=summary",
19+
"agent:check": "astro check 2>&1 | grep -E '(error|warning|Error|Warning)' || true",
20+
"agent:build": "astro build --silent 2>&1 | grep -E '(error|Error|warn|✗)' || true",
21+
"agent:spell": "cspell \"**\" --no-progress --no-summary 2>&1 | grep -v '^$' || true",
2222
"agent:verify": "bun run agent:lint && bun run agent:check && bun run agent:build"
2323
},
2424
"keywords": [],

src/components/CalEmbed.astro

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<script is:inline>
2+
(function (C, A, L) {
3+
let p = function (a, ar) {
4+
a.q.push(ar);
5+
};
6+
let d = C.document;
7+
C.Cal = C.Cal || function () {
8+
let cal = C.Cal;
9+
let ar = arguments;
10+
if (!cal.loaded) {
11+
cal.ns = {};
12+
cal.q = cal.q || [];
13+
d.head.appendChild(d.createElement("script")).src = A;
14+
cal.loaded = true;
15+
}
16+
if (ar[0] === L) {
17+
const api = function () {
18+
p(api, arguments);
19+
};
20+
const namespace = ar[1];
21+
api.q = api.q || [];
22+
if (typeof namespace === "string") {
23+
cal.ns[namespace] = cal.ns[namespace] || api;
24+
p(cal.ns[namespace], ar);
25+
p(cal, ["initNamespace", namespace]);
26+
} else {
27+
p(cal, ar);
28+
}
29+
return;
30+
}
31+
p(cal, ar);
32+
};
33+
})(window, "https://app.cal.com/embed/embed.js", "init");
34+
35+
(function () {
36+
var isMobile = window.innerWidth < 768;
37+
var layout = isMobile ? "mobile" : "month_view";
38+
var namespace = "discovery-call";
39+
40+
Cal("init", namespace, { origin: "https://cal.com" });
41+
42+
Cal.ns[namespace]("ui", {
43+
styles: {
44+
branding: {
45+
brandColor: "#01696f",
46+
},
47+
},
48+
hideEventTypeDetails: false,
49+
layout: layout,
50+
});
51+
52+
Cal.ns[namespace]("on", {
53+
action: "bookingSuccessful",
54+
callback: function () {
55+
if (typeof gtag !== "undefined") {
56+
gtag("event", "booking_completed", {
57+
event_category: "conversion",
58+
event_label: "discovery_call",
59+
value: 1,
60+
});
61+
}
62+
},
63+
});
64+
})();
65+
</script>

src/layouts/BaseLayout.astro

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
import AnalyticsConsent from "@components/AnalyticsConsent.astro";
3+
import CalEmbed from "@components/CalEmbed.astro";
34
import FooterNav from "@components/FooterNav.astro";
45
import GoogleAnalytics from "@components/GoogleAnalytics.astro";
56
import HeaderNav from "@components/HeaderNav.astro";
@@ -120,5 +121,92 @@ const currentPath = Astro.url.pathname;
120121
import "../scripts/code-copy.ts";
121122
import "../scripts/homepage.ts";
122123
</script>
124+
125+
<CalEmbed />
126+
127+
<div
128+
id="cal-mobile-bar"
129+
class="fixed bottom-0 left-0 right-0 z-50 md:hidden pb-[env(safe-area-inset-bottom,0px)]"
130+
style="transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1); transform: translateY(0px);"
131+
>
132+
<button
133+
data-cal-link="avaabrazzaq"
134+
data-cal-namespace="discovery-call"
135+
data-cal-config='{"layout":"mobile"}'
136+
class="w-full flex items-center justify-center gap-2 bg-[linear-gradient(120deg,#db7a38,#b05422)] text-[var(--accent-contrast)] font-bold uppercase tracking-[0.05em] text-[0.84rem] px-6 min-h-[56px] active:opacity-90 transition-opacity cursor-pointer shadow-[0_-4px_20px_rgba(176,84,34,0.3)]"
137+
type="button"
138+
aria-label="Book a discovery call with Avaab Razzaq"
139+
>
140+
<svg
141+
width="16"
142+
height="16"
143+
viewBox="0 0 24 24"
144+
fill="none"
145+
stroke="currentColor"
146+
stroke-width="2.5"
147+
stroke-linecap="round"
148+
stroke-linejoin="round"
149+
aria-hidden="true"
150+
>
151+
<rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
152+
<line x1="16" y1="2" x2="16" y2="6" />
153+
<line x1="8" y1="2" x2="8" y2="6" />
154+
<line x1="3" y1="10" x2="21" y2="10" />
155+
</svg>
156+
Book a Discovery Call
157+
</button>
158+
</div>
159+
160+
<div class="fixed bottom-6 right-6 z-50 hidden md:block">
161+
<button
162+
data-cal-link="avaabrazzaq"
163+
data-cal-namespace="discovery-call"
164+
data-cal-config='{"layout":"month_view"}'
165+
class="inline-flex items-center gap-2 bg-[linear-gradient(120deg,#db7a38,#b05422)] text-[var(--accent-contrast)] shadow-[0_14px_30px_rgba(176,84,34,0.25)] hover:shadow-[0_12px_26px_rgba(15,23,42,0.2)] hover:-translate-y-[1px] rounded-full px-5 py-3 text-[0.84rem] font-bold uppercase tracking-[0.05em] transition-[transform,box-shadow,background] duration-200 cursor-pointer"
166+
type="button"
167+
aria-label="Book a discovery call with Avaab Razzaq"
168+
>
169+
<svg
170+
width="15"
171+
height="15"
172+
viewBox="0 0 24 24"
173+
fill="none"
174+
stroke="currentColor"
175+
stroke-width="2.5"
176+
stroke-linecap="round"
177+
stroke-linejoin="round"
178+
aria-hidden="true"
179+
>
180+
<rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
181+
<line x1="16" y1="2" x2="16" y2="6" />
182+
<line x1="8" y1="2" x2="8" y2="6" />
183+
<line x1="3" y1="10" x2="21" y2="10" />
184+
</svg>
185+
Book a Call
186+
</button>
187+
</div>
188+
189+
<script is:inline>
190+
(function () {
191+
var bar = document.getElementById("cal-mobile-bar");
192+
if (!bar) return;
193+
194+
var contact = document.querySelector("#contact, [data-section='contact'], section:last-of-type");
195+
if (!contact) return;
196+
197+
bar.style.transition = "transform 0.3s cubic-bezier(0.16,1,0.3,1)";
198+
199+
var io = new IntersectionObserver(
200+
function (entries) {
201+
entries.forEach(function (entry) {
202+
bar.style.transform = entry.isIntersecting ? "translateY(110%)" : "translateY(0)";
203+
});
204+
},
205+
{ threshold: 0.25 }
206+
);
207+
208+
io.observe(contact);
209+
})();
210+
</script>
123211
</body>
124212
</html>

src/layouts/ServiceLayout.astro

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { getCollection } from "astro:content";
44
import logo from "@assets/logo.png";
55
import "../styles/global.css";
66
import AnalyticsConsent from "@components/AnalyticsConsent.astro";
7+
import CalEmbed from "@components/CalEmbed.astro";
78
import GoogleAnalytics from "@components/GoogleAnalytics.astro";
89
import HeadSEO from "@components/HeadSEO.astro";
910
import { serviceCrossLinks } from "@data/services";
@@ -48,7 +49,6 @@ const {
4849
heroHeadline,
4950
heroSubheadline,
5051
ctaText,
51-
ctaHref = "/contact/",
5252
serviceName,
5353
serviceDescription,
5454
keywords = [],
@@ -352,9 +352,15 @@ const structuredData = {
352352
<p class={`hero-subheadline service-intro mt-6 ${TYPOGRAPHY_CLASSES.subheading}`}>{heroSubheadline}</p>
353353

354354
<div class="mt-10 flex flex-wrap gap-4">
355-
<a href={ctaHref} class={`${BUTTON_CLASSES.base} ${BUTTON_CLASSES.primary}`}>
355+
<button
356+
type="button"
357+
data-cal-link="avaabrazzaq"
358+
data-cal-namespace="discovery-call"
359+
data-cal-config='{"layout":"month_view"}'
360+
class={`${BUTTON_CLASSES.base} ${BUTTON_CLASSES.primary} min-h-[44px] active:scale-95 transition-transform cursor-pointer`}
361+
>
356362
{ctaText}
357-
</a>
363+
</button>
358364
<a href="/#portfolio" class={`${BUTTON_CLASSES.base} ${BUTTON_CLASSES.secondary}`}>
359365
See my work →
360366
</a>
@@ -454,9 +460,15 @@ const structuredData = {
454460
<div class="mx-auto max-w-2xl text-center">
455461
<h2 class={TYPOGRAPHY_CLASSES.sectionTitle}>Ready to Get Started?</h2>
456462
<p class="mt-4 text-[var(--text-muted)]">Free discovery call · No commitment</p>
457-
<a href={ctaHref} class={`mt-8 ${BUTTON_CLASSES.base} ${BUTTON_CLASSES.primary}`}>
463+
<button
464+
type="button"
465+
data-cal-link="avaabrazzaq"
466+
data-cal-namespace="discovery-call"
467+
data-cal-config='{"layout":"month_view"}'
468+
class={`mt-8 ${BUTTON_CLASSES.base} ${BUTTON_CLASSES.primary} min-h-[44px] active:scale-95 transition-transform cursor-pointer`}
469+
>
458470
{ctaText}
459-
</a>
471+
</button>
460472
</div>
461473
</div>
462474
</section>
@@ -486,5 +498,7 @@ const structuredData = {
486498
<script>
487499
import "../scripts/code-copy.ts";
488500
</script>
501+
502+
<CalEmbed />
489503
</body>
490504
</html>

src/pages/index.astro

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,12 @@ const structuredData = {
140140
"AI Growth Engineer helping businesses build web apps, implement AI automation, and scale technical SEO and GEO performance.",
141141
url: siteUrl,
142142
image: ogImage,
143-
sameAs: [homepage.githubUrl, linkedInUrl, twitterUrl, "https://x.com/itsmeAvaab"],
143+
sameAs: [
144+
homepage.githubUrl,
145+
linkedInUrl,
146+
twitterUrl,
147+
"https://x.com/itsmeAvaab",
148+
],
144149
address: {
145150
"@type": "PostalAddress",
146151
addressLocality: "Miami",
@@ -379,7 +384,17 @@ const structuredData = {
379384
Based in <strong class="text-[var(--text-strong)]">Miami, Florida</strong> • Serving clients across the <strong class="text-[var(--text-strong)]">United States</strong>
380385
</p>
381386
<div class="mt-10 flex flex-wrap gap-4">
382-
<a href="/contact/" class={primaryButtonClass} data-track="cta_hero_primary">Book a Discovery Call</a>
387+
<button
388+
data-cal-link="avaabrazzaq"
389+
data-cal-namespace="discovery-call"
390+
data-cal-config='{"layout":"month_view"}'
391+
class={primaryButtonClass}
392+
data-track="cta_hero_primary"
393+
type="button"
394+
aria-label="Book a discovery call with Avaab Razzaq"
395+
>
396+
Book a Discovery Call
397+
</button>
383398
<a href="/portfolio/" class={secondaryButtonClass} data-track="cta_hero_secondary">See My Work</a>
384399
</div>
385400
<SocialLinks links={socialLinks} variant="icon" className="mt-6 gap-3" />
@@ -410,11 +425,17 @@ const structuredData = {
410425
</div>
411426
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-4">
412427
{homepageServiceItems.map((service) => (
413-
<a href={service.href} class="group flex flex-col rounded-xl border border-[var(--card-uniform-border)] bg-[var(--card-uniform-bg)] p-6 shadow-[var(--card-shadow)] transition-all hover:-translate-y-1 hover:shadow-xl">
428+
<button
429+
type="button"
430+
data-cal-link="avaabrazzaq"
431+
data-cal-namespace="discovery-call"
432+
data-cal-config='{"layout":"month_view"}'
433+
class="group flex flex-col rounded-xl border border-[var(--card-uniform-border)] bg-[var(--card-uniform-bg)] p-6 shadow-[var(--card-shadow)] transition-all hover:-translate-y-1 hover:shadow-xl min-h-[44px] active:scale-95 transition-transform cursor-pointer"
434+
>
414435
<h3 class="text-lg font-bold text-[var(--text-strong)] group-hover:text-[var(--accent-strong)] transition-colors">{service.title}</h3>
415436
<p class="mt-3 text-sm text-[var(--text-muted)] flex-grow">{service.body}</p>
416437
<span class="mt-4 text-sm font-semibold text-[var(--accent-strong)]">Get started →</span>
417-
</a>
438+
</button>
418439
))}
419440
</div>
420441
<div class="mt-10 text-center">
@@ -490,9 +511,17 @@ const structuredData = {
490511
</ul>
491512
<div class="mt-8 flex flex-wrap gap-4">
492513
<a class={primaryButtonClass} href="/contact/" data-track="cta_contact_page">Get in Touch</a>
493-
<a class={secondaryButtonClass} href={homepage.bookingUrl} target="_blank" rel="noopener noreferrer" data-track="cta_booking_link">
514+
<button
515+
data-cal-link="avaabrazzaq"
516+
data-cal-namespace="discovery-call"
517+
data-cal-config='{"layout":"month_view"}'
518+
class={secondaryButtonClass}
519+
data-track="cta_booking_link"
520+
type="button"
521+
aria-label="Book a calendar slot with Avaab Razzaq"
522+
>
494523
Book a Calendar Slot
495-
</a>
524+
</button>
496525
</div>
497526
</div>
498527

src/pages/services/mcp-integration.astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
import ServiceLayout from "@layouts/ServiceLayout.astro";
33
import { CONTAINER_CLASSES, TYPOGRAPHY_CLASSES } from "@lib/constants";
44
5-
const siteUrl = new URL(Astro.site?.toString() ?? "https://avaabrazzaq.com").origin;
5+
const siteUrl = new URL(Astro.site?.toString() ?? "https://avaabrazzaq.com")
6+
.origin;
67
78
const faqs = [
89
{

src/styles/global.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@
108108
line-height: 1.6;
109109
}
110110

111+
@media (max-width: 767px) {
112+
body {
113+
padding-bottom: max(72px, calc(72px + env(safe-area-inset-bottom)));
114+
}
115+
}
116+
111117
/* Enhanced typography for headings */
112118
h1,
113119
h2,

0 commit comments

Comments
 (0)