@hachej/boring-core 0.1.52 → 0.1.54
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.
|
@@ -267,3 +267,24 @@
|
|
|
267
267
|
font-weight: 600;
|
|
268
268
|
color: color-mix(in oklch, var(--foreground) 88%, transparent);
|
|
269
269
|
}
|
|
270
|
+
|
|
271
|
+
/* Optional marketing/nav links rendered beside the brand in the public top bar
|
|
272
|
+
(ChatFirstPublicShellOptions.navLinks). The authed workspace is unaffected. */
|
|
273
|
+
.public-topbar-nav {
|
|
274
|
+
display: flex;
|
|
275
|
+
align-items: center;
|
|
276
|
+
gap: 1rem;
|
|
277
|
+
margin-left: 0.75rem;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.public-topbar-nav a {
|
|
281
|
+
font-size: 0.8125rem;
|
|
282
|
+
font-weight: 500;
|
|
283
|
+
text-decoration: none;
|
|
284
|
+
color: color-mix(in oklch, var(--foreground) 65%, transparent);
|
|
285
|
+
transition: color 0.15s ease;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.public-topbar-nav a:hover {
|
|
289
|
+
color: var(--foreground);
|
|
290
|
+
}
|
|
@@ -33,6 +33,15 @@ interface ChatFirstPublicShellOptions {
|
|
|
33
33
|
* otherwise the fixed-position arrows overlay the open panel. Defaults to on.
|
|
34
34
|
*/
|
|
35
35
|
showTeachingArrows?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Marketing/navigation links rendered in the public (no-auth) top bar next to
|
|
38
|
+
* the brand — e.g. About, Pricing, Docs. The authenticated workspace top bar
|
|
39
|
+
* is unaffected. Use plain hrefs (router or full-page routes both work).
|
|
40
|
+
*/
|
|
41
|
+
navLinks?: Array<{
|
|
42
|
+
label: string;
|
|
43
|
+
href: string;
|
|
44
|
+
}>;
|
|
36
45
|
}
|
|
37
46
|
|
|
38
47
|
type ChatEntryMode = 'auth-first' | 'chat-first';
|
|
@@ -57,7 +66,7 @@ interface CoreWorkspaceAgentFrontProps<TSession extends WorkspaceAgentSession =
|
|
|
57
66
|
/** Default top-bar right content. Exported so apps can compose extra widgets
|
|
58
67
|
* (e.g. a credit balance badge) alongside the user menu. */
|
|
59
68
|
declare function DefaultTopBarRight(): react_jsx_runtime.JSX.Element;
|
|
60
|
-
declare function CoreWorkspaceAgentFront<TSession extends WorkspaceAgentSession = WorkspaceAgentSession>({ authPages, cspNonce, children, workspaceRoute, workspaceIdParam, workspaceHref, loadingFallback, bootPreloadPaths, topBarLeft, topBarRight, appTitle, bridgeEndpoint, hotReload, chatEntryMode, chatFirstPublicShell, chatFirstPublicWorkspaceProps, publicPaths, ...workspaceProps }: CoreWorkspaceAgentFrontProps<TSession>): react_jsx_runtime.JSX.Element;
|
|
69
|
+
declare function CoreWorkspaceAgentFront<TSession extends WorkspaceAgentSession = WorkspaceAgentSession>({ authPages, cspNonce, children, workspaceRoute, workspaceIdParam, workspaceHref, loadingFallback, bootPreloadPaths, topBarLeft, topBarRight, appTitle, bridgeEndpoint, fullPageBasePath, hotReload, chatEntryMode, chatFirstPublicShell, chatFirstPublicWorkspaceProps, publicPaths, ...workspaceProps }: CoreWorkspaceAgentFrontProps<TSession>): react_jsx_runtime.JSX.Element;
|
|
61
70
|
|
|
62
71
|
interface CreditBalanceBadgeProps {
|
|
63
72
|
/** Base URL for the credits API (default: same origin). */
|
package/dist/app/front/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
useSignIn,
|
|
10
10
|
useSignUp,
|
|
11
11
|
useWorkspaceRouteStatus
|
|
12
|
-
} from "../../chunk-
|
|
12
|
+
} from "../../chunk-Q53N4QUK.js";
|
|
13
13
|
import "../../chunk-HYNKZSTF.js";
|
|
14
14
|
import {
|
|
15
15
|
isRuntimeEmailVerificationEnabled
|
|
@@ -20,8 +20,13 @@ import "../../chunk-MLKGABMK.js";
|
|
|
20
20
|
// src/app/front/CoreWorkspaceAgentFront.tsx
|
|
21
21
|
import { useEffect as useEffect3, useMemo, useState as useState3 } from "react";
|
|
22
22
|
import { Navigate, Route, useLocation as useLocation2, useParams } from "react-router-dom";
|
|
23
|
+
import { WorkspaceProvider } from "@hachej/boring-workspace";
|
|
24
|
+
import { ErrorState } from "@hachej/boring-ui-kit";
|
|
23
25
|
import {
|
|
24
|
-
|
|
26
|
+
parseFullPagePanelLocation,
|
|
27
|
+
WorkspaceAgentFront as WorkspaceAgentFront2,
|
|
28
|
+
WorkspaceBootGate,
|
|
29
|
+
WorkspaceFullPagePanel
|
|
25
30
|
} from "@hachej/boring-workspace/app/front";
|
|
26
31
|
|
|
27
32
|
// src/app/front/chatFirst/ChatFirstAuthenticatedShell.tsx
|
|
@@ -420,7 +425,8 @@ function ChatFirstPublicShell({
|
|
|
420
425
|
children: (appTitle?.[0] ?? "B").toUpperCase()
|
|
421
426
|
}
|
|
422
427
|
),
|
|
423
|
-
/* @__PURE__ */ jsx4("span", { className: "truncate text-[13px] font-medium leading-none tracking-tight text-foreground", children: appTitle })
|
|
428
|
+
/* @__PURE__ */ jsx4("span", { className: "truncate text-[13px] font-medium leading-none tracking-tight text-foreground", children: appTitle }),
|
|
429
|
+
publicShell?.navLinks?.length ? /* @__PURE__ */ jsx4("nav", { className: "public-topbar-nav", "aria-label": "Site", children: publicShell.navLinks.map((link) => /* @__PURE__ */ jsx4("a", { href: link.href, children: link.label }, link.href)) }) : null
|
|
424
430
|
] }),
|
|
425
431
|
className: workspaceProps.className,
|
|
426
432
|
surfaceButtonBottomOffset: 456,
|
|
@@ -503,6 +509,7 @@ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-run
|
|
|
503
509
|
installVitePreloadRecovery();
|
|
504
510
|
var DEFAULT_WORKSPACE_ROUTE = "/workspace/:id";
|
|
505
511
|
var DEFAULT_WORKSPACE_ID_PARAM = "id";
|
|
512
|
+
var DEFAULT_FULL_PAGE_BASE_PATH = "/full-page";
|
|
506
513
|
function DefaultTopBarRight() {
|
|
507
514
|
return /* @__PURE__ */ jsx5(UserMenu, {});
|
|
508
515
|
}
|
|
@@ -689,6 +696,10 @@ function WorkspaceRoute({
|
|
|
689
696
|
() => ({ ...resolvedWorkspaceProps.authHeaders, "x-boring-workspace-id": workspaceId }),
|
|
690
697
|
[workspaceId, resolvedWorkspaceProps.authHeaders]
|
|
691
698
|
);
|
|
699
|
+
const scopedFullPageBasePath = useMemo(
|
|
700
|
+
() => resolvedWorkspaceProps.fullPageBasePath ? withWorkspaceIdSearch(resolvedWorkspaceProps.fullPageBasePath, workspaceId) : void 0,
|
|
701
|
+
[resolvedWorkspaceProps.fullPageBasePath, workspaceId]
|
|
702
|
+
);
|
|
692
703
|
if (!workspaceId) return /* @__PURE__ */ jsx5(Fragment3, { children: resolvedLoadingFallback });
|
|
693
704
|
if (!session.data?.user && chatEntryMode === "chat-first") {
|
|
694
705
|
return /* @__PURE__ */ jsx5(
|
|
@@ -736,6 +747,7 @@ function WorkspaceRoute({
|
|
|
736
747
|
workspaceLabel: resolvedWorkspaceProps.workspaceLabel ?? currentWorkspace.name,
|
|
737
748
|
requestHeaders,
|
|
738
749
|
authHeaders,
|
|
750
|
+
fullPageBasePath: scopedFullPageBasePath,
|
|
739
751
|
chatParams,
|
|
740
752
|
bootPreloadPaths,
|
|
741
753
|
frontPluginHotReload: false,
|
|
@@ -745,6 +757,110 @@ function WorkspaceRoute({
|
|
|
745
757
|
workspaceId
|
|
746
758
|
);
|
|
747
759
|
}
|
|
760
|
+
function fullPageRoutePath(basePath) {
|
|
761
|
+
const path = basePath.split(/[?#]/, 1)[0]?.trim();
|
|
762
|
+
return path || DEFAULT_FULL_PAGE_BASE_PATH;
|
|
763
|
+
}
|
|
764
|
+
function workspaceIdFromFullPageSearch(search) {
|
|
765
|
+
const workspaceId = new URLSearchParams(search).get("workspaceId")?.trim();
|
|
766
|
+
return workspaceId || null;
|
|
767
|
+
}
|
|
768
|
+
function withWorkspaceIdSearch(basePath, workspaceId) {
|
|
769
|
+
const [pathWithSearch, hash = ""] = basePath.split("#", 2);
|
|
770
|
+
const [path, rawSearch = ""] = pathWithSearch.split("?", 2);
|
|
771
|
+
const search = new URLSearchParams(rawSearch);
|
|
772
|
+
search.set("workspaceId", workspaceId);
|
|
773
|
+
return `${path}?${search.toString()}${hash ? `#${hash}` : ""}`;
|
|
774
|
+
}
|
|
775
|
+
function scopedWorkspaceHeaders(workspaceId, headers) {
|
|
776
|
+
return { ...headers ?? {}, "x-boring-workspace-id": workspaceId };
|
|
777
|
+
}
|
|
778
|
+
function FullPageRouteErrorPage({ code, title, description }) {
|
|
779
|
+
return /* @__PURE__ */ jsx5(
|
|
780
|
+
"div",
|
|
781
|
+
{
|
|
782
|
+
className: "flex min-h-screen items-center justify-center bg-background p-6 text-foreground",
|
|
783
|
+
"data-testid": "full-page-error-state",
|
|
784
|
+
"data-full-page-error-code": code,
|
|
785
|
+
children: /* @__PURE__ */ jsx5(ErrorState, { className: "w-full max-w-lg", title, description })
|
|
786
|
+
}
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
function CoreFullPagePanelRoute({
|
|
790
|
+
fullPageBasePath,
|
|
791
|
+
loadingFallback,
|
|
792
|
+
bootPreloadPaths,
|
|
793
|
+
workspaceProps,
|
|
794
|
+
appTitle
|
|
795
|
+
}) {
|
|
796
|
+
const location = useLocation2();
|
|
797
|
+
const parsed = useMemo(() => parseFullPagePanelLocation(location.search), [location.search]);
|
|
798
|
+
const currentWorkspace = useCurrentWorkspace();
|
|
799
|
+
const workspaceId = workspaceIdFromFullPageSearch(location.search) ?? currentWorkspace?.id ?? "";
|
|
800
|
+
const scopedFullPageBasePath = workspaceId ? withWorkspaceIdSearch(fullPageBasePath, workspaceId) : fullPageBasePath;
|
|
801
|
+
const requestHeaders = workspaceId ? scopedWorkspaceHeaders(workspaceId, workspaceProps.requestHeaders) : workspaceProps.requestHeaders;
|
|
802
|
+
const authHeaders = workspaceId ? scopedWorkspaceHeaders(workspaceId, { ...workspaceProps.requestHeaders ?? {}, ...workspaceProps.authHeaders ?? {} }) : { ...workspaceProps.requestHeaders ?? {}, ...workspaceProps.authHeaders ?? {} };
|
|
803
|
+
if (parsed.error || !parsed.componentId) {
|
|
804
|
+
return /* @__PURE__ */ jsx5(
|
|
805
|
+
FullPageRouteErrorPage,
|
|
806
|
+
{
|
|
807
|
+
code: parsed.error?.code ?? "FULL_PAGE_PANEL_MISSING_COMPONENT",
|
|
808
|
+
title: "Invalid full-page panel route",
|
|
809
|
+
description: parsed.error?.message ?? "Missing full-page panel component id."
|
|
810
|
+
}
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
if (!workspaceId) {
|
|
814
|
+
return /* @__PURE__ */ jsx5(Fragment3, { children: loadingFallback ?? /* @__PURE__ */ jsx5(
|
|
815
|
+
FullPageRouteErrorPage,
|
|
816
|
+
{
|
|
817
|
+
code: "FULL_PAGE_PANEL_MISSING_WORKSPACE",
|
|
818
|
+
title: "Workspace unavailable",
|
|
819
|
+
description: "The full-page panel route needs a workspace id. Open it from a workspace or include workspaceId in the URL."
|
|
820
|
+
}
|
|
821
|
+
) });
|
|
822
|
+
}
|
|
823
|
+
return /* @__PURE__ */ jsx5(
|
|
824
|
+
WorkspaceProvider,
|
|
825
|
+
{
|
|
826
|
+
chatPanel: workspaceProps.chatPanel,
|
|
827
|
+
plugins: workspaceProps.plugins,
|
|
828
|
+
excludeDefaults: workspaceProps.excludeDefaults,
|
|
829
|
+
panels: workspaceProps.panels,
|
|
830
|
+
commands: workspaceProps.commands,
|
|
831
|
+
catalogs: workspaceProps.catalogs,
|
|
832
|
+
capabilities: workspaceProps.capabilities,
|
|
833
|
+
apiBaseUrl: workspaceProps.apiBaseUrl,
|
|
834
|
+
authHeaders,
|
|
835
|
+
apiTimeout: workspaceProps.apiTimeout,
|
|
836
|
+
defaultTheme: workspaceProps.defaultTheme,
|
|
837
|
+
onThemeChange: workspaceProps.onThemeChange,
|
|
838
|
+
workspaceId,
|
|
839
|
+
workspaceLabel: currentWorkspace?.id === workspaceId ? currentWorkspace.name : workspaceProps.workspaceLabel,
|
|
840
|
+
appTitle,
|
|
841
|
+
storageKey: workspaceProps.providerStorageKey ?? `boring-ui-v2:layout:${workspaceId}`,
|
|
842
|
+
persistenceEnabled: workspaceProps.persistenceEnabled,
|
|
843
|
+
manageDocumentTitle: false,
|
|
844
|
+
bridgeEndpoint: null,
|
|
845
|
+
onAuthError: workspaceProps.onAuthError,
|
|
846
|
+
onOpenFile: workspaceProps.onOpenFile,
|
|
847
|
+
debug: workspaceProps.debug,
|
|
848
|
+
frontPluginHotReload: false,
|
|
849
|
+
fullPageBasePath: scopedFullPageBasePath,
|
|
850
|
+
children: /* @__PURE__ */ jsx5(
|
|
851
|
+
WorkspaceBootGate,
|
|
852
|
+
{
|
|
853
|
+
workspaceId,
|
|
854
|
+
requestHeaders,
|
|
855
|
+
apiBaseUrl: workspaceProps.apiBaseUrl,
|
|
856
|
+
preloadPaths: bootPreloadPaths,
|
|
857
|
+
provisionWorkspace: workspaceProps.provisionWorkspace,
|
|
858
|
+
children: /* @__PURE__ */ jsx5(WorkspaceFullPagePanel, { componentId: parsed.componentId, params: parsed.params })
|
|
859
|
+
}
|
|
860
|
+
)
|
|
861
|
+
}
|
|
862
|
+
);
|
|
863
|
+
}
|
|
748
864
|
function chatFirstPublicPaths(workspaceRoute) {
|
|
749
865
|
return Array.from(/* @__PURE__ */ new Set(["/", workspaceRoute, "/workspace/:id", "/w/:id"]));
|
|
750
866
|
}
|
|
@@ -761,6 +877,7 @@ function CoreWorkspaceAgentFront({
|
|
|
761
877
|
topBarRight = /* @__PURE__ */ jsx5(DefaultTopBarRight, {}),
|
|
762
878
|
appTitle,
|
|
763
879
|
bridgeEndpoint = "/api/v1/ui",
|
|
880
|
+
fullPageBasePath = DEFAULT_FULL_PAGE_BASE_PATH,
|
|
764
881
|
hotReload = false,
|
|
765
882
|
chatEntryMode = "auth-first",
|
|
766
883
|
chatFirstPublicShell,
|
|
@@ -775,7 +892,8 @@ function CoreWorkspaceAgentFront({
|
|
|
775
892
|
}
|
|
776
893
|
const routedWorkspaceProps = {
|
|
777
894
|
...workspaceProps,
|
|
778
|
-
bridgeEndpoint
|
|
895
|
+
bridgeEndpoint,
|
|
896
|
+
fullPageBasePath
|
|
779
897
|
};
|
|
780
898
|
return /* @__PURE__ */ jsxs4(
|
|
781
899
|
CoreFront,
|
|
@@ -828,6 +946,22 @@ function CoreWorkspaceAgentFront({
|
|
|
828
946
|
)
|
|
829
947
|
}
|
|
830
948
|
),
|
|
949
|
+
/* @__PURE__ */ jsx5(
|
|
950
|
+
Route,
|
|
951
|
+
{
|
|
952
|
+
path: fullPageRoutePath(fullPageBasePath),
|
|
953
|
+
element: /* @__PURE__ */ jsx5(
|
|
954
|
+
CoreFullPagePanelRoute,
|
|
955
|
+
{
|
|
956
|
+
fullPageBasePath,
|
|
957
|
+
loadingFallback,
|
|
958
|
+
bootPreloadPaths,
|
|
959
|
+
workspaceProps: routedWorkspaceProps,
|
|
960
|
+
appTitle
|
|
961
|
+
}
|
|
962
|
+
)
|
|
963
|
+
}
|
|
964
|
+
),
|
|
831
965
|
children
|
|
832
966
|
]
|
|
833
967
|
}
|
|
@@ -1463,15 +1463,25 @@ function SettingsTopBar() {
|
|
|
1463
1463
|
className: "relative flex h-[52px] items-center justify-between gap-3 border-b border-border/40 bg-background px-4",
|
|
1464
1464
|
"aria-label": "App top bar",
|
|
1465
1465
|
children: /* @__PURE__ */ jsxs6("div", { className: "flex min-w-0 flex-1 items-center gap-2.5", children: [
|
|
1466
|
-
/* @__PURE__ */
|
|
1467
|
-
"
|
|
1466
|
+
/* @__PURE__ */ jsxs6(
|
|
1467
|
+
"a",
|
|
1468
1468
|
{
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1469
|
+
href: "/",
|
|
1470
|
+
"aria-label": `${appTitle} home`,
|
|
1471
|
+
className: "flex min-w-0 items-center gap-2.5 rounded-md outline-none transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-ring",
|
|
1472
|
+
children: [
|
|
1473
|
+
/* @__PURE__ */ jsx13(
|
|
1474
|
+
"div",
|
|
1475
|
+
{
|
|
1476
|
+
"aria-hidden": "true",
|
|
1477
|
+
className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-foreground text-[12px] font-semibold text-background",
|
|
1478
|
+
children: appInitial
|
|
1479
|
+
}
|
|
1480
|
+
),
|
|
1481
|
+
/* @__PURE__ */ jsx13("span", { className: "truncate text-[13px] font-medium tracking-tight text-foreground", children: appTitle })
|
|
1482
|
+
]
|
|
1472
1483
|
}
|
|
1473
1484
|
),
|
|
1474
|
-
/* @__PURE__ */ jsx13("span", { className: "truncate text-[13px] font-medium tracking-tight text-foreground", children: appTitle }),
|
|
1475
1485
|
/* @__PURE__ */ jsx13("span", { "aria-hidden": "true", className: "text-muted-foreground/30", children: "/" }),
|
|
1476
1486
|
/* @__PURE__ */ jsx13("span", { className: "truncate text-[13px] text-muted-foreground", children: "Account settings" })
|
|
1477
1487
|
] })
|
package/dist/front/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hachej/boring-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.54",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Foundation package for boring-ui-v2 apps: DB, auth, config, HTTP app factory, and frontend app shell.",
|
|
@@ -79,9 +79,9 @@
|
|
|
79
79
|
"react-router-dom": "^7.14.2",
|
|
80
80
|
"smol-toml": "^1.6.1",
|
|
81
81
|
"zod": "^3.25.76",
|
|
82
|
-
"@hachej/boring-
|
|
83
|
-
"@hachej/boring-workspace": "0.1.
|
|
84
|
-
"@hachej/boring-
|
|
82
|
+
"@hachej/boring-ui-kit": "0.1.54",
|
|
83
|
+
"@hachej/boring-workspace": "0.1.54",
|
|
84
|
+
"@hachej/boring-agent": "0.1.54"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@testing-library/jest-dom": "^6.9.1",
|