hackatime/app/views/shared/_interval_selector.html.erb
Echo 89c2649898
fix broken color definition (#826)
* fix broken color definition

* switch to real colors

* fix bg

* fix leaderboards

* tidy up settings page
2026-01-25 12:05:22 -05:00

132 lines
5.5 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-gray-100 border border-gray-700 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-gray-500 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-gray-100 border border-gray-700 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 %>', '<%= config[:human_name] %>')"><%= 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-gray-700">
<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-gray-700 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-gray-700 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 %>';
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);
frame.src = frameUrl;
try {
frame.reload();
console.log('Frame reload called successfully');
} catch (e) {
console.error('Error reloading frame:', e);
}
history.replaceState({}, '', url);
} else {
console.error('Frame with ID "project_durations" not found');
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 %>