Skip to content

Commit

Permalink
Merge pull request #15 from kir-dev/feat/band-list
Browse files Browse the repository at this point in the history
Feat/band list
  • Loading branch information
justnyx authored Dec 19, 2024
2 parents fcb347a + c1283b2 commit 13bdf4a
Show file tree
Hide file tree
Showing 10 changed files with 720 additions and 17 deletions.
3 changes: 3 additions & 0 deletions apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"@radix-ui/react-dropdown-menu": "^2.1.2",
"@radix-ui/react-slider": "^1.2.1",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-collapsible": "^1.1.1",
"@tanstack/react-table": "^8.20.5",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"framer-motion": "^11.14.4",
Expand All @@ -25,6 +27,7 @@
"next-themes": "^0.4.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"shadcn": "^2.1.7",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7"
},
Expand Down
43 changes: 43 additions & 0 deletions apps/frontend/src/app/bands/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use client';

import { useEffect, useState } from 'react';

import BandRow from '@/components/band/bandRow';
import { Input } from '@/components/ui/input';
import { Table, TableBody, TableCell, TableRow } from '@/components/ui/table';
import { dummyBands } from '@/mocks/bands';

export default function Bands() {
const data = dummyBands;
const [filteredData, setFilteredData] = useState(data);
const [searchTerm, setSearchTerm] = useState('');
useEffect(() => {
setFilteredData(data.filter((band) => band.name.toLowerCase().includes(searchTerm.toLowerCase())));
}, [searchTerm]);
return (
<div className='w-full'>
<div className='flex items-center justify-between flex-row p-4'>
<h1 className='text-2xl font-semibold text-orange-500'>Zenekarok</h1>
<Input
placeholder='Keresés...'
value={searchTerm}
onChange={(event) => setSearchTerm(event.target.value)}
className='max-w-sm text-black target:ring-0'
/>
</div>
<Table>
<TableBody>
{filteredData.length ? (
filteredData.map((band) => <BandRow band={band} key={band.id} />)
) : (
<TableRow>
<TableCell colSpan={4} className='h-24 text-center'>
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
);
}
48 changes: 48 additions & 0 deletions apps/frontend/src/components/band/bandRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Play } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
import { TableCell, TableRow } from '@/components/ui/table';
import { Band } from '@/types/band';

export default function BandRow({ band }: { band: Band }) {
return (
<Collapsible key={band.id} asChild>
<>
<TableRow className='border-0'>
<TableCell colSpan={3}>
<div>
<strong className='text-xl'>{band.name}</strong>
<h1>{band.genres}</h1>
</div>
</TableCell>
<TableCell>{band.webPage}</TableCell>
<TableCell>
<a href={`mailto:${band.email}`}>{band.email}</a>
</TableCell>
<TableCell>{band.members?.length || 0} tag</TableCell>
<TableCell>
<CollapsibleTrigger asChild className='data-[state=open]:rotate-90 transition-all duration-300'>
<Button size='icon' variant='ghost'>
<Play className='h-4 w-4' />
</Button>
</CollapsibleTrigger>
</TableCell>
</TableRow>
<TableRow className='border-0 '>
<CollapsibleContent asChild>
<TableCell colSpan={7}>
<div className='flex flex-row justify-between px-4 gap-8 '>
<div>{band.description}</div>
<div>
<strong>Tagok: </strong>
{band.members?.join(', ')}
</div>
</div>
</TableCell>
</CollapsibleContent>
</TableRow>
</>
</Collapsible>
);
}
11 changes: 11 additions & 0 deletions apps/frontend/src/components/ui/collapsible.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use client';

import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';

const Collapsible = CollapsiblePrimitive.Root;

const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;

const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;

export { Collapsible, CollapsibleContent, CollapsibleTrigger };
1 change: 1 addition & 0 deletions apps/frontend/src/components/ui/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as React from 'react';
import { cn } from '@/lib/utils';

const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
// eslint-disable-next-line react/prop-types
({ className, type, ...props }, ref) => {
return (
<input
Expand Down
80 changes: 80 additions & 0 deletions apps/frontend/src/components/ui/table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/* eslint-disable react/prop-types */
import * as React from 'react';

import { cn } from '@/lib/utils';

const Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(
({ className, ...props }, ref) => (
<div className='relative w-full overflow-auto'>
<table ref={ref} className={cn('w-full caption-bottom text-sm', className)} {...props} />
</div>
)
);
Table.displayName = 'Table';

const TableHeader = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(
({ className, ...props }, ref) => <thead ref={ref} className={cn('[&_tr]:border-b', className)} {...props} />
);
TableHeader.displayName = 'TableHeader';

const TableBody = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(
({ className, ...props }, ref) => (
<tbody ref={ref} className={cn('[&_tr:last-child]:border-0', className)} {...props} />
)
);
TableBody.displayName = 'TableBody';

const TableFooter = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(
({ className, ...props }, ref) => (
<tfoot
ref={ref}
className={cn('border-t bg-slate-100/50 font-medium [&>tr]:last:border-b-0 dark:bg-slate-800/50', className)}
{...props}
/>
)
);
TableFooter.displayName = 'TableFooter';

const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(
({ className, ...props }, ref) => (
<tr
ref={ref}
className={cn(
'border-b transition-colors hover:bg-slate-100/50 data-[state=selected]:bg-slate-100 dark:hover:bg-slate-800/50 dark:data-[state=selected]:bg-slate-800',
className
)}
{...props}
/>
)
);
TableRow.displayName = 'TableRow';

const TableHead = React.forwardRef<HTMLTableCellElement, React.ThHTMLAttributes<HTMLTableCellElement>>(
({ className, ...props }, ref) => (
<th
ref={ref}
className={cn(
'h-12 px-4 text-left align-middle font-medium text-slate-500 [&:has([role=checkbox])]:pr-0 dark:text-slate-400',
className
)}
{...props}
/>
)
);
TableHead.displayName = 'TableHead';

const TableCell = React.forwardRef<HTMLTableCellElement, React.TdHTMLAttributes<HTMLTableCellElement>>(
({ className, ...props }, ref) => (
<td ref={ref} className={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)} {...props} />
)
);
TableCell.displayName = 'TableCell';

const TableCaption = React.forwardRef<HTMLTableCaptionElement, React.HTMLAttributes<HTMLTableCaptionElement>>(
({ className, ...props }, ref) => (
<caption ref={ref} className={cn('mt-4 text-sm text-slate-500 dark:text-slate-400', className)} {...props} />
)
);
TableCaption.displayName = 'TableCaption';

export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow };
49 changes: 49 additions & 0 deletions apps/frontend/src/mocks/bands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Band } from '@/types/band';

export const dummyBands: Band[] = [
{
id: '1',
name: 'The Echoes',
email: '[email protected]',
webPage: 'http://www.theechoes.com',
description: 'A soulful indie band blending melodic sounds with poignant lyrics.',
genres: 'Indie, Soul, Alternative',
members: ['Alice Walker', 'Jake Miles', 'Sophie Lee'],
},
{
id: '2',
name: 'Raging Tides',
email: '[email protected]',
webPage: 'http://www.ragingtidesband.com',
description: 'A high-energy rock band known for electrifying live performances.',
genres: 'Rock, Metal',
members: ['Liam Carter', 'Nina Wells', 'Tommy Drake'],
},
{
id: '3',
name: 'Starlight Symphony',
email: '[email protected]',
webPage: 'http://www.starlightsymphony.com',
description: 'An orchestral ensemble mixing classical music with modern influences.',
genres: 'Classical, Fusion',
members: ['Emma Clarke', 'Olivia Martinez', 'Jonathan Kim', 'Ethan Moore'],
},
{
id: '4',
name: 'Neon Dreams',
email: '[email protected]',
webPage: 'http://www.neondreams.com',
description: 'An electronic band with vibrant beats and immersive soundscapes.',
genres: 'Electronic, Synthwave',
members: ['Amy Chen', 'Brandon Davis'],
},
{
id: '5',
name: 'Crimson Folk',
email: '[email protected]',
webPage: 'http://www.crimsonfolk.com',
description: 'A folk band with a passion for storytelling through music.',
genres: 'Folk, Acoustic',
members: ['Rachel Green', 'Luke Harper', 'Ella Brown'],
},
];
9 changes: 9 additions & 0 deletions apps/frontend/src/types/band.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type Band = {
id: string;
name: string;
email: string;
webPage: string;
description: string;
genres?: string;
members?: string[];
};
3 changes: 2 additions & 1 deletion apps/frontend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
}
],
"paths": {
"@/*": ["./src/*"]
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
Expand Down
Loading

0 comments on commit 13bdf4a

Please sign in to comment.