initial commit

This commit is contained in:
2026-01-31 22:34:57 +09:00
commit f1301de543
875 changed files with 196598 additions and 0 deletions

90
components/StockRow.tsx Normal file
View File

@@ -0,0 +1,90 @@
import React from 'react';
import { Zap, ShoppingCart, Star } from 'lucide-react';
import { StockItem, MarketType, OrderType } from '../types';
interface StockRowProps {
stock: StockItem;
rank?: number;
showRank?: boolean;
showActions?: boolean;
showRatioBar?: boolean;
showPL?: { pl: number; percent: number };
isWatchlisted?: boolean;
onClick?: () => void;
onTrade?: (type: OrderType) => void;
onToggleWatchlist?: () => void;
}
export const StockRow: React.FC<StockRowProps> = ({
stock, rank, showRank, showActions, showRatioBar, showPL, isWatchlisted, onClick, onTrade, onToggleWatchlist
}) => {
return (
<tr
onClick={onClick}
className="group cursor-pointer transition-colors hover:bg-slate-50/70"
>
{showRank && (
<td className="pl-6 py-3 font-mono font-black text-slate-400 group-hover:text-blue-600 transition-colors">
{rank}
</td>
)}
<td className="px-4 py-3">
<div className="flex items-center gap-3">
{onToggleWatchlist && (
<button
onClick={(e) => { e.stopPropagation(); onToggleWatchlist(); }}
className="text-slate-300 hover:text-amber-500 transition-colors"
>
<Star size={16} fill={isWatchlisted ? "currentColor" : "none"} className={isWatchlisted ? "text-amber-500" : ""} />
</button>
)}
<div className="w-8 h-8 rounded-lg bg-slate-900 flex items-center justify-center text-white text-[10px] font-black shadow-sm overflow-hidden">
{stock.name[0]}
</div>
<div className="flex flex-col">
<span className="font-black text-slate-900 text-[13px] tracking-tight group-hover:text-blue-600">{stock.name}</span>
<span className="text-[9px] text-slate-400 font-mono font-bold">{stock.code}</span>
</div>
</div>
</td>
<td className="px-4 py-3 text-right font-mono font-black text-slate-800 text-[13px]">
{stock.market === MarketType.DOMESTIC ? stock.price.toLocaleString() + '원' : '$' + stock.price}
</td>
<td className="px-4 py-3 text-right">
{showPL ? (
<div className={showPL.pl >= 0 ? 'text-rose-500' : 'text-blue-600'}>
<p className="font-black text-[13px]">{showPL.pl.toLocaleString()}</p>
<p className="text-[10px] font-bold">({showPL.percent.toFixed(2)}%)</p>
</div>
) : (
<span className={`font-black text-[13px] ${stock.changePercent >= 0 ? 'text-rose-500' : 'text-blue-600'}`}>
{stock.changePercent >= 0 ? '+' : ''}{stock.changePercent}%
</span>
)}
</td>
{showRatioBar && (
<td className="px-4 py-3">
<div className="flex flex-col items-end gap-0.5">
<div className="w-full h-1 rounded-full bg-slate-100 overflow-hidden flex">
<div className="h-full bg-rose-400" style={{ width: `${stock.buyRatio || 50}%` }} />
<div className="h-full bg-blue-400" style={{ width: `${stock.sellRatio || 50}%` }} />
</div>
<div className="flex justify-between w-full text-[8px] font-black font-mono">
<span className="text-rose-500">{stock.buyRatio || 50}</span>
<span className="text-blue-500">{stock.sellRatio || 50}</span>
</div>
</div>
</td>
)}
{showActions && onTrade && (
<td className="px-4 py-3 text-right">
<div className="flex gap-1.5 justify-end opacity-0 group-hover:opacity-100 transition-opacity">
<button onClick={(e) => { e.stopPropagation(); onTrade(OrderType.BUY); }} className="p-1.5 bg-rose-50 text-rose-500 rounded-lg hover:bg-rose-500 hover:text-white transition-all"><Zap size={12} fill="currentColor" /></button>
<button onClick={(e) => { e.stopPropagation(); onTrade(OrderType.SELL); }} className="p-1.5 bg-blue-50 text-blue-500 rounded-lg hover:bg-blue-500 hover:text-white transition-all"><ShoppingCart size={12} /></button>
</div>
</td>
)}
</tr>
);
};