turbo-rails 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +24 -0
  3. data/.gitignore +2 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +147 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +66 -0
  8. data/Rakefile +11 -0
  9. data/app/assets/javascripts/turbo.js +3161 -0
  10. data/app/channels/turbo/streams/broadcasts.rb +66 -0
  11. data/app/channels/turbo/streams/stream_name.rb +24 -0
  12. data/app/channels/turbo/streams_channel.rb +17 -0
  13. data/app/controllers/turbo/frames/frame_request.rb +24 -0
  14. data/app/controllers/turbo/native/navigation.rb +49 -0
  15. data/app/controllers/turbo/native/navigation_controller.rb +13 -0
  16. data/app/controllers/turbo/streams/turbo_streams_tag_builder.rb +22 -0
  17. data/app/helpers/turbo/drive_helper.rb +16 -0
  18. data/app/helpers/turbo/frames_helper.rb +23 -0
  19. data/app/helpers/turbo/includes_helper.rb +5 -0
  20. data/app/helpers/turbo/streams/action_helper.rb +25 -0
  21. data/app/helpers/turbo/streams_helper.rb +22 -0
  22. data/app/javascript/turbo/cable.js +16 -0
  23. data/app/javascript/turbo/cable_stream_source_element.js +27 -0
  24. data/app/javascript/turbo/index.js +3 -0
  25. data/app/jobs/turbo/streams/action_broadcast_job.rb +6 -0
  26. data/app/jobs/turbo/streams/broadcast_job.rb +7 -0
  27. data/app/models/concerns/turbo/broadcastable.rb +236 -0
  28. data/app/models/turbo/streams/tag_builder.rb +127 -0
  29. data/config/routes.rb +6 -0
  30. data/lib/install/turbo.rb +11 -0
  31. data/lib/tasks/turbo_tasks.rake +6 -0
  32. data/lib/turbo-rails.rb +17 -0
  33. data/lib/turbo/engine.rb +65 -0
  34. data/lib/turbo/test_assertions.rb +22 -0
  35. data/lib/turbo/version.rb +3 -0
  36. data/package.json +42 -0
  37. data/rollup.config.js +23 -0
  38. data/test/drive/drive_helper_test.rb +8 -0
  39. data/test/dummy/.babelrc +18 -0
  40. data/test/dummy/.gitignore +3 -0
  41. data/test/dummy/.postcssrc.yml +3 -0
  42. data/test/dummy/Rakefile +6 -0
  43. data/test/dummy/app/assets/config/manifest.js +2 -0
  44. data/test/dummy/app/assets/images/.keep +0 -0
  45. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  46. data/test/dummy/app/assets/stylesheets/scaffold.css +80 -0
  47. data/test/dummy/app/channels/application_cable/channel.rb +4 -0
  48. data/test/dummy/app/channels/application_cable/connection.rb +4 -0
  49. data/test/dummy/app/controllers/application_controller.rb +2 -0
  50. data/test/dummy/app/controllers/concerns/.keep +0 -0
  51. data/test/dummy/app/controllers/messages_controller.rb +12 -0
  52. data/test/dummy/app/controllers/trays_controller.rb +17 -0
  53. data/test/dummy/app/helpers/application_helper.rb +2 -0
  54. data/test/dummy/app/javascript/packs/application.js +0 -0
  55. data/test/dummy/app/jobs/application_job.rb +2 -0
  56. data/test/dummy/app/mailboxes/application_mailbox.rb +2 -0
  57. data/test/dummy/app/mailboxes/messages_mailbox.rb +4 -0
  58. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  59. data/test/dummy/app/models/application_record.rb +3 -0
  60. data/test/dummy/app/models/concerns/.keep +0 -0
  61. data/test/dummy/app/models/message.rb +29 -0
  62. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  63. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  64. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  65. data/test/dummy/app/views/messages/_message.html.erb +1 -0
  66. data/test/dummy/app/views/messages/_message.turbo_stream.erb +1 -0
  67. data/test/dummy/app/views/messages/show.turbo_stream.erb +9 -0
  68. data/test/dummy/app/views/trays/index.html.erb +3 -0
  69. data/test/dummy/app/views/trays/show.html.erb +3 -0
  70. data/test/dummy/bin/bundle +3 -0
  71. data/test/dummy/bin/rails +4 -0
  72. data/test/dummy/bin/rake +4 -0
  73. data/test/dummy/bin/setup +36 -0
  74. data/test/dummy/bin/update +31 -0
  75. data/test/dummy/bin/yarn +11 -0
  76. data/test/dummy/config.ru +5 -0
  77. data/test/dummy/config/application.rb +22 -0
  78. data/test/dummy/config/boot.rb +5 -0
  79. data/test/dummy/config/cable.yml +10 -0
  80. data/test/dummy/config/environment.rb +5 -0
  81. data/test/dummy/config/environments/development.rb +34 -0
  82. data/test/dummy/config/environments/production.rb +96 -0
  83. data/test/dummy/config/environments/test.rb +38 -0
  84. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  85. data/test/dummy/config/initializers/assets.rb +14 -0
  86. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  87. data/test/dummy/config/initializers/content_security_policy.rb +22 -0
  88. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  89. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  90. data/test/dummy/config/initializers/inflections.rb +16 -0
  91. data/test/dummy/config/initializers/mime_types.rb +4 -0
  92. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  93. data/test/dummy/config/locales/en.yml +33 -0
  94. data/test/dummy/config/puma.rb +34 -0
  95. data/test/dummy/config/routes.rb +4 -0
  96. data/test/dummy/config/spring.rb +6 -0
  97. data/test/dummy/config/webpack/development.js +3 -0
  98. data/test/dummy/config/webpack/environment.js +3 -0
  99. data/test/dummy/config/webpack/production.js +3 -0
  100. data/test/dummy/config/webpack/test.js +3 -0
  101. data/test/dummy/config/webpacker.yml +65 -0
  102. data/test/dummy/lib/assets/.keep +0 -0
  103. data/test/dummy/log/.keep +0 -0
  104. data/test/dummy/public/404.html +67 -0
  105. data/test/dummy/public/422.html +67 -0
  106. data/test/dummy/public/500.html +66 -0
  107. data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
  108. data/test/dummy/public/apple-touch-icon.png +0 -0
  109. data/test/dummy/public/favicon.ico +0 -0
  110. data/test/frames/frame_request_controller_test.rb +21 -0
  111. data/test/frames/frames_helper_test.rb +15 -0
  112. data/test/native/navigation_controller_test.rb +42 -0
  113. data/test/streams/broadcastable_test.rb +80 -0
  114. data/test/streams/streams_channel_test.rb +105 -0
  115. data/test/streams/streams_controller_test.rb +29 -0
  116. data/test/turbo_test.rb +10 -0
  117. data/turbo-rails.gemspec +16 -0
  118. data/yarn.lock +282 -0
  119. metadata +254 -0
@@ -0,0 +1,127 @@
1
+ # This tag builder is used both for inline controller turbo actions (see <tt>Turbo::Streams::TurboStreamsTagBuilder</tt>) and for
2
+ # turbo stream templates. This object plays together with any normal Ruby you'd run in an ERB template, so you can iterate, like:
3
+ #
4
+ # <% # app/views/postings/destroy.turbo_stream.erb %>
5
+ # <% @postings.each do |posting| %>
6
+ # <%= turbo_stream.remove posting %>
7
+ # <% end %>
8
+ #
9
+ # Or string several separate updates together:
10
+ #
11
+ # <% # app/views/entries/_entry.turbo_stream.erb %>
12
+ # <%= turbo_stream.remove entry %>
13
+ #
14
+ # <%= turbo_stream.append "entries" do %>
15
+ # <% # format ensures that the _entry.html.erb partial is rendered, not _entry.turbo_stream.erb %>
16
+ # <%= render partial: "entries/entry", locals: { entry: entry }, formats: [ :html ] %>
17
+ # <%= end %>
18
+ #
19
+ # Or you can render the HTML that should be part of the update inline:
20
+ #
21
+ # <% # app/views/topics/merges/_merge.turbo_stream.erb %>
22
+ # <%= turbo_stream.append dom_id(topic_merge) do %>
23
+ # <%= link_to topic_merge.topic.name, topic_path(topic_merge.topic) %>
24
+ # <% end %>
25
+ class Turbo::Streams::TagBuilder
26
+ include Turbo::Streams::ActionHelper
27
+
28
+ def initialize(view_context)
29
+ @view_context = view_context
30
+ end
31
+
32
+ # Removes the <tt>target</tt> from the dom. The target can either be a dom id string or an object that responds to
33
+ # <tt>to_key</tt>, which is then called and passed through <tt>ActionView::RecordIdentifier.dom_id</tt> (all Active Records
34
+ # do). Examples:
35
+ #
36
+ # <%= turbo_stream.remove "clearance_5" %>
37
+ # <%= turbo_stream.remove clearance %>
38
+ def remove(target)
39
+ action :remove, target, allow_inferred_rendering: false
40
+ end
41
+
42
+ # Replace the <tt>target</tt> in the dom with the either the <tt>content</tt> passed in, a rendering result determined
43
+ # by the <tt>rendering</tt> keyword arguments, the content in the block, or the rendering of the target as a record. Examples:
44
+ #
45
+ # <%= turbo_stream.replace "clearance_5", "<div id='clearance_5'>Replace the dom target identified by clearance_5</div>" %>
46
+ # <%= turbo_stream.replace clearance %>
47
+ # <%= turbo_stream.replace clearance, partial: "clearances/clearance", locals: { title: "Hello" } %>
48
+ # <%= turbo_stream.replace "clearance_5" do %>
49
+ # <div id='clearance_5'>Replace the dom target identified by clearance_5</div>
50
+ # <% end %>
51
+ def replace(target, content = nil, **rendering, &block)
52
+ action :replace, target, content, **rendering, &block
53
+ end
54
+
55
+ # Update the <tt>target</tt> in the dom with the either the <tt>content</tt> passed in or a rendering result determined
56
+ # by the <tt>rendering</tt> keyword arguments, the content in the block, or the rendering of the target as a record. Examples:
57
+ #
58
+ # <%= turbo_stream.update "clearance_5", "Update the content of the dom target identified by clearance_5" %>
59
+ # <%= turbo_stream.update clearance %>
60
+ # <%= turbo_stream.update clearance, partial: "clearances/unique_clearance", locals: { title: "Hello" } %>
61
+ # <%= turbo_stream.update "clearance_5" do %>
62
+ # Update the content of the dom target identified by clearance_5
63
+ # <% end %>
64
+ def update(target, content = nil, **rendering, &block)
65
+ action :update, target, content, **rendering, &block
66
+ end
67
+
68
+ # Append to the target in the dom identified with <tt>target</tt> either the <tt>content</tt> passed in or a
69
+ # rendering result determined by the <tt>rendering</tt> keyword arguments, the content in the block,
70
+ # or the rendering of the content as a record. Examples:
71
+ #
72
+ # <%= turbo_stream.append "clearances", "<div id='clearance_5'>Append this to .clearances</div>" %>
73
+ # <%= turbo_stream.append "clearances", clearance %>
74
+ # <%= turbo_stream.append "clearances", partial: "clearances/unique_clearance", locals: { clearance: clearance } %>
75
+ # <%= turbo_stream.append "clearances" do %>
76
+ # <div id='clearance_5'>Append this to .clearances</div>
77
+ # <% end %>
78
+ def append(target, content = nil, **rendering, &block)
79
+ action :append, target, content, **rendering, &block
80
+ end
81
+
82
+ # Prepend to the target in the dom identified with <tt>target</tt> either the <tt>content</tt> passed in or a
83
+ # rendering result determined by the <tt>rendering</tt> keyword arguments or the content in the block,
84
+ # or the rendering of the content as a record. Examples:
85
+ #
86
+ # <%= turbo_stream.prepend "clearances", "<div id='clearance_5'>Prepend this to .clearances</div>" %>
87
+ # <%= turbo_stream.prepend "clearances", clearance %>
88
+ # <%= turbo_stream.prepend "clearances", partial: "clearances/unique_clearance", locals: { clearance: clearance } %>
89
+ # <%= turbo_stream.prepend "clearances" do %>
90
+ # <div id='clearance_5'>Prepend this to .clearances</div>
91
+ # <% end %>
92
+ def prepend(target, content = nil, **rendering, &block)
93
+ action :prepend, target, content, **rendering, &block
94
+ end
95
+
96
+ # Send an action of the type <tt>name</tt>. Options described in the concrete methods.
97
+ def action(name, target, content = nil, allow_inferred_rendering: true, **rendering, &block)
98
+ target_name = extract_target_name_from(target)
99
+
100
+ case
101
+ when content
102
+ turbo_stream_action_tag name, target: target_name, template: (render_record(content) if allow_inferred_rendering) || content
103
+ when block_given?
104
+ turbo_stream_action_tag name, target: target_name, template: @view_context.capture(&block)
105
+ when rendering.any?
106
+ turbo_stream_action_tag name, target: target_name, template: @view_context.render(formats: [ :html ], **rendering)
107
+ else
108
+ turbo_stream_action_tag name, target: target_name, template: (render_record(target) if allow_inferred_rendering)
109
+ end
110
+ end
111
+
112
+ private
113
+ def extract_target_name_from(target)
114
+ if target.respond_to?(:to_key)
115
+ ActionView::RecordIdentifier.dom_id(target)
116
+ else
117
+ target
118
+ end
119
+ end
120
+
121
+ def render_record(possible_record)
122
+ if possible_record.respond_to?(:to_partial_path)
123
+ record = possible_record
124
+ @view_context.render(partial: record.to_partial_path, locals: { record.model_name.singular.to_sym => record }, formats: [ :html ])
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,6 @@
1
+ # FIXME: Offer flag to opt out of these native routes
2
+ Rails.application.routes.draw do
3
+ get "recede_historical_location" => "turbo/native/navigation#recede", as: :turbo_recede_historical_location
4
+ get "resume_historical_location" => "turbo/native/navigation#resume", as: :turbo_resume_historical_location
5
+ get "refresh_historical_location" => "turbo/native/navigation#refresh", as: :turbo_refresh_historical_location
6
+ end
@@ -0,0 +1,11 @@
1
+ say "Yield head in application layout for cache helper"
2
+ insert_into_file Rails.root.join("app/views/layouts/application.html.erb").to_s, "\n <%= yield :head %>", before: /\s*<\/head>/
3
+
4
+ say "Add Turbo include tags in application layout"
5
+ insert_into_file Rails.root.join("app/views/layouts/application.html.erb").to_s, "\n <%= turbo_include_tags %>", before: /\s*<\/head>/
6
+
7
+ say "Enable redis in bundle"
8
+ uncomment_lines "Gemfile", %(gem 'redis')
9
+
10
+ say "Switch development cable to use redis"
11
+ gsub_file "config/cable.yml", /development:\n\s+adapter: async/, "development:\n adapter: redis\n url: redis://localhost:6379/1"
@@ -0,0 +1,6 @@
1
+ namespace :turbo do
2
+ desc "Install Turbo into the app"
3
+ task :install do
4
+ system "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{File.expand_path("../install/turbo.rb", __dir__)}"
5
+ end
6
+ end
@@ -0,0 +1,17 @@
1
+ require "turbo/engine"
2
+
3
+ module Turbo
4
+ extend ActiveSupport::Autoload
5
+
6
+ class << self
7
+ attr_writer :signed_stream_verifier_key
8
+
9
+ def signed_stream_verifier
10
+ @signed_stream_verifier ||= ActiveSupport::MessageVerifier.new(signed_stream_verifier_key, digest: "SHA256", serializer: JSON)
11
+ end
12
+
13
+ def signed_stream_verifier_key
14
+ @signed_stream_verifier_key or raise ArgumentError, "Turbo requires a signed_stream_verifier_key"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,65 @@
1
+ require "rails/engine"
2
+ require "turbo/test_assertions"
3
+
4
+ module Turbo
5
+ class Engine < Rails::Engine
6
+ isolate_namespace Turbo
7
+ config.eager_load_namespaces << Turbo
8
+ config.turbo = ActiveSupport::OrderedOptions.new
9
+
10
+ initializer "turbo.assets" do
11
+ Rails.application.config.assets.precompile += %w( turbo )
12
+ end
13
+
14
+ initializer "turbo.helpers" do
15
+ ActiveSupport.on_load(:action_controller_base) do
16
+ include Turbo::Streams::TurboStreamsTagBuilder, Turbo::Frames::FrameRequest, Turbo::Native::Navigation
17
+ helper Turbo::Engine.helpers
18
+ end
19
+ end
20
+
21
+ initializer "turbo.broadcastable" do
22
+ ActiveSupport.on_load(:active_record) do
23
+ include Turbo::Broadcastable
24
+ end
25
+ end
26
+
27
+ initializer "turbo.mimetype" do
28
+ Mime::Type.register "text/html; turbo-stream", :turbo_stream
29
+ end
30
+
31
+ initializer "turbo.renderer" do
32
+ ActiveSupport.on_load(:action_controller) do
33
+ ActionController::Renderers.add :turbo_stream do |turbo_streams_html, options|
34
+ self.content_type = Mime[:turbo_stream] if media_type.nil?
35
+ turbo_streams_html
36
+ end
37
+ end
38
+ end
39
+
40
+ initializer "turbo.signed_stream_verifier_key" do
41
+ Turbo.signed_stream_verifier_key = config.turbo.signed_stream_verifier_key ||
42
+ Rails.application.key_generator.generate_key("turbo/signed_stream_verifier_key")
43
+ end
44
+
45
+ initializer "turbo.test_assertions" do
46
+ ActiveSupport.on_load(:active_support_test_case) do
47
+ include Turbo::TestAssertions
48
+ end
49
+ end
50
+
51
+ initializer "turbo.integration_test_request_encoding" do
52
+ ActiveSupport.on_load(:action_dispatch_integration_test) do
53
+ # Support `as: :turbo_stream`. Public `register_encoder` API is a little too strict.
54
+ class ActionDispatch::RequestEncoder
55
+ class TurboStreamEncoder < IdentityEncoder
56
+ header = [ Mime[:turbo_stream], Mime[:html] ].join(",")
57
+ define_method(:accept_header) { header }
58
+ end
59
+
60
+ @encoders[:turbo_stream] = TurboStreamEncoder.new
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,22 @@
1
+ module Turbo
2
+ module TestAssertions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ # FIXME: Should happen in Rails at a different level
7
+ delegate :dom_id, :dom_class, to: ActionView::RecordIdentifier
8
+ end
9
+
10
+ def assert_turbo_stream(action:, target: nil, &block)
11
+ assert_response :ok
12
+ assert_equal Mime[:turbo_stream], response.media_type
13
+ assert_select %(turbo-stream[action="#{action}"][target="#{target.respond_to?(:to_key) ? dom_id(target) : target}"]), count: 1, &block
14
+ end
15
+
16
+ def assert_no_turbo_stream(action:, target: nil)
17
+ assert_response :ok
18
+ assert_equal Mime[:turbo_stream], response.media_type
19
+ assert_select %(turbo-stream[action="#{action}"][target="#{target.respond_to?(:to_key) ? dom_id(target) : target}"]), count: 0
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module Turbo
2
+ VERSION = "0.5.0"
3
+ end
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@hotwired/turbo-rails",
3
+ "version": "7.0.0-beta.1",
4
+ "description": "The speed of a single-page web application without having to write any JavaScript",
5
+ "module": "app/javascript/turbo/index.js",
6
+ "main": "app/assets/javascripts/turbo.js",
7
+ "files": [
8
+ "app/javascript/turbo"
9
+ ],
10
+ "scripts": {
11
+ "build": "rollup -c"
12
+ },
13
+ "dependencies": {
14
+ "@hotwired/turbo": "^7.0.0-beta.1",
15
+ "@rails/actioncable": "^6.1.0"
16
+ },
17
+ "devDependencies": {
18
+ "@rollup/plugin-node-resolve": "^11.0.1",
19
+ "rollup": "^2.35.1",
20
+ "rollup-plugin-terser": "^7.0.2"
21
+ },
22
+ "license": "MIT",
23
+ "author": "Basecamp, LLC",
24
+ "contributors": [
25
+ "David Heinemeier Hansson <david@basecamp.com>",
26
+ "Javan Makhmali <javan@javan.us>",
27
+ "Sam Stephenson <sstephenson@gmail.com>"
28
+ ],
29
+ "keywords": [
30
+ "hotwire",
31
+ "turbo",
32
+ "rails"
33
+ ],
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/hotwired/turbo-rails.git"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/hotwired/turbo-rails/issues"
40
+ },
41
+ "homepage": "https://github.com/hotwired/turbo-rails"
42
+ }
@@ -0,0 +1,23 @@
1
+ import resolve from "@rollup/plugin-node-resolve"
2
+ import { terser } from "rollup-plugin-terser"
3
+ import pkg from "./package.json"
4
+
5
+ export default {
6
+ input: pkg.module,
7
+ output: {
8
+ file: pkg.main,
9
+ format: "es",
10
+ inlineDynamicImports: true
11
+ },
12
+ plugins: [
13
+ resolve(),
14
+ terser({
15
+ mangle: false,
16
+ compress: false,
17
+ format: {
18
+ beautify: true,
19
+ indent_level: 2
20
+ }
21
+ })
22
+ ]
23
+ }
@@ -0,0 +1,8 @@
1
+ require "turbo_test"
2
+
3
+ class Turbo::DriveHelperTest < ActionDispatch::IntegrationTest
4
+ test "opting out of the default cache" do
5
+ get trays_path
6
+ assert_select "meta", name: "turbo-cache-control", content: "no-cache"
7
+ end
8
+ end
@@ -0,0 +1,18 @@
1
+ {
2
+ "presets": [
3
+ ["env", {
4
+ "modules": false,
5
+ "targets": {
6
+ "browsers": "> 1%",
7
+ "uglify": true
8
+ },
9
+ "useBuiltIns": true
10
+ }]
11
+ ],
12
+
13
+ "plugins": [
14
+ "syntax-dynamic-import",
15
+ "transform-object-rest-spread",
16
+ ["transform-class-properties", { "spec": true }]
17
+ ]
18
+ }
@@ -0,0 +1,3 @@
1
+ *.log
2
+ *.sqlite3
3
+ tmp/*
@@ -0,0 +1,3 @@
1
+ plugins:
2
+ postcss-import: {}
3
+ postcss-cssnext: {}
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative 'config/application'
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,2 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../stylesheets .css
File without changes
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,80 @@
1
+ body {
2
+ background-color: #fff;
3
+ color: #333;
4
+ margin: 33px;
5
+ }
6
+
7
+ body, p, ol, ul, td {
8
+ font-family: verdana, arial, helvetica, sans-serif;
9
+ font-size: 13px;
10
+ line-height: 18px;
11
+ }
12
+
13
+ pre {
14
+ background-color: #eee;
15
+ padding: 10px;
16
+ font-size: 11px;
17
+ }
18
+
19
+ a {
20
+ color: #000;
21
+ }
22
+
23
+ a:visited {
24
+ color: #666;
25
+ }
26
+
27
+ a:hover {
28
+ color: #fff;
29
+ background-color: #000;
30
+ }
31
+
32
+ th {
33
+ padding-bottom: 5px;
34
+ }
35
+
36
+ td {
37
+ padding: 0 5px 7px;
38
+ }
39
+
40
+ div.field,
41
+ div.actions {
42
+ margin-bottom: 10px;
43
+ }
44
+
45
+ #notice {
46
+ color: green;
47
+ }
48
+
49
+ .field_with_errors {
50
+ padding: 2px;
51
+ background-color: red;
52
+ display: table;
53
+ }
54
+
55
+ #error_explanation {
56
+ width: 450px;
57
+ border: 2px solid red;
58
+ padding: 7px 7px 0;
59
+ margin-bottom: 20px;
60
+ background-color: #f0f0f0;
61
+ }
62
+
63
+ #error_explanation h2 {
64
+ text-align: left;
65
+ font-weight: bold;
66
+ padding: 5px 5px 5px 15px;
67
+ font-size: 12px;
68
+ margin: -7px -7px 0;
69
+ background-color: #c00;
70
+ color: #fff;
71
+ }
72
+
73
+ #error_explanation ul li {
74
+ font-size: 12px;
75
+ list-style: square;
76
+ }
77
+
78
+ label {
79
+ display: block;
80
+ }