diff options
Diffstat (limited to 'front-end/src/bootstrap')
-rw-r--r-- | front-end/src/bootstrap/Environment.vue | 79 | ||||
-rw-r--r-- | front-end/src/bootstrap/components/ConfirmPrompt.vue | 76 | ||||
-rw-r--r-- | front-end/src/bootstrap/components/CookieWarning.vue | 30 | ||||
-rw-r--r-- | front-end/src/bootstrap/components/Footer.vue | 24 | ||||
-rw-r--r-- | front-end/src/bootstrap/components/Header.vue | 164 |
5 files changed, 178 insertions, 195 deletions
diff --git a/front-end/src/bootstrap/Environment.vue b/front-end/src/bootstrap/Environment.vue index 618ee62..c14b7b6 100644 --- a/front-end/src/bootstrap/Environment.vue +++ b/front-end/src/bootstrap/Environment.vue @@ -1,3 +1,42 @@ +<script setup lang="ts"> + +import { computed, defineAsyncComponent } from 'vue' +import { RouteLocation, useRouter } from 'vue-router' +import { filter, map, without, find, includes } from 'lodash-es' +import { storeToRefs } from 'pinia' +import { useEnvSize } from '@vnuge/vnlib.browser' +import { useStore } from '../store' +import siteHeader from './components/Header.vue' +import siteFooter from './components/Footer.vue' +const ConfirmPrompt = defineAsyncComponent(() => import('./components/ConfirmPrompt.vue')); +const CookieWarning = defineAsyncComponent(() => import('./components/CookieWarning.vue')); +const PasswordPrompt = defineAsyncComponent(() => import('./components/PasswordPrompt.vue')); + +const emit = defineEmits(['logout']) +const store = useStore() +const { showCookieWarning, currentRoutes } = storeToRefs(store) +const { getRoutes } = useRouter(); + +//Use the env size to calculate the header and footer heights for us +const { header, footer, content, headerHeight, footerHeight } = useEnvSize(true) + +const routes = computed<RouteLocation[]>(() => { + // Get routes that are defined above but only if they are defined in the router + // This is a computed property because loggedin is a reactive property + + const routes = filter(getRoutes(), (pageName) => includes(currentRoutes.value, pageName.name)) + + const activeRoutes = map(currentRoutes.value, route => find(routes, { name: route })) + + return without<RouteLocation>(activeRoutes, undefined) +}) + +//Forces the page content to be exactly the height of the viewport - header and footer sizes +const bodyStyle = computed(() => ({ 'min-height': `calc(100vh - ${headerHeight.value + footerHeight.value}px)` })) +const generalToastStyle = computed(() => ({ top: `${headerHeight.value + 5}px` })) +const formToastStyle = computed(() => ({ top: `${headerHeight.value}px` })) + +</script> <template> <div id="env-entry" ref="content" class="absolute top-0 left-0 w-full min-h-screen env-bg"> <div class="absolute flex w-full"> @@ -44,43 +83,3 @@ <ConfirmPrompt /> </div> </template> - -<script setup lang="ts"> - -import { computed } from 'vue' -import { RouteLocation, useRouter } from 'vue-router' -import { filter, map, without, find, includes } from 'lodash-es' -import { storeToRefs } from 'pinia' -import { useEnvSize } from '@vnuge/vnlib.browser' -import { useStore } from '../store' -import CookieWarning from './components/CookieWarning.vue' -import PasswordPrompt from './components/PasswordPrompt.vue' -import siteHeader from './components/Header.vue' -import siteFooter from './components/Footer.vue' -import ConfirmPrompt from './components/ConfirmPrompt.vue' - -const emit = defineEmits(['logout']) -const store = useStore() -const { showCookieWarning, currentRoutes } = storeToRefs(store) -const { getRoutes } = useRouter(); - -//Use the env size to calculate the header and footer heights for us -const { header, footer, content, headerHeight, footerHeight } = useEnvSize(true) - -const routes = computed<RouteLocation[]>(() => { - // Get routes that are defined above but only if they are defined in the router - // This is a computed property because loggedin is a reactive property - - const routes = filter(getRoutes(), (pageName) => includes(currentRoutes.value, pageName.name)) - - const activeRoutes = map(currentRoutes.value, route => find(routes, { name: route })) - - return without<RouteLocation>(activeRoutes, undefined) -}) - -//Forces the page content to be exactly the height of the viewport - header and footer sizes -const bodyStyle = computed(() => ({ 'min-height': `calc(100vh - ${headerHeight.value + footerHeight.value}px)` })) -const generalToastStyle = computed(() => ({ top: `${headerHeight.value + 5}px` })) -const formToastStyle = computed(() => ({ top: `${headerHeight.value}px` })) - -</script> diff --git a/front-end/src/bootstrap/components/ConfirmPrompt.vue b/front-end/src/bootstrap/components/ConfirmPrompt.vue index c67bcfc..3994672 100644 --- a/front-end/src/bootstrap/components/ConfirmPrompt.vue +++ b/front-end/src/bootstrap/components/ConfirmPrompt.vue @@ -1,3 +1,37 @@ +<script setup lang="ts"> +import { defaultTo, noop } from 'lodash-es' +import { computed, ref } from 'vue' +import { Dialog, DialogPanel, DialogTitle, DialogDescription } from '@headlessui/vue' +import { onClickOutside } from '@vueuse/core' +import { useConfirm, useEnvSize } from '@vnuge/vnlib.browser' + +export interface ConfirmMessage { + title: string + text: string + subtext?: string +} + +const { headerHeight } = useEnvSize() +//Use component side of confirm +const { isRevealed, confirm, cancel, onReveal } = useConfirm() + +const dialog = ref(null) +const message = ref<ConfirmMessage>() + +//Cancel prompt when user clicks outside of dialog, only when its open +onClickOutside(dialog, () => isRevealed.value ? cancel() : noop()) + +//Set message on reveal +onReveal(m => message.value = defaultTo(m, {})); + +const style = computed(() => { + return { + 'height': `calc(100vh - ${headerHeight.value}px)`, + 'top': `${headerHeight.value}px` + } +}) + +</script> <template> <div id="confirm-prompt"> @@ -5,15 +39,15 @@ <div class="modal-content-container"> <DialogPanel> <DialogTitle class="modal-title"> - {{ message.title ?? 'Confirm' }} + {{ message?.title ?? 'Confirm' }} </DialogTitle> <DialogDescription class="modal-description"> - {{ message.text }} + {{ message?.text }} </DialogDescription> <p class="modal-text-secondary"> - {{ message.subtext }} + {{ message?.subtext }} </p> <div class="modal-button-container"> @@ -29,39 +63,3 @@ </Dialog> </div> </template> - -<script setup lang="ts"> -import { defaultTo } from 'lodash-es' -import { computed, ref } from 'vue' - -import { - Dialog, - DialogPanel, - DialogTitle, - DialogDescription, -} from '@headlessui/vue' - -import { onClickOutside } from '@vueuse/core' -import { useConfirm, useEnvSize } from '@vnuge/vnlib.browser' - -const { headerHeight } = useEnvSize() -//Use component side of confirm -const { isRevealed, confirm, cancel, onReveal } = useConfirm() - -const dialog = ref(null) -const message = ref({}) - -//Cancel prompt when user clicks outside of dialog, only when its open -onClickOutside(dialog, () => isRevealed.value ? cancel() : null) - -//Set message on reveal -onReveal(m => message.value = defaultTo(m, {})); - -const style = computed(() => { - return { - 'height': `calc(100vh - ${headerHeight.value}px)`, - 'top': `${headerHeight.value}px` - } -}) - -</script>
\ No newline at end of file diff --git a/front-end/src/bootstrap/components/CookieWarning.vue b/front-end/src/bootstrap/components/CookieWarning.vue index b5239f5..2651cd1 100644 --- a/front-end/src/bootstrap/components/CookieWarning.vue +++ b/front-end/src/bootstrap/components/CookieWarning.vue @@ -1,15 +1,4 @@ -<template> - <div v-if="show" class="fixed top-0 left-0 z-10 w-full" :style="style"> - <div class="flex w-full p-2 text-center text-white bg-blue-600"> - <div class="m-auto text-sm font-semibold md:text-base"> - You must have cookies enabled for this site to work properly - </div> - </div> - </div> -</template> - <script setup lang="ts"> - import { computed, toRefs } from 'vue' import { useEnvSize } from '@vnuge/vnlib.browser' @@ -18,19 +7,20 @@ const props = defineProps<{ }>() const { hidden } = toRefs(props) - const { headerHeight } = useEnvSize() const show = computed(() => (!window.navigator.cookieEnabled) && !hidden.value) - -const style = computed(() => { - return { - top: headerHeight.value + 'px' - } -}) +const style = computed(() => ({ top: headerHeight.value + 'px' })) </script> +<template> + <div v-if="show" class="fixed top-0 left-0 z-10 w-full" :style="style"> + <div class="flex w-full p-2 text-center text-white bg-blue-600"> + <div class="m-auto text-sm font-semibold md:text-base"> + You must have cookies enabled for this site to work properly + </div> + </div> + </div> +</template> -<style> -</style> diff --git a/front-end/src/bootstrap/components/Footer.vue b/front-end/src/bootstrap/components/Footer.vue index 7c306c9..bdd0c92 100644 --- a/front-end/src/bootstrap/components/Footer.vue +++ b/front-end/src/bootstrap/components/Footer.vue @@ -1,9 +1,19 @@ +<script setup lang="ts"> +import { useDark } from '@vueuse/core' +import { debounce } from 'lodash-es' + +const isDark = useDark() + +const Dark = debounce(() => isDark.value = true, 50) +const Light = debounce(() => isDark.value = false, 50) +</script> + <template> <footer id="vn-footer" class="bottom-0 left-0 z-10 w-full"> <div id="footer-content" class="footer-content" > <div class="footer-main-container"> <div id="footer-text-container" class="col-span-4 sm:col-span-6 lg:col-span-3"> - <p class="my-4 text-sm leading-normal"> + <p class="my-4 text-xs leading-normal"> CMNext ia a AGPL3 licensed free and open source content management system </p> </div> @@ -50,19 +60,9 @@ </p> </div> <div class="mb-6 text-left md:mb-0"> - Copyright © 2023 Vaughn Nugent. All Rights Reserved. + Copyright © 2024 Vaughn Nugent. </div> </div> </div> </footer> </template> - -<script setup lang="ts"> -import { useDark } from '@vueuse/core' -import { debounce } from 'lodash-es' - -const isDark = useDark() - -const Dark = debounce(() => isDark.value = true, 50) -const Light = debounce(() => isDark.value = false, 50) -</script> diff --git a/front-end/src/bootstrap/components/Header.vue b/front-end/src/bootstrap/components/Header.vue index 43a805b..6093fdc 100644 --- a/front-end/src/bootstrap/components/Header.vue +++ b/front-end/src/bootstrap/components/Header.vue @@ -1,78 +1,4 @@ <!-- eslint-disable vue/max-attributes-per-line --> -<template> - <header class="sticky top-0 left-0 z-40"> - <div class="flex header-container"> - <div id="header-mobile-menu" ref="sideMenu" class="side-menu" :style="sideMenuStyle"> - <div class="pt-4 pl-4 pr-6"> - <nav id="header-mobile-nav" class="relative flex flex-col pr-3"> - <div v-for="route in routes" :key="route.path" class="m-auto ml-0"> - <div class="my-1" @click="closeSideMenu"> - <router-link :to="route"> - {{ route.name }} - </router-link> - </div> - </div> - </nav> - </div> - </div> - <div class="flex flex-row w-full md:mx-3"> - <div class="hidden w-4 lg:block" /> - <div class="flex px-4 my-auto text-xl md:hidden"> - <div v-if="!sideMenuActive" class="w-7" @click.prevent="openSideMenu"> - <fa-icon icon="bars" /> - </div> - <div v-else class="text-2xl w-7"> - <fa-icon icon="times" /> - </div> - </div> - <div id="site-title-container" class="flex m-0 mr-3"> - <div class="inline-block px-1"> - <slot name="site_logo" /> - </div> - <div id="site-title" class="inline-block m-auto mx-1"> - <router-link to="/"> - <h3>{{ siteTitle }}</h3> - </router-link> - </div> - </div> - <div class="hidden w-4 lg:block" /> - <nav id="header-desktop-nav" class="flex-row hidden mr-2 md:flex"> - <span v-for="route in routes" :key="route.fullPath" class="flex px-1 lg:px-3"> - <div v-if="!route.hide" class="m-auto"> - <router-link :to="route" class="flex-auto"> - {{ route.name }} - </router-link> - </div> - </span> - </nav> - <div id="user-menu" ref="userMenu" class="drop-controller" :class="{ 'hovered': userMenuHovered }"> - <div class="user-menu"> - Hello <span class="font-semibold">{{ uname }}</span> - </div> - <div ref="userDrop" class="absolute top-0 right-0 duration-100 ease-in-out" style="z-index:-1" :style="dropStyle"> - <div class="drop-menu" @click.prevent="userMenuHovered = false"> - <span class="space-x-2" /> - <a v-if="!loggedIn" href="#" data-header-dropdown="register" @click="gotoRoute('/register')"> - Register - </a> - <a v-else href="#" data-header-dropdown="account" @click="gotoRoute('/account')"> - Account - </a> - <a v-if="!loggedIn" href="#" data-header-dropdown="login" @click="gotoRoute('/login')"> - Login - </a> - <a v-else href="#" data-header-dropdown="logout" @click.prevent="OnLogout"> - Logout - </a> - </div> - </div> - </div> - <div class="hidden space-x-4 lg:block" /> - </div> - </div> - </header> -</template> - <script setup lang="ts"> import { debounce, find } from 'lodash-es' @@ -80,7 +6,7 @@ import { useElementSize, onClickOutside, useElementHover } from '@vueuse/core' import { computed, ref, toRefs } from 'vue' import { useEnvSize } from '@vnuge/vnlib.browser' import { RouteLocation, useRouter } from 'vue-router'; -import { storeToRefs } from 'pinia'; +import { storeToRefs } from 'pinia'; import { useStore } from '../../store'; const emit = defineEmits(['logout']) @@ -92,7 +18,6 @@ const { routes } = toRefs(props) const store = useStore(); const { loggedIn, siteTitle } = storeToRefs(store); - const { headerHeight } = useEnvSize() //Get the router for navigation @@ -132,7 +57,7 @@ const openSideMenu = debounce(() => sideMenuActive.value = true, 50) onClickOutside(sideMenu, closeSideMenu) //Redirect to the route when clicking on it -const gotoRoute = (route : string) =>{ +const gotoRoute = (route: string) => { //Get all routes from the router const allRoutes = router.getRoutes(); @@ -140,19 +65,90 @@ const gotoRoute = (route : string) =>{ //Try to find the route by its path const goto = find(allRoutes, { path: route }); - if(goto){ + if (goto) { //navigate to the route manually router.push(goto); } - else{ + else { //Fallback to full navigation window.location.assign(route); } } -const OnLogout = () =>{ - //Emit logout event - emit('logout') -} +//Emit logout event +const OnLogout = () => emit('logout') -</script>
\ No newline at end of file +</script> +<template> + <header class="sticky top-0 left-0 z-40"> + <div class="flex header-container"> + <div id="header-mobile-menu" ref="sideMenu" class="side-menu" :style="sideMenuStyle"> + <div class="pt-4 pl-4 pr-6"> + <nav id="header-mobile-nav" class="relative flex flex-col pr-3"> + <div v-for="route in routes" :key="route.path" class="m-auto ml-0"> + <div class="my-1" @click="closeSideMenu"> + <router-link :to="route"> + {{ route.name }} + </router-link> + </div> + </div> + </nav> + </div> + </div> + <div class="flex flex-row w-full md:mx-3"> + <div class="hidden w-4 lg:block" /> + <div class="flex px-4 my-auto text-xl md:hidden"> + <div v-if="!sideMenuActive" class="w-7" @click.prevent="openSideMenu"> + <fa-icon icon="bars" /> + </div> + <div v-else class="text-2xl w-7"> + <fa-icon icon="times" /> + </div> + </div> + <div id="site-title-container" class="flex m-0 mr-3"> + <div class="inline-block px-1"> + <slot name="site_logo" /> + </div> + <div id="site-title" class="inline-block m-auto mx-1"> + <router-link to="/"> + <h3>{{ siteTitle }}</h3> + </router-link> + </div> + </div> + <div class="hidden w-4 lg:block" /> + <nav id="header-desktop-nav" class="flex-row hidden mr-2 md:flex"> + <span v-for="route in routes" :key="route.fullPath" class="flex px-1 lg:px-3"> + <div v-if="!route.hide" class="m-auto"> + <router-link :to="route" class="flex-auto"> + {{ route.name }} + </router-link> + </div> + </span> + </nav> + <div id="user-menu" ref="userMenu" class="drop-controller" :class="{ 'hovered': userMenuHovered }"> + <div class="user-menu"> + Hello <span class="font-semibold">{{ uname }}</span> + </div> + <div ref="userDrop" class="absolute top-0 right-0 duration-100 ease-in-out" style="z-index:-1" :style="dropStyle"> + <div class="drop-menu" @click.prevent="userMenuHovered = false"> + <span class="space-x-2" /> + <a v-if="!loggedIn" href="#" data-header-dropdown="register" @click="gotoRoute('/register')"> + Register + </a> + <a v-else href="#" data-header-dropdown="account" @click="gotoRoute('/account')"> + Account + </a> + <a v-if="!loggedIn" href="#" data-header-dropdown="login" @click="gotoRoute('/login')"> + Login + </a> + <a v-else href="#" data-header-dropdown="logout" @click.prevent="OnLogout"> + Logout + </a> + </div> + </div> + </div> + <div class="hidden space-x-4 lg:block" /> + </div> + </div> + </header> +</template> |