feat: telegram commands, app settings, bot polling, webhook handling, UI improvements
Adds telegram bot command system with 13 commands (search, latest, random, etc.), webhook/polling handlers, rate limiting, app settings page, and various UI/UX improvements across all entity pages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
<script lang="ts">
|
||||
import '../app.css';
|
||||
import { page } from '$app/state';
|
||||
import { goto } from '$app/navigation';
|
||||
import { onMount } from 'svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { api } from '$lib/api';
|
||||
import { getAuth, loadUser, logout } from '$lib/auth.svelte';
|
||||
import { t, initLocale, getLocale, setLocale, type Locale } from '$lib/i18n';
|
||||
import { t, getLocale, setLocale, type Locale } from '$lib/i18n';
|
||||
import { getTheme, initTheme, setTheme, type Theme } from '$lib/theme.svelte';
|
||||
import Modal from '$lib/components/Modal.svelte';
|
||||
import MdiIcon from '$lib/components/MdiIcon.svelte';
|
||||
@@ -37,7 +36,7 @@
|
||||
|
||||
let collapsed = $state(false);
|
||||
|
||||
const navItems = [
|
||||
const baseNavItems = [
|
||||
{ href: '/', key: 'nav.dashboard', icon: 'mdiViewDashboard' },
|
||||
{ href: '/providers', key: 'nav.providers', icon: 'mdiServer' },
|
||||
{ href: '/trackers', key: 'nav.trackers', icon: 'mdiRadar' },
|
||||
@@ -46,20 +45,23 @@
|
||||
{ href: '/telegram-bots', key: 'nav.telegramBots', icon: 'mdiRobot' },
|
||||
{ href: '/targets', key: 'nav.targets', icon: 'mdiTarget' },
|
||||
];
|
||||
const navItems = $derived(auth.isAdmin
|
||||
? [...baseNavItems, { href: '/users', key: 'nav.users', icon: 'mdiAccountGroup' }, { href: '/settings', key: 'nav.settings', icon: 'mdiCogOutline' }]
|
||||
: baseNavItems
|
||||
);
|
||||
|
||||
const isAuthPage = $derived(
|
||||
page.url.pathname === '/login' || page.url.pathname === '/setup'
|
||||
);
|
||||
|
||||
onMount(async () => {
|
||||
initLocale();
|
||||
initTheme();
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
collapsed = localStorage.getItem('sidebar_collapsed') === 'true';
|
||||
}
|
||||
await loadUser();
|
||||
if (!auth.user && !isAuthPage) {
|
||||
goto('/login');
|
||||
window.location.href = '/login';
|
||||
}
|
||||
});
|
||||
|
||||
@@ -139,22 +141,6 @@
|
||||
{#if !collapsed}<span class="truncate">{t(item.key)}</span>{/if}
|
||||
</a>
|
||||
{/each}
|
||||
{#if auth.isAdmin}
|
||||
<a
|
||||
href="/users"
|
||||
class="nav-item group flex items-center gap-2.5 {collapsed ? 'justify-center px-2' : 'px-3'} py-2 rounded-lg text-sm transition-all duration-200 relative"
|
||||
style="color: {isActive('/users') ? 'var(--color-primary)' : 'var(--color-muted-foreground)'}; background: {isActive('/users') ? 'var(--color-sidebar-active)' : 'transparent'}; font-weight: {isActive('/users') ? '500' : '400'};"
|
||||
onmouseenter={(e) => { if (!isActive('/users')) { e.currentTarget.style.background = 'var(--color-muted)'; e.currentTarget.style.color = 'var(--color-foreground)'; } }}
|
||||
onmouseleave={(e) => { if (!isActive('/users')) { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--color-muted-foreground)'; } }}
|
||||
title={collapsed ? t('nav.users') : ''}
|
||||
>
|
||||
{#if isActive('/users')}
|
||||
<div style="position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 3px; height: 60%; border-radius: 0 3px 3px 0; background: var(--color-primary); box-shadow: 0 0 8px var(--color-glow-strong);"></div>
|
||||
{/if}
|
||||
<MdiIcon name="mdiAccountGroup" size={18} />
|
||||
{#if !collapsed}<span class="truncate">{t('nav.users')}</span>{/if}
|
||||
</a>
|
||||
{/if}
|
||||
</nav>
|
||||
|
||||
<!-- Footer -->
|
||||
|
||||
Reference in New Issue
Block a user