Template
The assistant only ever renders prose, links and the odd list, but Streamdown's plugin set dragged in shiki, mermaid and katex — and streamdown core declares mermaid as a hard dependency, so dropping the plugins alone would have left it installed. Rendering now runs on the same unified pipeline Streamdown used internally, minus the plugin surface: remark-parse -> remark-gfm -> remark-rehype -> rehype-sanitize -> hast-util-to-jsx-runtime. GFM, streaming repair and the link-safety hook all survive; fenced code renders as plain <pre>. Net -264/+101 packages. remend now runs only while a part is still streaming. On settled text it reads `*$89*` as an unclosed italic — the `$` throws off its closing-delimiter scan — and appends a stray `*` that parses as an empty bullet. Italic prices are ordinary storefront copy, so that would have shown up in production. Route-relative links go through next/link in the same tab; sending a shopper to a product page in a new tab would strand the conversation behind it. Only external destinations get the confirmation dialog. code-block.tsx and tool.tsx were the sole users of shiki and had no importers, so both are gone. Also folded in two unrelated changes that were already in the tree: the loader move out of app/components/ui, and dropping the fade on the command palette so it opens instantly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KuySwKLSF4uEPpZjHkdHBP
97 lines
2.2 KiB
TypeScript
97 lines
2.2 KiB
TypeScript
import { cn } from "@/lib/utils";
|
|
import type { HTMLAttributes } from "react";
|
|
|
|
interface LoaderIconProps {
|
|
size?: number;
|
|
}
|
|
|
|
const LoaderIcon = ({ size = 16 }: LoaderIconProps) => (
|
|
<svg
|
|
height={size}
|
|
strokeLinejoin="round"
|
|
style={{ color: "currentcolor" }}
|
|
viewBox="0 0 16 16"
|
|
width={size}
|
|
>
|
|
<title>Loader</title>
|
|
<g clipPath="url(#clip0_2393_1490)">
|
|
<path d="M8 0V4" stroke="currentColor" strokeWidth="1.5" />
|
|
<path
|
|
d="M8 16V12"
|
|
opacity="0.5"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
/>
|
|
<path
|
|
d="M3.29773 1.52783L5.64887 4.7639"
|
|
opacity="0.9"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
/>
|
|
<path
|
|
d="M12.7023 1.52783L10.3511 4.7639"
|
|
opacity="0.1"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
/>
|
|
<path
|
|
d="M12.7023 14.472L10.3511 11.236"
|
|
opacity="0.4"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
/>
|
|
<path
|
|
d="M3.29773 14.472L5.64887 11.236"
|
|
opacity="0.6"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
/>
|
|
<path
|
|
d="M15.6085 5.52783L11.8043 6.7639"
|
|
opacity="0.2"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
/>
|
|
<path
|
|
d="M0.391602 10.472L4.19583 9.23598"
|
|
opacity="0.7"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
/>
|
|
<path
|
|
d="M15.6085 10.4722L11.8043 9.2361"
|
|
opacity="0.3"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
/>
|
|
<path
|
|
d="M0.391602 5.52783L4.19583 6.7639"
|
|
opacity="0.8"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
/>
|
|
</g>
|
|
<defs>
|
|
<clipPath id="clip0_2393_1490">
|
|
<rect fill="white" height="16" width="16" />
|
|
</clipPath>
|
|
</defs>
|
|
</svg>
|
|
);
|
|
|
|
export type LoaderProps = HTMLAttributes<HTMLDivElement> & {
|
|
size?: number;
|
|
};
|
|
|
|
export const Loader = ({ className, size = 16, ...props }: LoaderProps) => (
|
|
<div
|
|
className={cn(
|
|
"inline-flex animate-spin items-center justify-center",
|
|
className
|
|
)}
|
|
{...props}
|
|
>
|
|
<LoaderIcon size={size} />
|
|
</div>
|
|
);
|