Calendly Embed
atroui/calendly-embedFreeBlock
Theme-aware Calendly iframe with editable CONTENT and email fallback.
Install it
npx shadcn@latest add https://atroui.com/r/calendly-embed.jsonSource
1"use client"23import { ExternalLink } from "lucide-react"4import { useEffect, useMemo, useState } from "react"56import { getBrand } from "@/lib/brand"78/**9 * Edit CONTENT for fallback copy and default Calendly URL.10 * Prefers CONTENT.url, then NEXT_PUBLIC_CALENDLY_URL.11 */12const CONTENT = {13 url: "",14 stamp: "Scheduler",15 emptyTitle: "Calendly isn't connected yet",16 emptyBody:17 "Set CONTENT.url or NEXT_PUBLIC_CALENDLY_URL - or email us and we'll find a slot.",18 emailCtaPrefix: "Email",19 iframeTitleSuffix: "Book a 15-minute intro call",20 primaryColor: "0b7bff",21 darkBg: "0a0a0a",22 lightBg: "ffffff",23 darkText: "fafafa",24 lightText: "0a0a0a",25}2627export type CalendlyEmbedProps = {28 url?: string29}3031export function CalendlyEmbed({ url }: CalendlyEmbedProps) {32 const calendlyUrl =33 url || CONTENT.url || process.env.NEXT_PUBLIC_CALENDLY_URL || ""34 const [mounted, setMounted] = useState(false)35 const [isDark, setIsDark] = useState(true)36 const brand = getBrand()3738 useEffect(() => {39 setMounted(true)40 const root = document.documentElement41 const sync = () => setIsDark(root.classList.contains("dark"))42 sync()43 const obs = new MutationObserver(sync)44 obs.observe(root, { attributes: true, attributeFilter: ["class"] })45 return () => obs.disconnect()46 }, [])4748 const src = useMemo(() => {49 if (!calendlyUrl) return ""50 try {51 const u = new URL(calendlyUrl)52 const params = new URLSearchParams({53 hide_gdpr_banner: "1",54 hide_landing_page_details: "1",55 hide_event_type_details: "0",56 primary_color: CONTENT.primaryColor,57 background_color: isDark ? CONTENT.darkBg : CONTENT.lightBg,58 text_color: isDark ? CONTENT.darkText : CONTENT.lightText,59 })60 u.search = u.search61 ? `${u.search}&${params.toString()}`62 : `?${params.toString()}`63 return u.toString()64 } catch {65 return ""66 }67 }, [calendlyUrl, isDark])6869 if (!calendlyUrl || !src) {70 return (71 <div className="flex flex-col gap-4 border border-border-subtle px-4 py-10 sm:px-6 sm:py-14">72 <p className="font-mono text-[11px] tracking-wide text-muted-foreground uppercase">73 {CONTENT.stamp}74 </p>75 <h3 className="text-xl font-medium text-foreground">76 {CONTENT.emptyTitle}77 </h3>78 <p className="max-w-md text-sm leading-relaxed text-muted-foreground">79 {CONTENT.emptyBody}80 </p>81 <a82// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from atroui
All 82 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Analytics Provideranalytics-provider | atroui | Blocks | Free | 1 dep | |
| AR Portfolioar-portfolio | atroui | Blocks | Free | 1 dep | |
| Before / Afterbefore-after-slider | atroui | Blocks | Free | no deps | |
| Changelogchangelog | atroui | Blocks | Free | no deps | |
| Command Menucommand-menu | atroui | Blocks | Free | 4 deps | |
| Contact Formcontact-form | atroui | Blocks | Free | 2 deps | |
| Contextual CTAcontextual-cta | atroui | Blocks | Free | 2 deps | |
| Count Upcount-up | atroui | Blocks | Free | no deps |
