Update to new design for avatars: individual/group icons/colors
And two initials.pull/27/head^2
							parent
							
								
									cf16ced91c
								
							
						
					
					
						commit
						8f3e3b7aaf
					
				@ -0,0 +1,22 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 | 
			
		||||
    <!-- Generator: Sketch 51.3 (57544) - http://www.bohemiancoding.com/sketch -->
 | 
			
		||||
    <title>Group/group-28</title>
 | 
			
		||||
    <desc>Created with Sketch.</desc>
 | 
			
		||||
    <defs>
 | 
			
		||||
        <path d="M18.7272727,13.2857143 C20.6890909,13.2857143 22.2609091,11.6585714 22.2609091,9.64285714 C22.2609091,7.62714286 20.6890909,6 18.7272727,6 C16.7654545,6 15.1818182,7.62714286 15.1818182,9.64285714 C15.1818182,11.6585714 16.7654545,13.2857143 18.7272727,13.2857143 Z M9.27272727,13.2857143 C11.2345455,13.2857143 12.8063636,11.6585714 12.8063636,9.64285714 C12.8063636,7.62714286 11.2345455,6 9.27272727,6 C7.31090909,6 5.72727273,7.62714286 5.72727273,9.64285714 C5.72727273,11.6585714 7.31090909,13.2857143 9.27272727,13.2857143 Z M9.27272727,15.7142857 C6.51909091,15.7142857 1,17.135 1,19.9642857 L1,23 L17.5454545,23 L17.5454545,19.9642857 C17.5454545,17.135 12.0263636,15.7142857 9.27272727,15.7142857 Z M18.7272727,15.7142857 C18.3845455,15.7142857 17.9945455,15.7385714 17.5809091,15.775 C18.9518182,16.795 19.9090909,18.1671429 19.9090909,19.9642857 L19.9090909,23 L27,23 L27,19.9642857 C27,17.135 21.4809091,15.7142857 18.7272727,15.7142857 Z" id="path-1"></path>
 | 
			
		||||
        <rect id="path-3" x="0" y="0" width="28" height="28"></rect>
 | 
			
		||||
    </defs>
 | 
			
		||||
    <g id="Group/group-28" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
 | 
			
		||||
        <mask id="mask-2" fill="white">
 | 
			
		||||
            <use xlink:href="#path-1"></use>
 | 
			
		||||
        </mask>
 | 
			
		||||
        <use id="Shape" fill="#000000" fill-rule="nonzero" xlink:href="#path-1"></use>
 | 
			
		||||
        <g id="Color/UI/Black" mask="url(#mask-2)">
 | 
			
		||||
            <mask id="mask-4" fill="white">
 | 
			
		||||
                <use xlink:href="#path-3"></use>
 | 
			
		||||
            </mask>
 | 
			
		||||
            <use id="fill" fill="#000000" fill-rule="evenodd" xlink:href="#path-3"></use>
 | 
			
		||||
        </g>
 | 
			
		||||
    </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 1.9 KiB  | 
@ -0,0 +1,22 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 | 
			
		||||
    <!-- Generator: Sketch 51.3 (57544) - http://www.bohemiancoding.com/sketch -->
 | 
			
		||||
    <title>Profile/profile-28</title>
 | 
			
		||||
    <desc>Created with Sketch.</desc>
 | 
			
		||||
    <defs>
 | 
			
		||||
        <path d="M14,14 C16.7625,14 19,11.7625 19,9 C19,6.2375 16.7625,4 14,4 C11.2375,4 9,6.2375 9,9 C9,11.7625 11.2375,14 14,14 Z M14,16.5 C10.6625,16.5 4,18.175 4,21.5 L4,24 L24,24 L24,21.5 C24,18.175 17.3375,16.5 14,16.5 Z" id="path-1"></path>
 | 
			
		||||
        <rect id="path-3" x="0" y="0" width="28" height="28"></rect>
 | 
			
		||||
    </defs>
 | 
			
		||||
    <g id="Profile/profile-28" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
 | 
			
		||||
        <mask id="mask-2" fill="white">
 | 
			
		||||
            <use xlink:href="#path-1"></use>
 | 
			
		||||
        </mask>
 | 
			
		||||
        <use id="Shape" fill="#000000" fill-rule="nonzero" xlink:href="#path-1"></use>
 | 
			
		||||
        <g id="Color/UI/Black" mask="url(#mask-2)">
 | 
			
		||||
            <mask id="mask-4" fill="white">
 | 
			
		||||
                <use xlink:href="#path-3"></use>
 | 
			
		||||
            </mask>
 | 
			
		||||
            <use id="fill" fill="#000000" fill-rule="evenodd" xlink:href="#path-3"></use>
 | 
			
		||||
        </g>
 | 
			
		||||
    </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
@ -0,0 +1,299 @@
 | 
			
		||||
### With avatar
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="pink"
 | 
			
		||||
  name="John Smith"
 | 
			
		||||
  avatarPath={util.gifObjectUrl}
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="pink"
 | 
			
		||||
  name="Puppies"
 | 
			
		||||
  avatarPath={util.gifObjectUrl}
 | 
			
		||||
  conversationType="group"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### With only name
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="blue"
 | 
			
		||||
  name="John"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="green"
 | 
			
		||||
  name="John Smith"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="red"
 | 
			
		||||
  name="Puppies"
 | 
			
		||||
  conversationType="group"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Just phone number
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="pink"
 | 
			
		||||
  phoneNumber="(555) 353-3433"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### All colors
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="red"
 | 
			
		||||
  name="Red"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="deep_orange"
 | 
			
		||||
  name="Deep Orange"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="brown"
 | 
			
		||||
  name="Broen"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="pink"
 | 
			
		||||
  name="Pink"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="purple"
 | 
			
		||||
  name="Purple"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="indigo"
 | 
			
		||||
  name="Indigo"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="blue"
 | 
			
		||||
  name="Blue"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="Teal"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="green"
 | 
			
		||||
  name="Green"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="light_green"
 | 
			
		||||
  name="Light Green"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="blue_grey"
 | 
			
		||||
  name="Blue Grey"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 36px
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={36}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="John Smith"
 | 
			
		||||
  avatarPath={util.gifObjectUrl}
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={36}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="John"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={36}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="John Smith"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={36}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={36}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="Pupplies"
 | 
			
		||||
  conversationType="group"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 48px
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={48}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="John Smith"
 | 
			
		||||
  avatarPath={util.gifObjectUrl}
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={48}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="John"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={48}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="John Smith"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={48}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={48}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="Pupplies"
 | 
			
		||||
  conversationType="group"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 80px
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={80}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="John Smith"
 | 
			
		||||
  avatarPath={util.gifObjectUrl}
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={80}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="John"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={80}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="John Smith"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={80}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={80}
 | 
			
		||||
  color="teal"
 | 
			
		||||
  name="Pupplies"
 | 
			
		||||
  conversationType="group"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Broken color
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="fake"
 | 
			
		||||
  name="F"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Broken image
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  color="pink"
 | 
			
		||||
  name="John Smith"
 | 
			
		||||
  avatarPath="nonexistent"
 | 
			
		||||
  conversationType="direct"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Broken image for group
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
<Avatar
 | 
			
		||||
  size={28}
 | 
			
		||||
  avatarPath="nonexistent"
 | 
			
		||||
  color="pink"
 | 
			
		||||
  name="Puppies"
 | 
			
		||||
  avatarPath="nonexistent"
 | 
			
		||||
  conversationType="group"
 | 
			
		||||
  i18n={util.i18n}
 | 
			
		||||
/>
 | 
			
		||||
```
 | 
			
		||||
@ -0,0 +1,118 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
 | 
			
		||||
import { getInitials } from '../util/getInitials';
 | 
			
		||||
import { Localizer } from '../types/Util';
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  avatarPath?: string;
 | 
			
		||||
  color?: string;
 | 
			
		||||
  conversationType: 'group' | 'direct';
 | 
			
		||||
  i18n: Localizer;
 | 
			
		||||
  name?: string;
 | 
			
		||||
  phoneNumber?: string;
 | 
			
		||||
  profileName?: string;
 | 
			
		||||
  size: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface State {
 | 
			
		||||
  imageBroken: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class Avatar extends React.Component<Props, State> {
 | 
			
		||||
  public handleImageErrorBound: () => void;
 | 
			
		||||
 | 
			
		||||
  public constructor(props: Props) {
 | 
			
		||||
    super(props);
 | 
			
		||||
 | 
			
		||||
    this.handleImageErrorBound = this.handleImageError.bind(this);
 | 
			
		||||
 | 
			
		||||
    this.state = {
 | 
			
		||||
      imageBroken: false,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public handleImageError() {
 | 
			
		||||
    // tslint:disable-next-line no-console
 | 
			
		||||
    console.log('Avatar: Image failed to load; failing over to placeholder');
 | 
			
		||||
    this.setState({
 | 
			
		||||
      imageBroken: true,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public renderImage() {
 | 
			
		||||
    const { avatarPath, i18n, name, phoneNumber, profileName } = this.props;
 | 
			
		||||
    const { imageBroken } = this.state;
 | 
			
		||||
    const hasImage = avatarPath && !imageBroken;
 | 
			
		||||
 | 
			
		||||
    if (!hasImage) {
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const title = `${name || phoneNumber}${
 | 
			
		||||
      !name && profileName ? ` ~${profileName}` : ''
 | 
			
		||||
    }`;
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <img
 | 
			
		||||
        onError={this.handleImageErrorBound}
 | 
			
		||||
        alt={i18n('contactAvatarAlt', [title])}
 | 
			
		||||
        src={avatarPath}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public renderNoImage() {
 | 
			
		||||
    const { conversationType, name, size } = this.props;
 | 
			
		||||
 | 
			
		||||
    const initials = getInitials(name);
 | 
			
		||||
    const isGroup = conversationType === 'group';
 | 
			
		||||
 | 
			
		||||
    if (!isGroup && initials) {
 | 
			
		||||
      return (
 | 
			
		||||
        <div
 | 
			
		||||
          className={classNames(
 | 
			
		||||
            'module-avatar__label',
 | 
			
		||||
            `module-avatar__label--${size}`
 | 
			
		||||
          )}
 | 
			
		||||
        >
 | 
			
		||||
          {initials}
 | 
			
		||||
        </div>
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div
 | 
			
		||||
        className={classNames(
 | 
			
		||||
          'module-avatar__icon',
 | 
			
		||||
          `module-avatar__icon--${conversationType}`,
 | 
			
		||||
          `module-avatar__icon--${size}`
 | 
			
		||||
        )}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public render() {
 | 
			
		||||
    const { avatarPath, color, size } = this.props;
 | 
			
		||||
    const { imageBroken } = this.state;
 | 
			
		||||
 | 
			
		||||
    const hasImage = avatarPath && !imageBroken;
 | 
			
		||||
 | 
			
		||||
    if (size !== 28 && size !== 36 && size !== 48 && size !== 80) {
 | 
			
		||||
      throw new Error(`Size ${size} is not supported!`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div
 | 
			
		||||
        className={classNames(
 | 
			
		||||
          'module-avatar',
 | 
			
		||||
          `module-avatar--${size}`,
 | 
			
		||||
          hasImage ? 'module-avatar--with-image' : 'module-avatar--no-image',
 | 
			
		||||
          !hasImage ? `module-avatar--${color}` : null
 | 
			
		||||
        )}
 | 
			
		||||
      >
 | 
			
		||||
        {hasImage ? this.renderImage() : this.renderNoImage()}
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,25 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  /**
 | 
			
		||||
   * Corresponds to the theme setting in the app, and the class added to the root element.
 | 
			
		||||
   */
 | 
			
		||||
  theme: 'light-theme' | 'dark-theme';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provides the parent elements necessary to allow the main Signal Desktop stylesheet to
 | 
			
		||||
 * apply (with no changes) to messages in the Style Guide.
 | 
			
		||||
 */
 | 
			
		||||
export class LeftPaneContext extends React.Component<Props> {
 | 
			
		||||
  public render() {
 | 
			
		||||
    const { theme } = this.props;
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div className={classNames(theme || 'light-theme')}>
 | 
			
		||||
        <div className="gutter">{this.props.children}</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,21 @@
 | 
			
		||||
const BAD_CHARACTERS = /[^A-Za-z\s]+/g;
 | 
			
		||||
const WHITESPACE = /\s+/g;
 | 
			
		||||
 | 
			
		||||
function removeNonInitials(name: string) {
 | 
			
		||||
  return name.replace(BAD_CHARACTERS, '').replace(WHITESPACE, ' ');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getInitials(name?: string): string | null {
 | 
			
		||||
  if (!name) {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const cleaned = removeNonInitials(name);
 | 
			
		||||
  const parts = cleaned.split(' ');
 | 
			
		||||
  const initials = parts.map(part => part.trim()[0]);
 | 
			
		||||
  if (!initials.length) {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return initials.slice(0, 2).join('');
 | 
			
		||||
}
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue