Admin settings: give each ingestion source its own card
CI/CD / CI · dotnet build (push) Successful in 2m17s
CI/CD / Deploy · hamkadr (push) Successful in 1m57s

The sources panel (Telegram/Bale/Divar/Medjobs/Websites/Proxy) ran
together as one flat list. Each is now wrapped in a bordered .source-box
with an icon + hint, so it's clear where one source's settings end and the
next begins.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-08 08:49:27 +03:30
parent 0622270cd2
commit f9d7c48d88
2 changed files with 64 additions and 46 deletions
@@ -96,54 +96,66 @@
<input type="number" name="IngestIntervalMinutes" min="1" value="@Model.IngestIntervalMinutes" dir="ltr" /> <input type="number" name="IngestIntervalMinutes" min="1" value="@Model.IngestIntervalMinutes" dir="ltr" />
</div> </div>
<p class="muted" style="font-size:12px; margin:0 0 4px;">هر منبع را جداگانه روشن/خاموش و تنظیم کن.</p>
<div class="source-box">
<label class="toggle-row"> <label class="toggle-row">
<input type="checkbox" name="TelegramEnabled" value="true" checked="@Model.TelegramEnabled" /> <input type="checkbox" name="TelegramEnabled" value="true" checked="@Model.TelegramEnabled" />
<span class="t-body"><span>تلگرام (کانال‌های عمومی — بدون توکن)</span></span> <span class="t-body"><span>📨 تلگرام</span><span class="t-hint">کانال‌های عمومی — بدون توکن.</span></span>
</label> </label>
<div class="filter-group"> <div class="filter-group">
<label>یوزرنیم کانال‌ها (هر خط یک کانال)</label> <label>یوزرنیم کانال‌ها (هر خط یک کانال)</label>
<textarea name="TelegramChannels" rows="3" dir="ltr" placeholder="shift_channel&#10;another_channel">@Model.TelegramChannels</textarea> <textarea name="TelegramChannels" rows="3" dir="ltr" placeholder="shift_channel&#10;another_channel">@Model.TelegramChannels</textarea>
<label class="proxy-toggle"><input type="checkbox" name="TelegramUseProxy" value="true" checked="@Model.TelegramUseProxy" /> از پروکسی استفاده شود</label> <label class="proxy-toggle"><input type="checkbox" name="TelegramUseProxy" value="true" checked="@Model.TelegramUseProxy" /> از پروکسی استفاده شود</label>
</div> </div>
</div>
<div class="source-box">
<label class="toggle-row"> <label class="toggle-row">
<input type="checkbox" name="BaleEnabled" value="true" checked="@Model.BaleEnabled" /> <input type="checkbox" name="BaleEnabled" value="true" checked="@Model.BaleEnabled" />
<span class="t-body"><span>بله (بات باید عضو کانال باشد)</span></span> <span class="t-body"><span>💬 بله</span><span class="t-hint">بات باید عضو کانال باشد.</span></span>
</label> </label>
<div class="filter-group"><label>توکن بات بله</label><input type="password" name="BaleBotToken" value="@Model.BaleBotToken" dir="ltr" /> <div class="filter-group"><label>توکن بات بله</label><input type="password" name="BaleBotToken" value="@Model.BaleBotToken" dir="ltr" />
<label class="proxy-toggle"><input type="checkbox" name="BaleUseProxy" value="true" checked="@Model.BaleUseProxy" /> از پروکسی استفاده شود</label> <label class="proxy-toggle"><input type="checkbox" name="BaleUseProxy" value="true" checked="@Model.BaleUseProxy" /> از پروکسی استفاده شود</label>
</div> </div>
</div>
<div class="source-box">
<label class="toggle-row"> <label class="toggle-row">
<input type="checkbox" name="DivarEnabled" value="true" checked="@Model.DivarEnabled" /> <input type="checkbox" name="DivarEnabled" value="true" checked="@Model.DivarEnabled" />
<span class="t-body"><span>دیوار</span></span> <span class="t-body"><span>🟥 دیوار</span></span>
</label> </label>
<div class="filter-group" style="display:flex; gap:8px;"> <div class="filter-group" style="display:flex; gap:8px;">
<div style="flex:0 0 120px;"><label>شهر (slug)</label><input type="text" name="DivarCity" value="@Model.DivarCity" dir="ltr" placeholder="tehran" /></div> <div style="flex:0 0 120px;"><label>شهر (slug)</label><input type="text" name="DivarCity" value="@Model.DivarCity" dir="ltr" placeholder="tehran" /></div>
<div style="flex:1;"><label>عبارت‌های جستجو (هر خط یکی)</label><textarea name="DivarQueries" rows="3">@Model.DivarQueries</textarea></div> <div style="flex:1;"><label>عبارت‌های جستجو (هر خط یکی)</label><textarea name="DivarQueries" rows="3">@Model.DivarQueries</textarea></div>
</div> </div>
<label class="proxy-toggle"><input type="checkbox" name="DivarUseProxy" value="true" checked="@Model.DivarUseProxy" /> از پروکسی استفاده شود</label> <label class="proxy-toggle"><input type="checkbox" name="DivarUseProxy" value="true" checked="@Model.DivarUseProxy" /> از پروکسی استفاده شود</label>
</div>
<div class="source-box">
<label class="toggle-row"> <label class="toggle-row">
<input type="checkbox" name="MedjobsEnabled" value="true" checked="@Model.MedjobsEnabled" /> <input type="checkbox" name="MedjobsEnabled" value="true" checked="@Model.MedjobsEnabled" />
<span class="t-body"><span>مدجابز (medjobs.ir)</span><span class="t-hint">خواندن کامل آگهی‌ها از سایت‌مپ.</span></span> <span class="t-body"><span>🩺 مدجابز (medjobs.ir)</span><span class="t-hint">خواندن کامل آگهی‌ها از سایت‌مپ + استخراج شماره.</span></span>
</label> </label>
<div class="filter-group"><label>حداکثر آگهی در هر اجرا</label><input type="number" name="MedjobsMaxAds" min="1" max="500" value="@Model.MedjobsMaxAds" dir="ltr" /> <div class="filter-group"><label>حداکثر آگهی در هر اجرا</label><input type="number" name="MedjobsMaxAds" min="1" max="500" value="@Model.MedjobsMaxAds" dir="ltr" />
<label class="proxy-toggle"><input type="checkbox" name="MedjobsUseProxy" value="true" checked="@Model.MedjobsUseProxy" /> از پروکسی استفاده شود</label> <label class="proxy-toggle"><input type="checkbox" name="MedjobsUseProxy" value="true" checked="@Model.MedjobsUseProxy" /> از پروکسی استفاده شود</label>
</div> </div>
</div>
<div class="source-box">
<label class="toggle-row"> <label class="toggle-row">
<input type="checkbox" name="WebsitesEnabled" value="true" checked="@Model.WebsitesEnabled" /> <input type="checkbox" name="WebsitesEnabled" value="true" checked="@Model.WebsitesEnabled" />
<span class="t-body"><span>وب‌سایت‌ها (آدرس‌های دلخواه)</span></span> <span class="t-body"><span>🌐 وب‌سایت‌ها</span><span class="t-hint">آدرس‌های دلخواه.</span></span>
</label> </label>
<div class="filter-group"> <div class="filter-group">
<label>آدرس صفحه‌ها (هر خط یک URL)</label> <label>آدرس صفحه‌ها (هر خط یک URL)</label>
<textarea name="WebsiteUrls" rows="3" dir="ltr" placeholder="https://example.ir/jobs/123">@Model.WebsiteUrls</textarea> <textarea name="WebsiteUrls" rows="3" dir="ltr" placeholder="https://example.ir/jobs/123">@Model.WebsiteUrls</textarea>
<label class="proxy-toggle"><input type="checkbox" name="WebsitesUseProxy" value="true" checked="@Model.WebsitesUseProxy" /> از پروکسی استفاده شود</label> <label class="proxy-toggle"><input type="checkbox" name="WebsitesUseProxy" value="true" checked="@Model.WebsitesUseProxy" /> از پروکسی استفاده شود</label>
</div> </div>
</div>
<hr style="border:none; border-top:1px solid var(--line); margin:18px 0;" /> <div class="source-box">
<h3 style="margin-top:0;">پروکسی (Xray/V2Ray)</h3> <h4 style="margin:0 0 8px;">🛡️ پروکسی (Xray/V2Ray)</h4>
<div class="filter-group"> <div class="filter-group">
<label>آدرس پروکسی محلی</label> <label>آدرس پروکسی محلی</label>
<input type="text" name="IngestProxyUrl" value="@Model.IngestProxyUrl" dir="ltr" placeholder="socks5://xray:10808" /> <input type="text" name="IngestProxyUrl" value="@Model.IngestProxyUrl" dir="ltr" placeholder="socks5://xray:10808" />
@@ -151,6 +163,7 @@
<button type="submit" asp-page-handler="TestProxy" class="btn btn-outline" style="margin-top:8px;">🔌 تست اتصال VPN/پروکسی</button> <button type="submit" asp-page-handler="TestProxy" class="btn btn-outline" style="margin-top:8px;">🔌 تست اتصال VPN/پروکسی</button>
<p class="muted" style="font-size:11px; margin:4px 0 0;">از طریق پروکسی به یک سایت فیلترشده وصل می‌شود؛ موفقیت یعنی تونل برقرار است. (ابتدا آدرس را ذخیره کن.)</p> <p class="muted" style="font-size:11px; margin:4px 0 0;">از طریق پروکسی به یک سایت فیلترشده وصل می‌شود؛ موفقیت یعنی تونل برقرار است. (ابتدا آدرس را ذخیره کن.)</p>
</div> </div>
</div>
</section> </section>
<!-- CHANNELS --> <!-- CHANNELS -->
+5
View File
@@ -376,6 +376,11 @@ label { font-size: 13px; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } } @keyframes fadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.settings-panel h3:first-child { margin-top: 0; } .settings-panel h3:first-child { margin-top: 0; }
/* Each ingestion source gets its own card so the settings don't run together. */
.source-box { border: 1px solid var(--line); border-radius: 14px; padding: 14px; margin: 12px 0; background: var(--surface); }
.source-box .toggle-row { background: var(--bg); margin-bottom: 10px; }
.source-box .filter-group:last-child { margin-bottom: 0; }
/* Toggle rows — give each boolean field a clean, card-like row. */ /* Toggle rows — give each boolean field a clean, card-like row. */
.toggle-row { .toggle-row {
display: flex; align-items: flex-start; gap: 10px; font-weight: 700; display: flex; align-items: flex-start; gap: 10px; font-weight: 700;