[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6GWM5TYQEBJPFM9ZH4VZD8Y":3,"skill-same:01M6GWM5TYQEBJPFM9ZH4VZD8Y":78},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":16,"sourceHtmlUrl":17,"categories":18,"keywords":19,"publishedAt":36,"linkOnly":37,"markdownContent":38,"markdownBody":39,"frontMatter":40,"refName":41,"commitSha":42,"skillDirectory":43,"forksCount":44,"repositoryHtmlUrl":45,"repositoryHomepageUrl":6,"ownerHtmlUrl":46,"ownerBlogUrl":47,"ownerDescription":48,"updatedAt":49,"install":50,"resources":63},"01M6GWM5TYQEBJPFM9ZH4VZD8Y","gdex-ui-page-layouts",null,"Full page layout compositions for GDEX — trading page, portfolio page, copy trading page, and bridge page with responsive grid patterns","jiayaoqijia\u002Fcryptoskill","jiayaoqijia","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1453879?v=4","01M6GMYTX7Q7S504VC6E756ENR","YQ","01M6GMYV1QKJ1CC75MTTGT9PR0",81,"MIT","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fmcp-servers\u002Fgemachdao-gdex-ui-page-layouts\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fmcp-servers\u002Fgemachdao-gdex-ui-page-layouts\u002FSKILL.md",[],[20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35],"ui","page","ui page","gdex ui page layouts","bridge","portfolio","trading","patterns","full","responsive","layout","copy","with","grid","for","compositions","2026-11-10 10:12:30",false,"---\nname: gdex-ui-page-layouts\ndescription: Full page layout compositions for GDEX — trading page, portfolio page, copy trading page, and bridge page with responsive grid patterns\n---\n\n# GDEX: Page Layouts\n\nFull page layout compositions for GDEX trading apps. Each layout combines components from other UI skills into a complete, responsive page.\n\n## When to Use\n\n- Building a full trading page with chart, order form, and positions\n- Creating a portfolio dashboard page\n- Composing a copy trading management page\n- Building a bridge page\n\n## Prerequisites\n\n- Components from **gdex-ui-trading-components** and **gdex-ui-portfolio-dashboard**\n- Theme set up per **gdex-ui-theming**\n- SDK context provider from **gdex-ui-install-setup**\n\n## Trading Page\n\nThe primary trading interface — chart, order form, positions, and optionally an orderbook.\n\n```typescript\n\u002F\u002F app\u002Ftrade\u002Fpage.tsx\n'use client';\n\nimport { useState } from 'react';\nimport { SpotTradeForm } from '@\u002Fcomponents\u002FSpotTradeForm';\nimport { PerpOrderForm } from '@\u002Fcomponents\u002FPerpOrderForm';\nimport { PositionTable } from '@\u002Fcomponents\u002FPositionTable';\nimport { TokenSearch } from '@\u002Fcomponents\u002FTokenSearch';\nimport { ChainSelector } from '@\u002Fcomponents\u002FChainSelector';\nimport { PnLDisplay } from '@\u002Fcomponents\u002FPnLDisplay';\n\nexport default function TradingPage() {\n  const [chain, setChain] = useState('solana');\n  const [mode, setMode] = useState\u003C'spot' | 'perp'>('spot');\n  const [selectedToken, setSelectedToken] = useState\u003Cstring>('');\n\n  return (\n    \u003Cdiv className=\"min-h-screen bg-[var(--bg-primary)] text-[var(--text-primary)]\">\n      {\u002F* Top bar *\u002F}\n      \u003Cheader className=\"border-b border-[var(--border-primary)] px-4 py-3 flex items-center justify-between\">\n        \u003Cdiv className=\"flex items-center gap-4\">\n          \u003Ch1 className=\"text-lg font-bold\">GDEX Trade\u003C\u002Fh1>\n          \u003Cdiv className=\"flex gap-1\">\n            \u003Cbutton onClick={() => setMode('spot')}\n              className={`px-3 py-1 rounded text-sm ${mode === 'spot' ? 'bg-brand text-white' : ''}`}>\n              Spot\n            \u003C\u002Fbutton>\n            \u003Cbutton onClick={() => setMode('perp')}\n              className={`px-3 py-1 rounded text-sm ${mode === 'perp' ? 'bg-brand text-white' : ''}`}>\n              Perp\n            \u003C\u002Fbutton>\n          \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n        \u003CChainSelector value={chain} onChange={setChain} \u002F>\n      \u003C\u002Fheader>\n\n      {\u002F* Main grid — responsive *\u002F}\n      \u003Cdiv className=\"grid grid-cols-1 lg:grid-cols-[1fr_380px] gap-0 lg:gap-4 p-4\">\n        {\u002F* Left: Chart + Token search + Positions *\u002F}\n        \u003Cdiv className=\"space-y-4\">\n          {mode === 'spot' && (\n            \u003CTokenSearch chain={chain}\n              onSelect={token => setSelectedToken(token.address)} \u002F>\n          )}\n\n          {\u002F* Chart placeholder — integrate TradingView or Lightweight Charts *\u002F}\n          \u003Cdiv className=\"bg-[var(--bg-card)] border border-[var(--border-primary)] rounded-lg h-[400px] flex items-center justify-center text-[var(--text-secondary)]\">\n            Chart — TradingView or Lightweight Charts\n          \u003C\u002Fdiv>\n\n          {\u002F* Positions \u002F Open orders *\u002F}\n          {mode === 'perp' && (\n            \u003Cdiv className=\"bg-[var(--bg-card)] border border-[var(--border-primary)] rounded-lg p-4\">\n              \u003Ch2 className=\"text-sm font-bold mb-3\">Open Positions\u003C\u002Fh2>\n              \u003CPositionTable \u002F>\n            \u003C\u002Fdiv>\n          )}\n        \u003C\u002Fdiv>\n\n        {\u002F* Right: Order form *\u002F}\n        \u003Cdiv className=\"bg-[var(--bg-card)] border border-[var(--border-primary)] rounded-lg p-4 h-fit lg:sticky lg:top-4\">\n          \u003Ch2 className=\"text-sm font-bold mb-3\">\n            {mode === 'spot' ? 'Spot Trade' : 'Perp Order'}\n          \u003C\u002Fh2>\n          {mode === 'spot'\n            ? \u003CSpotTradeForm defaultChain={chain} \u002F>\n            : \u003CPerpOrderForm \u002F>\n          }\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n### Layout Grid (responsive)\n\n```\nMobile (\u003C 1024px):          Desktop (≥ 1024px):\n┌────────────────┐          ┌──────────────┬─────────┐\n│ Token Search   │          │ Token Search │ Order   │\n├────────────────┤          ├──────────────┤ Form    │\n│ Chart          │          │ Chart        │         │\n├────────────────┤          ├──────────────┤         │\n│ Positions      │          │ Positions    │         │\n├────────────────┤          └──────────────┴─────────┘\n│ Order Form     │\n└────────────────┘\n```\n\n## Portfolio Page\n\n```typescript\n\u002F\u002F app\u002Fportfolio\u002Fpage.tsx\n'use client';\n\nimport { useState } from 'react';\nimport { PortfolioOverview } from '@\u002Fcomponents\u002FPortfolioOverview';\nimport { TokenBalanceGrid } from '@\u002Fcomponents\u002FTokenBalanceGrid';\nimport { TradeHistoryTable } from '@\u002Fcomponents\u002FTradeHistoryTable';\nimport { ChainSelector } from '@\u002Fcomponents\u002FChainSelector';\n\nexport default function PortfolioPage() {\n  const [chain, setChain] = useState('all');\n  const [tab, setTab] = useState\u003C'balances' | 'history'>('balances');\n\n  return (\n    \u003Cdiv className=\"min-h-screen bg-[var(--bg-primary)] text-[var(--text-primary)] p-4 space-y-6\">\n      \u003Ch1 className=\"text-2xl font-bold\">Portfolio\u003C\u002Fh1>\n\n      {\u002F* Overview cards *\u002F}\n      \u003CPortfolioOverview \u002F>\n\n      {\u002F* Chain filter *\u002F}\n      \u003CChainSelector value={chain} onChange={setChain} \u002F>\n\n      {\u002F* Tabs *\u002F}\n      \u003Cdiv className=\"flex gap-4 border-b border-[var(--border-primary)]\">\n        \u003Cbutton onClick={() => setTab('balances')}\n          className={`pb-2 text-sm ${tab === 'balances' ? 'border-b-2 border-brand font-bold' : 'text-[var(--text-secondary)]'}`}>\n          Token Balances\n        \u003C\u002Fbutton>\n        \u003Cbutton onClick={() => setTab('history')}\n          className={`pb-2 text-sm ${tab === 'history' ? 'border-b-2 border-brand font-bold' : 'text-[var(--text-secondary)]'}`}>\n          Trade History\n        \u003C\u002Fbutton>\n      \u003C\u002Fdiv>\n\n      {\u002F* Content *\u002F}\n      {tab === 'balances'\n        ? \u003CTokenBalanceGrid chain={chain === 'all' ? undefined : chain} \u002F>\n        : \u003CTradeHistoryTable \u002F>\n      }\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n## Copy Trading Page\n\n```typescript\n\u002F\u002F app\u002Fcopy-trade\u002Fpage.tsx\n'use client';\n\nimport { useState } from 'react';\nimport { CopyTradePanel } from '@\u002Fcomponents\u002FCopyTradePanel';\n\nexport default function CopyTradingPage() {\n  const [platform, setPlatform] = useState\u003C'solana' | 'hyperliquid'>('solana');\n\n  return (\n    \u003Cdiv className=\"min-h-screen bg-[var(--bg-primary)] text-[var(--text-primary)] p-4 space-y-6\">\n      \u003Cdiv className=\"flex items-center justify-between\">\n        \u003Ch1 className=\"text-2xl font-bold\">Copy Trading\u003C\u002Fh1>\n        \u003Cdiv className=\"flex gap-2\">\n          \u003Cbutton onClick={() => setPlatform('solana')}\n            className={`px-3 py-1.5 rounded text-sm ${platform === 'solana' ? 'bg-[var(--color-chain-solana)] text-white' : 'border'}`}>\n            Solana Spot\n          \u003C\u002Fbutton>\n          \u003Cbutton onClick={() => setPlatform('hyperliquid')}\n            className={`px-3 py-1.5 rounded text-sm ${platform === 'hyperliquid' ? 'bg-brand text-white' : 'border'}`}>\n            HL Perp\n          \u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n\n      \u003Cdiv className=\"grid grid-cols-1 lg:grid-cols-[1fr_400px] gap-6\">\n        {\u002F* Left: Leaderboard \u002F Top traders *\u002F}\n        \u003Cdiv className=\"bg-[var(--bg-card)] border border-[var(--border-primary)] rounded-lg p-4\">\n          \u003Ch2 className=\"text-lg font-bold mb-4\">Top Traders\u003C\u002Fh2>\n          \u003Cp className=\"text-sm text-[var(--text-secondary)]\">\n            {platform === 'solana' ? 'Top Solana spot traders by PnL' : 'Top HyperLiquid perp traders by PnL'}\n          \u003C\u002Fp>\n          {\u002F* Trader leaderboard list *\u002F}\n        \u003C\u002Fdiv>\n\n        {\u002F* Right: Active copy trades *\u002F}\n        \u003Cdiv className=\"bg-[var(--bg-card)] border border-[var(--border-primary)] rounded-lg p-4\">\n          \u003Ch2 className=\"text-lg font-bold mb-4\">Your Copy Trades\u003C\u002Fh2>\n          \u003CCopyTradePanel \u002F>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n## Bridge Page\n\n```typescript\n\u002F\u002F app\u002Fbridge\u002Fpage.tsx\n'use client';\n\nimport { useState } from 'react';\nimport { useGdex } from '@\u002Fproviders\u002FGdexProvider';\nimport { ChainSwitcher } from '@\u002Fcomponents\u002FChainSwitcher';\n\nexport default function BridgePage() {\n  const { skill, isReady } = useGdex();\n  const [fromChain, setFromChain] = useState(1);\n  const [toChain, setToChain] = useState(622112261);\n  const [amount, setAmount] = useState('');\n  const [estimate, setEstimate] = useState\u003Cany>(null);\n  const [loading, setLoading] = useState(false);\n\n  const getEstimate = async () => {\n    if (!isReady || !amount) return;\n    setLoading(true);\n    try {\n      const est = await skill.estimateBridge({\n        fromChainId: fromChain,\n        toChainId: toChain,\n        amount,   \u002F\u002F raw units of the source native token (wei \u002F lamports)\n      });\n      setEstimate(est);\n    } finally {\n      setLoading(false);\n    }\n  };\n\n  return (\n    \u003Cdiv className=\"min-h-screen bg-[var(--bg-primary)] text-[var(--text-primary)] p-4\">\n      \u003Ch1 className=\"text-2xl font-bold mb-6\">Bridge\u003C\u002Fh1>\n\n      \u003Cdiv className=\"max-w-lg mx-auto bg-[var(--bg-card)] border border-[var(--border-primary)] rounded-lg p-6 space-y-4\">\n        {\u002F* From chain *\u002F}\n        \u003Cdiv>\n          \u003Clabel className=\"text-xs text-[var(--text-secondary)] mb-1 block\">From\u003C\u002Flabel>\n          \u003CChainSwitcher value={fromChain} onChange={setFromChain} \u002F>\n        \u003C\u002Fdiv>\n\n        {\u002F* Swap button *\u002F}\n        \u003Cdiv className=\"flex justify-center\">\n          \u003Cbutton onClick={() => { setFromChain(toChain); setToChain(fromChain); }}\n            className=\"p-2 border rounded-full hover:bg-[var(--bg-tertiary)]\">\n            ↕\n          \u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n\n        {\u002F* To chain *\u002F}\n        \u003Cdiv>\n          \u003Clabel className=\"text-xs text-[var(--text-secondary)] mb-1 block\">To\u003C\u002Flabel>\n          \u003CChainSwitcher value={toChain} onChange={setToChain} \u002F>\n        \u003C\u002Fdiv>\n\n        {\u002F* Amount *\u002F}\n        \u003Cinput type=\"number\" placeholder=\"Amount (native token)\" value={amount}\n          onChange={e => setAmount(e.target.value)} step=\"any\" min=\"0\"\n          className=\"w-full p-3 border rounded-lg bg-[var(--bg-input)]\" \u002F>\n\n        {\u002F* Estimate *\u002F}\n        \u003Cbutton onClick={getEstimate} disabled={loading || !amount}\n          className=\"w-full py-3 bg-brand text-white rounded-lg font-bold disabled:opacity-50\">\n          {loading ? 'Getting estimate...' : 'Get Estimate'}\n        \u003C\u002Fbutton>\n\n        {estimate && (\n          \u003Cdiv className=\"border border-[var(--border-primary)] rounded-lg p-4 space-y-2 text-sm\">\n            \u003Cdiv className=\"flex justify-between\">\n              \u003Cspan className=\"text-[var(--text-secondary)]\">You receive\u003C\u002Fspan>\n              \u003Cspan className=\"font-bold\">{estimate.estimateAmount}\u003C\u002Fspan>\n            \u003C\u002Fdiv>\n            \u003Cdiv className=\"flex justify-between\">\n              \u003Cspan className=\"text-[var(--text-secondary)]\">ETA\u003C\u002Fspan>\n              \u003Cspan>{estimate.minEstimateTime}–{estimate.maxEstimateTime}s via {estimate.tool}\u003C\u002Fspan>\n            \u003C\u002Fdiv>\n            \u003Cbutton className=\"w-full py-2 mt-2 bg-brand text-white rounded-lg\">\n              Bridge Now\n            \u003C\u002Fbutton>\n          \u003C\u002Fdiv>\n        )}\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n## Navigation Layout\n\n```typescript\n\u002F\u002F components\u002FNavigation.tsx\n'use client';\n\nimport Link from 'next\u002Flink';\nimport { usePathname } from 'next\u002Fnavigation';\nimport { ConnectButton } from '.\u002FConnectButton';\nimport { ThemeToggle } from '.\u002FThemeToggle';\n\nconst NAV_ITEMS = [\n  { href: '\u002Ftrade', label: 'Trade' },\n  { href: '\u002Fportfolio', label: 'Portfolio' },\n  { href: '\u002Fcopy-trade', label: 'Copy Trade' },\n  { href: '\u002Fbridge', label: 'Bridge' },\n];\n\nexport function Navigation() {\n  const pathname = usePathname();\n\n  return (\n    \u003Cnav className=\"border-b border-[var(--border-primary)] bg-[var(--bg-primary)]\">\n      \u003Cdiv className=\"max-w-7xl mx-auto px-4 flex items-center justify-between h-14\">\n        \u003Cdiv className=\"flex items-center gap-6\">\n          \u003Cspan className=\"font-bold text-lg\">GDEX\u003C\u002Fspan>\n          {NAV_ITEMS.map(item => (\n            \u003CLink key={item.href} href={item.href}\n              className={`text-sm ${pathname === item.href\n                ? 'text-brand font-bold'\n                : 'text-[var(--text-secondary)] hover:text-[var(--text-primary)]'}`}>\n              {item.label}\n            \u003C\u002FLink>\n          ))}\n        \u003C\u002Fdiv>\n        \u003Cdiv className=\"flex items-center gap-3\">\n          \u003CThemeToggle \u002F>\n          \u003CConnectButton \u002F>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fnav>\n  );\n}\n```\n\n## Page → Component → SDK Method Map\n\n| Page | Components Used | SDK Methods |\n|------|----------------|-------------|\n| Trading | `SpotTradeForm`, `PerpOrderForm`, `PositionTable`, `TokenSearch`, `ChainSelector` | `buyToken`, `sellToken`, `hlCreateOrder`, `getPerpPositions`, `closePerpPosition`, `getTokenDetails` |\n| Portfolio | `PortfolioOverview`, `TokenBalanceGrid`, `TradeHistoryTable`, `ChainSelector` | `getPortfolio`, `getTradeHistory` |\n| Copy Trading | `CopyTradePanel` | `getCopyTradeList`, `getCopyTradeWallets` |\n| Bridge | `ChainSwitcher` | `estimateBridge`, `requestBridge` |\n\n## Related Skills\n\n- **gdex-ui-install-setup** — Project scaffolding to build these pages\n- **gdex-ui-trading-components** — Individual component patterns\n- **gdex-ui-portfolio-dashboard** — Dashboard-specific components\n- **gdex-ui-theming** — Theme tokens and CSS variables used throughout\n- **gdex-ui-wallet-connection** — ConnectButton and auth flows\n","# GDEX: Page Layouts\n\nFull page layout compositions for GDEX trading apps. Each layout combines components from other UI skills into a complete, responsive page.\n\n## When to Use\n\n- Building a full trading page with chart, order form, and positions\n- Creating a portfolio dashboard page\n- Composing a copy trading management page\n- Building a bridge page\n\n## Prerequisites\n\n- Components from **gdex-ui-trading-components** and **gdex-ui-portfolio-dashboard**\n- Theme set up per **gdex-ui-theming**\n- SDK context provider from **gdex-ui-install-setup**\n\n## Trading Page\n\nThe primary trading interface — chart, order form, positions, and optionally an orderbook.\n\n```typescript\n\u002F\u002F app\u002Ftrade\u002Fpage.tsx\n'use client';\n\nimport { useState } from 'react';\nimport { SpotTradeForm } from '@\u002Fcomponents\u002FSpotTradeForm';\nimport { PerpOrderForm } from '@\u002Fcomponents\u002FPerpOrderForm';\nimport { PositionTable } from '@\u002Fcomponents\u002FPositionTable';\nimport { TokenSearch } from '@\u002Fcomponents\u002FTokenSearch';\nimport { ChainSelector } from '@\u002Fcomponents\u002FChainSelector';\nimport { PnLDisplay } from '@\u002Fcomponents\u002FPnLDisplay';\n\nexport default function TradingPage() {\n  const [chain, setChain] = useState('solana');\n  const [mode, setMode] = useState\u003C'spot' | 'perp'>('spot');\n  const [selectedToken, setSelectedToken] = useState\u003Cstring>('');\n\n  return (\n    \u003Cdiv className=\"min-h-screen bg-[var(--bg-primary)] text-[var(--text-primary)]\">\n      {\u002F* Top bar *\u002F}\n      \u003Cheader className=\"border-b border-[var(--border-primary)] px-4 py-3 flex items-center justify-between\">\n        \u003Cdiv className=\"flex items-center gap-4\">\n          \u003Ch1 className=\"text-lg font-bold\">GDEX Trade\u003C\u002Fh1>\n          \u003Cdiv className=\"flex gap-1\">\n            \u003Cbutton onClick={() => setMode('spot')}\n              className={`px-3 py-1 rounded text-sm ${mode === 'spot' ? 'bg-brand text-white' : ''}`}>\n              Spot\n            \u003C\u002Fbutton>\n            \u003Cbutton onClick={() => setMode('perp')}\n              className={`px-3 py-1 rounded text-sm ${mode === 'perp' ? 'bg-brand text-white' : ''}`}>\n              Perp\n            \u003C\u002Fbutton>\n          \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n        \u003CChainSelector value={chain} onChange={setChain} \u002F>\n      \u003C\u002Fheader>\n\n      {\u002F* Main grid — responsive *\u002F}\n      \u003Cdiv className=\"grid grid-cols-1 lg:grid-cols-[1fr_380px] gap-0 lg:gap-4 p-4\">\n        {\u002F* Left: Chart + Token search + Positions *\u002F}\n        \u003Cdiv className=\"space-y-4\">\n          {mode === 'spot' && (\n            \u003CTokenSearch chain={chain}\n              onSelect={token => setSelectedToken(token.address)} \u002F>\n          )}\n\n          {\u002F* Chart placeholder — integrate TradingView or Lightweight Charts *\u002F}\n          \u003Cdiv className=\"bg-[var(--bg-card)] border border-[var(--border-primary)] rounded-lg h-[400px] flex items-center justify-center text-[var(--text-secondary)]\">\n            Chart — TradingView or Lightweight Charts\n          \u003C\u002Fdiv>\n\n          {\u002F* Positions \u002F Open orders *\u002F}\n          {mode === 'perp' && (\n            \u003Cdiv className=\"bg-[var(--bg-card)] border border-[var(--border-primary)] rounded-lg p-4\">\n              \u003Ch2 className=\"text-sm font-bold mb-3\">Open Positions\u003C\u002Fh2>\n              \u003CPositionTable \u002F>\n            \u003C\u002Fdiv>\n          )}\n        \u003C\u002Fdiv>\n\n        {\u002F* Right: Order form *\u002F}\n        \u003Cdiv className=\"bg-[var(--bg-card)] border border-[var(--border-primary)] rounded-lg p-4 h-fit lg:sticky lg:top-4\">\n          \u003Ch2 className=\"text-sm font-bold mb-3\">\n            {mode === 'spot' ? 'Spot Trade' : 'Perp Order'}\n          \u003C\u002Fh2>\n          {mode === 'spot'\n            ? \u003CSpotTradeForm defaultChain={chain} \u002F>\n            : \u003CPerpOrderForm \u002F>\n          }\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n### Layout Grid (responsive)\n\n```\nMobile (\u003C 1024px):          Desktop (≥ 1024px):\n┌────────────────┐          ┌──────────────┬─────────┐\n│ Token Search   │          │ Token Search │ Order   │\n├────────────────┤          ├──────────────┤ Form    │\n│ Chart          │          │ Chart        │         │\n├────────────────┤          ├──────────────┤         │\n│ Positions      │          │ Positions    │         │\n├────────────────┤          └──────────────┴─────────┘\n│ Order Form     │\n└────────────────┘\n```\n\n## Portfolio Page\n\n```typescript\n\u002F\u002F app\u002Fportfolio\u002Fpage.tsx\n'use client';\n\nimport { useState } from 'react';\nimport { PortfolioOverview } from '@\u002Fcomponents\u002FPortfolioOverview';\nimport { TokenBalanceGrid } from '@\u002Fcomponents\u002FTokenBalanceGrid';\nimport { TradeHistoryTable } from '@\u002Fcomponents\u002FTradeHistoryTable';\nimport { ChainSelector } from '@\u002Fcomponents\u002FChainSelector';\n\nexport default function PortfolioPage() {\n  const [chain, setChain] = useState('all');\n  const [tab, setTab] = useState\u003C'balances' | 'history'>('balances');\n\n  return (\n    \u003Cdiv className=\"min-h-screen bg-[var(--bg-primary)] text-[var(--text-primary)] p-4 space-y-6\">\n      \u003Ch1 className=\"text-2xl font-bold\">Portfolio\u003C\u002Fh1>\n\n      {\u002F* Overview cards *\u002F}\n      \u003CPortfolioOverview \u002F>\n\n      {\u002F* Chain filter *\u002F}\n      \u003CChainSelector value={chain} onChange={setChain} \u002F>\n\n      {\u002F* Tabs *\u002F}\n      \u003Cdiv className=\"flex gap-4 border-b border-[var(--border-primary)]\">\n        \u003Cbutton onClick={() => setTab('balances')}\n          className={`pb-2 text-sm ${tab === 'balances' ? 'border-b-2 border-brand font-bold' : 'text-[var(--text-secondary)]'}`}>\n          Token Balances\n        \u003C\u002Fbutton>\n        \u003Cbutton onClick={() => setTab('history')}\n          className={`pb-2 text-sm ${tab === 'history' ? 'border-b-2 border-brand font-bold' : 'text-[var(--text-secondary)]'}`}>\n          Trade History\n        \u003C\u002Fbutton>\n      \u003C\u002Fdiv>\n\n      {\u002F* Content *\u002F}\n      {tab === 'balances'\n        ? \u003CTokenBalanceGrid chain={chain === 'all' ? undefined : chain} \u002F>\n        : \u003CTradeHistoryTable \u002F>\n      }\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n## Copy Trading Page\n\n```typescript\n\u002F\u002F app\u002Fcopy-trade\u002Fpage.tsx\n'use client';\n\nimport { useState } from 'react';\nimport { CopyTradePanel } from '@\u002Fcomponents\u002FCopyTradePanel';\n\nexport default function CopyTradingPage() {\n  const [platform, setPlatform] = useState\u003C'solana' | 'hyperliquid'>('solana');\n\n  return (\n    \u003Cdiv className=\"min-h-screen bg-[var(--bg-primary)] text-[var(--text-primary)] p-4 space-y-6\">\n      \u003Cdiv className=\"flex items-center justify-between\">\n        \u003Ch1 className=\"text-2xl font-bold\">Copy Trading\u003C\u002Fh1>\n        \u003Cdiv className=\"flex gap-2\">\n          \u003Cbutton onClick={() => setPlatform('solana')}\n            className={`px-3 py-1.5 rounded text-sm ${platform === 'solana' ? 'bg-[var(--color-chain-solana)] text-white' : 'border'}`}>\n            Solana Spot\n          \u003C\u002Fbutton>\n          \u003Cbutton onClick={() => setPlatform('hyperliquid')}\n            className={`px-3 py-1.5 rounded text-sm ${platform === 'hyperliquid' ? 'bg-brand text-white' : 'border'}`}>\n            HL Perp\n          \u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n\n      \u003Cdiv className=\"grid grid-cols-1 lg:grid-cols-[1fr_400px] gap-6\">\n        {\u002F* Left: Leaderboard \u002F Top traders *\u002F}\n        \u003Cdiv className=\"bg-[var(--bg-card)] border border-[var(--border-primary)] rounded-lg p-4\">\n          \u003Ch2 className=\"text-lg font-bold mb-4\">Top Traders\u003C\u002Fh2>\n          \u003Cp className=\"text-sm text-[var(--text-secondary)]\">\n            {platform === 'solana' ? 'Top Solana spot traders by PnL' : 'Top HyperLiquid perp traders by PnL'}\n          \u003C\u002Fp>\n          {\u002F* Trader leaderboard list *\u002F}\n        \u003C\u002Fdiv>\n\n        {\u002F* Right: Active copy trades *\u002F}\n        \u003Cdiv className=\"bg-[var(--bg-card)] border border-[var(--border-primary)] rounded-lg p-4\">\n          \u003Ch2 className=\"text-lg font-bold mb-4\">Your Copy Trades\u003C\u002Fh2>\n          \u003CCopyTradePanel \u002F>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n## Bridge Page\n\n```typescript\n\u002F\u002F app\u002Fbridge\u002Fpage.tsx\n'use client';\n\nimport { useState } from 'react';\nimport { useGdex } from '@\u002Fproviders\u002FGdexProvider';\nimport { ChainSwitcher } from '@\u002Fcomponents\u002FChainSwitcher';\n\nexport default function BridgePage() {\n  const { skill, isReady } = useGdex();\n  const [fromChain, setFromChain] = useState(1);\n  const [toChain, setToChain] = useState(622112261);\n  const [amount, setAmount] = useState('');\n  const [estimate, setEstimate] = useState\u003Cany>(null);\n  const [loading, setLoading] = useState(false);\n\n  const getEstimate = async () => {\n    if (!isReady || !amount) return;\n    setLoading(true);\n    try {\n      const est = await skill.estimateBridge({\n        fromChainId: fromChain,\n        toChainId: toChain,\n        amount,   \u002F\u002F raw units of the source native token (wei \u002F lamports)\n      });\n      setEstimate(est);\n    } finally {\n      setLoading(false);\n    }\n  };\n\n  return (\n    \u003Cdiv className=\"min-h-screen bg-[var(--bg-primary)] text-[var(--text-primary)] p-4\">\n      \u003Ch1 className=\"text-2xl font-bold mb-6\">Bridge\u003C\u002Fh1>\n\n      \u003Cdiv className=\"max-w-lg mx-auto bg-[var(--bg-card)] border border-[var(--border-primary)] rounded-lg p-6 space-y-4\">\n        {\u002F* From chain *\u002F}\n        \u003Cdiv>\n          \u003Clabel className=\"text-xs text-[var(--text-secondary)] mb-1 block\">From\u003C\u002Flabel>\n          \u003CChainSwitcher value={fromChain} onChange={setFromChain} \u002F>\n        \u003C\u002Fdiv>\n\n        {\u002F* Swap button *\u002F}\n        \u003Cdiv className=\"flex justify-center\">\n          \u003Cbutton onClick={() => { setFromChain(toChain); setToChain(fromChain); }}\n            className=\"p-2 border rounded-full hover:bg-[var(--bg-tertiary)]\">\n            ↕\n          \u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n\n        {\u002F* To chain *\u002F}\n        \u003Cdiv>\n          \u003Clabel className=\"text-xs text-[var(--text-secondary)] mb-1 block\">To\u003C\u002Flabel>\n          \u003CChainSwitcher value={toChain} onChange={setToChain} \u002F>\n        \u003C\u002Fdiv>\n\n        {\u002F* Amount *\u002F}\n        \u003Cinput type=\"number\" placeholder=\"Amount (native token)\" value={amount}\n          onChange={e => setAmount(e.target.value)} step=\"any\" min=\"0\"\n          className=\"w-full p-3 border rounded-lg bg-[var(--bg-input)]\" \u002F>\n\n        {\u002F* Estimate *\u002F}\n        \u003Cbutton onClick={getEstimate} disabled={loading || !amount}\n          className=\"w-full py-3 bg-brand text-white rounded-lg font-bold disabled:opacity-50\">\n          {loading ? 'Getting estimate...' : 'Get Estimate'}\n        \u003C\u002Fbutton>\n\n        {estimate && (\n          \u003Cdiv className=\"border border-[var(--border-primary)] rounded-lg p-4 space-y-2 text-sm\">\n            \u003Cdiv className=\"flex justify-between\">\n              \u003Cspan className=\"text-[var(--text-secondary)]\">You receive\u003C\u002Fspan>\n              \u003Cspan className=\"font-bold\">{estimate.estimateAmount}\u003C\u002Fspan>\n            \u003C\u002Fdiv>\n            \u003Cdiv className=\"flex justify-between\">\n              \u003Cspan className=\"text-[var(--text-secondary)]\">ETA\u003C\u002Fspan>\n              \u003Cspan>{estimate.minEstimateTime}–{estimate.maxEstimateTime}s via {estimate.tool}\u003C\u002Fspan>\n            \u003C\u002Fdiv>\n            \u003Cbutton className=\"w-full py-2 mt-2 bg-brand text-white rounded-lg\">\n              Bridge Now\n            \u003C\u002Fbutton>\n          \u003C\u002Fdiv>\n        )}\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n## Navigation Layout\n\n```typescript\n\u002F\u002F components\u002FNavigation.tsx\n'use client';\n\nimport Link from 'next\u002Flink';\nimport { usePathname } from 'next\u002Fnavigation';\nimport { ConnectButton } from '.\u002FConnectButton';\nimport { ThemeToggle } from '.\u002FThemeToggle';\n\nconst NAV_ITEMS = [\n  { href: '\u002Ftrade', label: 'Trade' },\n  { href: '\u002Fportfolio', label: 'Portfolio' },\n  { href: '\u002Fcopy-trade', label: 'Copy Trade' },\n  { href: '\u002Fbridge', label: 'Bridge' },\n];\n\nexport function Navigation() {\n  const pathname = usePathname();\n\n  return (\n    \u003Cnav className=\"border-b border-[var(--border-primary)] bg-[var(--bg-primary)]\">\n      \u003Cdiv className=\"max-w-7xl mx-auto px-4 flex items-center justify-between h-14\">\n        \u003Cdiv className=\"flex items-center gap-6\">\n          \u003Cspan className=\"font-bold text-lg\">GDEX\u003C\u002Fspan>\n          {NAV_ITEMS.map(item => (\n            \u003CLink key={item.href} href={item.href}\n              className={`text-sm ${pathname === item.href\n                ? 'text-brand font-bold'\n                : 'text-[var(--text-secondary)] hover:text-[var(--text-primary)]'}`}>\n              {item.label}\n            \u003C\u002FLink>\n          ))}\n        \u003C\u002Fdiv>\n        \u003Cdiv className=\"flex items-center gap-3\">\n          \u003CThemeToggle \u002F>\n          \u003CConnectButton \u002F>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fnav>\n  );\n}\n```\n\n## Page → Component → SDK Method Map\n\n| Page | Components Used | SDK Methods |\n|------|----------------|-------------|\n| Trading | `SpotTradeForm`, `PerpOrderForm`, `PositionTable`, `TokenSearch`, `ChainSelector` | `buyToken`, `sellToken`, `hlCreateOrder`, `getPerpPositions`, `closePerpPosition`, `getTokenDetails` |\n| Portfolio | `PortfolioOverview`, `TokenBalanceGrid`, `TradeHistoryTable`, `ChainSelector` | `getPortfolio`, `getTradeHistory` |\n| Copy Trading | `CopyTradePanel` | `getCopyTradeList`, `getCopyTradeWallets` |\n| Bridge | `ChainSwitcher` | `estimateBridge`, `requestBridge` |\n\n## Related Skills\n\n- **gdex-ui-install-setup** — Project scaffolding to build these pages\n- **gdex-ui-trading-components** — Individual component patterns\n- **gdex-ui-portfolio-dashboard** — Dashboard-specific components\n- **gdex-ui-theming** — Theme tokens and CSS variables used throughout\n- **gdex-ui-wallet-connection** — ConnectButton and auth flows\n",{"name":5,"description":7},"main","3df1d0d67b30ff15236561f8c0f9f06d33f42dfd","skills\u002Fmcp-servers\u002Fgemachdao-gdex-ui-page-layouts",17,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia","https:\u002F\u002Feth2030.com","Hardcore infra. Building @alt-research and applied cryptography.","2026-11-15 02:28:10",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add jiayaoqijia\u002Fcryptoskill --skill gdex-ui-page-layouts",{"tool":56,"command":57},"bunx","bunx skills add jiayaoqijia\u002Fcryptoskill --skill gdex-ui-page-layouts",{"tool":59,"command":60},"pnpm","pnpm dlx skills add jiayaoqijia\u002Fcryptoskill --skill gdex-ui-page-layouts","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fmcp-servers\u002Fgemachdao-gdex-ui-page-layouts\u002FSKILL.md",true,[64,68,74],{"path":65,"resourceType":65,"resourceTypeDesc":66,"sizeBytes":67,"sourceHtmlUrl":16},"LICENSE","许可证",1066,{"path":69,"resourceType":70,"resourceTypeDesc":71,"sizeBytes":72,"sourceHtmlUrl":73},"SOURCE.md","REFERENCE","参考文档",349,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fmcp-servers\u002Fgemachdao-gdex-ui-page-layouts\u002FSOURCE.md",{"path":75,"resourceType":70,"resourceTypeDesc":71,"sizeBytes":76,"sourceHtmlUrl":77},"TRUST.auto.yaml",2217,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fmcp-servers\u002Fgemachdao-gdex-ui-page-layouts\u002FTRUST.auto.yaml",[79,106,128,146,159,169],{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":83,"sourceHtmlUrl":84,"categories":85,"keywords":86,"publishedAt":36},"01M712C436EQYE43342Q4E7GG1","recipe-performance","Diagnose a specific MetaMask user flow's real-app performance and Sentry critical-user-flow telemetry with deterministic mm-harness recipes. Use for CUF boundaries, cold\u002Fwarm\u002Fbackground-resume behavior, latency regressions, lifecycle tags, duplicate or blocking network requests, long tasks, layout\u002Fpaint cost, screen redraws, React rerenders, or browser trace analysis where tests alone cannot prove the real app.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fwallets\u002Fmetamask-official-recipe-performance\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fwallets\u002Fmetamask-official-recipe-performance\u002FSKILL.md",[],[87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,30,103,104,105],"performance","recipe performance","recipe","mm","sentry","harness","app","deterministic","recipes","flow","cold","critical","analysis","tasks","react","browser","screen","network","metamask",{"skillNo":107,"name":108,"nameZh":6,"description":109,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":110,"licenseFileUrl":111,"sourceHtmlUrl":112,"categories":113,"keywords":114,"publishedAt":36},"01M70XT2F8A5CQZ81JBP98KSW3","mexc-spot-websocket","MEXC Spot WebSocket workflows for public streams, protobuf handling, depth maintenance, listen keys, and private streams without exposing API keys.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-websocket\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-websocket\u002FSKILL.md",[],[115,116,117,118,119,120,121,122,123,124,34,125,126,127],"mexc spot websocket","spot","websocket","api","workflows","public","listen","streams","depth","keys","api keys","maintenance","protobuf",{"skillNo":129,"name":130,"nameZh":6,"description":131,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":110,"licenseFileUrl":132,"sourceHtmlUrl":133,"categories":134,"keywords":135,"publishedAt":36},"01M70XT0MBXN3WZY1BKN0CPNKR","mexc-spot-rest","MEXC Spot REST workflows for public data, signed account requests, orders, wallet\u002Fadmin actions, and secure signing without exposing API keys.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-rest\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-rest\u002FSKILL.md",[],[136,116,137,138,139,140,141,125,34,124,142,143,144,120,145,119,118],"mexc spot rest","REST","admin","signing","Wallet","requests","actions","secure","data","orders",{"skillNo":147,"name":148,"nameZh":6,"description":149,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":110,"licenseFileUrl":150,"sourceHtmlUrl":151,"categories":152,"keywords":153,"publishedAt":36},"01M70XSYSVZ2N0N91XCAR2CAK0","mexc-futures-websocket","MEXC Futures WebSocket workflows for public streams, private account\u002Forder\u002Fposition streams, ping\u002Fpong, subscriptions, and depth maintenance.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-futures-websocket\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-futures-websocket\u002FSKILL.md",[],[154,155,117,156,157,126,34,158,123,122,120,119],"mexc futures websocket","futures","position","ping","subscriptions",{"skillNo":160,"name":161,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":162,"sourceHtmlUrl":163,"categories":164,"keywords":165,"publishedAt":36},"01M6H0ZWHVE5W04WG2DKQE2SQC","0xklen-version-and-refresh-sanctions-lists","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-version-and-refresh-sanctions-lists\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-version-and-refresh-sanctions-lists\u002FSKILL.md",[],[166,167,168],"refresh","0xklen version and refresh sanctions lists","version",{"skillNo":170,"name":171,"nameZh":6,"description":172,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":173,"sourceHtmlUrl":174,"categories":175,"keywords":176,"publishedAt":36},"01M6H0Z28Q3R8J0S799GJQWXM3","verify-tests-cover-changed-lines","Use when a PR adds code that the existing suite may not exercise. Measures patch coverage — the share of newly changed lines hit by tests — before approving.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-verify-tests-cover-changed-lines\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-verify-tests-cover-changed-lines\u002FSKILL.md",[],[177,178,179,180,181,182,183,184,185,186,187],"tests","cover","verify tests cover changed lines","verify","coverage","pr","exercise","use","patch","code","share"]