diff --git a/.dockerignore b/.dockerignore index f99d8860..285737f8 100644 --- a/.dockerignore +++ b/.dockerignore @@ -13,4 +13,3 @@ venv .git .envrc - diff --git a/client/package.json b/client/package.json index eea590d3..433ab715 100644 --- a/client/package.json +++ b/client/package.json @@ -26,6 +26,8 @@ "@intlify/vite-plugin-vue-i18n": "^3.4.0", "@rollup/plugin-alias": "^3.1.9", "@rushstack/eslint-patch": "^1.1.0", + "@tailwindcss/forms": "^0.5.2", + "@tailwindcss/typography": "^0.5.4", "@testing-library/vue": "^6.6.0", "@types/d3": "^7.4.0", "@types/jsdom": "^16.2.14", diff --git a/client/src/App.vue b/client/src/App.vue index 10f11ea1..b91f07f0 100644 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -1,7 +1,11 @@ @@ -11,6 +15,25 @@ import * as log from 'loglevel'; import MainNavigationBar from '@/components/MainNavigationBar.vue'; import Footer from '@/components/Footer.vue'; +import {onMounted} from 'vue'; log.debug('App created'); + +onMounted(() => { + log.debug('App mounted'); +}); + + + diff --git a/client/src/components/Footer.vue b/client/src/components/Footer.vue index 262251e0..7d678303 100644 --- a/client/src/components/Footer.vue +++ b/client/src/components/Footer.vue @@ -10,7 +10,7 @@ log.debug('Footer created'); class=" px-8 py-4 - bg-gray-100 + bg-gray-200 border-t border-gray-500 "> @2022 VBV diff --git a/client/src/components/MainNavigationBar.vue b/client/src/components/MainNavigationBar.vue index 3ddaa904..f3e7454a 100644 --- a/client/src/components/MainNavigationBar.vue +++ b/client/src/components/MainNavigationBar.vue @@ -1,27 +1,29 @@ - @@ -165,4 +244,16 @@ function backButtonUrl() { .nav-item--active { @apply underline underline-offset-[21px] decoration-sky-500 decoration-4 } + +.nav-enter-active, +.nav-leave-active { + transition: opacity 0.3s ease, transform 0.3s ease; +} + +.nav-enter-from, +.nav-leave-to { + opacity: 0; + transform: translateY(-80px); +} + diff --git a/client/src/components/MobileMenu.vue b/client/src/components/MobileMenu.vue new file mode 100644 index 00000000..93312cf1 --- /dev/null +++ b/client/src/components/MobileMenu.vue @@ -0,0 +1,70 @@ + + + diff --git a/client/src/components/circle/CircleDiagram.vue b/client/src/components/circle/CircleDiagram.vue index dcb2f49b..1eb10a51 100644 --- a/client/src/components/circle/CircleDiagram.vue +++ b/client/src/components/circle/CircleDiagram.vue @@ -5,20 +5,6 @@ import * as _ from 'underscore' import {useCircleStore} from '@/stores/circle'; import * as log from 'loglevel'; -const props = defineProps<{ - width: { - default: 500, - type: number, - required: false - - }, - height: { - default: 500, - type: number, - required: false - }, -}>() - const circleStore = useCircleStore(); function someFinished(learningSequence) { @@ -70,12 +56,12 @@ const blue900 = '#00224D', sky400 = '#72CAFF', sky500 = '#41B5FA' -function render() { - const width = 450, //props.width, - height = 450, //props.height, - radius: number = Math.min(width, height) / 2.4, - arrowStrokeWidth = 2 +const width = 450 +const height = 450 +const radius = Math.min(width, height) / 2.4 +function render() { + const arrowStrokeWidth = 2 const svg = d3.select('.circle-visualization') .attr('viewBox', `0 0 ${width} ${height}`) @@ -224,6 +210,8 @@ function render() { + + diff --git a/client/src/components/circle/CircleOverview.vue b/client/src/components/circle/CircleOverview.vue index 29bf5ec5..59776904 100644 --- a/client/src/components/circle/CircleOverview.vue +++ b/client/src/components/circle/CircleOverview.vue @@ -1,22 +1,21 @@ diff --git a/client/src/components/icons/IconLogout.vue b/client/src/components/icons/IconLogout.vue new file mode 100644 index 00000000..ebc6f65a --- /dev/null +++ b/client/src/components/icons/IconLogout.vue @@ -0,0 +1,6 @@ + diff --git a/client/src/components/icons/IconSettings.vue b/client/src/components/icons/IconSettings.vue new file mode 100644 index 00000000..9f0300a2 --- /dev/null +++ b/client/src/components/icons/IconSettings.vue @@ -0,0 +1,6 @@ + diff --git a/client/src/components/ui/ItDropdown.vue b/client/src/components/ui/ItDropdown.vue new file mode 100644 index 00000000..dbe526dc --- /dev/null +++ b/client/src/components/ui/ItDropdown.vue @@ -0,0 +1,63 @@ + + + diff --git a/client/src/components/ui/ItFullScreenModal.vue b/client/src/components/ui/ItFullScreenModal.vue new file mode 100644 index 00000000..53ff4e5a --- /dev/null +++ b/client/src/components/ui/ItFullScreenModal.vue @@ -0,0 +1,27 @@ + + + diff --git a/client/src/router/guards.ts b/client/src/router/guards.ts index 80596c46..9fe06bfd 100644 --- a/client/src/router/guards.ts +++ b/client/src/router/guards.ts @@ -1,14 +1,13 @@ -import type {NavigationGuardWithThis, RouteLocationNormalized} from 'vue-router'; -import {useUserStore} from '@/stores/user'; - +import type { NavigationGuardWithThis, RouteLocationNormalized } from 'vue-router' +import { useUserStore } from '@/stores/user' export const updateLoggedIn: NavigationGuardWithThis = (_to) => { const loggedIn = getCookieValue('loginStatus') === 'true' const userStore = useUserStore() - userStore.$patch({loggedIn}); + userStore.$patch({ loggedIn }) if (loggedIn && !userStore.email) { - userStore.fetchUser(); + userStore.fetchUser() } } diff --git a/client/src/router/index.ts b/client/src/router/index.ts index 93842418..e6683230 100644 --- a/client/src/router/index.ts +++ b/client/src/router/index.ts @@ -1,7 +1,8 @@ -import {createRouter, createWebHistory} from 'vue-router' -import CockpitView from '@/views/CockpitView.vue'; -import LoginView from '@/views/LoginView.vue'; -import {redirectToLoginIfRequired, updateLoggedIn} from '@/router/guards'; +import { createRouter, createWebHistory } from 'vue-router' +import CockpitView from '@/views/CockpitView.vue' +import LoginView from '@/views/LoginView.vue' +import { redirectToLoginIfRequired, updateLoggedIn } from '@/router/guards' +import { useAppStore } from '@/stores/app' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -11,8 +12,8 @@ const router = createRouter({ component: LoginView, meta: { // no login required -> so `public === true` - public: true - } + public: true, + }, }, { path: '/', @@ -38,28 +39,33 @@ const router = createRouter({ { path: '/learningpath/:learningPathSlug', component: () => import('../views/LearningPathView.vue'), - props: true + props: true, }, { path: '/circle/:circleSlug', component: () => import('../views/CircleView.vue'), - props: true + props: true, }, { path: '/styleguide', component: () => import('../views/StyelGuideView.vue'), meta: { - public: true - } + public: true, + }, }, { path: '/:pathMatch(.*)*', component: () => import('../views/404View.vue'), }, - ] + ], }) router.beforeEach(updateLoggedIn) router.beforeEach(redirectToLoginIfRequired) +router.afterEach((to, from) => { + const appStore = useAppStore(); + appStore.routingFinished = true; +}); + export default router diff --git a/client/src/stores/app.ts b/client/src/stores/app.ts index 473c102a..8e4bec05 100644 --- a/client/src/stores/app.ts +++ b/client/src/stores/app.ts @@ -1,13 +1,17 @@ -import {defineStore} from 'pinia' +import { defineStore } from 'pinia' export type AppState = { - showMainNavigationBar: boolean; + userLoaded: boolean + routingFinished: boolean + showMainNavigationBar: boolean } export const useAppStore = defineStore({ id: 'app', state: () => ({ showMainNavigationBar: true, + userLoaded: false, + routingFinished: false, } as AppState), getters: { }, diff --git a/client/src/stores/learningPath.ts b/client/src/stores/learningPath.ts index 58e231c6..8759565f 100644 --- a/client/src/stores/learningPath.ts +++ b/client/src/stores/learningPath.ts @@ -25,7 +25,7 @@ export const useLearningPathStore = defineStore({ return this.learningPath; } try { - const learningPathData = await itGet(`/learnpath/api/learningpath/${slug}/`); + const learningPathData = await itGet(`/learnpath/api/page/${slug}/`); const completionData = await itGet(`/api/completion/learning_path/${learningPathData.translation_key}/`); this.learningPath = learningPathData; @@ -54,8 +54,6 @@ export const useLearningPathStore = defineStore({ }) this.learningPath.topics.push(topic); - console.log('#######################'); - console.log(this.learningPath); } return this.learningPath; } catch (error) { diff --git a/client/src/stores/user.ts b/client/src/stores/user.ts index 4881e38c..c756a08a 100644 --- a/client/src/stores/user.ts +++ b/client/src/stores/user.ts @@ -2,6 +2,7 @@ import * as log from 'loglevel'; import {defineStore} from 'pinia' import {itGet, itPost} from '@/fetchHelpers'; +import {useAppStore} from '@/stores/app'; // typed state https://stackoverflow.com/questions/71012513/when-using-pinia-and-typescript-how-do-you-use-an-action-to-set-the-state export type UserState = { @@ -46,11 +47,14 @@ export const useUserStore = defineStore({ } }, fetchUser() { + const appStore = useAppStore(); itGet('/api/core/me/').then((data) => { this.$state = data; this.loggedIn = true; + appStore.userLoaded = true; }).catch(() => { this.loggedIn = false; + appStore.userLoaded = true; }) } } diff --git a/client/src/views/CircleView.vue b/client/src/views/CircleView.vue index bd2e7314..77498f2c 100644 --- a/client/src/views/CircleView.vue +++ b/client/src/views/CircleView.vue @@ -2,12 +2,12 @@ import * as log from 'loglevel'; import LearningSequence from '@/components/circle/LearningSequence.vue'; import CircleOverview from '@/components/circle/CircleOverview.vue'; +import CircleDiagram from '@/components/circle/CircleDiagram.vue'; import LearningContent from '@/components/circle/LearningContent.vue'; import {onMounted} from 'vue' import {useCircleStore} from '@/stores/circle'; import SelfEvaluation from '@/components/circle/SelfEvaluation.vue'; -import CircleDiagram from '@/components/circle/CircleDiagram.vue'; log.debug('CircleView.vue created'); @@ -16,34 +16,39 @@ const props = defineProps<{ }>() const circleStore = useCircleStore(); +circleStore.loadCircle(props.circleSlug); onMounted(async () => { log.info('CircleView.vue mounted'); - await circleStore.loadCircle(props.circleSlug); }); diff --git a/client/src/views/CockpitView.vue b/client/src/views/CockpitView.vue index 191d1b0d..b0dd0a70 100644 --- a/client/src/views/CockpitView.vue +++ b/client/src/views/CockpitView.vue @@ -9,7 +9,7 @@ const userStore = useUserStore();