@schandlergarcia/sf-web-components 1.2.16 → 1.2.18
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 +1 -1
- package/scripts/reset-command-center.sh +127 -163
package/package.json
CHANGED
|
@@ -122,14 +122,67 @@ HOME="src/pages/Home.tsx"
|
|
|
122
122
|
echo "→ Updating ${HOME}..."
|
|
123
123
|
|
|
124
124
|
cat > "$HOME" << 'HOME_EOF'
|
|
125
|
-
import
|
|
125
|
+
import { useState } from "react";
|
|
126
|
+
import { useNavigate } from "react-router";
|
|
127
|
+
import UIInput from '@/components/library/ui/UIInput';
|
|
128
|
+
import UIButton from '@/components/library/ui/UIButton';
|
|
129
|
+
import { Search } from "lucide-react";
|
|
130
|
+
|
|
131
|
+
export default function HomePage() {
|
|
132
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
133
|
+
const navigate = useNavigate();
|
|
134
|
+
|
|
135
|
+
const handleSearch = () => {
|
|
136
|
+
const trimmed = searchQuery.trim();
|
|
137
|
+
if (trimmed) {
|
|
138
|
+
navigate(`/accounts?search=${encodeURIComponent(trimmed)}`);
|
|
139
|
+
} else {
|
|
140
|
+
navigate('/accounts');
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
145
|
+
if (e.key === "Enter") {
|
|
146
|
+
e.preventDefault();
|
|
147
|
+
handleSearch();
|
|
148
|
+
}
|
|
149
|
+
};
|
|
126
150
|
|
|
127
|
-
|
|
128
|
-
|
|
151
|
+
return (
|
|
152
|
+
<div className="flex min-h-[80vh] items-center justify-center px-4 sm:px-6 lg:px-8 bg-slate-50 dark:bg-slate-950 transition-colors">
|
|
153
|
+
<div className="w-full max-w-4xl">
|
|
154
|
+
<div className="text-center mb-8">
|
|
155
|
+
<h1 className="text-4xl font-bold text-slate-900 dark:text-slate-50 mb-4">Search</h1>
|
|
156
|
+
<p className="text-lg text-slate-600 dark:text-slate-300">Find records across your organization.</p>
|
|
157
|
+
</div>
|
|
158
|
+
<div className="flex flex-col gap-4">
|
|
159
|
+
<div className="relative">
|
|
160
|
+
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-slate-400" />
|
|
161
|
+
<UIInput
|
|
162
|
+
type="text"
|
|
163
|
+
value={searchQuery}
|
|
164
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
165
|
+
onKeyDown={handleKeyDown}
|
|
166
|
+
placeholder="Search..."
|
|
167
|
+
className="pl-10 w-full"
|
|
168
|
+
/>
|
|
169
|
+
</div>
|
|
170
|
+
<div className="flex gap-3 justify-center">
|
|
171
|
+
<UIButton onClick={handleSearch} variant="primary">
|
|
172
|
+
Search
|
|
173
|
+
</UIButton>
|
|
174
|
+
<UIButton onClick={() => navigate('/accounts')} variant="secondary">
|
|
175
|
+
Browse All
|
|
176
|
+
</UIButton>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
);
|
|
129
182
|
}
|
|
130
183
|
HOME_EOF
|
|
131
184
|
|
|
132
|
-
echo " ✓ Home renders
|
|
185
|
+
echo " ✓ Home renders search interface"
|
|
133
186
|
echo ""
|
|
134
187
|
|
|
135
188
|
# ── 5. Ensure Search.tsx page exists ─────────────────────────────────────────
|
|
@@ -138,17 +191,60 @@ SEARCH="src/pages/Search.tsx"
|
|
|
138
191
|
echo "→ Updating ${SEARCH}..."
|
|
139
192
|
|
|
140
193
|
cat > "$SEARCH" << 'SEARCH_EOF'
|
|
141
|
-
import {
|
|
194
|
+
import { useState } from "react";
|
|
195
|
+
import { useNavigate } from "react-router";
|
|
196
|
+
import UIInput from '@/components/library/ui/UIInput';
|
|
197
|
+
import UIButton from '@/components/library/ui/UIButton';
|
|
198
|
+
import { Search as SearchIcon } from "lucide-react";
|
|
142
199
|
|
|
143
200
|
export default function Search() {
|
|
201
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
202
|
+
const navigate = useNavigate();
|
|
203
|
+
|
|
204
|
+
const handleSearch = () => {
|
|
205
|
+
const trimmed = searchQuery.trim();
|
|
206
|
+
if (trimmed) {
|
|
207
|
+
navigate(`/accounts?search=${encodeURIComponent(trimmed)}`);
|
|
208
|
+
} else {
|
|
209
|
+
navigate('/accounts');
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
214
|
+
if (e.key === "Enter") {
|
|
215
|
+
e.preventDefault();
|
|
216
|
+
handleSearch();
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
144
220
|
return (
|
|
145
|
-
<div className="flex min-h-[80vh] items-center justify-center px-4 sm:px-6 lg:px-8">
|
|
221
|
+
<div className="flex min-h-[80vh] items-center justify-center px-4 sm:px-6 lg:px-8 bg-slate-50 dark:bg-slate-950 transition-colors">
|
|
146
222
|
<div className="w-full max-w-4xl">
|
|
147
223
|
<div className="text-center mb-8">
|
|
148
224
|
<h1 className="text-4xl font-bold text-slate-900 dark:text-slate-50 mb-4">Search</h1>
|
|
149
225
|
<p className="text-lg text-slate-600 dark:text-slate-300">Find records across your organization.</p>
|
|
150
226
|
</div>
|
|
151
|
-
<
|
|
227
|
+
<div className="flex flex-col gap-4">
|
|
228
|
+
<div className="relative">
|
|
229
|
+
<SearchIcon className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-slate-400" />
|
|
230
|
+
<UIInput
|
|
231
|
+
type="text"
|
|
232
|
+
value={searchQuery}
|
|
233
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
234
|
+
onKeyDown={handleKeyDown}
|
|
235
|
+
placeholder="Search..."
|
|
236
|
+
className="pl-10 w-full"
|
|
237
|
+
/>
|
|
238
|
+
</div>
|
|
239
|
+
<div className="flex gap-3 justify-center">
|
|
240
|
+
<UIButton onClick={handleSearch} variant="primary">
|
|
241
|
+
Search
|
|
242
|
+
</UIButton>
|
|
243
|
+
<UIButton onClick={() => navigate('/accounts')} variant="secondary">
|
|
244
|
+
Browse All
|
|
245
|
+
</UIButton>
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
152
248
|
</div>
|
|
153
249
|
</div>
|
|
154
250
|
);
|
|
@@ -165,178 +261,43 @@ echo "→ Updating ${ROUTES}..."
|
|
|
165
261
|
|
|
166
262
|
cat > "$ROUTES" << 'ROUTES_EOF'
|
|
167
263
|
import type { RouteObject } from 'react-router';
|
|
168
|
-
import
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const NotFound = lazy(() => import('./pages/NotFound'));
|
|
174
|
-
const TestAccPage = lazy(() => import("./pages/TestAccPage"));
|
|
175
|
-
const GlobalSearch = lazy(() => import("./features/global-search/pages/GlobalSearch"));
|
|
176
|
-
const DetailPage = lazy(() => import("./features/global-search/pages/DetailPage"));
|
|
177
|
-
|
|
178
|
-
function SuspenseWrap({ children }: { children: React.ReactNode }) {
|
|
179
|
-
return <Suspense fallback={<div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">Loading...</div>}>{children}</Suspense>;
|
|
180
|
-
}
|
|
264
|
+
import Home from './pages/Home';
|
|
265
|
+
import NotFound from './pages/NotFound';
|
|
266
|
+
import AuthAppLayout from "./features/authentication/layouts/AuthAppLayout";
|
|
267
|
+
import AccountSearch from "./features/object-search/__examples__/pages/AccountSearch";
|
|
268
|
+
import AccountObjectDetail from "./features/object-search/__examples__/pages/AccountObjectDetailPage";
|
|
181
269
|
|
|
182
270
|
export const routes: RouteObject[] = [
|
|
183
271
|
{
|
|
184
272
|
path: "/",
|
|
185
|
-
element:
|
|
186
|
-
<SuspenseWrap>
|
|
187
|
-
<AppLayout />
|
|
188
|
-
</SuspenseWrap>
|
|
189
|
-
),
|
|
273
|
+
element: <AuthAppLayout />,
|
|
190
274
|
children: [
|
|
191
275
|
{
|
|
192
276
|
index: true,
|
|
193
|
-
element: <
|
|
194
|
-
handle: { showInNavigation: true, showNavBar: true, label:
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
path: "search",
|
|
198
|
-
element: <SuspenseWrap><Search /></SuspenseWrap>,
|
|
199
|
-
handle: { showInNavigation: true, showNavBar: true, label: 'Search' }
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
path: "test-acc",
|
|
203
|
-
element: <SuspenseWrap><TestAccPage /></SuspenseWrap>,
|
|
204
|
-
handle: { showInNavigation: true, label: "Test ACC" }
|
|
277
|
+
element: <Home />,
|
|
278
|
+
handle: { showInNavigation: true, showNavBar: true, label: "Home" }
|
|
205
279
|
},
|
|
206
280
|
{
|
|
207
|
-
path: "
|
|
208
|
-
element:
|
|
209
|
-
<SuspenseWrap>
|
|
210
|
-
<GlobalSearch />
|
|
211
|
-
</SuspenseWrap>
|
|
212
|
-
),
|
|
213
|
-
handle: { showInNavigation: false }
|
|
281
|
+
path: "accounts",
|
|
282
|
+
element: <AccountSearch />
|
|
214
283
|
},
|
|
215
284
|
{
|
|
216
|
-
path: "
|
|
217
|
-
element:
|
|
218
|
-
<SuspenseWrap>
|
|
219
|
-
<DetailPage />
|
|
220
|
-
</SuspenseWrap>
|
|
221
|
-
),
|
|
222
|
-
handle: { showInNavigation: false }
|
|
285
|
+
path: "accounts/:recordId",
|
|
286
|
+
element: <AccountObjectDetail />
|
|
223
287
|
},
|
|
224
288
|
{
|
|
225
289
|
path: '*',
|
|
226
|
-
element: <
|
|
227
|
-
}
|
|
290
|
+
element: <NotFound />
|
|
291
|
+
}
|
|
228
292
|
]
|
|
229
293
|
}
|
|
230
294
|
];
|
|
231
295
|
ROUTES_EOF
|
|
232
296
|
|
|
233
|
-
echo " ✓ Routes updated (Home at
|
|
234
|
-
echo ""
|
|
235
|
-
|
|
236
|
-
# ── 7. Reset appLayout.tsx (nav on Home/Search only) ─────────────────────────
|
|
237
|
-
|
|
238
|
-
LAYOUT="src/appLayout.tsx"
|
|
239
|
-
echo "→ Updating ${LAYOUT}..."
|
|
240
|
-
|
|
241
|
-
cat > "$LAYOUT" << 'LAYOUT_EOF'
|
|
242
|
-
import { AgentforceConversationClient } from "./components/AgentforceConversationClient";
|
|
243
|
-
import { Outlet, Link, useLocation, useMatches } from "react-router";
|
|
244
|
-
import { getAllRoutes } from "./router-utils";
|
|
245
|
-
import { useState } from "react";
|
|
246
|
-
|
|
247
|
-
export default function AppLayout() {
|
|
248
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
249
|
-
const location = useLocation();
|
|
250
|
-
const matches = useMatches();
|
|
251
|
-
|
|
252
|
-
const showNavBar = matches.some(
|
|
253
|
-
(m) => (m.handle as Record<string, unknown>)?.showNavBar === true,
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
const isActive = (path: string) => location.pathname === path;
|
|
257
|
-
|
|
258
|
-
const toggleMenu = () => setIsOpen(!isOpen);
|
|
259
|
-
|
|
260
|
-
const navigationRoutes: { path: string; label: string }[] = getAllRoutes()
|
|
261
|
-
.filter(
|
|
262
|
-
(route) =>
|
|
263
|
-
route.handle?.showInNavigation === true &&
|
|
264
|
-
route.fullPath !== undefined &&
|
|
265
|
-
route.handle?.label !== undefined,
|
|
266
|
-
)
|
|
267
|
-
.map(
|
|
268
|
-
(route) =>
|
|
269
|
-
({
|
|
270
|
-
path: route.fullPath,
|
|
271
|
-
label: route.handle?.label,
|
|
272
|
-
}) as { path: string; label: string },
|
|
273
|
-
);
|
|
274
|
-
|
|
275
|
-
return (
|
|
276
|
-
<>
|
|
277
|
-
{showNavBar && (
|
|
278
|
-
<nav className="bg-white border-b border-gray-200">
|
|
279
|
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
280
|
-
<div className="flex justify-between items-center h-16">
|
|
281
|
-
<Link to="/" className="text-xl font-semibold text-gray-900">
|
|
282
|
-
React App
|
|
283
|
-
</Link>
|
|
284
|
-
<button
|
|
285
|
-
onClick={toggleMenu}
|
|
286
|
-
className="p-2 rounded-md text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
287
|
-
aria-label="Toggle menu"
|
|
288
|
-
>
|
|
289
|
-
<div className="w-6 h-6 flex flex-col justify-center space-y-1.5">
|
|
290
|
-
<span
|
|
291
|
-
className={`block h-0.5 w-6 bg-current transition-all ${
|
|
292
|
-
isOpen ? "rotate-45 translate-y-2" : ""
|
|
293
|
-
}`}
|
|
294
|
-
/>
|
|
295
|
-
<span
|
|
296
|
-
className={`block h-0.5 w-6 bg-current transition-all ${isOpen ? "opacity-0" : ""}`}
|
|
297
|
-
/>
|
|
298
|
-
<span
|
|
299
|
-
className={`block h-0.5 w-6 bg-current transition-all ${
|
|
300
|
-
isOpen ? "-rotate-45 -translate-y-2" : ""
|
|
301
|
-
}`}
|
|
302
|
-
/>
|
|
303
|
-
</div>
|
|
304
|
-
</button>
|
|
305
|
-
</div>
|
|
306
|
-
{isOpen && (
|
|
307
|
-
<div className="pb-4">
|
|
308
|
-
<div className="flex flex-col space-y-2">
|
|
309
|
-
{navigationRoutes.map((item) => (
|
|
310
|
-
<Link
|
|
311
|
-
key={item.path}
|
|
312
|
-
to={item.path}
|
|
313
|
-
onClick={() => setIsOpen(false)}
|
|
314
|
-
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
315
|
-
isActive(item.path)
|
|
316
|
-
? "bg-blue-100 text-blue-700"
|
|
317
|
-
: "text-gray-700 hover:bg-gray-100"
|
|
318
|
-
}`}
|
|
319
|
-
>
|
|
320
|
-
{item.label}
|
|
321
|
-
</Link>
|
|
322
|
-
))}
|
|
323
|
-
</div>
|
|
324
|
-
</div>
|
|
325
|
-
)}
|
|
326
|
-
</div>
|
|
327
|
-
</nav>
|
|
328
|
-
)}
|
|
329
|
-
<Outlet />
|
|
330
|
-
<AgentforceConversationClient />
|
|
331
|
-
</>
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
LAYOUT_EOF
|
|
335
|
-
|
|
336
|
-
echo " ✓ Layout updated (nav bar on Home/Search pages)"
|
|
297
|
+
echo " ✓ Routes updated (Home at /)"
|
|
337
298
|
echo ""
|
|
338
299
|
|
|
339
|
-
# ──
|
|
300
|
+
# ── 7. Clear Vite cache ─────────────────────────────────────────────────────
|
|
340
301
|
|
|
341
302
|
echo "→ Cleaning caches…"
|
|
342
303
|
rm -rf node_modules/.vite 2>/dev/null && echo " ✓ Cleared Vite cache" || true
|
|
@@ -351,16 +312,19 @@ echo "║ Everything preserved: ║"
|
|
|
351
312
|
echo "║ • Theme (global.css + initialMode) ║"
|
|
352
313
|
echo "║ • Component library (cards, charts, etc.) ║"
|
|
353
314
|
echo "║ • HeroUI wrappers & theme providers ║"
|
|
354
|
-
echo "║ •
|
|
315
|
+
echo "║ • Authentication features ║"
|
|
355
316
|
echo "║ • All styles & dependencies ║"
|
|
356
317
|
echo "║ ║"
|
|
357
318
|
echo "║ Layout: ║"
|
|
358
|
-
echo "║ / → Home (
|
|
359
|
-
echo "║ /
|
|
360
|
-
echo "║
|
|
319
|
+
echo "║ / → Home (Search interface) ║"
|
|
320
|
+
echo "║ /accounts → Account search and browse ║"
|
|
321
|
+
echo "║ ║"
|
|
322
|
+
echo "║ Search functionality: ║"
|
|
323
|
+
echo "║ • Search button navigates to /accounts ║"
|
|
324
|
+
echo "║ • Enter key in search input triggers search║"
|
|
325
|
+
echo "║ • Browse All button shows all accounts ║"
|
|
361
326
|
echo "║ ║"
|
|
362
327
|
echo "║ Start building: ║"
|
|
363
|
-
echo "║ Edit src/components/pages/BlankDashboard.jsx║"
|
|
364
328
|
echo "║ npm run dev ║"
|
|
365
329
|
echo "╚════════════════════════════════════════════════╝"
|
|
366
330
|
echo ""
|