diff --git a/packages/dashboard-v2/.storybook/main.js b/packages/dashboard-v2/.storybook/main.js
index 09e2ce48..8a1198a4 100644
--- a/packages/dashboard-v2/.storybook/main.js
+++ b/packages/dashboard-v2/.storybook/main.js
@@ -3,6 +3,7 @@ module.exports = {
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
+ "storybook-addon-gatsby",
{
name: "@storybook/addon-postcss",
options: {
diff --git a/packages/dashboard-v2/gatsby-config.js b/packages/dashboard-v2/gatsby-config.js
index b82a34b1..b742e91b 100644
--- a/packages/dashboard-v2/gatsby-config.js
+++ b/packages/dashboard-v2/gatsby-config.js
@@ -9,6 +9,7 @@ module.exports = {
"gatsby-plugin-react-helmet",
"gatsby-plugin-sharp",
"gatsby-transformer-sharp",
+ "gatsby-plugin-styled-components",
"gatsby-plugin-postcss",
{
resolve: "gatsby-source-filesystem",
diff --git a/packages/dashboard-v2/gatsby-ssr.js b/packages/dashboard-v2/gatsby-ssr.js
new file mode 100644
index 00000000..a71e49c3
--- /dev/null
+++ b/packages/dashboard-v2/gatsby-ssr.js
@@ -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 {element};
+}
diff --git a/packages/dashboard-v2/package.json b/packages/dashboard-v2/package.json
index c5bb6214..8d088e7c 100644
--- a/packages/dashboard-v2/package.json
+++ b/packages/dashboard-v2/package.json
@@ -24,6 +24,7 @@
"gatsby": "^4.6.2",
"gatsby-plugin-postcss": "^5.7.0",
"postcss": "^8.4.6",
+ "pretty-bytes": "^6.0.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-helmet": "^6.1.0",
@@ -44,20 +45,23 @@
"autoprefixer": "^10.4.2",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.3",
+ "babel-plugin-preval": "^5.1.0",
"babel-plugin-styled-components": "^2.0.2",
"eslint": "^8.9.0",
"eslint-config-react-app": "^7.0.0",
"eslint-plugin-storybook": "^0.5.6",
"gatsby-plugin-alias-imports": "^1.0.5",
"gatsby-plugin-image": "^2.6.0",
+ "gatsby-plugin-preval": "^1.0.0",
"gatsby-plugin-provide-react": "^1.0.2",
"gatsby-plugin-react-helmet": "^5.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-transformer-sharp": "^4.6.0",
"prettier": "2.5.1",
"react-is": "^17.0.2",
+ "storybook-addon-gatsby": "^0.0.5",
"styled-components": "^5.3.3"
}
}
diff --git a/packages/dashboard-v2/src/components/CurrentUsage/CurrentUsage.js b/packages/dashboard-v2/src/components/CurrentUsage/CurrentUsage.js
new file mode 100644
index 00000000..b467e1ea
--- /dev/null
+++ b/packages/dashboard-v2/src/components/CurrentUsage/CurrentUsage.js
@@ -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 (
+ <>
+
+ {storageUsage.text} of {storageLimit.text}
+
+
+ {files.used} of {files.limit} files
+
+
+
+ Storage
+ {storageLimit.text}
+
+
+
+
+
+
+ Files
+
+
+ UPGRADE
+ {" "}
+ {/* TODO: proper URL */}
+ {files.limit}
+
+
+
+ >
+ );
+}
diff --git a/packages/dashboard-v2/src/components/CurrentUsage/GraphBar.js b/packages/dashboard-v2/src/components/CurrentUsage/GraphBar.js
new file mode 100644
index 00000000..96421f6e
--- /dev/null
+++ b/packages/dashboard-v2/src/components/CurrentUsage/GraphBar.js
@@ -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 (
+
+
+
+
+
+ {label.value} {label.unit}
+
+
+ );
+};
diff --git a/packages/dashboard-v2/src/components/CurrentUsage/UsageGraph.js b/packages/dashboard-v2/src/components/CurrentUsage/UsageGraph.js
new file mode 100644
index 00000000..3f6f23c2
--- /dev/null
+++ b/packages/dashboard-v2/src/components/CurrentUsage/UsageGraph.js
@@ -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;
+`;
diff --git a/packages/dashboard-v2/src/components/CurrentUsage/index.js b/packages/dashboard-v2/src/components/CurrentUsage/index.js
new file mode 100644
index 00000000..802aa4e1
--- /dev/null
+++ b/packages/dashboard-v2/src/components/CurrentUsage/index.js
@@ -0,0 +1,3 @@
+import CurrentUsage from "./CurrentUsage";
+
+export default CurrentUsage;
diff --git a/packages/dashboard-v2/src/components/LatestActivity/ActivityTable.js b/packages/dashboard-v2/src/components/LatestActivity/ActivityTable.js
new file mode 100644
index 00000000..095ad728
--- /dev/null
+++ b/packages/dashboard-v2/src/components/LatestActivity/ActivityTable.js
@@ -0,0 +1,22 @@
+import * as React from "react";
+import { Table, TableBody, TableCell, TableRow } from "../Table";
+
+export default function ActivityTable({ data }) {
+ return (
+
+
+ {data.map(({ name, type, size, uploaded, skylink }) => (
+
+ {name}
+ {type}
+
+ {size}
+
+ {uploaded}
+ {skylink}
+
+ ))}
+
+
+ );
+}
diff --git a/packages/dashboard-v2/src/components/LatestActivity/LatestActivity.js b/packages/dashboard-v2/src/components/LatestActivity/LatestActivity.js
new file mode 100644
index 00000000..7e7fdf6c
--- /dev/null
+++ b/packages/dashboard-v2/src/components/LatestActivity/LatestActivity.js
@@ -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 (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/dashboard-v2/src/components/LatestActivity/index.js b/packages/dashboard-v2/src/components/LatestActivity/index.js
new file mode 100644
index 00000000..32a02f82
--- /dev/null
+++ b/packages/dashboard-v2/src/components/LatestActivity/index.js
@@ -0,0 +1,3 @@
+import LatestActivity from "./LatestActivity";
+
+export default LatestActivity;
diff --git a/packages/dashboard-v2/src/components/LatestActivity/useActivityData.js b/packages/dashboard-v2/src/components/LatestActivity/useActivityData.js
new file mode 100644
index 00000000..a262816e
--- /dev/null
+++ b/packages/dashboard-v2/src/components/LatestActivity/useActivityData.js
@@ -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,
+ };
+}
diff --git a/packages/dashboard-v2/src/components/NavBar/NavBar.js b/packages/dashboard-v2/src/components/NavBar/NavBar.js
index 257b8a0d..2b53f2be 100644
--- a/packages/dashboard-v2/src/components/NavBar/NavBar.js
+++ b/packages/dashboard-v2/src/components/NavBar/NavBar.js
@@ -1,21 +1,78 @@
+import { Link } from "gatsby";
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 { NavBarLink, NavBarSection } from ".";
+
const NavBarContainer = styled.div.attrs({
className: `grid sticky top-0 bg-white`,
})``;
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",
})`
- grid-template-columns: auto max-content 1fr;
+ 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-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 = () => (
-
-
+
+
+
+
+
+
+
+ Dashboard
+
+
+ Files
+
+
+ Payments
+
+
+
+
+
+
+
+
+
);
diff --git a/packages/dashboard-v2/src/components/NavBar/NavBar.stories.js b/packages/dashboard-v2/src/components/NavBar/NavBar.stories.js
index e1022faa..0dc7c925 100644
--- a/packages/dashboard-v2/src/components/NavBar/NavBar.stories.js
+++ b/packages/dashboard-v2/src/components/NavBar/NavBar.stories.js
@@ -9,17 +9,7 @@ export default {
},
};
-const Template = (props) => (
-
-
-
- Dashboard
-
- Files
- Payments
-
-
-);
+const Template = (props) => ;
export const DashboardTopNavigation = Template.bind({});
DashboardTopNavigation.args = {};
diff --git a/packages/dashboard-v2/src/components/NavBar/NavBarLink.js b/packages/dashboard-v2/src/components/NavBar/NavBarLink.js
index 772933c0..3c85dcda 100644
--- a/packages/dashboard-v2/src/components/NavBar/NavBarLink.js
+++ b/packages/dashboard-v2/src/components/NavBar/NavBarLink.js
@@ -3,7 +3,7 @@ import styled from "styled-components";
export const NavBarLink = styled.a.attrs(({ active }) => ({
className: `
- min-w-[168px]
+ sm:min-w-[133px] lg:min-w-[168px]
flex h-full items-center justify-center
border-x border-x-palette-100 border-b-2
text-palette-600 transition-colors hover:bg-palette-100/50
diff --git a/packages/dashboard-v2/src/components/PageContainer/PageContainer.js b/packages/dashboard-v2/src/components/PageContainer/PageContainer.js
index 9c95b59c..2fa037a8 100644
--- a/packages/dashboard-v2/src/components/PageContainer/PageContainer.js
+++ b/packages/dashboard-v2/src/components/PageContainer/PageContainer.js
@@ -2,7 +2,7 @@ import PropTypes from "prop-types";
import styled from "styled-components";
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 = {
diff --git a/packages/dashboard-v2/src/components/Panel/Panel.js b/packages/dashboard-v2/src/components/Panel/Panel.js
index ea79b4d1..27551ecd 100644
--- a/packages/dashboard-v2/src/components/Panel/Panel.js
+++ b/packages/dashboard-v2/src/components/Panel/Panel.js
@@ -25,7 +25,7 @@ Panel.propTypes = {
/**
* Label of the panel
*/
- title: PropTypes.string,
+ title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
};
Panel.defaultProps = {
diff --git a/packages/dashboard-v2/src/components/Slider/Bullets.js b/packages/dashboard-v2/src/components/Slider/Bullets.js
new file mode 100644
index 00000000..b43c66b5
--- /dev/null
+++ b/packages/dashboard-v2/src/components/Slider/Bullets.js
@@ -0,0 +1,29 @@
+import PropTypes from "prop-types";
+
+export default function Bullets({ visibleSlides, activeIndex, allSlides, changeSlide }) {
+ if (allSlides <= visibleSlides) {
+ return null;
+ }
+
+ return (
+
+ {Array(allSlides - visibleSlides + 1)
+ .fill(null)
+ .map((_, index) => (
+
+ );
+}
+
+Bullets.propTypes = {
+ allSlides: PropTypes.number.isRequired,
+ activeIndex: PropTypes.number.isRequired,
+ visibleSlides: PropTypes.number.isRequired,
+ changeSlide: PropTypes.func.isRequired,
+};
diff --git a/packages/dashboard-v2/src/components/Slider/Slide.js b/packages/dashboard-v2/src/components/Slider/Slide.js
new file mode 100644
index 00000000..4f700502
--- /dev/null
+++ b/packages/dashboard-v2/src/components/Slider/Slide.js
@@ -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;
diff --git a/packages/dashboard-v2/src/components/Slider/Slider.js b/packages/dashboard-v2/src/components/Slider/Slider.js
new file mode 100644
index 00000000..1a04485d
--- /dev/null
+++ b/packages/dashboard-v2/src/components/Slider/Slider.js
@@ -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 (
+
+
+ {slides.map((slide, index) => {
+ const isVisible = index >= activeIndex && index < activeIndex + visibleSlides;
+
+ return (
+
+ changeSlide(index) : null}
+ >
+ {slide}
+
+
+ );
+ })}
+
+ {scrollable && (
+
+ )}
+
+ );
+};
+
+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;
diff --git a/packages/dashboard-v2/src/components/Slider/index.js b/packages/dashboard-v2/src/components/Slider/index.js
new file mode 100644
index 00000000..a5890919
--- /dev/null
+++ b/packages/dashboard-v2/src/components/Slider/index.js
@@ -0,0 +1 @@
+export * from "./Slider";
diff --git a/packages/dashboard-v2/src/components/Slider/useActiveBreakpoint.js b/packages/dashboard-v2/src/components/Slider/useActiveBreakpoint.js
new file mode 100644
index 00000000..4b891ba7
--- /dev/null
+++ b/packages/dashboard-v2/src/components/Slider/useActiveBreakpoint.js
@@ -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;
+}
diff --git a/packages/dashboard-v2/src/components/Table/TableCell.js b/packages/dashboard-v2/src/components/Table/TableCell.js
index 98f2bd3d..12a45a72 100644
--- a/packages/dashboard-v2/src/components/Table/TableCell.js
+++ b/packages/dashboard-v2/src/components/Table/TableCell.js
@@ -4,7 +4,7 @@ import styled from "styled-components";
* Accepts all HMTL attributes a `` element does.
*/
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
first:rounded-l-sm last:rounded-r-sm`,
})`
diff --git a/packages/dashboard-v2/src/components/Tabs/ActiveTabIndicator.js b/packages/dashboard-v2/src/components/Tabs/ActiveTabIndicator.js
index f6f89266..e39a5f08 100644
--- a/packages/dashboard-v2/src/components/Tabs/ActiveTabIndicator.js
+++ b/packages/dashboard-v2/src/components/Tabs/ActiveTabIndicator.js
@@ -1,6 +1,7 @@
import { useEffect, useState } from "react";
import PropTypes from "prop-types";
import styled from "styled-components";
+import { useWindowSize } from "react-use";
const Wrapper = styled.div.attrs({
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 }) => {
const [position, setPosition] = useState(0);
const [width, setWidth] = useState(0);
+ const { width: windowWidth } = useWindowSize();
useEffect(() => {
if (!tabRef?.current) {
@@ -24,7 +26,7 @@ export const ActiveTabIndicator = ({ tabRef }) => {
const { offsetLeft, offsetWidth } = tabRef.current;
setPosition(offsetLeft);
setWidth(offsetWidth);
- }, [tabRef]);
+ }, [tabRef, windowWidth]);
return (
@@ -33,6 +35,9 @@ export const ActiveTabIndicator = ({ tabRef }) => {
);
};
-ActiveTabIndicator.propTypes = {
- tabRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.instanceOf(Element) })]),
-};
+// Needed, because we're using an Element constant here which Gatsby doesn't recognize during build time.
+if (typeof window !== "undefined") {
+ ActiveTabIndicator.propTypes = {
+ tabRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.instanceOf(Element) })]),
+ };
+}
diff --git a/packages/dashboard-v2/src/layouts/DashboardLayout.js b/packages/dashboard-v2/src/layouts/DashboardLayout.js
index 61d57870..bfd23c42 100644
--- a/packages/dashboard-v2/src/layouts/DashboardLayout.js
+++ b/packages/dashboard-v2/src/layouts/DashboardLayout.js
@@ -1,50 +1,23 @@
import * as React from "react";
-import { Link } from "gatsby";
-
import styled from "styled-components";
-import { DropdownMenu, DropdownMenuLink } from "../components/DropdownMenu";
+
import { PageContainer } from "../components/PageContainer";
-import { CogIcon, SkynetLogoIcon, LockClosedIcon } from "../components/Icons";
-import { NavBar, NavBarLink, NavBarSection } from "../components/Navbar";
+import { NavBar } from "../components/Navbar";
import { Footer } from "../components/Footer";
const Layout = styled.div.attrs({
- className: "h-screen overflow-hidden",
+ className: "min-h-screen overflow-hidden",
})`
background-image: url(/images/dashboard-bg.svg);
- background-position: -300px -280px;
-
- .navbar {
- grid-template-columns: auto max-content 1fr;
- }
+ background-position: center -280px;
+ background-repeat: no-repeat;
`;
const DashboardLayout = ({ children }) => {
return (
<>
-
-
-
-
-
-
- Dashboard
-
-
- Files
-
-
- Payments
-
-
-
-
-
-
-
-
-
+
{children}
diff --git a/packages/dashboard-v2/src/lib/cssHelpers.js b/packages/dashboard-v2/src/lib/cssHelpers.js
new file mode 100644
index 00000000..b47aac00
--- /dev/null
+++ b/packages/dashboard-v2/src/lib/cssHelpers.js
@@ -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}
+ }
+ `;
+};
diff --git a/packages/dashboard-v2/src/lib/theme.js b/packages/dashboard-v2/src/lib/theme.js
new file mode 100644
index 00000000..1df7f9f5
--- /dev/null
+++ b/packages/dashboard-v2/src/lib/theme.js
@@ -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;
diff --git a/packages/dashboard-v2/src/pages/index.js b/packages/dashboard-v2/src/pages/index.js
index 9bf765cb..a8d48ae2 100644
--- a/packages/dashboard-v2/src/pages/index.js
+++ b/packages/dashboard-v2/src/pages/index.js
@@ -1,9 +1,67 @@
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 Slider from "../components/Slider/Slider";
+import CurrentUsage from "../components/CurrentUsage";
const IndexPage = () => {
- return <>Dashboard>;
+ const showRecentActivity = useMedia(`(min-width: ${theme.screens.md})`);
+
+ return (
+ <>
+
+
+
+
+
+
+ Upload files...
+
+
+ Upload a directory...
+
+
+ ,
+
+ Usage
+ >
+ }
+ >
+
+ ,
+
+ Current plan
+ >
+ }
+ >
+
+ - Current
+ - Plan
+ - Info
+
+ ,
+ ]}
+ />
+
+ {showRecentActivity && (
+
+
+
+ )}
+ >
+ );
};
IndexPage.Layout = DashboardLayout;
diff --git a/packages/dashboard-v2/static/images/usage-graph-bg.svg b/packages/dashboard-v2/static/images/usage-graph-bg.svg
new file mode 100644
index 00000000..be055905
--- /dev/null
+++ b/packages/dashboard-v2/static/images/usage-graph-bg.svg
@@ -0,0 +1,35 @@
+
diff --git a/packages/dashboard-v2/yarn.lock b/packages/dashboard-v2/yarn.lock
index 8ec21531..03554f2e 100644
--- a/packages/dashboard-v2/yarn.lock
+++ b/packages/dashboard-v2/yarn.lock
@@ -338,7 +338,7 @@
chalk "^2.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"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0"
integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==
@@ -1139,7 +1139,7 @@
debug "^4.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"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==
@@ -3156,6 +3156,39 @@
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc"
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":
version "6.0.2"
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:
"@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:
version "4.2.1"
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"
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:
version "1.0.2"
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"
uuid "3.4.0"
-gatsby-plugin-styled-components@^5.7.0:
- version "5.7.0"
- resolved "https://registry.yarnpkg.com/gatsby-plugin-styled-components/-/gatsby-plugin-styled-components-5.7.0.tgz#8ba7b4ddb1722dcd0efd4fc6f1a8e62f47be012c"
- integrity sha512-mX8N4nqIX0Ow/pUSORUb8WlKvgX7foCoWZ0AifyBOFnhBCbRWYTsXFWwiea6jCnST5V61b2TOFpjIHcvHvc9aQ==
+gatsby-plugin-styled-components@^5.8.0:
+ version "5.8.0"
+ resolved "https://registry.yarnpkg.com/gatsby-plugin-styled-components/-/gatsby-plugin-styled-components-5.8.0.tgz#5d8c81802ed9266435aa1145451bfb3ac582ad37"
+ integrity sha512-4ma9PgOr3U5TUX6uwAqFW+VX+fDxmt1y4oM3ArfZufaiQvZJ52cuf/uiyI+Tx1DJebcypEpR5dXYVl9ZX1bUHg==
dependencies:
"@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"
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:
version "2.1.2"
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"
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:
version "2.0.2"
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
|