diff --git a/css/app-sidebar.scss b/css/app-sidebar.scss
index 6be5d0b0d..02fe53160 100644
--- a/css/app-sidebar.scss
+++ b/css/app-sidebar.scss
@@ -467,6 +467,7 @@
.property-text,
.property-select,
+ .property-color,
.property-select-multiple,
.property-title {
display: flex;
@@ -524,6 +525,18 @@
}
}
+ .property-color {
+ &__color-preview {
+ border-radius: var(--border-radius);
+ height: 34px !important;
+ width: 34px !important;
+ }
+
+ &__info {
+ margin-top: 0;
+ }
+ }
+
.property-text {
&__input {
textarea {
diff --git a/package-lock.json b/package-lock.json
index dcda39ff0..edb9e50e7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7171,6 +7171,27 @@
"is-regexp": "^2.0.0"
}
},
+ "closest-css-color": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/closest-css-color/-/closest-css-color-0.1.1.tgz",
+ "integrity": "sha512-Vor9mkq3sXlEO8FTTjxVhV8jlmh2dQ9oVsrhcSan2f4qikBgnqZnJQXSvxrYrGWEp5UHUIAEEtPZ1OLeyfMa5w==",
+ "requires": {
+ "colour-proximity": "0.0.2",
+ "css-color-names": "0.0.4",
+ "hex-rgb": "^2.0.0",
+ "lodash.merge": "^4.6.1",
+ "lodash.pick": "^4.4.0",
+ "lodash.sortby": "^4.7.0",
+ "lodash.uniqby": "^4.7.0"
+ },
+ "dependencies": {
+ "css-color-names": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
+ "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA="
+ }
+ }
+ },
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -7223,6 +7244,29 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
+ "color-string": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.1.3.tgz",
+ "integrity": "sha1-6GXS4+WfZlw68N4UOD9r8HBWhfM=",
+ "requires": {
+ "color-convert": "0.2.x"
+ },
+ "dependencies": {
+ "color-convert": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.2.1.tgz",
+ "integrity": "sha1-NjyrI8lLMaDWTbcQSLjGqUD4xow="
+ }
+ }
+ },
+ "colour-proximity": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/colour-proximity/-/colour-proximity-0.0.2.tgz",
+ "integrity": "sha1-E5rTr+zzAbyAO42mmPMslyl0dpw=",
+ "requires": {
+ "color-string": "~0.1.2"
+ }
+ },
"combined-stream": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
@@ -7533,6 +7577,11 @@
}
}
},
+ "css-color-names": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-1.0.1.tgz",
+ "integrity": "sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA=="
+ },
"css-loader": {
"version": "3.4.2",
"resolved": "http://registry.npmjs.org/css-loader/-/css-loader-3.4.2.tgz",
@@ -10112,6 +10161,11 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true
},
+ "hex-rgb": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-2.0.0.tgz",
+ "integrity": "sha512-JDPETuFBgYKFWufLB9tk7SaLoia5nSsOSa2DWzbLvK0TXxQglIQ4FBxrO9QmfUKenJJjBfFQ0jJ6jSIK2468kQ=="
+ },
"hmac-drbg": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@@ -13513,14 +13567,17 @@
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
+ },
+ "lodash.pick": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
+ "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM="
},
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
- "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
- "dev": true
+ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg="
},
"lodash.throttle": {
"version": "4.1.1",
@@ -13533,6 +13590,11 @@
"integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=",
"dev": true
},
+ "lodash.uniqby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz",
+ "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI="
+ },
"log-symbols": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
diff --git a/src/components/Editor/Properties/PropertyCalendarPicker.vue b/src/components/Editor/Properties/PropertyCalendarPicker.vue
index cff0d6622..bd824beb3 100644
--- a/src/components/Editor/Properties/PropertyCalendarPicker.vue
+++ b/src/components/Editor/Properties/PropertyCalendarPicker.vue
@@ -76,6 +76,12 @@ export default {
},
},
methods: {
+ /**
+ * Emits the select calendar event
+ *
+ * // TODO: this should emit the calendar id instead
+ * @param {Object} value The calendar Object
+ */
selectCalendar(value) {
this.$emit('selectCalendar', value)
},
diff --git a/src/components/Editor/Properties/PropertyColor.vue b/src/components/Editor/Properties/PropertyColor.vue
new file mode 100644
index 000000000..7eb0783ca
--- /dev/null
+++ b/src/components/Editor/Properties/PropertyColor.vue
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('calendar', 'Remove color') }}
+
+
+
+
+
+
+
diff --git a/src/components/Shared/CalendarPicker.vue b/src/components/Shared/CalendarPicker.vue
index 3fdc3cacf..470f588fd 100644
--- a/src/components/Shared/CalendarPicker.vue
+++ b/src/components/Shared/CalendarPicker.vue
@@ -44,6 +44,10 @@ export default {
},
},
methods: {
+ /**
+ * TODO: this should emit the calendar id instead
+ * @param {Object} newCalendar The selected calendar
+ */
change(newCalendar) {
if (!newCalendar) {
return
diff --git a/src/fullcalendar/eventSourceFunction.js b/src/fullcalendar/eventSourceFunction.js
index 06e51eed6..499a31195 100644
--- a/src/fullcalendar/eventSourceFunction.js
+++ b/src/fullcalendar/eventSourceFunction.js
@@ -24,7 +24,7 @@ import {
hexToRGB,
isLight,
generateTextColorForHex,
- getHexForColorName
+ getHexForColorName,
} from '../utils/color.js'
import logger from '../utils/logger.js'
@@ -94,7 +94,6 @@ export function eventSourceFunction(calendarObjects, calendar, start, end, timez
if (object.color) {
const customColor = getHexForColorName(object.color)
- console.debug(customColor)
if (customColor) {
fcEvent.backgroundColor = customColor
fcEvent.borderColor = customColor
diff --git a/src/mixins/EditorMixin.js b/src/mixins/EditorMixin.js
index d7130071f..e617b3c4f 100644
--- a/src/mixins/EditorMixin.js
+++ b/src/mixins/EditorMixin.js
@@ -177,6 +177,14 @@ export default {
backgroundImage() {
return getIllustrationForTitle(this.title)
},
+ /**
+ * Returns the color the illustration should be colored in
+ *
+ * @returns {String}
+ */
+ illustrationColor() {
+ return this.color || this.selectedCalendarColor
+ },
/**
* Returns the color of the calendar selected by the user
* This is used to color illustration
@@ -195,6 +203,18 @@ export default {
return this.selectedCalendar.color
},
+ /**
+ * Returns the custom color of this event
+ *
+ * @returns {null|String}
+ */
+ color() {
+ if (!this.calendarObjectInstance) {
+ return null
+ }
+
+ return this.calendarObjectInstance.customColor
+ },
/**
* Returns whether or not to display event details
*
diff --git a/src/models/calendarObjectInstance.js b/src/models/calendarObjectInstance.js
index adaec751f..3e7f77649 100644
--- a/src/models/calendarObjectInstance.js
+++ b/src/models/calendarObjectInstance.js
@@ -23,6 +23,7 @@ import { getDateFromDateTimeValue } from '../utils/date.js'
import DurationValue from 'calendar-js/src/values/durationValue.js'
import { getWeekDayFromDate } from '../utils/recurrence.js'
import { getAmountAndUnitForTimedEvents, getAmountHoursMinutesAndUnitForAllDayEvents } from '../utils/alarms.js'
+import { getHexForColorName } from '../utils/color.js'
/**
* Creates a complete calendar-object-instance-object based on given props
@@ -129,6 +130,13 @@ export const mapEventComponentToCalendarObjectInstanceObject = (eventComponent)
calendarObjectInstanceObject.attendees = getAttendeesFromEventComponent(eventComponent)
calendarObjectInstanceObject.alarms = getAlarmsFromEventComponent(eventComponent)
+ if (eventComponent.hasProperty('COLOR')) {
+ const hexColor = getHexForColorName(eventComponent.getFirstPropertyFirstValue('COLOR'))
+ if (hexColor !== null) {
+ calendarObjectInstanceObject.customColor = hexColor
+ }
+ }
+
return calendarObjectInstanceObject
}
diff --git a/src/store/calendarObjectInstance.js b/src/store/calendarObjectInstance.js
index 06eecb642..d97b8ec91 100644
--- a/src/store/calendarObjectInstance.js
+++ b/src/store/calendarObjectInstance.js
@@ -39,6 +39,10 @@ import {
getAmountHoursMinutesAndUnitForAllDayEvents,
getTotalSecondsFromAmountAndUnitForTimedEvents, getTotalSecondsFromAmountHourMinutesAndUnitForAllDayEvents,
} from '../utils/alarms.js'
+import {
+ getClosestCSS3ColorNameForHex,
+ getHexForColorName,
+} from '../utils/color.js'
const state = {
isNew: null,
@@ -355,11 +359,29 @@ const mutations = {
* @param {Object} state The Vuex state
* @param {Object} data The destructuring object
* @param {Object} data.calendarObjectInstance The calendarObjectInstance object
- * @param {String} data.customColor New color to set
+ * @param {String|null} data.customColor New color to set
*/
changeCustomColor(state, { calendarObjectInstance, customColor }) {
- calendarObjectInstance.eventComponent.customColor = customColor
- calendarObjectInstance.customColor = customColor
+ if (customColor === null) {
+ calendarObjectInstance.eventComponent.deleteAllProperties('COLOR')
+ Vue.set(calendarObjectInstance, 'customColor', null)
+ return
+ }
+
+ const cssColorName = getClosestCSS3ColorNameForHex(customColor)
+ const hexColorOfCssName = getHexForColorName(cssColorName)
+
+ // Abort if either is undefined
+ if (!cssColorName || !hexColorOfCssName) {
+ console.error('Setting custom color failed')
+ console.error('customColor: ', customColor)
+ console.error('cssColorName: ', cssColorName)
+ console.error('hexColorOfCssName: ', hexColorOfCssName)
+ return
+ }
+
+ calendarObjectInstance.eventComponent.color = cssColorName
+ Vue.set(calendarObjectInstance, 'customColor', hexColorOfCssName)
},
/**
diff --git a/src/views/EditSidebar.vue b/src/views/EditSidebar.vue
index 511985b0f..968259e7c 100644
--- a/src/views/EditSidebar.vue
+++ b/src/views/EditSidebar.vue
@@ -51,7 +51,7 @@
-
+
@@ -124,6 +124,13 @@
:value="categories"
@addSingleValue="addCategory"
@removeSingleValue="removeCategory" />
+
+
diff --git a/src/views/EditSimple.vue b/src/views/EditSimple.vue
index 844defcd8..6a7a8609d 100644
--- a/src/views/EditSimple.vue
+++ b/src/views/EditSimple.vue
@@ -50,7 +50,7 @@
{
beforeEach(() => {
translate.mockClear()
+ getHexForColorName.mockClear()
+ generateTextColorForHex.mockClear()
})
it('should provide fc-events', () => {
translate
.mockImplementation((app, str) => str)
+ getHexForColorName
+ .mockImplementation(() => '#ff0000')
+ generateTextColorForHex
+ .mockImplementation(() => '#eeeeee')
+ isLight
+ .mockImplementation(() => false)
const event11Start = new Date(2020, 1, 1, 10, 0, 0, 0);
const event11End = new Date(2020, 1, 1, 15, 0, 0, 0);
@@ -131,6 +146,7 @@ describe('fullcalendar/eventSourceFunction test suite', () => {
})
},
hasComponent: jest.fn().mockReturnValue(false),
+ color: 'red',
}]
const calendarObjects = [{
@@ -249,7 +265,10 @@ describe('fullcalendar/eventSourceFunction test suite', () => {
calendarName: 'Calendar displayname',
calendarOrder: 1337,
darkText: false,
- }
+ },
+ backgroundColor: '#ff0000',
+ borderColor: '#ff0000',
+ textColor: '#eeeeee',
}
])
@@ -285,6 +304,12 @@ describe('fullcalendar/eventSourceFunction test suite', () => {
expect(translate).toHaveBeenNthCalledWith(4, 'calendar', 'Untitled event')
expect(translate).toHaveBeenNthCalledWith(5, 'calendar', 'Untitled event')
+ expect(getHexForColorName).toHaveBeenCalledTimes(1)
+ expect(getHexForColorName).toHaveBeenNthCalledWith(1, 'red')
+
+ expect(generateTextColorForHex).toHaveBeenCalledTimes(1)
+ expect(generateTextColorForHex).toHaveBeenNthCalledWith(1, '#ff0000')
+
// Make sure the following dates have not been touched
expect(event11Start.getFullYear()).toEqual(2020)
expect(event11Start.getMonth()).toEqual(1)