cosensee 0.6.0 → 0.8.0

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