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 (
-
+ className={'bg-black dib ' + classes} + style={{ width: props.size, height: props.size }} + > ); } else { 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') ? : ; + 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 (
@@ -470,39 +477,41 @@ export class ContactCard extends Component {

{shipType}


- { !!props.contact.nickname ? ( + { props.contact.nickname ? (

Nickname

{props.contact.nickname}

) : null } - { !!props.contact.email ? ( + { props.contact.email ? (

Email

{props.contact.email}

) : null } - { !!props.contact.phone ? ( + { props.contact.phone ? (

Phone

{props.contact.phone}

) : null } - { !!props.contact.website ? ( + { props.contact.website ? (

website

+ href={websiteHref} + > {props.contact.website}
) : null } - { !!props.contact.notes ? ( + { props.contact.notes ? (

notes

{props.contact.notes}

@@ -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 (
+ 'flex justify-between w-100 bg-white bg-gray0-d ' + + 'bb b--gray4 b--gray1-d ' + } + >
- {"⟵"} + {'⟵'}
@@ -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}
{card}
diff --git a/pkg/interface/groups/src/js/components/lib/icons/sigil.js b/pkg/interface/groups/src/js/components/lib/icons/sigil.js index 8bd10a379..d996866ce 100644 --- a/pkg/interface/groups/src/js/components/lib/icons/sigil.js +++ b/pkg/interface/groups/src/js/components/lib/icons/sigil.js @@ -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 (
+ className={'bg-black dib ' + classes} + style={{ width: props.size, height: props.size }} + >
); } else { return (
+ 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] })}
); diff --git a/pkg/interface/link/src/js/components/lib/icons/sigil.js b/pkg/interface/link/src/js/components/lib/icons/sigil.js index 2ef775e8b..202a9e592 100644 --- a/pkg/interface/link/src/js/components/lib/icons/sigil.js +++ b/pkg/interface/link/src/js/components/lib/icons/sigil.js @@ -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 (
+ className={'bg-black dib ' + classes} + style={{ width: props.size, height: props.size }} + >
); } else { return (
+ 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] })}
); diff --git a/pkg/interface/publish/src/js/components/lib/icons/sigil.js b/pkg/interface/publish/src/js/components/lib/icons/sigil.js index 55336013d..d18eee46e 100644 --- a/pkg/interface/publish/src/js/components/lib/icons/sigil.js +++ b/pkg/interface/publish/src/js/components/lib/icons/sigil.js @@ -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 (
-
+ className={'bg-black dib ' + classes} + style={{ width: props.size, height: props.size }} + >
); } else { return ( -
+
{sigil({ patp: props.ship, renderer: reactRenderer, size: props.size, - colors: [props.color, "white"] + colors: [props.color, foreground] })}
); } } } -