Skip to content

Page tabs component #1780

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/images/tutorial-icons/foundry-icn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/tutorial-icons/hardhat-icn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/tutorial-icons/remix-icn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 21 additions & 6 deletions src/components/LeftSidebar/LeftSidebar.astro
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,24 @@ const removeSlashes = (url: string) => {
return sanitizedUrl
}

const currentPageMatch = removeSlashes(currentPage.slice(1))
// This function checks if the current page is a match for the main section or any of its subpages
// (e.g. /getting-started-hardhat is a subpage of /getting-started).
const isCurrentPageMatch = (sectionUrl: string, currentPage: string): boolean => {
const normalizedSectionUrl = removeSlashes(sectionUrl)
const normalizedCurrentPage = removeSlashes(currentPage.slice(1))

// Direct match (e.g., both "/getting-started")
if (normalizedCurrentPage === normalizedSectionUrl) {
return true
}

// Check for subpage match (e.g., currentPage is "/getting-started-hardhat" and sectionUrl is "/getting-started")
if (normalizedCurrentPage.startsWith(`${normalizedSectionUrl}-`)) {
return true
}

return false
}
---

<nav aria-labelledby="grid-left">
Expand All @@ -42,9 +59,7 @@ const currentPageMatch = removeSlashes(currentPage.slice(1))
sidebarSections.map((s: { parentSection: Sections; contents: SectionContent[]; section: Sections }) => (
<li aria-hidden={section === "global"} class={s.parentSection ? `parent-${s.parentSection}` : ""}>
<details
open={
!!flattenChildren(s.contents).filter((object) => removeSlashes(object.url) == currentPageMatch).length
}
open={!!flattenChildren(s.contents).filter((object) => isCurrentPageMatch(object.url, currentPage)).length}
>
<summary class="nav-group-title">{s.section}</summary>
<ul class="nav-group-entries">
Expand All @@ -55,7 +70,7 @@ const currentPageMatch = removeSlashes(currentPage.slice(1))
<a
class="nav-link"
href={`${Astro.site?.pathname}${child.url}`}
aria-current={currentPageMatch === removeSlashes(child.url) ? "page" : "false"}
aria-current={isCurrentPageMatch(child.url, currentPage) ? "page" : "false"}
>
<ActiveIcon />
{child.title}
Expand All @@ -67,7 +82,7 @@ const currentPageMatch = removeSlashes(currentPage.slice(1))
<a
class="nav-link nested"
href={`${Astro.site?.pathname}${childItem.url}`}
aria-current={`${currentPageMatch === removeSlashes(childItem.url) ? "page" : "false"}`}
aria-current={isCurrentPageMatch(childItem.url, currentPage) ? "page" : "false"}
>
<ActiveIcon />
{childItem.title}
Expand Down
99 changes: 99 additions & 0 deletions src/components/PageTabs.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
export interface Props {
pages: Array<{
name: string
url: string
icon?: string // icon is optional
}>
}

const { pages } = Astro.props as Props

const currentPath = Astro.url.pathname

const normalizeUrl = (url: string) => {
return url.trim().replace(/\/$/, "")
}

const isActive = (pageUrl: string) => {
const normalizedCurrentPath = normalizeUrl(currentPath)
const normalizedPageUrl = normalizeUrl(pageUrl)
return normalizedCurrentPath === normalizedPageUrl
}

const pageDetails = pages.filter((page): page is { name: string; url: string; icon?: string } => page.url !== undefined)
---

<div class="pages-table">
{
pageDetails.map((page) => (
<a href={page.url} class={`page-column ${isActive(page.url) ? "active" : ""}`}>
{page.icon && <img src={page.icon} alt={`${page.name} icon`} class="page-icon" />}
<div>{page.name}</div>
</a>
))
}
</div>

<style>
.pages-table {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 1rem;
margin-top: 1rem;
padding: 1rem;
}

.page-column {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
cursor: pointer;
border-bottom: 2px solid var(--gray-200, rgb(236, 237, 239));
color: var(--gray-500, rgb(133, 138, 149));
font-size: 1rem;
line-height: 24px;
margin-bottom: 16px;
padding: 9px 20px;
text-decoration: none;
-webkit-font-smoothing: antialiased;
box-sizing: border-box;
}

.page-column:hover:not(.active) {
color: var(--blue-700);
border-bottom-color: var(--blue-700);
}

.page-icon {
margin-right: 10px;
width: 23px;
height: 23px;
}

.page-column.active {
color: var(--blue-600, rgb(55, 91, 210));
border-bottom-color: var(--blue-600, rgb(55, 91, 210));
}

@media (max-width: 768px) {
.pages-table {
padding: 0.5rem;
}

.page-column {
padding: 9px 10px;
flex-direction: column;
}

.pages-table {
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
}

.page-icon {
margin-right: 0;
margin-bottom: 5px;
}
}
</style>
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ export { default as Icon } from "./Icon.astro"
export { default as ClickToZoom } from "./ClickToZoom.astro"
export { default as PackageManagerTabs } from "./Tabs/PackageManagerTabs.astro"
export { default as Accordion } from "./Quickstart/Accordion/Accordion.astro"
export { default as PageTabs } from "./PageTabs.astro"
6 changes: 1 addition & 5 deletions src/config/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,9 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = {
url: "data-streams",
},
{
title: "Getting Started (Remix IDE)",
title: "Getting Started",
url: "data-streams/getting-started",
},
{
title: "Getting Started (Hardhat CLI)",
url: "data-streams/getting-started-hardhat",
},
{
title: "Data Streams Feed IDs",
url: "data-streams/stream-ids",
Expand Down
19 changes: 17 additions & 2 deletions src/content/data-streams/getting-started-hardhat.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
section: dataStreams
date: Last Modified
title: "Getting Started with Chainlink Data Streams using the Hardhat CLI"
title: "Getting Started with Chainlink Data Streams (Hardhat CLI)"
metadata:
linkToWallet: true
excerpt: "Learn the basics for how to get data from Chainlink Data Streams."
Expand All @@ -12,9 +12,24 @@ whatsnext: {
}
---

import { Aside } from "@components"
import { Aside, PageTabs } from "@components"
import DataStreams from "@features/data-streams/common/DataStreams.astro"

<PageTabs
pages={[
{
name: "Remix",
url: "/data-streams/getting-started",
icon: "/images/tutorial-icons/remix-icn.png",
},
{
name: "Hardhat",
url: "/data-streams/getting-started-hardhat",
icon: "/images/tutorial-icons/hardhat-icn.png",
},
]}
/>

<DataStreams section="dsNotes" />

<DataStreams section="gettingStartedHardhat" />
19 changes: 17 additions & 2 deletions src/content/data-streams/getting-started.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
section: dataStreams
date: Last Modified
title: "Getting Started with Chainlink Data Streams"
title: "Getting Started with Chainlink Data Streams (Remix)"
metadata:
linkToWallet: true
excerpt: "Learn the basics for how to get data from Chainlink Data Streams."
Expand All @@ -12,9 +12,24 @@ whatsnext: {
}
---

import { Aside } from "@components"
import { Aside, PageTabs } from "@components"
import DataStreams from "@features/data-streams/common/DataStreams.astro"

<PageTabs
pages={[
{
name: "Remix",
url: "/data-streams/getting-started",
icon: "/images/tutorial-icons/remix-icn.png",
},
{
name: "Hardhat",
url: "/data-streams/getting-started-hardhat",
icon: "/images/tutorial-icons/hardhat-icn.png",
},
]}
/>

<DataStreams section="dsNotes" />

<DataStreams section="gettingStarted" />
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ import { Aside } from "@components"

<Aside type="caution" title="Onchain data verification">
In this tutorial, you decode the `FullReport` payload to extract the report data and log it to the terminal. In a
production environment, verify the data onchain to ensure the integrity and authenticity of the report. See the [Onchain data verification](/data-streams/reference/streams-direct-onchain-verification) guide for details.
production environment, verify the data onchain to ensure the integrity and authenticity of the report. See the
[Onchain data verification](/data-streams/reference/streams-direct-onchain-verification) guide for details.
</Aside>
2 changes: 1 addition & 1 deletion src/features/data-streams/common/gettingStarted.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CodeSample, CopyText, ClickToZoom } from "@components"
import DataStreams from "@features/data-streams/common/DataStreams.astro"

This guide shows you how to read data from a Data Streams feed, validate the answer, and store the answer onchain. This guide uses the [Remix IDE](https://remix-project.org/) so you can complete these steps in a web-based development environment. If you prefer to complete these steps using terminal commands, read the [Getting Started - Hardhat CLI](/data-streams/getting-started-hardhat) guide instead.
This guide shows you how to read data from a Data Streams feed, verify the answer onchain, and store it.

This example uses the _[Streams Trade](/data-streams#streams-trade-using-data-streams-with-chainlink-automation) implementation_, with a [Chainlink Automation Log Trigger](/chainlink-automation/guides/log-trigger) to check for events that require data. For this example, the log trigger comes from a simple emitter contract. Chainlink Automation then uses `StreamsLookup` to retrieve a signed report from the Data Streams Aggregation Network, return the data in a callback, and run the [`performUpkeep` function](/chainlink-automation/reference/automation-interfaces#performupkeep-function-for-log-triggers) on your registered upkeep contract. The `performUpkeep` function calls the `verify` function on the verifier contract.

Expand Down
4 changes: 2 additions & 2 deletions src/features/data-streams/common/gettingStartedHardhat.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Aside, CodeSample, CopyText } from "@components"
import DataStreams from "@features/data-streams/common/DataStreams.astro"

This guide shows you how to read data from a Data Streams feed, verify the answer onchain, and store it. This CLI guide uses the [Hardhat](https://hardhat.org/) development environment so you can complete these steps using terminal commands rather than the web-based Remix IDE. If you prefer Remix or are unfamiliar with how to run terminal commands, read the [Getting Started - Remix IDE](/data-streams/getting-started) guide instead.
This guide shows you how to read data from a Data Streams feed, verify the answer onchain, and store it.

This example uses the _[Streams Trade](/data-streams#streams-trade-using-data-streams-with-chainlink-automation) implementation_, with a [Chainlink Automation Log Trigger](/chainlink-automation/guides/log-trigger) to check for events that require data. For this example, the log trigger comes from a simple emitter contract. Chainlink Automation then uses `StreamsLookup` to retrieve a signed report from the Data Streams Aggregation Network, return the data in a callback, and run the [`performUpkeep` function](/chainlink-automation/reference/automation-interfaces#performupkeep-function-for-log-triggers) on your registered upkeep contract. The `performUpkeep` function calls the `verify` function on the verifier contract.

Note: If you want to learn how to use the _[Streams Direct](/data-streams#streams-direct-using-data-streams-with-your-own-bot) implementation_ of Data Streams, refer to the [Fetch and decode reports via a REST API](/data-streams/tutorials/streams-direct-api) guide or the [Stream and decode reports via WebSocket](/data-streams/tutorials/streams-direct-ws) guide.
Note: To learn how to use the _[Streams Direct](/data-streams#streams-direct-using-data-streams-with-your-own-bot) implementation_ of Data Streams, see the [Fetch and decode reports via a REST API](/data-streams/tutorials/streams-direct-api) guide or the [Stream and decode reports via WebSocket](/data-streams/tutorials/streams-direct-ws) guide.

<DataStreams section="asideDisclaimer" />

Expand Down