Unified · Split
| @@ -109,6 +109,7 @@ · 108 unmodified lines | ||
| 109 | 109 | 'pages/qt', |
| 110 | 110 | 'pages/ramda', |
| 111 | 111 | 'pages/rdoc', |
| 112 | + 'pages/react', | |
| 112 | 113 | 'pages/react_native', |
| 113 | 114 | 'pages/reactivex', |
| 114 | 115 | 'pages/redis', |
| @@ -0,0 +1,24 @@ | ||
| 1 | +._react { | |
| 2 | + @extend %simple; | |
| 3 | + | |
| 4 | + .note { | |
| 5 | + @extend %note; | |
| 6 | + h4 { | |
| 7 | + margin-top: .25rem; | |
| 8 | + margin-bottom: .5rem; | |
| 9 | + } | |
| 10 | + } | |
| 11 | + | |
| 12 | + .note-orange { | |
| 13 | + @extend %note-orange; | |
| 14 | + } | |
| 15 | + | |
| 16 | + .note-blue { | |
| 17 | + @extend %note-blue; | |
| 18 | + } | |
| 19 | + | |
| 20 | + .note-green { | |
| 21 | + @extend %note-green; | |
| 22 | + } | |
| 23 | + | |
| 24 | +} | |
| @@ -13,7 +13,7 @@ Adding a documentation may look like a daunting task but once you get the hang o · 12 unmodified lines | ||
| 13 | 13 | 6. Generate the full documentation using the `thor docs:generate [my_doc] --force` command. Additionally, you can use the `--verbose` option to see which files are being created/updated/deleted (useful to see what changed since the last run), and the `--debug` option to see which URLs are being requested and added to the queue (useful to pin down which page adds unwanted URLs to the queue). |
| 14 | 14 | 7. Start the server, open the app, enable the documentation, and see how everything plays out. |
| 15 | 15 | 8. Tweak the scraper/filters and repeat 5) and 6) until the pages and metadata are ok. |
| 16 | −9. To customize the pages' styling, create an SCSS file in the `assets/stylesheets/pages/` directory and import it in both `application.css.scss` AND `application-dark.css.scss`. Both the file and CSS class should be named `_[type]` where [type] is equal to the scraper's `type` attribute (documentations with the same type share the same custom CSS and JS). Setting the type to `simple` will apply the general styling rules in `assets/stylesheets/pages/_simple.scss`, which can be used for documentations where little to no CSS changes are needed. | |
| 16 | +9. To customize the pages' styling, create an SCSS file in the `assets/stylesheets/pages/` directory and import it in `application.css.scss`. Both the file and CSS class should be named `_[type]` where [type] is equal to the scraper's `type` attribute (documentations with the same type share the same custom CSS and JS). Setting the type to `simple` will apply the general styling rules in `assets/stylesheets/pages/_simple.scss`, which can be used for documentations where little to no CSS changes are needed. | |
| 17 | 17 | 10. To add syntax highlighting or execute custom JavaScript on the pages, create a file in the `assets/javascripts/views/pages/` directory (take a look at the other files to see how it works). |
| 18 | 18 | 11. Add the documentation's icon in the `public/icons/docs/[my_doc]/` directory, in both 16x16 and 32x32-pixels formats. The icon spritesheet is automatically generated when you (re)start your local DevDocs instance. |
| 19 | 19 | 12. Add the documentation's copyright details to `options[:attribution]`. This is the data shown in the table on the [about](https://devdocs.io/about) page, and is ordered alphabetically. Please see an existing scraper for the typesetting. |
| @@ -0,0 +1,77 @@ | ||
| 1 | +module Docs | |
| 2 | + class React | |
| 3 | + class CleanHtmlReactDevFilter < Filter | |
| 4 | + def call | |
| 5 | + @doc = at_css('article') | |
| 6 | + | |
| 7 | + # Remove breadcrumbs before h1 | |
| 8 | + css('h1').each do |node| | |
| 9 | + if node.previous | |
| 10 | + node.previous.remove | |
| 11 | + end | |
| 12 | + end | |
| 13 | + | |
| 14 | + remove_selectors = [ | |
| 15 | + 'div.grid > a', # prev-next links | |
| 16 | + 'button', # "show more" etc. buttons | |
| 17 | + 'div.order-last', # code iframe containers | |
| 18 | + 'div.dark-image', # dark images | |
| 19 | + 'a[title="Open in CodeSandbox"]', # codesandbox links | |
| 20 | + ] | |
| 21 | + css(*remove_selectors).each do |node| | |
| 22 | + node.remove | |
| 23 | + end | |
| 24 | + | |
| 25 | + # Fix images not loading | |
| 26 | + css('img').remove_attr('srcset') | |
| 27 | + | |
| 28 | + # Remove recipe blocks - TODO transform to outgoing link to docs | |
| 29 | + css('h4[id^="examples-"]').each do |node| | |
| 30 | + node.parent.parent.parent.remove | |
| 31 | + end | |
| 32 | + | |
| 33 | + # Transform callout blocks | |
| 34 | + class_transform = { | |
| 35 | + '.expandable-callout[class*=yellow]' => 'note note-orange', # pitfalls, experimental | |
| 36 | + '.expandable-callout[class*=green]' => 'note note-green', # note | |
| 37 | + '.expandable-callout[class*=gray]' => 'note', # canary | |
| 38 | + '.bg-card' => 'note', # you will learn | |
| 39 | + 'details' => 'note note-blue' # deep dive | |
| 40 | + } | |
| 41 | + | |
| 42 | + class_transform.each do |old_class, new_class| | |
| 43 | + css(old_class).each do |node| | |
| 44 | + node.set_attribute('class', new_class) | |
| 45 | + end | |
| 46 | + end | |
| 47 | + | |
| 48 | + # Transform h3 to h4 inside callouts | |
| 49 | + css('.note h3', '.note h2').each do |node| | |
| 50 | + new_node = Nokogiri::XML::Node.new('h4', @doc) | |
| 51 | + new_node.content = node.content | |
| 52 | + node.replace(new_node) | |
| 53 | + end | |
| 54 | + | |
| 55 | + # Remove styling divs while lifting children | |
| 56 | + styling_prefixes = %w[ps- mx- my- px- py- mb- sp- rounded-] | |
| 57 | + selectors = styling_prefixes.map { |prefix| "div[class*=\"#{prefix}\"]:not(.note)" } | |
| 58 | + css(*selectors, 'div[class=""]', 'div.cm-line').each do |node| | |
| 59 | + node.before(node.children).remove | |
| 60 | + end | |
| 61 | + | |
| 62 | + # Syntax highlighting | |
| 63 | + css('pre br').each do |node| | |
| 64 | + node.replace("\n") | |
| 65 | + end | |
| 66 | + css('pre').each do |node| | |
| 67 | + node['data-language'] = 'jsx' | |
| 68 | + end | |
| 69 | + | |
| 70 | + # Remove styling except for callouts and images | |
| 71 | + css('*:not([class*=image]):not(.note)').remove_attr('class').remove_attr('style') | |
| 72 | + | |
| 73 | + doc | |
| 74 | + end | |
| 75 | + end | |
| 76 | + end | |
| 77 | +end | |
| @@ -0,0 +1,32 @@ | ||
| 1 | +module Docs | |
| 2 | + class React | |
| 3 | + class EntriesReactDevFilter < Docs::EntriesFilter | |
| 4 | + def get_name | |
| 5 | + name = at_css('article h1')&.content | |
| 6 | + | |
| 7 | + update_canary_copy(name) | |
| 8 | + end | |
| 9 | + | |
| 10 | + def get_type | |
| 11 | + # Category is the opened category in the sidebar | |
| 12 | + category = css('a:has(> span.text-link) > div').first&.content | |
| 13 | + # The grey category in the sidebar | |
| 14 | + top_category = css('h3:has(~ li a.text-link)') | |
| 15 | + .last&.content | |
| 16 | + &.sub(/@.*$/, '') # remove version tag | |
| 17 | + &.sub(/^./, &:upcase) # capitalize first letter | |
| 18 | + &.concat(": ") | |
| 19 | + is_learn_page = path.start_with?('learn/') || slug == 'learn' | |
| 20 | + prefix = is_learn_page ? 'Learn: ' : top_category || '' | |
| 21 | + | |
| 22 | + update_canary_copy(prefix + (category || 'Miscellaneous')) | |
| 23 | + end | |
| 24 | + | |
| 25 | + def update_canary_copy(string) | |
| 26 | + canary_copy = '- This feature is available in the latest Canary' | |
| 27 | + | |
| 28 | + string.sub(canary_copy, ' (Canary)') | |
| 29 | + end | |
| 30 | + end | |
| 31 | + end | |
| 32 | +end | |
| @@ -1,38 +1,59 @@ | ||
| 1 | 1 | module Docs |
| 2 | 2 | class React < UrlScraper |
| 3 | + | |
| 3 | 4 | self.name = 'React' |
| 4 | − self.type = 'simple' | |
| 5 | − self.release = '18.2.0' | |
| 6 | − self.base_url = 'https://reactjs.org/docs/' | |
| 7 | − self.root_path = 'hello-world.html' | |
| 5 | + self.type = 'react' | |
| 8 | 6 | self.links = { |
| 9 | − home: 'https://reactjs.org/', | |
| 7 | + home: 'https://react.dev/', | |
| 10 | 8 | code: 'https://github.com/facebook/react' |
| 11 | 9 | } |
| 12 | 10 | |
| 13 | − html_filters.push 'react/entries', 'react/clean_html' | |
| 14 | − | |
| 15 | − options[:skip] = %w( | |
| 16 | − codebase-overview.html | |
| 17 | − design-principles.html | |
| 18 | − how-to-contribute.html | |
| 19 | − implementation-notes.html | |
| 20 | − ) | |
| 21 | − | |
| 22 | − options[:replace_paths] = { | |
| 23 | − 'more-about-refs.html' => 'refs-and-the-dom.html', | |
| 24 | − 'interactivity-and-dynamic-uis.html' => 'state-and-lifecycle.html', | |
| 25 | − 'working-with-the-browser.html' => 'refs-and-the-dom.html', | |
| 26 | − 'top-level-api.html' => 'react-api.html', | |
| 27 | − } | |
| 28 | − | |
| 29 | 11 | options[:attribution] = <<-HTML |
| 30 | 12 | © 2013–present Facebook Inc.<br> |
| 31 | 13 | Licensed under the Creative Commons Attribution 4.0 International Public License. |
| 32 | 14 | HTML |
| 33 | 15 | |
| 16 | + version do | |
| 17 | + self.release = '19' | |
| 18 | + self.base_url = 'https://react.dev' | |
| 19 | + self.initial_paths = %w(/reference/react /learn) | |
| 20 | + html_filters.push 'react/entries_react_dev', 'react/clean_html_react_dev' | |
| 21 | + | |
| 22 | + options[:only_patterns] = [/\A\/learn/, /\A\/reference/] | |
| 23 | + end | |
| 24 | + | |
| 25 | + version '18' do | |
| 26 | + self.release = '18.3.1' | |
| 27 | + self.base_url = 'https://18.react.dev' | |
| 28 | + self.initial_paths = %w(/reference/react /learn) | |
| 29 | + html_filters.push 'react/entries_react_dev', 'react/clean_html_react_dev' | |
| 30 | + | |
| 31 | + options[:only_patterns] = [/\A\/learn/, /\A\/reference/] | |
| 32 | + end | |
| 33 | + | |
| 34 | + version '17' do | |
| 35 | + self.release = '17.0.2' | |
| 36 | + self.base_url = 'https://17.reactjs.org/docs/' | |
| 37 | + self.root_path = 'hello-world.html' | |
| 38 | + html_filters.push 'react/entries', 'react/clean_html' | |
| 39 | + | |
| 40 | + options[:skip] = %w( | |
| 41 | + codebase-overview.html | |
| 42 | + design-principles.html | |
| 43 | + how-to-contribute.html | |
| 44 | + implementation-notes.html | |
| 45 | + ) | |
| 46 | + | |
| 47 | + options[:replace_paths] = { | |
| 48 | + 'more-about-refs.html' => 'refs-and-the-dom.html', | |
| 49 | + 'interactivity-and-dynamic-uis.html' => 'state-and-lifecycle.html', | |
| 50 | + 'working-with-the-browser.html' => 'refs-and-the-dom.html', | |
| 51 | + 'top-level-api.html' => 'react-api.html', | |
| 52 | + } | |
| 53 | + end | |
| 54 | + | |
| 34 | 55 | def get_latest_version(opts) |
| 35 | − doc = fetch_doc('https://reactjs.org/docs/getting-started.html', opts) | |
| 56 | + doc = fetch_doc('https://react.dev/', opts) | |
| 36 | 57 | doc.at_css('a[href="/versions"]').content.strip[1..-1] |
| 37 | 58 | end |
| 38 | 59 | end |
Binary file not shown.
Binary file not shown.
| @@ -1,2 +1,2 @@ | ||
| 1 | −https://es.m.wikipedia.org/wiki/React#/media/Archivo%3AReact.svg | |
| 2 | −https://github.com/facebook/react/blob/master/docs/img/logo.svg | |
| 1 | +https://github.com/reactjs/react.dev/blob/master/public/favicon-16x16.png | |
| 2 | +https://github.com/reactjs/react.dev/blob/master/public/favicon-32x32.png | |