Skip to content
Open
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
34 changes: 32 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,14 @@ <h3 class="card-title">Hobby</h3>
<span class="checkmark">✓</span>
Limited Tab completions
</li>
<li>
<span class="checkmark">✓</span>
Some agents
</li>
</ul>
</div>
</div>
<button class="download-button secondary">Download</button>
<button class="download-button tertiary">Start for free</button>
</div>
<div class="card">
<div class="card-top">
Expand All @@ -60,14 +64,40 @@ <h3 class="card-title">Pro</h3>
<span class="checkmark">✓</span>
Background Agents
</li>
</ul>
</div>
</div>
<button class="download-button secondary">Get Pro</button>
</div>
<div class="card">
<div class="card-top">
<h3 class="card-title">Enterprise</h3>
<p class="card-price">
<span class="card-price-amount">Custom</span>
</p>
<div class="card-content">
<p class="includes-text">Everything in Pro, plus:</p>
<ul class="features-list">
<li>
<span class="checkmark">✓</span>
Unlimited Agent requests
</li>
<li>
<span class="checkmark">✓</span>
Unlimited Tab completions
</li>
<li>
<span class="checkmark">✓</span>
Background Agents
</li>
<li>
<span class="checkmark">✓</span>
Maximum context windows
</li>
</ul>
</div>
</div>
<button class="download-button primary">Get Pro</button>
<button class="download-button primary">Contact sales</button>
</div>
</div>
</body>
Expand Down
66 changes: 44 additions & 22 deletions jsx-version.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,31 @@

// Same card UI, written as a JSX component (HTML-like syntax inside JavaScript)
// This component is reusable - we can create multiple cards by passing different data
function PricingCard({ title, price, includesText, features, buttonText, buttonVariant }) {
function PricingCard({ title, priceAmount, pricePeriod, includesText, features, buttonText, buttonVariant }) {
return (
// JSX uses "className" instead of "class" because "class" is a reserved word in JavaScript
<div className="card">
{/* Curly braces { } let you insert JavaScript expressions into JSX */}
<h1 className="card-title">{title}</h1>
<p className="card-price">{price}</p>
<div className="card-content">
<p className="includes-text">{includesText}</p>
<ul className="features-list">
{/* .map() loops through the features array and creates a <li> for each item */}
{features.map((feature, i) => (
// "key" helps React track which items changed - using index (i) is OK for static lists
<li key={i}>
<span className="checkmark">✓</span>
{feature}
</li>
))}
</ul>
<div className="card-top">
{/* Curly braces { } let you insert JavaScript expressions into JSX */}
<h3 className="card-title">{title}</h3>
{/* Matches index.html: card-price-amount + card-price-period */}
<p className="card-price">
<span className="card-price-amount">{priceAmount}</span>
<span className="card-price-period">{pricePeriod}</span>
</p>
<div className="card-content">
<p className="includes-text">{includesText}</p>
<ul className="features-list">
{/* .map() loops through the features array and creates a <li> for each item */}
{features.map((feature, i) => (
// "key" helps React track which items changed - using index (i) is OK for static lists
<li key={i}>
<span className="checkmark">✓</span>
{feature}
</li>
))}
</ul>
</div>
</div>
{/* Using our Button component instead of a raw <button> element */}
<Button label={buttonText} variant={buttonVariant} />
Expand All @@ -55,23 +61,38 @@ <h1 className="card-title">{title}</h1>
// These objects hold all the content for each pricing card
const hobbyPlan = {
title: 'Hobby',
price: 'Free',
priceAmount: 'Free',
pricePeriod: null,
includesText: 'Includes:',
features: ['No credit card required', 'Limited Agent requests', 'Limited Tab completions'],
buttonText: 'Download',
buttonVariant: 'secondary',
features: ['No credit card required', 'Limited Agent requests', 'Limited Tab completions', 'Some agents'],
buttonText: 'Start for free',
buttonVariant: 'tertiary',
};
const proPlan = {
title: 'Pro',
price: '$20/mo.',
priceAmount: '$20',
pricePeriod: '/mo.',
includesText: 'Everything in Hobby, plus:',
features: [
'Extended limits on Agent',
'Unlimited Tab completions',
'Background Agents',
'Maximum context windows',
],
buttonText: 'Get Pro',
buttonVariant: 'secondary',
};
const enterprisePlan = {
title: 'Enterprise',
priceAmount: 'Custom',
pricePeriod: null,
includesText: 'Everything in Pro, plus:',
features: [
'Unlimited Agent requests',
'Unlimited Tab completions',
'Background Agents',
'Maximum context windows',
],
buttonText: 'Contact sales',
buttonVariant: 'primary',
};

Expand All @@ -84,6 +105,7 @@ <h1 className="card-title">{title}</h1>
{/* This is the same as writing: title="Hobby" price="Free" includesText="Includes:" etc. */}
<PricingCard {...hobbyPlan} />
<PricingCard {...proPlan} />
<PricingCard {...enterprisePlan} />
</div>
</>
);
Expand Down
24 changes: 24 additions & 0 deletions src/components/Button/Button.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,27 @@
.download-button.primary:active {
background-color: #333;
}

.download-button.tertiary {
background-color: transparent;
color: #111;
border: 1px solid #c8c7c2;
}

.download-button.tertiary:hover {
background-color: #D8D6CE;
}

.download-button.tertiary:active {
background-color: #D8D6CE;
}

/* Focus — outline on all button variants */
.download-button:focus {
outline: none;
}

.download-button:focus-visible {
outline: 2px solid yellow;
outline-offset: 2px;
}
2 changes: 1 addition & 1 deletion src/components/PricingCard/PricingCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function PricingCard({ title, priceAmount, pricePeriod, includesText, features,
<h3 className="card-title">{title}</h3>
<p className="card-price">
<span className="card-price-amount">{priceAmount}</span>
{pricePeriod != null && <span className="card-price-period">{pricePeriod}</span>}
<span className="card-price-period">{pricePeriod}</span>
</p>
<div className="card-content">
<p className="includes-text">{includesText}</p>
Expand Down
23 changes: 18 additions & 5 deletions src/pages/Pricing.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ function Pricing() {
priceAmount: 'Free',
pricePeriod: null,
includesText: 'Includes:',
features: ['No credit card required', 'Limited Agent requests', 'Limited Tab completions'],
buttonText: 'Download',
buttonVariant: 'secondary',
features: ['No credit card required', 'Limited Agent requests', 'Limited Tab completions', 'Some agents'],
buttonText: 'Start for free',
buttonVariant: 'tertiary',
};
const proPlan = {
title: 'Pro',
Expand All @@ -28,9 +28,22 @@ function Pricing() {
'Extended limits on Agent',
'Unlimited Tab completions',
'Background Agents',
'Maximum context windows',
],
buttonText: 'Get Pro',
buttonVariant: 'secondary',
};
const enterprisePlan = {
title: 'Enterprise',
priceAmount: 'Custom',
pricePeriod: null,
includesText: 'Everything in Pro, plus:',
features: [
'Unlimited Agent requests',
'Unlimited Tab completions',
'Background Agents',
'Maximum context windows',
],
buttonText: 'Contact sales',
buttonVariant: 'primary',
};

Expand All @@ -40,9 +53,9 @@ function Pricing() {
<p className="page-label"><strong>React App</strong> — running with Vite</p>
<div className="cards-container">
{/* The spread operator {...hobbyPlan} passes all object properties as individual props */}
{/* This is the same as: title="Hobby" price="Free" includesText="Includes:" etc. */}
<PricingCard {...hobbyPlan} />
<PricingCard {...proPlan} />
<PricingCard {...enterprisePlan} />
</div>
</>
);
Expand Down
24 changes: 24 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,30 @@ body {
background-color: #333;
}

.download-button.tertiary {
background-color: transparent;
color: #111;
border: 1px solid #c8c7c2;
}

.download-button.tertiary:hover {
background-color: #D8D6CE;
}

.download-button.tertiary:active {
background-color: #D8D6CE;
}

/* Focus — outline on all button variants (keyboard / :focus-visible) */
.download-button:focus {
outline: none;
}

.download-button:focus-visible {
outline: 2px solid rgb(4, 0, 255);
outline-offset: 2px;
}

.page-label {
position: fixed;
top: 16px;
Expand Down