Skip to content

Commit f8ebaa5

Browse files
[Grace's branch] content/link updates, dynamic buttons (#225)
* content/link updates, dynamic buttons * fix: correct formatting and fix tests * fix: update import path for AggregatorV3Interface * remove package.json and package-lock.json from the PR --------- Co-authored-by: Grace Fletcher <grace.fletcher@smartcontract.com>
1 parent d8c52df commit f8ebaa5

File tree

8 files changed

+250
-46
lines changed

8 files changed

+250
-46
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { cre } from "@chainlink/cre-sdk"
2+
3+
cre.handler(
4+
cron.trigger({ schedule: "0 */5 * * *" }), // Every 5 minutes
5+
(runtime) => {
6+
// Fetch data from API
7+
const price = httpClient.get(url).result()
8+
9+
// Read from EVM blockchain
10+
const threshold = evmClient.read(contract).result()
11+
12+
// Make any computation
13+
const shouldUpdate = price > threshold
14+
15+
// Write result onchain
16+
return evmClient.write(contract, price).result()
17+
}
18+
)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
2+
3+
contract SVRConsumer {
4+
AggregatorV3Interface internal svrFeed;
5+
6+
constructor(
7+
address _svrFeedAddress
8+
) {
9+
svrFeed = AggregatorV3Interface(_svrFeedAddress);
10+
}
11+
12+
function getLatestPrice() public view returns (int256) {
13+
(, /* uint80 roundID */
14+
int256 price, /* uint256 startedAt */
15+
/* uint256 timeStamp */
16+
/* uint80 answeredInRound */,,
17+
) = svrFeed.latestRoundData();
18+
return price;
19+
}
20+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { createClient, decodeReport, LogLevel, getReportVersion, formatReport } from "@chainlink/data-streams-sdk"
2+
import "dotenv/config"
3+
4+
async function main() {
5+
if (process.argv.length < 3) {
6+
console.error("Please provide a feed ID as an argument")
7+
console.error("Example: npx tsx singleStream.ts 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782")
8+
process.exit(1)
9+
}
10+
11+
const feedId = process.argv[2]
12+
const version = getReportVersion(feedId)
13+
14+
try {
15+
const config = {
16+
apiKey: process.env.API_KEY || "YOUR_API_KEY",
17+
userSecret: process.env.USER_SECRET || "YOUR_USER_SECRET",
18+
endpoint: "https://api.testnet-dataengine.chain.link",
19+
wsEndpoint: "wss://ws.testnet-dataengine.chain.link",
20+
// Comment to disable SDK logging:
21+
logging: {
22+
logger: console,
23+
logLevel: LogLevel.INFO,
24+
},
25+
}
26+
27+
const client = createClient(config)
28+
console.log(`\nFetching latest report for feed ${feedId} (${version})...\n`)
29+
30+
// Get raw report data
31+
const report = await client.getLatestReport(feedId)
32+
console.log(`Raw Report Blob: ${report.fullReport}`)
33+
34+
// Decode the report
35+
const decodedData = decodeReport(report.fullReport, report.feedID)
36+
37+
// Combine decoded data with report metadata
38+
const decodedReport = {
39+
...decodedData,
40+
feedID: report.feedID,
41+
validFromTimestamp: report.validFromTimestamp,
42+
observationsTimestamp: report.observationsTimestamp,
43+
}
44+
console.log(formatReport(decodedReport, version))
45+
} catch (error) {
46+
if (error instanceof Error) {
47+
console.error("Error:", error.message)
48+
} else {
49+
console.error("Unknown error:", error)
50+
}
51+
process.exit(1)
52+
}
53+
}
54+
55+
main()

src/components/LandingHero/LandingHero.astro

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import styles from "./landingHero.module.css"
66

77
<section class={styles.wrapper}>
88
<div class={styles.content}>
9-
<Typography variant="h1" className={styles.title}>Explore docs & resources</Typography>
9+
<div className={styles.heroText}>
10+
<Typography variant="h1" className={styles.title}> Build on the Chainlink Platform </Typography>
11+
</div>
12+
1013
<section class={styles.menu}>
1114
<MegaMenu client:only="react" />
1215
</section>

src/components/LandingHero/landingHero.module.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@
1616
.title {
1717
font-weight: 400;
1818
margin-bottom: var(--space-8x);
19+
white-space: nowrap;
20+
}
21+
22+
.title br {
23+
display: none;
24+
}
25+
26+
@media (min-width: 768px) {
27+
.title br {
28+
display: inline;
29+
}
1930
}
2031

2132
.wrapper {
@@ -46,6 +57,11 @@
4657
height: 100%;
4758
}
4859

60+
.heroText {
61+
max-width: 880px; /* wide enough for one line */
62+
padding-right: var(--space-16x); /* optical buffer from seam */
63+
}
64+
4965
@media screen and (max-width: 991px) {
5066
.wrapper {
5167
background-color: transparent;

src/components/TryItOut/TryItOut.astro

Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,18 @@ interface CTA {
1111
variant?: "primary" | "secondary"
1212
}
1313
14+
interface Tab {
15+
title: string
16+
text: string
17+
codeSampleSrc: string
18+
ctas?: CTA[]
19+
}
20+
1421
interface Props {
15-
accordionTabs: Array<{ title: string; text: string; codeSampleSrc: string }>
16-
ctas: CTA[]
22+
accordionTabs: Tab[]
1723
}
1824
19-
const { accordionTabs, ctas } = Astro.props
25+
const { accordionTabs } = Astro.props
2026
---
2127

2228
<div class={styles.container}>
@@ -27,21 +33,31 @@ const { accordionTabs, ctas } = Astro.props
2733
<div class={styles.contentLeft}>
2834
<TryItOutAccordion client:load tabs={accordionTabs} />
2935

36+
{/* Desktop CTAs (dynamic per active tab) */}
3037
<footer class={styles.contentFooter}>
3138
{
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-
)}
39+
accordionTabs.map((tab, index) => (
40+
<div
41+
class="cta-item"
42+
data-cta-index={index}
43+
style={index === 0 ? "" : "display: none;"}
44+
aria-hidden={index === 0 ? "false" : "true"}
4245
>
43-
{cta.text}
44-
</a>
46+
{(tab.ctas ?? []).map((cta) => (
47+
<a
48+
href={cta.href}
49+
class={clsx(
50+
buttonVariants({
51+
variant: cta.variant === "secondary" ? "tertiary" : "primary",
52+
size: "default",
53+
}),
54+
cta.variant === "secondary" && styles.secondaryBtn
55+
)}
56+
>
57+
{cta.text}
58+
</a>
59+
))}
60+
</div>
4561
))
4662
}
4763
</footer>
@@ -62,21 +78,31 @@ const { accordionTabs, ctas } = Astro.props
6278
}
6379
</section>
6480

81+
{/* Mobile CTAs (dynamic per active tab) */}
6582
<footer class={styles.contentFooterMobile}>
6683
{
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-
)}
84+
accordionTabs.map((tab, index) => (
85+
<div
86+
class="cta-item-mobile"
87+
data-cta-index={index}
88+
style={index === 0 ? "" : "display: none;"}
89+
aria-hidden={index === 0 ? "false" : "true"}
7790
>
78-
{cta.text}
79-
</a>
91+
{(tab.ctas ?? []).map((cta) => (
92+
<a
93+
href={cta.href}
94+
class={clsx(
95+
buttonVariants({
96+
variant: cta.variant === "secondary" ? "tertiary" : "primary",
97+
size: "default",
98+
}),
99+
cta.variant === "secondary" && styles.secondaryBtn
100+
)}
101+
>
102+
{cta.text}
103+
</a>
104+
))}
105+
</div>
80106
))
81107
}
82108
</footer>
@@ -102,5 +128,20 @@ const { accordionTabs, ctas } = Astro.props
102128
;(activeCodeSample as HTMLElement).style.display = "block"
103129
;(activeCodeSample as HTMLElement).setAttribute("aria-hidden", "false")
104130
}
131+
132+
// Hide all CTA groups
133+
const allCtas = document.querySelectorAll("[data-cta-index]")
134+
allCtas.forEach((el) => {
135+
;(el as HTMLElement).style.display = "none"
136+
;(el as HTMLElement).setAttribute("aria-hidden", "true")
137+
})
138+
139+
// Show the active CTA group(s)
140+
// IMPORTANT: remove inline display so CSS (flex) can apply
141+
const activeCtas = document.querySelectorAll(`[data-cta-index="${newIndex}"]`)
142+
activeCtas.forEach((el) => {
143+
;(el as HTMLElement).style.removeProperty("display") // ✅ key fix
144+
;(el as HTMLElement).setAttribute("aria-hidden", "false")
145+
})
105146
})
106147
</script>

src/components/TryItOut/styles.module.css

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,35 @@
1919
margin-top: 55px;
2020
}
2121

22+
/* NEW: CTA group wrapper should behave like the old footer (buttons as direct children) */
23+
.contentFooter :global(.cta-item),
24+
.contentFooterMobile :global(.cta-item-mobile) {
25+
display: flex;
26+
gap: var(--space-6x); /* match footer spacing */
27+
align-items: center;
28+
}
29+
30+
/* Optional: ensure hidden groups don't occupy space (extra-safe) */
31+
.contentFooter :global(.cta-item[aria-hidden="true"]),
32+
.contentFooterMobile :global(.cta-item-mobile[aria-hidden="true"]) {
33+
display: none;
34+
}
35+
36+
/* prevent CTA row reflow across tabs */
37+
.contentFooter,
38+
.contentFooterMobile {
39+
min-height: 56px; /* keeps vertical stability too */
40+
}
41+
42+
/* apply to actual anchor buttons inside the active CTA group */
43+
.contentFooter :global(.cta-item) a,
44+
.contentFooterMobile :global(.cta-item-mobile) a {
45+
width: 280px; /* tune */
46+
justify-content: center; /* centers text inside button */
47+
text-align: center;
48+
white-space: nowrap; /* avoid wrapping */
49+
}
50+
2251
.content {
2352
display: grid;
2453
grid-template-columns: 1fr 1fr;

src/pages/index.astro

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,36 +24,58 @@ const formattedContentTitle = `${CONFIG.PAGE.titleFallback} | ${CONFIG.SITE.titl
2424
<TryItOut
2525
accordionTabs={[
2626
{
27-
title: "Transfer Tokens Between Chains",
28-
text: "Use Chainlink CCIP to transfer tokens from a smart contract to an account on a different blockchain.",
29-
codeSampleSrc: "/samples/ChainlinkFunctions/FunctionsConsumerDecoder.sol",
27+
title: "Build an Orchestrated Workflow",
28+
text: "Use Chainlink CRE to build, test, and deploy advanced workflows for institutional-grade smart contracts without needing to manage new infrastructure or complex onchain logic.",
29+
codeSampleSrc: "/samples/CRE/basic-functionality.ts",
30+
ctas: [
31+
{ text: "Get started with CRE", href: "/cre/getting-started/overview", variant: "primary" },
32+
{ text: "Create CRE account", href: "https://cre.chain.link/signup", variant: "secondary" },
33+
],
3034
},
3135
{
32-
title: "Leverage MVR feeds",
33-
text: "Use Multiple-Variable Response (MVR) feeds data in your consumer contracts on EVM chains using Solidity.",
34-
codeSampleSrc: "/samples/ChainlinkFunctions/AutomatedFunctionsConsumerExample.sol",
36+
title: "Transfer Tokens Between Chains",
37+
text: "Use Chainlink CCIP to transfer CCIP-BnM tokens from a contract on Avalanche Fuji to an account on Ethereum Sepolia",
38+
codeSampleSrc: "/samples/CCIP/TokenTransferor.sol",
39+
ctas: [
40+
{
41+
text: "Open in Remix",
42+
href: "https://remix.ethereum.org/#url=https://docs.chain.link/samples/CCIP/TokenTransferor.sol&autoCompile=true",
43+
variant: "primary",
44+
},
45+
{ text: "Read Tutorial", href: "/ccip/tutorials/evm/transfer-tokens-from-contract", variant: "secondary" },
46+
],
3547
},
3648
{
37-
title: "Fetch and Decode Real World Asset Streams",
38-
text: "Use the Data Streams SDK for Go/Rust to fetch and decode reports from the Data Streams Aggregation Network.",
39-
codeSampleSrc: "/samples/ChainlinkFunctions/GettingStartedFunctionsConsumer.sol",
49+
title: "Recapture Oracle Extractable Value",
50+
text: "Use Chainlink Smart Value Recapture (SVR) Feeds to backrun new prices with liquidation transactions and compete for profit.",
51+
codeSampleSrc: "/samples/DataFeeds/SVR/import-aggregatorV3.sol",
52+
ctas: [
53+
{ text: "Integrate SVR Feeds", href: "/data-feeds/svr-feeds", variant: "primary" },
54+
{
55+
text: "Find SVR-enabled Feeds",
56+
href: "/data-feeds/price-feeds/addresses",
57+
variant: "secondary",
58+
},
59+
],
4060
},
4161
{
42-
title: "Automate your Functions",
43-
text: "Use Chainlink Automation to trigger the same functions regularly, such as fetching weather data daily or fetching an asset price on every block.",
44-
codeSampleSrc: "/samples/ChainlinkFunctions/AutomatedFunctionsConsumerExample.sol",
62+
title: "Access Real-Time Data for Traditional Financial Markets",
63+
text: "Use the Data Streams SDK in TypeScript/Go/Rust to fetch and decode reports from the Data Streams Aggregation Network.",
64+
codeSampleSrc: "/samples/DataStreams/FetchSingleStream.ts",
65+
ctas: [
66+
{
67+
text: "Download the SDK",
68+
href: "https://github.com/smartcontractkit/data-streams-sdk",
69+
variant: "primary",
70+
},
71+
{ text: "Read Tutorial", href: "/data-streams/tutorials/ts-sdk-fetch", variant: "secondary" },
72+
],
4573
},
4674
]}
47-
ctas={[
48-
{ text: "Create CRE account", href: "#", variant: "primary" },
49-
{ text: "Get the SDK", href: "#", variant: "secondary" },
50-
]}
5175
/>
5276

5377
<div class="wrapper">
5478
<Demos />
55-
56-
<TechnicalStandards />
5779
</div>
5880

5981
<CommunityEvents />

0 commit comments

Comments
 (0)