Browse Source

Merge pull request #3096 from nocodb/refactor/gui-v2-ui-updates

refactor(gui-v2): ui updates
pull/3108/head
navi 2 years ago committed by GitHub
parent
commit
d16129b49a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      packages/nc-gui-v2/assets/style-v2.scss
  2. 2
      packages/nc-gui-v2/components.d.ts
  3. 19
      packages/nc-gui-v2/components/dashboard/TreeView.vue
  4. 2
      packages/nc-gui-v2/components/smartsheet-header/Cell.vue
  5. 2
      packages/nc-gui-v2/components/smartsheet-header/VirtualCell.vue
  6. 38
      packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilter.vue
  7. 6
      packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilterMenu.vue
  8. 4
      packages/nc-gui-v2/components/smartsheet-toolbar/FieldListAutoCompleteDropdown.vue
  9. 11
      packages/nc-gui-v2/components/smartsheet-toolbar/FieldsMenu.vue
  10. 4
      packages/nc-gui-v2/components/smartsheet-toolbar/MoreActions.vue
  11. 4
      packages/nc-gui-v2/components/smartsheet-toolbar/ShareView.vue
  12. 18
      packages/nc-gui-v2/components/smartsheet-toolbar/SortListMenu.vue
  13. 8
      packages/nc-gui-v2/components/smartsheet/Grid.vue
  14. 4
      packages/nc-gui-v2/components/smartsheet/Toolbar.vue
  15. 24
      packages/nc-gui-v2/components/smartsheet/sidebar/MenuBottom.vue
  16. 8
      packages/nc-gui-v2/components/smartsheet/sidebar/MenuTop.vue
  17. 3
      packages/nc-gui-v2/nuxt.config.ts
  18. 36
      packages/nc-gui-v2/pages/nc/[projectId]/index/index.vue
  19. 2
      packages/nc-gui-v2/utils/colorsUtils.ts

2
packages/nc-gui-v2/assets/style-v2.scss

@ -102,7 +102,7 @@ html {
// for highlighting toolbar menu item // for highlighting toolbar menu item
.nc-active-btn > .ant-btn{ .nc-active-btn > .ant-btn{
@apply bg-primary/20; @apply bg-primary/20 hover:(bg-primary/20);
} }
.ant-modal-wrap { .ant-modal-wrap {

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

@ -91,6 +91,7 @@ declare module '@vue/runtime-core' {
MdiContentSave: typeof import('~icons/mdi/content-save')['default'] MdiContentSave: typeof import('~icons/mdi/content-save')['default']
MdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default'] MdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default']
MdiDiscord: typeof import('~icons/mdi/discord')['default'] MdiDiscord: typeof import('~icons/mdi/discord')['default']
MdiDotsHorizontal: typeof import('~icons/mdi/dots-horizontal')['default']
MdiDotsVertical: typeof import('~icons/mdi/dots-vertical')['default'] MdiDotsVertical: typeof import('~icons/mdi/dots-vertical')['default']
MdiDownload: typeof import('~icons/mdi/download')['default'] MdiDownload: typeof import('~icons/mdi/download')['default']
MdiDrag: typeof import('~icons/mdi/drag')['default'] MdiDrag: typeof import('~icons/mdi/drag')['default']
@ -120,6 +121,7 @@ declare module '@vue/runtime-core' {
MdiPlus: typeof import('~icons/mdi/plus')['default'] MdiPlus: typeof import('~icons/mdi/plus')['default']
MdiPlusOutline: typeof import('~icons/mdi/plus-outline')['default'] MdiPlusOutline: typeof import('~icons/mdi/plus-outline')['default']
MdiReload: typeof import('~icons/mdi/reload')['default'] MdiReload: typeof import('~icons/mdi/reload')['default']
MdiSearch: typeof import('~icons/mdi/search')['default']
MdiShieldLockOutline: typeof import('~icons/mdi/shield-lock-outline')['default'] MdiShieldLockOutline: typeof import('~icons/mdi/shield-lock-outline')['default']
MdiSlack: typeof import('~icons/mdi/slack')['default'] MdiSlack: typeof import('~icons/mdi/slack')['default']
MdiStar: typeof import('~icons/mdi/star')['default'] MdiStar: typeof import('~icons/mdi/star')['default']

19
packages/nc-gui-v2/components/dashboard/TreeView.vue

@ -4,7 +4,6 @@ import Sortable from 'sortablejs'
import { useNuxtApp, useRoute } from '#app' import { useNuxtApp, useRoute } from '#app'
import { computed, useProject, useTable, useTabs, watchEffect } from '#imports' import { computed, useProject, useTable, useTabs, watchEffect } from '#imports'
import { TabType } from '~/composables' import { TabType } from '~/composables'
import MdiTable from '~icons/mdi/table'
import MdiView from '~icons/mdi/eye-circle-outline' import MdiView from '~icons/mdi/eye-circle-outline'
import MdiTableLarge from '~icons/mdi/table-large' import MdiTableLarge from '~icons/mdi/table-large'
import MdiMenuDown from '~icons/mdi/chevron-down' import MdiMenuDown from '~icons/mdi/chevron-down'
@ -153,9 +152,7 @@ const activeTable = computed(() => {
@click="showTableList = !showTableList" @click="showTableList = !showTableList"
@contextmenu="setMenuContext('main')" @contextmenu="setMenuContext('main')"
> >
<MdiTable class="mr-1 text-gray-500" /> <span class="flex-grow text-bold nc-project-tree text-gray-500">
<span class="flex-grow text-bold nc-project-tree">
{{ $t('objects.tables') }} {{ $t('objects.tables') }}
<template v-if="tables?.length"> ({{ tables.length }}) </template> <template v-if="tables?.length"> ({{ tables.length }}) </template>
@ -196,14 +193,10 @@ const activeTable = computed(() => {
@click.stop.prevent @click.stop.prevent
/> />
<component <component :is="icon(table)" class="nc-view-icon group-hover:hidden text-xs group-hover:text-gray-500" />
:is="icon(table)"
:class="route.params.title && route.params.title.includes(table.title) ? 'text-pink-500' : 'text-gray-500'"
class="nc-view-icon group-hover:hidden text-xs"
/>
</div> </div>
<div class="nc-tbl-title text-xs flex-1">{{ table.title }}</div> <div class="nc-tbl-title flex-1">{{ table.title }}</div>
<a-dropdown :trigger="['click']" @click.stop> <a-dropdown :trigger="['click']" @click.stop>
<MdiMenuIcon class="transition-opacity opacity-0 group-hover:opacity-100" /> <MdiMenuIcon class="transition-opacity opacity-0 group-hover:opacity-100" />
@ -298,17 +291,17 @@ const activeTable = computed(() => {
} }
.nc-tree-item svg { .nc-tree-item svg {
@apply text-gray-500; @apply text-primary/60;
} }
.nc-tree-item.active { .nc-tree-item.active {
@apply !text-primary after:(!opacity-5); @apply !text-primary font-weight-medium after:(!opacity-20);
svg { svg {
@apply !text-primary; @apply !text-primary;
} }
} }
.nc-tree-item:hover { .nc-tree-item:hover {
@apply !text-grey after:(!opacity-2); @apply !text-grey after:(!opacity-5);
} }
</style> </style>

2
packages/nc-gui-v2/components/smartsheet-header/Cell.vue

@ -21,7 +21,7 @@ useProvideColumnCreateStore(meta as Ref<TableType>, column)
</script> </script>
<template> <template>
<div class="flex align-center w-full"> <div class="flex align-center w-full text-xs font-weight-regular">
<SmartsheetHeaderCellIcon v-if="column" /> <SmartsheetHeaderCellIcon v-if="column" />
<span v-if="column" class="name" style="white-space: nowrap" :title="column.title">{{ column.title }}</span> <span v-if="column" class="name" style="white-space: nowrap" :title="column.title">{{ column.title }}</span>
<span v-if="(column.rqd && !column.cdf) || required" class="text-red-500">&nbsp;*</span> <span v-if="(column.rqd && !column.cdf) || required" class="text-red-500">&nbsp;*</span>

2
packages/nc-gui-v2/components/smartsheet-header/VirtualCell.vue

@ -80,7 +80,7 @@ useProvideColumnCreateStore(meta as Ref<TableType>, column)
</script> </script>
<template> <template>
<div class="d-flex align-center w-full"> <div class="d-flex align-center w-full text-xs font-weight-regular">
<!-- <v-tooltip bottom> <!-- <v-tooltip bottom>
<template #activator="{ on }"> <template #activator="{ on }">
todo: bring tooltip todo: bring tooltip

38
packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilter.vue

@ -112,7 +112,7 @@ defineExpose({
<template> <template>
<div <div
class="pa-2 menu-filter-dropdown bg-gray-50" class="p-6 menu-filter-dropdown bg-gray-50"
:class="{ 'shadow-xl min-w-[430px] max-w-[630px] max-h-[max(80vh,500px)] overflow-auto': !nested, 'border-1 w-full': nested }" :class="{ 'shadow-xl min-w-[430px] max-w-[630px] max-h-[max(80vh,500px)] overflow-auto': !nested, 'border-1 w-full': nested }"
> >
<div v-if="filters && filters.length" class="nc-filter-grid mb-2" @click.stop> <div v-if="filters && filters.length" class="nc-filter-grid mb-2" @click.stop>
@ -132,13 +132,12 @@ defineExpose({
<a-select <a-select
v-model:value="filter.logical_op" v-model:value="filter.logical_op"
:dropdown-match-select-width="false" :dropdown-match-select-width="false"
size="small" class="shrink grow-0"
class="flex-shrink-1 flex-grow-0 elevation-0 caption !text-xs"
placeholder="Group op" placeholder="Group op"
@click.stop @click.stop
@change="saveOrUpdate(filter, i)" @change="saveOrUpdate(filter, i)"
> >
<a-select-option v-for="op in logicalOps" :key="op.value" :value="op.value" class="!text-xs"> <a-select-option v-for="op in logicalOps" :key="op.value" :value="op.value" class="">
{{ op.text }} {{ op.text }}
</a-select-option> </a-select-option>
</a-select> </a-select>
@ -173,20 +172,19 @@ defineExpose({
/> />
<span v-else /> <span v-else />
<span v-if="!i" class="text-xs d-flex align-center">{{ $t('labels.where') }}</span> <span v-if="!i" class="flex items-center">{{ $t('labels.where') }}</span>
<a-select <a-select
v-else v-else
v-model:value="filter.logical_op" v-model:value="filter.logical_op"
:dropdown-match-select-width="false" :dropdown-match-select-width="false"
size="small" class="h-full"
class="h-full !text-xs"
hide-details hide-details
:disabled="filter.readOnly" :disabled="filter.readOnly"
@click.stop @click.stop
@change="filterUpdateCondition(filter, i)" @change="filterUpdateCondition(filter, i)"
> >
<a-select-option v-for="op in logicalOps" :key="op.value" :value="op.value" class="!text-xs"> <a-select-option v-for="op in logicalOps" :key="op.value" :value="op.value">
{{ op.text }} {{ op.text }}
</a-select-option> </a-select-option>
</a-select> </a-select>
@ -194,7 +192,7 @@ defineExpose({
<FieldListAutoCompleteDropdown <FieldListAutoCompleteDropdown
:key="`${i}_6`" :key="`${i}_6`"
v-model="filter.fk_column_id" v-model="filter.fk_column_id"
class="caption nc-filter-field-select" class="nc-filter-field-select"
:columns="columns" :columns="columns"
:disabled="filter.readOnly" :disabled="filter.readOnly"
@click.stop @click.stop
@ -204,8 +202,7 @@ defineExpose({
<a-select <a-select
v-model:value="filter.comparison_op" v-model:value="filter.comparison_op"
:dropdown-match-select-width="false" :dropdown-match-select-width="false"
size="small" class="caption nc-filter-operation-select"
class="caption nc-filter-operation-select !text-xs"
:placeholder="$t('labels.operation')" :placeholder="$t('labels.operation')"
density="compact" density="compact"
variant="solo" variant="solo"
@ -213,7 +210,7 @@ defineExpose({
hide-details hide-details
@change="filterUpdateCondition(filter, i)" @change="filterUpdateCondition(filter, i)"
> >
<a-select-option v-for="compOp in comparisonOpList" :key="compOp.value" :value="compOp.value" class="!text-xs"> <a-select-option v-for="compOp in comparisonOpList" :key="compOp.value" :value="compOp.value" class="">
{{ compOp.text }} {{ compOp.text }}
</a-select-option> </a-select-option>
</a-select> </a-select>
@ -232,7 +229,6 @@ defineExpose({
<a-checkbox <a-checkbox
v-else-if="types[filter.field] === 'boolean'" v-else-if="types[filter.field] === 'boolean'"
v-model:checked="filter.value" v-model:checked="filter.value"
size="small"
dense dense
:disabled="filter.readOnly" :disabled="filter.readOnly"
@change="saveOrUpdate(filter, i)" @change="saveOrUpdate(filter, i)"
@ -241,8 +237,7 @@ defineExpose({
v-else v-else
:key="`${i}_7`" :key="`${i}_7`"
v-model:value="filter.value" v-model:value="filter.value"
size="small" class="nc-filter-value-select"
class="caption nc-filter-value-select"
:disabled="filter.readOnly" :disabled="filter.readOnly"
@click.stop @click.stop
@input="saveOrUpdate(filter, i)" @input="saveOrUpdate(filter, i)"
@ -252,8 +247,8 @@ defineExpose({
</template> </template>
</div> </div>
<div class="flex gap-2 my-2"> <div class="flex gap-2 mb-2 mt-4">
<a-button size="small" class="elevation-0 text-capitalize text-grey" @click.stop="addFilter"> <a-button class="elevation-0 text-capitalize" @click.stop="addFilter">
<div class="flex align-center gap-1"> <div class="flex align-center gap-1">
<!-- <v-icon small color="grey"> mdi-plus </v-icon> --> <!-- <v-icon small color="grey"> mdi-plus </v-icon> -->
<MdiAddIcon /> <MdiAddIcon />
@ -261,7 +256,7 @@ defineExpose({
{{ $t('activity.addFilter') }} {{ $t('activity.addFilter') }}
</div> </div>
</a-button> </a-button>
<a-button size="small" class="elevation-0 text-capitalize text-grey" @click.stop="addFilterGroup"> <a-button class="text-capitalize !text-gray-500" @click.stop="addFilterGroup">
<div class="flex align-center gap-1"> <div class="flex align-center gap-1">
<!-- <v-icon small color="grey"> mdi-plus </v-icon> --> <!-- <v-icon small color="grey"> mdi-plus </v-icon> -->
<MdiAddIcon /> <MdiAddIcon />
@ -278,15 +273,10 @@ defineExpose({
.nc-filter-grid { .nc-filter-grid {
display: grid; display: grid;
grid-template-columns: 18px 70px auto auto auto; grid-template-columns: 18px 70px auto auto auto;
column-gap: 6px; @apply gap-[12px]
row-gap: 6px;
align-items: center; align-items: center;
} }
:deep(.ant-btn, .ant-select, .ant-input) {
@apply "!text-xs";
}
:deep(.ant-select-item-option) { :deep(.ant-select-item-option) {
@apply "!min-w-full"; @apply "!min-w-full";
} }

6
packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilterMenu.vue

@ -34,11 +34,11 @@ const applyChanges = async () => {
<template> <template>
<a-dropdown :trigger="['click']"> <a-dropdown :trigger="['click']">
<div :class="{ 'nc-badge nc-active-btn': filtersLength }"> <div :class="{ 'nc-badge nc-active-btn': filtersLength }">
<a-button v-t="['c:filter']" class="text-xs nc-filter-menu-btn nc-toolbar-btn" :disabled="isLocked" size="small"> <a-button v-t="['c:filter']" class="nc-filter-menu-btn nc-toolbar-btn txt-sm" :disabled="isLocked">
<div class="flex align-center gap-1"> <div class="flex align-center gap-1">
<MdiFilterIcon class="text-grey" /> <MdiFilterIcon class="text-grey" />
<!-- Filter --> <!-- Filter -->
<span class="text-capitalize">{{ $t('activity.filter') }}</span> <span class="text-capitalize !text-sm font-weight-regular">{{ $t('activity.filter') }}</span>
<MdiMenuDownIcon class="text-grey" /> <MdiMenuDownIcon class="text-grey" />
</div> </div>
</a-button> </a-button>
@ -46,7 +46,7 @@ const applyChanges = async () => {
<template #overlay> <template #overlay>
<SmartsheetToolbarColumnFilter <SmartsheetToolbarColumnFilter
ref="filterComp" ref="filterComp"
class="nc-table-toolbar-menu" class="nc-table-toolbar-menu shadow-lg"
:auto-save="filterAutoSave" :auto-save="filterAutoSave"
@update:filters-length="filtersLength = $event" @update:filters-length="filtersLength = $event"
> >

4
packages/nc-gui-v2/components/smartsheet-toolbar/FieldListAutoCompleteDropdown.vue

@ -81,14 +81,12 @@ const filterOption = (input: string, option: any) => {
<a-select <a-select
v-model:value="localValue" v-model:value="localValue"
:dropdown-match-select-width="false" :dropdown-match-select-width="false"
size="small"
show-search show-search
class="!text-xs"
placeholder="Select a field" placeholder="Select a field"
:filter-option="filterOption" :filter-option="filterOption"
> >
<a-select-option v-for="option in options" :key="option.value" :value="option.value"> <a-select-option v-for="option in options" :key="option.value" :value="option.value">
<div class="flex gap-2 text-xs items-center align-center h-full"> <div class="flex gap-2 items-center align-center h-full">
<component :is="option.icon" class="min-w-5 !mx-0" /> <component :is="option.icon" class="min-w-5 !mx-0" />
<span class="min-w-0"> {{ option.label }}</span> <span class="min-w-0"> {{ option.label }}</span>
</div> </div>

11
packages/nc-gui-v2/components/smartsheet-toolbar/FieldsMenu.vue

@ -67,19 +67,19 @@ const onMove = (event: { moved: { newIndex: number } }) => {
<template> <template>
<a-dropdown :trigger="['click']"> <a-dropdown :trigger="['click']">
<div :class="{ 'nc-badge nc-active-btn': isAnyFieldHidden }"> <div :class="{ 'nc-badge nc-active-btn': isAnyFieldHidden }">
<a-button v-t="['c:fields']" class="nc-fields-menu-btn nc-toolbar-btn" :disabled="isLocked" size="small"> <a-button v-t="['c:fields']" class="nc-fields-menu-btn nc-toolbar-btn" :disabled="isLocked">
<div class="flex align-center gap-1"> <div class="flex align-center gap-1">
<MdiEyeOffOutline class="text-grey" /> <MdiEyeOffOutline class="text-grey" />
<!-- Fields --> <!-- Fields -->
<span class="text-xs text-capitalize">{{ $t('objects.fields') }}</span> <span class="text-capitalize !text-sm font-weight-regular">{{ $t('objects.fields') }}</span>
<MdiMenuDown class="text-grey" /> <MdiMenuDown class="text-grey" />
</div> </div>
</a-button> </a-button>
</div> </div>
<template #overlay> <template #overlay>
<div class="pt-0 min-w-[280px] bg-gray-50 shadow nc-table-toolbar-menu max-h-[max(80vh,500px)] overflow-auto" @click.stop> <div class="p-3 min-w-[280px] bg-gray-50 shadow-lg nc-table-toolbar-menu max-h-[max(80vh,500px)] overflow-auto" @click.stop>
<div class="p-1" @click.stop> <div class="p-1" @click.stop>
<a-input v-model:value="filterQuery" size="small" :placeholder="$t('placeholder.searchFields')" /> <a-input v-model:value="filterQuery" size="small" :placeholder="$t('placeholder.searchFields')" />
</div> </div>
@ -88,7 +88,7 @@ const onMove = (event: { moved: { newIndex: number } }) => {
<template #item="{ element: field }"> <template #item="{ element: field }">
<div v-show="filteredFieldList.includes(field)" :key="field.id" class="px-2 py-1 flex" @click.stop> <div v-show="filteredFieldList.includes(field)" :key="field.id" class="px-2 py-1 flex" @click.stop>
<a-checkbox v-model:checked="field.show" class="flex-shrink" @change="saveOrUpdate(field, i)"> <a-checkbox v-model:checked="field.show" class="flex-shrink" @change="saveOrUpdate(field, i)">
<span class="text-xs">{{ field.title }}</span> <span class="">{{ field.title }}</span>
</a-checkbox> </a-checkbox>
<div class="flex-1" /> <div class="flex-1" />
<MdiDrag class="cursor-move" /> <MdiDrag class="cursor-move" />
@ -122,7 +122,4 @@ const onMove = (event: { moved: { newIndex: number } }) => {
:deep(.ant-checkbox-inner) { :deep(.ant-checkbox-inner) {
@apply transform scale-60; @apply transform scale-60;
} }
:deep(::placeholder) {
@apply !text-xs;
}
</style> </style>

4
packages/nc-gui-v2/components/smartsheet-toolbar/MoreActions.vue

@ -118,12 +118,12 @@ const exportFile = async (exportType: ExportTypes.EXCEL | ExportTypes.CSV) => {
<div class="flex gap-1 align-center"> <div class="flex gap-1 align-center">
<MdiFlashIcon class="text-grey" /> <MdiFlashIcon class="text-grey" />
<!-- More --> <!-- More -->
{{ $t('general.more') }} <span class="!text-sm font-weight-regular">{{ $t('general.more') }}</span>
<MdiMenuDownIcon class="text-grey" /> <MdiMenuDownIcon class="text-grey" />
</div> </div>
</a-button> </a-button>
<template #overlay> <template #overlay>
<div class="bg-white shadow"> <div class="bg-white shadow-lg">
<div> <div>
<div class="nc-menu-item" @click="exportFile(ExportTypes.CSV)"> <div class="nc-menu-item" @click="exportFile(ExportTypes.CSV)">
<MdiDownloadIcon /> <MdiDownloadIcon />

4
packages/nc-gui-v2/components/smartsheet-toolbar/ShareView.vue

@ -110,11 +110,11 @@ const copyLink = () => {
<template> <template>
<div> <div>
<a-button v-t="['c:view:share']" outlined class="nc-btn-share-view nc-toolbar-btn" size="small"> <a-button v-t="['c:view:share']" outlined class="nc-btn-share-view nc-toolbar-btn">
<div class="flex align-center gap-1" @click="genShareLink"> <div class="flex align-center gap-1" @click="genShareLink">
<MdiOpenInNewIcon class="text-grey" /> <MdiOpenInNewIcon class="text-grey" />
<!-- Share View --> <!-- Share View -->
{{ $t('activity.shareView') }} <span class="!text-sm font-weight-regular"> {{ $t('activity.shareView') }}</span>
</div> </div>
</a-button> </a-button>

18
packages/nc-gui-v2/components/smartsheet-toolbar/SortListMenu.vue

@ -36,17 +36,17 @@ watch(
<template> <template>
<a-dropdown offset-y class="" :trigger="['click']"> <a-dropdown offset-y class="" :trigger="['click']">
<div :class="{ 'nc-badge nc-active-btn': sorts?.length }"> <div :class="{ 'nc-badge nc-active-btn': sorts?.length }">
<a-button v-t="['c:sort']" size="small" class="nc-sort-menu-btn nc-toolbar-btn" :disabled="isLocked" <a-button v-t="['c:sort']" class="nc-sort-menu-btn nc-toolbar-btn" :disabled="isLocked"
><div class="flex align-center gap-1"> ><div class="flex align-center gap-1">
<MdiSortIcon class="text-grey" /> <MdiSortIcon class="text-grey" />
<!-- Sort --> <!-- Sort -->
<span class="text-capitalize">{{ $t('activity.sort') }}</span> <span class="text-capitalize !text-sm font-weight-regular">{{ $t('activity.sort') }}</span>
<MdiMenuDownIcon class="text-grey" /> <MdiMenuDownIcon class="text-grey" />
</div> </div>
</a-button> </a-button>
</div> </div>
<template #overlay> <template #overlay>
<div class="bg-gray-50 shadow p-2 menu-filter-dropdown min-w-[400px] max-h-[max(80vh,500px)] overflow-auto"> <div class="bg-gray-50 p-6 shadow-lg menu-filter-dropdown min-w-[400px] max-h-[max(80vh,500px)] overflow-auto">
<div v-if="sorts?.length" class="sort-grid mb-2" @click.stop> <div v-if="sorts?.length" class="sort-grid mb-2" @click.stop>
<template v-for="(sort, i) in sorts || []" :key="i"> <template v-for="(sort, i) in sorts || []" :key="i">
<!-- <v-icon :key="`${i}icon`" class="nc-sort-item-remove-btn" small @click.stop="deleteSort(sort)"> mdi-close-box </v-icon> --> <!-- <v-icon :key="`${i}icon`" class="nc-sort-item-remove-btn" small @click.stop="deleteSort(sort)"> mdi-close-box </v-icon> -->
@ -65,7 +65,6 @@ watch(
/> />
<a-select <a-select
v-model:value="sort.direction" v-model:value="sort.direction"
size="small"
class="flex-shrink-1 flex-grow-0 caption nc-sort-dir-select !text-xs" class="flex-shrink-1 flex-grow-0 caption nc-sort-dir-select !text-xs"
:label="$t('labels.operation')" :label="$t('labels.operation')"
@click.stop @click.stop
@ -76,7 +75,7 @@ watch(
:key="j" :key="j"
:value="option.value" :value="option.value"
> >
<span class="text-xs">{{ option.text }}</span> <span>{{ option.text }}</span>
</a-select-option> </a-select-option>
</a-select> </a-select>
<!-- <template #item="{ item }"> --> <!-- <template #item="{ item }"> -->
@ -85,7 +84,7 @@ watch(
<!-- </v-select> --> <!-- </v-select> -->
</template> </template>
</div> </div>
<a-button size="small" class="text-xs text-grey text-capitalize my-2" @click.stop="addSort"> <a-button class="text-capitalize mb-1 mt-4" @click.stop="addSort">
<div class="flex gap-1 align-center"> <div class="flex gap-1 align-center">
<MdiAddIcon /> <MdiAddIcon />
<!-- Add Sort Option --> <!-- Add Sort Option -->
@ -101,11 +100,6 @@ watch(
.sort-grid { .sort-grid {
display: grid; display: grid;
grid-template-columns: 22px auto 150px; grid-template-columns: 22px auto 150px;
column-gap: 6px; @apply gap-[12px];
row-gap: 6px;
}
:deep(.ant-btn, .ant-select, .ant-input, ::placeholder) {
@apply "!text-xs";
} }
</style> </style>

8
packages/nc-gui-v2/components/smartsheet/Grid.vue

@ -293,7 +293,7 @@ const expandForm = (row: Row, state: Record<string, any>) => {
<thead> <thead>
<tr> <tr>
<th> <th>
<div class="flex align-center w-[80px] px-1"> <div class="w-full h-full bg-gray-100 flex w-[80px] px-1 items-center">
<div class="group-hover:hidden" :class="{ hidden: selectedAllRecords }">#</div> <div class="group-hover:hidden" :class="{ hidden: selectedAllRecords }">#</div>
<div <div
:class="{ hidden: !selectedAllRecords, flex: selectedAllRecords }" :class="{ hidden: !selectedAllRecords, flex: selectedAllRecords }"
@ -315,9 +315,11 @@ const expandForm = (row: Row, state: Record<string, any>) => {
@xcresizing="onXcResizing(col.title, $event)" @xcresizing="onXcResizing(col.title, $event)"
@xcresized="resizingCol = null" @xcresized="resizingCol = null"
> >
<SmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" /> <div class="w-full h-full bg-gray-100 flex items-center">
<SmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" />
<SmartsheetHeaderCell v-else :column="col" /> <SmartsheetHeaderCell v-else :column="col" />
</div>
</th> </th>
<!-- v-if="!isLocked && !isVirtual && !isPublicView && _isUIAllowed('add-column')" --> <!-- v-if="!isLocked && !isVirtual && !isPublicView && _isUIAllowed('add-column')" -->
<th v-t="['c:column:add']" @click="addColumnDropdown = true"> <th v-t="['c:column:add']" @click="addColumnDropdown = true">

4
packages/nc-gui-v2/components/smartsheet/Toolbar.vue

@ -5,8 +5,8 @@ const { isGrid, isForm } = useSmartsheetStoreOrThrow()
</script> </script>
<template> <template>
<div class="nc-table-toolbar w-full py-1 flex gap-1 items-center" style="z-index: 7"> <div class="nc-table-toolbar w-full py-1 flex gap-1 items-center h-[48px] px-2" style="z-index: 7">
<SmartsheetToolbarSearchData v-if="isGrid" class="flex-shrink" /> <SmartsheetToolbarSearchData v-if="isGrid" class="shrink mr-2" />
<SmartsheetToolbarFieldsMenu v-if="isGrid" :show-system-fields="false" /> <SmartsheetToolbarFieldsMenu v-if="isGrid" :show-system-fields="false" />

24
packages/nc-gui-v2/components/smartsheet/sidebar/MenuBottom.vue

@ -33,14 +33,8 @@ function onOpenModal(type: ViewTypes, title = '') {
<template> <template>
<a-menu :selected-keys="[]" class="flex-1 flex flex-col"> <a-menu :selected-keys="[]" class="flex-1 flex flex-col">
<h3 class="px-3 py-1 text-xs font-semibold flex items-center gap-4"> <h3 class="px-3 py-1 text-xs font-semibold flex items-center gap-4 text-gray-500">
{{ $t('activity.createView') }} {{ $t('activity.createView') }}
<a-tooltip>
<template #title>
{{ $t('msg.info.onlyCreator') }}
</template>
<mdi-shield-lock-outline class="text-pink-500" />
</a-tooltip>
</h3> </h3>
<a-menu-item key="grid" class="group !flex !items-center !my-0 !h-[30px]" @click="onOpenModal(ViewTypes.GRID)"> <a-menu-item key="grid" class="group !flex !items-center !my-0 !h-[30px]" @click="onOpenModal(ViewTypes.GRID)">
@ -100,17 +94,17 @@ function onOpenModal(type: ViewTypes, title = '') {
<SmartsheetSidebarMenuApiSnippet v-model="showApiSnippet" /> <SmartsheetSidebarMenuApiSnippet v-model="showApiSnippet" />
<div class="flex-auto justify-end flex flex-col gap-4 mt-4"> <div class="flex-auto justify-end flex flex-col gap-4 mt-4">
<button <button
class="flex items-center gap-2 w-full mx-3 px-4 py-3 rounded !bg-primary text-white transform translate-x-4 hover:(translate-x-0 shadow-lg) transition duration-150 ease" class="flex items-center gap-2 w-full mx-3 px-4 py-3 rounded border transform translate-x-4 hover:(translate-x-0 shadow-lg) transition duration-150 ease !text-xs"
@click="onApiSnippet" @click="onWebhooks"
> >
<mdi-xml />Get API Snippet <mdi-hook />{{ $t('objects.webhooks') }}
</button> </button>
<button <button
class="flex items-center gap-2 w-full mx-3 px-4 py-3 rounded border transform translate-x-4 hover:(translate-x-0 shadow-lg) transition duration-150 ease" class="flex items-center gap-2 w-full mx-3 px-4 py-3 rounded border transform translate-x-4 hover:(translate-x-0 shadow-lg) transition duration-150 ease !text-xs"
@click="onWebhooks" @click="onApiSnippet"
> >
<mdi-hook />{{ $t('objects.webhooks') }} <mdi-xml />Get API Snippet
</button> </button>
</div> </div>
@ -122,7 +116,7 @@ function onOpenModal(type: ViewTypes, title = '') {
<div> <div>
<a <a
v-t="['e:hiring']" v-t="['e:hiring']"
class="px-4 py-3 !bg-primary rounded shadow text-white" class="px-4 py-3 rounded border text-xs text-current"
href="https://angel.co/company/nocodb" href="https://angel.co/company/nocodb"
target="_blank" target="_blank"
@click.stop @click.stop
@ -138,7 +132,7 @@ function onOpenModal(type: ViewTypes, title = '') {
<a <a
href="https://github.com/sponsors/nocodb" href="https://github.com/sponsors/nocodb"
target="_blank" target="_blank"
class="group flex items-center gap-2 w-full mx-3 px-4 py-2 rounded-l !bg-primary text-white transform translate-x-4 hover:(translate-x-0 shadow-lg !opacity-100) transition duration-150 ease" class="group flex items-center gap-2 w-full mx-3 px-4 py-3 rounded-l border transform translate-x-4 hover:(translate-x-0 shadow-lg !opacity-100) transition duration-150 ease !text-xs text-current"
@click.stop @click.stop
> >
<mdi-cards-heart class="text-red-500" /> <mdi-cards-heart class="text-red-500" />

8
packages/nc-gui-v2/components/smartsheet/sidebar/MenuTop.vue

@ -185,7 +185,7 @@ function onDeleted() {
</script> </script>
<template> <template>
<h3 class="pt-3 px-3 text-xs font-semibold">{{ $t('objects.views') }}</h3> <h3 class="pt-3 px-3 text-xs text-gray-500 font-semibold">{{ $t('objects.views') }}</h3>
<a-menu ref="menuRef" :class="{ dragging }" class="nc-views-menu" :selected-keys="selected"> <a-menu ref="menuRef" :class="{ dragging }" class="nc-views-menu" :selected-keys="selected">
<RenameableMenuItem <RenameableMenuItem
@ -236,11 +236,7 @@ function onDeleted() {
} }
.active { .active {
@apply bg-blue-500/15; @apply bg-primary/20 text-primary font-medium;
.nc-icon {
@apply !text-pink-500;
}
} }
} }
</style> </style>

3
packages/nc-gui-v2/nuxt.config.ts

@ -6,6 +6,7 @@ import IconsResolver from 'unplugin-icons/resolver'
import Components from 'unplugin-vue-components/vite' import Components from 'unplugin-vue-components/vite'
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers' import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'
import monacoEditorPlugin from 'vite-plugin-monaco-editor' import monacoEditorPlugin from 'vite-plugin-monaco-editor'
import { themeColors } from './utils/colorsUtils'
// https://v3.nuxtjs.org/api/configuration/nuxt.config // https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({ export default defineNuxtConfig({
@ -50,7 +51,7 @@ export default defineNuxtConfig({
css: { css: {
preprocessorOptions: { preprocessorOptions: {
less: { less: {
modifyVars: { 'primary-color': '#1348ba', 'text-color': 'rgba(61, 61, 61, 1)' }, modifyVars: { 'primary-color': themeColors.primary, 'text-color': 'rgba(61, 61, 61, 1)' },
javascriptEnabled: true, javascriptEnabled: true,
}, },
}, },

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

@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { TabItem } from '~/composables'
import { TabType } from '~/composables'
import { TabMetaInj } from '~/context' import { TabMetaInj } from '~/context'
import { useTabs, useUIPermission } from '#imports' import { useTabs, useUIPermission } from '#imports'
import MdiPlusIcon from '~icons/mdi/plus' import MdiPlusIcon from '~icons/mdi/plus'
@ -8,6 +10,8 @@ import MdiExcelIcon from '~icons/mdi/file-excel'
import MdiJSONIcon from '~icons/mdi/code-json' import MdiJSONIcon from '~icons/mdi/code-json'
import MdiAirTableIcon from '~icons/mdi/table-large' import MdiAirTableIcon from '~icons/mdi/table-large'
import MdiRequestDataSourceIcon from '~icons/mdi/open-in-new' import MdiRequestDataSourceIcon from '~icons/mdi/open-in-new'
import MdiView from '~icons/mdi/eye-circle-outline'
import MdiAccountGroup from '~icons/mdi/account-group'
const { tabs, activeTabIndex, activeTab, closeTab } = useTabs() const { tabs, activeTabIndex, activeTab, closeTab } = useTabs()
@ -25,14 +29,32 @@ function openQuickImportDialog(type: string) {
quickImportDialog.value = true quickImportDialog.value = true
importType.value = type importType.value = type
} }
const icon = (tab: TabItem) => {
switch (tab.type) {
case TabType.TABLE:
return MdiAirTableIcon
case TabType.VIEW:
return MdiView
case TabType.AUTH:
return MdiAccountGroup
}
}
</script> </script>
<template> <template>
<div class="h-full w-full nc-container pt-[9px]"> <div class="h-full w-full nc-container pt-[9px]">
<div class="h-full w-full flex flex-col"> <div class="h-full w-full flex flex-col">
<div class="px-2"> <div>
<a-tabs v-model:activeKey="activeTabIndex" type="editable-card" @edit="closeTab"> <a-tabs v-model:activeKey="activeTabIndex" type="editable-card" @edit="closeTab">
<a-tab-pane v-for="(tab, i) in tabs" :key="i" :tab="tab.title" /> <a-tab-pane v-for="(tab, i) in tabs" :key="i">
<template #tab>
<div class="flex align-center gap-2">
<component :is="icon(tab)" class="text-sm"></component>
{{ tab.title }}
</div>
</template>
</a-tab-pane>
<template #leftExtra> <template #leftExtra>
<a-menu v-model:selectedKeys="currentMenu" class="border-0" mode="horizontal"> <a-menu v-model:selectedKeys="currentMenu" class="border-0" mode="horizontal">
@ -123,7 +145,7 @@ function openQuickImportDialog(type: string) {
</a-tabs> </a-tabs>
</div> </div>
<NuxtPage class="px-4 pt-2" /> <NuxtPage />
</div> </div>
<DlgTableCreate v-if="tableCreateDialog" v-model="tableCreateDialog" /> <DlgTableCreate v-if="tableCreateDialog" v-model="tableCreateDialog" />
@ -155,4 +177,12 @@ function openQuickImportDialog(type: string) {
:deep(.ant-tabs-nav-add) { :deep(.ant-tabs-nav-add) {
@apply !hidden; @apply !hidden;
} }
:deep(.ant-tabs-tab-active) {
@apply font-weight-medium;
}
:deep(.ant-tabs-tab:not(.ant-tabs-tab-active)) {
@apply bg-gray-100;
}
</style> </style>

2
packages/nc-gui-v2/utils/colorsUtils.ts

@ -33,7 +33,7 @@ export const enumColor = {
export const themeColors = { export const themeColors = {
'background': '#FFFFFF', 'background': '#FFFFFF',
'surface': '#FFFFFF', 'surface': '#FFFFFF',
'primary': '#1348ba', 'primary': '#4351e8',
'secondary': '#03DAC6', 'secondary': '#03DAC6',
'secondary-darken-1': '#018786', 'secondary-darken-1': '#018786',
'error': '#B00020', 'error': '#B00020',

Loading…
Cancel
Save