diff --git a/apps/passport-client/components/screens/AddEmailScreen.tsx b/apps/passport-client/components/screens/AddEmailScreen.tsx index 28834bc6be..46fa81ad42 100644 --- a/apps/passport-client/components/screens/AddEmailScreen.tsx +++ b/apps/passport-client/components/screens/AddEmailScreen.tsx @@ -246,7 +246,7 @@ export function AddEmailScreen(): JSX.Element | null { return ( <> - + {content} diff --git a/apps/passport-client/components/screens/AddScreen/AddScreen.tsx b/apps/passport-client/components/screens/AddScreen/AddScreen.tsx index 4dd324f040..d1796c1fa5 100644 --- a/apps/passport-client/components/screens/AddScreen/AddScreen.tsx +++ b/apps/passport-client/components/screens/AddScreen/AddScreen.tsx @@ -36,7 +36,7 @@ export function AddScreen(): JSX.Element | null { if (!screen) { // Need AppContainer to display error - return ; + return ; } return screen; } diff --git a/apps/passport-client/components/screens/AddScreen/JustAddScreen.tsx b/apps/passport-client/components/screens/AddScreen/JustAddScreen.tsx index e90cdc705a..2b7ebf25ac 100644 --- a/apps/passport-client/components/screens/AddScreen/JustAddScreen.tsx +++ b/apps/passport-client/components/screens/AddScreen/JustAddScreen.tsx @@ -146,7 +146,7 @@ export function JustAddScreen({ <> {isProtocolWorlds && } - + diff --git a/apps/passport-client/components/screens/AddScreen/ProveAndAddScreen.tsx b/apps/passport-client/components/screens/AddScreen/ProveAndAddScreen.tsx index bf73f59133..f12ae15ece 100644 --- a/apps/passport-client/components/screens/AddScreen/ProveAndAddScreen.tsx +++ b/apps/passport-client/components/screens/AddScreen/ProveAndAddScreen.tsx @@ -79,7 +79,7 @@ export function ProveAndAddScreen({ return ( <> - + diff --git a/apps/passport-client/components/screens/AddSubscriptionScreen.tsx b/apps/passport-client/components/screens/AddSubscriptionScreen.tsx index 361cb1573a..0a14bcd4da 100644 --- a/apps/passport-client/components/screens/AddSubscriptionScreen.tsx +++ b/apps/passport-client/components/screens/AddSubscriptionScreen.tsx @@ -187,7 +187,7 @@ export function AddSubscriptionScreen(): JSX.Element | null { return ( <> - + {mismatchedEmails && ( diff --git a/apps/passport-client/components/screens/ChangeEmailScreen.tsx b/apps/passport-client/components/screens/ChangeEmailScreen.tsx index 8264526894..ef426d348b 100644 --- a/apps/passport-client/components/screens/ChangeEmailScreen.tsx +++ b/apps/passport-client/components/screens/ChangeEmailScreen.tsx @@ -257,7 +257,7 @@ export function ChangeEmailScreen(): JSX.Element | null { return ( <> - + {content} diff --git a/apps/passport-client/components/screens/ChangePasswordScreen.tsx b/apps/passport-client/components/screens/ChangePasswordScreen.tsx index 0b22947b03..585bfc1e4e 100644 --- a/apps/passport-client/components/screens/ChangePasswordScreen.tsx +++ b/apps/passport-client/components/screens/ChangePasswordScreen.tsx @@ -201,7 +201,7 @@ export function ChangePasswordScreen(): JSX.Element | null { return ( <> - + {content} diff --git a/apps/passport-client/components/screens/EmbeddedScreens/EmbeddedGPCProofScreen.tsx b/apps/passport-client/components/screens/EmbeddedScreens/EmbeddedGPCProofScreen.tsx index 183a921ab8..eabfed4626 100644 --- a/apps/passport-client/components/screens/EmbeddedScreens/EmbeddedGPCProofScreen.tsx +++ b/apps/passport-client/components/screens/EmbeddedScreens/EmbeddedGPCProofScreen.tsx @@ -50,7 +50,7 @@ export function EmbeddedGPCProofScreen({ const identity = useIdentityV3(); return ( - +

+ diff --git a/apps/passport-client/components/shared/AppContainer.tsx b/apps/passport-client/components/shared/AppContainer.tsx index 16e3752fae..526ebeb8bd 100644 --- a/apps/passport-client/components/shared/AppContainer.tsx +++ b/apps/passport-client/components/shared/AppContainer.tsx @@ -11,7 +11,8 @@ import { ScreenLoader } from "./ScreenLoader"; // Wrapper for all screens. export function AppContainer({ - children + children, + bg }: { bg: "primary" | "gray"; children?: ReactNode; @@ -25,7 +26,8 @@ export function AppContainer({ [dispatch] ); - const col = "var(--bg-dark-primary)"; + const col = + bg === "gray" ? "var(--dot-pattern-bg)" : "var(--bg-dark-primary)"; return ( <> @@ -53,7 +55,7 @@ export function AppContainer({ export const GlobalBackground = createGlobalStyle<{ color: string }>` html { - background-color: ${(p): string => p.color}; + background: ${(p): string => p.color}; } `; diff --git a/apps/passport-client/new-components/Accordion/index.tsx b/apps/passport-client/new-components/Accordion/index.tsx new file mode 100644 index 0000000000..340891e169 --- /dev/null +++ b/apps/passport-client/new-components/Accordion/index.tsx @@ -0,0 +1,139 @@ +import { forwardRef, useImperativeHandle, useMemo, useState } from "react"; +import styled, { FlattenSimpleInterpolation, css } from "styled-components"; +import { Typography } from "../Typography"; +import { FaChevronDown, FaChevronRight } from "react-icons/fa"; + +export type AccrodionChild = { + title: string; + key?: string; + onClick?: () => void; +}; + +export type AccordionProps = { + title: string; + children: AccrodionChild[]; +}; + +export type AccordionRef = { + open: () => void; + close: () => void; + toggle: () => void; + getState: () => boolean; +}; + +const parentContainerOpenCss = css` + border-bottom: 1.15px solid #eceaf4; +`; +const Container = styled.div<{ open: boolean }>` + border-top: 1.15px solid #eceaf4; + border-left: 1.15px solid #eceaf4; + border-right: 1.15px solid #eceaf4; + background: #f6f8fd; + border-radius: 10px; + ${({ open }): FlattenSimpleInterpolation | undefined => + open ? parentContainerOpenCss : undefined} +`; + +const closedCss = css` + border-radius: 10px; +`; +const HeaderContainer = styled.div<{ open: boolean }>` + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + padding: 12px 16px; + color: var(--text-tertiary); + border-bottom: 1.15px solid #eceaf4; + cursor: pointer; + ${({ open }): FlattenSimpleInterpolation | undefined => + !open ? closedCss : undefined} +`; + +const ToggleContainer = styled.div` + display: flex; + flex-direction: row; + gap: 8px; + align-items: center; +`; + +const AccordionItem = styled.div<{ lastItem: boolean; clickable: boolean }>` + padding: 12px 16px; + color: var(--text-primary); + cursor: ${({ clickable }): string => (clickable ? "pointer" : "unset")}; + ${({ lastItem }): string | undefined => + !lastItem ? "border-bottom: 1.15px solid #eceaf4;" : undefined} +`; +export const Accordion = forwardRef( + ({ title, children }, ref) => { + const [open, setOpen] = useState(false); + + useImperativeHandle(ref, () => { + return { + open(): void { + setOpen(true); + }, + close(): void { + setOpen(false); + }, + toggle(): void { + setOpen((old) => !old); + }, + getState(): boolean { + return open; + } + }; + }); + + const renderedChildren = useMemo(() => { + const len = children.length; + return children.map((child, i) => { + const isLast = len - 1 === i; + return ( + + + {child.title} + + + ); + }); + }, [children]); + + return ( + + { + setOpen((old) => !old); + }} + > + + {title.toUpperCase()} + + + {open ? undefined : ( + + {children.length} + + )} + {open ? : } + + + {open && renderedChildren} + + ); + } +); diff --git a/apps/passport-client/new-components/Avatar.tsx b/apps/passport-client/new-components/Avatar.tsx new file mode 100644 index 0000000000..dd05c1636b --- /dev/null +++ b/apps/passport-client/new-components/Avatar.tsx @@ -0,0 +1,38 @@ +import { ReactElement } from "react"; +import styled from "styled-components"; +const AVATAR_SIZE = 36; +type IconProps = { + imgSrc?: string; +}; + +const Inner = styled.div<{ size: number }>` + width: ${({ size }): number => size / 3}px; + height: ${({ size }): number => size / 3}px; + border-radius: ${({ size }): number => size / 3}px; + background: #bcc4dc; +`; + +const Outer = styled.div<{ size: number }>` + width: ${({ size }): number => size}px; + height: ${({ size }): number => size}px; + border-radius: ${({ size }): number => size / 3}px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + background: #e4eaff; +`; + +const AvatarImage = styled.img` + flex-shrink: 0; + min-height: 100%; + min-width: 100%; +`; + +export const Avatar = ({ imgSrc }: IconProps): ReactElement => { + return ( + + {imgSrc ? : } + + ); +}; diff --git a/apps/passport-client/new-components/BottomModal.tsx b/apps/passport-client/new-components/BottomModal.tsx new file mode 100644 index 0000000000..5c1d6ae3c7 --- /dev/null +++ b/apps/passport-client/new-components/BottomModal.tsx @@ -0,0 +1,63 @@ +import { ReactNode } from "react"; +import styled from "styled-components"; +import { useDispatch } from "../src/appHooks"; + +const BottomModalOverlay = styled.div<{ $fullScreen?: boolean }>` + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + overflow-x: hidden; + overflow-y: hidden; + backdrop-filter: blur(4px); + z-index: 9999; + padding: 12px; + display: flex; + align-items: end; +`; + +const BottomModalContainer = styled.div` + padding: 24px 24px 20px 24px; + gap: 20px; + border-radius: 40px; + background: #ffffff; + bottom: 12px; + color: black; + flex: 1; + box-shadow: 0px 4px 6px -1px #0000001a; +`; + +export type BottomModalProps = { + isOpen: boolean; + children: ReactNode; +}; + +export const BottomModal = ({ + isOpen, + children +}: BottomModalProps): JSX.Element | null => { + const dispatch = useDispatch(); + if (!isOpen) { + return null; + } + return ( + { + dispatch({ + type: "set-bottom-modal", + modal: { modalType: "none" } + }); + }} + > + { + // Consider use clickOutside hook instead of that + e.stopPropagation(); + }} + > + {children} + + + ); +}; diff --git a/apps/passport-client/new-components/Button.tsx b/apps/passport-client/new-components/Button.tsx new file mode 100644 index 0000000000..6b7e5e6039 --- /dev/null +++ b/apps/passport-client/new-components/Button.tsx @@ -0,0 +1,80 @@ +import * as React from "react"; +import styled, { FlattenSimpleInterpolation, css } from "styled-components"; + +type BtnVariant = "primary" | "secondary" | "danger"; + +const getBtnVariant = (variant: BtnVariant): typeof BtnBase => { + switch (variant) { + case "secondary": + return BtnSecondary; + case "danger": + return BtnDanger; + default: + return BtnBase; + } +}; + +interface BtnProps extends React.ButtonHTMLAttributes { + variant?: BtnVariant; +} +export const Button2 = React.forwardRef( + (btnProps: BtnProps, ref: React.ForwardedRef) => { + const Btn = getBtnVariant(btnProps.variant ?? "primary"); + return ; + } +); + +const buttonStyle = css` + user-select: none; + word-break: break-word; + width: 100%; + height: 54px; + padding: 12px; + color: #fff; + border: none; + border-radius: 200px; + font-size: 16px; + font-weight: 500; + background: var(--core-accent); + opacity: 1; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; + + &:hover { + background: hsl(210, 100%, 50%); + } + &:active:not([disabled]) { + opacity: 0.9; + } +`; + +const disabledCSS = css` + cursor: not-allowed; + opacity: 0.5; +`; + +export const BtnBase = styled.button` + ${buttonStyle} + ${({ disabled }): FlattenSimpleInterpolation | undefined => + disabled === true ? disabledCSS : undefined} +} +`; + +const BtnSecondary = styled(BtnBase)` + color: var(--text-primary); + background: #fff; + border: 1px solid rgba(0, 0, 0, 0.05); + &:hover { + background: hsl(0, 0%, 98%); + } +`; + +const BtnDanger = styled(BtnBase)` + color: #fff; + background: var(--new-danger); + &:hover { + background: hsl(0, 100%, 57%); + } +`; diff --git a/apps/passport-client/new-components/ComponentsScreen.tsx b/apps/passport-client/new-components/ComponentsScreen.tsx new file mode 100644 index 0000000000..c9a2f24772 --- /dev/null +++ b/apps/passport-client/new-components/ComponentsScreen.tsx @@ -0,0 +1,212 @@ +import { useRef, useState } from "react"; +import { CenterColumn, Spacer, TextCenter } from "../components/core"; +import { AppContainer } from "../components/shared/AppContainer"; +import { Avatar } from "./Avatar"; +import { Button2 } from "./Button"; +import { FloatingMenu } from "./FloatingMenu"; +import { Input2 } from "./Input"; +import { List } from "./List"; +import { Ticket } from "./Ticket"; +import { TicketCard } from "./TicketCard"; +import { SettingsBottomModal } from "./settingsBottomModal"; +import { FaTrashCan } from "react-icons/fa6"; +import { Accordion, AccordionRef } from "./Accordion"; +const exampleList = [ + { + title: "Event Passes", + isLastItemBorder: false, + children: [ + { + title: "Devcon Pass", + LeftIcon: + }, + { + title: "Berlin Event Pass", + variant: "danger", + LeftIcon: + }, + { + title: "Denver Event Pass", + variant: "danger", + LeftIcon: + } + ] + }, + { + title: "Puddle Crypto", + children: [ + { + title: "American Bullfrog", + LeftIcon: ( + + ) + }, + { + title: "Wood Frog", + LeftIcon: ( + + ) + } + ] + }, + { + title: "FrogCraiglist", + children: [ + { + title: "Digital Chair Listing" + } + ] + } +]; + +const ComponentsScreen = (): JSX.Element => { + const [error, setError] = useState(""); + const accordionRef = useRef(null); + return ( + + {/* We need to reconsider the MaybeModal concept, not sure we will apply the same for bottom-modal */} + +
+ + Hello, world! + + + + + +
+ { + if (error) { + setError(""); + } else { + setError("some generic error"); + } + }} + > + primary + + { + if (error) { + setError(""); + } else { + setError("some generic error"); + } + }} + > + test input{" "} + + secondary +
+
+ +
+
+
+ +
+ +
+ + { + accordionRef.current?.toggle(); + }} + > + Click to toggle accordion + +
+
+
+
+ + +
+ + +
+
+ ); +}; + +export default ComponentsScreen; diff --git a/apps/passport-client/new-components/FloatingMenu.tsx b/apps/passport-client/new-components/FloatingMenu.tsx new file mode 100644 index 0000000000..7373d88f15 --- /dev/null +++ b/apps/passport-client/new-components/FloatingMenu.tsx @@ -0,0 +1,51 @@ +import { Cog6ToothIcon, Square3Stack3DIcon } from "@heroicons/react/24/solid"; +import styled from "styled-components"; +import { useDispatch } from "../src/appHooks"; + +const FloatingMenuContainer = styled.div` + position: fixed; + display: flex; + align-items: center; + justify-content: space-between; + bottom: 20px; + background-color: #ffffff; + + z-index: 2; + min-height: 56px; + left: 50%; + transform: translateX(-50%); + box-shadow: 0px 1px 3px 0px #0000001a; + + padding: 8px 20px 8px 20px; + border-radius: 200px; + opacity: 0px; +`; + +const FloatingMenuItem = styled.div` + width: 48px; + height: 40px; + justify-content: center; + align-items: center; + display: flex; +`; + +export const FloatingMenu = (): JSX.Element => { + const dispatch = useDispatch(); + return ( + + + + + + dispatch({ + type: "set-bottom-modal", + modal: { modalType: "settings" } + }) + } + > + + + + ); +}; diff --git a/apps/passport-client/new-components/Input.tsx b/apps/passport-client/new-components/Input.tsx new file mode 100644 index 0000000000..ece7499a59 --- /dev/null +++ b/apps/passport-client/new-components/Input.tsx @@ -0,0 +1,101 @@ +import { ForwardedRef, InputHTMLAttributes, Ref, forwardRef } from "react"; +import styled, { FlattenSimpleInterpolation, css } from "styled-components"; +import { Typography } from "./Typography"; + +interface InputProps extends InputHTMLAttributes { + variant?: "primary" | "secondary"; + error?: string; +} + +const errorCSS = css` + border: 2px solid var(--new-danger); + color: var(--new-danger); + ::placeholder { + color: var(--text-tertiary); + } + + &:focus, + &:active, + &:focus-visible, + &:focus-within { + border: 2px solid var(--new-danger); + outline: none; + } +`; + +const secondaryCSS = css` + background: var(--secondary-input-bg); +`; + +export const BigInput2 = styled.input<{ + error?: string; + variant: "primary" | "secondary"; +}>` + width: 100%; + height: 54px; + border-radius: 200px; + padding: 8px 24px; + font-size: 16px; + font-weight: 400; + border: 1px solid rgba(var(--white-rgb), 0.3); + background: white; + color: var(--text-primary); + box-shadow: 0px 1px 2px 0px #0000000d; + ::placeholder { + color: var(--text-tertiary); + } + + &:disabled { + user-select: none; + pointer-events: none; + background: rgba(0, 0, 0, 0.05); + } + ${({ error }): FlattenSimpleInterpolation | undefined => { + if (error) return errorCSS; + }} + ${({ variant }): FlattenSimpleInterpolation | undefined => { + if (variant === "secondary") return secondaryCSS; + }} +`; + +const ErrorContainer = styled.div` + display: flex; + flex-direction: column; + gap: 8px; + justify-content: flex-start; +`; + +export const Input2 = forwardRef( + (inputProps: InputProps, ref: ForwardedRef) => { + const { error, variant } = inputProps; + const defaultVariant = variant ?? "primary"; + if (error) { + return ( + + + + {error} + + + ); + } + return ; + } +); + +interface EmailCodeInputProps extends InputHTMLAttributes { + ref?: Ref; +} + +export const ConfirmationCodeInput = ( + inputProps: EmailCodeInputProps +): JSX.Element => { + return ( + + ); +}; diff --git a/apps/passport-client/new-components/List/ListItem.tsx b/apps/passport-client/new-components/List/ListItem.tsx new file mode 100644 index 0000000000..3a477e1a78 --- /dev/null +++ b/apps/passport-client/new-components/List/ListItem.tsx @@ -0,0 +1,100 @@ +import styled, { FlattenSimpleInterpolation, css } from "styled-components"; +import { Typography } from "../Typography"; +import { FaChevronRight } from "react-icons/fa"; +import { Avatar } from "../Avatar"; +import { ReactElement } from "react"; + +export type ListItemVariant = "primary" | "danger"; +export type ListItemType = { + title: string; + LeftIcon?: React.ReactNode; + variant?: ListItemVariant; + showBottomBorder?: boolean; + key?: string; + onClick?: () => void; +}; + +const getVariantColor = (variant: ListItemVariant): string => { + switch (variant) { + case "danger": + return "var(--new-danger)"; + default: + case "primary": + return "var(--text-primary)"; + } +}; + +const listItemClickableCSS = css` + cursor: pointer; + // so it wont be annoying ot click on an item + -webkit-user-select: none; /* Safari */ + -ms-user-select: none; /* IE 10 and IE 11 */ + user-select: none; /* Standard syntax */ +`; + +const ListItemContainer = styled.div<{ + variant: ListItemVariant; + isClickable: boolean; +}>` + display: flex; + width: 100%; + align-items: center; + gap: 16px; + color: ${({ variant }): string => getVariantColor(variant)}; + ${({ isClickable }): FlattenSimpleInterpolation | undefined => + isClickable ? listItemClickableCSS : undefined}; +`; + +const ListItemRightContainer = styled.div<{ showBottomBorder: boolean }>` + flex: 1 1 auto; + + display: flex; + height: 56px; + align-items: center; + justify-content: space-between; + ${({ showBottomBorder }): string | undefined => + showBottomBorder + ? "border-bottom: 1px solid rgba(0, 0, 0, 0.05);" + : undefined}; +`; + +const IconContainer = styled.div` + width: 36px; + height: 36px; + + display: flex; + align-items: center; + justify-content: center; +`; + +export const ListItem = ({ + title, + LeftIcon, + variant, + showBottomBorder, + onClick +}: ListItemType): ReactElement => { + const defaultVariant = variant ?? "primary"; + const defaultShowBottomBorder = + showBottomBorder !== undefined ? showBottomBorder : true; + return ( + + {LeftIcon ? LeftIcon : } + + + {title} + + + + + ); +}; diff --git a/apps/passport-client/new-components/List/index.tsx b/apps/passport-client/new-components/List/index.tsx new file mode 100644 index 0000000000..5d1979470c --- /dev/null +++ b/apps/passport-client/new-components/List/index.tsx @@ -0,0 +1,70 @@ +import styled from "styled-components"; +import { Typography } from "../Typography"; +import { ListItem, ListItemType } from "./ListItem"; +import { ReactElement } from "react"; + +export type GroupType = { + children: ListItemType[]; + title?: string; + isLastItemBorder?: boolean; +}; + +type ListChild = GroupType | ListItemType; +const isListGroup = (child: ListChild): child is GroupType => { + return !!(child as GroupType).children; +}; + +const GroupContainer = styled.div` + width: 100%; + margin-bottom: 20px; +`; + +const ListGroup = ({ + children, + title, + isLastItemBorder +}: GroupType): ReactElement => { + const len = children.length; + + return ( + + + {title} + + {children.map((child, i) => { + if (i === len - 1) { + return ( + + ); + } + return ; + })} + + ); +}; + +type ListProps = { + list: ListChild[]; +}; + +const ListContainer = styled.div` + padding: 12px 24px; +`; + +export const List = ({ list }: ListProps): ReactElement => { + return ( + + {list.map((child) => { + return isListGroup(child) ? ( + + ) : ( + + ); + })} + + ); +}; diff --git a/apps/passport-client/new-components/Ticket.tsx b/apps/passport-client/new-components/Ticket.tsx new file mode 100644 index 0000000000..060786f09e --- /dev/null +++ b/apps/passport-client/new-components/Ticket.tsx @@ -0,0 +1,60 @@ +import { QRDisplay } from "@pcd/passport-ui"; +import styled from "styled-components"; +import { Typography } from "./Typography"; + +const TicketBody = styled.div` + display: flex; + flex-direction: column; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 12px; +`; + +const QRWrapper = styled.div` + width: 250px; + height: 250px; + border-radius: 12px; + background-color: white; +`; + +const TicketDetails = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 2px; +`; + +interface TicketProps { + name: string; + type: "Speaker" | "General"; + email: string; +} +export const Ticket = ({ name, type, email }: TicketProps): JSX.Element => { + return ( + + + ; + + + + {name.toUpperCase()} + + + {type} + + + {email} + + + Share ticket + + + + ); +}; diff --git a/apps/passport-client/new-components/TicketCard.tsx b/apps/passport-client/new-components/TicketCard.tsx new file mode 100644 index 0000000000..324a24076f --- /dev/null +++ b/apps/passport-client/new-components/TicketCard.tsx @@ -0,0 +1,104 @@ +import { Property } from "csstype"; +import styled from "styled-components"; +import { Typography } from "./Typography"; + +type CardColor = "purple" | "orange"; +const CARD_COLORS: Record = { + purple: "rgba(154, 74, 201, 1)", + orange: "rgba(255, 115, 0, 1)" +}; + +const TicketCardContainer = styled.div<{ $borderColor: Property.Color }>` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 8px; + border-radius: 16px; + border-style: solid; + border-width: 4px; + border-color: ${({ $borderColor }): Property.Color => $borderColor}; + background-color: white; + box-shadow: + 0px 2px 4px -1px rgba(0, 0, 0, 0.06), + 0px 4px 6px -1px rgba(0, 0, 0, 0.1); +`; + +const TicketCardImage = styled.img` + width: 100%; + height: 100%; +`; + +const TicketCardImageContainer = styled.div` + position: relative; + width: 100%; + min-width: 350px; + height: 215px; + border-radius: 8px; + overflow: hidden; +`; + +const TicketCardDetails = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 2px; + padding: 8px; +`; + +const DateChipContainer = styled.div` + display: flex; + justify-content: center; + align-items: center; + text-align: center; + position: absolute; + top: 10px; + left: 10px; + border-radius: 200px; + padding: 4px 10px; + gap: 10px; + background-color: black; +`; + +interface TicketCardProps { + imgSource: string; + title: string; + address: string; + ticketCount: number; + ticketDate: string; + cardColor: CardColor; +} +export const TicketCard = ({ + imgSource, + title, + address, + ticketCount, + cardColor, + ticketDate +}: TicketCardProps): JSX.Element => { + return ( + + + + + {ticketDate} + + + + + + + {title} + + + {`${address} • ${ticketCount} ticket${ticketCount > 1 ? "s" : ""}`} + + + + ); +}; diff --git a/apps/passport-client/new-components/Typography.tsx b/apps/passport-client/new-components/Typography.tsx new file mode 100644 index 0000000000..f4ff447248 --- /dev/null +++ b/apps/passport-client/new-components/Typography.tsx @@ -0,0 +1,67 @@ +import { Property } from "csstype"; +import React from "react"; +import styled from "styled-components"; + +export type FontWeight = 400 | 500 | 600 | 700 | 800 | 900; +export type FontSize = 12 | 14 | 16 | 18; +export type FontFamily = "Barlow" | "Rubik"; +const LINE_HEIGHT: Record = { + "12": 16.2, + "14": 18.9, + "16": 21.6, + "18": 24.3 +}; + +const TypographyText = styled.span<{ + $fontSize: FontSize; + $fontWeight: FontWeight; + $color: Property.Color; + $opacity?: number; + $underline?: boolean; + $family?: FontFamily; +}>` + font-family: ${({ $family }): string => $family ?? "Barlow"}, sans-serif; + font-size: ${({ $fontSize }): string => `${$fontSize}px`}; + font-weight: ${({ $fontWeight }): number => $fontWeight}; + line-height: ${({ $fontSize }): string => + `${LINE_HEIGHT[$fontSize ?? 16]}px`}; + color: ${({ $color }): Property.Color => $color}; + opacity: ${({ $opacity }): number => $opacity ?? 1}; + text-decoration: ${({ $underline }): string => + $underline ? "underline" : "none"}; +`; + +interface TypographyProps { + fontSize?: FontSize; + fontWeight?: FontWeight; + family?: FontFamily; + color?: Property.Color; + children?: React.ReactNode; + opacity?: number; + underline?: boolean; + style?: React.CSSProperties; +} +export const Typography: React.FC = ({ + children, + fontSize = 14, + fontWeight = 400, + color = "var(--text-primary)", + opacity, + underline, + style, + family +}): JSX.Element => { + return ( + + {children} + + ); +}; diff --git a/apps/passport-client/new-components/settingsBottomModal.tsx b/apps/passport-client/new-components/settingsBottomModal.tsx new file mode 100644 index 0000000000..30f3132595 --- /dev/null +++ b/apps/passport-client/new-components/settingsBottomModal.tsx @@ -0,0 +1,66 @@ +import { FaTrashCan } from "react-icons/fa6"; +import { useBottomModal } from "../src/appHooks"; +import { Avatar } from "./Avatar"; +import { BottomModal } from "./BottomModal"; +import { List } from "./List"; + +const exampleList = [ + { + title: "Event Passes", + isLastItemBorder: false, + children: [ + { + title: "Devcon Pass", + LeftIcon: + }, + { + title: "Berlin Event Pass", + variant: "danger", + LeftIcon: + }, + { + title: "Denver Event Pass", + variant: "danger", + LeftIcon: + } + ] + }, + { + title: "Puddle Crypto", + children: [ + { + title: "American Bullfrog", + LeftIcon: ( + + ) + }, + { + title: "Wood Frog", + LeftIcon: ( + + ) + } + ] + }, + { + title: "FrogCraiglist", + children: [ + { + title: "Digital Chair Listing" + } + ] + } +]; + +export function SettingsBottomModal(): JSX.Element { + const activeBottomModal = useBottomModal(); + return ( + + + + ); +} diff --git a/apps/passport-client/package.json b/apps/passport-client/package.json index 671db198ec..c4f3bac5ce 100644 --- a/apps/passport-client/package.json +++ b/apps/passport-client/package.json @@ -16,6 +16,7 @@ }, "dependencies": { "@babel/runtime": "^7.24.0", + "@heroicons/react": "^2.1.5", "@parcnet-js/client-helpers": "^0.0.5", "@parcnet-js/client-rpc": "^0.0.4", "@parcnet-js/podspec": "^0.0.3", diff --git a/apps/passport-client/pages/index.tsx b/apps/passport-client/pages/index.tsx index 1305f693c5..28d8188387 100644 --- a/apps/passport-client/pages/index.tsx +++ b/apps/passport-client/pages/index.tsx @@ -56,19 +56,24 @@ import { GlobalBackground } from "../components/shared/AppContainer"; import { useTsParticles } from "../components/shared/useTsParticles"; +import ComponentsScreen from "../new-components/ComponentsScreen"; import { appConfig } from "../src/appConfig"; import { useIsDeletingAccount, useStateContext } from "../src/appHooks"; import { useBackgroundJobs } from "../src/backgroundJobs"; import { Action, StateContext, dispatch } from "../src/dispatch"; import { Emitter } from "../src/emitter"; +import { enableLiveReload } from "../src/liveReload"; import { loadInitialState } from "../src/loadInitialState"; import { registerServiceWorker } from "../src/registerServiceWorker"; import { AppState, StateEmitter } from "../src/state"; import { ListenMode, useZappServer } from "../src/zapp/useZappServer"; +enableLiveReload(); + function App(): JSX.Element { useBackgroundJobs(); useZappServer(ListenMode.LISTEN_IF_EMBEDDED); + const state = useStateContext().getState(); const hasStack = !!state.error?.stack; @@ -94,7 +99,7 @@ function App(): JSX.Element { } /> - } /> + } /> )} @@ -131,6 +136,9 @@ function RouterImpl(): JSX.Element { } /> } /> } /> + + } /> + } diff --git a/apps/passport-client/public/fonts/Barlow-Black.ttf b/apps/passport-client/public/fonts/Barlow-Black.ttf new file mode 100644 index 0000000000..9675b8ae4e Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-Black.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-BlackItalic.ttf b/apps/passport-client/public/fonts/Barlow-BlackItalic.ttf new file mode 100644 index 0000000000..2314595308 Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-BlackItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-Bold.ttf b/apps/passport-client/public/fonts/Barlow-Bold.ttf new file mode 100644 index 0000000000..28f2d3a578 Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-Bold.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-BoldItalic.ttf b/apps/passport-client/public/fonts/Barlow-BoldItalic.ttf new file mode 100644 index 0000000000..9dc16aded4 Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-BoldItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-ExtraBold.ttf b/apps/passport-client/public/fonts/Barlow-ExtraBold.ttf new file mode 100644 index 0000000000..22901110ff Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-ExtraBold.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-ExtraBoldItalic.ttf b/apps/passport-client/public/fonts/Barlow-ExtraBoldItalic.ttf new file mode 100644 index 0000000000..9e30cef695 Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-ExtraBoldItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-ExtraLight.ttf b/apps/passport-client/public/fonts/Barlow-ExtraLight.ttf new file mode 100644 index 0000000000..34f025145b Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-ExtraLight.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-ExtraLightItalic.ttf b/apps/passport-client/public/fonts/Barlow-ExtraLightItalic.ttf new file mode 100644 index 0000000000..14f2370f81 Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-ExtraLightItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-Italic.ttf b/apps/passport-client/public/fonts/Barlow-Italic.ttf new file mode 100644 index 0000000000..dc46deb270 Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-Italic.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-Light.ttf b/apps/passport-client/public/fonts/Barlow-Light.ttf new file mode 100644 index 0000000000..f3c5b701e5 Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-Light.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-LightItalic.ttf b/apps/passport-client/public/fonts/Barlow-LightItalic.ttf new file mode 100644 index 0000000000..bf78286892 Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-LightItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-Medium.ttf b/apps/passport-client/public/fonts/Barlow-Medium.ttf new file mode 100644 index 0000000000..11d4ab205a Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-Medium.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-MediumItalic.ttf b/apps/passport-client/public/fonts/Barlow-MediumItalic.ttf new file mode 100644 index 0000000000..62a4fb215c Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-MediumItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-Regular.ttf b/apps/passport-client/public/fonts/Barlow-Regular.ttf new file mode 100644 index 0000000000..d39c293ef2 Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-Regular.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-SemiBold.ttf b/apps/passport-client/public/fonts/Barlow-SemiBold.ttf new file mode 100644 index 0000000000..58a643058e Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-SemiBold.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-SemiBoldItalic.ttf b/apps/passport-client/public/fonts/Barlow-SemiBoldItalic.ttf new file mode 100644 index 0000000000..8cbb7bff31 Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-SemiBoldItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-Thin.ttf b/apps/passport-client/public/fonts/Barlow-Thin.ttf new file mode 100644 index 0000000000..a9d7cb9685 Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-Thin.ttf differ diff --git a/apps/passport-client/public/fonts/Barlow-ThinItalic.ttf b/apps/passport-client/public/fonts/Barlow-ThinItalic.ttf new file mode 100644 index 0000000000..8678b99717 Binary files /dev/null and b/apps/passport-client/public/fonts/Barlow-ThinItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-Black.ttf b/apps/passport-client/public/fonts/Rubik-Black.ttf new file mode 100644 index 0000000000..055ad2205d Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-Black.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-BlackItalic.ttf b/apps/passport-client/public/fonts/Rubik-BlackItalic.ttf new file mode 100644 index 0000000000..308529cba2 Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-BlackItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-Bold.ttf b/apps/passport-client/public/fonts/Rubik-Bold.ttf new file mode 100644 index 0000000000..1a9693d97f Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-Bold.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-BoldItalic.ttf b/apps/passport-client/public/fonts/Rubik-BoldItalic.ttf new file mode 100644 index 0000000000..abf760439b Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-BoldItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-ExtraBold.ttf b/apps/passport-client/public/fonts/Rubik-ExtraBold.ttf new file mode 100644 index 0000000000..3b1e190361 Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-ExtraBold.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-ExtraBoldItalic.ttf b/apps/passport-client/public/fonts/Rubik-ExtraBoldItalic.ttf new file mode 100644 index 0000000000..59cd758652 Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-ExtraBoldItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-Italic.ttf b/apps/passport-client/public/fonts/Rubik-Italic.ttf new file mode 100644 index 0000000000..1683a763ee Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-Italic.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-Light.ttf b/apps/passport-client/public/fonts/Rubik-Light.ttf new file mode 100644 index 0000000000..8a5a50ab63 Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-Light.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-LightItalic.ttf b/apps/passport-client/public/fonts/Rubik-LightItalic.ttf new file mode 100644 index 0000000000..b028d93c85 Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-LightItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-Medium.ttf b/apps/passport-client/public/fonts/Rubik-Medium.ttf new file mode 100644 index 0000000000..f0bd59588f Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-Medium.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-MediumItalic.ttf b/apps/passport-client/public/fonts/Rubik-MediumItalic.ttf new file mode 100644 index 0000000000..1a7d7f9f67 Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-MediumItalic.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-Regular.ttf b/apps/passport-client/public/fonts/Rubik-Regular.ttf new file mode 100644 index 0000000000..8b7b632f9c Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-Regular.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-SemiBold.ttf b/apps/passport-client/public/fonts/Rubik-SemiBold.ttf new file mode 100644 index 0000000000..26f657de75 Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-SemiBold.ttf differ diff --git a/apps/passport-client/public/fonts/Rubik-SemiBoldItalic.ttf b/apps/passport-client/public/fonts/Rubik-SemiBoldItalic.ttf new file mode 100644 index 0000000000..88729833c3 Binary files /dev/null and b/apps/passport-client/public/fonts/Rubik-SemiBoldItalic.ttf differ diff --git a/apps/passport-client/public/global-zupass.css b/apps/passport-client/public/global-zupass.css index 487de3a184..cc9dda9332 100644 --- a/apps/passport-client/public/global-zupass.css +++ b/apps/passport-client/public/global-zupass.css @@ -19,6 +19,26 @@ html { --black: #000000; --black-rgb: 0, 0, 0; + --text-tertiary: #8b94ac; + --text-primary: #1E2C50; + + --core-accent: #0077FF; + + --dot-bg: #ececec; + --dot-color: #e4e4e4; + --dot-size: 3px; + --dot-space: 22px; + --dot-pattern-bg: linear-gradient(90deg, + var(--dot-bg) calc(var(--dot-space) - var(--dot-size)), + transparent 1%) center / var(--dot-space) var(--dot-space), + linear-gradient(var(--dot-bg) calc(var(--dot-space) - var(--dot-size)), + transparent 1%) center / var(--dot-space) var(--dot-space), + var(--dot-color); + + --new-danger: #FF5555; + --secondary-input-bg: #EBF1F6; + + background: var(--bg-dark-primary); color: var(--white); font: @@ -37,63 +57,225 @@ a:visited { color: var(--accent-dark); text-decoration: none; } + a:hover { text-decoration: underline; cursor: pointer; } +/* Barlow */ +@font-face { + font-family: "Barlow"; + font-style: normal; + font-weight: 200; + src: url(/fonts/Barlow-ExtraLight.ttf) format("truetype") url(/fonts/Barlow-ExtraLight.woff) format("woff"); +} + +@font-face { + font-family: "Barlow"; + font-style: normal; + font-weight: 300; + src: url(/fonts/Barlow-Light.ttf) format("truetype"); +} + +@font-face { + font-family: "Barlow"; + font-style: italic; + font-weight: 300; + src: url(/fonts/Barlow-LightItalic.ttf) format("truetype"); +} + +@font-face { + font-family: "Barlow"; + font-style: normal; + font-weight: 400; + src: url(/fonts/Barlow-Regular.ttf) format("truetype"); +} + +@font-face { + font-family: "Barlow"; + font-style: normal; + font-weight: 500; + src: url(/fonts/Barlow-Medium.ttf) format("truetype"); +} + +@font-face { + font-family: "Barlow"; + font-style: normal; + font-weight: 600; + src: url(/fonts/Barlow-SemiBold.ttf) format("truetype"); +} + +@font-face { + font-family: "Barlow"; + font-style: normal; + font-weight: 700; + src: url(/fonts/Barlow-Bold.ttf) format("truetype"); +} + +@font-face { + font-family: "Barlow"; + font-style: normal; + font-weight: 800; + src: url(/fonts/Barlow-ExtraBold.ttf) format("truetype"); +} + /* IBM Plex Sans */ @font-face { font-family: "PlexSans"; font-style: normal; font-weight: 200; - src: url(/fonts/IBMPlexSans-ExtraLight.ttf) format("truetype") - url(/fonts/IBMPlexSans-ExtraLight.woff) format("woff"); + src: url(/fonts/IBMPlexSans-ExtraLight.ttf) format("truetype") url(/fonts/IBMPlexSans-ExtraLight.woff) format("woff"); } + @font-face { font-family: "PlexSans"; font-style: normal; font-weight: 300; - src: url(/fonts/IBMPlexSans-Light.ttf) format("truetype") - url(/fonts/IBMPlexSans-Light.woff) format("woff"); + src: url(/fonts/IBMPlexSans-Light.ttf) format("truetype") url(/fonts/IBMPlexSans-Light.woff) format("woff"); } + @font-face { font-family: "PlexSans"; font-style: italic; font-weight: 300; - src: url(/fonts/IBMPlexSans-LightItalic.ttf) format("truetype") - url(/fonts/IBMPlexSans-LightItalic.woff) format("woff"); + src: url(/fonts/IBMPlexSans-LightItalic.ttf) format("truetype") url(/fonts/IBMPlexSans-LightItalic.woff) format("woff"); } + @font-face { font-family: "PlexSans"; font-style: normal; font-weight: 400; - src: url(/fonts/IBMPlexSans-Regular.ttf) format("truetype") - url(/fonts/IBMPlexSans-Regular.woff) format("woff"); + src: url(/fonts/IBMPlexSans-Regular.ttf) format("truetype") url(/fonts/IBMPlexSans-Regular.woff) format("woff"); } + @font-face { font-family: "PlexSans"; font-style: normal; font-weight: 500; - src: url(/fonts/IBMPlexSans-Medium.ttf) format("truetype") - url(/fonts/IBMPlexSans-Medium.woff) format("woff"); + src: url(/fonts/IBMPlexSans-Medium.ttf) format("truetype") url(/fonts/IBMPlexSans-Medium.woff) format("woff"); } + @font-face { font-family: "PlexSans"; font-style: normal; font-weight: 600; - src: url(/fonts/IBMPlexSans-SemiBold.ttf) format("truetype") - url(/fonts/IBMPlexSans-SemiBold.woff) format("woff"); + src: url(/fonts/IBMPlexSans-SemiBold.ttf) format("truetype") url(/fonts/IBMPlexSans-SemiBold.woff) format("woff"); } + @font-face { font-family: "SuperFunky"; src: url(/fonts/SuperFunky.ttf) format("truetype"); } + @font-face { font-family: "PressStart2P"; src: url(/fonts/PressStart2P.ttf) format("truetype"); } + +/* Rubik */ + +@font-face { + font-family: "Rubik"; + font-style: normal; + font-weight: 300; + src: url(/fonts/Rubik-Light.ttf) format("truetype"); +} + + +@font-face { + font-family: "Rubik"; + font-style: italic; + font-weight: 300; + src: url(/fonts/Rubik-SemiBoldItaic.ttf) format("truetype"); +} + +@font-face { + font-family: "Rubik"; + font-style: italic; + font-weight: 300; + src: url(/fonts/Rubik-Itaic.ttf) format("truetype"); +} + + +@font-face { + font-family: "Rubik"; + font-style: italic; + font-weight: 300; + src: url(/fonts/Rubik-LightItalic.ttf) format("truetype"); +} + +@font-face { + font-family: "Rubik"; + font-style: normal; + font-weight: 400; + src: url(/fonts/Rubik-Regular.ttf) format("truetype"); +} + +@font-face { + font-family: "Rubik"; + font-style: italic; + font-weight: 500; + src: url(/fonts/Rubik-MediumItalic.ttf) format("truetype"); +} + +@font-face { + font-family: "Rubik"; + font-style: normal; + font-weight: 500; + src: url(/fonts/Rubik-Medium.ttf) format("truetype"); +} + +@font-face { + font-family: "Rubik"; + font-style: normal; + font-weight: 600; + src: url(/fonts/Rubik-SemiBold.ttf) format("truetype"); +} + +@font-face { + font-family: "Rubik"; + font-style: italic; + font-weight: 700; + src: url(/fonts/Rubik-BoldItalic.ttf) format("truetype"); +} + +@font-face { + font-family: "Rubik"; + font-style: normal; + font-weight: 700; + src: url(/fonts/Rubik-Bold.ttf) format("truetype"); +} + +@font-face { + font-family: "Rubik"; + font-style: italic; + font-weight: 800; + src: url(/fonts/Rubik-ExtraBoldItalic.ttf) format("truetype"); +} + +@font-face { + font-family: "Rubik"; + font-style: normal; + font-weight: 800; + src: url(/fonts/Rubik-ExtraBold.ttf) format("truetype"); +} + +@font-face { + font-family: "Rubik"; + font-style: italic; + font-weight: 800; + src: url(/fonts/Rubik-BlackItalic.ttf) format("truetype"); +} + +@font-face { + font-family: "Rubik"; + font-style: normal; + font-weight: 800; + src: url(/fonts/Rubik-Black.ttf) format("truetype"); +} + /*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */ html, body, @@ -121,6 +303,7 @@ h6 { margin: 0; padding: 0; } + h1, h2, h3, @@ -130,34 +313,42 @@ h6 { font-size: 100%; font-weight: normal; } + ul { list-style: none; } + button, input, select { margin: 0; } + html { box-sizing: border-box; } + *, *::before, *::after { box-sizing: inherit; } + img, video { height: auto; max-width: 100%; } + iframe { border: 0; } + table { border-collapse: collapse; border-spacing: 0; } + td, th { padding: 0; @@ -197,14 +388,16 @@ img { width: 80px; height: 80px; } -.loader > div { + +.loader>div { position: absolute; border: 4px solid var(--accent-dark); opacity: 1; border-radius: 50%; animation: ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite; } -.loader > div:nth-child(2) { + +.loader>div:nth-child(2) { animation-delay: -0.5s; } @@ -216,6 +409,7 @@ img { height: 0; opacity: 0; } + 4.9% { top: 36px; left: 36px; @@ -223,6 +417,7 @@ img { height: 0; opacity: 0; } + 5% { top: 36px; left: 36px; @@ -230,6 +425,7 @@ img { height: 0; opacity: 1; } + 100% { top: 0px; left: 0px; diff --git a/apps/passport-client/public/index.hbs b/apps/passport-client/public/index.hbs index 08175f5e3d..9e4fb0c5e7 100644 --- a/apps/passport-client/public/index.hbs +++ b/apps/passport-client/public/index.hbs @@ -26,6 +26,27 @@ type="font/woff" crossorigin="anonymous" /> + + + {{!-- Lazily load zxcvbn.js since it contains 700KB+ of data --}} diff --git a/apps/passport-client/src/appHooks.ts b/apps/passport-client/src/appHooks.ts index 00868c28c4..6006554af2 100644 --- a/apps/passport-client/src/appHooks.ts +++ b/apps/passport-client/src/appHooks.ts @@ -162,6 +162,10 @@ export function useModal(): AppState["modal"] { return useSelector((s) => s.modal, []); } +export function useBottomModal(): AppState["modal"] { + return useSelector((s) => s.bottomModal, []); +} + export function useSyncKey(): string | undefined { return useSelector((s) => s.encryptionKey, []); } diff --git a/apps/passport-client/src/dispatch.ts b/apps/passport-client/src/dispatch.ts index da94d2fb38..a6d6ce223b 100644 --- a/apps/passport-client/src/dispatch.ts +++ b/apps/passport-client/src/dispatch.ts @@ -115,6 +115,10 @@ export type Action = type: "set-modal"; modal: AppState["modal"]; } + | { + type: "set-bottom-modal"; + modal: AppState["bottomModal"]; + } | { type: "error"; error: AppError; @@ -256,6 +260,10 @@ export async function dispatch( return update({ modal: action.modal }); + case "set-bottom-modal": + return update({ + bottomModal: action.modal + }); case "password-change-on-other-tab": return handlePasswordChangeOnOtherTab(update); case "change-password": diff --git a/apps/passport-client/src/liveReload.ts b/apps/passport-client/src/liveReload.ts new file mode 100644 index 0000000000..f731ef8c21 --- /dev/null +++ b/apps/passport-client/src/liveReload.ts @@ -0,0 +1,10 @@ +import { appConfig } from "./appConfig"; + +// Implement fe part for esbuild live reload - this does not preserve the js state https://esbuild.github.io/api/#live-reload +export function enableLiveReload(): void { + if (appConfig.devMode) { + new EventSource("/esbuild").addEventListener("change", () => { + location.reload(); + }); + } +} diff --git a/apps/passport-client/src/loadInitialState.ts b/apps/passport-client/src/loadInitialState.ts index 0fc525ea4c..2be4ae6ecd 100644 --- a/apps/passport-client/src/loadInitialState.ts +++ b/apps/passport-client/src/loadInitialState.ts @@ -60,6 +60,7 @@ export async function loadInitialState(): Promise { pcds, identityV3, modal, + bottomModal: { modalType: "none" }, subscriptions, resolvingSubscriptionId: undefined, credentialCache, diff --git a/apps/passport-client/src/state.ts b/apps/passport-client/src/state.ts index 5e20fc2c3c..4f2ab7cc4c 100644 --- a/apps/passport-client/src/state.ts +++ b/apps/passport-client/src/state.ts @@ -24,6 +24,9 @@ export interface AppState { encryptionKey?: string; credentialCache: CredentialCache; + // bottom modal will deprecate modal + bottomModal: { modalType: "settings" } | { modalType: "none" }; + // View state modal: | { modalType: "info" } diff --git a/apps/passport-client/src/worker/service-worker.ts b/apps/passport-client/src/worker/service-worker.ts index 40ece1bd98..743c36da51 100644 --- a/apps/passport-client/src/worker/service-worker.ts +++ b/apps/passport-client/src/worker/service-worker.ts @@ -61,6 +61,14 @@ const STABLE_CACHE_RESOURCES = new Set([ "/semaphore-artifacts/16.zkey", "/artifacts/zk-eddsa-event-ticket-pcd/circuit.wasm", "/artifacts/zk-eddsa-event-ticket-pcd/circuit.zkey", + "/fonts/Barlow-ExtraLight.ttf", + "/fonts/Barlow-Light.ttf", + "/fonts/Barlow-LightItalic.ttf", + "/fonts/Barlow-Regular.ttf", + "/fonts/Barlow-Medium.ttf", + "/fonts/Barlow-SemiBold.ttf", + "/fonts/Barlow-Bold.ttf", + "/fonts/Barlow-ExtraBold.ttf", "/fonts/IBMPlexSans-ExtraLight.woff", "/fonts/IBMPlexSans-Light.woff", "/fonts/IBMPlexSans-LightItalic.woff", @@ -83,7 +91,21 @@ const STABLE_CACHE_RESOURCES = new Set([ "/images/social.webp", "/images/star.webp", "/images/wristband.webp", - "/zxcvbn.js" + "/zxcvbn.js", + "fonts/Rubik-Black.ttf", + "fonts/Rubik-BlackItalic.ttf", + "fonts/Rubik-Bold.ttf", + "fonts/Rubik-BoldItalic.ttf", + "fonts/Rubik-ExtraBold.ttf", + "fonts/Rubik-ExtraBoldItalic.ttf", + "fonts/Rubik-Italic.ttf", + "fonts/Rubik-Light.ttf", + "fonts/Rubik-LightItalic.ttf", + "fonts/Rubik-Medium.ttf", + "fonts/Rubik-MediumItalic.ttf", + "fonts/Rubik-Regular.ttf", + "fonts/Rubik-SemiBold.ttf", + "fonts/Rubik-SemiBoldItalic.ttf" ]); /** diff --git a/yarn.lock b/yarn.lock index b0c94eeb4b..6d1aad63fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3591,6 +3591,11 @@ resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.1.3.tgz#78a2a7f504a7370283d07eabcddc7fec04f503db" integrity sha512-fEcPfo4oN345SoqdlCDdSa4ivjaKbk0jTd+oubcgNxnNgAfzysfwWfQUr+51wigiWHQQRiZNd1Ao0M5Y3M2EGg== +"@heroicons/react@^2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.1.5.tgz#1e13f34976cc542deae92353c01c8b3d7942e9ba" + integrity sha512-FuzFN+BsHa+7OxbvAERtgBTNeZpUjgM/MIizfVkSCL2/edriN0Hx/DWRCR//aPYwO5QX/YlgLGXk+E3PcfZwjA== + "@hexagon/base64@^1.1.25": version "1.1.27" resolved "https://registry.yarnpkg.com/@hexagon/base64/-/base64-1.1.27.tgz#f145fbb6242fe7d997b43dbadfa241567c279f79" @@ -20280,16 +20285,7 @@ string-template@~0.2.1: resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" integrity sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -20422,14 +20418,7 @@ stringify-entities@^4.0.0: character-entities-html4 "^2.0.0" character-entities-legacy "^3.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -22838,7 +22827,7 @@ workspace-tools@^0.36.4: js-yaml "^4.1.0" micromatch "^4.0.0" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -22856,15 +22845,6 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"