From 150cfe764aeb9e93341ba2f231fd121fe85472af Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Wed, 27 Dec 2017 13:09:17 +0100 Subject: First working draft of icon upload --- src/models/Service.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/models') diff --git a/src/models/Service.js b/src/models/Service.js index 0b19440e7..652d2594c 100644 --- a/src/models/Service.js +++ b/src/models/Service.js @@ -24,7 +24,7 @@ export default class Service { @observable isNotificationEnabled = true; @observable isBadgeEnabled = true; @observable isIndirectMessageBadgeEnabled = true; - @observable customIconUrl = ''; + @observable iconUrl = ''; @observable hasCrashed = false; constructor(data, recipe) { @@ -42,7 +42,8 @@ export default class Service { this.name = data.name || this.name; this.team = data.team || this.team; this.customUrl = data.customUrl || this.customUrl; - this.customIconUrl = data.customIconUrl || this.customIconUrl; + // this.customIconUrl = data.customIconUrl || this.customIconUrl; + this.iconUrl = data.iconUrl || this.iconUrl; this.order = data.order !== undefined ? data.order : this.order; @@ -97,15 +98,15 @@ export default class Service { } @computed get icon() { - if (this.hasCustomIcon) { - return this.customIconUrl; + if (this.iconUrl) { + return this.iconUrl; } return path.join(this.recipe.path, 'icon.svg'); } @computed get hasCustomIcon() { - return (this.customIconUrl !== ''); + return Boolean(this.iconUrl); } @computed get iconPNG() { -- cgit v1.2.3-70-g09d2 From 6b97e42537879be306cd2aaf95dd8aebf8655fcb Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Tue, 2 Jan 2018 22:54:17 +0100 Subject: feat(Service): Add custom service icon upload --- .../settings/services/EditServiceForm.js | 75 +++++++++-------- src/components/ui/ImageUpload.js | 93 ++++++++++++---------- src/containers/settings/EditServiceScreen.js | 4 +- src/i18n/locales/en-US.json | 4 +- src/models/Service.js | 3 + src/stores/ServicesStore.js | 10 ++- src/styles/image-upload.scss | 47 ++++++++++- src/styles/settings.scss | 11 ++- 8 files changed, 163 insertions(+), 84 deletions(-) (limited to 'src/models') diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js index 4f2f98a01..c0a993736 100644 --- a/src/components/settings/services/EditServiceForm.js +++ b/src/components/settings/services/EditServiceForm.js @@ -84,6 +84,14 @@ const messages = defineMessages({ id: 'settings.service.form.headlineGeneral', defaultMessage: '!!!General', }, + iconDelete: { + id: 'settings.service.form.iconDelete', + defaultMessage: '!!!Delete', + }, + iconUpload: { + id: 'settings.service.form.iconUpload', + defaultMessage: '!!!Drop your image, or click here', + }, }); @observer @@ -223,14 +231,8 @@ export default class EditServiceForm extends Component {
this.submit(e)} id="form"> -
-
- -
-
- {/* */} - -
+
+
{(recipe.hasTeamId || recipe.hasCustomUrl) && ( )} -
-
-

{intl.formatMessage(messages.headlineNotifications)}

- - -

- {intl.formatMessage(messages.isMutedInfo)} -

-
+
+
+
+

{intl.formatMessage(messages.headlineNotifications)}

+ + +

+ {intl.formatMessage(messages.isMutedInfo)} +

+
-
-

{intl.formatMessage(messages.headlineBadges)}

- - {recipe.hasIndirectMessages && form.$('isBadgeEnabled').value && ( -
- -

- {intl.formatMessage(messages.indirectMessageInfo)} -

-
- )} -
+
+

{intl.formatMessage(messages.headlineBadges)}

+ + {recipe.hasIndirectMessages && form.$('isBadgeEnabled').value && ( +
+ +

+ {intl.formatMessage(messages.indirectMessageInfo)} +

+
+ )} +
-
-

{intl.formatMessage(messages.headlineGeneral)}

- +
+

{intl.formatMessage(messages.headlineGeneral)}

+ +
+
+
+
{recipe.message && ( diff --git a/src/components/ui/ImageUpload.js b/src/components/ui/ImageUpload.js index f25d966f4..08809f007 100644 --- a/src/components/ui/ImageUpload.js +++ b/src/components/ui/ImageUpload.js @@ -12,6 +12,8 @@ export default class ImageUpload extends Component { field: PropTypes.instanceOf(Field).isRequired, className: PropTypes.string, multiple: PropTypes.bool, + textDelete: PropTypes.string.isRequired, + textUpload: PropTypes.string.isRequired, }; static defaultProps = { @@ -39,56 +41,63 @@ export default class ImageUpload extends Component { field, className, multiple, + textDelete, + textUpload, } = this.props; const cssClasses = classnames({ - 'franz-form__button': true, + 'image-upload__dropzone': true, [`${className}`]: className, }); return ( -
- {field.label} - {(field.value && field.value !== 'delete') || this.state.path ? ( -
-
-
- -
+
+ +
+ {(field.value && field.value !== 'delete') || this.state.path ? ( +
+
+
+ +
+
-
- ) : ( - { this.dropzoneRef = node; }} - onDrop={this.onDrop.bind(this)} - className={cssClasses} - multiple={multiple} - accept="image/jpeg, image/png" - > -

Try dropping some files here, or click to select files to upload.

-
- )} + ) : ( + { this.dropzoneRef = node; }} + onDrop={this.onDrop.bind(this)} + className={cssClasses} + multiple={multiple} + accept="image/jpeg, image/png" + > + +

+ {textUpload} +

+
+ )} +
); } diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.js index 8d3a268ad..c26195a1e 100644 --- a/src/containers/settings/EditServiceScreen.js +++ b/src/containers/settings/EditServiceScreen.js @@ -48,7 +48,7 @@ const messages = defineMessages({ }, icon: { id: 'settings.service.form.icon', - defaultMessage: '!!!Icon', + defaultMessage: '!!!Custom icon', }, }); @@ -108,7 +108,7 @@ export default class EditServiceScreen extends Component { }, customIcon: { label: intl.formatMessage(messages.icon), - value: service.hasCustomIcon ? service.icon : false, + value: service.hasCustomUploadedIcon ? service.icon : false, default: null, type: 'file', }, diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index bfb95da04..f3db20aea 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -127,7 +127,9 @@ "settings.service.form.headlineNotifications": "Notifications", "settings.service.form.headlineBadges": "Unread message badges", "settings.service.form.headlineGeneral": "General", - "settings.service.form.icon": "Icon", + "settings.service.form.icon": "Custom icon", + "settings.service.form.iconDelete": "Delete", + "settings.service.form.iconUpload": "Drop your image, or click here", "settings.service.error.headline": "Error", "settings.service.error.goBack": "Back to services", "settings.service.error.message": "Could not load service recipe.", diff --git a/src/models/Service.js b/src/models/Service.js index 652d2594c..423510c7d 100644 --- a/src/models/Service.js +++ b/src/models/Service.js @@ -25,6 +25,7 @@ export default class Service { @observable isBadgeEnabled = true; @observable isIndirectMessageBadgeEnabled = true; @observable iconUrl = ''; + @observable hasCustomUploadedIcon = false; @observable hasCrashed = false; constructor(data, recipe) { @@ -62,6 +63,8 @@ export default class Service { this.isMuted = data.isMuted !== undefined ? data.isMuted : this.isMuted; + this.hasCustomUploadedIcon = data.hasCustomIcon !== undefined ? data.hasCustomIcon : this.hasCustomUploadedIcon; + this.recipe = recipe; autorun(() => { diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 4fb5c9767..f2a8683ba 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -177,13 +177,21 @@ export default class ServicesStore extends Store { await request._promise; newData.iconUrl = request.result.data.iconUrl; + newData.hasCustomUploadedIcon = true; } this.allServicesRequest.patch((result) => { if (!result) return; + // patch custom icon deletion if (data.customIcon === 'delete') { data.iconUrl = ''; + data.hasCustomUploadedIcon = false; + } + + // patch custom icon url + if (data.customIconUrl) { + data.iconUrl = data.customIconUrl; } Object.assign(result.find(c => c.id === serviceId), newData); @@ -328,7 +336,7 @@ export default class ServicesStore extends Store { } } else if (channel === 'avatar') { const url = args[0]; - if (service.customIconUrl !== url) { + if (service.iconUrl !== url && !service.hasCustomUploadedIcon) { service.customIconUrl = url; this.actions.service.updateService({ diff --git a/src/styles/image-upload.scss b/src/styles/image-upload.scss index 764bb3158..06176a7af 100644 --- a/src/styles/image-upload.scss +++ b/src/styles/image-upload.scss @@ -1,9 +1,12 @@ .image-upload { position: absolute; - width: 100px; - height: 100px; - border-radius: $theme-border-radius; + width: 140px; + height: 140px; + border: 1px solid $theme-gray-lighter; + border-radius: $theme-border-radius-small; + background: $theme-gray-lightest; overflow: hidden; + margin-top: 5px; &__preview, &__action { @@ -19,7 +22,7 @@ background-size: 100%; background-repeat: no-repeat; background-position: center center; - margin: 5px; + border-radius: 3px; } &__action { @@ -27,6 +30,8 @@ z-index: 10; opacity: 0; transition: opacity 0.5s; + display: flex; + justify-content: center; &-background { position: absolute; @@ -41,6 +46,33 @@ button { position: relative; z-index: 100; + color: #FFF; + + .mdi { + color: #FFF; + } + } + } + + &__dropzone { + text-align: center; + border-radius: 5px; + padding: 10px; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + } + + &__dropzone, + button { + .mdi { + margin-bottom: 5px; + } + + p { + font-size: 10px; + line-height: 10px; } } @@ -49,4 +81,11 @@ opacity: 1; } } +} + +.image-upload-wrapper { + .mdi { + font-size: 40px; + color: $theme-gray-light; + } } \ No newline at end of file diff --git a/src/styles/settings.scss b/src/styles/settings.scss index 283913ab7..cb39717ea 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss @@ -121,9 +121,15 @@ } .service-icon { - width: 30%; - min-width: 100px; + width: 140px; + float: right; + margin-top: 30px; margin-left: 40px; + + label { + font-weight: bold; + letter-spacing: -0.1px; + } } } @@ -167,6 +173,7 @@ &__options { margin-top: 20px; + flex: 1; } &__settings-group { -- cgit v1.2.3-70-g09d2