@ramme-io/ui 4.0.1 → 4.1.1
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/README.md +159 -7
- package/dist/blocks/ai/Actions.js +2 -2
- package/dist/blocks/ai/PromptInput.js +6 -6
- package/dist/component-registry.js +389 -359
- package/dist/components/ai/AIChatThread/AIChatThread.js +81 -73
- package/dist/components/ai/ArchitectureReferenceCard/ArchitectureReferenceCard.d.ts +28 -0
- package/dist/components/ai/ArchitectureReferenceCard/ArchitectureReferenceCard.js +70 -0
- package/dist/components/ai/ArchitectureReferenceCard/index.d.ts +2 -0
- package/dist/components/ai/CounterpartyGraphCard/CounterpartyGraphCard.d.ts +30 -0
- package/dist/components/ai/CounterpartyGraphCard/CounterpartyGraphCard.js +82 -0
- package/dist/components/ai/CounterpartyGraphCard/index.d.ts +2 -0
- package/dist/components/ai/DivergenceMetricsCard/DivergenceMetricsCard.d.ts +29 -0
- package/dist/components/ai/DivergenceMetricsCard/DivergenceMetricsCard.js +69 -0
- package/dist/components/ai/DivergenceMetricsCard/index.d.ts +2 -0
- package/dist/components/ai/KeyInjectionOverlay.d.ts +10 -0
- package/dist/components/ai/KeyInjectionOverlay.js +11 -11
- package/dist/components/ai/NewsSummaryCard/NewsSummaryCard.js +17 -17
- package/dist/components/ai/StockChart/StockChart.js +4 -4
- package/dist/components/auth/AuthLayout.js +4 -4
- package/dist/components/auth/LoginPage.d.ts +22 -0
- package/dist/components/auth/LoginPage.js +50 -42
- package/dist/components/data-display/CodeBlock.d.ts +33 -7
- package/dist/components/data-display/CodeBlock.js +134 -41
- package/dist/components/data-display/Table.js +8 -8
- package/dist/components/feedback/EmptyState.js +9 -9
- package/dist/components/feedback/ToastProvider.js +4 -4
- package/dist/components/forms/Checkbox.js +5 -5
- package/dist/components/forms/ComboBox.js +2 -2
- package/dist/components/forms/DatePicker.js +37 -32
- package/dist/components/forms/FileUpload.js +39 -37
- package/dist/components/forms/Input.js +19 -18
- package/dist/components/forms/MultiSelect.js +9 -8
- package/dist/components/forms/Radio.js +6 -6
- package/dist/components/forms/SegmentedControl.d.ts +1 -1
- package/dist/components/forms/SegmentedControl.js +28 -11
- package/dist/components/forms/Select.js +9 -8
- package/dist/components/forms/Textarea.d.ts +13 -11
- package/dist/components/forms/Textarea.js +36 -16
- package/dist/components/forms/ToggleSwitch.js +9 -9
- package/dist/components/layout/AboutRamme.d.ts +8 -0
- package/dist/components/layout/Accordion.js +25 -32
- package/dist/components/layout/AppShell.js +7 -7
- package/dist/components/layout/Card.js +38 -21
- package/dist/components/layout/DetailDrawer.js +37 -38
- package/dist/components/layout/Drawer.js +50 -51
- package/dist/components/layout/List.js +9 -9
- package/dist/components/layout/Modal.js +5 -5
- package/dist/components/layout/PageHeader.js +7 -7
- package/dist/components/layout/SectionHeader.js +4 -4
- package/dist/components/layout/SettingsContainer.d.ts +12 -0
- package/dist/components/layout/SettingsContainer.js +30 -18
- package/dist/components/layout/Sheet.d.ts +58 -0
- package/dist/components/layout/Sheet.js +144 -0
- package/dist/components/layout/Sidebar.js +1 -1
- package/dist/components/layout/UserNav.d.ts +13 -0
- package/dist/components/layout/UserNav.js +17 -17
- package/dist/components/molecular/ConnectorOverlay.d.ts +12 -0
- package/dist/components/navigation/Breadcrumbs.js +8 -8
- package/dist/components/navigation/Menu.js +6 -6
- package/dist/components/navigation/MobileNav.d.ts +44 -1
- package/dist/components/navigation/MobileNav.js +97 -71
- package/dist/components/navigation/Pagination.js +46 -41
- package/dist/components/navigation/Stepper.js +17 -17
- package/dist/components/navigation/Tabs.js +18 -11
- package/dist/components/theme/ThemeLab.d.ts +7 -1
- package/dist/components/theme/ThemeLab.js +175 -154
- package/dist/components/ui/icon-loader.d.ts +1 -1
- package/dist/contexts/ThemeContext.js +111 -82
- package/dist/data/mockData.d.ts +0 -3
- package/dist/index.css +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +222 -197
- package/dist/lib/hooks/useBodyScrollLock.d.ts +27 -0
- package/dist/lib/hooks/useBodyScrollLock.js +18 -0
- package/dist/lib/hooks/useSheetGesture.d.ts +81 -0
- package/dist/lib/hooks/useSheetGesture.js +70 -0
- package/dist/lib/theme/themeUtils.d.ts +21 -0
- package/dist/lib/theme/themeUtils.js +31 -17
- package/dist/setupTests.d.ts +1 -0
- package/dist/wizardManifest.js +364 -19
- package/package.json +10 -4
- package/src/wizardManifest.ts +364 -19
- package/tailwind.preset.js +98 -10
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { jsx as e, jsxs as
|
|
1
|
+
import { jsx as e, jsxs as t } from "react/jsx-runtime";
|
|
2
2
|
import { useState as n } from "react";
|
|
3
3
|
import { Button as m } from "../ui/Button.js";
|
|
4
4
|
import { Input as c } from "../forms/Input.js";
|
|
5
5
|
import { Card as u } from "../layout/Card.js";
|
|
6
6
|
import { Icon as f } from "../ui/Icon.js";
|
|
7
|
-
function I({ status: i, setSessionKey:
|
|
8
|
-
const [s,
|
|
9
|
-
return i !== "BYOK_REQUIRED" && i !== "KEY_EXPIRED" ? null : /* @__PURE__ */ e("div", { className: "fixed inset-0 z-
|
|
10
|
-
|
|
7
|
+
function I({ status: i, setSessionKey: a }) {
|
|
8
|
+
const [s, o] = n(""), [l, d] = n(!0);
|
|
9
|
+
return i !== "BYOK_REQUIRED" && i !== "KEY_EXPIRED" ? null : /* @__PURE__ */ e("div", { className: "fixed inset-0 z-drawer flex items-center justify-center bg-background/80 backdrop-blur-sm", children: /* @__PURE__ */ e(u, { className: "w-[450px] p-6 shadow-xl border-destructive/20 border", children: /* @__PURE__ */ t("form", { onSubmit: (r) => {
|
|
10
|
+
r.preventDefault(), s.trim() && a(s.trim());
|
|
11
11
|
}, className: "space-y-4", children: [
|
|
12
|
-
/* @__PURE__ */
|
|
13
|
-
/* @__PURE__ */
|
|
12
|
+
/* @__PURE__ */ t("div", { className: "space-y-2", children: [
|
|
13
|
+
/* @__PURE__ */ t("div", { className: "flex items-center gap-2 text-destructive", children: [
|
|
14
14
|
/* @__PURE__ */ e(f, { name: "alert-triangle", size: 20 }),
|
|
15
15
|
/* @__PURE__ */ e("h3", { className: "font-semibold text-lg", children: "AI Key Required" })
|
|
16
16
|
] }),
|
|
17
17
|
/* @__PURE__ */ e("p", { className: "text-sm text-muted-foreground", children: i === "KEY_EXPIRED" ? "Your AI API key has expired or is invalid. Please provide a new key." : "This terminal requires an AI API key to function. We do not bundle keys in the client for security." })
|
|
18
18
|
] }),
|
|
19
|
-
/* @__PURE__ */
|
|
19
|
+
/* @__PURE__ */ t("div", { className: "space-y-2", children: [
|
|
20
20
|
/* @__PURE__ */ e("label", { className: "text-sm font-medium text-foreground", children: "API Key" }),
|
|
21
21
|
/* @__PURE__ */ e(
|
|
22
22
|
c,
|
|
@@ -24,20 +24,20 @@ function I({ status: i, setSessionKey: o }) {
|
|
|
24
24
|
type: "password",
|
|
25
25
|
placeholder: "Paste your AI provider key here...",
|
|
26
26
|
value: s,
|
|
27
|
-
onChange: (
|
|
27
|
+
onChange: (r) => o(r.target.value),
|
|
28
28
|
className: "font-mono w-full font-medium",
|
|
29
29
|
autoComplete: "off"
|
|
30
30
|
}
|
|
31
31
|
)
|
|
32
32
|
] }),
|
|
33
|
-
/* @__PURE__ */
|
|
33
|
+
/* @__PURE__ */ t("div", { className: "flex items-center gap-2", children: [
|
|
34
34
|
/* @__PURE__ */ e(
|
|
35
35
|
"input",
|
|
36
36
|
{
|
|
37
37
|
type: "checkbox",
|
|
38
38
|
id: "session-only",
|
|
39
39
|
checked: l,
|
|
40
|
-
onChange: (
|
|
40
|
+
onChange: (r) => d(r.target.checked),
|
|
41
41
|
className: "rounded border-input text-primary focus:ring-primary"
|
|
42
42
|
}
|
|
43
43
|
),
|
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
import { jsxs as t, jsx as e } from "react/jsx-runtime";
|
|
2
2
|
import { useState as i, useEffect as g } from "react";
|
|
3
3
|
import { Card as N, CardHeader as b, CardTitle as w, CardContent as y } from "../../layout/Card.js";
|
|
4
|
-
import { Icon as
|
|
4
|
+
import { Icon as s } from "../../ui/Icon.js";
|
|
5
5
|
const d = { BASE_URL: "/", DEV: !1, MODE: "production", PROD: !0, SSR: !1 }, k = ({ params: u }) => {
|
|
6
|
-
const { ticker:
|
|
6
|
+
const { ticker: a } = u, [c, x] = i([]), [l, m] = i(!0), [n, p] = i(null);
|
|
7
7
|
return g(() => {
|
|
8
8
|
(async () => {
|
|
9
9
|
try {
|
|
10
10
|
m(!0), p(null);
|
|
11
|
-
const
|
|
11
|
+
const o = (d == null ? void 0 : d.VITE_API_URL) ?? "http://localhost:8000", f = await fetch(`${o}/companies/${a.toUpperCase()}/news?limit=5`);
|
|
12
12
|
if (!f.ok)
|
|
13
|
-
throw new Error(`No news available for ${
|
|
13
|
+
throw new Error(`No news available for ${a.toUpperCase()}`);
|
|
14
14
|
const h = await f.json();
|
|
15
15
|
x(h);
|
|
16
|
-
} catch (
|
|
17
|
-
p(
|
|
16
|
+
} catch (o) {
|
|
17
|
+
p(o instanceof Error ? o.message : "Failed to fetch news");
|
|
18
18
|
} finally {
|
|
19
19
|
m(!1);
|
|
20
20
|
}
|
|
21
21
|
})();
|
|
22
|
-
}, [
|
|
22
|
+
}, [a]), /* @__PURE__ */ t(N, { className: "w-full min-w-[320px] max-w-2xl shadow-lg border-primary/20", children: [
|
|
23
23
|
/* @__PURE__ */ e(b, { className: "pb-3", children: /* @__PURE__ */ t(w, { className: "text-sm font-medium text-muted-foreground flex items-center gap-2", children: [
|
|
24
|
-
/* @__PURE__ */ e(
|
|
24
|
+
/* @__PURE__ */ e(s, { name: "newspaper", size: 14 }),
|
|
25
25
|
"Recent News · ",
|
|
26
|
-
|
|
26
|
+
a.toUpperCase()
|
|
27
27
|
] }) }),
|
|
28
28
|
/* @__PURE__ */ t(y, { className: "pt-0", children: [
|
|
29
|
-
l && /* @__PURE__ */ e("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ e(
|
|
30
|
-
|
|
31
|
-
/* @__PURE__ */ e(
|
|
32
|
-
/* @__PURE__ */ e("span", { children:
|
|
29
|
+
l && /* @__PURE__ */ e("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ e(s, { name: "loader", size: 24, className: "animate-spin text-muted-foreground" }) }),
|
|
30
|
+
n && /* @__PURE__ */ t("div", { className: "flex items-start gap-2 rounded-lg border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: [
|
|
31
|
+
/* @__PURE__ */ e(s, { name: "alert-circle", size: 14, className: "mt-px shrink-0" }),
|
|
32
|
+
/* @__PURE__ */ e("span", { children: n })
|
|
33
33
|
] }),
|
|
34
|
-
c.length === 0 && !l && !
|
|
35
|
-
/* @__PURE__ */ e(
|
|
34
|
+
c.length === 0 && !l && !n && /* @__PURE__ */ t("div", { className: "flex flex-col items-center justify-center py-8 gap-2 text-muted-foreground", children: [
|
|
35
|
+
/* @__PURE__ */ e(s, { name: "inbox", size: 24, opacity: 0.5 }),
|
|
36
36
|
/* @__PURE__ */ e("p", { className: "text-sm", children: "No recent news available" })
|
|
37
37
|
] }),
|
|
38
|
-
c.length > 0 && !l && !
|
|
38
|
+
c.length > 0 && !l && !n && /* @__PURE__ */ e("div", { className: "space-y-3", children: c.map((r) => /* @__PURE__ */ e(
|
|
39
39
|
"div",
|
|
40
40
|
{
|
|
41
41
|
className: "border-b border-border/50 pb-3 last:border-0 last:pb-0",
|
|
@@ -64,7 +64,7 @@ const d = { BASE_URL: "/", DEV: !1, MODE: "production", PROD: !0, SSR: !1 }, k =
|
|
|
64
64
|
] })
|
|
65
65
|
] })
|
|
66
66
|
] }),
|
|
67
|
-
r.url && /* @__PURE__ */ e(
|
|
67
|
+
r.url && /* @__PURE__ */ e(s, { name: "external-link", size: 12, className: "text-muted-foreground/50 flex-shrink-0 mt-0.5" })
|
|
68
68
|
] })
|
|
69
69
|
},
|
|
70
70
|
r.id
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsxs as a, jsx as e } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
3
|
-
import { ResponsiveContainer as
|
|
2
|
+
import _ from "react";
|
|
3
|
+
import { ResponsiveContainer as F, ComposedChart as W, CartesianGrid as K, XAxis as U, YAxis as A, Tooltip as $, Legend as j, Line as S, Bar as z } from "recharts";
|
|
4
4
|
import { Card as E, CardHeader as H, CardTitle as L, CardContent as V } from "../../layout/Card.js";
|
|
5
5
|
import { useChartTheme as Y } from "../../../lib/hooks/useChartTheme.js";
|
|
6
6
|
function G(s, p, C) {
|
|
@@ -59,7 +59,7 @@ const b = {
|
|
|
59
59
|
data: C
|
|
60
60
|
}) => {
|
|
61
61
|
var y, k;
|
|
62
|
-
const { ticker: N, timeRange: M, metrics: c } = s, { textColor: g, gridColor: l } = Y(), h = N || s.symbol || "UNKNOWN", r = M || "1M", o = c && Array.isArray(c) && c.length > 0 ? c : ["price", "volume"], x =
|
|
62
|
+
const { ticker: N, timeRange: M, metrics: c } = s, { textColor: g, gridColor: l } = Y(), h = N || s.symbol || "UNKNOWN", r = M || "1M", o = c && Array.isArray(c) && c.length > 0 ? c : ["price", "volume"], x = _.useMemo(
|
|
63
63
|
() => {
|
|
64
64
|
const t = C || G(r, o);
|
|
65
65
|
return console.log("[StockChart] Data generated:", {
|
|
@@ -98,7 +98,7 @@ const b = {
|
|
|
98
98
|
] })
|
|
99
99
|
] }) }),
|
|
100
100
|
/* @__PURE__ */ a(V, { className: "pt-0", children: [
|
|
101
|
-
/* @__PURE__ */ e("div", { className: "h-64 w-full bg-background", style: { minHeight: "256px", minWidth: "350px" }, children: /* @__PURE__ */ e(
|
|
101
|
+
/* @__PURE__ */ e("div", { className: "h-64 w-full bg-background", style: { minHeight: "256px", minWidth: "350px" }, children: /* @__PURE__ */ e(F, { width: "100%", height: 256, children: /* @__PURE__ */ a(W, { data: x, margin: { top: 5, right: 20, bottom: 5, left: 0 }, children: [
|
|
102
102
|
/* @__PURE__ */ e(K, { strokeDasharray: "3 3", stroke: l, opacity: 0.3 }),
|
|
103
103
|
/* @__PURE__ */ e(
|
|
104
104
|
U,
|
|
@@ -3,7 +3,7 @@ import { Outlet as c } from "react-router-dom";
|
|
|
3
3
|
import { useTheme as d } from "../../contexts/ThemeContext.js";
|
|
4
4
|
import { Button as t } from "../ui/Button.js";
|
|
5
5
|
const m = () => {
|
|
6
|
-
const { setTheme:
|
|
6
|
+
const { setTheme: a, customTheme: n, setCustomTheme: i } = d(), s = {
|
|
7
7
|
name: "Cyberpunk",
|
|
8
8
|
colors: {
|
|
9
9
|
primary: "255 238 88",
|
|
@@ -26,19 +26,19 @@ const m = () => {
|
|
|
26
26
|
},
|
|
27
27
|
borderRadius: "0px"
|
|
28
28
|
};
|
|
29
|
-
return /* @__PURE__ */ o("div", { className: "absolute top-4 right-4 flex gap-2 z-
|
|
29
|
+
return /* @__PURE__ */ o("div", { className: "absolute top-4 right-4 flex gap-2 z-drawer", children: [
|
|
30
30
|
["light", "dark", "system"].map((r) => /* @__PURE__ */ e(
|
|
31
31
|
t,
|
|
32
32
|
{
|
|
33
33
|
size: "sm",
|
|
34
34
|
variant: "ghost",
|
|
35
|
-
onClick: () =>
|
|
35
|
+
onClick: () => a(r),
|
|
36
36
|
className: "opacity-50 hover:opacity-100 capitalize",
|
|
37
37
|
children: r
|
|
38
38
|
},
|
|
39
39
|
r
|
|
40
40
|
)),
|
|
41
|
-
/* @__PURE__ */ e(t, { size: "sm", variant: "ghost", onClick: () => i(
|
|
41
|
+
/* @__PURE__ */ e(t, { size: "sm", variant: "ghost", onClick: () => i(n ? null : s), className: "opacity-50 hover:opacity-100", children: "AI" })
|
|
42
42
|
] });
|
|
43
43
|
}, g = () => /* @__PURE__ */ o("div", { className: "min-h-dvh w-full flex items-center justify-center bg-background text-foreground relative transition-colors duration-300", children: [
|
|
44
44
|
/* @__PURE__ */ e("div", { className: "absolute inset-0 z-0 opacity-[0.03] pointer-events-none bg-[radial-gradient(#888_1px,transparent_1px)] [background-size:16px_16px]" }),
|
|
@@ -10,6 +10,9 @@ import React from 'react';
|
|
|
10
10
|
* @param {string} error - Message shown above the form when sign-in fails.
|
|
11
11
|
* @param {boolean} loading - Disables the form and shows progress while authenticating.
|
|
12
12
|
* @param {QuickProfile[]} quickProfiles - Optional one-click demo identities, each `{ name, email, role }`.
|
|
13
|
+
* @param {string} signupHref - Where "Create one" points. Pass `null` to hide that line entirely, which is what an invite-only product wants. Defaults to `/auth/signup`.
|
|
14
|
+
* @param {string} signupLabel - Text for that link. Defaults to "Create one".
|
|
15
|
+
* @param {string} forgotHref - Where "Forgot?" points. Pass `null` to hide it — a product with no reset email has nothing to link to. Defaults to `#`.
|
|
13
16
|
*/
|
|
14
17
|
export interface QuickProfile {
|
|
15
18
|
name: string;
|
|
@@ -21,5 +24,24 @@ export interface LoginPageProps {
|
|
|
21
24
|
error?: string | null;
|
|
22
25
|
loading?: boolean;
|
|
23
26
|
quickProfiles?: QuickProfile[];
|
|
27
|
+
/**
|
|
28
|
+
* Where "Create one" goes, or `null` to hide the line.
|
|
29
|
+
*
|
|
30
|
+
* Defaults to `/auth/signup` so every product that already renders this keeps
|
|
31
|
+
* exactly what it has. Invite-only products pass `null`: ramme.io deleted its
|
|
32
|
+
* signup route when accounts became invite-only, and this link kept pointing at
|
|
33
|
+
* it — a dead end offered to everyone who could not get in.
|
|
34
|
+
*/
|
|
35
|
+
signupHref?: string | null;
|
|
36
|
+
signupLabel?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Where "Forgot?" goes, or `null` to hide it.
|
|
39
|
+
*
|
|
40
|
+
* Defaults to `#`, which is what it has always been — a link that does nothing.
|
|
41
|
+
* Worth being able to remove: on a product with no reset email, offering a
|
|
42
|
+
* recovery link that goes nowhere is worse than saying so in plain words
|
|
43
|
+
* underneath the form.
|
|
44
|
+
*/
|
|
45
|
+
forgotHref?: string | null;
|
|
24
46
|
}
|
|
25
47
|
export declare const LoginPage: React.FC<LoginPageProps>;
|
|
@@ -1,98 +1,106 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { useState as
|
|
3
|
-
import { Link as
|
|
4
|
-
import { Button as
|
|
5
|
-
import { Input as
|
|
6
|
-
import { Alert as
|
|
1
|
+
import { jsxs as a, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { useState as h } from "react";
|
|
3
|
+
import { Link as x } from "react-router-dom";
|
|
4
|
+
import { Button as v } from "../ui/Button.js";
|
|
5
|
+
import { Input as f } from "../forms/Input.js";
|
|
6
|
+
import { Alert as y } from "../feedback/Alert.js";
|
|
7
7
|
import { Icon as s } from "../ui/Icon.js";
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
const A = ({
|
|
9
|
+
onLogin: g,
|
|
10
|
+
error: l,
|
|
11
|
+
loading: i,
|
|
12
|
+
quickProfiles: r,
|
|
13
|
+
signupHref: n = "/auth/signup",
|
|
14
|
+
signupLabel: b = "Create one",
|
|
15
|
+
forgotHref: o = "#"
|
|
16
|
+
}) => {
|
|
17
|
+
const [c, d] = h(""), [m, u] = h(""), N = (t) => {
|
|
18
|
+
t.preventDefault(), g(c, m);
|
|
19
|
+
}, p = "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 mb-2 block text-foreground/90";
|
|
20
|
+
return /* @__PURE__ */ a("div", { className: "w-full max-w-[400px] space-y-6 animate-in fade-in zoom-in-95 duration-300", children: [
|
|
21
|
+
/* @__PURE__ */ a("div", { className: "flex flex-col items-center space-y-2 text-center mb-8", children: [
|
|
14
22
|
/* @__PURE__ */ e("div", { className: "h-10 w-10 bg-primary/10 rounded-xl flex items-center justify-center mb-2 border border-primary/20", children: /* @__PURE__ */ e(s, { name: "hexagon", className: "text-primary fill-primary/20", size: 24, strokeWidth: 2.5 }) }),
|
|
15
23
|
/* @__PURE__ */ e("h1", { className: "text-2xl font-bold tracking-tight", children: "Welcome back" }),
|
|
16
24
|
/* @__PURE__ */ e("p", { className: "text-sm text-muted-foreground", children: "Enter your credentials to access your workspace" })
|
|
17
25
|
] }),
|
|
18
|
-
/* @__PURE__ */
|
|
19
|
-
/* @__PURE__ */ e("div", { className: "p-6 pt-6", children: /* @__PURE__ */
|
|
20
|
-
l && /* @__PURE__ */ e(
|
|
21
|
-
/* @__PURE__ */
|
|
22
|
-
/* @__PURE__ */ e("label", { htmlFor: "email", className:
|
|
23
|
-
/* @__PURE__ */
|
|
26
|
+
/* @__PURE__ */ a("div", { className: "bg-card text-card-foreground border shadow-sm rounded-xl overflow-hidden", children: [
|
|
27
|
+
/* @__PURE__ */ e("div", { className: "p-6 pt-6", children: /* @__PURE__ */ a("form", { onSubmit: N, className: "space-y-4", children: [
|
|
28
|
+
l && /* @__PURE__ */ e(y, { variant: "danger", title: "Authentication Error", className: "mb-4", children: l }),
|
|
29
|
+
/* @__PURE__ */ a("div", { className: "space-y-1", children: [
|
|
30
|
+
/* @__PURE__ */ e("label", { htmlFor: "email", className: p, children: "Email" }),
|
|
31
|
+
/* @__PURE__ */ a("div", { className: "relative group", children: [
|
|
24
32
|
/* @__PURE__ */ e(s, { name: "mail", className: "absolute left-3 top-2.5 h-4 w-4 text-muted-foreground group-focus-within:text-primary transition-colors" }),
|
|
25
33
|
/* @__PURE__ */ e(
|
|
26
|
-
|
|
34
|
+
f,
|
|
27
35
|
{
|
|
28
36
|
id: "email",
|
|
29
37
|
type: "email",
|
|
30
38
|
placeholder: "name@example.com",
|
|
31
39
|
className: "pl-9 h-10 bg-background/50",
|
|
32
|
-
value:
|
|
33
|
-
onChange: (
|
|
40
|
+
value: c,
|
|
41
|
+
onChange: (t) => d(t.target.value),
|
|
34
42
|
required: !0
|
|
35
43
|
}
|
|
36
44
|
)
|
|
37
45
|
] })
|
|
38
46
|
] }),
|
|
39
|
-
/* @__PURE__ */
|
|
40
|
-
/* @__PURE__ */
|
|
41
|
-
/* @__PURE__ */ e("label", { htmlFor: "password", className:
|
|
42
|
-
/* @__PURE__ */ e(
|
|
47
|
+
/* @__PURE__ */ a("div", { className: "space-y-1", children: [
|
|
48
|
+
/* @__PURE__ */ a("div", { className: "flex items-center justify-between", children: [
|
|
49
|
+
/* @__PURE__ */ e("label", { htmlFor: "password", className: p, children: "Password" }),
|
|
50
|
+
o !== null && /* @__PURE__ */ e(x, { to: o, className: "text-xs text-primary hover:underline font-medium", children: "Forgot?" })
|
|
43
51
|
] }),
|
|
44
|
-
/* @__PURE__ */
|
|
52
|
+
/* @__PURE__ */ a("div", { className: "relative group", children: [
|
|
45
53
|
/* @__PURE__ */ e(s, { name: "lock", className: "absolute left-3 top-2.5 h-4 w-4 text-muted-foreground group-focus-within:text-primary transition-colors" }),
|
|
46
54
|
/* @__PURE__ */ e(
|
|
47
|
-
|
|
55
|
+
f,
|
|
48
56
|
{
|
|
49
57
|
id: "password",
|
|
50
58
|
type: "password",
|
|
51
59
|
className: "pl-9 h-10 bg-background/50",
|
|
52
|
-
value:
|
|
53
|
-
onChange: (
|
|
60
|
+
value: m,
|
|
61
|
+
onChange: (t) => u(t.target.value),
|
|
54
62
|
required: !0
|
|
55
63
|
}
|
|
56
64
|
)
|
|
57
65
|
] })
|
|
58
66
|
] }),
|
|
59
|
-
/* @__PURE__ */ e(
|
|
67
|
+
/* @__PURE__ */ e(v, { type: "submit", className: "w-full mt-2", size: "lg", disabled: i, children: i ? "Authenticating..." : "Sign In" })
|
|
60
68
|
] }) }),
|
|
61
|
-
r && r.length > 0 && /* @__PURE__ */
|
|
62
|
-
/* @__PURE__ */
|
|
69
|
+
r && r.length > 0 && /* @__PURE__ */ a("div", { className: "px-6 pb-6 space-y-3", children: [
|
|
70
|
+
/* @__PURE__ */ a("div", { className: "relative mb-4", children: [
|
|
63
71
|
/* @__PURE__ */ e("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ e("span", { className: "w-full border-t border-border/50" }) }),
|
|
64
72
|
/* @__PURE__ */ e("div", { className: "relative flex justify-center text-xs uppercase", children: /* @__PURE__ */ e("span", { className: "bg-card px-2 text-muted-foreground", children: "Quick Select Profiles" }) })
|
|
65
73
|
] }),
|
|
66
|
-
/* @__PURE__ */ e("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: r.map((
|
|
74
|
+
/* @__PURE__ */ e("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: r.map((t) => /* @__PURE__ */ a(
|
|
67
75
|
"button",
|
|
68
76
|
{
|
|
69
77
|
type: "button",
|
|
70
78
|
onClick: () => {
|
|
71
|
-
|
|
79
|
+
d(t.email), u("demo");
|
|
72
80
|
},
|
|
73
81
|
className: "flex flex-col items-start p-3 text-left border rounded-lg hover:border-primary hover:bg-primary/5 transition-all w-full focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-1 focus:ring-offset-card",
|
|
74
82
|
children: [
|
|
75
|
-
/* @__PURE__ */ e("span", { className: "font-medium text-sm text-foreground", children:
|
|
76
|
-
/* @__PURE__ */ e("span", { className: "text-xs text-muted-foreground", children:
|
|
83
|
+
/* @__PURE__ */ e("span", { className: "font-medium text-sm text-foreground", children: t.name }),
|
|
84
|
+
/* @__PURE__ */ e("span", { className: "text-xs text-muted-foreground", children: t.role })
|
|
77
85
|
]
|
|
78
86
|
},
|
|
79
|
-
|
|
87
|
+
t.email
|
|
80
88
|
)) })
|
|
81
89
|
] }),
|
|
82
|
-
/* @__PURE__ */
|
|
83
|
-
/* @__PURE__ */
|
|
90
|
+
n !== null && /* @__PURE__ */ a("div", { className: "p-6 pt-0 text-center", children: [
|
|
91
|
+
/* @__PURE__ */ a("div", { className: "relative mb-4", children: [
|
|
84
92
|
/* @__PURE__ */ e("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ e("span", { className: "w-full border-t" }) }),
|
|
85
93
|
/* @__PURE__ */ e("div", { className: "relative flex justify-center text-xs uppercase", children: /* @__PURE__ */ e("span", { className: "bg-card px-2 text-muted-foreground", children: "Or continue with" }) })
|
|
86
94
|
] }),
|
|
87
|
-
/* @__PURE__ */
|
|
95
|
+
/* @__PURE__ */ a("p", { className: "text-sm text-muted-foreground", children: [
|
|
88
96
|
"Don't have an account?",
|
|
89
97
|
" ",
|
|
90
|
-
/* @__PURE__ */ e(
|
|
98
|
+
/* @__PURE__ */ e(x, { to: n, className: "font-semibold text-primary hover:underline transition-all", children: b })
|
|
91
99
|
] })
|
|
92
100
|
] })
|
|
93
101
|
] })
|
|
94
102
|
] });
|
|
95
103
|
};
|
|
96
104
|
export {
|
|
97
|
-
|
|
105
|
+
A as LoginPage
|
|
98
106
|
};
|
|
@@ -1,23 +1,49 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
interface CodeBlockProps {
|
|
2
|
+
export interface CodeBlockProps {
|
|
3
|
+
/** The snippet. Leading/trailing blank lines are trimmed. */
|
|
3
4
|
code: string;
|
|
4
|
-
language
|
|
5
|
+
/** Prism language id — `tsx`, `bash`, `css`, `json`, … Defaults to `tsx`. */
|
|
6
|
+
language?: string;
|
|
7
|
+
/** Shown in the header. Prefer a real path (`src/App.tsx`); falls back to the language. */
|
|
8
|
+
filename?: string;
|
|
9
|
+
/** Gutter line numbers. Worth it when prose refers to "line 12". */
|
|
10
|
+
showLineNumbers?: boolean;
|
|
11
|
+
/** 1-based lines to emphasise — the "change this line" case in a tutorial. */
|
|
12
|
+
highlightLines?: number[];
|
|
13
|
+
/** Wrap long lines instead of scrolling. Off by default: wrapping a shell command misrepresents it. */
|
|
14
|
+
wrap?: boolean;
|
|
15
|
+
/** Hide the copy button. Only for snippets that are not meant to be run. */
|
|
16
|
+
hideCopy?: boolean;
|
|
5
17
|
className?: string;
|
|
6
18
|
}
|
|
7
19
|
/**
|
|
8
20
|
* @wizard
|
|
9
21
|
* @name CodeBlock
|
|
10
|
-
* @description
|
|
11
|
-
* @tags ui, data-display, code
|
|
22
|
+
* @description The one way to show code. Syntax-highlighted, theme-aware, with a copy button that works on touch and outside secure contexts. Use for every snippet in docs and tutorials — do not hand-roll a <pre>. Long lines scroll inside the block so the page never scrolls sideways on a phone.
|
|
23
|
+
* @tags ui, data-display, code, docs, tutorial
|
|
12
24
|
* @props
|
|
13
25
|
* - name: code
|
|
14
26
|
* type: string
|
|
15
|
-
* description: The
|
|
27
|
+
* description: The snippet to display. Outer blank lines are trimmed.
|
|
16
28
|
* - name: language
|
|
17
29
|
* type: string
|
|
18
|
-
* description:
|
|
30
|
+
* description: Prism language id — 'tsx', 'bash', 'css', 'json'. Defaults to 'tsx'.
|
|
31
|
+
* - name: filename
|
|
32
|
+
* type: string
|
|
33
|
+
* description: Header label. Prefer a real path like 'src/App.tsx'; falls back to the language.
|
|
34
|
+
* - name: showLineNumbers
|
|
35
|
+
* type: boolean
|
|
36
|
+
* description: Show gutter line numbers. Use when the surrounding prose cites line numbers.
|
|
37
|
+
* - name: highlightLines
|
|
38
|
+
* type: number[]
|
|
39
|
+
* description: 1-based lines to emphasise, for "change this line" steps.
|
|
40
|
+
* - name: wrap
|
|
41
|
+
* type: boolean
|
|
42
|
+
* description: Wrap long lines instead of scrolling them. Off by default.
|
|
43
|
+
* - name: hideCopy
|
|
44
|
+
* type: boolean
|
|
45
|
+
* description: Hide the copy button, for snippets that are not meant to be run.
|
|
19
46
|
* @category ui
|
|
20
47
|
* @id code-block
|
|
21
48
|
*/
|
|
22
49
|
export declare const CodeBlock: React.FC<CodeBlockProps>;
|
|
23
|
-
export {};
|
|
@@ -1,45 +1,138 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import
|
|
3
|
-
import { Prism as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
import { jsxs as f, jsx as n } from "react/jsx-runtime";
|
|
2
|
+
import t from "react";
|
|
3
|
+
import { Prism as x } from "react-syntax-highlighter";
|
|
4
|
+
import { oneDark as k, oneLight as w } from "react-syntax-highlighter/dist/esm/styles/prism";
|
|
5
|
+
import { cn as C } from "../../utils/cn.js";
|
|
6
|
+
import { Icon as S } from "../ui/Icon.js";
|
|
7
|
+
function T() {
|
|
8
|
+
const [r, e] = t.useState(
|
|
9
|
+
() => typeof document < "u" && document.documentElement.classList.contains("dark")
|
|
10
|
+
);
|
|
11
|
+
return t.useEffect(() => {
|
|
12
|
+
const o = document.documentElement, s = () => e(o.classList.contains("dark"));
|
|
13
|
+
s();
|
|
14
|
+
const i = new MutationObserver(s);
|
|
15
|
+
return i.observe(o, { attributes: !0, attributeFilter: ["class"] }), () => i.disconnect();
|
|
16
|
+
}, []), r;
|
|
17
|
+
}
|
|
18
|
+
async function N(r) {
|
|
19
|
+
var o;
|
|
20
|
+
if ((o = navigator.clipboard) != null && o.writeText) {
|
|
21
|
+
await navigator.clipboard.writeText(r);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const e = document.createElement("textarea");
|
|
25
|
+
e.value = r, e.setAttribute("readonly", ""), e.style.position = "fixed", e.style.opacity = "0", document.body.appendChild(e), e.select(), document.execCommand("copy"), document.body.removeChild(e);
|
|
26
|
+
}
|
|
27
|
+
const B = ({
|
|
28
|
+
code: r,
|
|
29
|
+
language: e = "tsx",
|
|
30
|
+
filename: o,
|
|
31
|
+
showLineNumbers: s = !1,
|
|
32
|
+
highlightLines: i,
|
|
33
|
+
wrap: b = !1,
|
|
34
|
+
hideCopy: v = !1,
|
|
35
|
+
className: g
|
|
36
|
+
}) => {
|
|
37
|
+
const y = T(), [a, m] = t.useState(!1), d = t.useRef(), p = t.useMemo(() => r.replace(/^\n+|\s+$/g, ""), [r]), u = o || e;
|
|
38
|
+
t.useEffect(() => () => clearTimeout(d.current), []);
|
|
39
|
+
const h = async () => {
|
|
40
|
+
try {
|
|
41
|
+
await N(p), m(!0), clearTimeout(d.current), d.current = setTimeout(() => m(!1), 2e3);
|
|
42
|
+
} catch (l) {
|
|
43
|
+
console.warn("[CodeBlock] Copy failed", l);
|
|
44
|
+
}
|
|
45
|
+
}, c = t.useMemo(
|
|
46
|
+
() => new Set(i ?? []),
|
|
47
|
+
[i]
|
|
48
|
+
);
|
|
49
|
+
return /* @__PURE__ */ f(
|
|
50
|
+
"div",
|
|
51
|
+
{
|
|
52
|
+
className: C(
|
|
53
|
+
"group relative overflow-hidden rounded-lg border border-border bg-card",
|
|
54
|
+
g
|
|
55
|
+
),
|
|
56
|
+
children: [
|
|
57
|
+
/* @__PURE__ */ f("div", { className: "flex items-center justify-between gap-2 border-b border-border bg-surface-muted pl-4 pr-1.5", children: [
|
|
58
|
+
/* @__PURE__ */ n("span", { className: "truncate py-2 font-mono text-2xs font-medium uppercase tracking-wider text-muted-foreground", children: u }),
|
|
59
|
+
!v && /* @__PURE__ */ n(
|
|
60
|
+
"button",
|
|
61
|
+
{
|
|
62
|
+
type: "button",
|
|
63
|
+
onClick: h,
|
|
64
|
+
className: "inline-flex min-h-11 min-w-11 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-surface-hover hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
65
|
+
"aria-label": a ? "Copied" : `Copy ${u} snippet to clipboard`,
|
|
66
|
+
children: /* @__PURE__ */ n(
|
|
67
|
+
S,
|
|
68
|
+
{
|
|
69
|
+
name: a ? "check" : "copy",
|
|
70
|
+
size: 16,
|
|
71
|
+
className: a ? "text-success" : void 0
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
] }),
|
|
77
|
+
/* @__PURE__ */ n(
|
|
78
|
+
"div",
|
|
79
|
+
{
|
|
80
|
+
className: "overflow-x-auto overscroll-x-contain focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset",
|
|
81
|
+
tabIndex: 0,
|
|
82
|
+
role: "region",
|
|
83
|
+
"aria-label": `${u} code`,
|
|
84
|
+
children: /* @__PURE__ */ n(
|
|
85
|
+
x,
|
|
86
|
+
{
|
|
87
|
+
language: e,
|
|
88
|
+
style: y ? k : w,
|
|
89
|
+
showLineNumbers: s,
|
|
90
|
+
wrapLines: c.size > 0,
|
|
91
|
+
lineProps: c.size > 0 ? (l) => ({
|
|
92
|
+
style: {
|
|
93
|
+
display: "block",
|
|
94
|
+
// Semantic tokens, so the emphasis survives all five themes.
|
|
95
|
+
backgroundColor: c.has(l) ? "rgb(var(--app-primary-color) / 0.12)" : void 0,
|
|
96
|
+
boxShadow: c.has(l) ? "inset 2px 0 0 0 rgb(var(--app-primary-color))" : void 0
|
|
97
|
+
}
|
|
98
|
+
}) : void 0,
|
|
99
|
+
lineNumberStyle: {
|
|
100
|
+
minWidth: "2.5em",
|
|
101
|
+
paddingRight: "1em",
|
|
102
|
+
color: "rgb(var(--app-fg-muted) / 0.6)",
|
|
103
|
+
userSelect: "none"
|
|
104
|
+
},
|
|
105
|
+
customStyle: {
|
|
106
|
+
margin: 0,
|
|
107
|
+
padding: "1rem 1.25rem",
|
|
108
|
+
background: "transparent",
|
|
109
|
+
// Sizes come from the fluid scale, never a hardcoded rem — the three
|
|
110
|
+
// implementations this replaces used 0.875rem, 0.85rem and text-sm.
|
|
111
|
+
fontSize: "var(--app-step--1)",
|
|
112
|
+
lineHeight: "var(--app-leading-relaxed)",
|
|
113
|
+
tabSize: 2,
|
|
114
|
+
...b ? { whiteSpace: "pre-wrap", wordBreak: "break-word" } : {}
|
|
115
|
+
},
|
|
116
|
+
codeTagProps: {
|
|
117
|
+
style: {
|
|
118
|
+
// The single place the code typeface is decided. Swapping the
|
|
119
|
+
// token in index.css re-fonts every snippet in every product.
|
|
120
|
+
fontFamily: "var(--app-font-mono)",
|
|
121
|
+
// Ligatures off: a tutorial shows the characters you must type,
|
|
122
|
+
// and a font that draws `=>` as one arrow misleads a beginner.
|
|
123
|
+
fontVariantLigatures: "none"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
children: p
|
|
127
|
+
}
|
|
128
|
+
)
|
|
36
129
|
}
|
|
37
|
-
|
|
38
|
-
children:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
130
|
+
),
|
|
131
|
+
/* @__PURE__ */ n("span", { "aria-live": "polite", className: "sr-only", children: a ? "Copied to clipboard" : "" })
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
);
|
|
42
135
|
};
|
|
43
136
|
export {
|
|
44
|
-
|
|
137
|
+
B as CodeBlock
|
|
45
138
|
};
|