Skip to content

Commit ba56920

Browse files
committed
feat(frontend): more extensive UI (layouts) boilerplate, general adjustments and fixes
1 parent 902300a commit ba56920

22 files changed

Lines changed: 369 additions & 30 deletions

File tree

apps/frontend/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
* [@antfu/eslint-config](https://github.com/antfu/eslint-config)
1111
* [UnoCSS](https://unocss.dev/guide/)
1212
* UnoCSS is an atomic CSS engine, similar to Tailwind but is super fast and have some amazing features like automatically imported icons in pure CSS.
13+
* [VueUse](https://vueuse.org/)
14+
* + [VueUse Motion](https://motion.vueuse.org/)
1315
* Tanstack Query
1416
* Default is configured for client-side fetching usage, data is persisted to IndexedDB.
1517
* PrimeVue * UI library
@@ -24,6 +26,8 @@
2426
* Dark and Light mode with auto detection made easy with Nuxt.
2527
* [NuxtImage](https://image.nuxt.com/)
2628
* Automatic optimized images for the app, as well as placeholder support.
29+
* [NuxtSVGO](https://github.com/cpsoinos/nuxt-svgo)
30+
* Support for loading SVGs and optimizing them.
2731
* [Nuxt Booster](https://basics.github.io/nuxt-booster/)
2832
* Lighthouse score optimizations
2933
* [NuxtI18n](https://i18n.nuxtjs.org/)

apps/frontend/app/app.vue

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,20 @@ onMounted(async () => {
1414
</script>
1515

1616
<template>
17-
<NuxtLayout>
18-
<NuxtPage />
19-
</NuxtLayout>
17+
<div>
18+
<template v-if="!$init.mounted">
19+
<NuxtLayout name="loading">
20+
<NuxtPage />
21+
<!-- <LoadingScreen /> -->
22+
</NuxtLayout>
23+
</template>
24+
25+
<template v-else>
26+
<GlobalRegister />
27+
28+
<NuxtLayout>
29+
<NuxtPage />
30+
</NuxtLayout>
31+
</template>
32+
</div>
2033
</template>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!-- This file is similar to GlobalRegister.vue, but it is only used for local development purposes and type checking is disabled. -->
2+
<script setup lang="ts">
3+
// eslint-disable-next-line ts/ban-ts-comment
4+
// @ts-nocheck
5+
6+
if (import.meta.env.DEV) {
7+
if (import.meta.client) {
8+
window.dayjs = dayjs
9+
}
10+
}
11+
</script>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script setup lang="ts">
2+
</script>
3+
4+
<template>
5+
<!-- Register global Primevue components -->
6+
<div>
7+
<Toast />
8+
<ConfirmPopup />
9+
</div>
10+
<DevRegister />
11+
</template>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script setup lang="ts">
2+
import LogoFull from '~~/public/logo-full.svg'
3+
import LogoSimple from '~~/public/logo-simple.svg'
4+
5+
const {
6+
variant = 'simple',
7+
} = defineProps<{
8+
variant?: 'simple' | 'full'
9+
}>()
10+
</script>
11+
12+
<template>
13+
<LogoFull v-if="variant === 'full'" />
14+
<LogoSimple v-else />
15+
</template>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script setup lang="ts">
2+
3+
</script>
4+
5+
<template>
6+
<footer class="bg-mono-i py-4 text-center">
7+
<div>© 2025 NamesMT.</div>
8+
</footer>
9+
</template>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<script setup lang="ts">
2+
// const theme = useTheme()
3+
</script>
4+
5+
<template>
6+
<header class="grid grid-cols-12 h-73px items-center border-b bg-gray-400 px-2 transition-background-color xl:gap-10 dark:bg-gray-600 lg:px-8 md:px-6 sm:px-4">
7+
<div class="col-span-3 h-full flex items-center justify-start gap-2 py-4 text-xl">
8+
<NuxtLink to="/" class="h-full">
9+
<Logo class="h-full text-black dark:text-white" />
10+
</NuxtLink>
11+
</div>
12+
13+
<div
14+
class="divide-primary-2 text-body-2 text-grey-500 col-span-6 h-full flex flex-row justify-center gap-2 2xl:gap-10 lg:gap-6 md:gap-5 sm:gap-4 xl:gap-7 [&>*]:(px-4 md:px-6 xl:px-8)"
15+
>
16+
<NuxtLink
17+
to="/" class="group flex items-center"
18+
exact-active-class="text-white font-medium border-t-2px border-primary-400 bg-gradient-to-b from-primary-400/20"
19+
>
20+
<span class="group-hover:text-mainGradient">{{ $t('pages.home.title') }}</span>
21+
</NuxtLink>
22+
23+
<NuxtLink
24+
to="/test" class="group flex items-center"
25+
active-class="text-white font-medium border-t-2px border-primary-400 bg-gradient-to-b from-primary-400/20"
26+
>
27+
<span class="group-hover:text-mainGradient">{{ $t('pages.test.title') }}</span>
28+
</NuxtLink>
29+
</div>
30+
31+
<div class="col-span-3 flex">
32+
<div class="flex grow items-center justify-end gap-5">
33+
<Avatar label="MT" size="large" shape="circle" />
34+
</div>
35+
</div>
36+
</header>
37+
</template>

apps/frontend/app/layouts/default.vue

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ const head = useLocaleHead({
55
key: 'id',
66
})
77
const title = computed(() => route.meta.title && t(route.meta.title))
8+
9+
const windowsScroll = useWindowScroll()
810
</script>
911

1012
<template>
1113
<div>
12-
<Html class="font-sans">
14+
<Html :lang="head.htmlAttrs.lang" :dir="head.htmlAttrs.dir" class="font-sans">
1315
<Head>
1416
<!-- Don't set Title tag if we doesn't have a title, this allows `Nuxt SEO`'s fallback title to be used -->
1517
<Title v-if="title">
@@ -22,8 +24,27 @@ const title = computed(() => route.meta.title && t(route.meta.title))
2224
<Meta :id="meta.id" :property="meta.property" :content="meta.content" />
2325
</template>
2426
</Head>
27+
2528
<Body>
26-
<slot />
29+
<div class="min-h-screen w-full flex flex-col">
30+
<!-- Header -->
31+
<DefaultHeader
32+
v-motion-slide-visible-once-left
33+
class="fixed w-full transition-top"
34+
:class="windowsScroll.arrivedState.top ? 'top-0' : '-top-20'"
35+
/>
36+
37+
<!-- NuxtPage -->
38+
<div id="app-body" class="flex grow px-5 py-15 pt-20 2xl:px-20 lg:px-10 xl:px-15">
39+
<slot />
40+
</div>
41+
42+
<!-- Footer -->
43+
<DefaultFooter
44+
class="fixed w-full transition-bottom"
45+
:class="windowsScroll.arrivedState.bottom ? 'bottom-0' : '-bottom-20'"
46+
/>
47+
</div>
2748
</Body>
2849
</Html>
2950
</div>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<script setup>
2+
const route = useRoute()
3+
const { t } = useI18n()
4+
const head = useLocaleHead({
5+
key: 'id',
6+
})
7+
const title = computed(() => route.meta.title && t(route.meta.title))
8+
</script>
9+
10+
<template>
11+
<div>
12+
<Html :lang="head.htmlAttrs.lang" :dir="head.htmlAttrs.dir" class="font-sans">
13+
<Head>
14+
<!-- Don't set Title tag if we doesn't have a title, this allows `Nuxt SEO`'s fallback title to be used -->
15+
<Title v-if="title">
16+
{{ title }}
17+
</Title>
18+
<template v-for="link in head.link" :key="link.id">
19+
<Link :id="link.id" :rel="link.rel" :href="link.href" :hreflang="link.hreflang" />
20+
</template>
21+
<template v-for="meta in head.meta" :key="meta.id">
22+
<Meta :id="meta.id" :property="meta.property" :content="meta.content" />
23+
</template>
24+
</Head>
25+
26+
<Body>
27+
<div class="min-h-screen w-full flex flex-col">
28+
<!-- NuxtPage -->
29+
<div id="app-body" class="flex grow px-5 py-15 pt-20 2xl:px-20 lg:px-10 xl:px-15">
30+
<slot />
31+
</div>
32+
</div>
33+
</Body>
34+
</Html>
35+
</div>
36+
</template>

apps/frontend/app/pages/index.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
import GridMaker from '@local/common-vue/src/components/GridMaker.vue'
33
44
definePageMeta({
5-
title: 'pages.title.home',
5+
title: 'pages.home.title',
66
})
77
</script>
88

99
<template>
10-
<div class="min-h-screen flex flex-col items-center justify-center gap-4 px-4 py-4 text-center">
10+
<div class="w-full flex flex-col items-center justify-center gap-4 px-4 py-4 text-center">
1111
<div class="flex items-end gap-2">
1212
<GridMaker
1313
:value="[

0 commit comments

Comments
 (0)