From 489a0c1a2ac402ece6b4ac65f590b4d7c7941d90 Mon Sep 17 00:00:00 2001 From: Bana Malik Date: Fri, 17 Dec 2021 17:38:06 -0500 Subject: [PATCH 01/19] working version --- packages/codebytes/src/consts.ts | 15 +++ packages/codebytes/src/drawers.tsx | 128 +++++++++++++++++++++++ packages/codebytes/src/editor.tsx | 161 ++++++++++++++++++++++++++++- packages/codebytes/src/index.tsx | 7 ++ packages/codebytes/tsconfig.json | 2 +- 5 files changed, 308 insertions(+), 5 deletions(-) create mode 100644 packages/codebytes/src/consts.ts create mode 100644 packages/codebytes/src/drawers.tsx diff --git a/packages/codebytes/src/consts.ts b/packages/codebytes/src/consts.ts new file mode 100644 index 000000000..8dbd6f3a9 --- /dev/null +++ b/packages/codebytes/src/consts.ts @@ -0,0 +1,15 @@ +// key = language param to send to snippets service +// val = label in language selection drop down +export const languageOptions = { + '': 'Select your language', + cpp: 'C++', + csharp: 'C#', + golang: 'Go', + javascript: 'JavaScript', + php: 'PHP', + python: 'Python 3', + ruby: 'Ruby', + scheme: 'Scheme', + }; + + export type languageOption = keyof typeof languageOptions; \ No newline at end of file diff --git a/packages/codebytes/src/drawers.tsx b/packages/codebytes/src/drawers.tsx new file mode 100644 index 000000000..7fb0d76c5 --- /dev/null +++ b/packages/codebytes/src/drawers.tsx @@ -0,0 +1,128 @@ +import { FlexBox, IconButton } from '@codecademy/gamut'; +import { + ArrowChevronLeftIcon, + ArrowChevronRightIcon, +} from '@codecademy/gamut-icons'; +import styled from '@emotion/styled'; +import React, { useState } from 'react'; + +const DrawerLabel = styled.span` + padding: 0.875rem 0.5rem; +`; + +const LeftDrawerIcon = styled(ArrowChevronLeftIcon)<{ open?: boolean }>` + transition: transform 0.2s ease-in-out; +`; +const RightDrawerIcon = LeftDrawerIcon.withComponent(ArrowChevronRightIcon); + +const Drawer = styled(FlexBox)<{ open?: boolean; hideOnClose?: boolean }>` + position: relative; + ${({ open, hideOnClose }) => ` + flex-basis: ${open ? '100%' : '0%'}; + ${!open && hideOnClose ? 'visibility: hidden;' : ''} + transition: flex-basis 0.2s ${ + open ? 'ease-out' : 'ease-in, visibility 0s 0.2s' + }; + + ${LeftDrawerIcon}, ${RightDrawerIcon} { + transform: rotateZ(${open ? '0' : '180'}deg)}; + } + `} +`; + +export type DrawersProps = { + leftChild: React.ReactNode; + rightChild: React.ReactNode; +}; + +export const Drawers: React.FC = ({ leftChild, rightChild }) => { + const [show, setShow] = useState<'left' | 'right' | 'both'>('both'); + + let buttonLabelL = 'hide code'; + let buttonLabelR = 'hide output'; + + if (show === 'left') { + buttonLabelL = buttonLabelR = 'show output'; + } else if (show === 'right') { + buttonLabelL = buttonLabelR = 'show code'; + } + + return ( + <> + + + + setShow((state) => (state === 'both' ? 'right' : 'both')) + } + aria-label={buttonLabelL} + aria-controls="code-drawer" + aria-expanded={show !== 'right'} + /> + Code + + + Output + + setShow((state) => (state === 'both' ? 'left' : 'both')) + } + aria-label={buttonLabelR} + aria-controls="output-drawer" + aria-expanded={show !== 'left'} + /> + + + + + {leftChild} + + + {rightChild} + + + + ); +}; diff --git a/packages/codebytes/src/editor.tsx b/packages/codebytes/src/editor.tsx index 39710e871..cbde378a5 100644 --- a/packages/codebytes/src/editor.tsx +++ b/packages/codebytes/src/editor.tsx @@ -1,10 +1,163 @@ -import React from 'react'; +import { + FillButton, + FlexBox, + Spinner, + TextButton, + ToolTip, +} from '@codecademy/gamut'; +import { CopyIcon } from '@codecademy/gamut-icons'; +import { theme } from '@codecademy/gamut-styles'; +import styled from '@emotion/styled'; +import React, { useState } from 'react'; + +import type { languageOption } from './consts'; +import { Drawers } from './drawers'; + +const Output = styled.pre<{ hasError: boolean }>` + width: 100%; + height: 100%; + margin: 0; + padding: 0 1rem; + font-family: Monaco; + font-size: 0.875rem; + overflow: auto; + ${({ hasError }) => ` + color: ${hasError ? theme.colors.orange : theme.colors.white}; + background-color: ${theme.colors['gray-900']}; +`} +`; + +const CopyIconStyled = styled(CopyIcon)` + margin-right: 0.5rem; +`; + +const DOCKER_SIGTERM = 143; type EditorProps = { + hideCopyButton: boolean; + language: languageOption; text: string; - onChange: (text: string) => void; + // eslint-disable-next-line react/no-unused-prop-types + onChange: (text: string) => void /* Will use in upcoming pr */; + onCopy?: (text: string, language: string) => void; }; -export const Editor: React.FC = ({ text, onChange }) => { - return