Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions l10n/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ msgstr ""
msgid "{tag} (restricted)"
msgstr ""

msgid "A color with a HEX value {hex}"
msgstr ""

msgid "a few seconds ago"
msgstr ""

Expand Down Expand Up @@ -119,6 +122,9 @@ msgstr ""
msgid "Go back to the list"
msgstr ""

msgid "Gold"
msgstr ""

msgid "Hide password"
msgstr ""

Expand All @@ -137,6 +143,9 @@ msgstr ""
msgid "Next"
msgstr ""

msgid "Nextcloud blue"
msgstr ""

msgid "No emoji found"
msgstr ""

Expand Down Expand Up @@ -209,6 +218,9 @@ msgstr ""
msgid "Provider icon"
msgstr ""

msgid "Purple"
msgstr ""

msgid "Raw link {options}"
msgstr ""

Expand Down
76 changes: 57 additions & 19 deletions src/components/NcColorPicker/NcColorPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- @copyright Copyright (c) 2019 Marco Ambrosini <[email protected]>
-
- @author Marco Ambrosini <[email protected]>
- @author Grigorii K. Shartsev <[email protected]>
-
- @license GNU AGPL version 3 or any later version
-
Expand Down Expand Up @@ -165,26 +166,29 @@ export default {
</template>
<div class="color-picker"
:class="{ 'color-picker--advanced-fields': advanced && advancedFields }">
<transition name="slide" mode="out-in">
<Transition name="slide" mode="out-in">
<div v-if="!advanced" class="color-picker__simple">
<button v-for="(color, index) in palette"
<label v-for="({ color, name }, index) in normalizedPalette"
:key="index"
:style="{'background-color': color }"
:style="{ backgroundColor: color }"
class="color-picker__simple-color-circle"
:class="{ 'color-picker__simple-color-circle--active' : color === currentColor }"
type="button"
@click="pickColor(color)">
<Check v-if="color === currentColor"
:size="20" />
</button>
:aria-label="name">
<Check v-if="color === currentColor" :size="20" />
<input type="radio"
class="hidden-visually"
:name="`color-picker-${uid}`"
:checked="color === currentColor"
@click="pickColor(color)">
</label>
</div>
<Chrome v-if="advanced"
v-model="currentColor"
class="color-picker__advanced"
:disable-alpha="true"
:disable-fields="!advancedFields"
@input="pickColor" />
</transition>
</Transition>
<div class="color-picker__navigation">
<NcButton v-if="advanced"
type="tertiary"
Expand Down Expand Up @@ -217,18 +221,30 @@ import NcButton from '../NcButton/index.js'
import NcPopover from '../NcPopover/index.js'
import { t } from '../../l10n.js'
import GenColors from '../../utils/GenColors.js'
import GenRandomId from '../../utils/GenRandomId.js'

import ArrowLeft from 'vue-material-design-icons/ArrowLeft.vue'
import Check from 'vue-material-design-icons/Check.vue'
import DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'

import { Chrome } from 'vue-color'

const rgbToHex = function(color) {
const hex = color.toString(16)
return hex.length === 1 ? '0' + hex : hex
/**
* Convert RGB object to a HEX string color
*
* @param {object} color - The color to convert
* @param {string} [color.r] - Red value
* @param {string} [color.g] - Green value
* @param {string} [color.b] - Blue value
* @return {string} The hex value
*/
export function rgbToHex({ r, g, b }) {
const toHex = (number) => number.toString(16).padStart(2, '0')
return `#${toHex(r)}${toHex(g)}${toHex(b)}`
}

const HEX_REGEX = /^#([a-f0-9]{3}|[a-f0-9]{6})$/i

export default {
name: 'NcColorPicker',

Expand Down Expand Up @@ -259,16 +275,20 @@ export default {
},

/**
* Provide a custom array of hexadecimal colors to show
* Provide a custom array of colors to show.
* Can be either an array of string hexadecimal colors,
* or an array of object with a `color` property with hexadecimal color string,
* and a `name` property for accessibility.
*
* @type {string[] | {color: string, name: string}[]}
*/
palette: {
type: Array,
default: () => GenColors(4).map(color => {
return '#' + rgbToHex(color.r) + rgbToHex(color.g) + rgbToHex(color.b)
}),
validator(palette) {
return palette.every(color => /^#([a-f0-9]{3}|[a-f0-9]{6})$/i.test(color))
},
default: () => GenColors(4).map(item => ({ color: rgbToHex(item), name: item.name })),
validator: (palette) => palette.every(item =>
(typeof item === 'string' && HEX_REGEX.test(item))
|| (typeof item === 'object' && item.color && HEX_REGEX.test(item.color)),
),
},
},

Expand All @@ -289,6 +309,21 @@ export default {
}
},

computed: {
normalizedPalette() {
return this.palette.map((item) => ({
color: typeof item === 'object' ? item.color : item,
name: typeof item === 'object' && item.name
? item.name
: t('A color with a HEX value {hex}', { hex: item.color }),
}))
},

uid() {
return GenRandomId()
},
},

watch: {
value(color) {
this.currentColor = color
Expand Down Expand Up @@ -389,6 +424,9 @@ export default {
border: 1px solid rgba(0, 0, 0, 0.25);
border-radius: 50%;
font-size: 16px;
&:focus-within {
outline: 2px solid var(--color-main-text);
}
&:hover {
opacity: .6;
}
Expand Down
45 changes: 28 additions & 17 deletions src/utils/GenColors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* @copyright Copyright (c) 2019 John Molakvoæ <[email protected]>
*
* @author John Molakvoæ <[email protected]>
* @author Grigorii K. Shartsev <[email protected]>
*
* @license AGPL-3.0-or-later
*
Expand All @@ -24,15 +25,25 @@
* Originally taken from https://github.com/nextcloud/server/blob/master/core/js/placeholder.js
*/

/**
* @param {number} r The red value
* @param {number} g The green value
* @param {number} b The blue value
*/
function Color(r, g, b) {
this.r = r
this.g = g
this.b = b
import { t } from '../l10n.js'

class Color {

/**
* @param {number} r The red value
* @param {number} g The green value
* @param {number} b The blue value
* @param {string} [name] The name of the color
*/
constructor(r, g, b, name) {
this.r = r
this.g = g
this.b = b
if (name) {
this.name = name
}
}

}

/**
Expand All @@ -54,18 +65,18 @@ function stepCalc(steps, ends) {
* Create a color palette from two colors
*
* @param {number} steps The number of steps the palette has
* @param {string} color1 The first color
* @param {string} color2 The second color
* @param {Color} color1 The first color
* @param {Color} color2 The second color
* @return {Array} The created palette array
*/
function mixPalette(steps, color1, color2) {
const palette = []
palette.push(color1)
const step = stepCalc(steps, [color1, color2])
for (let i = 1; i < steps; i++) {
const r = parseInt(color1.r + step[0] * i, 10)
const g = parseInt(color1.g + step[1] * i, 10)
const b = parseInt(color1.b + step[2] * i, 10)
const r = Math.floor(color1.r + step[0] * i)
const g = Math.floor(color1.g + step[1] * i)
const b = Math.floor(color1.b + step[2] * i)
palette.push(new Color(r, g, b))
}
return palette
Expand All @@ -85,9 +96,9 @@ function GenColors(steps) {
steps = 6
}

const red = new Color(182, 70, 157)
const yellow = new Color(221, 203, 85)
const blue = new Color(0, 130, 201) // Nextcloud blue
const red = new Color(182, 70, 157, t('Purple'))
const yellow = new Color(221, 203, 85, t('Gold'))
const blue = new Color(0, 130, 201, t('Nextcloud blue'))

const palette1 = mixPalette(steps, red, yellow)
const palette2 = mixPalette(steps, yellow, blue)
Expand Down