diff --git a/src/components/Resource/README.md b/src/components/Resource/README.md new file mode 100644 index 00000000000..e2f6f4d8b44 --- /dev/null +++ b/src/components/Resource/README.md @@ -0,0 +1,106 @@ +# ResourceGrid + +## What it does + +This component displays a grid of resource cards. Each card can represent either an article or a video, with an optional image, title, description, and link. Article cards show a "Read the full article" footer with an arrow. + +## How to use it + +1. Import the component in your Astro layout or page: + +```astro +import ResourceGrid from "~/components/Resource/ResourceGrid.astro" import type {ResourceItem} from "~/components/Resource/ResourceGrid.astro" +``` + +2. (Optional) If you want to use imported images, import them: + +```astro +import myImage from "~/assets/images/my-image.png" +``` + +3. Create an array of resources with the information for each resource card + +4. Add the component to your page and pass in the resources: + +```astro + +``` + +## Example + +Here's a complete example showing how to use the component: + +```astro +--- +import ResourceGrid from "~/components/Resource/ResourceGrid.astro" +import type { ResourceItem } from "~/components/Resource/ResourceGrid.astro" +import tokenPoolImage from "~/assets/images/token-pool.png" + +const resources: ResourceItem[] = [ + { + image: tokenPoolImage, + imageAlt: "Token Pool illustration", + label: "Token Pool Types", + description: + "Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs.", + link: "/resources/token-pool-types", + type: "article", + }, + { + label: "Getting Started with CCIP", + description: + "Learn how to build cross-chain applications using Chainlink CCIP in this comprehensive video tutorial.", + link: "https://youtube.com/watch?v=example", + type: "video", + }, + { + image: "/images/cross-chain-messaging.png", + imageAlt: "Cross-chain messaging diagram", + label: "Understanding Cross-Chain Messaging", + description: "A deep dive into how cross-chain messaging works and how to implement it in your smart contracts.", + link: "/resources/cross-chain-messaging", + type: "article", + }, +] +--- + + +``` + +## What you need to provide + +Each item in your `resources` array needs these fields: + +| Field | Required? | What it is | Example | +| --------------- | --------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------- | +| **label** | Yes | The title of the resource | `"Token Pool Types"` | +| **link** | Yes | Where the card should link to (can be internal or external) | `"/resources/token-pool-types"` or `"https://youtube.com/..."` | +| **description** | Yes | A description explaining what the resource covers | `"Explore the various token pool types..."` | +| **type** | Yes | The type of resource - either `"article"` or `"video"` | `"article"` | +| **image** | No | Either an imported image or a path string | `myImage` (imported) or `"/images/token-pool.png"` (string path) | +| **imageAlt** | No | Description of the image for accessibility (required if image is provided) | `"Token Pool illustration"` | + +## Where to put images + +Images are optional for resource cards. You have two options: + +### Option 1: Import images (recommended for images in your project) + +1. Place your image file in the `src/assets/images/` directory +2. Import it at the top of your file: + ```astro + import myImage from "~/assets/images/my-image.png" + ``` +3. Use the imported variable in your resource object + +### Option 2: Use a path string (for public directory or external images) + +1. Place your image file in the `/public/images/` directory +2. Reference it with the full path starting with `/images/` + +Both approaches work! Use imported images for better optimization, or use path strings for simplicity. + +## Resource types + +- **article**: Displays "Read the full article" footer with an arrow icon +- **video**: No special footer (just the card with title and description) diff --git a/src/components/Resource/ResourceCard.astro b/src/components/Resource/ResourceCard.astro new file mode 100644 index 00000000000..e3ef42de9d4 --- /dev/null +++ b/src/components/Resource/ResourceCard.astro @@ -0,0 +1,47 @@ +--- +import { Typography, SvgArrowRight2 } from "@chainlink/blocks" +import type { ImageMetadata } from "astro" +import styles from "./ResourceCard.module.css" + +interface Props { + image?: string | ImageMetadata + imageAlt?: string + label: string + link: string + description: string + type: "article" | "video" +} + +const { image, imageAlt, label, link, description, type } = Astro.props + +const imageSrc = typeof image === "string" ? image : image?.src +--- + + + { + imageSrc && ( +
+ {imageAlt} +
+ ) + } +
+ {label} + + {description} + +
+ { + type === "article" && ( +
+ Read the full article + +
+ ) + } +
diff --git a/src/components/Resource/ResourceCard.module.css b/src/components/Resource/ResourceCard.module.css new file mode 100644 index 00000000000..475a298cbad --- /dev/null +++ b/src/components/Resource/ResourceCard.module.css @@ -0,0 +1,79 @@ +.card { + display: flex; + flex-direction: column; + background: var(--color-background); + padding: var(--space-6x); + gap: var(--space-4x); + border-right: 1px solid var(--border); + border-bottom: 1px solid var(--border); + text-decoration: none; + transition: background-color 0.2s; + min-height: 329px; + cursor: default; +} + +.card:nth-child(-n + 3) { + border-top: 1px solid var(--border); +} + +.card:hover { + background-color: var(--muted); +} + +.imageWrapper { + width: 100%; + aspect-ratio: 16 / 9; + overflow: hidden; + border-radius: var(--space-2x); +} + +.image { + width: 100%; + height: 100%; + object-fit: cover; +} + +.content { + display: flex; + flex-direction: column; + flex: 1; +} + +.cardLabel { + font-size: 16px; + font-weight: 525; + color: var(--foreground); + margin-bottom: var(--space-2x); +} + +.cardFooter { + display: flex; + align-items: center; + width: 100%; + gap: var(--space-2x); + margin-top: var(--space-4x); +} + +.footerText { + font-size: 14px; + color: var(--color-text-secondary); +} +@media screen and (max-width: 1024px) { + .card:nth-child(-n + 3) { + border-top: none; + } + + .card:nth-child(-n + 2) { + border-top: 1px solid var(--border); + } +} + +@media screen and (max-width: 768px) { + .card:nth-child(n) { + border-top: none; + } + + .card:nth-child(1) { + border-top: 1px solid var(--border); + } +} diff --git a/src/components/Resource/ResourceGrid.astro b/src/components/Resource/ResourceGrid.astro new file mode 100644 index 00000000000..1ec37d2aac1 --- /dev/null +++ b/src/components/Resource/ResourceGrid.astro @@ -0,0 +1,24 @@ +--- +import type { ImageMetadata } from "astro" +import ResourceCard from "./ResourceCard.astro" +import styles from "./ResourceGrid.module.css" + +export interface ResourceItem { + image?: string | ImageMetadata + imageAlt?: string + label: string + link: string + description: string + type: "article" | "video" +} + +interface Props { + resources: ResourceItem[] +} + +const { resources } = Astro.props +--- + +
+ {resources.map((resource) => )} +
diff --git a/src/components/Resource/ResourceGrid.module.css b/src/components/Resource/ResourceGrid.module.css new file mode 100644 index 00000000000..02cb548eeb9 --- /dev/null +++ b/src/components/Resource/ResourceGrid.module.css @@ -0,0 +1,17 @@ +.grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + border-left: 1px solid var(--border); +} + +@media (max-width: 1024px) { + .grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 768px) { + .grid { + grid-template-columns: 1fr; + } +} diff --git a/src/components/Resource/ResourceSection.astro b/src/components/Resource/ResourceSection.astro new file mode 100644 index 00000000000..148f2b2213d --- /dev/null +++ b/src/components/Resource/ResourceSection.astro @@ -0,0 +1,23 @@ +--- +import { Typography } from "@chainlink/blocks" +import ResourceGrid from "./ResourceGrid.astro" +import type { ResourceItem } from "./ResourceGrid.astro" +import styles from "./ResourceSection.module.css" + +interface Props { + title: string + resources: ResourceItem[] +} + +const { title, resources } = Astro.props +--- + +
+ {title} + +
diff --git a/src/components/Resource/ResourceSection.module.css b/src/components/Resource/ResourceSection.module.css new file mode 100644 index 00000000000..13896ba6e6c --- /dev/null +++ b/src/components/Resource/ResourceSection.module.css @@ -0,0 +1,6 @@ +.section { + display: flex; + flex-direction: column; + gap: var(--space-8x); + margin: 56px 0; +} diff --git a/src/components/TabGrid/TabGrid.tsx b/src/components/TabGrid/TabGrid.tsx index 6e85ec3cfa6..ab4962bc6e8 100644 --- a/src/components/TabGrid/TabGrid.tsx +++ b/src/components/TabGrid/TabGrid.tsx @@ -18,7 +18,14 @@ export const TabGrid = ({ tabs, header, columns = 3 }: TabGridProps) => { return (
- {header} + + {header} + {tabs.map((tab) => ( diff --git a/src/layouts/DocsV3Layout/DocsV3Layout.astro b/src/layouts/DocsV3Layout/DocsV3Layout.astro index d9377a1ee8b..e22c08c265b 100644 --- a/src/layouts/DocsV3Layout/DocsV3Layout.astro +++ b/src/layouts/DocsV3Layout/DocsV3Layout.astro @@ -8,6 +8,7 @@ import LeftSidebar from "~/components/LeftSidebar/LeftSidebar.astro" import PageContent from "~/components/PageContent/PageContent.astro" import { TabGrid } from "~/components/TabGrid/TabGrid" import LayoutHero from "~/components/LayoutHero/LayoutHero.astro" +import ResourceSection from "~/components/Resource/ResourceSection.astro" import MediaSection from "~/components/MediaSection/MediaSection.astro" import QuickLinkCard from "~/components/QuickLinkCard/QuickLinkCard.astro" import { @@ -40,6 +41,31 @@ const currentPage = new URL(Astro.request.url).pathname const includeLinkToWalletScript = !!Astro.props.frontmatter.metadata?.linkToWallet +// Example resources data +const exampleResources = [ + { + label: "Token Pool Types", + description: + "Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs. Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs...", + link: "/resources/token-pool-types", + type: "article", + }, + { + label: "Token Pool Types", + description: + "Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs. Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs...", + link: "/resources/token-pool-types", + type: "article", + }, + { + label: "Token Pool Types", + description: + "Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs. Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs...", + link: "/resources/token-pool-types", + type: "article", + }, +] + // Example tutorial data const exampleTutorials = [ { @@ -188,6 +214,8 @@ const quickLinks = [ ]} image="/images/ccip/ccip-hero.png" /> + +