Skip to content

Commit

Permalink
add table component
Browse files Browse the repository at this point in the history
  • Loading branch information
FelixTJDietrich committed Sep 11, 2024
1 parent 23c3967 commit 314ecc5
Show file tree
Hide file tree
Showing 9 changed files with 279 additions and 0 deletions.
18 changes: 18 additions & 0 deletions webapp/src/app/ui/table/table-body.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Component, computed, input } from '@angular/core';
import { ClassValue } from 'clsx';
import { cn } from 'app/utils';

@Component({
selector: 'app-table-body',
standalone: true,
template: `<ng-content />`,
host: {
'[class]': 'computedClass()',
style: 'display: table-row-group;'
}
})
export class TableBodyComponent {
class = input<ClassValue>();

computedClass = computed(() => cn('[&_tr:last-child]:border-0', this.class()));
}
18 changes: 18 additions & 0 deletions webapp/src/app/ui/table/table-caption.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Component, computed, input } from '@angular/core';
import { ClassValue } from 'clsx';
import { cn } from 'app/utils';

@Component({
selector: 'app-table-caption',
standalone: true,
template: `<ng-content />`,
host: {
'[class]': 'computedClass()',
style: 'display: table-caption;'
}
})
export class TableCaptionComponent {
class = input<ClassValue>();

computedClass = computed(() => cn('mt-4 text-sm text-muted-foreground', this.class()));
}
26 changes: 26 additions & 0 deletions webapp/src/app/ui/table/table-cell.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Component, computed, input } from '@angular/core';
import { ClassValue } from 'clsx';
import { cn } from 'app/utils';

@Component({
selector: 'app-table-cell',
standalone: true,
template: `<ng-content />`,
host: {
'[class]': 'computedClass()',
style: 'display: table-cell;',
'[attr.colspan]': 'colspan()',
'[attr.headers]': 'headers()',
'[attr.rowspan]': 'rowspan()',
'[attr.data-cell]': 'true'
}
})
export class TableCellComponent {
class = input<ClassValue>();

colspan = input<number>();
headers = input<string>();
rowspan = input<number>();

computedClass = computed(() => cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', this.class()));
}
18 changes: 18 additions & 0 deletions webapp/src/app/ui/table/table-footer.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Component, computed, input } from '@angular/core';
import { ClassValue } from 'clsx';
import { cn } from 'app/utils';

@Component({
selector: 'app-table-footer',
standalone: true,
template: `<ng-content />`,
host: {
'[class]': 'computedClass()',
style: 'display: table-footer-group;'
}
})
export class TableFooterComponent {
class = input<ClassValue>();

computedClass = computed(() => cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', this.class()));
}
31 changes: 31 additions & 0 deletions webapp/src/app/ui/table/table-head.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Component, computed, input } from '@angular/core';
import { ClassValue } from 'clsx';
import { cn } from 'app/utils';

type TableHeadScope = 'col' | 'colgroup' | 'row' | 'rowgroup';

@Component({
selector: 'app-table-head',
standalone: true,
template: `<ng-content />`,
host: {
'[class]': 'computedClass()',
style: 'display: table-cell;',
'[attr.abbr]': 'abbr()',
'[attr.colspan]': 'colspan()',
'[attr.headers]': 'headers()',
'[attr.rowspan]': 'rowspan()',
'[attr.scope]': 'scope()'
}
})
export class TableHeadComponent {
class = input<ClassValue>();

abbr = input<string>();
colspan = input<number>();
headers = input<string>();
rowspan = input<number>();
scope = input<TableHeadScope>();

computedClass = computed(() => cn('h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0', this.class()));
}
18 changes: 18 additions & 0 deletions webapp/src/app/ui/table/table-header.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Component, computed, input } from '@angular/core';
import { ClassValue } from 'clsx';
import { cn } from 'app/utils';

@Component({
selector: 'app-table-header',
standalone: true,
template: `<ng-content />`,
host: {
'[class]': 'computedClass()',
style: 'display: table-header-group;'
}
})
export class TableHeaderComponent {
class = input<ClassValue>();

computedClass = computed(() => cn('w-full caption-bottom text-sm', this.class()));
}
18 changes: 18 additions & 0 deletions webapp/src/app/ui/table/table-row.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Component, computed, input } from '@angular/core';
import { ClassValue } from 'clsx';
import { cn } from 'app/utils';

@Component({
selector: 'app-table-row',
standalone: true,
template: `<ng-content />`,
host: {
'[class]': 'computedClass()',
style: 'display: table-row;'
}
})
export class TableRowComponent {
class = input<ClassValue>();

computedClass = computed(() => cn('border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted', this.class()));
}
19 changes: 19 additions & 0 deletions webapp/src/app/ui/table/table.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Component, computed, input } from '@angular/core';
import { ClassValue } from 'clsx';
import { cn } from 'app/utils';

@Component({
selector: 'app-table',
standalone: true,
template: `<table [class]="computedClass()">
<ng-content />
</table>`,
host: {
class: 'relative w-full overflow-auto'
}
})
export class TableComponent {
class = input<ClassValue>();

computedClass = computed(() => cn('w-full caption-bottom text-sm', this.class()));
}
113 changes: 113 additions & 0 deletions webapp/src/app/ui/table/table.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
import { TableComponent } from './table.component';
import { TableBodyComponent } from './table-body.component';
import { TableCaptionComponent } from './table-caption.component';
import { TableCellComponent } from './table-cell.component';
import { TableFooterComponent } from './table-footer.component';
import { TableHeaderComponent } from './table-header.component';
import { TableHeadComponent } from './table-head.component';
import { TableRowComponent } from './table-row.component';

type CustomArgs = {
invoices: {
invoice: string;
paymentStatus: string;
totalAmount: string;
paymentMethod: string;
}[];
};

const meta: Meta<CustomArgs> = {
title: 'UI/Table',
component: TableComponent,
decorators: [
moduleMetadata({
imports: [TableBodyComponent, TableCaptionComponent, TableCellComponent, TableFooterComponent, TableHeaderComponent, TableHeadComponent, TableRowComponent]
})
],
tags: ['autodocs'],
args: {
invoices: [
{
invoice: 'INV001',
paymentStatus: 'Paid',
totalAmount: '$250.00',
paymentMethod: 'Credit Card'
},
{
invoice: 'INV002',
paymentStatus: 'Pending',
totalAmount: '$150.00',
paymentMethod: 'PayPal'
},
{
invoice: 'INV003',
paymentStatus: 'Unpaid',
totalAmount: '$350.00',
paymentMethod: 'Bank Transfer'
},
{
invoice: 'INV004',
paymentStatus: 'Paid',
totalAmount: '$450.00',
paymentMethod: 'Credit Card'
},
{
invoice: 'INV005',
paymentStatus: 'Paid',
totalAmount: '$550.00',
paymentMethod: 'PayPal'
},
{
invoice: 'INV006',
paymentStatus: 'Pending',
totalAmount: '$200.00',
paymentMethod: 'Bank Transfer'
},
{
invoice: 'INV007',
paymentStatus: 'Unpaid',
totalAmount: '$300.00',
paymentMethod: 'Credit Card'
}
]
}
};

export default meta;
type Story = StoryObj<TableComponent>;

export const Default: Story = {
render: (args) => ({
props: args,
template: `
<app-table>
<app-table-caption>A list of your recent invoices.</app-table-caption>
<app-table-header>
<app-table-row>
<app-table-head class="w-[100px]">Invoice</app-table-head>
<app-table-head>Status</app-table-head>
<app-table-head>Method</app-table-head>
<app-table-head class="text-right">Amount</app-table-head>
</app-table-row>
</app-table-header>
<app-table-body>
@for (invoice of invoices; track invoice.invoice) {
<app-table-row>
<app-table-cell class="font-medium">{{invoice.invoice}}</app-table-cell>
<app-table-cell>{{invoice.paymentStatus}}</app-table-cell>
<app-table-cell>{{invoice.paymentMethod}}</app-table-cell>
<app-table-cell class="text-right">{{invoice.totalAmount}}</app-table-cell>
</app-table-row>
}
</app-table-body>
<app-table-footer>
<app-table-row>
<app-table-cell colspan="3">Total</app-table-cell>
<app-table-cell class="text-right">$2,500.00</app-table-cell>
</app-table-row>
</app-table-footer>
</app-table>
`
})
};

0 comments on commit 314ecc5

Please sign in to comment.