Merge pull request #1760 from SkynetLabs/dashboard-v2-main-screen
Dashboard V2: main screen
This commit is contained in:
commit
8e648a32a0
|
@ -3,6 +3,7 @@ module.exports = {
|
||||||
addons: [
|
addons: [
|
||||||
"@storybook/addon-links",
|
"@storybook/addon-links",
|
||||||
"@storybook/addon-essentials",
|
"@storybook/addon-essentials",
|
||||||
|
"storybook-addon-gatsby",
|
||||||
{
|
{
|
||||||
name: "@storybook/addon-postcss",
|
name: "@storybook/addon-postcss",
|
||||||
options: {
|
options: {
|
||||||
|
|
|
@ -9,6 +9,7 @@ module.exports = {
|
||||||
"gatsby-plugin-react-helmet",
|
"gatsby-plugin-react-helmet",
|
||||||
"gatsby-plugin-sharp",
|
"gatsby-plugin-sharp",
|
||||||
"gatsby-transformer-sharp",
|
"gatsby-transformer-sharp",
|
||||||
|
"gatsby-plugin-styled-components",
|
||||||
"gatsby-plugin-postcss",
|
"gatsby-plugin-postcss",
|
||||||
{
|
{
|
||||||
resolve: "gatsby-source-filesystem",
|
resolve: "gatsby-source-filesystem",
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import "@fontsource/sora/300.css"; // light
|
||||||
|
import "@fontsource/sora/400.css"; // normal
|
||||||
|
import "@fontsource/sora/500.css"; // medium
|
||||||
|
import "@fontsource/sora/600.css"; // semibold
|
||||||
|
import "@fontsource/source-sans-pro/400.css"; // normal
|
||||||
|
import "@fontsource/source-sans-pro/600.css"; // semibold
|
||||||
|
import "./src/styles/global.css";
|
||||||
|
|
||||||
|
export function wrapPageElement({ element, props }) {
|
||||||
|
const Layout = element.type.Layout ?? React.Fragment;
|
||||||
|
return <Layout {...props}>{element}</Layout>;
|
||||||
|
}
|
|
@ -24,6 +24,7 @@
|
||||||
"gatsby": "^4.6.2",
|
"gatsby": "^4.6.2",
|
||||||
"gatsby-plugin-postcss": "^5.7.0",
|
"gatsby-plugin-postcss": "^5.7.0",
|
||||||
"postcss": "^8.4.6",
|
"postcss": "^8.4.6",
|
||||||
|
"pretty-bytes": "^6.0.0",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
|
@ -44,20 +45,23 @@
|
||||||
"autoprefixer": "^10.4.2",
|
"autoprefixer": "^10.4.2",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-loader": "^8.2.3",
|
"babel-loader": "^8.2.3",
|
||||||
|
"babel-plugin-preval": "^5.1.0",
|
||||||
"babel-plugin-styled-components": "^2.0.2",
|
"babel-plugin-styled-components": "^2.0.2",
|
||||||
"eslint": "^8.9.0",
|
"eslint": "^8.9.0",
|
||||||
"eslint-config-react-app": "^7.0.0",
|
"eslint-config-react-app": "^7.0.0",
|
||||||
"eslint-plugin-storybook": "^0.5.6",
|
"eslint-plugin-storybook": "^0.5.6",
|
||||||
"gatsby-plugin-alias-imports": "^1.0.5",
|
"gatsby-plugin-alias-imports": "^1.0.5",
|
||||||
"gatsby-plugin-image": "^2.6.0",
|
"gatsby-plugin-image": "^2.6.0",
|
||||||
|
"gatsby-plugin-preval": "^1.0.0",
|
||||||
"gatsby-plugin-provide-react": "^1.0.2",
|
"gatsby-plugin-provide-react": "^1.0.2",
|
||||||
"gatsby-plugin-react-helmet": "^5.6.0",
|
"gatsby-plugin-react-helmet": "^5.6.0",
|
||||||
"gatsby-plugin-sharp": "^4.6.0",
|
"gatsby-plugin-sharp": "^4.6.0",
|
||||||
"gatsby-plugin-styled-components": "^5.7.0",
|
"gatsby-plugin-styled-components": "^5.8.0",
|
||||||
"gatsby-source-filesystem": "^4.6.0",
|
"gatsby-source-filesystem": "^4.6.0",
|
||||||
"gatsby-transformer-sharp": "^4.6.0",
|
"gatsby-transformer-sharp": "^4.6.0",
|
||||||
"prettier": "2.5.1",
|
"prettier": "2.5.1",
|
||||||
"react-is": "^17.0.2",
|
"react-is": "^17.0.2",
|
||||||
|
"storybook-addon-gatsby": "^0.0.5",
|
||||||
"styled-components": "^5.3.3"
|
"styled-components": "^5.3.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import fileSize from "pretty-bytes";
|
||||||
|
import { Link } from "gatsby";
|
||||||
|
|
||||||
|
import { GraphBar } from "./GraphBar";
|
||||||
|
import { UsageGraph } from "./UsageGraph";
|
||||||
|
|
||||||
|
// TODO: get real data
|
||||||
|
const useUsageData = () => ({
|
||||||
|
files: {
|
||||||
|
used: 19_521,
|
||||||
|
limit: 20_000,
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
used: 23_000_000_000,
|
||||||
|
limit: 1_000_000_000_000,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const size = (bytes) => {
|
||||||
|
const text = fileSize(bytes, { maximumFractionDigits: 1 });
|
||||||
|
const [value, unit] = text.split(" ");
|
||||||
|
|
||||||
|
return {
|
||||||
|
text,
|
||||||
|
value,
|
||||||
|
unit,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function CurrentUsage() {
|
||||||
|
const { files, storage } = useUsageData();
|
||||||
|
|
||||||
|
const storageUsage = size(storage.used);
|
||||||
|
const storageLimit = size(storage.limit);
|
||||||
|
const filesUsedLabel = React.useMemo(() => ({ value: files.used, unit: "files" }), [files.used]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h4>
|
||||||
|
{storageUsage.text} of {storageLimit.text}
|
||||||
|
</h4>
|
||||||
|
<p className="text-palette-400">
|
||||||
|
{files.used} of {files.limit} files
|
||||||
|
</p>
|
||||||
|
<div className="relative mt-7 font-sans uppercase text-xs">
|
||||||
|
<div className="flex place-content-between">
|
||||||
|
<span>Storage</span>
|
||||||
|
<span>{storageLimit.text}</span>
|
||||||
|
</div>
|
||||||
|
<UsageGraph>
|
||||||
|
<GraphBar value={storage.used} limit={storage.limit} label={storageUsage} />
|
||||||
|
<GraphBar value={files.used} limit={files.limit} label={filesUsedLabel} />
|
||||||
|
</UsageGraph>
|
||||||
|
<div className="flex place-content-between">
|
||||||
|
<span>Files</span>
|
||||||
|
<span className="inline-flex place-content-between w-[37%]">
|
||||||
|
<Link
|
||||||
|
to="/upgrade"
|
||||||
|
className="text-primary underline-offset-3 decoration-dotted hover:text-primary-light hover:underline"
|
||||||
|
>
|
||||||
|
UPGRADE
|
||||||
|
</Link>{" "}
|
||||||
|
{/* TODO: proper URL */}
|
||||||
|
<span>{files.limit}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
const Bar = styled.div.attrs({
|
||||||
|
className: `relative flex justify-end h-4 bg-primary rounded-l rounded-r-lg`,
|
||||||
|
})`
|
||||||
|
min-width: 1rem;
|
||||||
|
width: ${({ $percentage }) => $percentage}%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const BarTip = styled.span.attrs({
|
||||||
|
className: "relative w-4 h-4 border-2 rounded-full bg-white border-primary",
|
||||||
|
})``;
|
||||||
|
|
||||||
|
const BarLabel = styled.span.attrs({
|
||||||
|
className: "bg-white rounded border-2 border-palette-200 px-3 whitespace-nowrap absolute shadow",
|
||||||
|
})`
|
||||||
|
right: max(0%, ${({ $percentage }) => 100 - $percentage}%);
|
||||||
|
top: -0.5rem;
|
||||||
|
transform: translateX(50%);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const GraphBar = ({ value, limit, label }) => {
|
||||||
|
const percentage = typeof limit !== "number" || limit === 0 ? 0 : (value / limit) * 100;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative flex items-center">
|
||||||
|
<Bar $percentage={percentage}>
|
||||||
|
<BarTip />
|
||||||
|
</Bar>
|
||||||
|
<BarLabel $percentage={percentage}>
|
||||||
|
<span className="font-sora text-lg">{label.value}</span> <span>{label.unit}</span>
|
||||||
|
</BarLabel>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,9 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
export const UsageGraph = styled.div.attrs({
|
||||||
|
className: "w-full my-3 grid grid-flow-row grid-rows-2",
|
||||||
|
})`
|
||||||
|
height: 146px;
|
||||||
|
background: url(/images/usage-graph-bg.svg) no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
`;
|
|
@ -0,0 +1,3 @@
|
||||||
|
import CurrentUsage from "./CurrentUsage";
|
||||||
|
|
||||||
|
export default CurrentUsage;
|
|
@ -0,0 +1,22 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { Table, TableBody, TableCell, TableRow } from "../Table";
|
||||||
|
|
||||||
|
export default function ActivityTable({ data }) {
|
||||||
|
return (
|
||||||
|
<Table style={{ tableLayout: "fixed" }}>
|
||||||
|
<TableBody>
|
||||||
|
{data.map(({ name, type, size, uploaded, skylink }) => (
|
||||||
|
<TableRow key={skylink}>
|
||||||
|
<TableCell>{name}</TableCell>
|
||||||
|
<TableCell className="w-[80px]">{type}</TableCell>
|
||||||
|
<TableCell className="w-[80px]" align="right">
|
||||||
|
{size}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="w-[180px]">{uploaded}</TableCell>
|
||||||
|
<TableCell>{skylink}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { Panel } from "../Panel";
|
||||||
|
import { Tab, TabPanel, Tabs } from "../Tabs";
|
||||||
|
import ActivityTable from "./ActivityTable";
|
||||||
|
import useRecentActivityData from "./useActivityData";
|
||||||
|
|
||||||
|
export default function LatestActivity() {
|
||||||
|
const { downloads, uploads } = useRecentActivityData();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Panel title="Latest activity">
|
||||||
|
<Tabs>
|
||||||
|
<Tab id="uploads" title="Uploads" />
|
||||||
|
<Tab id="downloads" title="Downloads" />
|
||||||
|
<TabPanel tabId="uploads" className="pt-4">
|
||||||
|
<ActivityTable data={uploads} />
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel tabId="downloads" className="pt-4">
|
||||||
|
<ActivityTable data={downloads} />
|
||||||
|
</TabPanel>
|
||||||
|
</Tabs>
|
||||||
|
</Panel>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
import LatestActivity from "./LatestActivity";
|
||||||
|
|
||||||
|
export default LatestActivity;
|
|
@ -0,0 +1,54 @@
|
||||||
|
const UPLOADS_DATA = [
|
||||||
|
{
|
||||||
|
name: "At_vereo_eos_censes",
|
||||||
|
type: ".mp4",
|
||||||
|
size: "2.45 MB",
|
||||||
|
uploaded: "a few seconds ago",
|
||||||
|
skylink: "_HyFqH632Rmy99c93idTtBVXeRDgaDAAWg6Bmm5P1izriu",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Miriam Klein IV",
|
||||||
|
type: ".pdf",
|
||||||
|
size: "7.52 MB",
|
||||||
|
uploaded: "01/04/2021; 17:11",
|
||||||
|
skylink: "_izriuHyFqH632Rmy99c93idTtBVXeRDgaDAAWg6Bmm5P1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tmp/QmWR6eVDVkwhAYq7X99w4xT9KNKBzwK39Fj1PDmr4ZnzMm/QmWR6eVDVkwhAYq7X99w4xT9KNKBzwK39Fj1PDmr4ZnzMm",
|
||||||
|
type: ".doc",
|
||||||
|
size: "8.15 MB",
|
||||||
|
uploaded: "10/26/2020; 7:21",
|
||||||
|
skylink: "_VXeRDgaDAAWg6Bmm5P1izriuHyFqH632Rmy99c93idTtB",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Perm_London",
|
||||||
|
type: ".avi",
|
||||||
|
size: "225.6 MB",
|
||||||
|
uploaded: "09/12/2020; 19:28",
|
||||||
|
skylink: "_eRDgaDAAWg6Bmm5P1izriuHyFqH632Rmy99c93idTtBVX",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Santa_Clara",
|
||||||
|
type: ".pdf",
|
||||||
|
size: "7.52 MB",
|
||||||
|
uploaded: "09/12/2020; 19:23",
|
||||||
|
skylink: "_AWg6Bmm5P1izriuHyFqH632Rmy99c93idTtBVXeRDgaDA",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Marysa_Labrone",
|
||||||
|
type: ".doc",
|
||||||
|
size: "8.15 MB",
|
||||||
|
uploaded: "09/12/2020; 19:21",
|
||||||
|
skylink: "_P1izriuHyFqH632Rmy99c93idTtBVXeRDgaDAAWg6Bmm5",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const DOWNLOADS_DATA = UPLOADS_DATA.slice().reverse();
|
||||||
|
|
||||||
|
// TODO: get real data
|
||||||
|
export default function useRecentActivityData() {
|
||||||
|
return {
|
||||||
|
uploads: UPLOADS_DATA,
|
||||||
|
downloads: DOWNLOADS_DATA,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,21 +1,78 @@
|
||||||
|
import { Link } from "gatsby";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
import { screen } from "../../lib/cssHelpers";
|
||||||
|
import { DropdownMenu, DropdownMenuLink } from "../DropdownMenu";
|
||||||
|
import { CogIcon, LockClosedIcon, SkynetLogoIcon } from "../Icons";
|
||||||
import { PageContainer } from "../PageContainer";
|
import { PageContainer } from "../PageContainer";
|
||||||
|
|
||||||
|
import { NavBarLink, NavBarSection } from ".";
|
||||||
|
|
||||||
const NavBarContainer = styled.div.attrs({
|
const NavBarContainer = styled.div.attrs({
|
||||||
className: `grid sticky top-0 bg-white`,
|
className: `grid sticky top-0 bg-white`,
|
||||||
})``;
|
})``;
|
||||||
|
|
||||||
const NavBarBody = styled.nav.attrs({
|
const NavBarBody = styled.nav.attrs({
|
||||||
className: "grid h-[80px] font-sans font-light text-sm",
|
className: "grid font-sans font-light text-xs sm:text-sm",
|
||||||
})`
|
})`
|
||||||
|
height: 100px;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-template-rows: 60px 40px;
|
||||||
|
grid-template-areas:
|
||||||
|
"logo dropdown"
|
||||||
|
"navigation navigation";
|
||||||
|
|
||||||
|
${screen(
|
||||||
|
"sm",
|
||||||
|
`
|
||||||
|
height: 80px;
|
||||||
grid-template-columns: auto max-content 1fr;
|
grid-template-columns: auto max-content 1fr;
|
||||||
|
grid-template-areas: "logo navigation dropdown";
|
||||||
|
grid-template-rows: auto;
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
|
||||||
|
.navigation-area {
|
||||||
|
grid-area: navigation;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-area {
|
||||||
|
grid-area: logo;
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-area {
|
||||||
|
grid-area: dropdown;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const NavBar = (props) => (
|
export const NavBar = () => (
|
||||||
<NavBarContainer>
|
<NavBarContainer>
|
||||||
<PageContainer>
|
<PageContainer className="px-0">
|
||||||
<NavBarBody {...props} />
|
<NavBarBody>
|
||||||
|
<NavBarSection className="logo-area pl-2 pr-4 md:px-0 md:w-[110px] justify-center sm:justify-start">
|
||||||
|
<SkynetLogoIcon size={48} />
|
||||||
|
</NavBarSection>
|
||||||
|
<NavBarSection className="navigation-area border-t border-palette-100">
|
||||||
|
<NavBarLink to="/" as={Link} activeClassName="!border-b-primary">
|
||||||
|
Dashboard
|
||||||
|
</NavBarLink>
|
||||||
|
<NavBarLink to="/files" as={Link} activeClassName="!border-b-primary">
|
||||||
|
Files
|
||||||
|
</NavBarLink>
|
||||||
|
<NavBarLink to="/payments" as={Link} activeClassName="!border-b-primary">
|
||||||
|
Payments
|
||||||
|
</NavBarLink>
|
||||||
|
</NavBarSection>
|
||||||
|
<NavBarSection className="dropdown-area justify-end">
|
||||||
|
<DropdownMenu title="My account">
|
||||||
|
<DropdownMenuLink href="/settings" icon={CogIcon} label="Settings" />
|
||||||
|
<DropdownMenuLink href="/logout" icon={LockClosedIcon} label="Log out" />
|
||||||
|
</DropdownMenu>
|
||||||
|
</NavBarSection>
|
||||||
|
</NavBarBody>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
</NavBarContainer>
|
</NavBarContainer>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,17 +9,7 @@ export default {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const Template = (props) => (
|
const Template = (props) => <NavBar {...props} />;
|
||||||
<NavBar {...props}>
|
|
||||||
<NavBarSection>
|
|
||||||
<NavBarLink href="/dashboard" active>
|
|
||||||
Dashboard
|
|
||||||
</NavBarLink>
|
|
||||||
<NavBarLink href="/files">Files</NavBarLink>
|
|
||||||
<NavBarLink href="/payments">Payments</NavBarLink>
|
|
||||||
</NavBarSection>
|
|
||||||
</NavBar>
|
|
||||||
);
|
|
||||||
|
|
||||||
export const DashboardTopNavigation = Template.bind({});
|
export const DashboardTopNavigation = Template.bind({});
|
||||||
DashboardTopNavigation.args = {};
|
DashboardTopNavigation.args = {};
|
||||||
|
|
|
@ -3,7 +3,7 @@ import styled from "styled-components";
|
||||||
|
|
||||||
export const NavBarLink = styled.a.attrs(({ active }) => ({
|
export const NavBarLink = styled.a.attrs(({ active }) => ({
|
||||||
className: `
|
className: `
|
||||||
min-w-[168px]
|
sm:min-w-[133px] lg:min-w-[168px]
|
||||||
flex h-full items-center justify-center
|
flex h-full items-center justify-center
|
||||||
border-x border-x-palette-100 border-b-2
|
border-x border-x-palette-100 border-b-2
|
||||||
text-palette-600 transition-colors hover:bg-palette-100/50
|
text-palette-600 transition-colors hover:bg-palette-100/50
|
||||||
|
|
|
@ -2,7 +2,7 @@ import PropTypes from "prop-types";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
export const PageContainer = styled.div.attrs({
|
export const PageContainer = styled.div.attrs({
|
||||||
className: `mx-auto w-page md:w-page-md lg:w-page-lg xl:w-page-xl`,
|
className: `mx-auto w-page lg:w-page-lg xl:w-page-xl px-2 md:px-16 lg:px-0`,
|
||||||
})``;
|
})``;
|
||||||
|
|
||||||
PageContainer.propTypes = {
|
PageContainer.propTypes = {
|
||||||
|
|
|
@ -25,7 +25,7 @@ Panel.propTypes = {
|
||||||
/**
|
/**
|
||||||
* Label of the panel
|
* Label of the panel
|
||||||
*/
|
*/
|
||||||
title: PropTypes.string,
|
title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||||
};
|
};
|
||||||
|
|
||||||
Panel.defaultProps = {
|
Panel.defaultProps = {
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
export default function Bullets({ visibleSlides, activeIndex, allSlides, changeSlide }) {
|
||||||
|
if (allSlides <= visibleSlides) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex gap-3 pt-6">
|
||||||
|
{Array(allSlides - visibleSlides + 1)
|
||||||
|
.fill(null)
|
||||||
|
.map((_, index) => (
|
||||||
|
<button
|
||||||
|
key={index}
|
||||||
|
type="button"
|
||||||
|
className={`rounded-full w-3 h-3 ${activeIndex === index ? "bg-primary" : "border-2 cursor-pointer"}`}
|
||||||
|
onClick={() => changeSlide(index)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bullets.propTypes = {
|
||||||
|
allSlides: PropTypes.number.isRequired,
|
||||||
|
activeIndex: PropTypes.number.isRequired,
|
||||||
|
visibleSlides: PropTypes.number.isRequired,
|
||||||
|
changeSlide: PropTypes.func.isRequired,
|
||||||
|
};
|
|
@ -0,0 +1,12 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
const Slide = styled.div.attrs(({ isVisible }) => ({
|
||||||
|
className: `slider-slide transition-opacity ${isVisible ? "" : "opacity-50 cursor-pointer"}`,
|
||||||
|
}))``;
|
||||||
|
|
||||||
|
Slide.propTypes = {
|
||||||
|
isVisible: PropTypes.bool.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Slide;
|
|
@ -0,0 +1,127 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import styled, { css } from "styled-components";
|
||||||
|
import theme from "../../lib/theme";
|
||||||
|
|
||||||
|
import useActiveBreakpoint from "./useActiveBreakpoint";
|
||||||
|
import Bullets from "./Bullets";
|
||||||
|
import Slide from "./Slide";
|
||||||
|
|
||||||
|
const Container = styled.div.attrs({
|
||||||
|
className: "slider w-full",
|
||||||
|
})``;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles applied to the movable element when the number of slide elements
|
||||||
|
* exceeds the number of visible slides for the current breakpoint
|
||||||
|
* */
|
||||||
|
const scrollableStyles = css`
|
||||||
|
${({ $allSlides, $visibleSlides, $activeIndex }) => `
|
||||||
|
transform: translateX(calc(-1 * ${$activeIndex} * ((100% + 1rem) / ${$visibleSlides})));
|
||||||
|
grid-template-columns: repeat(${$allSlides}, calc((100% - ${$visibleSlides - 1}rem) / ${$visibleSlides}));
|
||||||
|
`}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Scroller = styled.div.attrs({
|
||||||
|
className: "slider-scroller grid gap-4 transition-transform",
|
||||||
|
})`
|
||||||
|
${({ $scrollable }) => ($scrollable ? scrollableStyles : "")}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Slider = ({ slides, breakpoints }) => {
|
||||||
|
const { visibleSlides, scrollable } = useActiveBreakpoint(breakpoints);
|
||||||
|
const [activeIndex, setActiveIndex] = React.useState(0);
|
||||||
|
const changeSlide = React.useCallback(
|
||||||
|
(index) => {
|
||||||
|
setActiveIndex(Math.min(index, slides.length - visibleSlides)); // Don't let it scroll too far
|
||||||
|
},
|
||||||
|
[slides, visibleSlides, setActiveIndex]
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const maxIndex = slides.length - visibleSlides;
|
||||||
|
|
||||||
|
// Make sure to not scroll too far when screen size changes.
|
||||||
|
if (activeIndex > maxIndex) {
|
||||||
|
setActiveIndex(maxIndex);
|
||||||
|
}
|
||||||
|
}, [slides.length, visibleSlides, activeIndex]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Scroller
|
||||||
|
$visibleSlides={visibleSlides}
|
||||||
|
$allSlides={slides.length}
|
||||||
|
$activeIndex={activeIndex}
|
||||||
|
$scrollable={scrollable}
|
||||||
|
>
|
||||||
|
{slides.map((slide, index) => {
|
||||||
|
const isVisible = index >= activeIndex && index < activeIndex + visibleSlides;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={`slide-${index}`}>
|
||||||
|
<Slide
|
||||||
|
isVisible={isVisible || !scrollable}
|
||||||
|
onClick={scrollable && !isVisible ? () => changeSlide(index) : null}
|
||||||
|
>
|
||||||
|
{slide}
|
||||||
|
</Slide>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Scroller>
|
||||||
|
{scrollable && (
|
||||||
|
<Bullets
|
||||||
|
activeIndex={activeIndex}
|
||||||
|
allSlides={slides.length}
|
||||||
|
visibleSlides={visibleSlides}
|
||||||
|
changeSlide={changeSlide}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Slider.propTypes = {
|
||||||
|
slides: PropTypes.arrayOf(PropTypes.node.isRequired),
|
||||||
|
breakpoints: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
/**
|
||||||
|
* Breakpoint name as defined in Tailwind config. If not defined, config
|
||||||
|
* will be applied to all non-configured screen sizes.
|
||||||
|
*/
|
||||||
|
name: PropTypes.string,
|
||||||
|
/**
|
||||||
|
* Number of slides visible for a given breakpoint.
|
||||||
|
*/
|
||||||
|
visibleSlides: PropTypes.number.isRequired,
|
||||||
|
/**
|
||||||
|
* Whether or not the list should be scrollable horizontally at the given breakpoint.
|
||||||
|
* If set to false, all slides will be visible & rendered in a column.
|
||||||
|
*/
|
||||||
|
scrollable: PropTypes.bool.isRequired,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
Slider.defaultProps = {
|
||||||
|
breakpoints: [
|
||||||
|
{
|
||||||
|
name: "xl",
|
||||||
|
scrollable: true,
|
||||||
|
visibleSlides: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "md",
|
||||||
|
scrollable: true,
|
||||||
|
visibleSlides: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// For the smallest screens, we won't scroll but instead stack the slides vertically.
|
||||||
|
scrollable: false,
|
||||||
|
visibleSlides: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Slider;
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./Slider";
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { useEffect, useMemo, useCallback, useState } from "react";
|
||||||
|
import { useWindowSize } from "react-use";
|
||||||
|
|
||||||
|
import theme from "../../lib/theme";
|
||||||
|
|
||||||
|
const { screens } = theme;
|
||||||
|
|
||||||
|
export default function useActiveBreakpoint(breakpoints) {
|
||||||
|
const { width: windowWidth } = useWindowSize();
|
||||||
|
const monitoredBreakpoints = useMemo(
|
||||||
|
() =>
|
||||||
|
breakpoints
|
||||||
|
.slice()
|
||||||
|
// Map breakpoint names to their min-width configured in Tailwind
|
||||||
|
.map(({ name, ...config }) => {
|
||||||
|
// If breakpoint name is not configured,
|
||||||
|
// we'll apply this config to all unmatched breakpoints.
|
||||||
|
const minWidth = screens[name] ? parseInt(screens[name], 10) : -Infinity;
|
||||||
|
|
||||||
|
return { minWidth, ...config };
|
||||||
|
})
|
||||||
|
// Since our breakpoints are setup with min-width rule, we need to sort them from largest to smallest
|
||||||
|
.sort(({ minWidth: widthA }, { minWidth: widthB }) => widthB - widthA),
|
||||||
|
[breakpoints]
|
||||||
|
);
|
||||||
|
const findActiveBreakpoint = useCallback(
|
||||||
|
() => monitoredBreakpoints.find((breakpoint) => windowWidth >= breakpoint.minWidth),
|
||||||
|
[monitoredBreakpoints, windowWidth]
|
||||||
|
);
|
||||||
|
|
||||||
|
const [activeBreakpoint, setActiveBreakpoint] = useState(findActiveBreakpoint());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setActiveBreakpoint(findActiveBreakpoint());
|
||||||
|
}, [findActiveBreakpoint]);
|
||||||
|
|
||||||
|
return activeBreakpoint;
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import styled from "styled-components";
|
||||||
* Accepts all HMTL attributes a `<td>` element does.
|
* Accepts all HMTL attributes a `<td>` element does.
|
||||||
*/
|
*/
|
||||||
export const TableCell = styled.td.attrs({
|
export const TableCell = styled.td.attrs({
|
||||||
className: `px-6 py-4 h-tableRow truncate
|
className: `first:pl-6 last:pr-6 px-2 py-4 h-tableRow truncate
|
||||||
text-palette-600 even:text-palette-400
|
text-palette-600 even:text-palette-400
|
||||||
first:rounded-l-sm last:rounded-r-sm`,
|
first:rounded-l-sm last:rounded-r-sm`,
|
||||||
})`
|
})`
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
import { useWindowSize } from "react-use";
|
||||||
|
|
||||||
const Wrapper = styled.div.attrs({
|
const Wrapper = styled.div.attrs({
|
||||||
className: "absolute left-0 bottom-0 w-full h-0.5 bg-palette-200",
|
className: "absolute left-0 bottom-0 w-full h-0.5 bg-palette-200",
|
||||||
|
@ -15,6 +16,7 @@ const Indicator = styled.div.attrs({
|
||||||
export const ActiveTabIndicator = ({ tabRef }) => {
|
export const ActiveTabIndicator = ({ tabRef }) => {
|
||||||
const [position, setPosition] = useState(0);
|
const [position, setPosition] = useState(0);
|
||||||
const [width, setWidth] = useState(0);
|
const [width, setWidth] = useState(0);
|
||||||
|
const { width: windowWidth } = useWindowSize();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!tabRef?.current) {
|
if (!tabRef?.current) {
|
||||||
|
@ -24,7 +26,7 @@ export const ActiveTabIndicator = ({ tabRef }) => {
|
||||||
const { offsetLeft, offsetWidth } = tabRef.current;
|
const { offsetLeft, offsetWidth } = tabRef.current;
|
||||||
setPosition(offsetLeft);
|
setPosition(offsetLeft);
|
||||||
setWidth(offsetWidth);
|
setWidth(offsetWidth);
|
||||||
}, [tabRef]);
|
}, [tabRef, windowWidth]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
|
@ -33,6 +35,9 @@ export const ActiveTabIndicator = ({ tabRef }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Needed, because we're using an Element constant here which Gatsby doesn't recognize during build time.
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
ActiveTabIndicator.propTypes = {
|
ActiveTabIndicator.propTypes = {
|
||||||
tabRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.instanceOf(Element) })]),
|
tabRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.instanceOf(Element) })]),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,50 +1,23 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Link } from "gatsby";
|
|
||||||
|
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { DropdownMenu, DropdownMenuLink } from "../components/DropdownMenu";
|
|
||||||
import { PageContainer } from "../components/PageContainer";
|
import { PageContainer } from "../components/PageContainer";
|
||||||
import { CogIcon, SkynetLogoIcon, LockClosedIcon } from "../components/Icons";
|
import { NavBar } from "../components/Navbar";
|
||||||
import { NavBar, NavBarLink, NavBarSection } from "../components/Navbar";
|
|
||||||
import { Footer } from "../components/Footer";
|
import { Footer } from "../components/Footer";
|
||||||
|
|
||||||
const Layout = styled.div.attrs({
|
const Layout = styled.div.attrs({
|
||||||
className: "h-screen overflow-hidden",
|
className: "min-h-screen overflow-hidden",
|
||||||
})`
|
})`
|
||||||
background-image: url(/images/dashboard-bg.svg);
|
background-image: url(/images/dashboard-bg.svg);
|
||||||
background-position: -300px -280px;
|
background-position: center -280px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
.navbar {
|
|
||||||
grid-template-columns: auto max-content 1fr;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const DashboardLayout = ({ children }) => {
|
const DashboardLayout = ({ children }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Layout>
|
<Layout>
|
||||||
<NavBar className="navbar">
|
<NavBar />
|
||||||
<NavBarSection className="w-[110px] justify-start">
|
|
||||||
<SkynetLogoIcon size={48} />
|
|
||||||
</NavBarSection>
|
|
||||||
<NavBarSection>
|
|
||||||
<NavBarLink to="/" as={Link} activeClassName="!border-b-primary">
|
|
||||||
Dashboard
|
|
||||||
</NavBarLink>
|
|
||||||
<NavBarLink to="/files" as={Link} activeClassName="!border-b-primary">
|
|
||||||
Files
|
|
||||||
</NavBarLink>
|
|
||||||
<NavBarLink to="/payments" as={Link} activeClassName="!border-b-primary">
|
|
||||||
Payments
|
|
||||||
</NavBarLink>
|
|
||||||
</NavBarSection>
|
|
||||||
<NavBarSection className="justify-end">
|
|
||||||
<DropdownMenu title="My account">
|
|
||||||
<DropdownMenuLink href="/settings" icon={CogIcon} label="Settings" />
|
|
||||||
<DropdownMenuLink href="/logout" icon={LockClosedIcon} label="Log out" />
|
|
||||||
</DropdownMenu>
|
|
||||||
</NavBarSection>
|
|
||||||
</NavBar>
|
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<main className="mt-14">{children}</main>
|
<main className="mt-14">{children}</main>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { css } from "styled-components";
|
||||||
|
import theme from "./theme";
|
||||||
|
|
||||||
|
export const screen = (breakpoint, style) => {
|
||||||
|
const { screens } = theme;
|
||||||
|
const minWidth = screens[breakpoint];
|
||||||
|
|
||||||
|
if (typeof minWidth === "undefined") {
|
||||||
|
throw ReferenceError(
|
||||||
|
`Screen "${breakpoint}" is not defined in Tailwind config. Available values are: ${Object.keys(screens).join(
|
||||||
|
", "
|
||||||
|
)}.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return css`
|
||||||
|
@media (min-width: ${minWidth}) {
|
||||||
|
${style}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
};
|
|
@ -0,0 +1,8 @@
|
||||||
|
// @preval
|
||||||
|
// This file is pre-evaluated on build-time, so the config is only resolved once
|
||||||
|
// and then included in the bundle for us to use in dynamic styles.
|
||||||
|
import resolveConfig from "tailwindcss/resolveConfig";
|
||||||
|
|
||||||
|
import tailwindConfig from "../../tailwind.config.js";
|
||||||
|
|
||||||
|
export default resolveConfig(tailwindConfig).theme;
|
|
@ -1,9 +1,67 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import { useMedia } from "react-use";
|
||||||
|
|
||||||
|
import theme from "../lib/theme";
|
||||||
|
import { ArrowRightIcon } from "../components/Icons";
|
||||||
|
import { Panel } from "../components/Panel";
|
||||||
|
import { Tab, TabPanel, Tabs } from "../components/Tabs";
|
||||||
|
import LatestActivity from "../components/LatestActivity/LatestActivity";
|
||||||
import DashboardLayout from "../layouts/DashboardLayout";
|
import DashboardLayout from "../layouts/DashboardLayout";
|
||||||
|
import Slider from "../components/Slider/Slider";
|
||||||
|
import CurrentUsage from "../components/CurrentUsage";
|
||||||
|
|
||||||
const IndexPage = () => {
|
const IndexPage = () => {
|
||||||
return <>Dashboard</>;
|
const showRecentActivity = useMedia(`(min-width: ${theme.screens.md})`);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="w-full">
|
||||||
|
<Slider
|
||||||
|
slides={[
|
||||||
|
<Panel title="Upload">
|
||||||
|
<Tabs variant="fill">
|
||||||
|
<Tab id="files" title="Files" />
|
||||||
|
<Tab id="directory" title="Directory" />
|
||||||
|
<TabPanel tabId="files">
|
||||||
|
<div className="w-full py-16 bg-palette-100/50 text-center">Upload files...</div>
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel tabId="directory">
|
||||||
|
<div className="w-full py-16 bg-palette-100/50 text-center">Upload a directory...</div>
|
||||||
|
</TabPanel>
|
||||||
|
</Tabs>
|
||||||
|
</Panel>,
|
||||||
|
<Panel
|
||||||
|
title={
|
||||||
|
<>
|
||||||
|
<ArrowRightIcon /> Usage
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<CurrentUsage />
|
||||||
|
</Panel>,
|
||||||
|
<Panel
|
||||||
|
title={
|
||||||
|
<>
|
||||||
|
<ArrowRightIcon /> Current plan
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ul>
|
||||||
|
<li>Current</li>
|
||||||
|
<li>Plan</li>
|
||||||
|
<li>Info</li>
|
||||||
|
</ul>
|
||||||
|
</Panel>,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{showRecentActivity && (
|
||||||
|
<div className="mt-10">
|
||||||
|
<LatestActivity />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
IndexPage.Layout = DashboardLayout;
|
IndexPage.Layout = DashboardLayout;
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 378 146" preserveAspectRatio="none">
|
||||||
|
<defs>
|
||||||
|
<pattern id="diagonalHatch" patternUnits="userSpaceOnUse" width="8" height="8">
|
||||||
|
<path d="M-2,2 l6,-6
|
||||||
|
M0,8 l8,-8
|
||||||
|
M7,10 l6,-6" stroke="#d4dddb" />
|
||||||
|
</pattern>
|
||||||
|
<style>.cls-1{fill:#f5f7f7;}.cls-2{fill:#d4dddb; opacity: 0.5;}.cls-3{fill:url(#diagonalHatch);}.cls-4{fill:#80e3af;}</style>
|
||||||
|
</defs>
|
||||||
|
<g id="Layer_2" data-name="Layer 2">
|
||||||
|
<g id="Layer_1-2" data-name="Layer 1">
|
||||||
|
<rect class="cls-1" width="2" height="146" rx="1"/>
|
||||||
|
<rect class="cls-1" x="4" width="4" height="146" rx="2"/>
|
||||||
|
<rect class="cls-1" x="10" width="6" height="146" rx="2"/>
|
||||||
|
<rect class="cls-1" x="18" width="8" height="146" rx="2"/>
|
||||||
|
<rect class="cls-1" x="28" width="10" height="146" rx="2"/>
|
||||||
|
<rect class="cls-1" x="40" width="12" height="146" rx="2"/>
|
||||||
|
<rect class="cls-1" x="54" width="14" height="146" rx="2"/>
|
||||||
|
<rect class="cls-1" x="70" width="16" height="146" rx="2"/>
|
||||||
|
<rect class="cls-1" x="88" width="18" height="146" rx="2"/>
|
||||||
|
<rect class="cls-1" x="108" width="20" height="146" rx="2"/>
|
||||||
|
<rect class="cls-1" x="130" width="22" height="146" rx="2"/>
|
||||||
|
<rect class="cls-1" x="154" width="24" height="146" rx="2"/>
|
||||||
|
<rect class="cls-1" x="180" width="26" height="146" rx="2"/>
|
||||||
|
<rect class="cls-1" x="208" width="28" height="146" rx="2"/>
|
||||||
|
<rect class="cls-2" x="238" width="30" height="146" rx="2"/>
|
||||||
|
<rect class="cls-2" x="270" width="32" height="146" rx="2"/>
|
||||||
|
<rect class="cls-2" x="304" width="34" height="146" rx="2"/>
|
||||||
|
<rect class="cls-3" x="340" width="38" height="146" rx="2"/>
|
||||||
|
<path class="cls-4" d="M304,144h34a0,0,0,0,1,0,0v0a2,2,0,0,1-2,2H306a2,2,0,0,1-2-2v0A0,0,0,0,1,304,144Z"/>
|
||||||
|
<path class="cls-4" d="M270,144h32a0,0,0,0,1,0,0v0a2,2,0,0,1-2,2H272a2,2,0,0,1-2-2v0A0,0,0,0,1,270,144Z"/>
|
||||||
|
<path class="cls-4" d="M238,144h30a0,0,0,0,1,0,0v0a2,2,0,0,1-2,2H240a2,2,0,0,1-2-2v0A0,0,0,0,1,238,144Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
|
@ -338,7 +338,7 @@
|
||||||
chalk "^2.0.0"
|
chalk "^2.0.0"
|
||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
|
|
||||||
"@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.14.7", "@babel/parser@^7.15.5", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.7.0":
|
"@babel/parser@^7.1.0", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.14.7", "@babel/parser@^7.15.5", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.7.0":
|
||||||
version "7.17.3"
|
version "7.17.3"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0"
|
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0"
|
||||||
integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==
|
integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==
|
||||||
|
@ -1139,7 +1139,7 @@
|
||||||
debug "^4.1.0"
|
debug "^4.1.0"
|
||||||
globals "^11.1.0"
|
globals "^11.1.0"
|
||||||
|
|
||||||
"@babel/types@^7.0.0-beta.49", "@babel/types@^7.12.11", "@babel/types@^7.12.7", "@babel/types@^7.15.4", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0":
|
"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.12.11", "@babel/types@^7.12.7", "@babel/types@^7.15.4", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0":
|
||||||
version "7.17.0"
|
version "7.17.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
|
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
|
||||||
integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==
|
integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==
|
||||||
|
@ -3156,6 +3156,39 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc"
|
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc"
|
||||||
integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==
|
integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==
|
||||||
|
|
||||||
|
"@types/babel__core@^7.1.12":
|
||||||
|
version "7.1.18"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8"
|
||||||
|
integrity sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.1.0"
|
||||||
|
"@babel/types" "^7.0.0"
|
||||||
|
"@types/babel__generator" "*"
|
||||||
|
"@types/babel__template" "*"
|
||||||
|
"@types/babel__traverse" "*"
|
||||||
|
|
||||||
|
"@types/babel__generator@*":
|
||||||
|
version "7.6.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7"
|
||||||
|
integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.0.0"
|
||||||
|
|
||||||
|
"@types/babel__template@*":
|
||||||
|
version "7.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969"
|
||||||
|
integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.1.0"
|
||||||
|
"@babel/types" "^7.0.0"
|
||||||
|
|
||||||
|
"@types/babel__traverse@*":
|
||||||
|
version "7.14.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43"
|
||||||
|
integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.3.0"
|
||||||
|
|
||||||
"@types/cacheable-request@^6.0.1":
|
"@types/cacheable-request@^6.0.1":
|
||||||
version "6.0.2"
|
version "6.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9"
|
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9"
|
||||||
|
@ -4679,6 +4712,16 @@ babel-plugin-polyfill-regenerator@^0.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-define-polyfill-provider" "^0.3.1"
|
"@babel/helper-define-polyfill-provider" "^0.3.1"
|
||||||
|
|
||||||
|
babel-plugin-preval@^5.1.0:
|
||||||
|
version "5.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/babel-plugin-preval/-/babel-plugin-preval-5.1.0.tgz#6efb89bf6b97af592cd1400c6df49c0e9e6ab027"
|
||||||
|
integrity sha512-G5R+xmo5LS41A4UyZjOjV0mp9AvkuCyUOAJ6TOv/jTZS+VKh7L7HUDRcCSOb0YCM/u0fFarh7Diz0wjY8rFNFg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.12.5"
|
||||||
|
"@types/babel__core" "^7.1.12"
|
||||||
|
babel-plugin-macros "^3.0.1"
|
||||||
|
require-from-string "^2.0.2"
|
||||||
|
|
||||||
babel-plugin-react-docgen@^4.2.1:
|
babel-plugin-react-docgen@^4.2.1:
|
||||||
version "4.2.1"
|
version "4.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz#7cc8e2f94e8dc057a06e953162f0810e4e72257b"
|
resolved "https://registry.yarnpkg.com/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz#7cc8e2f94e8dc057a06e953162f0810e4e72257b"
|
||||||
|
@ -8159,6 +8202,11 @@ gatsby-plugin-postcss@^5.7.0:
|
||||||
"@babel/runtime" "^7.15.4"
|
"@babel/runtime" "^7.15.4"
|
||||||
postcss-loader "^4.3.0"
|
postcss-loader "^4.3.0"
|
||||||
|
|
||||||
|
gatsby-plugin-preval@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/gatsby-plugin-preval/-/gatsby-plugin-preval-1.0.0.tgz#b0e9dcc9ef568cb6ca998f7211b5365824b97201"
|
||||||
|
integrity sha512-HpPp2bdA4nZsuD3R++GRhM9BPlFp8+ilkXIo53hNr14OlHXxrgimh9lqVVvP3q4JriHh+bYcvmfqm6msIsxxLg==
|
||||||
|
|
||||||
gatsby-plugin-provide-react@^1.0.2:
|
gatsby-plugin-provide-react@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/gatsby-plugin-provide-react/-/gatsby-plugin-provide-react-1.0.2.tgz#e50bb311cd8ef5855c6d94f708266ab117c77a15"
|
resolved "https://registry.yarnpkg.com/gatsby-plugin-provide-react/-/gatsby-plugin-provide-react-1.0.2.tgz#e50bb311cd8ef5855c6d94f708266ab117c77a15"
|
||||||
|
@ -8196,10 +8244,10 @@ gatsby-plugin-sharp@^4.6.0:
|
||||||
svgo "1.3.2"
|
svgo "1.3.2"
|
||||||
uuid "3.4.0"
|
uuid "3.4.0"
|
||||||
|
|
||||||
gatsby-plugin-styled-components@^5.7.0:
|
gatsby-plugin-styled-components@^5.8.0:
|
||||||
version "5.7.0"
|
version "5.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/gatsby-plugin-styled-components/-/gatsby-plugin-styled-components-5.7.0.tgz#8ba7b4ddb1722dcd0efd4fc6f1a8e62f47be012c"
|
resolved "https://registry.yarnpkg.com/gatsby-plugin-styled-components/-/gatsby-plugin-styled-components-5.8.0.tgz#5d8c81802ed9266435aa1145451bfb3ac582ad37"
|
||||||
integrity sha512-mX8N4nqIX0Ow/pUSORUb8WlKvgX7foCoWZ0AifyBOFnhBCbRWYTsXFWwiea6jCnST5V61b2TOFpjIHcvHvc9aQ==
|
integrity sha512-4ma9PgOr3U5TUX6uwAqFW+VX+fDxmt1y4oM3ArfZufaiQvZJ52cuf/uiyI+Tx1DJebcypEpR5dXYVl9ZX1bUHg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.15.4"
|
"@babel/runtime" "^7.15.4"
|
||||||
|
|
||||||
|
@ -12402,6 +12450,11 @@ pretty-bytes@^5.4.1:
|
||||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
|
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
|
||||||
integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
|
integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
|
||||||
|
|
||||||
|
pretty-bytes@^6.0.0:
|
||||||
|
version "6.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-6.0.0.tgz#928be2ad1f51a2e336add8ba764739f9776a8140"
|
||||||
|
integrity sha512-6UqkYefdogmzqAZWzJ7laYeJnaXDy2/J+ZqiiMtS7t7OfpXWTlaeGMwX8U6EFvPV/YWWEKRkS8hKS4k60WHTOg==
|
||||||
|
|
||||||
pretty-error@^2.1.1, pretty-error@^2.1.2:
|
pretty-error@^2.1.1, pretty-error@^2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6"
|
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6"
|
||||||
|
@ -14061,6 +14114,11 @@ store2@^2.12.0:
|
||||||
resolved "https://registry.yarnpkg.com/store2/-/store2-2.13.1.tgz#fae7b5bb9d35fc53dc61cd262df3abb2f6e59022"
|
resolved "https://registry.yarnpkg.com/store2/-/store2-2.13.1.tgz#fae7b5bb9d35fc53dc61cd262df3abb2f6e59022"
|
||||||
integrity sha512-iJtHSGmNgAUx0b/MCS6ASGxb//hGrHHRgzvN+K5bvkBTN7A9RTpPSf1WSp+nPGvWCJ1jRnvY7MKnuqfoi3OEqg==
|
integrity sha512-iJtHSGmNgAUx0b/MCS6ASGxb//hGrHHRgzvN+K5bvkBTN7A9RTpPSf1WSp+nPGvWCJ1jRnvY7MKnuqfoi3OEqg==
|
||||||
|
|
||||||
|
storybook-addon-gatsby@^0.0.5:
|
||||||
|
version "0.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/storybook-addon-gatsby/-/storybook-addon-gatsby-0.0.5.tgz#94f5b67bab8659d0248b65e60dabc3702818ce8b"
|
||||||
|
integrity sha512-18f8Kc6mx8mEFfqY2DgF9ayDfmM58+9IjJqIxGV4bA4r2EtB/Q1LDNELIJmpLLyA5NrSvECxCqzLu7jNBlWgmA==
|
||||||
|
|
||||||
stream-browserify@^2.0.1:
|
stream-browserify@^2.0.1:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
|
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
|
||||||
|
|
Reference in New Issue