aider (free)
Get your Gemini API key (free tier)
π One-Page Memecoin Portfolio Tracker β Product Requirements
π― Goal
A single-page web app that mocks a memecoin portfolio. All data is fake. Built with React and Tailwind CSS. Focus on fun UI/UX, minimal complexity.
π Layout Overview
+---------------------------------------------+
| π My Memecoin Portfolio |
+---------------------------------------------+
| Total Value: $69,420.00 β² +4.20% |
| βYouβre going to the moon! πβ |
+---------------------------------------------+
| Coin | Holdings | Price | 24h % | Value |
|--------|----------|---------|-------|---------|
| πΆ DOGE | 10,000 | $0.08 | +2.1% | $800.00 |
| πΈ PEPE | 42,069K | $0.0001 | -1.2% | $4,206.90|
| π BAN | 900 | $0.69 | +69% | $621.00 |
+---------------------------------------------+
[ Refresh π ] [ Dark Mode π ]
β
Requirements
1. Single React Page
No routing.
One main component (App.jsx or similar).
State stored via useState.
2. Mock Data
Hardcoded in the component:
[
{ symbol: 'DOGE', name: 'DogeCoin', icon: 'πΆ', holdings: 10000, price: 0.08, change: 2.1 },
{ symbol: 'PEPE', name: 'PepeCoin', icon: 'πΈ', holdings: 42069000, price: 0.0001, change: -1.2 },
{ symbol: 'BAN', name: 'Banana Token', icon: 'π', holdings: 900, price: 0.69, change: 69 }
]
3. Core UI Sections
Header: Title, total value (sum of all holdings Γ price), 24h gain/loss %.
Quote: Meme quote like βTo the moon!β
Table:
Icon + name
Holdings
Price
24h change (% with color: green/red)
Value per coin
Buttons:
π Fake refresh (randomizes 24h %)
π Light/Dark mode toggle
4. Styling
Tailwind for layout, spacing, color, responsiveness
Responsive down to mobile
Fun meme fonts/colors (e.g., bold, Comic Sansβlike optional vibe)
"based on these specs, create 1 react page"
Component Name: CoinRow
Purpose:
The CoinRow component is responsible for displaying a single row of data about a specific cryptocurrency in a tabular format. It is typically used within a table that lists multiple cryptocurrencies owned by a user.
Input:
Prop: coin β An object of type Coin, which includes the following fields:
icon (string or JSX) β A visual representation or icon of the cryptocurrency.
symbol (string) β The ticker symbol of the cryptocurrency (e.g., BTC, ETH).
holdings (number) β The quantity of the coin the user holds.
price (number) β The current price per unit of the coin.
change (number) β The percentage change in the coinβs price over a certain period.
Display:
Each row (<tr>) includes five columns (<td>):
Coin Icon and Symbol: Displays the coinβs icon and its ticker symbol side by side.
Holdings: Shows the number of units the user owns, formatted with commas (e.g., 1,234.56).
Price: Shows the current price per unit, rounded to 4 decimal places and prefixed with $.
Price Change: Displays the percentage change. The text color is:
Green if the change is positive or zero.
Red if the change is negative.
Total Value: Calculates and displays the total value of the holdings (holdings Γ price), formatted with commas and at least two decimal places, prefixed with $.
Design:
Uses padding (p-2) for consistent spacing in each cell.
Adds a border below each row for visual separation (border-b).
Adapts to light and dark themes using Tailwind's dark: utility classes.
import React from 'react';
import { render, screen } from '@testing-library/react';
import CoinRow from './CoinRow';
import type { Coin } from '../types';
describe('CoinRow', () => {
const mockCoin: Coin = {
symbol: 'TEST',
name: 'TestCoin',
icon: 'π§ͺ',
holdings: 100,
price: 1.2345,
change: 5.5,
};
it('renders coin data correctly', () => {
render(
<table>
<tbody>
<CoinRow coin={mockCoin} />
</tbody>
</table>
);
expect(screen.getByText('π§ͺ TEST')).toBeInTheDocument();
expect(screen.getByText('100')).toBeInTheDocument(); // Holdings
expect(screen.getByText('$1.2345')).toBeInTheDocument(); // Price
expect(screen.getByText('5.5%')).toBeInTheDocument(); // Change
expect(screen.getByText('$123.45')).toBeInTheDocument(); // Value
});
it('renders negative change with red color', () => {
const negativeChangeCoin: Coin = { ...mockCoin, change: -2.0 };
render(
<table>
<tbody>
<CoinRow coin={negativeChangeCoin} />
</tbody>
</table>
);
const changeElement = screen.getByText('-2%'); // Use '-2%' instead of '-2.0%'
expect(changeElement).toBeInTheDocument();
expect(changeElement).toHaveClass('text-red-500');
});
it('renders positive change with green color', () => {
render(
<table>
<tbody>
<CoinRow coin={mockCoin} />
</tbody>
</table>
);
const changeElement = screen.getByText('5.5%');
expect(changeElement).toBeInTheDocument();
expect(changeElement).toHaveClass('text-green-500');
});
});
You are a senior software engineer tasked with implementing a scalable and maintainable React component.
Inputs:
- A business specification written in Markdown. It includes the functional description, user interface requirements, and any edge cases or constraints.
- A Vitest test file written manually, describing the expected behavior and usage of the component.
Your task:
- Read and understand the business specification and test file.
- Infer the structure, logic, props, and internal state of the component.
Write a complete React component (in TypeScript if type annotations are present in tests), following industry best practices for:
- Scalability (modular, composable structure)
- Maintainability (clear separation of concerns, minimal side effects)
- Accessibility (ARIA where relevant)
- Performance (memoization or lazy-loading if justified)
- Reusability (generic, configurable via props)
Requirements:
- Follow the Atomic Design or other consistent component hierarchy, if appropriate.
- Keep side effects isolated in useEffect or event handlers.
- Prefer hooks and functional components.
- Structure code for future extensibility.
- Ensure naming is clear and intuitive.
- Do not include the test file in the output.
- Include inline comments only where logic may be non-obvious.