cosensee 0.6.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|