Compare commits
7 Commits
b81b78d13a
...
52022ce65e
Author | SHA1 | Date |
---|---|---|
Trevor Vallender | 52022ce65e | |
Trevor Vallender | 79e3e79b12 | |
Trevor Vallender | d4b982ea16 | |
Trevor Vallender | c870e373bc | |
Trevor Vallender | 032c18d05d | |
Trevor Vallender | e62578dc0d | |
Trevor Vallender | 202f827d57 |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -5,6 +5,12 @@
|
||||||
--header-color: #15345b;
|
--header-color: #15345b;
|
||||||
--header-text-color: #fff;
|
--header-text-color: #fff;
|
||||||
--header-height: 200px;
|
--header-height: 200px;
|
||||||
|
--footer-height: 150px;
|
||||||
|
|
||||||
|
--shadow-color: #999;
|
||||||
|
--light-shadow-color: #CCC;
|
||||||
|
--secondary-text-color: #777;
|
||||||
|
|
||||||
|
|
||||||
--shadow-color: #999;
|
--shadow-color: #999;
|
||||||
--light-shadow-color: #CCC;
|
--light-shadow-color: #CCC;
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
body {
|
body {
|
||||||
font-family: Roboto, sans-serif;
|
font-family: sans-serif;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ main {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 1em 1em 4em 1em;
|
padding: 1em 1em 4em 1em;
|
||||||
min-height: calc(100vh - var(--header-height));
|
min-height: calc(100vh - var(--header-height) - var(--footer-height));
|
||||||
}
|
}
|
||||||
|
|
||||||
@media(min-width: 800px) {
|
@media(min-width: 800px) {
|
||||||
|
@ -58,6 +58,11 @@ header {
|
||||||
header h1 {
|
header h1 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
min-width: 400px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header h1 a:link, header h1 a:visited {
|
header h1 a:link, header h1 a:visited {
|
||||||
|
@ -166,6 +171,7 @@ footer {
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
font-size: .8em;
|
font-size: .8em;
|
||||||
|
height: var(--footer-height);
|
||||||
a:link, a:visited {
|
a:link, a:visited {
|
||||||
color: var(--header-text-color);
|
color: var(--header-text-color);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
@ -175,3 +181,7 @@ footer {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subsections {
|
||||||
|
margin: .5em;
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ class CharacterSheetSectionsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
@templates = Template.game_system(@character.game_system)
|
||||||
if params[:parent_section_id].present?
|
if params[:parent_section_id].present?
|
||||||
@parent_section = @character.character_sheet_sections.find_by(id: params[:parent_section_id])
|
@parent_section = @character.character_sheet_sections.find_by(id: params[:parent_section_id])
|
||||||
end
|
end
|
||||||
|
@ -22,7 +23,16 @@ class CharacterSheetSectionsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@section = @character.character_sheet_sections.new(character_sheet_section_params)
|
@templates = Template.game_system(@character.game_system)
|
||||||
|
if params[:template_id].present?
|
||||||
|
@section = CharacterSheetSection.new_from_template(
|
||||||
|
template: Template.find(params[:template_id]),
|
||||||
|
params: character_sheet_section_params,
|
||||||
|
character: @character,
|
||||||
|
)
|
||||||
|
else
|
||||||
|
@section = @character.character_sheet_sections.new(character_sheet_section_params)
|
||||||
|
end
|
||||||
@editable = true
|
@editable = true
|
||||||
unless @section.save
|
unless @section.save
|
||||||
@parent_section = @section.parent_section
|
@parent_section = @section.parent_section
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class TemplatesController < ApplicationController
|
||||||
|
before_action :set_character_sheet_section, only: [ :new ]
|
||||||
|
before_action :set_template, only: [ :show ]
|
||||||
|
|
||||||
|
def new
|
||||||
|
@template = Template.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@section = CharacterSheetSection.find(template_params[:character_sheet_section_id])
|
||||||
|
@template = TemplateBuilder.create!(
|
||||||
|
name: template_params[:name],
|
||||||
|
from: @section,
|
||||||
|
game_system: GameSystem.find(template_params[:game_system_id]),
|
||||||
|
)
|
||||||
|
if @template.persisted?
|
||||||
|
redirect_to @template
|
||||||
|
else
|
||||||
|
flash.now[:alert] = t(".error")
|
||||||
|
render :new, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_template
|
||||||
|
@template = Template.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_character_sheet_section
|
||||||
|
@section = CharacterSheetSection.find(params[:character_sheet_section_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def template_params
|
||||||
|
params.require(:template).permit(
|
||||||
|
:name,
|
||||||
|
:character_sheet_section_id,
|
||||||
|
:game_system_id,
|
||||||
|
:klass,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
|
@ -35,7 +35,7 @@ class CharacterSheetFeature < ApplicationRecord
|
||||||
def set_order_index
|
def set_order_index
|
||||||
return if order_index.present?
|
return if order_index.present?
|
||||||
|
|
||||||
if character_sheet_section.character_sheet_features.any?
|
if character_sheet_section.character_sheet_features.count > 1
|
||||||
self.order_index = character_sheet_section.character_sheet_features.order(:order_index).last.order_index + 1
|
self.order_index = character_sheet_section.character_sheet_features.order(:order_index).last.order_index + 1
|
||||||
else
|
else
|
||||||
self.order_index = 1
|
self.order_index = 1
|
||||||
|
|
|
@ -18,6 +18,13 @@ class CharacterSheetSection < ApplicationRecord
|
||||||
|
|
||||||
scope :top_level, -> { where.missing(:parent_section) }
|
scope :top_level, -> { where.missing(:parent_section) }
|
||||||
|
|
||||||
|
def self.new_from_template(template:, character:, params:)
|
||||||
|
section = CharacterSheetSection.deserialize(JSON.parse(template.content))
|
||||||
|
section.assign_attributes(params)
|
||||||
|
section.character = character
|
||||||
|
section
|
||||||
|
end
|
||||||
|
|
||||||
def lowest_order_index
|
def lowest_order_index
|
||||||
character_sheet_features.minimum(:order_index) || 1
|
character_sheet_features.minimum(:order_index) || 1
|
||||||
end
|
end
|
||||||
|
@ -25,4 +32,22 @@ class CharacterSheetSection < ApplicationRecord
|
||||||
def highest_order_index
|
def highest_order_index
|
||||||
character_sheet_features.maximum(:order_index) || 1
|
character_sheet_features.maximum(:order_index) || 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.deserialize(h)
|
||||||
|
section = new
|
||||||
|
|
||||||
|
h["character_sheet_subsections"].each do |sub|
|
||||||
|
section.character_sheet_subsections.deserialize(sub)
|
||||||
|
end
|
||||||
|
|
||||||
|
h["stats"].each do |stat|
|
||||||
|
section.stats.build(stat)
|
||||||
|
end
|
||||||
|
|
||||||
|
h["text_fields"].each do |text_field|
|
||||||
|
section.text_fields.build(text_field)
|
||||||
|
end
|
||||||
|
|
||||||
|
section
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Template < ApplicationRecord
|
||||||
|
belongs_to :game_system
|
||||||
|
|
||||||
|
validates :name, presence: true,
|
||||||
|
uniqueness: { scope: :game_system_id },
|
||||||
|
length: { maximum: 200 }
|
||||||
|
validates :content, presence: true
|
||||||
|
validates :klass, presence: true,
|
||||||
|
length: { maximum: 200 }
|
||||||
|
|
||||||
|
scope :game_system, ->(game_system) { where(game_system:) }
|
||||||
|
end
|
|
@ -0,0 +1,40 @@
|
||||||
|
# frozen_string_literaL: true
|
||||||
|
|
||||||
|
class TemplateBuilder
|
||||||
|
class << self
|
||||||
|
def create!(name:, from:, game_system:)
|
||||||
|
Template.create(
|
||||||
|
name:,
|
||||||
|
klass: from.class.name,
|
||||||
|
game_system:,
|
||||||
|
content: serialize_character_sheet_section(from),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def serialize_character_sheet_section(section)
|
||||||
|
always_except = [ :id, :created_at, :updated_at ]
|
||||||
|
subsection_except = [ :character_id, :parent_section_id ]
|
||||||
|
always_include = {
|
||||||
|
stats: { except: always_except + [ :value ] },
|
||||||
|
text_fields: { except: always_except },
|
||||||
|
}
|
||||||
|
|
||||||
|
section.to_json(
|
||||||
|
except: always_except + subsection_except,
|
||||||
|
include: {
|
||||||
|
character_sheet_subsections: {
|
||||||
|
except: always_except + subsection_except,
|
||||||
|
include: always_include.merge(
|
||||||
|
character_sheet_subsections: {
|
||||||
|
except: always_except + subsection_except,
|
||||||
|
include: always_include,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}.merge(always_include),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -14,4 +14,8 @@
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="<%= dom_id(character_sheet_section) %>_subsections" class="subsections">
|
||||||
|
<%= render character_sheet_section.character_sheet_subsections %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
new_character_sheet_section_stat_path(section), data: { turbo_stream: true }, class: "add-stat" %>
|
new_character_sheet_section_stat_path(section), data: { turbo_stream: true }, class: "add-stat" %>
|
||||||
<%= link_to t(".add_text_field"),
|
<%= link_to t(".add_text_field"),
|
||||||
new_character_sheet_section_text_field_path(section), data: { turbo_stream: true }, class: "add-text-field" %>
|
new_character_sheet_section_text_field_path(section), data: { turbo_stream: true }, class: "add-text-field" %>
|
||||||
|
<%= link_to t(".save_as_template"),
|
||||||
|
new_character_sheet_section_template_path(section), data: { turbo_frame: "_top" } %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% unless id == "character_sheet_add_section" %>
|
<% unless id == "character_sheet_add_section" %>
|
||||||
<%= link_to t(".delete_section", name: section.name), character_sheet_section_path(section),
|
<%= link_to t(".delete_section", name: section.name), character_sheet_section_path(section),
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
<%= f.text_field :name %>
|
<%= f.text_field :name %>
|
||||||
<%= display_form_errors(@section, :name) %>
|
<%= display_form_errors(@section, :name) %>
|
||||||
|
|
||||||
|
<%= label_tag :template_id, t(".template") %>
|
||||||
|
<%= collection_select nil, :template_id, @templates, :id, :name, include_blank: " " %>
|
||||||
|
<%= display_form_errors(@section, :template) %>
|
||||||
|
|
||||||
<%= f.submit button_text %>
|
<%= f.submit button_text %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<% content_target = @section.parent_section.present? ? "#{dom_id(@section.parent_section)}_sections"
|
<% content_target = @section.parent_section.present? ? "#{dom_id(@section.parent_section)}_subsections"
|
||||||
: "character_sheet" %>
|
: "character_sheet" %>
|
||||||
<%= turbo_stream.append(content_target) do %>
|
<%= turbo_stream.append(content_target) do %>
|
||||||
<%= render @section %>
|
<%= render @section %>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div id=<%= dom_id(character) %> class="character">
|
<div id=<%= dom_id(character) %> class="character">
|
||||||
<h5><%= link_to character.name, character %></h5>
|
<h5><%= link_to character.name, character, data: { turbo_frame: "_top" } %></h5>
|
||||||
<ul>
|
<ul>
|
||||||
<li><%= character.game_system.name %></li>
|
<li><%= character.game_system.name %></li>
|
||||||
<li><%= character.user.username %></li>
|
<li><%= character.user.username %></li>
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
<%= turbo_frame_tag :modal %>
|
<%= turbo_frame_tag :modal %>
|
||||||
<header>
|
<header>
|
||||||
<%= yield(:header_content) if content_for?(:header_content) %>
|
<%= yield(:header_content) if content_for?(:header_content) %>
|
||||||
<h1><%= link_to t("site_name"), root_path %></h1>
|
<h1><%= link_to root_path do %>
|
||||||
|
<%= image_tag "logo.png", width: "600px" %>
|
||||||
|
<% end %></h1>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<% if logged_in? %>
|
<% if logged_in? %>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<section class="inset">
|
||||||
|
<%= form_with model: @template, url: character_sheet_section_templates_path(@section) do |f| %>
|
||||||
|
<%= f.hidden_field :character_sheet_section_id, value: @section.id %>
|
||||||
|
<%= f.hidden_field :game_system_id, value: @section.character.game_system.id %>
|
||||||
|
<%= f.hidden_field :klass, value: "CharacterSheetSection" %>
|
||||||
|
|
||||||
|
<%= f.label :name %>
|
||||||
|
<%= f.text_field :name %>
|
||||||
|
<%= display_form_errors(@section, :name) %>
|
||||||
|
|
||||||
|
<%= f.submit t(".save") %>
|
||||||
|
<% end %>
|
||||||
|
</section>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<% content_for :title, t(".create_template") %>
|
||||||
|
|
||||||
|
<h1><%= t(".create_template") %></h1>
|
||||||
|
|
||||||
|
<%= render partial: "templates/form",
|
||||||
|
locals: { template: @template, button_text: t(".create_template") } %>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<% content_for :title, @template.name %>
|
||||||
|
|
||||||
|
<h1><%= @template.name %></h1>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><%= t(".game_system") %>:</dt>
|
||||||
|
<dd><%= @template.game_system.name %></dd>
|
||||||
|
<dt><%= t(".content") %>:</dt>
|
||||||
|
<dd><%= @template.content %></dd>
|
||||||
|
</dl>
|
|
@ -66,6 +66,7 @@ en:
|
||||||
confirm_delete: Are you sure you want to delete this section?
|
confirm_delete: Are you sure you want to delete this section?
|
||||||
add_stat: Add stat
|
add_stat: Add stat
|
||||||
add_text_field: Add text field
|
add_text_field: Add text field
|
||||||
|
save_as_template: Save as template
|
||||||
index:
|
index:
|
||||||
edit: Edit character sheet
|
edit: Edit character sheet
|
||||||
stop_editing: Stop editing
|
stop_editing: Stop editing
|
||||||
|
@ -74,6 +75,8 @@ en:
|
||||||
add_section: Add section
|
add_section: Add section
|
||||||
new:
|
new:
|
||||||
create_section: Create section
|
create_section: Create section
|
||||||
|
form:
|
||||||
|
template: From template (leave blank for none)
|
||||||
characters:
|
characters:
|
||||||
index:
|
index:
|
||||||
my_characters: My characters
|
my_characters: My characters
|
||||||
|
@ -141,7 +144,7 @@ en:
|
||||||
stats:
|
stats:
|
||||||
show:
|
show:
|
||||||
roll: Roll!
|
roll: Roll!
|
||||||
roll_type_html: Roll %{name}! <br> <small>%{command}</small>
|
roll_type_html: Roll %{name}! (%{command})
|
||||||
min_allowed: Min
|
min_allowed: Min
|
||||||
max_allowed: Max
|
max_allowed: Max
|
||||||
stat:
|
stat:
|
||||||
|
@ -220,6 +223,17 @@ en:
|
||||||
destroy:
|
destroy:
|
||||||
success: Deleted table “%{name}”.
|
success: Deleted table “%{name}”.
|
||||||
error: Failed to delete table.
|
error: Failed to delete table.
|
||||||
|
templates:
|
||||||
|
new:
|
||||||
|
create_template: Create template
|
||||||
|
create:
|
||||||
|
success: The template “%{name}” has been created
|
||||||
|
error: Failed to create template
|
||||||
|
form:
|
||||||
|
save: Create template
|
||||||
|
show:
|
||||||
|
game_system: Game system
|
||||||
|
content: Content
|
||||||
text_fields:
|
text_fields:
|
||||||
text_field:
|
text_field:
|
||||||
delete: Delete text field
|
delete: Delete text field
|
||||||
|
|
|
@ -23,6 +23,7 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
resources :character_sheet_sections, only: [ :destroy ] do
|
resources :character_sheet_sections, only: [ :destroy ] do
|
||||||
resources :stats, only: [ :new, :create ]
|
resources :stats, only: [ :new, :create ]
|
||||||
|
resources :templates, only: [ :new, :create ]
|
||||||
resources :text_fields, only: [ :new, :create ]
|
resources :text_fields, only: [ :new, :create ]
|
||||||
end
|
end
|
||||||
resources :characters do
|
resources :characters do
|
||||||
|
@ -38,6 +39,7 @@ Rails.application.routes.draw do
|
||||||
resources :events, only: [ :index ]
|
resources :events, only: [ :index ]
|
||||||
resources :table_invites, only: [ :new, :create ]
|
resources :table_invites, only: [ :new, :create ]
|
||||||
end
|
end
|
||||||
|
resources :templates, only: [ :show ]
|
||||||
resources :text_fields, only: [ :show, :update, :destroy ]
|
resources :text_fields, only: [ :show, :update, :destroy ]
|
||||||
|
|
||||||
resources :admin, only: [ :index ]
|
resources :admin, only: [ :index ]
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CreateTemplates < ActiveRecord::Migration[7.1]
|
||||||
|
def change
|
||||||
|
create_table :templates do |t|
|
||||||
|
t.belongs_to :game_system, null: false, foreign_key: true
|
||||||
|
t.string :name, null: false
|
||||||
|
t.jsonb :content, null: false, default: {}
|
||||||
|
t.string :klass, null: false
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_check_constraint :templates, "length(name) <= 200", name: "chk_template_name_max_length"
|
||||||
|
add_check_constraint :templates, "length(klass) <= 200", name: "chk_template_klass_max_length"
|
||||||
|
add_index :templates, [ :name, :game_system_id ], unique: true
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[7.1].define(version: 2024_06_21_141219) do
|
ActiveRecord::Schema[7.1].define(version: 2024_06_29_080930) do
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
|
||||||
|
@ -283,6 +283,19 @@ ActiveRecord::Schema[7.1].define(version: 2024_06_21_141219) do
|
||||||
t.check_constraint "length(slug::text) <= 100", name: "chk_table_slug_max_length"
|
t.check_constraint "length(slug::text) <= 100", name: "chk_table_slug_max_length"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "templates", force: :cascade do |t|
|
||||||
|
t.bigint "game_system_id", null: false
|
||||||
|
t.string "name", null: false
|
||||||
|
t.jsonb "content", default: {}, null: false
|
||||||
|
t.string "klass", null: false
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["game_system_id"], name: "index_templates_on_game_system_id"
|
||||||
|
t.index ["name", "game_system_id"], name: "index_templates_on_name_and_game_system_id", unique: true
|
||||||
|
t.check_constraint "length(klass::text) <= 200", name: "chk_template_klass_max_length"
|
||||||
|
t.check_constraint "length(name::text) <= 200", name: "chk_template_name_max_length"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "text_fields", force: :cascade do |t|
|
create_table "text_fields", force: :cascade do |t|
|
||||||
t.string "name", null: false
|
t.string "name", null: false
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
|
@ -328,4 +341,5 @@ ActiveRecord::Schema[7.1].define(version: 2024_06_21_141219) do
|
||||||
add_foreign_key "table_invites", "tables"
|
add_foreign_key "table_invites", "tables"
|
||||||
add_foreign_key "tables", "game_systems"
|
add_foreign_key "tables", "game_systems"
|
||||||
add_foreign_key "tables", "users", column: "owner_id"
|
add_foreign_key "tables", "users", column: "owner_id"
|
||||||
|
add_foreign_key "templates", "game_systems"
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class TemplateBuilderTest < ActiveSupport::TestCase
|
||||||
|
test "creates template from a CharacterSheetSection" do
|
||||||
|
section = character_sheet_sections(:stats)
|
||||||
|
template = TemplateBuilder.create!(
|
||||||
|
name: "Test template",
|
||||||
|
game_system: GameSystem.last,
|
||||||
|
from: section,
|
||||||
|
)
|
||||||
|
template_hash = JSON.parse(template.content)
|
||||||
|
assert_equal 1, template_hash["character_sheet_subsections"].count
|
||||||
|
assert_equal 3, template_hash["stats"].count
|
||||||
|
assert_equal "Stats", template_hash["name"]
|
||||||
|
end
|
||||||
|
end
|
12
todo.md
12
todo.md
|
@ -1,8 +1,12 @@
|
||||||
- Edit dice roll command, types
|
- Templates
|
||||||
|
- Rename to SectionTemplate
|
||||||
|
- Template accessibility level
|
||||||
|
- Users can add their own, "official" ones are always available
|
||||||
|
- Unofficial ones can be added to a local list of favourites
|
||||||
|
- Add from template
|
||||||
|
- Edit/delete templates
|
||||||
|
- Lists
|
||||||
- request invite
|
- request invite
|
||||||
- Weapons/spells: skills?
|
|
||||||
- Do this have_many :stats?
|
|
||||||
- Lists
|
|
||||||
- improve dice roll parsing to allow e.g. choose highest
|
- improve dice roll parsing to allow e.g. choose highest
|
||||||
- Easy add amount to stat
|
- Easy add amount to stat
|
||||||
- icons on features
|
- icons on features
|
||||||
|
|
Loading…
Reference in New Issue