124 lines
5.1 KiB
Swift
124 lines
5.1 KiB
Swift
import SwiftUI
|
||
|
||
// MARK: - Палитра
|
||
|
||
/// Фирменные цвета Rapira из дизайн-макета.
|
||
enum RapiraPalette {
|
||
// Рост
|
||
static let accent = Color(red: 0.251, green: 0.835, blue: 0.216) // #40D537
|
||
static let accentEdge = Color(red: 0.051, green: 0.157, blue: 0.082) // #0D2815
|
||
static let accentHalo = Color(red: 0.075, green: 0.214, blue: 0.106) // #13371B
|
||
static let accentText = Color(red: 0.277, green: 0.895, blue: 0.239) // #47E43D
|
||
|
||
// Падение — зеркальная красная гамма.
|
||
static let negative = Color(red: 0.949, green: 0.267, blue: 0.267) // #F24444
|
||
static let negativeEdge = Color(red: 0.161, green: 0.051, blue: 0.051)
|
||
static let negativeHalo = Color(red: 0.220, green: 0.075, blue: 0.075)
|
||
static let negativeText = Color(red: 0.965, green: 0.310, blue: 0.290)
|
||
|
||
// Фон и разделители
|
||
static let backgroundTint = Color(red: 0.157, green: 0.161, blue: 0.169) // #28292B
|
||
static let divider = Color.white.opacity(0.06)
|
||
|
||
// MARK: Выбор цвета по направлению движения
|
||
|
||
static func line(_ positive: Bool) -> Color { positive ? accent : negative }
|
||
static func lineEdge(_ positive: Bool) -> Color { positive ? accentEdge : negativeEdge }
|
||
static func halo(_ positive: Bool) -> Color { positive ? accentHalo : negativeHalo }
|
||
static func stat(_ positive: Bool) -> Color { positive ? accentText : negativeText }
|
||
}
|
||
|
||
// MARK: - Фон
|
||
|
||
/// Радиальный фон из макета: широкая подсветка от верхней кромки, уходящая
|
||
/// в чёрный на 61%. В исходнике это эллипс с радиусами 995×512 — отсюда
|
||
/// растяжение по горизонтали.
|
||
struct RapiraBackground: View {
|
||
var body: some View {
|
||
GeometryReader { geo in
|
||
RadialGradient(
|
||
gradient: Gradient(stops: [
|
||
.init(color: RapiraPalette.backgroundTint, location: 0),
|
||
.init(color: .black, location: 0.612),
|
||
]),
|
||
center: UnitPoint(x: 0.5, y: 0),
|
||
startRadius: 0,
|
||
endRadius: geo.size.height
|
||
)
|
||
.frame(width: geo.size.width, height: geo.size.height)
|
||
.scaleEffect(x: 1.94, y: 1, anchor: .top)
|
||
.clipped()
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - Логотип
|
||
|
||
/// Знак Rapira — две «ленты», кривые сняты с фирменного SVG
|
||
/// (34.7 × 32 в исходных координатах).
|
||
struct RapiraMark: View {
|
||
var size: CGFloat = 22
|
||
|
||
var body: some View {
|
||
ZStack {
|
||
MarkShape(part: .upper).fill(.white)
|
||
MarkShape(part: .lower).fill(.white.opacity(0.6))
|
||
}
|
||
.frame(width: size * (34.736 / 32.0), height: size)
|
||
}
|
||
|
||
private struct MarkShape: Shape {
|
||
enum Part { case upper, lower }
|
||
let part: Part
|
||
|
||
func path(in rect: CGRect) -> Path {
|
||
let sx = rect.width / 34.736
|
||
let sy = rect.height / 32.0
|
||
func p(_ x: CGFloat, _ y: CGFloat) -> CGPoint {
|
||
CGPoint(x: rect.minX + x * sx, y: rect.minY + y * sy)
|
||
}
|
||
|
||
var path = Path()
|
||
switch part {
|
||
case .upper:
|
||
path.move(to: p(15.545, 0))
|
||
path.addCurve(to: p(7.406, 6.217), control1: p(12.037, 0), control2: p(8.393, 2.783))
|
||
path.addLine(to: p(0, 31.996))
|
||
path.addLine(to: p(6.942, 31.996))
|
||
path.addLine(to: p(12.094, 14.062))
|
||
path.addCurve(to: p(20.233, 7.845), control1: p(13.081, 10.629), control2: p(16.725, 7.845))
|
||
path.addLine(to: p(32.482, 7.845))
|
||
path.addLine(to: p(34.736, 0))
|
||
case .lower:
|
||
path.move(to: p(31.083, 12.803))
|
||
path.addLine(to: p(27.464, 25.713))
|
||
path.addCurve(to: p(19.432, 32.0), control1: p(26.490, 29.186), control2: p(22.895, 32.0))
|
||
path.addLine(to: p(11.886, 32.0))
|
||
path.addLine(to: p(15.506, 19.090))
|
||
path.addCurve(to: p(23.537, 12.803), control1: p(16.479, 15.618), control2: p(20.075, 12.803))
|
||
path.addLine(to: p(31.083, 12.803))
|
||
}
|
||
path.closeSubpath()
|
||
return path
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - Цвета монет
|
||
|
||
/// Фолбэк-цвета для иконок монет, когда SVG с CDN недоступен.
|
||
enum CoinPalette {
|
||
static func color(for currency: String) -> Color {
|
||
switch currency {
|
||
case "BTC": .orange
|
||
case "ETH": Color(red: 0.39, green: 0.49, blue: 0.94)
|
||
case "SOL": Color(red: 0.56, green: 0.25, blue: 0.95)
|
||
case "BNB": Color(red: 0.96, green: 0.72, blue: 0.04)
|
||
case "XRP": Color(red: 0.14, green: 0.14, blue: 0.14)
|
||
case "TON": Color(red: 0.04, green: 0.65, blue: 0.93)
|
||
case "USDT": Color(red: 0.149, green: 0.631, blue: 0.482)
|
||
default: Color(red: 0.55, green: 0.55, blue: 0.60)
|
||
}
|
||
}
|
||
}
|