@lupinum/ginko-content 1.0.0-beta.6 → 1.0.0-beta.7

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
@@ -15,7 +15,7 @@
15
15
  </p>
16
16
 
17
17
  > [!WARNING]
18
- > Version `1.0.0-beta.6` is a prerelease. Install it from npm's `next`
18
+ > Version `1.0.0-beta.7` is a prerelease. Install it from npm's `next`
19
19
  > channel. The stable `0.3` line remains on `latest`.
20
20
 
21
21
  ## Why use this package?
@@ -40,13 +40,13 @@ output.
40
40
  Use the Nuxt CLI:
41
41
 
42
42
  ```bash
43
- npx nuxi module add @lupinum/ginko-content@1.0.0-beta.6
43
+ npx nuxi module add @lupinum/ginko-content@1.0.0-beta.7
44
44
  ```
45
45
 
46
46
  Or install and register the module by hand:
47
47
 
48
48
  ```bash
49
- pnpm add @lupinum/ginko-content@1.0.0-beta.6
49
+ pnpm add @lupinum/ginko-content@1.0.0-beta.7
50
50
  ```
51
51
 
52
52
  ```ts
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lupinum/ginko-content",
3
- "version": "1.0.0-beta.6",
3
+ "version": "1.0.0-beta.7",
4
4
  "configKey": "content",
5
5
  "compatibility": {
6
6
  "nuxt": ">=4.5.1 <5"
package/dist/module.mjs CHANGED
@@ -34,7 +34,7 @@ import { assertCanonicalHighlightOptionNames } from '../dist/parsers/markdown-pl
34
34
  import { BUILTIN_MARKDOWN_RENDER_CONTRACTS } from '../dist/core/markdown/builtin-render-contracts.js';
35
35
 
36
36
  const name = "@lupinum/ginko-content";
37
- const version = "1.0.0-beta.6";
37
+ const version = "1.0.0-beta.7";
38
38
  const peerDependencies = {
39
39
  nuxt: ">=4.5.1 <5"};
40
40
 
@@ -252,6 +252,7 @@ const registerContentDevRuntime = (nuxt, options, contentContext) => {
252
252
  };
253
253
 
254
254
  const runtimeAppImportSpecs = [
255
+ { name: "useContentLocalePath", as: "useContentLocalePath", from: "./app/composables/use-content-locale-path.js" },
255
256
  { name: "useContentPage", as: "useContentPage", from: "./app/composables/use-content-page.js" },
256
257
  { name: "useContentSearch", as: "useGinkoContentSearch", from: "./app/composables/search.js" }
257
258
  ];
@@ -2,14 +2,16 @@
2
2
  * Client-side public API surface (browser + SSR Vue).
3
3
  *
4
4
  * The unified query API (ADR-0016) is the supported core read path. The
5
- * public composable surface is exactly `useContentPage` and
6
- * `useContentSearch`; every other application workflow is
5
+ * public composable surface includes page loading, locale links, and
6
+ * search; every other application workflow is
7
7
  * ordinary Nuxt composition over the one-shot async query operations below.
8
8
  */
9
9
  export { one, many, count, paginate, backlinks, resolveOne, surround, navigation } from '../runtime/app/composables/query-api.js';
10
10
  export { getCollectionPath } from '../features/query/routes.js';
11
11
  export type { CollectionPathOptions } from '../features/query/routes.js';
12
12
  export { findFirstNavigationPage } from '../features/navigation/resolve.js';
13
+ export { useContentLocalePath } from '../runtime/app/composables/use-content-locale-path.js';
14
+ export type { ContentLocalePage, UseContentLocalePathOptions } from '../runtime/app/composables/use-content-locale-path.js';
13
15
  export { useContentPage } from '../runtime/app/composables/use-content-page.js';
14
16
  export type { ContentPageStatus, UseContentPageOptions, UseContentPageReturn } from '../runtime/app/composables/use-content-page.js';
15
17
  export type { QueryWhere, QueryOperators, ContentSelector, BacklinkFields, BacklinkSource, BacklinksOptions, BacklinksResult, CountOptions, LocaleFallback, DocumentFromHandle, OneOptions, ManyOptions, PaginationOptions, PaginationResult, PopulateSpec, PopulatedDocument, ResolveOneOptions, ResolveOneResult, LocalizedContentDocument, ResolutionEnvelope, SortSpec, ContentAlternate, ContentDocumentRoute, ContentDocumentResolution, ContentNavigationItem, ContentCollectionName, ContentCollectionTarget, ContentSearchSection, SurroundOptions, SurroundResult, NavigationOptions, ContentNavigationTreeItem, ResolvedContentNavigationItem, PaginationMode, OffsetPaginationResult, CursorPaginationResult } from '../types/query.js';
@@ -10,6 +10,7 @@ export {
10
10
  } from "../runtime/app/composables/query-api.js";
11
11
  export { getCollectionPath } from "../features/query/routes.js";
12
12
  export { findFirstNavigationPage } from "../features/navigation/resolve.js";
13
+ export { useContentLocalePath } from "../runtime/app/composables/use-content-locale-path.js";
13
14
  export { useContentPage } from "../runtime/app/composables/use-content-page.js";
14
15
  export { useContentSearch } from "../runtime/app/composables/search.js";
15
16
  export { querySiteData } from "../runtime/app/composables/site-data.js";
@@ -0,0 +1,10 @@
1
+ import { type MaybeRefOrGetter } from 'vue';
2
+ import type { UseContentPageReturn } from './use-content-page';
3
+ /** The existing page result supplies the facts; no shared state or second query. */
4
+ export type ContentLocalePage = Pick<UseContentPageReturn<unknown>, 'page' | 'status'>;
5
+ export interface UseContentLocalePathOptions<L extends string = string> {
6
+ /** Used only when the source is undefined (an application-only page). */
7
+ fallback?: (locale: L) => string | undefined;
8
+ }
9
+ /** Derive interactive locale links from a page result supplied by its owner. */
10
+ export declare function useContentLocalePath<L extends string = string>(source: MaybeRefOrGetter<ContentLocalePage | undefined>, options?: UseContentLocalePathOptions<L>): (locale: L) => string | undefined;
@@ -0,0 +1,20 @@
1
+ import { toValue } from "vue";
2
+ import { useRoute, useRouter } from "#imports";
3
+ import { pageMatchesRoute } from "./use-content-shared.js";
4
+ import { getContentRuntime } from "./runtime.js";
5
+ export function useContentLocalePath(source, options = {}) {
6
+ const route = useRoute();
7
+ const router = useRouter();
8
+ const runtime = getContentRuntime();
9
+ return (locale) => {
10
+ const result = toValue(source);
11
+ if (!result) return runtime.locales?.includes(locale) ? options.fallback?.(locale) : void 0;
12
+ if (result.status.value !== "success") return void 0;
13
+ const document = result.page.value;
14
+ if (!document || !pageMatchesRoute(document, route.path)) return void 0;
15
+ const alternates = document.route.alternates;
16
+ const alternate = alternates.find((item) => item.locale === locale && item.source === "variant") ?? alternates.find((item) => item.locale === locale);
17
+ if (!alternate) return void 0;
18
+ return router.resolve({ path: alternate.path, query: route.query, hash: route.hash }).fullPath;
19
+ };
20
+ }
@@ -3,21 +3,11 @@ import { useAsyncData, useRoute } from "#imports";
3
3
  import { resolveCollectionI18n } from "../../../features/localization/path.js";
4
4
  import { one, surround } from "./query-api.js";
5
5
  import { getContentRuntime } from "./runtime.js";
6
- import { contentCollectionName, resolveLocaleFromRoutePath, resolveOptions, stableKey } from "./use-content-shared.js";
7
- const normalizeRoutePath = (path) => {
8
- if (typeof path !== "string") return void 0;
9
- const normalized = path.replace(/\/+$/, "");
10
- return normalized || "/";
11
- };
6
+ import { contentCollectionName, normalizeRoutePath, pageMatchesRoute, resolveLocaleFromRoutePath, resolveOptions, stableKey } from "./use-content-shared.js";
12
7
  const normalizePageSurround = (surroundOption) => {
13
8
  if (!surroundOption) return void 0;
14
9
  return surroundOption === true ? {} : surroundOption;
15
10
  };
16
- const pageMatchesRoute = (doc, path) => {
17
- if (!doc?.route) return false;
18
- const normalizedPath = normalizeRoutePath(path);
19
- return normalizeRoutePath(doc.route.requestedPath) === normalizedPath || normalizeRoutePath(doc.route.resolvedPath) === normalizedPath;
20
- };
21
11
  export async function useContentPage(handle, options = {}) {
22
12
  const route = useRoute();
23
13
  const { surround: surroundOption, ...oneOptions } = options;
@@ -11,3 +11,18 @@ export declare const resolveOptions: <T extends Record<string, unknown>>(reactiv
11
11
  export declare const stableKey: (prefix: string, name: string, options: unknown) => string;
12
12
  export declare const contentCollectionName: (handle: ContentCollectionTarget) => string;
13
13
  export declare const resolveLocaleFromRoutePath: (path: string, locales: string[], defaultLocale?: string) => string | undefined;
14
+ export declare const normalizeRoutePath: (path: unknown) => string | undefined;
15
+ /**
16
+ * A resolved page "matches" the current route when either the exact
17
+ * selector the app queried with (`route.requestedPath`) or the document's
18
+ * own canonical public path (`route.resolvedPath`) equals the current route
19
+ * — the first covers a provider/alias match whose canonical path differs
20
+ * from the requested one, the
21
+ * second covers static/prerendered routes served under a normalized path.
22
+ */
23
+ export declare const pageMatchesRoute: (doc: {
24
+ route?: {
25
+ requestedPath?: string;
26
+ resolvedPath?: string;
27
+ };
28
+ } | null | undefined, path: string) => boolean;
@@ -27,3 +27,13 @@ export const resolveLocaleFromRoutePath = (path, locales, defaultLocale) => {
27
27
  const firstSegment = path.split("/").filter(Boolean)[0];
28
28
  return firstSegment && locales.includes(firstSegment) ? firstSegment : defaultLocale;
29
29
  };
30
+ export const normalizeRoutePath = (path) => {
31
+ if (typeof path !== "string") return void 0;
32
+ const normalized = path.replace(/\/+$/, "");
33
+ return normalized || "/";
34
+ };
35
+ export const pageMatchesRoute = (doc, path) => {
36
+ if (!doc?.route) return false;
37
+ const normalizedPath = normalizeRoutePath(path);
38
+ return normalizeRoutePath(doc.route.requestedPath) === normalizedPath || normalizeRoutePath(doc.route.resolvedPath) === normalizedPath;
39
+ };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "framework": "vue",
3
3
  "name": "@lupinum/ginko-content",
4
- "version": "1.0.0-beta.6",
4
+ "version": "1.0.0-beta.7",
5
5
  "contributions": {
6
6
  "html": {
7
7
  "description-markup": "markdown",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lupinum/ginko-content",
3
- "version": "1.0.0-beta.6",
3
+ "version": "1.0.0-beta.7",
4
4
  "description": "Collection-first content engine for Nuxt",
5
5
  "homepage": "https://ginko-content.lupinum.com",
6
6
  "bugs": {