Compare commits
2 Commits
41bcdba91d
...
810ebcbed3
Author | SHA1 | Date |
---|---|---|
Trevor Vallender | 810ebcbed3 | |
Trevor Vallender | 2f0e1b90b4 |
|
@ -6,6 +6,7 @@
|
||||||
--header-text-color: #fff;
|
--header-text-color: #fff;
|
||||||
--header-height: 200px;
|
--header-height: 200px;
|
||||||
|
|
||||||
|
--shadow-color: #999;
|
||||||
--secondary-text-color: #777;
|
--secondary-text-color: #777;
|
||||||
|
|
||||||
--inset-bg-color: #eee;
|
--inset-bg-color: #eee;
|
||||||
|
|
|
@ -45,3 +45,9 @@ form.stat-form, form.counter-form {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.feature-box form.stat-form {
|
||||||
|
display: block;
|
||||||
|
margin: 1em auto;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
|
@ -98,3 +98,53 @@ header nav {
|
||||||
hr {
|
hr {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#modal:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#modal {
|
||||||
|
position: fixed;
|
||||||
|
background-color: rgba(0,0,0,0.8);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#modal div {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 80vw;
|
||||||
|
max-width: 800px;
|
||||||
|
min-width: 200px;
|
||||||
|
max-height: 800px;
|
||||||
|
min-height: 400px;
|
||||||
|
padding: 1em;
|
||||||
|
word-break: break-word;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
background-color: var(--inset-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-box h2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nf {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.roll-button {
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
scale: 1.4;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 0 5px var(--shadow-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.roll-button::before {
|
||||||
|
content: "YO";
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#table-notifications {
|
#table-notifications {
|
||||||
|
z-index: 1000;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 60em;
|
width: 60em;
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
top: 1em; left: 0;
|
top: 1em; left: 0;
|
||||||
transform: translate(calc(50vw - 50%));
|
transform: translate(calc(50vw - 50%));
|
||||||
li {
|
li {
|
||||||
|
box-shadow: 5px 5px 15px var(--shadow-color);
|
||||||
background-color: var(--notification-bg-color);
|
background-color: var(--notification-bg-color);
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding: .5em;
|
padding: .5em;
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
}
|
}
|
||||||
a:link.active, a:visited.active {
|
a:link.active, a:visited.active {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
z-index: 1000;
|
z-index: 500;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,11 @@ class DiceRollsController < ApplicationController
|
||||||
rollable = dice_roll_params[:rollable_type].constantize.find(dice_roll_params[:rollable_id])
|
rollable = dice_roll_params[:rollable_type].constantize.find(dice_roll_params[:rollable_id])
|
||||||
return head :bad_request if rollable.roll_command.blank?
|
return head :bad_request if rollable.roll_command.blank?
|
||||||
|
|
||||||
|
roller = DiceRoller.new(rollable.roll_command, stat: rollable)
|
||||||
@table.dice_rolls.create!(
|
@table.dice_rolls.create!(
|
||||||
rollable:,
|
rollable:,
|
||||||
result: DiceRoller.new(rollable.roll_command, stat: rollable).roll,
|
result: roller.roll,
|
||||||
|
dice: roller.dice,
|
||||||
)
|
)
|
||||||
head :ok
|
head :ok
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,7 +15,7 @@ class SessionsController < ApplicationController
|
||||||
session[:user_id] = Current.user.id
|
session[:user_id] = Current.user.id
|
||||||
flash[:notice] = t(".success", name: Current.user.first_name)
|
flash[:notice] = t(".success", name: Current.user.first_name)
|
||||||
redirect_to :root
|
redirect_to :root
|
||||||
elsif !Current.user.verified?
|
elsif Current.user && !Current.user.verified?
|
||||||
flash[:alert] = t(".not_verified")
|
flash[:alert] = t(".not_verified")
|
||||||
render :new, status: :unprocessable_entity
|
render :new, status: :unprocessable_entity
|
||||||
else
|
else
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
class StatsController < ApplicationController
|
class StatsController < ApplicationController
|
||||||
before_action :set_section, only: [ :new, :create ]
|
before_action :set_section, only: [ :new, :create ]
|
||||||
before_action :set_character, only: [ :new, :create ]
|
before_action :set_character, only: [ :new, :create ]
|
||||||
before_action :set_stat, only: [ :update, :destroy ]
|
before_action :set_stat, only: [ :show, :update, :destroy ]
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@stat = @section.stats.new
|
@stat = @section.stats.new
|
||||||
|
@ -18,8 +18,11 @@ class StatsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@editable = true
|
@editable = ActiveModel::Type::Boolean.new.cast(params[:editable])
|
||||||
@stat.update(stat_params)
|
@stat.update(stat_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ module ApplicationHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def icon_link_to(icon_name, path, data: {})
|
def icon_link_to(icon_name, path, data: {}, class: "")
|
||||||
icon = content_tag(:i, nil, class: "nf nf-#{icon_name}").html_safe
|
icon = content_tag(:i, nil, class: "nf nf-#{icon_name}").html_safe
|
||||||
link_to icon, path, data: data
|
link_to icon, path, data:, class:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Controller } from "@hotwired/stimulus"
|
||||||
|
|
||||||
|
// Connects to data-controller="modal-closer"
|
||||||
|
export default class extends Controller {
|
||||||
|
closeModal() {
|
||||||
|
const modal = document.getElementById("modal")
|
||||||
|
modal.innerHTML = ""
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,15 @@ class DiceRoll < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def display_text
|
def display_text
|
||||||
"#{rollable.character.name} rolled #{rollable.name}: <strong>#{result}</strong>".html_safe
|
text = <<~TEXT
|
||||||
|
#{rollable.character.name} rolled #{rollable.name}:
|
||||||
|
<strong>#{result}</strong>
|
||||||
|
(#{dice_text})
|
||||||
|
TEXT
|
||||||
|
text.html_safe
|
||||||
|
end
|
||||||
|
|
||||||
|
def dice_text
|
||||||
|
dice.map { |d| "D#{d[0]}: #{d[1]}" }.join(", ")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,8 +15,9 @@ class Stat < ApplicationRecord
|
||||||
validate :validate_roll_command
|
validate :validate_roll_command
|
||||||
|
|
||||||
def roll(table)
|
def roll(table)
|
||||||
result = DiceRoller.new(roll_command, stat: self).roll
|
roller = DiceRoller.new(roll_command, stat: self)
|
||||||
dice_rolls.create(result:, table:)
|
result = roller.roll
|
||||||
|
dice_rolls.create(result: roller.roll, table:, dice: roller.dice)
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class DiceRoller
|
class DiceRoller
|
||||||
|
attr_reader :dice
|
||||||
|
attr_reader :result
|
||||||
|
|
||||||
def initialize(roll_command, stat: nil)
|
def initialize(roll_command, stat: nil)
|
||||||
@roll_command = roll_command
|
@roll_command = roll_command
|
||||||
@stat = stat&.value
|
@stat = stat&.value
|
||||||
|
@dice = []
|
||||||
end
|
end
|
||||||
|
|
||||||
def roll
|
def roll
|
||||||
|
@ -59,7 +63,9 @@ class DiceRoller
|
||||||
|
|
||||||
result = 0
|
result = 0
|
||||||
dice_number.times do
|
dice_number.times do
|
||||||
result += rand(1..die_type.to_i)
|
roll = rand(1..die_type.to_i)
|
||||||
|
result += roll
|
||||||
|
dice << [ die_type, result ]
|
||||||
end
|
end
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<%= 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 t("site_name"), root_path %></h1>
|
||||||
|
|
|
@ -12,16 +12,12 @@
|
||||||
<h6><%= stat.name %></h6>
|
<h6><%= stat.name %></h6>
|
||||||
<% if @editable %>
|
<% if @editable %>
|
||||||
<%= form_with model: stat, class: "stat-form", data: { controller: "auto-update" } do |f| %>
|
<%= form_with model: stat, class: "stat-form", data: { controller: "auto-update" } do |f| %>
|
||||||
|
<%= hidden_field_tag :editable, value: true %>
|
||||||
<%= f.number_field :value %>
|
<%= f.number_field :value %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% elsif stat.roll_command.present? %>
|
|
||||||
<%= form_with model: DiceRoll.new, url: table_dice_rolls_path(stat.character.table), class: "stat-form",
|
|
||||||
data: { controller: "dice-roll" } do |f| %>
|
|
||||||
<%= f.hidden_field :rollable_type, value: "Stat" %>
|
|
||||||
<%= f.hidden_field :rollable_id, value: stat.id %>
|
|
||||||
<div class="stat-value" data-action="click->dice-roll#rollDice"><%= stat.value %></div>
|
|
||||||
<% end %>
|
|
||||||
<% else %>
|
<% else %>
|
||||||
<div class="stat-value"><%= stat.value %></div>
|
<%= link_to stat, data: { turbo_frame: :modal } do %>
|
||||||
|
<div class="stat-value"><%= stat.value %></div>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<%= turbo_frame_tag :modal do %>
|
||||||
|
<div class="feature-box stat">
|
||||||
|
<%= icon_link_to "fa-close", table_character_character_sheet_sections_path(@stat.character.table, @stat.character),
|
||||||
|
class: "icon-link" %>
|
||||||
|
<h2><%= @stat.name %></h2>
|
||||||
|
<%= form_with model: @stat, class: "stat-form", data: { controller: "auto-update" } do |f| %>
|
||||||
|
<%= f.number_field :value %>
|
||||||
|
<% end %>
|
||||||
|
<%= form_with model: DiceRoll.new, url: table_dice_rolls_path(@stat.character.table), class: "stat-form",
|
||||||
|
data: { controller: "dice-roll modal-closer", action: "modal-closer#closeModal" } do |f| %>
|
||||||
|
<%= f.hidden_field :rollable_type, value: "Stat" %>
|
||||||
|
<%= f.hidden_field :rollable_id, value: @stat.id %>
|
||||||
|
<%= f.submit "#{t(".roll")}".html_safe, class: "roll-button" %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
|
@ -145,6 +145,8 @@ en:
|
||||||
log_out: Log out
|
log_out: Log out
|
||||||
success: "You have signed out."
|
success: "You have signed out."
|
||||||
stats:
|
stats:
|
||||||
|
show:
|
||||||
|
roll: Roll!
|
||||||
stat:
|
stat:
|
||||||
down: Move down
|
down: Move down
|
||||||
up: Move up
|
up: Move up
|
||||||
|
|
|
@ -30,7 +30,7 @@ Rails.application.routes.draw do
|
||||||
resources :character_sheet_sections, only: [ :index, :new, :create ]
|
resources :character_sheet_sections, only: [ :index, :new, :create ]
|
||||||
end
|
end
|
||||||
resources :counters, only: [ :update, :destroy ]
|
resources :counters, only: [ :update, :destroy ]
|
||||||
resources :stats, only: [ :update, :destroy ]
|
resources :stats, only: [ :show, :update, :destroy ]
|
||||||
resources :table_invites, only: [ :index, :edit, :update ]
|
resources :table_invites, only: [ :index, :edit, :update ]
|
||||||
resources :tables do
|
resources :tables do
|
||||||
resources :characters, only: [] do
|
resources :characters, only: [] do
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddPartsToDiceRolls < ActiveRecord::Migration[7.1]
|
||||||
|
def change
|
||||||
|
add_column :dice_rolls, :dice, :jsonb, null: false, default: {}
|
||||||
|
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_17_151532) do
|
ActiveRecord::Schema[7.1].define(version: 2024_06_19_190424) 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"
|
||||||
|
|
||||||
|
@ -103,6 +103,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_06_17_151532) do
|
||||||
t.integer "result", null: false
|
t.integer "result", null: false
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
|
t.jsonb "dice", default: {}, null: false
|
||||||
t.index ["rollable_type", "rollable_id"], name: "index_dice_rolls_on_rollable"
|
t.index ["rollable_type", "rollable_id"], name: "index_dice_rolls_on_rollable"
|
||||||
t.index ["table_id"], name: "index_dice_rolls_on_table_id"
|
t.index ["table_id"], name: "index_dice_rolls_on_table_id"
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
nardren:
|
nardren:
|
||||||
name: Nardren Rockseeker
|
name: Nardren Rockseeker
|
||||||
table: dnd_table
|
table: table
|
||||||
game_system: dnd
|
game_system: dnd
|
||||||
user: trevor
|
user: trevor
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "application_system_test_case"
|
||||||
|
|
||||||
|
class CharacterSheetTest < ApplicationSystemTestCase
|
||||||
|
test "can roll dice on a character sheet" do
|
||||||
|
system_sign_in users(:trevor)
|
||||||
|
|
||||||
|
character = characters(:nardren)
|
||||||
|
visit table_character_character_sheet_sections_path(tables(:table), character)
|
||||||
|
|
||||||
|
assert_no_css ".feature-box"
|
||||||
|
first(".stat-value").click
|
||||||
|
assert_css ".feature-box"
|
||||||
|
|
||||||
|
click_button I18n.t("stats.show.roll")
|
||||||
|
assert_text "rolled"
|
||||||
|
assert_no_css ".feature-box"
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue