@monkeyplus/flow 6.0.56 → 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.56",
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[]>;
@@ -317,6 +317,7 @@ export async function resolvePage(pathname, request) {
317
317
  const assign = match.localePage.dynamic?.assign;
318
318
  const resolvedContext = mergeResolvedContext(context, layoutContext.context, dynamic, assign);
319
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);
320
321
  return {
321
322
  definition: match.definition,
322
323
  locale,
@@ -327,7 +328,8 @@ export async function resolvePage(pathname, request) {
327
328
  dynamic,
328
329
  head,
329
330
  seo: head,
330
- context: resolvedContext
331
+ context: resolvedContext,
332
+ breadcrumbs
331
333
  };
332
334
  }
333
335
  return void 0;
@@ -350,6 +352,7 @@ export async function resolvePageByName(name, pathname, request) {
350
352
  const layoutContext = await resolveLayoutContext(definition, ctx);
351
353
  const context = localePage.context ? await localePage.context(ctx) : {};
352
354
  const head = mergeHeadDefinitions(layoutContext.head.global, layoutContext.head.layout, pageHead);
355
+ const breadcrumbs = await resolveBreadcrumbs(definition.name, pathname, localeCode, params, void 0, request);
353
356
  return {
354
357
  definition,
355
358
  locale,
@@ -359,8 +362,48 @@ export async function resolvePageByName(name, pathname, request) {
359
362
  params,
360
363
  head,
361
364
  seo: head,
362
- context: mergeResolvedContext(context, layoutContext.context)
365
+ context: mergeResolvedContext(context, layoutContext.context),
366
+ breadcrumbs
363
367
  };
364
368
  }
365
369
  return void 0;
366
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
+ }
@@ -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({
@@ -168,7 +169,8 @@ export async function renderDocument(page, clientAssets) {
168
169
  title: fallbackTitle,
169
170
  locale: page.locale,
170
171
  mode,
171
- images: getFlowImageBootPayload()
172
+ images: getFlowImageBootPayload(),
173
+ breadcrumbs: page.breadcrumbs
172
174
  };
173
175
  const rendered = await renderBody(page);
174
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, useHead, 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';
@@ -6,8 +6,10 @@ export {
6
6
  usePage,
7
7
  useSeo,
8
8
  useSharedContext,
9
+ useUrl,
9
10
  useUtils,
10
- useView
11
+ useView,
12
+ useBreadcrumb
11
13
  } from "../runtime/composables.mjs";
12
14
  export { defineFlowConfig, defineFlowModule, resolveFlowConfig } from "../runtime/config.mjs";
13
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),
@@ -382,9 +385,11 @@ export function createFlowViteConfig(options = {}) {
382
385
  "useUtils",
383
386
  "useSharedContext",
384
387
  "useGlobal",
388
+ "useUrl",
385
389
  "useLocale",
386
390
  "usePage",
387
- "useView"
391
+ "useView",
392
+ "useBreadcrumb"
388
393
  ],
389
394
  ...mappedNitroImports
390
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,4 +1,4 @@
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
3
  export declare function useSeo(): any;
4
4
  export declare function useHead<T = any>(): T;
@@ -8,3 +8,11 @@ export declare function useGlobal<T = any>(): T;
8
8
  export declare function useLocale(): FlowLocale;
9
9
  export declare function usePage(): PageDefinition;
10
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", {});
@@ -37,3 +38,24 @@ export function useView() {
37
38
  const ctx = inject("context", {});
38
39
  return { ...ctx.page?.view || {} };
39
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";
@@ -107,6 +107,19 @@ export interface PageContextInput {
107
107
  utils: PageContextUtils;
108
108
  preview?: boolean;
109
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
+ }
110
123
  export interface PageLocaleDefinition {
111
124
  url: string;
112
125
  head?: (ctx: PageContextInput) => MaybePromise<HeadDefinition>;
@@ -115,6 +128,7 @@ export interface PageLocaleDefinition {
115
128
  */
116
129
  seo?: (ctx: PageContextInput) => MaybePromise<HeadDefinition>;
117
130
  context?: (ctx: PageContextInput) => MaybePromise<Record<string, unknown>>;
131
+ breadcrumb?: (ctx: PageContextInput) => MaybePromise<BreadcrumbDefinition>;
118
132
  dynamic?: DynamicRouteOptions;
119
133
  }
120
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
+ }