mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
3.6 KiB
140 lines
3.6 KiB
<script lang="ts" setup> |
|
import tinycolor from 'tinycolor2' |
|
import { computed, enumColor, ref, watch } from '#imports' |
|
|
|
interface Props { |
|
modelValue?: string | any |
|
colors?: string[] |
|
rowSize?: number |
|
advanced?: boolean |
|
pickButton?: boolean |
|
colorBoxBorder?: boolean |
|
isNewDesign?: boolean |
|
} |
|
|
|
const props = withDefaults(defineProps<Props>(), { |
|
modelValue: () => enumColor.light[0], |
|
colors: () => enumColor.light.concat(enumColor.dark), |
|
rowSize: 10, |
|
advanced: true, |
|
pickButton: false, |
|
colorBoxBorder: false, |
|
isNewDesign: false, |
|
}) |
|
|
|
const emit = defineEmits(['input', 'closeModal']) |
|
|
|
const vModel = computed({ |
|
get: () => props.modelValue, |
|
set: (val) => { |
|
emit('input', val || null) |
|
}, |
|
}) |
|
|
|
const picked = ref<string>(props.modelValue || enumColor.light[0]) |
|
|
|
const selectColor = (color: string, closeModal = false) => { |
|
picked.value = color |
|
if (props.pickButton) vModel.value = color |
|
if (closeModal) { |
|
emit('closeModal') |
|
} |
|
} |
|
|
|
const isPickerOn = ref(false) |
|
|
|
const compare = (colorA: string, colorB: string) => |
|
colorA.toLowerCase() === colorB.toLowerCase() || colorA.toLowerCase() === tinycolor(colorB).toHex8String().toLowerCase() |
|
|
|
watch(picked, (n, _o) => { |
|
vModel.value = n |
|
}) |
|
</script> |
|
|
|
<template> |
|
<div class="color-picker"> |
|
<div |
|
v-for="colId in Math.ceil(props.colors.length / props.rowSize)" |
|
:key="colId" |
|
class="color-picker-row" |
|
:class="{ |
|
'mt-2': colId > 1, |
|
}" |
|
> |
|
<div |
|
v-for="(color, i) of colors.slice((colId - 1) * rowSize, colId * rowSize)" |
|
:key="`color-${colId}-${i}`" |
|
class="p-1 rounded-md flex h-8" |
|
:class="{ |
|
'hover:bg-gray-200': isNewDesign, |
|
}" |
|
> |
|
<button |
|
class="color-selector" |
|
:class="{ 'selected': compare(picked, color), 'new-design': isNewDesign }" |
|
:style="{ |
|
backgroundColor: `${color}`, |
|
border: colorBoxBorder ? `1px solid ${tinycolor(color).darken(30).toString()}` : undefined, |
|
}" |
|
@click="selectColor(color, true)" |
|
> |
|
{{ compare(picked, color) && !isNewDesign ? '✓' : '' }} |
|
</button> |
|
</div> |
|
<div |
|
class="p-1 rounded-md h-8" |
|
:class="{ |
|
'hover:bg-gray-200': isNewDesign, |
|
}" |
|
> |
|
<button class="nc-more-colors-trigger h-6 w-6 border-1 border-gray-400 rounded" @click="isPickerOn = !isPickerOn"> |
|
<GeneralTooltip> |
|
<template #title>{{ $t('activity.moreColors') }}</template> |
|
<div class="flex items-center justify-center"> |
|
<GeneralIcon :icon="isPickerOn ? 'minus' : 'plus'" class="w-4 h-4" /> |
|
</div> |
|
</GeneralTooltip> |
|
</button> |
|
</div> |
|
</div> |
|
|
|
<a-card |
|
v-if="props.advanced" |
|
class="w-full mt-2" |
|
:body-style="{ paddingLeft: '4px !important', paddingRight: '4px !important' }" |
|
:bordered="false" |
|
> |
|
<div v-if="isPickerOn" class="flex justify-center"> |
|
<LazyGeneralChromeWrapper v-model="picked" class="!w-full !shadow-none" /> |
|
</div> |
|
</a-card> |
|
</div> |
|
</template> |
|
|
|
<style lansg="scss" scoped> |
|
.color-picker { |
|
@apply flex flex-col items-center justify-center bg-white p-2.5; |
|
} |
|
.color-picker-row { |
|
@apply flex flex-row space-x-1; |
|
} |
|
.color-selector { |
|
@apply h-6 w-6 rounded; |
|
-webkit-text-stroke-width: 1px; |
|
-webkit-text-stroke-color: white; |
|
} |
|
.color-selector:hover { |
|
filter: brightness(90%); |
|
-webkit-filter: brightness(90%); |
|
} |
|
.color-selector:focus, |
|
.color-selector.selected, |
|
.nc-more-colors-trigger:focus { |
|
outline: none; |
|
box-shadow: 0px 0px 0px 2px #fff, 0px 0px 0px 4px #3069fe; |
|
} |
|
|
|
:deep(.vc-chrome-toggle-icon) { |
|
@apply !ml-3; |
|
} |
|
</style>
|
|
|