diff --git a/package.json b/package.json index 9bfea0d..b12a4d3 100644 --- a/package.json +++ b/package.json @@ -8,5 +8,14 @@ "keywords": [], "author": "", "license": "MIT", - "packageManager": "yarn@3.2.3" + "packageManager": "yarn@3.2.3", + "dependencies": { + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@mui/icons-material": "^6.0.1", + "@mui/material": "^6.0.1", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.41", + "tailwindcss": "^3.4.10" + } } diff --git a/packages/app/index.css b/packages/app/index.css index 4bf1c5d..ece3c5e 100644 --- a/packages/app/index.css +++ b/packages/app/index.css @@ -1,4 +1,4 @@ -@tailwind base; +/* @tailwind base; @tailwind components; @tailwind utilities; @@ -14,4 +14,27 @@ body { code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; -} \ No newline at end of file +} */ + +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + font-family: "Space Grotesk", sans-serif; + background-color: #ffbfbf; + background: radial-gradient(70.71% 70.71% at 50% 50%, #FFF 19%, rgba(255, 255, 255, 0.00) 61%), linear-gradient(38deg, rgba(255, 255, 255, 0.00) 60%, rgba(255, 255, 255, 0.69) 100%), linear-gradient(45deg, #FFF 10%, rgba(255, 255, 255, 0.00) 23.5%), linear-gradient(36deg, #FFF 12.52%, rgba(255, 255, 255, 0.00) 76.72%), linear-gradient(214deg, rgba(255, 255, 255, 0.00) 0%, rgba(255, 220, 234, 0.40) 37.53%, rgba(255, 255, 255, 0.00) 71%), linear-gradient(212deg, rgba(255, 255, 255, 0.00) 15%, #E4F1FE 72.5%, rgba(255, 255, 255, 0.00) 91.5%); +} + +body { + margin: 0; + font-family: "Space Grotesk", sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} + diff --git a/packages/app/index.html b/packages/app/index.html index 10746d0..4aeb9d1 100644 --- a/packages/app/index.html +++ b/packages/app/index.html @@ -39,7 +39,17 @@ window.process = process; window.setImmediate = setImmediate; + + + + + + + +
diff --git a/packages/app/package.json b/packages/app/package.json index 6c7213b..5aeceb4 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -2,6 +2,10 @@ "name": "@zk-email/twitter-verifier-app", "version": "4.0.0", "dependencies": { + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@mui/icons-material": "^6.0.1", + "@mui/material": "^6.0.1", "@proof-of-twitter/circuits": "workspace:^", "@proof-of-twitter/contracts": "workspace:^", "@rainbow-me/rainbowkit": "^2.1.4", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 29676be..1a4c696 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -1,4 +1,5 @@ import { MainPage } from "./pages/MainPage"; +import AboutPage from './pages/AboutPage' import "./styles.css"; import { BrowserRouter as Router, @@ -10,36 +11,15 @@ import { useLocation } from "react-use"; import styled from "styled-components"; import { ConnectButton } from "@rainbow-me/rainbowkit"; -const NavSection = () => { - const { pathname } = useLocation(); - return ( - - ); -}; const App = () => { return (
- - } /> + } /> Not found} />
@@ -48,28 +28,3 @@ const App = () => { }; export default App; - -const Logo = styled(Link)` - text-transform: uppercase; - letter-spacing: 0.04em; - color: #fff; - text-decoration: none; - font-size: 1.2rem; -`; - -const Nav = styled.nav` - display: flex; - align-items: center; - justify-content: space-between; - margin: 12px; -`; - -const DocsLink = styled.a` - color: rgba(255, 255, 255, 0.8); - text-decoration: none; - underline: none; - transition: all 0.2s ease-in-out; - &:hover { - color: rgba(255, 255, 255, 1); - } -`; diff --git a/packages/app/src/components/Accordion.tsx b/packages/app/src/components/Accordion.tsx new file mode 100644 index 0000000..f179332 --- /dev/null +++ b/packages/app/src/components/Accordion.tsx @@ -0,0 +1,97 @@ +import React, { FC } from 'react'; +import { + Accordion as MuiAccordion, + AccordionSummary, + AccordionDetails, + Typography, + styled, +} from '@mui/material'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; + +// Define the props types +interface AccordionProps { + title: string; + contents: string; + alignment?: 'left' | 'right'; +} + +const CustomAccordion = styled(MuiAccordion)(({ theme }) => ({ + marginBottom: theme.spacing(2), + '&:before': { + display: 'none', + }, + background: 'inherit', + boxShadow: 'none', + borderBottom: '1px solid rgba(0, 0, 0, 0.12)', + '& .MuiAccordionSummary-root': { + backgroundColor: 'rgba(0, 0, 0, 0)', + '&:hover .MuiAccordionSummary-expandIconWrapper': { + color: theme.palette.secondary.main, + }, + }, + '& .MuiAccordionSummary-content': { + margin: 0, + display: 'flex', + alignItems: 'center', + width: '100%', + }, + '& .MuiAccordionSummary-expandIconWrapper': { + marginRight: theme.spacing(1), + transition: 'transform 0.2s', + }, + '& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': { + transform: 'rotate(180deg)', + }, + '& .MuiAccordionDetails-root': { + padding: theme.spacing(2), + }, +})); + +const Accordion: FC = ({ title, contents, alignment = 'left' }) => { + return ( + + } + aria-controls="panel-content" + id="panel-header" + sx={{ + flexDirection: alignment === 'right' ? 'row-reverse' : 'row', + justifyContent: alignment === 'right' ? 'space-between' : 'flex-start', + '& .MuiAccordionSummary-expandIconWrapper': { + order: alignment === 'right' ? 2 : 1, + marginRight: alignment === 'right' ? 0 : 1, + marginLeft: alignment === 'right' ? 1 : 0, + }, + width: '100%', + }} + > + + {title} + + + + + {contents} + + + + ); +}; + +export default Accordion; \ No newline at end of file diff --git a/packages/app/src/components/Button.tsx b/packages/app/src/components/Button.tsx index 385498f..f194d84 100644 --- a/packages/app/src/components/Button.tsx +++ b/packages/app/src/components/Button.tsx @@ -1,10 +1,22 @@ + + +import React from 'react'; import styled from "styled-components"; +import { useTheme, Button as MuiButton } from "@mui/material"; -export const Button = styled.button` - padding: 0 14px; - border-radius: 4px; - background: #8272e4; - border: none; +interface ButtonProps { + highlighted?: boolean; + disabled?: boolean; + onClick?: () => void; + children: React.ReactNode; + endIcon?: React.ReactNode; + href?: string; + target?: string; +} + +const StyledButton = styled(MuiButton)<{ highlighted: boolean }>` + text-transform: none; + border-radius: 9px; display: flex; align-items: center; justify-content: center; @@ -17,58 +29,174 @@ export const Button = styled.button` width: 100%; min-width: 32px; transition: all 0.2s ease-in-out; + background: ${({ highlighted, theme }) => (highlighted ? theme.palette.accent.main : '#1C1C1C')}; + &:hover { - background: #9b8df2; + background: ${({ highlighted, theme }) => (highlighted ? theme.palette.accent.main : '#1C1C1C')}; + opacity: 0.5; } + &:disabled { opacity: 0.5; cursor: not-allowed; + color: ${({ highlighted, theme }) => (highlighted ? '#ffffff' : 'grey')}; + } + + @media (max-width: 600px) { + font-size: 0.8rem; + padding: 0 12px; + } + + @media (max-width: 400px) { + font-size: 0.6rem; + padding: 0 4px; + height: 40px; } `; -export const OutlinedButton = styled.button` - padding: 0 14px; - border-radius: 4px; - border: none; +const StyledOutlinedButton = styled(MuiButton)<{ highlighted: boolean }>` + padding: 0 5px; + border-radius: 9px; display: flex; align-items: center; justify-content: center; font-weight: 500; font-size: 0.9rem; letter-spacing: -0.02em; - color: #8272e4; + text-transform: none; cursor: pointer; height: 48px; width: 100%; - min-width: 32px; + min-width: 30px; transition: all 0.2s ease-in-out; - background: transparent; - border: 1px solid #8272e4; + background: '#ffffff'; + border: 1px solid ${({ highlighted, theme }) => (highlighted ? theme.palette.accent.main : '#1C1C1C')}; + color: ${({ highlighted, theme }) => (highlighted ? theme.palette.accent.main : '#1C1C1C')}; + &:hover { - background: #9b8df2; + background: ${({ highlighted, theme }) => (highlighted ? theme.palette.accent.main : '#1C1C1C')}; color: white; } + &:disabled { opacity: 0.5; cursor: not-allowed; } + + @media (max-width: 600px) { + font-size: 0.8rem; + padding: 0 12px; + } + + @media (max-width: 400px) { + font-size: 0.6rem; + padding: 0 2px; + height: 40px; + } `; +const StyledTextButton = styled(MuiButton)<{ highlighted: boolean }>` + width: fit-content; + background: '#ffffff'; + border: none; + color: ${({ highlighted, theme }) => (highlighted ? theme.palette.accent.main : theme.palette.secondary.main)}; + font-weight: 500; + border-radius: 9px; -export const TextButton = styled.button` -width: fit-content; -background: transparent; -border: none; -color: white; -font-weight: 500; -padding: 4px 16px; -border-radius: 4px; &:hover { - background: #00000020; - color: white; + color: theme.palette.secondary.main; } + &:disabled { opacity: 0.5; cursor: not-allowed; } + + @media (max-width: 600px) { + font-size: 0.8rem; + padding: 2px 12px; + } + + @media (max-width: 400px) { + font-size: 0.6rem; + padding: 0 2px; + height: 40px; + } `; + +export const Button: React.FC = ({ highlighted = false, disabled, onClick, children, endIcon, href, target }) => { + const theme = useTheme(); + + const handleClick = (e: React.MouseEvent) => { + if (disabled) return; + if (href) { + window.open(href, target); + } else if (onClick) { + onClick(); + } + }; + + return ( + + {children} + + ); +}; + +export const OutlinedButton: React.FC = ({ highlighted = false, disabled, onClick, children, endIcon, href, target }) => { + const theme = useTheme(); + + const handleClick = (e: React.MouseEvent) => { + if (disabled) return; + if (href) { + window.open(href, target); + } else if (onClick) { + onClick(); + } + }; + + return ( + + {children} + + ); +}; + +export const TextButton: React.FC = ({ highlighted = false, disabled, onClick, children, endIcon, href, target }) => { + const theme = useTheme(); + + const handleClick = (e: React.MouseEvent) => { + if (disabled) return; + if (href) { + window.open(href, target); + } else if (onClick) { + onClick(); + } + }; + + return ( + + {children} + {endIcon && {endIcon}} + + ); +}; + diff --git a/packages/app/src/components/DragAndDropTextBox.tsx b/packages/app/src/components/DragAndDropTextBox.tsx index 9f51137..5402db5 100644 --- a/packages/app/src/components/DragAndDropTextBox.tsx +++ b/packages/app/src/components/DragAndDropTextBox.tsx @@ -1,20 +1,79 @@ +// import React from "react"; +// import styled from 'styled-components'; +// import { useDragAndDrop } from '../hooks/useDragAndDrop'; + +// const DragAndDropTextBoxWrapper = styled.div` +// display: flex; +// flex-direction: column; +// align-items: center; +// border: 2px dashed #ccc; +// padding: 20px; +// `; + +// type Props = { +// onFileDrop: (file: File) => void; +// }; + +// const DragAndDropTextBox: React.FC = ({onFileDrop}) => { +// const { +// dragging, +// handleDragEnter, +// handleDragLeave, +// handleDragOver, +// handleDrop, +// handleDragEnd, +// } = useDragAndDrop(); + +// return ( +// handleDrop(e, onFileDrop)} +// > +// {dragging ? ( +//
Drop here
+// ) : ( +//
Drop .eml file here
+// )} +//
+// ); +// }; + +// export default DragAndDropTextBox; + + + + import React from "react"; -import styled from 'styled-components'; +import styled, { css, ThemeProvider } from 'styled-components'; +import { useTheme } from "@mui/material/styles"; import { useDragAndDrop } from '../hooks/useDragAndDrop'; +import { Typography } from "@mui/material"; -const DragAndDropTextBoxWrapper = styled.div` +const DragAndDropTextBoxWrapper = styled.div<{ highlighted: boolean }>` display: flex; flex-direction: column; align-items: center; border: 2px dashed #ccc; padding: 20px; + ${({ highlighted, theme }) => + highlighted + ? css` + border-color: ${theme.palette.accent.main}; + color: ${theme.palette.accent.main} + ` + : ''} `; type Props = { onFileDrop: (file: File) => void; + highlighted?: boolean; }; -const DragAndDropTextBox: React.FC = ({onFileDrop}) => { +const DragAndDropTextBox: React.FC = ({ onFileDrop, highlighted = false }) => { + const theme = useTheme(); const { dragging, handleDragEnter, @@ -25,20 +84,24 @@ const DragAndDropTextBox: React.FC = ({onFileDrop}) => { } = useDragAndDrop(); return ( - handleDrop(e, onFileDrop)} - > - {dragging ? ( -
Drop here
- ) : ( -
Drop .eml file here
- )} -
+ + handleDrop(e, onFileDrop)} + > + {dragging ? ( +
Drop here
+ ) : ( +
Drop .eml file here
+ )} +
+
); }; export default DragAndDropTextBox; + diff --git a/packages/app/src/components/EmailInputMethod.tsx b/packages/app/src/components/EmailInputMethod.tsx index 851b661..38f3ff0 100644 --- a/packages/app/src/components/EmailInputMethod.tsx +++ b/packages/app/src/components/EmailInputMethod.tsx @@ -1,12 +1,55 @@ -import { useState } from "react"; +// import { useState } from "react"; +// import { Button, OutlinedButton } from "./Button"; + +// const EmailInputMethod = ({ +// onClickGoogle, +// onClickEMLFile, +// }: { +// onClickGoogle: () => void; +// onClickEMLFile: () => void; +// }) => { +// return ( +//
+// +// or +// { +// onClickEMLFile(); +// }} +// > +// Upload email .eml file{" "} +// +//
+// ); +// }; + +// export default EmailInputMethod; + + + import { Button, OutlinedButton } from "./Button"; -const EmailInputMethod = ({ - onClickGoogle, - onClickEMLFile, -}: { +interface EmailInputMethodProps { onClickGoogle: () => void; onClickEMLFile: () => void; + highlighted?: boolean; + disabled?: boolean; // Optional disabled prop +} + +const EmailInputMethod: React.FC = ({ + onClickGoogle, + onClickEMLFile, + highlighted = false, + disabled = false, // Default value set to false }) => { return (
- - or - { - onClickEMLFile(); - }} - > - Upload email .eml file{" "} - + + {!disabled && ( + <> + or + + Upload email .eml file{" "} + + + )}
); }; diff --git a/packages/app/src/components/LabeledTextArea.tsx b/packages/app/src/components/LabeledTextArea.tsx index 66112c6..a4dc935 100644 --- a/packages/app/src/components/LabeledTextArea.tsx +++ b/packages/app/src/components/LabeledTextArea.tsx @@ -1,7 +1,109 @@ +// import _ from "lodash"; +// import React, { CSSProperties } from "react"; +// import styled from "styled-components"; +// import { Col } from "./Layout"; + +// export const LabeledTextArea: React.FC<{ +// style?: CSSProperties; +// className?: string; +// label: string; +// value: string; +// warning?: string; +// warningColor?: string; +// disabled?: boolean; +// disabledReason?: string; +// secret?: boolean; +// onChange?: React.ChangeEventHandler; +// }> = ({ +// style, +// warning, +// warningColor, +// disabled, +// disabledReason, +// label, +// value, +// onChange, +// className, +// secret, +// }) => { +// return ( +// +// +// {warning && ( +// +// {warning} +// +// )} +//