diff --git a/.gitignore b/.gitignore index a8d1ff4..7de53ac 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,9 @@ /config/*.key .idea/ + +/app/assets/builds/* +!/app/assets/builds/.keep + +node_modules +package*.json \ No newline at end of file diff --git a/Gemfile b/Gemfile index 6d7497f..b07ef10 100644 --- a/Gemfile +++ b/Gemfile @@ -64,3 +64,5 @@ group :test do gem "capybara" gem "selenium-webdriver" end + +gem "tailwindcss-rails", "~> 4.3" diff --git a/Gemfile.lock b/Gemfile.lock index fdd9d9f..e2a01ec 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -344,6 +344,15 @@ GEM stimulus-rails (1.3.4) railties (>= 6.0.0) stringio (3.1.7) + tailwindcss-rails (4.3.0) + railties (>= 7.0.0) + tailwindcss-ruby (~> 4.0) + tailwindcss-ruby (4.1.13) + tailwindcss-ruby (4.1.13-aarch64-linux-gnu) + tailwindcss-ruby (4.1.13-aarch64-linux-musl) + tailwindcss-ruby (4.1.13-arm64-darwin) + tailwindcss-ruby (4.1.13-x86_64-linux-gnu) + tailwindcss-ruby (4.1.13-x86_64-linux-musl) thor (1.4.0) thruster (0.1.16) thruster (0.1.16-aarch64-linux) @@ -406,6 +415,7 @@ DEPENDENCIES solid_queue sqlite3 (>= 2.1) stimulus-rails + tailwindcss-rails (~> 4.3) thruster turbo-rails tzinfo-data diff --git a/Procfile.dev b/Procfile.dev new file mode 100644 index 0000000..da151fe --- /dev/null +++ b/Procfile.dev @@ -0,0 +1,2 @@ +web: bin/rails server +css: bin/rails tailwindcss:watch diff --git a/app/assets/builds/.keep b/app/assets/builds/.keep new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/tailwind/application.css b/app/assets/tailwind/application.css new file mode 100644 index 0000000..f1d8c73 --- /dev/null +++ b/app/assets/tailwind/application.css @@ -0,0 +1 @@ +@import "tailwindcss"; diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 31a9ca8..bf8cc0a 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -12,7 +12,7 @@ class TodosController < ApplicationController # GET /todos/new def new - @todo = Todo.new + @todo = Todo.new(project_id: params[:project_id]) end # GET /todos/1/edit diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 3a65097..127598b 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -24,9 +24,23 @@ - <% if flash[:notice] %> -

<%= flash[:notice] %>

- <% end %> - <%= yield %> +
+
+ <%= link_to "Doable", root_path, class: "text-3xl text-indigo-600 font-extrabold" %> + +
+
+
+ <% if flash[:notice] %> +

<%= flash[:notice] %>

+ <% end %> + <%= yield %> +
+ diff --git a/app/views/projects/_form.html.erb b/app/views/projects/_form.html.erb index 2f17c84..a96dbfc 100644 --- a/app/views/projects/_form.html.erb +++ b/app/views/projects/_form.html.erb @@ -1,21 +1,47 @@ -<%= form_with model: project do |f| %> +<%= form_with model: project, class: "space-y-6" do |f| %> <% if project.errors.any? %> -
-

<%= pluralize(project.errors.count, "error") %> prohibited this project from being saved:

- +
+
+
+ + + +
+
+

+ <%= pluralize(project.errors.count, "error") %> prohibited this project from being saved: +

+
+
    + <% project.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+
+
<% end %> -
- <%= f.label :name %> - <%= f.text_field :name %> +
+ <%= f.label :name, class: "block text-sm font-medium text-gray-700" %> +
+ <%= f.text_field :name, class: "shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md" %> +
-
- <%= f.submit %> +
+ <%= f.label :active, class: "block text-sm font-medium text-gray-700" %> +
+ <%= f.check_box :active, class: "h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded" %> + Mark as active +
-<% end %> + +
+
+ <%= link_to "Cancel", projects_path, class: "bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %> + <%= f.submit class: "ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm 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-indigo-500" %> +
+
+<% end %> \ No newline at end of file diff --git a/app/views/projects/edit.html.erb b/app/views/projects/edit.html.erb index b2347e9..24222e1 100644 --- a/app/views/projects/edit.html.erb +++ b/app/views/projects/edit.html.erb @@ -1,3 +1,17 @@ -

Edit Project

- -<%= render "form", project: @project %> +
+
+
+

Edit Project

+

+ Update your project's details. +

+
+
+
+
+
+ <%= render "form", project: @project %> +
+
+
+
\ No newline at end of file diff --git a/app/views/projects/index.html.erb b/app/views/projects/index.html.erb index 80801d7..a65d535 100644 --- a/app/views/projects/index.html.erb +++ b/app/views/projects/index.html.erb @@ -1,6 +1,40 @@ -

Projects

+
+

Projects

+ <%= link_to "New Project", new_project_path, class: "px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition-colors" %> +
-<% @projects.each do |project| %> -
  • <%= link_to project.name, project_path(project) %>
  • -<% end %> -

    <%= link_to "New project", new_project_path %>

    \ No newline at end of file +
    + <% @projects.each do |project| %> +
    +
    +

    + <%= project.name %> +

    + +
    + + + + <%= project.todos.count %> <%= "Todo".pluralize(project.todos.count) %> +
    + +
    + <%= link_to "View Project", project_path(project), class: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-indigo-700 bg-indigo-100 hover:bg-indigo-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %> +
    +
    +
    + <% end %> +
    + +<% if @projects.empty? %> +
    + + + +

    No projects

    +

    Get started by creating a new project.

    +
    + <%= link_to "New Project", new_project_path, class: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %> +
    +
    +<% end %> \ No newline at end of file diff --git a/app/views/projects/new.html.erb b/app/views/projects/new.html.erb index 23ac254..be83e6d 100644 --- a/app/views/projects/new.html.erb +++ b/app/views/projects/new.html.erb @@ -1,3 +1,17 @@ -

    New project

    - -<%= render "form", project: @project %> +
    +
    +
    +

    New Project

    +

    + Create a new project to organize your todos. +

    +
    +
    +
    +
    +
    + <%= render "form", project: @project %> +
    +
    +
    +
    \ No newline at end of file diff --git a/app/views/projects/show.html.erb b/app/views/projects/show.html.erb index af03c54..64c6f76 100644 --- a/app/views/projects/show.html.erb +++ b/app/views/projects/show.html.erb @@ -1,9 +1,95 @@ -

    <%= @project.name %>

    +
    +
    +
    +

    <%= @project.name %>

    +
    + <%= link_to edit_project_path(@project), class: "text-gray-400 hover:text-gray-500" do %> + + + + <% end %> +
    +
    + <% if @project.active? %> + + Active + + <% else %> + + Inactive + + <% end %> +
    +
    -<% @project.todos.each do |todo| %> -
  • <%= link_to todo.name, todo_path(todo) %>
  • +
    +

    Todos for this project

    + <%= link_to new_todo_path(project_id: @project.id), class: "inline-flex items-center px-4 py-2 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-indigo-500" do %> + + + + Add Todo + <% end %> +
    + +<% if @project.todos.any? %> +
    +
      + <% @project.todos.each do |todo| %> +
    • +
      +
      +
      +
      + <% if todo.completed %> + + + + + + <% else %> + + <% end %> +
      +

      <%= link_to todo.name, todo_path(todo) %>

      +

      <%= truncate(todo.description, length: 100) %>

      +
      +
      +
      +
      + <% if todo.priority && todo.priority > 0 %> + + Priority: <%= todo.priority %> + + <% end %> + <%= link_to edit_todo_path(todo), class: "text-gray-400 hover:text-gray-500" do %> + + + + <% end %> +
      +
      +
      +
    • + <% end %> +
    +
    +<% else %> +
    + + + +

    No todos

    +

    Get started by creating a new todo.

    +
    + <%= link_to new_todo_path(project_id: @project.id), class: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" do %> + Add a todo + <% end %> +
    +
    <% end %> -<%= link_to "Edit", edit_project_path %> -<%= button_to "Delete", project_path, method: :delete %> -<%= link_to "Back", projects_path %> \ No newline at end of file +
    + <%= link_to "Back to Projects", projects_path, class: "inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %> + <%= button_to "Delete Project", project_path(@project), method: :delete, class: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500", data: { confirm: "Are you sure you want to delete this project and all its todos?" } %> +
    \ No newline at end of file diff --git a/app/views/todos/_form.html.erb b/app/views/todos/_form.html.erb index 2e437c1..1eae6bf 100644 --- a/app/views/todos/_form.html.erb +++ b/app/views/todos/_form.html.erb @@ -1,42 +1,74 @@ -<%= form_with(model: todo) do |form| %> +<%= form_with(model: todo, class: "space-y-6") do |form| %> <% if todo.errors.any? %> -
    -

    <%= pluralize(todo.errors.count, "error") %> prohibited this todo from being saved:

    - -
      - <% todo.errors.each do |error| %> -
    • <%= error.full_message %>
    • - <% end %> -
    +
    +
    +
    + + + +
    +
    +

    + <%= pluralize(todo.errors.count, "error") %> prohibited this todo from being saved: +

    +
    +
      + <% todo.errors.each do |error| %> +
    • <%= error.full_message %>
    • + <% end %> +
    +
    +
    +
    <% end %>
    - <%= form.label :name, style: "display: block" %> - <%= form.text_field :name %> + <%= form.label :name, class: "block text-sm font-medium text-gray-700" %> +
    + <%= form.text_field :name, class: "shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md" %> +
    - <%= form.label :description, style: "display: block" %> - <%= form.textarea :description %> + <%= form.label :description, class: "block text-sm font-medium text-gray-700" %> +
    + <%= form.text_area :description, rows: 4, class: "shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md" %> +

    Brief description of what needs to be done.

    +
    +
    + +
    +
    + <%= form.check_box :completed, class: "focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" %> +
    +
    + <%= form.label :completed, class: "font-medium text-gray-700" %> +

    Mark as completed if the task is done.

    +
    - <%= form.label :completed %> - <%= form.check_box :completed %> + <%= form.label :priority, class: "block text-sm font-medium text-gray-700" %> +
    + <%= form.number_field :priority, in: 0..5, class: "shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md" %> +

    Set a priority from 0 (lowest) to 5 (highest).

    +
    - <%= form.label :priority %> - <%= form.number_field :priority %> + <%= form.label :project_id, class: "block text-sm font-medium text-gray-700" %> +
    + <%= form.collection_select :project_id, Project.all, :id, :name, + { prompt: "Select a project" }, + { class: "mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md" } %> +
    -
    - <%= form.label :project_id %> - <%= form.collection_select :project_id, Project.all, :id, :name, prompt: "Select a project" %> +
    +
    + <%= link_to "Cancel", todos_path, class: "bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %> + <%= form.submit class: "ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm 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-indigo-500" %> +
    - -
    - <%= form.submit %> -
    -<% end %> +<% end %> \ No newline at end of file diff --git a/app/views/todos/_todo.html.erb b/app/views/todos/_todo.html.erb index a6ec100..f2be144 100644 --- a/app/views/todos/_todo.html.erb +++ b/app/views/todos/_todo.html.erb @@ -1,26 +1,51 @@ -
    -
    - Name: - <%= todo.name %> +
    +
    +

    + <% if todo.completed %> + + + + <% else %> + + <% end %> + <%= todo.name %> +

    +
    + <% if todo.priority && todo.priority > 0 %> + + Priority: <%= todo.priority %> + + <% end %> +
    - -
    - Description: - <%= todo.description %> +
    +
    +
    +
    Description
    +
    <%= todo.description.present? ? todo.description : "No description provided" %>
    +
    +
    +
    Project
    +
    + <%= link_to todo.project.name, project_path(todo.project), class: "text-indigo-600 hover:text-indigo-900" %> +
    +
    +
    +
    Status
    +
    + <% if todo.completed %> + + Completed + + <% else %> + + In Progress + + <% end %> +
    +
    +
    - -
    - Completed: - <%= todo.completed %> -
    - -
    - Priority: - <%= todo.priority %> -
    - -
    - Project: - <%= link_to todo.project.name, project_path(todo.project) %> -
    -
    +
    \ No newline at end of file diff --git a/app/views/todos/edit.html.erb b/app/views/todos/edit.html.erb index 023da66..f2be144 100644 --- a/app/views/todos/edit.html.erb +++ b/app/views/todos/edit.html.erb @@ -1,12 +1,51 @@ -<% content_for :title, "Editing todo" %> - -

    Editing todo

    - -<%= render "form", todo: @todo %> - -
    - -
    - <%= link_to "Show this todo", @todo %> | - <%= link_to "Back to todos", todos_path %> -
    +
    +
    +

    + <% if todo.completed %> + + + + <% else %> + + <% end %> + <%= todo.name %> +

    +
    + <% if todo.priority && todo.priority > 0 %> + + Priority: <%= todo.priority %> + + <% end %> +
    +
    +
    +
    +
    +
    Description
    +
    <%= todo.description.present? ? todo.description : "No description provided" %>
    +
    +
    +
    Project
    +
    + <%= link_to todo.project.name, project_path(todo.project), class: "text-indigo-600 hover:text-indigo-900" %> +
    +
    +
    +
    Status
    +
    + <% if todo.completed %> + + Completed + + <% else %> + + In Progress + + <% end %> +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/app/views/todos/index.html.erb b/app/views/todos/index.html.erb index 09bfa92..26fa9ed 100644 --- a/app/views/todos/index.html.erb +++ b/app/views/todos/index.html.erb @@ -1,16 +1,90 @@ -

    <%= notice %>

    - <% content_for :title, "Todos" %> -

    Todos

    - -
    - <% @todos.each do |todo| %> - <%= render todo %> -

    - <%= link_to "Show this todo", todo %> -

    +
    +

    Todos

    + <%= link_to new_todo_path, class: "px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition-colors" do %> +
    + + + + New Todo +
    <% end %>
    -<%= link_to "New todo", new_todo_path %> +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    + Total Todos +
    +
    +
    + <%= @todos.count %> +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + + +
    +
    +
    +
    + Completed +
    +
    +
    + <%= @todos.where(completed: true).count %> +
    +
    +
    +
    +
    +
    +
    +
    + +
    + <% @todos.each do |todo| %> +
    + <%= render todo %> +
    + <%= link_to "View", todo, class: "inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %> + <%= link_to "Edit", edit_todo_path(todo), class: "inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %> +
    +
    + <% end %> +
    + +<% if @todos.empty? %> +
    + + + +

    No todos

    +

    Get started by creating a new todo.

    +
    + <%= link_to new_todo_path, class: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" do %> + Add a todo + <% end %> +
    +
    +<% end %> \ No newline at end of file diff --git a/app/views/todos/new.html.erb b/app/views/todos/new.html.erb index 669ec00..1097c79 100644 --- a/app/views/todos/new.html.erb +++ b/app/views/todos/new.html.erb @@ -1,11 +1,22 @@ <% content_for :title, "New todo" %> -

    New todo

    - -<%= render "form", todo: @todo %> - -
    - -
    - <%= link_to "Back to todos", todos_path %> -
    +
    +
    +
    +

    New Todo

    +

    + Create a new todo to track your tasks. +

    +
    + <%= link_to "Back to Todos", todos_path, class: "text-indigo-600 hover:text-indigo-900" %> +
    +
    +
    +
    +
    +
    + <%= render "form", todo: @todo %> +
    +
    +
    +
    \ No newline at end of file diff --git a/app/views/todos/show.html.erb b/app/views/todos/show.html.erb index 66b1329..437138d 100644 --- a/app/views/todos/show.html.erb +++ b/app/views/todos/show.html.erb @@ -1,10 +1,11 @@ -

    <%= notice %>

    - -<%= render @todo %> - -
    - <%= link_to "Edit this todo", edit_todo_path(@todo) %> | - <%= link_to "Back to todos", todos_path %> - - <%= button_to "Destroy this todo", @todo, method: :delete %> +
    + <%= render @todo %>
    + +
    +
    + <%= link_to "Back to todos", todos_path, class: "inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %> + <%= link_to "Edit this todo", edit_todo_path(@todo), class: "inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %> +
    + <%= button_to "Delete this todo", @todo, method: :delete, class: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500", data: { confirm: "Are you sure you want to delete this todo?" } %> +
    \ No newline at end of file diff --git a/bin/dev b/bin/dev index 5f91c20..ad72c7d 100755 --- a/bin/dev +++ b/bin/dev @@ -1,2 +1,16 @@ -#!/usr/bin/env ruby -exec "./bin/rails", "server", *ARGV +#!/usr/bin/env sh + +if ! gem list foreman -i --silent; then + echo "Installing foreman..." + gem install foreman +fi + +# Default to port 3000 if not specified +export PORT="${PORT:-3000}" + +# Let the debug gem allow remote connections, +# but avoid loading until `debugger` is called +export RUBY_DEBUG_OPEN="true" +export RUBY_DEBUG_LAZY="true" + +exec foreman start -f Procfile.dev "$@" diff --git a/config/routes.rb b/config/routes.rb index 903a7ac..6d5c560 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -13,5 +13,5 @@ Rails.application.routes.draw do # get "service-worker" => "rails/pwa#service_worker", as: :pwa_service_worker # Defines the root path route ("/") - # root "posts#index" + root "todos#index" end