mirror of
https://github.com/System-End/hackatime.git
synced 2026-04-19 16:38:23 +00:00
377 lines
19 KiB
Text
377 lines
19 KiB
Text
<div class="min-h-screen text-white">
|
|
<div class="max-w-6xl mx-auto p-4">
|
|
<div class="text-center mb-4">
|
|
<h1 class="text-4xl font-bold text-primary mb-2">Hackatime Setup</h1>
|
|
<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" />
|
|
</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" />
|
|
</svg>
|
|
</div>
|
|
<div class="w-16 h-1 bg-green"></div>
|
|
<div class="w-8 h-8 bg-primary rounded-full flex items-center justify-center text-sm font-bold">3</div>
|
|
<div class="w-16 h-1 bg-darkless"></div>
|
|
<div class="w-8 h-8 bg-darkless rounded-full flex items-center justify-center text-sm">4</div>
|
|
</div>
|
|
</div>
|
|
|
|
<% if params[:editor] == "vscode" %>
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
<div class="lg:col-span-2">
|
|
<section class="bg-dark rounded-lg p-6">
|
|
<h3 class="text-2xl font-bold text-blue mb-4">💻 Install the VS Code Extension</h3>
|
|
<div class="space-y-4">
|
|
<p class="text-lg">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 font-semibold">WakaTime extension from the marketplace</a>.</p>
|
|
|
|
<h4 class="font-bold mb-2">Step-by-step:</h4>
|
|
<ol class="list-decimal list-inside space-y-1">
|
|
<li>Open VS Code</li>
|
|
<li>Click the Extensions icon (squares) on the left sidebar</li>
|
|
<li>Search for "WakaTime"</li>
|
|
<li>Click <strong>Install</strong> on the WakaTime extension</li>
|
|
<li>Restart VS Code if prompted</li>
|
|
<li>Code for a few minutes to start tracking your time to make sure it's working</li>
|
|
</ol>
|
|
|
|
<details class="group">
|
|
<summary class="cursor-pointer text-secondary hover:text-white flex items-center gap-2">
|
|
<svg class="w-4 h-4 transition-transform group-open:rotate-90" 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" />
|
|
</svg>
|
|
How do I know it's working?
|
|
</summary>
|
|
<div class="mt-3 pl-6">
|
|
<p class="text-md mb-3">You'll see a clock icon in your status bar:</p>
|
|
<img src="https://hc-cdn.hel1.your-objectstorage.com/s/v3/95d2513ce4b0c1c147827d17ecb4c24540cd73cc_p.png" alt="WakaTime status bar in VS Code" class="max-w-full h-auto rounded-lg border border-darkless">
|
|
</div>
|
|
</details>
|
|
<details class="group">
|
|
<summary class="cursor-pointer text-secondary hover:text-white flex items-center gap-2">
|
|
<svg class="w-4 h-4 transition-transform group-open:rotate-90" 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" />
|
|
</svg>
|
|
Why is the extension called WakaTime?
|
|
</summary>
|
|
<div class="mt-3 pl-6">
|
|
<p class="text-md mb-3">WakaTime is a popular time tracking service for developers. Hackatime is compatible with WakaTime’s API, so you can install WakaTime plugins or extensions in your editor or IDE and configure them to send their data to Hackatime instead of the WakaTime service.</p>
|
|
</div>
|
|
</details>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div class="lg:col-span-1">
|
|
<div class="lg:sticky lg:top-4">
|
|
<section id="status-panel" class="bg-dark rounded-lg p-6 border-2 border-darkless">
|
|
<div id="waiting-state">
|
|
<div class="text-center mb-4">
|
|
<div class="w-16 h-16 mx-auto mb-3 rounded-full bg-blue/20 flex items-center justify-center">
|
|
<svg class="w-8 h-8 text-blue animate-pulse" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
|
</svg>
|
|
</div>
|
|
<h4 class="text-xl font-bold text-white mb-2">Waiting for you to code...</h4>
|
|
<p class="text-secondary text-sm" id="status-message">Once you've installed the extension, open a file and start typing!</p>
|
|
</div>
|
|
|
|
<div class="bg-darkless rounded-lg p-3">
|
|
<div class="flex items-center justify-center gap-2 text-secondary">
|
|
<div class="spin"></div>
|
|
<span class="text-sm" id="poll-status">Checking for heartbeats...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="success-state" class="hidden">
|
|
<div class="text-center mb-4">
|
|
<div class="w-16 h-16 mx-auto mb-3 rounded-full bg-green/20 flex items-center justify-center">
|
|
<svg class="w-8 h-8 text-green" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
|
</svg>
|
|
</div>
|
|
<h4 class="text-xl font-bold text-green mb-2">Heartbeat detected <span id="heartbeat-time-ago"></span>!</h4>
|
|
<p class="text-secondary text-sm" id="success-message">Hackatime is tracking your coding. Nice work!</p>
|
|
<p id="editor-mismatch-message" class="hidden text-cyan text-sm mt-2"></p>
|
|
</div>
|
|
|
|
<%= link_to my_wakatime_setup_step_4_path, class: "block w-full bg-primary hover:bg-red text-white text-center px-6 py-3 rounded-lg font-semibold transition-colors" do %>
|
|
Continue →
|
|
<% end %>
|
|
</div>
|
|
</section>
|
|
|
|
<p class="text-center text-secondary text-xs mt-3">Already set up? <a href="<%= my_wakatime_setup_step_4_path %>" class="text-cyan hover:underline">Skip to finish</a></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% elsif params[:editor] == "vim" %>
|
|
<section id="vim" class="bg-dark rounded-lg p-6 mb-6">
|
|
<h3 class="text-2xl font-bold text-green mb-4">📟 Vim</h3>
|
|
<div class="space-y-6">
|
|
<p class="text-lg">Install the WakaTime plugin using your preferred plugin manager:</p>
|
|
|
|
<div class="space-y-4">
|
|
<div class="bg-green/10 border border-green/30 rounded-lg p-4">
|
|
<h4 class="font-bold mb-2">Using vim-plug:</h4>
|
|
<pre class="bg-darkless rounded p-3 text-cyan text-sm overflow-x-auto"><code>Plug 'wakatime/vim-wakatime'</code></pre>
|
|
<p class="text-sm mt-2">Then run <code class="bg-darkless px-1 rounded text-cyan">:PlugInstall</code></p>
|
|
</div>
|
|
|
|
<div class="bg-green/10 border border-green/30 rounded-lg p-4">
|
|
<h4 class="font-bold mb-2">Using Vundle:</h4>
|
|
<pre class="bg-darkless rounded p-3 text-cyan text-sm overflow-x-auto"><code>Plugin 'wakatime/vim-wakatime'</code></pre>
|
|
<p class="text-sm mt-2">Then run <code class="bg-darkless px-1 rounded text-cyan">:PluginInstall</code></p>
|
|
</div>
|
|
|
|
<div class="bg-green/10 border border-green/30 rounded-lg p-4">
|
|
<h4 class="font-bold mb-2">Manual installation:</h4>
|
|
<pre class="bg-darkless rounded p-3 text-cyan text-sm overflow-x-auto"><code>cd ~/.vim/bundle
|
|
git clone https://github.com/wakatime/vim-wakatime.git</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="flex gap-4 flex-wrap justify-center">
|
|
<%= link_to my_wakatime_setup_step_4_path, class: "bg-primary hover:bg-red text-white px-6 py-3 rounded-lg font-semibold transition-colors" do %>
|
|
Next Step
|
|
<% end %>
|
|
</div>
|
|
<% elsif params[:editor] == "neovim" %>
|
|
<section id="neovim" class="bg-dark rounded-lg p-6 mb-6">
|
|
<h3 class="text-2xl font-bold text-green mb-4">📟 Neovim</h3>
|
|
<div class="space-y-6">
|
|
<p class="text-lg">Install the WakaTime plugin using your preferred plugin manager:</p>
|
|
|
|
<div class="space-y-4">
|
|
<div class="bg-green/10 border border-green/30 rounded-lg p-4">
|
|
<h4 class="font-bold mb-2">Using lazy.nvim:</h4>
|
|
<pre class="bg-darkless rounded p-3 text-cyan text-sm overflow-x-auto"><code>{ "wakatime/vim-wakatime", lazy = false }</code></pre>
|
|
</div>
|
|
|
|
<div class="bg-green/10 border border-green/30 rounded-lg p-4">
|
|
<h4 class="font-bold mb-2">Using packer.nvim:</h4>
|
|
<pre class="bg-darkless rounded p-3 text-cyan text-sm overflow-x-auto"><code>use 'wakatime/vim-wakatime'</code></pre>
|
|
</div>
|
|
|
|
<div class="bg-green/10 border border-green/30 rounded-lg p-4">
|
|
<h4 class="font-bold mb-2">Using vim-plug:</h4>
|
|
<pre class="bg-darkless rounded p-3 text-cyan text-sm overflow-x-auto"><code>Plug 'wakatime/vim-wakatime'</code></pre>
|
|
<p class="text-sm mt-2">Then run <code class="bg-darkless px-1 rounded text-cyan">:PlugInstall</code></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="flex gap-4 flex-wrap justify-center">
|
|
<%= link_to my_wakatime_setup_step_4_path, class: "bg-primary hover:bg-red text-white px-6 py-3 rounded-lg font-semibold transition-colors" do %>
|
|
Next Step
|
|
<% end %>
|
|
</div>
|
|
<% elsif params[:editor] == "emacs" %>
|
|
<section id="emacs" class="bg-dark rounded-lg p-6 mb-6">
|
|
<h3 class="text-2xl font-bold text-purple mb-4">🔮 Emacs</h3>
|
|
<div class="space-y-6">
|
|
<p class="text-lg">Install the WakaTime package using your preferred method:</p>
|
|
|
|
<div class="space-y-4">
|
|
<div class="bg-purple/10 border border-purple/30 rounded-lg p-4">
|
|
<h4 class="font-bold mb-2">Using MELPA:</h4>
|
|
<pre class="bg-darkless rounded p-3 text-cyan text-sm overflow-x-auto"><code>M-x package-install RET wakatime-mode RET</code></pre>
|
|
<p class="text-sm mt-2">Then add to your config: <code class="bg-darkless px-1 rounded text-cyan">(global-wakatime-mode)</code></p>
|
|
</div>
|
|
|
|
<div class="bg-purple/10 border border-purple/30 rounded-lg p-4">
|
|
<h4 class="font-bold mb-2">Using use-package:</h4>
|
|
<pre class="bg-darkless rounded p-3 text-cyan text-sm overflow-x-auto"><code>(use-package wakatime-mode
|
|
:ensure t
|
|
:config
|
|
(global-wakatime-mode))</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="flex gap-4 flex-wrap justify-center">
|
|
<%= link_to my_wakatime_setup_step_4_path, class: "bg-primary hover:bg-red text-white px-6 py-3 rounded-lg font-semibold transition-colors" do %>
|
|
Next Step
|
|
<% end %>
|
|
</div>
|
|
<% elsif params[:editor] == "godot" %>
|
|
<section id="godot" class="bg-dark rounded-lg p-6 mb-6">
|
|
<h3 class="text-2xl font-bold text-cyan mb-4">🎮 Godot</h3>
|
|
<div class="space-y-6">
|
|
<p class="text-lg">Follow our comprehensive <a href="/docs/editors/godot" class="text-cyan hover:text-blue underline">Godot & Hackatime Setup guide</a> with video tutorial!</p>
|
|
|
|
<div class="bg-cyan/10 border border-cyan/30 rounded-lg p-4">
|
|
<h4 class="font-bold mb-2">Quick steps:</h4>
|
|
<ol class="list-decimal list-inside space-y-1 text-sm">
|
|
<li>Open your Godot project</li>
|
|
<li>Go to the <strong>AssetLib</strong> tab</li>
|
|
<li>Search for <strong>"Godot Super Wakatime"</strong></li>
|
|
<li>Click <strong>Download</strong> and <strong>Install</strong></li>
|
|
<li>Enable in <strong>Project → Project Settings → Plugins</strong></li>
|
|
</ol>
|
|
<p class="text-sm mt-3 text-cyan">📺 <a href="https://www.youtube.com/watch?v=a938RgsBzNg&t=29s" target="_blank" class="underline">Watch the workshop recording</a> for a complete walkthrough!</p>
|
|
</div>
|
|
|
|
<div class="bg-yellow/10 border border-yellow/30 rounded-lg p-4">
|
|
<p class="text-yellow text-sm"><strong>Note:</strong> You need to install the plugin for each Godot project separately (it's a Godot limitation).</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="flex gap-4 flex-wrap justify-center">
|
|
<%= link_to my_wakatime_setup_step_4_path, class: "bg-primary hover:bg-red text-white px-6 py-3 rounded-lg font-semibold transition-colors" do %>
|
|
Next Step
|
|
<% end %>
|
|
</div>
|
|
<% else %>
|
|
<section class="bg-dark rounded-lg p-6 mb-6">
|
|
<h3 class="text-2xl font-bold text-orange mb-4">🔧 Setup your Editor</h3>
|
|
<div class="bg-orange/10 border border-orange/30 rounded-lg p-4 mb-4">
|
|
<p class="mb-4"><strong>Hackatime works with any editor that supports WakaTime!</strong> This includes PyCharm, IntelliJ, Sublime Text, Atom, Neovim, Unity, Godot, and <a href="https://hackatime.hackclub.com/docs#supported-editors" class="text-cyan hover:text-blue underline">77+ more editors</a>.</p>
|
|
</div>
|
|
|
|
<div class="space-y-4">
|
|
<div>
|
|
<h4 class="font-bold mb-2 text-lg">Popular Editors:</h4>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
<a href="/docs/editors/pycharm" class="flex items-center gap-3 bg-darkless rounded-lg p-3 hover:bg-primary/75 transition-colors">
|
|
<img src="/images/editor-icons/pycharm-128.png" alt="PyCharm" class="w-8 h-8">
|
|
<span>PyCharm</span>
|
|
</a>
|
|
<a href="/docs/editors/sublime-text" class="flex items-center gap-3 bg-darkless rounded-lg p-3 hover:bg-primary/75 transition-colors">
|
|
<img src="/images/editor-icons/sublime-text-128.png" alt="Sublime Text" class="w-8 h-8">
|
|
<span>Sublime Text</span>
|
|
</a>
|
|
<a href="/docs/editors/unity" class="flex items-center gap-3 bg-darkless rounded-lg p-3 hover:bg-primary/75 transition-colors">
|
|
<img src="/images/editor-icons/unity-128.png" alt="Unity" class="w-8 h-8">
|
|
<span>Unity</span>
|
|
</a>
|
|
<a href="/docs/editors/neovim" class="flex items-center gap-3 bg-darkless rounded-lg p-3 hover:bg-primary/75 transition-colors">
|
|
<img src="/images/editor-icons/neovim-128.png" alt="Neovim" class="w-8 h-8">
|
|
<span>Neovim</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-yellow/10 border border-yellow/30 rounded-lg p-4">
|
|
<p class="text-yellow font-bold mb-2">⚠️ Important:</p>
|
|
<p>When setting up WakaTime plugins, <strong>skip any steps that ask you to update ~/.wakatime.cfg</strong> or change the api_url. The setup script from Step 1 already configured this correctly!</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="flex gap-4 flex-wrap justify-center">
|
|
<%= link_to my_wakatime_setup_step_4_path, class: "bg-primary hover:bg-red text-white px-6 py-3 rounded-lg font-semibold transition-colors" do %>
|
|
Next Step
|
|
<% end %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
|
|
<% if params[:editor] == "vscode" %>
|
|
<script>
|
|
document.addEventListener("turbo:load", function () {
|
|
const waitingState = document.getElementById("waiting-state");
|
|
const successState = document.getElementById("success-state");
|
|
const statusMessage = document.getElementById("status-message");
|
|
const pollStatus = document.getElementById("poll-status");
|
|
const statusPanel = document.getElementById("status-panel");
|
|
|
|
let checkCount = 0;
|
|
const maxChecks = 120; // 10m (5s)
|
|
|
|
const msg = ["Open any code file and start typing!", "Try editing some code in VS Code...", "Type a few characters in your editor!", "We're watching for your first keystroke...", "Make any edit in VS Code to continue!"];
|
|
|
|
function showSuccess(timeAgo, detectedEditor) {
|
|
waitingState.classList.add("hidden");
|
|
successState.classList.remove("hidden");
|
|
statusPanel.classList.remove("border-darkless");
|
|
statusPanel.classList.add("border-green");
|
|
document.getElementById("heartbeat-time-ago").textContent = timeAgo;
|
|
|
|
if (detectedEditor && detectedEditor.toLowerCase() !== "vscode" && detectedEditor.toLowerCase() !== "vs code") {
|
|
const mismatchMessage = document.getElementById("editor-mismatch-message");
|
|
mismatchMessage.textContent = `We detected a heartbeat from ${detectedEditor}. If this is intended, you're all set!`;
|
|
mismatchMessage.classList.remove("hidden");
|
|
}
|
|
}
|
|
|
|
function check() {
|
|
fetch(<%== api_v1_my_heartbeats_most_recent_path.to_json %>, {
|
|
headers: {
|
|
Authorization: "Bearer " + <%== @current_user_api_key.to_json %>,
|
|
},
|
|
})
|
|
.then((response) => response.json())
|
|
.then((data) => {
|
|
if (data.has_heartbeat) {
|
|
const heartbeatTime = new Date(data.heartbeat.created_at);
|
|
const now = new Date();
|
|
const secondsAgo = (now - heartbeatTime) / 1000;
|
|
const recentThreshold = 86400;
|
|
|
|
if (secondsAgo <= recentThreshold) {
|
|
showSuccess(data.time_ago, data.editor);
|
|
return;
|
|
}
|
|
}
|
|
throw new Error("No recent heartbeats");
|
|
})
|
|
.catch((error) => {
|
|
checkCount++;
|
|
|
|
if (checkCount % 3 === 0) {
|
|
const msgIndex = Math.floor(checkCount / 3) % msg.length;
|
|
statusMessage.textContent = msg[msgIndex];
|
|
}
|
|
|
|
pollStatus.textContent = `Checked ${checkCount} time${checkCount === 1 ? "" : "s"}...`;
|
|
|
|
if (checkCount >= maxChecks) {
|
|
pollStatus.textContent = "Still waiting... Make sure the extension is installed!";
|
|
return;
|
|
}
|
|
|
|
setTimeout(check, 5000);
|
|
});
|
|
}
|
|
|
|
check();
|
|
|
|
window.skipToNext = function () {
|
|
window.location.href = <%== my_wakatime_setup_step_4_path.to_json %>;
|
|
};
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.spin {
|
|
width: 16px;
|
|
height: 16px;
|
|
border: 2px solid var(--color-darkless);
|
|
border-top: 2px solid var(--color-blue);
|
|
border-radius: 50%;
|
|
animation: spin 1s linear infinite;
|
|
}
|
|
|
|
@keyframes spin {
|
|
0% {
|
|
transform: rotate(0deg);
|
|
}
|
|
100% {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
</style>
|
|
<% end %>
|