Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 248 additions & 47 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@
"@rollup/plugin-node-resolve": "^15.1.0",
"@testing-library/jest-dom": "^6.4.5",
"@testing-library/react": "^15.0.7",
"@types/lz-string": "^1.3.34",
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@types/testing-library__jest-dom": "^5.14.9",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"@vitejs/plugin-react": "^4.0.3",
Expand Down
211 changes: 112 additions & 99 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useEffect, useState } from "react";
import { App as AntdApp, Layout, Row, Col, Collapse } from "antd";
import { Routes, Route, useSearchParams } from "react-router-dom";
import { App as AntdApp, Layout, Row, Col, Collapse, Spin } from "antd";
import { LoadingOutlined } from "@ant-design/icons";
import { Routes, Route, useSearchParams, useNavigate } from "react-router-dom";
import Navbar from "./components/Navbar";
import Footer from "./components/Footer";
import tour from "./components/Tour";
Expand All @@ -18,8 +19,8 @@ import FloatingFAB from "./components/FabButton";

const { Content } = Layout;


const App = () => {
const navigate = useNavigate();
const init = useAppStore((state) => state.init);
const loadFromLink = useAppStore((state) => state.loadFromLink);
const backgroundColor = useAppStore((state) => state.backgroundColor);
Expand All @@ -35,66 +36,68 @@ const App = () => {
}
};


const onChange = (key: string | string[]) => {
setActivePanel(key);
};

useEffect(() => {
const initializeApp = async () => {
try{
await init();
const compressedData = searchParams.get("data");
if (compressedData) {
await loadFromLink(compressedData);
try {
setLoading(true);
const compressedData = searchParams.get("data");
if (compressedData) {
await loadFromLink(compressedData);
if (window.location.pathname !== "/") {
navigate("/", { replace: true });
}
} else {
await init();
}
} catch (error) {
console.error("Initialization error:", error);
} finally {
setLoading(false);
}
} catch(error){
console.error(error);
} finally {
setLoading(false);
}
};
void initializeApp();
};
initializeApp();
}, [init, loadFromLink, searchParams, navigate]);

// DarkMode Styles
useEffect(() => {
const style = document.createElement("style");
style.innerHTML = `
.ant-collapse-header {
color: ${textColor} !important;
}
.ant-collapse-content {
background-color: ${backgroundColor} !important;
}
.ant-collapse-content-active {
background-color: ${backgroundColor} !important;
}
`;
.ant-collapse-header {
color: ${textColor} !important;
}
.ant-collapse-content {
background-color: ${backgroundColor} !important;
}
.ant-collapse-content-active {
background-color: ${backgroundColor} !important;
}
`;
document.head.appendChild(style);

return () => {
document.head.removeChild(style);
};
}, [init, loadFromLink, searchParams, textColor, backgroundColor]);
}, [backgroundColor, textColor]);

useEffect(() => {
const startTour = async () => {
try {
await tour.start();
localStorage.setItem("hasVisited", "true");
} catch (error) {
console.error("Tour failed to start:", error);
}
};

const showTour = searchParams.get("showTour") === "true";

if (showTour || !localStorage.getItem("hasVisited")) {
void startTour();
localStorage.setItem("hasVisited", "true");
startTour();
}
}, [searchParams]);



const panels = [
{
key: "templateMark",
Expand All @@ -118,91 +121,101 @@ const App = () => {
<Layout style={{ minHeight: "100vh" }}>
<Navbar scrollToFooter={scrollToFooter} />
<Content>
<Routes>
<Route
path="/"
element={
<div
style={{
padding: 24,
paddingBottom: 150,
minHeight: 360,
background: backgroundColor,
}}
>
<Row>
<Col xs={24} sm={8}>
<Row
style={{
marginLeft: "25px",
display: "flex",
flexDirection: "row",
gap: "10px",
}}
>
<SampleDropdown setLoading={setLoading} />
<UseShare />
</Row>
</Col>
<Col span={18}>
<Errors />
</Col>
</Row>
{loading ? (
<div
style={{
flex: 1,
display: "flex",
justifyContent: "center",
alignItems: "center",
minHeight: "calc(100vh - 64px - 70px)", // Adjust for Navbar and Footer height
}}
>
<Spinner />
</div>
) : (
<Routes>
<Route
path="/"
element={
<div
style={{
padding: 24,
paddingBottom: 150,
minHeight: 360,
background: backgroundColor,
}}
>
<Row gutter={24}>
<Col xs={24} sm={16} style={{ paddingBottom: "20px" }}>
<Collapse
defaultActiveKey={activePanel}
onChange={onChange}
items={panels}
/>
</Col>
<Row>
<Col xs={24} sm={8}>
<div
<Row
style={{
marginBottom: "10px",
marginLeft: "25px",
display: "flex",
flexDirection: "row",
gap: "10px",
}}
>
</div>
<AgreementHtml loading={loading} isModal={false} />
<SampleDropdown setLoading={setLoading} />
<UseShare />
</Row>
</Col>
<Col span={18}>
<Errors />
</Col>
</Row>
<div
style={{
padding: 24,
minHeight: 360,
background: backgroundColor,
}}
>
<Row gutter={24}>
<Col xs={24} sm={16} style={{ paddingBottom: "20px" }}>
<Collapse
defaultActiveKey={activePanel}
onChange={onChange}
items={panels}
/>
</Col>
<Col xs={24} sm={8}>
<AgreementHtml loading={loading} isModal={false} />
</Col>
</Row>
</div>
<FloatingFAB />
</div>
<FloatingFAB />
</div>
}
/>

<Route path="/learn" element={<LearnNow />}>
{/* ❕ learning-module routes */}
<Route path="intro" element={<LearnContent file="intro.md" />} />
<Route
path="module1"
element={<LearnContent file="module1.md" />}
/>
<Route
path="module2"
element={<LearnContent file="module2.md" />}
/>

<Route
path="module3"
element={<LearnContent file="module3.md" />}
}
/>
</Route>
</Routes>
<Route path="/learn" element={<LearnNow />}>
<Route path="intro" element={<LearnContent file="intro.md" />} />
<Route path="module1" element={<LearnContent file="module1.md" />} />
<Route path="module2" element={<LearnContent file="module2.md" />} />
<Route path="module3" element={<LearnContent file="module3.md" />} />
</Route>
</Routes>
)}
</Content>
<Footer />

</Layout>
</AntdApp>
);
};

export default App;
const Spinner = () => (
<div
style={{
flex: 1,
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<Spin
indicator={<LoadingOutlined style={{ fontSize: 42, color: "#19c6c7" }} spin />}
/>
</div>
);

export default App;
15 changes: 7 additions & 8 deletions src/components/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import { Spin } from "antd";
import fetchContent from "../utils/fetchContent";
import { steps } from "../constants/learningSteps/steps";
import { LearnContentProps } from "../types/components/Content.types";

// markdown syntax highlighting theme
import "highlight.js/styles/github.css";

const LearnContent: React.FC<LearnContentProps> = ({ file }) => {
Expand All @@ -28,20 +26,21 @@ const LearnContent: React.FC<LearnContentProps> = ({ file }) => {
const navigate = useNavigate();

useEffect(() => {
const loadContent = async (): Promise<void> => {
const loadContent = async () => {
try {
setLoading(true);
const content = await fetchContent(file);
setContent(content);
const contentData = await fetchContent(file);
setContent(contentData);
setError(null);
} catch (err: unknown) {
} catch (err) {
setError("Failed to load content");
console.error(err);
} finally {
setLoading(false);
}
};

void loadContent();
loadContent();
}, [file]);

const currentIndex = steps.findIndex((step) =>
Expand Down Expand Up @@ -117,4 +116,4 @@ const LearnContent: React.FC<LearnContentProps> = ({ file }) => {
);
};

export default LearnContent;
export default LearnContent;
20 changes: 11 additions & 9 deletions src/components/UseShare.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ const UseShare = () => {
);
const [copied, setCopied] = useState(false);

const handleCopy = () => {
const link = generateShareableLink();
void navigator.clipboard.writeText(link).then(() => {
const handleCopy = async () => {
try {
const link = generateShareableLink();
await navigator.clipboard.writeText(link);
setCopied(true);
void message.success("Link copied to clipboard!");
setTimeout(() => {
setCopied(false);
}, 3000);
});
message.success("Link copied to clipboard!");
setTimeout(() => setCopied(false), 3000);
} catch (error) {
message.error("Failed to copy link");
console.error("Clipboard error:", error);
}
};

return (
Expand All @@ -29,4 +31,4 @@ const UseShare = () => {
);
};

export default UseShare;
export default UseShare;
6 changes: 4 additions & 2 deletions src/components/useUndoRedo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

import { useState,useEffect } from 'react';

function useUndoRedo<T>(initialValue: T, onChange?: (value: T) => void) {
const [past, setPast] = useState<T[]>([]);
const [present, setPresent] = useState<T>(initialValue);
Expand All @@ -14,7 +16,7 @@ function useUndoRedo<T>(initialValue: T, onChange?: (value: T) => void) {
setPast((prevPast) => [...prevPast, present]);
setPresent(newValue);
setFuture([]);
if (onChange) onChange(newValue); // Ensure preview updates
if (onChange) onChange(newValue); // Sync with store
};

const undo = () => {
Expand All @@ -38,4 +40,4 @@ function useUndoRedo<T>(initialValue: T, onChange?: (value: T) => void) {
return { value: present, setValue, undo, redo };
}

export default useUndoRedo;
export default useUndoRedo;
Loading