diff --git a/ts/components/Avatar.md b/ts/components/Avatar.md
deleted file mode 100644
index abedd4bf5..000000000
--- a/ts/components/Avatar.md
+++ /dev/null
@@ -1,468 +0,0 @@
-### With avatar
-
-```jsx
-
-
-
-
-
-
- console.log('onClick')}
- i18n={util.i18n}
- />
- console.log('onClick')}
- i18n={util.i18n}
- />
- console.log('onClick')}
- i18n={util.i18n}
- />
-
-```
-
-### With only name
-
-```jsx
-
-
-
-
-```
-
-### Just phone number
-
-```jsx
-
-
-
-```
-
-### Letters
-
-```jsx
-
-
-
-
-
-
- console.log('onClick')}
- i18n={util.i18n}
- />
- console.log('onClick')}
- i18n={util.i18n}
- />
- console.log('onClick')}
- i18n={util.i18n}
- />
-
-```
-
-### Note to self
-
-```jsx
-
-
-
-
-
-
-```
-
-### Group Icon
-
-```jsx
-
-
-
-
-
-
-```
-
-### Contact Icon
-
-```jsx
-
-
-
-
-
-
-```
-
-### All colors, 28px
-
-```jsx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
-
-### 52px
-
-```jsx
-
-
-
-
-
-
-
-```
-
-### 80px
-
-```jsx
-
-
-
-
-
-
-
-```
-
-### 112px
-
-```jsx
-
-
-
-
-
-
-
-```
-
-### Broken color
-
-```jsx
-
-
-
-```
-
-### Broken image
-
-```jsx
-
-
-
-```
-
-### Broken image for group
-
-```jsx
-
-
-
-```
diff --git a/ts/components/Avatar.stories.tsx b/ts/components/Avatar.stories.tsx
new file mode 100644
index 000000000..e80220695
--- /dev/null
+++ b/ts/components/Avatar.stories.tsx
@@ -0,0 +1,126 @@
+import * as React from 'react';
+import { Avatar, Props } from './Avatar';
+
+import { storiesOf } from '@storybook/react';
+import { boolean, select, text } from '@storybook/addon-knobs';
+import { action } from '@storybook/addon-actions';
+
+// @ts-ignore
+import { setup as setupI18n } from '../../js/modules/i18n';
+
+// @ts-ignore
+import enMessages from '../../_locales/en/messages.json';
+import { Colors, ColorType } from '../types/Colors';
+
+const i18n = setupI18n('en', enMessages);
+
+const story = storiesOf('Components/Avatar', module);
+
+const colorMap: Record = Colors.reduce(
+ (m, color) => ({
+ ...m,
+ [color]: color,
+ }),
+ {}
+);
+
+const conversationTypeMap: Record = {
+ direct: 'direct',
+ group: 'group',
+};
+
+const createProps = (overrideProps: Partial = {}): Props => ({
+ avatarPath: text('avatarPath', overrideProps.avatarPath || ''),
+ color: select('color', colorMap, overrideProps.color || 'blue'),
+ conversationType: select(
+ 'conversationType',
+ conversationTypeMap,
+ overrideProps.conversationType || 'direct'
+ ),
+ i18n,
+ name: text('name', overrideProps.name || ''),
+ noteToSelf: boolean('noteToSelf', overrideProps.noteToSelf || false),
+ onClick: action('onClick'),
+ phoneNumber: text('phoneNumber', overrideProps.phoneNumber || ''),
+ size: 80,
+ title: '',
+});
+
+const sizes: Array = [112, 80, 52, 32, 28];
+
+story.add('Avatar', () => {
+ const props = createProps({
+ avatarPath: '/fixtures/giphy-GVNvOUpeYmI7e.gif',
+ });
+
+ return sizes.map(size => );
+});
+
+story.add('One-word Name', () => {
+ const props = createProps({
+ name: 'John',
+ });
+
+ return sizes.map(size => );
+});
+
+story.add('Multi-word Name', () => {
+ const props = createProps({
+ name: 'John Smith',
+ });
+
+ return sizes.map(size => );
+});
+
+story.add('Note to Self', () => {
+ const props = createProps({
+ noteToSelf: true,
+ });
+
+ return sizes.map(size => );
+});
+
+story.add('Contact Icon', () => {
+ const props = createProps();
+
+ return sizes.map(size => );
+});
+
+story.add('Group Icon', () => {
+ const props = createProps({
+ conversationType: 'group',
+ });
+
+ return sizes.map(size => );
+});
+
+story.add('Colors', () => {
+ const props = createProps();
+
+ return Colors.map(color => );
+});
+
+story.add('Broken Color', () => {
+ const props = createProps({
+ color: 'nope' as ColorType,
+ });
+
+ return sizes.map(size => );
+});
+
+story.add('Broken Avatar', () => {
+ const props = createProps({
+ avatarPath: 'badimage.png',
+ });
+
+ return sizes.map(size => );
+});
+
+story.add('Broken Avatar for Group', () => {
+ const props = createProps({
+ avatarPath: 'badimage.png',
+ conversationType: 'group',
+ });
+
+ return sizes.map(size => );
+});
diff --git a/ts/components/Avatar.tsx b/ts/components/Avatar.tsx
index b5bf6e0b7..0e8afde31 100644
--- a/ts/components/Avatar.tsx
+++ b/ts/components/Avatar.tsx
@@ -2,7 +2,8 @@ import * as React from 'react';
import classNames from 'classnames';
import { getInitials } from '../util/getInitials';
-import { ColorType, LocalizerType } from '../types/Util';
+import { LocalizerType } from '../types/Util';
+import { ColorType } from '../types/Colors';
export type Props = {
avatarPath?: string;
diff --git a/ts/components/CallManager.stories.tsx b/ts/components/CallManager.stories.tsx
index 21bd88996..99c59875a 100644
--- a/ts/components/CallManager.stories.tsx
+++ b/ts/components/CallManager.stories.tsx
@@ -1,7 +1,7 @@
import * as React from 'react';
import { CallManager } from './CallManager';
import { CallState } from '../types/Calling';
-import { ColorType } from '../types/Util';
+import { ColorType } from '../types/Colors';
// @ts-ignore
import { setup as setupI18n } from '../../js/modules/i18n';
diff --git a/ts/components/CallScreen.stories.tsx b/ts/components/CallScreen.stories.tsx
index 3c34b6b7e..9f847f8e1 100644
--- a/ts/components/CallScreen.stories.tsx
+++ b/ts/components/CallScreen.stories.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import { CallState } from '../types/Calling';
-import { ColorType } from '../types/Util';
+import { ColorType } from '../types/Colors';
import { CallScreen } from './CallScreen';
// @ts-ignore
diff --git a/ts/components/ContactListItem.tsx b/ts/components/ContactListItem.tsx
index 0438cffa0..6a1428401 100644
--- a/ts/components/ContactListItem.tsx
+++ b/ts/components/ContactListItem.tsx
@@ -5,7 +5,8 @@ import { Avatar } from './Avatar';
import { Emojify } from './conversation/Emojify';
import { InContactsIcon } from './InContactsIcon';
-import { ColorType, LocalizerType } from '../types/Util';
+import { LocalizerType } from '../types/Util';
+import { ColorType } from '../types/Colors';
interface Props {
title: string;
diff --git a/ts/components/ConversationListItem.tsx b/ts/components/ConversationListItem.tsx
index aa303a383..4cad6b6a4 100644
--- a/ts/components/ConversationListItem.tsx
+++ b/ts/components/ConversationListItem.tsx
@@ -9,7 +9,8 @@ import { ContactName } from './conversation/ContactName';
import { TypingAnimation } from './conversation/TypingAnimation';
import { cleanId } from './_util';
-import { ColorType, LocalizerType } from '../types/Util';
+import { LocalizerType } from '../types/Util';
+import { ColorType } from '../types/Colors';
export type PropsData = {
id: string;
diff --git a/ts/components/IncomingCallBar.stories.tsx b/ts/components/IncomingCallBar.stories.tsx
index 30e819dbe..8c7679e80 100644
--- a/ts/components/IncomingCallBar.stories.tsx
+++ b/ts/components/IncomingCallBar.stories.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import { IncomingCallBar } from './IncomingCallBar';
-import { ColorType } from '../types/Util';
+import { Colors, ColorType } from '../types/Colors';
// @ts-ignore
import { setup as setupI18n } from '../../js/modules/i18n';
@@ -31,22 +31,6 @@ const defaultProps = {
i18n,
};
-const colors: Array = [
- 'blue',
- 'blue_grey',
- 'brown',
- 'deep_orange',
- 'green',
- 'grey',
- 'indigo',
- 'light_green',
- 'pink',
- 'purple',
- 'red',
- 'teal',
- 'ultramarine',
-];
-
const permutations = [
{
title: 'Incoming Call Bar (no call details)',
@@ -74,7 +58,7 @@ const permutations = [
storiesOf('Components/IncomingCallBar', module)
.add('Knobs Playground', () => {
- const color = select('color', colors, 'ultramarine');
+ const color = select('color', Colors, 'ultramarine');
const isVideoCall = boolean('isVideoCall', false);
const name = text(
'name',
diff --git a/ts/components/MainHeader.tsx b/ts/components/MainHeader.tsx
index 60f232451..97b7d458e 100644
--- a/ts/components/MainHeader.tsx
+++ b/ts/components/MainHeader.tsx
@@ -7,7 +7,8 @@ import { createPortal } from 'react-dom';
import { showSettings } from '../shims/Whisper';
import { Avatar } from './Avatar';
import { AvatarPopup } from './AvatarPopup';
-import { ColorType, LocalizerType } from '../types/Util';
+import { LocalizerType } from '../types/Util';
+import { ColorType } from '../types/Colors';
export interface PropsType {
searchTerm: string;
diff --git a/ts/components/MessageSearchResult.tsx b/ts/components/MessageSearchResult.tsx
index e4463d5a6..4e753cfb9 100644
--- a/ts/components/MessageSearchResult.tsx
+++ b/ts/components/MessageSearchResult.tsx
@@ -6,7 +6,8 @@ import { MessageBodyHighlight } from './MessageBodyHighlight';
import { Timestamp } from './conversation/Timestamp';
import { ContactName } from './conversation/ContactName';
-import { ColorType, LocalizerType } from '../types/Util';
+import { LocalizerType } from '../types/Util';
+import { ColorType } from '../types/Colors';
export type PropsDataType = {
isSelected?: boolean;
diff --git a/ts/components/conversation/ConversationHeader.tsx b/ts/components/conversation/ConversationHeader.tsx
index 007c46896..97d47b5cd 100644
--- a/ts/components/conversation/ConversationHeader.tsx
+++ b/ts/components/conversation/ConversationHeader.tsx
@@ -11,7 +11,8 @@ import { Emojify } from './Emojify';
import { Avatar } from '../Avatar';
import { InContactsIcon } from '../InContactsIcon';
-import { ColorType, LocalizerType } from '../../types/Util';
+import { LocalizerType } from '../../types/Util';
+import { ColorType } from '../../types/Colors';
interface TimerOption {
name: string;
diff --git a/ts/components/conversation/Message.tsx b/ts/components/conversation/Message.tsx
index e77c6bb7e..079572283 100644
--- a/ts/components/conversation/Message.tsx
+++ b/ts/components/conversation/Message.tsx
@@ -39,7 +39,8 @@ import { ContactType } from '../../types/Contact';
import { getIncrement } from '../../util/timer';
import { isFileDangerous } from '../../util/isFileDangerous';
-import { ColorType, LocalizerType } from '../../types/Util';
+import { LocalizerType } from '../../types/Util';
+import { ColorType } from '../../types/Colors';
import { createRefMerger } from '../_util';
import { ContextMenu, ContextMenuTrigger, MenuItem } from 'react-contextmenu';
diff --git a/ts/components/conversation/MessageDetail.tsx b/ts/components/conversation/MessageDetail.tsx
index 972549bc0..65fd0f744 100644
--- a/ts/components/conversation/MessageDetail.tsx
+++ b/ts/components/conversation/MessageDetail.tsx
@@ -5,7 +5,8 @@ import moment from 'moment';
import { Avatar } from '../Avatar';
import { ContactName } from './ContactName';
import { Message, Props as MessageProps } from './Message';
-import { ColorType, LocalizerType } from '../../types/Util';
+import { LocalizerType } from '../../types/Util';
+import { ColorType } from '../../types/Colors';
interface Contact {
status: string;
diff --git a/ts/components/conversation/Quote.tsx b/ts/components/conversation/Quote.tsx
index f422d8b39..7b8d6362f 100644
--- a/ts/components/conversation/Quote.tsx
+++ b/ts/components/conversation/Quote.tsx
@@ -7,7 +7,8 @@ import * as MIME from '../../../ts/types/MIME';
import * as GoogleChrome from '../../../ts/util/GoogleChrome';
import { MessageBody } from './MessageBody';
-import { ColorType, LocalizerType } from '../../types/Util';
+import { LocalizerType } from '../../types/Util';
+import { ColorType } from '../../types/Colors';
import { ContactName } from './ContactName';
interface Props {
diff --git a/ts/components/conversation/ReactionViewer.tsx b/ts/components/conversation/ReactionViewer.tsx
index 7394dc4e8..493706b74 100644
--- a/ts/components/conversation/ReactionViewer.tsx
+++ b/ts/components/conversation/ReactionViewer.tsx
@@ -5,7 +5,7 @@ import { ContactName } from './ContactName';
import { Avatar, Props as AvatarProps } from '../Avatar';
import { Emoji } from '../emoji/Emoji';
import { useRestoreFocus } from '../../util/hooks';
-import { ColorType } from '../../types/Util';
+import { ColorType } from '../../types/Colors';
export type Reaction = {
emoji: string;
diff --git a/ts/components/conversation/TypingBubble.tsx b/ts/components/conversation/TypingBubble.tsx
index 5e8171097..5988afeec 100644
--- a/ts/components/conversation/TypingBubble.tsx
+++ b/ts/components/conversation/TypingBubble.tsx
@@ -4,7 +4,8 @@ import classNames from 'classnames';
import { TypingAnimation } from './TypingAnimation';
import { Avatar } from '../Avatar';
-import { ColorType, LocalizerType } from '../../types/Util';
+import { LocalizerType } from '../../types/Util';
+import { ColorType } from '../../types/Colors';
interface Props {
avatarPath?: string;
diff --git a/ts/model-types.d.ts b/ts/model-types.d.ts
index a4127ad64..0e926bfb7 100644
--- a/ts/model-types.d.ts
+++ b/ts/model-types.d.ts
@@ -1,6 +1,7 @@
import * as Backbone from 'backbone';
-import { ColorType, LocalizerType } from './types/Util';
+import { LocalizerType } from './types/Util';
+import { ColorType } from './types/Colors';
import { ConversationType } from './state/ducks/conversations';
import { CallingClass, CallHistoryDetailsType } from './services/calling';
import { SendOptionsType } from './textsecure/SendMessage';
diff --git a/ts/state/ducks/calling.ts b/ts/state/ducks/calling.ts
index a0df03139..5b5a6fd38 100644
--- a/ts/state/ducks/calling.ts
+++ b/ts/state/ducks/calling.ts
@@ -2,7 +2,7 @@ import { notify } from '../../services/notify';
import { calling, VideoCapturer, VideoRenderer } from '../../services/calling';
import { CallState } from '../../types/Calling';
import { CanvasVideoRenderer, GumVideoCapturer } from '../../window.d';
-import { ColorType } from '../../types/Util';
+import { ColorType } from '../../types/Colors';
import { NoopActionType } from './noop';
import { callingTones } from '../../util/callingTones';
import { requestCameraPermissions } from '../../util/callingPermissions';
diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts
index c24fe6b60..6304323f7 100644
--- a/ts/state/ducks/conversations.ts
+++ b/ts/state/ducks/conversations.ts
@@ -12,7 +12,7 @@ import {
import { trigger } from '../../shims/events';
import { NoopActionType } from './noop';
import { AttachmentType } from '../../types/Attachment';
-import { ColorType } from '../../types/Util';
+import { ColorType } from '../../types/Colors';
// State
diff --git a/ts/types/Colors.ts b/ts/types/Colors.ts
new file mode 100644
index 000000000..801a9a62d
--- /dev/null
+++ b/ts/types/Colors.ts
@@ -0,0 +1,18 @@
+export const Colors = [
+ 'red',
+ 'deep_orange',
+ 'brown',
+ 'pink',
+ 'purple',
+ 'indigo',
+ 'blue',
+ 'teal',
+ 'green',
+ 'light_green',
+ 'blue_grey',
+ 'grey',
+ 'ultramarine',
+ 'signal-blue',
+] as const;
+
+export type ColorType = typeof Colors[number];
diff --git a/ts/types/Util.ts b/ts/types/Util.ts
index daa931c62..2ec3d816f 100644
--- a/ts/types/Util.ts
+++ b/ts/types/Util.ts
@@ -11,19 +11,3 @@ export type LocalizerType = (
key: string,
values?: Array | ReplacementValuesType
) => string;
-
-export type ColorType =
- | 'red'
- | 'deep_orange'
- | 'brown'
- | 'pink'
- | 'purple'
- | 'indigo'
- | 'blue'
- | 'teal'
- | 'green'
- | 'light_green'
- | 'blue_grey'
- | 'grey'
- | 'ultramarine'
- | 'signal-blue';
diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json
index b4fc2352b..4b0aeb643 100644
--- a/ts/util/lint/exceptions.json
+++ b/ts/util/lint/exceptions.json
@@ -11770,7 +11770,7 @@
"rule": "React-createRef",
"path": "ts/components/MainHeader.tsx",
"line": " this.inputRef = React.createRef();",
- "lineNumber": 70,
+ "lineNumber": 71,
"reasonCategory": "usageTrusted",
"updated": "2020-02-14T20:02:37.507Z",
"reasonDetail": "Used only to set focus"
@@ -11806,7 +11806,7 @@
"rule": "React-createRef",
"path": "ts/components/conversation/ConversationHeader.tsx",
"line": " this.menuTriggerRef = React.createRef();",
- "lineNumber": 75,
+ "lineNumber": 76,
"reasonCategory": "usageTrusted",
"updated": "2020-05-20T20:10:43.540Z",
"reasonDetail": "Used to reference popup menu"
@@ -11850,7 +11850,7 @@
"rule": "React-createRef",
"path": "ts/components/conversation/Message.tsx",
"line": " public audioRef: React.RefObject = React.createRef();",
- "lineNumber": 185,
+ "lineNumber": 186,
"reasonCategory": "usageTrusted",
"updated": "2020-05-21T16:56:07.875Z"
},
@@ -11858,7 +11858,7 @@
"rule": "React-createRef",
"path": "ts/components/conversation/Message.tsx",
"line": " > = React.createRef();",
- "lineNumber": 189,
+ "lineNumber": 190,
"reasonCategory": "usageTrusted",
"updated": "2020-05-21T16:56:07.875Z"
},
diff --git a/ts/util/migrateColor.ts b/ts/util/migrateColor.ts
index 21a68805a..75ef94729 100644
--- a/ts/util/migrateColor.ts
+++ b/ts/util/migrateColor.ts
@@ -1,6 +1,8 @@
+import { ColorType } from '../types/Colors';
+
// import { missingCaseError } from './missingCaseError';
-type OldColor =
+type OldColorType =
| 'amber'
| 'blue'
| 'blue_grey'
@@ -22,22 +24,7 @@ type OldColor =
| 'yellow'
| 'ultramarine';
-type NewColor =
- | 'red'
- | 'deep_orange'
- | 'brown'
- | 'pink'
- | 'purple'
- | 'indigo'
- | 'blue'
- | 'teal'
- | 'green'
- | 'light_green'
- | 'blue_grey'
- | 'grey'
- | 'ultramarine';
-
-export function migrateColor(color: OldColor): NewColor {
+export function migrateColor(color: OldColorType): ColorType {
switch (color) {
// These colors no longer exist
case 'orange':
diff --git a/ts/window.d.ts b/ts/window.d.ts
index 67185e1b5..09c8a5a66 100644
--- a/ts/window.d.ts
+++ b/ts/window.d.ts
@@ -18,7 +18,8 @@ import { ContactRecordIdentityState, TextSecureType } from './textsecure.d';
import { WebAPIConnectType } from './textsecure/WebAPI';
import { CallingClass, CallHistoryDetailsType } from './services/calling';
import * as Crypto from './Crypto';
-import { ColorType, LocalizerType } from './types/Util';
+import { LocalizerType } from './types/Util';
+import { ColorType } from './types/Colors';
import { ConversationController } from './ConversationController';
import { SendOptionsType } from './textsecure/SendMessage';
import Data from './sql/Client';