-
Notifications
You must be signed in to change notification settings - Fork 308
chore(dev-hub) Component: Integration Card #3176
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
Changes from 3 commits
6f0f8dd
5bf4f17
d61e9a2
e5d2301
795ceba
5233525
2b05b44
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,59 @@ | ||
| import { Lightning } from "@phosphor-icons/react/dist/ssr"; | ||
|
|
||
| import styles from "./index.module.scss"; | ||
| import { ProductCard } from "../../ProductCard"; | ||
|
|
||
| export const Homepage = () => { | ||
| return ( | ||
| <div className={styles.landing}> | ||
| <h2>Homepage Landing Page</h2> | ||
| <div className={styles.cards}> | ||
| <ProductCard | ||
| title="Pyth Pro" | ||
| description="Subscription-based price data for institutions and advanced use cases." | ||
| features={[ | ||
| { label: "Ultra-low latency", icon: <Lightning size={12.5} /> }, | ||
| { | ||
| label: "Crypto, Equities & Indexes", | ||
| icon: <Lightning size={12.5} />, | ||
| }, | ||
| { | ||
| label: "Customizable channels and latency", | ||
| icon: <Lightning size={12.5} />, | ||
| }, | ||
| { label: "Dedicated support", icon: <Lightning size={12.5} /> }, | ||
| ]} | ||
| quickLinks={[ | ||
| { | ||
| label: "Get Pyth Pro Access Token", | ||
| href: "/docs/price-feeds/v2/acquire-an-access-token", | ||
| }, | ||
| { label: "Browse Supported Feeds", href: "/docs/price-feeds" }, | ||
| { label: "Error Codes", href: "/docs/price-feeds" }, | ||
| ]} | ||
| buttonLabel="Get started" | ||
| buttonHref="/docs/price-feeds" | ||
| /> | ||
| <ProductCard | ||
| title="Entropy" | ||
| description="Generate verifiable random numbers on-chain using Pyth's entropy service for your smart contracts." | ||
| features={[ | ||
| { label: "On-chain randomness", icon: <Lightning size={12.5} /> }, | ||
| { label: "Verifiable results", icon: <Lightning size={12.5} /> }, | ||
| { label: "Multiple chains", icon: <Lightning size={12.5} /> }, | ||
| ]} | ||
| quickLinks={[ | ||
| { | ||
| label: "Getting Started", | ||
| href: "/docs/entropy/create-your-first-entropy-app", | ||
| }, | ||
| { label: "Protocol Design", href: "/docs/entropy/protocol-design" }, | ||
| { label: "Examples", href: "/docs/entropy/examples" }, | ||
| ]} | ||
| buttonLabel="Get started" | ||
| buttonHref="/docs/entropy" | ||
| /> | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,203 @@ | ||
| @use "@pythnetwork/component-library/theme"; | ||
|
|
||
| .card { | ||
| flex: 1; | ||
| padding: theme.spacing(6); | ||
| border: 1px solid var(--color-fd-border); | ||
| border-radius: theme.border-radius("3xl"); | ||
| background-color: var(--color-fd-card); | ||
| box-shadow: 0 1px 2px 0 rgb(0 0 0 / 5%); | ||
| } | ||
|
|
||
| .content { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 2rem; // 32px | ||
| height: 100%; | ||
| flex: 1; | ||
| overflow: visible; | ||
| } | ||
|
|
||
| .mainContent { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 3rem; | ||
| padding-top: 0; | ||
| padding-bottom: 0; | ||
| flex: 1; | ||
| overflow: visible; | ||
| } | ||
|
|
||
| .header { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 0.75rem; // 12px | ||
| min-height: 7rem; // 88px - fixed height to keep FEATURES at consistent position | ||
| height: 7rem; // 88px - fixed height | ||
| } | ||
|
|
||
| .decorativeIcon { | ||
aditya520 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| position: absolute; | ||
| right: 1.5rem; // 24px from right | ||
| top: 1.5rem; | ||
| pointer-events: none; | ||
| z-index: 0; | ||
| } | ||
|
|
||
| .barChart { | ||
aditya520 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| position: relative; | ||
| width: 30px; // Space for all bars | ||
| height: 32px; | ||
| } | ||
|
|
||
| .bar { | ||
| position: absolute; | ||
| width: 3px; | ||
| border-radius: 1.5px; | ||
| } | ||
|
|
||
| .title { | ||
| margin: 0; | ||
| font-size: 1.875rem; // 30px | ||
| font-weight: 600; | ||
| line-height: 1; // 30px | ||
| letter-spacing: -0.03em; // -0.9px | ||
| color: var(--color-fd-foreground); | ||
| white-space: nowrap; | ||
| overflow: visble; | ||
aditya520 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| text-overflow: ellipsis; | ||
| flex-shrink: 0; | ||
| } | ||
|
|
||
| .description { | ||
| margin: 0; | ||
| font-size: 1rem; // 16px | ||
| font-weight: 400; | ||
| line-height: 1.65; | ||
| letter-spacing: -0.01em; // -0.16px | ||
alexcambose marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| color: var(--color-fd-foreground); | ||
| opacity: 0.9; | ||
| overflow: visible; | ||
| display: -webkit-box; | ||
| -webkit-line-clamp: 3; | ||
| line-clamp: 3; | ||
| -webkit-box-orient: vertical; | ||
| flex: 1; | ||
aditya520 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| .featuresSection { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 1.5rem; // 24px | ||
| min-height: 12rem; | ||
| max-height: 12rem; | ||
| overflow: visible; | ||
| } | ||
|
|
||
| .quickLinksSection { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 1.5rem; | ||
| } | ||
|
|
||
| .sectionLabel { | ||
| margin: 0; | ||
| font-size: 0.6875rem; | ||
| font-weight: 500; | ||
| line-height: 1.82; | ||
| letter-spacing: -0.01em; | ||
| color: var(--color-fd-foreground); | ||
| opacity: 0.5; | ||
| text-transform: uppercase; | ||
| white-space: pre; | ||
| } | ||
|
|
||
| .features { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 0.5rem; // 8px | ||
| } | ||
|
|
||
| .featureItem { | ||
| position: relative; | ||
| display: flex; | ||
| align-items: center; | ||
| gap: 0.5rem; // 8px | ||
| padding: 0.3125rem 0.8125rem 0.3125rem 0.5rem; | ||
| border: 1px solid var(--color-fd-border, #ddd4d4); | ||
| border-radius: 1.3125rem; // 21px | ||
| background-color: var(--color-fd-card); | ||
| justify-content: left; | ||
| box-shadow: 0 0 4px 0 rgb(255 255 255 / 25%) inset; | ||
| } | ||
|
|
||
| .featureIcon { | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| width: 0.781rem; // 12.5px | ||
| height: 0.781rem; // 12.5px | ||
| flex-shrink: 0; | ||
| color: var(--color-fd-foreground); | ||
| } | ||
|
|
||
| .featureLabel { | ||
| font-size: 0.875rem; // 14px | ||
| font-weight: 600; | ||
| line-height: 1.65; | ||
| letter-spacing: -0.01em; // -0.14px | ||
| color: var(--color-fd-foreground); | ||
| white-space: pre; | ||
| } | ||
|
|
||
| .featureShadow { | ||
| position: absolute; | ||
| inset: 0; | ||
| pointer-events: none; | ||
| box-shadow: inset 0 0 4px 0 rgb(255 255 255 / 25%); | ||
| border-radius: 1.32rem; // 21px | ||
| } | ||
|
||
|
|
||
| .quickLinks { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 1rem; // 16px | ||
| } | ||
|
|
||
| .quickLink { | ||
| font-size: 1rem; // 16px | ||
| font-weight: 500; | ||
| line-height: 1.25; // 20px | ||
| letter-spacing: -0.01em; // -0.16px | ||
| color: var(--color-fd-foreground); | ||
| text-decoration: underline; | ||
| text-decoration-skip-ink: none; | ||
| text-underline-position: from-font; | ||
| text-underline-offset: 0.1875rem; // 3px | ||
| transition: opacity 200ms ease-out; | ||
|
|
||
| &:hover { | ||
| opacity: 0.7; | ||
| } | ||
| } | ||
|
|
||
| .buttonWrapper { | ||
| margin-top: auto; | ||
| flex-shrink: 0; | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: flex-start; | ||
|
|
||
| :global(button) { | ||
aditya520 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| padding: 0.625rem; // 10px | ||
| border-radius: 0.5rem; // 8px | ||
| background-color: #27253d; | ||
| color: #f8f9fc; | ||
| font-size: 1rem; // 16px | ||
| font-weight: 500; | ||
| line-height: 1.25; // 20px | ||
| letter-spacing: -0.01em; // -0.16px | ||
| width: auto; | ||
| min-width: auto; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| "use client"; | ||
|
|
||
| import { Lightning } from "@phosphor-icons/react/dist/ssr"; | ||
| import { Button } from "@pythnetwork/component-library/Button"; | ||
| import { clsx } from "clsx"; | ||
| import Link from "next/link"; | ||
| import { useRouter } from "next/navigation"; | ||
| import type { ReactNode } from "react"; | ||
|
|
||
| import styles from "./index.module.scss"; | ||
|
|
||
| type Feature = { | ||
| label: string; | ||
| icon?: ReactNode; | ||
| }; | ||
|
|
||
| type QuickLink = { | ||
| label: string; | ||
| href: string; | ||
| }; | ||
|
|
||
| type ProductCardProps = { | ||
| title: string; | ||
| description?: string; | ||
| icon?: ReactNode; | ||
| features?: Feature[]; | ||
| quickLinks?: QuickLink[]; | ||
| buttonLabel?: string; | ||
| buttonHref?: string; | ||
| external?: boolean; | ||
| className?: string; | ||
| }; | ||
|
|
||
| export function ProductCard({ | ||
| title, | ||
| description, | ||
| icon, | ||
| features, | ||
| quickLinks, | ||
| buttonLabel, | ||
| buttonHref, | ||
| external, | ||
| className, | ||
| }: ProductCardProps) { | ||
| const router = useRouter(); | ||
|
|
||
| const handleButtonClick = () => { | ||
| if (!buttonHref) return; | ||
|
|
||
| if (external) { | ||
| window.open(buttonHref, "_blank", "noopener,noreferrer"); | ||
| } else { | ||
| router.push(buttonHref); | ||
| } | ||
| }; | ||
|
|
||
| return ( | ||
| <div className={clsx(styles.card, className)}> | ||
| <div className={styles.content}> | ||
| <div className={styles.mainContent}> | ||
| <div className={styles.header}> | ||
| <h3 className={styles.title}>{title}</h3> | ||
| {description && <p className={styles.description}>{description}</p>} | ||
| {icon && <div className={styles.icon}>{icon}</div>} | ||
| </div> | ||
|
|
||
| {features && features.length > 0 && ( | ||
| <div className={styles.featuresSection}> | ||
| <p className={styles.sectionLabel}>FEATURES</p> | ||
| <div className={styles.features}> | ||
| {features.map((feature, index) => ( | ||
| <div key={index} className={styles.featureItem}> | ||
| <div className={styles.featureIcon}> | ||
| {feature.icon ?? <Lightning size={12.5} />} | ||
| </div> | ||
| <span className={styles.featureLabel}>{feature.label}</span> | ||
| <div className={styles.featureShadow} /> | ||
| </div> | ||
| ))} | ||
| </div> | ||
| </div> | ||
| )} | ||
|
|
||
| {quickLinks && quickLinks.length > 0 && ( | ||
| <div className={styles.quickLinksSection}> | ||
| <p className={styles.sectionLabel}>QUICK LINKS</p> | ||
| <div className={styles.quickLinks}> | ||
| {quickLinks.map((link, index) => ( | ||
| <Link | ||
| key={index} | ||
| href={link.href} | ||
aditya520 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| className={styles.quickLink} | ||
| > | ||
| {link.label} | ||
| </Link> | ||
| ))} | ||
| </div> | ||
| </div> | ||
| )} | ||
| </div> | ||
|
|
||
| {buttonLabel && ( | ||
| <div className={styles.buttonWrapper}> | ||
| <Button onPress={handleButtonClick} size="md" variant="primary"> | ||
| {buttonLabel} | ||
| </Button> | ||
| </div> | ||
| )} | ||
| </div> | ||
| </div> | ||
| ); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.