Merge branch 'mp/sigil-foregrounding' (#2762)

* mp/sigil-foregrounding:
  groups: lint contact-card.js
  groups: restrict sigil color input to 6 hex chars
  various: set sigil foreground based on contrast

Signed-off-by: Matilde Park <matilde@tlon.io>
This commit is contained in:
Matilde Park 2020-04-22 18:40:08 -04:00
commit 14dd521fbc
5 changed files with 258 additions and 184 deletions

View File

@ -1,28 +1,44 @@
import React, { Component } from 'react';
import { sigil, reactRenderer } from 'urbit-sigil-js';
export class Sigil extends Component {
render() {
const { props } = this;
let classes = props.classes || "";
const classes = props.classes || '';
const rgb = {
r: parseInt(props.color.slice(1, 3), 16),
g: parseInt(props.color.slice(3, 5), 16),
b: parseInt(props.color.slice(5, 7), 16)
};
const brightness = ((299 * rgb.r) + (587 * rgb.g) + (114 * rgb.b)) / 1000;
const whiteBrightness = 255;
let foreground = 'white';
if ((whiteBrightness - brightness) < 50) {
foreground = 'black';
}
if (props.ship.length > 14) {
return (
<div
className={"bg-black dib " + classes}
style={{width: props.size, height: props.size}}>
</div>
className={'bg-black dib ' + classes}
style={{ width: props.size, height: props.size }}
></div>
);
} else {
return (
<div className={"dib " + classes} style={{ flexBasis: props.size, backgroundColor: props.color }}>
<div
className={'dib ' + classes}
style={{ flexBasis: 32, backgroundColor: props.color }}
>
{sigil({
patp: props.ship,
renderer: reactRenderer,
size: props.size,
colors: [props.color, "white"],
colors: [props.color, foreground],
class: props.svgClass
})}
</div>
@ -30,4 +46,3 @@ export class Sigil extends Component {
}
}
}

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Sigil } from './icons/sigil';
import { api } from '/api';
import { Route, Link } from 'react-router-dom';
import { Link } from 'react-router-dom';
import { EditElement } from '/components/lib/edit-element';
import { Spinner } from './icons/icon-spinner';
import { uxToHex } from '/lib/util';
@ -19,7 +19,7 @@ export class ContactCard extends Component {
websiteToSet: null,
notesToSet: null,
awaiting: false,
type: "Saving to group"
type: 'Saving to group'
};
this.editToggle = this.editToggle.bind(this);
this.sigilColorSet = this.sigilColorSet.bind(this);
@ -50,10 +50,9 @@ export class ContactCard extends Component {
}
editToggle() {
const { props } = this;
let editSwitch = this.state.edit;
editSwitch = !editSwitch;
this.setState({edit: editSwitch});
this.setState({ edit: editSwitch });
}
emailToSet(value) {
@ -82,172 +81,169 @@ export class ContactCard extends Component {
shipParser(ship) {
switch (ship.length) {
case 3: return "Galaxy";
case 6: return "Star";
case 13: return "Planet";
case 56: return "Comet";
default: return "Unknown";
case 3: return 'Galaxy';
case 6: return 'Star';
case 13: return 'Planet';
case 56: return 'Comet';
default: return 'Unknown';
}
}
setField(field) {
const { props, state } = this;
let ship = "~" + props.ship;
let emailTest = new RegExp(''
+ /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*/.source
const ship = '~' + props.ship;
const emailTest = new RegExp(String(/[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*/.source)
+ /@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/.source
);
let phoneTest = new RegExp(''
+ /^\s*(?:\+?(\d{1,3}))?/.source
const phoneTest = new RegExp(String(/^\s*(?:\+?(\d{1,3}))?/.source)
+ /([-. (]*(\d{3})[-. )]*)?((\d{3})[-. ]*(\d{2,4})(?:[-.x ]*(\d+))?)\s*$/.source
);
let websiteTest = new RegExp(''
+ /[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}/.source
const websiteTest = new RegExp(String(/[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}/.source)
+ /\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/.source
);
switch (field) {
case "color": {
let currentColor = (props.contact.color) ? props.contact.color : "000000";
case 'color': {
let currentColor = (props.contact.color) ? props.contact.color : '000000';
currentColor = uxToHex(currentColor);
let hexExp = /([0-9A-Fa-f]{6})/
let hexTest = hexExp.exec(this.state.colorToSet);
const hexExp = /([0-9A-Fa-f]{6})/;
const hexTest = hexExp.exec(this.state.colorToSet);
if (hexTest && (hexTest[1] !== currentColor) && !props.share) {
this.setState({ awaiting: true, type: "Saving to group" }, (() => {
this.setState({ awaiting: true, type: 'Saving to group' }, (() => {
api.contactEdit(props.path, `~${props.ship}`, { color: hexTest[1] }).then(() => {
this.setState({ awaiting: false });
});
}))
}));
}
break;
}
case "email": {
case 'email': {
if (
(state.emailToSet === "") ||
(state.emailToSet === '') ||
(state.emailToSet === props.contact.email)
) {
return false;
}
let emailTestResult = emailTest.exec(state.emailToSet);
const emailTestResult = emailTest.exec(state.emailToSet);
if (emailTestResult) {
this.setState({ awaiting: true, type: "Saving to group" }, (() => {
this.setState({ awaiting: true, type: 'Saving to group' }, (() => {
api.contactEdit(props.path, ship, { email: state.emailToSet }).then(() => {
this.setState({awaiting: false});
this.setState({ awaiting: false });
});
}))
}));
}
break;
}
case "nickname": {
case 'nickname': {
if (
(state.nickNameToSet === "") ||
(state.nickNameToSet === '') ||
(state.nickNameToSet === props.contact.nickname)
) {
return false;
}
this.setState({ awaiting: true, type: "Saving to group" }, (() => {
this.setState({ awaiting: true, type: 'Saving to group' }, (() => {
api.contactEdit(props.path, ship, { nickname: state.nickNameToSet }).then(() => {
this.setState({ awaiting: false });
});
}))
}));
break;
}
case "notes": {
case 'notes': {
if (
(state.notesToSet === "") ||
(state.notesToSet === '') ||
(state.notesToSet === props.contact.notes)
) {
return false;
}
this.setState({ awaiting: true, type: "Saving to group" }, (() => {
this.setState({ awaiting: true, type: 'Saving to group' }, (() => {
api.contactEdit(props.path, ship, { notes: state.notesToSet }).then(() => {
this.setState({ awaiting: false });
});
}))
}));
break;
}
case "phone": {
case 'phone': {
if (
(state.phoneToSet === "") ||
(state.phoneToSet === '') ||
(state.phoneToSet === props.contact.phone)
) {
return false;
}
let phoneTestResult = phoneTest.exec(state.phoneToSet);
const phoneTestResult = phoneTest.exec(state.phoneToSet);
if (phoneTestResult) {
this.setState({ awaiting: true, type: "Saving to group" }, (() => {
this.setState({ awaiting: true, type: 'Saving to group' }, (() => {
api.contactEdit(props.path, ship, { phone: state.phoneToSet }).then(() => {
this.setState({ awaiting: false });
});
}))
}));
}
break;
}
case "website": {
case 'website': {
if (
(state.websiteToSet === "") ||
(state.websiteToSet === '') ||
(state.websiteToSet === props.contact.website)
) {
return false;
}
let websiteTestResult = websiteTest.exec(state.websiteToSet);
const websiteTestResult = websiteTest.exec(state.websiteToSet);
if (websiteTestResult) {
this.setState({ awaiting: true, type: "Saving to group" }, (() => {
this.setState({ awaiting: true, type: 'Saving to group' }, (() => {
api.contactEdit(props.path, ship, { website: state.websiteToSet }).then(() => {
this.setState({ awaiting: false });
});
}))
}));
}
break;
}
case "removeAvatar": {
this.setState({ awaiting: true, type: "Removing from group" }, (() => {
case 'removeAvatar': {
this.setState({ awaiting: true, type: 'Removing from group' }, (() => {
api.contactEdit(props.path, ship, { avatar: null }).then(() => {
this.setState({ awaiting: false });
});
}))
}));
break;
}
case "removeEmail": {
this.setState({ emailToSet: "", awaiting: true, type: "Removing from group" }, (() => {
api.contactEdit(props.path, ship, { email: "" }).then(() => {
this.setState({awaiting: false});
case 'removeEmail': {
this.setState({ emailToSet: '', awaiting: true, type: 'Removing from group' }, (() => {
api.contactEdit(props.path, ship, { email: '' }).then(() => {
this.setState({ awaiting: false });
});
}));
break;
}
case "removeNickname": {
this.setState({ nicknameToSet: "", awaiting: true, type: "Removing from group" }, (() => {
api.contactEdit(props.path, ship, { nickname: "" }).then(() => {
this.setState({awaiting: false});
case 'removeNickname': {
this.setState({ nicknameToSet: '', awaiting: true, type: 'Removing from group' }, (() => {
api.contactEdit(props.path, ship, { nickname: '' }).then(() => {
this.setState({ awaiting: false });
});
}));
break;
}
case "removePhone": {
this.setState({ phoneToSet: "", awaiting: true, type: "Removing from group" }, (() => {
api.contactEdit(props.path, ship, { phone: "" }).then(() => {
this.setState({awaiting: false});
case 'removePhone': {
this.setState({ phoneToSet: '', awaiting: true, type: 'Removing from group' }, (() => {
api.contactEdit(props.path, ship, { phone: '' }).then(() => {
this.setState({ awaiting: false });
});
}));
break;
}
case "removeWebsite": {
this.setState({ websiteToSet: "", awaiting: true, type: "Removing from group" }, (() => {
api.contactEdit(props.path, ship, { website: "" }).then(() => {
this.setState({awaiting: false});
case 'removeWebsite': {
this.setState({ websiteToSet: '', awaiting: true, type: 'Removing from group' }, (() => {
api.contactEdit(props.path, ship, { website: '' }).then(() => {
this.setState({ awaiting: false });
});
}));
break;
}
case "removeNotes": {
this.setState({ notesToSet: "", awaiting: true, type: "Removing from group" }, (() => {
api.contactEdit(props.path, ship, { notes: "" }).then(() => {
this.setState({awaiting: false});
case 'removeNotes': {
this.setState({ notesToSet: '', awaiting: true, type: 'Removing from group' }, (() => {
api.contactEdit(props.path, ship, { notes: '' }).then(() => {
this.setState({ awaiting: false });
});
}));
break;
@ -264,7 +260,7 @@ export class ContactCard extends Component {
shareWithGroup() {
const { props, state } = this;
let defaultVal = props.share ? {
const defaultVal = props.share ? {
nickname: props.rootIdentity.nickname,
email: props.rootIdentity.email,
phone: props.rootIdentity.phone,
@ -280,7 +276,7 @@ export class ContactCard extends Component {
color: props.contact.color
};
let contact = {
const contact = {
nickname: this.pickFunction(state.nickNameToSet, defaultVal.nickname),
email: this.pickFunction(state.emailToSet, defaultVal.email),
phone: this.pickFunction(state.phoneToSet, defaultVal.phone),
@ -289,26 +285,26 @@ export class ContactCard extends Component {
color: this.pickFunction(state.colorToSet, defaultVal.color),
avatar: null
};
this.setState({awaiting: true, type: "Sharing with group"}, (() => {
this.setState({ awaiting: true, type: 'Sharing with group' }, (() => {
api.contactView.share(
`~${props.ship}`, props.path, `~${window.ship}`, contact
).then(() => {
props.history.push(`/~groups/view${props.path}/${window.ship}`)
props.history.push(`/~groups/view${props.path}/${window.ship}`);
});
}))
}));
}
removeFromGroup() {
const { props } = this;
// share empty contact so that we can remove ourselves from group
// if we haven't shared yet
let contact = {
nickname: "",
email: "",
phone: "",
website: "",
notes: "",
color: "000000",
const contact = {
nickname: '',
email: '',
phone: '',
website: '',
notes: '',
color: '000000',
avatar: null
};
@ -316,20 +312,20 @@ export class ContactCard extends Component {
`~${props.ship}`, props.path, `~${window.ship}`, contact
);
this.setState({awaiting: true, type: "Removing from group"}, (() => {
this.setState({ awaiting: true, type: 'Removing from group' }, (() => {
api.contactView.delete(props.path).then(() => {
let destination = (props.ship === window.ship)
? "" : props.path;
this.setState({awaiting: false});
const destination = (props.ship === window.ship)
? '' : props.path;
this.setState({ awaiting: false });
props.history.push(`/~groups${destination}`);
});
}))
}));
}
renderEditCard() {
const { props, state } = this;
// if this is our first edit in a new group, propagate from root identity
let defaultValue = props.share ? {
const defaultValue = props.share ? {
nickname: props.rootIdentity.nickname,
email: props.rootIdentity.email,
phone: props.rootIdentity.phone,
@ -345,47 +341,52 @@ export class ContactCard extends Component {
color: props.contact.color
};
let shipType = this.shipParser(props.ship);
const shipType = this.shipParser(props.ship);
let defaultColor = !!defaultValue.color ? defaultValue.color : "000000";
let defaultColor = defaultValue.color ? defaultValue.color : '000000';
defaultColor = uxToHex(defaultColor);
let currentColor = !!state.colorToSet ? state.colorToSet : defaultColor;
let currentColor = state.colorToSet ? state.colorToSet : defaultColor;
currentColor = uxToHex(currentColor);
let sigilColor = "";
let hasAvatar =
'avatar' in props.contact && props.contact.avatar !== "TODO";
let sigilColor = '';
const hasAvatar =
'avatar' in props.contact && props.contact.avatar !== 'TODO';
if (!hasAvatar) {
sigilColor = (
<div className="tl mt4 mb4 w-auto ml-auto mr-auto"
style={{ width: "fit-content" }}>
style={{ width: 'fit-content' }}
>
<p className="f9 gray2 lh-copy">Sigil Color</p>
<textarea
className={"b--gray4 b--gray2-d black white-d bg-gray0-d f7 ba db pl2 " +
"focus-b--black focus-b--white-d"}
className={'b--gray4 b--gray2-d black white-d bg-gray0-d f7 ba db pl2 ' +
'focus-b--black focus-b--white-d'}
onChange={this.sigilColorSet}
defaultValue={defaultColor}
key={"default" + defaultColor}
onBlur={(() => this.setField("color"))}
key={'default' + defaultColor}
onKeyPress={ e => !e.key.match(/[0-9a-f]/i) ? e.preventDefault() : null}
onBlur={(() => this.setField('color'))}
maxLength={6}
style={{
resize: "none",
resize: 'none',
height: 40,
paddingTop: 10,
width: 114
}}>
}}
>
</textarea>
</div>
);
}
let avatar = (hasAvatar)
const avatar = (hasAvatar)
? <img className="dib h-auto" width={128} src={props.contact.avatar} />
: <Sigil
ship={props.ship}
size={128}
color={"#" + currentColor}
key={"avatar" + currentColor} />;
color={'#' + currentColor}
key={'avatar' + currentColor}
/>;
return (
<div className="w-100 mt8 flex justify-center pa4 pt8 pt0-l pa0-xl pt4-xl pb8">
@ -402,38 +403,43 @@ export class ContactCard extends Component {
title="Nickname"
defaultValue={defaultValue.nickname}
onChange={this.nickNameToSet}
onDeleteClick={() => this.setField("removeNickname")}
onSaveClick={() => this.setField("nickname")}
showButtons={!props.share} />
onDeleteClick={() => this.setField('removeNickname')}
onSaveClick={() => this.setField('nickname')}
showButtons={!props.share}
/>
<EditElement
title="Email"
defaultValue={defaultValue.email}
onChange={this.emailToSet}
onDeleteClick={() => this.setField("removeEmail")}
onSaveClick={() => this.setField("email")}
showButtons={!props.share} />
onDeleteClick={() => this.setField('removeEmail')}
onSaveClick={() => this.setField('email')}
showButtons={!props.share}
/>
<EditElement
title="Phone"
defaultValue={defaultValue.phone}
onChange={this.phoneToSet}
onDeleteClick={() => this.setField("removePhone")}
onSaveClick={() => this.setField("phone")}
showButtons={!props.share} />
onDeleteClick={() => this.setField('removePhone')}
onSaveClick={() => this.setField('phone')}
showButtons={!props.share}
/>
<EditElement
title="Website"
defaultValue={defaultValue.website}
onChange={this.websiteToSet}
onDeleteClick={() => this.setField("removeWebsite")}
onSaveClick={() => this.setField("website")}
showButtons={!props.share} />
onDeleteClick={() => this.setField('removeWebsite')}
onSaveClick={() => this.setField('website')}
showButtons={!props.share}
/>
<EditElement
title="Notes"
defaultValue={defaultValue.notes}
onChange={this.notesToSet}
onDeleteClick={() => this.setField("removeNotes")}
onSaveClick={() => this.setField("notes")}
onDeleteClick={() => this.setField('removeNotes')}
onSaveClick={() => this.setField('notes')}
resizable={true}
showButtons={!props.share} />
showButtons={!props.share}
/>
</div>
</div>
</div>
@ -442,22 +448,23 @@ export class ContactCard extends Component {
renderCard() {
const { props } = this;
let shipType = this.shipParser(props.ship);
let currentColor = props.contact.color ? props.contact.color : "0x0";
let hexColor = uxToHex(currentColor);
const shipType = this.shipParser(props.ship);
const currentColor = props.contact.color ? props.contact.color : '0x0';
const hexColor = uxToHex(currentColor);
let avatar =
('avatar' in props.contact && props.contact.avatar !== "TODO") ?
const avatar =
('avatar' in props.contact && props.contact.avatar !== 'TODO') ?
<img className="dib h-auto" width={128} src={props.contact.avatar} /> :
<Sigil
ship={props.ship}
size={128}
color={"#" + hexColor}
key={hexColor} />;
color={'#' + hexColor}
key={hexColor}
/>;
let websiteHref =
(props.contact.website && props.contact.website.includes("://")) ?
props.contact.website : "http://" + props.contact.website;
const websiteHref =
(props.contact.website && props.contact.website.includes('://')) ?
props.contact.website : 'http://' + props.contact.website;
return (
<div className="w-100 mt8 flex justify-center pa4 pt8 pt0-l pa0-xl pt4-xl">
@ -470,39 +477,41 @@ export class ContactCard extends Component {
<p className="f8">{shipType}</p>
<hr className="mv8 gray4 b--gray4 bb-0 b--solid" />
<div>
{ !!props.contact.nickname ? (
{ props.contact.nickname ? (
<div>
<p className="f9 gray2">Nickname</p>
<p className="f8">{props.contact.nickname}</p>
</div>
) : null
}
{ !!props.contact.email ? (
{ props.contact.email ? (
<div>
<p className="f9 mt6 gray2">Email</p>
<p className="f8">{props.contact.email}</p>
</div>
) : null
}
{ !!props.contact.phone ? (
{ props.contact.phone ? (
<div>
<p className="f9 mt6 gray2">Phone</p>
<p className="f8">{props.contact.phone}</p>
</div>
) : null
}
{ !!props.contact.website ? (
{ props.contact.website ? (
<div>
<p className="f9 mt6 gray2">website</p>
<a target="_blank"
rel="noopener noreferrer"
className="bb b--black f8"
href={websiteHref}>
href={websiteHref}
>
{props.contact.website}
</a>
</div>
) : null
}
{ !!props.contact.notes ? (
{ props.contact.notes ? (
<div>
<p className="f9 mt6 gray2">notes</p>
<p className="f8">{props.contact.notes}</p>
@ -520,32 +529,33 @@ export class ContactCard extends Component {
const { props, state } = this;
let editInfoText =
state.edit ? "Finish" : "Edit";
state.edit ? 'Finish' : 'Edit';
if (props.share && state.edit) {
editInfoText = "Share";
editInfoText = 'Share';
}
let ourOpt = (props.ship === window.ship) ? "dib" : "dn";
const ourOpt = (props.ship === window.ship) ? 'dib' : 'dn';
let adminOpt =
const adminOpt =
((props.path.includes(`~${window.ship}/`)) || ((props.ship === window.ship) &&
!(props.path.includes('/~/default'))))
? "dib" : "dn";
? 'dib' : 'dn';
let meLink = (props.path === "/~/default")
? `/~groups` : `/~groups/detail${props.path}`;
const meLink = (props.path === '/~/default')
? '/~groups' : `/~groups/detail${props.path}`;
let card = state.edit ? this.renderEditCard() : this.renderCard();
const card = state.edit ? this.renderEditCard() : this.renderCard();
return (
<div className="w-100 h-100 overflow-hidden">
<div
className={
"flex justify-between w-100 bg-white bg-gray0-d " +
"bb b--gray4 b--gray1-d "
}>
'flex justify-between w-100 bg-white bg-gray0-d ' +
'bb b--gray4 b--gray1-d '
}
>
<div className="f9 mv4 mh3 pt1 dib w-100">
<Link to={meLink}>
{"⟵"}
{'⟵'}
</Link>
</div>
<div className="flex">
@ -558,20 +568,22 @@ export class ContactCard extends Component {
}
}}
className={
`white-d bg-gray0-d mv4 mh3 f9 pa1 pointer flex-shrink-0 ` +
'white-d bg-gray0-d mv4 mh3 f9 pa1 pointer flex-shrink-0 ' +
ourOpt
}>
}
>
{editInfoText}
</button>
</div>
<button
className={
`bg-gray0-d mv4 mh3 pa1 f9 red2 pointer flex-shrink-0 ` + adminOpt
'bg-gray0-d mv4 mh3 pa1 f9 red2 pointer flex-shrink-0 ' + adminOpt
}
onClick={this.removeFromGroup}>
onClick={this.removeFromGroup}
>
{props.ship === window.ship
? "Leave Group"
: "Remove from Group"}
? 'Leave Group'
: 'Remove from Group'}
</button>
</div>
<div className="h-100 w-100 overflow-x-hidden pb8 white-d">{card}</div>

View File

@ -1,28 +1,44 @@
import React, { Component } from "react";
import { sigil, reactRenderer } from "urbit-sigil-js";
import React, { Component } from 'react';
import { sigil, reactRenderer } from 'urbit-sigil-js';
export class Sigil extends Component {
render() {
const { props } = this;
let classes = props.classes || "";
const classes = props.classes || '';
const rgb = {
r: parseInt(props.color.slice(1, 3), 16),
g: parseInt(props.color.slice(3, 5), 16),
b: parseInt(props.color.slice(5, 7), 16)
};
const brightness = ((299 * rgb.r) + (587 * rgb.g) + (114 * rgb.b)) / 1000;
const whiteBrightness = 255;
let foreground = 'white';
if ((whiteBrightness - brightness) < 50) {
foreground = 'black';
}
if (props.ship.length > 14) {
return (
<div
className={"bg-black dib " + classes}
style={{ width: props.size, height: props.size }}></div>
className={'bg-black dib ' + classes}
style={{ width: props.size, height: props.size }}
></div>
);
} else {
return (
<div
className={"dib " + classes}
style={{ flexBasis: 32, backgroundColor: props.color }}>
className={'dib ' + classes}
style={{ flexBasis: 32, backgroundColor: props.color }}
>
{sigil({
patp: props.ship,
renderer: reactRenderer,
size: props.size,
colors: [props.color, "white"]
colors: [props.color, foreground]
})}
</div>
);

View File

@ -1,28 +1,44 @@
import React, { Component } from "react";
import { sigil, reactRenderer } from "urbit-sigil-js";
import React, { Component } from 'react';
import { sigil, reactRenderer } from 'urbit-sigil-js';
export class Sigil extends Component {
render() {
const { props } = this;
let classes = props.classes || "";
const classes = props.classes || '';
const rgb = {
r: parseInt(props.color.slice(1, 3), 16),
g: parseInt(props.color.slice(3, 5), 16),
b: parseInt(props.color.slice(5, 7), 16)
};
const brightness = ((299 * rgb.r) + (587 * rgb.g) + (114 * rgb.b)) / 1000;
const whiteBrightness = 255;
let foreground = 'white';
if ((whiteBrightness - brightness) < 50) {
foreground = 'black';
}
if (props.ship.length > 14) {
return (
<div
className={"bg-black dib " + classes}
style={{ width: props.size, height: props.size }}></div>
className={'bg-black dib ' + classes}
style={{ width: props.size, height: props.size }}
></div>
);
} else {
return (
<div
className={"dib " + classes}
style={{ flexBasis: props.size, backgroundColor: props.color }}>
className={'dib ' + classes}
style={{ flexBasis: props.size, backgroundColor: props.color }}
>
{sigil({
patp: props.ship,
renderer: reactRenderer,
size: props.size,
colors: [props.color, "white"]
colors: [props.color, foreground]
})}
</div>
);

View File

@ -1,32 +1,47 @@
import React, { Component } from 'react';
import { sigil, reactRenderer } from 'urbit-sigil-js';
export class Sigil extends Component {
render() {
const { props } = this;
let classes = props.classes || "";
const classes = props.classes || '';
const rgb = {
r: parseInt(props.color.slice(1, 3), 16),
g: parseInt(props.color.slice(3, 5), 16),
b: parseInt(props.color.slice(5, 7), 16)
};
const brightness = ((299 * rgb.r) + (587 * rgb.g) + (114 * rgb.b)) / 1000;
const whiteBrightness = 255;
let foreground = 'white';
if ((whiteBrightness - brightness) < 50) {
foreground = 'black';
}
if (props.ship.length > 14) {
return (
<div
className={"bg-black dib " + classes}
style={{ width: props.size, height: props.size }}>
</div>
className={'bg-black dib ' + classes}
style={{ width: props.size, height: props.size }}
></div>
);
} else {
return (
<div className={"dib " + classes} style={{ flexBasis: props.size, backgroundColor: props.color }}>
<div
className={'dib ' + classes}
style={{ backgroundColor: props.color }}
>
{sigil({
patp: props.ship,
renderer: reactRenderer,
size: props.size,
colors: [props.color, "white"]
colors: [props.color, foreground]
})}
</div>
);
}
}
}