2024-10-26 15:01:33 -04:00
|
|
|
defmodule ZoeyscomputerWeb.CodeBlock do
|
|
|
|
|
use Phoenix.Component
|
2024-10-26 21:41:22 -04:00
|
|
|
|
|
|
|
|
import ZoeyscomputerWeb.CoreComponents
|
2024-10-26 15:01:33 -04:00
|
|
|
|
|
|
|
|
@moduledoc """
|
|
|
|
|
A code block component with syntax highlighting using Shiki.
|
|
|
|
|
|
|
|
|
|
## Features:
|
|
|
|
|
- Syntax highlighting with Shiki
|
|
|
|
|
- Optional line numbers
|
|
|
|
|
- Optional highlighted lines
|
|
|
|
|
- Optional title
|
|
|
|
|
- Copy button
|
|
|
|
|
- Catppuccin theme styling
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
|
Renders a code block with syntax highlighting.
|
|
|
|
|
|
|
|
|
|
## Examples
|
|
|
|
|
|
|
|
|
|
<.code_block
|
|
|
|
|
code="def hello, do: :world"
|
|
|
|
|
language="elixir"
|
|
|
|
|
title="Example Code"
|
|
|
|
|
line_numbers={true}
|
|
|
|
|
highlighted_lines={[1, 3]}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
## Options
|
|
|
|
|
* `:code` - Required. The code string to highlight
|
|
|
|
|
* `:language` - Required. Programming language for syntax highlighting
|
|
|
|
|
* `:title` - Optional. Title displayed above the code block
|
|
|
|
|
* `:line_numbers` - Optional. Show line numbers (default: false)
|
|
|
|
|
* `:highlighted_lines` - Optional. List of line numbers to highlight
|
|
|
|
|
"""
|
|
|
|
|
attr :code, :string, required: true
|
|
|
|
|
attr :language, :string, required: true
|
|
|
|
|
attr :title, :string, default: nil
|
2024-10-26 21:41:22 -04:00
|
|
|
attr :class, :string, default: ""
|
2024-10-26 15:01:33 -04:00
|
|
|
attr :line_numbers, :boolean, default: false
|
|
|
|
|
attr :highlighted_lines, :list, default: []
|
|
|
|
|
|
|
|
|
|
def code_block(assigns) do
|
|
|
|
|
# Calculate the number of lines for line numbers
|
|
|
|
|
assigns = assign(assigns, :num_lines, String.split(assigns.code, "\n") |> length())
|
|
|
|
|
|
2024-10-26 21:41:22 -04:00
|
|
|
id = System.unique_integer()
|
|
|
|
|
|
2024-10-26 15:01:33 -04:00
|
|
|
~H"""
|
2024-10-26 21:41:22 -04:00
|
|
|
<div class={"relative rounded-lg overflow-hidden w-full bg-ctp-mantle border border-ctp-surface0 #{@class} "}>
|
2024-10-26 15:01:33 -04:00
|
|
|
<%= if @title do %>
|
2024-10-26 21:41:22 -04:00
|
|
|
<div class="bg-ctp-crust px-4 py-2 border-b border-ctp-surface0">
|
|
|
|
|
<h3 class="ctp-text-text text-[0.75rem] font-medium"><%= @title %></h3>
|
2024-10-26 15:01:33 -04:00
|
|
|
</div>
|
|
|
|
|
<% end %>
|
|
|
|
|
|
2024-11-14 13:05:48 -05:00
|
|
|
<div class="bg-ctp-mantle">
|
2024-10-26 21:41:22 -04:00
|
|
|
<div class="relative bg-ctp-crust">
|
|
|
|
|
<%= if @line_numbers do %>
|
|
|
|
|
<div class="absolute bg-ctp-crust left-0 top-0 bottom-0 ctp-bg-crust min-w-12 flex flex-col items-end py-4 ctp-text-surface2 select-none">
|
|
|
|
|
<%= for line_num <- 1..@num_lines do %>
|
|
|
|
|
<span class={[
|
|
|
|
|
"text-sm leading-6 pr-2",
|
|
|
|
|
line_num in @highlighted_lines &&
|
|
|
|
|
"text-ctp-mauve bg-ctp-mauve/15 w-full text-right font-bold"
|
|
|
|
|
]}>
|
|
|
|
|
<%= line_num %>
|
|
|
|
|
</span>
|
|
|
|
|
<% end %>
|
|
|
|
|
</div>
|
|
|
|
|
<% end %>
|
2024-10-26 15:01:33 -04:00
|
|
|
|
2024-11-14 13:05:48 -05:00
|
|
|
<div class={[
|
|
|
|
|
"bg-ctp-mantle overflow-x-scroll scrollbar scrollbar-track-ctp-base scrollbar-thumb-ctp-mauve pb-0.5",
|
|
|
|
|
@line_numbers && "pl-12"
|
|
|
|
|
]}>
|
2024-10-26 21:41:22 -04:00
|
|
|
<pre
|
|
|
|
|
class="p-4 leading-6 text-sm mb-4"
|
|
|
|
|
id={"code-block-#{id}"}
|
|
|
|
|
phx-hook="CodeBlockHook"
|
|
|
|
|
data-code={@code}
|
|
|
|
|
data-language={@language}
|
|
|
|
|
data-highlighted-lines={Jason.encode!(@highlighted_lines)}
|
|
|
|
|
><code class="text-sm"><%= @code %></code></pre>
|
|
|
|
|
</div>
|
2024-10-26 15:01:33 -04:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2024-10-26 21:41:22 -04:00
|
|
|
<div class="bg-ctp-mantle px-4 py-2 border-t border-ctp-surface0 flex justify-end">
|
|
|
|
|
<.copy_button id="code-copy-btn" content={"code-block-#{id}"} />
|
2024-10-26 15:01:33 -04:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
end
|