Browse Source

feat(gui-v2): implement customizable theme vars

pull/3249/head
braks 2 years ago
parent
commit
df7f506893
  1. 17
      packages/nc-gui-v2/app.vue
  2. 4
      packages/nc-gui-v2/assets/css/color.css
  3. 23
      packages/nc-gui-v2/assets/css/global.css
  4. 19
      packages/nc-gui-v2/assets/style.css
  5. 10
      packages/nc-gui-v2/assets/style.scss
  6. 1
      packages/nc-gui-v2/components.d.ts
  7. 2
      packages/nc-gui-v2/components/cell/Decimal.vue
  8. 2
      packages/nc-gui-v2/components/cell/Float.vue
  9. 2
      packages/nc-gui-v2/components/cell/Integer.vue
  10. 4
      packages/nc-gui-v2/components/cell/attachment/Modal.vue
  11. 4
      packages/nc-gui-v2/components/cell/attachment/index.vue
  12. 33
      packages/nc-gui-v2/components/dashboard/TreeView.vue
  13. 2
      packages/nc-gui-v2/components/dashboard/settings/AppStore.vue
  14. 2
      packages/nc-gui-v2/components/dashboard/settings/Metadata.vue
  15. 2
      packages/nc-gui-v2/components/dashboard/settings/Misc.vue
  16. 4
      packages/nc-gui-v2/components/dashboard/settings/UIAcl.vue
  17. 4
      packages/nc-gui-v2/components/dlg/AirtableImport.vue
  18. 2
      packages/nc-gui-v2/components/general/MiniSidebar.vue
  19. 4
      packages/nc-gui-v2/components/general/ReleaseInfo.vue
  20. 2
      packages/nc-gui-v2/components/general/language/Menu.vue
  21. 14
      packages/nc-gui-v2/components/shared-view/Form.vue
  22. 6
      packages/nc-gui-v2/components/smartsheet-column/EditOrAdd.vue
  23. 2
      packages/nc-gui-v2/components/smartsheet-column/LinkedToAnotherRecordOptions.vue
  24. 4
      packages/nc-gui-v2/components/smartsheet-column/SelectOptions.vue
  25. 8
      packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilter.vue
  26. 4
      packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilterMenu.vue
  27. 2
      packages/nc-gui-v2/components/smartsheet-toolbar/FieldListAutoCompleteDropdown.vue
  28. 7
      packages/nc-gui-v2/components/smartsheet-toolbar/FieldsMenu.vue
  29. 2
      packages/nc-gui-v2/components/smartsheet-toolbar/MoreActions.vue
  30. 2
      packages/nc-gui-v2/components/smartsheet-toolbar/SearchData.vue
  31. 8
      packages/nc-gui-v2/components/smartsheet-toolbar/ShareView.vue
  32. 2
      packages/nc-gui-v2/components/smartsheet-toolbar/SharedViewList.vue
  33. 19
      packages/nc-gui-v2/components/smartsheet-toolbar/SortListMenu.vue
  34. 24
      packages/nc-gui-v2/components/smartsheet/Form.vue
  35. 17
      packages/nc-gui-v2/components/smartsheet/Grid.vue
  36. 2
      packages/nc-gui-v2/components/smartsheet/Pagination.vue
  37. 9
      packages/nc-gui-v2/components/smartsheet/expanded-form/Comments.vue
  38. 6
      packages/nc-gui-v2/components/smartsheet/expanded-form/Header.vue
  39. 4
      packages/nc-gui-v2/components/smartsheet/expanded-form/index.vue
  40. 4
      packages/nc-gui-v2/components/smartsheet/sidebar/MenuTop.vue
  41. 2
      packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/AddRow.vue
  42. 4
      packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/LockMenu.vue
  43. 2
      packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/ToggleDrawer.vue
  44. 2
      packages/nc-gui-v2/components/tabs/Auth.vue
  45. 2
      packages/nc-gui-v2/components/tabs/Smartsheet.vue
  46. 2
      packages/nc-gui-v2/components/template/Editor.vue
  47. 6
      packages/nc-gui-v2/components/virtual-cell/BelongsTo.vue
  48. 2
      packages/nc-gui-v2/components/virtual-cell/Formula.vue
  49. 6
      packages/nc-gui-v2/components/virtual-cell/HasMany.vue
  50. 6
      packages/nc-gui-v2/components/virtual-cell/ManyToMany.vue
  51. 4
      packages/nc-gui-v2/components/virtual-cell/components/ItemChip.vue
  52. 10
      packages/nc-gui-v2/components/virtual-cell/components/ListChildItems.vue
  53. 4
      packages/nc-gui-v2/components/virtual-cell/components/ListItems.vue
  54. 2
      packages/nc-gui-v2/components/webhook/Drawer.vue
  55. 4
      packages/nc-gui-v2/components/webhook/List.vue
  56. 1
      packages/nc-gui-v2/composables/index.ts
  57. 50
      packages/nc-gui-v2/composables/useTheme/index.ts
  58. 2
      packages/nc-gui-v2/lang/nl.json
  59. 2
      packages/nc-gui-v2/layouts/base.vue
  60. 16
      packages/nc-gui-v2/nuxt.config.ts
  61. 164
      packages/nc-gui-v2/package-lock.json
  62. 4
      packages/nc-gui-v2/package.json
  63. 4
      packages/nc-gui-v2/pages/[projectType]/[projectId]/index.vue
  64. 13
      packages/nc-gui-v2/pages/[projectType]/[projectId]/index/index.vue
  65. 17
      packages/nc-gui-v2/pages/forgot-password.vue
  66. 2
      packages/nc-gui-v2/pages/index/index.vue
  67. 8
      packages/nc-gui-v2/pages/index/user/index/index.vue
  68. 16
      packages/nc-gui-v2/pages/projects/index.vue
  69. 2
      packages/nc-gui-v2/pages/projects/index/list.vue
  70. 21
      packages/nc-gui-v2/pages/signin.vue
  71. 25
      packages/nc-gui-v2/pages/signup/[[token]].vue
  72. 10
      packages/nc-gui-v2/plugins/ant.ts
  73. 17
      packages/nc-gui-v2/plugins/state.ts
  74. 2
      packages/nc-gui-v2/plugins/vuetify.ts
  75. 42
      packages/nc-gui-v2/utils/colorsUtils.ts
  76. 18
      packages/nc-gui-v2/windi.config.ts

17
packages/nc-gui-v2/app.vue

@ -1,11 +1,20 @@
<script setup lang="ts">
import { computed, themeV2Colors, useRoute, useTheme } from '#imports'
const route = useRoute()
const disableBaseLayout = $computed(() => route.path.startsWith('/nc/view') || route.path.startsWith('/nc/form'))
const disableBaseLayout = computed(() => route.path.startsWith('/nc/view') || route.path.startsWith('/nc/form'))
useTheme({
primaryColor: themeV2Colors['royal-blue'].DEFAULT,
accentColor: themeV2Colors.pink['500'],
})
</script>
<template>
<NuxtLayout :name="disableBaseLayout ? false : 'base'">
<NuxtPage />
</NuxtLayout>
<a-config-provider>
<NuxtLayout :name="disableBaseLayout ? false : 'base'">
<NuxtPage />
</NuxtLayout>
</a-config-provider>
</template>

4
packages/nc-gui-v2/assets/css/color.css

@ -1,4 +0,0 @@
:root {
--primary: #00b786;
--secondary: #8ceaf6;
}

23
packages/nc-gui-v2/assets/css/global.css

@ -1,4 +1,3 @@
@import './color.css';
html {
font-size: 16px;
word-spacing: 1px;
@ -8,30 +7,10 @@ html {
-webkit-font-smoothing: antialiased;
box-sizing: border-box;
}
body {
font-family: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, Vazirmatn, sans-serif;
}
*, *:before, *:after {
box-sizing: border-box;
margin: 0;
}
.btn, .pointer {
cursor: pointer;
}
.primary {
color: var(--primary);
}
.secondary {
color: var(--secondary);
}
.btn-primary {
background-color: var(--primary);
color: #fff;
}
.btn-secondary {
background-color: var(--secondary);
color: #000;
}
/*
Apply Vazirmatn for rtl

19
packages/nc-gui-v2/assets/style.css

@ -1,19 +0,0 @@
::-webkit-scrollbar {
width: .7em;
height: .7em
}
::-webkit-scrollbar-button {
background: #77777722
}
::-webkit-scrollbar-track-piece {
background: #66666622
}
::-webkit-scrollbar-thumb {
background: #888;
border-radius: .7em;
border: .15em solid #00000000;
background-clip: padding-box;
}

10
packages/nc-gui-v2/assets/style-v2.scss → packages/nc-gui-v2/assets/style.scss

@ -1,9 +1,9 @@
@import 'ant-design-vue/dist/antd.variable.min.css';
@import 'ant-design-vue/dist/antd.min.css';
:root {
--header-height: 50px;
--toolbar-height: 48px;
--tw-text-opacity: 1;
}
.ant-layout-header {
@ -28,11 +28,7 @@ main {
}
a {
@apply prose text-primary !underline hover:!text-pink-500;
}
h1, h2, h3, h4, h5, h6, p, label, button, textarea, select {
@apply dark:(!text-white);
@apply !text-primary !underline hover:!text-accent;
}
.nc-icon {
@ -90,7 +86,7 @@ h1, h2, h3, h4, h5, h6, p, label, button, textarea, select {
// for highlighting toolbar menu item
.nc-active-btn > .ant-btn{
@apply bg-primary/20 hover:(bg-primary/20);
@apply bg-primary bg-opacity-20 hover:(bg-primary bg-opacity-20);
}
.nc-locked-overlay {

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

@ -19,6 +19,7 @@ declare module '@vue/runtime-core' {
ACol: typeof import('ant-design-vue/es')['Col']
ACollapse: typeof import('ant-design-vue/es')['Collapse']
ACollapsePanel: typeof import('ant-design-vue/es')['CollapsePanel']
AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
ADivider: typeof import('ant-design-vue/es')['Divider']
ADrawer: typeof import('ant-design-vue/es')['Drawer']

2
packages/nc-gui-v2/components/cell/Decimal.vue

@ -27,7 +27,7 @@ const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
v-if="editEnabled"
:ref="focus"
v-model="vModel"
class="outline-none pa-0 border-none w-full h-full prose-sm"
class="outline-none p-0 border-none w-full h-full prose-sm"
type="number"
step="0.1"
@blur="editEnabled = false"

2
packages/nc-gui-v2/components/cell/Float.vue

@ -27,7 +27,7 @@ const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
v-if="editEnabled"
:ref="focus"
v-model="vModel"
class="outline-none pa-0 border-none w-full h-full prose-sm"
class="outline-none p-0 border-none w-full h-full prose-sm"
type="number"
step="0.1"
@blur="editEnabled = false"

2
packages/nc-gui-v2/components/cell/Integer.vue

@ -31,7 +31,7 @@ function onKeyDown(evt: KeyboardEvent) {
v-if="editEnabled"
:ref="focus"
v-model="vModel"
class="outline-none pa-0 border-none w-full h-full prose-sm"
class="outline-none p-0 border-none w-full h-full prose-sm"
type="number"
@blur="editEnabled = false"
@keydown="onKeyDown"

4
packages/nc-gui-v2/components/cell/attachment/Modal.vue

@ -154,8 +154,8 @@ function onClick(item: Record<string, any>) {
.nc-attachment-modal {
.nc-attach-file {
@apply select-none cursor-pointer color-transition flex items-center gap-1 border-1 p-2 rounded
@apply hover:(bg-primary/10 text-primary ring);
@apply active:(ring-pink-500 bg-primary/20);
@apply hover:(bg-primary bg-opacity-10 text-primary ring);
@apply active:(ring-pink-500 bg-primary bg-opacity-20);
}
.nc-attachment-item {

4
packages/nc-gui-v2/components/cell/attachment/index.vue

@ -109,7 +109,7 @@ const { isSharedForm } = useSmartsheetStoreOrThrow()
<div
v-if="!isReadonly"
:class="{ 'mx-auto px-4': !visibleItems.length }"
class="group flex gap-1 items-center active:ring rounded border-1 p-1 hover:bg-primary/10"
class="group flex gap-1 items-center active:ring rounded border-1 p-1 hover:(bg-primary bg-opacity-10)"
@click.stop="open"
>
<MdiReload v-if="isLoading" :class="{ 'animate-infinite animate-spin': isLoading }" />
@ -160,7 +160,7 @@ const { isSharedForm } = useSmartsheetStoreOrThrow()
</div>
</div>
<div class="group flex gap-1 items-center border-1 active:ring rounded p-1 hover:bg-primary/10">
<div class="group flex gap-1 items-center border-1 active:ring rounded p-1 hover:(bg-primary bg-opacity-10)">
<MdiReload v-if="isLoading" :class="{ 'animate-infinite animate-spin': isLoading }" />
<a-tooltip v-else placement="bottom">

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

@ -220,12 +220,9 @@ function openTableCreateDialog() {
<template>
<div class="nc-treeview-container flex flex-col">
<a-dropdown :trigger="['contextmenu']">
<div
class="pt-2 pl-2 pb-2 flex-1 overflow-y-auto flex flex-column scrollbar-thin-dull"
:class="{ 'mb-[20px]': isSharedBase }"
>
<div class="py-1 px-3 flex w-full align-center gap-1 cursor-pointer" @contextmenu="setMenuContext('main')">
<span class="flex-grow text-bold uppercase nc-project-tree text-gray-500 font-weight-bold">
<div class="pt-2 pl-2 pb-2 flex-1 overflow-y-auto flex flex-col scrollbar-thin-dull" :class="{ 'mb-[20px]': isSharedBase }">
<div class="py-1 px-3 flex w-full items-center gap-1 cursor-pointer" @contextmenu="setMenuContext('main')">
<span class="flex-1 text-bold uppercase nc-project-tree text-gray-500 font-weight-bold">
{{ $t('objects.tables') }}
<template v-if="tables?.length"> ({{ tables.length }}) </template>
@ -322,7 +319,7 @@ function openTableCreateDialog() {
:data-id="table.id"
@click="addTableTab(table)"
>
<div class="flex align-center gap-2 h-full" @contextmenu="setMenuContext('table', table)">
<div class="flex items-center gap-2 h-full" @contextmenu="setMenuContext('table', table)">
<div class="flex w-auto">
<MdiDrag
v-if="isUIAllowed('treeview-drag-n-drop')"
@ -369,7 +366,7 @@ function openTableCreateDialog() {
</div>
<a-card v-else class="mt-4 mx-4 !bg-gray-50">
<div class="flex flex-col align-center">
<div class="flex flex-col items-center">
<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
<a-button type="primary" @click.stop="openTableCreateDialog">
@ -410,10 +407,10 @@ function openTableCreateDialog() {
</template>
</a-dropdown>
<a-divider class="mt-0 mb-0" />
<a-divider class="!my-0" />
<div class="items-center flex justify-center p-2">
<GeneralShareBaseButton class="!mr-0" />
<div class="flex items-center justify-center p-2">
<GeneralShareBaseButton />
</div>
</div>
</template>
@ -424,7 +421,7 @@ function openTableCreateDialog() {
}
.nc-treeview-footer-item {
@apply cursor-pointer px-4 py-2 flex align-center hover:bg-gray-200/20 text-xs text-current;
@apply cursor-pointer px-4 py-2 flex items-center hover:bg-gray-200/20 text-xs text-current;
}
:deep(.nc-filter-input input::placeholder) {
@ -460,7 +457,7 @@ function openTableCreateDialog() {
}
.sortable-chosen {
@apply !bg-primary/25 text-primary;
@apply !bg-primary bg-opacity-25 text-primary;
}
}
@ -469,20 +466,20 @@ function openTableCreateDialog() {
}
.nc-tree-item svg {
@apply text-primary/60;
@apply text-primary text-opacity-60;
}
.nc-tree-item.active {
@apply !text-primary font-weight-bold after:(!opacity-20);
@apply border-r-3 border-indigo-500;
@apply text-primary font-weight-bold after:(!opacity-20);
@apply border-r-3 border-primary;
svg {
@apply !text-primary;
@apply text-primary !text-opacity-100;
}
}
.nc-tree-item:hover {
@apply !text-grey after:(!opacity-5);
@apply text-primary after:(!opacity-5);
}
:deep(.nc-filter-input) {

2
packages/nc-gui-v2/components/dashboard/settings/AppStore.vue

@ -130,7 +130,7 @@ onMounted(async () => {
/>
<div v-else />
</div>
<div class="flex flex-col flex-grow-1 w-3/5 pl-3">
<div class="flex flex-col flex-1 w-3/5 pl-3">
<a-typography-title :level="5">{{ app.title }}</a-typography-title>
{{ app.description }}
</div>

2
packages/nc-gui-v2/components/dashboard/settings/Metadata.vue

@ -73,7 +73,7 @@ const columns = [
<template>
<div class="flex flex-row w-full">
<div class="flex flex-column w-3/5">
<div class="flex flex-col w-3/5">
<div class="flex flex-row justify-end items-center w-full mb-4">
<a-button class="self-start nc-btn-metasync-reload" @click="loadMetaDiff">
<div class="flex items-center gap-2 text-gray-600 font-light">

2
packages/nc-gui-v2/components/dashboard/settings/Misc.vue

@ -7,7 +7,7 @@ watch(includeM2M, async () => await loadTables())
<template>
<div class="flex flex-row w-full">
<div class="flex flex-column w-full">
<div class="flex flex-col w-full">
<div class="flex flex-row items-center w-full mb-4 gap-2">
<a-checkbox v-model:checked="includeM2M">Show M2M Tables</a-checkbox>
</div>

4
packages/nc-gui-v2/components/dashboard/settings/UIAcl.vue

@ -99,7 +99,7 @@ const columns = [
<template>
<div class="flex flex-row w-full">
<div class="flex flex-column w-full">
<div class="flex flex-col w-full">
<div class="flex flex-row items-center w-full mb-4 gap-2">
<a-input v-model:value="searchInput" placeholder="Search models" class="nc-acl-search">
<template #prefix>
@ -137,7 +137,7 @@ const columns = [
<template #bodyCell="{ record, column }">
<div v-if="column.name === 'table_name'">{{ record._ptn }}</div>
<div v-if="column.name === 'view_name'">
<div class="flex align-center">
<div class="flex items-center">
<component :is="viewIcons[record.type].icon" :class="`text-${viewIcons[record.type].color} mr-1`" />
{{ record.title }}
</div>

4
packages/nc-gui-v2/components/dlg/AirtableImport.vue

@ -229,7 +229,7 @@ onBeforeUnmount(() => {
</script>
<template>
<a-modal v-model:visible="dialogShow" width="max(30vw, 600px)" class="pa-2" @keydown.esc="dialogShow = false">
<a-modal v-model:visible="dialogShow" width="max(30vw, 600px)" class="p-2" @keydown.esc="dialogShow = false">
<div class="px-5">
<div class="mt-5 prose-xl font-weight-bold">QUICK IMPORT - AIRTABLE</div>
@ -245,7 +245,7 @@ onBeforeUnmount(() => {
</a>
</div>
<a-form ref="form" :model="syncSource" name="quick-import-airtable-form" layout="horizontal" class="ma-0">
<a-form ref="form" :model="syncSource" name="quick-import-airtable-form" layout="horizontal" class="m-0">
<a-form-item v-bind="validateInfos['details.apiKey']">
<a-input-password
v-model:value="syncSource.details.apiKey"

2
packages/nc-gui-v2/components/general/MiniSidebar.vue

@ -48,7 +48,7 @@ const logout = () => {
<a-menu-item key="signout" class="!rounded-b">
<div v-t="['a:navbar:user:sign-out']" class="group flex items-center py-2" @click="logout">
<MdiLogout class="dark:text-white group-hover:(!text-red-500)" />&nbsp;
<MdiLogout class="group-hover:(!text-red-500)" />&nbsp;
<span class="prose font-semibold text-gray-500 group-hover:text-black nc-user-menu-signout">
{{ $t('general.signOut') }}
</span>

4
packages/nc-gui-v2/components/general/ReleaseInfo.vue

@ -36,7 +36,7 @@ onMounted(async () => await fetchReleaseInfo())
<div v-if="releaseAlert" class="flex items-center">
<a-dropdown :trigger="['click']" placement="bottom">
<a-button class="bg-primary border-none">
<div class="flex gap-1 align-center text-white">
<div class="flex gap-1 items-center text-white">
<span class="text-sm font-weight-medium">{{ $t('activity.upgrade.available') }}</span>
<mdi-menu-down />
</div>
@ -56,7 +56,7 @@ onMounted(async () => await fetchReleaseInfo())
{{ $t('activity.upgrade.howTo') }}
</div>
</nuxt-link>
<a-divider class="ma-0" />
<a-divider class="m-0" />
<div class="nc-menu-item" @click="latestRelease = null">
<mdi-close />
<!-- Hide menu -->

2
packages/nc-gui-v2/components/general/language/Menu.vue

@ -39,7 +39,7 @@ onMounted(() => {
<a-menu-item
v-for="lang of languages"
:key="lang"
:class="lang === locale ? '!bg-primary/10 text-primary' : ''"
:class="lang === locale ? '!bg-primary bg-opacity-10 text-primary' : ''"
class="group"
:value="lang"
@click="changeLanguage(lang)"

14
packages/nc-gui-v2/components/shared-view/Form.vue

@ -34,7 +34,7 @@ function isRequired(_columnObj: Record<string, any>, required = false) {
</script>
<template>
<div class="bg-primary/100 !h-[100vh] overflow-auto w-100 flex flex-col">
<div class="bg-primary !h-[100vh] overflow-auto w-full flex flex-col">
<div>
<img src="~/assets/img/icons/512x512-trans.png" width="30" class="mx-4 mt-2" />
</div>
@ -59,21 +59,21 @@ function isRequired(_columnObj: Record<string, any>, required = false) {
<a-row class="justify-center">
<a-col :md="20">
<div>
<div class="h-full ma-0 rounded-b-0">
<div class="h-full m-0 rounded-b-0">
<div
class="nc-form-wrapper pb-10 rounded shadow-xl"
style="background: linear-gradient(180deg, #dbdbdb 0, #dbdbdb 200px, white 200px)"
>
<div class="mt-10 flex items-center justify-center flex-col">
<div class="nc-form-banner backgroundColor darken-1 flex-column justify-center d-flex">
<div class="flex items-center justify-center grow h-[100px]">
<div class="nc-form-banner backgroundColor darken-1 flex-col justify-center flex">
<div class="flex items-center justify-center flex-1 h-[100px]">
<img src="~/assets/img/icon.png" width="50" class="mx-4" />
<span class="text-4xl font-weight-bold">NocoDB</span>
</div>
</div>
</div>
<div class="mx-auto nc-form bg-white shadow-lg pa-2 mb-10 max-w-[600px] mx-auto rounded">
<div class="mx-auto nc-form bg-white shadow-lg p-2 mb-10 max-w-[600px] mx-auto rounded">
<h2 class="mt-4 text-4xl font-weight-bold text-left mx-4 mb-3 px-1">
{{ sharedFormView.heading }}
</h2>
@ -81,7 +81,7 @@ function isRequired(_columnObj: Record<string, any>, required = false) {
<div class="text-lg text-left mx-4 py-2 px-1 text-gray-500">
{{ sharedFormView.subheading }}
</div>
<div class="h-100">
<div class="h-full">
<div v-for="(field, index) in formColumns" :key="index" class="flex flex-col mt-4 px-4 space-y-2">
<div class="flex">
<SmartsheetHeaderVirtualCell
@ -159,7 +159,7 @@ function isRequired(_columnObj: Record<string, any>, required = false) {
<style scoped lang="scss">
.nc-input {
@apply w-full !bg-white rounded px-2 py-2 min-h-[40px] mt-2 mb-2 flex align-center border-solid border-1 border-primary;
@apply w-full !bg-white rounded px-2 py-2 min-h-[40px] mt-2 mb-2 flex items-center border-solid border-1 border-primary;
}
.nc-form-wrapper {

6
packages/nc-gui-v2/components/smartsheet-column/EditOrAdd.vue

@ -117,7 +117,7 @@ useEventListener(document, 'click', handleClose)
>
<a-select v-model:value="formState.uidt" show-search class="nc-column-type-input" @change="onUidtOrIdTypeChange">
<a-select-option v-for="opt of uiTypesOptions" :key="opt.name" :value="opt.name" v-bind="validateInfos.uidt">
<div class="flex gap-1 align-center">
<div class="flex gap-1 items-center">
<component :is="opt.icon" class="text-grey" />
{{ opt.name }}
</div>
@ -144,7 +144,7 @@ useEventListener(document, 'click', handleClose)
</div>
<div
v-if="!isVirtualCol(formState.uidt)"
class="text-xs cursor-pointer text-grey nc-more-options mb-1 mt-4 flex align-center gap-1 justify-end"
class="text-xs cursor-pointer text-grey nc-more-options mb-1 mt-4 flex items-center gap-1 justify-end"
@click="advancedOptions = !advancedOptions"
>
{{ advancedOptions ? $t('general.hideAll') : $t('general.showMore') }}
@ -197,7 +197,7 @@ useEventListener(document, 'click', handleClose)
}
:deep(.ant-select-selection-item) {
@apply flex align-center;
@apply flex items-center;
}
:deep(.ant-form-item-explain-error) {

2
packages/nc-gui-v2/components/smartsheet-column/LinkedToAnotherRecordOptions.vue

@ -68,7 +68,7 @@ const refTables = $computed(() => {
</div>
<div
class="text-xs cursor-pointer text-grey nc-more-options my-2 flex align-center gap-1 justify-end"
class="text-xs cursor-pointer text-grey nc-more-options my-2 flex items-center gap-1 justify-end"
@click="advancedOptions = !advancedOptions"
>
{{ advancedOptions ? $t('general.hideAll') : $t('general.showMore') }}

4
packages/nc-gui-v2/components/smartsheet-column/SelectOptions.vue

@ -95,7 +95,7 @@ watch(inputs, () => {
<div class="w-full">
<Draggable :list="options" item-key="id" handle=".nc-child-draggable-icon">
<template #item="{ element, index }">
<div class="flex py-1 align-center">
<div class="flex py-1 items-center">
<MdiDragIcon small class="nc-child-draggable-icon handle" />
<a-dropdown v-model:visible="colorMenus[index]" :trigger="['click']">
<template #overlay>
@ -109,7 +109,7 @@ watch(inputs, () => {
</template>
<template #footer>
<a-button type="dashed" class="w-full caption mt-2" @click="addNewOption()">
<div class="flex align-center"><MdiPlusIcon /><span class="flex-auto">Add option</span></div>
<div class="flex items-center"><MdiPlusIcon /><span class="flex-auto">Add option</span></div>
</a-button>
</template>
</Draggable>

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

@ -148,7 +148,7 @@ defineExpose({
/>
<span v-else :key="`${i}dummy`" />
<div :key="`${i}nested`" class="d-flex">
<div :key="`${i}nested`" class="flex">
<a-select
v-model:value="filter.logical_op"
:dropdown-match-select-width="false"
@ -187,7 +187,7 @@ defineExpose({
<MdiCloseBox
v-if="!filter.readOnly"
class="nc-filter-item-remove-btn text-grey align-self-center"
class="nc-filter-item-remove-btn text-grey self-center"
@click.stop="deleteFilter(filter, i)"
/>
<span v-else />
@ -269,7 +269,7 @@ defineExpose({
<div class="flex gap-2 mb-2 mt-4">
<a-button class="elevation-0 text-capitalize" type="primary" ghost @click.stop="addFilter">
<div class="flex align-center gap-1">
<div class="flex items-center gap-1">
<!-- <v-icon small color="grey"> mdi-plus </v-icon> -->
<MdiPlus />
<!-- Add Filter -->
@ -277,7 +277,7 @@ defineExpose({
</div>
</a-button>
<a-button class="text-capitalize !text-gray-500" @click.stop="addFilterGroup">
<div class="flex align-center gap-1">
<div class="flex items-center gap-1">
<!-- <v-icon small color="grey"> mdi-plus </v-icon> -->
<MdiPlus />
Add Filter Group

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

@ -36,7 +36,7 @@ const applyChanges = async () => await filterComp.value?.applyChanges()
<a-dropdown :trigger="['click']">
<div :class="{ 'nc-badge nc-active-btn': filtersLength }">
<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 items-center gap-1">
<MdiFilterOutline />
<!-- Filter -->
<span class="text-capitalize !text-sm font-weight-medium">{{ $t('activity.filter') }}</span>
@ -51,7 +51,7 @@ const applyChanges = async () => await filterComp.value?.applyChanges()
:auto-save="filterAutoSave"
@update:filters-length="filtersLength = $event"
>
<div v-if="!isPublic" class="d-flex align-end mt-2 min-h-[30px]" @click.stop>
<div v-if="!isPublic" class="flex items-end mt-2 min-h-[30px]" @click.stop>
<a-checkbox id="col-filter-checkbox" v-model:checked="filterAutoSave" class="col-filter-checkbox" hide-details dense>
<span class="text-grey text-xs">
{{ $t('msg.info.filterAutoApply') }}

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

@ -86,7 +86,7 @@ const filterOption = (input: string, option: any) => {
:filter-option="filterOption"
>
<a-select-option v-for="option in options" :key="option.value" :value="option.value">
<div class="flex gap-2 items-center align-center h-full">
<div class="flex gap-2 items-center items-center h-full">
<component :is="option.icon" class="min-w-5 !mx-0" />
<span class="min-w-0"> {{ option.label }}</span>
</div>

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

@ -82,7 +82,7 @@ const onMove = (event: { moved: { newIndex: number } }) => {
<a-dropdown :trigger="['click']">
<div :class="{ 'nc-badge nc-active-btn': isAnyFieldHidden }">
<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 items-center gap-1">
<MdiEyeOffOutline />
<!-- Fields -->
@ -104,7 +104,7 @@ const onMove = (event: { moved: { newIndex: number } }) => {
<Draggable v-model="fields" item-key="id" @change="onMove($event)">
<template #item="{ element: field, index: index }">
<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, index)">
<a-checkbox v-model:checked="field.show" class="shrink" @change="saveOrUpdate(field, index)">
<span class="">{{ field.title }}</span>
</a-checkbox>
<div class="flex-1" />
@ -113,7 +113,8 @@ const onMove = (event: { moved: { newIndex: number } }) => {
</template>
</Draggable>
</div>
<v-divider class="my-2" />
<a-divider class="!my-2" />
<div v-if="!isPublic" class="p-2 py-1 flex" @click.stop>
<a-checkbox v-model:checked="showSystemFields">

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

@ -92,7 +92,7 @@ const exportFile = async (exportType: ExportTypes) => {
<div>
<a-dropdown>
<a-button v-t="['c:actions']" class="nc-actions-menu-btn nc-toolbar-btn">
<div class="flex gap-1 align-center">
<div class="flex gap-1 items-center">
<MdiFlashOutline />
<!-- More -->

2
packages/nc-gui-v2/components/smartsheet-toolbar/SearchData.vue

@ -24,7 +24,7 @@ function onPressEnter() {
<template>
<a-input v-model:value="search.query" size="small" class="max-w-[200px]" placeholder="Filter query" @press-enter="onPressEnter">
<template #addonBefore>
<div class="flex align-center relative" @click="isDropdownOpen = true">
<div class="flex items-center relative" @click="isDropdownOpen = true">
<MdiMagnify class="text-grey" />
<MdiMenuDown class="text-grey" />

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

@ -1,10 +1,8 @@
<script lang="ts" setup>
import { useClipboard } from '@vueuse/core'
import { ViewTypes } from 'nocodb-sdk'
import { computed } from 'vue'
import { message } from 'ant-design-vue'
import { useNuxtApp } from '#app'
import { extractSdkResponseErrorMsg, useProject, useSmartsheetStoreOrThrow } from '#imports'
import { computed, extractSdkResponseErrorMsg, useNuxtApp, useProject, useSmartsheetStoreOrThrow } from '#imports'
import MdiOpenInNewIcon from '~icons/mdi/open-in-new'
import MdiCopyIcon from '~icons/mdi/content-copy'
@ -125,7 +123,7 @@ onMounted(() => {
outlined
class="nc-btn-share-view nc-toolbar-btn"
>
<div class="flex align-center gap-1" @click="genShareLink">
<div class="flex items-center gap-1" @click="genShareLink">
<MdiOpenInNewIcon />
<!-- Share View -->
<span class="!text-sm font-weight-medium"> {{ $t('activity.shareView') }}</span>
@ -179,7 +177,7 @@ onMounted(() => {
<style scoped>
.share-link-box {
@apply flex p-2 w-full items-center align-center gap-1 bg-gray-100 rounded;
@apply flex p-2 w-full items-center items-center gap-1 bg-gray-100 rounded;
}
:deep(.ant-collapse-header) {

2
packages/nc-gui-v2/components/smartsheet-toolbar/SharedViewList.vue

@ -110,7 +110,7 @@ const deleteLink = async (id: string) => {
<!-- Password -->
<a-table-column key="password" :title="$t('labels.password')" data-index="title">
<template #default="{ record }">
<div class="flex align-center items-center gap-1">
<div class="flex items-center items-center gap-1">
<template v-if="record.password">
<span class="h-min">{{ record.showPassword ? record.password : '***************************' }}</span>
<component

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

@ -37,7 +37,7 @@ watch(
<a-dropdown offset-y class="" :trigger="['click']">
<div :class="{ 'nc-badge nc-active-btn': sorts?.length }">
<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 items-center gap-1">
<MdiSortIcon />
<!-- Sort -->
<span class="text-capitalize !text-sm font-weight-medium">{{ $t('activity.sort') }}</span>
@ -49,12 +49,8 @@ watch(
<div class="bg-gray-50 p-6 shadow-lg menu-filter-dropdown min-w-[400px] max-h-[max(80vh,500px)] overflow-auto !border">
<div v-if="sorts?.length" class="sort-grid mb-2" @click.stop>
<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> -->
<MdiDeleteIcon
class="nc-sort-item-remove-btn text-grey align-self-center"
small
@click.stop="deleteSort(sort, i)"
></MdiDeleteIcon>
<MdiDeleteIcon class="nc-sort-item-remove-btn text-grey self-center" small @click.stop="deleteSort(sort, i)" />
<FieldListAutoCompleteDropdown
v-model="sort.fk_column_id"
class="caption nc-sort-field-select"
@ -63,9 +59,10 @@ watch(
@click.stop
@update:model-value="saveOrUpdate(sort, i)"
/>
<a-select
v-model:value="sort.direction"
class="flex-shrink-1 flex-grow-0 caption nc-sort-dir-select !text-xs"
class="shrink grow-0 nc-sort-dir-select !text-xs"
:label="$t('labels.operation')"
@click.stop
@update:value="saveOrUpdate(sort, i)"
@ -78,14 +75,10 @@ watch(
<span>{{ option.text }}</span>
</a-select-option>
</a-select>
<!-- <template #item="{ item }"> -->
<!-- <span class="caption font-weight-regular">{{ item.text }}</span> -->
<!-- </template> -->
<!-- </v-select> -->
</template>
</div>
<a-button class="text-capitalize mb-1 mt-4" type="primary" ghost @click.stop="addSort">
<div class="flex gap-1 align-center">
<div class="flex gap-1 items-center">
<MdiAddIcon />
<!-- Add Sort Option -->
{{ $t('activity.addSort') }}

24
packages/nc-gui-v2/components/smartsheet/Form.vue

@ -357,7 +357,7 @@ onMounted(async () => {
<template>
<a-row v-if="submitted" class="h-full">
<a-col :span="24">
<div v-if="formViewData" class="align-center justify-center text-center mt-2">
<div v-if="formViewData" class="items-center justify-center text-center mt-2">
<a-alert type="success">
<template #message>
<div class="text-center">{{ formViewData.success_msg || 'Successfully submitted form data' }}</div>
@ -376,7 +376,7 @@ onMounted(async () => {
<a-col
v-if="isEditable"
:span="8"
class="bg-[#f7f7f7] shadow-md pa-5 h-full overflow-auto scrollbar-thin-primary nc-form-left-drawer"
class="bg-[#f7f7f7] shadow-md p-5 h-full overflow-auto scrollbar-thin-primary nc-form-left-drawer"
>
<div class="flex">
<div class="flex flex-row flex-1 text-lg">
@ -412,7 +412,7 @@ onMounted(async () => {
<template #item="{ element }">
<a-card
size="small"
class="ma-0 pa-0 cursor-pointer item mb-2"
class="m-0 p-0 cursor-pointer item mb-2"
@mousedown="moved = false"
@mousemove="moved = false"
@mouseup="handleMouseUp(element)"
@ -470,7 +470,7 @@ onMounted(async () => {
<!-- for future implementation of cover image -->
</div>
<a-card
class="h-full ma-0 rounded-b-0 pa-4 border-none"
class="h-full m-0 rounded-b-0 p-4 border-none"
:body-style="{
maxWidth: '700px',
margin: '0 auto',
@ -478,9 +478,9 @@ onMounted(async () => {
}"
>
<a-form ref="formRef" :model="formState" class="nc-form">
<a-card class="rounded ma-2 py-10 px-5">
<a-card class="rounded m-2 py-10 px-5">
<!-- Header -->
<a-form-item v-if="isEditable" class="ma-0 gap-0 pa-0">
<a-form-item v-if="isEditable" class="m-0 gap-0 p-0">
<a-input
v-model:value="formViewData.heading"
class="w-full text-bold text-h3"
@ -496,7 +496,7 @@ onMounted(async () => {
<div v-else class="ml-3 w-full text-bold text-h3">{{ formViewData.heading }}</div>
<!-- Sub Header -->
<a-form-item v-if="isEditable" class="ma-0 gap-0 pa-0">
<a-form-item v-if="isEditable" class="m-0 gap-0 p-0">
<a-input
v-model:value="formViewData.subheading"
class="w-full"
@ -518,7 +518,7 @@ onMounted(async () => {
item-key="fk_column_id"
draggable=".item"
group="form-inputs"
class="h-100"
class="h-full"
:move="onMoveCallback"
@change="onMove($event)"
@start="drag = true"
@ -526,7 +526,7 @@ onMounted(async () => {
>
<template #item="{ element, index }">
<div
class="nc-editable item cursor-pointer hover:bg-primary/10 pa-3"
class="nc-editable item cursor-pointer hover:(bg-primary bg-opacity-10) p-3"
:class="`nc-form-drag-${element.title.replaceAll(' ', '')}`"
@click="activeRow = element.title"
>
@ -555,7 +555,7 @@ onMounted(async () => {
<a-form-item
v-if="isVirtualCol(element)"
class="ma-0 gap-0 pa-0"
class="m-0 gap-0 p-0"
:name="element.title"
:rules="[{ required: element.required, message: `${element.title} is required` }]"
>
@ -570,7 +570,7 @@ onMounted(async () => {
<a-form-item
v-else
class="ma-0 gap-0 pa-0"
class="m-0 gap-0 p-0"
:name="element.title"
:rules="[{ required: element.required, message: `${element.title} is required` }]"
>
@ -710,7 +710,7 @@ onMounted(async () => {
}
.nc-input {
@apply w-full !bg-white rounded px-2 py-2 min-h-[40px] mt-2 mb-2 flex align-center border-solid border-1 border-primary;
@apply w-full !bg-white rounded px-2 py-2 min-h-[40px] mt-2 mb-2 flex items-center border-solid border-1 border-primary;
}
.form-meta-input::placeholder {

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

@ -309,7 +309,7 @@ const onNavigate = (dir: NavigateDir) => {
</script>
<template>
<div class="flex flex-col h-100 min-h-0 w-100">
<div class="flex flex-col h-full min-h-0 w-full">
<div class="nc-grid-wrapper min-h-0 flex-1 scrollbar-thin-dull">
<a-dropdown v-model:visible="contextMenu" :trigger="['contextmenu']">
<table
@ -325,7 +325,7 @@ const onNavigate = (dir: NavigateDir) => {
<div class="nc-no-label text-gray-500" :class="{ hidden: selectedAllRecords }">#</div>
<div
:class="{ hidden: !selectedAllRecords, flex: selectedAllRecords }"
class="nc-check-all w-full align-center"
class="nc-check-all w-full items-center"
>
<a-checkbox v-model:checked="selectedAllRecords" />
@ -360,7 +360,7 @@ const onNavigate = (dir: NavigateDir) => {
@click.stop="addColumnDropdown = true"
>
<a-dropdown v-model:visible="addColumnDropdown" :trigger="['click']">
<div class="h-full w-[60px] flex align-center justify-center">
<div class="h-full w-[60px] flex items-center justify-center">
<MdiPlus class="text-sm nc-column-add" />
</div>
@ -382,7 +382,7 @@ const onNavigate = (dir: NavigateDir) => {
<template #default="{ state }">
<tr class="nc-grid-row">
<td key="row-index" class="caption nc-grid-cell pl-5 pr-1">
<div class="align-center flex gap-1 min-w-[55px]">
<div class="items-center flex gap-1 min-w-[55px]">
<div
v-if="!readOnly && !isLocked"
class="nc-row-no text-xs text-gray-500"
@ -407,7 +407,10 @@ const onNavigate = (dir: NavigateDir) => {
>
{{ row.rowMeta.commentCount }}
</span>
<div v-else class="cursor-pointer flex items-center border-1 active:ring rounded p-1 hover:bg-primary/10">
<div
v-else
class="cursor-pointer flex items-center border-1 active:ring rounded p-1 hover:(bg-primary bg-opacity-10)"
>
<MdiArrowExpand
class="select-none transform hover:(text-pink-500 scale-120) nc-row-expand"
@click="expandForm(row, state)"
@ -540,7 +543,7 @@ const onNavigate = (dir: NavigateDir) => {
td:not(:first-child) > div {
overflow: hidden;
@apply flex align-center h-auto px-1;
@apply flex items-center h-auto px-1;
}
table,
@ -572,7 +575,7 @@ const onNavigate = (dir: NavigateDir) => {
}
td.active::before {
@apply bg-primary/5;
@apply bg-primary bg-opacity-5;
}
}

2
packages/nc-gui-v2/components/smartsheet/Pagination.vue

@ -34,7 +34,7 @@ const page = computed({
show-less-items
:show-size-changer="false"
/>
<div v-else class="mx-auto d-flex align-center mt-n1" style="max-width: 250px">
<div v-else class="mx-auto flex items-center mt-n1" style="max-width: 250px">
<span class="text-xs" style="white-space: nowrap"> Change page:</span>
<a-input :value="page" size="small" class="ml-1 !text-xs" type="number" @keydown.enter="changePage(page)">
<template #suffix>

9
packages/nc-gui-v2/components/smartsheet/expanded-form/Comments.vue

@ -24,13 +24,14 @@ watch(
<template>
<div class="h-full flex flex-col w-full bg-[#eceff1] p-2">
<div ref="commentsWrapperEl" class="flex-grow-1 min-h-[100px] overflow-y-auto scrollbar-thin-primary p-2 space-y-2">
<div ref="commentsWrapperEl" class="flex-1 min-h-[100px] overflow-y-auto scrollbar-thin-primary p-2 space-y-2">
<v-skeleton-loader v-if="isCommentsLoading && !commentsAndLogs" type="list-item-avatar-two-line@8" />
<template v-else>
<div v-for="log of commentsAndLogs" :key="log.id" class="flex gap-1 text-xs">
<MdiAccountCircle class="row-span-2" :class="isYou(log.user) ? 'text-pink-300' : 'text-blue-300 '" />
<div class="flex-grow">
<div class="flex-1">
<p class="mb-1 caption edited-text text-[10px] text-gray-500">
{{ isYou(log.user) ? 'You' : log.user == null ? 'Shared base' : log.user }}
{{ log.op_type === 'COMMENT' ? 'commented' : log.op_sub_type === 'INSERT' ? 'created' : 'edited' }}
@ -59,7 +60,7 @@ watch(
><span class="text-[11px] text-gray-500">Comments only</span>
</a-checkbox>
</div>
<div class="flex-shrink-1 mt-2 d-flex">
<div class="shrink mt-2 flex">
<a-input
v-model:value="comment"
class="!text-xs nc-comment-box"
@ -70,7 +71,7 @@ watch(
@keyup.enter.prevent="saveComment"
>
<template #addonBefore>
<div class="flex align-center">
<div class="flex items-center">
<mdi-account-circle class="text-lg text-pink-300" small @click="saveComment" />
</div>
</template>

6
packages/nc-gui-v2/components/smartsheet/expanded-form/Header.vue

@ -35,8 +35,8 @@ const iconColor = '#1890ff'
</script>
<template>
<div class="flex p-2 align-center gap-2 p-4">
<h5 class="text-lg font-weight-medium flex align-center gap-1 mb-0 min-w-0 overflow-x-hidden truncate">
<div class="flex p-2 items-center gap-2 p-4">
<h5 class="text-lg font-weight-medium flex items-center gap-1 mb-0 min-w-0 overflow-x-hidden truncate">
<mdi-table-arrow-right :style="{ color: iconColor }" />
<template v-if="meta">
@ -51,7 +51,7 @@ const iconColor = '#1890ff'
<template v-if="primaryValue">: {{ primaryValue }}</template>
</h5>
<div class="flex-grow" />
<div class="flex-1" />
<mdi-reload class="cursor-pointer select-none" />

4
packages/nc-gui-v2/components/smartsheet/expanded-form/index.vue

@ -109,13 +109,13 @@ export default {
<Header @cancel="onClose" />
<div class="!bg-gray-100 rounded">
<div class="flex h-full nc-form-wrapper items-stretch min-h-[70vh]">
<div class="flex-grow overflow-auto scrollbar-thin-primary">
<div class="flex-1 overflow-auto scrollbar-thin-primary">
<div class="w-[500px] mx-auto">
<div v-for="col of fields" :key="col.title" class="mt-2 py-2" :class="`nc-expand-col-${col.title}`">
<SmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" />
<SmartsheetHeaderCell v-else :column="col" />
<div class="!bg-white rounded px-1 min-h-[35px] flex align-center mt-2">
<div class="!bg-white rounded px-1 min-h-[35px] flex items-center mt-2">
<VirtualCell v-if="isVirtualCol(col)" v-model="row.row[col.title]" :row="row" :column="col" />
<Cell

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

@ -219,11 +219,11 @@ function onDeleted() {
}
.sortable-chosen {
@apply !bg-primary/25 text-primary;
@apply !bg-primary bg-opacity-25 text-primary;
}
.active {
@apply bg-primary/20 text-primary font-medium;
@apply bg-primary bg-opacity-25 text-primary font-medium;
}
}
</style>

2
packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/AddRow.vue

@ -15,7 +15,7 @@ const onClick = () => {
<a-tooltip :placement="isOpen ? 'bottomRight' : 'left'">
<template #title> {{ $t('activity.addRow') }} </template>
<div
:class="{ 'hover:after:bg-primary/75 group': !isLocked, 'disabled-ring': isLocked }"
:class="{ 'hover:after:(bg-primary bg-opacity-75) group': !isLocked, 'disabled-ring': isLocked }"
class="nc-sidebar-right-item nc-sidebar-add-row"
>
<MdiPlusOutline :class="{ 'cursor-pointer group-hover:(!text-white)': !isLocked, 'disabled': isLocked }" @click="onClick" />

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

@ -99,7 +99,7 @@ const Icon = computed(() => {
<style scoped>
.nc-menu-item > div {
@apply grid grid-cols-[30px,auto] gap-2 p-2 align-center;
@apply grid grid-cols-[30px,auto] gap-2 p-2 items-center;
}
.nc-menu-item > div > svg {
@ -107,7 +107,7 @@ const Icon = computed(() => {
}
.nc-menu-option > :first-child {
@apply align-self-center;
@apply self-center;
}
.nc-subtitle {

2
packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/ToggleDrawer.vue

@ -7,7 +7,7 @@ const { isOpen, toggle } = useSidebar({ storageKey: 'nc-right-sidebar' })
<a-tooltip :placement="isOpen ? 'bottomRight' : 'left'" :mouse-enter-delay="0.8">
<template #title> Toggle sidebar</template>
<div class="nc-sidebar-right-item hover:after:bg-primary/75 group nc-sidebar-add-row">
<div class="nc-sidebar-right-item hover:after:(bg-primary bg-opacity-75) group nc-sidebar-add-row">
<MdiChevronDoubleLeft
class="cursor-pointer group-hover:(!text-white) transform transition-transform"
:class="{ 'rotate-180': isOpen }"

2
packages/nc-gui-v2/components/tabs/Auth.vue

@ -26,7 +26,7 @@ const selectedTab = $computed(() => tabsInfo[selectedTabKey])
<template>
<div>
<a-tabs v-model:active-key="selectedTabKey" :open-keys="[]" mode="horizontal" class="nc-auth-tabs mx-6">
<a-tabs v-model:active-key="selectedTabKey" :open-keys="[]" mode="horizontal" class="nc-auth-tabs !mx-6">
<a-tab-pane v-for="(tab, key) of tabsInfo" :key="key" class="select-none">
<template #tab>
<span>

2
packages/nc-gui-v2/components/tabs/Smartsheet.vue

@ -76,7 +76,7 @@ watch(isLocked, (nextValue) => (treeViewIsLockedInj.value = nextValue), { immedi
<template v-if="meta">
<div class="flex flex-1 min-h-0">
<div v-if="activeView" class="h-full flex-grow min-w-0 min-h-0">
<div v-if="activeView" class="h-full flex-1 min-w-0 min-h-0">
<SmartsheetGrid v-if="isGrid" :ref="el" />
<SmartsheetGallery v-else-if="isGallery" />

2
packages/nc-gui-v2/components/template/Editor.vue

@ -761,7 +761,7 @@ onMounted(() => {
@apply bg-white;
}
:deep(.template-form-row) > td {
@apply pa-0 mb-0;
@apply p-0 mb-0;
.ant-form-item {
@apply mb-0;
}

6
packages/nc-gui-v2/components/virtual-cell/BelongsTo.vue

@ -72,15 +72,15 @@ const unlinkRef = async (rec: Record<string, any>) => {
</script>
<template>
<div class="flex w-full chips-wrapper align-center" :class="{ active }">
<div class="chips d-flex align-center flex-grow">
<div class="flex w-full chips-wrapper items-center" :class="{ active }">
<div class="chips flex items-center flex-1">
<template v-if="value && relatedTablePrimaryValueProp">
<ItemChip :item="value" :value="value[relatedTablePrimaryValueProp]" @unlink="unlinkRef(value)" />
</template>
</div>
<div
v-if="!readOnly && !isLocked && isUIAllowed('xcDatatableEditable')"
class="flex-1 flex justify-end gap-1 min-h-[30px] align-center"
class="flex-1 flex justify-end gap-1 min-h-[30px] items-center"
>
<component
:is="addIcon"

2
packages/nc-gui-v2/components/virtual-cell/Formula.vue

@ -32,7 +32,7 @@ const urls = computed(() => replaceUrlsWithLink(result.value))
<span>ERR!</span>
</a-tooltip>
<div class="pa-2" @dblclick="showEditFormulaWarningMessage">
<div class="p-2" @dblclick="showEditFormulaWarningMessage">
<div v-if="urls" v-html="urls" />
<div v-else>{{ result }}</div>
<div v-if="showEditFormulaWarning" class="text-left text-wrap mt-2 text-[#e65100]">

6
packages/nc-gui-v2/components/virtual-cell/HasMany.vue

@ -85,9 +85,9 @@ const unlinkRef = async (rec: Record<string, any>) => {
</script>
<template>
<div class="flex align-center items-center gap-1 w-full chips-wrapper">
<div class="flex items-center items-center gap-1 w-full chips-wrapper">
<template v-if="!isForm">
<div class="chips flex align-center img-container flex-grow hm-items flex-nowrap min-w-0 overflow-hidden">
<div class="chips flex items-center img-container flex-1 hm-items flex-nowrap min-w-0 overflow-hidden">
<template v-if="cells">
<ItemChip v-for="(cell, i) of cells" :key="i" :item="cell.item" :value="cell.value" @unlink="unlinkRef(cell.item)" />
<span v-if="cellValue?.length === 10" class="caption pointer ml-1 grey--text" @click="childListDlg = true">
@ -97,7 +97,7 @@ const unlinkRef = async (rec: Record<string, any>) => {
</div>
<div
v-if="!isLocked && isUIAllowed('xcDatatableEditable')"
class="flex-grow flex justify-end gap-1 min-h-[30px] align-center"
class="flex-1 flex justify-end gap-1 min-h-[30px] items-center"
>
<MdiArrowExpand
class="select-none transform text-sm nc-action-icon text-gray-500/50 hover:text-gray-500 nc-arrow-expand"

6
packages/nc-gui-v2/components/virtual-cell/ManyToMany.vue

@ -84,9 +84,9 @@ const unlinkRef = async (rec: Record<string, any>) => {
</script>
<template>
<div class="flex align-center gap-1 w-full h-full chips-wrapper">
<div class="flex items-center gap-1 w-full h-full chips-wrapper">
<template v-if="!isForm">
<div class="chips flex align-center img-container flex-grow hm-items flex-nowrap min-w-0 overflow-hidden">
<div class="chips flex items-center img-container flex-1 hm-items flex-nowrap min-w-0 overflow-hidden">
<template v-if="cells">
<ItemChip v-for="(cell, i) of cells" :key="i" :item="cell.item" :value="cell.value" @unlink="unlinkRef(cell.item)" />
@ -94,7 +94,7 @@ const unlinkRef = async (rec: Record<string, any>) => {
</template>
</div>
<div v-if="!isLocked && isUIAllowed('xcDatatableEditable')" class="flex-1 flex justify-end gap-1 min-h-[30px] align-center">
<div v-if="!isLocked && isUIAllowed('xcDatatableEditable')" class="flex-1 flex justify-end gap-1 min-h-[30px] items-center">
<MdiArrowExpand
class="text-sm nc-action-icon text-gray-500/50 hover:text-gray-500 nc-arrow-expand"
@click="childListDlg = true"

4
packages/nc-gui-v2/components/virtual-cell/components/ItemChip.vue

@ -44,13 +44,13 @@ export default {
<template>
<div
class="group py-1 px-2 mr-1 my-1 flex align-center bg-blue-100/60 hover:bg-blue-100/40 rounded-[2px]"
class="group py-1 px-2 mr-1 my-1 flex items-center bg-blue-100/60 hover:bg-blue-100/40 rounded-[2px]"
:class="{ active }"
@click="expandedFormDlg = true"
>
<span class="name">{{ value }}</span>
<div v-show="active || isForm" v-if="!readOnly && !isLocked && isUIAllowed('xcDatatableEditable')" class="flex align-center">
<div v-show="active || isForm" v-if="!readOnly && !isLocked && isUIAllowed('xcDatatableEditable')" class="flex items-center">
<MdiCloseThick class="unlink-icon text-xs text-gray-500/50 group-hover:text-gray-500" @click.stop="emit('unlink')" />
</div>

10
packages/nc-gui-v2/components/virtual-cell/components/ListChildItems.vue

@ -83,13 +83,13 @@ const expandedFormRow = ref()
<template>
<component :is="container" v-model:visible="vModel" :footer="null" title="Child list">
<div class="max-h-[max(calc(100vh_-_300px)_,500px)] flex flex-col">
<div class="flex mb-4 align-center gap-2">
<div class="flex mb-4 items-center gap-2">
<div class="flex-1" />
<MdiReload v-if="!isForm" class="cursor-pointer text-gray-500" @click="loadChildrenList" />
<a-button v-if="!readonly" type="primary" ghost class="!text-xs" size="small" @click="emit('attachRecord')">
<div class="flex align-center gap-1">
<div class="flex items-center gap-1">
<MdiLinkVariantRemove class="text-xs" type="primary" @click="unlinkRow(row)" />
Link to '{{ meta.title }}'
</div>
@ -100,7 +100,7 @@ const expandedFormRow = ref()
<a-card
v-for="(row, i) of childrenList?.list ?? state?.[column?.title] ?? []"
:key="i"
class="ma-2 hover:(!bg-gray-200/50 shadow-md)"
class="m-2 hover:(!bg-gray-200/50 shadow-md)"
@click="
() => {
expandedFormRow = row
@ -108,8 +108,8 @@ const expandedFormRow = ref()
}
"
>
<div class="flex align-center">
<div class="flex-grow overflow-hidden min-w-0">
<div class="flex items-center">
<div class="flex-1 overflow-hidden min-w-0">
{{ row[relatedTablePrimaryValueProp] }}
<span class="text-gray-400 text-[11px] ml-1">(Primary key : {{ getRelatedTableRowId(row) }})</span>
</div>

4
packages/nc-gui-v2/components/virtual-cell/components/ListItems.vue

@ -99,7 +99,7 @@ const newRowState = computed(() => {
<template>
<a-modal v-model:visible="vModel" :footer="null" title="Link Record">
<div class="max-h-[max(calc(100vh_-_300px)_,500px)] flex flex-col">
<div class="flex mb-4 align-center gap-2">
<div class="flex mb-4 items-center gap-2">
<a-input
v-model:value="childrenExcludedListPagination.query"
placeholder="Filter query"
@ -115,7 +115,7 @@ const newRowState = computed(() => {
<a-card
v-for="(refRow, i) in childrenExcludedList?.list ?? []"
:key="i"
class="ma-2 cursor-pointer hover:(!bg-gray-200/50 shadow-md) group"
class="m-2 cursor-pointer hover:(!bg-gray-200/50 shadow-md) group"
@click="linkRow(refRow)"
>
{{ refRow[relatedTablePrimaryValueProp]

2
packages/nc-gui-v2/components/webhook/Drawer.vue

@ -35,7 +35,7 @@ async function editHook(hook: Record<string, any>) {
<WebhookEditor v-if="editOrAdd" ref="webhookEditorRef" @back-to-list="editOrAdd = false" />
<WebhookList v-else @edit="editHook" @add="editOrAdd = true" />
</div>
<div class="self-center flex flex-column flex-wrap gap-4 items-center mt-4 md:mx-8 md:justify-between justify-center">
<div class="self-center flex flex-col flex-wrap gap-4 items-center mt-4 md:mx-8 md:justify-between justify-center">
<a-button v-t="['e:hiring']" href="https://angel.co/company/nocodb" target="_blank" size="large">
🚀 We are Hiring! 🚀
</a-button>

4
packages/nc-gui-v2/components/webhook/List.vue

@ -64,7 +64,7 @@ onMounted(() => {
class="cursor-pointer max-h-[75vh] overflow-y-auto scrollbar-thin-primary"
>
<template #renderItem="{ item, index }">
<a-list-item class="pa-2" @click="emit('edit', item)">
<a-list-item class="p-2" @click="emit('edit', item)">
<a-list-item-meta>
<template #description>
<span class="uppercase"> {{ item.event }} {{ item.operation }}</span>
@ -93,7 +93,7 @@ onMounted(() => {
</template>
</a-list>
</div>
<div v-else class="pa-4 bg-gray-100 text-gray-600">
<div v-else class="p-4 bg-gray-100 text-gray-600">
Webhooks list is empty, create new webhook by clicking 'Create webhook' button.
</div>
</div>

1
packages/nc-gui-v2/composables/index.ts

@ -3,6 +3,7 @@ export * from './useDialog'
export * from './useGlobal'
export * from './useInjectionState'
export * from './useSidebar'
export * from './useTheme'
export * from './useUIPermission'
export * from './useAttachment'
export * from './useColors'

50
packages/nc-gui-v2/composables/useTheme/index.ts

@ -0,0 +1,50 @@
import { ConfigProvider } from 'ant-design-vue'
import type { Theme as AntTheme } from 'ant-design-vue/es/config-provider'
import { hexToRGB, ref, useCssVar, useInjectionState } from '#imports'
interface ThemeConfig extends AntTheme {
accentColor: string
}
const [setup, use] = useInjectionState((config?: Partial<ThemeConfig>) => {
const primaryColor = useCssVar('--color-primary', typeof document !== 'undefined' ? document.documentElement : null)
const accentColor = useCssVar('--color-accent', typeof document !== 'undefined' ? document.documentElement : null)
/** current theme config */
const currentTheme = ref<Partial<ThemeConfig>>()
/** set initial config if exists */
if (config) setTheme(config)
function setTheme(theme: Partial<ThemeConfig>) {
// convert hex colors to rgb values
if (theme.primaryColor) primaryColor.value = hexToRGB(theme.primaryColor)
if (theme.accentColor) accentColor.value = hexToRGB(theme.accentColor)
currentTheme.value = theme
ConfigProvider.config({
theme,
})
}
return {
theme: currentTheme,
setTheme,
cssVars: { primaryColor, accentColor },
}
})
export const provideTheme = setup
export function useTheme(config?: Partial<ThemeConfig>) {
const theme = use()
if (!theme) {
return setup(config)
} else {
if (config) theme.setTheme(config)
}
return theme
}

2
packages/nc-gui-v2/lang/nl.json

@ -447,7 +447,7 @@
"importZip": "Import project meta zip-bestand en start opnieuw op.",
"importText": "Import NocoDB-project door het uploaden van het metadata zip-bestand",
"metaNoChange": "Geen verandering gevonden",
"sqlMigration": "Schema-migraties worden automatisch gemaakt. Maak een tabel en vernieuw deze pagina.",
"sqlMigration": "Schem-migraties worden automatisch gemaakt. Maak een tabel en vernieuw deze pagina.",
"dbConnectionStatus": "Omgeving gevalideerd",
"dbConnected": "Succesvolle verbinding",
"notifications": {

2
packages/nc-gui-v2/layouts/base.vue

@ -63,7 +63,7 @@ const logout = () => {
<MdiDotsVertical class="md:text-xl cursor-pointer hover:text-pink-500 nc-menu-accounts" @click.prevent />
<template #overlay>
<a-menu class="!py-0 dark:(!bg-gray-800) leading-8 !rounded">
<a-menu class="!py-0 leading-8 !rounded">
<a-menu-item key="0" class="!rounded-t">
<nuxt-link v-t="['c:navbar:user:email']" class="nc-project-menu-item group no-underline" to="/user">
<MdiAt class="mt-1 group-hover:text-pink-500" />&nbsp;

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

@ -6,7 +6,6 @@ import IconsResolver from 'unplugin-icons/resolver'
import Components from 'unplugin-vue-components/vite'
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'
import monacoEditorPlugin from 'vite-plugin-monaco-editor'
import { themeColors } from './utils/colorsUtils'
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
@ -17,11 +16,9 @@ export default defineNuxtConfig({
css: [
'virtual:windi.css',
'virtual:windi-devtools',
'vuetify/lib/styles/main.sass',
'~/assets/style/fonts.css',
'~/assets/css/global.css',
'~/assets/style.css',
'~/assets/style-v2.scss',
'~/assets/style.scss',
],
meta: {
@ -55,14 +52,6 @@ export default defineNuxtConfig({
external: 'httpsnippet',
},
},
css: {
preprocessorOptions: {
less: {
modifyVars: { 'primary-color': themeColors.primary, 'text-color': 'rgba(61, 61, 61, 1)' },
javascriptEnabled: true,
},
},
},
plugins: [
vueI18n({
include: path.resolve(__dirname, './lang'),
@ -76,7 +65,8 @@ export default defineNuxtConfig({
Components({
resolvers: [
AntDesignVueResolver({
importStyle: 'less',
importStyle: false,
resolveIcons: false,
}),
IconsResolver({
prefix: false,

164
packages/nc-gui-v2/package-lock.json generated

@ -10,7 +10,7 @@
"@vuelidate/validators": "^2.0.0-alpha.31",
"@vueuse/core": "^9.0.2",
"@vueuse/integrations": "^9.0.2",
"ant-design-vue": "^3.2.10",
"ant-design-vue": "^3.2.11",
"dayjs": "^1.11.3",
"file-saver": "^2.0.5",
"jsep": "^1.3.6",
@ -66,7 +66,7 @@
"prettier": "^2.7.1",
"sass": "^1.53.0",
"unplugin-icons": "^0.14.7",
"unplugin-vue-components": "^0.21.1",
"unplugin-vue-components": "^0.22.4",
"vite-plugin-monaco-editor": "^1.1.0",
"vitest": "^0.18.0",
"windicss": "^3.5.6"
@ -932,7 +932,7 @@
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"json-schem-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
@ -956,9 +956,9 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": {
"node_modules/@eslint/eslintrc/node_modules/json-schem-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"resolved": "https://registry.npmjs.org/json-schem-traverse/-/json-schem-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
"peer": true
@ -993,7 +993,7 @@
},
"node_modules/@humanwhocodes/object-schema": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schem-1.2.1.tgz",
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true,
"peer": true
@ -1717,7 +1717,7 @@
},
"node_modules/@nuxt/schema": {
"version": "3.0.0-rc.6",
"resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.0.0-rc.6.tgz",
"resolved": "https://registry.npmjs.org/@nuxt/schema/-/schem-3.0.0-rc.6.tgz",
"integrity": "sha512-BcD5YtWRhn+jU2DlzuI1TeITFeOt5x6qm2KeaU/d5jzJ0oZDzmZwKsAimLtRbHwyU6/kKa+zFbK6pp5obm1XLg==",
"dev": true,
"dependencies": {
@ -2366,7 +2366,7 @@
},
"node_modules/@types/json-schema": {
"version": "7.0.11",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schem-7.0.11.tgz",
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
"dev": true
},
@ -3447,9 +3447,9 @@
"dev": true
},
"node_modules/acorn": {
"version": "8.7.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
"integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
"version": "8.8.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
"integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
@ -3549,7 +3549,7 @@
"dev": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"json-schem-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
},
@ -3598,9 +3598,9 @@
}
},
"node_modules/ant-design-vue": {
"version": "3.2.10",
"resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-3.2.10.tgz",
"integrity": "sha512-aqa0kjJzVQ74MfVw5w7rTOdJQL2JN9V/O6Ro+VQQMq/tY7q91JiomhI9TRKAK3tFdBDXJpUoBCVOsosbbxMzRw==",
"version": "3.2.11",
"resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-3.2.11.tgz",
"integrity": "sha512-QKCAcOY5EJF0PepiVGA4X5PzUetYUvG5qALmA+2TON40pc2+brOEiVTwr3kjF9N+f7q4MpyiLPu4pIErwoajOQ==",
"dependencies": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-vue": "^6.1.0",
@ -6775,7 +6775,7 @@
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"json-schem-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
@ -6866,9 +6866,9 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint/node_modules/json-schema-traverse": {
"node_modules/eslint/node_modules/json-schem-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"resolved": "https://registry.npmjs.org/json-schem-traverse/-/json-schem-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
"peer": true
@ -6902,7 +6902,7 @@
},
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"resolved": "https://registry.npmjs.org/esprima/-/esprim-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true,
"optional": true,
@ -7858,7 +7858,7 @@
},
"node_modules/har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schem-2.0.0.tgz",
"integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==",
"dev": true,
"engines": {
@ -7887,7 +7887,7 @@
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"json-schem-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
@ -7895,9 +7895,9 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/har-validator/node_modules/json-schema-traverse": {
"node_modules/har-validator/node_modules/json-schem-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"resolved": "https://registry.npmjs.org/json-schem-traverse/-/json-schem-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
@ -9213,9 +9213,9 @@
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"dev": true
},
"node_modules/json-schema-traverse": {
"node_modules/json-schem-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/json-schem-traverse/-/json-schem-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
},
@ -12586,9 +12586,9 @@
"node": ">=v12.22.7"
}
},
"node_modules/schema-utils": {
"node_modules/schem-utils": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
"resolved": "https://registry.npmjs.org/schem-utils/-/schem-utils-3.1.1.tgz",
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
"dev": true,
"optional": true,
@ -12606,7 +12606,7 @@
"url": "https://opencollective.com/webpack"
}
},
"node_modules/schema-utils/node_modules/ajv": {
"node_modules/schem-utils/node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
@ -12616,7 +12616,7 @@
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"json-schem-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
@ -12624,7 +12624,7 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/schema-utils/node_modules/ajv-keywords": {
"node_modules/schem-utils/node_modules/ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
@ -12635,9 +12635,9 @@
"ajv": "^6.9.1"
}
},
"node_modules/schema-utils/node_modules/json-schema-traverse": {
"node_modules/schem-utils/node_modules/json-schem-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"resolved": "https://registry.npmjs.org/json-schem-traverse/-/json-schem-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
"optional": true,
@ -13549,7 +13549,7 @@
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.7",
"jest-worker": "^27.4.5",
"schema-utils": "^3.1.1",
"schem-utils": "^3.1.1",
"serialize-javascript": "^6.0.0",
"terser": "^5.7.2"
},
@ -14118,9 +14118,9 @@
}
},
"node_modules/unplugin-vue-components": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.21.1.tgz",
"integrity": "sha512-8MhIT323q1EUu7rz6NfQeiHqDrZKtygy6s9jzcQAuuZUM2T38SHlPT5YJjBOZmM0Bau6YuNTKfBBX4iHzeusaQ==",
"version": "0.22.4",
"resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.22.4.tgz",
"integrity": "sha512-2rRZcM9OnJGXnYxQNfaceEYuPeVACcWySIjy8WBwIiN3onr980TmA3XE5pRJFt8zoQrUA+c46oyIq96noLqrEQ==",
"dev": true,
"dependencies": {
"@antfu/utils": "^0.5.2",
@ -14128,11 +14128,11 @@
"chokidar": "^3.5.3",
"debug": "^4.3.4",
"fast-glob": "^3.2.11",
"local-pkg": "^0.4.1",
"local-pkg": "^0.4.2",
"magic-string": "^0.26.2",
"minimatch": "^5.1.0",
"resolve": "^1.22.1",
"unplugin": "^0.7.1"
"unplugin": "^0.9.0"
},
"engines": {
"node": ">=14"
@ -14172,12 +14172,12 @@
}
},
"node_modules/unplugin-vue-components/node_modules/unplugin": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-0.7.2.tgz",
"integrity": "sha512-m7thX4jP8l5sETpLdUASoDOGOcHaOVtgNyrYlToyQUvILUtEzEnngRBrHnAX3IKqooJVmXpoa/CwQ/QqzvGaHQ==",
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-0.9.3.tgz",
"integrity": "sha512-GWXxizZG+tobNs8fuGTCeilerkkfZTZax2iivuE4pxLaF9wTnPJHOq8tbLKDb5ohVb+2BXNjrU9xx59yWTUnuw==",
"dev": true,
"dependencies": {
"acorn": "^8.7.1",
"acorn": "^8.8.0",
"chokidar": "^3.5.3",
"webpack-sources": "^3.2.3",
"webpack-virtual-modules": "^0.4.4"
@ -14842,7 +14842,7 @@
"loader-runner": "^4.2.0",
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
"schema-utils": "^3.1.0",
"schem-utils": "^3.1.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.1.3",
"watchpack": "^2.3.1",
@ -15926,7 +15926,7 @@
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"json-schem-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
@ -15940,9 +15940,9 @@
"type-fest": "^0.20.2"
}
},
"json-schema-traverse": {
"json-schem-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"resolved": "https://registry.npmjs.org/json-schem-traverse/-/json-schem-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
"peer": true
@ -15970,7 +15970,7 @@
},
"@humanwhocodes/object-schema": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schem-1.2.1.tgz",
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true,
"peer": true
@ -16535,7 +16535,7 @@
},
"@nuxt/schema": {
"version": "3.0.0-rc.6",
"resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.0.0-rc.6.tgz",
"resolved": "https://registry.npmjs.org/@nuxt/schema/-/schem-3.0.0-rc.6.tgz",
"integrity": "sha512-BcD5YtWRhn+jU2DlzuI1TeITFeOt5x6qm2KeaU/d5jzJ0oZDzmZwKsAimLtRbHwyU6/kKa+zFbK6pp5obm1XLg==",
"dev": true,
"requires": {
@ -17076,7 +17076,7 @@
},
"@types/json-schema": {
"version": "7.0.11",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schem-7.0.11.tgz",
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
"dev": true
},
@ -17872,9 +17872,9 @@
"dev": true
},
"acorn": {
"version": "8.7.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
"integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
"version": "8.8.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
"integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
"dev": true
},
"acorn-globals": {
@ -17948,7 +17948,7 @@
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"json-schem-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
}
@ -17978,9 +17978,9 @@
}
},
"ant-design-vue": {
"version": "3.2.10",
"resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-3.2.10.tgz",
"integrity": "sha512-aqa0kjJzVQ74MfVw5w7rTOdJQL2JN9V/O6Ro+VQQMq/tY7q91JiomhI9TRKAK3tFdBDXJpUoBCVOsosbbxMzRw==",
"version": "3.2.11",
"resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-3.2.11.tgz",
"integrity": "sha512-QKCAcOY5EJF0PepiVGA4X5PzUetYUvG5qALmA+2TON40pc2+brOEiVTwr3kjF9N+f7q4MpyiLPu4pIErwoajOQ==",
"requires": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-vue": "^6.1.0",
@ -19919,7 +19919,7 @@
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"json-schem-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
@ -19979,9 +19979,9 @@
"type-fest": "^0.20.2"
}
},
"json-schema-traverse": {
"json-schem-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"resolved": "https://registry.npmjs.org/json-schem-traverse/-/json-schem-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
"peer": true
@ -20357,7 +20357,7 @@
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"resolved": "https://registry.npmjs.org/esprima/-/esprim-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true,
"optional": true,
@ -21087,7 +21087,7 @@
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schem-2.0.0.tgz",
"integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==",
"dev": true
},
@ -21109,13 +21109,13 @@
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"json-schem-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"json-schema-traverse": {
"json-schem-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"resolved": "https://registry.npmjs.org/json-schem-traverse/-/json-schem-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
}
@ -22081,9 +22081,9 @@
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"dev": true
},
"json-schema-traverse": {
"json-schem-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/json-schem-traverse/-/json-schem-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
},
@ -24636,9 +24636,9 @@
"xmlchars": "^2.2.0"
}
},
"schema-utils": {
"schem-utils": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
"resolved": "https://registry.npmjs.org/schem-utils/-/schem-utils-3.1.1.tgz",
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
"dev": true,
"optional": true,
@ -24659,7 +24659,7 @@
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"json-schem-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
@ -24672,9 +24672,9 @@
"peer": true,
"requires": {}
},
"json-schema-traverse": {
"json-schem-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"resolved": "https://registry.npmjs.org/json-schem-traverse/-/json-schem-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
"optional": true,
@ -25390,7 +25390,7 @@
"requires": {
"@jridgewell/trace-mapping": "^0.3.7",
"jest-worker": "^27.4.5",
"schema-utils": "^3.1.1",
"schem-utils": "^3.1.1",
"serialize-javascript": "^6.0.0",
"terser": "^5.7.2"
},
@ -25789,9 +25789,9 @@
}
},
"unplugin-vue-components": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.21.1.tgz",
"integrity": "sha512-8MhIT323q1EUu7rz6NfQeiHqDrZKtygy6s9jzcQAuuZUM2T38SHlPT5YJjBOZmM0Bau6YuNTKfBBX4iHzeusaQ==",
"version": "0.22.4",
"resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.22.4.tgz",
"integrity": "sha512-2rRZcM9OnJGXnYxQNfaceEYuPeVACcWySIjy8WBwIiN3onr980TmA3XE5pRJFt8zoQrUA+c46oyIq96noLqrEQ==",
"dev": true,
"requires": {
"@antfu/utils": "^0.5.2",
@ -25799,11 +25799,11 @@
"chokidar": "^3.5.3",
"debug": "^4.3.4",
"fast-glob": "^3.2.11",
"local-pkg": "^0.4.1",
"local-pkg": "^0.4.2",
"magic-string": "^0.26.2",
"minimatch": "^5.1.0",
"resolve": "^1.22.1",
"unplugin": "^0.7.1"
"unplugin": "^0.9.0"
},
"dependencies": {
"brace-expansion": {
@ -25825,12 +25825,12 @@
}
},
"unplugin": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-0.7.2.tgz",
"integrity": "sha512-m7thX4jP8l5sETpLdUASoDOGOcHaOVtgNyrYlToyQUvILUtEzEnngRBrHnAX3IKqooJVmXpoa/CwQ/QqzvGaHQ==",
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-0.9.3.tgz",
"integrity": "sha512-GWXxizZG+tobNs8fuGTCeilerkkfZTZax2iivuE4pxLaF9wTnPJHOq8tbLKDb5ohVb+2BXNjrU9xx59yWTUnuw==",
"dev": true,
"requires": {
"acorn": "^8.7.1",
"acorn": "^8.8.0",
"chokidar": "^3.5.3",
"webpack-sources": "^3.2.3",
"webpack-virtual-modules": "^0.4.4"
@ -26298,7 +26298,7 @@
"loader-runner": "^4.2.0",
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
"schema-utils": "^3.1.0",
"schem-utils": "^3.1.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.1.3",
"watchpack": "^2.3.1",

4
packages/nc-gui-v2/package.json

@ -16,7 +16,7 @@
"@vuelidate/validators": "^2.0.0-alpha.31",
"@vueuse/core": "^9.0.2",
"@vueuse/integrations": "^9.0.2",
"ant-design-vue": "^3.2.10",
"ant-design-vue": "^3.2.11",
"dayjs": "^1.11.3",
"file-saver": "^2.0.5",
"jsep": "^1.3.6",
@ -72,7 +72,7 @@
"prettier": "^2.7.1",
"sass": "^1.53.0",
"unplugin-icons": "^0.14.7",
"unplugin-vue-components": "^0.21.1",
"unplugin-vue-components": "^0.22.4",
"vite-plugin-monaco-editor": "^1.1.0",
"vitest": "^0.18.0",
"windicss": "^3.5.6"

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

@ -314,7 +314,9 @@ definePageMeta({
</template>
</a-dropdown>
<div class="nc-sidebar-left-toggle-icon hover:after:bg-primary/75 group nc-sidebar-add-row flex align-center px-2">
<div
class="nc-sidebar-left-toggle-icon hover:after:(bg-primary bg-opacity-75) group nc-sidebar-add-row flex items-center px-2"
>
<MdiBackburger
class="cursor-pointer transform transition-transform duration-500"
:class="{ 'rotate-180': !isOpen }"

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

@ -29,8 +29,11 @@ const { isOpen, toggle } = useSidebar()
<template>
<div class="h-full w-full nc-container">
<div class="h-full w-full flex flex-col">
<div class="flex items-end !min-h-[50px] bg-primary/100">
<div v-if="!isOpen" class="nc-sidebar-left-toggle-icon hover:after:bg-primary/75 group nc-sidebar-add-row py-2 px-3">
<div class="flex items-end !min-h-[50px] !bg-primary">
<div
v-if="!isOpen"
class="nc-sidebar-left-toggle-icon hover:after:(bg-primary bg-opacity-75) group nc-sidebar-add-row py-2 px-3"
>
<MdiMenu
class="cursor-pointer transform transition-transform duration-500 text-white"
:class="{ 'rotate-180': !isOpen }"
@ -41,7 +44,7 @@ const { isOpen, toggle } = useSidebar()
<a-tabs v-model:activeKey="activeTabIndex" class="nc-root-tabs" type="editable-card" @edit="closeTab(activeTabIndex)">
<a-tab-pane v-for="(tab, i) in tabs" :key="i">
<template #tab>
<div class="flex align-center gap-2">
<div class="flex items-center gap-2">
<component :is="icon(tab)" class="text-sm" />
{{ tab.title }}
@ -49,8 +52,10 @@ const { isOpen, toggle } = useSidebar()
</template>
</a-tab-pane>
</a-tabs>
<span class="flex-1" />
<div class="flex justify-center align-self-center mr-2 min-w-[115px]">
<div class="flex justify-center self-center mr-2 min-w-[115px]">
<div v-show="isLoading" class="flex items-center gap-2 ml-3 text-white">
{{ $t('general.loading') }}

17
packages/nc-gui-v2/pages/forgot-password.vue

@ -59,14 +59,11 @@ function resetError() {
<template>
<NuxtLayout>
<div class="md:bg-primary/5 forgot-password h-full min-h-[600px] flex flex-col justify-center items-center">
<div class="md:bg-primary bg-opacity-5 forgot-password h-full min-h-[600px] flex flex-col justify-center items-center">
<div
class="bg-white mt-[60px] relative flex flex-col justify-center gap-2 w-full max-w-[500px] mx-auto p-8 md:(rounded-lg border-1 border-gray-200 shadow-xl)"
>
<general-noco-icon
class="color-transition hover:(ring ring-pink-500)"
:class="[isLoading ? 'animated-bg-gradient' : '']"
/>
<general-noco-icon class="color-transition hover:(ring ring-accent)" :class="[isLoading ? 'animated-bg-gradient' : '']" />
<div class="self-center flex flex-col justify-center items-center text-center gap-2">
<h1 class="prose-2xl font-bold my-4 w-full">{{ $t('title.resetPassword') }}</h1>
@ -122,24 +119,24 @@ function resetError() {
.forgot-password {
.ant-input-affix-wrapper,
.ant-input {
@apply dark:(bg-gray-700 !text-white) !appearance-none my-1 border-1 border-solid border-primary/50 rounded;
@apply !appearance-none my-1 border-1 border-solid border-primary/50 rounded;
}
.submit {
@apply z-1 relative color-transition border border-gray-300 rounded-md p-3 text-white;
@apply z-1 relative color-transition rounded p-3 text-white shadow;
&::after {
@apply rounded-md absolute top-0 left-0 right-0 bottom-0 transition-all duration-150 ease-in-out bg-primary;
@apply rounded absolute top-0 left-0 right-0 bottom-0 transition-all duration-150 ease-in-out bg-primary;
content: '';
z-index: -1;
}
&:hover::after {
@apply transform scale-110 ring ring-pink-500;
@apply transform scale-110 ring ring-accent;
}
&:active::after {
@apply ring ring-pink-500;
@apply ring ring-accent;
}
}
}

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

@ -101,7 +101,7 @@ onMounted(() => {
:placeholder="$t('activity.searchProject')"
/>
<div class="flex-grow" />
<div class="flex-1" />
<a-dropdown v-if="isUIAllowed('projectCreate', true)" :trigger="['click']">
<button class="nc-new-project-menu">

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

@ -131,21 +131,17 @@ const resetError = () => {
.ant-input-affix-wrapper,
.ant-input {
@apply dark:(!bg-gray-700 !text-white) !appearance-none my-1 border-1 border-solid border-primary/50 rounded;
@apply !appearance-none my-1 border-1 border-solid border-primary/50 rounded;
}
.password {
input {
@apply !border-none;
}
.ant-input-password-icon {
@apply dark:!text-white;
}
}
.submit {
@apply ml-1 border border-gray-300 rounded-lg p-4 bg-gray-100/50 text-white bg-primary hover:bg-primary/75 dark:(!bg-secondary/75 hover:!bg-secondary/50);
@apply ml-1 border border-gray-300 rounded-lg p-4 bg-gray-100/50 text-white bg-primary hover:(bg-primary bg-opacity-75);
}
}
</style>

16
packages/nc-gui-v2/pages/projects/index.vue

@ -64,10 +64,10 @@ const deleteProject = (project: ProjectType) => {
<v-menu class="select-none">
<template #activator="{ props }">
<div
class="color-transition hover:(bg-gray-100 dark:bg-secondary/25) dark:(bg-secondary/50 !text-white shadow-gray-600) mr-auto select-none flex items-center gap-2 leading-8 cursor-pointer rounded-full border-1 border-gray-300 px-5 py-2 shadow prose-lg font-semibold"
class="color-transition hover:(bg-gray-100) mr-auto select-none flex items-center gap-2 leading-8 cursor-pointer rounded-full border-1 border-gray-300 px-5 py-2 shadow prose-lg font-semibold"
@click="props.onClick"
>
<MdiPlus class="text-primary dark:(!text-white) text-2xl" />
<MdiPlus class="text-primary text-2xl" />
{{ $t('title.newProj') }}
</div>
</template>
@ -91,7 +91,7 @@ const deleteProject = (project: ProjectType) => {
</v-menu>
</div>
<a-menu class="pr-4 dark:bg-gray-800 dark:text-white flex-1 border-0">
<a-menu class="pr-4 flex-1 border-0">
<a-menu-item
v-for="(option, index) in navDrawerOptions"
:key="index"
@ -114,20 +114,20 @@ const deleteProject = (project: ProjectType) => {
</div>
</template>
<v-container class="flex-1 mb-12">
<div class="flex-1 mb-12">
<div class="flex">
<div class="flex-1 text-2xl md:text-4xl font-bold text-gray-500 dark:text-white p-4">
<div class="flex-1 text-2xl md:text-4xl font-bold text-gray-500 p-4">
{{ activePage }}
</div>
<div class="self-end flex text-4xl mb-1">
<MaterialSymbolsGridView
:class="route.name === 'index-index' ? '!text-primary dark:(!text-secondary/75)' : ''"
:class="route.name === 'index-index' ? '!text-primary' : ''"
class="cursor-pointer p-2 hover:bg-gray-300/50 rounded-full"
@click="navigateTo('/')"
/>
<MaterialSymbolsFormatListBulletedRounded
:class="route.name === 'index-index-list' ? '!text-primary dark:(!text-secondary/75)' : ''"
:class="route.name === 'index-index-list' ? '!text-primary' : ''"
class="cursor-pointer p-2 hover:bg-gray-300/50 rounded-full"
@click="navigateTo('/list')"
/>
@ -137,7 +137,7 @@ const deleteProject = (project: ProjectType) => {
<a-divider class="!mb-4 lg:(!mb-8)" />
<NuxtPage :projects="projects" @delete-project="deleteProject" />
</v-container>
</div>
<a-modal></a-modal>
</NuxtLayout>

2
packages/nc-gui-v2/pages/projects/index/list.vue

@ -32,7 +32,7 @@ const openProject = async (project: ProjectType) => {
<template v-for="project of projects" :key="project.id">
<div
class="cursor-pointer grid grid-cols-3 gap-2 prose-md hover:(bg-gray-300/30 dark:bg-gray-500/30 shadow-sm) p-2 transition-color ease-in duration-100"
class="cursor-pointer grid grid-cols-3 gap-2 prose-md hover:(bg-gray-300/30) p-2 transition-color ease-in duration-100"
@click="openProject(project)"
>
<div class="font-semibold capitalize">{{ project.title || 'Untitled' }}</div>

21
packages/nc-gui-v2/pages/signin.vue

@ -80,14 +80,11 @@ function resetError() {
<template>
<NuxtLayout>
<div class="md:bg-primary/5 signin h-full min-h-[600px] flex flex-col justify-center items-center nc-form-signup">
<div class="md:bg-primary bg-opacity-5 signin h-full min-h-[600px] flex flex-col justify-center items-center nc-form-signup">
<div
class="bg-white mt-[60px] relative flex flex-col justify-center gap-2 w-full max-w-[500px] mx-auto p-8 md:(rounded-lg border-1 border-gray-200 shadow-xl)"
>
<general-noco-icon
class="!rounded-full color-transition hover:(ring ring-pink-500)"
:class="[isLoading ? 'animated-bg-gradient' : '']"
/>
<general-noco-icon class="color-transition hover:(ring ring-accent)" :class="[isLoading ? 'animated-bg-gradient' : '']" />
<h1 class="prose-2xl font-bold self-center my-4">{{ $t('general.signIn') }}</h1>
@ -150,34 +147,30 @@ function resetError() {
.signin {
.ant-input-affix-wrapper,
.ant-input {
@apply dark:(bg-gray-700 !text-white) !appearance-none my-1 border-1 border-solid border-primary/50 rounded;
@apply !appearance-none my-1 border-1 border-solid border-primary/50 rounded;
}
.password {
input {
@apply !border-none;
}
.ant-input-password-icon {
@apply dark:!text-white;
}
}
.submit {
@apply z-1 relative color-transition border border-gray-300 rounded-md p-3 text-white;
@apply z-1 relative color-transition rounded p-3 text-white shadow-sm;
&::after {
@apply rounded-md absolute top-0 left-0 right-0 bottom-0 transition-all duration-150 ease-in-out bg-primary;
@apply rounded absolute top-0 left-0 right-0 bottom-0 transition-all duration-150 ease-in-out bg-primary;
content: '';
z-index: -1;
}
&:hover::after {
@apply transform scale-110 ring ring-pink-500;
@apply transform scale-110 ring ring-accent;
}
&:active::after {
@apply ring ring-pink-500;
@apply ring ring-accent;
}
}
}

25
packages/nc-gui-v2/pages/signup/[[token]].vue

@ -103,14 +103,11 @@ function resetError() {
<template>
<NuxtLayout>
<div class="md:bg-primary/5 signup h-full min-h-[600px] flex flex-col justify-center items-center">
<div class="md:bg-primary bg-opacity-5 signup h-full min-h-[600px] flex flex-col justify-center items-center">
<div
class="bg-white mt-[60px] relative flex flex-col justify-center gap-2 w-full max-w-[500px] mx-auto p-8 md:(rounded-lg border-1 border-gray-200 shadow-xl)"
>
<general-noco-icon
class="color-transition hover:(ring ring-pink-500)"
:class="[isLoading ? 'animated-bg-gradient' : '']"
/>
<general-noco-icon class="color-transition hover:(ring ring-accent)" :class="[isLoading ? 'animated-bg-gradient' : '']" />
<h1 class="prose-2xl font-bold self-center my-4">
{{ $t('general.signUp') }}
@ -159,7 +156,7 @@ function resetError() {
<a-switch
v-model:checked="subscribe"
size="small"
class="my-1 hover:(ring ring-pink-500) focus:(!ring !ring-pink-500)"
class="my-1 hover:(ring ring-accent) focus:(!ring !ring-accent)"
/>
<div class="prose-xs text-gray-500">Subscribe to our weekly newsletter</div>
</div>
@ -175,7 +172,7 @@ function resetError() {
<div class="prose-sm mt-4 text-gray-500">
By signing up, you agree to the
<a class="prose-sm text-gray-500 underline" target="_blank" href="https://nocodb.com/policy-nocodb">Terms of Service</a>
<a class="prose-sm !text-gray-500 underline" target="_blank" href="https://nocodb.com/policy-nocodb">Terms of Service</a>
</div>
</div>
</NuxtLayout>
@ -185,34 +182,30 @@ function resetError() {
.signup {
.ant-input-affix-wrapper,
.ant-input {
@apply dark:(bg-gray-700 !text-white) !appearance-none my-1 border-1 border-solid border-primary/50 rounded;
@apply !appearance-none my-1 border-1 border-solid border-primary/50 rounded;
}
.password {
input {
@apply !border-none;
}
.ant-input-password-icon {
@apply dark:!text-white;
}
}
.submit {
@apply z-1 relative color-transition border border-gray-300 rounded-md p-3 text-white;
@apply z-1 relative color-transition rounded p-3 text-white shadow;
&::after {
@apply rounded-md absolute top-0 left-0 right-0 bottom-0 transition-all duration-150 ease-in-out bg-primary;
@apply rounded absolute top-0 left-0 right-0 bottom-0 transition-all duration-150 ease-in-out bg-primary;
content: '';
z-index: -1;
}
&:hover::after {
@apply transform scale-110 ring ring-pink-500;
@apply transform scale-110 ring ring-accent;
}
&:active::after {
@apply ring ring-pink-500;
@apply ring ring-accent;
}
}
}

10
packages/nc-gui-v2/plugins/ant.ts

@ -1,12 +1,6 @@
import { Menu as AntMenu, ConfigProvider } from 'ant-design-vue'
import { defineNuxtPlugin, themeColors } from '#imports'
import { Menu as AntMenu } from 'ant-design-vue'
import { defineNuxtPlugin } from '#imports'
export default defineNuxtPlugin((nuxtApp) => {
ConfigProvider.config({
theme: {
primaryColor: themeColors.primary,
},
})
nuxtApp.vueApp.component(AntMenu.name, AntMenu)
})

17
packages/nc-gui-v2/plugins/state.ts

@ -1,5 +1,4 @@
import { defineNuxtPlugin } from '#app'
import { useDark, useGlobal, watch } from '#imports'
import { defineNuxtPlugin, useApi, useGlobal } from '#imports'
/**
* Initialize global state and watches for changes
@ -15,25 +14,15 @@ import { useDark, useGlobal, watch } from '#imports'
*/
export default defineNuxtPlugin(async (nuxtApp) => {
const state = useGlobal()
const { $api } = useNuxtApp()
const darkMode = useDark()
const { api } = useApi()
/** set i18n locale to stored language */
nuxtApp.vueApp.i18n.locale.value = state.lang.value
try {
state.appInfo.value = await $api.utils.appInfo()
state.appInfo.value = await api.utils.appInfo()
} catch (e) {
console.error(e)
}
/** set current dark mode from storage */
watch(
state.darkMode,
(newMode) => {
darkMode.value = newMode
},
{ immediate: true },
)
})

2
packages/nc-gui-v2/plugins/vuetify.ts

@ -25,5 +25,5 @@ export const createVuetifyPlugin = () =>
})
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(createVuetifyPlugin())
// nuxtApp.vueApp.use(createVuetifyPlugin())
})

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

@ -1,3 +1,5 @@
import colors from 'windicss/colors'
export const theme = {
light: ['#ffdce5', '#fee2d5', '#ffeab6', '#d1f7c4', '#ede2fe', '#eee', '#cfdffe', '#d0f1fd', '#c2f5e8', '#ffdaf6'],
dark: [
@ -41,3 +43,43 @@ export const themeColors = {
'success': '#4CAF50',
'warning': '#FB8C00',
}
export const themeV2Colors = {
/** Primary shades */
'royal-blue': {
'DEFAULT': '#4351E8',
'50': '#E7E8FC',
'100': '#D4D8FA',
'200': '#B0B6F5',
'300': '#8C94F1',
'400': '#6773EC',
'500': '#4351E8',
'600': '#1A2BD8',
'700': '#1421A6',
'800': '#0E1774',
'900': '#080D42',
},
/** Accent shades */
'pink': colors.pink,
}
const isValidHex = (hex: string) => /^#([A-Fa-f0-9]{3,4}){1,2}$/.test(hex)
const getChunksFromString = (st: string, chunkSize: number) => st.match(new RegExp(`.{${chunkSize}}`, 'g'))
const convertHexUnitTo256 = (hexStr: string) => parseInt(hexStr.repeat(2 / hexStr.length), 16)
export const hexToRGB = (hex: string) => {
if (!isValidHex(hex)) {
throw new Error('Invalid HEX')
}
const chunkSize = Math.floor((hex.length - 1) / 3)
const hexArr = getChunksFromString(hex.slice(1), chunkSize)!
const [r, g, b] = hexArr.map(convertHexUnitTo256)
return `${r}, ${g}, ${b}`
}

18
packages/nc-gui-v2/windi.config.ts

@ -11,7 +11,7 @@ import animations from '@windicss/plugin-animations'
// @ts-expect-error no types for plugin-question-mark
import questionMark from '@windicss/plugin-question-mark'
import { theme as colors, themeColors } from './utils/colorsUtils'
import { theme as colors, themeColors, themeV2Colors } from './utils/colorsUtils'
export default defineConfig({
extract: {
@ -27,7 +27,7 @@ export default defineConfig({
questionMark,
formsPlugin,
typographyPlugin({
dark: true,
dark: false,
}),
aspectRatioPlugin,
lineClampPlugin,
@ -42,10 +42,8 @@ export default defineConfig({
shortcuts: {
'color-transition': 'transition-color duration-100 ease-in',
'scrollbar-thin-primary':
'scrollbar scrollbar-thin scrollbar-thumb-rounded scrollbar-thumb-primary scrollbar-track-white dark:(!scrollbar-track-black)',
'scrollbar-thin-dull':
'scrollbar scrollbar-thin scrollbar-thumb-rounded scrollbar-thumb-gray-300 scrollbar-track-white dark:(!scrollbar-track-black)',
'scrollbar-thin-primary': 'scrollbar scrollbar-thin scrollbar-thumb-rounded scrollbar-thumb-primary scrollbar-track-white',
'scrollbar-thin-dull': 'scrollbar scrollbar-thin scrollbar-thumb-rounded scrollbar-thumb-gray-300 scrollbar-track-white',
},
theme: {
@ -55,10 +53,16 @@ export default defineConfig({
mono: ['Roboto', 'mono'],
},
extend: {
textColor: {
primary: 'rgba(var(--color-primary), var(--tw-text-opacity))',
accent: 'rgba(var(--color-accent), var(--tw-text-opacity))',
},
colors: {
...windiColors,
...themeColors,
accent: windiColors.pink['500'],
...themeV2Colors,
primary: 'rgba(var(--color-primary), var(--tw-bg-opacity))',
accent: 'rgba(var(--color-accent), var(--tw-bg-opacity))',
dark: colors.dark,
light: colors.light,
},

Loading…
Cancel
Save