mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-31 21:52:54 +00:00
fix(markdown): derive table and task list colours from the theme
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { darkTheme, lightTheme } from "@/styles/theme";
|
||||
import { createMarkdownStyles } from "./styles";
|
||||
import { prepareMarkdownSource } from "./source";
|
||||
|
||||
describe("shared Markdown source adaptation", () => {
|
||||
@@ -139,3 +141,57 @@ it.each(['""', "''", "()"])("preserves an authored empty link title: %s", (title
|
||||
const source = `[Open](/repo/file.ts ${title})`;
|
||||
expect(prepareMarkdownSource(source, "/repo").render()).toBe(source);
|
||||
});
|
||||
|
||||
describe("shared Markdown theme colours", () => {
|
||||
it.each([
|
||||
["dark", darkTheme],
|
||||
["light", lightTheme],
|
||||
] as const)("uses %s theme colours for tables and task labels", (_name, theme) => {
|
||||
const { markdownStyle: style } = createMarkdownStyles(theme);
|
||||
expect(style.table).toMatchObject({
|
||||
color: theme.colors.foreground,
|
||||
headerTextColor: theme.colors.foreground,
|
||||
headerBackgroundColor: theme.colors.surface2,
|
||||
rowEvenBackgroundColor: theme.colors.surface0,
|
||||
rowOddBackgroundColor: theme.colors.surface1,
|
||||
borderColor: theme.colors.border,
|
||||
});
|
||||
expect(style.list?.color).toBe(theme.colors.foreground);
|
||||
expect(style.taskList).toMatchObject({
|
||||
checkedTextColor: theme.colors.foregroundMuted,
|
||||
checkedColor: theme.colors.accent,
|
||||
checkmarkColor: theme.colors.accentForeground,
|
||||
borderColor: theme.colors.foregroundMuted,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
["dark", darkTheme],
|
||||
["light", lightTheme],
|
||||
] as const)(
|
||||
"uses %s theme colours for quotes, admonitions, code, links and dividers",
|
||||
(_name, theme) => {
|
||||
const { markdownStyle: style } = createMarkdownStyles(theme);
|
||||
expect(style.blockquote).toMatchObject({
|
||||
color: theme.colors.foregroundMuted,
|
||||
backgroundColor: theme.colors.surface2,
|
||||
borderColor: theme.colors.border,
|
||||
admonitions: {
|
||||
note: { color: theme.colors.accentBright, backgroundColor: theme.colors.surface2 },
|
||||
tip: { color: theme.colors.statusSuccess, backgroundColor: theme.colors.surface2 },
|
||||
important: { color: theme.colors.statusMerged, backgroundColor: theme.colors.surface2 },
|
||||
warning: { color: theme.colors.statusWarning, backgroundColor: theme.colors.surface2 },
|
||||
caution: { color: theme.colors.statusDanger, backgroundColor: theme.colors.surface2 },
|
||||
},
|
||||
});
|
||||
expect(style.code).toMatchObject({
|
||||
color: theme.colors.foreground,
|
||||
backgroundColor: theme.colors.surface2,
|
||||
borderColor: "transparent",
|
||||
});
|
||||
expect(style.link?.color).toBe(theme.colors.accent);
|
||||
expect(style.linkVariants?.["^(?!https?://).+"]?.color).toBe(theme.colors.accent);
|
||||
expect(style.thematicBreak?.color).toBe(theme.colors.border);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -3,7 +3,6 @@ import { markdownCopyImageSourcesDataSet } from "@/assistant-selection-copy/mark
|
||||
import { memo, useMemo, useState } from "react";
|
||||
import {
|
||||
EnrichedMarkdownText,
|
||||
type MarkdownStyle,
|
||||
type LinkPressEvent,
|
||||
type CodeBlockRendererProps,
|
||||
} from "react-native-enriched-markdown";
|
||||
@@ -17,6 +16,7 @@ import { HighlightedCodeBlock } from "@/components/highlighted-code-block";
|
||||
import { AttachmentLightbox, type ImageLightboxSource } from "@/components/attachment-lightbox";
|
||||
import type { Theme } from "@/styles/theme";
|
||||
import { isWeb } from "@/constants/platform";
|
||||
import { createMarkdownStyles } from "./styles";
|
||||
import { useMarkdownSource, type MarkdownImageContext } from "./images";
|
||||
|
||||
import { MermaidFence, MermaidStreamingContext, splitMermaidFences } from "./fence/mermaid";
|
||||
@@ -24,84 +24,8 @@ import { MermaidFence, MermaidStreamingContext, splitMermaidFences } from "./fen
|
||||
const ThemedMarkdown = withUnistyles(EnrichedMarkdownText);
|
||||
const MD4C_FLAGS = { latexMath: false, hardSoftBreaks: true, admonitions: true };
|
||||
|
||||
function markdownStyle(theme: Theme, compact = false): { markdownStyle: MarkdownStyle } {
|
||||
const fontSize = compact ? theme.fontSize.base : theme.fontSize.content;
|
||||
const paragraph = {
|
||||
fontSize,
|
||||
fontFamily: theme.fontFamily.ui,
|
||||
lineHeight: Math.round(fontSize * 1.4),
|
||||
color: theme.colors.foreground,
|
||||
marginTop: 0,
|
||||
marginBottom: theme.spacing[3],
|
||||
};
|
||||
const heading = (scale: number) => ({
|
||||
...paragraph,
|
||||
fontSize: Math.round(fontSize * scale),
|
||||
lineHeight: Math.round(fontSize * scale * 1.3),
|
||||
fontWeight: "bold",
|
||||
marginTop: theme.spacing[3],
|
||||
});
|
||||
return {
|
||||
markdownStyle: {
|
||||
paragraph,
|
||||
h1: heading(1.6),
|
||||
h2: heading(1.4),
|
||||
h3: heading(1.2),
|
||||
h4: heading(1.1),
|
||||
h5: heading(1),
|
||||
h6: heading(1),
|
||||
list: {
|
||||
...paragraph,
|
||||
bulletColor: theme.colors.foreground,
|
||||
markerColor: theme.colors.foregroundMuted,
|
||||
gapWidth: 7,
|
||||
itemSpacing: 4,
|
||||
marginLeft: 20,
|
||||
},
|
||||
blockquote: {
|
||||
...paragraph,
|
||||
color: theme.colors.foregroundMuted,
|
||||
backgroundColor: theme.colors.surface2,
|
||||
borderColor: theme.colors.border,
|
||||
borderWidth: 3,
|
||||
padding: 12,
|
||||
gapWidth: 8,
|
||||
},
|
||||
link: { color: theme.colors.accent, underline: false },
|
||||
linkVariants: {
|
||||
"^(?!https?://).+": {
|
||||
color: theme.colors.accent,
|
||||
pill: { borderRadius: 4, paddingHorizontal: 3 },
|
||||
},
|
||||
},
|
||||
code: {
|
||||
fontFamily: theme.fontFamily.mono === "ui-monospace" && !isWeb ? "" : theme.fontFamily.mono,
|
||||
fontSize: theme.fontSize.code,
|
||||
color: theme.colors.foreground,
|
||||
backgroundColor: theme.colors.surface2,
|
||||
borderColor: "transparent",
|
||||
},
|
||||
codeBlock: {
|
||||
...paragraph,
|
||||
fontFamily: theme.fontFamily.mono === "ui-monospace" && !isWeb ? "" : theme.fontFamily.mono,
|
||||
fontSize: theme.fontSize.code,
|
||||
backgroundColor: theme.colors.surface2,
|
||||
borderColor: theme.colors.border,
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
},
|
||||
table: {
|
||||
...paragraph,
|
||||
borderColor: theme.colors.border,
|
||||
headerBackgroundColor: theme.colors.surface2,
|
||||
},
|
||||
image: { height: 320, resizeMode: "contain", borderRadius: 8 },
|
||||
thematicBreak: { color: theme.colors.border, height: 1, marginTop: 12, marginBottom: 12 },
|
||||
},
|
||||
};
|
||||
}
|
||||
const regularStyle = (theme: Theme) => markdownStyle(theme);
|
||||
const compactStyle = (theme: Theme) => markdownStyle(theme, true);
|
||||
const regularStyle = (theme: Theme) => createMarkdownStyles(theme);
|
||||
const compactStyle = (theme: Theme) => createMarkdownStyles(theme, true);
|
||||
const ThemedCodeBlock = withUnistyles(HighlightedCodeBlock);
|
||||
const codeStyle = (theme: Theme) => ({
|
||||
inheritedStyles: {
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
import type { MarkdownStyle } from "react-native-enriched-markdown";
|
||||
import type { Theme } from "@/styles/theme";
|
||||
import { isWeb } from "@/constants/platform";
|
||||
|
||||
export function createMarkdownStyles(
|
||||
theme: Theme,
|
||||
compact = false,
|
||||
): { markdownStyle: MarkdownStyle } {
|
||||
const fontSize = compact ? theme.fontSize.base : theme.fontSize.content;
|
||||
const paragraph = {
|
||||
fontSize,
|
||||
fontFamily: theme.fontFamily.ui,
|
||||
lineHeight: Math.round(fontSize * 1.4),
|
||||
color: theme.colors.foreground,
|
||||
marginTop: 0,
|
||||
marginBottom: theme.spacing[3],
|
||||
};
|
||||
const heading = (scale: number) => ({
|
||||
...paragraph,
|
||||
fontSize: Math.round(fontSize * scale),
|
||||
lineHeight: Math.round(fontSize * scale * 1.3),
|
||||
fontWeight: "bold",
|
||||
marginTop: theme.spacing[3],
|
||||
});
|
||||
return {
|
||||
markdownStyle: {
|
||||
paragraph,
|
||||
h1: heading(1.6),
|
||||
h2: heading(1.4),
|
||||
h3: heading(1.2),
|
||||
h4: heading(1.1),
|
||||
h5: heading(1),
|
||||
h6: heading(1),
|
||||
list: {
|
||||
...paragraph,
|
||||
bulletColor: theme.colors.foreground,
|
||||
markerColor: theme.colors.foregroundMuted,
|
||||
gapWidth: 7,
|
||||
itemSpacing: 4,
|
||||
marginLeft: 20,
|
||||
},
|
||||
blockquote: {
|
||||
...paragraph,
|
||||
color: theme.colors.foregroundMuted,
|
||||
backgroundColor: theme.colors.surface2,
|
||||
borderColor: theme.colors.border,
|
||||
borderWidth: 3,
|
||||
padding: 12,
|
||||
gapWidth: 8,
|
||||
admonitions: {
|
||||
note: { color: theme.colors.accentBright, backgroundColor: theme.colors.surface2 },
|
||||
tip: { color: theme.colors.statusSuccess, backgroundColor: theme.colors.surface2 },
|
||||
important: { color: theme.colors.statusMerged, backgroundColor: theme.colors.surface2 },
|
||||
warning: { color: theme.colors.statusWarning, backgroundColor: theme.colors.surface2 },
|
||||
caution: { color: theme.colors.statusDanger, backgroundColor: theme.colors.surface2 },
|
||||
},
|
||||
},
|
||||
link: { color: theme.colors.accent, underline: false },
|
||||
linkVariants: {
|
||||
"^(?!https?://).+": {
|
||||
color: theme.colors.accent,
|
||||
pill: { borderRadius: 4, paddingHorizontal: 3 },
|
||||
},
|
||||
},
|
||||
code: {
|
||||
fontFamily: theme.fontFamily.mono === "ui-monospace" && !isWeb ? "" : theme.fontFamily.mono,
|
||||
fontSize: theme.fontSize.code,
|
||||
color: theme.colors.foreground,
|
||||
backgroundColor: theme.colors.surface2,
|
||||
borderColor: "transparent",
|
||||
},
|
||||
codeBlock: {
|
||||
...paragraph,
|
||||
fontFamily: theme.fontFamily.mono === "ui-monospace" && !isWeb ? "" : theme.fontFamily.mono,
|
||||
fontSize: theme.fontSize.code,
|
||||
backgroundColor: theme.colors.surface2,
|
||||
borderColor: theme.colors.border,
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
},
|
||||
table: {
|
||||
...paragraph,
|
||||
borderColor: theme.colors.border,
|
||||
headerBackgroundColor: theme.colors.surface2,
|
||||
headerTextColor: theme.colors.foreground,
|
||||
rowEvenBackgroundColor: theme.colors.surface0,
|
||||
rowOddBackgroundColor: theme.colors.surface1,
|
||||
},
|
||||
taskList: {
|
||||
checkedTextColor: theme.colors.foregroundMuted,
|
||||
checkedColor: theme.colors.accent,
|
||||
checkmarkColor: theme.colors.accentForeground,
|
||||
borderColor: theme.colors.foregroundMuted,
|
||||
},
|
||||
image: { height: 320, resizeMode: "contain", borderRadius: 8 },
|
||||
thematicBreak: { color: theme.colors.border, height: 1, marginTop: 12, marginBottom: 12 },
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user