Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions website/src/components/Button.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Link from '@docusaurus/Link';
import clsx from 'clsx';
import React from 'react';

import styles from './Button.module.css';
import CrawleeSvg from '../../static/img/crawlee-logo-monocolor.svg';

export default function Button({ children, to, withIcon, type = 'primary', className, isBig }) {
return (
<Link to={to} target="_self" rel="dofollow">
<span className={clsx(
className,
styles.button,
type === 'primary' && styles.buttonPrimary,
type === 'secondary' && styles.buttonSecondary,
isBig && styles.big,
)}>
{withIcon && <CrawleeSvg />}
{children}
</span>
</Link>
);
}
63 changes: 63 additions & 0 deletions website/src/components/Button.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
.button {
display: inline-flex;
align-items: center;
text-align: center;
padding: 8px 16px;
border-radius: 8px;
font-family: (--ifm-font-family-base);
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 24px;
cursor: pointer;
transition: background-color 0.2s;

svg {
margin-right: 8px;
}
}

.buttonPrimary {
background-color: var(--color-black-action);
color: var(--color-text-on-primary);
border: none;

path {
stroke: var(--color-text-on-primary);
&:first-child {
fill: var(--color-text-on-primary);
}
}
}

.buttonPrimary:hover {
background-color: var(--color-primary-action-hover);
}

.buttonSecondary {
background-color: var(--color-background);
color: var(--color-text);
border: 1px solid var(--color-border);

path {
stroke: var(--color-black-action);
&:first-child {
fill: var(--color-black-action);
}
}
}

.buttonSecondary:hover {
border: 1px solid var(--color-text);
}

.big {
padding: 12px 24px;
}

/* TABLET */
@media (min-width: 768px) {
.button {
width: auto;
}
}
34 changes: 34 additions & 0 deletions website/src/components/CopyButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* eslint-disable max-len */
import clsx from 'clsx';
import React, { useState } from 'react';

import styles from './CopyButton.module.css';

export default function CopyButton({ copyText, compact = false, className }) {
const [copied, setCopied] = useState(false);
const copy = async () => {
await navigator.clipboard.writeText(copyText);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return <button
type="button"
aria-label="Copy code to clipboard"
title="Copy"
onClick={copy}
className={clsx(className, styles.copyButton, compact ? styles.copyButtonCompact : styles.copyButtonDefault)}
>
{copied
? <svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fillRule="evenodd" clipRule="evenodd" d="M18.0303 5.09467C18.3232 5.38756 18.3232 5.86244 18.0303 6.15533L8.03033 16.1553C7.73744 16.4482 7.26256 16.4482 6.96967 16.1553L2.59467 11.7803C2.30178 11.4874 2.30178 11.0126 2.59467 10.7197C2.88756 10.4268 3.36244 10.4268 3.65533 10.7197L7.5 14.5643L16.9697 5.09467C17.2626 4.80178 17.7374 4.80178 18.0303 5.09467Z" />
</svg>

: <svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.375 2.375C7.13236 2.375 6.125 3.38236 6.125 4.625V6.125H4.625C3.38236 6.125 2.375 7.13236 2.375 8.375V15.375C2.375 16.6176 3.38236 17.625 4.625 17.625H11.625C12.8676 17.625 13.875 16.6176 13.875 15.375V13.875H15.375C16.6176 13.875 17.625 12.8676 17.625 11.625V4.625C17.625 3.38236 16.6176 2.375 15.375 2.375H8.375ZM13.875 12.375H15.375C15.7892 12.375 16.125 12.0392 16.125 11.625V4.625C16.125 4.21079 15.7892 3.875 15.375 3.875H8.375C7.96079 3.875 7.625 4.21079 7.625 4.625V6.125H11.625C12.8676 6.125 13.875 7.13236 13.875 8.375V12.375ZM4.625 7.625C4.21079 7.625 3.875 7.96079 3.875 8.375V15.375C3.875 15.7892 4.21079 16.125 4.625 16.125H11.625C12.0392 16.125 12.375 15.7892 12.375 15.375V8.375C12.375 7.96079 12.0392 7.625 11.625 7.625H4.625Z" />
</svg>
}
</button>;
}
37 changes: 37 additions & 0 deletions website/src/components/CopyButton.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.copyButton {
all: unset;
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
cursor: pointer;
fill: var(--color-icon);

svg {
flex-shrink: 0;
}
}

.copyButtonDefault {
width: 28px;
height: 28px;
background-color: var(--color-editor);
border: 1px solid var(--color-border);
border-radius: 6px;
transition: background-color 0.12s ease-out;

&:hover {
background-color: var(--color-hover);
}

svg {
padding: 1px;
}
}

.copyButtonCompact {
svg {
width: 16px;
height: 16px;
}
}
23 changes: 23 additions & 0 deletions website/src/components/Homepage/HomepageCliExample.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';

import CopyButton from '../CopyButton';
import styles from './HomepageCliExample.module.css';

const cliCommand = `npx crawlee create my-crawler`;

export default function CliExample() {
return (
<section className={styles.cliExampleSection}>
<div className={styles.cliExampleTitle}>
Or start with a template from our CLI
</div>
<pre className={styles.cliExampleCodeBlock}>
{cliCommand}
<CopyButton copyText={cliCommand} />
</pre>
<div className={styles.cliExampleSubtitle}>
Built with 🤍 by Apify. Forever free and open-source.
</div>
</section>
);
}
50 changes: 50 additions & 0 deletions website/src/components/Homepage/HomepageCliExample.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
.cliExampleSection {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
padding: 16px;
}

.cliExampleTitle {
color: var(--color-text-muted);
font-size: 18px;
font-style: normal;
font-weight: 400;
line-height: 28px;
margin-bottom: 16px;
}

.cliExampleCodeBlock {
width: 100%;
padding: 12px 16px;
background-color: var(--color-editor);
border: 1px solid var(--color-border);
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
font-size: 14px;
line-height: 20px;

/* TABLET */
@media (min-width: 768px) {
max-width: 526px;
}
}

.cliExampleSubtitle {
color: var(--color-text-subtle);
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 24px;
}

/* TABLET */
@media (min-width: 768px) {
.cliExampleSection {
padding: 64px 0;
}
}
48 changes: 48 additions & 0 deletions website/src/components/Homepage/HomepageCtaSection.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import ThemedImage from '@theme/ThemedImage';
import clsx from 'clsx';
import React from 'react';

import styles from './HomepageCtaSection.module.css';
import Button from '../Button';

export default function HomepageCtaSection({ showJs, showPython }) {
return (
<section className={styles.ctaSection}>
<h2 className={styles.ctaTitle}>Get started now!</h2>
<div className={styles.ctaDescription}>
Crawlee won’t fix broken selectors for you (yet), but it makes
building and maintaining reliable crawlers faster and easier—so
you can focus on what matters most.
</div>
<div className={styles.ctaButtonContainer}>
{showJs && (
<Button
to="/js"
withIcon
type={showJs && showPython ? 'secondary' : 'primary'}
isBig
>
{showPython ? 'Get started with JS' : 'Get started'}
</Button>
)}
{showPython && (
<Button
to="https://crawlee.dev/python"
withIcon
type="secondary"
isBig
>
{showJs ? 'Get started with Python' : 'Get started'}
</Button>
)}
</div>
<ThemedImage
className={styles.ctaImage}
sources={{
light: '/img/animated-crawlee-logo-light.svg',
dark: '/img/animated-crawlee-logo-dark.svg',
}}
/>
</section>
);
}
67 changes: 67 additions & 0 deletions website/src/components/Homepage/HomepageCtaSection.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
.ctaSection {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
padding: 16px;
padding-bottom: 0;
gap: 24px;
}

.ctaTitle {
color: var(--color-text);
font-family: 'Lota Grotesque';
font-size: 36px;
font-style: normal;
font-weight: 400;
line-height: 46px;
margin: 0;
}

.ctaDescription {
color: var(--color-text-muted);
font-size: 18px;
font-style: normal;
font-weight: 400;
line-height: 28px;
max-width: 780px;
}

.ctaButtonContainer {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
gap: 16px;
width: 100%;
}

.ctaImage {
z-index: -1;
margin-top: -100px;
}

#ctaDecorativeCircle {
width: 120px;
height: 120px;
left: -60px;
top: -60px;
}

/* TABLET */
@media (min-width: 768px) {
.ctaSection {
padding-top: 80px;
}

.ctaTitle {
font-size: 48px;
line-height: 56px;
}

.ctaButtonContainer {
flex-direction: row;
}
}
31 changes: 31 additions & 0 deletions website/src/components/Homepage/HomepageHeroSection.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';

import styles from './HomepageHeroSection.module.css';
import homepageStyles from '../../pages/index.module.css';

export default function HomepageHeroSection() {
return (
<section className={styles.hero}>
<h1 className={styles.heroTitle}>
Build reliable web scrapers. Fast.
</h1>
<div
className={homepageStyles.dashedSeparator}
id={styles.separatorHeroHeader}
/>
<p className={styles.heroSubtitle}>
Crawlee is a web scraping library for JavaScript and Python. It
handles blocking, crawling, proxies, and browsers for you.
</p>
<div
className={homepageStyles.dashedSeparator}
id={styles.separatorHeroHeader2}
>
<div
className={homepageStyles.dashedDecorativeCircle}
id={styles.heroDecorativeCircle}
/>
</div>
</section>
);
}
Loading