@djangocfg/layouts 1.4.27 → 1.4.29
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 +8 -8
- package/src/auth/context/AuthContext.tsx +4 -1
- package/src/auth/hooks/index.ts +2 -0
- package/src/auth/hooks/useAuthForm.ts +2 -0
- package/src/auth/hooks/useAuthGuard.ts +2 -0
- package/src/auth/hooks/useAutoAuth.ts +16 -11
- package/src/auth/hooks/useLocalStorage.ts +2 -0
- package/src/auth/hooks/useProfileCache.ts +2 -0
- package/src/auth/hooks/useSessionStorage.ts +2 -0
- package/src/auth/middlewares/index.ts +1 -1
- package/src/auth/middlewares/proxy.ts +10 -2
- package/src/layouts/AppLayout/AppLayout.tsx +9 -7
- package/src/layouts/AppLayout/components/ErrorBoundary.tsx +6 -3
- package/src/layouts/AppLayout/components/PageProgress.tsx +2 -0
- package/src/layouts/AppLayout/components/Seo.tsx +2 -0
- package/src/layouts/AppLayout/components/UpdateNotifier/UpdateNotifier.tsx +3 -2
- package/src/layouts/AppLayout/hooks/index.ts +2 -0
- package/src/layouts/AppLayout/hooks/useNavigation.ts +3 -1
- package/src/layouts/AppLayout/layouts/AdminLayout/AdminLayout.tsx +1 -0
- package/src/layouts/AppLayout/layouts/AuthLayout/AuthContext.tsx +2 -0
- package/src/layouts/AppLayout/layouts/AuthLayout/IdentifierForm.tsx +2 -0
- package/src/layouts/AppLayout/layouts/AuthLayout/OTPForm.tsx +4 -0
- package/src/layouts/AppLayout/layouts/AuthLayout/index.ts +2 -0
- package/src/layouts/AppLayout/layouts/PrivateLayout/PrivateLayout.tsx +1 -0
- package/src/layouts/AppLayout/providers/CoreProviders.tsx +1 -0
- package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +1 -0
- package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +1 -0
- package/src/layouts/PaymentsLayout/events.ts +2 -0
- package/src/layouts/ProfileLayout/ProfileLayout.tsx +1 -0
- package/src/layouts/ProfileLayout/components/ProfileForm.tsx +1 -0
- package/src/layouts/SimpleLayout/SimpleLayout.tsx +72 -0
- package/src/layouts/SimpleLayout/index.ts +3 -0
- package/src/layouts/SupportLayout/SupportLayout.tsx +1 -0
- package/src/layouts/SupportLayout/components/CreateTicketDialog.tsx +1 -0
- package/src/layouts/SupportLayout/components/TicketList.tsx +6 -5
- package/src/layouts/SupportLayout/events.ts +2 -0
- package/src/layouts/index.ts +1 -3
- package/src/snippets/AuthDialog/useAuthDialog.ts +2 -0
- package/src/snippets/Chat/components/MessageList.tsx +12 -11
- package/src/snippets/Chat/index.tsx +1 -0
- package/src/snippets/ContactForm/ContactForm.tsx +7 -2
- package/src/snippets/ContactForm/ContactPage.tsx +16 -3
- package/src/snippets/VideoPlayer/README.md +35 -0
- package/src/snippets/VideoPlayer/VideoControls.tsx +13 -9
- package/src/snippets/VideoPlayer/VideoPlayer.tsx +159 -25
- package/src/snippets/VideoPlayer/index.ts +1 -1
- package/src/validation/utils/curl-generator.ts +5 -1
- package/src/layouts/UILayout/README.md +0 -267
- package/src/layouts/UILayout/SUMMARY.md +0 -298
- package/src/layouts/UILayout/TOOLS_INTEGRATION.md +0 -216
- package/src/layouts/UILayout/components/AutoComponentDemo.tsx +0 -77
- package/src/layouts/UILayout/components/CategoryRenderer.tsx +0 -45
- package/src/layouts/UILayout/components/TailwindGuideRenderer.tsx +0 -138
- package/src/layouts/UILayout/components/index.ts +0 -15
- package/src/layouts/UILayout/components/layout/Header/CopyAIButton.tsx +0 -58
- package/src/layouts/UILayout/components/layout/Header/Header.tsx +0 -60
- package/src/layouts/UILayout/components/layout/Header/HeaderDesktop.tsx +0 -51
- package/src/layouts/UILayout/components/layout/Header/HeaderMobile.tsx +0 -71
- package/src/layouts/UILayout/components/layout/Header/TestValidationButton.tsx +0 -268
- package/src/layouts/UILayout/components/layout/Header/index.ts +0 -11
- package/src/layouts/UILayout/components/layout/MobileOverlay/MobileOverlay.tsx +0 -47
- package/src/layouts/UILayout/components/layout/MobileOverlay/index.ts +0 -6
- package/src/layouts/UILayout/components/layout/Sidebar/Sidebar.tsx +0 -95
- package/src/layouts/UILayout/components/layout/Sidebar/SidebarCategory.tsx +0 -54
- package/src/layouts/UILayout/components/layout/Sidebar/SidebarContent.tsx +0 -93
- package/src/layouts/UILayout/components/layout/Sidebar/SidebarFooter.tsx +0 -49
- package/src/layouts/UILayout/components/layout/Sidebar/index.ts +0 -9
- package/src/layouts/UILayout/components/layout/index.ts +0 -8
- package/src/layouts/UILayout/components/shared/Badge/CountBadge.tsx +0 -38
- package/src/layouts/UILayout/components/shared/Badge/index.ts +0 -5
- package/src/layouts/UILayout/components/shared/CodeBlock/CodeBlock.tsx +0 -48
- package/src/layouts/UILayout/components/shared/CodeBlock/CopyButton.tsx +0 -49
- package/src/layouts/UILayout/components/shared/CodeBlock/index.ts +0 -6
- package/src/layouts/UILayout/components/shared/Section/Section.tsx +0 -63
- package/src/layouts/UILayout/components/shared/Section/index.ts +0 -5
- package/src/layouts/UILayout/components/shared/index.ts +0 -8
- package/src/layouts/UILayout/config/ai-export.config.ts +0 -89
- package/src/layouts/UILayout/config/categories.config.tsx +0 -122
- package/src/layouts/UILayout/config/components/blocks.config.tsx +0 -239
- package/src/layouts/UILayout/config/components/data.config.tsx +0 -433
- package/src/layouts/UILayout/config/components/feedback.config.tsx +0 -290
- package/src/layouts/UILayout/config/components/forms.config.tsx +0 -996
- package/src/layouts/UILayout/config/components/hooks.config.tsx +0 -168
- package/src/layouts/UILayout/config/components/index.ts +0 -72
- package/src/layouts/UILayout/config/components/layout.config.tsx +0 -246
- package/src/layouts/UILayout/config/components/navigation.config.tsx +0 -352
- package/src/layouts/UILayout/config/components/overlay.config.tsx +0 -569
- package/src/layouts/UILayout/config/components/specialized.config.tsx +0 -400
- package/src/layouts/UILayout/config/components/tools.config.tsx +0 -234
- package/src/layouts/UILayout/config/components/types.ts +0 -14
- package/src/layouts/UILayout/config/index.ts +0 -42
- package/src/layouts/UILayout/config/tailwind.config.ts +0 -131
- package/src/layouts/UILayout/constants.ts +0 -23
- package/src/layouts/UILayout/context/ShowcaseContext.tsx +0 -81
- package/src/layouts/UILayout/context/index.ts +0 -1
- package/src/layouts/UILayout/core/UIGuideApp.client.tsx +0 -18
- package/src/layouts/UILayout/core/UIGuideApp.tsx +0 -33
- package/src/layouts/UILayout/core/UIGuideLanding.tsx +0 -172
- package/src/layouts/UILayout/core/UIGuideView.tsx +0 -61
- package/src/layouts/UILayout/core/UILayout.tsx +0 -125
- package/src/layouts/UILayout/core/UILayoutSidebar.tsx +0 -11
- package/src/layouts/UILayout/core/index.ts +0 -10
- package/src/layouts/UILayout/hooks/index.ts +0 -9
- package/src/layouts/UILayout/hooks/useAIExport.ts +0 -78
- package/src/layouts/UILayout/hooks/useCategoryNavigation.ts +0 -92
- package/src/layouts/UILayout/hooks/useComponentSearch.ts +0 -81
- package/src/layouts/UILayout/hooks/useSidebarState.ts +0 -36
- package/src/layouts/UILayout/index.ts +0 -160
- package/src/layouts/UILayout/types/component.ts +0 -45
- package/src/layouts/UILayout/types/index.ts +0 -23
- package/src/layouts/UILayout/types/layout.ts +0 -57
- package/src/layouts/UILayout/types/navigation.ts +0 -33
- package/src/layouts/UILayout/utils/ai-export/formatters.ts +0 -71
- package/src/layouts/UILayout/utils/ai-export/index.ts +0 -5
- package/src/layouts/UILayout/utils/component-helpers/filter.ts +0 -109
- package/src/layouts/UILayout/utils/component-helpers/index.ts +0 -6
- package/src/layouts/UILayout/utils/component-helpers/search.ts +0 -95
- package/src/layouts/UILayout/utils/index.ts +0 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/layouts",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.29",
|
|
4
4
|
"description": "Pre-built dashboard layouts, authentication pages, and admin templates for Next.js applications with Tailwind CSS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"layouts",
|
|
@@ -85,9 +85,9 @@
|
|
|
85
85
|
"check": "tsc --noEmit"
|
|
86
86
|
},
|
|
87
87
|
"peerDependencies": {
|
|
88
|
-
"@djangocfg/api": "^1.4.
|
|
89
|
-
"@djangocfg/og-image": "^1.4.
|
|
90
|
-
"@djangocfg/ui": "^1.4.
|
|
88
|
+
"@djangocfg/api": "^1.4.29",
|
|
89
|
+
"@djangocfg/og-image": "^1.4.29",
|
|
90
|
+
"@djangocfg/ui": "^1.4.29",
|
|
91
91
|
"@hookform/resolvers": "^5.2.0",
|
|
92
92
|
"consola": "^3.4.2",
|
|
93
93
|
"lucide-react": "^0.468.0",
|
|
@@ -103,13 +103,13 @@
|
|
|
103
103
|
"zod": "^4.0.10"
|
|
104
104
|
},
|
|
105
105
|
"dependencies": {
|
|
106
|
-
"@vidstack/react": "
|
|
107
|
-
"
|
|
106
|
+
"@vidstack/react": "next",
|
|
107
|
+
"media-icons": "next",
|
|
108
108
|
"react-ga4": "^2.1.0",
|
|
109
|
-
"vidstack": "
|
|
109
|
+
"vidstack": "next"
|
|
110
110
|
},
|
|
111
111
|
"devDependencies": {
|
|
112
|
-
"@djangocfg/typescript-config": "^1.4.
|
|
112
|
+
"@djangocfg/typescript-config": "^1.4.29",
|
|
113
113
|
"@types/node": "^24.7.2",
|
|
114
114
|
"@types/react": "19.2.2",
|
|
115
115
|
"@types/react-dom": "19.2.1",
|
package/src/auth/hooks/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
2
3
|
import { useEffect } from 'react';
|
|
4
|
+
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
|
3
5
|
import { authLogger } from '../../utils/logger';
|
|
4
6
|
|
|
5
7
|
export interface UseAutoAuthOptions {
|
|
@@ -13,12 +15,17 @@ export interface UseAutoAuthOptions {
|
|
|
13
15
|
*/
|
|
14
16
|
export const useAutoAuth = (options: UseAutoAuthOptions = {}) => {
|
|
15
17
|
const { onOTPDetected, cleanupUrl = true } = options;
|
|
18
|
+
const searchParams = useSearchParams();
|
|
19
|
+
const pathname = usePathname();
|
|
16
20
|
const router = useRouter();
|
|
17
21
|
|
|
22
|
+
const isReady = !!pathname && !!searchParams.get('otp');
|
|
23
|
+
const hasOTP = !!(searchParams.get('otp'));
|
|
24
|
+
|
|
18
25
|
useEffect(() => {
|
|
19
|
-
if (!
|
|
26
|
+
if (!isReady) return;
|
|
20
27
|
|
|
21
|
-
const queryOtp =
|
|
28
|
+
const queryOtp = searchParams.get('otp') as string;
|
|
22
29
|
|
|
23
30
|
// Handle OTP detection
|
|
24
31
|
if (queryOtp && typeof queryOtp === 'string' && queryOtp.length === 6) {
|
|
@@ -28,16 +35,14 @@ export const useAutoAuth = (options: UseAutoAuthOptions = {}) => {
|
|
|
28
35
|
|
|
29
36
|
// Clean up URL to remove sensitive params for security
|
|
30
37
|
if (cleanupUrl && queryOtp) {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
query: cleanQuery
|
|
35
|
-
}, undefined, { shallow: true });
|
|
38
|
+
const cleanQuery = Object.fromEntries(searchParams.entries());
|
|
39
|
+
delete cleanQuery.otp;
|
|
40
|
+
router.push(`${pathname}?${new URLSearchParams(cleanQuery).toString()}`);
|
|
36
41
|
}
|
|
37
|
-
}, [
|
|
42
|
+
}, [pathname, searchParams, onOTPDetected, cleanupUrl]);
|
|
38
43
|
|
|
39
44
|
return {
|
|
40
|
-
isReady
|
|
41
|
-
hasOTP
|
|
45
|
+
isReady,
|
|
46
|
+
hasOTP,
|
|
42
47
|
};
|
|
43
48
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { proxyMiddleware, proxyMiddlewareConfig } from './proxy';
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Proxy middleware for media and API endpoints
|
|
5
|
+
* Use this in your middleware.ts file
|
|
6
|
+
*/
|
|
7
|
+
export function proxyMiddleware(request: NextRequest) {
|
|
4
8
|
const { pathname, search } = request.nextUrl;
|
|
5
9
|
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
|
|
6
10
|
|
|
@@ -19,6 +23,10 @@ export function middleware(request: NextRequest) {
|
|
|
19
23
|
return NextResponse.next();
|
|
20
24
|
}
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Recommended matcher config for proxy middleware
|
|
28
|
+
* Add this to your middleware.ts config
|
|
29
|
+
*/
|
|
30
|
+
export const proxyMiddlewareConfig = {
|
|
23
31
|
matcher: ['/media/:path*', '/api/:path*'],
|
|
24
32
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
/**
|
|
2
3
|
* AppLayout - Unified Application Layout System
|
|
3
4
|
*
|
|
@@ -342,13 +343,14 @@ export function AppLayout({ children, config, component, pageProps, fontFamily,
|
|
|
342
343
|
// Wrap with ErrorBoundary if enabled
|
|
343
344
|
if (enableErrorBoundary) {
|
|
344
345
|
return (
|
|
345
|
-
<
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
346
|
+
<React.Fragment key={router.pathname}>
|
|
347
|
+
<ErrorBoundary
|
|
348
|
+
supportEmail={supportEmail}
|
|
349
|
+
onError={onError}
|
|
350
|
+
>
|
|
351
|
+
{content}
|
|
352
|
+
</ErrorBoundary>
|
|
353
|
+
</React.Fragment>
|
|
352
354
|
);
|
|
353
355
|
}
|
|
354
356
|
|
|
@@ -37,6 +37,9 @@ interface ErrorBoundaryState {
|
|
|
37
37
|
* Catches React errors and shows ErrorLayout
|
|
38
38
|
*/
|
|
39
39
|
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
40
|
+
declare state: ErrorBoundaryState;
|
|
41
|
+
declare props: Readonly<ErrorBoundaryProps>;
|
|
42
|
+
|
|
40
43
|
constructor(props: ErrorBoundaryProps) {
|
|
41
44
|
super(props);
|
|
42
45
|
this.state = { hasError: false };
|
|
@@ -62,12 +65,12 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
|
|
|
62
65
|
// Call optional callback
|
|
63
66
|
this.props.onError?.(error, errorInfo);
|
|
64
67
|
|
|
65
|
-
// Store error info in state
|
|
66
|
-
|
|
68
|
+
// Store error info in state using base class method
|
|
69
|
+
Component.prototype.setState.call(this, { errorInfo });
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
resetError = () => {
|
|
70
|
-
|
|
73
|
+
Component.prototype.setState.call(this, { hasError: false, error: undefined, errorInfo: undefined });
|
|
71
74
|
};
|
|
72
75
|
|
|
73
76
|
render() {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
'use client';
|
|
10
10
|
|
|
11
11
|
import React, { useEffect, useState } from 'react';
|
|
12
|
+
import consola from 'consola';
|
|
12
13
|
import { toast } from '@djangocfg/ui/hooks';
|
|
13
14
|
|
|
14
15
|
const PACKAGE_NAME = '@djangocfg/layouts';
|
|
@@ -63,7 +64,7 @@ async function fetchLatestVersion(): Promise<string | null> {
|
|
|
63
64
|
const data = await response.json();
|
|
64
65
|
return data.version || null;
|
|
65
66
|
} catch (error) {
|
|
66
|
-
|
|
67
|
+
consola.warn('[UpdateNotifier] Failed to check for updates:', error);
|
|
67
68
|
return null;
|
|
68
69
|
}
|
|
69
70
|
}
|
|
@@ -94,7 +95,7 @@ function setCache(data: UpdateCheckCache): void {
|
|
|
94
95
|
try {
|
|
95
96
|
localStorage.setItem(CACHE_KEY, JSON.stringify(data));
|
|
96
97
|
} catch (error) {
|
|
97
|
-
|
|
98
|
+
consola.warn('[UpdateNotifier] Failed to cache update check:', error);
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
// @ts-nocheck
|
|
1
4
|
import React from 'react';
|
|
2
5
|
import { Mail, MessageCircle, ArrowLeft, RotateCw, ShieldCheck } from 'lucide-react';
|
|
3
6
|
|
|
@@ -70,6 +73,7 @@ export const OTPForm: React.FC = () => {
|
|
|
70
73
|
Enter verification code
|
|
71
74
|
</label>
|
|
72
75
|
<div className="flex justify-center">
|
|
76
|
+
{/* @ts-expect-error - TypeScript doesn't recognize children in JSX props for discriminated union */}
|
|
73
77
|
<InputOTP
|
|
74
78
|
value={otp}
|
|
75
79
|
onChange={setOtp}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* SimpleLayout - Lightweight provider for docs and marketing sites
|
|
4
|
+
*
|
|
5
|
+
* Provides essential UI infrastructure without the overhead of full AppLayout:
|
|
6
|
+
* - TooltipProvider for all tooltip components
|
|
7
|
+
* - Toaster for notifications
|
|
8
|
+
* - Basic theme support
|
|
9
|
+
*
|
|
10
|
+
* Perfect for documentation sites, landing pages, and simple apps.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
'use client';
|
|
14
|
+
|
|
15
|
+
import React from 'react';
|
|
16
|
+
import { TooltipProvider, Toaster } from '@djangocfg/ui';
|
|
17
|
+
|
|
18
|
+
export interface SimpleLayoutProps {
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
/**
|
|
21
|
+
* Delay before tooltips appear (in milliseconds)
|
|
22
|
+
* @default 200
|
|
23
|
+
*/
|
|
24
|
+
tooltipDelayDuration?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Skip delay when moving between tooltips
|
|
27
|
+
* @default 300
|
|
28
|
+
*/
|
|
29
|
+
tooltipSkipDelayDuration?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Lightweight layout provider for documentation and marketing sites.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```tsx
|
|
37
|
+
* // In your root layout.tsx
|
|
38
|
+
* import { SimpleLayout } from '@djangocfg/layouts';
|
|
39
|
+
*
|
|
40
|
+
* export default function RootLayout({ children }) {
|
|
41
|
+
* return (
|
|
42
|
+
* <html>
|
|
43
|
+
* <body>
|
|
44
|
+
* <SimpleLayout>
|
|
45
|
+
* {children}
|
|
46
|
+
* </SimpleLayout>
|
|
47
|
+
* </body>
|
|
48
|
+
* </html>
|
|
49
|
+
* );
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function SimpleLayout({
|
|
54
|
+
children,
|
|
55
|
+
tooltipDelayDuration = 200,
|
|
56
|
+
tooltipSkipDelayDuration = 300,
|
|
57
|
+
}: SimpleLayoutProps) {
|
|
58
|
+
return (
|
|
59
|
+
<>
|
|
60
|
+
<TooltipProvider
|
|
61
|
+
delayDuration={tooltipDelayDuration}
|
|
62
|
+
skipDelayDuration={tooltipSkipDelayDuration}
|
|
63
|
+
>
|
|
64
|
+
{children}
|
|
65
|
+
</TooltipProvider>
|
|
66
|
+
<Toaster />
|
|
67
|
+
</>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
SimpleLayout.displayName = 'SimpleLayout';
|
|
72
|
+
|
|
@@ -73,11 +73,12 @@ export const TicketList: React.FC = () => {
|
|
|
73
73
|
return (
|
|
74
74
|
<div className="p-4 space-y-2">
|
|
75
75
|
{[1, 2, 3, 4, 5].map((i) => (
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
<div key={i}>
|
|
77
|
+
<Skeleton
|
|
78
|
+
className="h-24 w-full animate-pulse"
|
|
79
|
+
style={{ animationDelay: `${i * 100}ms` }}
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
81
82
|
))}
|
|
82
83
|
</div>
|
|
83
84
|
);
|
package/src/layouts/index.ts
CHANGED
|
@@ -8,9 +8,7 @@ export * from './SupportLayout';
|
|
|
8
8
|
export * from './PaymentsLayout';
|
|
9
9
|
export * from './AppLayout';
|
|
10
10
|
export * from './ErrorLayout';
|
|
11
|
-
|
|
12
|
-
// UILayout - Config-driven UI documentation layout
|
|
13
|
-
export * from './UILayout';
|
|
11
|
+
export * from './SimpleLayout';
|
|
14
12
|
|
|
15
13
|
// Note: CfgLayout is now part of AppLayout exports
|
|
16
14
|
// Import it via: import { CfgLayout, useCfgApp } from '@djangocfg/layouts';
|
|
@@ -111,17 +111,18 @@ export const MessageList: React.FC<MessageListProps> = ({
|
|
|
111
111
|
message.sources.length > 0 && (
|
|
112
112
|
<div className="flex flex-wrap gap-2 px-1 animate-in fade-in slide-in-from-left-2 duration-300 delay-100">
|
|
113
113
|
{message.sources.map((source, idx) => (
|
|
114
|
-
<
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
114
|
+
<div key={idx}>
|
|
115
|
+
<Badge
|
|
116
|
+
variant="secondary"
|
|
117
|
+
className="text-xs flex items-center gap-1 cursor-pointer
|
|
118
|
+
hover:bg-secondary/80 hover:scale-105 active:scale-95
|
|
119
|
+
transition-all duration-200 animate-in fade-in zoom-in-95"
|
|
120
|
+
style={{ animationDelay: `${(idx + 1) * 100}ms` }}
|
|
121
|
+
>
|
|
122
|
+
{source.document_title || `Source ${idx + 1}`}
|
|
123
|
+
<ExternalLink className="h-3 w-3" />
|
|
124
|
+
</Badge>
|
|
125
|
+
</div>
|
|
125
126
|
))}
|
|
126
127
|
</div>
|
|
127
128
|
)}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
'use client';
|
|
2
3
|
|
|
3
4
|
import React, { useEffect, useState } from 'react';
|
|
@@ -131,12 +132,13 @@ function ContactFormInner({
|
|
|
131
132
|
// Apply draft from localStorage and set site_url
|
|
132
133
|
const currentValues = form.getValues();
|
|
133
134
|
const hasDraftData = draft.name || draft.email || draft.company || draft.subject || draft.message;
|
|
135
|
+
const currentSiteUrl = typeof window !== 'undefined' ? window.location.href : '';
|
|
134
136
|
|
|
135
137
|
if (hasDraftData || !currentValues.site_url) {
|
|
136
138
|
form.reset({
|
|
137
139
|
...emptyDraft,
|
|
138
140
|
...draft,
|
|
139
|
-
site_url:
|
|
141
|
+
site_url: currentSiteUrl,
|
|
140
142
|
});
|
|
141
143
|
}
|
|
142
144
|
}, [draft, form, isHydrated]);
|
|
@@ -165,14 +167,17 @@ function ContactFormInner({
|
|
|
165
167
|
const result = await submit(data);
|
|
166
168
|
if (resetOnSuccess) {
|
|
167
169
|
// Keep contact info (name, email, company), clear only message content
|
|
170
|
+
// Store current site_url before reset to avoid re-reading window.location
|
|
168
171
|
const currentValues = form.getValues();
|
|
172
|
+
const currentSiteUrl = currentValues.site_url || (typeof window !== 'undefined' ? window.location.href : '');
|
|
173
|
+
|
|
169
174
|
form.reset({
|
|
170
175
|
name: currentValues.name,
|
|
171
176
|
email: currentValues.email,
|
|
172
177
|
company: currentValues.company,
|
|
173
178
|
subject: '',
|
|
174
179
|
message: '',
|
|
175
|
-
site_url:
|
|
180
|
+
site_url: currentSiteUrl, // Keep the original site_url
|
|
176
181
|
});
|
|
177
182
|
// Update draft to keep contact info
|
|
178
183
|
setDraft({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import React from 'react';
|
|
4
|
-
import { Mail, MapPin, Calendar } from 'lucide-react';
|
|
4
|
+
import { Mail, MapPin, Calendar, MessageCircle } from 'lucide-react';
|
|
5
5
|
import { ContactFormBase as ContactForm } from './ContactForm';
|
|
6
6
|
import { ContactInfo } from './ContactInfo';
|
|
7
7
|
import type { ContactDetail, LeadSubmissionResult } from './types';
|
|
@@ -15,6 +15,7 @@ const isDev = process.env.NODE_ENV === 'development';
|
|
|
15
15
|
const DEFAULT_CONFIG = {
|
|
16
16
|
apiUrl: isDev ? 'http://localhost:8000' : 'https://api.reforms.ai',
|
|
17
17
|
email: 'markolofsen@gmail.com',
|
|
18
|
+
whatsapp: '+62 813 39646301',
|
|
18
19
|
calendly: 'https://calendly.com/markolofsen/meeting',
|
|
19
20
|
};
|
|
20
21
|
|
|
@@ -27,6 +28,8 @@ export interface ContactPageProps {
|
|
|
27
28
|
apiUrl?: string;
|
|
28
29
|
/** Override email */
|
|
29
30
|
email?: string;
|
|
31
|
+
/** Override whatsapp */
|
|
32
|
+
whatsapp?: string;
|
|
30
33
|
/** Override calendly link */
|
|
31
34
|
calendlyUrl?: string;
|
|
32
35
|
/** Page title */
|
|
@@ -61,6 +64,7 @@ export interface ContactPageProps {
|
|
|
61
64
|
export function ContactPageBase({
|
|
62
65
|
apiUrl = DEFAULT_CONFIG.apiUrl,
|
|
63
66
|
email = DEFAULT_CONFIG.email,
|
|
67
|
+
whatsapp = DEFAULT_CONFIG.whatsapp,
|
|
64
68
|
calendlyUrl = DEFAULT_CONFIG.calendly,
|
|
65
69
|
title = 'Get in Touch',
|
|
66
70
|
subtitle = "Have a question or want to work together? We'd love to hear from you.",
|
|
@@ -69,6 +73,9 @@ export function ContactPageBase({
|
|
|
69
73
|
className,
|
|
70
74
|
onSuccess,
|
|
71
75
|
}: ContactPageProps) {
|
|
76
|
+
// Format phone for WhatsApp link (remove spaces and special chars)
|
|
77
|
+
const whatsappPhone = whatsapp.replace(/[\s\-\(\)]/g, '');
|
|
78
|
+
|
|
72
79
|
const contactDetails: ContactDetail[] = [
|
|
73
80
|
{
|
|
74
81
|
icon: <Mail className="h-5 w-5" />,
|
|
@@ -76,6 +83,12 @@ export function ContactPageBase({
|
|
|
76
83
|
value: email,
|
|
77
84
|
href: `mailto:${email}`,
|
|
78
85
|
},
|
|
86
|
+
{
|
|
87
|
+
icon: <MessageCircle className="h-5 w-5" />,
|
|
88
|
+
label: 'WhatsApp',
|
|
89
|
+
value: whatsapp,
|
|
90
|
+
href: `https://wa.me/${whatsappPhone}`,
|
|
91
|
+
},
|
|
79
92
|
{
|
|
80
93
|
icon: <MapPin className="h-5 w-5" />,
|
|
81
94
|
label: 'Location',
|
|
@@ -96,8 +109,8 @@ export function ContactPageBase({
|
|
|
96
109
|
</div>
|
|
97
110
|
|
|
98
111
|
{/* Content Grid */}
|
|
99
|
-
<div className="grid grid-cols-1 lg:grid-cols-
|
|
100
|
-
<div
|
|
112
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 w-full">
|
|
113
|
+
<div>
|
|
101
114
|
<ContactForm apiUrl={apiUrl} onSuccess={onSuccess} />
|
|
102
115
|
</div>
|
|
103
116
|
<div>
|