UPD: Change HSLInput to HSV
Ported to color library
This commit is contained in:
35
package-lock.json
generated
35
package-lock.json
generated
@@ -18,6 +18,7 @@
|
|||||||
"axios": "^1.6.5",
|
"axios": "^1.6.5",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
|
"color": "^4.2.3",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"lucide-vue-next": "^0.309.0",
|
"lucide-vue-next": "^0.309.0",
|
||||||
"radix-vue": "^1.3.0",
|
"radix-vue": "^1.3.0",
|
||||||
@@ -4254,6 +4255,18 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/color": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^2.0.1",
|
||||||
|
"color-string": "^1.9.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
@@ -4270,6 +4283,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/color-string": {
|
||||||
|
"version": "1.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
|
||||||
|
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "^1.0.0",
|
||||||
|
"simple-swizzle": "^0.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/colors": {
|
"node_modules/colors": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
|
||||||
@@ -11287,6 +11309,19 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/simple-swizzle": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
|
||||||
|
"dependencies": {
|
||||||
|
"is-arrayish": "^0.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/simple-swizzle/node_modules/is-arrayish": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
|
||||||
|
},
|
||||||
"node_modules/sirv": {
|
"node_modules/sirv": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"axios": "^1.6.5",
|
"axios": "^1.6.5",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
|
"color": "^4.2.3",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"lucide-vue-next": "^0.309.0",
|
"lucide-vue-next": "^0.309.0",
|
||||||
"radix-vue": "^1.3.0",
|
"radix-vue": "^1.3.0",
|
||||||
|
|||||||
@@ -1,152 +1,63 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
|
import Color from 'color'
|
||||||
import { SliderRoot, SliderThumb, SliderTrack } from 'radix-vue'
|
import { SliderRoot, SliderThumb, SliderTrack } from 'radix-vue'
|
||||||
|
|
||||||
|
const hueSliderValue = ref(0)
|
||||||
|
const saturationSliderValue = ref(100)
|
||||||
|
const valueSliderValue = ref(50)
|
||||||
|
|
||||||
const hueSliderModel = computed({
|
const hueSliderModel = computed({
|
||||||
get() {
|
get() {
|
||||||
return [hue.value]
|
return [hueSliderValue.value]
|
||||||
},
|
},
|
||||||
set(value) {
|
set(hue) {
|
||||||
hue.value = value[0]
|
hueSliderValue.value = hue[0]
|
||||||
|
color.value = color.value.hue(hue[0])
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const saturationSliderModel = computed({
|
const saturationSliderModel = computed({
|
||||||
get() {
|
get() {
|
||||||
return [saturation.value]
|
return [saturationSliderValue.value]
|
||||||
},
|
},
|
||||||
set(value) {
|
set(saturation) {
|
||||||
saturation.value = value[0]
|
saturationSliderValue.value = saturation[0]
|
||||||
|
color.value = color.value.saturationv(saturation[0])
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const lightnessSliderModel = computed({
|
const valueSliderModel = computed({
|
||||||
get() {
|
get() {
|
||||||
return [lightness.value]
|
return [valueSliderValue.value]
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
lightness.value = value[0]
|
valueSliderValue.value = value[0]
|
||||||
|
color.value = color.value.value(value[0])
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const hue = ref(0)
|
const color = ref(Color('#FF0000'))
|
||||||
const saturation = ref(100)
|
|
||||||
const lightness = ref(50)
|
const sliderColor = computed(() => {
|
||||||
|
return Color.hsv(hueSliderModel.value[0], 100, valueSliderModel.value[0])
|
||||||
|
})
|
||||||
|
|
||||||
const hexInput = ref('FF0000')
|
const hexInput = ref('FF0000')
|
||||||
const hueInput = ref('000')
|
const hueInput = ref('000')
|
||||||
const saturationInput = ref('100')
|
const saturationInput = ref('100')
|
||||||
const lightnessInput = ref('050')
|
const valueInput = ref('050')
|
||||||
const rInput = ref('255')
|
const rInput = ref('255')
|
||||||
const gInput = ref('000')
|
const gInput = ref('000')
|
||||||
const bInput = ref('000')
|
const bInput = ref('000')
|
||||||
|
|
||||||
function hueToRGB(p, q, t) {
|
|
||||||
if (t < 0) t += 1
|
|
||||||
if (t > 1) t -= 1
|
|
||||||
if (t < 1 / 6) return p + (q - p) * 6 * t
|
|
||||||
if (t < 1 / 2) return q
|
|
||||||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
function RGBtoHSL(r, g, b) {
|
|
||||||
r /= 255
|
|
||||||
g /= 255
|
|
||||||
b /= 255
|
|
||||||
|
|
||||||
const max = Math.max(r, g, b)
|
|
||||||
const min = Math.min(r, g, b)
|
|
||||||
let h, s, l = (max + min) / 2
|
|
||||||
|
|
||||||
if (max === min) {
|
|
||||||
h = s = 0 // achromatic
|
|
||||||
} else {
|
|
||||||
const d = max - min
|
|
||||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
|
|
||||||
switch (max) {
|
|
||||||
case r:
|
|
||||||
h = (g - b) / d + (g < b ? 6 : 0)
|
|
||||||
break
|
|
||||||
case g:
|
|
||||||
h = (b - r) / d + 2
|
|
||||||
break
|
|
||||||
case b:
|
|
||||||
h = (r - g) / d + 4
|
|
||||||
break
|
|
||||||
}
|
|
||||||
h /= 6
|
|
||||||
}
|
|
||||||
|
|
||||||
return [h * 360, s * 100, l * 100]
|
|
||||||
}
|
|
||||||
|
|
||||||
function HSLtoRGB(h, s, l) {
|
|
||||||
h /= 360
|
|
||||||
s /= 100
|
|
||||||
l /= 100
|
|
||||||
|
|
||||||
let r, g, b
|
|
||||||
|
|
||||||
if (s === 0) {
|
|
||||||
r = g = b = l // achromatic
|
|
||||||
} else {
|
|
||||||
const q = l < 0.5 ? l * (1 + s) : l + s - l * s
|
|
||||||
const p = 2 * l - q
|
|
||||||
r = hueToRGB(p, q, h + 1 / 3)
|
|
||||||
g = hueToRGB(p, q, h)
|
|
||||||
b = hueToRGB(p, q, h - 1 / 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]
|
|
||||||
}
|
|
||||||
|
|
||||||
function hexToRGB(hex) {
|
|
||||||
const r = parseInt(hex.substring(1, 3), 16)
|
|
||||||
const g = parseInt(hex.substring(3, 5), 16)
|
|
||||||
const b = parseInt(hex.substring(5, 7), 16)
|
|
||||||
|
|
||||||
return [r, g, b]
|
|
||||||
}
|
|
||||||
|
|
||||||
function rgbToHex(r, g, b) {
|
|
||||||
const componentToHex = (c) => {
|
|
||||||
const hex = c.toString(16)
|
|
||||||
return hex.length === 1 ? '0' + hex : hex
|
|
||||||
}
|
|
||||||
|
|
||||||
return '#' + componentToHex(r) + componentToHex(g) + componentToHex(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
const rgb = computed({
|
|
||||||
get() {
|
|
||||||
return HSLtoRGB(hue.value, saturation.value, lightness.value)
|
|
||||||
},
|
|
||||||
set([r, g, b]) {
|
|
||||||
const [h, s, l] = RGBtoHSL(r, g, b)
|
|
||||||
hue.value = h
|
|
||||||
saturation.value = s
|
|
||||||
lightness.value = l
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const hexCode = computed({
|
|
||||||
get() {
|
|
||||||
return rgbToHex(rgb.value[0], rgb.value[1], rgb.value[2])
|
|
||||||
},
|
|
||||||
set(hex) {
|
|
||||||
const [r, g, b] = hexToRGB(hex)
|
|
||||||
rgb.value = [r, g, b]
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
function onSubmitHexInput() {
|
function onSubmitHexInput() {
|
||||||
let input = hexInput.value
|
let input = hexInput.value
|
||||||
if (input[0] !== '#') {
|
if (input[0] !== '#') {
|
||||||
input = '#' + input
|
input = '#' + input
|
||||||
}
|
}
|
||||||
if (input.match(/^#[0-9A-F]{6}$/i)) {
|
if (input.match(/^#[0-9A-F]{6}$/i)) {
|
||||||
hexCode.value = input
|
color.value = Color(input)
|
||||||
} else
|
} else
|
||||||
shake()
|
shake()
|
||||||
}
|
}
|
||||||
@@ -157,11 +68,11 @@ function onSubmitHueInput() {
|
|||||||
shake()
|
shake()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const newValue = Math.max(0, Math.min(input, 360))
|
const newHue = Math.max(0, Math.min(input, 360))
|
||||||
if (newValue === hue.value) {
|
if (newHue === color.value.hue()) {
|
||||||
updateHueInput(newValue)
|
updateInputs()
|
||||||
}
|
}
|
||||||
hue.value = newValue
|
color.value = color.value.hue(newHue)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSubmitSaturationInput() {
|
function onSubmitSaturationInput() {
|
||||||
@@ -170,24 +81,24 @@ function onSubmitSaturationInput() {
|
|||||||
shake()
|
shake()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const newValue = Math.max(0, Math.min(input, 100))
|
const newSaturation = Math.max(0, Math.min(input, 100))
|
||||||
if (newValue === saturation.value) {
|
if (newSaturation === color.value.saturationv()) {
|
||||||
updateSaturationInput(newValue)
|
updateInputs()
|
||||||
}
|
}
|
||||||
saturation.value = newValue
|
color.value = color.value.saturationv(newSaturation)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSubmitLightnessInput() {
|
function onSubmitValueInput() {
|
||||||
const input = parseInt(lightnessInput.value)
|
const input = parseInt(valueInput.value)
|
||||||
if (isNaN(input)) {
|
if (isNaN(input)) {
|
||||||
shake()
|
shake()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const newValue = Math.max(0, Math.min(input, 100))
|
const newValue = Math.max(0, Math.min(input, 100))
|
||||||
if (newValue === lightness.value) {
|
if (newValue === color.value.value()) {
|
||||||
updateLightnessInput(newValue)
|
updateInputs()
|
||||||
}
|
}
|
||||||
lightness.value = newValue
|
color.value = color.value.value(newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSubmitRGBInput() {
|
function onSubmitRGBInput() {
|
||||||
@@ -198,68 +109,27 @@ function onSubmitRGBInput() {
|
|||||||
shake()
|
shake()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const newValue = [
|
const newColor = Color.rgb(r, g, b)
|
||||||
Math.max(0, Math.min(r, 255)),
|
if (newColor.hex() === color.value.hex()) {
|
||||||
Math.max(0, Math.min(g, 255)),
|
updateInputs()
|
||||||
Math.max(0, Math.min(b, 255)),
|
|
||||||
]
|
|
||||||
if (newValue[0] === rgb.value[0] && newValue[1] === rgb.value[1] && newValue[2] === rgb.value[2]) {
|
|
||||||
updateRInput(newValue[0])
|
|
||||||
updateGInput(newValue[1])
|
|
||||||
updateBInput(newValue[2])
|
|
||||||
}
|
}
|
||||||
rgb.value = newValue
|
color.value = newColor
|
||||||
}
|
}
|
||||||
|
|
||||||
function foregroundBlack(r, g, b) {
|
function updateInputs() {
|
||||||
const bgColor = [r / 255, g / 255, b / 255]
|
hexInput.value = color.value.hex().substring(1, 7)
|
||||||
const c = bgColor.map((col) => {
|
hueInput.value = String(parseInt(color.value.hue())).padStart(3, '0')
|
||||||
if (col <= 0.03928) {
|
saturationInput.value = String(parseInt(color.value.saturationv())).padStart(3, '0')
|
||||||
return col / 12.92
|
valueInput.value = String(parseInt(color.value.value())).padStart(3, '0')
|
||||||
}
|
rInput.value = String(parseInt(color.value.red())).padStart(3, '0')
|
||||||
return Math.pow((col + 0.055) / 1.055, 2.4)
|
gInput.value = String(parseInt(color.value.green())).padStart(3, '0')
|
||||||
})
|
bInput.value = String(parseInt(color.value.blue())).padStart(3, '0')
|
||||||
const l = (0.2126 * c[0]) + (0.7152 * c[1]) + (0.0722 * c[2])
|
hueSliderValue.value = color.value.hue()
|
||||||
return l > 0.179
|
saturationSliderValue.value = color.value.saturationv()
|
||||||
|
valueSliderValue.value = color.value.value()
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateHexInput(hex) {
|
watch(color, updateInputs)
|
||||||
hexInput.value = hex.substring(1, 7)
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateHueInput(hue) {
|
|
||||||
hueInput.value = String(parseInt(hue)).padStart(3, '0')
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateSaturationInput(saturation) {
|
|
||||||
saturationInput.value = String(parseInt(saturation)).padStart(3, '0')
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLightnessInput(lightness) {
|
|
||||||
lightnessInput.value = String(parseInt(lightness)).padStart(3, '0')
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateRInput(r) {
|
|
||||||
rInput.value = String(parseInt(r)).padStart(3, '0')
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateGInput(g) {
|
|
||||||
gInput.value = String(parseInt(g)).padStart(3, '0')
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateBInput(b) {
|
|
||||||
bInput.value = String(parseInt(b)).padStart(3, '0')
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(hexCode, updateHexInput)
|
|
||||||
watch(hue, updateHueInput)
|
|
||||||
watch(saturation, updateSaturationInput)
|
|
||||||
watch(lightness, updateLightnessInput)
|
|
||||||
watch(rgb, ([r, g, b]) => {
|
|
||||||
updateRInput(r)
|
|
||||||
updateGInput(g)
|
|
||||||
updateBInput(b)
|
|
||||||
}, { deep: true })
|
|
||||||
|
|
||||||
const colorFieldText = ref(null)
|
const colorFieldText = ref(null)
|
||||||
|
|
||||||
@@ -275,10 +145,10 @@ function shake() {
|
|||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="w-full flex p-4 font-heading"
|
class="w-full flex p-4 font-heading"
|
||||||
:style="{backgroundColor: `hsl(${hue},${saturation}%,${lightness}%)`}">
|
:style="{backgroundColor: `hsl(${color.hue()},${color.saturationl()}%,${color.lightness()}%)`}">
|
||||||
<div
|
<div
|
||||||
ref="colorFieldText" class="w-full flex opacity-50"
|
ref="colorFieldText" class="w-full flex opacity-50"
|
||||||
:class="foregroundBlack(...rgb) ? 'text-black selection:bg-black selection:text-white' : 'selection:bg-white selection:text-black'"
|
:class="color.lighten(0.37).isLight() ? 'text-black selection:bg-black selection:text-white' : 'selection:bg-white selection:text-black'"
|
||||||
style="transition: color 0.2s ease-in-out">
|
style="transition: color 0.2s ease-in-out">
|
||||||
<div>
|
<div>
|
||||||
<form @submit.prevent="onSubmitHueInput">
|
<form @submit.prevent="onSubmitHueInput">
|
||||||
@@ -288,7 +158,7 @@ function shake() {
|
|||||||
onfocus="this.select()"
|
onfocus="this.select()"
|
||||||
type="number" maxlength="3"
|
type="number" maxlength="3"
|
||||||
class="w-8 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
class="w-8 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
||||||
@blur="updateHueInput(hue)">
|
@blur="updateInputs">
|
||||||
</form>
|
</form>
|
||||||
<form @submit.prevent="onSubmitSaturationInput">
|
<form @submit.prevent="onSubmitSaturationInput">
|
||||||
<label for="saturationInput">S: </label><input
|
<label for="saturationInput">S: </label><input
|
||||||
@@ -297,16 +167,16 @@ function shake() {
|
|||||||
onfocus="this.select()"
|
onfocus="this.select()"
|
||||||
type="number" maxlength="3"
|
type="number" maxlength="3"
|
||||||
class="w-8 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
class="w-8 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
||||||
@blur="updateSaturationInput(saturation)">
|
@blur="updateInputs">
|
||||||
</form>
|
</form>
|
||||||
<form @submit.prevent="onSubmitLightnessInput">
|
<form @submit.prevent="onSubmitValueInput">
|
||||||
<label for="lightnessInput">L: </label><input
|
<label for="valueInput">V: </label><input
|
||||||
id="lightnessInput"
|
id="valueInput"
|
||||||
v-model="lightnessInput"
|
v-model="valueInput"
|
||||||
onfocus="this.select()"
|
onfocus="this.select()"
|
||||||
type="number" maxlength="3"
|
type="number" maxlength="3"
|
||||||
class="w-8 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
class="w-8 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
||||||
@blur="updateLightnessInput(lightness)">
|
@blur="updateInputs">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="mx-auto">
|
<div class="mx-auto">
|
||||||
@@ -316,7 +186,7 @@ function shake() {
|
|||||||
v-model="hexInput" maxlength="6"
|
v-model="hexInput" maxlength="6"
|
||||||
onfocus="this.select()"
|
onfocus="this.select()"
|
||||||
class="w-16 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
class="w-16 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
||||||
@blur="updateHexInput(hexCode)">
|
@blur="updateInputs">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -327,7 +197,7 @@ function shake() {
|
|||||||
onfocus="this.select()"
|
onfocus="this.select()"
|
||||||
type="number" maxlength="3"
|
type="number" maxlength="3"
|
||||||
class="w-8 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
class="w-8 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
||||||
@blur="updateRInput(rgb[0])">
|
@blur="updateInputs">
|
||||||
</form>
|
</form>
|
||||||
<form @submit.prevent="onSubmitRGBInput">
|
<form @submit.prevent="onSubmitRGBInput">
|
||||||
<label for="gInput">G: </label><input
|
<label for="gInput">G: </label><input
|
||||||
@@ -336,7 +206,7 @@ function shake() {
|
|||||||
onfocus="this.select()"
|
onfocus="this.select()"
|
||||||
type="number" maxlength="3"
|
type="number" maxlength="3"
|
||||||
class="w-8 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
class="w-8 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
||||||
@blur="updateGInput(rgb[1])">
|
@blur="updateInputs">
|
||||||
</form>
|
</form>
|
||||||
<form @submit.prevent="onSubmitRGBInput">
|
<form @submit.prevent="onSubmitRGBInput">
|
||||||
<label for="bInput">B: </label><input
|
<label for="bInput">B: </label><input
|
||||||
@@ -345,17 +215,17 @@ function shake() {
|
|||||||
onfocus="this.select()"
|
onfocus="this.select()"
|
||||||
type="number" maxlength="3"
|
type="number" maxlength="3"
|
||||||
class="w-8 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
class="w-8 bg-transparent focus-visible:ring-0 focus-visible:outline-none"
|
||||||
@blur="updateBInput(rgb[2])">
|
@blur="updateInputs">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
:style="{background: `linear-gradient(180deg, hsla(${hue}, ${saturation}%, ${lightness}%, 30%) 0%, transparent 30%`}">
|
:style="{background: `linear-gradient(180deg, hsla(${color.hue()}, ${color.saturationl()}%, ${color.lightness()}%, 30%) 0%, transparent 30%`}">
|
||||||
<div class="px-6 py-4 flex">
|
<div class="px-6 py-4 flex">
|
||||||
<p class="font-heading text-muted-foreground w-24">HUE</p>
|
<p class="font-heading text-muted-foreground w-24">HUE</p>
|
||||||
<SliderRoot
|
<SliderRoot
|
||||||
v-model="hueSliderModel" :max="360"
|
v-model="hueSliderModel" :max="359"
|
||||||
class="relative flex w-full touch-none select-none items-center">
|
class="relative flex w-full touch-none select-none items-center">
|
||||||
<SliderTrack
|
<SliderTrack
|
||||||
class="relative h-2.5 w-full grow overflow-hidden rounded-full border-2 border-zinc-900"
|
class="relative h-2.5 w-full grow overflow-hidden rounded-full border-2 border-zinc-900"
|
||||||
@@ -371,19 +241,19 @@ function shake() {
|
|||||||
class="relative flex w-full touch-none select-none items-center">
|
class="relative flex w-full touch-none select-none items-center">
|
||||||
<SliderTrack
|
<SliderTrack
|
||||||
class="relative h-2.5 w-full grow overflow-hidden rounded-full border-2 border-zinc-900"
|
class="relative h-2.5 w-full grow overflow-hidden rounded-full border-2 border-zinc-900"
|
||||||
:style="{background: `linear-gradient(90deg, hsl(${hue}, 0%, ${lightness}%) 0%, hsl(${hue}, 100%, ${lightness}%) 100%)`}" />
|
:style="{background: `linear-gradient(90deg, hsl(0, 0%, ${sliderColor.lightness()}%) 0%, hsl(${sliderColor.hue()}, 100%, ${sliderColor.lightness()}%) 100%)`}" />
|
||||||
<SliderThumb
|
<SliderThumb
|
||||||
class="block h-5 w-5 rounded-full border hover:bg-zinc-900 border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 cursor-pointer focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
|
class="block h-5 w-5 rounded-full border hover:bg-zinc-900 border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 cursor-pointer focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
|
||||||
</SliderRoot>
|
</SliderRoot>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-6 py-4 flex">
|
<div class="px-6 py-4 flex">
|
||||||
<p class="font-heading text-muted-foreground w-24">LIT</p>
|
<p class="font-heading text-muted-foreground w-24">VAL</p>
|
||||||
<SliderRoot
|
<SliderRoot
|
||||||
v-model="lightnessSliderModel" :max="100"
|
v-model="valueSliderModel" :max="100"
|
||||||
class="relative flex w-full touch-none select-none items-center">
|
class="relative flex w-full touch-none select-none items-center">
|
||||||
<SliderTrack
|
<SliderTrack
|
||||||
class="relative h-2.5 w-full grow overflow-hidden rounded-full border-2 border-zinc-900"
|
class="relative h-2.5 w-full grow overflow-hidden rounded-full border-2 border-zinc-900"
|
||||||
:style="{background: `linear-gradient(90deg, hsl(${hue}, ${saturation}%, 0%) 0%, hsl(${hue}, ${saturation}%, 50%) 50%, hsl(${hue}, ${saturation}%, 100%) 100%)`}" />
|
:style="{background: `linear-gradient(90deg, black, hsl(${sliderColor.hue()}, ${color.saturationl()}%, 50%) 100%`}" />
|
||||||
<SliderThumb
|
<SliderThumb
|
||||||
class="block h-5 w-5 rounded-full border hover:bg-zinc-900 border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 cursor-pointer focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
|
class="block h-5 w-5 rounded-full border hover:bg-zinc-900 border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 cursor-pointer focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
|
||||||
</SliderRoot>
|
</SliderRoot>
|
||||||
@@ -10,13 +10,13 @@
|
|||||||
<div class="h-6" />
|
<div class="h-6" />
|
||||||
<!-- TODO: Instead of 3 color pickers, add a context select above -->
|
<!-- TODO: Instead of 3 color pickers, add a context select above -->
|
||||||
<ConfigSection :title="$t('config_options.light_designer.primary_color')" :icon-component="Paintbrush">
|
<ConfigSection :title="$t('config_options.light_designer.primary_color')" :icon-component="Paintbrush">
|
||||||
<HSLInput />
|
<HSVInput />
|
||||||
</ConfigSection>
|
</ConfigSection>
|
||||||
<ConfigSection :title="$t('config_options.light_designer.secondary_color')" :icon-component="Brush">
|
<ConfigSection :title="$t('config_options.light_designer.secondary_color')" :icon-component="Brush">
|
||||||
<HSLInput />
|
<HSVInput />
|
||||||
</ConfigSection>
|
</ConfigSection>
|
||||||
<ConfigSection :title="$t('config_options.light_designer.pointer_color')" :icon-component="Pencil">
|
<ConfigSection :title="$t('config_options.light_designer.pointer_color')" :icon-component="Pencil">
|
||||||
<HSLInput />
|
<HSVInput />
|
||||||
</ConfigSection>
|
</ConfigSection>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
</div>
|
</div>
|
||||||
@@ -26,5 +26,5 @@
|
|||||||
import { ScrollArea } from '@/components/ui/scroll-area/index.js'
|
import { ScrollArea } from '@/components/ui/scroll-area/index.js'
|
||||||
import { Lightbulb, Brush, Pencil, Paintbrush } from 'lucide-vue-next'
|
import { Lightbulb, Brush, Pencil, Paintbrush } from 'lucide-vue-next'
|
||||||
import ConfigSection from '@/components/config/ConfigSection.vue'
|
import ConfigSection from '@/components/config/ConfigSection.vue'
|
||||||
import HSLInput from '@/components/HSLInput.vue'
|
import HSVInput from '@/components/HSVInput.vue'
|
||||||
</script>
|
</script>
|
||||||
Reference in New Issue
Block a user