From 88dc198d71643ce75a5b565026055e71837dc99e Mon Sep 17 00:00:00 2001 From: Noah Over Date: Mon, 23 May 2022 12:25:51 -0400 Subject: [PATCH] [#107] Allow users to create custom themes for their stories --- app/controllers/adventures_controller.rb | 8 +- app/controllers/custom_themes_controller.rb | 105 +++++++++++ app/javascript/packs/adventure-form.tsx | 12 ++ app/javascript/packs/application.tsx | 1 + app/javascript/packs/custom-theme-form.tsx | 28 +++ app/javascript/packs/custom-theme-preview.tsx | 40 ++++ .../src/components/themes/DesertTheme.css | 26 ++- .../src/css/default/AccountForm.css | 4 + .../src/css/default/CustomThemeForm.css | 3 + app/models/adventure.rb | 12 +- app/models/custom_theme.rb | 73 ++++++++ app/models/user.rb | 1 + app/views/adventures/show.html.erb | 4 + app/views/custom_themes/_form.html.erb | 107 +++++++++++ app/views/custom_themes/edit.html.erb | 9 + app/views/custom_themes/index.html.erb | 31 ++++ app/views/custom_themes/new.html.erb | 9 + app/views/custom_themes/show.html.erb | 16 ++ .../layouts/custom_theme_preview.html.erb | 12 ++ app/views/shared/_adventure_form.html.erb | 17 +- app/views/shared/_custom_styles.html.erb | 171 ++++++++++++++++++ app/views/shared/_header.html.erb | 1 + config/routes.rb | 2 + .../20220523135918_create_custom_themes.rb | 30 +++ ...0220629191950_add_slug_to_custom_themes.rb | 5 + ...82837_add_custom_theme_id_to_adventures.rb | 8 + db/schema.rb | 32 +++- 27 files changed, 756 insertions(+), 11 deletions(-) create mode 100644 app/controllers/custom_themes_controller.rb create mode 100644 app/javascript/packs/adventure-form.tsx create mode 100644 app/javascript/packs/custom-theme-form.tsx create mode 100644 app/javascript/packs/custom-theme-preview.tsx create mode 100644 app/javascript/src/css/default/CustomThemeForm.css create mode 100644 app/models/custom_theme.rb create mode 100644 app/views/custom_themes/_form.html.erb create mode 100644 app/views/custom_themes/edit.html.erb create mode 100644 app/views/custom_themes/index.html.erb create mode 100644 app/views/custom_themes/new.html.erb create mode 100644 app/views/custom_themes/show.html.erb create mode 100644 app/views/layouts/custom_theme_preview.html.erb create mode 100644 app/views/shared/_custom_styles.html.erb create mode 100644 db/migrate/20220523135918_create_custom_themes.rb create mode 100644 db/migrate/20220629191950_add_slug_to_custom_themes.rb create mode 100644 db/migrate/20220701182837_add_custom_theme_id_to_adventures.rb diff --git a/app/controllers/adventures_controller.rb b/app/controllers/adventures_controller.rb index 752ce98c..f3de55d6 100644 --- a/app/controllers/adventures_controller.rb +++ b/app/controllers/adventures_controller.rb @@ -138,6 +138,11 @@ def set_adventure @adventure = Adventure.find_by_slug!(params[:id]) end + def custom_theme + @adventure.custom_theme + end + helper_method :custom_theme + def adventure_params params.require(:adventure).permit( :title, @@ -152,7 +157,8 @@ def adventure_params :back_button, :show_source, :character_card, - :archived + :archived, + :custom_theme_id ) end diff --git a/app/controllers/custom_themes_controller.rb b/app/controllers/custom_themes_controller.rb new file mode 100644 index 00000000..6998a8e6 --- /dev/null +++ b/app/controllers/custom_themes_controller.rb @@ -0,0 +1,105 @@ +class CustomThemesController < ApplicationController + + def index + if !current_user + flash[:alert] = "You must be logged in to view your custom themes." + return redirect_to new_user_session_path + end + + @custom_themes = current_user.custom_themes + end + + def show + if custom_theme.user != current_user + flash[:alert] = "You can't view that custom theme." + return redirect_to root_url + end + + @adventure = Adventure.find_by_slug!('lemonade-stand') + render layout: 'custom_theme_preview' + end + + def new + if !current_user + flash[:alert] = "You must be logged in to create a custom theme." + return redirect_to new_user_session_path + end + + @custom_theme = CustomTheme.new + end + + def create + if !current_user + flash[:alert] = "You must be logged in to create a custom theme." + return redirect_to new_user_session_path + end + + @custom_theme = CustomTheme.new(custom_theme_params) + custom_theme.user = current_user + + if custom_theme.save + redirect_to custom_theme + else + display_errors(:create) + render :new + end + end + + def edit + if custom_theme.user != current_user + flash[:alert] = "You can't modify that custom theme." + return redirect_to root_url + end + end + + def update + if custom_theme.user != current_user + flash[:alert] = "You can't modify that custom theme." + return redirect_to root_url + end + + if custom_theme.update(custom_theme_params) + redirect_to custom_theme_path(custom_theme) + else + display_errors(:update) + render :edit + end + end + + private + + def custom_theme + @custom_theme ||= CustomTheme.find_by_slug!(params[:id]) + end + helper_method :custom_theme + + def custom_theme_params + params.require(:custom_theme).permit( + :title, + :background_color, + :border_color, + :intro_image, + :scene_image, + :end_image, + :header_font_family, + :header_font_color, + :body_font_family, + :body_font_color, + :choice_font_family, + :choice_font_color, + :button_color, + :button_font_family, + :button_font_color + ) + end + + def display_errors(method) + # the slug validation technically "runs" on create, even though it is not a field + if method == :create + custom_theme.errors.delete(:slug) + end + if custom_theme.errors.any? + flash[:alert] = custom_theme.errors.full_messages.join(", ") + end + end +end diff --git a/app/javascript/packs/adventure-form.tsx b/app/javascript/packs/adventure-form.tsx new file mode 100644 index 00000000..eaaf620a --- /dev/null +++ b/app/javascript/packs/adventure-form.tsx @@ -0,0 +1,12 @@ +const customThemeSection = document.getElementById("custom_theme_section"); +const themeField = (document.getElementById("adventure_theme")) as HTMLSelectElement; + +if (themeField && customThemeSection) { + themeField.addEventListener("change", function() { + if (themeField.value == "custom") { + customThemeSection.classList.remove("no-display"); + } else { + customThemeSection.classList.add("no-display"); + } + }); +} diff --git a/app/javascript/packs/application.tsx b/app/javascript/packs/application.tsx index c961cdac..1ea88ec2 100644 --- a/app/javascript/packs/application.tsx +++ b/app/javascript/packs/application.tsx @@ -4,6 +4,7 @@ import '../src/button.css' import '../src/modal.css' import '../src/css/default/AccountForm.css' import '../src/css/default/AdventureList.css' +import '../src/css/default/CustomThemeForm.css' import '../src/css/default/StoryIndex.css' import '../src/css/default/ThemeDark.css' import '../src/css/default/FormattingHelp.css' diff --git a/app/javascript/packs/custom-theme-form.tsx b/app/javascript/packs/custom-theme-form.tsx new file mode 100644 index 00000000..2e1eacb3 --- /dev/null +++ b/app/javascript/packs/custom-theme-form.tsx @@ -0,0 +1,28 @@ +const headerFontField = (document.getElementById("custom_theme_header_font_family")) as HTMLSelectElement; +const bodyFontField = (document.getElementById("custom_theme_body_font_family")) as HTMLSelectElement; +const choiceFontField = (document.getElementById("custom_theme_choice_font_family")) as HTMLSelectElement; +const buttonFontField = (document.getElementById("custom_theme_button_font_family")) as HTMLSelectElement; + +if (headerFontField) { + headerFontField.addEventListener("change", function() { + headerFontField.style.fontFamily = headerFontField.value; + }); +} + +if (bodyFontField) { + bodyFontField.addEventListener("change", function() { + bodyFontField.style.fontFamily = bodyFontField.value; + }); +} + +if (choiceFontField) { + choiceFontField.addEventListener("change", function() { + choiceFontField.style.fontFamily = choiceFontField.value; + }); +} + +if (buttonFontField) { + buttonFontField.addEventListener("change", function() { + buttonFontField.style.fontFamily = buttonFontField.value; + }); +} diff --git a/app/javascript/packs/custom-theme-preview.tsx b/app/javascript/packs/custom-theme-preview.tsx new file mode 100644 index 00000000..f5dd4d78 --- /dev/null +++ b/app/javascript/packs/custom-theme-preview.tsx @@ -0,0 +1,40 @@ +// Important: Order matters here. Otherwise our flow chart's layout +// calculations fail + +import '../src/global.css' +import '../src/button.css' +import '../src/modal.css' + +import * as React from 'react' +import * as ReactDOM from 'react-dom' + +import Player from '../src/components/Player' +import { load } from '../src/persistance' + +const slug = SEED.slug + +async function render() { + const content = await load(slug) + const customThemePreview = document.getElementById('custom-theme-preview') + + if (content) { + ReactDOM.render( + , + customThemePreview + ) + } +} + +render() diff --git a/app/javascript/src/components/themes/DesertTheme.css b/app/javascript/src/components/themes/DesertTheme.css index af52e72a..c751d029 100644 --- a/app/javascript/src/components/themes/DesertTheme.css +++ b/app/javascript/src/components/themes/DesertTheme.css @@ -44,24 +44,36 @@ body:after { } .DesertTheme .PlayerIntro { - background: url('../../images/desert-theme-intro-background.jpg') 0 0 no-repeat / - cover; + background-image: url('../../images/desert-theme-intro-background.jpg'); + background-position: 0 0; + background-repeat: no-repeat; + background-size: cover; + margin-top: 0; + margin-bottom: 0; } .DesertTheme .PlayerScene { - background: url('../../images/desert-theme-scene-background.jpg') 0 0 no-repeat / - cover; + background-image: url('../../images/desert-theme-scene-background.jpg'); + background-position: 0 0; + background-repeat: no-repeat; + background-size: cover; + margin-top: 0; + margin-bottom: 30px; } .DesertTheme .PlayerEnd { - background: url('../../images/desert-theme-end-background.jpg') 50% 50% no-repeat / - cover; + background-image: url('../../images/desert-theme-end-background.jpg'); + background-position: 50% 50%; + background-repeat: no-repeat; + background-size: cover; + margin-top: 0; + margin-bottom: 0; text-align: center; } .DesertTheme .PlayerForeground { max-width: 1184px; - margin: 0 auto; + margin: auto auto; padding: 24px 36px; width: 100%; } diff --git a/app/javascript/src/css/default/AccountForm.css b/app/javascript/src/css/default/AccountForm.css index 03fd8ada..9e2f94f1 100644 --- a/app/javascript/src/css/default/AccountForm.css +++ b/app/javascript/src/css/default/AccountForm.css @@ -69,3 +69,7 @@ display: block; color: white; } + +.no-display { + display: none; +} diff --git a/app/javascript/src/css/default/CustomThemeForm.css b/app/javascript/src/css/default/CustomThemeForm.css new file mode 100644 index 00000000..e3a7debc --- /dev/null +++ b/app/javascript/src/css/default/CustomThemeForm.css @@ -0,0 +1,3 @@ +.CustomThemeForm select { + font-size: 20px; +} diff --git a/app/models/adventure.rb b/app/models/adventure.rb index 49a3ba49..6a640006 100644 --- a/app/models/adventure.rb +++ b/app/models/adventure.rb @@ -5,7 +5,8 @@ class Adventure < ApplicationRecord "Light" => "light", "Viget" => "viget", "Space" => "space", - "Desert" => "desert" + "Desert" => "desert", + "Custom" => "custom", } FEATURE_GROUPS = [ @@ -17,6 +18,7 @@ class Adventure < ApplicationRecord slug_from :slug_source belongs_to :user, optional: true + belongs_to :custom_theme, optional: true validates :title, :theme, presence: true @@ -24,6 +26,8 @@ class Adventure < ApplicationRecord validates :age_limit, numericality: { only_integer: true }, presence: true, if: :has_age_limit + validate :custom_theme_set + def to_s title end @@ -52,4 +56,10 @@ def editable_by?(current_user) def slug_source title end + + def custom_theme_set + if theme == 'custom' && custom_theme.nil? + errors.add(:custom_theme, "required when theme is set to 'Custom'") + end + end end diff --git a/app/models/custom_theme.rb b/app/models/custom_theme.rb new file mode 100644 index 00000000..8a820824 --- /dev/null +++ b/app/models/custom_theme.rb @@ -0,0 +1,73 @@ +class CustomTheme < ApplicationRecord + include Sluggable + + FONTS = [ + ["American Typewriter", "American Typewriter, serif"], + ["Andale Mono", "Andale Mono, monospace"], + ["Apple Chancery", "Apple Chancery, cursive"], + ["Arial", "Arial, sans-serif"], + ["Arial Narrow", "Arial Narrow, sans-serif"], + ["Avantgarde", "Avantgarde, TeX Gyre Adventor, URW Gothic L, sans-serif"], + ["Blippo", "Blippo, fantasy"], + ["Bookman", "Bookman, URW Bookman L, serif"], + ["Bradley Hand", "Bradley Hand, cursive"], + ["Brush Script MT", "Brush Script MT, Brush Script Std, cursive"], + ["Chalkduster", "Chalkduster, fantasy"], + ["Comic Sans MS", "Comic Sans MS, Comic Sans, cursive"], + ["Courier", "Courier, monospace"], + ["Courier New", "Courier New, monospace"], + ["Cursive", "cursive"], + ["DejaVu Sans Mono", "DejaVu Sans Mono, monospace"], + ["Didot", "Didot, serif"], + ["Fantasy", "Fantasy"], + ["FreeMono", "FreeMono, monospace"], + ["Georgia", "Georgia, serif"], + ["Gill Sans", "Gill Sans, sans-serif"], + ["Helvetica", "Helvetica, sans-serif"], + ["Impact", "Impact, fantasy"], + ["Jazz LET", "Jazz LET, fantasy"], + ["Luminari", "Luminari, fantasy"], + ["Marker Felt", "Marker Felt, fantasy"], + ["Monospace", "monospace"], + ["New Century Schoolbook", "New Century Schoolbook, TeX Gyre Schola, serif"], + ["Noto Sans", "Noto Sans, sans-serif"], + ["OCR A Std", "OCR A Std, monospace"], + ["Optima", "Optima, sans-serif"], + ["Palatino", "Palatino, URW Palladio L, serif"], + ["Sans-Serif", "sans-serif"], + ["Serif", "serif"], + ["Snell Roundhand", "Snell Roundhand, cursive"], + ["Stencil Std", "Stencil Std, fantasy"], + ["Times", "Times, Times New Roman, serif"], + ["Trattatello", "Trattatello, fantasy"], + ["Trebuchet MS", "Trebuchet MS, sans-serif"], + ["URW Chancery L", "URW Chancery L, cursive"], + ["Verdana", "Verdana, sans-serif"] + ] + + has_many :adventures + + slug_from :slug_source + + dragonfly_accessor :intro_image + dragonfly_accessor :scene_image + dragonfly_accessor :end_image + + belongs_to :user + + validates :title, presence: true + + def to_s + title + end + + def to_param + slug + end + + private + + def slug_source + title + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 873d0a89..4c7a091b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,6 +3,7 @@ class User < ApplicationRecord :recoverable, :rememberable, :trackable, :validatable has_many :adventures, dependent: :destroy + has_many :custom_themes, dependent: :destroy def is_admin? email.in? [ diff --git a/app/views/adventures/show.html.erb b/app/views/adventures/show.html.erb index 2c4bf2d9..31bc9dcb 100644 --- a/app/views/adventures/show.html.erb +++ b/app/views/adventures/show.html.erb @@ -21,3 +21,7 @@ showSource: <%= @adventure.show_source? %> } + +<% if @adventure.theme === 'custom' %> + <%= render "shared/custom_styles" %> +<% end %> diff --git a/app/views/custom_themes/_form.html.erb b/app/views/custom_themes/_form.html.erb new file mode 100644 index 00000000..2eb39dfd --- /dev/null +++ b/app/views/custom_themes/_form.html.erb @@ -0,0 +1,107 @@ +<%= javascript_pack_tag "custom-theme-form", async: true, defer: true %> + +<%= form_for custom_theme, html: { class: "CustomThemeForm" } do |f| %> +
+ <%= f.label :title, "Title" %> + <%= f.text_field :title %> +
+ +
+ <%= f.label :background_color, "Background Color" %> + <%= f.color_field :background_color %> +
+ +
+ <%= f.label :border_color, "Border Color" %> + <%= f.color_field :border_color %> +
+ +
+ <%= f.label :intro_image, "Intro Photo Background" %> + <% if custom_theme.intro_image %> + <%= image_tag custom_theme.intro_image.thumb('400x200#').url %>
+ <% end %> + <%= f.file_field :intro_image, accept: "image/gif,image/jpeg,image/png" %> +
+ +
+ <%= f.label :scene_image, "Scene Photo Background" %> + <% if custom_theme.scene_image %> + <%= image_tag custom_theme.scene_image.thumb('400x200#').url %>
+ <% end %> + <%= f.file_field :scene_image, accept: "image/gif,image/jpeg,image/png" %> +
+ +
+ <%= f.label :end_image, "Ending Photo Background" %> + <% if custom_theme.end_image %> + <%= image_tag custom_theme.end_image.thumb('400x200#').url %>
+ <% end %> + <%= f.file_field :end_image, accept: "image/gif,image/jpeg,image/png" %> +
+ +
+ <%= f.label :header_font_family, "Header Font" %> + <% if custom_theme.header_font_family %> + <%= f.select :header_font_family, options_for_select(CustomTheme::FONTS, custom_theme.header_font_family), { include_blank: true }, { style: "font-family:#{custom_theme.header_font_family}" } %> + <% else %> + <%= f.select :header_font_family, options_for_select(CustomTheme::FONTS), include_blank: true %> + <% end %> +
+ +
+ <%= f.label :header_font_color, "Header Text Color" %> + <%= f.color_field :header_font_color %> +
+ +
+ <%= f.label :body_font_family, "Body Font" %> + <% if custom_theme.header_font_family %> + <%= f.select :body_font_family, options_for_select(CustomTheme::FONTS, custom_theme.body_font_family), { include_blank: true }, { style: "font-family:#{custom_theme.body_font_family}" } %> + <% else %> + <%= f.select :body_font_family, options_for_select(CustomTheme::FONTS), include_blank: true %> + <% end %> +
+ +
+ <%= f.label :body_font_color, "Body Text Color" %> + <%= f.color_field :body_font_color %> +
+ +
+ <%= f.label :choice_font_family, "Choice Font" %> + <% if custom_theme.choice_font_family %> + <%= f.select :choice_font_family, options_for_select(CustomTheme::FONTS, custom_theme.choice_font_family), { include_blank: true }, { style: "font-family:#{custom_theme.choice_font_family}" } %> + <% else %> + <%= f.select :choice_font_family, options_for_select(CustomTheme::FONTS), include_blank: true %> + <% end %> +
+ +
+ <%= f.label :choice_font_color, "Choice Text Color" %> + <%= f.color_field :choice_font_color %> +
+ +
+ <%= f.label :button_color, "Button Color" %> + <%= f.color_field :button_color %> +
+ +
+ <%= f.label :button_font_family, "Button Font" %> + <% if custom_theme.button_font_family %> + <%= f.select :button_font_family, options_for_select(CustomTheme::FONTS, custom_theme.button_font_family), { include_blank: true }, { style: "font-family:#{custom_theme.button_font_family}" } %> + <% else %> + <%= f.select :button_font_family, options_for_select(CustomTheme::FONTS), include_blank: true %> + <% end %> +
+ +
+ <%= f.label :button_font_color, "Button Text Color" %> + <%= f.color_field :button_font_color %> +
+ +
+ +
+<% end %> diff --git a/app/views/custom_themes/edit.html.erb b/app/views/custom_themes/edit.html.erb new file mode 100644 index 00000000..8ae41877 --- /dev/null +++ b/app/views/custom_themes/edit.html.erb @@ -0,0 +1,9 @@ +
+

<%= custom_theme %>

+ + <%= render "form", custom_theme: custom_theme, is_update: true %> + +
+ <%= link_to 'Back', custom_theme_path(custom_theme) %> +
+
diff --git a/app/views/custom_themes/index.html.erb b/app/views/custom_themes/index.html.erb new file mode 100644 index 00000000..b4dfb51e --- /dev/null +++ b/app/views/custom_themes/index.html.erb @@ -0,0 +1,31 @@ +
+

My Custom Themes

+ + <% if @custom_themes.size <= 0 %> +

You have no custom themes.

+ <% end %> + +

+ <%= link_to "Create a Custom Theme", new_custom_theme_path, class: "SlantButton" %> +

+ +
+ <% @custom_themes.each do |custom_theme| %> +
+ <%= link_to custom_theme do %> +
+ +
+ <% end %> + +
+ <%= link_to custom_theme_path(custom_theme) do %> +
+ <%= custom_theme %> +
+ <% end %> +
+
+ <% end %> +
+
diff --git a/app/views/custom_themes/new.html.erb b/app/views/custom_themes/new.html.erb new file mode 100644 index 00000000..8031f334 --- /dev/null +++ b/app/views/custom_themes/new.html.erb @@ -0,0 +1,9 @@ +
+

Create a
Custom Theme

+ + <%= render "form", custom_theme: custom_theme, is_update: false %> + +
+ <%= link_to 'Back', custom_themes_path %> +
+
diff --git a/app/views/custom_themes/show.html.erb b/app/views/custom_themes/show.html.erb new file mode 100644 index 00000000..f5f91017 --- /dev/null +++ b/app/views/custom_themes/show.html.erb @@ -0,0 +1,16 @@ +<% content_for :theme, "CustomTheme" %> + +
+ <%= link_to 'Edit', [:edit, custom_theme], class: "SlantButton" %> +
+ +
+ + + +<%= render "shared/custom_styles", custom_theme: custom_theme %> diff --git a/app/views/layouts/custom_theme_preview.html.erb b/app/views/layouts/custom_theme_preview.html.erb new file mode 100644 index 00000000..a7a7c859 --- /dev/null +++ b/app/views/layouts/custom_theme_preview.html.erb @@ -0,0 +1,12 @@ + + + + <%= render "shared/head_tags" %> + + + <%= yield %> + + <%= stylesheet_pack_tag "player" %> + <%= javascript_pack_tag "custom-theme-preview", async: true, defer: true %> + + diff --git a/app/views/shared/_adventure_form.html.erb b/app/views/shared/_adventure_form.html.erb index 52706519..f94be175 100644 --- a/app/views/shared/_adventure_form.html.erb +++ b/app/views/shared/_adventure_form.html.erb @@ -1,3 +1,5 @@ +<%= javascript_pack_tag "adventure-form", async: true, defer: true %> + <%= form_for @adventure do |f| %>
<%= f.label :title, "What's your title?" %> @@ -18,7 +20,20 @@
<%= f.label :Theme %> - <%= f.select :theme, options_for_select(Adventure::THEMES) %> + <% if @adventure.theme %> + <%= f.select :theme, options_for_select(Adventure::THEMES, @adventure.theme) %> + <% else %> + <%= f.select :theme, options_for_select(Adventure::THEMES) %> + <% end %> +
+ +
+ <%= f.label :custom_theme_id, "Custom Theme" %> + <% if @adventure.custom_theme %> + <%= f.select :custom_theme_id, options_for_select(CustomTheme.where(user_id: current_user.id).map { |ct| [ct.title, ct.id] }, @adventure.custom_theme_id)%> + <% else %> + <%= f.select :custom_theme_id, options_for_select(CustomTheme.where(user_id: current_user.id).map { |ct| [ct.title, ct.id] }) %> + <% end %>
<% if correct_user %> diff --git a/app/views/shared/_custom_styles.html.erb b/app/views/shared/_custom_styles.html.erb new file mode 100644 index 00000000..3b84f4cd --- /dev/null +++ b/app/views/shared/_custom_styles.html.erb @@ -0,0 +1,171 @@ + diff --git a/app/views/shared/_header.html.erb b/app/views/shared/_header.html.erb index 7c95779d..bda9a0fc 100644 --- a/app/views/shared/_header.html.erb +++ b/app/views/shared/_header.html.erb @@ -16,6 +16,7 @@ height="0" width="0" style="display:none;visibility:hidden">
<% if current_user.present? %> <%= link_to "My Stories", my_adventures_path %> + <%= link_to "My Themes", custom_themes_path %> <%= link_to "Account", edit_user_registration_path %> <%= link_to "Log Out", destroy_user_session_path %> <% else %> diff --git a/config/routes.rb b/config/routes.rb index 91f1f74e..432638b5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -28,6 +28,8 @@ get "unsubscribe", to: "unsubscribes#new", as: :new_unsubscribe resources :unsubscribes, only: [:create] + resources :custom_themes, path: "/custom_themes" + # Keep this block at the bottom so the "/:id adventures#show" # doesn't catch other routes resources :adventures, path: "/" do diff --git a/db/migrate/20220523135918_create_custom_themes.rb b/db/migrate/20220523135918_create_custom_themes.rb new file mode 100644 index 00000000..5d386d4e --- /dev/null +++ b/db/migrate/20220523135918_create_custom_themes.rb @@ -0,0 +1,30 @@ +class CreateCustomThemes < ActiveRecord::Migration[5.2] + def change + create_table :custom_themes do |t| + t.string :title, null: false + t.string :background_color + t.string :border_color + t.string :intro_image_uid + t.string :intro_image_name + t.string :scene_image_uid + t.string :scene_image_name + t.string :end_image_name + t.string :end_image_uid + t.string :header_font_family + t.string :header_font_color + t.string :body_font_family + t.string :body_font_color + t.string :choice_font_family + t.string :choice_font_color + t.string :button_color + t.string :button_font_family + t.string :button_font_color + t.integer :user_id, null: false + + t.timestamps + end + + add_index :custom_themes, :user_id + add_foreign_key :custom_themes, :users, on_delete: :cascade + end +end diff --git a/db/migrate/20220629191950_add_slug_to_custom_themes.rb b/db/migrate/20220629191950_add_slug_to_custom_themes.rb new file mode 100644 index 00000000..b1aa208a --- /dev/null +++ b/db/migrate/20220629191950_add_slug_to_custom_themes.rb @@ -0,0 +1,5 @@ +class AddSlugToCustomThemes < ActiveRecord::Migration[5.2] + def change + add_column :custom_themes, :slug, :string, null: false + end +end diff --git a/db/migrate/20220701182837_add_custom_theme_id_to_adventures.rb b/db/migrate/20220701182837_add_custom_theme_id_to_adventures.rb new file mode 100644 index 00000000..5a7ba562 --- /dev/null +++ b/db/migrate/20220701182837_add_custom_theme_id_to_adventures.rb @@ -0,0 +1,8 @@ +class AddCustomThemeIdToAdventures < ActiveRecord::Migration[5.2] + def change + add_column :adventures, :custom_theme_id, :integer + + add_index :adventures, :custom_theme_id + add_foreign_key :adventures, :custom_themes, on_delete: :cascade + end +end diff --git a/db/schema.rb b/db/schema.rb index 2c847896..fdab80ae 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2022_05_19_134603) do +ActiveRecord::Schema.define(version: 2022_07_01_182837) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -34,6 +34,8 @@ t.boolean "back_button", default: false, null: false t.boolean "character_card", default: true, null: false t.boolean "archived", default: false, null: false + t.integer "custom_theme_id" + t.index ["custom_theme_id"], name: "index_adventures_on_custom_theme_id" t.index ["user_id"], name: "index_adventures_on_user_id" end @@ -43,6 +45,32 @@ t.index ["meta_id"], name: "index_audio_tracks_on_meta_id", unique: true end + create_table "custom_themes", force: :cascade do |t| + t.string "title", null: false + t.string "background_color" + t.string "border_color" + t.string "intro_image_uid" + t.string "intro_image_name" + t.string "scene_image_uid" + t.string "scene_image_name" + t.string "end_image_name" + t.string "end_image_uid" + t.string "header_font_family" + t.string "header_font_color" + t.string "body_font_family" + t.string "body_font_color" + t.string "choice_font_family" + t.string "choice_font_color" + t.string "button_color" + t.string "button_font_family" + t.string "button_font_color" + t.integer "user_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "slug", null: false + t.index ["user_id"], name: "index_custom_themes_on_user_id" + end + create_table "photos", force: :cascade do |t| t.string "meta_id" t.string "image_name" @@ -87,5 +115,7 @@ t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end + add_foreign_key "adventures", "custom_themes", on_delete: :cascade add_foreign_key "adventures", "users", on_delete: :cascade + add_foreign_key "custom_themes", "users", on_delete: :cascade end