basecoat 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.idea/.gitignore +8 -0
  3. data/.idea/basecoat.iml +17 -0
  4. data/.idea/misc.xml +4 -0
  5. data/.idea/modules.xml +8 -0
  6. data/.idea/vcs.xml +6 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +194 -0
  9. data/Rakefile +4 -0
  10. data/lib/basecoat/railtie.rb +11 -0
  11. data/lib/basecoat/version.rb +5 -0
  12. data/lib/basecoat.rb +8 -0
  13. data/lib/generators/basecoat/templates/application.html.erb +16 -0
  14. data/lib/generators/basecoat/templates/devise/confirmations/new.html.erb +27 -0
  15. data/lib/generators/basecoat/templates/devise/mailer/confirmation_instructions.html.erb +5 -0
  16. data/lib/generators/basecoat/templates/devise/mailer/email_changed.html.erb +7 -0
  17. data/lib/generators/basecoat/templates/devise/mailer/password_change.html.erb +3 -0
  18. data/lib/generators/basecoat/templates/devise/mailer/reset_password_instructions.html.erb +8 -0
  19. data/lib/generators/basecoat/templates/devise/mailer/unlock_instructions.html.erb +7 -0
  20. data/lib/generators/basecoat/templates/devise/passwords/edit.html.erb +40 -0
  21. data/lib/generators/basecoat/templates/devise/passwords/new.html.erb +31 -0
  22. data/lib/generators/basecoat/templates/devise/registrations/edit.html.erb +63 -0
  23. data/lib/generators/basecoat/templates/devise/registrations/new.html.erb +40 -0
  24. data/lib/generators/basecoat/templates/devise/sessions/new.html.erb +38 -0
  25. data/lib/generators/basecoat/templates/devise/shared/_error_messages.html.erb +15 -0
  26. data/lib/generators/basecoat/templates/devise/shared/_links.html.erb +27 -0
  27. data/lib/generators/basecoat/templates/devise/unlocks/new.html.erb +29 -0
  28. data/lib/generators/basecoat/templates/devise.html.erb +36 -0
  29. data/lib/generators/basecoat/templates/layouts/_alert.html.erb +6 -0
  30. data/lib/generators/basecoat/templates/layouts/_aside.html.erb +21 -0
  31. data/lib/generators/basecoat/templates/layouts/_form_errors.html.erb +13 -0
  32. data/lib/generators/basecoat/templates/layouts/_head.html.erb +21 -0
  33. data/lib/generators/basecoat/templates/layouts/_header.html.erb +12 -0
  34. data/lib/generators/basecoat/templates/layouts/_notice.html.erb +18 -0
  35. data/lib/generators/basecoat/templates/pagy.scss +31 -0
  36. data/lib/generators/basecoat/templates/passwords/edit.html.erb +30 -0
  37. data/lib/generators/basecoat/templates/passwords/new.html.erb +25 -0
  38. data/lib/generators/basecoat/templates/scaffold_hook.rb +36 -0
  39. data/lib/generators/basecoat/templates/sessions/new.html.erb +30 -0
  40. data/lib/generators/basecoat/templates/sessions.html.erb +36 -0
  41. data/lib/tasks/basecoat.rake +281 -0
  42. data/lib/templates/erb/scaffold/_form.html.erb.tt +43 -0
  43. data/lib/templates/erb/scaffold/edit.html.erb.tt +21 -0
  44. data/lib/templates/erb/scaffold/index.html.erb.tt +35 -0
  45. data/lib/templates/erb/scaffold/new.html.erb.tt +20 -0
  46. data/lib/templates/erb/scaffold/partial.html.erb.tt +20 -0
  47. data/lib/templates/erb/scaffold/show.html.erb.tt +23 -0
  48. data/sig/basecoat.rbs +4 -0
  49. metadata +104 -0
@@ -0,0 +1,29 @@
1
+
2
+
3
+ <div class="container mx-auto px-4 py-8">
4
+ <div class="max-w-2xl mx-auto">
5
+ <div class="card">
6
+ <header>
7
+ <h2>Resend unlock instructions</h2>
8
+ <p>Enter your email address to receive unlock instructions.</p>
9
+ </header>
10
+ <section class="space-y-4">
11
+ <%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post, class: "grid gap-6" }) do |f| %>
12
+ <%= render "devise/shared/error_messages", resource: resource %>
13
+
14
+ <div class="grid gap-3">
15
+ <%= f.label :email, class: "label" %>
16
+ <%= f.email_field :email, autofocus: true, autocomplete: "email", class: "input" %>
17
+ </div>
18
+
19
+ <div class="grid gap-3">
20
+ <%= f.submit "Resend unlock instructions", class: "btn" %>
21
+ </div>
22
+ <% end %>
23
+ </section>
24
+ </div>
25
+ <div class="mt-6">
26
+ <%= render "devise/shared/links" %>
27
+ </div>
28
+ </div>
29
+ </div>
@@ -0,0 +1,36 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <%= render "layouts/head" %>
4
+ <body class="dark">
5
+ <%= render 'layouts/notice', notice: notice if notice %>
6
+ <div class="grid min-h-svh lg:grid-cols-2">
7
+ <div class="flex flex-col gap-4 p-6 md:p-10">
8
+ <div class="flex justify-between items-center gap-2">
9
+ <a href="#" class="flex items-center gap-2 font-medium">
10
+ <div class="bg-primary text-primary-foreground flex size-6 items-center justify-center rounded-md">
11
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" class="h-4 w-4"><rect width="256" height="256" fill="none"></rect><line x1="208" y1="128" x2="128" y2="208" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></line><line x1="192" y1="40" x2="40" y2="192" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></line></svg>
12
+ </div>
13
+ Basecoat
14
+ </a>
15
+ <button type="button" aria-label="Toggle dark mode" data-tooltip="Toggle dark mode" data-side="left" onclick="document.dispatchEvent(new CustomEvent('basecoat:theme'))" class="btn-icon-outline size-8">
16
+ <span class="hidden dark:block"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2"></path><path d="M12 20v2"></path><path d="m4.93 4.93 1.41 1.41"></path><path d="m17.66 17.66 1.41 1.41"></path><path d="M2 12h2"></path><path d="M20 12h2"></path><path d="m6.34 17.66-1.41 1.41"></path><path d="m19.07 4.93-1.41 1.41"></path></svg></span>
17
+ <span class="block dark:hidden"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path></svg></span>
18
+ </button>
19
+ </div>
20
+ <%= render 'layouts/alert', alert: alert if alert %>
21
+
22
+ <div class="flex flex-1 items-center justify-center">
23
+
24
+ <div class="w-full max-w-xs">
25
+ <%= yield %>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ <div class="bg-muted relative hidden lg:block">
30
+ <svg class="absolute inset-0 h-full w-full object-cover dark:brightness-[0.2] dark:grayscale" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
31
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M33.2503 38.4816C33.2603 37.0472 34.4199 35.8864 35.8543 35.875H83.1463C84.5848 35.875 85.7503 37.0431 85.7503 38.4816V80.5184C85.7403 81.9528 84.5807 83.1136 83.1463 83.125H35.8543C34.4158 83.1236 33.2503 81.957 33.2503 80.5184V38.4816ZM80.5006 41.1251H38.5006V77.8751L62.8921 53.4783C63.9172 52.4536 65.5788 52.4536 66.6039 53.4783L80.5006 67.4013V41.1251ZM43.75 51.6249C43.75 54.5244 46.1005 56.8749 49 56.8749C51.8995 56.8749 54.25 54.5244 54.25 51.6249C54.25 48.7254 51.8995 46.3749 49 46.3749C46.1005 46.3749 43.75 48.7254 43.75 51.6249Z" fill="#687787"/>
32
+ </svg>
33
+ </div>
34
+ </div>
35
+ </body>
36
+ </html>
@@ -0,0 +1,6 @@
1
+ <div class="alert-destructive max-w-2xl mx-auto" data-turbo-cache="false">
2
+ <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
3
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
4
+ </svg>
5
+ <h2><%= alert %></h2>
6
+ </div>
@@ -0,0 +1,21 @@
1
+ <aside class="sidebar" data-side="left" aria-hidden="false">
2
+ <nav aria-label="Sidebar navigation">
3
+ <header>
4
+ <a href="/" class="btn-ghost p-2 h-12 w-full justify-start" aria-current="page">
5
+ <div class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg">
6
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" class="h-4 w-4"><rect width="256" height="256" fill="none"></rect><line x1="208" y1="128" x2="128" y2="208" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></line><line x1="192" y1="40" x2="40" y2="192" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></line></svg>
7
+ </div>
8
+ <div class="grid flex-1 text-left text-sm leading-tight">
9
+ <span class="truncate font-medium">Basecoat</span>
10
+ <span class="truncate text-xs">v0.0.1</span>
11
+ </div>
12
+ </a>
13
+ </header>
14
+ <section class="scrollbar">
15
+ <div role="group" aria-labelledby="group-label-content-1">
16
+ <ul>
17
+ </ul>
18
+ </div>
19
+ </section>
20
+ </nav>
21
+ </aside>
@@ -0,0 +1,13 @@
1
+ <div class="alert-destructive max-w-2xl mx-auto">
2
+ <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
3
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
4
+ </svg>
5
+ <h2><%= pluralize(object.errors.count, "error") %> prohibited this object from being saved</h2>
6
+ <section>
7
+ <ul>
8
+ <% object.errors.each do |error| %>
9
+ <li><%= error.full_message %></li>
10
+ <% end %>
11
+ </ul>
12
+ </section>
13
+ </div>
@@ -0,0 +1,21 @@
1
+ <head>
2
+ <title><%= content_for(:title) || "Base" %></title>
3
+ <meta name="viewport" content="width=device-width,initial-scale=1">
4
+ <meta name="apple-mobile-web-app-capable" content="yes">
5
+ <meta name="mobile-web-app-capable" content="yes">
6
+ <%= csrf_meta_tags %>
7
+ <%= csp_meta_tag %>
8
+
9
+ <%= yield :head %>
10
+
11
+ <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %>
12
+ <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %>
13
+
14
+ <link rel="icon" href="/icon.png" type="image/png">
15
+ <link rel="icon" href="/icon.svg" type="image/svg+xml">
16
+ <link rel="apple-touch-icon" href="/icon.png">
17
+
18
+ <%# Includes all stylesheet files in app/assets/stylesheets %>
19
+ <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
20
+ <%= javascript_importmap_tags %>
21
+ </head>
@@ -0,0 +1,12 @@
1
+ <header class="bg-background sticky inset-x-0 top-0 isolate flex shrink-0 items-center gap-2 border-b z-10 px-4">
2
+ <div class="flex h-14 flex-1 items-center gap-2">
3
+ <button type="button" onclick="document.dispatchEvent(new CustomEvent('basecoat:sidebar'))" aria-label="Toggle sidebar" data-tooltip="Toggle sidebar" data-side="bottom" data-align="start" class="btn-sm-icon-ghost mr-auto size-7 -ml-1.5">
4
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"></rect><path d="M9 3v18"></path></svg>
5
+ </button>
6
+ <button type="button" aria-label="Toggle dark mode" data-tooltip="Toggle dark mode" data-side="left" onclick="document.dispatchEvent(new CustomEvent('basecoat:theme'))" class="btn-icon-outline size-8">
7
+ <span class="hidden dark:block"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2"></path><path d="M12 20v2"></path><path d="m4.93 4.93 1.41 1.41"></path><path d="m17.66 17.66 1.41 1.41"></path><path d="M2 12h2"></path><path d="M20 12h2"></path><path d="m6.34 17.66-1.41 1.41"></path><path d="m19.07 4.93-1.41 1.41"></path></svg></span>
8
+ <span class="block dark:hidden"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path></svg></span>
9
+ </button>
10
+ <!-- DEVISE_USER_DROPDOWN -->
11
+ </div>
12
+ </header>
@@ -0,0 +1,18 @@
1
+ <div id="toaster" class="toaster">
2
+ <div class="toast" role="status" aria-atomic="true" aria-hidden="false" data-category="success">
3
+ <div class="toast-content">
4
+ <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
5
+ <circle cx="12" cy="12" r="10" />
6
+ <path d="m9 12 2 2 4-4" />
7
+ </svg>
8
+
9
+ <section>
10
+ <h2><%= notice %></h2>
11
+ </section>
12
+
13
+ <footer>
14
+ <button type="button" class="btn" data-toast-cancel>Dismiss</button>
15
+ </footer>
16
+ </div>
17
+ </div>
18
+ </div>
@@ -0,0 +1,31 @@
1
+ .pagy.nav {
2
+ @apply py-6 flex w-full justify-center flex-row items-center gap-1;
3
+
4
+ a {
5
+ @apply inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors;
6
+ @apply focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring;
7
+ @apply disabled:pointer-events-none disabled:opacity-50;
8
+ @apply h-9 w-9;
9
+ @apply hover:bg-accent hover:text-accent-foreground;
10
+
11
+ &[aria-current="page"],
12
+ &.current {
13
+ @apply border border-input bg-background shadow-sm;
14
+ @apply hover:bg-accent hover:text-accent-foreground;
15
+ }
16
+
17
+ &[aria-label="Previous"],
18
+ &[aria-label="Next"] {
19
+ @apply h-9 px-3 w-auto;
20
+ @apply hover:bg-accent hover:text-accent-foreground;
21
+ }
22
+
23
+ &[aria-disabled="true"] {
24
+ @apply opacity-50 cursor-not-allowed;
25
+
26
+ &:not([aria-current="page"]):not(.current) {
27
+ pointer-events: none;
28
+ }
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,30 @@
1
+ <div class="container mx-auto px-4 py-8">
2
+ <div class="max-w-2xl mx-auto">
3
+ <div class="card">
4
+ <header>
5
+ <h2>Update your password</h2>
6
+ <p>Enter your new password below.</p>
7
+ </header>
8
+ <section class="space-y-4">
9
+ <%= form_with url: password_path(params[:token]), method: :put, html: { class: "grid gap-6" } do |form| %>
10
+ <div class="grid gap-3">
11
+ <%= form.label :password, "New password", class: "label" %>
12
+ <%= form.password_field :password, required: true, autocomplete: "new-password", maxlength: 72, class: "input" %>
13
+ </div>
14
+
15
+ <div class="grid gap-3">
16
+ <%= form.label :password_confirmation, "Confirm password", class: "label" %>
17
+ <%= form.password_field :password_confirmation, required: true, autocomplete: "new-password", maxlength: 72, class: "input" %>
18
+ </div>
19
+
20
+ <div class="grid gap-2">
21
+ <%= form.submit "Update password", class: "btn" %>
22
+ </div>
23
+ <% end %>
24
+ </section>
25
+ </div>
26
+ <div class="mt-6 text-center">
27
+ <%= link_to "Back to sign in", new_session_path, class: "text-sm hover:underline" %>
28
+ </div>
29
+ </div>
30
+ </div>
@@ -0,0 +1,25 @@
1
+ <div class="container mx-auto px-4 py-8">
2
+ <div class="max-w-2xl mx-auto">
3
+ <div class="card">
4
+ <header>
5
+ <h2>Forgot your password?</h2>
6
+ <p>Enter your email address and we'll send you instructions to reset your password.</p>
7
+ </header>
8
+ <section class="space-y-4">
9
+ <%= form_with url: passwords_path, html: { class: "grid gap-6" } do |form| %>
10
+ <div class="grid gap-3">
11
+ <%= form.label :email_address, "Email", class: "label" %>
12
+ <%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", value: params[:email_address], class: "input" %>
13
+ </div>
14
+
15
+ <div class="grid gap-2">
16
+ <%= form.submit "Email reset instructions", class: "btn" %>
17
+ </div>
18
+ <% end %>
19
+ </section>
20
+ </div>
21
+ <div class="mt-6 text-center">
22
+ <%= link_to "Back to sign in", new_session_path, class: "text-sm hover:underline" %>
23
+ </div>
24
+ </div>
25
+ </div>
@@ -0,0 +1,36 @@
1
+ begin
2
+ require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
3
+
4
+ module ScaffoldControllerGeneratorPatch
5
+ def create_controller_files
6
+ super
7
+ add_to_sidebar
8
+ end
9
+
10
+ def add_to_sidebar
11
+ aside_path = 'app/views/layouts/_aside.html.erb'
12
+ return unless File.exist?(aside_path)
13
+
14
+ link_html = <<~HTML
15
+ <li>
16
+ <%= link_to #{plural_table_name}_path, data: { turbo_frame: "main_content", turbo_action: "advance" } do %>
17
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
18
+ <path d="m7 11 2-2-2-2" />
19
+ <path d="M11 13h4" />
20
+ <rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
21
+ </svg>
22
+ <span>#{human_name.pluralize}</span>
23
+ <% end %>
24
+ </li>
25
+
26
+ HTML
27
+
28
+ inject_into_file aside_path, link_html, before: /\s*<\/ul>/
29
+ say "Added #{human_name.pluralize} to sidebar", :green
30
+ end
31
+ end
32
+
33
+ Rails::Generators::ScaffoldControllerGenerator.prepend(ScaffoldControllerGeneratorPatch)
34
+ rescue LoadError, NameError
35
+ # Generators not loaded, skip this initializer
36
+ end
@@ -0,0 +1,30 @@
1
+ <div class="container mx-auto px-4 py-8">
2
+ <div class="max-w-2xl mx-auto">
3
+ <div class="card">
4
+ <header>
5
+ <h2>Sign in</h2>
6
+ <p>Sign in to your account to continue.</p>
7
+ </header>
8
+ <section class="space-y-4">
9
+ <%= form_with url: session_url, html: { class: "grid gap-6" } do |form| %>
10
+ <div class="grid gap-3">
11
+ <%= form.label :email_address, "Email", class: "label" %>
12
+ <%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", value: params[:email_address], class: "input" %>
13
+ </div>
14
+
15
+ <div class="grid gap-3">
16
+ <%= form.label :password, class: "label" %>
17
+ <%= form.password_field :password, required: true, autocomplete: "current-password", maxlength: 72, class: "input" %>
18
+ </div>
19
+
20
+ <div class="grid gap-2">
21
+ <%= form.submit "Sign in", class: "btn" %>
22
+ </div>
23
+ <% end %>
24
+ </section>
25
+ </div>
26
+ <div class="mt-6 text-center">
27
+ <%= link_to "Forgot password?", new_password_path, class: "text-sm hover:underline" %>
28
+ </div>
29
+ </div>
30
+ </div>
@@ -0,0 +1,36 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <%= render "layouts/head" %>
4
+ <body class="dark">
5
+ <%= render 'layouts/notice', notice: notice if notice %>
6
+ <div class="grid min-h-svh lg:grid-cols-2">
7
+ <div class="flex flex-col gap-4 p-6 md:p-10">
8
+ <div class="flex justify-between items-center gap-2">
9
+ <a href="#" class="flex items-center gap-2 font-medium">
10
+ <div class="bg-primary text-primary-foreground flex size-6 items-center justify-center rounded-md">
11
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" class="h-4 w-4"><rect width="256" height="256" fill="none"></rect><line x1="208" y1="128" x2="128" y2="208" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></line><line x1="192" y1="40" x2="40" y2="192" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></line></svg>
12
+ </div>
13
+ Basecoat
14
+ </a>
15
+ <button type="button" aria-label="Toggle dark mode" data-tooltip="Toggle dark mode" data-side="left" onclick="document.dispatchEvent(new CustomEvent('basecoat:theme'))" class="btn-icon-outline size-8">
16
+ <span class="hidden dark:block"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2"></path><path d="M12 20v2"></path><path d="m4.93 4.93 1.41 1.41"></path><path d="m17.66 17.66 1.41 1.41"></path><path d="M2 12h2"></path><path d="M20 12h2"></path><path d="m6.34 17.66-1.41 1.41"></path><path d="m19.07 4.93-1.41 1.41"></path></svg></span>
17
+ <span class="block dark:hidden"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path></svg></span>
18
+ </button>
19
+ </div>
20
+ <%= render 'layouts/alert', alert: alert if alert %>
21
+
22
+ <div class="flex flex-1 items-center justify-center">
23
+
24
+ <div class="w-full max-w-xs">
25
+ <%= yield %>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ <div class="bg-muted relative hidden lg:block">
30
+ <svg class="absolute inset-0 h-full w-full object-cover dark:brightness-[0.2] dark:grayscale" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
31
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M33.2503 38.4816C33.2603 37.0472 34.4199 35.8864 35.8543 35.875H83.1463C84.5848 35.875 85.7503 37.0431 85.7503 38.4816V80.5184C85.7403 81.9528 84.5807 83.1136 83.1463 83.125H35.8543C34.4158 83.1236 33.2503 81.957 33.2503 80.5184V38.4816ZM80.5006 41.1251H38.5006V77.8751L62.8921 53.4783C63.9172 52.4536 65.5788 52.4536 66.6039 53.4783L80.5006 67.4013V41.1251ZM43.75 51.6249C43.75 54.5244 46.1005 56.8749 49 56.8749C51.8995 56.8749 54.25 54.5244 54.25 51.6249C54.25 48.7254 51.8995 46.3749 49 46.3749C46.1005 46.3749 43.75 48.7254 43.75 51.6249Z" fill="#687787"/>
32
+ </svg>
33
+ </div>
34
+ </div>
35
+ </body>
36
+ </html>