Refine appearance settings and syntax highlighting
Keep parsed chat and tool detail content in sync with appearance token changes. Hide font-family controls on native, use One as the default syntax theme, add Swift highlighting, and give Nord a distinct light palette.
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import { Fragment, type ReactNode } from "react";
|
||||
import { withUnistyles } from "react-native-unistyles";
|
||||
import type { Theme } from "@/styles/theme";
|
||||
|
||||
interface AppearanceStyleBoundaryProps {
|
||||
appearanceKey?: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
function AppearanceStyleBoundaryBase({ appearanceKey, children }: AppearanceStyleBoundaryProps) {
|
||||
return <Fragment key={appearanceKey}>{children}</Fragment>;
|
||||
}
|
||||
|
||||
const appearanceStyleBoundaryMapping = (theme: Theme): Partial<AppearanceStyleBoundaryProps> => ({
|
||||
appearanceKey: [
|
||||
theme.fontFamily.ui,
|
||||
theme.fontFamily.mono,
|
||||
theme.fontSize.xs,
|
||||
theme.fontSize.sm,
|
||||
theme.fontSize.base,
|
||||
theme.fontSize.lg,
|
||||
theme.fontSize.xl,
|
||||
theme.fontSize["2xl"],
|
||||
theme.fontSize["3xl"],
|
||||
theme.fontSize["4xl"],
|
||||
theme.fontSize.code,
|
||||
theme.lineHeight.diff,
|
||||
theme.colors.foreground,
|
||||
theme.colors.foregroundMuted,
|
||||
theme.colors.mutedForeground,
|
||||
theme.colors.surface1,
|
||||
theme.colors.surface2,
|
||||
theme.colors.border,
|
||||
theme.colors.accentBright,
|
||||
theme.colors.syntax.keyword,
|
||||
theme.colors.syntax.comment,
|
||||
theme.colors.syntax.string,
|
||||
theme.colors.syntax.number,
|
||||
theme.colors.syntax.literal,
|
||||
theme.colors.syntax.function,
|
||||
theme.colors.syntax.definition,
|
||||
theme.colors.syntax.class,
|
||||
theme.colors.syntax.type,
|
||||
theme.colors.syntax.tag,
|
||||
theme.colors.syntax.attribute,
|
||||
theme.colors.syntax.property,
|
||||
theme.colors.syntax.variable,
|
||||
theme.colors.syntax.operator,
|
||||
theme.colors.syntax.punctuation,
|
||||
theme.colors.syntax.regexp,
|
||||
theme.colors.syntax.escape,
|
||||
theme.colors.syntax.meta,
|
||||
theme.colors.syntax.heading,
|
||||
theme.colors.syntax.link,
|
||||
].join("\u0000"),
|
||||
});
|
||||
|
||||
const ThemedAppearanceStyleBoundary = withUnistyles(AppearanceStyleBoundaryBase);
|
||||
|
||||
export function AppearanceStyleBoundary({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<ThemedAppearanceStyleBoundary uniProps={appearanceStyleBoundaryMapping}>
|
||||
{children}
|
||||
</ThemedAppearanceStyleBoundary>
|
||||
);
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { Text, View, type StyleProp, type TextStyle, type ViewStyle } from "reac
|
||||
|
||||
interface MarkdownTextSpanProps {
|
||||
style?: StyleProp<TextStyle>;
|
||||
monoSurface?: boolean;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { UITextView } from "react-native-uitextview";
|
||||
|
||||
interface MarkdownTextSpanProps {
|
||||
style?: StyleProp<TextStyle>;
|
||||
monoSurface?: boolean;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { useMemo, type ReactNode } from "react";
|
||||
import { Text, View, type StyleProp, type TextStyle, type ViewStyle } from "react-native";
|
||||
import { CODE_SURFACE_DATASET } from "@/styles/code-surface";
|
||||
|
||||
interface MarkdownTextSpanProps {
|
||||
style?: StyleProp<TextStyle>;
|
||||
monoSurface?: boolean;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
@@ -11,8 +13,12 @@ interface MarkdownTextSpanProps {
|
||||
// react-native-uitextview: its transitive import of codegenNativeComponent
|
||||
// pulls in setUpReactDevTools, which doesn't resolve under Metro's web
|
||||
// target in dev mode.
|
||||
export function MarkdownTextSpan({ style, children }: MarkdownTextSpanProps) {
|
||||
return <Text style={style}>{children}</Text>;
|
||||
export function MarkdownTextSpan({ style, monoSurface, children }: MarkdownTextSpanProps) {
|
||||
return (
|
||||
<Text dataSet={monoSurface ? CODE_SURFACE_DATASET : undefined} style={style}>
|
||||
{children}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
interface MarkdownParagraphViewProps {
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
type TextStyle,
|
||||
} from "react-native";
|
||||
import { MarkdownParagraphView, MarkdownTextSpan } from "@/components/markdown-text";
|
||||
import { AppearanceStyleBoundary } from "@/components/appearance-style-boundary";
|
||||
import * as React from "react";
|
||||
import {
|
||||
useState,
|
||||
@@ -1496,16 +1497,18 @@ const MemoizedMarkdownBlock = React.memo(function MemoizedMarkdownBlock({
|
||||
onLinkPress,
|
||||
}: MemoizedMarkdownBlockProps) {
|
||||
return (
|
||||
<ThemedMarkdown
|
||||
uniProps={markdownStyleMapping}
|
||||
rules={rules}
|
||||
markdownit={parser}
|
||||
onLinkPress={onLinkPress}
|
||||
allowedImageHandlers={MARKDOWN_ALLOWED_IMAGE_HANDLERS}
|
||||
topLevelMaxExceededItem={MARKDOWN_TOP_LEVEL_MAX_EXCEEDED_ITEM}
|
||||
>
|
||||
{text}
|
||||
</ThemedMarkdown>
|
||||
<AppearanceStyleBoundary>
|
||||
<ThemedMarkdown
|
||||
uniProps={markdownStyleMapping}
|
||||
rules={rules}
|
||||
markdownit={parser}
|
||||
onLinkPress={onLinkPress}
|
||||
allowedImageHandlers={MARKDOWN_ALLOWED_IMAGE_HANDLERS}
|
||||
topLevelMaxExceededItem={MARKDOWN_TOP_LEVEL_MAX_EXCEEDED_ITEM}
|
||||
>
|
||||
{text}
|
||||
</ThemedMarkdown>
|
||||
</AppearanceStyleBoundary>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1513,6 +1516,7 @@ interface MarkdownInheritedTextProps {
|
||||
inheritedStyles: TextStyle;
|
||||
textStyle: TextStyle;
|
||||
style?: StyleProp<TextStyle>;
|
||||
monoSurface?: boolean;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
@@ -1520,13 +1524,18 @@ function MarkdownInheritedText({
|
||||
inheritedStyles,
|
||||
textStyle,
|
||||
style: overrideStyle,
|
||||
monoSurface,
|
||||
children,
|
||||
}: MarkdownInheritedTextProps) {
|
||||
const style = useMemo(
|
||||
() => [inheritedStyles, textStyle, overrideStyle],
|
||||
[inheritedStyles, textStyle, overrideStyle],
|
||||
);
|
||||
return <MarkdownTextSpan style={style}>{children}</MarkdownTextSpan>;
|
||||
return (
|
||||
<MarkdownTextSpan monoSurface={monoSurface} style={style}>
|
||||
{children}
|
||||
</MarkdownTextSpan>
|
||||
);
|
||||
}
|
||||
|
||||
interface MarkdownListItemContentProps {
|
||||
@@ -1696,6 +1705,7 @@ export const AssistantMessage = memo(function AssistantMessage({
|
||||
key={node.key}
|
||||
inheritedStyles={inheritedStyles}
|
||||
textStyle={styles.code_inline}
|
||||
monoSurface
|
||||
>
|
||||
{content}
|
||||
</MarkdownInheritedText>
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from "react-native";
|
||||
import { ScrollView as GHScrollView } from "react-native-gesture-handler";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
import { AppearanceStyleBoundary } from "@/components/appearance-style-boundary";
|
||||
import type { ToolCallDetail } from "@getpaseo/protocol/agent-types";
|
||||
import { buildLineDiff, parseUnifiedDiff, type DiffLine } from "@/utils/tool-call-parsers";
|
||||
import { highlightDiffLines } from "@/utils/diff-highlight";
|
||||
@@ -756,7 +757,15 @@ function LoadingSkeleton({ containerStyle }: { containerStyle: StyleProp<ViewSty
|
||||
);
|
||||
}
|
||||
|
||||
export function ToolCallDetailsContent({
|
||||
export function ToolCallDetailsContent({ ...props }: ToolCallDetailsContentProps) {
|
||||
return (
|
||||
<AppearanceStyleBoundary>
|
||||
<ToolCallDetailsContentInner {...props} />
|
||||
</AppearanceStyleBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
function ToolCallDetailsContentInner({
|
||||
detail,
|
||||
errorText,
|
||||
maxHeight,
|
||||
|
||||
Reference in New Issue
Block a user