diff --git a/pkg/interface/chat/src/js/components/lib/icons/sigil.js b/pkg/interface/chat/src/js/components/lib/icons/sigil.js
index d5bcfd188..2209ccab7 100644
--- a/pkg/interface/chat/src/js/components/lib/icons/sigil.js
+++ b/pkg/interface/chat/src/js/components/lib/icons/sigil.js
@@ -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 (
+
{sigil({
patp: props.ship,
renderer: reactRenderer,
size: props.size,
- colors: [props.color, "white"],
+ colors: [props.color, foreground],
class: props.svgClass
})}
@@ -30,4 +46,3 @@ export class Sigil extends Component {
}
}
}
-
diff --git a/pkg/interface/groups/src/js/components/lib/contact-card.js b/pkg/interface/groups/src/js/components/lib/contact-card.js
index 6ee155c34..33070e4f4 100644
--- a/pkg/interface/groups/src/js/components/lib/contact-card.js
+++ b/pkg/interface/groups/src/js/components/lib/contact-card.js
@@ -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 = (
+ style={{ width: 'fit-content' }}
+ >
Sigil Color
);
}
- let avatar = (hasAvatar)
+ const avatar = (hasAvatar)
?
:
;
+ color={'#' + currentColor}
+ key={'avatar' + currentColor}
+ />;
return (
@@ -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}
+ />
this.setField("removeEmail")}
- onSaveClick={() => this.setField("email")}
- showButtons={!props.share} />
+ onDeleteClick={() => this.setField('removeEmail')}
+ onSaveClick={() => this.setField('email')}
+ showButtons={!props.share}
+ />
this.setField("removePhone")}
- onSaveClick={() => this.setField("phone")}
- showButtons={!props.share} />
+ onDeleteClick={() => this.setField('removePhone')}
+ onSaveClick={() => this.setField('phone')}
+ showButtons={!props.share}
+ />
this.setField("removeWebsite")}
- onSaveClick={() => this.setField("website")}
- showButtons={!props.share} />
+ onDeleteClick={() => this.setField('removeWebsite')}
+ onSaveClick={() => this.setField('website')}
+ showButtons={!props.share}
+ />
this.setField("removeNotes")}
- onSaveClick={() => this.setField("notes")}
+ onDeleteClick={() => this.setField('removeNotes')}
+ onSaveClick={() => this.setField('notes')}
resizable={true}
- showButtons={!props.share} />
+ showButtons={!props.share}
+ />
@@ -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') ?