create-brainerce-store 1.3.3 → 1.4.0

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 (38) hide show
  1. package/dist/index.js +62 -5
  2. package/messages/en.json +258 -0
  3. package/messages/he.json +258 -0
  4. package/package.json +3 -2
  5. package/templates/nextjs/base/src/app/account/page.tsx +108 -105
  6. package/templates/nextjs/base/src/app/auth/callback/page.tsx +90 -88
  7. package/templates/nextjs/base/src/app/cart/page.tsx +110 -109
  8. package/templates/nextjs/base/src/app/checkout/page.tsx +46 -43
  9. package/templates/nextjs/base/src/app/layout.tsx.ejs +8 -5
  10. package/templates/nextjs/base/src/app/login/page.tsx +58 -56
  11. package/templates/nextjs/base/src/app/order-confirmation/page.tsx +18 -23
  12. package/templates/nextjs/base/src/app/page.tsx +98 -95
  13. package/templates/nextjs/base/src/app/products/[slug]/page.tsx +16 -12
  14. package/templates/nextjs/base/src/app/products/page.tsx +246 -243
  15. package/templates/nextjs/base/src/app/register/page.tsx +68 -66
  16. package/templates/nextjs/base/src/app/verify-email/page.tsx +293 -291
  17. package/templates/nextjs/base/src/components/account/order-history.tsx +198 -184
  18. package/templates/nextjs/base/src/components/account/profile-section.tsx +75 -73
  19. package/templates/nextjs/base/src/components/auth/login-form.tsx +94 -92
  20. package/templates/nextjs/base/src/components/auth/oauth-buttons.tsx +137 -134
  21. package/templates/nextjs/base/src/components/auth/register-form.tsx +184 -177
  22. package/templates/nextjs/base/src/components/cart/cart-item.tsx +153 -150
  23. package/templates/nextjs/base/src/components/cart/cart-summary.tsx +70 -67
  24. package/templates/nextjs/base/src/components/cart/coupon-input.tsx +134 -131
  25. package/templates/nextjs/base/src/components/cart/reservation-countdown.tsx +103 -100
  26. package/templates/nextjs/base/src/components/checkout/checkout-form.tsx +28 -25
  27. package/templates/nextjs/base/src/components/checkout/delivery-method-step.tsx +6 -4
  28. package/templates/nextjs/base/src/components/checkout/payment-step.tsx +39 -20
  29. package/templates/nextjs/base/src/components/checkout/pickup-step.tsx +15 -11
  30. package/templates/nextjs/base/src/components/checkout/shipping-step.tsx +110 -111
  31. package/templates/nextjs/base/src/components/checkout/tax-display.tsx +7 -4
  32. package/templates/nextjs/base/src/components/layout/footer.tsx +38 -35
  33. package/templates/nextjs/base/src/components/layout/header.tsx +332 -329
  34. package/templates/nextjs/base/src/components/products/product-card.tsx +3 -1
  35. package/templates/nextjs/base/src/components/products/product-grid.tsx +35 -33
  36. package/templates/nextjs/base/src/components/shared/loading-spinner.tsx +32 -30
  37. package/templates/nextjs/base/src/i18n.ts.ejs +5 -0
  38. package/templates/nextjs/base/src/lib/translations.ts +11 -0
@@ -4,6 +4,7 @@ import Link from 'next/link';
4
4
  import Image from 'next/image';
5
5
  import type { Product } from 'brainerce';
6
6
  import { getProductPriceInfo } from 'brainerce';
7
+ import { useTranslations } from '@/lib/translations';
7
8
  import { PriceDisplay } from '@/components/shared/price-display';
8
9
  import { StockBadge } from '@/components/products/stock-badge';
9
10
  import { DiscountBadge } from '@/components/products/discount-badge';
@@ -15,6 +16,7 @@ interface ProductCardProps {
15
16
  }
16
17
 
17
18
  export function ProductCard({ product, className }: ProductCardProps) {
19
+ const t = useTranslations('common');
18
20
  const { price, originalPrice, isOnSale } = getProductPriceInfo(product);
19
21
  const mainImage = product.images?.[0];
20
22
  const imageUrl = mainImage?.url || null;
@@ -55,7 +57,7 @@ export function ProductCard({ product, className }: ProductCardProps) {
55
57
  <div className="absolute start-2 top-2 flex flex-col gap-1">
56
58
  {isOnSale && (
57
59
  <span className="bg-destructive text-destructive-foreground rounded px-2 py-1 text-xs font-bold">
58
- Sale
60
+ {t('sale')}
59
61
  </span>
60
62
  )}
61
63
  <DiscountBadge discount={product.discount} />
@@ -1,33 +1,35 @@
1
- 'use client';
2
-
3
- import type { Product } from 'brainerce';
4
- import { ProductCard } from '@/components/products/product-card';
5
- import { cn } from '@/lib/utils';
6
-
7
- interface ProductGridProps {
8
- products: Product[];
9
- className?: string;
10
- }
11
-
12
- export function ProductGrid({ products, className }: ProductGridProps) {
13
- if (products.length === 0) {
14
- return (
15
- <div className="py-16 text-center">
16
- <p className="text-muted-foreground text-lg">No products found.</p>
17
- </div>
18
- );
19
- }
20
-
21
- return (
22
- <div
23
- className={cn(
24
- 'grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
25
- className
26
- )}
27
- >
28
- {products.map((product) => (
29
- <ProductCard key={product.id} product={product} />
30
- ))}
31
- </div>
32
- );
33
- }
1
+ 'use client';
2
+
3
+ import type { Product } from 'brainerce';
4
+ import { useTranslations } from '@/lib/translations';
5
+ import { ProductCard } from '@/components/products/product-card';
6
+ import { cn } from '@/lib/utils';
7
+
8
+ interface ProductGridProps {
9
+ products: Product[];
10
+ className?: string;
11
+ }
12
+
13
+ export function ProductGrid({ products, className }: ProductGridProps) {
14
+ const t = useTranslations('products');
15
+ if (products.length === 0) {
16
+ return (
17
+ <div className="py-16 text-center">
18
+ <p className="text-muted-foreground text-lg">{t('noProducts')}</p>
19
+ </div>
20
+ );
21
+ }
22
+
23
+ return (
24
+ <div
25
+ className={cn(
26
+ 'grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
27
+ className
28
+ )}
29
+ >
30
+ {products.map((product) => (
31
+ <ProductCard key={product.id} product={product} />
32
+ ))}
33
+ </div>
34
+ );
35
+ }
@@ -1,30 +1,32 @@
1
- 'use client';
2
-
3
- import { cn } from '@/lib/utils';
4
-
5
- interface LoadingSpinnerProps {
6
- size?: 'sm' | 'md' | 'lg';
7
- className?: string;
8
- }
9
-
10
- const sizeClasses = {
11
- sm: 'h-4 w-4 border-2',
12
- md: 'h-8 w-8 border-2',
13
- lg: 'h-12 w-12 border-3',
14
- };
15
-
16
- export function LoadingSpinner({ size = 'md', className }: LoadingSpinnerProps) {
17
- return (
18
- <div
19
- className={cn(
20
- 'border-muted-foreground/30 border-t-primary animate-spin rounded-full',
21
- sizeClasses[size],
22
- className
23
- )}
24
- role="status"
25
- aria-label="Loading"
26
- >
27
- <span className="sr-only">Loading...</span>
28
- </div>
29
- );
30
- }
1
+ 'use client';
2
+
3
+ import { useTranslations } from '@/lib/translations';
4
+ import { cn } from '@/lib/utils';
5
+
6
+ interface LoadingSpinnerProps {
7
+ size?: 'sm' | 'md' | 'lg';
8
+ className?: string;
9
+ }
10
+
11
+ const sizeClasses = {
12
+ sm: 'h-4 w-4 border-2',
13
+ md: 'h-8 w-8 border-2',
14
+ lg: 'h-12 w-12 border-3',
15
+ };
16
+
17
+ export function LoadingSpinner({ size = 'md', className }: LoadingSpinnerProps) {
18
+ const t = useTranslations('common');
19
+ return (
20
+ <div
21
+ className={cn(
22
+ 'border-muted-foreground/30 border-t-primary animate-spin rounded-full',
23
+ sizeClasses[size],
24
+ className
25
+ )}
26
+ role="status"
27
+ aria-label={t('loading')}
28
+ >
29
+ <span className="sr-only">{t('loading')}</span>
30
+ </div>
31
+ );
32
+ }
@@ -0,0 +1,5 @@
1
+ import messages from '../messages/<%= language %>.json';
2
+
3
+ export const defaultLocale = '<%= language %>';
4
+ export const direction = '<%= direction %>' as 'ltr' | 'rtl';
5
+ export { messages };
@@ -0,0 +1,11 @@
1
+ import { messages } from '@/i18n';
2
+
3
+ type Messages = typeof messages;
4
+ type Namespace = keyof Messages;
5
+
6
+ export function useTranslations<N extends Namespace>(namespace: N) {
7
+ const ns = messages[namespace] as Record<string, string>;
8
+ return function t(key: keyof Messages[N]): string {
9
+ return ns[key as string] || `${String(namespace)}.${key as string}`;
10
+ };
11
+ }