json-schema-docs 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +48 -9
  3. data/Rakefile +1 -8
  4. data/json-schema-docs.gemspec +11 -0
  5. data/lib/json-schema-docs.rb +1 -0
  6. data/lib/json-schema-docs/configuration.rb +25 -2
  7. data/lib/json-schema-docs/generator.rb +93 -21
  8. data/lib/json-schema-docs/helpers.rb +17 -1
  9. data/lib/json-schema-docs/landing_pages/index.md +7 -0
  10. data/lib/json-schema-docs/layouts/assets/_sass/_content.scss +518 -0
  11. data/lib/json-schema-docs/layouts/assets/_sass/_header.scss +59 -0
  12. data/lib/json-schema-docs/layouts/assets/_sass/_links.scss +33 -0
  13. data/lib/json-schema-docs/layouts/assets/_sass/_normalize.scss +127 -0
  14. data/lib/json-schema-docs/layouts/assets/_sass/_resource.scss +23 -0
  15. data/lib/json-schema-docs/layouts/assets/_sass/_sidebar.scss +75 -0
  16. data/lib/json-schema-docs/layouts/assets/css/screen.scss +32 -0
  17. data/lib/json-schema-docs/layouts/default.html.erb +43 -0
  18. data/lib/json-schema-docs/layouts/includes/{example.md.erb → curl_example.html.erb} +3 -3
  19. data/lib/json-schema-docs/layouts/includes/resource_example.html.erb +3 -0
  20. data/lib/json-schema-docs/layouts/includes/{response.md.erb → response.html.erb} +5 -5
  21. data/lib/json-schema-docs/layouts/includes/sidebar.html.erb +31 -0
  22. data/lib/json-schema-docs/layouts/links.html.erb +73 -0
  23. data/lib/json-schema-docs/layouts/resource.html.erb +42 -0
  24. data/lib/json-schema-docs/parser.rb +12 -6
  25. data/lib/json-schema-docs/renderer.rb +67 -0
  26. data/lib/json-schema-docs/version.rb +1 -1
  27. metadata +144 -6
  28. data/lib/json-schema-docs/layouts/endpoint.md.erb +0 -39
  29. data/lib/json-schema-docs/layouts/object.md.erb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3049cd9fed945058bbd3d668f0cda02d75f50aa114ea0e93e7aa3ed17313011b
4
- data.tar.gz: f247ed95de772c8461e7022dc12a1d922288cb9b85d4d259c2a904ccfb09bae3
3
+ metadata.gz: 70ce09af68c836c67047b91049579f0907fe9e4e8b935211482dd6163bb96bc2
4
+ data.tar.gz: a069ce9a8503d02bcf5d98f608ad734f335296b25a8528701b26a0eb4306a286
5
5
  SHA512:
6
- metadata.gz: ce9a9ef62d0216c5f7fb110850c71d2b1f9da4738f12eb204fa588d22078ba046361907b0594fb9fc8ec919fb52b16060f8c6ffd163d17251ceeeb60228f1b25
7
- data.tar.gz: 180f02533338faa832fe751eea09c7cde31ee9abcb81e4d19b384bb09d3dc2a29313cc1e882b17a97497f01640b738906890666766d1964a08ec04eae7b702cf
6
+ metadata.gz: f4ff3f550c966a17f8faf158564610b14132e044a3aafcc0c1614f4509a961ef77ad03e0967e6d8a73a3942c1ac23c97e89904ed473ec4799117510cff93e31c
7
+ data.tar.gz: 48e657b95352ef05360e07137fea1748deaa4cdcbe6d87bbb9c3f6f6c71f5c0523afd1d64ee85dfcfcbe313c5fb558e9478f6450f1c724879c22fa87e96a2075
data/README.md CHANGED
@@ -39,7 +39,8 @@ There are several phases going on the single `JsonSchemaDocs.build` call:
39
39
 
40
40
  * The JSON schema file is read (if you passed `filename`) through `Prmd::Schema` (or simply consumed if you passed it through `schema`).
41
41
  * `JsonSchemaDocs::Parser` manipulates the schema into a slightly saner format.
42
- * `JsonSchemaDocs::Generator` takes that saner format and converts it into Markdown, via ERB templates.
42
+ * `JsonSchemaDocs::Generator` takes that saner format and begins the process of applying items to the HTML templates.
43
+ * `JsonSchemaDocs::Renderer` technically runs as part of the generation phase. It passes the contents of each page and converts it into HTML.
43
44
 
44
45
  If you wanted to, you could break these calls up individually. For example:
45
46
 
@@ -47,7 +48,7 @@ If you wanted to, you could break these calls up individually. For example:
47
48
  options = {}
48
49
  options[:filename] = "#{File.dirname(__FILE__)}/../data/schema.json"
49
50
 
50
- options = JsonSchemaDocs::Configuration::JSON_SCHEMA_DOCS.merge(options)
51
+ options = JsonSchemaDocs::Configuration::JSON_SCHEMA_DOCS_DEFAULTS.merge(options)
51
52
 
52
53
  response = File.read(options[:filename])
53
54
 
@@ -61,14 +62,47 @@ generator.generate
61
62
 
62
63
  ## Generating output
63
64
 
64
- By default, the generation process uses ERB to layout the content into Markdown.
65
+ By default, the generation process uses ERB to layout the content. There are a bunch of default options provided for you, but feel free to override any of these. The *Configuration* section below has more information on what you can change.
66
+
67
+ It also uses [html-pipeline](https://github.com/jch/html-pipeline) to perform the rendering by default. You can override this by providing a custom rendering class.You must implement two methods:
68
+
69
+ * `initialize` - Takes two arguments, the parsed `schema` and the configuration `options`.
70
+ * `render` Takes the contents of a template page. It also takes an optional kwargs, `meta`, for anything you want to include in your template. For example:
71
+
72
+ ``` ruby
73
+ class CustomRenderer
74
+ def initialize(parsed_schema, options)
75
+ @parsed_schema = parsed_schema
76
+ @options = options
77
+ end
78
+
79
+ def render(contents, meta: {})
80
+ contents = contents.sub(/Repository/i, '<strong>Meow Woof!</strong>')
81
+ opts = meta.merge({ foo: "bar" })
82
+
83
+ @default_layout.result(OpenStruct.new(opts).instance_eval { binding })
84
+ end
85
+ end
86
+
87
+ options[:filename] = 'location/to/schema.json'
88
+ options[:renderer] = CustomRenderer
89
+
90
+ JsonSchemaDocs.build(options)
91
+ ```
92
+
93
+ If your `render` method returns `nil`, the `Generator` will not attempt to write any HTML file.
65
94
 
66
95
  ### Helper methods
67
96
 
68
97
  In your ERB layouts, there are several helper methods you can use. The helper methods are:
69
98
 
70
- * `slugify(str)` - This slugifies the given string.
71
- * `include(filename, opts)` - This embeds a template from your `includes` folder, passing along the local options provided.
99
+ * `slugify(str)`: This slugifies the given string.
100
+ * `include(filename, opts)`: This embeds a template from your `includes` folder, passing along the local options provided.
101
+ * `markdownify(string)`: This converts a string into HTML via CommonMarker.
102
+ * `types`: Collections of the various types.
103
+ * `schemata(name)`: The schemata defined by `name`.
104
+
105
+ To call these methods within templates, you must use the dot notation, such as `<%= slugify.(text) %>`.
72
106
 
73
107
  ## Configuration
74
108
 
@@ -76,11 +110,16 @@ The following options are available:
76
110
 
77
111
  | Option | Description | Default |
78
112
  | :----- | :---------- | :------ |
79
- | `filename` | The location of your schema's IDL file. | `nil` |
80
- | `schema` | A string representing a schema IDL file. | `nil` |
113
+ | `filename` | The location of your schema's JSON file. | `nil` |
114
+ | `schema` | A string representing a schema JSON file. | `nil` |
115
+ | `output_dir` | The location of the output HTML files. | `./output/` |
116
+ | `use_default_styles` | Indicates if you want to use the default styles. | `true` |
117
+ | `base_url` | Indicates the base URL to prepend for assets and links. | `""` |
81
118
  | `delete_output` | Deletes `output_dir` before generating content. | `false` |
82
- | `output_dir` | The location of the output Markdown files. | `./output/` |
83
- | `templates` | The templates to use when generating Markdown files. You may override any of the following keys: `endpoint`, `object`, `includes`. | The defaults are found in _lib/json-schema-docs/layouts/_.
119
+ | `pipeline_config` | Defines two sub-keys, `pipeline` and `context`, which are used by `html-pipeline` when rendering your output. | The defaults are found in _lib/json-schema-docs/configuration.rb/_ |
120
+ | `renderer` | The rendering class to use. | `JsonSchemaDocs::Renderer`
121
+ | `templates` | The templates to use when generating HTML. You may override any of the following keys: `default`, `links`, `resource`. | The defaults are found in _lib/json-schema-docs/layouts/_.
122
+ | `landing_pages` | The landing page to use when generating HTML for each type. You may override any of the following keys: `index`. | The defaults are found in _lib/json-schema-docs/landing\_pages/_.
84
123
  | `prmd` | The options to pass into PRMD's parser. | The defaults are found in _lib/json-schema-docs/configuration.rb/_.
85
124
 
86
125
  ## Development
data/Rakefile CHANGED
@@ -33,14 +33,7 @@ task sample: [:generate_sample] do
33
33
 
34
34
  puts 'Navigate to http://localhost:3000 to see the sample docs'
35
35
 
36
- mime_types = WEBrick::HTTPUtils::DefaultMimeTypes
37
- mime_types.store 'md', 'text/plain'
38
-
39
- options = {
40
- Port: 3000,
41
- MimeTypes: mime_types
42
- }
43
- server = WEBrick::HTTPServer.new options
36
+ server = WEBrick::HTTPServer.new Port: 3000
44
37
  server.mount '/', WEBrick::HTTPServlet::FileHandler, 'output'
45
38
  trap('INT') { server.stop }
46
39
  server.start
@@ -23,6 +23,17 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_dependency 'prmd', '~> 0.13'
25
25
 
26
+ # rendering
27
+ spec.add_dependency 'commonmarker', '~> 0.16'
28
+ spec.add_dependency 'gemoji', '~> 3.0'
29
+ spec.add_dependency 'html-pipeline', '~> 2.9'
30
+ spec.add_dependency 'escape_utils', '~> 1.2'
31
+ spec.add_dependency 'extended-markdown-filter', '~> 0.4'
32
+ spec.add_dependency 'neatjson', '~> 0.9'
33
+ spec.add_dependency 'page-toc-filter', '~> 0.2'
34
+ spec.add_dependency 'rouge', '~> 3.10'
35
+ spec.add_dependency 'sass', '~> 3.4'
36
+
26
37
  spec.add_development_dependency 'awesome_print'
27
38
  spec.add_development_dependency 'html-proofer', '~> 3.4'
28
39
  spec.add_development_dependency 'minitest', '~> 5.0'
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require 'json-schema-docs/helpers'
3
+ require 'json-schema-docs/renderer'
3
4
  require 'json-schema-docs/configuration'
4
5
  require 'json-schema-docs/generator'
5
6
  require 'json-schema-docs/parser'
@@ -9,12 +9,35 @@ module JsonSchemaDocs
9
9
  # Generating
10
10
  delete_output: false,
11
11
  output_dir: './output/',
12
+ pipeline_config: {
13
+ pipeline:
14
+ %i(ExtendedMarkdownFilter
15
+ EmojiFilter
16
+ TableOfContentsFilter
17
+ SyntaxHighlightFilter),
18
+ context: {
19
+ gfm: false,
20
+ unsafe: true, # necessary for layout needs, given that it's all HTML templates
21
+ asset_root: 'https://a248.e.akamai.net/assets.github.com/images/icons'
22
+ }
23
+ },
24
+ renderer: JsonSchemaDocs::Renderer,
25
+ use_default_styles: true,
26
+ base_url: '',
12
27
 
13
28
  templates: {
14
- endpoint: "#{File.dirname(__FILE__)}/layouts/endpoint.md.erb",
15
- object: "#{File.dirname(__FILE__)}/layouts/object.md.erb",
29
+ default: "#{File.dirname(__FILE__)}/layouts/default.html.erb",
16
30
 
17
31
  includes: "#{File.dirname(__FILE__)}/layouts/includes",
32
+
33
+ links: "#{File.dirname(__FILE__)}/layouts/links.html.erb",
34
+ resource: "#{File.dirname(__FILE__)}/layouts/resource.html.erb",
35
+ },
36
+
37
+ landing_pages: {
38
+ index: "#{File.dirname(__FILE__)}/landing_pages/index.md",
39
+
40
+ variables: {} # only used for ERB landing pages
18
41
  },
19
42
 
20
43
  prmd: {
@@ -7,50 +7,92 @@ module JsonSchemaDocs
7
7
 
8
8
  attr_accessor :parsed_schema
9
9
 
10
+ DYNAMIC_PAGES = %i(links resource)
11
+ STATIC_PAGES = %i(index)
12
+
10
13
  def initialize(parsed_schema, options)
11
14
  @parsed_schema = parsed_schema
12
15
  @options = options
13
16
 
14
- %i(endpoint object).each do |sym|
17
+ @renderer = @options[:renderer].new(@parsed_schema, @options)
18
+
19
+ DYNAMIC_PAGES.each do |sym|
15
20
  if !File.exist?(@options[:templates][sym])
16
21
  raise IOError, "`#{sym}` template #{@options[:templates][sym]} was not found"
17
22
  end
18
23
  instance_variable_set("@json_schema_#{sym}_template", ERB.new(File.read(@options[:templates][sym]), nil, '-'))
19
24
  end
25
+
26
+ STATIC_PAGES.each do |sym|
27
+ if @options[:landing_pages][sym].nil?
28
+ instance_variable_set("@#{sym}_landing_page", nil)
29
+ elsif !File.exist?(@options[:landing_pages][sym])
30
+ raise IOError, "`#{sym}` landing page #{@options[:landing_pages][sym]} was not found"
31
+ end
32
+
33
+ landing_page_contents = File.read(@options[:landing_pages][sym])
34
+
35
+ instance_variable_set("@json_schema_#{sym}_landing_page", landing_page_contents)
36
+ end
20
37
  end
21
38
 
22
39
  def generate
23
40
  FileUtils.rm_rf(@options[:output_dir]) if @options[:delete_output]
24
41
 
25
42
  @parsed_schema.each_pair do |resource, schemata|
26
- %i(endpoint object).each do |type|
27
- contents = render(type, resource, schemata)
28
- write_file(type, resource, contents)
43
+ DYNAMIC_PAGES.each do |type|
44
+ layout = instance_variable_get("@json_schema_#{type}_template")
45
+ opts = @options.merge(helper_methods)
29
46
 
30
- contents = render(type, resource, schemata)
47
+ opts[:schemata_resource] = resource
48
+ opts[:schemata] = schemata
49
+
50
+ contents = layout.result(OpenStruct.new(opts).instance_eval { binding })
31
51
  write_file(type, resource, contents)
32
52
  end
33
53
  end
34
- end
35
54
 
36
- private
55
+ STATIC_PAGES.each do |name|
56
+ landing_page = instance_variable_get("@json_schema_#{name}_landing_page")
57
+
58
+ unless landing_page.nil?
59
+ write_file(:landing_page, name.to_s, landing_page, trim: false)
60
+ end
61
+ end
37
62
 
38
- def render(type, resource, schemata)
39
- layout = instance_variable_get("@json_schema_#{type}_template")
40
- opts = @options.merge(helper_methods)
63
+ if @options[:use_default_styles]
64
+ assets_dir = File.join(File.dirname(__FILE__), 'layouts', 'assets')
65
+ FileUtils.mkdir_p(File.join(@options[:output_dir], 'assets'))
66
+
67
+ sass = File.join(assets_dir, 'css', 'screen.scss')
68
+ system `sass --sourcemap=none #{sass}:#{@options[:output_dir]}/assets/style.css`
69
+ end
41
70
 
42
- opts[:schemata_resource] = resource
43
- opts[:schemata] = schemata
44
- layout.result(OpenStruct.new(opts).instance_eval { binding })
71
+ true
45
72
  end
46
73
 
74
+ private
75
+
47
76
  def write_file(type, name, contents, trim: true)
48
- if type == :object
49
- path = File.join(@options[:output_dir], 'objects', name.downcase)
50
- FileUtils.mkdir_p(path)
51
- elsif type == :endpoint
52
- path = File.join(@options[:output_dir], 'objects', name.downcase, 'endpoints')
53
- FileUtils.mkdir_p(path)
77
+ if type == :landing_page
78
+ if name == 'index'
79
+ path = @options[:output_dir]
80
+ else
81
+ path = File.join(@options[:output_dir], name)
82
+ FileUtils.mkdir_p(path)
83
+ end
84
+ elsif type == :resource
85
+ path = File.join(@options[:output_dir], 'resources', name.downcase)
86
+ elsif type == :links
87
+ path = File.join(@options[:output_dir], 'resources', name.downcase, 'links')
88
+ end
89
+
90
+ FileUtils.mkdir_p(path)
91
+
92
+ meta = { title: name, name: name }
93
+ if has_yaml?(contents)
94
+ # Split data
95
+ meta, contents = split_into_metadata_and_contents(contents)
54
96
  end
55
97
 
56
98
  if trim
@@ -59,8 +101,38 @@ module JsonSchemaDocs
59
101
  contents = contents.gsub(/^\s{4}/m, ' ')
60
102
  end
61
103
 
62
- filename = File.join(path, 'index.md')
63
- File.write(filename, contents) unless contents.nil?
104
+ filename = File.join(path, 'index.html')
105
+ output = @renderer.render(contents, meta: meta)
106
+ File.write(filename, output) unless output.nil?
107
+ end
108
+
109
+ def split_into_metadata_and_contents(contents, parse: true)
110
+ opts = {}
111
+ pieces = yaml_split(contents)
112
+ if pieces.size < 4
113
+ raise RuntimeError.new(
114
+ "The file '#{content_filename}' appears to start with a metadata section (three or five dashes at the top) but it does not seem to be in the correct format.",
115
+ )
116
+ end
117
+ # Parse
118
+ begin
119
+ if parse
120
+ meta = YAML.load(pieces[2]) || {}
121
+ else
122
+ meta = pieces[2]
123
+ end
124
+ rescue Exception => e # rubocop:disable Lint/RescueException
125
+ raise "Could not parse YAML for #{name}: #{e.message}"
126
+ end
127
+ [meta, pieces[4]]
128
+ end
129
+
130
+ def has_yaml?(contents)
131
+ contents =~ /\A-{3,5}\s*$/
132
+ end
133
+
134
+ def yaml_split(contents)
135
+ contents.split(/^(-{5}|-{3})[ \t]*\r?\n?/, 3)
64
136
  end
65
137
  end
66
138
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'commonmarker'
4
+
3
5
  module JsonSchemaDocs
4
6
  module Helpers
5
7
  SLUGIFY_PRETTY_REGEXP = Regexp.new("[^[:alnum:]._~!$&'()+,;=@]+").freeze
@@ -14,10 +16,24 @@ module JsonSchemaDocs
14
16
 
15
17
  def include(filename, opts = {})
16
18
  template = fetch_include(filename)
17
- opts = @options.merge(opts)
19
+ opts = { base_url: @options[:base_url] }.merge(opts)
18
20
  template.result(OpenStruct.new(opts.merge(helper_methods)).instance_eval { binding })
19
21
  end
20
22
 
23
+ def markdownify(string)
24
+ return '' if string.nil?
25
+ type = @options[:pipeline_config][:context][:unsafe] ? :UNSAFE : :DEFAULT
26
+ ::CommonMarker.render_html(string, type).strip
27
+ end
28
+
29
+ def types
30
+ @parsed_schema.keys
31
+ end
32
+
33
+ def schemata(name)
34
+ @parsed_schema[name]
35
+ end
36
+
21
37
  private
22
38
 
23
39
  def fetch_include(filename)
@@ -0,0 +1,7 @@
1
+ ---
2
+ title: API Reference documentation
3
+ ---
4
+
5
+ # API Reference documentation
6
+
7
+ These docs were generated by [json-schema-docs](https://github.com/gjtorikian/json-schema-docs).
@@ -0,0 +1,518 @@
1
+ #content {
2
+ padding: 20px 30px;
3
+ margin: 0px auto;
4
+ -webkit-text-size-adjust: 100%;
5
+ em {
6
+ font-style: italic;
7
+ }
8
+ strong {
9
+ font-family: "ProximaNova-Bold";
10
+ }
11
+ h1 {
12
+ margin: 15px 0;
13
+ line-height: 1.4em;
14
+ font-size: 2em;
15
+ margin-top: 0;
16
+ margin-bottom: 30px;
17
+ }
18
+ h2 {
19
+ margin: 15px 0;
20
+ line-height: 1.4em;
21
+ font-size: 1.5em;
22
+ margin-top: 30px;
23
+ padding-bottom: 10px;
24
+ border-bottom: 1px solid #eee;
25
+ position: relative;
26
+ .anchor {
27
+ opacity: 0;
28
+ position: absolute;
29
+ font-size: 16px;
30
+ top: 2px;
31
+ left: -21px;
32
+ }
33
+ &:hover {
34
+ .anchor {
35
+ opacity: 1;
36
+ }
37
+ }
38
+ }
39
+ h3 {
40
+ margin: 15px 0;
41
+ line-height: 1.4em;
42
+ font-size: 1.2em;
43
+ margin-top: 30px;
44
+ position: relative;
45
+ .anchor {
46
+ opacity: 0;
47
+ position: absolute;
48
+ font-size: 16px;
49
+ top: 2px;
50
+ left: -21px;
51
+ }
52
+ &:hover {
53
+ .anchor {
54
+ opacity: 1;
55
+ }
56
+ }
57
+ }
58
+ h4 {
59
+ margin: 15px 0;
60
+ line-height: 1.4em;
61
+ }
62
+ h5 {
63
+ margin: 15px 0;
64
+ line-height: 1.4em;
65
+ }
66
+ h6 {
67
+ margin: 15px 0;
68
+ line-height: 1.4em;
69
+ }
70
+ p {
71
+ margin: 15px 0;
72
+ line-height: 1.4em;
73
+ }
74
+ ul {
75
+ margin: 15px 0;
76
+ line-height: 1.4em;
77
+ padding-left: 1.5em;
78
+ list-style-type: disc;
79
+ li {
80
+ margin-bottom: 5px;
81
+ }
82
+ }
83
+ ol {
84
+ margin: 15px 0;
85
+ line-height: 1.4em;
86
+ padding-left: 1.5em;
87
+ list-style-type: decimal;
88
+ li {
89
+ margin-bottom: 5px;
90
+ }
91
+ }
92
+ figure {
93
+ margin: 15px 0;
94
+ line-height: 1.4em;
95
+ }
96
+ a {
97
+ color: #de4f4f;
98
+ }
99
+ img {
100
+ max-width: 100%;
101
+ }
102
+ code {
103
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
104
+ font-size: 0.8em;
105
+ line-height: 1.6em;
106
+ padding: 1px 4px;
107
+ background-color: #eee;
108
+ margin: 0 2px;
109
+ }
110
+ blockquote {
111
+ padding-left: 1.3em;
112
+ border-left: #eee solid 0.2em;
113
+ font-style: italic;
114
+ }
115
+ blockquote.warning {
116
+ border-color: #f00;
117
+ color: #f00;
118
+ }
119
+ dl {
120
+ margin-left: 1.5em;
121
+ dt {
122
+ .name {
123
+ font-family: monospace;
124
+ }
125
+ .type {
126
+ margin-left: 0.5em;
127
+ }
128
+ }
129
+ dd {
130
+ margin-left: 1.5em;
131
+ }
132
+ }
133
+ .edit-discuss-links {
134
+ margin-top: -25px;
135
+ margin-bottom: 40px;
136
+ }
137
+ table {
138
+ margin-top: 10px;
139
+ th {
140
+ text-align: left;
141
+ padding: 0 25px 0 25px;
142
+ }
143
+ thead th:first-child {
144
+ padding: 0;
145
+ }
146
+ td p {
147
+ padding: 0 25px 0 25px;
148
+ }
149
+ }
150
+ pre {
151
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
152
+ line-height: 1.6em;
153
+ margin: 20px 0;
154
+ overflow-x: auto;
155
+ position: relative;
156
+ padding: 20px 30px;
157
+ table {
158
+ width: 100%;
159
+ border-collapse: collapse;
160
+ padding: 0;
161
+ margin: 0;
162
+ }
163
+ tr {
164
+ width: 100%;
165
+ border-collapse: collapse;
166
+ padding: 0;
167
+ margin: 0;
168
+ }
169
+ td {
170
+ width: 100%;
171
+ border-collapse: collapse;
172
+ padding: 0;
173
+ margin: 0;
174
+ }
175
+ code {
176
+ background-color: #272822;
177
+ padding: 0;
178
+ margin: 0;
179
+ }
180
+ .gutter {
181
+ user-select: none;
182
+ width: 1.5em;
183
+ padding-right: 30px;
184
+ }
185
+ }
186
+ .highlight.html {
187
+ .code {
188
+ &:after {
189
+ font-family: "ProximaNova-Semibold";
190
+ position: absolute;
191
+ top: 0;
192
+ right: 0;
193
+ color: #ccc;
194
+ text-align: right;
195
+ font-size: 0.75em;
196
+ padding: 5px 10px 0;
197
+ letter-spacing: 1.5px;
198
+ line-height: 15px;
199
+ height: 15px;
200
+ font-weight: 600;
201
+ }
202
+ }
203
+ }
204
+ .highlight.js {
205
+ .code {
206
+ &:after {
207
+ font-family: "ProximaNova-Semibold";
208
+ position: absolute;
209
+ top: 0;
210
+ right: 0;
211
+ color: #ccc;
212
+ text-align: right;
213
+ font-size: 0.75em;
214
+ padding: 5px 10px 0;
215
+ letter-spacing: 1.5px;
216
+ line-height: 15px;
217
+ height: 15px;
218
+ font-weight: 600;
219
+ }
220
+ }
221
+ }
222
+ .highlight.bash {
223
+ .code {
224
+ &:after {
225
+ font-family: "ProximaNova-Semibold";
226
+ position: absolute;
227
+ top: 0;
228
+ right: 0;
229
+ color: #ccc;
230
+ text-align: right;
231
+ font-size: 0.75em;
232
+ padding: 5px 10px 0;
233
+ letter-spacing: 1.5px;
234
+ line-height: 15px;
235
+ height: 15px;
236
+ font-weight: 600;
237
+ }
238
+ }
239
+ }
240
+ .highlight.css {
241
+ .code {
242
+ &:after {
243
+ font-family: "ProximaNova-Semibold";
244
+ position: absolute;
245
+ top: 0;
246
+ right: 0;
247
+ color: #ccc;
248
+ text-align: right;
249
+ font-size: 0.75em;
250
+ padding: 5px 10px 0;
251
+ letter-spacing: 1.5px;
252
+ line-height: 15px;
253
+ height: 15px;
254
+ font-weight: 600;
255
+ }
256
+ }
257
+ }
258
+ .highlight.jsx {
259
+ .code {
260
+ &:after {
261
+ font-family: "ProximaNova-Semibold";
262
+ position: absolute;
263
+ top: 0;
264
+ right: 0;
265
+ color: #ccc;
266
+ text-align: right;
267
+ font-size: 0.75em;
268
+ padding: 5px 10px 0;
269
+ letter-spacing: 1.5px;
270
+ line-height: 15px;
271
+ height: 15px;
272
+ font-weight: 600;
273
+ }
274
+ }
275
+ }
276
+ .highlight.html.html {
277
+ .code {
278
+ &:after {
279
+ content: "HTML";
280
+ }
281
+ }
282
+ }
283
+ .highlight.js.html {
284
+ .code {
285
+ &:after {
286
+ content: "HTML";
287
+ }
288
+ }
289
+ }
290
+ .highlight.bash.html {
291
+ .code {
292
+ &:after {
293
+ content: "HTML";
294
+ }
295
+ }
296
+ }
297
+ .highlight.css.html {
298
+ .code {
299
+ &:after {
300
+ content: "HTML";
301
+ }
302
+ }
303
+ }
304
+ .highlight.jsx.html {
305
+ .code {
306
+ &:after {
307
+ content: "HTML";
308
+ }
309
+ }
310
+ }
311
+ .highlight.html.js {
312
+ .code {
313
+ &:after {
314
+ content: "JS";
315
+ }
316
+ }
317
+ }
318
+ .highlight.js.js {
319
+ .code {
320
+ &:after {
321
+ content: "JS";
322
+ }
323
+ }
324
+ }
325
+ .highlight.bash.js {
326
+ .code {
327
+ &:after {
328
+ content: "JS";
329
+ }
330
+ }
331
+ }
332
+ .highlight.css.js {
333
+ .code {
334
+ &:after {
335
+ content: "JS";
336
+ }
337
+ }
338
+ }
339
+ .highlight.jsx.js {
340
+ .code {
341
+ &:after {
342
+ content: "JS";
343
+ }
344
+ }
345
+ }
346
+ .highlight.html.bash {
347
+ .code {
348
+ &:after {
349
+ content: "Shell";
350
+ }
351
+ }
352
+ }
353
+ .highlight.js.bash {
354
+ .code {
355
+ &:after {
356
+ content: "Shell";
357
+ }
358
+ }
359
+ }
360
+ .highlight.bash.bash {
361
+ .code {
362
+ &:after {
363
+ content: "Shell";
364
+ }
365
+ }
366
+ }
367
+ .highlight.css.bash {
368
+ .code {
369
+ &:after {
370
+ content: "Shell";
371
+ }
372
+ }
373
+ }
374
+ .highlight.jsx.bash {
375
+ .code {
376
+ &:after {
377
+ content: "Shell";
378
+ }
379
+ }
380
+ }
381
+ .highlight.html.css {
382
+ .code {
383
+ &:after {
384
+ content: "CSS";
385
+ }
386
+ }
387
+ }
388
+ .highlight.js.css {
389
+ .code {
390
+ &:after {
391
+ content: "CSS";
392
+ }
393
+ }
394
+ }
395
+ .highlight.bash.css {
396
+ .code {
397
+ &:after {
398
+ content: "CSS";
399
+ }
400
+ }
401
+ }
402
+ .highlight.css.css {
403
+ .code {
404
+ &:after {
405
+ content: "CSS";
406
+ }
407
+ }
408
+ }
409
+ .highlight.jsx.css {
410
+ .code {
411
+ &:after {
412
+ content: "CSS";
413
+ }
414
+ }
415
+ }
416
+ .highlight.html.jsx {
417
+ .code {
418
+ &:after {
419
+ content: "JSX";
420
+ }
421
+ }
422
+ }
423
+ .highlight.js.jsx {
424
+ .code {
425
+ &:after {
426
+ content: "JSX";
427
+ }
428
+ }
429
+ }
430
+ .highlight.bash.jsx {
431
+ .code {
432
+ &:after {
433
+ content: "JSX";
434
+ }
435
+ }
436
+ }
437
+ .highlight.css.jsx {
438
+ .code {
439
+ &:after {
440
+ content: "JSX";
441
+ }
442
+ }
443
+ }
444
+ .highlight.jsx.jsx {
445
+ .code {
446
+ &:after {
447
+ content: "JSX";
448
+ }
449
+ }
450
+ }
451
+ > table {
452
+ width: 100%;
453
+ margin: 20px 0;
454
+ tr {
455
+ border-top: 1px solid #eee;
456
+ &:nth-child(2n) {
457
+ background-color: #f8f8f8;
458
+ }
459
+ }
460
+ th {
461
+ font-family: "ProximaNova-Semibold";
462
+ padding: 12px 13px;
463
+ border: 1px solid #eee;
464
+ vertical-align: middle;
465
+ text-align: left;
466
+ }
467
+ td {
468
+ border: 1px solid #eee;
469
+ vertical-align: middle;
470
+ padding: 6px 13px;
471
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
472
+ font-size: 0.8em;
473
+ line-height: 1.6em;
474
+ }
475
+ }
476
+ .bottom-nav {
477
+ height: 44px;
478
+ margin: 30px 0 25px;
479
+ border-bottom: 1px solid #eee;
480
+ padding-bottom: 25px;
481
+ a {
482
+ font-family: "ProximaNova-Semibold";
483
+ margin: 0 5px;
484
+ }
485
+ }
486
+ .edit-link {
487
+ text-align: center;
488
+ a {
489
+ color: #aaa;
490
+ font-family: "ProximaNova-Semibold";
491
+ &:before {
492
+ content: "";
493
+ display: inline-block;
494
+ width: 16px;
495
+ height: 16px;
496
+ background-size: 16px;
497
+ opacity: 0.3;
498
+ margin-right: 8px;
499
+ position: relative;
500
+ top: 2px;
501
+ }
502
+ }
503
+ }
504
+
505
+ .field-name {
506
+ font-weight: bold;
507
+ }
508
+
509
+ .field-entry {
510
+ margin-bottom: 4rem;
511
+ }
512
+ .description-wrapper {
513
+ > p {
514
+ padding-left: 1rem;
515
+ margin-bottom: 1rem;
516
+ }
517
+ }
518
+ }