cosensee 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -2
- data/README.md +25 -7
- data/Rakefile +1 -1
- data/assets/js/search.js +42 -0
- data/assets/styles/input.css +3 -0
- data/exe/cosensee +36 -0
- data/lib/cosensee/api/page_data.rb +43 -0
- data/lib/cosensee/bracket_parser.rb +21 -16
- data/lib/cosensee/bracket_serializer.rb +3 -1
- data/lib/cosensee/cli/initializer.rb +64 -0
- data/lib/cosensee/cli/option.rb +65 -0
- data/lib/cosensee/cli/parser.rb +83 -0
- data/lib/cosensee/delegatable.rb +33 -0
- data/lib/cosensee/html_builder.rb +26 -17
- data/lib/cosensee/line_parser.rb +29 -16
- data/lib/cosensee/node/blank_bracket.rb +10 -0
- data/lib/cosensee/node/code.rb +20 -0
- data/lib/cosensee/node/codeblock.rb +32 -0
- data/lib/cosensee/node/command_line.rb +20 -0
- data/lib/cosensee/node/decorate_bracket.rb +23 -0
- data/lib/cosensee/node/double_bracket.rb +22 -0
- data/lib/cosensee/node/empty_bracket.rb +10 -0
- data/lib/cosensee/node/external_link_bracket.rb +10 -0
- data/lib/cosensee/node/formula_bracket.rb +10 -0
- data/lib/cosensee/node/gyazo_image_bracket.rb +10 -0
- data/lib/cosensee/node/hash_tag.rb +21 -0
- data/lib/cosensee/node/icon_bracket.rb +10 -0
- data/lib/cosensee/node/image_bracket.rb +10 -0
- data/lib/cosensee/node/indent.rb +27 -0
- data/lib/cosensee/node/internal_link_bracket.rb +10 -0
- data/lib/cosensee/node/link.rb +20 -0
- data/lib/cosensee/node/quote.rb +26 -0
- data/lib/cosensee/node/spotify_playlist_bracket.rb +10 -0
- data/lib/cosensee/node/text_bracket.rb +12 -0
- data/lib/cosensee/node/youtube_bracket.rb +10 -0
- data/lib/cosensee/page.rb +46 -16
- data/lib/cosensee/page_store.rb +25 -2
- data/lib/cosensee/parsed_line.rb +24 -6
- data/lib/cosensee/project.rb +21 -6
- data/lib/cosensee/render_class_findable.rb +13 -0
- data/lib/cosensee/tailwind_command.rb +24 -0
- data/lib/cosensee/tailwind_renderer/blank_bracket.rb +1 -1
- data/lib/cosensee/tailwind_renderer/code.rb +1 -1
- data/lib/cosensee/tailwind_renderer/codeblock.rb +22 -0
- data/lib/cosensee/tailwind_renderer/command_line.rb +1 -1
- data/lib/cosensee/tailwind_renderer/decorate_bracket.rb +1 -1
- data/lib/cosensee/tailwind_renderer/double_bracket.rb +2 -2
- data/lib/cosensee/tailwind_renderer/empty_bracket.rb +1 -1
- data/lib/cosensee/tailwind_renderer/external_link_bracket.rb +1 -1
- data/lib/cosensee/tailwind_renderer/formula_bracket.rb +1 -1
- data/lib/cosensee/tailwind_renderer/gyazo_image_bracket.rb +15 -0
- data/lib/cosensee/tailwind_renderer/hash_tag.rb +1 -1
- data/lib/cosensee/tailwind_renderer/icon_bracket.rb +4 -3
- data/lib/cosensee/tailwind_renderer/image_bracket.rb +3 -3
- data/lib/cosensee/tailwind_renderer/inline_svg_text.rb +37 -0
- data/lib/cosensee/tailwind_renderer/internal_link_bracket.rb +1 -1
- data/lib/cosensee/tailwind_renderer/link.rb +1 -1
- data/lib/cosensee/tailwind_renderer/page.rb +3 -18
- data/lib/cosensee/tailwind_renderer/parsed_line.rb +4 -3
- data/lib/cosensee/tailwind_renderer/quote.rb +2 -2
- data/lib/cosensee/tailwind_renderer/spotify_playlist_bracket.rb +11 -0
- data/lib/cosensee/tailwind_renderer/text_bracket.rb +2 -2
- data/lib/cosensee/tailwind_renderer/youtube_bracket.rb +11 -0
- data/lib/cosensee/tailwind_renderer.rb +6 -11
- data/lib/cosensee/user.rb +7 -1
- data/lib/cosensee/version.rb +1 -1
- data/lib/cosensee/web_content_generator.rb +77 -0
- data/lib/cosensee/web_server/static_file_handler.rb +43 -0
- data/lib/cosensee/web_server.rb +38 -0
- data/lib/cosensee.rb +45 -20
- data/templates/index.html.erb +49 -27
- data/templates/page.html.erb +85 -29
- metadata +114 -23
- data/lib/cosensee/blank_bracket.rb +0 -8
- data/lib/cosensee/code.rb +0 -18
- data/lib/cosensee/codeblock.rb +0 -18
- data/lib/cosensee/command_line.rb +0 -18
- data/lib/cosensee/decorate_bracket.rb +0 -16
- data/lib/cosensee/double_bracket.rb +0 -20
- data/lib/cosensee/empty_bracket.rb +0 -8
- data/lib/cosensee/external_link_bracket.rb +0 -8
- data/lib/cosensee/formula_bracket.rb +0 -8
- data/lib/cosensee/hash_tag.rb +0 -19
- data/lib/cosensee/icon_bracket.rb +0 -8
- data/lib/cosensee/image_bracket.rb +0 -8
- data/lib/cosensee/indent.rb +0 -25
- data/lib/cosensee/internal_link_bracket.rb +0 -8
- data/lib/cosensee/line.rb +0 -47
- data/lib/cosensee/link.rb +0 -18
- data/lib/cosensee/quote.rb +0 -22
- data/lib/cosensee/tailwind_renderer/codeblock_builder.rb +0 -37
- data/lib/cosensee/text_bracket.rb +0 -10
data/lib/cosensee/parsed_line.rb
CHANGED
|
@@ -3,18 +3,20 @@
|
|
|
3
3
|
module Cosensee
|
|
4
4
|
# parse a line
|
|
5
5
|
class ParsedLine
|
|
6
|
-
def initialize(indent: nil, line_content: nil, content: [], rest: nil, parsed: false)
|
|
6
|
+
def initialize(indent: nil, line_content: nil, content: [], rest: nil, raw: '', parsed: false)
|
|
7
7
|
@indent = indent
|
|
8
8
|
@line_content = line_content
|
|
9
9
|
@content = content
|
|
10
10
|
@rest = rest
|
|
11
|
+
@raw = raw
|
|
11
12
|
@parsed = parsed
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
attr_accessor :indent, :line_content, :content, :rest, :parsed
|
|
16
|
+
attr_reader :raw
|
|
15
17
|
|
|
16
18
|
def codeblock?
|
|
17
|
-
line_content.is_a?(Cosensee::Codeblock)
|
|
19
|
+
line_content.is_a?(Cosensee::Node::Codeblock)
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def parsed?
|
|
@@ -25,10 +27,26 @@ module Cosensee
|
|
|
25
27
|
!!rest
|
|
26
28
|
end
|
|
27
29
|
|
|
30
|
+
def song_tagged?
|
|
31
|
+
content.any? { |elem| elem.is_a?(Node::HashTag) && elem.anchor == '楽曲' }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def first_image
|
|
35
|
+
if line_content?
|
|
36
|
+
line_content.is_a?(Node::Quote) && line_content.content.find { |elem| elem.is_a?(Node::ImageBracket) || elem.is_a?(Node::GyazoImageBracket) }
|
|
37
|
+
else
|
|
38
|
+
content.find { |elem| elem.is_a?(Node::ImageBracket) || elem.is_a?(Node::GyazoImageBracket) }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
28
42
|
def line_content?
|
|
29
43
|
!!line_content
|
|
30
44
|
end
|
|
31
45
|
|
|
46
|
+
def append_text(text:, raw_line:)
|
|
47
|
+
self.line_content = line_content.append_text(text:, raw_line:)
|
|
48
|
+
end
|
|
49
|
+
|
|
32
50
|
def indent_level
|
|
33
51
|
indent.level
|
|
34
52
|
end
|
|
@@ -53,14 +71,14 @@ module Cosensee
|
|
|
53
71
|
end
|
|
54
72
|
|
|
55
73
|
def internal_links
|
|
56
|
-
content.select { |c| c.is_a?(Cosensee::InternalLinkBracket) || c.is_a?(Cosensee::HashTag) }.map(&:anchor)
|
|
74
|
+
content.select { |c| c.is_a?(Cosensee::Node::InternalLinkBracket) || c.is_a?(Cosensee::Node::HashTag) }.map(&:anchor)
|
|
57
75
|
end
|
|
58
76
|
|
|
59
|
-
def
|
|
77
|
+
def to_s
|
|
60
78
|
if line_content?
|
|
61
|
-
|
|
79
|
+
line_content.to_s
|
|
62
80
|
else
|
|
63
|
-
|
|
81
|
+
content.map(&:to_s).join
|
|
64
82
|
end
|
|
65
83
|
end
|
|
66
84
|
|
data/lib/cosensee/project.rb
CHANGED
|
@@ -5,18 +5,20 @@ require 'json'
|
|
|
5
5
|
module Cosensee
|
|
6
6
|
# for Project
|
|
7
7
|
class Project
|
|
8
|
-
|
|
8
|
+
extend Delegatable
|
|
9
|
+
|
|
10
|
+
def self.parse(source, renderer_class:)
|
|
9
11
|
json = JSON.parse(source, symbolize_names: true)
|
|
10
12
|
name, display_name, exported, users, pages = json.values_at(:name, :displayName, :exported, :users, :pages)
|
|
11
|
-
Cosensee::Project.new(name:, display_name:, exported:, users:, pages:, source:)
|
|
13
|
+
Cosensee::Project.new(name:, display_name:, exported:, users:, pages:, source:, renderer_class:)
|
|
12
14
|
end
|
|
13
15
|
|
|
14
|
-
def self.parse_file(filename)
|
|
16
|
+
def self.parse_file(filename, renderer_class:)
|
|
15
17
|
src = File.read(filename)
|
|
16
|
-
parse(src)
|
|
18
|
+
parse(src, renderer_class:)
|
|
17
19
|
end
|
|
18
20
|
|
|
19
|
-
def initialize(name:, exported:, users:, pages:, source:, **kwargs)
|
|
21
|
+
def initialize(name:, exported:, users:, pages:, source:, renderer_class:, **kwargs)
|
|
20
22
|
@name = name
|
|
21
23
|
@display_name = if kwargs.keys.size == 1 && kwargs.key?(:display_name)
|
|
22
24
|
kwargs[:display_name]
|
|
@@ -31,9 +33,22 @@ module Cosensee
|
|
|
31
33
|
@source = source
|
|
32
34
|
|
|
33
35
|
@page_store = PageStore.new(project: self)
|
|
36
|
+
@renderer_class = renderer_class
|
|
34
37
|
end
|
|
35
38
|
|
|
36
|
-
attr_reader :name, :display_name, :users, :pages, :exported, :source, :page_store
|
|
39
|
+
attr_reader :name, :display_name, :users, :pages, :exported, :source, :page_store, :renderer_class
|
|
40
|
+
|
|
41
|
+
delegate :orphan_page_titles, :dump_search_data, :find_page_by_title, to: :page_store
|
|
42
|
+
|
|
43
|
+
def sorted_pages_for_top
|
|
44
|
+
pinned_pages = page_store.pinned_pages
|
|
45
|
+
if pinned_pages.empty?
|
|
46
|
+
pages.sort_by(&:updated).reverse
|
|
47
|
+
else
|
|
48
|
+
unpinned_pages = pages - pinned_pages
|
|
49
|
+
pinned_pages + unpinned_pages.sort_by(&:updated).reverse
|
|
50
|
+
end
|
|
51
|
+
end
|
|
37
52
|
|
|
38
53
|
def to_obj
|
|
39
54
|
{ name:, displayName: display_name, exported: exported.to_i, users:, pages: }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cosensee
|
|
4
|
+
# provide `renderer_class` method
|
|
5
|
+
module RenderClassFindable
|
|
6
|
+
# ex. Cosensee::TailwindRenderer::Code for Cosensee::Node::Code
|
|
7
|
+
def find_renderer_class(content)
|
|
8
|
+
name = content.class.name.split('::').last
|
|
9
|
+
|
|
10
|
+
Cosensee::TailwindRenderer.const_get(name)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'tailwindcss/ruby'
|
|
4
|
+
|
|
5
|
+
module Cosensee
|
|
6
|
+
# build TailwindCSS Command, based on https://github.com/rails/tailwindcss-rails
|
|
7
|
+
module TailwindCommand
|
|
8
|
+
def self.compile_command(output_dir: Cosensee::DEFAULT_OUTPUT_DIR, css_dir: DEFAULT_CSS_DIR, debug: false, **)
|
|
9
|
+
command = [
|
|
10
|
+
Tailwindcss::Ruby.executable(**),
|
|
11
|
+
'-i', File.join(__dir__, '../../assets/styles/input.css'),
|
|
12
|
+
'-o', File.join(output_dir, css_dir, 'tailwind.css'),
|
|
13
|
+
'-c', Cosensee::TAILWIND_CONFIG_FILE
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
command << '--minify' unless debug
|
|
17
|
+
|
|
18
|
+
postcss_path = 'postcss.config.js'
|
|
19
|
+
command += ['--postcss', postcss_path.to_s] if File.exist?(postcss_path)
|
|
20
|
+
|
|
21
|
+
command
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cosensee
|
|
4
|
+
class TailwindRenderer
|
|
5
|
+
# codeblock renderer
|
|
6
|
+
Codeblock = Data.define(:content, :project) do
|
|
7
|
+
include HtmlEncodable
|
|
8
|
+
|
|
9
|
+
def render
|
|
10
|
+
title = content.name
|
|
11
|
+
|
|
12
|
+
# !!! EXTENSION: if name ends with .svgtext, render as inline SVG text
|
|
13
|
+
return InlineSvgText.new(content:, project:).render if title.match?(/\.svgtext$/)
|
|
14
|
+
|
|
15
|
+
<<~HTML_BLOCK
|
|
16
|
+
<div class="bg-orange-300 text-gray-900 px-4 py-1 rounded-t-lg font-mono text-sm">#{title}</div>
|
|
17
|
+
<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>
|
|
18
|
+
HTML_BLOCK
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module Cosensee
|
|
4
4
|
class TailwindRenderer
|
|
5
|
-
DoubleBracket = Data.define(:content) do
|
|
5
|
+
DoubleBracket = Data.define(:content, :project) do
|
|
6
6
|
def render
|
|
7
|
-
rendered_content = Cosensee::TailwindRenderer.new(content: content.content).render
|
|
7
|
+
rendered_content = Cosensee::TailwindRenderer.new(content: content.content, project:).render
|
|
8
8
|
|
|
9
9
|
%(<span class="font-bold">#{rendered_content}</span>)
|
|
10
10
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cosensee
|
|
4
|
+
class TailwindRenderer
|
|
5
|
+
GyazoImageBracket = Data.define(:content, :project) do
|
|
6
|
+
def render
|
|
7
|
+
if content.link
|
|
8
|
+
%(<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>)
|
|
9
|
+
else
|
|
10
|
+
%(<span><img loading="lazy" src="https://gyazo.com/#{content.image_id}/raw" class="max-w-max max-h-80"></span>)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
module Cosensee
|
|
4
4
|
class TailwindRenderer
|
|
5
|
-
IconBracket = Data.define(:content) do
|
|
5
|
+
IconBracket = Data.define(:content, :project) do
|
|
6
6
|
include HtmlEncodable
|
|
7
7
|
|
|
8
8
|
def render
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
page = project.find_page_by_title(content.icon_name)
|
|
10
|
+
icon_src = page&.first_image&.src
|
|
11
|
+
%(<img src="#{icon_src}" loading="lazy" alt="icon" class="inline-block h-5 w-5 align-middle">)
|
|
11
12
|
end
|
|
12
13
|
end
|
|
13
14
|
end
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module Cosensee
|
|
4
4
|
class TailwindRenderer
|
|
5
|
-
ImageBracket = Data.define(:content) do
|
|
5
|
+
ImageBracket = Data.define(:content, :project) do
|
|
6
6
|
def render
|
|
7
7
|
if content.link
|
|
8
|
-
%(<span><a href="#{content.link}"><img src="#{content.src}" class="max-w-max max-h-80"></a></span>)
|
|
8
|
+
%(<span><a href="#{content.link}"><img src="#{content.src}" loading="lazy" class="max-w-max max-h-80"></a></span>)
|
|
9
9
|
else
|
|
10
|
-
%(<span><img src="#{content.src}" class="max-w-max max-h-80"></span>)
|
|
10
|
+
%(<span><img src="#{content.src}" loading="lazy" class="max-w-max max-h-80"></span>)
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cosensee
|
|
4
|
+
class TailwindRenderer
|
|
5
|
+
# extended renderer for inline SVG text
|
|
6
|
+
InlineSvgText = Data.define(:content, :project) do
|
|
7
|
+
include HtmlEncodable
|
|
8
|
+
|
|
9
|
+
def render
|
|
10
|
+
output = <<~SVG_TEXT_HEADER
|
|
11
|
+
<svg style="inherit" xmlns="http://www.w3.org/2000/svg" class="svg-text">
|
|
12
|
+
<style>
|
|
13
|
+
.text { -ms-user-select: none; -webkit-user-select: none; user-select: none; }
|
|
14
|
+
@media print { .svg-text { display: none !important; } text { display: none !important; } }
|
|
15
|
+
</style>
|
|
16
|
+
<text x="0" y="0" font-size="inherit" class="text" fill="break">
|
|
17
|
+
SVG_TEXT_HEADER
|
|
18
|
+
|
|
19
|
+
content.content.lines.each do |line|
|
|
20
|
+
tspan_text = if line.strip.empty?
|
|
21
|
+
' '
|
|
22
|
+
else
|
|
23
|
+
escape_html(line.chomp)
|
|
24
|
+
end
|
|
25
|
+
output << %(<tspan x="0" dy="1.4em">#{tspan_text}</tspan>\n)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
output << <<~SVG_TEXT_FOOTER
|
|
29
|
+
</text>
|
|
30
|
+
</svg>
|
|
31
|
+
SVG_TEXT_FOOTER
|
|
32
|
+
|
|
33
|
+
output
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -2,26 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
module Cosensee
|
|
4
4
|
class TailwindRenderer
|
|
5
|
-
Page = Data.define(:content) do
|
|
5
|
+
Page = Data.define(:content, :project) do
|
|
6
6
|
def render
|
|
7
|
-
current_block_builder = nil
|
|
8
|
-
|
|
9
7
|
page = content
|
|
10
|
-
rendered_lines =
|
|
11
|
-
|
|
12
|
-
page.parsed_lines.each do |parsed_line|
|
|
13
|
-
if current_block_builder
|
|
14
|
-
if current_block_builder.continued_line?(parsed_line)
|
|
15
|
-
current_block_builder.append(parsed_line)
|
|
16
|
-
else
|
|
17
|
-
rendered_lines << current_block_builder.render
|
|
18
|
-
rendered_lines << ParsedLine.new(parsed_line).render
|
|
19
|
-
end
|
|
20
|
-
elsif parsed_line.codeblock?
|
|
21
|
-
current_block_builder = CodeblockBuilder.new(parsed_line)
|
|
22
|
-
else
|
|
23
|
-
rendered_lines << ParsedLine.new(parsed_line).render
|
|
24
|
-
end
|
|
8
|
+
rendered_lines = page.parsed_lines.map do |parsed_line|
|
|
9
|
+
ParsedLine.new(parsed_line, project).render
|
|
25
10
|
end
|
|
26
11
|
|
|
27
12
|
rendered_lines.join
|
|
@@ -2,18 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
module Cosensee
|
|
4
4
|
class TailwindRenderer
|
|
5
|
-
ParsedLine = Data.define(:content) do
|
|
5
|
+
ParsedLine = Data.define(:content, :project) do
|
|
6
6
|
include HtmlEncodable
|
|
7
|
+
include RenderClassFindable
|
|
7
8
|
|
|
8
9
|
def render
|
|
9
10
|
result = if content.line_content?
|
|
10
|
-
|
|
11
|
+
find_renderer_class(content.line_content).new(content: content.line_content, project:).render
|
|
11
12
|
else
|
|
12
13
|
content.content.map do |c|
|
|
13
14
|
if c.is_a?(String)
|
|
14
15
|
escape_html(c)
|
|
15
16
|
else
|
|
16
|
-
TailwindRenderer.new(content: c).render
|
|
17
|
+
TailwindRenderer.new(content: c, project:).render
|
|
17
18
|
end
|
|
18
19
|
end.join
|
|
19
20
|
end
|
|
@@ -4,9 +4,9 @@ require 'json'
|
|
|
4
4
|
|
|
5
5
|
module Cosensee
|
|
6
6
|
class TailwindRenderer
|
|
7
|
-
Quote = Data.define(:content) do
|
|
7
|
+
Quote = Data.define(:content, :project) do
|
|
8
8
|
def render
|
|
9
|
-
code = Cosensee::TailwindRenderer.new(content: content.content).render
|
|
9
|
+
code = Cosensee::TailwindRenderer.new(content: content.content, project:).render
|
|
10
10
|
%(<blockquote class="border-l-4 border-gray-300 bg-gray-100 px-4 text-gray-800">#{code}</blockquote>)
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cosensee
|
|
4
|
+
class TailwindRenderer
|
|
5
|
+
SpotifyPlaylistBracket = Data.define(:content, :project) do
|
|
6
|
+
def render
|
|
7
|
+
%(<iframe src="https://open.spotify.com/embed/playlist/#{content.playlist_id}" class="w-full h-96" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe>)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module Cosensee
|
|
4
4
|
class TailwindRenderer
|
|
5
|
-
TextBracket = Data.define(:content) do
|
|
5
|
+
TextBracket = Data.define(:content, :project) do
|
|
6
6
|
def render
|
|
7
|
-
rendered = TailwindRenderer.new(content: content.content).render
|
|
7
|
+
rendered = TailwindRenderer.new(content: content.content, project:).render
|
|
8
8
|
%(<span>[#{rendered}]</span>)
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cosensee
|
|
4
|
+
class TailwindRenderer
|
|
5
|
+
YoutubeBracket = Data.define(:content, :project) do
|
|
6
|
+
def render
|
|
7
|
+
%(<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>)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -4,13 +4,15 @@ module Cosensee
|
|
|
4
4
|
# convert into html
|
|
5
5
|
class TailwindRenderer
|
|
6
6
|
include HtmlEncodable
|
|
7
|
+
include RenderClassFindable
|
|
7
8
|
|
|
8
9
|
# content is Cosensee objects or an array of them
|
|
9
|
-
def initialize(content:)
|
|
10
|
+
def initialize(content:, project:)
|
|
10
11
|
@content = content
|
|
12
|
+
@project = project
|
|
11
13
|
end
|
|
12
14
|
|
|
13
|
-
attr_reader :content
|
|
15
|
+
attr_reader :content, :project
|
|
14
16
|
|
|
15
17
|
def render
|
|
16
18
|
if content.is_a?(Array)
|
|
@@ -18,19 +20,12 @@ module Cosensee
|
|
|
18
20
|
if c.is_a?(String)
|
|
19
21
|
escape_html(c)
|
|
20
22
|
else
|
|
21
|
-
|
|
23
|
+
find_renderer_class(c).new(content: c, project:).render
|
|
22
24
|
end
|
|
23
25
|
end.join
|
|
24
26
|
else
|
|
25
|
-
|
|
27
|
+
find_renderer_class(content).new(content:, project:).render
|
|
26
28
|
end
|
|
27
29
|
end
|
|
28
|
-
|
|
29
|
-
# ex. Cosensee::TailwindRenderer::Code for Cosensee::Code
|
|
30
|
-
def renderer_class(content)
|
|
31
|
-
name = content.class.name.split('::').last
|
|
32
|
-
|
|
33
|
-
Cosensee::TailwindRenderer.const_get(name)
|
|
34
|
-
end
|
|
35
30
|
end
|
|
36
31
|
end
|
data/lib/cosensee/user.rb
CHANGED
|
@@ -6,7 +6,13 @@ module Cosensee
|
|
|
6
6
|
# for User
|
|
7
7
|
User = Data.define(:id, :name, :display_name, :email) do
|
|
8
8
|
def self.from_array(users_args)
|
|
9
|
-
users_args.map
|
|
9
|
+
users_args.map do |args|
|
|
10
|
+
if args.is_a?(Cosensee::User)
|
|
11
|
+
args
|
|
12
|
+
else
|
|
13
|
+
new(**args)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
10
16
|
end
|
|
11
17
|
|
|
12
18
|
# allow both `:display_key` and `:displayKey`
|
data/lib/cosensee/version.rb
CHANGED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cosensee
|
|
4
|
+
# convert project file to web content
|
|
5
|
+
class WebContentGenerator
|
|
6
|
+
extend Cosensee::Delegatable
|
|
7
|
+
|
|
8
|
+
class Error < StandardError; end
|
|
9
|
+
|
|
10
|
+
SEARCH_DATA_PATH = 'search.json'
|
|
11
|
+
|
|
12
|
+
attr_reader :option, :logger, :sid, :skip_tailwind_execution, :renderer_class
|
|
13
|
+
|
|
14
|
+
def initialize(option:, renderer_class:, logger:, sid:)
|
|
15
|
+
@option = option
|
|
16
|
+
@renderer_class = renderer_class
|
|
17
|
+
@logger = logger
|
|
18
|
+
@sid = sid
|
|
19
|
+
@skip_tailwind_execution = option.skip_tailwind_execution?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def generate
|
|
23
|
+
raise Error, 'Filename is missing.' unless filename
|
|
24
|
+
|
|
25
|
+
download_page_data(sid) if option.remote?
|
|
26
|
+
|
|
27
|
+
raise Error, "File not found - #{filename}" unless File.exist?(filename)
|
|
28
|
+
|
|
29
|
+
logger.info "Processing file: #{filename}"
|
|
30
|
+
project = Cosensee::Project.parse_file(filename, renderer_class:)
|
|
31
|
+
Cosensee::HtmlBuilder.new(project, output_dir: option.output_dir, base_url: option.base_url).build_all(clean: option.clean?)
|
|
32
|
+
logger.info "Build all files into #{option.output_dir}."
|
|
33
|
+
|
|
34
|
+
copy_js_files
|
|
35
|
+
|
|
36
|
+
execute_tailwind unless skip_tailwind_execution
|
|
37
|
+
|
|
38
|
+
dump_search_data(project)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def execute_tailwind
|
|
42
|
+
FileUtils.mkdir_p(File.join(option.output_dir, option.css_dir))
|
|
43
|
+
command = Cosensee::TailwindCommand.compile_command(output_dir: option.output_dir, css_dir: option.css_dir, debug: false)
|
|
44
|
+
logger.info "Processing TailwindCSS: #{command.inspect}"
|
|
45
|
+
system(*command, exception: true)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def dump_search_data(project)
|
|
49
|
+
data = project.dump_search_data
|
|
50
|
+
File.write(File.join(option.output_dir, SEARCH_DATA_PATH), data.to_json)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
delegate :filename, :project_name, to: :option
|
|
56
|
+
|
|
57
|
+
def download_page_data(sid)
|
|
58
|
+
raise Error, 'You must set CONNECT_SID as environment variable.' unless sid
|
|
59
|
+
|
|
60
|
+
logger.info 'Retrieving file from remote API...'
|
|
61
|
+
Cosensee::Api::PageData.new.download(
|
|
62
|
+
project_name:,
|
|
63
|
+
sid:,
|
|
64
|
+
filename:
|
|
65
|
+
)
|
|
66
|
+
logger.info "File retrieved and saved as: #{filename}"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def copy_js_files
|
|
70
|
+
FileUtils.mkdir_p(File.join(option.output_dir, 'js'))
|
|
71
|
+
Dir.glob("#{__dir__}/../../assets/js/*.js") do |path|
|
|
72
|
+
js_file = File.basename(path)
|
|
73
|
+
FileUtils.cp(path, File.join(option.output_dir, 'js', js_file))
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|