Add DeepSeek/xAI/OpenAI-compatible sentiment providers; custom dark dropdown
Deploy / lint (push) Successful in 5s
Deploy / test (push) Successful in 32s
Deploy / deploy (push) Successful in 22s

Providers (admin-switchable, no redeploy):
- DeepSeek and any OpenAI-compatible endpoint (OpenRouter, Together,
  Groq, local Ollama) via a generic Chat Completions adapter + base_url
- xAI Grok with Live Search (search_parameters web+X, citations) —
  grounded tier alongside OpenAI and Gemini
- DeepSeek / generic compatible endpoints are ungrounded (no web
  search); UI shows an amber warning and labels each provider's grounding
- Optional env fallbacks DEEPSEEK_API_KEY / XAI_API_KEY

UI: replace native <select> (unstyleable white popup on Windows) with a
custom dark Dropdown component everywhere — sentiment provider, scanner
filters, market sort, indicators, admin universe, user role.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 12:42:04 +02:00
parent d53ed972d1
commit 126c3b3c17
16 changed files with 521 additions and 98 deletions
@@ -1,7 +1,7 @@
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { getIndicator, getEMACross } from '../../api/indicators';
import { Select } from '../ui/Field';
import { Dropdown } from '../ui/Dropdown';
import type { IndicatorResult, EMACrossResult } from '../../lib/types';
const INDICATOR_TYPES = ['ADX', 'EMA', 'RSI', 'ATR', 'volume_profile', 'pivot_points'] as const;
@@ -86,16 +86,12 @@ export function IndicatorSelector({ symbol }: IndicatorSelectorProps) {
<h3 className="mb-3 text-xs font-medium uppercase tracking-widest text-gray-500">Indicators</h3>
<div className="mb-4">
<Select
<Dropdown
value={selectedType}
onChange={(e) => setSelectedType(e.target.value)}
className="w-full !py-2.5"
>
<option value="">Select indicator</option>
{INDICATOR_TYPES.map((type) => (
<option key={type} value={type}>{type}</option>
))}
</Select>
onChange={setSelectedType}
placeholder="Select indicator…"
options={INDICATOR_TYPES.map((type) => ({ value: type, label: type }))}
/>
</div>
{selectedType && indicatorQuery.isLoading && (