hackatime/app/views/shared/_interval_selector.html.erb
Mahad Kalam dd978bbeb9
Themes! (#952)
* Themes pt1

* Themes pt2

* Standard -> Classic, new default is Gruvbox Dark

* Make settings shell fatter
2026-02-15 22:14:46 +00:00

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 %>