rewrite table styles from tailwind into scss

This commit is contained in:
smanylov
2025-12-30 13:35:20 +07:00
parent 1032c5420b
commit f16e527a32
4 changed files with 330 additions and 107 deletions
+76 -79
View File
@@ -48,15 +48,15 @@ type ApiResponse = {
const FileTypeIcon = ({ type }: { type: string }) => {
switch (type) {
case 'image':
return <span className="text-[#f08c00]">
return <span className="color-image">
<IconImageFile />
</span>;
case 'video':
return <span className="text-[#2f9e44]">
return <span className="color-video">
<IconVideoFile />
</span>;
case 'audio':
return <span className="text-[#1971c2]">
return <span className="color-audio">
<IconAudioFile />
</span>;
default:
@@ -136,13 +136,13 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
{
accessorKey: 'fileName',
header: ({ column }) => (
<div className="flex items-center justify-start">
<div className="column start">
<span>
{t('file')}
</span>
<button
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
className="ml-2 p-1 hover:bg-gray-200 rounded"
className="sort-button"
>
{
column.getIsSorted() === 'asc' ?
@@ -164,7 +164,7 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
<div className="flex items-center space-x-2 w-[250px]">
<FileTypeIcon type={row.original.fileType} />
<div>
<div className="font-medium w-full max-w-[300px] truncate" title={row.original.fileName}>{row.original.fileName}</div>
<div className="font-medium w-full max-w-[250px] truncate" title={row.original.fileName}>{row.original.fileName}</div>
</div>
</div>
),
@@ -173,13 +173,13 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
{
accessorKey: 'status',
header: ({ column }) => (
<div className="flex items-center justify-center">
<div className="column">
<span>
status
</span>
<button
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
className="ml-2 p-1 hover:bg-gray-200 rounded"
className="sort-button"
>
{
column.getIsSorted() === 'asc' ?
@@ -208,13 +208,13 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
{
accessorKey: 'violations',
header: ({ column }) => (
<div className="flex items-center justify-center">
<div className="column">
<span>
{t('violations')}
</span>
<button
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
className="ml-2 p-1 hover:bg-gray-200 rounded"
className="sort-button"
>
{
column.getIsSorted() === 'asc' ?
@@ -250,13 +250,13 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
{
accessorKey: 'checks',
header: ({ column }) => (
<div className="flex items-center justify-center">
<div className="column">
<span>
{t('checks')}
</span>
<button
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
className="ml-2 p-1 hover:bg-gray-200 rounded"
className="sort-button"
>
{
column.getIsSorted() === 'asc' ?
@@ -283,13 +283,13 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
{
accessorKey: 'lastCheck',
header: ({ column }) => (
<div className="flex items-center justify-center">
<div className="column">
<span>
{t('last-check')}
</span>
<button
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
className="ml-2 p-1 hover:bg-gray-200 rounded"
className="sort-button"
>
{
column.getIsSorted() === 'asc' ?
@@ -328,7 +328,7 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
id: 'actions',
header: () => {
return (
<div className="flex items-center justify-center">
<div className="column">
{t('actions')}
</div>
)
@@ -542,13 +542,13 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
});
return (
<div className="p-6 mx-auto tanstak-table">
<div className="tanstak-table-wrapper">
<ModalWindow children={openWindowChildren} state={openWindow} callBack={setOpenWindow}></ModalWindow>
{/* Фильтры */}
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4 pb-4 pt-0 px-0">
<div className="flex flex-col md:flex-row gap-4 w-full md:w-auto">
<div className="flex flex-col w-50">
<div className="text-sm font-medium mb-1">{t('date-filter')}:</div>
<div className="tanstak-table-filtres">
<div className="table-filtres-wrapper">
<div className="table-filtres-item">
<div className="table-filtres-label">{t('date-filter')}:</div>
<DropDownList
value={dateFilter}
translatedValue={(() => {
@@ -586,8 +586,8 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
</div>
{fileType === "all" && (
<div className="flex flex-col w-50">
<div className="text-sm font-medium mb-1">{t('type-filter')}:</div>
<div className="table-filtres-item">
<div className="table-filtres-label">{t('type-filter')}:</div>
<DropDownList
value={typeFilter}
translatedValue={
@@ -623,8 +623,8 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
)}
</div>
<div className="flex flex-col w-full md:w-auto">
<div className="text-sm font-medium mb-1">{t('items-per-page')}:</div>
<div className="table-filtres-item">
<div className="table-filtres-label">{t('items-per-page')}:</div>
<DropDownList
value={table.getState().pagination.pageSize}
//@ts-ignore сделал так потому что для table.setPageSize нужна цифра
@@ -640,83 +640,80 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
</div>
{/* Таблица */}
<div className='w-full tanstak-file-table'>
<div className="overflow-x-auto rounded-lg shadow">
<table className=" divide-y divide-gray-200 table-fixed md:table-auto w-full">
<thead className="bg-gray-50">
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th
key={header.id}
className="px-6 py-3 text-left text-xs font-medium text-gray-700 uppercase tracking-wider whitespace-nowrap"
>
{header.isPlaceholder
? null
: typeof header.column.columnDef.header === 'function'
? header.column.columnDef.header(header.getContext())
: header.column.columnDef.header as string}
</th>
<div className="tanstak-table-block">
<table className="tanstak-table">
<thead className="tanstak-table-head">
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th
key={header.id}
>
{header.isPlaceholder
? null
: typeof header.column.columnDef.header === 'function'
? header.column.columnDef.header(header.getContext())
: header.column.columnDef.header as string}
</th>
))}
</tr>
))}
</thead>
<tbody className="tanstak-table-body">
{table.getRowModel().rows.length > 0 ? (
table.getRowModel().rows.map(row => (
<tr key={row.id}>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>
{typeof cell.column.columnDef.cell === 'function'
? cell.column.columnDef.cell(cell.getContext())
: cell.getValue() as string}
</td>
))}
</tr>
))}
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{table.getRowModel().rows.length > 0 ? (
table.getRowModel().rows.map(row => (
<tr key={row.id} className="hover:bg-gray-50 transition-colors">
{row.getVisibleCells().map(cell => (
<td key={cell.id} className="px-6 py-4 whitespace-nowrap">
{typeof cell.column.columnDef.cell === 'function'
? cell.column.columnDef.cell(cell.getContext())
: cell.getValue() as string}
</td>
))}
</tr>
))
) : (
<tr>
<td colSpan={columns.length} className="px-6 py-8 text-center text-gray-500">
{t('no-data-for-selected-filters')}
</td>
</tr>
)}
</tbody>
</table>
</div>
))
) : (
<tr>
<td colSpan={columns.length} className="text-center">
{t('no-data-for-selected-filters')}
</td>
</tr>
)}
</tbody>
</table>
</div>
{/* Пагинация */}
<div className="flex flex-col md:flex-row items-end justify-between mt-6 gap-4">
<div className="flex items-center gap-2">
<span className="text-sm text-gray-700">
<div className="tanstak-table-pagination">
<div className="pagination-info">
<span className="pagination-info-pages">
{t('page')}{' '}
<strong>
{table.getState().pagination.pageIndex + 1} {t('out-of')} {table.getPageCount() ? table.getPageCount() : 1}
</strong>
</span>
<span className="text-sm text-gray-500">
<span className="pagination-info-files">
| {t('shown')} {table.getRowModel().rows.length} {t('out-of')} {filteredData.length} {t('files')}
</span>
</div>
<div className="flex items-center gap-2">
<div className="pagination-controls">
<button
className="px-2 py-1 border rounded-md hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
className="arrow"
onClick={() => table.firstPage()}
disabled={!table.getCanPreviousPage()}
>
<IconDoubleArrowLeft />
</button>
<button
className="px-2 py-1 border rounded-md hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
className="arrow"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
<IconArrowLeft />
</button>
<div className="flex items-center gap-1">
<div className="pagination-controls-pages">
{Array.from({ length: Math.min(5, table.getPageCount()) }, (_, i) => {
const pageIndex = Math.max(
0,
@@ -730,9 +727,9 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
return (
<button
key={pageIndex}
className={`border border-black px-3 py-1 rounded-md ${table.getState().pagination.pageIndex === pageIndex
? 'bg-blue-500 text-white'
: 'hover:bg-gray-100'
className={`${table.getState().pagination.pageIndex === pageIndex
? 'current'
: 'other'
}`}
onClick={() => table.setPageIndex(pageIndex)}
>
@@ -745,14 +742,14 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
</div>
<button
className="px-2 py-1 border rounded-md hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
className="arrow"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
<IconArrowRight />
</button>
<button
className="px-2 py-1 border rounded-md hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
className="arrow"
onClick={() => table.lastPage()}
disabled={!table.getCanNextPage()}
>
+14 -27
View File
@@ -142,20 +142,6 @@
}
}
@media (max-width: 1300px) {
.tanstak-file-table {
max-width: 800px;
margin: 0 auto;
}
}
@media (max-width: 1200px) {
.tanstak-file-table {
max-width: 500px;
margin: 0 auto;
}
}
.modal-wrapper {
position: fixed;
z-index: 101;
@@ -178,19 +164,6 @@
}
}
.tanstak-table {
.btn-modal {
transition: all 0.3ms ease-in-out;
border-radius: 10px;
padding: 5px 20px;
font-weight: 500;
}
:where(.divide-gray-200 > tr:last-child) {
border-bottom: 1px solid var(--color-gray-200);
}
}
.sidebar {
width: 280px;
background: linear-gradient(180deg, v.$p-color 0%, v.$s-color 100%);
@@ -296,4 +269,18 @@
height: 30px;
fill: v.$white;
}
}
.color {
&-image {
color: v.$color-image;
}
&-audio {
color: v.$color-audio;
}
&-video {
color: v.$color-video;
}
}
+235
View File
@@ -412,4 +412,239 @@
justify-content: space-between;
flex-wrap: wrap;
gap: 20px;
}
.tanstak-table-wrapper {
padding: 1.5rem;
margin: 0 auto;
.btn-modal {
transition: all 0.3ms ease-in-out;
border-radius: 10px;
padding: 5px 20px;
font-weight: 500;
}
:where(.divide-gray-200 > tr:last-child) {
border-bottom: 1px solid var(--color-gray-200);
}
.tanstak-table-filtres {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
gap: 1rem;
padding-bottom: 1rem;
padding-top: 0;
padding-left: 0;
padding-right: 0;
@media (min-width: 768px) {
flex-direction: row;
align-items: center;
}
.table-filtres-wrapper {
display: flex;
flex-direction: column;
gap: 1rem;
width: 100%;
@media (min-width: 768px) {
flex-direction: row;
width: auto;
}
.table-filtres-item {
display: flex;
flex-direction: column;
width: 12.5rem;
}
.table-filtres-label {
font-size: 0.875rem;
font-weight: 500;
margin-bottom: 0.25rem;
}
}
}
.tanstak-table-pagination {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: space-between;
margin-top: 1.5rem;
gap: 1rem;
@media (min-width: 768px) {
flex-direction: row;
}
.pagination-info {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.875rem;
&-pages {
color: v.$text-p;
}
&-files {
color: v.$text-s;
}
}
.pagination-controls {
display: flex;
align-items: center;
gap: 0.5rem;
.arrow {
padding-left: 0.5rem;
padding-right: 0.5rem;
padding-top: 0.25rem;
padding-bottom: 0.25rem;
border: 1px solid;
border-radius: 0.375rem;
&:hover {
background-color: v.$bg-light;
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
&-pages {
display: flex;
align-items: center;
gap: 0.25rem;
button {
border: 1px solid v.$p-color;
padding-left: 0.75rem;
padding-right: 0.75rem;
padding-top: 0.25rem;
padding-bottom: 0.25rem;
border-radius: 0.375rem;
&.current {
background-color: v.$p-color;
color: v.$white;
}
&.other {
&:hover {
background-color: v.$bg-light;
}
}
}
}
}
}
.tanstak-table-block {
width: 100%;
overflow-x: auto;
border-radius: 0.5rem;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.tanstak-table {
width: 100%;
table-layout: fixed;
>*+* {
border-top: 1px solid v.$b-color-2;
}
> :not(:last-child) {
border-bottom: 1px solid v.$b-color-2;
}
@media (min-width: 768px) {
table-layout: auto;
}
&-head {
background-color: v.$b-color-1;
th {
padding-left: 1.5rem;
padding-right: 1.5rem;
padding-top: 0.75rem;
padding-bottom: 0.75rem;
text-align: left;
font-size: 0.75rem;
font-weight: 500;
color: v.$text-p;
text-transform: uppercase;
letter-spacing: 0.05em;
white-space: nowrap;
}
.column {
display: flex;
align-items: center;
justify-content: center;
&.start {
justify-content: start;
}
.sort-button {
margin-left: 0.5rem;
padding: 0.25rem;
border-radius: 0.25rem;
&:hover {
background-color: #e5e7eb;
}
}
}
}
&-body {
background-color: v.$white;
>*+* {
border-top: 1px solid v.$b-color-2;
}
tr {
transition: background-color 0.2s ease-in-out;
&:hover {
background-color: v.$bg-light;
}
}
td {
padding-left: 1.5rem;
padding-right: 1.5rem;
padding-top: 1rem;
padding-bottom: 1rem;
white-space: nowrap;
}
}
}
}
@media (max-width: 1300px) {
.tanstak-table {
max-width: 800px;
margin: 0 auto;
}
}
@media (max-width: 1200px) {
.tanstak-table {
max-width: 500px;
margin: 0 auto;
}
}
+5 -1
View File
@@ -11,4 +11,8 @@ $bg-light: #f8f9ff;
$bg-darkening: #0000007a;
$shadow-1: #0000001a;
$white: #fff;
$red: #dc2626;
$red: #dc2626;
$color-image: #f08c00;
$color-video: #2f9e44;
$color-audio: #1971c2;