@flamingo-stack/openframe-frontend-core 0.0.305 → 0.0.306

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.
Files changed (80) hide show
  1. package/dist/{chunk-DVVQY4VI.cjs → chunk-2YYAKVL7.cjs} +12 -12
  2. package/dist/{chunk-DVVQY4VI.cjs.map → chunk-2YYAKVL7.cjs.map} +1 -1
  3. package/dist/{chunk-AGJPN5RS.js → chunk-46KRPHHL.js} +2 -2
  4. package/dist/{chunk-OYAALXG6.cjs → chunk-4OY3ALHJ.cjs} +28 -28
  5. package/dist/{chunk-OYAALXG6.cjs.map → chunk-4OY3ALHJ.cjs.map} +1 -1
  6. package/dist/{chunk-TFEXHBJE.cjs → chunk-4RHOLPFU.cjs} +14 -14
  7. package/dist/{chunk-TFEXHBJE.cjs.map → chunk-4RHOLPFU.cjs.map} +1 -1
  8. package/dist/{chunk-SR6ZSDOP.cjs → chunk-4RI7S6ZD.cjs} +9 -9
  9. package/dist/{chunk-SR6ZSDOP.cjs.map → chunk-4RI7S6ZD.cjs.map} +1 -1
  10. package/dist/{chunk-KCID66IW.js → chunk-5OFBD6EQ.js} +2 -2
  11. package/dist/{chunk-3NDFB23M.cjs → chunk-6TRTIHGW.cjs} +27 -2
  12. package/dist/chunk-6TRTIHGW.cjs.map +1 -0
  13. package/dist/{chunk-UN7RFOZI.cjs → chunk-AIHM4TT7.cjs} +5 -5
  14. package/dist/{chunk-UN7RFOZI.cjs.map → chunk-AIHM4TT7.cjs.map} +1 -1
  15. package/dist/{chunk-TKGSUJZF.cjs → chunk-CKFHYXSJ.cjs} +7 -7
  16. package/dist/{chunk-TKGSUJZF.cjs.map → chunk-CKFHYXSJ.cjs.map} +1 -1
  17. package/dist/{chunk-QHOX4JWP.js → chunk-E7FIV5LH.js} +2 -2
  18. package/dist/{chunk-UEGSCIAW.js → chunk-ER4CMF47.js} +26 -1
  19. package/dist/chunk-ER4CMF47.js.map +1 -0
  20. package/dist/{chunk-L3JKIAQX.cjs → chunk-J3YKVLQ5.cjs} +26 -26
  21. package/dist/{chunk-L3JKIAQX.cjs.map → chunk-J3YKVLQ5.cjs.map} +1 -1
  22. package/dist/{chunk-NG6YEOHW.js → chunk-N3YPIZBH.js} +2 -2
  23. package/dist/{chunk-EEVOKQGR.js → chunk-NATCXYJK.js} +4 -4
  24. package/dist/{chunk-VP4VKYR2.cjs → chunk-PLFQJ5E7.cjs} +37 -37
  25. package/dist/{chunk-VP4VKYR2.cjs.map → chunk-PLFQJ5E7.cjs.map} +1 -1
  26. package/dist/{chunk-KKSZQLGC.js → chunk-QPTJOLAP.js} +2 -2
  27. package/dist/{chunk-GC4CNBTS.js → chunk-QWMYOUGP.js} +2 -2
  28. package/dist/{chunk-7QHSLXTB.js → chunk-WSEK6W4B.js} +2 -2
  29. package/dist/components/case-studies/index.cjs +8 -8
  30. package/dist/components/case-studies/index.js +2 -2
  31. package/dist/components/chat/index.cjs +2 -2
  32. package/dist/components/chat/index.js +1 -1
  33. package/dist/components/contact/index.cjs +3 -3
  34. package/dist/components/contact/index.js +2 -2
  35. package/dist/components/docs/index.cjs +5 -5
  36. package/dist/components/docs/index.js +4 -4
  37. package/dist/components/embeds/index.cjs +3 -3
  38. package/dist/components/embeds/index.js +2 -2
  39. package/dist/components/faq/index.cjs +3 -3
  40. package/dist/components/faq/index.js +2 -2
  41. package/dist/components/features/index.cjs +2 -2
  42. package/dist/components/features/index.js +1 -1
  43. package/dist/components/features/seo-editor-preview.d.ts.map +1 -1
  44. package/dist/components/index.cjs +172 -172
  45. package/dist/components/index.js +8 -8
  46. package/dist/components/navigation/index.cjs +2 -2
  47. package/dist/components/navigation/index.js +1 -1
  48. package/dist/components/onboarding-guides/index.cjs +23 -23
  49. package/dist/components/onboarding-guides/index.js +3 -3
  50. package/dist/components/related-content/index.cjs +3 -3
  51. package/dist/components/related-content/index.js +2 -2
  52. package/dist/components/tickets/index.cjs +60 -60
  53. package/dist/components/tickets/index.js +3 -3
  54. package/dist/components/ui/index.cjs +2 -2
  55. package/dist/components/ui/index.js +1 -1
  56. package/dist/index.cjs +4 -2
  57. package/dist/index.cjs.map +1 -1
  58. package/dist/index.js +3 -1
  59. package/dist/utils/index.cjs +4 -0
  60. package/dist/utils/index.cjs.map +1 -1
  61. package/dist/utils/index.d.ts +1 -0
  62. package/dist/utils/index.d.ts.map +1 -1
  63. package/dist/utils/index.js +4 -1
  64. package/dist/utils/index.js.map +1 -1
  65. package/dist/utils/seo-title.d.ts +15 -0
  66. package/dist/utils/seo-title.d.ts.map +1 -0
  67. package/package.json +1 -1
  68. package/src/components/features/seo-editor-preview.tsx +24 -0
  69. package/src/utils/index.ts +3 -0
  70. package/src/utils/seo-title.ts +14 -0
  71. package/dist/chunk-3NDFB23M.cjs.map +0 -1
  72. package/dist/chunk-UEGSCIAW.js.map +0 -1
  73. /package/dist/{chunk-AGJPN5RS.js.map → chunk-46KRPHHL.js.map} +0 -0
  74. /package/dist/{chunk-KCID66IW.js.map → chunk-5OFBD6EQ.js.map} +0 -0
  75. /package/dist/{chunk-QHOX4JWP.js.map → chunk-E7FIV5LH.js.map} +0 -0
  76. /package/dist/{chunk-NG6YEOHW.js.map → chunk-N3YPIZBH.js.map} +0 -0
  77. /package/dist/{chunk-EEVOKQGR.js.map → chunk-NATCXYJK.js.map} +0 -0
  78. /package/dist/{chunk-KKSZQLGC.js.map → chunk-QPTJOLAP.js.map} +0 -0
  79. /package/dist/{chunk-GC4CNBTS.js.map → chunk-QWMYOUGP.js.map} +0 -0
  80. /package/dist/{chunk-7QHSLXTB.js.map → chunk-WSEK6W4B.js.map} +0 -0
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Single source of truth for the `seo_title` length budget.
3
+ *
4
+ * The `seo_title` is rendered as the page `<title>` VERBATIM — no brand suffix is
5
+ * appended to it (the `| <Brand>` suffix is kept only on the default/actual-title
6
+ * fallback). So this is the full rendered-title budget; search engines truncate
7
+ * page titles around 60 chars.
8
+ *
9
+ * This number lives in exactly ONE place. Consumers:
10
+ * - `SEOEditorPreview` — input `maxLength` + the too-long alert.
11
+ * - the hub — imports it (via `@flamingo-stack/openframe-frontend-core/utils`)
12
+ * for the AI generation prompt guidance and the DB CHECK value.
13
+ */
14
+ export declare const SEO_TITLE_MAX_LENGTH = 60;
15
+ //# sourceMappingURL=seo-title.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seo-title.d.ts","sourceRoot":"","sources":["../../src/utils/seo-title.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flamingo-stack/openframe-frontend-core",
3
- "version": "0.0.305",
3
+ "version": "0.0.306",
4
4
  "description": "Shared design system and components for all Flamingo platforms",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -6,6 +6,9 @@ import { ConfidenceBadge } from '../features';
6
6
  import { Globe, ExternalLink, Upload, X, Loader2, Sparkles } from 'lucide-react';
7
7
  import { cn } from '../../utils';
8
8
  import Image from '../../embed-shims/next-image';
9
+ // SSOT for the field cap (server-safe constant). The seo_title renders as the
10
+ // page <title> verbatim (no brand suffix), so this is the full ~60-char budget.
11
+ import { SEO_TITLE_MAX_LENGTH } from '../../utils/seo-title';
9
12
 
10
13
  export interface SEOEditorPreviewProps {
11
14
  // SEO fields - must be strings (not undefined)
@@ -68,6 +71,10 @@ export function SEOEditorPreview({
68
71
  const [isUploading, setIsUploading] = useState(false);
69
72
  const [fileInputRef, setFileInputRef] = useState<HTMLInputElement | null>(null);
70
73
 
74
+ // SEO title length state — alerts the editor when the title would render too long.
75
+ const seoTitleLength = (seoTitle || '').length;
76
+ const seoTitleTooLong = seoTitleLength > SEO_TITLE_MAX_LENGTH;
77
+
71
78
  // Use fallback values if OG fields are empty
72
79
  const displayTitle = seoTitle.trim() || title || 'Untitled';
73
80
  const displayDescription = seoDescription.trim() || summary || 'No description';
@@ -124,9 +131,26 @@ export function SEOEditorPreview({
124
131
  value={seoTitle || ''}
125
132
  onChange={(e) => onSeoTitleChange(e.target.value)}
126
133
  disabled={disabled}
134
+ maxLength={SEO_TITLE_MAX_LENGTH}
135
+ invalid={seoTitleTooLong}
127
136
  placeholder="Enter SEO meta title..."
128
137
  className="bg-ods-bg border-ods-border text-ods-text-primary"
129
138
  />
139
+ <div className="flex items-center justify-between gap-2">
140
+ <span className="text-[11px] text-ods-error font-['DM_Sans']">
141
+ {seoTitleTooLong
142
+ ? `Too long — search engines may truncate this title (keep it ≤ ${SEO_TITLE_MAX_LENGTH})`
143
+ : ''}
144
+ </span>
145
+ <span
146
+ className={cn(
147
+ "text-[11px] font-['DM_Sans'] tabular-nums shrink-0",
148
+ seoTitleTooLong ? 'text-ods-error font-semibold' : 'text-ods-text-secondary'
149
+ )}
150
+ >
151
+ {seoTitleLength}/{SEO_TITLE_MAX_LENGTH}
152
+ </span>
153
+ </div>
130
154
  {!seoTitle && title && (
131
155
  <p className="text-[11px] text-ods-accent font-['DM_Sans']">
132
156
  Auto-populated from title
@@ -26,6 +26,9 @@ export {
26
26
  } from './ods-color-utils'
27
27
  export { delay, generateRandomString, truncateString, deepClone, getSlackCommunityJoinUrl, serializeJsonLd } from './common'
28
28
  export { getBaseUrl } from '../utils/cn'
29
+ // SEO title length budget — server-safe constant (SSOT). Consumed by the hub
30
+ // (prompt guidance + DB check value) and by SEOEditorPreview (input maxLength).
31
+ export { SEO_TITLE_MAX_LENGTH } from './seo-title'
29
32
 
30
33
  export * from './platform-config'
31
34
  export * from './os-platforms'
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Single source of truth for the `seo_title` length budget.
3
+ *
4
+ * The `seo_title` is rendered as the page `<title>` VERBATIM — no brand suffix is
5
+ * appended to it (the `| <Brand>` suffix is kept only on the default/actual-title
6
+ * fallback). So this is the full rendered-title budget; search engines truncate
7
+ * page titles around 60 chars.
8
+ *
9
+ * This number lives in exactly ONE place. Consumers:
10
+ * - `SEOEditorPreview` — input `maxLength` + the too-long alert.
11
+ * - the hub — imports it (via `@flamingo-stack/openframe-frontend-core/utils`)
12
+ * for the AI generation prompt guidance and the DB CHECK value.
13
+ */
14
+ export const SEO_TITLE_MAX_LENGTH = 60;