develop #3

Merged
kbe merged 227 commits from develop into main 2025-09-16 14:35:23 +00:00
8 changed files with 536 additions and 1256 deletions
Showing only changes of commit c7d28dca71 - Show all commits

View File

@@ -0,0 +1,83 @@
<footer class="py-10 bg-gray-900 text-white border-t-1 border-solid border-color-gray">
<div class="max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
<!-- Column 1: About -->
<div class="space-y-4">
<h3 class="text-lg font-semibold text-indigo-400">À propos</h3>
<p class="text-sm text-gray-300 leading-relaxed">
Aperonight est la plateforme qui connecte les amateurs de soirées aux meilleurs événements de leur ville.
</p>
<div class="flex space-x-4">
<a href="#" class="text-gray-400 hover:text-white transition-colors">
<span class="sr-only">Facebook</span>
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
<path fill-rule="evenodd" d="M22 12c0-5.523-4.477-10-10-10S2 6.477 2 12c0 4.991 3.657 9.128 8.438 9.878v-6.987h-2.54V12h2.54V9.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V12h2.773l-.443 2.89h-2.33v6.988C18.343 21.128 22 16.991 22 12z" clip-rule="evenodd"/>
</svg>
</a>
<a href="#" class="text-gray-400 hover:text-white transition-colors">
<span class="sr-only">Instagram</span>
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
<path fill-rule="evenodd" d="M12.315 2c2.43 0 2.784.013 3.808.06 1.064.049 1.791.218 2.427.465a4.902 4.902 0 011.772 1.153 4.902 4.902 0 011.153 1.772c.247.636.416 1.363.465 2.427.048 1.024.06 1.378.06 3.808s-.012 2.784-.06 3.808c-.049 1.064-.218 1.791-.465 2.427a4.902 4.902 0 01-1.153 1.772 4.902 4.902 0 01-1.772 1.153c-.636.247-1.363.416-2.427.465-1.024.048-1.378.06-3.808.06s-2.784-.012-3.808-.06c-1.064-.049-1.791-.218-2.427-.465a4.902 4.902 0 01-1.772-1.153 4.902 4.902 0 01-1.153-1.772c-.247-.636-.416-1.363-.465-2.427-.048-1.024-.06-1.378-.06-3.808s.012-2.784.06-3.808c.049-1.064.218-1.791.465-2.427A4.902 4.902 0 015.45 2.525c.636-.247 1.363-.416 2.427-.465C8.901 2.013 9.256 2 11.685 2h.63zm-.081 1.802c-.468 0-.514.043-.514.043v2.378h2.575c0-2.378 0-2.378-.514-2.378zm-2.189 2.378v-2.378c0-.468.043-.514.043-.514h-2.378v2.892h2.335zm1.097 1.097c-.468 0-.514.043-.514.043v2.335h2.892v-2.892h-2.378c-.468 0-.514.043-.514.043v.514zm-1.097 1.097v-2.335c0-.468.043-.514.043-.514h-2.378v2.892h2.335z" clip-rule="evenodd"/>
</svg>
</a>
</div>
</div>
<!-- Column 2: Quick Links -->
<div class="space-y-4">
<h3 class="text-lg font-semibold text-indigo-400">Liens rapides</h3>
<ul class="space-y-2 text-sm">
<li><%= link_to "Accueil", "/", class: "text-gray-300 hover:text-white transition-colors" %></li>
<li><%= link_to "Événements", "/events", class: "text-gray-300 hover:text-white transition-colors" %></li>
<li><%= link_to "Organisateurs", "/organizers", class: "text-gray-300 hover:text-white transition-colors" %></li>
<li><%= link_to "Support", "/support", class: "text-gray-300 hover:text-white transition-colors" %></li>
</ul>
</div>
<!-- Column 3: Legal -->
<div class="space-y-4">
<h3 class="text-lg font-semibold text-indigo-400">Légal</h3>
<ul class="space-y-2 text-sm">
<li><%= link_to "Conditions d'utilisation", "/terms", class: "text-gray-300 hover:text-white transition-colors" %></li>
<li><%= link_to "Politique de confidentialité", "/privacy", class: "text-gray-300 hover:text-white transition-colors" %></li>
<li><%= link_to "CGV", "/cgv", class: "text-gray-300 hover:text-white transition-colors" %></li>
<li><%= link_to "Mentions légales", "/legal", class: "text-gray-300 hover:text-white transition-colors" %></li>
</ul>
</div>
<!-- Column 4: Contact -->
<div class="space-y-4">
<h3 class="text-lg font-semibold text-indigo-400">Contact</h3>
<address class="not-italic text-sm text-gray-300 space-y-2">
<p>
<span class="block font-medium">Email:</span>
<a href="mailto:hello@aperonight.com" class="text-indigo-400 hover:text-indigo-300 transition-colors">
hello@aperonight.com
</a>
</p>
<p>
<span class="block font-medium">Support:</span>
<a href="mailto:support@aperonight.com" class="text-indigo-400 hover:text-indigo-300 transition-colors">
support@aperonight.com
</a>
</p>
</address>
<p class="text-xs text-gray-400">
Réponse sous 24h en semaine
</p>
</div>
</div>
<!-- Bottom Bar -->
<div class="mt-12 pt-8 border-t border-gray-800">
<div class="flex flex-col md:flex-row justify-between items-center">
<p class="text-sm text-gray-400">
© <%= Time.current.year %> Aperonight. Tous droits réservés.
</p>
<p class="text-xs text-gray-500 mt-2 md:mt-0">
Fait avec 💜 pour la communauté
</p>
</div>
</div>
</div>
</footer>

View File

@@ -32,12 +32,14 @@
</div> </div>
</div> </div>
<!-- Authentication Links -->
<% if user_signed_in? %>
<!-- Settings Dropdown --> <!-- Settings Dropdown -->
<div class="hidden sm:flex sm:items-center sm:ms-6"> <div class="hidden sm:flex sm:items-center sm:ms-6">
<div class="relative" x-data="{ open: false }" @click.outside="open = false" @close.stop="open = false"> <div class="relative" x-data="{ open: false }" @click.outside="open = false" @close.stop="open = false">
<div @click="open = ! open"> <div @click="open = ! open">
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150"> <button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
<div>Mon profil</div> <div><%= current_user.email %></div>
<div class="ms-1"> <div class="ms-1">
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> <svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" /> <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
@@ -57,7 +59,7 @@
style="display: none;" style="display: none;"
@click="open = false"> @click="open = false">
<div class="rounded-md ring-1 ring-black ring-opacity-5 py-1 bg-white"> <div class="rounded-md ring-1 ring-black ring-opacity-5 py-1 bg-white">
<%= link_to "Mon profil", "#", class: "block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out" %> <%= link_to "Mon profil", edit_user_registration_path, class: "block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out" %>
<%= link_to "Mes réservations", "#", class: "block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out" %> <%= link_to "Mes réservations", "#", class: "block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out" %>
<!-- Logout --> <!-- Logout -->
@@ -70,12 +72,17 @@
turbo: false turbo: false
}, },
class: "inline-block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out" %> class: "inline-block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out" %>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<% else %>
<!-- Login/Register Links -->
<div class="hidden sm:flex sm:items-center sm:ms-6 space-x-4">
<%= link_to "S'inscrire", new_user_registration_path, class: "inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-300 hover:text-white focus:outline-none transition ease-in-out duration-150" %>
<%= link_to "Se connecter", new_user_session_path, class: "inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-300 hover:text-white focus:outline-none transition ease-in-out duration-150" %>
</div>
<% end %>
<!-- Hamburger --> <!-- Hamburger -->
<div class="-me-2 flex items-center sm:hidden"> <div class="-me-2 flex items-center sm:hidden">
@@ -98,13 +105,14 @@
<!-- Responsive Settings Options --> <!-- Responsive Settings Options -->
<div class="pt-4 pb-1 border-t border-gray-200"> <div class="pt-4 pb-1 border-t border-gray-200">
<% if user_signed_in? %>
<div class="px-4"> <div class="px-4">
<div class="font-medium text-base text-gray-800">Test</div> <div class="font-medium text-base text-gray-800"><%= current_user.email %></div>
<div class="font-medium text-sm text-gray-500">Test</div> <div class="font-medium text-sm text-gray-500"><%= current_user.email %></div>
</div> </div>
<div class="mt-3 space-y-1"> <div class="mt-3 space-y-1">
<%= link_to "Mon profil", "#", class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %> <%= link_to "Mon profil", edit_user_registration_path, class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %>
<%= link_to "Mes réservations", "#", class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %> <%= link_to "Mes réservations", "#", class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %>
<!-- Logout --> <!-- Logout -->
@@ -116,9 +124,14 @@
login_url_value: new_user_session_path, login_url_value: new_user_session_path,
turbo: false turbo: false
}, },
class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out" %> class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %>
</div> </div>
<% else %>
<div class="mt-3 space-y-1">
<%= link_to "S'inscrire", new_user_registration_path, class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %>
<%= link_to "Se connecter", new_user_session_path, class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %>
</div>
<% end %>
</div> </div>
</div> </div>
</nav> </nav>

View File

@@ -1,26 +1,68 @@
<h2>Log in</h2> <div class="min-h-screen flex items-center justify-center bg-gray-900 py-12 px-4 sm:px-6 lg:px-8">
<div class="max-w-md w-full space-y-8">
<div>
<%= link_to "/" do %>
<img class="mx-auto h-12 w-auto" src="/icon.svg" alt="Aperonight" />
<% end %>
<h2 class="mt-6 text-center text-3xl font-extrabold text-white">
Connexion à votre compte
</h2>
<p class="mt-2 text-center text-sm text-gray-400">
Ou
<a href="<%= new_user_registration_path %>" class="font-medium text-indigo-400 hover:text-indigo-300">
créez un nouveau compte
</a>
</p>
</div>
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> <%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: "mt-8 space-y-6" }) do |f| %>
<%= devise_error_messages! %>
<div class="rounded-md shadow-sm -space-y-px">
<div class="field"> <div class="field">
<%= f.label :email %><br /> <%= f.label :email, class: "sr-only" %>
<%= f.email_field :email, autofocus: true, autocomplete: "email" %> <%= f.email_field :email, autofocus: true, autocomplete: "email",
class: "appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-700 placeholder-gray-500 text-gray-100 bg-gray-800 rounded-t-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm",
placeholder: "Adresse email" %>
</div> </div>
<div class="field"> <div class="field">
<%= f.label :password %><br /> <%= f.label :password, class: "sr-only" %>
<%= f.password_field :password, autocomplete: "current-password" %> <%= f.password_field :password, autocomplete: "current-password",
class: "appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-700 placeholder-gray-500 text-gray-100 bg-gray-800 rounded-b-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm",
placeholder: "Mot de passe" %>
</div>
</div> </div>
<% if devise_mapping.rememberable? %> <% if devise_mapping.rememberable? %>
<div class="field"> <div class="flex items-center justify-between">
<%= f.check_box :remember_me %> <div class="flex items-center">
<%= f.label :remember_me %> <%= f.check_box :remember_me, class: "h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-700 rounded bg-gray-800" %>
<label for="user_remember_me" class="ml-2 block text-sm text-gray-400"> Se souvenir de moi </label>
</div>
<div class="text-sm">
<%= link_to "Mot de passe oublié?", new_password_path(resource_name), class: "font-medium text-indigo-400 hover:text-indigo-300" %>
</div>
</div> </div>
<% end %> <% end %>
<div class="actions"> <div class="actions">
<%= f.submit "Log in" %> <%= f.submit "Se connecter", class: "group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-indigo-500" %>
</div> </div>
<% end %> <% end %>
<%= render "devise/shared/links" %> <div class="mt-6">
<div class="relative">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-gray-700"></div>
</div>
<div class="relative flex justify-center text-sm">
<span class="px-2 bg-gray-900 text-gray-400"> Ou continuer avec </span>
</div>
</div>
<%= render "devise/shared/links" %>
</div>
</div>
</div>

View File

@@ -1,25 +1,39 @@
<%- if controller_name != 'sessions' %> <div class="">
<%= link_to "Log in", new_session_path(resource_name) %><br /> <%- if controller_name != "sessions" %>
<% end %> <div class="w-full flex justify-center py-2 px-4 border border-gray-700 rounded-md shadow-sm text-sm font-medium text-gray-300 bg-gray-800 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-indigo-500">
<%= link_to "Se connecter", new_session_path(resource_name), class: "block" %>
<%- if devise_mapping.registerable? && controller_name != 'registrations' %> </div>
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end %>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
<% end %>
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
<% end %>
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
<% end %>
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %><br />
<% end %> <% end %>
<% end %>
<%- if devise_mapping.registerable? && controller_name != "registrations" %>
<div class="w-full flex justify-center mt-4 py-2 px-4 border border-gray-700 rounded-md shadow-sm text-sm font-medium text-gray-300 bg-gray-800 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-indigo-500">
<%= link_to "S'inscrire", new_registration_path(resource_name), class: "" %>
</div>
<% end %>
<%- if devise_mapping.recoverable? && controller_name != "passwords" && controller_name != "registrations" %>
<div class="w-full flex justify-center mt-4 py-2 px-4 border border-gray-700 rounded-md shadow-sm text-sm font-medium text-gray-300 bg-gray-800 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-indigo-500">
<%= link_to "Mot de passe oublié ?", new_password_path(resource_name), class: "" %>
</div>
<% end %>
<%- if devise_mapping.confirmable? && controller_name != "confirmations" %>
<div class="w-full flex justify-center mt-4 py-2 px-4 border border-gray-700 rounded-md shadow-sm text-sm font-medium text-gray-300 bg-gray-800 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-indigo-500">
<%= link_to "Vous n'avez pas reçu les instructions de confirmation ?", new_confirmation_path(resource_name), class: "" %>
</div>
<% end %>
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != "unlocks" %>
<div class="w-full flex justify-center mt-4 py-2 px-4 border border-gray-700 rounded-md shadow-sm text-sm font-medium text-gray-300 bg-gray-800 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-indigo-500">
<%= link_to "Vous n'avez pas reçu les instructions de déverrouillage?", new_unlock_path(resource_name), class: "" %>
</div>
<% end %>
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<div class="w-full flex justify-center mt-4 py-2 px-4 border border-gray-700 rounded-md shadow-sm text-sm font-medium text-gray-300 bg-gray-800 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-indigo-500">
<%= button_to "Se connecter avec #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false }, class: "" %>
</div>
<% end %>
<% end %>
</div>

View File

@@ -28,6 +28,12 @@
<%= render "components/header" %> <%= render "components/header" %>
</div><!-- /#header --> </div><!-- /#header -->
<main>
<%= yield %> <%= yield %>
</main>
<div id="footer">
<%= render "components/footer" %>
</div>
</body> </body>
</html> </html>

View File

@@ -15,7 +15,7 @@ Rails.application.routes.draw do
# Routes for devise authentication Gem # Routes for devise authentication Gem
# Bind devise to user # Bind devise to user
# devise_for :users # devise_for :users
devise_for :users, path: "authentications", path_names: { devise_for :users, path: "auth", path_names: {
sign_up: "register", # Route for user registration sign_up: "register", # Route for user registration
sign_in: "login", # Route for user login sign_in: "login", # Route for user login
sign_out: "logout", # Route for user logout sign_out: "logout", # Route for user logout

File diff suppressed because it is too large Load Diff

View File

@@ -1,103 +1,280 @@
# Theme Rules & Color Palette - Aperonight # Theme Rules for Aperonight
Extracted from `app/views/pages/home.html.erb` ## Core Design System
## Color Palette ### Color Palette
```css
/* Primary - Purple gradient system */
--color-primary-50: #faf5ff;
--color-primary-100: #f3e8ff;
--color-primary-200: #e9d5ff;
--color-primary-300: #d8b4fe;
--color-primary-400: #c084fc;
--color-primary-500: #a855f7;
--color-primary-600: #9333ea;
--color-primary-700: #7e22ce;
--color-primary-800: #6b21a8;
--color-primary-900: #581c87;
### Primary Colors /* Accent - Pink gradient */
- **Indigo**: `#4338ca` (rgb(67, 56, 202)) - Used in hero gradient --color-accent-400: #f472b6;
- **Purple**: `#8b5cf6` (rgb(139, 92, 246)) - Primary brand color --color-accent-500: #ec4899;
- **Pink**: `#ec4899` (rgb(236, 72, 153)) - Accent color --color-accent-600: #db2777;
### Background Gradients /* Neutral - Slate system */
- **Hero**: `bg-gradient-to-br from-indigo-900 via-purple-800 to-pink-700` --color-neutral-50: #f8fafc;
- **CTA**: `bg-gradient-to-r from-purple-900 via-indigo-900 to-pink-900` --color-neutral-100: #f1f5f9;
- **Cards**: `bg-gradient-to-br from-gray-800 to-gray-900` --color-neutral-200: #e2e8f0;
- **Buttons**: `bg-gradient-to-r from-purple-600 to-pink-600` --color-neutral-300: #cbd5e1;
--color-neutral-400: #94a3b8;
### Text Colors --color-neutral-500: #64748b;
- **White**: `text-white` - Primary text --color-neutral-600: #475569;
- **Gray-200**: `text-gray-200` - Secondary text --color-neutral-700: #334155;
- **Gray-300**: `text-gray-300` - Subtle text --color-neutral-800: #1e293b;
- **Gray-400**: `text-gray-400` - Muted text --color-neutral-900: #0f172a;
- **Transparent gradient**: `text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-400` - Special highlight
### Background Colors
- **Gray-900**: `bg-gray-900` - Main background
- **Black**: `bg-black` - Overlay backgrounds
- **Gray-800**: `bg-gray-800` - Card backgrounds
- **White/Transparent**: `bg-white bg-opacity-10 backdrop-blur-sm` - Glass effect
## Spacing & Layout
### Hero Section
- **Height**: `min-h-[70vh]`
- **Max-width**: `max-w-7xl mx-auto`
- **Padding**: `px-4 sm:px-6 lg:px-8`
### Grid Layouts
- **Responsive**: `grid-cols-1 md:grid-cols-2 lg:grid-cols-3`
- **Gap**: `gap-8` standard spacing
### Padding Classes
- **Section**: `py-16`, `py-20`
- **Card**: `p-4`, `p-6`, `p-8`
- **Button**: `py-3`, `py-4`, `px-6`, `px-8`
## Typography
### Font Sizes
- **Hero Title**: `text-5xl md:text-7xl`
- **Section Title**: `text-4xl`
- **Card Title**: `text-2xl`
- **Body**: `text-xl`, `text-lg`
- **Small**: `text-sm`
### Font Weights
- **Bold**: `font-bold` (headings)
- **Semibold**: `font-semibold` (buttons, important text)
- **Medium**: `font-medium` (labels)
## Interactive States
### Hover Effects
- **Scale**: `hover:scale-105`
- **Transition**: `transition-all duration-300`
- **Button Hover**: `hover:from-purple-700 hover:to-pink-700`
- **Glass Hover**: `hover:bg-opacity-20`
### Shadows
- **Default**: `shadow-lg`
- **Strong**: `shadow-xl`
- **Card**: `shadow-2xl`
## Border Radius
- **Buttons**: `rounded-full` (pill-shaped)
- **Cards**: `rounded-2xl`
- **Inputs**: `rounded-lg`
## Icon Colors
- **Primary**: `text-white` (on colored backgrounds)
- **Accent**: `text-purple-400`, `text-pink-400`
- **Muted**: `text-gray-400`
## Usage Examples
### Primary Button
```html
class="bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 text-white font-semibold py-4 px-8 rounded-full transition-all duration-300 transform hover:scale-105 shadow-lg"
``` ```
### Card Background ### Typography
```html ```css
class="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl overflow-hidden hover:transform hover:scale-105 transition-all duration-300 shadow-xl" /* Font families */
--font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
/* Font sizes */
--text-xs: 0.75rem; /* 12px */
--text-sm: 0.875rem; /* 14px */
--text-base: 1rem; /* 16px */
--text-lg: 1.125rem; /* 18px */
--text-xl: 1.25rem; /* 20px */
--text-2xl: 1.5rem; /* 24px */
--text-3xl: 1.875rem; /* 30px */
``` ```
### Hero Gradient ### Spacing
```html ```css
class="bg-gradient-to-br from-indigo-900 via-purple-800 to-pink-700" --space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
``` ```
### Glass Effect ## Component Rules
```html
class="bg-white bg-opacity-10 backdrop-blur-sm border border-white border-opacity-30" ### Buttons
```css
/* Primary button */
.btn-primary {
@apply bg-gradient-to-r from-purple-600 to-pink-600 text-white font-medium py-2 px-4 rounded-lg shadow-sm hover:shadow-md transition-all duration-200;
}
/* Secondary button */
.btn-secondary {
@apply bg-white text-purple-600 border border-purple-200 font-medium py-2 px-4 rounded-lg hover:bg-purple-50 transition-colors duration-200;
}
/* Destructive button */
.btn-destructive {
@apply bg-red-600 text-white font-medium py-2 px-4 rounded-lg shadow-sm hover:bg-red-700 transition-colors duration-200;
}
```
### Cards
```css
.card {
@apply bg-white rounded-lg shadow-sm border border-slate-200 p-6 hover:shadow-md transition-shadow duration-200;
}
.card-header {
@apply pb-4 border-b border-slate-200 mb-4;
}
.card-body {
@apply space-y-4;
}
```
### Forms
```css
.form-input {
@apply block w-full rounded-md border-slate-300 shadow-sm focus:border-purple-500 focus:ring-purple-500 sm:text-sm;
}
.form-label {
@apply block text-sm font-medium text-slate-700 mb-1;
}
.form-error {
@apply text-sm text-red-600 mt-1;
}
```
### Navigation
```css
.nav-link {
@apply text-slate-600 hover:text-purple-600 px-3 py-2 rounded-md text-sm font-medium transition-colors duration-200;
}
.nav-link-active {
@apply text-purple-600 bg-purple-50;
}
```
## Layout Rules
### Grid System
```css
.container {
@apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8;
}
.grid-responsive {
@apply grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6;
}
.grid-cards {
@apply grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6;
}
```
### Responsive Breakpoints
```css
/* Mobile-first approach */
@media (min-width: 640px) { /* sm */ }
@media (min-width: 768px) { /* md */ }
@media (min-width: 1024px) { /* lg */ }
@media (min-width: 1280px) { /* xl */ }
```
## Component States
### Hover States
```css
.hover-lift {
@apply transition-transform duration-200 hover:-translate-y-1;
}
.hover-glow {
@apply transition-all duration-200 hover:shadow-lg hover:shadow-purple-500/25;
}
```
### Focus States
```css
.focus-ring {
@apply focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2;
}
```
### Disabled States
```css
.disabled {
@apply opacity-50 cursor-not-allowed;
}
```
## Animation Rules
### Transitions
```css
.transition-fast {
@apply transition-all duration-150 ease-in-out;
}
.transition-normal {
@apply transition-all duration-200 ease-in-out;
}
.transition-slow {
@apply transition-all duration-300 ease-in-out;
}
```
### Micro-animations
```css
/* Subtle pulse for notifications */
.animate-pulse-subtle {
@apply animate-pulse;
animation-duration: 3s;
}
/* Gentle fade in */
.fade-in {
@apply animate-in fade-in-0 duration-500;
}
```
## Dark Mode Rules
### Dark mode color tokens
```css
@media (prefers-color-scheme: dark) {
:root {
--color-background: #0f172a;
--color-surface: #1e293b;
--color-border: #334155;
--color-text-primary: #f1f5f9;
--color-text-secondary: #cbd5e1;
--color-text-muted: #64748b;
}
}
```
### Dark mode components
```css
.dark .card {
@apply bg-slate-800 border-slate-700;
}
.dark .form-input {
@apply bg-slate-700 border-slate-600 text-white placeholder-slate-400;
}
```
## Accessibility Rules
### Focus Indicators
```css
.focus-visible {
@apply focus:outline-none focus-visible:ring-2 focus-visible:ring-purple-500 focus-visible:ring-offset-2;
}
```
### Color Contrast
```css
/* Ensure WCAG 2.1 AA compliance */
.text-primary {
@apply text-slate-900 dark:text-slate-100;
}
.text-secondary {
@apply text-slate-600 dark:text-slate-400;
}
```
## Naming Conventions
### CSS Classes
- Use kebab-case: `btn-primary`, `form-input`
- Prefix utilities with `u-`: `u-flex`, `u-text-sm`
- State modifiers: `is-active`, `has-error`
### JavaScript/React
- Components: PascalCase (`UserProfile.jsx`)
- Utilities: camelCase (`formatDate.js`)
- Constants: UPPER_SNAKE_CASE (`API_ENDPOINTS`)
### File Structure
```
app/javascript/
├── components/
│ ├── ui/ # Reusable UI components
│ ├── forms/ # Form-specific components
│ └── layouts/ # Layout components
├── lib/ # Utilities and helpers
└── controllers/ # Stimulus controllers
```