Skip to content

Commit 4d851d5

Browse files
authored
Merge pull request #3 from Infvyr/migrate_ui_from_chakraui_to_tailwindcss
Migrate UI from chakraui to tailwindcss
2 parents 074684a + 941c626 commit 4d851d5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+6565
-20616
lines changed

.eslintrc.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55
// "next/babel",
66
"next/core-web-vitals",
77
"prettier"
8-
]
8+
],
9+
"rules": {
10+
"no-unused-vars": "warn"
11+
}
912
}

app/error.js

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
"use client";
22

3-
import { useEffect } from "react";
4-
import { Button, Flex, Text } from "@chakra-ui/react";
5-
63
export default function Error({ error, reset }) {
7-
useEffect(() => {
8-
console.error(error);
9-
}, [error]);
10-
114
return (
12-
<Flex gap={5} direction="column" alignItems="center">
13-
<Text color="red.200">Something went wrong!</Text>
14-
<Button onClick={() => reset()} variant="outline" colorScheme="red">
5+
<div className="h-full w-full flex-center flex-col gap-5">
6+
<p className="text-3xl text-red-500">Something went wrong! </p>
7+
<p className="text-red-500">{error.toString()}</p>
8+
<button className="btn" onClick={() => reset()}>
159
Retry
16-
</Button>
17-
</Flex>
10+
</button>
11+
</div>
1812
);
1913
}

app/layout.js

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,20 @@
1-
"use client";
2-
31
import { Suspense } from "react";
4-
import { ChakraProvider, Box } from "@chakra-ui/react";
5-
import { AppHeader, AppFooter } from "components";
6-
import { LayoutProvider } from "context/layout";
7-
import { theme, navigationHeight, footerHeight } from "util/theme-config";
2+
import { AppHeader, AppFooter, AppMetadata } from "components";
83
import Loading from "./loading";
4+
import "styles/globals.css";
5+
import { ThemeContext } from "context";
96

10-
// export const metadata = { ...AppMetadata };
7+
export const metadata = { ...AppMetadata };
118

129
export default function RootLayout({ children }) {
1310
return (
1411
<html lang="en">
1512
<body>
16-
<ChakraProvider theme={theme}>
13+
<ThemeContext>
1714
<AppHeader />
18-
19-
<LayoutProvider>
20-
<Box as="main" minHeight={`calc(100vh - ${navigationHeight}px - ${footerHeight}px)`}>
21-
<Suspense fallback={<Loading />}>{children}</Suspense>
22-
</Box>
23-
<AppFooter />
24-
</LayoutProvider>
25-
</ChakraProvider>
15+
<Suspense fallback={<Loading />}>{children}</Suspense>
16+
<AppFooter />
17+
</ThemeContext>
2618
</body>
2719
</html>
2820
);

app/loading.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
"use client";
2-
31
import { Loader } from "components";
42

53
export default function Loading() {
6-
return <Loader width="100%" />;
4+
return (
5+
<div className="flex-center">
6+
<Loader textClassNames="text-2xl text-center" />
7+
</div>
8+
);
79
}

app/page.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import { WelcomeSection, AboutSection, TechnologiesSection, ProjectsSection } fr
44

55
export default function Page() {
66
return (
7-
<>
7+
<div className="container-md">
88
<WelcomeSection />
99
<AboutSection />
1010
<ProjectsSection />
1111
<TechnologiesSection />
12-
</>
12+
</div>
1313
);
1414
}

app/projects/components/Filter.jsx

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,63 @@
1-
import { useRef } from "react";
1+
import { useRef, useState } from "react";
22
import { LazyMotion, domAnimation, useInView } from "framer-motion";
3-
import { Flex, Button, Heading, HStack } from "@chakra-ui/react";
43
import { TbBrandJavascript, TbBrandNextjs } from "react-icons/tb";
54
import { FaReact } from "react-icons/fa";
5+
import { FilterButton } from "./FilterButton";
66

77
export function Filter({ onClick = (f) => f }) {
88
const animRef = useRef(null);
99
const isInView = useInView(animRef, { once: true });
10+
const [activeFilter, setActiveFilter] = useState(undefined);
11+
12+
const handleFilterClick = (filter) => {
13+
onClick(filter);
14+
setActiveFilter(filter);
15+
};
1016

1117
return (
1218
<LazyMotion features={domAnimation}>
13-
<Flex
14-
py={8}
15-
gap={3}
16-
alignItems="center"
19+
<div
1720
ref={animRef}
18-
sx={{
21+
className="flex items-start flex-col sm:flex-row sm:items-center gap-4 my-10"
22+
style={{
1923
opacity: isInView ? 1 : 0,
20-
transition: "all 0.9s cubic-bezier(0.17, 0.55, 0.55, 1) 0.5s"
24+
transition: "all 0.9s cubic-bezier(0.17, 0.55, 0.55, 1) 1s"
2125
}}
2226
>
23-
<Heading as="h3" fontSize="xl" aria-label="Filter projects" tabIndex="0">
27+
<h3 aria-label="Filter projects" tabIndex="0" className="font-bold text-xl">
2428
Filter by:
25-
</Heading>
26-
<HStack>
27-
<Button
28-
variant="outline"
29-
onClick={() => onClick(undefined)}
30-
aria-label="Show all projects"
29+
</h3>
30+
<div className="flex items-center gap-4">
31+
<FilterButton
32+
onClick={() => handleFilterClick(undefined)}
33+
label="All"
34+
active={activeFilter === undefined}
3135
>
3236
All
33-
</Button>
34-
<Button
35-
variant="outline"
36-
onClick={() => onClick("React")}
37-
aria-label="Filter projects by react"
37+
</FilterButton>
38+
<FilterButton
39+
onClick={() => handleFilterClick("React")}
40+
label="React"
41+
active={activeFilter === "React"}
3842
>
3943
<FaReact size="20" />
40-
</Button>
41-
<Button
42-
variant="outline"
43-
onClick={() => onClick("Next")}
44-
aria-label="Filter projects by next"
44+
</FilterButton>
45+
<FilterButton
46+
onClick={() => handleFilterClick("Next")}
47+
label="Next"
48+
active={activeFilter === "Next"}
4549
>
4650
<TbBrandNextjs size="20" />
47-
</Button>
48-
<Button
49-
variant="outline"
50-
onClick={() => onClick("Javascript")}
51-
aria-label="Filter projects by javascript"
51+
</FilterButton>
52+
<FilterButton
53+
onClick={() => handleFilterClick("Javascript")}
54+
label="Javascript"
55+
active={activeFilter === "Javascript"}
5256
>
5357
<TbBrandJavascript size="20" />
54-
</Button>
55-
</HStack>
56-
</Flex>
58+
</FilterButton>
59+
</div>
60+
</div>
5761
</LazyMotion>
5862
);
5963
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export function FilterButton({ onClick, label, active, children }) {
2+
const activeClassName = "icon-link-btn--active";
3+
return (
4+
<button
5+
className={`icon-link-btn icon-link-btn--outline w-14 h-10 ${active ? activeClassName : ""}`}
6+
onClick={onClick}
7+
aria-label={`Filter projects by ${label.toLowerCase()}`}
8+
>
9+
{children}
10+
</button>
11+
);
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { ProjectItem } from "../../sections";
2+
3+
export function Projects({ projects }) {
4+
return (
5+
<div className="grid grid-cols-1 sm:grid-cols-3 gap-8">
6+
{projects
7+
?.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
8+
?.map((project, index) => (
9+
<ProjectItem key={project._id} project={project} index={index} />
10+
))}
11+
</div>
12+
);
13+
}

app/projects/layout.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"use client";
2+
3+
import { Suspense, useState } from "react";
4+
import useSWR from "swr";
5+
import { ErrorBoundary } from "react-error-boundary";
6+
import { HeadingDivider, Loader } from "components";
7+
import { Filter } from "./components/Filter";
8+
import { fetcher } from "utils/fetcher";
9+
import Error from "../error";
10+
import { Projects } from "./components/Projects";
11+
12+
const url = `${process.env.NEXT_PUBLIC_SANITY_URL}${process.env.NEXT_PUBLIC_SANITY_ALL_PROJECTS}`;
13+
14+
export default function Page() {
15+
const [category, setCategory] = useState(undefined);
16+
const filterUrl = `${process.env.NEXT_PUBLIC_SANITY_URL}${process.env.NEXT_PUBLIC_SANITY_PROJECTS}${category}${process.env.NEXT_PUBLIC_SANITY_PROJECT_BY_CATEGORY}`;
17+
18+
const fetchUrl = category ? filterUrl : url;
19+
const { data, error } = useSWR(fetchUrl, fetcher);
20+
const filteredProjects = data?.result;
21+
22+
const onClick = (catName) => setCategory(catName);
23+
24+
if (error) {
25+
return <div className="container-md">Error loading projects...</div>;
26+
}
27+
28+
return (
29+
<div className="container-md">
30+
<section id="projects" className="section">
31+
<HeadingDivider title="Relevant projects" />
32+
33+
<Filter onClick={onClick} />
34+
35+
<Suspense
36+
fallback={
37+
<div className="flex-center">
38+
<Loader />
39+
</div>
40+
}
41+
>
42+
<ErrorBoundary FallbackComponent={Error}>
43+
{filteredProjects === undefined ? (
44+
// Loading state
45+
<div className="flex-center">
46+
<Loader />
47+
</div>
48+
) : filteredProjects.length === 0 ? (
49+
// Empty state
50+
<div className="flex-center">
51+
<h3 className="text-2xl">No projects found in {category} category</h3>
52+
</div>
53+
) : (
54+
<Projects projects={filteredProjects} />
55+
)}
56+
</ErrorBoundary>
57+
</Suspense>
58+
</section>
59+
</div>
60+
);
61+
}

app/projects/page.js

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,7 @@
1-
"use client";
1+
export const metadata = {
2+
title: `Projects`
3+
};
24

3-
import { useState } from "react";
4-
import useSWR from "swr";
5-
import { ErrorBoundary } from "react-error-boundary";
6-
import { Box, SimpleGrid } from "@chakra-ui/react";
7-
import { HeadingDivider } from "components";
8-
import { ProjectItem } from "app/sections/project/ProjectItem";
9-
import { Filter } from "./components/Filter";
10-
import { fetcher } from "util/fetcher";
11-
import Error from "../error";
12-
13-
const url = `${process.env.NEXT_PUBLIC_SANITY_URL}${process.env.NEXT_PUBLIC_SANITY_ALL_PROJECTS}`;
14-
15-
export default function Page() {
16-
const [category, setCategory] = useState();
17-
const filterUrl = `${process.env.NEXT_PUBLIC_SANITY_URL}?query=*%5B_type%20%3D%3D%20%22projects%22%20%26%26%20category%5B0%5D-%3Etitle%20%3D%3D%20%22${category}%22%5D%7B%0A%20%20_id%2C%0A%20%20createdAt%2C%0A%20%20%22category%22%3A%20category%5B0%5D-%3Etitle%2C%0A%20%20description%2C%0A%20%20title%2C%0A%20%20%22poster%22%3A%20poster.asset-%3Eurl%2C%0A%20%20liveUrl%2C%0A%20%20repoUrl%2C%0A%20%20%22images%22%3A%20images%5B%5D.asset-%3Eurl%2C%0A%20%20%22stack%22%3A%20stack%5B%5D-%3Etitle%0A%7D%20%7C%20order(createdAt%20desc)`;
18-
19-
const fetchUrl = category ? filterUrl : url;
20-
const { data: filteredProjs } = useSWR(fetchUrl, fetcher);
21-
const filteredProjects = filteredProjs?.result;
22-
23-
const onClick = (catName) => setCategory(catName);
24-
25-
return (
26-
<Box as="section" id="projects" className="section">
27-
<HeadingDivider title="Relevant projects" />
28-
29-
<Filter onClick={onClick} />
30-
31-
<ErrorBoundary FallbackComponent={Error}>
32-
<SimpleGrid spacingY={10} spacingX={6} columns={[1, 1, 3]}>
33-
{filteredProjects
34-
?.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
35-
?.map((project) => (
36-
<ProjectItem key={project._id} project={project} />
37-
))}
38-
</SimpleGrid>
39-
</ErrorBoundary>
40-
</Box>
41-
);
5+
export default function Page({ children }) {
6+
return <div className="container-md">{children}</div>;
427
}

0 commit comments

Comments
 (0)