Setup GitHub Actions (#287)

* add new GitHub Action for CI

* add yarn flag

* use actions v3

* add ci badge (lol)

* cache lint and format scripts

* add more steps

* remove unused component

* fix lint errors

* remove unsued eslint plugins
This commit is contained in:
Pavel 2022-06-29 16:46:51 +02:00 committed by GitHub
parent 4669960896
commit 0677fedc0e
No known key found for this signature in database
GPG Key ID: 0EB8D75C775AB6F1
17 changed files with 69 additions and 838 deletions

View File

@ -32,14 +32,14 @@
"plugin:jsx-a11y/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
// "plugin:node/recommended",
// "plugin:jest/recommended",
"prettier"
],
"rules": {
"react/prop-types": 0,
// "@typescript-eslint/consistent-type-definitions": ["error", "interface"],
"@typescript-eslint/consistent-type-imports": "error",
// TODO: turn on this rul
"@typescript-eslint/no-non-null-assertion": "off",
// "@typescript-eslint/consistent-type-exports": "error",
"simple-import-sort/imports": [
"error",

View File

@ -1,20 +1,44 @@
name: CI
on:
pull_request:
push:
branches:
- main
branches: ["main"]
pull_request:
types: [opened, synchronize]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup node 16
uses: actions/setup-node@v1
with:
node-version: 16.x
- run: yarn install --frozen-lockfile
- run: yarn build
- run: DEBUG=communities:test* yarn test
build:
name: Build and Test
timeout-minutes: 15
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- name: Check out code
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'
- name: Install dependencies
run: yarn --frozen-lockfile
- name: Build
run: yarn build
- name: Typecheck
run: yarn typecheck
- name: Lint
run: yarn lint && yarn format:check
- name: Test
run: yarn test

View File

@ -1 +1,3 @@
# Status Communities for the Web
[![CI](https://github.com/status-im/status-web/actions/workflows/ci.yml/badge.svg)](https://github.com/status-im/status-web/actions/workflows/ci.yml)

View File

@ -11,9 +11,9 @@
"test": "turbo run test --filter=@status-im/* -- --run",
"dev": "turbo run dev --parallel --filter=@status-im/*",
"build": "turbo run build --filter=@status-im/*",
"lint": "turbo run lint --filter=@status-im/*",
"check": "turbo run check --filter=@status-im/*",
"format": "prettier --write .",
"typecheck": "turbo run typecheck --filter=@status-im/*",
"lint": "eslint --cache --cache-location ./node_modules/.cache/eslint/.eslint-cache .",
"format": "prettier --cache --write .",
"format:check": "prettier --check .",
"clean": "turbo run clean && rm -rf node_modules .parcel-cache"
},
@ -27,9 +27,7 @@
"eslint-import-resolver-typescript": "^2.4.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-jest": "^26.1.1",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-react": "^7.27.0",
"eslint-plugin-react-hooks": "^4.3.0",
"eslint-plugin-simple-import-sort": "^7.0.0",

View File

@ -20,11 +20,12 @@
},
"scripts": {
"dev": "vite build --watch --mode development",
"build": "vite build && yarn typegen",
"build": "vite build",
"postbuild": "yarn typegen",
"test": "vitest",
"lint": "eslint src",
"typecheck": "tsc",
"typegen": "tsc --noEmit false --emitDeclarationOnly --paths null || true",
"lint": "eslint src",
"format": "prettier --write src",
"protos": "protons protos/*.proto",
"clean": "rm -rf dist node_modules .turbo"

View File

@ -20,7 +20,8 @@
},
"scripts": {
"dev": "vite build --watch --mode development",
"build": "vite build && yarn typegen",
"build": "vite build",
"postbuild": "yarn typegen",
"#test": "vitest",
"typecheck": "tsc",
"typegen": "tsc --noEmit false --emitDeclarationOnly --paths null || true",

View File

@ -1,117 +0,0 @@
// @ts-nocheck
import React, { useMemo, useRef, useState } from 'react'
import styled from 'styled-components'
import { useIdentity } from '../../contexts/identityProvider'
import { useActivities } from '../../hooks/useActivities'
import { useClickOutside } from '../../hooks/useClickOutside'
import { TopBtn } from '../Chat-legacy/ChatTopbar'
import { ActivityIcon } from '../Icons/ActivityIcon'
import { ActivityCenter } from './ActivityCenter'
interface ActivityButtonProps {
className?: string
}
export function ActivityButton({ className }: ActivityButtonProps) {
const { activities, activityDispatch } = useActivities()
const identity = useIdentity()
const disabled = useMemo(() => !identity, [identity])
const ref = useRef(null)
useClickOutside(ref, () => setShowActivityCenter(false))
const [showActivityCenter, setShowActivityCenter] = useState(false)
const badgeAmount = useMemo(
() => activities.filter(activity => !activity.isRead).length,
[activities]
)
return (
<ActivityWrapper ref={ref} className={className}>
<TopBtn
onClick={() => setShowActivityCenter(!showActivityCenter)}
disabled={disabled}
>
<ActivityIcon />
{badgeAmount > 0 && (
<NotificationBagde
className={
badgeAmount > 99
? 'countless'
: badgeAmount > 9
? 'wide'
: undefined
}
>
{badgeAmount < 100 ? badgeAmount : '∞'}
</NotificationBagde>
)}
</TopBtn>
{showActivityCenter && (
<ActivityCenter
activities={activities}
setShowActivityCenter={setShowActivityCenter}
activityDispatch={activityDispatch}
/>
)}
</ActivityWrapper>
)
}
export const ActivityWrapper = styled.div`
padding-left: 10px;
margin-left: 10px;
position: relative;
&:before {
content: '';
position: absolute;
left: 0;
top: 50%;
width: 2px;
height: 24px;
transform: translateY(-50%);
border-radius: 1px;
background: ${({ theme }) => theme.primary};
opacity: 0.1;
}
&.creation {
padding-left: 0px;
margin-left: 16px;
&:before {
width: 0px;
height: 0px;
}
}
`
const NotificationBagde = styled.div`
width: 18px;
height: 18px;
position: absolute;
top: -2px;
right: -2px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
border-radius: 50%;
font-size: 12px;
line-height: 16px;
font-weight: 500;
background-color: ${({ theme }) => theme.notificationColor};
color: ${({ theme }) => theme.bodyBackgroundColor};
border-radius: 9px;
&.wide {
width: 26px;
right: -7px;
}
&.countless {
width: 22px;
}
`

View File

@ -1,191 +0,0 @@
// @ts-nocheck
import React, { useMemo, useState } from 'react'
import styled from 'styled-components'
import { useMessengerContext } from '../../contexts/messengerProvider'
import { buttonTransparentStyles } from '../Buttons/buttonStyle'
import { Tooltip } from '../Form/Tooltip'
import { HideIcon } from '../Icons/HideIcon'
import { ReadIcon } from '../Icons/ReadIcon'
import { ShowIcon } from '../Icons/ShowIcon'
import { ActivityMessage } from './ActivityMessage'
import type { ActivityAction } from '../../hooks/useActivities'
import type { Activity } from '../../models/Activity'
interface ActivityCenterProps {
activities: Activity[]
setShowActivityCenter: (val: boolean) => void
activityDispatch: React.Dispatch<ActivityAction>
}
export function ActivityCenter({
activities,
setShowActivityCenter,
activityDispatch,
}: ActivityCenterProps) {
const { contacts } = useMessengerContext()
const shownActivities = useMemo(
() =>
activities.filter(
activity => !contacts?.[activity.user]?.blocked ?? true
),
[contacts, activities]
)
const [hideRead, setHideRead] = useState(false)
const [filter, setFilter] = useState('')
const filteredActivities = shownActivities.filter(activity =>
filter
? activity.type === filter
: hideRead
? activity.isRead !== true
: activity
)
return (
<ActivityBlock>
<ActivityFilter>
<FlexDiv>
<FilterBtn onClick={() => setFilter('')}>All</FilterBtn>
<FilterBtn onClick={() => setFilter('mention')}>Mentions</FilterBtn>
<FilterBtn onClick={() => setFilter('reply')}>Replies</FilterBtn>
<FilterBtn onClick={() => setFilter('request')}>
Contact requests
</FilterBtn>
</FlexDiv>
<Btns>
<BtnWrapper>
<ActivityBtn
onClick={() => activityDispatch({ type: 'setAllAsRead' })}
>
<ReadIcon />
</ActivityBtn>
<Tooltip tip="Mark all as Read" />
</BtnWrapper>
<BtnWrapper>
<ActivityBtn onClick={() => setHideRead(!hideRead)}>
{hideRead ? <ShowIcon /> : <HideIcon />}
</ActivityBtn>
<Tooltip tip={hideRead ? 'Show read' : 'Hide read'} />
</BtnWrapper>
</Btns>
</ActivityFilter>
{filteredActivities.length > 0 ? (
<Activities>
{filteredActivities.map(activity => (
<ActivityMessage
key={activity.id}
activity={activity}
setShowActivityCenter={setShowActivityCenter}
activityDispatch={activityDispatch}
/>
))}
</Activities>
) : (
<EmptyActivities>Notifications will appear here</EmptyActivities>
)}
</ActivityBlock>
)
}
const ActivityBlock = styled.div`
width: 600px;
height: 770px;
display: flex;
flex-direction: column;
background: ${({ theme }) => theme.bodyBackgroundColor};
box-shadow: 0px 12px 24px rgba(0, 34, 51, 0.1);
border-radius: 8px;
position: absolute;
top: calc(100% + 4px);
right: 0;
z-index: 100;
`
const ActivityFilter = styled.div`
display: flex;
justify-content: space-between;
padding: 13px 16px;
`
export const FlexDiv = styled.div`
display: flex;
`
const FilterBtn = styled.button`
${buttonTransparentStyles}
& + & {
margin-left: 8px;
}
`
const BtnWrapper = styled.div`
position: relative;
&:hover > div {
visibility: visible;
}
`
export const ActivityBtn = styled.button`
width: 32px;
height: 32px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 8px;
align-self: center;
&:hover {
background: ${({ theme }) => theme.buttonBgHover};
}
&.read {
&:hover {
background: ${({ theme }) => theme.bodyBackgroundColor};
}
}
&.accept {
&:hover {
background: rgba(78, 188, 96, 0.1);
}
}
&.decline {
&:hover {
background: rgba(255, 45, 85, 0.1);
}
}
& + & {
margin-left: 8px;
}
`
const Activities = styled.div`
display: flex;
flex-direction: column;
width: 100%;
overflow: auto;
`
const EmptyActivities = styled.div`
display: flex;
justify-content: center;
align-items: center;
flex: 1;
width: 100%;
color: ${({ theme }) => theme.secondary};
`
const Btns = styled.div`
display: flex;
align-items: center;
`

View File

@ -1,389 +0,0 @@
// @ts-nocheck
import React, { useEffect, useMemo, useRef, useState } from 'react'
import styled from 'styled-components'
import { useMessengerContext } from '../../contexts/messengerProvider'
import { useModal } from '../../contexts/modalProvider'
import { useScrollToMessage } from '../../contexts/scrollProvider'
import { useClickOutside } from '../../hooks/useClickOutside'
import { equalDate } from '../../utils/equalDate'
import { DownloadButton } from '../Buttons/DownloadButton'
import { Mention } from '../Chat-legacy/ChatMessageContent'
import { Logo } from '../CommunityIdentity'
import { ContactMenu } from '../Form/ContactMenu'
import { Tooltip } from '../Form/Tooltip'
import { CheckIcon } from '../Icons/CheckIcon'
import { ClearSvg } from '../Icons/ClearIcon'
import { CommunityIcon } from '../Icons/CommunityIcon'
import { GroupIcon } from '../Icons/GroupIcon'
import { MoreIcon } from '../Icons/MoreIcon'
import { ReadMessageIcon } from '../Icons/ReadMessageIcon'
import { ReplyIcon } from '../Icons/ReplyActivityIcon'
import { UntrustworthIcon } from '../Icons/UntrustworthIcon'
import { UserIcon } from '../Icons/UserIcon'
import {
ContentWrapper,
DateSeparator,
MessageHeaderWrapper,
MessageOuterWrapper,
MessageText,
TimeWrapper,
UserAddress,
UserName,
UserNameWrapper,
} from '../Messages/Styles'
import { ProfileModalName } from '../Modals/ProfileModal'
import { textMediumStyles, textSmallStyles } from '../Text'
import { ActivityBtn, FlexDiv } from './ActivityCenter'
import type { ActivityAction } from '../../hooks/useActivities'
import type { Activity } from '../../models/Activity'
const today = new Date()
type ActivityMessageProps = {
activity: Activity
setShowActivityCenter: (val: boolean) => void
activityDispatch: React.Dispatch<ActivityAction>
}
export function ActivityMessage({
activity,
setShowActivityCenter,
activityDispatch,
}: ActivityMessageProps) {
const { contacts, channelsDispatch } = useMessengerContext()
const scroll = useScrollToMessage()
const { setModal } = useModal(ProfileModalName)
const showChannel = () => {
'channel' in activity &&
channelsDispatch({ type: 'ChangeActive', payload: activity.channel.id }),
setShowActivityCenter(false)
}
const [showMenu, setShowMenu] = useState(false)
const type = activity.type
const contact = useMemo(
() => contacts[activity.user],
[activity.user, contacts]
)
const [elements, setElements] = useState<
(string | React.ReactElement | undefined)[]
>(['message' in activity ? activity.message?.content : undefined])
useEffect(() => {
if ('message' in activity) {
const split = activity.message?.content.split(' ')
const newSplit = split.flatMap((element, idx) => {
if (element.startsWith('@')) {
return [
<Mention
key={idx}
id={element}
setMentioned={() => true}
className="activity"
/>,
' ',
]
}
return [element, ' ']
})
newSplit.pop()
setElements(newSplit)
}
}, [activity])
const ref = useRef(null)
useClickOutside(ref, () => setShowMenu(false))
return (
<MessageOuterWrapper>
<ActivityDate>
{equalDate(activity.date, today)
? 'Today'
: activity.date.toLocaleDateString()}
</ActivityDate>
<MessageWrapper className={`${!activity.isRead && 'unread'}`}>
<>
<UserIcon />
<ActivityContent>
<MessageHeaderWrapper>
<UserNameWrapper>
<ActivityUserName
onClick={() => {
setModal({
id: activity.user,
renamingState: false,
requestState: false,
})
}}
>
{' '}
{contact?.customName ?? activity.user.slice(0, 10)}
</ActivityUserName>
{contact?.customName && (
<UserAddress>
{activity.user.slice(0, 5)}...{activity.user.slice(-3)}
</UserAddress>
)}
{contact.isUntrustworthy && <UntrustworthIcon />}
</UserNameWrapper>
<TimeWrapper>
{activity.date.toLocaleString('en-US', {
hour: 'numeric',
minute: 'numeric',
hour12: true,
})}
</TimeWrapper>
</MessageHeaderWrapper>
{type === 'request' && (
<ContextHeading>
Contact request
{activity.requestType === 'outcome'
? ` to ${activity.user.slice(0, 10)}`
: ': '}
</ContextHeading>
)}
{type === 'invitation' && (
<FlexDiv>
<ContextHeading>{`Invited you to join a community `}</ContextHeading>
<Tag>
<CommunityIcon width={17} height={16} />
<CommunityLogo
style={{
backgroundImage: activity.invitation?.icon
? `url(${activity.invitation?.icon}`
: '',
}}
>
{activity.invitation?.icon === undefined &&
activity.invitation?.name.slice(0, 1).toUpperCase()}
</CommunityLogo>
<span>{activity.invitation?.name}</span>
</Tag>
</FlexDiv>
)}
<ActivityText>
{'message' in activity && activity.message?.content && (
// TODO: Check if broken (was a div)
<button
onClick={() => {
scroll(activity.message, activity.channel.id)
setShowActivityCenter(false)
}}
>
{elements.map(el => el)}
</button>
)}
{activity.type === 'request' &&
activity.requestType === 'income' &&
activity.request}
</ActivityText>
{type === 'mention' &&
activity.channel &&
activity.channel.type !== 'dm' && (
<Tag onClick={showChannel}>
{activity.channel.type === 'group' ? <GroupIcon /> : '#'}{' '}
<span>{` ${activity.channel.name.slice(0, 10)}`}</span>
</Tag>
)}
{type === 'reply' && activity.quote && (
<ReplyWrapper>
{activity.quote.image && (
<ContextHeading>Posted an image in</ContextHeading>
)}
<Tag onClick={showChannel}>
<ReplyIcon /> <span>{activity.quote.content}</span>
</Tag>
</ReplyWrapper>
)}
{type === 'invitation' && (
<InviteDiv>
<ContextHeading>{`To access other communities, `}</ContextHeading>
<DownloadButton className="activity" />
</InviteDiv>
)}
</ActivityContent>
</>
{type === 'request' &&
!activity.status &&
activity.requestType === 'income' && (
<>
<ActivityBtn
onClick={() => {
activityDispatch({
type: 'setStatus',
payload: { id: activity.id, status: 'accepted' },
})
}}
className="accept"
>
<CheckIcon width={20} height={20} className="accept" />
</ActivityBtn>
<ActivityBtn
onClick={() => {
activityDispatch({
type: 'setStatus',
payload: { id: activity.id, status: 'declined' },
})
}}
className="decline"
>
<ClearSvg width={20} height={20} className="decline" />
</ActivityBtn>
<ActivityBtn
onClick={() => {
setShowMenu(e => !e)
}}
ref={ref}
>
{showMenu && (
<ContactMenu id={activity.user} setShowMenu={setShowMenu} />
)}
<MoreIcon />
</ActivityBtn>
</>
)}
{type === 'request' && activity.status === 'accepted' && (
<RequestStatus className="accepted">Accepted</RequestStatus>
)}
{type === 'request' && activity.status === 'declined' && (
<RequestStatus className="declined">Declined</RequestStatus>
)}
{type === 'request' && activity.status === 'sent' && (
<RequestStatus>Sent</RequestStatus>
)}
{(type === 'mention' || type === 'reply') && (
<BtnWrapper>
<ActivityBtn
onClick={() =>
activityDispatch({ type: 'setAsRead', payload: activity.id })
}
className={`${activity.isRead && 'read'}`}
>
<ReadMessageIcon isRead={activity.isRead} />
</ActivityBtn>
<Tooltip tip="Mark Read" className="read" />
</BtnWrapper>
)}
</MessageWrapper>
</MessageOuterWrapper>
)
}
const InviteDiv = styled.div`
display: flex;
margin-top: -4px;
`
const BtnWrapper = styled.div`
position: relative;
&:hover > div {
visibility: visible;
}
`
const ActivityDate = styled(DateSeparator)`
justify-content: flex-start;
padding: 8px 16px;
margin: 0;
`
const MessageWrapper = styled.div`
width: 100%;
display: flex;
align-items: flex-start;
padding: 8px 16px;
&.unread {
background: ${({ theme }) => theme.buttonBgHover};
}
`
const ActivityText = styled(MessageText)`
white-space: unset;
margin-bottom: 8px;
`
const Tag = styled.div`
width: fit-content;
max-width: 200px;
display: flex;
align-items: center;
border: 1px solid ${({ theme }) => theme.secondary};
border-radius: 11px;
padding: 0 6px;
cursor: pointer;
font-weight: 500;
color: ${({ theme }) => theme.secondary};
${textSmallStyles}
& > span {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
`
const ContextHeading = styled.p`
font-style: italic;
color: ${({ theme }) => theme.secondary};
flex-shrink: 0;
white-space: pre-wrap;
${textMediumStyles}
`
const RequestStatus = styled.p`
font-weight: 500;
align-self: center;
text-align: end;
color: ${({ theme }) => theme.secondary};
${textSmallStyles}
&.accepted {
color: ${({ theme }) => theme.greenColor};
}
&.declined {
color: ${({ theme }) => theme.redColor};
}
`
const ActivityContent = styled(ContentWrapper)`
max-width: calc(100% - 80px);
flex: 1;
`
const ActivityUserName = styled(UserName)`
cursor: pointer;
&:hover {
text-decoration: underline;
}
`
const ReplyWrapper = styled.div`
max-width: 100%;
display: flex;
align-items: center;
& > p {
margin-right: 4px;
}
`
const CommunityLogo = styled(Logo)`
width: 16px;
height: 16px;
margin: 0 2px 0 4px;
${textSmallStyles}
`

View File

@ -5,7 +5,7 @@ import { Dialog, Grid, Text } from '~/src/system'
// TODO: Add wallet integration
export const ConnectWalletDialog = () => {
const [wallet, setWallet] = useState<'coinbase' | undefined>()
const [, setWallet] = useState<'coinbase' | undefined>()
// TODO: Add wallet logos
return (

View File

@ -1,25 +1,25 @@
import React from 'react'
import { CreateProfileDialog } from '~/src/components/create-profile-dialog'
import { useLocalStorage } from '~/src/hooks/use-local-storage'
// import { CreateProfileDialog } from '~/src/components/create-profile-dialog'
// import { useLocalStorage } from '~/src/hooks/use-local-storage'
import { useAccount } from '~/src/protocol'
import { Button, Flex } from '~/src/system'
import { DialogTrigger } from '~/src/system/dialog'
// import { DialogTrigger } from '~/src/system/dialog'
import { Grid } from '~/src/system/grid'
import { Heading } from '~/src/system/heading'
// import { ConnectWalletDialog } from './connect-wallet-dialog'
// import { SyncStatusProfileDialog } from './sync-status-profile-dialog'
import { ThrowawayProfileFoundDialog } from './throwaway-profile-found-dialog'
// import { ThrowawayProfileFoundDialog } from './throwaway-profile-found-dialog'
export const GetStarted = () => {
const [throwawayProfile] = useLocalStorage('cipherIdentityt', null)
// const [throwawayProfile] = useLocalStorage('cipherIdentityt', null)
const handleSkip = () => {
// TODO: Add skip logic
}
// const handleSkip = () => {
// // TODO: Add skip logic
// }
const { account, createAccount } = useAccount()
const { createAccount } = useAccount()
return (
<Flex direction="column" align="center" gap={5} css={{ padding: '30px 0' }}>

View File

@ -1,3 +1,4 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import React from 'react'

View File

@ -19,63 +19,6 @@ export type Reactions = {
}
}
interface BaseMessage {
id: string
type: 'text' | 'image' | 'image-text'
contact: {
name: string
imageUrl?: string
}
owner: boolean
pinned: boolean
mention: boolean
reply?: TextReply | ImageReply | ImageTextReply
reactions: Reactions
}
interface TextMessage extends BaseMessage {
type: 'text'
text: string
}
interface ImageMessage extends BaseMessage {
type: 'image'
imageUrl: string
}
interface ImageTextMessage extends BaseMessage {
type: 'image-text'
text: string
imageUrl: string
}
// export type Message = TextMessage | ImageMessage | ImageTextMessage
interface BaseReply {
type: Message['type']
contact: {
name: string
imageUrl?: string
}
}
interface TextReply extends BaseReply {
type: 'text'
text: string
}
interface ImageReply extends BaseReply {
type: 'image'
imageUrl: string
}
interface ImageTextReply extends BaseReply {
type: 'image-text'
text: string
imageUrl: string
}
export type Reply = TextReply | ImageReply | ImageTextReply
export type { Message }
interface Result {

View File

@ -2,9 +2,8 @@ import React from 'react'
import { useChatContext } from '~/src/contexts/chat-context'
import { CrossIcon } from '~/src/icons/cross-icon'
import { ReplyIcon } from '~/src/icons/reply-icon'
import { styled } from '~/src/styles/config'
import { Flex, Icon, IconButton, Image, Text } from '~/src/system'
import { Flex, IconButton, Image, Text } from '~/src/system'
import type { Member, Message } from '~/src/protocol'

View File

@ -6,9 +6,7 @@ interface Props {
name?: string
}
const EmojiHash = (props: Props) => {
const { name } = props
const EmojiHash = () => {
return (
<Base>
🎩🍞🥑🦍🌈📡

View File

@ -12,7 +12,7 @@
"lint": {
"outputs": []
},
"check": {
"typecheck": {
"outputs": []
},
"test": {

View File

@ -2104,7 +2104,7 @@
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.12.1", "@typescript-eslint/utils@^5.10.0":
"@typescript-eslint/utils@5.12.1":
version "5.12.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.12.1.tgz#447c24a05d9c33f9c6c64cb48f251f2371eef920"
integrity sha512-Qq9FIuU0EVEsi8fS6pG+uurbhNTtoYr4fq8tKjBupsK5Bgbk2I32UGm0Sh+WOyjOPgo/5URbxxSNV6HYsxV4MQ==
@ -3248,14 +3248,6 @@ eslint-module-utils@^2.7.2:
debug "^3.2.7"
find-up "^2.1.0"
eslint-plugin-es@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893"
integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==
dependencies:
eslint-utils "^2.0.0"
regexpp "^3.0.0"
eslint-plugin-eslint-comments@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa"
@ -3283,13 +3275,6 @@ eslint-plugin-import@^2.25.2:
resolve "^1.20.0"
tsconfig-paths "^3.12.0"
eslint-plugin-jest@^26.1.1:
version "26.1.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-26.1.1.tgz#7176dd745ef8bca3070263f62cdf112f2dfc9aa1"
integrity sha512-HRKOuPi5ADhza4ZBK5ufyNXy28bXXkib87w+pQqdvBhSTsamndh6sIAKPAUl8y0/n9jSWBdTPslrwtKWqkp8dA==
dependencies:
"@typescript-eslint/utils" "^5.10.0"
eslint-plugin-jsx-a11y@^6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz#cdbf2df901040ca140b6ec14715c988889c2a6d8"
@ -3308,18 +3293,6 @@ eslint-plugin-jsx-a11y@^6.5.1:
language-tags "^1.0.5"
minimatch "^3.0.4"
eslint-plugin-node@^11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d"
integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==
dependencies:
eslint-plugin-es "^3.0.0"
eslint-utils "^2.0.0"
ignore "^5.1.1"
minimatch "^3.0.4"
resolve "^1.10.1"
semver "^6.1.0"
eslint-plugin-react-hooks@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172"
@ -3366,13 +3339,6 @@ eslint-scope@^7.1.1:
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-utils@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
dependencies:
eslint-visitor-keys "^1.1.0"
eslint-utils@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
@ -3380,11 +3346,6 @@ eslint-utils@^3.0.0:
dependencies:
eslint-visitor-keys "^2.0.0"
eslint-visitor-keys@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
eslint-visitor-keys@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
@ -3944,7 +3905,7 @@ ignore@^4.0.6:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
ignore@^5.0.5, ignore@^5.1.1, ignore@^5.1.8, ignore@^5.2.0:
ignore@^5.0.5, ignore@^5.1.8, ignore@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
@ -5864,7 +5825,7 @@ regexp.prototype.flags@^1.3.1:
call-bind "^1.0.2"
define-properties "^1.1.3"
regexpp@^3.0.0, regexpp@^3.2.0:
regexpp@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
@ -5900,7 +5861,7 @@ resolve-from@^4.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
resolve@^1.10.1, resolve@^1.20.0:
resolve@^1.20.0:
version "1.22.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198"
integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==
@ -6022,7 +5983,7 @@ semver@^5.7.0, semver@^5.7.1:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
semver@^6.1.0, semver@^6.3.0:
semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==