@ramme-io/ui 4.1.0 → 4.2.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/README.md +4 -3
- package/dist/component-registry.js +55 -52
- package/dist/components/ai/AIChatThread/AIChatThread.js +3 -3
- package/dist/components/ai/NewsSummaryCard/NewsSummaryCard.js +17 -17
- package/dist/components/ai/StockChart/StockChart.js +35 -35
- package/dist/components/auth/LoginPage.d.ts +22 -0
- package/dist/components/auth/LoginPage.js +50 -42
- package/dist/components/data-display/StatusBadge.d.ts +4 -3
- package/dist/components/data-display/StatusBadge.js +18 -18
- package/dist/components/feedback/Alert.js +19 -19
- 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/SegmentedControl.js +10 -10
- 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/layout/Accordion.js +25 -32
- package/dist/components/layout/Card.js +38 -21
- package/dist/components/layout/DetailDrawer.d.ts +9 -1
- package/dist/components/layout/DetailDrawer.js +60 -51
- package/dist/components/layout/Drawer.js +47 -39
- package/dist/components/layout/Modal.js +28 -23
- package/dist/components/layout/SettingsContainer.js +23 -13
- package/dist/components/layout/Sheet.d.ts +58 -0
- package/dist/components/layout/Sheet.js +146 -0
- package/dist/components/navigation/MobileNav.d.ts +44 -1
- package/dist/components/navigation/MobileNav.js +96 -70
- package/dist/components/navigation/Tabs.js +19 -12
- package/dist/components/ui/icon-loader.d.ts +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +218 -209
- package/dist/lib/hooks/useDialogFocus.d.ts +1 -0
- package/dist/lib/hooks/useDialogFocus.js +46 -0
- package/dist/lib/hooks/useSheetGesture.d.ts +81 -0
- package/dist/lib/hooks/useSheetGesture.js +70 -0
- package/dist/setupTests.d.ts +1 -0
- package/dist/wizardManifest.js +139 -14
- package/package.json +9 -2
- package/src/wizardManifest.ts +139 -14
- package/tailwind.preset.js +8 -0
package/README.md
CHANGED
|
@@ -225,7 +225,7 @@ Props, variants and live examples are in Storybook (`pnpm run storybook`) and at
|
|
|
225
225
|
| `MenuDivider` | `@atom/primitive/menu-divider` | A visual separator for grouping MenuItems within a Menu. |
|
|
226
226
|
| `MenuItem` | `@atom/primitive/menu-item` | An individual selectable item within a Menu component. |
|
|
227
227
|
| `Message` | `@molecule/ai/message` | Displays a single message in a conversation, including an avatar, author, content, and optional suggestions. |
|
|
228
|
-
| `MobileNav` | `@molecule/nav/mobile-nav` |
|
|
228
|
+
| `MobileNav` | `@molecule/nav/mobile-nav` | Mobile navigation, in two shapes. |
|
|
229
229
|
| `MultiSelect` | `@molecule/form/multi-select` | A searchable dropdown for picking several options at once, rendering selections as removable chips. |
|
|
230
230
|
| `NewsSummaryCard` | `@molecule/ai/news-summary-card` | AI-generated news summary card with recent headlines |
|
|
231
231
|
| `PageHeader` | `@atom/templates-patterns/page-header` | Displays the main header section of a page, including a title, optional description, and a slot for action buttons. |
|
|
@@ -253,7 +253,7 @@ Props, variants and live examples are in Storybook (`pnpm run storybook`) and at
|
|
|
253
253
|
| `Tabs` | `@molecule/nav/tabs` | A navigation component that allows users to switch between different content panels within the same area. |
|
|
254
254
|
| `TelemetryGraph` | `@molecule/ai/telemetry-graph` | AI-generated telemetry visualization component |
|
|
255
255
|
| `TelemetryLog` | `@molecule/iot/telemetry-log` | A scrolling, newest-first table of raw sensor readings with a bounded row count. |
|
|
256
|
-
| `Textarea` | `@atom/form/textarea` | A theme-aware
|
|
256
|
+
| `Textarea` | `@atom/form/textarea` | A theme-aware multi-line text input with label, helper text, and validation state support. |
|
|
257
257
|
| `TippyTooltip` | `@molecule/feedback/tippy-tooltip` | A flexible and theme-aware tooltip component that displays additional information on hover. |
|
|
258
258
|
| `Toast` | `@molecule/feedback/toast` | A single, transient notification message that appears briefly to provide feedback. |
|
|
259
259
|
| `ToastProvider` | `@molecule/feedback/toast-provider` | Provides a context for displaying transient notifications (toasts). |
|
|
@@ -262,7 +262,7 @@ Props, variants and live examples are in Storybook (`pnpm run storybook`) and at
|
|
|
262
262
|
| `WatchlistEngine` | `@molecule/block/watchlist-engine` | A self-contained financial watchlist showing tickers with live price, day change, market cap, and a risk grade. |
|
|
263
263
|
| `WaterPumpControl` | `@molecule/iot/water-pump-control` | An irrigation control block: choose automatic or manual operation and set the soil-moisture target the controller should hold. |
|
|
264
264
|
|
|
265
|
-
### Layouts (
|
|
265
|
+
### Layouts (33)
|
|
266
266
|
|
|
267
267
|
| Name | SKU | What it is |
|
|
268
268
|
| --- | --- | --- |
|
|
@@ -294,6 +294,7 @@ Props, variants and live examples are in Storybook (`pnpm run storybook`) and at
|
|
|
294
294
|
| `Modal` | `@chassis/layout/modal` | A centered dialog that blocks interaction with the page until dismissed. |
|
|
295
295
|
| `PageContainer` | `@chassis/layout/page-container` | Standard responsive padding wrapper for the content inside a page. |
|
|
296
296
|
| `SettingsContainer` | `@chassis/layout/settings-container` | The canonical settings page arrangement, with a fixed slot per section so every app's settings read the same way. |
|
|
297
|
+
| `Sheet` | `@chassis/layout/sheet` | A bottom sheet that opens at a partial height and grows to full screen as you drag or scroll it up. |
|
|
297
298
|
| `Sidebar` | `@chassis/layout/sidebar` | A collapsible, theme-aware application navigation rail. |
|
|
298
299
|
| `Statusbar` | `@chassis/layout/statusbar` | The persistent strip pinned to the bottom of the app shell. |
|
|
299
300
|
| `Toolbar` | `@chassis/layout/toolbar` | The secondary action strip that sits beneath the header. |
|
|
@@ -22,8 +22,8 @@ import { AuthLayout as g } from "./components/auth/AuthLayout.js";
|
|
|
22
22
|
import { LoginPage as b } from "./components/auth/LoginPage.js";
|
|
23
23
|
import { SignupPage as C } from "./components/auth/SignupPage.js";
|
|
24
24
|
import { ActivityFeed as y } from "./components/data-display/ActivityFeed.js";
|
|
25
|
-
import { AreaChart as
|
|
26
|
-
import { BarChart as
|
|
25
|
+
import { AreaChart as S } from "./components/data-display/AreaChart.js";
|
|
26
|
+
import { BarChart as v } from "./components/data-display/BarChart.js";
|
|
27
27
|
import { ChartWithTable as T } from "./components/data-display/ChartWithTable.js";
|
|
28
28
|
import { CodeBlock as D } from "./components/data-display/CodeBlock.js";
|
|
29
29
|
import { DataTable as A } from "./components/data-display/DataTable.js";
|
|
@@ -77,25 +77,26 @@ import { PageContainer as dr } from "./components/layout/PageContainer.js";
|
|
|
77
77
|
import { PageHeader as lr } from "./components/layout/PageHeader.js";
|
|
78
78
|
import { SectionHeader as fr } from "./components/layout/SectionHeader.js";
|
|
79
79
|
import { SettingsContainer as sr } from "./components/layout/SettingsContainer.js";
|
|
80
|
-
import {
|
|
81
|
-
import {
|
|
82
|
-
import {
|
|
80
|
+
import { Sheet as zr } from "./components/layout/Sheet.js";
|
|
81
|
+
import { Sidebar as Jr } from "./components/layout/Sidebar.js";
|
|
82
|
+
import { Statusbar as Vr } from "./components/layout/Statusbar.js";
|
|
83
|
+
import { Toolbar as Xr } from "./components/layout/Toolbar.js";
|
|
83
84
|
import { ButtonItem as ur, UserNav as hr } from "./components/layout/UserNav.js";
|
|
84
85
|
import { ConnectorOverlay as gr } from "./components/molecular/ConnectorOverlay.js";
|
|
85
86
|
import { DataCard as br } from "./components/molecular/DataCard.js";
|
|
86
87
|
import { StateMatrix as Cr } from "./components/molecular/StateMatrix.js";
|
|
87
|
-
import { Breadcrumbs as
|
|
88
|
-
import { Menu as
|
|
88
|
+
import { Breadcrumbs as Zr, BreadcrumbItem as yr } from "./components/navigation/Breadcrumbs.js";
|
|
89
|
+
import { Menu as $r, MenuItem as Sr, MenuDivider as vr } from "./components/navigation/Menu.js";
|
|
89
90
|
import { MobileNav as Tr } from "./components/navigation/MobileNav.js";
|
|
90
|
-
import { Pagination as
|
|
91
|
-
import { Stepper as
|
|
92
|
-
import { Tabs as
|
|
93
|
-
import { Avatar as
|
|
94
|
-
import { Badge as
|
|
91
|
+
import { Pagination as rt } from "./components/navigation/Pagination.js";
|
|
92
|
+
import { Stepper as tt } from "./components/navigation/Stepper.js";
|
|
93
|
+
import { Tabs as et, TabPanel as Dr } from "./components/navigation/Tabs.js";
|
|
94
|
+
import { Avatar as ot } from "./components/ui/Avatar.js";
|
|
95
|
+
import { Badge as at } from "./components/ui/Badge.js";
|
|
95
96
|
import { BrandLogo as Ar } from "./components/ui/BrandLogo.js";
|
|
96
|
-
import { Button as
|
|
97
|
-
import { Icon as
|
|
98
|
-
const
|
|
97
|
+
import { Button as it } from "./components/ui/Button.js";
|
|
98
|
+
import { Icon as mt } from "./components/ui/Icon.js";
|
|
99
|
+
const Xe = {
|
|
99
100
|
Suggestion: Pr,
|
|
100
101
|
suggestion: Pr,
|
|
101
102
|
Actions: Br,
|
|
@@ -166,12 +167,12 @@ const Je = {
|
|
|
166
167
|
ActivityFeed: y,
|
|
167
168
|
"activity-feed": y,
|
|
168
169
|
activityfeed: y,
|
|
169
|
-
AreaChart:
|
|
170
|
-
"area-chart":
|
|
171
|
-
areachart:
|
|
172
|
-
BarChart:
|
|
173
|
-
"bar-chart":
|
|
174
|
-
barchart:
|
|
170
|
+
AreaChart: S,
|
|
171
|
+
"area-chart": S,
|
|
172
|
+
areachart: S,
|
|
173
|
+
BarChart: v,
|
|
174
|
+
"bar-chart": v,
|
|
175
|
+
barchart: v,
|
|
175
176
|
ChartWithTable: T,
|
|
176
177
|
"chart-with-table": T,
|
|
177
178
|
chartwithtable: T,
|
|
@@ -346,12 +347,14 @@ const Je = {
|
|
|
346
347
|
SettingsContainer: sr,
|
|
347
348
|
"settings-container": sr,
|
|
348
349
|
settingscontainer: sr,
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
350
|
+
Sheet: zr,
|
|
351
|
+
sheet: zr,
|
|
352
|
+
Sidebar: Jr,
|
|
353
|
+
sidebar: Jr,
|
|
354
|
+
Statusbar: Vr,
|
|
355
|
+
statusbar: Vr,
|
|
356
|
+
Toolbar: Xr,
|
|
357
|
+
toolbar: Xr,
|
|
355
358
|
UserNav: hr,
|
|
356
359
|
"user-nav": hr,
|
|
357
360
|
usernav: hr,
|
|
@@ -370,40 +373,40 @@ const Je = {
|
|
|
370
373
|
BreadcrumbItem: yr,
|
|
371
374
|
"breadcrumb-item": yr,
|
|
372
375
|
breadcrumbitem: yr,
|
|
373
|
-
Breadcrumbs:
|
|
374
|
-
breadcrumbs:
|
|
375
|
-
MenuDivider:
|
|
376
|
-
"menu-divider":
|
|
377
|
-
menudivider:
|
|
378
|
-
MenuItem:
|
|
379
|
-
"menu-item":
|
|
380
|
-
menuitem:
|
|
381
|
-
Menu:
|
|
382
|
-
menu:
|
|
376
|
+
Breadcrumbs: Zr,
|
|
377
|
+
breadcrumbs: Zr,
|
|
378
|
+
MenuDivider: vr,
|
|
379
|
+
"menu-divider": vr,
|
|
380
|
+
menudivider: vr,
|
|
381
|
+
MenuItem: Sr,
|
|
382
|
+
"menu-item": Sr,
|
|
383
|
+
menuitem: Sr,
|
|
384
|
+
Menu: $r,
|
|
385
|
+
menu: $r,
|
|
383
386
|
MobileNav: Tr,
|
|
384
387
|
"mobile-nav": Tr,
|
|
385
388
|
mobilenav: Tr,
|
|
386
|
-
Pagination:
|
|
387
|
-
pagination:
|
|
388
|
-
Stepper:
|
|
389
|
-
stepper:
|
|
389
|
+
Pagination: rt,
|
|
390
|
+
pagination: rt,
|
|
391
|
+
Stepper: tt,
|
|
392
|
+
stepper: tt,
|
|
390
393
|
TabPanel: Dr,
|
|
391
394
|
"tab-panel": Dr,
|
|
392
395
|
tabpanel: Dr,
|
|
393
|
-
Tabs:
|
|
394
|
-
tabs:
|
|
395
|
-
Avatar:
|
|
396
|
-
avatar:
|
|
397
|
-
Badge:
|
|
398
|
-
badge:
|
|
396
|
+
Tabs: et,
|
|
397
|
+
tabs: et,
|
|
398
|
+
Avatar: ot,
|
|
399
|
+
avatar: ot,
|
|
400
|
+
Badge: at,
|
|
401
|
+
badge: at,
|
|
399
402
|
BrandLogo: Ar,
|
|
400
403
|
"brand-logo": Ar,
|
|
401
404
|
brandlogo: Ar,
|
|
402
|
-
Button:
|
|
403
|
-
button:
|
|
404
|
-
Icon:
|
|
405
|
-
icon:
|
|
405
|
+
Button: it,
|
|
406
|
+
button: it,
|
|
407
|
+
Icon: mt,
|
|
408
|
+
icon: mt
|
|
406
409
|
};
|
|
407
410
|
export {
|
|
408
|
-
|
|
411
|
+
Xe as AUTO_REGISTRY
|
|
409
412
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs as c, jsx as t, Fragment as w } from "react/jsx-runtime";
|
|
2
|
-
import { useState as
|
|
2
|
+
import { useState as B, useRef as R, useEffect as D, useCallback as N } from "react";
|
|
3
3
|
import { CodeBlock as G } from "../../data-display/CodeBlock.js";
|
|
4
4
|
import { Icon as C } from "../../ui/Icon.js";
|
|
5
5
|
import { PromptInput as $ } from "../../../blocks/ai/PromptInput.js";
|
|
@@ -91,12 +91,12 @@ const W = () => /* @__PURE__ */ t("div", { className: "flex items-center gap-1 p
|
|
|
91
91
|
activeModel: i,
|
|
92
92
|
connectionStatus: d,
|
|
93
93
|
renderMessage: u,
|
|
94
|
-
placeholder: f = "Ask
|
|
94
|
+
placeholder: f = "Ask AI…",
|
|
95
95
|
className: h,
|
|
96
96
|
suggestions: s,
|
|
97
97
|
onSuggestionClick: k
|
|
98
98
|
}) => {
|
|
99
|
-
const _ = d ?? (a ? "error" : l ? "streaming" : "idle"), [b, y] =
|
|
99
|
+
const _ = d ?? (a ? "error" : l ? "streaming" : "idle"), [b, y] = B(""), v = R(null);
|
|
100
100
|
D(() => {
|
|
101
101
|
var r;
|
|
102
102
|
(r = v.current) == null || r.scrollIntoView({ behavior: "smooth", block: "end" });
|
|
@@ -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,9 +1,9 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import
|
|
3
|
-
import { ResponsiveContainer as
|
|
1
|
+
import { jsxs as s, jsx as e } from "react/jsx-runtime";
|
|
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
|
-
function G(
|
|
6
|
+
function G(a, p, C) {
|
|
7
7
|
const N = Date.now(), M = p && Array.isArray(p) && p.length > 0 ? p : ["price", "volume"], c = {
|
|
8
8
|
"1D": { duration: 6.5 * 60 * 60 * 1e3, points: 78, basePrice: 150 },
|
|
9
9
|
// 5-minute intervals (market hours)
|
|
@@ -13,30 +13,30 @@ function G(s, p, C) {
|
|
|
13
13
|
// Daily close
|
|
14
14
|
"1Y": { duration: 365 * 24 * 60 * 60 * 1e3, points: 52, basePrice: 100 }
|
|
15
15
|
// Weekly close
|
|
16
|
-
}, g = c[
|
|
16
|
+
}, g = c[a] || c["1M"], { duration: l, points: u, basePrice: r } = g, o = l / u, x = [];
|
|
17
17
|
let n = r;
|
|
18
|
-
const
|
|
19
|
-
for (let d = 0; d <
|
|
18
|
+
const h = [];
|
|
19
|
+
for (let d = 0; d < u; d++) {
|
|
20
20
|
const v = N - l + d * o, m = {
|
|
21
21
|
timestamp: new Date(v).toLocaleString("en-US", {
|
|
22
|
-
...
|
|
23
|
-
...
|
|
24
|
-
...
|
|
25
|
-
...
|
|
22
|
+
...a === "1D" && { hour: "2-digit", minute: "2-digit" },
|
|
23
|
+
...a === "1W" && { weekday: "short", hour: "2-digit" },
|
|
24
|
+
...a === "1M" && { month: "short", day: "numeric" },
|
|
25
|
+
...a === "1Y" && { month: "short", year: "2-digit" }
|
|
26
26
|
})
|
|
27
27
|
};
|
|
28
28
|
M.forEach((i) => {
|
|
29
29
|
switch (i) {
|
|
30
30
|
case "price":
|
|
31
|
-
const P = r * 0.02, y = 1e-4 * r,
|
|
32
|
-
n = Math.max(n +
|
|
31
|
+
const P = r * 0.02, y = 1e-4 * r, b = (Math.random() - 0.48) * P + y;
|
|
32
|
+
n = Math.max(n + b, r * 0.7), h.push(n), m[i] = Number(n.toFixed(2));
|
|
33
33
|
break;
|
|
34
34
|
case "volume":
|
|
35
35
|
const t = 1e6, f = Math.random() > 0.7 ? Math.random() * 2 : 1;
|
|
36
36
|
m[i] = Math.round((t + Math.random() * t * 2) * f);
|
|
37
37
|
break;
|
|
38
38
|
case "moving_average":
|
|
39
|
-
const w = Math.min(20, d + 1), D =
|
|
39
|
+
const w = Math.min(20, d + 1), D = h.slice(-w).reduce((I, T) => I + T, 0) / w;
|
|
40
40
|
m[i] = Number(D.toFixed(2));
|
|
41
41
|
break;
|
|
42
42
|
default:
|
|
@@ -46,7 +46,7 @@ function G(s, p, C) {
|
|
|
46
46
|
}
|
|
47
47
|
return x;
|
|
48
48
|
}
|
|
49
|
-
const
|
|
49
|
+
const k = {
|
|
50
50
|
price: { label: "Price", unit: "USD", color: "#10b981" },
|
|
51
51
|
// Emerald/green
|
|
52
52
|
volume: { label: "Volume", unit: "shares", color: "#f59e0b" },
|
|
@@ -54,16 +54,16 @@ const b = {
|
|
|
54
54
|
moving_average: { label: "MA(20)", unit: "", color: "#ef4444" }
|
|
55
55
|
// Red
|
|
56
56
|
}, Q = ({
|
|
57
|
-
params:
|
|
57
|
+
params: a,
|
|
58
58
|
title: p,
|
|
59
59
|
data: C
|
|
60
60
|
}) => {
|
|
61
|
-
var y,
|
|
62
|
-
const { ticker: N, timeRange: M, metrics: c } =
|
|
61
|
+
var y, b;
|
|
62
|
+
const { ticker: N, timeRange: M, metrics: c } = a, { textColor: g, gridColor: l } = Y(), u = N || a.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:", {
|
|
66
|
-
ticker:
|
|
66
|
+
ticker: u,
|
|
67
67
|
timeRange: r,
|
|
68
68
|
metrics: o,
|
|
69
69
|
dataPoints: t.length,
|
|
@@ -71,20 +71,20 @@ const b = {
|
|
|
71
71
|
lastPoint: t[t.length - 1]
|
|
72
72
|
}), t;
|
|
73
73
|
},
|
|
74
|
-
[C, r, o,
|
|
75
|
-
), n = x.filter((t) => t.price !== void 0),
|
|
76
|
-
return /* @__PURE__ */
|
|
77
|
-
/* @__PURE__ */ e(H, { className: "pb-2", children: /* @__PURE__ */
|
|
74
|
+
[C, r, o, u]
|
|
75
|
+
), n = x.filter((t) => t.price !== void 0), h = ((y = n[0]) == null ? void 0 : y.price) || 0, d = ((b = n[n.length - 1]) == null ? void 0 : b.price) || 0, v = d - h, m = h > 0 ? (v / h * 100).toFixed(2) : "0.00", i = v >= 0, P = p || `${u.toUpperCase()} - ${r}`;
|
|
76
|
+
return /* @__PURE__ */ s(E, { className: "w-full max-w-2xl shadow-lg border-primary/20", children: [
|
|
77
|
+
/* @__PURE__ */ e(H, { className: "pb-2", children: /* @__PURE__ */ s("div", { className: "flex items-center justify-between", children: [
|
|
78
78
|
/* @__PURE__ */ e(L, { className: "text-sm font-medium text-foreground/80", children: P }),
|
|
79
|
-
o.includes("price") && /* @__PURE__ */
|
|
80
|
-
/* @__PURE__ */
|
|
79
|
+
o.includes("price") && /* @__PURE__ */ s("div", { className: "flex items-center gap-2", children: [
|
|
80
|
+
/* @__PURE__ */ s("span", { className: "text-base font-semibold", children: [
|
|
81
81
|
"$",
|
|
82
82
|
d.toFixed(2)
|
|
83
83
|
] }),
|
|
84
|
-
/* @__PURE__ */
|
|
84
|
+
/* @__PURE__ */ s(
|
|
85
85
|
"span",
|
|
86
86
|
{
|
|
87
|
-
className: `text-xs font-medium ${i ? "text-
|
|
87
|
+
className: `text-xs font-medium ${i ? "text-success-strong" : "text-destructive-strong"}`,
|
|
88
88
|
children: [
|
|
89
89
|
i ? "+" : "",
|
|
90
90
|
v.toFixed(2),
|
|
@@ -97,8 +97,8 @@ const b = {
|
|
|
97
97
|
)
|
|
98
98
|
] })
|
|
99
99
|
] }) }),
|
|
100
|
-
/* @__PURE__ */
|
|
101
|
-
/* @__PURE__ */ e("div", { className: "h-64 w-full bg-background", style: { minHeight: "256px", minWidth: "350px" }, children: /* @__PURE__ */ e(
|
|
100
|
+
/* @__PURE__ */ s(V, { className: "pt-0", children: [
|
|
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__ */ s(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,
|
|
@@ -136,7 +136,7 @@ const b = {
|
|
|
136
136
|
yAxisId: "price",
|
|
137
137
|
type: "monotone",
|
|
138
138
|
dataKey: "price",
|
|
139
|
-
stroke:
|
|
139
|
+
stroke: k.price.color,
|
|
140
140
|
strokeWidth: 2,
|
|
141
141
|
dot: !1,
|
|
142
142
|
name: "Price (USD)"
|
|
@@ -148,7 +148,7 @@ const b = {
|
|
|
148
148
|
yAxisId: "price",
|
|
149
149
|
type: "monotone",
|
|
150
150
|
dataKey: "moving_average",
|
|
151
|
-
stroke:
|
|
151
|
+
stroke: k.moving_average.color,
|
|
152
152
|
strokeWidth: 2,
|
|
153
153
|
dot: !1,
|
|
154
154
|
name: "MA(20)",
|
|
@@ -160,15 +160,15 @@ const b = {
|
|
|
160
160
|
{
|
|
161
161
|
yAxisId: "volume",
|
|
162
162
|
dataKey: "volume",
|
|
163
|
-
fill:
|
|
163
|
+
fill: k.volume.color,
|
|
164
164
|
opacity: 0.6,
|
|
165
165
|
name: "Volume"
|
|
166
166
|
}
|
|
167
167
|
)
|
|
168
168
|
] }) }) }),
|
|
169
169
|
/* @__PURE__ */ e("div", { className: "mt-3 flex flex-wrap gap-2", children: o.map((t) => {
|
|
170
|
-
const f =
|
|
171
|
-
return /* @__PURE__ */
|
|
170
|
+
const f = k[t];
|
|
171
|
+
return /* @__PURE__ */ s(
|
|
172
172
|
"div",
|
|
173
173
|
{
|
|
174
174
|
className: "inline-flex items-center gap-1.5 rounded-full bg-muted/50 px-2.5 py-1 text-xs",
|
|
@@ -181,7 +181,7 @@ const b = {
|
|
|
181
181
|
}
|
|
182
182
|
),
|
|
183
183
|
/* @__PURE__ */ e("span", { className: "font-medium", children: f.label }),
|
|
184
|
-
f.unit && /* @__PURE__ */
|
|
184
|
+
f.unit && /* @__PURE__ */ s("span", { className: "text-muted-foreground", children: [
|
|
185
185
|
"(",
|
|
186
186
|
f.unit,
|
|
187
187
|
")"
|
|
@@ -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>;
|