@protobase/ui 0.51.3 → 0.52.0
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/app/app.js +6 -16
- package/dist/auth/auth-layout.d.ts +4 -2
- package/dist/auth/auth-layout.js +7 -3
- package/dist/auth/sign-in-prompt.js +4 -4
- package/dist/connect/connect-page.js +38 -35
- package/dist/connect/connect-route.js +37 -0
- package/dist/notifications/bell/messages.js +0 -2
- package/dist/notifications/bell/notification-item.js +2 -10
- package/dist/notifications/bell/notification-target.js +1 -1
- package/dist/package.js +1 -1
- package/dist/shell/assets/{app-BiL2dM7x.js → app-hedApKlw.js} +7 -7
- package/dist/shell/assets/{index-DnaLvHu6.js → index-CsmVfUWw.js} +2 -2
- package/dist/shell/assets/index-CymocR26.css +2 -0
- package/dist/shell/assets/{records-map-CvVnB3Ev.js → records-map-4KZSI0_U.js} +2 -2
- package/dist/shell/assets/{shared-protobase-ui-CTj1OZ6i.js → shared-protobase-ui-DPmt7o30.js} +2 -2
- package/dist/shell/index.html +4 -4
- package/dist/shell/protobase.shell.json +1 -1
- package/dist/shell/protobase.sw.js +2 -2
- package/dist/shell-source-maps/assets/app-hedApKlw.js.map +1 -0
- package/dist/shell-source-maps/assets/{index-DnaLvHu6.js.map → index-CsmVfUWw.js.map} +1 -1
- package/dist/shell-source-maps/assets/{records-map-CvVnB3Ev.js.map → records-map-4KZSI0_U.js.map} +1 -1
- package/dist/shell-source-maps/assets/{shared-protobase-ui-CTj1OZ6i.js.map → shared-protobase-ui-DPmt7o30.js.map} +1 -1
- package/package.json +4 -4
- package/dist/shell/assets/index-DETGvbIP.css +0 -2
- package/dist/shell-source-maps/assets/app-BiL2dM7x.js.map +0 -1
package/dist/app/app.js
CHANGED
|
@@ -18,10 +18,10 @@ import { CustomBoundary } from "./pages/custom-boundary.js";
|
|
|
18
18
|
import { useSidebarNoticeShown } from "../app-shell/sidebar-notice.js";
|
|
19
19
|
import { AppShell } from "../app-shell/app-shell.js";
|
|
20
20
|
import { useSignInAddress } from "../auth/use-sign-in-address.js";
|
|
21
|
-
import { SignInPrompt } from "../auth/sign-in-prompt.js";
|
|
22
21
|
import { managesOrganization, organizationMenuItems, organizationPageTitle } from "../organizations/organization-paths.js";
|
|
23
22
|
import { AccountPage, useAccountPage } from "../account/account-page.js";
|
|
24
|
-
import {
|
|
23
|
+
import { documentTitle, titleParts, useDocumentTitle } from "./document-title.js";
|
|
24
|
+
import { ConnectRoute } from "../connect/connect-route.js";
|
|
25
25
|
import { SignInPolicyPage } from "../account/sign-in-policy-page.js";
|
|
26
26
|
import { PluginSourceProvider } from "../plugins/plugin-source.js";
|
|
27
27
|
import { AuthGate } from "../auth/auth-gate.js";
|
|
@@ -29,7 +29,6 @@ import { isAdmin, userToShell } from "../auth/user-to-shell.js";
|
|
|
29
29
|
import { AuthLocale } from "../auth/auth-locale.js";
|
|
30
30
|
import { useLiveUpdates } from "../data/use-live-updates.js";
|
|
31
31
|
import { useOpenedRecord } from "../data/use-record.js";
|
|
32
|
-
import { documentTitle, titleParts, useDocumentTitle } from "./document-title.js";
|
|
33
32
|
import { PublicFormPage } from "../forms/public-form-page.js";
|
|
34
33
|
import { useFormAddress } from "../forms/use-form-address.js";
|
|
35
34
|
import { ThemeProvider, useTheme } from "../theme/theme-provider.js";
|
|
@@ -73,10 +72,6 @@ const placeOf = (address) => {
|
|
|
73
72
|
return address?.resource;
|
|
74
73
|
};
|
|
75
74
|
const recordOf = (address) => address?.kind === "record" ? address : void 0;
|
|
76
|
-
const connectPrompt = {
|
|
77
|
-
title: "Sign in to connect an app",
|
|
78
|
-
description: "An app asks to act as you here. Sign in, then choose whether to allow it."
|
|
79
|
-
};
|
|
80
75
|
const Routes = ({ workspace, sidebarMode, assistant, runtime }) => {
|
|
81
76
|
const meta = useAdminMeta();
|
|
82
77
|
const { state, session, signOut, stopStaffSession, organizations: organizationSettings } = useAuth();
|
|
@@ -151,7 +146,7 @@ const Routes = ({ workspace, sidebarMode, assistant, runtime }) => {
|
|
|
151
146
|
const account = useAccountPage();
|
|
152
147
|
const accountAddress = user ? readAccountPath(path) : void 0;
|
|
153
148
|
const accountTab = accountAddress && account ? shownPageTab(pageTabs(account.tree), accountAddress.tab) : void 0;
|
|
154
|
-
const accountPage =
|
|
149
|
+
const accountPage = !user ? void 0 : accountAddress ? account?.title ?? text("account") : path === "/-/sign-in-policy" ? text("signInPolicy") : organizationPage;
|
|
155
150
|
const resourceLabel = view?.names?.plural ?? (resource && humanize(resource));
|
|
156
151
|
const breadcrumb = accountPage ? [accountPage] : breadcrumbFor({
|
|
157
152
|
basePath,
|
|
@@ -180,13 +175,7 @@ const Routes = ({ workspace, sidebarMode, assistant, runtime }) => {
|
|
|
180
175
|
recordTitle: title,
|
|
181
176
|
recordLoading: titleLoading
|
|
182
177
|
}), meta.appName));
|
|
183
|
-
const content = path ===
|
|
184
|
-
email: user.email,
|
|
185
|
-
appName: meta.appName ?? "this app"
|
|
186
|
-
}) : /* @__PURE__ */ jsx(SignInPrompt, {
|
|
187
|
-
as: "page",
|
|
188
|
-
prompt: connectPrompt
|
|
189
|
-
}) : accountAddress ? /* @__PURE__ */ jsx(AccountPage, { ...accountAddress }) : user && path === "/-/sign-in-policy" ? admin ? /* @__PURE__ */ jsx(SignInPolicyPage, {}) : /* @__PURE__ */ jsx(Notice, {
|
|
178
|
+
const content = accountAddress ? /* @__PURE__ */ jsx(AccountPage, { ...accountAddress }) : user && path === "/-/sign-in-policy" ? admin ? /* @__PURE__ */ jsx(SignInPolicyPage, {}) : /* @__PURE__ */ jsx(Notice, {
|
|
190
179
|
title: text("adminsOnly"),
|
|
191
180
|
children: text("onlyAdminPolicy")
|
|
192
181
|
}) : organizationPage && path === "/-/organization" ? /* @__PURE__ */ jsx(OrganizationPage, {
|
|
@@ -294,13 +283,14 @@ const Routes = ({ workspace, sidebarMode, assistant, runtime }) => {
|
|
|
294
283
|
const Authenticated = ({ baseUrl, client, sources, workspace, sidebarMode, ui, assistant, runtime }) => {
|
|
295
284
|
const { state, session, markSignedOut } = useAuth();
|
|
296
285
|
const sidebarBanner = useSidebarNoticeShown(sidebarMode ?? "text-small");
|
|
286
|
+
const { path } = useRouter();
|
|
297
287
|
return /* @__PURE__ */ jsx(ApiProvider, {
|
|
298
288
|
baseUrl,
|
|
299
289
|
client,
|
|
300
290
|
sources,
|
|
301
291
|
token: state.kind === "visitor" ? void 0 : session.token,
|
|
302
292
|
onUnauthenticated: markSignedOut,
|
|
303
|
-
children: /* @__PURE__ */ jsx(MetaGate, { children: /* @__PURE__ */ jsxs(ToastProvider, { children: [!sidebarBanner && /* @__PURE__ */ jsx(NewVersionToast, {}), /* @__PURE__ */ jsx(PluginGate, {
|
|
293
|
+
children: /* @__PURE__ */ jsx(MetaGate, { children: /* @__PURE__ */ jsxs(ToastProvider, { children: [!sidebarBanner && /* @__PURE__ */ jsx(NewVersionToast, {}), path === connectRoute ? /* @__PURE__ */ jsx(ConnectRoute, {}) : /* @__PURE__ */ jsx(PluginGate, {
|
|
304
294
|
ui,
|
|
305
295
|
children: /* @__PURE__ */ jsx(Routes, {
|
|
306
296
|
workspace,
|
|
@@ -5,11 +5,13 @@ export type AuthLayoutProps = {
|
|
|
5
5
|
description?: string;
|
|
6
6
|
/** How wide the card is: `sm`, the default, for a few short inputs; `md` for a form with longer ones. */
|
|
7
7
|
size?: 'sm' | 'md';
|
|
8
|
+
/** The path of the app's own icon, shown in place of Protobase's mark. */
|
|
9
|
+
icon?: string;
|
|
8
10
|
children: ReactNode;
|
|
9
11
|
};
|
|
10
12
|
/**
|
|
11
|
-
* The frame of the sign-in and first-run pages and of public forms: logo, title and a card. On a page as short as a
|
|
13
|
+
* The frame of the sign-in and first-run pages and of public forms: logo, or the app's own icon, title and a card. On a page as short as a
|
|
12
14
|
* phone's above its keyboard the logo and most of the margins go, so the card still shows whole above the keyboard.
|
|
13
15
|
*/
|
|
14
|
-
export declare const AuthLayout: ({ title, description, size, children }: AuthLayoutProps) => import("react").JSX.Element;
|
|
16
|
+
export declare const AuthLayout: ({ title, description, size, icon, children }: AuthLayoutProps) => import("react").JSX.Element;
|
|
15
17
|
//#endregion
|
package/dist/auth/auth-layout.js
CHANGED
|
@@ -3,17 +3,21 @@ import { LogoMark } from "../app-shell/logo.js";
|
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
//#region src/auth/auth-layout.tsx
|
|
5
5
|
/**
|
|
6
|
-
* The frame of the sign-in and first-run pages and of public forms: logo, title and a card. On a page as short as a
|
|
6
|
+
* The frame of the sign-in and first-run pages and of public forms: logo, or the app's own icon, title and a card. On a page as short as a
|
|
7
7
|
* phone's above its keyboard the logo and most of the margins go, so the card still shows whole above the keyboard.
|
|
8
8
|
*/
|
|
9
|
-
const AuthLayout = ({ title, description, size = "sm", children }) => /* @__PURE__ */ jsx("div", {
|
|
9
|
+
const AuthLayout = ({ title, description, size = "sm", icon, children }) => /* @__PURE__ */ jsx("div", {
|
|
10
10
|
className: "flex min-h-full w-full items-center justify-center bg-surface px-4 pb-[calc(2.5rem+var(--pb-safe-bottom))] pt-[calc(2.5rem+var(--pb-safe-top))] short:pb-[calc(1rem+var(--pb-safe-bottom))] short:pt-[calc(1rem+var(--pb-safe-top))]",
|
|
11
11
|
children: /* @__PURE__ */ jsxs("div", {
|
|
12
12
|
className: cn("w-full", size === "sm" ? "max-w-sm" : "max-w-lg"),
|
|
13
13
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
14
14
|
className: "mb-6 flex flex-col items-center text-center short:mb-4",
|
|
15
15
|
children: [
|
|
16
|
-
/* @__PURE__ */ jsx(
|
|
16
|
+
icon ? /* @__PURE__ */ jsx("img", {
|
|
17
|
+
src: icon,
|
|
18
|
+
alt: "",
|
|
19
|
+
className: "size-10 object-contain short:hidden"
|
|
20
|
+
}) : /* @__PURE__ */ jsx(LogoMark, { className: "size-10 short:hidden" }),
|
|
17
21
|
/* @__PURE__ */ jsx("h1", {
|
|
18
22
|
className: "mt-4 text-xl font-semibold tracking-tight short:mt-0",
|
|
19
23
|
children: title
|
|
@@ -19,7 +19,7 @@ const Benefits = ({ benefits }) => benefits && benefits.length > 0 ? /* @__PURE_
|
|
|
19
19
|
}), benefit]
|
|
20
20
|
}, benefit))
|
|
21
21
|
}) : null;
|
|
22
|
-
const
|
|
22
|
+
const SignInPromptActions = ({ prompt }) => {
|
|
23
23
|
const { canSignUp } = useAuth();
|
|
24
24
|
const { link } = useSignInAddress();
|
|
25
25
|
const primary = buttonClass({ variant: "primary" });
|
|
@@ -57,7 +57,7 @@ const SignInPrompt = (props) => {
|
|
|
57
57
|
actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
|
|
58
58
|
onClick: props.onClose,
|
|
59
59
|
children: text("notNow")
|
|
60
|
-
}), /* @__PURE__ */ jsx(
|
|
60
|
+
}), /* @__PURE__ */ jsx(SignInPromptActions, { prompt })] }),
|
|
61
61
|
children: /* @__PURE__ */ jsx(Benefits, { benefits: prompt.benefits })
|
|
62
62
|
});
|
|
63
63
|
const Icon = namedIcon(prompt.icon) ?? LogIn;
|
|
@@ -86,10 +86,10 @@ const SignInPrompt = (props) => {
|
|
|
86
86
|
/* @__PURE__ */ jsx(Benefits, { benefits: prompt.benefits }),
|
|
87
87
|
/* @__PURE__ */ jsx("div", {
|
|
88
88
|
className: "mt-2 flex w-full flex-col-reverse gap-2 sm:w-auto sm:flex-row sm:justify-center [&>*]:min-h-11 sm:[&>*]:min-h-0",
|
|
89
|
-
children: /* @__PURE__ */ jsx(
|
|
89
|
+
children: /* @__PURE__ */ jsx(SignInPromptActions, { prompt })
|
|
90
90
|
})
|
|
91
91
|
]
|
|
92
92
|
});
|
|
93
93
|
};
|
|
94
94
|
//#endregion
|
|
95
|
-
export { SignInPrompt };
|
|
95
|
+
export { SignInPrompt, SignInPromptActions };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useAuth } from "../auth/auth-provider.js";
|
|
2
2
|
import { Spinner } from "../primitives/spinner.js";
|
|
3
|
-
import { Notice } from "../app/meta-gate.js";
|
|
4
3
|
import { Button } from "../primitives/button.js";
|
|
5
4
|
import { useRouter } from "../app/router.js";
|
|
6
5
|
import { authMessage } from "../auth/auth-messages.js";
|
|
6
|
+
import { AuthLayout } from "../auth/auth-layout.js";
|
|
7
7
|
import { clientName } from "./client-name.js";
|
|
8
8
|
import { clientPublisher } from "./client-publisher.js";
|
|
9
9
|
import { isFramed, useArmedAfterFocus, useGuardedPress } from "./interaction-guard.js";
|
|
@@ -39,7 +39,15 @@ const TargetText = ({ target }) => target.kind === "site" ? /* @__PURE__ */ jsxs
|
|
|
39
39
|
className: "break-all text-foreground",
|
|
40
40
|
children: target.uri
|
|
41
41
|
})] });
|
|
42
|
-
const
|
|
42
|
+
const Notice = ({ title, icon, children }) => /* @__PURE__ */ jsx(AuthLayout, {
|
|
43
|
+
title,
|
|
44
|
+
icon,
|
|
45
|
+
children: /* @__PURE__ */ jsx("p", {
|
|
46
|
+
className: "text-muted-foreground",
|
|
47
|
+
children
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
const Request = ({ asking, appName, appIcon, email, onAnswer, onSignOut }) => {
|
|
43
51
|
const [busy, setBusy] = useState(false);
|
|
44
52
|
const armed = useArmedAfterFocus(500);
|
|
45
53
|
const answer = (accept) => {
|
|
@@ -50,38 +58,28 @@ const Request = ({ asking, appName, email, onAnswer, onSignOut }) => {
|
|
|
50
58
|
const name = clientName(asking.client.client_name);
|
|
51
59
|
const publisher = clientPublisher(asking.client.client_id);
|
|
52
60
|
const { target } = asking;
|
|
53
|
-
return /* @__PURE__ */ jsx(
|
|
54
|
-
|
|
61
|
+
return /* @__PURE__ */ jsx(AuthLayout, {
|
|
62
|
+
title: `Allow an app to act as you in ${appName}?`,
|
|
63
|
+
icon: appIcon,
|
|
64
|
+
size: "md",
|
|
55
65
|
children: /* @__PURE__ */ jsxs("section", {
|
|
56
66
|
"aria-label": "Allow an app",
|
|
57
|
-
className: "rounded-lg border bg-background p-5",
|
|
58
67
|
children: [
|
|
59
|
-
/* @__PURE__ */ jsxs("
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
title: name,
|
|
75
|
-
children: [
|
|
76
|
-
"“",
|
|
77
|
-
name ?? "no name",
|
|
78
|
-
"”"
|
|
79
|
-
]
|
|
80
|
-
}),
|
|
81
|
-
" ",
|
|
82
|
-
"asks to act as you here."
|
|
83
|
-
]
|
|
84
|
-
}),
|
|
68
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
69
|
+
"An app that calls itself",
|
|
70
|
+
" ",
|
|
71
|
+
/* @__PURE__ */ jsxs("bdi", {
|
|
72
|
+
className: "inline-block max-w-full truncate align-bottom font-medium",
|
|
73
|
+
title: name,
|
|
74
|
+
children: [
|
|
75
|
+
"“",
|
|
76
|
+
name ?? "no name",
|
|
77
|
+
"”"
|
|
78
|
+
]
|
|
79
|
+
}),
|
|
80
|
+
" ",
|
|
81
|
+
"asks to act as you here."
|
|
82
|
+
] }),
|
|
85
83
|
publisher && /* @__PURE__ */ jsxs("p", {
|
|
86
84
|
className: "mt-1 text-muted-foreground",
|
|
87
85
|
children: [
|
|
@@ -139,7 +137,7 @@ const Request = ({ asking, appName, email, onAnswer, onSignOut }) => {
|
|
|
139
137
|
})
|
|
140
138
|
});
|
|
141
139
|
};
|
|
142
|
-
const Connecting = ({ oauthQuery, appName, email, assign }) => {
|
|
140
|
+
const Connecting = ({ oauthQuery, appName, appIcon, email, assign }) => {
|
|
143
141
|
const { session, signOut } = useAuth();
|
|
144
142
|
const { path, basePath } = useRouter();
|
|
145
143
|
const go = goWith(assign);
|
|
@@ -185,15 +183,17 @@ const Connecting = ({ oauthQuery, appName, email, assign }) => {
|
|
|
185
183
|
};
|
|
186
184
|
if (state.kind === "failed") return /* @__PURE__ */ jsx(Notice, {
|
|
187
185
|
title: "This app cannot be connected",
|
|
186
|
+
icon: appIcon,
|
|
188
187
|
children: state.message
|
|
189
188
|
});
|
|
190
189
|
if (state.kind === "loading") return /* @__PURE__ */ jsxs("div", {
|
|
191
|
-
className: "flex min-h-
|
|
190
|
+
className: "flex min-h-full w-full items-center justify-center gap-2 bg-surface text-muted-foreground",
|
|
192
191
|
children: [/* @__PURE__ */ jsx(Spinner, {}), " Loading"]
|
|
193
192
|
});
|
|
194
193
|
return /* @__PURE__ */ jsx(Request, {
|
|
195
194
|
asking: state.asking,
|
|
196
195
|
appName,
|
|
196
|
+
appIcon,
|
|
197
197
|
email,
|
|
198
198
|
onAnswer: (accept) => answer(accept, state.asking),
|
|
199
199
|
onSignOut: () => void signOut()
|
|
@@ -201,14 +201,15 @@ const Connecting = ({ oauthQuery, appName, email, assign }) => {
|
|
|
201
201
|
};
|
|
202
202
|
/**
|
|
203
203
|
* The connect page: someone signed in allows an outside app, such as an MCP client, to act as them, from the request
|
|
204
|
-
* the server signed and sent here. Inside another page's frame it shows only that it cannot be used there and calls
|
|
204
|
+
* the server signed and sent here. It stands alone on the page, as the sign-in pages do, without the app's shell. Inside another page's frame it shows only that it cannot be used there and calls
|
|
205
205
|
* nothing, whatever headers the host sent; Allow takes a click only once the page has been in front for a moment.
|
|
206
206
|
*/
|
|
207
|
-
const ConnectPage = ({ email, appName, isFramed: isFramed$1 = isFramed, assign = (url) => window.location.assign(url) }) => {
|
|
207
|
+
const ConnectPage = ({ email, appName, appIcon, isFramed: isFramed$1 = isFramed, assign = (url) => window.location.assign(url) }) => {
|
|
208
208
|
const [framed] = useState(isFramed$1);
|
|
209
209
|
const { oauthQuery } = useConnectAddress();
|
|
210
210
|
if (framed) return /* @__PURE__ */ jsxs(Notice, {
|
|
211
211
|
title: "This page cannot be used inside another site",
|
|
212
|
+
icon: appIcon,
|
|
212
213
|
children: [
|
|
213
214
|
/* @__PURE__ */ jsx("a", {
|
|
214
215
|
href: window.location.href,
|
|
@@ -223,11 +224,13 @@ const ConnectPage = ({ email, appName, isFramed: isFramed$1 = isFramed, assign =
|
|
|
223
224
|
});
|
|
224
225
|
if (!oauthQuery) return /* @__PURE__ */ jsx(Notice, {
|
|
225
226
|
title: "Nothing to connect",
|
|
227
|
+
icon: appIcon,
|
|
226
228
|
children: "Connect again from your app."
|
|
227
229
|
});
|
|
228
230
|
return /* @__PURE__ */ jsx(Connecting, {
|
|
229
231
|
oauthQuery,
|
|
230
232
|
appName,
|
|
233
|
+
appIcon,
|
|
231
234
|
email,
|
|
232
235
|
assign
|
|
233
236
|
}, oauthQuery);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useAuth } from "../auth/auth-provider.js";
|
|
2
|
+
import { useAdminMeta } from "../app/meta-gate.js";
|
|
3
|
+
import { SignInPromptActions } from "../auth/sign-in-prompt.js";
|
|
4
|
+
import { AuthLayout } from "../auth/auth-layout.js";
|
|
5
|
+
import { documentTitle, useDocumentTitle } from "../app/document-title.js";
|
|
6
|
+
import { ConnectPage } from "./connect-page.js";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
//#region src/connect/connect-route.tsx
|
|
9
|
+
const connectPrompt = {
|
|
10
|
+
title: "Sign in to connect an app",
|
|
11
|
+
description: "An app asks to act as you here. Sign in, then choose whether to allow it."
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* `/-/connect`, alone on the page without the app's shell, as the sign-in pages are: the connect page for someone
|
|
15
|
+
* signed in, else the way to sign in first. Both carry the app's name and icon.
|
|
16
|
+
*/
|
|
17
|
+
const ConnectRoute = () => {
|
|
18
|
+
const meta = useAdminMeta();
|
|
19
|
+
const { state } = useAuth();
|
|
20
|
+
useDocumentTitle(documentTitle(["Connect an app"], meta.appName));
|
|
21
|
+
if (state.kind === "signed-in") return /* @__PURE__ */ jsx(ConnectPage, {
|
|
22
|
+
email: state.user.email,
|
|
23
|
+
appName: meta.appName ?? "this app",
|
|
24
|
+
appIcon: meta.appIcon
|
|
25
|
+
});
|
|
26
|
+
return /* @__PURE__ */ jsx(AuthLayout, {
|
|
27
|
+
title: connectPrompt.title,
|
|
28
|
+
description: connectPrompt.description,
|
|
29
|
+
icon: meta.appIcon,
|
|
30
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
31
|
+
className: "flex flex-col gap-2 [&>*]:min-h-10 [&>*]:w-full",
|
|
32
|
+
children: /* @__PURE__ */ jsx(SignInPromptActions, { prompt: connectPrompt })
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
37
|
+
export { ConnectRoute };
|
|
@@ -11,7 +11,6 @@ const text = defineMessages({
|
|
|
11
11
|
loadFailed: "Your notifications could not be loaded.",
|
|
12
12
|
tryAgain: "Try again",
|
|
13
13
|
unread: "Unread",
|
|
14
|
-
opensNewTab: "(opens in a new tab)",
|
|
15
14
|
pushOff: "Get notifications on this device, even when the app is closed.",
|
|
16
15
|
turnOn: "Turn on",
|
|
17
16
|
pushOn: "Notifications are on for this device.",
|
|
@@ -28,7 +27,6 @@ const text = defineMessages({
|
|
|
28
27
|
loadFailed: "Je meldingen konden niet worden geladen.",
|
|
29
28
|
tryAgain: "Opnieuw proberen",
|
|
30
29
|
unread: "Ongelezen",
|
|
31
|
-
opensNewTab: "(opent in een nieuw tabblad)",
|
|
32
30
|
pushOff: "Ontvang meldingen op dit apparaat, ook als de app gesloten is.",
|
|
33
31
|
turnOn: "Inschakelen",
|
|
34
32
|
pushOn: "Meldingen staan op dit apparaat aan.",
|
|
@@ -8,8 +8,8 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
8
8
|
const row = "flex w-full gap-2.5 px-3 py-2.5 text-left";
|
|
9
9
|
/**
|
|
10
10
|
* One notification of the panel: unread ones in bold beside a dot, its text, and how long ago it came. A notification
|
|
11
|
-
* with a url is a link to it, followed in the app for the app's own pages and
|
|
12
|
-
*
|
|
11
|
+
* with a url is a link to it, followed in the app for the app's own pages and loaded in this tab for any other; one
|
|
12
|
+
* without is not a link. The history never answers a url on another site.
|
|
13
13
|
*/
|
|
14
14
|
const NotificationItem = ({ item, target, onNavigate, onOpen, now }) => {
|
|
15
15
|
const unread = item.readAt === null;
|
|
@@ -34,10 +34,6 @@ const NotificationItem = ({ item, target, onNavigate, onOpen, now }) => {
|
|
|
34
34
|
dateTime: item.createdAt,
|
|
35
35
|
className: "mt-0.5 block text-xs text-faint-foreground",
|
|
36
36
|
children: formatRelativeTime((now - Date.parse(item.createdAt)) / 1e3)
|
|
37
|
-
}),
|
|
38
|
-
target?.kind === "external" && /* @__PURE__ */ jsx("span", {
|
|
39
|
-
className: "sr-only",
|
|
40
|
-
children: text("opensNewTab")
|
|
41
37
|
})
|
|
42
38
|
]
|
|
43
39
|
})] });
|
|
@@ -64,10 +60,6 @@ const NotificationItem = ({ item, target, onNavigate, onOpen, now }) => {
|
|
|
64
60
|
onClick: opened,
|
|
65
61
|
onAuxClick: middle,
|
|
66
62
|
className: cn(row, "hover:bg-muted"),
|
|
67
|
-
...target.kind === "external" && {
|
|
68
|
-
target: "_blank",
|
|
69
|
-
rel: "noopener"
|
|
70
|
-
},
|
|
71
63
|
children: content
|
|
72
64
|
});
|
|
73
65
|
};
|
|
@@ -5,7 +5,7 @@ const notificationTarget = (url, { origin, basePath }) => {
|
|
|
5
5
|
const target = new URL(url, origin);
|
|
6
6
|
if (target.protocol !== "http:" && target.protocol !== "https:") return void 0;
|
|
7
7
|
if (target.origin !== origin) return {
|
|
8
|
-
kind: "
|
|
8
|
+
kind: "page",
|
|
9
9
|
href: target.href
|
|
10
10
|
};
|
|
11
11
|
const local = `${target.pathname}${target.search}${target.hash}`;
|
package/dist/package.js
CHANGED