diff --git a/public/images/tryitout.png b/public/images/tryitout.png new file mode 100644 index 00000000000..330416da8c9 Binary files /dev/null and b/public/images/tryitout.png differ diff --git a/src/components/CodeSample/CodeSample.astro b/src/components/CodeSample/CodeSample.astro index 73cef4f4cb2..8ffa36e46b8 100644 --- a/src/components/CodeSample/CodeSample.astro +++ b/src/components/CodeSample/CodeSample.astro @@ -10,8 +10,9 @@ export type Props = { showButtonOnly?: boolean optimize?: boolean runs?: number + showButtons?: boolean } -const { src, lang, showButtonOnly, optimize, runs } = Astro.props as Props +const { src, lang, showButtonOnly, optimize, runs, showButtons = true } = Astro.props as Props const data = (await fs.readFile(path.join(process.cwd(), "public", src), "utf-8")).toString() @@ -31,7 +32,7 @@ const remixUrl = `https://remix.ethereum.org/#url=https://docs.chain.link/${clea {!showButtonOnly && } { - isSample && ( + isSample && showButtons && (
Open in Remix diff --git a/src/components/CodeSample/CodeSampleReact.tsx b/src/components/CodeSample/CodeSampleReact.tsx index 4b17738649b..687e13ade30 100644 --- a/src/components/CodeSample/CodeSampleReact.tsx +++ b/src/components/CodeSample/CodeSampleReact.tsx @@ -13,7 +13,6 @@ export const CodeSampleReact: React.FC = ({ src, showButto const isSolidityFile = src.match(/\.sol/) const isSample = isSolidityFile && (src.indexOf("samples/") === 0 || src.indexOf("/samples/") === 0) - if (!isSample || !showButtonOnly || !remixUrl) return null return ( diff --git a/src/components/Header/Nav/ProductNavigation/Desktop/MegaMenu.tsx b/src/components/Header/Nav/ProductNavigation/Desktop/MegaMenu.tsx index 61bfa307004..a8a65f8f984 100644 --- a/src/components/Header/Nav/ProductNavigation/Desktop/MegaMenu.tsx +++ b/src/components/Header/Nav/ProductNavigation/Desktop/MegaMenu.tsx @@ -138,7 +138,7 @@ export const megaMenuSections = { icon: creLogo, title: "Chainlink Runtime Environment (CRE)", description: "The global orchestration layer", - link: "/", + link: "/cre", }, ], }, diff --git a/src/components/LeftSidebar/leftSidebar.module.css b/src/components/LeftSidebar/leftSidebar.module.css index d869aebd2a4..0c907405fe0 100644 --- a/src/components/LeftSidebar/leftSidebar.module.css +++ b/src/components/LeftSidebar/leftSidebar.module.css @@ -9,6 +9,7 @@ .navGroups { padding: 0 var(--space-10x) var(--space-10x) 0; + height: calc(100vh - var(--space-16x) - var(--space-16x)); /* Subtract header and footer height */ overflow-y: auto; scrollbar-width: thin; diff --git a/src/components/TryItOut/README.md b/src/components/TryItOut/README.md new file mode 100644 index 00000000000..50a8e94c97a --- /dev/null +++ b/src/components/TryItOut/README.md @@ -0,0 +1,92 @@ +# TryItOut Component + +A component that displays an interactive accordion of features alongside a dynamically changing code sample preview. The code sample updates based on which accordion item is currently expanded. + +## Usage + +```astro + +``` + +## Props + +### `accordionTabs` (required) + +A list of expandable sections that describe different features. Each tab needs: + +- **title**: The heading text for the accordion item +- **text**: The description that appears when the accordion is expanded +- **codeSampleSrc**: The file path to the code sample for this specific tab (should point to a file in the `/samples/` folder) + +**Example:** + +```js +;[ + { + title: "Transfer Tokens", + text: "Move tokens between different blockchains easily.", + codeSampleSrc: "/samples/CCIP/TokenTransfer.sol", + }, + { + title: "Fetch Data", + text: "Get real-time information from external sources.", + codeSampleSrc: "/samples/DataFeeds/PriceFeed.sol", + }, +] +``` + +### `ctas` (optional) + +An array of call-to-action buttons to display in the footer. If not provided, defaults to "Create CRE account" and "Get the SDK" buttons. + +Each CTA object needs: + +- **text**: The button text +- **href**: The button link URL +- **variant** (optional): Either "primary" or "secondary" (defaults to "primary") + +**Example:** + +```js +;[ + { text: "Get Started", href: "/getting-started", variant: "primary" }, + { text: "View Docs", href: "/documentation", variant: "secondary" }, +] +``` + +## How It Works + +The component uses [Astro's nano stores](https://docs.astro.build/en/core-concepts/sharing-state/) to track which accordion item is currently expanded. When you click on a different accordion item, the code sample automatically updates to show the code associated with that item. + +### Technical Implementation + +**Why we pre-render all code samples:** + +All code samples are rendered at build time using the `` Astro component and included in the HTML. While this means all code samples are present in the DOM, they are toggled via visibility rather than dynamically loaded. This approach is necessary because: + +1. **Astro components are build-time only** - The `` component uses Astro's Prism integration which only runs during the build process, not at runtime +2. **Proper syntax highlighting** - Pre-rendering ensures all code has proper syntax highlighting applied via Prism +3. **Performance** - No runtime file reading or syntax highlighting processing; instant switching between code samples +4. **Simplicity** - Avoids complex API endpoints or client-side file fetching + +**Accessibility considerations:** + +Inactive code samples are hidden from both visual users and assistive technology: + +- `display: none` hides them visually +- `aria-hidden="true"` ensures screen readers ignore hidden code blocks +- Only the active code sample has `aria-hidden="false"`, making it visible to screen readers + +When the active accordion changes, the visibility and `aria-hidden` attributes are updated via JavaScript to show the new code sample and hide all others. diff --git a/src/components/TryItOut/TryItOut.astro b/src/components/TryItOut/TryItOut.astro new file mode 100644 index 00000000000..c015f66c5bf --- /dev/null +++ b/src/components/TryItOut/TryItOut.astro @@ -0,0 +1,106 @@ +--- +import { buttonVariants, Typography } from "@chainlink/blocks" +import styles from "./styles.module.css" +import CodeSample from "../CodeSample/CodeSample.astro" +import { TryItOutAccordion } from "./TryItOutAccordion" +import { clsx } from "~/lib/clsx/clsx" + +interface CTA { + text: string + href: string + variant?: "primary" | "secondary" +} + +interface Props { + accordionTabs: Array<{ title: string; text: string; codeSampleSrc: string }> + ctas: CTA[] +} + +const { accordionTabs, ctas } = Astro.props +--- + +
+
+ Try it out + +
+ + +
+ { + accordionTabs.map((tab, index) => ( +
+ +
+ )) + } +
+ + +
+
+
+ + diff --git a/src/components/TryItOut/TryItOutAccordion.tsx b/src/components/TryItOut/TryItOutAccordion.tsx new file mode 100644 index 00000000000..7328daa63ab --- /dev/null +++ b/src/components/TryItOut/TryItOutAccordion.tsx @@ -0,0 +1,37 @@ +import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Typography } from "@chainlink/blocks" +import { activeAccordionIndex } from "~/stores/tryItOutStore.ts" +import styles from "./styles.module.css" + +interface AccordionTab { + title: string + text: string + codeSampleSrc: string +} + +interface TryItOutAccordionProps { + tabs: AccordionTab[] +} + +export const TryItOutAccordion = ({ tabs }: TryItOutAccordionProps) => { + const handleValueChange = (value: string) => { + if (value) { + activeAccordionIndex.set(parseInt(value, 10)) + } + } + + return ( + + {tabs.map((tab, idx) => ( + + + {tab.title}{" "} + + 0{idx + 1} + + + {tab.text} + + ))} + + ) +} diff --git a/src/components/TryItOut/styles.module.css b/src/components/TryItOut/styles.module.css new file mode 100644 index 00000000000..9aed11c8332 --- /dev/null +++ b/src/components/TryItOut/styles.module.css @@ -0,0 +1,124 @@ +.container { + background-color: var(--tertiary-foreground); + padding: var(--space-10x) var(--space-16x); + margin: 86px 0; +} + +.title { + margin-bottom: var(--space-8x); + color: var(--background); +} + +.secondaryBtn { + color: var(--muted-on-surface); +} + +.contentFooter { + display: flex; + gap: var(--space-6x); + margin-top: 55px; +} + +.content { + display: grid; + grid-template-columns: 1fr 1fr; + justify-content: space-between; + gap: var(--space-24x); +} + +.accordionItem { + border-bottom: none; + border-top: 1px solid var(--segment-button-foreground); + display: flex; + flex-direction: column; + + * { + transition: all 0.2s linear; + } +} + +.contentLeft { + display: flex; + flex-direction: column; + justify-content: center; +} + +.text { + color: var(--muted-more-foreground); +} + +.indicator { + color: var(--segment-button-foreground); +} + +.accordionTrigger { + color: var(--muted-more-foreground); + padding: var(--space-4x) 0; + border: none; + outline: none; + & p { + color: var(--muted-more-foreground); + } + + & svg { + display: none; + } + + & span { + word-wrap: normal; + } +} + +.image { + width: 100%; + max-height: 412px; + overflow-y: auto; + border-bottom: 1.5px solid var(--stepper-counter-pending-foreground); + border-radius: 6.317px; +} + +.accordionItem[data-state="open"] { + border-top: 2px solid var(--link); + + & .accordionTrigger { + color: var(--background); + } + & .indicator { + color: var(--link); + } +} + +.body { + max-width: var(--fullwidth-max-width); + width: 100%; + margin: 0 auto; +} + +.contentFooterMobile { + display: none; + gap: var(--space-6x); +} + +@media screen and (max-width: 425px) { + .contentFooterMobile { + flex-direction: column; + } +} + +@media screen and (max-width: 768px) { + .content { + grid-template-columns: 1fr; + gap: var(--space-8x); + } + + .title { + font-size: 28px; + } + .contentFooter { + display: none; + } + + .contentFooterMobile { + display: flex; + } +} diff --git a/src/pages/index.astro b/src/pages/index.astro index 8aba79a3fe7..3ea40693d4d 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -7,6 +7,7 @@ import * as CONFIG from "../config" import Demos from "~/components/Demos.astro" import { Typography } from "@chainlink/blocks" import LandingHero from "~/components/LandingHero/LandingHero.astro" +import TryItOut from "~/components/TryItOut/TryItOut.astro" import CommunityEvents from "~/components/CommunityEvents/CommunityEvents.astro" const formattedContentTitle = `${CONFIG.PAGE.titleFallback} | ${CONFIG.SITE.title}` @@ -18,7 +19,38 @@ const formattedContentTitle = `${CONFIG.PAGE.titleFallback} | ${CONFIG.SITE.titl
+
+ + +
diff --git a/src/stores/tryItOutStore.ts b/src/stores/tryItOutStore.ts new file mode 100644 index 00000000000..fe13f6662e9 --- /dev/null +++ b/src/stores/tryItOutStore.ts @@ -0,0 +1,3 @@ +import { atom } from "nanostores" + +export const activeAccordionIndex = atom(0)