Design sign-in flow
This commit is contained in:
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m23.6 11.289-9.793-9.7a2.607 2.607 0 0 0-3.679.075 2.64 2.64 0 0 0-.068 3.689l3.871 3.714a.25.25 0 0 1-.173.43H2.135A2.28 2.28 0 0 0 .1 12c0 .815.448 2.51 2 2.51h11.679a.25.25 0 0 1 .177.427l-3.731 3.733a2.66 2.66 0 0 0 3.758 3.754l9.625-9.72a1 1 0 0 0-.008-1.415"/></svg>
|
||||
|
After Width: | Height: | Size: 341 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m23.888 5.832a.182.182 0 0 0 -.2.039l-9.747 9.745a2.75 2.75 0 0 1 -3.888 0l-9.743-9.745a.18.18 0 0 0 -.2-.039.182.182 0 0 0 -.11.168v12a2 2 0 0 0 2 2h20a2 2 0 0 0 2-2v-12a.181.181 0 0 0 -.112-.168z"/><path d="m11.115 14.556a1.252 1.252 0 0 0 1.768 0l9.686-9.686a.5.5 0 0 0 .121-.511c-.11-.329-.416-.359-.69-.359h-20c-.275 0-.583.03-.691.359a.5.5 0 0 0 .121.511z"/></svg>
|
||||
|
After Width: | Height: | Size: 439 B |
@@ -0,0 +1 @@
|
||||
<svg enable-background="new 0 0 24 24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12.2" cy="12.1" fill="#4183bf" r="9.3"/><path d="m17.9 17.4c-.3-.8-1-1.4-1.9-1.4h-1v-3c0-.6-.4-1-1-1h-6v-2h2c.6 0 1-.4 1-1v-2h2c1.1 0 2-.9 2-2v-.4c2.9 1.2 5 4.1 5 7.4 0 2.1-.8 4-2.1 5.4m-6.9 2.5c-3.9-.5-7-3.9-7-7.9 0-.6.1-1.2.2-1.8l4.8 4.8v1c0 1.1.9 2 2 2m1-16c-5.5 0-10 4.5-10 10s4.5 10 10 10 10-4.5 10-10-4.5-10-10-10z" fill="#40c149"/></svg>
|
||||
|
After Width: | Height: | Size: 450 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m17.508 18.5a1 1 0 0 0 -1 1v.5a.5.5 0 0 1 -.5.5h-5.5a.5.5 0 0 1 -.5-.5v-16a.5.5 0 0 1 .5-.5h5.5a.5.5 0 0 1 .5.5v1a1 1 0 0 0 2 0v-2.5a1 1 0 0 0 -1-1h-7.5v-1a.5.5 0 0 0 -.608-.488l-9 2a.5.5 0 0 0 -.392.488v19a.5.5 0 0 0 .392.489l9 2a.506.506 0 0 0 .421-.1.5.5 0 0 0 .187-.39v-1h7.5a1 1 0 0 0 1-1v-2a1 1 0 0 0 -1-.999zm-10-6a1.5 1.5 0 1 1 -1.5-1.5 1.5 1.5 0 0 1 1.5 1.5z"/><path d="m23.546 11.668-4.875-3.25a1 1 0 0 0 -1.554.832v1.75h-4.125a1.5 1.5 0 0 0 0 3h4.125v1.75a1 1 0 0 0 1.554.832l4.875-3.25a1 1 0 0 0 0-1.664z"/></svg>
|
||||
|
After Width: | Height: | Size: 594 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m21.5 2.5h-19-.00000011c-1.38071.00000006-2.5 1.11929-2.5 2.5v14 .00000038c.00000021 1.38071 1.11929 2.5 2.5 2.5h19 .00000011c1.38071-.00000027 2.5-1.11929 2.5-2.5v-14c0-1.38071-1.11929-2.5-2.5-2.5zm-.5 12.25h-4-.00000003c-.414214-.00000002-.75-.335786-.75-.75.00000002-.414214.335786-.75.75-.75h4-.00000003c.414214-.00000002.75.335786.75.75.00000002.414214-.335786.75-.75.75zm-6.469-1.28c.292711.292294.293049.766535.00075431 1.05925-.00025126.00025162-.0005027.00050305-.00075431.00075431l-.00000003.00000002c-.29683.283557-.76417.283557-1.061-.00000005l-1.293-1.293-.00000001-.00000001c-.0975674-.0972627-.255433-.0972627-.353.00000002l-1.293 1.293.00000001-.00000001c-.294501.28931-.766499.28931-1.061.00000002l.00000002.00000002c-.292711-.292294-.293049-.766535-.00075434-1.05925.00025126-.00025162.0005027-.00050305.00075431-.00075431l1.293-1.293.00000001-.00000001c.0977544-.0975076.0979545-.255799.00044687-.353553-.00014878-.00014915-.00029774-.00029812-.00044689-.00044689l-1.293-1.293-.00000005-.00000006c-.28762-.298073-.279147-.772871.0189256-1.06049.290776-.280579.751564-.280362 1.04207.00049142l1.293 1.293c.0975674.0972627.255433.0972627.353-.00000001l1.293-1.293.00000005-.00000005c.297801-.287901.772607-.279876 1.06051.0179256.280853.290511.28107.751299.00049121 1.04207l-1.293 1.293-.00000003.00000003c-.0977544.0975076-.0979544.255799-.00044684.353553.00014878.00014915.00029774.00029812.00044689.00044689zm-7 0c.292711.292294.293049.766535.00075431 1.05925-.00025126.00025162-.0005027.00050305-.00075431.00075431l.00000003-.00000003c-.294812.287593-.765187.287593-1.06.00000005l-1.294-1.293c-.0981335-.0968348-.255866-.0968348-.354 0l-1.293 1.293.00000001-.00000001c-.296698.282921-.763302.282921-1.06.00000002l.00000002.00000002c-.292711-.292294-.293049-.766535-.00075434-1.05925.00025126-.00025162.0005027-.00050305.00075431-.00075431l1.293-1.293c.0968348-.0981335.0968348-.255866-.00000001-.354l-1.293-1.293-.00000002-.00000002c-.282379-.303043-.265627-.777621.0374166-1.06.28803-.268389.734554-.268389 1.02258.00000004l1.293 1.293c.0981335.0968348.255866.0968348.354.00000001l1.293-1.293.00000002-.00000002c.303043-.282379.777621-.265627 1.06.0374166.268389.28803.268389.734554-.00000003 1.02258l-1.293 1.293c-.0968348.0981335-.0968348.255866 0 .354z"/></svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,12 @@
|
||||
/* Animation classes */
|
||||
.shake {
|
||||
animation: shake 400ms both;
|
||||
}
|
||||
|
||||
/* Keyframes */
|
||||
@keyframes shake {
|
||||
0% { transform: translateX(-2rem); }
|
||||
25% { transform: translateX(2rem); }
|
||||
50% { transform: translateX(-1rem); }
|
||||
75% { transform: translateX(1rem); }
|
||||
}
|
||||
@@ -32,17 +32,9 @@ body {
|
||||
|
||||
:where(#footer) {
|
||||
max-inline-size: 100vw;
|
||||
view-transition-name: footer;
|
||||
|
||||
> nav {
|
||||
padding-inline: var(--inline-space);
|
||||
view-transition-name: footer-nav;
|
||||
}
|
||||
|
||||
&:has(.new-book-btn) {
|
||||
inset-block-end: 0;
|
||||
pointer-events: none;
|
||||
position: sticky;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,19 +59,7 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
:where(#toolbar) {
|
||||
display: flex;
|
||||
inset: 0 0 auto;
|
||||
justify-content: center;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
padding-inline: var(--inline-space);
|
||||
position: sticky;
|
||||
view-transition-name: toolbar;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
:is(#header, #footer, #toolbar) {
|
||||
:is(#header, #footer) {
|
||||
@media print {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Language translations */
|
||||
.lanuage-list-menu {
|
||||
--max-width: 40ch;
|
||||
|
||||
background-color: var(--color-subtle);
|
||||
border: 1px solid var(--color-subtle-dark);
|
||||
border-radius: 0.5em;
|
||||
inset: auto;
|
||||
inline-size: max-content;
|
||||
margin-inline: var(--inline-space);
|
||||
max-inline-size: 40ch;
|
||||
overflow: clip;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
|
||||
@media (max-width: 70ch) {
|
||||
max-inline-size: calc(var(--max-width) - var(--inline-space));
|
||||
}
|
||||
|
||||
.popover-orientation-top & {
|
||||
inset-block-end: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.language-list {
|
||||
display: grid;
|
||||
gap: var(--block-space-half) var(--inline-space);
|
||||
grid-template-rows: min-content;
|
||||
grid-template-columns: min-content 1fr;
|
||||
justify-content: start;
|
||||
margin: 0;
|
||||
text-align: start;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
module TranslationsHelper
|
||||
TRANSLATIONS = {
|
||||
email_address: { "🇺🇸": "Enter your email address", "🇪🇸": "Introduce tu correo electrónico", "🇫🇷": "Entrez votre adresse courriel", "🇮🇳": "अपना ईमेल पता दर्ज करें", "🇩🇪": "Geben Sie Ihre E-Mail-Adresse ein", "🇧🇷": "Insira seu endereço de email" },
|
||||
password: { "🇺🇸": "Enter your password", "🇪🇸": "Introduce tu contraseña", "🇫🇷": "Saisissez votre mot de passe", "🇮🇳": "अपना पासवर्ड दर्ज करें", "🇩🇪": "Geben Sie Ihr Passwort ein", "🇧🇷": "Insira sua senha" }
|
||||
}
|
||||
|
||||
def translations_for(translation_key)
|
||||
tag.dl(class: "language-list") do
|
||||
TRANSLATIONS[translation_key].map do |language, translation|
|
||||
concat tag.dt(language)
|
||||
concat tag.dd(translation, class: "margin-none")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def translation_button(translation_key)
|
||||
tag.div(class: "position-relative", data: { controller: "popover", action: "keydown.esc->popover#close click@document->popover#closeOnClickOutside", popover_orientation_top_class: "popover-orientation-top" }) do
|
||||
tag.button(type: "button", class: "btn", tabindex: -1, data: { action: "popover#toggle" }) do
|
||||
concat image_tag("globe.svg", size: 20, role: "presentation", class: "color-icon")
|
||||
concat tag.span("Translate", class: "for-screen-reader")
|
||||
end +
|
||||
tag.dialog(class: "lanuage-list-menu popover shadow", data: { popover_target: "menu" }) do
|
||||
translations_for(translation_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
const BOTTOM_THRESHOLD = 0
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = [ "menu" ]
|
||||
static classes = [ "orientationTop" ]
|
||||
|
||||
close() {
|
||||
this.menuTarget.close()
|
||||
this.#orient()
|
||||
}
|
||||
|
||||
open() {
|
||||
this.menuTarget.show()
|
||||
this.#orient()
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this.menuTarget.open ? this.close() : this.open()
|
||||
}
|
||||
|
||||
closeOnClickOutside({ target }) {
|
||||
if (!this.element.contains(target)) this.close()
|
||||
}
|
||||
|
||||
#orient() {
|
||||
this.element.classList.toggle(this.orientationTopClass, this.#distanceToBottom < BOTTOM_THRESHOLD)
|
||||
this.menuTarget.style.setProperty("--max-width", this.#maxWidth + "px")
|
||||
}
|
||||
|
||||
get #distanceToBottom() {
|
||||
return window.innerHeight - this.#boundingClientRect.bottom
|
||||
}
|
||||
|
||||
get #maxWidth() {
|
||||
return window.innerWidth - this.#boundingClientRect.left
|
||||
}
|
||||
|
||||
get #boundingClientRect() {
|
||||
return this.menuTarget.getBoundingClientRect()
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,33 @@
|
||||
<%= form_with model: User.new, url: session_path do |f| %>
|
||||
<%= f.label :email_address %>
|
||||
<%= f.email_field :email_address %>
|
||||
<% content_for(:title) { "Sign in" } %>
|
||||
<% turbo_page_requires_reload %>
|
||||
|
||||
<%= f.label :password %>
|
||||
<%= f.password_field :password %>
|
||||
<div class="panel shadow center margin-block-double <%= "shake" if flash[:alert] %>" style="--panel-size: 40ch;">
|
||||
<%= image_tag "splat-1.svg", class: "product__logo center colorize--black", size: 130 %>
|
||||
<h1 class="margin-none-block-start margin-block-end-double">Splat</h1>
|
||||
|
||||
<%= f.submit "Sign in" %>
|
||||
<%= form_with model: User.new, url: session_path, class: "flex flex-column gap" do |form| %>
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button(:email_address) %>
|
||||
<label class="flex align-center gap input input--actor txt-large">
|
||||
<%= form.email_field :email_address, required: true, class: "input full-width", autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address] %>
|
||||
<%= image_tag "email.svg", aria: { hidden: "true" }, size: 30, class: "colorize--black" %>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button(:password) %>
|
||||
<label class="flex align-center gap input input--actor txt-large">
|
||||
<%= form.password_field :password, required: true, class: "input full-width", autocomplete: "current-password", placeholder: "Enter your password", maxlength: 72 %>
|
||||
<%= image_tag "password.svg", aria: { hidden: "true" }, size: 30, class: "colorize--black" %>
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" id="log_in" class="btn btn--reversed center">
|
||||
<%= image_tag "arrow-right.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Sign in</span>
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% content_for(:footer) do %>
|
||||
<div class="txt-align-center center margin-block-double txt-subtle">Splat™ version 0</div>
|
||||
<% end %>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<h1>Hello <%= Current.user.name %></h1>
|
||||
|
||||
<%= button_to "Sign out", session_path, method: :delete %>
|
||||
@@ -1,9 +1,9 @@
|
||||
<% content_for :header do %>
|
||||
<nav>
|
||||
<button class="btn flex-item-justify-start">
|
||||
<%= image_tag "settings.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Settings</span>
|
||||
</button>
|
||||
<%= button_to session_path, method: :delete, class: "btn", form_class: "flex-item-justify-start" do %>
|
||||
<%= image_tag "logout.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Sign out</span>
|
||||
<% end %>
|
||||
|
||||
<h1 class="txt-xx-large margin-none flex align-center gap-half">
|
||||
Splats
|
||||
|
||||
Reference in New Issue
Block a user