|
|
|
|
@@ -2,358 +2,385 @@
|
|
|
|
|
<%= @is_own_settings ? "My Settings" : "Settings | #{@user.username}" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
|
|
|
|
|
<% content_for :body_class, "settings-page" %>
|
|
|
|
|
|
|
|
|
|
<main class="container">
|
|
|
|
|
<header>
|
|
|
|
|
<h1><%= @is_own_settings ? "My Settings" : "Settings for #{@user.username}" %></h1>
|
|
|
|
|
<p>Change your settings for Hackatime and Sailors Log.</p>
|
|
|
|
|
<div class="max-w-6xl mx-auto p-6 space-y-6">
|
|
|
|
|
<header class="text-center mb-8">
|
|
|
|
|
<h1 class="text-4xl font-bold text-white mb-2">
|
|
|
|
|
<%= @is_own_settings ? "My Settings" : "Settings for #{@user.username}" %>
|
|
|
|
|
</h1>
|
|
|
|
|
<p class="text-muted text-lg">Change your Hackatime experience and preferences</p>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<div class="grid">
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
|
|
|
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
|
|
|
|
|
<div class="flex items-center gap-3 mb-4">
|
|
|
|
|
<div class="p-2 bg-red-600/10 rounded">
|
|
|
|
|
<span class="text-2xl">🚀</span>
|
|
|
|
|
</div>
|
|
|
|
|
<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,
|
|
|
|
|
class: "inline-flex items-center gap-2 px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2>🚀 Time tracking wizard</h2>
|
|
|
|
|
</header>
|
|
|
|
|
<p>Get started with tracking your coding time in just a few minutes.</p>
|
|
|
|
|
<%= link_to "Set up time tracking", my_wakatime_setup_path, role: "button" %>
|
|
|
|
|
</article>
|
|
|
|
|
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2 id="user_timezone">🌍 Timezone</h2>
|
|
|
|
|
</header>
|
|
|
|
|
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
|
|
|
|
|
<div class="flex items-center gap-3 mb-4">
|
|
|
|
|
<div class="p-2 bg-red-600/10 rounded">
|
|
|
|
|
<span class="text-2xl">🌍</span>
|
|
|
|
|
</div>
|
|
|
|
|
<h2 class="text-xl font-semibold text-white" id="user_timezone">Timezone</h2>
|
|
|
|
|
</div>
|
|
|
|
|
<%= form_with model: @user,
|
|
|
|
|
url: @is_own_settings ? my_settings_path : settings_user_path(@user),
|
|
|
|
|
method: :patch do |f| %>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<%= f.label :timezone, "Your timezone" %>
|
|
|
|
|
<%= f.select :timezone,
|
|
|
|
|
method: :patch, local: false,
|
|
|
|
|
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,
|
|
|
|
|
TZInfo::Timezone.all.map(&:identifier).sort,
|
|
|
|
|
include_blank: @user.timezone.blank?, class: "form-select" %>
|
|
|
|
|
{ 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" } %>
|
|
|
|
|
</div>
|
|
|
|
|
<small>This affects how your activity graph and other time-based features are displayed.</small>
|
|
|
|
|
<%= f.submit "Save Settings", role: "button" %>
|
|
|
|
|
<p class="text-xs text-gray-400">This affects how your activity graph and other time-based features are displayed.</p>
|
|
|
|
|
<%= f.submit "Save Settings", class: "w-full px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
</article>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2 id="user_slack_status">💬 Slack Integration</h2>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h3>Status Updates</h3>
|
|
|
|
|
<p>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 to give permission to update your status", slack_auth_path, role: "button", class: "secondary" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
<%= form_with model: @user,
|
|
|
|
|
url: @is_own_settings ? my_settings_path : settings_user_path(@user),
|
|
|
|
|
method: :patch do |f| %>
|
|
|
|
|
<fieldset>
|
|
|
|
|
<label>
|
|
|
|
|
<%= f.check_box :uses_slack_status, id: "user_uses_slack_status" %>
|
|
|
|
|
<%= f.label :uses_slack_status, "Update my Slack status with my current project" %>
|
|
|
|
|
</label>
|
|
|
|
|
</fieldset>
|
|
|
|
|
<%= f.submit "Save Settings", role: "button" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h3 id="user_slack_notifications">Channel Notifications</h3>
|
|
|
|
|
<% if @enabled_sailors_logs.any? %>
|
|
|
|
|
<p>You have notifications enabled for the following channels:</p>
|
|
|
|
|
<ul>
|
|
|
|
|
<% @enabled_sailors_logs.each do |sl| %>
|
|
|
|
|
<li>
|
|
|
|
|
<%= render "shared/slack_channel_mention", channel_id: sl.slack_channel_id %>
|
|
|
|
|
</li>
|
|
|
|
|
<% end %>
|
|
|
|
|
</ul>
|
|
|
|
|
<% else %>
|
|
|
|
|
<p>You have no notifications enabled.</p>
|
|
|
|
|
<% end %>
|
|
|
|
|
<p>
|
|
|
|
|
You can enable notifications for specific channels by running <code>/sailorslog on</code> in the Slack channel you want to enable notifications for.
|
|
|
|
|
</p>
|
|
|
|
|
</section>
|
|
|
|
|
</article>
|
|
|
|
|
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2 id="user_github_account">🔗 Connected Accounts</h2>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h3>GitHub Account</h3>
|
|
|
|
|
<p>This is used to show your active projects on the leaderboard & current hacking activity on the dashboard.</p>
|
|
|
|
|
<% if @user.github_uid.present? %>
|
|
|
|
|
<p>✅ Your GitHub account is linked: <%= link_to "@#{@user.github_username}", "https://github.com/#{@user.github_username}", target: "_blank" %></p>
|
|
|
|
|
<% if @user.github_access_token.present? %>
|
|
|
|
|
<%= link_to "Relink GitHub Account", github_auth_path, data: { turbo: "false" }, role: "button" %>
|
|
|
|
|
<%= link_to "Unlink GitHub Account", github_unlink_path,
|
|
|
|
|
data: {
|
|
|
|
|
turbo_method: :delete,
|
|
|
|
|
confirm: "Are you sure? This will remove access to your GitHub data."
|
|
|
|
|
},
|
|
|
|
|
role: "button",
|
|
|
|
|
class: "outline" %>
|
|
|
|
|
<% else %>
|
|
|
|
|
<p>⚠️ Your GitHub token has expired. Please relink your account.</p>
|
|
|
|
|
<%= link_to "Relink GitHub Account", github_auth_path, data: { turbo: "false" }, role: "button" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
<% else %>
|
|
|
|
|
<%= link_to "Link GitHub Account", github_auth_path, data: { turbo: "false" }, role: "button" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h3 id="user_email_addresses">Email Addresses</h3>
|
|
|
|
|
<p>These are the email addresses associated with your account.</p>
|
|
|
|
|
<% if @user.email_addresses.any? %>
|
|
|
|
|
<ul>
|
|
|
|
|
<% @user.email_addresses.each do |email_address| %>
|
|
|
|
|
<li>
|
|
|
|
|
<%= email_address.email %>
|
|
|
|
|
<% if email_address.source.present? %>
|
|
|
|
|
<span class="super">
|
|
|
|
|
(from <%= email_address.source.humanize %>)
|
|
|
|
|
</span>
|
|
|
|
|
<% end %>
|
|
|
|
|
</li>
|
|
|
|
|
<% end %>
|
|
|
|
|
</ul>
|
|
|
|
|
<% else %>
|
|
|
|
|
<p>No email addresses found.</p>
|
|
|
|
|
<% end %>
|
|
|
|
|
|
|
|
|
|
<div class="email-form">
|
|
|
|
|
<%= form_tag add_email_auth_path, data: { turbo: false } do %>
|
|
|
|
|
<div class="field">
|
|
|
|
|
<%= email_field_tag :email, nil, placeholder: "Add another email address", required: true %>
|
|
|
|
|
</div>
|
|
|
|
|
<%= submit_tag "Add Email", role: "button", class: "secondary" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
|
|
|
|
|
<div class="flex items-center gap-3 mb-4">
|
|
|
|
|
<div class="p-2 bg-red-600/10 rounded">
|
|
|
|
|
<span class="text-2xl">⚙️</span>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
</article>
|
|
|
|
|
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2 id="user_hackatime_extension">⚙️ Extension Settings</h2>
|
|
|
|
|
</header>
|
|
|
|
|
<h2 class="text-xl font-semibold text-white" id="user_hackatime_extension">Extension Settings</h2>
|
|
|
|
|
</div>
|
|
|
|
|
<%= form_with model: @user,
|
|
|
|
|
url: @is_own_settings ? my_settings_path : settings_user_path(@user),
|
|
|
|
|
method: :patch do |f| %>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<%= f.label "Simple text" %>
|
|
|
|
|
method: :patch, local: false,
|
|
|
|
|
class: "space-y-4" do |f| %>
|
|
|
|
|
<div>
|
|
|
|
|
<%= f.label :hackatime_extension_text_type, "Status bar text style", class: "block text-sm font-medium text-gray-200 mb-2" %>
|
|
|
|
|
<%= f.select :hackatime_extension_text_type,
|
|
|
|
|
User.hackatime_extension_text_types.keys.map { |type| [type.humanize, type] },
|
|
|
|
|
selected: @user.hackatime_extension_text_type, class: "form-select" %>
|
|
|
|
|
User.hackatime_extension_text_types.keys.map { |key| [key.humanize, key] },
|
|
|
|
|
{},
|
|
|
|
|
{ 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" } %>
|
|
|
|
|
</div>
|
|
|
|
|
<%= f.submit "Save Settings", role: "button" %>
|
|
|
|
|
<%= f.submit "Save Settings", class: "w-full px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
</article>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2 id="user_stats_badges">📊 Stats Badges</h2>
|
|
|
|
|
</header>
|
|
|
|
|
<section>
|
|
|
|
|
<p>Show your coding stats on your GitHub profile with beautiful badges.</p>
|
|
|
|
|
<h3>General Stats Badge</h3>
|
|
|
|
|
<p>This badge shows your overall coding statistics.</p>
|
|
|
|
|
<select name="theme" id="theme-select" onchange="updateBadgeTheme(this.value)" class="form-select">
|
|
|
|
|
<% GithubReadmeStats.themes.each do |theme| %>
|
|
|
|
|
<option value="<%= theme %>"><%= theme.humanize %></option>
|
|
|
|
|
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
|
|
|
|
|
<div class="flex items-center gap-3 mb-4">
|
|
|
|
|
<div class="p-2 bg-red-600/10 rounded">
|
|
|
|
|
<span class="text-2xl">💬</span>
|
|
|
|
|
</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,
|
|
|
|
|
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 %>
|
|
|
|
|
</select>
|
|
|
|
|
<% gh_badge = GithubReadmeStats.new(current_user.id, "darcula") %>
|
|
|
|
|
<img id="badge-preview" src="<%= gh_badge.generate_badge_url %>" data-url="<%= gh_badge.generate_badge_url %>">
|
|
|
|
|
<pre id="badge-url"><%= gh_badge.generate_badge_url %></pre>
|
|
|
|
|
</section>
|
|
|
|
|
<%= 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,
|
|
|
|
|
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",
|
|
|
|
|
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" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<% if @projects.any? && @user.slack_uid.present? %>
|
|
|
|
|
<section>
|
|
|
|
|
<h3>Project Stats Badge</h3>
|
|
|
|
|
<p>This badge shows individual project statistics.</p>
|
|
|
|
|
<p><small>See <a href="https://github.com/pbhak/hackatime-badge">the documentation</a> for more customization options!</small></p>
|
|
|
|
|
<select name="project-id" id="project-select" onchange="updateBadgeProject(this.value)" class="form-select">
|
|
|
|
|
<% @projects.each do |project_name| %>
|
|
|
|
|
<option value="<%= project_name %>"><%= project_name %></option>
|
|
|
|
|
<% end %>
|
|
|
|
|
</select>
|
|
|
|
|
<img id="work-time-badge-preview" src="<%= @work_time_stats_url %>" data-url="<%= @work_time_stats_url %>">
|
|
|
|
|
<pre id="work-time-badge-url"><%= @work_time_stats_url %></pre>
|
|
|
|
|
</section>
|
|
|
|
|
<div class="border-t border-gray-700 pt-4">
|
|
|
|
|
<h3 class="text-lg font-medium text-white mb-2" id="user_slack_notifications">Channel Notifications</h3>
|
|
|
|
|
<% if @enabled_sailors_logs.any? %>
|
|
|
|
|
<p class="text-gray-300 text-sm mb-2">You have notifications enabled for the following channels:</p>
|
|
|
|
|
<ul class="space-y-1 mb-3">
|
|
|
|
|
<% @enabled_sailors_logs.each do |sl| %>
|
|
|
|
|
<li class="text-xs text-gray-300 px-2 py-1 bg-gray-800 rounded">
|
|
|
|
|
<%= render "shared/slack_channel_mention", channel_id: sl.slack_channel_id %>
|
|
|
|
|
</li>
|
|
|
|
|
<% end %>
|
|
|
|
|
</ul>
|
|
|
|
|
<% else %>
|
|
|
|
|
<p class="text-gray-300 text-sm mb-3">You have no notifications enabled.</p>
|
|
|
|
|
<% end %>
|
|
|
|
|
<p class="text-xs text-gray-400">
|
|
|
|
|
You can enable notifications for specific channels by running <code class="px-1 py-0.5 bg-gray-800 rounded text-gray-200">/sailorslog on</code> in the Slack channel.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
|
|
|
|
|
<div class="flex items-center gap-3 mb-4">
|
|
|
|
|
<div class="p-2 bg-red-600/10 rounded">
|
|
|
|
|
<span class="text-2xl">🔒</span>
|
|
|
|
|
</div>
|
|
|
|
|
<h2 class="text-xl font-semibold text-white" id="user_privacy">Privacy Settings</h2>
|
|
|
|
|
</div>
|
|
|
|
|
<%= 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 :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",
|
|
|
|
|
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>
|
|
|
|
|
<%= f.submit "Save Settings", class: "w-full px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
|
|
|
|
|
<div class="flex items-center gap-3 mb-4">
|
|
|
|
|
<div class="p-2 bg-red-600/10 rounded">
|
|
|
|
|
<span class="text-2xl">🏆</span>
|
|
|
|
|
</div>
|
|
|
|
|
<h2 class="text-xl font-semibold text-white" id="user_beta_features">Leaderboard Settings</h2>
|
|
|
|
|
</div>
|
|
|
|
|
<p class="text-gray-300 text-sm mb-4">Customize how you see the leaderboard</p>
|
|
|
|
|
<%= render "timezone_leaderboard_toggle", user: @user %>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200 md:col-span-2">
|
|
|
|
|
<div class="flex items-center gap-3 mb-4">
|
|
|
|
|
<div class="p-2 bg-red-600/10 rounded">
|
|
|
|
|
<span class="text-2xl">🔗</span>
|
|
|
|
|
</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>
|
|
|
|
|
<p class="text-gray-300 text-sm">This is used to show your active projects on the leaderboard & current hacking activity on the dashboard.</p>
|
|
|
|
|
<% if @user.github_uid.present? %>
|
|
|
|
|
<div class="flex items-center gap-2 p-3 bg-gray-800 border border-gray-600 rounded">
|
|
|
|
|
<span class="text-green-400">✅</span>
|
|
|
|
|
<span class="text-gray-200 text-sm">Connected: <%= link_to "@#{@user.github_username}", "https://github.com/#{@user.github_username}", target: "_blank", class: "text-primary hover:text-primary/80 underline" %></span>
|
|
|
|
|
</div>
|
|
|
|
|
<% unless @user.github_access_token.present? %>
|
|
|
|
|
<%= 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" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
<% else %>
|
|
|
|
|
<%= 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>
|
|
|
|
|
|
|
|
|
|
<div class="space-y-3" id="user_email_addresses">
|
|
|
|
|
<h3 class="text-lg font-medium text-white">Email Addresses</h3>
|
|
|
|
|
<p class="text-gray-300 text-sm">These are the email addresses associated with your account.</p>
|
|
|
|
|
<% if @user.email_addresses.any? %>
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
<% @user.email_addresses.each do |email| %>
|
|
|
|
|
<div class="flex items-center gap-2 p-2 bg-gray-800 border border-gray-600 rounded">
|
|
|
|
|
<span class="text-gray-300 text-sm"><%= email.email %></span>
|
|
|
|
|
<span class="text-xs px-2 py-1 bg-gray-700 text-gray-200 rounded">
|
|
|
|
|
<%= email.source&.humanize || "Unknown" %>
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<% end %>
|
|
|
|
|
</div>
|
|
|
|
|
<% else %>
|
|
|
|
|
<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",
|
|
|
|
|
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" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
|
|
|
|
|
<div class="flex items-center gap-3 mb-4">
|
|
|
|
|
<div class="p-2 bg-red-600/10 rounded">
|
|
|
|
|
<span class="text-2xl">📊</span>
|
|
|
|
|
</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)"
|
|
|
|
|
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">
|
|
|
|
|
<pre id="badge-url" class="text-xs text-gray-300 bg-gray-900 p-2 rounded overflow-x-auto"><%= gh_badge.generate_badge_url %></pre>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<% if @projects.any? && @user.slack_uid.present? %>
|
|
|
|
|
<div class="border-t border-gray-700 pt-4">
|
|
|
|
|
<h3 class="text-lg font-medium text-white mb-2">Project Stats Badge</h3>
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
<label class="block text-sm font-medium text-gray-200">Project</label>
|
|
|
|
|
<select name="project" id="project-select" onchange="up2(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">
|
|
|
|
|
<% @projects.each do |project| %>
|
|
|
|
|
<option value="<%= project %>"><%= project %></option>
|
|
|
|
|
<% end %>
|
|
|
|
|
</select>
|
|
|
|
|
<div class="mt-3 p-4 bg-gray-800 border border-gray-600 rounded">
|
|
|
|
|
<img id="project-badge-preview" src="<%= @work_time_stats_url %>" class="mb-3 rounded">
|
|
|
|
|
<pre id="project-badge-url" class="text-xs text-gray-300 bg-gray-900 p-2 rounded overflow-x-auto"><%= @work_time_stats_url %></pre>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<% end %>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
function updateBadgeTheme(theme) {
|
|
|
|
|
const originalUrl = document.getElementById('badge-preview').dataset.url;
|
|
|
|
|
const [baseUrl, queryString] = originalUrl.split('?');
|
|
|
|
|
const params = queryString.split('&').map(param => {
|
|
|
|
|
const [key, value] = param.split('=');
|
|
|
|
|
return key === 'theme' ? `theme=${theme}` : param;
|
|
|
|
|
});
|
|
|
|
|
const newUrl = `${baseUrl}?${params.join('&')}`;
|
|
|
|
|
document.getElementById('badge-preview').src = newUrl;
|
|
|
|
|
document.getElementById('badge-url').textContent = newUrl;
|
|
|
|
|
function up1(theme) {
|
|
|
|
|
const preview = document.getElementById('badge-preview');
|
|
|
|
|
const url = document.getElementById('badge-url');
|
|
|
|
|
const baseUrl = preview.dataset.url.replace(/theme=[^&]*/, '');
|
|
|
|
|
const newUrl = baseUrl + (baseUrl.includes('?') ? '&' : '?') + 'theme=' + theme;
|
|
|
|
|
preview.src = newUrl;
|
|
|
|
|
url.textContent = newUrl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateBadgeProject(project) {
|
|
|
|
|
const originalUrl = document.getElementById('work-time-badge-preview').dataset.url;
|
|
|
|
|
let splitUrl = originalUrl.split('/');
|
|
|
|
|
splitUrl[splitUrl.length - 1] = project;
|
|
|
|
|
const newUrl = splitUrl.join('/');
|
|
|
|
|
document.getElementById('work-time-badge-preview').src = newUrl;
|
|
|
|
|
document.getElementById('work-time-badge-url').textContent = newUrl;
|
|
|
|
|
function up2(project) {
|
|
|
|
|
const preview = document.getElementById('project-badge-preview');
|
|
|
|
|
const url = document.getElementById('project-badge-url');
|
|
|
|
|
const baseUrl = '<%= @work_time_stats_url.gsub(@projects.first || 'example', '') %>';
|
|
|
|
|
const newUrl = baseUrl + project;
|
|
|
|
|
preview.src = newUrl;
|
|
|
|
|
url.textContent = newUrl;
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
</article>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2 id="user_markscribe">📝 Markscribe Templates</h2>
|
|
|
|
|
<p>Use markscribe to create beautiful GitHub profile READMEs with your coding stats.</p>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<div class="code-example">
|
|
|
|
|
<pre><code>{{ wakatimeDoubleCategoryBar "💾 Languages:" wakatimeData.Languages "💼 Projects:" wakatimeData.Projects 5 }}</code></pre>
|
|
|
|
|
</div>
|
|
|
|
|
<p>Add this to your GitHub profile README template to display your top languages and projects.</p>
|
|
|
|
|
<p><small>See the <a href="https://github.com/taciturnaxolotl/markscribe#your-wakatime-languages-formated-as-a-bar" target="_blank">markscribe documentation</a> for more template options.</small></p>
|
|
|
|
|
<img src="https://cdn.fluff.pw/slackcdn/524e293aa09bc5f9115c0c29c18fb4bc.png" alt="Example of markscribe output showing coding language and project statistics" width="100%"/>
|
|
|
|
|
</article>
|
|
|
|
|
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2 id="user_config_file">📄 Config File</h2>
|
|
|
|
|
<p>
|
|
|
|
|
<% if current_user.most_recent_direct_entry_heartbeat %>
|
|
|
|
|
Your last heartbeat was <%= time_ago_in_words current_user.most_recent_direct_entry_heartbeat.created_at %> ago.
|
|
|
|
|
<% else %>
|
|
|
|
|
You haven't sent any heartbeats yet directly to this platform.
|
|
|
|
|
<% end %>
|
|
|
|
|
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200 space-y-6">
|
|
|
|
|
<div>
|
|
|
|
|
<div class="flex items-center gap-3 mb-4">
|
|
|
|
|
<div class="p-2 bg-red-600/10 rounded">
|
|
|
|
|
<span class="text-2xl">📄</span>
|
|
|
|
|
</div>
|
|
|
|
|
<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>
|
|
|
|
|
<p class="text-xs text-gray-400 mt-2">
|
|
|
|
|
This configuration file is automatically generated and updated when you make changes to your settings.
|
|
|
|
|
</p>
|
|
|
|
|
</header>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="border-t border-gray-700 pt-6">
|
|
|
|
|
<div class="flex items-center gap-3 mb-4">
|
|
|
|
|
<div class="p-2 bg-red-600/10 rounded">
|
|
|
|
|
<span class="text-2xl">🚚</span>
|
|
|
|
|
</div>
|
|
|
|
|
<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,
|
|
|
|
|
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>
|
|
|
|
|
<% @heartbeats_migration_jobs.each do |job| %>
|
|
|
|
|
<div class="p-2 bg-gray-800 border border-gray-600 rounded text-xs text-gray-300">
|
|
|
|
|
Job ID: <%= job.id %> - Status: <%= job.status %>
|
|
|
|
|
</div>
|
|
|
|
|
<% end %>
|
|
|
|
|
</div>
|
|
|
|
|
<% end %>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200 md:col-span-2">
|
|
|
|
|
<div class="flex items-center gap-3 mb-4">
|
|
|
|
|
<div class="p-2 bg-red-600/10 rounded">
|
|
|
|
|
<span class="text-2xl">📝</span>
|
|
|
|
|
</div>
|
|
|
|
|
<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>
|
|
|
|
|
|
|
|
|
|
<%= render "wakatime_config_display" %>
|
|
|
|
|
<p>
|
|
|
|
|
<small>
|
|
|
|
|
This file is located in <code>~/.wakatime.cfg</code> on your computer.
|
|
|
|
|
You can configure it with <a href="https://github.com/wakatime/wakatime-cli/blob/develop/USAGE.md#ini-config-file">other settings</a> as well.
|
|
|
|
|
</small>
|
|
|
|
|
</p>
|
|
|
|
|
</article>
|
|
|
|
|
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2 id="user_privacy">🔒 Privacy Settings</h2>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<%= form_with model: @user,
|
|
|
|
|
url: @is_own_settings ? my_settings_path : settings_user_path(@user),
|
|
|
|
|
method: :patch do |f| %>
|
|
|
|
|
<fieldset>
|
|
|
|
|
<label for="user_allow_public_stats_lookup">
|
|
|
|
|
<%= f.check_box :allow_public_stats_lookup, id: "user_allow_public_stats_lookup" %>
|
|
|
|
|
<%= f.label :allow_public_stats_lookup, "Allow others to look up my public coding stats via the API" %>
|
|
|
|
|
</label>
|
|
|
|
|
</fieldset>
|
|
|
|
|
<%= f.submit "Save Settings", role: "button" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
</article>
|
|
|
|
|
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2 id="user_beta_features">🏆 Leaderboard settings</h2>
|
|
|
|
|
<p>Customize how you see the leaderboard</p>
|
|
|
|
|
</header>
|
|
|
|
|
<%= render "timezone_leaderboard_toggle", user: @user %>
|
|
|
|
|
</article>
|
|
|
|
|
|
|
|
|
|
<%#
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2 id="user_beta_features">🧪 Beta Features</h2>
|
|
|
|
|
<p>Enable experimental features and help us test new functionality.</p>
|
|
|
|
|
</header>
|
|
|
|
|
</article>
|
|
|
|
|
%>
|
|
|
|
|
<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">
|
|
|
|
|
<pre class="text-sm text-gray-200 whitespace-pre-wrap break-all"><code>{{ wakatimeDoubleCategoryBar "💾 Languages:" wakatimeData.Languages "💼 Projects:" wakatimeData.Projects 5 }}</code></pre>
|
|
|
|
|
</div>
|
|
|
|
|
<p class="text-gray-300 text-sm mb-2">Add this to your GitHub profile README template to display your top languages and projects.</p>
|
|
|
|
|
<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"/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<% admin_tool do %>
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2 id="wakatime_mirror">🔄 WakaTime Mirror</h2>
|
|
|
|
|
<p>Mirror your coding activity to WakaTime.</p>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<div class="p-6 md:col-span-2">
|
|
|
|
|
<div class="flex items-center gap-3 mb-4">
|
|
|
|
|
<div class="p-2 bg-red-600/10 rounded">
|
|
|
|
|
<span class="text-2xl">🔧</span>
|
|
|
|
|
</div>
|
|
|
|
|
<h2 class="text-xl font-semibold text-white">WakaTime Mirrors</h2>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<% if current_user.wakatime_mirrors.any? %>
|
|
|
|
|
<div class="mirrors-list">
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
|
|
|
|
<% current_user.wakatime_mirrors.each do |mirror| %>
|
|
|
|
|
<div class="mirror">
|
|
|
|
|
<p>
|
|
|
|
|
<strong>Endpoint:</strong> <%= mirror.endpoint_url %><br>
|
|
|
|
|
<strong>Last synced:</strong> <%= mirror.last_synced_at ? time_ago_in_words(mirror.last_synced_at) + " ago" : "Never" %>
|
|
|
|
|
</p>
|
|
|
|
|
<%= button_to "Delete", user_wakatime_mirror_path(current_user, mirror), method: :delete, role: "button", class: "secondary", data: { confirm: "Are you sure?" } %>
|
|
|
|
|
<div class="p-4 bg-gray-800 border border-gray-600 rounded">
|
|
|
|
|
<h3 class="text-white font-medium"><%= mirror.name %></h3>
|
|
|
|
|
<p class="text-gray-400 text-sm"><%= mirror.endpoint_url %></p>
|
|
|
|
|
</div>
|
|
|
|
|
<% end %>
|
|
|
|
|
</div>
|
|
|
|
|
<% end %>
|
|
|
|
|
|
|
|
|
|
<%= form_with(model: [current_user, WakatimeMirror.new], local: true) do |f| %>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<%= f.label :endpoint_url, "WakaTime API Endpoint" %>
|
|
|
|
|
<%= f.text_field :endpoint_url, value: "https://wakatime.com/api/v1", placeholder: "https://wakatime.com/api/v1", class: "form-control" %>
|
|
|
|
|
<%= form_with(model: [current_user, WakatimeMirror.new], local: true, class: "space-y-4") do |f| %>
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
|
|
<div>
|
|
|
|
|
<%= f.label :name, class: "block text-sm font-medium text-gray-200 mb-2" %>
|
|
|
|
|
<%= f.text_field :name, 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" %>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<%= f.label :endpoint_url, class: "block text-sm font-medium text-gray-200 mb-2" %>
|
|
|
|
|
<%= f.url_field :endpoint_url, 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" %>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<%= f.label :encrypted_api_key, "WakaTime API Key" %>
|
|
|
|
|
<%= f.text_field :encrypted_api_key, placeholder: "Enter your WakaTime API key", class: "form-control" %>
|
|
|
|
|
</div>
|
|
|
|
|
<%= f.submit "Add Mirror", role: "button" %>
|
|
|
|
|
<%= f.submit "Add Mirror", class: "px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
|
|
|
|
|
<% end %>
|
|
|
|
|
</article>
|
|
|
|
|
</div>
|
|
|
|
|
<% end %>
|
|
|
|
|
|
|
|
|
|
<article>
|
|
|
|
|
<header>
|
|
|
|
|
<h2 id="user_migration_assistant">🚚 Migration Assistant</h2>
|
|
|
|
|
<p>This will migrate your heartbeats from waka.hackclub.com to this platform.</p>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<%= button_to "Migrate heartbeats", my_settings_migrate_heartbeats_path, method: :post, role: "button" %>
|
|
|
|
|
|
|
|
|
|
<% if @heartbeats_migration_jobs.any? %>
|
|
|
|
|
<section>
|
|
|
|
|
<h3>Migration Jobs</h3>
|
|
|
|
|
<ul>
|
|
|
|
|
<% @heartbeats_migration_jobs.each do |job| %>
|
|
|
|
|
<li>
|
|
|
|
|
<% if job.finished_at && !job.error %>
|
|
|
|
|
✅
|
|
|
|
|
<% elsif job.finished_at && job.error %>
|
|
|
|
|
❌
|
|
|
|
|
<% else %>
|
|
|
|
|
⏳
|
|
|
|
|
<% end %>
|
|
|
|
|
Job started at <%= job.created_at.strftime("%Y-%m-%d %H:%M:%S") %>
|
|
|
|
|
<% if job.finished_at %>
|
|
|
|
|
(and finished after <%= distance_of_time_in_words(job.finished_at - job.created_at) %>)
|
|
|
|
|
<% end %>
|
|
|
|
|
<% admin_tool('', 'span') do %>
|
|
|
|
|
<%= link_to "View job", GoodJob::Engine.routes.url_helpers.job_path(job.id) %>
|
|
|
|
|
<% end %>
|
|
|
|
|
</li>
|
|
|
|
|
<% end %>
|
|
|
|
|
</ul>
|
|
|
|
|
</section>
|
|
|
|
|
<% end %>
|
|
|
|
|
</article>
|
|
|
|
|
</div>
|
|
|
|
|
</main>
|
|
|
|
|
</div>
|
|
|
|
|
|