главная страница

This commit is contained in:
sbb45
2026-05-22 15:16:04 +05:00
parent 5929d5862f
commit 8bda936c4b
22 changed files with 872 additions and 5 deletions
+2 -1
View File
@@ -22,7 +22,8 @@ export default defineConfig(
rules: { rules: {
// typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects. // typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects.
// see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors // see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors
'no-undef': 'off' 'no-undef': 'off',
'svelte/no-navigation-without-resolve': 'off'
} }
}, },
{ {
+4
View File
@@ -34,5 +34,9 @@
"typescript": "^6.0.2", "typescript": "^6.0.2",
"typescript-eslint": "^8.58.1", "typescript-eslint": "^8.58.1",
"vite": "^8.0.7" "vite": "^8.0.7"
},
"dependencies": {
"clsx": "^2.1.1",
"tailwind-merge": "^3.6.0"
} }
} }
+12
View File
@@ -7,6 +7,13 @@ settings:
importers: importers:
.: .:
dependencies:
clsx:
specifier: ^2.1.1
version: 2.1.1
tailwind-merge:
specifier: ^3.6.0
version: 3.6.0
devDependencies: devDependencies:
'@eslint/compat': '@eslint/compat':
specifier: ^2.0.4 specifier: ^2.0.4
@@ -1254,6 +1261,9 @@ packages:
resolution: {integrity: sha512-fTjjT8cHLDwigcu2j3pv7Jq04LklXevPB8uBgyHNiTXv+RMNvVnrjS4UEYrLMkhuq1vpCodHjiW+z/95SDs/fg==} resolution: {integrity: sha512-fTjjT8cHLDwigcu2j3pv7Jq04LklXevPB8uBgyHNiTXv+RMNvVnrjS4UEYrLMkhuq1vpCodHjiW+z/95SDs/fg==}
engines: {node: '>=18'} engines: {node: '>=18'}
tailwind-merge@3.6.0:
resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==}
tailwindcss@4.3.0: tailwindcss@4.3.0:
resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==}
@@ -2409,6 +2419,8 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- '@typescript-eslint/types' - '@typescript-eslint/types'
tailwind-merge@3.6.0: {}
tailwindcss@4.3.0: {} tailwindcss@4.3.0: {}
tapable@2.3.3: {} tapable@2.3.3: {}
+138
View File
@@ -0,0 +1,138 @@
<script lang="ts">
import { cn } from '$lib/utils';
type Direction = 'bull' | 'bear' | 'flat';
type Signal = {
sym: string;
dir: Direction;
conf: string;
entry: string;
tp: string;
sl: string;
};
type Level = { label: string; val: string; color: string };
const signals: Signal[] = [
{ sym: 'BTCUSDT', dir: 'bull', conf: '73%', entry: '103.4k', tp: '104.2k', sl: '102.8k' },
{ sym: 'ETHUSDT', dir: 'bear', conf: '68%', entry: '3.21k', tp: '3.08k', sl: '3.28k' },
{ sym: 'SOLUSDT', dir: 'bull', conf: '81%', entry: '178.2', tp: '183.5', sl: '175.0' },
{ sym: 'BNBUSDT', dir: 'flat', conf: '52%', entry: '612.4', tp: '618.0', sl: '608.0' },
{ sym: 'XRPUSDT', dir: 'bull', conf: '76%', entry: '0.614', tp: '0.641', sl: '0.598' },
{ sym: 'ADAUSDT', dir: 'bear', conf: '61%', entry: '0.482', tp: '0.461', sl: '0.494' }
];
const paths: Record<Direction, string> = {
bull: 'M 0 32 L 20 28 L 40 30 L 60 22 L 80 24 L 100 16 L 120 12 L 140 8 L 160 4',
bear: 'M 0 8 L 20 12 L 40 10 L 60 18 L 80 16 L 100 24 L 120 28 L 140 32 L 160 36',
flat: 'M 0 20 L 40 18 L 80 22 L 120 20 L 160 19'
};
const dirColor: Record<Direction, string> = {
bull: 'text-emerald-400',
bear: 'text-red-400',
flat: 'text-zinc-500'
};
const dirStroke: Record<Direction, string> = {
bull: '#34d399',
bear: '#f87171',
flat: '#71717a'
};
const dirBorder: Record<Direction, string> = {
bull: 'border-l-emerald-400',
bear: 'border-l-red-400',
flat: 'border-l-zinc-500'
};
const dirLabel: Record<Direction, string> = {
bull: '▲ LONG',
bear: '▼ SHORT',
flat: '— FLAT'
};
function getLevels(signal: Signal): Level[] {
return [
{ label: 'E', val: signal.entry, color: 'text-orange-400' },
{ label: 'TP', val: signal.tp, color: 'text-emerald-400' },
{ label: 'SL', val: signal.sl, color: 'text-red-400' }
];
}
</script>
<div class="w-full max-w-170 z-20" style="perspective: 1000px;">
<div
class="overflow-hidden rounded-2xl border border-white/10 bg-zinc-950 shadow-[0_40px_100px_rgba(0,0,0,0.7),0_0_0_1px_rgba(255,255,255,0.04)] will-change-transform"
style="transform: perspective(1000px) rotateY(-6deg) rotateX(3deg); transform-style: preserve-3d;"
>
<!-- Title bar -->
<div class="flex items-center justify-between border-b border-white/6 bg-white/2 px-4 py-2.5">
<div class="flex items-center gap-1.5">
<div class="h-2.5 w-2.5 rounded-full bg-[#ff5f57]"></div>
<div class="h-2.5 w-2.5 rounded-full bg-[#febc2e]"></div>
<div class="h-2.5 w-2.5 rounded-full bg-[#28c840]"></div>
</div>
<span class="font-mono text-[0.6rem] tracking-widest text-zinc-500">FLAMY TRADE</span>
</div>
<!-- Signal grid -->
<div class="grid grid-cols-2">
{#each signals as signal, i (signal.sym)}
<div
class={cn(
'border-l-[3px] p-3',
dirBorder[signal.dir],
i % 2 === 0 && 'border-r border-r-white/6',
i < 4 && 'border-b border-b-white/6'
)}
>
<!-- Header -->
<div class="mb-2 flex items-center justify-between">
<span class="font-display text-[0.6875rem] font-black tracking-tight text-zinc-100">
{signal.sym}
</span>
<div class="flex items-center gap-2">
<span class={cn('font-mono text-[0.5625rem]', dirColor[signal.dir])}>
{dirLabel[signal.dir]}
</span>
<span class="font-mono text-[0.5625rem] text-zinc-400">{signal.conf}</span>
</div>
</div>
<!-- Mini chart -->
<div class="relative mb-2 h-10 overflow-hidden rounded bg-white/2">
<svg
width="100%"
height="40"
viewBox="0 0 160 40"
preserveAspectRatio="none"
fill="none"
aria-hidden="true"
>
<path
d={paths[signal.dir]}
stroke={dirStroke[signal.dir]}
stroke-width="1.2"
fill="none"
/>
</svg>
</div>
<!-- Levels -->
<div class="flex gap-3">
{#each getLevels(signal) as level (level.label)}
<div class="flex flex-col gap-0.5">
<span class="font-mono text-[0.5rem] tracking-widest text-zinc-600"
>{level.label}</span
>
<span class={cn('font-mono text-[0.5625rem]', level.color)}>{level.val}</span>
</div>
{/each}
</div>
</div>
{/each}
</div>
</div>
</div>
+134
View File
@@ -0,0 +1,134 @@
<script lang="ts">
type Direction = 'bull' | 'bear' | 'flat';
type Signal = {
sym: string;
dir: Direction;
conf: number;
};
const signals: Signal[] = [
{ sym: 'BTCUSDT', dir: 'bull', conf: 73 },
{ sym: 'ETHUSDT', dir: 'bear', conf: 68 },
{ sym: 'SOLUSDT', dir: 'bull', conf: 81 },
{ sym: 'BNBUSDT', dir: 'flat', conf: 52 },
{ sym: 'XRPUSDT', dir: 'bull', conf: 76 },
{ sym: 'ADAUSDT', dir: 'bear', conf: 61 },
{ sym: 'DOGEUSDT', dir: 'bull', conf: 59 },
{ sym: 'LINKUSDT', dir: 'bear', conf: 64 }
];
const dirColor: Record<Direction, string> = {
bull: 'text-emerald-400',
bear: 'text-red-400',
flat: 'text-zinc-500'
};
const dirBorder: Record<Direction, string> = {
bull: 'border-l-emerald-400',
bear: 'border-l-red-400',
flat: 'border-l-zinc-500'
};
const dirStroke: Record<Direction, string> = {
bull: 'bg-emerald-400',
bear: 'bg-red-400',
flat: 'bg-zinc-500'
};
const dirBadgeBg: Record<Direction, string> = {
bull: 'bg-emerald-400/10',
bear: 'bg-red-400/10',
flat: 'bg-zinc-500/10'
};
const dirArrow: Record<Direction, string> = {
bull: '▲',
bear: '▼',
flat: '—'
};
const dirLabel: Record<Direction, string> = {
bull: 'BULL',
bear: 'BEAR',
flat: 'FLAT'
};
</script>
<div class="hidden h-full w-full max-w-140 items-center justify-end lg:flex z-20">
<div
class="w-full overflow-hidden rounded-2xl border border-white/8 bg-zinc-950 shadow-[0_0_0_1px_rgba(255,255,255,0.03),0_40px_80px_rgba(0,0,0,0.5),0_0_80px_rgba(255,69,0,0.05)]"
>
<div class="flex items-center justify-between border-b border-white/6 bg-white/2.5 px-4 py-3.5">
<div class="flex items-center gap-2">
<div class="flex gap-1.5">
<div class="h-2 w-2 rounded-full bg-[#ff5f57]"></div>
<div class="h-2 w-2 rounded-full bg-[#febc2e]"></div>
<div class="h-2 w-2 rounded-full bg-[#28c840]"></div>
</div>
<span class="font-mono text-[0.57rem] tracking-widest text-zinc-500">
FLAMY TRADE · СИГНАЛЫ
</span>
</div>
<div class="flex items-center gap-1.5">
<span class="inline-flex h-1.5 w-1.5 animate-ping rounded-full bg-emerald-400 opacity-75"
></span>
<span class="font-mono text-[0.57rem] tracking-widest text-emerald-400">LIVE</span>
</div>
</div>
<div
class="grid grid-cols-[1fr_56px_76px] gap-2.5 border-b border-white/6 bg-white/1 px-4 py-3.5"
>
<span class="font-mono text-[0.55rem] tracking-widest text-zinc-600">ИНСТРУМЕНТ</span>
<span class="text-right font-mono text-[0.55rem] tracking-widest text-zinc-600"
>КОНФИД.</span
>
<span class="pl-2 font-mono text-[0.55rem] tracking-widest text-zinc-600">ПРОГНОЗ</span>
</div>
{#each signals as signal, i (signal.sym)}
<div
class="grid grid-cols-[1fr_56px_76px] items-center gap-2.5 border-l-2 px-4 py-3 {dirBorder[
signal.dir
]} {i < signals.length - 1 ? 'border-b border-b-white/[0.06]' : ''}"
>
<span class="font-display text-[0.6875rem] font-black tracking-tight text-zinc-100">
{signal.sym}
</span>
<div class="flex flex-col items-end gap-1">
<span class="font-mono text-[0.5625rem] text-zinc-300">{signal.conf}%</span>
<div class="h-0.5 w-11 rounded-full bg-zinc-800">
<div
class="h-full rounded-full transition-[width] duration-300 {dirStroke[signal.dir]}"
style="width: {signal.conf}%"
></div>
</div>
</div>
<div class="inline-flex items-center gap-1 rounded px-2 py-0.5 {dirBadgeBg[signal.dir]}">
<span class="text-[0.5rem] leading-none {dirColor[signal.dir]}"
>{dirArrow[signal.dir]}</span
>
<span
class="font-mono text-[0.4375rem] font-semibold tracking-wider {dirColor[signal.dir]}"
>{dirLabel[signal.dir]}</span
>
</div>
</div>
{/each}
<div class="flex items-center justify-between border-t border-white/6 bg-white/1 px-4 py-2">
<span class="font-mono text-[0.6rem] tracking-wider text-zinc-600">
ГОРИЗОНТ 19 СВЕЧЕЙ · 5 Mоделей
</span>
<a
href="/dashboard"
class="font-mono text-[0.6rem] tracking-wider text-orange-400 transition-opacity duration-200 hover:opacity-70"
>
ВСЕ СИГНАЛЫ →
</a>
</div>
</div>
</div>
+77
View File
@@ -0,0 +1,77 @@
<script lang="ts">
const yr = new Date().getFullYear();
const navLinks = [
{ href: '/dashboard', label: 'Дашборд' },
{ href: '/blog', label: 'Блог' },
{ href: '/about', label: 'О проекте' }
];
</script>
<footer class="mt-auto border-t border-white/6 bg-bg-e">
<div class="mx-auto max-w-400 px-5 py-14 sm:px-10">
<div class="grid grid-cols-2 gap-10 sm:grid-cols-4">
<div class="col-span-2 flex flex-col gap-4 sm:col-span-1">
<a href="/" class="flex items-center gap-2.5 no-underline">
<svg width="24" height="24" viewBox="0 0 26 26" fill="none">
<rect width="26" height="26" rx="6" fill="rgba(255,69,0,0.08)" />
<path
d="M7 20 C7 20 9.5 13 13 15.5 C16.5 18 17 10 20 7"
stroke="#fe4b07"
stroke-width="1.8"
stroke-linecap="round"
stroke-linejoin="round"
fill="none"
/>
<circle cx="20" cy="7" r="1.6" fill="#fe4b07" />
</svg>
<span class="font-display text-sm font-black tracking-tighter">
FLAMY<span class="text-primary">TRADE</span>
</span>
</a>
<p class="max-w-[200px] text-[0.8125rem] leading-relaxed text-zinc-600">
ML-прогнозы для рыночных инструментов. Только исследования.
</p>
</div>
<div class="flex flex-col gap-3">
<span class="font-mono text-[0.6rem] tracking-widest text-zinc-600 uppercase">Навигация</span>
{#each navLinks as link}
<a
href={link.href}
class="text-[0.8125rem] text-desc no-underline transition-colors duration-150 hover:text-zinc-100"
>
{link.label}
</a>
{/each}
</div>
<div class="col-span-2 flex flex-col gap-3 sm:col-span-2">
<span class="font-mono text-[0.6rem] tracking-widest text-zinc-600 uppercase">Дисклеймер</span>
<p class="max-w-[380px] text-xs leading-relaxed text-zinc-600">
Материалы являются результатом работы исследовательской ML-модели и используются в
демонстрационных целях. Не являются индивидуальной инвестиционной рекомендацией.
</p>
</div>
</div>
<div
class="mt-10 flex flex-col items-start justify-between gap-2 border-t border-white/6 pt-8 sm:flex-row sm:items-center"
>
<span class="text-xs text-zinc-600">© {yr} Flamy Trade</span>
<span class="text-xs text-zinc-600">
implemented in
<a
href="https://flamy.studio"
target="_blank"
rel="noopener noreferrer"
class="text-desc no-underline transition-colors duration-150 hover:text-primary"
>
flamy studio
</a>
</span>
</div>
</div>
</footer>
+32
View File
@@ -0,0 +1,32 @@
<script lang="ts">
// Ссылки
import { cn } from '$lib/utils';
const menuLinks = [
{ id: 0, href: 'reg', text: 'Главная' },
{ id: 1, href: 'reg', text: 'О проекте' },
{ id: 2, href: 'reg', text: 'Блог' },
{ id: 3, href: 'reg', text: 'Открыть дашборд', isButton: true }
];
</script>
<header class="fixed right-0 left-0 border-b border-b-bg-h bg-bg-e py-5 z-9999">
<div class="mx-auto flex max-w-400 items-center justify-between">
<a href="/" class="font-display text-lg font-semibold uppercase">Flamy Trade</a>
<nav>
<ul class="flex items-center justify-center gap-5.5 transition-colors duration-300">
{#each menuLinks as link (link.id)}
<li>
<a
href={link.href}
class={cn('transition-colors duration-300', link.isButton ? 'nav-btn' : 'nav-link')}
>
{link.text}
</a>
</li>
{/each}
</ul>
</nav>
</div>
</header>
+31
View File
@@ -0,0 +1,31 @@
<script lang="ts">
import type { Snippet } from 'svelte';
import { cn } from '$lib/utils';
type Props = {
href?: string;
target?: string;
variant?: 'primary' | 'secondary';
children: Snippet;
};
let { href, target = '_self', variant = 'primary', children }: Props = $props();
</script>
<svelte:element
this={href ? 'a' : 'button'}
{href}
{target}
rel={target === '_blank' ? 'noopener noreferrer' : undefined}
class={cn(
'flex items-center justify-center gap-2 w-fit rounded-xl px-6 py-3 font-display text-lg font-medium transition-colors duration-300',
variant === 'primary' && 'bg-primary hover:bg-primary-h',
variant === 'secondary' && 'bg-bg border hover:text-desc'
)}
>
{@render children()}
{#if variant === 'primary'}
<img src="images/icons/arrow-right.svg" alt="Перейти" class="h-5 w-5" />
{/if}
</svelte:element>
+6
View File
@@ -0,0 +1,6 @@
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
+12
View File
@@ -0,0 +1,12 @@
<script>
import Button from '$lib/components/ui/Button.svelte';
</script>
<section class="flex h-screen items-center justify-center pt-16">
<h1
class="flex flex-col text-center font-display text-[110px] leading-[1.1] font-black uppercase"
>
Страница не найдена
<span class="text-[64px] leading-none text-primary"> Возможно стр </span>
</h1>
</section>
+15 -2
View File
@@ -1,9 +1,22 @@
<script lang="ts"> <script lang="ts">
import './layout.css'; import './layout.css';
import favicon from '$lib/assets/favicon.svg'; import Header from '$lib/components/layout/Header.svelte';
import Footer from '$lib/components/layout/Footer.svelte';
let { children } = $props(); let { children } = $props();
</script> </script>
<svelte:head><link rel="icon" href={favicon} /></svelte:head> <svelte:head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous" />
<link
href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Unbounded:wght@200..900&display=swap"
rel="stylesheet"
/>
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
</svelte:head>
<Header />
{@render children()} {@render children()}
<Footer />
+21 -2
View File
@@ -1,2 +1,21 @@
<h1>Welcome to SvelteKit</h1> <script lang="ts">
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p> import Hero from './_sections/Hero.svelte';
import Ticker from './_sections/Ticker.svelte';
import About from './_sections/About.svelte';
import Features from './_sections/Features.svelte';
import Stats from './_sections/Stats.svelte';
import BlogPreview from './_sections/BlogPreview.svelte';
import Cta from './_sections/Cta.svelte';
</script>
<main>
<Hero />
<Ticker />
<About />
<Features />
<Stats />
<BlogPreview posts={[]} />
<Cta />
<div class="noise"></div>
</main>
+35
View File
@@ -0,0 +1,35 @@
<script lang="ts">
import Button from '$lib/components/ui/Button.svelte';
import DashboardStatus from '$lib/components/DashboardStatus.svelte';
</script>
<div class="relative bg-bg-e">
<section class="flex h-[70vh] items-center justify-center gap-40">
<div>
<h2 class="font-display text-7xl font-bold">Дашборд</h2>
<p class="mt-8 max-w-140 text-xl text-desc">
Все инструменты одним взглядом. Интерактивные графики, уровни входа и выхода, статистика
winrate — доступно без регистрации.
</p>
<ul class="mt-6 mb-10 flex flex-col gap-1 text-xl text-desc">
<li class="flex items-center gap-2">
<span class="h-2 w-2 shrink-0 rounded-full bg-primary"></span>
Интерактивные свечные графики с прогнозом
</li>
<li class="flex items-center gap-2">
<span class="h-2 w-2 shrink-0 rounded-full bg-primary"></span>
Уровни Entry · TP · SL на каждом графике
</li>
<li class="flex items-center gap-2">
<span class="h-2 w-2 shrink-0 rounded-full bg-primary"></span>
Поиск и фильтрация по направлению
</li>
</ul>
<Button href="/dashboard">Перейти к дашборду</Button>
</div>
<DashboardStatus />
</section>
<div class="noise"></div>
</div>
+71
View File
@@ -0,0 +1,71 @@
<script lang="ts">
type Post = {
slug: string;
date: string;
title: string;
description: string;
tags?: string[];
};
let { posts = [] }: { posts: Post[] } = $props();
function fmtDate(d: string) {
try {
return new Intl.DateTimeFormat('ru', {
day: 'numeric',
month: 'short',
year: 'numeric'
}).format(new Date(d));
} catch {
return d;
}
}
</script>
{#if posts.length > 0}
<div class="border-b border-white/6">
<section class="px-5 py-24 sm:px-10 sm:py-32">
<div class="mb-12 flex items-end justify-between">
<h2 class="font-display text-4xl font-black uppercase tracking-tighter">БЛОГ</h2>
<a
href="/blog"
class="font-display text-[0.75rem] font-bold tracking-wider text-desc transition-colors duration-150 hover:text-white"
>
ВСЕ СТАТЬИ →
</a>
</div>
<div
class="grid grid-cols-1 overflow-hidden rounded-xl border border-white/6 sm:grid-cols-[repeat(auto-fit,minmax(20rem,1fr))]"
>
{#each posts as post, i}
<a
href="/blog/{post.slug}"
class="flex flex-col gap-5 p-10 no-underline transition-colors duration-150 hover:bg-white/2
{i > 0 ? 'border-t border-white/6 sm:border-t-0 sm:border-l' : ''}"
>
<div class="flex items-center justify-between">
<time datetime={post.date} class="font-mono text-[0.6875rem] tracking-widest text-zinc-600">
{fmtDate(post.date)}
</time>
{#if post.tags?.length}
<span class="font-mono text-[0.625rem] uppercase tracking-widest text-zinc-600">
{post.tags[0]}
</span>
{/if}
</div>
<h3
class="font-display font-black leading-tight tracking-tight text-[clamp(1.25rem,2.5vw,1.75rem)]"
>
{post.title}
</h3>
<p class="flex-1 text-sm leading-relaxed text-desc">{post.description}</p>
<span class="font-display text-[0.75rem] font-bold tracking-wider text-primary">
ЧИТАТЬ →
</span>
</a>
{/each}
</div>
</section>
</div>
{/if}
+26
View File
@@ -0,0 +1,26 @@
<script lang="ts">
import Button from '$lib/components/ui/Button.svelte';
</script>
<section class="flex flex-col items-center justify-center overflow-hidden px-5 py-36 text-center sm:px-10">
<div
class="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_100%_80%_at_50%_110%,rgba(255,69,0,0.12)_0%,transparent_65%)]"
></div>
<div
class="pointer-events-none absolute inset-0 opacity-10"
style="background-image: radial-gradient(circle, rgba(255,255,255,0.1) 1px, transparent 1px); background-size: 48px 48px; mask-image: radial-gradient(ellipse 70% 70% at 50% 50%, black 20%, transparent 80%);"
></div>
<div class="relative flex flex-col items-center gap-8">
<span class="font-mono text-[0.6875rem] tracking-widest text-primary">НАЧАТЬ</span>
<h2
class="font-display font-black uppercase leading-[0.9] tracking-tighter text-[clamp(4rem,10vw,9rem)]"
>
ОТКРОЙТЕ<br /><span class="text-primary">ДАШБОРД</span>
</h2>
<Button href="/dashboard">Открыть дашборд</Button>
<p class="max-w-[26rem] font-mono text-[0.6875rem] leading-relaxed text-zinc-600">
Материалы носят исследовательский характер. Не являются инвестиционными рекомендациями.
</p>
</div>
</section>
+67
View File
@@ -0,0 +1,67 @@
<script lang="ts">
type Feature = { num: string; title: string; desc: string };
const features: Feature[] = [
{
num: '01',
title: 'Интерактивные графики',
desc: 'Свечной график с историческими данными и прогнозной зоной. Zoom, pan, crosshair. Корректно работает на любом экране.'
},
{
num: '02',
title: 'Уровни TP и SL',
desc: 'Entry, Take Profit, Stop Loss — только когда модель уверена. Если данных нет, уровни не отображаются.'
},
{
num: '03',
title: 'История публикаций',
desc: 'До 20 дней назад. Выбор даты и времени из реально доступных публикаций. Сравнивайте прогнозы с реальными движениями.'
},
{
num: '04',
title: 'Версия модели',
desc: 'Каждая публикация помечена версией ML-модели, горизонтом и точным временем публикации.'
},
{
num: '05',
title: 'Статистика WR',
desc: 'Winrate, количество сделок и накопленная доходность по каждому инструменту — где API предоставляет данные.'
},
{
num: '06',
title: 'Блог и обучение',
desc: 'Гайды по чтению графиков, управлению рисками и интерпретации ML-прогнозов в формате статей.'
}
];
</script>
<div class="border-b border-white/6">
<section class="px-5 py-24 sm:px-10 sm:py-36">
<h2 class="mb-16 font-display text-4xl font-black uppercase tracking-tighter">ВОЗМОЖНОСТИ</h2>
<div class="border-t border-white/6">
{#each features as f}
<div
class="group cursor-default border-b border-white/6 py-6 transition-colors duration-150 hover:bg-primary/2.5
md:grid md:grid-cols-[80px_1fr_1fr] md:items-center md:gap-8 md:py-8"
>
<span
class="block font-display text-3xl font-black leading-none tracking-tighter text-primary opacity-20 transition-opacity duration-150 group-hover:opacity-100
md:text-[clamp(2rem,4vw,3.5rem)]"
>
{f.num}
</span>
<span
class="mt-1 block font-display text-xl font-bold tracking-tight
md:mt-0 md:text-[clamp(1rem,1.8vw,1.5rem)]"
>
{f.title}
</span>
<span class="mt-1 block text-sm leading-relaxed text-desc md:mt-0">
{f.desc}
</span>
</div>
{/each}
</div>
</section>
</div>
+33
View File
@@ -0,0 +1,33 @@
<script lang="ts">
import Button from '$lib/components/ui/Button.svelte';
import DashboardMockup from '$lib/components/DashboardMockup.svelte';
</script>
<section class="flex h-screen items-center justify-between pt-16">
<div style="transform: perspective(1000px) rotateY(6deg) rotateX(3deg); z-index: 20;">
<h1 class="flex flex-col font-display text-[100px] leading-[0.95] font-black uppercase">
<span> Рыночный </span>
<span class="text-[128px]"> прогноз </span>
<span class="text-[64px] leading-none text-primary"> от ML-модели </span>
</h1>
<p class="mt-10 max-w-180 text-2xl leading-[1.1] text-desc">
Исторические свечи, прогнозная зона, уровни входа и выхода — всё на одном интерактивном
графике. Горизонт 19 свечей, таймфрейм 5M.
</p>
<div class="mt-10 flex items-center justify-start gap-4">
<Button href="/dashboard">Открыть дашборд</Button>
<Button href="/about" variant="secondary">Как работает</Button>
</div>
</div>
<DashboardMockup />
<!-- Визуальные элементы -->
<span
class="absolute -top-60 left-0 z-0 h-80 w-full rotate-3 rounded-full bg-primary opacity-30 blur-[200px]"
></span>
<span class="absolute bottom-35 left-0 z-0 h-px w-full bg-bg-h"></span>
<span class="absolute top-55 left-0 z-0 h-px w-full bg-bg-h"></span>
</section>
+49
View File
@@ -0,0 +1,49 @@
<script lang="ts">
type Stat = { num: string; suffix: string; label: string; sub: string };
const stats: Stat[] = [
{ num: '19', suffix: '', label: 'ГОРИЗОНТ', sub: 'свечей вперёд' },
{ num: '5', suffix: 'M', label: 'ТАЙМФРЕЙМ', sub: 'минутные свечи' },
{ num: '24/7', suffix: '', label: 'ОБНОВЛЕНИЕ', sub: 'ежечасно' }
];
</script>
<div class="relative border-b border-white/6 bg-bg-e">
<div class="noise"></div>
<section class="px-5 py-24 sm:px-10 sm:py-32">
<div class="grid grid-cols-1 overflow-hidden rounded-xl border border-white/6 sm:grid-cols-3">
{#each stats as stat, i}
<div
class="relative overflow-hidden px-8 py-12 border-white/6 sm:px-14 sm:py-16
{i > 0 ? 'border-t sm:border-t-0 sm:border-l' : ''}"
>
<div
class="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_80%_60%_at_50%_100%,rgba(255,69,0,0.04)_0%,transparent_70%)]"
></div>
<div class="relative flex flex-col gap-3">
<div class="flex items-baseline gap-1">
<span
class="font-display font-black leading-none tracking-tighter text-[clamp(3.5rem,9vw,8rem)]"
>
{stat.num}
</span>
{#if stat.suffix}
<span
class="font-display font-black leading-none tracking-tighter text-primary text-[clamp(2rem,5vw,4rem)]"
>
{stat.suffix}
</span>
{/if}
</div>
<div class="flex flex-col gap-0.5">
<span class="font-mono text-[0.6875rem] tracking-widest text-primary">
{stat.label}
</span>
<span class="text-[0.8125rem] text-desc">{stat.sub}</span>
</div>
</div>
</div>
{/each}
</div>
</section>
</div>
+24
View File
@@ -0,0 +1,24 @@
<script lang="ts">
const items = [
'BTCUSDT',
'ETHUSDT',
'SOLUSDT',
'BNBUSDT',
'XRPUSDT',
'ML ПРОГНОЗ',
'FLAMY TRADE',
'ГОРИЗОНТ 19',
'ТАЙМФРЕЙМ 5M'
];
</script>
<div class="overflow-hidden border-y border-white/6 bg-bg-e py-2.5">
<div class="ticker-track flex whitespace-nowrap">
{#each [0, 1] as _}
{#each items as item}
<span class="px-8 font-mono text-[0.6875rem] tracking-widest text-zinc-500">{item}</span>
<span class="font-mono text-[0.6875rem] text-zinc-700 opacity-30">·</span>
{/each}
{/each}
</div>
</div>
+79
View File
@@ -1 +1,80 @@
@import 'tailwindcss'; @import 'tailwindcss';
@theme {
--font-display: 'Unbounded', sans-serif;
--font-sans: 'DM Sans', sans-serif;
--font-mono: 'JetBrains Mono', monospace;
--color-primary: #fe4b07;
--color-primary-h: #c83e06; /* hover */
--color-bg: #09080a;
--color-bg-e: #0f0e10; /* elevated */
--color-bg-c: #141318; /* card */
--color-bg-h: #1a191e; /* hover */
--color-title: #f0ede6;
--color-desc: #8a887f;
}
@layer base {
*,
*::before,
*::after {
box-sizing: border-box;
}
main {
overflow: hidden;
}
html {
background: #09080a;
color: #f0ede6;
font-family: var(--font-sans), sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
scroll-behavior: smooth;
}
::selection {
background: rgba(255, 69, 0, 0.5);
color: #f0ede6;
}
:focus-visible {
outline: 1px solid #ff4500;
outline-offset: 3px;
}
section {
@apply relative mx-auto max-w-400 min-h-175 max-h-300;
}
}
@layer utilities {
}
@keyframes ticker {
to {
transform: translateX(-50%);
}
}
@layer components {
.nav-btn {
@apply rounded-xl bg-primary px-5 py-3 font-display text-base font-normal hover:bg-primary-h;
}
.nav-link {
@apply font-display text-base font-normal hover:text-desc;
}
.noise {
pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
background-image: url('/images/noise.png');
background-repeat: repeat;
opacity: 0.14;
mix-blend-mode: screen;
}
.ticker-track {
animation: ticker 22s linear infinite;
}
}
+4
View File
@@ -0,0 +1,4 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.75 6H11.25" stroke="#F0EDE6" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 0.75L11.25 6L6 11.25" stroke="#F0EDE6" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB