code.tsx 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import { codeToHtml } from "shiki";
  2. import { CopyButton } from "./copy-button";
  3. const vercelTheme = {
  4. name: "vercel",
  5. type: "dark" as const,
  6. colors: {
  7. "editor.background": "transparent",
  8. "editor.foreground": "#EDEDED",
  9. },
  10. settings: [
  11. {
  12. scope: ["comment", "punctuation.definition.comment"],
  13. settings: { foreground: "#666666" },
  14. },
  15. {
  16. scope: ["string", "string.quoted", "string.template"],
  17. settings: { foreground: "#50E3C2" },
  18. },
  19. {
  20. scope: ["constant.numeric", "constant.language.boolean", "constant.language.null"],
  21. settings: { foreground: "#50E3C2" },
  22. },
  23. {
  24. scope: ["keyword", "storage.type", "storage.modifier"],
  25. settings: { foreground: "#FF0080" },
  26. },
  27. {
  28. scope: ["keyword.operator", "keyword.control"],
  29. settings: { foreground: "#FF0080" },
  30. },
  31. {
  32. scope: ["entity.name.function", "support.function", "meta.function-call"],
  33. settings: { foreground: "#7928CA" },
  34. },
  35. {
  36. scope: ["variable", "variable.other", "variable.parameter"],
  37. settings: { foreground: "#EDEDED" },
  38. },
  39. {
  40. scope: ["entity.name.tag", "support.class.component", "entity.name.type"],
  41. settings: { foreground: "#FF0080" },
  42. },
  43. {
  44. scope: ["punctuation", "meta.brace", "meta.bracket"],
  45. settings: { foreground: "#888888" },
  46. },
  47. {
  48. scope: ["support.type.property-name", "entity.name.tag.json", "meta.object-literal.key"],
  49. settings: { foreground: "#EDEDED" },
  50. },
  51. {
  52. scope: ["entity.other.attribute-name"],
  53. settings: { foreground: "#50E3C2" },
  54. },
  55. {
  56. scope: ["support.type.primitive", "entity.name.type.primitive"],
  57. settings: { foreground: "#50E3C2" },
  58. },
  59. ],
  60. };
  61. interface CodeProps {
  62. children: string;
  63. lang?: "json" | "tsx" | "typescript" | "bash" | "javascript";
  64. }
  65. export async function Code({ children, lang = "typescript" }: CodeProps) {
  66. const html = await codeToHtml(children.trim(), {
  67. lang,
  68. theme: vercelTheme,
  69. });
  70. return (
  71. <div className="group relative my-6 rounded-lg border border-border bg-card p-4 overflow-x-auto text-sm [&_pre]:bg-transparent! [&_pre]:p-0! [&_pre]:m-0! [&_code]:bg-transparent! font-mono">
  72. <div className="sticky top-0 float-right z-10 -mt-1 -mr-1">
  73. <CopyButton
  74. text={children.trim()}
  75. className="opacity-0 group-hover:opacity-100 text-muted-foreground bg-card"
  76. />
  77. </div>
  78. <div dangerouslySetInnerHTML={{ __html: html }} />
  79. </div>
  80. );
  81. }