diff --git a/src/components/FormGenerator/FormGeneratorControls/FormGeneratorControls.module.css b/src/components/FormGenerator/FormGeneratorControls/FormGeneratorControls.module.css index 367ca7c..d9ed884 100644 --- a/src/components/FormGenerator/FormGeneratorControls/FormGeneratorControls.module.css +++ b/src/components/FormGenerator/FormGeneratorControls/FormGeneratorControls.module.css @@ -24,6 +24,8 @@ align-items: center; gap: 10px; flex-shrink: 0; + flex-wrap: wrap; + flex: 1; } .activeFiltersCount { @@ -72,7 +74,7 @@ .floatingLabelInput { position: relative; - width: 250px; + width: 400px; } .label { @@ -280,3 +282,167 @@ } } +/* Pagination Controls */ +.paginationControls { + display: flex; + align-items: center; + gap: 8px; + flex-shrink: 0; + margin-left: auto; + flex-wrap: wrap; +} + +.pageSizeSelector { + display: flex; + align-items: center; + gap: 8px; + font-size: 14px; + color: var(--color-text); +} + +.pageSizeSelector label { + white-space: nowrap; + font-family: var(--font-family); +} + +.pageSizeSelect { + height: 32px; + padding: 4px 8px; + border: 1px solid var(--color-primary); + border-radius: 4px; + font-size: 14px; + font-family: var(--font-family); + background: var(--color-bg); + color: var(--color-text); + cursor: pointer; + min-width: 60px; +} + +.pageSizeSelect:focus { + outline: none; + border-color: var(--color-secondary); +} + +.paginationButton { + width: 36px; + height: 36px; + padding: 0; + border: none; + background: var(--color-secondary); + color: white; + border-radius: 50%; + cursor: pointer; + font-family: var(--font-family); + transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + font-weight: 500; + flex-shrink: 0; +} + +.paginationButton:hover:not(:disabled) { + background: var(--color-secondary-hover); +} + +.paginationButton:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.paginationInfo { + font-size: 14px; + color: var(--color-text); + white-space: nowrap; + flex-shrink: 0; +} + +/* Page numbers container */ +.pageNumbers { + display: flex; + flex-wrap: wrap; + gap: 2px; + align-items: center; + justify-content: flex-start; + max-width: 40vw; + max-height: 120px; + overflow-y: auto; + padding: 4px; +} + +/* Individual page number button */ +.pageNumber { + min-width: 28px; + height: 28px; + padding: 0 6px; + border: 1px solid var(--color-border, #ddd); + background: var(--color-bg, #fff); + color: var(--color-text); + border-radius: 4px; + cursor: pointer; + font-family: var(--font-family); + font-size: 12px; + transition: all 0.15s ease; + display: flex; + align-items: center; + justify-content: center; +} + +.pageNumber:hover:not(:disabled) { + background: var(--color-secondary); + color: white; + border-color: var(--color-secondary); +} + +.pageNumber:disabled { + cursor: default; +} + +/* Active/current page number */ +.pageNumberActive { + background: var(--color-secondary); + color: white; + border-color: var(--color-secondary); + font-weight: 600; +} + +/* Ellipsis indicator */ +.pageEllipsis { + padding: 0 8px; + color: var(--color-text-secondary, #666); + font-size: 14px; +} + +/* Responsive Design for Pagination */ +@media (max-width: 768px) { + .paginationControls { + flex-direction: column; + align-items: stretch; + gap: 10px; + margin-left: 0; + width: 100%; + } + + .pageSizeSelector { + order: -1; + justify-content: center; + } + + .paginationInfo { + text-align: center; + font-size: 13px; + } + + .pageNumbers { + max-width: 100%; + justify-content: center; + } + + .pageNumber { + min-width: 24px; + height: 24px; + font-size: 11px; + } +} + diff --git a/src/components/FormGenerator/FormGeneratorControls/FormGeneratorControls.tsx b/src/components/FormGenerator/FormGeneratorControls/FormGeneratorControls.tsx index 4439c77..7fc4137 100644 --- a/src/components/FormGenerator/FormGeneratorControls/FormGeneratorControls.tsx +++ b/src/components/FormGenerator/FormGeneratorControls/FormGeneratorControls.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import { useLanguage } from '../../../providers/language/LanguageContext'; import styles from './FormGeneratorControls.module.css'; import { Button } from '../../UiComponents/Button'; @@ -49,6 +50,18 @@ export interface FormGeneratorControlsProps { // Active filters count for display activeFiltersCount?: number; + + // Pagination props + pagination?: boolean; + currentPage?: number; + totalPages?: number; + currentPageSize?: number; + pageSizeOptions?: number[]; + showPageSizeSelector?: boolean; + onPageChange?: (page: number) => void; + onPageSizeChange?: (pageSize: number) => void; + supportsBackendPagination?: boolean; + hookData?: any; } export function FormGeneratorControls({ @@ -64,7 +77,17 @@ export function FormGeneratorControls({ searchable = true, selectable = true, loading = false, - activeFiltersCount = 0 + activeFiltersCount = 0, + pagination = false, + currentPage = 1, + totalPages = 1, + currentPageSize = 10, + pageSizeOptions = [10, 25, 50, 100, 500], + showPageSizeSelector = true, + onPageChange, + onPageSizeChange, + supportsBackendPagination = false, + hookData }: FormGeneratorControlsProps) { const { t } = useLanguage(); @@ -101,7 +124,7 @@ export function FormGeneratorControls({ )} - {/* Search Controls - Hide when items are selected */} + {/* Search Controls with Pagination - Hide when items are selected */} {searchable && selectedCount === 0 && (
@@ -133,6 +156,109 @@ export function FormGeneratorControls({ )} + + {/* Pagination Controls */} + {pagination && supportsBackendPagination && onPageChange && ( +
+ {showPageSizeSelector && onPageSizeChange && ( +
+ + +
+ )} + + + + + {/* Page number buttons - show up to 100 pages before and after current */} +
+ {(() => { + const maxPagesVisible = 100; // Max pages to show on each side + const startPage = Math.max(1, currentPage - maxPagesVisible); + const endPage = Math.min(totalPages, currentPage + maxPagesVisible); + const pages: React.ReactNode[] = []; + + // Show ellipsis at start if we're not showing page 1 + if (startPage > 1) { + pages.push( + ... + ); + } + + // Generate page buttons + for (let i = startPage; i <= endPage; i++) { + pages.push( + + ); + } + + // Show ellipsis at end if we're not showing last page + if (endPage < totalPages) { + pages.push( + ... + ); + } + + return pages; + })()} +
+ + + + + {/* Total items count */} + + ({hookData?.pagination?.totalItems != null + ? hookData.pagination.totalItems.toString() + : (loading ? '...' : displayData.length.toString())} {t('formgen.pagination.items', 'items')}) + +
+ )}
)}
diff --git a/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.module.css b/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.module.css index 95433d3..9ff925f 100644 --- a/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.module.css +++ b/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.module.css @@ -74,6 +74,7 @@ font-size: 14px; background: var(--color-bg); table-layout: fixed; + word-wrap: break-word; } /* Disabled user row styling */ @@ -104,9 +105,13 @@ text-align: left; font-weight: 400; color: var(--color-text); - white-space: nowrap; + white-space: normal; + word-wrap: break-word; + overflow-wrap: break-word; + word-break: break-word; user-select: none; z-index: 10; + overflow: visible; } .th.actionsColumn { @@ -286,6 +291,11 @@ border-top: 1px solid var(--color-primary); color: var(--color-text); vertical-align: middle; + word-wrap: break-word; + overflow-wrap: break-word; + word-break: break-word; + white-space: normal; + overflow: visible; } diff --git a/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.tsx b/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.tsx index 2fbabc1..8aafec5 100644 --- a/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.tsx +++ b/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.tsx @@ -1150,116 +1150,19 @@ export function FormGeneratorTable>({ selectable={selectable} loading={loading} activeFiltersCount={activeFiltersCount} + pagination={pagination} + currentPage={currentPage} + totalPages={totalPages} + currentPageSize={currentPageSize} + pageSizeOptions={pageSizeOptions} + showPageSizeSelector={showPageSizeSelector} + onPageChange={setCurrentPage} + onPageSizeChange={handlePageSizeChange} + supportsBackendPagination={supportsBackendPagination} + hookData={hookData} /> )} - {/* Pagination - Above Table */} - {pagination && ( -
- {showPageSizeSelector && ( -
- - -
- )} - - {pagination && supportsBackendPagination && ( - <> - - - - {/* Page number buttons - show up to 100 pages before and after current */} -
- {(() => { - const maxPagesVisible = 100; // Max pages to show on each side - const startPage = Math.max(1, currentPage - maxPagesVisible); - const endPage = Math.min(totalPages, currentPage + maxPagesVisible); - const pages: React.ReactNode[] = []; - - // Show ellipsis at start if we're not showing page 1 - if (startPage > 1) { - pages.push( - ... - ); - } - - // Generate page buttons - for (let i = startPage; i <= endPage; i++) { - pages.push( - - ); - } - - // Show ellipsis at end if we're not showing last page - if (endPage < totalPages) { - pages.push( - ... - ); - } - - return pages; - })()} -
- - - - - {/* Total items count */} - - ({hookData?.pagination?.totalItems != null - ? hookData.pagination.totalItems.toString() - : (loading ? '...' : displayData.length.toString())} {t('formgen.pagination.items', 'items')}) - - - )} -
- )} - {/* Table */}
{/* Loading overlay - shown while loading */}