Skip to content

Commit

Permalink
Adjust QR Code formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
jribbink committed Aug 7, 2024
1 parent 0956294 commit cd23244
Show file tree
Hide file tree
Showing 6 changed files with 349 additions and 26 deletions.
130 changes: 130 additions & 0 deletions components/QRCode.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { Box, Flex, Image } from '@chakra-ui/react'
import { Fragment, memo } from 'react'
import QRCodeLib from 'qrcode'
import NextImage, { StaticImageData } from 'next/image'
import { isDataURL } from '../helpers/urls'
import { convertToPixels } from '../helpers/sizes'

type QRCodeProps = {
value: string
image?: string | StaticImageData
size?: string
imageSize?: string
}

const QRCode = memo(function QRCode({
value,
image,
size,
imageSize,
}: QRCodeProps) {
const qr = QRCodeLib.create(value, {
errorCorrectionLevel: 'H',
})
const modules1D = qr.modules.data
const modules: boolean[][] = []
const length = Math.sqrt(modules1D.length)

// Check if the module is part of the finder pattern
const isFindingPattern = (x: number, y: number) =>
(x < 8 && (y < 8 || y >= length - 8)) || (x >= length - 8 && y < 8)

// Compute the scale factor so we can determine which modules are behind the image
let isModuleBehindImage: (x: number, y: number) => boolean = () => false
if (image) {
const scaleFactor = length / convertToPixels(size)
const imageViewboxSize = convertToPixels(imageSize) * scaleFactor
const imagePadding = 1
const imageTop = Math.floor((length - imageViewboxSize) / 2 - imagePadding)
const imageBottom = Math.ceil(
imageTop + imageViewboxSize + imagePadding * 2,
)
const imageLeft = Math.floor((length - imageViewboxSize) / 2 - imagePadding)
const imageRight = Math.ceil(
imageLeft + imageViewboxSize + imagePadding * 2,
)
isModuleBehindImage = (x: number, y: number) => {
return (
x >= imageTop && x < imageBottom && y >= imageLeft && y < imageRight
)
}
}

for (let i = 0; i < length; i++) {
modules.push(
[...modules1D.slice(i * length, (i + 1) * length)].map((bit, j) => {
return bit && !isFindingPattern(i, j) && !isModuleBehindImage(i, j)
}),
)
}

// Positions of the finder patterns used for custom rendering
const findingPatternPositions = [
[0, 0],
[0, length - 7],
[length - 7, 0],
]

return (
<Box position="relative" width={size} height={size}>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox={`0 0 ${modules.length} ${modules.length}`}
width={size}
height={size}
>
{modules.map((row, y) =>
row.map((cell, x) => (
<circle
key={`${x}-${y}`}
cx={x + 0.5}
cy={y + 0.5}
r={0.4}
fill={cell ? 'black' : 'white'}
/>
)),
)}

{findingPatternPositions.map(([x, y]) => (
<Fragment key={`${x}-${y}`}>
<rect x={x} y={y} width={7} height={7} fill="black" rx={2} ry={2} />

<rect
x={x + 1}
y={y + 1}
width={5}
height={5}
fill="white"
rx={1.5}
ry={1.5}
/>

<rect x={x + 2} y={y + 2} width={3} height={3} fill="black" />
</Fragment>
))}
</svg>
<Flex
position="absolute"
top={0}
left={0}
right={0}
bottom={0}
justifyContent="center"
alignItems="center"
>
{image && (
<Image
as={isDataURL(image as any) ? 'img' : NextImage}
src={image as any}
alt="QR Code"
objectFit="contain"
boxSize={imageSize}
borderRadius="lg"
/>
)}
</Flex>
</Box>
)
})

export default QRCode
4 changes: 2 additions & 2 deletions components/views/ScanConnect.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Box, Stack, Text } from '@chakra-ui/react'
import QRCode from 'react-qr-code'
import { Wallet } from '../../data/wallets'
import { useConfig } from '../../contexts/ConfigContext'
import QRCode from '../QRCode'

interface ScanConnectProps {
wallet: Wallet
Expand All @@ -23,7 +23,7 @@ export default function ScanConnect({ wallet }: ScanConnectProps) {
border="1px"
borderColor="gray.200"
>
<QRCode level="M" value={walletConnectUri} size={300} />
<QRCode value={walletConnectUri} size="300px" />
</Box>
</Stack>
)
Expand Down
4 changes: 2 additions & 2 deletions components/views/ScanInstall.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Box, Button, Stack, Text } from '@chakra-ui/react'
import QRCode from 'react-qr-code'
import { Wallet } from '../../data/wallets'
import QRCode from '../QRCode'

interface ScanInstallProps {
onContinue: () => void
Expand All @@ -22,7 +22,7 @@ export default function ScanInstall({ onContinue, wallet }: ScanInstallProps) {
border="1px"
borderColor="gray.200"
>
<QRCode level="M" value={wallet.installLink?.mobile} size={300} />
<QRCode value={wallet.installLink?.mobile} size="300px" />
</Box>

<Button
Expand Down
24 changes: 24 additions & 0 deletions helpers/sizes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export function convertToPixels(
size: string,
context = document.documentElement,
) {
// Create a temporary element
const tempEl = document.createElement('div')

// Set the element's style
tempEl.style.width = size
tempEl.style.position = 'absolute'
tempEl.style.visibility = 'hidden'

// Append the element to the context (usually the document or a specific element)
context.appendChild(tempEl)

// Get the computed width in pixels
const pixels = window.getComputedStyle(tempEl).width

// Remove the temporary element
context.removeChild(tempEl)

// Return the width as a number (parseFloat removes the 'px' unit)
return parseFloat(pixels)
}
Loading

0 comments on commit cd23244

Please sign in to comment.