Skip to content

Commit

Permalink
add table component (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremy-babylonlabs authored Dec 4, 2024
1 parent 95e4bf9 commit c012efe
Show file tree
Hide file tree
Showing 21 changed files with 655 additions and 13 deletions.
11 changes: 7 additions & 4 deletions .changeset/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ We have a quick list of common questions to get you started engaging with this p
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

# Usage

1. `npx changeset` to create a changeset

2. Select change type:
2. Select change type:

```
Major:
Major:
- Describes when to use a major change, focusing on breaking changes.
Minor:
Minor:
- Describes when to use a minor change, focusing on new features that are backward compatible.
Patch:
Patch:
- Describes when to use a patch change, focusing on bug fixes and small improvements.
```

Expand All @@ -31,5 +33,6 @@ Patch:
9. After reviewing, merge the `Version Packages` PR on Github, the package version is then updated and published to npm.

Notes:

- The `Version Packages` is automatically updated with the latest changeset(s).
- The `Version Packages` will only update the package versions and publish to npm, not the actual code.
5 changes: 5 additions & 0 deletions .changeset/weak-drinks-punch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@babylonlabs-io/bbn-core-ui": minor
---

add table component
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ npm run storybook
Provide examples of how to use the library in a project. Include code snippets and explanations.

```javascript
import { ComponentName } from '@babylonlabs-io/bbn-core-ui';
import { ComponentName } from "@babylonlabs-io/bbn-core-ui";

function App() {
return <ComponentName prop="value" />;
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

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

Binary file added public/images/fps/lombard.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/fps/pumpbtc.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/fps/solv.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/Accordion/Accordion.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
@apply transition-opacity;

&-summary {
@apply cursor-pointer relative pr-5 transition-colors;
@apply relative cursor-pointer pr-5 transition-colors;
}

&-details {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Dialog/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@
&-mobile {
@apply fixed inset-x-0 bottom-0 z-50 flex flex-col rounded-t-3xl bg-[#ffffff] px-4 pb-4 pt-6;
}
}
}
189 changes: 189 additions & 0 deletions src/components/Table/Table.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/* Table wrapper styles - controls scrolling behavior */
.bbn-table-wrapper {
@apply relative h-full w-full overflow-auto;

/* Hide scrollbar for Firefox */
scrollbar-width: none;
/* Hide scrollbar for IE and Edge */
-ms-overflow-style: none;

/* Hide WebKit scrollbar */
&::-webkit-scrollbar {
display: none;
}
}

/* Main table styles */
.bbn-table {
@apply w-full border-separate border-spacing-0;

/* Header row styles */
&-header {
@apply sticky top-0 z-30 bg-secondary-contrast text-sm font-medium text-primary-light transition-shadow;

tr {
@apply relative;
}

/* Header cell styles */
th {
@apply whitespace-nowrap px-6 py-3 transition-all border-b border-[#f9f9f9];
width: var(--column-width);
min-width: var(--column-width);
max-width: var(--column-width);

&:first-child {
@apply border-l;
}

&:last-child {
@apply border-r;
}
}

/* First header cell when fixed */
th:first-child.bbn-table-fixed {
@apply sticky left-0 z-30 bg-secondary-contrast;
width: fit-content;
min-width: max-content;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

&.scrolled-top {
@apply shadow-[0_2px_4px_rgba(0,0,0,0.05)];
}
}

/* Table body styles */
&-body {
/* Row styles */
tr {
@apply transition-colors;

td {
@apply border-b border-t border-[#f9f9f9];

&:first-child {
@apply border-l;
}

&:last-child {
@apply border-r;
}
}

&:hover td {
@apply bg-primary-contrast;
}

&.selected td {
@apply bg-primary-contrast border-secondary-main;
}
}

/* Odd row styles */
tr:nth-child(odd) {
@apply bg-[#F9F9F9];

&:hover {
@apply bg-primary-contrast;
}

td.bbn-table-cell-hover {
@apply bg-primary-contrast/50;
}

/* First cell when fixed in odd rows */
td:first-child.bbn-table-fixed {
@apply sticky left-0 z-20 bg-[#F9F9F9];
width: fit-content;
min-width: max-content;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}

/* Even row styles */
tr:nth-child(even) {
@apply bg-secondary-contrast;

&:hover {
@apply bg-primary-contrast;
}

td.bbn-table-cell-hover {
@apply bg-primary-contrast/50;
}

/* First cell when fixed in even rows */
td:first-child.bbn-table-fixed {
@apply sticky left-0 z-20 bg-secondary-contrast;
width: fit-content;
min-width: max-content;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}

/* Standard cell styles */
td {
@apply px-6 py-4 text-sm text-primary-light transition-colors;
width: var(--column-width);
min-width: var(--column-width);
max-width: var(--column-width);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}

/* Sortable column styles */
&-sortable {
@apply cursor-pointer select-none;
}

/* Sort icons container */
&-sort-icons {
@apply ml-1 inline-flex flex-col;

svg {
@apply h-4 w-4;
}

/* Individual sort icon styles */
.bbn-sort-icon {
@apply text-primary/20 transition-colors;

&.bbn-sort-icon-up {
@apply -mb-1;
}

&.bbn-sort-icon-down {
@apply -mt-1;
}

&.bbn-sort-icon-active {
@apply !text-primary-light;
}

&.bbn-sort-icon-inactive {
@apply !text-primary/10;
}
}
}

/* Cell alignment styles */
&-cell {
&-right {
@apply text-right;
}

&-left {
@apply text-left;
}
}
}
121 changes: 121 additions & 0 deletions src/components/Table/Table.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import type { Meta, StoryObj } from "@storybook/react";
import { useState } from "react";

import { Table } from "./";
import { Avatar } from "../Avatar";

const meta: Meta<typeof Table> = {
component: Table,
tags: ["autodocs"],
};

export default meta;

type Story = StoryObj<typeof meta>;

interface FinalityProvider {
id: string;
name: string;
icon: string;
status: string;
btcPk: string;
totalDelegation: number;
commission: number;
}

const data: FinalityProvider[] = [
{
id: "1",
name: "Lombard",
icon: "/images/fps/lombard.jpeg",
status: "Active",
btcPk: "1234...4321",
totalDelegation: 10,
commission: 1,
},
{
id: "2",
name: "Solv Protocol",
icon: "/images/fps/solv.jpeg",
status: "Active",
btcPk: "1234...4321",
totalDelegation: 20,
commission: 3,
},
{
id: "3",
name: "PumpBTC",
icon: "/images/fps/pumpbtc.jpeg",
status: "Active",
btcPk: "1234...4321",
totalDelegation: 30,
commission: 5,
},
];

export const Default: Story = {
render: () => {
const [tableData, setTableData] = useState(data.slice(0, 3));
const [loading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(true);

const handleLoadMore = async () => {
setLoading(true);
await new Promise((resolve) => setTimeout(resolve, 1000));

const nextItems = data.slice(tableData.length, tableData.length + 3);
setTableData((prev) => [...prev, ...nextItems]);
setHasMore(tableData.length + nextItems.length < data.length);
setLoading(false);
};

const handleRowSelect = (row: FinalityProvider) => {
console.log(row);
};

return (
<div className="h-[150px]">
<Table
data={tableData}
hasMore={hasMore}
loading={loading}
onLoadMore={handleLoadMore}
onRowSelect={handleRowSelect}
columns={[
{
key: "name",
header: "Finality Provider",
render: (_, row) => (
<div className="flex items-center gap-2">
<Avatar size="small" url={row.icon} alt={row.name} />
<span className="text-primary-light">{row.name}</span>
</div>
),
sorter: (a, b) => a.name.localeCompare(b.name),
},
{
key: "status",
header: "Status",
},
{
key: "btcPk",
header: "BTC PK",
},
{
key: "totalDelegation",
header: "Total Delegation",
render: (value) => `${value} sBTC`,
sorter: (a, b) => a.totalDelegation - b.totalDelegation,
},
{
key: "commission",
header: "Commission",
render: (value) => `${value}%`,
sorter: (a, b) => a.commission - b.commission,
},
]}
/>
</div>
);
},
};
Loading

0 comments on commit c012efe

Please sign in to comment.