Skip to content

Commit 7adfe94

Browse files
authored
feat: create list feature (#1698)
1 parent 1b33900 commit 7adfe94

File tree

17 files changed

+703
-79
lines changed

17 files changed

+703
-79
lines changed

Diff for: components/atoms/FilterChip/filter-chip.tsx

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import clsx from "clsx";
2+
import React from "react";
3+
import { MdClose } from "react-icons/md";
4+
5+
interface FilterChipProps {
6+
className?: string;
7+
items: string[];
8+
onClear: () => void;
9+
}
10+
const FilterChip = ({ className, items, onClear }: FilterChipProps) => {
11+
return (
12+
<div
13+
className={clsx(
14+
"p-2.5 rounded-xl bg-sauced-light w-max text-sauced-orange max-w-[12.5rem] flex items-center",
15+
className
16+
)}
17+
>
18+
<span className="max-w-[75%] truncate">{items[0]}</span>
19+
{items.length > 1 && <span className="text-sauced-orange"> ,+{items.length - 1}</span>}
20+
<MdClose onClick={onClear} className="ml-1 text-2xl" />
21+
</div>
22+
);
23+
};
24+
25+
export default FilterChip;

Diff for: components/atoms/ListNameHeader/list-name-header.tsx

+41-23
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useRef } from "react";
1+
import React, { useRef, useState } from "react";
22
import { HiPencil } from "react-icons/hi";
33
import clsx from "clsx";
44

@@ -9,36 +9,54 @@ interface ListNameHeaderProps {
99
onEditTitle?: (value: string) => void;
1010
}
1111
const ListNameHeader = ({ title, onEditTitle }: ListNameHeaderProps) => {
12-
const ref = useRef<HTMLSpanElement>(null);
12+
const ref = useRef<HTMLInputElement>(null);
13+
const [focused, setFocused] = useState(false);
1314

1415
const handleFocus = () => {
15-
ref.current?.focus();
16-
// select all text in the span... this is a hacky way to do it and not sure if it's the best way
17-
document.execCommand("selectAll", false, undefined);
16+
ref?.current?.focus();
1817
};
1918

2019
return (
2120
<div>
2221
<Title className="text-base text-sauced-orange">New List</Title>
2322
<div className="flex items-center gap-3">
24-
{/* Using a span to mimic an input because native inputs can't auto grow in width relative to it's content
25-
** https://css-tricks.com/auto-growing-inputs-textareas/
26-
*/}
27-
<span
28-
ref={ref}
29-
onInput={(e) => {
30-
onEditTitle && onEditTitle(e.currentTarget.textContent ?? "");
31-
}}
32-
suppressContentEditableWarning
33-
className={clsx("text-3xl auto-grow-input text-gray-300 focus:outline-none cursor-text")}
34-
role="text-box"
35-
contentEditable
36-
>
37-
{title}
38-
</span>
39-
<button onClick={handleFocus} type="button">
40-
<HiPencil className="text-xl" />
41-
</button>
23+
<div className="relative text-3xl w-max">
24+
<input
25+
ref={ref}
26+
onChange={(e) => {
27+
onEditTitle?.(e.target.value);
28+
}}
29+
onBlur={() => {
30+
setFocused(false);
31+
}}
32+
onFocus={(e) => {
33+
setFocused(true);
34+
e.target.select();
35+
}}
36+
autoFocus
37+
value={title}
38+
type="text"
39+
placeholder="List Name"
40+
className={clsx(
41+
"text-3xl w-40 bg-transparent text-light-slate-12 focus:outline-none cursor-text",
42+
!focused && "!text-white"
43+
)}
44+
/>
45+
<span className={clsx("absolute left-0 w-max", focused && "invisible")}>
46+
{title}
47+
48+
{title && title.length > 0 && (
49+
<button onClick={handleFocus} type="button">
50+
<HiPencil className="ml-2 text-xl" />
51+
</button>
52+
)}
53+
</span>
54+
</div>
55+
{!focused && !title && (
56+
<button onClick={handleFocus} type="button">
57+
<HiPencil className="ml-2 text-xl" />
58+
</button>
59+
)}
4260
</div>
4361
</div>
4462
);

Diff for: components/atoms/ToggleSwitch/toggle-switch.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const ToggleSwitch = ({
2626
classNames ?? classNames,
2727
checked && "!bg-light-orange-10 justify-end",
2828
"flex rounded-2xl p-[2px] transition overflow-hidden bg-light-slate-8",
29-
size === "lg" ? "w-14 h-[30px]" : size === "base" ? "w-11 h-6" : size === "sm" ? "w-7 h-4" : ""
29+
size === "lg" ? "w-14 h-[30px]" : size === "base" ? "w-10 h-5" : size === "sm" ? "w-7 h-4" : ""
3030
)}
3131
>
3232
<Switch.Thumb className={clsx("bg-white block rounded-2xl h-full w-1/2")} />

Diff for: components/molecules/ComponentDateFilter/component-date-filter.tsx

+12-15
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,18 @@ const ComponentDateFilter = ({ setRangeFilter, defaultRange }: ComponentDateFilt
2020
};
2121

2222
return (
23-
<div className="flex text-sm gap-4 items-center">
24-
<span>Date filter:</span>
25-
<div className="flex items-center">
26-
{dates.map((range, index) => (
27-
<div
28-
onClick={() => handleFilterClick(range)}
29-
className={`px-2 py-1 rounded-lg cursor-pointer transition text-light-slate-9 ${
30-
activeFilter === range && "border text-light-slate-12 border-light-orange-10"
31-
}`}
32-
key={index}
33-
>
34-
{rangeFormatter(range)}
35-
</div>
36-
))}
37-
</div>
23+
<div className="flex items-center text-sm bg-white rounded-lg">
24+
{dates.map((range, index) => (
25+
<div
26+
onClick={() => handleFilterClick(range)}
27+
className={`px-4 py-1.5 rounded-lg cursor-pointer transition text-light-slate-9 ${
28+
activeFilter === range && "border text-light-slate-12 bg-light-slate-5"
29+
}`}
30+
key={index}
31+
>
32+
{rangeFormatter(range)}
33+
</div>
34+
))}
3835
</div>
3936
);
4037
};

Diff for: components/molecules/ContributorListTableHeader/contributor-list-table-header.tsx

+29-9
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,26 @@ import clsx from "clsx";
22
import React from "react";
33
import TableTitle from "components/atoms/TableTitle/table-title";
44
import { classNames } from "components/organisms/RepositoriesTable/repositories-table";
5+
import Checkbox from "components/atoms/Checkbox/checkbox";
56

6-
const ContributorListTableHeaders = () => {
7+
interface ContributorListTableHeadersProps {
8+
selected?: boolean;
9+
handleOnSelectAllContributor?: (contributor: any) => void;
10+
}
11+
12+
const ContributorListTableHeaders = ({ selected, handleOnSelectAllContributor }: ContributorListTableHeadersProps) => {
713
return (
814
<div className="mt-4">
915
{/* Mobile */}
10-
<div className="flex justify-between gap-2 px-6 py-4 rounded-t-lg md:hidden bg-light-slate-3">
11-
<div className="w-[58%]">
16+
<div className="flex justify-between gap-2 px-2 py-4 rounded-t-lg md:hidden bg-light-slate-3">
17+
{handleOnSelectAllContributor && (
18+
<Checkbox
19+
checked={selected ? true : false}
20+
onCheckedChange={handleOnSelectAllContributor}
21+
className={`${"border-orange-500 hover:bg-orange-600"}`}
22+
/>
23+
)}
24+
<div className="w-[50%]">
1225
<TableTitle>Contributor</TableTitle>
1326
</div>
1427
<div className="flex-1 w-[42%]">
@@ -17,23 +30,30 @@ const ContributorListTableHeaders = () => {
1730
</div>
1831
{/* Desktop */}
1932
<div className="hidden gap-6 px-6 py-4 border rounded-t-lg md:flex bg-light-slate-3">
20-
<div className={clsx("flex-1 lg:min-w-[250px] flex justify-center")}>
33+
{handleOnSelectAllContributor && (
34+
<Checkbox
35+
checked={selected ? true : false}
36+
onCheckedChange={handleOnSelectAllContributor}
37+
className={`${"border-orange-500 hover:bg-orange-600"}`}
38+
/>
39+
)}
40+
<div className={clsx("flex-1 lg:min-w-[12.5rem] flex justify-center")}>
2141
<TableTitle>Contributor</TableTitle>
2242
</div>
23-
<div className={clsx(" flex-1 lg:max-w-[100px] flex justify-center ")}>
43+
<div className={clsx(" flex-1 lg:max-w-[6.25rem] flex justify-center ")}>
2444
<TableTitle>Act</TableTitle>
2545
</div>
26-
<div className={clsx("flex-1 lg:max-w-[100px] ")}>
46+
<div className={clsx("flex-1 lg:max-w-[6.25rem] ")}>
2747
<TableTitle>Repositories</TableTitle>
2848
</div>
29-
<div className={clsx("flex-1 lg:max-w-[130px] ")}>
49+
<div className={clsx("flex-1 lg:max-w-[8.1rem] ")}>
3050
<TableTitle>Last Contributed</TableTitle>
3151
</div>
32-
<div className={clsx(" flex flex-1 justify-center max-w-[120px]")}>
52+
<div className={clsx(" flex flex-1 justify-center max-w-[7.5rem]")}>
3353
<TableTitle>Language</TableTitle>
3454
</div>
3555

36-
<div className={clsx("flex-1 hidden lg:flex justify-center lg:max-w-[80px]")}>
56+
<div className={clsx("flex-1 hidden lg:flex justify-center lg:max-w-[5rem]")}>
3757
<TableTitle>Time zone</TableTitle>
3858
</div>
3959
<div className={clsx("flex-1 hidden lg:flex lg:max-w-fit")}>

Diff for: components/molecules/ContributorListTableRow/contributor-list-table-row.tsx

+36-17
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@ import { classNames } from "components/organisms/RepositoriesTable/repositories-
1010
import useContributorPullRequests from "lib/hooks/api/useContributorPullRequests";
1111
import useRepoList from "lib/hooks/useRepoList";
1212
import { useFetchUser } from "lib/hooks/useFetchUser";
13+
import Checkbox from "components/atoms/Checkbox/checkbox";
1314
import { getActivity } from "../RepoRow/repo-row";
1415
import DevProfile from "../DevProfile/dev-profile";
1516

1617
interface ContributorListTableRow {
1718
contributor: DbPRContributor;
1819
topic: string;
20+
selected?: boolean;
21+
handleOnSelectContributor?: (state: boolean, contributor: DbPRContributor) => void;
1922
}
2023

2124
function getLastContributionDate(contributions: DbRepoPR[]) {
@@ -39,7 +42,12 @@ function getLastContributedRepo(pullRequests: DbRepoPR[]) {
3942

4043
return sortedPullRequests[0].full_name;
4144
}
42-
const ContributorListTableRow = ({ contributor, topic }: ContributorListTableRow) => {
45+
const ContributorListTableRow = ({
46+
contributor,
47+
topic,
48+
selected,
49+
handleOnSelectContributor,
50+
}: ContributorListTableRow) => {
4351
const [tableOpen, setTableOpen] = useState(false);
4452

4553
const { data: user } = useFetchUser(contributor.author_login);
@@ -62,9 +70,18 @@ const ContributorListTableRow = ({ contributor, topic }: ContributorListTableRow
6270
return (
6371
<>
6472
{/* Mobile version */}
65-
<div className="px-5 py-2 overflow-hidden odd:bg-white md:hidden even:bg-light-slate-2">
73+
<div className="px-2 py-2 overflow-hidden md:px-5 odd:bg-white md:hidden even:bg-light-slate-2">
6674
<div className="flex items-center gap-x-3 text-light-slate-12">
67-
<div className="w-[66%]">
75+
{handleOnSelectContributor && (
76+
<Checkbox
77+
checked={selected ? true : false}
78+
disabled={!user}
79+
title={!user ? "Connect to GitHub" : ""}
80+
onCheckedChange={(state) => handleOnSelectContributor?.(state as boolean, contributor)}
81+
className={`${user && "border-orange-500 hover:bg-orange-600"}`}
82+
/>
83+
)}
84+
<div className="w-[68%]">
6885
<DevProfile company={user?.company || getLastContributedRepo(data)} username={contributor.author_login} />
6986
</div>
7087
<div className="w-[34%] text-normal text-light-slate-11 h-full">
@@ -121,34 +138,36 @@ const ContributorListTableRow = ({ contributor, topic }: ContributorListTableRow
121138
{/* Desktop Version */}
122139

123140
<div className={`${classNames.row} !gap-6 text-light-slate-11`}>
124-
{/* <Checkbox
125-
checked={true}
126-
onCheckedChange={() => console.log("yeah")}
127-
disabled={!user}
128-
title={!user ? "Connect to GitHub" : ""}
129-
className={`${user && "border-orange-500 hover:bg-orange-600"}`}
130-
/> */}
141+
{handleOnSelectContributor && (
142+
<Checkbox
143+
checked={selected ? true : false}
144+
disabled={!user}
145+
title={!user ? "Connect to GitHub" : ""}
146+
onCheckedChange={(state) => handleOnSelectContributor?.(state as boolean, contributor)}
147+
className={`${user && "border-orange-500 hover:bg-orange-600"}`}
148+
/>
149+
)}
131150

132151
{/* Column: Contributors */}
133-
<div className={clsx("flex-1 lg:min-w-[250px] overflow-hidden")}>
152+
<div className={clsx("flex-1 lg:min-w-[12.5rem] overflow-hidden")}>
134153
<DevProfile company={user?.company || getLastContributedRepo(data)} username={contributor.author_login} />
135154
</div>
136155

137156
{/* Column: Act */}
138-
<div className={clsx("flex-1 flex lg:max-w-[100px] w-fit justify-center")}>
157+
<div className={clsx("flex-1 flex lg:max-w-[6.25rem] w-fit justify-center")}>
139158
{getActivity(totalPrs, false)}
140159
</div>
141160

142161
{/* Column Repositories */}
143-
<div className={clsx("flex-1 lg:max-w-[100px] flex justify-center ")}>{repoList.length}</div>
162+
<div className={clsx("flex-1 lg:max-w-[6.25rem] flex justify-center ")}>{repoList.length}</div>
144163

145164
{/* Column: Last Contribution */}
146165
<div className={clsx("flex-1 lg:max-w-[130px] flex text-light-slate-11 justify-center ")}>
147166
<div className="flex">{<p>{getLastContributionDate(mergedPrs)}</p>}</div>
148167
</div>
149168

150169
{/* Column: Language */}
151-
<div className={clsx("flex-1 hidden lg:max-w-[120px] justify-center lg:flex")}>
170+
<div className={clsx("flex-1 hidden lg:max-w-[7.5rem] justify-center lg:flex")}>
152171
{contributorLanguageList.length > 0 ? (
153172
<p>
154173
{contributorLanguageList[0]}
@@ -160,16 +179,16 @@ const ContributorListTableRow = ({ contributor, topic }: ContributorListTableRow
160179
</div>
161180

162181
{/* Column: Time Zone */}
163-
<div className={clsx("flex-1 hidden lg:max-w-[80px] text-light-slate-11 justify-center lg:flex ")}>
182+
<div className={clsx("flex-1 hidden lg:max-w-[5rem] text-light-slate-11 justify-center lg:flex ")}>
164183
<div className="flex gap-x-3">{user && user.timezone ? <p>{user.timezone}</p> : "-"}</div>
165184
</div>
166185

167186
{/* Column: Contributions */}
168-
<div className={clsx("flex-1 hidden justify-center lg:flex lg:max-w-[120px]")}>
187+
<div className={clsx("flex-1 hidden justify-center lg:flex lg:max-w-[7.5rem]")}>
169188
<p>{mergedPrs.length}</p>
170189
</div>
171190
{/* Column Last 30 Days */}
172-
<div className={clsx("flex-1 lg:min-w-[150px] hidden lg:flex justify-center")}>
191+
<div className={clsx("flex-1 lg:min-w-[9.37rem] hidden lg:flex justify-center")}>
173192
{last30days ? <Sparkline data={last30days} width="100%" height={54} /> : "-"}
174193
</div>
175194
</div>

Diff for: components/molecules/DevProfile/dev-profile.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const DevProfile = ({ username, company }: DevProfileProps) => {
1919
</div>
2020
{/* Desktop */}
2121
<div className="hidden rounded-full md:flex">
22-
<Avatar className="" size={60} isCircle avatarURL={getAvatarByUsername(username)} />
22+
<Avatar className="" size={45} isCircle avatarURL={getAvatarByUsername(username)} />
2323
</div>
2424
<div>
2525
<h1 className="text-light-slate-12">

0 commit comments

Comments
 (0)