linting erb

This commit is contained in:
Echo
2025-07-14 13:40:57 -04:00
parent dfb6a17116
commit bb4aacc42a
40 changed files with 288 additions and 296 deletions

View File

@@ -7,8 +7,8 @@
<h1 class="text-3xl font-bold text-white mb-2">admin api keys</h1>
<p class="text-gray-400">fraud team is gonna foam at the mouth for this shit</p>
</div>
<%= link_to "spawn in a new key",
new_admin_admin_api_key_path,
<%= link_to "spawn in a new key",
new_admin_admin_api_key_path,
class: "bg-primary hover:bg-red text-white px-4 py-2 rounded-lg font-medium transition-colors" %>
</div>
</div>
@@ -53,11 +53,11 @@
</code>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium space-x-2">
<%= link_to "inspect",
admin_admin_api_key_path(api_key),
<%= link_to "inspect",
admin_admin_api_key_path(api_key),
class: "text-blue-400 hover:text-blue-300" %>
<%= link_to "nuke",
admin_admin_api_key_path(api_key),
<%= link_to "nuke",
admin_admin_api_key_path(api_key),
data: { "turbo-method": :delete },
class: "text-red-400 hover:text-red-300" %>
</td>
@@ -66,7 +66,7 @@
</tbody>
</table>
</div>
<% if @admin_api_keys.empty? %>
<div class="text-center py-12">
<div class="text-gray-400 text-lg mb-2">nothing here cuzo</div>

View File

@@ -7,8 +7,8 @@
<h1 class="text-3xl font-bold text-white mb-2">spawn in a new key</h1>
<p class="text-gray-400">its geting real</p>
</div>
<%= link_to "← get me outta here",
admin_admin_api_keys_path,
<%= link_to "← get me outta here",
admin_admin_api_keys_path,
class: "text-gray-400 hover:text-white" %>
</div>
</div>
@@ -28,7 +28,7 @@
<div>
<%= f.label :name, class: "block text-md font-medium text-white mb-2" %>
<%= f.text_field :name,
<%= f.text_field :name,
placeholder: "put down something good please",
class: "w-full px-3 py-2 bg-darkless rounded text-white focus:border-primary focus:ring-1 focus:ring-primary" %>
</div>
@@ -38,10 +38,10 @@
</div>
<div class="flex justify-end space-x-4">
<%= link_to "fuck no imma head out",
admin_admin_api_keys_path,
<%= link_to "fuck no imma head out",
admin_admin_api_keys_path,
class: "px-4 py-2 text-gray-400 hover:text-white" %>
<%= f.submit "okay lets do this thing",
<%= f.submit "okay lets do this thing",
class: "px-6 py-2 bg-primary hover:bg-red text-white rounded-lg font-medium transition-colors" %>
</div>
<% end %>

View File

@@ -7,8 +7,8 @@
<h1 class="text-3xl font-bold text-white mb-2">lookin at <%= @admin_api_key.name %></h1>
<p class="text-gray-400">get the deets</p>
</div>
<%= link_to "← Back to API Keys",
admin_admin_api_keys_path,
<%= link_to "← Back to API Keys",
admin_admin_api_keys_path,
class: "text-gray-400 hover:text-white" %>
</div>
</div>
@@ -16,13 +16,13 @@
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<div class="bg-dark rounded-lg p-6">
<h2 class="text-xl font-semibold text-white mb-4">deets</h2>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-400 mb-1">name</label>
<div class="text-white"><%= @admin_api_key.name %></div>
</div>
<div>
<label class="block text-sm font-medium text-gray-400 mb-1">spawned by</label>
<div class="flex items-center">
@@ -35,21 +35,21 @@
</div>
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-400 mb-1">spawned at</label>
<div class="text-white"><%= @admin_api_key.created_at.strftime("%B %d, %Y at %I:%M %p") %></div>
</div>
<div>
<label class="block text-sm font-medium text-gray-400 mb-1">status</label>
<div class="text-green-400">live</div>
</div>
</div>
<div class="mt-6 pt-6 border-t border-gray-600">
<%= link_to "nuke it",
admin_admin_api_key_path(@admin_api_key),
<%= link_to "nuke it",
admin_admin_api_key_path(@admin_api_key),
data: { "turbo-method": :delete },
class: "bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg font-medium transition-colors" %>
</div>
@@ -57,7 +57,7 @@
<div class="bg-dark rounded-lg p-6">
<h2 class="text-xl font-semibold text-white mb-4">how 2 api</h2>
<div class="space-y-4">
<% if flash[:api_key_token] %>
<div class="bg-green-900/30 border border-green-500/50 rounded-lg p-4">
@@ -72,7 +72,7 @@
</div>
</div>
<% end %>
<div>
<label class="block text-sm font-medium text-gray-400 mb-2">preview</label>
<code class="block bg-gray-800 px-3 py-2 rounded text-white text-sm">
@@ -84,7 +84,7 @@
</p>
<% end %>
</div>
<div>
<label class="block text-sm font-medium text-gray-400 mb-2">auth stuff</label>
<div class="bg-gray-800 rounded p-3">
@@ -96,7 +96,7 @@
replace <code>YOUR_KEY_HERE</code> with your actual api key, pass it as a header and your balling
</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-400 mb-2">domain</label>
<div class="bg-gray-800 rounded p-3">

View File

@@ -62,4 +62,4 @@ document.addEventListener('turbo:load', function() {
return hours + 'h' + (remainingMinutes > 0 ? ' ' + remainingMinutes + 'm' : '');
}
});
</script>
</script>

View File

@@ -203,11 +203,11 @@
<% @unique_project_names.each do |project_name| %>
<% is_selected = @selected_projects.include?(project_name) %>
<% is_recommended = @recommended_project_names.include?(project_name) %>
<label class="project-filter-label <%= 'recommended' if is_recommended %>"
<label class="project-filter-label <%= 'recommended' if is_recommended %>"
style="display: flex; align-items: center; background: <%= is_recommended ? '#1F2937' : '#374151' %>; padding: 0.25rem 0.5rem; border-radius: 0.25rem; cursor: pointer; border: 1px solid <%= is_recommended ? '#60A5FA' : 'transparent' %>;">
<input type="checkbox"
class="project-filter-checkbox"
data-project-name="<%= h(project_name) %>"
<input type="checkbox"
class="project-filter-checkbox"
data-project-name="<%= h(project_name) %>"
<%= is_selected ? 'checked' : '' %>
style="margin-right: 0.5rem; accent-color: #60A5FA;">
<%= h(project_name) %>
@@ -223,11 +223,11 @@
<div class="extension-filters" style="display: flex; flex-wrap: wrap; gap: 0.5rem;">
<% @unique_file_extensions.each do |extension| %>
<% is_selected = @selected_extensions.include?(extension) %>
<label class="extension-filter-label"
<label class="extension-filter-label"
style="display: flex; align-items: center; background: #374151; padding: 0.25rem 0.5rem; border-radius: 0.25rem; cursor: pointer; border: 1px solid transparent;">
<input type="checkbox"
class="extension-filter-checkbox"
data-extension="<%= extension %>"
<input type="checkbox"
class="extension-filter-checkbox"
data-extension="<%= extension %>"
<%= is_selected ? 'checked' : '' %>
style="margin-right: 0.5rem; accent-color: #60A5FA;">
<%= extension %>
@@ -306,7 +306,7 @@
span_top_px = top_offset_minutes * pixels_per_minute
span_height_px = [duration_minutes_on_day * pixels_per_minute, 2].max
projects_display = span[:projects_edited_details].map do |p_detail|
name = p_detail[:name].blank? ? "Unknown" : p_detail[:name].truncate(15)
p_detail[:repo_url] ? link_to(name, p_detail[:repo_url], target: "_blank", rel: "noopener noreferrer") : name
@@ -324,13 +324,13 @@
tooltip_parts << "Languages: #{span[:languages].join(', ')}" if span[:languages].any?
tooltip_parts << "Editors: #{span[:editors].join(', ')}" if span[:editors].any?
tooltip_parts << "Files: #{span[:files_edited].join(', ')}" if span[:files_edited].any?
%>
%>
<div class="timeline-item coding-span"
style="top: <%= span_top_px %>px; height: <%= span_height_px %>px;"
data-projects="<%= project_names %>"
title="<%= tooltip_parts.join("\n") %>">
<input type="checkbox"
class="span-selector-checkbox"
<input type="checkbox"
class="span-selector-checkbox"
id="<%= span[:id] %>"
data-duration-seconds="<%= span[:duration] %>">
<div class="timeline-item-content">
@@ -351,11 +351,11 @@
commit_time_in_user_tz = commit.created_at.in_time_zone(@target_user_timezone)
top_offset_minutes = (commit_time_in_user_tz - day_start_in_user_tz) / 60.0
commit_top_px = top_offset_minutes * pixels_per_minute
commit_pill_height = 16
commit_top_px = [commit_top_px - (commit_pill_height / 2), last_commit_bottom_px].max
last_commit_bottom_px = commit_top_px + commit_pill_height + 1
additions = commit.github_raw.dig("stats", "additions") || 0
deletions = commit.github_raw.dig("stats", "deletions") || 0
%>
@@ -394,11 +394,11 @@ document.addEventListener('turbo:load', function() {
timelineViewport.addEventListener('scroll', function() {
dayHeaderStickyWrapper.style.transform = `translateX(-${timelineViewport.scrollLeft}px)`;
});
const postStartDate = new Date('<%= @post_start_display.iso8601 %>');
const reviewStartDate = new Date('<%= @review_start_date.iso8601 %>');
const dayDiff = Math.floor((postStartDate - reviewStartDate) / (1000 * 60 * 60 * 24));
if (dayDiff >= 0 && dayDiff < <%= num_days_in_review %>) {
const scrollAmount = dayDiff * <%= day_column_width_px %>;
timelineViewport.scrollLeft = Math.max(0, scrollAmount - (<%= day_column_width_px %>/2) );
@@ -407,16 +407,16 @@ document.addEventListener('turbo:load', function() {
daysContainer.addEventListener('mousemove', function(e) {
const rect = daysContainer.getBoundingClientRect();
const viewportRect = timelineViewport.getBoundingClientRect();
let mouseYInGrid = e.clientY - rect.top;
let mouseYInGrid = e.clientY - rect.top;
mouseYInGrid = Math.max(0, Math.min(mouseYInGrid, rect.height));
cursorLine.style.top = `${mouseYInGrid}px`;
cursorLine.style.display = 'block';
const minutesFromTimelineStart = mouseYInGrid / pixelsPerMinute;
const totalMinutes = Math.floor(timelineStartHour * 60 + minutesFromTimelineStart);
const displayHours = Math.floor(totalMinutes / 60) % 24;
const displayMinutes = totalMinutes % 60;
cursorTimeDisplay.textContent = `${String(displayHours).padStart(2, '0')}:${String(displayMinutes).padStart(2, '0')}`;
cursorTimeDisplay.style.top = `${mouseYInGrid + headerHeight}px`;
cursorTimeDisplay.style.left = `5px`;
@@ -455,4 +455,4 @@ document.getElementById('filters-form').addEventListener('submit', function(e) {
}
window.location.href = url.toString();
});
</script>
</script>

View File

@@ -40,18 +40,17 @@
</style>
<div class=" text-white flex flex-col font-sans min-h-screen">
<div
<div
data-controller="admin-timeline-user-selector"
data-admin-timeline-user-selector-current-user-json-value='<%= current_admin_user_json %>'
data-admin-timeline-user-selector-initial-selected-users-json-value='<%= initial_selected_users_json %>'
data-admin-timeline-user-selector-search-url-value="<%= admin_timeline_search_users_path %>"
data-admin-timeline-user-selector-leaderboard-users-url-value="<%= admin_timeline_leaderboard_users_path %>"
class="mb-4 p-3 bg-dark rounded-md flex-shrink-0"
>
class="mb-4 p-3 bg-dark rounded-md flex-shrink-0">
<form id="timeline-filter-form" action="<%= admin_timeline_path %>" method="get" data-turbo-frame="_top">
<input type="hidden" name="user_ids" data-admin-timeline-user-selector-target="userIdsInput">
<input type="hidden" name="date" value="<%= current_date_for_form %>" data-admin-timeline-user-selector-target="dateInput">
<div class="flex items-center gap-3">
<div class="flex-1 relative">
<div class="relative">
@@ -72,29 +71,29 @@
autocomplete="off"
class="w-full pl-10 pr-3 py-2 bg-darker rounded-md text-white placeholder-gray-300 focus:outline-none focus:border-transparent text-sm">
</div>
<div class="absolute top-full left-0 w-full bg-dark border border-gray-700 rounded-lg mt-1 z-50 max-h-48 overflow-y-auto hidden shadow-lg"
<div class="absolute top-full left-0 w-full bg-dark border border-gray-700 rounded-lg mt-1 z-50 max-h-48 overflow-y-auto hidden shadow-lg"
data-admin-timeline-user-selector-target="searchResults">
<%# Search results will appear here %>
</div>
</div>
<button type="button"
class="px-3 py-2 bg-darker rounded-md text-sm text-white transition-colors"
data-action="admin-timeline-user-selector#applyPreset"
<button type="button"
class="px-3 py-2 bg-darker rounded-md text-sm text-white transition-colors"
data-action="admin-timeline-user-selector#applyPreset"
data-period="today">
Top 15 Today
</button>
<button type="button"
class="px-3 py-2 bg-darker rounded-md text-sm text-white transition-colors"
data-action="admin-timeline-user-selector#applyPreset"
<button type="button"
class="px-3 py-2 bg-darker rounded-md text-sm text-white transition-colors"
data-action="admin-timeline-user-selector#applyPreset"
data-period="last_7_days">
Top 15 Week
</button>
<button type="submit"
<button type="submit"
class="px-4 py-2 bg-green-600 rounded-md text-sm text-white transition-colors font-medium">
View
</button>
</div>
<div class="mt-2 min-h-7" data-admin-timeline-user-selector-target="selectedUsersContainer">
<%# Selected user pills will appear here %>
</div>
@@ -106,14 +105,14 @@
<%= @date.in_time_zone(primary_user_tz).strftime("%A, %B %-d, %Y") %>
</div>
<div class="flex gap-2">
<%= link_to "← Prev", admin_timeline_path(date: @prev_date.to_s),
class: "px-3 py-1 bg-darker rounded text-sm transition-colors",
<%= link_to "← Prev", admin_timeline_path(date: @prev_date.to_s),
class: "px-3 py-1 bg-darker rounded text-sm transition-colors",
data: { "date-nav-link": "true" } %>
<%= link_to "Today", admin_timeline_path(date: Time.current.to_date.to_s),
class: "px-3 py-1 bg-darker rounded text-sm transition-colors",
<%= link_to "Today", admin_timeline_path(date: Time.current.to_date.to_s),
class: "px-3 py-1 bg-darker rounded text-sm transition-colors",
data: { "date-nav-link": "true" } %>
<%= link_to "Next →", admin_timeline_path(date: @next_date.to_s),
class: "px-3 py-1 bg-darker rounded text-sm transition-colors",
<%= link_to "Next →", admin_timeline_path(date: @next_date.to_s),
class: "px-3 py-1 bg-darker rounded text-sm transition-colors",
data: { "date-nav-link": "true" } %>
</div>
</div>
@@ -125,33 +124,33 @@
grid_width = hour_label_width + (users_data_array.count * (min_column_width_px + gutter_px))
grid_height = 120 + (24 * pixels_per_hour)
%>
<div class="relative" style="width: <%= grid_width %>px; height: <%= grid_height %>px;">
<% (0..23).each do |hour| %>
<%
<%
hour_top = 120 + (hour * pixels_per_hour)
formatted_hour = Time.utc(2000,1,1, hour).strftime("%-l:00 %p")
%>
<div class="absolute left-0 w-full border-t border-gray-600"
<div class="absolute left-0 w-full border-t border-gray-600"
style="top: <%= hour_top %>px; height: <%= pixels_per_hour %>px;">
<div class="absolute left-2 top-2 text-xs text-gray-300 font-mono px-1">
<%= formatted_hour %>
</div>
</div>
<% end %>
<% users_data_array.each_with_index do |data, index| %>
<%
user = data[:user]
<%
user = data[:user]
total_coded_time_seconds = data[:total_coded_time]
column_left = hour_label_width + (index * (min_column_width_px + gutter_px))
trust_level_emoji = case user.respond_to?(:trust_level) ? user.trust_level : nil
when "red" then "🔴"
when "green" then "🟢"
when "green" then "🟢"
when "yellow" then "🟡"
else "🔵"
end
trust_level_bg = case user.respond_to?(:trust_level) ? user.trust_level : nil
when "red" then "bg-red-500/20"
when "green" then "bg-green-500/20"
@@ -160,7 +159,7 @@
else "bg-gray-500/20"
end
%>
<div class="absolute border-r border-gray-700"
<div class="absolute border-r border-gray-700"
style="left: <%= column_left %>px; width: <%= min_column_width_px %>px; top: 120px; bottom: 0; padding-bottom: 0;">
</div>
<div class="absolute top-0 p-3 rounded-lg shadow-lg <%= trust_level_bg %>"
@@ -173,15 +172,15 @@
<div class="flex justify-center items-center gap-4 mb-1 text-center">
<% if current_user && user != current_user && user.slack_uid.present? %>
<div>
<%= link_to "Slack", "slack://user?team=T0266FRGM&id=#{user.slack_uid}",
target: "_blank",
<%= link_to "Slack", "slack://user?team=T0266FRGM&id=#{user.slack_uid}",
target: "_blank",
class: "text-xs text-blue-400 hover:text-blue-300 underline" %>
</div>
<% end %>
<% if user.respond_to?(:github_profile_url) && user.github_profile_url.present? %>
<div>
<%= link_to "Git", user.github_profile_url,
target: "_blank",
<%= link_to "Git", user.github_profile_url,
target: "_blank",
class: "text-xs text-green-400 hover:text-green-300 underline" %>
</div>
<% end %>
@@ -190,7 +189,7 @@
</div>
<% if current_user && current_user.admin_level.in?(["admin", "superadmin"]) && user != current_user %>
<div>
<button onclick="setTrust(<%= user.id %>)"
<button onclick="setTrust(<%= user.id %>)"
class="text-xs text-gray-300 hover:text-white"
title="Set trust level">🔨</button>
</div>
@@ -199,13 +198,13 @@
<div class="text-sm font-medium mb-1 <%= total_coded_time_seconds && total_coded_time_seconds > 0 ? 'text-green-300' : 'text-gray-400' %>">
<%= total_coded_time_seconds && total_coded_time_seconds > 0 ? "#{short_time_simple(total_coded_time_seconds)} coded" : "No time coded" %>
</div>
<div class="text-xs text-gray-300">
<%= user.timezone %>
</div>
</div>
<% end %>
<%
current_time_in_zone = Time.current.in_time_zone(primary_user_tz)
is_today = @date == Time.current.in_time_zone(primary_user_tz).to_date
@@ -217,7 +216,7 @@
end
%>
<% if show_current_time_line %>
<div class="absolute w-full h-0.5 bg-red-500 z-300 flex items-center"
<div class="absolute w-full h-0.5 bg-red-500 z-300 flex items-center"
style="left: <%= hour_label_width %>px; right: 0; top: <%= current_time_line_top_px %>px;">
<div class="bg-red-500 text-white text-xs px-2 py-1 rounded -ml-16">NOW</div>
</div>
@@ -266,7 +265,7 @@
}
end
%>
<% users_data_array.each_with_index do |data, index| %>
<%
user = data[:user]
@@ -278,7 +277,7 @@
<% props = calculate_span_properties.call(span_data, user.timezone || primary_user_tz) %>
<% next unless props %>
<div class="absolute rounded-md p-2 text-white text-xs overflow-hidden z-10"
style="background-color: <%= block_color %>;
style="background-color: <%= block_color %>;
left: <%= column_left + 2 %>px;
width: <%= min_column_width_px - 4 %>px;
top: <%= props[:final_top_px] %>px;
@@ -288,8 +287,8 @@
<% if props[:projects_to_display]&.any? %>
<% props[:projects_to_display].each_with_index do |project_detail, p_idx| %>
<% if project_detail[:repo_url].present? %>
<a href="<%= project_detail[:repo_url] %>" target="_blank" rel="noopener noreferrer"
class="text-white hover:text-gray-200 underline"
<a href="<%= project_detail[:repo_url] %>" target="_blank" rel="noopener noreferrer"
class="text-white hover:text-gray-200 underline"
title="Open <%= h(project_detail[:name]) %> on GitHub"><%= h(project_detail[:name]).truncate(20) %></a>
<% else %>
<span title="<%= h(project_detail[:name]) %> - No GitHub Repo Mapped"><%= h(project_detail[:name]).truncate(20) %> 🚫</span>
@@ -341,7 +340,7 @@
</div>
<% end %>
</div>
</div>
<script>
@@ -404,7 +403,7 @@ window.setTrust = function(userId) {
'Content-Type': 'application/json',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
},
body: JSON.stringify({
body: JSON.stringify({
trust_level: levelForAPI,
reason: reason.trim(),
notes: notes ? notes.trim() : ''
@@ -432,7 +431,7 @@ window.setTrust = function(userId) {
span.textContent = trust.emoji;
}
}
alert(`set trust to ${trust.name}\nreason: ${reason}${notes ? '\nanything else? ' + notes : ''}`);
})
.catch(error => {

View File

@@ -11,23 +11,23 @@
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<%= form.label :user_search, "user lookup", class: "block text-sm font-medium text-gray-300 mb-2" %>
<%= form.text_field :user_search,
value: @user_search,
placeholder: "just put anything here or something",
<%= form.text_field :user_search,
value: @user_search,
placeholder: "just put anything here or something",
class: "w-full px-3 py-2 bg-darkless rounded-md text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" %>
</div>
<div>
<%= form.label :admin_search, "admin lookup", class: "block text-sm font-medium text-gray-300 mb-2" %>
<%= form.text_field :admin_search,
value: @admin_search,
placeholder: "just put anything here or something",
<%= form.text_field :admin_search,
value: @admin_search,
placeholder: "just put anything here or something",
class: "w-full px-3 py-2 bg-darkless rounded-md text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" %>
</div>
<div>
<%= form.label :trust_level_filter, "filter by trust updates", class: "block text-sm font-medium text-gray-300 mb-2" %>
<%= form.select :trust_level_filter,
<%= form.select :trust_level_filter,
options_for_select([
['All Changes', 'all'],
['🔴 Set to Convicted', 'to_convicted'],
@@ -39,7 +39,7 @@
{ class: "w-full px-3 py-2 bg-darkless rounded-md text-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" } %>
</div>
</div>
<div class="flex items-center gap-4">
<%= form.submit "run that shit", class: "bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md font-medium transition-colors" %>
<%= link_to "alt+f4", admin_trust_level_audit_logs_path, class: "bg-gray-600 hover:bg-darkless text-white px-4 py-2 rounded-md font-medium transition-colors" %>
@@ -65,8 +65,8 @@
</p>
<% end %>
</div>
<%= link_to "fuckin abort",
admin_trust_level_audit_logs_path,
<%= link_to "fuckin abort",
admin_trust_level_audit_logs_path,
class: "text-sm bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded" %>
</div>
</div>
@@ -121,14 +121,14 @@
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<span class="text-sm text-gray-300">
<%
<%
previous_emoji = case log.previous_trust_level
when "blue" then "🔵"
when "red" then "🔴"
when "green" then "🟢"
when "yellow" then "🟡"
end
new_emoji = case log.new_trust_level
when "blue" then "🔵"
when "red" then "🔴"
@@ -177,8 +177,8 @@
<% end %>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<%= link_to "the deets",
admin_trust_level_audit_log_path(log),
<%= link_to "the deets",
admin_trust_level_audit_log_path(log),
class: "text-blue-400 hover:text-blue-300" %>
</td>
</tr>
@@ -186,7 +186,7 @@
</tbody>
</table>
</div>
<% if @audit_logs.empty? %>
<div class="text-center py-12">
<div class="text-gray-400 text-lg mb-2">theres nothin</div>

View File

@@ -4,8 +4,8 @@
<div class="mb-8">
<div class="flex items-center justify-between">
<h1 class="text-3xl font-bold text-white">looking at a single audit log</h1>
<%= link_to "get me outta here",
admin_trust_level_audit_logs_path,
<%= link_to "get me outta here",
admin_trust_level_audit_logs_path,
class: "bg-darkless text-white px-4 py-2 rounded-lg" %>
</div>
</div>
@@ -21,10 +21,10 @@
id: <%= @audit_log.user.id %>
</div>
</div>
<div class="pt-4">
<%= link_to "actions on this goober",
admin_trust_level_audit_logs_path(user_id: @audit_log.user.id),
<%= link_to "actions on this goober",
admin_trust_level_audit_logs_path(user_id: @audit_log.user.id),
class: "text-blue-400 hover:text-blue-300" %>
</div>
</div>
@@ -54,10 +54,10 @@
id: <%= @audit_log.changed_by.id %>
</div>
</div>
<div class="pt-4">
<%= link_to "changes by this goober",
admin_trust_level_audit_logs_path(admin_id: @audit_log.changed_by.id),
<%= link_to "changes by this goober",
admin_trust_level_audit_logs_path(admin_id: @audit_log.changed_by.id),
class: "text-blue-400 hover:text-blue-300" %>
</div>
</div>
@@ -66,7 +66,7 @@
<div class="mt-4">
<h2 class="text-xl font-semibold text-white mb-4">the deets</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
<div>
<label class="block text-sm font-medium text-gray-400 mb-2">executed at</label>
@@ -74,11 +74,11 @@
<%= @audit_log.created_at.strftime("%B %d, %Y at %I:%M %p %Z") %>
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-400 mb-2">before</label>
<div class="text-white text-lg">
<%
<%
a = case @audit_log.previous_trust_level
when "blue" then "🔵"
when "red" then "🔴"
@@ -89,11 +89,11 @@
<%= a %> <strong><%= @audit_log.previous_trust_level.capitalize %></strong>
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-400 mb-2">after</label>
<div class="text-white text-lg">
<%
<%
b = case @audit_log.new_trust_level
when "blue" then "🔵"
when "red" then "🔴"

View File

@@ -31,7 +31,7 @@
<strong>App:</strong> <%= @app.airtable_fields["Name"] %>
</p>
<p style="margin-bottom: 0.5rem; color: #A0AEC0; line-height: 1.5;">
<strong>Airtable Link:</strong>
<strong>Airtable Link:</strong>
<%= link_to "View on Airtable", @submission.airtable_url, target: "_blank", style: "color: #60A5FA; text-decoration: none;" %>
</p>
</section>
@@ -60,7 +60,7 @@
</div>
</div>
<div style="display: flex; gap: 0.5rem; margin-top: 0.5rem;">
<%= link_to "View Post Review", admin_post_review_path(post.airtable_id),
<%= link_to "View Post Review", admin_post_review_path(post.airtable_id),
style: "display: inline-block; padding: 0.4rem 0.8rem; background-color: #3B82F6; color: white; text-decoration: none; border-radius: 0.25rem; font-size: 0.85rem;" %>
<%= link_to "View on Airtable", post.airtable_url, target: "_blank",
style: "display: inline-block; padding: 0.4rem 0.8rem; background-color: #374151; color: #E5E7EB; text-decoration: none; border-radius: 0.25rem; font-size: 0.85rem;" %>
@@ -72,4 +72,4 @@
<p style="color: #A0AEC0;">No posts found for this submission.</p>
<% end %>
</section>
</div>
</div>

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type'>
</head>
<body>
<h1>Welcome back to Hackatime!</h1>
@@ -18,4 +18,4 @@
If you didn't request this email, you can safely ignore it.
</p>
</body>
</html>
</html>

View File

@@ -39,7 +39,6 @@
<strong class="text-primary">💡 Tip:</strong> The <a href="<%= my_wakatime_setup_path %>" class="text-primary hover:text-red underline">setup page</a> does everything for you. No hard stuff to figure out!
</div>
<h3 class="text-2xl font-semibold text-primary mb-4">🔌 What Code Editors Work</h3>
<div class="bg-dark rounded-lg p-6 mb-8">
<p class="mb-6">
@@ -104,11 +103,11 @@
<h3 class="text-2xl font-semibold text-primary mb-4">🆘 Need Help?</h3>
<div class="bg-darkless rounded-lg p-6 mb-8">
<p class="mb-4">
<strong class="text-primary">Not seeing your time?</strong> Go to the <a href="<%= my_wakatime_setup_path %>" class="text-primary hover:text-red underline">setup page</a>
<strong class="text-primary">Not seeing your time?</strong> Go to the <a href="<%= my_wakatime_setup_path %>" class="text-primary hover:text-red underline">setup page</a>
to check if everything is working.
</p>
<p>
<strong class="text-primary">Have questions?</strong> Ask in the <a href="https://hackclub.slack.com" target="_blank" class="text-primary hover:text-red underline">Hack Club Slack</a>
<strong class="text-primary">Have questions?</strong> Ask in the <a href="https://hackclub.slack.com" target="_blank" class="text-primary hover:text-red underline">Hack Club Slack</a>
(#hackatime-v2 channel) or <a href="https://github.com/hackclub/hackatime/issues" target="_blank" class="text-primary hover:text-red underline">ask on GitHub</a>.
</p>
</div>
@@ -135,14 +134,14 @@
<div class="text-sm text-white"><%= name %></div>
</a>
<% end %>
</div>
</div>
<details class="bg-dark rounded-lg p-6 mb-8">
<summary class="cursor-pointer font-semibold text-primary">View all 77 supported editors</summary>
<div id="all-editors" class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-3 mt-4 p-4">
<%
<%
# All 77 editors - alphabetically sorted
all_editors = [
['Android Studio', 'android-studio'], ['AppCode', 'appcode'], ['Aptana', 'aptana'], ['Arduino IDE', 'arduino-ide'],
@@ -160,7 +159,7 @@
['Processing', 'processing'], ['Pulsar', 'pulsar'], ['PyCharm', 'pycharm'], ['ReClassEx', 'reclassex'],
['Rider', 'rider'], ['Roblox Studio', 'roblox-studio'], ['RubyMine', 'rubymine'], ['RustRover', 'rustrover'],
['Safari', 'safari'], ['SiYuan', 'siyuan'], ['Sketch', 'sketch'], ['SlickEdit', 'slickedit'],
['SQL Server Management Studio', 'sql-server-management-studio'], ['Sublime Text', 'sublime-text'],
['SQL Server Management Studio', 'sql-server-management-studio'], ['Sublime Text', 'sublime-text'],
['Terminal', 'terminal'], ['TeXstudio', 'texstudio'], ['TextMate', 'textmate'], ['Trae', 'trae'],
['Unity', 'unity'], ['Vim', 'vim'], ['Visual Studio', 'visual-studio'], ['VS Code', 'vs-code'],
['WebStorm', 'webstorm'], ['Windsurf', 'windsurf'], ['Wing', 'wing'], ['Word', 'word'],
@@ -180,7 +179,7 @@
<div class="text-center">
<p class="text-secondary">
Found an issue with the docs?
Found an issue with the docs?
<a href="https://github.com/hackclub/hackatime" target="_blank" class="text-primary hover:text-red underline">
Edit on GitHub
</a> - we'd love your help making them better!

View File

@@ -96,7 +96,7 @@
</div>
<div class="text-center bg-darkless rounded-lg p-6">
<p class="text-secondary">
Found an issue with this page?
Found an issue with this page?
<a href="https://github.com/hackclub/hackatime/edit/main/docs/<%= @doc_path %>.md" target="_blank" class="text-primary hover:text-red underline">Edit it on GitHub</a> - we'd love your help making the docs better!
</p>
</div>

View File

@@ -40,4 +40,4 @@
<%= hidden_field_tag :code_challenge_method, @pre_auth.code_challenge_method, id: nil %>
<%= submit_tag t('doorkeeper.authorizations.buttons.deny'), class: "btn btn-danger btn-lg btn-block" %>
<% end %>
</div>
</div>

View File

@@ -6,18 +6,18 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="color-scheme" content="dark">
<!-- SEO Meta Tags -->
<meta name="description" content="<%= @meta_description || content_for(:meta_description) || 'Track your coding time easily with Hackatime. A free tool to see how much time you spend programming in different languages and editors. Better than WakaTime and totally free!' %>">
<meta name="keywords" content="<%= @meta_keywords || content_for(:meta_keywords) || 'coding time tracker, programming stats, wakatime alternative, free time tracking, code statistics, developer analytics, programming time, coding productivity' %>">
<meta name="author" content="Hack Club">
<meta name="robots" content="index, follow">
<link rel="canonical" href="<%= content_for(:canonical_url) || request.original_url %>">
<!-- Enhanced SEO -->
<meta name="theme-color" content="#ec3750">
<meta name="msapplication-TileColor" content="#ec3750">
<!-- Open Graph Tags -->
<meta property="og:title" content="<%= @og_title || content_for(:og_title) || @page_title || content_for(:title) || 'Hackatime - Free Coding Time Tracker' %>">
<meta property="og:description" content="<%= @og_description || content_for(:og_description) || @meta_description || content_for(:meta_description) || 'Track your coding time easily with Hackatime. A free tool to see how much time you spend programming. Better than WakaTime!' %>">
@@ -28,7 +28,7 @@
<meta property="og:image:height" content="630">
<meta property="og:site_name" content="Hackatime">
<meta property="og:locale" content="en_US">
<!-- Twitter Card Tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@hackclub">
@@ -39,7 +39,7 @@
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<% if current_user %>
<meta name="user-is-superadmin" content="<%= current_user.admin_level == "superadmin" %>">
<meta name="user-is-admin" content="<%= current_user.admin_level == "admin" %>">
@@ -47,7 +47,7 @@
<% end %>
<%= yield :head %>
<!-- JSON-LD Structured Data -->
<script type="application/ld+json">
{
@@ -79,7 +79,7 @@
]
}
</script>
<!-- Organization Schema -->
<script type="application/ld+json">
{
@@ -94,7 +94,7 @@
]
}
</script>
<!-- FAQ Schema for Homepage -->
<% if request.path == "/" %>
<script type="application/ld+json">
@@ -111,7 +111,7 @@
}
},
{
"@type": "Question",
"@type": "Question",
"name": "Is Hackatime free?",
"acceptedAnswer": {
"@type": "Answer",
@@ -147,8 +147,8 @@
</head>
<body class="<%= content_for(:body_class) %> flex min-h-screen bg-darker" data-controller="nav">
<button class="mobile-nav-button"
data-action="click->nav#toggle"
<button class="mobile-nav-button"
data-action="click->nav#toggle"
data-nav-target="button"
aria-label="Toggle navigation menu"
aria-expanded="false">
@@ -156,11 +156,11 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
<div class="nav-overlay" data-nav-target="overlay" data-action="click->nav#close"></div>
<%= render "shared/nav" %>
<!-- 250px is defined in nav.css -->
<main class="flex-1 lg:ml-[250px] lg:max-w-[calc(100%-250px)] p-5 mb-[100px] pt-16 lg:pt-5 transition-all duration-300 ease-in-out">
<%= yield %>
@@ -185,7 +185,7 @@
</main>
<div class="fixed top-0 right-5 max-w-sm max-h-[80vh] bg-elevated border border-darkless rounded-b-xl shadow-lg z-[1000] overflow-hidden transform -translate-y-full transition-transform duration-300 ease-out hidden"
data-controller="currently-hacking"
data-controller="currently-hacking"
data-currently-hacking-target="container"
data-currently-hacking-count-url-value="<%= currently_hacking_count_static_pages_path %>"
data-currently-hacking-full-url-value="<%= currently_hacking_static_pages_path %>"
@@ -207,7 +207,7 @@
<div class="flex flex-col items-center w-full">
<div class="mb-4 flex justify-center w-full">
<svg class="w-12 h-12 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path fill="currentColor" d="M5 5h6c.55 0 1-.45 1-1s-.45-1-1-1H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h6c.55 0 1-.45 1-1s-.45-1-1-1H5z"/><path fill="currentColor" d="m20.65 11.65l-2.79-2.79a.501.501 0 0 0-.86.35V11h-7c-.55 0-1 .45-1 1s.45 1 1 1h7v1.79c0 .45.54.67.85.35l2.79-2.79c.2-.19.2-.51.01-.7"/>
<path fill="currentColor" d="M5 5h6c.55 0 1-.45 1-1s-.45-1-1-1H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h6c.55 0 1-.45 1-1s-.45-1-1-1H5z" /><path fill="currentColor" d="m20.65 11.65l-2.79-2.79a.501.501 0 0 0-.86.35V11h-7c-.55 0-1 .45-1 1s.45 1 1 1h7v1.79c0 .45.54.67.85.35l2.79-2.79c.2-.19.2-.51.01-.7" />
</svg>
</div>
<h3 class="text-xl font-bold text-white mb-2 text-center w-full">Woah hold on a sec</h3>

View File

@@ -2,11 +2,11 @@
<% if leaderboard.present? %>
<%
entries = leaderboard.entries.respond_to?(:order) ? leaderboard.entries.order(total_seconds: :desc) : leaderboard.entries
top_entries = entries.first(3)
user_entry = current_user ? entries.find { |entry| entry.user_id == current_user.id } : nil
user_rank = user_entry ? entries.index(user_entry) : nil
if user_entry && user_rank && user_rank >= 3
person_above = entries[user_rank - 1] if user_rank > 0
person_below = entries[user_rank + 1] if user_rank < entries.length - 1
@@ -33,8 +33,8 @@
</p>
<div class="space-y-2">
<% mini_leaderboard_entries.each_with_index do |entry, idx| %>
<%
actual_rank = entries.index(entry)
<%
actual_rank = entries.index(entry)
is_separator_needed = show_user_separately && idx == 3 && actual_rank > 3
%>
@@ -81,4 +81,4 @@
</div>
<% end %>
<% end %>
<% end %>
<% end %>

View File

@@ -14,4 +14,4 @@
</div>
<% end %>
</div>
</div>
</div>

View File

@@ -124,4 +124,4 @@
</div>
<% end %>
</div>
</div>
</div>

View File

@@ -14,12 +14,12 @@
<div class="flex items-center gap-3 mb-4">
<div class="w-8 h-8 bg-green rounded-full flex items-center justify-center">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
</div>
<h2 class="text-xl font-bold text-green">Address on File</h2>
</div>
<div class="bg-darkless rounded-lg p-6 border-l-4 border-primary">
<div class="space-y-2 text-lg">
<p class="font-semibold text-white">
@@ -49,9 +49,9 @@
<% end %>
<div class="flex justify-center">
<%= link_to @user.mailing_address.present? ? "Update this address" : "Add your address",
edit_my_mailing_address_path,
<%= link_to @user.mailing_address.present? ? "Update this address" : "Add your address",
edit_my_mailing_address_path,
class: "bg-primary hover:bg-red text-white px-8 py-3 rounded-lg text-lg font-semibold transition-colors inline-flex items-center gap-2" %>
</div>
</div>
</div>
</div>

View File

@@ -14,7 +14,7 @@
<div class="flex items-center gap-3 mb-3">
<div class="w-8 h-8 bg-green rounded-full flex items-center justify-center">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
</div>
<h2 class="text-xl font-bold text-green">Address Verified</h2>
@@ -35,7 +35,7 @@
<h2 class="text-xl font-bold text-yellow">Mailing Address Required</h2>
</div>
<p class="text-lg mb-4">You need to add your mailing address for your mail to be sent.</p>
<%= link_to "Add my address", edit_my_mailing_address_path,
<%= link_to "Add my address", edit_my_mailing_address_path,
class: "bg-primary hover:bg-red text-white px-6 py-3 rounded-lg font-semibold transition-colors inline-block" %>
</section>
<% end %>
@@ -85,4 +85,4 @@
<% end %>
</section>
</div>
</div>
</div>

View File

@@ -9,14 +9,14 @@
<%= form_with(model: @project_repo_mapping, url: my_project_repo_mapping_path(@project_repo_mapping.project_name), method: :patch, local: true, class: "space-y-6") do |f| %>
<div class="space-y-2">
<%= f.label :project_name, "Project Name", class: "block text-sm font-semibold text-white" %>
<%= f.text_field :project_name, value: @project_repo_mapping.project_name, disabled: true,
<%= f.text_field :project_name, value: @project_repo_mapping.project_name, disabled: true,
class: "w-full px-4 py-3 bg-darkless text-secondary border border-darkless rounded-lg cursor-not-allowed" %>
<p class="text-xs text-secondary">Project name cannot be changed</p>
</div>
<div class="space-y-2">
<%= f.label :repo_url, "Repository URL", class: "block text-sm font-semibold text-white" %>
<%= f.url_field :repo_url, placeholder: "https://github.com/username/repo",
<%= f.url_field :repo_url, placeholder: "https://github.com/username/repo",
class: "w-full px-4 py-3 bg-darkless text-white border border-darkless rounded-lg focus:border-primary focus:outline-none transition-colors" %>
<p class="text-xs text-secondary">Enter the full GitHub repository URL</p>
</div>
@@ -28,4 +28,4 @@
<% end %>
</div>
</div>
</div>
</div>

View File

@@ -11,4 +11,4 @@
<%= 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>
<% end %>
<% end %>

View File

@@ -30,25 +30,25 @@
// Common function to update URL parameters and refresh the frame
function updateWithParams(params) {
const url = new URL(window.location.href);
// Clear existing parameters
url.searchParams.delete('interval');
url.searchParams.delete('from');
url.searchParams.delete('to');
// Add new parameters
Object.entries(params).forEach(([key, value]) => {
if (value) url.searchParams.set(key, value);
});
updateProjectsFrame(url.toString());
}
function updateProjectsFrame(url) {
let baseUrl = '<%= project_durations_static_pages_path %>';
const params = new URLSearchParams(new URL(url).search);
const frameUrl = baseUrl + '?' + params.toString();
const frame = document.getElementById('project_durations');
if (frame) {
console.log('Updating frame with URL:', frameUrl);
@@ -78,11 +78,11 @@
document.getElementById('interval-dropdown-menu').style.display = 'none';
updateWithParams({ interval });
}
function applyCustomRange() {
const start = document.getElementById('custom-start').value;
const end = document.getElementById('custom-end').value;
if (start || end) {
let label = 'Custom Range';
if (start && end) {
@@ -92,19 +92,19 @@
} else if (end) {
label = `Until ${end}`;
}
updateDropdownLabel(label);
document.getElementById('interval-dropdown-menu').style.display = 'none';
updateWithParams({ interval: 'custom', from: start, to: end });
}
}
function toggleIntervalDropdown() {
const menu = document.getElementById('interval-dropdown-menu');
menu.style.display = menu.style.display === 'block' ? 'none' : 'block';
document.addEventListener('mousedown', closeDropdownOnClickOutside);
}
function closeDropdownOnClickOutside(e) {
const menu = document.getElementById('interval-dropdown-menu');
const trigger = document.querySelector('.interval-dropdown-trigger');
@@ -127,9 +127,9 @@
color: white;
cursor: pointer;
}
.interval-custom-range .primary-button:hover {
filter: brightness(1.1);
}
</style>
<% end %>
<% end %>

View File

@@ -12,15 +12,14 @@
<div class="options-list">
<% values.reject(&:blank?).each do |value| %>
<label class="option">
<input
type="checkbox"
value="<%= value %>"
<%= 'checked' if selected&.include?(value) %>
>
<input
type="checkbox"
value="<%= value %>"
<%= 'checked' if selected&.include?(value) %>>
<span><%= value %></span>
</label>
<% end %>
</div>
</div>
</div>
</div>
</div>

View File

@@ -6,8 +6,7 @@
"border-green text-green"
else
"border-primary text-primary"
end
%>
end %>
<div>
<div class="rounded-lg border text-center text-lg px-3 py-2 mb-2 <%= c %>"><%= msg %></div>
</div>
@@ -76,8 +75,7 @@
class="w-full text-left cursor-pointer block px-2 py-1 rounded-lg transition hover:text-primary"
style="display: block; padding: 10px 15px; border-radius: 6px; transition: background-color 0.15s, color 0.15s; text-decoration: none;"
onmouseover="this.style.color='var(--primary-color, #e13950)'"
onmouseout="this.style.color=''"
> <!-- sorry but what the fuck is this hover logic-->
onmouseout="this.style.color=''"> <!-- sorry but what the fuck is this hover logic-->
Logout
</button>
</div>

View File

@@ -35,4 +35,4 @@
<% end %>
<% end %>
<% end %>
</div>
</div>

View File

@@ -1,12 +1,11 @@
<%# This is a partial for a video that plays on hover. it's provided a src %>
<video
<video
class="video-on-hover"
src="<%= src %>"
controls
playsinline
onmouseover="this.play()"
<%# onmouseout="this.pause()" %>
>
<%# onmouseout="this.pause()" %>>
Your browser does not support the video tag.
</video>
@@ -17,4 +16,4 @@
max-width: 200px;
max-height: 200px;
}
</style>
</style>

View File

@@ -35,4 +35,3 @@
</div>
<% end %>
<% end %>

View File

@@ -39,7 +39,7 @@
</div>
<div id="filterable_dashboard_content">
<%= render partial: 'filterable_dashboard_content' %>
<%= render partial: 'filterable_dashboard_content' %>
</div>
<script>
@@ -47,14 +47,14 @@
window.initializeMultiSelect = window.initializeMultiSelect || function(selectId) {
const select = document.getElementById(selectId);
if (!select || select.dataset.initialized) return;
select.dataset.initialized = 'true';
const header = select.querySelector('.select-header');
const container = select.querySelector('.options-container');
const checkboxes = select.querySelectorAll('input[type="checkbox"]');
const clearButton = select.querySelector('.clear-button');
const searchInput = select.querySelector('.search-input');
// Initialize clear button visibility
const checkedBoxes = Array.from(checkboxes).filter(cb => cb.checked);
if (checkedBoxes.length > 0 && clearButton) {
@@ -65,20 +65,20 @@
header.textContent = `${checkedBoxes.length} selected`;
}
}
// Toggle dropdown
header.addEventListener('click', function(e) {
e.stopPropagation();
const isVisible = container.style.display === 'block';
// Close all other dropdowns
document.querySelectorAll('.options-container').forEach(c => {
if (c !== container) c.style.display = 'none';
});
// Toggle current dropdown
container.style.display = isVisible ? 'none' : 'block';
// Focus search input when opening
if (!isVisible && searchInput) {
searchInput.focus();
@@ -100,7 +100,7 @@
console.log('searchInput.addEventListener', e.target.value);
const searchTerm = e.target.value.toLowerCase().trim();
const options = select.querySelectorAll('.option');
options.forEach(option => {
const text = option.querySelector('span').textContent.toLowerCase().trim();
option.style.display = text.includes(searchTerm) ? '' : 'none';
@@ -130,11 +130,11 @@
const frame = document.querySelector('#filterable_dashboard_content');
frame.classList.add('loading');
const selected = Array.from(checkboxes)
.filter(cb => cb.checked)
.map(cb => cb.value);
// Update header text
if (selected.length === 0) {
header.textContent = `Filter by ${header.closest('.filter').querySelector('.filter-label').textContent.slice(2).toLowerCase()}...`;
@@ -163,7 +163,7 @@
// Let Turbo handle the content update
frame.src = contentUrl.toString();
// Track this request with a timestamp
const requestTimestamp = Date.now();
window.lastRequestTimestamp = requestTimestamp;
@@ -200,7 +200,7 @@
});
}
});
</script>
</script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js" data-turbo-track="reload"></script>
@@ -212,7 +212,7 @@
formatDuration(seconds) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
if (hours > 0) {
return `${hours}h ${minutes}m`;
} else {
@@ -279,7 +279,7 @@
if (!canvas) return;
const weeklyStats = JSON.parse(canvas.dataset.stats);
const allProjects = new Set();
Object.values(weeklyStats).forEach(weekData => {
Object.keys(weekData).forEach(project => allProjects.add(project));
@@ -387,7 +387,7 @@
if (!window.chartListenersInitialized) {
window.chartListenersInitialized = true;
document.addEventListener('turbo:frame-load', () => {
if (typeof Chart === 'undefined') {
const checkChart = setInterval(() => {
@@ -407,4 +407,4 @@
window.hackatimeCharts.initializeCharts();
}
</script>
<% end %>
<% end %>

View File

@@ -4,7 +4,7 @@
<div class="stat-label">TOTAL TIME</div>
<div class="stat-value" data-stat="total_time"><%= ApplicationController.helpers.short_time_simple(@total_time) %></div>
</div>
<% dev_tool do %>
<div class="stat-card">
<div class="stat-label">TOTAL HEARTBEATS</div>
@@ -13,7 +13,7 @@
</div>
</div>
<% end %>
<div class="stat-card">
<div class="stat-label">TOP PROJECT</div>
<div class="stat-value" data-stat="top_project">
@@ -23,7 +23,7 @@
<% end %>
</div>
</div>
<div class="stat-card">
<div class="stat-label">TOP LANGUAGE</div>
<div class="stat-value" data-stat="top_language">
@@ -33,7 +33,7 @@
<% end %>
</div>
</div>
<div class="stat-card">
<div class="stat-label">TOP OS</div>
<div class="stat-value" data-stat="top_operating_system">
@@ -43,7 +43,7 @@
<% end %>
</div>
</div>
<div class="stat-card">
<div class="stat-label">TOP EDITOR</div>
<div class="stat-value" data-stat="top_editor">
@@ -60,7 +60,7 @@
<div class="card">
<h2>Project Durations</h2>
<div class="bar-graph">
<%
<%
max_duration = @project_durations.values.max
min_duration = @project_durations.values.min
@@ -70,20 +70,20 @@
return 0 if value == 0
min_percent = 5 # Minimum bar width percentage
max_percent = 100 # Maximum bar width percentage
# Mix linear and logarithmic scaling
# 80% linear, 20% logarithmic
linear_ratio = value.to_f / max_val
log_ratio = Math.log(value + 1) / Math.log(max_val + 1)
linear_weight = 0.8
log_weight = 0.2
scaled = min_percent + (linear_weight * linear_ratio + log_weight * log_ratio) * (max_percent - min_percent)
[scaled, max_percent].min.round
end
%>
<% @project_durations.each do |project, duration| %>
<div class="bar-row">
<div class="bar-label"><%= h(project.presence || "Unknown") %></div>
@@ -135,4 +135,4 @@
</div>
</div>
</div>
</div>
</div>

View File

@@ -13,7 +13,7 @@
<% if project[:repository]&.stars.present? %>
<div class="flex items-center gap-1 text-sm text-yellow-400">
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20">
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/>
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
</svg>
<%= project[:repository].stars %>
</div>
@@ -23,21 +23,21 @@
<% if project[:repository]&.homepage.present? %>
<%= link_to project[:repository].homepage, target: "_blank", title: "View project website", class: "p-2 rounded-lg bg-white/5 hover:bg-white/10 transition-colors duration-200" do %>
<svg class="w-4 h-4 text-white/70" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path fill="currentColor" d="M16.36 14c.08-.66.14-1.32.14-2s-.06-1.34-.14-2h3.38c.16.64.26 1.31.26 2s-.1 1.36-.26 2m-5.15 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95a8.03 8.03 0 0 1-4.33 3.56M14.34 14H9.66c-.1-.66-.16-1.32-.16-2s.06-1.35.16-2h4.68c.09.65.16 1.32.16 2s-.07 1.34-.16 2M12 19.96c-.83-1.2-1.5-2.53-1.91-3.96h3.82c-.41 1.43-1.08 2.76-1.91 3.96M8 8H5.08A7.92 7.92 0 0 1 9.4 4.44C8.8 5.55 8.35 6.75 8 8m-2.92 8H8c.35 1.25.8 2.45 1.4 3.56A8 8 0 0 1 5.08 16m-.82-2C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2s.06 1.34.14 2M12 4.03c.83 1.2 1.5 2.54 1.91 3.97h-3.82c.41-1.43 1.08-2.77 1.91-3.97M18.92 8h-2.95a15.7 15.7 0 0 0-1.38-3.56c1.84.63 3.37 1.9 4.33 3.56M12 2C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2"/>
<path fill="currentColor" d="M16.36 14c.08-.66.14-1.32.14-2s-.06-1.34-.14-2h3.38c.16.64.26 1.31.26 2s-.1 1.36-.26 2m-5.15 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95a8.03 8.03 0 0 1-4.33 3.56M14.34 14H9.66c-.1-.66-.16-1.32-.16-2s.06-1.35.16-2h4.68c.09.65.16 1.32.16 2s-.07 1.34-.16 2M12 19.96c-.83-1.2-1.5-2.53-1.91-3.96h3.82c-.41 1.43-1.08 2.76-1.91 3.96M8 8H5.08A7.92 7.92 0 0 1 9.4 4.44C8.8 5.55 8.35 6.75 8 8m-2.92 8H8c.35 1.25.8 2.45 1.4 3.56A8 8 0 0 1 5.08 16m-.82-2C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2s.06 1.34.14 2M12 4.03c.83 1.2 1.5 2.54 1.91 3.97h-3.82c.41-1.43 1.08-2.77 1.91-3.97M18.92 8h-2.95a15.7 15.7 0 0 0-1.38-3.56c1.84.63 3.37 1.9 4.33 3.56M12 2C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2" />
</svg>
<% end %>
<% end %>
<% if project[:repo_url].present? %>
<%= link_to project[:repo_url], target: "_blank", title: "View repository", class: "p-2 rounded-lg bg-white/5 hover:bg-white/10 transition-colors duration-200" do %>
<svg class="w-4 h-4 text-white/70" fill="currentColor" viewBox="0 0 24 24">
<path fill="currentColor" d="M2.6 10.59L8.38 4.8l1.69 1.7c-.24.85.15 1.78.93 2.23v5.54c-.6.34-1 .99-1 1.73a2 2 0 0 0 2 2a2 2 0 0 0 2-2c0-.74-.4-1.39-1-1.73V9.41l2.07 2.09c-.07.15-.07.32-.07.5a2 2 0 0 0 2 2a2 2 0 0 0 2-2a2 2 0 0 0-2-2c-.18 0-.35 0-.5.07L13.93 7.5a1.98 1.98 0 0 0-1.15-2.34c-.43-.16-.88-.2-1.28-.09L9.8 3.38l.79-.78c.78-.79 2.04-.79 2.82 0l7.99 7.99c.79.78.79 2.04 0 2.82l-7.99 7.99c-.78.79-2.04.79-2.82 0L2.6 13.41c-.79-.78-.79-2.04 0-2.82"/>
<path fill="currentColor" d="M2.6 10.59L8.38 4.8l1.69 1.7c-.24.85.15 1.78.93 2.23v5.54c-.6.34-1 .99-1 1.73a2 2 0 0 0 2 2a2 2 0 0 0 2-2c0-.74-.4-1.39-1-1.73V9.41l2.07 2.09c-.07.15-.07.32-.07.5a2 2 0 0 0 2 2a2 2 0 0 0 2-2a2 2 0 0 0-2-2c-.18 0-.35 0-.5.07L13.93 7.5a1.98 1.98 0 0 0-1.15-2.34c-.43-.16-.88-.2-1.28-.09L9.8 3.38l.79-.78c.78-.79 2.04-.79 2.82 0l7.99 7.99c.79.78.79 2.04 0 2.82l-7.99 7.99c-.78.79-2.04.79-2.82 0L2.6 13.41c-.79-.78-.79-2.04 0-2.82" />
</svg>
<% end %>
<% end %>
<% if current_user.github_uid.present? && project[:project].present? %>
<%= link_to edit_my_project_repo_mapping_path(project_name: CGI.escape(project[:project])), class: "p-2 rounded-lg bg-white/5 hover:bg-white/10 transition-colors duration-200", data: { turbo_frame: '_top'}, title: "Edit mapping" do %>
<svg class="w-4 h-4 text-white/70" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path fill="currentColor" d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83l3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75z"/>
<path fill="currentColor" d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83l3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75z" />
</svg>
<% end %>
<% end %>
@@ -50,8 +50,7 @@
<div class="w-16 h-2 bg-white/10 rounded-full overflow-hidden">
<div
class="h-full bg-primary transition-all duration-500 rounded-full"
style="width: <%= [project[:duration].to_f / max.to_f * 100, 100].min %>%;"
></div>
style="width: <%= [project[:duration].to_f / max.to_f * 100, 100].min %>%;"></div>
</div>
<span class="text-xs text-white/40"><%= number_to_percentage([project[:duration].to_f / max.to_f * 100, 100].min, precision: 0) %></span>
</div>
@@ -66,7 +65,7 @@
<% if project[:repository]&.formatted_languages.present? %>
<div class="flex items-center gap-1 text-sm">
<svg class="w-4 h-4 text-white/50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path fill="currentColor" d="M5.59 3.41L7 4.82L3.82 8L7 11.18L5.59 12.6L1 8zm5.82 0L16 8l-4.59 4.6L10 11.18L13.18 8L10 4.82zM22 6v12c0 1.11-.89 2-2 2H4a2 2 0 0 1-2-2v-4h2v4h16V6h-2.97V4H20c1.11 0 2 .89 2 2"/>
<path fill="currentColor" d="M5.59 3.41L7 4.82L3.82 8L7 11.18L5.59 12.6L1 8zm5.82 0L16 8l-4.59 4.6L10 11.18L13.18 8L10 4.82zM22 6v12c0 1.11-.89 2-2 2H4a2 2 0 0 1-2-2v-4h2v4h16V6h-2.97V4H20c1.11 0 2 .89 2 2" />
</svg>
<span class="text-white/50"><%= project[:repository].formatted_languages %></span>
</div>
@@ -75,7 +74,7 @@
<% if project[:repository]&.last_commit_at.present? %>
<div class="flex items-center gap-1 text-sm">
<svg class="w-4 h-4 text-white/50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path fill="currentColor" d="M12 20c4.4 0 8-3.6 8-8s-3.6-8-8-8s-8 3.6-8 8s3.6 8 8 8m0-18c5.5 0 10 4.5 10 10s-4.5 10-10 10S2 17.5 2 12S6.5 2 12 2m.5 10.8l-4.8 2.8l-.7-1.4l4-2.3V7h1.5z"/>
<path fill="currentColor" d="M12 20c4.4 0 8-3.6 8-8s-3.6-8-8-8s-8 3.6-8 8s3.6 8 8 8m0-18c5.5 0 10 4.5 10 10s-4.5 10-10 10S2 17.5 2 12S6.5 2 12 2m.5 10.8l-4.8 2.8l-.7-1.4l4-2.3V7h1.5z" />
</svg>
<span class="text-white/50">Last commit <%= time_ago_in_words(project[:repository].last_commit_at) %> ago</span>
</div>

View File

@@ -2,7 +2,7 @@
<% if current_user&.trust_level == "red" %>
<div class="text-primary bg-red-500/10 border-2 border-red-500/20 p-4 text-center rounded-lg mb-4">
<div class="flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 16 16"><path fill="currentColor" fill-rule="evenodd" d="M8 14.5a6.5 6.5 0 1 0 0-13a6.5 6.5 0 0 0 0 13M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m1-5a1 1 0 1 1-2 0a1 1 0 0 1 2 0m-.25-6.25a.75.75 0 0 0-1.5 0v3.5a.75.75 0 0 0 1.5 0z" clip-rule="evenodd"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 16 16"><path fill="currentColor" fill-rule="evenodd" d="M8 14.5a6.5 6.5 0 1 0 0-13a6.5 6.5 0 0 0 0 13M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m1-5a1 1 0 1 1-2 0a1 1 0 0 1 2 0m-.25-6.25a.75.75 0 0 0-1.5 0v3.5a.75.75 0 0 0 1.5 0z" clip-rule="evenodd" /></svg>
<span class="text-3xl font-bold block ml-2">Hold up! Your account has been banned for suspicious activity.</span>
</div>
<div>
@@ -71,7 +71,7 @@
<%= h(user[:display_name]) %>
<div class="absolute top-full left-1/2 -ml-1 border-l-2 border-r-2 border-t-2 border-transparent border-t-gray-800"></div>
</div>
<img src="<%= user[:avatar_url] %>" alt="<%= h(user[:display_name]) %>" class="w-10 h-10 rounded-full border-2 border-primary object-cover shadow-sm" />
<img src="<%= user[:avatar_url] %>" alt="<%= h(user[:display_name]) %>" class="w-10 h-10 rounded-full border-2 border-primary object-cover shadow-sm">
</div>
<% end %>
<% if @ssp_users_size && @ssp_users_size > 5 %>
@@ -82,7 +82,7 @@
<div class="flex flex-col gap-2">
<% @ssp_users_recent.each do |user| %>
<div class="flex items-center p-1 rounded hover:bg-gray-700 transition-colors duration-200">
<img src="<%= user[:avatar_url] %>" alt="<%= h(user[:display_name]) %>" class="w-8 h-8 rounded-full mr-2 border border-primary" />
<img src="<%= user[:avatar_url] %>" alt="<%= h(user[:display_name]) %>" class="w-8 h-8 rounded-full mr-2 border border-primary">
<span class="font-medium text-sm"><%= h(user[:display_name]) %></span>
</div>
<% end %>
@@ -171,4 +171,4 @@
</div>
</div>
<% end %>
</div>
</div>

View File

@@ -11,4 +11,4 @@
<%= 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>
<% end %>
<% end %>

View File

@@ -1,10 +1,10 @@
<%= form_with model: user, url: (@is_own_settings ? my_settings_path : settings_user_path(user)), method: :patch, local: false, class: "space-y-4" do |f| %>
<div class="flex items-center gap-3">
<%= f.check_box :default_timezone_leaderboard,
checked: user.default_timezone_leaderboard,
<%= f.check_box :default_timezone_leaderboard,
checked: user.default_timezone_leaderboard,
id: "user_default_timezone_leaderboard",
class: "w-4 h-4 text-primary border-gray-600 rounded focus:ring-primary bg-gray-800" %>
<%= f.label :default_timezone_leaderboard, "Default to Timezone Leaderboard",
<%= f.label :default_timezone_leaderboard, "Default to Timezone Leaderboard",
for: "user_default_timezone_leaderboard",
class: "text-sm text-gray-200" %>
</div>

View File

@@ -29,4 +29,4 @@
<%= f.submit "Add Mirror", class: "button" %>
<% end %>
</section>
</section>

View File

@@ -19,7 +19,7 @@
<h2 class="text-xl font-semibold text-white">Time Tracking Wizard</h2>
</div>
<p class="text-gray-300 mb-4">Get started with tracking your coding time in just a few minutes.</p>
<%= link_to "Set up time tracking", my_wakatime_setup_path,
<%= link_to "Set up time tracking", my_wakatime_setup_path,
class: "inline-flex items-center gap-2 px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
</div>
@@ -36,7 +36,7 @@
class: "space-y-4" do |f| %>
<div>
<%= f.label :timezone, "Your timezone", class: "block text-sm font-medium text-gray-200 mb-2" %>
<%= f.select :timezone,
<%= f.select :timezone,
TZInfo::Timezone.all.map(&:identifier).sort,
{ include_blank: @user.timezone.blank? },
{ class: "w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded text-white focus:border-primary focus:ring-1 focus:ring-primary" } %>
@@ -75,22 +75,22 @@
</div>
<h2 class="text-xl font-semibold text-white" id="user_slack_status">Slack Integration</h2>
</div>
<div class="space-y-4">
<div>
<h3 class="text-lg font-medium text-white mb-2">Status Updates</h3>
<p class="text-gray-300 text-sm mb-3">When you're hacking on a project, Hackatime can update your Slack status so you can show it off!</p>
<% unless @can_enable_slack_status %>
<%= link_to "Re-authorize with Slack", slack_auth_path,
<%= link_to "Re-authorize with Slack", slack_auth_path,
class: "inline-flex items-center gap-2 px-3 py-2 bg-gray-700 hover:bg-gray-600 text-gray-200 text-sm font-medium rounded transition-colors duration-200 mb-3" %>
<% end %>
<%= form_with model: @user,
url: @is_own_settings ? my_settings_path : settings_user_path(@user),
method: :patch, local: false do |f| %>
<div class="flex items-center gap-3">
<%= f.check_box :uses_slack_status,
<%= f.check_box :uses_slack_status,
class: "w-4 h-4 text-primary border-gray-600 rounded focus:ring-primary bg-gray-800" %>
<%= f.label :uses_slack_status, "Update my Slack status automatically",
<%= f.label :uses_slack_status, "Update my Slack status automatically",
class: "text-sm text-gray-200" %>
</div>
<%= f.submit "Save", class: "mt-3 px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
@@ -130,9 +130,9 @@
method: :patch, local: false,
class: "space-y-4" do |f| %>
<div class="flex items-center gap-3">
<%= f.check_box :allow_public_stats_lookup,
<%= f.check_box :allow_public_stats_lookup,
class: "w-4 h-4 text-primary border-gray-600 rounded focus:ring-primary bg-gray-800" %>
<%= f.label :allow_public_stats_lookup, "Allow public stats lookup",
<%= f.label :allow_public_stats_lookup, "Allow public stats lookup",
class: "text-sm text-gray-200" %>
</div>
<p class="text-xs text-gray-400">When enabled, others can view your coding statistics through public APIs.</p>
@@ -158,7 +158,7 @@
</div>
<h2 class="text-xl font-semibold text-white" id="user_github_account">Connected Accounts</h2>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="space-y-3">
<h3 class="text-lg font-medium text-white">GitHub Account</h3>
@@ -170,7 +170,7 @@
</div>
<%= link_to "Relink GitHub Account", github_auth_path, data: { turbo: "false" }, class: "inline-flex items-center gap-2 px-3 py-2 bg-primary text-white text-sm font-medium rounded transition-colors duration-200" %>
<% else %>
<%= link_to "Link GitHub Account", github_auth_path, data: { turbo: "false" },
<%= link_to "Link GitHub Account", github_auth_path, data: { turbo: "false" },
class: "inline-flex items-center gap-2 px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
<% end %>
</div>
@@ -193,8 +193,8 @@
<p class="text-gray-400 text-sm">No email addresses found.</p>
<% end %>
<%= form_tag add_email_auth_path, data: { turbo: false }, class: "space-y-2" do %>
<%= email_field_tag :email, nil,
placeholder: "Add another email address",
<%= email_field_tag :email, nil,
placeholder: "Add another email address",
required: true,
class: "w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded text-white focus:border-primary focus:ring-1 focus:ring-primary text-sm" %>
<%= submit_tag "Add Email", class: "w-full px-3 py-2 bg-primary hover:bg-primary/80 text-white text-sm font-medium rounded transition-colors duration-200" %>
@@ -210,23 +210,23 @@
</div>
<h2 class="text-xl font-semibold text-white" id="user_stats_badges">Stats Badges</h2>
</div>
<div class="space-y-6">
<div>
<h3 class="text-lg font-medium text-white mb-2">General Stats Badge</h3>
<p class="text-gray-300 text-sm mb-4">Show your coding stats on your GitHub profile with beautiful badges.</p>
<div class="space-y-3">
<div>
<label class="block text-sm font-medium text-gray-200 mb-2">Theme</label>
<select name="theme" id="theme-select" onchange="up1(this.value)"
<select name="theme" id="theme-select" onchange="up1(this.value)"
class="w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded text-white focus:border-primary focus:ring-1 focus:ring-primary">
<% GithubReadmeStats.themes.each do |theme| %>
<option value="<%= theme %>"><%= theme.humanize %></option>
<% end %>
</select>
</div>
<% gh_badge = GithubReadmeStats.new(current_user.id, "darcula") %>
<div class="p-4 bg-gray-800 border border-gray-600 rounded">
<img id="badge-preview" src="<%= gh_badge.generate_badge_url %>" data-url="<%= gh_badge.generate_badge_url %>" class="mb-3 rounded">
@@ -264,7 +264,7 @@
preview.src = newUrl;
url.textContent = newUrl;
}
function up2(project) {
const preview = document.getElementById('project-badge-preview');
const url = document.getElementById('project-badge-url');
@@ -285,7 +285,7 @@
<h2 class="text-xl font-semibold text-white" id="user_config_file">Config File</h2>
</div>
<p class="text-gray-300 text-sm mb-4">Your Wakatime configuration file for tracking coding time.</p>
<div class="bg-gray-800 border border-gray-600 rounded p-4 overflow-x-auto">
<%= render "wakatime_config_display" %>
</div>
@@ -302,10 +302,10 @@
<h2 class="text-xl font-semibold text-white" id="user_migration_assistant">Migration Assistant</h2>
</div>
<p class="text-gray-300 text-sm mb-4">This will migrate your heartbeats from waka.hackclub.com to this platform.</p>
<%= button_to "Migrate heartbeats", my_settings_migrate_heartbeats_path, method: :post,
<%= button_to "Migrate heartbeats", my_settings_migrate_heartbeats_path, method: :post,
class: "w-full px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
<% if @heartbeats_migration_jobs.any? %>
<div class="mt-4 space-y-2">
<h3 class="text-sm font-medium text-white">Migration Status</h3>
@@ -327,7 +327,7 @@
<h2 class="text-xl font-semibold text-white" id="user_markscribe">Markscribe Templates</h2>
</div>
<p class="text-gray-300 text-sm mb-4">Use markscribe to create beautiful GitHub profile READMEs with your coding stats.</p>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div>
<div class="p-4 bg-gray-800 border border-gray-600 rounded mb-4 overflow-x-auto">
@@ -337,9 +337,9 @@
<p class="text-xs text-gray-400">See the <a href="https://github.com/taciturnaxolotl/markscribe#your-wakatime-languages-formated-as-a-bar" target="_blank" class="text-primary hover:text-primary/80 underline">markscribe documentation</a> for more template options.</p>
</div>
<div>
<img src="https://cdn.fluff.pw/slackcdn/524e293aa09bc5f9115c0c29c18fb4bc.png"
alt="Example of markscribe output showing coding language and project statistics"
class="w-full rounded border border-gray-600"/>
<img src="https://cdn.fluff.pw/slackcdn/524e293aa09bc5f9115c0c29c18fb4bc.png"
alt="Example of markscribe output showing coding language and project statistics"
class="w-full rounded border border-gray-600">
</div>
</div>
</div>
@@ -352,7 +352,7 @@
</div>
<h2 class="text-xl font-semibold text-white">WakaTime Mirrors</h2>
</div>
<% if current_user.wakatime_mirrors.any? %>
<% grid_cols = current_user.wakatime_mirrors.size > 1 ? "md:grid-cols-2" : "" %>
<div class="grid grid-cols-1 <%= grid_cols %> gap-4 mb-4">

View File

@@ -10,4 +10,4 @@
<%= turbo_frame_tag "filterable_dashboard", src: filterable_dashboard_static_pages_path do %>
<span>Loading...</span>
<% end %>
<% end %>

View File

@@ -49,7 +49,7 @@
<div class="rounded-lg mb-6">
<iframe width="100%" height="300" src="https://www.youtube.com/embed/QTwhJy7nT_w?loop=1&playlist=QTwhJy7nT_w&modestbranding=1&rel=0" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen class="rounded"></iframe>
</div>
<div class="flex gap-4 flex-wrap">
<button id="show-windows-button" class="bg-blue hover:bg-cyan text-white border-0 px-4 py-2 rounded transition-colors cursor-pointer" onclick="toggleSection('windows')">Using Windows?</button>
<button id="show-advanced-button-from-mac" class="bg-purple hover:bg-darkless text-white border-0 px-4 py-2 rounded transition-colors cursor-pointer" onclick="toggleSection('advanced')">Custom Setup</button>
@@ -71,7 +71,7 @@
<div class="rounded-lg mb-6">
<iframe width="100%" height="300" src="https://www.youtube.com/embed/fX9tsiRvzhg?loop=1&playlist=fX9tsiRvzhg&modestbranding=1&rel=0" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen class="rounded"></iframe>
</div>
<div class="flex gap-4 flex-wrap">
<button id="show-mac-linux-button" class="bg-green hover:bg-cyan text-white border-0 px-4 py-2 rounded transition-colors cursor-pointer" onclick="toggleSection('mac-linux')">Using Mac/Linux/Codespaces?</button>
<button id="show-advanced-button" class="bg-purple hover:bg-darkless text-white border-0 px-4 py-2 rounded transition-colors cursor-pointer" onclick="toggleSection('advanced')">Custom Setup</button>
@@ -84,12 +84,12 @@
<p class="text-sm">For advanced users who want to manually configure their setup or have specific requirements.</p>
</div>
<p class="text-lg mb-4">Create or edit <code class="bg-darkless px-2 py-1 rounded text-cyan">~/.wakatime.cfg</code> with the following content:</p>
<div class="code-block bg-darkless rounded-lg p-4 mb-6">
<code class="text-cyan text-sm">[settings]&#10;api_url = <%= api_hackatime_v1_url %>&#10;api_key = <%= @current_user_api_key %>&#10;heartbeat_rate_limit_seconds = 30</code>
<button class="copy-button bg-primary hover:bg-red border-0 text-white px-6 py-2 rounded transition-colors cursor-pointer font-semibold" onclick="copy(this)">Copy</button>
</div>
<div class="flex gap-4 flex-wrap">
<button id="show-mac-linux-from-advanced-button" class="bg-green hover:bg-cyan text-white border-0 px-4 py-2 rounded transition-colors cursor-pointer" onclick="toggleSection('mac-linux')">Using Mac/Linux/Codespaces?</button>
<button id="show-windows-from-advanced-button" class="bg-blue hover:bg-cyan text-white border-0 px-4 py-2 rounded transition-colors cursor-pointer" onclick="toggleSection('windows')">Using Windows?</button>
@@ -121,19 +121,19 @@
mac.style.display = 'block';
}
}
document.addEventListener('turbo:load', function() {
a();
window.toggleSection = function(section) {
const mac = document.getElementById('mac-linux');
const windows = document.getElementById('windows');
const advanced = document.getElementById('advanced');
mac.style.display = 'block';
windows.style.display = 'none';
advanced.style.display = 'none';
if (section === 'windows') {
windows.style.display = 'block';
} else if (section === 'advanced') {
@@ -142,7 +142,7 @@
mac.style.display = 'block';
}
}
const statusDiv = document.getElementById('heartbeat-status');
const nextStepLink = document.getElementById('next-step');
let checkCount = 0;
@@ -258,11 +258,11 @@
flex-direction: column;
align-items: stretch;
}
.code-block code {
margin-bottom: 1rem;
}
iframe {
height: 200px;
}

View File

@@ -5,7 +5,7 @@
<div class="flex items-center justify-center gap-2 mb-4">
<div class="w-8 h-8 bg-green rounded-full flex items-center justify-center text-sm font-bold">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
</div>
<div class="w-16 h-1 bg-green"></div>
@@ -26,7 +26,7 @@
<div class="bg-dark rounded-lg p-6 hover:bg-darkless transition-colors">
<%= link_to my_wakatime_setup_step_3_path(anchor: "vs-code"), class: "flex items-center gap-4 text-white no-underline" do %>
<div class="w-12 h-12 rounded-lg flex items-center justify-center">
<img src="/images/editor-icons/vs-code-128.png" alt="VS Code" class="w-full h-full object-contain" />
<img src="/images/editor-icons/vs-code-128.png" alt="VS Code" class="w-full h-full object-contain">
</div>
<div>
<h3 class="text-xl font-bold">Visual Studio Code</h3>
@@ -34,7 +34,7 @@
</div>
<div class="ml-auto text-primary flex items-center">
<svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
</svg>
</div>
<% end %>
@@ -43,7 +43,7 @@
<div class="bg-dark rounded-lg p-6 hover:bg-darkless transition-colors">
<%= link_to my_wakatime_setup_step_3_path(anchor: "vim"), class: "flex items-center gap-4 text-white no-underline" do %>
<div class="w-12 h-12 rounded-lg flex items-center justify-center">
<img src="/images/editor-icons/vim-128.png" alt="Vim" class="w-full h-full object-contain" />
<img src="/images/editor-icons/vim-128.png" alt="Vim" class="w-full h-full object-contain">
</div>
<div>
<h3 class="text-xl font-bold">Vim</h3>
@@ -51,7 +51,7 @@
</div>
<div class="ml-auto text-primary flex items-center">
<svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
</svg>
</div>
<% end %>
@@ -60,7 +60,7 @@
<div class="bg-dark rounded-lg p-6 hover:bg-darkless transition-colors">
<%= link_to my_wakatime_setup_step_3_path, class: "flex items-center gap-4 text-white no-underline" do %>
<div class="w-12 h-12 rounded-lg flex items-center justify-center">
<img src="/images/editor-icons/emacs-128.png" alt="Emacs" class="w-full h-full object-contain" />
<img src="/images/editor-icons/emacs-128.png" alt="Emacs" class="w-full h-full object-contain">
</div>
<div>
<h3 class="text-xl font-bold">Emacs</h3>
@@ -68,7 +68,7 @@
</div>
<div class="ml-auto text-primary flex items-center">
<svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
</svg>
</div>
<% end %>
@@ -83,7 +83,7 @@
</div>
<div class="ml-auto text-primary flex items-center">
<svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
</svg>
</div>
<% end %>

View File

@@ -5,13 +5,13 @@
<div class="flex items-center justify-center gap-2 mb-4">
<div class="w-8 h-8 bg-green rounded-full flex items-center justify-center text-sm font-bold">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
</div>
<div class="w-16 h-1 bg-green"></div>
<div class="w-8 h-8 bg-green rounded-full flex items-center justify-center text-sm font-bold">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
</div>
<div class="w-16 h-1 bg-green"></div>
@@ -36,14 +36,14 @@
</p>
</div>
</section>
<section id="vs-code" class="bg-dark rounded-lg p-6">
<h3 class="text-2xl font-bold text-blue mb-4">💻 VS Code (Visual Studio Code)</h3>
<div class="space-y-6">
<p class="text-lg">
<em>Hackatime uses the VS Code WakaTime extension. For VS Code, install the <a href="https://marketplace.visualstudio.com/items?itemName=WakaTime.vscode-wakatime" target="_blank" rel="noopener noreferrer" class="text-cyan hover:text-blue underline">WakaTime extension here</a>.</em>
</p>
<div>
<p class="text-lg mb-4">You'll know it works if you see a clock in your status bar, for example I already coded so it shows how much I have coded today</p>
<div>

View File

@@ -5,25 +5,25 @@
<div class="flex items-center justify-center gap-2 mb-4">
<div class="w-8 h-8 bg-green rounded-full flex items-center justify-center text-sm font-bold">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
</div>
<div class="w-16 h-1 bg-green"></div>
<div class="w-8 h-8 bg-green rounded-full flex items-center justify-center text-sm font-bold">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
</div>
<div class="w-16 h-1 bg-green"></div>
<div class="w-8 h-8 bg-green rounded-full flex items-center justify-center text-sm font-bold">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
</div>
<div class="w-16 h-1 bg-green"></div>
<div class="w-8 h-8 bg-green rounded-full flex items-center justify-center text-sm font-bold">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
</div>
</div>