Skip to content

Commit d47f01a

Browse files
authored
Merge pull request #60490 from nextcloud/backport/60347/stable33
[stable33] fix(workflowengine): use proper contrast colors for operations
2 parents f39a3c5 + 49aca3f commit d47f01a

8 files changed

Lines changed: 491 additions & 33 deletions

File tree

apps/workflowengine/src/components/Operation.spec.ts

Lines changed: 408 additions & 0 deletions
Large diffs are not rendered by default.

apps/workflowengine/src/components/Operation.vue

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
- SPDX-License-Identifier: AGPL-3.0-or-later
44
-->
55
<template>
6-
<div class="actions__item" :class="{ colored: colored }" :style="{ backgroundColor: colored ? operation.color : 'transparent' }">
6+
<div
7+
ref="operationElement"
8+
class="actions__item"
9+
:class="{ colored: colored }">
710
<div class="icon" :class="operation.iconClass" :style="{ backgroundImage: operation.iconClass ? '' : `url(${operation.icon})` }" />
811
<div class="actions__item__description">
912
<h3>{{ operation.name }}</h3>
@@ -18,30 +21,69 @@
1821
</div>
1922
</template>
2023

21-
<script>
24+
<script setup lang="ts">
25+
/* eslint vue/multi-word-component-names: "warn" */
26+
27+
import { t } from '@nextcloud/l10n'
28+
import Color from 'color'
29+
import { computed, nextTick, ref, watch } from 'vue'
2230
import NcButton from '@nextcloud/vue/components/NcButton'
2331
24-
export default {
25-
/* eslint vue/multi-word-component-names: "warn" */
26-
name: 'Operation',
27-
components: {
28-
NcButton,
29-
},
30-
31-
props: {
32-
operation: {
33-
type: Object,
34-
required: true,
35-
},
36-
37-
colored: {
38-
type: Boolean,
39-
default: true,
40-
},
41-
},
42-
}
32+
const props = defineProps<{
33+
operation: Record<string, string>
34+
colored?: boolean
35+
}>()
36+
37+
const operationElement = ref<HTMLDivElement>()
38+
const color = ref('var(--color-main-text)')
39+
const backgroundColor = computed(() => props.colored ? (props.operation.color || 'var(--color-primary-element)') : 'transparent')
40+
41+
watch(backgroundColor, async () => {
42+
if (backgroundColor.value === 'transparent') {
43+
color.value = 'var(--color-main-text)'
44+
return
45+
} else if (backgroundColor.value === 'var(--color-primary-element)') {
46+
color.value = 'var(--color-primary-element-text)'
47+
return
48+
}
49+
50+
let bgColor = backgroundColor.value
51+
if (!bgColor.startsWith('#')) {
52+
await nextTick()
53+
bgColor = window.getComputedStyle(operationElement.value!).backgroundColor
54+
}
55+
try {
56+
const contrast = Color(bgColor).contrast(Color('#ffffff'))
57+
color.value = contrast > 4.5 ? '#ffffff' : '#000000'
58+
} catch {
59+
color.value = 'var(--color-main-text)'
60+
}
61+
}, { immediate: true })
62+
63+
/**
64+
* Filter to apply to the icon to make it accessible on the given background color.
65+
*/
66+
const iconFilter = computed(() => {
67+
if (color.value === '#000000') {
68+
return 'invert(100%)'
69+
}
70+
return 'none'
71+
})
4372
</script>
4473

4574
<style scoped lang="scss">
4675
@use "./../styles/operation.scss" as *;
76+
77+
.actions__item {
78+
color: v-bind('color');
79+
background-color: v-bind('backgroundColor');
80+
81+
h3 {
82+
color: v-bind('color');
83+
}
84+
85+
.icon {
86+
filter: v-bind('iconFilter');
87+
}
88+
}
4789
</style>

apps/workflowengine/src/components/Rule.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
</div>
3131
<div class="flow-icon icon-confirm" />
3232
<div class="action">
33-
<Operation :operation="operation" :colored="false">
33+
<Operation :operation="operation">
3434
<component
3535
:is="operation.element"
3636
v-if="operation.element"

apps/workflowengine/src/components/Workflow.vue

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@
2828
v-for="operation in mainOperations"
2929
:key="operation.id"
3030
:operation="operation"
31+
colored
3132
@click.native="createNewRule(operation)" />
3233
<a
3334
v-if="showAppStoreHint"
3435
key="add"
3536
:href="appstoreUrl"
3637
class="actions__item colored more">
37-
<div class="icon icon-add" />
38+
<NcIconSvgWrapper class="actions__itemMore__icon" :path="mdiPlus" :size="50" />
3839
<div class="actions__item__description">
3940
<h3>{{ t('workflowengine', 'More flows') }}</h3>
4041
<small>{{ t('workflowengine', 'Browse the App Store') }}</small>
@@ -69,6 +70,7 @@
6970
</template>
7071

7172
<script>
73+
import { mdiPlus } from '@mdi/js'
7274
import { loadState } from '@nextcloud/initial-state'
7375
import { generateUrl } from '@nextcloud/router'
7476
import { mapGetters, mapState } from 'vuex'
@@ -100,6 +102,10 @@ export default {
100102
Rule,
101103
},
102104
105+
setup() {
106+
return { mdiPlus }
107+
},
108+
103109
data() {
104110
return {
105111
showMoreOperations: false,
@@ -186,6 +192,10 @@ export default {
186192
margin-bottom: 10px;
187193
}
188194
195+
.actions__itemMore__icon {
196+
margin-block: 10px;
197+
}
198+
189199
.slide-enter-active {
190200
-moz-transition-duration: 0.3s;
191201
-webkit-transition-duration: 0.3s;

apps/workflowengine/src/styles/operation.scss

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,6 @@ small {
5454
flex-grow: 1;
5555
}
5656

57-
.colored:not(.more) {
58-
background-color: var(--color-primary-element);
59-
h3, small {
60-
color: var(--color-primary-element-text)
61-
}
62-
}
63-
6457
.actions__item:not(.colored) {
6558
flex-direction: row;
6659

dist/workflowengine-workflowengine.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/workflowengine-workflowengine.js.license

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ SPDX-License-Identifier: MIT
22
SPDX-License-Identifier: ISC
33
SPDX-License-Identifier: GPL-3.0-or-later
44
SPDX-License-Identifier: BSD-3-Clause
5+
SPDX-License-Identifier: Apache-2.0
56
SPDX-License-Identifier: AGPL-3.0-or-later
67
SPDX-License-Identifier: (MPL-2.0 OR Apache-2.0)
78
SPDX-FileCopyrightText: webfansplz
@@ -35,6 +36,7 @@ SPDX-FileCopyrightText: Eduardo San Martin Morote
3536
SPDX-FileCopyrightText: Dr.-Ing. Mario Heiderich, Cure53 <mario@cure53.de> (https://cure53.de/)
3637
SPDX-FileCopyrightText: David Clark
3738
SPDX-FileCopyrightText: Christoph Wurst
39+
SPDX-FileCopyrightText: Austin Andrews
3840
SPDX-FileCopyrightText: Anthony Fu <https://github.com/antfu>
3941
SPDX-FileCopyrightText: Anthony Fu <anthonyfu117@hotmail.com>
4042
SPDX-FileCopyrightText: @nextcloud/dialogs developers
@@ -50,6 +52,9 @@ This file is generated from multiple sources. Included packages:
5052
- @floating-ui/utils
5153
- version: 0.2.11
5254
- license: MIT
55+
- @mdi/js
56+
- version: 7.4.47
57+
- license: Apache-2.0
5358
- @nextcloud/auth
5459
- version: 2.6.0
5560
- license: GPL-3.0-or-later

dist/workflowengine-workflowengine.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)