reflex-agent 0.2.4 → 0.3.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/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +111 -98
- package/.next/app-path-routes-manifest.json +9 -9
- package/.next/build-manifest.json +5 -5
- package/.next/prerender-manifest.json +4 -54
- package/.next/react-loadable-manifest.json +1 -1
- package/.next/server/app/_not-found/page.js +1 -1
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/agents/[agentId]/page.js +3 -3
- package/.next/server/app/agents/[agentId]/page.js.nft.json +1 -1
- package/.next/server/app/agents/[agentId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/[agentId]/respond/route.js +2 -2
- package/.next/server/app/api/agents/[agentId]/respond/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/[agentId]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/images/[rootId]/[file]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/oauth/callback/route.js +3 -3
- package/.next/server/app/api/oauth/callback/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/oauth/start/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/roots/[id]/attachments/route.js +0 -0
- package/.next/server/app/api/roots/[id]/attachments/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/roots/[id]/chat/[topicId]/send/route.js +2 -2
- package/.next/server/app/api/roots/[id]/chat/[topicId]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/roots/[id]/chat/[topicId]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/roots/[id]/chat/[topicId]/stop/route.js +2 -2
- package/.next/server/app/api/roots/[id]/chat/[topicId]/stop/route.js.nft.json +1 -1
- package/.next/server/app/api/roots/[id]/chat/[topicId]/stop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/roots/[id]/chat/[topicId]/stream/route.js +2 -2
- package/.next/server/app/api/roots/[id]/chat/[topicId]/stream/route.js.nft.json +1 -1
- package/.next/server/app/api/roots/[id]/chat/[topicId]/stream/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/roots/[id]/dashboard/route.js +1 -1
- package/.next/server/app/api/roots/[id]/dashboard/route.js.nft.json +1 -1
- package/.next/server/app/api/roots/[id]/dashboard/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/roots/[id]/suggestions/route.js +1 -1
- package/.next/server/app/api/roots/[id]/suggestions/route.js.nft.json +1 -1
- package/.next/server/app/api/roots/[id]/suggestions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/utilities/[scope]/[id]/bundle.js/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/utilities/[scope]/[id]/host/route.js +2 -2
- package/.next/server/app/api/utilities/[scope]/[id]/host/route.js.nft.json +1 -1
- package/.next/server/app/api/utilities/[scope]/[id]/host/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/utilities/[scope]/[id]/host-api.mjs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/utilities/[scope]/[id]/host-ui.mjs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/utilities/[scope]/[id]/iframe/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/utilities/[scope]/[id]/style.css/route_client-reference-manifest.js +1 -1
- package/.next/server/app/audit/page.js +2 -2
- package/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/server/app/onboarding/page.js +4 -4
- package/.next/server/app/onboarding/page.js.nft.json +1 -1
- package/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page.js +2 -2
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/roots/[id]/chat/[topicId]/page.js +2 -6
- package/.next/server/app/roots/[id]/chat/[topicId]/page.js.nft.json +1 -1
- package/.next/server/app/roots/[id]/chat/[topicId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/roots/[id]/kb/[...slug]/page.js +2 -6
- package/.next/server/app/roots/[id]/kb/[...slug]/page.js.nft.json +1 -1
- package/.next/server/app/roots/[id]/kb/[...slug]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/roots/[id]/page.js +3 -3
- package/.next/server/app/roots/[id]/page.js.nft.json +1 -1
- package/.next/server/app/roots/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/roots/[id]/workflows/[wfId]/page.js +2 -2
- package/.next/server/app/roots/[id]/workflows/[wfId]/page.js.nft.json +1 -1
- package/.next/server/app/roots/[id]/workflows/[wfId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/roots/[id]/workflows/page.js +2 -2
- package/.next/server/app/roots/[id]/workflows/page.js.nft.json +1 -1
- package/.next/server/app/roots/[id]/workflows/page_client-reference-manifest.js +1 -1
- package/.next/server/app/roots/new/page.js +4 -2
- package/.next/server/app/roots/new/page.js.nft.json +1 -1
- package/.next/server/app/roots/new/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/page.js +6 -6
- package/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/share/[id]/file/page.js +2 -2
- package/.next/server/app/share/[id]/file/page.js.nft.json +1 -1
- package/.next/server/app/share/[id]/file/page_client-reference-manifest.js +1 -1
- package/.next/server/app/share/[id]/page.js +2 -2
- package/.next/server/app/share/[id]/page.js.nft.json +1 -1
- package/.next/server/app/share/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/utilities/[scope]/[id]/page.js +2 -2
- package/.next/server/app/utilities/[scope]/[id]/page.js.nft.json +1 -1
- package/.next/server/app/utilities/[scope]/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/utilities/page.js +2 -17
- package/.next/server/app/utilities/page.js.nft.json +1 -1
- package/.next/server/app/utilities/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +9 -9
- package/.next/server/chunks/1223.js +1 -1
- package/.next/server/chunks/133.js +1 -490
- package/.next/server/chunks/1888.js +1 -1
- package/.next/server/chunks/{9739.js → 1988.js} +13 -9
- package/.next/server/chunks/2433.js +1 -1
- package/.next/server/chunks/2503.js +1 -1
- package/.next/server/chunks/285.js +471 -0
- package/.next/server/chunks/2959.js +1 -0
- package/.next/server/chunks/2995.js +1 -0
- package/.next/server/chunks/3240.js +1 -1
- package/.next/server/chunks/3332.js +1 -1
- package/.next/server/chunks/3657.js +1 -1
- package/.next/server/chunks/4066.js +1 -1
- package/.next/server/chunks/4438.js +1 -0
- package/.next/server/chunks/4514.js +3 -0
- package/.next/server/chunks/4553.js +1 -1
- package/.next/server/chunks/4812.js +179 -0
- package/.next/server/chunks/4925.js +1 -1
- package/.next/server/chunks/{3953.js → 5068.js} +2 -2
- package/.next/server/chunks/5319.js +1 -1
- package/.next/server/chunks/569.js +1 -1
- package/.next/server/chunks/6730.js +1 -1
- package/.next/server/chunks/6909.js +142 -161
- package/.next/server/chunks/8262.js +1 -1
- package/.next/server/chunks/9098.js +1 -1
- package/.next/server/chunks/94.js +1 -1
- package/.next/server/chunks/9427.js +1 -0
- package/.next/server/chunks/9538.js +1 -0
- package/.next/server/chunks/963.js +1 -0
- package/.next/server/chunks/9835.js +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/pages-manifest.json +1 -2
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/2865-134f546f21ca4330.js +1 -0
- package/.next/static/chunks/4108.5abdb7812a13eafd.js +1 -0
- package/.next/static/chunks/5254-4196f25e56270de5.js +1 -0
- package/.next/static/chunks/5521-cbc665104c7e59d3.js +1 -0
- package/.next/static/chunks/6445-99824866a51b582a.js +1 -0
- package/.next/static/chunks/8855-9b941d2b78f398ce.js +1 -0
- package/.next/static/chunks/8871-2948840b33c0863d.js +1 -0
- package/.next/static/chunks/9411-af5f758c57741929.js +3 -0
- package/.next/static/chunks/app/agents/[agentId]/page-5d6f4cb16b42d02b.js +1 -0
- package/.next/static/chunks/app/layout-d4cf24375db6d793.js +1 -0
- package/.next/static/chunks/app/onboarding/page-7303664b62ccc24a.js +1 -0
- package/.next/static/chunks/app/page-97d312db91d569f7.js +1 -0
- package/.next/static/chunks/app/roots/[id]/chat/[topicId]/page-123f60a544619a3c.js +1 -0
- package/.next/static/chunks/app/roots/[id]/kb/[...slug]/page-e253597edb1b2440.js +1 -0
- package/.next/static/chunks/app/roots/[id]/page-91a8de6a1c79f8a3.js +1 -0
- package/.next/static/chunks/app/roots/[id]/workflows/[wfId]/page-4300a52e163883df.js +1 -0
- package/.next/static/chunks/app/roots/new/page-6b104aad46a38173.js +1 -0
- package/.next/static/chunks/app/settings/page-afe1b80f7f45c5eb.js +1 -0
- package/.next/static/chunks/app/share/[id]/page-a5fb565bd892d4df.js +1 -0
- package/.next/static/chunks/app/utilities/[scope]/[id]/page-eb713a2b5209942c.js +1 -0
- package/.next/static/chunks/app/utilities/page-b7f30c151c42a27c.js +1 -0
- package/.next/static/chunks/{webpack-5fca180586957874.js → webpack-bddc3babcbc30dd7.js} +1 -1
- package/.next/static/css/60e9b6cdf1283e83.css +1 -0
- package/.next/trace +47 -46
- package/dist/lib/reflex/agents/prompts.js +46 -46
- package/dist/lib/reflex/agents/prompts.js.map +1 -1
- package/dist/lib/reflex/prompts/defaults.js +102 -102
- package/next.config.ts +4 -1
- package/package.json +2 -2
- package/.next/server/app/_not-found.html +0 -1
- package/.next/server/app/_not-found.meta +0 -8
- package/.next/server/app/_not-found.rsc +0 -18
- package/.next/server/app/index.html +0 -1
- package/.next/server/app/index.meta +0 -9
- package/.next/server/app/index.rsc +0 -19
- package/.next/server/chunks/1410.js +0 -1
- package/.next/server/chunks/1986.js +0 -1
- package/.next/server/chunks/2448.js +0 -3
- package/.next/server/chunks/5754.js +0 -3
- package/.next/server/chunks/7097.js +0 -1
- package/.next/server/chunks/7782.js +0 -1
- package/.next/server/chunks/7987.js +0 -1
- package/.next/server/chunks/810.js +0 -1
- package/.next/server/chunks/8843.js +0 -1
- package/.next/server/chunks/9328.js +0 -179
- package/.next/server/pages/404.html +0 -1
- package/.next/static/chunks/2488-c9590facb4b9f184.js +0 -1
- package/.next/static/chunks/2684-257d38989ef53935.js +0 -1
- package/.next/static/chunks/4108.fb9f99a9c899ef54.js +0 -1
- package/.next/static/chunks/6231-d83c1544bbea8424.js +0 -1
- package/.next/static/chunks/9045-731ff0865352dd95.js +0 -1
- package/.next/static/chunks/9496-75ccd3fadb294fba.js +0 -1
- package/.next/static/chunks/992-4e7b7f722c629e21.js +0 -1
- package/.next/static/chunks/app/agents/[agentId]/page-0b5c2838354d0eba.js +0 -1
- package/.next/static/chunks/app/layout-9a59ed07c18cb786.js +0 -1
- package/.next/static/chunks/app/onboarding/page-79f07a813ea2abfe.js +0 -1
- package/.next/static/chunks/app/page-27f4b98b02ac4f79.js +0 -1
- package/.next/static/chunks/app/roots/[id]/chat/[topicId]/page-8db2d0b75cd333c8.js +0 -1
- package/.next/static/chunks/app/roots/[id]/kb/[...slug]/page-873b131eec3a2f30.js +0 -1
- package/.next/static/chunks/app/roots/[id]/page-270d0d49eb668784.js +0 -1
- package/.next/static/chunks/app/roots/[id]/workflows/[wfId]/page-7c1f10dbe0bcb9ad.js +0 -1
- package/.next/static/chunks/app/roots/new/page-ac1a9f6379710ca2.js +0 -1
- package/.next/static/chunks/app/settings/page-81cb1393e817dfc3.js +0 -1
- package/.next/static/chunks/app/share/[id]/page-2d123f0a99e1606f.js +0 -1
- package/.next/static/chunks/app/utilities/[scope]/[id]/page-0bbb8d17af80c1da.js +0 -1
- package/.next/static/chunks/app/utilities/page-e6ce673b9357bf1f.js +0 -1
- package/.next/static/css/87e01f779d555d04.css +0 -1
- package/packages/utilities/learn-anything/README.md +0 -41
- package/packages/utilities/learn-anything/actions/_json.ts +0 -191
- package/packages/utilities/learn-anything/actions/_store.ts +0 -248
- package/packages/utilities/learn-anything/actions/buildModule.ts +0 -487
- package/packages/utilities/learn-anything/actions/explainSelection.ts +0 -64
- package/packages/utilities/learn-anything/actions/generateOutline.ts +0 -170
- package/packages/utilities/learn-anything/actions/generateQuiz.ts +0 -72
- package/packages/utilities/learn-anything/actions/generateTrainer.ts +0 -106
- package/packages/utilities/learn-anything/actions/refreshCourseCard.ts +0 -76
- package/packages/utilities/learn-anything/actions/tutorAsk.ts +0 -93
- package/packages/utilities/learn-anything/article-view.tsx +0 -464
- package/packages/utilities/learn-anything/manifest.json +0 -42
- package/packages/utilities/learn-anything/ui.tsx +0 -1589
- /package/.next/static/{og_wC7UPkGtJDiapaTgBr → IGuuMcet1qtGZQCP2MEn4}/_buildManifest.js +0 -0
- /package/.next/static/{og_wC7UPkGtJDiapaTgBr → IGuuMcet1qtGZQCP2MEn4}/_ssgManifest.js +0 -0
|
@@ -1,464 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
-
import ReactMarkdown, { type Components } from "react-markdown";
|
|
3
|
-
import remarkGfm from "remark-gfm";
|
|
4
|
-
import mermaid from "mermaid";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Self-contained article renderer for course modules. Owns:
|
|
8
|
-
*
|
|
9
|
-
* • Typography — no dependency on @tailwindcss/typography. Each
|
|
10
|
-
* markdown element is mapped to an explicit class so headings,
|
|
11
|
-
* blockquotes, lists, code blocks look like they belong in a
|
|
12
|
-
* reading app (think "course on the web", not "raw textarea").
|
|
13
|
-
*
|
|
14
|
-
* • Mermaid diagrams — any `code` block with language=`mermaid` is
|
|
15
|
-
* swapped for a `<pre class="mermaid">` shell after mount; we then
|
|
16
|
-
* ask the global mermaid library to compile every such block on
|
|
17
|
-
* screen into an SVG. Re-runs whenever the source content changes.
|
|
18
|
-
*/
|
|
19
|
-
let mermaidReady = false;
|
|
20
|
-
function ensureMermaid(): void {
|
|
21
|
-
if (mermaidReady) return;
|
|
22
|
-
mermaidReady = true;
|
|
23
|
-
try {
|
|
24
|
-
mermaid.initialize({
|
|
25
|
-
startOnLoad: false,
|
|
26
|
-
theme: "neutral",
|
|
27
|
-
securityLevel: "loose", // utility iframe is already sandboxed
|
|
28
|
-
fontFamily:
|
|
29
|
-
"-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
|
|
30
|
-
});
|
|
31
|
-
} catch {
|
|
32
|
-
/* mermaid init can be re-run safely; ignore early failures */
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function ArticleView({
|
|
37
|
-
source,
|
|
38
|
-
onMouseUp,
|
|
39
|
-
}: {
|
|
40
|
-
source: string;
|
|
41
|
-
onMouseUp?: () => void;
|
|
42
|
-
}) {
|
|
43
|
-
const ref = useRef<HTMLDivElement | null>(null);
|
|
44
|
-
// Agents sometimes embed mermaid blocks without ```mermaid fences —
|
|
45
|
-
// we wrap them on the fly so ReactMarkdown emits language-mermaid
|
|
46
|
-
// <code> nodes that the `pre` override below picks up.
|
|
47
|
-
const normalized = wrapBareMermaid(source);
|
|
48
|
-
|
|
49
|
-
// Compile every <pre class="reflex-mermaid"> to inline SVG. Using
|
|
50
|
-
// mermaid.render() per element (rather than mermaid.run) gives us
|
|
51
|
-
// proper error capture per-block — we replace failed blocks with a
|
|
52
|
-
// visible error message instead of leaving raw source on screen.
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
ensureMermaid();
|
|
55
|
-
const root = ref.current;
|
|
56
|
-
if (!root) return;
|
|
57
|
-
const nodes = Array.from(
|
|
58
|
-
root.querySelectorAll<HTMLElement>("pre.reflex-mermaid:not(.reflex-mermaid-done)"),
|
|
59
|
-
);
|
|
60
|
-
if (nodes.length === 0) return;
|
|
61
|
-
let cancelled = false;
|
|
62
|
-
void (async () => {
|
|
63
|
-
for (const node of nodes) {
|
|
64
|
-
if (cancelled) return;
|
|
65
|
-
const src = (node.dataset["src"] ?? node.textContent ?? "").trim();
|
|
66
|
-
if (!src) continue;
|
|
67
|
-
const id = `mmd-${Math.random().toString(36).slice(2, 9)}`;
|
|
68
|
-
try {
|
|
69
|
-
const { svg } = await mermaid.render(id, src);
|
|
70
|
-
if (cancelled) return;
|
|
71
|
-
node.innerHTML = svg;
|
|
72
|
-
node.classList.add("reflex-mermaid-done");
|
|
73
|
-
node.classList.remove("reflex-mermaid"); // shed the source styling
|
|
74
|
-
node.style.fontFamily = "inherit";
|
|
75
|
-
} catch (err) {
|
|
76
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
77
|
-
node.innerHTML = `<div class="text-xs text-red-600 not-italic">⚠ Не удалось отрисовать схему: ${escapeHtml(msg)}</div><pre class="mt-2 text-[11px] text-slate-700 whitespace-pre-wrap">${escapeHtml(src)}</pre>`;
|
|
78
|
-
node.classList.add("reflex-mermaid-done");
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
})();
|
|
82
|
-
return () => {
|
|
83
|
-
cancelled = true;
|
|
84
|
-
};
|
|
85
|
-
}, [normalized]);
|
|
86
|
-
|
|
87
|
-
const [zoom, setZoom] = useState<{ src: string; alt: string } | null>(null);
|
|
88
|
-
// Component map needs access to `setZoom`, so build it per-render
|
|
89
|
-
// (memoed). The vast majority of nodes are static — only the `img`
|
|
90
|
-
// override carries the click handler.
|
|
91
|
-
const components = useMemo<Components>(
|
|
92
|
-
() => ({
|
|
93
|
-
...MD_COMPONENTS,
|
|
94
|
-
img: ({ src, alt }) => {
|
|
95
|
-
const url = typeof src === "string" ? src : "";
|
|
96
|
-
const safeAlt = typeof alt === "string" ? alt : "";
|
|
97
|
-
if (!url) return null;
|
|
98
|
-
return (
|
|
99
|
-
// eslint-disable-next-line @next/next/no-img-element
|
|
100
|
-
<img
|
|
101
|
-
src={url}
|
|
102
|
-
alt={safeAlt}
|
|
103
|
-
title={safeAlt || "Открыть на весь экран"}
|
|
104
|
-
loading="lazy"
|
|
105
|
-
onClick={() => setZoom({ src: url, alt: safeAlt })}
|
|
106
|
-
className="my-5 rounded-lg border bg-white max-w-full h-auto cursor-zoom-in transition hover:opacity-90"
|
|
107
|
-
/>
|
|
108
|
-
);
|
|
109
|
-
},
|
|
110
|
-
}),
|
|
111
|
-
[],
|
|
112
|
-
);
|
|
113
|
-
return (
|
|
114
|
-
<div
|
|
115
|
-
ref={ref}
|
|
116
|
-
onMouseUp={onMouseUp}
|
|
117
|
-
className="text-slate-900 [&_*::selection]:bg-violet-200"
|
|
118
|
-
style={{ fontFamily: "Georgia, 'Times New Roman', serif" }}
|
|
119
|
-
>
|
|
120
|
-
<ReactMarkdown remarkPlugins={[remarkGfm]} components={components}>
|
|
121
|
-
{normalized}
|
|
122
|
-
</ReactMarkdown>
|
|
123
|
-
{zoom && (
|
|
124
|
-
<ArticleImageLightbox
|
|
125
|
-
src={zoom.src}
|
|
126
|
-
alt={zoom.alt}
|
|
127
|
-
onClose={() => setZoom(null)}
|
|
128
|
-
/>
|
|
129
|
-
)}
|
|
130
|
-
</div>
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Reusable fullscreen lightbox. Exported so the rest of the learn-anything
|
|
136
|
-
* UI (gallery card, etc.) can share the same overlay rather than each
|
|
137
|
-
* surface rolling its own.
|
|
138
|
-
*/
|
|
139
|
-
export function ArticleImageLightbox({
|
|
140
|
-
src,
|
|
141
|
-
alt,
|
|
142
|
-
onClose,
|
|
143
|
-
}: {
|
|
144
|
-
src: string;
|
|
145
|
-
alt: string;
|
|
146
|
-
onClose: () => void;
|
|
147
|
-
}) {
|
|
148
|
-
const handleKey = useCallback(
|
|
149
|
-
(e: KeyboardEvent) => {
|
|
150
|
-
if (e.key === "Escape") onClose();
|
|
151
|
-
},
|
|
152
|
-
[onClose],
|
|
153
|
-
);
|
|
154
|
-
useEffect(() => {
|
|
155
|
-
document.addEventListener("keydown", handleKey);
|
|
156
|
-
const prev = document.body.style.overflow;
|
|
157
|
-
document.body.style.overflow = "hidden";
|
|
158
|
-
return () => {
|
|
159
|
-
document.removeEventListener("keydown", handleKey);
|
|
160
|
-
document.body.style.overflow = prev;
|
|
161
|
-
};
|
|
162
|
-
}, [handleKey]);
|
|
163
|
-
return (
|
|
164
|
-
<div
|
|
165
|
-
onClick={onClose}
|
|
166
|
-
role="dialog"
|
|
167
|
-
aria-label={alt || "Просмотр изображения"}
|
|
168
|
-
style={{
|
|
169
|
-
position: "fixed",
|
|
170
|
-
inset: 0,
|
|
171
|
-
zIndex: 9999,
|
|
172
|
-
display: "flex",
|
|
173
|
-
alignItems: "center",
|
|
174
|
-
justifyContent: "center",
|
|
175
|
-
padding: "24px",
|
|
176
|
-
background: "rgba(15, 23, 42, 0.85)",
|
|
177
|
-
backdropFilter: "blur(4px)",
|
|
178
|
-
cursor: "zoom-out",
|
|
179
|
-
}}
|
|
180
|
-
>
|
|
181
|
-
<button
|
|
182
|
-
type="button"
|
|
183
|
-
onClick={(e) => {
|
|
184
|
-
e.stopPropagation();
|
|
185
|
-
onClose();
|
|
186
|
-
}}
|
|
187
|
-
aria-label="Закрыть"
|
|
188
|
-
style={{
|
|
189
|
-
position: "absolute",
|
|
190
|
-
top: 16,
|
|
191
|
-
right: 16,
|
|
192
|
-
height: 36,
|
|
193
|
-
width: 36,
|
|
194
|
-
borderRadius: 8,
|
|
195
|
-
background: "rgba(255,255,255,0.92)",
|
|
196
|
-
border: "1px solid rgba(15,23,42,0.1)",
|
|
197
|
-
cursor: "pointer",
|
|
198
|
-
fontSize: 18,
|
|
199
|
-
}}
|
|
200
|
-
>
|
|
201
|
-
×
|
|
202
|
-
</button>
|
|
203
|
-
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
204
|
-
<img
|
|
205
|
-
src={src}
|
|
206
|
-
alt={alt}
|
|
207
|
-
onClick={(e) => e.stopPropagation()}
|
|
208
|
-
style={{
|
|
209
|
-
maxHeight: "100%",
|
|
210
|
-
maxWidth: "100%",
|
|
211
|
-
objectFit: "contain",
|
|
212
|
-
borderRadius: 12,
|
|
213
|
-
boxShadow: "0 30px 60px rgba(0,0,0,0.5)",
|
|
214
|
-
}}
|
|
215
|
-
/>
|
|
216
|
-
{alt && (
|
|
217
|
-
<div
|
|
218
|
-
style={{
|
|
219
|
-
position: "absolute",
|
|
220
|
-
bottom: 24,
|
|
221
|
-
left: 24,
|
|
222
|
-
right: 24,
|
|
223
|
-
textAlign: "center",
|
|
224
|
-
color: "rgba(255,255,255,0.85)",
|
|
225
|
-
fontSize: 13,
|
|
226
|
-
pointerEvents: "none",
|
|
227
|
-
}}
|
|
228
|
-
>
|
|
229
|
-
{alt}
|
|
230
|
-
</div>
|
|
231
|
-
)}
|
|
232
|
-
</div>
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// ---------------------------------------------------------------------------
|
|
237
|
-
// Typography map. Explicit per-element so we don't rely on @tailwindcss/
|
|
238
|
-
// typography being available inside the utility's tailwind compile.
|
|
239
|
-
|
|
240
|
-
const MD_COMPONENTS: Components = {
|
|
241
|
-
h1: ({ children }) => (
|
|
242
|
-
<h1 className="mt-8 mb-4 text-3xl font-bold tracking-tight text-slate-900 border-b border-slate-200 pb-2">
|
|
243
|
-
{children}
|
|
244
|
-
</h1>
|
|
245
|
-
),
|
|
246
|
-
h2: ({ children }) => (
|
|
247
|
-
<h2 className="mt-7 mb-3 text-2xl font-semibold tracking-tight text-slate-900">
|
|
248
|
-
{children}
|
|
249
|
-
</h2>
|
|
250
|
-
),
|
|
251
|
-
h3: ({ children }) => (
|
|
252
|
-
<h3 className="mt-6 mb-2 text-xl font-semibold tracking-tight text-slate-900">
|
|
253
|
-
{children}
|
|
254
|
-
</h3>
|
|
255
|
-
),
|
|
256
|
-
h4: ({ children }) => (
|
|
257
|
-
<h4 className="mt-5 mb-2 text-base font-semibold uppercase tracking-wider text-slate-700">
|
|
258
|
-
{children}
|
|
259
|
-
</h4>
|
|
260
|
-
),
|
|
261
|
-
p: ({ children }) => (
|
|
262
|
-
<p className="my-4 leading-7 text-slate-800 text-[15px]">{children}</p>
|
|
263
|
-
),
|
|
264
|
-
strong: ({ children }) => (
|
|
265
|
-
<strong className="font-semibold text-slate-900">{children}</strong>
|
|
266
|
-
),
|
|
267
|
-
em: ({ children }) => <em className="italic text-slate-800">{children}</em>,
|
|
268
|
-
blockquote: ({ children }) => (
|
|
269
|
-
<blockquote className="my-5 border-l-4 border-violet-400 bg-violet-50/60 px-4 py-2 italic text-slate-700">
|
|
270
|
-
{children}
|
|
271
|
-
</blockquote>
|
|
272
|
-
),
|
|
273
|
-
hr: () => <hr className="my-8 border-slate-200" />,
|
|
274
|
-
a: ({ href, children }) => (
|
|
275
|
-
<a
|
|
276
|
-
href={href}
|
|
277
|
-
target="_blank"
|
|
278
|
-
rel="noopener noreferrer"
|
|
279
|
-
className="text-violet-700 underline decoration-violet-300 underline-offset-2 hover:decoration-violet-600"
|
|
280
|
-
>
|
|
281
|
-
{children}
|
|
282
|
-
</a>
|
|
283
|
-
),
|
|
284
|
-
ul: ({ children }) => (
|
|
285
|
-
<ul className="my-4 ml-6 list-disc space-y-1.5 text-[15px] text-slate-800 leading-7 marker:text-slate-400">
|
|
286
|
-
{children}
|
|
287
|
-
</ul>
|
|
288
|
-
),
|
|
289
|
-
ol: ({ children }) => (
|
|
290
|
-
<ol className="my-4 ml-6 list-decimal space-y-1.5 text-[15px] text-slate-800 leading-7 marker:text-slate-500 marker:font-semibold">
|
|
291
|
-
{children}
|
|
292
|
-
</ol>
|
|
293
|
-
),
|
|
294
|
-
li: ({ children }) => <li className="pl-1">{children}</li>,
|
|
295
|
-
code: ({ className, children }) => {
|
|
296
|
-
const lang = /language-(\w+)/.exec(className ?? "")?.[1];
|
|
297
|
-
// Inline code (no language) → small chip.
|
|
298
|
-
if (!lang) {
|
|
299
|
-
return (
|
|
300
|
-
<code className="rounded bg-slate-100 px-1.5 py-0.5 text-[0.875em] font-mono text-violet-700">
|
|
301
|
-
{children}
|
|
302
|
-
</code>
|
|
303
|
-
);
|
|
304
|
-
}
|
|
305
|
-
// Block code with a recognized fence — leave class for parent <pre>.
|
|
306
|
-
return (
|
|
307
|
-
<code className={`language-${lang} font-mono`}>{children}</code>
|
|
308
|
-
);
|
|
309
|
-
},
|
|
310
|
-
pre: ({ children }) => {
|
|
311
|
-
// Detect the mermaid case: the child <code> has lang=mermaid. Swap
|
|
312
|
-
// <pre> for a marker class the effect later compiles into SVG.
|
|
313
|
-
const child = Array.isArray(children) ? children[0] : children;
|
|
314
|
-
if (
|
|
315
|
-
child &&
|
|
316
|
-
typeof child === "object" &&
|
|
317
|
-
"props" in child &&
|
|
318
|
-
typeof (child as { props?: { className?: string } }).props?.className ===
|
|
319
|
-
"string"
|
|
320
|
-
) {
|
|
321
|
-
const cls = (child as { props: { className: string } }).props.className;
|
|
322
|
-
if (cls.includes("language-mermaid")) {
|
|
323
|
-
const codeNode = child as { props: { children?: unknown } };
|
|
324
|
-
const text = collectText(codeNode.props.children);
|
|
325
|
-
// `data-src` carries the raw mermaid source so the effect
|
|
326
|
-
// doesn't have to depend on `textContent` (which can pick up
|
|
327
|
-
// ReactMarkdown's internal whitespace handling).
|
|
328
|
-
return (
|
|
329
|
-
<pre
|
|
330
|
-
className="reflex-mermaid my-6 rounded-lg border border-slate-200 bg-slate-50 p-4 text-sm overflow-x-auto whitespace-pre"
|
|
331
|
-
data-src={text}
|
|
332
|
-
style={{ fontFamily: "ui-monospace, monospace" }}
|
|
333
|
-
>
|
|
334
|
-
{text}
|
|
335
|
-
</pre>
|
|
336
|
-
);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
return (
|
|
340
|
-
<pre className="my-5 rounded-lg bg-slate-900 text-slate-50 px-4 py-3 text-sm overflow-x-auto leading-relaxed">
|
|
341
|
-
{children}
|
|
342
|
-
</pre>
|
|
343
|
-
);
|
|
344
|
-
},
|
|
345
|
-
table: ({ children }) => (
|
|
346
|
-
<div className="my-5 overflow-x-auto">
|
|
347
|
-
<table className="w-full border-collapse text-sm">{children}</table>
|
|
348
|
-
</div>
|
|
349
|
-
),
|
|
350
|
-
thead: ({ children }) => (
|
|
351
|
-
<thead className="bg-slate-100">{children}</thead>
|
|
352
|
-
),
|
|
353
|
-
th: ({ children }) => (
|
|
354
|
-
<th className="border border-slate-300 px-3 py-2 text-left font-semibold text-slate-700">
|
|
355
|
-
{children}
|
|
356
|
-
</th>
|
|
357
|
-
),
|
|
358
|
-
td: ({ children }) => (
|
|
359
|
-
<td className="border border-slate-200 px-3 py-2 align-top">{children}</td>
|
|
360
|
-
),
|
|
361
|
-
// `img` is overridden per-render inside ArticleView (it needs setZoom).
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* Wrap unfenced mermaid diagrams in ```mermaid …``` so ReactMarkdown
|
|
366
|
-
* tags them as `language-mermaid` and the renderer pipeline catches
|
|
367
|
-
* them. Detects blocks that START with a mermaid keyword (graph,
|
|
368
|
-
* flowchart, sequenceDiagram, etc.) and run until a blank line or
|
|
369
|
-
* the next heading.
|
|
370
|
-
*
|
|
371
|
-
* Already-fenced blocks pass through untouched.
|
|
372
|
-
*/
|
|
373
|
-
const MERMAID_KEYWORDS = [
|
|
374
|
-
"graph",
|
|
375
|
-
"flowchart",
|
|
376
|
-
"sequenceDiagram",
|
|
377
|
-
"classDiagram",
|
|
378
|
-
"stateDiagram",
|
|
379
|
-
"stateDiagram-v2",
|
|
380
|
-
"erDiagram",
|
|
381
|
-
"gantt",
|
|
382
|
-
"pie",
|
|
383
|
-
"journey",
|
|
384
|
-
"gitGraph",
|
|
385
|
-
"mindmap",
|
|
386
|
-
"timeline",
|
|
387
|
-
"quadrantChart",
|
|
388
|
-
"C4Context",
|
|
389
|
-
"requirementDiagram",
|
|
390
|
-
];
|
|
391
|
-
|
|
392
|
-
function wrapBareMermaid(text: string): string {
|
|
393
|
-
if (!text) return text;
|
|
394
|
-
const lines = text.split("\n");
|
|
395
|
-
const out: string[] = [];
|
|
396
|
-
let i = 0;
|
|
397
|
-
let inFence = false;
|
|
398
|
-
while (i < lines.length) {
|
|
399
|
-
const line = lines[i]!;
|
|
400
|
-
// Track fenced state so we never wrap inside an existing code block.
|
|
401
|
-
if (/^```/.test(line)) {
|
|
402
|
-
inFence = !inFence;
|
|
403
|
-
out.push(line);
|
|
404
|
-
i++;
|
|
405
|
-
continue;
|
|
406
|
-
}
|
|
407
|
-
if (!inFence && isMermaidStart(line)) {
|
|
408
|
-
// Collect lines until blank line, heading, or another fence start.
|
|
409
|
-
const block: string[] = [line];
|
|
410
|
-
let j = i + 1;
|
|
411
|
-
while (j < lines.length) {
|
|
412
|
-
const l = lines[j]!;
|
|
413
|
-
if (l.trim() === "") break;
|
|
414
|
-
if (/^#{1,6}\s/.test(l)) break;
|
|
415
|
-
if (/^```/.test(l)) break;
|
|
416
|
-
block.push(l);
|
|
417
|
-
j++;
|
|
418
|
-
}
|
|
419
|
-
out.push("```mermaid");
|
|
420
|
-
out.push(...block);
|
|
421
|
-
out.push("```");
|
|
422
|
-
i = j;
|
|
423
|
-
continue;
|
|
424
|
-
}
|
|
425
|
-
out.push(line);
|
|
426
|
-
i++;
|
|
427
|
-
}
|
|
428
|
-
return out.join("\n");
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
function isMermaidStart(line: string): boolean {
|
|
432
|
-
const trimmed = line.trim();
|
|
433
|
-
if (!trimmed) return false;
|
|
434
|
-
for (const kw of MERMAID_KEYWORDS) {
|
|
435
|
-
if (trimmed === kw) return true;
|
|
436
|
-
if (trimmed.startsWith(kw + " ")) return true;
|
|
437
|
-
// `graph LR`, `flowchart TD` etc.
|
|
438
|
-
if (
|
|
439
|
-
trimmed.startsWith(kw) &&
|
|
440
|
-
/^[A-Z]{2}$/.test(trimmed.slice(kw.length).trim())
|
|
441
|
-
) {
|
|
442
|
-
return true;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
return false;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
function escapeHtml(s: string): string {
|
|
449
|
-
return s
|
|
450
|
-
.replace(/&/g, "&")
|
|
451
|
-
.replace(/</g, "<")
|
|
452
|
-
.replace(/>/g, ">")
|
|
453
|
-
.replace(/"/g, """);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
function collectText(children: unknown): string {
|
|
457
|
-
if (typeof children === "string") return children;
|
|
458
|
-
if (Array.isArray(children)) return children.map(collectText).join("");
|
|
459
|
-
if (children && typeof children === "object" && "props" in children) {
|
|
460
|
-
const props = (children as { props?: { children?: unknown } }).props;
|
|
461
|
-
return collectText(props?.children);
|
|
462
|
-
}
|
|
463
|
-
return "";
|
|
464
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "learn-anything",
|
|
3
|
-
"name": "🎓 Изучи что угодно",
|
|
4
|
-
"version": "0.4.7",
|
|
5
|
-
"description": "Универсальный AI-наставник: курсы под твой уровень с контентом, тестами и тренажёрами",
|
|
6
|
-
"author": "reflex-org",
|
|
7
|
-
"category": "study",
|
|
8
|
-
"ui": "ui.tsx",
|
|
9
|
-
"icon": "lucide:GraduationCap",
|
|
10
|
-
"card": {
|
|
11
|
-
"kind": "kpi",
|
|
12
|
-
"title": "🎓 Учусь",
|
|
13
|
-
"data": {
|
|
14
|
-
"items": [
|
|
15
|
-
{ "label": "Активных курсов", "value": "0" },
|
|
16
|
-
{ "label": "Прогресс", "value": "—", "hint": "среднее по курсам" }
|
|
17
|
-
]
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
"serverActions": [
|
|
21
|
-
{ "name": "tutorAsk", "entry": "actions/tutorAsk.ts", "timeoutMs": 120000 },
|
|
22
|
-
{ "name": "generateOutline", "entry": "actions/generateOutline.ts", "timeoutMs": 300000 },
|
|
23
|
-
{ "name": "buildModule", "entry": "actions/buildModule.ts", "timeoutMs": 480000 },
|
|
24
|
-
{ "name": "generateQuiz", "entry": "actions/generateQuiz.ts", "timeoutMs": 180000 },
|
|
25
|
-
{ "name": "explainSelection", "entry": "actions/explainSelection.ts", "timeoutMs": 120000 },
|
|
26
|
-
{ "name": "generateTrainer", "entry": "actions/generateTrainer.ts", "timeoutMs": 480000 },
|
|
27
|
-
{ "name": "refreshCourseCard", "entry": "actions/refreshCourseCard.ts", "timeoutMs": 30000 }
|
|
28
|
-
],
|
|
29
|
-
"permissions": {
|
|
30
|
-
"llm": { "tasks": ["chat", "quick"] },
|
|
31
|
-
"kb": { "read": true, "write": true, "kinds": ["course", "course-module", "course-trainer", "course-note"] },
|
|
32
|
-
"fs": { "sandbox": true },
|
|
33
|
-
"web": {
|
|
34
|
-
"fetch": { "domains": ["wikipedia.org", "en.wikipedia.org", "ru.wikipedia.org", "developer.mozilla.org", "youtube.com", "youtu.be", "github.com", "raw.githubusercontent.com", "stackoverflow.com", "medium.com"] },
|
|
35
|
-
"search": true
|
|
36
|
-
},
|
|
37
|
-
"audit": { "write": true },
|
|
38
|
-
"workers": { "enabled": true, "maxConcurrent": 3 },
|
|
39
|
-
"agent": { "invoke": true },
|
|
40
|
-
"images": { "generate": true, "search": true, "attach": true }
|
|
41
|
-
}
|
|
42
|
-
}
|