@linktr.ee/linkapp 0.0.48 → 0.0.49
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/README.md +1 -1
- package/dev-server/components/form/array-field.tsx +115 -0
- package/dev-server/components/form/file-field.tsx +48 -0
- package/dev-server/components/form/form-element.tsx +304 -0
- package/dev-server/components/form/link-behavior-field.tsx +68 -0
- package/dev-server/components/form/location-field.tsx +60 -0
- package/dev-server/components/settings-preview.tsx +138 -302
- package/dev-server/components/ui/checkbox.tsx +29 -0
- package/dev-server/components/ui/dialog.tsx +2 -10
- package/dev-server/components/ui/field.tsx +24 -49
- package/dev-server/components/ui/input.tsx +20 -21
- package/dev-server/components/ui/label.tsx +4 -4
- package/dev-server/components/ui/radio-group.tsx +37 -0
- package/dev-server/components/ui/select.tsx +153 -0
- package/dev-server/components/ui/switch.tsx +31 -0
- package/dev-server/components/ui/tabs.tsx +1 -1
- package/dev-server/components/ui/textarea.tsx +18 -19
- package/dev-server/env.d.ts +4 -1
- package/dev-server/expanded/main.tsx +20 -22
- package/dev-server/expanded.html +0 -1
- package/dev-server/featured/main.tsx +29 -36
- package/dev-server/featured-carousel.html +0 -1
- package/dev-server/featured.html +0 -1
- package/dev-server/index.html +1 -7
- package/dev-server/lib/utils.ts +3 -3
- package/dev-server/package.json +3 -3
- package/dev-server/postcss/tailwind-source-fallback.js +2 -7
- package/dev-server/postcss.config.mjs +2 -2
- package/dev-server/preview/Preview.tsx +310 -350
- package/dev-server/preview/main.tsx +8 -8
- package/dev-server/preview/preview.css +0 -1
- package/dev-server/public/site.webmanifest +1 -1
- package/dev-server/rsbuild.config.ts +1 -1
- package/dev-server/shared/dev-parent-simulator.ts +219 -0
- package/dev-server/shared/theme-presets.ts +71 -75
- package/dev-server/shared/theme-utils.ts +11 -11
- package/dist/cli.js +18 -12
- package/dist/cli.js.map +1 -1
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +27 -42
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +26 -16
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/deploy.d.ts +1 -11
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +3 -13
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +132 -388
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +17 -29
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts.map +1 -1
- package/dist/commands/logout.js +6 -11
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/rollback.d.ts +10 -0
- package/dist/commands/rollback.d.ts.map +1 -0
- package/dist/commands/rollback.js +148 -0
- package/dist/commands/rollback.js.map +1 -0
- package/dist/commands/status.d.ts +8 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +96 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/test-url-match-rules.d.ts.map +1 -1
- package/dist/commands/test-url-match-rules.js +20 -26
- package/dist/commands/test-url-match-rules.js.map +1 -1
- package/dist/lib/auth/device-flow.d.ts +1 -1
- package/dist/lib/auth/device-flow.d.ts.map +1 -1
- package/dist/lib/auth/device-flow.js +3 -3
- package/dist/lib/auth/device-flow.js.map +1 -1
- package/dist/lib/auth/token-storage.d.ts.map +1 -1
- package/dist/lib/auth/token-storage.js +14 -37
- package/dist/lib/auth/token-storage.js.map +1 -1
- package/dist/lib/build/detect-layouts.d.ts.map +1 -1
- package/dist/lib/build/detect-layouts.js +27 -13
- package/dist/lib/build/detect-layouts.js.map +1 -1
- package/dist/lib/config/load-config.d.ts.map +1 -1
- package/dist/lib/config/load-config.js +0 -2
- package/dist/lib/config/load-config.js.map +1 -1
- package/dist/lib/deploy/deploy-output.d.ts +2 -1
- package/dist/lib/deploy/deploy-output.d.ts.map +1 -1
- package/dist/lib/deploy/deploy-output.js +9 -1
- package/dist/lib/deploy/deploy-output.js.map +1 -1
- package/dist/lib/deploy/deploy-phases.d.ts +2 -0
- package/dist/lib/deploy/deploy-phases.d.ts.map +1 -1
- package/dist/lib/deploy/deploy-phases.js +9 -23
- package/dist/lib/deploy/deploy-phases.js.map +1 -1
- package/dist/lib/deploy/deploy-utils.d.ts +15 -7
- package/dist/lib/deploy/deploy-utils.d.ts.map +1 -1
- package/dist/lib/deploy/deploy-utils.js +49 -36
- package/dist/lib/deploy/deploy-utils.js.map +1 -1
- package/dist/lib/deploy/generate-manifest-files.d.ts.map +1 -1
- package/dist/lib/deploy/generate-manifest-files.js +13 -39
- package/dist/lib/deploy/generate-manifest-files.js.map +1 -1
- package/dist/lib/deploy/pack-project.d.ts.map +1 -1
- package/dist/lib/deploy/pack-project.js +34 -20
- package/dist/lib/deploy/pack-project.js.map +1 -1
- package/dist/lib/deploy/slot-manager.d.ts +54 -0
- package/dist/lib/deploy/slot-manager.d.ts.map +1 -0
- package/dist/lib/deploy/slot-manager.js +72 -0
- package/dist/lib/deploy/slot-manager.js.map +1 -0
- package/dist/lib/deploy/test-url-match-rules.d.ts +10 -2
- package/dist/lib/deploy/test-url-match-rules.d.ts.map +1 -1
- package/dist/lib/deploy/test-url-match-rules.js +1 -1
- package/dist/lib/deploy/test-url-match-rules.js.map +1 -1
- package/dist/lib/deploy/upload.d.ts +1 -0
- package/dist/lib/deploy/upload.d.ts.map +1 -1
- package/dist/lib/deploy/upload.js +15 -24
- package/dist/lib/deploy/upload.js.map +1 -1
- package/dist/lib/deploy/validation.d.ts.map +1 -1
- package/dist/lib/deploy/validation.js +43 -48
- package/dist/lib/deploy/validation.js.map +1 -1
- package/dist/lib/rsbuild/config-factory.d.ts.map +1 -1
- package/dist/lib/rsbuild/config-factory.js +10 -17
- package/dist/lib/rsbuild/config-factory.js.map +1 -1
- package/dist/lib/rsbuild/plugins/asset-versioning.d.ts.map +1 -1
- package/dist/lib/rsbuild/plugins/asset-versioning.js +4 -14
- package/dist/lib/rsbuild/plugins/asset-versioning.js.map +1 -1
- package/dist/lib/rsbuild/plugins/brotli-compression.d.ts.map +1 -1
- package/dist/lib/rsbuild/plugins/brotli-compression.js +4 -4
- package/dist/lib/rsbuild/plugins/brotli-compression.js.map +1 -1
- package/dist/lib/rsbuild/plugins/copy-public.d.ts.map +1 -1
- package/dist/lib/rsbuild/plugins/copy-public.js.map +1 -1
- package/dist/lib/rsbuild/postcss/tailwind-source-fallback.d.ts.map +1 -1
- package/dist/lib/rsbuild/postcss/tailwind-source-fallback.js +1 -3
- package/dist/lib/rsbuild/postcss/tailwind-source-fallback.js.map +1 -1
- package/dist/lib/utils/console.d.ts +8 -0
- package/dist/lib/utils/console.d.ts.map +1 -0
- package/dist/lib/utils/console.js +10 -0
- package/dist/lib/utils/console.js.map +1 -0
- package/dist/lib/utils/filesystem.d.ts +9 -0
- package/dist/lib/utils/filesystem.d.ts.map +1 -0
- package/dist/lib/utils/filesystem.js +30 -0
- package/dist/lib/utils/filesystem.js.map +1 -0
- package/dist/lib/utils/formatters.d.ts +8 -0
- package/dist/lib/utils/formatters.d.ts.map +1 -0
- package/dist/lib/utils/formatters.js +22 -0
- package/dist/lib/utils/formatters.js.map +1 -0
- package/dist/lib/utils/index.d.ts +7 -0
- package/dist/lib/utils/index.d.ts.map +1 -0
- package/dist/lib/utils/index.js +7 -0
- package/dist/lib/utils/index.js.map +1 -0
- package/dist/lib/utils/setup-runtime.d.ts.map +1 -1
- package/dist/lib/utils/setup-runtime.js +22 -63
- package/dist/lib/utils/setup-runtime.js.map +1 -1
- package/dist/schema/config.schema.d.ts +9 -48
- package/dist/schema/config.schema.d.ts.map +1 -1
- package/dist/schema/config.schema.js +119 -120
- package/dist/schema/config.schema.js.map +1 -1
- package/dist/sdk/hooks/mocks.d.ts +9 -0
- package/dist/sdk/hooks/mocks.d.ts.map +1 -0
- package/dist/sdk/hooks/mocks.js +17 -0
- package/dist/sdk/hooks/mocks.js.map +1 -0
- package/dist/sdk/hooks/use-audience-manager.d.ts +44 -0
- package/dist/sdk/hooks/use-audience-manager.d.ts.map +1 -0
- package/dist/sdk/hooks/use-audience-manager.js +109 -0
- package/dist/sdk/hooks/use-audience-manager.js.map +1 -0
- package/dist/sdk/hooks/use-ip.d.ts +45 -0
- package/dist/sdk/hooks/use-ip.d.ts.map +1 -0
- package/dist/sdk/hooks/use-ip.js +46 -0
- package/dist/sdk/hooks/use-ip.js.map +1 -0
- package/dist/sdk/hooks/use-sdk-request.d.ts +46 -0
- package/dist/sdk/hooks/use-sdk-request.d.ts.map +1 -0
- package/dist/sdk/hooks/use-sdk-request.js +65 -0
- package/dist/sdk/hooks/use-sdk-request.js.map +1 -0
- package/dist/sdk/hooks/use-theme.d.ts +45 -0
- package/dist/sdk/hooks/use-theme.d.ts.map +1 -0
- package/dist/sdk/hooks/use-theme.js +97 -0
- package/dist/sdk/hooks/use-theme.js.map +1 -0
- package/dist/sdk/hooks/use-visitor.d.ts +41 -0
- package/dist/sdk/hooks/use-visitor.d.ts.map +1 -0
- package/dist/sdk/hooks/use-visitor.js +42 -0
- package/dist/sdk/hooks/use-visitor.js.map +1 -0
- package/dist/sdk/hooks/validation.d.ts +8 -0
- package/dist/sdk/hooks/validation.d.ts.map +1 -0
- package/dist/sdk/hooks/validation.js +13 -0
- package/dist/sdk/hooks/validation.js.map +1 -0
- package/dist/sdk/index.d.ts +17 -5
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +16 -5
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/message-bus.d.ts +59 -0
- package/dist/sdk/message-bus.d.ts.map +1 -0
- package/dist/sdk/message-bus.js +152 -0
- package/dist/sdk/message-bus.js.map +1 -0
- package/dist/sdk/messages.d.ts +121 -0
- package/dist/sdk/messages.d.ts.map +1 -0
- package/dist/sdk/messages.js +9 -0
- package/dist/sdk/messages.js.map +1 -0
- package/dist/sdk/send-message.d.ts +1 -1
- package/dist/sdk/send-message.js +18 -18
- package/dist/sdk/send-message.js.map +1 -1
- package/dist/sdk/use-expand-link-app.d.ts +3 -3
- package/dist/sdk/use-expand-link-app.d.ts.map +1 -1
- package/dist/sdk/use-expand-link-app.js +9 -5
- package/dist/sdk/use-expand-link-app.js.map +1 -1
- package/dist/types.d.ts +235 -55
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +8 -3
- package/dist/types.js.map +1 -1
- package/package.json +3 -9
|
@@ -1,330 +1,166 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Settings } from 'lucide-react'
|
|
2
|
+
import { useMemo, useState } from 'react'
|
|
3
|
+
|
|
4
|
+
import type { LinkAppManifest, LinkAppSettings, SettingsElement } from '../../src/types'
|
|
5
|
+
import { FormElement } from './form/form-element'
|
|
2
6
|
|
|
3
7
|
interface SettingsPreviewProps {
|
|
4
|
-
settings: LinkAppSettings
|
|
8
|
+
settings: LinkAppSettings
|
|
9
|
+
manifest?: Partial<LinkAppManifest>
|
|
10
|
+
previewProps?: Record<string, unknown>
|
|
5
11
|
}
|
|
6
12
|
|
|
7
|
-
export function SettingsPreview({ settings }: SettingsPreviewProps) {
|
|
8
|
-
|
|
9
|
-
<div className="max-w-4xl mx-auto p-6 space-y-6">
|
|
10
|
-
{/* Header */}
|
|
11
|
-
<div className="space-y-2">
|
|
12
|
-
<h2 className="text-2xl font-bold">{settings.title}</h2>
|
|
13
|
-
{settings.overview && (
|
|
14
|
-
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
|
15
|
-
{settings.overview.title && (
|
|
16
|
-
<h3 className="font-semibold text-blue-900 mb-1">
|
|
17
|
-
{settings.overview.title}
|
|
18
|
-
</h3>
|
|
19
|
-
)}
|
|
20
|
-
<p className="text-blue-800 text-sm">
|
|
21
|
-
{settings.overview.description}
|
|
22
|
-
</p>
|
|
23
|
-
</div>
|
|
24
|
-
)}
|
|
25
|
-
</div>
|
|
13
|
+
export function SettingsPreview({ settings, manifest, previewProps = {} }: SettingsPreviewProps) {
|
|
14
|
+
const [iconError, setIconError] = useState(false)
|
|
26
15
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<span className="text-sm font-medium text-gray-600">Uses URL:</span>
|
|
31
|
-
<span className="ml-2 text-sm">
|
|
32
|
-
{settings.uses_url || settings.has_url ? "Yes" : "No"}
|
|
33
|
-
</span>
|
|
34
|
-
</div>
|
|
35
|
-
<div>
|
|
36
|
-
<span className="text-sm font-medium text-gray-600">
|
|
37
|
-
Supports Featured Layout:
|
|
38
|
-
</span>
|
|
39
|
-
<span className="ml-2 text-sm">
|
|
40
|
-
{settings.supports_featured_layout ? "Yes" : "No"}
|
|
41
|
-
</span>
|
|
42
|
-
</div>
|
|
43
|
-
{settings.icon && (
|
|
44
|
-
<div>
|
|
45
|
-
<span className="text-sm font-medium text-gray-600">Icon:</span>
|
|
46
|
-
<span className="ml-2 text-sm">{settings.icon}</span>
|
|
47
|
-
</div>
|
|
48
|
-
)}
|
|
49
|
-
{settings.settings_tab_title && (
|
|
50
|
-
<div>
|
|
51
|
-
<span className="text-sm font-medium text-gray-600">
|
|
52
|
-
Settings Tab Title:
|
|
53
|
-
</span>
|
|
54
|
-
<span className="ml-2 text-sm">{settings.settings_tab_title}</span>
|
|
55
|
-
</div>
|
|
56
|
-
)}
|
|
57
|
-
</div>
|
|
16
|
+
// Build values map from preview_props merged with defaultValues
|
|
17
|
+
const values = useMemo(() => {
|
|
18
|
+
const result: Record<string, unknown> = {}
|
|
58
19
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
</h3>
|
|
66
|
-
)}
|
|
67
|
-
<p className="text-green-800 text-sm">
|
|
68
|
-
{settings.setup_instructions.description}
|
|
69
|
-
</p>
|
|
70
|
-
</div>
|
|
71
|
-
)}
|
|
20
|
+
// First, set default values from elements
|
|
21
|
+
for (const element of settings.elements) {
|
|
22
|
+
if (element.defaultValue !== undefined) {
|
|
23
|
+
result[element.id] = element.defaultValue
|
|
24
|
+
}
|
|
25
|
+
}
|
|
72
26
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
{settings.elements.length === 0 ? (
|
|
77
|
-
<p className="text-gray-500 italic">No settings elements defined</p>
|
|
78
|
-
) : (
|
|
79
|
-
<div className="space-y-4">
|
|
80
|
-
{settings.elements.map((element, index) => (
|
|
81
|
-
<SettingsElementCard key={element.id} element={element} index={index} />
|
|
82
|
-
))}
|
|
83
|
-
</div>
|
|
84
|
-
)}
|
|
85
|
-
</div>
|
|
86
|
-
</div>
|
|
87
|
-
);
|
|
88
|
-
}
|
|
27
|
+
// Then, override with preview props
|
|
28
|
+
return { ...result, ...previewProps }
|
|
29
|
+
}, [settings.elements, previewProps])
|
|
89
30
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
31
|
+
// Filter elements based on conditional display
|
|
32
|
+
const visibleElements = useMemo(() => {
|
|
33
|
+
return settings.elements.filter((element) => shouldDisplayElement(element, values))
|
|
34
|
+
}, [settings.elements, values])
|
|
94
35
|
|
|
95
|
-
function SettingsElementCard({ element, index }: SettingsElementCardProps) {
|
|
96
36
|
return (
|
|
97
|
-
<div className="
|
|
98
|
-
<div className="
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
<h4 className="font-semibold text-lg">{element.title || element.label}</h4>
|
|
105
|
-
</div>
|
|
106
|
-
<p className="text-sm text-gray-600 mt-1">
|
|
107
|
-
<span className="font-mono text-xs bg-blue-100 text-blue-800 px-1.5 py-0.5 rounded">
|
|
108
|
-
{element.id}
|
|
109
|
-
</span>
|
|
110
|
-
</p>
|
|
111
|
-
</div>
|
|
112
|
-
<span className="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-purple-100 text-purple-800">
|
|
113
|
-
{element.inputType}
|
|
114
|
-
</span>
|
|
115
|
-
</div>
|
|
116
|
-
|
|
117
|
-
{element.description && (
|
|
118
|
-
<p className="text-sm text-gray-700 mb-3">{element.description}</p>
|
|
119
|
-
)}
|
|
120
|
-
|
|
121
|
-
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
|
|
122
|
-
{element.placeholder && (
|
|
123
|
-
<div>
|
|
124
|
-
<span className="font-medium text-gray-600">Placeholder:</span>
|
|
125
|
-
<span className="ml-2 text-gray-800">{element.placeholder}</span>
|
|
126
|
-
</div>
|
|
127
|
-
)}
|
|
128
|
-
|
|
129
|
-
{element.defaultValue !== undefined && (
|
|
37
|
+
<div className="min-h-screen bg-gray-50">
|
|
38
|
+
<div className="max-w-2xl mx-auto p-6">
|
|
39
|
+
{/* Header */}
|
|
40
|
+
<div className="mb-6 flex items-start gap-3">
|
|
41
|
+
{!iconError && (
|
|
42
|
+
<img src="/app-icon.svg" alt="" className="h-8 w-8 shrink-0" onError={() => setIconError(true)} />
|
|
43
|
+
)}
|
|
130
44
|
<div>
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
: Array.isArray(element.defaultValue)
|
|
136
|
-
? `[${element.defaultValue.join(", ")}]`
|
|
137
|
-
: element.defaultValue}
|
|
138
|
-
</span>
|
|
45
|
+
<h1 className="text-xl font-semibold text-gray-900">{manifest?.name || settings.title}</h1>
|
|
46
|
+
{(manifest?.tagline || settings.overview?.description) && (
|
|
47
|
+
<p className="mt-1 text-sm text-gray-500">{manifest?.tagline || settings.overview?.description}</p>
|
|
48
|
+
)}
|
|
139
49
|
</div>
|
|
140
|
-
|
|
50
|
+
</div>
|
|
141
51
|
|
|
142
|
-
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
</div>
|
|
152
|
-
)}
|
|
153
|
-
{element.validation.minLength !== undefined && (
|
|
154
|
-
<div className="text-xs text-gray-600">
|
|
155
|
-
Min Length: {element.validation.minLength}
|
|
156
|
-
</div>
|
|
157
|
-
)}
|
|
158
|
-
{element.validation.maxLength !== undefined && (
|
|
159
|
-
<div className="text-xs text-gray-600">
|
|
160
|
-
Max Length: {element.validation.maxLength}
|
|
161
|
-
</div>
|
|
162
|
-
)}
|
|
163
|
-
{element.validation.min !== undefined && (
|
|
164
|
-
<div className="text-xs text-gray-600">
|
|
165
|
-
Min: {element.validation.min}
|
|
166
|
-
</div>
|
|
167
|
-
)}
|
|
168
|
-
{element.validation.max !== undefined && (
|
|
169
|
-
<div className="text-xs text-gray-600">
|
|
170
|
-
Max: {element.validation.max}
|
|
171
|
-
</div>
|
|
172
|
-
)}
|
|
173
|
-
{element.validation.maxSize !== undefined && (
|
|
174
|
-
<div className="text-xs text-gray-600">
|
|
175
|
-
Max Size: {element.validation.maxSize}
|
|
176
|
-
</div>
|
|
177
|
-
)}
|
|
178
|
-
{element.validation.pattern && (
|
|
179
|
-
<div className="text-xs text-gray-600 font-mono">
|
|
180
|
-
Pattern: {element.validation.pattern}
|
|
181
|
-
</div>
|
|
182
|
-
)}
|
|
52
|
+
{/* Form Card */}
|
|
53
|
+
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
|
|
54
|
+
{/* Form Header */}
|
|
55
|
+
<div className="px-6 py-4 border-b border-gray-100 bg-gray-50/50">
|
|
56
|
+
<div className="flex items-center justify-between">
|
|
57
|
+
<h2 className="font-semibold text-gray-900">Settings</h2>
|
|
58
|
+
<span className="inline-flex items-center px-2.5 py-1 rounded-md text-xs font-medium bg-gray-100 text-gray-500">
|
|
59
|
+
Preview Mode
|
|
60
|
+
</span>
|
|
183
61
|
</div>
|
|
184
62
|
</div>
|
|
185
|
-
)}
|
|
186
63
|
|
|
187
|
-
|
|
188
|
-
<div className="
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
<span className="font-mono text-blue-700">{option.value}</span>
|
|
194
|
-
<span className="mx-1 text-gray-400">→</span>
|
|
195
|
-
<span>{option.label}</span>
|
|
64
|
+
{/* Form Content */}
|
|
65
|
+
<div className="p-6">
|
|
66
|
+
{visibleElements.length === 0 ? (
|
|
67
|
+
<div className="text-center py-12">
|
|
68
|
+
<div className="w-12 h-12 mx-auto mb-4 rounded-full bg-gray-100 flex items-center justify-center">
|
|
69
|
+
<Settings className="h-6 w-6 text-gray-400" />
|
|
196
70
|
</div>
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
</div>
|
|
200
|
-
)}
|
|
201
|
-
|
|
202
|
-
{element.linkBehaviorLabels && (
|
|
203
|
-
<div className="col-span-2">
|
|
204
|
-
<span className="font-medium text-gray-600">Link Behavior Labels:</span>
|
|
205
|
-
<div className="ml-2 mt-1 space-y-1">
|
|
206
|
-
<div className="text-xs">
|
|
207
|
-
<span className="font-medium">Embed:</span> {element.linkBehaviorLabels.embedLabel}
|
|
71
|
+
<p className="text-sm text-gray-500 font-medium">No settings defined</p>
|
|
72
|
+
<p className="text-xs text-gray-400 mt-1">Add elements to your config to preview the form</p>
|
|
208
73
|
</div>
|
|
209
|
-
|
|
210
|
-
|
|
74
|
+
) : (
|
|
75
|
+
<div className="space-y-6">
|
|
76
|
+
{visibleElements.map((element) => (
|
|
77
|
+
<FormElement key={element.id} element={element} value={values[element.id]} />
|
|
78
|
+
))}
|
|
211
79
|
</div>
|
|
212
|
-
|
|
213
|
-
</div>
|
|
214
|
-
)}
|
|
215
|
-
|
|
216
|
-
{element.accept && element.accept.length > 0 && (
|
|
217
|
-
<div className="col-span-2">
|
|
218
|
-
<span className="font-medium text-gray-600">Accepted Files:</span>
|
|
219
|
-
<span className="ml-2 text-xs font-mono">
|
|
220
|
-
{element.accept.join(", ")}
|
|
221
|
-
</span>
|
|
222
|
-
</div>
|
|
223
|
-
)}
|
|
224
|
-
|
|
225
|
-
{element.multiple && (
|
|
226
|
-
<div>
|
|
227
|
-
<span className="bg-orange-100 text-orange-800 px-2 py-0.5 rounded text-xs">
|
|
228
|
-
Multiple values allowed
|
|
229
|
-
</span>
|
|
230
|
-
</div>
|
|
231
|
-
)}
|
|
232
|
-
|
|
233
|
-
{element.capability && (
|
|
234
|
-
<div>
|
|
235
|
-
<span className="font-medium text-gray-600">Integration Capability:</span>
|
|
236
|
-
<span className="ml-2 text-xs">{element.capability}</span>
|
|
237
|
-
</div>
|
|
238
|
-
)}
|
|
239
|
-
|
|
240
|
-
{element.vendor && (
|
|
241
|
-
<div>
|
|
242
|
-
<span className="font-medium text-gray-600">Vendor:</span>
|
|
243
|
-
<span className="ml-2 text-xs">{element.vendor}</span>
|
|
80
|
+
)}
|
|
244
81
|
</div>
|
|
245
|
-
|
|
82
|
+
</div>
|
|
246
83
|
|
|
247
|
-
{
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
)}
|
|
254
|
-
{element.array_options.add_item_title && (
|
|
255
|
-
<div>Add Title: "{element.array_options.add_item_title}"</div>
|
|
256
|
-
)}
|
|
257
|
-
{element.array_options.edit_item_title && (
|
|
258
|
-
<div>Edit Title: "{element.array_options.edit_item_title}"</div>
|
|
259
|
-
)}
|
|
260
|
-
{element.array_options.item_format && (
|
|
261
|
-
<div>Item Format: "{element.array_options.item_format}"</div>
|
|
262
|
-
)}
|
|
263
|
-
{element.array_options.min !== undefined && (
|
|
264
|
-
<div>Min Items: {element.array_options.min}</div>
|
|
265
|
-
)}
|
|
266
|
-
{element.array_options.max !== undefined && (
|
|
267
|
-
<div>Max Items: {element.array_options.max}</div>
|
|
268
|
-
)}
|
|
269
|
-
</div>
|
|
270
|
-
</div>
|
|
271
|
-
)}
|
|
84
|
+
{/* Metadata Card */}
|
|
85
|
+
<MetadataSummary settings={settings} />
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
272
90
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
<div className="ml-2 mt-2 space-y-2">
|
|
277
|
-
{element.array_elements.map((arrayElement, arrayIndex) => (
|
|
278
|
-
<div key={arrayElement.id} className="bg-gray-50 border border-gray-200 rounded p-3">
|
|
279
|
-
<div className="text-xs font-mono text-blue-700 mb-1">
|
|
280
|
-
{arrayElement.id}
|
|
281
|
-
</div>
|
|
282
|
-
<div className="text-xs">
|
|
283
|
-
<span className="font-medium">Type:</span> {arrayElement.inputType}
|
|
284
|
-
</div>
|
|
285
|
-
{arrayElement.label && (
|
|
286
|
-
<div className="text-xs">
|
|
287
|
-
<span className="font-medium">Label:</span> {arrayElement.label}
|
|
288
|
-
</div>
|
|
289
|
-
)}
|
|
290
|
-
{arrayElement.placeholder && (
|
|
291
|
-
<div className="text-xs">
|
|
292
|
-
<span className="font-medium">Placeholder:</span> {arrayElement.placeholder}
|
|
293
|
-
</div>
|
|
294
|
-
)}
|
|
295
|
-
</div>
|
|
296
|
-
))}
|
|
297
|
-
</div>
|
|
298
|
-
</div>
|
|
299
|
-
)}
|
|
91
|
+
interface MetadataSummaryProps {
|
|
92
|
+
settings: LinkAppSettings
|
|
93
|
+
}
|
|
300
94
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
95
|
+
function MetadataSummary({ settings }: MetadataSummaryProps) {
|
|
96
|
+
const metadata = [
|
|
97
|
+
{
|
|
98
|
+
label: 'Uses URL',
|
|
99
|
+
value: settings.uses_url || settings.has_url ? 'Yes' : 'No',
|
|
100
|
+
},
|
|
101
|
+
settings.featured_chin_position && {
|
|
102
|
+
label: 'Chin Position',
|
|
103
|
+
value: settings.featured_chin_position,
|
|
104
|
+
},
|
|
105
|
+
settings.sheet_behavior && {
|
|
106
|
+
label: 'Sheet Behavior',
|
|
107
|
+
value: settings.sheet_behavior,
|
|
108
|
+
},
|
|
109
|
+
settings.featured_head_click_behavior && {
|
|
110
|
+
label: 'Click Behavior',
|
|
111
|
+
value: settings.featured_head_click_behavior,
|
|
112
|
+
},
|
|
113
|
+
settings.icon && { label: 'Icon', value: settings.icon },
|
|
114
|
+
].filter(Boolean) as Array<{ label: string; value: string }>
|
|
115
|
+
|
|
116
|
+
if (metadata.length === 0) return null
|
|
313
117
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
118
|
+
return (
|
|
119
|
+
<div className="mt-6 bg-white rounded-xl border border-gray-200 overflow-hidden">
|
|
120
|
+
<div className="px-6 py-4 border-b border-gray-100 bg-gray-50/50">
|
|
121
|
+
<h3 className="font-semibold text-gray-900 text-sm">Configuration</h3>
|
|
122
|
+
</div>
|
|
123
|
+
<div className="p-6">
|
|
124
|
+
<div className="grid grid-cols-2 gap-4">
|
|
125
|
+
{metadata.map(({ label, value }) => (
|
|
126
|
+
<div key={label} className="flex items-center justify-between py-2 px-3 rounded-lg bg-gray-50">
|
|
127
|
+
<span className="text-sm text-gray-500">{label}</span>
|
|
128
|
+
<span className="text-sm font-medium text-gray-900">{value}</span>
|
|
324
129
|
</div>
|
|
325
|
-
|
|
326
|
-
|
|
130
|
+
))}
|
|
131
|
+
</div>
|
|
327
132
|
</div>
|
|
328
133
|
</div>
|
|
329
|
-
)
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Evaluates conditional display rules to determine if an element should be shown
|
|
139
|
+
*/
|
|
140
|
+
function shouldDisplayElement(element: SettingsElement, values: Record<string, unknown>): boolean {
|
|
141
|
+
// New format (preferred): conditional with fieldId and values array
|
|
142
|
+
if (element.conditional) {
|
|
143
|
+
const { fieldId, values: allowedValues } = element.conditional
|
|
144
|
+
const currentValue = values[fieldId]
|
|
145
|
+
return allowedValues.some((v) => v === currentValue)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Legacy format (deprecated): conditionalDisplay with dependsOn, value, operator
|
|
149
|
+
if (element.conditionalDisplay) {
|
|
150
|
+
const { dependsOn, value, operator = 'equals' } = element.conditionalDisplay
|
|
151
|
+
const currentValue = values[dependsOn]
|
|
152
|
+
|
|
153
|
+
switch (operator) {
|
|
154
|
+
case 'equals':
|
|
155
|
+
return currentValue === value
|
|
156
|
+
case 'notEquals':
|
|
157
|
+
return currentValue !== value
|
|
158
|
+
case 'contains':
|
|
159
|
+
return typeof currentValue === 'string' && typeof value === 'string' && currentValue.includes(value)
|
|
160
|
+
default:
|
|
161
|
+
return true
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return true
|
|
330
166
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as CheckboxPrimitive from '@radix-ui/react-checkbox'
|
|
2
|
+
import { Check } from 'lucide-react'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
import { cn } from '../../lib/utils'
|
|
6
|
+
|
|
7
|
+
const Checkbox = React.forwardRef<
|
|
8
|
+
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
|
9
|
+
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
|
10
|
+
>(({ className, ...props }, ref) => (
|
|
11
|
+
<CheckboxPrimitive.Root
|
|
12
|
+
ref={ref}
|
|
13
|
+
className={cn(
|
|
14
|
+
'peer h-4 w-4 shrink-0 rounded-sm border border-gray-300 shadow-sm',
|
|
15
|
+
'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-blue-500',
|
|
16
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
17
|
+
'data-[state=checked]:bg-blue-500 data-[state=checked]:border-blue-500 data-[state=checked]:text-white',
|
|
18
|
+
className
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
>
|
|
22
|
+
<CheckboxPrimitive.Indicator className={cn('flex items-center justify-center text-current')}>
|
|
23
|
+
<Check className="h-3.5 w-3.5" strokeWidth={3} />
|
|
24
|
+
</CheckboxPrimitive.Indicator>
|
|
25
|
+
</CheckboxPrimitive.Root>
|
|
26
|
+
))
|
|
27
|
+
Checkbox.displayName = CheckboxPrimitive.Root.displayName
|
|
28
|
+
|
|
29
|
+
export { Checkbox }
|
|
@@ -50,9 +50,7 @@ function DialogContent({
|
|
|
50
50
|
)}
|
|
51
51
|
{...props}
|
|
52
52
|
>
|
|
53
|
-
<div className="flex h-full flex-col">
|
|
54
|
-
{children}
|
|
55
|
-
</div>
|
|
53
|
+
<div className="flex h-full flex-col">{children}</div>
|
|
56
54
|
|
|
57
55
|
{showCloseButton && (
|
|
58
56
|
<DialogPrimitive.Close
|
|
@@ -69,13 +67,7 @@ function DialogContent({
|
|
|
69
67
|
}
|
|
70
68
|
|
|
71
69
|
function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
72
|
-
return (
|
|
73
|
-
<div
|
|
74
|
-
data-slot="dialog-header"
|
|
75
|
-
className={cn(className)}
|
|
76
|
-
{...props}
|
|
77
|
-
/>
|
|
78
|
-
)
|
|
70
|
+
return <div data-slot="dialog-header" className={cn(className)} {...props} />
|
|
79
71
|
}
|
|
80
72
|
|
|
81
73
|
function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
@@ -1,62 +1,37 @@
|
|
|
1
|
-
import * as React from
|
|
1
|
+
import * as React from 'react'
|
|
2
2
|
|
|
3
|
-
import { cn } from
|
|
4
|
-
import { Label } from
|
|
3
|
+
import { cn } from '../../lib/utils'
|
|
4
|
+
import { Label } from './label'
|
|
5
5
|
|
|
6
6
|
interface FieldProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
7
|
-
orientation?:
|
|
7
|
+
orientation?: 'vertical' | 'horizontal'
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const Field = React.forwardRef<HTMLDivElement, FieldProps>(
|
|
11
|
-
|
|
12
|
-
<div
|
|
13
|
-
ref={ref}
|
|
14
|
-
role="group"
|
|
15
|
-
className={cn(
|
|
16
|
-
"space-y-2",
|
|
17
|
-
orientation === "horizontal" && "flex items-start gap-3 space-y-0",
|
|
18
|
-
className
|
|
19
|
-
)}
|
|
20
|
-
{...props}
|
|
21
|
-
/>
|
|
22
|
-
)
|
|
23
|
-
)
|
|
24
|
-
Field.displayName = "Field"
|
|
25
|
-
|
|
26
|
-
const FieldLabel = React.forwardRef<
|
|
27
|
-
React.ElementRef<typeof Label>,
|
|
28
|
-
React.ComponentPropsWithoutRef<typeof Label>
|
|
29
|
-
>(({ className, ...props }, ref) => (
|
|
30
|
-
<Label
|
|
10
|
+
const Field = React.forwardRef<HTMLDivElement, FieldProps>(({ className, orientation = 'vertical', ...props }, ref) => (
|
|
11
|
+
<div
|
|
31
12
|
ref={ref}
|
|
32
|
-
|
|
13
|
+
role="group"
|
|
14
|
+
className={cn('space-y-2', orientation === 'horizontal' && 'flex items-start gap-3 space-y-0', className)}
|
|
33
15
|
{...props}
|
|
34
16
|
/>
|
|
35
17
|
))
|
|
36
|
-
|
|
18
|
+
Field.displayName = 'Field'
|
|
37
19
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
className={cn("text-sm text-gray-500", className)}
|
|
45
|
-
{...props}
|
|
46
|
-
/>
|
|
47
|
-
))
|
|
48
|
-
FieldDescription.displayName = "FieldDescription"
|
|
20
|
+
const FieldLabel = React.forwardRef<React.ElementRef<typeof Label>, React.ComponentPropsWithoutRef<typeof Label>>(
|
|
21
|
+
({ className, ...props }, ref) => (
|
|
22
|
+
<Label ref={ref} className={cn('text-sm font-medium text-gray-900', className)} {...props} />
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
FieldLabel.displayName = 'FieldLabel'
|
|
49
26
|
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
))
|
|
60
|
-
FieldError.displayName = "FieldError"
|
|
27
|
+
const FieldDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
|
|
28
|
+
({ className, ...props }, ref) => <p ref={ref} className={cn('text-sm text-gray-500', className)} {...props} />
|
|
29
|
+
)
|
|
30
|
+
FieldDescription.displayName = 'FieldDescription'
|
|
31
|
+
|
|
32
|
+
const FieldError = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
|
|
33
|
+
({ className, ...props }, ref) => <p ref={ref} className={cn('text-sm text-red-500', className)} {...props} />
|
|
34
|
+
)
|
|
35
|
+
FieldError.displayName = 'FieldError'
|
|
61
36
|
|
|
62
37
|
export { Field, FieldLabel, FieldDescription, FieldError }
|