Skip to content

Commit 58ea3c9

Browse files
authored
Merge pull request #624 from dzcode-io/global-search
Global Search
2 parents 9988863 + 3af1e4e commit 58ea3c9

File tree

14 files changed

+551
-198
lines changed

14 files changed

+551
-198
lines changed

api/src/app/endpoints.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
GetProjectsForSitemapResponse,
1313
GetProjectsResponse,
1414
} from "src/project/types";
15+
import { SearchResponse } from "src/search/types";
1516

1617
// ts-prune-ignore-next
1718
export interface Endpoints {
@@ -50,4 +51,8 @@ export interface Endpoints {
5051
"api:MileStones/dzcode": {
5152
response: GetMilestonesResponse;
5253
};
54+
"api:Search": {
55+
response: SearchResponse;
56+
query: [["query", string], ["limit", number]];
57+
};
5358
}

api/src/search/service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class SearchService {
3434
indexUid: "contribution",
3535
q,
3636
limit,
37-
attributesToRetrieve: ["id", "title", "type", "activityCount"],
37+
attributesToRetrieve: ["id", "title", "type", "activityCount", "url"],
3838
},
3939
{ indexUid: "contributor", q, limit, attributesToRetrieve: ["id", "name", "avatarUrl"] },
4040
],

web/src/_entry/app.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { TopBar, TopBarProps } from "src/components/top-bar";
99
import { StoreProvider } from "src/redux/store";
1010
import { getInitialLanguageCode } from "src/utils/website-language";
1111
import React from "react";
12+
import { Search } from "src/components/search";
1213

1314
let routes: Array<
1415
RouteProps & {
@@ -119,6 +120,7 @@ const App = () => {
119120
return (
120121
<>
121122
<div className="flex flex-col min-h-screen">
123+
<Search />
122124
<TopBar version={window.bundleInfo.version} links={topBarLinks} />
123125
<Routes>
124126
{routes.map((route) => {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { GetContributionsResponse } from "@dzcode.io/api/dist/contribution/types";
2+
import React from "react";
3+
import { Link } from "src/components/link";
4+
import { useLocale } from "src/components/locale";
5+
import { Markdown } from "src/components/markdown";
6+
import { getElapsedTime } from "src/utils/elapsed-time";
7+
8+
export function ContributionCard({
9+
contribution,
10+
compact = false,
11+
}: {
12+
contribution: GetContributionsResponse["contributions"][number];
13+
compact?: boolean;
14+
}) {
15+
const { localize } = useLocale();
16+
17+
return (
18+
<div dir="ltr" className="card card-compact bg-base-300 flex-auto w-full max-w-xs sm:max-w-sm">
19+
<div className="card-body markdown">
20+
<div className="card-body">
21+
<h2 className="card-title">
22+
<Markdown content={contribution.title} />
23+
</h2>
24+
<span className="flex-1" />
25+
{!compact && (
26+
<>
27+
<span className="card-normal">{contribution.repository.project.name}</span>
28+
<span className="card-normal">
29+
{contribution.repository.owner}/{contribution.repository.name}
30+
</span>
31+
</>
32+
)}
33+
<div className="card-actions justify-end mt-4 gap-4">
34+
{!compact && (
35+
<img className="w-6 h-6 rounded-full" src={contribution.contributor.avatarUrl} />
36+
)}
37+
<div className="flex-1" />
38+
{contribution.activityCount > 0 && (
39+
<div className="flex flex-row">
40+
<svg
41+
xmlns="http://www.w3.org/2000/svg"
42+
fill="none"
43+
viewBox="0 0 24 24"
44+
strokeWidth={1.5}
45+
stroke="currentColor"
46+
className="size-6"
47+
>
48+
<path
49+
strokeLinecap="round"
50+
strokeLinejoin="round"
51+
d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 0 1-.825-.242m9.345-8.334a2.126 2.126 0 0 0-.476-.095 48.64 48.64 0 0 0-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0 0 11.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155"
52+
/>
53+
</svg>
54+
<span className="">{contribution.activityCount}</span>
55+
</div>
56+
)}
57+
{!compact && (
58+
<div className="flex flex-row">
59+
{getElapsedTime(contribution.updatedAt, localize("elapsed-time-suffixes"))}
60+
</div>
61+
)}
62+
<Link href={contribution.url} className="link">
63+
{contribution.type === "ISSUE"
64+
? localize("contribute-read-issue")
65+
: localize("contribute-review-changes")}
66+
</Link>
67+
</div>
68+
</div>
69+
</div>
70+
</div>
71+
);
72+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import React from "react";
2+
import { Link } from "src/components/link";
3+
import { getContributorURL } from "src/utils/contributor";
4+
import { GetContributorsResponse } from "@dzcode.io/api/dist/contributor/types";
5+
6+
export function ContributorCard({
7+
contributor,
8+
compact = false,
9+
onClick,
10+
}: {
11+
contributor: GetContributorsResponse["contributors"][number];
12+
compact?: boolean;
13+
onClick?: () => void;
14+
}) {
15+
return (
16+
<Link
17+
className="card bg-base-300 w-full sm:max-w-52 rounded-lg flex flex-row border-base-200 border-2 overflow-hidden"
18+
href={getContributorURL(contributor)}
19+
// TODO-OB: there's a bug here: when passing onClick to Link, the link no longer work as a SPA link, and instead causes a full reload of the page
20+
onClick={onClick}
21+
>
22+
<img
23+
src={contributor.avatarUrl}
24+
alt={contributor.name}
25+
className="flex sm:hidden rounded-none size-28"
26+
/>
27+
<div className="flex-1 flex flex-col items-center">
28+
<div className="flex-1 flex flex-row sm:flex-col justify-start sm:justify-center items-center p-4 gap-4 w-full">
29+
<img
30+
src={contributor.avatarUrl}
31+
alt={contributor.name}
32+
className="hidden sm:flex rounded-full size-20"
33+
/>
34+
<span className="card-title break-all">{contributor.name}</span>
35+
</div>
36+
{!compact && (
37+
<div className="flex flex-row gap-4 w-full justify-around bg-base-200 text-gray-500 p-2">
38+
<div className="flex flex-row gap-2">
39+
<svg
40+
xmlns="http://www.w3.org/2000/svg"
41+
fill="none"
42+
viewBox="0 0 24 24"
43+
strokeWidth={1.5}
44+
stroke="currentColor"
45+
className="size-6"
46+
>
47+
<path
48+
strokeLinecap="round"
49+
strokeLinejoin="round"
50+
d="m6.75 7.5 3 2.25-3 2.25m4.5 0h3m-9 8.25h13.5A2.25 2.25 0 0 0 21 18V6a2.25 2.25 0 0 0-2.25-2.25H5.25A2.25 2.25 0 0 0 3 6v12a2.25 2.25 0 0 0 2.25 2.25Z"
51+
/>
52+
</svg>
53+
{contributor.totalContributionScore}
54+
</div>
55+
<div className="divider divider-horizontal" />
56+
<div className="flex flex-row gap-2">
57+
{contributor.totalRepositoryCount}
58+
<svg
59+
xmlns="http://www.w3.org/2000/svg"
60+
fill="none"
61+
viewBox="0 0 24 24"
62+
strokeWidth={1.5}
63+
stroke="currentColor"
64+
className="size-6"
65+
>
66+
<path
67+
strokeLinecap="round"
68+
strokeLinejoin="round"
69+
d="M3.75 4.875c0-.621.504-1.125 1.125-1.125h4.5c.621 0 1.125.504 1.125 1.125v4.5c0 .621-.504 1.125-1.125 1.125h-4.5A1.125 1.125 0 0 1 3.75 9.375v-4.5ZM3.75 14.625c0-.621.504-1.125 1.125-1.125h4.5c.621 0 1.125.504 1.125 1.125v4.5c0 .621-.504 1.125-1.125 1.125h-4.5a1.125 1.125 0 0 1-1.125-1.125v-4.5ZM13.5 4.875c0-.621.504-1.125 1.125-1.125h4.5c.621 0 1.125.504 1.125 1.125v4.5c0 .621-.504 1.125-1.125 1.125h-4.5A1.125 1.125 0 0 1 13.5 9.375v-4.5Z"
70+
/>
71+
<path
72+
strokeLinecap="round"
73+
strokeLinejoin="round"
74+
d="M6.75 6.75h.75v.75h-.75v-.75ZM6.75 16.5h.75v.75h-.75v-.75ZM16.5 6.75h.75v.75h-.75v-.75ZM13.5 13.5h.75v.75h-.75v-.75ZM13.5 19.5h.75v.75h-.75v-.75ZM19.5 13.5h.75v.75h-.75v-.75ZM19.5 19.5h.75v.75h-.75v-.75ZM16.5 16.5h.75v.75h-.75v-.75Z"
75+
/>
76+
</svg>
77+
</div>
78+
</div>
79+
)}
80+
</div>
81+
</Link>
82+
);
83+
}

web/src/components/locale/dictionary.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const dictionary = {
1616
"navbar-section-projects": { en: "Projects", ar: "مشاريع" },
1717
"navbar-section-articles": { en: "Articles", ar: "مقالات" },
1818
"navbar-section-faq": { en: "FAQ", ar: "أسئلة / أجوبة" },
19+
"navbar-section-search": { en: "Search...", ar: "بحث..." },
1920

2021
"footer-category-title-helpful-links": {
2122
en: "Helpful Links",
@@ -433,4 +434,24 @@ Besides the open tasks on [/Contribute](/Contribute) page, you can also contribu
433434
en: "Algeria Codes",
434435
ar: "الجزائر تبرمج",
435436
},
437+
"search-contributions": {
438+
en: "Contributions",
439+
ar: "مساهمات",
440+
},
441+
"search-contributors": {
442+
en: "Contributors",
443+
ar: "مساهمين",
444+
},
445+
"search-projects": {
446+
en: "Projects",
447+
ar: "مشاريع",
448+
},
449+
"search-type-to-search": {
450+
en: "Type to search...",
451+
ar: "اكتب للبحث...",
452+
},
453+
"search-no-results-found": {
454+
en: "No results found",
455+
ar: "لم يتم العثور على نتائج",
456+
},
436457
} as const;
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { GetProjectsResponse } from "@dzcode.io/api/dist/project/types";
2+
import React from "react";
3+
import { Link } from "src/components/link";
4+
import { getProjectURL } from "src/utils/project";
5+
6+
export function ProjectCard({
7+
project,
8+
compact = false,
9+
onClick,
10+
}: {
11+
project: GetProjectsResponse["projects"][number];
12+
compact?: boolean;
13+
onClick?: () => void;
14+
}) {
15+
return (
16+
<Link
17+
href={getProjectURL(project)}
18+
dir="ltr"
19+
className="bg-base-300 w-full max-w-xs sm:max-w-sm flex flex-col rounded-lg border-base-200 border-2 overflow-hidden"
20+
onClick={onClick}
21+
>
22+
<h2 className="card-title p-4">{project.name}</h2>
23+
{!compact && (
24+
<>
25+
<div className="flex-1" />
26+
<div className="flex flex-row gap-4 justify-around bg-base-200 text-gray-500 p-2">
27+
<div className="flex flex-row gap-2">
28+
<svg
29+
xmlns="http://www.w3.org/2000/svg"
30+
fill="none"
31+
viewBox="0 0 24 24"
32+
strokeWidth={1.5}
33+
stroke="currentColor"
34+
className="size-6"
35+
>
36+
<path
37+
strokeLinecap="round"
38+
strokeLinejoin="round"
39+
d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z"
40+
/>
41+
</svg>
42+
{project.totalRepoStars}
43+
</div>
44+
<div className="divider divider-horizontal" />
45+
<div className="flex flex-row gap-2">
46+
<svg
47+
xmlns="http://www.w3.org/2000/svg"
48+
fill="none"
49+
viewBox="0 0 24 24"
50+
strokeWidth={1.5}
51+
stroke="currentColor"
52+
className="size-6"
53+
>
54+
<path
55+
strokeLinecap="round"
56+
strokeLinejoin="round"
57+
d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z"
58+
/>
59+
</svg>
60+
{project.totalRepoScore}
61+
</div>
62+
<div className="divider divider-horizontal" />
63+
<div className="flex flex-row gap-2">
64+
<svg
65+
xmlns="http://www.w3.org/2000/svg"
66+
fill="none"
67+
viewBox="0 0 24 24"
68+
strokeWidth={1.5}
69+
stroke="currentColor"
70+
className="size-6"
71+
>
72+
<path
73+
strokeLinecap="round"
74+
strokeLinejoin="round"
75+
d="M18 18.72a9.094 9.094 0 0 0 3.741-.479 3 3 0 0 0-4.682-2.72m.94 3.198.001.031c0 .225-.012.447-.037.666A11.944 11.944 0 0 1 12 21c-2.17 0-4.207-.576-5.963-1.584A6.062 6.062 0 0 1 6 18.719m12 0a5.971 5.971 0 0 0-.941-3.197m0 0A5.995 5.995 0 0 0 12 12.75a5.995 5.995 0 0 0-5.058 2.772m0 0a3 3 0 0 0-4.681 2.72 8.986 8.986 0 0 0 3.74.477m.94-3.197a5.971 5.971 0 0 0-.94 3.197M15 6.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Zm6 3a2.25 2.25 0 1 1-4.5 0 2.25 2.25 0 0 1 4.5 0Zm-13.5 0a2.25 2.25 0 1 1-4.5 0 2.25 2.25 0 0 1 4.5 0Z"
76+
/>
77+
</svg>
78+
{project.totalRepoContributorCount}
79+
</div>
80+
</div>
81+
</>
82+
)}
83+
</Link>
84+
);
85+
}

0 commit comments

Comments
 (0)