Browse Source

Merge pull request #3159 from nocodb/chore/sidebar-toggle-effect

refactor(gui-v2): show sidebar toggle on hover
pull/3163/head
navi 2 years ago committed by GitHub
parent
commit
369a64eeee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 64
      packages/nc-gui-v2/assets/style-v2.scss
  2. 2
      packages/nc-gui-v2/components/dashboard/TreeView.vue
  3. 12
      packages/nc-gui-v2/components/general/SocialCard.vue
  4. 6
      packages/nc-gui-v2/components/general/Sponsors.vue
  5. 2
      packages/nc-gui-v2/components/smartsheet/Pagination.vue
  6. 8
      packages/nc-gui-v2/components/smartsheet/sidebar/MenuBottom.vue
  7. 3
      packages/nc-gui-v2/components/smartsheet/sidebar/RenameableMenuItem.vue
  8. 13
      packages/nc-gui-v2/components/smartsheet/sidebar/index.vue
  9. 2
      packages/nc-gui-v2/components/smartsheet/sidebar/menu/ApiSnippet.vue
  10. 2
      packages/nc-gui-v2/components/tabs/Smartsheet.vue
  11. 23
      packages/nc-gui-v2/composables/useUIPermission/index.ts
  12. 3
      packages/nc-gui-v2/nuxt.config.ts
  13. 35
      packages/nc-gui-v2/pages/[projectType]/[projectId]/index.vue
  14. 52
      packages/nc-gui-v2/pages/index/index.vue

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

@ -31,31 +31,6 @@ nav .v-list {
@apply dark:bg-white @apply dark:bg-white
} }
.page-enter-active,
.page-leave-active,
.layout-enter-active,
.layout-leave-active {
@apply transition-opacity duration-300 ease-in-out;
}
.page-enter,
.page-leave-active,
.layout-enter,
.layout-leave-active {
@apply opacity-0;
}
.slide-enter-active,
.slide-leave-active {
@apply transition-all duration-200 ease-in-out;
transform: translate(100%, 0);
}
.slide-enter,
.slide-leave-active {
transform: translate(-100%, 0);
}
a { a {
@apply prose text-primary underline hover:opacity-75 dark:(text-secondary) hover:(opacity-75); @apply prose text-primary underline hover:opacity-75 dark:(text-secondary) hover:(opacity-75);
} }
@ -153,3 +128,42 @@ html {
background-position: 0% 22% background-position: 0% 22%
} }
} }
.page-enter-active,
.page-leave-active,
.layout-enter-active,
.layout-leave-active {
@apply transition-opacity duration-300 ease-in-out;
}
.page-enter,
.page-leave-active,
.layout-enter,
.layout-leave-active {
@apply opacity-0;
}
.slide-enter-active,
.slide-leave-active {
@apply transition-all duration-200 ease-in-out;
transform: translate(100%, 0);
}
.slide-enter,
.slide-leave-active {
transform: translate(-100%, 0);
}
.glow-enter-active,
.glow-leave-active {
@apply transition-all duration-300 ease-in-out;
}
.glow-enter-active {
@apply ring ring-xl;
}
.glow-enter,
.glow-leave-active {
@apply opacity-0;
}

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

@ -137,7 +137,7 @@ const activeTable = computed(() => {
<template> <template>
<div class="nc-treeview-container flex flex-col"> <div class="nc-treeview-container flex flex-col">
<div class="px-6 py-[8.75px] border-b-1 nc-filter-input"> <div class="px-6 py-[9px] border-b-1 nc-filter-input">
<div class="flex items-center bg-gray-50 rounded relative"> <div class="flex items-center bg-gray-50 rounded relative">
<a-input <a-input
v-model:value="filterQuery" v-model:value="filterQuery"

12
packages/nc-gui-v2/components/general/SocialCard.vue

@ -7,8 +7,9 @@ const isRtlLang = $computed(() => ['fa'].includes(currentLang.value))
</script> </script>
<template> <template>
<a-list class="w-[300px] pa-3 elevation-4 rounded-xl mr-10" dense> <a-card :body-style="{ padding: '0' }" class="w-[300px] shadow-sm rounded-lg">
<a-list-item class="cursor-pointer"> <a-list class="w-full" dense>
<a-list-item>
<nuxt-link class="text-primary" to="https://github.com/nocodb/nocodb" target="_blank"> <nuxt-link class="text-primary" to="https://github.com/nocodb/nocodb" target="_blank">
<div class="flex items-center text-sm"> <div class="flex items-center text-sm">
<mdi-github class="mx-3 text-lg" /> <mdi-github class="mx-3 text-lg" />
@ -70,4 +71,11 @@ const isRtlLang = $computed(() => ['fa'].includes(currentLang.value))
</nuxt-link> </nuxt-link>
</a-list-item> </a-list-item>
</a-list> </a-list>
</a-card>
</template> </template>
<style scoped>
:deep(.ant-list-item) {
@apply hover:(bg-gray-100 !text-primary);
}
</style>

6
packages/nc-gui-v2/components/general/Sponsors.vue

@ -7,9 +7,9 @@ const { nav = false } = defineProps<Props>()
</script> </script>
<template> <template>
<a-card class="w-[300px] ma-10 shadow-lg rounded-lg"> <a-card class="w-[300px] shadow-sm rounded-lg">
<template #cover> <template #cover>
<img class="max-h-[180px]" alt="cover" src="/ants-leaf-cutter.jpeg" /> <img class="max-h-[180px] rounded-t-lg" alt="cover" src="/ants-leaf-cutter.jpeg" />
</template> </template>
<a-card-meta> <a-card-meta>
@ -26,7 +26,7 @@ const { nav = false } = defineProps<Props>()
<div class="flex justify-center"> <div class="flex justify-center">
<nuxt-link href="https://github.com/sponsors/nocodb" target="_blank"> <nuxt-link href="https://github.com/sponsors/nocodb" target="_blank">
<a-button class="!shadow" size="large"> <a-button class="!shadow rounded" size="large">
<div class="flex items-center"> <div class="flex items-center">
<mdi-cards-heart class="text-red-500 mr-2" /> <mdi-cards-heart class="text-red-500 mr-2" />
{{ $t('activity.sponsorUs') }} {{ $t('activity.sponsorUs') }}

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

@ -17,7 +17,7 @@ const page = computed({
</script> </script>
<template> <template>
<div class="flex items-center"> <div class="flex items-center mb-1">
<span v-if="count !== null && count !== Infinity" class="caption ml-5 text-gray-500"> <span v-if="count !== null && count !== Infinity" class="caption ml-5 text-gray-500">
{{ count }} record{{ count !== 1 ? 's' : '' }} {{ count }} record{{ count !== 1 ? 's' : '' }}
</span> </span>

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

@ -46,7 +46,7 @@ function onOpenModal(type: ViewTypes, title = '') {
class="group !flex !items-center !my-0 !h-[30px] nc-create-3-view" class="group !flex !items-center !my-0 !h-[30px] nc-create-3-view"
@click="onOpenModal(ViewTypes.GRID)" @click="onOpenModal(ViewTypes.GRID)"
> >
<a-tooltip placement="left"> <a-tooltip :mouse-enter-delay="1" placement="left">
<template #title> <template #title>
{{ $t('msg.info.addView.grid') }} {{ $t('msg.info.addView.grid') }}
</template> </template>
@ -68,7 +68,7 @@ function onOpenModal(type: ViewTypes, title = '') {
class="group !flex !items-center !-my0 !h-[30px] nc-create-2-view" class="group !flex !items-center !-my0 !h-[30px] nc-create-2-view"
@click="onOpenModal(ViewTypes.GALLERY)" @click="onOpenModal(ViewTypes.GALLERY)"
> >
<a-tooltip placement="left"> <a-tooltip :mouse-enter-delay="1" placement="left">
<template #title> <template #title>
{{ $t('msg.info.addView.gallery') }} {{ $t('msg.info.addView.gallery') }}
</template> </template>
@ -91,7 +91,7 @@ function onOpenModal(type: ViewTypes, title = '') {
class="group !flex !items-center !my-0 !h-[30px] nc-create-1-view" class="group !flex !items-center !my-0 !h-[30px] nc-create-1-view"
@click="onOpenModal(ViewTypes.FORM)" @click="onOpenModal(ViewTypes.FORM)"
> >
<a-tooltip placement="left"> <a-tooltip :mouse-enter-delay="1" placement="left">
<template #title> <template #title>
{{ $t('msg.info.addView.form') }} {{ $t('msg.info.addView.form') }}
</template> </template>
@ -111,7 +111,7 @@ 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-3 mt-3">
<button <button
v-if="isUIAllowed('virtualViewsCreateOrEdit')" v-if="isUIAllowed('virtualViewsCreateOrEdit')"
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" 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"

3
packages/nc-gui-v2/components/smartsheet/sidebar/RenameableMenuItem.vue

@ -2,7 +2,7 @@
import type { ViewTypes } from 'nocodb-sdk' import type { ViewTypes } from 'nocodb-sdk'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import { viewIcons } from '~/utils' import { viewIcons } from '~/utils'
import { onKeyStroke, useDebounceFn, useNuxtApp, useVModel } from '#imports' import { onKeyStroke, useDebounceFn, useNuxtApp, useUIPermission, useVModel } from '#imports'
interface Props { interface Props {
view: Record<string, any> view: Record<string, any>
@ -163,6 +163,7 @@ function onStopEdit() {
</div> </div>
<a-input v-if="isEditing" :ref="focusInput" v-model:value="vModel.title" @blur="onCancel" @keydown="onKeyDown($event)" /> <a-input v-if="isEditing" :ref="focusInput" v-model:value="vModel.title" @blur="onCancel" @keydown="onKeyDown($event)" />
<div v-else>{{ vModel.alias || vModel.title }}</div> <div v-else>{{ vModel.alias || vModel.title }}</div>
<div class="flex-1" /> <div class="flex-1" />

13
packages/nc-gui-v2/components/smartsheet/sidebar/index.vue

@ -3,7 +3,7 @@ import type { FormType, GalleryType, GridType, KanbanType, ViewTypes } from 'noc
import MenuTop from './MenuTop.vue' import MenuTop from './MenuTop.vue'
import MenuBottom from './MenuBottom.vue' import MenuBottom from './MenuBottom.vue'
import Toolbar from './toolbar/index.vue' import Toolbar from './toolbar/index.vue'
import { computed, inject, provide, ref, useRoute, useRouter, useViews, watch } from '#imports' import { computed, inject, provide, ref, useElementHover, useRoute, useRouter, useViews, watch } from '#imports'
import { ActiveViewInj, MetaInj, RightSidebarInj, ViewListInj } from '~/context' import { ActiveViewInj, MetaInj, RightSidebarInj, ViewListInj } from '~/context'
const meta = inject(MetaInj, ref()) const meta = inject(MetaInj, ref())
@ -25,6 +25,9 @@ const sidebarOpen = inject(RightSidebarInj, ref(true))
const sidebarCollapsed = computed(() => !sidebarOpen.value) const sidebarCollapsed = computed(() => !sidebarOpen.value)
/** Sidebar ref */
const sidebar = ref()
/** View type to create from modal */ /** View type to create from modal */
let viewCreateType = $ref<ViewTypes>() let viewCreateType = $ref<ViewTypes>()
@ -37,6 +40,8 @@ let selectedViewId = $ref('')
/** is view creation modal open */ /** is view creation modal open */
let modalOpen = $ref(false) let modalOpen = $ref(false)
const isHovered = useElementHover(sidebar)
/** Watch route param and change active view based on `viewTitle` */ /** Watch route param and change active view based on `viewTitle` */
watch( watch(
[views, () => route.params.viewTitle], [views, () => route.params.viewTitle],
@ -74,6 +79,7 @@ function onCreate(view: GridType | FormType | KanbanType | GalleryType) {
<template> <template>
<a-layout-sider <a-layout-sider
ref="sidebar"
:collapsed="sidebarCollapsed" :collapsed="sidebarCollapsed"
collapsiple collapsiple
collapsed-width="50" collapsed-width="50"
@ -81,10 +87,12 @@ function onCreate(view: GridType | FormType | KanbanType | GalleryType) {
class="relative shadow-md h-full" class="relative shadow-md h-full"
theme="light" theme="light"
> >
<a-tooltip placement="left"> <a-tooltip :mouse-enter-delay="1" placement="left">
<template #title> Toggle sidebar </template> <template #title> Toggle sidebar </template>
<Transition name="glow">
<div <div
v-show="sidebarCollapsed || isHovered"
class="group color-transition cursor-pointer hover:ring active:ring-pink-500 z-1 flex items-center p-[1px] absolute top-1/2 left-[-1rem] shadow bg-gray-100 rounded-full" class="group color-transition cursor-pointer hover:ring active:ring-pink-500 z-1 flex items-center p-[1px] absolute top-1/2 left-[-1rem] shadow bg-gray-100 rounded-full"
> >
<MaterialSymbolsChevronRightRounded <MaterialSymbolsChevronRightRounded
@ -99,6 +107,7 @@ function onCreate(view: GridType | FormType | KanbanType | GalleryType) {
@click="sidebarOpen = true" @click="sidebarOpen = true"
/> />
</div> </div>
</Transition>
</a-tooltip> </a-tooltip>
<Toolbar v-if="sidebarOpen" class="flex items-center py-3 px-3 justify-between border-b-1" /> <Toolbar v-if="sidebarOpen" class="flex items-center py-3 px-3 justify-between border-b-1" />

2
packages/nc-gui-v2/components/smartsheet/sidebar/menu/ApiSnippet.vue

@ -172,5 +172,3 @@ const afterVisibleChange = (visible: boolean) => {
</div> </div>
</a-drawer> </a-drawer>
</template> </template>
<style scoped></style>

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

@ -34,7 +34,7 @@ provide(ActiveViewInj, activeView)
provide(IsLockedInj, false) provide(IsLockedInj, false)
provide(ReloadViewDataHookInj, reloadEventHook) provide(ReloadViewDataHookInj, reloadEventHook)
provide(FieldsInj, fields) provide(FieldsInj, fields)
provide(RightSidebarInj, ref(true)) provide(RightSidebarInj, ref(false))
const { isGallery, isGrid, isForm } = useProvideSmartsheetStore(activeView as Ref<TableType>, meta) const { isGallery, isGrid, isForm } = useProvideSmartsheetStore(activeView as Ref<TableType>, meta)

23
packages/nc-gui-v2/composables/useUIPermission/index.ts

@ -1,14 +1,15 @@
import type { Permission } from './rolePermissions' import type { Permission } from './rolePermissions'
import rolePermissions from './rolePermissions' import rolePermissions from './rolePermissions'
import { USER_PROJECT_ROLES, useNuxtApp, useState } from '#imports' import { USER_PROJECT_ROLES, useGlobal, useState } from '#imports'
export function useUIPermission() { export function useUIPermission() {
const { $state } = useNuxtApp() const { user, previewAs } = useGlobal()
const projectRoles = useState<Record<string, boolean>>(USER_PROJECT_ROLES, () => ({})) const projectRoles = useState<Record<string, boolean>>(USER_PROJECT_ROLES, () => ({}))
const isUIAllowed = (permission: Permission | string, skipPreviewAs = false) => { const getRoles = (skipPreviewAs = false) => {
const user = $state.user let userRoles = user.value?.roles || {}
let userRoles = user?.value?.roles || {}
// if string populate key-value paired object // if string populate key-value paired object
if (typeof userRoles === 'string') { if (typeof userRoles === 'string') {
userRoles = userRoles.split(',').reduce<Record<string, boolean>>((acc, role) => { userRoles = userRoles.split(',').reduce<Record<string, boolean>>((acc, role) => {
@ -20,16 +21,20 @@ export function useUIPermission() {
// merge user role and project specific user roles // merge user role and project specific user roles
let roles = { let roles = {
...userRoles, ...userRoles,
...(projectRoles?.value || {}), ...projectRoles.value,
} }
if ($state.previewAs.value && !skipPreviewAs) { if (previewAs.value && !skipPreviewAs) {
roles = { roles = {
[$state.previewAs.value]: true, [previewAs.value]: true,
} }
} }
return Object.entries<boolean>(roles).some(([role, hasRole]) => { return roles
}
const isUIAllowed = (permission: Permission | string, skipPreviewAs = false) => {
return Object.entries<boolean>(getRoles(skipPreviewAs)).some(([role, hasRole]) => {
const rolePermission = rolePermissions[role as keyof typeof rolePermissions] as '*' | Record<Permission, true> const rolePermission = rolePermissions[role as keyof typeof rolePermissions] as '*' | Record<Permission, true>
return hasRole && (rolePermission === '*' || rolePermission?.[permission as Permission]) return hasRole && (rolePermission === '*' || rolePermission?.[permission as Permission])

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

@ -51,6 +51,9 @@ export default defineNuxtConfig({
// todo: minifiy again // todo: minifiy again
build: { build: {
minify: false, minify: false,
rollupOptions: {
external: 'httpsnippet',
},
}, },
css: { css: {
preprocessorOptions: { preprocessorOptions: {

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

@ -1,7 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { navigateTo, onKeyStroke, provideSidebar, ref, useProject, useRoute, useTabs, useUIPermission } from '#imports' import {
navigateTo,
onKeyStroke,
openLink,
provideSidebar,
ref,
useElementHover,
useProject,
useRoute,
useTabs,
useUIPermission,
} from '#imports'
import { TabType } from '~/composables' import { TabType } from '~/composables'
import { openLink } from '~/utils'
const route = useRoute() const route = useRoute()
@ -20,6 +30,9 @@ const openDialogKey = ref<string>()
const dropdownOpen = ref(false) const dropdownOpen = ref(false)
/** Sidebar ref */
const sidebar = ref()
onKeyStroke( onKeyStroke(
'Escape', 'Escape',
() => { () => {
@ -42,12 +55,15 @@ function toggleDialog(value?: boolean, key?: string) {
await loadProject() await loadProject()
await loadTables() await loadTables()
const isHovered = useElementHover(sidebar)
</script> </script>
<template> <template>
<NuxtLayout id="content" class="flex"> <NuxtLayout id="content" class="flex">
<template #sidebar> <template #sidebar>
<a-layout-sider <a-layout-sider
ref="sidebar"
:collapsed="!isOpen" :collapsed="!isOpen"
width="250" width="250"
collapsed-width="50" collapsed-width="50"
@ -56,7 +72,11 @@ await loadTables()
collapsible collapsible
theme="light" theme="light"
> >
<div style="height: var(--header-height)" class="flex items-center !bg-primary text-white px-1 pl-5 gap-2"> <div
style="height: var(--header-height)"
:class="isOpen ? 'pl-6' : ''"
class="flex items-center !bg-primary text-white px-1 gap-2"
>
<div <div
v-if="isOpen && !isSharedBase" v-if="isOpen && !isSharedBase"
class="w-[40px] min-w-[40px] transition-all duration-200 p-1 cursor-pointer transform hover:scale-105" class="w-[40px] min-w-[40px] transition-all duration-200 p-1 cursor-pointer transform hover:scale-105"
@ -64,6 +84,7 @@ await loadTables()
> >
<img alt="NocoDB" src="~/assets/img/icons/512x512-trans.png" /> <img alt="NocoDB" src="~/assets/img/icons/512x512-trans.png" />
</div> </div>
<a <a
v-if="isOpen && isSharedBase" v-if="isOpen && isSharedBase"
class="w-[40px] min-w-[40px] transition-all duration-200 p-1 cursor-pointer transform hover:scale-105" class="w-[40px] min-w-[40px] transition-all duration-200 p-1 cursor-pointer transform hover:scale-105"
@ -77,6 +98,7 @@ await loadTables()
<template v-if="isOpen"> <template v-if="isOpen">
<div class="text-xl font-semibold truncate">{{ project.title }}</div> <div class="text-xl font-semibold truncate">{{ project.title }}</div>
</template> </template>
<template v-else> <template v-else>
<MdiFolder class="text-primary cursor-pointer transform hover:scale-105 text-2xl" /> <MdiFolder class="text-primary cursor-pointer transform hover:scale-105 text-2xl" />
</template> </template>
@ -111,6 +133,7 @@ await loadTables()
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<div class="group-hover:(!text-primary)">ID:</div> <div class="group-hover:(!text-primary)">ID:</div>
<div class="text-xs group-hover:text-pink-500 truncate font-italic">{{ project.id }}</div> <div class="text-xs group-hover:text-pink-500 truncate font-italic">{{ project.id }}</div>
</div> </div>
</div> </div>
@ -212,10 +235,12 @@ await loadTables()
</a-dropdown> </a-dropdown>
</div> </div>
<a-tooltip placement="right"> <a-tooltip :mouse-enter-delay="1" placement="right">
<template #title> Toggle table list </template> <template #title> Toggle table list </template>
<Transition name="glow">
<div <div
v-show="!isOpen || isHovered"
class="group color-transition cursor-pointer hover:ring active:ring-pink-500 z-1 flex items-center absolute top-1/2 right-[-0.75rem] shadow bg-gray-100 rounded-full" class="group color-transition cursor-pointer hover:ring active:ring-pink-500 z-1 flex items-center absolute top-1/2 right-[-0.75rem] shadow bg-gray-100 rounded-full"
> >
<MaterialSymbolsChevronLeftRounded <MaterialSymbolsChevronLeftRounded
@ -230,6 +255,7 @@ await loadTables()
@click="toggle(true)" @click="toggle(true)"
/> />
</div> </div>
</Transition>
</a-tooltip> </a-tooltip>
<DashboardTreeView v-show="isOpen" /> <DashboardTreeView v-show="isOpen" />
@ -237,6 +263,7 @@ await loadTables()
</template> </template>
<dashboard-settings-modal v-model="dialogOpen" :open-key="openDialogKey" /> <dashboard-settings-modal v-model="dialogOpen" :open-key="openDialogKey" />
<NuxtPage /> <NuxtPage />
<GeneralPreviewAs float /> <GeneralPreviewAs float />

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

@ -1,8 +1,17 @@
<script lang="ts" setup> <script lang="ts" setup>
import { Modal, message } from 'ant-design-vue' import { Modal, message } from 'ant-design-vue'
import type { ProjectType } from 'nocodb-sdk' import type { ProjectType } from 'nocodb-sdk'
import { computed, navigateTo, onMounted, ref, useApi, useNuxtApp, useSidebar } from '#imports' import {
import { extractSdkResponseErrorMsg } from '~/utils' computed,
extractSdkResponseErrorMsg,
navigateTo,
onMounted,
ref,
useApi,
useNuxtApp,
useSidebar,
useUIPermission,
} from '#imports'
const { $e } = useNuxtApp() const { $e } = useNuxtApp()
@ -54,11 +63,14 @@ onMounted(() => {
<template> <template>
<NuxtLayout> <NuxtLayout>
<a-row> <div class="flex flex-col md:flex-row flex-wrap gap-6 py-6 px-12">
<a-col :span="8"></a-col> <div class="hidden xl:(block)">
<a-col :span="8" class="!bg-red"> <GeneralSponsors />
<a-card :loading="isLoading" class="mx-auto mt-10 !max-w-[600px] shadow-lg"> </div>
<h1 class="text-center text-4xl pa-2 nc-project-page-title flex align-center justify-center gap-2 text-gray-600">
<div class="min-w-2/4 flex-auto">
<a-card :loading="isLoading" class="!rounded-lg shadow">
<h1 class="text-center text-4xl p-2 nc-project-page-title flex items-center justify-center gap-2 text-gray-600">
<!-- My Projects --> <!-- My Projects -->
<b>{{ $t('title.myProject') }}</b> <b>{{ $t('title.myProject') }}</b>
@ -66,16 +78,17 @@ onMounted(() => {
v-t="['a:project:refresh']" v-t="['a:project:refresh']"
class="text-sm text-gray-500 hover:text-primary mt-1 cursor-pointer" class="text-sm text-gray-500 hover:text-primary mt-1 cursor-pointer"
@click="loadProjects" @click="loadProjects"
></MdiRefresh> />
</h1> </h1>
<div class="flex mb-6"> <div class="order-1 flex mb-6">
<a-input-search <a-input-search
v-model:value="filterQuery" v-model:value="filterQuery"
class="max-w-[200px] nc-project-page-search" class="max-w-[200px] nc-project-page-search"
:placeholder="$t('activity.searchProject')" :placeholder="$t('activity.searchProject')"
></a-input-search> />
<div class="flex-grow"></div>
<div class="flex-grow" />
<a-dropdown v-if="isUIAllowed('projectCreate', true)" @click.stop> <a-dropdown v-if="isUIAllowed('projectCreate', true)" @click.stop>
<a-button class="nc-new-project-menu !shadow"> <a-button class="nc-new-project-menu !shadow">
@ -93,14 +106,17 @@ onMounted(() => {
@click="navigateTo('/project/create')" @click="navigateTo('/project/create')"
> >
<MdiPlus class="col-span-2 mr-1 mt-[1px] text-primary text-lg" /> <MdiPlus class="col-span-2 mr-1 mt-[1px] text-primary text-lg" />
<div class="col-span-10 text-sm xl:text-md">{{ $t('activity.createProject') }}</div> <div class="col-span-10 text-sm xl:text-md">{{ $t('activity.createProject') }}</div>
</div> </div>
<div <div
v-t="['c:project:create:extdb']" v-t="['c:project:create:extdb']"
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2 nc-create-external-db-project" class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2 nc-create-external-db-project"
@click="navigateTo('/project/create-external')" @click="navigateTo('/project/create-external')"
> >
<MdiDatabaseOutline class="col-span-2 mr-1 mt-[1px] text-green-500 text-lg" /> <MdiDatabaseOutline class="col-span-2 mr-1 mt-[1px] text-green-500 text-lg" />
<div class="col-span-10 text-sm xl:text-md" v-html="$t('activity.createProjectExtended.extDB')" /> <div class="col-span-10 text-sm xl:text-md" v-html="$t('activity.createProjectExtended.extDB')" />
</div> </div>
</a-menu> </a-menu>
@ -151,16 +167,16 @@ onMounted(() => {
</a-table-column> </a-table-column>
</a-table> </a-table>
</a-card> </a-card>
</a-col>
<a-col :span="8" class="">
<div class="justify-end flex">
<GeneralSponsors />
</div> </div>
<div class="justify-end flex">
<div class="flex gap-6 md:block">
<GeneralSocialCard /> <GeneralSocialCard />
<div class="block mt-0 md:(!mt-6) xl:hidden">
<GeneralSponsors />
</div>
</div>
</div> </div>
</a-col>
</a-row>
</NuxtLayout> </NuxtLayout>
</template> </template>

Loading…
Cancel
Save