faster animations and copy button

This commit is contained in:
Robby Klein 2020-02-12 14:13:34 -08:00
parent 6d89dbaef8
commit a35d66a1cb
13 changed files with 300 additions and 223 deletions

View File

@ -1,24 +1,24 @@
import React from 'react' import React from "react";
import Fade from 'react-reveal/Fade' import Fade from "react-reveal/Fade";
import Reveal from 'react-reveal/Reveal' import Reveal from "react-reveal/Reveal";
import { Arrow, FooterOrb, FooterCube, Built } from '../../svg' import { Arrow, FooterOrb, FooterCube, Built } from "../../svg";
import './Footer.scss' import "./Footer.scss";
import { Mailing } from '..' import { Mailing } from "..";
export default function Footer() { export default function Footer() {
return ( return (
<Reveal effect="active"> <Reveal effect="active">
<footer className="footer"> <footer className="footer">
<div className="width"> <div className="width">
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<div className="footer-column"> <div className="footer-column">
<Built /> <Built />
</div> </div>
</Fade> </Fade>
<div className="footer-column"> <div className="footer-column">
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<h2>Sia Elsewhere</h2> <h2>Sia Elsewhere</h2>
<ul> <ul>
@ -48,7 +48,7 @@ export default function Footer() {
</div> </div>
<div className="footer-column"> <div className="footer-column">
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<h2>Social</h2> <h2>Social</h2>
<ul> <ul>
<li> <li>
@ -77,7 +77,7 @@ export default function Footer() {
</div> </div>
<div className="footer-column"> <div className="footer-column">
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<h2>Stay up-to-date with Skynet updates</h2> <h2>Stay up-to-date with Skynet updates</h2>
<Mailing id="check2" light /> <Mailing id="check2" light />
</Fade> </Fade>
@ -88,5 +88,5 @@ export default function Footer() {
<FooterOrb className="footer-orb fadeInUp delay2" /> <FooterOrb className="footer-orb fadeInUp delay2" />
</footer> </footer>
</Reveal> </Reveal>
) );
} }

View File

@ -1,15 +1,15 @@
import React from 'react' import React from "react";
import Fade from 'react-reveal/Fade' import Fade from "react-reveal/Fade";
import './HomeBuilt.scss' import "./HomeBuilt.scss";
import { CircleIcon, CodeExamples } from '../' import { CircleIcon, CodeExamples } from "../";
import { Cylinder, SmallOrb } from '../../svg' import { Cylinder, SmallOrb } from "../../svg";
export default function HomeBuilt() { export default function HomeBuilt() {
return ( return (
<div className="home-built"> <div className="home-built">
<header className="home-built-header"> <header className="home-built-header">
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<div className="home-built-divider"> <div className="home-built-divider">
<div className="small-divider" /> <div className="small-divider" />
<div className="divider" /> <div className="divider" />
@ -22,7 +22,7 @@ export default function HomeBuilt() {
<div className="small-divider" /> <div className="small-divider" />
</div> </div>
</Fade> </Fade>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<h2> <h2>
Infrastructure built for Infrastructure built for
<br /> <br />
@ -31,9 +31,9 @@ export default function HomeBuilt() {
</Fade> </Fade>
</header> </header>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<CodeExamples /> <CodeExamples />
</Fade> </Fade>
</div> </div>
) );
} }

View File

@ -1,36 +1,36 @@
import React, { Component } from 'react' import React, { Component } from "react";
import CountUp from 'react-countup' import CountUp from "react-countup";
import VisibilitySensor from 'react-visibility-sensor' import VisibilitySensor from "react-visibility-sensor";
import Fade from 'react-reveal/Fade' import Fade from "react-reveal/Fade";
import './HomeNetwork.scss' import "./HomeNetwork.scss";
import { CircleIcon, FAQ } from '../' import { CircleIcon, FAQ } from "../";
import { SmallOrb, LogoSolid, Arrow, Deco6, Deco7, Deco8 } from '../../svg' import { SmallOrb, LogoSolid, Arrow, Deco6, Deco7, Deco8 } from "../../svg";
const stats = [ const stats = [
{ name: 'TB Used', value: 664 }, { name: "TB Used", value: 664 },
{ name: 'TB Capacity', value: 2315 }, { name: "TB Capacity", value: 2315 },
{ name: 'Hosts', value: 335 }, { name: "Hosts", value: 335 },
{ name: 'Storage/TB', value: 91, cent: true }, { name: "Storage/TB", value: 91, cent: true },
{ name: 'Bandwidth/TB', value: 18, cent: true }, { name: "Bandwidth/TB", value: 18, cent: true }
] ];
export default class HomeNetwork extends Component { export default class HomeNetwork extends Component {
state = { state = {
visable: false, visable: false
} };
onChange = isVisible => { onChange = isVisible => {
if (isVisible && !this.state.visable) { if (isVisible && !this.state.visable) {
this.setState({ visable: true }) this.setState({ visable: true });
} }
} };
render() { render() {
return ( return (
<div className="home-network"> <div className="home-network">
<header className="home-network-header"> <header className="home-network-header">
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<div className="home-network-divider"> <div className="home-network-divider">
<CircleIcon> <CircleIcon>
<LogoSolid /> <LogoSolid />
@ -40,7 +40,7 @@ export default class HomeNetwork extends Component {
<div className="small-divider"></div> <div className="small-divider"></div>
</div> </div>
</Fade> </Fade>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<h2> <h2>
Sia Sia
<br /> <br />
@ -49,16 +49,25 @@ export default class HomeNetwork extends Component {
</Fade> </Fade>
</header> </header>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<VisibilitySensor onChange={this.onChange} partialVisibility offset={{ bottom: 100 }} scrollThrottle={50}> <VisibilitySensor
onChange={this.onChange}
partialVisibility
offset={{ bottom: 100 }}
scrollThrottle={50}
>
<div className="home-network-stats"> <div className="home-network-stats">
{stats.map((stat, i) => ( {stats.map((stat, i) => (
<React.Fragment key={i}> <React.Fragment key={i}>
<div key={i} className="home-network-stat"> <div key={i} className="home-network-stat">
<div className="inner"> <div className="inner">
<h3> <h3>
{this.state.visable ? <CountUp end={stat.value} duration={3.2} /> : 0} {this.state.visable ? (
{stat.cent && '¢'} <CountUp end={stat.value} duration={3.2} />
) : (
0
)}
{stat.cent && "¢"}
</h3> </h3>
<span className="network-stat-name">{stat.name}</span> <span className="network-stat-name">{stat.name}</span>
</div> </div>
@ -75,25 +84,31 @@ export default class HomeNetwork extends Component {
<div className="home-network-columns"> <div className="home-network-columns">
<div className="home-network-column left"> <div className="home-network-column left">
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<p> <p>
Skynet Webportal is a low cost server that sits between Skynet and everyday users, enabling them to Skynet Webportal is a low cost server that sits between Skynet
access Skynet content without needing to operate any special software. Once the Skylinks are generated, and everyday users, enabling them to access Skynet content
they can be shared with anyone to fetch data from Skynet. The original uploader does not need to stay without needing to operate any special software. Once the
online in order for the file to remain available. The Sia network handles all of the pinning, Skylinks are generated, they can be shared with anyone to fetch
guaranteeing both high speeds and excellent uptime. A typical Skynet download starts in under 500 data from Skynet. The original uploader does not need to stay
milliseconds and can stream at rates as high as 1 gigabit per second. The Sia network serves as the online in order for the file to remain available. The Sia
backend storage layer for Skynet. network handles all of the pinning, guaranteeing both high
speeds and excellent uptime. A typical Skynet download starts in
under 500 milliseconds and can stream at rates as high as 1
gigabit per second. The Sia network serves as the backend
storage layer for Skynet.
</p> </p>
</Fade> </Fade>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<p> <p>
Sia is the leading decentralized cloud storage platform. No signups, no servers, no trusted third Sia is the leading decentralized cloud storage platform. No
parties. Sia leverages blockchain technology to create a data storage marketplace that is more robust signups, no servers, no trusted third parties. Sia leverages
and more affordable than traditional cloud storage providers. Storage costs are as much as 10x lower blockchain technology to create a data storage marketplace that
than traditional infrastructure, bandwidth costs as much as 100x lower, all without sacrificing is more robust and more affordable than traditional cloud
performance or reliability. storage providers. Storage costs are as much as 10x lower than
traditional infrastructure, bandwidth costs as much as 100x
lower, all without sacrificing performance or reliability.
</p> </p>
<p> <p>
@ -104,41 +119,45 @@ export default class HomeNetwork extends Component {
</Fade> </Fade>
</div> </div>
<div className="home-network-column"> <div className="home-network-column">
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<FAQ title="What does pinning mean?"> <FAQ title="What does pinning mean?">
<p> <p>
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer Lorem Ipsum has been the industry's standard dummy text ever
took a galley of type and scrambled it to make. since the 1500s, when an unknown printer took a galley of type
and scrambled it to make.
</p> </p>
</FAQ> </FAQ>
</Fade> </Fade>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<FAQ title="Is my data secure?"> <FAQ title="Is my data secure?">
<p> <p>
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Sed posuere consectetur est at lobortis. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
Sed posuere consectetur est at lobortis.
</p> </p>
</FAQ> </FAQ>
</Fade> </Fade>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<FAQ title="How does Sia compare to other decentralized storage solutions?"> <FAQ title="How does Sia compare to other decentralized storage solutions?">
<p> <p>
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Sed posuere consectetur est at lobortis. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
Sed posuere consectetur est at lobortis.
</p> </p>
</FAQ> </FAQ>
</Fade> </Fade>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<FAQ title="How long will my files be available?"> <FAQ title="How long will my files be available?">
<p> <p>
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer Lorem Ipsum has been the industry's standard dummy text ever
took a galley of type and scrambled it to make a type specimen book. since the 1500s, when an unknown printer took a galley of type
and scrambled it to make a type specimen book.
</p> </p>
</FAQ> </FAQ>
</Fade> </Fade>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<a className="more more-faq" href="https://support.sia.tech/"> <a className="more more-faq" href="https://support.sia.tech/">
View more faq View more faq
<Arrow /> <Arrow />
@ -147,6 +166,6 @@ export default class HomeNetwork extends Component {
</div> </div>
</div> </div>
</div> </div>
) );
} }
} }

View File

@ -1,37 +1,42 @@
import React from 'react' import React from "react";
import Fade from 'react-reveal/Fade' import Fade from "react-reveal/Fade";
import Reveal from 'react-reveal/Reveal' import Reveal from "react-reveal/Reveal";
import './HomeSamples.scss' import "./HomeSamples.scss";
import { Sample } from '../' import { Sample } from "../";
const samples = [ const samples = [
{ type: 'HTML', url: '#' }, { type: "HTML", url: "#" },
{ type: 'PDF', url: '#' }, { type: "PDF", url: "#" },
{ type: 'Image', url: '#' }, { type: "Image", url: "#" },
{ type: 'Audio', url: '#' }, { type: "Audio", url: "#" },
{ type: 'Video', url: '#' }, { type: "Video", url: "#" },
{ type: 'JSON', url: '#' }, { type: "JSON", url: "#" },
{ type: 'Dapps', url: '#' }, { type: "Dapps", url: "#" }
] ];
export default function HomeSamples() { export default function HomeSamples() {
return ( return (
<div className="home-samples"> <div className="home-samples">
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<p> <p>
Skynet has SDKs for popular programming languages which integrate seamlessly with existing applications. Above Skynet has SDKs for popular programming languages which integrate
are a few code snippets for uploading and downloading data from Skynet. seamlessly with existing applications. Above are a few code snippets
for uploading and downloading data from Skynet.
</p> </p>
</Fade> </Fade>
<Reveal effect="active"> <Reveal effect="active">
<div className="home-samples-samples"> <div className="home-samples-samples">
{samples.map((sample, i) => ( {samples.map((sample, i) => (
<Sample className={`fadeInUp delay${(i + 1) * 2}`} key={`${i}-${sample.url}`} {...sample} /> <Sample
className={`fadeInUp delay${i + 1}`}
key={`${i}-${sample.url}`}
{...sample}
/>
))} ))}
</div> </div>
</Reveal> </Reveal>
</div> </div>
) );
} }

View File

@ -1,16 +1,16 @@
import React, { Component } from 'react' import React, { Component } from "react";
import Fade from 'react-reveal/Fade' import Fade from "react-reveal/Fade";
import './HomeStay.scss' import "./HomeStay.scss";
import { SocialLink, CircleIcon, Mailing } from '../' import { SocialLink, CircleIcon, Mailing } from "../";
import { SmallOrb, Pyramid } from '../../svg' import { SmallOrb, Pyramid } from "../../svg";
export default class HomeStay extends Component { export default class HomeStay extends Component {
render() { render() {
return ( return (
<div className="home-stay"> <div className="home-stay">
<header className="home-stay-header"> <header className="home-stay-header">
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<div className="home-stay-divider"> <div className="home-stay-divider">
<CircleIcon> <CircleIcon>
<Pyramid /> <Pyramid />
@ -20,7 +20,7 @@ export default class HomeStay extends Component {
<div className="small-divider" /> <div className="small-divider" />
</div> </div>
</Fade> </Fade>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<h2> <h2>
Stay up to date with Stay up to date with
<br /> <br />
@ -31,27 +31,27 @@ export default class HomeStay extends Component {
<div className="home-stay-flex"> <div className="home-stay-flex">
<div className="home-stay-left"> <div className="home-stay-left">
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<p> <p>
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cras justo odio, dapibus ac Integer posuere erat a ante venenatis dapibus posuere velit
facilisis in. aliquet. Cras justo odio, dapibus ac facilisis in.
</p> </p>
</Fade> </Fade>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<Mailing id="check1" /> <Mailing id="check1" />
</Fade> </Fade>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<p className="disclaimer-text"> <p className="disclaimer-text">
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cras justo odio, dapibus ac Integer posuere erat a ante venenatis dapibus posuere velit
facilisis in. aliquet. Cras justo odio, dapibus ac facilisis in.
</p> </p>
</Fade> </Fade>
</div> </div>
<ul className="home-stay-right"> <ul className="home-stay-right">
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<li> <li>
<SocialLink <SocialLink
icon="github" icon="github"
@ -65,7 +65,7 @@ export default class HomeStay extends Component {
/> />
</li> </li>
</Fade> </Fade>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<li> <li>
<SocialLink <SocialLink
icon="discord" icon="discord"
@ -75,7 +75,7 @@ export default class HomeStay extends Component {
/> />
</li> </li>
</Fade> </Fade>
<Fade distance="40px" bottom> <Fade duration={700} distance="40px" bottom>
<li> <li>
<SocialLink <SocialLink
icon="twitter" icon="twitter"
@ -88,6 +88,6 @@ export default class HomeStay extends Component {
</ul> </ul>
</div> </div>
</div> </div>
) );
} }
} }

View File

@ -1,8 +1,8 @@
import React from 'react' import React from "react";
import Reveal from 'react-reveal/Reveal' import Reveal from "react-reveal/Reveal";
import './HomeTop.scss' import "./HomeTop.scss";
import { Skynet, Deco1, Deco2 } from '../../svg' import { Skynet, Deco1, Deco2 } from "../../svg";
export default function HomeTop() { export default function HomeTop() {
return ( return (
@ -12,11 +12,14 @@ export default function HomeTop() {
<h1 className="fadeInUp delay2">Build the Future Web.</h1> <h1 className="fadeInUp delay2">Build the Future Web.</h1>
<p className="fadeInUp delay4">Skynet is a decentralized file sharing and content distribution protocol.</p> <p className="fadeInUp delay3">
Skynet is a decentralized file sharing and content distribution
protocol.
</p>
<Deco1 className="deco-1 fadeInUp delay8" /> <Deco1 className="deco-1 fadeInUp delay6" />
<Deco2 className="deco-2 fadeInUp delay8" /> <Deco2 className="deco-2 fadeInUp delay6" />
</div> </div>
</Reveal> </Reveal>
) );
} }

View File

@ -1,4 +1,4 @@
@import '../../variables.scss'; @import "../../variables.scss";
.home-top { .home-top {
text-align: center; text-align: center;
@ -47,8 +47,8 @@
.deco-1 { .deco-1 {
position: absolute; position: absolute;
left: 100%; left: 100%;
bottom: 54%; bottom: 25%;
margin-left: -20px; margin-left: 20px;
animation: 6s float infinite; animation: 6s float infinite;
@media (min-width: 591px) { @media (min-width: 591px) {
@ -59,8 +59,8 @@
.deco-2 { .deco-2 {
position: absolute; position: absolute;
left: 100%; left: 100%;
bottom: 34%; bottom: 5%;
margin-left: -40px; margin-left: -15px;
animation: 8s float infinite; animation: 8s float infinite;
@media (min-width: 591px) { @media (min-width: 591px) {

View File

@ -1,43 +1,47 @@
import React, { Component } from 'react' import React, { Component } from "react";
import classNames from 'classnames' import classNames from "classnames";
import Dropzone from 'react-dropzone' import Dropzone from "react-dropzone";
import Reveal from 'react-reveal/Reveal' import Reveal from "react-reveal/Reveal";
import { Button, UploadFile } from '../' import { Button, UploadFile } from "../";
import { Deco3, Deco4, Deco5 } from '../../svg' import { Deco3, Deco4, Deco5 } from "../../svg";
import './HomeUpload.scss' import "./HomeUpload.scss";
export default class HomeUpload extends Component { export default class HomeUpload extends Component {
state = { files: [] } state = { files: [] };
handleDrop = async acceptedFiles => { handleDrop = async acceptedFiles => {
this.setState({ this.setState({
files: [ files: [
...acceptedFiles.map(file => { ...acceptedFiles.map(file => {
return { file, status: 'uploading' } return { file, status: "uploading" };
}), }),
...this.state.files, ...this.state.files
], ]
}) });
acceptedFiles.forEach(async (file) => { acceptedFiles.forEach(async file => {
const url = `https://siasky.net/api/skyfile?filename=${file.name}` const url = `https://siasky.net/api/skyfile?filename=${file.name}`;
const fd = new FormData() const fd = new FormData();
fd.append("file", file) fd.append("file", file);
const onComplete = (status, skylink) => { const onComplete = (status, skylink) => {
this.setState((state) => { this.setState(state => {
const index = state.files.findIndex((f) => f.file === file); const index = state.files.findIndex(f => f.file === file);
return { return {
files: [ files: [
...state.files.slice(0, index), ...state.files.slice(0, index),
{ ...state.files[index], status, url: `https://siasky.net/${skylink}` }, {
...state.files[index],
status,
url: `https://siasky.net/${skylink}`
},
...state.files.slice(index + 1) ...state.files.slice(index + 1)
] ]
} };
}) });
} };
try { try {
const response = await fetch(url, { const response = await fetch(url, {
@ -47,26 +51,30 @@ export default class HomeUpload extends Component {
}); });
const { skylink } = await response.json(); const { skylink } = await response.json();
onComplete('complete', skylink); onComplete("complete", skylink);
} catch(error) { } catch (error) {
onComplete('error'); onComplete("error");
} }
}) });
} };
render() { render() {
return ( return (
<Reveal effect="active"> <Reveal effect="active">
<div className="home-upload"> <div className="home-upload">
<div className="home-upload-box fadeInUp delay6"> <div className="home-upload-box fadeInUp delay4">
<Dropzone onDrop={acceptedFiles => this.handleDrop(acceptedFiles)}> <Dropzone onDrop={acceptedFiles => this.handleDrop(acceptedFiles)}>
{({ getRootProps, getInputProps, isDragActive }) => ( {({ getRootProps, getInputProps, isDragActive }) => (
<> <>
<div <div
className={classNames('home-upload-dashed', { 'drop-active': isDragActive })} className={classNames("home-upload-dashed", {
"drop-active": isDragActive
})}
{...getRootProps()} {...getRootProps()}
> >
<span className="home-upload-text">Drag &amp; drop your file(s) here to pin</span> <span className="home-upload-text">
Drag &amp; drop your file(s) here to pin
</span>
<Button>Browse</Button> <Button>Browse</Button>
</div> </div>
<input {...getInputProps()} className="offscreen" /> <input {...getInputProps()} className="offscreen" />
@ -77,22 +85,23 @@ export default class HomeUpload extends Component {
{this.state.files.length > 0 && ( {this.state.files.length > 0 && (
<div className="home-uploaded-files"> <div className="home-uploaded-files">
{this.state.files.map((file, i) => { {this.state.files.map((file, i) => {
return <UploadFile key={i} {...file} /> return <UploadFile key={i} {...file} />;
})} })}
</div> </div>
)} )}
</div> </div>
<p className="bottom-text fadeInUp delay8"> <p className="bottom-text fadeInUp delay5">
Once a file has been uploaded, a 46 byte link called a 'Skylink' is generated. That link can then be shared Once a file has been uploaded, a 46 byte link called a 'Skylink' is
with anyone to fetch the file from Skynet. generated. That link can then be shared with anyone to fetch the
file from Skynet.
</p> </p>
<Deco3 className="deco-3 fadeInUp delay8" /> <Deco3 className="deco-3 fadeInUp delay6" />
<Deco4 className="deco-4 fadeInUp delay8" /> <Deco4 className="deco-4 fadeInUp delay6" />
<Deco5 className="deco-5 fadeInUp delay8" /> <Deco5 className="deco-5 fadeInUp delay6" />
</div> </div>
</Reveal> </Reveal>
) );
} }
} }

View File

@ -1,4 +1,4 @@
@import '../../variables.scss'; @import "../../variables.scss";
.home-upload { .home-upload {
position: relative; position: relative;
@ -19,7 +19,8 @@
.home-upload-box { .home-upload-box {
background: $white; background: $white;
border-radius: 12px; border-radius: 12px;
box-shadow: 0 8px 24px 0 rgba(90, 94, 91, 0.15), 0 2px 4px 0 rgba(0, 0, 0, 0.05); box-shadow: 0 8px 24px 0 rgba(90, 94, 91, 0.15),
0 2px 4px 0 rgba(0, 0, 0, 0.05);
padding: 16px; padding: 16px;
} }
@ -97,10 +98,14 @@
.home-uploaded-files { .home-uploaded-files {
border: solid 1px #c5cec7; border: solid 1px #c5cec7;
padding: 0 40px; padding: 0 20px;
margin-top: 10px; margin-top: 10px;
border-radius: 4px; border-radius: 4px;
@media (min-width: $largebp) {
padding: 0 40px;
}
.upload-file + .upload-file { .upload-file + .upload-file {
border-top: 1px solid rgba(197, 206, 199, 0.4); border-top: 1px solid rgba(197, 206, 199, 0.4);
} }

View File

@ -1,73 +1,82 @@
import React, { Component } from 'react' import React, { Component } from "react";
import './UploadFile.scss' import "./UploadFile.scss";
import { LoadingSpinner } from '../' import { LoadingSpinner } from "../";
import { File, FileCheck, FileError, Copy } from '../../svg' import { File, FileCheck, FileError, Copy } from "../../svg";
export default class UploadFile extends Component { export default class UploadFile extends Component {
state = { state = {
copied: false, copied: false
} };
getIcon = () => { getIcon = () => {
const { status } = this.props // const { status } = this.props;
const status = "complete";
if (status === 'uploading' || status === 'processing') { if (status === "uploading" || status === "processing") {
return <File /> return <File />;
} else if (status === 'error') { } else if (status === "error") {
return <FileError /> return <FileError />;
} else { } else {
return <FileCheck /> return <FileCheck />;
} }
} };
copyToClipboard = e => { copyToClipboard = e => {
this.urlRef.current.select() this.urlRef.current.select();
document.execCommand('copy') document.execCommand("copy");
e.target.focus() e.target.focus();
this.setState({ copied: true }, () => { this.setState({ copied: true }, () => {
setTimeout(() => { setTimeout(() => {
this.setState({ copied: false }) this.setState({ copied: false });
}, 1500) }, 1500);
}) });
} };
urlRef = React.createRef() urlRef = React.createRef();
render() { render() {
const { file, url, status } = this.props const { file, url } = this.props;
const copyText = this.state.copied ? 'Copied!' : 'Copy to clipboard'
const status = "complete";
const copyText = this.state.copied ? "Copied!" : "Copy to clipboard";
return ( return (
<div className="upload-file"> <div className="upload-file">
<div className="upload-file-icon">{this.getIcon()}</div> <div className="upload-file-icon">{this.getIcon()}</div>
<div className="upload-file-text"> <div className="upload-file-text">
<h3>{file.name}</h3> <h3>{file.name}</h3>
<p> <p>
{status === 'uploading' && 'Uploading...'} {status === "uploading" && "Uploading..."}
{status === 'processing' && 'Processing...'} {status === "processing" && "Processing..."}
{status === 'error' && <span className="red-text">Error processing file.</span>} {status === "error" && (
{status === 'complete' && ( <span className="red-text">Error processing file.</span>
)}
{status === "complete" && (
<a href={url} className="url green-text"> <a href={url} className="url green-text">
{url} {url}
</a> </a>
)} )}
</p> </p>
</div> </div>
{(status === 'uploading' || status === 'processing') && ( {(status === "uploading" || status === "processing") && (
<div className="upload-file-loading"> <div className="upload-file-loading">
<LoadingSpinner /> <LoadingSpinner />
</div> </div>
)} )}
{status === 'complete' && ( {status === "complete" && (
<button onClick={this.copyToClipboard} className="upload-file-copy"> <button onClick={this.copyToClipboard} className="upload-file-copy">
<p className="upload-file-copy-tooltip">{copyText}</p> <p className="upload-file-copy-tooltip">{copyText}</p>
<Copy /> <div className="upload-file-copy-button">
Copy Link
<Copy />
</div>
<textarea value={url} ref={this.urlRef} /> <textarea value={url} ref={this.urlRef} />
</button> </button>
)} )}
</div> </div>
) );
} }
} }

View File

@ -1,4 +1,4 @@
@import '../../variables.scss'; @import "../../variables.scss";
.upload-file { .upload-file {
display: flex; display: flex;
@ -97,8 +97,36 @@
top: 100%; top: 100%;
left: 50%; left: 50%;
margin-left: -6px; margin-left: -6px;
content: ''; content: "";
position: absolute; position: absolute;
box-shadow: 0 2px 8px 0 rgba(23, 25, 23, 0.2); box-shadow: 0 2px 8px 0 rgba(23, 25, 23, 0.2);
} }
} }
.upload-file-copy-button {
border: 1px solid $green;
border-radius: 3px;
color: $green;
line-height: 40px;
font-size: 13px;
padding: 0 10px;
display: inline-flex;
align-items: center;
font-weight: 700;
transition: 0.2s color, 0.2s background-color;
@media (min-width: $largebp) {
font-size: 14px;
padding: 0 15px;
line-height: 46px;
}
&:hover {
background-color: $green;
color: $white;
}
svg {
margin-left: 10px;
}
}

View File

@ -1,41 +1,41 @@
@import './variables.scss'; @import "./variables.scss";
@font-face { @font-face {
font-family: 'Haas Grot Disp'; font-family: "Haas Grot Disp";
src: url('/fonts/hinted-subset-HaasGrotDispR-55Roman.woff2') format('woff2'), src: url("/fonts/hinted-subset-HaasGrotDispR-55Roman.woff2") format("woff2"),
url('/fonts/hinted-subset-HaasGrotDispR-55Roman.woff') format('woff'); url("/fonts/hinted-subset-HaasGrotDispR-55Roman.woff") format("woff");
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
} }
@font-face { @font-face {
font-family: 'Haas Grot Disp'; font-family: "Haas Grot Disp";
src: url('/fonts/hinted-subset-HaasGrotDispR-65Medium.woff2') format('woff2'), src: url("/fonts/hinted-subset-HaasGrotDispR-65Medium.woff2") format("woff2"),
url('/fonts/hinted-subset-HaasGrotDispR-65Medium.woff') format('woff'); url("/fonts/hinted-subset-HaasGrotDispR-65Medium.woff") format("woff");
font-weight: 700; font-weight: 700;
font-style: normal; font-style: normal;
} }
@font-face { @font-face {
font-family: 'Haas Grot Text'; font-family: "Haas Grot Text";
src: url('/fonts/hinted-subset-HaasGrotTextR-75Bold.woff2') format('woff2'), src: url("/fonts/hinted-subset-HaasGrotTextR-75Bold.woff2") format("woff2"),
url('/fonts/hinted-subset-HaasGrotTextR-75Bold.woff') format('woff'); url("/fonts/hinted-subset-HaasGrotTextR-75Bold.woff") format("woff");
font-weight: bold; font-weight: bold;
font-style: normal; font-style: normal;
} }
@font-face { @font-face {
font-family: 'Haas Grot Text'; font-family: "Haas Grot Text";
src: url('/fonts/hinted-subset-HaasGrotTextR-65Medium.woff2') format('woff2'), src: url("/fonts/hinted-subset-HaasGrotTextR-65Medium.woff2") format("woff2"),
url('/fonts/hinted-subset-HaasGrotTextR-65Medium.woff') format('woff'); url("/fonts/hinted-subset-HaasGrotTextR-65Medium.woff") format("woff");
font-weight: 600; font-weight: 600;
font-style: normal; font-style: normal;
} }
@font-face { @font-face {
font-family: 'Haas Grot Text'; font-family: "Haas Grot Text";
src: url('/fonts/hinted-subset-HaasGrotTextR-55Roman.woff2') format('woff2'), src: url("/fonts/hinted-subset-HaasGrotTextR-55Roman.woff2") format("woff2"),
url('/fonts/hinted-subset-HaasGrotTextR-55Roman.woff') format('woff'); url("/fonts/hinted-subset-HaasGrotTextR-55Roman.woff") format("woff");
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }
@ -88,10 +88,10 @@ textarea {
font-size: 16px; font-size: 16px;
} }
input[type='email'], input[type="email"],
input[type='text'], input[type="text"],
input[type='password'], input[type="password"],
input[type='search'] { input[type="search"] {
display: block; display: block;
width: 100%; width: 100%;
} }
@ -99,9 +99,9 @@ input[type='search'] {
a, a,
button, button,
label, label,
input[type='submit'], input[type="submit"],
input[type='checkbox'], input[type="checkbox"],
input[type='radio'] { input[type="radio"] {
cursor: pointer; cursor: pointer;
} }
@ -181,7 +181,7 @@ svg {
.fadeInUp { .fadeInUp {
transform: translateY(40px); transform: translateY(40px);
opacity: 0; opacity: 0;
transition: 1s opacity, 1s transform; transition: 0.7s opacity, 0.7s transform;
.active & { .active & {
opacity: 1; opacity: 1;

View File

@ -1,17 +1,16 @@
import React from 'react' import React from "react";
export default function Copy(props) { export default function Copy(props) {
return ( return (
<svg width={18} height={18} viewBox="0 0 18 18" {...props}> <svg width={12} height={14} viewBox="0 0 12 14" {...props}>
<path <path
d="M15 13v2a2 2 0 01-2 2H3a2 2 0 01-2-2V5a2 2 0 012-2h2m2.464 3.293L6.05 7.707a3 3 0 104.243 4.243l1.414-1.414h0m-1.414-7.072l1.414-1.414a3 3 0 114.243 4.243l-1.414 1.414h0M8.879 9.121L13.12 4.88" d="M8 1H4a3 3 0 00-3 3v6h0m4-6h5a1 1 0 011 1v7a1 1 0 01-1 1H5a1 1 0 01-1-1V5a1 1 0 011-1z"
stroke="currentColor" stroke="currentColor"
strokeWidth={2} strokeWidth={2}
fill="none" fill="none"
fillRule="evenodd" fillRule="evenodd"
strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> />
</svg> </svg>
) );
} }