Browse Source

feat: project color

Signed-off-by: mertmit <mertmit99@gmail.com>
pull/3368/head
mertmit 2 years ago
parent
commit
888145905e
  1. 1
      packages/nc-gui-v2/components.d.ts
  2. 49
      packages/nc-gui-v2/pages/index/index/[id].vue
  3. 8
      packages/nc-gui-v2/pages/index/index/index.vue
  4. 1
      packages/nocodb/src/lib/meta/api/projectApis.ts
  5. 2
      packages/nocodb/src/lib/meta/helpers/extractProps.ts

1
packages/nc-gui-v2/components.d.ts vendored

@ -186,6 +186,7 @@ declare module '@vue/runtime-core' {
MdiMinusCircleOutline: typeof import('~icons/mdi/minus-circle-outline')['default']
MdiMoonFull: typeof import('~icons/mdi/moon-full')['default']
MdiNotebookCheckOutline: typeof import('~icons/mdi/notebook-check-outline')['default']
MdiNull: typeof import('~icons/mdi/null')['default']
MdiNumeric: typeof import('~icons/mdi/numeric')['default']
MdiOpenInNew: typeof import('~icons/mdi/open-in-new')['default']
MdiPencil: typeof import('~icons/mdi/pencil')['default']

49
packages/nc-gui-v2/pages/index/index/[id].vue

@ -1,6 +1,8 @@
<script lang="ts" setup>
import type { Form } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import type { ProjectType } from 'nocodb-sdk'
import tinycolor from 'tinycolor2'
import {
extractSdkResponseErrorMsg,
navigateTo,
@ -34,11 +36,13 @@ const nameValidationRules = [
const form = ref<typeof Form>()
const formState = reactive({
const formState = reactive<Partial<ProjectType>>({
title: '',
color: '#FFFFFF00',
})
const renameProject = async () => {
formState.color = formState.color === '#FFFFFF00' ? '' : formState.color
try {
await updateProject(formState)
@ -51,6 +55,7 @@ const renameProject = async () => {
// select and focus title field on load
onMounted(async () => {
formState.title = project.value.title as string
formState.color = project.value.color && tinycolor(project.value.color).isValid() ? project.value.color : '#FFFFFF00'
await nextTick(() => {
// todo: replace setTimeout and follow better approach
setTimeout(() => {
@ -93,6 +98,27 @@ onMounted(async () => {
<a-input v-model:value="formState.title" name="title" class="nc-metadb-project-name" />
</a-form-item>
<div class="flex items-center">
<span>Project color: </span>
<a-menu class="!border-0 !m-0 !p-0">
<a-sub-menu key="project-color">
<template #title>
<button type="button" class="color-selector" :style="{ 'background-color': formState.color }">
<MdiNull v-if="formState.color === '#FFFFFF00'" />
</button>
</template>
<template #expandIcon></template>
<GeneralColorPicker v-model="formState.color" name="color" class="nc-metadb-project-color" />
</a-sub-menu>
</a-menu>
<MdiClose
v-show="formState.color !== '#FFFFFF00'"
class="cursor-pointer"
:style="{ color: 'red' }"
@click="formState.color = '#FFFFFF00'"
/>
</div>
<div class="text-center">
<button type="submit" class="submit">
<span class="flex items-center gap-2">
@ -105,7 +131,7 @@ onMounted(async () => {
</div>
</template>
<style lang="scss">
<style lang="scss" scoped>
.update-project {
.ant-input-affix-wrapper,
.ant-input {
@ -130,4 +156,23 @@ onMounted(async () => {
}
}
}
:deep(.ant-menu-submenu-title) {
@apply !p-0 !mx-2;
}
.color-selector {
position: relative;
height: 32px;
width: 32px;
border-radius: 5px;
-webkit-text-stroke-width: 1px;
-webkit-text-stroke-color: white;
@apply flex text-gray-500 border-4 items-center justify-center;
}
.color-selector:hover {
filter: brightness(90%);
-webkit-filter: brightness(90%);
}
</style>

8
packages/nc-gui-v2/pages/index/index/index.vue

@ -158,9 +158,13 @@ await loadProjects()
>
<!-- Title -->
<a-table-column key="title" :title="$t('general.title')" data-index="title">
<template #default="{ text }">
<template #default="{ text, record }">
<div
class="capitalize color-transition group-hover:text-primary !w-[400px] overflow-hidden overflow-ellipsis whitespace-nowrap"
class="capitalize color-transition group-hover:text-primary !w-[400px] h-full overflow-hidden overflow-ellipsis whitespace-nowrap pl-2"
:class="{ 'border-l-4': record.color }"
:style="{
'border-color': record.color,
}"
>
{{ text }}
</div>

1
packages/nocodb/src/lib/meta/api/projectApis.ts

@ -52,6 +52,7 @@ export async function projectUpdate(
const data: Partial<Project> = extractPropsAndSanitize(req?.body, [
'title',
'meta',
'color',
]);
if (data?.title && project.title !== data.title && await Project.getByTitle(data.title)) {

2
packages/nocodb/src/lib/meta/helpers/extractProps.ts

@ -11,7 +11,7 @@ export function extractProps<T>(body: T, props: string[]): Partial<T> {
export function extractPropsAndSanitize<T>(body: T, props: string[]): Partial<T> {
// todo: throw error if no props found
return props.reduce((o, key) => {
if (key in body) o[key] = DOMPurify.sanitize(body[key]);
if (key in body) o[key] = body[key] === '' ? null : DOMPurify.sanitize(body[key]);
return o;
}, {});
}

Loading…
Cancel
Save