Class: Cosensee::TailwindRenderer

Inherits:
Object
  • Object
show all
Includes:
HtmlEncodable, RenderClassFindable
Defined in:
lib/cosensee/tailwind_renderer.rb,
lib/cosensee/tailwind_renderer/code.rb,
lib/cosensee/tailwind_renderer/link.rb,
lib/cosensee/tailwind_renderer/page.rb,
lib/cosensee/tailwind_renderer/quote.rb,
lib/cosensee/tailwind_renderer/hash_tag.rb,
lib/cosensee/tailwind_renderer/codeblock.rb,
lib/cosensee/tailwind_renderer/parsed_line.rb,
lib/cosensee/tailwind_renderer/command_line.rb,
lib/cosensee/tailwind_renderer/icon_bracket.rb,
lib/cosensee/tailwind_renderer/text_bracket.rb,
lib/cosensee/tailwind_renderer/blank_bracket.rb,
lib/cosensee/tailwind_renderer/empty_bracket.rb,
lib/cosensee/tailwind_renderer/image_bracket.rb,
lib/cosensee/tailwind_renderer/double_bracket.rb,
lib/cosensee/tailwind_renderer/formula_bracket.rb,
lib/cosensee/tailwind_renderer/inline_svg_text.rb,
lib/cosensee/tailwind_renderer/youtube_bracket.rb,
lib/cosensee/tailwind_renderer/decorate_bracket.rb,
lib/cosensee/tailwind_renderer/gyazo_image_bracket.rb,
lib/cosensee/tailwind_renderer/external_link_bracket.rb,
lib/cosensee/tailwind_renderer/internal_link_bracket.rb,
lib/cosensee/tailwind_renderer/spotify_playlist_bracket.rb

Overview

convert into html

Constant Summary collapse

Code =
Data.define(:content, :project) do
  include HtmlEncodable

  def render
    code = content.content
    %(<code class="bg-gray-100 text-red-500 px-1 py-0.5 rounded">#{escape_html(code)}</code>)
  end
end
Data.define(:content, :project) do
  include HtmlEncodable

  def render
    link = content.content
    %(<span><a href="#{escape_html(link)}" class="text-blue-500 hover:text-blue-700">#{escape_html(link)}</a></span>)
  end
end
Page =
Data.define(:content, :project) do
  def render
    page = content
    rendered_lines = page.parsed_lines.map do |parsed_line|
      ParsedLine.new(parsed_line, project).render
    end

    rendered_lines.join
  end
end
Quote =
Data.define(:content, :project) do
  def render
    code = Cosensee::TailwindRenderer.new(content: content.content, project:).render
    %(<blockquote class="border-l-4 border-gray-300 bg-gray-100 px-4 text-gray-800">#{code}</blockquote>)
  end
end
HashTag =
Data.define(:content, :project) do
  include LinkEncodable
  include HtmlEncodable

  def render
    hash_tag = content.content
    %(<span><a href="#{make_link(hash_tag)}" class="text-blue-500 hover:text-blue-700">##{escape_html(hash_tag)}</a></span>)
  end
end
Codeblock =

codeblock renderer

Data.define(:content, :project) do
  include HtmlEncodable

  def render
    title = content.name

    # !!! EXTENSION: if name ends with .svgtext, render as inline SVG text
    return InlineSvgText.new(content:, project:).render if title.match?(/\.svgtext$/)

    <<~HTML_BLOCK
      <div class="bg-orange-300 text-gray-900 px-4 py-1 rounded-t-lg font-mono text-sm">#{title}</div>
      <div class="px-4 bg-gray-300 text-gray-900 rounded-b-lg shadow-md"><pre class="overflow-x-auto"><code class="block font-mono text-sm leading-relaxed">#{escape_html(content.content)}</code></pre></div>
    HTML_BLOCK
  end
end
ParsedLine =
Data.define(:content, :project) do
  include HtmlEncodable
  include RenderClassFindable

  def render
    result = if content.line_content?
               find_renderer_class(content.line_content).new(content: content.line_content, project:).render
             else
               content.content.map do |c|
                 if c.is_a?(String)
                   escape_html(c)
                 else
                   TailwindRenderer.new(content: c, project:).render
                 end
               end.join
             end
    level = content.indent_level * 2
    result = '&nbsp;' if result == ''
    if level > 0
      %(<div class="relative pl-[#{level}rem]"><span class="absolute left-[#{level - 1}rem] top-1/2 -translate-y-1/2 w-1.5 h-1.5 rounded-full bg-gray-800"></span>#{result}</div>)
    else
      %(<div class="relative pl-[#{level}rem]">#{result}</div>)
    end
  end
end
CommandLine =
Data.define(:content, :project) do
  include HtmlEncodable

  def render
    code = content.content
    prompt = content.prompt
    %(<code class="bg-gray-100 text-gray-800 px-4"><span class="text-red-400">#{prompt}</span>#{escape_html(code)}</code>)
  end
end
IconBracket =
Data.define(:content, :project) do
  include HtmlEncodable

  def render
    page = project.find_page_by_title(content.icon_name)
    icon_src = page&.first_image&.src
    %(<img src="#{icon_src}" loading="lazy" alt="icon" class="inline-block h-5 w-5 align-middle">)
  end
end
TextBracket =
Data.define(:content, :project) do
  def render
    rendered = TailwindRenderer.new(content: content.content, project:).render
    %(<span>[#{rendered}]</span>)
  end
end
BlankBracket =
Data.define(:content, :project) do
  def render
    %(<span>#{content.blank}</span>)
  end
end
EmptyBracket =
Data.define(:content, :project) do
  def render
    %(<span>[]</span>)
  end
end
ImageBracket =
Data.define(:content, :project) do
  def render
    if content.link
      %(<span><a href="#{content.link}"><img src="#{content.src}" loading="lazy" class="max-w-max max-h-80"></a></span>)
    else
      %(<span><img src="#{content.src}" loading="lazy" class="max-w-max max-h-80"></span>)
    end
  end
end
DoubleBracket =
Data.define(:content, :project) do
  def render
    rendered_content = Cosensee::TailwindRenderer.new(content: content.content, project:).render

    %(<span class="font-bold">#{rendered_content}</span>)
  end
end
FormulaBracket =
Data.define(:content, :project) do
  include HtmlEncodable

  def render
    %(<span class="math-container">$#{escape_html(content.formula)}$</span>)
  end
end
InlineSvgText =

extended renderer for inline SVG text

Data.define(:content, :project) do
  include HtmlEncodable

  def render
    output = <<~SVG_TEXT_HEADER
      <svg style="inherit" xmlns="http://www.w3.org/2000/svg" class="svg-text">
        <style>
          .text { -ms-user-select: none; -webkit-user-select: none; user-select: none; }
          @media print { .svg-text { display: none !important; } text  { display: none !important; } }
        </style>
      <text x="0" y="0" font-size="inherit" class="text" fill="break">
    SVG_TEXT_HEADER

    content.content.lines.each do |line|
      tspan_text = if line.strip.empty?
                     '&#xA0;'
                   else
                     escape_html(line.chomp)
                   end
      output << %(<tspan x="0" dy="1.4em">#{tspan_text}</tspan>\n)
    end

    output << <<~SVG_TEXT_FOOTER
        </text>
      </svg>
    SVG_TEXT_FOOTER

    output
  end
end
YoutubeBracket =
Data.define(:content, :project) do
  def render
    %(<iframe class="w-full aspect-video px-8" src="https://www.youtube.com/embed/#{content.video_id}?autoplay=0" type="text/html" allowfullscreen="" scrolling="no" allow="encrypted-media"></iframe>)
  end
end
DecorateBracket =
Data.define(:content, :project) do
  def render
    classes = []
    classes << font_sizes[content.font_size] if content.font_size
    classes << 'font-semibold' if content.font_size && content.font_size > 0
    classes << 'underline' if content.underlined
    classes << 'italic' if content.slanted
    classes << 'line-through' if content.deleted
    class_attr = classes.join(' ')

    %(<span class="#{class_attr}">#{content.text}</span>)
  end

  private

  def font_sizes
    %w[text-base text-lg text-xl text-2xl text-3xl text-4xl text-5xl text-6xl text-7xl text-8xl text-9xl].freeze
  end
end
GyazoImageBracket =
Data.define(:content, :project) do
  def render
    if content.link
      %(<span><a href="#{content.link}"><img loading="lazy" src="https://gyazo.com/#{content.image_id}/raw" class="max-w-max max-h-80"></a></span>)
    else
      %(<span><img loading="lazy" src="https://gyazo.com/#{content.image_id}/raw" class="max-w-max max-h-80"></span>)
    end
  end
end
ExternalLinkBracket =
Data.define(:content, :project) do
  include HtmlEncodable

  def render
    link = content.link
    anchor = content.anchor || content.link
    %(<span><a href="#{link}" class="text-blue-500 hover:text-blue-700">#{escape_html(anchor)}</a></span>)
  end
end
InternalLinkBracket =
Data.define(:content, :project) do
  include HtmlEncodable

  def render
    %(<span><a href="#{content.link}" class="text-blue-500 hover:text-blue-700">#{escape_html(content.anchor)}</a></span>)
  end
end
SpotifyPlaylistBracket =
Data.define(:content, :project) do
  def render
    %(<iframe src="https://open.spotify.com/embed/playlist/#{content.playlist_id}" class="w-full h-96" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe>)
  end
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from RenderClassFindable

#find_renderer_class

Methods included from HtmlEncodable

#escape_html

Constructor Details

#initialize(content:, project:) ⇒ TailwindRenderer

content is Cosensee objects or an array of them



10
11
12
13
# File 'lib/cosensee/tailwind_renderer.rb', line 10

def initialize(content:, project:)
  @content = content
  @project = project
end

Instance Attribute Details

#contentObject (readonly)

Returns the value of attribute content.



15
16
17
# File 'lib/cosensee/tailwind_renderer.rb', line 15

def content
  @content
end

#projectObject (readonly)

Returns the value of attribute project.



15
16
17
# File 'lib/cosensee/tailwind_renderer.rb', line 15

def project
  @project
end

Instance Method Details

#renderObject



17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/cosensee/tailwind_renderer.rb', line 17

def render
  if content.is_a?(Array)
    content.map do |c|
      if c.is_a?(String)
        escape_html(c)
      else
        find_renderer_class(c).new(content: c, project:).render
      end
    end.join
  else
    find_renderer_class(content).new(content:, project:).render
  end
end