Skip to content

Commit afd5580

Browse files
Feat/130 try it (#142)
* add component * styling * update try it out component * Update MegaMenu.tsx * wrap up tryit * add README * Update TryItOutAccordion.tsx * add dynamic code samples and accordian control * prerender code * Update CodeSampleReact.tsx * Update styles.module.css --------- Co-authored-by: Simone Cuomo <[email protected]>
1 parent 01c8eee commit afd5580

File tree

11 files changed

+399
-4
lines changed

11 files changed

+399
-4
lines changed

public/images/tryitout.png

118 KB
Loading

src/components/CodeSample/CodeSample.astro

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ export type Props = {
1010
showButtonOnly?: boolean
1111
optimize?: boolean
1212
runs?: number
13+
showButtons?: boolean
1314
}
14-
const { src, lang, showButtonOnly, optimize, runs } = Astro.props as Props
15+
const { src, lang, showButtonOnly, optimize, runs, showButtons = true } = Astro.props as Props
1516
1617
const data = (await fs.readFile(path.join(process.cwd(), "public", src), "utf-8")).toString()
1718
@@ -31,7 +32,7 @@ const remixUrl = `https://remix.ethereum.org/#url=https://docs.chain.link/${clea
3132

3233
{!showButtonOnly && <Prism code={data} lang={lang ?? "solidity"} />}
3334
{
34-
isSample && (
35+
isSample && showButtons && (
3536
<div class="remix-callout">
3637
<a href={remixUrl} target="_blank">
3738
Open in Remix

src/components/CodeSample/CodeSampleReact.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ export const CodeSampleReact: React.FC<CodeSampleReactProps> = ({ src, showButto
1313

1414
const isSolidityFile = src.match(/\.sol/)
1515
const isSample = isSolidityFile && (src.indexOf("samples/") === 0 || src.indexOf("/samples/") === 0)
16-
1716
if (!isSample || !showButtonOnly || !remixUrl) return null
1817

1918
return (

src/components/Header/Nav/ProductNavigation/Desktop/MegaMenu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export const megaMenuSections = {
138138
icon: creLogo,
139139
title: "Chainlink Runtime Environment (CRE)",
140140
description: "The global orchestration layer",
141-
link: "/",
141+
link: "/cre",
142142
},
143143
],
144144
},

src/components/LeftSidebar/leftSidebar.module.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
.navGroups {
1111
padding: 0 var(--space-10x) var(--space-10x) 0;
12+
height: calc(100vh - var(--space-16x) - var(--space-16x)); /* Subtract header and footer height */
1213

1314
overflow-y: auto;
1415
scrollbar-width: thin;

src/components/TryItOut/README.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# TryItOut Component
2+
3+
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.
4+
5+
## Usage
6+
7+
```astro
8+
<TryItOut
9+
accordionTabs={[
10+
{
11+
title: "Your Feature Title",
12+
text: "A brief description of what this feature does.",
13+
codeSampleSrc: "/samples/YourCodeFile.sol",
14+
},
15+
]}
16+
ctas={[
17+
{ text: "Get Started", href: "/getting-started", variant: "primary" },
18+
{ text: "Learn More", href: "/docs", variant: "secondary" },
19+
]}
20+
/>
21+
```
22+
23+
## Props
24+
25+
### `accordionTabs` (required)
26+
27+
A list of expandable sections that describe different features. Each tab needs:
28+
29+
- **title**: The heading text for the accordion item
30+
- **text**: The description that appears when the accordion is expanded
31+
- **codeSampleSrc**: The file path to the code sample for this specific tab (should point to a file in the `/samples/` folder)
32+
33+
**Example:**
34+
35+
```js
36+
;[
37+
{
38+
title: "Transfer Tokens",
39+
text: "Move tokens between different blockchains easily.",
40+
codeSampleSrc: "/samples/CCIP/TokenTransfer.sol",
41+
},
42+
{
43+
title: "Fetch Data",
44+
text: "Get real-time information from external sources.",
45+
codeSampleSrc: "/samples/DataFeeds/PriceFeed.sol",
46+
},
47+
]
48+
```
49+
50+
### `ctas` (optional)
51+
52+
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.
53+
54+
Each CTA object needs:
55+
56+
- **text**: The button text
57+
- **href**: The button link URL
58+
- **variant** (optional): Either "primary" or "secondary" (defaults to "primary")
59+
60+
**Example:**
61+
62+
```js
63+
;[
64+
{ text: "Get Started", href: "/getting-started", variant: "primary" },
65+
{ text: "View Docs", href: "/documentation", variant: "secondary" },
66+
]
67+
```
68+
69+
## How It Works
70+
71+
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.
72+
73+
### Technical Implementation
74+
75+
**Why we pre-render all code samples:**
76+
77+
All code samples are rendered at build time using the `<CodeSample>` 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:
78+
79+
1. **Astro components are build-time only** - The `<CodeSample>` component uses Astro's Prism integration which only runs during the build process, not at runtime
80+
2. **Proper syntax highlighting** - Pre-rendering ensures all code has proper syntax highlighting applied via Prism
81+
3. **Performance** - No runtime file reading or syntax highlighting processing; instant switching between code samples
82+
4. **Simplicity** - Avoids complex API endpoints or client-side file fetching
83+
84+
**Accessibility considerations:**
85+
86+
Inactive code samples are hidden from both visual users and assistive technology:
87+
88+
- `display: none` hides them visually
89+
- `aria-hidden="true"` ensures screen readers ignore hidden code blocks
90+
- Only the active code sample has `aria-hidden="false"`, making it visible to screen readers
91+
92+
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.
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
---
2+
import { buttonVariants, Typography } from "@chainlink/blocks"
3+
import styles from "./styles.module.css"
4+
import CodeSample from "../CodeSample/CodeSample.astro"
5+
import { TryItOutAccordion } from "./TryItOutAccordion"
6+
import { clsx } from "~/lib/clsx/clsx"
7+
8+
interface CTA {
9+
text: string
10+
href: string
11+
variant?: "primary" | "secondary"
12+
}
13+
14+
interface Props {
15+
accordionTabs: Array<{ title: string; text: string; codeSampleSrc: string }>
16+
ctas: CTA[]
17+
}
18+
19+
const { accordionTabs, ctas } = Astro.props
20+
---
21+
22+
<div class={styles.container}>
23+
<section class={styles.body}>
24+
<Typography variant="h2" className={styles.title}> Try it out </Typography>
25+
26+
<section class={styles.content}>
27+
<div class={styles.contentLeft}>
28+
<TryItOutAccordion client:load tabs={accordionTabs} />
29+
30+
<footer class={styles.contentFooter}>
31+
{
32+
ctas.map((cta) => (
33+
<a
34+
href={cta.href}
35+
class={clsx(
36+
buttonVariants({
37+
variant: cta.variant === "secondary" ? "tertiary" : "primary",
38+
size: "default",
39+
}),
40+
cta.variant === "secondary" && styles.secondaryBtn
41+
)}
42+
>
43+
{cta.text}
44+
</a>
45+
))
46+
}
47+
</footer>
48+
</div>
49+
50+
<section class={styles.image}>
51+
{
52+
accordionTabs.map((tab, index) => (
53+
<div
54+
class="code-sample-item"
55+
data-code-index={index}
56+
style={index === 0 ? "" : "display: none;"}
57+
aria-hidden={index === 0 ? "false" : "true"}
58+
>
59+
<CodeSample showButtons={false} src={tab.codeSampleSrc} />
60+
</div>
61+
))
62+
}
63+
</section>
64+
65+
<footer class={styles.contentFooterMobile}>
66+
{
67+
ctas.map((cta) => (
68+
<a
69+
href={cta.href}
70+
class={clsx(
71+
buttonVariants({
72+
variant: cta.variant === "secondary" ? "tertiary" : "primary",
73+
size: "default",
74+
}),
75+
cta.variant === "secondary" && styles.secondaryBtn
76+
)}
77+
>
78+
{cta.text}
79+
</a>
80+
))
81+
}
82+
</footer>
83+
</section>
84+
</section>
85+
</div>
86+
87+
<script>
88+
import { activeAccordionIndex } from "~/stores/tryItOutStore.ts"
89+
90+
// Subscribe to nano store changes
91+
activeAccordionIndex.subscribe((newIndex) => {
92+
// Hide all code samples and mark as hidden for screen readers
93+
const allCodeSamples = document.querySelectorAll(".code-sample-item")
94+
allCodeSamples.forEach((el) => {
95+
;(el as HTMLElement).style.display = "none"
96+
;(el as HTMLElement).setAttribute("aria-hidden", "true")
97+
})
98+
99+
// Show the active one and mark as visible for screen readers
100+
const activeCodeSample = document.querySelector(`[data-code-index="${newIndex}"]`)
101+
if (activeCodeSample) {
102+
;(activeCodeSample as HTMLElement).style.display = "block"
103+
;(activeCodeSample as HTMLElement).setAttribute("aria-hidden", "false")
104+
}
105+
})
106+
</script>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Typography } from "@chainlink/blocks"
2+
import { activeAccordionIndex } from "~/stores/tryItOutStore.ts"
3+
import styles from "./styles.module.css"
4+
5+
interface AccordionTab {
6+
title: string
7+
text: string
8+
codeSampleSrc: string
9+
}
10+
11+
interface TryItOutAccordionProps {
12+
tabs: AccordionTab[]
13+
}
14+
15+
export const TryItOutAccordion = ({ tabs }: TryItOutAccordionProps) => {
16+
const handleValueChange = (value: string) => {
17+
if (value) {
18+
activeAccordionIndex.set(parseInt(value, 10))
19+
}
20+
}
21+
22+
return (
23+
<Accordion collapsible type="single" defaultValue="0" onValueChange={handleValueChange}>
24+
{tabs.map((tab, idx) => (
25+
<AccordionItem key={idx} value={String(idx)} className={styles.accordionItem}>
26+
<AccordionTrigger className={styles.accordionTrigger}>
27+
{tab.title}{" "}
28+
<Typography variant="code" className={styles.indicator}>
29+
0{idx + 1}
30+
</Typography>
31+
</AccordionTrigger>
32+
<AccordionContent className={styles.text}>{tab.text}</AccordionContent>
33+
</AccordionItem>
34+
))}
35+
</Accordion>
36+
)
37+
}

0 commit comments

Comments
 (0)