1
0
mirror of https://github.com/JKorf/CryptoExchange.Net.git synced 2026-08-12 17:03:10 +00:00

Compare commits

..

21 Commits

Author SHA1 Message Date
Jkorf d06f891cee Updated to version 12.2.0 2026-07-20 14:02:03 +02:00
Jkorf 8dcbb687f5 Fixed warning 2026-07-20 13:45:32 +02:00
Jan Korf fcb36f7ee0 Shared asset and symbol types
Added SpotSymbolCatalog to Shared ISpotSymbolRestClient interface
Added FuturesSymbolCatalog to Shared IFuturesSymbolRestClient interface
Added BaseAssetType, BaseAssetSubType, QuoteAssetType and QuoteAssetSubType to GetSymbolsRequest model
Added DisplayName to SharedSpotSymbol and SharedFuturesSymbol models
Added BaseAssetType, BaseAssetSubType, QuoteAssetType and QuoteAssetSubType to SharedSpotSymbol and SharedFuturesSymbol models
Added IsStableCoin, IsCommodity and IsEquity helper methods to LibraryHelpers
2026-07-20 13:40:58 +02:00
nils2525 3cffd67518 Fixed socket individual subscription target calculation (#282)
* Fixed socket individual subscription target calculation

* Fixed socket selection when the least-loaded connection has reached its individual subscription limit
2026-07-20 09:24:01 +02:00
Jkorf ecd00ea707 Added DebuggerDisplay attributes to Shared models 2026-07-14 09:59:02 +02:00
JKorf 38a7b981ce Updated to version 12.1.1 2026-07-11 15:34:31 +02:00
JKorf c41cc3c4c7 Added timestamp deserialization support for yyyy-MM-dd HH:mm:ss.ffffff+00:00:00 2026-07-11 15:19:02 +02:00
Jkorf 4accc8039b Updated to version 12.1.0 2026-07-09 15:06:09 +02:00
Jkorf 87c86ec0c0 Fixed nullability operator on Parameters.AddCommaSeperated 2026-07-09 08:35:39 +02:00
Jkorf d9850da282 Added ExchangeParameters parameter to KlineTracker, TradeTracker and ITrackerFactory methods 2026-07-08 12:00:26 +02:00
Jkorf c4a8b02054 Updated some testing logic 2026-07-02 14:09:55 +02:00
Jkorf 34b7258496 Updated to version 12.0.2 2026-07-01 13:19:57 +02:00
Jkorf 69099922c9 Updated test validation to output a list of issues instead of throwing on the first 2026-07-01 13:16:06 +02:00
Jkorf 64c1cd5fa8 Updated RestIntegrationTest to output missing properties in a list so the running test can output them as warning instead of error 2026-07-01 09:42:55 +02:00
JKorf 936ac6640b Cleanup 2026-06-30 19:22:54 +02:00
Jkorf 68ad9ae114 Fixed warnings in tests 2026-06-30 15:25:08 +02:00
Jkorf 6238c17471 Added skills hub reference 2026-06-30 15:01:54 +02:00
Jkorf 52e6fbfe47 Updated examples 2026-06-30 12:55:20 +02:00
Jkorf 4129622d71 Added Lighter ref 2026-06-29 16:07:25 +02:00
Jkorf 95e0aefb9f Updated to version 12.0.1 2026-06-29 11:33:33 +02:00
Jkorf dd1cefdc90 Fixed bug in bool converter 2026-06-29 11:20:06 +02:00
565 changed files with 952 additions and 116106 deletions
+8
View File
@@ -30,6 +30,14 @@ var ticker = await binance.GetSpotTickerAsync(new GetTickerRequest(symbol));
`SharedSymbol(TradingMode.Spot, "BTC", "USDT")` is portable. Each library translates to its native format internally. Don't pass raw strings like `"BTCUSDT"` to shared methods.
## Symbol metadata and catalogs
In 12.2.0, `SharedSpotSymbol` and `SharedFuturesSymbol` include `DisplayName` and base/quote asset classification through `SharedAssetType` (`Crypto`, `Fiat`, `TradFi`) and `SharedAssetSubType` (`StableCoin`, `Equity`, `Commodity`). Pass the matching base/quote filters to `GetSymbolsRequest` when discovery should return only a class of markets.
After calling `GetSpotSymbolsAsync`, `ISpotSymbolRestClient.SpotSymbolCatalog` maps asset and symbol names to shared metadata. `IFuturesSymbolRestClient.FuturesSymbolCatalog` works the same way after `GetFuturesSymbolsAsync`. Treat either property as unavailable before its corresponding request has populated the cache.
When implementing an exchange library, use `LibraryHelpers.IsStableCoin`, `IsCommodity`, and `IsEquity` only as best-effort classifiers and supply exchange-specific additions where needed.
## Result pattern
REST methods return `HttpResult<T>` and websocket subscription methods return `WebSocketResult<UpdateSubscription>`. Always check `.Success`. `.Exchange` property identifies which exchange responded — useful for logging.
+6
View File
@@ -24,6 +24,12 @@ var ticker = await binance.GetSpotTickerAsync(new GetTickerRequest(symbol));
Same code works on every exchange that implements the interface. Use `Task.WhenAll` for concurrent multi-exchange calls.
## Shared symbol metadata
CryptoExchange.Net 12.2.0 classifies the base and quote sides of `SharedSpotSymbol` and `SharedFuturesSymbol` with `SharedAssetType` (`Crypto`, `Fiat`, `TradFi`) and optional `SharedAssetSubType` (`StableCoin`, `Equity`, `Commodity`). The models also expose `DisplayName`. Use the corresponding base/quote fields on `GetSymbolsRequest` to filter symbol discovery.
`ISpotSymbolRestClient.SpotSymbolCatalog` is populated by `GetSpotSymbolsAsync`; `IFuturesSymbolRestClient.FuturesSymbolCatalog` is populated by `GetFuturesSymbolsAsync`. Do not assume a catalog is available before that request. For exchange-library implementations, `LibraryHelpers.IsStableCoin`, `IsCommodity`, and `IsEquity` offer best-effort classification and can be extended with exchange-specific values.
## Single-exchange code uses the exchange's own client
For Binance-only code, use `BinanceRestClient` directly (see Binance.Net repo `AGENTS.md`). SharedApis is for portability — use it when you need that.
+18
View File
@@ -67,6 +67,24 @@ var btcusdtPerp = new SharedSymbol(TradingMode.PerpetualLinear, "BTC", "USDT");
For exchanges that use exotic asset names, see the AssetAliases configuration.
## Symbol Metadata and Asset Classification
Since CryptoExchange.Net 12.2.0, shared symbol responses describe both sides of a market with `BaseAssetType`, `BaseAssetSubType`, `QuoteAssetType`, and `QuoteAssetSubType`. `SharedAssetType` distinguishes `Crypto`, `Fiat`, and `TradFi`; `SharedAssetSubType` distinguishes `StableCoin`, `Equity`, and `Commodity`. `SharedSpotSymbol` and `SharedFuturesSymbol` also expose `DisplayName`.
The same fields on `GetSymbolsRequest` filter spot or futures symbol discovery:
```csharp
var request = new GetSymbolsRequest(
baseAssetType: SharedAssetType.Crypto,
quoteAssetSubType: SharedAssetSubType.StableCoin);
var result = await symbolClient.GetSpotSymbolsAsync(request);
```
After calling `GetSpotSymbolsAsync` or `GetFuturesSymbolsAsync`, use the client's `SpotSymbolCatalog` or `FuturesSymbolCatalog` to look up normalized asset and symbol metadata by name. The catalog is unavailable until the corresponding symbol request has populated the cache.
For exchange-library implementations, `LibraryHelpers.IsStableCoin`, `IsCommodity`, and `IsEquity` provide best-effort classification of known assets and accept exchange-specific additions. These helpers are heuristics, not an exhaustive source of truth.
## Available Shared Interfaces
**REST:**
@@ -138,6 +138,68 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
Assert.That(socket2.Connected == false);
}
[TestCase()]
public async Task BatchedSubscription_Should_NotExceedIndividualCombineTarget()
{
// arrange
var client = new TestSocketClient(options =>
{
options.SocketSubscriptionsCombineTarget = 10;
options.SocketIndividualSubscriptionCombineTarget = 10;
});
TestHelpers.ConfigureSocketClient(client, "wss://localhost");
// act
await client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => { }, false, default, individualSubscriptionCount: 6);
TestHelpers.ConfigureSocketClient(client, "wss://localhost");
await client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => { }, false, default, individualSubscriptionCount: 6);
// assert
Assert.That(client.ApiClient1._socketConnections.Count == 2);
Assert.That(client.ApiClient1._socketConnections.Values.All(connection => connection.Subscriptions.Sum(subscription => subscription.IndividualSubscriptionCount) <= 10));
}
[TestCase()]
public async Task BatchedSubscription_FullIndividualConnection_Should_NotPreventEligibleConnectionReuse()
{
// arrange
var client = new TestSocketClient(options =>
{
options.SocketSubscriptionsCombineTarget = 5;
options.SocketIndividualSubscriptionCombineTarget = 10;
});
TestHelpers.ConfigureSocketClient(client, "wss://localhost");
await client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => { }, false, default);
await client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => { }, false, default);
TestHelpers.ConfigureSocketClient(client, "wss://localhost");
await client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => { }, false, default, individualSubscriptionCount: 10);
TestHelpers.ConfigureSocketClient(client, "wss://localhost");
// act
await client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => { }, false, default);
// assert
Assert.That(
client.ApiClient1._socketConnections.Count,
Is.EqualTo(2),
"The eligible connection should be reused instead of opening a new connection after selecting a full individual-subscription connection");
var fullConnection = client.ApiClient1._socketConnections.Values
.Single(connection => connection.Subscriptions.Sum(subscription => subscription.IndividualSubscriptionCount) == 10);
Assert.That(
fullConnection.UserSubscriptionCount,
Is.EqualTo(1),
"The full connection should not receive the normal subscription");
var eligibleConnection = client.ApiClient1._socketConnections.Values.Single(connection => connection != fullConnection);
Assert.That(
eligibleConnection.UserSubscriptionCount,
Is.EqualTo(3),
"The existing eligible connection should receive the normal subscription");
}
[TestCase()]
public async Task ErrorResponse_ShouldNot_ConfirmSubscription()
{
@@ -25,6 +25,17 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
Assert.That(output!.Value == expected);
}
[TestCase(1, true)]
[TestCase(2, true)]
[TestCase(0, false)]
[TestCase(-1, false)]
public void TestBoolConverterInts(int value, bool? expected)
{
var val = $"{value}";
var output = JsonSerializer.Deserialize<STJBoolObject>($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new TestSerializerContext()));
Assert.That(output!.Value == expected);
}
[TestCase("1", true)]
[TestCase("true", true)]
[TestCase("yes", true)]
@@ -15,6 +15,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
[TestCase("1620777600000")]
[TestCase("2021-05-12T00:00:00.000Z")]
[TestCase("2021-05-12T00:00:00.000000000Z")]
[TestCase("2021-05-12 00:00:00.000000+00:00:00")]
[TestCase("0.000000", true)]
[TestCase("0", true)]
[TestCase("", true)]
@@ -36,9 +36,13 @@ namespace CryptoExchange.Net.UnitTests.Implementations
protected override TestAuthenticationProvider CreateAuthenticationProvider(TestCredentials credentials) =>
new TestAuthenticationProvider(credentials);
public async Task<WebSocketResult<UpdateSubscription>> SubscribeToUpdatesAsync<T>(Action<DataEvent<T>> handler, bool subQuery, CancellationToken ct)
public async Task<WebSocketResult<UpdateSubscription>> SubscribeToUpdatesAsync<T>(Action<DataEvent<T>> handler, bool subQuery, CancellationToken ct, int individualSubscriptionCount = 1)
{
return await base.SubscribeAsync(new TestSubscription<T>(_logger, handler, subQuery, false), ct);
var subscription = new TestSubscription<T>(_logger, handler, subQuery, false)
{
IndividualSubscriptionCount = individualSubscriptionCount
};
return await base.SubscribeAsync(subscription, ct);
}
}
}
@@ -156,8 +156,9 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
MessageRouter = messageRouter;
}
#pragma warning disable CS0067 // The event is never used, but it's required by the interface
public event Action? OnMessageRouterUpdated;
#pragma warning restore CS0067
public bool Handle(string typeIdentifier, string? topicFilter, SocketConnection socketConnection, DateTime receiveTime, string? originalData, object result)
{
return true;
+27 -31
View File
@@ -679,45 +679,26 @@ namespace CryptoExchange.Net.Clients
&& (s.Authenticated == authenticated || !authenticated)
&& s.Connected).ToList();
SocketConnection? connection;
if (!dedicatedRequestConnection)
{
connection = socketQuery
.Where(s => !s.DedicatedRequestConnection.IsDedicatedRequestConnection)
.OrderBy(s => s.UserSubscriptionCount)
.FirstOrDefault();
}
else
bool maxConnectionsReached = _socketConnections.Count >= (ApiOptions.MaxSocketConnections ?? ClientOptions.MaxSocketConnections);
SocketConnection? connection = null;
if (dedicatedRequestConnection)
{
connection = socketQuery.Where(s => s.DedicatedRequestConnection.IsDedicatedRequestConnection).FirstOrDefault();
if (connection != null && !connection.DedicatedRequestConnection.Authenticated)
// Mark dedicated request connection as authenticated if the request is authenticated
connection.DedicatedRequestConnection.Authenticated = authenticated;
if (connection == null)
// Fall back to an existing connection if there is no dedicated request connection available
connection = socketQuery.OrderBy(s => s.UserSubscriptionCount).FirstOrDefault();
}
bool maxConnectionsReached = _socketConnections.Count >= (ApiOptions.MaxSocketConnections ?? ClientOptions.MaxSocketConnections);
if (connection == null)
// Use an eligible non-dedicated connection for subscriptions, or as fallback when no dedicated request connection is available
connection = socketQuery
.Where(s => !s.DedicatedRequestConnection.IsDedicatedRequestConnection)
.Where(s => IsConnectionEligible(s, individualSubscriptionCount, maxConnectionsReached))
.OrderBy(s => s.UserSubscriptionCount)
.FirstOrDefault();
if (connection != null)
{
bool lessThanBatchSubCombineTarget = connection.UserSubscriptionCount < ClientOptions.SocketSubscriptionsCombineTarget;
bool lessThanIndividualSubCombineTarget = connection.Subscriptions.Sum(x => x.IndividualSubscriptionCount) < ClientOptions.SocketIndividualSubscriptionCombineTarget;
if ((lessThanBatchSubCombineTarget && lessThanIndividualSubCombineTarget)
|| maxConnectionsReached)
{
// Use existing socket if it has less than target connections OR it has the least connections and we can't make new
// If there is a max subscriptions per connection limit also only use existing if the new subscription doesn't go over the limit
if (MaxIndividualSubscriptionsPerConnection == null)
return CallResult.Ok(connection);
var currentCount = connection.Subscriptions.Sum(x => x.IndividualSubscriptionCount);
if (currentCount + individualSubscriptionCount <= MaxIndividualSubscriptionsPerConnection)
return CallResult.Ok(connection);
}
}
return CallResult.Ok(connection);
if (maxConnectionsReached)
return CallResult.Fail<SocketConnection>(new InvalidOperationError("Max amount of socket connections reached"));
@@ -784,6 +765,21 @@ namespace CryptoExchange.Net.Clients
return CallResult.Ok(socketConnection);
}
private bool IsConnectionEligible(SocketConnection socketConnection, int individualSubscriptionCount, bool maxConnectionsReached)
{
var currentIndividualSubscriptionCount = socketConnection.Subscriptions.Sum(x => x.IndividualSubscriptionCount);
bool lessThanBatchSubCombineTarget = socketConnection.UserSubscriptionCount < ClientOptions.SocketSubscriptionsCombineTarget;
// Include the incoming batch so batched subscriptions cannot overshoot the configured socket target.
bool lessThanIndividualSubCombineTarget = currentIndividualSubscriptionCount + individualSubscriptionCount <= ClientOptions.SocketIndividualSubscriptionCombineTarget;
if ((!lessThanBatchSubCombineTarget || !lessThanIndividualSubCombineTarget)
&& !maxConnectionsReached)
return false;
return MaxIndividualSubscriptionsPerConnection == null
|| currentIndividualSubscriptionCount + individualSubscriptionCount <= MaxIndividualSubscriptionsPerConnection;
}
/// <summary>
/// Process an unhandled message
/// </summary>
@@ -59,7 +59,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
if (reader.TokenType == JsonTokenType.Number)
{
var number = reader.GetInt16();
if (number > 1)
if (number >= 1)
return true;
return false;
@@ -198,6 +198,9 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
return new DateTime(year, month, day, 0, 0, 0, DateTimeKind.Utc);
}
if (stringValue.EndsWith("+00:00:00"))
return DateTime.Parse(stringValue.Substring(0, stringValue.Length - 9), CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
return DateTime.Parse(stringValue, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
}
+3 -3
View File
@@ -6,9 +6,9 @@
<PackageId>CryptoExchange.Net</PackageId>
<Authors>JKorf</Authors>
<Description>CryptoExchange.Net is a base library which is used to implement different cryptocurrency (exchange) API's. It provides a standardized way of implementing different API's, which results in a very similar experience for users of the API implementations.</Description>
<PackageVersion>12.0.0</PackageVersion>
<AssemblyVersion>12.0.0</AssemblyVersion>
<FileVersion>12.0.0</FileVersion>
<PackageVersion>12.2.0</PackageVersion>
<AssemblyVersion>12.2.0</AssemblyVersion>
<FileVersion>12.2.0</FileVersion>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageTags>OKX;OKX.Net;Mexc;Mexc.Net;Kucoin;Kucoin.Net;Kraken;Kraken.Net;Huobi;Huobi.Net;CoinEx;CoinEx.Net;Bybit;Bybit.Net;Bitget;Bitget.Net;Bitfinex;Bitfinex.Net;Binance;Binance.Net;CryptoCurrency;CryptoCurrency Exchange;CryptoExchange.Net</PackageTags>
<RepositoryType>git</RepositoryType>
+71 -10
View File
@@ -33,7 +33,7 @@ namespace CryptoExchange.Net
if (keyedCache != null && DateTime.UtcNow - keyedCache.UpdateTime < TimeSpan.FromMinutes(60))
return;
exchangeInfo.Set(key, new ExchangeInfo(DateTime.UtcNow, updateData.ToDictionary(x => x.Name, x => x.SharedSymbol)));
exchangeInfo.Set(key, new ExchangeInfo(DateTime.UtcNow, updateData.ToDictionary(x => x.Name, x => x)));
}
/// <summary>
@@ -118,6 +118,22 @@ namespace CryptoExchange.Net
return exchangeInfo.ParseSymbol(key, symbolName);
}
/// <summary>
/// Get a symbol catalog for a specific exchange(topic) and environment. Only available if <see cref="UpdateSymbolInfo(string, string, string?, SharedSpotSymbol[])"/> has been called previously.
/// </summary>
/// <param name="exchange">Exchange name</param>
/// <param name="topicId">Id for the provided data</param>
/// <param name="environmentName">Trade environment</param>
/// <param name="key">Additional data set identification key</param>
public static SharedSymbolCatalog? GetSymbolCatalog(string exchange, string topicId, string environmentName, string? key)
{
var id = topicId + environmentName;
if (!_symbolInfos.TryGetValue(id, out var exchangeInfo))
return null;
return exchangeInfo.GetSymbolCatalog(exchange, key);
}
class ExchangeKeyedCache
{
private ExchangeInfo? _noKeyCache;
@@ -163,7 +179,7 @@ namespace CryptoExchange.Net
public SharedSymbol? ParseSymbol(string? key, string symbolName)
{
SharedSymbol? symbolInfo = null;
SharedSpotSymbol? symbolInfo = null;
if (key == null)
{
if (_noKeyCache != null)
@@ -173,7 +189,7 @@ namespace CryptoExchange.Net
return new SharedSymbol(symbolInfo.TradingMode, symbolInfo.BaseAsset, symbolInfo.QuoteAsset, symbolName)
{
DeliverTime = symbolInfo.DeliverTime
DeliverTime = (symbolInfo as SharedFuturesSymbol)?.DeliveryTime
};
}
@@ -183,7 +199,7 @@ namespace CryptoExchange.Net
{
return new SharedSymbol(symbolInfo.TradingMode, symbolInfo.BaseAsset, symbolInfo.QuoteAsset, symbolName)
{
DeliverTime = symbolInfo.DeliverTime
DeliverTime = (symbolInfo as SharedFuturesSymbol)?.DeliveryTime
};
}
}
@@ -199,7 +215,7 @@ namespace CryptoExchange.Net
{
return new SharedSymbol(symbolInfo.TradingMode, symbolInfo.BaseAsset, symbolInfo.QuoteAsset, symbolName)
{
DeliverTime = symbolInfo.DeliverTime
DeliverTime = (symbolInfo as SharedFuturesSymbol)?.DeliveryTime
};
}
@@ -265,7 +281,7 @@ namespace CryptoExchange.Net
{
return _noKeyCache.Symbols
.Where(x => x.Value.BaseAsset.Equals(baseAsset, StringComparison.InvariantCultureIgnoreCase))
.Select(x => x.Value)
.Select(x => x.Value.SharedSymbol)
.ToArray();
}
@@ -274,7 +290,7 @@ namespace CryptoExchange.Net
{
result.AddRange(cache.Symbols
.Where(x => x.Value.BaseAsset.Equals(baseAsset, StringComparison.InvariantCultureIgnoreCase))
.Select(x => x.Value));
.Select(x => x.Value.SharedSymbol));
}
return result.ToArray();
@@ -286,18 +302,63 @@ namespace CryptoExchange.Net
return exchangeInfo.Symbols
.Where(x => x.Value.BaseAsset.Equals(baseAsset, StringComparison.InvariantCultureIgnoreCase))
.Select(x => x.Value)
.Select(x => x.Value.SharedSymbol)
.ToArray();
}
internal SharedSymbolCatalog? GetSymbolCatalog(string exchange, string? key)
{
IEnumerable<SharedSpotSymbol> cachedSymbols;
if (key == null)
{
if (_noKeyCache != null)
cachedSymbols = _noKeyCache.Symbols.Values;
else
cachedSymbols = _keyedCache.Values.SelectMany(x => x.Symbols.Values);
}
else
{
if (!_keyedCache.TryGetValue(key, out var exchangeInfo) || exchangeInfo == null)
return null;
cachedSymbols = exchangeInfo.Symbols.Values;
}
var assets = new Dictionary<string, SharedAssetInfo>();
var symbols = new Dictionary<string, SharedSpotSymbol>();
foreach (var symbol in cachedSymbols)
{
if (!assets.TryGetValue(symbol.BaseAsset, out var baseAssetInfo))
{
baseAssetInfo = new SharedAssetInfo(symbol.BaseAsset, symbol.BaseAssetType, symbol.BaseAssetSubType);
assets.Add(symbol.BaseAsset, baseAssetInfo);
}
if (!assets.TryGetValue(symbol.QuoteAsset, out var quoteAssetInfo))
{
quoteAssetInfo = new SharedAssetInfo(symbol.QuoteAsset, symbol.QuoteAssetType, symbol.QuoteAssetSubType);
assets.Add(symbol.QuoteAsset, quoteAssetInfo);
}
symbols.Add(symbol.Name, symbol);
}
return new SharedSymbolCatalog
{
Exchange = exchange,
Assets = assets,
Symbols = symbols
};
}
}
class ExchangeInfo
{
public DateTime UpdateTime { get; set; }
public Dictionary<string, SharedSymbol> Symbols { get; set; }
public Dictionary<string, SharedSpotSymbol> Symbols { get; set; }
public ExchangeInfo(DateTime updateTime, Dictionary<string, SharedSymbol> symbols)
public ExchangeInfo(DateTime updateTime, Dictionary<string, SharedSpotSymbol> symbols)
{
UpdateTime = updateTime;
Symbols = symbols;
@@ -24,8 +24,9 @@ namespace CryptoExchange.Net.Interfaces
/// <param name="interval">Kline interval</param>
/// <param name="limit">The max amount of klines to retain</param>
/// <param name="period">The max period the data should be retained</param>
/// <param name="exchangeParameters">Exchange parameters</param>
/// <returns></returns>
IKlineTracker CreateKlineTracker(SharedSymbol symbol, SharedKlineInterval interval, int? limit = null, TimeSpan? period = null);
IKlineTracker CreateKlineTracker(SharedSymbol symbol, SharedKlineInterval interval, int? limit = null, TimeSpan? period = null, ExchangeParameters? exchangeParameters = null);
/// <summary>
/// Whether the factory supports creating a TradeTracker instance for this symbol
@@ -39,7 +40,8 @@ namespace CryptoExchange.Net.Interfaces
/// <param name="symbol">The symbol</param>
/// <param name="limit">The max amount of trades to retain</param>
/// <param name="period">The max period the data should be retained</param>
/// <param name="exchangeParameters">Exchange parameters</param>
/// <returns></returns>
ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null, TimeSpan? period = null);
ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null, TimeSpan? period = null, ExchangeParameters? exchangeParameters = null);
}
}
+118
View File
@@ -4,6 +4,8 @@ using CryptoExchange.Net.Objects.Options;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO.Pipelines;
using System.Linq;
using System.Net;
using System.Net.Http;
@@ -14,6 +16,61 @@ namespace CryptoExchange.Net
/// </summary>
public static class LibraryHelpers
{
private static readonly HashSet<string> _stableCoins = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
// USD
"USDT", "USDC", "DAI", "FDUSD", "USDE", "TUSD", "USDP", "PYUSD", "GUSD",
"USDD", "LUSD", "USDJ", "SUSD", "ZUSD", "BUSD", "USTC", "USDX", "USDK",
"CUSD", "USD1", "USD0", "XUSD", "BFUSD", "USDS", "RLUSD", "OUSD", "USDH",
"APXUSD", "USDQ", "USDPT", "FIDD", "AUSD",
// EUR
"EURS", "EURC", "EURI", "EURT", "AGEUR", "CEUR", "AEUR", "EURQ", "EUROP",
// Other
"CNYT", // CNY
"CREAL", "BRL1", // BRL
"XSGD", // SGD
"GYEN", // JPY
"KGST", // KGS
"QCAD", // CAD
"TGBP", // GBP
"AUDX", // AUD
"MXNB", // MXN
};
private static readonly HashSet<string> _commodities = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
// Metals
"XAU", "XAUT", "XAG", "XPT", "XPD", "COPPER", "PAXG", "XNI", "XCU", "XAL", "GOLD", "SILVER",
// Energy
"BZ", "NATGAS", "NGAS", "CL", "XTI", "UKOIL", "USOIL", "BRENTOIL"
};
private static readonly HashSet<string> _stocks = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
// Top stocks, will need to update periodically
"AAAU", "AADR", "AAPL", "ACWI", "ACWX", "AGG", "AMD", "AMLP", "AMZN", "ARKF",
"ARKG", "ARKK", "ARKQ", "ARKW", "AVGO", "BA", "BABA", "BND", "BNDX", "BOTZ",
"CIBR", "COIN", "DIA", "DIVB", "DVY", "EEM", "EFA", "EFAV", "ESGU", "EWG",
"EWJ", "EWT", "EWU", "EWW", "EWY", "EWZ", "FDN", "FEZ", "GLDM", "GOOGL",
"HDV", "HOOD", "HYG", "IAU", "IBB", "ICLN", "IEFA", "IEMG", "IGSB", "IJH",
"IJR", "INTC", "ITOT", "IUSB", "IUSG", "IUSV", "IWM", "IWO", "IWR", "IYR",
"JETS", "JPM", "LIT", "MCHI", "META", "MGK", "MSTR", "MTUM", "MU", "NET",
"NFLX", "NOBL", "NVDA", "OIH", "ORCL", "PAVE", "PBW", "PLTR", "QQQ", "QQQM",
"SCHB", "SCHD", "SCHF", "SCHG", "SCHH", "SCHV", "SCHX", "SKHY", "SPCX", "SPCXD",
"SPLG", "SPY", "SPYG", "SPYV", "SQQQ", "TSLA", "TSM", "TQQQ", "USMV", "VBR",
"VCIT", "VCSH", "VEA", "VEU", "VGIT", "VGK", "VGT", "VHT", "VIG", "VNQ",
"VOO", "VOT", "VTI", "VTV", "VUG", "VXUS", "XBI", "XLC", "XLE", "XLF",
"XLI", "XLK", "XLP", "XLU", "XLV", "XLY", "CSCO", "UBER", "MRVL", "RKLB",
"COHR", "SOXL", "HD", "DIS", "CBRS", "V", "BRKB", "FLNC", "LLY", "COST",
"ARM", "BMNR", "NBIS", "ASML", "AAOI", "GLW", "SHLD", "BE", "QNTX", "IBM",
"AMAT", "NOK", "ASTS", "BBX", "SLX", "SKHYNIX", "SAMSUNG", "HYUNDAI", "NVO",
"IREN", "ONDS", "CRM" , "VRT", "ZEST", "BTW", "HPE", "AXTI", "BX", "CRWD",
"CRDO", "NOW", "ZM", "DKNG", "RIVN", "URNM", "EBAY", "ADBE", "UVXY", "RDW",
"CIEN","PANW", "WIN", "PAYP", "HIMS", "CRWV", "QCOM", "LITE", "DRAM", "ANTHROPIC",
"OPENAI", "USAR", "BILL", "SNDK", "NASDAQ100", "SPX500", "BSB", "CRCL", "STRC",
"MSFT", "WDC"
};
private static ILogger? _staticLogger;
/// <summary>
/// Static logger
@@ -105,6 +162,67 @@ namespace CryptoExchange.Net
return _defaultClientReferences.TryGetValue(key, out var id) ? id : throw new KeyNotFoundException($"{exchange} not found in configuration");
}
/// <summary>
/// Check whether an asset is a known stablecoin. Note that this is not definitive, only large known stocks are checked
/// </summary>
/// <param name="asset">Asset name</param>
/// <param name="additionalStableCoins">Additional stablecoin names for the specific exchange</param>
public static bool IsStableCoin(string asset, params HashSet<string> additionalStableCoins)
{
if (string.IsNullOrEmpty(asset))
return false;
return _stableCoins.Contains(asset) || (additionalStableCoins != null && additionalStableCoins.Contains(asset, StringComparer.OrdinalIgnoreCase));
}
/// <summary>
/// Check whether an asset is a known commodity. Note that this is not definitive, only large known stocks are checked
/// </summary>
/// <param name="asset">Asset name</param>
/// <param name="additionalCommodities">Additional commodity names for the specific exchange</param>
public static bool IsCommodity(string asset, params HashSet<string> additionalCommodities)
{
if (string.IsNullOrEmpty(asset))
return false;
return _commodities.Contains(asset) || (additionalCommodities != null && additionalCommodities.Contains(asset, StringComparer.OrdinalIgnoreCase));
}
/// <summary>
/// Check whether an asset is a known stock. Note that this is not definitive, only large known stocks are checked
/// </summary>
/// <param name="asset">Asset name</param>
/// <param name="additionalStocks">Additional stock names for the specific exchange</param>
public static bool IsEquity(string asset, params HashSet<string> additionalStocks)
=> IsEquity(asset, [], additionalStocks);
/// <summary>
/// Check whether an asset is a known stock.
/// </summary>
/// <param name="asset">Asset name</param>
/// <param name="potentialSuffixes">Suffixes to check, for example when `X` is a potential suffix both `TSLA` and `TSLAX` will be checked</param>
/// <param name="additionalStocks">Additional stock names for the specific exchange</param>
public static bool IsEquity(string asset, string[] potentialSuffixes, params HashSet<string> additionalStocks)
{
if (string.IsNullOrEmpty(asset))
return false;
if (_stocks.Contains(asset) || (additionalStocks != null && additionalStocks.Contains(asset, StringComparer.OrdinalIgnoreCase)))
return true;
foreach (var suffix in potentialSuffixes)
{
if (!asset.EndsWith(suffix))
continue;
var suffixAsset = asset.Substring(0, asset.Length - suffix.Length);
if (_stocks.Contains(suffixAsset) || (additionalStocks != null && additionalStocks.Contains(suffixAsset, StringComparer.OrdinalIgnoreCase)))
return true;
}
return false;
}
/// <summary>
/// Create a new HttpMessageHandler instance
/// </summary>
+1 -1
View File
@@ -233,7 +233,7 @@ namespace CryptoExchange.Net.Objects
/// Add key as comma separated values
/// </summary>
#if NET5_0_OR_GREATER
public void AddCommaSeparated<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, IEnumerable<T> values)
public void AddCommaSeparated<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, IEnumerable<T>? values)
#else
public void AddCommaSeparated<T>(string key, IEnumerable<T>? values)
#endif
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Asset type
/// </summary>
public enum SharedAssetType
{
/// <summary>
/// Unknown or unspecified asset type
/// </summary>
Unspecified,
/// <summary>
/// Cryptocurrency asset type
/// </summary>
Crypto,
/// <summary>
/// Fiat currency asset type
/// </summary>
Fiat,
/// <summary>
/// Traditional finance asset type
/// </summary>
TradFi
}
/// <summary>
/// Asset sub type
/// </summary>
public enum SharedAssetSubType
{
// --- Crypto sub types ---
/// <summary>
/// Stable coin, can be for different fiat currencies
/// </summary>
StableCoin,
// --- TradFi sub types ---
/// <summary>
/// Equity, can be stocks, ETFs, or indices
/// </summary>
Equity,
/// <summary>
/// Commodity, can be oil, gas, metals, etc.
/// </summary>
Commodity
}
}
@@ -9,6 +9,11 @@ namespace CryptoExchange.Net.SharedApis
/// </summary>
public interface IFuturesSymbolRestClient : ISharedClient
{
/// <summary>
/// Get the futures symbol catalog. Only available if <see cref="GetFuturesSymbolsAsync(GetSymbolsRequest, CancellationToken)"/> has been called previously.
/// </summary>
SharedSymbolCatalog? FuturesSymbolCatalog { get; }
/// <summary>
/// Futures symbol request options.<br />
/// Use <see cref="EndpointOptions.RequiredExchangeParameters"/> and <see cref="EndpointOptions.OptionalExchangeParameters"/> to check for required and optional parameters for the request. <br />
@@ -9,6 +9,11 @@ namespace CryptoExchange.Net.SharedApis
/// </summary>
public interface ISpotSymbolRestClient : ISharedClient
{
/// <summary>
/// Get the spot symbol catalog. Only available if <see cref="GetSpotSymbolsAsync(GetSymbolsRequest, CancellationToken)"/> has been called previously.
/// </summary>
SharedSymbolCatalog? SpotSymbolCatalog { get; }
/// <summary>
/// Spot symbols request options.<br />
/// Use <see cref="EndpointOptions.RequiredExchangeParameters"/> and <see cref="EndpointOptions.OptionalExchangeParameters"/> to check for required and optional parameters for the request. <br />
@@ -1,4 +1,5 @@
using System;
using CryptoExchange.Net.Objects;
using System;
using System.Collections.Generic;
using System.Text;
@@ -15,5 +16,43 @@ namespace CryptoExchange.Net.SharedApis
public GetFuturesSymbolsOptions(string exchange, bool authenticated) : base(exchange, authenticated, nameof(IFuturesSymbolRestClient.GetFuturesSymbolsAsync))
{
}
/// <inheritdoc />
public override Error? ValidateRequest(GetSymbolsRequest request, IFuturesSymbolRestClient client)
{
if (request.BaseAssetType != null && request.BaseAssetSubType != null)
{
var error = ValidateAssetTypeCombination(request.BaseAssetType.Value, request.BaseAssetSubType.Value);
if (error != null)
return error;
}
if (request.QuoteAssetType != null && request.QuoteAssetSubType != null)
{
var error = ValidateAssetTypeCombination(request.QuoteAssetType.Value, request.QuoteAssetSubType.Value);
if (error != null)
return error;
}
return base.ValidateRequest(request, client);
}
private Error? ValidateAssetTypeCombination(SharedAssetType type, SharedAssetSubType subType)
{
if (type == SharedAssetType.Crypto
&& (subType == SharedAssetSubType.Commodity
|| (subType == SharedAssetSubType.Equity)))
{
return ArgumentError.Invalid(nameof(GetSymbolsRequest.BaseAssetSubType), $"Invalid combination of asset type filters: {type} and {subType}");
}
if (type == SharedAssetType.TradFi && subType == SharedAssetSubType.StableCoin)
return ArgumentError.Invalid(nameof(GetSymbolsRequest.BaseAssetSubType), $"Invalid combination of asset type filters: {type} and {subType}");
if (type == SharedAssetType.Fiat)
return ArgumentError.Invalid(nameof(GetSymbolsRequest.BaseAssetSubType), $"Invalid combination of asset type filters: {type} and {subType}");
return null;
}
}
}
@@ -1,4 +1,5 @@
using System;
using CryptoExchange.Net.Objects;
using System;
using System.Collections.Generic;
using System.Text;
@@ -15,5 +16,44 @@ namespace CryptoExchange.Net.SharedApis
public GetSpotSymbolsOptions(string exchange, bool authenticated) : base(exchange, authenticated, nameof(ISpotSymbolRestClient.GetSpotSymbolsAsync))
{
}
/// <inheritdoc />
public override Error? ValidateRequest(GetSymbolsRequest request, ISpotSymbolRestClient client)
{
if (request.BaseAssetType != null && request.BaseAssetSubType != null)
{
var error = ValidateAssetTypeCombination(request.BaseAssetType.Value, request.BaseAssetSubType.Value);
if (error != null)
return error;
}
if (request.QuoteAssetType != null && request.QuoteAssetSubType != null)
{
var error = ValidateAssetTypeCombination(request.QuoteAssetType.Value, request.QuoteAssetSubType.Value);
if (error != null)
return error;
}
return base.ValidateRequest(request, client);
}
private Error? ValidateAssetTypeCombination(SharedAssetType type, SharedAssetSubType subType)
{
if (type == SharedAssetType.Crypto
&& (subType == SharedAssetSubType.Commodity
|| (subType == SharedAssetSubType.Equity)))
{
return ArgumentError.Invalid(nameof(GetSymbolsRequest.BaseAssetSubType), $"Invalid combination of asset type filters: {type} and {subType}");
}
if (type == SharedAssetType.TradFi && subType == SharedAssetSubType.StableCoin)
return ArgumentError.Invalid(nameof(GetSymbolsRequest.BaseAssetSubType), $"Invalid combination of asset type filters: {type} and {subType}");
if (type == SharedAssetType.Fiat)
return ArgumentError.Invalid(nameof(GetSymbolsRequest.BaseAssetSubType), $"Invalid combination of asset type filters: {type} and {subType}");
return null;
}
}
}
@@ -5,13 +5,44 @@
/// </summary>
public record GetSymbolsRequest : SharedRequest
{
/// <summary>
/// Base asset type filter
/// </summary>
public SharedAssetType? BaseAssetType { get; }
/// <summary>
/// Base asset subtype filter
/// </summary>
public SharedAssetSubType? BaseAssetSubType { get; }
/// <summary>
/// Quote asset type filter
/// </summary>
public SharedAssetType? QuoteAssetType { get; }
/// <summary>
/// Quote asset subtype filter
/// </summary>
public SharedAssetSubType? QuoteAssetSubType { get; }
/// <summary>
/// ctor
/// </summary>
/// <param name="tradingMode">Trading mode filter</param>
/// <param name="baseAssetType">Filter by base asset type</param>
/// <param name="baseAssetSubType">Filter by base asset subtype</param>
/// <param name="quoteAssetType">Filter by quote asset type</param>
/// <param name="quoteAssetSubType">Filter by quote asset subtype</param>
/// <param name="exchangeParameters">Exchange specific parameters</param>
public GetSymbolsRequest(TradingMode? tradingMode = null, ExchangeParameters? exchangeParameters = null) : base(tradingMode, exchangeParameters)
public GetSymbolsRequest(
TradingMode? tradingMode = null,
SharedAssetType? baseAssetType = null,
SharedAssetSubType? baseAssetSubType = null,
SharedAssetType? quoteAssetType = null,
SharedAssetSubType? quoteAssetSubType = null,
ExchangeParameters? exchangeParameters = null) : base(tradingMode, exchangeParameters)
{
BaseAssetType = baseAssetType;
BaseAssetSubType = baseAssetSubType;
QuoteAssetType = quoteAssetType;
QuoteAssetSubType = quoteAssetSubType;
}
}
}
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Symbol and asset catalog for a shared client
/// </summary>
public class SharedSymbolCatalog
{
/// <summary>
/// Exchange name
/// </summary>
public string Exchange { get; set; } = string.Empty;
/// <summary>
/// Assets supported
/// </summary>
public IReadOnlyDictionary<string, SharedAssetInfo> Assets { get; set; } = new Dictionary<string, SharedAssetInfo>();
/// <summary>
/// Symbols supported
/// </summary>
public IReadOnlyDictionary<string, SharedSpotSymbol> Symbols { get; set; } = new Dictionary<string, SharedSpotSymbol>();
}
/// <summary>
/// Asset info
/// </summary>
[DebuggerDisplay("{DebugView,nq}")]
public class SharedAssetInfo
{
private string DebugView => $"{Name} - {Type}{(SubType == null ? "": $" {SubType}")}";
/// <summary>
/// Asset name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Asset type
/// </summary>
public SharedAssetType Type { get; set; }
/// <summary>
/// Asset sub type
/// </summary>
public SharedAssetSubType? SubType { get; set; }
/// <summary>
/// ctor
/// </summary>
public SharedAssetInfo(string name, SharedAssetType type, SharedAssetSubType? subType)
{
Name = name;
Type = type;
SubType = subType;
}
}
}
@@ -1,10 +1,12 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Asset info
/// </summary>
[DebuggerDisplay("{Name,nq} - {Networks.Length} network(s)")]
public record SharedAsset
{
/// <summary>
@@ -32,6 +34,7 @@ namespace CryptoExchange.Net.SharedApis
/// <summary>
/// Asset network info
/// </summary>
[DebuggerDisplay("{Name,nq}")]
public record SharedAssetNetwork
{
/// <summary>
@@ -1,8 +1,11 @@
namespace CryptoExchange.Net.SharedApis
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Balance info
/// </summary>
[DebuggerDisplay("{Available} {Asset, nq}")]
public record SharedBalance
{
/// <summary>
@@ -1,8 +1,11 @@
namespace CryptoExchange.Net.SharedApis
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Book ticker
/// </summary>
[DebuggerDisplay("{Symbol,nq} - {BestBidPrice} / {BestAskPrice}")]
public record SharedBookTicker : SharedSymbolModel
{
/// <summary>
@@ -1,10 +1,12 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Deposit info
/// </summary>
[DebuggerDisplay("[{Timestamp}] {Quantity} {Asset,nq}")]
public record SharedDeposit
{
/// <summary>
@@ -1,8 +1,11 @@
namespace CryptoExchange.Net.SharedApis
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Deposit address info
/// </summary>
[DebuggerDisplay("{Asset,nq} - {Address,nq}")]
public record SharedDepositAddress
{
/// <summary>
@@ -1,8 +1,11 @@
namespace CryptoExchange.Net.SharedApis
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Trading fee info
/// </summary>
[DebuggerDisplay("{MakerFee} / {TakerFee}")]
public record SharedFee
{
/// <summary>
@@ -1,10 +1,12 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Funding rate
/// </summary>
[DebuggerDisplay("[{Timestamp}] {FundingRate}")]
public record SharedFundingRate
{
/// <summary>
@@ -1,10 +1,12 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Mark/index price kline
/// </summary>
[DebuggerDisplay("[{OpenTime}] O: {OpenPrice} H: {HighPrice} L: {LowPrice} C: {ClosePrice}")]
public record SharedFuturesKline : SharedSymbolModel
{
/// <summary>
@@ -1,12 +1,19 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Futures order info
/// </summary>
[DebuggerDisplay("{DebugView,nq}")]
public record SharedFuturesOrder : SharedSymbolModel
{
private string DebugView =>
$"[{CreateTime}] {OrderId} {(PositionSide != null ? $"{PositionSide} " : "")}{Symbol} - " +
$"{OrderType} {Side} {OrderQuantity}{(OrderPrice != null ? " @ " + OrderPrice : "")}, " +
$"{Status}{(QuantityFilled != null && Status != SharedOrderStatus.Canceled ? $" {QuantityFilled}" : "")}{(AveragePrice != null ? " @ " + AveragePrice : "")}";
/// <summary>
/// Id of the order
/// </summary>
@@ -1,12 +1,17 @@
using System;
using System.Diagnostics;
using System.Drawing;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Futures symbol info
/// </summary>
[DebuggerDisplay("{DebugView,nq}")]
public record SharedFuturesSymbol : SharedSpotSymbol
{
private string DebugView => $"{TradingMode} {(DisplayName ?? Name)} - {BaseAssetType}{(BaseAssetSubType == null ? "" : " " + BaseAssetSubType)}{(DeliveryTime != null ? $" Delivery: {DeliveryTime:yyyy-MM-dd}": "")}";
/// <summary>
/// The size of a single contract
/// </summary>
@@ -1,10 +1,12 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Futures ticker info
/// </summary>
[DebuggerDisplay("{Symbol,nq} High: {HighPrice}, Low: {LowPrice}, Last: {LastPrice}, Change: {ChangePercentage}%")]
public record SharedFuturesTicker: SharedSymbolModel
{
/// <summary>
@@ -1,10 +1,12 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Kline info
/// </summary>
[DebuggerDisplay("[{OpenTime}] O: {OpenPrice} H: {HighPrice} L: {LowPrice} C: {ClosePrice} V: {Volume}")]
public record SharedKline : SharedSymbolModel
{
/// <summary>
@@ -1,10 +1,12 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Position info
/// </summary>
[DebuggerDisplay("{Symbol,nq} {PositionSide}: {PositionSize} {AverageOpenPrice}")]
public record SharedPosition : SharedSymbolModel
{
/// <summary>
@@ -1,10 +1,12 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Position history
/// </summary>
[DebuggerDisplay("[{Timestamp}] {Symbol,nq} {PositionSide}: {RealizedPnl}")]
public record SharedPositionHistory : SharedSymbolModel
{
/// <summary>
@@ -1,12 +1,19 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Spot order info
/// </summary>
[DebuggerDisplay("{DebugView,nq}")]
public record SharedSpotOrder : SharedSymbolModel
{
private string DebugView =>
$"[{CreateTime}] {OrderId} {Symbol} - " +
$"{OrderType} {Side} {OrderQuantity}{(OrderPrice != null ? " @ " + OrderPrice : "")}, " +
$"{Status}{(QuantityFilled != null && Status != SharedOrderStatus.Canceled ? $" {QuantityFilled}" : "")}{(AveragePrice != null ? " @ " + AveragePrice : "")}";
/// <summary>
/// The id of the order
/// </summary>
@@ -1,10 +1,17 @@
namespace CryptoExchange.Net.SharedApis
using System;
using System.Data;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Symbol info
/// </summary>
[DebuggerDisplay("{DebugView,nq}")]
public record SharedSpotSymbol
{
private string DebugView => $"{TradingMode} {(DisplayName ?? Name)} - {BaseAssetType} {BaseAssetSubType}";
/// <summary>
/// The trading mode of the symbol
/// </summary>
@@ -22,6 +29,10 @@
/// </summary>
public string Name { get; set; }
/// <summary>
/// The display name of the symbol
/// </summary>
public string? DisplayName { get; set; }
/// <summary>
/// Minimal quantity of an order in the base asset
/// </summary>
public decimal? MinTradeQuantity { get; set; }
@@ -57,6 +68,22 @@
/// Whether the symbol is currently available for trading
/// </summary>
public bool Trading { get; set; }
/// <summary>
/// Base asset type
/// </summary>
public SharedAssetType BaseAssetType { get; set; }
/// <summary>
/// Base asset sub type
/// </summary>
public SharedAssetSubType? BaseAssetSubType { get; set; }
/// <summary>
/// Quote asset type
/// </summary>
public SharedAssetType QuoteAssetType { get; set; }
/// <summary>
/// Quote asset sub type
/// </summary>
public SharedAssetSubType? QuoteAssetSubType { get; set; }
/// <summary>
/// ctor
@@ -1,8 +1,11 @@
namespace CryptoExchange.Net.SharedApis
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Ticker info
/// </summary>
[DebuggerDisplay("{Symbol,nq} High: {HighPrice}, Low: {LowPrice}, Last: {LastPrice}, Change: {ChangePercentage}%")]
public record SharedSpotTicker: SharedSymbolModel
{
/// <summary>
@@ -1,10 +1,12 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Public trade info
/// </summary>
[DebuggerDisplay("[{Timestamp}] {Symbol,nq} {Side.ToString(),nq} {Quantity} @ {Price}")]
public record SharedTrade : SharedSymbolModel
{
/// <summary>
@@ -1,10 +1,12 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// A user trade
/// </summary>
[DebuggerDisplay("[{Timestamp}] {Id,nq} {Symbol,nq} {Side.ToString(),nq} {Quantity} @ {Price}")]
public record SharedUserTrade : SharedSymbolModel
{
/// <summary>
@@ -1,10 +1,12 @@
using System;
using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// A withdrawal record
/// </summary>
[DebuggerDisplay("[{Timestamp}] {Quantity} {Asset,nq}")]
public record SharedWithdrawal
{
/// <summary>
@@ -1,4 +1,5 @@
using CryptoExchange.Net.Converters.SystemTextJson;
using System.Text;
using System.Text.Json.Serialization;
namespace CryptoExchange.Net.SharedApis
@@ -35,6 +36,33 @@ namespace CryptoExchange.Net.SharedApis
QuantityInQuoteAsset = quoteAssetQuantity;
QuantityInContracts = contractQuantity;
}
/// <inheritdoc />
public override string ToString()
{
var sb = new StringBuilder("[");
if (QuantityInBaseAsset != null)
sb.Append($"{QuantityInBaseAsset} base");
if (QuantityInQuoteAsset != null)
{
if (sb.Length > 1)
sb.Append(", ");
sb.Append($"{QuantityInQuoteAsset} quote");
}
if (QuantityInContracts != null)
{
if (sb.Length > 1)
sb.Append(", ");
sb.Append($"{QuantityInContracts} contracts");
}
sb.Append("]");
return sb.ToString();
}
}
/// <summary>
@@ -53,6 +81,9 @@ namespace CryptoExchange.Net.SharedApis
/// </summary>
public SharedQuantity() : base(null, null, null) { }
/// <inheritdoc />
public override string ToString() => base.ToString();
/// <summary>
/// Specify quantity in base asset
/// </summary>
@@ -123,5 +154,8 @@ namespace CryptoExchange.Net.SharedApis
: base(baseAssetQuantity, quoteAssetQuantity, contractQuantity)
{
}
/// <inheritdoc />
public override string ToString() => base.ToString();
}
}
@@ -1,5 +1,6 @@
using CryptoExchange.Net.Objects;
using System.Collections.Generic;
using System.Linq;
namespace CryptoExchange.Net.SharedApis
{
@@ -176,5 +177,24 @@ namespace CryptoExchange.Net.SharedApis
return result.ToArray();
}
/// <summary>
/// Apply symbols request filter for asset type and trading mode
/// </summary>
public static T[] ApplySymbolFilter<T>(T[] symbols, GetSymbolsRequest request) where T : SharedSpotSymbol
{
IEnumerable<T> resultData = symbols;
if (request.TradingMode != null)
resultData = resultData.Where(x => x.TradingMode == request.TradingMode);
if (request.BaseAssetType != null)
resultData = resultData.Where(x => x.BaseAssetType == request.BaseAssetType);
if (request.QuoteAssetType != null)
resultData = resultData.Where(x => x.QuoteAssetType == request.QuoteAssetType);
if (request.BaseAssetSubType != null)
resultData = resultData.Where(x => x.BaseAssetSubType == request.BaseAssetSubType);
if (request.QuoteAssetSubType != null)
resultData = resultData.Where(x => x.QuoteAssetSubType == request.QuoteAssetSubType);
return resultData.ToArray();
}
}
}
@@ -8,6 +8,7 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using CryptoExchange.Net.Converters;
using CryptoExchange.Net.Converters.SystemTextJson;
using CryptoExchange.Net.Testing.Exceptions;
#pragma warning disable IL2026
#pragma warning disable IL2070
@@ -18,7 +19,7 @@ namespace CryptoExchange.Net.Testing.Comparers
{
internal class SystemTextJsonComparer
{
internal static void CompareData(
internal static List<Exception> CompareData(
string method,
object? resultData,
string json,
@@ -26,6 +27,7 @@ namespace CryptoExchange.Net.Testing.Comparers
List<string>? ignoreProperties = null,
bool userSingleArrayItem = false)
{
var outputExceptions = new List<Exception>();
var jsonObject = JsonDocument.Parse(json).RootElement;
if (nestedJsonProperty != null)
{
@@ -46,10 +48,10 @@ namespace CryptoExchange.Net.Testing.Comparers
if (resultData == null)
{
if (jsonObject.ValueKind == JsonValueKind.Null)
return;
return outputExceptions;
if (jsonObject.ValueKind == JsonValueKind.Object && jsonObject.GetPropertyCount() == 0)
return;
return outputExceptions;
throw new Exception("ResultData null");
}
@@ -61,13 +63,16 @@ namespace CryptoExchange.Net.Testing.Comparers
foreach (var dictProp in jObj.EnumerateObject())
{
if (!dict.Contains(dictProp.Name))
throw new Exception($"{method}: Dictionary has no value for {dictProp.Name} while input json `{dictProp.Name}` has value {dictProp.Value}");
{
outputExceptions.Add(new Exception($"{method}: Dictionary has no value for {dictProp.Name} while input json `{dictProp.Name}` has value {dictProp.Value}"));
continue;
}
if (dictProp.Value.ValueKind == JsonValueKind.Object)
{
// TODO Some additional checking for objects
foreach (var prop in dictProp.Value.EnumerateObject())
CheckObject(method, prop, dict[dictProp.Name]!, ignoreProperties!);
CheckObject(method, prop, dict[dictProp.Name]!, ignoreProperties!, outputExceptions);
}
else
{
@@ -77,7 +82,8 @@ namespace CryptoExchange.Net.Testing.Comparers
continue;
// Property value not correct
throw new Exception($"{method}: Dictionary entry `{dictProp.Name}` has no value while input json has value {dictProp.Value}");
outputExceptions.Add(new Exception($"{method}: Dictionary entry `{dictProp.Name}` has no value while input json has value {dictProp.Value}"));
continue;
}
}
}
@@ -99,7 +105,7 @@ namespace CryptoExchange.Net.Testing.Comparers
{
if (ignoreProperties?.Contains(subProp.Name) == true)
continue;
CheckObject(method, subProp, enumerator.Current, ignoreProperties!);
CheckObject(method, subProp, enumerator.Current, ignoreProperties!, outputExceptions);
}
}
else if (jObj.ValueKind == JsonValueKind.Array)
@@ -121,7 +127,7 @@ namespace CryptoExchange.Net.Testing.Comparers
{
var arrayProp = resultProps.Where(p => p.Item2 != null).FirstOrDefault(p => p.Item2!.Index == i).p;
if (arrayProp != null)
CheckPropertyValue(method, item.Value, arrayProp.GetValue(resultObj), arrayProp.PropertyType, arrayProp.Name, "Array index " + i, ignoreProperties!);
CheckPropertyValue(method, item.Value, arrayProp.GetValue(resultObj), arrayProp.PropertyType, arrayProp.Name, "Array index " + i, ignoreProperties!, outputExceptions);
i++;
}
}
@@ -129,7 +135,10 @@ namespace CryptoExchange.Net.Testing.Comparers
{
var value = enumerator.Current;
if (value == default && jObj.ValueKind != JsonValueKind.Null)
throw new Exception($"{method}: Array has no value while input json array has value {jObj}");
{
outputExceptions.Add(new Exception($"{method}: Array has no value while input json array has value {jObj}"));
continue;
}
}
}
}
@@ -141,7 +150,7 @@ namespace CryptoExchange.Net.Testing.Comparers
{
var arrayProp = resultProps.Where(p => p.Item2 != null).FirstOrDefault(p => p.Item2!.Index == i).p;
if (arrayProp != null)
CheckPropertyValue(method, item, arrayProp.GetValue(resultData), arrayProp.PropertyType, arrayProp.Name, "Array index " + i, ignoreProperties!);
CheckPropertyValue(method, item, arrayProp.GetValue(resultData), arrayProp.PropertyType, arrayProp.Name, "Array index " + i, ignoreProperties!, outputExceptions);
i++;
}
}
@@ -155,7 +164,7 @@ namespace CryptoExchange.Net.Testing.Comparers
if (ignoreProperties?.Contains(item.Name) == true)
continue;
CheckObject(method, item, resultData, ignoreProperties);
CheckObject(method, item, resultData, ignoreProperties, outputExceptions);
//}
}
}
@@ -165,9 +174,10 @@ namespace CryptoExchange.Net.Testing.Comparers
}
Debug.WriteLine($"Successfully validated {method}");
return outputExceptions.Distinct().ToList();
}
private static void CheckObject(string method, JsonProperty prop, object obj, List<string>? ignoreProperties)
private static void CheckObject(string method, JsonProperty prop, object obj, List<string>? ignoreProperties, List<Exception> outputExceptions)
{
var publicProperties = obj.GetType().GetProperties(
System.Reflection.BindingFlags.Public
@@ -190,8 +200,11 @@ namespace CryptoExchange.Net.Testing.Comparers
property ??= resultProperties.SingleOrDefault(p => p.p.Name == prop.Name).p;
if (property is null)
{
// Property not found
throw new Exception($"{method}: Missing property `{prop.Name}` on `{obj.GetType().Name}`");
outputExceptions.Add(new MissingPropertyException(method, obj.GetType().Name, prop.Name, prop.Value.ValueKind == JsonValueKind.Null ? "[null]" : prop.Value.ToString()));
return;
}
var getMethod = property.GetGetMethod();
if (getMethod is null)
@@ -199,10 +212,18 @@ namespace CryptoExchange.Net.Testing.Comparers
return;
var propertyValue = property.GetValue(obj);
CheckPropertyValue(method, prop.Value, propertyValue, property.PropertyType, property.Name, prop.Name, ignoreProperties);
CheckPropertyValue(method, prop.Value, propertyValue, property.PropertyType, property.Name, prop.Name, ignoreProperties, outputExceptions);
}
private static void CheckPropertyValue(string method, JsonElement propValue, object? propertyValue, Type propertyType, string? propertyName = null, string? propName = null, List<string>? ignoreProperties = null)
private static void CheckPropertyValue(
string method,
JsonElement propValue,
object? propertyValue,
Type propertyType,
string? propertyName,
string? propName,
List<string>? ignoreProperties,
List<Exception> outputExceptions)
{
if (propertyValue == default && propValue.ValueKind != JsonValueKind.Null && !string.IsNullOrEmpty(propValue.ToString()))
{
@@ -211,7 +232,10 @@ namespace CryptoExchange.Net.Testing.Comparers
// Property value not correct
if (propValue.ToString() != "0")
throw new Exception($"{method}: Property `{propertyName}` has no value while input json `{propName}` has value {propValue}");
{
outputExceptions.Add(new Exception($"{method}: Property `{propertyName}` has no value while input json `{propName}` has value {propValue}"));
return;
}
}
if ((propertyValue == default && (propValue.ValueKind == JsonValueKind.Null || string.IsNullOrEmpty(propValue.ToString()))) || propValue.ToString() == "0")
@@ -223,17 +247,23 @@ namespace CryptoExchange.Net.Testing.Comparers
foreach (var dictProp in propValue.EnumerateObject())
{
if (!dict.Contains(dictProp.Name))
throw new Exception($"{method}: Property `{propertyName}` has no value while input json `{propName}` has value {propValue}");
{
outputExceptions.Add(new Exception($"{method}: Property `{propertyName}` has no value while input json `{propName}` has value {propValue}"));
continue;
}
if (dictProp.Value.ValueKind == JsonValueKind.Object)
{
CheckPropertyValue(method, dictProp.Value, dict[dictProp.Name]!, dict[dictProp.Name]!.GetType(), null, null, ignoreProperties);
CheckPropertyValue(method, dictProp.Value, dict[dictProp.Name]!, dict[dictProp.Name]!.GetType(), null, null, ignoreProperties, outputExceptions);
}
else
{
if (dict[dictProp.Name] == default && dictProp.Value.ValueKind != JsonValueKind.Null)
{
// Property value not correct
throw new Exception($"{method}: Dictionary entry `{dictProp.Name}` has no value while input json has value {propValue} for");
outputExceptions.Add(new Exception($"{method}: Dictionary entry `{dictProp.Name}` has no value while input json has value {propValue} for"));
continue;
}
}
}
}
@@ -263,7 +293,7 @@ namespace CryptoExchange.Net.Testing.Comparers
if (ignoreProperties?.Contains(subProp.Name) == true)
continue;
CheckObject(method, subProp, enumerator.Current, ignoreProperties);
CheckObject(method, subProp, enumerator.Current, ignoreProperties, outputExceptions);
}
}
else if (jToken.ValueKind == JsonValueKind.Array)
@@ -281,7 +311,7 @@ namespace CryptoExchange.Net.Testing.Comparers
{
var arrayProp = resultProps.Where(p => p.Item2 != null).FirstOrDefault(p => p.Item2!.Index == i).p;
if (arrayProp != null)
CheckPropertyValue(method, item, arrayProp.GetValue(resultObj), arrayProp.PropertyType, arrayProp.Name, "Array index " + i, ignoreProperties);
CheckPropertyValue(method, item, arrayProp.GetValue(resultObj), arrayProp.PropertyType, arrayProp.Name, "Array index " + i, ignoreProperties, outputExceptions);
i++;
}
@@ -290,9 +320,12 @@ namespace CryptoExchange.Net.Testing.Comparers
{
var value = enumerator.Current;
if (value == default && jToken.ValueKind != JsonValueKind.Null)
throw new Exception($"{method}: Property `{propertyName}` has no value while input json `{propName}` has value {jToken}");
{
outputExceptions.Add(new Exception($"{method}: Property `{propertyName}` has no value while input json `{propName}` has value {jToken}"));
return;
}
CheckValues(method, propertyName!, propertyType, jToken, value!);
CheckValues(method, propertyName!, propertyType, jToken, value!, outputExceptions);
}
}
}
@@ -307,7 +340,7 @@ namespace CryptoExchange.Net.Testing.Comparers
if (ignoreProperties?.Contains(item.Name) == true)
continue;
CheckObject(method, item, propertyValue, ignoreProperties);
CheckObject(method, item, propertyValue, ignoreProperties, outputExceptions);
//}
}
}
@@ -328,7 +361,7 @@ namespace CryptoExchange.Net.Testing.Comparers
{
if (ignoreProperties?.Contains(subProp.Name) == true)
continue;
CheckObject(method, subProp, enumerator.Current, ignoreProperties!);
CheckObject(method, subProp, enumerator.Current, ignoreProperties!, outputExceptions);
}
}
else if (jObj.ValueKind == JsonValueKind.Array)
@@ -346,7 +379,7 @@ namespace CryptoExchange.Net.Testing.Comparers
{
var arrayProp = resultProps.SingleOrDefault(p => p.Item2!.Index == i).p;
if (arrayProp != null)
CheckPropertyValue(method, item, arrayProp.GetValue(resultObj), arrayProp.PropertyType, arrayProp.Name, "Array index " + i, ignoreProperties!);
CheckPropertyValue(method, item, arrayProp.GetValue(resultObj), arrayProp.PropertyType, arrayProp.Name, "Array index " + i, ignoreProperties!, outputExceptions);
i++;
}
}
@@ -354,7 +387,10 @@ namespace CryptoExchange.Net.Testing.Comparers
{
var value = enumerator.Current;
if (value == default && jObj.ValueKind != JsonValueKind.Null)
throw new Exception($"{method}: Array has no value while input json array has value {jObj}");
{
outputExceptions.Add(new Exception($"{method}: Array has no value while input json array has value {jObj}"));
continue;
}
}
}
}
@@ -366,19 +402,19 @@ namespace CryptoExchange.Net.Testing.Comparers
{
var arrayProp = resultProps.Where(p => p.Item2 != null).FirstOrDefault(p => p.Item2!.Index == i).p;
if (arrayProp != null)
CheckPropertyValue(method, item, arrayProp.GetValue(propertyValue), arrayProp.PropertyType, arrayProp.Name, "Array index " + i, ignoreProperties!);
CheckPropertyValue(method, item, arrayProp.GetValue(propertyValue), arrayProp.PropertyType, arrayProp.Name, "Array index " + i, ignoreProperties!, outputExceptions);
i++;
}
}
}
else
{
CheckValues(method, propertyName!, propertyType, propValue, propertyValue);
CheckValues(method, propertyName!, propertyType, propValue, propertyValue, outputExceptions);
}
}
}
private static void CheckValues(string method, string property, Type propertyType, JsonElement jsonValue, object objectValue)
private static void CheckValues(string method, string property, Type propertyType, JsonElement jsonValue, object objectValue, List<Exception> outputExceptions)
{
if (jsonValue.ValueKind == JsonValueKind.String)
{
@@ -386,19 +422,19 @@ namespace CryptoExchange.Net.Testing.Comparers
if (objectValue is decimal dec)
{
if (ExchangeHelpers.ParseDecimal(stringValue!) != dec)
throw new Exception($"{method}: {property} not equal: {stringValue} vs {dec}");
outputExceptions.Add(new Exception($"{method}: {property} not equal: {stringValue} vs {dec}") );
}
else if (objectValue is DateTime time)
{
if (!string.IsNullOrEmpty(stringValue) && time != DateTimeConverter.ParseFromString(stringValue!, null))
throw new Exception($"{method}: {property} not equal: {stringValue} vs {time}");
outputExceptions.Add(new Exception($"{method}: {property} not equal: {stringValue} vs {time}"));
}
else if (objectValue is bool bl)
{
if (bl && (stringValue != "1" && stringValue != "true" && stringValue != "True" && stringValue != "yes" && stringValue != "YES" && stringValue != "enabled"))
throw new Exception($"{method}: {property} not equal: {stringValue} vs {bl}");
outputExceptions.Add(new Exception($"{method}: {property} not equal: {stringValue} vs {bl}"));
if (!bl && (stringValue != "0" && stringValue != "-1" && stringValue != "false" && stringValue != "False" && stringValue != "no" && stringValue != "NO" && stringValue != "disabled"))
throw new Exception($"{method}: {property} not equal: {stringValue} vs {bl}");
outputExceptions.Add(new Exception($"{method}: {property} not equal: {stringValue} vs {bl}") );
}
else if (propertyType.IsEnum || Nullable.GetUnderlyingType(propertyType)?.IsEnum == true)
{
@@ -406,7 +442,7 @@ namespace CryptoExchange.Net.Testing.Comparers
}
else if (!stringValue!.Equals(Convert.ToString(objectValue, CultureInfo.InvariantCulture), StringComparison.InvariantCultureIgnoreCase))
{
throw new Exception($"{method}: {property} not equal: {stringValue} vs {objectValue}");
outputExceptions.Add(new Exception($"{method}: {property} not equal: {stringValue} vs {objectValue}"));
}
}
else if (jsonValue.ValueKind == JsonValueKind.Number)
@@ -415,7 +451,7 @@ namespace CryptoExchange.Net.Testing.Comparers
if (objectValue is DateTime time)
{
if (time != DateTimeConverter.ParseFromDecimal(value))
throw new Exception($"{method}: {property} not equal: {DateTimeConverter.ParseFromDouble((double)value!)} vs {time}");
outputExceptions.Add(new Exception($"{method}: {property} not equal: {DateTimeConverter.ParseFromDouble((double)value!)} vs {time}"));
}
else if (propertyType.IsEnum || Nullable.GetUnderlyingType(propertyType)?.IsEnum == true)
{
@@ -424,27 +460,27 @@ namespace CryptoExchange.Net.Testing.Comparers
else if(objectValue is decimal dec)
{
if (dec != value)
throw new Exception($"{method}: {property} not equal: {dec} vs {value}");
outputExceptions.Add(new Exception($"{method}: {property} not equal: {dec} vs {value}"));
}
else if (objectValue is double dbl)
{
if ((decimal)dbl != value)
throw new Exception($"{method}: {property} not equal: {dbl} vs {value}");
outputExceptions.Add(new Exception($"{method}: {property} not equal: {dbl} vs {value}"));
}
else if(objectValue is string objStr)
{
if (objStr != value.ToString())
throw new Exception($"{method}: {property} not equal: {value} vs {objStr}");
outputExceptions.Add(new Exception($"{method}: {property} not equal: {value} vs {objStr}"));
}
else if (value != Convert.ToInt64(objectValue, CultureInfo.InvariantCulture))
{
throw new Exception($"{method}: {property} not equal: {value} vs {Convert.ToInt64(objectValue)}");
outputExceptions.Add(new Exception($"{method}: {property} not equal: {value} vs {Convert.ToInt64(objectValue)}"));
}
}
else if (jsonValue.ValueKind == JsonValueKind.True || jsonValue.ValueKind == JsonValueKind.False)
{
if (jsonValue.GetBoolean() != (bool)objectValue)
throw new Exception($"{method}: {property} not equal: {jsonValue.GetBoolean()} vs {(bool)objectValue}");
outputExceptions.Add(new Exception($"{method}: {property} not equal: {jsonValue.GetBoolean()} vs {(bool)objectValue}"));
}
}
}
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Text;
namespace CryptoExchange.Net.Testing.Exceptions
{
internal class MissingPropertyException : Exception
{
public MissingPropertyException(string method, string objName, string propName, string value)
: base($"{method}: Missing property `{propName}` on `{objName}`, value: {value.Substring(0, Math.Min(50, value.Length))}")
{
}
}
}
@@ -1,10 +1,12 @@
using CryptoExchange.Net.Interfaces;
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Testing.Comparers;
using CryptoExchange.Net.Testing.Exceptions;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
@@ -55,6 +57,26 @@ namespace CryptoExchange.Net.Testing
return true;
}
/// <summary>
/// Execute a REST endpoint call and check for any errors or warnings. Also checks for missing fields in the response mapping
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="warningExceptionsHolder">List for outputting warnings</param>
/// <param name="expression">The call expression</param>
/// <param name="authRequest">Whether this is an authenticated request</param>
/// <param name="compareNestedProperty">Nested property to use for comparing when checking for missing fields</param>
/// <param name="ignoreProperties">Properties to ignore when checking for missing fields</param>
/// <param name="useSingleArrayItem">Whether to use the single array item as compare when checking for missing fields</param>
/// <returns></returns>
public Task RunAndCheckResult<T>(
List<Exception> warningExceptionsHolder,
Expression<Func<TClient, Task<HttpResult<T>>>> expression,
bool authRequest,
string? compareNestedProperty = null,
List<string>? ignoreProperties = null,
bool? useSingleArrayItem = null)
=> RunAndCheckResult(expression, authRequest, true, compareNestedProperty, ignoreProperties, useSingleArrayItem, warningExceptionsHolder);
/// <summary>
/// Execute a REST endpoint call and check for any errors or warnings.
/// </summary>
@@ -65,13 +87,15 @@ namespace CryptoExchange.Net.Testing
/// <param name="compareNestedProperty">Nested property to use for comparing when checking for missing fields</param>
/// <param name="ignoreProperties">Properties to ignore when checking for missing fields</param>
/// <param name="useSingleArrayItem">Whether to use the single array item as compare when checking for missing fields</param>
/// <param name="warnings">List for outputting warnings</param>
public async Task RunAndCheckResult<T>(
Expression<Func<TClient, Task<HttpResult<T>>>> expression,
bool authRequest,
bool checkMissingFields = false,
string? compareNestedProperty = null,
List<string>? ignoreProperties = null,
bool? useSingleArrayItem = null)
bool? useSingleArrayItem = null,
List<Exception>? warnings = null)
{
if (!ShouldRun())
return;
@@ -112,8 +136,20 @@ namespace CryptoExchange.Net.Testing
if (originalData == null)
throw new Exception($"Original data needs to be enabled in the client options to check for missing fields");
try {
SystemTextJsonComparer.CompareData(expressionBody.Method.Name, data, originalData, compareNestedProperty, ignoreProperties, useSingleArrayItem ?? false);
var errors = new List<Exception>();
try
{
var issues = SystemTextJsonComparer.CompareData(expressionBody.Method.Name, data, originalData, compareNestedProperty, ignoreProperties, useSingleArrayItem ?? false);
foreach(var issue in issues)
{
if (issue is MissingPropertyException)
warnings?.Add(issue);
else
errors.Add(issue);
}
if (errors.Count > 0)
throw new AggregateException(errors);
}
catch (Exception ex)
{
@@ -1,6 +1,7 @@
using CryptoExchange.Net.Clients;
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Testing.Comparers;
using CryptoExchange.Net.Testing.Exceptions;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -184,7 +185,9 @@ namespace CryptoExchange.Net.Testing
{
// Check response data
object responseData = (TActualResponse)result.Data!;
SystemTextJsonComparer.CompareData(name, responseData, response, nestedJsonProperty ?? _nestedPropertyForCompare, ignoreProperties, useSingleArrayItem);
var issues = SystemTextJsonComparer.CompareData(name, responseData, response, nestedJsonProperty ?? _nestedPropertyForCompare, ignoreProperties, useSingleArrayItem);
if (issues.Count > 0)
throw new AggregateException(issues);
}
Trace.Listeners.Remove(listener);
@@ -155,7 +155,7 @@ namespace CryptoExchange.Net.Testing
else if (line.StartsWith("< "))
{
// Expect a message from server to client
foreach(var item in replaceValues)
foreach (var item in replaceValues)
line = line.Replace(item.Key, item.Value);
socket.InvokeMessage(line.Substring(2));
@@ -175,7 +175,11 @@ namespace CryptoExchange.Net.Testing
result = responseMapper(task.Result.Data!);
if (!skipResponseValidation)
SystemTextJsonComparer.CompareData(name, result, compareData, nestedJsonProperty ?? _nestedPropertyForCompare, ignoreProperties, useSingleArrayItem);
{
var issues = SystemTextJsonComparer.CompareData(name, result, compareData, nestedJsonProperty ?? _nestedPropertyForCompare, ignoreProperties, useSingleArrayItem);
if (issues.Count > 0)
throw new AggregateException(issues);
}
}
}
@@ -326,7 +326,11 @@ namespace CryptoExchange.Net.Testing
throw new Exception($"{name} Update send to client did not trigger in update handler");
if (skipUpdateValidation != true)
SystemTextJsonComparer.CompareData(name, update, compareData, nestedJsonProperty ?? _nestedPropertyForCompare, ignoreProperties, useFirstUpdateItem ?? false);
{
var issues = SystemTextJsonComparer.CompareData(name, update, compareData, nestedJsonProperty ?? _nestedPropertyForCompare, ignoreProperties, useFirstUpdateItem ?? false);
if (issues.Count > 0)
throw new AggregateException(issues);
}
}
}
@@ -19,6 +19,7 @@ namespace CryptoExchange.Net.Trackers.Klines
private readonly IKlineRestClient _restClient;
private SyncStatus _status;
private bool _startWithSnapshot;
private ExchangeParameters? _exchangeParameters;
/// <summary>
/// The internal data structure
@@ -157,9 +158,11 @@ namespace CryptoExchange.Net.Trackers.Klines
SharedSymbol symbol,
SharedKlineInterval interval,
int? limit = null,
TimeSpan? period = null)
TimeSpan? period = null,
ExchangeParameters? exchangeParameters = null)
{
_logger = logger ?? new NullLogger<KlineTracker>();
_exchangeParameters = exchangeParameters;
Symbol = symbol;
SymbolName = socketClient.FormatSymbol(symbol.BaseAsset, symbol.QuoteAsset, symbol.TradingMode, symbol.DeliverTime);
Exchange = restClient.Exchange;
@@ -180,7 +183,7 @@ namespace CryptoExchange.Net.Trackers.Klines
Status = SyncStatus.Syncing;
_logger.KlineTrackerStarting(SymbolName);
var subResult = await _socketClient.SubscribeToKlineUpdatesAsync(new SubscribeKlineRequest(Symbol, Interval),
var subResult = await _socketClient.SubscribeToKlineUpdatesAsync(new SubscribeKlineRequest(Symbol, Interval, exchangeParameters: _exchangeParameters),
update =>
{
AddOrUpdate(update.Data);
@@ -237,7 +240,7 @@ namespace CryptoExchange.Net.Trackers.Klines
var limit = Math.Min(_restClient.GetKlinesOptions.MaxLimit, Limit ?? 100);
var request = new GetKlinesRequest(Symbol, Interval, startTime, DateTime.UtcNow, limit: limit);
var request = new GetKlinesRequest(Symbol, Interval, startTime, DateTime.UtcNow, limit: limit, exchangeParameters: _exchangeParameters);
var data = new List<SharedKline>();
await foreach (var result in ExchangeHelpers.ExecutePages(_restClient.GetKlinesAsync, request).ConfigureAwait(false))
{
@@ -21,6 +21,7 @@ namespace CryptoExchange.Net.Trackers.Trades
private SyncStatus _status;
private long _snapshotId;
private bool _startWithSnapshot;
private ExchangeParameters? _exchangeParameters;
/// <summary>
/// The internal data structure
@@ -154,12 +155,14 @@ namespace CryptoExchange.Net.Trackers.Trades
ITradeSocketClient socketClient,
SharedSymbol symbol,
int? limit = null,
TimeSpan? period = null)
TimeSpan? period = null,
ExchangeParameters? exchangeParameters = null)
{
_logger = logger ?? new NullLogger<TradeTracker>();
_recentRestClient = recentRestClient;
_historyRestClient = historyRestClient;
_socketClient = socketClient;
_exchangeParameters = exchangeParameters;
Exchange = socketClient.Exchange;
Symbol = symbol;
SymbolName = socketClient.FormatSymbol(symbol.BaseAsset, symbol.QuoteAsset, symbol.TradingMode, symbol.DeliverTime);
@@ -203,7 +206,7 @@ namespace CryptoExchange.Net.Trackers.Trades
_startWithSnapshot = startWithSnapshot;
Status = SyncStatus.Syncing;
_logger.TradeTrackerStarting(SymbolName);
var subResult = await _socketClient.SubscribeToTradeUpdatesAsync(new SubscribeTradeRequest(Symbol),
var subResult = await _socketClient.SubscribeToTradeUpdatesAsync(new SubscribeTradeRequest(Symbol, exchangeParameters: _exchangeParameters),
update =>
{
AddData(update.Data);
@@ -257,7 +260,7 @@ namespace CryptoExchange.Net.Trackers.Trades
if (_historyRestClient != null)
{
var startTime = Period == null ? DateTime.UtcNow.AddMinutes(-5) : DateTime.UtcNow.Add(-Period.Value);
var request = new GetTradeHistoryRequest(Symbol, startTime, DateTime.UtcNow);
var request = new GetTradeHistoryRequest(Symbol, startTime, DateTime.UtcNow, exchangeParameters: _exchangeParameters);
var data = new List<SharedTrade>();
await foreach (var result in ExchangeHelpers.ExecutePages(_historyRestClient.GetTradeHistoryAsync, request).ConfigureAwait(false))
{
@@ -278,7 +281,7 @@ namespace CryptoExchange.Net.Trackers.Trades
if (Limit.HasValue)
limit = Math.Min(_recentRestClient.GetRecentTradesOptions.MaxLimit, Limit.Value);
var snapshot = await _recentRestClient.GetRecentTradesAsync(new GetRecentTradesRequest(Symbol, limit)).ConfigureAwait(false);
var snapshot = await _recentRestClient.GetRecentTradesAsync(new GetRecentTradesRequest(Symbol, limit, exchangeParameters: _exchangeParameters)).ConfigureAwait(false);
if (!snapshot.Success)
{
return CallResult.Fail(snapshot.Error);
+27 -26
View File
@@ -5,33 +5,34 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Binance.Net" Version="12.13.0" />
<PackageReference Include="Bitfinex.Net" Version="10.12.0" />
<PackageReference Include="BitMart.Net" Version="3.11.2" />
<PackageReference Include="BloFin.Net" Version="2.11.0" />
<PackageReference Include="Bybit.Net" Version="6.13.0" />
<PackageReference Include="CoinEx.Net" Version="10.11.0" />
<PackageReference Include="CoinW.Net" Version="2.10.0" />
<PackageReference Include="CryptoCom.Net" Version="3.11.0" />
<PackageReference Include="DeepCoin.Net" Version="3.10.0" />
<PackageReference Include="GateIo.Net" Version="3.11.0" />
<PackageReference Include="HyperLiquid.Net" Version="4.7.1" />
<PackageReference Include="JK.BingX.Net" Version="3.11.1" />
<PackageReference Include="JK.Bitget.Net" Version="3.12.1" />
<PackageReference Include="JK.Mexc.Net" Version="5.2.0" />
<PackageReference Include="JK.OKX.Net" Version="4.14.0" />
<PackageReference Include="Jkorf.Aster.Net" Version="3.3.0" />
<PackageReference Include="JKorf.BitMEX.Net" Version="3.10.0" />
<PackageReference Include="JKorf.Coinbase.Net" Version="3.10.1" />
<PackageReference Include="JKorf.HTX.Net" Version="8.10.1" />
<PackageReference Include="JKorf.Upbit.Net" Version="2.10.1" />
<PackageReference Include="KrakenExchange.Net" Version="7.11.0" />
<PackageReference Include="Kucoin.Net" Version="8.13.0" />
<PackageReference Include="Binance.Net" Version="13.0.0" />
<PackageReference Include="Bitfinex.Net" Version="11.0.0" />
<PackageReference Include="BitMart.Net" Version="4.0.0" />
<PackageReference Include="BloFin.Net" Version="3.0.0" />
<PackageReference Include="Bybit.Net" Version="7.0.0" />
<PackageReference Include="CoinEx.Net" Version="11.0.0" />
<PackageReference Include="CoinW.Net" Version="3.0.0" />
<PackageReference Include="CryptoCom.Net" Version="4.0.0" />
<PackageReference Include="DeepCoin.Net" Version="4.0.0" />
<PackageReference Include="GateIo.Net" Version="4.0.0" />
<PackageReference Include="HyperLiquid.Net" Version="5.0.0" />
<PackageReference Include="JK.BingX.Net" Version="4.0.0" />
<PackageReference Include="JK.Bitget.Net" Version="4.0.0" />
<PackageReference Include="JK.Mexc.Net" Version="6.0.0" />
<PackageReference Include="JK.OKX.Net" Version="5.0.1" />
<PackageReference Include="Jkorf.Aster.Net" Version="4.0.0" />
<PackageReference Include="JKorf.BitMEX.Net" Version="4.0.0" />
<PackageReference Include="JKorf.Coinbase.Net" Version="4.0.0" />
<PackageReference Include="JKorf.HTX.Net" Version="9.0.0" />
<PackageReference Include="JKorf.Lighter.Net" Version="1.0.0" />
<PackageReference Include="JKorf.Upbit.Net" Version="3.0.0" />
<PackageReference Include="KrakenExchange.Net" Version="8.0.0" />
<PackageReference Include="Kucoin.Net" Version="9.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageReference Include="Toobit.Net" Version="3.10.0" />
<PackageReference Include="Weex.Net" Version="1.1.1" />
<PackageReference Include="WhiteBit.Net" Version="3.11.1" />
<PackageReference Include="XT.Net" Version="3.10.0" />
<PackageReference Include="Toobit.Net" Version="4.0.0" />
<PackageReference Include="Weex.Net" Version="2.0.0" />
<PackageReference Include="WhiteBit.Net" Version="4.0.0" />
<PackageReference Include="XT.Net" Version="4.0.0" />
</ItemGroup>
</Project>
+6 -1
View File
@@ -18,6 +18,7 @@
@inject IHyperLiquidRestClient hyperLiquidClient
@inject IKrakenRestClient krakenClient
@inject IKucoinRestClient kucoinClient
@inject ILighterRestClient lighterClient
@inject IMexcRestClient mexcClient
@inject IOKXRestClient okxClient
@inject IToobitRestClient toobitClient
@@ -40,7 +41,7 @@
var asterTask = asterClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT");
var binanceTask = binanceClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT");
var bingXTask = bingXClient.SpotApi.ExchangeData.GetTickersAsync("BTC-USDT");
var bitfinexTask = bitfinexClient.SpotApi.ExchangeData.GetTickerAsync("tBTCUSD");
var bitfinexTask = bitfinexClient.ExchangeApi.ExchangeData.GetTickerAsync("tBTCUSD");
var bitgetTask = bitgetClient.SpotApiV2.ExchangeData.GetTickersAsync("BTCUSDT");
var bitmartTask = bitmartClient.SpotApi.ExchangeData.GetTickerAsync("BTC_USDT");
var bitmexTask = bitmexClient.ExchangeApi.ExchangeData.GetSymbolsAsync("XBT_USDT");
@@ -56,6 +57,7 @@
var hyperLiquidTask = hyperLiquidClient.FuturesApi.ExchangeData.GetExchangeInfoAndTickersAsync();
var krakenTask = krakenClient.SpotApi.ExchangeData.GetTickerAsync("XBTUSD");
var kucoinTask = kucoinClient.SpotApi.ExchangeData.GetTickerAsync("BTC-USDT");
var lighterTask = lighterClient.ExchangeApi.ExchangeData.GetSymbolDetailsAsync("BTC");
var mexcTask = mexcClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT");
var okxTask = okxClient.UnifiedApi.ExchangeData.GetTickerAsync("BTC-USDT");
var toobitTask = toobitClient.SpotApi.ExchangeData.GetTickersAsync("BTCUSDT");
@@ -131,6 +133,9 @@
if (kucoinTask.Result.Success)
_prices.Add("Kucoin", kucoinTask.Result.Data.LastPrice ?? 0);
if (lighterTask.Result.Success)
_prices.Add("Lighter", lighterTask.Result.Data.PerpSymbols[0].LastPrice);
if (mexcTask.Result.Success)
_prices.Add("Mexc", mexcTask.Result.Data.LastPrice);
+3 -2
View File
@@ -18,6 +18,7 @@
@inject IHyperLiquidSocketClient hyperLiquidSocketClient
@inject IKrakenSocketClient krakenSocketClient
@inject IKucoinSocketClient kucoinSocketClient
@inject ILighterSocketClient lighterSocketClient
@inject IMexcSocketClient mexcSocketClient
@inject IOKXSocketClient okxSocketClient
@inject IToobitSocketClient toobitSocketClient
@@ -44,13 +45,13 @@
protected override async Task OnInitializedAsync()
{
var tasks = new Task<CallResult<UpdateSubscription>>[]
var tasks = new Task<WebSocketResult<UpdateSubscription>>[]
{
// Aster doesn't support the ETH/BTC pair
//asterSocketClient.SpotApi.ExchangeData.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("Aster", data.Data.LastPrice)),
binanceSocketClient.SpotApi.ExchangeData.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("Binance", data.Data.LastPrice)),
bingXSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH-BTC", data => UpdateData("BingX", data.Data.LastPrice)),
bitfinexSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("tETHBTC", data => UpdateData("Bitfinex", data.Data.LastPrice)),
bitfinexSocketClient.ExchangeApi.SubscribeToTickerUpdatesAsync("tETHBTC", data => UpdateData("Bitfinex", data.Data.LastPrice)),
bitgetSocketClient.SpotApiV2.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("Bitget", data.Data.First().LastPrice)),
bitmartSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH_BTC", data => UpdateData("BitMart", data.Data.LastPrice)),
bitmexSocketClient.ExchangeApi.SubscribeToSymbolUpdatesAsync("ETH_XBT", data => UpdateData("BitMEX", data.Data.LastPrice ?? 0)),
@@ -24,6 +24,7 @@
@using Kucoin.Net
@using Kucoin.Net.Clients
@using Kucoin.Net.Interfaces
@using Lighter.Net.Interfaces
@using Mexc.Net.Interfaces
@using OKX.Net.Interfaces;
@using Upbit.Net.Interfaces;
@@ -50,6 +51,7 @@
@inject IHyperLiquidOrderBookFactory hyperLiquidFactory
@inject IKrakenOrderBookFactory krakenFactory
@inject IKucoinOrderBookFactory kucoinFactory
@inject ILighterOrderBookFactory lighterFactory
@inject IMexcOrderBookFactory mexcFactory
@inject IOKXOrderBookFactory okxFactory
@inject IToobitOrderBookFactory toobitFactory
@@ -110,6 +112,7 @@
{ "HyperLiquid", hyperLiquidFactory.Create("UETH/USDC") },
{ "Kraken", krakenFactory.CreateSpot("ETH/BTC") },
{ "Kucoin", kucoinFactory.CreateSpot("ETH-BTC") },
{ "Lighter", lighterFactory.Create("ETH/USDC") },
{ "Mexc", mexcFactory.CreateSpot("ETHBTC") },
{ "OKX", okxFactory.Create("ETH-BTC") },
{ "Toobit", toobitFactory.CreateSpot("ETHUSDT") },
@@ -24,6 +24,7 @@
@using Kraken.Net.Interfaces
@using Kucoin.Net.Clients
@using Kucoin.Net.Interfaces
@using Lighter.Net.Interfaces
@using Mexc.Net.Interfaces
@using OKX.Net.Interfaces;
@using Upbit.Net.Interfaces;
@@ -50,6 +51,7 @@
@inject IHyperLiquidTrackerFactory hyperLiquidFactory
@inject IKrakenTrackerFactory krakenFactory
@inject IKucoinTrackerFactory kucoinFactory
@inject ILighterTrackerFactory lighterFactory
@inject IMexcTrackerFactory mexcFactory
@inject IOKXTrackerFactory okxFactory
@inject IToobitTrackerFactory toobitFactory
@@ -103,6 +105,7 @@
{ hyperLiquidFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
{ krakenFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
{ kucoinFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
{ lighterFactory.CreateTradeTracker(futuresSymbol, period: TimeSpan.FromMinutes(5)) },
{ mexcFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
{ okxFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
{ toobitFactory.CreateTradeTracker(symbol, period: TimeSpan.FromMinutes(5)) },
+1
View File
@@ -52,6 +52,7 @@ namespace BlazorClient
services.AddHTX();
services.AddKraken();
services.AddKucoin();
services.AddLighter();
services.AddMexc();
services.AddOKX();
services.AddToobit();
+1
View File
@@ -27,6 +27,7 @@
@using HyperLiquid.Net.Interfaces.Clients;
@using Kraken.Net.Interfaces.Clients;
@using Kucoin.Net.Interfaces.Clients;
@using Lighter.Net.Interfaces.Clients
@using Mexc.Net.Interfaces.Clients;
@using OKX.Net.Interfaces.Clients;
@using Upbit.Net.Interfaces.Clients;
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2018 Jan Korf
Copyright (c) 2026 JKorf
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+27
View File
@@ -20,6 +20,8 @@ This library and the entire CryptoExchange.Net ecosystem provide first-class sup
For single-exchange code, see also the AI files in each exchange's repository (Binance.Net, Bybit.Net, OKX.Net, ...) — they cover exchange-specific patterns.
See [cryptoexchange-skills-hub](https://github.com/JKorf/cryptoexchange-skills-hub) for installable skills.
**Quick prompt to verify your assistant is using these:**
> "Show me how to fetch BTC/USDT spot tickers from Binance and OKX concurrently in C# using the SharedApis pattern."
@@ -51,6 +53,7 @@ Full list of all libraries part of the CryptoExchange.Net ecosystem. Consider us
|![HyperLiquid](https://raw.githubusercontent.com/JKorf/HyperLiquid.Net/refs/heads/main/HyperLiquid.Net/Icon/icon.png)|HyperLiquid|DEX|[JKorf/HyperLiquid.Net](https://github.com/JKorf/HyperLiquid.Net)|[![Nuget version](https://img.shields.io/nuget/v/HyperLiquid.Net.svg?style=flat-square)](https://www.nuget.org/packages/HyperLiquid.Net)|[Link](https://app.hyperliquid.xyz/join/JKORF)|4%|
|![Kraken](https://raw.githubusercontent.com/JKorf/Kraken.Net/refs/heads/master/Kraken.Net/Icon/icon.png)|Kraken|CEX|[JKorf/Kraken.Net](https://github.com/JKorf/Kraken.Net)|[![Nuget version](https://img.shields.io/nuget/v/KrakenExchange.net.svg?style=flat-square)](https://www.nuget.org/packages/KrakenExchange.Net)|-|-|
|![Kucoin](https://raw.githubusercontent.com/JKorf/Kucoin.Net/refs/heads/master/Kucoin.Net/Icon/icon.png)|Kucoin|CEX|[JKorf/Kucoin.Net](https://github.com/JKorf/Kucoin.Net)|[![Nuget version](https://img.shields.io/nuget/v/Kucoin.net.svg?style=flat-square)](https://www.nuget.org/packages/Kucoin.Net)|[Link](https://www.kucoin.com/r/rf/QBS4FPED)|-|
|![Lighter](https://raw.githubusercontent.com/JKorf/Lighter.Net/refs/heads/main/Lighter.Net/Icon/icon.png)|Lighter|DEX|[JKorf/Lighter.Net](https://github.com/JKorf/Lighter.Net)|[![Nuget version](https://img.shields.io/nuget/v/JKorf.Lighter.net.svg?style=flat-square)](https://www.nuget.org/packages/JKorf.Lighter.Net)|-|-|
|![Mexc](https://raw.githubusercontent.com/JKorf/Mexc.Net/refs/heads/main/Mexc.Net/Icon/icon.png)|Mexc|CEX|[JKorf/Mexc.Net](https://github.com/JKorf/Mexc.Net)|[![Nuget version](https://img.shields.io/nuget/v/JK.Mexc.net.svg?style=flat-square)](https://www.nuget.org/packages/JK.Mexc.Net)|-|-|
|![OKX](https://raw.githubusercontent.com/JKorf/OKX.Net/refs/heads/main/OKX.Net/Icon/icon.png)|OKX|CEX|[JKorf/OKX.Net](https://github.com/JKorf/OKX.Net)|[![Nuget version](https://img.shields.io/nuget/v/JK.OKX.net.svg?style=flat-square)](https://www.nuget.org/packages/JK.OKX.Net)|[Link](https://www.okx.com/join/14592495)|20%|
|![Polymarket](https://raw.githubusercontent.com/JKorf/Polymarket.Net/main/Polymarket.Net/Icon/icon.png)|Polymarket|DEX|[JKorf/Polymarket.Net](https://github.com/JKorf/Polymarket.Net)|[![Nuget version](https://img.shields.io/nuget/v/Polymarket.net.svg?style=flat-square)](https://www.nuget.org/packages/Polymarket.Net)|-|-|
@@ -124,6 +127,30 @@ Various:
* PlatformInfo now required support environment names in the constructor
## Release notes
* Version 12.2.0 - 20 Jul 2026
* Added SpotSymbolCatalog to Shared ISpotSymbolRestClient interface
* Added FuturesSymbolCatalog to Shared IFuturesSymbolRestClient interface
* Added BaseAssetType, BaseAssetSubType, QuoteAssetType and QuoteAssetSubType to GetSymbolsRequest model
* Added DisplayName to SharedSpotSymbol and SharedFuturesSymbol models
* Added BaseAssetType, BaseAssetSubType, QuoteAssetType and QuoteAssetSubType to SharedSpotSymbol and SharedFuturesSymbol models
* Added IsStableCoin, IsCommodity and IsEquity helper methods to LibraryHelpers
* Added DebuggerDisplay attributes to Shared models
* Fixed socket connection combine calculations
* Version 12.1.1 - 11 Jul 2026
* Added timestamp deserialization support for yyyy-MM-dd HH:mm:ss.ffffff+00:00:00
* Version 12.1.0 - 09 Jul 2026
* Added ExchangeParameters parameter to KlineTracker, TradeTracker and ITrackerFactory methods
* Updated some testing logic
* Fixed nullability operator on Parameters.AddCommaSeperated
* Version 12.0.2 - 01 Jul 2026
* Updated test validation to output a list of issues instead of throwing on the first
* Version 12.0.1 - 29 Jun 2026
* Fixed bug in bool converter
* Version 12.0.0 - 29 Jun 2026
* Result types:
* (Web)CallResult types are replaced by HttpResult, WebSocketResult and QueryResult with the same logic
-1
View File
@@ -1 +0,0 @@
Source for https://jkorf.github.io/CryptoExchange.Net
-2
View File
@@ -1,2 +0,0 @@
remote_theme: pmarsceill/just-the-docs
markdown: GFM
-159
View File
@@ -1,159 +0,0 @@
/*============================
COLOR Blue
==============================*/
::selection {
background: #007bff;
}
a, a:focus {
color: #007bff;
}
a:hover, a:active {
color: #006adb;
}
.primary-menu ul.navbar-nav > li:hover > a:not(.btn), .primary-menu ul.navbar-nav > li > a.active:not(.btn) {
color: #007bff;
}
.primary-menu ul.navbar-nav > li.dropdown .dropdown-menu li:hover > a:not(.btn) {
color: #007bff;
}
.primary-menu.navbar-line-under-text ul.navbar-nav > li > a:not(.btn):after {
border-color: #007bff;
}
/*=== Side Navigation ===*/
.idocs-navigation .nav .nav .nav-item .nav-link.active:after, .idocs-navigation.docs-navigation-dark .nav .nav .nav-item .nav-link.active:after {
border-color: #007bff;
}
/* Accordion & Toggle */
.accordion .card-header a:hover.collapsed {
color: #007bff !important;
}
.accordion:not(.accordion-alternate) .card-header a {
background-color: #007bff;
color: #fff;
}
/* Nav */
.nav:not(.nav-pills) .nav-item .nav-link.active, .nav:not(.nav-pills) .nav-item .nav-link:hover {
color: #007bff;
}
.nav-tabs .nav-item .nav-link.active {
color: #0c2f55;
}
.nav-tabs .nav-item .nav-link.active:after {
background-color: #007bff;
}
.nav-tabs .nav-item .nav-link:not(.active):hover {
color: #007bff;
}
.nav-tabs.flex-column .nav-item .nav-link.active {
color: #007bff;
}
.nav-pills .nav-link:not(.active):hover {
color: #007bff;
}
#footer .nav .nav-item .nav-link:focus {
color: #007bff;
}
#footer .nav .nav-link:hover {
color: #007bff;
}
#footer .footer-copyright .nav .nav-link:hover {
color: #007bff;
}
/* Back to Top */
#back-to-top:hover {
background-color: #007bff;
}
/* Extras */
.bg-primary, .badge-primary {
background-color: #007bff !important;
}
.text-primary, .btn-light, .btn-outline-light:hover, .btn-link, .btn-outline-light:not(:disabled):not(.disabled).active, .btn-outline-light:not(:disabled):not(.disabled):active {
color: #007bff !important;
}
.btn-link:hover {
color: #006adb !important;
}
.text-muted {
color: #8e9a9d !important;
}
.text-light {
color: #dee3e4 !important;
}
a.bg-primary:focus, a.bg-primary:hover, button.bg-primary:focus, button.bg-primary:hover {
background-color: #006adb !important;
}
.border-primary {
border-color: #007bff !important;
}
.btn-primary {
background-color: #007bff;
border-color: #007bff;
}
.btn-primary:hover {
background-color: #006adb;
border-color: #006adb;
}
.btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active {
background-color: #006adb;
border-color: #006adb;
}
.btn-primary.focus, .btn-primary:focus {
background-color: #006adb;
border-color: #006adb;
}
.btn-outline-primary, .btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active {
color: #007bff;
border-color: #007bff;
}
.btn-outline-primary:hover, .btn-outline-primary:not(:disabled):not(.disabled).active:hover, .btn-outline-primary:not(:disabled):not(.disabled):active:hover {
background-color: #007bff;
border-color: #007bff;
color: #fff;
}
.progress-bar,
.nav-pills .nav-link.active, .nav-pills .show > .nav-link, .dropdown-item.active, .dropdown-item:active {
background-color: #007bff;
}
.page-item.active .page-link,
.custom-radio .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label::before,
.custom-checkbox .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label:before {
background-color: #007bff;
border-color: #007bff;
}
.list-group-item.active {
background-color: #007bff;
border-color: #007bff;
}
.page-link {
color: #007bff;
}
.page-link:hover {
color: #006adb;
}
-159
View File
@@ -1,159 +0,0 @@
/*============================
COLOR Brown
==============================*/
::selection {
background: #795548;
}
a, a:focus {
color: #795548;
}
a:hover, a:active {
color: #63453b;
}
.primary-menu ul.navbar-nav > li:hover > a:not(.btn), .primary-menu ul.navbar-nav > li > a.active:not(.btn) {
color: #795548;
}
.primary-menu ul.navbar-nav > li.dropdown .dropdown-menu li:hover > a:not(.btn) {
color: #795548;
}
.primary-menu.navbar-line-under-text ul.navbar-nav > li > a:not(.btn):after {
border-color: #795548;
}
/*=== Side Navigation ===*/
.idocs-navigation .nav .nav .nav-item .nav-link.active:after, .idocs-navigation.docs-navigation-dark .nav .nav .nav-item .nav-link.active:after {
border-color: #795548;
}
/* Accordion & Toggle */
.accordion .card-header a:hover.collapsed {
color: #795548 !important;
}
.accordion:not(.accordion-alternate) .card-header a {
background-color: #795548;
color: #fff;
}
/* Nav */
.nav:not(.nav-pills) .nav-item .nav-link.active, .nav:not(.nav-pills) .nav-item .nav-link:hover {
color: #795548;
}
.nav-tabs .nav-item .nav-link.active {
color: #0c2f55;
}
.nav-tabs .nav-item .nav-link.active:after {
background-color: #795548;
}
.nav-tabs .nav-item .nav-link:not(.active):hover {
color: #795548;
}
.nav-tabs.flex-column .nav-item .nav-link.active {
color: #795548;
}
.nav-pills .nav-link:not(.active):hover {
color: #795548;
}
#footer .nav .nav-item .nav-link:focus {
color: #795548;
}
#footer .nav .nav-link:hover {
color: #795548;
}
#footer .footer-copyright .nav .nav-link:hover {
color: #795548;
}
/* Back to Top */
#back-to-top:hover {
background-color: #795548;
}
/* Extras */
.bg-primary, .badge-primary {
background-color: #795548 !important;
}
.text-primary, .btn-light, .btn-outline-light:hover, .btn-link, .btn-outline-light:not(:disabled):not(.disabled).active, .btn-outline-light:not(:disabled):not(.disabled):active {
color: #795548 !important;
}
.btn-link:hover {
color: #63453b !important;
}
.text-muted {
color: #8e9a9d !important;
}
.text-light {
color: #dee3e4 !important;
}
a.bg-primary:focus, a.bg-primary:hover, button.bg-primary:focus, button.bg-primary:hover {
background-color: #63453b !important;
}
.border-primary {
border-color: #795548 !important;
}
.btn-primary {
background-color: #795548;
border-color: #795548;
}
.btn-primary:hover {
background-color: #63453b;
border-color: #63453b;
}
.btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active {
background-color: #63453b;
border-color: #63453b;
}
.btn-primary.focus, .btn-primary:focus {
background-color: #63453b;
border-color: #63453b;
}
.btn-outline-primary, .btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active {
color: #795548;
border-color: #795548;
}
.btn-outline-primary:hover, .btn-outline-primary:not(:disabled):not(.disabled).active:hover, .btn-outline-primary:not(:disabled):not(.disabled):active:hover {
background-color: #795548;
border-color: #795548;
color: #fff;
}
.progress-bar,
.nav-pills .nav-link.active, .nav-pills .show > .nav-link, .dropdown-item.active, .dropdown-item:active {
background-color: #795548;
}
.page-item.active .page-link,
.custom-radio .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label::before,
.custom-checkbox .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label:before {
background-color: #795548;
border-color: #795548;
}
.list-group-item.active {
background-color: #795548;
border-color: #795548;
}
.page-link {
color: #795548;
}
.page-link:hover {
color: #63453b;
}
-159
View File
@@ -1,159 +0,0 @@
/*============================
COLOR Cyan
==============================*/
::selection {
background: #17a2b8;
}
a, a:focus {
color: #17a2b8;
}
a:hover, a:active {
color: #138698;
}
.primary-menu ul.navbar-nav > li:hover > a:not(.btn), .primary-menu ul.navbar-nav > li > a.active:not(.btn) {
color: #17a2b8;
}
.primary-menu ul.navbar-nav > li.dropdown .dropdown-menu li:hover > a:not(.btn) {
color: #17a2b8;
}
.primary-menu.navbar-line-under-text ul.navbar-nav > li > a:not(.btn):after {
border-color: #17a2b8;
}
/*=== Side Navigation ===*/
.idocs-navigation .nav .nav .nav-item .nav-link.active:after, .idocs-navigation.docs-navigation-dark .nav .nav .nav-item .nav-link.active:after {
border-color: #17a2b8;
}
/* Accordion & Toggle */
.accordion .card-header a:hover.collapsed {
color: #17a2b8 !important;
}
.accordion:not(.accordion-alternate) .card-header a {
background-color: #17a2b8;
color: #fff;
}
/* Nav */
.nav:not(.nav-pills) .nav-item .nav-link.active, .nav:not(.nav-pills) .nav-item .nav-link:hover {
color: #17a2b8;
}
.nav-tabs .nav-item .nav-link.active {
color: #0c2f55;
}
.nav-tabs .nav-item .nav-link.active:after {
background-color: #17a2b8;
}
.nav-tabs .nav-item .nav-link:not(.active):hover {
color: #17a2b8;
}
.nav-tabs.flex-column .nav-item .nav-link.active {
color: #17a2b8;
}
.nav-pills .nav-link:not(.active):hover {
color: #17a2b8;
}
#footer .nav .nav-item .nav-link:focus {
color: #17a2b8;
}
#footer .nav .nav-link:hover {
color: #17a2b8;
}
#footer .footer-copyright .nav .nav-link:hover {
color: #17a2b8;
}
/* Back to Top */
#back-to-top:hover {
background-color: #17a2b8;
}
/* Extras */
.bg-primary, .badge-primary {
background-color: #17a2b8 !important;
}
.text-primary, .btn-light, .btn-outline-light:hover, .btn-link, .btn-outline-light:not(:disabled):not(.disabled).active, .btn-outline-light:not(:disabled):not(.disabled):active {
color: #17a2b8 !important;
}
.btn-link:hover {
color: #138698 !important;
}
.text-muted {
color: #8e9a9d !important;
}
.text-light {
color: #dee3e4 !important;
}
a.bg-primary:focus, a.bg-primary:hover, button.bg-primary:focus, button.bg-primary:hover {
background-color: #138698 !important;
}
.border-primary {
border-color: #17a2b8 !important;
}
.btn-primary {
background-color: #17a2b8;
border-color: #17a2b8;
}
.btn-primary:hover {
background-color: #138698;
border-color: #138698;
}
.btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active {
background-color: #138698;
border-color: #138698;
}
.btn-primary.focus, .btn-primary:focus {
background-color: #138698;
border-color: #138698;
}
.btn-outline-primary, .btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active {
color: #17a2b8;
border-color: #17a2b8;
}
.btn-outline-primary:hover, .btn-outline-primary:not(:disabled):not(.disabled).active:hover, .btn-outline-primary:not(:disabled):not(.disabled):active:hover {
background-color: #17a2b8;
border-color: #17a2b8;
color: #fff;
}
.progress-bar,
.nav-pills .nav-link.active, .nav-pills .show > .nav-link, .dropdown-item.active, .dropdown-item:active {
background-color: #17a2b8;
}
.page-item.active .page-link,
.custom-radio .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label::before,
.custom-checkbox .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label:before {
background-color: #17a2b8;
border-color: #17a2b8;
}
.list-group-item.active {
background-color: #17a2b8;
border-color: #17a2b8;
}
.page-link {
color: #17a2b8;
}
.page-link:hover {
color: #138698;
}
-159
View File
@@ -1,159 +0,0 @@
/*============================
COLOR Green
==============================*/
::selection {
background: #28a745;
}
a, a:focus {
color: #28a745;
}
a:hover, a:active {
color: #218a39;
}
.primary-menu ul.navbar-nav > li:hover > a:not(.btn), .primary-menu ul.navbar-nav > li > a.active:not(.btn) {
color: #28a745;
}
.primary-menu ul.navbar-nav > li.dropdown .dropdown-menu li:hover > a:not(.btn) {
color: #28a745;
}
.primary-menu.navbar-line-under-text ul.navbar-nav > li > a:not(.btn):after {
border-color: #28a745;
}
/*=== Side Navigation ===*/
.idocs-navigation .nav .nav .nav-item .nav-link.active:after, .idocs-navigation.docs-navigation-dark .nav .nav .nav-item .nav-link.active:after {
border-color: #28a745;
}
/* Accordion & Toggle */
.accordion .card-header a:hover.collapsed {
color: #28a745 !important;
}
.accordion:not(.accordion-alternate) .card-header a {
background-color: #28a745;
color: #fff;
}
/* Nav */
.nav:not(.nav-pills) .nav-item .nav-link.active, .nav:not(.nav-pills) .nav-item .nav-link:hover {
color: #28a745;
}
.nav-tabs .nav-item .nav-link.active {
color: #0c2f55;
}
.nav-tabs .nav-item .nav-link.active:after {
background-color: #28a745;
}
.nav-tabs .nav-item .nav-link:not(.active):hover {
color: #28a745;
}
.nav-tabs.flex-column .nav-item .nav-link.active {
color: #28a745;
}
.nav-pills .nav-link:not(.active):hover {
color: #28a745;
}
#footer .nav .nav-item .nav-link:focus {
color: #28a745;
}
#footer .nav .nav-link:hover {
color: #28a745;
}
#footer .footer-copyright .nav .nav-link:hover {
color: #28a745;
}
/* Back to Top */
#back-to-top:hover {
background-color: #28a745;
}
/* Extras */
.bg-primary, .badge-primary {
background-color: #28a745 !important;
}
.text-primary, .btn-light, .btn-outline-light:hover, .btn-link, .btn-outline-light:not(:disabled):not(.disabled).active, .btn-outline-light:not(:disabled):not(.disabled):active {
color: #28a745 !important;
}
.btn-link:hover {
color: #218a39 !important;
}
.text-muted {
color: #8e9a9d !important;
}
.text-light {
color: #dee3e4 !important;
}
a.bg-primary:focus, a.bg-primary:hover, button.bg-primary:focus, button.bg-primary:hover {
background-color: #218a39 !important;
}
.border-primary {
border-color: #28a745 !important;
}
.btn-primary {
background-color: #28a745;
border-color: #28a745;
}
.btn-primary:hover {
background-color: #218a39;
border-color: #218a39;
}
.btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active {
background-color: #218a39;
border-color: #218a39;
}
.btn-primary.focus, .btn-primary:focus {
background-color: #218a39;
border-color: #218a39;
}
.btn-outline-primary, .btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active {
color: #28a745;
border-color: #28a745;
}
.btn-outline-primary:hover, .btn-outline-primary:not(:disabled):not(.disabled).active:hover, .btn-outline-primary:not(:disabled):not(.disabled):active:hover {
background-color: #28a745;
border-color: #28a745;
color: #fff;
}
.progress-bar,
.nav-pills .nav-link.active, .nav-pills .show > .nav-link, .dropdown-item.active, .dropdown-item:active {
background-color: #28a745;
}
.page-item.active .page-link,
.custom-radio .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label::before,
.custom-checkbox .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label:before {
background-color: #28a745;
border-color: #28a745;
}
.list-group-item.active {
background-color: #28a745;
border-color: #28a745;
}
.page-link {
color: #28a745;
}
.page-link:hover {
color: #218a39;
}
-159
View File
@@ -1,159 +0,0 @@
/*============================
COLOR Indigo
==============================*/
::selection {
background: #6610f2;
}
a, a:focus {
color: #6610f2;
}
a:hover, a:active {
color: #570bd3;
}
.primary-menu ul.navbar-nav > li:hover > a:not(.btn), .primary-menu ul.navbar-nav > li > a.active:not(.btn) {
color: #6610f2;
}
.primary-menu ul.navbar-nav > li.dropdown .dropdown-menu li:hover > a:not(.btn) {
color: #6610f2;
}
.primary-menu.navbar-line-under-text ul.navbar-nav > li > a:not(.btn):after {
border-color: #6610f2;
}
/*=== Side Navigation ===*/
.idocs-navigation .nav .nav .nav-item .nav-link.active:after, .idocs-navigation.docs-navigation-dark .nav .nav .nav-item .nav-link.active:after {
border-color: #6610f2;
}
/* Accordion & Toggle */
.accordion .card-header a:hover.collapsed {
color: #6610f2 !important;
}
.accordion:not(.accordion-alternate) .card-header a {
background-color: #6610f2;
color: #fff;
}
/* Nav */
.nav:not(.nav-pills) .nav-item .nav-link.active, .nav:not(.nav-pills) .nav-item .nav-link:hover {
color: #6610f2;
}
.nav-tabs .nav-item .nav-link.active {
color: #0c2f55;
}
.nav-tabs .nav-item .nav-link.active:after {
background-color: #6610f2;
}
.nav-tabs .nav-item .nav-link:not(.active):hover {
color: #6610f2;
}
.nav-tabs.flex-column .nav-item .nav-link.active {
color: #6610f2;
}
.nav-pills .nav-link:not(.active):hover {
color: #6610f2;
}
#footer .nav .nav-item .nav-link:focus {
color: #6610f2;
}
#footer .nav .nav-link:hover {
color: #6610f2;
}
#footer .footer-copyright .nav .nav-link:hover {
color: #6610f2;
}
/* Back to Top */
#back-to-top:hover {
background-color: #6610f2;
}
/* Extras */
.bg-primary, .badge-primary {
background-color: #6610f2 !important;
}
.text-primary, .btn-light, .btn-outline-light:hover, .btn-link, .btn-outline-light:not(:disabled):not(.disabled).active, .btn-outline-light:not(:disabled):not(.disabled):active {
color: #6610f2 !important;
}
.btn-link:hover {
color: #570bd3 !important;
}
.text-muted {
color: #8e9a9d !important;
}
.text-light {
color: #dee3e4 !important;
}
a.bg-primary:focus, a.bg-primary:hover, button.bg-primary:focus, button.bg-primary:hover {
background-color: #570bd3 !important;
}
.border-primary {
border-color: #6610f2 !important;
}
.btn-primary {
background-color: #6610f2;
border-color: #6610f2;
}
.btn-primary:hover {
background-color: #570bd3;
border-color: #570bd3;
}
.btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active {
background-color: #570bd3;
border-color: #570bd3;
}
.btn-primary.focus, .btn-primary:focus {
background-color: #570bd3;
border-color: #570bd3;
}
.btn-outline-primary, .btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active {
color: #6610f2;
border-color: #6610f2;
}
.btn-outline-primary:hover, .btn-outline-primary:not(:disabled):not(.disabled).active:hover, .btn-outline-primary:not(:disabled):not(.disabled):active:hover {
background-color: #6610f2;
border-color: #6610f2;
color: #fff;
}
.progress-bar,
.nav-pills .nav-link.active, .nav-pills .show > .nav-link, .dropdown-item.active, .dropdown-item:active {
background-color: #6610f2;
}
.page-item.active .page-link,
.custom-radio .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label::before,
.custom-checkbox .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label:before {
background-color: #6610f2;
border-color: #6610f2;
}
.list-group-item.active {
background-color: #6610f2;
border-color: #6610f2;
}
.page-link {
color: #6610f2;
}
.page-link:hover {
color: #570bd3;
}
-159
View File
@@ -1,159 +0,0 @@
/*============================
COLOR Orange
==============================*/
::selection {
background: #fd7e14;
}
a, a:focus {
color: #fd7e14;
}
a:hover, a:active {
color: #eb6c02;
}
.primary-menu ul.navbar-nav > li:hover > a:not(.btn), .primary-menu ul.navbar-nav > li > a.active:not(.btn) {
color: #fd7e14;
}
.primary-menu ul.navbar-nav > li.dropdown .dropdown-menu li:hover > a:not(.btn) {
color: #fd7e14;
}
.primary-menu.navbar-line-under-text ul.navbar-nav > li > a:not(.btn):after {
border-color: #fd7e14;
}
/*=== Side Navigation ===*/
.idocs-navigation .nav .nav .nav-item .nav-link.active:after, .idocs-navigation.docs-navigation-dark .nav .nav .nav-item .nav-link.active:after {
border-color: #fd7e14;
}
/* Accordion & Toggle */
.accordion .card-header a:hover.collapsed {
color: #fd7e14 !important;
}
.accordion:not(.accordion-alternate) .card-header a {
background-color: #fd7e14;
color: #fff;
}
/* Nav */
.nav:not(.nav-pills) .nav-item .nav-link.active, .nav:not(.nav-pills) .nav-item .nav-link:hover {
color: #fd7e14;
}
.nav-tabs .nav-item .nav-link.active {
color: #0c2f55;
}
.nav-tabs .nav-item .nav-link.active:after {
background-color: #fd7e14;
}
.nav-tabs .nav-item .nav-link:not(.active):hover {
color: #fd7e14;
}
.nav-tabs.flex-column .nav-item .nav-link.active {
color: #fd7e14;
}
.nav-pills .nav-link:not(.active):hover {
color: #fd7e14;
}
#footer .nav .nav-item .nav-link:focus {
color: #fd7e14;
}
#footer .nav .nav-link:hover {
color: #fd7e14;
}
#footer .footer-copyright .nav .nav-link:hover {
color: #fd7e14;
}
/* Back to Top */
#back-to-top:hover {
background-color: #fd7e14;
}
/* Extras */
.bg-primary, .badge-primary {
background-color: #fd7e14 !important;
}
.text-primary, .btn-light, .btn-outline-light:hover, .btn-link, .btn-outline-light:not(:disabled):not(.disabled).active, .btn-outline-light:not(:disabled):not(.disabled):active {
color: #fd7e14 !important;
}
.btn-link:hover {
color: #eb6c02 !important;
}
.text-muted {
color: #8e9a9d !important;
}
.text-light {
color: #dee3e4 !important;
}
a.bg-primary:focus, a.bg-primary:hover, button.bg-primary:focus, button.bg-primary:hover {
background-color: #eb6c02 !important;
}
.border-primary {
border-color: #fd7e14 !important;
}
.btn-primary {
background-color: #fd7e14;
border-color: #fd7e14;
}
.btn-primary:hover {
background-color: #eb6c02;
border-color: #eb6c02;
}
.btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active {
background-color: #eb6c02;
border-color: #eb6c02;
}
.btn-primary.focus, .btn-primary:focus {
background-color: #eb6c02;
border-color: #eb6c02;
}
.btn-outline-primary, .btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active {
color: #fd7e14;
border-color: #fd7e14;
}
.btn-outline-primary:hover, .btn-outline-primary:not(:disabled):not(.disabled).active:hover, .btn-outline-primary:not(:disabled):not(.disabled):active:hover {
background-color: #fd7e14;
border-color: #fd7e14;
color: #fff;
}
.progress-bar,
.nav-pills .nav-link.active, .nav-pills .show > .nav-link, .dropdown-item.active, .dropdown-item:active {
background-color: #fd7e14;
}
.page-item.active .page-link,
.custom-radio .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label::before,
.custom-checkbox .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label:before {
background-color: #fd7e14;
border-color: #fd7e14;
}
.list-group-item.active {
background-color: #fd7e14;
border-color: #fd7e14;
}
.page-link {
color: #fd7e14;
}
.page-link:hover {
color: #eb6c02;
}
-159
View File
@@ -1,159 +0,0 @@
/*============================
COLOR Purple
==============================*/
::selection {
background: #6f42c1;
}
a, a:focus {
color: #6f42c1;
}
a:hover, a:active {
color: #5f37a8;
}
.primary-menu ul.navbar-nav > li:hover > a:not(.btn), .primary-menu ul.navbar-nav > li > a.active:not(.btn) {
color: #6f42c1;
}
.primary-menu ul.navbar-nav > li.dropdown .dropdown-menu li:hover > a:not(.btn) {
color: #6f42c1;
}
.primary-menu.navbar-line-under-text ul.navbar-nav > li > a:not(.btn):after {
border-color: #6f42c1;
}
/*=== Side Navigation ===*/
.idocs-navigation .nav .nav .nav-item .nav-link.active:after, .idocs-navigation.docs-navigation-dark .nav .nav .nav-item .nav-link.active:after {
border-color: #6f42c1;
}
/* Accordion & Toggle */
.accordion .card-header a:hover.collapsed {
color: #6f42c1 !important;
}
.accordion:not(.accordion-alternate) .card-header a {
background-color: #6f42c1;
color: #fff;
}
/* Nav */
.nav:not(.nav-pills) .nav-item .nav-link.active, .nav:not(.nav-pills) .nav-item .nav-link:hover {
color: #6f42c1;
}
.nav-tabs .nav-item .nav-link.active {
color: #0c2f55;
}
.nav-tabs .nav-item .nav-link.active:after {
background-color: #6f42c1;
}
.nav-tabs .nav-item .nav-link:not(.active):hover {
color: #6f42c1;
}
.nav-tabs.flex-column .nav-item .nav-link.active {
color: #6f42c1;
}
.nav-pills .nav-link:not(.active):hover {
color: #6f42c1;
}
#footer .nav .nav-item .nav-link:focus {
color: #6f42c1;
}
#footer .nav .nav-link:hover {
color: #6f42c1;
}
#footer .footer-copyright .nav .nav-link:hover {
color: #6f42c1;
}
/* Back to Top */
#back-to-top:hover {
background-color: #6f42c1;
}
/* Extras */
.bg-primary, .badge-primary {
background-color: #6f42c1 !important;
}
.text-primary, .btn-light, .btn-outline-light:hover, .btn-link, .btn-outline-light:not(:disabled):not(.disabled).active, .btn-outline-light:not(:disabled):not(.disabled):active {
color: #6f42c1 !important;
}
.btn-link:hover {
color: #5f37a8 !important;
}
.text-muted {
color: #8e9a9d !important;
}
.text-light {
color: #dee3e4 !important;
}
a.bg-primary:focus, a.bg-primary:hover, button.bg-primary:focus, button.bg-primary:hover {
background-color: #5f37a8 !important;
}
.border-primary {
border-color: #6f42c1 !important;
}
.btn-primary {
background-color: #6f42c1;
border-color: #6f42c1;
}
.btn-primary:hover {
background-color: #5f37a8;
border-color: #5f37a8;
}
.btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active {
background-color: #5f37a8;
border-color: #5f37a8;
}
.btn-primary.focus, .btn-primary:focus {
background-color: #5f37a8;
border-color: #5f37a8;
}
.btn-outline-primary, .btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active {
color: #6f42c1;
border-color: #6f42c1;
}
.btn-outline-primary:hover, .btn-outline-primary:not(:disabled):not(.disabled).active:hover, .btn-outline-primary:not(:disabled):not(.disabled):active:hover {
background-color: #6f42c1;
border-color: #6f42c1;
color: #fff;
}
.progress-bar,
.nav-pills .nav-link.active, .nav-pills .show > .nav-link, .dropdown-item.active, .dropdown-item:active {
background-color: #6f42c1;
}
.page-item.active .page-link,
.custom-radio .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label::before,
.custom-checkbox .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label:before {
background-color: #6f42c1;
border-color: #6f42c1;
}
.list-group-item.active {
background-color: #6f42c1;
border-color: #6f42c1;
}
.page-link {
color: #6f42c1;
}
.page-link:hover {
color: #5f37a8;
}
-159
View File
@@ -1,159 +0,0 @@
/*============================
COLOR Red
==============================*/
::selection {
background: #dc3545;
}
a, a:focus {
color: #dc3545;
}
a:hover, a:active {
color: #ca2333;
}
.primary-menu ul.navbar-nav > li:hover > a:not(.btn), .primary-menu ul.navbar-nav > li > a.active:not(.btn) {
color: #dc3545;
}
.primary-menu ul.navbar-nav > li.dropdown .dropdown-menu li:hover > a:not(.btn) {
color: #dc3545;
}
.primary-menu.navbar-line-under-text ul.navbar-nav > li > a:not(.btn):after {
border-color: #dc3545;
}
/*=== Side Navigation ===*/
.idocs-navigation .nav .nav .nav-item .nav-link.active:after, .idocs-navigation.docs-navigation-dark .nav .nav .nav-item .nav-link.active:after {
border-color: #dc3545;
}
/* Accordion & Toggle */
.accordion .card-header a:hover.collapsed {
color: #dc3545 !important;
}
.accordion:not(.accordion-alternate) .card-header a {
background-color: #dc3545;
color: #fff;
}
/* Nav */
.nav:not(.nav-pills) .nav-item .nav-link.active, .nav:not(.nav-pills) .nav-item .nav-link:hover {
color: #dc3545;
}
.nav-tabs .nav-item .nav-link.active {
color: #0c2f55;
}
.nav-tabs .nav-item .nav-link.active:after {
background-color: #dc3545;
}
.nav-tabs .nav-item .nav-link:not(.active):hover {
color: #dc3545;
}
.nav-tabs.flex-column .nav-item .nav-link.active {
color: #dc3545;
}
.nav-pills .nav-link:not(.active):hover {
color: #dc3545;
}
#footer .nav .nav-item .nav-link:focus {
color: #dc3545;
}
#footer .nav .nav-link:hover {
color: #dc3545;
}
#footer .footer-copyright .nav .nav-link:hover {
color: #dc3545;
}
/* Back to Top */
#back-to-top:hover {
background-color: #dc3545;
}
/* Extras */
.bg-primary, .badge-primary {
background-color: #dc3545 !important;
}
.text-primary, .btn-light, .btn-outline-light:hover, .btn-link, .btn-outline-light:not(:disabled):not(.disabled).active, .btn-outline-light:not(:disabled):not(.disabled):active {
color: #dc3545 !important;
}
.btn-link:hover {
color: #ca2333 !important;
}
.text-muted {
color: #8e9a9d !important;
}
.text-light {
color: #dee3e4 !important;
}
a.bg-primary:focus, a.bg-primary:hover, button.bg-primary:focus, button.bg-primary:hover {
background-color: #ca2333 !important;
}
.border-primary {
border-color: #dc3545 !important;
}
.btn-primary {
background-color: #dc3545;
border-color: #dc3545;
}
.btn-primary:hover {
background-color: #ca2333;
border-color: #ca2333;
}
.btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active {
background-color: #ca2333;
border-color: #ca2333;
}
.btn-primary.focus, .btn-primary:focus {
background-color: #ca2333;
border-color: #ca2333;
}
.btn-outline-primary, .btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active {
color: #dc3545;
border-color: #dc3545;
}
.btn-outline-primary:hover, .btn-outline-primary:not(:disabled):not(.disabled).active:hover, .btn-outline-primary:not(:disabled):not(.disabled):active:hover {
background-color: #dc3545;
border-color: #dc3545;
color: #fff;
}
.progress-bar,
.nav-pills .nav-link.active, .nav-pills .show > .nav-link, .dropdown-item.active, .dropdown-item:active {
background-color: #dc3545;
}
.page-item.active .page-link,
.custom-radio .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label::before,
.custom-checkbox .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label:before {
background-color: #dc3545;
border-color: #dc3545;
}
.list-group-item.active {
background-color: #dc3545;
border-color: #dc3545;
}
.page-link {
color: #dc3545;
}
.page-link:hover {
color: #ca2333;
}
-159
View File
@@ -1,159 +0,0 @@
/*============================
COLOR Teal
==============================*/
::selection {
background: #20c997;
}
a, a:focus {
color: #20c997;
}
a:hover, a:active {
color: #1baa80;
}
.primary-menu ul.navbar-nav > li:hover > a:not(.btn), .primary-menu ul.navbar-nav > li > a.active:not(.btn) {
color: #20c997;
}
.primary-menu ul.navbar-nav > li.dropdown .dropdown-menu li:hover > a:not(.btn) {
color: #20c997;
}
.primary-menu.navbar-line-under-text ul.navbar-nav > li > a:not(.btn):after {
border-color: #20c997;
}
/*=== Side Navigation ===*/
.idocs-navigation .nav .nav .nav-item .nav-link.active:after, .idocs-navigation.docs-navigation-dark .nav .nav .nav-item .nav-link.active:after {
border-color: #20c997;
}
/* Accordion & Toggle */
.accordion .card-header a:hover.collapsed {
color: #20c997 !important;
}
.accordion:not(.accordion-alternate) .card-header a {
background-color: #20c997;
color: #fff;
}
/* Nav */
.nav:not(.nav-pills) .nav-item .nav-link.active, .nav:not(.nav-pills) .nav-item .nav-link:hover {
color: #20c997;
}
.nav-tabs .nav-item .nav-link.active {
color: #0c2f55;
}
.nav-tabs .nav-item .nav-link.active:after {
background-color: #20c997;
}
.nav-tabs .nav-item .nav-link:not(.active):hover {
color: #20c997;
}
.nav-tabs.flex-column .nav-item .nav-link.active {
color: #20c997;
}
.nav-pills .nav-link:not(.active):hover {
color: #20c997;
}
#footer .nav .nav-item .nav-link:focus {
color: #20c997;
}
#footer .nav .nav-link:hover {
color: #20c997;
}
#footer .footer-copyright .nav .nav-link:hover {
color: #20c997;
}
/* Back to Top */
#back-to-top:hover {
background-color: #20c997;
}
/* Extras */
.bg-primary, .badge-primary {
background-color: #20c997 !important;
}
.text-primary, .btn-light, .btn-outline-light:hover, .btn-link, .btn-outline-light:not(:disabled):not(.disabled).active, .btn-outline-light:not(:disabled):not(.disabled):active {
color: #20c997 !important;
}
.btn-link:hover {
color: #1baa80 !important;
}
.text-muted {
color: #8e9a9d !important;
}
.text-light {
color: #dee3e4 !important;
}
a.bg-primary:focus, a.bg-primary:hover, button.bg-primary:focus, button.bg-primary:hover {
background-color: #1baa80 !important;
}
.border-primary {
border-color: #20c997 !important;
}
.btn-primary {
background-color: #20c997;
border-color: #20c997;
}
.btn-primary:hover {
background-color: #1baa80;
border-color: #1baa80;
}
.btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active {
background-color: #1baa80;
border-color: #1baa80;
}
.btn-primary.focus, .btn-primary:focus {
background-color: #1baa80;
border-color: #1baa80;
}
.btn-outline-primary, .btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active {
color: #20c997;
border-color: #20c997;
}
.btn-outline-primary:hover, .btn-outline-primary:not(:disabled):not(.disabled).active:hover, .btn-outline-primary:not(:disabled):not(.disabled):active:hover {
background-color: #20c997;
border-color: #20c997;
color: #fff;
}
.progress-bar,
.nav-pills .nav-link.active, .nav-pills .show > .nav-link, .dropdown-item.active, .dropdown-item:active {
background-color: #20c997;
}
.page-item.active .page-link,
.custom-radio .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label::before,
.custom-checkbox .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label:before {
background-color: #20c997;
border-color: #20c997;
}
.list-group-item.active {
background-color: #20c997;
border-color: #20c997;
}
.page-link {
color: #20c997;
}
.page-link:hover {
color: #1baa80;
}
-159
View File
@@ -1,159 +0,0 @@
/*============================
COLOR Yellow
==============================*/
::selection {
background: #ffc107;
}
a, a:focus {
color: #ffc107;
}
a:hover, a:active {
color: #f7b900;
}
.primary-menu ul.navbar-nav > li:hover > a:not(.btn), .primary-menu ul.navbar-nav > li > a.active:not(.btn) {
color: #ffc107;
}
.primary-menu ul.navbar-nav > li.dropdown .dropdown-menu li:hover > a:not(.btn) {
color: #ffc107;
}
.primary-menu.navbar-line-under-text ul.navbar-nav > li > a:not(.btn):after {
border-color: #ffc107;
}
/*=== Side Navigation ===*/
.idocs-navigation .nav .nav .nav-item .nav-link.active:after, .idocs-navigation.docs-navigation-dark .nav .nav .nav-item .nav-link.active:after {
border-color: #ffc107;
}
/* Accordion & Toggle */
.accordion .card-header a:hover.collapsed {
color: #ffc107 !important;
}
.accordion:not(.accordion-alternate) .card-header a {
background-color: #ffc107;
color: #fff;
}
/* Nav */
.nav:not(.nav-pills) .nav-item .nav-link.active, .nav:not(.nav-pills) .nav-item .nav-link:hover {
color: #ffc107;
}
.nav-tabs .nav-item .nav-link.active {
color: #0c2f55;
}
.nav-tabs .nav-item .nav-link.active:after {
background-color: #ffc107;
}
.nav-tabs .nav-item .nav-link:not(.active):hover {
color: #ffc107;
}
.nav-tabs.flex-column .nav-item .nav-link.active {
color: #ffc107;
}
.nav-pills .nav-link:not(.active):hover {
color: #ffc107;
}
#footer .nav .nav-item .nav-link:focus {
color: #ffc107;
}
#footer .nav .nav-link:hover {
color: #ffc107;
}
#footer .footer-copyright .nav .nav-link:hover {
color: #ffc107;
}
/* Back to Top */
#back-to-top:hover {
background-color: #ffc107;
}
/* Extras */
.bg-primary, .badge-primary {
background-color: #ffc107 !important;
}
.text-primary, .btn-light, .btn-outline-light:hover, .btn-link, .btn-outline-light:not(:disabled):not(.disabled).active, .btn-outline-light:not(:disabled):not(.disabled):active {
color: #ffc107 !important;
}
.btn-link:hover {
color: #f7b900 !important;
}
.text-muted {
color: #8e9a9d !important;
}
.text-light {
color: #dee3e4 !important;
}
a.bg-primary:focus, a.bg-primary:hover, button.bg-primary:focus, button.bg-primary:hover {
background-color: #f7b900 !important;
}
.border-primary {
border-color: #ffc107 !important;
}
.btn-primary {
background-color: #ffc107;
border-color: #ffc107;
}
.btn-primary:hover {
background-color: #f7b900;
border-color: #f7b900;
}
.btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active {
background-color: #f7b900;
border-color: #f7b900;
}
.btn-primary.focus, .btn-primary:focus {
background-color: #f7b900;
border-color: #f7b900;
}
.btn-outline-primary, .btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active {
color: #ffc107;
border-color: #ffc107;
}
.btn-outline-primary:hover, .btn-outline-primary:not(:disabled):not(.disabled).active:hover, .btn-outline-primary:not(:disabled):not(.disabled):active:hover {
background-color: #ffc107;
border-color: #ffc107;
color: #fff;
}
.progress-bar,
.nav-pills .nav-link.active, .nav-pills .show > .nav-link, .dropdown-item.active, .dropdown-item:active {
background-color: #ffc107;
}
.page-item.active .page-link,
.custom-radio .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label::before,
.custom-checkbox .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label:before {
background-color: #ffc107;
border-color: #ffc107;
}
.list-group-item.active {
background-color: #ffc107;
border-color: #ffc107;
}
.page-link {
color: #ffc107;
}
.page-link:hover {
color: #f7b900;
}
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

-162
View File
@@ -1,162 +0,0 @@
/*
================================================================
* Template: iDocs - One Page Documentation HTML Template
* Written by: Harnish Design - (http://www.harnishdesign.net)
* Description: Main Custom Script File
================================================================
*/
(function ($) {
"use strict";
// Preloader
$(window).on('load', function () {
$('.lds-ellipsis').fadeOut(); // will first fade out the loading animation
$('.preloader').delay(333).fadeOut('slow'); // will fade out the white DIV that covers the website.
$('body').delay(333);
});
/*-------------------------------
Primary Menu
--------------------------------- */
// Dropdown show on hover
$('.primary-menu ul.navbar-nav li.dropdown, .login-signup ul.navbar-nav li.dropdown').on("mouseover", function() {
if ($(window).width() > 991) {
$(this).find('> .dropdown-menu').stop().slideDown('fast');
$(this).bind('mouseleave', function() {
$(this).find('> .dropdown-menu').stop().css('display', 'none');
});
}
});
// When dropdown going off to the out of the screen.
$('.primary-menu ul.navbar-nav .dropdown-menu').each(function() {
var menu = $('#header .container-fluid').offset();
var dropdown = $(this).parent().offset();
var i = (dropdown.left + $(this).outerWidth()) - (menu.left + $('#header .container-fluid').outerWidth());
if (i > 0) {
$(this).css('margin-left', '-' + (i + 5) + 'px');
}
});
$(function () {
$(".dropdown li").on('mouseenter mouseleave', function (e) {
if ($(window).width() > 991) {
var elm = $('.dropdown-menu', this);
var off = elm.offset();
var l = off.left;
var w = elm.width();
var docW = $(window).width();
var isEntirelyVisible = (l + w + 30 <= docW);
if (!isEntirelyVisible) {
$(elm).addClass('dropdown-menu-right');
} else {
$(elm).removeClass('dropdown-menu-right');
}
}
});
});
// DropDown Arrow
$('.primary-menu ul.navbar-nav').find('a.dropdown-toggle').append($('<i />').addClass('arrow'));
// Mobile Collapse Nav
$('.primary-menu .navbar-nav .dropdown-toggle[href="#"], .primary-menu .dropdown-toggle[href!="#"] .arrow').on('click', function(e) {
if ($(window).width() < 991) {
e.preventDefault();
var $parentli = $(this).closest('li');
$parentli.siblings('li').find('.dropdown-menu:visible').slideUp();
$parentli.find('> .dropdown-menu').stop().slideToggle();
$parentli.siblings('li').find('a .arrow.show').toggleClass('show');
$parentli.find('> a .arrow').toggleClass('show');
}
});
// Mobile Menu
$('.navbar-toggler').on('click', function() {
$(this).toggleClass('show');
});
/*------------------------
Side Navigation
-------------------------- */
$('#sidebarCollapse').on('click', function () {
$('#sidebarCollapse span:nth-child(3)').toggleClass('w-50');
$('.idocs-navigation').toggleClass('active');
});
/*------------------------
Sections Scroll
-------------------------- */
$('.smooth-scroll,.idocs-navigation a').on('click', function() {
event.preventDefault();
var sectionTo = $(this).attr('href');
$('html, body').stop().animate({
scrollTop: $(sectionTo).offset().top - 120}, 1000, 'easeInOutExpo');
});
/*-----------------------------
Magnific Popup
------------------------------- */
// Image on Modal
$('.popup-img').each(function() {
$(this).magnificPopup({
type: "image",
tLoading: '<div class="preloader"><div class="lds-ellipsis"><div></div><div></div><div></div><div></div></div></div>',
closeOnContentClick: !0,
mainClass: "mfp-fade",
});
});
// YouTube/Viemo Video & Gmaps
$('.popup-youtube, .popup-vimeo, .popup-gmaps').each(function() {
$(this).magnificPopup({
type: 'iframe',
mainClass: 'mfp-fade',
});
});
/*------------------------
Highlight Js
-------------------------- */
hljs.initHighlightingOnLoad();
/*------------------------
tooltips
-------------------------- */
$('[data-toggle=\'tooltip\']').tooltip({container: 'body'});
/*------------------------
Scroll to top
-------------------------- */
$(function () {
$(window).on('scroll', function(){
if ($(this).scrollTop() > 400) {
$('#back-to-top').fadeIn();
} else {
$('#back-to-top').fadeOut();
}
});
});
$('#back-to-top').on("click", function() {
$('html, body').animate({scrollTop:0}, 'slow');
return false;
});
})(jQuery)
-537
View File
@@ -1,537 +0,0 @@
/* =================================== */
/* 5. Elements
/* =================================== */
/*=== 5.1 List Style ===*/
.list-style-1 > li {
position: relative;
list-style-type: none;
line-height: 24px;
&:after {
content: " ";
position: absolute;
top: 12px;
left: -15px;
border-color: #000;
border-top: 1px solid;
border-right: 1px solid;
width: 6px;
height: 6px;
-webkit-transform: translate(-50%, -50%) rotate(45deg);
transform: translate(-50%, -50%) rotate(45deg);
}
}
.list-style-2{padding:0;}
.list-style-2 > li {
list-style-type: none;
border-bottom: 1px solid #eaeaea;
padding-top: 12px;
padding-bottom: 12px;
}
.list-style-2.list-style-light > li {
border-bottom: 1px solid rgba(250,250,250,0.12);
}
/*=== 5.2 Changelog ===*/
.changelog {
list-style: none;
padding: 0;
.badge {
width: 90px;
margin-right: 10px;
border-radius: .20rem;
text-transform: uppercase;
}
li {
line-height: 1.8;
}
}
/*=== 5.3 Accordion & Toggle ===*/
.accordion {
.card {
border: none;
margin-bottom: 16px;
margin-bottom: 1rem;
background-color: transparent;
}
.card-header {
padding: 0;
border: none;
background: none;
a {
font-size: 16px;
font-weight:normal;
padding: 1rem 1.25rem 1rem 2.25rem;
display: block;
border-radius: 4px;
position: relative;
&:hover{
text-decoration:none;
}
&:hover.collapsed {
color: $primary-color!important;
}
}
}
&:not(.accordion-alternate) .card-header a {
background-color: $primary-color;
color: #fff;
&.collapsed {
background-color: #f1f2f4;
color: #4c4d4d;
}
}
.card-header a {
&:before {
position: absolute;
content: " ";
left: 20px;
top: calc(50% + 2px);
width: 9px;
height: 9px;
border-color: #CCC;
border-top: 2px solid;
border-right: 2px solid;
-webkit-transform: translate(-50%, -50%) rotate(-45deg);
transform: translate(-50%, -50%) rotate(-45deg);
@include transition(all 0.2s ease);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
&.collapsed:before {
top: calc(50% - 2px);
-webkit-transform: translate(-50%, -50%) rotate(135deg);
transform: translate(-50%, -50%) rotate(135deg);
}
}
.card-body {
line-height: 26px;
}
&.arrow-right .card-header a{
padding-left:1.25rem;
&:before {
right: 15px;
left: auto;
}
}
&.accordion-alternate {
.card {
margin: 0;
}
.card-header a {
padding-left: 1.40rem;
border-top: 1px solid #e4e9ec;
border-radius: 0px;
}
.card:first-of-type .card-header a {
border-top: 0px;
}
.card-header a {
&:before {
left: 6px;
}
&.collapsed {
color: #4c4d4d;
}
}
.card-body {
padding: 0rem 0 1rem 1.25rem;
}
&.arrow-right .card-header a{
padding-left:0;
&:before {
right: 0px;
left: auto;
}
}
}
&.toggle .card-header a {
&:before {
content: "-";
border: none;
font-size: 20px;
height: auto;
top: calc(50% + 2px);
width: auto;
-webkit-transform: translate(-50%, -50%) rotate(180deg);
transform: translate(-50%, -50%) rotate(180deg);
}
&.collapsed:before {
content: "+";
top: calc(50% - 1px);
-webkit-transform: translate(-50%, -50%) rotate(0deg);
transform: translate(-50%, -50%) rotate(0deg);
}
}
&.accordion-alternate.style-2 {
.card-header a {
&:before {
right: 2px;
left: auto;
-webkit-transform: translate(-50%, -50%) rotate(135deg);
transform: translate(-50%, -50%) rotate(135deg);
top: 50%;
}
&.collapsed:before {
-webkit-transform: translate(-50%, -50%) rotate(45deg);
transform: translate(-50%, -50%) rotate(45deg);
}
padding-left: 0px;
}
.card-body {
padding-left: 0px;
}
}
&.accordion-alternate.popularRoutes {
.card-header {
.nav {
margin-top: 3px;
a {
font-size: 14px;
}
}
a {
padding: 0px 8px 0px 0px;
border: none;
font-size: inherit;
&:before {
content: none;
}
}
h5 {
cursor: pointer;
&:before {
position: absolute;
content: " ";
right: 0px;
top: 24px;
width: 10px;
height: 10px;
opacity: 0.6;
border-top: 2px solid;
border-right: 2px solid;
-webkit-transform: translate(-50%, -50%) rotate(-45deg);
transform: translate(-50%, -50%) rotate(-45deg);
-webkit-transition: all 0.2s ease;
transition: all 0.2s ease;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
&.collapsed:before {
top: 24px;
-webkit-transform: translate(-50%, -50%) rotate(135deg);
transform: translate(-50%, -50%) rotate(135deg);
}
}
}
.card-body {
padding: 0;
}
.card {
border-bottom: 2px solid #e4e9ec;
padding: 15px 0px;
}
.routes-list {
margin: 1rem 0px 0px 0px;
padding: 0px;
list-style: none;
a {
color: inherit;
display: -ms-flexbox !important;
display: flex !important;
-ms-flex-align: center !important;
align-items: center !important;
&:hover {
color: #0071cc;
text-decoration: underline;
}
}
}
}
}
/* 5.4 Nav */
.nav .nav-item .nav-link{color: #222222;}
.nav.nav-light .nav-item .nav-link{color: #ddd;}
.nav:not(.nav-pills) .nav-item .nav-link.active, .nav:not(.nav-pills) .nav-item .nav-link:hover{color: $primary-color;}
.nav-pills .nav-link:not(.active):hover{color: $primary-color;}
.nav-pills .nav-link.active,.nav-pills.nav-light .nav-link.active, .nav-pills .show > .nav-link{color:#fff;}
.nav.nav-separator .nav-item .nav-link{position:relative;}
.nav.nav-separator .nav-item + .nav-item .nav-link:after{
height: 14px;
width: 1px;
content: ' ';
background-color: rgba(0,0,0,0.2);
display: block;
position: absolute;
top: 50%;
left: 0;
@include translateY(-7px);
}
.nav.nav-separator.nav-separator-light .nav-item + .nav-item .nav-link:after{
background-color: rgba(250,250,250,0.2);
}
.nav.nav-sm .nav-item .nav-link{font-size:14px;}
/*=== 5.5 Tabs ===*/
.nav-tabs {
border-bottom: 1px solid #d7dee3;
.nav-item .nav-link {
border:0;
background: transparent;
position: relative;
border-radius: 0;
padding:0.6rem 1rem;
color: #7b8084;
white-space: nowrap !important;
&.active {
&:after {
height: 2px;
width: 100%;
content: ' ';
background-color: $primary-color;
display: block;
position: absolute;
bottom: -3px;
left: 0;
@include translateY(-3px);
}
color: #0c2f55;
}
&:not(.active):hover {
color: $primary-color;
}
}
&.flex-column {
border-right: 1px solid #d7dee3;
border-bottom: 0px;
padding: 1.5rem 0;
.nav-item {
.nav-link {
border: 1px solid #d7dee3;
border-right: 0px;
background-color: #f6f7f8;
font-size: 14px;
padding: 0.75rem 1rem;
color: #535b61;
}
&:first-of-type .nav-link {
border-top-left-radius: 4px;
}
&:last-of-type .nav-link {
border-bottom-left-radius: 4px;
}
.nav-link.active {
&:after {
height: 100%;
width: 2px;
background: #fff;
right: -1px;
left: auto;
}
background-color: transparent;
color: $primary-color;
}
}
}
}
.nav-tabs:not(.flex-column) {
.nav-item {
margin-bottom: 0px;
}
flex-wrap: nowrap;
overflow: hidden;
overflow-x: auto;
-ms-overflow-style: -ms-autohiding-scrollbar;
-webkit-overflow-scrolling: touch;
}
@include media-breakpoint-down(xs) {
.nav-tabs .nav-item .nav-link {
padding-left: 0px;
padding-right: 0px;
margin-right: 10px;
font-size: 0.875rem;
}
}
/*=== 5.6 Popup Img ===*/
.popup-img img{@include transition(all 0.2s ease-in-out);}
.popup-img:hover img{
opacity:0.8;
cursor: -webkit-zoom-in;
cursor: -moz-zoom-in;
cursor: zoom-in;
}
/*=== 5.7 Featured Box ===*/
.featured-box {
box-sizing: border-box;
position: relative;
h3, h4 {
font-size: 1.25rem;
font-size: 20px;
margin-bottom: 10px;
font-weight: 500;
}
&:not(.style-5) .featured-box-icon {
display: inline-block;
font-size: 48px;
min-width: 55px;
min-height: 55px;
padding: 0;
margin-top: 0;
margin-bottom: 0.8rem;
color: #4c4d4d;
border-radius: 0;
}
&.style-1, &.style-2, &.style-3 {
padding-left: 50px;
padding-top: 8px;
}
&.style-1 .featured-box-icon, &.style-2 .featured-box-icon, &.style-3 .featured-box-icon {
position: absolute;
top: 0;
left: 0;
margin-bottom: 0;
font-size: 30px;
-ms-flex-pack: center !important;
justify-content: center !important;
text-align: center;
}
&.style-2 p {
margin-left: -50px;
}
&.style-3 {
padding-left: 90px;
padding-top: 0px;
.featured-box-icon {
width: 70px;
height: 70px;
-ms-flex-negative: 0;
flex-shrink: 0;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
}
&.style-4 {
text-align: center;
.featured-box-icon {
margin: 0 auto 24px;
margin: 0 auto 1.5rem;
width: 120px;
height: 120px;
text-align: center;
-ms-flex-negative: 0;
flex-shrink: 0;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-ms-flex-pack: center;
justify-content: center;
@include box-shadow(0px 0px 50px rgba(0, 0, 0, 0.03));
}
}
&.style-5 {
text-align: center;
background: #fff;
border: 1px solid #f0f2f3;
@include box-shadow(0px 2px 5px rgba(0, 0, 0, 0.05));
@include transition(all 0.3s ease-in-out);
&:hover {
border: 1px solid #ebeded;
@include box-shadow(0px 5px 1.5rem rgba(0, 0, 0, 0.15));
}
h3 {
background: #f1f5f6;
font-size: 16px;
padding: 8px 0;
margin-bottom: 0px;
}
.featured-box-icon {
font-size: 50px;
margin: 44px 0px;
}
}
}
@mixin featured-box-reverse {
text-align:right;
&.style-1, &.style-2{
padding-right:50px;
padding-left:0px;
.featured-box-icon{
left:auto;
right:0px;
}
}
&.style-2 p{
margin-right: -50px;
margin-left:0;
}
&.style-3{
padding-left:0;
padding-right:90px;
.featured-box-icon{
left:auto;
right:0px;
}
}
}
.featured-box.featured-box-reverse{
@include featured-box-reverse;
}
@include media-breakpoint-up(xs) {
.featured-box.featured-box-reverse-sm{
@include featured-box-reverse;
}
}
@include media-breakpoint-up(sm) {
.featured-box.featured-box-reverse-md{
@include featured-box-reverse;
}
}
@include media-breakpoint-up(md) {
.featured-box.featured-box-reverse-lg{
@include featured-box-reverse;
}
}
@include media-breakpoint-up(lg) {
.featured-box.featured-box-reverse-xl{
@include featured-box-reverse;
}
}
-448
View File
@@ -1,448 +0,0 @@
/* =================================== */
/* Extras
/* =================================== */
/* Bootstrap Specific */
.form-control, .custom-select {
border-color: #dae1e3;
font-size: 16px;
color: #656565;
}
.form-control:not(.form-control-sm) {
padding: .810rem .96rem;
height:inherit;
}
.form-control-sm{font-size:14px;}
.icon-inside {
position: absolute;
right: 15px;
top: calc(50% - 11px);
pointer-events: none;
font-size: 18px;
font-size: 1.125rem;
color: #c4c3c3;
z-index:3;
}
.form-control-sm + .icon-inside {
font-size: 0.875rem !important;
font-size: 14px;
top: calc(50% - 13px);
}
select.form-control:not([size]):not([multiple]):not(.form-control-sm) {
height: auto;
padding-top: .700rem;
padding-bottom: .700rem;
}
.custom-select:not(.custom-select-sm){
height:calc(3.05rem + 2px);
padding-top: .700rem;
padding-bottom: .700rem;}
.col-form-label-sm{font-size:13px;}
.custom-select-sm{padding-left:5px!important; font-size:14px;}
.custom-select:not(.custom-select-sm).border-0{height:3.00rem;}
.form-control:focus, .custom-select:focus{
@include box-shadow(0 0 5px rgba(128, 189, 255, 0.5));
}
.form-control:focus[readonly]{box-shadow:none;}
.input-group-text {
border-color: #dae1e3;
background-color:#f1f5f6;
color: #656565;
}
.form-control {
&::-webkit-input-placeholder {
color: #b1b4b6;
}
&:-moz-placeholder {
/* FF 4-18 */
color: #b1b4b6;
}
&::-moz-placeholder {
/* FF 19+ */
color: #b1b4b6;
}
&:-ms-input-placeholder, &::-ms-input-placeholder {
/* IE 10+ */
color: #b1b4b6;
}
}
/* Form Dark */
.form-dark {
.form-control, .custom-select {
border-color: #232a31;
background:#232a31;
color: #fff;
}
.form-control:focus{border-color: #80bdff!important;}
.form-control {
&::-webkit-input-placeholder {
color: #777b7f;
}
&:-moz-placeholder {
/* FF 4-18 */
color: #777b7f;
}
&::-moz-placeholder {
/* FF 19+ */
color: #777b7f;
}
&:-ms-input-placeholder, &::-ms-input-placeholder {
/* IE 10+ */
color: #777b7f;
}
}
.custom-select {
color: #777b7f;
background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='rgba(250,250,250,0.3)' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right 0.75rem center;
background-size: 13px 15px;
border-color: #232a31;
background-color:#232a31;
}
.icon-inside {
color: #777b7f;
}
}
/* Input with only bottom border */
.form-border {
.form-control {
background-color: transparent;
border: none;
border-bottom: 2px solid rgba(0, 0, 0, 0.12);
border-radius: 0px;
padding-left: 0px!important;
color: rgba(0, 0, 0, 1);
&::-webkit-input-placeholder {
color: rgba(0, 0, 0, 0.4);
}
&:-moz-placeholder {
/* FF 4-18 */
color: rgba(0, 0, 0, 0.4);
}
&::-moz-placeholder {
/* FF 19+ */
color: rgba(0, 0, 0, 0.4);
}
&:-ms-input-placeholder, &::-ms-input-placeholder {
/* IE 10+ */
color: rgba(0, 0, 0, 0.4);
}
}
.custom-select {
background-color: transparent;
border: none;
border-bottom: 2px solid rgba(0, 0, 0, 0.12);
border-radius: 0px;
padding-left: 0px;
color: rgba(0, 0, 0, 0.4);
background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='rgba(0,0,0,0.3)' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right 0.75rem center;
background-size: 13px 15px;
}
.form-control:focus, .custom-select:focus {
box-shadow: none;
-webkit-box-shadow: none;
border-bottom: 2px solid rgba(0, 0, 0, 0.7);
}
.form-control:not(output):-moz-ui-invalid, .custom-select:not(output):-moz-ui-invalid {
&:not(:focus), &:-moz-focusring:not(:focus) {
border-bottom: 2px solid #b00708;
box-shadow: none;
-webkit-box-shadow: none;
}
}
.icon-inside {
color: rgba(0, 0, 0, 0.25);
}
select option {
color: #666;
}
}
.form-border-light {
.form-control {
border-bottom: 2px solid rgba(250, 250, 250, 0.3);
color: rgba(250, 250, 250, 1);
&::-webkit-input-placeholder {
color: rgba(250, 250, 250, 0.7);
}
&:-moz-placeholder {
/* FF 4-18 */
color: rgba(250, 250, 250, 0.7);
}
&::-moz-placeholder {
/* FF 19+ */
color: rgba(250, 250, 250, 0.7);
}
&:-ms-input-placeholder, &::-ms-input-placeholder {
/* IE 10+ */
color: rgba(250, 250, 250, 0.7);
}
}
.custom-select {
border-bottom: 2px solid rgba(250, 250, 250, 0.3);
color: rgba(250, 250, 250, 1);
background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='rgba(250,250,250,0.6)' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right 0.75rem center;
background-size: 13px 15px;
}
.form-control:focus, .custom-select:focus {
border-bottom: 2px solid rgba(250, 250, 250, 0.8);
}
.icon-inside {
color: #999;
}
select option {
color: #333;
}
}
.input-group-append .btn, .input-group-prepend .btn {
@include box-shadow(none);
padding-left: 0.75rem;
padding-right: 0.75rem;
}
.input-group-append .btn:hover, .input-group-prepend .btn:hover {
@include box-shadow(none);
}
@include media-breakpoint-down(xs) {
.input-group > {
.input-group-append > .btn, .input-group-prepend > .btn {
padding: 0 0.75rem;
}
}
}
.bg-primary, .badge-primary {
background-color: $primary-color !important;
}
.bg-secondary {
background-color: $secondary-color !important;
}
.text-primary, .btn-light, .btn-outline-light:hover, .btn-link, .btn-outline-light:not(:disabled):not(.disabled).active, .btn-outline-light:not(:disabled):not(.disabled):active {
color: $primary-color !important;
}
.btn-link:hover {
color: $primary-color-hover !important;
}
.text-secondary{
color: $secondary-color !important;
}
.text-light{
color:#dee3e4!important;
}
.text-body{
color: $text-color !important;
}
a.bg-primary:focus, a.bg-primary:hover, button.bg-primary:focus, button.bg-primary:hover{background-color: $primary-color-hover!important;}
.border-primary {
border-color: $primary-color !important;
}
.border-secondary {
border-color: $secondary-color !important;
}
.btn-primary{
background-color: $primary-color;
border-color: $primary-color;
&:hover {
background-color: $primary-color-hover;
border-color: $primary-color-hover;
}
}
.btn-primary:not(:disabled):not(.disabled).active, .btn-primary:not(:disabled):not(.disabled):active{
background-color: $primary-color-hover;
border-color: $primary-color-hover;
}
.btn-primary.focus, .btn-primary:focus{
background-color: $primary-color-hover;
border-color: $primary-color-hover;
}
.btn-primary:not(:disabled):not(.disabled).active:focus, .btn-primary:not(:disabled):not(.disabled):active:focus, .show > .btn-primary.dropdown-toggle:focus{
@include box-shadow(none);
}
.btn-secondary {
background-color: $secondary-color;
border-color: $secondary-color;
}
.btn-outline-primary, .btn-outline-primary:not(:disabled):not(.disabled).active, .btn-outline-primary:not(:disabled):not(.disabled):active{
color: $primary-color;
border-color: $primary-color;
&:hover {
background-color: $primary-color;
border-color: $primary-color;
color: #fff;
}
}
.btn-outline-secondary{
color: $secondary-color;
border-color: $secondary-color;
&:hover {
background-color: $secondary-color;
border-color: $secondary-color;
color: #fff;
}
}
.progress-bar,
.nav-pills .nav-link.active, .nav-pills .show > .nav-link, .dropdown-item.active, .dropdown-item:active{
background-color: $primary-color;
}
.page-item.active .page-link,
.custom-radio .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label::before,
.custom-checkbox .custom-control-input:checked ~ .custom-control-label:before,
.custom-control-input:checked ~ .custom-control-label:before{
background-color: $primary-color;
border-color: $primary-color;
}
.list-group-item.active{
background-color: $primary-color;
border-color: $primary-color;
}
.page-link {
color: $primary-color;
&:hover {
color: $primary-color-hover;
}
}
/* Pagination */
.page-link {
border: none;
border-radius: 0.25rem;
margin: 0 0.22rem;
font-size: 16px;
font-size: 1rem;
&:hover {
background-color: #e9eff0;
}
}
/* Vertical Multilple input group */
.vertical-input-group .input-group {
&:first-child {
padding-bottom: 0;
* {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
&:last-child {
padding-top: 0;
* {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
}
&:not(:last-child):not(:first-child) {
padding-top: 0;
padding-bottom: 0;
* {
border-radius: 0;
}
}
&:not(:first-child) * {
border-top: 0;
}
}
/* styles-switcher */
#styles-switcher {
background: #fff;
width: 202px;
position: fixed;
top: 35%;
z-index: 99;
padding: 20px;
left: -202px;
ul {
padding: 0;
li {
list-style-type: none;
width: 25px;
height: 25px;
margin: 4px 2px;
border-radius: 50%;
display: inline-block;
cursor: pointer;
transition: all .2s ease-in-out;
&.blue {
background: #007bff;
}
&.brown {
background: #795548;
}
&.purple {
background: #6f42c1;
}
&.indigo {
background: #6610f2;
}
&.red {
background: #dc3545;
}
&.orange {
background: #fd7e14;
}
&.yellow {
background: #ffc107;
}
&.green {
background: #28a745;
}
&.teal {
background: #20c997;
}
&.cyan {
background: #17a2b8;
}
&.active {
transform: scale(0.7);
cursor:default;
}
}
}
.switcher-toggle {
position: absolute;
background: #333;
color: #fff;
font-size: 1.25rem;
border-radius: 0px 4px 4px 0;
right: -40px;
top: 0;
width: 40px;
height: 40px;
padding: 0;
}
#reset-color{background: #e83e8c;}
}
input:-internal-autofill-selected {
background-color: transparent;
}
#styles-switcher.right{left:auto; right: -202px;}
#styles-switcher.right .switcher-toggle{right: auto; left: -40px; border-radius: 4px 0px 0px 4px;}
-188
View File
@@ -1,188 +0,0 @@
/* =================================== */
/* 6. Footer
/* =================================== */
#footer {
background: #fff;
color: #252b33;
margin-left:260px;
padding: 66px 0px;
padding: 4.125rem 0;
.nav {
.nav-item {
display: inline-block;
line-height: 12px;
margin: 0;
.nav-link {
color: #252b33;
-webkit-transition: all 0.2s ease;
transition: all 0.2s ease;
&:focus {
color: $primary-color;
-webkit-transition: all 0.2s ease;
transition: all 0.2s ease;
}
}
&:first-child .nav-link {
padding-left: 0px;
}
&:last-child .nav-link{
padding-right: 0px;
}
}
.nav-link:hover {
color: $primary-color;
-webkit-transition: all 0.2s ease;
transition: all 0.2s ease;
}
}
.footer-copyright {
border-top: 1px solid #e2e8ea;
padding: 0px 0px;
color: #67727c;
.nav {
.nav-item .nav-link {
color: #67727c;
}
.nav-link:hover {
color: $primary-color;
-webkit-transition: all 0.2s ease;
transition: all 0.2s ease;
}
}
}
.nav.flex-column .nav-item {
padding: 0px;
.nav-link {
margin: 0.7rem 0px;
}
}
&.footer-text-light {
color: rgba(250, 250, 250, 0.8);
.nav .nav-item .nav-link {
color: rgba(250, 250, 250, 0.8);
&:hover {
color: rgba(250, 250, 250, 1);
}
}
.footer-copyright {
border-color: rgba(250, 250, 250, 0.15);
color: rgba(250, 250, 250, 0.5);
}
&:not(.bg-primary) .social-icons-light.social-icons li a {
color: rgba(250, 250, 250, 0.8);
&:hover {
color: rgba(250, 250, 250, 1);
}
}
&.bg-primary {
color: #fff;
.nav .nav-item .nav-link {
color: #fff;
&:hover {
color: rgba(250, 250, 250, 0.7);
}
}
.footer-copyright {
border-color: rgba(250, 250, 250, 0.15);
color: rgba(250, 250, 250, 0.9);
}
:not(.social-icons) a {
color: #fff;
&:hover {
color: rgba(250, 250, 250, 0.7);
}
}
}
}
}
@include media-breakpoint-down(sm) {
#footer {
margin-left:0px;
}
}
/*=== 6.1 Social Icons ===*/
.social-icons {
margin: 0;
padding: 0;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
list-style: none;
li {
margin: 0px 6px;
padding: 0;
overflow: visible;
a {
display: block;
height: 26px;
line-height: 26px;
width: 26px;
font-size: 18px;
text-align: center;
color: #4d555a;
text-decoration: none;
@include transition(all 0.2s ease);
}
i {
line-height: inherit;
}
}
&.social-icons-sm li{
margin: 0px 4px;
}
&.social-icons-sm li a {
font-size: 15px;
width:22px;
}
&.social-icons-lg li a {
width: 34px;
height: 34px;
line-height:34px;
font-size: 22px;
}
&.social-icons-light li a {
color: #eee;
}
&.social-icons-muted li a {
color: #aab1b8;
}
li:hover {
a {
color: #999;
}
}
}
/*=== 6.2 Back to Top ===*/
#back-to-top {
display: none;
position: fixed;
z-index: 1030;
bottom: 8px;
right: 10px;
background-color: rgba(0, 0, 0, 0.22);
text-align: center;
color: #fff;
font-size: 14px;
width: 36px;
height: 36px;
line-height: 34px;
border-radius:3px;
@include transition(all 0.3s ease-in-out);
@include box-shadow(0px 5px 15px rgba(0, 0, 0, 0.15));
&:hover {
background-color: $primary-color;
@include box-shadow(0px 5px 15px rgba(0, 0, 0, 0.25));
@include transition(all 0.3s ease-in-out);
}
}
@include media-breakpoint-down(xs) {
#back-to-top {z-index: 1029;}
}
-554
View File
@@ -1,554 +0,0 @@
/* =================================== */
/* 4. Header
/* =================================== */
#header {
@include transition(all .5s ease);
.navbar {
padding: 0px;
min-height:70px;
}
.logo {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-item-align: stretch;
align-self: stretch;
}
}
/*=== 4.1 Main Navigation ===*/
.navbar-light .navbar-nav {
.active > .nav-link {
color: #0c2f55;
}
.nav-link {
&.active, &.show {
color: #0c2f55;
}
}
.show > .nav-link {
color: #0c2f55;
}
}
.primary-menu {
display: -webkit-box !important;
display: -ms-flexbox !important;
display: flex !important;
height: auto !important;
-webkit-box-ordinal-group: 0;
-ms-flex-item-align: stretch;
align-self: stretch;
background: #fff;
border-bottom:1px solid #efefef;
&.bg-transparent {
position: absolute;
z-index: 999;
top: 0;
left: 0;
width: 100%;
box-shadow: none;
border-bottom: 1px solid rgba(250, 250, 250, 0.3);
}
&.sticky-on{
position: fixed;
top: 0;
width: 100%;
z-index: 1020;
left: 0;
@include box-shadow(0px 0px 10px rgba(0, 0, 0, 0.05));
-webkit-animation: slide-down 0.7s;
-moz-animation: slide-down 0.7s;
animation: slide-down 0.7s;
@-webkit-keyframes slide-down { 0% { opacity:0; transform:translateY(-100%);}100% { opacity:1; transform:translateY(0);}}
@-moz-keyframes slide-down { 0% { opacity:0; transform:translateY(-100%);}100% { opacity:1; transform:translateY(0);}}
@keyframes slide-down { 0% { opacity:0; transform:translateY(-100%);}100% { opacity:1; transform:translateY(0);}}
.none-on-sticky{
display:none!important;
}
}
ul.navbar-nav > li {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
height: 100%;
+ li {
margin-left: 2px;
}
a {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
> a:not(.btn) {
height: 70px;
padding:0px 0.85em;
color: #252b33;
@include transition(all .2s ease);
position: relative;
position:relative;
}
&:hover > a:not(.btn), & > a.active:not(.btn) {
color: $primary-color;
text-decoration:none;
@include transition(all .2s ease);
}
a.btn{padding: 0.4rem 1.4rem;}
&.dropdown {
.dropdown-menu li {
> a:not(.btn) {
padding: 8px 0px;
background-color: transparent;
text-transform: none;
color: #777;
@include transition(all .2s ease);
}
&:hover > a:not(.btn) {
color: $primary-color;
@include transition(all .2s ease);
}
}
&:hover > a:after {
clear: both;
content: ' ';
display: block;
width: 0;
height: 0;
border-style: solid;
border-color: transparent transparent #fff transparent;
position: absolute;
border-width: 0px 7px 6px 7px;
bottom: 0px;
left: 50%;
margin: 0 0 0 -5px;
z-index: 1022;
}
.dropdown-menu {
@include box-shadow(0px 0px 12px rgba(0, 0, 0, 0.176));
border: 0px none;
padding: 10px 15px;
min-width: 220px;
margin: 0;
font-size: 14px;
font-size: 0.875rem;
z-index:1021;
}
> .dropdown-toggle .arrow {
display: none;
}
}
}
.dropdown-menu-right {
left: auto !important;
right: 100% !important;
}
ul.navbar-nav > li {
&.dropdown-mega {
position: static;
> .dropdown-menu {
width: 100%;
padding: 20px 20px;
margin-left: 0px !important;
}
.dropdown-mega-content > .row > div {
padding: 5px 5px 5px 20px;
border-right: 1px solid #eee;
&:last-child {
border-right: 0;
}
}
.sub-title {
display: block;
font-size: 16px;
margin-top: 1rem;
padding-bottom: 5px;
}
.dropdown-mega-submenu {
list-style-type: none;
padding-left: 0px;
}
}
a.btn{font-size:14px; padding: 0.65rem 2rem; text-transform:uppercase;}
&.dropdown {
.dropdown-menu {
.dropdown-menu {
left: 100%;
margin-top: -40px;
}
.dropdown-toggle:after {
border-top: .4em solid transparent;
border-right: 0;
border-bottom: 0.4em solid transparent;
border-left: 0.4em solid;
}
}
.dropdown-toggle .arrow {
position: absolute;
min-width: 30px;
height: 100%;
right: 0px;
top: 0;
@include transition(all .2s ease);
&:after {
content: " ";
position: absolute;
top: 50%;
left: 50%;
border-color: #000;
border-top: 1px solid;
border-right: 1px solid;
width: 6px;
height: 6px;
-webkit-transform: translate(-50%, -50%) rotate(45deg);
transform: translate(-50%, -50%) rotate(45deg);
}
}
}
}
.dropdown-toggle:after {
content: none;
}
&.navbar-line-under-text ul.navbar-nav > li {
> a:not(.btn):after {
position: absolute;
content: "";
height: 2px;
width: 0;
left: 50%;
right: 0;
bottom: 14px;
background-color: transparent;
color:#fff;
border-bottom: 2px solid $primary-color;
@include transition(all .3s ease-in-out);
transform: translate(-50%,0) translateZ(0);
-webkit-transform: translate(-50%,0) translateZ(0);
}
& > a:hover:not(.logo):after, & > a.active:after{
width:calc(100% - 0.99em);
}
}
}
/*== Color Options ==*/
.primary-menu.navbar-text-light .navbar-toggler span {background:#fff;}
.primary-menu.navbar-text-light .navbar-nav > li{
> a:not(.btn) {
color: #fff;
}
&:hover > a:not(.btn), & > a.active:not(.btn) {
color: rgba(250, 250, 250, 0.75);
}
}
.primary-menu.navbar-text-light.navbar-line-under-text .navbar-nav > li{
& > a:not(.logo):after, & > a.active:after{
border-color:rgba(250, 250, 250, 0.60);
}
}
.primary-menu {
&.navbar-dropdown-dark ul.navbar-nav > li {
&.dropdown {
.dropdown-menu {
background-color: #252A2C;
color: #fff;
.dropdown-menu {
background-color: #272c2e;
}
}
&:hover > a:after {
border-color: transparent transparent #252A2C transparent;
}
.dropdown-menu li {
> a:not(.btn) {
color: rgba(250, 250, 250, 0.8);
}
&:hover > a:not(.btn) {
color: rgba(250, 250, 250, 1);
font-weight:600;
}
}
}
&.dropdown-mega .dropdown-mega-content > .row > div {
border-color: #3a3a3a;
}
}
&.navbar-dropdown-primary ul.navbar-nav > li {
&.dropdown {
.dropdown-menu {
background-color: $primary-color;
color: #fff;
.dropdown-menu {
background-color: $primary-color;
}
}
&:hover > a:after {
border-color: transparent transparent $primary-color transparent;
}
.dropdown-menu li {
> a:not(.btn) {
color: rgba(250, 250, 250, 0.95);
}
&:hover > a:not(.btn) {
color: rgba(250, 250, 250, 1);
font-weight:600;
}
}
}
&.dropdown-mega .dropdown-mega-content > .row > div {
border-color: rgba(250, 250, 250, 0.2);
}
}
}
/* Hamburger Menu Button */
.navbar-toggler {
width: 25px;
height: 30px;
padding: 10px;
margin: 18px 15px;
position: relative;
border:none;
@include rotate(0deg);
@include transition(.5s ease-in-out);
cursor: pointer;
display: block;
span {
display: block;
position: absolute;
height: 2px;
width: 100%;
background: #3c3636;
border-radius: 2px;
opacity: 1;
left: 0;
@include rotate(0deg);
@include transition(.25s ease-in-out);
&:nth-child(1) {
top: 7px;
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
-o-transform-origin: left center;
transform-origin: left center;
}
&:nth-child(2) {
top: 14px;
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
-o-transform-origin: left center;
transform-origin: left center;
}
&:nth-child(3) {
top: 21px;
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
-o-transform-origin: left center;
transform-origin: left center;
}
}
&.show span {
&:nth-child(1) {
top: 4px;
left: 3px;
@include rotate(45deg);
}
&:nth-child(2) {
width: 0%;
opacity: 0;
}
&:nth-child(3) {
top: 22px;
left: 3px;
@include rotate(-45deg);
}
}
}
.navbar-accordion{position:initial;}
// For Responsive Navbar
@mixin navbar-responsive {
.navbar-collapse {
position: absolute;
top: 99%;
right: 0;
left: 0;
background: #fff;
margin-top: 0px;
z-index: 1000;
@include box-shadow(0px 0px 15px rgba(0, 0, 0, 0.1));
.navbar-nav {
overflow: hidden;
overflow-y: auto;
max-height: 65vh;
padding: 15px;
}
}
ul.navbar-nav {
li {
display: block;
border-bottom: 1px solid #eee;
margin: 0;
padding: 0;
&:last-child {
border: none;
}
+ li {
margin-left: 0px;
}
&.dropdown > .dropdown-toggle > .arrow.show:after {
-webkit-transform: translate(-50%, -50%) rotate(-45deg);
transform: translate(-50%, -50%) rotate(-45deg);
@include transition(all .2s ease);
}
> a:hover:after, > a.active:after {
content: none!important;
width:0px!important;
}
&.dropdown{
> .dropdown-toggle .arrow {
display: block;
}
}
}
> li {
> a:not(.btn) {
height: auto;
padding: 8px 0;
position: relative;
}
&.dropdown {
.dropdown-menu li > a:not(.btn) {
padding: 8px 0;
position: relative;
}
&:hover > a:after {
content: none;
}
.dropdown-toggle .arrow:after {
-webkit-transform: translate(-50%, -50%) rotate(134deg);
transform: translate(-50%, -50%) rotate(134deg);
@include transition(all .2s ease);
}
}
}
> li {
&.dropdown .dropdown-menu {
margin: 0;
@include box-shadow(none);
border: none;
padding: 0px 0px 0px 15px;
.dropdown-menu {
margin: 0;
}
}
&.dropdown-mega {
.dropdown-mega-content > .row > div {
padding: 0px 15px;
}
}
}
}
&.navbar-text-light .navbar-collapse{background:rgba(0,0,0,0.95);}
&.navbar-text-light .navbar-collapse ul.navbar-nav li{
border-color:rgba(250,250,250,0.15);
}
&.navbar-dropdown-dark .navbar-collapse {
background-color: #252A2C;
}
&.navbar-dropdown-primary .navbar-collapse {
background-color: $primary-color;
}
&.navbar-dropdown-primary ul.navbar-nav > li.dropdown .dropdown-menu .dropdown-menu {
background-color: $primary-color;
}
&.navbar-dropdown-dark ul.navbar-nav {
li {
border-color: #444;
}
> li {
> a {
color: #a3a2a2;
}
&:hover > a {
color: #fff;
}
}
}
&.navbar-dropdown-primary ul.navbar-nav {
li {
border-color: rgba(250, 250, 250, 0.2);
}
> li {
> a {
color: rgba(250, 250, 250, 0.8);
}
&:hover > a {
color: #fff;
}
}
}
}
.navbar-expand-none{
@include navbar-responsive;
}
@include media-breakpoint-down(xs) {
.navbar-expand-sm{
@include navbar-responsive;
}
}
@include media-breakpoint-down(sm) {
.navbar-expand-md{
@include navbar-responsive;
}
}
@include media-breakpoint-down(md) {
.navbar-expand-lg{
@include navbar-responsive;
}
}
@include media-breakpoint-down(lg) {
.navbar-expand-xl{
@include navbar-responsive;
}
}
-301
View File
@@ -1,301 +0,0 @@
/* =================================== */
/* 2. Helpers Classes
/* =================================== */
/* Box Shadow */
.shadow-md {
@include box-shadow(0px 0px 50px -35px rgba(0, 0, 0, 0.4)!important);
}
/* Border Radius */
.rounded-lg{
border-radius: 0.6rem !important;
}
.rounded-top-0{
border-top-left-radius:0px!important;
border-top-right-radius:0px!important;
}
.rounded-bottom-0{
border-bottom-left-radius:0px!important;
border-bottom-right-radius:0px!important;
}
.rounded-left-0{
border-top-left-radius:0px!important;
border-bottom-left-radius:0px!important;
}
.rounded-right-0{border-top-right-radius:0px!important;
border-bottom-right-radius:0px!important;
}
/* Border Size */
.border-1{
border-width:1px!important;
}
.border-2{
border-width:2px!important;
}
.border-3{
border-width:3px!important;
}
.border-4{
border-width:4px!important;
}
.border-5{
border-width:5px!important;
}
/* Text Size */
.text-0 {
font-size: 11px !important;
font-size: 0.6875rem !important;
}
.text-1 {
font-size: 12px !important;
font-size: 0.75rem !important;
}
.text-2 {
font-size: 14px !important;
font-size: 0.875rem !important;
}
.text-3 {
font-size: 16px !important;
font-size: 1rem !important;
}
.text-4 {
font-size: 18px !important;
font-size: 1.125rem !important;
}
.text-5 {
font-size: 21px !important;
font-size: 1.3125rem !important;
}
.text-6 {
font-size: 24px !important;
font-size: 1.50rem !important;
}
.text-7 {
font-size: 28px !important;
font-size: 1.75rem !important;
}
.text-8 {
font-size: 32px !important;
font-size: 2rem !important;
}
.text-9 {
font-size: 36px !important;
font-size: 2.25rem !important;
}
.text-10 {
font-size: 40px !important;
font-size: 2.50rem !important;
}
.text-11 {
@include rfs(44, true);
}
.text-12 {
@include rfs(48, true);
}
.text-13 {
@include rfs(52, true);
}
.text-14 {
@include rfs(56, true);
}
.text-15 {
@include rfs(60, true);
}
.text-16 {
@include rfs(64, true);
}
.text-17 {
@include rfs(72, true);
}
.text-18 {
@include rfs(80, true);
}
.text-19 {
@include rfs(84, true);
}
.text-20 {
@include rfs(92, true);
}
.text-21 {
@include rfs(104, true);
}
.text-22 {
@include rfs(112, true);
}
.text-23 {
@include rfs(124, true);
}
.text-24 {
@include rfs(132, true);
}
.text-25 {
@include rfs(144, true);
}
.text-11, .text-12, .text-13, .text-14, .text-15, .text-16, .text-17, .text-18, .text-19, .text-20, .text-21, .text-22, .text-23, .text-24, .text-25{
line-height: 1.3;
}
/* Line height */
.line-height-07 {
line-height: 0.7 !important;
}
.line-height-1 {
line-height: 1 !important;
}
.line-height-2 {
line-height: 1.2 !important;
}
.line-height-3 {
line-height: 1.4 !important;
}
.line-height-4 {
line-height: 1.6 !important;
}
.line-height-5 {
line-height: 1.8 !important;
}
/* Font Weight */
.font-weight-100 {
font-weight: 100 !important;
}
.font-weight-200 {
font-weight: 200 !important;
}
.font-weight-300 {
font-weight: 300 !important;
}
.font-weight-400 {
font-weight: 400 !important;
}
.font-weight-500 {
font-weight: 500 !important;
}
.font-weight-600 {
font-weight: 600 !important;
}
.font-weight-700 {
font-weight: 700 !important;
}
.font-weight-800 {
font-weight: 800 !important;
}
.font-weight-900 {
font-weight: 900 !important;
}
/* Opacity */
.opacity-0 {
opacity: 0;
}
.opacity-1 {
opacity: 0.1;
}
.opacity-2 {
opacity: 0.2;
}
.opacity-3 {
opacity: 0.3;
}
.opacity-4 {
opacity: 0.4;
}
.opacity-5 {
opacity: 0.5;
}
.opacity-6 {
opacity: 0.6;
}
.opacity-7 {
opacity: 0.7;
}
.opacity-8 {
opacity: 0.8;
}
.opacity-9 {
opacity: 0.9;
}
.opacity-10 {
opacity: 1;
}
/* Background light */
.bg-light-1 {
background-color: $gray-200 !important;
}
.bg-light-2 {
background-color: $gray-300 !important;
}
.bg-light-3 {
background-color: $gray-400 !important;
}
.bg-light-4 {
background-color: $gray-500 !important;
}
/* Background Dark */
.bg-dark {
background-color: #111418 !important;
}
.bg-dark-1 {
background-color: $gray-900 !important;
}
.bg-dark-2 {
background-color: $gray-800 !important;
}
.bg-dark-3 {
background-color: $gray-700 !important;
}
.bg-dark-4 {
background-color: $gray-600 !important;
}
/* Progress Bar */
.progress-sm {
height: 0.5rem !important;
}
.progress-lg {
height: 1.5rem !important;
}
hr{
border-top:1px solid rgba(16,85,96,.1);
}
-171
View File
@@ -1,171 +0,0 @@
/* =================================== */
/* 3. Layouts
/* =================================== */
#main-wrapper {
background:#fff;
}
.box {
#main-wrapper {
max-width: 1200px;
margin: 0 auto;
@include box-shadow(0px 0px 10px rgba(0, 0, 0, 0.1));
}
.idocs-navigation {
left: auto;
}
}
@include media-breakpoint-up(xl) {
.container {
max-width: 1170px !important;
}
}
/*=== 3.1 Side Navigation ===*/
.idocs-navigation {
position: fixed;
top: 70px;
left: 0;
overflow: hidden;
overflow-y: auto;
width: 260px;
height: calc(100% - 70px);
z-index: 1;
border-right: 1px solid rgba(0, 0, 0, 0.05);
transition: all 0.3s;
> .nav {
padding: 30px 0;
}
.nav {
.nav-item {
position: relative;
}
.nav {
margin: 0 0 5px;
}
.nav-link {
position: relative;
padding: 6px 30px;
line-height: 25px;
font-weight: 600;
}
.nav-item {
&:hover > .nav-link, .nav-link.active {
font-weight: 700;
}
}
.nav {
.nav-item .nav-link {
&:after {
content: "";
position: absolute;
left: 30px;
height: 100%;
border-left: 1px solid rgba(0, 0, 0, 0.12);
width: 1px;
top: 0;
}
&.active:after {
border-color: $primary-color;
border-width: 2px;
}
}
display: none;
border-left: 1px solid regba(0, 0, 0, 0.3);
}
.nav-item .nav-link.active + .nav {
display: block;
}
.nav {
.nav-link {
color: #6a6a6a;
padding: 4px 30px 4px 45px;
font-size: 15px;
text-transform: none;
}
.nav {
.nav-link {
padding: 4px 30px 4px 60px;
font-size: 15px;
}
.nav-item .nav-link:after {
left: 45px;
}
}
}
}
> .nav > .nav-item > .nav-link.active:after {
position: absolute;
content: " ";
top: 50%;
right: 18px;
border-color: #000;
border-top: 2px solid;
border-right: 2px solid;
width: 7px;
height: 7px;
-webkit-transform: translate(-50%, -50%) rotate(45deg);
transform: translate(-50%, -50%) rotate(45deg);
@include transition(all .2s ease);
}
&.docs-navigation-dark .nav {
.nav-link {
color: rgba(250, 250, 250, 0.85);
}
.nav {
.nav-link {
color: rgba(250, 250, 250, 0.7);
}
.nav-item .nav-link {
&:after {
border-color: rgba(250, 250, 250, 0.2);
}
&.active:after {
border-color: $primary-color;
}
}
}
}
}
/*=== 3.2 Docs Content ===*/
.idocs-content {
position: relative;
margin-left: 260px;
padding: 0px 50px 50px;
min-height: 750px;
transition: all 0.3s;
section:first-child {
padding-top: 3rem;
}
ol li, ul li {
margin-top: 10px;
}
}
@include media-breakpoint-down(sm) {
.idocs-navigation {
margin-left: -260px;
&.active {
margin-left: 0;
}
}
.idocs-content {
margin-left:0px;
padding:0px;
}
}
/*=== 3.3 Section Divider ===*/
.divider{margin: 4rem 0;}
-31
View File
@@ -1,31 +0,0 @@
//---------- @mixins ----------//
@mixin box-shadow($val...) {
-webkit-box-shadow: ($val);
box-shadow: ($val);
}
@mixin transition($val...) {
-webkit-transition: ($val);
transition: ($val);
}
@mixin translateY($val...) {
-webkit-transform: translateY($val);
transform: translateY($val);
}
@mixin translateX($val...) {
-webkit-transform: translateX($val);
transform: translateX($val);
}
@mixin rotate($val){
-webkit-transform: rotate($val);
transform: rotate($val);
}
@mixin scale($val){
-webkit-transform: scale($val);
transform: scale($val);
}
-164
View File
@@ -1,164 +0,0 @@
/* =================================== */
/* 1. Basic Style
/* =================================== */
body, html {
height:100%;
}
body {
background: $body-bg;
color: $text-color;
}
/*-------- Preloader --------*/
.preloader {
position: fixed;
width: 100%;
height: 100%;
z-index: 999999999 !important;
background-color: #fff;
top: 0;
left: 0;
right: 0;
bottom: 0;
.lds-ellipsis {
display: inline-block;
position: absolute;
width: 80px;
height: 80px;
margin-top: -40px;
margin-left: -40px;
top: 50%;
left: 50%;
div {
position: absolute;
top: 33px;
width: 13px;
height: 13px;
border-radius: 50%;
background: #000;
animation-timing-function: cubic-bezier(0, 1, 1, 0);
&:nth-child(1) {
left: 8px;
animation: lds-ellipsis1 0.6s infinite;
}
&:nth-child(2) {
left: 8px;
animation: lds-ellipsis2 0.6s infinite;
}
&:nth-child(3) {
left: 32px;
animation: lds-ellipsis2 0.6s infinite;
}
&:nth-child(4) {
left: 56px;
animation: lds-ellipsis3 0.6s infinite;
}
}
}
}
@keyframes lds-ellipsis1 {
0% {
transform: scale(0);
}
100% {
transform: scale(1);
}
}
@keyframes lds-ellipsis3 {
0% {
transform: scale(1);
}
100% {
transform: scale(0);
}
}
@keyframes lds-ellipsis2 {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(24px, 0);
}
}
/*--- Preloader Magnific Popup ----*/
.mfp-container .preloader{
background: transparent;
.lds-ellipsis div{
background: #fff;
}
}
::selection {
background: $primary-color;
color: #fff;
text-shadow: none;
}
code{padding: 2px 5px; background-color: #f9f2f4; border-radius: 4px;}
form {
padding: 0;
margin: 0;
display: inline;
}
img {
vertical-align: inherit;
}
a, a:focus {
color: $primary-color;
@include transition(all .2s ease);
}
a:hover, a:active {
color: $primary-color-hover;
@include transition(all .2s ease);
}
a:focus, a:active,
.btn.active.focus,
.btn.active:focus,
.btn.focus,
.btn:active.focus,
.btn:active:focus,
.btn:focus,
button:focus,
button:active{
outline: none;
}
p {
line-height: 1.8;
}
blockquote {
border-left: 5px solid #eee;
padding: 10px 20px;
}
iframe {
border: 0 !important;
}
h1, h2, h3, h4, h5, h6 {
color: $title-color;
line-height: 1.5;
margin: 0 0 1.5rem 0;
font-family:Roboto, sans-serif;
}
h1{font-size:3rem;}
h2{font-size:2.2rem;}
dl, ol, ul, pre, blockquote, .table{margin-bottom:1.8rem;}
/*=== Highlight Js ===*/
.hljs {padding: 1.5rem;}
-44
View File
@@ -1,44 +0,0 @@
/*===========================================================
Template Name: iDocs - One Page Documentation HTML Template
Author: Harnish Design
Template URL: http://demo.harnishdesign.net/html/idocs
Author URL: https://themeforest.net/user/harnishdesign
File Description : Main css file of the template
=================================================
Table of Contents
=================================================
1. Basic
2. Helpers Classes
3. Layouts
3.1 Side Navigation
3.2 Docs Content
3.3 Section Divider
4. Header
4.1 Main Navigation
5 Elements
5.1 List Style
5.2 Changelog
5.3 Accordion & Toggle
5.4 Nav
5.5 Tabs
5.6 Popup Img
5.7 Featured Box
6 Footer
6.1 Social Icons
6.2 Back to Top
7 Extra
=======================================================*/
//-------------------- Base Colors --------------------//
$primary-color: #0366d6;
$primary-color-hover: darken($primary-color, 7%);
$secondary-color: $secondary;
$body-bg: #dddddd;
$text-color: #4c4d4d;
$title-color: #252b33;
-51
View File
@@ -1,51 +0,0 @@
//
// Base styles
//
.alert {
position: relative;
padding: $alert-padding-y $alert-padding-x;
margin-bottom: $alert-margin-bottom;
border: $alert-border-width solid transparent;
@include border-radius($alert-border-radius);
}
// Headings for larger alerts
.alert-heading {
// Specified to prevent conflicts of changing $headings-color
color: inherit;
}
// Provide class for links that match alerts
.alert-link {
font-weight: $alert-link-font-weight;
}
// Dismissible alerts
//
// Expand the right padding and account for the close button's positioning.
.alert-dismissible {
padding-right: $close-font-size + $alert-padding-x * 2;
// Adjust close link position
.close {
position: absolute;
top: 0;
right: 0;
padding: $alert-padding-y $alert-padding-x;
color: inherit;
}
}
// Alternate styles
//
// Generate contextual modifier classes for colorizing the alert.
@each $color, $value in $theme-colors {
.alert-#{$color} {
@include alert-variant(theme-color-level($color, $alert-bg-level), theme-color-level($color, $alert-border-level), theme-color-level($color, $alert-color-level));
}
}
-54
View File
@@ -1,54 +0,0 @@
// Base class
//
// Requires one of the contextual, color modifier classes for `color` and
// `background-color`.
.badge {
display: inline-block;
padding: $badge-padding-y $badge-padding-x;
@include font-size($badge-font-size);
font-weight: $badge-font-weight;
line-height: 1;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
@include border-radius($badge-border-radius);
@include transition($badge-transition);
@at-root a#{&} {
@include hover-focus() {
text-decoration: none;
}
}
// Empty badges collapse automatically
&:empty {
display: none;
}
}
// Quick fix for badges in buttons
.btn .badge {
position: relative;
top: -1px;
}
// Pill badges
//
// Make them extra rounded with a modifier to replace v3's badges.
.badge-pill {
padding-right: $badge-pill-padding-x;
padding-left: $badge-pill-padding-x;
@include border-radius($badge-pill-border-radius);
}
// Colors
//
// Contextual variations (linked badges get darker on :hover).
@each $color, $value in $theme-colors {
.badge-#{$color} {
@include badge-variant($value);
}
}

Some files were not shown because too many files have changed in this diff Show More