diff --git a/src/components/attendee/AttendeeHeader/AttendeeHeader.module.scss b/src/components/attendee/AttendeeHeader/AttendeeHeader.module.scss index d1544880d9..426abdf471 100644 --- a/src/components/attendee/AttendeeHeader/AttendeeHeader.module.scss +++ b/src/components/attendee/AttendeeHeader/AttendeeHeader.module.scss @@ -6,6 +6,7 @@ // These is module private. $-z-index--header: layer.level(layer.$z-index--header); +$h-logo-image: 42px; .attendeeHeader { display: flex; @@ -84,3 +85,7 @@ $-z-index--header: layer.level(layer.$z-index--header); .blur { filter: blur(100px) contrast(60%) opacity(0); } + +.logoImage { + height: $h-logo-image; +} diff --git a/src/components/attendee/AttendeeHeader/AttendeeHeader.tsx b/src/components/attendee/AttendeeHeader/AttendeeHeader.tsx index 04eb69f5af..f9322f1a2c 100644 --- a/src/components/attendee/AttendeeHeader/AttendeeHeader.tsx +++ b/src/components/attendee/AttendeeHeader/AttendeeHeader.tsx @@ -20,6 +20,8 @@ import { useLiveUser } from "hooks/user/useLiveUser"; import { useShowHide } from "hooks/useShowHide"; import { useMediaQuery } from "hooks/viewport/useMediaQuery"; +import sparkleLogoImage from "assets/images/sparkle-header.png"; + import CN from "./AttendeeHeader.module.scss"; type HeaderTab = "schedule" | "search" | "profile"; @@ -33,11 +35,13 @@ const tabCaptions: Readonly> = { interface AttendeeHeaderProps { backButtonSpace?: BaseVenue; isBannerOn?: boolean; + hasLogo?: boolean; } export const AttendeeHeader: React.FC = ({ backButtonSpace, isBannerOn, + hasLogo, }) => { const { isShown, hide, show } = useShowHide(false); const [overlayLabel, setOverlayLabel] = useState(""); @@ -109,28 +113,43 @@ export const AttendeeHeader: React.FC = ({ <>
- {backButtonSpace ? ( - + {hasLogo ? ( + sparkle-logo ) : ( - + <> + {backButtonSpace ? ( + + ) : ( + + )} + {!isLaptopSmall && space && } + )} - {!isLaptopSmall && space && } +
{renderedCaptions}
diff --git a/src/components/attendee/ProfileOverlay/ProfileOverlay.tsx b/src/components/attendee/ProfileOverlay/ProfileOverlay.tsx index deb3973d8d..07c743d0c2 100644 --- a/src/components/attendee/ProfileOverlay/ProfileOverlay.tsx +++ b/src/components/attendee/ProfileOverlay/ProfileOverlay.tsx @@ -149,25 +149,32 @@ export const ProfileOverlay: React.FC = ({ const validLinks = data.profileLinks?.filter( (link) => link.url && link.title !== "" ); + const requestDto = { ...data, - profileLinks: data.profileLinks?.filter( - (link) => link.url && link.title !== "" - ), + ...(validLinks?.length && { profileLinks: validLinks }), }; - await updateUserProfile(firebaseUser.uid, requestDto); + await updateUserProfile(firebaseUser.uid, requestDto); reset({ ...data, oldPassword: "", newPassword: "", confirmNewPassword: "", - profileLinks: validLinks, + profileLinks: validLinks || values.profileLinks, }); setSuccess(true); } }, - [firebaseUser, dirtyFields, checkOldPassword, setError, clearErrors, reset] + [ + firebaseUser, + dirtyFields, + checkOldPassword, + setError, + clearErrors, + reset, + values.profileLinks, + ] ); const history = useHistory(); diff --git a/src/components/attendee/SplashSpace/SplashSpace.module.scss b/src/components/attendee/SplashSpace/SplashSpace.module.scss index 76e7f51703..fd94afa4fe 100644 --- a/src/components/attendee/SplashSpace/SplashSpace.module.scss +++ b/src/components/attendee/SplashSpace/SplashSpace.module.scss @@ -1,6 +1,110 @@ +@use "scss/attendee/theme"; +@use "scss/attendee/space"; +@use "scss/attendee/border"; +@use "scss/attendee/effects/sparkle"; + +$h-logo-image: 42px; +$w-enter-button: 150px; + +.splashWrapper { + height: 100%; + + header { + width: 99%; + } +} + .Container { display: flex; - flex-flow: column; + flex-direction: column; + position: absolute; + top: 50%; /* position the top edge of the element at the middle of the parent */ + left: 50%; /* position the left edge of the element at the middle of the parent */ + + transform: translate(-50%, -50%); + height: 340px; + + svg { + margin-right: space.gap(2); + } +} + +.wrapper { + display: flex; + align-items: center; + box-sizing: border-box; + height: 270px; + width: 800px; + background: theme.$c-splash-background-color; + border: border.$width--slim solid theme.$sparkle--border; + backdrop-filter: blur(sparkle.$blur--lg); + /* Note: backdrop-filter has minimal browser support */ + + border-radius: border.$radius--xs; +} + +.AttendeeHeader { + padding: space.empty(1) 0; +} + +.spaceInfo { + height: 100%; + min-width: 200px; + width: 200px; + padding: space.empty(1) 0; + display: flex; + flex-direction: column; justify-content: center; + text-align: center; + margin-left: space.empty(1); +} + +.divider { + border: 1px solid rgba(130, 130, 130, 0.3); + height: 90%; + margin: 0 space.empty(1); +} + +.contentWrapper { + display: flex; + flex-direction: column; align-items: center; + justify-content: center; + width: 100%; + + div { + margin: space.empty(1) 0; + } +} + +.actionWrapper { + width: 100%; + + button { + margin: auto; + width: $w-enter-button; + display: flex; + justify-content: center; + } +} + +a { + &:visited { + text-decoration: none; + color: theme.$c-dark-text; + } +} + +.backButton { + margin: space.empty(1) 0; + align-self: flex-start; +} + +.logoImage { + height: $h-logo-image; + margin: space.empty(1); +} + +.authDivider { + margin: 0 space.empty(0.5); } diff --git a/src/components/attendee/SplashSpace/SplashSpace.tsx b/src/components/attendee/SplashSpace/SplashSpace.tsx index 57705c5a8a..5837afdeb5 100644 --- a/src/components/attendee/SplashSpace/SplashSpace.tsx +++ b/src/components/attendee/SplashSpace/SplashSpace.tsx @@ -1,25 +1,35 @@ -import React, { useEffect } from "react"; -import { useHistory } from "react-router-dom"; -import { useSearchParam } from "react-use"; +import React, { useEffect, useMemo } from "react"; +import { Link, useHistory } from "react-router-dom"; +import { useCss, useSearchParam } from "react-use"; +import { faArrowLeft } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Button } from "components/attendee/Button"; import { ATTENDEE_SPACE_URL, ATTENDEE_WORLD_SPLASH_URL, + DEFAULT_BACKGROUNDS, JOIN_WORLD_URL, QUICK_JOIN_PARAM_NAME, RETURN_URL_PARAM_NAME, SIGN_IN_URL, SIGN_UP_URL, + STRING_SPACE, } from "settings"; import { SpaceWithId, WorldWithId } from "types/id"; +import { isDefined } from "utils/types"; import { generateUrl } from "utils/url"; +import { usePreloadAssets } from "hooks/usePreloadAssets"; import { useLiveUser } from "hooks/user/useLiveUser"; import { useOnboardingDetails } from "hooks/user/useOnboardingDetails"; +import { AttendeeHeader } from "../AttendeeHeader"; + +import sparkleLogoImage from "assets/images/sparkle-header.png"; + import styles from "./SplashSpace.module.scss"; type SplashSpaceProps = { @@ -112,21 +122,74 @@ export const SplashSpace: React.FC = ({ space, world }) => { const buttonText = isOnboarded ? "Enter" : "Join"; + const [assetsToPreload] = useMemo( + () => + [space?.mapBackgroundImageUrl].filter(isDefined).map((url) => ({ url })), + [space] + ); + + usePreloadAssets([assetsToPreload]); + + const { url } = assetsToPreload ?? {}; + const [defaultBackground] = DEFAULT_BACKGROUNDS; + + const mapStyles = useCss({ + backgroundImage: `url(${url || defaultBackground})`, + }); + return ( -
-

Space splash page!

- -

{space.name}

-

{space.config?.landingPageConfig.description}

- - - - {!userId && ( -
- - -
+
+ {userId ? ( + + ) : ( + sparkle-logo )} +
+ {userId && ( + + )} +
+
+

{space.name}

+

{space.config?.landingPageConfig.description}

+
+
+
+
+ {space.name} is part of {world.name} +
+
+ +
+ {!userId && ( +
+ You also need a Sparkle id to join. + {STRING_SPACE} + + Sign Up + + or + + Login + +
+ )} +
+
+
); }; diff --git a/src/components/attendee/SplashWorld/SplashWorld.module.scss b/src/components/attendee/SplashWorld/SplashWorld.module.scss index 76e7f51703..c715984efb 100644 --- a/src/components/attendee/SplashWorld/SplashWorld.module.scss +++ b/src/components/attendee/SplashWorld/SplashWorld.module.scss @@ -1,6 +1,85 @@ +@use "scss/attendee/theme"; +@use "scss/attendee/space"; +@use "scss/attendee/border"; +@use "scss/attendee/effects/sparkle"; + +$h-logo-image: 42px; +$w-enter-button: 150px; + +.splashWrapper { + height: 100%; + + header { + width: 99%; + } +} + .Container { display: flex; - flex-flow: column; - justify-content: center; + flex-direction: column; + position: absolute; + top: 50%; /* position the top edge of the element at the middle of the parent */ + left: 50%; /* position the left edge of the element at the middle of the parent */ + background: theme.$c-splash-background-color; + border: border.$width--slim solid theme.$sparkle--border; + backdrop-filter: blur(sparkle.$blur--lg); + transform: translate(-50%, -50%); + border-radius: border.$radius--xs; + + svg { + margin-right: space.gap(2); + } +} + +.AttendeeHeader { + padding: space.empty(1) 0; +} + +.contentWrapper { + display: flex; + flex-direction: column; align-items: center; + justify-content: center; + padding: space.empty(2); + text-align: center; + + div { + margin: space.empty(1) 0; + } + + h3 { + padding: 0 space.empty(2); + } +} + +.actionWrapper { + width: 100%; + + button { + display: flex; + justify-content: center; + margin: auto; + width: $w-enter-button; + } +} + +a { + &:visited { + text-decoration: none; + color: theme.$c-dark-text; + } +} + +.backButton { + margin: space.empty(1) 0; + align-self: flex-start; +} + +.logoImage { + height: $h-logo-image; + margin: space.empty(1); +} + +.authDivider { + margin: 0 space.empty(0.5); } diff --git a/src/components/attendee/SplashWorld/SplashWorld.tsx b/src/components/attendee/SplashWorld/SplashWorld.tsx index e05267502a..1f4f9122f5 100644 --- a/src/components/attendee/SplashWorld/SplashWorld.tsx +++ b/src/components/attendee/SplashWorld/SplashWorld.tsx @@ -1,24 +1,32 @@ -import React, { useEffect } from "react"; -import { useHistory } from "react-router-dom"; -import { useSearchParam } from "react-use"; +import React, { useEffect, useMemo } from "react"; +import { Link, useHistory } from "react-router-dom"; +import { useCss, useSearchParam } from "react-use"; import { Button } from "components/attendee/Button"; import { ATTENDEE_SPACE_URL, + DEFAULT_BACKGROUNDS, JOIN_WORLD_URL, QUICK_JOIN_PARAM_NAME, RETURN_URL_PARAM_NAME, SIGN_IN_URL, SIGN_UP_URL, + STRING_SPACE, } from "settings"; import { WorldWithId } from "types/id"; +import { isDefined } from "utils/types"; import { generateUrl } from "utils/url"; +import { usePreloadAssets } from "hooks/usePreloadAssets"; import { useLiveUser } from "hooks/user/useLiveUser"; import { useOnboardingDetails } from "hooks/user/useOnboardingDetails"; +import { AttendeeHeader } from "../AttendeeHeader"; + +import sparkleLogoImage from "assets/images/sparkle-header.png"; + import styles from "./SplashWorld.module.scss"; type SplashWorldProps = { @@ -27,11 +35,10 @@ type SplashWorldProps = { export const SplashWorld: React.FC = ({ world }) => { const { userId } = useLiveUser(); + const worldHomeSpace = world.defaultSpaceSlug; const history = useHistory(); - const worldHomeSpace = world.defaultSpaceSlug; - const { onboardingDetails } = useOnboardingDetails({ worldId: world.id, userId, @@ -39,13 +46,6 @@ export const SplashWorld: React.FC = ({ world }) => { const isOnboarded = onboardingDetails?.isOnboarded; - const navigateToSignIn = () => { - history.push({ - pathname: SIGN_IN_URL, - search: `?${RETURN_URL_PARAM_NAME}=${history.location.pathname}`, - }); - }; - const quickJoinWorld = () => { history.push({ pathname: SIGN_IN_URL, @@ -89,6 +89,13 @@ export const SplashWorld: React.FC = ({ world }) => { return navigateToSpace(); }; + const navigateToSignIn = () => { + history.push({ + pathname: SIGN_IN_URL, + search: `?${RETURN_URL_PARAM_NAME}=${history.location.pathname}`, + }); + }; + const navigateToSignUp = () => { history.push({ pathname: SIGN_UP_URL, @@ -104,27 +111,60 @@ export const SplashWorld: React.FC = ({ world }) => { navigateToSpace(); }); - const hasHomeSpace = !!worldHomeSpace; - const buttonText = isOnboarded ? "Enter" : "Join"; + const [assetsToPreload] = useMemo( + () => + [world?.config?.landingPageConfig?.coverImageUrl] + .filter(isDefined) + .map((url) => ({ url })), + [world?.config?.landingPageConfig?.coverImageUrl] + ); + + usePreloadAssets([assetsToPreload]); + + const { url } = assetsToPreload ?? {}; + const [defaultBackground] = DEFAULT_BACKGROUNDS; + + const mapStyles = useCss({ + backgroundImage: `url(${url || defaultBackground})`, + }); + return ( -
-

World splash page!

-

{world.name}

-

{world.config.landingPageConfig.description}

- - {!hasHomeSpace &&

No home space was specified!

} - - - {!userId && ( -
- - -
+
+ {userId ? ( + + ) : ( + sparkle-logo )} +
+
+

{world.name}

+

{world.config?.landingPageConfig.description}

+
+ +
+ {!userId && ( +
+ You also need a Sparkle id to join. + {STRING_SPACE} + + Sign Up + + or + + Login + +
+ )} +
+
); }; diff --git a/src/core/AppRouter/AppRouter.tsx b/src/core/AppRouter/AppRouter.tsx index bb062f89ec..e20cc98e2b 100644 --- a/src/core/AppRouter/AppRouter.tsx +++ b/src/core/AppRouter/AppRouter.tsx @@ -143,7 +143,9 @@ export const AppRouter: React.FC = () => ( - + + + {/* If not Signed in / profile filled / onboarded redirect to splash page */} diff --git a/src/index.scss b/src/index.scss index 8ecd1c74ea..92d0314e30 100644 --- a/src/index.scss +++ b/src/index.scss @@ -1,6 +1,12 @@ // THIS FILE IS FOR RARE CASES OF GLOBALLY SHARED RESOURCES // PLEASE EXPLORE OTHER OPTIONS BEFORE ADDING TO IT +html, +body, +#root { + height: 100%; +} + @font-face { font-family: "Sparkle"; font-style: normal; diff --git a/src/pages/VenuePage/VenuePage.tsx b/src/pages/VenuePage/VenuePage.tsx index 371d494e2b..71abea8092 100644 --- a/src/pages/VenuePage/VenuePage.tsx +++ b/src/pages/VenuePage/VenuePage.tsx @@ -63,7 +63,7 @@ type VenuePageProps = SpaceSlugLocation & { userId?: UserId; profile?: Profile; userLocation?: UserLocation; - setBackButtonSpace: React.Dispatch< + setBackButtonSpace?: React.Dispatch< React.SetStateAction >; }; @@ -79,7 +79,7 @@ export const VenuePage: React.FC = ({ userId, profile, userLocation, - setBackButtonSpace, + setBackButtonSpace = () => {}, }) => { const analytics = useAnalytics({ venue: space }); diff --git a/src/scss/attendee/theme.scss b/src/scss/attendee/theme.scss index afc491e231..0c718e72f2 100644 --- a/src/scss/attendee/theme.scss +++ b/src/scss/attendee/theme.scss @@ -144,4 +144,6 @@ $c-tuner-radio-button-background: rgba(255, 255, 255, 0.16); $c-tuner-radio-button-border: rgba(255, 255, 255, 0.4); $c-tuner-divider-color: rgba(255, 255, 255, 0.14); +$c-splash-background-color: rgba(255, 255, 255, 0.7); + $disabled-opacity: 0.4;