Skip to content
Merged
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
4 changes: 2 additions & 2 deletions packages/babylon-core-ui/src/components/List/List.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@


.bbn-list-title {
@apply text-accent-secondary;
@apply text-accent-secondary overflow-hidden text-ellipsis whitespace-nowrap;

&-adaptive {
@apply text-base md:text-sm;
}
}

.bbn-list-value {
@apply text-accent-primary;
@apply text-accent-primary overflow-hidden text-ellipsis;

&-horizontal {
@apply flex items-center gap-1;
Expand Down
168 changes: 168 additions & 0 deletions packages/babylon-core-ui/src/components/Tabs/Tabs.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import type { Meta, StoryObj } from "@storybook/react";
import { Tabs } from "./Tabs";
import { useState } from "react";

const meta: Meta<typeof Tabs> = {
title: "Components/Tabs",
component: Tabs,
tags: ["autodocs"],
parameters: {
docs: {
description: {
component:
"A tabs component for organizing content into multiple panels with tab navigation. Supports controlled and uncontrolled modes, as well as keeping all tab panels mounted.",
},
},
},
};

export default meta;
type Story = StoryObj<typeof Tabs>;

export const Default: Story = {
args: {
items: [
{
id: "tab1",
label: "Tab 1",
content: (
<div className="rounded bg-primary-highlight p-4 text-accent-primary">
Content for Tab 1
</div>
),
},
{
id: "tab2",
label: "Tab 2",
content: (
<div className="rounded bg-primary-highlight p-4 text-accent-primary">
Content for Tab 2
</div>
),
},
{
id: "tab3",
label: "Tab 3",
content: (
<div className="rounded bg-primary-highlight p-4 text-accent-primary">
Content for Tab 3
</div>
),
},
],
defaultActiveTab: "tab1",
},
};

export const Controlled: Story = {
render: () => {
const [activeTab, setActiveTab] = useState("tab1");
return (
<div>
<div className="mb-4 text-accent-secondary text-sm">
Active tab: {activeTab}
</div>
<Tabs
items={[
{
id: "tab1",
label: "Tab 1",
content: (
<div className="rounded bg-primary-highlight p-4 text-accent-primary">
Controlled Tab 1 Content
</div>
),
},
{
id: "tab2",
label: "Tab 2",
content: (
<div className="rounded bg-primary-highlight p-4 text-accent-primary">
Controlled Tab 2 Content
</div>
),
},
]}
activeTab={activeTab}
onTabChange={setActiveTab}
/>
</div>
);
},
};

export const KeepMounted: Story = {
args: {
items: [
{
id: "tab1",
label: "Form Tab",
content: (
<div className="rounded bg-primary-highlight p-4">
<input
type="text"
placeholder="This input state is preserved when switching tabs"
className="w-full rounded border border-secondary-strokeLight bg-surface p-2 text-accent-primary"
/>
</div>
),
},
{
id: "tab2",
label: "Another Tab",
content: (
<div className="rounded bg-primary-highlight p-4 text-accent-primary">
Switch back to Form Tab - your input will still be there!
</div>
),
},
],
keepMounted: true,
defaultActiveTab: "tab1",
},
};

export const ManyTabs: Story = {
args: {
items: [
{
id: "stake",
label: "Stake",
content: (
<div className="rounded bg-primary-highlight p-4 text-accent-primary">
Stake Content
</div>
),
},
{
id: "activity",
label: "Activity",
content: (
<div className="rounded bg-primary-highlight p-4 text-accent-primary">
Activity Content
</div>
),
},
{
id: "rewards",
label: "Rewards",
content: (
<div className="rounded bg-primary-highlight p-4 text-accent-primary">
Rewards Content
</div>
),
},
{
id: "faqs",
label: "FAQs",
content: (
<div className="rounded bg-primary-highlight p-4 text-accent-primary">
FAQs Content
</div>
),
},
],
defaultActiveTab: "stake",
},
};

Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { ReactNode, useEffect, useState } from "react";
import { twMerge } from "tailwind-merge";

interface TabItem {
export interface TabItem {
id: string;
label: string;
content: ReactNode;
}

interface TabsProps {
export interface TabsProps {
items: TabItem[];
defaultActiveTab?: string;
activeTab?: string;
Expand Down Expand Up @@ -97,3 +97,4 @@ export const Tabs = ({
</div>
);
};

3 changes: 3 additions & 0 deletions packages/babylon-core-ui/src/components/Tabs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { Tabs } from "./Tabs";
export type { TabItem, TabsProps } from "./Tabs";

1 change: 1 addition & 0 deletions packages/babylon-core-ui/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export * from "./components/Badge";
export * from "./components/SubSection";
export * from "./components/CounterButton";
export * from "./components/Menu";
export * from "./components/Tabs";
export * from "./components/AmountItem";
export * from "./components/CoStakingAmountItem";
export * from "./components/DisplayHash";
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions routes/vault/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"dependencies": {
"@babylonlabs-io/core-ui": "workspace:*",
"@babylonlabs-io/wallet-connector": "workspace:*",
"react-icons": "5.3.0",
"react-router": "7.6.3"
},
"devDependencies": {
Expand Down
17 changes: 11 additions & 6 deletions routes/vault/src/VaultLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { Card } from "@babylonlabs-io/core-ui";
import { VaultStats, VaultOverviewPanel } from "./components";

const isVaultEnabled = process.env.NEXT_PUBLIC_FF_VAULT === "true";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we need to use FeatureFlagService.IsVaultEnabled


export default function VaultLayout() {
if (!isVaultEnabled) {
return null;
}

return (
<div className="container mx-auto flex max-w-[760px] flex-1 flex-col gap-12 px-4">
<Card className="bg-surface flex flex-col gap-6 p-6">
<h1 className="text-primary text-2xl font-bold">hello vault</h1>
</Card>
<div className="container mx-auto flex max-w-[760px] flex-1 flex-col gap-6 px-4 py-6 max-md:gap-4 max-md:px-0 max-md:pt-0 max-md:pb-4">
<VaultStats />
<VaultOverviewPanel />
</div>
);
}
}
40 changes: 40 additions & 0 deletions routes/vault/src/components/DepositOverview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { IconButton } from "@babylonlabs-io/core-ui";
import { AiOutlinePlus } from "react-icons/ai";

export function DepositOverview() {
const handleAddDeposit = () => {
console.log("Add deposit clicked");
};

return (
<div className="rounded-2xl bg-primary-contrast p-6">
<div className="flex flex-col items-center">
<img
src="/mascot-bitcoin.png"
alt="Supply collateral mascot"
className="h-auto max-w-[240px]"
/>
<div className="flex flex-col gap-1 text-center">
<h4 className="text-lg font-semibold text-accent-primary">
Supply Collateral BTC Trustlessly
</h4>
<p className="text-sm text-accent-secondary">
Enter the amount of BTC you want to deposit and select a provider to secure it.
<br />
Your deposit will appear here once confirmed.
</p>
</div>
<div className="mt-8">
<IconButton
variant="outlined"
size="large"
onClick={handleAddDeposit}
aria-label="Add deposit"
>
<AiOutlinePlus />
</IconButton>
</div>
</div>
</div>
);
}
61 changes: 61 additions & 0 deletions routes/vault/src/components/MarketOverview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import type { Market } from "../types/market";

const columns = [
{ field: "loan" as const, headerName: "Loan", align: "left" as const, width: "1fr" },
{ field: "ltv" as const, headerName: "LTV", align: "left" as const, width: "1fr" },
{ field: "marketSize" as const, headerName: "Market Size", align: "left" as const, width: "1fr" },
{ field: "totalLiquidity" as const, headerName: "Total Liquidity", align: "left" as const, width: "1fr" },
{ field: "rate" as const, headerName: "Rate", align: "right" as const, width: "1fr" },
];

export function MarketOverview() {
const markets: Market[] = [];

return (
<div className="overflow-x-auto">
<div
className="grid min-w-[600px]"
style={{
gridTemplateColumns: columns.map((col) => col.width).join(" "),
}}
>
<div className="contents">
{columns.map((col) => (
<div
key={col.field}
className={`p-4 text-xs text-accent-secondary ${
col.align === "right" ? "text-right" : "text-left"
}`}
>
{col.headerName}
</div>
))}
</div>

{markets.length === 0 && (
<div
className="col-span-full py-8 text-center text-sm text-accent-secondary"
style={{ gridColumn: "1 / -1" }}
>
No markets available
</div>
)}

{markets.map((market) => (
<div key={market.id} className="contents">
{columns.map((col) => (
<div
key={`${market.id}-${col.field}`}
className={`p-4 text-sm text-accent-primary ${
col.align === "right" ? "text-right" : "text-left"
}`}
>
{market[col.field]}
</div>
))}
</div>
))}
</div>
</div>
);
}
Loading