-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make "Rules of Engagement" toggleable
We remember the open/closed state of the Rules of Engagement section by storing state into cookie called "rules". A non-blank value indicates that the section should be collapsed on page load. - I strongly considered making this a signing-user-only feature, but it does make the code somewhat significantly more complex. And, in the end, it feels like the sort of thing that could be too annoying to have to look at, even for first-time visitors if they're experts at minesweeper already. And since there's no way to know that signing will give this feature, it's probably better to just go this route. We use el-transition.js combined with TailwindCSS's `transition` class to define and then animate the transition effects between open/closed states. Also, remove unused code from menu_controller.js. I noticed this when copying code into the new collapse_controller.js. The unused code comes from copying menu_controller.js in from another app that used it for a bit more than just the Theme menu.
- Loading branch information
Paul DobbinSchmaltz
committed
Oct 24, 2024
1 parent
0eca51d
commit 6bef505
Showing
6 changed files
with
157 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { Controller } from "@hotwired/stimulus" | ||
import { toggle } from "el-transition" | ||
import { cookies } from "cookies" | ||
|
||
export default class extends Controller { | ||
static targets = ["button", "icon", "section"] | ||
static values = { | ||
cookieName: String, | ||
collapsedCookie: { type: String, default: "collapsed" }, | ||
} | ||
static classes = ["buttonToggle", "iconToggle"] | ||
|
||
toggle() { | ||
this.#setCookie() | ||
this.toggleButtonState() | ||
toggle(this.sectionTarget) | ||
this.#updateAriaAttributes() | ||
} | ||
|
||
#setCookie() { | ||
if (this.#sectionIsHidden()) { | ||
// -> Visible | ||
cookies.delete(this.cookieNameValue) | ||
} else { | ||
// -> Hidden | ||
cookies.permanent.set(this.cookieNameValue, this.collapsedCookieValue) | ||
} | ||
} | ||
|
||
#sectionIsHidden() { | ||
return this.sectionTarget.classList.contains("hidden") | ||
} | ||
|
||
toggleButtonState() { | ||
this.buttonTarget.classList.toggle(this.buttonToggleClass) | ||
this.iconTarget.classList.toggle(this.iconToggleClass) | ||
} | ||
|
||
#updateAriaAttributes() { | ||
if (this.sectionTarget.getAttribute("aria-hidden") === "true") { | ||
this.sectionTarget.setAttribute("aria-hidden", "false") | ||
this.buttonTarget.setAttribute("aria-expanded", "true") | ||
} else { | ||
this.sectionTarget.setAttribute("aria-hidden", "true") | ||
this.buttonTarget.setAttribute("aria-expanded", "false") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,78 @@ | ||
<%# locals: () %> | ||
<%# locals: (view:) %> | ||
|
||
<div class="space-y-6"> | ||
<h3 class="h4">Rules of Engagement</h3> | ||
<div | ||
data-controller="collapse" | ||
data-collapse-button-toggle-class="<%= view.collapsed_button_css_class %>" | ||
data-collapse-icon-toggle-class="<%= view.collapsed_icon_css_class %>" | ||
data-collapse-cookie-name-value="<%= view.cookie_name %>" | ||
class="space-y-6" | ||
> | ||
<h3 | ||
data-collapse-target="button" | ||
data-action="click->collapse#toggle" | ||
aria-label="Toggle Rules of Engagement" | ||
aria-haspopup="true" | ||
aria-expanded="<%= view.open? %>" | ||
class=" | ||
h4 flex items-center gap-x-3 cursor-pointer | ||
transition-colors | ||
<%= class_names(view.collapsed_button_css_class) if view.collapsed? %> | ||
" | ||
> | ||
Rules of Engagement | ||
<%= inline_svg_tag( | ||
"heroicons/chevron-down.svg", | ||
class: | ||
"max-w-4 max-h-4 stroke-2 transition-transform "\ | ||
"#{class_names(view.collapsed_icon_css_class) if view.collapsed?}", | ||
data: { collapse_target: "icon" }) %> | ||
</h3> | ||
|
||
<ol class="space-y-2 list-decimal ml-7"> | ||
<li><strong>Click</strong> a cell to reveal it.</li> | ||
<li> | ||
A revealed cell indicates the number of mines (<%= Icon.mine %>) in the cells surrounding it. | ||
<p class="text-gray-500 dark:text-neutral-400"> | ||
– Possible values include: Blank/0 (<%= Icon.cell %>), or 1–8. | ||
</p> | ||
</li> | ||
<li><strong>Right Click</strong> a cell to flag (<%= Icon.flag %>) it as a suspected mine (<%= Icon.mine %>).</li> | ||
<li> | ||
<strong>Click</strong> a revealed cell to reveal all possible surrounding cells (this is called "chording"). | ||
<p class="text-gray-500 dark:text-neutral-400"> | ||
– Possible only after the correct number of surrounding cells have been flagged. | ||
</p> | ||
<p class="text-gray-500 dark:text-neutral-400"> | ||
– Be careful! This does not protect against mistaken flag (<%= Icon.flag %>) placements. | ||
</p> | ||
</li> | ||
<li>The game is <strong>lost</strong> if a mine (<%= Icon.mine %>) is revealed.</li> | ||
<li> | ||
The game is <strong>won</strong> when all non-mine cells are revealed. | ||
<p class="text-gray-500 dark:text-neutral-400"> | ||
– Regardless of how many flags have been placed. | ||
</p> | ||
</li> | ||
</ol> | ||
</div> | ||
<div | ||
data-collapse-target="section" | ||
data-transition-enter="transition ease-out duration-100" | ||
data-transition-enter-start="transform opacity-0 scale-95" | ||
data-transition-enter-end="transform opacity-100 scale-100" | ||
data-transition-leave="transition ease-in duration-75" | ||
data-transition-leave-start="transform opacity-100 scale-100" | ||
data-transition-leave-end="transform opacity-0 scale-95" | ||
aria-hidden="<%= view.collapsed? %>" | ||
aria-orientation="vertical" | ||
class=" | ||
space-y-10 | ||
<%= class_names(view.collapsed_section_css_class) if view.collapsed? %> | ||
" | ||
> | ||
<ol class="space-y-2 list-decimal ml-7"> | ||
<li><strong>Click</strong> a cell to reveal it.</li> | ||
<li> | ||
A revealed cell indicates the number of mines (<%= Icon.mine %>) in the cells surrounding it. | ||
<p class="text-gray-500 dark:text-neutral-400"> | ||
– Possible values include: Blank/0 (<%= Icon.cell %>), or 1–8. | ||
</p> | ||
</li> | ||
<li><strong>Right Click</strong> a cell to flag (<%= Icon.flag %>) it as a suspected mine (<%= Icon.mine %>).</li> | ||
<li> | ||
<strong>Click</strong> a revealed cell to reveal all possible surrounding cells (this is called "chording"). | ||
<p class="text-gray-500 dark:text-neutral-400"> | ||
– Possible only after the correct number of surrounding cells have been flagged. | ||
</p> | ||
<p class="text-gray-500 dark:text-neutral-400"> | ||
– Be careful! This does not protect against mistaken flag (<%= Icon.flag %>) placements. | ||
</p> | ||
</li> | ||
<li>The game is <strong>lost</strong> if a mine (<%= Icon.mine %>) is revealed.</li> | ||
<li> | ||
The game is <strong>won</strong> when all non-mine cells are revealed. | ||
<p class="text-gray-500 dark:text-neutral-400"> | ||
– Regardless of how many flags have been placed. | ||
</p> | ||
</li> | ||
</ol> | ||
|
||
<p class="mt-10"> | ||
<%= Icon.clover %> Good luck! | ||
The Alliance is counting on you<span class="font-sans">…</span> | ||
</p> | ||
<p> | ||
<%= Icon.clover %> Good luck! | ||
The Alliance is counting on you<span class="font-sans">…</span> | ||
</p> | ||
</div> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# frozen_string_literal: true | ||
|
||
# :reek:RepeatedConditional | ||
|
||
# Games::Rules is a View Model for managing display of the game-play rules | ||
# section. | ||
class Games::Rules | ||
COOKIE_NAME = "rules" | ||
|
||
def initialize(context:) | ||
@context = context | ||
end | ||
|
||
def cookie_name = COOKIE_NAME | ||
|
||
def collapsed_button_css_class = "text-gray-500" | ||
def collapsed_icon_css_class = "-rotate-90" | ||
def collapsed_section_css_class = "hidden" | ||
|
||
def open? = !collapsed? | ||
def collapsed? = cookies[cookie_name].present? | ||
|
||
private | ||
|
||
attr_reader :context | ||
|
||
def cookies = context.cookies | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters