Guides visual redesign (#51341)

Improve the visual presentation of the Rails Guides, bringing them more inline with the new marketing rubyonrails.org site, as part of a project with the Rails Foundation.

The CSS has been recreated from SCSS files, generated into the final pieces. The stylesrc directory contains those commented source files. The generate task will now process those scss => css files.

Co-authored-by: Carlos Antonio da Silva <carlosantoniodasilva@gmail.com>
This commit is contained in:
John Athayde 2024-03-20 15:50:51 -04:00 committed by GitHub
parent 9f01421d7d
commit 1e4f12c12c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
67 changed files with 2777 additions and 1392 deletions

27
guides/README.md Normal file

@ -0,0 +1,27 @@
# Rails Guides Redesign 2024
## About the Project
The Rails Guides Visual Refresh occured in Q1 2024, and was intended to bring the visual style of the guides inline with the rubyonrails.org site.
## Editing Depedencies
The editing files for the Guides rebuild reside in `stylesrc` and use SCSS to improve developer experience. The code base relies on `include_media` (https://eduardoboucas.github.io/include-media/) to enable inline media-queries adjustments. We've also relied on the standard `normalize.css` (https://necolas.github.io/normalize.css/) to help bring all browsers together.
## Building the Guides in Development
To generate new guides into static files, type `rake guides:generate` from inside the `guides` folder. If you make changes to the HTML or ERB, you'll need to remove the "output" directory before running this command. The master SCSS files (style.scss, highlight.scss) will compile as part of this process.
## FAQ
### Why are you not using CSS variables?
Per the MDN documentation on CSS custom properties (https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties), they are not supported in media or container queries at this point (Feb 2024). They may in future releases, and we should pivot to that when they are more wholistically supported. SCSS variables, because they are interpolated at build, serve a similar purpose and allow us the flexibilty to support much older browsers.
### Why do we include LTR and RTL?
LTR/RTL (Left to right/right to left) is a layout change based on the nature of the language the site is being displayed in. Arabic and Farsi are two well known "RTL" languages. If the site is automatically translated, then the layout will adjust (mirror horizontally) to be more in line with the text.
### Why is Dark Mode in a seperate file
IncludeMedia does not handle `prefers-color-scheme` at this time, so it was extracted.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 B

@ -1 +0,0 @@
<svg fill="none" stroke="#eee" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m16 4v12l-4-2-4 2v-12m-2 16h12a2 2 0 0 0 2-2v-12a2 2 0 0 0 -2-2h-12a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2z" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>

Before

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 376 B

@ -1 +0,0 @@
<svg fill="none" stroke="#a6e22e" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m5 13 4 4 10-10" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>

Before

Width:  |  Height:  |  Size: 186 B

@ -1 +0,0 @@
<svg fill="none" stroke="#444" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="m10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 0 0 -2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 0 0 -1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 0 0 1.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path d="m15 12a3 3 0 1 1 -6 0 3 3 0 0 1 6 0z"/></g></svg>

Before

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 B

@ -1 +0,0 @@
<svg fill="none" stroke="#f9d9d8" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m7 11.5v2.5m0-2.5v-6a1.5 1.5 0 1 1 3 0m-3 6a1.5 1.5 0 0 0 -3 0v2a7.5 7.5 0 0 0 15 0v-5a1.5 1.5 0 0 0 -3 0m-6-3v5.5m0-5.5v-1a1.5 1.5 0 0 1 3 0v1m0 0v5.5m0-5.5a1.5 1.5 0 0 1 3 0v3m0 0v2.5" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>

Before

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 B

@ -0,0 +1 @@
<svg fill="none" height="18" viewBox="0 0 687 18" width="687" xmlns="http://www.w3.org/2000/svg"><path d="m358 8.50008 329-.00003" stroke="#c81418"/><path d="m0 8.50008h329" stroke="#c81418"/><path clip-rule="evenodd" d="m351.712 1.08696c.473.2102.934.44889 1.381.71432l-.071.65833c-.449-.25428-.911-.48052-1.385-.67682zm-16.859 8.6916c-.19.44074-.364.89314-.52 1.35594l-1.092-.4899c.161-.461.337-.91197.529-1.35182zm2.522-4.11275-.855-.77421c.318-.36896.651-.72067.996-1.05383l.844.76437c-.343.33569-.672.69072-.985 1.06367zm4.329-3.48218-.527-.91995c.439-.21257.89-.400236 1.349-.561524l.516.898714c-.457.16735-.903.36215-1.338.58276zm5-1.30064-.185-.88244759c.038-.00036138.077-.00054241.116-.00054241.466 0 .927.0261359 1.381.0772411l.178.8492139c-.359-.033344-.722-.050329-1.088-.050329-.134 0-.269.002298-.402.006864zm8.969 4.16376c-2.32-2.30421-5.307-3.69085-8.567-3.69085-7.094 0-12.898 6.56929-13.344 14.8709l10.057 1.7732c-.204-.8597-.313-1.7668-.313-2.7042 0-5.48458 3.732-9.93073 8.336-9.93073 1.114 0 2.177.26034 3.148.73274zm-3.013.7624c-.262-.03097-.528-.04682-.797-.04682-.222 0-.442.01083-.66.03208l-.082.76181c.361-.0662.73-.10054 1.107-.10054.121 0 .241.00357.361.01061zm-7.617 10.13175c-.024-.2864-.037-.5769-.037-.8709 0-.2436.009-.485.026-.7235l-1.056-.4738c-.055.4511-.084.9124-.084 1.3817 0 .057.001.1138.001.1706zm-.671-3.9372.886.8029c.121-.529.282-1.0378.481-1.5211l-.804-.7282c-.22.4595-.409.943-.563 1.4464zm1.354-2.80683.56.97633c.272-.46939.583-.90491.926-1.30024l-.497-.86582c-.358.36123-.689.75946-.989 1.18973zm2.252-2.23226.203.96996c.407-.32961.845-.61083 1.306-.83673l-.176-.83857c-.465.18713-.911.42402-1.333.70534z" fill="#c81418" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

@ -0,0 +1 @@
<svg fill="none" height="60" viewBox="0 0 60 60" width="60" xmlns="http://www.w3.org/2000/svg"><rect fill="#c81418" height="60" rx="10" width="60"/><g fill="#fff"><path clip-rule="evenodd" d="m50.1525 24.0866c-3.9042-6.1074-10.0793-10.0507-17.029-10.0507-10.6287 0-19.4457 9.2233-21.0982 21.3056h15.368c.4248-8.3117 6.2175-14.8962 13.301-14.8962 3.5025 0 6.6895 1.6098 9.0679 4.2423z" fill-rule="evenodd"/><path clip-rule="evenodd" d="m43.8337 21.6004c-.5319-.1586-1.077-.2774-1.633-.3535l-.0365 1.0453c.557.0485 1.1031.1442 1.6354.2837zm-14.0129 13.0792c.0462-.5669.1211-1.1239.2231-1.6686l-1.6331-.5944c-.1198.5375-.2155 1.0867-.2856 1.6459zm-.1131-5.9822 1.3303 1.0394c.2242-.52.4754-1.0208.7512-1.4998l-1.2728-.9944c-.2921.465-.5623.9507-.8087 1.4548zm2.9106-4.0815.8672 1.2857c.3785-.4165.7804-.8032 1.2031-1.1569l-.8192-1.2146c-.4359.3321-.8536.6949-1.2511 1.0858zm4.1931-2.7388.3687 1.2858c.5006-.2289 1.018-.4174 1.5494-.5622l-.3436-1.1981c-.5374.1189-1.0631.278-1.5745.4745z" fill-rule="evenodd"/><path clip-rule="evenodd" d="m44.0404 15.6794c-.5238-.3639-1.0607-.704-1.6097-1.0192l-.0385 1.1008c.5497.3038 1.087.6337 1.6108.9885zm-30.9267 12.9192c.1985-.5153.4108-1.0216.6361-1.5183l-1.7857-.65c-.2251.497-.4377 1.0032-.6373 1.5179zm3.9407-9.7871 1.4476 1.131c.3819-.404.7757-.7923 1.1808-1.1642l-1.4441-1.1283c-.4056.3718-.8006.7592-1.1843 1.1615zm7.9648-5.4618.9447 1.4006c.5238-.214 1.0565-.4052 1.5972-.5726l-.9372-1.3895c-.5428.1647-1.0779.3522-1.6047.5615zm8.96-1.3497.3947 1.3767c.5963.0397 1.1861.1076 1.7687.2026l-.3879-1.3529c-.585-.1018-1.1772-.1776-1.7755-.2264z" fill-rule="evenodd"/><path d="m14.5601 47.088h-1.33v-1.68h3.556v.854c0 2.38-1.568 3.878-3.85 3.878-2.492 0-4.25603-1.82-4.25603-4.438s1.76403-4.438 4.22803-4.438c2.212 0 3.486 1.274 3.808 3.024h-2.296c-.238-.658-.7-1.05-1.512-1.05-1.246 0-1.96 1.036-1.96 2.464 0 1.47.756 2.464 1.988 2.464.854 0 1.414-.42 1.624-1.078zm6.8326 3.052c-2.268 0-3.752-1.288-3.752-3.654v-5.082h2.24v4.886c0 1.218.574 1.848 1.512 1.848.924 0 1.498-.63 1.498-1.848v-4.886h2.24v5.096c0 2.352-1.47 3.64-3.738 3.64zm7.186-8.736v8.596h-2.254v-8.596zm3.499 6.65h.924c1.428 0 2.226-.91 2.226-2.352 0-1.456-.798-2.366-2.226-2.366h-.924zm-2.212 1.946v-8.596h3.248c2.702 0 4.34 1.68 4.34 4.298s-1.638 4.298-4.34 4.298zm8.5312-8.596h6.146v1.932h-3.934v1.344h3.598v1.89h-3.598v1.484h3.934v1.946h-6.146zm6.7838 6.048h2.338c.182.588.686.882 1.386.882.686 0 1.162-.294 1.162-.826 0-.406-.266-.588-.812-.714l-1.652-.35c-1.26-.28-2.212-.938-2.212-2.394 0-1.68 1.4-2.786 3.304-2.786 2.1 0 3.29 1.148 3.528 2.632h-2.198c-.182-.476-.574-.84-1.316-.84-.644 0-1.078.28-1.078.756 0 .378.266.588.714.686l1.68.392c1.47.35 2.282 1.148 2.282 2.478 0 1.764-1.484 2.772-3.36 2.772-2.058 0-3.458-.994-3.766-2.688z"/></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

@ -0,0 +1 @@
<svg height="34" viewBox="0 0 28 34" width="28" xmlns="http://www.w3.org/2000/svg"><g style="fill:none;fill-rule:evenodd;stroke:#fff;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.71" transform="translate(1.141 .927)"><path d="m25.71745 32.14683h-22.50276c-.85259 0-1.67026-.3387-2.27313-.9415-.60287-.6029-.94156-1.4206-.94156-2.2732"/><path d="m12.85875 2.14313h-8.5725c-1.13678 0-2.22701.45159-3.03084 1.25542-.80382.80382-1.25541 1.89405-1.25541 3.03083v22.50285c0-.8526.33869-1.6703.94156-2.2732.60287-.6028 1.42054-.9415 2.27313-.9415h21.43126c.2842 0 .5567-.1129.7577-.3139.201-.2009.3138-.4735.3138-.7577v-21.43124c0-.28419-.1128-.55675-.3138-.7577-.201-.20096-.4735-.31386-.7577-.31386h-3.2147"/><path d="m23.574 32.147v-6.429"/><path d="m21.43125 17.14503-4.2863-4.2863-4.2862 4.2863v-15.0019c0-.56839.2258-1.1135.6277-1.51542.4019-.40191.947-.62771 1.5154-.62771h4.2863c.2814 0 .5601.05544.8201.16314s.4963.26556.6953.46457.3569.43527.4646.69528c.1077.26002.1631.5387.1631.82014z"/></g></svg>

After

Width:  |  Height:  |  Size: 1014 B

@ -0,0 +1 @@
<svg fill="none" height="36" viewBox="0 0 36 36" width="36" xmlns="http://www.w3.org/2000/svg"><g stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.71"><path d="m30.8587 34.0734h-22.50276c-.85259 0-1.67026-.3387-2.27313-.9415-.60287-.6029-.94156-1.4206-.94156-2.2732"/><path d="m18 4.0697h-8.5725c-1.13678 0-2.22701.45159-3.03084 1.25542-.80382.80382-1.25541 1.89405-1.25541 3.03083v22.50285c0-.8526.33869-1.6703.94156-2.2732.60287-.6028 1.42054-.9415 2.27313-.9415h21.43126c.2842 0 .5567-.1129.7577-.3139.201-.2009.3138-.4735.3138-.7577v-21.43124c0-.28419-.1128-.55675-.3138-.7577-.201-.20096-.4735-.31386-.7577-.31386h-3.2147"/><path d="m28.7156 34.0734v-6.4293"/><path d="m26.5725 19.0716-4.2863-4.2863-4.2862 4.2863v-15.0019c0-.56839.2258-1.1135.6277-1.51542.4019-.40191.947-.62771 1.5154-.62771h4.2863c.2814 0 .5601.05544.8201.16314s.4963.26556.6953.46457.3569.43527.4646.69528c.1077.26002.1631.5387.1631.82014z"/></g></svg>

After

Width:  |  Height:  |  Size: 956 B

@ -0,0 +1 @@
<svg fill="none" height="36" viewBox="0 0 36 36" width="36" xmlns="http://www.w3.org/2000/svg"><g stroke="#00b9c4" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.71"><path d="m22.2862 25.5009v6.4294c0 .5684-.2257 1.1135-.6277 1.5154-.4019.402-.947.6277-1.5154.6277h-4.2862c-.5684 0-1.1135-.2257-1.5154-.6277-.402-.4019-.6278-.947-.6278-1.5154v-6.4294"/><path d="m13.7137 29.7872h8.5725"/><path d="m18 1.92656v2.14312"/><path d="m2.99817 16.9284h2.14312"/><path d="m6.21289 6.21281 1.57163 1.51448"/><path d="m33.0019 16.9284h-2.1431"/><path d="m29.7872 6.21281-1.5716 1.51448"/><path d="m13.7137 16.2141c.5684 0 1.1135.2258 1.5155.6277.4019.4019.6277.947.6277 1.5154v7.1437"/><path d="m20.1432 25.5009v-7.1437c0-.2814.0554-.5601.1631-.8201.1077-.2601.2656-.4963.4646-.6953s.4353-.3569.6953-.4646.5387-.1631.8201-.1631"/><path d="m13.5995 25.5009h8.8011c1.5933-.7892 2.9311-2.0127 3.8588-3.5295.9278-1.5169 1.4078-3.2651 1.3847-5.043-.044-2.544-1.0742-4.9714-2.8734-6.7706-1.7991-1.79915-4.2266-2.82936-6.7706-2.87342-2.544.04406-4.9715 1.07427-6.7707 2.87342-1.7991 1.7992-2.82932 4.2266-2.87338 6.7706-.0231 1.7779.45693 3.5261 1.38471 5.043.92777 1.5168 2.26547 2.7403 3.85877 3.5295z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -0,0 +1 @@
<svg fill="none" height="36" viewBox="0 0 36 36" width="36" xmlns="http://www.w3.org/2000/svg"><g stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.71"><path d="m3.35532 8.35593h29.28938s1.4287 0 1.4287 1.42875v12.14442s.0001 1.4287-1.4287 1.4287h-29.28938s-1.42875 0-1.42875-1.4287v-12.14442s0-1.42875 1.42875-1.42875z"/><path d="m6.21283 23.3578v10.7156"/><path d="m29.7872 23.3578v10.7156"/><path d="m7.28436 4.06968c0 .28144.05544.56013.16314.82014.1077.26002.26556.49628.46457.69528.19901.19901.43526.35687.69528.46457.26002.10771.5387.16314.82014.16314s.56012-.05543.82011-.16314c.26-.1077.4963-.26556.6953-.46457.199-.199.3569-.43526.4646-.69528.1077-.26001.1631-.5387.1631-.82014 0-.56839-.2258-1.1135-.6277-1.51541-.4019-.40192-.94702-.62771-1.51541-.62771s-1.11351.22579-1.51542.62771c-.40191.40191-.62771.94702-.62771 1.51541z"/><path d="m24.4294 4.06968c0 .5684.2258 1.11351.6277 1.51542.4019.40192.947.62771 1.5154.62771s1.1135-.22579 1.5154-.62771c.4019-.40191.6277-.94702.6277-1.51542 0-.56839-.2258-1.1135-.6277-1.51541-.4019-.40192-.947-.62771-1.5154-.62771s-1.1135.22579-1.5154.62771c-.4019.40191-.6277.94702-.6277 1.51541z"/><path d="m12.6422 8.35593-10.71563 10.71567"/><path d="m21.2147 8.35593-15.00187 15.00187"/><path d="m29.7872 8.35593-15.0019 15.00187"/><path d="m34.0734 12.6422-10.7156 10.7156"/></g></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
<svg fill="none" height="36" viewBox="0 0 36 36" width="36" xmlns="http://www.w3.org/2000/svg"><g stroke="#c81418" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="1.71"><path d="m16.8591 15.4997v-11.00139c0-1.42875 1.143-2.57174 2.5718-2.57174 1.4287 0 2.5717 1.14299 2.5717 2.57174v11.00139"/><path d="m16.8591 15.4997v-9.42972c0-1.42875-1.143-2.57175-2.5717-2.57175s-2.5718 1.143-2.5718 2.57175v15.85902l-4.00046-2.286c-1.143-.4286-2.57175-.1428-3.429.8573s-.71436 2.5717.14289 3.5719l5.42924 6.1436c2.14313 2.4289 5.28633 3.8576 8.57243 3.8576h5.2864c4.7149 0 8.5725-3.8576 8.5725-8.5725v-16.14484c0-1.42875-1.143-2.57173-2.5717-2.57173-1.4288 0-2.5718 1.14298-2.5718 2.57173v6.14364"/><path d="m27.1462 15.4997v-9.42972c0-1.42875-1.143-2.57175-2.5718-2.57175-1.4287 0-2.5717 1.143-2.5717 2.57175v9.42972"/></g></svg>

After

Width:  |  Height:  |  Size: 856 B

@ -0,0 +1 @@
<svg height="22" viewBox="0 0 24 22" width="24" xmlns="http://www.w3.org/2000/svg"><g style="fill:none;fill-rule:evenodd;stroke:#fff;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.14" transform="translate(1.284 1.291)"><path d="m2.85752 11.55661v7.8581h5.715v-5.715c0-.3789.15052-.7423.41842-1.0103.268-.2679.6314-.4184 1.0103-.4184h1.4288c.3789 0 .7423.1505 1.0103.4184.2679.268.4184.6314.4184 1.0103v5.715h5.715v-7.8581m-18.57374-1.4288 9.70594-9.70598c.132-.13363.2893-.23972.4626-.31213s.3593-.1097.5471-.1097.3738.03729.5471.1097.3305.1785.4625.31213l9.706 9.70598"/><path d="m15.002 3.698v-2.781h3.572v6.353"/></g></svg>

After

Width:  |  Height:  |  Size: 637 B

@ -0,0 +1 @@
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><g stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.14"><path d="m4.14188 13.8479v7.8581h5.715v-5.715c0-.3789.15052-.7423.41842-1.0103.268-.2679.6314-.4184 1.0103-.4184h1.4288c.3789 0 .7423.1505 1.0103.4184.2679.268.4184.6314.4184 1.0103v5.715h5.715v-7.8581"/><path d="m1.28436 12.4191 9.70594-9.70598c.132-.13363.2893-.23972.4626-.31213s.3593-.1097.5471-.1097.3738.03729.5471.1097.3305.1785.4625.31213l9.706 9.70598"/><path d="m16.2863 5.98973v-2.78129h3.5718v6.35317"/></g></svg>

After

Width:  |  Height:  |  Size: 604 B

@ -0,0 +1 @@
<svg fill="none" height="36" viewBox="0 0 36 36" width="36" xmlns="http://www.w3.org/2000/svg"><g stroke="#666" stroke-width="1.71"><path d="m31.9303 27.6441h-15.0019l-8.57251 6.4293v-6.4293h-4.28625c-.56839 0-1.11351-.2258-1.51542-.6277s-.62771-.9471-.62771-1.5155v-21.43122c0-.56838.2258-1.11351.62771-1.51541.40191-.40192.94703-.62771 1.51542-.62771h27.86066c.5683 0 1.1135.22579 1.5154.62771.4019.4019.6277.94703.6277 1.51541v21.43122c0 .5684-.2258 1.1136-.6277 1.5155s-.9471.6277-1.5154.6277z" stroke-linecap="round" stroke-linejoin="round"/><path d="m13.7137 10.4991c.0002-.78575.2163-1.55636.6249-2.22759.4085-.67123.9936-1.21724 1.6916-1.57837.6978-.36112 1.4816-.52345 2.2654-.46924.784.05419 1.5379.32284 2.1794.77656.6415.45373 1.146 1.07508 1.4582 1.79614.3123.72106.4203 1.5141.3123 2.2924s-.4277 1.512-.9245 2.1208-1.1514 1.0693-1.8923 1.3312c-.418.1478-.7799.4216-1.0358.7837-.2559.3622-.3932.7946-.3929 1.238v.3657" stroke-linecap="round" stroke-linejoin="round"/><path d="m18 22.2863c-.2959 0-.5358-.2399-.5358-.5358s.2399-.5358.5358-.5358"/><path d="m18 22.2863c.2959 0 .5358-.2399.5358-.5358s-.2399-.5358-.5358-.5358"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1 @@
<svg fill="none" height="36" viewBox="0 0 36 36" width="36" xmlns="http://www.w3.org/2000/svg"><g stroke="#c4a500" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.71"><path d="m23.3578 10.5148h5.3578c.5684 0 1.1135.2258 1.5154.6277s.6277.947.6277 1.5154v14.1146c-.0001.568-.2257 1.1127-.6272 1.5145l-5.1749 5.1749c-.4018.4015-.9465.6271-1.5145.6273h-16.25774c-.56839 0-1.1135-.2258-1.51542-.6278-.40191-.4019-.6277-.947-.6277-1.5154v-19.2881c0-.5684.22579-1.1135.6277-1.5154.40192-.4019.94703-.6277 1.51542-.6277h5.35784"/><path d="m22.2863 34.0892v-6.4294c0-.2815.0554-.5601.1631-.8202.1077-.26.2656-.4962.4646-.6952s.4352-.3569.6952-.4646c.2601-.1077.5387-.1631.8202-.1631h6.4294"/><path d="m14.7853 5.15697c0 .85258.3387 1.67025.9415 2.27312.6029.60287 1.4206.94156 2.2732.94156s1.6702-.33869 2.2731-.94156.9416-1.42054.9416-2.27312c0-.85259-.3387-1.67026-.9416-2.27313s-1.4205-.94156-2.2731-.94156-1.6703.33869-2.2732.94156c-.6028.60287-.9415 1.42054-.9415 2.27313z"/><path d="m18 15.8726v-7.50095"/><path d="m10.499 21.2304h15.0019"/><path d="m10.499 27.6598h6.4294"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -1 +0,0 @@
<svg fill="none" stroke="#d5e9f6" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m13 16h-1v-4h-1m1-4h.01m8.99 4a9 9 0 1 1 -18 0 9 9 0 0 1 18 0z" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>

Before

Width:  |  Height:  |  Size: 233 B

@ -0,0 +1 @@
<svg fill="none" height="75" viewBox="0 0 75 75" width="75" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path d="m7.36609 24.1071h60.2678v21.4286h-60.2678z"/></clipPath><circle cx="37.5" cy="37.5" fill="#c81418" r="37.5"/><g clip-path="url(#a)"><path d="m67.0194 34.8211v2.7546h-4.8886v1.2713h2.467c1.3209 0 2.7271.982 2.8112 2.6562l.0039.159v1.0594c-.0588 2.0143-1.703 2.7717-2.7265 2.8133l-.0886.0018h-4.9492v-2.7394l5.0097-.0152v-1.3318l-.7969.0005-.2323.0005-.0566.0002-.0855.0005-.03.0003-.0373.0005-.011.0006c.0003.0002.0089.0005.023.0008l.0349.0005c.0205.0003.0448.0006.0705.0008l.0523.0004-.104-.0003c-.2105-.001-.5709-.0027-1.1579-.0053-1.1887 0-2.7333-.8966-2.8259-2.6484l-.0043-.1668v-.9535c0-1.8068 1.5256-2.801 2.7224-2.8579l.1078-.0026zm-12.5167 0v7.9459h4.1319v2.7697h-7.1892v-10.7156zm-4.3135 0v10.7156h-3.0724v-10.7156zm-7.2345 0c.7083 0 2.7115.4892 2.8112 2.6459l.0039.1692v7.9005h-2.8605v-1.8919h-2.7697v1.8919h-2.9514v-7.9005c0-.8828.6724-2.7099 2.6431-2.8107l.1721-.0044zm-16.17-.0018 5.7457.0004c.1201.0131 3.183.3818 3.183 3.7124 0 3.3305-2.5283 3.6125-2.6275 3.6223l-.003.0002 3.352 3.3821h-4.2689l-2.4953-2.5854v2.5854h-2.886zm15.0125-1.8062.0224.0221s-.2573.1816-.5298.4086c-8.5967-6.3567-13.8485-3.3599-15.4983-2.5578-7.4918 4.1805-5.3268 14.4428-5.2827 14.6476l.0006.0031h-11.95666s.45404-4.4799 3.63236-9.7772c3.1784-5.2973 8.5968-9.3081 13.0011-9.7016 8.4921-.8507 16.1457 6.4998 16.611 6.9552zm-20.8337 9.4966 1.6346.5903c.0756.5928.1828 1.154.2953 1.6662l.0679.3013-1.8162-.6508c-.0757-.454-.1514-1.1048-.1816-1.907zm21.0982-5.1308h-1.014c-.7554 0-.8927.3952-.9177.5389l-.0049.0377-.0006.0102-.0001 2.6219h2.7697l-.0002-2.6227c-.0033-.0532-.0558-.586-.8322-.586zm-33.81167.2271 1.74054.6356c-.21189.49-.48172 1.1191-.67767 1.6134l-.07909.2028-1.74052-.6356c.15135-.4087.46917-1.1654.75674-1.8162zm23.73557-.0961h-2.3149v2.4501h2.2999s.6614-.2555.6614-1.2325c0-.9771-.6464-1.2176-.6464-1.2176zm-10.341-.5093 1.0897.8627c-.1211.4722-.2131.9444-.2761 1.4166l-.0418.3542-1.2259-.9687c.1211-.5448.2573-1.1048.4541-1.6648zm2.6789-4.2227.681 1.0292c-.2664.2785-.5134.5569-.7332.8509l-.1597.2237-.7265-1.0898c.2724-.3481.5902-.6962.9384-1.014zm-10.8367-2.24 1.0745.9384c-.2724.2838-.5363.5846-.7853.8896l-.2438.306-1.1654-.9989c.3481-.3783.7264-.7567 1.12-1.1351zm14.9988-.0605.333.9989c-.3512.1089-.7023.247-1.0534.4063l-.2634.1234-.3481-1.0443c.3784-.1665.8173-.333 1.3319-.4843zm3.5416-.3633c.3874.0242.7846.0678 1.1914.1385l.307.0583-.0606.9383c-.3996-.0847-.7991-.1404-1.1987-.167l-.2996-.0146zm-12.4259-4.1773.6811 1.0444c-.2951.1475-.5818.3121-.8726.4874l-.2928.1785-.6962-1.0594c.4086-.2422.8021-.4541 1.1805-.6509zm12.4562-.5751c.9005.2573 1.288.4336 1.4431.5162l.025.0135-.0606 1.0141c-.3229-.1312-.6457-.2556-.9731-.3733l-.495-.1716zm-5.7816-.8929.3027.9232h-.1514c-.3292 0-.6584.0085-.9875.0319l-.3292.0286-.2876-.8929c.4995-.0606.9838-.0908 1.453-.0908z" fill="#fff"/></g></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 B

After

Width:  |  Height:  |  Size: 245 B

@ -64,6 +64,11 @@
document.addEventListener("scroll", toggleBackToTop); document.addEventListener("scroll", toggleBackToTop);
var guidesVersion = document.querySelector("select.guides-version");
guidesVersion.addEventListener("change", function(e) {
Turbo.visit(e.target.value);
});
var guidesIndexItem = document.querySelector("select.guides-index-item"); var guidesIndexItem = document.querySelector("select.guides-index-item");
var currentGuidePath = window.location.pathname; var currentGuidePath = window.location.pathname;
guidesIndexItem.value = currentGuidePath.substring(currentGuidePath.lastIndexOf("/") + 1) || 'index.html'; guidesIndexItem.value = currentGuidePath.substring(currentGuidePath.lastIndexOf("/") + 1) || 'index.html';

@ -1,152 +0,0 @@
@media (prefers-color-scheme: dark) {
:root {
--text-color: #ddd;
--text-red: #fc4343;
--note-color: #fff9d8;
}
body {
background-color: #222;
}
p code, ul code {
background-color: #444;
color: var(--text-color);
}
pre, code {
color: #ddd;
}
table {
background: #222;
}
tbody, thead {
border: 2px solid #666;
}
table th {
background-color: #333;
border-bottom: 2px solid #666;
}
table th, table td {
border: 1px solid #666;
}
#container {
color: var(--text-color);
}
#feature {
color: #eee;
background: unset;
background-color: #243440;
border: 1px solid #d5e9f6;
border-right: 0;
border-left: 0;
}
#feature ul li {
background-size: 1.4em 1.4em;
background-image: url(../images/check_icon.svg);
background-position: left 0.5em;
}
#mainCol a.anchorlink, #mainCol a.anchorlink code {
color: #eee;
}
#mainCol a code, #subCol a code, #feature a code {
color: var(--text-red);
}
#mainCol a, #subCol a, #feature a {
color: #ee3f3f;
}
#subCol {
background: #222;
border: 1px solid #111;
}
#subCol .chapters {
color: var(--text-red);
}
#subCol .chapters ul li {
background-image: url(../images/bullet_dark.gif);
}
#subCol h3.chapter {
padding-left:30px;
background-image: url(../images/book_icon.svg);
background-size: 1.25em;
background-repeat: no-repeat;
}
#subCol h3.chapter img {
display: none;
}
#mainCol div.warning, #subCol dd.warning {
border: 1px solid #f9d9d8;
background-color: #482928;
background-image: url(../images/hand_icon.svg);
background-size: 28px 28px;
background-position: 10px 12px;
color: #f9d9d8;
}
#footer {
background-color: #000;
}
.note code, .info code, .todo code {
background-color: #555;
}
.note {
color: var(--note-color);
border: 1px solid var(--note-color);
background-color: #3e3b2c;
background-image: url(../images/note_icon.svg);
background-size: 28px 28px;
background-position: 10px 10px;
}
#mainCol dd.work-in-progress, #subCol dd.work-in-progress {
color: var(--note-color);
border: 1px solid var(--note-color);
background-color: #3e3b2c;
background-image: url(../images/note_icon.svg);
background-size: 28px 28px;
background-position: 10px 10px;
}
.info, #mainCol dd.kindle, #subCol dd.kindle {
border: 1px solid #d5e9f6;
background-color: #243440;
color: #d5e9f6;
background-image: url(../images/info_icon.svg);
background-size: 28px 28px;
background-position: 10px 10px;
}
.clipboard-button {
color: #ddd;
background-color: #222;
}
div.code_container {
/*background: none;*/
background-color: #000;
background-image: url(../images/cog_icon.svg);
background-size: 28px 28px;
background-position: 10px 14px;
border: 1px solid #333;
}
}

@ -1,276 +0,0 @@
.highlight table td { padding: 5px; }
.highlight table pre { margin: 0; }
.highlight .cm {
color: #6c6c65;
font-style: italic;
}
.highlight .cp {
color: #6c6c6c;
font-weight: bold;
}
.highlight .c1 {
color: #6c6c65;
font-style: italic;
}
.highlight .cs {
color: #6c6c6c;
font-weight: bold;
font-style: italic;
}
.highlight .c, .highlight .ch, .highlight .cd, .highlight .cpf {
color: #6c6c65;
font-style: italic;
}
.highlight .err {
color: #a61717;
background-color: #e3d2d2;
}
.highlight .gd {
color: #000000;
background-color: #ffdddd;
}
.highlight .ge {
color: #000000;
font-style: italic;
}
.highlight .gr {
color: #aa0000;
}
.highlight .gh {
color: #6c6c6c;
}
.highlight .gi {
color: #000000;
background-color: #ddffdd;
}
.highlight .go {
color: #6c6c6c;
}
.highlight .gp {
color: #555555;
}
.highlight .gs {
font-weight: bold;
}
.highlight .gu {
color: #6c6c6c;
}
.highlight .gt {
color: #aa0000;
}
.highlight .kc {
color: #000000;
font-weight: bold;
}
.highlight .kd {
color: #000000;
font-weight: bold;
}
.highlight .kn {
color: #000000;
font-weight: bold;
}
.highlight .kp {
color: #000000;
font-weight: bold;
}
.highlight .kr {
color: #000000;
font-weight: bold;
}
.highlight .kt {
color: #445588;
font-weight: bold;
}
.highlight .k, .highlight .kv {
color: #0073a6;
}
.highlight .mf {
color: #007979;
}
.highlight .mh {
color: #007979;
}
.highlight .il {
color: #007979;
}
.highlight .mi {
color: #007979;
}
.highlight .mo {
color: #007979;
}
.highlight .m, .highlight .mb, .highlight .mx {
color: #007979;
}
.highlight .sb {
color: #d51144;
}
.highlight .sc {
color: #d51144;
}
.highlight .sd {
color: #d51144;
}
.highlight .s2 {
color: #d51144;
}
.highlight .se {
color: #d51144;
}
.highlight .sh {
color: #d51144;
}
.highlight .si {
color: #d51144;
}
.highlight .sx {
color: #d51144;
}
.highlight .sr {
color: #007e26;
}
.highlight .s1 {
color: #d51144;
}
.highlight .ss {
color: #990073;
}
.highlight .s, .highlight .sa, .highlight .dl {
color: #d51144;
}
.highlight .na {
color: #007979;
}
.highlight .bp {
color: #6c6c6c;
}
.highlight .nb {
color: #0074a1;
}
.highlight .nc {
color: #445588;
font-weight: bold;
}
.highlight .no {
color: #007979;
}
.highlight .nd {
color: #3c5d5d;
font-weight: bold;
}
.highlight .ni {
color: #800080;
}
.highlight .ne {
color: #990000;
font-weight: bold;
}
.highlight .nf, .highlight .fm {
color: #990000;
font-weight: bold;
}
.highlight .nl {
color: #990000;
font-weight: bold;
}
.highlight .nn {
color: #555555;
}
.highlight .nt {
color: #000080;
}
.highlight .vc {
color: #007979;
}
.highlight .vg {
color: #007979;
}
.highlight .vi {
color: #005cc5;
}
.highlight .nv, .highlight .vm {
color: #007979;
}
.highlight .ow {
color: #000000;
font-weight: bold;
}
.highlight .o {
color: #000000;
font-weight: bold;
}
.highlight .w {
color: #6c6c6c;
}
.highlight {
background-color: transparent;
}
@media (prefers-color-scheme: dark) {
.highlight pre { background-color: #272822; }
.highlight .hll { background-color: #272822; }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
.highlight .gh { } /* Generic Heading & Diff Header */
.highlight .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */
.highlight .gd { color: #f92672; background-color: unset; } /* Generic.Deleted & Diff Deleted */
.highlight .gi { color: #a6e22e; background-color: unset; } /* Generic.Inserted & Diff Inserted */
}

@ -1,849 +0,0 @@
/* Guides.rubyonrails.org */
/* Main.css */
/* Created January 30, 2009 */
/* Modified February 8, 2009
--------------------------------------- */
/* General
--------------------------------------- */
.left {float: left; margin-right: 1em;}
.right {float: right; margin-left: 1em;}
@media screen and (max-width: 480px) {
.left, .right { float: none; }
}
.small {font-size: smaller;}
.large {font-size: larger;}
.hide {display: none;}
ul, ol { margin: 0 1.5em 1.5em 1.5em; }
ul { list-style-type: disc; }
ol { list-style-type: decimal; }
dl { margin: 0 0 1.5em 0; }
dl dt { font-weight: bold; }
:where(body[dir="ltr"]) dd { margin-left: 1.5em; }
:where(body[dir="rtl"]) dd { margin-right: 1.5em; }
pre, code {
font-size: 1em;
font-family: "Anonymous Pro", "Inconsolata", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace;
line-height: 1.5;
margin: 1em 0;
overflow: auto;
color: #222;
}
p code, ul code {
background: #eee;
border-radius: 2px;
padding: 1px 3px;
}
pre, tt, code {
white-space: pre-wrap; /* css-3 */
white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
abbr, acronym { border-bottom: 1px dotted #666; }
address { margin: 0 0 1.5em; font-style: italic; }
del { color:#666; }
blockquote { margin: 1.5em; color: #666; font-style: italic; }
strong { font-weight: bold; }
em, dfn { font-style: italic; }
dfn { font-weight: bold; }
sup, sub { line-height: 0; }
p {margin: 0 0 1.5em;}
label { font-weight: bold; }
fieldset { padding:1.4em; margin: 0 0 1.5em 0; border: 1px solid #ccc; }
legend { font-weight: bold; font-size:1.2em; }
input.text, input.title,
textarea, select {
margin:0.5em 0;
border:1px solid #bbb;
}
table {
margin: 0 0 1.5em;
background: #FFF;
border-collapse: collapse;
}
tbody, thead {
border: 2px solid #CCC;
}
table th, table td {
padding: 9px 10px;
border: 1px solid #CCC;
border-collapse: collapse;
}
table th {
border-bottom: 2px solid #CCC;
background: #EEE;
font-weight: bold;
}
@media only screen and (max-width: 480px) {
table {
display: block;
overflow-x: auto;
}
td {
min-width: 7em;
}
}
img {
max-width: 100%;
}
/* Structure and Layout
--------------------------------------- */
body {
text-align: center;
font-family: Helvetica, Arial, sans-serif;
font-size: 87.5%;
line-height: 1.5;
background: #fff;
color: #999;
}
.wrapper {
margin: 0 auto;
max-width: 960px;
padding: 0 1em;
}
:where(body[dir="ltr"]) .wrapper { text-align: left; }
:where(body[dir="rtl"]) .wrapper { text-align: right; }
.red-button {
display: inline-block;
border-top: 1px solid rgba(255,255,255,.5);
background: #751913;
background: -webkit-gradient(linear, left top, left bottom, from(#c52f24), to(#751913));
background: -webkit-linear-gradient(top, #c52f24, #751913);
background: -moz-linear-gradient(top, #c52f24, #751913);
background: -ms-linear-gradient(top, #c52f24, #751913);
background: -o-linear-gradient(top, #c52f24, #751913);
padding: 9px 18px;
-webkit-border-radius: 11px;
-moz-border-radius: 11px;
border-radius: 11px;
-webkit-box-shadow: rgba(0,0,0,1) 0 1px 0;
-moz-box-shadow: rgba(0,0,0,1) 0 1px 0;
box-shadow: rgba(0,0,0,1) 0 1px 0;
text-shadow: rgba(0,0,0,.4) 0 1px 0;
color: white;
font-size: 15px;
font-family: Helvetica, Arial, Sans-Serif;
text-decoration: none;
vertical-align: middle;
cursor: pointer;
}
.red-button:active {
border-top: none;
padding-top: 10px;
background: -webkit-gradient(linear, left top, left bottom, from(#751913), to(#c52f24));
background: -webkit-linear-gradient(top, #751913, #c52f24);
background: -moz-linear-gradient(top, #751913, #c52f24);
background: -ms-linear-gradient(top, #751913, #c52f24);
background: -o-linear-gradient(top, #751913, #c52f24);
}
#topNav {
padding: 1em 0;
color: #565656;
background: #222;
}
.s-hidden {
display: none;
}
@media screen and (min-width: 1025px) {
.more-info-button {
display: none;
}
.more-info-links {
list-style: none;
display: inline;
margin: 0;
}
.more-info {
display: inline-block;
}
.more-info:after {
content: " |";
color: #8a8a8a;
}
.more-info:last-child:after {
content: "";
}
#topNav a, #footer a {
color: #F1938C;
}
}
@media screen and (max-width: 1024px) {
#topNav .wrapper { text-align: center; }
.more-info-button {
position: relative;
z-index: 25;
}
.more-info-label {
display: none;
}
.more-info-container {
position: absolute;
top: .5em;
z-index: 20;
margin: 0 auto;
left: 0;
right: 0;
width: 20em;
}
.more-info-links {
display: block;
list-style: none;
background-color: #c52f24;
border-radius: 5px;
padding-top: 5.25em;
border: 1px #980905 solid;
}
.more-info-links.s-hidden {
display: none;
}
.more-info {
padding: .75em;
border-top: 1px #980905 solid;
}
.more-info a, .more-info a:link, .more-info a:visited {
display: block;
color: white;
width: 100%;
height: 100%;
text-decoration: none;
text-transform: uppercase;
}
}
.clipboard-button {
background: #dbdbdb;
border: 0;
border-radius: 5px;
padding: 2px 10px;
position: absolute;
bottom: 2px;
right: 2px;
cursor: pointer;
}
.clipboard-button:hover {
color: #005cc5;
}
.clipboard-button:active {
background: #ccc;
}
a.back-to-top {
visibility: hidden;
position: fixed;
right: 1em;
bottom: 1em;
padding: 2.5em;
border-radius: 3em;
box-shadow: 2px 2px 4px 0px black;
background: url('../images/up_white_arrow.png') no-repeat center center, #c52f24;
background-size: 2em;
}
a.back-to-top.show {
visibility: visible;
}
#header {
background: #c52f24 url(../images/header_tile.gif) repeat-x;
color: #FFF;
padding: 1.5em 0;
z-index: 99;
}
#feature {
background: #d5e9f6 url(../images/feature_tile.gif) repeat-x;
color: #333;
padding: 0.5em 0 1.5em;
}
#container {
color: #333;
padding: 0.5em 0 1.5em 0;
}
#mainCol {
max-width: 630px;
}
#subCol {
position: absolute;
z-index: 0;
top: 21px;
background: #FFF;
padding: 1em 1.5em 1em 1.25em;
width: 20em;
font-size: 0.9285em;
line-height: 1.3846;
}
:where(body[dir="ltr"]) #subCol { right: 0; margin-right: 1em; }
:where(body[dir="rtl"]) #subCol { left: 0; margin-left: 1em; }
@media screen and (max-width: 800px) {
#subCol {
position: static;
width: inherit;
margin-left: -1em;
margin-right: -1em;
}
:where(body[dir="ltr"]) #subCol { padding-right: 1.25em; }
:where(body[dir="rtl"]) #subCol { padding-left: 1.25em; }
}
#footer {
padding: 2em 0;
background: #222 url(../images/footer_tile.gif) repeat-x;
}
#footer .wrapper {
max-width: 960px;
}
:where(body[dir="ltr"]) #footer .wrapper { padding-left: 1em; }
:where(body[dir="rtl"]) #footer .wrapper { padding-right: 1em; }
#footer p:last-child {
margin-bottom: 0;
}
#header .wrapper, #topNav .wrapper { max-width: 960px; }
:where(body[dir="ltr"]) :is(#header .wrapper, #topNav .wrapper) { padding-left: 1em; }
:where(body[dir="rtl"]) :is(#header .wrapper, #topNav .wrapper) { padding-right: 1em; }
#feature .wrapper { max-width: 720px; position: relative; z-index: 0; }
:where(body[dir="ltr"]) #feature .wrapper { padding-left: 1em; padding-right: 23em; }
:where(body[dir="rtl"]) #feature .wrapper { padding-left: 23em; padding-right: 1em; }
@media screen and (max-width: 960px) {
:where(body[dir="ltr"]) #container .wrapper { padding-right: 23em; }
:where(body[dir="rtl"]) #container .wrapper { padding-left: 23em; }
}
@media screen and (max-width: 800px) {
:where(body[dir="ltr"]) :is(#feature .wrapper, #container .wrapper) { padding-right: 1em; }
:where(body[dir="rtl"]) :is(#feature .wrapper, #container .wrapper) { padding-left: 1em; }
}
/* Links
--------------------------------------- */
a, a:link, a:visited {
color: #ee3f3f;
text-decoration: underline;
}
#mainCol a, #subCol a, #feature a {color: #980905;}
#mainCol a code, #subCol a code, #feature a code {color: #980905;}
#mainCol a.anchorlink, #mainCol a.anchorlink code {color: #333;}
#mainCol a.anchorlink { text-decoration: none; }
#mainCol a.anchorlink:hover { text-decoration: underline; }
/* Navigation
--------------------------------------- */
.nav {
margin: 0;
padding: 0;
list-style: none;
margin-top: 1.5em;
font-size: 1.2857em;
}
:where(body[dir="ltr"]) .nav { float: right; }
:where(body[dir="rtl"]) .nav { float: left; }
.nav .nav-item {color: #FFF; text-decoration: none;}
.nav .nav-item:hover {text-decoration: underline;}
.guides-index-large, .guides-index-small .guides-index-item {
padding: 0.5em 1.5em;
border-radius: 1em;
-webkit-border-radius: 1em;
-moz-border-radius: 1em;
background: #980905;
position: relative;
color: white;
}
.guides-index .guides-index-item {
background: #980905 url(../images/nav_arrow.gif) no-repeat;
position: relative;
z-index: 15;
padding-bottom: 0.125em;
}
:where(body[dir="ltr"]) .guides-index .guides-index-item { background-position: right top; padding-right: 1em; }
:where(body[dir="rtl"]) .guides-index .guides-index-item { background-position: left top; padding-left: 1em; }
.guides-index:hover .guides-index-item {
text-decoration: underline !important;
}
:where(body[dir="ltr"]) .guides-index:hover .guides-index-item { background-position: right -81px; }
:where(body[dir="rtl"]) .guides-index:hover .guides-index-item { background-position: left -81px; }
@media screen and (min-width: 481px) {
.nav {
margin-top: 1.5em;
font-size: 1.2857em;
}
:where(body[dir="ltr"]) .nav { float: right; }
:where(body[dir="rtl"]) .nav { float: left; }
.nav>li {
display: inline;
}
:where(body[dir="ltr"]) .nav>li { margin-left: 0.5em; }
:where(body[dir="rtl"]) .nav>li { margin-right: 0.5em; }
.guides-index.guides-index-small {
display: none;
}
}
@media screen and (max-width: 480px) {
.nav {
float: none;
width: 100%;
text-align: center;
}
.nav .nav-item {
display: block;
margin: 0;
width: 100%;
background-color: #980905;
border: solid 1px #620c04;
border-top: 0;
padding: 15px 0;
text-align: center;
}
.nav .nav-item, .nav-item.guides-index-item {
text-transform: uppercase;
}
.nav .nav-item:first-child, .nav-item.guides-index-small {
border-top: solid 1px #620c04;
}
.guides-index.guides-index-small {
display: block;
margin-top: 1.5em;
}
.guides-index.guides-index-large {
display: none;
}
.guides-index-small .guides-index-item {
font: inherit;
font-size: .95em;
background-position: 96% 16px;
-webkit-appearance: none;
}
:where(body[dir="ltr"]) .guides-index-small .guides-index-item { padding-left: .75em; }
:where(body[dir="rtl"]) .guides-index-small .guides-index-item { padding-right: .75em; }
.guides-index-small .guides-index-item:hover{
background-position: 96% -65px;
}
}
#guides {
width: 37em;
display: block;
background: #980905;
border-radius: 1em;
color: #f1938c;
padding: 1.5em 2em;
position: absolute;
z-index: 10;
top: -0.25em;
padding-top: 2em;
}
:where(body[dir="ltr"]) #guides { right: 0; }
:where(body[dir="rtl"]) #guides { left: 0; }
#guides.visible {
display: block !important;
}
.guides-section dt, .guides-section dd {
font-weight: normal;
font-size: 0.722em;
margin: 0;
padding: 0;
}
.guides-section dt {
margin: 0.5em 0 0;
padding:0;
}
#guides a {
background: none !important;
color: #FFF;
text-decoration: none;
}
#guides a:hover {
text-decoration: underline;
}
.guides-section-container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
width: 100%;
max-height: 35em;
}
.guides-section {
min-width: 5em;
margin: 0 2em 0.5em 0;
flex: auto;
max-width: 12em;
}
.guides-section dd {
line-height: 1.3;
margin-bottom: 0.5em;
}
#guides hr {
display: block;
border: none;
height: 1px;
color: #f1938c;
background: #f1938c;
}
/* Headings
--------------------------------------- */
h1 {
font-size: 2.1428em;
line-height: 1;
margin: 0.7em 0 .2333em;
font-weight: bold;
}
@media screen and (max-width: 480px) {
h1 {
font-size: 1.45em;
}
}
h2 {
font-size: 1.7142em;
line-height: 1.286;
margin: 0.875em 0 0.2916em;
font-weight: bold;
}
@media screen and (max-width: 480px) {
h2 {
font-size: 1.45em;
}
}
h3 {
font-size: 1.2857em;
line-height: 1.2;
margin: 1.6667em 0 .3887em;
font-weight: bold;
}
h4 {
font-size: 1em;
line-height: 1.5;
margin: 1em 0 .5em;
font-weight: bold;
}
h5 {
font-size: 1em;
line-height: 1.5;
margin: 1em 0 .5em;
font-weight: normal;
}
.section {
padding-bottom: 0.25em;
border-bottom: 1px solid #999;
}
/* Content
--------------------------------------- */
.pic {
margin: 0 2em 2em 0;
}
#topNav strong { color: #999; }
:where(body[dir="ltr"]) #topNav strong { margin-right: 0.5em; }
:where(body[dir="rtl"]) #topNav strong { margin-left: 0.5em; }
#topNav strong a {color: #FFF;}
#header .header-logo {
background: url(../images/rails_guides_logo_1x.png) no-repeat;
width: 297px;
text-indent: -9999em;
margin: 0;
padding: 0;
}
:where(body[dir="ltr"]) #header .header-logo { float: left; }
:where(body[dir="rtl"]) #header .header-logo { float: right; }
@media
only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and ( min--moz-device-pixel-ratio: 2),
only screen and ( -o-min-device-pixel-ratio: 2/1),
only screen and ( min-device-pixel-ratio: 2),
only screen and ( min-resolution: 192dpi),
only screen and ( min-resolution: 2dppx) {
#header .header-logo {
background: url(../images/rails_guides_logo_2x.png) no-repeat;
background-size: 160%;
}
}
@media screen and (max-width: 480px) {
#header .header-logo {
float: none;
}
}
#header .header-logo a {
text-decoration: none;
display: block;
height: 77px;
}
#feature p {
font-size: 1.2857em;
margin-bottom: 0.75em;
}
@media screen and (max-width: 480px) {
#feature p {
font-size: 1em;
}
}
:where(body[dir="ltr"]) #feature ul { margin-left: 0; }
:where(body[dir="rtl"]) #feature ul { margin-right: 0; }
#feature ul li {
list-style: none;
background: url(../images/check_bullet.gif) no-repeat;
padding: 0.5em 1.75em 0.5em 1.75em;
font-size: 1.1428em;
font-weight: bold;
}
:where(body[dir="ltr"]) #feature ul li { background-position: left 0.5em }
:where(body[dir="rtl"]) #feature ul li { background-position: right 0.5em }
#mainCol dd, #subCol dd {
padding: 0.25em 0 1em;
border-bottom: 1px solid #CCC;
margin-bottom: 1em;
}
:where(body[dir="ltr"]) :is(#mainCol dd, #subCol dd) { margin-left: 0; padding-left: 0; }
:where(body[dir="rtl"]) :is(#mainCol dd, #subCol dd) { margin-right: 0; padding-right: 0; }
#mainCol dt, #subCol dt {
font-size: 1.2857em;
padding: 0.125em 0 0.25em 0;
margin-bottom: 0;
}
@media screen and (max-width: 480px) {
#mainCol dt, #subCol dt {
font-size: 1em;
}
}
#mainCol dd.work-in-progress, #subCol dd.work-in-progress {
background: #fff9d8 url(../images/tab_yellow.gif) no-repeat left top;
border: none;
padding: 1.25em 1em 1.25em 48px;
margin-top: 0.25em;
}
:where(body[dir="ltr"]) :is(#mainCol dd.work-in-progress, #subCol dd.work-in-progress) { margin-left: 0; }
:where(body[dir="rtl"]) :is(#mainCol dd.work-in-progress, #subCol dd.work-in-progress) { margin-right: 0; }
#mainCol dd.kindle, #subCol dd.kindle {
background: #d5e9f6 url(../images/tab_info.gif) no-repeat left top;
border: none;
padding: 1.25em 1em 1.25em 48px;
margin-top: 0.25em;
}
:where(body[dir="ltr"]) :is(#mainCol dd.kindle, #subCol dd.kindle) { margin-left: 0; }
:where(body[dir="rtl"]) :is(#mainCol dd.kindle, #subCol dd.kindle) { margin-right: 0; }
#mainCol div.warning, #subCol dd.warning {
background: #f9d9d8 url(../images/tab_red.gif) no-repeat left top;
border: none;
padding: 1.25em 1.25em 0.25em 48px;
margin-top: 0.25em;
}
:where(body[dir="ltr"]) :is(#mainCol div.warning, #subCol dd.warning) { margin-left: 0; }
:where(body[dir="rtl"]) :is(#mainCol div.warning, #subCol dd.warning) { margin-right: 0; }
#subCol .chapters {color: #980905;}
#subCol .chapters a {font-weight: bold;}
#subCol .chapters ul a {font-weight: normal;}
#subCol .chapters li {margin-bottom: 0.75em;}
#subCol h3.chapter {margin-top: 0.25em;}
#subCol h3.chapter img {vertical-align: text-bottom;}
#subCol .chapters ul { margin-top: 0.5em; }
:where(body[dir="ltr"]) #subCol .chapters ul { margin-left: 0; }
:where(body[dir="rtl"]) #subCol .chapters ul { margin-right: 0; }
#subCol .chapters ul li {
list-style: none;
padding: 0;
background: url(../images/bullet.gif) no-repeat;
font-size: 1em;
font-weight: normal;
}
:where(body[dir="ltr"]) #subCol .chapters ul li { background-position: left 0.45em; padding-left: 1em; margin-left: 0; }
:where(body[dir="rtl"]) #subCol .chapters ul li { background-position: right 0.45em; padding-right: 1em; margin-right: 0; }
#subCol li ul, li ol { margin:0 1.5em; }
div.code_container {
background: #EEE url(../images/tab_grey.gif) no-repeat;
padding-top: 0.25em;
padding-bottom: 0.5em;
position: relative;
}
:where(body[dir="ltr"]) div.code_container { background-position: left top; padding-right: 1em; padding-left: 48px; }
:where(body[dir="rtl"]) div.code_container { background-position: right top; padding-right: 48px; padding-left: 1em; }
.note {
background: #fff9d8 url(../images/tab_note.gif) no-repeat;
border: none;
padding-top: 1em;
padding-bottom: 0.25em;
margin: 0.25em 0 1.5em 0;
}
:where(body[dir="ltr"]) .note { background-position: left top; padding-right: 1em; padding-left: 48px; }
:where(body[dir="rtl"]) .note { background-position: right top; padding-right: 48px; padding-left: 1em; }
.info {
background: #d5e9f6 url(../images/tab_info.gif) no-repeat;
border: none;
padding-top: 1em;
padding-bottom: 0.25em;
margin: 0.25em 0 1.5em 0;
}
:where(body[dir="ltr"]) .info { background-position: left top; padding-right: 1em; padding-left: 48px; }
:where(body[dir="rtl"]) .info { background-position: right top; padding-right: 48px; padding-left: 1em; }
#mainCol div.todo {
background: #fff9d8 url(../images/tab_yellow.gif) no-repeat;
border: none;
padding-top: 1em;
padding-bottom: 0.25em;
margin: 0.25em 0 1.5em 0;
}
:where(body[dir="ltr"]) #mainCol div.todo { background-position: left top; padding-right: 1em; padding-left: 48px; }
:where(body[dir="rtl"]) #mainCol div.todo { background-position: right top; padding-right: 48px; padding-left: 1em; }
.note code, .info code, .todo code {
background: #fff;
}
#mainCol ul li {
list-style:none;
background: url(../images/grey_bullet.gif) no-repeat;
}
:where(body[dir="ltr"]) #mainCol ul li { background-position: left 0.5em; padding-left: 1em; margin-left: 0; }
:where(body[dir="rtl"]) #mainCol ul li { background-position: right 0.5em; padding-right: 1em; margin-right: 0; }
#subCol .content {
font-size: 0.7857em;
line-height: 1.5;
}
#subCol .content li {
font-weight: normal;
background: none;
padding: 0 0 1em;
font-size: 1.1667em;
}
/* Clearing
--------------------------------------- */
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
* html .clearfix {height: 1%;}
.clearfix {display: block;}
/* Same bottom margin for special boxes than for regular paragraphs, this way
intermediate whitespace looks uniform. */
div.code_container, div.important, div.caution, div.warning, div.note, div.info {
margin-bottom: 1.5em;
}
/* Remove bottom margin of paragraphs in special boxes, otherwise they get a
spurious blank area below with the box background. */
div.important p, div.caution p, div.warning p, div.note p, div.info p {
margin-bottom: 1em;
}
/* When triple-clicking console code, select only the command, not the prompt */
code.highlight.console span.w, code.highlight.irb span.w {
display: table-cell;
}
/* Version Badge
--------------------------------------- */
#version-badge {
position: fixed;
right: 0;
top: 0;
z-index: 100;
color: white;
font-size: 30px;
transform: rotate(45deg) translate(27.5%, -40%);
min-width: 200px;
font-weight: bold;
font-style: italic;
box-shadow: 0px 2px 2px 1px #1209096e;
text-shadow: 2px 2px 4px #5400007d;
background: radial-gradient(circle, rgb(255, 10, 0) 0%, rgb(200, 0, 0) 90%);
}

@ -1,36 +0,0 @@
/* Guides.rubyonrails.org */
/* Reset.css */
/* Created January 30, 2009
--------------------------------------- */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
background: transparent;
}
body {line-height: 1; color: black; background: white;}
a img {border:none;}
ins {text-decoration: none;}
del {text-decoration: line-through;}
/* tables still need 'cellspacing="0"' in the markup */
table {border-collapse: collapse; border-spacing: 0;}
caption, th, td {text-align: left; font-weight: normal;}
blockquote, q {quotes: none;}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}

@ -1,14 +0,0 @@
/* Guides.rubyonrails.org */
/* Style.css */
/* Created January 30, 2009
--------------------------------------- */
/*
---------------------------------------
Import advanced style sheet
---------------------------------------
*/
@import url("reset.css");
@import url("main.css");
@import url("dark.css");

@ -0,0 +1,159 @@
// ----------------------------------------------------------------------------
// Dark Mode Styles for Rails Guided 2024 Redesign
// ----------------------------------------------------------------------------
//
// @include-media does not handle prefers-color-scheme so we are declaring this
// as an independent file with the overrides for dark mode.
@media (prefers-color-scheme: dark) {
body.guide {
background-color: $gray-900;
color: #fff;
a {
&:link {
color: $rf-brand-light;
}
&:hover,
&:active {
color: $rf-brand-darker;
} // &:hover, &:active
&:visited {
color: $rf-brand;
} // &:visited
} // a
table {
th {
color: $gray-900;
background-color: $gray-200;
} // th
tr {
&:nth-child(even) {
background-color: $gray-800;
}
}
} // table
h3 {
a,
a:link,
a:visited {
color: $gray-100;
} // a, a:link, a:visited
} // h3
pre, code {
background-color: $gray-200;
color: $gray-200;
} // pre, code
p code, ul code, li code, h2 code, h3 code, h4 code, h5 code, td code {
background-color: $gray-600;
}
nav#topNav {
background-color: $gray-200;
color: $gray-600;
.more-info-links {
background: $gray-900;
} // .more-info-links
li {
border-bottom: 1px solid $gray-700;
} // li
} // nav#topNav
header#page_header {
nav#feature_nav {
.header-logo {
span#version_switcher {
color: $gray-400;
select {
background-color: $gray-800;
color: $gray-400;
} // select
} // span#version_switcher
} // .header-logo
ul.nav {
li {
background: $gray-900;
border-bottom: 1px solid $gray-900;
@include media('>desktop'){
a,
a:link,
a:visited {
color: $gray-100;
} // a
a#home_nav {
background-image: url("../images/icon_house-chimney-wht.svg");
}
} // @include media('>desktop')
} // li
} // ul.nav
} // nav#feature_nav
} // header#page_header
#guides {
background: $gray-700;
color: $gray-100;
.guides-section {
dd {
a,
a:link,
a:visited {
color: $gray-100;
} // a
a:hover,
a:active {
color: $rf-brand-light;
} // a:hover
} // dd
} // .guides-section
} // #guides
footer#page_footer {
background-color: $gray-200;
color: $gray-900;
} // footer#page_footer
#feature {
background-color: $gray-800;
@include media('>desktop') {
background-color: $gray-900;
}
#subCol {
background-color: $gray-700;
ol {
li {
a,
a:link,
a:visited {
color: $gray-100;
}
a:hover,
a:active {
color: $rf-brand-light;
} // a
} // li
} // ol
} // #subCol
} // #feature
.interstitial.code {
background-color: $gray-200;
}
} // body.guide
} // @media (prefers-color-scheme: dark

@ -0,0 +1,714 @@
body.guide {
-webkit-tap-highlight-color:rgba(38, 27, 35, 0);
// ----------------------------------------------------------------------------
// Typographic Baseline
// ----------------------------------------------------------------------------
:root {
font-family: Inter, sans-serif;
font-feature-settings: 'liga' 1, 'calt' 1; /* fix for Chrome */
}
@supports (font-variation-settings: normal) {
:root { font-family: InterVariable, sans-serif; }
}
font-family: Inter, sans-serif;
font-size: 1.125rem; /* 18px */
font-style: normal;
font-weight: 400;
font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
line-height: 1.4;
font-feature-settings: "liga" 1;
@supports (font-variant-ligatures: common-ligatures) {
font-feature-settings: normal;
font-variant-ligatures: common-ligatures;
}
font-feature-settings: "onum" 1;
@supports (font-variant-numeric: oldstyle-nums) {
font-feature-settings: normal;
font-variant-numeric: oldstyle-nums;
}
p {
// Set hyphenation rules
hyphenate-limit-lines: 2; /* Safari */
-webkit-hyphenate-limit-before: 3;
-webkit-hyphenate-limit-after: 2;
hyphenate-limit-chars: 6 3 2; /* Not Safari */
hyphenate-limit-last: always;
@include media('>tablet') {
// On larger screens, set a width of 45-75 characters, using em as ch
// has too much variation between various fonts
min-width: 23em;
max-width: 38em;
}
margin: 0 0 0.75em 0; // Space after paragraph
text-align: left;
} // p
// Links
a {
&:link {
color: $rf-brand;
text-decoration: underline;
}
&:hover,
&:active {
color: $rf-brand-light;
}
&:visited {
color: $rf-brand-darker;
}
}
abbr {
hyphens: manual;
}
abbr.smallcaps {
font-feature-settings: "smcp" 1, "c2sc" 1;
@supports (font-variant-caps: all-small-caps) {
font-feature-settings: normal;
font-variant-caps: all-small-caps;
}
}
// Tables
table {
border-collapse: collapse;
font-variant-numeric: lining-nums tabular-nums;
margin: 2em auto;
width: 100%;
caption {
caption-side: bottom;
}
th {
background-color: $gray-700;
color: #fff;
font-size: 0.875em;
padding: 0.5em;
text-align: left;
}
tr {
&:nth-child(even) {
background-color: $gray-100;
}
}
td {
padding: 0.5em;
}
}
// Headlines
// TODO: media queries to increase font size, current sizes are for desktop, so drop base to mobile appropriate and MQ up twice (min width 60/120 em, minheight 30/60em)
// Font family is Calibre, declared globally
h1 {
color: $rf-brand;
font-family: 'Calibre', sans-serif;
font-size: 3rem; /* 48px */
font-weight: 700; /* Light */
line-height: 1em;
margin-top: 0;
@include media('<desktop') { margin-top: 0.5em; }
} // h1
h2 {
font-family: 'Calibre', sans-serif;
font-size: 2.25rem; // Calibre is smaller than inter at the same size
font-weight: 700; /* Bold */
a,
a:link,
a:visited {
color: $rf-brand;
} // a, a:link, a:visited
} // h2
h3 {
font-size: 1.5rem; /* 24px */
font-weight: 600; /* Semibold */
a,
a:link,
a:visited {
color: $gray-900;
} // a, a:link, a:visited
code {
font-size: 1.5rem;
font-weight: 400;
}
} // h3
h4 {
font-size: 1.125rem;
code {
font-size: 1.125rem;
font-weight: 400;
}
}
h5 {
font-size: 0.9375rem;
code {
font-size: 0.9375rem;
font-weight: 400;
}
}
h1, h2, h3, h4, h5 {
a,
a:link {
text-decoration: none;
} // a, a:link
a:hover,
a:active {
text-decoration: underline;
} // a:hover, a:active
span {
font-weight: 400;
}
} // h1, h2, h3, h4
// Old style numbers look weird in headlines and ordered lists, so use proportional lining numbers
h1, h2, h3, h4, h5, h6, ol, ol > li {
font-feature-settings: "kern" 1;
@supports (kerning: normal) {
font-feature-settings: normal;
kerning: normal;
}
font-feature-settings: "lnum" 1;
@supports (font-variant-numeric: lining-nums) {
font-feature-settings: normal;
font-variant-numeric: lining-nums;
}
}
// Horizontal Rule
hr {
height: 1em;
border: 0;
background: url("../images/hr_rails.svg") center no-repeat;
background-size: contain;
margin: 1em auto;
width: 90%;
@include media('>tablet') {
height: 1.5em;
}
@include media('>desktop-ultra-wide') {
height: 2em;
}
&.hide {
height: 0 !important;
}
}
// Definition Lists
dl {
margin: 0;
dt {
font-weight: bold;
font-size: 1.125rem;
padding: 0.125em 0 0.25em 0;
margin-bottom: 0.75em;
@include media('<phone-wide') {
font-size: 1rem;
} // @include media('<phone-wide')
} // dt
dd {
padding: 0.25em 0 1em;
border-bottom: 1px solid $gray-500;
margin: 0 0 1em 0;
} // dd
} // dl
// :where(&[dir="ltr"]) dd { margin-left: 1.5em; }
// :where(&[dir="rtl"]) dd { margin-right: 1.5em; }
// :where(&[dir="ltr"]) :is(dd) { margin-left: 0; padding-left: 0; }
// :where(&[dir="rtl"]) :is(dd) { margin-right: 0; padding-right: 0; }
li {
margin-bottom: 0.5em;
}
// Code
pre, code {
font-size: 1rem;
font-family: "IBM Plex Mono", "Anonymous Pro", "Inconsolata", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace;
line-height: 1.5;
margin: 1em 0;
overflow: auto;
color: #222;
} // pre, code
p code, ul code {
background: $gray-200;
border-radius: calc($base-border-radius / 2);
padding: 1px 3px;
}
p img {
max-width: 100%;
}
pre, tt, code {
// https://caniuse.com/mdn-css_properties_white-space_pre-wrap
white-space: pre-wrap; /* css-3 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
// Back to Top element
a.back-to-top {
background: url('../images/up_white_arrow.png') no-repeat center center, $rf-brand;
background-size: 1em;
border-radius: calc($base-border-radius * 2);
box-shadow: 0 2px 20px rgba(0,0,0,0.25);
padding: 1.5em;
position: fixed;
right: 1em;
bottom: 1em;
visibility: hidden;
}
a.back-to-top.show {
visibility: visible;
}
// ----------------------------------------------------------------------------
// Layout
// ----------------------------------------------------------------------------
.wrapper {
padding: 1em;
:where(body[dir="ltr"]) & { text-align: left; }
:where(body[dir="rtl"]) & { text-align: right; }
@include media('>desktop') {
padding-left: 5vw;
width: 60vw;
}
} // .wrapper
// topNav is a hidden area for mobile only
nav#topNav {
background-color: $gray-800;
color: $gray-400;
padding: 0.5em 0;
font-size: 0.875rem;
@include media('>desktop') {
display: none;
}
.wrapper {
text-align: center;
}
.s-hidden {
display: none;
}
.red-button {
background: $rf-brand;
border-bottom: 2px solid $rf-brand-dark;
border-radius: $base-border-radius;
color: white;
padding: 0.5em 1em;
}
.more-info-label {
@include media('<desktop') {
display: none;
}
}
.more-info-button {
cursor: pointer;
}
.more-info-links {
@extend %list-in-disguise;
background: $gray-200;
border-radius: $base-border-radius;
box-shadow: 0 2px 20px rgba(0,0,0,0.25);
font-size: 1.25em;
position: absolute;
left: 10vw;
width: 80vw;
li {
border-bottom: 1px solid $gray-300;
padding: 0.5em;
&:last-child {
border-bottom: none;
}
a,
a:link,
a:visited {
font-weight: bold;
text-decoration: none;
}
}
}
} // nav#topNav
header#page_header {
nav#feature_nav {
@include media('>desktop'){
align-items: top;
display: flex;
flex-direction: row;
justify-content: space-between;
width: 90vw;
}
// Image augmented
.header-logo {
text-align: center;
a {
background-image: url("../images/logo_rails-circle.svg");
background-repeat: no-repeat;
background-position: top center;
display: inline-block;
font-family: 'Calibre', sans-serif;
font-size: 2.25rem;
font-weight: 700;
margin: 0 auto;
padding-top: 75px;
text-align: center;
text-decoration: none;
font-weight: 700;
@include media('>desktop'){
padding: 10px 0 0 85px;
background-position: top left;
height: 85px;
vertical-align: middle;
}
} // a
span#version_switcher {
color: $gray-600;
display: block;
font-size: 0.75em;
@include media('>desktop') {
display: inline-block;
margin-left: 0.5em;
vertical-align: 1px;
}
select {
color: $gray-600;
}
} // span#version_switcher
} // .header-logo
ul.nav {
@extend %list-in-disguise;
margin: 1em 1em 0 1em;
@include media('>desktop'){
display: flex;
flex-direction: row;
justify-content: space-between;
margin: 0;
padding: 1em 0 0 0;
}
li {
background: $gray-200;
border-bottom: 1px solid $gray-300;
font-size: 1.25em;
text-align: center;
padding: 1em;
@include media('>desktop'){
background: none;
border: none;
font-size: 0.75rem;
height: 24px;
padding-top: 5px;
&:first-child {padding-top: 0;}
a,
a:link,
a:visited {
color: $gray-900;
font-weight: bold;
text-decoration: none;
}
}
&:first-child {
border-top-left-radius: $base-border-radius;
border-top-right-radius: $base-border-radius;
}
&:nth-last-child(2) {
border-bottom: none;
border-bottom-left-radius: $base-border-radius;
border-bottom-right-radius: $base-border-radius;
}
&:last-child {
// the drop down
background: none;
border: none;
padding: 1em 0 0 0;
select {
max-width: 100%;
}
}
a#home_nav {
@include media('>desktop') {
// Image replacement
background-color: transparent;
color: transparent;
border: 0;
overflow: hidden;
text-indent: 100%;
text-shadow: none;
white-space: nowrap;
&:before {
content: "";
display: block;
height: 100%;
width: 0;
}
// all the rest
background-image: url("../images/icon_house-chimney.svg");
background-repeat: no-repeat;
background-position: top center;
display: inline-block;
height: 24px;
width: 24px;
}
}
&.guides-index-large {
@include media('<desktop') {
display: none;
}
}
&.guides-index-small {
@include media('>desktop') {
display: none;
}
@include media('<desktop') {
display: block;
}
}
}
}
} // nav#feature_nav
} // header#page_header
// Desktop guides flyout
.guides-index .guides-index-item {
position: relative;
z-index: 15;
padding-bottom: 0.125em;
:where(body[dir="ltr"]) & { background-position: right top; padding-right: 1em; }
:where(body[dir="rtl"]) & { background-position: left top; padding-left: 1em; }
}
#guides {
background: $gray-200;
box-shadow: 0 2px 20px rgba(0,0,0,0.25);
display: block;
border-radius: $base-border-radius;
color: $gray-900;
height: 58em;
padding: 2em 2em 1.5em 2em;
position: absolute;
top: 25px;
right: 50px;
width: 90vw;
max-width: 1000px;
z-index: 10;
:where(body[dir="ltr"]) & { left: auto; right: 50px; }
:where(body[dir="rtl"]) & { left: 50px; right: auto; }
&.visible {
display: block !important;
}
.guides-section-container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
max-height: 53em;
width: 100%;
.guides-section {
flex: auto;
margin: 0 2em 0.5em 0;
text-align: left;
width: 33%;
dt, dd {
font-weight: 400 !important;
font-size: 0.825rem;
margin: 0;
padding: 0;
font-variant-numeric: lining-nums tabular-nums;
}
dt {
margin: 0.5em 0;
font-weight: bold !important;
}
dd {
line-height: 1.2;
margin-bottom: 0.5em;
border-bottom: none;
a,
a:link,
a:visited {
color: $gray-900;
text-decoration: none;
font-weight: 400 !important;
}
a:hover,
a:active {
color: $rf-brand;
text-decoration: underline;
}
}
}
}
} // #guides
footer#page_footer {
background-color: $gray-800;
color: #fff;
font-size: 0.75em;
padding: 1em 0 .5em 0;
width: 100%;
p {
max-width: 100vw;
}
}
#feature {
background-color: $gray-100;
@include media('>desktop') {
background-color: #fff;
}
#subCol {
background-color: $gray-100;
border-radius: $base-border-radius;
font-size: 1rem;
padding: 0.5em 1em;
@include media('>desktop') {
display: block;
position: fixed;
top: 100px;
right: 5vw;
max-height: calc(100vh - 90px);
width: 30vw;
}
h3.chapter img {
margin-right: 0.25em;
}
ol {
@include media('>desktop') {
overflow-y: auto;
max-height: 73vh;
}
li {
font-weight: bold;
a,
a:link,
a:visited {
color: $gray-900;
text-decoration: none;
}
a:hover,
a:active {
color: $rf-brand;
text-decoration: underline;
} // a
ul {
padding-inline-start: 1em;
li {
font-weight: 400;
} // li
} // ul
} // li
} // ol
}
}
@include media('>desktop') {
padding-right: 400px;
}
} // body.guide

@ -0,0 +1,93 @@
// ----------------------------------------------------------------------------
// Containers
//
// These are interstitial elements used throughout the guides, providing help,
// context, more info, or warnings to readers.
// ----------------------------------------------------------------------------
/* Same bottom margin for special boxes than for regular paragraphs, this way
intermediate whitespace looks uniform. */
.interstitial {
background-repeat: no-repeat;
background-size: 36px 36px;
border-radius: $base-border-radius;
border: 2px solid $gray-500;
min-height: calc(36px + 1.2em);
margin: 2em auto;
padding: 0.75em !important;
position: relative;
// Padding and spacing for LTR vs RTL langauge defaults
:where(body[dir="ltr"]) & { background-position: 10px 10px; padding-right: 1em !important; padding-left: 56px !important; }
:where(body[dir="rtl"]) & { background-position: calc(100% - 10px) 10px; padding-right: 56px !important; padding-left: 1em !important; }
/* Remove bottom margin of paragraphs in special boxes, otherwise they get a
spurious blank area below with the box background. */
p {
margin-bottom: 0.75em;
&:last-child {
margin-bottom: 0;
}
}
&.code {
border: none;
background-color: $gray-900;
min-height: auto; // remove if icon is restored
padding-left: 1em !important; // remove if icon is restored
pre {margin: 0;}
button.clipboard-button {
color: $gray-100;
background-color: $gray-700;
border: 1px solid $gray-500;
border-radius: 4px;
font-size: 0.75em;
padding: 0.25em 0.5em !important;
position: absolute;
bottom: 10px;
:where(body[dir="ltr"]) & { right: 10px; }
:where(body[dir="rtl"]) & { left: 10px; }
text-transform: uppercase;
} // button.clipboard-button
} // &.code
&.note {
border-color: $note;
background-color: $note-bkgnd;
background-image: url("../images/icon_task-list-pin.svg");
}
&.work-in-progress,
&.todo {
border-color: $note;
background-color: $note-bkgnd;
background-image: url("../images/icon_construction-sign.svg");
}
&.info {
border-color: $tip;
background-color: $tip-bkgnd;
background-image: url("../images/icon_bulb-1.svg");
}
&.warning {
border-color: $stop;
background-color: $stop-bkgnd;
background-image: url("../images/icon_hand-stop.svg");
}
&.question {
border-color: $gray-500;
background-color: $gray-200;
background-image: url("../images/icon_question-bubble.svg");
}
&.kindle {
padding-top: 1em !important;
}
} // .interstitial

@ -0,0 +1,211 @@
/* ----------------------------------------------------------------------------
// Rails Guides Redesign
// February 2024
//
// John Athayde (https://www.johnathayde.com) for Meticulous
// ---------------------------------------------------------------------------- */
// ----------------------------------------------------------------------------
// Syntax Highlighting
// ----------------------------------------------------------------------------
.highlight {
background-color: transparent !important;
table {
td { padding: 5px; }
pre { margin: 0; }
} // table
// Block Styles - Global
.c,
.cd,
.ch,
.cm,
.cpf,
.cs
.c1,
.ge {
font-style: italic;
}
.cp,
.cs,
.fm,
.gs,
.kc,
.kd,
.kn,
.kp,
.kr,
.kt,
.nc,
.nd,
.ne,
.nf,
.nl,
.o,
.ow {
font-weight: bold;
}
} // .highlight
// ----------------------------------------------------------------------------
// The Colors
//
// These are the inverse of what they used to be, as we use a dark block on the
// light background and a light block on the dark background pages.
// Include media does not support prefers-color-scheme yet
@media (prefers-color-scheme: dark) {
.highlight {
&.plaintext,
&.console,
&.erb,
&.html { color: #000; }
// .hll { background-color: #272822; }
.c { color: #6c6c65; } /* Comment */
.err { color: #a61717; background-color: #e3d2d2 } /* Error */
.k { color: #0073a6; } /* Keyword */
.l { color: #007979; } /* Literal */
.n { color: #007979; } /* Name */
.o { color: #f92672; } /* Operator */
.p { color: #007979; } /* Punctuation */
.bp { color: #6c6c6c; }
.cm { color: #6c6c65; } /* Comment.Multiline */
.cp { color: #6c6c6c; } /* Comment.Preproc */
.c1 { color: #6c6c65; } /* Comment.Single */
.cs { color: #6c6c6c; } /* Comment.Special */
.fm { color: #990000; }
.kc { color: #32aac2; } /* Keyword.Constant */
.kd { color: #32aac2; } /* Keyword.Declaration */
.kn { color: #FF538C; } /* Keyword.Namespace */
.kp { color: #32aac2; } /* Keyword.Pseudo */
.kr { color: #32aac2; } /* Keyword.Reserved */
.kt { color: #445588; } /* Keyword.Type */
.kv { color: #0073a6; }
.ld { color: #d51144; } /* Literal.Date */
.m { color: #007979; } /* Literal.Number */
.s { color: #d51144; } /* Literal.String */
.na { color: #007979; } /* Name.Attribute */
.nb { color: #0074a1; } /* Name.Builtin */
.nc { color: #445588; } /* Name.Class */
.no { color: #007979; } /* Name.Constant */
.nd { color: #3c5d5d; } /* Name.Decorator */
.ni { color: #800080; } /* Name.Entity */
.ne { color: #990000; } /* Name.Exception */
.nf { color: #990000; } /* Name.Function */
.nl { color: #990000; } /* Name.Label */
.nn { color: #555555; } /* Name.Namespace */
.nx { color: #BDFB42; } /* Name.Other */
.py { color: #007979; } /* Name.Property */
.nt { color: #000080; } /* Name.Tag */
.nv { color: #007979; } /* Name.Variable */
.ow { color: #000000; } /* Operator.Word */
.w { color: #6c6c6c; } /* Text.Whitespace */
.mf { color: #007979; } /* Literal.Number.Float */
.mh { color: #007979; } /* Literal.Number.Hex */
.mi { color: #007979; } /* Literal.Number.Integer */
.mo { color: #007979; } /* Literal.Number.Oct */
.sb { color: #d51144; } /* Literal.String.Backtick */
.sc { color: #d51144; } /* Literal.String.Char */
.sd { color: #d51144; } /* Literal.String.Doc */
.s2 { color: #d51144; } /* Literal.String.Double */
.se { color: #007979; } /* Literal.String.Escape */
.sh { color: #d51144; } /* Literal.String.Heredoc */
.si { color: #d51144; } /* Literal.String.Interpol */
.sx { color: #d51144; } /* Literal.String.Other */
.sr { color: #d51144; } /* Literal.String.Regex */
.s1 { color: #d51144; } /* Literal.String.Single */
.ss { color: #d51144; } /* Literal.String.Symbol */
.bp { color: #007979; } /* Name.Builtin.Pseudo */
.vc { color: #007979; } /* Name.Variable.Class */
.vg { color: #007979; } /* Name.Variable.Global */
.vi { color: #005cc5; } /* Name.Variable.Instance */
.vm { color: #007979; }
.il { color: #007979; } /* Literal.Number.Integer.Long */
.gh { color: #6c6c6c; } /* Generic Heading & Diff Header */
.gu { color: #6c6c6c; } /* Generic.Subheading & Diff Unified/Comment? */
.gd { color: #000000; background-color: #ffdddd; } /* Generic.Deleted & Diff Deleted */
.gi { color: #000000; background-color: #ddffdd; } /* Generic.Inserted & Diff Inserted */
.gr { color: #aa0000; }
.go { color: #6c6c6c; }
.gp { color: #555555; }
.gt { color: #aa0000; }
}
}
@media (prefers-color-scheme: light) {
.highlight {
color: #fff;
&.plaintext,
&.console,
&.erb,
&.html { color: #fff; }
.hll { background-color: #272822; }
.c { color: #A9A9A8; } /* Comment */
.err { color: #e7007b; background-color: #1e0010 } /* Error */
.k { color: #8AECFF; } /* Keyword */
.l { color: #C3A2FF; } /* Literal */
.n { color: #f8f8f2; } /* Name */
.o { color: #FF538C; } /* Operator */
.p { color: #f8f8f2; } /* Punctuation */
.cm { color: #A9A9A8; } /* Comment.Multiline */
.cp { color: #A9A9A8; } /* Comment.Preproc */
.c1 { color: #A9A9A8; } /* Comment.Single */
.cs { color: #A9A9A8; } /* Comment.Special */
.kc { color: #8AECFF; } /* Keyword.Constant */
.kd { color: #8AECFF; } /* Keyword.Declaration */
.kn { color: #FF538C; } /* Keyword.Namespace */
.kp { color: #8AECFF; } /* Keyword.Pseudo */
.kr { color: #8AECFF; } /* Keyword.Reserved */
.kt { color: #8AECFF; } /* Keyword.Type */
.ld { color: #FCEF8D; } /* Literal.Date */
.m { color: #C3A2FF; } /* Literal.Number */
.s { color: #FCEF8D; } /* Literal.String */
.na { color: #BDFB42; } /* Name.Attribute */
.nb { color: #f8f8f2; } /* Name.Builtin */
.nc { color: #BDFB42; } /* Name.Class */
.no { color: #8AECFF; } /* Name.Constant */
.nd { color: #BDFB42; } /* Name.Decorator */
.ni { color: #f8f8f2; } /* Name.Entity */
.ne { color: #BDFB42; } /* Name.Exception */
.nf { color: #BDFB42; } /* Name.Function */
.nl { color: #f8f8f2; } /* Name.Label */
.nn { color: #f8f8f2; } /* Name.Namespace */
.nx { color: #BDFB42; } /* Name.Other */
.py { color: #f8f8f2; } /* Name.Property */
.nt { color: #FF538C; } /* Name.Tag */
.nv { color: #f8f8f2; } /* Name.Variable */
.ow { color: #FF538C; } /* Operator.Word */
.w { color: #f8f8f2; } /* Text.Whitespace */
.mf { color: #C3A2FF; } /* Literal.Number.Float */
.mh { color: #C3A2FF; } /* Literal.Number.Hex */
.mi { color: #C3A2FF; } /* Literal.Number.Integer */
.mo { color: #C3A2FF; } /* Literal.Number.Oct */
.sb { color: #FCEF8D; } /* Literal.String.Backtick */
.sc { color: #FCEF8D; } /* Literal.String.Char */
.sd { color: #FCEF8D; } /* Literal.String.Doc */
.s2 { color: #FCEF8D; } /* Literal.String.Double */
.se { color: #C3A2FF; } /* Literal.String.Escape */
.sh { color: #FCEF8D; } /* Literal.String.Heredoc */
.si { color: #FCEF8D; } /* Literal.String.Interpol */
.sx { color: #FCEF8D; } /* Literal.String.Other */
.sr { color: #FCEF8D; } /* Literal.String.Regex */
.s1 { color: #FCEF8D; } /* Literal.String.Single */
.ss { color: #FCEF8D; } /* Literal.String.Symbol */
.bp { color: #f8f8f2; } /* Name.Builtin.Pseudo */
.vc { color: #f8f8f2; } /* Name.Variable.Class */
.vg { color: #f8f8f2; } /* Name.Variable.Global */
.vi { color: #f8f8f2; } /* Name.Variable.Instance */
.il { color: #C3A2FF; } /* Literal.Number.Integer.Long */
.gh { color: #A9A9A8; } /* Generic Heading & Diff Header */
.gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */
.gd { color: #FF538C; background-color: unset; } /* Generic.Deleted & Diff Deleted */
.gi { color: #BDFB42; background-color: unset; } /* Generic.Inserted & Diff Inserted */
.gr { color: #FF538C; }
.go { color: #A9A9A8; }
.gp { color: #fff; }
}
}

@ -0,0 +1,250 @@
/* ----------------------------------------------------------------------------
// Rails Guides Redesign
//
// Created: 29 February 2024
// Modified: 19 March 2024
// ---------------------------------------------------------------------------- */
// ----------------------------------------------------------------------------
// Imports
@import 'vendor/normalize';
@import 'vendor/boilerplate';
@import 'vendor/include-media';
// ----------------------------------------------------------------------------
// Breakpoints
//
// This overrides the defaults in include-media.
$breakpoints: (
'phone': 320px,
'phone-wide': 480px,
'tablet': 768px,
'desktop': 1024px,
'desktop-wide': 1280px,
'desktop-ultra-wide': 1440px,
'desktop-hd': 1920px,
'desktop-full': 2560px
);
// ----------------------------------------------------------------------------
// Variables
// ----------------------------------------------------------------------------
// Global Colors
$rf-brand: #C81418;
$rf-brand-light: lighten($rf-brand, 5%);
$rf-brand-dark: darken($rf-brand, 10%);
$rf-brand-darker: darken($rf-brand, 20%);
$rf-highlight: rgba($rf-brand, 10%);
$gray-100: #FAF9F8;
$gray-200: #F5F3F1;
$gray-300: #EBEBEA;
$gray-400: #DCDCD8;
$gray-500: #A9A9A8;
$gray-600: #666666;
$gray-700: #3A3939;
$gray-800: #343434;
$gray-900: #2E2E2E;
$note: #FFD600;
$note-bkgnd: rgba($note, 15%); // Works for light and dark mode
$tip: #00F0FF;
$tip-bkgnd: rgba($tip, 15%); // Works for light and dark mode
$stop: $rf-brand;
$stop-bkgnd: rgba($stop, 15%); // Works for light and dark mode
// ----------------------------------------------------------------------------
// Fonts
// These are the same fonts that are used on the marcom site, and they are
// included from those links/embeds.
@font-face {
font-family: InterVariable;
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url('https://rubyonrails.org/assets/fonts/InterVariable.woff2?v=4.0') format('woff2');
}
@font-face {
font-family: InterVariable;
font-style: italic;
font-weight: 100 900;
font-display: swap;
src: url('https://rubyonrails.org/assets/fonts/InterVariable-Italic.woff2?v=4.0') format('woff2');
}
/* static fonts */
@font-face { font-family:Inter; font-style:normal; font-weight:100; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-Thin.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:italic; font-weight:100; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-ThinItalic.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:normal; font-weight:200; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-ExtraLight.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:italic; font-weight:200; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-ExtraLightItalic.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:normal; font-weight:300; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-Light.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:italic; font-weight:300; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-LightItalic.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:normal; font-weight:400; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-Regular.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:italic; font-weight:400; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-Italic.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:normal; font-weight:500; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-Medium.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:italic; font-weight:500; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-MediumItalic.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:normal; font-weight:600; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-SemiBold.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:italic; font-weight:600; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-SemiBoldItalic.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:normal; font-weight:700; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-Bold.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:italic; font-weight:700; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-BoldItalic.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:normal; font-weight:800; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-ExtraBold.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:italic; font-weight:800; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-ExtraBoldItalic.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:normal; font-weight:900; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-Black.woff2?v=4.0") format("woff2"); }
@font-face { font-family:Inter; font-style:italic; font-weight:900; font-display:swap; src:url("https://rubyonrails.org/assets/fonts/Inter-BlackItalic.woff2?v=4.0") format("woff2"); }
@font-face {
font-family: 'IBM Plex Mono';
font-style: normal;
font-weight: 400;
src: url("https://rubyonrails.org/assets/fonts/IBMPlexMono-Text.eot");
src: url("https://rubyonrails.org/assets/fonts/IBMPlexMono-Text.eot?#iefix") format("embedded-opentype"), url("https://rubyonrails.org/assets/fonts/IBMPlexMono-Text.woff2") format("woff2"), url("https://rubyonrails.org/assets/fonts/IBMPlexMono-Text.woff") format("woff");
font-display:swap
}
@font-face {
font-family: 'IBM Plex Mono';
font-style: italic;
font-weight: 400;
src: url("https://rubyonrails.org/assets/fonts/IBMPlexMono-TextItalic.eot");
src: url("https://rubyonrails.org/assets/fonts/IBMPlexMono-TextItalic.eot?#iefix") format("embedded-opentype"), url("https://rubyonrails.org/assets/fonts/IBMPlexMono-TextItalic.woff2") format("woff2"), url("https://rubyonrails.org/assets/fonts/IBMPlexMono-TextItalic.woff") format("woff");
font-display:swap
}
@font-face {
font-family: 'IBM Plex Mono';
font-style: normal;
font-weight: 500;
src: url("https://rubyonrails.org/assets/fonts/IBMPlexMono-Medium.eot");
src: url("https://rubyonrails.org/assets/fonts/IBMPlexMono-Medium.eot?#iefix") format("embedded-opentype"), url("https://rubyonrails.org/assets/fonts/IBMPlexMono-Medium.woff2") format("woff2"), url("https://rubyonrails.org/assets/fonts/IBMPlexMono-Medium.woff") format("woff");
font-display:swap
}
@font-face {
font-family: 'IBM Plex Mono';
font-style: italic;
font-weight: 500;
src: url("https://rubyonrails.org/assets/fonts/IBMPlexMono-MediumItalic.eot");
src: url("https://rubyonrails.org/assets/fonts/IBMPlexMono-MediumItalic.eot?#iefix") format("embedded-opentype"), url("https://rubyonrails.org/assets/fonts/IBMPlexMono-MediumItalic.woff2") format("woff2"), url("https://rubyonrails.org/assets/fonts/IBMPlexMono-MediumItalic.woff") format("woff");
font-display:swap
}
@font-face {
font-family: 'Calibre';
font-style: normal;
font-weight: 400;
src: url("https://rubyonrails.org/assets/fonts/calibre-regular.woff2") format("woff2");
font-display:swap
}
@font-face {
font-family: 'Calibre';
font-style: italic;
font-weight: 400;
src: url("https://rubyonrails.org/assets/fonts/calibre-regular-italic.woff2") format("woff2");
font-display:swap
}
@font-face {
font-family: 'Calibre';
font-style: normal;
font-weight: 600;
src: url("https://rubyonrails.org/assets/fonts/calibre-semibold.woff2") format("woff2");
font-display:swap
}
@font-face {
font-family: 'Calibre';
font-style: italic;
font-weight: 600;
src: url("https://rubyonrails.org/assets/fonts/calibre-semibold-italic.woff2") format("woff2");
font-display:swap
}
@font-face {
font-family: 'Calibre';
font-style: normal;
font-weight: 700;
src: url("https://rubyonrails.org/assets/fonts/calibre-bold.woff2") format("woff2");
font-display:swap
}
// ----------------------------------------------------------------------------
// Sizes
$base-border-radius: 8px;
// ----------------------------------------------------------------------------
// Base & Utility
// Fix everything's box model for better style control
* {
box-sizing: border-box;
} // *
// Makes a list not look like a list
%list-in-disguise {
margin: 0;
padding: 0;
li {
margin: 0;
padding: 0;
list-style: none;
}
} // %list-in-disguise
// For image replacement
%image-replacement {
background-color: transparent;
color: transparent;
border: 0;
overflow: hidden;
text-indent: 100%;
text-shadow: none;
white-space: nowrap;
&:before {
content: "";
display: block;
height: 100%;
width: 0;
}
} // %image-replacement
// Clearfix, not used often anymore, but present for times when the browser misbehaves.
.clearfix, %clearfix {
&:after,
&:before {
content: " ";
display: table;
} // &:after, &:before
&:after {
clear: both;
} // &:after
} // %clearfix // .clearfix, %clearfix
.hide {
visibility: hidden;
}
// ----------------------------------------------------------------------------
// COMPONENTS
@import 'components/_code-container';
// ----------------------------------------------------------------------------
// Now, bring me that horizon.
@import 'main';
@import 'dark';

@ -0,0 +1,246 @@
/*! HTML5 Boilerplate v9.0.0-RC1 | MIT License | https://html5boilerplate.com/ */
/* main.css 3.0.0 | MIT License | https://github.com/h5bp/main.css#readme */
/*
* What follows is the result of much research on cross-browser styling.
* Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
* Kroc Camen, and the H5BP dev community and team.
*/
/* ==========================================================================
Base styles: opinionated defaults
========================================================================== */
html {
color: #222;
font-size: 1em;
line-height: 1.4;
}
/*
* Remove text-shadow in selection highlight:
* https://twitter.com/miketaylr/status/12228805301
*
* Customize the background color to match your design.
*/
::-moz-selection {
background: #b3d4fc;
text-shadow: none;
}
::selection {
background: #b3d4fc;
text-shadow: none;
}
/*
* A better looking default horizontal rule
*/
hr {
display: block;
height: 1px;
border: 0;
border-top: 1px solid #ccc;
margin: 1em 0;
padding: 0;
}
/*
* Remove the gap between audio, canvas, iframes,
* images, videos and the bottom of their containers:
* https://github.com/h5bp/html5-boilerplate/issues/440
*/
audio,
canvas,
iframe,
img,
svg,
video {
vertical-align: middle;
}
/*
* Remove default fieldset styles.
*/
fieldset {
border: 0;
margin: 0;
padding: 0;
}
/*
* Allow only vertical resizing of textareas.
*/
textarea {
resize: vertical;
}
/* ==========================================================================
Author's custom styles
========================================================================== */
/* ==========================================================================
Helper classes
========================================================================== */
/*
* Hide visually and from screen readers
*/
.hidden,
[hidden] {
display: none !important;
}
/*
* Hide only visually, but have it available for screen readers:
* https://snook.ca/archives/html_and_css/hiding-content-for-accessibility
*
* 1. For long content, line feeds are not interpreted as spaces and small width
* causes content to wrap 1 word per line:
* https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfe
*/
.visually-hidden {
border: 0;
clip: rect(0, 0, 0, 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
white-space: nowrap;
width: 1px;
/* 1 */
}
/*
* Extends the .visually-hidden class to allow the element
* to be focusable when navigated to via the keyboard:
* https://www.drupal.org/node/897638
*/
.visually-hidden.focusable:active,
.visually-hidden.focusable:focus {
clip: auto;
height: auto;
margin: 0;
overflow: visible;
position: static;
white-space: inherit;
width: auto;
}
/*
* Hide visually and from screen readers, but maintain layout
*/
.invisible {
visibility: hidden;
}
/*
* Clearfix: contain floats
*
* The use of `table` rather than `block` is only necessary if using
* `::before` to contain the top-margins of child elements.
*/
.clearfix::before,
.clearfix::after {
content: "";
display: table;
}
.clearfix::after {
clear: both;
}
/* ==========================================================================
EXAMPLE Media Queries for Responsive Design.
These examples override the primary ('mobile first') styles.
Modify as content requires.
========================================================================== */
@media only screen and (min-width: 35em) {
/* Style adjustments for viewports that meet the condition */
}
@media print,
(-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 1.25dppx),
(min-resolution: 120dpi) {
/* Style adjustments for high resolution devices */
}
/* ==========================================================================
Print styles.
Inlined to avoid the additional HTTP request:
https://www.phpied.com/delay-loading-your-print-css/
========================================================================== */
@media print {
*,
*::before,
*::after {
background: #fff !important;
color: #000 !important;
/* Black prints faster */
box-shadow: none !important;
text-shadow: none !important;
}
a,
a:visited {
text-decoration: underline;
}
a[href]::after {
content: " (" attr(href) ")";
}
abbr[title]::after {
content: " (" attr(title) ")";
}
/*
* Don't show links that are fragment identifiers,
* or use the `javascript:` pseudo protocol
*/
a[href^="#"]::after,
a[href^="javascript:"]::after {
content: "";
}
pre {
white-space: pre-wrap !important;
}
pre,
blockquote {
border: 1px solid #999;
page-break-inside: avoid;
}
tr,
img {
page-break-inside: avoid;
}
p,
h2,
h3 {
orphans: 3;
widows: 3;
}
h2,
h3 {
page-break-after: avoid;
}
}

@ -0,0 +1,618 @@
// _ _ _ _ _
// (_) | | | | | (_)
// _ _ __ ___| |_ _ __| | ___ _ __ ___ ___ __| |_ __ _
// | | '_ \ / __| | | | |/ _` |/ _ \ | '_ ` _ \ / _ \/ _` | |/ _` |
// | | | | | (__| | |_| | (_| | __/ | | | | | | __/ (_| | | (_| |
// |_|_| |_|\___|_|\__,_|\__,_|\___| |_| |_| |_|\___|\__,_|_|\__,_|
//
// Simple, elegant and maintainable media queries in Sass
// v2.0.0
//
// https://eduardoboucas.github.io/include-media
//
// Authors: Eduardo Boucas (@eduardoboucas)
// Kitty Giraudel (@kittygiraudel)
//
// This project is licensed under the terms of the MIT license
@charset "UTF-8";
////
/// include-media library public configuration
/// @author Eduardo Boucas
/// @access public
////
@use 'sass:math';
@use 'sass:map';
@use 'sass:list';
@use 'sass:string';
@use 'sass:meta';
///
/// Creates a list of global breakpoints
///
/// @example scss - Creates a single breakpoint with the label `phone`
/// $breakpoints: ('phone': 320px);
///
$breakpoints: (
'phone': 320px,
'tablet': 768px,
'desktop': 1024px,
) !default;
///
/// Creates a list of static expressions or media types
///
/// @example scss - Creates a single media type (screen)
/// $media-expressions: ('screen': 'screen');
///
/// @example scss - Creates a static expression with logical disjunction (OR operator)
/// $media-expressions: (
/// 'retina2x': '(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)'
/// );
///
$media-expressions: (
'screen': 'screen',
'print': 'print',
'handheld': 'handheld',
'landscape': '(orientation: landscape)',
'portrait': '(orientation: portrait)',
'retina2x':
'(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi), (min-resolution: 2dppx)',
'retina3x':
'(-webkit-min-device-pixel-ratio: 3), (min-resolution: 350dpi), (min-resolution: 3dppx)',
) !default;
///
/// Defines a number to be added or subtracted from each unit when declaring breakpoints with exclusive intervals
///
/// @example scss - Interval for pixels is defined as `1` by default
/// @include media('>128px') {}
///
/// /* Generates: */
/// @media (min-width: 129px) {}
///
/// @example scss - Interval for ems is defined as `0.01` by default
/// @include media('>20em') {}
///
/// /* Generates: */
/// @media (min-width: 20.01em) {}
///
/// @example scss - Interval for rems is defined as `0.1` by default, to be used with `font-size: 62.5%;`
/// @include media('>2.0rem') {}
///
/// /* Generates: */
/// @media (min-width: 2.1rem) {}
///
$unit-intervals: (
'px': 1,
'em': 0.01,
'rem': 0.1,
'': 0,
) !default;
///
/// Defines whether support for media queries is available, useful for creating separate stylesheets
/// for browsers that don't support media queries.
///
/// @example scss - Disables support for media queries
/// $im-media-support: false;
/// @include media('>=tablet') {
/// .foo {
/// color: tomato;
/// }
/// }
///
/// /* Generates: */
/// .foo {
/// color: tomato;
/// }
///
$im-media-support: true !default;
///
/// Selects which breakpoint to emulate when support for media queries is disabled. Media queries that start at or
/// intercept the breakpoint will be displayed, any others will be ignored.
///
/// @example scss - This media query will show because it intercepts the static breakpoint
/// $im-media-support: false;
/// $im-no-media-breakpoint: 'desktop';
/// @include media('>=tablet') {
/// .foo {
/// color: tomato;
/// }
/// }
///
/// /* Generates: */
/// .foo {
/// color: tomato;
/// }
///
/// @example scss - This media query will NOT show because it does not intercept the desktop breakpoint
/// $im-media-support: false;
/// $im-no-media-breakpoint: 'tablet';
/// @include media('>=desktop') {
/// .foo {
/// color: tomato;
/// }
/// }
///
/// /* No output */
///
$im-no-media-breakpoint: 'desktop' !default;
///
/// Selects which media expressions are allowed in an expression for it to be used when media queries
/// are not supported.
///
/// @example scss - This media query will show because it intercepts the static breakpoint and contains only accepted media expressions
/// $im-media-support: false;
/// $im-no-media-breakpoint: 'desktop';
/// $im-no-media-expressions: ('screen');
/// @include media('>=tablet', 'screen') {
/// .foo {
/// color: tomato;
/// }
/// }
///
/// /* Generates: */
/// .foo {
/// color: tomato;
/// }
///
/// @example scss - This media query will NOT show because it intercepts the static breakpoint but contains a media expression that is not accepted
/// $im-media-support: false;
/// $im-no-media-breakpoint: 'desktop';
/// $im-no-media-expressions: ('screen');
/// @include media('>=tablet', 'retina2x') {
/// .foo {
/// color: tomato;
/// }
/// }
///
/// /* No output */
///
$im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
////
/// Cross-engine logging engine
/// @author Kitty Giraudel
/// @access private
////
///
/// Log a message either with `@error` if supported
/// else with `@warn`, using `feature-exists('at-error')`
/// to detect support.
///
/// @param {String} $message - Message to log
///
@function im-log($message) {
@if meta.feature-exists('at-error') {
@error $message;
} @else {
@warn $message;
$_: noop();
}
@return $message;
}
///
/// Wrapper mixin for the log function so it can be used with a more friendly
/// API than `@if im-log('..') {}` or `$_: im-log('..')`. Basically, use the function
/// within functions because it is not possible to include a mixin in a function
/// and use the mixin everywhere else because it's much more elegant.
///
/// @param {String} $message - Message to log
///
@mixin log($message) {
@if im-log($message) {
}
}
///
/// Function with no `@return` called next to `@warn` in Sass 3.3
/// to trigger a compiling error and stop the process.
///
@function noop() {
}
///
/// Determines whether a list of conditions is intercepted by the static breakpoint.
///
/// @param {Arglist} $conditions - Media query conditions
///
/// @return {Boolean} - Returns true if the conditions are intercepted by the static breakpoint
///
@function im-intercepts-static-breakpoint($conditions...) {
$no-media-breakpoint-value: map.get($breakpoints, $im-no-media-breakpoint);
@if not $no-media-breakpoint-value {
@if im-log('`#{$im-no-media-breakpoint}` is not a valid breakpoint.') {
}
}
@each $condition in $conditions {
@if not map.has-key($media-expressions, $condition) {
$operator: get-expression-operator($condition);
$prefix: get-expression-prefix($operator);
$value: get-expression-value($condition, $operator);
@if ($prefix == 'max' and $value <= $no-media-breakpoint-value) or
($prefix == 'min' and $value > $no-media-breakpoint-value)
{
@return false;
}
} @else if not list.index($im-no-media-expressions, $condition) {
@return false;
}
}
@return true;
}
////
/// Parsing engine
/// @author Kitty Giraudel
/// @access private
////
///
/// Get operator of an expression
///
/// @param {String} $expression - Expression to extract operator from
///
/// @return {String} - Any of `>=`, `>`, `<=`, `<`, ``, ``
///
@function get-expression-operator($expression) {
@each $operator in ('>=', '>', '<=', '<', '', '') {
@if string.index($expression, $operator) {
@return $operator;
}
}
// It is not possible to include a mixin inside a function, so we have to
// rely on the `im-log(..)` function rather than the `log(..)` mixin. Because
// functions cannot be called anywhere in Sass, we need to hack the call in
// a dummy variable, such as `$_`. If anybody ever raise a scoping issue with
// Sass 3.3, change this line in `@if im-log(..) {}` instead.
$_: im-log('No operator found in `#{$expression}`.');
}
///
/// Get dimension of an expression, based on a found operator
///
/// @param {String} $expression - Expression to extract dimension from
/// @param {String} $operator - Operator from `$expression`
///
/// @return {String} - `width` or `height` (or potentially anything else)
///
@function get-expression-dimension($expression, $operator) {
$operator-index: string.index($expression, $operator);
$parsed-dimension: string.slice($expression, 0, $operator-index - 1);
$parsed-dimension: str-trim($parsed-dimension);
$dimension: 'width';
@if string.length($parsed-dimension) > 0 {
$dimension: $parsed-dimension;
}
@return $dimension;
}
///
/// Get dimension prefix based on an operator
///
/// @param {String} $operator - Operator
///
/// @return {String} - `min` or `max`
///
@function get-expression-prefix($operator) {
@return if(list.index(('<', '<=', ''), $operator), 'max', 'min');
}
///
/// Get value of an expression, based on a found operator
///
/// @param {String} $expression - Expression to extract value from
/// @param {String} $operator - Operator from `$expression`
///
/// @return {Number} - A numeric value
///
@function get-expression-value($expression, $operator) {
$operator-index: string.index($expression, $operator);
$value: string.slice($expression, $operator-index + string.length($operator));
$trimmedValue: str-trim($value);
@if map.has-key($breakpoints, $trimmedValue) {
$value: map.get($breakpoints, $trimmedValue);
} @else {
$value: to-number($trimmedValue);
}
$interval: map.get($unit-intervals, math.unit($value));
@if not $interval {
// It is not possible to include a mixin inside a function, so we have to
// rely on the `im-log(..)` function rather than the `log(..)` mixin. Because
// functions cannot be called anywhere in Sass, we need to hack the call in
// a dummy variable, such as `$_`. If anybody ever raise a scoping issue with
// Sass 3.3, change this line in `@if im-log(..) {}` instead.
$_: im-log('Unknown unit `#{math.unit($value)}`.');
}
@if $operator == '>' {
$value: $value + $interval;
} @else if $operator == '<' {
$value: $value - $interval;
}
@return $value;
}
///
/// Parse an expression to return a valid media-query expression
///
/// @param {String} $expression - Expression to parse
///
/// @return {String} - Valid media query
///
@function parse-expression($expression) {
// If it is part of $media-expressions, it has no operator
// then there is no need to go any further, just return the value
@if map.has-key($media-expressions, $expression) {
@return map.get($media-expressions, $expression);
}
$operator: get-expression-operator($expression);
$dimension: get-expression-dimension($expression, $operator);
$prefix: get-expression-prefix($operator);
$value: get-expression-value($expression, $operator);
@return '(#{$prefix}-#{$dimension}: #{$value})';
}
///
/// Slice `$list` between `$start` and `$end` indexes
///
/// @access private
///
/// @param {List} $list - List to slice
/// @param {Number} $start [1] - Start index
/// @param {Number} $end [length($list)] - End index
///
/// @return {List} Sliced list
///
@function slice($list, $start: 1, $end: list.length($list)) {
@if list.length($list) < 1 or $start > $end {
@return ();
}
$result: ();
@for $i from $start through $end {
$result: list.append($result, list.nth($list, $i), comma);
}
@return $result;
}
////
/// String to number converter
/// @author Kitty Giraudel
/// @access private
////
///
/// Casts a string into a number
///
/// @param {String | Number} $value - Value to be parsed
///
/// @return {Number}
///
@function to-number($value) {
@if meta.type-of($value) == 'number' {
@return $value;
} @else if meta.type-of($value) != 'string' {
$_: im-log('Value for `to-number` should be a number or a string.');
}
$first-character: string.slice($value, 1, 1);
$result: 0;
$digits: 0;
$minus: ($first-character == '-');
$numbers: (
'0': 0,
'1': 1,
'2': 2,
'3': 3,
'4': 4,
'5': 5,
'6': 6,
'7': 7,
'8': 8,
'9': 9,
);
// Remove +/- sign if present at first character
@if ($first-character == '+' or $first-character == '-') {
$value: string.slice($value, 2);
}
@for $i from 1 through string.length($value) {
$character: string.slice($value, $i, $i);
@if not(list.index(map.keys($numbers), $character) or $character == '.') {
@return to-length(if($minus, -$result, $result), string.slice($value, $i));
}
@if $character == '.' {
$digits: 1;
} @else if $digits == 0 {
$result: $result * 10 + map.get($numbers, $character);
} @else {
$digits: $digits * 10;
$result: $result + math.div(map.get($numbers, $character), $digits);
}
}
@return if($minus, -$result, $result);
}
///
/// Add `$unit` to `$value`
///
/// @param {Number} $value - Value to add unit to
/// @param {String} $unit - String representation of the unit
///
/// @return {Number} - `$value` expressed in `$unit`
///
@function to-length($value, $unit) {
$units: (
'px': 1px,
'cm': 1cm,
'mm': 1mm,
'%': 1%,
'ch': 1ch,
'pc': 1pc,
'in': 1in,
'em': 1em,
'rem': 1rem,
'pt': 1pt,
'ex': 1ex,
'vw': 1vw,
'vh': 1vh,
'vmin': 1vmin,
'vmax': 1vmax,
);
@if not list.index(map.keys($units), $unit) {
$_: im-log('Invalid unit `#{$unit}`.');
}
@return $value * map.get($units, $unit);
}
////
/// String to number converter
/// @author Jack McNicol
/// @access private
////
///
/// Trims a string of leading and trailing spaces
///
/// @param {String} $string - Value to be trimmed
///
/// @return {String}
///
@function str-trim($string) {
@if (str-slice($string, 1, 1) == ' ') {
@return str-trim(str-slice($string, 2));
} @else if (str-slice($string, str-length($string), -1) == ' ') {
@return str-trim(str-slice($string, 1, -2));
} @else {
@return $string;
}
}
///
/// This mixin aims at redefining the configuration just for the scope of
/// the call. It is helpful when having a component needing an extended
/// configuration such as custom breakpoints (referred to as tweakpoints)
/// for instance.
///
/// @author Kitty Giraudel
///
/// @param {Map} $tweakpoints [()] - Map of tweakpoints to be merged with `$breakpoints`
/// @param {Map} $tweak-media-expressions [()] - Map of tweaked media expressions to be merged with `$media-expression`
///
/// @example scss - Extend the global breakpoints with a tweakpoint
/// @include media-context(('custom': 678px)) {
/// .foo {
/// @include media('>phone', '<=custom') {
/// // ...
/// }
/// }
/// }
///
/// @example scss - Extend the global media expressions with a custom one
/// @include media-context($tweak-media-expressions: ('all': 'all')) {
/// .foo {
/// @include media('all', '>phone') {
/// // ...
/// }
/// }
/// }
///
/// @example scss - Extend both configuration maps
/// @include media-context(('custom': 678px), ('all': 'all')) {
/// .foo {
/// @include media('all', '>phone', '<=custom') {
/// // ...
/// }
/// }
/// }
///
@mixin media-context($tweakpoints: (), $tweak-media-expressions: ()) {
// Save global configuration
$global-breakpoints: $breakpoints;
$global-media-expressions: $media-expressions;
// Update global configuration
$breakpoints: map.merge($breakpoints, $tweakpoints) !global;
$media-expressions: map.merge($media-expressions, $tweak-media-expressions) !global;
@content;
// Restore global configuration
$breakpoints: $global-breakpoints !global;
$media-expressions: $global-media-expressions !global;
}
////
/// include-media public exposed API
/// @author Eduardo Boucas
/// @access public
////
///
/// Generates a media query based on a list of conditions
///
/// @param {Arglist} $conditions - Media query conditions
///
/// @example scss - With a single set breakpoint
/// @include media('>phone') { }
///
/// @example scss - With two set breakpoints
/// @include media('>phone', '<=tablet') { }
///
/// @example scss - With custom values
/// @include media('>=358px', '<850px') { }
///
/// @example scss - With set breakpoints with custom values
/// @include media('>desktop', '<=1350px') { }
///
/// @example scss - With a static expression
/// @include media('retina2x') { }
///
/// @example scss - Mixing everything
/// @include media('>=350px', '<tablet', 'retina3x') { }
///
@mixin media($conditions...) {
@if ($im-media-support and list.length($conditions) == 0) or
(not $im-media-support and im-intercepts-static-breakpoint($conditions...))
{
@content;
} @else if ($im-media-support and list.length($conditions) > 0) {
@media #{string.unquote(parse-expression(list.nth($conditions, 1)))} {
// Recursive call
$sliced-conditions: slice($conditions, 2);
@include media($sliced-conditions...) {
@content;
}
}
}
}

@ -0,0 +1,349 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Render the `main` element consistently in IE.
*/
main {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}

@ -38,6 +38,7 @@ def initialize(edge:, version:, all:, only:, epub:, language:, direction: nil)
def generate def generate
generate_guides generate_guides
process_scss
copy_assets copy_assets
generate_epub if @epub generate_epub if @epub
end end
@ -105,8 +106,13 @@ def select_only(guides)
end end
end end
def process_scss
system "bundle exec dartsass ./assets/stylesrc/style.scss:#{@output_dir}/stylesheets/style.css ./assets/stylesrc/highlight.scss:#{@output_dir}/stylesheets/highlight.css"
end
def copy_assets def copy_assets
FileUtils.cp_r(Dir.glob("#{@guides_dir}/assets/*"), @output_dir) source_files = Dir.glob("#{@guides_dir}/assets/*").reject { |name| name.include?("stylesrc") }
FileUtils.cp_r(source_files, @output_dir)
end end
def output_file_for(guide) def output_file_for(guide)

@ -9,7 +9,7 @@ def guide(name, url, options = {}, &block)
result = content_tag(:dt, link) result = content_tag(:dt, link)
if options[:work_in_progress] if options[:work_in_progress]
result << content_tag(:dd, "Work in progress", class: "work-in-progress") result << content_tag(:dd, "Work in progress", class: "interstitial work-in-progress")
end end
result << content_tag(:dd, capture(&block)) result << content_tag(:dd, capture(&block))

@ -120,7 +120,7 @@ def generate_structure
end end
node[:id] = dom_id(hierarchy) unless node[:id] node[:id] = dom_id(hierarchy) unless node[:id]
node.inner_html = "#{node_index(hierarchy)} #{node.inner_html}" node.inner_html = "<span>#{node_index(hierarchy)}</span> #{node.inner_html}"
end end
end end
@ -148,10 +148,20 @@ def generate_index
end.to_html end.to_html
@index = <<-INDEX.html_safe @index = <<-INDEX.html_safe
<div id="subCol"> <nav id="subCol">
<h3 class="chapter"><img src="images/chapters_icon.gif" alt="" />Chapters</h3> <h3 class="chapter">
<picture>
<!-- Using the `source` HTML tag to set the dark theme image -->
<source
srcset="images/icon_book-close-bookmark-1-wht.svg"
media="(prefers-color-scheme: dark)"
/>
<img src="images/icon_book-close-bookmark-1.svg" alt="Chapter Icon" />
</picture>
Chapters
</h3>
#{@index} #{@index}
</div> </nav>
INDEX INDEX
end end
end end

@ -15,7 +15,7 @@ def block_code(code, language)
lexer = ::Rouge::Lexer.find_fancy(lexer_language(language)) lexer = ::Rouge::Lexer.find_fancy(lexer_language(language))
formatted_code = formatter.format(lexer.lex(code)) formatted_code = formatter.format(lexer.lex(code))
<<~HTML <<~HTML
<div class="code_container"> <div class="interstitial code">
<pre><code class="highlight #{lexer_language(language)}">#{formatted_code}</code></pre> <pre><code class="highlight #{lexer_language(language)}">#{formatted_code}</code></pre>
<button class="clipboard-button" data-clipboard-text="#{clipboard_content(code, language)}">Copy</button> <button class="clipboard-button" data-clipboard-text="#{clipboard_content(code, language)}">Copy</button>
</div> </div>
@ -112,7 +112,7 @@ def convert_notes(body)
else else
$1.downcase $1.downcase
end end
%(<div class="#{css_class}"><p>#{$2.strip}</p></div>) %(<div class="interstitial #{css_class}"><p>#{$2.strip}</p></div>)
end end
end end

@ -6,15 +6,15 @@
<% end %> <% end %>
<% content_for :index_section do %> <% content_for :index_section do %>
<div id="subCol"> <nav id="subCol" aria-label="Chapter">
<dl> <dl>
<dt></dt> <dt></dt>
<% unless @edge -%> <% unless @edge -%>
<dd class="kindle">Rails Guides are also available for <%= link_to 'Kindle', @epub %>.</dd> <dd class="interstitial info kindle">Rails Guides are also available for <%= link_to 'Kindle', @epub %>.</dd>
<% end -%> <% end -%>
<dd class="work-in-progress">Guides marked with this icon are currently being worked on and will not be available in the Guides Index menu. While still useful, they may contain incomplete information and even errors. You can help by reviewing them and posting your comments and corrections.</dd> <dd class="interstitial work-in-progress">Guides marked with this icon are currently being worked on and will not be available in the Guides Index menu. While still useful, they may contain incomplete information and even errors. You can help by reviewing them and posting your comments and corrections.</dd>
</dl> </dl>
</div> </nav>
<% end %> <% end %>
<% documents_by_section.each do |section| %> <% documents_by_section.each do |section| %>

@ -1,5 +1,6 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
@ -7,10 +8,15 @@
<link rel="stylesheet" type="text/css" href="stylesheets/style.css" data-turbo-track="reload"> <link rel="stylesheet" type="text/css" href="stylesheets/style.css" data-turbo-track="reload">
<link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print"> <link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print">
<link rel="stylesheet" type="text/css" href="stylesheets/highlight.css" data-turbo-track="reload"> <link rel="stylesheet" type="text/css" href="stylesheets/highlight.css" data-turbo-track="reload">
<link href="images/favicon.ico" rel="icon" type="image/x-icon" />
<link rel="icon" href="images/favicon.ico" sizes="any">
<link rel="icon" href="images/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="images/icon.png">
<script src="javascripts/@hotwired--turbo.js" data-turbo-track="reload"></script> <script src="javascripts/@hotwired--turbo.js" data-turbo-track="reload"></script>
<script src="javascripts/clipboard.js" data-turbo-track="reload"></script> <script src="javascripts/clipboard.js" data-turbo-track="reload"></script>
<script src="javascripts/guides.js" data-turbo-track="reload"></script> <script src="javascripts/guides.js" data-turbo-track="reload"></script>
<meta property="og:title" content="<%= yield(:page_title) %>" /> <meta property="og:title" content="<%= yield(:page_title) %>" />
<meta name="description" content="<%= yield(:description) %>" /> <meta name="description" content="<%= yield(:description) %>" />
<meta property="og:description" content="<%= yield(:description) %>" /> <meta property="og:description" content="<%= yield(:description) %>" />
@ -18,14 +24,12 @@
<meta property="og:site_name" content="Ruby on Rails Guides" /> <meta property="og:site_name" content="Ruby on Rails Guides" />
<meta property="og:image" content="https://avatars.githubusercontent.com/u/4223" /> <meta property="og:image" content="https://avatars.githubusercontent.com/u/4223" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta name="theme-color" content="#C81418">
</head> </head>
<body dir="<%= @direction %>" class="guide"> <body dir="<%= @direction %>" class="guide">
<% if badge_version = @edge ? "edge" : @version %> <nav id="topNav" aria-label="Secondary">
<div>
<div id="version-badge"><%= badge_version %></div>
</div>
<% end %>
<div id="topNav">
<div class="wrapper"> <div class="wrapper">
<strong class="more-info-label">More at <a href="https://rubyonrails.org/">rubyonrails.org:</a> </strong> <strong class="more-info-label">More at <a href="https://rubyonrails.org/">rubyonrails.org:</a> </strong>
<span class="red-button more-info-button"> <span class="red-button more-info-button">
@ -39,59 +43,72 @@
<li class="more-info"><a href="https://github.com/rails/rails">Contribute on GitHub</a></li> <li class="more-info"><a href="https://github.com/rails/rails">Contribute on GitHub</a></li>
</ul> </ul>
</div> </div>
</div> </nav>
<div id="header"> <header id="page_header">
<div class="wrapper clearfix"> <div class="wrapper clearfix">
<div class="header-logo"><a href="index.html" title="Return to home page">Guides.rubyonrails.org</a></div> <nav id="feature_nav">
<ul class="nav"> <div class="header-logo">
<li><a class="nav-item" href="index.html">Home</a></li> <a href="index.html" title="Return to the Guides Home for <%= @edge.present? ? 'Edge' : @version %> Guides">Guides</a>
<li class="guides-index guides-index-large"> <span id="version_switcher">
<a href="index.html" id="guidesMenu" class="guides-index-item nav-item">Guides Index</a> Version:
<div id="guides" class="clearfix" style="display: none;"> <select class="guides-version">
<hr /> <option value="https://edgeguides.rubyonrails.org/"<%= " selected" if @edge %>>Edge</option>
<dl class="guides-section-container"> <% %w[7.1 7.0 6.1 6.0 5.2 5.1 5.0 4.2 4.1 4.0 3.2 3.1 3.0 2.3].each do |version| %>
<% documents_by_section.each do |section| %> <option value="https://guides.rubyonrails.org/v<%= version %>/"<%= " selected" if @version&.start_with?(version) %>><%= version %></option>
<div class="guides-section">
<dt><%= section['name'] %></dt>
<% finished_documents(section['documents']).each do |document| %>
<dd><a href="<%= document['url'] %>"><%= document['name'] %></a></dd>
<% end %>
</div>
<% end %> <% end %>
</dl> </select>
</div> </span>
</li> </div>
<li><a class="nav-item" href="contributing_to_ruby_on_rails.html">Contribute</a></li> <ul class="nav">
<li class="guides-index guides-index-small"> <li><a class="nav-item" id="home_nav" href="https://rubyonrails.org/">Home</a></li>
<select class="guides-index-item nav-item"> <li class="guides-index guides-index-large">
<option value="index.html">Guides Index</option> <a href="index.html" id="guidesMenu" class="guides-index-item nav-item">Guides Index</a>
<% docs_for_menu.each do |section| %> <div id="guides" class="clearfix" style="display: none;">
<optgroup label="<%= section['name'] %>"> <hr />
<% finished_documents(section['documents']).each do |document| %> <dl class="guides-section-container">
<option value="<%= document['url'] %>"><%= document['name'] %></option> <% documents_by_section.each do |section| %>
<div class="guides-section">
<dt><%= section['name'] %></dt>
<% finished_documents(section['documents']).each do |document| %>
<dd><a href="<%= document['url'] %>"><%= document['name'] %></a></dd>
<% end %>
</div>
<% end %> <% end %>
</optgroup> </dl>
<% end %> </div>
</select> </li>
</li> <li><a class="nav-item" href="contributing_to_ruby_on_rails.html">Contribute</a></li>
<li class="guides-index guides-index-small">
<select class="guides-index-item nav-item">
<option value="index.html">Guides Index</option>
<% docs_for_menu.each do |section| %>
<optgroup label="<%= section['name'] %>">
<% finished_documents(section['documents']).each do |document| %>
<option value="<%= document['url'] %>"><%= document['name'] %></option>
<% end %>
</optgroup>
<% end %>
</select>
</li>
</ul> </ul>
</nav>
</div> </div>
</div> </header>
<hr class="hide" /> <hr class="hide" />
<div id="feature"> <section id="feature">
<div class="wrapper"> <div class="wrapper">
<%= yield :header_section %> <%= yield :header_section %>
<%= yield :index_section %> <%= yield :index_section %>
</div> </div>
</div> </section>
<div id="container"> <main id="container">
<div class="wrapper"> <div class="wrapper">
<div id="mainCol"> <div id="mainCol">
<%= yield %> <%= yield %>
<hr>
<h3>Feedback</h3> <h3>Feedback</h3>
<p> <p>
You're encouraged to help improve the quality of this guide. You're encouraged to help improve the quality of this guide.
@ -117,13 +134,13 @@
</p> </p>
</div> </div>
</div> </div>
</div> </main>
<hr class="hide" /> <hr class="hide" />
<div id="footer"> <footer id="page_footer">
<div class="wrapper"> <div class="wrapper">
<%= render 'license' %> <%= render 'license' %>
</div> </div>
</div> </footer>
</body> </body>
</html> </html>