Skip to content

Commit

Permalink
[ IMPROVEMENT ] Landing page redesign (#231)
Browse files Browse the repository at this point in the history
* base for landing page redesign

* landing page image based on darkmode state

* refactor/style improvements

* footer, landing page refined, refactor code

* react device detect for mobile specific layout

* social link component for footer

* initial landing page done

* fix build error

* resolve PR comments
  • Loading branch information
Winston-Hsiao authored Aug 3, 2024
1 parent e3c0384 commit d2a2f81
Show file tree
Hide file tree
Showing 14 changed files with 383 additions and 44 deletions.
43 changes: 39 additions & 4 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "frontend",
"version": "0.1.0",
"name": "k-scale-store",
"version": "0.1.1",
"private": true,
"dependencies": {
"@hookform/resolvers": "^3.9.0",
Expand All @@ -23,6 +23,7 @@
"postcss": ">=8.4.31",
"radix-ui": "^1.0.1",
"react": "^18.3.1",
"react-device-detect": "^2.2.3",
"react-dom": "^18.3.1",
"react-dropzone": "^14.2.3",
"react-hook-form": "^7.52.1",
Expand Down
4 changes: 2 additions & 2 deletions frontend/public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"short_name": "K-Scale",
"name": "K-Scale Store",
"icons": [
{
"src": "favicon.ico",
Expand Down
10 changes: 6 additions & 4 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import Container from "components/Container";
import Footer from "components/footer/Footer";
import Navbar from "components/nav/Navbar";
import NotFoundRedirect from "components/NotFoundRedirect";
import { AlertQueue, AlertQueueProvider } from "hooks/alerts";
import { AuthenticationProvider } from "hooks/auth";
import { DarkModeProvider } from "hooks/dark_mode";
import { DarkModeProvider } from "hooks/useDarkMode";
import About from "pages/About";
import APIKeys from "pages/APIKeys";
import Browse from "pages/Browse";
Expand All @@ -25,8 +27,7 @@ const App = () => {
<AlertQueue>
<div className="dark:bg-gray-900 dark:text-white min-h-screen">
<Navbar />

<div className="container mx-auto py-24 px-8">
<Container>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
Expand All @@ -40,7 +41,8 @@ const App = () => {
<Route path="/404" element={<NotFound />} />
<Route path="*" element={<NotFoundRedirect />} />
</Routes>
</div>
</Container>
<Footer />
</div>
</AlertQueue>
</AlertQueueProvider>
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/components/Container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ReactNode } from "react";
import { useLocation } from "react-router-dom";

interface ContainerProps {
children: ReactNode;
}

const Container = (props: ContainerProps) => {
const { children } = props;
const location = useLocation();
const { pathname } = location;

// Landing page/home path
if (pathname === "/") {
return <div className="pt-16">{children}</div>;
}

return <div className="container mx-auto pt-24 px-8">{children}</div>;
};

export default Container;
97 changes: 97 additions & 0 deletions frontend/src/components/footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { FaDiscord, FaGithub, FaLinkedinIn } from "react-icons/fa";
import { Link, useLocation } from "react-router-dom";
import {
DiscordPrimaryColor,
GithubPrimaryColor,
LinkedinPrimaryColor,
} from "types/colors";
import SocialLink from "./SocialLink";

const Footer = () => {
const location = useLocation();
const { pathname } = location;

// Show/hide footer based on pathname
// - to hide footer on a page add path to this
const showFooter =
pathname?.startsWith("/browse") === false &&
pathname?.startsWith("/some-other-path-to-hide-footer") === false;

if (!showFooter) {
return null;
}

return (
<footer className="bg-gray-50 dark:bg-gray-800 text-sm py-20">
<div className="flex flex-col gap-4 mx-12 sm:mx-36">
<div className="flex flex-row justify-between items-center">
<span className="text-2xl">K-Scale Labs</span>
<div className="flex flex-row gap-4 rounded-full">
<SocialLink
href="https://www.linkedin.com/company/kscale"
ariaLabel="Visit K-Scale's LinkedIn Page"
bgColor={LinkedinPrimaryColor}
ringColor="focus:ring-sky-500"
>
<FaLinkedinIn />
</SocialLink>
<SocialLink
href="https://github.com/kscalelabs/store"
ariaLabel="Visit K-Scale's Github Page"
bgColor={GithubPrimaryColor}
ringColor="focus:ring-black"
>
<FaGithub />
</SocialLink>
<SocialLink
href="https://discord.gg/rhCy6UdBRD"
ariaLabel="Join K-Scale's Discord"
bgColor={DiscordPrimaryColor}
ringColor="focus:ring-black"
>
<FaDiscord />
</SocialLink>
</div>
</div>
<div className="flex flex-row gap-32 sm:gap-56 md:gap-64">
<div className="flex flex-col items-start gap-2 sm:gap-3">
<h2 className="text-lg font-semibold mb-1">Company</h2>
<a
href="https://kscale.dev/about/"
className="hover:text-gray-500"
target="_blank"
rel="noopener noreferrer"
>
About us
</a>
<a href="" className="hover:text-gray-500">
News
</a>
<a href="" className="hover:text-gray-500">
Blog
</a>
</div>
<div className="flex flex-col items-start gap-2 sm:gap-3">
<h2 className="text-lg font-semibold mb-1">Buy and Sell</h2>
<Link to={"/browse"} className="hover:text-gray-500">
Robots
</Link>
<Link to={"/browse"} className="hover:text-gray-500">
Parts
</Link>
<Link to={"/browse"} className="hover:text-gray-500">
Designs
</Link>
</div>
</div>
<div className="mt-10 text-xs">
<p>
<span>©</span> {new Date().getFullYear()} K-Scale Labs
</p>
</div>
</div>
</footer>
);
};

export default Footer;
43 changes: 43 additions & 0 deletions frontend/src/components/footer/SocialLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { FC, ReactNode } from "react";

interface SocialLinkProps {
href: string;
ariaLabel: string;
bgColor: string;
ringColor: string;
children: ReactNode; // social link icon
className?: string;
}

const SocialLink: FC<SocialLinkProps> = ({
href,
ariaLabel,
bgColor,
ringColor,
children,
className,
}) => {
return (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
className={`
hover:bg-opacity-80
rounded-full
text-white
cursor-pointer
focus:outline-none
focus:ring-2 focus:ring-offset-2 ${ringColor}
${className}
`}
style={{ backgroundColor: bgColor }}
>
<button className="text-xl p-2 rounded-full" aria-label={ariaLabel}>
{children}
</button>
</a>
);
};

export default SocialLink;
66 changes: 66 additions & 0 deletions frontend/src/components/home/Features.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { FaGear, FaMessage, FaRobot } from "react-icons/fa6";

const Features = () => {
const features = [
{
name: "Buy and sell robots",
description: "Buy and sell completed robots, parts, and designs.",
icon: <FaRobot />,
},
{
name: "Find parts",
description:
"Actuators, motors, and more! Buy, sell, and read about any part. Get recommendations and suggestions to help you with your project.",
icon: <FaGear />,
},
{
name: "Join the converstation",
description:
"Join the K-Scale discord for Q&A and to see what other people are building.",
icon: <FaMessage />,
},
// {
// name: "Another feature item",
// description: "Description tbd",
// // icon: <Icon />, // tbd
// },
];

return (
<div className="my-20 mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-2xl lg:text-center">
<h2 className="text-lg font-semibold leading-6 text-blue-700 dark:text-blue-300">
Robots made here.
</h2>
<p className="mt-2 text-3xl font-bold tracking-tight sm:text-4xl">
Everything you need to build your next robot
</p>
<p className="mt-6 text-lg leading-8 text-gray-600 dark:text-gray-300">
Talk with professionals, researchers, and hobbyists.
</p>
</div>

<div className="mx-auto mt-16 max-w-2xl sm:mt-20 lg:mt-24 lg:max-w-4xl">
<dl className="grid max-w-xl grid-cols-1 gap-x-8 gap-y-10 lg:max-w-none lg:grid-cols-2 lg:gap-y-16">
{features.map((feature) => (
<div key={feature.name} className="relative pl-16">
<dt className="text-base font-semibold leading-7">
<div className="absolute left-0 top-0 flex h-10 w-10 items-center justify-center rounded-lg bg-blue-700">
<div aria-hidden="true" className="text-xl text-white">
{feature.icon}
</div>
</div>
{feature.name}
</dt>
<dd className="mt-2 text-base leading-7 text-gray-600 dark:text-gray-300">
{feature.description}
</dd>
</div>
))}
</dl>
</div>
</div>
);
};

export default Features;
Loading

0 comments on commit d2a2f81

Please sign in to comment.