From c0de8e1404ff669adf4bbdfdbf732e08a8bedb15 Mon Sep 17 00:00:00 2001 From: nitro56565 Date: Fri, 8 Nov 2024 18:56:52 +0530 Subject: [PATCH 1/2] Dark Mode Toggle Feature Signed-off-by: nitro56565 --- package-lock.json | 59 ++++++++++++++++++- package.json | 2 + src/AgreementHtml.tsx | 6 +- src/App.tsx | 36 ++++++++--- src/components/FullScreenModal.tsx | 28 ++++++++- src/components/ToggleDarkMode.tsx | 31 ++++++++++ src/editors/MarkdownEditor.tsx | 45 ++++++++++++-- .../editorsContainer/AgreementData.tsx | 5 +- .../editorsContainer/TemplateMarkdown.tsx | 8 ++- .../editorsContainer/TemplateModel.tsx | 5 +- src/store/store.ts | 14 +++++ src/styles/components/ToggleDarkMode.ts | 9 +++ 12 files changed, 223 insertions(+), 25 deletions(-) create mode 100644 src/components/ToggleDarkMode.tsx create mode 100644 src/styles/components/ToggleDarkMode.ts diff --git a/package-lock.json b/package-lock.json index 913770c..9d8808c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,9 @@ "monaco-editor": "^0.50.0", "node-stdlib-browser": "^1.2.0", "normalize.css": "^8.0.1", + "prop-types": "^15.8.1", "react": "^18.2.0", + "react-dark-mode-toggle": "^0.2.0", "react-dom": "^18.2.0", "react-dropdown": "^1.11.0", "react-markdown": "^9.0.1", @@ -14563,6 +14565,12 @@ "npm": ">= 5.x" } }, + "node_modules/lottie-web": { + "version": "5.12.2", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz", + "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==", + "license": "MIT" + }, "node_modules/loupe": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", @@ -16608,7 +16616,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -17015,6 +17022,12 @@ "node": ">=0.10.0" } }, + "node_modules/parse-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-unit/-/parse-unit-1.0.1.tgz", + "integrity": "sha512-hrqldJHokR3Qj88EIlV/kAyAi/G5R2+R56TBANxNMy0uPlYcttx0jnMW6Yx5KsKPSbC3KddM/7qQm3+0wEXKxg==", + "license": "MIT" + }, "node_modules/parse5": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", @@ -17399,6 +17412,17 @@ "node": ">= 6" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/property-information": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", @@ -18188,6 +18212,16 @@ "node": ">=0.10.0" } }, + "node_modules/react-dark-mode-toggle": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/react-dark-mode-toggle/-/react-dark-mode-toggle-0.2.0.tgz", + "integrity": "sha512-YGN6EKU54TaEIQ2G5veB+XVRXSsbyrW9+rop/1Ap06A0z1j6QBVuMIZjhQpwYLKVhSPIxoe7zsWj0cZaEf7cQA==", + "license": "MIT", + "dependencies": { + "parse-unit": "^1.0.1", + "react-lottie-player": "^1.1.1" + } + }, "node_modules/react-devtools-core": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-5.3.1.tgz", @@ -18304,6 +18338,23 @@ "react": "^18.3.1" } }, + "node_modules/react-lottie-player": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/react-lottie-player/-/react-lottie-player-1.5.6.tgz", + "integrity": "sha512-t0GdTYbml0Ihski8ZPx+1WjpjM/EQlTqTcuGm5yeZGJAgFXTmoqrHbSX8bcREIxrHjibWAyIWnLVUK/iHLcqAQ==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lottie-web": "^5.7.6", + "rfdc": "^1.3.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-markdown": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.1.tgz", @@ -19206,6 +19257,12 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", diff --git a/package.json b/package.json index a8fe0be..9cca6a2 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,9 @@ "monaco-editor": "^0.50.0", "node-stdlib-browser": "^1.2.0", "normalize.css": "^8.0.1", + "prop-types": "^15.8.1", "react": "^18.2.0", + "react-dark-mode-toggle": "^0.2.0", "react-dom": "^18.2.0", "react-dropdown": "^1.11.0", "react-markdown": "^9.0.1", diff --git a/src/AgreementHtml.tsx b/src/AgreementHtml.tsx index 75f828a..42c8b2b 100644 --- a/src/AgreementHtml.tsx +++ b/src/AgreementHtml.tsx @@ -4,6 +4,8 @@ import useAppStore from "./store/store"; function AgreementHtml({ loading }: { loading: any }) { const agreementHtml = useAppStore((state) => state.agreementHtml); + const backgroundColor = useAppStore((state) => state.backgroundColor); + const textColor = useAppStore((state) => state.textColor); return (
-
+

Preview Output

The result of merging the JSON data with the template. This is @@ -47,7 +49,7 @@ function AgreementHtml({ loading }: { loading: any }) {

)}
diff --git a/src/App.tsx b/src/App.tsx index 2a2697a..f7183fd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -15,6 +15,7 @@ import SampleDropdown from "./components/SampleDropdown"; import FullScreenModal from "./components/FullScreenModal"; import UseShare from "./components/UseShare"; import LearnContent from "./components/Content"; +import ToggleDarkMode from "./components/ToggleDarkMode"; const { Content } = Layout; const { useBreakpoint } = Grid; @@ -22,6 +23,8 @@ const { useBreakpoint } = Grid; const App = () => { const init = useAppStore((state) => state.init); const loadFromLink = useAppStore((state) => state.loadFromLink); + const backgroundColor = useAppStore((state) => state.backgroundColor); + const textColor = useAppStore((state) => state.textColor); const [activePanel, setActivePanel] = useState(); const [loading, setLoading] = useState(true); const [searchParams] = useSearchParams(); @@ -33,9 +36,6 @@ const App = () => { } }; - const { - token: { colorBgContainer }, - } = theme.useToken(); const onChange = (key: string | string[]) => { setActivePanel(key); @@ -51,7 +51,26 @@ const App = () => { setLoading(false); }; initializeApp(); - }, [init, loadFromLink, searchParams]); + + // DarkMode Styles + 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; + } +`; + document.head.appendChild(style); + + return () => { + document.head.removeChild(style); + }; + }, [init, loadFromLink, searchParams, textColor, backgroundColor]); useEffect(() => { const showTour = searchParams.get("showTour") === "true"; @@ -96,7 +115,7 @@ const App = () => { padding: 24, paddingBottom: 150, minHeight: 360, - background: colorBgContainer, + background: backgroundColor, }} > @@ -121,7 +140,7 @@ const App = () => { style={{ padding: 24, minHeight: 360, - background: colorBgContainer, + background: backgroundColor, }} > @@ -138,7 +157,10 @@ const App = () => { marginBottom: "10px", }} > - +
+ + +
diff --git a/src/components/FullScreenModal.tsx b/src/components/FullScreenModal.tsx index 295fa12..b3ee580 100644 --- a/src/components/FullScreenModal.tsx +++ b/src/components/FullScreenModal.tsx @@ -1,13 +1,37 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import { Modal } from "antd"; import AgreementHtml from "../AgreementHtml"; import { FullscreenOutlined } from "@ant-design/icons"; +import useAppStore from "../store/store"; const FullScreenModal: React.FC = () => { const [open, setOpen] = useState(false); + const textColor = useAppStore((state) => state.textColor); + const backgroundColor = useAppStore((state) => state.backgroundColor); + + useEffect(() => { + const style = document.createElement("style"); + style.innerHTML = ` + .ant-modal-content { + background-color: ${backgroundColor} !important; + color: ${textColor} !important; + } + .ant-modal-header { + background-color: ${backgroundColor} !important; + color: ${textColor} !important; + } + .ant-modal-title{ + color: ${textColor} !important; + } + `; + document.head.appendChild(style); + return () => { + document.head.removeChild(style); + }; + }, [textColor, backgroundColor]); return ( -
+
setOpen(true)} diff --git a/src/components/ToggleDarkMode.tsx b/src/components/ToggleDarkMode.tsx new file mode 100644 index 0000000..88e3621 --- /dev/null +++ b/src/components/ToggleDarkMode.tsx @@ -0,0 +1,31 @@ +import React, { useEffect, useState } from "react"; +import { ToggleDarkModeContainer } from "../styles/components/ToggleDarkMode"; +import DarkModeToggle from "react-dark-mode-toggle"; +import useAppStore from "../store/store"; + +const ToggleDarkMode: React.FC = () => { + const { backgroundColor, textColor, toggleDarkMode } = useAppStore(); + const [isDarkMode, setIsDarkMode] = useState(backgroundColor === "#121212"); + + useEffect(() => { + setIsDarkMode(backgroundColor === "#121212"); + }, [backgroundColor]); + + const handleChange = () => { + toggleDarkMode(); + setIsDarkMode((prev) => !prev); + }; + + return ( + + + + ); +}; + +export default ToggleDarkMode; \ No newline at end of file diff --git a/src/editors/MarkdownEditor.tsx b/src/editors/MarkdownEditor.tsx index 528db47..26e42ee 100644 --- a/src/editors/MarkdownEditor.tsx +++ b/src/editors/MarkdownEditor.tsx @@ -1,9 +1,10 @@ -import * as monaco from "@monaco-editor/react"; -import { editor } from "monaco-editor"; +import { useEffect } from "react"; +import Editor, { useMonaco } from "@monaco-editor/react"; +import useAppStore from "../store/store"; -const options: editor.IStandaloneEditorConstructionOptions = { +const options = { minimap: { enabled: false }, - wordWrap: "on", + wordWrap: "on" as const, automaticLayout: true, scrollBeyondLastLine: false, }; @@ -15,15 +16,47 @@ export default function MarkdownEditor({ value: string; onChange?: (value: string | undefined) => void; }) { + const monaco = useMonaco(); + const backgroundColor = useAppStore((state) => state.backgroundColor); + const textColor = useAppStore((state) => state.textColor); + + useEffect(() => { + if (monaco) { + monaco.editor.defineTheme("lightTheme", { + base: "vs", + inherit: true, + rules: [], + colors: { + "editor.background": backgroundColor, + "editor.foreground": textColor, + "editor.lineHighlightBorder": "#EDE8DC", + }, + }); + + monaco.editor.defineTheme("darkTheme", { + base: "vs-dark", + inherit: true, + rules: [], + colors: { + "editor.background": backgroundColor, + "editor.foreground": textColor, + "editor.lineHighlightBorder": "#EDE8DC", + }, + }); + monaco.editor.setTheme(backgroundColor ? "darkTheme" : "lightTheme"); + } + }, [monaco, backgroundColor, textColor]); + return (
-
); -} +} \ No newline at end of file diff --git a/src/editors/editorsContainer/AgreementData.tsx b/src/editors/editorsContainer/AgreementData.tsx index ce46e81..b278ff2 100644 --- a/src/editors/editorsContainer/AgreementData.tsx +++ b/src/editors/editorsContainer/AgreementData.tsx @@ -9,6 +9,7 @@ function AgreementData() { (state) => state.setEditorAgreementData ); const setData = useAppStore((state) => state.setData); + const textColor = useAppStore((state) => state.textColor); const debouncedSetData = useCallback( debounce((value: string) => { @@ -27,8 +28,8 @@ function AgreementData() { return (
-

Data

- +

Data

+ JSON data (an instance of the Concerto model) used to preview output from the template. diff --git a/src/editors/editorsContainer/TemplateMarkdown.tsx b/src/editors/editorsContainer/TemplateMarkdown.tsx index e8776f3..830bfdf 100644 --- a/src/editors/editorsContainer/TemplateMarkdown.tsx +++ b/src/editors/editorsContainer/TemplateMarkdown.tsx @@ -7,6 +7,8 @@ function TemplateMarkdown() { const editorValue = useAppStore((state) => state.editorValue); const setEditorValue = useAppStore((state) => state.setEditorValue); const setTemplateMarkdown = useAppStore((state) => state.setTemplateMarkdown); + const backgroundColor = useAppStore((state) => state.backgroundColor); + const textColor = useAppStore((state) => state.textColor); const debouncedSetTemplateMarkdown = useCallback( debounce((value: string) => { @@ -23,9 +25,9 @@ function TemplateMarkdown() { }; return ( -
-

TemplateMark

-

+

+

TemplateMark

+

A natural language template with embedded variables, conditional sections, and TypeScript code.

diff --git a/src/editors/editorsContainer/TemplateModel.tsx b/src/editors/editorsContainer/TemplateModel.tsx index 757f38b..f4a83df 100644 --- a/src/editors/editorsContainer/TemplateModel.tsx +++ b/src/editors/editorsContainer/TemplateModel.tsx @@ -7,6 +7,7 @@ function TemplateModel() { const editorModelCto = useAppStore((state) => state.editorModelCto); const setEditorModelCto = useAppStore((state) => state.setEditorModelCto); const setModelCto = useAppStore((state) => state.setModelCto); + const textColor = useAppStore((state) => state.textColor); const debouncedSetModelCto = useCallback( debounce((value: string) => { @@ -25,8 +26,8 @@ function TemplateModel() { return (
-

Concerto Model

- +

Concerto Model

+ Defines the data model for the template and its logic.
diff --git a/src/store/store.ts b/src/store/store.ts index 3d3038b..3fb5aaa 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -21,6 +21,8 @@ interface AppState { error: string | undefined; samples: Array; sampleName: string; + backgroundColor: string; + textColor: string; setTemplateMarkdown: (template: string) => Promise; setEditorValue: (value: string) => void; setModelCto: (model: string) => Promise; @@ -32,6 +34,7 @@ interface AppState { loadSample: (name: string) => Promise; generateShareableLink: () => string; loadFromLink: (compressedData: string) => Promise; + toggleDarkMode: () => void; } export interface DecompressedData { @@ -69,6 +72,17 @@ const rebuildDeBounce = debounce(rebuild, 500); const useAppStore = create()( immer( devtools((set, get) => ({ + backgroundColor: '#ffffff', + textColor: '#121212', + toggleDarkMode: () => { + set((state) => { + const isDark = state.backgroundColor === '#121212'; + return { + backgroundColor: isDark ? '#ffffff' : '#121212', + textColor: isDark ? '#121212' : '#ffffff', + }; + }); + }, sampleName: playground.NAME, templateMarkdown: playground.TEMPLATE, editorValue: playground.TEMPLATE, diff --git a/src/styles/components/ToggleDarkMode.ts b/src/styles/components/ToggleDarkMode.ts new file mode 100644 index 0000000..fa79f36 --- /dev/null +++ b/src/styles/components/ToggleDarkMode.ts @@ -0,0 +1,9 @@ +import styled from "styled-components"; + +export const ToggleDarkModeContainer = styled.div` +.dark-mode-toggle { + overflow: visible !important; + display: flex; + padding-left: 10px !important; + } +`; \ No newline at end of file From faa04bbfbe86e873b5ade07504df5138207c9c54 Mon Sep 17 00:00:00 2001 From: nitro56565 Date: Fri, 8 Nov 2024 19:51:06 +0530 Subject: [PATCH 2/2] fixed unnecessary properties Signed-off-by: nitro56565 --- src/App.tsx | 2 +- src/components/ToggleDarkMode.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index f7183fd..22d5a39 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { App as AntdApp, Layout, Row, Col, Collapse, theme, Grid } from "antd"; +import { App as AntdApp, Layout, Row, Col, Collapse, Grid } from "antd"; import { Routes, Route, useSearchParams } from "react-router-dom"; import Navbar from "./components/Navbar"; import Footer from "./components/Footer"; diff --git a/src/components/ToggleDarkMode.tsx b/src/components/ToggleDarkMode.tsx index 88e3621..16366fa 100644 --- a/src/components/ToggleDarkMode.tsx +++ b/src/components/ToggleDarkMode.tsx @@ -4,7 +4,7 @@ import DarkModeToggle from "react-dark-mode-toggle"; import useAppStore from "../store/store"; const ToggleDarkMode: React.FC = () => { - const { backgroundColor, textColor, toggleDarkMode } = useAppStore(); + const { backgroundColor, toggleDarkMode } = useAppStore(); const [isDarkMode, setIsDarkMode] = useState(backgroundColor === "#121212"); useEffect(() => {