From 59e27e9ae9289eca30f7b1f57cca6efb369acaca Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 10 Feb 2022 04:30:13 +0000 Subject: [PATCH 1/3] Replace Create Project buttons with CLI call to action --- site/components/Button/CopyButton.tsx | 72 +++++++++++++++++++++++++++ site/components/Button/index.ts | 1 + site/components/Icons/FileCopy.tsx | 11 ++++ site/components/Icons/index.ts | 1 + site/pages/projects/index.tsx | 26 ++++------ 5 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 site/components/Button/CopyButton.tsx create mode 100644 site/components/Icons/FileCopy.tsx diff --git a/site/components/Button/CopyButton.tsx b/site/components/Button/CopyButton.tsx new file mode 100644 index 0000000000000..a8a28e9e2c8f0 --- /dev/null +++ b/site/components/Button/CopyButton.tsx @@ -0,0 +1,72 @@ +import { makeStyles } from "@material-ui/core/styles" +import Button from "@material-ui/core/Button" +import Tooltip from "@material-ui/core/Tooltip" +import React from "react" +import { FileCopy } from "../Icons" + +interface CopyButtonProps { + text: string + className?: string + onFailure: () => void + onSuccess: () => void +} + +/** + * Copy button used inside the CodeBlock component internally + */ +export const CopyButton: React.FC = ({ className = "", text, onSuccess, onFailure }) => { + const styles = useStyles() + + + const copyToClipboard = async (): Promise => { + try { + await window.navigator.clipboard.writeText(text) + onSuccess() + } catch (err) { + const wrappedErr = new Error("copyToClipboard: failed to copy text to clipboard") + if (err instanceof Error) { + wrappedErr.stack = err.stack + } + console.error(wrappedErr) + + onFailure() + } + } + + return ( + +
+ +
+
+ ) +} + +const useStyles = makeStyles((theme) => ({ + copyButtonWrapper: { + display: "flex", + marginLeft: theme.spacing(1), + }, + copyButton: { + borderRadius: 7, + background: theme.palette.codeBlock.button.main, + color: theme.palette.codeBlock.button.contrastText, + padding: theme.spacing(0.85), + minWidth: 32, + + "&:hover": { + background: theme.palette.codeBlock.button.hover, + }, + }, + fileCopyIcon: { + width: 20, + height: 20, + }, +})) + diff --git a/site/components/Button/index.ts b/site/components/Button/index.ts index 318c0c373932d..a0845e5d310f1 100644 --- a/site/components/Button/index.ts +++ b/site/components/Button/index.ts @@ -1,2 +1,3 @@ export * from "./SplitButton" export * from "./LoadingButton" +export * from "./CopyButton" diff --git a/site/components/Icons/FileCopy.tsx b/site/components/Icons/FileCopy.tsx new file mode 100644 index 0000000000000..5f06bdbfaf368 --- /dev/null +++ b/site/components/Icons/FileCopy.tsx @@ -0,0 +1,11 @@ +import SvgIcon from "@material-ui/core/SvgIcon" +import React from "react" + +export const FileCopy: typeof SvgIcon = (props) => ( + + + +) \ No newline at end of file diff --git a/site/components/Icons/index.ts b/site/components/Icons/index.ts index 17f48ebaa4a98..bb6950f2f1da9 100644 --- a/site/components/Icons/index.ts +++ b/site/components/Icons/index.ts @@ -1,4 +1,5 @@ export { CoderIcon } from "./CoderIcon" +export * from "./FileCopy" export { Logo } from "./Logo" export * from "./Logout" export { WorkspacesIcon } from "./WorkspacesIcon" diff --git a/site/pages/projects/index.tsx b/site/pages/projects/index.tsx index bf67deb52502b..eccdb914f0cf1 100644 --- a/site/pages/projects/index.tsx +++ b/site/pages/projects/index.tsx @@ -14,6 +14,7 @@ import { FullScreenLoader } from "../../components/Loader/FullScreenLoader" import { Organization, Project } from "./../../api" import useSWR from "swr" +import { CodeBlock } from "../../components/CodeBlock" const ProjectsPage: React.FC = () => { const styles = useStyles() @@ -38,11 +39,6 @@ const ProjectsPage: React.FC = () => { void router.push("/projects/create") } - const action = { - text: "Create Project", - onClick: createProject, - } - // Create a dictionary of organization ID -> organization Name // Needed to properly construct links to dive into a project const orgDictionary = orgs.reduce((acc: Record, curr: Organization) => { @@ -62,16 +58,14 @@ const ProjectsPage: React.FC = () => { }, ] - const emptyState = ( - - ) + const description =
+
Run the following command to get started:
+ +
+ + const emptyState = const tableProps = { title: "All Projects", @@ -85,7 +79,7 @@ const ProjectsPage: React.FC = () => { return (
-
+
From 9b84598f23180a328110498e89c64ec361991ef1 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Fri, 11 Feb 2022 03:30:36 +0000 Subject: [PATCH 2/3] Add CodeExample component --- site/components/Button/CopyButton.tsx | 7 +--- site/components/CodeBlock/index.stories.tsx | 2 +- site/components/CodeBlock/index.tsx | 3 +- site/components/CodeExample/index.stories.tsx | 20 +++++++++++ site/components/CodeExample/index.test.tsx | 15 ++++++++ site/components/CodeExample/index.tsx | 34 +++++++++++++++++++ site/pages/projects/index.tsx | 4 +-- site/theme/palettes.ts | 23 +++++++++++++ 8 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 site/components/CodeExample/index.stories.tsx create mode 100644 site/components/CodeExample/index.test.tsx create mode 100644 site/components/CodeExample/index.tsx diff --git a/site/components/Button/CopyButton.tsx b/site/components/Button/CopyButton.tsx index a8a28e9e2c8f0..993e8976ac4db 100644 --- a/site/components/Button/CopyButton.tsx +++ b/site/components/Button/CopyButton.tsx @@ -7,29 +7,24 @@ import { FileCopy } from "../Icons" interface CopyButtonProps { text: string className?: string - onFailure: () => void - onSuccess: () => void } /** * Copy button used inside the CodeBlock component internally */ -export const CopyButton: React.FC = ({ className = "", text, onSuccess, onFailure }) => { +export const CopyButton: React.FC = ({ className = "", text }) => { const styles = useStyles() const copyToClipboard = async (): Promise => { try { await window.navigator.clipboard.writeText(text) - onSuccess() } catch (err) { const wrappedErr = new Error("copyToClipboard: failed to copy text to clipboard") if (err instanceof Error) { wrappedErr.stack = err.stack } console.error(wrappedErr) - - onFailure() } } diff --git a/site/components/CodeBlock/index.stories.tsx b/site/components/CodeBlock/index.stories.tsx index b31d450e21246..86e14ffca2856 100644 --- a/site/components/CodeBlock/index.stories.tsx +++ b/site/components/CodeBlock/index.stories.tsx @@ -12,7 +12,7 @@ export default { title: "CodeBlock", component: CodeBlock, argTypes: { - lines: { control: "object", defaultValue: sampleLines }, + lines: { control: "text", defaultValue: sampleLines }, }, } diff --git a/site/components/CodeBlock/index.tsx b/site/components/CodeBlock/index.tsx index 6b8b1afd336a1..e32468f705afc 100644 --- a/site/components/CodeBlock/index.tsx +++ b/site/components/CodeBlock/index.tsx @@ -1,5 +1,6 @@ import { makeStyles } from "@material-ui/core/styles" import React from "react" +import { MONOSPACE_FONT_FAMILY } from "../../theme/constants" export interface CodeBlockProps { lines: string[] @@ -18,8 +19,6 @@ export const CodeBlock: React.FC = ({ lines }) => { ) } -const MONOSPACE_FONT_FAMILY = - "'Fira Code', 'Lucida Console', 'Lucida Sans Typewriter', 'Liberation Mono', 'Monaco', 'Courier New', Courier, monospace" const useStyles = makeStyles((theme) => ({ root: { diff --git a/site/components/CodeExample/index.stories.tsx b/site/components/CodeExample/index.stories.tsx new file mode 100644 index 0000000000000..d3fc86b324066 --- /dev/null +++ b/site/components/CodeExample/index.stories.tsx @@ -0,0 +1,20 @@ +import { Story } from "@storybook/react" +import React from "react" +import { CodeExample, CodeExampleProps } from "./index" + +const sampleCode = `echo "Hello, world"` + +export default { + title: "CodeExample", + component: CodeExample, + argTypes: { + code: { control: "string", defaultValue: sampleCode }, + }, +} + +const Template: Story = (args: CodeExampleProps) => + +export const Example = Template.bind({}) +Example.args = { + code: sampleCode, +} diff --git a/site/components/CodeExample/index.test.tsx b/site/components/CodeExample/index.test.tsx new file mode 100644 index 0000000000000..4a4af3af8d5e5 --- /dev/null +++ b/site/components/CodeExample/index.test.tsx @@ -0,0 +1,15 @@ +import { screen } from "@testing-library/react" +import { render } from "../../test_helpers" +import React from "react" +import { CodeExample } from "./index" + +describe("CodeExample", () => { + it("renders code", async () => { + // When + render() + + // Then + // Both lines should be rendered + await screen.findByText("echo hello") + }) +}) diff --git a/site/components/CodeExample/index.tsx b/site/components/CodeExample/index.tsx new file mode 100644 index 0000000000000..9baf0b7e349d3 --- /dev/null +++ b/site/components/CodeExample/index.tsx @@ -0,0 +1,34 @@ +import { makeStyles } from "@material-ui/core/styles" +import React from "react" +import { MONOSPACE_FONT_FAMILY } from "../../theme/constants" + +import { CopyButton } from "./../Button" + +export interface CodeExampleProps { + code: string +} + +export const CodeExample: React.FC = ({ code }) => { + const styles = useStyles() + + return ( +
+ {code} + +
+ ) +} + +const useStyles = makeStyles((theme) => ({ + root: { + display: "flex", + flexDirection: "row", + justifyContent: "flex-start", + background: theme.palette.background.default, + color: theme.palette.codeBlock.contrastText, + fontFamily: MONOSPACE_FONT_FAMILY, + fontSize: 13, + padding: theme.spacing(2), + borderRadius: theme.shape.borderRadius, + }, +})) diff --git a/site/pages/projects/index.tsx b/site/pages/projects/index.tsx index eccdb914f0cf1..c80acfc848656 100644 --- a/site/pages/projects/index.tsx +++ b/site/pages/projects/index.tsx @@ -14,7 +14,7 @@ import { FullScreenLoader } from "../../components/Loader/FullScreenLoader" import { Organization, Project } from "./../../api" import useSWR from "swr" -import { CodeBlock } from "../../components/CodeBlock" +import { CodeExample } from "../../components/CodeExample" const ProjectsPage: React.FC = () => { const styles = useStyles() @@ -60,7 +60,7 @@ const ProjectsPage: React.FC = () => { const description =
Run the following command to get started:
- +
const emptyState = Date: Fri, 11 Feb 2022 03:45:04 +0000 Subject: [PATCH 3/3] Fix up --- site/.eslintrc.yaml | 2 -- site/components/Button/CopyButton.tsx | 19 ++++++------- ...ex.stories.tsx => CodeExample.stories.tsx} | 2 +- .../{index.test.tsx => CodeExample.test.tsx} | 2 +- .../{index.tsx => CodeExample.tsx} | 8 ++++-- site/components/CodeExample/index.ts | 1 + site/components/Icons/FileCopy.tsx | 2 +- site/pages/projects/index.tsx | 27 +++++++++---------- 8 files changed, 32 insertions(+), 31 deletions(-) rename site/components/CodeExample/{index.stories.tsx => CodeExample.stories.tsx} (87%) rename site/components/CodeExample/{index.test.tsx => CodeExample.test.tsx} (88%) rename site/components/CodeExample/{index.tsx => CodeExample.tsx} (81%) create mode 100644 site/components/CodeExample/index.ts diff --git a/site/.eslintrc.yaml b/site/.eslintrc.yaml index 5f8386529919a..d6c6be9eb6b95 100644 --- a/site/.eslintrc.yaml +++ b/site/.eslintrc.yaml @@ -92,8 +92,6 @@ rules: message: "Use path imports to avoid pulling in unused modules. See: https://material-ui.com/guides/minimizing-bundle-size/" - - name: "@material-ui/core/Tooltip" - message: "Use the custom Tooltip on componens/Tooltip" no-storage/no-browser-storage: error no-unused-vars: "off" "object-curly-spacing": "off" diff --git a/site/components/Button/CopyButton.tsx b/site/components/Button/CopyButton.tsx index 993e8976ac4db..b10a6088da285 100644 --- a/site/components/Button/CopyButton.tsx +++ b/site/components/Button/CopyButton.tsx @@ -1,7 +1,8 @@ import { makeStyles } from "@material-ui/core/styles" import Button from "@material-ui/core/Button" import Tooltip from "@material-ui/core/Tooltip" -import React from "react" +import Check from "@material-ui/icons/Check" +import React, { useState } from "react" import { FileCopy } from "../Icons" interface CopyButtonProps { @@ -14,11 +15,16 @@ interface CopyButtonProps { */ export const CopyButton: React.FC = ({ className = "", text }) => { const styles = useStyles() - + const [isCopied, setIsCopied] = useState(false) const copyToClipboard = async (): Promise => { try { await window.navigator.clipboard.writeText(text) + setIsCopied(true) + + window.setTimeout(() => { + setIsCopied(false) + }, 1000) } catch (err) { const wrappedErr = new Error("copyToClipboard: failed to copy text to clipboard") if (err instanceof Error) { @@ -31,12 +37,8 @@ export const CopyButton: React.FC = ({ className = "", text }) return (
-
@@ -64,4 +66,3 @@ const useStyles = makeStyles((theme) => ({ height: 20, }, })) - diff --git a/site/components/CodeExample/index.stories.tsx b/site/components/CodeExample/CodeExample.stories.tsx similarity index 87% rename from site/components/CodeExample/index.stories.tsx rename to site/components/CodeExample/CodeExample.stories.tsx index d3fc86b324066..4eafb626a83d2 100644 --- a/site/components/CodeExample/index.stories.tsx +++ b/site/components/CodeExample/CodeExample.stories.tsx @@ -1,6 +1,6 @@ import { Story } from "@storybook/react" import React from "react" -import { CodeExample, CodeExampleProps } from "./index" +import { CodeExample, CodeExampleProps } from "./CodeExample" const sampleCode = `echo "Hello, world"` diff --git a/site/components/CodeExample/index.test.tsx b/site/components/CodeExample/CodeExample.test.tsx similarity index 88% rename from site/components/CodeExample/index.test.tsx rename to site/components/CodeExample/CodeExample.test.tsx index 4a4af3af8d5e5..7618f29d38f34 100644 --- a/site/components/CodeExample/index.test.tsx +++ b/site/components/CodeExample/CodeExample.test.tsx @@ -1,7 +1,7 @@ import { screen } from "@testing-library/react" import { render } from "../../test_helpers" import React from "react" -import { CodeExample } from "./index" +import { CodeExample } from "./CodeExample" describe("CodeExample", () => { it("renders code", async () => { diff --git a/site/components/CodeExample/index.tsx b/site/components/CodeExample/CodeExample.tsx similarity index 81% rename from site/components/CodeExample/index.tsx rename to site/components/CodeExample/CodeExample.tsx index 9baf0b7e349d3..c3145af8f349b 100644 --- a/site/components/CodeExample/index.tsx +++ b/site/components/CodeExample/CodeExample.tsx @@ -2,12 +2,15 @@ import { makeStyles } from "@material-ui/core/styles" import React from "react" import { MONOSPACE_FONT_FAMILY } from "../../theme/constants" -import { CopyButton } from "./../Button" +import { CopyButton } from "../Button" export interface CodeExampleProps { code: string } +/** + * Component to show single-line code examples, with a copy button + */ export const CodeExample: React.FC = ({ code }) => { const styles = useStyles() @@ -23,7 +26,8 @@ const useStyles = makeStyles((theme) => ({ root: { display: "flex", flexDirection: "row", - justifyContent: "flex-start", + justifyContent: "space-between", + alignItems: "center", background: theme.palette.background.default, color: theme.palette.codeBlock.contrastText, fontFamily: MONOSPACE_FONT_FAMILY, diff --git a/site/components/CodeExample/index.ts b/site/components/CodeExample/index.ts new file mode 100644 index 0000000000000..a2c38996d0f11 --- /dev/null +++ b/site/components/CodeExample/index.ts @@ -0,0 +1 @@ +export * from "./CodeExample" diff --git a/site/components/Icons/FileCopy.tsx b/site/components/Icons/FileCopy.tsx index 5f06bdbfaf368..d8f33f101ef5f 100644 --- a/site/components/Icons/FileCopy.tsx +++ b/site/components/Icons/FileCopy.tsx @@ -8,4 +8,4 @@ export const FileCopy: typeof SvgIcon = (props) => ( fill="currentColor" /> -) \ No newline at end of file +) diff --git a/site/pages/projects/index.tsx b/site/pages/projects/index.tsx index c80acfc848656..105216e069d39 100644 --- a/site/pages/projects/index.tsx +++ b/site/pages/projects/index.tsx @@ -1,7 +1,6 @@ import React from "react" import { makeStyles } from "@material-ui/core/styles" import Paper from "@material-ui/core/Paper" -import { useRouter } from "next/router" import Link from "next/link" import { EmptyState } from "../../components" import { ErrorSummary } from "../../components/ErrorSummary" @@ -14,11 +13,10 @@ import { FullScreenLoader } from "../../components/Loader/FullScreenLoader" import { Organization, Project } from "./../../api" import useSWR from "swr" -import { CodeExample } from "../../components/CodeExample" +import { CodeExample } from "../../components/CodeExample/CodeExample" const ProjectsPage: React.FC = () => { const styles = useStyles() - const router = useRouter() const { me, signOut } = useUser(true) const { data: projects, error } = useSWR("/api/v2/projects") const { data: orgs, error: orgsError } = useSWR("/api/v2/users/me/organizations") @@ -35,10 +33,6 @@ const ProjectsPage: React.FC = () => { return } - const createProject = () => { - void router.push("/projects/create") - } - // Create a dictionary of organization ID -> organization Name // Needed to properly construct links to dive into a project const orgDictionary = orgs.reduce((acc: Record, curr: Organization) => { @@ -58,14 +52,14 @@ const ProjectsPage: React.FC = () => { }, ] - const description =
-
Run the following command to get started:
- -
+ const description = ( +
+
Run the following command to get started:
+ +
+ ) - const emptyState = + const emptyState = const tableProps = { title: "All Projects", @@ -88,11 +82,14 @@ const ProjectsPage: React.FC = () => { ) } -const useStyles = makeStyles(() => ({ +const useStyles = makeStyles((theme) => ({ root: { display: "flex", flexDirection: "column", }, + descriptionLabel: { + marginBottom: theme.spacing(1), + }, })) export default ProjectsPage pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy