Skip to content

Commit

Permalink
fix: update scanner design
Browse files Browse the repository at this point in the history
  • Loading branch information
nikaaru authored and RanGojo committed Jan 17, 2024
1 parent 942b562 commit 4ffafb6
Show file tree
Hide file tree
Showing 35 changed files with 614 additions and 140 deletions.
1 change: 1 addition & 0 deletions components/common/ButtonCopyIcon/ButtonCopyIcon.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export type PropsType = ButtonOnclick & {
className?: string;
hasTooltip?: boolean;
tooltipText?: string;
copiedTooltipText?: string;
};
7 changes: 4 additions & 3 deletions components/common/ButtonCopyIcon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ function ButtonCopyIcon(props: PropsType) {
text,
className,
hasTooltip = true,
tooltipText = 'Copied To Clipboard',
tooltipText = 'Copy To Clipboard',
copiedTooltipText = 'Copied To Clipboard',
} = props;
const [copied, setCopied] = useState<boolean>(false);

Expand All @@ -27,9 +28,9 @@ function ButtonCopyIcon(props: PropsType) {
className={`flex items-center ${className || ''}`}
onClick={handleClick}>
{copied ? (
<>
<Tooltip label={copiedTooltipText}>
<CheckIcon />
</>
</Tooltip>
) : (
<>
{hasTooltip ? (
Expand Down
41 changes: 41 additions & 0 deletions components/common/Error/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Navbar from 'components/common/Navbar';
import Image from 'next/image';
import { useRouter } from 'next/router';
import errorImage from 'public/img/error.png';

function Error() {
const router = useRouter();

return (
<div className="h-full w-full bg-body-mask bg-cover">
<Navbar theme="dark" />
<main className="w-full flex justify-center">
<div className="container flex flex-col mt-[100px] items-center">
<div className="w-full relative">
<div className="w-full pt-1/4 opacity-75">
<Image
src={errorImage}
className="w-1/2 md:w-auto mx-auto"
alt="error"
/>
</div>
</div>
<div className="text-16 md:text-45 pt-[45px] md:pt-[100px] text-primary-500 font-semibold">
Sorry, something went wrong
</div>
<div className="text-14 md:text-20 w-[80%] text-center mt-10 md:mt-5 text-neutral-800">
An unexpected error has occurred. If reloading the page does not fix
it, please contact Rango support.
</div>
<button
onClick={() => router.reload()}
className="text-baseForeground bg-primary-600 py-10 md:py-15 px-20 mt-50 text-center rounded-full w-[224px] text-14 md:text-18 font-medium">
Reload
</button>
</div>
</main>
</div>
);
}

export default Error;
4 changes: 3 additions & 1 deletion components/common/Navbar/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ function Menu(props: MenuProps) {
className="flex items-center hover:text-secondary-500"
href={item.location}>
<Icon size="1.12rem" className="text-secondary-500" />
<span className="pl-1.5">{item.title}</span>
<span className="pl-1.5 text-14 font-normal">
{item.title}
</span>
</Link>
</li>
);
Expand Down
15 changes: 15 additions & 0 deletions components/common/RefreshButton/RefreshButton.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { SvgIconPropsWithChildren } from '../SvgIcon';

export type RefreshButtonProps = {
onClick: (() => void) | undefined;
refreshTime: number;
};

export type RefreshProgressButtonProps = SvgIconPropsWithChildren & {
progress: number;
};

export type EllipseProps = {
fill?: string;
progress?: number;
};
79 changes: 79 additions & 0 deletions components/common/RefreshButton/RefreshProgressButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { createElement } from 'react';

import { SvgIcon } from '../SvgIcon';
import { EllipseProps, RefreshProgressButtonProps } from './RefreshButton.type';

const DEFAULT_STROKE_DASHOFFSET = 59;
const MAX_PERCENTAGE = 100;
const MAX_PROGRESS = 41;
const MIN_PROGRESS = 0;
const NORMALIZE_FACTOR = 10;
const OPACITY_THRESHOLD = 82;
const DIVISION_FACTOR = 2;

const Ellipse = (props: EllipseProps) => {
const type = props.progress ? 'in-progress' : 'basic';
return (
<ellipse
cx="12.5"
cy="12.5"
rx="7.7"
ry="7.7"
stroke="currentColor"
strokeDashoffset={props.progress || DEFAULT_STROKE_DASHOFFSET}
style={{
strokeLinecap: 'round',
fill: 'none',
strokeDasharray: 100,
transform: `rotate(20deg)`,
transformOrigin: 'center',
...(type === 'in-progress' && { stroke: '#5BABFF', strokeWidth: 2 }),
...(type === 'basic' && { strokeWidth: 1.8 }),
}}
/>
);
};

function RefreshProgressButton(props: RefreshProgressButtonProps) {
const normalizeValue = (value: number) => {
return (value - OPACITY_THRESHOLD) / NORMALIZE_FACTOR;
};
const normalizedProgress = Math.min(
props.progress / DIVISION_FACTOR,
MAX_PROGRESS,
);
const opacity =
normalizedProgress !== MAX_PROGRESS
? MIN_PROGRESS
: normalizeValue(props.progress);

return createElement(
SvgIcon,
props,
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<Ellipse />
<Ellipse progress={MAX_PERCENTAGE - normalizedProgress} />

<path
d="M19.2696 9.6089C19.1207 9.49207 19.0218 9.31141 19.01 9.10738L18.807 5.14476C18.788 4.77467 19.0763 4.45089 19.4464 4.43183C19.8165 4.41278 20.1402 4.70108 20.1593 5.07117L20.3622 9.0338C20.3813 9.40389 20.093 9.72767 19.7229 9.74672C19.5584 9.76661 19.3973 9.70903 19.2696 9.6089Z"
fill="currentColor"
/>
<path
d="M19.2696 9.6089C19.1207 9.49207 19.0218 9.31141 19.01 9.10738L18.807 5.14476C18.788 4.77467 19.0763 4.45089 19.4464 4.43183C19.8165 4.41278 20.1402 4.70108 20.1593 5.07117L20.3622 9.0338C20.3813 9.40389 20.093 9.72767 19.7229 9.74672C19.5584 9.76661 19.3973 9.70903 19.2696 9.6089Z"
fillOpacity={opacity}
className="fill-running"
/>
<path
d="M15.5108 9.47903C15.3476 9.35108 15.2457 9.14511 15.2505 8.9198C15.2639 8.55221 15.575 8.25778 15.9482 8.26404L19.707 8.3939C20.0802 8.40016 20.3691 8.71837 20.3628 9.09152C20.3565 9.46466 20.0383 9.75353 19.6652 9.74728L15.9007 9.62451C15.7529 9.62312 15.6243 9.56804 15.5108 9.47903Z"
fill="currentColor"
/>
<path
d="M15.5108 9.47903C15.3476 9.35108 15.2457 9.14511 15.2505 8.9198C15.2639 8.55221 15.575 8.25778 15.9482 8.26404L19.707 8.3939C20.0802 8.40016 20.3691 8.71837 20.3628 9.09152C20.3565 9.46466 20.0383 9.75353 19.6652 9.74728L15.9007 9.62451C15.7529 9.62312 15.6243 9.56804 15.5108 9.47903Z"
fillOpacity={opacity}
className="fill-running"
/>
</svg>,
);
}

export default RefreshProgressButton;
80 changes: 80 additions & 0 deletions components/common/RefreshButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { useEffect, useState } from 'react';

import RefreshProgressButton from './RefreshProgressButton';
import { RefreshButtonProps } from './RefreshButton.type';

const REFRESH_INTERVAL = 1000;
const MAX_PERCENTAGE = 100;

export default function RefreshButton(props: RefreshButtonProps) {
const { onClick, refreshTime } = props;
const [elapsedTime, setElapsedTime] = useState(0);
const [isRefetch, setIsRefetch] = useState(false);

const handleVisibilityChange = (interval?: number) => {
if (document.hidden && interval) {
clearTimeout(interval);
}
};

useEffect(() => {
let interval: number | undefined;
if (onClick) {
interval = window.setInterval(() => {
setElapsedTime((prevTime) => prevTime + 1);

if (elapsedTime === refreshTime) {
handleRefreshClick();
}
}, REFRESH_INTERVAL);
} else {
clearTimeout(interval);
}

document.addEventListener('visibilitychange', () =>
handleVisibilityChange(interval),
);

return () => {
document.removeEventListener('visibilitychange', () =>
handleVisibilityChange(interval),
);
if (interval) {
clearInterval(interval);
}
};
}, [elapsedTime, onClick]);

const clearTimeout = (interval?: number) => {
if (interval) {
clearInterval(interval);
}
setElapsedTime(0);
};

const handleRefreshClick = () => {
if (onClick) onClick();
setElapsedTime(0);
setIsRefetch(true);
};

return (
<button onClick={handleRefreshClick} disabled={!onClick}>
<div
className="p-[2px]"
style={{
...(isRefetch && {
transform: `rotate(360deg)`,
transition: 'transform 1s ease-in-out',
}),
}}
onTransitionEnd={() => setIsRefetch(false)}>
<RefreshProgressButton
size="24"
className="text-neutral-400"
progress={(elapsedTime / refreshTime) * MAX_PERCENTAGE}
/>
</div>
</button>
);
}
6 changes: 6 additions & 0 deletions components/common/Skeleton/Skeleton.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type PropTypes = {
width?: number;
height?: number;
variant?: 'circular' | 'rectangular';
className?: string;
};
18 changes: 18 additions & 0 deletions components/common/Skeleton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { PropTypes } from './Skeleton.types';

export function Skeleton(props: PropTypes) {
const { height, width, variant = 'rectangular', className = '' } = props;
return (
<div
style={{
background:
'linear-gradient(90deg, #C8E2FF 0%, rgba(200, 226, 255, 0.20) 70%, #C8E2FF 100%)',
backgroundSize: '800px 100px',
...(width && { width: `${width}px` }),
...(height && { height: `${height}px` }),
}}
className={`animate-wave ${
variant === 'rectangular' ? 'rounded-soft' : 'rounded-full'
} ${className} `}></div>
);
}
Loading

0 comments on commit 4ffafb6

Please sign in to comment.