Fix projects layout
This commit is contained in:
parent
ff113cfe48
commit
2e30fef430
15 changed files with 164 additions and 83 deletions
|
|
@ -10,11 +10,15 @@ class Project < ActiveRecord::Base
|
|||
validates :name, presence: true
|
||||
|
||||
def task_status_counts
|
||||
status_counts = tasks.group(:status).count
|
||||
|
||||
total = status_counts.values.sum
|
||||
|
||||
{
|
||||
total: tasks.count,
|
||||
in_progress: tasks.where(status: Task.statuses[:in_progress]).count,
|
||||
done: tasks.where(status: Task.statuses[:done]).count,
|
||||
not_started: tasks.where(status: Task.statuses[:not_started]).count
|
||||
total: total,
|
||||
in_progress: status_counts[Task.statuses[:in_progress]] || 0,
|
||||
done: status_counts[Task.statuses[:done]] || 0,
|
||||
not_started: status_counts[Task.statuses[:not_started]] || 0
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
class Sinatra::Application
|
||||
get '/projects' do
|
||||
@projects_with_tasks = current_user.projects.includes(:tasks, :area).order('areas.name ASC, projects.name ASC')
|
||||
@projects_with_tasks = current_user.projects.left_joins(:tasks, :area).order('areas.name ASC, projects.name ASC')
|
||||
|
||||
@task_status_counts = @projects_with_tasks.each_with_object({}) do |project, counts|
|
||||
counts[project.id] = project.task_status_counts
|
||||
end
|
||||
|
||||
@grouped_projects = @projects_with_tasks.group_by(&:area)
|
||||
|
||||
erb :'projects/index'
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ module Sinatra
|
|||
@tasks = @tasks.where(id: tagged_task_ids)
|
||||
end
|
||||
|
||||
@tasks = @tasks.joins(:tags).distinct
|
||||
@tasks = @tasks.left_joins(:tags).distinct
|
||||
|
||||
erb :'tasks/index'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="border-0 rounded shadow-sm mb-1 px-3 py-2 d-flex align-items-center note-item" data-note-id="<%= note.id || 'new' %>">
|
||||
<div class="border-0 rounded shadow-sm px-3 py-1 d-flex align-items-center note-item" data-note-id="<%= note.id || 'new' %>">
|
||||
<i class="fs-6 bi-journal-text me-2"></i>
|
||||
<div class="row flex-grow-1 align-items-center">
|
||||
<div class="col-md-4">
|
||||
|
|
|
|||
39
app/views/projects/_cards.erb
Normal file
39
app/views/projects/_cards.erb
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<% projects.each do |project| %>
|
||||
<% counts = @task_status_counts[project.id] %>
|
||||
<div class="col-md-4 mb-3">
|
||||
<a class="text-decoration-none project-card" href="/project/<%= project.id %>">
|
||||
<div class="card shadow-sm" style="min-height: 177px;">
|
||||
<div class="d-flex flex-column justify-content-between h-100">
|
||||
<div>
|
||||
<div class="rounded" style="height: 100px;"></div>
|
||||
<div class="card-body p-0">
|
||||
<div class="card-footer p-0">
|
||||
<div class="progress rounded-0" style="height: 2px;">
|
||||
<div class="progress-bar" role="progressbar" style="width: <%= project.progress_percentage %>%" aria-valuenow="<%= project.progress_percentage %>" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="card-title px-3 pt-3 pb-0 mb-1">
|
||||
<%= project.name.length > 20 ? project.name.upcase[0,25] + "..." : project.name.upcase %>
|
||||
</h5>
|
||||
<div class="card-text px-3 small opacity-50">
|
||||
<%= counts[:total] %> Tasks
|
||||
<% if counts[:in_progress] > 0 %>
|
||||
, <i class="bi bi-circle-fill text-success me-1" style="font-size: 0.5em; position: relative; top: -0.3em;"></i> <%= counts[:in_progress] %> in progress
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="col-md-4 mb-3">
|
||||
<a class="text-decoration-none project-card" href="#" data-bs-toggle="modal" data-bs-target="#newProjectModal">
|
||||
<div class="card shadow-sm p-0 opacity-25" style="min-height: 177px;">
|
||||
<div class="card-body rounded px-0 p-0 text-center">
|
||||
<i class="bi bi-plus opacity-25" style="font-size: 72px; line-height: 175px;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
43
app/views/projects/_list.erb
Normal file
43
app/views/projects/_list.erb
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<table class="table-dark">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Project Name</th>
|
||||
<th scope="col">Progress</th>
|
||||
<th scope="col">Total Tasks</th>
|
||||
<th scope="col">Tasks in Progress</th>
|
||||
<th scope="col">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% projects.each_with_index do |project, index| %>
|
||||
<% counts = @task_status_counts[project.id] %>
|
||||
<tr>
|
||||
<th scope="row"><%= index + 1 %></th>
|
||||
<td><%= project.name %></td>
|
||||
<td>
|
||||
<div class="progress" style="height: 2px;">
|
||||
<div class="progress-bar" role="progressbar" style="width: <%= project.progress_percentage %>%;" aria-valuenow="<%= project.progress_percentage %>" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<%= project.progress_percentage %>%
|
||||
</td>
|
||||
<td><%= counts[:total] %> Tasks</td>
|
||||
<td>
|
||||
<% if counts[:in_progress] > 0 %>
|
||||
<i class="bi bi-circle-fill text-success" style="font-size: 0.5em; position: relative; top: -0.3em;"></i> <%= counts[:in_progress] %>
|
||||
<% else %>
|
||||
0
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/project/<%= project.id %>" class="btn btn-primary btn-sm">View</a>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Button to add new project -->
|
||||
<div class="mt-3">
|
||||
<a href="#" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#newProjectModal">Add New Project</a>
|
||||
</div>
|
||||
|
|
@ -1,67 +1,38 @@
|
|||
<h2 class="mb-5"><i class="bi bi-hexagon ms-3 me-2"></i>Areas & Projects</h2>
|
||||
<h2 class="mb-5"><i class="bi bi-hexagon ms-3 me-2"></i>Projects</h2>
|
||||
<div class="row px-3">
|
||||
<% @grouped_projects.each do |area, projects| %>
|
||||
<div class="mb-5">
|
||||
<div class="area-item d-flex align-items-center mb-3">
|
||||
<a href="#area_<%= area.id %>_projects" class="nav-link link-dark" data-bs-toggle="collapse" aria-expanded="false">
|
||||
<h4 class="mb-0 pb-0 fw-bold"><%= area.name %></h4>
|
||||
</a>
|
||||
<div class="dropdown area-options ms-2">
|
||||
<button class="btn btn-link link-dark p-0" type="button" id="dropdownMenuButton<%= area.id %>" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-three-dots-vertical"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton<%= area.id %>">
|
||||
<li><a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#editAreaModal<%= area.id %>">Edit</a></li>
|
||||
<li>
|
||||
<form action="/area/<%= area.id %>" method="post" onsubmit="return confirm('Are you sure you want to delete this area?');">
|
||||
<input type="hidden" name="_method" value="delete">
|
||||
<button type="submit" class="dropdown-item">Delete</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<% projects.each do |project| %>
|
||||
<div class="col-md-4 mb-3">
|
||||
<a class="text-decoration-none project-card" href="/project/<%= project.id %>">
|
||||
<div class="card shadow-sm" style="min-height: 177px;">
|
||||
<div class="d-flex flex-column justify-content-between h-100">
|
||||
<div>
|
||||
<div class="rounded" style="height: 100px;"></div>
|
||||
<div class="card-body p-0">
|
||||
<div class="card-footer p-0">
|
||||
<div class="progress rounded-0" style="height: 2px;">
|
||||
<div class="progress-bar" role="progressbar" style="width: <%= project.progress_percentage %>%" aria-valuenow="<%= project.progress_percentage %>" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="card-title px-3 pt-3 pb-0 mb-1"><%= project.name.upcase %></h5>
|
||||
<div class="card-text px-3 small opacity-50">
|
||||
<%= project.task_status_counts[:total] %> Tasks
|
||||
<% if project.task_status_counts[:in_progress] > 0 %>
|
||||
, <i class="bi bi-circle-fill text-success me-1" style="font-size: 0.5em; position: relative; top: -0.3em;"></i> <%= project.task_status_counts[:in_progress] %> in progress
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<% projects.each_with_index do |project, index| %>
|
||||
<% counts = @task_status_counts[project.id] %>
|
||||
<div class="border-0 rounded bg-transparent px-2 py-1 d-flex align-items-center task-item" data-project-id="<%= project.id %>" onclick="window.location.href='/project/<%= project.id %>'" style="cursor: pointer;">
|
||||
<div class="row flex-grow-1 align-items-top">
|
||||
<div class="col-md-6 d-flex align-items-center">
|
||||
<i class="bi bi-circle me-2"></i>
|
||||
<span class="fw-light"><%= project.name %></span>
|
||||
<span>— <%= area&.name || 'No area' %></span>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="col-md-4 mb-3">
|
||||
<a class="text-decoration-none project-card" href="#" data-bs-toggle="modal" data-bs-target="#newProjectModal">
|
||||
<div class="card shadow-sm p-0 opacity-25" style="min-height: 177px;">
|
||||
<div class="card-body rounded px-0 p-0 text-center">
|
||||
<i class="bi bi-plus opacity-25" style="font-size: 72px; line-height: 175px;"></i>
|
||||
</div>
|
||||
<div class="col-md-6 text-end">
|
||||
<div class="progress" style="height: 5px; width: 100px; display: inline-block; vertical-align: middle;">
|
||||
<div class="progress-bar bg-success" role="progressbar" style="width: <%= project.progress_percentage %>%;" aria-valuenow="<%= project.progress_percentage %>" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</a>
|
||||
<span>
|
||||
<%= counts[:total] %> /
|
||||
<% if counts[:in_progress] > 0 %>
|
||||
<i class="bi bi-circle-fill text-success" style="font-size: 0.5em; position: relative; top: -0.3em;"></i> <%= counts[:in_progress] %>
|
||||
<% else %>
|
||||
0
|
||||
<% end %>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<a href="#" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#newProjectModal">Add New Project</a>
|
||||
</div>
|
||||
|
||||
<%= partial :'tasks/_edit_task_modal' %>
|
||||
<% current_user.areas.each do |area| %>
|
||||
<%= partial :'areas/_edit_area_modal', locals: { area: area } %>
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
<li class="border-top my-3"></li>
|
||||
<li class="nav-item d-flex justify-content-between align-items-center w-100 <%= nav_link('/projects') %>">
|
||||
<a href="/projects" class="text-decoration-none flex-grow-1 <%= nav_link_active?('/projects') ? 'text-light' : 'link-dark' %>">
|
||||
<i class="bi bi-hexagon-fill me-1"></i> Areas & Projects
|
||||
<i class="bi bi-hexagon-fill me-1"></i> Projects
|
||||
</a>
|
||||
<button class="btn btn-link text-secondary p-0 ms-2" type="button" id="addNewDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-plus-lg"></i>
|
||||
|
|
|
|||
|
|
@ -1,34 +1,32 @@
|
|||
<div class="border-0 rounded shadow-sm mb-1 px-3 py-2 d-flex align-items-center task-item <%= 'opacity-50' if task.done? %>" data-task-id="<%= task.id %>">
|
||||
<div class="border-0 rounded bg-transparent px-2 py-1 d-flex align-items-center task-item <%= 'opacity-50' if task.done? %>" data-task-id="<%= task.id %>">
|
||||
<div class="row flex-grow-1 align-items-top">
|
||||
<div class="col-md-6">
|
||||
<span onclick="toggleTaskCompletion(event, <%= task.id %>)" class="toggle-completion">
|
||||
<i class="fs-6 bi <%= task.done? ? 'bi-check-circle-fill' : 'bi-circle' %> <%= priority_class(task) %> me-2"></i>
|
||||
</span>
|
||||
<span class="fw-light"><%= task.name %></span>
|
||||
</div>
|
||||
<div class="col-md-6 text-end">
|
||||
<% if task.tags.any? %>
|
||||
<div class="ms-3 opacity-75 d-inline-block">
|
||||
<% task.tags.each do |tag| %>
|
||||
<a href="<%= "/tasks?#{update_query_params('tag', tag.name)}" %>" class="badge bg-primary-subtle link-primary text-decoration-none">
|
||||
<a href="<%= "/tasks?#{update_query_params('tag', tag.name)}" %>" class="badge bg-primary-subtle py-1 link-primary text-decoration-none">
|
||||
<i class="bi bi-tag-fill me-1 opacity-50"></i><%= tag.name %>
|
||||
</a>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="col-md-3 text-end">
|
||||
<% if task.project && params[:id].blank? %>
|
||||
<a href="/project/<%= task.project.id %>" class="badge border border-secondary text-decoration-none link-dark fw-light">
|
||||
<%= task.project.name %>
|
||||
<a href="/project/<%= task.project.id %>" class="badge border border-secondary text-decoration-none py-1 link-dark fw-normal">
|
||||
<%= task.project.name.length > 25 ? task.project.name[0,25] + "..." : task.project.name %>
|
||||
</a>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="col-md-3 text-end">
|
||||
<% if task.due_date %>
|
||||
<span class="badge <%= due_date_badge_class(task.due_date) %> fw-light">
|
||||
<span class="badge py-1 <%= due_date_badge_class(task.due_date) %>" style="width: 95px">
|
||||
<i class="bi bi-clock me-2"></i> <%= format_due_date(task.due_date) %>
|
||||
</span>
|
||||
<% end %>
|
||||
<span class="badge <%= status_badge_class(task.status) %> fw-light">
|
||||
<span class="badge py-1 <%= status_badge_class(task.status) %>">
|
||||
<i class="bi bi-circle-fill me-1" style="font-size: 0.6em; position: relative; top: -0.15em;"></i>
|
||||
<span class="text-dark"><%= task.status.gsub('_', ' ').capitalize %></span>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
<% unless params[:status] == 'done' %>
|
||||
<%= partial :'tasks/_minimal_form', locals: { task: Task.new } %>
|
||||
<% end %>
|
||||
<div class="mx-3">
|
||||
<div class="mt-2 mx-3">
|
||||
<% if @tasks.any? %>
|
||||
<% @tasks.each do |task| %>
|
||||
<div id="edit_task_form_<%= task.id %>" class="d-none">
|
||||
|
|
|
|||
4
console.rb
Normal file
4
console.rb
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
require 'irb'
|
||||
require './app'
|
||||
|
||||
IRB.start
|
||||
3
create_migration.sh
Executable file
3
create_migration.sh
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
#! /bin/bash
|
||||
|
||||
bundle exec ../bin/rake db:create_migration "$1"
|
||||
5
db/migrate/20240326093339_add_active_to_projects.rb
Normal file
5
db/migrate/20240326093339_add_active_to_projects.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class AddActiveToProjects < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
add_column :projects, :active, :boolean, default: false
|
||||
end
|
||||
end
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.1].define(version: 2023_11_27_094906) do
|
||||
ActiveRecord::Schema[7.1].define(version: 2024_03_26_093339) do
|
||||
create_table "areas", force: :cascade do |t|
|
||||
t.string "name"
|
||||
t.integer "user_id", null: false
|
||||
|
|
@ -44,6 +44,7 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_27_094906) do
|
|||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.text "description"
|
||||
t.boolean "active", default: false
|
||||
t.index ["area_id"], name: "index_projects_on_area_id"
|
||||
t.index ["user_id"], name: "index_projects_on_user_id"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
body {
|
||||
font-family: 'Poppins', sans-serif;
|
||||
font-size: 0.85rem;
|
||||
background: #f8f8f8;
|
||||
font-size: 0.86rem;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
h1 {
|
||||
|
|
@ -114,6 +114,14 @@ h6 {
|
|||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-link:hover, .nav-link a:hover {
|
||||
color: #666 !important;
|
||||
}
|
||||
|
||||
.nav-link.active-link:hover, .nav-link.active-link a:hover {
|
||||
color: #ccc !important;
|
||||
}
|
||||
|
||||
.dark-mode .nav-link {
|
||||
color: #fff;
|
||||
}
|
||||
|
|
@ -126,22 +134,22 @@ h6 {
|
|||
|
||||
.task-item,
|
||||
.note-item {
|
||||
background: var(--bs-white);
|
||||
/* background: var(--bs-white); */
|
||||
}
|
||||
|
||||
.dark-mode .task-item,
|
||||
.dark-mode .note-item {
|
||||
background: var(--bs-gray-dark) !important;
|
||||
/* background: var(--bs-gray-dark) !important; */
|
||||
}
|
||||
|
||||
.task-item:hover,
|
||||
.note-item:hover {
|
||||
background: #fafafa !important;
|
||||
background: #eee !important;
|
||||
}
|
||||
|
||||
.dark-mode .task-item:hover,
|
||||
.dark-mode .note-item:hover {
|
||||
background: var(--bs-black) !important;
|
||||
background: #292929 !important;
|
||||
}
|
||||
|
||||
/* task form */
|
||||
|
|
@ -169,7 +177,7 @@ a.project-card .card:hover {
|
|||
|
||||
/* dark mode */
|
||||
.dark-mode {
|
||||
background-color: var(--bs-dark);
|
||||
background-color: #191919;
|
||||
color: var(--bs-light);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue