Skip to content

Commit

Permalink
Add benefits to homepage (#1593)
Browse files Browse the repository at this point in the history
  • Loading branch information
ovidiuch committed Jan 14, 2024
1 parent d60c866 commit c86a8ee
Show file tree
Hide file tree
Showing 10 changed files with 290 additions and 39 deletions.
62 changes: 62 additions & 0 deletions docs/components/Benefits.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
.root {
margin: 0 auto;
max-width: 1208px;
padding: min(12vw, 6rem) 0;
padding-left: max(env(safe-area-inset-left), 1.5rem);
padding-right: max(env(safe-area-inset-right), 1.5rem);
border-top: 1px solid rgb(229, 231, 235);

:global(.dark) & {
border-top: 1px solid rgb(31, 31, 31);
}
}

.benefits {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: hsl(204 12% 5%);

:global(.dark) & {
color: hsl(204, 8%, 90%);
}

@media (min-width: 768px) {
flex-direction: row;
justify-content: space-evenly;
}

@media (min-width: 960px) {
flex-direction: row;
justify-content: center;
}

li {
flex-shrink: 0;
}

li.text {
font-size: 20px;
line-height: 1.4;
font-weight: 400;
text-align: center;
white-space: nowrap;

@media (min-width: 960px) {
font-size: 22px;
}
}

li.icon {
padding: 2em 0;

@media (min-width: 768px) {
padding: 0;
}

@media (min-width: 960px) {
padding: 0 min(5vw, 6em);
}
}
}
44 changes: 44 additions & 0 deletions docs/components/Benefits.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { ReactNode } from 'react';
import styles from './Benefits.module.css';
import { Rocket } from './Rocket';

export function Benefits() {
return (
<div className={styles.root}>
<ul className={styles.benefits}>
<li className={styles.text}>
Prototype quickly, debug easily
<br />
and maintain quality at scale.
</li>
<li className={styles.icon}>
<Rocket />
</li>
<li className={styles.text}>
Stay organized with a well-
<br />
designed component library.
</li>
</ul>
</div>
);
}

// Prototype quickly, debug with ease and
// maintain quality at scale.

type FeatureProps = {
title: string;
description: string;
icon: ReactNode;
};
function Feature({ title, description, icon }: FeatureProps) {
return (
<li>
<strong>
{icon} {title}
</strong>{' '}
{description}
</li>
);
}
34 changes: 28 additions & 6 deletions docs/components/Features.module.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
.features {
.root {
margin: 0 auto;
max-width: 1208px;
padding: min(12vw, 5rem) 0;
padding-left: max(env(safe-area-inset-left), 1.5rem);
padding-right: max(env(safe-area-inset-right), 1.5rem);
border-top: 1px solid rgb(229, 231, 235);

:global(.dark) & {
border-top: 1px solid rgb(31, 31, 31);
}

h3 {
position: absolute;
left: 50%;
padding: 0 32px;
transform: translate(-50%, -50%);
background-color: #f3f4f6;
text-transform: uppercase;
font-size: 15px;
letter-spacing: 0.1em;
font-weight: 400;
font-weight: 500;
color: hsl(204 12% 45%);

:global(.dark) & {
background-color: #000;
color: hsl(204, 8%, 50%);
}
}
}

.features {
padding: min(12vw, 6rem) 0;
display: grid;
grid-template-columns: repeat(1, 1fr);
place-items: start center;
Expand All @@ -18,10 +44,6 @@
grid-template-columns: repeat(3, 1fr);
}

:global(.dark) & {
border-top: 1px solid rgb(31, 31, 31);
}

li {
max-width: 300px;
color: hsl(204 12% 45%);
Expand Down
67 changes: 35 additions & 32 deletions docs/components/Features.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,41 @@ import ZapSvg from './svg/icons/zap.svg';

export function Features() {
return (
<ul className={styles.features}>
<Feature
title="Fixtures"
description="File-system based module convention for defining component states effortlessly."
icon={<CodeSvg />}
/>
<Feature
title="User Interface"
description="Beautiful interface for browsing fixtures and manipulating component inputs."
icon={<MonitorSvg />}
/>
<Feature
title="Static Export"
description="Interactive component library deployable to any static hosting service."
icon={<UploadCloudSvg />}
/>
<Feature
title="Integration"
description="Vite, Webpack, React Native, Next.js, and support for custom setups."
icon={<SettingsSvg />}
/>
<Feature
title="Plugins"
description="Full-stack plugin system for extending every aspect of React Cosmos."
icon={<BoxSvg />}
/>
<Feature
title="High Quality"
description="100% TypeScript. Minimal deps. Meticulously designed and tested."
icon={<ZapSvg />}
/>
</ul>
<div className={styles.root}>
<h3>Key Features</h3>
<ul className={styles.features}>
<Feature
title="Fixtures"
description="File-system based module convention for defining component states effortlessly."
icon={<CodeSvg />}
/>
<Feature
title="User Interface"
description="Beautiful interface for browsing fixtures and manipulating component inputs."
icon={<MonitorSvg />}
/>
<Feature
title="Static Export"
description="Interactive component library deployable to any static hosting service."
icon={<UploadCloudSvg />}
/>
<Feature
title="Integration"
description="Vite, Webpack, React Native, Next.js, and support for custom setups."
icon={<SettingsSvg />}
/>
<Feature
title="Plugins"
description="Full-stack plugin system for extending every aspect of React Cosmos."
icon={<BoxSvg />}
/>
<Feature
title="High Quality"
description="100% TypeScript. Minimal deps. Meticulously designed and tested."
icon={<ZapSvg />}
/>
</ul>
</div>
);
}

Expand Down
2 changes: 2 additions & 0 deletions docs/components/Homepage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useData } from 'nextra/data';
import { Benefits } from './Benefits';
import { Features } from './Features';
import styles from './Homepage.module.css';
import { HomepageHero } from './HomepageHero';
Expand All @@ -24,6 +25,7 @@ export function Homepage() {
<img src="/demo.png" />
</a>
<HomepageLogos />
<Benefits />
<Features />
</div>
</div>
Expand Down
8 changes: 8 additions & 0 deletions docs/components/HomepageHero.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@
font-weight: 400;
line-height: 1.6;

br {
display: none;

@media (min-width: 810px) {
display: block;
}
}

:global(.dark) & {
color: hsl(204, 12%, 50%);
}
Expand Down
2 changes: 1 addition & 1 deletion docs/components/HomepageHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function HomepageHero({ version, stars: initialStars }: Props) {
</h1>
<p className={styles.subtitle}>
React Cosmos is a sandbox for developing and testing UI components in
isolation. <br className="hidden lg:block" />
isolation. <br />
It&apos;s fast, extendable and easy to install.{' '}
<span className="whitespace-nowrap">Our users love it.</span>
</p>
Expand Down
51 changes: 51 additions & 0 deletions docs/components/Rocket.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.root {
margin: 0 auto;
width: 120px;
height: 120px;
border-radius: 50%;
background-image: linear-gradient(0deg, hsl(204 12% 90%), hsl(204 12% 94%));
transition: opacity 0.8s;
overflow: hidden;
/* https://stackoverflow.com/a/58283449/128816 */
transform: translateZ(0);

@media (min-width: 960px) {
width: 140px;
height: 140px;
}

:global(.dark) & {
background-image: linear-gradient(0deg, hsl(204, 8%, 8%), hsl(204, 8%, 4%));
}
}

.icon {
position: relative;
width: 50%;
height: 50%;
fill: currentColor;
animation: hover 0.5s infinite ease;
transition:
left,
0.4s ease-out,
bottom 0.4s ease-out;
transition-delay: 0.4s;

@keyframes hover {
0% {
transform: translateY(-1px) translateX(-1px);
}
25% {
transform: translateX(1px) translateY(1px);
}
50% {
transform: translateX(-1px) translateY(1px);
}
75% {
transform: translateX(1px) translateY(-1px);
}
100% {
transform: translateY(-1px) translateX(-1px);
}
}
}
21 changes: 21 additions & 0 deletions docs/components/Rocket.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useViewportEnter } from '../utils/useViewportEnter';
import styles from './Rocket.module.css';

export function Rocket() {
const [ref, entered] = useViewportEnter();
const offset = entered ? 0 : 75;
return (
<div className={styles.root} ref={ref} style={{ opacity: entered ? 1 : 0 }}>
<svg
className={styles.icon}
viewBox="0 0 24 24"
style={{
left: `${25 - offset}%`,
top: `${27 + offset}%`,
}}
>
<path d="M8.566 17.842c-.945 2.462-3.678 4.012-6.563 4.161.139-2.772 1.684-5.608 4.209-6.563l.51.521c-1.534 1.523-2.061 2.765-2.144 3.461.704-.085 2.006-.608 3.483-2.096l.505.516zm-1.136-11.342c-1.778-.01-4.062.911-5.766 2.614-.65.649-1.222 1.408-1.664 2.258 1.538-1.163 3.228-1.485 5.147-.408.566-1.494 1.32-3.014 2.283-4.464zm5.204 17.5c.852-.44 1.61-1.013 2.261-1.664 1.708-1.706 2.622-4.001 2.604-5.782-1.575 1.03-3.125 1.772-4.466 2.296 1.077 1.92.764 3.614-.399 5.15zm11.312-23.956c-.428-.03-.848-.044-1.261-.044-9.338 0-14.465 7.426-16.101 13.009l4.428 4.428c5.78-1.855 12.988-6.777 12.988-15.993v-.059c-.002-.437-.019-.884-.054-1.341zm-5.946 7.956c-1.105 0-2-.895-2-2s.895-2 2-2 2 .895 2 2-.895 2-2 2z" />
</svg>
</div>
);
}
38 changes: 38 additions & 0 deletions docs/utils/useViewportEnter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';

export function useViewportEnter() {
const [el, setEl] = React.useState<HTMLElement | null>(null);
const [entered, setEntered] = React.useState(false);

React.useEffect(() => {
if (el === null) return () => {};

function updateEntered() {
const newEntered = hasEnteredViewport(el.offsetTop, el.offsetHeight);
if (newEntered && !entered) {
setEntered(true);
} else if (entered && !newEntered && scrolledToTop()) {
setEntered(false);
}
}

updateEntered();
window.addEventListener('scroll', updateEntered);
window.addEventListener('resize', updateEntered);

return () => {
window.removeEventListener('scroll', updateEntered);
window.removeEventListener('resize', updateEntered);
};
}, [el, entered]);

return [setEl, entered] as const;
}

function hasEnteredViewport(elTop: number, elHeight: number) {
return window.scrollY > elTop - window.innerHeight + elHeight;
}

function scrolledToTop() {
return window.scrollY === 0;
}

0 comments on commit c86a8ee

Please sign in to comment.