Browse Source

Merge pull request #2722 from nocodb/feat/user-settings

feat(gui-v2): add user settings page
pull/2728/head
Pranav C 2 years ago committed by GitHub
parent
commit
a74b9c8e68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 145
      packages/nc-gui-v2/app.vue
  2. 36
      packages/nc-gui-v2/assets/style-v2.scss
  3. 9
      packages/nc-gui-v2/components.d.ts
  4. 12
      packages/nc-gui-v2/components/general/Language.vue
  5. 6
      packages/nc-gui-v2/components/general/Sponsors.vue
  6. 10
      packages/nc-gui-v2/layouts/default.vue
  7. 13
      packages/nc-gui-v2/pages/index.vue
  8. 0
      packages/nc-gui-v2/pages/index/create-external.vue
  9. 0
      packages/nc-gui-v2/pages/index/create.vue
  10. 123
      packages/nc-gui-v2/pages/index/index.vue
  11. 4
      packages/nc-gui-v2/pages/index/index/index.vue
  12. 0
      packages/nc-gui-v2/pages/index/index/list.vue
  13. 42
      packages/nc-gui-v2/pages/index/user/index.vue
  14. 140
      packages/nc-gui-v2/pages/index/user/index/index.vue
  15. 133
      packages/nc-gui-v2/pages/projects/index.vue
  16. 2
      packages/nc-gui-v2/pages/signin.vue
  17. 2
      packages/nc-gui-v2/pages/signup.vue
  18. 5
      packages/nc-gui-v2/windi.config.ts

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

@ -12,81 +12,92 @@ const signOut = () => {
$state.signOut()
navigateTo('/signin')
}
const toggleSidebar = useToggle($state.sidebarOpen)
const sidebarOpen = computed({
get: () => $state.sidebarOpen.value ?? true,
set: (val) => toggleSidebar(val),
})
</script>
<template>
<v-app>
<v-app-bar class="shadow-md bg-primary" height="48">
<div class="flex items-center flex-1">
<v-toolbar-title>
<v-tooltip bottom>
{{ $t('general.home') }}
<span class="caption font-weight-light pointer">(version)</span>
</v-tooltip>
<span class="body-1" @click="navigateTo('/projects')">NocoDB</span>
</v-toolbar-title>
<a-layout>
<a-layout-header class="flex !bg-primary items-center text-white !px-4">
<MaterialSymbolsMenu
v-if="$state.signedIn.value"
class="text-xl cursor-pointer"
@click="toggleSidebar(!$state.sidebarOpen.value)"
/>
<div class="flex-1" />
<div class="ml-4 flex items-center flex-1">
<div class="flex items-center gap-2">
<img width="35" src="~/assets/img/icons/512x512-trans.png" />
<span class="prose-xl" @click="navigateTo('/')">NocoDB</span>
</div>
<!-- todo: loading is not yet supported by nuxt 3 - see https://v3.nuxtjs.org/migration/component-options#loading
<span v-show="$nuxt.$loading.show" class="caption grey--text ml-3">
{{ $t('general.loading') }} <v-icon small color="grey">mdi-spin mdi-loading</v-icon>
</span>
<span v-show="$nuxt.$loading.show" class="caption grey--text ml-3">
{{ $t('general.loading') }} <v-icon small color="grey">mdi-spin mdi-loading</v-icon>
</span>
todo: replace shortkey?
<span v-shortkey="['ctrl', 'shift', 'd']" @shortkey="openDiscord" />
-->
todo: replace shortkey?
<span v-shortkey="['ctrl', 'shift', 'd']" @shortkey="openDiscord" />
-->
</div>
<div class="flex justify-end">
<v-toolbar-items class="flex gap-4 nc-topright-menu">
<!-- todo: implement components
<release-info />
-->
<general-color-mode-switcher v-model="$state.darkMode.value" />
<general-language class="mr-3" />
<MaterialSymbolsMenu
v-if="$state.signedIn.value"
class="block text-xl cursor-pointer xl:(hidden)"
@click="$state.sidebarOpen.value = !$state.sidebarOpen.value"
/>
<template v-if="$state.signedIn.value">
<v-menu class="leading-8">
<template #activator="{ props }">
<MdiDotsVertical class="md:text-xl cursor-pointer" @click="props.onClick" />
</template>
<v-list class="!py-0 nc-user-menu min-w-32 dark:(!bg-gray-800)">
<nuxt-link
v-t="['c:navbar:user:email']"
class="group hover:(bg-gray-200) dark:(hover:bg-gray-600) flex items-center p-2 no-underline"
to="/user/settings"
>
<MdiAt class="mt-1 group-hover:text-success" />&nbsp;
<span class="prose">{{ email }}</span>
</nuxt-link>
<v-divider />
<div
v-t="['a:navbar:user:sign-out']"
class="group flex flex-row cursor-pointer hover:bg-gray-200 dark:(hover:bg-gray-600) flex items-center p-2"
@click="signOut"
>
<MdiLogout class="dark:text-white group-hover:(!text-red-500)" />&nbsp;
<span class="prose font-semibold text-gray-500">{{ $t('general.signOut') }}</span>
</div>
</v-list>
</v-menu>
</template>
</v-toolbar-items>
<div class="flex-1" />
<div class="flex justify-end gap-4">
<general-color-mode-switcher v-model="$state.darkMode.value" />
<general-language class="mr-3" />
<template v-if="$state.signedIn.value">
<a-dropdown :trigger="['click']">
<MdiDotsVertical class="md:text-xl cursor-pointer" @click.prevent />
<template #overlay>
<a-menu class="!py-0 nc-user-menu min-w-32 dark:(!bg-gray-800) leading-8 !rounded">
<a-menu-item key="0" class="!rounded">
<nuxt-link v-t="['c:navbar:user:email']" class="group flex items-center no-underline py-2" to="/user">
<MdiAt class="mt-1 group-hover:text-success" />&nbsp;
<span class="prose">{{ email }}</span>
</nuxt-link>
</a-menu-item>
<a-menu-divider class="!m-0" />
<a-menu-item key="1" class="!rounded">
<div v-t="['a:navbar:user:sign-out']" class="group flex items-center py-2" @click="signOut">
<MdiLogout class="dark:text-white group-hover:(!text-red-500)" />&nbsp;
<span class="prose font-semibold text-gray-500">{{ $t('general.signOut') }}</span>
</div>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
</div>
</v-app-bar>
<NuxtPage />
</v-app>
</a-layout-header>
<a-layout>
<a-layout-sider
v-model:collapsed="sidebarOpen"
width="300"
breakpoint="md"
collapsed-width="0"
class="bg-white dark:!bg-gray-800 border-r-1 border-gray-200 dark:!border-gray-600 h-full"
:trigger="null"
collapsible
>
<div id="sidebar" class="w-full h-full" />
</a-layout-sider>
<NuxtPage />
</a-layout>
</a-layout>
</template>

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

@ -1,28 +1,19 @@
html,
body,
#__nuxt,
.v-application__wrap {
@apply color-transition m-0 h-full w-full bg-white dark:(bg-black text-white);
.ant-layout,
main {
@apply m-0 h-full w-full bg-white dark:(bg-black text-white);
}
a, button {
@apply color-transition;
}
.v-main {
@apply w-full h-full;
overflow: hidden;
flex: unset !important;
}
.v-main .v-main__wrap {
main {
@apply flex-0 w-full relative scrollbar-thin-primary;
overflow-x: hidden;
}
nav,
nav .v-list {
@apply color-transition dark:(bg-gray-900 text-white)
@apply dark:(!bg-gray-900 text-white)
}
.v-divider {
@ -43,8 +34,23 @@ nav .v-list {
@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 {
@apply cursor-pointer 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);
}
h1, h2, h3, h4, h5, h6 {
@apply text-black dark:(text-white);
}
.v-field__field {

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

@ -7,6 +7,15 @@ export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
ALayout: typeof import('ant-design-vue/es')['Layout']
ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader']
ALayoutSider: typeof import('ant-design-vue/es')['LayoutSider']
AMenu: typeof import('ant-design-vue/es')['Menu']
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
ATable: typeof import('ant-design-vue/es')['Table']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']

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

@ -38,18 +38,18 @@ onMounted(() => {
<template #activator="{ props }">
<MaterialSymbolsTranslate class="md:text-xl cursor-pointer" @click="props.onClick" />
</template>
<v-list class="min-w-50 max-h-90vh overflow-auto !py-0 scrollbar-thin-primary">
<v-list class="scrollbar min-w-50 max-h-90vh overflow-auto !py-0 dark:(!bg-gray-800 !text-white)">
<v-list-item
v-for="lang of languages"
:key="lang.value"
:class="lang === locale ? '!bg-primary/10 text-primary' : ''"
:class="lang === locale ? '!bg-primary/10 text-primary dark:(!bg-gray-700 !text-secondary)' : ''"
class="!min-h-8 group"
:value="lang"
@click="changeLanguage(lang)"
>
<v-list-item-subtitle
:class="lang === locale ? '!font-semibold' : ''"
class="capitalize md:(!leading-8) group-hover:(text-primary font-semibold)"
class="capitalize md:(!leading-8) group-hover:(text-primary font-semibold) dark:(group-hover:text-secondary)"
>
{{ Language[lang] || lang }}
</v-list-item-subtitle>
@ -69,3 +69,9 @@ onMounted(() => {
</v-list>
</v-menu>
</template>
<style scoped>
.scrollbar {
@apply scrollbar scrollbar-thin scrollbar-thumb-rounded scrollbar-thumb-primary scrollbar-track-white dark:(!scrollbar-track-gray-900);
}
</style>

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

@ -28,3 +28,9 @@ const { nav = false } = defineProps<Props>()
</v-card-actions>
</v-card>
</template>
<style>
a img {
margin: 0 !important;
}
</style>

10
packages/nc-gui-v2/layouts/default.vue

@ -18,11 +18,11 @@ export default {
</script>
<template>
<v-main>
<slot name="sidebar">
<div id="sidebar" />
</slot>
<a-layout-content>
<teleport v-if="$slots.sidebar" to="#sidebar">
<slot name="sidebar" />
</teleport>
<slot />
</v-main>
</a-layout-content>
</template>

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

@ -1,13 +0,0 @@
<script setup lang="ts">
import { useRouter } from '#app'
const router = useRouter()
router.replace('/projects')
</script>
<template>
<div class="container" />
</template>
<style lang="scss"></style>

0
packages/nc-gui-v2/pages/projects/create-external.vue → packages/nc-gui-v2/pages/index/create-external.vue

0
packages/nc-gui-v2/pages/projects/create.vue → packages/nc-gui-v2/pages/index/create.vue

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

@ -0,0 +1,123 @@
<script lang="ts" setup>
import { navigateTo } from '#app'
import MaterialSymbolsFormatListBulletedRounded from '~icons/material-symbols/format-list-bulleted-rounded'
import MaterialSymbolsGridView from '~icons/material-symbols/grid-view'
import MdiPlus from '~icons/mdi/plus'
import MdiDatabaseOutline from '~icons/mdi/database-outline'
import MdiFolderOutline from '~icons/mdi/folder-outline'
import MdiAccountGroup from '~icons/mdi/account-group'
import MdiClockOutline from '~icons/mdi/clock-outline'
import MdiStar from '~icons/mdi/star'
const navDrawerOptions = [
{
title: 'My NocoDB',
icon: MdiFolderOutline,
},
{
title: 'Shared With Me',
icon: MdiAccountGroup,
},
{
title: 'Recent',
icon: MdiClockOutline,
},
{
title: 'Starred',
icon: MdiStar,
},
]
const route = useRoute()
const { $api, $state } = useNuxtApp()
const response = await $api.project.list({})
const projects = $ref(response.list)
const activePage = $ref(navDrawerOptions[0].title)
</script>
<template>
<NuxtLayout>
<template #sidebar>
<div class="flex flex-col h-full">
<div class="flex p-4">
<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"
@click="props.onClick"
>
<MdiPlus class="text-primary dark:(!text-white) text-2xl" />
{{ $t('title.newProj') }}
</div>
</template>
<v-list class="!py-0 flex flex-col bg-white rounded-lg shadow-md border-1 border-gray-300 mt-2 ml-2">
<div
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2"
@click="navigateTo('/create')"
>
<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>
<div
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2"
@click="navigateTo('/create-external')"
>
<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>
</v-list>
</v-menu>
</div>
<a-menu class="mx-4 dark:bg-gray-800 dark:text-white flex-1 border-0">
<a-menu-item
v-for="(option, index) in navDrawerOptions"
:key="index"
class="f!rounded-r-lg"
@click="activePage = option.title"
>
<div class="flex items-center gap-4">
<component :is="option.icon" />
<span class="font-semibold">
{{ option.title }}
</span>
</div>
</a-menu-item>
</a-menu>
<general-social />
<general-sponsors :nav="true" />
</div>
</template>
<v-container 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">
{{ activePage }}
</div>
<div class="self-end flex text-4xl mb-1">
<MaterialSymbolsGridView
:class="route.name === 'index-index' ? 'text-primary dark:(!text-secondary/75)' : ''"
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="cursor-pointer p-2 hover:bg-gray-300/50 rounded-full"
@click="navigateTo('/list')"
/>
</div>
</div>
<v-divider class="!mb-4 lg:(!mb-8)" />
<NuxtPage :projects="projects" />
</v-container>
</NuxtLayout>
</template>

4
packages/nc-gui-v2/pages/projects/index/index.vue → packages/nc-gui-v2/pages/index/index/index.vue

@ -50,14 +50,14 @@ const formatTitle = (title: string) =>
<v-list class="!py-0 flex flex-col bg-white rounded-lg shadow-md border-1 border-gray-300 mt-2 ml-2">
<div
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2"
@click="navigateTo('/projects/create')"
@click="navigateTo('/create')"
>
<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>
<div
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2"
@click="navigateTo('/projects/create-external')"
@click="navigateTo('/create-external')"
>
<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')" />

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

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

@ -0,0 +1,42 @@
<script setup lang="ts">
import { useNuxtApp, useRoute } from '#app'
import MdiAccountCog from '~icons/mdi/account-cog'
const { $api, $state } = useNuxtApp()
const route = useRoute()
</script>
<template>
<NuxtLayout>
<template #sidebar>
<v-navigation-drawer v-model="$state.sidebarOpen.value" :border="0">
<div class="flex flex-col h-full">
<div class="advance-menu flex-1">
<v-list class="flex flex-col gap-1" :color="$state.darkMode.value ? 'secondary' : 'primary'">
<v-list-item
:active="route.name === 'index-user-index'"
class="flex items-center gap-4 !rounded-r-lg"
:value="$t('activity.settings')"
>
<MdiAccountCog />
<span class="font-semibold">
{{ $t('activity.settings') }}
</span>
</v-list-item>
</v-list>
</div>
<v-divider />
<general-social />
<general-sponsors :nav="true" />
</div>
</v-navigation-drawer>
</template>
<NuxtPage />
</NuxtLayout>
</template>

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

@ -0,0 +1,140 @@
<script lang="ts" setup>
import { useI18n } from 'vue-i18n'
import { extractSdkResponseErrorMsg } from '~/utils/errorUtils'
import { navigateTo, useNuxtApp } from '#app'
import { isEmail } from '~/utils/validation'
import MaterialSymbolsWarning from '~icons/material-symbols/warning'
import MaterialSymbolsRocketLaunchOutline from '~icons/material-symbols/rocket-launch-outline'
import { reactive, ref } from '#imports'
const { $api, $state } = useNuxtApp()
const { t } = useI18n()
const valid = ref()
let error = $ref<string | null>(null)
const form = reactive({
currentPassword: '',
password: '',
passwordRepeat: '',
})
const formRules = {
currentPassword: [
(v: string) => !!v || t('msg.error.signUpRules.passwdRequired'),
// E-mail must be valid format
(v: string) => isEmail(v) || t('msg.error.signUpRules.emailInvalid'),
],
password: [
// Password is required
(v: string) => !!v || t('msg.error.signUpRules.passwdRequired'),
(v: string) => v.length >= 8 || t('msg.error.signUpRules.passwdLength'),
],
passwordRepeat: [
// Passwords match
(v: string) => v === form.password || t('msg.error.signUpRules.passwdMismatch'),
],
}
const passwordChange = async () => {
error = null
try {
const { msg } = await $api.auth.passwordChange(form)
console.log(msg)
} catch (e: any) {
error = await extractSdkResponseErrorMsg(e)
}
}
const resetError = () => {
if (error) {
error = null
}
}
</script>
<template>
<v-form
ref="formValidator"
v-model="valid"
class="h-[calc(100%_+_180px)] min-h-[600px] flex justify-center items-center"
@submit.prevent="passwordChange"
>
<div class="h-full w-full flex flex-col flex-wrap justify-center items-center">
<div
class="dark:(md:bg-gray-900 !text-white) md: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)"
>
<div
style="left: -moz-calc(50% - 45px); left: -webkit-calc(50% - 45px); left: calc(50% - 45px)"
class="absolute top-12 md:top-[-10%] rounded-lg bg-primary"
>
<img width="90" height="90" src="~/assets/img/icons/512x512-trans.png" />
</div>
<h1 class="prose-2xl font-bold self-center my-4">{{ $t('general.signUp') }}</h1>
<Transition name="layout">
<div v-if="error" class="self-center mb-4 bg-red-500 text-white rounded-lg w-3/4 p-1">
<div class="flex items-center gap-2 justify-center"><MaterialSymbolsWarning /> {{ error }}</div>
</div>
</Transition>
<v-text-field
id="email"
v-model="form.email"
class="bg-white dark:!bg-gray-900"
:rules="formRules.email"
:label="$t('labels.email')"
:placeholder="$t('labels.email')"
:persistent-placeholder="true"
type="text"
@focus="resetError"
/>
<v-text-field
id="password"
v-model="form.password"
class="bg-white dark:!bg-gray-900"
:rules="formRules.password"
:label="$t('labels.password')"
:placeholder="$t('labels.password')"
:persistent-placeholder="true"
type="password"
@focus="resetError"
/>
<v-text-field
id="password_repeat"
v-model="form.passwordRepeat"
class="bg-white dark:!bg-gray-900"
:rules="formRules.passwordRepeat"
:label="`Repeat ${$t('labels.password')}`"
:placeholder="`Repeat ${$t('labels.password')}`"
:persistent-placeholder="true"
type="password"
@focus="resetError"
/>
<div class="self-center flex flex-wrap gap-4 items-center mt-4 md:mx-8 md:justify-between justify-center w-full">
<button
:disabled="!valid"
:class="[
!valid
? '!opacity-50 !cursor-default'
: 'shadow-md hover:(text-primary bg-primary/10 dark:text-white dark:!bg-primary/50)',
]"
class="ml-1 border-1 border-solid border-gray-300 color-transition rounded-lg p-4 bg-gray-100/50"
type="submit"
>
<span class="flex items-center gap-2"><MaterialSymbolsRocketLaunchOutline /> {{ $t('general.signUp') }}</span>
</button>
<div class="text-end prose-sm">
{{ $t('msg.info.signUp.alreadyHaveAccount') }}
<nuxt-link to="/signin">{{ $t('general.signIn') }}</nuxt-link>
</div>
</div>
</div>
</div>
</v-form>
</template>

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

@ -1,133 +0,0 @@
<script lang="ts" setup>
import { navigateTo } from '#app'
import MaterialSymbolsFormatListBulletedRounded from '~icons/material-symbols/format-list-bulleted-rounded'
import MaterialSymbolsGridView from '~icons/material-symbols/grid-view'
import MdiPlus from '~icons/mdi/plus'
import MdiDatabaseOutline from '~icons/mdi/database-outline'
import MdiFolderOutline from '~icons/mdi/folder-outline'
import MdiAccountGroup from '~icons/mdi/account-group'
import MdiClockOutline from '~icons/mdi/clock-outline'
import MdiStar from '~icons/mdi/star'
const navDrawerOptions = [
{
title: 'My NocoDB',
icon: MdiFolderOutline,
},
{
title: 'Shared With Me',
icon: MdiAccountGroup,
},
{
title: 'Recent',
icon: MdiClockOutline,
},
{
title: 'Starred',
icon: MdiStar,
},
]
const route = useRoute()
const { $api, $state } = useNuxtApp()
const response = await $api.project.list({})
const projects = $ref(response.list)
const activePage = $ref(navDrawerOptions[0].title)
</script>
<template>
<NuxtLayout>
<template #sidebar>
<v-navigation-drawer v-model="$state.sidebarOpen.value" :border="0">
<div class="flex flex-col h-full">
<div class="flex p-4">
<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"
@click="props.onClick"
>
<MdiPlus class="text-primary dark:(!text-white) text-2xl" />
{{ $t('title.newProj') }}
</div>
</template>
<v-list class="!py-0 flex flex-col bg-white rounded-lg shadow-md border-1 border-gray-300 mt-2 ml-2">
<div
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2"
@click="navigateTo('/projects/create')"
>
<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>
<div
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2"
@click="navigateTo('/projects/create-external')"
>
<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>
</v-list>
</v-menu>
</div>
<div class="advance-menu flex-1">
<v-list class="flex flex-col gap-1" :color="$state.darkMode.value ? 'secondary' : 'primary'">
<!-- todo: v-list-item-group doesn't seem to work with vuetify 3 yet ... -->
<v-list-item
v-for="item in navDrawerOptions"
:key="item.title"
class="flex items-center gap-4 !rounded-r-lg"
:value="item.title"
>
<component :is="item.icon" />
<span
class="font-semibold"
:class="{
'textColor--text text--lighten-2': item.title !== activePage,
}"
>
{{ item.title }}
</span>
</v-list-item>
</v-list>
</div>
<v-divider />
<general-social />
<general-sponsors :nav="true" />
</div>
</v-navigation-drawer>
</template>
<v-container 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">
{{ activePage }}
</div>
<div class="self-end flex text-4xl mb-1">
<MaterialSymbolsGridView
:class="route.name === 'projects-index' ? 'text-primary dark:(!text-secondary/75)' : ''"
class="cursor-pointer p-2 hover:bg-gray-300/50 rounded-full"
@click="navigateTo('/projects')"
/>
<MaterialSymbolsFormatListBulletedRounded
:class="route.name === 'projects-index-list' ? 'text-primary dark:(!text-secondary/75)' : ''"
class="cursor-pointer p-2 hover:bg-gray-300/50 rounded-full"
@click="navigateTo('/projects/list')"
/>
</div>
</div>
<v-divider class="!mb-4 lg:(!mb-8)" />
<NuxtPage :projects="projects" />
</v-container>
</NuxtLayout>
</template>

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

@ -55,7 +55,7 @@ const signIn = async () => {
try {
const { token } = await $api.auth.signin(form)
$state.signIn(token!)
await navigateTo('/projects')
await navigateTo('/')
} catch (e: any) {
// todo: errors should not expose what was wrong (i.e. do not show "Password is wrong" messages)
error = await extractSdkResponseErrorMsg(e)

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

@ -46,7 +46,7 @@ const signUp = async () => {
try {
const { token } = await $api.auth.signup(form)
$state.signIn(token!)
await navigateTo('/projects')
await navigateTo('/')
} catch (e: any) {
error = await extractSdkResponseErrorMsg(e)
}

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

@ -15,7 +15,7 @@ import colors, { themeColors } from './utils/colorsUtils'
export default defineConfig({
extract: {
include: ['**/*.{vue,html,jsx,tsx,css}'],
include: ['**/*.{vue,html,jsx,tsx,css,scss}'],
exclude: ['node_modules', '.git'],
},
@ -42,7 +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',
'scrollbar-thin-primary':
'scrollbar scrollbar-thin scrollbar-thumb-rounded scrollbar-thumb-primary scrollbar-track-white dark:(!scrollbar-track-black)',
},
theme: {

Loading…
Cancel
Save