diff --git a/package.json b/package.json index 82e1b22..3fd9a25 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "markdown-editor", - "version": "1.6.4", + "version": "1.8.0", "description": "A react app to preview and edit Markdown", "private": true, "author": { diff --git a/public/index.html b/public/index.html index bd30521..bcb34d8 100644 --- a/public/index.html +++ b/public/index.html @@ -46,6 +46,8 @@ + + diff --git a/public/styles/dark.css b/public/styles/dark.css new file mode 100644 index 0000000..a51870a --- /dev/null +++ b/public/styles/dark.css @@ -0,0 +1,123 @@ +/** + * okaidia theme for JavaScript, CSS and HTML + * Loosely based on Monokai textmate theme by http://www.monokai.nl/ + * @author ocodia + */ + + code[class*="language-"], + pre[class*="language-"] { + color: #f8f8f2; + background: none; + text-shadow: 0 1px rgba(0, 0, 0, 0.3); + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; + } + + /* Code blocks */ + pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; + border-radius: 0.3em; + } + + :not(pre) > code[class*="language-"], + pre[class*="language-"] { + background: #272822; + } + + /* Inline code */ + :not(pre) > code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; + } + + .token.comment, + .token.prolog, + .token.doctype, + .token.cdata { + color: #8292a2; + } + + .token.punctuation { + color: #f8f8f2; + } + + .token.namespace { + opacity: .7; + } + + .token.property, + .token.tag, + .token.constant, + .token.symbol, + .token.deleted { + color: #f92672; + } + + .token.boolean, + .token.number { + color: #ae81ff; + } + + .token.selector, + .token.attr-name, + .token.string, + .token.char, + .token.builtin, + .token.inserted { + color: #a6e22e; + } + + .token.operator, + .token.entity, + .token.url, + .language-css .token.string, + .style .token.string, + .token.variable { + color: #f8f8f2; + } + + .token.atrule, + .token.attr-value, + .token.function, + .token.class-name { + color: #e6db74; + } + + .token.keyword { + color: #66d9ef; + } + + .token.regex, + .token.important { + color: #fd971f; + } + + .token.important, + .token.bold { + font-weight: bold; + } + .token.italic { + font-style: italic; + } + + .token.entity { + cursor: help; + } + \ No newline at end of file diff --git a/src/styles/github.css b/public/styles/light.css similarity index 93% rename from src/styles/github.css rename to public/styles/light.css index 30040d8..a796816 100644 --- a/src/styles/github.css +++ b/public/styles/light.css @@ -9,11 +9,6 @@ pre { word-spacing: normal; word-break: normal; word-wrap: normal; - line-height: 1.45; - padding: 0.8em; - overflow: auto; - font-size: 0.9em; - border-radius: 6px; background: #f6f8fa; -moz-tab-size: 8; @@ -29,12 +24,8 @@ pre { /* Inline code */ :not(pre) > code { color: inherit; - font-size: 85%; - border-radius: 0.3em; white-space: normal; background: #f5f5f5; - padding: 0.2em 0.4em; - margin: 0; background-color: rgba(27, 31, 35, 0.05); } diff --git a/src/App.scss b/src/App.scss index c94899b..16f9595 100644 --- a/src/App.scss +++ b/src/App.scss @@ -2,18 +2,6 @@ @import url("https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Open+Sans&display=swap"); -//Variable Decelerations -$primary-color: var(--primary-color); -$primary-accent: var(--accent-color); -$primary-text: #24292e; -$text-accent: var(--text-color); -$test:#8d0404; -$white: #fff; -$gray: #eaecef; -$dark-gray: #e1e4e8; -$source-code-font: "Source Code Pro", monospace; -$open-sans-font: "Open Sans", sans-serif; - // General Styling * { box-sizing: border-box; @@ -22,11 +10,30 @@ $open-sans-font: "Open Sans", sans-serif; body { --primary-color: #339989; --accent-color: #7de2d1; - --text-color:#2b2c28; - background-color: $white; + --nav-section-text-color: #2b2c28; + --body-color: #fff; + --nav-item-color: #fff; + --body-accent-color: #e1e4e8; + --alternate-table-color: #eaecef; + --primary-text-color: #24292e; + --link-color: var(--primary-color); + --table-border-color: #ddd; + --source-code-font: "Source Code Pro", monospace; + --open-sans-font: "Open Sans", sans-serif; + --color-transition: 0.5s ease; + background-color: var(--body-color); + transition: background-color var(--color-transition); margin: 0; - color: $primary-text; - font-family: $open-sans-font; + color: var(--primary-text-color); + font-family: var(--open-sans-font); +} + +.dark { + --body-color: #1a1a1d; + --body-accent-color: #202124; + --primary-text-color: #c0c0c0; + --table-border-color: #3b3b3b; + --alternate-table-color: #2b2c2f; } ::-webkit-scrollbar { @@ -39,8 +46,9 @@ body { padding: 0.4rem 1rem; font-weight: 600; border-radius: 0.2rem; - color: $white; - background-color: $primary-color; + color: var(--nav-item-color); + background-color: var(--primary-color); + transition: color, background-color var(--color-transition); border: none; transition: filter 200ms ease; margin: 0 0.5rem; @@ -55,16 +63,19 @@ body { .navbar { margin: 0; - background-color: $primary-color; - color: $white; + background-color: var(--primary-color); + transition: background-color var(--color-transition); + color: var(--nav-item-color); height: 3.75rem; padding-left: 1.5rem; padding-right: 1.5rem; display: flex; align-items: center; justify-content: space-between; - .title { + * { user-select: none; + } + .title { margin: 0; line-height: 30px; display: flex; @@ -83,7 +94,7 @@ body { display: flex; justify-content: center; align-items: center; - margin:0 1rem; + margin: 0 1rem; img { position: static; cursor: pointer; @@ -99,27 +110,26 @@ body { width: 2rem; height: 2rem; border-radius: 50%; - border: 0.18rem solid white; - background-color: $primary-color; + border: 0.15rem solid white; display: flex; - align-items:center; + align-items: center; justify-content: center; - img{ + img { width: 50%; } &:hover { - filter: brightness(1.1); - } + filter: brightness(1.1); + } } .all-theme-wrapper { position: absolute; right: -2.5rem; top: 2.2rem; width: 15.625rem; - height: 18.75rem; - background-color: $primary-color; - border: .1rem solid $primary-accent; - padding: 1rem 1.5rem; + background-color: var(--primary-color); + transition: background-color, border var(--color-transition); + border: 0.1rem solid var(--accent-color); + padding: 1rem 1.5rem 1.5rem; border-radius: 0.6rem; z-index: 999; -webkit-box-shadow: 0px 0px 14px 5px rgba(0, 0, 0, 0.17); @@ -128,7 +138,10 @@ body { h3 { margin: 0.5rem 0 1rem; padding-bottom: 1rem; - border-bottom: 0.1rem solid $primary-accent; + border-bottom: 0.1rem solid var(--accent-color); + } + h4 { + margin-bottom: 0em; } } .theme-btn { @@ -183,10 +196,10 @@ body { padding: 0 1rem; height: 2.5rem; width: 100%; - background-color: $primary-accent; - color: $text-accent; + background-color: var(--accent-color); + transition: background-color var(--color-transition); + color: var(--nav-section-text-color); text-transform: uppercase; - user-select: none; h3 { font-weight: 600; margin: 0; @@ -203,12 +216,14 @@ body { .markdown-edit { width: 100%; textarea { + color: var(--primary-text-color); border: none; - background-color: $white; + background-color: var(--body-color); + transition: background-color var(--color-transition); font-size: 1rem; font-weight: 400; margin-top: 2rem; - font-family: $source-code-font; + font-family: var(--source-code-font); width: 100%; resize: none; height: 100%; @@ -221,7 +236,8 @@ body { .markdown-preview { width: 100%; .html-div { - background-color: $white; + background-color: var(--body-color); + transition: background-color var(--color-transition); margin-top: 2rem; overflow-y: scroll; } @@ -241,7 +257,7 @@ body { line-height: 1.5; } a { - color: $primary-color; + color: var(--link-color); &:hover { filter: brightness(1.2); } @@ -250,24 +266,41 @@ body { border: none; height: 0.187rem; margin: 1.5rem 0; - background-color: $dark-gray; + background-color: var(--body-accent-color); + transition: background-color var(--color-transition); } pre { + transition: background-color var(--color-transition); + line-height: 1.45; + padding: 0.8em; + overflow: auto; + border-radius: 6px; + font-size: 0.9em; padding: 1rem; width: 100%; overflow: auto; margin-top: 0; margin-bottom: 1rem; + *{ + transition: color var(--color-transition); + } + } + :not(pre) > code { + font-size: 85%; + border-radius: 0.3em; + padding: 0.2em 0.4em; + margin: 0; } code { - font-family: $source-code-font; + font-family: var(--source-code-font); } li + li { margin-top: 0.25em; } blockquote { - border-left: .312em solid $dark-gray; + border-left: 0.312em solid var(--body-accent-color); + transition: border-color var(--color-transition); padding-left: 1rem; } img { @@ -277,13 +310,15 @@ body { margin: 1.5rem 0 1rem; line-height: 1.33; padding-bottom: 0.3em; - border-bottom: 1px solid #eaecef; + border-bottom: 1px solid var(--body-accent-color); + transition: border-color var(--color-transition); } h2 { margin: 1.5rem 0 1rem; line-height: 1.33; padding-bottom: 0.3em; - border-bottom: 1px solid #eaecef; + border-bottom: 1px solid var(--body-accent-color); + transition: border-color var(--color-transition); } h3 { margin: 1.5rem 0 1rem; @@ -300,20 +335,26 @@ body { th, td { - border: 0.08rem solid #ddd; + border: 0.08rem solid var(--table-border-color); + transition: border-color var(--color-transition); text-align: left; text-align: center; - padding: .5rem 1.25rem; + padding: 0.5rem 1.25rem; } tr:nth-child(even) { - background-color: $gray; + background-color: var(--alternate-table-color); + transition: background-color var(--color-transition); } th { - background-color: $primary-color; + background-color: var(--primary-color); + transition: background-color var(--color-transition); color: white; } + summary:focus { + outline: none; + } } @media screen and (max-width: 600px) { diff --git a/src/components/DarkCodeToggle.jsx b/src/components/DarkCodeToggle.jsx new file mode 100644 index 0000000..896dc80 --- /dev/null +++ b/src/components/DarkCodeToggle.jsx @@ -0,0 +1,25 @@ +import React, { useEffect } from "react"; +import Switch from "@material-ui/core/Switch"; +import useLocalStorage from "../hooks/useLocalStorage"; + +function DarkCodeToggle() { + const [darkMode, setDarkMode] = useLocalStorage("codeDarkMode", false); + + useEffect(() => { + const styleSheet = `/styles/${darkMode?"dark":"light"}.css` + document.getElementById('code-stylesheet').setAttribute("href", styleSheet); + }, [darkMode]) + + const handleSwitchToggle = (e) => { + setDarkMode(e.target.checked); + }; + + return ( + <> +

Code Dark Mode

+ + + ); +} + +export default DarkCodeToggle; diff --git a/src/components/DarkModeToggle.jsx b/src/components/DarkModeToggle.jsx new file mode 100644 index 0000000..9cc7702 --- /dev/null +++ b/src/components/DarkModeToggle.jsx @@ -0,0 +1,28 @@ +import React, { useEffect } from "react"; +import Switch from "@material-ui/core/Switch"; +import useLocalStorage from "../hooks/useLocalStorage"; + +function DarkModeToggle() { + const [darkMode, setDarkMode] = useLocalStorage("darkMode", false); + + useEffect(() => { + if (darkMode) { + document.body.classList.add("dark"); + } else { + document.body.classList.remove("dark"); + } + }, [darkMode]); + + const handleSwitchToggle = (e) => { + setDarkMode(e.target.checked); + }; + + return ( + <> +

Dark Mode

+ + + ); +} + +export default DarkModeToggle; diff --git a/src/components/MarkdownPreview.jsx b/src/components/MarkdownPreview.jsx index 0600876..2834a44 100644 --- a/src/components/MarkdownPreview.jsx +++ b/src/components/MarkdownPreview.jsx @@ -1,8 +1,8 @@ import React, { useState, useEffect } from "react"; import * as marked from "marked"; import Prism from 'prismjs'; -import '../styles/github.css'; import '../utils/prism-imports'; +//css for Prism is imported in ThemeSelector function MarkdownPreview({ content }) { const [html, setHtml] = useState(getHtml(content)); diff --git a/src/components/ThemeSelector.jsx b/src/components/ThemeSelector.jsx index 3a38dee..d19391e 100644 --- a/src/components/ThemeSelector.jsx +++ b/src/components/ThemeSelector.jsx @@ -1,12 +1,14 @@ import React, { useEffect, useRef } from "react"; import themeData from "../data/theme"; import tickIcon from "../icons/tick.svg"; +import DarkModeToggle from "./DarkModeToggle"; +import DarkCodeToggle from "./DarkCodeToggle"; function ThemeSelector({ isVisible, setVisible, activeTheme, setActiveTheme }) { + const themeSelectorRef = useRef(null); const handleThemeButtonClick = (theme) => { - setVisible(false); setActiveTheme(theme); }; @@ -14,6 +16,7 @@ function ThemeSelector({ isVisible, setVisible, activeTheme, setActiveTheme }) { const hideDropDown = (e) => { if ( themeSelectorRef.current && + !themeSelectorRef.current.parentElement.contains(e.target) && !themeSelectorRef.current.contains(e.target) ) { setVisible(false); @@ -23,7 +26,7 @@ function ThemeSelector({ isVisible, setVisible, activeTheme, setActiveTheme }) { return () => { document.removeEventListener("click", hideDropDown); }; - }, [themeSelectorRef, setVisible]); + }, [themeSelectorRef]); const themeButtons = themeData.map((theme) => { return ( @@ -39,13 +42,17 @@ function ThemeSelector({ isVisible, setVisible, activeTheme, setActiveTheme }) { ); }); - return isVisible ? ( -
+ return ( + +

Change Theme

{themeButtons}
+ +
- ) : ( - <> ); } diff --git a/src/components/ThemeToggle.jsx b/src/components/ThemeToggle.jsx index b0464be..8a5693f 100644 --- a/src/components/ThemeToggle.jsx +++ b/src/components/ThemeToggle.jsx @@ -21,14 +21,12 @@ function ThemeToggle() {
Theme Icon
- {dropDownVisible && ( - )}
); } @@ -36,9 +34,8 @@ function ThemeToggle() { const changeTheme = (theme) => { document.body.style.setProperty("--primary-color", theme.primaryColor); document.body.style.setProperty("--accent-color", theme.accentColor); - if (theme.textColor) { - document.body.style.setProperty("--text-color", theme.textColor); - } + document.body.style.setProperty("--link-color", theme.linkColor ? theme.linkColor : theme.primaryColor); + theme.textColor && document.body.style.setProperty("--nav-section-text-color", theme.textColor); }; export default ThemeToggle; diff --git a/src/data/theme.js b/src/data/theme.js index 785f33b..c2e3a6e 100644 --- a/src/data/theme.js +++ b/src/data/theme.js @@ -9,7 +9,8 @@ const themeData = [ name: "Dessert", primaryColor: "#46211a", accentColor: "#693d3d", - textColor: "#e0e0e0" + textColor: "#eaecef", + linkColor:"#693d3d" }, { name: "Red", primaryColor: "#f44336", @@ -40,7 +41,8 @@ const themeData = [ name: "Github", primaryColor: "#24292E", accentColor: "#3F4448", - textColor: "#CFD0D1" + textColor: "#CFD0D1", + linkColor:"#eaecef" },{ name: "lightGreen", primaryColor: "#4caf50",