Skip to content
Open
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
Binary file added .DS_Store
Binary file not shown.
Binary file added dist/.DS_Store
Binary file not shown.
555 changes: 349 additions & 206 deletions dist/EnhanceCodeBlocks.plugin.js

Large diffs are not rendered by default.

2,296 changes: 2,296 additions & 0 deletions dist/EnhanceCodeBlocksnew.plugin.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion src/codeblock/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Tooltip, Icon, Popout } from "../components";
import ChangeLang from "./changeLang";
import { formatBytes, message } from "../util";

function Header({ angle, collapsed, setCollapsed, languageName, isSVG, showPreview, setShowPreview, copied, downloadAction, copyAction, enlargeAction, modal, setLang, remove, bytes, loading }: { angle: SpringValue<number>, collapsed: boolean, setCollapsed: (v: boolean) => void, languageName: string, isSVG: boolean, showPreview: boolean, setShowPreview: (v: boolean) => void, copied: boolean, downloadAction: () => void, copyAction: () => void, enlargeAction: () => void, modal: boolean, setLang: (lang: string) => void, remove?: (() => void) | false, bytes: number, loading?: boolean }) {
function Header({ angle, collapsed, setCollapsed, languageName, isSVG, isMarkdown, markdownViewMode, setMarkdownViewMode, showPreview, setShowPreview, copied, downloadAction, copyAction, enlargeAction, modal, setLang, remove, bytes, loading }: { angle: SpringValue<number>, collapsed: boolean, setCollapsed: (v: boolean) => void, languageName: string, isSVG: boolean, isMarkdown?: boolean, markdownViewMode?: string, setMarkdownViewMode?: (v: string) => void, showPreview: boolean, setShowPreview: (v: boolean) => void, copied: boolean, downloadAction: () => void, copyAction: () => void, enlargeAction: () => void, modal: boolean, setLang: (lang: string) => void, remove?: (() => void) | false, bytes: number, loading?: boolean }) {
const [ shouldShow, setShouldShow ] = React.useState(false);

const targetElementRef = React.useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -79,6 +79,15 @@ function Header({ angle, collapsed, setCollapsed, languageName, isSVG, showPrevi
)}
</Tooltip>
)}
{isMarkdown && (
<Tooltip text={markdownViewMode === "rendered" ? "View Code" : "View Rendered"} hideOnClick={false}>
{(props) => (
<div className={`ECBlock-markdownButton${markdownViewMode === "rendered" ? " ECBlock-active" : ""}`} {...props} onClick={() => setMarkdownViewMode?.(markdownViewMode === "rendered" ? "raw" : "rendered")}>
<Icon size={22} name={markdownViewMode === "rendered" ? "copy" : "eye"} />
</div>
)}
</Tooltip>
)}
<Tooltip text={message("1WjMbC" || "DOWNLOAD")} hideOnClick={false}>
{(props) => (
<div className="ECBlock-downloadButton" {...props} onClick={downloadAction}>
Expand Down
41 changes: 25 additions & 16 deletions src/codeblock/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useLanguage, useHighlighted, useSizing, useStateDeps, useSrc } from "..
import Header from "./header";
import Table from "./table";
import Preview from "./preview";
import MarkdownRenderer from "./markdown";
import { ModalRoot, Spinner } from "../components";
import { useData } from "../data";
import { debounce } from "../util";
Expand Down Expand Up @@ -36,14 +37,18 @@ function CodeBlock({ content, lang, modal, fileName, loading = false, remove }:
const highlighted = useHighlighted(language, _lang, content);

const [ showPreview, setShowPreview ] = useState(false);
const [ previewHeight ] = useData("previewHeight", 200);
const [ previewHeight ] = useData("previewHeight", 200);
const [ markdownViewMode, setMarkdownViewMode ] = useData("markdownViewMode", "raw");

const { height, angle } = useSizing(collapsed, tableRef, modal, content, lang, showPreview);

const src = useSrc(content);

// Original language must be SVG and the language name must be the html like
const isSVG = useMemo(() => lang === "svg" && language.name === "HTML, XML" && Boolean(src), [ lang, language, src ]);

// Check if this is a markdown file
const isMarkdown = useMemo(() => ["md", "markdown", "mdx"].includes(lang.toLowerCase()), [ lang ]);

const downloadAction = useCallback(() => {
if (loading) return;
Expand Down Expand Up @@ -76,27 +81,31 @@ function CodeBlock({ content, lang, modal, fileName, loading = false, remove }:
<div
className={`ECBlock${wrapText ? " ECBlock-wrap" : ""}${collapsed ? " ECBlock-collapsed" : ""}${modal ? " ECBlock-modal" : ""}${loading ? " ECBlock-loading" : ""}`}
data-language={language.name}>
<Header
angle={angle}
collapsed={collapsed}
setCollapsed={setCollapsed}
languageName={`${isSVG ? "SVG, " : ""}${language.name}`}
isSVG={isSVG}
showPreview={showPreview}
setShowPreview={setShowPreview}
copied={copied}
downloadAction={downloadAction}
copyAction={copyAction}
enlargeAction={enlargeAction}
modal={modal}
setLang={setLang}
<Header
angle={angle}
collapsed={collapsed}
setCollapsed={setCollapsed}
languageName={`${isSVG ? "SVG, " : ""}${language.name}`}
isSVG={isSVG}
isMarkdown={isMarkdown}
markdownViewMode={markdownViewMode}
setMarkdownViewMode={setMarkdownViewMode}
showPreview={showPreview}
setShowPreview={setShowPreview}
copied={copied}
downloadAction={downloadAction}
copyAction={copyAction}
enlargeAction={enlargeAction}
modal={modal}
setLang={setLang}
remove={remove}
bytes={byteSize}
loading={loading} />
<ReactSpring.animated.div className={`ECBlock-wrapper ${thin}`} style={{ height }}>
{loading && <Spinner type={Spinner.Type.WANDERING_CUBES} />}
{(!loading && showPreview && isSVG) && <Preview src={src as string} height={modal ? 400 : previewHeight} />}
{(!loading && !(showPreview && isSVG)) && <Table highlighted={highlighted} tableRef={tableRef} language={language} />}
{(!loading && !(showPreview && isSVG) && isMarkdown && markdownViewMode === "rendered") && <MarkdownRenderer content={content} />}
{(!loading && !(showPreview && isSVG) && !(isMarkdown && markdownViewMode === "rendered")) && <Table highlighted={highlighted} tableRef={tableRef} language={language} />}
</ReactSpring.animated.div>
</div>
)
Expand Down
64 changes: 64 additions & 0 deletions src/codeblock/markdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/// <reference path="../index.d.ts" />
import React from "react";

function MarkdownRenderer({ content }: { content: string }) {
const marked = window.marked || (() => {
// Inline fallback markdown parser
return (text: string) => {
// Basic markdown parsing logic
let html = text
.replace(/^#### (.*$)/gim, "<h4>$1</h4>")
.replace(/^### (.*$)/gim, "<h3>$1</h3>")
.replace(/^## (.*$)/gim, "<h2>$1</h2>")
.replace(/^# (.*$)/gim, "<h1>$1</h1>")
.replace(/\*\*\*(.*?)\*\*\*/gim, "<strong><em>$1</em></strong>")
.replace(/\*\*(.*?)\*\*/gim, "<strong>$1</strong>")
.replace(/\*(.*?)\*/gim, "<em>$1</em>")
.replace(/~~(.*?)~~/gim, "<del>$1</del>")
.replace(/`(.*?)`/gim, "<code>$1</code>")
.replace(/\n/gim, "<br>");

// Handle blockquotes
html = html.replace(/^> (.*$)/gim, "<blockquote>$1</blockquote>");

// Handle task lists
html = html.replace(/^\- \[x\] (.*$)/gim, '<li class="task-list-item"><input type="checkbox" checked disabled> $1</li>');
html = html.replace(/^\- \[ \] (.*$)/gim, '<li class="task-list-item"><input type="checkbox" disabled> $1</li>');

// Handle unordered lists
html = html.replace(/^\- (.*$)/gim, "<li>$1</li>");

// Handle ordered lists
html = html.replace(/^\d+\. (.*$)/gim, "<li>$1</li>");

// Handle horizontal rules
html = html.replace(/^---$/gim, "<hr>");
html = html.replace(/^\*\*\*$/gim, "<hr>");

// Handle links
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/gim, '<a href="$2" target="_blank">$1</a>');

// Handle images
html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/gim, '<img src="$2" alt="$1">');

// Handle code blocks
html = html.replace(/```([\s\S]*?)```/gim, "<pre><code>$1</code></pre>");

// Wrap consecutive list items
html = html.replace(/(<li[^>]*>.*?<\/li>\n?)+/gim, "<ul>$&</ul>");

return html;
};
})();

const html = marked(content);

return (
<div
className="ECBlock-markdown"
dangerouslySetInnerHTML={{ __html: html }}
/>
);
}

export default React.memo(MarkdownRenderer);
5 changes: 3 additions & 2 deletions src/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ type settings = {
previewHeight: number,
maxBytes: number,
maxFileBytes: number,
instantCollapse: boolean
wrapText: boolean
instantCollapse: boolean,
wrapText: boolean,
markdownViewMode: "raw" | "rendered"
};

const listeners = new Map<string, Set<() => void>>();
Expand Down
15 changes: 15 additions & 0 deletions src/settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function Settings() {
const [ maxBytes, setBytes ] = useData("maxBytes", 21_846);
const [ maxFileBytes, setFileBytes ] = useData("maxFileBytes", 200_000_000);
const [ wrapText, setWrapText ] = useData("wrapText", false);
const [ markdownViewMode, setMarkdownViewMode ] = useData("markdownViewMode", "raw");

const [ open, setOpen ] = useState(false);

Expand Down Expand Up @@ -110,6 +111,20 @@ function Settings() {
value={wrapText}
onChange={setWrapText}
>Wrap Text</Switch>
<SettingItem
item={
<div className="ECBlock-selectSetting">
<select
value={markdownViewMode}
onChange={(e) => setMarkdownViewMode(e.target.value as "raw" | "rendered")}
>
<option value="raw">Raw</option>
<option value="rendered">Rendered</option>
</select>
</div>
}
note="Choose how markdown files (.md, .markdown, .mdx) display by default"
title="Markdown View Mode" />
</div>
)
};
Expand Down
102 changes: 102 additions & 0 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
.ECBlock-file .ECBlock {
/* so they wont be small */
width: 100vw;
max-width: 66rem;
}
.ECBlock.ECBlock-loading .ECBlock-wrapper {
display: flex;
Expand Down Expand Up @@ -133,6 +134,7 @@
}
.ECBlock .ECBlock-wrapper {
overflow: auto scroll;
user-select: text;
}
.ECBlock .ECBlock-table {
font-size: 0.9em;
Expand Down Expand Up @@ -182,4 +184,104 @@
}
.ECBlock-zIndex-hook {
z-index: 1;
}
.ECBlock-selectSetting select {
padding: 8px;
border-radius: 4px;
border: 1px solid var(--background-tertiary);
background: var(--background-secondary);
color: var(--text-normal);
}
.ECBlock-markdown {
background: var(--background-secondary-alt);
padding: 16px;
color: var(--text-normal);
line-height: 1.6;
}
.ECBlock-markdown h1,
.ECBlock-markdown h2,
.ECBlock-markdown h3,
.ECBlock-markdown h4,
.ECBlock-markdown h5,
.ECBlock-markdown h6 {
margin-top: 1em;
margin-bottom: 0.5em;
font-weight: 600;
color: var(--text-normal);
}
.ECBlock-markdown h1 { font-size: 2em; border-bottom: 1px solid var(--background-tertiary); padding-bottom: 0.3em; }
.ECBlock-markdown h2 { font-size: 1.5em; border-bottom: 1px solid var(--background-tertiary); padding-bottom: 0.3em; }
.ECBlock-markdown h3 { font-size: 1.25em; }
.ECBlock-markdown h4 { font-size: 1em; }
.ECBlock-markdown h5 { font-size: 0.875em; }
.ECBlock-markdown h6 { font-size: 0.85em; color: var(--text-muted); }
.ECBlock-markdown p {
margin-bottom: 1em;
}
.ECBlock-markdown code {
background: var(--background-tertiary);
padding: 2px 6px;
border-radius: 4px;
font-family: var(--font-code);
font-size: 0.9em;
}
.ECBlock-markdown pre {
background: var(--background-tertiary);
padding: 12px;
border-radius: 4px;
overflow-x: auto;
margin-bottom: 1em;
}
.ECBlock-markdown pre code {
background: transparent;
padding: 0;
}
.ECBlock-markdown blockquote {
border-left: 4px solid var(--background-tertiary);
padding-left: 1em;
margin-left: 0;
color: var(--text-muted);
}
.ECBlock-markdown a {
color: var(--text-link);
text-decoration: none;
}
.ECBlock-markdown a:hover {
text-decoration: underline;
}
.ECBlock-markdown ul,
.ECBlock-markdown ol {
margin-bottom: 1em;
padding-left: 2em;
}
.ECBlock-markdown li {
margin-bottom: 0.25em;
}
.ECBlock-markdown table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1em;
}
.ECBlock-markdown table th,
.ECBlock-markdown table td {
border: 1px solid var(--background-tertiary);
padding: 8px;
}
.ECBlock-markdown table th {
background: var(--background-secondary);
}
.ECBlock-markdown img {
max-width: 100%;
border-radius: 4px;
}
.ECBlock-markdown hr {
border: none;
border-top: 1px solid var(--background-tertiary);
margin: 1em 0;
}
.ECBlock-markdown input[type="checkbox"] {
margin-right: 8px;
}
.ECBlock-markdown li.task-list-item {
list-style-type: none;
}