Compare commits

..

No commits in common. "52022ce65e2a947ee90a1624c4ee2658c28fe271" and "b81b78d13a40b7808639af2512a984bc91d5365d" have entirely different histories.

25 changed files with 13 additions and 276 deletions

Binary file not shown.

Before

(image error) Size: 12 KiB

View File

@ -5,12 +5,6 @@
--header-color: #15345b;
--header-text-color: #fff;
--header-height: 200px;
--footer-height: 150px;
--shadow-color: #999;
--light-shadow-color: #CCC;
--secondary-text-color: #777;
--shadow-color: #999;
--light-shadow-color: #CCC;

View File

@ -1,3 +1,3 @@
body {
font-family: sans-serif;
font-family: Roboto, sans-serif;
}

View File

@ -17,7 +17,7 @@ main {
display: flex;
flex-direction: column;
padding: 1em 1em 4em 1em;
min-height: calc(100vh - var(--header-height) - var(--footer-height));
min-height: calc(100vh - var(--header-height));
}
@media(min-width: 800px) {
@ -58,11 +58,6 @@ header {
header h1 {
margin: 0;
padding: 1em;
img {
width: 100%;
max-width: 600px;
min-width: 400px;
}
}
header h1 a:link, header h1 a:visited {
@ -171,7 +166,6 @@ footer {
padding: 1em;
margin: 0 auto;
font-size: .8em;
height: var(--footer-height);
a:link, a:visited {
color: var(--header-text-color);
text-decoration: none;
@ -181,7 +175,3 @@ footer {
margin: 0 auto;
}
}
.subsections {
margin: .5em;
}

View File

@ -15,7 +15,6 @@ class CharacterSheetSectionsController < ApplicationController
end
def new
@templates = Template.game_system(@character.game_system)
if params[:parent_section_id].present?
@parent_section = @character.character_sheet_sections.find_by(id: params[:parent_section_id])
end
@ -23,16 +22,7 @@ class CharacterSheetSectionsController < ApplicationController
end
def create
@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
unless @section.save
@parent_section = @section.parent_section

View File

@ -1,47 +0,0 @@
# 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

View File

@ -35,7 +35,7 @@ class CharacterSheetFeature < ApplicationRecord
def set_order_index
return if order_index.present?
if character_sheet_section.character_sheet_features.count > 1
if character_sheet_section.character_sheet_features.any?
self.order_index = character_sheet_section.character_sheet_features.order(:order_index).last.order_index + 1
else
self.order_index = 1

View File

@ -18,13 +18,6 @@ class CharacterSheetSection < ApplicationRecord
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
character_sheet_features.minimum(:order_index) || 1
end
@ -32,22 +25,4 @@ class CharacterSheetSection < ApplicationRecord
def highest_order_index
character_sheet_features.maximum(:order_index) || 1
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

View File

@ -1,14 +0,0 @@
# 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

View File

@ -1,40 +0,0 @@
# 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

View File

@ -14,8 +14,4 @@
</div>
<% end %>
</div>
<div id="<%= dom_id(character_sheet_section) %>_subsections" class="subsections">
<%= render character_sheet_section.character_sheet_subsections %>
</div>
</div>

View File

@ -7,8 +7,6 @@
new_character_sheet_section_stat_path(section), data: { turbo_stream: true }, class: "add-stat" %>
<%= link_to t(".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 %>
<% unless id == "character_sheet_add_section" %>
<%= link_to t(".delete_section", name: section.name), character_sheet_section_path(section),

View File

@ -6,10 +6,6 @@
<%= f.text_field :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 %>
<% end %>
</section>

View File

@ -1,4 +1,4 @@
<% content_target = @section.parent_section.present? ? "#{dom_id(@section.parent_section)}_subsections"
<% content_target = @section.parent_section.present? ? "#{dom_id(@section.parent_section)}_sections"
: "character_sheet" %>
<%= turbo_stream.append(content_target) do %>
<%= render @section %>

View File

@ -1,5 +1,5 @@
<div id=<%= dom_id(character) %> class="character">
<h5><%= link_to character.name, character, data: { turbo_frame: "_top" } %></h5>
<h5><%= link_to character.name, character %></h5>
<ul>
<li><%= character.game_system.name %></li>
<li><%= character.user.username %></li>

View File

@ -16,9 +16,7 @@
<%= turbo_frame_tag :modal %>
<header>
<%= yield(:header_content) if content_for?(:header_content) %>
<h1><%= link_to root_path do %>
<%= image_tag "logo.png", width: "600px" %>
<% end %></h1>
<h1><%= link_to t("site_name"), root_path %></h1>
<nav>
<ul>
<% if logged_in? %>

View File

@ -1,13 +0,0 @@
<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>

View File

@ -1,6 +0,0 @@
<% content_for :title, t(".create_template") %>
<h1><%= t(".create_template") %></h1>
<%= render partial: "templates/form",
locals: { template: @template, button_text: t(".create_template") } %>

View File

@ -1,10 +0,0 @@
<% 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>

View File

@ -66,7 +66,6 @@ en:
confirm_delete: Are you sure you want to delete this section?
add_stat: Add stat
add_text_field: Add text field
save_as_template: Save as template
index:
edit: Edit character sheet
stop_editing: Stop editing
@ -75,8 +74,6 @@ en:
add_section: Add section
new:
create_section: Create section
form:
template: From template (leave blank for none)
characters:
index:
my_characters: My characters
@ -144,7 +141,7 @@ en:
stats:
show:
roll: Roll!
roll_type_html: Roll %{name}! (%{command})
roll_type_html: Roll %{name}! <br> <small>%{command}</small>
min_allowed: Min
max_allowed: Max
stat:
@ -223,17 +220,6 @@ en:
destroy:
success: Deleted table “%{name}”.
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_field:
delete: Delete text field

View File

@ -23,7 +23,6 @@ Rails.application.routes.draw do
end
resources :character_sheet_sections, only: [ :destroy ] do
resources :stats, only: [ :new, :create ]
resources :templates, only: [ :new, :create ]
resources :text_fields, only: [ :new, :create ]
end
resources :characters do
@ -39,7 +38,6 @@ Rails.application.routes.draw do
resources :events, only: [ :index ]
resources :table_invites, only: [ :new, :create ]
end
resources :templates, only: [ :show ]
resources :text_fields, only: [ :show, :update, :destroy ]
resources :admin, only: [ :index ]

View File

@ -1,18 +0,0 @@
# 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

16
db/schema.rb generated
View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2024_06_29_080930) do
ActiveRecord::Schema[7.1].define(version: 2024_06_21_141219) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -283,19 +283,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_06_29_080930) do
t.check_constraint "length(slug::text) <= 100", name: "chk_table_slug_max_length"
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|
t.string "name", null: false
t.datetime "created_at", null: false
@ -341,5 +328,4 @@ ActiveRecord::Schema[7.1].define(version: 2024_06_29_080930) do
add_foreign_key "table_invites", "tables"
add_foreign_key "tables", "game_systems"
add_foreign_key "tables", "users", column: "owner_id"
add_foreign_key "templates", "game_systems"
end

View File

@ -1,18 +0,0 @@
# 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
View File

@ -1,12 +1,8 @@
- 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
- Edit dice roll command, types
- request invite
- Weapons/spells: skills?
- Do this have_many :stats?
- Lists
- improve dice roll parsing to allow e.g. choose highest
- Easy add amount to stat
- icons on features