Skip to content

Commit

Permalink
built a listing website demo
Browse files Browse the repository at this point in the history
  • Loading branch information
Big-Mineon committed Feb 1, 2024
0 parents commit b8d8fe4
Show file tree
Hide file tree
Showing 29 changed files with 11,578 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
35 changes: 35 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
14 changes: 14 additions & 0 deletions assets/Logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Icon } from "@chakra-ui/react";

function Logo() {
return (
<Icon viewBox="0 0 46 32" w="10" h="10">
<path
d="M19.557.113C11.34.32 9.117 8.757 9.03 12.95c1.643-2.67 4.62-3.08 6.931-3.08 2.825.085 10.27.205 17.458 0C40.61 9.663 44.802 3.28 46 .112c-5.391-.085-18.228-.205-26.443 0zM14.422 14.234C3.332 14.234-.468 24.76.045 31.948c3.594-6.418 7.617-7.53 9.243-7.445h6.675c5.956 0 11.039-6.846 12.836-10.27H14.422z"
fill="white"
/>
</Icon>
);
}

export default Logo;
42 changes: 42 additions & 0 deletions components/Main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// UI
import { Button, Flex, Text, useDisclosure } from "@chakra-ui/react";
// Components
import Modal from "./Modal";

function Main() {
const { isOpen, onOpen, onClose } = useDisclosure();

return (
<>
<Flex
as="main"
w="70%"
mx="auto"
textColor="white"
align="flex-start"
justify="space-between"
my="4rem"
>
<Flex direction="column">
<Text fontSize="sm">Dashboard</Text>
<Text fontSize={["2xl", "4xl"]} fontWeight="extrabold">
My Sites
</Text>
</Flex>
<Flex>
<Button
onClick={onOpen}
textColor="blackAlpha.900"
size="lg"
width={["100px", "160px"]}
>
Add Site
</Button>
</Flex>
</Flex>
<Modal isOpen={isOpen} onClose={onClose} />
</>
);
}

export default Main;
99 changes: 99 additions & 0 deletions components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useRef, useState } from "react";
import { useSWRConfig } from "swr";
// UI
import {
Button,
FormControl,
FormLabel,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
useToast,
} from "@chakra-ui/react";
// Context
import { useAuth } from "context/AuthContext";
// Firebase
import { addSite } from "lib/database";

interface Props {
isOpen: boolean;
onClose: () => void;
}

function Main({ isOpen, onClose }: Props) {
const [siteName, setSiteName] = useState("");
const [siteUrl, setSiteUrl] = useState("");

const { mutate } = useSWRConfig();

const { user } = useAuth();

const toast = useToast();

const initialRef = useRef(null);

function saveData() {
toast({
title: "Site has been created successfully.",
status: "success",
duration: 3000,
isClosable: true,
});
onClose();
addSite(user?.currentUser?.uid!, {
siteName,
siteUrl,
});
setTimeout(() => {
mutate("/api/user");
}, 500);
}

return (
<Modal
isOpen={isOpen}
onClose={onClose}
initialFocusRef={initialRef}
isCentered
motionPreset="slideInBottom"
size="lg"
>
<ModalContent>
<ModalHeader>Create your site</ModalHeader>
<ModalCloseButton />
<ModalBody pb={5}>
<FormControl mb={5}>
<FormLabel>Name</FormLabel>
<Input
onChange={(e) => setSiteName(e.target.value)}
ref={initialRef}
placeholder="Your site name"
/>
</FormControl>

<FormControl>
<FormLabel>URL</FormLabel>
<Input
onChange={(e) => setSiteUrl(e.target.value)}
placeholder="Your site URL"
/>
</FormControl>
</ModalBody>
<ModalFooter>
<Button onClick={saveData} colorScheme="linkedin" mr={4}>
Save
</Button>
<Button colorScheme="blackAlpha" onClick={onClose}>
Cancel
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}

export default Main;
58 changes: 58 additions & 0 deletions components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Link from "next/link";
// UI
import { Avatar, Flex, Text } from "@chakra-ui/react";
// Context
import { useAuth } from "context/AuthContext";
// Assets
import Logo from "assets/Logo";

function Navbar() {
const { user } = useAuth();

return (
<Flex
as="nav"
bg="blackAlpha.400"
w="100%"
h="72px"
borderTopWidth="6px"
borderTopColor="cyan.300"
align="center"
>
<Flex
w="70%"
mx="auto"
align="center"
justify="space-between"
textColor="white"
>
<Flex align="center">
<Logo />
<Link href="/dashboard">
<Text
ml={5}
userSelect="none"
fontWeight="semibold"
_hover={{
textDecoration: "underline",
textDecorationThickness: "2px",
textUnderlineOffset: "8px",
cursor: "pointer",
}}
>
Dashboard
</Text>
</Link>
</Flex>
<Link href="/profile">
<Avatar
cursor="pointer"
src={user?.currentUser?.photoURL!}
/>
</Link>
</Flex>
</Flex>
);
}

export default Navbar;
95 changes: 95 additions & 0 deletions components/Profile/Profile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { useState } from "react";
import { useRouter } from "next/router";
// UI
import {
Avatar,
Badge,
Box,
Button,
Flex,
Link,
Tag,
Text,
} from "@chakra-ui/react";
// Context
import { useAuth } from "context/AuthContext";
// Hooks
import useAuthFirebase from "hooks/useAuthFirebase";

function Profile() {
const [logout, setLogout] = useState(false);

const { user } = useAuth();
const router = useRouter();

function logoutHandler() {
setLogout(true);
router.push("/");
}

useAuthFirebase(false, logout);

return (
<Flex
align="center"
justify="center"
direction="column"
textColor="white"
mt={8}
gap={3}
>
<Avatar src={user?.currentUser?.photoURL!} size="2xl" />
<Text textAlign="center" fontSize="4xl" fontWeight="bold">
{user?.currentUser?.displayName}
</Text>
<Text mb={3} fontSize="xl">
{user?.currentUser?.email}
</Text>
<Box maxW="600px" w="90%" bg="blackAlpha.500" borderRadius="xl">
<Box borderBottom="4px">
<Flex align="center" justify="space-between" p={5}>
<Text>Settings</Text>
<Badge>Free</Badge>
</Flex>
</Box>
<Text
p={5}
textAlign="justify"
fontSize="lg"
fontWeight="semibold"
>
I developed this project as a part of a tutorial from
Youtube thanks to{" "}
<Link
color="linkedin.300"
href="https://leerob.io/"
isExternal
>
Lee Robinson
</Link>{" "}
for inspiration. I have used Chakra UI, useSWR, and Skeleton
loading for the first time with this project. I also stored
the user information on Firebase Firestore and login was
implemented with Firebase authentication.
</Text>
<Flex py={2} px={5} gap={2}>
<Tag>Github</Tag>
<Tag>NextJS</Tag>
<Tag>Firebase</Tag>
</Flex>
<Flex justifyContent="flex-end">
<Button
onClick={logoutHandler}
size="lg"
colorScheme="whiteAlpha"
m={5}
>
Sign out
</Button>
</Flex>
</Box>
</Flex>
);
}

export default Profile;
44 changes: 44 additions & 0 deletions components/Table/EmptyTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Td, Tr, Skeleton } from "@chakra-ui/react";
import TableWrapper from "./TableWrapper";

function EmptyTable() {
const longSkeleton = <Skeleton color="white" w="200px" h="20px" />;
const smallSkeleton = <Skeleton color="white" w="125px" h="20px" />;

return (
<TableWrapper>
<Tr>
<Td>{longSkeleton}</Td>
<Td>{longSkeleton}</Td>
<Td>{longSkeleton}</Td>
<Td>{longSkeleton}</Td>
</Tr>
<Tr>
<Td>{smallSkeleton}</Td>
<Td>{smallSkeleton}</Td>
<Td>{smallSkeleton}</Td>
<Td>{smallSkeleton}</Td>
</Tr>
<Tr>
<Td>{longSkeleton}</Td>
<Td>{longSkeleton}</Td>
<Td>{longSkeleton}</Td>
<Td>{longSkeleton}</Td>
</Tr>
<Tr>
<Td>{smallSkeleton}</Td>
<Td>{smallSkeleton}</Td>
<Td>{smallSkeleton}</Td>
<Td>{smallSkeleton}</Td>
</Tr>
<Tr>
<Td>{longSkeleton}</Td>
<Td>{longSkeleton}</Td>
<Td>{longSkeleton}</Td>
<Td>{longSkeleton}</Td>
</Tr>
</TableWrapper>
);
}

export default EmptyTable;
Loading

0 comments on commit b8d8fe4

Please sign in to comment.