@pablozaiden/webapp 0.3.9 → 0.3.10
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/src/web/WebAppRoot.tsx +24 -2
- package/src/web/styles.css +38 -1
package/package.json
CHANGED
package/src/web/WebAppRoot.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { startAuthentication, startRegistration } from "@simplewebauthn/browser";
|
|
2
|
-
import { useCallback, useEffect, useMemo, useState, type ReactNode } from "react";
|
|
2
|
+
import { useCallback, useEffect, useId, useMemo, useRef, useState, type ReactNode } from "react";
|
|
3
3
|
import type { ApiKeySummary, AuthSessionSummary, CreatedApiKeyResponse, CreatedUserResponse, DeviceVerificationDetails, PasskeyAuthStatusResponse, ThemePreference, UserSetupDetails, WebAppConfigResponse, WebAppUserRole, WebAppUserSummary } from "../contracts";
|
|
4
4
|
import { ActionMenu, Badge, Button, ConfirmDialog, ContextMenu, DangerZone, Dialog, EmptyState, FormSection, IconButton, Panel, SelectField, TextField, type ContextMenuPosition } from "./components";
|
|
5
5
|
import type { ActionMenuItem, SidebarAction, SidebarBuildContext, SidebarNode, WebAppRoute } from "./sidebar/types";
|
|
@@ -1047,6 +1047,8 @@ export function WebAppRoot({ appName, homeRoute, sidebar, routes, header, onRout
|
|
|
1047
1047
|
const { route, navigate } = useRoute(homeRoute);
|
|
1048
1048
|
const { theme, setTheme } = useTheme();
|
|
1049
1049
|
const [search, setSearch] = useState("");
|
|
1050
|
+
const sidebarSearchId = useId();
|
|
1051
|
+
const sidebarSearchInputRef = useRef<HTMLInputElement>(null);
|
|
1050
1052
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
1051
1053
|
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
|
|
1052
1054
|
const sidebarTreeState = useSidebarCollapsedState(appName);
|
|
@@ -1213,7 +1215,27 @@ export function WebAppRoot({ appName, homeRoute, sidebar, routes, header, onRout
|
|
|
1213
1215
|
</div>
|
|
1214
1216
|
</div>
|
|
1215
1217
|
<div className="wapp-sidebar-scroll">
|
|
1216
|
-
{sidebarSearchEnabled ?
|
|
1218
|
+
{sidebarSearchEnabled ? (
|
|
1219
|
+
<div className="wapp-search">
|
|
1220
|
+
<label className="sr-only" htmlFor={sidebarSearchId}>Search</label>
|
|
1221
|
+
<div className={`wapp-search-input-wrap${search.length > 0 ? " wapp-search-input-wrap--clearable" : ""}`}>
|
|
1222
|
+
<input id={sidebarSearchId} ref={sidebarSearchInputRef} value={search} onInput={(event) => setSearch(event.currentTarget.value)} placeholder="Search" />
|
|
1223
|
+
{search.length > 0 ? (
|
|
1224
|
+
<button
|
|
1225
|
+
type="button"
|
|
1226
|
+
className="wapp-search-clear"
|
|
1227
|
+
aria-label="Clear search"
|
|
1228
|
+
onClick={() => {
|
|
1229
|
+
setSearch("");
|
|
1230
|
+
sidebarSearchInputRef.current?.focus();
|
|
1231
|
+
}}
|
|
1232
|
+
>
|
|
1233
|
+
×
|
|
1234
|
+
</button>
|
|
1235
|
+
) : null}
|
|
1236
|
+
</div>
|
|
1237
|
+
</div>
|
|
1238
|
+
) : null}
|
|
1217
1239
|
<SidebarTree nodes={nodes} route={route} navigate={(next) => { navigate(next); setSidebarOpen(false); }} collapsed={sidebarTreeState.collapsed} toggleCollapsed={sidebarTreeState.toggleCollapsed} searchActive={sidebarSearchActive} />
|
|
1218
1240
|
<div className="wapp-sidebar-footer">v{effectiveVersion}<button type="button" aria-label="Reload" onClick={() => window.location.reload()}><Icon name="refresh" /></button></div>
|
|
1219
1241
|
</div>
|
package/src/web/styles.css
CHANGED
|
@@ -282,10 +282,17 @@ textarea::placeholder {
|
|
|
282
282
|
scroll-padding-bottom: var(--wapp-mobile-bottom-clearance);
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
.wapp-search {
|
|
286
|
+
margin-bottom: 1.5rem;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.wapp-search-input-wrap {
|
|
290
|
+
position: relative;
|
|
291
|
+
}
|
|
292
|
+
|
|
285
293
|
.wapp-search input {
|
|
286
294
|
width: 100%;
|
|
287
295
|
height: 2.625rem;
|
|
288
|
-
margin-bottom: 1.5rem;
|
|
289
296
|
border: 1px solid var(--wapp-border);
|
|
290
297
|
border-radius: 0.75rem;
|
|
291
298
|
background: var(--wapp-surface);
|
|
@@ -296,11 +303,41 @@ textarea::placeholder {
|
|
|
296
303
|
font-size: 0.875rem;
|
|
297
304
|
}
|
|
298
305
|
|
|
306
|
+
.wapp-search-input-wrap--clearable input {
|
|
307
|
+
padding-right: 2.5rem;
|
|
308
|
+
}
|
|
309
|
+
|
|
299
310
|
.wapp-search input:focus {
|
|
300
311
|
border-color: var(--wapp-muted);
|
|
301
312
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--wapp-muted), transparent 70%);
|
|
302
313
|
}
|
|
303
314
|
|
|
315
|
+
.wapp-search-clear {
|
|
316
|
+
position: absolute;
|
|
317
|
+
top: 50%;
|
|
318
|
+
right: 0.375rem;
|
|
319
|
+
width: 1.875rem;
|
|
320
|
+
height: 1.875rem;
|
|
321
|
+
display: inline-flex;
|
|
322
|
+
align-items: center;
|
|
323
|
+
justify-content: center;
|
|
324
|
+
transform: translateY(-50%);
|
|
325
|
+
border: 0;
|
|
326
|
+
border-radius: 999px;
|
|
327
|
+
background: transparent;
|
|
328
|
+
color: var(--wapp-muted);
|
|
329
|
+
cursor: pointer;
|
|
330
|
+
font-size: 1.125rem;
|
|
331
|
+
line-height: 1;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.wapp-search-clear:hover,
|
|
335
|
+
.wapp-search-clear:focus-visible {
|
|
336
|
+
background: color-mix(in srgb, var(--wapp-muted), transparent 88%);
|
|
337
|
+
color: var(--wapp-text);
|
|
338
|
+
outline: none;
|
|
339
|
+
}
|
|
340
|
+
|
|
304
341
|
.wapp-sidebar-section.top {
|
|
305
342
|
margin-bottom: 1.5rem;
|
|
306
343
|
}
|