@frigear-nu/base 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -94,6 +94,7 @@ With more than one i18n locale, every page gets `<link rel="alternate" hreflang>
94
94
  - This package is a shared workspace dependency and is linked via `workspace:*` from apps.
95
95
  - Keep changes here compatible with both consuming apps.
96
96
  - If you change module config or public runtime behavior, validate both app consumers in the same change.
97
+ - Client-side navigation: the content page and landing template render `UPageHeader`, `UPageBody` and `ContentRenderer` directly, not their `Lazy*` variants. Every page needs them, and a lazy wrapper costs one more round trip on each navigation. `app.vue` shows `NuxtLoadingIndicator`. `@nuxt/ui` must be ≥ 4.12: older `ULink` renders `NuxtLink` in `custom` mode without its prefetch listeners, so links never prefetch on hover or focus.
97
98
 
98
99
  ## Publishing
99
100
 
package/app/app.vue CHANGED
@@ -14,6 +14,8 @@ useLocaleAlternates()
14
14
 
15
15
  <template>
16
16
  <UApp>
17
+ <!-- Feedback while a client-side navigation loads; the default throttle hides it on fast ones. -->
18
+ <NuxtLoadingIndicator color="var(--ui-primary)" />
17
19
  <NuxtLayout>
18
20
  <NuxtPage />
19
21
  </NuxtLayout>
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Whether the current route can be a content page. Routes a module registers through `addModulePages` carry
3
+ * `meta.moduleName` and are never served from `@nuxt/content` (account, admin, auth, ...); any other page can opt out
4
+ * with `definePageMeta({ content: false })`. Skipping them avoids a content query (and, in the browser, loading the
5
+ * WASM SQLite dump behind it) on every navigation inside those areas.
6
+ */
7
+ export const routeServedByContent = (meta: Record<string, unknown>) =>
8
+ meta.content !== false && !meta.moduleName
9
+
1
10
  export const useCurrentPage = () => {
2
11
  const route = useRoute()
3
12
  const { locale, stripLocalePrefix } = useContentLocale()
@@ -8,10 +17,16 @@ export const useCurrentPage = () => {
8
17
  () => `current-page:${collection.value}:${path.value}`,
9
18
  // Locale-suffixed collections (e.g. `pages_no`) share the same schema as
10
19
  // `pages`, so the cast keeps the return type stable across locales.
11
- () => queryCollection(collection.value as 'pages').path(path.value).first(),
20
+ () => routeServedByContent(route.meta)
21
+ ? queryCollection(collection.value as 'pages').path(path.value).first()
22
+ : Promise.resolve(null),
12
23
  {
13
24
  watch: [path, locale, collection],
14
25
  dedupe: 'cancel',
26
+ // Content is static, so a path that was already loaded (revisit) reuses its payload entry instead of querying
27
+ // again. Only an explicit refresh asks the content database.
28
+ getCachedData: (key, nuxtApp, ctx) =>
29
+ ctx.cause === 'refresh:manual' ? undefined : (nuxtApp.payload.data[key] ?? nuxtApp.static.data[key]),
15
30
  },
16
31
  )
17
32
  }
@@ -1,13 +1,14 @@
1
1
  export const useNavigation = (tags?: string[]) => {
2
+ // Resolved in setup: calling a composable inside the handler, after an await, loses the Nuxt context.
3
+ const config = useConfig()
4
+
2
5
  return useAsyncData(
3
6
  () => `navigation:${tags?.join(',') || 'all'}`,
4
7
  async () => {
5
- const { data: config } = await useConfig() // or however you access the pending promise
6
- if (!tags) {
7
- return config.value?.navigation || []
8
- }
9
- return (config.value?.navigation || [])
10
- .filter(item => !tags || tags.some(tag => item?.tags?.includes(tag)))
8
+ const { data } = await config
9
+ const navigation = data.value?.navigation || []
10
+ if (!tags) return navigation
11
+ return navigation.filter(item => tags.some(tag => item?.tags?.includes(tag)))
11
12
  },
12
13
  )
13
14
  }
@@ -11,18 +11,18 @@ if (!data.value) {
11
11
  <template>
12
12
  <UPage>
13
13
  <UContainer v-if="data && data.pageHeader">
14
- <LazyUPageHeader
14
+ <UPageHeader
15
15
  v-bind="data.pageHeader"
16
16
  :ui="{ root: 'text-center', wrapper: 'lg:flex-col lg:items-center lg:justify-center' }"
17
17
  />
18
18
  </UContainer>
19
- <LazyUPageBody>
19
+ <UPageBody>
20
20
  <component
21
21
  :is="data?.container ? UContainer : 'div'"
22
22
  v-if="data"
23
23
  >
24
- <LazyContentRenderer :value="data" />
24
+ <ContentRenderer :value="data" />
25
25
  </component>
26
- </LazyUPageBody>
26
+ </UPageBody>
27
27
  </UPage>
28
28
  </template>
@@ -6,7 +6,7 @@ if (!data.value) {
6
6
  </script>
7
7
 
8
8
  <template>
9
- <LazyContentRenderer
9
+ <ContentRenderer
10
10
  v-if="data"
11
11
  :value="data"
12
12
  />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frigear-nu/base",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Shared Nuxt layer for Frigear websites - bundled modules, UI defaults, content collections, layouts and routing.",
5
5
  "homepage": "https://docs.frigear.dev/layers/base",
6
6
  "repository": {
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "dependencies": {
26
26
  "@comark/nuxt": "0.6.2",
27
- "@frigear-nu/menu": "0.1.1",
27
+ "@frigear-nu/menu": "0.1.3",
28
28
  "@iconify-json/lucide": "^1.2.127",
29
29
  "@iconify-json/simple-icons": "^1.2.94",
30
30
  "@nuxt/content": "^3.16.1",
@@ -34,7 +34,7 @@
34
34
  "@nuxt/image": "^2.1.0",
35
35
  "@nuxt/kit": "^4.6.1",
36
36
  "@nuxt/schema": "^4.6.1",
37
- "@nuxt/ui": "^4.11.2",
37
+ "@nuxt/ui": "^4.12.0",
38
38
  "@nuxtjs/device": "4.0.0",
39
39
  "@nuxtjs/i18n": "^10.6.0",
40
40
  "@nuxtjs/robots": "^7.0.2",