Landing Page Redesign Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Redesign docs.volr.io landing page with a prominent npx volr command, Claude Code skills showcase, and terminal typing animation demo.
Architecture: Three new React components (NpxCommand, SkillsSection, TerminalDemo) added to the existing Docusaurus homepage. All use Framer Motion (already installed) for animations and CSS Modules for styling. The existing hero is restructured with new copy and the npx command box. Existing doc cards section is preserved at the bottom.
Tech Stack: React 18, Docusaurus 3, Framer Motion 11, lucide-react, CSS Modules, Tailwind CSS v4
Task 1: Create NpxCommand component
Files:
- Create:
src/components/NpxCommand/NpxCommand.tsx - Create:
src/components/NpxCommand/NpxCommand.module.css
Step 1: Create the NpxCommand component
// src/components/NpxCommand/NpxCommand.tsx
import { useState, useCallback } from 'react';
import { Copy, Check } from 'lucide-react';
import styles from './NpxCommand.module.css';
const COMMAND = 'npx volr';
export default function NpxCommand() {
const [copied, setCopied] = useState(false);
const handleCopy = useCallback(async () => {
try {
await navigator.clipboard.writeText(COMMAND);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch {
// Fallback for older browsers
const textarea = document.createElement('textarea');
textarea.value = COMMAND;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
}, []);
return (
<button className={styles.container} onClick={handleCopy} type="button" aria-label="Copy npx volr command">
<span className={styles.prompt}>$</span>
<span className={styles.command}>{COMMAND}</span>
<span className={styles.copyIcon}>
{copied ? <Check size={16} /> : <Copy size={16} />}
</span>
</button>
);
}
Step 2: Create NpxCommand styles
/* src/components/NpxCommand/NpxCommand.module.css */
.container {
display: inline-flex;
align-items: center;
gap: 0.75rem;
padding: 0.875rem 1.25rem;
background-color: #111827;
border: 1px solid #374151;
border-radius: 0.5rem;
cursor: pointer;
transition: all 0.2s ease;
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;
font-size: 1rem;
line-height: 1;
}
.container:hover {
border-color: #4b5563;
background-color: #1f2937;
}
[data-theme='dark'] .container {
background-color: #0d1117;
border-color: #30363d;
}
[data-theme='dark'] .container:hover {
border-color: #484f58;
background-color: #161b22;
}
.prompt {
color: #6b7280;
user-select: none;
}
.command {
color: #f9fafb;
font-weight: 500;
}
.copyIcon {
display: flex;
align-items: center;
color: #6b7280;
transition: color 0.2s ease;
margin-left: 0.5rem;
}
.container:hover .copyIcon {
color: #9ca3af;
}
Step 3: Verify the component renders
Run: cd /Users/danny/strartups/volr/volr-project/volr-docs && yarn start
Expected: Dev server starts without errors
Step 4: Commit
git add src/components/NpxCommand/
git commit -m "feat: add NpxCommand copy-to-clipboard component"
Task 2: Create SkillsSection component
Files:
- Create:
src/components/SkillsSection/SkillsSection.tsx - Create:
src/components/SkillsSection/SkillsSection.module.css
Step 1: Create SkillsSection component
The skills data comes from the actual volr-skills repo. Each card shows skill name, description, and a copy button for the skill install command.
// src/components/SkillsSection/SkillsSection.tsx
import { useState, useCallback } from 'react';
import { Copy, Check, ShoppingCart, Music, Store, Hotel, Palette } from 'lucide-react';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import styles from './SkillsSection.module.css';
interface Skill {
id: string;
icon: typeof ShoppingCart;
name: { en: string; ko: string };
description: { en: string; ko: string };
}
const skills: Skill[] = [
{
id: 'volr-checkout-base',
icon: ShoppingCart,
name: { en: 'Checkout Base', ko: 'Checkout Base' },
description: {
en: 'Stablecoin payment API setup and integration',
ko: '스테이블코인 결제 API 설정 및 연동',
},
},
{
id: 'volr-fandom',
icon: Music,
name: { en: 'Fandom & K-Culture', ko: 'Fandom & K-Culture' },
description: {
en: 'Fan commerce, tickets, merch, and event payments',
ko: '팬 커머스, 티켓, 굿즈, 이벤트 결제',
},
},
{
id: 'volr-sellers',
icon: Store,
name: { en: 'Global Sellers', ko: 'Global Sellers' },
description: {
en: 'E-commerce and marketplace seller integrations',
ko: '이커머스 및 마켓플레이스 셀러 연동',
},
},
{
id: 'volr-accommodation',
icon: Hotel,
name: { en: 'Accommodation', ko: 'Accommodation' },
description: {
en: 'Hotel, booking, and vacation rental payments',
ko: '호텔, 예약, 숙소 결제',
},
},
{
id: 'volr-creators',
icon: Palette,
name: { en: 'Creator Economy', ko: 'Creator Economy' },
description: {
en: 'Tips, subscriptions, and digital goods payments',
ko: '팁, 구독, 디지털 상품 결제',
},
},
];
const translations = {
en: {
title: 'Built-in AI Skills',
subtitle: 'Install Volr skills in your AI coding agent to accelerate integration',
copied: 'Copied!',
copy: 'Copy install command',
},
ko: {
title: 'Built-in AI Skills',
subtitle: 'AI 코딩 에이전트에 Volr skill을 설치하여 통합을 가속화하세요',
copied: '복사됨!',
copy: '설치 명령어 복사',
},
};
function SkillCard({ skill, locale }: { skill: Skill; locale: 'en' | 'ko' }) {
const [copied, setCopied] = useState(false);
const t = translations[locale];
const Icon = skill.icon;
const handleCopy = useCallback(async () => {
const command = `npx volr skill install ${skill.id}`;
try {
await navigator.clipboard.writeText(command);
} catch {
const textarea = document.createElement('textarea');
textarea.value = command;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
}
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}, [skill.id]);
return (
<div className={styles.card}>
<div className={styles.cardHeader}>
<div className={styles.iconBox}>
<Icon size={20} />
</div>
<h3 className={styles.cardTitle}>{skill.name[locale]}</h3>
</div>
<p className={styles.cardDescription}>{skill.description[locale]}</p>
<button className={styles.copyButton} onClick={handleCopy} type="button" aria-label={t.copy}>
<code className={styles.commandText}>npx volr skill install {skill.id}</code>
<span className={styles.copyIconWrapper}>
{copied ? <Check size={14} /> : <Copy size={14} />}
</span>
</button>
</div>
);
}
export default function SkillsSection() {
const { i18n } = useDocusaurusContext();
const locale = (i18n.currentLocale as 'en' | 'ko') || 'en';
const t = translations[locale];
return (
<section className={styles.section}>
<h2 className={styles.title}>{t.title}</h2>
<p className={styles.subtitle}>{t.subtitle}</p>
<div className={styles.grid}>
{skills.map((skill) => (
<SkillCard key={skill.id} skill={skill} locale={locale} />
))}
</div>
</section>
);
}
Step 2: Create SkillsSection styles
/* src/components/SkillsSection/SkillsSection.module.css */
.section {
margin-top: 5rem;
margin-bottom: 5rem;
}
.title {
font-size: 1.75rem;
font-weight: 600;
color: var(--ifm-font-color-base);
margin: 0 0 0.75rem 0;
text-align: center;
letter-spacing: -0.01em;
}
@media (min-width: 768px) {
.title {
font-size: 2rem;
}
}
.subtitle {
font-size: 1rem;
color: #6b7280;
text-align: center;
margin: 0 auto 2.5rem;
max-width: 500px;
line-height: 1.6;
}
[data-theme='dark'] .subtitle {
color: #9ca3af;
}
.grid {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
}
@media (min-width: 640px) {
.grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1024px) {
.grid {
grid-template-columns: repeat(3, 1fr);
}
}
.card {
display: flex;
flex-direction: column;
padding: 1.5rem;
background-color: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 0.75rem;
transition: all 0.2s ease;
}
.card:hover {
border-color: #d1d5db;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
[data-theme='dark'] .card {
background-color: #1f2937;
border-color: #374151;
}
[data-theme='dark'] .card:hover {
border-color: #4b5563;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
}
.cardHeader {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 0.75rem;
}
.iconBox {
display: flex;
align-items: center;
justify-content: center;
width: 2.5rem;
height: 2.5rem;
color: #276AFF;
background-color: #EDF2FF;
border-radius: 0.5rem;
flex-shrink: 0;
}
[data-theme='dark'] .iconBox {
color: #82A8FF;
background-color: #1A3A6B;
}
.cardTitle {
font-size: 1rem;
font-weight: 600;
color: var(--ifm-font-color-base);
margin: 0;
line-height: 1.4;
}
.cardDescription {
font-size: 0.875rem;
color: #6b7280;
margin: 0 0 1rem 0;
line-height: 1.5;
flex: 1;
}
[data-theme='dark'] .cardDescription {
color: #9ca3af;
}
.copyButton {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.75rem;
background-color: #f3f4f6;
border: 1px solid #e5e7eb;
border-radius: 0.375rem;
cursor: pointer;
transition: all 0.15s ease;
width: 100%;
}
.copyButton:hover {
background-color: #e5e7eb;
border-color: #d1d5db;
}
[data-theme='dark'] .copyButton {
background-color: #111827;
border-color: #374151;
}
[data-theme='dark'] .copyButton:hover {
background-color: #1f2937;
border-color: #4b5563;
}
.commandText {
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;
font-size: 0.75rem;
color: #6b7280;
flex: 1;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
background: none;
border: none;
padding: 0;
}
[data-theme='dark'] .commandText {
color: #9ca3af;
}
.copyIconWrapper {
display: flex;
align-items: center;
color: #9ca3af;
flex-shrink: 0;
}
Step 3: Verify dev server still works
Run: cd /Users/danny/strartups/volr/volr-project/volr-docs && yarn start
Expected: No errors
Step 4: Commit
git add src/components/SkillsSection/
git commit -m "feat: add SkillsSection component with copy-to-clipboard commands"