create-nextblock 0.15.5 → 0.15.9

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 (79) hide show
  1. package/package.json +50 -26
  2. package/templates/nextblock-template/app/ToasterProvider.tsx +26 -17
  3. package/templates/nextblock-template/app/actions/contactSellerActions.test.ts +280 -0
  4. package/templates/nextblock-template/app/actions/contactSellerActions.ts +222 -0
  5. package/templates/nextblock-template/app/actions/email-retry.test.ts +62 -0
  6. package/templates/nextblock-template/app/actions/email.ts +241 -110
  7. package/templates/nextblock-template/app/actions/formActions.ts +245 -116
  8. package/templates/nextblock-template/app/actions/interactions.ts +489 -396
  9. package/templates/nextblock-template/app/actions/threadActions.ts +166 -0
  10. package/templates/nextblock-template/app/api/checkout/route.ts +162 -146
  11. package/templates/nextblock-template/app/api/cron/reset-sandbox/route.ts +14 -0
  12. package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +664 -1
  13. package/templates/nextblock-template/app/checkout/page.tsx +57 -52
  14. package/templates/nextblock-template/app/cms/CmsClientLayout.tsx +552 -529
  15. package/templates/nextblock-template/app/cms/blocks/editors/FormBlockEditor.tsx +304 -181
  16. package/templates/nextblock-template/app/cms/components/ContactReminderBanner.tsx +75 -0
  17. package/templates/nextblock-template/app/cms/components/PaymentsReminderBanner.tsx +58 -0
  18. package/templates/nextblock-template/app/cms/components/VisibilityControl.tsx +542 -528
  19. package/templates/nextblock-template/app/cms/inquiries/actions.ts +66 -0
  20. package/templates/nextblock-template/app/cms/inquiries/page.tsx +12 -0
  21. package/templates/nextblock-template/app/cms/interactions/page.tsx +12 -51
  22. package/templates/nextblock-template/app/cms/layout.tsx +101 -73
  23. package/templates/nextblock-template/app/cms/messages/MessagesClient.tsx +661 -0
  24. package/templates/nextblock-template/app/cms/messages/actions.ts +404 -0
  25. package/templates/nextblock-template/app/cms/messages/loadInbox.ts +333 -0
  26. package/templates/nextblock-template/app/cms/messages/page.tsx +87 -0
  27. package/templates/nextblock-template/app/cms/messages/require-admin.ts +37 -0
  28. package/templates/nextblock-template/app/cms/products/[id]/edit/page.tsx +370 -362
  29. package/templates/nextblock-template/app/cms/revisions/service.ts +20 -0
  30. package/templates/nextblock-template/app/cms/settings/email/components/EmailForm.tsx +227 -185
  31. package/templates/nextblock-template/app/layout.tsx +671 -667
  32. package/templates/nextblock-template/app/lib/seo.ts +319 -311
  33. package/templates/nextblock-template/app/product/[slug]/page.tsx +502 -482
  34. package/templates/nextblock-template/app/providers.tsx +96 -96
  35. package/templates/nextblock-template/app/thread/ThreadView.tsx +164 -0
  36. package/templates/nextblock-template/app/thread/[token]/route.ts +57 -0
  37. package/templates/nextblock-template/app/thread/layout.tsx +15 -0
  38. package/templates/nextblock-template/app/thread/page.tsx +98 -0
  39. package/templates/nextblock-template/components/BlockRenderer.tsx +312 -296
  40. package/templates/nextblock-template/components/ContactSellerSection.tsx +188 -0
  41. package/templates/nextblock-template/components/PostCommentsSection.tsx +378 -369
  42. package/templates/nextblock-template/components/ProductReviewsSection.tsx +426 -419
  43. package/templates/nextblock-template/components/StaffReplies.tsx +102 -0
  44. package/templates/nextblock-template/components/blocks/renderers/CartBlockRenderer.tsx +18 -17
  45. package/templates/nextblock-template/components/blocks/renderers/CheckoutBlockRenderer.tsx +20 -19
  46. package/templates/nextblock-template/components/blocks/renderers/FeaturedProductBlockRenderer.tsx +25 -22
  47. package/templates/nextblock-template/components/blocks/renderers/FormBlockRenderer.tsx +385 -381
  48. package/templates/nextblock-template/components/blocks/renderers/ProductDetailsBlockRenderer.tsx +157 -92
  49. package/templates/nextblock-template/components/blocks/renderers/ProductGridBlockRenderer.tsx +34 -31
  50. package/templates/nextblock-template/components/blocks/renderers/SectionBlockRenderer.tsx +612 -600
  51. package/templates/nextblock-template/components/commerce/PaymentReadinessBoundary.tsx +32 -0
  52. package/templates/nextblock-template/docs/05-DEVELOPER-GUIDE.md +25 -19
  53. package/templates/nextblock-template/docs/06-CLI-AND-SCAFFOLDING.md +1 -1
  54. package/templates/nextblock-template/docs/08-NEXTBLOCK-CORTEX-AI-ARCHITECTURE.md +2 -2
  55. package/templates/nextblock-template/docs/12-VERCEL-DEPLOYMENT.md +32 -9
  56. package/templates/nextblock-template/docs/14-MESSAGES-INBOX.md +309 -0
  57. package/templates/nextblock-template/docs/README.md +42 -41
  58. package/templates/nextblock-template/docs/TECHNICAL_SPECIFICATION.md +540 -542
  59. package/templates/nextblock-template/docs/assets/lighthouse-scores.png +0 -0
  60. package/templates/nextblock-template/lib/blocks/blockColors.test.ts +22 -2
  61. package/templates/nextblock-template/lib/blocks/blockColors.ts +44 -1
  62. package/templates/nextblock-template/lib/blocks/blockRegistry.ts +761 -753
  63. package/templates/nextblock-template/lib/cms/contact-reminder.ts +64 -0
  64. package/templates/nextblock-template/lib/cms/payments-reminder.ts +98 -0
  65. package/templates/nextblock-template/lib/cms/unread-messages.ts +42 -0
  66. package/templates/nextblock-template/lib/commerce/seller-contact.ts +162 -0
  67. package/templates/nextblock-template/lib/config/email-settings.ts +323 -254
  68. package/templates/nextblock-template/lib/config/email-tls.test.ts +57 -0
  69. package/templates/nextblock-template/lib/email/placeholder-address.test.ts +59 -0
  70. package/templates/nextblock-template/lib/email/placeholder-address.ts +39 -0
  71. package/templates/nextblock-template/lib/messages/thread-reference.test.ts +70 -0
  72. package/templates/nextblock-template/lib/messages/thread-token.test.ts +93 -0
  73. package/templates/nextblock-template/lib/messages/thread-token.ts +157 -0
  74. package/templates/nextblock-template/lib/messages/threads.ts +579 -0
  75. package/templates/nextblock-template/lib/setup/migrations-bundle.ts +20 -0
  76. package/templates/nextblock-template/lib/site-url.test.ts +89 -0
  77. package/templates/nextblock-template/lib/site-url.ts +102 -48
  78. package/templates/nextblock-template/package.json +14 -1
  79. package/templates/nextblock-template/public/assets/nextblock-banner.jpg +0 -0
@@ -39,12 +39,26 @@ describe('resolveTextColor', () => {
39
39
  expect(resolveTextColor(undefined)).toEqual({});
40
40
  expect(resolveTextColor(null)).toEqual({});
41
41
  expect(resolveTextColor('')).toEqual({});
42
- expect(resolveTextColor('chartreuse')).toEqual({});
42
+ expect(resolveTextColor('notacolour')).toEqual({});
43
43
  expect(resolveTextColor('javascript:alert(1)')).toEqual({});
44
44
  expect(resolveTextColor('url(https://evil.test/x.png)')).toEqual({});
45
+ // A valid name with anything appended is not a name — this is the injection case,
46
+ // and it must stay rejected even though `red` on its own is now accepted.
45
47
  expect(resolveTextColor('red; background: url(x)')).toEqual({});
46
48
  });
47
49
 
50
+ it('accepts CSS named colours, which seeded and AI-authored content actually uses', () => {
51
+ // The seeded contact-page heading is `textColor: "white"`. It matched neither a
52
+ // token nor the hex/rgb/hsl pattern, so it resolved to {} and the white-on-dark hero
53
+ // rendered dark-on-dark with nothing reporting a problem.
54
+ expect(resolveTextColor('white')).toEqual({ style: { color: 'white' } });
55
+ expect(resolveTextColor('Black')).toEqual({ style: { color: 'Black' } });
56
+ expect(resolveTextColor(' transparent ')).toEqual({ style: { color: 'transparent' } });
57
+
58
+ // Still distinguishable from a theme token, which resolves to a class instead.
59
+ expect(resolveTextColor('accent')).toEqual({ className: 'text-accent' });
60
+ });
61
+
48
62
  it('never emits an interpolated class name', () => {
49
63
  for (const token of TEXT_COLOR_TOKENS) {
50
64
  const { className } = resolveTextColor(token);
@@ -73,7 +87,11 @@ describe('guards', () => {
73
87
  expect(isTextColorToken('accent')).toBe(true);
74
88
  expect(isTextColorToken('#FFF')).toBe(false);
75
89
  expect(isCustomCssColor('#FFF')).toBe(true);
90
+ expect(isCustomCssColor('white')).toBe(true);
91
+ // A theme token is not a literal colour: the two share one field and are told apart
92
+ // only here, so this must keep answering false.
76
93
  expect(isCustomCssColor('accent')).toBe(false);
94
+ expect(isCustomCssColor('notacolour')).toBe(false);
77
95
  });
78
96
  });
79
97
 
@@ -103,7 +121,9 @@ describe('HeadingBlockSchema.textColor', () => {
103
121
  });
104
122
 
105
123
  it('rejects values that are neither a token nor a colour', () => {
106
- for (const bad of ['nonsense', 'url(x)', 'red', '']) {
124
+ // 'red' was in this list only because named colours used to be rejected wholesale.
125
+ // It is a real colour and is now accepted; the genuinely invalid values stay here.
126
+ for (const bad of ['nonsense', 'url(x)', 'red; background: url(x)', '']) {
107
127
  expect(HeadingBlockSchema.safeParse({ ...base, textColor: bad }).success).toBe(false);
108
128
  }
109
129
  });
@@ -82,12 +82,55 @@ export const TEXT_COLOR_TOKEN_OPTIONS = TEXT_COLOR_TOKENS.map((token) => ({
82
82
  export const CSS_COLOR_PATTERN =
83
83
  /^(#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})|rgba?\([^)]+\)|hsla?\([^)]+\))$/i;
84
84
 
85
+ /**
86
+ * CSS named colours, which the picker never emits but hand-authored and AI-authored
87
+ * content does.
88
+ *
89
+ * The seeded contact page sets `textColor: "white"` on its heading. That is perfectly
90
+ * valid CSS, but it matched neither a theme token nor the literal pattern above, so
91
+ * `resolveTextColor` returned `{}` and the heading quietly inherited the dark default —
92
+ * a white-on-dark hero rendering dark-on-dark, with nothing anywhere reporting a problem.
93
+ *
94
+ * Spelled out as a set rather than folded into the pattern as `[a-z]+`, because
95
+ * `isCustomCssColor` has to keep answering false for a theme token like `accent`: the
96
+ * two are stored in the same field and told apart only by these predicates.
97
+ */
98
+ const CSS_NAMED_COLORS = new Set(
99
+ (
100
+ 'aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue ' +
101
+ 'blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk ' +
102
+ 'crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkgrey darkkhaki ' +
103
+ 'darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen ' +
104
+ 'darkslateblue darkslategray darkslategrey darkturquoise darkviolet deeppink deepskyblue ' +
105
+ 'dimgray dimgrey dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite ' +
106
+ 'gold goldenrod gray green greenyellow grey honeydew hotpink indianred indigo ivory khaki ' +
107
+ 'lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan ' +
108
+ 'lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen ' +
109
+ 'lightskyblue lightslategray lightslategrey lightsteelblue lightyellow lime limegreen linen ' +
110
+ 'magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen ' +
111
+ 'mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream ' +
112
+ 'mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid ' +
113
+ 'palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum ' +
114
+ 'powderblue purple rebeccapurple red rosybrown royalblue saddlebrown salmon sandybrown ' +
115
+ 'seagreen seashell sienna silver skyblue slateblue slategray slategrey snow springgreen ' +
116
+ 'steelblue tan teal thistle tomato turquoise violet wheat white whitesmoke yellow ' +
117
+ 'yellowgreen transparent currentcolor'
118
+ ).split(' ')
119
+ );
120
+
121
+ export function isCssNamedColor(value: unknown): value is string {
122
+ return typeof value === 'string' && CSS_NAMED_COLORS.has(value.trim().toLowerCase());
123
+ }
124
+
85
125
  export function isTextColorToken(value: unknown): value is TextColorToken {
86
126
  return typeof value === 'string' && (TEXT_COLOR_TOKENS as readonly string[]).includes(value);
87
127
  }
88
128
 
89
129
  export function isCustomCssColor(value: unknown): value is string {
90
- return typeof value === 'string' && CSS_COLOR_PATTERN.test(value.trim());
130
+ return (
131
+ (typeof value === 'string' && CSS_COLOR_PATTERN.test(value.trim())) ||
132
+ isCssNamedColor(value)
133
+ );
91
134
  }
92
135
 
93
136
  export interface ResolvedTextColor {