@pablozaiden/webapp 0.3.8 → 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 +26 -3
- 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);
|
|
@@ -1112,6 +1114,7 @@ export function WebAppRoot({ appName, homeRoute, sidebar, routes, header, onRout
|
|
|
1112
1114
|
...augmented,
|
|
1113
1115
|
];
|
|
1114
1116
|
}, [augmentPinningActions, baseNodes, currentPins, filteredNodes, pinningEnabled, sidebar.pinning, sidebarSearchActive]);
|
|
1117
|
+
const activeActionNodes = useMemo(() => augmentPinningActions(baseNodes), [augmentPinningActions, baseNodes]);
|
|
1115
1118
|
|
|
1116
1119
|
useEffect(() => {
|
|
1117
1120
|
if (!config?.currentUser) return;
|
|
@@ -1176,7 +1179,7 @@ export function WebAppRoot({ appName, homeRoute, sidebar, routes, header, onRout
|
|
|
1176
1179
|
const topActions = sidebar.topActions?.slice(0, 2) ?? [];
|
|
1177
1180
|
const defaultTitle = route.view === "settings" ? "Settings" : route.view === homeRoute.view ? appName : route.view.replace(/-/g, " ");
|
|
1178
1181
|
const headerContext = { route, defaultTitle };
|
|
1179
|
-
const activeSidebarNode = flattenSidebarItems(
|
|
1182
|
+
const activeSidebarNode = flattenSidebarItems(activeActionNodes).find((node) => routeMatches(node.route, route));
|
|
1180
1183
|
const activeSidebarActions = activeSidebarNode?.actions ?? [];
|
|
1181
1184
|
const headerActions = [
|
|
1182
1185
|
...(header?.getActions?.(headerContext) ?? []),
|
|
@@ -1212,7 +1215,27 @@ export function WebAppRoot({ appName, homeRoute, sidebar, routes, header, onRout
|
|
|
1212
1215
|
</div>
|
|
1213
1216
|
</div>
|
|
1214
1217
|
<div className="wapp-sidebar-scroll">
|
|
1215
|
-
{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}
|
|
1216
1239
|
<SidebarTree nodes={nodes} route={route} navigate={(next) => { navigate(next); setSidebarOpen(false); }} collapsed={sidebarTreeState.collapsed} toggleCollapsed={sidebarTreeState.toggleCollapsed} searchActive={sidebarSearchActive} />
|
|
1217
1240
|
<div className="wapp-sidebar-footer">v{effectiveVersion}<button type="button" aria-label="Reload" onClick={() => window.location.reload()}><Icon name="refresh" /></button></div>
|
|
1218
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
|
}
|