mirror of
https://github.com/System-End/hackatime.git
synced 2026-04-19 22:15:14 +00:00
Small UI improvements, include total time tracking in Projects page. (#785)
This commit is contained in:
parent
880e06bdea
commit
9982746122
5 changed files with 89 additions and 228 deletions
|
|
@ -45,7 +45,7 @@
|
|||
|
||||
.filter .options-list {
|
||||
/* not 200 cause the search thingie is 35.5 px high */
|
||||
max-height: 164.5px;
|
||||
max-height: 164.5px;
|
||||
overflow-y: auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
|
@ -155,61 +155,61 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.filter .options-container {
|
||||
background: white;
|
||||
border: 1px solid #ddd;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.filter .options-container {
|
||||
background: white;
|
||||
border: 1px solid #ddd;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.filter .search-input {
|
||||
border-bottom: 1px solid #eee;
|
||||
color: var(--text-color);
|
||||
}
|
||||
.filter .search-input {
|
||||
border-bottom: 1px solid #eee;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.filter .search-input::placeholder {
|
||||
color: #999;
|
||||
}
|
||||
.filter .search-input::placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.filter .option {
|
||||
color: var(--text-color);
|
||||
}
|
||||
.filter .option {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.filter .option:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.filter .option:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.filter .select-header-container {
|
||||
border: 1px solid #ddd;
|
||||
background-color: white;
|
||||
}
|
||||
.filter .select-header-container {
|
||||
border: 1px solid #ddd;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.filter .select-header {
|
||||
color: #666;
|
||||
}
|
||||
.filter .select-header {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.filter .clear-button {
|
||||
color: #666;
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
.filter .clear-button {
|
||||
color: #666;
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.filter .clear-button:hover {
|
||||
color: #ff4444;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.filter .clear-button:hover {
|
||||
color: #ff4444;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.filter .option input[type="checkbox"] {
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.filter .option input[type="checkbox"] {
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.filter .option input[type="checkbox"]:checked {
|
||||
background: #3291ff;
|
||||
border-color: #3291ff;
|
||||
}
|
||||
.filter .option input[type="checkbox"]:checked {
|
||||
background: #3291ff;
|
||||
border-color: #3291ff;
|
||||
}
|
||||
|
||||
.filter .option input[type="checkbox"]:hover {
|
||||
border-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
.filter .option input[type="checkbox"]:hover {
|
||||
border-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
|
||||
.dashboard-wrapper {
|
||||
|
|
@ -234,9 +234,11 @@
|
|||
0% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
|
@ -453,7 +455,7 @@
|
|||
border-radius: 4px;
|
||||
margin-top: 4px;
|
||||
max-height: 200px;
|
||||
overflow-y: hidden ;
|
||||
overflow-y: hidden;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
|
@ -496,11 +498,6 @@
|
|||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.dropdown-arrow {
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#dashboard-content {
|
||||
min-height: 200px;
|
||||
width: 100%;
|
||||
|
|
@ -561,139 +558,4 @@
|
|||
.date-inputs span {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.interval-dropdown {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
.interval-dropdown-trigger {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 1rem;
|
||||
border: 1px solid #bbb;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
min-width: 180px;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.interval-dropdown-menu {
|
||||
position: absolute;
|
||||
top: 110%;
|
||||
left: 0;
|
||||
min-width: 220px;
|
||||
background: #fff;
|
||||
border: 1px solid #bbb;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
z-index: 1000;
|
||||
padding: 0.5rem 0.75rem;
|
||||
}
|
||||
.interval-options-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.interval-options-list li {
|
||||
padding: 0.4rem 0.2rem;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.interval-options-list li:hover {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
.interval-custom-range {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
.interval-custom-range label {
|
||||
font-size: 0.95rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.interval-custom-range input[type="date"] {
|
||||
margin-left: 0.5rem;
|
||||
padding: 0.2rem 0.4rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.interval-custom-range button {
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.4rem 0.8rem;
|
||||
font-size: 1rem;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
background: #f5b041;
|
||||
color: #222;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
.interval-custom-range button:hover {
|
||||
background: #f39c12;
|
||||
}
|
||||
.dropdown-arrow {
|
||||
margin-left: 0.5rem;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.interval-dropdown-trigger {
|
||||
background: #23272f;
|
||||
color: #f5f5f5;
|
||||
border: 1px solid #444;
|
||||
}
|
||||
.interval-dropdown-menu {
|
||||
background: #23272f;
|
||||
color: #f5f5f5;
|
||||
border: 1px solid #444;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.4);
|
||||
}
|
||||
.interval-options-list li {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
.interval-options-list li:hover {
|
||||
background: #2c313a;
|
||||
}
|
||||
.interval-custom-range label {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
.interval-custom-range input[type="date"] {
|
||||
background: #181b20;
|
||||
color: #f5f5f5;
|
||||
border: 1px solid #444;
|
||||
}
|
||||
.interval-custom-range button {
|
||||
background: #f5b041;
|
||||
color: #23272f;
|
||||
}
|
||||
.interval-custom-range button:hover {
|
||||
background: #f39c12;
|
||||
}
|
||||
.dropdown-arrow {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
|
||||
.compact-options-list {
|
||||
max-height: 220px;
|
||||
overflow-y: auto;
|
||||
font-size: 0.97rem;
|
||||
padding-bottom: 0.2rem;
|
||||
}
|
||||
.compact-options-list li {
|
||||
padding: 0.25rem 0.2rem;
|
||||
font-size: 0.97rem;
|
||||
}
|
||||
.interval-dropdown-menu {
|
||||
min-width: 210px;
|
||||
padding: 0.3rem 0.5rem 0.5rem 0.5rem;
|
||||
}
|
||||
.interval-custom-range {
|
||||
margin-top: 0.3rem;
|
||||
padding-bottom: 0.1rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,14 +14,14 @@
|
|||
</div>
|
||||
|
||||
<% if current_user.github_uid.blank? %>
|
||||
<div class="notice">
|
||||
You can't tie your projects to GitHub until you connect your GitHub account.
|
||||
<%= link_to "Sign in with GitHub", github_auth_path, class: "btn btn-primary" %>
|
||||
<div class="text-red-400 mb-4">
|
||||
Heads up! You can't link your projects to GitHub until you connect your GitHub account.
|
||||
<%= link_to "Sign in with GitHub", github_auth_path, class: "btn btn-primary text-white underline" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "shared/interval_selector" %>
|
||||
|
||||
<%= turbo_frame_tag "project_durations", src: project_durations_static_pages_path(interval: params[:interval], from: params[:from], to: params[:to], show_archived: params[:show_archived]), target: "_top" do %>
|
||||
<div class="loading-indicator">Loading projects...</div>
|
||||
<p class="text-lg font-semibold text-gray-500 mt-6">Loading projects, please wait...</p>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,35 @@
|
|||
<%= turbo_frame_tag "interval_selector" do %>
|
||||
<div class="interval-dropdown">
|
||||
<button type="button" class="interval-dropdown-trigger" onclick="toggleIntervalDropdown()">
|
||||
<div class="relative inline-block w-full max-w-xs">
|
||||
<button type="button" id="interval-dropdown-trigger" class="w-full px-4 py-2 bg-[#23272f] text-gray-100 border border-gray-700 rounded cursor-pointer text-left flex items-center justify-between shadow-lg" onclick="toggleIntervalDropdown()">
|
||||
<span id="interval-dropdown-label">
|
||||
<%= human_interval_name(params[:interval], from: params[:from], to: params[:to]) %>
|
||||
</span>
|
||||
<span class="dropdown-arrow">▼</span>
|
||||
|
||||
<svg viewBox="0 0 20 20" fill="currentColor" data-slot="icon" aria-hidden="true" class="w-5 h-5 text-gray-500">
|
||||
<path d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" fill-rule="evenodd" />
|
||||
</svg>
|
||||
</button>
|
||||
<div class="interval-dropdown-menu" id="interval-dropdown-menu" style="display: none;">
|
||||
<ul class="interval-options-list compact-options-list">
|
||||
|
||||
<div id="interval-dropdown-menu" class="w-full px-3 py-2 mt-2 bg-[#23272f] text-gray-100 border border-gray-700 rounded-lg absolute z-[1000] shadow-lg" style="display: none;">
|
||||
<ul class="list-none m-0 p-0 overflow-y-auto max-h-60">
|
||||
<% TimeRangeFilterable::RANGES.each do |key, config| %>
|
||||
<li onclick="selectInterval('<%= key %>', '<%= config[:human_name] %>')"><%= config[:human_name] %></li>
|
||||
<li class="py-1.5 px-2 cursor-pointer rounded bg-transparent hover:bg-[#2c313a] transition" onclick="selectInterval('<%= key %>', '<%= config[:human_name] %>')"><%= config[:human_name] %></li>
|
||||
<% end %>
|
||||
<li onclick="selectInterval('', 'All Time')">All Time</li>
|
||||
<li class="py-1.5 px-2 cursor-pointer rounded bg-transparent hover:bg-[#2c313a] transition" onclick="selectInterval('', 'All Time')">All Time</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<div class="interval-custom-range">
|
||||
<label>Start:
|
||||
<input type="date" id="custom-start" value="<%= params[:from] %>">
|
||||
|
||||
<hr class="my-2 border-gray-700">
|
||||
|
||||
<div class="flex flex-col gap-2 mt-2">
|
||||
<label class="flex items-center justify-between">Start:
|
||||
<input type="date" class="ml-2 py-1 px-2 bg-[#181b20] border border-gray-700" id="custom-start" value="<%= params[:from] %>">
|
||||
</label>
|
||||
<label>End:
|
||||
<input type="date" id="custom-end" value="<%= params[:to] %>">
|
||||
|
||||
<label class="flex items-center justify-between">End:
|
||||
<input type="date" class="ml-2 py-1 px-2 bg-[#181b20] border border-gray-700" id="custom-end" value="<%= params[:to] %>">
|
||||
</label>
|
||||
<button type="button" class="primary-button" onclick="applyCustomRange()">Apply</button>
|
||||
|
||||
<button type="button" class="px-3 py-2 mt-2 mb-1 rounded bg-[#f5b041] hover:bg-[#f39c12] text-gray-800 font-semibold transition cursor-pointer" onclick="applyCustomRange()">Apply</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -107,29 +115,11 @@
|
|||
|
||||
function closeDropdownOnClickOutside(e) {
|
||||
const menu = document.getElementById('interval-dropdown-menu');
|
||||
const trigger = document.querySelector('.interval-dropdown-trigger');
|
||||
const trigger = document.getElementById('interval-dropdown-trigger');
|
||||
if (!menu.contains(e.target) && !trigger.contains(e.target)) {
|
||||
menu.style.display = 'none';
|
||||
document.removeEventListener('mousedown', closeDropdownOnClickOutside);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Adding explicit styles for the Apply button */
|
||||
.interval-custom-range .primary-button {
|
||||
padding: 0.4rem 0.8rem;
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.interval-custom-range .primary-button:hover {
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
</style>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,15 @@
|
|||
<%
|
||||
max = project_durations.map { |p| p[:duration] }.max || 1
|
||||
%>
|
||||
<p class="text-lg text-white mt-6">
|
||||
<% total_time = project_durations.sum { |p| p[:duration].to_i } %>
|
||||
|
||||
<% if total_time > 0 %>
|
||||
You've spent <span class="font-semibold"><%= short_time_detailed(total_time) %></span> coding across all projects.
|
||||
<% else %>
|
||||
You haven't logged any time yet. Start coding!
|
||||
<% end %>
|
||||
</p>
|
||||
<div class="grid grid-cols-[repeat(auto-fill,minmax(280px,1fr))] gap-6 mt-6">
|
||||
<% project_durations.each do |project| %>
|
||||
<% if current_user.github_uid.present? && project[:project].present? %>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
<h1 class="text-3xl font-bold text-white mb-4">My Projects</h1>
|
||||
|
||||
<% if current_user.github_uid.blank? %>
|
||||
<div class="notice">
|
||||
You can't tie your projects to GitHub until you connect your GitHub account.
|
||||
<%= link_to "Sign in with GitHub", github_auth_path, class: "btn btn-primary" %>
|
||||
<div class="text-red-400 mb-4">
|
||||
Heads up! You can't link your projects to GitHub until you connect your GitHub account.
|
||||
<%= link_to "Sign in with GitHub", github_auth_path, class: "btn btn-primary text-white underline" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "shared/interval_selector" %>
|
||||
|
||||
<%= turbo_frame_tag "project_durations", src: project_durations_static_pages_path(interval: params[:interval], from: params[:from], to: params[:to]), target: "_top" do %>
|
||||
<div class="loading-indicator">Loading projects...</div>
|
||||
<p class="text-lg font-semibold text-gray-500 mt-6">Loading projects, please wait...</p>
|
||||
<% end %>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue