feat: travel service with 2GIS routing, POI, hotels + finance providers + UI overhaul
- Add travel-svc microservice (Amadeus, TravelPayouts, 2GIS, OpenRouteService) - Add travel orchestrator with parallel collectors (events, POI, hotels, flights) - Add 2GIS road routing with transport cost calculation (car/bus/taxi) - Add TravelMap (2GIS MapGL) and TravelWidgets components - Add useTravelChat hook for streaming travel agent responses - Add finance heatmap providers refactor - Add SearXNG settings, API proxy routes, Docker compose updates - Update Dockerfiles, config, types, and all UI pages for consistency Made-with: Cursor
This commit is contained in:
@@ -83,15 +83,15 @@ export default function AdminAuditPage() {
|
||||
const getActionColor = (action: string) => {
|
||||
switch (action) {
|
||||
case 'create':
|
||||
return 'bg-green-500/10 text-green-400';
|
||||
return 'bg-green-500/10 text-green-600';
|
||||
case 'update':
|
||||
return 'bg-blue-500/10 text-blue-400';
|
||||
return 'bg-blue-500/10 text-blue-600';
|
||||
case 'delete':
|
||||
return 'bg-red-500/10 text-red-400';
|
||||
return 'bg-red-500/10 text-red-600';
|
||||
case 'publish':
|
||||
return 'bg-purple-500/10 text-purple-400';
|
||||
return 'bg-purple-500/10 text-purple-600';
|
||||
default:
|
||||
return 'bg-gray-500/10 text-gray-400';
|
||||
return 'bg-surface text-muted';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -48,8 +48,8 @@ function CategoryModal({ category, onClose, onSave }: CategoryModalProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
||||
<div className="bg-surface rounded-xl p-6 w-full max-w-md">
|
||||
<div className="fixed inset-0 bg-primary/25 backdrop-blur-sm flex items-center justify-center z-50">
|
||||
<div className="bg-elevated rounded-xl p-6 w-full max-w-md shadow-dropdown border border-border">
|
||||
<h2 className="text-xl font-bold text-primary mb-4">
|
||||
{category ? 'Редактировать категорию' : 'Новая категория'}
|
||||
</h2>
|
||||
@@ -138,7 +138,7 @@ function CategoryModal({ category, onClose, onSave }: CategoryModalProps) {
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="flex-1 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors"
|
||||
className="flex-1 px-4 py-2 bg-accent text-accent-foreground rounded-lg hover:bg-accent-hover transition-colors"
|
||||
>
|
||||
Сохранить
|
||||
</button>
|
||||
@@ -175,8 +175,8 @@ function SourceModal({ onClose, onSave }: SourceModalProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
||||
<div className="bg-surface rounded-xl p-6 w-full max-w-md">
|
||||
<div className="fixed inset-0 bg-primary/25 backdrop-blur-sm flex items-center justify-center z-50">
|
||||
<div className="bg-elevated rounded-xl p-6 w-full max-w-md shadow-dropdown border border-border">
|
||||
<h2 className="text-xl font-bold text-primary mb-4">Новый источник</h2>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
@@ -254,7 +254,7 @@ function SourceModal({ onClose, onSave }: SourceModalProps) {
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="flex-1 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors"
|
||||
className="flex-1 px-4 py-2 bg-accent text-accent-foreground rounded-lg hover:bg-accent-hover transition-colors"
|
||||
>
|
||||
Добавить
|
||||
</button>
|
||||
@@ -390,7 +390,7 @@ export default function AdminDiscoverPage() {
|
||||
<p className="text-sm text-muted">Перетащите для изменения порядка</p>
|
||||
<button
|
||||
onClick={() => setCategoryModal(null)}
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-primary text-white rounded-lg text-sm hover:bg-primary/90 transition-colors"
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-accent text-accent-foreground rounded-lg text-sm hover:bg-accent-hover transition-colors"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Добавить
|
||||
@@ -414,7 +414,7 @@ export default function AdminDiscoverPage() {
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => handleToggleCategory(cat)}
|
||||
className={`p-1 rounded ${cat.isActive ? 'text-green-400' : 'text-muted'}`}
|
||||
className={`p-1 rounded ${cat.isActive ? 'text-green-600' : 'text-muted'}`}
|
||||
>
|
||||
{cat.isActive ? <ToggleRight className="w-6 h-6" /> : <ToggleLeft className="w-6 h-6" />}
|
||||
</button>
|
||||
@@ -426,7 +426,7 @@ export default function AdminDiscoverPage() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleDeleteCategory(cat.id)}
|
||||
className="p-1 text-muted hover:text-red-400 rounded"
|
||||
className="p-1 text-muted hover:text-red-600 rounded"
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</button>
|
||||
@@ -443,7 +443,7 @@ export default function AdminDiscoverPage() {
|
||||
<p className="text-sm text-muted">Доверенные источники новостей</p>
|
||||
<button
|
||||
onClick={() => setShowSourceModal(true)}
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-primary text-white rounded-lg text-sm hover:bg-primary/90 transition-colors"
|
||||
className="flex items-center gap-2 px-3 py-1.5 bg-accent text-accent-foreground rounded-lg text-sm hover:bg-accent-hover transition-colors"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Добавить
|
||||
@@ -474,15 +474,15 @@ export default function AdminDiscoverPage() {
|
||||
<div className="text-sm">
|
||||
<span className="text-muted">Доверие:</span>
|
||||
<span className={`ml-1 font-medium ${
|
||||
source.trustScore >= 0.7 ? 'text-green-400' :
|
||||
source.trustScore >= 0.4 ? 'text-yellow-400' : 'text-red-400'
|
||||
source.trustScore >= 0.7 ? 'text-green-600' :
|
||||
source.trustScore >= 0.4 ? 'text-yellow-600' : 'text-red-600'
|
||||
}`}>
|
||||
{(source.trustScore * 100).toFixed(0)}%
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleDeleteSource(source.id)}
|
||||
className="p-1 text-muted hover:text-red-400 rounded"
|
||||
className="p-1 text-muted hover:text-red-600 rounded"
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</button>
|
||||
|
||||
@@ -69,7 +69,7 @@ export default function AdminDashboardPage() {
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="bg-red-500/10 text-red-400 p-4 rounded-lg">
|
||||
<div className="bg-red-500/10 text-red-600 p-4 rounded-lg">
|
||||
{error}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -46,7 +46,7 @@ function PostModal({ post, onClose, onSave }: PostModalProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
||||
<div className="fixed inset-0 bg-primary/25 backdrop-blur-sm flex items-center justify-center z-50 p-4">
|
||||
<div className="bg-surface rounded-xl p-6 w-full max-w-2xl max-h-[90vh] overflow-y-auto">
|
||||
<h2 className="text-xl font-bold text-primary mb-4">
|
||||
{post ? 'Редактировать пост' : 'Новый пост'}
|
||||
@@ -129,7 +129,7 @@ function PostModal({ post, onClose, onSave }: PostModalProps) {
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="flex-1 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors"
|
||||
className="flex-1 px-4 py-2 bg-accent text-accent-foreground rounded-lg hover:bg-accent-hover transition-colors"
|
||||
>
|
||||
Сохранить
|
||||
</button>
|
||||
@@ -204,13 +204,13 @@ export default function AdminPostsPage() {
|
||||
const getStatusBadge = (status: string) => {
|
||||
switch (status) {
|
||||
case 'published':
|
||||
return 'bg-green-500/10 text-green-400';
|
||||
return 'bg-green-500/10 text-green-600';
|
||||
case 'draft':
|
||||
return 'bg-yellow-500/10 text-yellow-400';
|
||||
return 'bg-yellow-500/10 text-yellow-600';
|
||||
case 'archived':
|
||||
return 'bg-gray-500/10 text-gray-400';
|
||||
return 'bg-surface text-muted';
|
||||
default:
|
||||
return 'bg-gray-500/10 text-gray-400';
|
||||
return 'bg-surface text-muted';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -236,7 +236,7 @@ export default function AdminPostsPage() {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setModalPost(null)}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors"
|
||||
className="flex items-center gap-2 px-4 py-2 bg-accent text-accent-foreground rounded-lg hover:bg-accent-hover transition-colors"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Создать
|
||||
@@ -338,7 +338,7 @@ export default function AdminPostsPage() {
|
||||
handlePublish(post.id);
|
||||
setActiveMenu(null);
|
||||
}}
|
||||
className="w-full flex items-center gap-2 px-3 py-2 text-sm text-green-400 hover:bg-base"
|
||||
className="w-full flex items-center gap-2 px-3 py-2 text-sm text-green-600 hover:bg-base"
|
||||
>
|
||||
<Send className="w-4 h-4" />
|
||||
Опубликовать
|
||||
@@ -358,7 +358,7 @@ export default function AdminPostsPage() {
|
||||
handleDelete(post.id);
|
||||
setActiveMenu(null);
|
||||
}}
|
||||
className="w-full flex items-center gap-2 px-3 py-2 text-sm text-red-400 hover:bg-base"
|
||||
className="w-full flex items-center gap-2 px-3 py-2 text-sm text-red-600 hover:bg-base"
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
Удалить
|
||||
|
||||
@@ -121,7 +121,7 @@ export default function AdminSettingsPage() {
|
||||
|
||||
if (!settings || !features) {
|
||||
return (
|
||||
<div className="bg-red-500/10 text-red-400 p-4 rounded-lg">
|
||||
<div className="bg-red-500/10 text-red-600 p-4 rounded-lg">
|
||||
Не удалось загрузить настройки
|
||||
</div>
|
||||
);
|
||||
@@ -224,7 +224,7 @@ export default function AdminSettingsPage() {
|
||||
<button
|
||||
onClick={handleSaveGeneral}
|
||||
disabled={saving}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors disabled:opacity-50"
|
||||
className="flex items-center gap-2 px-4 py-2 bg-accent text-accent-foreground rounded-lg hover:bg-accent-hover transition-colors disabled:opacity-50"
|
||||
>
|
||||
<Save className="w-4 h-4" />
|
||||
{saving ? 'Сохранение...' : 'Сохранить'}
|
||||
@@ -252,7 +252,7 @@ export default function AdminSettingsPage() {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => toggleFeature(feature.key as keyof FeatureFlags)}
|
||||
className={features[feature.key as keyof FeatureFlags] ? 'text-green-400' : 'text-muted'}
|
||||
className={features[feature.key as keyof FeatureFlags] ? 'text-green-600' : 'text-muted'}
|
||||
>
|
||||
{features[feature.key as keyof FeatureFlags] ? (
|
||||
<ToggleRight className="w-8 h-8" />
|
||||
@@ -267,7 +267,7 @@ export default function AdminSettingsPage() {
|
||||
<button
|
||||
onClick={handleSaveFeatures}
|
||||
disabled={saving}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors disabled:opacity-50"
|
||||
className="flex items-center gap-2 px-4 py-2 bg-accent text-accent-foreground rounded-lg hover:bg-accent-hover transition-colors disabled:opacity-50"
|
||||
>
|
||||
<Save className="w-4 h-4" />
|
||||
{saving ? 'Сохранение...' : 'Сохранить'}
|
||||
@@ -345,7 +345,7 @@ export default function AdminSettingsPage() {
|
||||
<button
|
||||
onClick={handleSaveLLM}
|
||||
disabled={saving}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors disabled:opacity-50"
|
||||
className="flex items-center gap-2 px-4 py-2 bg-accent text-accent-foreground rounded-lg hover:bg-accent-hover transition-colors disabled:opacity-50"
|
||||
>
|
||||
<Save className="w-4 h-4" />
|
||||
{saving ? 'Сохранение...' : 'Сохранить'}
|
||||
@@ -397,7 +397,7 @@ export default function AdminSettingsPage() {
|
||||
...settings,
|
||||
searchSettings: { ...settings.searchSettings, safeSearch: !settings.searchSettings.safeSearch }
|
||||
})}
|
||||
className={settings.searchSettings.safeSearch ? 'text-green-400' : 'text-muted'}
|
||||
className={settings.searchSettings.safeSearch ? 'text-green-600' : 'text-muted'}
|
||||
>
|
||||
{settings.searchSettings.safeSearch ? (
|
||||
<ToggleRight className="w-8 h-8" />
|
||||
@@ -411,7 +411,7 @@ export default function AdminSettingsPage() {
|
||||
<button
|
||||
onClick={handleSaveSearch}
|
||||
disabled={saving}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors disabled:opacity-50"
|
||||
className="flex items-center gap-2 px-4 py-2 bg-accent text-accent-foreground rounded-lg hover:bg-accent-hover transition-colors disabled:opacity-50"
|
||||
>
|
||||
<Save className="w-4 h-4" />
|
||||
{saving ? 'Сохранение...' : 'Сохранить'}
|
||||
|
||||
@@ -44,7 +44,7 @@ function UserModal({ user, onClose, onSave }: UserModalProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
||||
<div className="fixed inset-0 bg-primary/25 backdrop-blur-sm flex items-center justify-center z-50">
|
||||
<div className="bg-surface rounded-xl p-6 w-full max-w-md">
|
||||
<h2 className="text-xl font-bold text-primary mb-4">
|
||||
{user ? 'Редактировать пользователя' : 'Новый пользователь'}
|
||||
@@ -117,7 +117,7 @@ function UserModal({ user, onClose, onSave }: UserModalProps) {
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="flex-1 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors"
|
||||
className="flex-1 px-4 py-2 bg-accent text-accent-foreground rounded-lg hover:bg-accent-hover transition-colors"
|
||||
>
|
||||
Сохранить
|
||||
</button>
|
||||
@@ -198,7 +198,7 @@ export default function AdminUsersPage() {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setModalUser(null)}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors"
|
||||
className="flex items-center gap-2 px-4 py-2 bg-accent text-accent-foreground rounded-lg hover:bg-accent-hover transition-colors"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Добавить
|
||||
@@ -263,8 +263,8 @@ export default function AdminUsersPage() {
|
||||
<td className="px-4 py-3">
|
||||
<span className={`inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs ${
|
||||
user.role === 'admin'
|
||||
? 'bg-purple-500/10 text-purple-400'
|
||||
: 'bg-blue-500/10 text-blue-400'
|
||||
? 'bg-purple-500/10 text-purple-600'
|
||||
: 'bg-blue-500/10 text-blue-600'
|
||||
}`}>
|
||||
{user.role === 'admin' && <Crown className="w-3 h-3" />}
|
||||
{user.role === 'admin' ? 'Админ' : 'Пользователь'}
|
||||
@@ -273,10 +273,10 @@ export default function AdminUsersPage() {
|
||||
<td className="px-4 py-3">
|
||||
<span className={`px-2 py-1 rounded-full text-xs ${
|
||||
user.tier === 'business'
|
||||
? 'bg-yellow-500/10 text-yellow-400'
|
||||
? 'bg-yellow-500/10 text-yellow-600'
|
||||
: user.tier === 'pro'
|
||||
? 'bg-green-500/10 text-green-400'
|
||||
: 'bg-gray-500/10 text-gray-400'
|
||||
? 'bg-green-500/10 text-green-600'
|
||||
: 'bg-surface text-muted'
|
||||
}`}>
|
||||
{user.tier.toUpperCase()}
|
||||
</span>
|
||||
@@ -284,8 +284,8 @@ export default function AdminUsersPage() {
|
||||
<td className="px-4 py-3">
|
||||
<span className={`inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs ${
|
||||
user.isActive
|
||||
? 'bg-green-500/10 text-green-400'
|
||||
: 'bg-red-500/10 text-red-400'
|
||||
? 'bg-green-500/10 text-green-600'
|
||||
: 'bg-red-500/10 text-red-600'
|
||||
}`}>
|
||||
{user.isActive ? <UserCheck className="w-3 h-3" /> : <UserX className="w-3 h-3" />}
|
||||
{user.isActive ? 'Активен' : 'Неактивен'}
|
||||
@@ -329,7 +329,7 @@ export default function AdminUsersPage() {
|
||||
handleDelete(user.id);
|
||||
setActiveMenu(null);
|
||||
}}
|
||||
className="w-full flex items-center gap-2 px-3 py-2 text-sm text-red-400 hover:bg-base"
|
||||
className="w-full flex items-center gap-2 px-3 py-2 text-sm text-red-600 hover:bg-base"
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
Удалить
|
||||
|
||||
@@ -241,7 +241,7 @@ export default function FinancePage() {
|
||||
</span>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
{sector.tickers.slice(0, 3).map((stock, i) => (
|
||||
{(sector.tickers ?? []).slice(0, 3).map((stock, i) => (
|
||||
<StockRow key={stock.symbol} stock={stock} market={currentMarket} delay={i * 0.02} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -80,9 +80,9 @@ const healthArticles: Article[] = [
|
||||
];
|
||||
|
||||
const quickServices = [
|
||||
{ icon: Stethoscope, label: 'Найти врача', color: 'bg-blue-500/10 text-blue-400' },
|
||||
{ icon: Pill, label: 'Справочник лекарств', color: 'bg-green-500/10 text-green-400' },
|
||||
{ icon: FileText, label: 'Анализы', color: 'bg-purple-500/10 text-purple-400' },
|
||||
{ icon: Stethoscope, label: 'Найти врача', color: 'bg-blue-500/10 text-blue-600' },
|
||||
{ icon: Pill, label: 'Справочник лекарств', color: 'bg-green-500/10 text-green-600' },
|
||||
{ icon: FileText, label: 'Анализы', color: 'bg-purple-500/10 text-purple-600' },
|
||||
{ icon: Sparkles, label: 'AI Консультант', color: 'active-gradient text-gradient' },
|
||||
];
|
||||
|
||||
@@ -159,9 +159,9 @@ export default function MedicinePage() {
|
||||
|
||||
{/* Disclaimer */}
|
||||
<div className="flex items-start gap-3 p-4 bg-amber-500/5 border border-amber-500/20 rounded-xl mb-6">
|
||||
<AlertTriangle className="w-5 h-5 text-amber-400 flex-shrink-0 mt-0.5" />
|
||||
<AlertTriangle className="w-5 h-5 text-amber-600 flex-shrink-0 mt-0.5" />
|
||||
<div>
|
||||
<p className="text-sm font-medium text-amber-400 mb-1">Важно</p>
|
||||
<p className="text-sm font-medium text-amber-600 mb-1">Важно</p>
|
||||
<p className="text-xs text-muted">
|
||||
Информация носит справочный характер и не заменяет консультацию врача.
|
||||
При серьёзных симптомах обратитесь к специалисту.
|
||||
@@ -236,7 +236,7 @@ export default function MedicinePage() {
|
||||
<div className="mb-6 sm:mb-8">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="w-9 h-9 rounded-xl bg-red-500/10 flex items-center justify-center">
|
||||
<HeartPulse className="w-4 h-4 text-red-400" />
|
||||
<HeartPulse className="w-4 h-4 text-red-600" />
|
||||
</div>
|
||||
<h2 className="text-sm font-medium text-primary">Частые симптомы</h2>
|
||||
</div>
|
||||
@@ -256,7 +256,7 @@ export default function MedicinePage() {
|
||||
<div className="mb-6">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="w-9 h-9 rounded-xl bg-green-500/10 flex items-center justify-center">
|
||||
<FileText className="w-4 h-4 text-green-400" />
|
||||
<FileText className="w-4 h-4 text-green-600" />
|
||||
</div>
|
||||
<h2 className="text-sm font-medium text-primary">Полезные статьи</h2>
|
||||
</div>
|
||||
@@ -271,8 +271,8 @@ export default function MedicinePage() {
|
||||
{/* Emergency Info */}
|
||||
<div className="bg-red-500/5 border border-red-500/20 rounded-xl p-4">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<AlertTriangle className="w-4 h-4 text-red-400" />
|
||||
<span className="text-sm font-medium text-red-400">Экстренная помощь</span>
|
||||
<AlertTriangle className="w-4 h-4 text-red-600" />
|
||||
<span className="text-sm font-medium text-red-600">Экстренная помощь</span>
|
||||
</div>
|
||||
<p className="text-sm text-muted mb-3">
|
||||
При угрозе жизни немедленно вызывайте скорую помощь
|
||||
@@ -280,13 +280,13 @@ export default function MedicinePage() {
|
||||
<div className="flex gap-3">
|
||||
<a
|
||||
href="tel:103"
|
||||
className="flex-1 h-10 flex items-center justify-center gap-2 bg-red-500/10 border border-red-500/30 text-red-400 font-medium text-sm rounded-lg hover:bg-red-500/20 transition-colors"
|
||||
className="flex-1 h-10 flex items-center justify-center gap-2 bg-red-500/10 border border-red-500/30 text-red-600 font-medium text-sm rounded-lg hover:bg-red-500/20 transition-colors"
|
||||
>
|
||||
📞 103
|
||||
</a>
|
||||
<a
|
||||
href="tel:112"
|
||||
className="flex-1 h-10 flex items-center justify-center gap-2 bg-red-500/10 border border-red-500/30 text-red-400 font-medium text-sm rounded-lg hover:bg-red-500/20 transition-colors"
|
||||
className="flex-1 h-10 flex items-center justify-center gap-2 bg-red-500/10 border border-red-500/30 text-red-600 font-medium text-sm rounded-lg hover:bg-red-500/20 transition-colors"
|
||||
>
|
||||
📞 112
|
||||
</a>
|
||||
|
||||
@@ -335,7 +335,7 @@ export default function SpaceDetailPage() {
|
||||
</span>
|
||||
<span className={`flex items-center gap-1 text-xs px-2 py-0.5 rounded-full ${
|
||||
member.role === 'owner'
|
||||
? 'bg-amber-500/20 text-amber-400'
|
||||
? 'bg-amber-500/15 text-amber-600'
|
||||
: member.role === 'admin'
|
||||
? 'bg-accent/20 text-accent'
|
||||
: 'bg-surface text-muted'
|
||||
@@ -394,7 +394,7 @@ export default function SpaceDetailPage() {
|
||||
{/* Invite Modal */}
|
||||
<Dialog.Root open={showInviteModal} onOpenChange={setShowInviteModal}>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay className="fixed inset-0 bg-black/60 backdrop-blur-sm z-50" />
|
||||
<Dialog.Overlay className="fixed inset-0 bg-primary/30 backdrop-blur-sm z-50" />
|
||||
<Dialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-md bg-elevated border border-border rounded-2xl p-6 z-50 shadow-2xl">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<Dialog.Title className="text-lg font-semibold text-primary">
|
||||
|
||||
@@ -105,7 +105,7 @@ export default function NewSpacePage() {
|
||||
`}
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-14 h-14 rounded-xl bg-white/10 backdrop-blur-sm flex items-center justify-center text-2xl">
|
||||
<div className="w-14 h-14 rounded-xl bg-surface/60 backdrop-blur-sm flex items-center justify-center text-2xl">
|
||||
{formData.icon}
|
||||
</div>
|
||||
<div>
|
||||
@@ -183,7 +183,7 @@ export default function NewSpacePage() {
|
||||
onClick={() => setFormData((f) => ({ ...f, color: color.id }))}
|
||||
className={`w-10 h-10 rounded-xl ${color.class} transition-all ${
|
||||
formData.color === color.id
|
||||
? 'ring-2 ring-white ring-offset-2 ring-offset-base'
|
||||
? 'ring-2 ring-accent ring-offset-2 ring-offset-base'
|
||||
: 'opacity-60 hover:opacity-100'
|
||||
}`}
|
||||
title={color.label}
|
||||
@@ -237,7 +237,7 @@ export default function NewSpacePage() {
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`absolute top-1 w-5 h-5 rounded-full bg-white shadow transition-transform ${
|
||||
className={`absolute top-1 w-5 h-5 rounded-full bg-elevated shadow transition-transform ${
|
||||
formData.isPublic ? 'translate-x-6' : 'translate-x-1'
|
||||
}`}
|
||||
/>
|
||||
|
||||
@@ -160,7 +160,7 @@ export default function SpacesPage() {
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-start justify-between mb-4">
|
||||
<div className="w-12 h-12 rounded-xl bg-white/10 backdrop-blur-sm flex items-center justify-center">
|
||||
<div className="w-12 h-12 rounded-xl bg-surface/60 backdrop-blur-sm flex items-center justify-center">
|
||||
<FolderOpen className="w-6 h-6 text-primary" />
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
@@ -173,7 +173,7 @@ export default function SpacesPage() {
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<button
|
||||
onClick={(e) => e.preventDefault()}
|
||||
className="p-1.5 hover:bg-white/10 rounded-lg transition-colors opacity-0 group-hover:opacity-100"
|
||||
className="p-1.5 hover:bg-surface/50 rounded-lg transition-colors opacity-0 group-hover:opacity-100"
|
||||
>
|
||||
<MoreHorizontal className="w-4 h-4 text-secondary" />
|
||||
</button>
|
||||
@@ -229,7 +229,7 @@ export default function SpacesPage() {
|
||||
|
||||
{/* Members avatars */}
|
||||
{space.members && space.members.length > 0 && (
|
||||
<div className="flex items-center gap-1 mt-4 pt-4 border-t border-white/10">
|
||||
<div className="flex items-center gap-1 mt-4 pt-4 border-t border-border/50">
|
||||
<div className="flex -space-x-2">
|
||||
{space.members.slice(0, 4).map((member, idx) => (
|
||||
<div
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user