diff --git a/GPTutor-Frontend/npm_install.log b/GPTutor-Frontend/npm_install.log new file mode 100644 index 00000000..55ce4e02 --- /dev/null +++ b/GPTutor-Frontend/npm_install.log @@ -0,0 +1,35 @@ +npm error code ERESOLVE +npm error ERESOLVE could not resolve +npm error +npm error While resolving: @happysanta/router@0.3.1 +npm error Found: react@18.2.0 +npm error node_modules/react +npm error react@"18.2.0" from the root project +npm error peer react@">=16.8.0" from @floating-ui/react-dom@2.0.8 +npm error node_modules/@floating-ui/react-dom +npm error @floating-ui/react-dom@"^2.0.8" from @vkontakte/vkui-floating-ui@0.1.5 +npm error node_modules/@vkontakte/vkui-floating-ui +npm error @vkontakte/vkui-floating-ui@"^0.1.2" from @vkontakte/vkui@6.0.2 +npm error node_modules/@vkontakte/vkui +npm error @vkontakte/vkui@"6.0.2" from the root project +npm error 14 more (@monaco-editor/react, @uiw/react-codemirror, ...) +npm error +npm error Could not resolve dependency: +npm error peer react@"^17.0.0" from @happysanta/router@0.3.1 +npm error node_modules/@happysanta/router +npm error @happysanta/router@"0.3.1" from the root project +npm error +npm error Conflicting peer dependency: react@17.0.2 +npm error node_modules/react +npm error peer react@"^17.0.0" from @happysanta/router@0.3.1 +npm error node_modules/@happysanta/router +npm error @happysanta/router@"0.3.1" from the root project +npm error +npm error Fix the upstream dependency conflict, or retry +npm error this command with --force or --legacy-peer-deps +npm error to accept an incorrect (and potentially broken) dependency resolution. +npm error +npm error +npm error For a full report see: +npm error /home/hive/.npm/_logs/2025-09-10T17_59_42_363Z-eresolve-report.txt +npm error A complete log of this run can be found in: /home/hive/.npm/_logs/2025-09-10T17_59_42_363Z-debug-0.log diff --git a/GPTutor-Frontend/npm_install_legacy.log b/GPTutor-Frontend/npm_install_legacy.log new file mode 100644 index 00000000..9532c6d7 --- /dev/null +++ b/GPTutor-Frontend/npm_install_legacy.log @@ -0,0 +1,3 @@ +npm warn deprecated @types/classnames@2.3.1: This is a stub types definition. classnames provides its own type definitions, so you do not need this installed. +npm warn deprecated @braintree/sanitize-url@3.1.0: Potential XSS vulnerability patched in v6.0.0. +npm warn deprecated axios@0.18.1: Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410 diff --git a/GPTutor-Frontend/src/App.tsx b/GPTutor-Frontend/src/App.tsx index f7bc2896..1d9bfdc3 100644 --- a/GPTutor-Frontend/src/App.tsx +++ b/GPTutor-Frontend/src/App.tsx @@ -74,6 +74,7 @@ import ApplicationInfoHumor from "./modals/ApplicationInfoHumor/ApplicationInfoH import { BingPanel } from "$/panels/BingPanel"; import VKDocQuestionPanel from "./panels/VKDocQuestionPanel/VKDocQestionPanel"; import { VkDocQuestionRequest } from "$/panels/VkDocQuestionRequest"; +import { MarkdownReader } from "$/panels/MarkdownReader"; import { retrieveLaunchParams } from "@telegram-apps/sdk"; const App = () => { @@ -198,6 +199,7 @@ const App = () => { + )} diff --git a/GPTutor-Frontend/src/NavigationContext.tsx b/GPTutor-Frontend/src/NavigationContext.tsx index 5c363ab7..14419ab8 100644 --- a/GPTutor-Frontend/src/NavigationContext.tsx +++ b/GPTutor-Frontend/src/NavigationContext.tsx @@ -57,6 +57,7 @@ export type NavigationContextType = { goToAnecdoteMain: () => void; goToBingPanel: () => void; goToVkDocQuestionRequest: () => void; + goToMarkdownReader: () => void; openAlert: (data: AlertType) => void; alert: AlertType; isForbidden: boolean; @@ -223,6 +224,10 @@ export function NavigationContextProvider({ router.pushPage(RoutingPages.vkDocQuestionRequest); }; + const goToMarkdownReader = () => { + router.pushPage(RoutingPages.markdownReader); + }; + return ( (""); + const [fileName, setFileName] = useState(""); + const [urlInput, setUrlInput] = useState(""); + const [isLoading, setIsLoading] = useState(false); + + const markdown = useMemo(() => new Markdown(), []); + const html = markdownContent ? markdown.render(markdownContent) : ""; + + const handleFileUpload = (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (file && file.type === "text/markdown") { + setFileName(file.name); + const reader = new FileReader(); + reader.onload = (e) => { + const content = e.target?.result as string; + setMarkdownContent(content); + }; + reader.readAsText(file); + } + }; + + const handleUrlLoad = async () => { + if (!urlInput.trim()) return; + + setIsLoading(true); + try { + const response = await fetch(urlInput); + if (response.ok) { + const content = await response.text(); + setMarkdownContent(content); + setFileName(urlInput.split('/').pop() || 'loaded-file.md'); + } else { + console.error('Failed to load markdown file from URL'); + } + } catch (error) { + console.error('Error loading markdown file:', error); + } finally { + setIsLoading(false); + } + }; + + const sampleMarkdown = `# Добро пожаловать в Markdown Reader + +## Что это такое? + +Это средство для чтения и просмотра Markdown файлов с поддержкой: + +- **Выделения кода** с подсветкой синтаксиса +- Математических формул с MathJax +- Сносок и ссылок +- И многого другого! + +## Пример кода + +\`\`\`javascript +function hello() { + console.log("Привет, мир!"); +} +\`\`\` + +## Математика + +Inline формула: $E = mc^2$ + +Block формула: +$$\\sum_{i=1}^{n} x_i = x_1 + x_2 + \\cdots + x_n$$ + +> Это цитата с важной информацией + +Используйте загрузку файла или URL для просмотра ваших Markdown документов!`; + + useEffect(() => { + if (!markdownContent) { + setMarkdownContent(sampleMarkdown); + setFileName("sample.md"); + } + }, []); + + return ( + + } + after={} + > + Markdown Reader + + } + > + + + + Загрузить Markdown файл + + + setUrlInput(e.target.value)} + style={{ marginBottom: 12 }} + /> + + + {isLoading ? "Загрузка..." : "Загрузить по URL"} + + + {fileName && ( + + Текущий файл: {fileName} + + )} + + + + + + + + + + ); +} + +export default MarkdownReader; \ No newline at end of file diff --git a/GPTutor-Frontend/src/panels/MarkdownReader/__tests__/MarkdownReader.test.ts b/GPTutor-Frontend/src/panels/MarkdownReader/__tests__/MarkdownReader.test.ts new file mode 100644 index 00000000..b84681e8 --- /dev/null +++ b/GPTutor-Frontend/src/panels/MarkdownReader/__tests__/MarkdownReader.test.ts @@ -0,0 +1,53 @@ +/** + * @jest-environment jsdom + */ + +// Basic test for MarkdownReader component +describe('MarkdownReader', () => { + it('should have proper file structure', () => { + // Test that the necessary files exist and are properly structured + const fs = require('fs'); + const path = require('path'); + + const componentPath = path.join(__dirname, '../MarkdownReader.tsx'); + const cssPath = path.join(__dirname, '../MarkdownReader.module.css'); + const indexPath = path.join(__dirname, '../index.ts'); + + expect(fs.existsSync(componentPath)).toBe(true); + expect(fs.existsSync(cssPath)).toBe(true); + expect(fs.existsSync(indexPath)).toBe(true); + }); + + it('should export MarkdownReader component', () => { + // This test would normally import and check the component + // but without a build environment, we just validate the export exists + const fs = require('fs'); + const path = require('path'); + + const indexPath = path.join(__dirname, '../index.ts'); + const indexContent = fs.readFileSync(indexPath, 'utf8'); + + expect(indexContent).toContain('export { default as MarkdownReader }'); + expect(indexContent).toContain('./MarkdownReader'); + }); + + it('should have required component structure', () => { + const fs = require('fs'); + const path = require('path'); + + const componentPath = path.join(__dirname, '../MarkdownReader.tsx'); + const componentContent = fs.readFileSync(componentPath, 'utf8'); + + // Check for required imports and structure + expect(componentContent).toContain('import React'); + expect(componentContent).toContain('import Markdown from "$/services/Markdown"'); + expect(componentContent).toContain('function MarkdownReader'); + expect(componentContent).toContain('export default MarkdownReader'); + + // Check for key functionality + expect(componentContent).toContain('useState'); + expect(componentContent).toContain('markdownContent'); + expect(componentContent).toContain('handleFileUpload'); + expect(componentContent).toContain('handleUrlLoad'); + }); +}); \ No newline at end of file diff --git a/GPTutor-Frontend/src/panels/MarkdownReader/index.ts b/GPTutor-Frontend/src/panels/MarkdownReader/index.ts new file mode 100644 index 00000000..f0b8d206 --- /dev/null +++ b/GPTutor-Frontend/src/panels/MarkdownReader/index.ts @@ -0,0 +1 @@ +export { default as MarkdownReader } from "./MarkdownReader"; \ No newline at end of file diff --git a/GPTutor-Frontend/src/panels/Modes/Modes.tsx b/GPTutor-Frontend/src/panels/Modes/Modes.tsx index d660672e..2b62d387 100644 --- a/GPTutor-Frontend/src/panels/Modes/Modes.tsx +++ b/GPTutor-Frontend/src/panels/Modes/Modes.tsx @@ -32,6 +32,7 @@ function Modes({ id }: IProps) { goToChatInterview, goToLeetcodeProblems, goToEditor, + goToMarkdownReader, } = useNavigationContext(); return ( @@ -90,6 +91,14 @@ function Modes({ id }: IProps) { goToEditor(); }} /> + { + goToMarkdownReader(); + }} + /> );