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
23 changes: 23 additions & 0 deletions package-lock.json

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

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
"dompurify": "^3.2.7",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"github-markdown-css": "^5.9.0",
"highlight.js": "^11.11.1",
"jose": "^5.9.3",
"katex": "^0.16.22",
"lucide-react": "^0.546.0",
Expand Down
17 changes: 16 additions & 1 deletion src/lib/render-markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { TokenizerAndRendererExtension } from 'marked';
import DOMPurify from 'dompurify';
import katex from 'katex';
import 'katex/dist/katex.min.css';
import hljs from 'highlight.js';

export type { MarkdownRenderMode };
export { renderMarkdown };
Expand Down Expand Up @@ -123,6 +124,8 @@ function configureMarkedOnce() {
},
tokenizer(src) {
if (src[0] !== '$' || src[1] === '$') return undefined;
// Don't match currency: $ followed by a digit or comma (e.g. $1,200)
if (src[1] !== undefined && /[\d,]/.test(src[1])) return undefined;
let index = 1;
let closing = -1;
while (index < src.length) {
Expand Down Expand Up @@ -159,7 +162,19 @@ function configureMarkedOnce() {
}
},
};
marked.use({ extensions: [blockMathExtension, inlineMathExtension] });
// Syntax-highlight fenced code blocks using highlight.js.
// Falls back to plain text for unknown languages.
const codeRenderer = {
code(code: string, infostring: string | undefined): string {
let lang = (infostring ?? '').split(/\s/)[0] ?? '';
let valid = lang !== '' && hljs.getLanguage(lang) !== undefined;
let highlighted = (valid && lang !== '')
? hljs.highlight(code, { language: lang as string }).value
: hljs.highlightAuto(code).value;
return `<pre><code class="hljs${valid ? ` language-${lang}` : ''}">${highlighted}</code></pre>\n`;
},
};
marked.use({ extensions: [blockMathExtension, inlineMathExtension], renderer: codeRenderer });
markedConfigured = true;
}

Expand Down
2 changes: 2 additions & 0 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from 'react';
import { createRoot } from 'react-dom/client';
import { App } from './App';
import './styles.css';
import 'github-markdown-css/github-markdown-light.css';
import 'highlight.js/styles/github.css';

const root = createRoot(document.getElementById('root')!);
root.render(<App />);
Expand Down
4 changes: 3 additions & 1 deletion src/share/ShareApp.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Public share viewer entry that resolves the share ref and renders the note.
import React, { useEffect, useMemo, useState } from 'react';
import { renderMarkdown } from '../lib/render-markdown';
import 'github-markdown-css/github-markdown-light.css';
import 'highlight.js/styles/github.css';
import { fetchShareContent, fetchShareMeta, buildAssetUrl, parseShareUrl, type ShareRef, type ShareMetaResponse } from './api';

type ViewerState =
Expand Down Expand Up @@ -121,7 +123,7 @@ export function ShareApp() {
</a>
</p>
</header>
<div className="share-content" dangerouslySetInnerHTML={{ __html: renderedHtml }} />
<div className="share-content markdown-body" dangerouslySetInnerHTML={{ __html: renderedHtml }} />
</article>
</main>
</div>
Expand Down
50 changes: 11 additions & 39 deletions src/share/share.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
body {
margin: 0;
font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: #f6f8fa;
background: #ffffff;
color: #0f172a;
}

Expand Down Expand Up @@ -39,23 +39,18 @@ body {

.share-main {
flex: 1;
padding: clamp(16px, 5vw, 32px);
padding: clamp(24px, 5vw, 48px) clamp(16px, 8vw, 56px);
display: flex;
justify-content: center;
align-items: flex-start;
}

.share-article {
max-width: clamp(720px, 70vw, 960px);
max-width: 861px;
width: 100%;
background: #ffffff;
border: 1px solid #d0d7de;
border-radius: 20px;
padding: clamp(20px, 3.5vw, 32px);
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.08);
display: flex;
flex-direction: column;
gap: clamp(20px, 4vw, 32px);
gap: 24px;
}

.share-article-header {
Expand Down Expand Up @@ -89,40 +84,17 @@ body {
display: block;
}

.share-article img {
max-width: 100%;
display: block;
margin: 16px auto;
border-radius: 12px;
}

.share-article a {
color: #0969da;
text-decoration: none;
}

.share-article a:hover {
text-decoration: underline;
/* Fit github-markdown-css inside our card — neutralise its own box model */
.share-content.markdown-body {
background: transparent;
font-family: inherit;
font-size: 1rem;
color: inherit;
}

@media (max-width: 600px) {
.share-main {
padding: 0;
justify-content: flex-start;
align-items: stretch;
}

.share-article {
max-width: none;
border-radius: 0;
border: none;
box-shadow: none;
min-height: 100vh;
box-sizing: border-box;
}

.share-content {
flex: 1;
padding: 16px;
}
}

Expand Down
51 changes: 6 additions & 45 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -878,53 +878,14 @@ textarea:focus-visible {

.workspace-panels .preview {
overflow: auto;
line-height: 1.68;
color: var(--text);
}

.workspace-panels .preview h1,
.workspace-panels .preview h2,
.workspace-panels .preview h3,
.workspace-panels .preview h4 {
margin-top: 1.5em;
margin-bottom: 0.75em;
line-height: 1.25;
}

.workspace-panels .preview h1 {
font-size: 2rem;
}

.workspace-panels .preview h2 {
font-size: 1.6rem;
}

.workspace-panels .preview h3 {
font-size: 1.3rem;
}

.workspace-panels .preview p {
margin: 0 0 1em;
}

.workspace-panels .preview pre {
background: var(--surface-subtle);
border-radius: 10px;
padding: 12px;
border: 1px solid var(--border);
overflow: auto;
}

.workspace-panels .preview code {
font: var(--code-font);
}

.workspace-panels .preview blockquote {
border-left: 4px solid var(--accent-border);
margin: 0 0 1em;
padding: 0.2em 1em;
background: rgba(9, 105, 218, 0.08);
border-radius: 0 8px 8px 0;
/* github-markdown-css provides all content styles; override only the
properties that would conflict with the card layout. */
.workspace-panels .preview.markdown-body {
font-family: inherit;
font-size: 1rem;
color: inherit;
}

.empty-state {
Expand Down
2 changes: 1 addition & 1 deletion src/ui/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export function Editor({ doc, onChange, readOnly = false, slug, loadAsset, onImp
)}
<div
ref={previewRef}
className={`preview${readOnly ? ' preview-only' : ''}`}
className={`preview markdown-body${readOnly ? ' preview-only' : ''}`}
dangerouslySetInnerHTML={{ __html: html }}
/>
</>
Expand Down