Animated menu icons

This commit is contained in:
Vladyslav Matsiiako
2023-04-27 18:44:23 -07:00
parent 4ac13f61e0
commit 3b94ee42e9
9 changed files with 9048 additions and 9710 deletions

18671
frontend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -51,6 +51,7 @@
"classnames": "^2.3.1",
"cookies": "^0.8.0",
"cva": "npm:class-variance-authority@^0.4.0",
"framer-motion": "^6.2.3",
"fs": "^0.0.1-security",
"gray-matter": "^4.0.3",
"http-proxy": "^1.18.1",
@@ -58,6 +59,7 @@
"infisical-node": "^1.0.37",
"jspdf": "^2.5.1",
"jsrp": "^0.2.4",
"lottie-react": "^2.4.0",
"markdown-it": "^13.0.1",
"next": "^12.3.4",
"next-i18next": "^13.0.2",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,8 @@
import { ComponentPropsWithRef, ElementType, ReactNode, Ref } from 'react';
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable global-require */
import { ComponentPropsWithRef, ElementType, ReactNode, Ref, useRef } from 'react';
import { motion } from 'framer-motion'
import Lottie from 'lottie-react'
import { twMerge } from 'tailwind-merge';
export type MenuProps = {
@@ -14,7 +18,7 @@ export type MenuItemProps<T extends ElementType> = {
// Kudos to https://itnext.io/react-polymorphic-components-with-typescript-f7ce72ea7af2
as?: T;
children: ReactNode;
icon?: ReactNode;
icon?: string;
description?: ReactNode;
isDisabled?: boolean;
isSelected?: boolean;
@@ -33,23 +37,43 @@ export const MenuItem = <T extends ElementType = 'button'>({
// wrapping in forward ref with generic component causes the loss of ts definitions on props
inputRef,
...props
}: MenuItemProps<T> & ComponentPropsWithRef<T>): JSX.Element => (
<li
className={twMerge(
'px-1 py-2.5 mt-0.5 font-inter flex flex-col text-sm text-bunker-100 transition-all rounded cursor-pointer hover:bg-mineshaft-600 duration-50',
isSelected && 'bg-mineshaft-500',
isDisabled && 'hover:bg-transparent cursor-not-allowed',
className
)}
>
<Item type="button" role="menuitem" className="flex items-center relative" ref={inputRef} {...props}>
<div className={`${isSelected ? "visisble" : "invisible"} absolute w-[0.25rem] rounded-md h-8 bg-primary`}/>
{icon && <span className="mr-3 ml-4 w-5">{icon}</span>}
<span className="flex-grow text-left">{children}</span>
</Item>
{description && <span className="mt-2 text-xs">{description}</span>}
</li>
);
}: MenuItemProps<T> & ComponentPropsWithRef<T>): JSX.Element => {
const iconRef = useRef()
return(
<a
onMouseEnter={() => iconRef.current?.play()}
onMouseLeave={() => iconRef.current?.stop()}
>
<li
className={twMerge(
'group px-1 py-2.5 mt-0.5 font-inter flex flex-col text-sm text-bunker-100 transition-all rounded cursor-pointer hover:bg-mineshaft-700 duration-50',
isSelected && 'bg-mineshaft-600 hover:bg-mineshaft-600',
isDisabled && 'hover:bg-transparent cursor-not-allowed',
className
)}
>
<motion.span className="w-full flex flex-row items-center justify-start rounded-sm">
<Item type="button" role="menuitem" className="flex items-center relative" ref={inputRef} {...props}>
<div className={`${isSelected ? "visisble" : "invisible"} absolute w-[0.25rem] rounded-md h-8 bg-primary`}/>
{/* {icon && <span className="mr-3 ml-4 w-5 block group-hover:hidden">{icon}</span>} */}
<Lottie
lottieRef={iconRef}
style={{ width: 24, height: 24 }}
// eslint-disable-next-line import/no-dynamic-require
animationData={require(`../../../../public/lotties/${icon}.json`)}
loop={false}
autoplay={false}
className="my-auto ml-3 mr-3"
/>
<span className="flex-grow text-left">{children}</span>
</Item>
{description && <span className="mt-2 text-xs">{description}</span>}
</motion.span>
</li>
</a>
)
};
MenuItem.displayName = 'MenuItem';

View File

@@ -10,13 +10,8 @@ import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import {
faBookOpen,
faFileLines,
faGear,
faKey,
faMobile,
faPlug,
faPlus,
faUser
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { yupResolver } from '@hookform/resolvers/yup';
@@ -309,7 +304,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
<a>
<MenuItem
isSelected={router.asPath.includes(`/dashboard/${currentWorkspace?._id}`)}
icon={<FontAwesomeIcon icon={faKey} size="lg" />}
icon="system-outline-90-lock-closed"
>
{t('nav:menu.secrets')}
</MenuItem>
@@ -319,7 +314,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
<a>
<MenuItem
isSelected={router.asPath === `/users/${currentWorkspace?._id}`}
icon={<FontAwesomeIcon icon={faUser} size="lg" />}
icon="system-outline-96-groups"
>
{t('nav:menu.members')}
</MenuItem>
@@ -329,21 +324,20 @@ export const AppLayout = ({ children }: LayoutProps) => {
<a>
<MenuItem
isSelected={router.asPath === `/integrations/${currentWorkspace?._id}`}
icon={<FontAwesomeIcon icon={faPlug} size="lg" />}
icon="system-outline-82-extension"
>
{t('nav:menu.integrations')}
</MenuItem>
</a>
</Link>
<Link href={`/activity/${currentWorkspace?._id}`} passHref>
<a>
<MenuItem
isSelected={router.asPath === `/activity/${currentWorkspace?._id}`}
icon={<FontAwesomeIcon icon={faFileLines} size="lg" />}
// icon={<FontAwesomeIcon icon={faFileLines} size="lg" />}
icon="system-outline-168-view-headline"
>
Audit Logs
</MenuItem>
</a>
</Link>
<Link href={`/settings/project/${currentWorkspace?._id}`} passHref>
<a>
@@ -351,7 +345,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
isSelected={
router.asPath === `/settings/project/${currentWorkspace?._id}`
}
icon={<FontAwesomeIcon icon={faGear} size="lg" />}
icon="system-outline-109-slider-toggle-settings"
>
{t('nav:menu.project-settings')}
</MenuItem>