Sat, 11 Apr 2020 19:08:37 +0200
HTML Preview and Exporter: added support for dark color schemes.
--- a/eric6/QScintilla/Exporters/ExporterHTML.py Sat Apr 11 14:50:48 2020 +0200 +++ b/eric6/QScintilla/Exporters/ExporterHTML.py Sat Apr 11 19:08:37 2020 +0200 @@ -17,7 +17,7 @@ from PyQt5.QtCore import Qt from PyQt5.QtGui import QCursor, QFontInfo -from PyQt5.QtWidgets import QApplication +from PyQt5.QtWidgets import QApplication, QInputDialog from PyQt5.Qsci import QsciScintilla from E5Gui import E5MessageBox @@ -408,7 +408,25 @@ self.editor.getLanguage().lower() == "markdown" ): # export markdown to HTML - html = self.__generateFromMarkdown() + colorSchemes = [ + self.tr("Light Background Color"), + self.tr("Dark Background Color"), + ] + QApplication.restoreOverrideCursor() + colorScheme, ok = QInputDialog.getItem( + None, + self.tr("Markdown Export"), + self.tr("Select color scheme:"), + colorSchemes, + 0, False) + if ok: + colorSchemeIndex = colorSchemes.index(colorScheme) + else: + # light background as default + colorSchemeIndex = 0 + QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) + QApplication.processEvents() + html = self.__generateFromMarkdown(colorSchemeIndex == 1) elif ( extension in Preferences.getEditor( "PreviewRestFileNameExtensions") or @@ -503,10 +521,13 @@ sys.stderr = origStderr return html - def __generateFromMarkdown(self): + def __generateFromMarkdown(self, useDarkScheme): """ Private method to convert Markdown text into HTML. + @param useDarkScheme flag indicating to export using a dark color + scheme + @type bool @return processed HTML @rtype str """ @@ -534,7 +555,7 @@ mermaidNeeded = False if Preferences.getEditor("PreviewMarkdownMermaid"): - if MarkdownExtensions.MermaidRegex.search(text): + if MarkdownExtensions.MermaidRegexFullText.search(text): extensions.append(MarkdownExtensions.MermaidExtension()) mermaidNeeded = True @@ -592,12 +613,37 @@ " src='https://unpkg.com/mermaid@8/dist/mermaid.min.js'>\n" "</script>\n" ) + if useDarkScheme: + mermaid_initialize = ( + "<script>mermaid.initialize({" + "theme: 'dark', " + "startOnLoad:true" + "});</script>" + ) + else: + mermaid_initialize = ( + "<script>mermaid.initialize({" + "theme: 'default', " + "startOnLoad:true" + "});</script>" + ) else: mermaid = "" + mermaid_initialize = "" htmlFormat = Preferences.getEditor("PreviewMarkdownHTMLFormat").lower() body = markdown.markdown(text, extensions=extensions, output_format=htmlFormat) + if useDarkScheme: + style = ( + PreviewerHTMLStyles.css_markdown_dark + + PreviewerHTMLStyles.css_pygments_dark + ) + else: + style = ( + PreviewerHTMLStyles.css_markdown_light + + PreviewerHTMLStyles.css_pygments_light + ) if htmlFormat == "xhtml1": head = ( @@ -632,12 +678,8 @@ '''</style>\n''' '''</head>\n''' '''<body>\n''' - ).format( - mathjax, mermaid, - PreviewerHTMLStyles.css_markdown + - PreviewerHTMLStyles.css_pygments - ) + ).format(mathjax, mermaid, style) foot = '''\n</body>\n</html>\n''' - return head + body + foot + return head + body + mermaid_initialize + foot
--- a/eric6/UI/Previewers/MarkdownExtensions.py Sat Apr 11 14:50:48 2020 +0200 +++ b/eric6/UI/Previewers/MarkdownExtensions.py Sat Apr 11 19:08:37 2020 +0200 @@ -86,9 +86,6 @@ if is_mermaid: new_lines.append('') - new_lines.append( - '<script>mermaid.initialize({startOnLoad:true});</script>' - ) return new_lines
--- a/eric6/UI/Previewers/PreviewerHTML.py Sat Apr 11 14:50:48 2020 +0200 +++ b/eric6/UI/Previewers/PreviewerHTML.py Sat Apr 11 19:08:37 2020 +0200 @@ -743,12 +743,37 @@ " src='https://unpkg.com/mermaid@8/dist/mermaid.min.js'>\n" "</script>\n" ) + if e5App().usesDarkPalette(): + mermaid_initialize = ( + "<script>mermaid.initialize({" + "theme: 'dark', " + "startOnLoad:true" + "});</script>" + ) + else: + mermaid_initialize = ( + "<script>mermaid.initialize({" + "theme: 'default', " + "startOnLoad:true" + "});</script>" + ) else: mermaid = "" + mermaid_initialize = "" htmlFormat = Preferences.getEditor("PreviewMarkdownHTMLFormat").lower() body = markdown.markdown(text, extensions=extensions, output_format=htmlFormat.lower()) + if e5App().usesDarkPalette(): + style = ( + PreviewerHTMLStyles.css_markdown_dark + + PreviewerHTMLStyles.css_pygments_dark + ) + else: + style = ( + PreviewerHTMLStyles.css_markdown_light + + PreviewerHTMLStyles.css_pygments_light + ) if htmlFormat == "xhtml1": head = ( @@ -777,12 +802,8 @@ '''</style>\n''' '''</head>\n''' '''<body>\n''' - ).format( - mathjax, mermaid, - PreviewerHTMLStyles.css_markdown + - PreviewerHTMLStyles.css_pygments - ) + ).format(mathjax, mermaid, style) foot = '''\n</body>\n</html>\n''' - return head + body + foot + return head + body + mermaid_initialize + foot
--- a/eric6/UI/Previewers/PreviewerHTMLStyles.py Sat Apr 11 14:50:48 2020 +0200 +++ b/eric6/UI/Previewers/PreviewerHTMLStyles.py Sat Apr 11 19:08:37 2020 +0200 @@ -7,33 +7,18 @@ Module implementing CSS styles for the Markdown preview. """ - -css_markdown = """ -@media (prefers-color-scheme: light) { - :root { - --font-color: #000; - --background-color: #fff; - --alt-backgroundcolor: #f8f8f8; - --frame-color: #333; - } -} +########################################################################### +## Styles for light window schemes below +########################################################################### -@media (prefers-color-scheme: dark) { - :root { - --font-color: #fff; - --background-color: #000; - --alt-backgroundcolor: #707070; - --frame-color: #ccc; - } -} - +css_markdown_light = """ html { - background-color: var(--background-color, #fff); + background-color: #ffffff; } body { - background-color: var(--background-color, #fff); - color: var(--font-color, #000); + background-color: #ffffff; + color: #000000; font-family: sans-serif; font-size:12px; line-height:1.7; @@ -85,7 +70,7 @@ h1 .octicon-link, h2 .octicon-link, h3 .octicon-link, h4 .octicon-link, h5 .octicon-link, h6 .octicon-link { display:none; - color: var(--font-color, #000); + color: #000000; } h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, @@ -211,11 +196,11 @@ table tr { border-top:1px solid #ccc; - background-color: var(--background-color, #fff); + background-color: #ffffff; } table tr:nth-child(2n) { - background-color:var(--alt-background-color, #f8f8f8); + background-color:#f8f8f8; } img { @@ -246,7 +231,7 @@ span.frame span span { clear:both; - color:var(--frame-color, #333); + color:#333333; display:block; padding:5px 0 0 } @@ -315,7 +300,7 @@ code, tt { margin:0; border:1px solid #ddd; - background-color:var(--alt-background-color, #f8f8f8); + background-color:#f8f8f8; border-radius:3px; max-width:100%; display:inline-block; @@ -342,7 +327,7 @@ } .highlight pre, pre { - background-color:var(--alt-background-color, #f8f8f8); + background-color:#f8f8f8; border:1px solid #ddd; font-size:12px; line-height:16px; @@ -386,7 +371,7 @@ """ -css_pygments = """ +css_pygments_light = """ pre .hll { background-color: #ffffcc } /* Comment */ @@ -570,3 +555,556 @@ pre .il { color: #009999 } """ + +########################################################################### +## Styles for dark window schemes below +########################################################################### + +css_markdown_dark = """ +html { + background-color: #262626; +} + +body { + background-color: #262626); + color: #ffffff; + font-family: sans-serif; + font-size:12px; + line-height:1.7; + word-wrap:break-word +} + +body>*:first-child { + margin-top:0 !important +} + +body>*:last-child { + margin-bottom:0 !important +} + +a { + color:#8ebfff +} + +a.absent { + color:#dd0000 +} + +a.anchor { + display:block; + padding-right:6px; + padding-left:30px; + margin-left:-30px; + cursor:pointer; + position:absolute; + top:0; + left:0; + bottom:0 +} + +a.anchor:focus { + outline:none +} + +tt, code, pre { + font-family: Consolas, "Liberation Mono", Courier, monospace; + font-size: 12px; +} + +h1, h2, h3, h4, h5, h6 { + margin:1em 0 6px; + padding:0; + font-weight:bold; + line-height:1.7; + cursor:text; + position:relative +} + +h1 .octicon-link, h2 .octicon-link, h3 .octicon-link, h4 .octicon-link, +h5 .octicon-link, h6 .octicon-link { + display:none; + color: #ffffff; +} + +h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, +h5:hover a.anchor, h6:hover a.anchor { + text-decoration:none; + line-height:1; + padding-left:8px; + margin-left:-30px; + top:15% +} + +h1:hover a.anchor .octicon-link, h2:hover a.anchor .octicon-link, +h3:hover a.anchor .octicon-link, h4:hover a.anchor .octicon-link, +h5:hover a.anchor .octicon-link, h6:hover a.anchor .octicon-link { + display:inline-block +} + +h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, +h5 tt, h5 code, h6 tt, h6 code { + font-size:inherit +} + +h1 { + font-size:2em; + border-bottom:1px solid #ddd +} + +h2 { + font-size:1.6em; + border-bottom:1px solid #eee +} + +h3 { + font-size:1.4em +} + +h4 { + font-size:1.2em +} + +h5 { + font-size:1em +} + +h6 { + color:#aaaaaa; + font-size:1em +} + +p, blockquote, ul, ol, dl, table, pre { + margin:8px 0 +} + +hr { + background: rgba(120, 120, 120, 1); + border: 0 none; + color: #ccc; + height: 2px; + padding: 0; + margin: 8px 0; +} + +ul, ol { + padding-left:15px +} + +ul.no-list, ul.task-list, ol.no-list, ol.task-list { + list-style-type:none; +} + +ul ul, ul ol, ol ol, ol ul { + margin-top:0; + margin-bottom:0 +} + + +dl { + padding:0 +} + +dl dt { + font-size:14px; + font-weight:bold; + font-style:italic; + padding:0; + margin-top:8px +} + +dl dd { + margin-bottom:15px; + padding:0 8px +} + +blockquote { + border-left:4px solid #DDD; + padding:0 8px; + color:#aaaaaa +} + +blockquote>:first-child { + margin-top:0px +} + +blockquote>:last-child { + margin-bottom:0px +} + +table { + border-collapse: collapse; + border-spacing: 0; + overflow:auto; + display:block +} + +table th { + font-weight:bold +} + +table th, table td { + border:1px solid #ddd; + padding:3px 3px +} + +table tr { + border-top:1px solid #cccccc; + background-color: #262626; +} + +table tr:nth-child(2n) { + background-color:#404040; +} + +img { + max-width:100%; + -moz-box-sizing:border-box; + box-sizing:border-box +} + +span.frame { + display:block; + overflow:hidden +} + +span.frame>span { + border:1px solid #464646; + display:block; + float:left; + overflow:hidden; + margin:6px 0 0; + padding:7px; + width:auto +} + +span.frame span img { + display:block; + float:left +} + +span.frame span span { + clear:both; + color:#565656; + display:block; + padding:5px 0 0 +} + +span.align-center { + display:block; + overflow:hidden; + clear:both +} + +span.align-center>span { + display:block; + overflow:hidden; + margin:6px auto 0; + text-align:center +} + +span.align-center span img { + margin:0 auto; + text-align:center +} + +span.align-right { + display:block; + overflow:hidden; + clear:both +} + +span.align-right>span { + display:block; + overflow:hidden; + margin:6px 0 0; + text-align:right +} + +span.align-right span img { + margin:0; + text-align:right +} + +span.float-left { + display:block; + margin-right:6px; + overflow:hidden; + float:left +} + +span.float-left span { + margin:6px 0 0 +} + +span.float-right { + display:block; + margin-left:6px; + overflow:hidden; + float:right +} + +span.float-right>span { + display:block; + overflow:hidden; + margin:6px auto 0; + text-align:right +} + +code, tt { + margin:0; + border:1px solid #ddd; + background-color:#404040; + border-radius:3px; + max-width:100%; + display:inline-block; + overflow:auto; + vertical-align:middle; + line-height:1.1; + padding:0 +} + +code:before, code:after, tt:before, tt:after { + content:"\00a0" +} + +code { + white-space:nowrap +} + +pre>code { + margin:0; + padding:0; + white-space:pre; + border:none; + background:transparent +} + +.highlight pre, pre { + background-color:#404040; + border:1px solid #ddd; + font-size:12px; + line-height:16px; + overflow:auto; + padding:6px 6px; + border-radius:3px +} + +pre { + word-wrap:normal +} + +pre code, pre tt { + margin:0; + padding:0; + background-color:transparent; + border:none; + word-wrap:normal; + max-width:initial; + display:inline; + overflow:initial; + line-height:inherit +} + +pre code:before, pre code:after, pre tt:before, pre tt:after { + content:normal +} + +kbd { + border:1px solid gray; + font-size:1.2em; + box-shadow:1px 0 1px 0 #eee, 0 1px 0 1px #ccc, 0 2px 0 2px #444; + -webkit-border-radius:2px; + -moz-border-radius:2px; + border-radius:2px; + margin:2px 3px; + padding:1px 5px; + color: #000; + background-color: #fff +} +""" + + +css_pygments_dark = """ +pre .hll { background-color: #464646 } + +/* Comment */ +pre .c { color: #74cc66; font-style: italic } + +/* Error */ +pre .err { color: #a61717; background-color: #e3d2d2 } + +/* Keyword */ +pre .k { font-weight: bold } + +/* Operator */ +pre .o { font-weight: bold } + +/* Comment.Multiline */ +pre .cm { color: #74cc66; font-style: italic } + +/* Comment.Preproc */ +pre .cp { color: #74cc66; font-weight: bold; font-style: italic } + +/* Comment.Single */ +pre .c1 { color: #74cc66; font-style: italic } + +/* Comment.Special */ +pre .cs { color: #74cc66; font-weight: bold; font-style: italic } + +/* Generic.Deleted */ +pre .gd { color: #ffffff; background-color: #843d3d } + +/* Generic.Emph */ +pre .ge { font-style: italic } + +/* Generic.Error */ +pre .gr { color: #ff0000 } + +/* Generic.Heading */ +pre .gh { color: #dadada } + +/* Generic.Inserted */ +pre .gi { color: #ffffff; background-color: #4e8750 } + +/* Generic.Output */ +pre .go { color: #bbbbbb } + +/* Generic.Prompt */ +pre .gp { color: #999999 } + +/* Generic.Strong */ +pre .gs { font-weight: bold } + +/* Generic.Subheading */ +pre .gu { color: #dd60dd } + +/* Generic.Traceback */ +pre .gt { color: #ff0000 } + +/* Keyword.Constant */ +pre .kc { font-weight: bold } + +/* Keyword.Declaration */ +pre .kd { font-weight: bold } + +/* Keyword.Namespace */ +pre .kn { font-weight: bold } + +/* Keyword.Pseudo */ +pre .kp { font-weight: bold } + +/* Keyword.Reserved */ +pre .kr { font-weight: bold } + +/* Keyword.Type */ +pre .kt { color: #b3efad; font-weight: bold } + +/* Literal.Number */ +pre .m { color: #00c8c8 } + +/* Literal.String */ +pre .s { color: #f46b6b } + +/* Name.Attribute */ +pre .na { color: #b6d13b } + +/* Name.Builtin */ +pre .nb { color: #b3efad } + +/* Name.Class */ +pre .nc { color: #00aaff; font-weight: bold } + +/* Name.Constant */ +pre .no { color: #dd3131 } + +/* Name.Decorator */ +pre .nd { color: #e19bff; font-weight: bold } + +/* Name.Entity */ +pre .ni { color: #dedede } + +/* Name.Exception */ +pre .ne { color: #e75555; font-weight: bold } + +/* Name.Function */ +pre .nf { color: #00aaff; font-weight: bold } + +/* Name.Label */ +pre .nl { color: #e1e100; font-weight: bold } + +/* Name.Namespace */ +pre .nn { color: #00aaff } + +/* Name.Tag */ +pre .nt { color: #b3efad } + +/* Name.Variable */ +pre .nv { color: #00aaff } + +/* Operator.Word */ +pre .ow { font-weight: bold } + +/* Text.Whitespace */ +pre .w { color: #bbbbbb } + +/* Literal.Number.Float */ +pre .mf { color: #00aaff } + +/* Literal.Number.Hex */ +pre .mh { color: #00aaff } + +/* Literal.Number.Integer */ +pre .mi { color: #00aaff } + +/* Literal.Number.Oct */ +pre .mo { color: #00aaff } + +/* Literal.String.Backtick */ +pre .sb { color: #f46b6b } + +/* Literal.String.Char */ +pre .sc { color: #f46b6b } + +/* Literal.String.Doc */ +pre .sd { color: #f46b6b } + +/* Literal.String.Double */ +pre .s2 { color: #f46b6b } + +/* Literal.String.Escape */ +pre .se { color: #f46b6b } + +/* Literal.String.Heredoc */ +pre .sh { color: #f46b6b } + +/* Literal.String.Interpol */ +pre .si { color: #f46b6b } + +/* Literal.String.Other */ +pre .sx { color: #f46b6b } + +/* Literal.String.Regex */ +pre .sr { color: #bb6688 } + +/* Literal.String.Single */ +pre .s1 { color: #f46b6b } + +/* Literal.String.Symbol */ +pre .ss { color: #00aaff } + +/* Name.Builtin.Pseudo */ +pre .bp { color: #b3efad } + +/* Name.Variable.Class */ +pre .vc { color: #00aaff } + +/* Name.Variable.Global */ +pre .vg { color: #00aaff } + +/* Name.Variable.Instance */ +pre .vi { color: #00aaff } + +/* Literal.Number.Integer.Long */ +pre .il { color: #00c8c8 } + +"""