Moves identicon svg to TS
This commit is contained in:
parent
347f542ac0
commit
e76f603233
9 changed files with 111 additions and 129 deletions
|
@ -132,15 +132,6 @@
|
||||||
<button class='finish' tabIndex='1'><span class='icon'></span></button>
|
<button class='finish' tabIndex='1'><span class='icon'></span></button>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/x-tmpl-mustache" id="identicon-svg">
|
|
||||||
<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'>
|
|
||||||
<circle cx='50' cy='50' r='40' fill='{{ color }}' />
|
|
||||||
<text text-anchor='middle' fill='white' font-family='sans-serif' font-size='24px' x='50' y='50' baseline-shift='-8px'>
|
|
||||||
{{ content }}
|
|
||||||
</text>
|
|
||||||
</svg>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/x-tmpl-mustache" id="phone-number">
|
<script type="text/x-tmpl-mustache" id="phone-number">
|
||||||
<div class='phone-input-form'>
|
<div class='phone-input-form'>
|
||||||
<div class='number-container'>
|
<div class='number-container'>
|
||||||
|
@ -336,17 +327,12 @@
|
||||||
type="text/javascript"
|
type="text/javascript"
|
||||||
src="ts/shims/showConfirmationDialog.js"
|
src="ts/shims/showConfirmationDialog.js"
|
||||||
></script>
|
></script>
|
||||||
<script
|
|
||||||
type="text/javascript"
|
|
||||||
src="js/views/identicon_svg_view.js"
|
|
||||||
></script>
|
|
||||||
<script type="text/javascript" src="js/views/install_view.js"></script>
|
<script type="text/javascript" src="js/views/install_view.js"></script>
|
||||||
<script type="text/javascript" src="js/views/phone-input-view.js"></script>
|
<script type="text/javascript" src="js/views/phone-input-view.js"></script>
|
||||||
<script
|
<script
|
||||||
type="text/javascript"
|
type="text/javascript"
|
||||||
src="js/views/standalone_registration_view.js"
|
src="js/views/standalone_registration_view.js"
|
||||||
></script>
|
></script>
|
||||||
<script type="text/javascript" src="js/views/clear_data_view.js"></script>
|
|
||||||
|
|
||||||
<script type="text/javascript" src="js/wall_clock_listener.js"></script>
|
<script type="text/javascript" src="js/wall_clock_listener.js"></script>
|
||||||
<script
|
<script
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
// Copyright 2015-2021 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
/* global Whisper, loadImage, $ */
|
|
||||||
|
|
||||||
// eslint-disable-next-line func-names
|
|
||||||
(function () {
|
|
||||||
window.Whisper = window.Whisper || {};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Render an avatar identicon to an svg for use in a notification.
|
|
||||||
*/
|
|
||||||
Whisper.IdenticonSVGView = Whisper.View.extend({
|
|
||||||
template: () => $('#identicon-svg').html(),
|
|
||||||
initialize(options) {
|
|
||||||
this.render_attributes = options;
|
|
||||||
this.render_attributes.color = COLORS[this.render_attributes.color];
|
|
||||||
},
|
|
||||||
getSVGUrl() {
|
|
||||||
const html = this.render().$el.html();
|
|
||||||
const svg = new Blob([html], { type: 'image/svg+xml;charset=utf-8' });
|
|
||||||
return URL.createObjectURL(svg);
|
|
||||||
},
|
|
||||||
getDataUrl() /* : Promise<string> */ {
|
|
||||||
const svgurl = this.getSVGUrl();
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const img = document.createElement('img');
|
|
||||||
img.onload = () => {
|
|
||||||
const canvas = loadImage.scale(img, {
|
|
||||||
canvas: true,
|
|
||||||
maxWidth: 100,
|
|
||||||
maxHeight: 100,
|
|
||||||
});
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
ctx.drawImage(img, 0, 0);
|
|
||||||
URL.revokeObjectURL(svgurl);
|
|
||||||
resolve(canvas.toDataURL('image/png'));
|
|
||||||
};
|
|
||||||
img.onerror = () => {
|
|
||||||
URL.revokeObjectURL(svgurl);
|
|
||||||
// If this fails for some reason, we'd rather continue on than reject.
|
|
||||||
resolve(undefined);
|
|
||||||
};
|
|
||||||
|
|
||||||
img.src = svgurl;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const COLORS = {
|
|
||||||
blue: '#0a69c7',
|
|
||||||
burlap: '#866118',
|
|
||||||
crimson: '#d00b2c',
|
|
||||||
forest: '#067919',
|
|
||||||
indigo: '#5151f6',
|
|
||||||
plum: '#c70a88',
|
|
||||||
steel: '#077288',
|
|
||||||
taupe: '#cb0b6b',
|
|
||||||
teal: '#077288',
|
|
||||||
ultramarine: '#0d59f2',
|
|
||||||
vermilion: '#c72a0a',
|
|
||||||
violet: '#a20ced',
|
|
||||||
wintergreen: '#067953',
|
|
||||||
};
|
|
||||||
})();
|
|
|
@ -114,15 +114,6 @@
|
||||||
<button class='close'><span class='icon'></span></button>
|
<button class='close'><span class='icon'></span></button>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/x-tmpl-mustache" id="identicon-svg">
|
|
||||||
<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'>
|
|
||||||
<circle cx='50' cy='50' r='40' fill='{{ color }}' />
|
|
||||||
<text text-anchor='middle' fill='white' font-family='sans-serif' font-size='24px' x='50' y='50' baseline-shift='-8px'>
|
|
||||||
{{ content }}
|
|
||||||
</text>
|
|
||||||
</svg>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/x-tmpl-mustache" id="phone-number">
|
<script type="text/x-tmpl-mustache" id="phone-number">
|
||||||
<div class='phone-input-form'>
|
<div class='phone-input-form'>
|
||||||
<div class='number-container'>
|
<div class='number-container'>
|
||||||
|
@ -355,20 +346,11 @@
|
||||||
src="../js/views/inbox_view.js"
|
src="../js/views/inbox_view.js"
|
||||||
data-cover
|
data-cover
|
||||||
></script>
|
></script>
|
||||||
<script
|
|
||||||
type="text/javascript"
|
|
||||||
src="../js/views/identicon_svg_view.js"
|
|
||||||
data-cover
|
|
||||||
></script>
|
|
||||||
<script
|
<script
|
||||||
type="text/javascript"
|
type="text/javascript"
|
||||||
src="../js/views/banner_view.js"
|
src="../js/views/banner_view.js"
|
||||||
data-cover
|
data-cover
|
||||||
></script>
|
></script>
|
||||||
<script
|
|
||||||
type="text/javascript"
|
|
||||||
src="../js/views/clear_data_view.js"
|
|
||||||
></script>
|
|
||||||
|
|
||||||
<script type="text/javascript" src="views/whisper_view_test.js"></script>
|
<script type="text/javascript" src="views/whisper_view_test.js"></script>
|
||||||
<script type="text/javascript" src="views/list_view_test.js"></script>
|
<script type="text/javascript" src="views/list_view_test.js"></script>
|
||||||
|
|
21
ts/components/IdenticonSVG.stories.tsx
Normal file
21
ts/components/IdenticonSVG.stories.tsx
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { storiesOf } from '@storybook/react';
|
||||||
|
|
||||||
|
import { IdenticonSVG } from './IdenticonSVG';
|
||||||
|
import { AvatarColorMap } from '../types/Colors';
|
||||||
|
|
||||||
|
const story = storiesOf('Components/IdenticonSVG', module);
|
||||||
|
|
||||||
|
AvatarColorMap.forEach((value, key) =>
|
||||||
|
story.add(key, () => (
|
||||||
|
<IdenticonSVG
|
||||||
|
backgroundColor={value.bg}
|
||||||
|
content="HI"
|
||||||
|
foregroundColor={value.fg}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
);
|
33
ts/components/IdenticonSVG.tsx
Normal file
33
ts/components/IdenticonSVG.tsx
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export type PropsType = {
|
||||||
|
backgroundColor: string;
|
||||||
|
content: string;
|
||||||
|
foregroundColor: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function IdenticonSVG({
|
||||||
|
backgroundColor,
|
||||||
|
content,
|
||||||
|
foregroundColor,
|
||||||
|
}: PropsType): JSX.Element {
|
||||||
|
return (
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
|
||||||
|
<circle cx="50" cy="50" r="40" fill={backgroundColor} />
|
||||||
|
<text
|
||||||
|
baselineShift="-8px"
|
||||||
|
fill={foregroundColor}
|
||||||
|
fontFamily="sans-serif"
|
||||||
|
fontSize="24px"
|
||||||
|
textAnchor="middle"
|
||||||
|
x="50"
|
||||||
|
y="50"
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
</text>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
|
@ -85,6 +85,7 @@ import { isAnnouncementGroupReady } from '../util/isAnnouncementGroupReady';
|
||||||
import { getProfile } from '../util/getProfile';
|
import { getProfile } from '../util/getProfile';
|
||||||
import { SEALED_SENDER } from '../types/SealedSender';
|
import { SEALED_SENDER } from '../types/SealedSender';
|
||||||
import { getAvatarData } from '../util/getAvatarData';
|
import { getAvatarData } from '../util/getAvatarData';
|
||||||
|
import { createIdenticon } from '../util/createIdenticon';
|
||||||
|
|
||||||
// TODO: remove once we move away from ArrayBuffers
|
// TODO: remove once we move away from ArrayBuffers
|
||||||
const FIXMEU8 = Uint8Array;
|
const FIXMEU8 = Uint8Array;
|
||||||
|
@ -4963,14 +4964,11 @@ export class ConversationModel extends window.Backbone
|
||||||
return cached.url;
|
return cached.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fresh = await new window.Whisper.IdenticonSVGView({
|
const url = await createIdenticon(color, content);
|
||||||
color,
|
|
||||||
content,
|
|
||||||
}).getDataUrl();
|
|
||||||
|
|
||||||
this.cachedIdenticon = { content, color, url: fresh };
|
this.cachedIdenticon = { content, color, url };
|
||||||
|
|
||||||
return fresh;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyTyping(options: {
|
notifyTyping(options: {
|
||||||
|
|
53
ts/util/createIdenticon.tsx
Normal file
53
ts/util/createIdenticon.tsx
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import loadImage from 'blueimp-load-image';
|
||||||
|
import { renderToString } from 'react-dom/server';
|
||||||
|
import { AvatarColorMap, AvatarColorType } from '../types/Colors';
|
||||||
|
import { IdenticonSVG } from '../components/IdenticonSVG';
|
||||||
|
|
||||||
|
export function createIdenticon(
|
||||||
|
color: AvatarColorType,
|
||||||
|
content: string
|
||||||
|
): Promise<string> {
|
||||||
|
const [defaultColorValue] = Array.from(AvatarColorMap.values());
|
||||||
|
const avatarColor = AvatarColorMap.get(color);
|
||||||
|
const html = renderToString(
|
||||||
|
<IdenticonSVG
|
||||||
|
backgroundColor={avatarColor?.bg || defaultColorValue.bg}
|
||||||
|
content={content}
|
||||||
|
foregroundColor={avatarColor?.fg || defaultColorValue.fg}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
const svg = new Blob([html], { type: 'image/svg+xml;charset=utf-8' });
|
||||||
|
const svgUrl = URL.createObjectURL(svg);
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.onload = () => {
|
||||||
|
const canvas = loadImage.scale(img, {
|
||||||
|
canvas: true,
|
||||||
|
maxWidth: 100,
|
||||||
|
maxHeight: 100,
|
||||||
|
});
|
||||||
|
if (!(canvas instanceof HTMLCanvasElement)) {
|
||||||
|
resolve('');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
if (ctx) {
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
}
|
||||||
|
URL.revokeObjectURL(svgUrl);
|
||||||
|
resolve(canvas.toDataURL('image/png'));
|
||||||
|
};
|
||||||
|
img.onerror = () => {
|
||||||
|
URL.revokeObjectURL(svgUrl);
|
||||||
|
resolve('');
|
||||||
|
};
|
||||||
|
|
||||||
|
img.src = svgUrl;
|
||||||
|
});
|
||||||
|
}
|
|
@ -312,30 +312,6 @@
|
||||||
"updated": "2021-02-26T18:44:56.450Z",
|
"updated": "2021-02-26T18:44:56.450Z",
|
||||||
"reasonDetail": "Static selector, read-only access"
|
"reasonDetail": "Static selector, read-only access"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"rule": "jQuery-$(",
|
|
||||||
"path": "js/views/identicon_svg_view.js",
|
|
||||||
"line": " template: () => $('#identicon-svg').html(),",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2021-02-26T18:44:56.450Z",
|
|
||||||
"reasonDetail": "Static selector, read-only access"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "jQuery-html(",
|
|
||||||
"path": "js/views/identicon_svg_view.js",
|
|
||||||
"line": " const html = this.render().$el.html();",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2018-09-15T00:38:04.183Z",
|
|
||||||
"reasonDetail": "Getting the value, not setting it"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "jQuery-html(",
|
|
||||||
"path": "js/views/identicon_svg_view.js",
|
|
||||||
"line": " template: () => $('#identicon-svg').html(),",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2021-02-26T18:44:56.450Z",
|
|
||||||
"reasonDetail": "Static selector, read-only access"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"rule": "jQuery-$(",
|
"rule": "jQuery-$(",
|
||||||
"path": "js/views/inbox_view.js",
|
"path": "js/views/inbox_view.js",
|
||||||
|
|
2
ts/window.d.ts
vendored
2
ts/window.d.ts
vendored
|
@ -633,8 +633,6 @@ export type WhisperType = {
|
||||||
) => void;
|
) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
IdenticonSVGView: WhatIsThis;
|
|
||||||
|
|
||||||
ExpiringMessagesListener: {
|
ExpiringMessagesListener: {
|
||||||
init: (events: Backbone.Events) => void;
|
init: (events: Backbone.Events) => void;
|
||||||
update: () => void;
|
update: () => void;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue