-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: Add Project Submissions With Hotwire (#3852)
Because: * We are converting project submissions from react to Hotwire. This commit: * Add Hotwire modal * Display project submissions form partial when within the modal when adding a project * Redesign the project submission form, modern styling and clearer privacy controls. * Prepend users and hide the add submission button with a turbo stream https://github.com/TheOdinProject/theodinproject/assets/7963776/592c6dcd-a426-4e24-b810-970715df4254
- Loading branch information
1 parent
3a25449
commit 552de31
Showing
28 changed files
with
314 additions
and
24 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
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,54 @@ | ||
<%= turbo_frame_tag 'modal' do %> | ||
<div | ||
class="relative z-10" | ||
aria-labelledby="modal-title" | ||
role="dialog" | ||
data-visibility-visible-value="true" | ||
aria-modal="true" | ||
data-controller="modal" | ||
data-action="turbo:submit-end->modal#submitEnd keydown.esc->modal#close"> | ||
|
||
<div | ||
class="fixed inset-0 bg-gray-500/75 dark:bg-black/70 transition-opacity" | ||
data-modal-target="transitionable" | ||
data-transition-enter="ease-out duration-300" | ||
data-transition-enter-start="opacity-0" | ||
data-transition-enter-end="opacity-100" | ||
data-transition-leave="ease-in duration200" | ||
data-transition-leave-start="opacity-100" | ||
data-transition-leave-end="opacity-0"> | ||
</div> | ||
|
||
<div class="fixed inset-0 z-10 overflow-y-auto"> | ||
<div class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0"> | ||
|
||
<div | ||
class="relative transform overflow-hidden rounded-lg bg-white dark:bg-gray-800 px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6" | ||
data-modal-target="transitionable" | ||
data-transition-enter="ease-out duration-300" | ||
data-transition-enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" | ||
data-transition-enter-end="opacity-100 translate-y-0 sm:scale-100" | ||
data-transition-leave="ease-in duration-200" | ||
data-transition-leave-start="opacity-100 translate-y-0 sm:scale-100" | ||
data-transition-leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"> | ||
|
||
<div class="absolute right-0 top-0 hidden pr-4 pt-4 sm:block"> | ||
<button type="button" data-action="click->visibility#off click->modal#close" class="rounded-md bg-white dark:bg-gray-800 text-gray-400 dark:text-gray-300 hover:text-gray-500 dark:hover:text-gray-400 focus:outline-none focus:ring-2 focus:ring-gold-500"> | ||
<span class="sr-only">Close</span> | ||
<%= inline_svg_tag 'icons/x.svg', class: 'h-6 w-6', aria: true, title: 'close', desc: 'close button' %> | ||
</button> | ||
</div> | ||
|
||
<div class="border-b border-gray-200 dark:border-gray-600 pb-5"> | ||
<h3 class="text-lg font-semibold leading-6 text-gray-900 dark:text-gray-300"><%= title %></h3> | ||
</div> | ||
|
||
<div class="flex"> | ||
<%= content %> | ||
</div> | ||
|
||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<% 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
class ModalComponent < ApplicationComponent | ||
def initialize(title:) | ||
@title = title | ||
end | ||
|
||
private | ||
|
||
attr_reader :title | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,10 @@ def initialize(item:) | |
@item = item | ||
end | ||
|
||
def render? | ||
item.present? | ||
end | ||
|
||
private | ||
|
||
attr_reader :item | ||
|
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 |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* eslint-disable class-methods-use-this */ | ||
import { Controller } from '@hotwired/stimulus'; | ||
import { enter, leave } from 'el-transition'; | ||
|
||
export default class ModalController extends Controller { | ||
static targets = ['transitionable']; | ||
|
||
connect() { | ||
this.lockScroll(); | ||
this.transitionableTargets.forEach((element) => enter(element)); | ||
} | ||
|
||
close() { | ||
Promise.all(this.transitionableTargets.map((element) => leave(element))).then(() => { | ||
this.element.parentElement.removeAttribute('src'); | ||
this.element.remove(); | ||
this.unlockScroll(); | ||
}); | ||
} | ||
|
||
submitEnd(event) { | ||
if (event.detail.success) { | ||
this.close(); | ||
} | ||
} | ||
|
||
lockScroll() { | ||
document.body.classList.add('overflow-hidden', 'pr-4'); | ||
} | ||
|
||
unlockScroll() { | ||
document.body.classList.remove('overflow-hidden', 'pr-4'); | ||
} | ||
} |
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
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
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,52 @@ | ||
<%= turbo_frame_tag 'project_submission_form', class: 'w-full' do %> | ||
<%= form_with url: lesson_v2_project_submissions_path(lesson.id), model: project_submission, builder: TailwindFormBuilder do |form| %> | ||
<div class='divide-y divide-gray-200 dark:divide-gray-600 space-y-6'> | ||
<div class="space-y-6 pt-4"> | ||
<div> | ||
<%= form.label :repo_url, 'GitHub repository' %> | ||
<%= form.text_field :repo_url, leading_icon: true, autofocus: true, class: 'text-sm', placeholder: 'http://github.com/user-name/repo-name', data: { test_id: 'repo-url-field' } do %> | ||
<%= inline_svg_tag 'socials/github.svg', class: 'h-5 w-5 text-gray-400', aria: true, title: 'Project GitHub repository', desc: 'GitHub icon' %> | ||
<% end %> | ||
</div> | ||
|
||
<div> | ||
<%= form.label :live_preview_url, 'Live preview (optional)' %> | ||
<%= form.text_field :live_preview_url, leading_icon: true, placeholder: 'http://example.com', class: 'text-sm', data: { test_id: 'live-preview-url-field' } do %> | ||
<%= inline_svg_tag 'icons/link.svg', class: 'h-5 w-5 text-gray-400', aria: true, title: 'Project live preview', desc: 'Link icon' %> | ||
<% end %> | ||
</div> | ||
|
||
<fieldset class="mt-2"> | ||
<legend class="text-sm font-medium leading-6 text-gray-900 dark:text-white">Privacy</legend> | ||
<div class="mt-2 space-y-4"> | ||
<div class="relative flex items-start"> | ||
<div class="absolute flex h-6 items-center"> | ||
<%= form.radio_button :is_public, true, class: 'h-4 w-4 border-gray-300 dark:border-gray-500 dark:bg-gray-700/50 dark:checked:bg-gold-600 dark:checked:border-gold-600 dark:focus:ring-offset-gray-800 text-gold-600 focus:ring-gold-600' %> | ||
</div> | ||
<div class="pl-7 text-sm leading-6"> | ||
<%= form.label :is_public_true, 'Public to other learners', class: 'dark:text-gray-200' %> | ||
<p class="text-gray-500 dark:text-gray-400">Anyone can see this project in the submissions list.</p> | ||
</div> | ||
</div> | ||
<div> | ||
<div class="relative flex items-start"> | ||
<div class="absolute flex h-6 items-center"> | ||
<%= form.radio_button :is_public, false, class: 'h-4 w-4 border-gray-300 dark:border-gray-500 dark:bg-gray-700/50 dark:checked:bg-gold-600 dark:checked:border-gold-600 dark:focus:ring-offset-gray-800 text-gold-600 focus:ring-gold-600' %> | ||
</div> | ||
<div class="pl-7 text-sm leading-6"> | ||
<%= form.label :is_public_false, 'Private to you' %> | ||
<p class="text-gray-500 dark:text-gray-400">Only you can see this project in the submissions list.</p> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</fieldset> | ||
</div> | ||
|
||
<div class="mt-5 sm:flex sm:flex-row-reverse pt-4"> | ||
<%= form.submit 'Save', class: 'cursor-pointer inline-flex w-full justify-center rounded-md button--primary px-5 py-2 text-sm font-semibold text-white shadow-sm sm:ml-3 sm:w-auto', data: { test_id: 'submit-btn' } %> | ||
<button type="button" data-action="click->modal#close" class="button--white mt-3 inline-flex w-full justify-center sm:mt-0 sm:w-auto">Cancel</button> | ||
</div> | ||
</div> | ||
<% end %> | ||
<% end %> |
5 changes: 5 additions & 0 deletions
5
app/views/lessons/v2_project_submissions/create.turbo_stream.erb
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,5 @@ | ||
<%= turbo_stream.prepend "submissions-list" do %> | ||
<%= render ProjectSubmissions::ItemComponent.new(item: @project_submission) %> | ||
<% end %> | ||
<%= turbo_stream.remove "add-submission-button" %> |
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 |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<%= render ModalComponent.new(title: 'Submit your project') do %> | ||
<%= render 'lessons/v2_project_submissions/form', lesson: @lesson, project_submission: @project_submission %> | ||
<% 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
2 changes: 1 addition & 1 deletion
2
spec/builders/__snapshots__/tailwind_form_builder/email_field.snap
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 +1 @@ | ||
<div class="mt-1 relative rounded-md shadow-sm"><input class="block w-full border rounded-md py-2 px-3 focus:outline-none dark:bg-gray-700/50 dark:border-gray-500 dark:text-gray-300 dark:placeholder-gray-400 dark:focus:ring-gray-500 dark:focus:ring-2 dark:focus:border-transparent border-gray-300 focus:ring-blue-600 focus:border-blue-600" type="email" value="" name="user[email]" id="user_email" /></div><div class="mt-2 text-sm text-red-600 dark:text-red-500 hidden"></div> | ||
<div class="mt-2 relative rounded-md shadow-sm"><input class="block w-full border rounded-md py-2 px-3 focus:outline-none dark:bg-gray-700/50 dark:border-gray-500 dark:text-gray-300 dark:placeholder-gray-400 dark:focus:ring-2 dark:focus:border-transparent border-gray-300 focus:ring-blue-600 focus:border-blue-600 dark:focus:ring-blue-400" type="email" value="" name="user[email]" id="user_email" /></div><div class="mt-2 text-sm text-red-600 dark:text-red-500 hidden"></div> |
2 changes: 1 addition & 1 deletion
2
spec/builders/__snapshots__/tailwind_form_builder/password_field.snap
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 +1 @@ | ||
<div class="mt-1 relative rounded-md shadow-sm"><input class="block w-full border rounded-md py-2 px-3 focus:outline-none dark:bg-gray-700/50 dark:border-gray-500 dark:text-gray-300 dark:placeholder-gray-400 dark:focus:ring-gray-500 dark:focus:ring-2 dark:focus:border-transparent border-gray-300 focus:ring-blue-600 focus:border-blue-600" type="password" name="user[password]" id="user_password" /></div><div class="mt-2 text-sm text-red-600 dark:text-red-500 hidden"></div> | ||
<div class="mt-2 relative rounded-md shadow-sm"><input class="block w-full border rounded-md py-2 px-3 focus:outline-none dark:bg-gray-700/50 dark:border-gray-500 dark:text-gray-300 dark:placeholder-gray-400 dark:focus:ring-2 dark:focus:border-transparent border-gray-300 focus:ring-blue-600 focus:border-blue-600 dark:focus:ring-blue-400" type="password" name="user[password]" id="user_password" /></div><div class="mt-2 text-sm text-red-600 dark:text-red-500 hidden"></div> |
2 changes: 1 addition & 1 deletion
2
spec/builders/__snapshots__/tailwind_form_builder/text_area.snap
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,2 +1,2 @@ | ||
<div class="mt-1 relative rounded-md shadow-sm"><textarea class="mt-1 block w-full border rounded-md py-2 px-3 focus:outline-none dark:bg-gray-700/50 dark:border-gray-500 dark:text-gray-300 dark:placeholder-gray-400 dark:focus:ring-gray-500 dark:focus:ring-2 dark:focus:border-transparent border-gray-300 focus:ring-blue-600 focus:border-blue-600" name="user[username]" id="user_username"> | ||
<div class="mt-2 relative rounded-md shadow-sm"><textarea class="mt-1 block w-full border rounded-md py-2 px-3 focus:outline-none dark:bg-gray-700/50 dark:border-gray-500 dark:text-gray-300 dark:placeholder-gray-400 dark:focus:ring-2 dark:focus:border-transparent border-gray-300 focus:ring-blue-600 focus:border-blue-600 dark:focus:ring-blue-400" name="user[username]" id="user_username"> | ||
</textarea></div><div class="mt-2 text-sm text-red-600 dark:text-red-500 hidden"></div> |
2 changes: 1 addition & 1 deletion
2
spec/builders/__snapshots__/tailwind_form_builder/text_field.snap
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 +1 @@ | ||
<div class="mt-1 relative rounded-md shadow-sm"><input class="block w-full border rounded-md py-2 px-3 focus:outline-none dark:bg-gray-700/50 dark:border-gray-500 dark:text-gray-300 dark:placeholder-gray-400 dark:focus:ring-gray-500 dark:focus:ring-2 dark:focus:border-transparent border-gray-300 focus:ring-blue-600 focus:border-blue-600" type="text" name="user[username]" id="user_username" /></div><div class="mt-2 text-sm text-red-600 dark:text-red-500 hidden"></div> | ||
<div class="mt-2 relative rounded-md shadow-sm"><input class="block w-full border rounded-md py-2 px-3 focus:outline-none dark:bg-gray-700/50 dark:border-gray-500 dark:text-gray-300 dark:placeholder-gray-400 dark:focus:ring-2 dark:focus:border-transparent border-gray-300 focus:ring-blue-600 focus:border-blue-600 dark:focus:ring-blue-400" type="text" name="user[username]" id="user_username" /></div><div class="mt-2 text-sm text-red-600 dark:text-red-500 hidden"></div> |
Oops, something went wrong.