mirror of
https://github.com/wahyd4/links.git
synced 2026-08-08 21:04:53 +10:00
158 lines
6.6 KiB
HTML
158 lines
6.6 KiB
HTML
{% extends "base.html" %}
|
|
{% load i18n %}
|
|
|
|
{% block title %}{{ title }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="max-w-5xl mx-auto px-4 py-6">
|
|
|
|
<div class="flex items-center gap-3 mb-6">
|
|
<a href="{% url 'pricemon-dashboard' %}"
|
|
class="text-gray-400 hover:text-gray-600 transition">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
|
|
</svg>
|
|
</a>
|
|
<h1 class="text-xl font-bold text-gray-900">{{ title }}</h1>
|
|
</div>
|
|
|
|
{% if messages %}
|
|
{% for msg in messages %}
|
|
<div class="mb-4 px-4 py-3 rounded-lg text-sm
|
|
{% if msg.tags == 'error' %}bg-red-50 text-red-700 border border-red-100
|
|
{% else %}bg-green-50 text-green-700 border border-green-100{% endif %}">
|
|
{{ msg }}
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-100 p-8">
|
|
<form method="post" id="watcher-form" class="space-y-6">
|
|
{% csrf_token %}
|
|
|
|
{% if form.non_field_errors %}
|
|
<div class="px-4 py-3 rounded-lg bg-red-50 border border-red-100 text-sm text-red-700">
|
|
{{ form.non_field_errors }}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Name (full width) -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">
|
|
{{ form.name.label }} <span class="text-red-500">*</span>
|
|
</label>
|
|
{{ form.name }}
|
|
{% for e in form.name.errors %}<p class="text-xs text-red-600 mt-1">{{ e }}</p>{% endfor %}
|
|
</div>
|
|
|
|
<!-- URL (full width) -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">
|
|
{{ form.url.label }} <span class="text-red-500">*</span>
|
|
</label>
|
|
{{ form.url }}
|
|
{% for e in form.url.errors %}<p class="text-xs text-red-600 mt-1">{{ e }}</p>{% endfor %}
|
|
</div>
|
|
|
|
<!-- CSS Selector + Test button (full width) -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">
|
|
{{ form.css_selector.label }} <span class="text-red-500">*</span>
|
|
</label>
|
|
<div class="flex gap-2 items-start">
|
|
<div class="flex-1">{{ form.css_selector }}</div>
|
|
<button type="button"
|
|
id="test-selector-btn"
|
|
class="flex-shrink-0 mt-px inline-flex items-center gap-1.5 px-3 py-2 text-sm font-medium text-indigo-700 bg-indigo-50 border border-indigo-200 rounded-md hover:bg-indigo-100 transition"
|
|
hx-post="{% url 'pricemon-test-selector' %}"
|
|
hx-include="#watcher-form [name='url'], #watcher-form [name='css_selector']"
|
|
hx-target="#selector-test-result"
|
|
hx-swap="innerHTML">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
</svg>
|
|
<span id="test-btn-label">{% trans "Test" %}</span>
|
|
</button>
|
|
</div>
|
|
<div id="selector-test-result" class="mt-2"></div>
|
|
<p class="text-xs text-gray-400 mt-1">{{ form.css_selector.help_text }}</p>
|
|
{% for e in form.css_selector.errors %}<p class="text-xs text-red-600 mt-1">{{ e }}</p>{% endfor %}
|
|
</div>
|
|
|
|
<!-- Row: Check interval + Alert price threshold -->
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">
|
|
{{ form.check_interval_hours.label }} <span class="text-red-500">*</span>
|
|
</label>
|
|
{{ form.check_interval_hours }}
|
|
{% for e in form.check_interval_hours.errors %}<p class="text-xs text-red-600 mt-1">{{ e }}</p>{% endfor %}
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">
|
|
{{ form.alert_price_threshold.label }}
|
|
</label>
|
|
{{ form.alert_price_threshold }}
|
|
<p class="text-xs text-gray-400 mt-1">{{ form.alert_price_threshold.help_text }}</p>
|
|
{% for e in form.alert_price_threshold.errors %}<p class="text-xs text-red-600 mt-1">{{ e }}</p>{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Row: Recurring notification + Enabled -->
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
|
<div class="flex items-start gap-3">
|
|
{{ form.recurring_notification }}
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">{{ form.recurring_notification.label }}</label>
|
|
<p class="text-xs text-gray-400 mt-0.5">{{ form.recurring_notification.help_text }}</p>
|
|
</div>
|
|
{% for e in form.recurring_notification.errors %}<p class="text-xs text-red-600 mt-1">{{ e }}</p>{% endfor %}
|
|
</div>
|
|
<div class="flex items-start gap-3">
|
|
{{ form.enabled }}
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">{{ form.enabled.label }}</label>
|
|
<p class="text-xs text-gray-400 mt-0.5">{% trans "Uncheck to pause price checks for this watcher." %}</p>
|
|
</div>
|
|
{% for e in form.enabled.errors %}<p class="text-xs text-red-600 mt-1">{{ e }}</p>{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-3 pt-2 border-t border-gray-100">
|
|
<button type="submit"
|
|
class="px-6 py-2 bg-indigo-600 text-white text-sm font-medium rounded-lg hover:bg-indigo-700 transition">
|
|
{% trans "Save" %}
|
|
</button>
|
|
<a href="{% url 'pricemon-dashboard' %}"
|
|
class="px-6 py-2 bg-gray-100 text-gray-700 text-sm font-medium rounded-lg hover:bg-gray-200 transition">
|
|
{% trans "Cancel" %}
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="mt-4 text-xs text-gray-400">
|
|
<p>{% trans "Selector tip:" %} inspect the price on the product page and find its CSS class. E.g. <code class="bg-gray-100 px-1 rounded">.product-price</code> or <code class="bg-gray-100 px-1 rounded">span[itemprop="price"]</code></p>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
document.addEventListener('htmx:beforeRequest', function(e) {
|
|
if (e.target.id === 'test-selector-btn') {
|
|
document.getElementById('test-btn-label').textContent = '{% trans "Testing…" %}';
|
|
e.target.disabled = true;
|
|
}
|
|
});
|
|
document.addEventListener('htmx:afterRequest', function(e) {
|
|
if (e.target.id === 'test-selector-btn') {
|
|
document.getElementById('test-btn-label').textContent = '{% trans "Test" %}';
|
|
e.target.disabled = false;
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
{% endblock %}
|