Skip to content

Commit

Permalink
fixup! feat(systemtags): add color support
Browse files Browse the repository at this point in the history
Signed-off-by: skjnldsv <[email protected]>
  • Loading branch information
skjnldsv committed Nov 14, 2024
1 parent 373e8a2 commit adf3ddf
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 13 deletions.
65 changes: 52 additions & 13 deletions apps/systemtags/src/components/SystemTagPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<li v-for="tag in filteredTags"
:key="tag.id"
:data-cy-systemtags-picker-tag="tag.id"
:style="{'--color-primary-element': tag.color ? `#${tag.color}` : null}"
:style="tagListStyle(tag)"
class="systemtags-picker__tag">
<NcCheckboxRadioSwitch :checked="isChecked(tag)"
:disabled="!tag.canAssign"
Expand All @@ -48,14 +48,19 @@
</NcCheckboxRadioSwitch>

<!-- Color picker -->
<NcColorPicker v-slot="{ attrs }"
:data-cy-systemtags-picker-tag-color="tag.id"
:value="tag.color ? `#${tag.color}` : primaryColor"
<NcColorPicker :data-cy-systemtags-picker-tag-color="tag.id"
:value="`#${tag.color || primaryColor}`"
class="systemtags-picker__tag-color"
@update:value="onColorChange(tag, $event)">
<CircleIcon v-bind="attrs" :size="24" />
<NcButton :aria-label="t('systemtags', 'Change tag color')" type="primary">
<template #icon>
<PencilIcon />
</template>
</NcButton>
</NcColorPicker>
</li>

<!-- Create new tag -->
<li>
<NcButton v-if="canCreateTag"
:disabled="status === Status.CREATING_TAG"
Expand Down Expand Up @@ -118,7 +123,6 @@ import { defineComponent } from 'vue'
import { emit } from '@nextcloud/event-bus'
import { sanitize } from 'dompurify'
import { showError, showInfo } from '@nextcloud/dialogs'
import { getCapabilities } from '@nextcloud/capabilities'
import { getLanguage, n, t } from '@nextcloud/l10n'
import escapeHTML from 'escape-html'
Expand All @@ -131,16 +135,19 @@ import NcEmptyContent from '@nextcloud/vue/dist/Components/NcEmptyContent.js'
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
import TagIcon from 'vue-material-design-icons/Tag.vue'
import CheckIcon from 'vue-material-design-icons/CheckCircle.vue'
import PencilIcon from 'vue-material-design-icons/Pencil.vue'
import PlusIcon from 'vue-material-design-icons/Plus.vue'
import CircleIcon from 'vue-material-design-icons/Circle.vue'
import TagIcon from 'vue-material-design-icons/Tag.vue'
import { getNodeSystemTags, setNodeSystemTags } from '../utils'
import { createTag, fetchTag, fetchTags, getTagObjects, setTagObjects } from '../services/api'
import { getNodeSystemTags, setNodeSystemTags } from '../utils'
import { invertTextColor } from '../utils/colorUtils'
import logger from '../services/logger'
const primaryColor = getCapabilities()?.theming?.['color-element'] || '#00679e'
const primaryColor = getComputedStyle(document.documentElement)
.getPropertyValue('--color-primary-element')
.replace('#', '') || '0069c3'
type TagListCount = {
string: number
Expand Down Expand Up @@ -168,9 +175,9 @@ export default defineComponent({
NcLoadingIcon,
NcNoteCard,
NcTextField,
PencilIcon,
PlusIcon,
TagIcon,
CircleIcon,
},
props: {
Expand Down Expand Up @@ -351,7 +358,14 @@ export default defineComponent({
// Format & sanitize a tag chip for v-html tag rendering
formatTagChip(tag: TagWithId): string {
const chip = this.$refs.chip as NcChip
const chipHtml = chip.$el.outerHTML
const chipCloneEl = chip.$el.cloneNode(true) as HTMLElement
if (tag.color) {
const style = this.tagListStyle(tag)
Object.entries(style).forEach(([key, value]) => {
chipCloneEl.style.setProperty(key, value)
})
}
const chipHtml = chipCloneEl.outerHTML
return chipHtml.replace('%s', escapeHTML(sanitize(tag.displayName)))
},
Expand Down Expand Up @@ -506,6 +520,19 @@ export default defineComponent({
showInfo(t('systemtags', 'File tags modification canceled'))
this.$emit('close', null)
},
tagListStyle(tag: TagWithId): Record<string, string> {
return {
'--color-primary': `#${tag.color || primaryColor}`,
'--color-primary-text': this.primaryElementTextColor(tag.color || primaryColor),
'--color-primary-element': `#${tag.color || primaryColor}`,
'--color-primary-element-text': this.primaryElementTextColor(tag.color || primaryColor),
}
},
primaryElementTextColor(color: string): string {
return invertTextColor(color) ? '#000000' : '#ffffff'
},
},
})
</script>
Expand Down Expand Up @@ -554,11 +581,23 @@ export default defineComponent({
}
.systemtags-picker__tag-color {
margin-inline-start: var(--default-grid-baseline);
margin-inline-start: calc(var(--default-grid-baseline) * 2);
color: var(--color-primary-element);
width: var(--default-clickable-area);
height: var(--default-clickable-area);
display: flex;
button {
border-radius: 50%;
span {
display: none;
}
&:focus span,
&:hover span {
display: block;
}
}
}
.systemtags-picker__tag-create {
Expand Down
41 changes: 41 additions & 0 deletions apps/systemtags/src/utils/colorUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

type rgb = {
red: number
green: number
blue: number
}

/**
* Convert hex color to RGB
*/
export function hexToRGB(hex: string): rgb {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
if (!result) {
throw new Error('Invalid color')
}

return {
red: parseInt(result[1], 16),
green: parseInt(result[2], 16),
blue: parseInt(result[3], 16),
}
}

/**
* Calculate luminance of provided hex color
*/
export function calculateLuma(color: string): number {
const rgb = hexToRGB(color)
return (0.2126 * rgb.red + 0.7152 * rgb.green + 0.0722 * rgb.blue) / 255
}

/**
* Do we need to invert the text if color is too bright?
*/
export function invertTextColor(color: string): boolean {
return calculateLuma(color) > 0.6
}

0 comments on commit adf3ddf

Please sign in to comment.