@flamingo-stack/openframe-frontend-core 0.0.257 → 0.0.258

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.
@@ -4,7 +4,7 @@
4
4
 
5
5
 
6
6
 
7
- var _chunk4MXBBBHBcjs = require('../../chunk-4MXBBBHB.cjs');
7
+ var _chunkKQQDN2WKcjs = require('../../chunk-KQQDN2WK.cjs');
8
8
 
9
9
 
10
10
  var _chunkT7AJBKZPcjs = require('../../chunk-T7AJBKZP.cjs');
@@ -140,7 +140,7 @@ function OnboardingGuidesCatalogView({
140
140
  });
141
141
  };
142
142
  const source = _nullishCoalesce(_optionalChain([runtime, 'optionalAccess', _4 => _4.source]), () => ( "openframe"));
143
- const docSearch = _chunk4MXBBBHBcjs.useDocSearch.call(void 0, {
143
+ const docSearch = _chunkKQQDN2WKcjs.useDocSearch.call(void 0, {
144
144
  source,
145
145
  baseRoute: basePath,
146
146
  onNavigate: (path) => router.push(path),
@@ -166,7 +166,7 @@ function OnboardingGuidesCatalogView({
166
166
  const renderCardFn = _nullishCoalesce(renderCard, () => ( defaultRenderCard));
167
167
  const preControls = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "space-y-4", children: [
168
168
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
169
- _chunk4MXBBBHBcjs.DocSearchBar,
169
+ _chunkKQQDN2WKcjs.DocSearchBar,
170
170
  {
171
171
  placeholder: "Search onboarding guides, releases, case studies\u2026",
172
172
  query: docSearch.query,
@@ -238,7 +238,7 @@ function OnboardingGuideDetailView({
238
238
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkEB76VWM4cjs.LoadError, { message: "Guide not found.", onRetry: reload });
239
239
  }
240
240
  if (!guide) {
241
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4MXBBBHBcjs.DetailPageSkeleton, { showImageGallery: false });
241
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKQQDN2WKcjs.DetailPageSkeleton, { showImageGallery: false });
242
242
  }
243
243
  const captionsUrl = _chunkEB76VWM4cjs.getCaptionsUrl.call(void 0, "onboarding_guide", guide.id, guide.srt_content);
244
244
  const videoPoster = guide.main_video_thumbnail || guide.featured_image || guide.og_image_url || _optionalChain([runtime, 'optionalAccess', _9 => _9.resolvePlaceholderUrl, 'optionalCall', _10 => _10(guide.title, { aspect: "wide" })]) || void 0;
@@ -307,7 +307,7 @@ function OnboardingGuideDetailView({
307
307
  }
308
308
  ),
309
309
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
310
- _chunk4MXBBBHBcjs.ArticleAuthorByline,
310
+ _chunkKQQDN2WKcjs.ArticleAuthorByline,
311
311
  {
312
312
  author: _nullishCoalesce(_optionalChain([guide, 'access', _12 => _12.author, 'optionalAccess', _13 => _13.full_name]), () => ( null)),
313
313
  avatar: _optionalChain([guide, 'access', _14 => _14.author, 'optionalAccess', _15 => _15.avatar_url]),
@@ -4,7 +4,7 @@ import {
4
4
  DetailPageSkeleton,
5
5
  DocSearchBar,
6
6
  useDocSearch
7
- } from "../../chunk-IJHORDN5.js";
7
+ } from "../../chunk-ACJPRIZC.js";
8
8
  import {
9
9
  useSelfFetch
10
10
  } from "../../chunk-L4LAAA5Q.js";
@@ -2,10 +2,9 @@
2
2
  * Shared "author byline" card used by article-shaped detail pages
3
3
  * (blog post, product release, onboarding guide, investor update).
4
4
  *
5
- * MOVED from the hub (`components/shared/article-author-byline.tsx`) so any
6
- * consuming app can embed it; the hub keeps a thin wrapper that pre-binds its
7
- * host-specific injections (the platform-aware `fallbackBio` default derived
8
- * from `getAppConfig()`).
5
+ * MOVED from the hub so any consuming app can embed it; hub call sites
6
+ * import it directly and pass their platform-aware copy explicitly
7
+ * (`fallbackBio={defaultAuthorFallbackBio()}` from the hub's app-config).
9
8
  *
10
9
  * Embed-readiness contract:
11
10
  * - `Link` / `Image` render through the embed-shims (plain `<a>` / `<img>`
@@ -1 +1 @@
1
- {"version":3,"file":"article-author-byline.d.ts","sourceRoot":"","sources":["../../../src/components/shared/article-author-byline.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAA;AASzB,MAAM,WAAW,wBAAwB;IACvC,uEAAuE;IACvE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,sDAAsD;IACtD,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAClC,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,+DAA+D;IAC/D,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;IAClB;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IACvC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAiBD,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,MAAM,EACN,GAAG,EACH,QAAQ,EACR,WAAW,EACX,IAAI,EACJ,WAAW,EACX,IAAW,EACX,aAAa,EACb,SAAS,GACV,EAAE,wBAAwB,4BA4F1B"}
1
+ {"version":3,"file":"article-author-byline.d.ts","sourceRoot":"","sources":["../../../src/components/shared/article-author-byline.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAA;AASzB,MAAM,WAAW,wBAAwB;IACvC,uEAAuE;IACvE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,sDAAsD;IACtD,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAClC,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,+DAA+D;IAC/D,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;IAClB;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IACvC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAiBD,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,MAAM,EACN,GAAG,EACH,QAAQ,EACR,WAAW,EACX,IAAI,EACJ,WAAW,EACX,IAAW,EACX,aAAa,EACb,SAAS,GACV,EAAE,wBAAwB,4BA4F1B"}
@@ -18,4 +18,29 @@ export interface EntityAuthor {
18
18
  /** Present only on server/admin payloads — public DALs strip it. */
19
19
  email?: string | null;
20
20
  }
21
+ /** One curated social link on an author profile (host junction:
22
+ * `profile_social_links` ordered by display_order in the hub). */
23
+ export interface AuthorSocialLink {
24
+ /** Platform key fed to `SocialIconRow` (e.g. 'linkedin', 'x'). */
25
+ platform: string;
26
+ url: string;
27
+ username?: string | null;
28
+ }
29
+ /**
30
+ * Public author-page view model — what `<AuthorDetailView>` renders. The
31
+ * hub's `PublicAuthor` (authors DAL) extends this with server-side extras
32
+ * (`updatedAt`); embedders construct it from whatever directory they have.
33
+ */
34
+ export interface AuthorProfile {
35
+ id: string;
36
+ slug: string;
37
+ fullName: string;
38
+ avatarUrl: string | null;
39
+ about: string | null;
40
+ jobTitle: string | null;
41
+ company: string | null;
42
+ knowsAbout: string[];
43
+ /** Ordered by display_order. */
44
+ socialLinks: AuthorSocialLink[];
45
+ }
21
46
  //# sourceMappingURL=entity-author.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entity-author.d.ts","sourceRoot":"","sources":["../../src/types/entity-author.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB;2EACuE;IACvE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB;8EAC0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB"}
1
+ {"version":3,"file":"entity-author.d.ts","sourceRoot":"","sources":["../../src/types/entity-author.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB;2EACuE;IACvE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB;8EAC0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAED;mEACmE;AACnE,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,gCAAgC;IAChC,WAAW,EAAE,gBAAgB,EAAE,CAAA;CAChC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flamingo-stack/openframe-frontend-core",
3
- "version": "0.0.257",
3
+ "version": "0.0.258",
4
4
  "description": "Shared design system and components for all Flamingo platforms",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,130 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * Author detail-page body — identity header (avatar → name → job title →
5
+ * socials), bio, expertise badges, and a `children` slot for the authored-
6
+ * content rail. THE one implementation behind the hub's `/authors/[slug]`
7
+ * page AND embedded author pages (react-embedding-example) — hosts fetch
8
+ * the `AuthorProfile` however they like and drill it in.
9
+ *
10
+ * Embed-readiness contract (same rules as ArticleAuthorByline):
11
+ * - `Image` renders through the embed shim (plain `<img>` in non-Next
12
+ * hosts; the real `next/image` once registered at app init).
13
+ * - Avatar proxying rides the OPTIONAL ambient `ChatRuntime`
14
+ * (`endpoints.imageProxyUrlPrefix`) — no provider ⇒ raw URL, never
15
+ * throws. `proxyImageUrl` prop wins over the runtime.
16
+ * - The authored-content rail is a SLOT (`children`), not a baked-in
17
+ * fetch: the hub passes its pre-bound `RelatedContentSection` with SSR
18
+ * `initialItems`; embedders pass the lib section with `apiBaseUrl`.
19
+ * The view stays data-in, markup-out.
20
+ *
21
+ * Heading semantics are the HOST's: the view renders the name as a styled
22
+ * `<p>` (like the hub profile header) so a hosting page can own its `<h1>`
23
+ * (the hub uses an sr-only h1 for crawlers).
24
+ */
25
+
26
+ import React from 'react'
27
+ import Image from '../../embed-shims/next-image'
28
+ import { cn } from '../../utils/cn'
29
+ import { formatBioText } from '../../utils/format'
30
+ import { getProxiedImageUrl } from '../../utils/image-proxy'
31
+ import { useChatRuntime } from '../../contexts/chat-runtime-context'
32
+ import { SocialIconRow } from '../social-icon-row'
33
+ import { StatusBadge } from '../ui/status-badge'
34
+ import type { AuthorProfile } from '../../types/entity-author'
35
+
36
+ export interface AuthorDetailViewProps {
37
+ author: AuthorProfile
38
+ /** Host-injected avatar-URL mapper — wins over the ambient runtime. */
39
+ proxyImageUrl?: (url: string) => string
40
+ /** Authored-content rail (or anything else) rendered below the profile. */
41
+ children?: React.ReactNode
42
+ className?: string
43
+ }
44
+
45
+ export function AuthorDetailView({
46
+ author,
47
+ proxyImageUrl,
48
+ children,
49
+ className,
50
+ }: AuthorDetailViewProps) {
51
+ // Optional runtime — null-safe outside a provider (bare embeds render the
52
+ // raw avatar URL; the hub's app-wide HubRuntimeProvider supplies the proxy).
53
+ const runtime = useChatRuntime()
54
+
55
+ const proxiedAvatar = author.avatarUrl
56
+ ? proxyImageUrl
57
+ ? proxyImageUrl(author.avatarUrl)
58
+ : (getProxiedImageUrl(author.avatarUrl, {
59
+ proxyPrefix: runtime?.endpoints.imageProxyUrlPrefix,
60
+ skipDomains: runtime?.endpoints.imageProxySkipDomains,
61
+ directHttps: true,
62
+ }) ?? author.avatarUrl)
63
+ : null
64
+
65
+ const subtitle = [author.jobTitle, author.company].filter(Boolean).join(' @ ')
66
+ const bioText = formatBioText(author.about)
67
+
68
+ return (
69
+ <div className={cn('flex flex-col gap-5 md:gap-6', className)}>
70
+ {/* Identity header: avatar left; name → subtitle → socials stacked right. */}
71
+ <div className="flex gap-6 w-full items-start">
72
+ <div className="relative shrink-0 h-24 w-24">
73
+ <div className="rounded-full overflow-hidden bg-ods-bg-secondary border border-ods-border w-full h-full relative">
74
+ {proxiedAvatar ? (
75
+ <Image
76
+ src={proxiedAvatar}
77
+ alt={author.fullName}
78
+ fill
79
+ className="object-cover"
80
+ unoptimized
81
+ />
82
+ ) : (
83
+ <div className="flex items-center justify-center h-full w-full text-3xl text-ods-text-secondary font-['Azeret_Mono']">
84
+ {author.fullName.charAt(0).toUpperCase()}
85
+ </div>
86
+ )}
87
+ </div>
88
+ </div>
89
+
90
+ <div className="min-w-0 flex flex-col justify-center gap-2">
91
+ <p className="text-h2 text-ods-text-primary leading-none truncate">
92
+ {author.fullName}
93
+ </p>
94
+ {subtitle && (
95
+ <p className="font-body text-lg text-ods-text-secondary leading-none truncate">
96
+ {subtitle}
97
+ </p>
98
+ )}
99
+ {author.socialLinks.length > 0 && (
100
+ // Ghost compact row (transparent 32px) — metadata, not CTAs.
101
+ <SocialIconRow
102
+ compact
103
+ links={author.socialLinks.map((link) => ({
104
+ platform: link.platform,
105
+ href: link.url,
106
+ label: `${author.fullName}'s ${link.platform}`,
107
+ }))}
108
+ />
109
+ )}
110
+ </div>
111
+ </div>
112
+
113
+ {bioText && (
114
+ <p className="font-body text-base leading-relaxed text-ods-text-secondary">
115
+ {bioText}
116
+ </p>
117
+ )}
118
+
119
+ {author.knowsAbout.length > 0 && (
120
+ <div className="flex flex-wrap gap-2">
121
+ {author.knowsAbout.map((topic) => (
122
+ <StatusBadge key={topic} text={topic} variant="button" colorScheme="cyan" singleLine />
123
+ ))}
124
+ </div>
125
+ )}
126
+
127
+ {children}
128
+ </div>
129
+ )
130
+ }
@@ -91,9 +91,14 @@ export * from './shared/legal-document'
91
91
  export { DetailPageSkeleton, type DetailPageSkeletonProps } from './shared/detail-page-skeleton'
92
92
 
93
93
  // Author byline card (end-of-article author description) — embeddable via
94
- // embed-shims + optional-runtime avatar proxying; the hub wraps it to inject
95
- // its platform-aware fallbackBio default.
94
+ // embed-shims + optional-runtime avatar proxying; hosts pass their own
95
+ // fallbackBio copy (the hub uses defaultAuthorFallbackBio()).
96
96
  export { ArticleAuthorByline, type ArticleAuthorBylineProps } from './shared/article-author-byline'
97
97
 
98
+ // Author detail-page body (identity + socials + bio + expertise, rail as
99
+ // children) — the one implementation behind /authors/[slug] and embedded
100
+ // author pages.
101
+ export { AuthorDetailView, type AuthorDetailViewProps } from './authors/author-detail-view'
102
+
98
103
  // Priority UI components that exist in main components directory
99
104
  // Note: These are re-exported from ./ui already, no need to duplicate
@@ -4,10 +4,9 @@
4
4
  * Shared "author byline" card used by article-shaped detail pages
5
5
  * (blog post, product release, onboarding guide, investor update).
6
6
  *
7
- * MOVED from the hub (`components/shared/article-author-byline.tsx`) so any
8
- * consuming app can embed it; the hub keeps a thin wrapper that pre-binds its
9
- * host-specific injections (the platform-aware `fallbackBio` default derived
10
- * from `getAppConfig()`).
7
+ * MOVED from the hub so any consuming app can embed it; hub call sites
8
+ * import it directly and pass their platform-aware copy explicitly
9
+ * (`fallbackBio={defaultAuthorFallbackBio()}` from the hub's app-config).
11
10
  *
12
11
  * Embed-readiness contract:
13
12
  * - `Link` / `Image` render through the embed-shims (plain `<a>` / `<img>`
@@ -18,3 +18,30 @@ export interface EntityAuthor {
18
18
  /** Present only on server/admin payloads — public DALs strip it. */
19
19
  email?: string | null
20
20
  }
21
+
22
+ /** One curated social link on an author profile (host junction:
23
+ * `profile_social_links` ordered by display_order in the hub). */
24
+ export interface AuthorSocialLink {
25
+ /** Platform key fed to `SocialIconRow` (e.g. 'linkedin', 'x'). */
26
+ platform: string
27
+ url: string
28
+ username?: string | null
29
+ }
30
+
31
+ /**
32
+ * Public author-page view model — what `<AuthorDetailView>` renders. The
33
+ * hub's `PublicAuthor` (authors DAL) extends this with server-side extras
34
+ * (`updatedAt`); embedders construct it from whatever directory they have.
35
+ */
36
+ export interface AuthorProfile {
37
+ id: string
38
+ slug: string
39
+ fullName: string
40
+ avatarUrl: string | null
41
+ about: string | null
42
+ jobTitle: string | null
43
+ company: string | null
44
+ knowsAbout: string[]
45
+ /** Ordered by display_order. */
46
+ socialLinks: AuthorSocialLink[]
47
+ }