Skip to content

Commit

Permalink
Merge pull request #2 from MystenLabs/APPS-redirect
Browse files Browse the repository at this point in the history
add redirect preference save
  • Loading branch information
plam-ml authored Apr 6, 2024
2 parents 9557c5e + 47c1db0 commit 23c3eca
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 37 deletions.
1 change: 1 addition & 0 deletions apps/core/tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ export default {
17: '4.25rem',
18: '4.5rem',
19: '4.75rem',
25: '6.25rem',
50: '12.5rem',
verticalListShort: '13.0625rem',
verticalListLong: '35.6875rem',
Expand Down
1 change: 1 addition & 0 deletions apps/explorer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@mysten/icons": "workspace:*",
"@mysten/sui.js": "^0.51.2",
"@mysten/ui": "workspace:*",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-collapsible": "^1.0.3",
"@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-popover": "^1.0.6",
Expand Down
45 changes: 45 additions & 0 deletions apps/explorer/src/components/CheckboxRedirectPreference.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {Checkbox} from "~/ui/Checkbox";
import {useLocalStorage} from "@mysten/core";

export enum RedirectExplorer {
SUISCAN = 'suiscan',
SUIVISION = 'suivision',
}

export function usePreference() {
const [checked, setChecked] = useLocalStorage<boolean>(
'is-explorer-preference-checked',
true,
);

const [preference, setPreference] = useLocalStorage<RedirectExplorer | undefined>(
'explorer-preference',
undefined,
);

return {
checked,
setChecked,
preference,
setPreference,
};
}

export function CheckboxRedirectPreference() {
const {
checked,
setChecked,
} = usePreference();

return (
<Checkbox
checked={checked}
onCheckedChange={(isChecked) => {
setChecked(!!isChecked);
}}
id="explorer-reference"
label="Remember my explorer preference"
className="justify-center"
/>
)
}
103 changes: 66 additions & 37 deletions apps/explorer/src/components/Layout/PageLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,28 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { useFeatureIsOn } from '@growthbook/growthbook-react';
import { useAppsBackend, useElementDimensions, useLocalStorage } from '@mysten/core';
import { Heading, LoadingIndicator, Text } from '@mysten/ui';
import { useQuery } from '@tanstack/react-query';
import {useFeatureIsOn} from '@growthbook/growthbook-react';
import {useAppsBackend, useElementDimensions, useLocalStorage} from '@mysten/core';
import {Heading, LoadingIndicator, Text} from '@mysten/ui';
import {useQuery} from '@tanstack/react-query';
import clsx from 'clsx';
import { type ReactNode, useEffect, useRef } from 'react';
import {type ReactNode, useEffect, useRef} from 'react';

import Footer from '../footer/Footer';
import Header from '../header/Header';
import { useNetworkContext } from '~/context';
import { Banner } from '~/ui/Banner';
import { Network } from '~/utils/api/DefaultRpcClient';
import {useNetworkContext} from '~/context';
import {Banner} from '~/ui/Banner';
import {Network} from '~/utils/api/DefaultRpcClient';
import suiscanImg from '~/assets/explorer-suiscan.jpg';
import suivisionImg from '~/assets/explorer-suivision.jpg';
import suiscanImg2x from '~/assets/[email protected]';
import suivisionImg2x from '~/assets/[email protected]';
import { ButtonOrLink } from '~/ui/utils/ButtonOrLink';
import { Image } from '~/ui/image/Image';
import { ArrowRight12, Sui, SuiLogoTxt } from '@mysten/icons';
import { useRedirectExplorerUrl } from '~/hooks/useRedirectExplorerUrl';
import { ampli } from '~/utils/analytics/ampli';

enum RedirectExplorer {
SUISCAN = 'suiscan',
SUIVISION = 'suivision',
}
import {ButtonOrLink} from '~/ui/utils/ButtonOrLink';
import {Image} from '~/ui/image/Image';
import {ArrowRight12, Sui, SuiLogoTxt} from '@mysten/icons';
import {useRedirectExplorerUrl} from '~/hooks/useRedirectExplorerUrl';
import {ampli} from '~/utils/analytics/ampli';
import {CheckboxRedirectPreference, RedirectExplorer, usePreference} from "~/components/CheckboxRedirectPreference";

export type PageLayoutProps = {
gradient?: {
Expand Down Expand Up @@ -59,6 +55,11 @@ function useRedirectExplorerOrder() {

function ImageLink({ type }: { type: RedirectExplorer }) {
const { suiscanUrl, suivisionUrl } = useRedirectExplorerUrl();
const {
checked,
preference,
setPreference,
} = usePreference();

const href = type === RedirectExplorer.SUISCAN ? suiscanUrl : suivisionUrl;
const src = type === RedirectExplorer.SUISCAN ? suiscanImg : suivisionImg;
Expand All @@ -67,15 +68,20 @@ function ImageLink({ type }: { type: RedirectExplorer }) {
? `${suiscanImg} 1x, ${suiscanImg2x} 2x`
: `${suivisionImg} 1x, ${suivisionImg2x} 2x`;

const handleRedirect = () => {
if (checked && !preference) {
setPreference(type);
}
ampli.redirectToExternalExplorer({
name: type,
url: href,
});
}

return (
<div className="relative overflow-hidden rounded-3xl border border-gray-45 transition duration-300 ease-in-out hover:shadow-lg">
<ButtonOrLink
onClick={() => {
ampli.redirectToExternalExplorer({
name: type,
url: href,
});
}}
onClick={handleRedirect}
href={href}
target="_blank"
rel="noopener noreferrer"
Expand All @@ -85,12 +91,7 @@ function ImageLink({ type }: { type: RedirectExplorer }) {
<div className="absolute bottom-10 left-1/2 right-0 flex -translate-x-1/2 whitespace-nowrap">
<ButtonOrLink
className="flex w-full items-center justify-center gap-2 rounded-3xl bg-sui-dark px-3 py-2"
onClick={() => {
ampli.redirectToExternalExplorer({
name: type,
url: href,
});
}}
onClick={handleRedirect}
href={href}
target="_blank"
rel="noopener noreferrer"
Expand All @@ -106,19 +107,44 @@ function ImageLink({ type }: { type: RedirectExplorer }) {
}

function RedirectContent() {
const { suiscanUrl, suivisionUrl } = useRedirectExplorerUrl();
const redirectExplorers = useRedirectExplorerOrder();
const {
checked,
preference,
} = usePreference();

useEffect(() => {
if (checked && preference) {
const redirectUrl = preference === RedirectExplorer.SUISCAN ? suiscanUrl : suivisionUrl;
ampli.redirectToExternalExplorer({
name: preference,
url: redirectUrl,
});
window.location.href = redirectUrl;
}
}, [checked, preference, suiscanUrl, suivisionUrl]);

return (
<section className="flex flex-col justify-center gap-10 sm:flex-row">
{redirectExplorers.map((type) => (
<ImageLink key={type} type={type} />
))}
<section className="flex flex-col gap-10">
<CheckboxRedirectPreference />

<div className="flex flex-col justify-center gap-10 sm:flex-row">
{redirectExplorers.map((type) => (
<ImageLink key={type} type={type} />
))}
</div>
</section>
);
}

function HeaderLink({ type }: { type: RedirectExplorer }) {
const { suiscanUrl, suivisionUrl } = useRedirectExplorerUrl();
const {
checked,
preference,
setPreference,
} = usePreference();
const href = type === RedirectExplorer.SUISCAN ? suiscanUrl : suivisionUrl;
const openWithLabel =
type === RedirectExplorer.SUISCAN ? 'Open on Suiscan.xyz' : 'Open on Suivision.xyz';
Expand All @@ -129,6 +155,9 @@ function HeaderLink({ type }: { type: RedirectExplorer }) {
target="_blank"
className="flex items-center gap-2 border-b border-gray-100 py-1 text-heading5 font-semibold"
onClick={() => {
if (checked && !preference) {
setPreference(type);
}
ampli.redirectToExternalExplorer({
name: type,
url: href,
Expand All @@ -146,7 +175,7 @@ export function RedirectHeader() {

return (
<section
className="flex flex-col items-center justify-center gap-5 px-5 py-12 text-center sm:mb-20"
className="flex flex-col items-center justify-center gap-5 px-5 py-12 text-center"
style={{
background: 'linear-gradient(159deg, #FAF8D2 50.65%, #F7DFD5 86.82%)',
}}
Expand All @@ -168,7 +197,7 @@ export function RedirectHeader() {
</div>
</div>
) : (
<Heading variant="heading3/semibold">Experience two amazing explorers on Sui!</Heading>
<Heading variant="heading3/semibold">Choose your preferred explorer on Sui</Heading>
)}
</section>
);
Expand Down Expand Up @@ -252,7 +281,7 @@ export function PageLayout({ gradient, content, loading, isError }: PageLayoutPr
</section>
) : null}
{!loading && (
<section className="mx-auto max-w-[1440px] p-5 pb-20 sm:py-8 md:p-10 md:pb-20">
<section className="mx-auto max-w-[1440px] px-5 pb-20 pt-10 sm:py-8 md:p-10 md:pb-25">
{enableExplorerRedirect ? <RedirectContent /> : content}
</section>
)}
Expand Down
2 changes: 2 additions & 0 deletions apps/explorer/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { ValidatorDetails } from './validator/ValidatorDetails';
import { ValidatorPageResult } from './validators/Validators';
import { Layout } from '~/components/Layout';
import { IdPage } from '~/pages/id-page';
import {Preference} from "~/pages/preference";

function RedirectWithId({ base }: { base: string }) {
const params = useParams();
Expand All @@ -40,6 +41,7 @@ export const router = sentryCreateBrowserRouter([
{ path: 'validators', element: <ValidatorPageResult /> },
{ path: 'validator/:id', element: <ValidatorDetails /> },
{ path: 'experimental--id/:id', element: <IdPage /> },
{ path: 'redirect-preference', element: <Preference />}
],
},
{
Expand Down
19 changes: 19 additions & 0 deletions apps/explorer/src/pages/preference/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {CheckboxRedirectPreference, RedirectExplorer, usePreference} from "~/components/CheckboxRedirectPreference";
import {RadioGroup, RadioGroupItem} from "@mysten/ui";

export function Preference() {
const {
preference,
setPreference,
} = usePreference();

return (
<div className="flex flex-col justify-center items-center gap-4 mt-4">
<RadioGroup aria-label="redirect-preferences" value={preference} onValueChange={(preference) => setPreference(preference as RedirectExplorer)}>
<RadioGroupItem value={RedirectExplorer.SUISCAN} label={RedirectExplorer.SUISCAN} />
<RadioGroupItem value={RedirectExplorer.SUIVISION} label={RedirectExplorer.SUIVISION} />
</RadioGroup>
<CheckboxRedirectPreference />
</div>
);
}
34 changes: 34 additions & 0 deletions apps/explorer/src/ui/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as RadixCheckbox from '@radix-ui/react-checkbox';
import { CheckStroke16 } from "@mysten/icons";
import { Text } from "@mysten/ui";
import clsx from "clsx";

interface CheckboxProps extends RadixCheckbox.CheckboxProps {
id: string;
label?: string;
className?: string;
}

export function Checkbox({ id, label, className, ...props }: CheckboxProps) {
return (
<div className={clsx("flex items-center gap-2 group", className)}>
<RadixCheckbox.Root
{...props}
id={id}
className="border border-steel hover:border-steel-dark rounded w-5 h-5 data-[state='checked']:bg-success"
>
<RadixCheckbox.Indicator forceMount className="items-center justify-center h-full w-full text-gray-60/60 data-[state='checked']:text-white">
<CheckStroke16 className="h-full w-full"/>
</RadixCheckbox.Indicator>
</RadixCheckbox.Root>
{label && (
<label className="Label group-hover:text-sui-dark cursor-pointer" htmlFor={id}>
<Text variant="body/medium">
{label}
</Text>
</label>
)}
</div>
)
}

31 changes: 31 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 23c3eca

Please sign in to comment.