From 9b7b42f5669b422c329eddae60a5c9ca020fec5b Mon Sep 17 00:00:00 2001 From: storywithoutend Date: Wed, 17 Apr 2024 11:46:56 +0800 Subject: [PATCH] another checkpoint before design adjustments --- .../Name/utils/calculateWrapName.test.ts | 59 +++++++++++++++-- .../@atoms/Name/utils/calculateWrapName.ts | 64 +++++++++++++------ .../@atoms/Name/utils/sharedFunctions.ts | 1 + src/components/@atoms/Name2/Name.tsx | 39 ++++++++--- .../@atoms/StyledName/StyledName.tsx | 1 - .../AvatarWithIdentifier.tsx | 13 +++- .../TransactionDialogManager/DisplayItems.tsx | 6 +- .../tabs/PermissionsTab/PermissionsTab.tsx | 1 + 8 files changed, 144 insertions(+), 40 deletions(-) diff --git a/src/components/@atoms/Name/utils/calculateWrapName.test.ts b/src/components/@atoms/Name/utils/calculateWrapName.test.ts index 10b652795..96b1a0fdd 100644 --- a/src/components/@atoms/Name/utils/calculateWrapName.test.ts +++ b/src/components/@atoms/Name/utils/calculateWrapName.test.ts @@ -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) => `${char}`).join('') const dom = new JSDOM(`${innerHtml}`) @@ -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), @@ -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) diff --git a/src/components/@atoms/Name/utils/calculateWrapName.ts b/src/components/@atoms/Name/utils/calculateWrapName.ts index 3db62ea93..69abf7d90 100644 --- a/src/components/@atoms/Name/utils/calculateWrapName.ts +++ b/src/components/@atoms/Name/utils/calculateWrapName.ts @@ -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, @@ -33,7 +62,7 @@ export const calculateWrapName = ({ initialWidth = maxWidth, minInitialWidth = 0, maxLines = Infinity, - tolerance = 5, + tolerance = 3, debug = false, }: { name: string @@ -58,19 +87,12 @@ 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 @@ -78,15 +100,19 @@ export const calculateWrapName = ({ 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 @@ -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) } diff --git a/src/components/@atoms/Name/utils/sharedFunctions.ts b/src/components/@atoms/Name/utils/sharedFunctions.ts index 251eddb79..af7b0fe78 100644 --- a/src/components/@atoms/Name/utils/sharedFunctions.ts +++ b/src/components/@atoms/Name/utils/sharedFunctions.ts @@ -1,4 +1,5 @@ export const insertZeroWidthNonJoinerAtLabel = (name: string) => { + if (!name) return const [label, ...rest] = name.split('.') return [`${label}\u200C`, ...rest].join('.') } diff --git a/src/components/@atoms/Name2/Name.tsx b/src/components/@atoms/Name2/Name.tsx index e4223bf2f..33fb862f1 100644 --- a/src/components/@atoms/Name2/Name.tsx +++ b/src/components/@atoms/Name2/Name.tsx @@ -23,6 +23,7 @@ const HiddenSpan = styled.span( pointer-events: none; visibility: hidden; white-space: nowrap; + font-weight: bold; `, ) @@ -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' @@ -42,6 +56,7 @@ type BaseProps = { rootRef?: React.RefObject nextTick?: boolean debug?: boolean + tolerance?: number } type InlineProps = { @@ -70,6 +85,7 @@ export const Name = ({ minInitialWidth, rootRef, nextTick, + tolerance, debug, }: Props) => { if (debug) @@ -91,7 +107,8 @@ export const Name = ({ 'debug', debug, ) - const charArray = children.split('') + const name = children + const charArray = name.split('') const ref = useRef(null) const hiddenRef = useRef(null) @@ -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, }) }) @@ -128,6 +147,7 @@ export const Name = ({ node: hiddenRef.current, ellipsisWidth, maxWidth, + tolerance, debug, }) }) @@ -149,7 +169,7 @@ export const Name = ({ () => '', ) - console.log('name2', name2) + const nameParts = name2?.split('\u200C') return ( @@ -159,7 +179,10 @@ export const Name = ({ {char} ))} - {name2} + + {nameParts?.[0]} + {nameParts?.[1]} + ) } @@ -173,8 +196,8 @@ export const TransComponentName = ({ children?: string[] } & Omit) => { const rootRef = useRef(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 ( diff --git a/src/components/@atoms/StyledName/StyledName.tsx b/src/components/@atoms/StyledName/StyledName.tsx index 2d751a425..ad3642747 100644 --- a/src/components/@atoms/StyledName/StyledName.tsx +++ b/src/components/@atoms/StyledName/StyledName.tsx @@ -9,7 +9,6 @@ const Container = styled.div( font-weight: ${theme.fontWeights.bold}; line-height: 1.36; overflow: hidden; - background: yellow; `, ) diff --git a/src/components/@molecules/AvatarWithIdentifier/AvatarWithIdentifier.tsx b/src/components/@molecules/AvatarWithIdentifier/AvatarWithIdentifier.tsx index 592fd79e8..2a201fc88 100644 --- a/src/components/@molecules/AvatarWithIdentifier/AvatarWithIdentifier.tsx +++ b/src/components/@molecules/AvatarWithIdentifier/AvatarWithIdentifier.tsx @@ -1,3 +1,4 @@ +import { useRef } from 'react' import styled, { css } from 'styled-components' import { Address } from 'viem' @@ -5,6 +6,7 @@ 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' @@ -17,6 +19,8 @@ const Container = styled.div( align-items: center; justify-content: flex-start; gap: ${theme.space['2']}; + position: relative; + overflow: hidden; `, ) @@ -66,18 +70,21 @@ export const AvatarWithIdentifier = ({ const _subtitle = subtitle || (_name ? shortenAddress(address) : undefined) const isTitleFullAddress = !shortenAddressAsTitle && !_name - + const ref = useRef(null) + const { width } = useElementDimensions({ ref }) const remPixelValue = useRemPixelValue() + console.log('remPixelValue', remPixelValue) + console.log('AvatarWithIdentifier', maxWidth, width) return ( - + {isTitleFullAddress ? ( {_title} ) : ( - {_title} + {_title} )} {_subtitle && ( diff --git a/src/components/@molecules/TransactionDialogManager/DisplayItems.tsx b/src/components/@molecules/TransactionDialogManager/DisplayItems.tsx index 20d967577..0c6ff28cd 100644 --- a/src/components/@molecules/TransactionDialogManager/DisplayItems.tsx +++ b/src/components/@molecules/TransactionDialogManager/DisplayItems.tsx @@ -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' @@ -134,7 +135,10 @@ const NameValue = ({ value }: { value: string }) => { return ( - {beautifiedName} + {/* {beautifiedName} */} + + {beautifiedName} + diff --git a/src/components/pages/profile/[name]/tabs/PermissionsTab/PermissionsTab.tsx b/src/components/pages/profile/[name]/tabs/PermissionsTab/PermissionsTab.tsx index 2b6107350..a6428bb81 100644 --- a/src/components/pages/profile/[name]/tabs/PermissionsTab/PermissionsTab.tsx +++ b/src/components/pages/profile/[name]/tabs/PermissionsTab/PermissionsTab.tsx @@ -49,6 +49,7 @@ export const PermissionsTab = ({ name, wrapperData, isCached: isBasicCached }: P const nameParts = name.split('.') const parentName = nameParts.slice(1).join('.') + console.log('>>>', parentName) const is2LDEth = nameParts.length === 2 && nameParts[1] === 'eth' const isSubname = nameParts.length > 2