Browse Source

feat: pick project theme from badge

Signed-off-by: mertmit <mertmit99@gmail.com>
pull/3390/head
mertmit 2 years ago
parent
commit
7b33b06fa7
  1. 8
      packages/nc-gui-v2/composables/useProject.ts
  2. 6
      packages/nc-gui-v2/pages/[projectType]/[projectId]/index.vue
  3. 93
      packages/nc-gui-v2/pages/index/index/index.vue

8
packages/nc-gui-v2/composables/useProject.ts

@ -91,16 +91,20 @@ const [setup, use] = useInjectionState((_projectId?: MaybeRef<string>) => {
if (projectType === 'base') { if (projectType === 'base') {
return return
} }
if (data.meta && typeof data.meta === 'string') {
await $api.project.update(projectId.value, data) await $api.project.update(projectId.value, data)
} else {
await $api.project.update(projectId.value, { ...data, meta: JSON.stringify(data.meta) })
}
} }
async function saveTheme(theme: Partial<ThemeConfig>) { async function saveTheme(theme: Partial<ThemeConfig>) {
await updateProject({ await updateProject({
color: theme.primaryColor, color: theme.primaryColor,
meta: JSON.stringify({ meta: {
...projectMeta.value, ...projectMeta.value,
theme, theme,
}), },
}) })
setTheme(theme) setTheme(theme)
} }

6
packages/nc-gui-v2/pages/[projectType]/[projectId]/index.vue

@ -89,19 +89,19 @@ const themeAccentColor = ref<any>(theme.value.accentColor)
// Chrome provides object so if custom picker used we only edit primary otherwise use analogous as accent // Chrome provides object so if custom picker used we only edit primary otherwise use analogous as accent
watch(themePrimaryColor, (nextColor) => { watch(themePrimaryColor, (nextColor) => {
const hexColor = nextColor.hex ? nextColor.hex : nextColor const hexColor = nextColor.hex8 ? nextColor.hex8 : nextColor
const tcolor = tinycolor(hexColor) const tcolor = tinycolor(hexColor)
if (tcolor) { if (tcolor) {
const analogous = tcolor.complement() const analogous = tcolor.complement()
saveTheme({ saveTheme({
primaryColor: hexColor, primaryColor: hexColor,
accentColor: nextColor.hex ? theme.value.accentColor : analogous.toHexString(), accentColor: nextColor.hex8 ? theme.value.accentColor : analogous.toHexString(),
}) })
} }
}) })
watch(themeAccentColor, (nextColor) => { watch(themeAccentColor, (nextColor) => {
const hexColor = nextColor.hex ? nextColor.hex : nextColor const hexColor = nextColor.hex8 ? nextColor.hex8 : nextColor
saveTheme({ saveTheme({
primaryColor: theme.value.primaryColor, primaryColor: theme.value.primaryColor,
accentColor: hexColor, accentColor: hexColor,

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

@ -1,6 +1,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { Modal, message } from 'ant-design-vue' import { Modal, message } from 'ant-design-vue'
import type { ProjectType } from 'nocodb-sdk' import type { ProjectType } from 'nocodb-sdk'
import { Chrome } from '@ckpack/vue-color'
import tinycolor from 'tinycolor2'
import { import {
computed, computed,
definePageMeta, definePageMeta,
@ -17,7 +19,7 @@ definePageMeta({
title: 'title.myProject', title: 'title.myProject',
}) })
const { $e } = useNuxtApp() const { $api, $e } = useNuxtApp()
const { api, isLoading } = useApi() const { api, isLoading } = useApi()
@ -64,6 +66,51 @@ const deleteProject = (project: ProjectType) => {
} }
await loadProjects() await loadProjects()
const themePrimaryColors = $ref(
(() => {
const colors: Record<string, any> = {}
for (const project of projects?.value || []) {
if (project?.id) {
try {
const projectMeta = typeof project.meta === 'string' ? JSON.parse(project.meta) : project.meta
colors[project.id] = tinycolor(projectMeta?.theme?.primaryColor).isValid()
? projectMeta?.theme?.primaryColor
: themeV2Colors['royal-blue'].DEFAULT
} catch (e) {
colors[project.id] = themeV2Colors['royal-blue'].DEFAULT
}
}
}
return colors
})(),
)
const oldPrimaryColors = ref({ ...themePrimaryColors })
watch(themePrimaryColors, async (nextColors) => {
for (const [projectId, nextColor] of Object.entries(nextColors)) {
if (oldPrimaryColors.value[projectId] === nextColor) continue
const hexColor = nextColor.hex8 ? nextColor.hex8 : nextColor
const tcolor = tinycolor(hexColor)
if (tcolor) {
const analogous = tcolor.complement()
const project: ProjectType = await $api.project.read(projectId)
const meta = project?.meta && typeof project.meta === 'string' ? JSON.parse(project.meta) : project.meta || {}
await $api.project.update(projectId, {
color: hexColor,
meta: JSON.stringify({
...meta,
theme: {
primaryColor: hexColor,
analogousColor: analogous.toHexString(),
},
}),
})
}
}
oldPrimaryColors.value = { ...themePrimaryColors }
})
</script> </script>
<template> <template>
@ -159,14 +206,50 @@ await loadProjects()
<!-- Title --> <!-- Title -->
<a-table-column key="title" :title="$t('general.title')" data-index="title"> <a-table-column key="title" :title="$t('general.title')" data-index="title">
<template #default="{ text, record }"> <template #default="{ text, record }">
<div class="flex items-center">
<div @click.stop>
<a-menu class="!border-0 !m-0 !p-0" trigger-sub-menu-action="click">
<template v-if="isUIAllowed('projectTheme')">
<a-sub-menu key="theme">
<template #title>
<div <div
class="capitalize color-transition group-hover:text-primary !w-[400px] h-full overflow-hidden overflow-ellipsis whitespace-nowrap pl-2 border-l-4" class="color-selector"
:style="{ :style="{
'border-color': record.color || themeV2Colors['royal-blue'].DEFAULT, 'background-color': themePrimaryColors[record.id],
'width': '8px',
'height': '100%',
}" }"
/>
</template>
<template #expandIcon></template>
<GeneralColorPicker
v-model="themePrimaryColors[record.id]"
:colors="enumColor.dark"
:row-size="5"
:advanced="false"
/>
<a-sub-menu key="pick-primary">
<template #title>
<div class="nc-project-menu-item group">
<ClarityColorPickerSolid class="group-hover:text-accent" />
Custom Color
</div>
</template>
<template #expandIcon></template>
<Chrome v-model="themePrimaryColors[record.id]" />
</a-sub-menu>
</a-sub-menu>
</template>
</a-menu>
</div>
<div
class="capitalize color-transition group-hover:text-primary !w-[400px] h-full overflow-hidden overflow-ellipsis whitespace-nowrap pl-2"
> >
{{ text }} {{ text }}
</div> </div>
</div>
</template> </template>
</a-table-column> </a-table-column>
<!-- Actions --> <!-- Actions -->
@ -219,4 +302,8 @@ await loadProjects()
:deep(.ant-table) { :deep(.ant-table) {
@apply min-h-[428px]; @apply min-h-[428px];
} }
:deep(.ant-menu-submenu-title) {
@apply !p-0 !mr-1 !my-0 !h-5;
}
</style> </style>

Loading…
Cancel
Save