Add dark mode with toggle and localStorage persistence

Uses Tailwind v4 class-based dark mode with a Stimulus controller for
toggling. Respects prefers-color-scheme as default, prevents FOUC with
an inline script, and persists the user's choice in localStorage. All
views updated with dark: variants for backgrounds, text, borders,
badges, buttons, and form inputs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dan Milne
2026-03-22 00:37:58 +11:00
parent 43958f50ce
commit 3d98261a51
38 changed files with 744 additions and 636 deletions

View File

@@ -1,41 +1,41 @@
<div class="mx-auto md:w-2/3 w-full">
<div class="mb-8">
<h1 class="font-bold text-4xl">Welcome to Clinch</h1>
<p class="mt-2 text-gray-600">Create your admin account to get started</p>
<p class="mt-2 text-gray-600 dark:text-gray-400">Create your admin account to get started</p>
</div>
<%= form_with model: @user, url: signup_path, class: "contents", data: { controller: "form-errors" } do |form| %>
<%= render "shared/form_errors", form: form %>
<div class="my-5">
<%= form.label :email_address, class: "block font-medium text-sm text-gray-700" %>
<%= form.label :email_address, class: "block font-medium text-sm text-gray-700 dark:text-gray-300" %>
<%= form.email_field :email_address,
required: true,
autofocus: true,
autocomplete: "email",
placeholder: "admin@example.com",
class: "block shadow-sm rounded-md border border-gray-400 focus:outline-blue-600 px-3 py-2 mt-2 w-full" %>
class: "block shadow-sm rounded-md border border-gray-400 focus:outline-blue-600 px-3 py-2 mt-2 w-full dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100" %>
</div>
<div class="my-5">
<%= form.label :password, class: "block font-medium text-sm text-gray-700" %>
<%= form.label :password, class: "block font-medium text-sm text-gray-700 dark:text-gray-300" %>
<%= form.password_field :password,
required: true,
autocomplete: "new-password",
placeholder: "Enter a strong password",
maxlength: 72,
class: "block shadow-sm rounded-md border border-gray-400 focus:outline-blue-600 px-3 py-2 mt-2 w-full" %>
<p class="mt-1 text-sm text-gray-500">Must be at least 8 characters</p>
class: "block shadow-sm rounded-md border border-gray-400 focus:outline-blue-600 px-3 py-2 mt-2 w-full dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100" %>
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">Must be at least 8 characters</p>
</div>
<div class="my-5">
<%= form.label :password_confirmation, "Confirm Password", class: "block font-medium text-sm text-gray-700" %>
<%= form.label :password_confirmation, "Confirm Password", class: "block font-medium text-sm text-gray-700 dark:text-gray-300" %>
<%= form.password_field :password_confirmation,
required: true,
autocomplete: "new-password",
placeholder: "Re-enter your password",
maxlength: 72,
class: "block shadow-sm rounded-md border border-gray-400 focus:outline-blue-600 px-3 py-2 mt-2 w-full" %>
class: "block shadow-sm rounded-md border border-gray-400 focus:outline-blue-600 px-3 py-2 mt-2 w-full dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100" %>
</div>
<div class="my-5">
@@ -43,8 +43,8 @@
class: "w-full rounded-md px-3.5 py-2.5 bg-blue-600 hover:bg-blue-500 text-white font-medium cursor-pointer" %>
</div>
<div class="mt-4 p-4 bg-blue-50 rounded-lg">
<p class="text-sm text-blue-900">
<div class="mt-4 p-4 bg-blue-50 rounded-lg dark:bg-blue-900/30">
<p class="text-sm text-blue-900 dark:text-blue-200">
<strong>Note:</strong> This is a first-run setup. You're creating the initial administrator account.
After this, you'll be able to invite other users from the admin dashboard.
</p>