diff --git a/app/package.json b/app/package.json index 099ae619..237046b5 100644 --- a/app/package.json +++ b/app/package.json @@ -57,7 +57,7 @@ "react-icons": "^5.2.1", "react-markdown": "^8.0.7", "react-parallax-tilt": "^1.7.146", - "react-qr-code": "^2.0.12", + "react-qrcode-logo": "^3.0.0", "react-router-dom": "^6.11.0", "react-syntax-highlighter": "^15.5.0", "react-use-websocket": "^4.3.1", diff --git a/app/src/components/Profile.tsx b/app/src/components/Profile.tsx index fc610bae..24ca5123 100644 --- a/app/src/components/Profile.tsx +++ b/app/src/components/Profile.tsx @@ -1,4 +1,17 @@ -import { Box, Button, Typography, Link, Skeleton, useTheme, alpha } from '@mui/material' +import { + Box, + Button, + Typography, + Link, + Skeleton, + useTheme, + alpha, + Menu, + MenuItem, + ListItemIcon, + ListItemText, + Modal +} from '@mui/material' import { CCAvatar } from '../components/ui/CCAvatar' import { WatchButton } from '../components/WatchButton' @@ -6,7 +19,7 @@ import { AckButton } from '../components/AckButton' import { MarkdownRenderer } from '../components/ui/MarkdownRenderer' import { Link as NavLink } from 'react-router-dom' - +import Tilt from 'react-parallax-tilt' import { useEffect, useMemo, useState } from 'react' import { type User } from '@concrnt/worldlib' import { type CCDocument, type Profile as TypeProfile } from '@concrnt/client' @@ -24,6 +37,10 @@ import { CCIconButton } from './ui/CCIconButton' import ReplayIcon from '@mui/icons-material/Replay' import SearchIcon from '@mui/icons-material/Search' import { useSearchDrawer } from '../context/SearchDrawer' +import ContentPasteIcon from '@mui/icons-material/ContentPaste' +import QrCodeIcon from '@mui/icons-material/QrCode' +import { ProfileQRCard } from './ui/ProfileQRCard' +import CancelIcon from '@mui/icons-material/Cancel' export interface ProfileProps { user?: User @@ -51,6 +68,8 @@ export function Profile(props: ProfileProps): JSX.Element { const [subProfile, setSubProfile] = useState | null>(null) const { t } = useTranslation('', { keyPrefix: 'common' }) + const [shareMenuAnchor, setShareMenuAnchor] = useState(null) + const [openQR, setOpenQR] = useState(false) useEffect(() => { let unmounted = false @@ -139,12 +158,15 @@ export function Profile(props: ProfileProps): JSX.Element { backgroundColor: alpha(theme.palette.primary.main, 0.7) } }} - onClick={() => { + onClick={(e) => { + setShareMenuAnchor(e.currentTarget) + /* if (props.user) { const id = props.user.alias ?? props.user.ccid navigator.clipboard.writeText('https://concrnt.world/' + id) enqueueSnackbar('リンクをコピーしました', { variant: 'success' }) } + */ }} > } + { + setShareMenuAnchor(null) + }} + > + { + if (props.user) { + const id = props.user.alias ?? props.user.ccid + navigator.clipboard.writeText('https://concrnt.world/' + id) + enqueueSnackbar('リンクをコピーしました', { variant: 'success' }) + setShareMenuAnchor(null) + } + }} + > + + + + Copy Share Link + + { + setOpenQR(true) + setShareMenuAnchor(null) + }} + > + + + + Show QR Code + + + { + setOpenQR(false) + }} + slotProps={{ + backdrop: { + sx: { + backgroundColor: 'background.default' + } + } + }} + > + { + if (e.target === e.currentTarget) setOpenQR(false) + }} + > + + {props.user && ( + + + + )} + + { + setOpenQR(false) + }} + > + + + + {props.user && ( { + const theme = useTheme() + + return ( + + + + + + + + + + + + + + {props.user?.profile?.username} + + {props.user?.alias && ( + + @{props.user.alias} + + )} + + + + + + {props.user.ccid} + + concrnt.world + + + ) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 659d2394..5012e32c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -171,9 +171,9 @@ importers: react-parallax-tilt: specifier: ^1.7.146 version: 1.7.146(react-dom@18.2.0)(react@18.2.0) - react-qr-code: - specifier: ^2.0.12 - version: 2.0.12(react@18.2.0) + react-qrcode-logo: + specifier: ^3.0.0 + version: 3.0.0(react-dom@18.2.0)(react@18.2.0) react-router-dom: specifier: ^6.11.0 version: 6.11.0(react-dom@18.2.0)(react@18.2.0) @@ -6660,6 +6660,11 @@ packages: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} dev: false + /lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. + dev: false + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -7492,8 +7497,8 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - /qr.js@0.0.0: - resolution: {integrity: sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==} + /qrcode-generator@1.4.4: + resolution: {integrity: sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==} dev: false /raf@3.4.1: @@ -7665,18 +7670,16 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /react-qr-code@2.0.12(react@18.2.0): - resolution: {integrity: sha512-k+pzP5CKLEGBRwZsDPp98/CAJeXlsYRHM2iZn1Sd5Th/HnKhIZCSg27PXO58zk8z02RaEryg+60xa4vyywMJwg==} + /react-qrcode-logo@3.0.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-2+vZ3GNBdUpYxIKyt6SFZsDGXa0xniyUQ0wPI4O0hJTzRjttPIx1pPnH9IWQmp/4nDMoN47IBhi3Breu1KudYw==} peerDependencies: - react: ^16.x || ^17.x || ^18.x - react-native-svg: '*' - peerDependenciesMeta: - react-native-svg: - optional: true + react: '>=18.0.0' + react-dom: '>=18.0.0' dependencies: - prop-types: 15.8.1 - qr.js: 0.0.0 + lodash.isequal: 4.5.0 + qrcode-generator: 1.4.4 react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) dev: false /react-router-dom@6.11.0(react-dom@18.2.0)(react@18.2.0):