Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
"eslint-plugin-qwik": "latest",
"np": "7.6.1",
"prettier": "2.8.8",
"sucrase": "^3.35.0",
"tiny-glob": "^0.2.9",
"typescript": "5.0.4",
"undici": "5.22.0",
"vite": "4.3.5"
Expand Down
57 changes: 31 additions & 26 deletions src/components/Pagination.tsx → src/components/Pagination.jsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,67 @@
import { Signal, component$, useStylesScoped$, $, useComputed$ } from '@builder.io/qwik';
import { component$, useSignal, useStylesScoped$, $, useComputed$ } from '@builder.io/qwik';

interface pageProps {
pageNo: Signal<number>,
postPerPage: Signal<number>,
totalPosts: Signal<number>
}

export const Pagination = component$((props: pageProps) => {





export const Pagination = component$((props) => {
useStylesScoped$(AppCSS);

const totalPage = useComputed$(() => {
return Math.ceil((props.totalPosts.value / props.postPerPage.value)) - 1;
return Math.ceil((props.totalPosts.value / props.postPerPage.value)) || 1;
});

const changePosts = $((e: any) => {
props.postPerPage.value = e.target.value as number;
})

const changePageNo = $((e: any) => {
props.pageNo.value = e.target.value as number;
})

const decPage = $(() => {
if (props.pageNo.value !== 0) props.pageNo.value--;
if (props.pageNo.value > 1) props.pageNo.value--;
})

const incPage = $(() => {
if (props.pageNo.value < totalPage.value) props.pageNo.value++;
})

const setFirstPage = $(() => {
if(props.pageNo.value !== 0) props.pageNo.value = 0;
if(props.pageNo.value !== 1) props.pageNo.value = 1;
})

const setLastPage = $(() => {
if(props.pageNo.value !== totalPage.value) props.pageNo.value = totalPage.value;
})

const postPerPageLast = useSignal(props.postPerPage.value);

const postPerPageChange = $(() => {
// scale pageNo to keep the first row in focus
const firstRowIdx = postPerPageLast.value * (props.pageNo.value - 1);
const totalPage2 = Math.ceil((props.totalPosts.value / props.postPerPage.value)) || 1;
const pageNo2 = Math.floor(Math.min(totalPage2, (firstRowIdx / props.postPerPage.value) + 1));
//console.log(`postPerPage: ${postPerPageLast.value} -> ${props.postPerPage.value}`);
//console.log(`totalPage: ${totalPage.value} -> ${totalPage2}`);
//console.log(`firstRowIdx: ${firstRowIdx}`);
//console.log(`pageNo: ${props.pageNo.value} -> ${pageNo2}`);
props.pageNo.value = pageNo2;
postPerPageLast.value = props.postPerPage.value;
});

return (
<div class='page-cont'>

<div class='post-select'>
<div>Rows per page </div>
<select onInput$={changePosts}>
<option>10</option>
<option>20</option>
<option>30</option>
<option>40</option>
<option>50</option>
<select bind:value={props.postPerPage} onChange$={postPerPageChange}>
{props.postPerPageValues.map((postPerPage, idx) => (
<option key={idx} selected={postPerPage == props.postPerPage.value}>{postPerPage}</option>
))}
</select>
</div>

<div>
<div class='select-page'>Page <input onInput$={changePageNo} value={props.pageNo.value} type='number' min={0} max={totalPage.value} /> of {totalPage.value}</div>
<div class='select-page'>Page <input bind:value={props.pageNo} type='number' min={1} max={totalPage.value} /> of {totalPage.value}</div>
</div>

<div class='btn-cont'>
<button disabled={props.pageNo.value === 0} onClick$={setFirstPage}>
<button disabled={props.pageNo.value === 1} onClick$={setFirstPage}>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4"><polyline points="11 17 6 12 11 7"></polyline><polyline points="18 17 13 12 18 7"></polyline></svg>
</button>
<button onClick$={decPage}>
Expand Down
41 changes: 25 additions & 16 deletions src/components/Search.tsx → src/components/Search.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
import { $, Signal, component$, useStylesScoped$ } from '@builder.io/qwik';

interface searchProps {
headers: {
key: string,
label: string
}[],
searchBy: Signal<string>,
searchInp: Signal<string>
}

export const Search = component$(( props: searchProps) => {
import { $, component$, useStylesScoped$, useSignal } from '@builder.io/qwik';










export const Search = component$(( props) => {
useStylesScoped$(AppCSS);

const setSearchBy = $((e: any) => {
const setSearchBy = $((e) => {
console.log(e.target.value)
props.searchBy.value = e.target.value;
})

const setSearchInp = $((e: any) => {
// https://qwik.dev/docs/cookbook/debouncer/
const debounce = (fn, delay) => {
const timeoutId = useSignal();
return $((args) => {
clearTimeout(timeoutId.value);
timeoutId.value = Number(setTimeout(() => fn(args), delay));
});
};

const setSearchInp = $((e) => {
props.searchInp.value = e.target.value;
})

Expand All @@ -26,10 +35,10 @@ export const Search = component$(( props: searchProps) => {
Search by
<select onInput$={setSearchBy}>
{props.headers.map((item, i) => (
<option key={i}>{item.key}</option>
<option key={i} value={item.key}>{item.label}</option>
))}
</select>
<input onInput$={setSearchInp} class='search-inp' placeholder='search' />
<input onInput$={debounce(setSearchInp, 500)} class='search-inp' placeholder='search' />
</div>
);
});
Expand Down
14 changes: 7 additions & 7 deletions src/components/SortButton.tsx → src/components/SortButton.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { component$, useOn, useStylesScoped$, $, Signal } from '@builder.io/qwik';
import { component$, useOn, useStylesScoped$, $, } from '@builder.io/qwik';

interface typeProps {
cellKey: string | number | null | undefined,
sortOrder: Signal<string>,
sortKey: Signal<string | number | null | undefined>
}

export const SortButton = component$((props: typeProps) => {





export const SortButton = component$((props) => {
useStylesScoped$(AppCSS);
useOn(
'click',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { Signal, component$, useStylesScoped$ } from "@builder.io/qwik";
import { component$, useStylesScoped$ } from "@builder.io/qwik";
import { Search } from '../Search';

interface headerProps {
headers: {
key: string,
label: string
}[],
searchBy: Signal<string>,
searchInp: Signal<string>,
title: string,
headerImg?: string
}

export const Header = component$((props: headerProps) => {











export const Header = component$((props) => {
useStylesScoped$(AppCSS);
return (
<div class='table-top'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ import { sortData } from '../../utils/sortData';
import { searchData } from '../../utils/searchedData';
import { Header } from '../header/Header';

interface tableProps {
header: {
key: string,
label: string
}[],
data: {
[key: string]: string | number | null | undefined
}[],
title: string,
headerImg?: string
}

export const QwikTable = component$((props: tableProps) => {












export const QwikTable = component$((props) => {
useStyles$(`
table {
border-collapse: collapse;
Expand All @@ -34,14 +34,33 @@ export const QwikTable = component$((props: tableProps) => {
);
useStylesScoped$(AppCSS);

const sortOrder = useSignal<string>('asc');
const sortKey = useSignal<string>(props.header[0].key);
const pageNo = useSignal<number>(0);
const postPerPage = useSignal<number>(10);
const totalPosts = useSignal<number>(props.data.length);
const searchBy = useSignal<string>(props.header[0].key);
const searchInp = useSignal<string>('');
const prevSearch = useSignal<boolean>(false);
const postPerPageValues = [
10,
20,
30,
50,
100,
200,
300,
500,
1000,
2000,
3000,
5000,
10000,
];

const postPerPageDefaultValue = 100;

const sortOrder = useSignal('asc');
//const sortKey = useSignal(props.header[0].key);
const sortKey = useSignal(undefined); // perf: dont sort by default
const pageNo = useSignal(1);
const postPerPage = useSignal(postPerPageDefaultValue);
const totalPosts = useSignal(props.data.length);
const searchBy = useSignal(props.header[0].key);
const searchInp = useSignal('');
const prevSearch = useSignal(false);

const finalData = useStore({
items: props.data
Expand All @@ -54,6 +73,7 @@ export const QwikTable = component$((props: tableProps) => {
sortOrder: sortOrder,
totalPosts: totalPosts,
prevSearch: prevSearch,
searchInp: searchInp,
searchBy: searchBy
}))

Expand Down Expand Up @@ -95,6 +115,13 @@ export const QwikTable = component$((props: tableProps) => {
headerImg={props.headerImg}
/>

<Pagination
pageNo={pageNo}
postPerPageValues={postPerPageValues}
postPerPage={postPerPage}
totalPosts={totalPosts}
/>

<table>
<TableHead
header={props.header}
Expand All @@ -109,6 +136,7 @@ export const QwikTable = component$((props: tableProps) => {

<Pagination
pageNo={pageNo}
postPerPageValues={postPerPageValues}
postPerPage={postPerPage}
totalPosts={totalPosts}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import { Signal, component$, useComputed$, useStylesScoped$ } from '@builder.io/qwik';
import { component$, useComputed$, useStylesScoped$ } from '@builder.io/qwik';
import { isImage } from '../../utils/imageBool';

interface bodyProps {
data: {
[key: string]: string | number | null | undefined
}[],
pageNo: Signal<number>,
postPerPage: Signal<number>
}

type cellType = {
[key: string]: string | number | null | undefined;
}

export const TableBody = component$((props: bodyProps) => {










export const TableBody = component$((props) => {
useStylesScoped$(AppCSS);

const computedPosts = useComputed$(() => {
return props.data.slice((props.pageNo.value * props.postPerPage.value),
((props.pageNo.value * props.postPerPage.value)
const pageIdx = props.pageNo.value - 1;
return props.data.slice((pageIdx * props.postPerPage.value),
((pageIdx * props.postPerPage.value)
+ parseInt(props.postPerPage.value.toString())))
})

Expand All @@ -27,13 +28,13 @@ export const TableBody = component$((props: bodyProps) => {

return (
<tbody>
{computedPosts.value.map((cell: cellType) => {
{computedPosts.value.map((cell) => {
const keys = Object.keys(cell);
return (
<tr key={cell[keys[0]]}>
{keys.map((item, i) => {
if (isImage(cell[item])) {
const imgSrc = cell[item] as string;
const imgSrc = cell[item] ;
return (
<td key={i}>
<img width={50} height={50} src={imgSrc} />
Expand Down
Loading