@byline/host-tanstack-start 2.2.4 → 2.2.6
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/dist/admin-shell/chrome/menu-drawer_module.css +3 -2
- package/dist/admin-shell/chrome/route-progress-bar.d.ts +1 -0
- package/dist/admin-shell/chrome/route-progress-bar.js +83 -0
- package/dist/admin-shell/chrome/route-progress-bar.module.js +7 -0
- package/dist/admin-shell/chrome/route-progress-bar_module.css +25 -0
- package/dist/routes/create-admin-layout-route.js +2 -0
- package/package.json +7 -7
- package/src/admin-shell/chrome/menu-drawer.module.css +27 -8
- package/src/admin-shell/chrome/route-progress-bar.module.css +41 -0
- package/src/admin-shell/chrome/route-progress-bar.tsx +128 -0
- package/src/routes/create-admin-layout-route.tsx +2 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
:is(.aside-zO2mZZ, .byline-admin-menu-drawer-aside) {
|
|
2
|
-
border-right: var(--border-width-thin) var(--border-style-solid)
|
|
2
|
+
border-right: var(--border-width-thin) var(--border-style-solid)
|
|
3
|
+
var(--gray-50);
|
|
3
4
|
background-color: var(--canvas-25);
|
|
4
|
-
z-index:
|
|
5
|
+
z-index: 40;
|
|
5
6
|
flex-direction: column;
|
|
6
7
|
transition: all .3s ease-in-out;
|
|
7
8
|
display: flex;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function RouteProgressBar(): import("react").JSX.Element;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { useRouterState } from "@tanstack/react-router";
|
|
5
|
+
import classnames from "classnames";
|
|
6
|
+
import route_progress_bar_module from "./route-progress-bar.module.js";
|
|
7
|
+
const SHOW_DELAY_MS = 80;
|
|
8
|
+
const MIN_VISIBLE_MS = 250;
|
|
9
|
+
const FINISH_EXIT_MS = 350;
|
|
10
|
+
function RouteProgressBar() {
|
|
11
|
+
const isNavigating = useRouterState({
|
|
12
|
+
select: (s)=>s.isLoading || s.isTransitioning
|
|
13
|
+
});
|
|
14
|
+
const [phase, setPhase] = useState('idle');
|
|
15
|
+
const showTimerRef = useRef(null);
|
|
16
|
+
const finishTimerRef = useRef(null);
|
|
17
|
+
const resetTimerRef = useRef(null);
|
|
18
|
+
const visibleSinceRef = useRef(null);
|
|
19
|
+
useEffect(()=>{
|
|
20
|
+
const clearShow = ()=>{
|
|
21
|
+
if (showTimerRef.current) {
|
|
22
|
+
clearTimeout(showTimerRef.current);
|
|
23
|
+
showTimerRef.current = null;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const clearFinish = ()=>{
|
|
27
|
+
if (finishTimerRef.current) {
|
|
28
|
+
clearTimeout(finishTimerRef.current);
|
|
29
|
+
finishTimerRef.current = null;
|
|
30
|
+
}
|
|
31
|
+
if (resetTimerRef.current) {
|
|
32
|
+
clearTimeout(resetTimerRef.current);
|
|
33
|
+
resetTimerRef.current = null;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
if (isNavigating) {
|
|
37
|
+
clearFinish();
|
|
38
|
+
if ('finishing' === phase) {
|
|
39
|
+
visibleSinceRef.current = performance.now();
|
|
40
|
+
setPhase('visible');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if ('idle' === phase && null === showTimerRef.current) showTimerRef.current = setTimeout(()=>{
|
|
44
|
+
showTimerRef.current = null;
|
|
45
|
+
visibleSinceRef.current = performance.now();
|
|
46
|
+
setPhase('visible');
|
|
47
|
+
}, SHOW_DELAY_MS);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (null !== showTimerRef.current) return void clearShow();
|
|
51
|
+
if ('visible' === phase) {
|
|
52
|
+
const elapsed = performance.now() - (visibleSinceRef.current ?? 0);
|
|
53
|
+
const wait = Math.max(0, MIN_VISIBLE_MS - elapsed);
|
|
54
|
+
finishTimerRef.current = setTimeout(()=>{
|
|
55
|
+
finishTimerRef.current = null;
|
|
56
|
+
setPhase('finishing');
|
|
57
|
+
resetTimerRef.current = setTimeout(()=>{
|
|
58
|
+
resetTimerRef.current = null;
|
|
59
|
+
visibleSinceRef.current = null;
|
|
60
|
+
setPhase('idle');
|
|
61
|
+
}, FINISH_EXIT_MS);
|
|
62
|
+
}, wait);
|
|
63
|
+
}
|
|
64
|
+
}, [
|
|
65
|
+
isNavigating,
|
|
66
|
+
phase
|
|
67
|
+
]);
|
|
68
|
+
useEffect(()=>()=>{
|
|
69
|
+
if (showTimerRef.current) clearTimeout(showTimerRef.current);
|
|
70
|
+
if (finishTimerRef.current) clearTimeout(finishTimerRef.current);
|
|
71
|
+
if (resetTimerRef.current) clearTimeout(resetTimerRef.current);
|
|
72
|
+
}, []);
|
|
73
|
+
return /*#__PURE__*/ jsx("div", {
|
|
74
|
+
"aria-hidden": "true",
|
|
75
|
+
className: classnames('byline-route-progress-bar', route_progress_bar_module.bar, {
|
|
76
|
+
[route_progress_bar_module.barVisible]: 'visible' === phase,
|
|
77
|
+
'byline-route-progress-bar-visible': 'visible' === phase,
|
|
78
|
+
[route_progress_bar_module.barFinishing]: 'finishing' === phase,
|
|
79
|
+
'byline-route-progress-bar-finishing': 'finishing' === phase
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
export { RouteProgressBar };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
:is(.bar-KT7kQq, .byline-route-progress-bar) {
|
|
2
|
+
z-index: 100;
|
|
3
|
+
background-color: var(--primary-500);
|
|
4
|
+
opacity: 0;
|
|
5
|
+
pointer-events: none;
|
|
6
|
+
will-change: width, opacity;
|
|
7
|
+
width: 0%;
|
|
8
|
+
height: 2px;
|
|
9
|
+
position: fixed;
|
|
10
|
+
top: 0;
|
|
11
|
+
left: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
:is(.barVisible-qOhb8T, .byline-route-progress-bar-visible) {
|
|
15
|
+
opacity: 1;
|
|
16
|
+
width: 90%;
|
|
17
|
+
transition: width 8s cubic-bezier(0, .6, .1, 1), opacity .1s linear;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
:is(.barFinishing-Ifa7gF, .byline-route-progress-bar-finishing) {
|
|
21
|
+
opacity: 0;
|
|
22
|
+
width: 100%;
|
|
23
|
+
transition: width .18s ease-out, opacity .25s ease-out 80ms;
|
|
24
|
+
}
|
|
25
|
+
|
|
@@ -9,6 +9,7 @@ import { DrawerToggle } from "../admin-shell/chrome/drawer-toggle.js";
|
|
|
9
9
|
import { AdminMenuDrawer } from "../admin-shell/chrome/menu-drawer.js";
|
|
10
10
|
import { AdminMenuProvider } from "../admin-shell/chrome/menu-provider.js";
|
|
11
11
|
import { RouteError, RouteNotFound } from "../admin-shell/chrome/route-error.js";
|
|
12
|
+
import { RouteProgressBar } from "../admin-shell/chrome/route-progress-bar.js";
|
|
12
13
|
import { bylineAdminServices } from "../integrations/byline-admin-services.js";
|
|
13
14
|
import { BylineAiAdminProvider } from "../integrations/byline-ai.js";
|
|
14
15
|
import { bylineFieldServices } from "../integrations/byline-field-services.js";
|
|
@@ -40,6 +41,7 @@ function createAdminLayoutRoute(path, opts = {}) {
|
|
|
40
41
|
children: /*#__PURE__*/ jsx(BylineAiAdminProvider, {
|
|
41
42
|
children: /*#__PURE__*/ jsxs(AdminMenuProvider, {
|
|
42
43
|
children: [
|
|
44
|
+
/*#__PURE__*/ jsx(RouteProgressBar, {}),
|
|
43
45
|
/*#__PURE__*/ jsx(AdminAppBar, {
|
|
44
46
|
user: user
|
|
45
47
|
}),
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"private": false,
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
|
-
"version": "2.2.
|
|
6
|
+
"version": "2.2.6",
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=20.9.0"
|
|
9
9
|
},
|
|
@@ -107,12 +107,12 @@
|
|
|
107
107
|
"react-swipeable": "^7.0.2",
|
|
108
108
|
"uuid": "^14.0.0",
|
|
109
109
|
"zod": "^4.4.3",
|
|
110
|
-
"@byline/
|
|
111
|
-
"@byline/
|
|
112
|
-
"@byline/
|
|
113
|
-
"@byline/
|
|
114
|
-
"@byline/
|
|
115
|
-
"@byline/
|
|
110
|
+
"@byline/auth": "2.2.6",
|
|
111
|
+
"@byline/client": "2.2.6",
|
|
112
|
+
"@byline/core": "2.2.6",
|
|
113
|
+
"@byline/ui": "2.2.6",
|
|
114
|
+
"@byline/ai": "2.2.6",
|
|
115
|
+
"@byline/admin": "2.2.6"
|
|
116
116
|
},
|
|
117
117
|
"peerDependencies": {
|
|
118
118
|
"@tanstack/react-router": "^1.167.0",
|
|
@@ -16,14 +16,16 @@
|
|
|
16
16
|
:global(.byline-admin-menu-drawer-aside) {
|
|
17
17
|
display: flex;
|
|
18
18
|
flex-direction: column;
|
|
19
|
-
border-right: var(--border-width-thin) var(--border-style-solid)
|
|
19
|
+
border-right: var(--border-width-thin) var(--border-style-solid)
|
|
20
|
+
var(--gray-50);
|
|
20
21
|
background-color: var(--canvas-25);
|
|
21
|
-
z-index:
|
|
22
|
+
z-index: 40;
|
|
22
23
|
transition: all 300ms ease-in-out;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
:is([data-theme="dark"], :global(.dark)) .aside,
|
|
26
|
-
:is([data-theme="dark"], :global(.dark))
|
|
27
|
+
:is([data-theme="dark"], :global(.dark))
|
|
28
|
+
:global(.byline-admin-menu-drawer-aside) {
|
|
27
29
|
border-right-color: var(--canvas-700);
|
|
28
30
|
background-color: var(--canvas-800);
|
|
29
31
|
}
|
|
@@ -132,18 +134,27 @@
|
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
.nav ul :global(li.menu-item) :is(a, button):disabled,
|
|
135
|
-
:global(.byline-admin-menu-drawer)
|
|
137
|
+
:global(.byline-admin-menu-drawer)
|
|
138
|
+
ul
|
|
139
|
+
:global(li.menu-item)
|
|
140
|
+
:is(a, button):disabled {
|
|
136
141
|
cursor: not-allowed;
|
|
137
142
|
opacity: 0.6;
|
|
138
143
|
}
|
|
139
144
|
|
|
140
145
|
.nav ul :global(li.menu-item.compact) :is(a, button),
|
|
141
|
-
:global(.byline-admin-menu-drawer)
|
|
146
|
+
:global(.byline-admin-menu-drawer)
|
|
147
|
+
ul
|
|
148
|
+
:global(li.menu-item.compact)
|
|
149
|
+
:is(a, button) {
|
|
142
150
|
justify-content: center;
|
|
143
151
|
}
|
|
144
152
|
|
|
145
153
|
.nav ul :global(li.menu-item.active) :is(a, button),
|
|
146
|
-
:global(.byline-admin-menu-drawer)
|
|
154
|
+
:global(.byline-admin-menu-drawer)
|
|
155
|
+
ul
|
|
156
|
+
:global(li.menu-item.active)
|
|
157
|
+
:is(a, button) {
|
|
147
158
|
color: #111111;
|
|
148
159
|
text-decoration: none;
|
|
149
160
|
}
|
|
@@ -156,7 +167,11 @@
|
|
|
156
167
|
background-color: #dddddd;
|
|
157
168
|
}
|
|
158
169
|
|
|
159
|
-
:is([data-theme="dark"], :global(.dark))
|
|
170
|
+
:is([data-theme="dark"], :global(.dark))
|
|
171
|
+
.nav
|
|
172
|
+
ul
|
|
173
|
+
:global(li.menu-item)
|
|
174
|
+
:is(a, button),
|
|
160
175
|
:is([data-theme="dark"], :global(.dark))
|
|
161
176
|
:global(.byline-admin-menu-drawer)
|
|
162
177
|
ul
|
|
@@ -165,7 +180,11 @@
|
|
|
165
180
|
color: #dddddd;
|
|
166
181
|
}
|
|
167
182
|
|
|
168
|
-
:is([data-theme="dark"], :global(.dark))
|
|
183
|
+
:is([data-theme="dark"], :global(.dark))
|
|
184
|
+
.nav
|
|
185
|
+
ul
|
|
186
|
+
:global(li.menu-item.active)
|
|
187
|
+
:is(a, button),
|
|
169
188
|
:is([data-theme="dark"], :global(.dark))
|
|
170
189
|
:global(.byline-admin-menu-drawer)
|
|
171
190
|
ul
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RouteProgressBar — top-of-viewport indeterminate progress indicator for
|
|
3
|
+
* admin route transitions.
|
|
4
|
+
*
|
|
5
|
+
* Override handles:
|
|
6
|
+
* .byline-route-progress-bar — base bar element
|
|
7
|
+
* .byline-route-progress-bar-visible — bar is growing (navigation in flight)
|
|
8
|
+
* .byline-route-progress-bar-finishing — bar is completing + fading out
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
.bar,
|
|
12
|
+
:global(.byline-route-progress-bar) {
|
|
13
|
+
position: fixed;
|
|
14
|
+
top: 0;
|
|
15
|
+
left: 0;
|
|
16
|
+
z-index: 100;
|
|
17
|
+
height: 2px;
|
|
18
|
+
width: 0%;
|
|
19
|
+
background-color: var(--primary-500);
|
|
20
|
+
opacity: 0;
|
|
21
|
+
pointer-events: none;
|
|
22
|
+
will-change: width, opacity;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.barVisible,
|
|
26
|
+
:global(.byline-route-progress-bar-visible) {
|
|
27
|
+
width: 90%;
|
|
28
|
+
opacity: 1;
|
|
29
|
+
transition:
|
|
30
|
+
width 8s cubic-bezier(0, 0.6, 0.1, 1),
|
|
31
|
+
opacity 100ms linear;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.barFinishing,
|
|
35
|
+
:global(.byline-route-progress-bar-finishing) {
|
|
36
|
+
width: 100%;
|
|
37
|
+
opacity: 0;
|
|
38
|
+
transition:
|
|
39
|
+
width 180ms ease-out,
|
|
40
|
+
opacity 250ms ease-out 80ms;
|
|
41
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
5
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) Infonomic Company Limited
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* RouteProgressBar — global navigation progress indicator for the admin shell.
|
|
13
|
+
*
|
|
14
|
+
* Driven by TanStack Router's reactive state via `useRouterState`. The bar
|
|
15
|
+
* appears across the top of the viewport whenever a route transition or
|
|
16
|
+
* loader is in flight.
|
|
17
|
+
*
|
|
18
|
+
* Timing:
|
|
19
|
+
* - SHOW_DELAY_MS — debounce before the bar appears. Sub-debounce
|
|
20
|
+
* navigations (typical instant client-side transitions)
|
|
21
|
+
* never show the bar at all.
|
|
22
|
+
* - MIN_VISIBLE_MS — once shown, the bar remains visible for at least this
|
|
23
|
+
* long before the completion animation, so it never
|
|
24
|
+
* flickers as a single-frame artefact.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { useEffect, useRef, useState } from 'react'
|
|
28
|
+
import { useRouterState } from '@tanstack/react-router'
|
|
29
|
+
|
|
30
|
+
import cx from 'classnames'
|
|
31
|
+
|
|
32
|
+
import styles from './route-progress-bar.module.css'
|
|
33
|
+
|
|
34
|
+
const SHOW_DELAY_MS = 80
|
|
35
|
+
const MIN_VISIBLE_MS = 250
|
|
36
|
+
const FINISH_EXIT_MS = 350
|
|
37
|
+
|
|
38
|
+
type Phase = 'idle' | 'visible' | 'finishing'
|
|
39
|
+
|
|
40
|
+
export function RouteProgressBar() {
|
|
41
|
+
const isNavigating = useRouterState({
|
|
42
|
+
select: (s) => s.isLoading || s.isTransitioning,
|
|
43
|
+
})
|
|
44
|
+
const [phase, setPhase] = useState<Phase>('idle')
|
|
45
|
+
const showTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
46
|
+
const finishTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
47
|
+
const resetTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
48
|
+
const visibleSinceRef = useRef<number | null>(null)
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const clearShow = () => {
|
|
52
|
+
if (showTimerRef.current) {
|
|
53
|
+
clearTimeout(showTimerRef.current)
|
|
54
|
+
showTimerRef.current = null
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const clearFinish = () => {
|
|
58
|
+
if (finishTimerRef.current) {
|
|
59
|
+
clearTimeout(finishTimerRef.current)
|
|
60
|
+
finishTimerRef.current = null
|
|
61
|
+
}
|
|
62
|
+
if (resetTimerRef.current) {
|
|
63
|
+
clearTimeout(resetTimerRef.current)
|
|
64
|
+
resetTimerRef.current = null
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (isNavigating) {
|
|
69
|
+
// A new navigation started — abort any pending exit animation.
|
|
70
|
+
clearFinish()
|
|
71
|
+
|
|
72
|
+
if (phase === 'finishing') {
|
|
73
|
+
// Re-grab the bar mid-fade.
|
|
74
|
+
visibleSinceRef.current = performance.now()
|
|
75
|
+
setPhase('visible')
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
if (phase === 'idle' && showTimerRef.current === null) {
|
|
79
|
+
showTimerRef.current = setTimeout(() => {
|
|
80
|
+
showTimerRef.current = null
|
|
81
|
+
visibleSinceRef.current = performance.now()
|
|
82
|
+
setPhase('visible')
|
|
83
|
+
}, SHOW_DELAY_MS)
|
|
84
|
+
}
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Navigation finished.
|
|
89
|
+
if (showTimerRef.current !== null) {
|
|
90
|
+
// Still inside the debounce window — bar never appeared. No-op.
|
|
91
|
+
clearShow()
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
if (phase === 'visible') {
|
|
95
|
+
const elapsed = performance.now() - (visibleSinceRef.current ?? 0)
|
|
96
|
+
const wait = Math.max(0, MIN_VISIBLE_MS - elapsed)
|
|
97
|
+
finishTimerRef.current = setTimeout(() => {
|
|
98
|
+
finishTimerRef.current = null
|
|
99
|
+
setPhase('finishing')
|
|
100
|
+
resetTimerRef.current = setTimeout(() => {
|
|
101
|
+
resetTimerRef.current = null
|
|
102
|
+
visibleSinceRef.current = null
|
|
103
|
+
setPhase('idle')
|
|
104
|
+
}, FINISH_EXIT_MS)
|
|
105
|
+
}, wait)
|
|
106
|
+
}
|
|
107
|
+
}, [isNavigating, phase])
|
|
108
|
+
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
return () => {
|
|
111
|
+
if (showTimerRef.current) clearTimeout(showTimerRef.current)
|
|
112
|
+
if (finishTimerRef.current) clearTimeout(finishTimerRef.current)
|
|
113
|
+
if (resetTimerRef.current) clearTimeout(resetTimerRef.current)
|
|
114
|
+
}
|
|
115
|
+
}, [])
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<div
|
|
119
|
+
aria-hidden="true"
|
|
120
|
+
className={cx('byline-route-progress-bar', styles.bar, {
|
|
121
|
+
[styles.barVisible]: phase === 'visible',
|
|
122
|
+
'byline-route-progress-bar-visible': phase === 'visible',
|
|
123
|
+
[styles.barFinishing]: phase === 'finishing',
|
|
124
|
+
'byline-route-progress-bar-finishing': phase === 'finishing',
|
|
125
|
+
})}
|
|
126
|
+
/>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
@@ -31,6 +31,7 @@ import { DrawerToggle } from '../admin-shell/chrome/drawer-toggle.js'
|
|
|
31
31
|
import { AdminMenuDrawer } from '../admin-shell/chrome/menu-drawer.js'
|
|
32
32
|
import { AdminMenuProvider } from '../admin-shell/chrome/menu-provider.js'
|
|
33
33
|
import { RouteError, RouteNotFound } from '../admin-shell/chrome/route-error.js'
|
|
34
|
+
import { RouteProgressBar } from '../admin-shell/chrome/route-progress-bar.js'
|
|
34
35
|
import { bylineAdminServices } from '../integrations/byline-admin-services.js'
|
|
35
36
|
import { BylineAiAdminProvider } from '../integrations/byline-ai.js'
|
|
36
37
|
import { bylineFieldServices } from '../integrations/byline-field-services.js'
|
|
@@ -70,6 +71,7 @@ export function createAdminLayoutRoute(path: string, opts: AdminLayoutOpts = {})
|
|
|
70
71
|
<BylineFieldServicesProvider services={bylineFieldServices}>
|
|
71
72
|
<BylineAiAdminProvider>
|
|
72
73
|
<AdminMenuProvider>
|
|
74
|
+
<RouteProgressBar />
|
|
73
75
|
<AdminAppBar user={user} />
|
|
74
76
|
<main className={cx('byline-admin-layout-main', layoutStyles.main)}>
|
|
75
77
|
<DrawerToggle />
|