@monkeyplus/flow 6.0.55 → 6.0.57

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monkeyplus/flow",
3
- "version": "6.0.55",
3
+ "version": "6.0.57",
4
4
  "description": "@monkeyplus/flow package-first runtime with Vite, Nitro, Vue and a workspace playground.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -1,4 +1,4 @@
1
- import type { DynamicRouteEntry, FlowLocale, GetUrlOptions, HeadDefinition, PageDefinition, PageLocaleDefinition, PageUrlInfo } from '../../src/runtime/pages';
1
+ import type { DynamicRouteEntry, FlowLocale, GetUrlOptions, HeadDefinition, PageDefinition, PageLocaleDefinition, PageUrlInfo, BreadcrumbItem } from '../../src/runtime/pages';
2
2
  export interface ResolvedPage {
3
3
  definition: PageDefinition;
4
4
  locale: FlowLocale;
@@ -13,8 +13,10 @@ export interface ResolvedPage {
13
13
  */
14
14
  seo: HeadDefinition;
15
15
  context: Record<string, unknown>;
16
+ breadcrumbs: BreadcrumbItem[];
16
17
  }
17
18
  export declare function getUrl(namePage: string, localeCode?: string, options?: GetUrlOptions): Promise<string | undefined>;
18
19
  export declare function getUrls(withLocale?: boolean, omitNoPublish?: boolean): Promise<(string | PageUrlInfo)[]>;
19
20
  export declare function resolvePage(pathname: string, request?: Request): Promise<ResolvedPage | undefined>;
20
21
  export declare function resolvePageByName(name: string, pathname: string, request?: Request): Promise<ResolvedPage | undefined>;
22
+ export declare function resolveBreadcrumbs(pageName: string, pathname: string, localeCode: string, params: Record<string, string>, dynamic: DynamicRouteEntry | undefined, request: Request | undefined, visited?: Set<string>): Promise<BreadcrumbItem[]>;
@@ -31,7 +31,6 @@ function mergeHeadDefinitions(...heads) {
31
31
  }
32
32
  }
33
33
  }
34
- console.log("mergeHeadDefinitions", result);
35
34
  return result;
36
35
  }
37
36
  const dynamicRouteCache = /* @__PURE__ */ new Map();
@@ -318,6 +317,7 @@ export async function resolvePage(pathname, request) {
318
317
  const assign = match.localePage.dynamic?.assign;
319
318
  const resolvedContext = mergeResolvedContext(context, layoutContext.context, dynamic, assign);
320
319
  const head = mergeHeadDefinitions(layoutContext.head.global, layoutContext.head.layout, pageHead);
320
+ const breadcrumbs = await resolveBreadcrumbs(match.definition.name, pathname, match.localeCode, match.params, dynamic, request);
321
321
  return {
322
322
  definition: match.definition,
323
323
  locale,
@@ -328,7 +328,8 @@ export async function resolvePage(pathname, request) {
328
328
  dynamic,
329
329
  head,
330
330
  seo: head,
331
- context: resolvedContext
331
+ context: resolvedContext,
332
+ breadcrumbs
332
333
  };
333
334
  }
334
335
  return void 0;
@@ -351,6 +352,7 @@ export async function resolvePageByName(name, pathname, request) {
351
352
  const layoutContext = await resolveLayoutContext(definition, ctx);
352
353
  const context = localePage.context ? await localePage.context(ctx) : {};
353
354
  const head = mergeHeadDefinitions(layoutContext.head.global, layoutContext.head.layout, pageHead);
355
+ const breadcrumbs = await resolveBreadcrumbs(definition.name, pathname, localeCode, params, void 0, request);
354
356
  return {
355
357
  definition,
356
358
  locale,
@@ -360,8 +362,48 @@ export async function resolvePageByName(name, pathname, request) {
360
362
  params,
361
363
  head,
362
364
  seo: head,
363
- context: mergeResolvedContext(context, layoutContext.context)
365
+ context: mergeResolvedContext(context, layoutContext.context),
366
+ breadcrumbs
364
367
  };
365
368
  }
366
369
  return void 0;
367
370
  }
371
+ export async function resolveBreadcrumbs(pageName, pathname, localeCode, params, dynamic, request, visited = /* @__PURE__ */ new Set()) {
372
+ if (visited.has(pageName)) {
373
+ return [];
374
+ }
375
+ visited.add(pageName);
376
+ const definition = pageDefinitions.find((candidate) => candidate.name === pageName);
377
+ if (!definition) return [];
378
+ const localePage = definition.locales[localeCode];
379
+ if (!localePage || !localePage.breadcrumb) return [];
380
+ const locale = createLocale(localeCode);
381
+ const ctx = createContext(definition, locale, localePage, pathname, params, dynamic, request);
382
+ const result = await localePage.breadcrumb(ctx);
383
+ if (!result) return [];
384
+ let currentItems = [];
385
+ if (result.items) {
386
+ currentItems = result.items;
387
+ } else if (result.item) {
388
+ currentItems = [result.item];
389
+ }
390
+ for (const item of currentItems) {
391
+ if (!item.url || item.url === "#") {
392
+ item.url = await ctx.utils.getUrl(pageName, localeCode, { params });
393
+ }
394
+ }
395
+ let parentItems = [];
396
+ if (result.parent) {
397
+ let parentName = "";
398
+ let parentParams = params;
399
+ if (typeof result.parent === "string") {
400
+ parentName = result.parent;
401
+ } else {
402
+ parentName = result.parent.name;
403
+ parentParams = result.parent.params;
404
+ }
405
+ const parentPathname = await ctx.utils.getUrl(parentName, localeCode, { params: parentParams }) || "/";
406
+ parentItems = await resolveBreadcrumbs(parentName, parentPathname, localeCode, parentParams, void 0, request, visited);
407
+ }
408
+ return [...parentItems, ...currentItems];
409
+ }
@@ -103,7 +103,7 @@ async function renderBody(page) {
103
103
  page: page.definition,
104
104
  context: page.context,
105
105
  head: page.head,
106
- seo: page.seo,
106
+ seo: page.head.seo,
107
107
  locale: page.locale,
108
108
  params: page.params,
109
109
  path: page.pathname
@@ -142,6 +142,7 @@ ${cleanTrace}`);
142
142
  };
143
143
  app.provide("context", context);
144
144
  app.provide("utils", utils);
145
+ app.provide("breadcrumbs", page.breadcrumbs);
145
146
  const head = createHead();
146
147
  head.use(UnheadSchemaOrg());
147
148
  head.push({
@@ -150,7 +151,6 @@ ${cleanTrace}`);
150
151
  }
151
152
  });
152
153
  head.push(normalizeSeoToHead(page.head, fallbackTitle, fallbackDescription));
153
- console.log("head", head);
154
154
  app.use(head);
155
155
  installFlowVuePlugins(app);
156
156
  return {
@@ -169,7 +169,8 @@ export async function renderDocument(page, clientAssets) {
169
169
  title: fallbackTitle,
170
170
  locale: page.locale,
171
171
  mode,
172
- images: getFlowImageBootPayload()
172
+ images: getFlowImageBootPayload(),
173
+ breadcrumbs: page.breadcrumbs
173
174
  };
174
175
  const rendered = await renderBody(page);
175
176
  const body = stripVueFragmentMarkers(rendered.body);
@@ -1,6 +1,6 @@
1
1
  export type { ContentDirectoryNode, ContentEntry, ContentFileNode, ContentTreeNode, } from '../../modules/content/query.ts';
2
2
  export type { FlowBootPayload } from '../runtime/boot.ts';
3
- export { useContext, useGlobal, useLocale, usePage, useSeo, useSharedContext, useUtils, useView, } from '../runtime/composables.ts';
3
+ export { useContext, useGlobal, useHead, useLocale, usePage, useSeo, useSharedContext, useUrl, useUtils, useView, useBreadcrumb, } from '../runtime/composables.ts';
4
4
  export { defineFlowConfig, defineFlowModule, resolveFlowConfig } from '../runtime/config.ts';
5
5
  export type { FlowConfig, UserFlowConfig, } from '../runtime/config.ts';
6
6
  export { useSchemaOrg } from '../runtime/head.ts';
@@ -1,12 +1,15 @@
1
1
  export {
2
2
  useContext,
3
3
  useGlobal,
4
+ useHead,
4
5
  useLocale,
5
6
  usePage,
6
7
  useSeo,
7
8
  useSharedContext,
9
+ useUrl,
8
10
  useUtils,
9
- useView
11
+ useView,
12
+ useBreadcrumb
10
13
  } from "../runtime/composables.mjs";
11
14
  export { defineFlowConfig, defineFlowModule, resolveFlowConfig } from "../runtime/config.mjs";
12
15
  export { useSchemaOrg } from "../runtime/head.mjs";
@@ -343,6 +343,9 @@ export function createFlowViteConfig(options = {}) {
343
343
  const { imports: userImports, ...userAutoImport } = options.userFlowConfig?.autoImport || {};
344
344
  const uiOptions = options.userFlowConfig?.ui || {};
345
345
  return defineConfig({
346
+ define: {
347
+ "import.meta.env.FLOW_SITE_URL": JSON.stringify(flowConfig.siteUrl || "")
348
+ },
346
349
  plugins: [
347
350
  createFlowVirtualServerModules(projectRoot, flowConfig),
348
351
  createFlowVirtualClientPages(projectRoot),
@@ -378,12 +381,15 @@ export function createFlowViteConfig(options = {}) {
378
381
  "useSchemaOrg",
379
382
  "useContext",
380
383
  "useSeo",
384
+ "useHead",
381
385
  "useUtils",
382
386
  "useSharedContext",
383
387
  "useGlobal",
388
+ "useUrl",
384
389
  "useLocale",
385
390
  "usePage",
386
- "useView"
391
+ "useView",
392
+ "useBreadcrumb"
387
393
  ],
388
394
  ...mappedNitroImports
389
395
  },
@@ -1,17 +0,0 @@
1
- import type { FlowImageMeta, FlowImageOptions } from '../../modules/images/runtime/types.ts';
2
- import type { FlowHydrationMode, FlowLocale } from './pages';
3
- export interface FlowImageBootPayload {
4
- all: Record<string, FlowImageMeta>;
5
- options: FlowImageOptions;
6
- generateOutput: boolean;
7
- strapiURL?: string;
8
- }
9
- export interface FlowBootPayload {
10
- path: string;
11
- bundle: string;
12
- template: string;
13
- title: string;
14
- locale: FlowLocale;
15
- mode: FlowHydrationMode;
16
- images?: FlowImageBootPayload;
17
- }
@@ -1,9 +1,18 @@
1
- import type { FlowLocale, PageContextUtils, PageDefinition } from './pages.ts';
1
+ import type { BreadcrumbItem, FlowLocale, PageContextUtils, PageDefinition } from './pages.ts';
2
2
  export declare function useContext<T = any>(): T;
3
- export declare function useSeo<T = any>(): T;
3
+ export declare function useSeo(): any;
4
+ export declare function useHead<T = any>(): T;
4
5
  export declare function useUtils(): PageContextUtils;
5
6
  export declare function useSharedContext<T = any>(): T;
6
7
  export declare function useGlobal<T = any>(): T;
7
8
  export declare function useLocale(): FlowLocale;
8
9
  export declare function usePage(): PageDefinition;
9
10
  export declare function useView(): PageDefinition['view'];
11
+ export interface UrlInfo {
12
+ pathname: string;
13
+ siteUrl?: string;
14
+ href: string;
15
+ joinUrl: (...params: string[]) => string;
16
+ }
17
+ export declare function useUrl(): UrlInfo;
18
+ export declare function useBreadcrumb(): BreadcrumbItem[];
@@ -1,3 +1,4 @@
1
+ import { joinURL } from "ufo";
1
2
  import { inject } from "vue";
2
3
  export function useContext() {
3
4
  const ctx = inject("context", {});
@@ -10,6 +11,10 @@ export function useSeo() {
10
11
  const ctx = inject("context", {});
11
12
  return ctx.seo || {};
12
13
  }
14
+ export function useHead() {
15
+ const ctx = inject("context", {});
16
+ return ctx.head || {};
17
+ }
13
18
  export function useUtils() {
14
19
  return inject("utils", {});
15
20
  }
@@ -33,3 +38,24 @@ export function useView() {
33
38
  const ctx = inject("context", {});
34
39
  return { ...ctx.page?.view || {} };
35
40
  }
41
+ export function useUrl() {
42
+ const ctx = inject("context", {});
43
+ const pathname = ctx.path || "/";
44
+ const siteUrl = import.meta.env.FLOW_SITE_URL || void 0;
45
+ let href = pathname || "/";
46
+ if (siteUrl) {
47
+ const base = siteUrl.endsWith("/") ? siteUrl.slice(0, -1) : siteUrl;
48
+ const path = href.startsWith("/") ? href : `/${href}`;
49
+ href = base + path;
50
+ }
51
+ return {
52
+ pathname,
53
+ siteUrl,
54
+ href,
55
+ joinUrl: (...params) => joinURL(siteUrl || "", ...params)
56
+ };
57
+ }
58
+ export function useBreadcrumb() {
59
+ const breadcrumbs = inject("breadcrumbs", []);
60
+ return breadcrumbs;
61
+ }
@@ -61,6 +61,7 @@ async function hydrateIsland(element, boot) {
61
61
  const imageUtils = createBootImageUtils(boot);
62
62
  app.use(getClientHead());
63
63
  app.provide("utils", imageUtils);
64
+ app.provide("breadcrumbs", boot?.breadcrumbs || []);
64
65
  installFlowVuePlugins(app);
65
66
  app.mount(element);
66
67
  element.dataset.flowIslandHydrated = "true";
@@ -1,4 +1,4 @@
1
- import type { UseHeadInput } from '@unhead/vue';
1
+ import type { UseHeadInput, UseSeoMetaInput } from '@unhead/vue';
2
2
  export type MaybePromise<T> = T | Promise<T>;
3
3
  export interface FlowLocale {
4
4
  code: string;
@@ -36,7 +36,9 @@ export interface LegacySeoDefinition {
36
36
  */
37
37
  facebook?: boolean;
38
38
  }
39
- export type HeadDefinition = UseHeadInput & LegacySeoDefinition;
39
+ export type HeadDefinition = UseHeadInput & LegacySeoDefinition & {
40
+ seo: UseSeoMetaInput;
41
+ };
40
42
  /**
41
43
  * @deprecated Use HeadDefinition.
42
44
  */
@@ -105,6 +107,19 @@ export interface PageContextInput {
105
107
  utils: PageContextUtils;
106
108
  preview?: boolean;
107
109
  }
110
+ export interface BreadcrumbItem {
111
+ title: string;
112
+ caption?: string;
113
+ url?: string;
114
+ }
115
+ export interface BreadcrumbDefinition {
116
+ parent?: string | {
117
+ name: string;
118
+ params: Record<string, string>;
119
+ };
120
+ item?: BreadcrumbItem;
121
+ items?: BreadcrumbItem[];
122
+ }
108
123
  export interface PageLocaleDefinition {
109
124
  url: string;
110
125
  head?: (ctx: PageContextInput) => MaybePromise<HeadDefinition>;
@@ -113,6 +128,7 @@ export interface PageLocaleDefinition {
113
128
  */
114
129
  seo?: (ctx: PageContextInput) => MaybePromise<HeadDefinition>;
115
130
  context?: (ctx: PageContextInput) => MaybePromise<Record<string, unknown>>;
131
+ breadcrumb?: (ctx: PageContextInput) => MaybePromise<BreadcrumbDefinition>;
116
132
  dynamic?: DynamicRouteOptions;
117
133
  }
118
134
  export interface PageDefinition {
@@ -123,4 +123,4 @@ declare module 'virtual:flow/bases' {
123
123
  const bases: Record<string, string>;
124
124
 
125
125
  export default bases;
126
- }
126
+ }