diff --git a/frontend/.storybook/preview.js b/frontend/.storybook/preview.js index 94133eee3d..1fef7cf804 100644 --- a/frontend/.storybook/preview.js +++ b/frontend/.storybook/preview.js @@ -10,6 +10,6 @@ export const parameters = { } }, darkMode: { - dark: { ...themes.dark, appContentBg: '#0e1014', appBg: '#0e1014' } + dark: { ...themes.dark, appContentBg: 'rgb(14,16,20)', appBg: 'rgb(14,16,20)' } } }; diff --git a/frontend/src/components/v2/EmptyState/EmptyState.stories.tsx b/frontend/src/components/v2/EmptyState/EmptyState.stories.tsx new file mode 100644 index 0000000000..d3fb1bd4aa --- /dev/null +++ b/frontend/src/components/v2/EmptyState/EmptyState.stories.tsx @@ -0,0 +1,20 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { EmptyState } from './EmptyState'; + +const meta: Meta = { + title: 'Components/EmptyState', + component: EmptyState, + tags: ['v2'], + argTypes: {}, + args: { + title: 'No members found' + } +}; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = { + render: (args) => +}; diff --git a/frontend/src/components/v2/EmptyState/EmptyState.tsx b/frontend/src/components/v2/EmptyState/EmptyState.tsx new file mode 100644 index 0000000000..be23337239 --- /dev/null +++ b/frontend/src/components/v2/EmptyState/EmptyState.tsx @@ -0,0 +1,21 @@ +import { ReactNode } from 'react'; +import { faCubesStacked, IconDefinition } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { twMerge } from 'tailwind-merge'; + +type Props = { + title: ReactNode; + className?: string; + children?: ReactNode; + icon?: IconDefinition; +}; + +export const EmptyState = ({ title, className, children, icon = faCubesStacked }: Props) => ( +
+ +
+
{title}
+
{children}
+
+
+); diff --git a/frontend/src/components/v2/EmptyState/index.tsx b/frontend/src/components/v2/EmptyState/index.tsx new file mode 100644 index 0000000000..89798dbd68 --- /dev/null +++ b/frontend/src/components/v2/EmptyState/index.tsx @@ -0,0 +1 @@ +export { EmptyState } from './EmptyState'; diff --git a/frontend/src/components/v2/Skeleton/Skeleton.stories.tsx b/frontend/src/components/v2/Skeleton/Skeleton.stories.tsx new file mode 100644 index 0000000000..5380f8f7f2 --- /dev/null +++ b/frontend/src/components/v2/Skeleton/Skeleton.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { Skeleton } from './Skeleton'; + +const meta: Meta = { + title: 'Components/Skeleton', + component: Skeleton, + tags: ['v2'], + argTypes: {} +}; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = { + render: (args) => +}; diff --git a/frontend/src/components/v2/Skeleton/Skeleton.tsx b/frontend/src/components/v2/Skeleton/Skeleton.tsx new file mode 100644 index 0000000000..4fe25ad644 --- /dev/null +++ b/frontend/src/components/v2/Skeleton/Skeleton.tsx @@ -0,0 +1,12 @@ +import { twMerge } from 'tailwind-merge'; + +export type Props = { + className?: string; +}; + +// To show something is coming up +// Can be used with cards +// Tables etc +export const Skeleton = ({ className }: Props) => ( +
+); diff --git a/frontend/src/components/v2/Skeleton/index.tsx b/frontend/src/components/v2/Skeleton/index.tsx new file mode 100644 index 0000000000..3f34073b3f --- /dev/null +++ b/frontend/src/components/v2/Skeleton/index.tsx @@ -0,0 +1 @@ +export { Skeleton } from './Skeleton'; diff --git a/frontend/src/components/v2/Table/Table.stories.tsx b/frontend/src/components/v2/Table/Table.stories.tsx index 666d43ed46..19be5216b3 100644 --- a/frontend/src/components/v2/Table/Table.stories.tsx +++ b/frontend/src/components/v2/Table/Table.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { Table, TableContainer, TBody, Td, Th, THead, Tr } from './Table'; +import { Table, TableContainer, TableSkeleton, TBody, Td, Th, THead, Tr } from './Table'; const meta: Meta = { title: 'Components/Table', @@ -39,3 +39,22 @@ export const Basic: Story = { ) }; + +export const Loading: Story = { + render: (args) => ( + + + + + + + + + + + + +
Head#1Head#2Head#3
+
+ ) +}; diff --git a/frontend/src/components/v2/Table/Table.tsx b/frontend/src/components/v2/Table/Table.tsx index d44ba77554..8466de970c 100644 --- a/frontend/src/components/v2/Table/Table.tsx +++ b/frontend/src/components/v2/Table/Table.tsx @@ -1,6 +1,8 @@ import { HTMLAttributes, ReactNode, TdHTMLAttributes } from 'react'; import { twMerge } from 'tailwind-merge'; +import { Skeleton } from '../Skeleton'; + export type TableContainerProps = { children: ReactNode; isRounded?: boolean; @@ -32,7 +34,7 @@ export type TableProps = { export const Table = ({ children, className }: TableProps): JSX.Element => ( @@ -59,7 +61,10 @@ export type TrProps = { } & HTMLAttributes; export const Tr = ({ children, className, ...props }: TrProps): JSX.Element => ( - + {children} ); @@ -71,7 +76,7 @@ export type ThProps = { }; export const Th = ({ children, className }: ThProps): JSX.Element => ( - + ); // table body @@ -95,3 +100,25 @@ export const Td = ({ children, className, ...props }: TdProps): JSX.Element => ( {children} ); + +export type TBodyLoader = { + rows?: number; + columns: number; + className?: string; + // unique key for mapping + key: string; +}; + +export const TableSkeleton = ({ rows = 3, columns, key, className }: TBodyLoader): JSX.Element => ( + <> + {Array.apply(0, Array(rows)).map((_x, i) => ( + + {Array.apply(0, Array(columns)).map((_y, j) => ( + + ))} + + ))} + +); diff --git a/frontend/src/components/v2/Table/index.tsx b/frontend/src/components/v2/Table/index.tsx index ccf14665f6..41ab022074 100644 --- a/frontend/src/components/v2/Table/index.tsx +++ b/frontend/src/components/v2/Table/index.tsx @@ -7,4 +7,4 @@ export type { ThProps, TrProps } from './Table'; -export { Table, TableContainer, TBody, Td, Th, THead, Tr } from './Table'; +export { Table, TableContainer, TableSkeleton,TBody, Td, Th, THead, Tr } from './Table'; diff --git a/frontend/src/components/v2/index.tsx b/frontend/src/components/v2/index.tsx index d69b0bfb44..52c8fc4f47 100644 --- a/frontend/src/components/v2/index.tsx +++ b/frontend/src/components/v2/index.tsx @@ -3,12 +3,14 @@ export * from './Card'; export * from './Checkbox'; export * from './DeleteActionModal'; export * from './Dropdown'; +export * from './EmptyState'; export * from './FormControl'; export * from './IconButton'; export * from './Input'; export * from './Menu'; export * from './Modal'; export * from './Select'; +export * from './Skeleton'; export * from './Spinner'; export * from './Switch'; export * from './Table'; diff --git a/frontend/src/views/Settings/OrgSettingsPage/OrgSettingsPage.tsx b/frontend/src/views/Settings/OrgSettingsPage/OrgSettingsPage.tsx index 26c06a9d21..ca1f3a3fd4 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/OrgSettingsPage.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/OrgSettingsPage.tsx @@ -36,10 +36,12 @@ export const OrgSettingsPage = () => { const { createNotification } = useNotificationContext(); const orgId = currentOrg?._id || ''; - const { data: orgUsers } = useGetOrgUsers(orgId); - const { data: workspaceMemberships } = useGetUserWorkspaceMemberships(orgId); + const { data: orgUsers, isLoading: isOrgUserLoading } = useGetOrgUsers(orgId); + const { data: workspaceMemberships, isLoading: IsWsMembershipLoading } = + useGetUserWorkspaceMemberships(orgId); const { data: wsKey } = useGetUserWsKey(currentWorkspace?._id || ''); - const { data: incidentContact } = useGetOrgIncidentContact(orgId); + const { data: incidentContact, isLoading: IsIncidentContactLoading } = + useGetOrgIncidentContact(orgId); const renameOrg = useRenameOrg(); const removeUserOrgMembership = useDeleteOrgMembership(); @@ -197,9 +199,9 @@ export const OrgSettingsPage = () => { /** * This function deleted a workspace. - * It first checks if there is more than one workspace aviable. Otherwise, it doesn't delete + * It first checks if there is more than one workspace available. Otherwise, it doesn't delete * It then checks if the name of the workspace to be deleted is correct. Otherwise, it doesn't delete. - * It then deletes the workspace and forwards the user to another aviable workspace. + * It then deletes the workspace and forwards the user to another available workspace. */ // const executeDeletingWorkspace = async () => { // const userWorkspaces = await getWorkspaces(); @@ -230,13 +232,11 @@ export const OrgSettingsPage = () => {
-

+

{t('section-members:org-members')}

-

- {t('section-members:org-members-description')} -

{
Promise; onAddContact: (email: string) => Promise; @@ -39,7 +46,8 @@ type TAddContactForm = yup.InferType; export const OrgIncidentContactsTable = ({ contacts = [], onAddContact, - onRemoveContact + onRemoveContact, + isLoading }: Props) => { const [searchContact, setSearchContact] = useState(''); const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([ @@ -66,6 +74,10 @@ export const OrgIncidentContactsTable = ({ handlePopUpClose('removeContact'); }; + const filteredContacts = contacts.filter(({ email }) => + email.toLocaleLowerCase().includes(searchContact) + ); + return (
@@ -96,28 +108,25 @@ export const OrgIncidentContactsTable = ({
- {contacts - ?.filter(({ email }) => email.toLocaleLowerCase().includes(searchContact)) - ?.map(({ email }) => ( - - - - - ))} + {isLoading && } + {filteredContacts?.map(({ email }) => ( + + + + + ))}
{children}{children}
+ +
{email} - handlePopUpOpen('removeContact', { email })} - > - - -
{email} + handlePopUpOpen('removeContact', { email })} + > + + +
- {contacts - ?.filter(({ email }) => email.toLocaleLowerCase().includes(searchContact)) - ?.length === 0 && ( -
No incident contacts found
+ {filteredContacts?.length === 0 && !isLoading && ( + )}
diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgMembersTable/OrgMembersTable.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgMembersTable/OrgMembersTable.tsx index 2911ae603c..020eae9636 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgMembersTable/OrgMembersTable.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/components/OrgMembersTable/OrgMembersTable.tsx @@ -1,6 +1,6 @@ import { useMemo, useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; -import { faMagnifyingGlass, faPlus, faTrash } from '@fortawesome/free-solid-svg-icons'; +import { faMagnifyingGlass, faPlus, faTrash, faUsers } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { yupResolver } from '@hookform/resolvers/yup'; import * as yup from 'yup'; @@ -8,6 +8,7 @@ import * as yup from 'yup'; import { Button, DeleteActionModal, + EmptyState, FormControl, IconButton, Input, @@ -17,14 +18,14 @@ import { SelectItem, Table, TableContainer, + TableSkeleton, Tag, TBody, Td, Th, THead, Tr, - UpgradePlanModal -} from '@app/components/v2'; + UpgradePlanModal} from '@app/components/v2'; import { usePopUp } from '@app/hooks'; import { OrgUser, Workspace } from '@app/hooks/api/types'; @@ -32,6 +33,7 @@ type Props = { members?: OrgUser[]; workspaceMemberships?: Record; orgName: string; + isLoading?: boolean; isMoreUserNotAllowed: boolean; onRemoveMember: (userId: string) => Promise; onInviteMember: (email: string) => Promise; @@ -56,7 +58,8 @@ export const OrgMembersTable = ({ onInviteMember, onGrantAccess, onRoleChange, - userId + userId, + isLoading }: Props) => { const [searchMemberFilter, setSearchMemberFilter] = useState(''); const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([ @@ -72,8 +75,8 @@ export const OrgMembersTable = ({ formState: { isSubmitting } } = useForm({ resolver: yupResolver(addMemberFormSchema) }); - const onAddMember = ({ email }: TAddMemberForm) => { - onInviteMember(email); + const onAddMember = async ({ email }: TAddMemberForm) => { + await onInviteMember(email); handlePopUpClose('addMember'); reset(); }; @@ -140,73 +143,79 @@ export const OrgMembersTable = ({ - {filterdUser.map(({ user, inviteEmail, role, _id: orgMembershipId, status }) => { - const name = user ? `${user.firstName} ${user.lastName}` : '-'; - const email = user?.email || inviteEmail; - const userWs = workspaceMemberships?.[user?._id]; + {isLoading && } + {!isLoading && + filterdUser.map(({ user, inviteEmail, role, _id: orgMembershipId, status }) => { + const name = user ? `${user.firstName} ${user.lastName}` : '-'; + const email = user?.email || inviteEmail; + const userWs = workspaceMemberships?.[user?._id]; - return ( - - {name} - {email} - - {status === 'accepted' && ( - - )} - {(status === 'invited' || status === 'verified') && ( - - )} - {status === 'completed' && ( - - )} - - - {userWs ? ( - userWs?.map(({ name: wsName, _id }) => ( - - {wsName} - - )) - ) : ( - This user isn't part of any projects yet - )} - - - {userId !== user?._id && handlePopUpOpen('removeMember', { id: orgMembershipId })} - > - - } - - - ); - })} + return ( + + {name} + {email} + + {status === 'accepted' && ( + + )} + {(status === 'invited' || status === 'verified') && ( + + )} + {status === 'completed' && ( + + )} + + + {userWs ? ( + userWs?.map(({ name: wsName, _id }) => ( + + {wsName} + + )) + ) : ( + This user isn't part of any projects yet + )} + + + {userId !== user?._id && ( + handlePopUpOpen('removeMember', { id: orgMembershipId })} + > + + + )} + + + ); + })} - {filterdUser.length === 0 && No project members found} + {!isLoading && filterdUser?.length === 0 && ( + + )} { const { t } = useTranslation(); - const { currentWorkspace, workspaces } = useWorkspace(); + const { currentWorkspace, workspaces, isLoading: isWorkspaceLoading } = useWorkspace(); const router = useRouter(); - const { data: serviceTokens } = useGetUserWsServiceTokens({ - workspaceID: currentWorkspace?._id || '' - }); + const workspaceID = currentWorkspace?._id || ''; const { createNotification } = useNotificationContext(); // delete action worksapce @@ -66,12 +64,15 @@ export const ProjectSettingsPage = () => { const deleteWsEnv = useDeleteWsEnvironment(); // service token + const { data: serviceTokens, isLoading: isServiceTokenLoading } = useGetUserWsServiceTokens({ + workspaceID: currentWorkspace?._id || '' + }); const { data: latestFileKey } = useGetUserWsKey(workspaceID); const createServiceToken = useCreateServiceToken(); const deleteServiceToken = useDeleteServiceToken(); // tag - const { data: wsTags } = useGetWsTags(workspaceID); + const { data: wsTags, isLoading: isTagLoading } = useGetWsTags(workspaceID); const createWsTag = useCreateWsTag(); const deleteWsTag = useDeleteWsTag(); @@ -300,7 +301,7 @@ export const ProjectSettingsPage = () => { }; return ( -
+
{/* TODO(akhilmhdh): Remove this right when layout is refactored */}
@@ -319,6 +320,7 @@ export const ProjectSettingsPage = () => { /> { isEnvServiceAllowed={isEnvServiceAllowed} /> { onCreateToken={onCreateServiceToken} /> { const { t } = useTranslation(); return ( -
-
-

- {t('settings-project:auto-capitalization')} -

- { - onAutoCapitalizationChange(state as boolean); - }} - > - {t('settings-project:auto-capitalization-description')} - -
-
+
+

{t('settings-project:auto-capitalization')}

+ { + onAutoCapitalizationChange(state as boolean); + }} + > + {t('settings-project:auto-capitalization-description')} + +
); }; diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/EnvironmentSection/EnvironmentSection.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/EnvironmentSection/EnvironmentSection.tsx index ddcf7f4b3e..817435a127 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/components/EnvironmentSection/EnvironmentSection.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/EnvironmentSection/EnvironmentSection.tsx @@ -7,6 +7,7 @@ import * as yup from 'yup'; import { Button, DeleteActionModal, + EmptyState, FormControl, IconButton, Input, @@ -14,6 +15,7 @@ import { ModalContent, Table, TableContainer, + TableSkeleton, TBody, Td, Th, @@ -25,6 +27,7 @@ import { usePopUp } from '@app/hooks/usePopUp'; type Props = { environments: Array<{ name: string; slug: string }>; + isLoading?: boolean; isEnvServiceAllowed: boolean; onCreate: (data: CreateUpdateEnvFormData) => Promise; onUpdate: (oldEnvSlug: string, data: CreateUpdateEnvFormData) => Promise; @@ -43,6 +46,7 @@ export const EnvironmentSection = ({ isEnvServiceAllowed, onCreate, onDelete, + isLoading, onUpdate }: Props): JSX.Element => { const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ @@ -116,7 +120,8 @@ export const EnvironmentSection = ({ - {environments?.length > 0 ? ( + {isLoading && } + {!isLoading && environments.map(({ name, slug }) => ( {name} @@ -152,11 +157,11 @@ export const EnvironmentSection = ({ - )) - ) : ( + ))} + {!isLoading && environments?.length === 0 && ( - - No environments found + + )} diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/SecretTagsSection/SecretTagsSection.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/SecretTagsSection/SecretTagsSection.tsx index 6aa4d26be8..98019e0ad0 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/components/SecretTagsSection/SecretTagsSection.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/SecretTagsSection/SecretTagsSection.tsx @@ -1,5 +1,5 @@ import { Controller, useForm } from 'react-hook-form'; -import { faPlus, faTrashCan } from '@fortawesome/free-solid-svg-icons'; +import { faPlus, faTags, faTrashCan } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { yupResolver } from '@hookform/resolvers/yup'; import * as yup from 'yup'; @@ -7,6 +7,7 @@ import * as yup from 'yup'; import { Button, DeleteActionModal, + EmptyState, FormControl, IconButton, Input, @@ -16,23 +17,24 @@ import { ModalTrigger, Table, TableContainer, + TableSkeleton, TBody, Td, Th, THead, - Tr, -} from '@app/components/v2'; + Tr} from '@app/components/v2'; import { usePopUp } from '@app/hooks'; import { WorkspaceTag } from '@app/hooks/api/types'; const createTagSchema = yup.object({ - name: yup.string().required().label('Tag Name'), + name: yup.string().required().label('Tag Name') }); export type CreateWsTag = yup.InferType; type Props = { tags: WorkspaceTag[]; + isLoading?: boolean; workspaceName: string; onDeleteTag: (tagID: string) => Promise; onCreateTag: (data: CreateWsTag) => Promise; @@ -42,6 +44,7 @@ type DeleteModalData = { name: string; id: string }; export const SecretTagsSection = ({ tags = [], + isLoading, onDeleteTag, workspaceName, onCreateTag @@ -76,7 +79,10 @@ export const SecretTagsSection = ({

Secret Tags

-

Every secret can be assigned to one or more tags. Here you can add and remove tags for the current project.

+

+ Every secret can be assigned to one or more tags. Here you can add and remove tags for + the current project. +

( @@ -130,7 +136,7 @@ export const SecretTagsSection = ({
- + @@ -140,7 +146,8 @@ export const SecretTagsSection = ({ - {tags?.length > 0 ? ( + {isLoading && } + {!isLoading && tags.map(({ _id, name, slug }) => ( @@ -149,7 +156,7 @@ export const SecretTagsSection = ({ handlePopUpOpen('deleteTagConfirmation', { - name, + name, id: _id }) } @@ -160,11 +167,11 @@ export const SecretTagsSection = ({ - )) - ) : ( + ))} + {!isLoading && tags?.length === 0 && ( - )} diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/ServiceTokenSection/ServiceTokenSection.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/ServiceTokenSection/ServiceTokenSection.tsx index 052fdc6788..e4c4bbf2e5 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/components/ServiceTokenSection/ServiceTokenSection.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/ServiceTokenSection/ServiceTokenSection.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import { faCheck, faCopy, faPlus, faTrashCan } from '@fortawesome/free-solid-svg-icons'; +import { faCheck, faCopy, faKey, faPlus, faTrashCan } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { yupResolver } from '@hookform/resolvers/yup'; import * as yup from 'yup'; @@ -9,6 +9,7 @@ import * as yup from 'yup'; import { Button, DeleteActionModal, + EmptyState, FormControl, IconButton, Input, @@ -20,6 +21,7 @@ import { SelectItem, Table, TableContainer, + TableSkeleton, TBody, Td, Th, @@ -47,6 +49,7 @@ export type CreateServiceToken = yup.InferType; type Props = { tokens: ServiceToken[]; + isLoading?: boolean; workspaceName: string; environments: WorkspaceEnv[]; onDeleteToken: (serviceTokenID: string) => Promise; @@ -57,6 +60,7 @@ type DeleteModalData = { name: string; id: string }; export const ServiceTokenSection = ({ tokens = [], + isLoading, onDeleteToken, workspaceName, environments = [], @@ -252,7 +256,7 @@ export const ServiceTokenSection = ({ isOpen={popUp.deleteAPITokenConfirmation.isOpen} title={`Delete ${ (popUp?.deleteAPITokenConfirmation?.data as DeleteModalData)?.name || ' ' - } api key?`} + } service token?`} onChange={(isOpen) => handlePopUpToggle('deleteAPITokenConfirmation', isOpen)} deleteKey={(popUp?.deleteAPITokenConfirmation?.data as DeleteModalData)?.name} onClose={() => handlePopUpClose('deleteAPITokenConfirmation')} @@ -269,7 +273,8 @@ export const ServiceTokenSection = ({ - {tokens?.length > 0 ? ( + {isLoading && } + {!isLoading && tokens.map((row) => ( @@ -290,11 +295,11 @@ export const ServiceTokenSection = ({ - )) - ) : ( + ))} + {!isLoading && tokens?.length === 0 && ( )} diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index f2c832acc9..54f527c47e 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -1340,163 +1340,165 @@ module.exports = { 900: '#176437', DEFAULT: '#2ecc71' } - } - }, - keyframes: { - type: { - '0%': { transform: 'translateX(0ch)' }, - '5%, 10%': { transform: 'translateX(1ch)' }, - '15%, 20%': { transform: 'translateX(2ch)' }, - '25%, 30%': { transform: 'translateX(3ch)' }, - '35%, 40%': { transform: 'translateX(4ch)' }, - '45%, 50%': { transform: 'translateX(5ch)' }, - '55%, 60%': { transform: 'translateX(6ch)' }, - '65%, 70%': { transform: 'translateX(7ch)' }, - '75%, 80%': { transform: 'translateX(8ch)' }, - '85%, 90%': { transform: 'translateX(9ch)' }, - '95%, 100%': { transform: 'translateX(11ch)' } - }, - // REQUIRED BY DEISGN COMPONENT - // MODAL - fadeIn: { - '0%': { opacity: 0 }, - '100%': { opacity: 1 } - }, - popIn: { - from: { - opacity: 0, - transform: 'translate(-50%, -48%) scale(0.96)' - }, - to: { - opacity: 1, - transform: 'translate(-50%, -50%) scale(1)' - } - }, - // Dropdown - slideUpAndFade: { - from: { - opacity: 0, - transform: ' translateY(2px)' - }, - to: { - opacity: 1, - transform: ' translateY(0)' - } - }, - slideRightAndFade: { - from: { - opacity: 0, - transform: ' translateX(-2px)' - }, - to: { - opacity: 1, - transform: ' translateX(0)' - } - }, - slideDownAndFade: { - from: { - opacity: 0, - transform: ' translateY(-2px)' - }, - to: { - opacity: 1, - transform: ' translateY(0)' - } - }, - slideLeftAndFade: { - from: { - opacity: 0, - transform: ' translateX(2px)' - }, - to: { - opacity: 1, - transform: ' translateX(0)' - } - }, - // END - spin: { - '0%': { transform: 'rotate(0deg)' }, - '40%': { transform: 'rotate(360deg)' }, - '100%': { transform: 'rotate(360deg)' } - }, - bounce: { - '0%': { transform: 'translateY(-90%)' }, - '100%': { transform: 'translateY(-100%)' } - }, - wiggle: { - '0%, 100%': { transform: 'rotate(-3deg)' }, - '50%': { transform: 'rotate(3deg)' } - }, - ping: { - '75%, 100%': { - transform: 'scale(2)', - opacity: 0 - } - }, - popup: { - '0%': { - transform: 'scale(0.2)', - opacity: 0 - // transform: "translateY(120%)", - }, - '100%': { - transform: 'scale(1)', - opacity: 1 - // transform: "translateY(100%)", - } }, - popright: { - '0%': { - transform: 'translateX(-100%)' - }, - '100%': { - transform: 'translateX(0%)' - } - }, - popleft: { - '0%': { - transform: 'translateX(100%)' + keyframes: { + type: { + '0%': { transform: 'translateX(0ch)' }, + '5%, 10%': { transform: 'translateX(1ch)' }, + '15%, 20%': { transform: 'translateX(2ch)' }, + '25%, 30%': { transform: 'translateX(3ch)' }, + '35%, 40%': { transform: 'translateX(4ch)' }, + '45%, 50%': { transform: 'translateX(5ch)' }, + '55%, 60%': { transform: 'translateX(6ch)' }, + '65%, 70%': { transform: 'translateX(7ch)' }, + '75%, 80%': { transform: 'translateX(8ch)' }, + '85%, 90%': { transform: 'translateX(9ch)' }, + '95%, 100%': { transform: 'translateX(11ch)' } + }, + // REQUIRED BY DESIGN COMPONENT + // MODAL + fadeIn: { + '0%': { opacity: 0 }, + '100%': { opacity: 1 } + }, + popIn: { + from: { + opacity: 0, + transform: 'translate(-50%, -48%) scale(0.96)' + }, + to: { + opacity: 1, + transform: 'translate(-50%, -50%) scale(1)' + } + }, + // Dropdown + slideUpAndFade: { + from: { + opacity: 0, + transform: ' translateY(2px)' + }, + to: { + opacity: 1, + transform: ' translateY(0)' + } + }, + slideRightAndFade: { + from: { + opacity: 0, + transform: ' translateX(-2px)' + }, + to: { + opacity: 1, + transform: ' translateX(0)' + } + }, + slideDownAndFade: { + from: { + opacity: 0, + transform: ' translateY(-2px)' + }, + to: { + opacity: 1, + transform: ' translateY(0)' + } + }, + slideLeftAndFade: { + from: { + opacity: 0, + transform: ' translateX(2px)' + }, + to: { + opacity: 1, + transform: ' translateX(0)' + } + }, + // END + spin: { + '0%': { transform: 'rotate(0deg)' }, + '40%': { transform: 'rotate(360deg)' }, + '100%': { transform: 'rotate(360deg)' } + }, + bounce: { + '0%': { transform: 'translateY(-90%)' }, + '100%': { transform: 'translateY(-100%)' } + }, + wiggle: { + '0%, 100%': { transform: 'rotate(-3deg)' }, + '50%': { transform: 'rotate(3deg)' } + }, + ping: { + '75%, 100%': { + transform: 'scale(2)', + opacity: 0 + } + }, + popup: { + '0%': { + transform: 'scale(0.2)', + opacity: 0 + // transform: "translateY(120%)", + }, + '100%': { + transform: 'scale(1)', + opacity: 1 + // transform: "translateY(100%)", + } + }, + popright: { + '0%': { + transform: 'translateX(-100%)' + }, + '100%': { + transform: 'translateX(0%)' + } }, - '100%': { - transform: 'translateX(0%)' + popleft: { + '0%': { + transform: 'translateX(100%)' + }, + '100%': { + transform: 'translateX(0%)' + } + }, + popdown: { + '0%': { + transform: 'scale(0.2)', + opacity: 0 + // transform: "translateY(80%)", + }, + '100%': { + transform: 'scale(1)', + opacity: 1 + // transform: "translateY(100%)", + } } }, - popdown: { - '0%': { - transform: 'scale(0.2)', - opacity: 0 - // transform: "translateY(80%)", - }, - '100%': { - transform: 'scale(1)', - opacity: 1 - // transform: "translateY(100%)", - } + animation: { + // Design Lib + // MODAL + fadeIn: 'fadeIn 100ms cubic-bezier(0.16, 1, 0.3, 1)', + popIn: 'popIn 150ms cubic-bezier(0.16, 1, 0.3, 1);', + // Dropdown + slideDownAndFade: 'slideDownAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', + slideLeftAndFade: 'slideLeftAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', + slideUpAndFade: 'slideUpAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', + slideRightAndFade: 'slideRightAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', + // END + // TODO:(akhilmhdh) remove all these unused and keep the config file as small as possible + // Make the whole color pallelte into simpler + bounce: 'bounce 1000ms ease-in-out infinite', + spin: 'spin 4000ms ease-in-out infinite', + cursor: 'cursor .6s linear infinite alternate', + type: 'type 2.7s ease-out .8s infinite alternate both', + 'type-reverse': 'type 1.8s ease-out 0s infinite alternate-reverse both', + wiggle: 'wiggle 200ms ease-in-out', + ping: 'ping 1000ms ease-in-out infinite', + popup: 'popup 300ms ease-in-out', + popdown: 'popdown 300ms ease-in-out', + popright: 'popright 100ms ease-in-out', + popleft: 'popleft 100ms ease-in-out' } }, - animation: { - // Design Lib - // MODAL - fadeIn: 'fadeIn 100ms cubic-bezier(0.16, 1, 0.3, 1)', - popIn: 'popIn 150ms cubic-bezier(0.16, 1, 0.3, 1);', - // Dropdown - slideDownAndFade: 'slideDownAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', - slideLeftAndFade: 'slideLeftAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', - slideUpAndFade: 'slideUpAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', - slideRightAndFade: 'slideRightAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', - // END - bounce: 'bounce 1000ms ease-in-out infinite', - spin: 'spin 4000ms ease-in-out infinite', - cursor: 'cursor .6s linear infinite alternate', - type: 'type 2.7s ease-out .8s infinite alternate both', - 'type-reverse': 'type 1.8s ease-out 0s infinite alternate-reverse both', - wiggle: 'wiggle 200ms ease-in-out', - ping: 'ping 1000ms ease-in-out infinite', - popup: 'popup 300ms ease-in-out', - popdown: 'popdown 300ms ease-in-out', - popright: 'popright 100ms ease-in-out', - popleft: 'popleft 100ms ease-in-out' - }, fontSize: { xxxs: '.23rem', xxs: '.5rem',
{name}
- No tags found for this project + +
{row.name}
- No service tokens found +