mirror of
https://github.com/System-End/hackatime.git
synced 2026-04-19 19:55:16 +00:00
* Themes pt1 * Themes pt2 * Standard -> Classic, new default is Gruvbox Dark * Make settings shell fatter
124 lines
5.2 KiB
Text
124 lines
5.2 KiB
Text
<%= turbo_frame_tag "interval_selector" do %>
|
|
<div class="relative inline-block w-full max-w-xs">
|
|
<button type="button" id="interval-dropdown-trigger" class="w-full px-4 py-2 bg-darkless text-muted border border-surface-200 rounded cursor-pointer text-left flex items-center justify-between shadow-lg" onclick="toggleIntervalDropdown()">
|
|
<span id="interval-dropdown-label">
|
|
<%= human_interval_name(params[:interval], from: params[:from], to: params[:to]) %>
|
|
</span>
|
|
|
|
<svg id="interval-dropdown-arrow" viewBox="0 0 20 20" fill="currentColor" data-slot="icon" aria-hidden="true" class="w-5 h-5 text-muted transition-transform duration-200">
|
|
<path d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" fill-rule="evenodd" />
|
|
</svg>
|
|
</button>
|
|
|
|
<div id="interval-dropdown-menu" class="w-full px-3 py-2 mt-2 bg-darkless text-muted border border-surface-200 rounded-lg absolute z-1000 shadow-lg" style="display: none;">
|
|
<ul class="list-none m-0 p-0 overflow-y-auto max-h-60">
|
|
<% TimeRangeFilterable::RANGES.each do |key, config| %>
|
|
<li class="py-1.5 px-2 cursor-pointer rounded bg-transparent hover:bg-[#2c313a] transition" onclick="selectInterval(<%= key.to_json %>, <%= config[:human_name].to_json %>)"><%= config[:human_name] %></li>
|
|
<% end %>
|
|
<li class="py-1.5 px-2 cursor-pointer rounded bg-transparent hover:bg-[#2c313a] transition" onclick="selectInterval('', 'All Time')">All Time</li>
|
|
</ul>
|
|
|
|
<hr class="my-2 border-surface-200">
|
|
|
|
<div class="flex flex-col gap-2 mt-2">
|
|
<label class="flex items-center justify-between">Start:
|
|
<input type="date" class="ml-2 py-1 px-2 bg-dark border border-surface-200 rounded" id="custom-start" value="<%= params[:from] %>">
|
|
</label>
|
|
|
|
<label class="flex items-center justify-between">End:
|
|
<input type="date" class="ml-2 py-1 px-2 bg-dark border border-surface-200 rounded" id="custom-end" value="<%= params[:to] %>">
|
|
</label>
|
|
|
|
<button type="button" class="interval-selector-button px-3 py-2 mt-2 mb-1 rounded font-semibold transition cursor-pointer" onclick="applyCustomRange()">Apply</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// 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.to_json %>;
|
|
const params = new URLSearchParams(new URL(url).search);
|
|
const frameUrl = baseUrl + "?" + params.toString();
|
|
|
|
const frame = document.getElementById("project_durations");
|
|
if (frame) {
|
|
frame.src = frameUrl;
|
|
history.replaceState({}, "", url);
|
|
} else {
|
|
window.location.href = url;
|
|
}
|
|
}
|
|
|
|
function updateDropdownLabel(label) {
|
|
const labelElement = document.getElementById("interval-dropdown-label");
|
|
if (labelElement) {
|
|
labelElement.textContent = label;
|
|
}
|
|
}
|
|
|
|
function selectInterval(interval, label) {
|
|
updateDropdownLabel(label);
|
|
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) {
|
|
label = `${start} to ${end}`;
|
|
} else if (start) {
|
|
label = `From ${start}`;
|
|
} 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");
|
|
const arrow = document.getElementById("interval-dropdown-arrow");
|
|
const isOpen = menu.style.display === "block";
|
|
|
|
menu.style.display = isOpen ? "none" : "block";
|
|
arrow.style.transform = isOpen ? "rotate(0deg)" : "rotate(180deg)";
|
|
document.addEventListener("mousedown", closeDropdownOnClickOutside);
|
|
}
|
|
|
|
function closeDropdownOnClickOutside(e) {
|
|
const menu = document.getElementById("interval-dropdown-menu");
|
|
const trigger = document.getElementById("interval-dropdown-trigger");
|
|
const arrow = document.getElementById("interval-dropdown-arrow");
|
|
|
|
if (!menu.contains(e.target) && !trigger.contains(e.target)) {
|
|
menu.style.display = "none";
|
|
arrow.style.transform = "rotate(0deg)";
|
|
document.removeEventListener("mousedown", closeDropdownOnClickOutside);
|
|
}
|
|
}
|
|
</script>
|
|
<% end %>
|