Skip to content

Commit

Permalink
another checkpoint before design adjustments
Browse files Browse the repository at this point in the history
  • Loading branch information
storywithoutend committed Apr 17, 2024
1 parent 6a2b1bc commit 9b7b42f
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 40 deletions.
59 changes: 52 additions & 7 deletions src/components/@atoms/Name/utils/calculateWrapName.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { describe, it, expect } from 'vitest'
import { calculateWrapName, findNumbersAddingUpToSum, sliceStringByNumbers } from './calculateWrapName'
import { calculateWrapName, findNumbersAddingUpToSum, insertSpecialSymbols, sliceStringByNumbers } from './calculateWrapName'
import { insertZeroWidthNonJoinerAtLabel } from './sharedFunctions'
const jsdom = require('jsdom')
const { JSDOM } = jsdom

const longName = 'areallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongname.eth'

const createNode = (str: string) => {
const innerHtml = str.split('').map((char) => `<span>${char}</span>`).join('')
const dom = new JSDOM(`<span id="root">${innerHtml}</span>`)
Expand Down Expand Up @@ -64,9 +67,51 @@ describe('sliceStringByNumbers', () => {
})
})

describe('injectSpecialSymbols', () => {
const label = 'onetwothreefourfivesixseveneightnine'
const name = `${label}.eth`
const subname = `${label}.${name}`

it('should return name if array is slices is single value', () => {
const nameWithZWNJ = insertZeroWidthNonJoinerAtLabel(name)
const result = insertSpecialSymbols(nameWithZWNJ, [name.length])
expect(result).toEqual(nameWithZWNJ)
})

it('should return correct an ellipsis string ', () => {
const nameWithZWNJ = insertZeroWidthNonJoinerAtLabel(name)
const result = insertSpecialSymbols(nameWithZWNJ, [5,5])
expect(result).toEqual('onetw\u2026\u200Be\u200C.eth')
})

it('should return correct an ellipsis string ', () => {
const nameWithZWNJ = insertZeroWidthNonJoinerAtLabel(name)
const result = insertSpecialSymbols(nameWithZWNJ, [5,5,5])
expect(result).toEqual('onetw\u2026\u200Bothre\u2026\u200Be\u200C.eth')
})

it('should return correct an ellipsis string ', () => {
const nameWithZWNJ = insertZeroWidthNonJoinerAtLabel(name)
const result = insertSpecialSymbols(nameWithZWNJ, [10,10,10,10])
expect(result).toEqual('onetwothre\u2026\u200Befourfives\u2026\u200Bixseveneig\u2026\u200Bhtnine\u200C.eth')
})

it('should return correct result if ZWNJ is on left side', () => {
const nameWithZWNJ = insertZeroWidthNonJoinerAtLabel(`123.${name}`)
const result = insertSpecialSymbols(nameWithZWNJ, [5,5])
expect(result).toEqual('123\u200C.o\u2026\u200Be.eth')
})

it('should return correct result if ZWNJ is in middle side', () => {
const nameWithZWNJ = insertZeroWidthNonJoinerAtLabel(subname)
const result = insertSpecialSymbols(nameWithZWNJ, [5,5])
expect(result).toEqual('onetw\u2026\u200B\u200Ce.eth')
})

})

describe('calculateWrapName', () => {
const longName = 'areallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongname.eth'
it.only('should return the correct result', () => {
it('should return the correct result', () => {
const result = calculateWrapName({
name: longName,
node: createNode(longName),
Expand All @@ -84,17 +129,17 @@ describe('calculateWrapName', () => {
expect(resultParts[3]).toHaveLength(longName.length - 19 - 99 - 99)
})

it('should return the correct result', () => {
it.only('should return the correct result', () => {
const result = calculateWrapName({
name: longName,
node: createNode(longName),
ellipsisWidth: 5,
initialWidth: 100,
maxWidth: 500,
maxLines: 2
maxLines: 2,
debug: true
})
expect(result).toEqual('areallyreallyreally…​allyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongname\u200C.eth')
console.log('areallyreallyreally…​llyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongname‌.eth')
expect(result).toEqual('areallyreallyreall…​allyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongname\u200C.eth')
const resultParts = result.split('…​')
expect(resultParts[0]).toHaveLength(19)
expect(resultParts[1]).toHaveLength(100)
Expand Down
64 changes: 44 additions & 20 deletions src/components/@atoms/Name/utils/calculateWrapName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,35 @@ export const sliceStringByNumbers = (numbers: number[], str: string): string[] =
return result
}

const sliceByLengthAndDirection = (str: string, start: number, length: number, reverse: boolean) =>
reverse ? str.slice(-length) : str.slice(start, start + length)

export const insertSpecialSymbols = (name: string, slices: number[]): string => {
let slicedName = ''
let sliceStart = 0
let hasFoundZWNJ = false

for (let i = 0; i < slices.length; i += 1) {
const isLastSlice = i === slices.length - 1
const sliceLength = slices[i]
const slice = sliceByLengthAndDirection(name, sliceStart, sliceLength, isLastSlice)

const sliceContainsZWNJ = slice.includes('\u200C')
const adjustedSliceLength = sliceContainsZWNJ ? sliceLength + 1 : sliceLength
const adjustedSlice = sliceContainsZWNJ
? sliceByLengthAndDirection(name, sliceStart, adjustedSliceLength, isLastSlice)
: slice

hasFoundZWNJ = hasFoundZWNJ || sliceContainsZWNJ
const prefix = isLastSlice && !hasFoundZWNJ ? '\u200C' : ''
const postfix = isLastSlice ? '' : '…\u200B'

sliceStart += adjustedSliceLength
slicedName += `${prefix}${adjustedSlice}${postfix}`
}
return slicedName
}

export const calculateWrapName = ({
name,
node,
Expand All @@ -33,7 +62,7 @@ export const calculateWrapName = ({
initialWidth = maxWidth,
minInitialWidth = 0,
maxLines = Infinity,
tolerance = 5,
tolerance = 3,
debug = false,
}: {
name: string
Expand All @@ -58,35 +87,32 @@ export const calculateWrapName = ({
maxLines,
)

const name_ = insertZeroWidthNonJoinerAtLabel(name)
const name_ = insertZeroWidthNonJoinerAtLabel(name) || ''
if (!node) {
console.error('node is null')
return name_
}

const _maxWdth = maxWidth ?? node.parentElement?.offsetWidth ?? Infinity
const containerWidth = node.offsetWidth || Infinity
if (containerWidth <= _maxWdth) return name_

let currentGroup: number[] = []
let currentGroupTotal = 0
let result: number[][] = []
return name_ || ''
}

const initialWidth_ = initialWidth < minInitialWidth ? maxWidth : initialWidth

const decimalTolerance = 1 - Math.max(0, Math.min(100, tolerance)) / 100
const initialWidthWithTolerance = initialWidth_ * decimalTolerance
const maxWidthWithTolerance = maxWidth * decimalTolerance

let currentGroup: number[] = []
let currentGroupTotal = 0
let result: number[][] = []
console.log('testing', maxWidth, maxWidthWithTolerance)
const children = node?.children || []
for (let index = 0; index < children.length; index += 1) {
const element = children[index] as HTMLSpanElement
const charWidth = element.offsetWidth
currentGroupTotal += charWidth
const currentMaxWidth = result.length === 0 ? initialWidthWithTolerance : maxWidthWithTolerance
if (debug)
console.log('charWidth', charWidth, 'currentGroupTotal', currentGroupTotal, currentMaxWidth)
if (currentGroupTotal + ellipsisWidth >= currentMaxWidth) {
// if (debug)
// console.log('charWidth', charWidth, 'currentGroupTotal', currentGroupTotal, currentMaxWidth)
if (currentGroupTotal + ellipsisWidth > currentMaxWidth) {
result.push(currentGroup)
currentGroup = [charWidth]
currentGroupTotal = charWidth
Expand All @@ -104,14 +130,12 @@ export const calculateWrapName = ({
.reverse()
.flat()
// console.log('left', left, right)
const filteredRight = findNumbersAddingUpToSum(right, maxWidth)
const filteredRight = findNumbersAddingUpToSum(right, maxWidthWithTolerance)
result = [...left, filteredRight]
}

const slices = result.map((group) => group.length)
const [last, ...reversedFirstSegments] = slices.reverse()
const firstSegments = reversedFirstSegments.reverse()
const firstNames = sliceStringByNumbers(firstSegments, name_)
const lastSegment = name_.slice(-last)
return [...firstNames, lastSegment].join('\u2026\u200B')
console.log('slices', slices)

return insertSpecialSymbols(name_, slices)
}
1 change: 1 addition & 0 deletions src/components/@atoms/Name/utils/sharedFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const insertZeroWidthNonJoinerAtLabel = (name: string) => {
if (!name) return
const [label, ...rest] = name.split('.')
return [`${label}\u200C`, ...rest].join('.')
}
39 changes: 31 additions & 8 deletions src/components/@atoms/Name2/Name.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const HiddenSpan = styled.span(
pointer-events: none;
visibility: hidden;
white-space: nowrap;
font-weight: bold;
`,
)

Expand All @@ -32,6 +33,19 @@ const VisibleSpan = styled.span<{ type: 'wrap' | 'inline' }>(
`,
)

const LeadSpan = styled.span(
() => css`
/* font-weight: bold; */
`,
)

const TrailingSpan = styled.span(
({ theme }) => css`
color: ${theme.colors.textTertiary};
/* font-weight: bold; */
`,
)

type BaseProps = {
children: string
type: 'wrap' | 'inline'
Expand All @@ -42,6 +56,7 @@ type BaseProps = {
rootRef?: React.RefObject<HTMLDivElement>
nextTick?: boolean
debug?: boolean
tolerance?: number
}

type InlineProps = {
Expand Down Expand Up @@ -70,6 +85,7 @@ export const Name = ({
minInitialWidth,
rootRef,
nextTick,
tolerance,
debug,
}: Props) => {
if (debug)
Expand All @@ -91,7 +107,8 @@ export const Name = ({
'debug',
debug,
)
const charArray = children.split('')
const name = children
const charArray = name.split('')

const ref = useRef<HTMLDivElement>(null)
const hiddenRef = useRef<HTMLSpanElement>(null)
Expand All @@ -110,14 +127,16 @@ export const Name = ({
const rootLeft = rootOrComponentRef.current?.offsetParent?.getBoundingClientRect().left ?? 0
const initialWidth_ = initialWidth ?? maxWidth_ - hiddenLeft + rootLeft

console.log('maxWidth_', maxWidth_, initialWidth_)
return calculateWrapName({
name_: children,
name: children,
node: hiddenRef.current,
ellipsisWidth,
maxWidth: Math.round(maxWidth_ * 0.95),
initialWidth: Math.round(initialWidth_ * 0.95),
maxWidth: maxWidth_,
initialWidth: initialWidth_,
minInitialWidth,
maxLines: wrapLines,
tolerance,
debug,
})
})
Expand All @@ -128,6 +147,7 @@ export const Name = ({
node: hiddenRef.current,
ellipsisWidth,
maxWidth,
tolerance,
debug,
})
})
Expand All @@ -149,7 +169,7 @@ export const Name = ({
() => '',
)

console.log('name2', name2)
const nameParts = name2?.split('\u200C')
return (
<Container ref={ref}>
<HiddenSpan ref={ellipsisRef}></HiddenSpan>
Expand All @@ -159,7 +179,10 @@ export const Name = ({
<span key={`${i}`}>{char}</span>
))}
</HiddenSpan>
<VisibleSpan type={type}>{name2}</VisibleSpan>
<VisibleSpan type={type}>
<LeadSpan>{nameParts?.[0]}</LeadSpan>
<TrailingSpan>{nameParts?.[1]}</TrailingSpan>
</VisibleSpan>
</Container>
)
}
Expand All @@ -173,8 +196,8 @@ export const TransComponentName = ({
children?: string[]
} & Omit<Props, 'children'>) => {
const rootRef = useRef<HTMLDivElement>(null)
const name = children?.[0] || ''
console.log('TRANS COMPONENT NAME', name, children)
const name = Array.isArray(children) ? children[0] : children
console.log('TRANS COMPONENT NAME', 'name', name, 'children', children)
if (href) {
return (
<StyledLink href={href} ref={rootRef}>
Expand Down
1 change: 0 additions & 1 deletion src/components/@atoms/StyledName/StyledName.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const Container = styled.div(
font-weight: ${theme.fontWeights.bold};
line-height: 1.36;
overflow: hidden;
background: yellow;
`,
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useRef } from 'react'
import styled, { css } from 'styled-components'
import { Address } from 'viem'

import { Typography } from '@ensdomains/thorin'

import { Name } from '@app/components/@atoms/Name2/Name'
import { AvatarWithZorb } from '@app/components/AvatarWithZorb'
import { useElementDimensions } from '@app/hooks/dom/useElementDimensions'
import { useRemPixelValue } from '@app/hooks/dom/useRemPixelValue'
import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName'
import { QuerySpace } from '@app/types'
Expand All @@ -17,6 +19,8 @@ const Container = styled.div(
align-items: center;
justify-content: flex-start;
gap: ${theme.space['2']};
position: relative;
overflow: hidden;
`,
)

Expand Down Expand Up @@ -66,18 +70,21 @@ export const AvatarWithIdentifier = ({
const _subtitle = subtitle || (_name ? shortenAddress(address) : undefined)

const isTitleFullAddress = !shortenAddressAsTitle && !_name

const ref = useRef<HTMLDivElement>(null)
const { width } = useElementDimensions({ ref })
const remPixelValue = useRemPixelValue()

console.log('remPixelValue', remPixelValue)
console.log('AvatarWithIdentifier', maxWidth, width)
return (
<Container>
<Container ref={ref}>
<AvatarWithZorb label={_title} address={address} name={_name} size={size} />
<TextContainer>
{isTitleFullAddress ? (
<AddressTitleContainer data-testid="avatar-label-title">{_title}</AddressTitleContainer>
) : (
<Typography fontVariant="bodyBold" data-testid="avatar-label-title">
<Name maxWidth={maxWidth! - 3 * remPixelValue}>{_title}</Name>
<Name maxWidth={width! - 3 * remPixelValue}>{_title}</Name>
</Typography>
)}
{_subtitle && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Address } from 'viem'

import { Typography } from '@ensdomains/thorin'

import { Name } from '@app/components/@atoms/Name2/Name'
import { AvatarWithZorb, NameAvatar } from '@app/components/AvatarWithZorb'
import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName'
import { useBeautifiedName } from '@app/hooks/useBeautifiedName'
Expand Down Expand Up @@ -134,7 +135,10 @@ const NameValue = ({ value }: { value: string }) => {

return (
<ValueWithAvatarContainer>
<ValueTypography fontVariant="bodyBold">{beautifiedName}</ValueTypography>
{/* <ValueTypography fontVariant="bodyBold">{beautifiedName}</ValueTypography> */}
<Name type="wrap" maxWidth={300} initialWidth={300} wrapLines={2}>
{beautifiedName}
</Name>
<AvatarWrapper>
<NameAvatar name={value} label={`${value}-avatar`} />
</AvatarWrapper>
Expand Down
Loading

0 comments on commit 9b7b42f

Please sign in to comment.