logo.tsx 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import { TextAttributes, RGBA } from "@opentui/core"
  2. import { For, type JSX } from "solid-js"
  3. import { useTheme, tint } from "@tui/context/theme"
  4. import { logo, marks } from "@/cli/logo"
  5. // Shadow markers (rendered chars in parens):
  6. // _ = full shadow cell (space with bg=shadow)
  7. // ^ = letter top, shadow bottom (▀ with fg=letter, bg=shadow)
  8. // ~ = shadow top only (▀ with fg=shadow)
  9. const SHADOW_MARKER = new RegExp(`[${marks}]`)
  10. export function Logo() {
  11. const { theme } = useTheme()
  12. const renderLine = (line: string, fg: RGBA, bold: boolean): JSX.Element[] => {
  13. const shadow = tint(theme.background, fg, 0.25)
  14. const attrs = bold ? TextAttributes.BOLD : undefined
  15. const elements: JSX.Element[] = []
  16. let i = 0
  17. while (i < line.length) {
  18. const rest = line.slice(i)
  19. const markerIndex = rest.search(SHADOW_MARKER)
  20. if (markerIndex === -1) {
  21. elements.push(
  22. <text fg={fg} attributes={attrs} selectable={false}>
  23. {rest}
  24. </text>,
  25. )
  26. break
  27. }
  28. if (markerIndex > 0) {
  29. elements.push(
  30. <text fg={fg} attributes={attrs} selectable={false}>
  31. {rest.slice(0, markerIndex)}
  32. </text>,
  33. )
  34. }
  35. const marker = rest[markerIndex]
  36. switch (marker) {
  37. case "_":
  38. elements.push(
  39. <text fg={fg} bg={shadow} attributes={attrs} selectable={false}>
  40. {" "}
  41. </text>,
  42. )
  43. break
  44. case "^":
  45. elements.push(
  46. <text fg={fg} bg={shadow} attributes={attrs} selectable={false}>
  47. </text>,
  48. )
  49. break
  50. case "~":
  51. elements.push(
  52. <text fg={shadow} attributes={attrs} selectable={false}>
  53. </text>,
  54. )
  55. break
  56. }
  57. i += markerIndex + 1
  58. }
  59. return elements
  60. }
  61. return (
  62. <box>
  63. <For each={logo.left}>
  64. {(line, index) => (
  65. <box flexDirection="row" gap={1}>
  66. <box flexDirection="row">{renderLine(line, theme.textMuted, false)}</box>
  67. <box flexDirection="row">{renderLine(logo.right[index()], theme.text, true)}</box>
  68. </box>
  69. )}
  70. </For>
  71. </box>
  72. )
  73. }