docyard 0.2.0 → 0.4.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -1
  3. data/LICENSE.vscode-icons +42 -0
  4. data/README.md +86 -23
  5. data/lib/docyard/asset_handler.rb +33 -0
  6. data/lib/docyard/build/asset_bundler.rb +139 -0
  7. data/lib/docyard/build/file_copier.rb +105 -0
  8. data/lib/docyard/build/sitemap_generator.rb +57 -0
  9. data/lib/docyard/build/static_generator.rb +141 -0
  10. data/lib/docyard/builder.rb +104 -0
  11. data/lib/docyard/cli.rb +19 -0
  12. data/lib/docyard/components/base_processor.rb +24 -0
  13. data/lib/docyard/components/callout_processor.rb +121 -0
  14. data/lib/docyard/components/code_block_processor.rb +55 -0
  15. data/lib/docyard/components/code_detector.rb +59 -0
  16. data/lib/docyard/components/icon_detector.rb +57 -0
  17. data/lib/docyard/components/icon_processor.rb +51 -0
  18. data/lib/docyard/components/registry.rb +34 -0
  19. data/lib/docyard/components/table_wrapper_processor.rb +18 -0
  20. data/lib/docyard/components/tabs_parser.rb +60 -0
  21. data/lib/docyard/components/tabs_processor.rb +44 -0
  22. data/lib/docyard/config/validator.rb +171 -0
  23. data/lib/docyard/config.rb +135 -0
  24. data/lib/docyard/constants.rb +5 -0
  25. data/lib/docyard/icons/LICENSE.phosphor +21 -0
  26. data/lib/docyard/icons/file_types.rb +92 -0
  27. data/lib/docyard/icons/phosphor.rb +64 -0
  28. data/lib/docyard/icons.rb +40 -0
  29. data/lib/docyard/initializer.rb +93 -9
  30. data/lib/docyard/language_mapping.rb +52 -0
  31. data/lib/docyard/markdown.rb +27 -3
  32. data/lib/docyard/preview_server.rb +72 -0
  33. data/lib/docyard/rack_application.rb +77 -8
  34. data/lib/docyard/renderer.rb +56 -9
  35. data/lib/docyard/server.rb +5 -2
  36. data/lib/docyard/sidebar/config_parser.rb +180 -0
  37. data/lib/docyard/sidebar/item.rb +58 -0
  38. data/lib/docyard/sidebar/renderer.rb +33 -6
  39. data/lib/docyard/sidebar_builder.rb +54 -2
  40. data/lib/docyard/templates/assets/css/code.css +150 -2
  41. data/lib/docyard/templates/assets/css/components/callout.css +169 -0
  42. data/lib/docyard/templates/assets/css/components/code-block.css +196 -0
  43. data/lib/docyard/templates/assets/css/components/icon.css +16 -0
  44. data/lib/docyard/templates/assets/css/components/logo.css +44 -0
  45. data/lib/docyard/templates/assets/css/{components.css → components/navigation.css} +111 -53
  46. data/lib/docyard/templates/assets/css/components/tabs.css +299 -0
  47. data/lib/docyard/templates/assets/css/components/theme-toggle.css +69 -0
  48. data/lib/docyard/templates/assets/css/layout.css +14 -4
  49. data/lib/docyard/templates/assets/css/markdown.css +27 -17
  50. data/lib/docyard/templates/assets/css/reset.css +4 -0
  51. data/lib/docyard/templates/assets/css/variables.css +94 -3
  52. data/lib/docyard/templates/assets/favicon.svg +16 -0
  53. data/lib/docyard/templates/assets/js/components/code-block.js +162 -0
  54. data/lib/docyard/templates/assets/js/components/navigation.js +221 -0
  55. data/lib/docyard/templates/assets/js/components/tabs.js +338 -0
  56. data/lib/docyard/templates/assets/js/theme.js +12 -179
  57. data/lib/docyard/templates/assets/logo-dark.svg +4 -0
  58. data/lib/docyard/templates/assets/logo.svg +12 -0
  59. data/lib/docyard/templates/config/docyard.yml.erb +42 -0
  60. data/lib/docyard/templates/layouts/default.html.erb +32 -4
  61. data/lib/docyard/templates/markdown/getting-started/installation.md.erb +46 -12
  62. data/lib/docyard/templates/markdown/guides/configuration.md.erb +202 -0
  63. data/lib/docyard/templates/markdown/guides/markdown-features.md.erb +247 -0
  64. data/lib/docyard/templates/markdown/index.md.erb +55 -59
  65. data/lib/docyard/templates/partials/_callout.html.erb +11 -0
  66. data/lib/docyard/templates/partials/_code_block.html.erb +6 -0
  67. data/lib/docyard/templates/partials/_icon.html.erb +1 -0
  68. data/lib/docyard/templates/partials/_icon_file_extension.html.erb +1 -0
  69. data/lib/docyard/templates/partials/_nav_group.html.erb +10 -4
  70. data/lib/docyard/templates/partials/_nav_leaf.html.erb +9 -1
  71. data/lib/docyard/templates/partials/_tabs.html.erb +40 -0
  72. data/lib/docyard/templates/partials/_theme_toggle.html.erb +13 -0
  73. data/lib/docyard/version.rb +1 -1
  74. data/lib/docyard.rb +8 -0
  75. metadata +91 -7
  76. data/lib/docyard/templates/markdown/core-concepts/file-structure.md.erb +0 -61
  77. data/lib/docyard/templates/markdown/core-concepts/markdown.md.erb +0 -90
  78. data/lib/docyard/templates/markdown/getting-started/introduction.md.erb +0 -30
  79. data/lib/docyard/templates/markdown/getting-started/quick-start.md.erb +0 -56
  80. data/lib/docyard/templates/partials/_icons.html.erb +0 -11
@@ -4,22 +4,25 @@ require "webrick"
4
4
  require "stringio"
5
5
  require_relative "file_watcher"
6
6
  require_relative "rack_application"
7
+ require_relative "config"
7
8
 
8
9
  module Docyard
9
10
  class Server
10
11
  DEFAULT_PORT = 4200
11
12
  DEFAULT_HOST = "localhost"
12
13
 
13
- attr_reader :port, :host, :docs_path
14
+ attr_reader :port, :host, :docs_path, :config
14
15
 
15
16
  def initialize(port: DEFAULT_PORT, host: DEFAULT_HOST, docs_path: "docs")
16
17
  @port = port
17
18
  @host = host
18
19
  @docs_path = docs_path
20
+ @config = Config.load
19
21
  @file_watcher = FileWatcher.new(File.expand_path(docs_path))
20
22
  @app = RackApplication.new(
21
23
  docs_path: File.expand_path(docs_path),
22
- file_watcher: @file_watcher
24
+ file_watcher: @file_watcher,
25
+ config: @config
23
26
  )
24
27
  end
25
28
 
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "item"
4
+ require_relative "title_extractor"
5
+
6
+ module Docyard
7
+ module Sidebar
8
+ class ConfigParser
9
+ attr_reader :config_items, :docs_path, :current_path, :title_extractor
10
+
11
+ def initialize(config_items, docs_path:, current_path: "/", title_extractor: TitleExtractor.new)
12
+ @config_items = config_items || []
13
+ @docs_path = docs_path
14
+ @current_path = Utils::PathResolver.normalize(current_path)
15
+ @title_extractor = title_extractor
16
+ end
17
+
18
+ def parse
19
+ parse_items(config_items)
20
+ end
21
+
22
+ private
23
+
24
+ def parse_items(items, base_path = "")
25
+ items.map do |item_config|
26
+ parse_item(item_config, base_path)
27
+ end.compact
28
+ end
29
+
30
+ def parse_item(item_config, base_path)
31
+ case item_config
32
+ when String
33
+ resolve_file_item(item_config, base_path)
34
+ when Hash
35
+ parse_hash_item(item_config, base_path)
36
+ end
37
+ end
38
+
39
+ def parse_hash_item(item_config, base_path)
40
+ return parse_link_item(item_config) if link_item?(item_config)
41
+ return parse_nested_item(item_config, base_path) if nested_item?(item_config)
42
+ return resolve_file_item(item_config.keys.first, base_path, {}) if nil_value_item?(item_config)
43
+
44
+ slug = item_config.keys.first
45
+ options = item_config.values.first || {}
46
+ resolve_file_item(slug, base_path, options)
47
+ end
48
+
49
+ def link_item?(config)
50
+ config.key?("link") || config.key?(:link)
51
+ end
52
+
53
+ def nested_item?(config)
54
+ config.size == 1 && config.values.first.is_a?(Hash)
55
+ end
56
+
57
+ def nil_value_item?(config)
58
+ config.size == 1 && config.values.first.nil?
59
+ end
60
+
61
+ def parse_link_item(config)
62
+ link = config["link"] || config[:link]
63
+ text = config["text"] || config[:text]
64
+ icon = config["icon"] || config[:icon]
65
+ target = config["target"] || config[:target] || "_blank"
66
+
67
+ Item.new(
68
+ text: text,
69
+ link: link,
70
+ path: link,
71
+ icon: icon,
72
+ target: target,
73
+ type: :external
74
+ )
75
+ end
76
+
77
+ def parse_nested_item(item_config, base_path)
78
+ slug = item_config.keys.first.to_s
79
+ options = item_config.values.first || {}
80
+ nested_items = extract_nested_items(options)
81
+
82
+ dir_path = File.join(docs_path, base_path, slug)
83
+
84
+ if File.directory?(dir_path)
85
+ build_directory_item(slug, options, nested_items, base_path)
86
+ elsif nested_items.any?
87
+ build_file_with_children_item(slug, options, nested_items, base_path)
88
+ else
89
+ resolve_file_item(slug, base_path, options)
90
+ end
91
+ end
92
+
93
+ def extract_nested_items(options)
94
+ options["items"] || options[:items] || []
95
+ end
96
+
97
+ def extract_common_options(options)
98
+ {
99
+ text: options["text"] || options[:text],
100
+ icon: options["icon"] || options[:icon],
101
+ collapsed: options["collapsed"] || options[:collapsed] || false
102
+ }
103
+ end
104
+
105
+ def build_directory_item(slug, options, nested_items, base_path)
106
+ common_opts = extract_common_options(options)
107
+ new_base_path = File.join(base_path, slug)
108
+ parsed_items = parse_items(nested_items, new_base_path)
109
+
110
+ Item.new(
111
+ slug: slug,
112
+ text: common_opts[:text] || Utils::TextFormatter.titleize(slug),
113
+ icon: common_opts[:icon],
114
+ collapsed: common_opts[:collapsed],
115
+ items: parsed_items,
116
+ type: :directory
117
+ )
118
+ end
119
+
120
+ def build_file_with_children_item(slug, options, nested_items, base_path)
121
+ common_opts = extract_common_options(options)
122
+ file_path = File.join(docs_path, base_path, "#{slug}.md")
123
+ url_path = Utils::PathResolver.to_url(File.join(base_path, slug))
124
+ resolved_text = common_opts[:text] || extract_file_title(file_path, slug)
125
+
126
+ Item.new(
127
+ slug: slug,
128
+ text: resolved_text,
129
+ path: url_path,
130
+ icon: common_opts[:icon],
131
+ collapsed: common_opts[:collapsed],
132
+ items: parse_items(nested_items, base_path),
133
+ active: current_path == url_path,
134
+ type: :file
135
+ )
136
+ end
137
+
138
+ def extract_file_title(file_path, slug)
139
+ File.exist?(file_path) ? title_extractor.extract(file_path) : Utils::TextFormatter.titleize(slug)
140
+ end
141
+
142
+ def resolve_file_item(slug, base_path, options = {})
143
+ slug_str = slug.to_s
144
+ options ||= {}
145
+
146
+ file_path = File.join(docs_path, base_path, "#{slug_str}.md")
147
+ url_path = Utils::PathResolver.to_url(File.join(base_path, slug_str))
148
+
149
+ frontmatter = extract_frontmatter_metadata(file_path)
150
+ text = resolve_item_text(slug_str, file_path, options, frontmatter[:text])
151
+ icon = resolve_item_icon(options, frontmatter[:icon])
152
+ final_path = options["link"] || options[:link] || url_path
153
+
154
+ Item.new(
155
+ slug: slug_str, text: text, path: final_path, icon: icon,
156
+ active: current_path == final_path, type: :file
157
+ )
158
+ end
159
+
160
+ def extract_frontmatter_metadata(file_path)
161
+ return { text: nil, icon: nil } unless File.exist?(file_path)
162
+
163
+ markdown = Markdown.new(File.read(file_path))
164
+ {
165
+ text: markdown.sidebar_text || markdown.title,
166
+ icon: markdown.sidebar_icon
167
+ }
168
+ end
169
+
170
+ def resolve_item_text(slug, file_path, options, frontmatter_text)
171
+ text = options["text"] || options[:text] || frontmatter_text
172
+ text || extract_file_title(file_path, slug)
173
+ end
174
+
175
+ def resolve_item_icon(options, frontmatter_icon)
176
+ options["icon"] || options[:icon] || frontmatter_icon
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Docyard
4
+ module Sidebar
5
+ class Item
6
+ attr_reader :slug, :text, :icon, :link, :target, :collapsed, :items, :path, :active, :type
7
+
8
+ def initialize(**options)
9
+ @slug = options[:slug]
10
+ @text = options[:text]
11
+ @icon = options[:icon]
12
+ @link = options[:link]
13
+ @target = options[:target] || "_self"
14
+ @collapsed = options[:collapsed] || false
15
+ @items = options[:items] || []
16
+ @path = options[:path] || options[:link]
17
+ @active = options[:active] || false
18
+ @type = options[:type] || :file
19
+ end
20
+
21
+ def external?
22
+ return false if path.nil?
23
+
24
+ path.start_with?("http://", "https://")
25
+ end
26
+
27
+ def children?
28
+ items.any?
29
+ end
30
+
31
+ def title
32
+ text
33
+ end
34
+
35
+ def children
36
+ items
37
+ end
38
+
39
+ def collapsible?
40
+ children?
41
+ end
42
+
43
+ def to_h
44
+ {
45
+ title: title,
46
+ path: path,
47
+ icon: icon,
48
+ active: active,
49
+ type: type,
50
+ collapsed: collapsed,
51
+ collapsible: collapsible?,
52
+ target: target,
53
+ children: children.map(&:to_h)
54
+ }
55
+ end
56
+ end
57
+ end
58
+ end
@@ -7,10 +7,11 @@ module Docyard
7
7
  class Renderer
8
8
  PARTIALS_PATH = File.join(__dir__, "../templates/partials")
9
9
 
10
- attr_reader :site_title
10
+ attr_reader :site_title, :base_url
11
11
 
12
- def initialize(site_title: "Documentation")
12
+ def initialize(site_title: "Documentation", base_url: "/")
13
13
  @site_title = site_title
14
+ @base_url = normalize_base_url(base_url)
14
15
  end
15
16
 
16
17
  def render(tree)
@@ -34,8 +35,21 @@ module Docyard
34
35
  ERB.new(template).result(erb_binding)
35
36
  end
36
37
 
37
- def icon(name)
38
- render_partial(:icons, icon_name: name)
38
+ def icon(name, weight = "regular")
39
+ Icons.render(name.to_s.tr("_", "-"), weight) || ""
40
+ end
41
+
42
+ def link_path(path)
43
+ return path if path.nil? || path.start_with?("http://", "https://")
44
+
45
+ "#{base_url.chomp('/')}#{path}"
46
+ end
47
+
48
+ def normalize_base_url(url)
49
+ return "/" if url.nil? || url.empty?
50
+
51
+ url = "/#{url}" unless url.start_with?("/")
52
+ url.end_with?("/") ? url : "#{url}/"
39
53
  end
40
54
 
41
55
  def render_tree_with_sections(items)
@@ -98,12 +112,25 @@ module Docyard
98
112
  end
99
113
 
100
114
  def render_leaf_item(item)
101
- render_partial(:nav_leaf, path: item[:path], title: item[:title], active: item[:active])
115
+ render_partial(
116
+ :nav_leaf,
117
+ path: item[:path],
118
+ title: item[:title],
119
+ active: item[:active],
120
+ icon: item[:icon],
121
+ target: item[:target]
122
+ )
102
123
  end
103
124
 
104
125
  def render_group_item(item)
105
126
  children_html = render_tree(item[:children])
106
- render_partial(:nav_group, title: item[:title], children_html: children_html)
127
+ render_partial(
128
+ :nav_group,
129
+ title: item[:title],
130
+ children_html: children_html,
131
+ icon: item[:icon],
132
+ collapsed: item[:collapsed]
133
+ )
107
134
  end
108
135
  end
109
136
  end
@@ -4,12 +4,13 @@ require_relative "sidebar/file_system_scanner"
4
4
  require_relative "sidebar/title_extractor"
5
5
  require_relative "sidebar/tree_builder"
6
6
  require_relative "sidebar/renderer"
7
+ require_relative "sidebar/config_parser"
7
8
 
8
9
  module Docyard
9
10
  class SidebarBuilder
10
11
  attr_reader :docs_path, :current_path, :config
11
12
 
12
- def initialize(docs_path:, current_path: "/", config: {})
13
+ def initialize(docs_path:, current_path: "/", config: nil)
13
14
  @docs_path = docs_path
14
15
  @current_path = current_path
15
16
  @config = config
@@ -26,10 +27,44 @@ module Docyard
26
27
  private
27
28
 
28
29
  def build_tree
30
+ if config_sidebar_items?
31
+ build_tree_from_config
32
+ else
33
+ build_tree_from_filesystem
34
+ end
35
+ end
36
+
37
+ def build_tree_from_config
38
+ config_parser.parse.map(&:to_h)
39
+ end
40
+
41
+ def build_tree_from_filesystem
29
42
  file_items = scanner.scan
30
43
  tree_builder.build(file_items)
31
44
  end
32
45
 
46
+ def config_sidebar_items?
47
+ config_sidebar_items&.any?
48
+ end
49
+
50
+ def config_sidebar_items
51
+ return [] unless config
52
+
53
+ if config.is_a?(Hash)
54
+ config.dig("sidebar", "items") || config.dig(:sidebar, :items) || []
55
+ else
56
+ config.sidebar&.items || []
57
+ end
58
+ end
59
+
60
+ def config_parser
61
+ @config_parser ||= Sidebar::ConfigParser.new(
62
+ config_sidebar_items,
63
+ docs_path: docs_path,
64
+ current_path: current_path
65
+ )
66
+ end
67
+
33
68
  def scanner
34
69
  @scanner ||= Sidebar::FileSystemScanner.new(docs_path)
35
70
  end
@@ -43,8 +78,25 @@ module Docyard
43
78
 
44
79
  def renderer
45
80
  @renderer ||= Sidebar::Renderer.new(
46
- site_title: config[:site_title] || "Documentation"
81
+ site_title: extract_site_title,
82
+ base_url: extract_base_url
47
83
  )
48
84
  end
85
+
86
+ def extract_base_url
87
+ if config.is_a?(Hash)
88
+ config.dig(:build, :base_url) || "/"
89
+ else
90
+ config&.build&.base_url || "/"
91
+ end
92
+ end
93
+
94
+ def extract_site_title
95
+ if config.is_a?(Hash)
96
+ config[:site_title] || "Documentation"
97
+ else
98
+ config&.site&.title || "Documentation"
99
+ end
100
+ end
49
101
  end
50
102
  end
@@ -35,7 +35,7 @@
35
35
  }
36
36
 
37
37
  .highlight table td {
38
- padding: 5px;
38
+ padding: 0.3125rem;
39
39
  }
40
40
 
41
41
  .highlight table pre {
@@ -196,7 +196,7 @@
196
196
 
197
197
  /* Code block scrollbar */
198
198
  .content pre::-webkit-scrollbar {
199
- height: 8px;
199
+ height: 0.5rem;
200
200
  }
201
201
 
202
202
  .content pre::-webkit-scrollbar-track {
@@ -212,3 +212,151 @@
212
212
  .content pre::-webkit-scrollbar-thumb:hover {
213
213
  background: var(--color-text-tertiary);
214
214
  }
215
+
216
+ /* Dark Mode Syntax Highlighting - GitHub Dark */
217
+ .dark .highlight,
218
+ .dark .highlight .w {
219
+ color: #e6edf3;
220
+ background-color: #161b22;
221
+ }
222
+
223
+ /* Keywords */
224
+ .dark .highlight .k,
225
+ .dark .highlight .kd,
226
+ .dark .highlight .kn,
227
+ .dark .highlight .kp,
228
+ .dark .highlight .kr,
229
+ .dark .highlight .kt,
230
+ .dark .highlight .kv {
231
+ color: #ff7b72;
232
+ }
233
+
234
+ .dark .highlight .gr {
235
+ color: #161b22;
236
+ }
237
+
238
+ .dark .highlight .gd {
239
+ color: #ffa198;
240
+ background-color: #490202;
241
+ }
242
+
243
+ /* Built-in names */
244
+ .dark .highlight .nb,
245
+ .dark .highlight .nc,
246
+ .dark .highlight .no,
247
+ .dark .highlight .nn {
248
+ color: #ffa657;
249
+ }
250
+
251
+ /* Strings and regex */
252
+ .dark .highlight .sr,
253
+ .dark .highlight .na,
254
+ .dark .highlight .nt {
255
+ color: #7ee787;
256
+ }
257
+
258
+ .dark .highlight .gi {
259
+ color: #7ee787;
260
+ background-color: #0f3b17;
261
+ }
262
+
263
+ /* Constants and literals */
264
+ .dark .highlight .kc,
265
+ .dark .highlight .l,
266
+ .dark .highlight .ld,
267
+ .dark .highlight .m,
268
+ .dark .highlight .mb,
269
+ .dark .highlight .mf,
270
+ .dark .highlight .mh,
271
+ .dark .highlight .mi,
272
+ .dark .highlight .il,
273
+ .dark .highlight .mo,
274
+ .dark .highlight .mx,
275
+ .dark .highlight .sb,
276
+ .dark .highlight .bp,
277
+ .dark .highlight .ne,
278
+ .dark .highlight .nl,
279
+ .dark .highlight .py {
280
+ color: #79c0ff;
281
+ }
282
+
283
+ /* Variables */
284
+ .dark .highlight .nv,
285
+ .dark .highlight .vc,
286
+ .dark .highlight .vg,
287
+ .dark .highlight .vi,
288
+ .dark .highlight .vm {
289
+ color: #79c0ff;
290
+ }
291
+
292
+ /* Operators */
293
+ .dark .highlight .o,
294
+ .dark .highlight .ow {
295
+ color: #79c0ff;
296
+ }
297
+
298
+ /* Headers and subheaders in diffs */
299
+ .dark .highlight .gh,
300
+ .dark .highlight .gu {
301
+ color: #79c0ff;
302
+ font-weight: bold;
303
+ }
304
+
305
+ /* Strings */
306
+ .dark .highlight .s,
307
+ .dark .highlight .sa,
308
+ .dark .highlight .sc,
309
+ .dark .highlight .dl,
310
+ .dark .highlight .sd,
311
+ .dark .highlight .s2,
312
+ .dark .highlight .se,
313
+ .dark .highlight .sh,
314
+ .dark .highlight .sx,
315
+ .dark .highlight .s1,
316
+ .dark .highlight .ss {
317
+ color: #a5d6ff;
318
+ }
319
+
320
+ /* Decorators and functions */
321
+ .dark .highlight .nd,
322
+ .dark .highlight .nf,
323
+ .dark .highlight .fm {
324
+ color: #d2a8ff;
325
+ }
326
+
327
+ /* Errors */
328
+ .dark .highlight .err {
329
+ color: #161b22;
330
+ background-color: #ffa198;
331
+ }
332
+
333
+ /* Comments */
334
+ .dark .highlight .c,
335
+ .dark .highlight .ch,
336
+ .dark .highlight .cd,
337
+ .dark .highlight .cm,
338
+ .dark .highlight .cp,
339
+ .dark .highlight .cpf,
340
+ .dark .highlight .c1,
341
+ .dark .highlight .cs,
342
+ .dark .highlight .gl,
343
+ .dark .highlight .gt {
344
+ color: #8b949e;
345
+ }
346
+
347
+ /* Name indicators */
348
+ .dark .highlight .ni,
349
+ .dark .highlight .si {
350
+ color: #e6edf3;
351
+ }
352
+
353
+ /* Generic emphasis */
354
+ .dark .highlight .ge {
355
+ color: #e6edf3;
356
+ font-style: italic;
357
+ }
358
+
359
+ .dark .highlight .gs {
360
+ color: #e6edf3;
361
+ font-weight: bold;
362
+ }