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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +13 -2
  3. data/README.md +25 -7
  4. data/Rakefile +1 -1
  5. data/assets/js/search.js +42 -0
  6. data/assets/styles/input.css +3 -0
  7. data/exe/cosensee +36 -0
  8. data/lib/cosensee/api/page_data.rb +43 -0
  9. data/lib/cosensee/bracket_parser.rb +21 -16
  10. data/lib/cosensee/bracket_serializer.rb +3 -1
  11. data/lib/cosensee/cli/initializer.rb +64 -0
  12. data/lib/cosensee/cli/option.rb +65 -0
  13. data/lib/cosensee/cli/parser.rb +83 -0
  14. data/lib/cosensee/delegatable.rb +33 -0
  15. data/lib/cosensee/html_builder.rb +26 -17
  16. data/lib/cosensee/line_parser.rb +29 -16
  17. data/lib/cosensee/node/blank_bracket.rb +10 -0
  18. data/lib/cosensee/node/code.rb +20 -0
  19. data/lib/cosensee/node/codeblock.rb +32 -0
  20. data/lib/cosensee/node/command_line.rb +20 -0
  21. data/lib/cosensee/node/decorate_bracket.rb +23 -0
  22. data/lib/cosensee/node/double_bracket.rb +22 -0
  23. data/lib/cosensee/node/empty_bracket.rb +10 -0
  24. data/lib/cosensee/node/external_link_bracket.rb +10 -0
  25. data/lib/cosensee/node/formula_bracket.rb +10 -0
  26. data/lib/cosensee/node/gyazo_image_bracket.rb +10 -0
  27. data/lib/cosensee/node/hash_tag.rb +21 -0
  28. data/lib/cosensee/node/icon_bracket.rb +10 -0
  29. data/lib/cosensee/node/image_bracket.rb +10 -0
  30. data/lib/cosensee/node/indent.rb +27 -0
  31. data/lib/cosensee/node/internal_link_bracket.rb +10 -0
  32. data/lib/cosensee/node/link.rb +20 -0
  33. data/lib/cosensee/node/quote.rb +26 -0
  34. data/lib/cosensee/node/spotify_playlist_bracket.rb +10 -0
  35. data/lib/cosensee/node/text_bracket.rb +12 -0
  36. data/lib/cosensee/node/youtube_bracket.rb +10 -0
  37. data/lib/cosensee/page.rb +46 -16
  38. data/lib/cosensee/page_store.rb +25 -2
  39. data/lib/cosensee/parsed_line.rb +24 -6
  40. data/lib/cosensee/project.rb +21 -6
  41. data/lib/cosensee/render_class_findable.rb +13 -0
  42. data/lib/cosensee/tailwind_command.rb +24 -0
  43. data/lib/cosensee/tailwind_renderer/blank_bracket.rb +1 -1
  44. data/lib/cosensee/tailwind_renderer/code.rb +1 -1
  45. data/lib/cosensee/tailwind_renderer/codeblock.rb +22 -0
  46. data/lib/cosensee/tailwind_renderer/command_line.rb +1 -1
  47. data/lib/cosensee/tailwind_renderer/decorate_bracket.rb +1 -1
  48. data/lib/cosensee/tailwind_renderer/double_bracket.rb +2 -2
  49. data/lib/cosensee/tailwind_renderer/empty_bracket.rb +1 -1
  50. data/lib/cosensee/tailwind_renderer/external_link_bracket.rb +1 -1
  51. data/lib/cosensee/tailwind_renderer/formula_bracket.rb +1 -1
  52. data/lib/cosensee/tailwind_renderer/gyazo_image_bracket.rb +15 -0
  53. data/lib/cosensee/tailwind_renderer/hash_tag.rb +1 -1
  54. data/lib/cosensee/tailwind_renderer/icon_bracket.rb +4 -3
  55. data/lib/cosensee/tailwind_renderer/image_bracket.rb +3 -3
  56. data/lib/cosensee/tailwind_renderer/inline_svg_text.rb +37 -0
  57. data/lib/cosensee/tailwind_renderer/internal_link_bracket.rb +1 -1
  58. data/lib/cosensee/tailwind_renderer/link.rb +1 -1
  59. data/lib/cosensee/tailwind_renderer/page.rb +3 -18
  60. data/lib/cosensee/tailwind_renderer/parsed_line.rb +4 -3
  61. data/lib/cosensee/tailwind_renderer/quote.rb +2 -2
  62. data/lib/cosensee/tailwind_renderer/spotify_playlist_bracket.rb +11 -0
  63. data/lib/cosensee/tailwind_renderer/text_bracket.rb +2 -2
  64. data/lib/cosensee/tailwind_renderer/youtube_bracket.rb +11 -0
  65. data/lib/cosensee/tailwind_renderer.rb +6 -11
  66. data/lib/cosensee/user.rb +7 -1
  67. data/lib/cosensee/version.rb +1 -1
  68. data/lib/cosensee/web_content_generator.rb +77 -0
  69. data/lib/cosensee/web_server/static_file_handler.rb +43 -0
  70. data/lib/cosensee/web_server.rb +38 -0
  71. data/lib/cosensee.rb +45 -20
  72. data/templates/index.html.erb +49 -27
  73. data/templates/page.html.erb +85 -29
  74. metadata +114 -23
  75. data/lib/cosensee/blank_bracket.rb +0 -8
  76. data/lib/cosensee/code.rb +0 -18
  77. data/lib/cosensee/codeblock.rb +0 -18
  78. data/lib/cosensee/command_line.rb +0 -18
  79. data/lib/cosensee/decorate_bracket.rb +0 -16
  80. data/lib/cosensee/double_bracket.rb +0 -20
  81. data/lib/cosensee/empty_bracket.rb +0 -8
  82. data/lib/cosensee/external_link_bracket.rb +0 -8
  83. data/lib/cosensee/formula_bracket.rb +0 -8
  84. data/lib/cosensee/hash_tag.rb +0 -19
  85. data/lib/cosensee/icon_bracket.rb +0 -8
  86. data/lib/cosensee/image_bracket.rb +0 -8
  87. data/lib/cosensee/indent.rb +0 -25
  88. data/lib/cosensee/internal_link_bracket.rb +0 -8
  89. data/lib/cosensee/line.rb +0 -47
  90. data/lib/cosensee/link.rb +0 -18
  91. data/lib/cosensee/quote.rb +0 -22
  92. data/lib/cosensee/tailwind_renderer/codeblock_builder.rb +0 -37
  93. data/lib/cosensee/text_bracket.rb +0 -10
@@ -14,12 +14,25 @@ module Cosensee
14
14
  new.parse(line)
15
15
  end
16
16
 
17
+ def self.merge_blocks(lines)
18
+ prev_line = nil
19
+ lines.each_with_object([]) do |line, result|
20
+ if prev_line&.codeblock? && prev_line.indent_level < line.indent_level
21
+ text = line.raw[prev_line.indent_level..]
22
+ prev_line.append_text(text:, raw_line: line.raw)
23
+ else
24
+ result << line
25
+ prev_line = line
26
+ end
27
+ end
28
+ end
29
+
17
30
  def initialize
18
31
  @bracket_parser = Cosensee::BracketParser.new
19
32
  end
20
33
 
21
34
  def parse(line)
22
- parsed_line = ParsedLine.new(rest: line)
35
+ parsed_line = ParsedLine.new(rest: line, raw: line)
23
36
  parsed_line
24
37
  .then { parse_indent(it) }
25
38
  .then { parse_whole_line(it) }
@@ -33,8 +46,8 @@ module Cosensee
33
46
 
34
47
  def parse_indent(line)
35
48
  matched = line.match(INDENT_PATTERN)
36
- ParsedLine.new(indent: Cosensee::Indent.new(matched[1], matched[1]),
37
- rest: matched[2])
49
+ ParsedLine.new(indent: Cosensee::Node::Indent.new(matched[1], matched[1]),
50
+ rest: matched[2], raw: line.raw)
38
51
  end
39
52
 
40
53
  def parse_whole_line(line)
@@ -42,7 +55,7 @@ module Cosensee
42
55
  matched = line.match(QUOTE_PATTERN)
43
56
  if matched
44
57
  line.update(rest: matched[2],
45
- line_content: Cosensee::Quote.new(content: nil, raw: matched[0], mark: matched[1]))
58
+ line_content: Cosensee::Node::Quote.new(content: nil, raw: matched[0], mark: matched[1]))
46
59
  return line
47
60
  end
48
61
 
@@ -50,7 +63,7 @@ module Cosensee
50
63
  matched = line.match(CODEBLOCK_PATTERN)
51
64
  if matched
52
65
  return line.update(rest: nil,
53
- line_content: Cosensee::Codeblock.new(content: matched[2], raw: matched[0]),
66
+ line_content: Cosensee::Node::Codeblock.new(content: '', name: matched[2], raw: matched[0]),
54
67
  parsed: true)
55
68
  end
56
69
 
@@ -58,9 +71,9 @@ module Cosensee
58
71
  matched = line.match(COMMANDLINE_PATTERN)
59
72
  if matched
60
73
  return line.update(rest: nil,
61
- line_content: Cosensee::CommandLine.new(content: matched[2],
62
- prompt: matched[1],
63
- raw: matched[0]),
74
+ line_content: Cosensee::Node::CommandLine.new(content: matched[2],
75
+ prompt: matched[1],
76
+ raw: matched[0]),
64
77
  parsed: true)
65
78
  end
66
79
 
@@ -93,7 +106,7 @@ module Cosensee
93
106
  return line.update(rest: nil,
94
107
  content: parsed)
95
108
  else
96
- parsed << Code.new(str, "`#{str}`")
109
+ parsed << Node::Code.new(str, "`#{str}`")
97
110
  end
98
111
  end
99
112
  end
@@ -109,7 +122,7 @@ module Cosensee
109
122
  matched = elem.match(/(^|\s)#(\S+)/)
110
123
  if matched
111
124
  parsed << "#{matched.pre_match}#{matched[1]}"
112
- parsed << Cosensee::HashTag.new(content: matched[2], raw: "##{matched[2]}")
125
+ parsed << Cosensee::Node::HashTag.new(content: matched[2], raw: "##{matched[2]}")
113
126
  elem = matched.post_match
114
127
  else
115
128
  parsed << elem
@@ -132,10 +145,10 @@ module Cosensee
132
145
  line.content.each do |elem|
133
146
  if elem.is_a?(String)
134
147
  loop do
135
- matched = elem.match(%r{(^|\s)(https?://[^\s]+)})
148
+ matched = elem.match(%r{(^|.*?)(https?://[^\s]+)})
136
149
  if matched
137
150
  parsed << "#{matched.pre_match}#{matched[1]}"
138
- parsed << Cosensee::Link.new(matched[2], matched[2])
151
+ parsed << Cosensee::Node::Link.new(matched[2], matched[2])
139
152
  elem = matched.post_match
140
153
  else
141
154
  parsed << elem
@@ -161,7 +174,7 @@ module Cosensee
161
174
  matched = elem.match(/\[\[(.+?)\]\]/)
162
175
  if matched
163
176
  parsed << matched.pre_match
164
- parsed << Cosensee::DoubleBracket.new(content: [matched[1]], raw: matched[0])
177
+ parsed << Cosensee::Node::DoubleBracket.new(content: [matched[1]], raw: matched[0])
165
178
  elem = matched.post_match
166
179
  else
167
180
  parsed << elem
@@ -185,7 +198,7 @@ module Cosensee
185
198
 
186
199
  line.content.each do |elem|
187
200
  case elem
188
- when Cosensee::Code, Cosensee::DoubleBracket
201
+ when Cosensee::Node::Code, Cosensee::Node::DoubleBracket
189
202
  if target_char == '['
190
203
  parsed << elem
191
204
  else
@@ -228,8 +241,8 @@ module Cosensee
228
241
  end
229
242
 
230
243
  def done_parsing(line)
231
- # If the line_content is Cosensee::Quote, move content into it.
232
- if line.line_content.is_a?(Cosensee::Quote)
244
+ # If the line_content is Cosensee::Node::Quote, move content into it.
245
+ if line.line_content.is_a?(Cosensee::Node::Quote)
233
246
  new_quote = line.line_content.replace_content(line.content)
234
247
  line.update(line_content: new_quote, content: [])
235
248
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cosensee
4
+ module Node
5
+ # for bracket only spaces
6
+ BlankBracket = Data.define(:content, :blank, :raw) do
7
+ include BracketSerializer
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Cosensee
6
+ module Node
7
+ # parse a line
8
+ Code = Data.define(:content, :raw) do
9
+ alias_method :to_s, :raw
10
+
11
+ def to_obj
12
+ "`#{content}`"
13
+ end
14
+
15
+ def to_json(*)
16
+ to_obj.to_json(*)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Cosensee
6
+ module Node
7
+ # for codeblock
8
+ Codeblock = Data.define(:content, :name, :raw) do
9
+ alias_method :to_s, :raw
10
+
11
+ # @param [String] text
12
+ # @param [String] raw_line
13
+ # @return [Codeblock]
14
+ def append_text(text:, raw_line:)
15
+ new_content = if content && !content.empty?
16
+ "#{content}\n#{text}"
17
+ else
18
+ text
19
+ end
20
+ Codeblock.new(content: new_content, name:, raw: "#{raw}\n#{raw_line}")
21
+ end
22
+
23
+ def to_obj
24
+ "code:#{content}"
25
+ end
26
+
27
+ def to_json(*)
28
+ to_obj.to_json(*)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Cosensee
6
+ module Node
7
+ # for command line
8
+ CommandLine = Data.define(:content, :prompt, :raw) do
9
+ alias_method :to_s, :raw
10
+
11
+ def to_obj
12
+ "#{prompt} #{content}"
13
+ end
14
+
15
+ def to_json(*)
16
+ to_obj.to_json(*)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cosensee
4
+ module Node
5
+ # for Decorate
6
+ DecorateBracket = Data.define(
7
+ :content,
8
+ :font_size,
9
+ :underlined,
10
+ :slanted,
11
+ :deleted,
12
+ :text,
13
+ :raw
14
+ ) do
15
+ include BracketSerializer
16
+
17
+ # override
18
+ def to_s
19
+ text
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cosensee
4
+ module Node
5
+ # for double Bracket
6
+ DoubleBracket = Data.define(:content, :raw) do
7
+ def image?
8
+ content.size == 1 && content[0].match?(/\.(png|jpg)$/)
9
+ end
10
+
11
+ alias_method :to_s, :raw
12
+
13
+ def to_obj
14
+ "[[#{content}]]"
15
+ end
16
+
17
+ def to_json(*)
18
+ to_obj.to_json(*)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cosensee
4
+ module Node
5
+ # for empty bracket
6
+ EmptyBracket = Data.define(:content, :raw) do
7
+ include BracketSerializer
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cosensee
4
+ module Node
5
+ # for Formula
6
+ ExternalLinkBracket = Data.define(:content, :link, :anchor, :raw) do
7
+ include BracketSerializer
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cosensee
4
+ module Node
5
+ # for Formula
6
+ FormulaBracket = Data.define(:content, :formula, :raw) do
7
+ include BracketSerializer
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cosensee
4
+ module Node
5
+ # for Image
6
+ GyazoImageBracket = Data.define(:content, :link, :src, :image_id, :raw) do
7
+ include BracketSerializer
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Cosensee
6
+ module Node
7
+ # parse a hash tag
8
+ HashTag = Data.define(:content, :raw) do
9
+ alias_method :to_s, :raw
10
+ alias_method :anchor, :content
11
+
12
+ def to_obj
13
+ "##{content}"
14
+ end
15
+
16
+ def to_json(*)
17
+ to_obj.to_json(*)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cosensee
4
+ module Node
5
+ # for Icon
6
+ IconBracket = Data.define(:content, :icon_name, :raw) do
7
+ include BracketSerializer
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cosensee
4
+ module Node
5
+ # for Image
6
+ ImageBracket = Data.define(:content, :link, :src, :raw) do
7
+ include BracketSerializer
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Cosensee
6
+ module Node
7
+ # for normal Text
8
+ Indent = Data.define(:content, :raw) do
9
+ def initialize(content: '', raw: '')
10
+ @level = content.size
11
+ super
12
+ end
13
+
14
+ attr_reader :level
15
+
16
+ alias_method :to_s, :raw
17
+
18
+ def to_obj
19
+ content
20
+ end
21
+
22
+ def to_json(*)
23
+ to_obj.to_json(*)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cosensee
4
+ module Node
5
+ # for Icon
6
+ InternalLinkBracket = Data.define(:content, :link, :anchor, :raw) do
7
+ include BracketSerializer
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Cosensee
6
+ module Node
7
+ # link node
8
+ Link = Data.define(:content, :raw) do
9
+ alias_method :to_s, :raw
10
+
11
+ def to_obj
12
+ content
13
+ end
14
+
15
+ def to_json(*)
16
+ to_obj.to_json(*)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Cosensee
6
+ module Node
7
+ # for quote
8
+ Quote = Data.define(:content, :raw, :mark) do
9
+ def replace_content(new_content)
10
+ Quote.new(content: new_content, raw:, mark:)
11
+ end
12
+
13
+ def to_s
14
+ content.map(&:to_s).join
15
+ end
16
+
17
+ def to_obj
18
+ content
19
+ end
20
+
21
+ def to_json(*)
22
+ to_obj.to_json(*)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cosensee
4
+ module Node
5
+ # for Spotify Playlist
6
+ SpotifyPlaylistBracket = Data.define(:content, :src, :playlist_id, :raw) do
7
+ include BracketSerializer
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Cosensee
6
+ module Node
7
+ # for mixed content (!= single text)
8
+ TextBracket = Data.define(:content, :raw) do
9
+ include BracketSerializer
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cosensee
4
+ module Node
5
+ # for Image
6
+ YoutubeBracket = Data.define(:content, :video_id, :raw) do
7
+ include BracketSerializer
8
+ end
9
+ end
10
+ end
data/lib/cosensee/page.rb CHANGED
@@ -7,16 +7,20 @@ module Cosensee
7
7
  # for Page
8
8
  Page = Data.define(:id, :title, :created, :updated, :views, :lines) do
9
9
  def self.from_array(args_list)
10
- args_list.map { |args| new(**args) }
11
- end
12
-
13
- def self.from_hash(obj)
14
- new(**obj)
10
+ args_list.map do |args|
11
+ if args.is_a?(Cosensee::Page)
12
+ args
13
+ else
14
+ new(**args)
15
+ end
16
+ end
15
17
  end
16
18
 
17
19
  def initialize(id:, title:, created:, updated:, views:, lines:)
18
- @parsed_lines = Cosensee::Line.from_array(lines.drop(1)).map(&:parsed)
20
+ temp_lines = lines.drop(1).map { |arg| LineParser.parse(arg) }
21
+ @parsed_lines = LineParser.merge_blocks(temp_lines)
19
22
  @linking_page_titles = @parsed_lines.map(&:internal_links).flatten
23
+ @first_image = @parsed_lines.find(&:first_image)&.first_image
20
24
 
21
25
  super(
22
26
  id:,
@@ -28,29 +32,55 @@ module Cosensee
28
32
  )
29
33
  end
30
34
 
31
- attr_accessor :parsed_lines, :linking_page_titles
35
+ attr_accessor :parsed_lines, :linking_page_titles, :first_image
32
36
 
33
- def body_lines
34
- lines.drop(1)
37
+ def summary
38
+ if (image = first_image)
39
+ if image.is_a?(Cosensee::Node::GyazoImageBracket)
40
+ %(<img src="#{image.src}/raw" loading="lazy">)
41
+ else
42
+ %(<img src="#{image.src}" loading="lazy">)
43
+ end
44
+ else
45
+ parsed_lines.map(&:to_s).take(MAX_SUMMARY_LINE).join
46
+ end
47
+ end
48
+
49
+ def summary_text
50
+ parsed_lines.map(&:to_s).join.slice(0, MAX_SUMMARY_TEXT_SIZE)
51
+ end
52
+
53
+ def description
54
+ summary_text
35
55
  end
36
56
 
37
- def some_images?
38
- lines.any?(&:some_image?)
57
+ def ogp_image_url
58
+ first_image
39
59
  end
40
60
 
41
- def first_image
42
- lines.find(&:some_image?)&.first_image
61
+ def song_page?
62
+ parsed_lines.any?(&:song_tagged?)
63
+ end
64
+
65
+ def body_lines
66
+ lines.drop(1)
43
67
  end
44
68
 
45
69
  def link_path
46
70
  # body = URI.encode_www_form_component(title.gsub(/ /, '_'))
47
- body = title.gsub(/ /, '_').gsub('/', '%2F')
71
+ body = title.gsub(/ /, '_').gsub('=', '=3d').gsub('/', '=2F').gsub('#', '=23')
48
72
 
49
73
  "#{body}.html"
50
74
  end
51
75
 
52
- def to_html
53
- Cosensee::TailwindRenderer.new(content: self).render
76
+ def full_url(base_url:)
77
+ return unless base_url && link_path
78
+
79
+ "#{base_url}/#{link_path}"
80
+ end
81
+
82
+ def to_html(project: nil)
83
+ Cosensee::TailwindRenderer.new(content: self, project:).render
54
84
  end
55
85
 
56
86
  def to_obj
@@ -6,16 +6,27 @@ require 'json'
6
6
  module Cosensee
7
7
  # To search for pages
8
8
  class PageStore
9
+ DEFAULT_PIN_TITLES = ['HOME'].freeze
10
+
11
+ extend Delegatable
12
+
9
13
  def initialize(project:)
10
14
  @project = project
11
15
  @pages = project.pages
12
16
  @pages_by_title = nil
13
17
  @linking_pages = nil
14
18
  @linked_pages = nil
19
+ @pin_titles = DEFAULT_PIN_TITLES.dup
15
20
  end
16
21
 
22
+ attr_reader :pin_titles, :pages
23
+
17
24
  def pages_by_title
18
- @pages_by_title ||= create_title_index(@pages)
25
+ @pages_by_title ||= create_title_index(pages)
26
+ end
27
+
28
+ def find_page_by_title(title)
29
+ pages_by_title[title]
19
30
  end
20
31
 
21
32
  def linking_pages
@@ -44,9 +55,21 @@ module Cosensee
44
55
  end
45
56
  end
46
57
 
58
+ def pinned_pages
59
+ pages_by_title.fetch_values(*pin_titles) { nil }.compact
60
+ end
61
+
47
62
  def find_link_pages_by_title(title)
48
63
  pages = linking_pages[title] + linked_pages[title]
49
- pages.sort_by(&:updated)
64
+ pages.sort_by(&:updated).uniq.reverse
65
+ end
66
+
67
+ def dump_search_data
68
+ pages.map do |page|
69
+ { title: page.title,
70
+ link: page.link_path,
71
+ summary: page.summary_text }
72
+ end
50
73
  end
51
74
 
52
75
  def setup_link_indexes